* Anchor the webcam overlay to the recorded region, not the monitor Recording a single window on an ultrawide put the camera outside the frame. The overlay is placed twice, and neither placement knows what is being captured: the window rules in default/hypr/apps/webcam-overlay.lua position it from monitor_w/monitor_h, and omarchy-capture-webcam-resize recomputes the same corner from hyprctl monitors. Both resolve to the monitor's bottom-right, so a window anywhere but the far right of the display records without the camera in it, and dragging it into frame by hand is undone by the next resize. The geometry is already known. select_capture_target resolves the picked window to a region rectangle before start_webcam_overlay runs, and a bare click in smart mode snaps that rectangle to the window's own bounds. gpu-screen-recorder takes the region in the compositor's logical coordinate space, which is the same space window moves take, so the value needs no conversion to be reused as an anchor. Publish it for the resize helper, which becomes the single place that positions the overlay. It anchors to the region when one is recorded and falls back to the monitor otherwise, so full-monitor captures, the portal backend, and manual resizes outside a recording all keep their current behaviour. A malformed or empty file falls back the same way. Presets scale from the anchor's height rather than the monitor's, so the camera keeps its proportion of the frame instead of covering a small capture outright. A tall, narrow region cannot fit a preset derived from its height, so widths are capped to the space available and heights follow at the same 8:9 aspect. Placement happens inside start_webcam_overlay rather than after it returns. Correcting the position once that function had returned left the move adjacent to gpu-screen-recorder starting, and the camera was recorded sliding the last stretch into its corner over the opening frames. The overlay is waited for explicitly instead, positioned, and only then does capture start. Waiting for the map is what the blind second was partly guessing at, so the remainder is trimmed to hold the delay before capture where it was. Starting later is not free: it eats the opening words of whatever is being narrated. * Keep the webcam size ladder usable in a narrow region Capping each preset's width to the region separately collapsed small, medium and large onto the same width, so Super + Alt + [ and ] had nothing to step between, and integer division left small taller than medium. Cap the height the presets scale from instead, which shrinks the ladder as a whole and keeps the three sizes ordered and distinct. Cover the anchoring in the test suite: a region the camera follows, the fallback for an unreadable one, and the narrow-region ladder. Point XDG_RUNTIME_DIR at the test's own directory while doing so — the resize helper now reads a region file from there, and the existing geometry assertions would pick up a real one from a live recording. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: David Heinemeier Hansson <david@hey.com> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
228 lines
8.6 KiB
Bash
228 lines
8.6 KiB
Bash
#!/bin/bash
|
|
|
|
set -euo pipefail
|
|
|
|
source "$(dirname "$0")/base-test.sh"
|
|
|
|
tmp_dir=$(mktemp -d)
|
|
trap 'rm -rf "$tmp_dir"' EXIT
|
|
|
|
stub_bin="$tmp_dir/bin"
|
|
mkdir -p "$stub_bin"
|
|
|
|
cat >"$stub_bin/v4l2-ctl" <<'SH'
|
|
#!/bin/bash
|
|
|
|
[[ ${OMARCHY_TEST_NO_WEBCAM:-false} == "true" ]] && exit 0
|
|
|
|
printf '%s\n' "Built-in Webcam: Integrated Camera"
|
|
printf '\t%s\n' "/dev/video0"
|
|
printf '\t%s\n' "/dev/video1"
|
|
printf '\n'
|
|
printf '%s\n' "USB Capture Card: External Camera"
|
|
printf '\t%s\n' "/dev/video2"
|
|
SH
|
|
|
|
cat >"$stub_bin/omarchy-menu-select" <<'SH'
|
|
#!/bin/bash
|
|
|
|
printf '%s\n' "$@" >"$OMARCHY_TEST_MENU_ARGS"
|
|
printf '%s\n' "$3"
|
|
SH
|
|
|
|
cat >"$stub_bin/omarchy-capture-screenrecording" <<'SH'
|
|
#!/bin/bash
|
|
|
|
printf '%s\n' "$@" >"$OMARCHY_TEST_RECORDER_ARGS"
|
|
SH
|
|
|
|
cat >"$stub_bin/omarchy-notification-send" <<'SH'
|
|
#!/bin/bash
|
|
|
|
printf '%s\n' "$@" >"$OMARCHY_TEST_NOTIFICATION_ARGS"
|
|
SH
|
|
|
|
chmod +x "$stub_bin"/*
|
|
|
|
export PATH="$stub_bin:$ROOT/bin:$PATH"
|
|
# The resize helper anchors to a region file here, so keep it out of the real one
|
|
export XDG_RUNTIME_DIR="$tmp_dir"
|
|
export OMARCHY_TEST_MENU_ARGS="$tmp_dir/menu-args"
|
|
export OMARCHY_TEST_RECORDER_ARGS="$tmp_dir/recorder-args"
|
|
export OMARCHY_TEST_NOTIFICATION_ARGS="$tmp_dir/notification-args"
|
|
|
|
if "$ROOT/bin/omarchy-hw-webcam"; then
|
|
pass "webcam hardware detection succeeds when a video device is available"
|
|
else
|
|
fail "webcam hardware detection succeeds when a video device is available"
|
|
fi
|
|
|
|
if OMARCHY_TEST_NO_WEBCAM=true "$ROOT/bin/omarchy-hw-webcam"; then
|
|
fail "webcam hardware detection fails when no video device is available"
|
|
else
|
|
pass "webcam hardware detection fails when no video device is available"
|
|
fi
|
|
|
|
"$ROOT/bin/omarchy-capture-screenrecording-with-webcam"
|
|
|
|
expected_menu_args="$tmp_dir/expected-menu-args"
|
|
printf '%s\n' \
|
|
"Select Webcam" \
|
|
"/dev/video0 Built-in Webcam: Integrated Camera" \
|
|
"/dev/video2 USB Capture Card: External Camera" \
|
|
"--" \
|
|
"--width" \
|
|
"520" \
|
|
"--maxheight" \
|
|
"520" >"$expected_menu_args"
|
|
|
|
if ! cmp -s "$OMARCHY_TEST_MENU_ARGS" "$expected_menu_args"; then
|
|
fail "screenrecording webcam picker passes each webcam as a menu option" "$(diff -u "$expected_menu_args" "$OMARCHY_TEST_MENU_ARGS")"
|
|
fi
|
|
pass "screenrecording webcam picker passes each webcam as a menu option"
|
|
|
|
expected_recorder_args="$tmp_dir/expected-recorder-args"
|
|
printf '%s\n' \
|
|
"--with-desktop-audio" \
|
|
"--with-microphone-audio" \
|
|
"--with-webcam" \
|
|
"--webcam-device=/dev/video2" >"$expected_recorder_args"
|
|
|
|
if ! cmp -s "$OMARCHY_TEST_RECORDER_ARGS" "$expected_recorder_args"; then
|
|
fail "screenrecording webcam picker starts recording with selected device" "$(diff -u "$expected_recorder_args" "$OMARCHY_TEST_RECORDER_ARGS")"
|
|
fi
|
|
pass "screenrecording webcam picker starts recording with selected device"
|
|
|
|
cat >"$stub_bin/hyprctl" <<'SH'
|
|
#!/bin/bash
|
|
|
|
case $1 in
|
|
clients)
|
|
printf '[{"address":"0xabc","title":"%s","size":[%s,%s],"monitor":2}]\n' \
|
|
"${OMARCHY_TEST_CLIENT_TITLE:-WebcamOverlay}" \
|
|
"${OMARCHY_TEST_CLIENT_WIDTH:-178}" \
|
|
"${OMARCHY_TEST_CLIENT_HEIGHT:-200}"
|
|
;;
|
|
monitors)
|
|
printf '[{"id":2,"x":1280,"y":-100,"width":%s,"height":%s,"scale":%s}]\n' \
|
|
"${OMARCHY_TEST_MONITOR_WIDTH:-2560}" \
|
|
"${OMARCHY_TEST_MONITOR_HEIGHT:-1600}" \
|
|
"${OMARCHY_TEST_MONITOR_SCALE:-2}"
|
|
;;
|
|
dispatch)
|
|
printf '%s\n' "$*" >>"$OMARCHY_TEST_HYPRCTL_ARGS"
|
|
;;
|
|
esac
|
|
SH
|
|
chmod +x "$stub_bin/hyprctl"
|
|
|
|
export OMARCHY_TEST_HYPRCTL_ARGS="$tmp_dir/hyprctl-args"
|
|
|
|
"$ROOT/bin/omarchy-capture-webcam-resize" smaller
|
|
|
|
expected_hyprctl_args="$tmp_dir/expected-hyprctl-args"
|
|
printf '%s\n' \
|
|
'dispatch hl.dsp.window.resize({ window = "address:0xabc", x = 128, y = 144 })' \
|
|
'dispatch hl.dsp.window.move({ window = "address:0xabc", x = 2392, y = 516 })' >"$expected_hyprctl_args"
|
|
|
|
if ! cmp -s "$OMARCHY_TEST_HYPRCTL_ARGS" "$expected_hyprctl_args"; then
|
|
fail "webcam resize preserves its aspect ratio and corner anchor" "$(diff -u "$expected_hyprctl_args" "$OMARCHY_TEST_HYPRCTL_ARGS")"
|
|
fi
|
|
pass "webcam resize preserves its aspect ratio and corner anchor"
|
|
|
|
: >"$OMARCHY_TEST_HYPRCTL_ARGS"
|
|
OMARCHY_TEST_MONITOR_WIDTH=1920 \
|
|
OMARCHY_TEST_MONITOR_HEIGHT=1080 \
|
|
OMARCHY_TEST_MONITOR_SCALE=1 \
|
|
OMARCHY_TEST_CLIENT_WIDTH=128 \
|
|
OMARCHY_TEST_CLIENT_HEIGHT=144 \
|
|
"$ROOT/bin/omarchy-capture-webcam-resize" reset
|
|
|
|
printf '%s\n' \
|
|
'dispatch hl.dsp.window.resize({ window = "address:0xabc", x = 240, y = 270 })' \
|
|
'dispatch hl.dsp.window.move({ window = "address:0xabc", x = 2920, y = 670 })' >"$expected_hyprctl_args"
|
|
|
|
if ! cmp -s "$OMARCHY_TEST_HYPRCTL_ARGS" "$expected_hyprctl_args"; then
|
|
fail "webcam default size adapts to monitor resolution" "$(diff -u "$expected_hyprctl_args" "$OMARCHY_TEST_HYPRCTL_ARGS")"
|
|
fi
|
|
pass "webcam default size adapts to monitor resolution"
|
|
|
|
: >"$OMARCHY_TEST_HYPRCTL_ARGS"
|
|
OMARCHY_TEST_CLIENT_TITLE="Other Window" "$ROOT/bin/omarchy-capture-webcam-resize" larger
|
|
|
|
if [[ -s $OMARCHY_TEST_HYPRCTL_ARGS ]]; then
|
|
fail "webcam resize ignores other windows" "$(cat "$OMARCHY_TEST_HYPRCTL_ARGS")"
|
|
fi
|
|
pass "webcam resize ignores other windows"
|
|
|
|
region_file="$XDG_RUNTIME_DIR/omarchy-screenrecord-region"
|
|
|
|
: >"$OMARCHY_TEST_HYPRCTL_ARGS"
|
|
echo "800x600+100+100" >"$region_file"
|
|
"$ROOT/bin/omarchy-capture-webcam-resize" reset
|
|
|
|
printf '%s\n' \
|
|
'dispatch hl.dsp.window.resize({ window = "address:0xabc", x = 133, y = 150 })' \
|
|
'dispatch hl.dsp.window.move({ window = "address:0xabc", x = 727, y = 510 })' >"$expected_hyprctl_args"
|
|
|
|
if ! cmp -s "$OMARCHY_TEST_HYPRCTL_ARGS" "$expected_hyprctl_args"; then
|
|
fail "webcam anchors to the recorded region" "$(diff -u "$expected_hyprctl_args" "$OMARCHY_TEST_HYPRCTL_ARGS")"
|
|
fi
|
|
pass "webcam anchors to the recorded region"
|
|
|
|
printf '%s\n' \
|
|
'dispatch hl.dsp.window.resize({ window = "address:0xabc", x = 178, y = 200 })' \
|
|
'dispatch hl.dsp.window.move({ window = "address:0xabc", x = 2342, y = 460 })' >"$expected_hyprctl_args"
|
|
|
|
for region in "not-a-region" ""; do
|
|
: >"$OMARCHY_TEST_HYPRCTL_ARGS"
|
|
printf '%s' "$region" >"$region_file"
|
|
"$ROOT/bin/omarchy-capture-webcam-resize" reset
|
|
|
|
if ! cmp -s "$OMARCHY_TEST_HYPRCTL_ARGS" "$expected_hyprctl_args"; then
|
|
fail "webcam falls back to the monitor for an unusable region" "$(diff -u "$expected_hyprctl_args" "$OMARCHY_TEST_HYPRCTL_ARGS")"
|
|
fi
|
|
done
|
|
pass "webcam falls back to the monitor for an unusable region"
|
|
|
|
# A region too narrow for presets scaled from its height shrinks the whole
|
|
# ladder, so the three sizes stay distinct and each one fits inside the margins
|
|
: >"$OMARCHY_TEST_HYPRCTL_ARGS"
|
|
echo "200x1200+0+0" >"$region_file"
|
|
for size in small medium large; do
|
|
"$ROOT/bin/omarchy-capture-webcam-resize" "$size"
|
|
done
|
|
|
|
printf '%s\n' \
|
|
'dispatch hl.dsp.window.resize({ window = "address:0xabc", x = 64, y = 72 })' \
|
|
'dispatch hl.dsp.window.move({ window = "address:0xabc", x = 96, y = 1088 })' \
|
|
'dispatch hl.dsp.window.resize({ window = "address:0xabc", x = 89, y = 100 })' \
|
|
'dispatch hl.dsp.window.move({ window = "address:0xabc", x = 71, y = 1060 })' \
|
|
'dispatch hl.dsp.window.resize({ window = "address:0xabc", x = 120, y = 135 })' \
|
|
'dispatch hl.dsp.window.move({ window = "address:0xabc", x = 40, y = 1025 })' >"$expected_hyprctl_args"
|
|
|
|
if ! cmp -s "$OMARCHY_TEST_HYPRCTL_ARGS" "$expected_hyprctl_args"; then
|
|
fail "webcam sizes stay distinct and inside a narrow region" "$(diff -u "$expected_hyprctl_args" "$OMARCHY_TEST_HYPRCTL_ARGS")"
|
|
fi
|
|
pass "webcam sizes stay distinct and inside a narrow region"
|
|
|
|
rm -f "$region_file"
|
|
|
|
grep -F 'o.bind("SUPER + ALT + code:34", "Make webcam overlay smaller", "omarchy-capture-webcam-resize smaller")' \
|
|
"$ROOT/default/hypr/bindings/utilities.lua" >/dev/null || fail "webcam smaller hotkey is configured"
|
|
grep -F 'o.bind("SUPER + ALT + code:35", "Make webcam overlay larger", "omarchy-capture-webcam-resize larger")' \
|
|
"$ROOT/default/hypr/bindings/utilities.lua" >/dev/null || fail "webcam larger hotkey is configured"
|
|
pass "webcam resize hotkeys are configured"
|
|
|
|
grep -F -- '--wayland-app-id="WebcamOverlay-$WEBCAM_SIZE"' \
|
|
"$ROOT/bin/omarchy-capture-screenrecording" >/dev/null || fail "webcam uses a dedicated size-specific app id"
|
|
|
|
webcam_rules="$ROOT/default/hypr/apps/webcam-overlay.lua"
|
|
grep -F 'move = { "(monitor_w-monitor_h*4/25-40)", "(monitor_h-monitor_h*9/50-40)" }' "$webcam_rules" >/dev/null || \
|
|
fail "small webcam starts at its final corner position"
|
|
grep -F 'move = { "(monitor_w-monitor_h*2/9-40)", "(monitor_h-monitor_h/4-40)" }' "$webcam_rules" >/dev/null || \
|
|
fail "medium webcam starts at its final corner position"
|
|
grep -F 'move = { "(monitor_w-monitor_h*3/10-40)", "(monitor_h-monitor_h*27/80-40)" }' "$webcam_rules" >/dev/null || \
|
|
fail "large webcam starts at its final corner position"
|
|
pass "webcam size rules place the initial window in its final corner"
|