diff --git a/image-recipe/configs/archipelago-kiosk-launcher.sh b/image-recipe/configs/archipelago-kiosk-launcher.sh index 7815578e..9b1afcf5 100644 --- a/image-recipe/configs/archipelago-kiosk-launcher.sh +++ b/image-recipe/configs/archipelago-kiosk-launcher.sh @@ -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} \