From 237fb57d5e034705644449e6cf4e311d263963e3 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 --- 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 1791ebd7d..01e5d1634 100644 --- a/quickshell/Modules/Lock/LockScreenContent.qml +++ b/quickshell/Modules/Lock/LockScreenContent.qml @@ -36,6 +36,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 @@ -134,12 +135,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