Permanent process for speed
This commit is contained in:
+95
-14
@@ -36,7 +36,11 @@ if (( ${#image_dirs[@]} == 0 )); then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
selection_file=$(mktemp)
|
selection_file=$(mktemp)
|
||||||
trap 'rm -f "$selection_file"' EXIT
|
done_file=$(mktemp)
|
||||||
|
rm -f "$done_file"
|
||||||
|
trap 'rm -f "$selection_file" "$done_file"' EXIT
|
||||||
|
socket_path="${XDG_RUNTIME_DIR:-/run/user/$UID}/omarchy-image-selector.sock"
|
||||||
|
selector_qml="$OMARCHY_PATH/default/quickshell/wallpaper-switcher.qml"
|
||||||
|
|
||||||
image_dirs_env=""
|
image_dirs_env=""
|
||||||
for dir in "${image_dirs[@]}"; do
|
for dir in "${image_dirs[@]}"; do
|
||||||
@@ -60,26 +64,103 @@ if [[ -n $current_image ]]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
cache_dir=${XDG_CACHE_HOME:-$HOME/.cache}/omarchy/image-selector
|
cache_dir=${XDG_CACHE_HOME:-$HOME/.cache}/omarchy/image-selector
|
||||||
|
index_file="$cache_dir/index.tsv"
|
||||||
|
rows=""
|
||||||
mkdir -p "$cache_dir"
|
mkdir -p "$cache_dir"
|
||||||
|
|
||||||
|
cache_key=$(printf '%s' "$image_dirs_env" | md5sum | cut -d ' ' -f 1)
|
||||||
|
rows_cache_file="$cache_dir/$cache_key.rows"
|
||||||
|
rows_signature_file="$cache_dir/$cache_key.signature"
|
||||||
|
rows_signature=""
|
||||||
|
|
||||||
for dir in "${image_dirs[@]}"; do
|
for dir in "${image_dirs[@]}"; do
|
||||||
if [[ -d $dir ]]; then
|
if [[ -d $dir ]]; then
|
||||||
while IFS= read -r -d '' image; do
|
rows_signature+="$dir:$(stat -Lc '%Y' "$dir")"$'\n'
|
||||||
hash=$(md5sum "$image" | cut -d ' ' -f 1)
|
|
||||||
thumbnail="$cache_dir/$hash.jpg"
|
|
||||||
|
|
||||||
if [[ ! -f $thumbnail ]]; then
|
|
||||||
magick "$image" -auto-orient -resize '1536x864^' -gravity center -extent '1536x864' -strip -quality 82 "$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
|
||||||
|
|
||||||
OMARCHY_IMAGE_SELECTOR_SELECTION_FILE=$selection_file \
|
thumbnail_for() {
|
||||||
OMARCHY_IMAGE_SELECTOR_DIRS="$image_dirs_env" \
|
local image="$1"
|
||||||
OMARCHY_IMAGE_SELECTOR_SELECTED="$selected_list_image" \
|
local signature hash thumbnail
|
||||||
OMARCHY_IMAGE_SELECTOR_COLORS_FILE="$colors_file" \
|
|
||||||
quickshell -p "$OMARCHY_PATH/default/quickshell/wallpaper-switcher.qml" >/dev/null
|
signature=$(stat -Lc '%s:%Y' "$image") || return
|
||||||
|
hash=$(awk -F '\t' -v path="$image" -v sig="$signature" '$1 == path && $2 == sig { print $3; exit }' "$index_file" 2>/dev/null)
|
||||||
|
|
||||||
|
if [[ -z $hash ]]; then
|
||||||
|
hash=$(md5sum "$image" | cut -d ' ' -f 1)
|
||||||
|
printf '%s\t%s\t%s\n' "$image" "$signature" "$hash" >>"$index_file"
|
||||||
|
fi
|
||||||
|
|
||||||
|
thumbnail="$cache_dir/$hash.jpg"
|
||||||
|
|
||||||
|
if [[ ! -f $thumbnail ]]; then
|
||||||
|
magick "$image" -auto-orient -resize '1536x864^' -gravity center -extent '1536x864' -strip -quality 82 "$thumbnail"
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf '%s' "$thumbnail"
|
||||||
|
}
|
||||||
|
|
||||||
|
if [[ -f $rows_cache_file && -f $rows_signature_file ]] && cmp -s "$rows_signature_file" <(printf '%s' "$rows_signature"); then
|
||||||
|
rows=$(<"$rows_cache_file")
|
||||||
|
else
|
||||||
|
for dir in "${image_dirs[@]}"; do
|
||||||
|
if [[ -d $dir ]]; then
|
||||||
|
while IFS= read -r -d '' image; do
|
||||||
|
thumbnail=$(thumbnail_for "$image")
|
||||||
|
[[ -n $thumbnail ]] || continue
|
||||||
|
|
||||||
|
if [[ -z $rows ]]; then
|
||||||
|
rows="$image"$'\t'"$thumbnail"
|
||||||
|
else
|
||||||
|
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
|
||||||
|
done
|
||||||
|
|
||||||
|
printf '%s' "$rows" >"$rows_cache_file"
|
||||||
|
printf '%s' "$rows_signature" >"$rows_signature_file"
|
||||||
|
fi
|
||||||
|
|
||||||
|
rows_payload=${rows//$'\t'/$'\f'}
|
||||||
|
rows_payload=${rows_payload//$'\n'/$'\v'}
|
||||||
|
|
||||||
|
selector_pid=$(quickshell list -p "$selector_qml" --json 2>/dev/null | jq -r '.[0].pid // empty')
|
||||||
|
if [[ -n $selector_pid ]]; then
|
||||||
|
selector_age=$(ps -o etimes= -p "$selector_pid" 2>/dev/null | tr -d ' ')
|
||||||
|
qml_mtime=$(stat -c %Y "$selector_qml")
|
||||||
|
now=$(date +%s)
|
||||||
|
|
||||||
|
if [[ -n $selector_age ]] && (( now - selector_age < qml_mtime )); then
|
||||||
|
quickshell kill -p "$selector_qml" >/dev/null 2>&1 || true
|
||||||
|
rm -f "$socket_path"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ! -S $socket_path ]]; then
|
||||||
|
quickshell kill -p "$selector_qml" >/dev/null 2>&1 || true
|
||||||
|
quickshell -d -p "$selector_qml" >/dev/null
|
||||||
|
|
||||||
|
for ((i = 0; i < 100; i++)); do
|
||||||
|
if [[ -S $socket_path ]]; then
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
|
||||||
|
sleep 0.01
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ! -S $socket_path ]]; then
|
||||||
|
echo "Image selector failed to start" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf '%s\t%s\t%s\t%s\t%s\n' "$rows_payload" "$selected_list_image" "$selection_file" "$done_file" "$colors_file" |
|
||||||
|
socat -u - "UNIX-CONNECT:$socket_path"
|
||||||
|
|
||||||
|
while [[ ! -e $done_file ]]; do
|
||||||
|
sleep 0.01
|
||||||
|
done
|
||||||
|
|
||||||
if [[ -s $selection_file ]]; then
|
if [[ -s $selection_file ]]; then
|
||||||
cat "$selection_file"
|
cat "$selection_file"
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ hl.on("hyprland.start", function()
|
|||||||
hl.exec_cmd("! omarchy-toggle-enabled waybar-off && uwsm-app -- waybar")
|
hl.exec_cmd("! omarchy-toggle-enabled waybar-off && uwsm-app -- waybar")
|
||||||
hl.exec_cmd("uwsm-app -- fcitx5 --disable notificationitem")
|
hl.exec_cmd("uwsm-app -- fcitx5 --disable notificationitem")
|
||||||
hl.exec_cmd("uwsm-app -- swaybg -i ~/.config/omarchy/current/background -m fill")
|
hl.exec_cmd("uwsm-app -- swaybg -i ~/.config/omarchy/current/background -m fill")
|
||||||
|
hl.exec_cmd("uwsm-app -- quickshell -p ~/.local/share/omarchy/default/quickshell/wallpaper-switcher.qml")
|
||||||
hl.exec_cmd("/usr/lib/polkit-gnome/polkit-gnome-authentication-agent-1")
|
hl.exec_cmd("/usr/lib/polkit-gnome/polkit-gnome-authentication-agent-1")
|
||||||
hl.exec_cmd("omarchy-first-run")
|
hl.exec_cmd("omarchy-first-run")
|
||||||
hl.exec_cmd("omarchy-powerprofiles-init")
|
hl.exec_cmd("omarchy-powerprofiles-init")
|
||||||
|
|||||||
@@ -9,11 +9,15 @@ ShellRoot {
|
|||||||
id: root
|
id: root
|
||||||
|
|
||||||
property string imageDirs: Quickshell.env("OMARCHY_IMAGE_SELECTOR_DIRS") || Quickshell.env("OMARCHY_IMAGE_SELECTOR_DIR") || Quickshell.env("OMARCHY_STOCK_BACKGROUNDS_DIR") || (Quickshell.env("HOME") + "/.config/omarchy/current/theme/backgrounds")
|
property string imageDirs: Quickshell.env("OMARCHY_IMAGE_SELECTOR_DIRS") || Quickshell.env("OMARCHY_IMAGE_SELECTOR_DIR") || Quickshell.env("OMARCHY_STOCK_BACKGROUNDS_DIR") || (Quickshell.env("HOME") + "/.config/omarchy/current/theme/backgrounds")
|
||||||
|
property string imageRows: ""
|
||||||
property string selectionFile: Quickshell.env("OMARCHY_IMAGE_SELECTOR_SELECTION_FILE") || Quickshell.env("OMARCHY_WALLPAPER_SELECTION_FILE")
|
property string selectionFile: Quickshell.env("OMARCHY_IMAGE_SELECTOR_SELECTION_FILE") || Quickshell.env("OMARCHY_WALLPAPER_SELECTION_FILE")
|
||||||
property string selectedImage: Quickshell.env("OMARCHY_IMAGE_SELECTOR_SELECTED")
|
property string selectedImage: Quickshell.env("OMARCHY_IMAGE_SELECTOR_SELECTED")
|
||||||
property string colorsFile: Quickshell.env("OMARCHY_IMAGE_SELECTOR_COLORS_FILE") || (Quickshell.env("HOME") + "/.config/omarchy/current/theme/wallpaper-switcher-colors.json")
|
property string colorsFile: Quickshell.env("OMARCHY_IMAGE_SELECTOR_COLORS_FILE") || (Quickshell.env("HOME") + "/.config/omarchy/current/theme/wallpaper-switcher-colors.json")
|
||||||
property int selectedIndex: 0
|
property int selectedIndex: 0
|
||||||
property bool imagesLoaded: false
|
property bool imagesLoaded: false
|
||||||
|
property bool opened: false
|
||||||
|
property string doneFile: ""
|
||||||
|
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"
|
||||||
property color foreground: "#cacccc"
|
property color foreground: "#cacccc"
|
||||||
@@ -31,6 +35,10 @@ ShellRoot {
|
|||||||
return "'" + String(value).replace(/'/g, "'\\''") + "'"
|
return "'" + String(value).replace(/'/g, "'\\''") + "'"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function decodeField(value) {
|
||||||
|
return String(value || "").replace(/\v/g, "\n").replace(/\f/g, "\t")
|
||||||
|
}
|
||||||
|
|
||||||
function currentPath() {
|
function currentPath() {
|
||||||
if (imageModel.count === 0) return ""
|
if (imageModel.count === 0) return ""
|
||||||
return imageModel.get(selectedIndex).filePath
|
return imageModel.get(selectedIndex).filePath
|
||||||
@@ -49,10 +57,51 @@ ShellRoot {
|
|||||||
function applySelected() {
|
function applySelected() {
|
||||||
var path = currentPath()
|
var path = currentPath()
|
||||||
if (!path) return
|
if (!path) return
|
||||||
applyProc.command = ["bash", "-lc", "printf '%s\\n' " + shellQuote(path) + " > " + shellQuote(selectionFile)]
|
applyProc.command = ["bash", "-lc", "printf '%s\\n' " + shellQuote(path) + " > " + shellQuote(selectionFile) + "; : > " + shellQuote(doneFile)]
|
||||||
applyProc.running = true
|
applyProc.running = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function cancel() {
|
||||||
|
cancelProc.command = ["bash", "-lc", ": > " + shellQuote(doneFile)]
|
||||||
|
cancelProc.running = true
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadRows(rows) {
|
||||||
|
var paths = rows.split("\n")
|
||||||
|
for (var i = 0; i < paths.length; i++) {
|
||||||
|
var row = paths[i].trim()
|
||||||
|
if (!row) continue
|
||||||
|
|
||||||
|
var columns = row.split("\t")
|
||||||
|
root.addImage(columns[0], columns[1])
|
||||||
|
}
|
||||||
|
|
||||||
|
root.select(root.selectedImageIndex())
|
||||||
|
root.imagesLoaded = true
|
||||||
|
root.opened = true
|
||||||
|
list.forceActiveFocus()
|
||||||
|
}
|
||||||
|
|
||||||
|
function openSelector(nextImageDirs, nextImageRows, nextSelectedImage, nextSelectionFile, nextDoneFile, nextColorsFile) {
|
||||||
|
imageDirs = nextImageDirs
|
||||||
|
imageRows = nextImageRows
|
||||||
|
selectedImage = nextSelectedImage
|
||||||
|
selectionFile = nextSelectionFile
|
||||||
|
doneFile = nextDoneFile
|
||||||
|
colorsFile = nextColorsFile || (Quickshell.env("HOME") + "/.config/omarchy/current/theme/wallpaper-switcher-colors.json")
|
||||||
|
imageModel.clear()
|
||||||
|
selectedIndex = 0
|
||||||
|
list.currentIndex = 0
|
||||||
|
imagesLoaded = false
|
||||||
|
opened = false
|
||||||
|
if (imageRows) {
|
||||||
|
loadRows(imageRows)
|
||||||
|
} else {
|
||||||
|
loadImagesProc.output = ""
|
||||||
|
loadImagesProc.running = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ListModel {
|
ListModel {
|
||||||
id: imageModel
|
id: imageModel
|
||||||
onCountChanged: {
|
onCountChanged: {
|
||||||
@@ -92,20 +141,38 @@ ShellRoot {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
onExited: {
|
onExited: {
|
||||||
var paths = output.split("\n")
|
root.loadRows(output)
|
||||||
for (var i = 0; i < paths.length; i++) {
|
|
||||||
var row = paths[i].trim()
|
|
||||||
if (!row) continue
|
|
||||||
|
|
||||||
var columns = row.split("\t")
|
|
||||||
root.addImage(columns[0], columns[1])
|
|
||||||
}
|
|
||||||
root.select(root.selectedImageIndex())
|
|
||||||
root.imagesLoaded = true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Component.onCompleted: loadImagesProc.running = true
|
Component.onCompleted: {
|
||||||
|
if (selectionFile)
|
||||||
|
openSelector(imageDirs, "", selectedImage, selectionFile, Quickshell.env("OMARCHY_IMAGE_SELECTOR_DONE_FILE"), colorsFile)
|
||||||
|
}
|
||||||
|
|
||||||
|
IpcHandler {
|
||||||
|
target: "image-selector"
|
||||||
|
|
||||||
|
function open(imageDirs: string, imageRows: string, selectedImage: string, selectionFile: string, doneFile: string, colorsFile: string): void {
|
||||||
|
root.openSelector(imageDirs, imageRows, selectedImage, selectionFile, doneFile, colorsFile)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SocketServer {
|
||||||
|
active: true
|
||||||
|
path: root.socketPath
|
||||||
|
|
||||||
|
handler: Socket {
|
||||||
|
id: clientSocket
|
||||||
|
parser: SplitParser {
|
||||||
|
onRead: function(message) {
|
||||||
|
var fields = message.split("\t")
|
||||||
|
root.openSelector("", root.decodeField(fields[0]), fields[1] || "", fields[2] || "", fields[3] || "", fields[4] || "")
|
||||||
|
clientSocket.connected = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
FileView {
|
FileView {
|
||||||
path: root.colorsFile
|
path: root.colorsFile
|
||||||
@@ -125,12 +192,17 @@ ShellRoot {
|
|||||||
|
|
||||||
Process {
|
Process {
|
||||||
id: applyProc
|
id: applyProc
|
||||||
onExited: Qt.quit()
|
onExited: root.opened = false
|
||||||
|
}
|
||||||
|
|
||||||
|
Process {
|
||||||
|
id: cancelProc
|
||||||
|
onExited: root.opened = false
|
||||||
}
|
}
|
||||||
|
|
||||||
PanelWindow {
|
PanelWindow {
|
||||||
id: panel
|
id: panel
|
||||||
visible: root.imagesLoaded
|
visible: root.opened && root.imagesLoaded
|
||||||
anchors { top: true; bottom: true; left: true; right: true }
|
anchors { top: true; bottom: true; left: true; right: true }
|
||||||
color: "transparent"
|
color: "transparent"
|
||||||
WlrLayershell.namespace: "omarchy-image-selector"
|
WlrLayershell.namespace: "omarchy-image-selector"
|
||||||
@@ -145,7 +217,7 @@ ShellRoot {
|
|||||||
|
|
||||||
MouseArea {
|
MouseArea {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
onClicked: Qt.quit()
|
onClicked: root.cancel()
|
||||||
}
|
}
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
@@ -189,7 +261,7 @@ ShellRoot {
|
|||||||
Keys.priority: Keys.BeforeItem
|
Keys.priority: Keys.BeforeItem
|
||||||
Keys.onPressed: function(event) {
|
Keys.onPressed: function(event) {
|
||||||
if (event.key === Qt.Key_Escape) {
|
if (event.key === Qt.Key_Escape) {
|
||||||
Qt.quit()
|
root.cancel()
|
||||||
event.accepted = true
|
event.accepted = true
|
||||||
} else if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) {
|
} else if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) {
|
||||||
root.applySelected()
|
root.applySelected()
|
||||||
|
|||||||
Reference in New Issue
Block a user