mirror of
https://github.com/arthur-pbty/arthur-os.git
synced 2026-08-01 20:28:16 +02:00
Pause Hyprland reloads during settings updates
This commit is contained in:
Executable
+138
@@ -0,0 +1,138 @@
|
||||
#!/bin/bash
|
||||
|
||||
# omarchy:summary=Pause or resume Hyprland config auto-reload around package transactions.
|
||||
# omarchy:hidden=true
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
command="${1:-}"
|
||||
case "$command" in
|
||||
pause | resume) ;;
|
||||
*)
|
||||
echo "Usage: omarchy-hyprland-reload-guard pause|resume" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
run_root="${OMARCHY_HYPRLAND_RELOAD_GUARD_RUN_ROOT:-/run/user}"
|
||||
state_dir="${OMARCHY_HYPRLAND_RELOAD_GUARD_STATE_DIR:-/run/omarchy/hyprland-reload-guard}"
|
||||
hyprctl_bin="${HYPRCTL:-}"
|
||||
|
||||
if [[ -z $hyprctl_bin ]]; then
|
||||
hyprctl_bin=/usr/bin/hyprctl
|
||||
[[ -x $hyprctl_bin ]] || hyprctl_bin=$(command -v hyprctl || true)
|
||||
fi
|
||||
[[ -n $hyprctl_bin && -x $hyprctl_bin ]] || exit 0
|
||||
|
||||
hyprctl_instance() {
|
||||
local runtime_dir="$1"
|
||||
local signature="$2"
|
||||
shift 2
|
||||
|
||||
XDG_RUNTIME_DIR="$runtime_dir" \
|
||||
HYPRLAND_INSTANCE_SIGNATURE="$signature" \
|
||||
"$hyprctl_bin" --instance "$signature" "$@"
|
||||
}
|
||||
|
||||
option_bool() {
|
||||
local runtime_dir="$1"
|
||||
local signature="$2"
|
||||
local option="$3"
|
||||
local output=""
|
||||
|
||||
output=$(hyprctl_instance "$runtime_dir" "$signature" -j getoption "$option" 2>/dev/null) || return 1
|
||||
|
||||
if command -v jq >/dev/null 2>&1; then
|
||||
jq -r 'if .bool == true then "true" else "false" end' <<<"$output"
|
||||
elif [[ $output == *'"bool": true'* ]]; then
|
||||
printf 'true\n'
|
||||
else
|
||||
printf 'false\n'
|
||||
fi
|
||||
}
|
||||
|
||||
instances() {
|
||||
[[ -d $run_root ]] || return 0
|
||||
|
||||
find "$run_root" -mindepth 3 -maxdepth 3 -type d -path "$run_root/*/hypr/*" -print 2>/dev/null |
|
||||
while IFS= read -r instance_dir; do
|
||||
local signature hypr_dir runtime_dir uid
|
||||
|
||||
signature="${instance_dir##*/}"
|
||||
hypr_dir="${instance_dir%/*}"
|
||||
runtime_dir="${hypr_dir%/*}"
|
||||
uid="${runtime_dir##*/}"
|
||||
|
||||
[[ $uid =~ ^[0-9]+$ ]] || continue
|
||||
[[ -n $signature ]] || continue
|
||||
|
||||
printf '%s\t%s\t%s\n' "$runtime_dir" "$uid" "$signature"
|
||||
done
|
||||
}
|
||||
|
||||
state_file_for() {
|
||||
local signature="$1"
|
||||
|
||||
printf '%s/%s\n' "$state_dir" "$signature"
|
||||
}
|
||||
|
||||
pause_instance() {
|
||||
local runtime_dir="$1"
|
||||
local uid="$2"
|
||||
local signature="$3"
|
||||
local disable_autoreload suppress_errors state_file
|
||||
|
||||
mkdir -p "$state_dir"
|
||||
state_file=$(state_file_for "$signature")
|
||||
|
||||
if [[ ! -f $state_file ]]; then
|
||||
disable_autoreload=$(option_bool "$runtime_dir" "$signature" misc.disable_autoreload) || return 0
|
||||
suppress_errors=$(option_bool "$runtime_dir" "$signature" debug.suppress_errors) || return 0
|
||||
|
||||
printf '%s\t%s\t%s\n' "$uid" "$disable_autoreload" "$suppress_errors" >"$state_file"
|
||||
chmod 0600 "$state_file" 2>/dev/null || true
|
||||
fi
|
||||
|
||||
hyprctl_instance "$runtime_dir" "$signature" eval \
|
||||
'hl.config({ misc = { disable_autoreload = true }, debug = { suppress_errors = true } })' \
|
||||
>/dev/null 2>&1 || true
|
||||
}
|
||||
|
||||
resume_instance() {
|
||||
local state_file="$1"
|
||||
local signature uid disable_autoreload suppress_errors runtime_dir
|
||||
|
||||
signature="${state_file##*/}"
|
||||
IFS=$'\t' read -r uid disable_autoreload suppress_errors <"$state_file" || return 0
|
||||
runtime_dir="$run_root/$uid"
|
||||
|
||||
if [[ -d $runtime_dir ]]; then
|
||||
hyprctl_instance "$runtime_dir" "$signature" eval \
|
||||
"hl.config({ debug = { suppress_errors = $suppress_errors } })" \
|
||||
>/dev/null 2>&1 || true
|
||||
|
||||
hyprctl_instance "$runtime_dir" "$signature" reload >/dev/null 2>&1 || true
|
||||
|
||||
hyprctl_instance "$runtime_dir" "$signature" eval \
|
||||
"hl.config({ misc = { disable_autoreload = $disable_autoreload }, debug = { suppress_errors = $suppress_errors } })" \
|
||||
>/dev/null 2>&1 || true
|
||||
fi
|
||||
|
||||
rm -f "$state_file"
|
||||
}
|
||||
|
||||
case "$command" in
|
||||
pause)
|
||||
while IFS=$'\t' read -r runtime_dir uid signature; do
|
||||
pause_instance "$runtime_dir" "$uid" "$signature"
|
||||
done < <(instances)
|
||||
;;
|
||||
resume)
|
||||
[[ -d $state_dir ]] || exit 0
|
||||
find "$state_dir" -mindepth 1 -maxdepth 1 -type f -print 2>/dev/null |
|
||||
while IFS= read -r state_file; do
|
||||
resume_instance "$state_file"
|
||||
done
|
||||
rmdir "$state_dir" 2>/dev/null || true
|
||||
;;
|
||||
esac
|
||||
@@ -0,0 +1,12 @@
|
||||
[Trigger]
|
||||
Operation = Install
|
||||
Operation = Upgrade
|
||||
Type = Package
|
||||
Target = omarchy-settings
|
||||
Target = omarchy-settings-dev
|
||||
|
||||
[Action]
|
||||
Description = Pausing Hyprland config auto-reload for Omarchy settings update...
|
||||
When = PreTransaction
|
||||
Depends = omarchy
|
||||
Exec = /usr/bin/omarchy-hyprland-reload-guard pause
|
||||
@@ -0,0 +1,12 @@
|
||||
[Trigger]
|
||||
Operation = Install
|
||||
Operation = Upgrade
|
||||
Type = Package
|
||||
Target = omarchy-settings
|
||||
Target = omarchy-settings-dev
|
||||
|
||||
[Action]
|
||||
Description = Reloading Hyprland after Omarchy settings update...
|
||||
When = PostTransaction
|
||||
Depends = omarchy
|
||||
Exec = /usr/bin/omarchy-hyprland-reload-guard resume
|
||||
+2
-2
@@ -54,8 +54,8 @@ bin/omarchy-debug,
|
||||
bin/omarchy-debug-idle,
|
||||
bin/omarchy-upload-log ──► omarchy-settings /usr/bin/ (needed before omarchy is installed)
|
||||
|
||||
default/libalpm/hooks/00-omarchy-update-guard.hook
|
||||
──► omarchy /usr/share/libalpm/hooks/00-omarchy-update-guard.hook
|
||||
default/libalpm/hooks/*.hook
|
||||
──► omarchy /usr/share/libalpm/hooks/*.hook
|
||||
|
||||
install/** ──► omarchy /usr/share/omarchy/install/
|
||||
migrations/system/** ──► omarchy /usr/share/omarchy/migrations/system/
|
||||
|
||||
@@ -151,6 +151,14 @@ sudo env OMARCHY_ALLOW_DIRECT_PACMAN=1 pacman -Syu
|
||||
The guard does not start `omarchy update` itself because pacman is already in a
|
||||
transaction setup path; it only aborts with instructions.
|
||||
|
||||
The `omarchy` package also installs ALPM hooks for `omarchy-settings` /
|
||||
`omarchy-settings-dev` installs and upgrades. The pre-transaction hook runs
|
||||
`omarchy-hyprland-reload-guard pause` to disable live Hyprland config reloads
|
||||
while `/usr/share/omarchy/default/hypr/**` is replaced. The post-transaction
|
||||
hook runs `omarchy-hyprland-reload-guard resume`, forces one `hyprctl reload`,
|
||||
and restores the session's previous `misc.disable_autoreload` and
|
||||
`debug.suppress_errors` values.
|
||||
|
||||
## Path 1: `omarchy update`
|
||||
|
||||
High-level flow:
|
||||
|
||||
@@ -127,12 +127,18 @@ for source, destination, legacy in package_defaults:
|
||||
if destination and (source not in pkgbuild or destination not in pkgbuild):
|
||||
errors.append(f"PKGBUILD does not explicitly install {source} -> {destination}")
|
||||
|
||||
guard_hook = "default/libalpm/hooks/00-omarchy-update-guard.hook"
|
||||
guard_destination = "/usr/share/libalpm/hooks/00-omarchy-update-guard.hook"
|
||||
if not (root / guard_hook).exists():
|
||||
errors.append(f"missing package default source: {guard_hook}")
|
||||
if guard_hook not in omarchy_pkgbuild or guard_destination not in omarchy_pkgbuild:
|
||||
errors.append(f"omarchy PKGBUILD does not install {guard_hook} -> {guard_destination}")
|
||||
alpm_hooks = [
|
||||
"00-omarchy-update-guard.hook",
|
||||
"10-omarchy-hyprland-reload-pause.hook",
|
||||
"90-omarchy-hyprland-reload-resume.hook",
|
||||
]
|
||||
for hook in alpm_hooks:
|
||||
source = f"default/libalpm/hooks/{hook}"
|
||||
destination = f"/usr/share/libalpm/hooks/{hook}"
|
||||
if not (root / source).exists():
|
||||
errors.append(f"missing package default source: {source}")
|
||||
if source not in omarchy_pkgbuild or destination not in omarchy_pkgbuild:
|
||||
errors.append(f"omarchy PKGBUILD does not install {source} -> {destination}")
|
||||
|
||||
if errors:
|
||||
print("\n".join(errors), file=sys.stderr)
|
||||
|
||||
Executable
+60
@@ -0,0 +1,60 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
source "$(dirname "$0")/base-test.sh"
|
||||
|
||||
test_tmp=$(mktemp -d)
|
||||
trap 'rm -rf "$test_tmp"' EXIT
|
||||
|
||||
run_root="$test_tmp/run-user"
|
||||
state_dir="$test_tmp/state"
|
||||
hyprctl_log="$test_tmp/hyprctl.log"
|
||||
fake_hyprctl="$test_tmp/hyprctl"
|
||||
signature="test-signature"
|
||||
runtime_dir="$run_root/1000"
|
||||
|
||||
mkdir -p "$runtime_dir/hypr/$signature"
|
||||
|
||||
cat >"$fake_hyprctl" <<'BASH'
|
||||
#!/bin/bash
|
||||
|
||||
printf '%s\t%s\t%s\n' "$XDG_RUNTIME_DIR" "$HYPRLAND_INSTANCE_SIGNATURE" "$*" >>"$FAKE_HYPRCTL_LOG"
|
||||
|
||||
case "$*" in
|
||||
*'getoption misc.disable_autoreload'*)
|
||||
printf '{"option":"misc.disable_autoreload","bool":%s,"set":true}\n' "${FAKE_DISABLE_AUTORELOAD:-false}"
|
||||
;;
|
||||
*'getoption debug.suppress_errors'*)
|
||||
printf '{"option":"debug.suppress_errors","bool":%s,"set":true}\n' "${FAKE_SUPPRESS_ERRORS:-false}"
|
||||
;;
|
||||
*)
|
||||
printf 'ok\n'
|
||||
;;
|
||||
esac
|
||||
BASH
|
||||
chmod 0755 "$fake_hyprctl"
|
||||
|
||||
FAKE_HYPRCTL_LOG="$hyprctl_log" \
|
||||
HYPRCTL="$fake_hyprctl" \
|
||||
OMARCHY_HYPRLAND_RELOAD_GUARD_RUN_ROOT="$run_root" \
|
||||
OMARCHY_HYPRLAND_RELOAD_GUARD_STATE_DIR="$state_dir" \
|
||||
"$ROOT/bin/omarchy-hyprland-reload-guard" pause
|
||||
|
||||
state_file="$state_dir/$signature"
|
||||
[[ -f $state_file ]] || fail "reload guard stores Hyprland state on pause"
|
||||
grep -Fx $'1000 false false' "$state_file" >/dev/null || fail "reload guard records previous Hyprland reload settings"
|
||||
grep -F 'hl.config({ misc = { disable_autoreload = true }, debug = { suppress_errors = true } })' "$hyprctl_log" >/dev/null || fail "reload guard pauses autoreload with hyprctl eval"
|
||||
pass "reload guard pauses live Hyprland reloads"
|
||||
|
||||
: >"$hyprctl_log"
|
||||
FAKE_HYPRCTL_LOG="$hyprctl_log" \
|
||||
HYPRCTL="$fake_hyprctl" \
|
||||
OMARCHY_HYPRLAND_RELOAD_GUARD_RUN_ROOT="$run_root" \
|
||||
OMARCHY_HYPRLAND_RELOAD_GUARD_STATE_DIR="$state_dir" \
|
||||
"$ROOT/bin/omarchy-hyprland-reload-guard" resume
|
||||
|
||||
[[ ! -e $state_file ]] || fail "reload guard clears Hyprland state after resume"
|
||||
grep -F $'test-signature --instance test-signature reload' "$hyprctl_log" >/dev/null || fail "reload guard forces one Hyprland reload after package transaction"
|
||||
grep -F 'hl.config({ misc = { disable_autoreload = false }, debug = { suppress_errors = false } })' "$hyprctl_log" >/dev/null || fail "reload guard restores previous Hyprland reload settings"
|
||||
pass "reload guard resumes live Hyprland reloads"
|
||||
Reference in New Issue
Block a user