swadhinbiswas Initial de-omarchy: Omarchy UI layer for Arch-based distros · 8/22/2026
9f393b2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
#!/bin/bash
# omarchy:summary=Launch the Omarchy shell with its log kept in the journal
# omarchy:hidden=true
# Quickshell only logs to its instance runtime dir (tmpfs), so when the shell
# dies the idle/lock event trail is gone after a reboot. The journal keeps it
# across sessions, bounded and timestamped, under the omarchy-shell tag.
#
# Backgrounded because bash defers a trap until a foreground command returns but
# interrupts wait. systemd-cat execs, so the job is Quickshell itself.
#
# Quickshell's own reloading is off; Omarchy restarts the shell deliberately.
# A package upgrade rewriting $OMARCHY_PATH/shell would otherwise reload it
# against a half-written tree, and that failed reload leaves a second engine
# generation behind that turns the next restart's IPC kill into a crash.
run_shell() {
QS_DISABLE_FILE_WATCHER=1 QS_NO_RELOAD_POPUP=1 \
systemd-cat -t omarchy-shell -- quickshell -n -p "$OMARCHY_PATH/shell" &
shell_pid=$!
local status
while true; do
wait "$shell_pid"
status=$?
# An interrupted wait and a shell killed by that signal report alike.
kill -0 "$shell_pid" 2>/dev/null || break
done
shell_pid=""
return $status
}
# A compositor busy reconfiguring outputs can miss a query without being gone,
# and that is when the shell dies.
compositor_alive() {
local attempt
for attempt in 1 2 3; do
hyprctl -j monitors >/dev/null 2>&1 && return 0
(( attempt < 3 )) && sleep 0.5
done
return 1
}
# Quickshell relaunches itself from its signal handlers, but Qt leaves through
# _exit() when the Wayland connection fails, raising no signal: no crash report,
# no relaunch, no bar. Supervise those deaths. A clean exit is a deliberate stop
# (omarchy-restart-shell starts its own replacement); a signal here means the
# session is going, and has to reach the shell the launcher used to exec.
terminating=0
shell_pid=""
stop() {
terminating=1
[[ -n $shell_pid ]] && kill -TERM "$shell_pid" 2>/dev/null
return 0
}
trap stop HUP INT TERM
attempts=0
window_started=$SECONDS
while true; do
# A signal during the backoff only reaches the trap once the sleep is over.
(( terminating )) && exit 0
run_shell
status=$?
(( terminating )) && exit 0
(( status == 0 )) && exit 0
# Relaunching into a session already tearing down burns the attempt budget.
compositor_alive || exit 0
if (( SECONDS - window_started > 60 )); then
attempts=0
window_started=$SECONDS
fi
if (( ++attempts > 5 )); then
logger -t omarchy-shell "Giving up on the Omarchy shell after $attempts relaunches in under a minute."
exit 1
fi
logger -t omarchy-shell "Omarchy shell exited with status $status; relaunching."
sleep 1
done