#!/bin/bash # Start a dedicated X server for the attached kiosk display. /usr/bin/Xorg :0 vt1 -nolisten tcp -keeptty & XPID=$! export DISPLAY=:0 export HOME=/home/archipelago X_READY=false for _ in $(seq 1 30); do if kill -0 "$XPID" 2>/dev/null && xrandr --query >/tmp/archipelago-kiosk-xrandr.txt 2>/dev/null; then X_READY=true break fi sleep 0.5 done if [ "$X_READY" != "true" ]; then echo 'ERROR: Xorg failed to become ready' kill "$XPID" 2>/dev/null || true exit 1 fi KIOSK_SAFE_AREA_X_PX=${ARCHIPELAGO_KIOSK_SAFE_AREA_X_PX:-} KIOSK_SAFE_AREA_Y_PX=${ARCHIPELAGO_KIOSK_SAFE_AREA_Y_PX:-} configure_display() { command -v xrandr >/dev/null 2>&1 || return 0 local output mode internal width height output=$(awk '/ connected/ && $1 !~ /^eDP|^LVDS/{print $1; exit}' /tmp/archipelago-kiosk-xrandr.txt) [ -n "$output" ] || output=$(awk '/ connected/{print $1; exit}' /tmp/archipelago-kiosk-xrandr.txt) [ -n "$output" ] || return 0 mode=$(awk -v out="$output" ' $1 == out { active = 1; next } active && /^[[:space:]]+[0-9]+x[0-9]+/ { if ($0 ~ /\*/) { print $1; exit } if (!first) first = $1 } active && /^[^[:space:]]/ { active = 0 } END { if (first) print first } ' /tmp/archipelago-kiosk-xrandr.txt) [ -n "$mode" ] || mode=1920x1080 # 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 [ "$internal" = "$output" ] || xrandr --output "$internal" --off 2>/dev/null || true done xrandr --output "$output" \ --primary \ --mode "$mode" \ --pos 0x0 \ --scale 1x1 \ --panning 0x0 \ --transform none 2>/dev/null || true width=${mode%x*} height=${mode#*x} case "$width:$height" in *[!0-9:]*|:*) width=1920; height=1080 ;; esac # Browser safe-area fallback for TVs that crop edges. Driver underscan is # preferable, but many Intel HDMI outputs do not expose that property. KIOSK_SAFE_AREA_X_PX=${KIOSK_SAFE_AREA_X_PX:-$((width * 3 / 100))} KIOSK_SAFE_AREA_Y_PX=${KIOSK_SAFE_AREA_Y_PX:-$((height * 3 / 100))} } configure_display xhost +SI:localuser:archipelago 2>/dev/null || true xsetroot -solid black 2>/dev/null || true xset s off 2>/dev/null || true xset -dpms 2>/dev/null || true xset s noblank 2>/dev/null || true pkill -u archipelago -f 'chromium.*localhost' 2>/dev/null || true sleep 1 # GPU vs headless (#36). On a real kiosk display with a GPU, GPU rasterization is # fast. On a GPU-less / headless server (no /dev/dri), --enable-gpu-rasterization # forces GPU paths that fall back to software compositing and SPIN a full core at # ~92% CPU, saturating the node. Detect the GPU and pick safe flags accordingly. if [ -e /dev/dri/card0 ] || [ -e /dev/dri/renderD128 ]; then GPU_FLAGS="--enable-gpu-rasterization --num-raster-threads=2" else GPU_FLAGS="--disable-gpu --num-raster-threads=1" fi while true; do sudo -u archipelago env DISPLAY=:0 HOME=/home/archipelago chromium --kiosk \ --app=http://localhost/kiosk?safe_area_x=${KIOSK_SAFE_AREA_X_PX:-0}\&safe_area_y=${KIOSK_SAFE_AREA_Y_PX:-0} \ --noerrdialogs \ --disable-infobars \ --disable-translate \ --no-first-run \ --check-for-update-interval=31536000 \ --disable-features=TranslateUI,MetricsReporting,AutofillServerCommunication,PasswordManagerEnabled \ --disable-session-crashed-bubble \ --disable-save-password-bubble \ --disable-suggestions-service \ --disable-component-update \ $GPU_FLAGS \ --renderer-process-limit=2 \ --window-size=1920,1080 \ --window-position=0,0 \ --start-fullscreen \ --force-device-scale-factor=1 \ --disable-background-networking \ --disable-background-timer-throttling \ --disable-backgrounding-occluded-windows \ --disable-breakpad \ --disable-metrics \ --disable-metrics-reporting \ --disable-domain-reliability \ --js-flags="--max-old-space-size=128" \ --user-data-dir=/var/lib/archipelago/chromium-kiosk sleep 3 done kill "$XPID" 2>/dev/null || true