nix-stuff/roles/kde/patches/kwin/pr7927.patch
2025-09-19 18:00:15 +02:00

669 lines
25 KiB
Diff

From 9f6c92806490d662117575a766f9fcb01e253344 Mon Sep 17 00:00:00 2001
From: Xaver Hugl <xaver.hugl@kde.org>
Date: Tue, 22 Jul 2025 23:24:51 +0200
Subject: [PATCH 1/4] xdgactivation: move the activation token to workspace
---
src/activation.cpp | 14 ++++++++++++
src/workspace.h | 6 +++++
src/xdgactivationv1.cpp | 50 +++++++++--------------------------------
src/xdgactivationv1.h | 14 ++----------
4 files changed, 32 insertions(+), 52 deletions(-)
diff --git a/src/activation.cpp b/src/activation.cpp
index 60b921247ce..9e743b8b098 100644
--- a/src/activation.cpp
+++ b/src/activation.cpp
@@ -630,4 +630,18 @@ void Workspace::windowAttentionChanged(Window *window, bool set)
}
}
+void Workspace::setActivationToken(const QString &token, uint32_t serial)
+{
+ m_activationToken = token;
+ m_activationTokenSerial = serial;
+}
+
+bool Workspace::mayActivate(const QString &token) const
+{
+ if (!m_activeWindow) {
+ return true;
+ }
+ return !m_activationToken.isEmpty() && token == m_activationToken && m_activeWindow->lastUsageSerial() <= m_activationTokenSerial;
+}
+
} // namespace
diff --git a/src/workspace.h b/src/workspace.h
index 2082bbe148d..03c54e06750 100644
--- a/src/workspace.h
+++ b/src/workspace.h
@@ -436,6 +436,9 @@ public:
OutputConfigurationError applyOutputConfiguration(OutputConfiguration &config, const std::optional<QList<Output *>> &outputOrder = std::nullopt);
void updateXwaylandScale();
+ void setActivationToken(const QString &token, uint32_t serial);
+ bool mayActivate(const QString &token) const;
+
public Q_SLOTS:
void performWindowOperation(KWin::Window *window, Options::WindowOperation op);
// Keybindings
@@ -729,6 +732,9 @@ private:
std::unique_ptr<DpmsInputEventFilter> m_dpmsFilter;
KConfigWatcher::Ptr m_kdeglobalsWatcher;
+ QString m_activationToken;
+ uint32_t m_activationTokenSerial = 0;
+
private:
friend bool performTransiencyCheck();
friend Workspace *workspace();
diff --git a/src/xdgactivationv1.cpp b/src/xdgactivationv1.cpp
index 39dade95332..a6be350399a 100644
--- a/src/xdgactivationv1.cpp
+++ b/src/xdgactivationv1.cpp
@@ -33,22 +33,6 @@ static bool isPrivilegedInWindowManagement(const ClientConnection *client)
XdgActivationV1Integration::XdgActivationV1Integration(XdgActivationV1Interface *activation, QObject *parent)
: QObject(parent)
{
- Workspace *ws = Workspace::self();
- connect(ws, &Workspace::windowActivated, this, [this](Window *window) {
- if (!m_currentActivationToken || !window || window->property("token").toString() == m_currentActivationToken->token) {
- return;
- }
-
- // We check that it's not the app that we are trying to activate
- if (window->desktopFileName() != m_currentActivationToken->applicationId) {
- // But also that the new one has been requested after the token was requested
- if (window->lastUsageSerial() < m_currentActivationToken->serial) {
- return;
- }
- }
-
- clear();
- });
activation->setActivationTokenCreator([this](ClientConnection *client, SurfaceInterface *surface, uint serial, SeatInterface *seat, const QString &appId) -> QString {
Workspace *ws = Workspace::self();
Q_ASSERT(client); // Should always be available as it's coming straight from the wayland implementation
@@ -69,9 +53,6 @@ QString XdgActivationV1Integration::requestToken(bool isPrivileged, SurfaceInter
static int i = 0;
const auto newToken = QStringLiteral("kwin-%1").arg(++i);
- if (m_currentActivationToken) {
- clear();
- }
bool showNotify = false;
QIcon icon = QIcon::fromTheme(QStringLiteral("system-run"));
if (const QString desktopFilePath = Window::findDesktopFile(appId); !desktopFilePath.isEmpty()) {
@@ -83,13 +64,13 @@ QString XdgActivationV1Integration::requestToken(bool isPrivileged, SurfaceInter
}
icon = QIcon::fromTheme(df.readIcon(), icon);
}
- std::unique_ptr<PlasmaWindowActivationInterface> activation;
if (showNotify) {
- activation = waylandServer()->plasmaActivationFeedback()->createActivation(appId);
+ m_lastToken = newToken;
+ m_activation = waylandServer()->plasmaActivationFeedback()->createActivation(appId);
}
- m_currentActivationToken = std::make_unique<ActivationToken>(ActivationToken{newToken, isPrivileged, surface, serial, seat, appId, showNotify, std::move(activation)});
+ workspace()->setActivationToken(newToken, serial);
if (showNotify) {
- Q_EMIT effects->startupAdded(m_currentActivationToken->token, icon);
+ Q_EMIT effects->startupAdded(newToken, icon);
}
return newToken;
}
@@ -103,31 +84,20 @@ void XdgActivationV1Integration::activateSurface(SurfaceInterface *surface, cons
return;
}
- if (!m_currentActivationToken || m_currentActivationToken->token != token) {
- qCDebug(KWIN_CORE) << "Refusing to activate " << window << " (provided token: " << token << ", current token:" << (m_currentActivationToken ? m_currentActivationToken->token : QStringLiteral("null")) << ")";
+ if (!ws->mayActivate(token)) {
window->demandAttention();
return;
}
-
- auto ownerWindow = waylandServer()->findWindow(m_currentActivationToken->surface);
- qCDebug(KWIN_CORE) << "activating" << window << surface << "on behalf of" << m_currentActivationToken->surface << "into" << ownerWindow;
- if (!ws->activeWindow() || ws->activeWindow() == ownerWindow || ws->activeWindow()->lastUsageSerial() < m_currentActivationToken->serial || m_currentActivationToken->isPrivileged) {
- ws->activateWindow(window);
- } else {
- qCWarning(KWIN_CORE) << "Activation requested while owner isn't active" << (ownerWindow ? ownerWindow->desktopFileName() : "null")
- << m_currentActivationToken->applicationId;
- window->demandAttention();
- clear();
- }
+ ws->activateWindow(window);
+ clear();
}
void XdgActivationV1Integration::clear()
{
- Q_ASSERT(m_currentActivationToken);
- if (m_currentActivationToken->showNotify) {
- Q_EMIT effects->startupRemoved(m_currentActivationToken->token);
+ if (m_activation) {
+ Q_EMIT effects->startupRemoved(m_lastToken);
+ m_activation.reset();
}
- m_currentActivationToken.reset();
}
}
diff --git a/src/xdgactivationv1.h b/src/xdgactivationv1.h
index 98835def8aa..77d21856095 100644
--- a/src/xdgactivationv1.h
+++ b/src/xdgactivationv1.h
@@ -38,18 +38,8 @@ private:
QString requestToken(bool isPrivileged, SurfaceInterface *surface, uint serial, SeatInterface *seat, const QString &appId);
void clear();
- struct ActivationToken
- {
- QString token;
- bool isPrivileged;
- QPointer<const SurfaceInterface> surface;
- uint serial;
- SeatInterface *seat;
- QString applicationId;
- bool showNotify;
- std::unique_ptr<PlasmaWindowActivationInterface> activation;
- };
- std::unique_ptr<ActivationToken> m_currentActivationToken;
+ QString m_lastToken;
+ std::unique_ptr<PlasmaWindowActivationInterface> m_activation;
};
}
--
GitLab
From 6c673a479412902a14c06046199f976e2192dc65 Mon Sep 17 00:00:00 2001
From: Xaver Hugl <xaver.hugl@kde.org>
Date: Tue, 22 Jul 2025 23:43:14 +0200
Subject: [PATCH 2/4] xdgactivation: also allow using activation tokens before
the window is mapped
We just store the token in the window, and then Workspace uses it to decide whether
or not to activate the window when it's actually shown.
---
src/window.cpp | 10 ++++++++++
src/window.h | 5 +++++
src/workspace.cpp | 4 ++--
src/xdgactivationv1.cpp | 6 +++++-
4 files changed, 22 insertions(+), 3 deletions(-)
diff --git a/src/window.cpp b/src/window.cpp
index 4a97a54aa74..879147ec673 100644
--- a/src/window.cpp
+++ b/src/window.cpp
@@ -4675,6 +4675,16 @@ void Window::setDescription(const QString &description)
}
}
+void Window::setActivationToken(const QString &token)
+{
+ m_activationToken = token;
+}
+
+QString Window::activationToken() const
+{
+ return m_activationToken;
+}
+
} // namespace KWin
#include "moc_window.cpp"
diff --git a/src/window.h b/src/window.h
index 1eb371018ca..91addb46819 100644
--- a/src/window.h
+++ b/src/window.h
@@ -1357,6 +1357,9 @@ public:
QString tag() const;
QString description() const;
+ void setActivationToken(const QString &token);
+ QString activationToken() const;
+
public Q_SLOTS:
virtual void closeWindow() = 0;
@@ -1880,6 +1883,8 @@ protected:
QString m_tag;
QString m_description;
+
+ QString m_activationToken;
};
inline QRectF Window::bufferGeometry() const
diff --git a/src/workspace.cpp b/src/workspace.cpp
index 3a5cb12677b..866abb8080d 100644
--- a/src/workspace.cpp
+++ b/src/workspace.cpp
@@ -781,8 +781,8 @@ void Workspace::addWaylandWindow(Window *window)
rearrange();
}
if (window->wantsInput() && !window->isMinimized()) {
- // Never activate a window on its own in "Extreme" mode.
- if (options->focusStealingPreventionLevel() < 4) {
+ // In "Extreme" mode, require an activation token to activate new windows
+ if (options->focusStealingPreventionLevel() < 4 || (!m_activationToken.isEmpty() && window->activationToken() == m_activationToken)) {
if (!window->isDesktop()
// If there's no active window, make this desktop the active one.
|| (activeWindow() == nullptr && should_get_focus.count() == 0)) {
diff --git a/src/xdgactivationv1.cpp b/src/xdgactivationv1.cpp
index a6be350399a..11c95c84b32 100644
--- a/src/xdgactivationv1.cpp
+++ b/src/xdgactivationv1.cpp
@@ -88,7 +88,11 @@ void XdgActivationV1Integration::activateSurface(SurfaceInterface *surface, cons
window->demandAttention();
return;
}
- ws->activateWindow(window);
+ if (window->readyForPainting()) {
+ ws->activateWindow(window);
+ } else {
+ window->setActivationToken(token);
+ }
clear();
}
--
GitLab
From 2436625a66257f586a0934c3d678c910bbdb3705 Mon Sep 17 00:00:00 2001
From: Xaver Hugl <xaver.hugl@kde.org>
Date: Wed, 23 Jul 2025 13:18:39 +0200
Subject: [PATCH 3/4] xdgactivation: move the "not granted" token to
requestToken
Having some but not all checks in that method is a bit confusing
---
src/xdgactivationv1.cpp | 14 ++++++--------
1 file changed, 6 insertions(+), 8 deletions(-)
diff --git a/src/xdgactivationv1.cpp b/src/xdgactivationv1.cpp
index 11c95c84b32..e818466f8ad 100644
--- a/src/xdgactivationv1.cpp
+++ b/src/xdgactivationv1.cpp
@@ -34,15 +34,8 @@ XdgActivationV1Integration::XdgActivationV1Integration(XdgActivationV1Interface
: QObject(parent)
{
activation->setActivationTokenCreator([this](ClientConnection *client, SurfaceInterface *surface, uint serial, SeatInterface *seat, const QString &appId) -> QString {
- Workspace *ws = Workspace::self();
Q_ASSERT(client); // Should always be available as it's coming straight from the wayland implementation
- const bool isPrivileged = isPrivilegedInWindowManagement(client);
- if (!isPrivileged && ws->activeWindow() && ws->activeWindow()->surface() != surface) {
- qCDebug(KWIN_CORE) << "Cannot grant a token to" << client;
- return QStringLiteral("not-granted-666");
- }
-
- return requestToken(isPrivileged, surface, serial, seat, appId);
+ return requestToken(isPrivilegedInWindowManagement(client), surface, serial, seat, appId);
});
connect(activation, &XdgActivationV1Interface::activateRequested, this, &XdgActivationV1Integration::activateSurface);
@@ -50,6 +43,11 @@ XdgActivationV1Integration::XdgActivationV1Integration(XdgActivationV1Interface
QString XdgActivationV1Integration::requestToken(bool isPrivileged, SurfaceInterface *surface, uint serial, SeatInterface *seat, const QString &appId)
{
+ auto window = waylandServer()->findWindow(surface);
+ if (!isPrivileged && workspace()->activeWindow() && workspace()->activeWindow()->surface() != surface) {
+ qCWarning(KWIN_CORE) << "Cannot grant a token to" << window;
+ return QStringLiteral("not-granted-666");
+ }
static int i = 0;
const auto newToken = QStringLiteral("kwin-%1").arg(++i);
--
GitLab
From 8508b8060813c07fe035801381bad1f9a375acf0 Mon Sep 17 00:00:00 2001
From: Xaver Hugl <xaver.hugl@kde.org>
Date: Thu, 24 Jul 2025 20:43:46 +0200
Subject: [PATCH 4/4] autotests/integration: add a test case for xdg activation
---
autotests/integration/CMakeLists.txt | 3 +-
autotests/integration/activation_test.cpp | 126 +++++++++++++++++++++-
autotests/integration/kwin_wayland_test.h | 31 ++++++
autotests/integration/test_helpers.cpp | 50 +++++++++
4 files changed, 208 insertions(+), 2 deletions(-)
diff --git a/autotests/integration/CMakeLists.txt b/autotests/integration/CMakeLists.txt
index 13b0cde04f5..408af6ac8b8 100644
--- a/autotests/integration/CMakeLists.txt
+++ b/autotests/integration/CMakeLists.txt
@@ -16,13 +16,14 @@ qt6_generate_wayland_protocol_client_sources(KWinIntegrationTestFramework
FILES
${CMAKE_SOURCE_DIR}/src/wayland/protocols/wlr-layer-shell-unstable-v1.xml
${WaylandProtocols_DATADIR}/stable/presentation-time/presentation-time.xml
+ ${WaylandProtocols_DATADIR}/stable/tablet/tablet-v2.xml
${WaylandProtocols_DATADIR}/stable/xdg-shell/xdg-shell.xml
${WaylandProtocols_DATADIR}/staging/color-management/color-management-v1.xml
- ${WaylandProtocols_DATADIR}/stable/tablet/tablet-v2.xml
${WaylandProtocols_DATADIR}/staging/cursor-shape/cursor-shape-v1.xml
${WaylandProtocols_DATADIR}/staging/fifo/fifo-v1.xml
${WaylandProtocols_DATADIR}/staging/fractional-scale/fractional-scale-v1.xml
${WaylandProtocols_DATADIR}/staging/security-context/security-context-v1.xml
+ ${WaylandProtocols_DATADIR}/staging/xdg-activation/xdg-activation-v1.xml
${WaylandProtocols_DATADIR}/staging/xdg-dialog/xdg-dialog-v1.xml
${WaylandProtocols_DATADIR}/unstable/idle-inhibit/idle-inhibit-unstable-v1.xml
${WaylandProtocols_DATADIR}/unstable/text-input/text-input-unstable-v3.xml
diff --git a/autotests/integration/activation_test.cpp b/autotests/integration/activation_test.cpp
index 75c9e7e8c7b..30f671d6fe2 100644
--- a/autotests/integration/activation_test.cpp
+++ b/autotests/integration/activation_test.cpp
@@ -15,6 +15,7 @@
#include "workspace.h"
#include "x11window.h"
+#include <KWayland/Client/seat.h>
#include <KWayland/Client/surface.h>
#include <netwm.h>
#include <xcb/xcb_icccm.h>
@@ -40,6 +41,7 @@ private Q_SLOTS:
void testSwitchToWindowMaximized();
void testSwitchToWindowFullScreen();
void testActiveFullscreen();
+ void testXdgActivation();
private:
void stackScreensHorizontally();
@@ -64,7 +66,7 @@ void ActivationTest::initTestCase()
void ActivationTest::init()
{
- QVERIFY(Test::setupWaylandConnection());
+ QVERIFY(Test::setupWaylandConnection(Test::AdditionalWaylandInterface::XdgActivation | Test::AdditionalWaylandInterface::Seat));
workspace()->setActiveOutput(QPoint(640, 512));
input()->pointer()->warp(QPoint(640, 512));
@@ -592,6 +594,128 @@ void ActivationTest::testActiveFullscreen()
QCOMPARE(workspace()->activeWindow(), waylandWindow);
QCOMPARE(x11Window->layer(), Layer::NormalLayer);
}
+
+void ActivationTest::testXdgActivation()
+{
+ Test::setOutputConfig({QRect(0, 0, 1280, 1024)});
+
+ uint32_t time = 0;
+
+ std::vector<std::unique_ptr<KWayland::Client::Surface>> surfaces;
+ std::vector<std::unique_ptr<Test::XdgToplevel>> shellSurfaces;
+ std::vector<Window *> windows;
+ const auto setupWindows = [&]() {
+ windows.clear();
+ shellSurfaces.clear();
+ surfaces.clear();
+
+ // re-create the same setup every time for reduced confusion
+ for (int i = 0; i < 3; i++) {
+ surfaces.push_back(Test::createSurface());
+ shellSurfaces.push_back(Test::createXdgToplevelSurface(surfaces.back().get()));
+ windows.push_back(Test::renderAndWaitForShown(surfaces.back().get(), QSize(100, 50), Qt::blue));
+ windows.back()->move(QPoint(150 * i, 0));
+
+ Test::pointerMotion(windows.back()->frameGeometry().center(), time++);
+ Test::pointerButtonPressed(1, time++);
+ Test::pointerButtonReleased(1, time++);
+ }
+ };
+ setupWindows();
+
+ QSignalSpy activationSpy(workspace(), &Workspace::windowActivated);
+
+ // activating a window without a valid token should fail
+ Test::xdgActivation()->activate(QString(), *surfaces[1]);
+ QVERIFY(!activationSpy.wait(10));
+
+ // activating it without a surface should fail as well, even if a serial is present
+ auto token = Test::xdgActivation()->createToken();
+ token->set_serial(windows.back()->lastUsageSerial(), *Test::waylandSeat());
+ Test::xdgActivation()->activate(token->commitAndWait(), *surfaces[1]);
+ QVERIFY(!activationSpy.wait(10));
+
+ // adding the surface should make it work
+ token = Test::xdgActivation()->createToken();
+ token->set_surface(*surfaces.back());
+ token->set_serial(windows.back()->lastUsageSerial(), *Test::waylandSeat());
+ Test::xdgActivation()->activate(token->commitAndWait(), *surfaces[1]);
+ QVERIFY(activationSpy.wait(10));
+ QCOMPARE(workspace()->activeWindow(), windows[1]);
+
+ // activation should still work if the window is closed after creating the token
+ setupWindows();
+ token = Test::xdgActivation()->createToken();
+ token->set_surface(*surfaces[2]);
+ token->set_serial(windows[2]->lastUsageSerial(), *Test::waylandSeat());
+ QString result = token->commitAndWait();
+
+ surfaces[2]->attachBuffer((wl_buffer *)nullptr);
+ surfaces[2]->commit(KWayland::Client::Surface::CommitFlag::None);
+ QVERIFY(activationSpy.wait(10));
+ QCOMPARE(workspace()->activeWindow(), windows[1]);
+
+ Test::xdgActivation()->activate(result, *surfaces[0]);
+ QVERIFY(activationSpy.wait(10));
+ QCOMPARE(workspace()->activeWindow(), windows[0]);
+
+ // ...unless the user interacted with another window in between
+ setupWindows();
+ token = Test::xdgActivation()->createToken();
+ token->set_surface(*surfaces[2]);
+ token->set_serial(windows[2]->lastUsageSerial(), *Test::waylandSeat());
+ result = token->commitAndWait();
+
+ surfaces[2]->attachBuffer((wl_buffer *)nullptr);
+ surfaces[2]->commit(KWayland::Client::Surface::CommitFlag::None);
+ QVERIFY(activationSpy.wait(10));
+ QCOMPARE(workspace()->activeWindow(), windows[1]);
+
+ Test::pointerMotion(windows[1]->frameGeometry().center(), time++);
+ Test::pointerButtonPressed(1, time++);
+ Test::pointerButtonReleased(1, time++);
+
+ Test::xdgActivation()->activate(result, *surfaces[0]);
+ QVERIFY(!activationSpy.wait(10));
+ QCOMPARE(workspace()->activeWindow(), windows[1]);
+
+ // ensure that windows are only activated on show with a valid activation token
+ options->setFocusStealingPreventionLevel(4);
+
+ // creating a new window and immediately activating it should work
+ setupWindows();
+ token = Test::xdgActivation()->createToken();
+ token->set_surface(*surfaces[2]);
+ token->set_serial(windows[2]->lastUsageSerial(), *Test::waylandSeat());
+ result = token->commitAndWait();
+ surfaces.push_back(Test::createSurface());
+ shellSurfaces.push_back(Test::createXdgToplevelSurface(surfaces.back().get(), [&](Test::XdgToplevel *toplevel) {
+ Test::xdgActivation()->activate(result, *surfaces.back());
+ }));
+ windows.push_back(Test::renderAndWaitForShown(surfaces.back().get(), QSize(100, 50), Qt::blue));
+ QCOMPARE(workspace()->activeWindow(), windows.back());
+ windows.back()->move(QPoint(150 * 3, 0));
+
+ // activation should fail if the user clicks on another window in between
+ // creating the activation token and using it
+ setupWindows();
+ token = Test::xdgActivation()->createToken();
+ token->set_surface(*surfaces[2]);
+ token->set_serial(windows[2]->lastUsageSerial(), *Test::waylandSeat());
+ result = token->commitAndWait();
+
+ Test::pointerMotion(windows[1]->frameGeometry().center(), time++);
+ Test::pointerButtonPressed(1, time++);
+ Test::pointerButtonReleased(1, time++);
+
+ surfaces.push_back(Test::createSurface());
+ shellSurfaces.push_back(Test::createXdgToplevelSurface(surfaces.back().get(), [&](Test::XdgToplevel *toplevel) {
+ Test::xdgActivation()->activate(result, *surfaces.back());
+ }));
+ windows.push_back(Test::renderAndWaitForShown(surfaces.back().get(), QSize(100, 50), Qt::blue));
+ QCOMPARE(workspace()->activeWindow(), windows[1]);
+ windows.back()->move(QPoint(150 * 3, 0));
+}
}
WAYLANDTEST_MAIN(KWin::ActivationTest)
diff --git a/autotests/integration/kwin_wayland_test.h b/autotests/integration/kwin_wayland_test.h
index b0f63dadbc5..a6616189617 100644
--- a/autotests/integration/kwin_wayland_test.h
+++ b/autotests/integration/kwin_wayland_test.h
@@ -34,6 +34,7 @@
#include "qwayland-security-context-v1.h"
#include "qwayland-text-input-unstable-v3.h"
#include "qwayland-wlr-layer-shell-unstable-v1.h"
+#include "qwayland-xdg-activation-v1.h"
#include "qwayland-xdg-decoration-unstable-v1.h"
#include "qwayland-xdg-dialog-v1.h"
#include "qwayland-xdg-shell.h"
@@ -611,6 +612,7 @@ enum class AdditionalWaylandInterface {
ColorManagement = 1 << 22,
FifoV1 = 1 << 23,
PresentationTime = 1 << 24,
+ XdgActivation = 1 << 25,
};
Q_DECLARE_FLAGS(AdditionalWaylandInterfaces, AdditionalWaylandInterface)
@@ -717,6 +719,33 @@ private:
void wp_presentation_feedback_discarded() override;
};
+class XdgActivationToken : public QObject, public QtWayland::xdg_activation_token_v1
+{
+ Q_OBJECT
+public:
+ explicit XdgActivationToken(::xdg_activation_token_v1 *object);
+ ~XdgActivationToken() override;
+
+ QString commitAndWait();
+
+Q_SIGNALS:
+ void tokenReceived();
+
+private:
+ void xdg_activation_token_v1_done(const QString &token) override;
+
+ QString m_token;
+};
+
+class XdgActivation : public QtWayland::xdg_activation_v1
+{
+public:
+ explicit XdgActivation(::wl_registry *registry, uint32_t id, int version);
+ ~XdgActivation() override;
+
+ std::unique_ptr<XdgActivationToken> createToken();
+};
+
struct Connection
{
static std::unique_ptr<Connection> setup(AdditionalWaylandInterfaces interfaces = AdditionalWaylandInterfaces());
@@ -757,6 +786,7 @@ struct Connection
std::unique_ptr<ColorManagerV1> colorManager;
std::unique_ptr<FifoManagerV1> fifoManager;
std::unique_ptr<PresentationTime> presentationTime;
+ std::unique_ptr<XdgActivation> xdgActivation;
};
void keyboardKeyPressed(quint32 key, quint32 time);
@@ -821,6 +851,7 @@ SecurityContextManagerV1 *waylandSecurityContextManagerV1();
ColorManagerV1 *colorManager();
FifoManagerV1 *fifoManager();
PresentationTime *presentationTime();
+XdgActivation *xdgActivation();
bool waitForWaylandSurface(Window *window);
diff --git a/autotests/integration/test_helpers.cpp b/autotests/integration/test_helpers.cpp
index 22380c947d3..e524f10826d 100644
--- a/autotests/integration/test_helpers.cpp
+++ b/autotests/integration/test_helpers.cpp
@@ -535,6 +535,11 @@ std::unique_ptr<Connection> Connection::setup(AdditionalWaylandInterfaces flags)
c->presentationTime = std::make_unique<PresentationTime>(*c->registry, name, version);
}
}
+ if (flags & AdditionalWaylandInterface::XdgActivation) {
+ if (interface == xdg_activation_v1_interface.name) {
+ c->xdgActivation = std::make_unique<XdgActivation>(*c->registry, name, version);
+ }
+ }
});
QSignalSpy allAnnounced(registry, &KWayland::Client::Registry::interfacesAnnounced);
@@ -665,6 +670,7 @@ Connection::~Connection()
colorManager.reset();
fifoManager.reset();
presentationTime.reset();
+ xdgActivation.reset();
delete queue; // Must be destroyed last
queue = nullptr;
@@ -796,6 +802,11 @@ PresentationTime *presentationTime()
return s_waylandConnection->presentationTime.get();
}
+XdgActivation *xdgActivation()
+{
+ return s_waylandConnection->xdgActivation.get();
+}
+
bool waitForWaylandSurface(Window *window)
{
if (window->surface()) {
@@ -1817,6 +1828,45 @@ void WpPresentationFeedback::wp_presentation_feedback_discarded()
Q_EMIT discarded();
}
+XdgActivationToken::XdgActivationToken(::xdg_activation_token_v1 *object)
+ : QtWayland::xdg_activation_token_v1(object)
+{
+}
+
+XdgActivationToken::~XdgActivationToken()
+{
+ destroy();
+}
+
+QString XdgActivationToken::commitAndWait()
+{
+ QSignalSpy received(this, &XdgActivationToken::tokenReceived);
+ commit();
+ received.wait();
+ return m_token;
+}
+
+void XdgActivationToken::xdg_activation_token_v1_done(const QString &token)
+{
+ m_token = token;
+ Q_EMIT tokenReceived();
+}
+
+XdgActivation::XdgActivation(::wl_registry *registry, uint32_t id, int version)
+ : QtWayland::xdg_activation_v1(registry, id, version)
+{
+}
+
+XdgActivation::~XdgActivation()
+{
+ destroy();
+}
+
+std::unique_ptr<XdgActivationToken> XdgActivation::createToken()
+{
+ return std::make_unique<XdgActivationToken>(get_activation_token());
+}
+
void keyboardKeyPressed(quint32 key, quint32 time)
{
auto virtualKeyboard = static_cast<WaylandTestApplication *>(kwinApp())->virtualKeyboard();
--
GitLab