forked from quickshell/quickshell
		
	feat(slock): implement ext_session_lock_v1 backend
note: did not run lints or fully test yet
This commit is contained in:
		
							parent
							
								
									70c5cf1e16
								
							
						
					
					
						commit
						1fa87b7c5a
					
				
					 12 changed files with 525 additions and 1 deletions
				
			
		| 
						 | 
					@ -22,7 +22,7 @@ message(STATUS "Found wayland-scanner at ${waylandscanner}")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
execute_process(
 | 
					execute_process(
 | 
				
			||||||
	COMMAND pkg-config --variable=pkgdatadir wayland-protocols
 | 
						COMMAND pkg-config --variable=pkgdatadir wayland-protocols
 | 
				
			||||||
	OUTPUT_VARIABLE WAYLAND_PROTOCOLS_DIR
 | 
						OUTPUT_VARIABLE WAYLAND_PROTOCOLS
 | 
				
			||||||
	OUTPUT_STRIP_TRAILING_WHITESPACE
 | 
						OUTPUT_STRIP_TRAILING_WHITESPACE
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -54,6 +54,7 @@ qt_add_qml_module(quickshell-wayland URI Quickshell.Wayland)
 | 
				
			||||||
add_library(quickshell-wayland-init OBJECT init.cpp)
 | 
					add_library(quickshell-wayland-init OBJECT init.cpp)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
add_subdirectory(wlr_layershell)
 | 
					add_subdirectory(wlr_layershell)
 | 
				
			||||||
 | 
					add_subdirectory(session_lock)
 | 
				
			||||||
target_link_libraries(quickshell-wayland PRIVATE ${QT_DEPS})
 | 
					target_link_libraries(quickshell-wayland PRIVATE ${QT_DEPS})
 | 
				
			||||||
target_link_libraries(quickshell-wayland-init PRIVATE ${QT_DEPS})
 | 
					target_link_libraries(quickshell-wayland-init PRIVATE ${QT_DEPS})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										12
									
								
								src/wayland/session_lock/CMakeLists.txt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/wayland/session_lock/CMakeLists.txt
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,12 @@
 | 
				
			||||||
 | 
					qt_add_library(quickshell-wayland-sessionlock STATIC
 | 
				
			||||||
 | 
						manager.cpp
 | 
				
			||||||
 | 
						surface.cpp
 | 
				
			||||||
 | 
						lock.cpp
 | 
				
			||||||
 | 
						shell_integration.cpp
 | 
				
			||||||
 | 
						session_lock.cpp
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					wl_proto(quickshell-wayland-sessionlock ext-session-lock-v1 "${WAYLAND_PROTOCOLS}/staging/ext-session-lock/ext-session-lock-v1.xml")
 | 
				
			||||||
 | 
					target_link_libraries(quickshell-wayland-sessionlock PRIVATE ${QT_DEPS} wayland-client)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					target_link_libraries(quickshell-wayland PRIVATE quickshell-wayland-sessionlock)
 | 
				
			||||||
							
								
								
									
										42
									
								
								src/wayland/session_lock/lock.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								src/wayland/session_lock/lock.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,42 @@
 | 
				
			||||||
 | 
					#include "lock.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <private/qwaylandshellintegration_p.h>
 | 
				
			||||||
 | 
					#include <qtmetamacros.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "manager.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					QSWaylandSessionLock::QSWaylandSessionLock(
 | 
				
			||||||
 | 
					    QSWaylandSessionLockManager* manager,
 | 
				
			||||||
 | 
					    ::ext_session_lock_v1* lock
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					    : manager(manager) {
 | 
				
			||||||
 | 
						this->init(lock); // if isInitialized is false that means we already unlocked.
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					QSWaylandSessionLock::~QSWaylandSessionLock() { this->unlock(); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void QSWaylandSessionLock::unlock() {
 | 
				
			||||||
 | 
						if (this->isInitialized()) {
 | 
				
			||||||
 | 
							if (this->locked) this->unlock_and_destroy();
 | 
				
			||||||
 | 
							else this->destroy();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							this->locked = false;
 | 
				
			||||||
 | 
							this->manager->active = nullptr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							emit this->unlocked();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool QSWaylandSessionLock::active() const { return this->isInitialized(); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool QSWaylandSessionLock::hasCompositorLock() const { return this->locked; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void QSWaylandSessionLock::ext_session_lock_v1_locked() {
 | 
				
			||||||
 | 
						this->locked = true;
 | 
				
			||||||
 | 
						emit this->compositorLocked();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void QSWaylandSessionLock::ext_session_lock_v1_finished() {
 | 
				
			||||||
 | 
						this->locked = false;
 | 
				
			||||||
 | 
						this->unlock();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										38
									
								
								src/wayland/session_lock/lock.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								src/wayland/session_lock/lock.hpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,38 @@
 | 
				
			||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <qobject.h>
 | 
				
			||||||
 | 
					#include <qtclasshelpermacros.h>
 | 
				
			||||||
 | 
					#include <qwayland-ext-session-lock-v1.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class QSWaylandSessionLockManager;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class QSWaylandSessionLock
 | 
				
			||||||
 | 
					    : public QObject
 | 
				
			||||||
 | 
					    , public QtWayland::ext_session_lock_v1 {
 | 
				
			||||||
 | 
						Q_OBJECT;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						QSWaylandSessionLock(QSWaylandSessionLockManager* manager, ::ext_session_lock_v1* lock);
 | 
				
			||||||
 | 
						~QSWaylandSessionLock() override;
 | 
				
			||||||
 | 
						Q_DISABLE_COPY_MOVE(QSWaylandSessionLock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void unlock();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Returns true if the lock has not finished.
 | 
				
			||||||
 | 
						[[nodiscard]] bool active() const;
 | 
				
			||||||
 | 
						// Returns true if the compositor considers the session to be locked.
 | 
				
			||||||
 | 
						[[nodiscard]] bool hasCompositorLock() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					signals:
 | 
				
			||||||
 | 
						void compositorLocked();
 | 
				
			||||||
 | 
						void unlocked();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
						void ext_session_lock_v1_locked() override;
 | 
				
			||||||
 | 
						void ext_session_lock_v1_finished() override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						QSWaylandSessionLockManager* manager; // static and not dealloc'd
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// true when the compositor determines the session is locked
 | 
				
			||||||
 | 
						bool locked = false;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
							
								
								
									
										22
									
								
								src/wayland/session_lock/manager.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								src/wayland/session_lock/manager.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,22 @@
 | 
				
			||||||
 | 
					#include "manager.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <qdebug.h>
 | 
				
			||||||
 | 
					#include <qlogging.h>
 | 
				
			||||||
 | 
					#include <qwaylandclientextension.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "lock.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					QSWaylandSessionLockManager::QSWaylandSessionLockManager()
 | 
				
			||||||
 | 
					    : QWaylandClientExtensionTemplate<QSWaylandSessionLockManager>(1) {
 | 
				
			||||||
 | 
						this->initialize();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					QSWaylandSessionLockManager::~QSWaylandSessionLockManager() { this->destroy(); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					QSWaylandSessionLock* QSWaylandSessionLockManager::acquireLock() {
 | 
				
			||||||
 | 
						if (this->isLocked()) return nullptr;
 | 
				
			||||||
 | 
						this->active = new QSWaylandSessionLock(this, this->lock());
 | 
				
			||||||
 | 
						return this->active;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool QSWaylandSessionLockManager::isLocked() const { return this->active != nullptr; }
 | 
				
			||||||
							
								
								
									
										27
									
								
								src/wayland/session_lock/manager.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								src/wayland/session_lock/manager.hpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,27 @@
 | 
				
			||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <qtclasshelpermacros.h>
 | 
				
			||||||
 | 
					#include <qwayland-ext-session-lock-v1.h>
 | 
				
			||||||
 | 
					#include <qwaylandclientextension.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "lock.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class QSWaylandSessionLockManager
 | 
				
			||||||
 | 
					    : public QWaylandClientExtensionTemplate<QSWaylandSessionLockManager>
 | 
				
			||||||
 | 
					    , public QtWayland::ext_session_lock_manager_v1 {
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						QSWaylandSessionLockManager();
 | 
				
			||||||
 | 
						~QSWaylandSessionLockManager() override;
 | 
				
			||||||
 | 
						Q_DISABLE_COPY_MOVE(QSWaylandSessionLockManager);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Create a new session lock if there is no currently active lock, otherwise null.
 | 
				
			||||||
 | 
						QSWaylandSessionLock* acquireLock();
 | 
				
			||||||
 | 
						[[nodiscard]] bool isLocked() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static bool sessionLocked();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
						QSWaylandSessionLock* active = nullptr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						friend class QSWaylandSessionLock;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
							
								
								
									
										107
									
								
								src/wayland/session_lock/session_lock.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										107
									
								
								src/wayland/session_lock/session_lock.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,107 @@
 | 
				
			||||||
 | 
					#include "session_lock.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <private/qwaylanddisplay_p.h>
 | 
				
			||||||
 | 
					#include <qlogging.h>
 | 
				
			||||||
 | 
					#include <qobject.h>
 | 
				
			||||||
 | 
					#include <qwindow.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "lock.hpp"
 | 
				
			||||||
 | 
					#include "manager.hpp"
 | 
				
			||||||
 | 
					#include "shell_integration.hpp"
 | 
				
			||||||
 | 
					#include "surface.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static QSWaylandSessionLockManager* manager() {
 | 
				
			||||||
 | 
						static QSWaylandSessionLockManager* manager = nullptr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (manager == nullptr) {
 | 
				
			||||||
 | 
							manager = new QSWaylandSessionLockManager();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return manager;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool SessionLockManager::lock() {
 | 
				
			||||||
 | 
						if (SessionLockManager::sessionLocked()) return false;
 | 
				
			||||||
 | 
						this->mLock = manager()->acquireLock();
 | 
				
			||||||
 | 
						this->mLock->setParent(this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// clang-format off
 | 
				
			||||||
 | 
						QObject::connect(this->mLock, &QSWaylandSessionLock::compositorLocked, this, &SessionLockManager::locked);
 | 
				
			||||||
 | 
						QObject::connect(this->mLock, &QSWaylandSessionLock::unlocked, this, &SessionLockManager::unlocked);
 | 
				
			||||||
 | 
						// clang-format on
 | 
				
			||||||
 | 
						return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool SessionLockManager::unlock() {
 | 
				
			||||||
 | 
						if (!this->isLocked()) return false;
 | 
				
			||||||
 | 
						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(); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					LockWindowExtension::~LockWindowExtension() {
 | 
				
			||||||
 | 
						if (this->surface != nullptr) {
 | 
				
			||||||
 | 
							this->surface->setExtension(nullptr);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					LockWindowExtension* LockWindowExtension::get(QWindow* window) {
 | 
				
			||||||
 | 
						auto v = window->property("sessionlock_ext");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (v.canConvert<LockWindowExtension*>()) {
 | 
				
			||||||
 | 
							return v.value<LockWindowExtension*>();
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							return nullptr;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool LockWindowExtension::attach(QWindow* window, SessionLockManager* manager) {
 | 
				
			||||||
 | 
						if (this->surface != nullptr) throw "Cannot change the attached window of a LockWindowExtension";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						auto* current = LockWindowExtension::get(window);
 | 
				
			||||||
 | 
						QtWaylandClient::QWaylandWindow* waylandWindow = nullptr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (current != nullptr) {
 | 
				
			||||||
 | 
							current->surface->setExtension(this);
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							window->create();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							waylandWindow = dynamic_cast<QtWaylandClient::QWaylandWindow*>(window->handle());
 | 
				
			||||||
 | 
							if (waylandWindow == nullptr) {
 | 
				
			||||||
 | 
								qWarning() << window << "is not a wayland window. Cannot create lock surface.";
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							static QSWaylandSessionLockIntegration* lockIntegration = nullptr;
 | 
				
			||||||
 | 
							if (lockIntegration == nullptr) {
 | 
				
			||||||
 | 
								lockIntegration = new QSWaylandSessionLockIntegration();
 | 
				
			||||||
 | 
								if (!lockIntegration->initialize(waylandWindow->display())) {
 | 
				
			||||||
 | 
									delete lockIntegration;
 | 
				
			||||||
 | 
									lockIntegration = nullptr;
 | 
				
			||||||
 | 
									qWarning() << "Failed to initialize lockscreen integration";
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							waylandWindow->setShellIntegration(lockIntegration);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						this->setParent(window);
 | 
				
			||||||
 | 
						window->setProperty("sessionlock_ext", QVariant::fromValue(this));
 | 
				
			||||||
 | 
						this->lock = manager->mLock;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (waylandWindow != nullptr) {
 | 
				
			||||||
 | 
							this->surface = new QSWaylandSessionLockSurface(waylandWindow);
 | 
				
			||||||
 | 
							if (this->immediatelyVisible) this->surface->setVisible();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void LockWindowExtension::setVisible() {
 | 
				
			||||||
 | 
						if (this->surface == nullptr) immediatelyVisible = true;
 | 
				
			||||||
 | 
						else this->surface->setVisible();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										92
									
								
								src/wayland/session_lock/session_lock.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								src/wayland/session_lock/session_lock.hpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,92 @@
 | 
				
			||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <qobject.h>
 | 
				
			||||||
 | 
					#include <qtclasshelpermacros.h>
 | 
				
			||||||
 | 
					#include <qtmetamacros.h>
 | 
				
			||||||
 | 
					#include <qwindow.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class QSWaylandSessionLock;
 | 
				
			||||||
 | 
					class QSWaylandSessionLockSurface;
 | 
				
			||||||
 | 
					class QSWaylandSessionLockIntegration;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class SessionLockManager: public QObject {
 | 
				
			||||||
 | 
						Q_OBJECT;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						SessionLockManager(QObject* parent = nullptr): QObject(parent) {}
 | 
				
			||||||
 | 
						Q_DISABLE_COPY_MOVE(SessionLockManager);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Returns true if a lock was acquired.
 | 
				
			||||||
 | 
						// If true is returned the caller must watch the global screen list and create/destroy
 | 
				
			||||||
 | 
						// windows with an attached LockWindowExtension to match it.
 | 
				
			||||||
 | 
						bool lock();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Returns true if the session was locked and is now unlocked.
 | 
				
			||||||
 | 
						bool unlock();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						[[nodiscard]] bool isLocked() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static bool sessionLocked();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					signals:
 | 
				
			||||||
 | 
						// This signal is sent once the compositor considers the session to be fully locked.
 | 
				
			||||||
 | 
						// This corrosponds to the ext_session_lock_v1::locked event.
 | 
				
			||||||
 | 
						void locked();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// This signal is sent once the compositor considers the session to be unlocked.
 | 
				
			||||||
 | 
						// This corrosponds to the ext_session_lock_v1::finished event.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// The session lock will end in one of three cases.
 | 
				
			||||||
 | 
						// 1. unlock() is called.
 | 
				
			||||||
 | 
						// 2. The SessionLockManager is destroyed.
 | 
				
			||||||
 | 
						// 3. The compositor forcibly unlocks the session.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// After receiving this event the caller should destroy all of its lock surfaces.
 | 
				
			||||||
 | 
						void unlocked();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private slots:
 | 
				
			||||||
 | 
						//void onUnlocked();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
						QSWaylandSessionLock* mLock = nullptr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						friend class LockWindowExtension;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class LockWindowExtension: public QObject {
 | 
				
			||||||
 | 
						Q_OBJECT;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						LockWindowExtension(QObject* parent = nullptr): QObject(parent) {}
 | 
				
			||||||
 | 
						~LockWindowExtension() override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Attach this lock extension to the given window.
 | 
				
			||||||
 | 
						// The extension is reparented to the window and replaces any existing lock extension.
 | 
				
			||||||
 | 
						// Returns false if the window cannot be used.
 | 
				
			||||||
 | 
						bool attach(QWindow* window, SessionLockManager* manager);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// This must be called in place of QWindow::setVisible. Calling QWindow::setVisible will result in a crash.
 | 
				
			||||||
 | 
						// To make a window invisible, destroy it as it cannot be recovered.
 | 
				
			||||||
 | 
						void setVisible();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						[[nodiscard]] bool isLocked() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static LockWindowExtension* get(QWindow* window);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					signals:
 | 
				
			||||||
 | 
						// This signal is sent once the compositor considers the session to be fully locked.
 | 
				
			||||||
 | 
						// See SessionLockManager::locked for details.
 | 
				
			||||||
 | 
						void locked();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// After receiving this signal the window is no longer in use by the compositor
 | 
				
			||||||
 | 
						// and should be destroyed. See SessionLockManager::unlocked for details.
 | 
				
			||||||
 | 
						void unlocked();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
						QSWaylandSessionLockSurface* surface = nullptr;
 | 
				
			||||||
 | 
						QSWaylandSessionLock* lock = nullptr;
 | 
				
			||||||
 | 
						bool immediatelyVisible = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						friend class QSWaylandSessionLockSurface;
 | 
				
			||||||
 | 
						friend class QSWaylandSessionLockIntegration;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
							
								
								
									
										20
									
								
								src/wayland/session_lock/shell_integration.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								src/wayland/session_lock/shell_integration.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,20 @@
 | 
				
			||||||
 | 
					#include "shell_integration.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <private/qwaylandshellsurface_p.h>
 | 
				
			||||||
 | 
					#include <private/qwaylandwindow_p.h>
 | 
				
			||||||
 | 
					#include <qlogging.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "session_lock.hpp"
 | 
				
			||||||
 | 
					#include "surface.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					QtWaylandClient::QWaylandShellSurface*
 | 
				
			||||||
 | 
					QSWaylandSessionLockIntegration::createShellSurface(QtWaylandClient::QWaylandWindow* window) {
 | 
				
			||||||
 | 
						auto* lock = LockWindowExtension::get(window->window());
 | 
				
			||||||
 | 
						if (lock == nullptr || lock->surface == nullptr || !lock->surface->isExposed()) {
 | 
				
			||||||
 | 
							qFatal() << "Visibility canary failed. A window with a LockWindowExtension MUST be set to "
 | 
				
			||||||
 | 
							            "visible via LockWindowExtension::setVisible";
 | 
				
			||||||
 | 
							throw nullptr;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return lock->surface;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										13
									
								
								src/wayland/session_lock/shell_integration.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								src/wayland/session_lock/shell_integration.hpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,13 @@
 | 
				
			||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <private/qwaylanddisplay_p.h>
 | 
				
			||||||
 | 
					#include <private/qwaylandshellintegration_p.h>
 | 
				
			||||||
 | 
					#include <private/qwaylandshellsurface_p.h>
 | 
				
			||||||
 | 
					#include <private/qwaylandwindow_p.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class QSWaylandSessionLockIntegration: public QtWaylandClient::QWaylandShellIntegration {
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						bool initialize(QtWaylandClient::QWaylandDisplay* /* display */) override { return true; }
 | 
				
			||||||
 | 
						QtWaylandClient::QWaylandShellSurface* createShellSurface(QtWaylandClient::QWaylandWindow* window
 | 
				
			||||||
 | 
						) override;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
							
								
								
									
										111
									
								
								src/wayland/session_lock/surface.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										111
									
								
								src/wayland/session_lock/surface.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,111 @@
 | 
				
			||||||
 | 
					#include "surface.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <private/qwaylandscreen_p.h>
 | 
				
			||||||
 | 
					#include <private/qwaylandshellsurface_p.h>
 | 
				
			||||||
 | 
					#include <private/qwaylandshmbackingstore_p.h>
 | 
				
			||||||
 | 
					#include <private/qwaylandsurface_p.h>
 | 
				
			||||||
 | 
					#include <private/qwaylandwindow_p.h>
 | 
				
			||||||
 | 
					#include <qlogging.h>
 | 
				
			||||||
 | 
					#include <qobject.h>
 | 
				
			||||||
 | 
					#include <wayland-client-protocol.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "lock.hpp"
 | 
				
			||||||
 | 
					#include "session_lock.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					QSWaylandSessionLockSurface::QSWaylandSessionLockSurface(QtWaylandClient::QWaylandWindow* window)
 | 
				
			||||||
 | 
					    : QtWaylandClient::QWaylandShellSurface(window) {
 | 
				
			||||||
 | 
						auto* qwindow = window->window();
 | 
				
			||||||
 | 
						this->setExtension(LockWindowExtension::get(qwindow));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (this->ext == nullptr) {
 | 
				
			||||||
 | 
							qFatal() << "QSWaylandSessionLockSurface created with null LockWindowExtension";
 | 
				
			||||||
 | 
							throw nullptr;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (this->ext->lock == nullptr) {
 | 
				
			||||||
 | 
							qFatal() << "QSWaylandSessionLock for QSWaylandSessionLockSurface died";
 | 
				
			||||||
 | 
							throw nullptr;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						wl_output* output = nullptr;
 | 
				
			||||||
 | 
						auto* waylandScreen = dynamic_cast<QtWaylandClient::QWaylandScreen*>(qwindow->screen()->handle());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (waylandScreen != nullptr) {
 | 
				
			||||||
 | 
							output = waylandScreen->output();
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							qFatal() << "Session lock screen does not corrospond to a real screen. Force closing window";
 | 
				
			||||||
 | 
							throw nullptr;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						this->init(this->ext->lock->get_lock_surface(window->waylandSurface()->object(), output));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					QSWaylandSessionLockSurface::~QSWaylandSessionLockSurface() { this->destroy(); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool QSWaylandSessionLockSurface::isExposed() const { return this->configured; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void QSWaylandSessionLockSurface::applyConfigure() {
 | 
				
			||||||
 | 
						this->window()->resizeFromApplyConfigure(this->size);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool QSWaylandSessionLockSurface::handleExpose(const QRegion& region) {
 | 
				
			||||||
 | 
						if (this->initBuf != nullptr) {
 | 
				
			||||||
 | 
							// at this point qt's next commit to the surface will have a new buffer, and we can safely delete this one.
 | 
				
			||||||
 | 
							delete this->initBuf;
 | 
				
			||||||
 | 
							this->initBuf = nullptr;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return this->QtWaylandClient::QWaylandShellSurface::handleExpose(region);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void QSWaylandSessionLockSurface::setExtension(LockWindowExtension* ext) {
 | 
				
			||||||
 | 
						if (ext == nullptr) {
 | 
				
			||||||
 | 
							this->window()->window()->close();
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							if (this->ext != nullptr) {
 | 
				
			||||||
 | 
								this->ext->surface = nullptr;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							this->ext = ext;
 | 
				
			||||||
 | 
							this->ext->surface = this;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void QSWaylandSessionLockSurface::setVisible() {
 | 
				
			||||||
 | 
						if (this->configured && !this->visible) initVisible();
 | 
				
			||||||
 | 
						this->visible = true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void QSWaylandSessionLockSurface::ext_session_lock_surface_v1_configure(
 | 
				
			||||||
 | 
					    quint32 serial,
 | 
				
			||||||
 | 
					    quint32 width,
 | 
				
			||||||
 | 
					    quint32 height
 | 
				
			||||||
 | 
					) {
 | 
				
			||||||
 | 
						this->ack_configure(serial);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						this->size = QSize(static_cast<qint32>(width), static_cast<qint32>(height));
 | 
				
			||||||
 | 
						if (!this->configured) {
 | 
				
			||||||
 | 
							this->configured = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							this->window()->resizeFromApplyConfigure(this->size);
 | 
				
			||||||
 | 
							this->window()->handleExpose(QRect(QPoint(), this->size));
 | 
				
			||||||
 | 
							if (this->visible) initVisible();
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							this->window()->applyConfigureWhenPossible();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void QSWaylandSessionLockSurface::initVisible() {
 | 
				
			||||||
 | 
						this->visible = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// qt always commits a null buffer in QWaylandWindow::initWindow.
 | 
				
			||||||
 | 
						// We attach a dummy buffer to satisfy ext_session_lock_v1.
 | 
				
			||||||
 | 
						this->initBuf = new QtWaylandClient::QWaylandShmBuffer(
 | 
				
			||||||
 | 
						    this->window()->display(),
 | 
				
			||||||
 | 
						    size,
 | 
				
			||||||
 | 
						    QImage::Format_ARGB32
 | 
				
			||||||
 | 
						);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						this->window()->waylandSurface()->attach(initBuf->buffer(), 0, 0);
 | 
				
			||||||
 | 
						this->window()->window()->setVisible(true);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										39
									
								
								src/wayland/session_lock/surface.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								src/wayland/session_lock/surface.hpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,39 @@
 | 
				
			||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <private/qwaylandshellsurface_p.h>
 | 
				
			||||||
 | 
					#include <private/qwaylandshmbackingstore_p.h>
 | 
				
			||||||
 | 
					#include <private/qwaylandwindow_p.h>
 | 
				
			||||||
 | 
					#include <qregion.h>
 | 
				
			||||||
 | 
					#include <qtclasshelpermacros.h>
 | 
				
			||||||
 | 
					#include <qtypes.h>
 | 
				
			||||||
 | 
					#include <qwayland-ext-session-lock-v1.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "session_lock.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class QSWaylandSessionLockSurface
 | 
				
			||||||
 | 
					    : public QtWaylandClient::QWaylandShellSurface
 | 
				
			||||||
 | 
					    , public QtWayland::ext_session_lock_surface_v1 {
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						QSWaylandSessionLockSurface(QtWaylandClient::QWaylandWindow* window);
 | 
				
			||||||
 | 
						~QSWaylandSessionLockSurface() override;
 | 
				
			||||||
 | 
						Q_DISABLE_COPY_MOVE(QSWaylandSessionLockSurface);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						[[nodiscard]] bool isExposed() const override;
 | 
				
			||||||
 | 
						void applyConfigure() override;
 | 
				
			||||||
 | 
						bool handleExpose(const QRegion& region) override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void setExtension(LockWindowExtension*);
 | 
				
			||||||
 | 
						void setVisible();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
						void
 | 
				
			||||||
 | 
						ext_session_lock_surface_v1_configure(quint32 serial, quint32 width, quint32 height) override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void initVisible();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						LockWindowExtension* ext = nullptr;
 | 
				
			||||||
 | 
						QSize size;
 | 
				
			||||||
 | 
						bool configured = false;
 | 
				
			||||||
 | 
						bool visible = false;
 | 
				
			||||||
 | 
						QtWaylandClient::QWaylandShmBuffer* initBuf = nullptr;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue