#!/usr/bin/env bash # DRIVE A GUI APPLICATION UNDER CIDER AND CAPTURE WHAT IT DREW. # # WHY THIS IS IN THE REPOSITORY. Every driver that verified an application used to live in the # session scratchpad under /tmp, and on 2026-09-01 systemd-tmpfiles deleted all of it: the drivers, # the status file and every analysis tool, because they were eleven days old and /tmp is swept by # age. The machine had not rebooted. Nothing was recoverable, because scratchpad/ in this repository # is a SYMLINK into that same directory and was never tracked. So the harness lives here now. # # WHAT IT DOES, which is exactly the three criteria and nothing else: # RENDERS a capture at startup, to be LOOKED AT rather than counted # INTERACTIVE a real pointer click and a real key press, through a virtual input device # RESIZABLE the compositor output is resized and the window captured again # # The application runs inside a NESTED compositor, not the user's own: the user's session is a # tiling manager, and a window there gets resized by the manager mid-run, which has silently # invalidated resize measurements before. # # scripts/app-drive.sh --prefix /tmp/cider-sp-1000/prefix \ # --app "/Applications/Swift Publisher 5.app/Contents/MacOS/Swift Publisher 5" # # Captures land in captures// in the repository, NOT in /tmp, for the reason above. set -u REPO=$(cd "$(dirname "$0")/.." && pwd) PREFIX="" APPBIN="" NAME="" SETTLE=${SETTLE:-25} # seconds to let the application draw before the first capture LIMIT=${LIMIT:-120} # hard stop for the whole run # Arguments for the application itself. NSUserDefaults consults the ARGUMENT DOMAIN before the # plist, so APPARGS="-someSetting YES" sets a default that an externally written plist cannot. WIDTH=${WIDTH:-1256} HEIGHT=${HEIGHT:-684} # The resize target. Default is the old subtraction, but it must clear the window MINIMUM or the # capture shows a clipped title bar and reads as a broken resize. See the note at the resize step. RESIZE_W=${RESIZE_W:-$((WIDTH - 256))} RESIZE_H=${RESIZE_H:-$((HEIGHT - 84))} CLICK=${CLICK:-} # "x,y" to click after the first capture, empty to skip # Milliseconds between creating the virtual pointer and pressing, so the guest has seen the seat # capability and attached its listener. See the race described at the click step. CLICK_SETTLE=${CLICK_SETTLE:-1500} TYPE=${TYPE:-} # text to type after the click, empty to skip POST_CLICK=${POST_CLICK:-} # "x,y" to click AFTER typing, when a keyboard exists (#210) # STEPS replaces the fixed CLICK, TYPE, POST_CLICK order with an arbitrary one, which is the only # way to fill two text fields. See the sequencer below for the verbs and the reason (#235). STEPS=${STEPS:-} while [ $# -gt 0 ]; do case "$1" in --prefix) PREFIX="$2"; shift 2 ;; --app) APPBIN="$2"; shift 2 ;; --name) NAME="$2"; shift 2 ;; *) echo "unknown option: $1" >&2; exit 2 ;; esac done [ -n "$PREFIX" ] && [ -n "$APPBIN" ] || { echo "usage: $0 --prefix --app [--name