aboutsummaryrefslogtreecommitdiffstats
path: root/desktop/island/Island.qml
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-10-17 13:11:22 +0200
committerDanilo M. <danix@danix.xyz>2026-10-17 13:11:22 +0200
commit9eb8878da78a32ebc707075008a24ba78cf2d901 (patch)
tree0945a42b8411d36a708457040841d2a13da4409d /desktop/island/Island.qml
parent611fb6b05f5820d8acae823cbcddd19310f46c74 (diff)
downloadquickshell-9eb8878da78a32ebc707075008a24ba78cf2d901.tar.gz
quickshell-9eb8878da78a32ebc707075008a24ba78cf2d901.zip
island: place the OBS pill and pulse the sliver while recording
Diffstat (limited to 'desktop/island/Island.qml')
-rw-r--r--desktop/island/Island.qml45
1 files changed, 43 insertions, 2 deletions
diff --git a/desktop/island/Island.qml b/desktop/island/Island.qml
index 5efe9bf..04a6350 100644
--- a/desktop/island/Island.qml
+++ b/desktop/island/Island.qml
@@ -42,12 +42,12 @@ PanelWindow {
WlrLayershell.namespace: "quickshell-island"
WlrLayershell.keyboardFocus: panel !== "" ? WlrKeyboardFocus.OnDemand : WlrKeyboardFocus.None
- // "", "sound" or "calendar".
+ // "", "sound", "calendar" or "obs".
property string panel: ""
// --- reveal and hide -------------------------------------------------
- readonly property bool hovered: sliverHit.containsMouse || clock.hovered || status.hovered || media.hovered
+ readonly property bool hovered: sliverHit.containsMouse || clock.hovered || status.hovered || media.hovered || obs.hovered
property bool shown: false
// A tray menu is a separate popup: moving onto it un-hovers the pills,
@@ -129,6 +129,13 @@ PanelWindow {
// --- dismissal -------------------------------------------------------
+ // OBS quitting with its panel open would leave the island held open by a
+ // pill that no longer exists.
+ Connections {
+ target: Obs
+ function onConnectedChanged() { if (!Obs.connected && win.panel === "obs") win.panel = ""; }
+ }
+
HyprlandFocusGrab {
windows: [win]
active: win.panel !== ""
@@ -153,6 +160,7 @@ PanelWindow {
Region { item: clock; intersection: Intersection.Combine }
Region { item: status; intersection: Intersection.Combine }
Region { item: media.visible ? media : null; intersection: Intersection.Combine }
+ Region { item: obs.visible ? obs : null; intersection: Intersection.Combine }
}
// The visible sliver: neutral at rest, the capture colours while
@@ -181,6 +189,27 @@ PanelWindow {
}
}
+ // Recording: a red pulse over the sliver, steady and dim while paused.
+ // Red alone would not say it: OBS's screen source already lights the
+ // privacy sliver's red segment whenever OBS is open.
+ Rectangle {
+ x: sliver.x
+ y: 0
+ width: sliver.width
+ height: sliver.height
+ radius: 2
+ color: Theme.red
+ visible: Obs.recording
+ property real pulse: 1
+ opacity: Obs.paused ? 0.4 : pulse
+ SequentialAnimation on pulse {
+ running: Obs.recording && !Obs.paused
+ loops: Animation.Infinite
+ NumberAnimation { to: 0.25; duration: 700; easing.type: Easing.InOutSine }
+ NumberAnimation { to: 1; duration: 700; easing.type: Easing.InOutSine }
+ }
+ }
+
MouseArea {
id: sliverHit
x: win.cx - width / 2
@@ -297,4 +326,16 @@ PanelWindow {
y: -height + (win.top + height) * win.reveal
opacity: Math.min(1, win.reveal * 2)
}
+
+ // While OBS runs; right of the status pill, following it as the sound
+ // panel widens it.
+ ObsPill {
+ id: obs
+ visible: Obs.connected
+ panel: win.panel
+ onOpenPanel: win.panel = "obs"
+ x: win.cx - width / 2 + (win.gap * 1.5 + status.width + width / 2) * win.reveal
+ y: -height + (win.top + height) * win.reveal
+ opacity: Math.min(1, win.reveal * 2)
+ }
}