From 060cbefc797c91a4148603046fb9b54234c4d4a3 Mon Sep 17 00:00:00 2001 From: Ivan Molodetskikh Date: Wed, 14 Jan 2026 21:55:21 -0800 Subject: [PATCH] Add screencast indicator for niri (#1361) * niri: Handle new Cast events * bar: Add screen sharing indicator Configurable like other icons; on by default. * lockscreen: Add screen sharing indicator --- quickshell/Common/SettingsData.qml | 1 + quickshell/Common/settings/Lists.qml | 5 ++- quickshell/Common/settings/SettingsSpec.js | 1 + quickshell/Modules/Lock/LockScreenContent.qml | 8 +++++ quickshell/Modules/Settings/WidgetsTab.qml | 12 ++++++- .../Modules/Settings/WidgetsTabSection.qml | 7 ++++ quickshell/Services/NiriService.qml | 35 +++++++++++++++++++ 7 files changed, 67 insertions(+), 2 deletions(-) diff --git a/quickshell/Common/SettingsData.qml b/quickshell/Common/SettingsData.qml index 9623ae55..30258e9f 100644 --- a/quickshell/Common/SettingsData.qml +++ b/quickshell/Common/SettingsData.qml @@ -145,6 +145,7 @@ Singleton { property bool controlCenterShowMicPercent: true property bool controlCenterShowBatteryIcon: false property bool controlCenterShowPrinterIcon: false + property bool controlCenterShowScreenSharingIcon: true property bool showPrivacyButton: true property bool privacyShowMicIcon: false property bool privacyShowCameraIcon: false diff --git a/quickshell/Common/settings/Lists.qml b/quickshell/Common/settings/Lists.qml index fc7d720c..57b5f2d7 100644 --- a/quickshell/Common/settings/Lists.qml +++ b/quickshell/Common/settings/Lists.qml @@ -28,7 +28,8 @@ Singleton { showMicIcon: false, showMicPercent: true, showBatteryIcon: false, - showPrinterIcon: false + showPrinterIcon: false, + showScreenSharingIcon: true }; leftModel.append(dummy); centerModel.append(dummy); @@ -84,6 +85,8 @@ Singleton { item.showBatteryIcon = order[i].showBatteryIcon; if (isObj && order[i].showPrinterIcon !== undefined) item.showPrinterIcon = order[i].showPrinterIcon; + if (isObj && order[i].showScreenSharingIcon !== undefined) + item.showScreenSharingIcon = order[i].showScreenSharingIcon; model.append(item); } diff --git a/quickshell/Common/settings/SettingsSpec.js b/quickshell/Common/settings/SettingsSpec.js index 3b7d7410..77693d13 100644 --- a/quickshell/Common/settings/SettingsSpec.js +++ b/quickshell/Common/settings/SettingsSpec.js @@ -70,6 +70,7 @@ var SPEC = { controlCenterShowMicPercent: { def: false }, controlCenterShowBatteryIcon: { def: false }, controlCenterShowPrinterIcon: { def: false }, + controlCenterShowScreenSharingIcon: { def: true }, showPrivacyButton: { def: true }, privacyShowMicIcon: { def: false }, diff --git a/quickshell/Modules/Lock/LockScreenContent.qml b/quickshell/Modules/Lock/LockScreenContent.qml index 9600c1dc..7554b0cb 100644 --- a/quickshell/Modules/Lock/LockScreenContent.qml +++ b/quickshell/Modules/Lock/LockScreenContent.qml @@ -1406,6 +1406,14 @@ Item { anchors.verticalCenter: parent.verticalCenter visible: NetworkService.networkAvailable || (BluetoothService.available && BluetoothService.enabled) || (AudioService.sink && AudioService.sink.audio) + DankIcon { + name: "screen_record" + size: Theme.iconSize - 2 + color: NiriService.hasActiveCast ? "white" : Qt.rgba(255, 255, 255, 0.5) + anchors.verticalCenter: parent.verticalCenter + visible: NiriService.hasCasts + } + DankIcon { name: { if (NetworkService.wifiToggling) diff --git a/quickshell/Modules/Settings/WidgetsTab.qml b/quickshell/Modules/Settings/WidgetsTab.qml index 9af31bf9..03e6925e 100644 --- a/quickshell/Modules/Settings/WidgetsTab.qml +++ b/quickshell/Modules/Settings/WidgetsTab.qml @@ -383,6 +383,7 @@ Item { widgetObj.showMicPercent = SettingsData.controlCenterShowMicPercent; widgetObj.showBatteryIcon = SettingsData.controlCenterShowBatteryIcon; widgetObj.showPrinterIcon = SettingsData.controlCenterShowPrinterIcon; + widgetObj.showScreenSharingIcon = SettingsData.controlCenterShowScreenSharingIcon; } if (widgetId === "diskUsage") widgetObj.mountPath = "/"; @@ -443,6 +444,7 @@ Item { newWidget.showMicPercent = widget.showMicPercent ?? SettingsData.controlCenterShowMicPercent; newWidget.showBatteryIcon = widget.showBatteryIcon ?? SettingsData.controlCenterShowBatteryIcon; newWidget.showPrinterIcon = widget.showPrinterIcon ?? SettingsData.controlCenterShowPrinterIcon; + newWidget.showScreenSharingIcon = widget.showScreenSharingIcon ?? SettingsData.controlCenterShowScreenSharingIcon; } widgets[i] = newWidget; break; @@ -499,6 +501,7 @@ Item { newWidget.showMicPercent = widget.showMicPercent ?? SettingsData.controlCenterShowMicPercent; newWidget.showBatteryIcon = widget.showBatteryIcon ?? SettingsData.controlCenterShowBatteryIcon; newWidget.showPrinterIcon = widget.showPrinterIcon ?? SettingsData.controlCenterShowPrinterIcon; + newWidget.showScreenSharingIcon = widget.showScreenSharingIcon ?? SettingsData.controlCenterShowScreenSharingIcon; } widgets[widgetIndex] = newWidget; setWidgetsForSection(sectionId, widgets); @@ -577,6 +580,7 @@ Item { newWidget.showMicPercent = widget.showMicPercent ?? SettingsData.controlCenterShowMicPercent; newWidget.showBatteryIcon = widget.showBatteryIcon ?? SettingsData.controlCenterShowBatteryIcon; newWidget.showPrinterIcon = widget.showPrinterIcon ?? SettingsData.controlCenterShowPrinterIcon; + newWidget.showScreenSharingIcon = widget.showScreenSharingIcon ?? SettingsData.controlCenterShowScreenSharingIcon; } widgets[widgetIndex] = newWidget; setWidgetsForSection(sectionId, widgets); @@ -608,7 +612,8 @@ Item { "showMicIcon": widget.showMicIcon ?? SettingsData.controlCenterShowMicIcon, "showMicPercent": widget.showMicPercent ?? SettingsData.controlCenterShowMicPercent, "showBatteryIcon": widget.showBatteryIcon ?? SettingsData.controlCenterShowBatteryIcon, - "showPrinterIcon": widget.showPrinterIcon ?? SettingsData.controlCenterShowPrinterIcon + "showPrinterIcon": widget.showPrinterIcon ?? SettingsData.controlCenterShowPrinterIcon, + "showScreenSharingIcon": widget.showScreenSharingIcon ?? SettingsData.controlCenterShowScreenSharingIcon }; newWidget[settingName] = value; @@ -675,6 +680,7 @@ Item { newWidget.showMicPercent = widget.showMicPercent ?? SettingsData.controlCenterShowMicPercent; newWidget.showBatteryIcon = widget.showBatteryIcon ?? SettingsData.controlCenterShowBatteryIcon; newWidget.showPrinterIcon = widget.showPrinterIcon ?? SettingsData.controlCenterShowPrinterIcon; + newWidget.showScreenSharingIcon = widget.showScreenSharingIcon ?? SettingsData.controlCenterShowScreenSharingIcon; } widgets[widgetIndex] = newWidget; setWidgetsForSection(sectionId, widgets); @@ -735,6 +741,7 @@ Item { newWidget.showMicPercent = widget.showMicPercent ?? SettingsData.controlCenterShowMicPercent; newWidget.showBatteryIcon = widget.showBatteryIcon ?? SettingsData.controlCenterShowBatteryIcon; newWidget.showPrinterIcon = widget.showPrinterIcon ?? SettingsData.controlCenterShowPrinterIcon; + newWidget.showScreenSharingIcon = widget.showScreenSharingIcon ?? SettingsData.controlCenterShowScreenSharingIcon; } widgets[widgetIndex] = newWidget; setWidgetsForSection(sectionId, widgets); @@ -795,6 +802,7 @@ Item { newWidget.showMicPercent = widget.showMicPercent ?? SettingsData.controlCenterShowMicPercent; newWidget.showBatteryIcon = widget.showBatteryIcon ?? SettingsData.controlCenterShowBatteryIcon; newWidget.showPrinterIcon = widget.showPrinterIcon ?? SettingsData.controlCenterShowPrinterIcon; + newWidget.showScreenSharingIcon = widget.showScreenSharingIcon ?? SettingsData.controlCenterShowScreenSharingIcon; } widgets[i] = newWidget; widget = newWidget; @@ -867,6 +875,8 @@ Item { item.showBatteryIcon = widget.showBatteryIcon; if (widget.showPrinterIcon !== undefined) item.showPrinterIcon = widget.showPrinterIcon; + if (widget.showScreenSharingIcon !== undefined) + item.showScreenSharingIcon = widget.showScreenSharingIcon; if (widget.minimumWidth !== undefined) item.minimumWidth = widget.minimumWidth; if (widget.showSwap !== undefined) diff --git a/quickshell/Modules/Settings/WidgetsTabSection.qml b/quickshell/Modules/Settings/WidgetsTabSection.qml index b5876797..d858e14c 100644 --- a/quickshell/Modules/Settings/WidgetsTabSection.qml +++ b/quickshell/Modules/Settings/WidgetsTabSection.qml @@ -875,6 +875,11 @@ Column { icon: "print", label: I18n.tr("Printer"), setting: "showPrinterIcon" + }, + { + icon: "screen_record", + label: I18n.tr("Screen Sharing"), + setting: "showScreenSharingIcon" } ] @@ -907,6 +912,8 @@ Column { return wd?.showBatteryIcon ?? SettingsData.controlCenterShowBatteryIcon; case "showPrinterIcon": return wd?.showPrinterIcon ?? SettingsData.controlCenterShowPrinterIcon; + case "showScreenSharingIcon": + return wd?.showScreenSharingIcon ?? SettingsData.controlCenterShowScreenSharingIcon; default: return false; } diff --git a/quickshell/Services/NiriService.qml b/quickshell/Services/NiriService.qml index e6458667..3b1e9568 100644 --- a/quickshell/Services/NiriService.qml +++ b/quickshell/Services/NiriService.qml @@ -27,6 +27,10 @@ Singleton { property bool inOverview: false + property var casts: [] + property bool hasCasts: casts.length > 0 + property bool hasActiveCast: casts.some(c => c.is_active) + property int currentKeyboardLayoutIndex: 0 property var keyboardLayoutNames: [] @@ -356,6 +360,15 @@ Singleton { case 'ScreenshotCaptured': handleScreenshotCaptured(event.ScreenshotCaptured); break; + case 'CastsChanged': + handleCastsChanged(event.CastsChanged); + break; + case 'CastStartedOrChanged': + handleCastStartedOrChanged(event.CastStartedOrChanged); + break; + case 'CastStopped': + handleCastStopped(event.CastStopped); + break; } } @@ -649,6 +662,28 @@ Singleton { } } + function handleCastsChanged(data) { + casts = data.casts || []; + } + + function handleCastStartedOrChanged(data) { + if (!data.cast) + return; + const cast = data.cast; + const existingIndex = casts.findIndex(c => c.stream_id === cast.stream_id); + if (existingIndex >= 0) { + const updatedCasts = [...casts]; + updatedCasts[existingIndex] = cast; + casts = updatedCasts; + } else { + casts = [...casts, cast]; + } + } + + function handleCastStopped(data) { + casts = casts.filter(c => c.stream_id !== data.stream_id); + } + function updateCurrentOutputWorkspaces() { if (!currentOutput) { currentOutputWorkspaces = allWorkspaces;