Skip to content

Commit 22b3fc9

Browse files
committed
fix: xembed tray popup window position correction for stashed container
之前托盘位置总是相对于任务栏的 wl_surface 的,会导致向上收起区域的偏移 位置不正确。此提交增加了托盘位于哪个区域的区分,并根据对应的位置决定 所基于的 wl_surface 是哪个。 PMS: BUG-360349 Log:
1 parent 46c66aa commit 22b3fc9

10 files changed

Lines changed: 102 additions & 26 deletions

panels/dock/DockCompositor.qml

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ Item {
2020
property alias dockSize: pluginManager.dockSize
2121
property var moveXEmbedWindowHandler: null
2222

23+
function notifyXEmbedWindowMoveResult(wid, success) {
24+
pluginManager.notifyXEmbedWindowMoveResult(wid, success)
25+
}
26+
2327
property ListModel trayPluginSurfaces: ListModel {}
2428
property ListModel quickPluginSurfaces: ListModel {}
2529
property ListModel fixedPluginSurfaces: ListModel {}
@@ -115,11 +119,15 @@ Item {
115119
dockCompositor.popupClosed()
116120
}
117121

118-
onMoveXEmbedWindowRequested: (wid, pluginId, itemKey, dx, dy) => {
119-
console.log("move xembed window requested:", wid, pluginId, itemKey, dx, dy)
122+
onMoveXEmbedWindowRequested: (wid, pluginId, itemKey, dx, dy, anchorWindow) => {
123+
console.log("move xembed window requested:", wid, pluginId, itemKey, dx, dy, "anchorWindow:", anchorWindow)
120124
if (typeof dockCompositor.moveXEmbedWindowHandler === 'function') {
121-
var success = dockCompositor.moveXEmbedWindowHandler(wid, dx, dy)
122-
pluginManager.notifyXEmbedWindowMoveResult(wid, success)
125+
var sent = dockCompositor.moveXEmbedWindowHandler(wid, dx, dy, anchorWindow)
126+
if (!sent) {
127+
// Pre-check failed (e.g. manager not ready) — no wl_callback registered
128+
pluginManager.notifyXEmbedWindowMoveResult(wid, false)
129+
}
130+
// If sent, result arrives asynchronously via xembedWindowMoveResult signal
123131
} else {
124132
console.warn("moveXEmbedWindowHandler not available")
125133
pluginManager.notifyXEmbedWindowMoveResult(wid, false)

panels/dock/dockhelper.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include "dockpanel.h"
99

1010
#include <QObject>
11+
#include <QQuickWindow>
1112

1213
namespace dock {
1314
class DockWakeUpArea;
@@ -22,8 +23,8 @@ class DockHelper : public QObject
2223
void enterScreen(QScreen *screen);
2324
void leaveScreen();
2425

25-
// Move XEmbed window relative to dock surface (no-op on X11)
26-
virtual bool moveXEmbedWindow(uint32_t wid, double dx, double dy) { return false; }
26+
// Move XEmbed window relative to anchor window's surface (no-op on X11)
27+
virtual bool moveXEmbedWindow(uint32_t wid, double dx, double dy, QQuickWindow *anchorWindow = nullptr) { return false; }
2728

2829
Q_SIGNALS:
2930
void isWindowOverlapChanged(bool overlap);

panels/dock/dockpanel.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,8 @@ bool DockPanel::init()
163163
if (QStringLiteral("wayland") == platformName) {
164164
// TODO: support get color type from wayland
165165
m_helper = new WaylandDockHelper(this);
166+
connect(static_cast<WaylandDockHelper *>(m_helper), &WaylandDockHelper::xembedWindowMoveResult,
167+
this, &DockPanel::xembedWindowMoveResult);
166168
} else if (QStringLiteral("xcb") == platformName) {
167169
QObject::connect(Dtk::Gui::DGuiApplicationHelper::instance(), &Dtk::Gui::DGuiApplicationHelper::themeTypeChanged,
168170
this, [this](){
@@ -490,10 +492,10 @@ void DockPanel::setIsResizing(bool resizing)
490492
emit isResizingChanged(m_isResizing);
491493
}
492494

493-
bool DockPanel::moveXEmbedWindow(uint32_t wid, double dx, double dy)
495+
bool DockPanel::moveXEmbedWindow(uint32_t wid, double dx, double dy, QQuickWindow *anchorWindow)
494496
{
495497
if (m_helper) {
496-
return m_helper->moveXEmbedWindow(wid, dx, dy);
498+
return m_helper->moveXEmbedWindow(wid, dx, dy, anchorWindow);
497499
}
498500
return false;
499501
}

panels/dock/dockpanel.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,9 @@ class DockPanel : public DS_NAMESPACE::DPanel, public QDBusContext
8484

8585
Q_INVOKABLE void notifyDockPositionChanged(int offsetX, int offsetY);
8686

87-
// Move XEmbed window relative to dock surface (Wayland only)
88-
Q_INVOKABLE bool moveXEmbedWindow(uint32_t wid, double dx, double dy);
87+
// Move XEmbed window relative to anchor window's surface (Wayland only)
88+
// anchorWindow: the window containing the plugin item (dock panel or popup window)
89+
Q_INVOKABLE bool moveXEmbedWindow(uint32_t wid, double dx, double dy, QQuickWindow *anchorWindow = nullptr);
8990

9091
bool showInPrimary() const;
9192
void setShowInPrimary(bool newShowInPrimary);
@@ -138,6 +139,9 @@ private Q_SLOTS:
138139
void contextDraggingChanged();
139140
void isResizingChanged(bool isResizing);
140141

142+
// Emitted when async XEmbed window move completes
143+
void xembedWindowMoveResult(uint32_t wid, bool success);
144+
141145
private:
142146
ColorTheme m_theme;
143147
HideState m_hideState;

panels/dock/package/main.qml

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -855,10 +855,16 @@ Window {
855855
return Panel.devicePixelRatio
856856
})
857857

858-
DockCompositor.moveXEmbedWindowHandler = function(wid, dx, dy) {
859-
return Panel.moveXEmbedWindow(wid, dx, dy)
858+
DockCompositor.moveXEmbedWindowHandler = function(wid, dx, dy, anchorWindow) {
859+
return Panel.moveXEmbedWindow(wid, dx, dy, anchorWindow)
860+
// If true: result arrives asynchronously via Panel.xembedWindowMoveResult signal
861+
// If false: pre-check failed, caller should notify failure immediately
860862
}
861863

864+
Panel.xembedWindowMoveResult.connect(function(wid, success) {
865+
DockCompositor.notifyXEmbedWindowMoveResult(wid, success)
866+
})
867+
862868
dock.itemIconSizeBase = dock.dockItemMaxSize
863869
dock.visible = Panel.hideState !== Dock.Hide
864870
changeDragAreaAnchor()

panels/dock/pluginmanagerextension.cpp

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,16 @@ QPoint PluginSurface::itemPosition() const
264264
return m_itemPosition;
265265
}
266266

267+
void PluginSurface::setAnchorWindow(QQuickWindow *window)
268+
{
269+
m_anchorWindow = window;
270+
}
271+
272+
QQuickWindow *PluginSurface::anchorWindow() const
273+
{
274+
return m_anchorWindow;
275+
}
276+
267277
void PluginSurface::plugin_mouse_event(QtWaylandServer::plugin::Resource *resource, int32_t type)
268278
{
269279
Q_UNUSED(resource)
@@ -305,6 +315,8 @@ void PluginSurface::plugin_destroy(Resource *resource)
305315

306316
void PluginSurface::setGlobalPos(const QPoint &pos)
307317
{
318+
m_lastGlobalPos = pos;
319+
308320
QRect g = qApp->primaryScreen() ? qApp->primaryScreen()->geometry() : QRect();
309321
for (auto *screen : qApp->screens())
310322
{
@@ -706,8 +718,8 @@ void PluginManager::plugin_manager_v1_move_xembed_window(Resource *resource, uin
706718
// Store pending callback for later response (supports concurrent requests)
707719
m_pendingXEmbedCallbacks[xembed_winid] = {callback, resource->handle};
708720

709-
// Emit signal with position info for QML to handle
710-
Q_EMIT moveXEmbedWindowRequested(xembed_winid, plugin_id, item_key, dx, dy);
721+
// Emit signal with position info and anchor window for QML to handle
722+
Q_EMIT moveXEmbedWindowRequested(xembed_winid, plugin_id, item_key, dx, dy, pluginSurface->anchorWindow());
711723
}
712724

713725
void PluginManager::notifyXEmbedWindowMoveResult(uint32_t wid, bool success)

panels/dock/pluginmanagerextension_p.h

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
#include <QMap>
88
#include <QPointer>
9+
#include <QQuickWindow>
910
#include <QtWaylandCompositor/QWaylandCompositor>
1011
#include <QtWaylandCompositor/QWaylandQuickExtension>
1112
#include <QtWaylandCompositor/QWaylandResource>
@@ -99,8 +100,8 @@ class PluginManager : public QWaylandCompositorExtensionTemplate<PluginManager>,
99100
void dockSizeChanged();
100101
void requestShutdown(const QString &type);
101102
// Signal emitted when XEmbed window move is requested
102-
// Parameters: wid (window ID), pluginId, itemKey, dx (relative x offset), dy (relative y offset)
103-
void moveXEmbedWindowRequested(uint32_t wid, const QString &pluginId, const QString &itemKey, double dx, double dy);
103+
// Parameters: wid (window ID), pluginId, itemKey, dx, dy, anchorWindow (the window containing the plugin item)
104+
void moveXEmbedWindowRequested(uint32_t wid, const QString &pluginId, const QString &itemKey, double dx, double dy, QQuickWindow *anchorWindow);
104105

105106
private Q_SLOTS:
106107
void onFontChanged();
@@ -192,10 +193,15 @@ class PluginSurface : public QWaylandShellSurfaceTemplate<PluginSurface>, public
192193

193194
Q_INVOKABLE void updatePluginGeometry(const QRect &geometry);
194195
Q_INVOKABLE void setGlobalPos(const QPoint &pos);
196+
Q_INVOKABLE void setAnchorWindow(QQuickWindow *window);
195197

196-
// Position relative to the dock window, set from QML via updatePluginGeometry
198+
// Position relative to the containing window, set from QML via updatePluginGeometry
197199
QPoint itemPosition() const;
198200

201+
QQuickWindow *anchorWindow() const;
202+
203+
QPoint lastGlobalPos() const { return m_lastGlobalPos; }
204+
199205
int margins() const;
200206
void setMargins(int newMargins);
201207

@@ -234,7 +240,9 @@ class PluginSurface : public QWaylandShellSurfaceTemplate<PluginSurface>, public
234240
int m_margins = 0;
235241
int m_height;
236242
int m_width;
237-
QPoint m_itemPosition; // Position relative to dock window, for XEmbed window positioning
243+
QPoint m_itemPosition;
244+
QPointer<QQuickWindow> m_anchorWindow;
245+
QPoint m_lastGlobalPos; // Last raw global position from QML (itemGlobalPos), logical pixels
238246
};
239247

240248
class PluginPopup : public QWaylandShellSurfaceTemplate<PluginPopup>, public QtWaylandServer::plugin_popup

panels/dock/tray/package/ActionLegacyTrayPluginDelegate.qml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ AppletItemButton {
9292
if (!pluginItem.plugin || !itemVisible)
9393
return
9494
updatePluginMargins()
95+
pluginItem.plugin.setAnchorWindow(pluginItem.Window.window)
9596
pluginItem.plugin.updatePluginGeometry(Qt.rect(pluginItem.itemGlobalPoint.x, pluginItem.itemGlobalPoint.y, 0, 0))
9697
pluginItem.plugin.setGlobalPos(pluginItem.itemGlobalPos)
9798
}
@@ -105,6 +106,7 @@ AppletItemButton {
105106
if (!pluginItem.plugin || !itemVisible)
106107
return
107108
updatePluginMargins()
109+
pluginItem.plugin.setAnchorWindow(pluginItem.Window.window)
108110
if (pluginItem.itemGlobalPoint.x >= 0 && pluginItem.itemGlobalPoint.y >= 0) {
109111
pluginItem.plugin.updatePluginGeometry(Qt.rect(pluginItem.itemGlobalPoint.x, pluginItem.itemGlobalPoint.y, 0, 0))
110112
}

panels/dock/waylanddockhelper.cpp

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ void WaylandDockHelper::setDockColorTheme(const ColorTheme &theme)
152152
m_panel->setColorTheme(theme);
153153
}
154154

155-
bool WaylandDockHelper::moveXEmbedWindow(uint32_t wid, double dx, double dy)
155+
bool WaylandDockHelper::moveXEmbedWindow(uint32_t wid, double dx, double dy, QQuickWindow *anchorWindow)
156156
{
157157
// Update dock wl_surface if needed
158158
if (!m_dockWlSurface && m_panel->window()) {
@@ -162,14 +162,43 @@ bool WaylandDockHelper::moveXEmbedWindow(uint32_t wid, double dx, double dy)
162162
}
163163
}
164164

165-
if (!m_ddeShellManager || !m_ddeShellManager->isActive() || !m_dockWlSurface) {
165+
struct ::wl_surface *anchorSurface = m_dockWlSurface;
166+
167+
if (anchorWindow) {
168+
auto waylandWindow = dynamic_cast<QtWaylandClient::QWaylandWindow*>(anchorWindow->handle());
169+
if (waylandWindow && waylandWindow->waylandSurface()) {
170+
anchorSurface = waylandWindow->waylandSurface()->object();
171+
}
172+
}
173+
174+
if (!m_ddeShellManager || !m_ddeShellManager->isActive() || !anchorSurface) {
166175
qWarning() << "WaylandDockHelper::moveXEmbedWindow: not ready, manager active:"
167176
<< (m_ddeShellManager && m_ddeShellManager->isActive())
168-
<< "surface:" << (m_dockWlSurface != nullptr);
177+
<< "surface:" << (anchorSurface != nullptr);
169178
return false;
170179
}
171180

172-
m_ddeShellManager->setXWindowPositionRelative(wid, m_dockWlSurface, dx, dy);
181+
struct wl_callback *cb = m_ddeShellManager->setXWindowPositionRelative(wid, anchorSurface, dx, dy);
182+
183+
// Register wl_callback listener — result arrives asynchronously
184+
if (!cb) {
185+
qWarning() << "WaylandDockHelper::moveXEmbedWindow: setXWindowPositionRelative returned null callback";
186+
Q_EMIT xembedWindowMoveResult(wid, false);
187+
return true;
188+
}
189+
190+
struct CallbackData { uint32_t wid; WaylandDockHelper *helper; };
191+
static struct wl_callback_listener s_callbackListener = {
192+
.done = [](void *data, wl_callback *callback, uint32_t callback_data) {
193+
auto *d = static_cast<CallbackData *>(data);
194+
bool success = (callback_data == 0);
195+
Q_EMIT d->helper->xembedWindowMoveResult(d->wid, success);
196+
wl_callback_destroy(callback);
197+
delete d;
198+
}
199+
};
200+
wl_callback_add_listener(cb, &s_callbackListener, new CallbackData{wid, this});
201+
173202
return true;
174203
}
175204

panels/dock/waylanddockhelper.h

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,14 @@ class WaylandDockHelper : public DockHelper
3131
void setDockColorTheme(const ColorTheme &theme);
3232
QString dockScreenName();
3333

34-
// Move XEmbed window relative to dock surface
35-
// dx, dy: offset relative to dock surface top-left
36-
// Returns true if the request was sent successfully
37-
bool moveXEmbedWindow(uint32_t wid, double dx, double dy) override;
34+
// Move XEmbed window relative to anchor window's surface
35+
// anchorWindow: the window containing the plugin item; falls back to dock panel if null
36+
// dx, dy: offset relative to anchor window top-left
37+
// Returns true if the request was sent (does NOT guarantee completion)
38+
bool moveXEmbedWindow(uint32_t wid, double dx, double dy, QQuickWindow *anchorWindow = nullptr) override;
39+
40+
Q_SIGNALS:
41+
void xembedWindowMoveResult(uint32_t wid, bool success);
3842

3943
protected:
4044
bool currentActiveWindowFullscreened() override;

0 commit comments

Comments
 (0)