# Sway kiosk session for the touch panel (docs/project-plan.md Phase 16).
#
# Installed to /home/<KIOSK_USERNAME>/.config/sway/config by build-touch-panel-iso.sh.
# Every `exec` below inherits the environment set by /usr/local/bin/kiosk-session,
# which sources /etc/touchpanel-agent/config.env — that is how $HA_URL gets here
# without this file being templated.
#
# This is a DIFFERENT device from hosts/thin-client: that one is a couch-distance
# media station whose primary control surface is HA/MQTT and wayvnc, deliberately with
# "no bars" (see its config's own comment). This one is touched directly, so the whole
# point is an always-visible on-screen dock a finger can hit — see the eww bar below.

set $mod Mod4
set $ws_spotify 1:spotify
set $ws_home    2:home
set $ws_web     3:web
set $ws_discord 4:discord

# Workspace names are a contract with touchpanel_agent/sway_control.py — changing one
# side means changing the other.

# ---------------------------------------------------------------------------
# Output / input
# ---------------------------------------------------------------------------
output * bg #101014 solid_color

input type:keyboard {
    xkb_layout @KEYBOARD_LAYOUT@
}

# Real touchscreen hardware, not the thin client's couch-distance camera-gesture
# trick: libinput/Wayland surfaces (GTK, Chromium, Firefox) all speak wl_touch
# natively, so taps/scrolls/pinches just work without a pointer-emulation layer —
# when the kernel/udev actually classifies the device as a touchscreen. See
# configs/udev/99-touchscreen-override.rules for the case where it doesn't.
input type:touch {
    map_to_output "*"
}

input type:tablet_tool {
    map_to_output "*"
}

# --- Fallback: some cheap touch controllers report themselves as an absolute-
# position HID mouse instead of a proper touch digitizer (ID_INPUT_MOUSE rather than
# ID_INPUT_TOUCHSCREEN in udev, so libinput hands sway a `type:pointer` device, not a
# `type:touch` one, and every tap becomes a mouse click at that position instead of a
# touch event). Rather than assume this never happens, this block makes that
# degraded mode usable on its own:
#   - accel_profile flat + pointer_accel 0: a touch-emulated pointer's coordinates
#     are already absolute; libinput's normal mouse acceleration curve is tuned for
#     relative motion and would make taps land somewhere other than where the finger
#     is, or make the cursor visibly drift/overshoot before settling.
#   - map_to_output: same coordinate-space fix `type:touch` already gets above,
#     needed here too since this device isn't going through that block.
# See configs/udev/99-touchscreen-override.rules for the real fix (reclassifying the
# device as a touchscreen instead of merely working around it being a pointer), and
# the "Touch input: two tiers" section in README.md for the full picture, including
# why single-touch click-drag (not true multi-touch/pinch) is the ceiling here.
input type:pointer {
    accel_profile flat
    pointer_accel 0
    map_to_output "*"
}

# Hides the cursor after ~1ms of no input instead of leaving a static arrow sitting
# on screen. Irrelevant for real wl_touch input (Wayland never draws a cursor for
# touch events at all) but is what keeps the type:pointer fallback above from looking
# broken — a touch-emulated tap moves the cursor, clicks, and it's gone again before
# anyone would register it as a cursor rather than a tap.
seat seat0 hide_cursor 1

# ---------------------------------------------------------------------------
# Look
# ---------------------------------------------------------------------------
default_border none
default_floating_border none
hide_edge_borders both
gaps inner 0
gaps outer 0

# Reserve a strip at the bottom for the touch dock (bar/app-switcher), so it is
# never covered by, and never steals area from behind, whatever app is on screen.
# :exclusive is the eww window's own setting (configs/eww/eww.yuck) — sway just
# needs to know nothing else should tile into that space, which layer-shell
# exclusivity already guarantees without a `bar {}` block here.

# ---------------------------------------------------------------------------
# Session-scoped helpers
# ---------------------------------------------------------------------------
# touchpanel-agent is NOT started here — see thin-client's identical note. systemd
# owns it so it is reachable over MQTT whether or not a graphical session is up, and
# survives a sway restart. Starting it from sway too would give two competing MQTT
# clients.

