174 lines
8.7 KiB
Plaintext
174 lines
8.7 KiB
Plaintext
# 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
|