Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
4.0 KiB
Volume Notification Design
Date: 2026-05-11 Status: Approved
Summary
Show a mako notification with the current volume level (or "Muted") whenever the user presses the XF86Audio volume keys. Notifications collapse onto themselves so rapid key presses produce a single updating bubble rather than a stack. Mako's progress-bar render shows the current level visually.
Current Behaviour
niri/config.kdl lines 97–99 wire the media keys directly to pamixer:
XF86AudioRaiseVolume allow-when-locked=true { spawn "pamixer" "-i" "5"; }
XF86AudioLowerVolume allow-when-locked=true { spawn "pamixer" "-d" "5"; }
XF86AudioMute allow-when-locked=true { spawn "pamixer" "-t"; }
Volume changes silently. The waybar pulseaudio widget reflects the new value on its next 5 s poll, but there is no immediate visual feedback at the moment of the keypress — and on the lock screen, no feedback at all (waybar isn't visible).
Target Behaviour
Each volume keypress:
- Adjusts the master sink via
pamixer -i 5/pamixer -d 5/pamixer -t. - Reads the resulting state.
- Fires a
notify-sendwith mako's progress-bar hint, replacing any previous volume notification (no stacking).
| Key | Action | Notification |
|---|---|---|
| XF86AudioRaiseVolume | volume +5% | Volume: NN% with N% progress bar |
| XF86AudioLowerVolume | volume −5% | Volume: NN% with N% progress bar |
| XF86AudioMute | toggle mute | Muted (with 0% bar) when muting; Volume: NN% when unmuting |
Notification timeout: 1500 ms.
Implementation
scripts/volume.sh (new)
#!/bin/bash
case "${1:-}" in
up) pamixer -i 5 ;;
down) pamixer -d 5 ;;
mute) pamixer -t ;;
*) echo "usage: $0 up|down|mute" >&2; exit 1 ;;
esac
if [ "$(pamixer --get-mute)" = "true" ]; then
notify-send -h string:x-canonical-private-synchronous:volume \
-h int:value:0 \
-t 1500 \
"Muted"
else
LEVEL=$(pamixer --get-volume)
notify-send -h string:x-canonical-private-synchronous:volume \
-h int:value:"$LEVEL" \
-t 1500 \
"Volume: ${LEVEL}%"
fi
The string:x-canonical-private-synchronous:volume hint is mako's standard mechanism for "transient" notifications — successive notifications carrying the same synchronous-key replace the previous one in place rather than stacking. Mashing the volume key produces a single updating bubble.
int:value:N makes mako render a progress bar at N% (mako displays this for any notification carrying the value hint).
niri/config.kdl
Replace lines 97–99 with calls to the wrapper:
XF86AudioRaiseVolume allow-when-locked=true { spawn "volume" "up"; }
XF86AudioLowerVolume allow-when-locked=true { spawn "volume" "down"; }
XF86AudioMute allow-when-locked=true { spawn "volume" "mute"; }
allow-when-locked=true stays — the notification is still wanted on the lock screen (the lockscreen appears above mako, but mako's bubble shows briefly when the screen is unlocked, and the volume change itself happens regardless).
install.sh
Append one symlink line in the existing ==> Installing scripts block (after the existing waybar-restart.sh and screenshot.sh lines):
ln -sf "$(pwd)/scripts/volume.sh" ~/.local/bin/volume
Files Touched
| File | Action |
|---|---|
scripts/volume.sh |
created |
niri/config.kdl |
three lines (97–99) modified |
install.sh |
one symlink line appended |
Out of Scope
- Volume changes from other sources (terminal
pamixer, GUI like pavucontrol). Only this wrapper's invocations trigger notifications. A pulseaudio event listener daemon could cover that case but is bigger scope. - Per-app sink-input volumes. Master volume only.
- Variable step sizes (Shift for 1% etc.). Fixed 5% step matches the existing keybinds.
- Microphone toggle (XF86AudioMicMute). Not in current keybinds.
- Custom notification icon. Default mako presentation suffices; icon hint would add machine-specific theming.