1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
|
// SPDX-FileCopyrightText: 2025 Devin Lin <devin@kde.org>
// SPDX-License-Identifier: LGPL-2.0-or-later
#include "raiselockscreen.h"
#include "utils.h"
#include <QQuickItem>
#include <QWaylandClientExtensionTemplate>
#include <qpa/qplatformwindow_p.h>
#include <KWaylandExtras>
#include <KWindowSystem>
#include "qwayland-kde-lockscreen-overlay-v1.h"
class WaylandAboveLockscreen : public QWaylandClientExtensionTemplate<WaylandAboveLockscreen>, public QtWayland::kde_lockscreen_overlay_v1
{
public:
WaylandAboveLockscreen()
: QWaylandClientExtensionTemplate<WaylandAboveLockscreen>(1)
{
initialize();
}
};
RaiseLockscreen::RaiseLockscreen(QObject *parent)
: QObject{parent}
, m_implementation(std::make_unique<WaylandAboveLockscreen>())
{
QObject::connect(KWaylandExtras::self(), &KWaylandExtras::xdgActivationTokenArrived, this, [this](int serial, const QString &token) {
if (!m_window || serial != m_serial) {
return;
}
qCDebug(LOGGING_CATEGORY) << "XDG activation token arrived, activating window:" << m_window;
// Activate window over lockscreen once we have activation token
KWindowSystem::setCurrentXdgActivationToken(token);
KWindowSystem::activateWindow(m_window);
});
}
RaiseLockscreen::~RaiseLockscreen()
{
}
QWindow *RaiseLockscreen::window() const
{
return m_window;
}
void RaiseLockscreen::setWindow(QWindow *window)
{
m_window = window;
Q_EMIT windowChanged();
}
bool RaiseLockscreen::initialized() const
{
return m_initialized;
}
void RaiseLockscreen::setInitialized(bool initialized)
{
m_initialized = initialized;
Q_EMIT initializedChanged();
}
void RaiseLockscreen::initializeOverlay(QQuickWindow *window)
{
if (!window || window == m_window) {
return;
}
setWindow(window);
setOverlay();
// also re-set the overlay when the compositor gets restarted
connect(m_implementation.get(), &WaylandAboveLockscreen::activeChanged, this, &RaiseLockscreen::setOverlay);
}
void RaiseLockscreen::setOverlay()
{
if (!m_implementation->isActive()) {
setInitialized(false);
qCWarning(LOGGING_CATEGORY) << "Unable to set overlay: wayland protocol is not active";
return;
}
auto waylandWindow = m_window->nativeInterface<QNativeInterface::Private::QWaylandWindow>();
if (!waylandWindow) {
// Add event filter to listen for when wayland window appears, and try again
m_window->installEventFilter(this);
setInitialized(false);
qCWarning(LOGGING_CATEGORY) << "Unable to set overlay: unable to get wayland window";
return;
}
// Listen to when new surface roles are created, and re-allow again.
// This can happen when a window is hidden, and then shown again (same surface, different surface role)
connect(waylandWindow, &QNativeInterface::Private::QWaylandWindow::surfaceRoleCreated, this, [this, waylandWindow]() {
m_implementation->allow(waylandWindow->surface());
setInitialized(true);
qCDebug(LOGGING_CATEGORY) << "Initialized overlay successfully";
});
if (waylandWindow->surface()) {
m_implementation->allow(waylandWindow->surface());
setInitialized(true);
qCDebug(LOGGING_CATEGORY) << "Initialized overlay successfully";
}
}
bool RaiseLockscreen::eventFilter(QObject *watched, QEvent *event)
{
auto window = qobject_cast<QQuickWindow *>(watched);
if (window && event->type() == QEvent::PlatformSurface) {
auto surfaceEvent = static_cast<QPlatformSurfaceEvent *>(event);
if (surfaceEvent->surfaceEventType() == QPlatformSurfaceEvent::SurfaceCreated) {
m_window->removeEventFilter(this);
setOverlay();
}
}
return false;
}
void RaiseLockscreen::raiseOverlay()
{
if (!m_window) {
qCWarning(LOGGING_CATEGORY) << "Unable to raise overlay: no window set";
return;
}
if (!m_initialized) {
qCWarning(LOGGING_CATEGORY) << "Unable to raise overlay: window is not initialized for lockscreen overlaying, trying anyway...";
}
m_serial = KWaylandExtras::lastInputSerial(m_window);
qCDebug(LOGGING_CATEGORY) << "Attempting to raise overlay: " << m_window << m_initialized;
KWaylandExtras::requestXdgActivationToken(m_window, m_serial, QStringLiteral("org.kde.plasmashell.desktop"));
}
|