Restore sysmon bar widget (CPU/RAM/disk/GPU temp/net) on current plugin API

swadhinbiswas committed 2 months ago
f5910ef
1 parent 12362d0
commit f5910ef
3 files changed
+192 -0
▼shell/plugins/sysmon/Sysmon.qml
+112-0
1
+import QtQuick
2
+import Quickshell
3
+import Quickshell.Io
4
+import qs.Commons
5
+import qs.Ui
6
+
7
+BarWidget {
8
+ id: root
9
+ moduleName: "omarchy.sysmon"
10
+
11
+ property int cpuPct: 0
12
+ property int memPct: 0
13
+ property int diskPct: 0
14
+ property int gpuTemp: 0
15
+ property int cpuTemp: 0
16
+ property string netDown: "0.0"
17
+ property string netUp: "0.0"
18
+ property bool sampled: false
19
+
20
+ // Poll interval in ms. The sampler itself needs ~0.6s inside each tick to
21
+ // measure its delta window, so don't push this below ~1500.
22
+ readonly property int intervalMs: setting("intervalMs", 2000)
23
+
24
+ readonly property string scriptPath: Qt.resolvedUrl("sysmon-stats.sh").toString().replace("file://", "")
25
+
26
+ visible: !root.vertical && sampled
27
+ implicitWidth: row.implicitWidth + Style.spacing.controlPaddingX * 2
28
+ implicitHeight: barSize
29
+
30
+ function refresh() {
31
+ if (!statsProc.running) statsProc.running = true
32
+ }
33
+
34
+ function applyStats(line) {
35
+ var m = String(line).match(/C=(\d+) M=(\d+) D=(\d+) G=(\d+) T=(-?\d+) RX=([\d.]+) TX=([\d.]+)/)
36
+ if (!m) return
37
+ root.cpuPct = parseInt(m[1])
38
+ root.memPct = parseInt(m[2])
39
+ root.diskPct = parseInt(m[3])
40
+ root.gpuTemp = parseInt(m[4])
41
+ root.cpuTemp = parseInt(m[5])
42
+ root.netDown = m[6]
43
+ root.netUp = m[7]
44
+ root.sampled = true
45
+ }
46
+
47
+ Component.onCompleted: refresh()
48
+
49
+ Process {
50
+ id: statsProc
51
+ command: ["bash", root.scriptPath]
52
+ stdout: StdioCollector {
53
+ waitForEnd: true
54
+ onStreamFinished: root.applyStats(text)
55
+ }
56
+ }
57
+
58
+ Timer {
59
+ interval: root.intervalMs
60
+ running: true
61
+ repeat: true
62
+ onTriggered: root.broadcast("refresh")
63
+ }
64
+
65
+ IpcHandler {
66
+ target: "omarchy.sysmon"
67
+ function refresh(): void { root.broadcast("refresh") }
68
+ }
69
+
70
+ Row {
71
+ id: row
72
+ anchors.verticalCenter: parent.verticalCenter
73
+ spacing: 10
74
+
75
+ Repeater {
76
+ model: [
77
+ { icon: "", value: root.cpuPct + "%" },
78
+ { icon: "󱋗", value: root.cpuTemp + "°" },
79
+ { icon: "󰗻", value: root.memPct + "%" },
80
+ { icon: "󰋓", value: root.diskPct + "%" },
81
+ { icon: "󱈘", value: root.gpuTemp + "°" },
82
+ { icon: "󰇣", value: root.netDown + "↓" },
83
+ { icon: "\uf093", value: root.netUp + "↑" }
84
+ ]
85
+ delegate: Text {
86
+ text: modelData.icon + " " + modelData.value
87
+ color: root.bar ? root.bar.barForeground : Color.foreground
88
+ font.family: root.bar ? root.bar.fontFamily : Style.font.family
89
+ font.pixelSize: Style.font.body
90
+ opacity: 0.85
91
+ }
92
+ }
93
+ }
94
+
95
+ MouseArea {
96
+ anchors.fill: parent
97
+ hoverEnabled: true
98
+ cursorShape: Qt.PointingHandCursor
99
+ onClicked: {
100
+ root.bar.run("uwsm-app -- kitty -e btop")
101
+ }
102
+ onEntered: {
103
+ if (root.bar) root.bar.showTooltip(root,
104
+ "CPU " + root.cpuPct + "% @ " + root.cpuTemp + "°\n" +
105
+ "RAM " + root.memPct + "%\n" +
106
+ "Disk " + root.diskPct + "%\n" +
107
+ "GPU " + root.gpuTemp + "°\n" +
108
+ "Net ↓ " + root.netDown + " MB/s ↑ " + root.netUp + " MB/s\n" +
109
+ "Click for btop")
110
+ }
111
+ }
112
+}
0
113
▼shell/plugins/sysmon/manifest.json
+21-0
1
+{
2
+ "schemaVersion": 1,
3
+ "id": "omarchy.sysmon",
4
+ "name": "System monitor",
5
+ "version": "1.1.0",
6
+ "author": "de-omarchy",
7
+ "description": "CPU, RAM, disk and GPU temperature usage in the bar",
8
+ "kinds": [
9
+ "bar-widget"
10
+ ],
11
+ "entryPoints": {
12
+ "barWidget": "Sysmon.qml"
13
+ },
14
+ "barWidget": {
15
+ "displayName": "System monitor",
16
+ "description": "CPU, RAM, disk, GPU temp readouts",
17
+ "category": "System",
18
+ "allowMultiple": false,
19
+ "defaultSection": "right"
20
+ }
21
+}
0
22
▼shell/plugins/sysmon/sysmon-stats.sh
+59-0
1
+#!/bin/bash
2
+# One-shot system stats sampler for the omarchy.sysmon bar widget.
3
+# Prints a single line:
4
+# C=<cpu%> M=<mem%> D=<disk%> G=<gpu-temp> T=<cpu-temp> RX=<MB/s down> TX=<MB/s up>
5
+# Stateless: each invocation takes two samples 0.6s apart and derives rates
6
+# from that window, so the QML side owns no previous-counter state and a dead
7
+# sample never poisons the next one.
8
+
9
+read -r t0 i0 <<< "$(awk '/^cpu /{print $2+$3+$4+$5+$6+$7+$8, $5}' /proc/stat 2>/dev/null)"
10
+read -r rx0 tx0 <<< "$(awk 'NR>2{rx+=$2; tx+=$10} END{print rx+0, tx+0}' /proc/net/dev 2>/dev/null)"
11
+
12
+sleep 0.6
13
+
14
+read -r t1 i1 <<< "$(awk '/^cpu /{print $2+$3+$4+$5+$6+$7+$8, $5}' /proc/stat 2>/dev/null)"
15
+read -r rx1 tx1 <<< "$(awk 'NR>2{rx+=$2; tx+=$10} END{print rx+0, tx+0}' /proc/net/dev 2>/dev/null)"
16
+
17
+dt=$(( t1 - t0 ))
18
+di=$(( i1 - i0 ))
19
+cpu=0
20
+(( dt > 0 )) && cpu=$(( 100 * (dt - di) / dt ))
21
+
22
+mem=$(awk '/^MemTotal:/{t=$2} /^MemAvailable:/{a=$2} END{if (t > 0) printf "%d", (t-a)*100/t; else print 0}' /proc/meminfo 2>/dev/null)
23
+mem=${mem:-0}
24
+
25
+dsk=$(df --output=pcent / 2>/dev/null | tail -1 | tr -dc '0-9')
26
+dsk=${dsk:-0}
27
+
28
+# GPU temperature: hwmon first (no subprocess cost), nvidia-smi as fallback.
29
+gpu=0
30
+for hm in /sys/class/hwmon/hwmon*/name; do
31
+ hm_name=$(cat "$hm" 2>/dev/null) || continue
32
+ case $hm_name in
33
+ nvidia*|amdgpu|nouveau|radeon)
34
+ hm_dir=${hm%/name}
35
+ hm_temp=$(cat "$hm_dir/temp1_input" 2>/dev/null) || continue
36
+ [[ -n $hm_temp ]] && { gpu=$(( hm_temp / 1000 )); break; }
37
+ ;;
38
+ esac
39
+done
40
+if (( gpu == 0 )) && command -v nvidia-smi >/dev/null 2>&1; then
41
+ gpu=$(nvidia-smi --query-gpu=temperature.gpu --format=csv,noheader,nounits 2>/dev/null | head -1)
42
+ gpu=${gpu:-0}
43
+fi
44
+
45
+ct=0
46
+for z in /sys/class/thermal/thermal_zone*/temp; do
47
+ zdir=${z%/temp}
48
+ ztype=$(cat "$zdir/type" 2>/dev/null) || continue
49
+ if [[ $ztype == x86_pkg_temp || $ztype == coretemp ]]; then
50
+ ct=$(awk '{printf "%d", $1/1000}' "$z" 2>/dev/null)
51
+ break
52
+ fi
53
+done
54
+ct=${ct:-0}
55
+
56
+down=$(awk "BEGIN{printf \"%.1f\", ($rx1-$rx0)/1048576/0.6}")
57
+up=$(awk "BEGIN{printf \"%.1f\", ($tx1-$tx0)/1048576/0.6}")
58
+
59
+echo "C=$cpu M=$mem D=$dsk G=$gpu T=$ct RX=$down TX=$up"
0
60