From 9b87c7047710627fed00bf3292a0ecee633be039 Mon Sep 17 00:00:00 2001 From: Damocles Date: Sun, 12 Apr 2026 15:05:59 +0200 Subject: [PATCH] workspace indicator --- modules/Bar.qml | 1 + modules/Modules.qml | 1 + modules/Workspaces.qml | 94 ++++++++++++++++++++++++++++++++++++++++-- nix/hm-module.nix | 1 + 4 files changed, 93 insertions(+), 4 deletions(-) diff --git a/modules/Bar.qml b/modules/Bar.qml index 28a7868..25673d1 100644 --- a/modules/Bar.qml +++ b/modules/Bar.qml @@ -50,6 +50,7 @@ PanelWindow { anchors.verticalCenter: parent.verticalCenter spacing: M.Theme.barSpacing + M.Workspaces { visible: M.Modules.workspaces } M.Tray { bar: bar visible: M.Modules.tray diff --git a/modules/Modules.qml b/modules/Modules.qml index 4476b57..b7645f6 100644 --- a/modules/Modules.qml +++ b/modules/Modules.qml @@ -7,6 +7,7 @@ import Quickshell.Io QtObject { id: root + property bool workspaces: true property bool tray: true property bool windowTitle: true property bool clock: true diff --git a/modules/Workspaces.qml b/modules/Workspaces.qml index d379941..6f45225 100644 --- a/modules/Workspaces.qml +++ b/modules/Workspaces.qml @@ -1,7 +1,93 @@ import QtQuick -import QtQuick.Layouts +import Quickshell.Io +import "." as M -// Placeholder — Quickshell.Services.Niri not yet available -RowLayout { - spacing: M.Theme.moduleSpacing +Row { + id: root + spacing: 4 + + property var _workspaces: [] + property int _activeId: -1 + + // Initial state + Process { + id: initProc + running: true + command: ["niri", "msg", "--json", "workspaces"] + stdout: StdioCollector { + onStreamFinished: { + try { + const ws = JSON.parse(text); + root._workspaces = ws.sort((a, b) => a.idx - b.idx); + for (const w of ws) { + if (w.is_focused) + root._activeId = w.id; + } + } catch (e) {} + } + } + } + + // Live updates + Process { + id: eventStream + running: true + command: ["niri", "msg", "--json", "event-stream"] + stdout: SplitParser { + splitMarker: "\n" + onRead: line => { + try { + const ev = JSON.parse(line); + if (ev.WorkspacesChanged !== undefined) { + root._workspaces = ev.WorkspacesChanged.workspaces + .sort((a, b) => a.idx - b.idx); + } else if (ev.WorkspaceActivated !== undefined) { + if (ev.WorkspaceActivated.focused) + root._activeId = ev.WorkspaceActivated.id; + } + } catch (e) {} + } + } + } + + Process { + id: switchProc + property int wsId: -1 + command: ["niri", "msg", "action", "focus-workspace", String(wsId)] + } + + Repeater { + model: root._workspaces + + delegate: Rectangle { + id: pill + + required property var modelData + + readonly property bool active: modelData.id === root._activeId + + width: 20 + height: 20 + radius: M.Theme.radius + color: pill.active ? M.Theme.base0D : M.Theme.base02 + + Text { + anchors.centerIn: parent + text: pill.modelData.idx + color: pill.active ? M.Theme.base00 : M.Theme.base04 + font.pixelSize: M.Theme.fontSize - 2 + font.family: M.Theme.fontFamily + font.bold: pill.active + } + + MouseArea { + anchors.fill: parent + cursorShape: Qt.PointingHandCursor + onClicked: { + switchProc.wsId = pill.modelData.id; + switchProc.running = true; + } + } + } + } } diff --git a/nix/hm-module.nix b/nix/hm-module.nix index ce34b6a..eb27d33 100644 --- a/nix/hm-module.nix +++ b/nix/hm-module.nix @@ -58,6 +58,7 @@ in type = lib.types.submodule { options = lib.genAttrs [ + "workspaces" "tray" "windowTitle" "clock"