Faster theme and bg changes

This commit is contained in:
David Heinemeier Hansson
2026-05-17 16:41:44 +02:00
parent 19a3622e7e
commit 4e50960c54
9 changed files with 251 additions and 36 deletions
+12 -2
View File
@@ -1,7 +1,7 @@
#!/bin/bash
# omarchy:summary=Open a generic image selector menu
# omarchy:args=[--selected <image>] [--print-name] [--show-labels] [--filterable] [--lazy-thumbnails] [--cache-only] <image-dir>...
# omarchy:args=[--selected <image>] [--print-name] [--show-labels] [--filterable] [--lazy-thumbnails] [--preload] [--cache-only] <image-dir>...
OMARCHY_PATH=${OMARCHY_PATH:-$HOME/.local/share/omarchy}
@@ -11,11 +11,12 @@ show_labels=false
filterable=false
lazy_thumbnails=false
prepare_only=false
preload=false
cache_only=false
image_dirs=()
usage() {
echo "Usage: omarchy-menu-images [--selected <image>] [--print-name] [--show-labels] [--filterable] [--lazy-thumbnails] [--cache-only] <image-dir>..."
echo "Usage: omarchy-menu-images [--selected <image>] [--print-name] [--show-labels] [--filterable] [--lazy-thumbnails] [--preload] [--cache-only] <image-dir>..."
}
while [[ $# -gt 0 ]]; do
@@ -49,6 +50,10 @@ while [[ $# -gt 0 ]]; do
prepare_only=true
shift
;;
--preload)
preload=true
shift
;;
--cache-only)
cache_only=true
shift
@@ -225,6 +230,11 @@ fi
# ImagePicker plugin Qt.atob()s on the other side.
rows_b64=$(printf '%s' "$rows" | base64 -w 0)
if [[ $preload == true ]]; then
omarchy-shell-ipc image-selector preload "$rows_b64" "$selected_list_image" "$show_labels" "$filterable" >/dev/null || true
exit 0
fi
send_builtin_ipc_request() {
perl -MCwd=abs_path -MEncode=encode,decode -MSocket \
-e '
+61
View File
@@ -0,0 +1,61 @@
#!/bin/bash
# omarchy:summary=Send a fire-and-forget IPC call to a running omarchy-shell
# omarchy:hidden=true
OMARCHY_PATH=${OMARCHY_PATH:-$HOME/.local/share/omarchy}
SHELL_QML="$OMARCHY_PATH/default/quickshell/omarchy-shell/shell.qml"
if (( $# < 2 )); then
echo "Usage: omarchy-shell-ipc-fast <target> <function> [args...]" >&2
exit 1
fi
perl -MCwd=abs_path -MEncode=encode,decode -MSocket \
-e '
sub read_qstring {
my ($data, $offset) = @_;
return ("", $offset) if $offset + 4 > length($data);
my $length = unpack("N", substr($data, $offset, 4));
$offset += 4;
return ("", $offset) if $length == 0xffffffff || $offset + $length > length($data);
return (decode("UTF-16BE", substr($data, $offset, $length)), $offset + $length);
}
sub qstring {
my $encoded = encode("UTF-16BE", $_[0] // "");
return pack("N", length($encoded)) . $encoded;
}
my $shell_qml = abs_path(shift @ARGV);
my $target = shift @ARGV;
my $function = shift @ARGV;
my @args = @ARGV;
my $runtime_dir = $ENV{"XDG_RUNTIME_DIR"} || "/run/user/$<";
my $payload = chr(3) . qstring($target) . qstring($function) . pack("N", scalar @args) . join("", map { qstring($_) } @args);
my @candidates;
for my $lock_path (glob("$runtime_dir/quickshell/by-id/*/instance.lock")) {
my $data;
next unless open(my $lock, "<:raw", $lock_path);
{ local $/; $data = <$lock>; }
close($lock);
my (undef, $offset) = read_qstring($data, 0);
my ($path) = read_qstring($data, $offset);
next unless $path && abs_path($path) eq $shell_qml;
(my $socket_path = $lock_path) =~ s{/instance\.lock$}{/ipc.sock};
push @candidates, [(stat($lock_path))[9] || 0, $socket_path];
}
for my $candidate (sort { $b->[0] <=> $a->[0] } @candidates) {
socket(my $client, AF_UNIX, SOCK_STREAM, 0) || next;
if (connect($client, sockaddr_un($candidate->[1]))) {
syswrite($client, $payload);
close($client);
exit 0;
}
close($client);
}
exit 1;
' "$SHELL_QML" "$@"
+4
View File
@@ -19,3 +19,7 @@ fi
# Create symlink to the new background
ln -nsf "$BACKGROUND" "$CURRENT_BACKGROUND_LINK"
# Update the live shell background immediately when it is running. The
# background plugin also polls this symlink, but IPC avoids the visible delay.
omarchy-shell-ipc-fast background set "$BACKGROUND" >/dev/null 2>&1 || true
+50 -7
View File
@@ -11,6 +11,7 @@ fi
CURRENT_THEME_PATH="$HOME/.config/omarchy/current/theme"
NEXT_THEME_PATH="$HOME/.config/omarchy/current/next-theme"
CURRENT_BACKGROUND_LINK="$HOME/.config/omarchy/current/background"
USER_THEMES_PATH="$HOME/.config/omarchy/themes"
OMARCHY_THEMES_PATH="$OMARCHY_PATH/themes"
@@ -28,6 +29,41 @@ run_parallel() {
done
}
set_theme_background() {
local backgrounds=()
local current_background index new_background next_index
mapfile -d '' -t backgrounds < <(
find -L "$HOME/.config/omarchy/backgrounds/$THEME_NAME/" "$CURRENT_THEME_PATH/backgrounds/" -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
)
if (( ${#backgrounds[@]} == 0 )); then
omarchy-notification-send "No background was found for theme" -t 2000
return
fi
current_background=$(readlink "$CURRENT_BACKGROUND_LINK" 2>/dev/null || true)
index=-1
for i in "${!backgrounds[@]}"; do
if [[ ${backgrounds[$i]} == $current_background ]]; then
index=$i
break
fi
done
if (( index == -1 )); then
new_background="${backgrounds[0]}"
else
next_index=$(((index + 1) % ${#backgrounds[@]}))
new_background="${backgrounds[$next_index]}"
fi
ln -nsf "$new_background" "$CURRENT_BACKGROUND_LINK"
omarchy-shell-ipc-fast background setInstant "$new_background" >/dev/null 2>&1 || true
}
THEME_NAME=$(echo "$1" | sed -E 's/<[^>]+>//g' | tr '[:upper:]' '[:lower:]' | tr ' ' '-')
if [[ ! -d $OMARCHY_THEMES_PATH/$THEME_NAME ]] && [[ ! -d $USER_THEMES_PATH/$THEME_NAME ]]; then
@@ -58,8 +94,17 @@ mv "$NEXT_THEME_PATH" "$CURRENT_THEME_PATH"
# Store theme name for reference
echo "$THEME_NAME" >"$HOME/.config/omarchy/current/theme.name"
# Make the running shell pick up the new palette immediately instead of waiting
# for file-watch debounce while the rest of the theme hooks run.
colors_payload=$([[ -f $CURRENT_THEME_PATH/colors.toml ]] && base64 -w 0 "$CURRENT_THEME_PATH/colors.toml")
shell_payload=$([[ -f $CURRENT_THEME_PATH/shell.toml ]] && base64 -w 0 "$CURRENT_THEME_PATH/shell.toml")
omarchy-shell-ipc-fast shell applyTheme "$colors_payload" "$shell_payload" >/dev/null 2>&1 || true
if [[ $OMARCHY_THEME_SKIP_BACKGROUND != "1" ]]; then
set_theme_background
fi
post_theme_commands=(
omarchy-restart-shell
omarchy-restart-terminal
omarchy-restart-hyprctl
omarchy-restart-btop
@@ -73,15 +118,13 @@ post_theme_commands=(
omarchy-theme-set-keyboard
)
# Change background with theme while restarting/retheming independent components.
if [[ $OMARCHY_THEME_SKIP_BACKGROUND != "1" ]]; then
post_theme_commands+=(omarchy-theme-bg-next)
fi
run_parallel "${post_theme_commands[@]}"
# Call hook on theme set
omarchy-hook theme-set "$THEME_NAME" >/dev/null
# Warm the background selector cache after the theme is applied, off the critical path.
# Warm selector caches after the theme is applied. The shell hot-reloads theme
# colors/backgrounds, so keep the running instance alive and preload the picker
# rows/selection to avoid first-open carousel settling after a theme change.
omarchy-theme-switcher --preload >/dev/null 2>&1
omarchy-theme-bg-cache >/dev/null 2>&1 &
+20 -7
View File
@@ -3,6 +3,13 @@
# omarchy:summary=Open the Omarchy theme switcher
OMARCHY_PATH=${OMARCHY_PATH:-$HOME/.local/share/omarchy}
preload=false
if [[ $1 == "--preload" ]]; then
preload=true
shift
fi
USER_THEMES_PATH="$HOME/.config/omarchy/themes"
OMARCHY_THEMES_PATH="$OMARCHY_PATH/themes"
CACHE_PATH="${XDG_CACHE_HOME:-$HOME/.cache}/omarchy/theme-selector"
@@ -104,10 +111,16 @@ for extension in png jpg jpeg webp gif bmp; do
break
fi
done
exec omarchy-menu-images \
--print-name \
--show-labels \
--filterable \
--lazy-thumbnails \
--selected "$selected_preview" \
"$preview_dir"
menu_args=(
--print-name
--show-labels
--filterable
--lazy-thumbnails
--selected "$selected_preview"
)
if [[ $preload == true ]]; then
menu_args+=(--preload)
fi
exec omarchy-menu-images "${menu_args[@]}" "$preview_dir"