From 4c43bed2f87346e1053ff5332f19d7153c1cd144 Mon Sep 17 00:00:00 2001 From: bbedward Date: Thu, 2 Jul 2026 15:41:05 -0400 Subject: [PATCH] lock: fix custom lock commands with lock before suspend and hibernate fixes #2326 --- quickshell/Modules/Lock/Lock.qml | 30 +++++++++++++++---- quickshell/Modules/Settings/PowerSleepTab.qml | 2 +- .../translations/settings_search_index.json | 7 +++++ 3 files changed, 33 insertions(+), 6 deletions(-) diff --git a/quickshell/Modules/Lock/Lock.qml b/quickshell/Modules/Lock/Lock.qml index c31b721f1..fb5750274 100644 --- a/quickshell/Modules/Lock/Lock.qml +++ b/quickshell/Modules/Lock/Lock.qml @@ -41,6 +41,7 @@ Scope { property bool pendingLock: false property bool lockPowerOffArmed: false property bool lockWakeAllowed: false + property bool customLockerSpawned: false Component.onCompleted: { IdleService.lockComponent = this; @@ -57,13 +58,26 @@ Scope { DMSService.unlockSession(() => {}); } + function spawnCustomLocker() { + Quickshell.execDetached(["sh", "-c", SettingsData.customPowerActionLock]); + // The custom locker manages its own surface; DMS never engages + // WlSessionLock here, so isShellLocked stays false and the fade + // overlay would never be dismissed. Hand off by dismissing it now. + IdleService.dismissFadeToLock(); + customLockerSpawned = true; + } + + function handleLoginctlCustomLock(): bool { + if (!(SettingsData.customPowerActionLock?.length > 0)) + return false; + if (!customLockerSpawned) + spawnCustomLocker(); + return true; + } + function lock() { if (SettingsData.customPowerActionLock?.length > 0) { - Quickshell.execDetached(["sh", "-c", SettingsData.customPowerActionLock]); - // The custom locker manages its own surface; DMS never engages - // WlSessionLock here, so isShellLocked stays false and the fade - // overlay would never be dismissed. Hand off by dismissing it now. - IdleService.dismissFadeToLock(); + spawnCustomLocker(); return; } if (shouldLock || pendingLock) @@ -94,6 +108,7 @@ Scope { lockInitiatedLocally = false; pendingLock = false; shouldLock = false; + customLockerSpawned = false; } function activate() { @@ -106,6 +121,8 @@ Scope { function onSessionLocked() { if (shouldLock || pendingLock) return; + if (handleLoginctlCustomLock()) + return; if (!SessionService.active && SessionService.loginctlAvailable && SettingsData.loginctlLockIntegration) { pendingLock = true; lockInitiatedLocally = false; @@ -117,6 +134,7 @@ Scope { } function onSessionUnlocked() { + customLockerSpawned = false; if (pendingLock) { pendingLock = false; lockInitiatedLocally = false; @@ -136,6 +154,8 @@ Scope { return; } if (SessionService.locked && !shouldLock && !pendingLock) { + if (handleLoginctlCustomLock()) + return; lockInitiatedLocally = false; lockPowerOffArmed = SettingsData.lockScreenPowerOffMonitorsOnLock; shouldLock = true; diff --git a/quickshell/Modules/Settings/PowerSleepTab.qml b/quickshell/Modules/Settings/PowerSleepTab.qml index 3fe339380..6293b8c55 100644 --- a/quickshell/Modules/Settings/PowerSleepTab.qml +++ b/quickshell/Modules/Settings/PowerSleepTab.qml @@ -536,6 +536,7 @@ Item { iconName: "developer_mode" title: I18n.tr("Custom Power Actions") settingKey: "customPowerActions" + tags: ["lock", "logout", "suspend", "hibernate", "reboot", "poweroff", "power off", "shutdown", "command", "script", "override"] Repeater { model: [ @@ -602,7 +603,6 @@ Item { } } } - } } } diff --git a/quickshell/translations/settings_search_index.json b/quickshell/translations/settings_search_index.json index d02831547..52b00f5f0 100644 --- a/quickshell/translations/settings_search_index.json +++ b/quickshell/translations/settings_search_index.json @@ -6778,12 +6778,19 @@ "category": "Power & Sleep", "keywords": [ "actions", + "command", "custom", "energy", "hibernate", + "lock", + "logout", + "override", "power", + "power off", + "poweroff", "reboot", "restart", + "script", "shutdown", "sleep", "suspend"