aboutsummaryrefslogtreecommitdiffstats
path: root/desktop/modules/status/statusctl
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-09-21 20:13:23 +0200
committerDanilo M. <danix@danix.xyz>2026-09-21 20:13:23 +0200
commit696f3ad4f65a6516549544af13a9646f57ae523e (patch)
tree10004eac68626f413da40c2287dd1838fbb82f86 /desktop/modules/status/statusctl
parent34a6a3cd65370fd31877da0c54abcae15d69d3a4 (diff)
downloadquickshell-696f3ad4f65a6516549544af13a9646f57ae523e.tar.gz
quickshell-696f3ad4f65a6516549544af13a9646f57ae523e.zip
feat(status): report a running game as its own presentation state
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>
Diffstat (limited to 'desktop/modules/status/statusctl')
-rwxr-xr-xdesktop/modules/status/statusctl45
1 files changed, 42 insertions, 3 deletions
diff --git a/desktop/modules/status/statusctl b/desktop/modules/status/statusctl
index 571beef..531951b 100755
--- a/desktop/modules/status/statusctl
+++ b/desktop/modules/status/statusctl
@@ -82,15 +82,34 @@ tooltip() {
case "$1" in
activated) printf '%s: on' "$mode" ;;
deactivated) printf '%s: off' "$mode" ;;
+ gaming) printf '%s: on (game running)' "$mode" ;;
esac
}
+# The shell's game detector owns status.gaming and presentation is the OR of
+# the two, so the CLI has to read it to agree with the shell. It is not a mode
+# in MODES: nothing here may write it, and only presentation is affected.
+gaming_on() {
+ local v=""
+ [[ -e "$DIR/status.gaming" ]] && v="$(tr -d '[:space:]' < "$DIR/status.gaming" 2>/dev/null)"
+ [[ "$v" == "1" ]]
+}
+
# A missing file is the off state, not a distinct condition: read_mode already
# reads it as 0, and this is the same path `get` uses. There is no "down": a
# file cannot report whether a watcher is alive, and a missing one is exactly
# what a fresh session looks like.
+#
+# A running game reports its own state rather than plain activated, so the
+# widget can show why the mode is on and that a click will not turn it off.
state_now() {
- [[ "$(read_mode)" == "1" ]] && printf 'activated' || printf 'deactivated'
+ if [[ "$mode" == "presentation" ]] && gaming_on; then
+ printf 'gaming'
+ elif [[ "$(read_mode)" == "1" ]]; then
+ printf 'activated'
+ else
+ printf 'deactivated'
+ fi
}
case "$action" in
@@ -106,6 +125,15 @@ case "$action" in
esac
;;
toggle)
+ # A running game pins presentation on and the detector reasserts it
+ # within its poll, so a toggle here would flip back on its own. Refuse
+ # it instead of writing a value that does not stick. `set` still works:
+ # it is the explicit verb, and the manual half is worth setting for
+ # when the game exits.
+ if [[ "$mode" == "presentation" ]] && gaming_on; then
+ printf '%s: presentation held on by a running game\n' "${0##*/}" >&2
+ exit 1
+ fi
[[ "$(read_mode)" == "1" ]] && write_mode 0 || write_mode 1
;;
watch)
@@ -123,9 +151,20 @@ case "$action" in
exec 3< <(inotifywait -q -m -e close_write,moved_to,delete --format '%f' "$DIR" 2>/dev/null)
watcher=$!
trap 'kill "$watcher" 2>/dev/null' EXIT TERM INT
+ # Presentation also follows status.gaming, so a game starting or
+ # ending redraws the widget. Emitting only on a real change keeps a
+ # write of an unchanged value from firing a duplicate line.
+ last="$(state_now)"
while read -r changed <&3; do
- [[ "$changed" == "status.$mode" ]] || continue
- emit "$(state_now)"
+ case "$changed" in
+ "status.$mode") ;;
+ status.gaming) [[ "$mode" == "presentation" ]] || continue ;;
+ *) continue ;;
+ esac
+ now="$(state_now)"
+ [[ "$now" == "$last" ]] && continue
+ last="$now"
+ emit "$now"
done
;;
*)