* Run menu summon actions in-process A menu action that only summons another shell plugin spawned bash and a qs ipc client to ask this same shell to do it, about 60ms of the path. Call shell.summon directly instead, and fall back to bash when the call is refused or the action is anything more than a bare summon. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Open the theme picker from rows held in the shell Opening the theme picker ran omarchy-theme-switcher to rebuild its index and then made a second IPC call, about 170ms before the picker mapped. The picker now holds the theme rows itself, opens from them at once, and refreshes them behind the open via omarchy-theme-switcher --print-rows. It applies the chosen theme with omarchy-theme-set directly, so omarchy-theme-set no longer preloads the picker. From the keybinding to the overlay mapped drops from ~245ms to ~83ms. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Keep the image picker surface mapped between opens Each open mapped a fresh surface, which rendered its first frames before Hyprland sent its fractional scale: the pixel ratio stepped 2, 1, then 1.6, so the picker flashed blurry for ~130ms and re-uploaded every thumbnail texture. Keep the surface and park it transparent and input-less on the bottom layer while closed, since anything on the overlay layer blocks direct scanout for fullscreen apps. It follows the focused monitor on each open. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
154 lines
5.4 KiB
Bash
154 lines
5.4 KiB
Bash
#!/bin/bash
|
|
|
|
set -euo pipefail
|
|
|
|
source "$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)/base-test.sh"
|
|
|
|
require_command flock
|
|
|
|
tmp=$(mktemp -d)
|
|
trap 'rm -rf "$tmp"' EXIT
|
|
|
|
cache_home="$tmp/cache"
|
|
images="$tmp/images"
|
|
stub_bin="$tmp/bin"
|
|
mkdir -p "$images" "$stub_bin"
|
|
|
|
cat >"$stub_bin/vipsthumbnail" <<'EOF'
|
|
#!/bin/bash
|
|
|
|
image="$1"
|
|
shift
|
|
|
|
while (( $# > 0 )); do
|
|
if [[ $1 == "--path" ]]; then
|
|
output=${2%%\[*}
|
|
break
|
|
fi
|
|
shift
|
|
done
|
|
|
|
if [[ -f ${VIPSTHUMBNAIL_FAIL_FILE:-} ]] && grep -Fxq "$image" "$VIPSTHUMBNAIL_FAIL_FILE"; then
|
|
exit 1
|
|
fi
|
|
|
|
[[ -z ${VIPSTHUMBNAIL_CALLS_FILE:-} ]] || printf '%s\n' "$image" >>"$VIPSTHUMBNAIL_CALLS_FILE"
|
|
[[ -z ${VIPSTHUMBNAIL_DELAY:-} ]] || sleep "$VIPSTHUMBNAIL_DELAY"
|
|
printf 'thumbnail' >"$output"
|
|
EOF
|
|
chmod +x "$stub_bin/vipsthumbnail"
|
|
|
|
for name in one two three; do
|
|
printf 'image-%s' "$name" >"$images/$name.png"
|
|
done
|
|
|
|
cache_dir="$cache_home/omarchy/image-selector"
|
|
mkdir -p "$cache_dir"
|
|
|
|
stale_tmp=""
|
|
live_lock=""
|
|
for image in "$images"/*; do
|
|
signature=$(stat -Lc '%s:%Y' "$image")
|
|
hash=$(printf '%s\t%s' "$image" "$signature" | md5sum | cut -d ' ' -f 1)
|
|
mkdir "$cache_dir/$hash.jpg.lock"
|
|
touch -m -d '10 minutes ago' "$cache_dir/$hash.jpg.lock"
|
|
stale_tmp="$cache_dir/$hash.jpg.4242.jpg"
|
|
live_lock="$cache_dir/$hash.jpg.lock"
|
|
done
|
|
printf 'partial' >"$stale_tmp"
|
|
|
|
cache_key=$(printf '%s' "$images" | md5sum | cut -d ' ' -f 1)
|
|
printf '%s\t%s' "$images/one.png" "$cache_dir/missing.jpg" >"$cache_dir/$cache_key.rows"
|
|
printf 'v2\n%s:%s\n' "$images" "$(stat -Lc '%Y' "$images")" >"$cache_dir/$cache_key.signature"
|
|
printf 'v1\n%s:%s\n' "$images" "$(stat -Lc '%Y' "$images")" >"$cache_dir/$cache_key.fast-signature"
|
|
|
|
PATH="$stub_bin:$PATH" XDG_CACHE_HOME="$cache_home" \
|
|
"$ROOT/bin/omarchy-menu-images" --cache-only "$images"
|
|
|
|
(( $(find "$cache_dir" -maxdepth 1 -name '*.jpg' -type f | wc -l) == 3 )) ||
|
|
fail "image menu recovers thumbnails from stranded locks"
|
|
(( $(awk 'END { print NR }' "$cache_dir/$cache_key.rows") == 3 )) ||
|
|
fail "image menu rebuilds every row after cache invalidation"
|
|
[[ $(head -n 1 "$cache_dir/$cache_key.signature") == "v4" ]] ||
|
|
fail "image menu invalidates stale row caches"
|
|
[[ ! -e $stale_tmp ]] ||
|
|
fail "image menu clears partial thumbnails left by killed generators"
|
|
pass "image menu recovers stranded locks and stale rows"
|
|
|
|
rm -rf "$cache_home"
|
|
mkdir -p "$cache_dir"
|
|
mkdir "$live_lock"
|
|
|
|
PATH="$stub_bin:$PATH" XDG_CACHE_HOME="$cache_home" \
|
|
"$ROOT/bin/omarchy-menu-images" --cache-only "$images"
|
|
|
|
(( $(find "$cache_dir" -maxdepth 1 -name '*.jpg' -type f | wc -l) == 2 )) ||
|
|
fail "image menu skips a thumbnail whose fresh legacy lock may still be owned"
|
|
[[ -d $live_lock ]] ||
|
|
fail "image menu leaves a fresh legacy lock directory alone"
|
|
[[ ! -e $cache_dir/$cache_key.rows ]] ||
|
|
fail "image menu does not cache rows while a legacy generator holds a lock"
|
|
pass "image menu respects a live legacy generator's lock"
|
|
|
|
rm -rf "$cache_home"
|
|
mkdir -p "$cache_home"
|
|
printf '%s\n' "$images/two.png" >"$tmp/failures"
|
|
|
|
PATH="$stub_bin:$PATH" XDG_CACHE_HOME="$cache_home" VIPSTHUMBNAIL_FAIL_FILE="$tmp/failures" \
|
|
"$ROOT/bin/omarchy-menu-images" --cache-only "$images"
|
|
|
|
cache_dir="$cache_home/omarchy/image-selector"
|
|
[[ ! -e $cache_dir/$cache_key.rows ]] || fail "image menu does not cache incomplete rows"
|
|
[[ ! -e $cache_dir/$cache_key.signature ]] || fail "image menu does not sign incomplete rows"
|
|
[[ ! -e $cache_dir/$cache_key.fast-signature ]] || fail "image menu does not fast-cache incomplete rows"
|
|
pass "image menu leaves failed thumbnail batches uncached"
|
|
|
|
rm "$tmp/failures"
|
|
PATH="$stub_bin:$PATH" XDG_CACHE_HOME="$cache_home" \
|
|
"$ROOT/bin/omarchy-menu-images" --cache-only "$images"
|
|
|
|
(( $(find "$cache_dir" -maxdepth 1 -name '*.jpg' -type f | wc -l) == 3 )) ||
|
|
fail "image menu retries a previously failed thumbnail"
|
|
(( $(awk 'END { print NR }' "$cache_dir/$cache_key.rows") == 3 )) ||
|
|
fail "image menu caches every row after retry"
|
|
pass "image menu completes and caches a later retry"
|
|
|
|
rm -rf "$cache_home"
|
|
mkdir -p "$cache_home"
|
|
: >"$tmp/calls"
|
|
|
|
# The delay keeps both runs inside the generation window so the locks are
|
|
# actually contended rather than the second run arriving after the first.
|
|
pids=()
|
|
for run in 1 2; do
|
|
PATH="$stub_bin:$PATH" XDG_CACHE_HOME="$cache_home" \
|
|
VIPSTHUMBNAIL_CALLS_FILE="$tmp/calls" VIPSTHUMBNAIL_DELAY=0.25 \
|
|
"$ROOT/bin/omarchy-menu-images" --cache-only "$images" &
|
|
pids+=($!)
|
|
done
|
|
for pid in "${pids[@]}"; do
|
|
wait "$pid" || fail "concurrent image menu runs exit cleanly"
|
|
done
|
|
|
|
(( $(wc -l <"$tmp/calls") == 3 )) || fail "image menu serializes concurrent thumbnail generators"
|
|
|
|
rm -f "$cache_dir"/*.jpg
|
|
rm -f "$cache_dir/$cache_key.rows" "$cache_dir/$cache_key.signature" "$cache_dir/$cache_key.fast-signature"
|
|
PATH="$stub_bin:$PATH" XDG_CACHE_HOME="$cache_home" VIPSTHUMBNAIL_CALLS_FILE="$tmp/calls" \
|
|
"$ROOT/bin/omarchy-menu-images" --cache-only "$images"
|
|
|
|
(( $(wc -l <"$tmp/calls") == 6 )) || fail "image menu releases thumbnail locks after generation"
|
|
pass "image menu owns locks for exactly one generator lifetime"
|
|
|
|
rm -rf "$cache_home"
|
|
mkdir -p "$cache_home"
|
|
rows=$(PATH="$stub_bin:$PATH" XDG_CACHE_HOME="$cache_home" \
|
|
"$ROOT/bin/omarchy-menu-images" --print-rows "$images")
|
|
|
|
(( $(wc -l <<<"$rows") == 3 )) || fail "image menu prints one row per image"
|
|
while IFS=$'\t' read -r row_image row_thumbnail; do
|
|
[[ $row_image == "$images"/* && -f $row_thumbnail ]] ||
|
|
fail "image menu prints each image with its generated thumbnail"
|
|
done <<<"$rows"
|
|
pass "image menu prints its rows for the shell to hold"
|