# Sway kiosk session for the thin client. # Installed to /home//.config/sway/config by build-thin-client-iso.sh. # # Every `exec` below inherits the environment set by /usr/local/bin/kiosk-session, # which sources /etc/thinclient-agent/config.env — that is how $DIGEST_WEB_URL gets # here without this file being templated. set $mod Mod4 set $ws_web 1:web set $ws_digest 2:digest set $ws_media 3:media # Workspace names are a contract with thinclient_agent/digest_canvas.py and # thinclient_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@ } input type:touchpad { tap enabled natural_scroll enabled } # --------------------------------------------------------------------------- # Look — no bars, no borders. Primary control is HA/MQTT and wayvnc; the local # display is a media surface, not a desktop. # --------------------------------------------------------------------------- default_border none default_floating_border none hide_edge_borders both gaps inner 0 gaps outer 0 # --------------------------------------------------------------------------- # Remote control # --------------------------------------------------------------------------- # exec_always so a `swaymsg reload` re-establishes it. start-wayvnc refuses to run # until /etc/wayvnc/wayvnc-password has been set on this machine. exec_always /usr/local/bin/start-wayvnc # Now-playing widget. Session-scoped (dies with sway, unlike thinclient-agent) — see # fullscreen-watcher.sh's own comment for why it isn't part of the system service. # Its own PID-file guard makes exec_always safe across `swaymsg reload`. exec_always /usr/local/bin/fullscreen-watcher # Camera gesture control. Session-scoped for the same blast-radius reason as the widget # above, plus a privacy one: the camera must not be open while there is no session whose # pointer it could move. It no-ops both when the image was built without it and when # gesture-config.json still has the default "enabled": false — see the wrapper. exec_always /usr/local/bin/gesture-control # thinclient-agent is NOT started here. systemd owns it (thinclient-agent.service, # enabled by 0700-thinclient-agent.hook.chroot) so that it is up and connected to # Mosquitto whether or not a graphical session ever comes up, and so it survives a # sway restart. Starting it from sway too would give two competing MQTT clients. # --------------------------------------------------------------------------- # Applications # --------------------------------------------------------------------------- # No `assign [app_id=...]` rules here on purpose: both digest-browser and web-browser # (added for the minimal-chrome general-browsing app) launch the same firefox-esr # app_id on different profiles, and `assign` cannot tell those two windows apart — # it would fight thinclient_agent.sway_control.launch_app()'s switch-workspace-then- # launch approach for whichever one it matched. Every launch path, including the one # below, is therefore explicit about its own workspace instead. # Steam Link runs under Xwayland (native Wayland black-screens on wlroots), so it # appears as an X11 class, not a Wayland app_id. assign [class="steamlink"] $ws_media for_window [class="steamlink"] fullscreen enable for_window [app_id="mpv"] fullscreen enable # Guarded so a powered-off container host (or an unset DIGEST_WEB_URL) leaves an # empty workspace instead of hanging the session — Phase 11.10. The explicit # `swaymsg workspace` mirrors launch_app()'s own switch-then-launch order, since this # runs before thinclient-agent's MQTT-driven launches ever fire. exec sh -c '[ -n "$DIGEST_WEB_URL" ] && { swaymsg workspace $ws_digest; /usr/local/bin/digest-browser "$DIGEST_WEB_URL/full.html?detail_level=full"; }' # --------------------------------------------------------------------------- # Idle # --------------------------------------------------------------------------- # Never lock: this is an always-on shared media station, and a lock screen would make # the room's display unusable to anyone who isn't holding a keyboard. Any wayvnc or # local input resumes it. # # After 15 minutes, idle-gallery replaces the old unconditional "blank the panel" # behaviour with a photo slideshow from the gallery SMB share (Phase 11 follow-up) — # but it degrades all the way back to that exact blank-the-panel behaviour itself if # no share is configured, unreachable, or empty, so a freshly-built or offline thin # client behaves exactly as before. See configs/idle-gallery/idle-gallery.sh. exec swayidle -w \ timeout 900 '/usr/local/bin/idle-gallery' \ resume 'swaymsg "output * power on"; /usr/local/bin/idle-gallery stop' # Media playback keeps the screen alive. for_window [class="steamlink"] inhibit_idle focus for_window [app_id="mpv"] inhibit_idle focus for_window [app_id="firefox-esr"] inhibit_idle fullscreen # --------------------------------------------------------------------------- # Local override keys — a fallback for standing in front of the machine, not the # primary control surface. # --------------------------------------------------------------------------- # Maintenance shell. A deliberately obscure chord (not $mod+Return, which is the # ordinary local-terminal key above it) so it is not something a visitor bumps into, # floating so it overlays the kiosk content instead of tiling against it. It only opens # a shell — it does not pause thinclient-agent or anything else, since standing at the # machine already means treating it as a maintenance session; if that turns out to be # too little, tightening it is a config change here, not a new subsystem. 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_web bindsym $mod+2 workspace $ws_digest bindsym $mod+3 workspace $ws_media bindsym $mod+Left focus left bindsym $mod+Right focus right bindsym $mod+Up focus up bindsym $mod+Down focus down bindsym XF86AudioPlay exec playerctl -p mpv,spotifyd play-pause bindsym XF86AudioNext exec playerctl -p mpv,spotifyd next bindsym XF86AudioPrev exec playerctl -p mpv,spotifyd 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: `swaymsg exit` would drop to a black VT, and greetd # would just autologin straight back in. Use SSH or the local terminal to administer. workspace $ws_digest