From eb3cb5225c2f93b001178a9e9a234c8a297c3104 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Mon, 22 Jun 2026 19:44:37 +0200 Subject: [PATCH] Delay session lock during display hotplug --- shell/plugins/lock/Service.qml | 23 +++++++++++++++++++++-- test/shell.d/monitor-recovery-test.sh | 4 +++- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/shell/plugins/lock/Service.qml b/shell/plugins/lock/Service.qml index ac1bed40..be2a0ba7 100644 --- a/shell/plugins/lock/Service.qml +++ b/shell/plugins/lock/Service.qml @@ -51,11 +51,19 @@ Item { return realScreenCount() > 0 } + function queueSessionLock() { + pendingSessionLock = true + if (!sessionLockStabilizeTimer.running) logEvent("lock-pending: screen-stabilizing") + sessionLockStabilizeTimer.restart() + if (!pendingSessionLockTimer.running) pendingSessionLockTimer.start() + } + function requestSessionLock() { if (!lockRequested || sessionLock.locked || sessionLock.secure) return + if (sessionLockStabilizeTimer.running) return if (!hasRealScreen()) { - if (!pendingSessionLock) logEvent("lock-pending: no-real-screen") + if (!pendingSessionLock || lastEvent !== "lock-pending: no-real-screen") logEvent("lock-pending: no-real-screen") pendingSessionLock = true if (!pendingSessionLockTimer.running) pendingSessionLockTimer.start() return @@ -102,7 +110,7 @@ Item { lockRequested = true idleBlankTimer.restart() logEvent("lock-requested") - requestSessionLock() + queueSessionLock() Qt.callLater(function() { root.refreshBackground() @@ -117,6 +125,7 @@ Item { lockRequested = false pendingSessionLock = false + sessionLockStabilizeTimer.stop() pendingSessionLockTimer.stop() resetAuthenticationState() idleBlankTimer.stop() @@ -197,6 +206,7 @@ Item { root.logEvent("secure=" + secure) if (secure) { root.pendingSessionLock = false + sessionLockStabilizeTimer.stop() pendingSessionLockTimer.stop() root.startFingerprint() } @@ -207,12 +217,14 @@ Item { if (locked) { root.pendingSessionLock = false + sessionLockStabilizeTimer.stop() pendingSessionLockTimer.stop() } if (!locked && root.lockRequested) { root.lockRequested = false root.pendingSessionLock = false + sessionLockStabilizeTimer.stop() pendingSessionLockTimer.stop() root.resetAuthenticationState() root.runWake() @@ -361,6 +373,13 @@ Item { onTriggered: if (root.lockRequested && !root.authenticating) root.runBlank() } + Timer { + id: sessionLockStabilizeTimer + interval: 500 + repeat: false + onTriggered: root.requestSessionLock() + } + Timer { id: pendingSessionLockTimer interval: 100 diff --git a/test/shell.d/monitor-recovery-test.sh b/test/shell.d/monitor-recovery-test.sh index e11c6f39..65fd41b8 100755 --- a/test/shell.d/monitor-recovery-test.sh +++ b/test/shell.d/monitor-recovery-test.sh @@ -20,6 +20,8 @@ grep -F '(( attempt % 5 == 0 )) && recover_internal_monitor_toggles' "$sleep_loc pass "sleep lock recovers internal monitor toggles while waiting for secure lock" grep -F 'lock-pending: no-real-screen' "$lock_service" >/dev/null +grep -F 'lock-pending: screen-stabilizing' "$lock_service" >/dev/null +grep -F 'id: sessionLockStabilizeTimer' "$lock_service" >/dev/null grep -F 'function onScreensChanged() { root.requestSessionLock() }' "$lock_service" >/dev/null grep -F 'realScreens: root.realScreenCount()' "$lock_service" >/dev/null -pass "lock service defers session lock until a real screen exists" +pass "lock service waits for stable real screens before session lock"