Compare commits
9 commits
70c5cf1e16
...
42ea70e04c
Author | SHA1 | Date | |
---|---|---|---|
outfoxxed | 42ea70e04c | ||
outfoxxed | cdd5729642 | ||
outfoxxed | a255889e5c | ||
outfoxxed | b05d98b56d | ||
outfoxxed | 0b529c6682 | ||
outfoxxed | cbdfba1a3f | ||
outfoxxed | 4eac0b40c3 | ||
outfoxxed | 48bdcf4db2 | ||
outfoxxed | 1fa87b7c5a |
|
@ -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; }
|
||||
|
|
|
@ -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
|
||||
)
|
||||
|
||||
|
@ -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)
|
||||
|
@ -54,6 +55,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})
|
||||
|
||||
|
|
|
@ -3,5 +3,6 @@ description = "Wayland specific Quickshell types"
|
|||
headers = [
|
||||
"wlr_layershell/window.hpp",
|
||||
"wlr_layershell.hpp",
|
||||
"session_lock.hpp",
|
||||
]
|
||||
-----
|
||||
|
|
282
src/wayland/session_lock.cpp
Normal file
282
src/wayland/session_lock.cpp
Normal file
|
@ -0,0 +1,282 @@
|
|||
#include "session_lock.hpp"
|
||||
|
||||
#include <qcolor.h>
|
||||
#include <qcoreapplication.h>
|
||||
#include <qguiapplication.h>
|
||||
#include <qlogging.h>
|
||||
#include <qobject.h>
|
||||
#include <qqmlcomponent.h>
|
||||
#include <qqmlengine.h>
|
||||
#include <qqmllist.h>
|
||||
#include <qquickitem.h>
|
||||
#include <qquickwindow.h>
|
||||
#include <qscreen.h>
|
||||
#include <qtmetamacros.h>
|
||||
#include <qtypes.h>
|
||||
|
||||
#include "../core/qmlscreen.hpp"
|
||||
#include "../core/reload.hpp"
|
||||
#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) {
|
||||
if (!this->manager->lock()) this->lockTarget = false;
|
||||
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;
|
||||
}
|
||||
|
||||
for (auto* surface: this->surfaces.values()) {
|
||||
surface->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::isSecure();
|
||||
}
|
||||
|
||||
void SessionLock::setLocked(bool locked) {
|
||||
if (this->isLocked() == locked) return;
|
||||
this->lockTarget = locked;
|
||||
|
||||
if (this->manager == nullptr) {
|
||||
emit this->lockStateChanged();
|
||||
return;
|
||||
}
|
||||
|
||||
if (locked) {
|
||||
if (!this->manager->lock()) this->lockTarget = false;
|
||||
this->updateSurfaces();
|
||||
if (this->lockTarget) emit this->lockStateChanged();
|
||||
} else {
|
||||
this->unlock(); // emits lockStateChanged
|
||||
}
|
||||
}
|
||||
|
||||
QQmlComponent* SessionLock::surfaceComponent() const { return this->mSurfaceComponent; }
|
||||
|
||||
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(this->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.";
|
||||
}
|
||||
}
|
||||
|
||||
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()); }
|
191
src/wayland/session_lock.hpp
Normal file
191
src/wayland/session_lock.hpp
Normal file
|
@ -0,0 +1,191 @@
|
|||
#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/qmlscreen.hpp"
|
||||
#include "../core/reload.hpp"
|
||||
#include "session_lock/session_lock.hpp"
|
||||
|
||||
class SessionLockSurface;
|
||||
|
||||
///! Wayland session locker.
|
||||
/// Wayland session lock implemented using the [ext_session_lock_v1] protocol.
|
||||
///
|
||||
/// SessionLock will create an instance of its `surface` component for every screen when
|
||||
/// `locked` is set to true. The `surface` component must create a [SessionLockSurface]
|
||||
/// which will be displayed on each screen.
|
||||
///
|
||||
/// The below example will create a session lock that disappears when the button is clicked.
|
||||
/// ```qml
|
||||
/// SessionLock {
|
||||
/// id: lock
|
||||
///
|
||||
/// SessionLockSurface {
|
||||
/// Button {
|
||||
/// text: "unlock me"
|
||||
/// onClicked: lock.locked = false
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// // ...
|
||||
/// lock.locked = true
|
||||
/// ```
|
||||
///
|
||||
/// > [!WARNING] If the SessionLock is destroyed or quickshell exits without setting `locked`
|
||||
/// > to false, conformant compositors will leave the screen locked and painted with a solid
|
||||
/// > color.
|
||||
/// >
|
||||
/// > This is what makes the session lock secure. The lock dying will not expose your session,
|
||||
/// > but it will render it inoperable.
|
||||
///
|
||||
/// [ext_session_lock_v1]: https://wayland.app/protocols/ext-session-lock-v1
|
||||
/// [SessionLockSurface]: ../sessionlocksurface
|
||||
class SessionLock: public Reloadable {
|
||||
Q_OBJECT;
|
||||
// clang-format off
|
||||
/// Controls the lock state.
|
||||
///
|
||||
/// > [!WARNING] Only one SessionLock may be locked at a time. Attempting to enable a lock while
|
||||
/// > another lock is enabled will do nothing.
|
||||
Q_PROPERTY(bool locked READ isLocked WRITE setLocked NOTIFY lockStateChanged);
|
||||
/// The compositor lock state.
|
||||
///
|
||||
/// This is set to true once the compositor has confirmed all screens are covered with locks.
|
||||
Q_PROPERTY(bool secure READ isSecure NOTIFY secureStateChanged);
|
||||
/// The surface that will be created for each screen. Must create a [SessionLockSurface].
|
||||
///
|
||||
/// [SessionLockSurface]: ../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);
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
///! Surface to display with a `SessionLock`.
|
||||
/// Surface displayed by a [SessionLock] when it is locked.
|
||||
///
|
||||
/// [SessionLock]: ../sessionlock
|
||||
class SessionLockSurface: public Reloadable {
|
||||
Q_OBJECT;
|
||||
// clang-format off
|
||||
Q_PROPERTY(QQuickItem* contentItem READ contentItem);
|
||||
/// If the surface has been made visible.
|
||||
///
|
||||
/// Note: SessionLockSurfaces will never become invisible, they will only be destroyed.
|
||||
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 surface is displayed on.
|
||||
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;
|
||||
};
|
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)
|
48
src/wayland/session_lock/lock.cpp
Normal file
48
src/wayland/session_lock/lock.cpp
Normal file
|
@ -0,0 +1,48 @@
|
|||
#include "lock.hpp"
|
||||
|
||||
#include <qtmetamacros.h>
|
||||
#include <wayland-ext-session-lock-v1-client-protocol.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() {
|
||||
if (this->isInitialized()) {
|
||||
// This will intentionally lock the session if the lock is destroyed without calling unlock.
|
||||
this->destroy();
|
||||
}
|
||||
}
|
||||
|
||||
void QSWaylandSessionLock::unlock() {
|
||||
if (this->isInitialized()) {
|
||||
if (this->finished) this->destroy();
|
||||
else this->unlock_and_destroy();
|
||||
|
||||
this->secure = false;
|
||||
this->manager->active = nullptr;
|
||||
|
||||
emit this->unlocked();
|
||||
}
|
||||
}
|
||||
|
||||
bool QSWaylandSessionLock::active() const { return this->isInitialized(); }
|
||||
|
||||
bool QSWaylandSessionLock::hasCompositorLock() const { return this->secure; }
|
||||
|
||||
void QSWaylandSessionLock::ext_session_lock_v1_locked() {
|
||||
this->secure = true;
|
||||
emit this->compositorLocked();
|
||||
}
|
||||
|
||||
void QSWaylandSessionLock::ext_session_lock_v1_finished() {
|
||||
this->secure = false;
|
||||
this->finished = true;
|
||||
this->unlock();
|
||||
}
|
39
src/wayland/session_lock/lock.hpp
Normal file
39
src/wayland/session_lock/lock.hpp
Normal file
|
@ -0,0 +1,39 @@
|
|||
#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 secure = false;
|
||||
bool finished = false;
|
||||
};
|
23
src/wayland/session_lock/manager.cpp
Normal file
23
src/wayland/session_lock/manager.cpp
Normal file
|
@ -0,0 +1,23 @@
|
|||
#include "manager.hpp"
|
||||
|
||||
#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; }
|
||||
bool QSWaylandSessionLockManager::isSecure() const {
|
||||
return this->isLocked() && this->active->hasCompositorLock();
|
||||
}
|
28
src/wayland/session_lock/manager.hpp
Normal file
28
src/wayland/session_lock/manager.hpp
Normal file
|
@ -0,0 +1,28 @@
|
|||
#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;
|
||||
[[nodiscard]] bool isSecure() const;
|
||||
|
||||
static bool sessionLocked();
|
||||
|
||||
private:
|
||||
QSWaylandSessionLock* active = nullptr;
|
||||
|
||||
friend class QSWaylandSessionLock;
|
||||
};
|
114
src/wayland/session_lock/session_lock.cpp
Normal file
114
src/wayland/session_lock/session_lock.cpp
Normal file
|
@ -0,0 +1,114 @@
|
|||
#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"
|
||||
|
||||
namespace {
|
||||
QSWaylandSessionLockManager* manager() {
|
||||
static QSWaylandSessionLockManager* manager = nullptr; // NOLINT
|
||||
|
||||
if (manager == nullptr) {
|
||||
manager = new QSWaylandSessionLockManager();
|
||||
}
|
||||
|
||||
return manager;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
bool SessionLockManager::lock() {
|
||||
if (this->isLocked() || 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;
|
||||
this->mLock->unlock();
|
||||
auto* lock = this->mLock;
|
||||
this->mLock = nullptr;
|
||||
delete lock;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SessionLockManager::isLocked() const { return this->mLock != nullptr; }
|
||||
bool SessionLockManager::sessionLocked() { return manager()->isLocked(); }
|
||||
bool SessionLockManager::isSecure() { return manager()->isSecure(); }
|
||||
|
||||
LockWindowExtension::~LockWindowExtension() {
|
||||
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 {
|
||||
// Qt appears to be resetting the window's screen on creation on some systems. This works around it.
|
||||
auto* screen = window->screen();
|
||||
window->create();
|
||||
window->setScreen(screen);
|
||||
|
||||
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; // NOLINT
|
||||
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) this->immediatelyVisible = true;
|
||||
else this->surface->setVisible();
|
||||
}
|
93
src/wayland/session_lock/session_lock.hpp
Normal file
93
src/wayland/session_lock/session_lock.hpp
Normal file
|
@ -0,0 +1,93 @@
|
|||
#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:
|
||||
explicit SessionLockManager(QObject* parent = nullptr): QObject(parent) {}
|
||||
|
||||
// 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();
|
||||
static bool isSecure();
|
||||
|
||||
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:
|
||||
explicit LockWindowExtension(QObject* parent = nullptr): QObject(parent) {}
|
||||
~LockWindowExtension() override;
|
||||
Q_DISABLE_COPY_MOVE(LockWindowExtension);
|
||||
|
||||
// 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;
|
||||
};
|
115
src/wayland/session_lock/surface.cpp
Normal file
115
src/wayland/session_lock/surface.cpp
Normal file
|
@ -0,0 +1,115 @@
|
|||
#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 <qtypes.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; // NOLINT (include)
|
||||
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() {
|
||||
if (this->ext != nullptr) this->ext->surface = nullptr;
|
||||
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) {
|
||||
if (this->window() != 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) this->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) this->initVisible();
|
||||
} else {
|
||||
// applyConfigureWhenPossible runs too late and causes a protocol error on reconfigure.
|
||||
this->window()->resizeFromApplyConfigure(this->size);
|
||||
}
|
||||
}
|
||||
|
||||
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(),
|
||||
this->size,
|
||||
QImage::Format_ARGB32
|
||||
);
|
||||
|
||||
this->window()->waylandSurface()->attach(this->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* ext);
|
||||
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;
|
||||
};
|
|
@ -5,14 +5,13 @@
|
|||
#include <private/qwaylandwindow_p.h>
|
||||
|
||||
#include "surface.hpp"
|
||||
#include "wayland-wlr-layer-shell-unstable-v1-client-protocol.h"
|
||||
|
||||
QSWaylandLayerShellIntegration::QSWaylandLayerShellIntegration()
|
||||
: QtWaylandClient::QWaylandShellIntegrationTemplate<QSWaylandLayerShellIntegration>(4) {}
|
||||
|
||||
QSWaylandLayerShellIntegration::~QSWaylandLayerShellIntegration() {
|
||||
if (this->object() != nullptr) {
|
||||
zwlr_layer_shell_v1_destroy(this->object());
|
||||
if (this->isInitialized()) {
|
||||
this->destroy();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
#include <private/qwaylandshellintegration_p.h>
|
||||
#include <private/qwaylandshellsurface_p.h>
|
||||
#include <qtwaylandclientexports.h>
|
||||
#include <qtclasshelpermacros.h>
|
||||
#include <qwayland-wlr-layer-shell-unstable-v1.h>
|
||||
|
||||
class QSWaylandLayerShellIntegration
|
||||
|
@ -11,10 +11,7 @@ class QSWaylandLayerShellIntegration
|
|||
public:
|
||||
QSWaylandLayerShellIntegration();
|
||||
~QSWaylandLayerShellIntegration() override;
|
||||
QSWaylandLayerShellIntegration(QSWaylandLayerShellIntegration&&) = delete;
|
||||
QSWaylandLayerShellIntegration(const QSWaylandLayerShellIntegration&) = delete;
|
||||
void operator=(QSWaylandLayerShellIntegration&&) = delete;
|
||||
void operator=(const QSWaylandLayerShellIntegration&) = delete;
|
||||
Q_DISABLE_COPY_MOVE(QSWaylandLayerShellIntegration);
|
||||
|
||||
QtWaylandClient::QWaylandShellSurface* createShellSurface(QtWaylandClient::QWaylandWindow* window
|
||||
) override;
|
||||
|
|
|
@ -23,12 +23,11 @@
|
|||
[[nodiscard]] QSize constrainedSize(const Anchors& anchors, const QSize& size) noexcept;
|
||||
// clang-format on
|
||||
|
||||
// clang-format off
|
||||
QSWaylandLayerSurface::QSWaylandLayerSurface(
|
||||
QSWaylandLayerShellIntegration* shell,
|
||||
QtWaylandClient::QWaylandWindow* window
|
||||
): QtWaylandClient::QWaylandShellSurface(window) {
|
||||
// clang-format on
|
||||
)
|
||||
: QtWaylandClient::QWaylandShellSurface(window) {
|
||||
|
||||
auto* qwindow = window->window();
|
||||
this->ext = LayershellWindowExtension::get(qwindow);
|
||||
|
@ -37,7 +36,7 @@ QSWaylandLayerSurface::QSWaylandLayerSurface(
|
|||
throw "QSWaylandLayerSurface created with null LayershellWindowExtension";
|
||||
}
|
||||
|
||||
wl_output* output = nullptr; // NOLINT (import)
|
||||
wl_output* output = nullptr; // NOLINT (include)
|
||||
if (this->ext->useWindowScreen) {
|
||||
auto* waylandScreen =
|
||||
dynamic_cast<QtWaylandClient::QWaylandScreen*>(qwindow->screen()->handle());
|
||||
|
@ -45,8 +44,8 @@ QSWaylandLayerSurface::QSWaylandLayerSurface(
|
|||
if (waylandScreen != nullptr) {
|
||||
output = waylandScreen->output();
|
||||
} else {
|
||||
qWarning() << "Layershell screen is set but does not corrospond to a real screen. Letting "
|
||||
"the compositor pick.";
|
||||
qWarning(
|
||||
) << "Layershell screen does not corrospond to a real screen. Letting the compositor pick.";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include <private/qwaylandshellsurface_p.h>
|
||||
#include <private/qwaylandwindow_p.h>
|
||||
#include <qtclasshelpermacros.h>
|
||||
#include <qtwaylandclientexports.h>
|
||||
#include <qtypes.h>
|
||||
#include <qwayland-wlr-layer-shell-unstable-v1.h>
|
||||
|
@ -20,10 +21,7 @@ public:
|
|||
);
|
||||
|
||||
~QSWaylandLayerSurface() override;
|
||||
QSWaylandLayerSurface(QSWaylandLayerSurface&&) = delete;
|
||||
QSWaylandLayerSurface(const QSWaylandLayerSurface&) = delete;
|
||||
void operator=(QSWaylandLayerSurface&&) = delete;
|
||||
void operator=(const QSWaylandLayerSurface&) = delete;
|
||||
Q_DISABLE_COPY_MOVE(QSWaylandLayerSurface);
|
||||
|
||||
[[nodiscard]] bool isExposed() const override;
|
||||
void applyConfigure() override;
|
||||
|
|
|
@ -54,7 +54,10 @@ bool LayershellWindowExtension::attach(QWindow* window) {
|
|||
}
|
||||
|
||||
if (!hasSurface) {
|
||||
// Qt appears to be resetting the window's screen on creation on some systems. This works around it.
|
||||
auto* screen = window->screen();
|
||||
window->create();
|
||||
window->setScreen(screen);
|
||||
|
||||
auto* waylandWindow = dynamic_cast<QtWaylandClient::QWaylandWindow*>(window->handle());
|
||||
if (waylandWindow == nullptr) {
|
||||
|
|
|
@ -56,17 +56,12 @@ class LayershellWindowExtension: public QObject {
|
|||
|
||||
public:
|
||||
LayershellWindowExtension(QObject* parent = nullptr): QObject(parent) {}
|
||||
~LayershellWindowExtension() override = default;
|
||||
LayershellWindowExtension(LayershellWindowExtension&&) = delete;
|
||||
LayershellWindowExtension(const LayershellWindowExtension&) = delete;
|
||||
void operator=(LayershellWindowExtension&&) = delete;
|
||||
void operator=(const LayershellWindowExtension&) = delete;
|
||||
|
||||
// returns the layershell extension if attached, otherwise nullptr
|
||||
static LayershellWindowExtension* get(QWindow* window);
|
||||
|
||||
// Attach this layershell extension to the given window.
|
||||
// The extension is reparented to the window and replaces any existing extensions.
|
||||
// The extension is reparented to the window and replaces any existing layershell extension.
|
||||
// Returns false if the window cannot be used.
|
||||
bool attach(QWindow* window);
|
||||
|
||||
|
|
Loading…
Reference in a new issue