1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-01-24 13:32:50 -05:00

power: add fade to monitor off option

fixes #558
This commit is contained in:
bbedward
2026-01-03 15:00:12 -05:00
parent f3f720bb37
commit 6d76f0b476
7 changed files with 219 additions and 15 deletions

View File

@@ -278,6 +278,8 @@ Singleton {
property bool loginctlLockIntegration: true
property bool fadeToLockEnabled: false
property int fadeToLockGracePeriod: 5
property bool fadeToDpmsEnabled: false
property int fadeToDpmsGracePeriod: 5
property string launchPrefix: ""
property var brightnessDevicePins: ({})
property var wifiNetworkPins: ({})

View File

@@ -168,6 +168,8 @@ var SPEC = {
loginctlLockIntegration: { def: true },
fadeToLockEnabled: { def: false },
fadeToLockGracePeriod: { def: 5 },
fadeToDpmsEnabled: { def: false },
fadeToDpmsGracePeriod: { def: 5 },
launchPrefix: { def: "" },
brightnessDevicePins: { def: {} },
wifiNetworkPins: { def: {} },

View File

@@ -104,6 +104,46 @@ Item {
}
}
Variants {
model: Quickshell.screens
delegate: Loader {
id: fadeDpmsWindowLoader
required property var modelData
active: SettingsData.fadeToDpmsEnabled
asynchronous: false
sourceComponent: FadeToDpmsWindow {
screen: fadeDpmsWindowLoader.modelData
onFadeCompleted: {
IdleService.requestMonitorOff();
}
onFadeCancelled: {
console.log("Fade to DPMS cancelled by user on screen:", fadeDpmsWindowLoader.modelData.name);
}
}
Connections {
target: IdleService
enabled: fadeDpmsWindowLoader.item !== null
function onFadeToDpmsRequested() {
if (fadeDpmsWindowLoader.item) {
fadeDpmsWindowLoader.item.startFade();
}
}
function onCancelFadeToDpms() {
if (fadeDpmsWindowLoader.item) {
fadeDpmsWindowLoader.item.cancelFade();
}
}
}
}
}
Repeater {
id: dankBarRepeater
model: ScriptModel {

View File

@@ -0,0 +1,102 @@
pragma ComponentBehavior: Bound
import QtQuick
import Quickshell
import Quickshell.Wayland
import qs.Common
PanelWindow {
id: root
property bool active: false
signal fadeCompleted
signal fadeCancelled
visible: active
color: "transparent"
WlrLayershell.namespace: "dms:fade-to-dpms"
WlrLayershell.layer: WlrLayershell.Overlay
WlrLayershell.exclusiveZone: -1
WlrLayershell.keyboardFocus: active ? WlrKeyboardFocus.Exclusive : WlrKeyboardFocus.None
anchors {
left: true
right: true
top: true
bottom: true
}
Rectangle {
id: fadeOverlay
anchors.fill: parent
color: "black"
opacity: 0
onOpacityChanged: {
if (opacity >= 0.99 && root.active) {
root.fadeCompleted();
}
}
}
SequentialAnimation {
id: fadeSeq
running: false
NumberAnimation {
target: fadeOverlay
property: "opacity"
from: 0.0
to: 1.0
duration: SettingsData.fadeToDpmsGracePeriod * 1000
easing.type: Easing.OutCubic
}
}
function startFade() {
if (!SettingsData.fadeToDpmsEnabled)
return;
active = true;
fadeOverlay.opacity = 0.0;
fadeSeq.stop();
fadeSeq.start();
}
function cancelFade() {
fadeSeq.stop();
fadeOverlay.opacity = 0.0;
active = false;
fadeCancelled();
}
MouseArea {
anchors.fill: parent
enabled: root.active
onClicked: root.cancelFade()
onPressed: root.cancelFade()
}
FocusScope {
anchors.fill: parent
focus: root.active
Keys.onPressed: event => {
root.cancelFade();
event.accepted = true;
}
}
Component.onCompleted: {
if (active) {
forceActiveFocus();
}
}
onActiveChanged: {
if (active) {
forceActiveFocus();
}
}
}

View File

@@ -23,15 +23,12 @@ Scope {
Quickshell.execDetached(["sh", "-c", SettingsData.customPowerActionLock]);
return;
}
shouldLock = true;
if (!processingExternalEvent && SettingsData.loginctlLockIntegration && DMSService.isConnected) {
DMSService.lockSession(response => {
if (response.error) {
console.warn("Lock: Failed to call loginctl.lock:", response.error);
shouldLock = true;
}
if (response.error)
console.warn("Lock: loginctl.lock failed:", response.error);
});
} else {
shouldLock = true;
}
}
@@ -81,6 +78,11 @@ Scope {
locked: shouldLock
onLockedChanged: {
if (locked)
dpmsReapplyTimer.start();
}
WlSessionLockSurface {
id: lockSurface
@@ -120,15 +122,12 @@ Scope {
target: "lock"
function lock() {
if (!root.processingExternalEvent && SettingsData.loginctlLockIntegration && DMSService.isConnected) {
root.shouldLock = true;
if (SettingsData.loginctlLockIntegration && DMSService.isConnected) {
DMSService.lockSession(response => {
if (response.error) {
console.warn("Lock: Failed to call loginctl.lock:", response.error);
root.shouldLock = true;
}
if (response.error)
console.warn("Lock: loginctl.lock failed:", response.error);
});
} else {
root.shouldLock = true;
}
}
@@ -140,4 +139,11 @@ Scope {
return sessionLock.locked;
}
}
Timer {
id: dpmsReapplyTimer
interval: 100
repeat: false
onTriggered: IdleService.reapplyDpmsIfNeeded()
}
}

View File

@@ -72,6 +72,15 @@ Item {
onToggled: checked => SettingsData.set("fadeToLockEnabled", checked)
}
SettingsToggleRow {
settingKey: "fadeToDpmsEnabled"
tags: ["fade", "dpms", "monitor", "screen", "idle", "grace period"]
text: I18n.tr("Fade to monitor off")
description: I18n.tr("Gradually fade the screen before turning off monitors with a configurable grace period")
checked: SettingsData.fadeToDpmsEnabled
onToggled: checked => SettingsData.set("fadeToDpmsEnabled", checked)
}
SettingsToggleRow {
settingKey: "lockBeforeSuspend"
tags: ["lock", "suspend", "sleep", "security"]
@@ -89,7 +98,7 @@ Item {
property var periodOptions: ["1 second", "2 seconds", "3 seconds", "4 seconds", "5 seconds", "10 seconds", "15 seconds", "20 seconds", "30 seconds"]
property var periodValues: [1, 2, 3, 4, 5, 10, 15, 20, 30]
text: I18n.tr("Fade grace period")
text: I18n.tr("Lock fade grace period")
options: periodOptions
visible: SettingsData.fadeToLockEnabled
enabled: SettingsData.fadeToLockEnabled
@@ -107,6 +116,32 @@ Item {
SettingsData.set("fadeToLockGracePeriod", periodValues[index]);
}
}
SettingsDropdownRow {
id: fadeDpmsGracePeriodDropdown
settingKey: "fadeToDpmsGracePeriod"
tags: ["fade", "grace", "period", "timeout", "dpms", "monitor"]
property var periodOptions: ["1 second", "2 seconds", "3 seconds", "4 seconds", "5 seconds", "10 seconds", "15 seconds", "20 seconds", "30 seconds"]
property var periodValues: [1, 2, 3, 4, 5, 10, 15, 20, 30]
text: I18n.tr("Monitor fade grace period")
options: periodOptions
visible: SettingsData.fadeToDpmsEnabled
enabled: SettingsData.fadeToDpmsEnabled
Component.onCompleted: {
const currentPeriod = SettingsData.fadeToDpmsGracePeriod;
const index = periodValues.indexOf(currentPeriod);
currentValue = index >= 0 ? periodOptions[index] : "5 seconds";
}
onValueChanged: value => {
const index = periodOptions.indexOf(value);
if (index < 0)
return;
SettingsData.set("fadeToDpmsGracePeriod", periodValues[index]);
}
}
SettingsDropdownRow {
id: powerProfileDropdown
settingKey: "powerProfile"

View File

@@ -53,6 +53,8 @@ Singleton {
signal lockRequested
signal fadeToLockRequested
signal cancelFadeToLock
signal fadeToDpmsRequested
signal cancelFadeToDpms
signal requestMonitorOff
signal requestMonitorOn
signal requestSuspend
@@ -61,11 +63,17 @@ Singleton {
property var lockMonitor: null
property var suspendMonitor: null
property var lockComponent: null
property bool monitorsOff: false
function wake() {
requestMonitorOn();
}
function reapplyDpmsIfNeeded() {
if (monitorsOff)
CompositorService.powerOffMonitors();
}
function createIdleMonitors() {
if (!idleMonitorAvailable) {
console.info("IdleService: IdleMonitor not available, skipping creation");
@@ -90,8 +98,15 @@ Singleton {
monitorOffMonitor.timeout = Qt.binding(() => root.monitorTimeout);
monitorOffMonitor.isIdleChanged.connect(function () {
if (monitorOffMonitor.isIdle) {
root.requestMonitorOff();
if (SettingsData.fadeToDpmsEnabled) {
root.fadeToDpmsRequested();
} else {
root.requestMonitorOff();
}
} else {
if (SettingsData.fadeToDpmsEnabled) {
root.cancelFadeToDpms();
}
root.requestMonitorOn();
}
});
@@ -131,10 +146,12 @@ Singleton {
Connections {
target: root
function onRequestMonitorOff() {
monitorsOff = true;
CompositorService.powerOffMonitors();
}
function onRequestMonitorOn() {
monitorsOff = false;
CompositorService.powerOnMonitors();
}