diff --git a/bin/omarchy-debug-idle b/bin/omarchy-debug-idle index db97c30e..308df73f 100755 --- a/bin/omarchy-debug-idle +++ b/bin/omarchy-debug-idle @@ -29,9 +29,12 @@ quickshell --no-color log -p "$OMARCHY_PATH/shell" --any-display --tail "$lines" section "Relevant processes" ps -eo pid=,args= \ - | grep -E 'quickshell -n -p|dbus-monitor.*PrepareForSleep|org\.omarchy\.screensaver|omarchy-screensaver|(^|/| )tte( |$)' \ + | grep -E 'quickshell -n -p|omarchy-system-sleep-monitor|systemd-inhibit.*Lock screen before suspend|org\.omarchy\.screensaver|omarchy-screensaver|(^|/| )tte( |$)' \ | grep -v grep || true +section "Sleep lock service" +systemctl --user status omarchy-sleep-lock.service --no-pager 2>/dev/null || true + section "Hyprland screensaver clients" hyprctl clients -j 2>/dev/null \ | jq -r '.[] | select(.class == "org.omarchy.screensaver" or .initialClass == "org.omarchy.screensaver") | [.pid,.class,.initialClass,.title,.focusHistoryID] | @tsv' || true diff --git a/bin/omarchy-restart-shell b/bin/omarchy-restart-shell index 88e91f7d..3896ada2 100755 --- a/bin/omarchy-restart-shell +++ b/bin/omarchy-restart-shell @@ -5,6 +5,11 @@ CONFIG_DIR="$OMARCHY_PATH/shell" +if [[ $(omarchy-shell lock isLocked 2>/dev/null || true) == "true" ]]; then + echo "Refusing to restart Omarchy shell while the session is locked." >&2 + exit 1 +fi + pkill -x quickshell 2>/dev/null || true sleep 0.2 setsid quickshell -n -p "$CONFIG_DIR" >/dev/null 2>&1 & diff --git a/bin/omarchy-system-sleep-lock b/bin/omarchy-system-sleep-lock new file mode 100755 index 00000000..be3ba621 --- /dev/null +++ b/bin/omarchy-system-sleep-lock @@ -0,0 +1,25 @@ +#!/bin/bash + +# omarchy:summary=Lock before suspend and wait for the session lock to become secure +# omarchy:group=system +# omarchy:hidden=true + +wait_attempts=${1:-100} + +if [[ ! $wait_attempts =~ ^[0-9]+$ ]] || (( wait_attempts < 1 )); then + wait_attempts=100 +fi + +omarchy-shell lock lock >/dev/null 2>&1 || exit 1 + +for (( attempt = 0; attempt < wait_attempts; attempt++ )); do + status=$(omarchy-shell lock status 2>/dev/null || true) + + if jq -e '.secure == true' <<<"$status" >/dev/null 2>&1; then + exit 0 + fi + + sleep 0.05 +done + +exit 1 diff --git a/bin/omarchy-system-sleep-monitor b/bin/omarchy-system-sleep-monitor new file mode 100755 index 00000000..37e7ca92 --- /dev/null +++ b/bin/omarchy-system-sleep-monitor @@ -0,0 +1,30 @@ +#!/bin/bash + +# omarchy:summary=Monitor sleep preparation and lock before suspend +# omarchy:group=system +# omarchy:hidden=true + +monitor_command='exec dbus-monitor --system "type='\''signal'\'',sender='\''org.freedesktop.login1'\'',interface='\''org.freedesktop.login1.Manager'\'',member='\''PrepareForSleep'\''"' + +consume_sleep_events() { + local line + + while IFS= read -r line; do + if [[ $line == *"boolean true"* ]]; then + "$OMARCHY_PATH/bin/omarchy-system-sleep-lock" + exit 0 + fi + done +} + +if [[ ${1:-} == "--consume" ]]; then + consume_sleep_events + exit 0 +fi + +exec systemd-inhibit \ + --what=sleep \ + --mode=delay \ + --who=Omarchy \ + --why="Lock screen before suspend" \ + bash -lc "$monitor_command | \"$OMARCHY_PATH/bin/omarchy-system-sleep-monitor\" --consume" diff --git a/config/systemd/user/omarchy-sleep-lock.service b/config/systemd/user/omarchy-sleep-lock.service new file mode 100644 index 00000000..39113fbc --- /dev/null +++ b/config/systemd/user/omarchy-sleep-lock.service @@ -0,0 +1,13 @@ +[Unit] +Description=Lock Omarchy before suspend +After=dbus.socket +Requires=dbus.socket + +[Service] +Type=simple +ExecStart=%h/.local/share/omarchy/bin/omarchy-system-sleep-monitor +Restart=always +RestartSec=2 + +[Install] +WantedBy=graphical-session.target diff --git a/install/config/all.sh b/install/config/all.sh index 2a99f035..06620446 100644 --- a/install/config/all.sh +++ b/install/config/all.sh @@ -7,6 +7,7 @@ run_logged $OMARCHY_INSTALL/config/timezones.sh run_logged $OMARCHY_INSTALL/config/increase-sudo-tries.sh run_logged $OMARCHY_INSTALL/config/increase-lockout-limit.sh run_logged $OMARCHY_INSTALL/config/lockscreen-pam.sh +run_logged $OMARCHY_INSTALL/config/sleep-lock.sh run_logged $OMARCHY_INSTALL/config/ssh-flakiness.sh run_logged $OMARCHY_INSTALL/config/increase-file-watchers.sh run_logged $OMARCHY_INSTALL/config/increase-fd-limit.sh diff --git a/install/config/sleep-lock.sh b/install/config/sleep-lock.sh new file mode 100644 index 00000000..62568b91 --- /dev/null +++ b/install/config/sleep-lock.sh @@ -0,0 +1,3 @@ +mkdir -p ~/.config/systemd/user/ +cp "$OMARCHY_PATH/config/systemd/user/omarchy-sleep-lock.service" ~/.config/systemd/user/ +systemctl --user enable omarchy-sleep-lock.service diff --git a/migrations/1779330555.sh b/migrations/1779330555.sh new file mode 100644 index 00000000..0821b301 --- /dev/null +++ b/migrations/1779330555.sh @@ -0,0 +1,8 @@ +echo "Install sleep lock service" + +mkdir -p ~/.config/systemd/user/ +cp "$OMARCHY_PATH/config/systemd/user/omarchy-sleep-lock.service" ~/.config/systemd/user/ + +systemctl --user daemon-reload +systemctl --user reset-failed omarchy-sleep-lock.service 2>/dev/null || true +systemctl --user enable --now omarchy-sleep-lock.service diff --git a/shell/plugins/services/idle/Service.qml b/shell/plugins/services/idle/Service.qml index c6651cc2..1d16df79 100644 --- a/shell/plugins/services/idle/Service.qml +++ b/shell/plugins/services/idle/Service.qml @@ -202,7 +202,6 @@ Item { idle: idleMonitor.isIdle, inIdleCycle: root.idledThisCycle, screensaverStarted: root.screensaverStartedThisCycle, - sleepMonitor: sleepMonitorProcess.running, screensaver: root.screensaverTimeoutSeconds, lock: root.lockTimeoutSeconds, screensaverDelay: root.screensaverDelaySeconds, @@ -211,32 +210,18 @@ Item { timers: { screensaver: screensaverTimer.running, lock: lockTimer.running, - screensaverLaunchGrace: screensaverLaunchGraceTimer.running, - sleepMonitorRestart: sleepMonitorRestartTimer.running + screensaverLaunchGrace: screensaverLaunchGraceTimer.running }, processes: { screensaver: screensaverProcess.running, lock: lockProcess.running, - wake: wakeProcess.running, - sleepLock: sleepLockProcess.running, - sleepWake: sleepWakeProcess.running + wake: wakeProcess.running }, lastEvent: root.lastEvent, lastEventAt: root.lastEventAt }) } - function handleSleepPreparing(preparing) { - if (!root.idleEnabled) return - - if (preparing) { - cancelIdleCycle("sleep-preparing") - runProcess(sleepLockProcess, "sleep-lock", "OMARCHY_LOCK_ONLY=true omarchy-system-lock") - } else { - runProcess(sleepWakeProcess, "sleep-wake", "sleep 1 && omarchy-system-wake") - } - } - function setIdleEnabled(value) { var enabled = !!value if (persisted.idleEnabled === enabled) return enabled ? "enabled" : "disabled" @@ -299,43 +284,6 @@ Item { id: wakeProcess onExited: function(exitCode, exitStatus) { root.logEvent("process-exit", "wake exitCode=" + exitCode + " status=" + exitStatus) } } - Process { - id: sleepLockProcess - onExited: function(exitCode, exitStatus) { root.logEvent("process-exit", "sleep-lock exitCode=" + exitCode + " status=" + exitStatus) } - } - Process { - id: sleepWakeProcess - onExited: function(exitCode, exitStatus) { root.logEvent("process-exit", "sleep-wake exitCode=" + exitCode + " status=" + exitStatus) } - } - - Process { - id: sleepMonitorProcess - command: ["bash", "-lc", "exec dbus-monitor --system \"type='signal',sender='org.freedesktop.login1',interface='org.freedesktop.login1.Manager',member='PrepareForSleep'\""] - running: true - stdout: SplitParser { - onRead: function(line) { - var text = String(line || "").trim() - if (text === "boolean true") root.handleSleepPreparing(true) - else if (text === "boolean false") root.handleSleepPreparing(false) - } - } - onExited: { - root.logEvent("sleep-monitor-exit", "restarting") - sleepMonitorRestartTimer.restart() - } - } - - Timer { - id: sleepMonitorRestartTimer - interval: 5000 - repeat: false - onTriggered: { - if (!sleepMonitorProcess.running) { - root.logEvent("sleep-monitor-restart") - sleepMonitorProcess.running = true - } - } - } Component.onCompleted: { logEvent("service-ready")