mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2025-12-06 05:25:41 -05:00
Implement IdleMonitor to replace swayidle/hypridle functionality
This commit is contained in:
@@ -45,6 +45,18 @@ Singleton {
|
|||||||
property string wallpaperCyclingTime: "06:00" // HH:mm format
|
property string wallpaperCyclingTime: "06:00" // HH:mm format
|
||||||
property string lastBrightnessDevice: ""
|
property string lastBrightnessDevice: ""
|
||||||
|
|
||||||
|
// Power management settings - AC Power
|
||||||
|
property int acMonitorTimeout: 0 // Never
|
||||||
|
property int acLockTimeout: 0 // Never
|
||||||
|
property int acSuspendTimeout: 0 // Never
|
||||||
|
property int acHibernateTimeout: 0 // Never
|
||||||
|
|
||||||
|
// Power management settings - Battery
|
||||||
|
property int batteryMonitorTimeout: 0 // Never
|
||||||
|
property int batteryLockTimeout: 0 // Never
|
||||||
|
property int batterySuspendTimeout: 0 // Never
|
||||||
|
property int batteryHibernateTimeout: 0 // Never
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
loadSettings()
|
loadSettings()
|
||||||
}
|
}
|
||||||
@@ -98,6 +110,15 @@ Singleton {
|
|||||||
wallpaperCyclingInterval = settings.wallpaperCyclingInterval !== undefined ? settings.wallpaperCyclingInterval : 300
|
wallpaperCyclingInterval = settings.wallpaperCyclingInterval !== undefined ? settings.wallpaperCyclingInterval : 300
|
||||||
wallpaperCyclingTime = settings.wallpaperCyclingTime !== undefined ? settings.wallpaperCyclingTime : "06:00"
|
wallpaperCyclingTime = settings.wallpaperCyclingTime !== undefined ? settings.wallpaperCyclingTime : "06:00"
|
||||||
lastBrightnessDevice = settings.lastBrightnessDevice !== undefined ? settings.lastBrightnessDevice : ""
|
lastBrightnessDevice = settings.lastBrightnessDevice !== undefined ? settings.lastBrightnessDevice : ""
|
||||||
|
|
||||||
|
acMonitorTimeout = settings.acMonitorTimeout !== undefined ? settings.acMonitorTimeout : 0
|
||||||
|
acLockTimeout = settings.acLockTimeout !== undefined ? settings.acLockTimeout : 0
|
||||||
|
acSuspendTimeout = settings.acSuspendTimeout !== undefined ? settings.acSuspendTimeout : 0
|
||||||
|
acHibernateTimeout = settings.acHibernateTimeout !== undefined ? settings.acHibernateTimeout : 0
|
||||||
|
batteryMonitorTimeout = settings.batteryMonitorTimeout !== undefined ? settings.batteryMonitorTimeout : 0
|
||||||
|
batteryLockTimeout = settings.batteryLockTimeout !== undefined ? settings.batteryLockTimeout : 0
|
||||||
|
batterySuspendTimeout = settings.batterySuspendTimeout !== undefined ? settings.batterySuspendTimeout : 0
|
||||||
|
batteryHibernateTimeout = settings.batteryHibernateTimeout !== undefined ? settings.batteryHibernateTimeout : 0
|
||||||
|
|
||||||
// Generate system themes but don't override user's theme choice
|
// Generate system themes but don't override user's theme choice
|
||||||
if (typeof Theme !== "undefined") {
|
if (typeof Theme !== "undefined") {
|
||||||
@@ -138,7 +159,15 @@ Singleton {
|
|||||||
"wallpaperCyclingMode": wallpaperCyclingMode,
|
"wallpaperCyclingMode": wallpaperCyclingMode,
|
||||||
"wallpaperCyclingInterval": wallpaperCyclingInterval,
|
"wallpaperCyclingInterval": wallpaperCyclingInterval,
|
||||||
"wallpaperCyclingTime": wallpaperCyclingTime,
|
"wallpaperCyclingTime": wallpaperCyclingTime,
|
||||||
"lastBrightnessDevice": lastBrightnessDevice
|
"lastBrightnessDevice": lastBrightnessDevice,
|
||||||
|
"acMonitorTimeout": acMonitorTimeout,
|
||||||
|
"acLockTimeout": acLockTimeout,
|
||||||
|
"acSuspendTimeout": acSuspendTimeout,
|
||||||
|
"acHibernateTimeout": acHibernateTimeout,
|
||||||
|
"batteryMonitorTimeout": batteryMonitorTimeout,
|
||||||
|
"batteryLockTimeout": batteryLockTimeout,
|
||||||
|
"batterySuspendTimeout": batterySuspendTimeout,
|
||||||
|
"batteryHibernateTimeout": batteryHibernateTimeout
|
||||||
}, null, 2))
|
}, null, 2))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -380,6 +409,46 @@ Singleton {
|
|||||||
saveSettings()
|
saveSettings()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setAcMonitorTimeout(timeout) {
|
||||||
|
acMonitorTimeout = timeout
|
||||||
|
saveSettings()
|
||||||
|
}
|
||||||
|
|
||||||
|
function setAcLockTimeout(timeout) {
|
||||||
|
acLockTimeout = timeout
|
||||||
|
saveSettings()
|
||||||
|
}
|
||||||
|
|
||||||
|
function setAcSuspendTimeout(timeout) {
|
||||||
|
acSuspendTimeout = timeout
|
||||||
|
saveSettings()
|
||||||
|
}
|
||||||
|
|
||||||
|
function setBatteryMonitorTimeout(timeout) {
|
||||||
|
batteryMonitorTimeout = timeout
|
||||||
|
saveSettings()
|
||||||
|
}
|
||||||
|
|
||||||
|
function setBatteryLockTimeout(timeout) {
|
||||||
|
batteryLockTimeout = timeout
|
||||||
|
saveSettings()
|
||||||
|
}
|
||||||
|
|
||||||
|
function setBatterySuspendTimeout(timeout) {
|
||||||
|
batterySuspendTimeout = timeout
|
||||||
|
saveSettings()
|
||||||
|
}
|
||||||
|
|
||||||
|
function setAcHibernateTimeout(timeout) {
|
||||||
|
acHibernateTimeout = timeout
|
||||||
|
saveSettings()
|
||||||
|
}
|
||||||
|
|
||||||
|
function setBatteryHibernateTimeout(timeout) {
|
||||||
|
batteryHibernateTimeout = timeout
|
||||||
|
saveSettings()
|
||||||
|
}
|
||||||
|
|
||||||
FileView {
|
FileView {
|
||||||
id: settingsFile
|
id: settingsFile
|
||||||
|
|
||||||
|
|||||||
237
Modals/Settings/PowerSettings.qml
Normal file
237
Modals/Settings/PowerSettings.qml
Normal file
@@ -0,0 +1,237 @@
|
|||||||
|
import QtQuick
|
||||||
|
import qs.Common
|
||||||
|
import qs.Services
|
||||||
|
import qs.Widgets
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: powerTab
|
||||||
|
|
||||||
|
DankFlickable {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.topMargin: Theme.spacingL
|
||||||
|
clip: true
|
||||||
|
contentHeight: mainColumn.height
|
||||||
|
contentWidth: width
|
||||||
|
|
||||||
|
Column {
|
||||||
|
id: mainColumn
|
||||||
|
width: parent.width
|
||||||
|
spacing: Theme.spacingXL
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: "Battery not detected - only AC power settings available"
|
||||||
|
font.pixelSize: Theme.fontSizeMedium
|
||||||
|
color: Theme.surfaceVariantText
|
||||||
|
visible: !BatteryService.batteryAvailable
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledRect {
|
||||||
|
width: parent.width
|
||||||
|
height: timeoutSection.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: 1
|
||||||
|
|
||||||
|
Column {
|
||||||
|
id: timeoutSection
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: Theme.spacingL
|
||||||
|
spacing: Theme.spacingM
|
||||||
|
|
||||||
|
Row {
|
||||||
|
width: parent.width
|
||||||
|
spacing: Theme.spacingM
|
||||||
|
|
||||||
|
DankIcon {
|
||||||
|
name: "schedule"
|
||||||
|
size: Theme.iconSize
|
||||||
|
color: Theme.primary
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: "Idle Settings"
|
||||||
|
font.pixelSize: Theme.fontSizeLarge
|
||||||
|
font.weight: Font.Medium
|
||||||
|
color: Theme.surfaceText
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
width: Math.max(0, parent.width - parent.children[0].width - parent.children[1].width - powerCategory.width - Theme.spacingM * 3)
|
||||||
|
height: parent.height
|
||||||
|
}
|
||||||
|
|
||||||
|
DankButtonGroup {
|
||||||
|
id: powerCategory
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
visible: BatteryService.batteryAvailable
|
||||||
|
model: ["AC Power", "Battery"]
|
||||||
|
currentIndex: 0
|
||||||
|
selectionMode: "single"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DankDropdown {
|
||||||
|
id: lockDropdown
|
||||||
|
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]
|
||||||
|
|
||||||
|
width: parent.width
|
||||||
|
text: "Automatically lock after"
|
||||||
|
options: timeoutOptions
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: powerCategory
|
||||||
|
function onCurrentIndexChanged() {
|
||||||
|
const currentTimeout = powerCategory.currentIndex === 0 ? SessionData.acLockTimeout : SessionData.batteryLockTimeout
|
||||||
|
const index = lockDropdown.timeoutValues.indexOf(currentTimeout)
|
||||||
|
lockDropdown.currentValue = index >= 0 ? lockDropdown.timeoutOptions[index] : "Never"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
const currentTimeout = powerCategory.currentIndex === 0 ? SessionData.acLockTimeout : SessionData.batteryLockTimeout
|
||||||
|
const index = timeoutValues.indexOf(currentTimeout)
|
||||||
|
currentValue = index >= 0 ? timeoutOptions[index] : "Never"
|
||||||
|
}
|
||||||
|
|
||||||
|
onValueChanged: value => {
|
||||||
|
const index = timeoutOptions.indexOf(value)
|
||||||
|
if (index >= 0) {
|
||||||
|
const timeout = timeoutValues[index]
|
||||||
|
if (powerCategory.currentIndex === 0) {
|
||||||
|
SessionData.setAcLockTimeout(timeout)
|
||||||
|
} else {
|
||||||
|
SessionData.setBatteryLockTimeout(timeout)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DankDropdown {
|
||||||
|
id: monitorDropdown
|
||||||
|
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]
|
||||||
|
|
||||||
|
width: parent.width
|
||||||
|
text: "Turn off monitors after"
|
||||||
|
options: timeoutOptions
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: powerCategory
|
||||||
|
function onCurrentIndexChanged() {
|
||||||
|
const currentTimeout = powerCategory.currentIndex === 0 ? SessionData.acMonitorTimeout : SessionData.batteryMonitorTimeout
|
||||||
|
const index = monitorDropdown.timeoutValues.indexOf(currentTimeout)
|
||||||
|
monitorDropdown.currentValue = index >= 0 ? monitorDropdown.timeoutOptions[index] : "Never"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
const currentTimeout = powerCategory.currentIndex === 0 ? SessionData.acMonitorTimeout : SessionData.batteryMonitorTimeout
|
||||||
|
const index = timeoutValues.indexOf(currentTimeout)
|
||||||
|
currentValue = index >= 0 ? timeoutOptions[index] : "Never"
|
||||||
|
}
|
||||||
|
|
||||||
|
onValueChanged: value => {
|
||||||
|
const index = timeoutOptions.indexOf(value)
|
||||||
|
if (index >= 0) {
|
||||||
|
const timeout = timeoutValues[index]
|
||||||
|
if (powerCategory.currentIndex === 0) {
|
||||||
|
SessionData.setAcMonitorTimeout(timeout)
|
||||||
|
} else {
|
||||||
|
SessionData.setBatteryMonitorTimeout(timeout)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DankDropdown {
|
||||||
|
id: suspendDropdown
|
||||||
|
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]
|
||||||
|
|
||||||
|
width: parent.width
|
||||||
|
text: "Suspend system after"
|
||||||
|
options: timeoutOptions
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: powerCategory
|
||||||
|
function onCurrentIndexChanged() {
|
||||||
|
const currentTimeout = powerCategory.currentIndex === 0 ? SessionData.acSuspendTimeout : SessionData.batterySuspendTimeout
|
||||||
|
const index = suspendDropdown.timeoutValues.indexOf(currentTimeout)
|
||||||
|
suspendDropdown.currentValue = index >= 0 ? suspendDropdown.timeoutOptions[index] : "Never"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
const currentTimeout = powerCategory.currentIndex === 0 ? SessionData.acSuspendTimeout : SessionData.batterySuspendTimeout
|
||||||
|
const index = timeoutValues.indexOf(currentTimeout)
|
||||||
|
currentValue = index >= 0 ? timeoutOptions[index] : "Never"
|
||||||
|
}
|
||||||
|
|
||||||
|
onValueChanged: value => {
|
||||||
|
const index = timeoutOptions.indexOf(value)
|
||||||
|
if (index >= 0) {
|
||||||
|
const timeout = timeoutValues[index]
|
||||||
|
if (powerCategory.currentIndex === 0) {
|
||||||
|
SessionData.setAcSuspendTimeout(timeout)
|
||||||
|
} else {
|
||||||
|
SessionData.setBatterySuspendTimeout(timeout)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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]
|
||||||
|
|
||||||
|
width: parent.width
|
||||||
|
text: "Hibernate system after"
|
||||||
|
description: "Requires swap space or a hibernation file"
|
||||||
|
options: timeoutOptions
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: powerCategory
|
||||||
|
function onCurrentIndexChanged() {
|
||||||
|
const currentTimeout = powerCategory.currentIndex === 0 ? SessionData.acHibernateTimeout : SessionData.batteryHibernateTimeout
|
||||||
|
const index = hibernateDropdown.timeoutValues.indexOf(currentTimeout)
|
||||||
|
hibernateDropdown.currentValue = index >= 0 ? hibernateDropdown.timeoutOptions[index] : "Never"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
const currentTimeout = powerCategory.currentIndex === 0 ? SessionData.acHibernateTimeout : SessionData.batteryHibernateTimeout
|
||||||
|
const index = timeoutValues.indexOf(currentTimeout)
|
||||||
|
currentValue = index >= 0 ? timeoutOptions[index] : "Never"
|
||||||
|
}
|
||||||
|
|
||||||
|
onValueChanged: value => {
|
||||||
|
const index = timeoutOptions.indexOf(value)
|
||||||
|
if (index >= 0) {
|
||||||
|
const timeout = timeoutValues[index]
|
||||||
|
if (powerCategory.currentIndex === 0) {
|
||||||
|
SessionData.setAcHibernateTimeout(timeout)
|
||||||
|
} else {
|
||||||
|
SessionData.setBatteryHibernateTimeout(timeout)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: "Idle monitoring not supported - requires newer Quickshell version"
|
||||||
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
|
color: Theme.error
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
visible: !IdleService.idleMonitorAvailable
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -141,13 +141,26 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Loader {
|
Loader {
|
||||||
id: aboutLoader
|
id: powerLoader
|
||||||
|
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
active: root.currentIndex === 9
|
active: root.currentIndex === 9
|
||||||
visible: active
|
visible: active
|
||||||
asynchronous: true
|
asynchronous: true
|
||||||
|
|
||||||
|
sourceComponent: PowerSettings {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Loader {
|
||||||
|
id: aboutLoader
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
active: root.currentIndex === 10
|
||||||
|
visible: active
|
||||||
|
asynchronous: true
|
||||||
|
|
||||||
sourceComponent: AboutTab {
|
sourceComponent: AboutTab {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -35,6 +35,9 @@ Rectangle {
|
|||||||
}, {
|
}, {
|
||||||
"text": "Theme & Colors",
|
"text": "Theme & Colors",
|
||||||
"icon": "palette"
|
"icon": "palette"
|
||||||
|
}, {
|
||||||
|
"text": "Power",
|
||||||
|
"icon": "power_settings_new"
|
||||||
}, {
|
}, {
|
||||||
"text": "About",
|
"text": "About",
|
||||||
"icon": "info"
|
"icon": "info"
|
||||||
|
|||||||
@@ -18,6 +18,14 @@ Item {
|
|||||||
getSessionPath.running = true
|
getSessionPath.running = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: IdleService
|
||||||
|
function onLockRequested() {
|
||||||
|
console.log("Lock: Received lock request from IdleService")
|
||||||
|
activate()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Process {
|
Process {
|
||||||
id: getSessionPath
|
id: getSessionPath
|
||||||
command: ["gdbus", "call", "--system", "--dest", "org.freedesktop.login1", "--object-path", "/org/freedesktop/login1", "--method", "org.freedesktop.login1.Manager.GetSession", sid]
|
command: ["gdbus", "call", "--system", "--dest", "org.freedesktop.login1", "--object-path", "/org/freedesktop/login1", "--method", "org.freedesktop.login1.Manager.GetSession", sid]
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
# DankMaterialShell (dms)
|
# DankMaterialShell (dms)
|
||||||
|
*Replace your Waybars, Fuzzels, Swayidles, and Swaylocks with a single Dank shell*
|
||||||
|
|
||||||
<div align=center>
|
<div align=center>
|
||||||
|
|
||||||
|
|||||||
@@ -162,6 +162,26 @@ Singleton {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function powerOffMonitors() {
|
||||||
|
if (isNiri) {
|
||||||
|
return NiriService.powerOffMonitors()
|
||||||
|
}
|
||||||
|
if (isHyprland) {
|
||||||
|
return Hyprland.dispatch("dpms off")
|
||||||
|
}
|
||||||
|
console.warn("CompositorService: Cannot power off monitors, unknown compositor")
|
||||||
|
}
|
||||||
|
|
||||||
|
function powerOnMonitors() {
|
||||||
|
if (isNiri) {
|
||||||
|
return NiriService.powerOnMonitors()
|
||||||
|
}
|
||||||
|
if (isHyprland) {
|
||||||
|
return Hyprland.dispatch("dpms on")
|
||||||
|
}
|
||||||
|
console.warn("CompositorService: Cannot power on monitors, unknown compositor")
|
||||||
|
}
|
||||||
|
|
||||||
Process {
|
Process {
|
||||||
id: niriSocketCheck
|
id: niriSocketCheck
|
||||||
command: ["test", "-S", root.niriSocket]
|
command: ["test", "-S", root.niriSocket]
|
||||||
|
|||||||
211
Services/IdleService.qml
Normal file
211
Services/IdleService.qml
Normal file
@@ -0,0 +1,211 @@
|
|||||||
|
pragma Singleton
|
||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Wayland
|
||||||
|
import qs.Common
|
||||||
|
import qs.Services
|
||||||
|
|
||||||
|
Singleton {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
readonly property bool idleMonitorAvailable: {
|
||||||
|
try {
|
||||||
|
return typeof IdleMonitor !== "undefined"
|
||||||
|
} catch (e) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
property bool enabled: true
|
||||||
|
property bool respectInhibitors: true
|
||||||
|
property bool _enableGate: true
|
||||||
|
|
||||||
|
readonly property bool isOnBattery: BatteryService.batteryAvailable && !BatteryService.isPluggedIn
|
||||||
|
readonly property int monitorTimeout: isOnBattery ? SessionData.batteryMonitorTimeout : SessionData.acMonitorTimeout
|
||||||
|
readonly property int lockTimeout: isOnBattery ? SessionData.batteryLockTimeout : SessionData.acLockTimeout
|
||||||
|
readonly property int suspendTimeout: isOnBattery ? SessionData.batterySuspendTimeout : SessionData.acSuspendTimeout
|
||||||
|
readonly property int hibernateTimeout: isOnBattery ? SessionData.batteryHibernateTimeout : SessionData.acHibernateTimeout
|
||||||
|
|
||||||
|
readonly property int firstTimeout: {
|
||||||
|
const timeouts = []
|
||||||
|
if (monitorTimeout > 0) timeouts.push(monitorTimeout)
|
||||||
|
if (lockTimeout > 0) timeouts.push(lockTimeout)
|
||||||
|
if (suspendTimeout > 0) timeouts.push(suspendTimeout)
|
||||||
|
if (hibernateTimeout > 0) timeouts.push(hibernateTimeout)
|
||||||
|
return timeouts.length > 0 ? Math.min(...timeouts) : 0
|
||||||
|
}
|
||||||
|
|
||||||
|
property int currentStepIndex: -1
|
||||||
|
property var steps: []
|
||||||
|
|
||||||
|
signal lockRequested()
|
||||||
|
signal requestMonitorOff()
|
||||||
|
signal requestMonitorOn()
|
||||||
|
signal requestSuspend()
|
||||||
|
signal requestHibernate()
|
||||||
|
signal stageFired(string name)
|
||||||
|
|
||||||
|
onFirstTimeoutChanged: {
|
||||||
|
if (idleMonitor) _rearmIdleMonitor()
|
||||||
|
}
|
||||||
|
|
||||||
|
function _rearmIdleMonitor() {
|
||||||
|
cancel()
|
||||||
|
|
||||||
|
_enableGate = false
|
||||||
|
Qt.callLater(() => { _enableGate = true })
|
||||||
|
}
|
||||||
|
|
||||||
|
function makeSteps() {
|
||||||
|
const steps = []
|
||||||
|
if (lockTimeout > 0) {
|
||||||
|
steps.push({name: "lock", delaySec: lockTimeout})
|
||||||
|
}
|
||||||
|
if (monitorTimeout > 0) {
|
||||||
|
steps.push({name: "monitor-off", delaySec: monitorTimeout})
|
||||||
|
}
|
||||||
|
if (suspendTimeout > 0) {
|
||||||
|
steps.push({name: "suspend", delaySec: suspendTimeout})
|
||||||
|
}
|
||||||
|
if (hibernateTimeout > 0) {
|
||||||
|
steps.push({name: "hibernate", delaySec: hibernateTimeout})
|
||||||
|
}
|
||||||
|
return steps.sort((a, b) => a.delaySec - b.delaySec)
|
||||||
|
}
|
||||||
|
|
||||||
|
function start() {
|
||||||
|
if (!enabled || !idleMonitorAvailable) return
|
||||||
|
if (currentStepIndex !== -1) return
|
||||||
|
|
||||||
|
steps = makeSteps()
|
||||||
|
currentStepIndex = -1
|
||||||
|
next()
|
||||||
|
}
|
||||||
|
|
||||||
|
function next() {
|
||||||
|
if (++currentStepIndex >= steps.length) return
|
||||||
|
|
||||||
|
const currentStep = steps[currentStepIndex]
|
||||||
|
|
||||||
|
const firstStepDelay = steps[0].delaySec
|
||||||
|
const relativeDelay = currentStep.delaySec - firstStepDelay
|
||||||
|
const ms = (relativeDelay * 1000) | 0
|
||||||
|
|
||||||
|
if (ms > 0) {
|
||||||
|
stepTimer.interval = ms
|
||||||
|
stepTimer.restart()
|
||||||
|
} else {
|
||||||
|
Qt.callLater(run)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function run() {
|
||||||
|
const currentStep = steps[currentStepIndex]
|
||||||
|
if (!currentStep) return
|
||||||
|
|
||||||
|
console.log("IdleService: Executing step:", currentStep.name)
|
||||||
|
|
||||||
|
if (currentStep.name === "lock") {
|
||||||
|
lockRequested()
|
||||||
|
} else if (currentStep.name === "monitor-off") {
|
||||||
|
requestMonitorOff()
|
||||||
|
} else if (currentStep.name === "suspend") {
|
||||||
|
requestSuspend()
|
||||||
|
} else if (currentStep.name === "hibernate") {
|
||||||
|
requestHibernate()
|
||||||
|
}
|
||||||
|
|
||||||
|
stageFired(currentStep.name)
|
||||||
|
next()
|
||||||
|
}
|
||||||
|
|
||||||
|
function cancel() {
|
||||||
|
stepTimer.stop()
|
||||||
|
currentStepIndex = -1
|
||||||
|
}
|
||||||
|
|
||||||
|
function wake() {
|
||||||
|
cancel()
|
||||||
|
requestMonitorOn()
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
id: stepTimer
|
||||||
|
repeat: false
|
||||||
|
onTriggered: root.run()
|
||||||
|
}
|
||||||
|
|
||||||
|
property var idleMonitor: null
|
||||||
|
|
||||||
|
function createIdleMonitor() {
|
||||||
|
if (!idleMonitorAvailable) {
|
||||||
|
console.log("IdleService: IdleMonitor not available, skipping creation")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const qmlString = `
|
||||||
|
import QtQuick
|
||||||
|
import Quickshell.Wayland
|
||||||
|
|
||||||
|
IdleMonitor {
|
||||||
|
enabled: false
|
||||||
|
respectInhibitors: true
|
||||||
|
timeout: 0
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
idleMonitor = Qt.createQmlObject(qmlString, root, "IdleService.IdleMonitor")
|
||||||
|
|
||||||
|
if (idleMonitor) {
|
||||||
|
idleMonitor.enabled = Qt.binding(
|
||||||
|
() => root._enableGate && root.enabled && root.idleMonitorAvailable && root.firstTimeout > 0
|
||||||
|
)
|
||||||
|
idleMonitor.respectInhibitors = Qt.binding(() => root.respectInhibitors)
|
||||||
|
idleMonitor.timeout = Qt.binding(() => root.firstTimeout)
|
||||||
|
|
||||||
|
idleMonitor.isIdleChanged.connect(function() {
|
||||||
|
if (idleMonitor.isIdle) {
|
||||||
|
console.log("IdleService: User is idle, starting power management")
|
||||||
|
Qt.callLater(root.start)
|
||||||
|
} else {
|
||||||
|
console.log("IdleService: User is active, canceling power management")
|
||||||
|
Qt.callLater(root.cancel)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.warn("IdleService: Error creating IdleMonitor:", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: root
|
||||||
|
function onRequestMonitorOff() {
|
||||||
|
CompositorService.powerOffMonitors()
|
||||||
|
}
|
||||||
|
|
||||||
|
function onRequestMonitorOn() {
|
||||||
|
CompositorService.powerOnMonitors()
|
||||||
|
}
|
||||||
|
|
||||||
|
function onRequestSuspend() {
|
||||||
|
SessionService.suspend()
|
||||||
|
}
|
||||||
|
|
||||||
|
function onRequestHibernate() {
|
||||||
|
SessionService.hibernate()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
if (!idleMonitorAvailable) {
|
||||||
|
console.warn("IdleService: IdleMonitor not available - power management disabled. This requires a newer version of Quickshell.")
|
||||||
|
} else {
|
||||||
|
console.log("IdleService: Initialized with idle monitoring support")
|
||||||
|
createIdleMonitor()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -438,6 +438,22 @@ Singleton {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function powerOffMonitors() {
|
||||||
|
return send({
|
||||||
|
"Action": {
|
||||||
|
"PowerOffMonitors": {}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function powerOnMonitors() {
|
||||||
|
return send({
|
||||||
|
"Action": {
|
||||||
|
"PowerOnMonitors": {}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
function getCurrentOutputWorkspaceNumbers() {
|
function getCurrentOutputWorkspaceNumbers() {
|
||||||
return currentOutputWorkspaces.map(w => w.idx + 1)
|
return currentOutputWorkspaces.map(w => w.idx + 1)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -85,6 +85,10 @@ Singleton {
|
|||||||
Quickshell.execDetached([isElogind ? "loginctl" : "systemctl", "suspend"])
|
Quickshell.execDetached([isElogind ? "loginctl" : "systemctl", "suspend"])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function hibernate() {
|
||||||
|
Quickshell.execDetached([isElogind ? "loginctl" : "systemctl", "hibernate"])
|
||||||
|
}
|
||||||
|
|
||||||
function reboot() {
|
function reboot() {
|
||||||
Quickshell.execDetached([isElogind ? "loginctl" : "systemctl", "reboot"])
|
Quickshell.execDetached([isElogind ? "loginctl" : "systemctl", "reboot"])
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user