Skip to content

Commit 955bd1f

Browse files
committed
volume-osd: add example
1 parent 0cf5fff commit 955bd1f

File tree

3 files changed

+99
-0
lines changed

3 files changed

+99
-0
lines changed

volume-osd/README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# Volume OSD
2+
3+
This is a simple overlay that shows the system volume when it changes using pipewire.
4+
5+
You can run the overlay with `qs -p shell.qml`.
6+
7+
![](./image.png)

volume-osd/image.png

9.18 KB
Loading

volume-osd/shell.qml

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
import QtQuick
2+
import QtQuick.Layouts
3+
import Quickshell
4+
import Quickshell.Services.Pipewire
5+
import Quickshell.Widgets
6+
7+
Scope {
8+
id: root
9+
10+
// Bind the pipewire node so its volume will be tracked
11+
PwObjectTracker {
12+
objects: [ Pipewire.defaultAudioSink ]
13+
}
14+
15+
Connections {
16+
target: Pipewire.defaultAudioSink?.audio
17+
18+
function onVolumeChanged() {
19+
root.shouldShowOsd = true;
20+
hideTimer.restart();
21+
}
22+
}
23+
24+
property bool shouldShowOsd: false
25+
26+
Timer {
27+
id: hideTimer
28+
interval: 1000
29+
onTriggered: root.shouldShowOsd = false
30+
}
31+
32+
// The OSD window will be created and destroyed based on shouldShowOsd.
33+
// PanelWindow.visible could be set instead of using a loader, but using
34+
// a loader will reduce the memory overhead when the window isn't open.
35+
LazyLoader {
36+
active: root.shouldShowOsd
37+
38+
PanelWindow {
39+
// Since the panel's screen is unset, it will be picked by the compositor
40+
// when the window is created. Most compositors pick the current active monitor.
41+
42+
anchors.bottom: true
43+
margins.bottom: screen.height / 5
44+
45+
implicitWidth: 400
46+
implicitHeight: 50
47+
color: "transparent"
48+
49+
// An empty click mask prevents the window from blocking mouse events.
50+
mask: Region {}
51+
52+
Rectangle {
53+
anchors.fill: parent
54+
radius: height / 2
55+
color: "#80000000"
56+
57+
RowLayout {
58+
anchors {
59+
fill: parent
60+
leftMargin: 10
61+
rightMargin: 15
62+
}
63+
64+
IconImage {
65+
implicitSize: 30
66+
source: Quickshell.iconPath("audio-volume-high-symbolic")
67+
}
68+
69+
Rectangle {
70+
// Stretches to fill all left-over space
71+
Layout.fillWidth: true
72+
73+
implicitHeight: 10
74+
radius: 20
75+
color: "#50ffffff"
76+
77+
Rectangle {
78+
anchors {
79+
left: parent.left
80+
top: parent.top
81+
bottom: parent.bottom
82+
}
83+
84+
implicitWidth: parent.width * (Pipewire.defaultAudioSink?.audio.volume ?? 0)
85+
radius: parent.radius
86+
}
87+
}
88+
}
89+
}
90+
}
91+
}
92+
}

0 commit comments

Comments
 (0)