119 lines
3.7 KiB
Bash
Executable File
119 lines
3.7 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Run playpen inside a throwaway headless Sway and screenshot it.
|
|
#
|
|
# This keeps UI checks out of the developer's real Wayland session: nothing
|
|
# pops up on screen, and it works even while the session is locked.
|
|
#
|
|
# Usage: ./shot.sh OUT.png ["keys to type"] [settle-seconds]
|
|
set -u
|
|
|
|
cd "$(dirname "$0")"
|
|
OUT="${1:-/tmp/playpen-shot.png}"
|
|
KEYS="${2:-}"
|
|
SETTLE="${3:-2}"
|
|
|
|
RUNDIR="$(mktemp -d)"
|
|
trap 'rm -rf "$RUNDIR"' EXIT
|
|
|
|
cat > "$RUNDIR/sway.conf" <<CONF
|
|
output HEADLESS-1 resolution 1200x800
|
|
default_border none
|
|
exec "'$RUNDIR/launch.sh' >'$RUNDIR/app.log' 2>&1"
|
|
CONF
|
|
|
|
# The nix dev shell exports bash functions into the environment. Any /bin/sh
|
|
# the terminal's child spawns tries to import them and spews parse errors that
|
|
# have nothing to do with playpen, so drop them just before exec.
|
|
cat > "$RUNDIR/launch.sh" <<'LAUNCH'
|
|
#!/usr/bin/env bash
|
|
while read -r fn; do unset -f "$fn" 2>/dev/null; done < <(declare -Fx | awk '{print $3}')
|
|
exec "$PLAYPEN_BIN"
|
|
LAUNCH
|
|
chmod +x "$RUNDIR/launch.sh"
|
|
export PLAYPEN_BIN="$PWD/zig-out/bin/playpen"
|
|
|
|
export WLR_BACKENDS=headless
|
|
export WLR_LIBINPUT_NO_DEVICES=1
|
|
# No GPU is available to a headless compositor here, so force software
|
|
# rendering on both the compositor and GTK sides.
|
|
export WLR_RENDERER=pixman
|
|
export LIBGL_ALWAYS_SOFTWARE=1
|
|
export GSK_RENDERER=cairo
|
|
|
|
# WebKit's web process renders through mesa, which the dev shell has already
|
|
# pointed at its own copy; here we only force that mesa down to its software
|
|
# rasterizer, so a web pane paints the same way with or without a GPU.
|
|
export GALLIUM_DRIVER=llvmpipe
|
|
export XDG_RUNTIME_DIR="${XDG_RUNTIME_DIR:-/run/user/$(id -u)}"
|
|
export SWAYSOCK="$RUNDIR/sway.sock"
|
|
# Don't let the app fall back to the real session.
|
|
unset DISPLAY
|
|
unset WAYLAND_DISPLAY
|
|
|
|
for sock in "$XDG_RUNTIME_DIR"/wayland-*; do
|
|
[ -S "$sock" ] && basename "$sock"
|
|
done > "$RUNDIR/pre-sockets" 2>/dev/null || true
|
|
|
|
sway -c "$RUNDIR/sway.conf" >"$RUNDIR/sway.log" 2>&1 &
|
|
SWAY_PID=$!
|
|
|
|
# Wait for the compositor socket before talking to it.
|
|
for _ in $(seq 1 50); do
|
|
[ -S "$SWAYSOCK" ] && break
|
|
sleep 0.2
|
|
done
|
|
|
|
# Sway picks its own socket name, so discover it by diffing the sockets in
|
|
# XDG_RUNTIME_DIR against the ones that existed before we started.
|
|
DISPLAY_NAME=""
|
|
for _ in $(seq 1 50); do
|
|
for sock in "$XDG_RUNTIME_DIR"/wayland-*; do
|
|
case "$sock" in *.lock) continue;; esac
|
|
[ -S "$sock" ] || continue
|
|
name="$(basename "$sock")"
|
|
grep -qx "$name" "$RUNDIR/pre-sockets" && continue
|
|
DISPLAY_NAME="$name"
|
|
break
|
|
done
|
|
[ -n "$DISPLAY_NAME" ] && break
|
|
sleep 0.2
|
|
done
|
|
if [ -z "$DISPLAY_NAME" ]; then
|
|
echo "could not determine wayland display" >&2
|
|
cat "$RUNDIR/sway.log" >&2
|
|
exit 1
|
|
fi
|
|
export WAYLAND_DISPLAY="$DISPLAY_NAME"
|
|
|
|
sleep "$SETTLE"
|
|
|
|
if [ -n "$KEYS" ]; then
|
|
# wtype drops the first keystroke of every invocation while the compositor
|
|
# takes up its freshly uploaded keymap, so burn one on a harmless key.
|
|
wtype -k Shift_L 2>/dev/null || true
|
|
sleep 0.3
|
|
wtype "$KEYS" 2>/dev/null || true
|
|
sleep 1.5
|
|
fi
|
|
|
|
if [ -n "${PLAYPEN_SHOT_DEBUG:-}" ]; then
|
|
echo "--- swaymsg get_tree (apps) ---" >&2
|
|
swaymsg -t get_tree 2>&1 | grep -E '"(app_id|name|pid)"' | head -30 >&2
|
|
echo "--- sway log ---" >&2
|
|
cat "$RUNDIR/sway.log" >&2
|
|
echo "--- app log ---" >&2
|
|
cat "$RUNDIR/app.log" >&2 2>/dev/null || echo "(no app log)" >&2
|
|
fi
|
|
|
|
if ! grim -o HEADLESS-1 "$OUT"; then
|
|
echo "grim -o failed, trying full capture" >&2
|
|
grim "$OUT" || echo "grim failed entirely" >&2
|
|
fi
|
|
|
|
swaymsg exit >/dev/null 2>&1 || kill "$SWAY_PID" 2>/dev/null
|
|
wait "$SWAY_PID" 2>/dev/null
|
|
|
|
echo "wrote $OUT"
|
|
# Surface app-side errors, which sway captures on its stdout.
|
|
grep -iE "error|warn|panic|segfault" "$RUNDIR/sway.log" | grep -v "portal" | head -20 || true
|