dotfiles/.config/quickshell/SystemStats.qml

144 lines
4.7 KiB
QML
Raw Normal View History

2026-03-09 00:07:31 -04:00
import QtQuick
import Quickshell
import Quickshell.Io
QtObject {
id: stats
property var _prevCpu: null
property int cpuUsage: 0
property int _memTotal: 0
property int _memAvail: 0
property int memUsage: 0
property string memInfo: "0/0"
property int temperature: 0
property int updatesCount: 0
property string updatesList: ""
property string cpuTemps: ""
property var _cpuProc: Process {
command: ["cat", "/proc/stat"]
running: true
stdout: SplitParser {
splitMarker: "\n"
onRead: data => {
if (!data.startsWith("cpu ")) return
let parts = data.trim().split(/\s+/).slice(1).map(Number)
let idle = parts[3] + (parts[4] || 0)
let total = parts.reduce((a, b) => a + b, 0)
if (stats._prevCpu) {
let di = idle - stats._prevCpu.idle
let dt = total - stats._prevCpu.total
stats.cpuUsage = dt > 0 ? Math.round(100 * (1 - di / dt)) : 0
}
stats._prevCpu = { idle: idle, total: total }
}
}
}
property var _memProc: Process {
command: ["cat", "/proc/meminfo"]
running: true
stdout: SplitParser {
splitMarker: "\n"
onRead: data => {
let line = data.trim()
if (line.startsWith("MemTotal:"))
stats._memTotal = parseInt(line.split(/\s+/)[1]) || 0
else if (line.startsWith("MemAvailable:"))
stats._memAvail = parseInt(line.split(/\s+/)[1]) || 0
}
}
onExited: (code, status) => {
if (stats._memTotal > 0) {
stats.memUsage = Math.round(100 * (1 - stats._memAvail / stats._memTotal))
let used = ((stats._memTotal - stats._memAvail) / 1048576).toFixed(1)
let total = (stats._memTotal / 1048576).toFixed(1)
stats.memInfo = used + "G/" + total + "G"
}
}
}
property var _tempProc: Process {
command: [
"bash", "-c",
"for f in /sys/class/hwmon/hwmon*/temp*_input; do " +
" d=$(dirname \"$f\"); b=$(basename \"$f\"); " +
" name=$(cat \"$d/name\" 2>/dev/null || echo unknown); " +
" label=$(cat \"$d/${b%_input}_label\" 2>/dev/null || echo ''); " +
" temp=$(($(cat \"$f\" 2>/dev/null)/1000)); " +
" printf '%s|%s|%s\\n' \"$name\" \"$label\" \"$temp\"; " +
"done 2>/dev/null"
]
running: true
stdout: StdioCollector {
onDataChanged: {
let lines = text.trim().split("\n").filter(l => l.length > 0)
let tempLines = []
let maxTemp = 0
for (let i = 0; i < lines.length; i++) {
let parts = lines[i].split("|")
let name = parts[0] || "unknown"
let label = parts[1] || ""
let temp = parseInt(parts[2]) || 0
if (temp > 0) {
2026-03-14 17:32:02 -04:00
if (temp <= 200)
{
let display = label ? label : name
tempLines.push(display + ": " + temp + "°C")
if (temp > maxTemp) maxTemp = temp
}
2026-03-09 00:07:31 -04:00
}
}
stats.temperature = maxTemp
stats.cpuTemps = tempLines.join("\n")
}
}
}
property var _pollTimer: Timer {
interval: 3000
running: true
repeat: true
onTriggered: {
if (!stats._cpuProc.running) stats._cpuProc.running = true
if (!stats._memProc.running) stats._memProc.running = true
if (!stats._tempProc.running) stats._tempProc.running = true
}
}
function checkUpdates() {
if (!_updatesProc.running) _updatesProc.running = true
}
property var _updatesProc: Process {
command: [
"bash", "-c",
"(checkupdates 2>/dev/null; yay -Qua 2>/dev/null)"
]
running: true
stdout: StdioCollector {
onDataChanged: {
let lines = text.trim()
let arr = lines ? lines.split("\n") : []
stats.updatesCount = arr.length
stats.updatesList = arr.slice(0, 25).join("\n") + (arr.length > 25 ? "\n..." : "")
}
}
}
property var _updatesTimer: Timer {
interval: 300000
running: true
repeat: true
onTriggered: {
if (!stats._updatesProc.running) stats._updatesProc.running = true
}
}
}