Let the idle timings know whether you are plugged in

An idle screen costs a screen on wall power and the rest of your
afternoon on battery, so they should not be the same number. hypridle
has no concept of a power source -- one config, one set of timeouts --
so rather than maintaining two configs and swapping them, panama-idle
builds the single config from whichever key set applies, and IdleLock
rebuilds it when the charger comes or goes. That runs through the same
400ms debounce a settings change uses, so a loose charger cannot
restart hypridle in a loop.

The battery keys fall back to their AC counterparts rather than to the
schema defaults. Without that, unplugging would silently override a
deliberately long timing with a shipped short one, which is the kind
of thing you would notice only by losing work.

A machine with no battery reads none of it and generates exactly what
it generated before. The contract pins that alongside the two obvious
directions, and was checked by sabotaging the detection to confirm it
fails rather than passing vacuously.
This commit is contained in:
Gabriel Brown
2026-08-21 22:18:29 -04:00
parent 3c359f3f7e
commit bc6d63b70f
8 changed files with 187 additions and 8 deletions
+35 -4
View File
@@ -49,10 +49,38 @@ clamp_int() {
printf '%s' "$value"
}
# hypridle has no concept of a power source: one config, one set of timeouts.
# So rather than maintaining two configs and swapping them, the single config
# is regenerated whenever the machine moves between wall power and battery, and
# this decides which set of keys it is built from. IdleLock watches
# Battery.acChanged and calls `apply` for exactly this reason.
#
# A machine with no battery never consults the battery keys at all, which is
# what keeps a desktop's generated config byte-for-byte what it was before any
# of this existed.
on_battery() {
local hw="${PANAMA_PATH:-$HOME/.local/share/Panama}/bin/panama-hw"
[[ -x "$hw" ]] || return 1
"$hw" battery || return 1
! "$hw" ac
}
load() {
blank_min="$(clamp_int "$(read_setting screenBlankMinutes 5)" 0 120 5)"
lock_min="$(clamp_int "$(read_setting lockMinutes 10)" 0 240 10)"
suspend_min="$(clamp_int "$(read_setting suspendMinutes 0)" 0 480 0)"
local suffix=""
if on_battery; then
suffix="Battery"
fi
# The battery variants fall back to their AC counterparts rather than to a
# constant, so a machine whose battery keys were never written still gets
# coherent behavior instead of the schema's shipped shorter timings
# overriding a deliberately long AC setting.
blank_min="$(clamp_int "$(read_setting "screenBlankMinutes$suffix" \
"$(read_setting screenBlankMinutes 5)")" 0 120 5)"
lock_min="$(clamp_int "$(read_setting "lockMinutes$suffix" \
"$(read_setting lockMinutes 10)")" 0 240 10)"
suspend_min="$(clamp_int "$(read_setting "suspendMinutes$suffix" \
"$(read_setting suspendMinutes 0)")" 0 480 0)"
lock_on_sleep="$(read_setting lockOnSleep true)"
[[ "$lock_on_sleep" == "true" || "$lock_on_sleep" == "false" ]] || lock_on_sleep=true
}
@@ -67,6 +95,8 @@ generate() {
{
printf '# Generated by panama-idle from %s\n' "$settings"
printf '# Power source at generation: %s\n' \
"$(on_battery && echo battery || echo 'wall power')"
printf '# Do not edit: it is rewritten whenever the idle settings change.\n'
printf '# The shipped defaults live in the Panama repo at config/dot/hypr/hypridle.conf.\n\n'
@@ -143,9 +173,10 @@ case "${1:-apply}" in
load
managed=false
[[ -f "$dropin" ]] && managed=true
printf '{"managed":%s,"active":"%s","blankMinutes":%s,"lockMinutes":%s,"suspendMinutes":%s,"lockOnSleep":%s,"generated":"%s"}\n' \
printf '{"managed":%s,"active":"%s","powerSource":"%s","blankMinutes":%s,"lockMinutes":%s,"suspendMinutes":%s,"lockOnSleep":%s,"generated":"%s"}\n' \
"$managed" \
"$(systemctl --user is-active hypridle.service 2>/dev/null || printf unknown)" \
"$(on_battery && printf battery || printf ac)" \
"$blank_min" "$lock_min" "$suspend_min" "$lock_on_sleep" "$generated"
;;
*)