Fork the desktop off Omarchy as a self-contained system
This commit is contained in:
Executable
+93
@@ -0,0 +1,93 @@
|
||||
#!/bin/bash
|
||||
|
||||
# blob:summary=Restart the Blob shell
|
||||
# blob:examples=blob restart shell
|
||||
|
||||
# A caller opened after dev link/unlink may disagree with the still-running
|
||||
# desktop. The user manager receives Hyprland's environment at session start.
|
||||
session_blob_path=$(systemctl --user show-environment 2>/dev/null | sed -n 's/^BLOB_PATH=//p' | tail -n 1)
|
||||
: "${session_blob_path:=$BLOB_PATH}"
|
||||
|
||||
CONFIG_DIR="$session_blob_path/shell"
|
||||
[[ -f $CONFIG_DIR/shell.qml ]] || { echo "Blob shell config not found: $CONFIG_DIR" >&2; exit 1; }
|
||||
|
||||
# Allow running from outside the session (e.g. over ssh) by deriving the
|
||||
# Hyprland instance signature from the newest instance runtime dir.
|
||||
if [[ -z ${HYPRLAND_INSTANCE_SIGNATURE:-} ]]; then
|
||||
hypr_dir=$(find "${XDG_RUNTIME_DIR:-/run/user/$UID}/hypr" -mindepth 1 -maxdepth 1 -type d -printf '%T@ %p\n' 2>/dev/null | sort -n | tail -n 1 | cut -d' ' -f2-)
|
||||
[[ -n $hypr_dir ]] && export HYPRLAND_INSTANCE_SIGNATURE=${hypr_dir##*/}
|
||||
fi
|
||||
|
||||
# Restarting a live lock client would kill the lock screen and strand the
|
||||
# session behind Hyprland's failsafe. But a LOCK session without an active
|
||||
# locker — the shell died, or its crash handler re-execed a fresh instance
|
||||
# that holds no lock — sits in that failsafe with no way to authenticate,
|
||||
# and a restart plus re-lock is the only way back in without a reboot. So
|
||||
# ask the lock service rather than merely pinging the shell: only a locker
|
||||
# that reports the lock secure or in progress is worth preserving.
|
||||
relock=0
|
||||
if blob-hypr-session-locked; then
|
||||
locking=$(BLOB_PATH="$session_blob_path" BLOB_SHELL_IPC_TIMEOUT=0.5s blob-shell lock status 2>/dev/null |
|
||||
jq -r '.secure or .requested' 2>/dev/null)
|
||||
if [[ $locking == "true" ]]; then
|
||||
echo "Refusing to restart Blob shell while the session is locked." >&2
|
||||
exit 1
|
||||
fi
|
||||
relock=1
|
||||
fi
|
||||
|
||||
# The lock plugin loads asynchronously, so a fresh shell answers ping before
|
||||
# it can lock, and may even refuse early lock requests while its plugins or
|
||||
# PAM config are still loading. Mirror blob-system-sleep: request the
|
||||
# lock and poll until the session reports secure, re-requesting as needed, so
|
||||
# recovery never claims success while the failsafe is still up. The deadline
|
||||
# is generous because slow plugin discovery delays the lock IPC target.
|
||||
relock_session() {
|
||||
local state deadline=$((SECONDS + 30))
|
||||
|
||||
while (( SECONDS < deadline )); do
|
||||
state=$(BLOB_PATH="$session_blob_path" BLOB_SHELL_IPC_TIMEOUT=0.5s blob-shell lock status 2>/dev/null |
|
||||
jq -r 'if .secure == true then "secure" elif .requested == true then "locking" else "idle" end' 2>/dev/null)
|
||||
|
||||
case $state in
|
||||
secure) return 0 ;;
|
||||
locking) ;;
|
||||
*) BLOB_PATH="$session_blob_path" BLOB_SHELL_IPC_TIMEOUT=0.5s blob-shell lock lock >/dev/null 2>&1 ;;
|
||||
esac
|
||||
|
||||
sleep 0.1
|
||||
done
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
# Each kill stops the oldest matching instance and only returns once it has
|
||||
# fully exited, so the no-duplicate launch below can't race a dying shell.
|
||||
while timeout 5 quickshell kill -p "$CONFIG_DIR" --any-display >/dev/null 2>&1; do :; done
|
||||
|
||||
# Spawn from Hyprland so the shell inherits the canonical session environment,
|
||||
# not transient variables from a terminal, SSH connection, or development tool.
|
||||
hyprctl dispatch 'hl.dsp.exec_cmd("blob-launch-shell")' >/dev/null
|
||||
|
||||
for (( attempt = 0; attempt < 20; attempt++ )); do
|
||||
if BLOB_PATH="$session_blob_path" BLOB_SHELL_IPC_TIMEOUT=0.5s blob-shell shell ping >/dev/null 2>&1; then
|
||||
# The session stays compositor-locked after the old lock client died, so
|
||||
# re-acquire the lock and let the user authenticate out of it.
|
||||
if (( relock )) && ! relock_session; then
|
||||
echo "Blob shell restarted, but the session lock was not re-secured." >&2
|
||||
exit 1
|
||||
fi
|
||||
# Invitation toasts (like Voxtype/fingerprint setup) die with the old
|
||||
# shell, and their notify-send waiters hang forever: the dying server
|
||||
# never emits NotificationClosed. A still-running blob-*-invitation
|
||||
# unit is therefore an unanswered invitation — re-run it so its toast
|
||||
# reappears on the new shell. Answered invitations have already exited
|
||||
# and been collected, so the glob no longer matches them.
|
||||
systemctl --user try-restart 'blob-*-invitation.service' 2>/dev/null || true
|
||||
exit 0
|
||||
fi
|
||||
sleep 0.1
|
||||
done
|
||||
|
||||
echo "Blob shell did not become ready after restart." >&2
|
||||
exit 1
|
||||
Reference in New Issue
Block a user