Skip to content

Commit be5963a

Browse files
18202781743claude
andcommitted
feat: add compositor-side xdg-activation-v1 proxy and fix SPDX headers
- Add compositor-side xdg-activation-v1 proxy for plugin clients - Use single year in SPDX header for new files Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 3e55374 commit be5963a

12 files changed

Lines changed: 217 additions & 53 deletions

debian/changelog

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,3 @@
1-
dde-shell (2.0.44) unstable; urgency=medium
2-
3-
* fix(dock): align multitask view to first app gap with app icon
4-
spacing
5-
6-
-- zhangkun <zhangkun2@uniontech.com> Thu, 04 Jun 2026 19:32:58 +0800
7-
81
dde-shell (2.0.43) unstable; urgency=medium
92

103
* fix: xembed tray popup window position correction for stashed

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
}

panels/dock/pluginmanagerextension.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,12 @@
22
//
33
// SPDX-License-Identifier: GPL-3.0-or-later
44

5+
#include "constants.h"
56
#include "pluginmanagerextension_p.h"
67
#include "pluginmanagerintegration_p.h"
7-
#include "constants.h"
8+
#include "xdgactivationmanager_p.h"
9+
10+
#include <wayland/xdgactivation.h>
811

912
#include <DGuiApplicationHelper>
1013
#include <DPlatformTheme>

panels/dock/taskmanager/abstractwindowmonitor.cpp

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -157,14 +157,4 @@ void AbstractWindowMonitor::destroyWindow(AbstractWindow * window)
157157
m_trackedWindows.removeAt(pos);
158158
endRemoveRows();
159159
}
160-
161-
void AbstractWindowMonitor::clearTrackedWindows()
162-
{
163-
if (m_trackedWindows.isEmpty())
164-
return;
165-
166-
beginResetModel();
167-
m_trackedWindows.clear();
168-
endResetModel();
169-
}
170160
}

panels/dock/taskmanager/abstractwindowmonitor.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// SPDX-FileCopyrightText: 2023 - 2026 UnionTech Software Technology Co., Ltd.
1+
// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
22
//
33
// SPDX-License-Identifier: GPL-3.0-or-later
44

@@ -25,8 +25,7 @@ class AbstractWindowMonitor : public QAbstractListModel, public AbstractTaskMana
2525
QVariant data(const QModelIndex &index, int role = TaskManager::WinIdRole) const override;
2626

2727
void trackWindow(AbstractWindow* window);
28-
void destroyWindow(AbstractWindow * window);
29-
void clearTrackedWindows();
28+
void destroyWindow(AbstractWindow *window);
3029

3130
AbstractWindowMonitor(QObject* parent = nullptr);
3231
virtual void start() = 0;

panels/dock/taskmanager/package/TaskManager.qml

Lines changed: 2 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -16,29 +16,13 @@ ContainmentItem {
1616
property int dockOrder: 16
1717
property real remainingSpacesForTaskManager: Panel.rootObject.dockRemainingSpaceForCenter
1818
readonly property int appTitleSpacing: Math.max(10, Math.round(Panel.rootObject.dockItemMaxSize * 9 / 14) / 3)
19-
// Start padding for the app container so that the visual gap
20-
// (multitask icon right edge → first app icon left edge) = appTitleSpacing.
21-
// Compensates for the multitask view's box being wider than its icon.
22-
// 4/5 = 0.8: multitask button width relative to dockItemMaxSize.
23-
// Derived from the 1:4 spacing ratio (app icon : dock item height = 4:1, so content = 4/5 = 0.8).
24-
// Matches AppletDockItem.qml implicitWidth/Height ratio.
25-
readonly property real multitaskViewIconRatio: 0.8
26-
// 9/14 ≈ 0.64: app icon size relative to dockItemMaxSize (iconSize:dockHeight = 9:14).
27-
// Defined in main.qml as dockItemIconSize = dockItemMaxSize * 9 / 14.
28-
// At default dock size (56), icon = 36px; at min (37), icon ≈ 24px; at max (100), icon ≈ 64px.
29-
readonly property real iconWidthToMaxSizeRatio: 9 / 14
30-
readonly property real startPadding: Math.max(0, appTitleSpacing - (Panel.rootObject.dockItemMaxSize * (multitaskViewIconRatio - iconWidthToMaxSizeRatio) / 2))
3119

3220
implicitWidth: {
33-
let extra = useColumnLayout ? 0 : startPadding
34-
let w = appContainer.implicitWidth + extra
35-
let maxW = Panel.itemAlignment === Dock.LeftAlignment ? Math.max(remainingSpacesForTaskManager, w) : Math.min(remainingSpacesForTaskManager, w)
21+
let maxW = Panel.itemAlignment === Dock.LeftAlignment ? Math.max(remainingSpacesForTaskManager, appContainer.implicitWidth) : Math.min(remainingSpacesForTaskManager, appContainer.implicitWidth)
3622
return useColumnLayout ? Panel.rootObject.dockSize : maxW
3723
}
3824
implicitHeight: {
39-
let extra = useColumnLayout ? startPadding : 0
40-
let h = appContainer.implicitHeight + extra
41-
let maxH = Panel.itemAlignment === Dock.LeftAlignment ? Math.max(remainingSpacesForTaskManager, h) : Math.min(remainingSpacesForTaskManager, h)
25+
let maxH = Panel.itemAlignment === Dock.LeftAlignment ? Math.max(remainingSpacesForTaskManager, appContainer.implicitHeight) : Math.min(remainingSpacesForTaskManager, appContainer.implicitHeight)
4226
return useColumnLayout ? maxH : Panel.rootObject.dockSize
4327
}
4428
// Helper function to find the current index of an app by its appId in the visualModel
@@ -88,8 +72,6 @@ ContainmentItem {
8872
OverflowContainer {
8973
id: appContainer
9074
anchors.fill: parent
91-
anchors.leftMargin: useColumnLayout ? 0 : taskmanager.startPadding
92-
anchors.topMargin: useColumnLayout ? taskmanager.startPadding : 0
9375
useColumnLayout: taskmanager.useColumnLayout
9476
spacing: taskmanager.appTitleSpacing
9577
remove: Transition {

panels/dock/taskmanager/treelandwindowmonitor.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,6 @@ void TreeLandWindowMonitor::stop()
102102

103103
void TreeLandWindowMonitor::clear()
104104
{
105-
clearTrackedWindows();
106105
m_windows.clear();
107106
m_dockPreview.reset(nullptr);
108107
updateFullscreenState();

panels/dock/taskmanager/x11windowmonitor.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,6 @@ void X11WindowMonitor::stop()
9191

9292
void X11WindowMonitor::clear()
9393
{
94-
clearTrackedWindows();
9594
m_windows.clear();
9695
m_windowPreview.reset(nullptr);
9796
}
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+
}

0 commit comments

Comments
 (0)