aboutsummaryrefslogtreecommitdiffstats
path: root/desktop/modules/status/statusctl
AgeCommit message (Collapse)AuthorFilesLines
12 daysfeat(status): report a running game as its own presentation stateDanilo M.1-3/+42
status.gaming is written by the shell's game detector and presentation is the OR of it and the manual file, but statusctl read only the manual half. A game therefore asserted the presentation effects while the waybar pill still read deactivated. Report gaming as a third state, for presentation only. The watch follows status.gaming as well as its own file, and emits only on a real change so an unchanged rewrite draws nothing. Toggle is refused while a game holds the mode: the detector reasserts the file within its poll, so the write would not stick. set stays allowed, the manual half is worth setting for when the game exits. gaming stays out of MODES. The detector owns that file and nothing here may write it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-18feat(status): add a screen lock modeDanilo M.1-1/+1
dnd and presentation were the only modes, and presentation was the sole holder of the Wayland idle inhibitor. That inhibitor is the only thing that stops hypridle's loginctl lock-session at the 600s timeout, so screen locking is on by default and there was no way to turn it off on its own. nolock is stored as "auto-lock disabled" so the file keeps the registry's "missing means off" rule, and the row inverts it so the switch reads as the default: lock on. Presentation now drives nolock the same way it drives dnd, holding the prior value in memory and restoring it on exit, so it needs no second inhibitor and the inhibitor has a single holder. The page sets the disable permanently or for a number of minutes. The deadline and its timer live in the singleton rather than the row because the drawer page is destroyed on close while the effect has to outlive it. The timer is shell-lifetime, the same class of limit as dndBeforePresentation: a restart during a timed disable leaves the lock off until it is toggled, which is safe because the user opted into the disable. The mode governs idle-triggered locking only. The SUPER+l bind and the lock on suspend are separate paths and stay live.
2026-09-17fix(status): read a missing state file as off, not downDanilo M.1-2/+4
statusctl watch reported class "down" for a missing state file and waybar's presentation rule drew a warning for it. That fires on every fresh session, before anything has written a file, which is the normal off state the registry's own invariant describes. The state was meant to flag a dead registry, but a crashed shell leaves a stale present file, not a missing one, so it never caught that case. get already read a missing file as 0; watch now matches it and the down state is gone.
2026-09-15fix(desktop): keep statusctl quiet when the mode file is absentDanilo M.1-6/+6
read_mode() failed on a missing mode file with a shell redirection error, 'statusctl: line 56: .../status.dnd: No such file or directory', printed to stderr on every get/toggle before the file existed and polluting waybar's exec stderr. The '2>/dev/null' sat on the 'tr' command, but the error is the parent shell's input redirection failure, which that redirect cannot suppress. Guard on '[[ -e "$file" ]]' before reading; a missing file still reads as 0, which was always the contract. Mirror the fix into the plan so plan and script agree.
2026-09-15feat(desktop): add the statusctl CLI and its checkDanilo M.1-0/+132
statusctl reads and writes the mode files directly rather than going through the shell, so it works while quickshell is down. Setting a mode that way records the state without firing its effects; the shell sees the change through its own watch and reasserts them. The watch listens on the directory, not the file: an atomic write replaces the file, so a watch held on the old inode dies with it. Same trap the mail watcher hit with Xapian, and the reason moved_to is in the event list. An unknown mode exits non-zero rather than reading as off, so a typo cannot masquerade as a mode that happens to be disabled. The watch loop runs inotifywait through process substitution, held open on fd 3, with the PID captured and trapped on EXIT/TERM/INT. Piped straight into the while loop, inotifywait would be a pipeline sibling rather than a child, so a plain kill on statusctl leaves it running, watching a directory nobody reads anymore. Task 7 wires this CLI into waybar's exec, and waybar kills and respawns exec children on every reload the same plain way, so every reload would otherwise leak another watcher for the rest of the session. Process substitution makes inotifywait a real child whose PID the trap can hold and kill. A SIGKILL still orphans it, since KILL cannot be trapped, but nothing in the described path sends one. A failed rename exits non-zero instead of being swallowed. Reporting success on a write that did not land would leave the caller and the shell disagreeing about the mode, with an orphan temp file as the only trace, and this script is the interface the whole registry is read and written through. Verified against an unwritable directory: exit 1, no orphan left, prior value intact. Reading uses a redirect rather than cat piped into tr, so that an unreadable file falling back to off is explicit rather than a side effect of a pipeline discarding cat's exit status. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A7ThHHh5iTYbVfp3rNAkw2