From a1c581e4432b0ca9850568295c20d72122327557 Mon Sep 17 00:00:00 2001 From: Damocles Date: Sat, 18 Apr 2026 10:06:22 +0200 Subject: [PATCH] extract logind integration into LockService singleton in services/ --- shell/lock/Lock.qml | 71 +++++---------------------- shell/services/LockService.qml | 88 ++++++++++++++++++++++++++++++++++ shell/services/qmldir | 1 + 3 files changed, 101 insertions(+), 59 deletions(-) create mode 100644 shell/services/LockService.qml diff --git a/shell/lock/Lock.qml b/shell/lock/Lock.qml index e139e16..3d5bc80 100644 --- a/shell/lock/Lock.qml +++ b/shell/lock/Lock.qml @@ -1,15 +1,11 @@ import QtQuick import Quickshell -import Quickshell.Io import Quickshell.Wayland import "../services" as S Scope { id: root - readonly property bool _enabled: S.Modules.lock.enable - property string _sessionPath: "" - WlSessionLock { id: _lock @@ -24,73 +20,30 @@ Scope { lock: _lock } - // Resolve the actual logind session object path at startup - Process { - id: _sessionResolver - command: ["busctl", "call", "--system", "org.freedesktop.login1", "/org/freedesktop/login1", "org.freedesktop.login1.Manager", "GetSession", "s", "auto"] - running: root._enabled + Connections { + target: S.LockService - stdout: SplitParser { - onRead: data => { - // Output: o "/org/freedesktop/login1/session/_32" - const match = data.match(/"([^"]+)"/); - if (match) - root._sessionPath = match[1]; - } + function onLockRequested() { + if (S.LockService.enabled) + _lock.locked = true; } - onExited: { - if (root._sessionPath) { - _logindMonitor.running = true; - _lockStateCheck.running = true; - } + function onUnlockRequested() { + if (_lock.locked) + _lock.locked = false; } - } - // Listen for logind Lock/Unlock signals via gdbus monitor. - // TODO: replace with native D-Bus integration when nova-stats becomes a quickshell plugin - Process { - id: _logindMonitor - command: ["gdbus", "monitor", "--system", "--dest", "org.freedesktop.login1", "--object-path", root._sessionPath] - running: false - - stdout: SplitParser { - onRead: data => { - if (data.indexOf(".Lock ()") !== -1 && root._enabled) - _lock.locked = true; - else if (data.indexOf(".Unlock ()") !== -1 && _lock.locked) - _lock.locked = false; - } + function onSessionLocked() { + if (S.LockService.enabled && !_lock.locked) + _lock.locked = true; } } - // Check if session is already locked on startup (crash recovery) - Process { - id: _lockStateCheck - running: false - command: ["busctl", "get-property", "--system", "org.freedesktop.login1", root._sessionPath, "org.freedesktop.login1.Session", "LockedHint"] - - stdout: SplitParser { - onRead: data => { - // Output: b true/false - if (data.indexOf("true") !== -1 && root._enabled && !_lock.locked) - _lock.locked = true; - } - } - } - - // Set logind LockedHint when lock state changes - Process { - id: _lockedHint - command: ["busctl", "call", "--system", "org.freedesktop.login1", root._sessionPath || "/org/freedesktop/login1/session/auto", "org.freedesktop.login1.Session", "SetLockedHint", "b", _lock.locked ? "true" : "false"] - } - Connections { target: _lock function onLockStateChanged() { - if (root._sessionPath) - _lockedHint.running = true; + S.LockService.setLockedHint(_lock.locked); } } } diff --git a/shell/services/LockService.qml b/shell/services/LockService.qml new file mode 100644 index 0000000..1b55916 --- /dev/null +++ b/shell/services/LockService.qml @@ -0,0 +1,88 @@ +pragma Singleton + +import QtQuick +import Quickshell.Io +import "." as S + +QtObject { + id: root + + readonly property bool enabled: S.Modules.lock.enable + property string sessionPath: "" + + // Lock/unlock requests from logind + signal lockRequested + signal unlockRequested + + // Set logind LockedHint + function setLockedHint(locked) { + if (!sessionPath) + return; + _lockedHint._locked = locked; + _lockedHint.running = true; + } + + // Check if session is currently locked (crash recovery) + function checkLockState() { + if (sessionPath) + _lockStateCheck.running = true; + } + + signal sessionLocked // fired if LockedHint is true on startup + + // Resolve the actual logind session object path at startup + property Process _sessionResolver: Process { + command: ["busctl", "call", "--system", "org.freedesktop.login1", "/org/freedesktop/login1", "org.freedesktop.login1.Manager", "GetSession", "s", "auto"] + running: root.enabled + + stdout: SplitParser { + onRead: data => { + const match = data.match(/"([^"]+)"/); + if (match) + root.sessionPath = match[1]; + } + } + + onExited: { + if (root.sessionPath) { + _logindMonitor.running = true; + root.checkLockState(); + } + } + } + + // Listen for logind Lock/Unlock signals via gdbus monitor. + // TODO: replace with native D-Bus integration when nova-stats becomes a quickshell plugin + property Process _logindMonitor: Process { + command: ["gdbus", "monitor", "--system", "--dest", "org.freedesktop.login1", "--object-path", root.sessionPath] + running: false + + stdout: SplitParser { + onRead: data => { + if (data.indexOf(".Lock ()") !== -1) + root.lockRequested(); + else if (data.indexOf(".Unlock ()") !== -1) + root.unlockRequested(); + } + } + } + + // Check if session is already locked on startup (crash recovery) + property Process _lockStateCheck: Process { + running: false + command: ["busctl", "get-property", "--system", "org.freedesktop.login1", root.sessionPath, "org.freedesktop.login1.Session", "LockedHint"] + + stdout: SplitParser { + onRead: data => { + if (data.indexOf("true") !== -1) + root.sessionLocked(); + } + } + } + + // Set logind LockedHint + property Process _lockedHint: Process { + property bool _locked: false + command: ["busctl", "call", "--system", "org.freedesktop.login1", root.sessionPath || "/org/freedesktop/login1/session/auto", "org.freedesktop.login1.Session", "SetLockedHint", "b", _locked ? "true" : "false"] + } +} diff --git a/shell/services/qmldir b/shell/services/qmldir index 62f2550..d23b48f 100644 --- a/shell/services/qmldir +++ b/shell/services/qmldir @@ -6,3 +6,4 @@ singleton NiriIpc 1.0 NiriIpc.qml singleton PowerProfileService 1.0 PowerProfileService.qml singleton NotifService 1.0 NotifService.qml NotifItem 1.0 NotifItem.qml +singleton LockService 1.0 LockService.qml