import Quickshell import Quickshell.Wayland import Quickshell.Hyprland import Quickshell.Io import QtQuick import QtQuick.Layouts import "." // qmllint disable uncreatable-type PanelWindow { id: root // ===================== // System stats // ===================== property int cpuUsage: 0 property int memUsage: 0 property var lastCpuIdle: 0 property var lastCpuTotal: 0 RandomWallpaper {} Process { id: cpuProc // get cpu usage, first line of /proc/stat command: ["cat", "/proc/stat"] stdout: StdioCollector { onStreamFinished: { var line = this.text.split(/\r?\n/)[1].split(" "); var user = parseInt(line[1]); var nice = parseInt(line[2]); var system = parseInt(line[3]); var idle = parseInt(line[4]); var iowait = parseInt(line[5]); var irq = parseInt(line[6]); var softirq = parseInt(line[7]); var idleAll = idle + iowait; var total = user + nice + system + idle + iowait + irq + softirq; var diffIdle = idleAll - root.lastCpuIdle; var diffTotal = total - root.lastCpuTotal; if (diffTotal > 0) { root.cpuUsage = Math.round(100 * (1 - diffIdle / diffTotal)); } root.lastCpuIdle = idleAll; root.lastCpuTotal = total; } } } Process { id: memProc command: ["sh", "-c", "free | grep Mem"] stdout: SplitParser { onRead: data => { if (!data) return; var parts = data.trim().split(/\s+/); var total = parseInt(parts[1]) || 1; var used = parseInt(parts[2]) || 0; memUsage = Math.round(100 * used / total); } } Component.onCompleted: running = true } // Update loop Timer { interval: 2000 running: true repeat: true onTriggered: { cpuProc.running = true; memProc.running = true; } } // ===================== // Theme // ===================== property color colBg: "#1a1b26" property color colMuted: "#444b6a" property color colCyan: "#0db9d7" property color colBlue: "#7aa2f7" property color colMagenta: "#e528c2" property color colYellow: "#e0af68" property string fontFamily: "JetBrainsMono Nerd Font" property int fontSize: 14 // ===================== // Helpers // ===================== function getWorkspace(id) { var list = Hyprland.workspaces.values; for (var i = 0; i < list.length; i++) { if (list[i].id === id) return list[i]; } return null; } function isWorkspaceActive(id) { return Hyprland.focusedWorkspace && Hyprland.focusedWorkspace.id === id; } // ===================== // Layout // ===================== anchors.top: true anchors.left: true anchors.right: true implicitHeight: 30 color: root.colBg RowLayout { anchors.fill: parent anchors.margins: 8 // ===================== // LEFT: Workspaces // ===================== RowLayout { spacing: 6 Repeater { model: 9 Text { required property int index property int wsId: index + 1 property var ws: root.getWorkspace(wsId) text: wsId color: root.isWorkspaceActive(wsId) ? root.colCyan : (ws ? root.colMagenta : root.colMuted) font { family: root.fontFamily pixelSize: root.fontSize bold: true } MouseArea { anchors.fill: parent onClicked: Hyprland.dispatch("workspace " + wsId) } } } } // Spacer Item { Layout.fillWidth: true } // ===================== // RIGHT: System info // ===================== RowLayout { spacing: 10 // CPU (placeholder, hook later) Text { id: cpuText text: "CPU: " + cpuUsage + "%" color: root.colYellow font.pixelSize: root.fontSize font.family: root.fontFamily font.bold: true } Rectangle { width: 1 height: 16 color: root.colMuted } // Memory (placeholder) Text { id: memText text: "Mem: " + memUsage + "%" color: root.colCyan font.pixelSize: root.fontSize font.family: root.fontFamily font.bold: true } Rectangle { width: 1 height: 16 color: root.colMuted } // Clock Text { id: clock color: root.colBlue font { family: root.fontFamily pixelSize: root.fontSize bold: true } function updateTime() { text = Qt.formatDateTime(new Date(), "ddd, MMM dd - HH:mm"); } Component.onCompleted: updateTime() Timer { interval: 1000 running: true repeat: true onTriggered: clock.updateTime() } } } } }