Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Assets/Translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -1305,6 +1305,8 @@
"fade-duration-label": "Fade duration",
"lock-description": "Seconds of inactivity before the lock screen activates.",
"lock-label": "Lock screen",
"lock-screen-off-description": "Seconds of inactivity before monitors are turned off while the lock screen is active. Set to 0 to disable.",
"lock-screen-off-label": "Turn off screen while locked",
"resume-command-label": "Resume command",
"screen-off-description": "Seconds of inactivity before monitors are turned off.",
"screen-off-label": "Turn off screen",
Expand Down
1 change: 1 addition & 0 deletions Assets/settings-default.json
Original file line number Diff line number Diff line change
Expand Up @@ -544,6 +544,7 @@
"screenOffTimeout": 600,
"lockTimeout": 660,
"suspendTimeout": 1800,
"lockScreenOffTimeout": 0,
"fadeDuration": 5,
"screenOffCommand": "",
"lockCommand": "",
Expand Down
1 change: 1 addition & 0 deletions Commons/Settings.qml
Original file line number Diff line number Diff line change
Expand Up @@ -789,6 +789,7 @@ Singleton {
property int screenOffTimeout: 600 // seconds, 0 = disabled
property int lockTimeout: 660 // seconds, 0 = disabled
property int suspendTimeout: 1800 // seconds, 0 = disabled
property int lockScreenOffTimeout: 0 // seconds, 0 = disabled — turn off monitors while lock screen is active
property int fadeDuration: 5 // seconds of fade-to-black before action fires
property string screenOffCommand: ""
property string lockCommand: ""
Expand Down
25 changes: 21 additions & 4 deletions Modules/Panels/Settings/Tabs/Idle/BehaviorSubTab.qml
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,15 @@ ColumnLayout {
}
}

DefaultActionRow {
actionName: I18n.tr("panels.idle.lock-screen-off-label")
actionDescription: I18n.tr("panels.idle.lock-screen-off-description")
timeoutValue: Settings.data.idle.lockScreenOffTimeout
defaultValue: Settings.getDefaultValue("idle.lockScreenOffTimeout")
showSettings: false
onActionTimeoutChanged: val => Settings.data.idle.lockScreenOffTimeout = val
}

DefaultActionRow {
actionName: I18n.tr("common.suspend")
actionDescription: I18n.tr("panels.idle.suspend-description")
Expand Down Expand Up @@ -172,6 +181,7 @@ ColumnLayout {
property int defaultValue
property string command
property string resumeCommand
property bool showSettings: true

signal actionTimeoutChanged(int newValue)
signal actionCommandChanged(string newCmd)
Expand All @@ -189,11 +199,18 @@ ColumnLayout {
onValueChanged: rowRoot.actionTimeoutChanged(value)
}

NIconButton {
Item {
Layout.alignment: Qt.AlignVCenter
icon: "settings"
tooltipText: I18n.tr("common.edit")
onClicked: root.openEdit(rowRoot.actionName, rowRoot.command, rowRoot.resumeCommand, rowRoot.actionCommandChanged, rowRoot.actionResumeCommandChanged)
implicitWidth: Style.toOdd(Style.baseWidgetSize * Style.uiScaleRatio)
implicitHeight: Style.toOdd(Style.baseWidgetSize * Style.uiScaleRatio)

NIconButton {
visible: rowRoot.showSettings
anchors.centerIn: parent
icon: "settings"
tooltipText: I18n.tr("common.edit")
onClicked: root.openEdit(rowRoot.actionName, rowRoot.command, rowRoot.resumeCommand, rowRoot.actionCommandChanged, rowRoot.actionResumeCommandChanged)
}
}
}
}
57 changes: 57 additions & 0 deletions Services/Power/IdleService.qml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ Singleton {
property var _customMonitors: ({})
property var _queuedStages: []
property bool _screenOffActive: false
property var _lockScreenOffMonitor: null

// Signals for external listeners (plugins, modules)
signal screenOffRequested
Expand Down Expand Up @@ -199,6 +200,7 @@ Singleton {
if (PanelService.lockScreen && !PanelService.lockScreen.active) {
PanelService.lockScreen.active = true;
}
_applyLockScreenOffMonitor();
root.lockRequested();
} else if (stage === "suspend") {
if (Settings.data.idle.suspendCommand)
Expand Down Expand Up @@ -240,6 +242,61 @@ Singleton {
function onCustomCommandsChanged() {
root._applyCustomMonitors();
}
function onLockScreenOffTimeoutChanged() {
if (PanelService.lockScreen && PanelService.lockScreen.active)
root._applyLockScreenOffMonitor();
else
root._destroyLockScreenOffMonitor();
}
}

// -------------------------------------------------------
// React to lock screen active state changes
Connections {
target: PanelService.lockScreen
function onActiveChanged() {
if (PanelService.lockScreen.active)
root._applyLockScreenOffMonitor();
else
root._destroyLockScreenOffMonitor();
}
}

function _applyLockScreenOffMonitor() {
_destroyLockScreenOffMonitor();
const t = Settings.data.idle.lockScreenOffTimeout;
if (!Settings.data.idle.enabled || t <= 0)
return;
try {
const qml = `
import Quickshell.Wayland
IdleMonitor { timeout: ${t} }
`;

const monitor = Qt.createQmlObject(qml, root, "IdleMonitor_lockScreenOff");
monitor.isIdleChanged.connect(function () {
if (monitor.isIdle) {
Logger.i("IdleService", "Lock-screen idle: turning off monitors");
CompositorService.turnOffMonitors();
root._screenOffActive = true;
} else {
root._restoreMonitors();
}
});
root._lockScreenOffMonitor = monitor;
root._monitorsCreated = true;
Logger.i("IdleService", "Lock-screen-off monitor created, timeout", t, "s");
} catch (e) {
Logger.w("IdleService", "Failed to create lock-screen-off monitor:", e);
}
}

function _destroyLockScreenOffMonitor() {
if (_lockScreenOffMonitor) {
_lockScreenOffMonitor.destroy();
root._lockScreenOffMonitor = null;
Logger.d("IdleService", "Lock-screen-off monitor destroyed");
}
}

function _applyTimeouts() {
Expand Down