From 9e4b53e20b9b65b63e3f037ae2648cd24944473b Mon Sep 17 00:00:00 2001 From: bbedward Date: Tue, 4 Nov 2025 13:05:48 -0500 Subject: [PATCH] power: replace hibernate with "suspend behavior" opt --- Common/SettingsData.qml | 10 ++++-- Common/settings/SettingsSpec.js | 4 +-- Modals/Settings/PowerSettings.qml | 60 +++++++++++++++++-------------- Services/IdleService.qml | 21 ++--------- Services/SessionService.qml | 14 ++++++++ 5 files changed, 59 insertions(+), 50 deletions(-) diff --git a/Common/SettingsData.qml b/Common/SettingsData.qml index 16d45d04..42197928 100644 --- a/Common/SettingsData.qml +++ b/Common/SettingsData.qml @@ -34,6 +34,12 @@ Singleton { Custom } + enum SuspendBehavior { + Suspend, + Hibernate, + SuspendThenHibernate + } + readonly property string defaultFontFamily: "Inter Variable" readonly property string defaultMonoFontFamily: "Fira Code" readonly property string _homeUrl: StandardPaths.writableLocation(StandardPaths.HomeLocation) @@ -213,11 +219,11 @@ Singleton { property int acMonitorTimeout: 0 property int acLockTimeout: 0 property int acSuspendTimeout: 0 - property int acHibernateTimeout: 0 + property int acSuspendBehavior: SettingsData.SuspendBehavior.Suspend property int batteryMonitorTimeout: 0 property int batteryLockTimeout: 0 property int batterySuspendTimeout: 0 - property int batteryHibernateTimeout: 0 + property int batterySuspendBehavior: SettingsData.SuspendBehavior.Suspend property bool lockBeforeSuspend: false property bool loginctlLockIntegration: true property string launchPrefix: "" diff --git a/Common/settings/SettingsSpec.js b/Common/settings/SettingsSpec.js index cb58dd89..66c57432 100644 --- a/Common/settings/SettingsSpec.js +++ b/Common/settings/SettingsSpec.js @@ -136,11 +136,11 @@ var SPEC = { acMonitorTimeout: { def: 0 }, acLockTimeout: { def: 0 }, acSuspendTimeout: { def: 0 }, - acHibernateTimeout: { def: 0 }, + acSuspendBehavior: { def: 0 }, batteryMonitorTimeout: { def: 0 }, batteryLockTimeout: { def: 0 }, batterySuspendTimeout: { def: 0 }, - batteryHibernateTimeout: { def: 0 }, + batterySuspendBehavior: { def: 0 }, lockBeforeSuspend: { def: false }, loginctlLockIntegration: { def: true }, launchPrefix: { def: "" }, diff --git a/Modals/Settings/PowerSettings.qml b/Modals/Settings/PowerSettings.qml index 16d0da85..af067eec 100644 --- a/Modals/Settings/PowerSettings.qml +++ b/Modals/Settings/PowerSettings.qml @@ -266,38 +266,44 @@ Item { } } - DankDropdown { - id: hibernateDropdown - property var timeoutOptions: ["Never", "1 minute", "2 minutes", "3 minutes", "5 minutes", "10 minutes", "15 minutes", "20 minutes", "30 minutes", "1 hour", "1 hour 30 minutes", "2 hours", "3 hours"] - property var timeoutValues: [0, 60, 120, 180, 300, 600, 900, 1200, 1800, 3600, 5400, 7200, 10800] - - text: I18n.tr("Hibernate system after") - options: timeoutOptions + Column { + width: parent.width + spacing: Theme.spacingS visible: SessionService.hibernateSupported - Connections { - target: powerCategory - function onCurrentIndexChanged() { - const currentTimeout = powerCategory.currentIndex === 0 ? SettingsData.acHibernateTimeout : SettingsData.batteryHibernateTimeout - const index = hibernateDropdown.timeoutValues.indexOf(currentTimeout) - hibernateDropdown.currentValue = index >= 0 ? hibernateDropdown.timeoutOptions[index] : "Never" + StyledText { + text: I18n.tr("Suspend behavior") + font.pixelSize: Theme.fontSizeMedium + color: Theme.surfaceText + } + + DankButtonGroup { + id: suspendBehaviorSelector + anchors.horizontalCenter: parent.horizontalCenter + model: ["Suspend", "Hibernate", "Suspend then Hibernate"] + selectionMode: "single" + checkEnabled: false + + Connections { + target: powerCategory + function onCurrentIndexChanged() { + const behavior = powerCategory.currentIndex === 0 ? SettingsData.acSuspendBehavior : SettingsData.batterySuspendBehavior + suspendBehaviorSelector.currentIndex = behavior + } } - } - Component.onCompleted: { - const currentTimeout = powerCategory.currentIndex === 0 ? SettingsData.acHibernateTimeout : SettingsData.batteryHibernateTimeout - const index = timeoutValues.indexOf(currentTimeout) - currentValue = index >= 0 ? timeoutOptions[index] : "Never" - } + Component.onCompleted: { + const behavior = powerCategory.currentIndex === 0 ? SettingsData.acSuspendBehavior : SettingsData.batterySuspendBehavior + currentIndex = behavior + } - onValueChanged: value => { - const index = timeoutOptions.indexOf(value) - if (index >= 0) { - const timeout = timeoutValues[index] - if (powerCategory.currentIndex === 0) { - SettingsData.set("acHibernateTimeout", timeout) - } else { - SettingsData.set("batteryHibernateTimeout", timeout) + onSelectionChanged: (index, selected) => { + if (selected) { + if (powerCategory.currentIndex === 0) { + SettingsData.set("acSuspendBehavior", index) + } else { + SettingsData.set("batterySuspendBehavior", index) + } } } } diff --git a/Services/IdleService.qml b/Services/IdleService.qml index ca3274c0..bfb72cf6 100644 --- a/Services/IdleService.qml +++ b/Services/IdleService.qml @@ -26,12 +26,11 @@ Singleton { readonly property int monitorTimeout: isOnBattery ? SettingsData.batteryMonitorTimeout : SettingsData.acMonitorTimeout readonly property int lockTimeout: isOnBattery ? SettingsData.batteryLockTimeout : SettingsData.acLockTimeout readonly property int suspendTimeout: isOnBattery ? SettingsData.batterySuspendTimeout : SettingsData.acSuspendTimeout - readonly property int hibernateTimeout: isOnBattery ? SettingsData.batteryHibernateTimeout : SettingsData.acHibernateTimeout + readonly property int suspendBehavior: isOnBattery ? SettingsData.batterySuspendBehavior : SettingsData.acSuspendBehavior onMonitorTimeoutChanged: _rearmIdleMonitors() onLockTimeoutChanged: _rearmIdleMonitors() onSuspendTimeoutChanged: _rearmIdleMonitors() - onHibernateTimeoutChanged: _rearmIdleMonitors() function _rearmIdleMonitors() { _enableGate = false @@ -42,12 +41,10 @@ Singleton { signal requestMonitorOff() signal requestMonitorOn() signal requestSuspend() - signal requestHibernate() property var monitorOffMonitor: null property var lockMonitor: null property var suspendMonitor: null - property var hibernateMonitor: null function wake() { requestMonitorOn() @@ -102,16 +99,6 @@ Singleton { root.requestSuspend() } }) - - hibernateMonitor = Qt.createQmlObject(qmlString, root, "IdleService.HibernateMonitor") - hibernateMonitor.enabled = Qt.binding(() => root._enableGate && root.enabled && root.idleMonitorAvailable && root.hibernateTimeout > 0) - hibernateMonitor.respectInhibitors = Qt.binding(() => root.respectInhibitors) - hibernateMonitor.timeout = Qt.binding(() => root.hibernateTimeout) - hibernateMonitor.isIdleChanged.connect(function() { - if (hibernateMonitor.isIdle) { - root.requestHibernate() - } - }) } catch (e) { console.warn("IdleService: Error creating IdleMonitors:", e) } @@ -128,11 +115,7 @@ Singleton { } function onRequestSuspend() { - SessionService.suspend() - } - - function onRequestHibernate() { - SessionService.hibernate() + SessionService.suspendWithBehavior(root.suspendBehavior) } } diff --git a/Services/SessionService.qml b/Services/SessionService.qml index 00929098..ea33c84c 100644 --- a/Services/SessionService.qml +++ b/Services/SessionService.qml @@ -217,6 +217,20 @@ Singleton { } } + function suspendThenHibernate() { + Quickshell.execDetached([isElogind ? "loginctl" : "systemctl", "suspend-then-hibernate"]) + } + + function suspendWithBehavior(behavior) { + if (behavior === SettingsData.SuspendBehavior.Hibernate) { + hibernate() + } else if (behavior === SettingsData.SuspendBehavior.SuspendThenHibernate) { + suspendThenHibernate() + } else { + suspend() + } + } + function reboot() { if (SettingsData.customPowerActionReboot.length === 0) { Quickshell.execDetached([isElogind ? "loginctl" : "systemctl", "reboot"])