From d91c0ab0e9de7ea28df826f0d7962e6aa6d7c9e5 Mon Sep 17 00:00:00 2001 From: Krzysztof kuhy Rudnicki Date: Sat, 25 Jul 2026 19:57:57 +0200 Subject: [PATCH] fix(i3): repair the dead idle-inhibitor autostart and make it a singleton The i3 `exec` line pointed at /home/kuchy/linux-configuration/scripts/utils/turn_off_auto_idle_screen_shutdown.sh - a typo'd home ("kuchy") *and* a path that stopped existing when the repo was reorganised in db6276b. The exec has been failing silently at every login ever since, so the idle inhibitor was simply not running: a controller was connected with no "idle-off" lock held, meaning the screen could blank and lock during controller gaming, which is exactly what the line exists to prevent. Point it at the script's real location. Also make --watch-controller a singleton. It is a long-lived watcher started from an i3 `exec`, and i3 re-runs those on every `i3-msg restart`, so each restart would leave another watcher holding a redundant inhibitor for the rest of the session. One flock, held for the life of the watcher. Verified: the watcher now holds idle-off 1000 kuhy systemd-inhibit idle "game controller connected" and a second invocation declines instead of stacking a second inhibitor. Co-Authored-By: Claude Opus 5 (1M context) --- .../i3-idle-inhibitor-path-2026-07-25.json | 44 +++++++++++++++++++ .../i3-configuration/i3/config | 2 +- .../turn_off_auto_idle_screen_shutdown.sh | 8 ++++ 3 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 docs/superpowers/evidence/i3-idle-inhibitor-path-2026-07-25.json diff --git a/docs/superpowers/evidence/i3-idle-inhibitor-path-2026-07-25.json b/docs/superpowers/evidence/i3-idle-inhibitor-path-2026-07-25.json new file mode 100644 index 00000000..de621a02 --- /dev/null +++ b/docs/superpowers/evidence/i3-idle-inhibitor-path-2026-07-25.json @@ -0,0 +1,44 @@ +{ + "intent": "Restore the idle-inhibitor autostart that has been silently failing at every i3 login, so the screen stops blanking/locking while a game controller is connected, and stop i3 restarts from stacking duplicate watchers.", + "scope": [ + "linux_configuration/scripts/periodic_background/i3-configuration/i3/config", + "linux_configuration/scripts/single_use/utils/turn_off_auto_idle_screen_shutdown.sh", + "Non-goal: no change to what the watcher does once running (the fork-free systemd-inhibit rewrite in fcd3f7e stands)", + "Non-goal: no i3 reload performed - a game was running on DP-0, so the live session was fixed by launching the watcher directly instead" + ], + "changes": [ + "i3 config: the exec pointed at /home/kuchy/linux-configuration/scripts/utils/turn_off_auto_idle_screen_shutdown.sh - a typo'd home ('kuchy', which does not exist) and a path that stopped existing when the repo was reorganised in db6276b. Repointed at the script's real location under linux_configuration/scripts/single_use/utils/.", + "turn_off_auto_idle_screen_shutdown.sh: --watch-controller now takes an flock on $XDG_RUNTIME_DIR/idle-off-watch.lock for the life of the watcher and declines to start if one is already running. i3 re-runs its exec lines on every `i3-msg restart`, so without this each restart left another long-lived watcher holding a redundant inhibitor." + ], + "verification": [ + { + "command": "systemd-inhibit --list | grep idle-off (before the fix)", + "result": "fail", + "evidence": "No idle-off inhibitor held, while /dev/input/js0 was present - i.e. the screen could blank during controller gaming. Only rtkit/upower/xss-lock inhibitors were listed." + }, + { + "command": "bash turn_off_auto_idle_screen_shutdown.sh --watch-controller (after the fix)", + "result": "pass", + "evidence": "[idle-off] Holding idle inhibitor (pid 941016) while a controller is connected; systemd-inhibit --list now shows: idle-off 1000 kuhy 941016 systemd-inhibit idle 'game controller connected' block" + }, + { + "command": "second invocation of the same script (singleton check)", + "result": "pass", + "evidence": "[idle-off] Controller watcher already running; not starting a second one. Exit 0, and `systemd-inhibit --list | grep -c idle-off` stays at 1." + }, + { + "command": "pre-commit run --files linux_configuration/scripts/single_use/utils/turn_off_auto_idle_screen_shutdown.sh", + "result": "pass", + "evidence": "All hooks Passed or Skipped, including shellcheck and 'Block polling script anti-patterns'." + } + ], + "risks": [ + "The lock lives in $XDG_RUNTIME_DIR, which is cleared on logout - correct here, since the watcher is per-session anyway. If XDG_RUNTIME_DIR is unset the lock falls back to /tmp, where a stale lock file is harmless because flock releases on process exit.", + "The i3 config change only takes effect on the next i3 restart/login. The running session was fixed by starting the watcher directly, so there is no gap; a future `i3-msg restart` will pick up the corrected path and the singleton guard will prevent a duplicate.", + "The deployed ~/.config/i3/config is a separate copy, not a symlink to this tracked file. Both were updated; if only one had been, the next deploy would have reintroduced the broken path." + ], + "rollback": [ + "git revert the commit, then restore the deployed copy: the pre-change ~/.config/i3/config is backed up in the session scratchpad as i3-config.bak.", + "After rollback, confirm with `systemd-inhibit --list | grep idle-off` that the inhibitor state matches expectations, and kill any running turn_off_auto_idle_screen_shutdown.sh watcher." + ] +} diff --git a/linux_configuration/scripts/periodic_background/i3-configuration/i3/config b/linux_configuration/scripts/periodic_background/i3-configuration/i3/config index 67df4533..475f052a 100644 --- a/linux_configuration/scripts/periodic_background/i3-configuration/i3/config +++ b/linux_configuration/scripts/periodic_background/i3-configuration/i3/config @@ -35,7 +35,7 @@ exec --no-startup-id xss-lock --transfer-sleep-lock -- i3lock --nofork exec --no-startup-id nm-applet # Keep screen awake and unlocked; also treat controller input as activity -exec --no-startup-id bash /home/kuchy/linux-configuration/scripts/utils/turn_off_auto_idle_screen_shutdown.sh --watch-controller +exec --no-startup-id bash /home/kuhy/testsAndMisc/linux_configuration/scripts/single_use/utils/turn_off_auto_idle_screen_shutdown.sh --watch-controller # Use pactl to adjust volume in PulseAudio. set $refresh_i3status killall -SIGUSR1 i3status diff --git a/linux_configuration/scripts/single_use/utils/turn_off_auto_idle_screen_shutdown.sh b/linux_configuration/scripts/single_use/utils/turn_off_auto_idle_screen_shutdown.sh index 7d8bcc85..43a9f697 100755 --- a/linux_configuration/scripts/single_use/utils/turn_off_auto_idle_screen_shutdown.sh +++ b/linux_configuration/scripts/single_use/utils/turn_off_auto_idle_screen_shutdown.sh @@ -270,6 +270,14 @@ main() { persist_with_systemd_logind if [[ $watch_controller == true ]]; then + # Singleton. i3 re-execs its `exec` lines on `i3-msg restart`, and a second + # long-lived watcher would sit there holding a redundant inhibitor for the + # rest of the session. One lock, taken for as long as the watcher lives. + exec 8> "${XDG_RUNTIME_DIR:-/tmp}/idle-off-watch.lock" + if ! flock -n 8; then + log "Controller watcher already running; not starting a second one." + exit 0 + fi log "Controller activity watcher enabled (idle-inhibitor mode)" # Blocks until terminated; releases the inhibitor on exit via its own trap. start_controller_watchers