diff --git a/cpugpuram-viewer@lyk4s5/README.md b/cpugpuram-viewer@lyk4s5/README.md new file mode 100644 index 00000000000..b4cc1a8d1b2 --- /dev/null +++ b/cpugpuram-viewer@lyk4s5/README.md @@ -0,0 +1,42 @@ +# CPU/GPU/RAM Viewer + +A minimalist, text-based system resource monitor for the Cinnamon Desktop Environment. + +This applet displays real-time usage percentages for CPU, GPU, and RAM directly on your panel. It is designed to be lightweight, unobtrusive, and dynamic. + +## Features + +* **Minimalist Design:** Text-only display (e.g., `CPU %15 • GPU %30 • RAM %40`). +* **Dynamic Resizing:** The applet grows or shrinks based on the text length (no fixed width). +* **Auto-Detect GPU:** + * **NVIDIA:** Uses `nvidia-smi` automatically if installed. + * **AMD:** Reads directly from system files (`/sys/class/drm/...`). + * **Intel/No GPU:** Automatically hides the GPU section if no dedicated GPU is detected. +* **One-Click Monitor:** Left-clicking the applet opens `gnome-system-monitor` directly to the **Resources** tab. +* **Native Behavior:** Fully supports right-click context menus and panel edit mode (drag & drop). + +## Requirements + +* **Cinnamon Desktop Environment** +* `gnome-system-monitor` (For the click action) +* `nvidia-smi` (Optional: Only required for NVIDIA GPU monitoring) + +## Installation + +1. Download or clone this repository. +2. Copy the folder to your local Cinnamon applets directory: + ```bash + cp -r cpugpuram-viewer@lyk4s5 ~/.local/share/cinnamon/applets/ + ``` +3. Right-click on your Cinnamon panel -> **Applets**. +4. Find **CPU/GPU/RAM Viewer** in the *Manage* tab and add it to your panel. + +## Usage + +* **Left Click:** Opens System Monitor (Resources tab). +* **Right Click:** Opens the standard applet context menu (About, Remove, etc.). + +## License + +1. Distributed under the MIT License. + diff --git a/cpugpuram-viewer@lyk4s5/files/cpugpuram-viewer@lyk4s5/applet.js b/cpugpuram-viewer@lyk4s5/files/cpugpuram-viewer@lyk4s5/applet.js new file mode 100644 index 00000000000..2a950dc0db1 --- /dev/null +++ b/cpugpuram-viewer@lyk4s5/files/cpugpuram-viewer@lyk4s5/applet.js @@ -0,0 +1,157 @@ +const Applet = imports.ui.applet; +const GLib = imports.gi.GLib; +const Util = imports.misc.util; +const Mainloop = imports.mainloop; + +class CinnamonApplet extends Applet.TextApplet { + constructor(metadata, orientation, panel_height, instance_id) { + super(orientation, panel_height, instance_id); + + + this.setAllowedLayout(Applet.AllowedLayout.BOTH); + + + this.set_applet_label("..."); + this.set_applet_tooltip("Click to open System Monitor."); + + + this.prevIdle = 0; + this.prevTotal = 0; + + + this.gpuProvider = this.detectGpuProvider(); + + + this.updateLoop(); + } + + + on_applet_clicked(event) { + Util.spawnCommandLine("gnome-system-monitor -r"); + } + + detectGpuProvider() { + // 1. NVIDIA + let nvidiaPath = GLib.find_program_in_path("nvidia-smi"); + if (nvidiaPath) { + return "nvidia"; + } + + // 2. AMD + if (GLib.file_test("/sys/class/drm/card0/device/gpu_busy_percent", GLib.FileTest.EXISTS)) { + return "amd_card0"; + } + if (GLib.file_test("/sys/class/drm/card1/device/gpu_busy_percent", GLib.FileTest.EXISTS)) { + return "amd_card1"; + } + + return null; + } + + updateLoop() { + this.updateMetrics(); + // 2 saniyede bir güncelle + Mainloop.timeout_add_seconds(2, () => { + this.updateLoop(); + }); + } + + updateMetrics() { + try { + let parts = []; + + // 1. CPU + let cpuUsage = this.getCpuUsage(); + parts.push(`CPU %${cpuUsage}`); + + // 2. GPU (if there) + if (this.gpuProvider) { + let gpuUsage = this.getGpuUsage(); + if (gpuUsage !== null) { + parts.push(`GPU %${gpuUsage}`); + } + } + + // 3. RAM + let ramUsage = this.getRamUsage(); + parts.push(`RAM %${ramUsage}`); + + + this.set_applet_label(parts.join(" • ")); + + } catch (e) { + global.logError(e); + this.set_applet_label("Hata"); + } + } + + getGpuUsage() { + try { + if (this.gpuProvider === "nvidia") { + let [res, out] = GLib.spawn_command_line_sync("nvidia-smi --query-gpu=utilization.gpu --format=csv,noheader,nounits"); + if (res) return out.toString().trim(); + } + else if (this.gpuProvider.startsWith("amd")) { + let cardPath = this.gpuProvider === "amd_card0" ? + "/sys/class/drm/card0/device/gpu_busy_percent" : + "/sys/class/drm/card1/device/gpu_busy_percent"; + + let [res, out] = GLib.file_get_contents(cardPath); + if (res) return out.toString().trim(); + } + } catch (e) { return null; } + return null; + } + + getCpuUsage() { + try { + let [res, fileContent] = GLib.file_get_contents('/proc/stat'); + if (!res) return 0; + + let lines = fileContent.toString().split('\n'); + let cpuLine = lines[0].split(/\s+/); + + let idle = parseInt(cpuLine[4]) + parseInt(cpuLine[5]); + let total = 0; + for (let i = 1; i < cpuLine.length; i++) { + let val = parseInt(cpuLine[i]); + if (!isNaN(val)) total += val; + } + + let diffIdle = idle - this.prevIdle; + let diffTotal = total - this.prevTotal; + let usage = 0; + + if (diffTotal > 0) { + usage = Math.round(100 * (diffTotal - diffIdle) / diffTotal); + } + + this.prevIdle = idle; + this.prevTotal = total; + + return usage; + } catch(e) { return 0; } + } + + getRamUsage() { + try { + let [res, fileContent] = GLib.file_get_contents('/proc/meminfo'); + if (!res) return 0; + + let contentStr = fileContent.toString(); + let totalMatch = contentStr.match(/MemTotal:\s+(\d+)/); + let availableMatch = contentStr.match(/MemAvailable:\s+(\d+)/); + + if (totalMatch && availableMatch) { + let total = parseInt(totalMatch[1]); + let available = parseInt(availableMatch[1]); + return Math.round(((total - available) / total) * 100); + } + } catch(e) { return 0; } + return 0; + } +} + +function main(metadata, orientation, panel_height, instance_id) { + return new CinnamonApplet(metadata, orientation, panel_height, instance_id); +} \ No newline at end of file diff --git a/cpugpuram-viewer@lyk4s5/files/cpugpuram-viewer@lyk4s5/icon.png b/cpugpuram-viewer@lyk4s5/files/cpugpuram-viewer@lyk4s5/icon.png new file mode 100644 index 00000000000..dbf3340756c Binary files /dev/null and b/cpugpuram-viewer@lyk4s5/files/cpugpuram-viewer@lyk4s5/icon.png differ diff --git a/cpugpuram-viewer@lyk4s5/files/cpugpuram-viewer@lyk4s5/metadata.json b/cpugpuram-viewer@lyk4s5/files/cpugpuram-viewer@lyk4s5/metadata.json new file mode 100644 index 00000000000..b3924b0e6ec --- /dev/null +++ b/cpugpuram-viewer@lyk4s5/files/cpugpuram-viewer@lyk4s5/metadata.json @@ -0,0 +1,6 @@ +{ + "uuid": "cpugpuram-viewer@lyk4s5", + "name": "CPU/GPU/RAM Viewer", + "description": "Minimalist system monitor for CPU, GPU, and RAM usage.", + "version": "1.0" +} diff --git a/cpugpuram-viewer@lyk4s5/info.json b/cpugpuram-viewer@lyk4s5/info.json new file mode 100644 index 00000000000..f8d5fb008a5 --- /dev/null +++ b/cpugpuram-viewer@lyk4s5/info.json @@ -0,0 +1,5 @@ + +{ + "author": "lyk4s5", + "name": "CPU/GPU/RAM Viewer" +} diff --git a/cpugpuram-viewer@lyk4s5/screenshot.png b/cpugpuram-viewer@lyk4s5/screenshot.png new file mode 100644 index 00000000000..02ec0f29bd1 Binary files /dev/null and b/cpugpuram-viewer@lyk4s5/screenshot.png differ diff --git a/rssdock@lyk4s5/files/rssdock@lyk4s5/applet.js b/rssdock@lyk4s5/files/rssdock@lyk4s5/applet.js index e2178d2b8e5..5f52c1e1fe2 100644 --- a/rssdock@lyk4s5/files/rssdock@lyk4s5/applet.js +++ b/rssdock@lyk4s5/files/rssdock@lyk4s5/applet.js @@ -39,8 +39,8 @@ MyApplet.prototype = { this._tickerLoop(); this._setWidth(); - // refresh every X seconds - this._refreshLoop = Mainloop.timeout_add_seconds(this.update_interval * 60, Lang.bind(this, this._updateFeed)); + + }, _setupSettings: function () { @@ -80,11 +80,13 @@ MyApplet.prototype = { _updateFeed: function () { // Collect news from all sources + if (this._refreshLoop) Mainloop.source_remove(this._refreshLoop); this._allNews = []; let sources = this.news_sources || []; if (!sources.length) { this._tickerText = _("No RSS source configured"); this._buildMenu(); + this._refreshLoop = Mainloop.timeout_add_seconds(60, Lang.bind(this, this._updateFeed)); return; } @@ -114,6 +116,7 @@ MyApplet.prototype = { link: link, date: dateObj, source: source.label || "RSS" + }); }); } catch (e) { @@ -128,6 +131,9 @@ MyApplet.prototype = { } }); }); + // refresh every X seconds + let interval = Math.max(1, this.update_interval) * 60; + this._refreshLoop = Mainloop.timeout_add_seconds(interval, Lang.bind(this, this._updateFeed)); }, _buildMenu: function () {