From 5fefee5e2c6f1463364e12f8ba8ff65856d87aa1 Mon Sep 17 00:00:00 2001 From: Uyanide Date: Sat, 25 Apr 2026 22:03:01 +0200 Subject: [PATCH] qs: add caps event handler for niri ipc --- .../Modules/Bar/Modules/RecordIndicator.qml | 20 +++-- .../.config/quickshell/Services/Niri.qml | 84 +++++++++++++++++++ 2 files changed, 95 insertions(+), 9 deletions(-) diff --git a/config/quickshell/.config/quickshell/Modules/Bar/Modules/RecordIndicator.qml b/config/quickshell/.config/quickshell/Modules/Bar/Modules/RecordIndicator.qml index 6bb5b5d..2d60caa 100644 --- a/config/quickshell/.config/quickshell/Modules/Bar/Modules/RecordIndicator.qml +++ b/config/quickshell/.config/quickshell/Modules/Bar/Modules/RecordIndicator.qml @@ -11,15 +11,23 @@ Item { property color fillColor: Colors.mRed property color _actualColor: Colors.mRed property bool _expand: mouseArea.containsMouse + property string displayText: Niri.castOutputs.length > 0 ? Niri.castOutputs.join(", ") : "Casting" - visible: RecordService.isRecording + visible: Niri.isCasting implicitHeight: Math.max(symbolIcon.implicitHeight, textLabel.implicitHeight) implicitWidth: height + expander.implicitWidth + Connections { + target: Niri + onCastOutputsListChanged: { + root.displayText = Niri.castOutputs.length > 0 ? Niri.castOutputs.join(", ") : "Casting"; + } + } + SequentialAnimation { id: blinkAnimation - running: RecordService.isRecording + running: root.visible loops: Animation.Infinite ColorAnimation { @@ -70,7 +78,7 @@ Item { anchors.verticalCenter: parent.verticalCenter anchors.left: parent.left anchors.leftMargin: 5 - text: RecordService.recordingDisplay || "Recording" + text: root.displayText color: root.fillColor } @@ -92,12 +100,6 @@ Item { anchors.fill: parent cursorShape: Qt.PointingHandCursor hoverEnabled: true - acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton - onClicked: (mouse) => { - if (mouse.button === Qt.LeftButton) - RecordService.startOrStop(); - - } } Behavior on _actualColor { diff --git a/config/quickshell/.config/quickshell/Services/Niri.qml b/config/quickshell/.config/quickshell/Services/Niri.qml index 47a1509..05fc981 100644 --- a/config/quickshell/.config/quickshell/Services/Niri.qml +++ b/config/quickshell/.config/quickshell/Services/Niri.qml @@ -35,11 +35,16 @@ Singleton { }) property var workspaceCache: ({ }) + property var castCache: ({ + }) + property var castOutputs: [] + property bool isCasting: false signal workspaceChanged() signal activeWindowChanged() signal windowListChanged() signal outputsChanged() + signal castOutputsListChanged() function initialize() { niriEventStream.connected = true; @@ -434,6 +439,79 @@ Singleton { } } + function _syncCasts() { + isCasting = Object.keys(castCache).length > 0; + castOutputs = []; + for (const castId in castCache) { + const cast = castCache[castId]; + if (cast.output) { + if (!castOutputs.includes(cast.output)) + castOutputs.push(cast.output); + } + } + castOutputsListChanged(); + } + + function _handleCastsChanged(eventData) { + try { + const casts = eventData.casts || []; + castCache = { + }; + castOutputs = []; + for (const cast of casts) { + const castData = { + "id": cast.stream_id, + "stream_id": cast.stream_id, + "session_id": cast.session_id, + "kind": cast.kind, + "output": cast.target?.Output?.name, + "pid": cast.pid + }; + castCache[castData.id] = castData; + } + _syncCasts(); + } catch (e) { + Logger.e("NiriService", "Error handling CastsChanged:", e); + } + } + + function _handleCastStopped(eventData) { + try { + const castId = eventData.stream_id; + delete castCache[castId]; + _syncCasts(); + } catch (e) { + Logger.e("NiriService", "Error handling CastStopped:", e); + } + } + + function _handleCastStartedOrChanged(eventData) { + try { + const cast = eventData.cast; + if (!cast) + return ; + if (cast.is_active === true) { + // If the cast is active, we can treat it as a new or updated cast + const castData = { + "id": cast.stream_id, + "stream_id": cast.stream_id, + "session_id": cast.session_id, + "kind": cast.kind, + "output": cast.target?.Output?.name, + "pid": cast.pid + }; + castCache[castData.id] = castData; + } else { + // If the cast is not active, we should remove it from the cache + const castId = cast.stream_id; + delete castCache[castId]; + } + _syncCasts(); + } catch (e) { + Logger.e("NiriService", "Error handling CastStartedOrChanged:", e); + } + } + function switchToWorkspace(workspace) { try { Quickshell.execDetached(["niri", "msg", "action", "focus-workspace", workspace.idx.toString()]); @@ -578,6 +656,12 @@ Singleton { _queryDisplayScales(); else if (event.ScreenshotCaptured) _handleScreenshotCaptured(event.ScreenshotCaptured); + else if (event.CastsChanged) + _handleCastsChanged(event.CastsChanged); + else if (event.CastStopped) + _handleCastStopped(event.CastStopped); + else if (event.CastStartedOrChanged) + _handleCastStartedOrChanged(event.CastStartedOrChanged); } catch (e) { Logger.e("NiriService", "Error parsing event stream:", e, data); }