Skip to content

Commit 18de6a1

Browse files
committed
feat: support move xembed window on treeland
通过 treeland 提供的 API 移动 xembed 窗口 Log:
1 parent 2ccf53c commit 18de6a1

8 files changed

Lines changed: 132 additions & 0 deletions

panels/dock/DockCompositor.qml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,18 @@ Item {
113113
console.log("quick panel closed")
114114
dockCompositor.popupClosed()
115115
}
116+
117+
onMoveXEmbedWindowRequested: (wid, pluginId, itemKey) => {
118+
console.log("move xembed window requested:", wid, pluginId, itemKey)
119+
// Delegate to Panel which has access to WaylandDockHelper
120+
if (Panel && typeof Panel.moveXEmbedWindow === 'function') {
121+
var success = Panel.moveXEmbedWindow(wid, pluginId, itemKey)
122+
pluginManager.notifyXEmbedWindowMoveResult(success)
123+
} else {
124+
console.warn("Panel.moveXEmbedWindow not available")
125+
pluginManager.notifyXEmbedWindowMoveResult(false)
126+
}
127+
}
116128
}
117129

118130
PluginScaleManager{

panels/dock/dockhelper.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ class DockHelper : public QObject
2121

2222
void enterScreen(QScreen *screen);
2323
void leaveScreen();
24+
25+
// Move XEmbed window relative to dock surface (no-op on X11)
26+
virtual bool moveXEmbedWindow(uint32_t wid, const QString &pluginId, const QString &itemKey) { return false; }
2427

2528
Q_SIGNALS:
2629
void isWindowOverlapChanged(bool overlap);

panels/dock/dockpanel.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -481,6 +481,14 @@ void DockPanel::setIsResizing(bool resizing)
481481
m_isResizing = resizing;
482482
emit isResizingChanged(m_isResizing);
483483
}
484+
485+
bool DockPanel::moveXEmbedWindow(uint32_t wid, const QString &pluginId, const QString &itemKey)
486+
{
487+
if (m_helper) {
488+
return m_helper->moveXEmbedWindow(wid, pluginId, itemKey);
489+
}
490+
return false;
491+
}
484492
}
485493

486494
#include "dockpanel.moc"

panels/dock/dockpanel.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,9 @@ class DockPanel : public DS_NAMESPACE::DPanel, public QDBusContext
8383
Q_INVOKABLE void openDockSettings() const;
8484

8585
Q_INVOKABLE void notifyDockPositionChanged(int offsetX, int offsetY);
86+
87+
// Move XEmbed window relative to dock surface (Wayland only)
88+
Q_INVOKABLE bool moveXEmbedWindow(uint32_t wid, const QString &pluginId, const QString &itemKey);
8689

8790
bool showInPrimary() const;
8891
void setShowInPrimary(bool newShowInPrimary);

panels/dock/pluginmanagerextension.cpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <DPlatformTheme>
1111

1212
#include <cstdint>
13+
#include <wayland-server-core.h>
1314

1415
#include <QtWaylandCompositor/QWaylandSurface>
1516
#include <QtWaylandCompositor/QWaylandResource>
@@ -673,6 +674,38 @@ void PluginManager::plugin_manager_v1_create_popup_at(Resource *resource, const
673674
Q_EMIT pluginPopupCreated(plugin);
674675
}
675676

