pragma ComponentBehavior: Bound import Quickshell import Quickshell.Io import QtQuick // amdgpu utilisation, straight off sysfs. // // node_exporter's hwmon collector carries the card's temperatures, power and // clocks — which is where VitalsData gets them — but not its busy percentage, // so this is the one vital that cannot come from the same scrape. // // The card number is globbed rather than pinned: it is card1 on terra today, // but it depends on probe order and moves when a GPU is added or removed. Scope { id: root // Poll only while something is showing it, like VitalsData. property bool active: false property int interval: 2000 property real value: 0 // 0..1 busy property bool ready: false onActiveChanged: { if (!root.active) root.ready = false; } Process { id: probe command: ["sh", "-c", "cat /sys/class/drm/card*/device/gpu_busy_percent 2>/dev/null | head -n1"] stdout: StdioCollector { onStreamFinished: { const busy = parseInt(this.text.trim(), 10); if (isFinite(busy)) { root.value = Math.max(0, Math.min(1, busy / 100)); root.ready = true; } else { // No amdgpu (or no permission) — leave the meter blank // rather than pinning it at zero, which would read as idle. root.ready = false; } } } } Timer { interval: root.interval running: root.active repeat: true triggeredOnStart: true onTriggered: { if (!probe.running) probe.running = true; } } }