Skip to content

Commit 2ff37bb

Browse files
committed
feat: add xdg-activation-v1 support to dock compositor
Implement the xdg-activation-v1 protocol for the dock compositor, enabling applications to activate their windows through the dock's taskbar integration. This allows proper window focus management when clicking dock icons. The patch adds: 1. XdgActivationManager compositor extension implementing xdg_activation_v1 global 2. XdgActivationTokenV1 implementation for token lifecycle management 3. Integration with outer compositor via ds::XdgActivation for token delegation 4. QML registration for easy inclusion in DockCompositor When a plugin client commits an activation token, the manager requests a real token from the outer compositor and forwards it back, ensuring proper multi-layer Wayland compositor activation handling. Log: Added xdg-activation-v1 protocol support for dock activation functionality Influence: 1. Test clicking dock icons focuses applications correctly 2. Verify activation tokens are properly forwarded between compositor layers 3. Test multiple rapid activation requests 4. Verify proper cleanup when clients disconnect 5. Test activation tokens with different app IDs feat: 为任务栏合成器添加 xdg-activation-v1 支持 在任务栏合成器中实现 xdg-activation-v1 协议,使应用程序能通过任务栏集成 激活其窗口。这允许在点击任务栏图标时进行正确的窗口焦点管理。 修改内容: 1. 添加 XdgActivationManager 合成器扩展,实现 xdg_activation_v1 全局对象 2. 实现 XdgActivationTokenV1 用于令牌生命周期管理 3. 通过 ds::XdgActivation 与外部合成器集成进行令牌代理 4. 在 DockCompositor 中注册 QML 组件 当插件客户端提交激活令牌时,管理器从外部合成器请求真实令牌并转发回去,确 保多层 Wayland 合成器激活机制的正确处理。 Log: 新增 xdg-activation-v1 协议支持任务栏激活功能 Influence: 1. 测试点击任务栏图标能否正确聚焦应用程序 2. 验证激活令牌在合成器层之间正确转发 3. 测试多次快速激活请求 4. 验证客户端断开连接时的清理逻辑 5. 测试不同应用 ID 的激活令牌
1 parent c37a0d8 commit 2ff37bb

4 files changed

Lines changed: 207 additions & 0 deletions

File tree

panels/dock/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,8 @@ file(
117117
pluginmanagerintegration.cpp
118118
dockpositioner.h
119119
dockpositioner.cpp
120+
xdgactivationmanager_p.h
121+
xdgactivationmanager.cpp
120122
)
121123

