aboutsummaryrefslogtreecommitdiffstats
path: root/volume-osd/README.md
diff options
context:
space:
mode:
Diffstat (limited to 'volume-osd/README.md')
-rw-r--r--volume-osd/README.md92
1 files changed, 92 insertions, 0 deletions
diff --git a/volume-osd/README.md b/volume-osd/README.md
new file mode 100644
index 0000000..3ef0212
--- /dev/null
+++ b/volume-osd/README.md
@@ -0,0 +1,92 @@
+# volume-osd
+
+An on-screen display for volume, covering both output (speakers) and input
+(microphone). It appears at the bottom of the screen when the level or mute
+state changes, and fades out 1.5 seconds later.
+
+ ┌──────────────────────────────────┐
+ │ 🔊 Output 75% │
+ │ ████████████████░░░░░░░░ │
+ └──────────────────────────────────┘
+
+## Running it
+
+ qs -p .
+
+From Hyprland, to start it with the session:
+
+ exec-once = qs -p ~/Programming/GIT/quickshell/volume-osd
+
+## No keybinds to change
+
+The OSD watches PipeWire rather than being triggered by a hotkey, so existing
+volume binds keep working untouched:
+
+ bind = , XF86AudioRaiseVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%+
+
+Because the source of truth is PipeWire and not the keypress, the OSD also
+appears for volume changed from anywhere else: pavucontrol, a per-application
+slider, or another machine's remote control.
+
+One widget serves both directions. Whichever device changed last is the one
+displayed, with a speaker icon for output and a microphone for input.
+
+Icons are Nerd Font glyphs (speaker and microphone), so the font stack needs a
+Nerd Font available for fallback. Inconsolata Nerd Font Mono, which
+unified-desktop-theme already installs, covers them.
+
+## Frosted glass
+
+The panel is drawn translucent (65% over the Macchiato base) and the blur
+behind it comes from the compositor, not from QML. Hyprland blurs a layer
+surface only when a rule says to, matched on the namespace this window sets
+(`quickshell-volume-osd`):
+
+ hl.layer_rule({
+ name = "blur-volume-osd",
+ match = { namespace = "^(quickshell-volume-osd)$" },
+ blur = true,
+ xray = false,
+ ignore_alpha = 0.1,
+ })
+
+`xray = false` frosts the windows actually behind the OSD rather than jumping
+straight to the wallpaper. `ignore_alpha = 0.1` leaves near-transparent pixels
+unblurred, which keeps the rounded corners from picking up a halo.
+
+Doing it this way costs nothing in the shell: no `MultiEffect`, no live
+blur pass in QML, no offscreen buffer. Without the rule the OSD still works,
+it just renders flat translucent instead of frosted.
+
+## Theme
+
+`Theme.qml` holds the Catppuccin Macchiato palette. The accent is read from
+`~/.cache/wal/udt-accent.rasi`, the file `udt-accent` writes on every wallpaper
+change, and is watched, so the OSD recolours without a restart. Lavender
+(`#b7bdf8`) is the fallback when that file is absent, which is also what makes
+this directory runnable on a machine that has no unified-desktop-theme.
+
+## Two details worth knowing
+
+**A node's volume arrives before it is ready.** When a `PwNode` binds, its
+volume populates and emits a change signal, and that happens while `ready` is
+still false. Those first signals are state being read, not the user turning a
+knob, so `show()` checks `ready` and ignores them, which is why there is no
+OSD at login.
+
+That one check is the whole guard, and it is tempting to add a second. An
+earlier version also swallowed the first change per node, on the assumption
+that the startup values arrived *after* ready. They do not, so the extra guard
+ate the user's first keypress instead: the OSD only appeared from the second
+change onward. If this symptom comes back, trace the signal order before
+adding a filter.
+
+**`PwObjectTracker` is not optional.** PipeWire node properties are only kept
+current while something binds the node. Without the tracker the volume reads
+once and then goes stale, which looks like an OSD that displays a number from
+several changes ago.
+
+## Volume above 100%
+
+PipeWire allows volume over 1.0. The percentage is reported as-is, so it can
+read above 100%, while the bar stops at full rather than overflowing its track.