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(
 | 
			
		||||
	COMMAND pkg-config --variable=pkgdatadir wayland-protocols
 | 
			
		||||
	OUTPUT_VARIABLE WAYLAND_PROTOCOLS_DIR
 | 
			
		||||
	OUTPUT_VARIABLE WAYLAND_PROTOCOLS
 | 
			
		||||
	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_subdirectory(wlr_layershell)
 | 
			
		||||
add_subdirectory(session_lock)
 | 
			
		||||
target_link_libraries(quickshell-wayland 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