diff --git a/src/dbus/CMakeLists.txt b/src/dbus/CMakeLists.txt index fc004f3d..e5ca75e5 100644 --- a/src/dbus/CMakeLists.txt +++ b/src/dbus/CMakeLists.txt @@ -7,6 +7,11 @@ set_source_files_properties(org.freedesktop.DBus.ObjectManager.xml PROPERTIES INCLUDE ${CMAKE_CURRENT_SOURCE_DIR}/dbus_objectmanager_types.hpp ) +set_source_files_properties(org.quickshell.SessionLock.xml PROPERTIES + CLASSNAME SessionLockAdaptor + INCLUDE session_lock_dbus.hpp +) + qt_add_dbus_interface(DBUS_INTERFACES org.freedesktop.DBus.Properties.xml dbus_properties @@ -17,20 +22,26 @@ qt_add_dbus_interface(DBUS_INTERFACES dbus_objectmanager ) +qt_add_dbus_adaptor(DBUS_INTERFACES + org.quickshell.SessionLock.xml + ${CMAKE_CURRENT_SOURCE_DIR}/session_lock_dbus.hpp + qs::dbus::SessionLockAdaptor +) + qt_add_library(quickshell-dbus STATIC properties.cpp objectmanager.cpp bus.cpp + session_lock_dbus.cpp ${DBUS_INTERFACES} ) # dbus headers target_include_directories(quickshell-dbus PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) - target_link_libraries(quickshell-dbus PRIVATE Qt::Core Qt::DBus) + # todo: link dbus to quickshell here instead of in modules that use it directly # linker does not like this as is - qs_add_pchset(dbus DEPENDENCIES Qt::DBus HEADERS diff --git a/src/dbus/objectmanager.hpp b/src/dbus/objectmanager.hpp index 4246ea28..ea88d499 100644 --- a/src/dbus/objectmanager.hpp +++ b/src/dbus/objectmanager.hpp @@ -34,4 +34,4 @@ class DBusObjectManager: public QObject { DBusObjectManagerInterface* mInterface = nullptr; }; -} // namespace qs::dbus \ No newline at end of file +} // namespace qs::dbus diff --git a/src/dbus/org.quickshell.SessionLock.xml b/src/dbus/org.quickshell.SessionLock.xml new file mode 100644 index 00000000..3b5c477c --- /dev/null +++ b/src/dbus/org.quickshell.SessionLock.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/dbus/session_lock_dbus.cpp b/src/dbus/session_lock_dbus.cpp new file mode 100644 index 00000000..9bb57d37 --- /dev/null +++ b/src/dbus/session_lock_dbus.cpp @@ -0,0 +1,66 @@ +#include "session_lock_dbus.hpp" + +#include +#include +#include +#include +#include +#include +#include + +#include "../core/logcat.hpp" + +namespace { +QS_LOGGING_CATEGORY(logDbusSessionLock, "quickshell.dbus.sessionlock", QtWarningMsg); +} + +namespace qs::dbus { + +SessionLockAdaptor::SessionLockAdaptor(QObject* parent): QDBusAbstractAdaptor(parent) { + // Register on session bus + auto connection = QDBusConnection::sessionBus(); + + if (!connection.registerService("org.quickshell.SessionLock")) { + qCWarning(logDbusSessionLock) << "Failed to register DBus service org.quickshell.SessionLock:" + << connection.lastError().message(); + } else { + qCInfo(logDbusSessionLock) << "Registered DBus service org.quickshell.SessionLock"; + } + + if (!connection + .registerObject("/org/quickshell/SessionLock", parent, QDBusConnection::ExportAdaptors)) + { + qCWarning(logDbusSessionLock) << "Failed to register DBus object /org/quickshell/SessionLock:" + << connection.lastError().message(); + } else { + qCInfo(logDbusSessionLock) << "Registered DBus object /org/quickshell/SessionLock"; + } +} + +void SessionLockAdaptor::setLocked(bool locked) { + if (this->mLocked != locked) { + this->mLocked = locked; + qCDebug(logDbusSessionLock) << "Lock state changed to:" << locked; + emit this->LockedChanged(locked); + } +} + +void SessionLockAdaptor::setSecure(bool secure) { + if (this->mSecure != secure) { + this->mSecure = secure; + qCDebug(logDbusSessionLock) << "Secure state changed to:" << secure; + emit this->SecureChanged(secure); + } +} + +bool SessionLockAdaptor::GetLocked() const { + qCDebug(logDbusSessionLock) << "GetLocked called, returning:" << this->mLocked; + return this->mLocked; +} + +bool SessionLockAdaptor::GetSecure() const { + qCDebug(logDbusSessionLock) << "GetSecure called, returning:" << this->mSecure; + return this->mSecure; +} + +} // namespace qs::dbus diff --git a/src/dbus/session_lock_dbus.hpp b/src/dbus/session_lock_dbus.hpp new file mode 100644 index 00000000..46aca932 --- /dev/null +++ b/src/dbus/session_lock_dbus.hpp @@ -0,0 +1,33 @@ +#pragma once +#include +#include +#include + +namespace qs::dbus { + +class SessionLockAdaptor: public QDBusAbstractAdaptor { + Q_OBJECT; + Q_CLASSINFO("D-Bus Interface", "org.quickshell.SessionLock") + +public: + explicit SessionLockAdaptor(QObject* parent); + ~SessionLockAdaptor() override = default; + Q_DISABLE_COPY_MOVE(SessionLockAdaptor); + + void setLocked(bool locked); + void setSecure(bool secure); + +public slots: + [[nodiscard]] bool GetLocked() const; // NOLINT(readability-identifier-naming) + [[nodiscard]] bool GetSecure() const; // NOLINT(readability-identifier-naming) + +signals: + void LockedChanged(bool locked); // NOLINT(readability-identifier-naming) + void SecureChanged(bool secure); // NOLINT(readability-identifier-naming) + +private: + bool mLocked = false; + bool mSecure = false; +}; + +} // namespace qs::dbus diff --git a/src/wayland/session_lock/CMakeLists.txt b/src/wayland/session_lock/CMakeLists.txt index d157fc13..a73dc8b0 100644 --- a/src/wayland/session_lock/CMakeLists.txt +++ b/src/wayland/session_lock/CMakeLists.txt @@ -5,14 +5,12 @@ qt_add_library(quickshell-wayland-sessionlock STATIC shell_integration.cpp session_lock.cpp ) - wl_proto(wlp-session-lock ext-session-lock-v1 "${WAYLAND_PROTOCOLS}/staging/ext-session-lock") - +target_include_directories(quickshell-wayland-sessionlock PRIVATE ${CMAKE_SOURCE_DIR}/src) target_link_libraries(quickshell-wayland-sessionlock PRIVATE - Qt::Quick Qt::WaylandClient Qt::WaylandClientPrivate wayland-client + Qt::Quick Qt::WaylandClient Qt::WaylandClientPrivate Qt::DBus wayland-client wlp-session-lock + quickshell-dbus ) - qs_pch(quickshell-wayland-sessionlock SET large) - target_link_libraries(quickshell-wayland PRIVATE quickshell-wayland-sessionlock) diff --git a/src/wayland/session_lock/session_lock.cpp b/src/wayland/session_lock/session_lock.cpp index c32dd90a..32bd287b 100644 --- a/src/wayland/session_lock/session_lock.cpp +++ b/src/wayland/session_lock/session_lock.cpp @@ -3,14 +3,17 @@ #include #include #include +#include #include +#include "../../dbus/session_lock_dbus.hpp" #include "lock.hpp" #include "manager.hpp" #include "shell_integration.hpp" #include "surface.hpp" namespace { + QSWaylandSessionLockManager* manager() { static QSWaylandSessionLockManager* manager = nullptr; // NOLINT @@ -20,33 +23,59 @@ QSWaylandSessionLockManager* manager() { return manager; } + } // namespace +SessionLockManager::SessionLockManager(QObject* parent) + : QObject(parent) + , mDbusAdaptor(new qs::dbus::SessionLockAdaptor(this)) { + // DBus adaptor initialized in member initializer list so the service is always available +} + bool SessionLockManager::lockAvailable() { return manager()->isActive(); } bool SessionLockManager::lock() { if (this->isLocked() || SessionLockManager::sessionLocked()) return false; + this->mLock = manager()->acquireLock(); this->mLock->setParent(this); + // Notify DBus that we're attempting to lock (not yet secure) + this->mDbusAdaptor->setLocked(true); + this->mDbusAdaptor->setSecure(false); + // clang-format off - QObject::connect(this->mLock, &QSWaylandSessionLock::compositorLocked, this, &SessionLockManager::locked); - QObject::connect(this->mLock, &QSWaylandSessionLock::unlocked, this, &SessionLockManager::unlocked); + QObject::connect(this->mLock, &QSWaylandSessionLock::compositorLocked, this, [this]() { + this->mDbusAdaptor->setSecure(true); + emit this->locked(); + }); + + QObject::connect(this->mLock, &QSWaylandSessionLock::unlocked, this, [this]() { + this->mDbusAdaptor->setLocked(false); + this->mDbusAdaptor->setSecure(false); + emit this->unlocked(); + }); // clang-format on + return true; } bool SessionLockManager::unlock() { if (!this->isLocked()) return false; + this->mLock->unlock(); + auto* lock = this->mLock; this->mLock = nullptr; delete lock; + return true; } bool SessionLockManager::isLocked() const { return this->mLock != nullptr; } + bool SessionLockManager::sessionLocked() { return manager()->isLocked(); } + bool SessionLockManager::isSecure() { return manager()->isSecure(); } LockWindowExtension::~LockWindowExtension() { @@ -83,14 +112,17 @@ bool LockWindowExtension::attach(QWindow* window, SessionLockManager* manager) { window->setScreen(screen); waylandWindow = dynamic_cast(window->handle()); + if (waylandWindow == nullptr) { qWarning() << window << "is not a wayland window. Cannot create lock surface."; return false; } static QSWaylandSessionLockIntegration* lockIntegration = nullptr; // NOLINT + if (lockIntegration == nullptr) { lockIntegration = new QSWaylandSessionLockIntegration(); + if (!lockIntegration->initialize(waylandWindow->display())) { delete lockIntegration; lockIntegration = nullptr; @@ -103,6 +135,7 @@ bool LockWindowExtension::attach(QWindow* window, SessionLockManager* manager) { this->setParent(window); window->setProperty("sessionlock_ext", QVariant::fromValue(this)); + this->lock = manager->mLock; if (waylandWindow != nullptr) { diff --git a/src/wayland/session_lock/session_lock.hpp b/src/wayland/session_lock/session_lock.hpp index 5a558966..80002533 100644 --- a/src/wayland/session_lock/session_lock.hpp +++ b/src/wayland/session_lock/session_lock.hpp @@ -1,5 +1,4 @@ #pragma once - #include #include #include @@ -9,11 +8,15 @@ class QSWaylandSessionLock; class QSWaylandSessionLockSurface; class QSWaylandSessionLockIntegration; +namespace qs::dbus { +class SessionLockAdaptor; +} + class SessionLockManager: public QObject { Q_OBJECT; public: - explicit SessionLockManager(QObject* parent = nullptr): QObject(parent) {} + explicit SessionLockManager(QObject* parent = nullptr); // Declare only, implement in .cpp [[nodiscard]] static bool lockAvailable(); @@ -46,11 +49,9 @@ class SessionLockManager: public QObject { // After receiving this event the caller should destroy all of its lock surfaces. void unlocked(); -private slots: - //void onUnlocked(); - private: QSWaylandSessionLock* mLock = nullptr; + qs::dbus::SessionLockAdaptor* mDbusAdaptor = nullptr; friend class LockWindowExtension; };