diff options
| author | 2026-05-29 11:18:15 +0100 | |
|---|---|---|
| committer | 2026-05-29 11:18:15 +0100 | |
| commit | ec3734c5ef9fcfe97c21cd19f198ec779ab5f052 (patch) | |
| tree | 578d98f90db4a174cc8045482bffa8a065fe724c /dot_local/bin/executable_zellij-inhibit-watcher | |
| parent | 3848d890979bd5fafae92054f85061edf10edff3 (diff) | |
| download | dotfiles-ec3734c5ef9fcfe97c21cd19f198ec779ab5f052.tar.gz dotfiles-ec3734c5ef9fcfe97c21cd19f198ec779ab5f052.tar.bz2 dotfiles-ec3734c5ef9fcfe97c21cd19f198ec779ab5f052.zip | |
refactor(suspend): gate suspend on AC, drop bespoke zellij inhibit
New, simpler suspend policy:
AC plugged in -> never auto-suspends (lid close ignored, idle no-op)
On battery only -> lid close suspends, swayidle suspends at 30 min idle
This replaces the SSH/zellij-aware inhibit machinery with a rule that
matches the user's mental model: if you don't want the machine to
sleep, plug it in. Long-running tasks (builds, downloads, SSH
sessions, headless services) just need AC.
Changes:
* etc/systemd/logind.conf.d/20-lid-ac.conf: set
HandleLidSwitchExternalPower=ignore so logind itself handles the AC
case at the source. No userspace daemon, no race, no rate-limit risk.
* dot_local/bin/on-battery-suspend: tiny POSIX wrapper that exits 0
when any /sys/class/power_supply/{AC,ADP}*/online == 1, else execs
`systemctl suspend`.
* dot_config/systemd/user/swayidle.service: add
`timeout 1800 on-battery-suspend`. Idle suspend now exists, but only
when on battery.
* Delete zellij-inhibit-suspend.{path,service} + watcher script and
remove the entry from systemd-units/user.txt. The .path
re-trigger storm bug is moot because the whole mechanism is gone.
Manual suspends (sway XF86Sleep keybind, sway power submode `s`,
`systemctl suspend` over SSH) still always work regardless of AC --
explicit user intent wins.
Also drop /migrate-podman-to-btrfs.sh from .gitignore; the one-off
migration script has been deleted now that the user has switched their
podman storage to the btrfs driver.
On-host steps to apply:
chezmoi apply -v
systemctl --user daemon-reload
systemctl --user reset-failed zellij-inhibit-suspend.service zellij-inhibit-suspend.path || true
systemctl --user stop zellij-inhibit-suspend.path zellij-inhibit-suspend.service || true
systemctl --user disable zellij-inhibit-suspend.path || true
systemctl --user restart swayidle.service
# logind drop-in is reloaded automatically by the etc deploy script.
Verify:
systemctl status systemd-logind | grep -i lid
loginctl show-session $XDG_SESSION_ID | grep -i lid
# Unplug AC -> close lid -> should suspend.
# Plug AC -> close lid -> nothing happens.
Diffstat (limited to 'dot_local/bin/executable_zellij-inhibit-watcher')
| -rwxr-xr-x | dot_local/bin/executable_zellij-inhibit-watcher | 81 |
1 files changed, 0 insertions, 81 deletions
diff --git a/dot_local/bin/executable_zellij-inhibit-watcher b/dot_local/bin/executable_zellij-inhibit-watcher deleted file mode 100755 index 7537b36..0000000 --- a/dot_local/bin/executable_zellij-inhibit-watcher +++ /dev/null @@ -1,81 +0,0 @@ -#!/bin/sh -# Stay alive while any zellij session exists; hold a systemd-inhibit -# lock only while at least one of those zellij sessions was spawned from -# an SSH context. -# -# Rationale: a zellij session started locally (e.g. from a sway terminal) -# is the user actively sitting in front of the laptop — that should NOT -# inhibit suspend. Only zellij sessions started while SSH'd in deserve -# the lock, so the host stays awake across detach + disconnect but -# normal local-attended suspend still works. -# -# Detection: zellij's daemonised server is exec'd by the client and -# inherits the client's environment. Linux preserves that exec-time -# environment in /proc/<pid>/environ for the life of the process, even -# after the original SSH session is gone. So an "ssh-spawned" zellij is -# one whose environ contains SSH_CONNECTION=. -# -# Lifecycle: the .path unit starts this script when the zellij socket -# directory becomes non-empty. The script then polls and stays alive as -# long as any zellij socket exists, so the .path unit never re-triggers -# the service while zellij is up (which previously caused a start-rate -# limit storm when only local zellij was around). When the last zellij -# exits, this script exits, the service stops, and the .path resumes -# watching for the next session. -set -eu - -poll=${ZELLIJ_INHIBIT_POLL:-15} -sock_dir="${XDG_RUNTIME_DIR:-/run/user/$(id -u)}/zellij" - -has_ssh_zellij() { - pids=$(pgrep -x zellij 2>/dev/null) || return 1 - for pid in $pids; do - [ -r "/proc/$pid/environ" ] || continue - if tr '\0' '\n' <"/proc/$pid/environ" 2>/dev/null | - grep -q '^SSH_CONNECTION='; then - return 0 - fi - done - return 1 -} - -any_zellij_socket() { - [ -d "$sock_dir" ] || return 1 - found=$(ls -A "$sock_dir" 2>/dev/null || true) - [ -n "$found" ] -} - -inhibit_pid= -release_inhibit() { - pid=$inhibit_pid - inhibit_pid= - [ -n "$pid" ] || return 0 - kill "$pid" 2>/dev/null || true - wait "$pid" 2>/dev/null || true -} -trap release_inhibit EXIT INT TERM - -inhibit_alive() { - [ -n "$inhibit_pid" ] || return 1 - kill -0 "$inhibit_pid" 2>/dev/null -} - -acquire_inhibit() { - if inhibit_alive; then return 0; fi - systemd-inhibit \ - --what=sleep:idle:handle-lid-switch \ - --who=zellij \ - --why='Active SSH-spawned zellij sessions' \ - --mode=block \ - sleep infinity & - inhibit_pid=$! -} - -while any_zellij_socket; do - if has_ssh_zellij; then - acquire_inhibit - else - release_inhibit - fi - sleep "$poll" -done |
