From 57e27aad526f9819579b844ce78c896b98a87040 Mon Sep 17 00:00:00 2001 From: rope Date: Wed, 2 Sep 2026 13:33:36 +0100 Subject: [PATCH] quickshell: drop server monitor and Archie Co-Authored-By: Claude Opus 5 --- settings/quickshell.nix | 794 +--------------------------------------- 1 file changed, 3 insertions(+), 791 deletions(-) diff --git a/settings/quickshell.nix b/settings/quickshell.nix index 25400b6..3b2b992 100644 --- a/settings/quickshell.nix +++ b/settings/quickshell.nix @@ -478,7 +478,6 @@ in Bar 1.0 Bar.qml Lock 1.0 Lock.qml Cheatsheet 1.0 Cheatsheet.qml - Archie 1.0 Archie.qml ''; }; @@ -1103,390 +1102,6 @@ in ''; }; - "quickshell/Archie.qml" = { - onChange = qsRestart; - text = '' - import QtQuick - - // Archie — a black and tan dachshund with a red collar, living - // along the bottom of the screen. He trots about, wags, naps in - // his bed and visits his bowl. - // - // The art is plain text, one character per pixel, so he can be - // redrawn by editing the picture instead of editing code. He walks - // evenly on all fours and never limps; that was deliberate. - Item { - id: archie - anchors.fill: parent - // One dog. The bar is instantiated per monitor. - property bool primary: true - visible: primary - - // 2px pixels: plenty of resolution for a proper pointed - // dachshund head, and he still lands smaller on screen than - // the chunkier drawing did. - readonly property int cell: 2 - readonly property int cols: 44 - readonly property int rows: 19 - - // Not themed — he looked how he looked. - readonly property var pal: ({ - "K": "#2b2523", // black - "T": "#a86a30", // tan - "R": "#b3322c", // collar, and his bowl - "N": "#14100f", // nose and eye - "B": "#96602f", // kibble - "G": "#5a667a", // bed - "D": "#3a4454" // bed cushion - }) - - // Trotting: front leg forward, hind leg back, tail up. Paws - // point the way he is going — drawn trailing behind the leg - // they read as feet on backwards, which is exactly how the - // first pass looked. - readonly property var walkA: [ - "...............................KKKKKKKK.....", - "KK............................KKKKKKKKKK....", - "KKKK..........................KKKKKKKKKKK...", - ".KKKK.........................KKKKK.KKKKK...", - "..KKKKKKKKKKKKKKKKKKKKKKKKKKRRKKKK..TTKKKKK.", - ".KKKKKKKKKKKKKKKKKKKKKKKKKKKRRKKKKTTTTTTTTT.", - "..KKKKKKKKKKKKKKKKKKKKKKKKKKRRKKKKTTTTTTTT..", - "..KKKKKKKKKKKKKKKKKKKKKKKKKKRRKKKKTTTTT.....", - "...KKKKKKKKKKKKKKKKKKKKKKKKKTTKKKK..........", - "...KKKKKKKKKKKKKKKKKKKKKKKKKTTTKKK..........", - "...KKKKKKKKKKKKKKKKKKKKKKKKTTTT.............", - ".....KKKKKKKKKKKKKKKKKKKKKTTTT..............", - "....TTKKKKKKKKKKKKKKKKKKKTTTT...............", - ".....TTTTT..............TTTT................", - "......TTTT..............TTT.................", - ".....TTT................TTT.................", - ".....TTT................TTT.................", - ".....TTT................TTT.................", - ".....TTTTT..............TTTTT..............." - ] - // Legs gathered under him, tail level. - readonly property var walkB: [ - "...............................KKKKKKKK.....", - "..............................KKKKKKKKKK....", - "KKKK..........................KKKKKKKKKKK...", - "KKKK..........................KKKKK.KKKKK...", - "..KKKKKKKKKKKKKKKKKKKKKKKKKKRRKKKK..TTKKKKK.", - ".KKKKKKKKKKKKKKKKKKKKKKKKKKKRRKKKKTTTTTTTTT.", - "..KKKKKKKKKKKKKKKKKKKKKKKKKKRRKKKKTTTTTTTT..", - "..KKKKKKKKKKKKKKKKKKKKKKKKKKRRKKKKTTTTT.....", - "...KKKKKKKKKKKKKKKKKKKKKKKKKTTKKKK..........", - "...KKKKKKKKKKKKKKKKKKKKKKKKKTTTKKK..........", - "...KKKKKKKKKKKKKKKKKKKKKKKKTTTT.............", - ".....KKKKKKKKKKKKKKKKKKKKKTTTT..............", - "....TTKKKKKKKKKKKKKKKKKKKTTTT...............", - "........TTTTT........TTTT...................", - ".........TTTT........TTT....................", - "........TTT..........TTT....................", - "........TTT..........TTT....................", - "........TTT..........TTT....................", - "........TTTTT........TTTTT.................." - ] - // Standing: walkA's planted legs, walkB's tail. Flipping - // between this and walkA is the wag. - readonly property var wag: [ - "...............................KKKKKKKK.....", - "..............................KKKKKKKKKK....", - "KKKK..........................KKKKKKKKKKK...", - "KKKK..........................KKKKK.KKKKK...", - "..KKKKKKKKKKKKKKKKKKKKKKKKKKRRKKKK..TTKKKKK.", - ".KKKKKKKKKKKKKKKKKKKKKKKKKKKRRKKKKTTTTTTTTT.", - "..KKKKKKKKKKKKKKKKKKKKKKKKKKRRKKKKTTTTTTTT..", - "..KKKKKKKKKKKKKKKKKKKKKKKKKKRRKKKKTTTTT.....", - "...KKKKKKKKKKKKKKKKKKKKKKKKKTTKKKK..........", - "...KKKKKKKKKKKKKKKKKKKKKKKKKTTTKKK..........", - "...KKKKKKKKKKKKKKKKKKKKKKKKTTTT.............", - ".....KKKKKKKKKKKKKKKKKKKKKTTTT..............", - "....TTKKKKKKKKKKKKKKKKKKKTTTT...............", - ".....TTTTT..............TTTT................", - "......TTTT..............TTT.................", - ".....TTT................TTT.................", - ".....TTT................TTT.................", - ".....TTT................TTT.................", - ".....TTTTT..............TTTTT..............." - ] - // Head down in the bowl. - readonly property var eat: [ - "............................................", - "KK..........................................", - "KKKK........................................", - ".KKKK.......................................", - "..KKKKKKKKKKKKKKKKKKKKKKKKKKKKKK............", - ".KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK...........", - "..KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK..........", - "..KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK..........", - "...KKKKKKKKKKKKKKKKKKKKKKKKKTTKKKK..........", - "...KKKKKKKKKKKKKKKKKKKKKKKKKTTTKKKK.........", - "...KKKKKKKKKKKKKKKKKKKKKKKKTTTTKKKKKKKK.....", - ".....KKKKKKKKKKKKKKKKKKKKKTTTTKKKKKKKKKK....", - "....TTKKKKKKKKKKKKKKKKKKKTTTT.KKKKK.KKKK....", - ".....TTTTT..............TTTT..KKKKK.TTTKK...", - "......TTTT..............TTT...KKKKTTTTTTTTT.", - ".....TTT................TTT...KKKKKTTTTTTT..", - ".....TTT................TTT....KKKKTTTT.....", - ".....TTT................TTT.................", - ".....TTTTT..............TTTTT..............." - ] - // Flat out in his bed, muzzle on the cushion. - readonly property var sleepArt: [ - "............................................", - "............................................", - "............................................", - "............................................", - "............................................", - "............................................", - "............................................", - "............................................", - "............................................", - "..............................KKKKKKKKK.....", - ".............................KKKKKKKKKKKK...", - "KKKKKKKKKKKKKKKKKKKKKKKKKKKRRKKKKKK.KKKKK...", - "..KKKKKKKKKKKKKKKKKKKKKKKKKRRKKKKKTTTTTKKK..", - "..KKKKKKKKKKKKKKKKKKKKKKKKKRRKKKKKTTTTTTTTT.", - "...KKKKKKKKKKKKKKKKKKKKKKKKRRKKKKKTTTTTTT...", - "...KKKKKKKKKKKKKKKKKKKKKKKKRRTTTT...........", - "....KKKKKKKKKKKKKKKKKKKKKKRRTTTT............", - ".....TTTTTTTTKKKKKKKKKKKKTTTT...............", - "......TTTTTT..........TTTTTT................" - ] - // Mid-breath: the same pose with his ribcage lifted one cell, - // just behind the collar where a dog's chest actually is. His - // belly stays put — that side is against the cushion. - readonly property var sleepIn: [ - "............................................", - "............................................", - "............................................", - "............................................", - "............................................", - "............................................", - "............................................", - "............................................", - "............................................", - "..............................KKKKKKKKK.....", - "................KKKKKKKKKK...KKKKKKKKKKKK...", - "KKKKKKKKKKKKKKKKKKKKKKKKKKKRRKKKKKK.KKKKK...", - "..KKKKKKKKKKKKKKKKKKKKKKKKKRRKKKKKTTTTTKKK..", - "..KKKKKKKKKKKKKKKKKKKKKKKKKRRKKKKKTTTTTTTTT.", - "...KKKKKKKKKKKKKKKKKKKKKKKKRRKKKKKTTTTTTT...", - "...KKKKKKKKKKKKKKKKKKKKKKKKRRTTTT...........", - "....KKKKKKKKKKKKKKKKKKKKKKRRTTTT............", - ".....TTTTTTTTKKKKKKKKKKKKTTTT...............", - "......TTTTTT..........TTTTTT................" - ] - readonly property var bowlArt: [ - ".....BBBBBB.....", - "...BBBBBBBBBB...", - ".BBBBBBBBBBBBBB.", - "RRRRRRRRRRRRRRRR", - ".RRRRRRRRRRRRRR.", - "..RRRRRRRRRRRR..", - "...RRRRRRRRRR...", - "....RRRRRRRR....", - ".....RRRRRR....." - ] - readonly property var bedArt: [ - "GGGGGGG........................................GGGGGGG", - "GGGGGGGGG....................................GGGGGGGGG", - "GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG", - "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD", - "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD", - "GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG", - "..GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG.." - ] - - property var frame: walkA - - // ── His patch of floor ────────────────────────────────── - readonly property real floorY: archie.height - Theme.frameWidth - readonly property real roamL: Theme.barWidth + 12 - readonly property real roamR: Math.max(roamL, - archie.width - Theme.frameWidth - cols * cell - 12) - // Bed tucked into the bottom right corner, bowl beside it — - // his corner of the room. The bowl derives from the bed so - // they cannot drift into each other. - readonly property real bedX: Math.max(roamL, - archie.width - Theme.frameWidth - 54 * cell - 8) - readonly property real bowlX: Math.max(roamL, bedX - 16 * cell - 26) - // Stand so his muzzle lands in the bowl, not his shoulder. - readonly property real bowlStandX: bowlX - 32 * cell - // Lying down, centred on the cushion. - readonly property real bedLieX: bedX + 5 * cell - - property real px: 0 - property int facing: 1 // 1 = right, -1 = left - property string mode: "walk" - property real targetX: 0 - property string errand: "" // "" | "bowl" | "bed" - property int hold: 0 - // Ticks since he last got up. Past `tired` he takes himself - // off to bed. - property int awake: 0 - readonly property int tired: 2700 // 90s on his feet - // Legs swap on distance covered, not on a tick count, so the - // gait stays in step. 3 cells is exactly how far the feet - // move in the art. - property real stride: 0 - property bool stepped: false - - // ── What he does next ─────────────────────────────────── - function wander() { - mode = "walk"; - errand = ""; - // Bed is not a random errand any more, it is what he does - // when he has been up long enough. A dog sleeps most of - // the day; pottering about non-stop is the odd bit. - if (awake > tired) { - errand = "bed"; - targetX = bedLieX; - return; - } - let dBowl = Math.abs(px - bowlStandX); - // Near enough to be worth it, and not already stood there - // — otherwise he marches half a minute for a snack, or - // rolls "go to the bowl" with his head already in it. - if (Math.random() < 0.3 && dBowl > 80 && dBowl < 900) { - errand = "bowl"; - targetX = bowlStandX; - return; - } - - let dir = Math.random() < 0.5 ? -1 : 1; - // Turn away from an end he is already near; clamping the - // target instead just parks him against the wall. - if (dir < 0 && px - roamL < 220) dir = 1; - if (dir > 0 && roamR - px < 220) dir = -1; - targetX = Math.max(roamL, Math.min(roamR, - px + dir * (150 + Math.random() * 550))); - } - - function arrive() { - if (errand === "bowl") { - mode = "eat"; - hold = 100 + Math.random() * 80; - facing = 1; - } else if (errand === "bed") { - mode = "sleep"; - hold = 9000 + Math.random() * 9000; // 5-10 minutes - // Facing into the screen. His bed is in the right - // corner, so unmirrored he sleeps nose-to-the-wall. - facing = -1; - } else { - mode = "idle"; - hold = 150 + Math.random() * 450; // 5-20s stood about - } - } - - // Placed on the first real width: anchors have not resolved at - // Component.onCompleted, so roamR collapses to roamL and he - // spawns pinned to the left edge. - property bool placed: false - onWidthChanged: { - if (placed || width <= 0) return; - placed = true; - px = roamL + Math.random() * (roamR - roamL); - wander(); - } - - Timer { - interval: 33; running: archie.primary; repeat: true - onTriggered: { - archie.awake = archie.mode === "sleep" ? 0 : archie.awake + 1; - - if (archie.mode === "walk") { - // Arrival first: checking after the step makes him - // stride backwards when he is already there. - if (Math.abs(archie.targetX - archie.px) < 2.5) { - archie.arrive(); - } else { - let dir = archie.targetX > archie.px ? 1 : -1; - let sp = 1.5; - archie.facing = dir; - archie.px += dir * sp; - archie.stride += sp; - if (archie.stride >= 3 * archie.cell) { - archie.stride = 0; - archie.stepped = !archie.stepped; - } - archie.frame = archie.stepped ? archie.walkB : archie.walkA; - } - } else { - // Breathing: in for a third of the cycle, then - // back down and a pause. 91 ticks is about three - // seconds a breath, which is where a small dog - // asleep actually sits. - archie.frame = archie.mode === "eat" ? archie.eat - : archie.mode === "sleep" - ? (archie.hold % 91 < 32 ? archie.sleepIn : archie.sleepArt) - : (archie.hold % 26 < 13 ? archie.walkA : archie.wag); - if (--archie.hold <= 0) archie.wander(); - } - } - } - - // ── Sprite: one Rectangle per pixel, colour looked up per - // frame, so switching frames just rebinds them. - component Sprite: Item { - id: sp - property var art: [] - property int w: 0 - property int h: 0 - width: w * archie.cell - height: h * archie.cell - Repeater { - // Delegates parent to the Repeater's PARENT, so `sp` - // is the only reliable way back to the sprite here. - model: sp.w * sp.h - Rectangle { - required property int index - readonly property int col: index % sp.w - readonly property int row: Math.floor(index / sp.w) - readonly property string ch: sp.art[row][col] - visible: ch !== "." - color: archie.pal[ch] || "transparent" - x: col * archie.cell - y: row * archie.cell - width: archie.cell - height: archie.cell - antialiasing: false - } - } - } - - // Bed first, so he lies in it rather than behind it. - Sprite { - art: archie.bedArt; w: 54; h: 7 - x: Math.round(archie.bedX / archie.cell) * archie.cell - y: archie.floorY - height - } - - Sprite { - art: archie.frame - w: archie.cols - h: archie.rows - // Snap x to the pixel grid or the art shimmers as he - // walks. y is exact: he never moves vertically, and - // rounding sank his paws through the floor. - x: Math.round(archie.px / archie.cell) * archie.cell - y: archie.floorY - height - // Mirror him when he heads back the other way. - transform: Scale { origin.x: archie.cols * archie.cell / 2; xScale: archie.facing } - } - - // Bowl after him, so at dinner his nose goes behind it. - Sprite { - art: archie.bowlArt; w: 16; h: 9 - x: Math.round(archie.bowlX / archie.cell) * archie.cell - y: archie.floorY - height - } - } - ''; - }; - "quickshell/Commands.qml" = { onChange = qsRestart; text = '' @@ -4285,211 +3900,8 @@ in } } - // ── Mid cluster: the server glance, pinned just above the - // bottom cluster. Its own anchor (not a barTop child) is the - // whole point: workspace count then changes nothing here. - // - // Server monitor: one persistent SSH streaming `top -b` - // from the mediaserver (2s ticks, parsed line by line — - // no per-poll reconnects) plus a streaming ping to the - // router. Glance = CPU/RAM numbers + ping ms; click - // opens the btop-style dropdown. - Item { - id: srvWidget - width: Theme.barWidth - height: srvGlanceCol.height - anchors.horizontalCenter: barBgRect.horizontalCenter - anchors.bottom: barBottom.top - anchors.bottomMargin: 20 - // Fades out while the OSD takes this slot. - opacity: osdItem.shown ? 0 : 1 - Behavior on opacity { - NumberAnimation { duration: Theme.animContent } - } - - property bool connected: false - property real cpu: 0 - property real memUsed: 0 // GiB - property real memTotal: 0 - property real pingMs: -1 - property string uptime: "" - property string load: "" - property var procs: [] - property int tempC: -1 - property real rxBps: 0 - property real txBps: 0 - - function fmtRate(bps) { - const b = bps * 8; - if (b >= 1e9) return (b / 1e9).toFixed(2) + " Gb/s"; - if (b >= 1e6) return (b / 1e6).toFixed(1) + " Mb/s"; - if (b >= 1e3) return Math.round(b / 1e3) + " Kb/s"; - return Math.round(b) + " b/s"; - } - - // Split variants for the bar glance: number and unit - // live on separate lines, so both stay narrow. - function rateVal(bps) { - const b = bps * 8; - if (b >= 1e9) return (b / 1e9).toFixed(1); - if (b >= 1e7) return Math.round(b / 1e6).toString(); - if (b >= 1e6) return (b / 1e6).toFixed(1); - return Math.round(b / 1e3).toString(); - } - function rateUnit(bps) { - const b = bps * 8; - if (b >= 1e9) return "gb/s"; - if (b >= 1e6) return "mb/s"; - return "kb/s"; - } - - property var _procsPending: [] - property bool _collecting: false - - function _parseLine(line) { - if (line.indexOf("@STAT ") === 0) { - const t = line.match(/temp=(\d+)/); - if (t) tempC = parseInt(t[1]); - const rx = line.match(/rxbps=(-?\d+)/); - if (rx) rxBps = Math.max(0, parseInt(rx[1])); - const tx = line.match(/txbps=(-?\d+)/); - if (tx) txBps = Math.max(0, parseInt(tx[1])); - return; - } - if (line.indexOf("top - ") === 0) { - if (_collecting) procs = _procsPending; - _collecting = false; - const up = line.match(/up\s+(.*?),\s*\d+\s+users?,/); - if (up) uptime = up[1].replace(/\s+/g, " "); - const la = line.match(/load average:\s*(.*)$/); - if (la) load = la[1]; - return; - } - if (line.indexOf("%Cpu(s)") === 0) { - const m = line.match(/([\d.]+)\s+id/); - if (m) { cpu = Math.max(0, 100 - parseFloat(m[1])); connected = true; } - return; - } - const mem = line.match(/^(\S+) Mem\s*:\s*([\d.]+)\s+total,\s*[\d.]+\s+free,\s*([\d.]+)\s+used/); - if (mem) { - const div = mem[1] === "KiB" ? 1048576 : mem[1] === "MiB" ? 1024 : 1; - memTotal = parseFloat(mem[2]) / div; - memUsed = parseFloat(mem[3]) / div; - return; - } - if (/^\s*PID\s/.test(line)) { _collecting = true; _procsPending = []; return; } - if (_collecting) { - const f = line.trim().split(/\s+/); - if (f.length >= 12) { - _procsPending.push({ pid: f[0], cpu: parseFloat(f[8]), mem: parseFloat(f[9]), name: f.slice(11).join(" ") }); - // top sorts by %CPU; first 10 rows are the story - if (_procsPending.length >= 10) { procs = _procsPending; _collecting = false; } - } else { - procs = _procsPending; _collecting = false; - } - } - } - - Process { - id: srvTop - command: [Commands.ssh, "-o", "BatchMode=yes", "-o", "ConnectTimeout=3", - "-o", "StrictHostKeyChecking=accept-new", - "-o", "ServerAliveInterval=5", "-o", "ServerAliveCountMax=2", - "fred@10.0.0.1", "qs-stats"] - running: true - stdout: SplitParser { - onRead: data => srvWidget._parseLine(data) - } - onRunningChanged: if (!running) { srvWidget.connected = false; srvRestart.start(); } - } - Timer { id: srvRestart; interval: 10000; onTriggered: srvTop.running = true } - - // Ping is deliberately separate from the SSH stream: - // ping up + ssh down = box alive but wedged (seen it). - Process { - id: srvPing - command: [Commands.ping, "-n", "-i", "2", "10.0.0.1"] - running: true - stdout: SplitParser { - onRead: data => { - const m = data.match(/time=([\d.]+)\s*ms/); - if (m) { srvWidget.pingMs = parseFloat(m[1]); pingStale.restart(); } - } - } - onRunningChanged: if (!running) pingRestart.start() - } - Timer { id: pingRestart; interval: 10000; onTriggered: srvPing.running = true } - // No echo reply for 3 intervals -> show dashes, not a stale number. - Timer { id: pingStale; interval: 6000; onTriggered: srvWidget.pingMs = -1 } - - function openSrvDropdown() { - bar.toggleDropdown(srvDropdown, function() { - let pos = srvWidget.mapToItem(bar.contentItem, 0, srvWidget.height / 2); - srvDropdown.dropdownY = pos.y; - }); - } - - // Stat stack, clock-sized values over faded captions. - Column { - id: srvGlanceCol - anchors.centerIn: parent - spacing: 5 - - GlanceStat { - value: srvWidget.connected ? Math.round(srvWidget.cpu) + "%" : "--" - caption: "cpu" - // base05, like temp: the accent was the one fully - // saturated thing in the column, which made the - // stat the eye landed on first for no reason. - valueColor: srvWidget.connected ? Theme.base05 : Theme.base03 - } - GlanceStat { - value: srvWidget.connected && srvWidget.memTotal > 0 - ? Math.round(100 * srvWidget.memUsed / srvWidget.memTotal) + "%" : "--" - caption: "ram" - valueColor: srvWidget.connected ? Theme.info : Theme.base03 - } - GlanceStat { - value: srvWidget.connected && srvWidget.tempC >= 0 ? srvWidget.tempC + "°" : "--" - caption: "temp" - valueColor: !srvWidget.connected || srvWidget.tempC < 0 ? Theme.base03 - : srvWidget.tempC >= 85 ? Theme.err - : srvWidget.tempC >= 70 ? Theme.warn : Theme.base05 - } - GlanceStat { - value: srvWidget.connected ? srvWidget.rateVal(srvWidget.rxBps) : "--" - caption: "↓ " + srvWidget.rateUnit(srvWidget.rxBps) - valueColor: srvWidget.connected ? Theme.ok : Theme.base03 - } - GlanceStat { - value: srvWidget.connected ? srvWidget.rateVal(srvWidget.txBps) : "--" - caption: "↑ " + srvWidget.rateUnit(srvWidget.txBps) - valueColor: srvWidget.connected ? Theme.alt : Theme.base03 - } - GlanceStat { - value: srvWidget.pingMs < 0 ? "--" - : srvWidget.pingMs < 10 ? srvWidget.pingMs.toFixed(1) - : Math.round(srvWidget.pingMs).toString() - caption: "ms" - valueColor: srvWidget.pingMs < 0 ? Theme.base03 : Theme.base04 - } - } - - MouseArea { - anchors.fill: parent - hoverEnabled: true - onClicked: srvWidget.openSrvDropdown() - onEntered: { - if (bar.activeDropdown) { - if (bar.activeDropdown !== srvDropdown) srvWidget.openSrvDropdown(); - } - } - } - } - // ── Bottom cluster: status icons, tray, clock, power button. Anchored - // to the bottom edge; the server glance sits just above it and - // the OSD borrows that same slot while it is on screen. + // to the bottom edge; the OSD sits just above it. Column { id: barBottom anchors.bottom: parent.bottom @@ -5580,200 +4992,6 @@ in } // Volume dropdown - // Server monitor dropdown — the btop-at-a-distance view. - BarDropdown { - id: srvDropdown - fullWidth: srvDropdownCol.width + 2 * Theme.panelGap - fullHeight: srvDropdownCol.height + 2 * Theme.panelGap - - Column { - id: srvDropdownCol - anchors.centerIn: parent - width: 340 - spacing: 8 - - Card { - width: parent.width - - Row { - spacing: 6 - SIcon { - anchors.verticalCenter: parent.verticalCenter - text: "server" - color: srvWidget.connected ? Theme.ok : Theme.err - } - SText { - anchors.verticalCenter: parent.verticalCenter - text: "FredOS-Mediaserver" - font.weight: Font.Medium - } - } - - SText { - width: parent.width - text: srvWidget.connected - ? "up " + srvWidget.uptime + " • load " + srvWidget.load - : "unreachable" - font.pixelSize: 12 - color: srvWidget.connected ? Theme.base04 : Theme.err - elide: Text.ElideRight - } - - Row { - width: parent.width - spacing: 10 - SText { width: 42; text: "cpu"; color: Theme.base04; anchors.verticalCenter: parent.verticalCenter } - MeterBar { - width: parent.width - 42 - 76 - 20 - anchors.verticalCenter: parent.verticalCenter - value: srvWidget.cpu / 100 - fillColor: srvWidget.cpu >= 90 ? Theme.err : Theme.accent - } - SText { - width: 76 - text: srvWidget.cpu.toFixed(1) + "%" - font.weight: Font.Medium - horizontalAlignment: Text.AlignRight - anchors.verticalCenter: parent.verticalCenter - } - } - - Row { - width: parent.width - spacing: 10 - SText { width: 42; text: "ram"; color: Theme.base04; anchors.verticalCenter: parent.verticalCenter } - MeterBar { - width: parent.width - 42 - 76 - 20 - anchors.verticalCenter: parent.verticalCenter - value: srvWidget.memTotal > 0 ? srvWidget.memUsed / srvWidget.memTotal : 0 - fillColor: Theme.info - } - SText { - width: 76 - text: srvWidget.memUsed.toFixed(1) + "/" + Math.round(srvWidget.memTotal) + "G" - font.weight: Font.Medium - horizontalAlignment: Text.AlignRight - anchors.verticalCenter: parent.verticalCenter - } - } - - Row { - width: parent.width - spacing: 10 - SText { width: 42; text: "temp"; color: Theme.base04 } - SText { - text: srvWidget.tempC < 0 ? "--" : srvWidget.tempC + "°C" - font.weight: Font.Medium - color: srvWidget.tempC < 0 ? Theme.base03 - : srvWidget.tempC >= 85 ? Theme.err - : srvWidget.tempC >= 70 ? Theme.warn : Theme.base05 - } - } - - Row { - width: parent.width - spacing: 10 - SText { width: 42; text: "wan"; color: Theme.base04 } - Row { - spacing: 14 - Row { - spacing: 4 - SIcon { text: "arrow-down"; font.pixelSize: 14; color: Theme.ok; anchors.verticalCenter: parent.verticalCenter } - SText { - text: srvWidget.fmtRate(srvWidget.rxBps) - font.weight: Font.Medium - anchors.verticalCenter: parent.verticalCenter - } - } - Row { - spacing: 4 - SIcon { text: "arrow-up"; font.pixelSize: 14; color: Theme.alt; anchors.verticalCenter: parent.verticalCenter } - SText { - text: srvWidget.fmtRate(srvWidget.txBps) - font.weight: Font.Medium - anchors.verticalCenter: parent.verticalCenter - } - } - } - } - - Row { - width: parent.width - spacing: 10 - SText { width: 42; text: "ping"; color: Theme.base04 } - SText { - text: srvWidget.pingMs < 0 ? "--" : srvWidget.pingMs.toFixed(1) + " ms" - font.weight: Font.Medium - color: srvWidget.pingMs < 0 ? Theme.base03 : Theme.base05 - } - } - } - - Card { - width: parent.width - - Row { - spacing: 6 - SIcon { anchors.verticalCenter: parent.verticalCenter; text: "activity" } - SText { - anchors.verticalCenter: parent.verticalCenter - text: "Processes" - font.weight: Font.Medium - } - } - - Row { - width: parent.width - SText { width: parent.width - 112; text: "name"; font.pixelSize: 11; color: Theme.base03 } - SText { width: 56; text: "cpu%"; font.pixelSize: 11; color: Theme.base03; horizontalAlignment: Text.AlignRight } - SText { width: 56; text: "mem%"; font.pixelSize: 11; color: Theme.base03; horizontalAlignment: Text.AlignRight } - } - - Column { - width: parent.width - spacing: 3 - - Repeater { - model: srvWidget.procs - - Row { - required property var modelData - width: parent.width - height: 21 - SText { - width: parent.width - 112 - text: modelData.name - elide: Text.ElideRight - anchors.verticalCenter: parent.verticalCenter - } - SText { - width: 56 - text: modelData.cpu.toFixed(1) - horizontalAlignment: Text.AlignRight - color: modelData.cpu >= 100 ? Theme.err - : modelData.cpu >= 25 ? Theme.warn : Theme.base05 - anchors.verticalCenter: parent.verticalCenter - } - SText { - width: 56 - text: modelData.mem.toFixed(1) - horizontalAlignment: Text.AlignRight - color: Theme.base04 - anchors.verticalCenter: parent.verticalCenter - } - } - } - - SText { - visible: srvWidget.procs.length === 0 - text: "no data" - color: Theme.base03 - } - } - } - } - } - BarDropdown { id: volDropdown fullWidth: volDropdownCol.width + 2 * Theme.panelGap @@ -7617,14 +6835,13 @@ in property real value: 0 property color fill: Theme.accent - // Takes over the server glance's slot: fixed position, no - // dependence on how tall the workspace column has grown. + // Fixed slot just above the bottom cluster. width: Theme.barWidth height: 170 anchors.horizontalCenter: parent.horizontalCenter // Both surfaces span the full screen height from y=0, so // the bar's coordinates carry over unchanged. - y: srvWidget.y + srvWidget.height / 2 - height / 2 + y: barBottom.y - 20 - height opacity: shown ? 1 : 0 visible: opacity > 0.01 @@ -7935,11 +7152,6 @@ in } } } - - ${lib.optionalString (!isMacbook) '' - // Archie. One dog, primary screen only. - Archie { id: archieDog; primary: bar.screen === Quickshell.screens[0] } - ''} } ''; };