677+
void PluginManager::plugin_manager_v1_move_xembed_window(Resource *resource, uint32_t xembed_winid, const QString &plugin_id, const QString &item_key, uint32_t callback)
678+
{
679+
Q_UNUSED(resource)
680+
qInfo() << "server pluginManager receive move_xembed_window:" << xembed_winid << plugin_id << item_key;
681+
682+
// Store pending callback for later response
683+
m_pendingXEmbedCallback = callback;
684+
m_pendingXEmbedClient = resource->client();
685+
686+
// Emit signal for QML to handle
687+
Q_EMIT moveXEmbedWindowRequested(xembed_winid, plugin_id, item_key);
688+
}
689+
690+
void PluginManager::notifyXEmbedWindowMoveResult(bool success)
691+
{
692+
if (m_pendingXEmbedCallback > 0 && m_pendingXEmbedClient) {
693+
wl_resource *callbackResource = wl_resource_create(m_pendingXEmbedClient, &wl_callback_interface,
694+
1, m_pendingXEmbedCallback);
695+
if (callbackResource) {
696+
wl_callback_send_done(callbackResource, success ? 0 : 1);
697+
wl_resource_destroy(callbackResource);
698+
}
699+
}
700+
m_pendingXEmbedCallback = 0;
701+
m_pendingXEmbedClient = nullptr;
702+
}
703+
704+
void PluginManager::setMoveXEmbedWindowCallback(MoveXEmbedWindowCallback callback)
705+
{
706+
m_moveXEmbedWindowCallback = std::move(callback);
707+
}
708+
676709
QJsonObject PluginManager::getRootObj(const QString &jsonStr) {
677710
QJsonParseError jsonParseError;
678711
const QJsonDocument &resultDoc = QJsonDocument::fromJson(jsonStr.toLocal8Bit(), &jsonParseError);

panels/dock/pluginmanagerextension_p.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,10 @@ class PluginManager : public QWaylandCompositorExtensionTemplate<PluginManager>,
6565

6666
Q_INVOKABLE void updateDockOverflowState(int state);
6767
Q_INVOKABLE void setPopupMinHeight(int height);
68+
69+
// Called from QML when moveXEmbedWindowRequested is handled
70+
// result: true = success, false = error
71+
Q_INVOKABLE void notifyXEmbedWindowMoveResult(bool result);
6872

6973
uint32_t dockPosition() const;
7074
void setDockPosition(uint32_t dockPosition);
@@ -92,6 +96,9 @@ class PluginManager : public QWaylandCompositorExtensionTemplate<PluginManager>,
9296
void messageRequest(PluginSurface *, const QString &msg);
9397
void dockSizeChanged();
9498
void requestShutdown(const QString &type);
99+
// Signal emitted when XEmbed window move is requested
100+
// Parameters: wid (window ID), pluginId, itemKey
101+
void moveXEmbedWindowRequested(uint32_t wid, const QString &pluginId, const QString &itemKey);
95102

96103
private Q_SLOTS:
97104
void onFontChanged();
@@ -103,6 +110,13 @@ private Q_SLOTS:
103110
virtual void plugin_manager_v1_request_message(Resource *resource, const QString &plugin_id, const QString &item_key, const QString &msg) override;
104111
virtual void plugin_manager_v1_create_popup_at(Resource *resource, const QString &plugin_id, const QString &item_key, int32_t type, int32_t x, int32_t y, struct ::wl_resource *surface, uint32_t id) override;
105112
virtual void plugin_manager_v1_create_plugin(Resource *resource, const QString &plugin_id, const QString &item_key, const QString &display_name, int32_t plugin_flags, int32_t type, int32_t size_policy, struct ::wl_resource *surface, uint32_t id) override;
113+
virtual void plugin_manager_v1_move_xembed_window(Resource *resource, uint32_t xembed_winid, const QString &plugin_id, const QString &item_key, uint32_t callback) override;
114+
115+
public:
116+
// Set callback for XEmbed window move requests
117+
// The callback should return true if the move was successful
118+
using MoveXEmbedWindowCallback = std::function<bool(uint32_t wid, const QString &pluginId, const QString &itemKey)>;
119+
void setMoveXEmbedWindowCallback(MoveXEmbedWindowCallback callback);
106120

107121
private:
108122
static QJsonObject getRootObj(const QString &jsonStr);
@@ -121,6 +135,11 @@ private Q_SLOTS:
121135
uint32_t m_dockColorTheme = 0;
122136
QSize m_dockSize;
123137
int m_popupMinHeight = 0;
138+
MoveXEmbedWindowCallback m_moveXEmbedWindowCallback;
139+
140+
// For pending XEmbed callback response
141+
uint32_t m_pendingXEmbedCallback = 0;
142+
struct ::wl_client *m_pendingXEmbedClient = nullptr;
124143
};
125144

126145
class PluginSurface : public QWaylandShellSurfaceTemplate<PluginSurface>, public QtWaylandServer::plugin

panels/dock/waylanddockhelper.cpp

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,14 @@ WaylandDockHelper::WaylandDockHelper(DockPanel *panel)
2828
if (auto applet = bridge.applet()) {
2929
connect(applet, SIGNAL(windowFullscreenChanged(bool)), this, SLOT(setCurrentActiveWindowFullscreened(bool)));
3030
}
31+
32+
// Store dock window's wl_surface for XEmbed window positioning
33+
if (m_panel->window()) {
34+
auto waylandWindow = dynamic_cast<QtWaylandClient::QWaylandWindow*>(m_panel->window()->handle());
35+
if (waylandWindow) {
36+
m_dockWlSurface = waylandWindow->waylandSurface()->object();
37+
}
38+
}
3139

