From 82aa7c415f42a74f01e0a3f4ac07d87049a572ee Mon Sep 17 00:00:00 2001 From: AramJonghu Date: Mon, 1 Jun 2026 19:50:40 +0200 Subject: [PATCH 01/25] initial commit From 7de8cc310424132335bc9aab8aacaaecc22910a2 Mon Sep 17 00:00:00 2001 From: AramJonghu Date: Mon, 1 Jun 2026 20:02:37 +0200 Subject: [PATCH 02/25] lidwatcher plugin initial setup --- Plugins/ZShell/CMakeLists.txt | 2 ++ Plugins/ZShell/lidwatcher.cpp | 49 +++++++++++++++++++++++++++++++++++ Plugins/ZShell/lidwatcher.hpp | 32 +++++++++++++++++++++++ shell.qml | 9 +++++++ 4 files changed, 92 insertions(+) create mode 100644 Plugins/ZShell/lidwatcher.cpp create mode 100644 Plugins/ZShell/lidwatcher.hpp diff --git a/Plugins/ZShell/CMakeLists.txt b/Plugins/ZShell/CMakeLists.txt index c5f041e..1e04ea7 100644 --- a/Plugins/ZShell/CMakeLists.txt +++ b/Plugins/ZShell/CMakeLists.txt @@ -45,11 +45,13 @@ qml_module(ZShell requests.hpp requests.cpp toaster.hpp toaster.cpp qalculator.hpp qalculator.cpp + lidwatcher.hpp lidwatcher.cpp LIBRARIES Qt::Gui Qt::Quick Qt::Concurrent Qt::Sql + Qt::DBus PkgConfig::Qalculate ) diff --git a/Plugins/ZShell/lidwatcher.cpp b/Plugins/ZShell/lidwatcher.cpp new file mode 100644 index 0000000..49386a2 --- /dev/null +++ b/Plugins/ZShell/lidwatcher.cpp @@ -0,0 +1,49 @@ +#include "lidwatcher.hpp" + +#include +#include + +Q_LOGGING_CATEGORY(lcLidWatcher, "ZShell.lidwatcher", QtInfoMsg) + +namespace ZShell { + +static constexpr auto kLogin1Service = "org.freedesktop.login1"; +static constexpr auto kLogin1Path = "/org/freedesktop/login1"; +static constexpr auto kLogin1Interface = "org.freedesktop.login1.Manager"; +static constexpr auto kPrepareForSleep = "PrepareForSleep"; + +LidWatcher::LidWatcher(QObject* parent) + : QObject(parent) + , m_available(false) { + QDBusConnection bus = QDBusConnection::systemBus(); + m_available = bus.isConnected(); + + if (!m_available) { + qCWarning(lcLidWatcher) << "system bus unavailable"; + emit availableChanged(); + return; + } + + const auto ok = bus.connect(kLogin1Service, kLogin1Path, kLogin1Interface, kPrepareForSleep, this, + SLOT(onPrepareForSleep(bool))); + + m_available = ok; + emit availableChanged(); + if (!m_available) { + qCWarning(lcLidWatcher) << "login1 lid signal unavailable"; + } +} + +bool LidWatcher::available() const { + return m_available; +} + +void LidWatcher::onPrepareForSleep(bool goingDown) { + if (goingDown) { + emit lidClosing(); + } else { + emit lidOpened(); + } +} + +} // namespace ZShell diff --git a/Plugins/ZShell/lidwatcher.hpp b/Plugins/ZShell/lidwatcher.hpp new file mode 100644 index 0000000..c2e1d08 --- /dev/null +++ b/Plugins/ZShell/lidwatcher.hpp @@ -0,0 +1,32 @@ +#pragma once + +#include +#include + +namespace ZShell { + +class LidWatcher : public QObject { + Q_OBJECT + QML_ELEMENT + QML_SINGLETON + + Q_PROPERTY(bool available READ available NOTIFY availableChanged) + +public: + explicit LidWatcher(QObject* parent = nullptr); + + [[nodiscard]] bool available() const; + +private Q_SLOTS: + void onPrepareForSleep(bool goingDown); + +Q_SIGNALS: + void availableChanged(); + void lidClosing(); + void lidOpened(); + +private: + bool m_available; +}; + +} // namespace ZShell diff --git a/shell.qml b/shell.qml index c5c5b7f..bde4d41 100644 --- a/shell.qml +++ b/shell.qml @@ -7,6 +7,7 @@ //@ pragma DropExpensiveFonts import Quickshell import Quickshell.Services.UPower +import ZShell import qs.Modules import qs.Modules.Wallpaper import qs.Modules.Lock @@ -35,6 +36,14 @@ ShellRoot { id: lock } + Connections { + function onLidClosing(): void { + lock.locked = true; + } + + target: LidWatcher + } + Shortcuts { } From 0d097524c332caf6d87b97381ff7c9db45a91b97 Mon Sep 17 00:00:00 2001 From: AramJonghu Date: Mon, 1 Jun 2026 20:07:09 +0200 Subject: [PATCH 03/25] shell.qml could not load Connections, now fixed --- shell.qml | 1 + 1 file changed, 1 insertion(+) diff --git a/shell.qml b/shell.qml index bde4d41..1f91580 100644 --- a/shell.qml +++ b/shell.qml @@ -7,6 +7,7 @@ //@ pragma DropExpensiveFonts import Quickshell import Quickshell.Services.UPower +import QtQuick import ZShell import qs.Modules import qs.Modules.Wallpaper From c514e98687b7641ce8707be18944eb1a1dad9212 Mon Sep 17 00:00:00 2001 From: AramJonghu Date: Mon, 1 Jun 2026 20:12:17 +0200 Subject: [PATCH 04/25] nonexistant locked should be resolved --- shell.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shell.qml b/shell.qml index 1f91580..62e207d 100644 --- a/shell.qml +++ b/shell.qml @@ -39,7 +39,7 @@ ShellRoot { Connections { function onLidClosing(): void { - lock.locked = true; + lock.lock.locked = true; } target: LidWatcher From 83cf008a1980f07e3d2d0544b2d3d0a742ef1bdc Mon Sep 17 00:00:00 2001 From: AramJonghu Date: Mon, 1 Jun 2026 20:28:55 +0200 Subject: [PATCH 05/25] setting option to disable lidwatcher, also in settingswindow --- Config/Config.qml | 1 + Config/General.qml | 1 + Modules/Settings/Categories/Lockscreen.qml | 9 +++++++++ shell.qml | 2 ++ 4 files changed, 13 insertions(+) diff --git a/Config/Config.qml b/Config/Config.qml index 272e6b2..4f4dca0 100644 --- a/Config/Config.qml +++ b/Config/Config.qml @@ -196,6 +196,7 @@ Singleton { wallpaperPath: general.wallpaperPath, desktopIcons: general.desktopIcons, dateFormat: general.dateFormat, + lidWatch: general.lidWatch, color: { mode: general.color.mode, smart: general.color.smart, diff --git a/Config/General.qml b/Config/General.qml index 45d3513..1ab28c1 100644 --- a/Config/General.qml +++ b/Config/General.qml @@ -10,6 +10,7 @@ JsonObject { } property string dateFormat: "ddd d MMM - hh:mm:ss" property bool desktopIcons: false + property bool lidWatch: true property Idle idle: Idle { } property string logo: "" diff --git a/Modules/Settings/Categories/Lockscreen.qml b/Modules/Settings/Categories/Lockscreen.qml index d08b8a1..47f0f4d 100644 --- a/Modules/Settings/Categories/Lockscreen.qml +++ b/Modules/Settings/Categories/Lockscreen.qml @@ -59,6 +59,15 @@ SettingsPage { Separator { } + SettingSwitch { + name: "Lid watch" + object: Config.general + setting: "lidWatch" + } + + Separator { + } + SettingSpinBox { min: 0 name: "Blur amount" diff --git a/shell.qml b/shell.qml index 62e207d..3720216 100644 --- a/shell.qml +++ b/shell.qml @@ -14,6 +14,7 @@ import qs.Modules.Wallpaper import qs.Modules.Lock import qs.Drawers import qs.Helpers +import qs.Config import qs.Modules.Polkit import qs.Daemons @@ -38,6 +39,7 @@ ShellRoot { } Connections { + enabled: Config.general.lidWatch function onLidClosing(): void { lock.lock.locked = true; } From 1c1c6275df06472ef739e044932e58ea89a82c6d Mon Sep 17 00:00:00 2001 From: AramJonghu Date: Mon, 1 Jun 2026 20:45:04 +0200 Subject: [PATCH 06/25] move lid watch toggle into lock settings --- Config/Config.qml | 2 +- Config/General.qml | 1 - Config/LockConf.qml | 1 + Modules/Settings/Categories/Lockscreen.qml | 4 ++-- shell.qml | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Config/Config.qml b/Config/Config.qml index 4f4dca0..b2a541e 100644 --- a/Config/Config.qml +++ b/Config/Config.qml @@ -196,7 +196,6 @@ Singleton { wallpaperPath: general.wallpaperPath, desktopIcons: general.desktopIcons, dateFormat: general.dateFormat, - lidWatch: general.lidWatch, color: { mode: general.color.mode, smart: general.color.smart, @@ -254,6 +253,7 @@ Singleton { return { recolorLogo: lock.recolorLogo, enableFprint: lock.enableFprint, + lidWatch: lock.lidWatch, showNotifContent: lock.showNotifContent, showNotifIcon: lock.showNotifIcon, maxFprintTries: lock.maxFprintTries, diff --git a/Config/General.qml b/Config/General.qml index 1ab28c1..45d3513 100644 --- a/Config/General.qml +++ b/Config/General.qml @@ -10,7 +10,6 @@ JsonObject { } property string dateFormat: "ddd d MMM - hh:mm:ss" property bool desktopIcons: false - property bool lidWatch: true property Idle idle: Idle { } property string logo: "" diff --git a/Config/LockConf.qml b/Config/LockConf.qml index 87a4f4e..874131b 100644 --- a/Config/LockConf.qml +++ b/Config/LockConf.qml @@ -4,6 +4,7 @@ JsonObject { property int blurAmount: 40 property bool enableFprint: true property int maxFprintTries: 3 + property bool lidWatch: true property bool recolorLogo: false property bool showNotifContent: false property bool showNotifIcon: true diff --git a/Modules/Settings/Categories/Lockscreen.qml b/Modules/Settings/Categories/Lockscreen.qml index 47f0f4d..3230086 100644 --- a/Modules/Settings/Categories/Lockscreen.qml +++ b/Modules/Settings/Categories/Lockscreen.qml @@ -60,8 +60,8 @@ SettingsPage { } SettingSwitch { - name: "Lid watch" - object: Config.general + name: "Laptop lid watch to lock session" + object: Config.lock setting: "lidWatch" } diff --git a/shell.qml b/shell.qml index 3720216..2a24bbc 100644 --- a/shell.qml +++ b/shell.qml @@ -39,7 +39,7 @@ ShellRoot { } Connections { - enabled: Config.general.lidWatch + enabled: Config.lock.lidWatch function onLidClosing(): void { lock.lock.locked = true; } From db9c98b322038f1577aa208de822e2d2dd50b3cf Mon Sep 17 00:00:00 2001 From: AramJonghu Date: Mon, 1 Jun 2026 21:03:59 +0200 Subject: [PATCH 07/25] set default enabled for laptops, disabled for non battery devices --- Config/LockConf.qml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Config/LockConf.qml b/Config/LockConf.qml index 874131b..88ad57c 100644 --- a/Config/LockConf.qml +++ b/Config/LockConf.qml @@ -1,10 +1,11 @@ import Quickshell.Io +import Quickshell.Services.UPower JsonObject { property int blurAmount: 40 property bool enableFprint: true property int maxFprintTries: 3 - property bool lidWatch: true + property bool lidWatch: UPower.displayDevice.isLaptopBattery property bool recolorLogo: false property bool showNotifContent: false property bool showNotifIcon: true From 7da2c7827a548afac3633103fff40a40eeaac6d6 Mon Sep 17 00:00:00 2001 From: AramJonghu Date: Mon, 1 Jun 2026 23:53:26 +0200 Subject: [PATCH 08/25] refactor: using more oop --- Config/LockConf.qml | 3 +-- Daemons/LidService.qml | 18 ++++++++++++++++++ Modules/Settings/Categories/Lockscreen.qml | 3 +++ scripts/SettingsIndex.mjs | 7 +++++++ shell.qml | 17 +++++++---------- 5 files changed, 36 insertions(+), 12 deletions(-) create mode 100644 Daemons/LidService.qml diff --git a/Config/LockConf.qml b/Config/LockConf.qml index 88ad57c..3826a90 100644 --- a/Config/LockConf.qml +++ b/Config/LockConf.qml @@ -1,11 +1,10 @@ import Quickshell.Io -import Quickshell.Services.UPower JsonObject { property int blurAmount: 40 property bool enableFprint: true property int maxFprintTries: 3 - property bool lidWatch: UPower.displayDevice.isLaptopBattery + property bool lidWatch: false property bool recolorLogo: false property bool showNotifContent: false property bool showNotifIcon: true diff --git a/Daemons/LidService.qml b/Daemons/LidService.qml new file mode 100644 index 0000000..d8ccbd7 --- /dev/null +++ b/Daemons/LidService.qml @@ -0,0 +1,18 @@ +import Quickshell +import ZShell + +Scope { + id: root + + required property var lock + + + Connections { + function onLidClosing(): void { + root.lock.lock.locked = true; + } + + target: LidWatcher + } + +} diff --git a/Modules/Settings/Categories/Lockscreen.qml b/Modules/Settings/Categories/Lockscreen.qml index 3230086..ae45f8d 100644 --- a/Modules/Settings/Categories/Lockscreen.qml +++ b/Modules/Settings/Categories/Lockscreen.qml @@ -1,5 +1,6 @@ import qs.Modules.Settings.Categories.Lockscreen import qs.Modules.Settings.Controls +import qs.Helpers import qs.Config SettingsPage { @@ -63,9 +64,11 @@ SettingsPage { name: "Laptop lid watch to lock session" object: Config.lock setting: "lidWatch" + shouldBeActive: Battery.isLaptop } Separator { + shouldBeActive: Battery.isLaptop } SettingSpinBox { diff --git a/scripts/SettingsIndex.mjs b/scripts/SettingsIndex.mjs index ba5eaed..902467b 100644 --- a/scripts/SettingsIndex.mjs +++ b/scripts/SettingsIndex.mjs @@ -326,6 +326,13 @@ export const settingsIndex = [ section: "Lockscreen", keywords: ["notification", "hide", "icon"], }, + { + name: "Laptop lid watch to lock session", + category: "lockscreen", + categoryName: "Lockscreen", + section: "Lockscreen", + keywords: ["lid", "lcck", "watch", "session", "laptop"], + }, { name: "Blur amount", category: "lockscreen", diff --git a/shell.qml b/shell.qml index 2a24bbc..39c550a 100644 --- a/shell.qml +++ b/shell.qml @@ -8,7 +8,6 @@ import Quickshell import Quickshell.Services.UPower import QtQuick -import ZShell import qs.Modules import qs.Modules.Wallpaper import qs.Modules.Lock @@ -38,15 +37,6 @@ ShellRoot { id: lock } - Connections { - enabled: Config.lock.lidWatch - function onLidClosing(): void { - lock.lock.locked = true; - } - - target: LidWatcher - } - Shortcuts { } @@ -57,6 +47,13 @@ ShellRoot { Polkit { } + LazyLoader { + activeAsync: Config.lock.lidWatch && Battery.isLaptop + component: LidService { + lock: lock + } + } + LazyLoader { activeAsync: root.laptop From ad2ee99d9c70dda7f5625012b15589b091544a41 Mon Sep 17 00:00:00 2001 From: AramJonghu Date: Mon, 1 Jun 2026 23:59:07 +0200 Subject: [PATCH 09/25] format using qmlformat --- Daemons/LidService.qml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Daemons/LidService.qml b/Daemons/LidService.qml index d8ccbd7..4911d31 100644 --- a/Daemons/LidService.qml +++ b/Daemons/LidService.qml @@ -2,10 +2,9 @@ import Quickshell import ZShell Scope { - id: root + id: root - required property var lock - + required property var lock Connections { function onLidClosing(): void { @@ -14,5 +13,4 @@ Scope { target: LidWatcher } - } From c91b53fbaa2e209e906a708fe2a300823c414bc2 Mon Sep 17 00:00:00 2001 From: AramJonghu Date: Tue, 2 Jun 2026 00:03:30 +0200 Subject: [PATCH 10/25] QTQuick --- Daemons/LidService.qml | 1 + 1 file changed, 1 insertion(+) diff --git a/Daemons/LidService.qml b/Daemons/LidService.qml index 4911d31..d015f6e 100644 --- a/Daemons/LidService.qml +++ b/Daemons/LidService.qml @@ -1,5 +1,6 @@ import Quickshell import ZShell +import QtQuick Scope { id: root From 016dcc008f0be8d23c9b87e2faf86aa2db1937cd Mon Sep 17 00:00:00 2001 From: AramJonghu Date: Wed, 3 Jun 2026 00:54:44 +0200 Subject: [PATCH 11/25] Cpp changes, minor refactor plus separate signal logic, typo. - typo in searchindex - Cpp plugin changed to use enum lidstate - minor refactor - Using signals instead of direct property access. - Using states instead - checking lidclosed instead of preparetosleep --- Daemons/LidService.qml | 7 +++--- Modules/Lock/Lock.qml | 3 +++ Plugins/ZShell/lidwatcher.cpp | 45 +++++++++++++++++++++++++++-------- Plugins/ZShell/lidwatcher.hpp | 24 ++++++++++++++----- scripts/SettingsIndex.mjs | 2 +- shell.qml | 12 +++++----- 6 files changed, 67 insertions(+), 26 deletions(-) diff --git a/Daemons/LidService.qml b/Daemons/LidService.qml index d015f6e..0a8fe79 100644 --- a/Daemons/LidService.qml +++ b/Daemons/LidService.qml @@ -5,11 +5,12 @@ import QtQuick Scope { id: root - required property var lock + signal requestLock Connections { - function onLidClosing(): void { - root.lock.lock.locked = true; + function onStateChanged(): void { + if (LidWatcher.state === LidWatcher.Closed) + root.requestLock(); } target: LidWatcher diff --git a/Modules/Lock/Lock.qml b/Modules/Lock/Lock.qml index 9c6f8df..68d8a46 100644 --- a/Modules/Lock/Lock.qml +++ b/Modules/Lock/Lock.qml @@ -18,6 +18,9 @@ Scope { signal requestLock signal unlock + onRequestLock: lock.locked = true + onUnlock: lock.locked = false + LockSurface { id: lockSurface diff --git a/Plugins/ZShell/lidwatcher.cpp b/Plugins/ZShell/lidwatcher.cpp index 49386a2..f1f0c43 100644 --- a/Plugins/ZShell/lidwatcher.cpp +++ b/Plugins/ZShell/lidwatcher.cpp @@ -1,6 +1,8 @@ #include "lidwatcher.hpp" #include +#include +#include #include Q_LOGGING_CATEGORY(lcLidWatcher, "ZShell.lidwatcher", QtInfoMsg) @@ -10,11 +12,12 @@ namespace ZShell { static constexpr auto kLogin1Service = "org.freedesktop.login1"; static constexpr auto kLogin1Path = "/org/freedesktop/login1"; 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) : QObject(parent) - , m_available(false) { + , m_available(false) + , m_state(Opened) { QDBusConnection bus = QDBusConnection::systemBus(); m_available = bus.isConnected(); @@ -24,26 +27,48 @@ LidWatcher::LidWatcher(QObject* parent) return; } - const auto ok = bus.connect(kLogin1Service, kLogin1Path, kLogin1Interface, kPrepareForSleep, this, - SLOT(onPrepareForSleep(bool))); + const auto ok = bus.connect(kLogin1Service, kLogin1Path, kDBusPropertiesInterface, "PropertiesChanged", + this, SLOT(onPropertiesChanged(QString,QVariantMap,QStringList))); m_available = ok; emit availableChanged(); if (!m_available) { - qCWarning(lcLidWatcher) << "login1 lid signal unavailable"; + qCWarning(lcLidWatcher) << "login1 properties signal unavailable"; + return; } + + queryInitialState(); } bool LidWatcher::available() const { return m_available; } -void LidWatcher::onPrepareForSleep(bool goingDown) { - if (goingDown) { - emit lidClosing(); - } else { - emit lidOpened(); +LidWatcher::LidState LidWatcher::state() const { + return m_state; +} + +void LidWatcher::queryInitialState() { + const auto msg = QDBusMessage::createMethodCall( + kLogin1Service, kLogin1Path, + kDBusPropertiesInterface, "Get"); + msg << kLogin1Interface << "LidClosed"; + const QDBusReply 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 diff --git a/Plugins/ZShell/lidwatcher.hpp b/Plugins/ZShell/lidwatcher.hpp index c2e1d08..7486f6a 100644 --- a/Plugins/ZShell/lidwatcher.hpp +++ b/Plugins/ZShell/lidwatcher.hpp @@ -1,6 +1,8 @@ #pragma once #include +#include +#include #include namespace ZShell { @@ -11,22 +13,32 @@ class LidWatcher : public QObject { QML_SINGLETON Q_PROPERTY(bool available READ available NOTIFY availableChanged) + Q_PROPERTY(LidState state READ state NOTIFY stateChanged) public: + enum LidState { + Opened, + Closed + }; + Q_ENUM(LidState) + explicit LidWatcher(QObject* parent = nullptr); [[nodiscard]] bool available() const; + [[nodiscard]] LidState state() const; + +private: + void queryInitialState(); + + bool m_available; + LidState m_state = Opened; private Q_SLOTS: - void onPrepareForSleep(bool goingDown); + void onPropertiesChanged(const QString& interface, const QVariantMap& changed, const QStringList& invalidated); Q_SIGNALS: void availableChanged(); - void lidClosing(); - void lidOpened(); - -private: - bool m_available; + void stateChanged(); }; } // namespace ZShell diff --git a/scripts/SettingsIndex.mjs b/scripts/SettingsIndex.mjs index 902467b..9d2c870 100644 --- a/scripts/SettingsIndex.mjs +++ b/scripts/SettingsIndex.mjs @@ -331,7 +331,7 @@ export const settingsIndex = [ category: "lockscreen", categoryName: "Lockscreen", section: "Lockscreen", - keywords: ["lid", "lcck", "watch", "session", "laptop"], + keywords: ["lid", "lock", "watch", "session", "laptop"], }, { name: "Blur amount", diff --git a/shell.qml b/shell.qml index 39c550a..3889720 100644 --- a/shell.qml +++ b/shell.qml @@ -47,12 +47,12 @@ ShellRoot { Polkit { } - LazyLoader { - activeAsync: Config.lock.lidWatch && Battery.isLaptop - component: LidService { - lock: lock - } - } + LazyLoader { + activeAsync: Config.lock.lidWatch && Battery.isLaptop + component: LidService { + onRequestLock: lock.requestLock() + } + } LazyLoader { activeAsync: root.laptop From 3bcdbbabbb0d61ecf24d65854794416eb7dc1b03 Mon Sep 17 00:00:00 2001 From: AramJonghu Date: Wed, 3 Jun 2026 01:02:50 +0200 Subject: [PATCH 12/25] build fix --- Plugins/ZShell/lidwatcher.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Plugins/ZShell/lidwatcher.cpp b/Plugins/ZShell/lidwatcher.cpp index f1f0c43..9c53aac 100644 --- a/Plugins/ZShell/lidwatcher.cpp +++ b/Plugins/ZShell/lidwatcher.cpp @@ -49,7 +49,7 @@ LidWatcher::LidState LidWatcher::state() const { } void LidWatcher::queryInitialState() { - const auto msg = QDBusMessage::createMethodCall( + auto msg = QDBusMessage::createMethodCall( kLogin1Service, kLogin1Path, kDBusPropertiesInterface, "Get"); msg << kLogin1Interface << "LidClosed"; From 45f36ce71cf3e2b9bf7f6ab36f47e68b917e448d Mon Sep 17 00:00:00 2001 From: AramJonghu Date: Wed, 3 Jun 2026 01:14:37 +0200 Subject: [PATCH 13/25] added lock. in shell.qml, wrong scope --- shell.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shell.qml b/shell.qml index 3889720..0f494ef 100644 --- a/shell.qml +++ b/shell.qml @@ -50,7 +50,7 @@ ShellRoot { LazyLoader { activeAsync: Config.lock.lidWatch && Battery.isLaptop component: LidService { - onRequestLock: lock.requestLock() + onRequestLock: lock.lock.requestLock() } } From 896e5e520dd896f8c76aeeff820c959daeecf37f Mon Sep 17 00:00:00 2001 From: AramJonghu Date: Wed, 3 Jun 2026 02:05:18 +0200 Subject: [PATCH 14/25] Added clang-format/tidy for additional rules. Adjusted inbranch cpp files. --- .clang-format | 58 +++++++++++++++++++++++++++++++++++ .clang-tidy | 31 +++++++++++++++++++ CMakeLists.txt | 3 ++ Plugins/ZShell/lidwatcher.cpp | 37 +++++++++++++--------- Plugins/ZShell/lidwatcher.hpp | 19 ++++++------ 5 files changed, 125 insertions(+), 23 deletions(-) create mode 100644 .clang-format create mode 100644 .clang-tidy diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..a2cde00 --- /dev/null +++ b/.clang-format @@ -0,0 +1,58 @@ +--- +BasedOnStyle: LLVM +AccessModifierOffset: 0 +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignOperands: Align +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortFunctionsOnASingleLine: Inline +AllowShortIfStatementsOnASingleLine: Never +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: Yes +BinPackArguments: false +BinPackParameters: false +BreakBeforeBraces: Attach +BreakBeforeTernaryOperators: true +BreakConstructorInitializers: BeforeComma +ColumnLimit: 80 +ConstructorInitializerAllOnOneLineOrOnePerLine: true +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DerivePointerAlignment: false +FixNamespaceComments: true +IndentCaseLabels: false +IndentWidth: 4 +KeepEmptyLinesAtTheStartOfBlocks: false +Language: Cpp +MaxEmptyLinesToKeep: 2 +NamespaceIndentation: None +PenaltyBreakAssignment: 10 +PenaltyBreakBeforeFirstCallParameter: 100 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyExcessCharacter: 100 +PenaltyReturnTypeOnItsOwnLine: 200 +PointerAlignment: Left +ReflowComments: false +SortIncludes: false +SpaceAfterCStyleCast: false +SpaceAfterTemplateKeyword: true +SpaceBeforeAssignmentOperators: true +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeParens: ControlStatements +SpaceBeforeRangeBasedForLoopColon: true +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: false +SpacesInContainerLiterals: false +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: c++20 +TabWidth: 4 +UseTab: Always diff --git a/.clang-tidy b/.clang-tidy new file mode 100644 index 0000000..888e041 --- /dev/null +++ b/.clang-tidy @@ -0,0 +1,31 @@ +--- +Checks: > + -*, + bugprone-*, + clang-analyzer-*, + modernize-*, + -modernize-use-trailing-return-type, + performance-*, + readability-braces-around-statements, + readability-else-after-return, + readability-identifier-naming, + readability-redundant-*, + readability-simplify-*, +CheckOptions: + readability-identifier-naming.ClassCase: CamelCase + readability-identifier-naming.EnumCase: CamelCase + readability-identifier-naming.FunctionCase: camelBack + readability-identifier-naming.MemberCase: camelBack + readability-identifier-naming.MemberPrefix: m_ + readability-identifier-naming.MethodCase: camelBack + readability-identifier-naming.NamespaceCase: lower_case + readability-identifier-naming.ParameterCase: camelBack + readability-identifier-naming.PrivateMemberPrefix: m_ + readability-identifier-naming.StaticConstantCase: UPPER_CASE + readability-identifier-naming.StaticConstantPrefix: k + readability-identifier-naming.VariableCase: camelBack +WarningsAsErrors: "*" +HeaderFilterRegex: ".*" +FormatStyle: file + +... diff --git a/CMakeLists.txt b/CMakeLists.txt index ce22903..0e4c6c4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,6 +25,9 @@ add_compile_options( if("plugin" IN_LIST ENABLE_MODULES) add_subdirectory(Plugins) + + add_custom_target(fix-cc + COMMAND sed -i "s/-mno-direct-extern-access/-fno-direct-access-external-data/g" "${CMAKE_BINARY_DIR}/compile_commands.json") endif() if("shell" IN_LIST ENABLE_MODULES) diff --git a/Plugins/ZShell/lidwatcher.cpp b/Plugins/ZShell/lidwatcher.cpp index 9c53aac..4ad1b49 100644 --- a/Plugins/ZShell/lidwatcher.cpp +++ b/Plugins/ZShell/lidwatcher.cpp @@ -12,12 +12,10 @@ namespace ZShell { static constexpr auto kLogin1Service = "org.freedesktop.login1"; static constexpr auto kLogin1Path = "/org/freedesktop/login1"; static constexpr auto kLogin1Interface = "org.freedesktop.login1.Manager"; -static constexpr auto kDBusPropertiesInterface = "org.freedesktop.DBus.Properties"; +static constexpr auto kDBusPropertiesInterface = + "org.freedesktop.DBus.Properties"; -LidWatcher::LidWatcher(QObject* parent) - : QObject(parent) - , m_available(false) - , m_state(Opened) { +LidWatcher::LidWatcher(QObject* parent) : QObject(parent), m_available(false) { QDBusConnection bus = QDBusConnection::systemBus(); m_available = bus.isConnected(); @@ -27,8 +25,13 @@ LidWatcher::LidWatcher(QObject* parent) return; } - const auto ok = bus.connect(kLogin1Service, kLogin1Path, kDBusPropertiesInterface, "PropertiesChanged", - this, SLOT(onPropertiesChanged(QString,QVariantMap,QStringList))); + const auto ok = bus.connect( + kLogin1Service, + kLogin1Path, + kDBusPropertiesInterface, + "PropertiesChanged", + this, + SLOT(onPropertiesChanged(QString, QVariantMap, QStringList))); m_available = ok; emit availableChanged(); @@ -49,24 +52,30 @@ LidWatcher::LidState LidWatcher::state() const { } void LidWatcher::queryInitialState() { - auto msg = QDBusMessage::createMethodCall( - kLogin1Service, kLogin1Path, - kDBusPropertiesInterface, "Get"); + auto msg = QDBusMessage::createMethodCall(kLogin1Service, + kLogin1Path, + kDBusPropertiesInterface, + "Get"); msg << kLogin1Interface << "LidClosed"; const QDBusReply reply = QDBusConnection::systemBus().call(msg); if (!reply.isValid()) { - qCWarning(lcLidWatcher) << "cannot query LidClosed:" << reply.error().message(); + 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) +void LidWatcher::onPropertiesChanged(const QString& interface, + const QVariantMap& changed, + const QStringList& ) { + if (interface != kLogin1Interface) { return; - if (!changed.contains("LidClosed")) + } + if (!changed.contains("LidClosed")) { return; + } m_state = changed.value("LidClosed").toBool() ? Closed : Opened; emit stateChanged(); } diff --git a/Plugins/ZShell/lidwatcher.hpp b/Plugins/ZShell/lidwatcher.hpp index 7486f6a..2f25d7b 100644 --- a/Plugins/ZShell/lidwatcher.hpp +++ b/Plugins/ZShell/lidwatcher.hpp @@ -3,6 +3,7 @@ #include #include #include +#include #include namespace ZShell { @@ -15,11 +16,8 @@ class LidWatcher : public QObject { Q_PROPERTY(bool available READ available NOTIFY availableChanged) Q_PROPERTY(LidState state READ state NOTIFY stateChanged) -public: - enum LidState { - Opened, - Closed - }; + public: + enum LidState : std::uint8_t{ Opened, Closed }; Q_ENUM(LidState) explicit LidWatcher(QObject* parent = nullptr); @@ -27,16 +25,19 @@ public: [[nodiscard]] bool available() const; [[nodiscard]] LidState state() const; -private: + private: void queryInitialState(); bool m_available; LidState m_state = Opened; -private Q_SLOTS: - void onPropertiesChanged(const QString& interface, const QVariantMap& changed, const QStringList& invalidated); -Q_SIGNALS: + void extracted(); + void onPropertiesChanged(const QString& interface, + const QVariantMap& changed, + const QStringList& invalidated); + + Q_SIGNALS: void availableChanged(); void stateChanged(); }; From 0584cd618ef319ad731d40507880942272970052 Mon Sep 17 00:00:00 2001 From: AramJonghu Date: Wed, 3 Jun 2026 02:30:13 +0200 Subject: [PATCH 15/25] missing changes --- .clang-tidy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.clang-tidy b/.clang-tidy index 888e041..cefd2c6 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -18,7 +18,7 @@ CheckOptions: readability-identifier-naming.MemberCase: camelBack readability-identifier-naming.MemberPrefix: m_ readability-identifier-naming.MethodCase: camelBack - readability-identifier-naming.NamespaceCase: lower_case + readability-identifier-naming.NamespaceCase: CamelCase readability-identifier-naming.ParameterCase: camelBack readability-identifier-naming.PrivateMemberPrefix: m_ readability-identifier-naming.StaticConstantCase: UPPER_CASE From 2920c5716343a2f3fa41e6a58f33bafccb39a68c Mon Sep 17 00:00:00 2001 From: AramJonghu Date: Wed, 3 Jun 2026 16:27:31 +0200 Subject: [PATCH 16/25] removes direct extern access, receives signal properly now, removed declaration unused method --- CMakeLists.txt | 2 -- Daemons/LidService.qml | 1 - Modules/Lock/Lock.qml | 8 ++++++++ Plugins/ZShell/lidwatcher.hpp | 1 - shell.qml | 5 +++++ 5 files changed, 13 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0e4c6c4..a2e2def 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,8 +26,6 @@ add_compile_options( if("plugin" IN_LIST ENABLE_MODULES) add_subdirectory(Plugins) - add_custom_target(fix-cc - COMMAND sed -i "s/-mno-direct-extern-access/-fno-direct-access-external-data/g" "${CMAKE_BINARY_DIR}/compile_commands.json") endif() if("shell" IN_LIST ENABLE_MODULES) diff --git a/Daemons/LidService.qml b/Daemons/LidService.qml index 0a8fe79..98f67d1 100644 --- a/Daemons/LidService.qml +++ b/Daemons/LidService.qml @@ -1,5 +1,4 @@ import Quickshell -import ZShell import QtQuick Scope { diff --git a/Modules/Lock/Lock.qml b/Modules/Lock/Lock.qml index 68d8a46..5de21c6 100644 --- a/Modules/Lock/Lock.qml +++ b/Modules/Lock/Lock.qml @@ -9,6 +9,7 @@ import qs.Components Scope { id: root + required property var lid property alias lock: lock property int seenOnce: 0 @@ -21,6 +22,13 @@ Scope { onRequestLock: lock.locked = true onUnlock: lock.locked = false + Connections { + target: root.lid + function onRequestLock(): void { + lock.locked = true + } + } + LockSurface { id: lockSurface diff --git a/Plugins/ZShell/lidwatcher.hpp b/Plugins/ZShell/lidwatcher.hpp index 2f25d7b..7579bcc 100644 --- a/Plugins/ZShell/lidwatcher.hpp +++ b/Plugins/ZShell/lidwatcher.hpp @@ -32,7 +32,6 @@ class LidWatcher : public QObject { LidState m_state = Opened; - void extracted(); void onPropertiesChanged(const QString& interface, const QVariantMap& changed, const QStringList& invalidated); diff --git a/shell.qml b/shell.qml index 0f494ef..9063f58 100644 --- a/shell.qml +++ b/shell.qml @@ -35,6 +35,8 @@ ShellRoot { Lock { id: lock + + lid: lid } Shortcuts { @@ -48,7 +50,10 @@ ShellRoot { } LazyLoader { + id: lid + activeAsync: Config.lock.lidWatch && Battery.isLaptop + component: LidService { onRequestLock: lock.lock.requestLock() } From 7dbce0bf8c4c0e8c05b0e7fd2546401b3acdbe0d Mon Sep 17 00:00:00 2001 From: AramJonghu Date: Wed, 3 Jun 2026 16:29:11 +0200 Subject: [PATCH 17/25] qmlls lied to me - import ZShell returned --- Daemons/LidService.qml | 1 + 1 file changed, 1 insertion(+) diff --git a/Daemons/LidService.qml b/Daemons/LidService.qml index 98f67d1..0a8fe79 100644 --- a/Daemons/LidService.qml +++ b/Daemons/LidService.qml @@ -1,4 +1,5 @@ import Quickshell +import ZShell import QtQuick Scope { From f9ab1e2a10d71deb286b9d79db131c24616e282c Mon Sep 17 00:00:00 2001 From: AramJonghu Date: Wed, 3 Jun 2026 16:51:15 +0200 Subject: [PATCH 18/25] inability to connect to DBus.Properties resolved --- Plugins/ZShell/lidwatcher.cpp | 84 +++++++++++++++++++++++++---------- Plugins/ZShell/lidwatcher.hpp | 16 ++++--- 2 files changed, 71 insertions(+), 29 deletions(-) diff --git a/Plugins/ZShell/lidwatcher.cpp b/Plugins/ZShell/lidwatcher.cpp index 4ad1b49..20036e0 100644 --- a/Plugins/ZShell/lidwatcher.cpp +++ b/Plugins/ZShell/lidwatcher.cpp @@ -3,7 +3,9 @@ #include #include #include +#include #include +#include Q_LOGGING_CATEGORY(lcLidWatcher, "ZShell.lidwatcher", QtInfoMsg) @@ -15,32 +17,32 @@ static constexpr auto kLogin1Interface = "org.freedesktop.login1.Manager"; static constexpr auto kDBusPropertiesInterface = "org.freedesktop.DBus.Properties"; -LidWatcher::LidWatcher(QObject* parent) : QObject(parent), m_available(false) { +LidWatcher::LidWatcher(QObject* parent) + : QObject(parent) + , m_watcher(nullptr) + , m_pollTimer(nullptr) + , m_available(false) +{ QDBusConnection bus = QDBusConnection::systemBus(); - m_available = bus.isConnected(); - - if (!m_available) { + if (!bus.isConnected()) { qCWarning(lcLidWatcher) << "system bus unavailable"; emit availableChanged(); return; } - const auto ok = bus.connect( + m_pollTimer = new QTimer(this); + m_pollTimer->setInterval(5000); + connect(m_pollTimer, &QTimer::timeout, this, &LidWatcher::queryLidState); + + m_watcher = new QDBusServiceWatcher( kLogin1Service, - kLogin1Path, - kDBusPropertiesInterface, - "PropertiesChanged", - this, - SLOT(onPropertiesChanged(QString, QVariantMap, QStringList))); + bus, + QDBusServiceWatcher::WatchForRegistration, + this); + connect(m_watcher, &QDBusServiceWatcher::serviceRegistered, + this, &LidWatcher::tryConnect); - m_available = ok; - emit availableChanged(); - if (!m_available) { - qCWarning(lcLidWatcher) << "login1 properties signal unavailable"; - return; - } - - queryInitialState(); + tryConnect(); } bool LidWatcher::available() const { @@ -51,7 +53,37 @@ LidWatcher::LidState LidWatcher::state() const { return m_state; } -void LidWatcher::queryInitialState() { +void LidWatcher::tryConnect() { + QDBusConnection bus = QDBusConnection::systemBus(); + + const auto connected = bus.connect( + kLogin1Service, + kLogin1Path, + kDBusPropertiesInterface, + "PropertiesChanged", + this, + SLOT(onPropertiesChanged(QString, QVariantMap, QStringList))); + + queryLidState(); + + if (connected) { + m_pollTimer->stop(); + qCInfo(lcLidWatcher) << "login1 PropertiesChanged connected"; + } else { + qCWarning(lcLidWatcher) + << "login1 PropertiesChanged unavailable, polling"; + if (!m_pollTimer->isActive()) { + m_pollTimer->start(); +} + } + + if (!m_available) { + m_available = true; + emit availableChanged(); + } +} + +void LidWatcher::queryLidState() { auto msg = QDBusMessage::createMethodCall(kLogin1Service, kLogin1Path, kDBusPropertiesInterface, @@ -63,8 +95,11 @@ void LidWatcher::queryInitialState() { << "cannot query LidClosed:" << reply.error().message(); return; } - m_state = reply.value().toBool() ? Closed : Opened; - emit stateChanged(); + const auto newState = reply.value().toBool() ? Closed : Opened; + if (m_state != newState) { + m_state = newState; + emit stateChanged(); + } } void LidWatcher::onPropertiesChanged(const QString& interface, @@ -76,8 +111,11 @@ void LidWatcher::onPropertiesChanged(const QString& interface, if (!changed.contains("LidClosed")) { return; } - m_state = changed.value("LidClosed").toBool() ? Closed : Opened; - emit stateChanged(); + const auto newState = changed.value("LidClosed").toBool() ? Closed : Opened; + if (m_state != newState) { + m_state = newState; + emit stateChanged(); + } } } // namespace ZShell diff --git a/Plugins/ZShell/lidwatcher.hpp b/Plugins/ZShell/lidwatcher.hpp index 7579bcc..e7685ec 100644 --- a/Plugins/ZShell/lidwatcher.hpp +++ b/Plugins/ZShell/lidwatcher.hpp @@ -6,6 +6,9 @@ #include #include +class QDBusServiceWatcher; +class QTimer; + namespace ZShell { class LidWatcher : public QObject { @@ -26,16 +29,17 @@ class LidWatcher : public QObject { [[nodiscard]] LidState state() const; private: - void queryInitialState(); - - bool m_available; - LidState m_state = Opened; - - + void tryConnect(); + void queryLidState(); void onPropertiesChanged(const QString& interface, const QVariantMap& changed, const QStringList& invalidated); + QDBusServiceWatcher* m_watcher; + QTimer* m_pollTimer; + bool m_available; + LidState m_state = Opened; + Q_SIGNALS: void availableChanged(); void stateChanged(); From deef85d10cd788785561a95a967bb173b8e2f8ca Mon Sep 17 00:00:00 2001 From: AramJonghu Date: Wed, 3 Jun 2026 17:02:46 +0200 Subject: [PATCH 19/25] troubleshooting dbus --- Plugins/ZShell/lidwatcher.cpp | 2 +- Plugins/ZShell/lidwatcher.hpp | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Plugins/ZShell/lidwatcher.cpp b/Plugins/ZShell/lidwatcher.cpp index 20036e0..212209c 100644 --- a/Plugins/ZShell/lidwatcher.cpp +++ b/Plugins/ZShell/lidwatcher.cpp @@ -57,7 +57,7 @@ void LidWatcher::tryConnect() { QDBusConnection bus = QDBusConnection::systemBus(); const auto connected = bus.connect( - kLogin1Service, + QString(), kLogin1Path, kDBusPropertiesInterface, "PropertiesChanged", diff --git a/Plugins/ZShell/lidwatcher.hpp b/Plugins/ZShell/lidwatcher.hpp index e7685ec..ec74ca1 100644 --- a/Plugins/ZShell/lidwatcher.hpp +++ b/Plugins/ZShell/lidwatcher.hpp @@ -31,15 +31,17 @@ class LidWatcher : public QObject { private: void tryConnect(); void queryLidState(); - void onPropertiesChanged(const QString& interface, - const QVariantMap& changed, - const QStringList& invalidated); QDBusServiceWatcher* m_watcher; QTimer* m_pollTimer; bool m_available; LidState m_state = Opened; + private Q_SLOTS: + void onPropertiesChanged(const QString& interface, + const QVariantMap& changed, + const QStringList& invalidated); + Q_SIGNALS: void availableChanged(); void stateChanged(); From ed28d8b56a9705e9a5194b3ad64b744a09e90d44 Mon Sep 17 00:00:00 2001 From: AramJonghu Date: Wed, 3 Jun 2026 17:41:17 +0200 Subject: [PATCH 20/25] Took caelestia lid logic (prepare to sleep) instead --- Plugins/ZShell/lidwatcher.cpp | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/Plugins/ZShell/lidwatcher.cpp b/Plugins/ZShell/lidwatcher.cpp index 212209c..7a6105f 100644 --- a/Plugins/ZShell/lidwatcher.cpp +++ b/Plugins/ZShell/lidwatcher.cpp @@ -1,6 +1,7 @@ #include "lidwatcher.hpp" #include +#include #include #include #include @@ -56,8 +57,34 @@ LidWatcher::LidState LidWatcher::state() const { void LidWatcher::tryConnect() { QDBusConnection bus = QDBusConnection::systemBus(); + const auto iface = bus.interface(); + if (!iface) { + queryLidState(); + if (!m_available) { + m_available = true; + emit availableChanged(); + } + if (!m_pollTimer->isActive()) { + m_pollTimer->start(); +} + return; + } + const auto reply = iface->isServiceRegistered(kLogin1Service); + if (!reply.isValid() || !reply.value()) { + queryLidState(); + qCInfo(lcLidWatcher) << "login1 not available, polling"; + if (!m_available) { + m_available = true; + emit availableChanged(); + } + if (!m_pollTimer->isActive()) { + m_pollTimer->start(); +} + return; + } + const auto connected = bus.connect( - QString(), + kLogin1Service, kLogin1Path, kDBusPropertiesInterface, "PropertiesChanged", From 0d8f558f6679239cecc62eef24f7123bacf0fdd7 Mon Sep 17 00:00:00 2001 From: AramJonghu Date: Wed, 3 Jun 2026 17:41:29 +0200 Subject: [PATCH 21/25] Took caelestia lid logic (prepare to sleep) instead --- Modules/Lock/IdleMonitors.qml | 4 + Modules/Lock/Lock.qml | 8 -- Plugins/ZShell/CMakeLists.txt | 1 - Plugins/ZShell/Internal/CMakeLists.txt | 1 + Plugins/ZShell/Internal/lidwatcher.cpp | 86 ++++++++++++++ Plugins/ZShell/Internal/lidwatcher.hpp | 27 +++++ Plugins/ZShell/lidwatcher.cpp | 148 ------------------------- Plugins/ZShell/lidwatcher.hpp | 50 --------- shell.qml | 12 -- 9 files changed, 118 insertions(+), 219 deletions(-) create mode 100644 Plugins/ZShell/Internal/lidwatcher.cpp create mode 100644 Plugins/ZShell/Internal/lidwatcher.hpp delete mode 100644 Plugins/ZShell/lidwatcher.cpp delete mode 100644 Plugins/ZShell/lidwatcher.hpp diff --git a/Modules/Lock/IdleMonitors.qml b/Modules/Lock/IdleMonitors.qml index 26b2854..647cf22 100644 --- a/Modules/Lock/IdleMonitors.qml +++ b/Modules/Lock/IdleMonitors.qml @@ -29,6 +29,10 @@ Scope { Quickshell.execDetached(action); } + LidWatcher { + onAboutToSleep: root.lock.lock.locked = true + } + Variants { model: Config.general.idle.timeouts diff --git a/Modules/Lock/Lock.qml b/Modules/Lock/Lock.qml index 5de21c6..68d8a46 100644 --- a/Modules/Lock/Lock.qml +++ b/Modules/Lock/Lock.qml @@ -9,7 +9,6 @@ import qs.Components Scope { id: root - required property var lid property alias lock: lock property int seenOnce: 0 @@ -22,13 +21,6 @@ Scope { onRequestLock: lock.locked = true onUnlock: lock.locked = false - Connections { - target: root.lid - function onRequestLock(): void { - lock.locked = true - } - } - LockSurface { id: lockSurface diff --git a/Plugins/ZShell/CMakeLists.txt b/Plugins/ZShell/CMakeLists.txt index 1e04ea7..f691bc9 100644 --- a/Plugins/ZShell/CMakeLists.txt +++ b/Plugins/ZShell/CMakeLists.txt @@ -45,7 +45,6 @@ qml_module(ZShell requests.hpp requests.cpp toaster.hpp toaster.cpp qalculator.hpp qalculator.cpp - lidwatcher.hpp lidwatcher.cpp LIBRARIES Qt::Gui Qt::Quick diff --git a/Plugins/ZShell/Internal/CMakeLists.txt b/Plugins/ZShell/Internal/CMakeLists.txt index dd353a3..93f1ca9 100644 --- a/Plugins/ZShell/Internal/CMakeLists.txt +++ b/Plugins/ZShell/Internal/CMakeLists.txt @@ -9,6 +9,7 @@ qml_module(ZShell-internal sparklineitem.hpp sparklineitem.cpp arcgauge.hpp arcgauge.cpp wallpaperimage.hpp wallpaperimage.cpp + lidwatcher.hpp lidwatcher.cpp LIBRARIES Qt::Gui Qt::Quick diff --git a/Plugins/ZShell/Internal/lidwatcher.cpp b/Plugins/ZShell/Internal/lidwatcher.cpp new file mode 100644 index 0000000..b6a8773 --- /dev/null +++ b/Plugins/ZShell/Internal/lidwatcher.cpp @@ -0,0 +1,86 @@ +#include "lidwatcher.hpp" + +#include +#include +#include +#include +#include + +Q_LOGGING_CATEGORY(lcLidWatcher, "caelestia.internal.logindmanager", QtInfoMsg) + +namespace ZShell::internal { + +LidWatcher::LidWatcher(QObject* parent) : QObject(parent) { + auto bus = QDBusConnection::systemBus(); + if (!bus.isConnected()) { + qCWarning(lcLidWatcher) + << "Failed to connect to system bus:" << bus.lastError().message(); + return; + } + + bool ok = bus.connect("org.freedesktop.login1", + "/org/freedesktop/login1", + "org.freedesktop.login1.Manager", + "PrepareForSleep", + this, + SLOT(handlePrepareForSleep(bool))); + + if (!ok) { + qCWarning(lcLidWatcher) + << "Failed to connect to PrepareForSleep signal:" + << bus.lastError().message(); + } + + QDBusInterface login1("org.freedesktop.login1", + "/org/freedesktop/login1", + "org.freedesktop.login1.Manager", + bus); + const QDBusReply reply = login1.call("GetSession", "auto"); + if (!reply.isValid()) { + qCWarning(lcLidWatcher) << "Failed to get session path"; + return; + } + const auto sessionPath = reply.value().path(); + + ok = bus.connect("org.freedesktop.login1", + sessionPath, + "org.freedesktop.login1.Session", + "Lock", + this, + SLOT(handleLockRequested())); + + if (!ok) { + qCWarning(lcLidWatcher) + << "Failed to connect to Lock signal:" << bus.lastError().message(); + } + + ok = bus.connect("org.freedesktop.login1", + sessionPath, + "org.freedesktop.login1.Session", + "Unlock", + this, + SLOT(handleUnlockRequested())); + + if (!ok) { + qCWarning(lcLidWatcher) << "Failed to connect to Unlock signal:" + << bus.lastError().message(); + } +} + +void LidWatcher::handlePrepareForSleep(bool sleep) { + if (sleep) { + emit aboutToSleep(); + } else { + emit resumed(); + } +} + +void LidWatcher::handleLockRequested() { + emit lockRequested(); +} + +void LidWatcher::handleUnlockRequested() { + emit unlockRequested(); +} + +} // namespace ZShell::internal diff --git a/Plugins/ZShell/Internal/lidwatcher.hpp b/Plugins/ZShell/Internal/lidwatcher.hpp new file mode 100644 index 0000000..6a6f4dc --- /dev/null +++ b/Plugins/ZShell/Internal/lidwatcher.hpp @@ -0,0 +1,27 @@ +#pragma once + +#include +#include + +namespace ZShell::internal { + +class LidWatcher : public QObject { + Q_OBJECT + QML_ELEMENT + + public: + explicit LidWatcher(QObject* parent = nullptr); + + signals: + void aboutToSleep(); + void resumed(); + void lockRequested(); + void unlockRequested(); + + private slots: + void handlePrepareForSleep(bool sleep); + void handleLockRequested(); + void handleUnlockRequested(); +}; + +} // namespace ZShell::internal diff --git a/Plugins/ZShell/lidwatcher.cpp b/Plugins/ZShell/lidwatcher.cpp deleted file mode 100644 index 7a6105f..0000000 --- a/Plugins/ZShell/lidwatcher.cpp +++ /dev/null @@ -1,148 +0,0 @@ -#include "lidwatcher.hpp" - -#include -#include -#include -#include -#include -#include -#include - -Q_LOGGING_CATEGORY(lcLidWatcher, "ZShell.lidwatcher", QtInfoMsg) - -namespace ZShell { - -static constexpr auto kLogin1Service = "org.freedesktop.login1"; -static constexpr auto kLogin1Path = "/org/freedesktop/login1"; -static constexpr auto kLogin1Interface = "org.freedesktop.login1.Manager"; -static constexpr auto kDBusPropertiesInterface = - "org.freedesktop.DBus.Properties"; - -LidWatcher::LidWatcher(QObject* parent) - : QObject(parent) - , m_watcher(nullptr) - , m_pollTimer(nullptr) - , m_available(false) -{ - QDBusConnection bus = QDBusConnection::systemBus(); - if (!bus.isConnected()) { - qCWarning(lcLidWatcher) << "system bus unavailable"; - emit availableChanged(); - return; - } - - m_pollTimer = new QTimer(this); - m_pollTimer->setInterval(5000); - connect(m_pollTimer, &QTimer::timeout, this, &LidWatcher::queryLidState); - - m_watcher = new QDBusServiceWatcher( - kLogin1Service, - bus, - QDBusServiceWatcher::WatchForRegistration, - this); - connect(m_watcher, &QDBusServiceWatcher::serviceRegistered, - this, &LidWatcher::tryConnect); - - tryConnect(); -} - -bool LidWatcher::available() const { - return m_available; -} - -LidWatcher::LidState LidWatcher::state() const { - return m_state; -} - -void LidWatcher::tryConnect() { - QDBusConnection bus = QDBusConnection::systemBus(); - - const auto iface = bus.interface(); - if (!iface) { - queryLidState(); - if (!m_available) { - m_available = true; - emit availableChanged(); - } - if (!m_pollTimer->isActive()) { - m_pollTimer->start(); -} - return; - } - const auto reply = iface->isServiceRegistered(kLogin1Service); - if (!reply.isValid() || !reply.value()) { - queryLidState(); - qCInfo(lcLidWatcher) << "login1 not available, polling"; - if (!m_available) { - m_available = true; - emit availableChanged(); - } - if (!m_pollTimer->isActive()) { - m_pollTimer->start(); -} - return; - } - - const auto connected = bus.connect( - kLogin1Service, - kLogin1Path, - kDBusPropertiesInterface, - "PropertiesChanged", - this, - SLOT(onPropertiesChanged(QString, QVariantMap, QStringList))); - - queryLidState(); - - if (connected) { - m_pollTimer->stop(); - qCInfo(lcLidWatcher) << "login1 PropertiesChanged connected"; - } else { - qCWarning(lcLidWatcher) - << "login1 PropertiesChanged unavailable, polling"; - if (!m_pollTimer->isActive()) { - m_pollTimer->start(); -} - } - - if (!m_available) { - m_available = true; - emit availableChanged(); - } -} - -void LidWatcher::queryLidState() { - auto msg = QDBusMessage::createMethodCall(kLogin1Service, - kLogin1Path, - kDBusPropertiesInterface, - "Get"); - msg << kLogin1Interface << "LidClosed"; - const QDBusReply reply = QDBusConnection::systemBus().call(msg); - if (!reply.isValid()) { - qCWarning(lcLidWatcher) - << "cannot query LidClosed:" << reply.error().message(); - return; - } - const auto newState = reply.value().toBool() ? Closed : Opened; - if (m_state != newState) { - m_state = newState; - emit stateChanged(); - } -} - -void LidWatcher::onPropertiesChanged(const QString& interface, - const QVariantMap& changed, - const QStringList& ) { - if (interface != kLogin1Interface) { - return; - } - if (!changed.contains("LidClosed")) { - return; - } - const auto newState = changed.value("LidClosed").toBool() ? Closed : Opened; - if (m_state != newState) { - m_state = newState; - emit stateChanged(); - } -} - -} // namespace ZShell diff --git a/Plugins/ZShell/lidwatcher.hpp b/Plugins/ZShell/lidwatcher.hpp deleted file mode 100644 index ec74ca1..0000000 --- a/Plugins/ZShell/lidwatcher.hpp +++ /dev/null @@ -1,50 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include - -class QDBusServiceWatcher; -class QTimer; - -namespace ZShell { - -class LidWatcher : public QObject { - Q_OBJECT - QML_ELEMENT - QML_SINGLETON - - Q_PROPERTY(bool available READ available NOTIFY availableChanged) - Q_PROPERTY(LidState state READ state NOTIFY stateChanged) - - public: - enum LidState : std::uint8_t{ Opened, Closed }; - Q_ENUM(LidState) - - explicit LidWatcher(QObject* parent = nullptr); - - [[nodiscard]] bool available() const; - [[nodiscard]] LidState state() const; - - private: - void tryConnect(); - void queryLidState(); - - QDBusServiceWatcher* m_watcher; - QTimer* m_pollTimer; - bool m_available; - LidState m_state = Opened; - - private Q_SLOTS: - void onPropertiesChanged(const QString& interface, - const QVariantMap& changed, - const QStringList& invalidated); - - Q_SIGNALS: - void availableChanged(); - void stateChanged(); -}; - -} // namespace ZShell diff --git a/shell.qml b/shell.qml index 9063f58..83a43ab 100644 --- a/shell.qml +++ b/shell.qml @@ -35,8 +35,6 @@ ShellRoot { Lock { id: lock - - lid: lid } Shortcuts { @@ -49,16 +47,6 @@ ShellRoot { Polkit { } - LazyLoader { - id: lid - - activeAsync: Config.lock.lidWatch && Battery.isLaptop - - component: LidService { - onRequestLock: lock.lock.requestLock() - } - } - LazyLoader { activeAsync: root.laptop From a19701222b31bcdf4e260ded0c9dd9f2f2a0ffd2 Mon Sep 17 00:00:00 2001 From: AramJonghu Date: Wed, 3 Jun 2026 17:43:58 +0200 Subject: [PATCH 22/25] forgotton import and removal LidService --- Daemons/LidService.qml | 18 ------------------ Modules/Lock/IdleMonitors.qml | 1 + 2 files changed, 1 insertion(+), 18 deletions(-) delete mode 100644 Daemons/LidService.qml diff --git a/Daemons/LidService.qml b/Daemons/LidService.qml deleted file mode 100644 index 0a8fe79..0000000 --- a/Daemons/LidService.qml +++ /dev/null @@ -1,18 +0,0 @@ -import Quickshell -import ZShell -import QtQuick - -Scope { - id: root - - signal requestLock - - Connections { - function onStateChanged(): void { - if (LidWatcher.state === LidWatcher.Closed) - root.requestLock(); - } - - target: LidWatcher - } -} diff --git a/Modules/Lock/IdleMonitors.qml b/Modules/Lock/IdleMonitors.qml index 647cf22..ccd95dc 100644 --- a/Modules/Lock/IdleMonitors.qml +++ b/Modules/Lock/IdleMonitors.qml @@ -2,6 +2,7 @@ pragma ComponentBehavior: Bound import Quickshell import Quickshell.Wayland +import ZShell.internal import qs.Config import qs.Helpers From 6f856e2162607e1857e52fcc106f79b2bbefe754 Mon Sep 17 00:00:00 2001 From: AramJonghu Date: Wed, 3 Jun 2026 17:47:12 +0200 Subject: [PATCH 23/25] fix typo --- Modules/Lock/IdleMonitors.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/Lock/IdleMonitors.qml b/Modules/Lock/IdleMonitors.qml index ccd95dc..a26cceb 100644 --- a/Modules/Lock/IdleMonitors.qml +++ b/Modules/Lock/IdleMonitors.qml @@ -2,7 +2,7 @@ pragma ComponentBehavior: Bound import Quickshell import Quickshell.Wayland -import ZShell.internal +import ZShell.Internal import qs.Config import qs.Helpers From a128c0fa404cfef9b9fc6265533cd7b1b650eae6 Mon Sep 17 00:00:00 2001 From: AramJonghu Date: Wed, 3 Jun 2026 17:59:03 +0200 Subject: [PATCH 24/25] removal reduntant config option and settings, unused lines in Lock.qml --- Config/Config.qml | 1 - Config/LockConf.qml | 1 - Modules/Lock/Lock.qml | 3 --- Modules/Settings/Categories/Lockscreen.qml | 11 ----------- scripts/SettingsIndex.mjs | 7 ------- 5 files changed, 23 deletions(-) diff --git a/Config/Config.qml b/Config/Config.qml index b2a541e..272e6b2 100644 --- a/Config/Config.qml +++ b/Config/Config.qml @@ -253,7 +253,6 @@ Singleton { return { recolorLogo: lock.recolorLogo, enableFprint: lock.enableFprint, - lidWatch: lock.lidWatch, showNotifContent: lock.showNotifContent, showNotifIcon: lock.showNotifIcon, maxFprintTries: lock.maxFprintTries, diff --git a/Config/LockConf.qml b/Config/LockConf.qml index 3826a90..87a4f4e 100644 --- a/Config/LockConf.qml +++ b/Config/LockConf.qml @@ -4,7 +4,6 @@ JsonObject { property int blurAmount: 40 property bool enableFprint: true property int maxFprintTries: 3 - property bool lidWatch: false property bool recolorLogo: false property bool showNotifContent: false property bool showNotifIcon: true diff --git a/Modules/Lock/Lock.qml b/Modules/Lock/Lock.qml index 68d8a46..9c6f8df 100644 --- a/Modules/Lock/Lock.qml +++ b/Modules/Lock/Lock.qml @@ -18,9 +18,6 @@ Scope { signal requestLock signal unlock - onRequestLock: lock.locked = true - onUnlock: lock.locked = false - LockSurface { id: lockSurface diff --git a/Modules/Settings/Categories/Lockscreen.qml b/Modules/Settings/Categories/Lockscreen.qml index ae45f8d..adfa74c 100644 --- a/Modules/Settings/Categories/Lockscreen.qml +++ b/Modules/Settings/Categories/Lockscreen.qml @@ -60,17 +60,6 @@ SettingsPage { Separator { } - SettingSwitch { - name: "Laptop lid watch to lock session" - object: Config.lock - setting: "lidWatch" - shouldBeActive: Battery.isLaptop - } - - Separator { - shouldBeActive: Battery.isLaptop - } - SettingSpinBox { min: 0 name: "Blur amount" diff --git a/scripts/SettingsIndex.mjs b/scripts/SettingsIndex.mjs index 9d2c870..ba5eaed 100644 --- a/scripts/SettingsIndex.mjs +++ b/scripts/SettingsIndex.mjs @@ -326,13 +326,6 @@ export const settingsIndex = [ section: "Lockscreen", keywords: ["notification", "hide", "icon"], }, - { - name: "Laptop lid watch to lock session", - category: "lockscreen", - categoryName: "Lockscreen", - section: "Lockscreen", - keywords: ["lid", "lock", "watch", "session", "laptop"], - }, { name: "Blur amount", category: "lockscreen", From 59789ab8d30c825b8480e59a60f0cb6575fdd354 Mon Sep 17 00:00:00 2001 From: AramJonghu Date: Wed, 3 Jun 2026 18:01:10 +0200 Subject: [PATCH 25/25] unused imports in shell.qml --- shell.qml | 2 -- 1 file changed, 2 deletions(-) diff --git a/shell.qml b/shell.qml index 83a43ab..c5c5b7f 100644 --- a/shell.qml +++ b/shell.qml @@ -7,13 +7,11 @@ //@ pragma DropExpensiveFonts import Quickshell import Quickshell.Services.UPower -import QtQuick import qs.Modules import qs.Modules.Wallpaper import qs.Modules.Lock import qs.Drawers import qs.Helpers -import qs.Config import qs.Modules.Polkit import qs.Daemons