lid behavior watcher to lock session #115
@@ -29,6 +29,10 @@ Scope {
|
||||
Quickshell.execDetached(action);
|
||||
}
|
||||
|
||||
LidWatcher {
|
||||
onAboutToSleep: root.lock.lock.locked = true
|
||||
}
|
||||
|
||||
Variants {
|
||||
model: Config.general.idle.timeouts
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
#include "lidwatcher.hpp"
|
||||
|
||||
#include <QtDBus/qdbusconnection.h>
|
||||
#include <QtDBus/qdbuserror.h>
|
||||
#include <QtDBus/qdbusinterface.h>
|
||||
#include <QtDBus/qdbusreply.h>
|
||||
#include <qloggingcategory.h>
|
||||
|
||||
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<QDBusObjectPath> 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
|
||||
@@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
|
||||
#include <qobject.h>
|
||||
#include <qqmlintegration.h>
|
||||
|
||||
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
|
||||
@@ -1,148 +0,0 @@
|
||||
#include "lidwatcher.hpp"
|
||||
|
||||
#include <QtDBus/QDBusConnection>
|
||||
#include <QtDBus/QDBusConnectionInterface>
|
||||
#include <QtDBus/QDBusMessage>
|
||||
#include <QtDBus/QDBusReply>
|
||||
#include <QtDBus/QDBusServiceWatcher>
|
||||
#include <QLoggingCategory>
|
||||
#include <QTimer>
|
||||
|
||||
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<QVariant> 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
|
||||
@@ -1,50 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
#include <QStringList>
|
||||
#include <QVariantMap>
|
||||
#include <cstdint>
|
||||
#include <qqmlintegration.h>
|
||||
|
||||
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
|
||||
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user