import QtQuick import QtQuick.Layouts import Quickshell import Quickshell.Io import Quickshell.Services.Pipewire import Quickshell.Widgets import qs.Modules Item { id: root implicitWidth: expanded ? 300 : 150 implicitHeight: 100 property bool expanded: false Behavior on implicitWidth { NumberAnimation { duration: 300 easing.type: Easing.OutCubic } } PwObjectTracker { objects: [ Pipewire.defaultAudioSink ] } PwObjectTracker { objects: [ Pipewire.defaultAudioSource ] } Rectangle { anchors.fill: parent radius: height / 2 color: "#40000000" // Background circle Rectangle { anchors.centerIn: parent width: parent.width height: parent.height radius: width / 2 color: "transparent" border.color: "#30ffffff" border.width: 0 } MouseArea { id: mouseArea anchors.fill: parent hoverEnabled: true cursorShape: Qt.PointingHandCursor onEntered: root.expanded = true onExited: root.expanded = false RowLayout { anchors { fill: parent leftMargin: 10 rightMargin: 15 } Text { Layout.alignment: Qt.AlignVCenter font.family: "Material Symbols Rounded" font.pixelSize: 18 text: "\ue050" // volume_up icon color: "#ffffff" } Rectangle { Layout.fillWidth: true implicitHeight: 4 radius: 20 color: "#50ffffff" Rectangle { id: sinkVolumeBar anchors { left: parent.left top: parent.top bottom: parent.bottom } implicitWidth: parent.width * (Pipewire.defaultAudioSink?.audio.volume ?? 0) radius: parent.radius color: "#ffffff" } Rectangle { id: sinkGrabber visible: root.expanded opacity: root.expanded ? 1 : 0 width: 12 height: 12 radius: width / 2 color: sinkVolumeMouseArea.containsMouse || sinkVolumeMouseArea.pressed ? "#ffffff" : "#aaaaaa" border.color: "#40000000" border.width: 2 anchors.verticalCenter: parent.verticalCenter x: sinkVolumeBar.width - width / 2 Behavior on opacity { NumberAnimation { duration: 300 } } Behavior on color { ColorAnimation { duration: 150 } } } MouseArea { id: sinkVolumeMouseArea anchors.fill: parent anchors { leftMargin: 0 rightMargin: 0 topMargin: -10 bottomMargin: -10 } cursorShape: Qt.PointingHandCursor hoverEnabled: true onPressed: function(mouse) { var newVolume = Math.max(0, Math.min(1, mouse.x / width)) if (Pipewire.defaultAudioSink?.audio) { Pipewire.defaultAudioSink.audio.volume = newVolume } } onPositionChanged: function(mouse) { if (pressed) { var newVolume = Math.max(0, Math.min(1, mouse.x / width)) if (Pipewire.defaultAudioSink?.audio) { Pipewire.defaultAudioSink.audio.volume = newVolume } } } } } Text { Layout.alignment: Qt.AlignVCenter font.family: "Material Symbols Rounded" font.pixelSize: 18 text: "\ue029" color: (Pipewire.defaultAudioSource?.audio.muted ?? false) ? "#ff4444" : "#ffffff" } Rectangle { Layout.fillWidth: true implicitHeight: 4 radius: 20 color: "#50ffffff" Rectangle { id: sourceVolumeBar anchors { left: parent.left top: parent.top bottom: parent.bottom } implicitWidth: parent.width * (Pipewire.defaultAudioSource?.audio.volume ?? 0) radius: parent.radius color: (Pipewire.defaultAudioSource?.audio.muted ?? false) ? "#ff4444" : "#ffffff" } Rectangle { id: sourceGrabber visible: root.expanded opacity: root.expanded ? 1 : 0 width: 12 height: 12 radius: width / 2 color: sourceVolumeMouseArea.containsMouse || sourceVolumeMouseArea.pressed ? "#ffffff" : "#aaaaaa" border.color: "#40000000" border.width: 2 anchors.verticalCenter: parent.verticalCenter x: sourceVolumeBar.width - width / 2 Behavior on opacity { NumberAnimation { duration: 300 } } Behavior on color { ColorAnimation { duration: 150 } } } MouseArea { id: sourceVolumeMouseArea anchors.fill: parent anchors { leftMargin: 0 rightMargin: 0 topMargin: -10 bottomMargin: -10 } cursorShape: Qt.PointingHandCursor hoverEnabled: true onPressed: function(mouse) { var newVolume = Math.max(0, Math.min(1, mouse.x / width)) if (Pipewire.defaultAudioSource?.audio) { Pipewire.defaultAudioSource.audio.volume = newVolume } } onPositionChanged: function(mouse) { if (pressed) { var newVolume = Math.max(0, Math.min(1, mouse.x / width)) if (Pipewire.defaultAudioSource?.audio) { Pipewire.defaultAudioSource.audio.volume = newVolume } } } } } } } Process { id: pavucontrolProc command: ["pavucontrol"] running: false } } }