From 25c12a14a9f10cba45ce6d2d9b8a596e9d3d247b Mon Sep 17 00:00:00 2001 From: Thomas Kroll <99196436+tkroll-ionos@users.noreply.github.com> Date: Wed, 22 Jul 2026 15:24:25 +0200 Subject: [PATCH] fix(lock): hold sleep inhibitor until compositor confirms lock (#2907) lock-before-suspend released the logind sleep delay inhibitor as soon as Qt reported the lock rendered (afterAnimating/afterRendering). That signal fires before the compositor has committed/presented the ext-session-lock surface, so the machine could freeze ~1 frame later with the desktop still the last presented frame. On resume the desktop was briefly visible before the lock appeared (both suspend and hibernate). Gate lockerReady on WlSessionLock.secure (the ext-session-lock `locked` event), so the inhibitor is held until the compositor confirms the session is locked and the desktop is hidden. LockSurface passes the WlSessionLock down as sessionLock; the readiness check returns early until secure, and re-fires on secureChanged. The Go-side fallback timer in loginctl monitor remains as the backstop. Reproduced on niri / s2idle with 3 outputs: debug log showed lockerReady sent 18 ms before `PM: suspend entry`; with this change the desktop no longer flashes on resume. Signed-off-by: Thomas Kroll <99196436+tkroll-ionos@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 (cherry picked from commit 237fb57d5e034705644449e6cf4e311d263963e3) --- quickshell/Modules/Lock/LockScreenContent.qml | 16 ++++++++++++++++ quickshell/Modules/Lock/LockSurface.qml | 1 + 2 files changed, 17 insertions(+) diff --git a/quickshell/Modules/Lock/LockScreenContent.qml b/quickshell/Modules/Lock/LockScreenContent.qml index 6b61b2555..ae46f1f53 100644 --- a/quickshell/Modules/Lock/LockScreenContent.qml +++ b/quickshell/Modules/Lock/LockScreenContent.qml @@ -35,6 +35,7 @@ Item { property int hyprlandLayoutCount: 0 property bool lockerReadySent: false property bool lockerReadyArmed: false + property var sessionLock: null readonly property bool hasCustomWallpaper: SettingsData.lockScreenWallpaperPath !== "" readonly property string lockFontFamily: SettingsData.lockScreenFontFamily @@ -133,12 +134,27 @@ Item { return; if (!root.visible || root.opacity <= 0) return; + // Don't report ready until the compositor has confirmed the session is + // locked (ext-session-lock `locked` event). Qt's afterRendering fires + // before the lock surface is committed/presented, so releasing the sleep + // inhibitor on it lets the machine freeze with the desktop still on screen, + // which then flashes on resume. secure=true guarantees the desktop is hidden. + if (root.sessionLock && !root.sessionLock.secure) + return; Qt.callLater(() => { if (root.visible && root.opacity > 0 && !root.unlocking) sendLockerReadyOnce(); }); } + Connections { + target: root.sessionLock + enabled: target !== null + function onSecureChanged() { + root.maybeSend(); + } + } + Connections { target: root.Window.window enabled: target !== null diff --git a/quickshell/Modules/Lock/LockSurface.qml b/quickshell/Modules/Lock/LockSurface.qml index d4a88a82e..f41a82666 100644 --- a/quickshell/Modules/Lock/LockSurface.qml +++ b/quickshell/Modules/Lock/LockSurface.qml @@ -33,6 +33,7 @@ FocusScope { anchors.fill: parent demoMode: false + sessionLock: root.lock pam: root.pam passwordBuffer: root.sharedPasswordBuffer screenName: root.screenName