Skip to content

feat: support move xembed window on treeland#1573

Merged
justforlxz merged 1 commit into
linuxdeepin:masterfrom
BLumia:xembed-treeland-move
May 26, 2026
Merged

feat: support move xembed window on treeland#1573
justforlxz merged 1 commit into
linuxdeepin:masterfrom
BLumia:xembed-treeland-move

Conversation

@BLumia
Copy link
Copy Markdown
Member

@BLumia BLumia commented Apr 28, 2026

通过 treeland 提供的 API 移动 xembed 窗口。

@BLumia BLumia requested a review from tsic404 April 28, 2026 09:02
@deepin-ci-robot
Copy link
Copy Markdown

Skipping CI for Draft Pull Request.
If you want CI signal for your change, please convert it to an actual PR.
You can still manually trigger a test run with /test all

Copy link
Copy Markdown

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry @BLumia, you have reached your weekly rate limit of 500000 diff characters.

Please try again later or upgrade to continue using Sourcery

@BLumia BLumia force-pushed the xembed-treeland-move branch from 18de6a1 to d0bfc61 Compare April 28, 2026 09:44
Comment thread panels/dock/pluginmanagerextension.cpp Outdated
return false;
}

m_ddeShellManager->setXWindowPositionRelative(wid, m_dockWlSurface, dx, dy);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

此处都是基于 dockWlSurface 进行偏移,是否有考虑托盘在展开区域情况呢?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

此 PR 中不考虑,后续 PR 中支持。

@deepin-bot
Copy link
Copy Markdown

deepin-bot Bot commented Apr 29, 2026

TAG Bot

New tag: 2.0.39
DISTRIBUTION: unstable
Suggest: synchronizing this PR through rebase #1580

@BLumia BLumia force-pushed the xembed-treeland-move branch from d0bfc61 to ebce64c Compare May 7, 2026 02:15
@deepin-bot
Copy link
Copy Markdown

deepin-bot Bot commented May 9, 2026

TAG Bot

New tag: 2.0.40
DISTRIBUTION: unstable
Suggest: synchronizing this PR through rebase #1592

@deepin-bot
Copy link
Copy Markdown

deepin-bot Bot commented May 14, 2026

TAG Bot

New tag: 2.0.41
DISTRIBUTION: unstable
Suggest: synchronizing this PR through rebase #1596

@deepin-bot
Copy link
Copy Markdown

deepin-bot Bot commented May 20, 2026

TAG Bot

New tag: 2.0.42
DISTRIBUTION: unstable
Suggest: synchronizing this PR through rebase #1603

@BLumia BLumia force-pushed the xembed-treeland-move branch from ebce64c to 9212ff4 Compare May 20, 2026 10:13
@BLumia BLumia marked this pull request as ready for review May 26, 2026 06:28
Copy link
Copy Markdown

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry @BLumia, you have reached your weekly rate limit of 500000 diff characters.

Please try again later or upgrade to continue using Sourcery

justforlxz
justforlxz previously approved these changes May 26, 2026
Copy link
Copy Markdown
Member

@justforlxz justforlxz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

按揭修复

通过 treeland 提供的 API 移动 xembed 窗口

Log:
@deepin-ci-robot
Copy link
Copy Markdown

deepin pr auto review

你好!我是CodeGeeX。我已仔细审查了你提交的Git Diff。此次代码变更的主要目的是在Wayland环境下,实现任务栏中XEmbed窗口相对于任务栏表面的移动定位功能,涉及从Wayland协议解析、QML信号传递到C++后端调用的完整链路。

整体来看,代码逻辑清晰,模块划分合理,但在生命周期管理、并发安全、Wayland资源使用规范以及代码性能方面存在一些需要改进的隐患。以下是详细的审查意见:

一、 代码安全

1. Wayland资源生命周期悬空指针风险(严重)
pluginmanagerextension.cpp.h 中,你使用了 PendingXEmbedCallback 结构体来保存 wl_resource *resource,以便在异步回调时获取 wl_client

