Files
blomarchy/bin/blob-launch-shell

92 lines
2.6 KiB
Bash
Executable File

#!/bin/bash
# blob:summary=Launch the Blob shell with its log kept in the journal
# blob: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 blob-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; Blob restarts the shell deliberately.
# A package upgrade rewriting $BLOB_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 blob-shell -- quickshell -n -p "$BLOB_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
# (blob-shell-restart 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 blob-shell "Giving up on the Blob shell after $attempts relaunches in under a minute."
exit 1
fi
logger -t blob-shell "Blob shell exited with status $status; relaunching."
sleep 1
done