aboutsummaryrefslogtreecommitdiffstats
path: root/desktop/island/perf/PerfPanel.qml
diff options
context:
space:
mode:
Diffstat (limited to 'desktop/island/perf/PerfPanel.qml')
-rw-r--r--desktop/island/perf/PerfPanel.qml336
1 files changed, 0 insertions, 336 deletions
diff --git a/desktop/island/perf/PerfPanel.qml b/desktop/island/perf/PerfPanel.qml
deleted file mode 100644
index f149d82..0000000
--- a/desktop/island/perf/PerfPanel.qml
+++ /dev/null
@@ -1,336 +0,0 @@
-// Copyright (C) 2026 Danilo M. <danix@danix.xyz>
-//
-// This program is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License version 2 as
-// published by the Free Software Foundation.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-import Quickshell
-import QtQuick
-import QtQuick.Layouts
-import "../.."
-import "Perf.js" as P
-
-// CPU, GPU, network and disks as cards in three columns: CPU down the left,
-// GPU and network beside it, disks under those two. Numbers come from Perf;
-// colours follow conky's bands, so they read as they did there.
-GridLayout {
- id: panel
-
- columns: 3
- columnSpacing: 8
- rowSpacing: 8
-
- readonly property real col: (width - 2 * columnSpacing) / 3
- readonly property var gpuTemp: sensor("GPU")
- readonly property var vramTemp: sensor("VRAM")
-
- function tone(v, warn, crit) {
- const b = P.band(v, warn, crit);
- return b === "crit" ? Theme.red : b === "warn" ? Theme.yellow : b === "ok" ? Theme.green : Theme.subtext;
- }
- function deg(v) { return v === null ? "--" : Math.round(v) + "°"; }
- function sensor(label) {
- return Perf.temps.find(t => t.label === label) || { value: null, warn: 0, crit: 0 };
- }
- // Detailed sampling (per-core, network, VRAM, fan) runs while any panel
- // exists. The island loads one only while open and the drawer page only
- // while shown, so counting instances is the whole gate, and two of them
- // never clear it under each other.
- Component.onCompleted: Perf.viewers++
- Component.onDestruction: Perf.viewers--
-
- function pct(part, whole) { return part === null || !whole ? null : 100 * part / whole; }
- function last(list) { return list.length ? list[list.length - 1] : null; }
- // Conky's glyphs, re-checked in Inconsolata Nerd Font.
- function glyph(d) {
- if (d.host) return String.fromCodePoint(0xF06F3); // network share
- return String.fromCodePoint({ "/": 0xF318, "/home": 0xF015 }[d.mount] ?? 0xF02CA);
- }
-
- component Label: Text {
- font { family: Theme.fontFamily; pixelSize: Theme.fontSize - 4 }
- color: Theme.text
- }
-
- // A label left, a value right, an optional glyph before the label.
- component Pair: Item {
- property string glyph: ""
- property string label: ""
- property string value: ""
- property color labelColor: Theme.subtext
- property color valueColor: Theme.text
- width: parent ? parent.width : 0
- implicitHeight: valueText.implicitHeight
-
- Row {
- spacing: 6
- Text {
- visible: text !== ""
- text: parent.parent.glyph
- font { family: Theme.iconFamily; pixelSize: Theme.fontSize - 2 }
- color: parent.parent.labelColor
- }
- Label { text: parent.parent.label; color: parent.parent.labelColor }
- }
- Label {
- id: valueText
- anchors.right: parent.right
- text: parent.value
- color: parent.valueColor
- }
- }
-
- component Bar: Rectangle {
- property real frac: 0
- property color fill: Theme.green
- width: parent ? parent.width : 0
- height: 5
- radius: 3
- color: Theme.surfaceAlt
- Rectangle {
- width: parent.width * Math.max(0, Math.min(1, parent.frac))
- height: parent.height
- radius: 3
- color: parent.fill
- }
- }
-
- component Card: Rectangle {
- default property alias content: body.data
- property string title: ""
- property string headline: ""
- property color headlineColor: Theme.text
- radius: 10
- color: Qt.alpha(Theme.surface, 0.6)
- implicitHeight: body.implicitHeight + 20
- Layout.fillHeight: true
-
- Column {
- id: body
- x: 10
- y: 10
- width: parent.width - 20
- spacing: 5
-
- Item {
- width: parent.width
- height: Math.max(titleText.implicitHeight, headText.implicitHeight)
- Text {
- id: titleText
- anchors.verticalCenter: parent.verticalCenter
- text: parent.parent.parent.title
- font { family: Theme.fontFamily; pixelSize: Theme.fontSize - 4; bold: true }
- color: Theme.subtext
- }
- Text {
- id: headText
- anchors.right: parent.right
- text: parent.parent.parent.headline
- font { family: Theme.fontFamily; pixelSize: Theme.fontSize + 4; bold: true }
- color: parent.parent.parent.headlineColor
- }
- }
- }
- }
-
- // --- CPU ----------------------------------------------------------------
-
- Card {
- Layout.row: 0
- Layout.column: 0
- Layout.rowSpan: 2
- Layout.preferredWidth: panel.col
- title: "CPU"
- headline: Perf.load === null ? "--" : Math.round(Perf.load) + "%"
- headlineColor: panel.tone(Perf.load, 25, 75)
-
- Label {
- width: parent.width
- text: Perf.cpuModel
- color: Theme.subtext
- elide: Text.ElideRight
- }
-
- // One bar per core, rising from a common baseline.
- Row {
- id: eq
- width: parent.width
- height: 40
- spacing: 2
- Repeater {
- model: Perf.cores
- delegate: Item {
- required property var modelData
- width: (eq.width - eq.spacing * (Perf.cores.length - 1)) / Perf.cores.length
- height: eq.height
- Rectangle {
- anchors.bottom: parent.bottom
- width: parent.width
- height: Math.max(1, parent.height * modelData / 100)
- radius: 1
- color: panel.tone(modelData, 25, 75)
- }
- }
- }
- }
-
- Pair {
- label: "RAM"
- value: Perf.mem ? P.bytes(Perf.mem.used) + " / " + P.bytes(Perf.mem.total) : "--"
- }
- Bar {
- frac: Perf.mem ? Perf.mem.used / Perf.mem.total : 0
- fill: panel.tone(panel.pct(Perf.mem ? Perf.mem.used : null, Perf.mem ? Perf.mem.total : 0), 25, 75)
- }
-
- Repeater {
- model: Perf.temps.filter(t => t.label !== "GPU" && t.label !== "VRAM")
- delegate: Pair {
- required property var modelData
- label: modelData.label
- value: panel.deg(modelData.value)
- valueColor: panel.tone(modelData.value, modelData.warn, modelData.crit)
- }
- }
- }
-
- // --- GPU ----------------------------------------------------------------
-
- // No utilisation: xe exposes no busy percentage.
- Card {
- Layout.row: 0
- Layout.column: 1
- Layout.preferredWidth: panel.col
- title: "GPU · " + Perf.gpuName
- headline: panel.deg(panel.gpuTemp.value)
- headlineColor: panel.tone(panel.gpuTemp.value, panel.gpuTemp.warn, panel.gpuTemp.crit)
-
- Pair {
- label: "VRAM"
- value: Perf.vram === null ? "--" : P.bytes(Perf.vram) + " / " + P.bytes(Perf.vramTotal)
- }
- Bar {
- frac: (Perf.vram ?? 0) / Perf.vramTotal
- fill: panel.tone(panel.pct(Perf.vram, Perf.vramTotal), 25, 75)
- }
- Pair {
- label: "VRAM temp"
- value: panel.deg(panel.vramTemp.value)
- valueColor: panel.tone(panel.vramTemp.value, panel.vramTemp.warn, panel.vramTemp.crit)
- }
- Pair {
- label: "Fan"
- value: Perf.fan === null ? "--" : Perf.fan + " rpm"
- }
- }
-
- // --- network ------------------------------------------------------------
-
- Card {
- Layout.row: 0
- Layout.column: 2
- Layout.preferredWidth: panel.col
- title: "NET · " + Perf.iface
-
- Canvas {
- id: graph
- width: parent.width
- height: 44
- onPaint: {
- const ctx = getContext("2d");
- ctx.reset();
- const max = Math.max(1, ...Perf.rx, ...Perf.tx);
- const line = (data, color) => {
- ctx.strokeStyle = color;
- ctx.lineWidth = 1.5;
- ctx.beginPath();
- data.forEach((v, i) => {
- const x = width * i / 59;
- const y = height - 1 - (height - 2) * v / max;
- if (i) ctx.lineTo(x, y); else ctx.moveTo(x, y);
- });
- ctx.stroke();
- };
- line(Perf.rx, Theme.teal);
- line(Perf.tx, Theme.peach);
- }
- Connections {
- target: Perf
- function onRxChanged() { graph.requestPaint(); }
- function onTxChanged() { graph.requestPaint(); }
- }
- }
-
- Pair {
- label: "↓ " + P.speed(panel.last(Perf.rx))
- labelColor: Theme.teal
- value: "↑ " + P.speed(panel.last(Perf.tx))
- valueColor: Theme.peach
- }
- Pair { label: "LAN"; value: Perf.lan || "--" }
-
- // The public IP, red when it differs from the pinned one. The pin
- // stores the address shown; it is lit while they are the same.
- Item {
- width: parent.width
- height: pubText.implicitHeight
-
- Label { text: "Public"; color: Theme.subtext }
- Label {
- id: pubText
- anchors { right: pin.left; rightMargin: 6 }
- text: Perf.ip.ip || "--"
- color: Perf.ip.mismatch ? Theme.red : Theme.text
- }
- Text {
- id: pin
- anchors { right: parent.right; verticalCenter: pubText.verticalCenter }
- text: String.fromCodePoint(0xF0403)
- font { family: Theme.iconFamily; pixelSize: Theme.fontSize - 2 }
- color: Perf.ip.ip !== "" && Perf.ip.ip === Prefs.pinnedIp ? Theme.text : Theme.overlay
-
- MouseArea {
- anchors.fill: parent
- anchors.margins: -4
- enabled: Perf.ip.ip !== ""
- cursorShape: Qt.PointingHandCursor
- onClicked: Prefs.setPinnedIp(Perf.ip.ip)
- }
- }
- }
- }
-
- // --- disks --------------------------------------------------------------
-
- Card {
- Layout.row: 1
- Layout.column: 1
- Layout.columnSpan: 2
- Layout.preferredWidth: 2 * panel.col + panel.columnSpacing
- title: "DISKS"
-
- Repeater {
- model: Perf.disks
- delegate: Column {
- required property var modelData
- width: parent.width
- spacing: 2
- Pair {
- glyph: panel.glyph(modelData)
- label: modelData.host || modelData.mount
- value: modelData.pct + "% · " + P.bytes(modelData.used) + " / " + P.bytes(modelData.size)
- valueColor: panel.tone(modelData.pct, 25, 75)
- }
- Bar {
- frac: modelData.pct / 100
- fill: panel.tone(modelData.pct, 25, 75)
- }
- }
- }
- }
-}