Watch
1
0
Fork
You've already forked souveraine
0

idle: wire the dim stage and native-coordinator hardening

Dimmed now actually lowers the backlight (brightnessctl save/restore)
and Active restores it - previously dimRequested had no consumer, so
auto-dim never existed on this stack. Keep System Awake is checked
inside the monitor handlers rather than bound to enabled: recreating
the ext-idle-notify object during lock teardown is a fatal Wayland
protocol error on the Pixel compositor. Defaults now mirror the
hypridle timers (dim 120s, lock 300s).
This commit is contained in:
Fimeg 2026-07-16 17:44:01 -04:00
commit b18fa331e0
2 changed files with 42 additions and 4 deletions

View file

@ -469,8 +469,11 @@ Singleton {
// Native idle-notify remains opt-in until verified on the
// Pixel compositor; hypridle is the current adapter.
property bool nativeCoordinatorEnabled: false
property int dimAfterSeconds: 45
property int lockAfterSeconds: 90
property int dimAfterSeconds: 120
property int lockAfterSeconds: 300
// Backlight level while Dimmed; Active restores the
// brightnessctl-saved value.
property string dimBrightness: "30%"
}
property JsonObject security: JsonObject {
property bool unlockKeyring: true

View file

@ -12,6 +12,7 @@ pragma Singleton
import QtQuick
import Quickshell
import Quickshell.Io
import Quickshell.Wayland
import qs
import qs.modules.common
@ -31,11 +32,38 @@ Singleton {
signal activeRequested()
signal stateTransitioned(int state)
// Whether we lowered the backlight, so Active only restores what
// Dimmed saved — never a stale brightnessctl snapshot.
property bool displayDimmed: false
function setState(next) {
if (root.state === next) return;
root.state = next;
root.stateTransitioned(next);
console.log("[idle-coordinator] state=" + next);
if (next === IdleCoordinator.Dimmed) {
dimProc.action = "dim";
dimProc.command = ["brightnessctl", "-q", "-s", "set",
Config.options.lock.idle.dimBrightness];
dimProc.running = true;
root.displayDimmed = true;
} else if (next === IdleCoordinator.Active && root.displayDimmed) {
dimProc.action = "restore";
dimProc.command = ["brightnessctl", "-q", "-r"];
dimProc.running = true;
root.displayDimmed = false;
}
}
Process {
id: dimProc
property string action: ""
onExited: (exitCode, exitStatus) => {
if (exitCode !== 0)
console.log("[idle-coordinator] brightness " + dimProc.action
+ " failed (exit " + exitCode + ")");
}
}
function returnActive() {
@ -44,13 +72,20 @@ Singleton {
root.activeRequested();
}
// Keep System Awake is checked inside the handlers, NOT bound to
// `enabled`: flipping enabled destroys/recreates the ext-idle-notify
// object, and doing that during lock teardown (ii's LockScreen toggles
// Idle.inhibit) races the compositor into a fatal "invalid object"
// protocol error that kills the whole shell. The Wayland idle-inhibitor
// surface is not honored on the Pixel compositor, so respectInhibitors
// alone can't see the toggle either (see Idle.qml).
IdleMonitor {
id: dimMonitor
enabled: root.nativeEnabled
timeout: Math.max(1, Config.options.lock.idle.dimAfterSeconds) * 1000
respectInhibitors: true
onIsIdleChanged: {
if (isIdle && !root.lockRequested) {
if (isIdle && !root.lockRequested && !Idle.inhibit) {
root.setState(IdleCoordinator.Dimmed);
root.dimRequested();
} else if (!isIdle) {
@ -65,7 +100,7 @@ Singleton {
timeout: Math.max(1, Config.options.lock.idle.lockAfterSeconds) * 1000
respectInhibitors: true
onIsIdleChanged: {
if (isIdle && !root.lockRequested) {
if (isIdle && !root.lockRequested && !Idle.inhibit) {
root.setState(IdleCoordinator.LockRequested);
Session.lock();
} else if (!isIdle) {