122124
set_source_files_properties(DockCompositor.qml PROPERTIES
@@ -148,6 +150,7 @@ qt_generate_wayland_protocol_server_sources(dock-plugin
148150
FILES
149151
${DDE_TRAY_LOADER_PROTOCOL}
150152
${WaylandProtocols_DATADIR}/staging/fractional-scale/fractional-scale-v1.xml
153+
${WaylandProtocols_DATADIR}/staging/xdg-activation/xdg-activation-v1.xml
151154
)
152155

153156
target_link_libraries(dock-plugin PUBLIC

panels/dock/DockCompositor.qml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,5 +139,7 @@ Item {
139139
id: pluginScaleManager
140140
pluginScale: dockCompositor.panelScale * 120
141141
}
142+
143+
XdgActivationManager {}
142144
}
143145
}
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
// SPDX-FileCopyrightText: 2026 UnionTech Software Technology Co., Ltd.
2+
//
3+
// SPDX-License-Identifier: GPL-3.0-or-later
4+
5+
#include "xdgactivationmanager_p.h"
6+
7+
#include <wayland/xdgactivation.h>
8+
9+
#include <QGuiApplication>
10+
#include <QLoggingCategory>
11+
#include <QWindow>
12+
13+
#include <QtWaylandCompositor/QWaylandSeat>
14+
15+
Q_LOGGING_CATEGORY(xdgActivationMgr, "dde.shell.xdgactivation.manager")
16+
17+
// ---------------------------------------------------------------------------
18+
// XdgActivationManager
19+
// ---------------------------------------------------------------------------
20+
21+
XdgActivationManager::XdgActivationManager(QWaylandCompositor *compositor)
22+
: QWaylandCompositorExtensionTemplate(compositor)
23+
, m_compositor(compositor)
24+
{
25+
}
26+
27+
void XdgActivationManager::initialize()
28+
{
29+
QWaylandCompositorExtensionTemplate::initialize();
30+
QWaylandCompositor *compositor = static_cast<QWaylandCompositor *>(extensionContainer());
31+
Q_ASSERT(compositor);
32+
m_compositor = compositor;
33+
init(compositor->display(), 1);
34+
35+
// Create the client-side xdg_activation_v1 connection to the outer compositor
36+
m_outerActivation = new ds::XdgActivation(this);
37+
connect(m_outerActivation, &ds::XdgActivation::tokenReady, this, &XdgActivationManager::onTokenReady);
38+
}
39+
40+
void XdgActivationManager::xdg_activation_v1_destroy(Resource *resource)
41+
{
42+
wl_resource_destroy(resource->handle);
43+
}
44+
45+
void XdgActivationManager::xdg_activation_v1_get_activation_token(Resource *resource, uint32_t id)
46+
{
47+
QWaylandResource tokenResource(wl_resource_create(resource->client(), &xdg_activation_token_v1_interface, wl_resource_get_version(resource->handle), id));
48+
new XdgActivationTokenV1(this, tokenResource);
49+
}
50+
51+
void XdgActivationManager::setPendingToken(XdgActivationTokenV1 *token)
52+
{
53+
m_pendingToken = token;
54+
}
55+
56+
void XdgActivationManager::requestOuterToken(const QString &appId)
57+
{
58+
QWindow *window = QGuiApplication::focusWindow();
59+
m_outerActivation->requestToken(window, appId);
60+
}
61+
62+
void XdgActivationManager::clearPendingTokenIf(XdgActivationTokenV1 *token)
63+
{
64+
if (m_pendingToken == token) {
65+
m_pendingToken = nullptr;
66+
}
67+
}
68+
69+
void XdgActivationManager::onTokenReady(const QString &token)
70+
{
71+
if (m_pendingToken) {
72+
qCDebug(xdgActivationMgr) << "Forwarding activation token to plugin client";
73+
m_pendingToken->sendToken(token);
74+
m_pendingToken = nullptr;
75+
}
76+
}
77+
78+
// ---------------------------------------------------------------------------
79+
// XdgActivationTokenV1
80+
// ---------------------------------------------------------------------------
81+
// XdgActivationTokenV1
82+
// ---------------------------------------------------------------------------
83+
84+
XdgActivationTokenV1::XdgActivationTokenV1(XdgActivationManager *manager, const QWaylandResource &resource)
85+
: QObject(manager)
86+
, m_manager(manager)
87+
{
88+
init(resource.resource());
89+
}
90+
91+
XdgActivationTokenV1::~XdgActivationTokenV1() = default;
92+
93+
void XdgActivationTokenV1::sendToken(const QString &token)
94+
{
95+
send_done(token);
96+
}
97+
98+
void XdgActivationTokenV1::xdg_activation_token_v1_set_serial(Resource *resource, uint32_t serial, struct ::wl_resource *seat)
99+
{
100+
Q_UNUSED(resource)
101+
Q_UNUSED(seat)
102+
m_serial = serial;
103+
}
104+
105+
void XdgActivationTokenV1::xdg_activation_token_v1_set_app_id(Resource *resource, const QString &app_id)
106+
{
107+
Q_UNUSED(resource)
108+
m_appId = app_id;
109+
}
110+
111+
void XdgActivationTokenV1::xdg_activation_token_v1_set_surface(Resource *resource, struct ::wl_resource *surface)
112+
{
113+
Q_UNUSED(resource)
114+
m_surface = QWaylandSurface::fromResource(surface);
115+
}
116+
117+
void XdgActivationTokenV1::xdg_activation_token_v1_commit(Resource *resource)
118+
{
119+
Q_UNUSED(resource)
120+
qCDebug(xdgActivationMgr) << "Token committed by plugin client, appId:" << m_appId;
121+
122+
// Store this token as pending and request from the outer compositor
123+
m_manager->setPendingToken(this);
124+
m_manager->requestOuterToken(m_appId);
125+
}
126+
127+
void XdgActivationTokenV1::xdg_activation_token_v1_destroy(Resource *resource)
128+
{
129+
Q_UNUSED(resource)
130+
m_manager->clearPendingTokenIf(this);
131+
deleteLater();
132+
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
// SPDX-FileCopyrightText: 2026 UnionTech Software Technology Co., Ltd.
2+
//
3+
// SPDX-License-Identifier: GPL-3.0-or-later
4+
5+
#pragma once
6+
7+
#include <QMap>
8+
#include <QPointer>
9+
#include <QtWaylandCompositor/QWaylandCompositor>
10+
#include <QtWaylandCompositor/QWaylandCompositorExtension>
11+
#include <QtWaylandCompositor/QWaylandQuickExtension>
12+
#include <QtWaylandCompositor/QWaylandResource>
13+
#include <QtWaylandCompositor/QWaylandSurface>
14+
15+
#include "qwayland-server-xdg-activation-v1.h"
16+
17+
namespace ds
18+
{
19+
class XdgActivation;
20+
}
21+
22+
class XdgActivationTokenV1;
23+
class XdgActivationManager : public QWaylandCompositorExtensionTemplate<XdgActivationManager>, public QtWaylandServer::xdg_activation_v1
24+
{
25+
Q_OBJECT
26+
QML_ELEMENT
27+
public:
28+
XdgActivationManager(QWaylandCompositor *compositor = nullptr);
29+
void initialize() override;
30+
31+
void setPendingToken(XdgActivationTokenV1 *token);
32+
void requestOuterToken(const QString &appId);
33+
void clearPendingTokenIf(XdgActivationTokenV1 *token);
34+
35+
protected:
36+
void xdg_activation_v1_destroy(Resource *resource) override;
37+
void xdg_activation_v1_get_activation_token(Resource *resource, uint32_t id) override;
38+
39+
private:
40+
void onTokenReady(const QString &token);
41+
42+
QWaylandCompositor *m_compositor = nullptr;
43+
ds::XdgActivation *m_outerActivation = nullptr;
44+
QPointer<XdgActivationTokenV1> m_pendingToken;
45+
};
46+
47+
class XdgActivationTokenV1 : public QObject, public QtWaylandServer::xdg_activation_token_v1
48+
{
49+
Q_OBJECT
50+
public:
51+
XdgActivationTokenV1(XdgActivationManager *manager, const QWaylandResource &resource);
52+
~XdgActivationTokenV1() override;
53+
54+
void sendToken(const QString &token);
55+
56+
protected:
57+
void xdg_activation_token_v1_set_serial(Resource *resource, uint32_t serial, struct ::wl_resource *seat) override;
58+
void xdg_activation_token_v1_set_app_id(Resource *resource, const QString &app_id) override;
59+
void xdg_activation_token_v1_set_surface(Resource *resource, struct ::wl_resource *surface) override;
60+
void xdg_activation_token_v1_commit(Resource *resource) override;
61+
void xdg_activation_token_v1_destroy(Resource *resource) override;
62+
63+
private:
64+
XdgActivationManager *m_manager;
65+
QPointer<QWaylandSurface> m_surface;
66+
uint32_t m_serial = 0;
67+
QString m_appId;
68+
};
69+
70+
Q_COMPOSITOR_DECLARE_QUICK_EXTENSION_CLASS(XdgActivationManager)

0 commit comments

Comments
 (0)