mirror of
https://invent.kde.org/marcoa/shift-shell.git
synced 2026-04-26 14:23:09 +00:00
Overlay the shell's status panel and quicksettings panel over the lockscreen, instead of rendering a second copy in the lockscreen theme. This will allow us to improve the lockscreen loading speed. Key changes: - Overlay quicksettings window and the status bar over the lockscreen when it is shown - Refactor the top panel's showing logic to be cleaner (as it supports various overlay modes over fullscreen apps already) - Implement lockscreen support to the status bar and quicksettings panel in the to panel - Forward quicksettings panel requests for "unlock" over DBus to the lockscreen - Add "raiselockscreen" QML plugin to easily request a window to be raised over the lockscreen Notes: - Now that we are sharing the quicksettings panel from the shell, notifications that are already there will be shown on the lockscreen (compared to right now, where only new notifications would be shown) Depends on: - https://invent.kde.org/plasma/plasma-workspace/-/merge_requests/2339 - https://invent.kde.org/plasma/kscreenlocker/-/merge_requests/283 - https://invent.kde.org/plasma/kwin/-/merge_requests/7839 Implements: https://invent.kde.org/plasma/plasma-mobile/-/issues/199 
140 lines
4.3 KiB
C++
140 lines
4.3 KiB
C++
// 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"));
|
|
}
|