Tighten image selector request handling
This commit is contained in:
+64
-32
@@ -12,13 +12,27 @@ show_labels=false
|
|||||||
cache_only=false
|
cache_only=false
|
||||||
image_dirs=()
|
image_dirs=()
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
echo "Usage: omarchy-menu-images [--selected <image>] [--colors-file <path>] [--print-name] [--show-labels] [--cache-only] <image-dir>..."
|
||||||
|
}
|
||||||
|
|
||||||
while [[ $# -gt 0 ]]; do
|
while [[ $# -gt 0 ]]; do
|
||||||
case "$1" in
|
case "$1" in
|
||||||
--selected)
|
--selected)
|
||||||
|
if (( $# < 2 )); then
|
||||||
|
usage >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
selected_image="$2"
|
selected_image="$2"
|
||||||
shift 2
|
shift 2
|
||||||
;;
|
;;
|
||||||
--colors-file)
|
--colors-file)
|
||||||
|
if (( $# < 2 )); then
|
||||||
|
usage >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
colors_file="$2"
|
colors_file="$2"
|
||||||
shift 2
|
shift 2
|
||||||
;;
|
;;
|
||||||
@@ -35,7 +49,7 @@ while [[ $# -gt 0 ]]; do
|
|||||||
shift
|
shift
|
||||||
;;
|
;;
|
||||||
--help|-h)
|
--help|-h)
|
||||||
echo "Usage: omarchy-menu-images [--selected <image>] [--colors-file <path>] [--print-name] [--show-labels] [--cache-only] <image-dir>..."
|
usage
|
||||||
exit 0
|
exit 0
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
@@ -46,7 +60,7 @@ while [[ $# -gt 0 ]]; do
|
|||||||
done
|
done
|
||||||
|
|
||||||
if (( ${#image_dirs[@]} == 0 )); then
|
if (( ${#image_dirs[@]} == 0 )); then
|
||||||
echo "Usage: omarchy-menu-images [--selected <image>] [--colors-file <path>] [--print-name] [--show-labels] [--cache-only] <image-dir>..." >&2
|
usage >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -90,10 +104,17 @@ cache_key=$(printf '%s' "$image_dirs_env" | md5sum | cut -d ' ' -f 1)
|
|||||||
rows_cache_file="$cache_dir/$cache_key.rows"
|
rows_cache_file="$cache_dir/$cache_key.rows"
|
||||||
rows_signature_file="$cache_dir/$cache_key.signature"
|
rows_signature_file="$cache_dir/$cache_key.signature"
|
||||||
rows_signature=""
|
rows_signature=""
|
||||||
|
image_files=()
|
||||||
|
|
||||||
for dir in "${image_dirs[@]}"; do
|
for dir in "${image_dirs[@]}"; do
|
||||||
if [[ -d $dir ]]; then
|
if [[ -d $dir ]]; then
|
||||||
rows_signature+="$dir:$(stat -Lc '%Y' "$dir")"$'\n'
|
rows_signature+="$dir:$(stat -Lc '%Y' "$dir")"$'\n'
|
||||||
|
|
||||||
|
while IFS= read -r -d '' image; do
|
||||||
|
image_files+=("$image")
|
||||||
|
image_signature=$(stat -Lc '%s:%Y' "$image") || continue
|
||||||
|
rows_signature+="$image:$image_signature"$'\n'
|
||||||
|
done < <(find -L "$dir" -maxdepth 1 -type f \( -iname '*.jpg' -o -iname '*.jpeg' -o -iname '*.png' -o -iname '*.gif' -o -iname '*.bmp' -o -iname '*.webp' \) -print0 2>/dev/null | sort -z)
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
@@ -112,27 +133,23 @@ thumbnail_for() {
|
|||||||
thumbnail="$cache_dir/$hash.jpg"
|
thumbnail="$cache_dir/$hash.jpg"
|
||||||
|
|
||||||
if [[ ! -f $thumbnail ]]; then
|
if [[ ! -f $thumbnail ]]; then
|
||||||
magick "$image" -auto-orient -resize '1536x864^' -gravity center -extent '1536x864' -strip -quality 82 "$thumbnail"
|
magick "${image}[0]" -auto-orient -resize '1536x864^' -gravity center -extent '1536x864' -strip -quality 82 "$thumbnail"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
printf '%s' "$thumbnail"
|
[[ -f $thumbnail ]] && printf '%s' "$thumbnail"
|
||||||
}
|
}
|
||||||
|
|
||||||
if [[ -f $rows_cache_file && -f $rows_signature_file ]] && cmp -s "$rows_signature_file" <(printf '%s' "$rows_signature"); then
|
if [[ -f $rows_cache_file && -f $rows_signature_file ]] && cmp -s "$rows_signature_file" <(printf '%s' "$rows_signature"); then
|
||||||
rows=$(<"$rows_cache_file")
|
rows=$(<"$rows_cache_file")
|
||||||
else
|
else
|
||||||
for dir in "${image_dirs[@]}"; do
|
for image in "${image_files[@]}"; do
|
||||||
if [[ -d $dir ]]; then
|
thumbnail=$(thumbnail_for "$image")
|
||||||
while IFS= read -r -d '' image; do
|
[[ -n $thumbnail ]] || continue
|
||||||
thumbnail=$(thumbnail_for "$image")
|
|
||||||
[[ -n $thumbnail ]] || continue
|
|
||||||
|
|
||||||
if [[ -z $rows ]]; then
|
if [[ -z $rows ]]; then
|
||||||
rows="$image"$'\t'"$thumbnail"
|
rows="$image"$'\t'"$thumbnail"
|
||||||
else
|
else
|
||||||
rows+=$'\n'"$image"$'\t'"$thumbnail"
|
rows+=$'\n'"$image"$'\t'"$thumbnail"
|
||||||
fi
|
|
||||||
done < <(find -L "$dir" -maxdepth 1 -type f \( -iname '*.jpg' -o -iname '*.jpeg' -o -iname '*.png' -o -iname '*.webp' \) -print0 2>/dev/null)
|
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
@@ -155,31 +172,46 @@ if [[ $cache_only == true ]]; then
|
|||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ -S $socket_path && $selector_qml -nt $socket_path ]]; then
|
ensure_selector() {
|
||||||
quickshell kill -p "$selector_qml" >/dev/null 2>&1 || true
|
if [[ -S $socket_path && $selector_qml -nt $socket_path ]]; then
|
||||||
rm -f "$socket_path"
|
quickshell kill -p "$selector_qml" >/dev/null 2>&1 || true
|
||||||
fi
|
rm -f "$socket_path"
|
||||||
|
fi
|
||||||
|
|
||||||
if [[ ! -S $socket_path ]]; then
|
if [[ ! -S $socket_path ]]; then
|
||||||
quickshell kill -p "$selector_qml" >/dev/null 2>&1 || true
|
quickshell kill -p "$selector_qml" >/dev/null 2>&1 || true
|
||||||
quickshell -d -p "$selector_qml" >/dev/null
|
quickshell -d -p "$selector_qml" >/dev/null
|
||||||
|
|
||||||
for ((i = 0; i < 100; i++)); do
|
for ((i = 0; i < 100; i++)); do
|
||||||
if [[ -S $socket_path ]]; then
|
if [[ -S $socket_path ]]; then
|
||||||
break
|
break
|
||||||
fi
|
fi
|
||||||
|
|
||||||
sleep 0.01
|
sleep 0.01
|
||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ ! -S $socket_path ]]; then
|
[[ -S $socket_path ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
send_request() {
|
||||||
|
printf '%s\t%s\t%s\t%s\t%s\t%s\n' "$rows_payload" "$selected_list_image" "$selection_file" "$done_file" "$colors_payload" "$show_labels" |
|
||||||
|
socat -u - "UNIX-CONNECT:$socket_path"
|
||||||
|
}
|
||||||
|
|
||||||
|
if ! ensure_selector; then
|
||||||
echo "Image selector failed to start" >&2
|
echo "Image selector failed to start" >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
printf '%s\t%s\t%s\t%s\t%s\t%s\n' "$rows_payload" "$selected_list_image" "$selection_file" "$done_file" "$colors_payload" "$show_labels" |
|
if ! send_request; then
|
||||||
socat -u - "UNIX-CONNECT:$socket_path"
|
rm -f "$socket_path"
|
||||||
|
|
||||||
|
if ! ensure_selector || ! send_request; then
|
||||||
|
echo "Image selector failed to accept request" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
while [[ ! -e $done_file ]]; do
|
while [[ ! -e $done_file ]]; do
|
||||||
sleep 0.01
|
sleep 0.01
|
||||||
|
|||||||
@@ -13,13 +13,19 @@ mkdir -p "$preview_dir"
|
|||||||
|
|
||||||
find_preview() {
|
find_preview() {
|
||||||
local theme_path="$1"
|
local theme_path="$1"
|
||||||
|
local preview preview_name
|
||||||
|
|
||||||
if [[ -f $theme_path/preview.png ]]; then
|
for preview_name in preview.png preview.jpg preview.jpeg preview.webp preview.gif preview.bmp; do
|
||||||
printf '%s\n' "$theme_path/preview.png"
|
preview=$(find -L "$theme_path" -maxdepth 1 -type f -iname "$preview_name" -print -quit 2>/dev/null)
|
||||||
elif [[ -f $theme_path/preview.jpg ]]; then
|
|
||||||
printf '%s\n' "$theme_path/preview.jpg"
|
if [[ -n $preview ]]; then
|
||||||
elif [[ -d $theme_path/backgrounds ]]; then
|
printf '%s\n' "$preview"
|
||||||
find -L "$theme_path/backgrounds" -maxdepth 1 -type f \( -iname '*.jpg' -o -iname '*.jpeg' -o -iname '*.png' -o -iname '*.webp' \) -print -quit 2>/dev/null
|
return
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if [[ -d $theme_path/backgrounds ]]; then
|
||||||
|
find -L "$theme_path/backgrounds" -maxdepth 1 -type f \( -iname '*.jpg' -o -iname '*.jpeg' -o -iname '*.png' -o -iname '*.gif' -o -iname '*.bmp' -o -iname '*.webp' \) -print 2>/dev/null | sort | head -n 1
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -27,6 +33,7 @@ add_theme_preview() {
|
|||||||
local theme_name="$1"
|
local theme_name="$1"
|
||||||
local preview="$2"
|
local preview="$2"
|
||||||
local extension="${preview##*.}"
|
local extension="${preview##*.}"
|
||||||
|
extension="${extension,,}"
|
||||||
|
|
||||||
[[ -n $preview ]] || return
|
[[ -n $preview ]] || return
|
||||||
[[ -e $preview_dir/$theme_name.$extension ]] && return
|
[[ -e $preview_dir/$theme_name.$extension ]] && return
|
||||||
@@ -38,6 +45,15 @@ theme_signature=""
|
|||||||
for theme_dir in "$USER_THEMES_PATH" "$OMARCHY_THEMES_PATH"; do
|
for theme_dir in "$USER_THEMES_PATH" "$OMARCHY_THEMES_PATH"; do
|
||||||
if [[ -d $theme_dir ]]; then
|
if [[ -d $theme_dir ]]; then
|
||||||
theme_signature+="$theme_dir:$(stat -Lc '%Y' "$theme_dir")"$'\n'
|
theme_signature+="$theme_dir:$(stat -Lc '%Y' "$theme_dir")"$'\n'
|
||||||
|
|
||||||
|
while IFS= read -r -d '' theme_path; do
|
||||||
|
preview=$(find_preview "$theme_path")
|
||||||
|
theme_signature+="$theme_path:$(stat -Lc '%Y' "$theme_path")"$'\n'
|
||||||
|
|
||||||
|
if [[ -n $preview ]]; then
|
||||||
|
theme_signature+="$preview:$(stat -Lc '%s:%Y' "$preview")"$'\n'
|
||||||
|
fi
|
||||||
|
done < <(find -L "$theme_dir" -mindepth 1 -maxdepth 1 \( -type d -o -type l \) -print0 2>/dev/null | sort -z)
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
@@ -67,7 +83,7 @@ fi
|
|||||||
|
|
||||||
current_theme=$(cat "$HOME/.config/omarchy/current/theme.name" 2>/dev/null)
|
current_theme=$(cat "$HOME/.config/omarchy/current/theme.name" 2>/dev/null)
|
||||||
selected_preview=""
|
selected_preview=""
|
||||||
for extension in png jpg jpeg webp; do
|
for extension in png jpg jpeg webp gif bmp; do
|
||||||
if [[ -e $preview_dir/$current_theme.$extension ]]; then
|
if [[ -e $preview_dir/$current_theme.$extension ]]; then
|
||||||
selected_preview="$preview_dir/$current_theme.$extension"
|
selected_preview="$preview_dir/$current_theme.$extension"
|
||||||
break
|
break
|
||||||
|
|||||||
@@ -17,7 +17,11 @@ ShellRoot {
|
|||||||
property bool imagesLoaded: false
|
property bool imagesLoaded: false
|
||||||
property bool opened: false
|
property bool opened: false
|
||||||
property bool showLabels: false
|
property bool showLabels: false
|
||||||
|
property bool requestActive: false
|
||||||
|
property int requestSerial: 0
|
||||||
|
property int applySerial: 0
|
||||||
property string doneFile: ""
|
property string doneFile: ""
|
||||||
|
property var doneFilesToRelease: []
|
||||||
property string socketPath: (Quickshell.env("XDG_RUNTIME_DIR") || ("/run/user/" + Quickshell.env("UID"))) + "/omarchy-image-selector.sock"
|
property string socketPath: (Quickshell.env("XDG_RUNTIME_DIR") || ("/run/user/" + Quickshell.env("UID"))) + "/omarchy-image-selector.sock"
|
||||||
property color accent: "#798186"
|
property color accent: "#798186"
|
||||||
property color background: "#101315"
|
property color background: "#101315"
|
||||||
@@ -62,23 +66,52 @@ ShellRoot {
|
|||||||
selectedIndex = index
|
selectedIndex = index
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function releaseNextDoneFile() {
|
||||||
|
if (releaseProc.running || doneFilesToRelease.length === 0) return
|
||||||
|
|
||||||
|
var path = doneFilesToRelease.shift()
|
||||||
|
releaseProc.command = ["bash", "-lc", ": > " + shellQuote(path)]
|
||||||
|
releaseProc.running = true
|
||||||
|
}
|
||||||
|
|
||||||
|
function finishDoneFile(path) {
|
||||||
|
if (!path) return
|
||||||
|
doneFilesToRelease.push(path)
|
||||||
|
releaseNextDoneFile()
|
||||||
|
}
|
||||||
|
|
||||||
function applySelected() {
|
function applySelected() {
|
||||||
var path = currentPath()
|
var path = currentPath()
|
||||||
if (!path) return
|
if (!path || !selectionFile) {
|
||||||
if (!selectionFile) return
|
cancel()
|
||||||
applyProc.command = ["bash", "-lc", "printf '%s\\n' " + shellQuote(path) + " > " + shellQuote(selectionFile) + "; : > " + shellQuote(doneFile)]
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var activeSelectionFile = selectionFile
|
||||||
|
var activeDoneFile = doneFile
|
||||||
|
applySerial = requestSerial
|
||||||
|
requestActive = false
|
||||||
|
selectionFile = ""
|
||||||
|
doneFile = ""
|
||||||
|
|
||||||
|
applyProc.command = ["bash", "-lc", "printf '%s\\n' " + shellQuote(path) + " > " + shellQuote(activeSelectionFile) + "; : > " + shellQuote(activeDoneFile)]
|
||||||
applyProc.running = true
|
applyProc.running = true
|
||||||
}
|
}
|
||||||
|
|
||||||
function cancel() {
|
function cancel() {
|
||||||
cancelProc.command = ["bash", "-lc", ": > " + shellQuote(doneFile)]
|
if (requestActive)
|
||||||
cancelProc.running = true
|
finishDoneFile(doneFile)
|
||||||
|
|
||||||
|
requestActive = false
|
||||||
|
selectionFile = ""
|
||||||
|
doneFile = ""
|
||||||
|
root.opened = false
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadRows(rows) {
|
function loadRows(rows) {
|
||||||
var paths = rows.split("\n")
|
var paths = rows.split("\n")
|
||||||
for (var i = 0; i < paths.length; i++) {
|
for (var i = 0; i < paths.length; i++) {
|
||||||
var row = paths[i].trim()
|
var row = paths[i]
|
||||||
if (!row) continue
|
if (!row) continue
|
||||||
|
|
||||||
var columns = row.split("\t")
|
var columns = row.split("\t")
|
||||||
@@ -92,11 +125,17 @@ ShellRoot {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function openSelector(nextImageDirs, nextImageRows, nextSelectedImage, nextSelectionFile, nextDoneFile, nextColorsFile, nextColorsRaw, nextShowLabels) {
|
function openSelector(nextImageDirs, nextImageRows, nextSelectedImage, nextSelectionFile, nextDoneFile, nextColorsFile, nextColorsRaw, nextShowLabels) {
|
||||||
|
if (requestActive && doneFile && doneFile !== nextDoneFile)
|
||||||
|
finishDoneFile(doneFile)
|
||||||
|
|
||||||
|
requestSerial += 1
|
||||||
|
|
||||||
imageDirs = nextImageDirs
|
imageDirs = nextImageDirs
|
||||||
imageRows = nextImageRows
|
imageRows = nextImageRows
|
||||||
selectedImage = nextSelectedImage
|
selectedImage = nextSelectedImage
|
||||||
selectionFile = nextSelectionFile
|
selectionFile = nextSelectionFile
|
||||||
doneFile = nextDoneFile
|
doneFile = nextDoneFile
|
||||||
|
requestActive = !!doneFile
|
||||||
showLabels = nextShowLabels === true || nextShowLabels === "true"
|
showLabels = nextShowLabels === true || nextShowLabels === "true"
|
||||||
colorsFile = nextColorsFile || (Quickshell.env("HOME") + "/.config/omarchy/current/theme/background-switcher-colors.json")
|
colorsFile = nextColorsFile || (Quickshell.env("HOME") + "/.config/omarchy/current/theme/background-switcher-colors.json")
|
||||||
if (nextColorsRaw)
|
if (nextColorsRaw)
|
||||||
@@ -139,7 +178,7 @@ ShellRoot {
|
|||||||
Process {
|
Process {
|
||||||
id: loadImagesProc
|
id: loadImagesProc
|
||||||
property string output: ""
|
property string output: ""
|
||||||
command: ["bash", "-lc", "cache_dir=${XDG_CACHE_HOME:-$HOME/.cache}/omarchy/image-selector; while IFS= read -r dir; do [[ -n $dir && -d $dir ]] && find -L \"$dir\" -maxdepth 1 -type f \\( -iname '*.jpg' -o -iname '*.jpeg' -o -iname '*.png' -o -iname '*.webp' \\) -print0; done <<< " + shellQuote(root.imageDirs) + " | sort -z | while IFS= read -r -d '' image; do hash=$(md5sum \"$image\" | cut -d ' ' -f 1); thumb=\"$cache_dir/$hash.jpg\"; [[ -f $thumb ]] || thumb=$image; printf '%s\\t%s\\n' \"$image\" \"$thumb\"; done"]
|
command: ["bash", "-lc", "cache_dir=${XDG_CACHE_HOME:-$HOME/.cache}/omarchy/image-selector; while IFS= read -r dir; do [[ -n $dir && -d $dir ]] && find -L \"$dir\" -maxdepth 1 -type f \\( -iname '*.jpg' -o -iname '*.jpeg' -o -iname '*.png' -o -iname '*.gif' -o -iname '*.bmp' -o -iname '*.webp' \\) -print0; done <<< " + shellQuote(root.imageDirs) + " | sort -z | while IFS= read -r -d '' image; do hash=$(md5sum \"$image\" | cut -d ' ' -f 1); thumb=\"$cache_dir/$hash.jpg\"; [[ -f $thumb ]] || thumb=$image; printf '%s\\t%s\\n' \"$image\" \"$thumb\"; done"]
|
||||||
stdout: SplitParser {
|
stdout: SplitParser {
|
||||||
onRead: function(data) {
|
onRead: function(data) {
|
||||||
loadImagesProc.output += data + "\n"
|
loadImagesProc.output += data + "\n"
|
||||||
@@ -197,12 +236,15 @@ ShellRoot {
|
|||||||
|
|
||||||
Process {
|
Process {
|
||||||
id: applyProc
|
id: applyProc
|
||||||
onExited: root.opened = false
|
onExited: {
|
||||||
|
if (root.applySerial === root.requestSerial)
|
||||||
|
root.opened = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Process {
|
Process {
|
||||||
id: cancelProc
|
id: releaseProc
|
||||||
onExited: root.opened = false
|
onExited: root.releaseNextDoneFile()
|
||||||
}
|
}
|
||||||
|
|
||||||
PanelWindow {
|
PanelWindow {
|
||||||
|
|||||||
Reference in New Issue
Block a user