File: raiselockscreen.cpp

package info (click to toggle)
plasma-mobile 6.5.4-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 20,412 kB
  • sloc: xml: 38,474; cpp: 18,529; javascript: 139; sh: 82; makefile: 5
file content (140 lines) | stat: -rw-r--r-- 4,429 bytes parent folder | download
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"));
}