fix(kiosk): correct --window-size to DIPs + panel-derived layout target

The kiosk window was sized in physical pixels, but Chromium interprets
--window-size in DIPs: with any device-scale > 1 the window painted
scale-times larger than the panel, and with no window manager in the
kiosk X session --kiosk/--start-fullscreen could not snap it back. On a
4K TV at scale 3 that meant an 11520x6480 window — 9x the panel area —
which blew the compositor tile-memory budget ("tile memory limits
exceeded, some content may not draw") and froze the screen on the last
painted frame; smaller scales cropped content off the right/bottom.

- Size the window in DIPs (panel / scale) so DIPs x scale = the panel.
- Panels >=2560 wide now target a 1920-wide layout (4K -> scale 2.0,
  validated on the Framework's 72" 4K TV: spacious desktop layout at 2x
  sharpness); smaller panels keep the 1280 target (1080p TV -> 1.5).
- Optional ARCHIPELAGO_KIOSK_MAX_WIDTH cap: drop to the best <=N-wide
  xrandr mode for weak hardware (TV upscales instead of us rasterizing).
- Source /etc/archipelago/kiosk-display.conf so the upcoming Settings
  display-resolution picker can manage these knobs per node.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
archipelago 2026-07-21 12:46:15 -04:00
parent 918b0275a9
commit be5122048b

View File

@ -22,6 +22,11 @@ if [ "$X_READY" != "true" ]; then
exit 1
fi
# Settings-managed display overrides (system.kiosk-display.set writes this
# file, then restarts the kiosk): may set ARCHIPELAGO_KIOSK_SCALE,
# ARCHIPELAGO_KIOSK_TARGET_CSS_WIDTH or ARCHIPELAGO_KIOSK_MAX_WIDTH.
[ -f /etc/archipelago/kiosk-display.conf ] && . /etc/archipelago/kiosk-display.conf
KIOSK_SAFE_AREA_X_PX=${ARCHIPELAGO_KIOSK_SAFE_AREA_X_PX:-}
KIOSK_SAFE_AREA_Y_PX=${ARCHIPELAGO_KIOSK_SAFE_AREA_Y_PX:-}
@ -54,6 +59,25 @@ configure_display() {
' /tmp/archipelago-kiosk-xrandr.txt)
[ -n "$mode" ] || mode=1920x1080
# Optional resolution cap for weak hardware: ARCHIPELAGO_KIOSK_MAX_WIDTH=1920
# drops a 4K panel to its best <=1920-wide mode (the TV upscales) so the
# software rasterizer paints 1/4 the pixels. Off by default — native mode
# is sharp and fits the tile budget now that --window-size is in DIPs.
local max_w=${ARCHIPELAGO_KIOSK_MAX_WIDTH:-0}
if [ "$max_w" -gt 0 ] 2>/dev/null && [ "${mode%x*}" -gt "$max_w" ] 2>/dev/null; then
local capped
capped=$(awk -v out="$output" -v maxw="$max_w" '
$1 == out { active = 1; next }
active && /^[[:space:]]+[0-9]+x[0-9]+/ {
split($1, wh, "x")
if (wh[1] + 0 <= maxw && wh[1] + 0 > best_w) { best_w = wh[1] + 0; best = $1 }
}
active && /^[^[:space:]]/ { active = 0 }
END { if (best) print best }
' /tmp/archipelago-kiosk-xrandr.txt)
[ -n "$capped" ] && mode=$capped
fi
# Kiosk should use one native output. A spanning desktop makes Chromium land
# on the laptop panel or stretch across both outputs.
for internal in $(awk '/ connected/ && $1 ~ /^eDP|^LVDS/{print $1}' /tmp/archipelago-kiosk-xrandr.txt); do
@ -90,9 +114,17 @@ configure_display
# panel becomes a 3840px-wide viewport and the UI renders tiny — and a
# keyboard-less kiosk can't zoom. Derive Chromium's device-scale-factor from
# the detected panel width so the *effective* CSS viewport lands near a
# comfortable across-the-room target, scaling the whole UI up on big screens:
# 1920x1080 -> 1.50 | 2560x1440 -> 2.00 | 3840x2160 -> 3.00 (clamped 1.0-3.0)
KIOSK_TARGET_CSS_WIDTH=${ARCHIPELAGO_KIOSK_TARGET_CSS_WIDTH:-1280}
# comfortable target. Panels >=2560 wide get a 1920-wide layout (4K -> scale
# 2.0 — user-validated on a 72" TV: spacious desktop layout, 2x sharp);
# smaller panels get a 1280-wide layout (1920 -> 1.50, laptops -> 1.0).
if [ -z "${ARCHIPELAGO_KIOSK_TARGET_CSS_WIDTH:-}" ]; then
if [ "$KIOSK_MODE_W" -ge 2560 ] 2>/dev/null; then
ARCHIPELAGO_KIOSK_TARGET_CSS_WIDTH=1920
else
ARCHIPELAGO_KIOSK_TARGET_CSS_WIDTH=1280
fi
fi
KIOSK_TARGET_CSS_WIDTH=$ARCHIPELAGO_KIOSK_TARGET_CSS_WIDTH
if [ -n "${ARCHIPELAGO_KIOSK_SCALE:-}" ]; then
KIOSK_SCALE=$ARCHIPELAGO_KIOSK_SCALE
else
@ -100,6 +132,14 @@ else
'BEGIN{if(t<=0)t=1280; s=w/t; s=int(s*4+0.5)/4; if(s<1)s=1; if(s>3)s=3; printf "%.2f", s}')
fi
# Chromium's --window-size is in DIPs (CSS px), not physical pixels: at scale S
# the window paints S x larger. This X session has no window manager, so
# --kiosk/--start-fullscreen cannot snap an oversized window back to the panel
# — it just hangs off the right/bottom edges (content cropped, background art
# offscreen). Size the window in DIPs so DIPs x scale = the panel exactly.
KIOSK_WIN_W=$(awk -v w="$KIOSK_MODE_W" -v s="$KIOSK_SCALE" 'BEGIN{printf "%d", w/s}')
KIOSK_WIN_H=$(awk -v h="$KIOSK_MODE_H" -v s="$KIOSK_SCALE" 'BEGIN{printf "%d", h/s}')
xhost +SI:localuser:archipelago 2>/dev/null || true
xsetroot -solid black 2>/dev/null || true
xset s off 2>/dev/null || true
@ -157,7 +197,7 @@ while true; do
--disable-component-update \
$GPU_FLAGS \
--renderer-process-limit=2 \
--window-size=${KIOSK_MODE_W},${KIOSK_MODE_H} \
--window-size=${KIOSK_WIN_W},${KIOSK_WIN_H} \
--window-position=0,0 \
--start-fullscreen \
--force-device-scale-factor=${KIOSK_SCALE} \