1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-04-16 10:42:06 -04:00

idle/lock: add option to turn off monitors after lock explicitly

fixes #452
fixes #2156
This commit is contained in:
bbedward
2026-04-14 16:28:52 -04:00
parent 6d0953de68
commit 0ab9b1e4e9
23 changed files with 128 additions and 83 deletions

View File

@@ -444,11 +444,13 @@ Singleton {
property int acSuspendTimeout: 0
property int acSuspendBehavior: SettingsData.SuspendBehavior.Suspend
property string acProfileName: ""
property int acPostLockMonitorTimeout: 0
property int batteryMonitorTimeout: 0
property int batteryLockTimeout: 0
property int batterySuspendTimeout: 0
property int batterySuspendBehavior: SettingsData.SuspendBehavior.Suspend
property string batteryProfileName: ""
property int batteryPostLockMonitorTimeout: 0
property int batteryChargeLimit: 100
property bool lockBeforeSuspend: false
property bool loginctlLockIntegration: true

View File

@@ -255,11 +255,13 @@ var SPEC = {
acSuspendTimeout: { def: 0 },
acSuspendBehavior: { def: 0 },
acProfileName: { def: "" },
acPostLockMonitorTimeout: { def: 0 },
batteryMonitorTimeout: { def: 0 },
batteryLockTimeout: { def: 0 },
batterySuspendTimeout: { def: 0 },
batterySuspendBehavior: { def: 0 },
batteryProfileName: { def: "" },
batteryPostLockMonitorTimeout: { def: 0 },
batteryChargeLimit: { def: 100 },
lockBeforeSuspend: { def: false },
loginctlLockIntegration: { def: true },
@@ -362,7 +364,7 @@ var SPEC = {
lockScreenShowMediaPlayer: { def: true },
lockScreenPowerOffMonitorsOnLock: { def: false },
lockAtStartup: { def: false },
enableFprint: { def: false, onChange: "scheduleAuthApply" },
enableFprint: { def: false },
maxFprintTries: { def: 15 },
enableU2f: { def: false, onChange: "scheduleAuthApply" },
u2fMode: { def: "or" },

View File

@@ -58,7 +58,7 @@ Item {
}
}
property bool enabled: isInstance ? (instanceData?.enabled ?? true) : SettingsData.desktopClockEnabled
enabled: isInstance ? (instanceData?.enabled ?? true) : SettingsData.desktopClockEnabled
property real transparency: isInstance ? (cfg.transparency ?? 0.8) : SettingsData.desktopClockTransparency
property string colorMode: isInstance ? (cfg.colorMode ?? "primary") : SettingsData.desktopClockColorMode
property color customColor: isInstance ? (cfg.customColor ?? "#ffffff") : SettingsData.desktopClockCustomColor

View File

@@ -37,7 +37,7 @@ Item {
readonly property var cfg: instanceData?.config ?? null
readonly property bool isInstance: instanceId !== "" && cfg !== null
property bool enabled: isInstance ? (instanceData?.enabled ?? true) : SettingsData.systemMonitorEnabled
enabled: isInstance ? (instanceData?.enabled ?? true) : SettingsData.systemMonitorEnabled
property bool showHeader: isInstance ? (cfg.showHeader ?? true) : SettingsData.systemMonitorShowHeader
property real transparency: isInstance ? (cfg.transparency ?? 0.8) : SettingsData.systemMonitorTransparency
property string colorMode: isInstance ? (cfg.colorMode ?? "primary") : SettingsData.systemMonitorColorMode

View File

@@ -12,7 +12,6 @@ Rectangle {
property string text: ""
property string secondaryText: ""
property bool isActive: false
property bool enabled: true
property int widgetIndex: 0
property var widgetData: null
property bool editMode: false

View File

@@ -14,7 +14,6 @@ Rectangle {
property real value: 0.0
property real maximumValue: 1.0
property real minimumValue: 0.0
property bool enabled: true
signal sliderValueChanged(real value)

View File

@@ -10,7 +10,7 @@ Rectangle {
LayoutMirroring.childrenInherit: true
property bool isActive: BatteryService.batteryAvailable && (BatteryService.isCharging || BatteryService.isPluggedIn)
property bool enabled: BatteryService.batteryAvailable
enabled: BatteryService.batteryAvailable
signal clicked

View File

@@ -25,7 +25,7 @@ Rectangle {
return parseFloat(selectedMount.percent.replace("%", "")) || 0;
}
property bool enabled: DgopService.dgopAvailable
enabled: DgopService.dgopAvailable
signal clicked

View File

@@ -7,7 +7,6 @@ Rectangle {
property string iconName: ""
property bool isActive: false
property bool enabled: true
property real iconRotation: 0
signal clicked

View File

@@ -11,7 +11,6 @@ Rectangle {
property string iconName: ""
property string text: ""
property bool isActive: false
property bool enabled: true
property string secondaryText: ""
property real iconRotation: 0

View File

@@ -147,6 +147,13 @@ Scope {
}
}
Pam {
id: sharedPam
lockSecured: root.shouldLock
buffer: root.sharedPasswordBuffer
onUnlockRequested: root.unlock()
}
WlSessionLock {
id: sessionLock
@@ -170,6 +177,7 @@ Scope {
anchors.fill: parent
visible: lockSurface.isActiveScreen
lock: sessionLock
pam: sharedPam
sharedPasswordBuffer: root.sharedPasswordBuffer
screenName: lockSurface.currentScreenName
isLocked: shouldLock

View File

@@ -23,6 +23,7 @@ Item {
property string passwordBuffer: ""
property bool demoMode: false
property var pam: demoPam
property string screenName: ""
property bool unlocking: false
property string pamState: ""
@@ -58,10 +59,8 @@ Item {
return I18n.tr("Too many attempts - locked out");
if (root.pamState === "fail")
return I18n.tr("Incorrect password - try again");
if (pam.fprintState === "error") {
const detail = (pam.fprint.message || "").trim();
return detail.length > 0 ? I18n.tr("Fingerprint error: %1").arg(detail) : I18n.tr("Fingerprint error");
}
if (pam.fprintState === "error")
return I18n.tr("Fingerprint error");
if (pam.fprintState === "max")
return I18n.tr("Maximum fingerprint attempts reached. Please use password.");
if (pam.fprintState === "fail")
@@ -745,13 +744,6 @@ Item {
easing.type: Theme.standardEasing
}
}
Behavior on color {
ColorAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
}
}
@@ -1639,49 +1631,46 @@ Item {
}
Pam {
id: pam
lockSecured: !demoMode
onUnlockRequested: {
id: demoPam
lockSecured: false
}
Connections {
target: root.pam
function onUnlockRequested() {
root.unlocking = true;
lockerReadyArmed = false;
passwordField.text = "";
root.passwordBuffer = "";
root.unlockRequested();
}
onStateChanged: {
root.pamState = state;
if (state !== "") {
root.unlocking = false;
placeholderDelay.restart();
passwordField.text = "";
root.passwordBuffer = "";
}
}
onU2fPendingChanged: {
if (u2fPending) {
passwordField.text = "";
root.passwordBuffer = "";
if (keyboardController.isKeyboardActive)
keyboardController.hide();
}
}
}
Connections {
target: pam
function onStateChanged() {
root.pamState = root.pam.state;
if (root.pam.state === "")
return;
root.unlocking = false;
placeholderDelay.restart();
passwordField.text = "";
root.passwordBuffer = "";
}
function onU2fPendingChanged() {
if (!root.pam.u2fPending)
return;
passwordField.text = "";
root.passwordBuffer = "";
if (keyboardController.isKeyboardActive)
keyboardController.hide();
}
function onUnlockInProgressChanged() {
if (!pam.unlockInProgress && root.unlocking)
if (!root.pam.unlockInProgress && root.unlocking)
root.unlocking = false;
}
}
Binding {
target: pam
property: "buffer"
value: root.passwordBuffer
}
Timer {
id: placeholderDelay

View File

@@ -8,6 +8,7 @@ FocusScope {
id: root
required property WlSessionLock lock
required property var pam
required property string sharedPasswordBuffer
required property string screenName
required property bool isLocked
@@ -32,6 +33,7 @@ FocusScope {
anchors.fill: parent
demoMode: false
pam: root.pam
passwordBuffer: root.sharedPasswordBuffer
screenName: root.screenName
enabled: !videoScreensaver.active

View File

@@ -182,6 +182,8 @@ Scope {
abort();
return;
}
if (active)
return;
tries = 0;
errorTries = 0;
@@ -195,22 +197,23 @@ Scope {
if (!available)
return;
if (res === PamResult.Success) {
switch (res) {
case PamResult.Success:
if (!root.unlockInProgress) {
passwd.abort();
root.proceedAfterPrimaryAuth();
}
return;
}
if (res === PamResult.Error) {
root.fprintState = "error";
case PamResult.Error:
errorTries++;
if (errorTries < 5) {
if (errorTries < 200) {
abort();
errorRetry.restart();
return;
}
} else if (res === PamResult.MaxTries) {
abort();
return;
case PamResult.MaxTries:
tries++;
if (tries < SettingsData.maxFprintTries) {
root.fprintState = "fail";
@@ -219,6 +222,9 @@ Scope {
root.fprintState = "max";
abort();
}
break;
default:
return;
}
root.flashMsg();
@@ -297,7 +303,7 @@ Scope {
Timer {
id: errorRetry
interval: 800
interval: 1500
onTriggered: fprint.start()
}
@@ -349,26 +355,22 @@ Scope {
id: fprintStateReset
interval: 4000
onTriggered: {
root.fprintState = "";
fprint.errorTries = 0;
}
onTriggered: root.fprintState = ""
}
onLockSecuredChanged: {
if (lockSecured) {
SettingsData.refreshAuthAvailability();
root.state = "";
root.fprintState = "";
root.u2fState = "";
root.u2fPending = false;
root.lockMessage = "";
root.resetAuthFlows();
fprint.checkAvail();
u2f.checkAvail();
} else {
if (!lockSecured) {
root.resetAuthFlows();
return;
}
root.state = "";
root.fprintState = "";
root.u2fState = "";
root.u2fPending = false;
root.lockMessage = "";
root.resetAuthFlows();
fprint.checkAvail();
u2f.checkAvail();
}
Connections {

View File

@@ -7,8 +7,8 @@ import qs.Modules.Settings.Widgets
Item {
id: root
readonly property var timeoutOptions: [I18n.tr("Never"), I18n.tr("1 minute"), I18n.tr("2 minutes"), I18n.tr("3 minutes"), I18n.tr("5 minutes"), I18n.tr("10 minutes"), I18n.tr("15 minutes"), I18n.tr("20 minutes"), I18n.tr("30 minutes"), I18n.tr("1 hour"), I18n.tr("1 hour 30 minutes"), I18n.tr("2 hours"), I18n.tr("3 hours")]
readonly property var timeoutValues: [0, 60, 120, 180, 300, 600, 900, 1200, 1800, 3600, 5400, 7200, 10800]
readonly property var timeoutOptions: [I18n.tr("Never"), I18n.tr("15 seconds"), I18n.tr("30 seconds"), I18n.tr("1 minute"), I18n.tr("2 minutes"), I18n.tr("3 minutes"), I18n.tr("5 minutes"), I18n.tr("10 minutes"), I18n.tr("15 minutes"), I18n.tr("20 minutes"), I18n.tr("30 minutes"), I18n.tr("1 hour"), I18n.tr("1 hour 30 minutes"), I18n.tr("2 hours"), I18n.tr("3 hours")]
readonly property var timeoutValues: [0, 15, 30, 60, 120, 180, 300, 600, 900, 1200, 1800, 3600, 5400, 7200, 10800]
function getTimeoutIndex(timeout) {
var idx = timeoutValues.indexOf(timeout);
@@ -260,6 +260,39 @@ Item {
}
}
SettingsDropdownRow {
id: postLockMonitorDropdown
settingKey: "postLockMonitorTimeout"
tags: ["monitor", "display", "screen", "timeout", "off", "lock", "after", "post"]
text: I18n.tr("Turn off monitors after lock")
options: root.timeoutOptions
Connections {
target: powerCategory
function onCurrentIndexChanged() {
const currentTimeout = powerCategory.currentIndex === 0 ? SettingsData.acPostLockMonitorTimeout : SettingsData.batteryPostLockMonitorTimeout;
postLockMonitorDropdown.currentValue = root.timeoutOptions[root.getTimeoutIndex(currentTimeout)];
}
}
Component.onCompleted: {
const currentTimeout = powerCategory.currentIndex === 0 ? SettingsData.acPostLockMonitorTimeout : SettingsData.batteryPostLockMonitorTimeout;
currentValue = root.timeoutOptions[root.getTimeoutIndex(currentTimeout)];
}
onValueChanged: value => {
const index = root.timeoutOptions.indexOf(value);
if (index < 0)
return;
const timeout = root.timeoutValues[index];
if (powerCategory.currentIndex === 0) {
SettingsData.set("acPostLockMonitorTimeout", timeout);
} else {
SettingsData.set("batteryPostLockMonitorTimeout", timeout);
}
}
}
SettingsDropdownRow {
id: suspendDropdown
settingKey: "suspendTimeout"

View File

@@ -17,7 +17,6 @@ StyledRect {
property string description: ""
property string iconName: ""
property bool checked: false
property bool enabled: true
default property alias content: expandedContent.children
readonly property bool hasContent: expandedContent.children.length > 0

View File

@@ -36,12 +36,16 @@ Singleton {
readonly property int lockTimeout: isOnBattery ? SettingsData.batteryLockTimeout : SettingsData.acLockTimeout
readonly property int suspendTimeout: isOnBattery ? SettingsData.batterySuspendTimeout : SettingsData.acSuspendTimeout
readonly property int suspendBehavior: isOnBattery ? SettingsData.batterySuspendBehavior : SettingsData.acSuspendBehavior
readonly property int postLockMonitorTimeout: isOnBattery ? SettingsData.batteryPostLockMonitorTimeout : SettingsData.acPostLockMonitorTimeout
readonly property bool postLockMonitorActive: isShellLocked && postLockMonitorTimeout > 0
readonly property bool mediaPlaying: MprisController.activePlayer !== null && MprisController.activePlayer.isPlaying
onMonitorTimeoutChanged: _rearmIdleMonitors()
onLockTimeoutChanged: _rearmIdleMonitors()
onSuspendTimeoutChanged: _rearmIdleMonitors()
onPostLockMonitorTimeoutChanged: _rearmIdleMonitors()
onIsShellLockedChanged: _rearmIdleMonitors()
function _rearmIdleMonitors() {
_enableGate = false;
@@ -60,6 +64,7 @@ Singleton {
signal requestSuspend
property var monitorOffMonitor: null
property var postLockMonitorOffMonitor: null
property var lockMonitor: null
property var suspendMonitor: null
property var lockComponent: null
@@ -96,7 +101,7 @@ Singleton {
monitorOffMonitor = Qt.createQmlObject(qmlString, root, "IdleService.MonitorOffMonitor");
monitorOffMonitor.timeout = Qt.binding(() => root.monitorTimeout > 0 ? root.monitorTimeout : 86400);
monitorOffMonitor.respectInhibitors = Qt.binding(() => root.respectInhibitors);
monitorOffMonitor.enabled = Qt.binding(() => root._enableGate && root.enabled && root.idleMonitorAvailable && root.monitorTimeout > 0);
monitorOffMonitor.enabled = Qt.binding(() => root._enableGate && root.enabled && root.idleMonitorAvailable && root.monitorTimeout > 0 && !root.postLockMonitorActive);
monitorOffMonitor.isIdleChanged.connect(function () {
if (monitorOffMonitor.isIdle) {
if (SettingsData.fadeToDpmsEnabled) {
@@ -112,6 +117,18 @@ Singleton {
}
});
postLockMonitorOffMonitor = Qt.createQmlObject(qmlString, root, "IdleService.PostLockMonitorOffMonitor");
postLockMonitorOffMonitor.timeout = Qt.binding(() => root.postLockMonitorTimeout > 0 ? root.postLockMonitorTimeout : 86400);
postLockMonitorOffMonitor.respectInhibitors = Qt.binding(() => root.respectInhibitors);
postLockMonitorOffMonitor.enabled = Qt.binding(() => root._enableGate && root.enabled && root.idleMonitorAvailable && root.postLockMonitorActive);
postLockMonitorOffMonitor.isIdleChanged.connect(function () {
if (postLockMonitorOffMonitor.isIdle) {
root.requestMonitorOff();
} else {
root.requestMonitorOn();
}
});
lockMonitor = Qt.createQmlObject(qmlString, root, "IdleService.LockMonitor");
lockMonitor.timeout = Qt.binding(() => root.lockTimeout > 0 ? root.lockTimeout : 86400);
lockMonitor.respectInhibitors = Qt.binding(() => root.respectInhibitors);

View File

@@ -10,7 +10,6 @@ StyledRect {
property color iconColor: Theme.surfaceText
property color backgroundColor: "transparent"
property bool circular: true
property bool enabled: true
property int buttonSize: 32
property var tooltipText: null
property string tooltipSide: "bottom"

View File

@@ -8,7 +8,6 @@ Rectangle {
property string text: ""
property string iconName: ""
property int iconSize: Theme.iconSizeSmall
property bool enabled: true
property bool hovered: mouseArea.containsMouse
property bool pressed: mouseArea.pressed
property color backgroundColor: Theme.buttonBg

View File

@@ -11,7 +11,6 @@ Item {
property int step: 1
property string leftIcon: ""
property string rightIcon: ""
property bool enabled: true
property string unit: "%"
property bool showValue: true
property bool isDragging: false

View File

@@ -25,7 +25,6 @@ StyledRect {
property string placeholderText: ""
property alias font: textInput.font
property alias textColor: textInput.color
property alias enabled: textInput.enabled
property alias echoMode: textInput.echoMode
property alias validator: textInput.validator
property alias maximumLength: textInput.maximumLength

View File

@@ -10,7 +10,6 @@ Item {
// API
property bool checked: false
property bool enabled: true
property bool toggling: false
property string text: ""
property string description: ""

View File

@@ -1,3 +1,3 @@
#%PAM-1.0
auth required pam_fprintd.so max-tries=1 timeout=5
auth required pam_fprintd.so max-tries=5