From e6f97fadd9a0208d9515be8be0c2327cc0d549c5 Mon Sep 17 00:00:00 2001 From: rope Date: Sun, 16 Aug 2026 13:57:53 +0100 Subject: [PATCH] quickshell: read live volume in OSD, drain slider at 0% Co-Authored-By: Claude Opus 5 --- settings/quickshell.nix | 47 ++++++++++++++++++++++++++--------------- 1 file changed, 30 insertions(+), 17 deletions(-) diff --git a/settings/quickshell.nix b/settings/quickshell.nix index db6fa2b..bf9c56d 100644 --- a/settings/quickshell.nix +++ b/settings/quickshell.nix @@ -7004,7 +7004,7 @@ in property string icon: "volume-2" property real value: 0 property color fill: Theme.base0D - + // Takes over the server glance's slot: fixed position, no // dependence on how tall the workspace column has grown. width: Theme.barWidth @@ -7015,11 +7015,11 @@ in y: srvWidget.y + srvWidget.height / 2 - height / 2 opacity: shown ? 1 : 0 visible: opacity > 0.01 - + Behavior on opacity { NumberAnimation { duration: Theme.animContent; easing.type: Easing.OutCubic } } - + function show(ic, v, f) { if (!armed || !isFocused) return; icon = ic; @@ -7028,17 +7028,26 @@ in shown = true; osdTimer.restart(); } - + Timer { id: osdTimer; interval: 1600; onTriggered: osdItem.shown = false } Timer { id: osdArm; interval: 1500; running: true; onTriggered: osdItem.armed = true } - + function showVolume() { // The volume dropdown already shows the level live. if (bar.activeDropdown === volDropdown) return; - show(volWidget.volIcon, volWidget.vol / 100, - volWidget.muted ? Theme.base03 : Theme.base0D); + // Read the audio object, not volWidget's derived + // properties: this runs from the change signal, and + // those bindings haven't re-evaluated yet — they + // still hold the previous level. + const a = volWidget.sink ? volWidget.sink.audio : null; + if (!a) return; + const v = a.volume; + show(a.muted ? "volume-x" + : v >= 0.5 ? "volume-2" + : v > 0 ? "volume-1" : "volume", + v, a.muted ? Theme.base03 : Theme.base0D); } - + Connections { target: volWidget.sink && volWidget.sink.audio ? volWidget.sink.audio : null // `volume` notifies through volumesChanged, not @@ -7047,14 +7056,14 @@ in function onVolumesChanged() { osdItem.showVolume(); } function onMutedChanged() { osdItem.showVolume(); } } - + Connections { target: bar.shellRoot function onOsdBrightness(icon, value) { osdItem.show(icon, value, Theme.base0D); } } - + // Card body so the OSD reads as a surface, not floating // marks on the bar. Scales in from slightly small. Rectangle { @@ -7067,19 +7076,19 @@ in Behavior on scale { NumberAnimation { duration: Theme.animMorph; easing.type: Easing.OutExpo } } - + Column { id: osdCol anchors.centerIn: parent spacing: 6 - + SText { anchors.horizontalCenter: parent.horizontalCenter text: Math.round(Math.max(0, Math.min(1, osdItem.value)) * 100) color: Theme.base04 font.pixelSize: 11 } - + // Vertical track — fill grows upward from the bottom. // PillSlider is horizontal-only, so this is its own // rather than a rotated instance. @@ -7089,12 +7098,16 @@ in height: 96 radius: 6 color: Theme.base02 - + Rectangle { anchors.bottom: parent.bottom width: parent.width - height: Math.max(parent.width, - parent.height * Math.max(0, Math.min(1, osdItem.value))) + // Round cap needs width as a floor, but + // 0% draws nothing so the track reads + // empty. + height: osdItem.value <= 0 ? 0 + : Math.max(parent.width, + parent.height * Math.min(1, osdItem.value)) radius: parent.radius color: osdItem.fill Behavior on height { @@ -7102,7 +7115,7 @@ in } } } - + SIcon { anchors.horizontalCenter: parent.horizontalCenter text: osdItem.icon