Files
dotfiles-violet-chaton/ags-v3/widget/modules/SystemStats.tsx
Tetardtek 9eaaa01663 feat(ags-v3): desktop adaptation — ultrawide scaling, brain power panel, system stats
- Scaling 16px base pour ultrawide 3440x1440
- Bar: CPU/RAM/GPU visible, media single player (skip playerctld), network tooltip LAN/WAN IPv4
- Volume: class module pour sizing cohérent
- Battery: désactivé (PC fixe)
- Clock: tooltip calendrier + uptime
- BrainPower: panel enrichi (focus, session, intentions, todos, repos git, derniers commits)
- App: BrainPower sur moniteur principal uniquement
- Heartbeat: Layer.TOP pour compatibilité COSMIC
2026-03-26 15:25:03 +01:00

90 lines
2.6 KiB
TypeScript

import GLib from "gi://GLib"
import { createPoll } from "ags/time"
import { exec } from "ags/process"
function readProc(path: string): string | null {
try {
const [ok, contents] = GLib.file_get_contents(path)
if (ok && contents) return new TextDecoder().decode(contents)
} catch {}
return null
}
let prevIdle = 0
let prevTotal = 0
function getCpuUsage(): string {
const content = readProc("/proc/stat")
if (!content) return "?"
const line = content.split("\n")[0]
const parts = line.split(/\s+/).slice(1).map(Number)
const idle = parts[3] + parts[4]
const total = parts.reduce((a, b) => a + b, 0)
const dIdle = idle - prevIdle
const dTotal = total - prevTotal
prevIdle = idle
prevTotal = total
if (dTotal === 0) return "0"
return `${Math.round(((dTotal - dIdle) / dTotal) * 100)}`
}
function getRamUsage(): { pct: string; used: string; total: string } {
const content = readProc("/proc/meminfo")
if (!content) return { pct: "?", used: "?", total: "?" }
const lines = content.split("\n")
let totalKb = 0, availableKb = 0
for (const line of lines) {
if (line.startsWith("MemTotal:")) totalKb = parseInt(line.split(/\s+/)[1])
if (line.startsWith("MemAvailable:")) availableKb = parseInt(line.split(/\s+/)[1])
if (totalKb && availableKb) break
}
if (!totalKb) return { pct: "?", used: "?", total: "?" }
const usedGb = ((totalKb - availableKb) / 1048576).toFixed(1)
const totalGb = (totalKb / 1048576).toFixed(0)
const pct = `${Math.round(((totalKb - availableKb) / totalKb) * 100)}`
return { pct, used: usedGb, total: totalGb }
}
function getGpuInfo(): string {
try {
const out = exec("bash -c \"nvidia-smi --query-gpu=utilization.gpu,temperature.gpu --format=csv,noheader,nounits 2>/dev/null\"")
const [usage, temp] = out.trim().split(", ")
return `GPU ${usage}% · ${temp}°C`
} catch {
return ""
}
}
export default function SystemStats() {
const cpu = createPoll("0", 3000, () => getCpuUsage())
const ram = createPoll("", 5000, () => {
const r = getRamUsage()
return JSON.stringify(r)
})
const ramLabel = ram((v: string) => {
try {
const r = JSON.parse(v)
return `RAM ${r.used}/${r.total}G`
} catch { return "RAM ?" }
})
const gpu = createPoll("", 5000, () => getGpuInfo())
return (
<box>
<label class="cpu module" label={cpu((v: string) => `CPU ${v}%`)} />
<label class="separator" label="│" />
<label class="ram module" label={ramLabel} />
<label class="separator" label="│" />
<label class="gpu module" label={gpu((v: string) => v || "GPU ?")} />
</box>
)
}