Give Sound the whole story, and keep the buttons inside the card
Claude-Session: https://claude.ai/code/session_01Ms2FbjQy31TVf3CEvQhGM8
This commit is contained in:
@@ -94,6 +94,13 @@ elif [[ $1 == "status" ]]; then
|
||||
fi
|
||||
SH
|
||||
|
||||
cat >"$scratch/bin/pw-play" <<'SH'
|
||||
#!/bin/bash
|
||||
printf 'pw-play' >>"$OSD_TEST_LOG"
|
||||
printf ' <%s>' "$@" >>"$OSD_TEST_LOG"
|
||||
printf '\n' >>"$OSD_TEST_LOG"
|
||||
SH
|
||||
|
||||
cat >"$scratch/bin/qs" <<'SH'
|
||||
#!/bin/bash
|
||||
printf 'qs' >>"$OSD_TEST_LOG"
|
||||
@@ -104,10 +111,31 @@ SH
|
||||
|
||||
chmod +x "$scratch/bin/"*
|
||||
|
||||
# The blip and the over-amplification limit are both read out of Panama's own
|
||||
# settings.json, so every run below gets its own config root. Without this the
|
||||
# helper would read Gabriel's real preferences and the assertions would pass or
|
||||
# fail depending on which switches he happens to have on.
|
||||
blip_sound="$scratch/blip.oga"
|
||||
: >"$blip_sound"
|
||||
mkdir -p "$scratch/config-default"
|
||||
|
||||
# Write a settings.json for one run. No arguments means no file at all, which
|
||||
# is what a fresh install looks like: the helper must fall back to the schema
|
||||
# defaults rather than treating an absent file as an error.
|
||||
settings_root() {
|
||||
local name="$1" body="${2:-}" root="$scratch/config-$name"
|
||||
rm -rf "$root"
|
||||
mkdir -p "$root/panama"
|
||||
[[ -n "$body" ]] && printf '%s\n' "$body" >"$root/panama/settings.json"
|
||||
printf '%s' "$root"
|
||||
}
|
||||
|
||||
run_helper() {
|
||||
local runtime="${OSD_RUNTIME_DIR:-$scratch/runtime-default}"
|
||||
mkdir -p "$runtime"
|
||||
PATH="$scratch/bin:$PATH" OSD_TEST_LOG="$log" \
|
||||
XDG_CONFIG_HOME="${OSD_CONFIG_HOME:-$scratch/config-default}" \
|
||||
PANAMA_OSD_BLIP_SOUND="${OSD_BLIP_SOUND:-$blip_sound}" \
|
||||
OSD_TEST_FAIL_QS="${OSD_TEST_FAIL_QS:-false}" \
|
||||
PANAMA_OSD_STRICT="${PANAMA_OSD_STRICT:-false}" \
|
||||
PANAMA_OSD_BRIGHTNESS_HELPER="$scratch/bin/panama-brightness" \
|
||||
@@ -132,6 +160,31 @@ assert_line() {
|
||||
}
|
||||
}
|
||||
|
||||
# The blip is backgrounded and never waited on -- deliberately, so it cannot sit
|
||||
# between the key press and the OSD. Which means the line may land after the
|
||||
# helper has already exited, and asserting it needs a moment rather than an
|
||||
# instant. Waiting here also keeps a slow blip from bleeding into the next
|
||||
# case's freshly truncated log.
|
||||
await_line() {
|
||||
local expected="$1"
|
||||
for _ in $(seq 1 60); do
|
||||
grep -Fqx -- "$expected" "$log" && return 0
|
||||
sleep 0.05
|
||||
done
|
||||
printf 'osd helper contract: missing call\n%s\nactual:\n' "$expected" >&2
|
||||
cat "$log" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
refute_line() {
|
||||
local unexpected="$1" why="$2"
|
||||
if grep -Fq -- "$unexpected" "$log"; then
|
||||
printf 'osd helper contract: %s\nunexpected: %s\nactual:\n' "$why" "$unexpected" >&2
|
||||
cat "$log" >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
: >"$log"
|
||||
run_helper volume up 6
|
||||
assert_line 'wpctl <set-volume> <-l> <1> <@DEFAULT_AUDIO_SINK@> <6%+>'
|
||||
@@ -148,6 +201,86 @@ WPCTL_OUTPUT='Volume: 0.72 [MUTED]' run_helper microphone toggle
|
||||
assert_line 'wpctl <set-mute> <@DEFAULT_AUDIO_SOURCE@> <toggle>'
|
||||
assert_line 'qs <ipc> <call> <osd> <progress> <microphone-muted> <72> <100> <Muted>'
|
||||
|
||||
# ── Over-amplification: the ceiling is a setting, not a constant ─────────────
|
||||
# `wpctl set-volume` clamps to 1.0 unless told otherwise, and it clamps the
|
||||
# *result* -- so the limit has to be on the down step too. Without it, coming
|
||||
# down from 130% would snap to 100% instead of stepping to 124%, which reads as
|
||||
# the slider jumping on its own.
|
||||
: >"$log"
|
||||
OSD_CONFIG_HOME="$(settings_root overamp '{"overAmplification": true}')" \
|
||||
run_helper volume up 6
|
||||
assert_line 'wpctl <set-volume> <-l> <1.5> <@DEFAULT_AUDIO_SINK@> <6%+>'
|
||||
|
||||
: >"$log"
|
||||
OSD_CONFIG_HOME="$(settings_root overamp '{"overAmplification": true}')" \
|
||||
run_helper volume down 6
|
||||
assert_line 'wpctl <set-volume> <-l> <1.5> <@DEFAULT_AUDIO_SINK@> <6%->'
|
||||
|
||||
# The microphone is not part of the bargain: no amount of gain past 100% makes
|
||||
# a capture device better, and the Sound page's input slider stays 0-100 to
|
||||
# match.
|
||||
: >"$log"
|
||||
OSD_CONFIG_HOME="$(settings_root overamp '{"overAmplification": true}')" \
|
||||
run_helper microphone up 6
|
||||
assert_line 'wpctl <set-volume> <-l> <1> <@DEFAULT_AUDIO_SOURCE@> <6%+>'
|
||||
refute_line '<-l> <1.5> <@DEFAULT_AUDIO_SOURCE@>' \
|
||||
'over-amplification leaked onto the microphone'
|
||||
|
||||
: >"$log"
|
||||
OSD_CONFIG_HOME="$(settings_root plain '{"overAmplification": false}')" \
|
||||
run_helper volume up 6
|
||||
assert_line 'wpctl <set-volume> <-l> <1> <@DEFAULT_AUDIO_SINK@> <6%+>'
|
||||
|
||||
# A settings file that predates the key, and a settings file that is not JSON
|
||||
# at all, both mean "off" rather than "no volume keys work today".
|
||||
: >"$log"
|
||||
OSD_CONFIG_HOME="$(settings_root nokey '{"barBackdrop": true}')" run_helper volume up 6
|
||||
assert_line 'wpctl <set-volume> <-l> <1> <@DEFAULT_AUDIO_SINK@> <6%+>'
|
||||
|
||||
: >"$log"
|
||||
OSD_CONFIG_HOME="$(settings_root broken '{not json')" run_helper volume up 6
|
||||
assert_line 'wpctl <set-volume> <-l> <1> <@DEFAULT_AUDIO_SINK@> <6%+>'
|
||||
assert_line 'qs <ipc> <call> <osd> <progress> <volume> <58> <100> <58%>'
|
||||
|
||||
# ── The volume blip ─────────────────────────────────────────────────────────
|
||||
# Default on, per the schema, so a settings.json that has never been written
|
||||
# still clicks. Fire-and-forget: the blip must never gate the OSD.
|
||||
: >"$log"
|
||||
run_helper volume up 6
|
||||
await_line "pw-play <$blip_sound>"
|
||||
assert_line 'qs <ipc> <call> <osd> <progress> <volume> <58> <100> <58%>'
|
||||
|
||||
: >"$log"
|
||||
run_helper volume down 6
|
||||
await_line "pw-play <$blip_sound>"
|
||||
|
||||
: >"$log"
|
||||
WPCTL_OUTPUT='Volume: 0.58' run_helper volume toggle
|
||||
await_line "pw-play <$blip_sound>"
|
||||
|
||||
: >"$log"
|
||||
OSD_CONFIG_HOME="$(settings_root silent '{"volumeChangeBlip": false}')" \
|
||||
run_helper volume up 6
|
||||
refute_line 'pw-play' 'the blip played with volumeChangeBlip off'
|
||||
assert_line 'qs <ipc> <call> <osd> <progress> <volume> <58> <100> <58%>'
|
||||
|
||||
# Brightness and the microphone are not volume changes.
|
||||
: >"$log"
|
||||
run_helper brightness up 5
|
||||
refute_line 'pw-play' 'a brightness step played the volume blip'
|
||||
|
||||
: >"$log"
|
||||
WPCTL_OUTPUT='Volume: 0.72' run_helper microphone up 6
|
||||
refute_line 'pw-play' 'a microphone step played the volume blip'
|
||||
|
||||
# A distribution without the freedesktop sound theme has no file to play. That
|
||||
# is a silent desktop, not a broken volume key.
|
||||
: >"$log"
|
||||
OSD_BLIP_SOUND="$scratch/nothing-here.oga" run_helper volume up 6
|
||||
refute_line 'pw-play' 'the blip ran against a file that does not exist'
|
||||
assert_line 'wpctl <set-volume> <-l> <1> <@DEFAULT_AUDIO_SINK@> <6%+>'
|
||||
assert_line 'qs <ipc> <call> <osd> <progress> <volume> <58> <100> <58%>'
|
||||
|
||||
: >"$log"
|
||||
run_helper brightness up 5
|
||||
assert_line 'brightnessctl <-m> <-c> <backlight>'
|
||||
|
||||
Reference in New Issue
Block a user