import QtQuick import QtQuick.Layouts import Quickshell import Quickshell.Services.Pipewire import Quickshell.Wayland // Volume OSD that appears on volume change, styled to match the system menus. Scope { id: root readonly property PwNode sink: Pipewire.defaultAudioSink property bool visible: false PwObjectTracker { objects: root.sink ? [root.sink] : [] } Connections { target: root.sink && root.sink.audio ? root.sink.audio : null ignoreUnknownSignals: true function onVolumeChanged() { root.visible = true hideTimer.restart() } function onMutedChanged() { root.visible = true hideTimer.restart() } } Timer { id: hideTimer interval: 2000 onTriggered: root.visible = false } PanelWindow { visible: root.visible // Compositor centers horizontally if only bottom anchor is set anchors.bottom: true margins.bottom: 100 exclusiveZone: 0 implicitWidth: 240 implicitHeight: 64 WlrLayershell.layer: WlrLayer.Overlay exclusionMode: ExclusionMode.Ignore color: Theme.transparent mask: Region {} // Pass-through clicks Squircle { id: card anchors.fill: parent fillColor: Theme.bg strokeColor: Theme.border strokeWidth: 1 cornerRadius: 16 RowLayout { anchors { fill: parent margins: 16 } spacing: 12 IconCircle { size: 32 source: { if (root.sink?.audio?.muted) return "audio-volume-muted" const vol = root.sink?.audio?.volume ?? 0 if (vol <= 0) return "audio-volume-low" if (vol <= 0.33) return "audio-volume-low" if (vol <= 0.66) return "audio-volume-medium" return "audio-volume-high" } active: !(root.sink?.audio?.muted ?? true) } PillSlider { Layout.fillWidth: true value: root.sink?.audio?.volume ?? 0 enabled: false // OSD is for display only } } } } }