forked from quickshell/quickshell
		
	feat(slock): add user facing SessionLock and SessionLockSurface
This commit is contained in:
		
							parent
							
								
									1fa87b7c5a
								
							
						
					
					
						commit
						48bdcf4db2
					
				
					 10 changed files with 458 additions and 14 deletions
				
			
		| 
						 | 
				
			
			@ -134,8 +134,10 @@ void ProxyWindowBase::setScreen(QuickshellScreenInfo* screen) {
 | 
			
		|||
		QObject::connect(qscreen, &QObject::destroyed, this, &ProxyWindowBase::onScreenDestroyed);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (this->window == nullptr) this->mScreen = qscreen;
 | 
			
		||||
	else this->window->setScreen(qscreen);
 | 
			
		||||
	if (this->window == nullptr) {
 | 
			
		||||
		this->mScreen = qscreen;
 | 
			
		||||
		emit this->screenChanged();
 | 
			
		||||
	} else this->window->setScreen(qscreen);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ProxyWindowBase::onScreenDestroyed() { this->mScreen = nullptr; }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -46,6 +46,7 @@ endfunction()
 | 
			
		|||
 | 
			
		||||
qt_add_library(quickshell-wayland STATIC
 | 
			
		||||
	wlr_layershell.cpp
 | 
			
		||||
	session_lock.cpp
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
qt_add_qml_module(quickshell-wayland URI Quickshell.Wayland)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,5 +3,6 @@ description = "Wayland specific Quickshell types"
 | 
			
		|||
headers = [
 | 
			
		||||
	"wlr_layershell/window.hpp",
 | 
			
		||||
	"wlr_layershell.hpp",
 | 
			
		||||
	"session_lock.hpp",
 | 
			
		||||
]
 | 
			
		||||
-----
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										284
									
								
								src/wayland/session_lock.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										284
									
								
								src/wayland/session_lock.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,284 @@
 | 
			
		|||
#include "session_lock.hpp"
 | 
			
		||||
 | 
			
		||||
#include <qcolor.h>
 | 
			
		||||
#include <qguiapplication.h>
 | 
			
		||||
#include <qlogging.h>
 | 
			
		||||
#include <qobject.h>
 | 
			
		||||
#include <qqmlcomponent.h>
 | 
			
		||||
#include <qqmlengine.h>
 | 
			
		||||
#include <qquickitem.h>
 | 
			
		||||
#include <qquickwindow.h>
 | 
			
		||||
#include <qscreen.h>
 | 
			
		||||
#include <qtmetamacros.h>
 | 
			
		||||
#include <qtypes.h>
 | 
			
		||||
 | 
			
		||||
#include "session_lock/session_lock.hpp"
 | 
			
		||||
 | 
			
		||||
void SessionLock::onReload(QObject* oldInstance) {
 | 
			
		||||
	auto* old = qobject_cast<SessionLock*>(oldInstance);
 | 
			
		||||
 | 
			
		||||
	if (old != nullptr) {
 | 
			
		||||
		QObject::disconnect(old->manager, nullptr, old, nullptr);
 | 
			
		||||
		this->manager = old->manager;
 | 
			
		||||
		this->manager->setParent(this);
 | 
			
		||||
	} else {
 | 
			
		||||
		this->manager = new SessionLockManager(this);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// clang-format off
 | 
			
		||||
	QObject::connect(this->manager, &SessionLockManager::locked, this, &SessionLock::secureStateChanged);
 | 
			
		||||
	QObject::connect(this->manager, &SessionLockManager::unlocked, this, &SessionLock::secureStateChanged);
 | 
			
		||||
 | 
			
		||||
	QObject::connect(this->manager, &SessionLockManager::unlocked, this, &SessionLock::unlock);
 | 
			
		||||
 | 
			
		||||
	auto* app = QCoreApplication::instance();
 | 
			
		||||
	auto* guiApp = qobject_cast<QGuiApplication*>(app);
 | 
			
		||||
 | 
			
		||||
	if (guiApp != nullptr) {
 | 
			
		||||
		QObject::connect(guiApp, &QGuiApplication::primaryScreenChanged, this, &SessionLock::onScreensChanged);
 | 
			
		||||
		QObject::connect(guiApp, &QGuiApplication::screenAdded, this, &SessionLock::onScreensChanged);
 | 
			
		||||
		QObject::connect(guiApp, &QGuiApplication::screenRemoved, this, &SessionLock::onScreensChanged);
 | 
			
		||||
	}
 | 
			
		||||
	// clang-format on
 | 
			
		||||
 | 
			
		||||
	if (this->lockTarget) {
 | 
			
		||||
		this->manager->lock();
 | 
			
		||||
		this->updateSurfaces(old);
 | 
			
		||||
	} else {
 | 
			
		||||
		this->setLocked(false);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SessionLock::updateSurfaces(SessionLock* old) {
 | 
			
		||||
	if (this->manager->isLocked()) {
 | 
			
		||||
		auto screens = QGuiApplication::screens();
 | 
			
		||||
 | 
			
		||||
		auto map = this->surfaces.toStdMap();
 | 
			
		||||
		for (auto& [screen, surface]: map) {
 | 
			
		||||
			if (!screens.contains(screen)) {
 | 
			
		||||
				this->surfaces.remove(screen);
 | 
			
		||||
				surface->deleteLater();
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (this->mSurfaceComponent == nullptr) {
 | 
			
		||||
			qWarning() << "SessionLock.surface is null. Aborting lock.";
 | 
			
		||||
			this->unlock();
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		for (auto* screen: screens) {
 | 
			
		||||
			if (!this->surfaces.contains(screen)) {
 | 
			
		||||
				auto* instanceObj = this->mSurfaceComponent->create(QQmlEngine::contextForObject(this));
 | 
			
		||||
				auto* instance = qobject_cast<SessionLockSurface*>(instanceObj);
 | 
			
		||||
 | 
			
		||||
				if (instance == nullptr) {
 | 
			
		||||
					qWarning() << "SessionLock.surface does not create a SessionLockSurface. Aborting lock.";
 | 
			
		||||
					this->unlock();
 | 
			
		||||
					return;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				instance->setParent(this);
 | 
			
		||||
				instance->setScreen(screen);
 | 
			
		||||
 | 
			
		||||
				auto* oldInstance = old == nullptr ? nullptr : old->surfaces.value(screen, nullptr);
 | 
			
		||||
				instance->onReload(oldInstance);
 | 
			
		||||
 | 
			
		||||
				this->surfaces[screen] = instance;
 | 
			
		||||
				instance->show();
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SessionLock::unlock() {
 | 
			
		||||
	if (this->isLocked()) {
 | 
			
		||||
		this->lockTarget = false;
 | 
			
		||||
		this->manager->unlock();
 | 
			
		||||
 | 
			
		||||
		for (auto* surface: this->surfaces) {
 | 
			
		||||
			surface->deleteLater();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		this->surfaces.clear();
 | 
			
		||||
 | 
			
		||||
		emit this->lockStateChanged();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SessionLock::onScreensChanged() { this->updateSurfaces(); }
 | 
			
		||||
 | 
			
		||||
bool SessionLock::isLocked() const {
 | 
			
		||||
	return this->manager == nullptr ? this->lockTarget : this->manager->isLocked();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool SessionLock::isSecure() const {
 | 
			
		||||
	return this->manager != nullptr && SessionLockManager::sessionLocked();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SessionLock::setLocked(bool locked) {
 | 
			
		||||
	if (this->isLocked() == locked) return;
 | 
			
		||||
	this->lockTarget = locked;
 | 
			
		||||
 | 
			
		||||
	if (this->manager == nullptr) {
 | 
			
		||||
		emit this->lockStateChanged();
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (locked) {
 | 
			
		||||
		this->manager->lock();
 | 
			
		||||
		this->updateSurfaces();
 | 
			
		||||
		if (this->lockTarget) emit this->lockStateChanged();
 | 
			
		||||
	} else {
 | 
			
		||||
		this->unlock(); // emits lockStateChanged
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QQmlComponent* SessionLock::surfaceComponent() const { return this->mSurfaceComponent; }
 | 
			
		||||
 | 
			
		||||
void SessionLock::rip() {
 | 
			
		||||
	if (this->isLocked()) {
 | 
			
		||||
		exit(1);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SessionLock::setSurfaceComponent(QQmlComponent* surfaceComponent) {
 | 
			
		||||
	if (this->mSurfaceComponent != nullptr) this->mSurfaceComponent->deleteLater();
 | 
			
		||||
	if (surfaceComponent != nullptr) surfaceComponent->setParent(this);
 | 
			
		||||
 | 
			
		||||
	this->mSurfaceComponent = surfaceComponent;
 | 
			
		||||
	emit this->surfaceComponentChanged();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SessionLockSurface::SessionLockSurface(QObject* parent)
 | 
			
		||||
    : Reloadable(parent)
 | 
			
		||||
    , mContentItem(new QQuickItem())
 | 
			
		||||
    , ext(new LockWindowExtension(this)) {
 | 
			
		||||
	this->mContentItem->setParent(this);
 | 
			
		||||
 | 
			
		||||
	// clang-format off
 | 
			
		||||
	QObject::connect(this, &SessionLockSurface::widthChanged, this, &SessionLockSurface::onWidthChanged);
 | 
			
		||||
	QObject::connect(this, &SessionLockSurface::heightChanged, this, &SessionLockSurface::onHeightChanged);
 | 
			
		||||
	// clang-format on
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SessionLockSurface::~SessionLockSurface() {
 | 
			
		||||
	if (this->window != nullptr) {
 | 
			
		||||
		this->window->deleteLater();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SessionLockSurface::onReload(QObject* oldInstance) {
 | 
			
		||||
	if (auto* old = qobject_cast<SessionLockSurface*>(oldInstance)) {
 | 
			
		||||
		this->window = old->disownWindow();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (this->window == nullptr) {
 | 
			
		||||
		this->window = new QQuickWindow();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	this->mContentItem->setParentItem(this->window->contentItem());
 | 
			
		||||
 | 
			
		||||
	this->mContentItem->setWidth(this->width());
 | 
			
		||||
	this->mContentItem->setHeight(this->height());
 | 
			
		||||
 | 
			
		||||
	if (this->mScreen != nullptr) this->window->setScreen(this->mScreen);
 | 
			
		||||
	this->window->setColor(this->mColor);
 | 
			
		||||
 | 
			
		||||
	// clang-format off
 | 
			
		||||
	QObject::connect(this->window, &QWindow::visibilityChanged, this, &SessionLockSurface::visibleChanged);
 | 
			
		||||
	QObject::connect(this->window, &QWindow::widthChanged, this, &SessionLockSurface::widthChanged);
 | 
			
		||||
	QObject::connect(this->window, &QWindow::heightChanged, this, &SessionLockSurface::heightChanged);
 | 
			
		||||
	QObject::connect(this->window, &QWindow::screenChanged, this, &SessionLockSurface::screenChanged);
 | 
			
		||||
	QObject::connect(this->window, &QQuickWindow::colorChanged, this, &SessionLockSurface::colorChanged);
 | 
			
		||||
	// clang-format on
 | 
			
		||||
 | 
			
		||||
	if (auto* parent = qobject_cast<SessionLock*>(this->parent())) {
 | 
			
		||||
		if (!this->ext->attach(window, parent->manager)) {
 | 
			
		||||
			qWarning(
 | 
			
		||||
			) << "Failed to attach LockWindowExtension to window. Surface will not behave correctly.";
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		qWarning(
 | 
			
		||||
		) << "SessionLockSurface parent is not a SessionLock. Surface will not behave correctly.";
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// without this the dangling screen pointer wont be updated to a real screen
 | 
			
		||||
	emit this->screenChanged();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QQuickWindow* SessionLockSurface::disownWindow() {
 | 
			
		||||
	QObject::disconnect(this->window, nullptr, this, nullptr);
 | 
			
		||||
	this->mContentItem->setParentItem(nullptr);
 | 
			
		||||
 | 
			
		||||
	auto* window = this->window;
 | 
			
		||||
	this->window = nullptr;
 | 
			
		||||
	return window;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SessionLockSurface::show() { this->ext->setVisible(); }
 | 
			
		||||
 | 
			
		||||
QQuickItem* SessionLockSurface::contentItem() const { return this->mContentItem; }
 | 
			
		||||
 | 
			
		||||
bool SessionLockSurface::isVisible() const { return this->window->isVisible(); }
 | 
			
		||||
 | 
			
		||||
qint32 SessionLockSurface::width() const {
 | 
			
		||||
	if (this->window == nullptr) return 0;
 | 
			
		||||
	else return this->window->width();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
qint32 SessionLockSurface::height() const {
 | 
			
		||||
	if (this->window == nullptr) return 0;
 | 
			
		||||
	else return this->window->height();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QuickshellScreenInfo* SessionLockSurface::screen() const {
 | 
			
		||||
	QScreen* qscreen = nullptr;
 | 
			
		||||
 | 
			
		||||
	if (this->window == nullptr) {
 | 
			
		||||
		if (this->mScreen != nullptr) qscreen = this->mScreen;
 | 
			
		||||
	} else {
 | 
			
		||||
		qscreen = this->window->screen();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return new QuickshellScreenInfo(
 | 
			
		||||
	    const_cast<SessionLockSurface*>(this), // NOLINT
 | 
			
		||||
	    qscreen
 | 
			
		||||
	);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SessionLockSurface::setScreen(QScreen* qscreen) {
 | 
			
		||||
	if (this->mScreen != nullptr) {
 | 
			
		||||
		QObject::disconnect(this->mScreen, nullptr, this, nullptr);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (qscreen != nullptr) {
 | 
			
		||||
		QObject::connect(qscreen, &QObject::destroyed, this, &SessionLockSurface::onScreenDestroyed);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (this->window == nullptr) {
 | 
			
		||||
		this->mScreen = qscreen;
 | 
			
		||||
		emit this->screenChanged();
 | 
			
		||||
	} else this->window->setScreen(qscreen);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SessionLockSurface::onScreenDestroyed() { this->mScreen = nullptr; }
 | 
			
		||||
 | 
			
		||||
QColor SessionLockSurface::color() const {
 | 
			
		||||
	if (this->window == nullptr) return this->mColor;
 | 
			
		||||
	else return this->window->color();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SessionLockSurface::setColor(QColor color) {
 | 
			
		||||
	if (this->window == nullptr) {
 | 
			
		||||
		this->mColor = color;
 | 
			
		||||
		emit this->colorChanged();
 | 
			
		||||
	} else this->window->setColor(color);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QQmlListProperty<QObject> SessionLockSurface::data() {
 | 
			
		||||
	return this->mContentItem->property("data").value<QQmlListProperty<QObject>>();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SessionLockSurface::onWidthChanged() { this->mContentItem->setWidth(this->width()); }
 | 
			
		||||
void SessionLockSurface::onHeightChanged() { this->mContentItem->setHeight(this->height()); }
 | 
			
		||||
							
								
								
									
										151
									
								
								src/wayland/session_lock.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										151
									
								
								src/wayland/session_lock.hpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,151 @@
 | 
			
		|||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <qcolor.h>
 | 
			
		||||
#include <qcontainerfwd.h>
 | 
			
		||||
#include <qguiapplication.h>
 | 
			
		||||
#include <qmap.h>
 | 
			
		||||
#include <qnamespace.h>
 | 
			
		||||
#include <qobject.h>
 | 
			
		||||
#include <qqmlcomponent.h>
 | 
			
		||||
#include <qqmlintegration.h>
 | 
			
		||||
#include <qquickitem.h>
 | 
			
		||||
#include <qquickwindow.h>
 | 
			
		||||
#include <qscreen.h>
 | 
			
		||||
#include <qtclasshelpermacros.h>
 | 
			
		||||
#include <qtmetamacros.h>
 | 
			
		||||
#include <qtypes.h>
 | 
			
		||||
 | 
			
		||||
#include "../core/doc.hpp"
 | 
			
		||||
#include "../core/qmlscreen.hpp"
 | 
			
		||||
#include "../core/reload.hpp"
 | 
			
		||||
#include "session_lock/session_lock.hpp"
 | 
			
		||||
 | 
			
		||||
class SessionLockSurface;
 | 
			
		||||
 | 
			
		||||
/// Note: Very untested. Do anything outside of the obvious use cases and you WILL red screen.
 | 
			
		||||
class SessionLock: public Reloadable {
 | 
			
		||||
	Q_OBJECT;
 | 
			
		||||
	// clang-format off
 | 
			
		||||
	/// Note: only one SessionLock may be locked at a time.
 | 
			
		||||
	Q_PROPERTY(bool locked READ isLocked WRITE setLocked NOTIFY lockStateChanged);
 | 
			
		||||
	/// Returns the *compositor* lock state, which will only be set to true after all surfaces are in place.
 | 
			
		||||
	Q_PROPERTY(bool secure READ isSecure NOTIFY secureStateChanged);
 | 
			
		||||
	/// Component that will be instantiated for each screen. Must be a `SessionLockSurface`.
 | 
			
		||||
	Q_PROPERTY(QQmlComponent* surface READ surfaceComponent WRITE setSurfaceComponent NOTIFY surfaceComponentChanged);
 | 
			
		||||
	// clang-format on
 | 
			
		||||
	QML_ELEMENT;
 | 
			
		||||
	Q_CLASSINFO("DefaultProperty", "surface");
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
	explicit SessionLock(QObject* parent = nullptr): Reloadable(parent) {}
 | 
			
		||||
 | 
			
		||||
	void onReload(QObject* oldInstance) override;
 | 
			
		||||
 | 
			
		||||
	[[nodiscard]] bool isLocked() const;
 | 
			
		||||
	void setLocked(bool locked);
 | 
			
		||||
 | 
			
		||||
	[[nodiscard]] bool isSecure() const;
 | 
			
		||||
 | 
			
		||||
	[[nodiscard]] QQmlComponent* surfaceComponent() const;
 | 
			
		||||
	void setSurfaceComponent(QQmlComponent* surfaceComponent);
 | 
			
		||||
 | 
			
		||||
	QSDOC_HIDE Q_INVOKABLE void rip();
 | 
			
		||||
 | 
			
		||||
signals:
 | 
			
		||||
	void lockStateChanged();
 | 
			
		||||
	void secureStateChanged();
 | 
			
		||||
	void surfaceComponentChanged();
 | 
			
		||||
 | 
			
		||||
private slots:
 | 
			
		||||
	void unlock();
 | 
			
		||||
	void onScreensChanged();
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	void updateSurfaces(SessionLock* old = nullptr);
 | 
			
		||||
 | 
			
		||||
	SessionLockManager* manager = nullptr;
 | 
			
		||||
	QQmlComponent* mSurfaceComponent = nullptr;
 | 
			
		||||
	QMap<QScreen*, SessionLockSurface*> surfaces;
 | 
			
		||||
	bool lockTarget = false;
 | 
			
		||||
 | 
			
		||||
	friend class SessionLockSurface;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class SessionLockSurface: public Reloadable {
 | 
			
		||||
	Q_OBJECT;
 | 
			
		||||
	// clang-format off
 | 
			
		||||
	Q_PROPERTY(QQuickItem* contentItem READ contentItem);
 | 
			
		||||
	/// If the window has been presented yet.
 | 
			
		||||
	Q_PROPERTY(bool visible READ isVisible NOTIFY visibleChanged);
 | 
			
		||||
	Q_PROPERTY(qint32 width READ width NOTIFY widthChanged);
 | 
			
		||||
	Q_PROPERTY(qint32 height READ height NOTIFY heightChanged);
 | 
			
		||||
	/// The screen that the window currently occupies.
 | 
			
		||||
	///
 | 
			
		||||
	/// > [!INFO] This cannot be changed after windowConnected.
 | 
			
		||||
	Q_PROPERTY(QuickshellScreenInfo* screen READ screen NOTIFY screenChanged);
 | 
			
		||||
	/// The background color of the window. Defaults to white.
 | 
			
		||||
	///
 | 
			
		||||
	/// > [!WARNING] This seems to behave weirdly when using transparent colors on some systems.
 | 
			
		||||
	/// > Using a colored content item over a transparent window is the recommended way to work around this:
 | 
			
		||||
	/// > ```qml
 | 
			
		||||
	/// > ProxyWindow {
 | 
			
		||||
	/// >   Rectangle {
 | 
			
		||||
	/// >     anchors.fill: parent
 | 
			
		||||
	/// >     color: "#20ffffff"
 | 
			
		||||
	/// >
 | 
			
		||||
	/// >     // your content here
 | 
			
		||||
	/// >   }
 | 
			
		||||
	/// > }
 | 
			
		||||
	/// > ```
 | 
			
		||||
	/// > ... but you probably shouldn't make a transparent lock,
 | 
			
		||||
	/// > and most compositors will ignore an attempt to do so.
 | 
			
		||||
	Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged);
 | 
			
		||||
	Q_PROPERTY(QQmlListProperty<QObject> data READ data);
 | 
			
		||||
	// clang-format on
 | 
			
		||||
	QML_ELEMENT;
 | 
			
		||||
	Q_CLASSINFO("DefaultProperty", "data");
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
	explicit SessionLockSurface(QObject* parent = nullptr);
 | 
			
		||||
	~SessionLockSurface() override;
 | 
			
		||||
	Q_DISABLE_COPY_MOVE(SessionLockSurface);
 | 
			
		||||
 | 
			
		||||
	void onReload(QObject* oldInstance) override;
 | 
			
		||||
	QQuickWindow* disownWindow();
 | 
			
		||||
 | 
			
		||||
	void show();
 | 
			
		||||
 | 
			
		||||
	[[nodiscard]] QQuickItem* contentItem() const;
 | 
			
		||||
 | 
			
		||||
	[[nodiscard]] bool isVisible() const;
 | 
			
		||||
 | 
			
		||||
	[[nodiscard]] qint32 width() const;
 | 
			
		||||
	[[nodiscard]] qint32 height() const;
 | 
			
		||||
 | 
			
		||||
	[[nodiscard]] QuickshellScreenInfo* screen() const;
 | 
			
		||||
	void setScreen(QScreen* qscreen);
 | 
			
		||||
 | 
			
		||||
	[[nodiscard]] QColor color() const;
 | 
			
		||||
	void setColor(QColor color);
 | 
			
		||||
 | 
			
		||||
	[[nodiscard]] QQmlListProperty<QObject> data();
 | 
			
		||||
 | 
			
		||||
signals:
 | 
			
		||||
	void visibleChanged();
 | 
			
		||||
	void widthChanged();
 | 
			
		||||
	void heightChanged();
 | 
			
		||||
	void screenChanged();
 | 
			
		||||
	void colorChanged();
 | 
			
		||||
 | 
			
		||||
private slots:
 | 
			
		||||
	void onScreenDestroyed();
 | 
			
		||||
	void onWidthChanged();
 | 
			
		||||
	void onHeightChanged();
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	QQuickWindow* window = nullptr;
 | 
			
		||||
	QQuickItem* mContentItem;
 | 
			
		||||
	QScreen* mScreen = nullptr;
 | 
			
		||||
	QColor mColor = Qt::white;
 | 
			
		||||
	LockWindowExtension* ext;
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -17,10 +17,10 @@ QSWaylandSessionLock::~QSWaylandSessionLock() { this->unlock(); }
 | 
			
		|||
 | 
			
		||||
void QSWaylandSessionLock::unlock() {
 | 
			
		||||
	if (this->isInitialized()) {
 | 
			
		||||
		if (this->locked) this->unlock_and_destroy();
 | 
			
		||||
		else this->destroy();
 | 
			
		||||
		if (this->finished) this->destroy();
 | 
			
		||||
		else this->unlock_and_destroy();
 | 
			
		||||
 | 
			
		||||
		this->locked = false;
 | 
			
		||||
		this->secure = false;
 | 
			
		||||
		this->manager->active = nullptr;
 | 
			
		||||
 | 
			
		||||
		emit this->unlocked();
 | 
			
		||||
| 
						 | 
				
			
			@ -29,14 +29,15 @@ void QSWaylandSessionLock::unlock() {
 | 
			
		|||
 | 
			
		||||
bool QSWaylandSessionLock::active() const { return this->isInitialized(); }
 | 
			
		||||
 | 
			
		||||
bool QSWaylandSessionLock::hasCompositorLock() const { return this->locked; }
 | 
			
		||||
bool QSWaylandSessionLock::hasCompositorLock() const { return this->secure; }
 | 
			
		||||
 | 
			
		||||
void QSWaylandSessionLock::ext_session_lock_v1_locked() {
 | 
			
		||||
	this->locked = true;
 | 
			
		||||
	this->secure = true;
 | 
			
		||||
	emit this->compositorLocked();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void QSWaylandSessionLock::ext_session_lock_v1_finished() {
 | 
			
		||||
	this->locked = false;
 | 
			
		||||
	this->secure = false;
 | 
			
		||||
	this->finished = true;
 | 
			
		||||
	this->unlock();
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -34,5 +34,6 @@ private:
 | 
			
		|||
	QSWaylandSessionLockManager* manager; // static and not dealloc'd
 | 
			
		||||
 | 
			
		||||
	// true when the compositor determines the session is locked
 | 
			
		||||
	bool locked = false;
 | 
			
		||||
	bool secure = false;
 | 
			
		||||
	bool finished = false;
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -21,7 +21,7 @@ static QSWaylandSessionLockManager* manager() {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
bool SessionLockManager::lock() {
 | 
			
		||||
	if (SessionLockManager::sessionLocked()) return false;
 | 
			
		||||
	if (this->isLocked() || SessionLockManager::sessionLocked()) return false;
 | 
			
		||||
	this->mLock = manager()->acquireLock();
 | 
			
		||||
	this->mLock->setParent(this);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -13,7 +13,7 @@ class SessionLockManager: public QObject {
 | 
			
		|||
	Q_OBJECT;
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
	SessionLockManager(QObject* parent = nullptr): QObject(parent) {}
 | 
			
		||||
	explicit SessionLockManager(QObject* parent = nullptr): QObject(parent) {}
 | 
			
		||||
	Q_DISABLE_COPY_MOVE(SessionLockManager);
 | 
			
		||||
 | 
			
		||||
	// Returns true if a lock was acquired.
 | 
			
		||||
| 
						 | 
				
			
			@ -57,7 +57,7 @@ class LockWindowExtension: public QObject {
 | 
			
		|||
	Q_OBJECT;
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
	LockWindowExtension(QObject* parent = nullptr): QObject(parent) {}
 | 
			
		||||
	explicit LockWindowExtension(QObject* parent = nullptr): QObject(parent) {}
 | 
			
		||||
	~LockWindowExtension() override;
 | 
			
		||||
 | 
			
		||||
	// Attach this lock extension to the given window.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -40,7 +40,10 @@ QSWaylandSessionLockSurface::QSWaylandSessionLockSurface(QtWaylandClient::QWayla
 | 
			
		|||
	this->init(this->ext->lock->get_lock_surface(window->waylandSurface()->object(), output));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QSWaylandSessionLockSurface::~QSWaylandSessionLockSurface() { this->destroy(); }
 | 
			
		||||
QSWaylandSessionLockSurface::~QSWaylandSessionLockSurface() {
 | 
			
		||||
	if (this->ext != nullptr) this->ext->surface = nullptr;
 | 
			
		||||
	this->destroy();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool QSWaylandSessionLockSurface::isExposed() const { return this->configured; }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -60,7 +63,7 @@ bool QSWaylandSessionLockSurface::handleExpose(const QRegion& region) {
 | 
			
		|||
 | 
			
		||||
void QSWaylandSessionLockSurface::setExtension(LockWindowExtension* ext) {
 | 
			
		||||
	if (ext == nullptr) {
 | 
			
		||||
		this->window()->window()->close();
 | 
			
		||||
		if (this->window() != nullptr) this->window()->window()->close();
 | 
			
		||||
	} else {
 | 
			
		||||
		if (this->ext != nullptr) {
 | 
			
		||||
			this->ext->surface = nullptr;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue