#!/usr/bin/env bash set -euo pipefail repo_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" component="$repo_dir/config/dot/quickshell/modules/settings/DisplayArrangement.qml" page="$repo_dir/config/dot/quickshell/modules/settings/DisplaysPage.qml" harness="$repo_dir/config/dot/quickshell/display-arrangement-harness.qml" fail() { printf 'display arrangement contract: %s\n' "$1" >&2 exit 1 } [[ -f "$component" ]] || fail 'DisplayArrangement.qml is missing' for contract in \ 'required property var displayService' \ 'property var draftLayout:' \ 'function setDraftPosition(' \ 'function nudge(' \ 'function applyDraft(' \ 'function makePrimary(' \ 'Accessible.name: "Move "' \ 'DragHandler {' \ 'Keys.onPressed:'; do rg -Fq "$contract" "$component" \ || fail "arrangement interaction is missing: $contract" done rg -Fq 'DisplayArrangement {' "$page" \ || fail 'Displays page does not expose the arrangement canvas' rg -Fq 'visible: Displays.monitors.length > 1' "$page" \ || fail 'arrangement is shown for a single display' state_home="$(mktemp -d /tmp/panama-display-arrangement-state.XXXXXX)" harness_pid="" cleanup() { [[ "$harness_pid" =~ ^[0-9]+$ ]] && kill "$harness_pid" 2>/dev/null || true rm -rf "$state_home" } trap cleanup EXIT XDG_STATE_HOME="$state_home" qs -p "$harness" --daemonize >/dev/null for _ in $(seq 1 60); do harness_pid="$(qs list --all 2>/dev/null | awk -v expected="$harness" ' /^Instance / {pid=""} /^[[:space:]]*Process ID:/ {pid=$3} /^[[:space:]]*Config path:/ {path=$0; sub(/^[[:space:]]*Config path: /,"",path); if(path==expected) print pid}' | head -1)" [[ "$harness_pid" =~ ^[0-9]+$ ]] \ && XDG_STATE_HOME="$state_home" qs -p "$harness" ipc --pid "$harness_pid" show 2>/dev/null \ | rg -q '^target display-arrangement-test$' && break sleep 0.1 done [[ "$harness_pid" =~ ^[0-9]+$ ]] || fail 'arrangement harness did not start' ipc() { XDG_STATE_HOME="$state_home" qs -p "$harness" ipc --pid "$harness_pid" \ call display-arrangement-test "$@" } wide="$(ipc status 800)" narrow="$(ipc status 500)" for snapshot in "$wide" "$narrow"; do jq -e '(.rects | length) == 2 and .scale > 0 and (.rects[0].width / .rects[0].height - 1.5 | fabs) < 0.0001 and (.rects[1].width / .rects[1].height - (2560 / 1440) | fabs) < 0.0001' \ <<<"$snapshot" >/dev/null \ || fail "canvas lost monitor geometry at a supported width: $snapshot" done drag="$(ipc dragFixture)" jq -e '.[0].x == 0 and .[1].x == 3000' <<<"$drag" >/dev/null \ || fail "drag release did not snap and apply the complete layout: $drag" keyboard="$(ipc keyboardFixture)" jq -e '.afterArrow == 2990 and .afterShiftArrow == 2890' <<<"$keyboard" >/dev/null \ || fail "keyboard movement did not use 10/100 logical-pixel steps: $keyboard" primary="$(ipc primaryFixture)" jq -e '. == [ {"name":"DP-2","x":-3000,"y":0,"primary":false}, {"name":"HDMI-A-1","x":0,"y":0,"primary":true} ]' <<<"$primary" >/dev/null \ || fail "Make primary did not normalize the selected output to 0,0: $primary" printf 'display arrangement contract: PASS\n'