From ab4f6baae6c91918338873709585808c02177cb6 Mon Sep 17 00:00:00 2001 From: max72bra <45419961+max72bra@users.noreply.github.com> Date: Wed, 15 Oct 2025 14:46:32 +0200 Subject: [PATCH] Improvement: Allow the user to perform custom power actions (#439) --- Common/SettingsData.qml | 42 +++++++ Modals/Settings/PowerSettings.qml | 196 ++++++++++++++++++++++++++++++ Services/SessionService.qml | 40 ++++-- 3 files changed, 268 insertions(+), 10 deletions(-) diff --git a/Common/SettingsData.qml b/Common/SettingsData.qml index b5202c9a..7559f557 100644 --- a/Common/SettingsData.qml +++ b/Common/SettingsData.qml @@ -235,6 +235,11 @@ Singleton { property bool osdAlwaysShowValue: false property bool powerActionConfirm: true + property string customPowerActionLogout: "" + property string customPowerActionSuspend: "" + property string customPowerActionHibernate: "" + property string customPowerActionReboot: "" + property string customPowerActionPowerOff: "" property bool updaterUseCustomCommand: false property string updaterCustomCommand: "" @@ -441,6 +446,11 @@ Singleton { notificationPopupPosition = settings.notificationPopupPosition !== undefined ? settings.notificationPopupPosition : SettingsData.Position.Top osdAlwaysShowValue = settings.osdAlwaysShowValue !== undefined ? settings.osdAlwaysShowValue : false powerActionConfirm = settings.powerActionConfirm !== undefined ? settings.powerActionConfirm : true + customPowerActionLogout = settings.customPowerActionLogout != undefined ? settings.customPowerActionLogout : "" + customPowerActionSuspend = settings.customPowerActionSuspend != undefined ? settings.customPowerActionSuspend : "" + customPowerActionHibernate = settings.customPowerActionHibernate != undefined ? settings.customPowerActionHibernate : "" + customPowerActionReboot = settings.customPowerActionReboot != undefined ? settings.customPowerActionReboot : "" + customPowerActionPowerOff = settings.customPowerActionPowerOff != undefined ? settings.customPowerActionPowerOff : "" updaterUseCustomCommand = settings.updaterUseCustomCommand !== undefined ? settings.updaterUseCustomCommand : false; updaterCustomCommand = settings.updaterCustomCommand !== undefined ? settings.updaterCustomCommand : ""; updaterTerminalAdditionalParams = settings.updaterTerminalAdditionalParams !== undefined ? settings.updaterTerminalAdditionalParams : ""; @@ -627,6 +637,11 @@ Singleton { "notificationPopupPosition": notificationPopupPosition, "osdAlwaysShowValue": osdAlwaysShowValue, "powerActionConfirm": powerActionConfirm, + "customPowerActionLogout": customPowerActionLogout, + "customPowerActionSuspend": customPowerActionSuspend, + "customPowerActionHibernate": customPowerActionHibernate, + "customPowerActionReboot": customPowerActionReboot, + "customPowerActionPowerOff": customPowerActionPowerOff, "updaterUseCustomCommand": updaterUseCustomCommand, "updaterCustomCommand": updaterCustomCommand, "updaterTerminalAdditionalParams": updaterTerminalAdditionalParams, @@ -692,6 +707,8 @@ Singleton { "hideBrightnessSlider", "widgetBackgroundColor", "surfaceBase", "notificationTimeoutLow", "notificationTimeoutNormal", "notificationTimeoutCritical", "notificationPopupPosition", "osdAlwaysShowValue", "powerActionConfirm", + "customPowerActionLogout", "customPowerActionSuspend", "customPowerActionHibernate", + "customPowerActionReboot", "customPowerActionPowerOff", "updaterUseCustomCommand", "updaterCustomCommand", "updaterTerminalAdditionalParams", "screenPreferences", "animationSpeed", "acMonitorTimeout", "acLockTimeout", "acSuspendTimeout", "acHibernateTimeout", "batteryMonitorTimeout", "batteryLockTimeout", @@ -1672,6 +1689,31 @@ Singleton { saveSettings(); } + function setCustomPowerActionLogout(command) { + customPowerActionLogout = command; + saveSettings(); + } + + function setCustomPowerActionSuspend(command) { + customPowerActionSuspend = command; + saveSettings(); + } + + function setCustomPowerActionHibernate(command) { + customPowerActionHibernate = command; + saveSettings(); + } + + function setCustomPowerActionReboot(command) { + customPowerActionReboot = command; + saveSettings(); + } + + function setCustomPowerActionPowerOff(command) { + customPowerActionPowerOff = command; + saveSettings(); + } + function setUpdaterUseCustomCommandEnabled(enabled) { updaterUseCustomCommand = enabled; saveSettings(); diff --git a/Modals/Settings/PowerSettings.qml b/Modals/Settings/PowerSettings.qml index 65fd88de..8c87fef2 100644 --- a/Modals/Settings/PowerSettings.qml +++ b/Modals/Settings/PowerSettings.qml @@ -356,6 +356,202 @@ Item { } } } + + StyledRect { + width: parent.width + height: powerCommandCustomization.implicitHeight + Theme.spacingL * 2 + radius: Theme.cornerRadius + color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3) + border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2) + border.width: 0 + + Column { + id: powerCommandCustomization + anchors.fill: parent + anchors.margins: Theme.spacingL + spacing: Theme.spacingL + + Row { + width: parent.width + spacing: Theme.spacingM + + DankIcon { + name: "developer_mode" + size: Theme.iconSize + color: Theme.primary + anchors.verticalCenter: parent.verticalCenter + } + + StyledText { + text: I18n.tr("Custom Power Actions") + font.pixelSize: Theme.fontSizeLarge + font.weight: Font.Medium + color: Theme.surfaceText + anchors.verticalCenter: parent.verticalCenter + } + } + + Column { + width: parent.width + spacing: Theme.spacingXS + anchors.left: parent.left + + StyledText { + text: I18n.tr("Command or script to run instead of the standard logout procedure") + font.pixelSize: Theme.fontSizeSmall + color: Theme.surfaceVariantText + } + + DankTextField { + id: customLogoutCommand + width: parent.width + height: 48 + placeholderText: "/usr/bin/myLogout.sh" + backgroundColor: Theme.surfaceVariant + normalBorderColor: Theme.primarySelected + focusedBorderColor: Theme.primary + + Component.onCompleted: { + if (SettingsData.customPowerActionLogout) { + text = SettingsData.customPowerActionLogout; + } + } + + onTextEdited: { + SettingsData.setCustomPowerActionLogout(text.trim()); + } + } + } + + Column { + width: parent.width + spacing: Theme.spacingXS + anchors.left: parent.left + + StyledText { + text: I18n.tr("Command or script to run instead of the standard suspend procedure") + font.pixelSize: Theme.fontSizeSmall + color: Theme.surfaceVariantText + } + + DankTextField { + id: customSuspendCommand + width: parent.width + height: 48 + placeholderText: "/usr/bin/mySuspend.sh" + backgroundColor: Theme.surfaceVariant + normalBorderColor: Theme.primarySelected + focusedBorderColor: Theme.primary + + Component.onCompleted: { + if (SettingsData.customPowerActionSuspend) { + text = SettingsData.customPowerActionSuspend; + } + } + + onTextEdited: { + SettingsData.setCustomPowerActionSuspend(text.trim()); + } + } + } + + Column { + width: parent.width + spacing: Theme.spacingXS + anchors.left: parent.left + + StyledText { + text: I18n.tr("Command or script to run instead of the standard hibernate procedure") + font.pixelSize: Theme.fontSizeSmall + color: Theme.surfaceVariantText + } + + DankTextField { + id: customHibernateCommand + width: parent.width + height: 48 + placeholderText: "/usr/bin/myHibernate.sh" + backgroundColor: Theme.surfaceVariant + normalBorderColor: Theme.primarySelected + focusedBorderColor: Theme.primary + + Component.onCompleted: { + if (SettingsData.customPowerActionHibernate) { + text = SettingsData.customPowerActionHibernate; + } + } + + onTextEdited: { + SettingsData.setCustomPowerActionHibernate(text.trim()); + } + } + } + + Column { + width: parent.width + spacing: Theme.spacingXS + anchors.left: parent.left + + StyledText { + text: I18n.tr("Command or script to run instead of the standard reboot procedure") + font.pixelSize: Theme.fontSizeSmall + color: Theme.surfaceVariantText + } + + DankTextField { + id: customRebootCommand + width: parent.width + height: 48 + placeholderText: "/usr/bin/myReboot.sh" + backgroundColor: Theme.surfaceVariant + normalBorderColor: Theme.primarySelected + focusedBorderColor: Theme.primary + + Component.onCompleted: { + if (SettingsData.customPowerActionReboot) { + text = SettingsData.customPowerActionReboot; + } + } + + onTextEdited: { + SettingsData.setCustomPowerActionReboot(text.trim()); + } + } + } + + Column { + width: parent.width + spacing: Theme.spacingXS + anchors.left: parent.left + + StyledText { + text: I18n.tr("Command or script to run instead of the standard power off procedure") + font.pixelSize: Theme.fontSizeSmall + color: Theme.surfaceVariantText + } + + DankTextField { + id: customPowerOffCommand + width: parent.width + height: 48 + placeholderText: "/usr/bin/myPowerOff.sh" + backgroundColor: Theme.surfaceVariant + normalBorderColor: Theme.primarySelected + focusedBorderColor: Theme.primary + + Component.onCompleted: { + if (SettingsData.customPowerActionPowerOff) { + text = SettingsData.customPowerActionPowerOff; + } + } + + onTextEdited: { + SettingsData.setCustomPowerActionPowerOff(text.trim()); + } + } + } + } + } } } } diff --git a/Services/SessionService.qml b/Services/SessionService.qml index 114c471e..92571362 100644 --- a/Services/SessionService.qml +++ b/Services/SessionService.qml @@ -178,29 +178,49 @@ Singleton { } function _logout() { - if (CompositorService.isNiri) { - NiriService.quit() - return - } + if (SettingsData.customPowerActionLogout.length === 0) { + if (CompositorService.isNiri) { + NiriService.quit() + return + } - // Hyprland fallback - Hyprland.dispatch("exit") + // Hyprland fallback + Hyprland.dispatch("exit") + } else { + Quickshell.execDetached(SettingsData.customPowerActionLogout.split(" ")) + } } function suspend() { - Quickshell.execDetached([isElogind ? "loginctl" : "systemctl", "suspend"]) + if (SettingsData.customPowerActionSuspend.length === 0) { + Quickshell.execDetached([isElogind ? "loginctl" : "systemctl", "suspend"]) + } else { + Quickshell.execDetached(SettingsData.customPowerActionSuspend.split(" ")) + } } function hibernate() { - Quickshell.execDetached([isElogind ? "loginctl" : "systemctl", "hibernate"]) + if (SettingsData.customPowerActionHibernate.length === 0) { + Quickshell.execDetached([isElogind ? "loginctl" : "systemctl", "hibernate"]) + } else { + Quickshell.execDetached(SettingsData.customPowerActionHibernate.split(" ")) + } } function reboot() { - Quickshell.execDetached([isElogind ? "loginctl" : "systemctl", "reboot"]) + if (SettingsData.customPowerActionReboot.length === 0) { + Quickshell.execDetached([isElogind ? "loginctl" : "systemctl", "reboot"]) + } else { + Quickshell.execDetached(SettingsData.customPowerActionReboot.split(" ")) + } } function poweroff() { - Quickshell.execDetached([isElogind ? "loginctl" : "systemctl", "poweroff"]) + if (SettingsData.customPowerActionPowerOff.length === 0) { + Quickshell.execDetached([isElogind ? "loginctl" : "systemctl", "poweroff"]) + } else { + Quickshell.execDetached(SettingsData.customPowerActionPowerOff.split(" ")) + } } // * Idle Inhibitor