Add System Monitor Cinnamon applet#8301
Conversation
There was a problem hiding this comment.
Pull request overview
This PR introduces a new Cinnamon desktop applet called "System Monitor Cinnamon" that displays real-time system metrics (CPU usage, memory usage, and network speed) in the panel with animated icons. The applet is inspired by RunCat365 and features customizable cat or horse animation icons that run faster as CPU usage increases.
Changes:
- Complete implementation of a system monitoring applet with CPU, RAM, and network speed tracking
- Animated icon system with cat and horse runners that respond to CPU load
- Comprehensive internationalization support with 50+ language translations
- Settings interface for customizing refresh rate, network display, icon theme, and animation type
Reviewed changes
Copilot reviewed 52 out of 94 changed files in this pull request and generated 14 comments.
Show a summary per file
| File | Description |
|---|---|
| applet.js | Main applet implementation with system monitoring logic and animation rendering |
| metadata.json | Applet metadata defining UUID, name, version, and description |
| settings-schema.json | Configuration schema for user-customizable options |
| info.json | Author information for Cinnamon Spices |
| stylesheet.css | Empty CSS file for potential styling |
| icon.png | Applet icon displayed in the Cinnamon settings |
| screenshot.png | Screenshot for applet showcase |
| po/* (50+ files) | Translation files for internationalization support |
| icons/runners/* | SVG animation frames for cat and horse icons in black and white variants |
| runners/* | Duplicate icon directory (appears redundant) |
| README.md / README.en.md | Documentation in Chinese and English |
| totalDownload += parseInt(data[1]); | ||
| totalUpload += parseInt(data[9]); |
There was a problem hiding this comment.
Potential integer overflow risk in network data parsing. The parseInt() calls on lines 190-191 could overflow for very large byte counts on systems with high network usage over extended uptime. Consider using parseInt with base 10 explicitly and potentially handling large numbers with BigInt for systems with high network throughput.
system-monitor-cinnamon@MainPoser/files/system-monitor-cinnamon@MainPoser/applet.js
Show resolved
Hide resolved
| _data_loop() { | ||
| this._stats.cpu = this._get_cpu_usage(); | ||
| this._stats.mem = this._get_mem_usage(); | ||
|
|
||
| // 5. 根据配置逻辑显示 | ||
| let label = ` CPU: ${this._stats.cpu}% | RAM: ${this._stats.mem}%`; | ||
|
|
||
| if (this._settings.show_network) { | ||
| let net = this._get_net_speed(); | ||
| label += ` | ${net}`; | ||
| } | ||
|
|
||
| this.set_applet_label(label); | ||
|
|
||
| // 使用绑定的变量 this._settings.refresh_interval | ||
| this._render.dataTimeoutId = Mainloop.timeout_add(this._settings.refresh_interval * 1000, () => this._data_loop()); | ||
| return false; |
There was a problem hiding this comment.
The timeout callbacks in _data_loop() and _anim_loop() return false, which prevents them from repeating automatically. However, new timeouts are manually scheduled at the end of each iteration. This creates a potential issue: if an exception occurs before reaching the timeout_add call, the loop will stop permanently. Consider using a try-catch block to ensure the loop continues even if errors occur, or return true to auto-repeat and only reschedule when settings change.
| this._render.frame = (this._render.frame + 1) % 5; | ||
| this._settings.them = this._get_them(); | ||
|
|
||
| let iconPath = `${this._render.path}/icons/runners/${this._settings.runner}/${this._settings.them}/${this._settings.runner}_${this._render.frame}.svg`; |
There was a problem hiding this comment.
Duplicate icon files exist in two separate directory structures: files/.../icons/runners/ and files/.../runners/. This redundancy wastes storage space and creates maintenance overhead. The code references the 'icons/runners' path (line 101), so the duplicate 'runners' directory appears to be unnecessary and should be removed.
| ├── metada.json # Applet metadata | ||
| ├── setting-schema.json # Configuration options definition |
There was a problem hiding this comment.
The README.en.md file contains the same typos as README.md. The file names "metada.json" should be "metadata.json" and "setting-schema.json" should be "settings-schema.json" to match the actual files in the project.
| ├── metada.json # Applet metadata | |
| ├── setting-schema.json # Configuration options definition | |
| ├── metadata.json # Applet metadata | |
| ├── settings-schema.json # Configuration options definition |
| this._settings.them = this._get_them(); | ||
|
|
||
| let iconPath = `${this._render.path}/icons/runners/${this._settings.runner}/${this._settings.them}/${this._settings.runner}_${this._render.frame}.svg`; |
There was a problem hiding this comment.
The variable name "them" appears to be a typo. It should be "theme" to properly represent the icon theme color scheme (black/white). This typo occurs in line 99 where it's assigned and line 101 where it's used in the path construction.
| this._settings.them = this._get_them(); | |
| let iconPath = `${this._render.path}/icons/runners/${this._settings.runner}/${this._settings.them}/${this._settings.runner}_${this._render.frame}.svg`; | |
| this._settings.theme = this._get_them(); | |
| let iconPath = `${this._render.path}/icons/runners/${this._settings.runner}/${this._settings.theme}/${this._settings.runner}_${this._render.frame}.svg`; |
| /** | ||
| * 核心: 决定当前应该使用哪个文件夹 | ||
| */ | ||
| _get_them() { |
There was a problem hiding this comment.
The method name "_get_them()" contains a typo and should be "_get_theme()" for consistency with standard naming conventions and to accurately represent its purpose of determining the theme color.
| ├── metada.json # 小部件元数据 | ||
| ├── setting-schema.json # 配置选项定义 |
There was a problem hiding this comment.
The README.md file references "metada.json" and "setting-schema.json" in the project structure section, but the actual files are named "metadata.json" and "settings-schema.json" (note the missing 't' in metadata and the plural 's' in settings). This documentation should be corrected to match the actual file names.
| ├── metada.json # 小部件元数据 | |
| ├── setting-schema.json # 配置选项定义 | |
| ├── metadata.json # 小部件元数据 | |
| ├── settings-schema.json # 配置选项定义 |
| 安装后,小部件将自动在面板上显示系统监控信息。默认显示格式为: | ||
|
|
||
| ``` | ||
| CPU: 45% | MEM: 2.1G/8G | ↑ 1.2MB/s ↓ 500KB/s |
There was a problem hiding this comment.
The network speed display format in the README shows "↑ 1.2MB/s ↓ 500KB/s" but the code (line 222) outputs "↓ ${down} KB/s ↑ ${up} KB/s" (download first, then upload). The order and unit case (MB vs KB) differ from the documentation. This should be clarified or made consistent.
| let content = GLib.file_get_contents("/proc/meminfo")[1].toString(); | ||
| let total = parseInt(content.match(/MemTotal:\s+(\d+)/)[1]); | ||
| let available = parseInt(content.match(/MemAvailable:\s+(\d+)/)[1]); | ||
| return Math.round(((total - available) / total) * 100); |
There was a problem hiding this comment.
Error handling in _get_mem_usage() is incomplete. If /proc/meminfo reading fails or the regex doesn't match, the function will throw an unhandled exception and crash the applet. Consider adding try-catch error handling similar to what's done in _get_cpu_usage() and _get_net_raw(), returning a fallback value (e.g., 0) on error.
| let content = GLib.file_get_contents("/proc/meminfo")[1].toString(); | |
| let total = parseInt(content.match(/MemTotal:\s+(\d+)/)[1]); | |
| let available = parseInt(content.match(/MemAvailable:\s+(\d+)/)[1]); | |
| return Math.round(((total - available) / total) * 100); | |
| try { | |
| let content = GLib.file_get_contents("/proc/meminfo")[1].toString(); | |
| let totalMatch = content.match(/MemTotal:\s+(\d+)/); | |
| let availableMatch = content.match(/MemAvailable:\s+(\d+)/); | |
| if (!totalMatch || !availableMatch) { | |
| throw new Error("Unexpected /proc/meminfo format"); | |
| } | |
| let total = parseInt(totalMatch[1]); | |
| let available = parseInt(availableMatch[1]); | |
| if (!isFinite(total) || total <= 0 || !isFinite(available)) { | |
| throw new Error("Failed to parse memory values"); | |
| } | |
| return Math.round(((total - available) / total) * 100); | |
| } catch (e) { | |
| global.logError("Failed to get memory usage: " + e); | |
| return 0; | |
| } |
| */ | ||
| _get_net_raw() { | ||
| try { | ||
| let content = GLib.file_get_contents("/proc/net/dev")[1].toString(); |
There was a problem hiding this comment.
Do not use synchronous i/o functions. Use Gio.File.read_async/read_finish
|
Your black/white icons seem unnecessary. Make a single set of symbolic icons. They'll use whatever color the theme dictates as an appropriate color for them. This is how themes work. I object to your entire 'animation' premise here - you're sharing a single thread with everything else in the UI. It's useless overhead. |
|
|
||
| let iconPath = `${this._render.path}/icons/runners/${this._settings.runner}/${this._settings.them}/${this._settings.runner}_${this._render.frame}.svg`; | ||
|
|
||
| if (GLib.file_test(iconPath, GLib.FileTest.EXISTS)) { |
There was a problem hiding this comment.
GLib.file_test() can block the thread, don't use it.
| _get_cpu_usage() { | ||
| try { | ||
| // 1. 读取 /proc/stat | ||
| let content = GLib.file_get_contents("/proc/stat")[1].toString(); |
Best-practices scannerThis is a regex-based check for API usage that can pose security, performance or This check is not perfect will not replace a normal review.Found 4 potential issue(s):
|
Best-practices scannerThis is a regex-based check for API usage that can pose security, performance or This check is not perfect will not replace a normal review.Found 5 potential issue(s):
|
Best-practices scannerThis is a regex-based check for API usage that can pose security, performance or This check is not perfect will not replace a normal review.Found 5 potential issue(s):
|
Best-practices scannerThis is a regex-based check for API usage that can pose security, performance or This check is not perfect will not replace a normal review.Found 5 potential issue(s):
|
Best-practices scannerThis is a regex-based check for API usage that can pose security, performance or This check is not perfect will not replace a normal review.Found 5 potential issue(s):
|
Best-practices scannerThis is a regex-based check for API usage that can pose security, performance or This check is not perfect will not replace a normal review.Found 5 potential issue(s):
|
This PR adds a new applet: System Monitor Cinnamon.
A small tool to display CPU usage, memory usage, and real-time network speed in the Cinnamon desktop panel.
Features:
Real-time monitoring of CPU, RAM, and net speed.
cat or horse run with cpu