lid behavior watcher to lock session #115

Merged
zach merged 25 commits from lid-switch-behavior into main 2026-06-03 18:02:21 +02:00
6 changed files with 67 additions and 26 deletions
Showing only changes of commit 016dcc008f - Show all commits
+4 -3
View File
@@ -5,11 +5,12 @@ import QtQuick
Scope { Scope {
id: root id: root
required property var lock signal requestLock
Connections { Connections {
function onLidClosing(): void { function onStateChanged(): void {
root.lock.lock.locked = true; if (LidWatcher.state === LidWatcher.Closed)
AramJonghu marked this conversation as resolved Outdated
Outdated
Review

You need to create a signal in the root Scope and call it here rather than setting the locked value directly.

Scope {
    id: root
    
    signal requestLock
    
    Connections {
    // ...

Is what I suggest, ties in nicely with a similar signal related to locking.

You need to create a signal in the root `Scope` and call it here rather than setting the locked value directly. ```qml Scope { id: root signal requestLock Connections { // ... ``` Is what I suggest, ties in nicely with a similar signal related to locking.
root.requestLock();
} }
target: LidWatcher target: LidWatcher
+3
View File
@@ -18,6 +18,9 @@ Scope {
signal requestLock signal requestLock
signal unlock signal unlock
onRequestLock: lock.locked = true
onUnlock: lock.locked = false
LockSurface { LockSurface {
id: lockSurface id: lockSurface
+35 -10
View File
@@ -1,6 +1,8 @@
#include "lidwatcher.hpp" #include "lidwatcher.hpp"
#include <QtDBus/QDBusConnection> #include <QtDBus/QDBusConnection>
#include <QtDBus/QDBusMessage>
#include <QtDBus/QDBusReply>
#include <QLoggingCategory> #include <QLoggingCategory>
Q_LOGGING_CATEGORY(lcLidWatcher, "ZShell.lidwatcher", QtInfoMsg) Q_LOGGING_CATEGORY(lcLidWatcher, "ZShell.lidwatcher", QtInfoMsg)
@@ -10,11 +12,12 @@ namespace ZShell {
static constexpr auto kLogin1Service = "org.freedesktop.login1"; static constexpr auto kLogin1Service = "org.freedesktop.login1";
static constexpr auto kLogin1Path = "/org/freedesktop/login1"; static constexpr auto kLogin1Path = "/org/freedesktop/login1";
static constexpr auto kLogin1Interface = "org.freedesktop.login1.Manager"; static constexpr auto kLogin1Interface = "org.freedesktop.login1.Manager";
static constexpr auto kPrepareForSleep = "PrepareForSleep"; static constexpr auto kDBusPropertiesInterface = "org.freedesktop.DBus.Properties";
LidWatcher::LidWatcher(QObject* parent) LidWatcher::LidWatcher(QObject* parent)
: QObject(parent) : QObject(parent)
, m_available(false) { , m_available(false)
, m_state(Opened) {
QDBusConnection bus = QDBusConnection::systemBus(); QDBusConnection bus = QDBusConnection::systemBus();
m_available = bus.isConnected(); m_available = bus.isConnected();
@@ -24,26 +27,48 @@ LidWatcher::LidWatcher(QObject* parent)
return; return;
} }
const auto ok = bus.connect(kLogin1Service, kLogin1Path, kLogin1Interface, kPrepareForSleep, this, const auto ok = bus.connect(kLogin1Service, kLogin1Path, kDBusPropertiesInterface, "PropertiesChanged",
SLOT(onPrepareForSleep(bool))); this, SLOT(onPropertiesChanged(QString,QVariantMap,QStringList)));
m_available = ok; m_available = ok;
emit availableChanged(); emit availableChanged();
if (!m_available) { if (!m_available) {
qCWarning(lcLidWatcher) << "login1 lid signal unavailable"; qCWarning(lcLidWatcher) << "login1 properties signal unavailable";
return;
} }
queryInitialState();
} }
AramJonghu marked this conversation as resolved Outdated
Outdated
Review

Doesn't this trigger only when the system is about to suspend/hibernate? There should be a way to query the lid state directly.

Doesn't this trigger only when the system is about to suspend/hibernate? There should be a way to query the lid state directly.
Outdated
Review

Correct. And in retrospect, not every distro has defaults where the system suspends when laptop is on AC. The idea was that it should only trigger when the system suspends or hibernates to cover it more broadly for desktops (if wished). Could be a separate plugin or addition to current implementation if that is a wish separate from laptop lid behavior.

Correct. And in retrospect, not every distro has defaults where the system suspends when laptop is on AC. The idea was that it should only trigger when the system suspends or hibernates to cover it more broadly for desktops (if wished). Could be a separate plugin or addition to current implementation if that is a wish separate from laptop lid behavior.
bool LidWatcher::available() const { bool LidWatcher::available() const {
return m_available; return m_available;
} }
void LidWatcher::onPrepareForSleep(bool goingDown) { LidWatcher::LidState LidWatcher::state() const {
if (goingDown) { return m_state;
emit lidClosing(); }
} else {
emit lidOpened(); void LidWatcher::queryInitialState() {
const auto msg = QDBusMessage::createMethodCall(
kLogin1Service, kLogin1Path,
kDBusPropertiesInterface, "Get");
msg << kLogin1Interface << "LidClosed";
const QDBusReply<QVariant> reply = QDBusConnection::systemBus().call(msg);
if (!reply.isValid()) {
qCWarning(lcLidWatcher) << "cannot query LidClosed:" << reply.error().message();
return;
} }
m_state = reply.value().toBool() ? Closed : Opened;
emit stateChanged();
}
void LidWatcher::onPropertiesChanged(const QString& interface, const QVariantMap& changed, const QStringList& /*invalidated*/) {
if (interface != kLogin1Interface)
return;
if (!changed.contains("LidClosed"))
return;
m_state = changed.value("LidClosed").toBool() ? Closed : Opened;
emit stateChanged();
} }
} // namespace ZShell } // namespace ZShell
+18 -6
View File
@@ -1,6 +1,8 @@
#pragma once #pragma once
#include <QObject> #include <QObject>
#include <QStringList>
#include <QVariantMap>
#include <qqmlintegration.h> #include <qqmlintegration.h>
namespace ZShell { namespace ZShell {
@@ -11,22 +13,32 @@ class LidWatcher : public QObject {
QML_SINGLETON QML_SINGLETON
Q_PROPERTY(bool available READ available NOTIFY availableChanged) Q_PROPERTY(bool available READ available NOTIFY availableChanged)
Q_PROPERTY(LidState state READ state NOTIFY stateChanged)
public: public:
enum LidState {
Opened,
Closed
};
Q_ENUM(LidState)
explicit LidWatcher(QObject* parent = nullptr); explicit LidWatcher(QObject* parent = nullptr);
[[nodiscard]] bool available() const; [[nodiscard]] bool available() const;
[[nodiscard]] LidState state() const;
private:
void queryInitialState();
bool m_available;
LidState m_state = Opened;
AramJonghu marked this conversation as resolved Outdated
Outdated
Review

extracted() is declared but never implemented in the .cpp file.

`extracted()` is declared but never implemented in the `.cpp` file.
private Q_SLOTS: private Q_SLOTS:
void onPrepareForSleep(bool goingDown); void onPropertiesChanged(const QString& interface, const QVariantMap& changed, const QStringList& invalidated);
Q_SIGNALS: Q_SIGNALS:
void availableChanged(); void availableChanged();
void lidClosing(); void stateChanged();
void lidOpened();
private:
bool m_available;
}; };
} // namespace ZShell } // namespace ZShell
+1 -1
View File
@@ -331,7 +331,7 @@ export const settingsIndex = [
category: "lockscreen", category: "lockscreen",
categoryName: "Lockscreen", categoryName: "Lockscreen",
section: "Lockscreen", section: "Lockscreen",
keywords: ["lid", "lcck", "watch", "session", "laptop"], keywords: ["lid", "lock", "watch", "session", "laptop"],
AramJonghu marked this conversation as resolved Outdated
Outdated
Review

Typo probably. "lcck" should be "lock"

Typo probably. `"lcck"` should be `"lock"`
}, },
{ {
name: "Blur amount", name: "Blur amount",
+6 -6
View File
@@ -47,12 +47,12 @@ ShellRoot {
Polkit { Polkit {
} }
LazyLoader { LazyLoader {
activeAsync: Config.lock.lidWatch && Battery.isLaptop activeAsync: Config.lock.lidWatch && Battery.isLaptop
component: LidService { component: LidService {
lock: lock onRequestLock: lock.requestLock()
} }
} }
LazyLoader { LazyLoader {
activeAsync: root.laptop activeAsync: root.laptop