struct PendingXEmbedCallback {
    uint32_t callback;
    struct ::wl_resource *resource; // 危险:存储了原始指针
};

Wayland客户端可能在请求发出后、回调执行前崩溃或断开连接,此时 resource 已经被销毁。后续在 notifyXEmbedWindowMoveResult 中调用 wl_resource_get_client(pending.resource) 会导致悬空指针访问(Use-After-Free),造成程序崩溃。
改进意见:不要存储 wl_resource *,而是在请求到来时直接存储 wl_client *,因为 wl_client 的生命周期由服务端的 wl_display 管理,即使客户端断开,在 wl_client_destroy 触发前它也是安全的。更好的做法是监听客户端的 wl_client_destroy 信号,在客户端销毁时清理其对应的所有 pending callbacks。

2. QML注入与类型校验风险
DockCompositor.qml 中:

property var moveXEmbedWindowHandler: null
// ...
if (typeof dockCompositor.moveXEmbedWindowHandler === 'function') {
    var success = dockCompositor.moveXEmbedWindowHandler(wid, dx, dy)

wid 传递到了 C++ 的 moveXEmbedWindow,其参数类型是 uint32_t。QML 的弱类型特性允许传入非数字类型(如字符串、对象),这可能导致 C++ 层发生隐式转换错误或断言失败。
改进意见:在 C++ 层的 DockPanel::moveXEmbedWindow 增加严格的类型校验,或者使用 Q_DECLARE_METATYPE 及注册类型系统来强化边界。同时在 QML 中建议加一层简单的类型守卫:

if (typeof wid === 'number' && typeof dx === 'number' && typeof dy === 'number') { ... }

二、 语法与逻辑

1. Wayland回调ID的误用(严重)
plugin_manager_v1_move_xembed_window 中:

wl_resource *callbackResource = wl_resource_create(resource->client(), &wl_callback_interface, 
                                                   1, callback);

Wayland协议中,callback 参数(通常名为 id)是一个新对象的ID(new_id),由客户端分配。它不是用于 wl_resource_create 的第四个参数。wl_resource_create 的第四个参数是服务端分配的版本号。直接将客户端传来的 ID 强行作为版本号传入,会破坏 Wayland 对象注册表,导致协议解析错误。
改进意见:如果你使用的是 QtWayland 生成的代码,通常框架已经帮你处理了 new_id 的资源创建。如果是手动实现,你需要使用 wl_resource_create(client, &wl_callback_interface, version, id),其中 version 应该从父 resource 获取(如 wl_resource_get_version(resource->handle)),而 id 才是客户端传来的 callback 变量。

2. dxdy 的语义混淆
pluginmanagerextension.cpp 中:

double dx = pluginSurface->itemPosition().x();
double dy = pluginSurface->itemPosition().y();

变量名 dxdy 在图形学和数学中通常表示“增量”或“偏移量”。但这里你获取的是 itemPosition 的绝对坐标,将其命名为 dx/dy 会导致严重的阅读误解。
改进意见:重命名为 xy,或者 posX / posY

3. 版权年份的修改

-// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
+// SPDX-FileCopyrightText: 2023 - 2026 UnionTech Software Technology Co., Ltd.

将版权年份修改为未来的年份(2026)不符合开源规范。版权年份应当是代码首次发表或修改的真实年份。
改进意见:如果是今年修改,应改为 2023 - 20242023, 2024

三、 代码性能

1. findPluginSurface 的线性查找

PluginSurface* PluginManager::findPluginSurface(const QString &pluginId, const QString &itemKey) const
{
    for (PluginSurface *plugin : m_pluginSurfaces) {
        if (plugin->pluginId() == pluginId && plugin->itemKey() == itemKey) {
            return plugin;
        }
    }
    return nullptr;
}

每次移动 XEmbed 窗口都会触发一次 $O(N)$ 复杂度的遍历,且涉及两次 QString 比较。如果插件数量较多或移动事件触发频率高(如跟随拖拽),会产生不必要的性能开销。
改进意见:建议在 PluginManager 中维护一个 QHash<QPair<QString, QString>, PluginSurface*>QMap,在插件创建和销毁时同步更新,将查找复杂度降至 $O(1)$

四、 代码质量

1. 并发请求的潜在逻辑漏洞
代码中用 QMap<uint32_t, PendingXEmbedCallback> m_pendingXEmbedCallbacks; 支持并发请求,以 wid 为键。但如果同一个 wid 连续发起多次移动请求,而前一次的回调还未处理,take 操作会覆盖旧的回调,导致旧的回调永远无法触发,造成 Wayland 客户端的回调等待死锁。
改进意见:如果业务逻辑保证同一窗口不会并发请求,则无需支持并发的复杂数据结构;如果必须支持,插入时需检查是否已存在并主动触发旧回调的取消逻辑(如发送 cancelled 或立即返回失败)。

2. QML 中的 console.log 遗留

onMoveXEmbedWindowRequested: (wid, pluginId, itemKey, dx, dy) => {
    console.log("move xembed window requested:", wid, pluginId, itemKey, dx, dy)

在频繁触发的事件(如窗口移动)中保留 console.log 会严重影响性能,且容易将内部数据结构暴露到系统日志中。
改进意见:移除或降级为 console.debug,并在发布构建中关闭此类调试输出。

3. wl_surface 原始指针的存储
waylanddockhelper.h 中:

struct ::wl_surface *m_dockWlSurface = nullptr;

存储 Wayland 核心对象的原始指针同样面临生命周期问题。如果 Dock 窗口因为屏幕变化被销毁重建,这个指针将失效。
改进意见:在 moveXEmbedWindow 中动态获取 m_panel->window()->handle(),而不是缓存这个指针。如果为了性能必须缓存,必须监听窗口销毁事件将其置空。


综合修改建议示例(针对核心问题):

C++ 端 pluginmanagerextension_p.h 修改:

struct PendingXEmbedCallback {
    uint32_t callback_id; // 客户端传来的 new_id
    struct ::wl_client *client; // 存储客户端指针,而非 resource 指针
    uint32_t resource_version;  // 记录请求时的版本号
};

C++ 端 pluginmanagerextension.cpp 修改:

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)
{
    // ... 寻找 pluginSurface 逻辑不变 ...
    
    // 记录客户端和版本号
    m_pendingXEmbedCallbacks[xembed_winid] = {
        callback, 
        wl_resource_get_client(resource->handle),
        wl_resource_get_version(resource->handle)
    };
    
    // 注意变量名修改为 posX, posY
    double posX = pluginSurface->itemPosition().x();
    double posY = pluginSurface->itemPosition().y();
    Q_EMIT moveXEmbedWindowRequested(xembed_winid, plugin_id, item_key, posX, posY);
}

void PluginManager::notifyXEmbedWindowMoveResult(uint32_t wid, bool success)
{
    if (!m_pendingXEmbedCallbacks.contains(wid)) return;
    
    PendingXEmbedCallback pending = m_pendingXEmbedCallbacks.take(wid);
    
    // 使用存储的 client 和 version 正确创建回调资源
    wl_resource *callbackResource = wl_resource_create(
        pending.client, 
        &wl_callback_interface, 
        pending.resource_version,  // 使用正确的版本号
        pending.callback_id        // 客户端指定的 new_id
    );
    
    if (callbackResource) {
        wl_callback_send_done(callbackResource, success ? 0 : 1);
        wl_resource_destroy(callbackResource);
    }
}

希望这些审查意见对你有所帮助!如果有任何细节需要进一步讨论,欢迎随时提问。

@deepin-ci-robot
Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: BLumia, justforlxz

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@justforlxz justforlxz merged commit 46c66aa into linuxdeepin:master May 26, 2026
9 of 12 checks passed
@BLumia BLumia deleted the xembed-treeland-move branch May 26, 2026 09:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants