qs: add caps event handler for niri ipc

This commit is contained in:
2026-04-25 22:03:01 +02:00
parent 6f90fe5d28
commit 5fefee5e2c
2 changed files with 95 additions and 9 deletions
@@ -11,15 +11,23 @@ Item {
property color fillColor: Colors.mRed property color fillColor: Colors.mRed
property color _actualColor: Colors.mRed property color _actualColor: Colors.mRed
property bool _expand: mouseArea.containsMouse 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) implicitHeight: Math.max(symbolIcon.implicitHeight, textLabel.implicitHeight)
implicitWidth: height + expander.implicitWidth implicitWidth: height + expander.implicitWidth
Connections {
target: Niri
onCastOutputsListChanged: {
root.displayText = Niri.castOutputs.length > 0 ? Niri.castOutputs.join(", ") : "Casting";
}
}
SequentialAnimation { SequentialAnimation {
id: blinkAnimation id: blinkAnimation
running: RecordService.isRecording running: root.visible
loops: Animation.Infinite loops: Animation.Infinite
ColorAnimation { ColorAnimation {
@@ -70,7 +78,7 @@ Item {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left anchors.left: parent.left
anchors.leftMargin: 5 anchors.leftMargin: 5
text: RecordService.recordingDisplay || "Recording" text: root.displayText
color: root.fillColor color: root.fillColor
} }
@@ -92,12 +100,6 @@ Item {
anchors.fill: parent anchors.fill: parent
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
hoverEnabled: true hoverEnabled: true
acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton
onClicked: (mouse) => {
if (mouse.button === Qt.LeftButton)
RecordService.startOrStop();
}
} }
Behavior on _actualColor { Behavior on _actualColor {
@@ -35,11 +35,16 @@ Singleton {
}) })
property var workspaceCache: ({ property var workspaceCache: ({
}) })
property var castCache: ({
})
property var castOutputs: []
property bool isCasting: false
signal workspaceChanged() signal workspaceChanged()
signal activeWindowChanged() signal activeWindowChanged()
signal windowListChanged() signal windowListChanged()
signal outputsChanged() signal outputsChanged()
signal castOutputsListChanged()
function initialize() { function initialize() {
niriEventStream.connected = true; 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) { function switchToWorkspace(workspace) {
try { try {
Quickshell.execDetached(["niri", "msg", "action", "focus-workspace", workspace.idx.toString()]); Quickshell.execDetached(["niri", "msg", "action", "focus-workspace", workspace.idx.toString()]);
@@ -578,6 +656,12 @@ Singleton {
_queryDisplayScales(); _queryDisplayScales();
else if (event.ScreenshotCaptured) else if (event.ScreenshotCaptured)
_handleScreenshotCaptured(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) { } catch (e) {
Logger.e("NiriService", "Error parsing event stream:", e, data); Logger.e("NiriService", "Error parsing event stream:", e, data);
} }