3240
connect(m_panel, &DockPanel::rootObjectChanged, this, [this]() {
3341
m_wallpaperColorManager->watchScreen(dockScreenName());
@@ -144,6 +152,35 @@ void WaylandDockHelper::setDockColorTheme(const ColorTheme &theme)
144152
m_panel->setColorTheme(theme);
145153
}
146154

155+
bool WaylandDockHelper::moveXEmbedWindow(uint32_t wid, const QString &pluginId, const QString &itemKey)
156+
{
157+
// Update dock wl_surface if needed
158+
if (!m_dockWlSurface && m_panel->window()) {
159+
auto waylandWindow = dynamic_cast<QtWaylandClient::QWaylandWindow*>(m_panel->window()->handle());
160+
if (waylandWindow && waylandWindow->waylandSurface()) {
161+
m_dockWlSurface = waylandWindow->waylandSurface()->object();
162+
}
163+
}
164+
165+
if (!m_ddeShellManager || !m_ddeShellManager->isActive() || !m_dockWlSurface) {
166+
qWarning() << "WaylandDockHelper::moveXEmbedWindow: not ready, manager active:"
167+
<< (m_ddeShellManager && m_ddeShellManager->isActive())
168+
<< "surface:" << (m_dockWlSurface != nullptr);
169+
return false;
170+
}
171+
172+
// The XEmbed window position is relative to the plugin item's position in the dock
173+
// For now, we use (0, 0) as the offset since the actual position calculation
174+
// should be done by the treeland compositor based on the anchor surface
175+
// The (dx, dy) offset will be calculated based on the plugin item's position
176+
//
177+
// TODO: We may need to get the actual plugin item position from the QML side
178+
// and pass it as the offset. For now, using (0, 0) as the window will be
179+
// positioned at the dock surface's top-left corner.
180+
m_ddeShellManager->setXWindowPositionRelative(wid, m_dockWlSurface, 0.0, 0.0);
181+
return true;
182+
}
183+
147184
WallpaperColorManager::WallpaperColorManager(WaylandDockHelper *helper)
148185
: QWaylandClientExtensionTemplate<WallpaperColorManager>(treeland_wallpaper_color_manager_v1_interface.version)
149186
, m_helper(helper)
@@ -169,6 +206,14 @@ TreeLandDDEShellManager::TreeLandDDEShellManager()
169206
{
170207
}
171208

209+
struct ::wl_callback *TreeLandDDEShellManager::setXWindowPositionRelative(uint32_t wid, struct ::wl_surface *anchor, double dx, double dy)
210+
{
211+
if (!isActive()) {
212+
return nullptr;
213+
}
214+
return QtWayland::treeland_dde_shell_manager_v1::set_xwindow_position_relative(wid, anchor, wl_fixed_from_double(dx), wl_fixed_from_double(dy));
215+
}
216+
172217
TreeLandWindowOverlapChecker::TreeLandWindowOverlapChecker(WaylandDockHelper *helper, struct ::treeland_window_overlap_checker *checker)
173218
: QWaylandClientExtensionTemplate<TreeLandWindowOverlapChecker>(treeland_dde_shell_manager_v1_interface.version)
174219
, m_helper(helper)

panels/dock/waylanddockhelper.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ class WaylandDockHelper : public DockHelper
3030

3131
void setDockColorTheme(const ColorTheme &theme);
3232
QString dockScreenName();
33+
34+
// Move XEmbed window relative to dock surface
35+
// Returns true if the request was sent successfully
36+
bool moveXEmbedWindow(uint32_t wid, const QString &pluginId, const QString &itemKey);
3337

3438
protected:
3539
bool currentActiveWindowFullscreened() override;
@@ -51,6 +55,7 @@ protected Q_SLOTS:
5155
QScopedPointer<WallpaperColorManager> m_wallpaperColorManager;
5256
QScopedPointer<TreeLandWindowOverlapChecker> m_overlapChecker;
5357
QScopedPointer<TreeLandDDEShellManager> m_ddeShellManager;
58+
struct ::wl_surface *m_dockWlSurface = nullptr; // Dock's wl_surface for XEmbed positioning
5459
};
5560

5661
class WallpaperColorManager : public QWaylandClientExtensionTemplate<WallpaperColorManager>, public QtWayland::treeland_wallpaper_color_manager_v1
@@ -75,6 +80,10 @@ class TreeLandDDEShellManager : public QWaylandClientExtensionTemplate<TreeLandD
7580

7681
public:
7782
explicit TreeLandDDEShellManager();
83+
84+
// Move XEmbed window to position relative to anchor surface
85+
// Returns wl_callback* or nullptr if not active
86+
struct ::wl_callback *setXWindowPositionRelative(uint32_t wid, struct ::wl_surface *anchor, double dx, double dy);
7887
};
7988

8089
class TreeLandWindowOverlapChecker : public QWaylandClientExtensionTemplate<TreeLandWindowOverlapChecker>, public QtWayland::treeland_window_overlap_checker

0 commit comments

Comments
 (0)