# The touch dock (eww bar) and the on-screen keyboard toggle both live for the
# session, not the system, for the same reason the thin client's now-playing widget
# does: they are compositor UI, not device control, and should die with sway rather
# than need their own restart-independent lifecycle.
exec_always eww daemon
exec_always eww open touch-dock

# ---------------------------------------------------------------------------
# Applications
# ---------------------------------------------------------------------------
# No `assign` rules, same reasoning as the thin client: every launch path is explicit
# about its own workspace via touchpanel_agent.sway_control.launch_app(), so a
# separately-matched `assign` rule can't race it.
for_window [app_id="chromium.*"] fullscreen enable
for_window [app_id="spotify"] fullscreen enable
# Discord runs under XWayland, so it lands as an X11 window with a `class`, not a
# native `app_id` — matching on app_id alone would silently never fire.
for_window [class="discord"] fullscreen enable

# HA kiosk, Spotify and (where enabled) Discord all auto-launch at session start —
# this is a fixed panel of three or four apps, not an on-demand surface like the thin
# client's digest/admin workspaces, so there is no "nothing to show yet" state to
# guard against beyond an unset HA_URL.
exec sh -c '[ -n "$HA_URL" ] && { swaymsg workspace $ws_home; /usr/local/bin/ha-kiosk; }'
exec sh -c 'swaymsg workspace $ws_spotify; /usr/local/bin/spotify-launch'
# Discord, on the panels that asked for it (kiosks[].enable_discord). Started at
# session boot rather than on demand for the reason in discord-launch's own header:
# the point is stepping out mid-call, and an app that needs fifteen seconds and a
# login is not something you use on the way past. $ENABLE_DISCORD is not a sway
# variable, so it passes through to sh, which reads it from the environment
# kiosk-session sourced out of /etc/touchpanel-agent/config.env.
exec sh -c '[ "$ENABLE_DISCORD" = "true" ] && { swaymsg workspace $ws_discord; /usr/local/bin/discord-launch; }'
exec swaymsg workspace $ws_home

# ---------------------------------------------------------------------------
# Idle
# ---------------------------------------------------------------------------
# Blank after 10 minutes to save the panel; any touch (or local input) resumes it.
# No lock screen, same reasoning as the thin client: a lock screen would make a wall
# panel unusable to anyone in the room who isn't holding a passcode.
exec swayidle -w \
    timeout 600 'swaymsg "output * power off"' \
    resume     'swaymsg "output * power on"'

for_window [app_id="chromium.*"] inhibit_idle fullscreen
for_window [app_id="spotify"] inhibit_idle fullscreen
# Deliberately NOT inhibiting idle for Discord: a voice call would otherwise hold the
# panel's screen on for an hour in an empty room. The call keeps running with the
# output powered off — sway's idle timeout blanks the display, it does not suspend
# the machine or the audio stream.

# ---------------------------------------------------------------------------
# Local override keys — a fallback for standing in front of the machine (or a
# connected keyboard), not the primary control surface, which is touch + HA/MQTT.
# ---------------------------------------------------------------------------
bindsym $mod+Shift+Ctrl+m exec foot --title maintenance-shell
for_window [title="maintenance-shell"] floating enable, resize set width 800 height 500, move position center

bindsym $mod+Return exec foot
bindsym $mod+q kill
bindsym $mod+f fullscreen toggle
bindsym $mod+Shift+c reload
bindsym $mod+1 workspace $ws_spotify
bindsym $mod+2 workspace $ws_home
bindsym $mod+3 workspace $ws_web
bindsym $mod+4 workspace $ws_discord

bindsym XF86AudioPlay exec playerctl -p spotify play-pause
bindsym XF86AudioNext exec playerctl -p spotify next
bindsym XF86AudioPrev exec playerctl -p spotify previous
bindsym XF86AudioRaiseVolume exec wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%+
bindsym XF86AudioLowerVolume exec wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-
bindsym XF86AudioMute exec wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle

# Deliberately no exit binding — see the thin client's identical note: `swaymsg exit`
# would just drop to a black VT and greetd would autologin straight back in.

workspace $ws_home
