import QtQuick import QtQuick.Layouts import Quickshell import Quickshell.Services.Pipewire import Quickshell.Widgets import qs import qs.common import qs.common.widgets Scope { id: root // communicate when the volume display should show or not property bool showVolumeDisplay: false // Bind to pipewire's default output node // https://quickshell.org/docs/v0.2.0/types/Quickshell.Services.Pipewire/PwObjectTracker/ PwObjectTracker { objects: [Pipewire.defaultAudioSink] } // Setup a connection to when the volume is changed // https://doc.qt.io/qt-6/qml-qtqml-connections.html Connections { target: Pipewire.defaultAudioSink?.audio function onVolumeChanged() { GlobalStates.osdVolumeOpen = true; hideTimer.restart(); } } // timer after 1 second hide the volume display // https://doc.qt.io/qt-6/qml-qtqml-timer.html Timer { id: hideTimer interval: Config.options.osd.timeout onTriggered: GlobalStates.osdVolumeOpen = false } // loader to create and destroy volume display LazyLoader { active: GlobalStates.osdVolumeOpen // according to documentation in Quickshell, PanelWindow is not an uncreatable-type, despite the qmlls language server's warning // I assume that the yelling is because there is a discrepancy between implementation and language server PanelWindow { // it seems you can use {} if you want multiple under a category // the example for that is in Bar.qml anchors.bottom: true // similar discrepancy it seems margins.bottom: screen.height / 5 exclusiveZone: 0 implicitHeight: 50 implicitWidth: 400 color: "transparent" // prevents clicking on volume display mask: Region {} Rectangle { anchors.fill: parent radius: height / 2 color: Appearance?.colors.colLayer1 // requires QtQuick.Layouts RowLayout { anchors { fill: parent leftMargin: 10 rightMargin: 15 } MaterialSymbol { iconSize: 30 visible: true fill: 1 // comes from Quickshell.Widgets text: "volume_up" color: Appearance.m3colors.m3onSecondaryContainer } Rectangle { Layout.fillWidth: true implicitHeight: 20 radius: height / 2 color: Appearance?.m3colors.m3secondaryContainer Rectangle { anchors { left: parent.left top: parent.top bottom: parent.bottom } color: Appearance.colors.colPrimary // What I presume is that the first ? is to check if defaultAudioSink is there, and if not, the ?? marks the returning value in place implicitWidth: parent.width * (Pipewire.defaultAudioSink?.audio.volume ?? 0) radius: parent.radius } } } } } } }