#!/bin/sh
# Watches sway for the user leaving Big Picture. Installed to /usr/local/bin/session-watcher.
#
# THIS IS THE "MEDIA APPS ONLY START WHEN YOU LEAVE BIG PICTURE" MECHANISM, HALF TWO.
# Read steam-session's header first — it explains why there are two halves.
#
# The case this one covers: Steam is *still running*, but the user is no longer looking
# at it. "Exit Big Picture mode" (which drops to Steam's desktop client), the remote's
# channel keys, $mod+3, or Home Assistant's Screen select — all of those change the
# focused sway workspace and none of them make the Steam process exit, so steam-session
# never resumes and something else has to notice.
#
# WHY WORKSPACE EVENTS AND NOT WINDOW TITLES
# ------------------------------------------
# The obvious implementation is to poll for a window titled "Steam Big Picture Mode"
# and react when it goes away. That was rejected: the title, the window class and the
# very existence of a separate Big Picture window have all changed across Steam client
# rewrites, and a media session that silently stops appearing after a Steam update is a
# bad failure — it looks like the image is broken, not like a string moved. A sway
# workspace name is a contract this repo owns and can only change by editing the sway
# config and steamtv_agent/sway_control.py together.
#
# Cost: one blocked read on a socket, and a jq per workspace switch. It publishes
# nothing and listens on nothing — the session-mode sensor in Home Assistant is
# steamtv-agent asking sway, not this script pushing anywhere. (Adding an inbound
# listener here would breach the MQTT-is-the-only-control-surface rule; see
# steamtv_agent/mqtt_discovery.py.)
set -eu

WS_STEAM="1:steam"

if ! command -v jq >/dev/null 2>&1; then
  echo "session-watcher: jq is missing; the media session will only start when Steam" >&2
  echo "  itself exits (steam-session's path). Install jq and reload sway." >&2
  exit 1
fi

# `swaymsg -m` streams one JSON object per event line and blocks forever. If sway goes
# away the pipe closes and this exits — which is correct, since sway restarting means
# `exec_always` starts a fresh watcher.
swaymsg -t subscribe -m '["workspace"]' 2>/dev/null | while read -r event; do
  # "focus" is the only change that means the user went somewhere; "init", "empty" and
  # "rename" fire during ordinary window churn and must not trigger a launch.
  change=$(printf '%s' "$event" | jq -r '.change // empty' 2>/dev/null) || continue
  [ "$change" = "focus" ] || continue

  current=$(printf '%s' "$event" | jq -r '.current.name // empty' 2>/dev/null) || continue
  [ -n "$current" ] || continue
  # An `if` rather than `[ … ] && continue`: the && form returns non-zero when the test
  # is false, which under `set -e` would kill the watcher the first time somebody moved
  # to a non-Steam workspace — i.e. exactly once, silently, on the first use.
  if [ "$current" = "$WS_STEAM" ]; then
    continue
  fi

  # No --focus: the user has already chosen where they want to be, and yanking them to
  # the browser workspace because they pressed the channel key would be worse than
  # doing nothing. This only makes sure the apps exist.
  /usr/local/bin/media-session start >/dev/null 2>&1 || true
done
