Skip to content

Conversation

@BLumia
Copy link
Member

@BLumia BLumia commented Jan 15, 2026

Log:

Summary by Sourcery

Introduce a Wayland protocol and client integration for moving XEmbed windows via the plugin manager, preparing Wayland-specific handling in the application tray.

New Features:

  • Add a move_xembed_window request and plugin_manager_callback_v1 interface to the plugin manager Wayland protocol for repositioning XEmbed windows.
  • Expose a moveXembedWindow API in PluginManagerIntegration with a corresponding PluginManagerCallback object for asynchronous completion handling.

Enhancements:

  • Begin wiring Wayland-specific XEmbed window movement in the application tray handler, gated by XDG_SESSION_TYPE detection.

@BLumia BLumia requested a review from tsic404 January 15, 2026 11:11
@deepin-ci-robot
Copy link

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: BLumia

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

@sourcery-ai
Copy link

sourcery-ai bot commented Jan 15, 2026

Reviewer's Guide

Adds a new Wayland protocol request and callback interface to move XEmbed windows via the plugin manager, exposes this as an asynchronous callback-based API in PluginManagerIntegration, and wires in initial Wayland-specific handling in the Xembed protocol handler (currently with a TODO).

Sequence diagram for move_xembed_window request and callback

sequenceDiagram
    actor User
    participant XembedProtocolHandler
    participant EmbedPlugin
    participant PluginManagerIntegration
    participant WaylandCompositor
    participant PluginManagerCallback

    User->>XembedProtocolHandler: triggers input on tray icon
    XembedProtocolHandler->>XembedProtocolHandler: detect Wayland session
    XembedProtocolHandler->>EmbedPlugin: get(windowHandle)
    EmbedPlugin-->>XembedProtocolHandler: plugin_id, item_key
    XembedProtocolHandler->>PluginManagerIntegration: moveXembedWindow(xembedWinId, plugin_id, item_key)
    PluginManagerIntegration->>PluginManagerIntegration: create PluginManagerCallback instance
    PluginManagerIntegration->>WaylandCompositor: plugin_manager_v1.move_xembed_window(xembed_winid, plugin_id, item_key, callback)
    WaylandCompositor-->>PluginManagerCallback: plugin_manager_callback_v1.done
    PluginManagerCallback->>PluginManagerCallback: plugin_manager_callback_v1_done()
    PluginManagerCallback-->>PluginManagerCallback: emit done()
Loading

Class diagram for PluginManagerIntegration and PluginManagerCallback changes

classDiagram
    class PluginManagerIntegration {
        +void requestMessage(QString plugin_id, QString item_key, QString msg)
        +PluginManagerCallback* moveXembedWindow(uint32_t xembedWinId, QString pluginId, QString itemKey)
        +void plugin_manager_v1_position_changed(uint32_t dock_position)
        +bool tryCreatePopupForSubWindow(QWindow* window)
        -uint32_t m_dockPosition
        -uint32_t m_dockColorType
        -static PluginManagerIntegration* s_instance
    }

    class PluginManagerCallback {
        +PluginManagerCallback()
        +~PluginManagerCallback()
        +signal void done()
        +void plugin_manager_callback_v1_done()
    }

    class QObject
    class QtWaylandClient_QWaylandShellIntegrationTemplate_PluginManagerIntegration
    class QtWayland_plugin_manager_v1
    class QtWayland_plugin_manager_callback_v1

    PluginManagerIntegration ..|> QtWaylandClient_QWaylandShellIntegrationTemplate_PluginManagerIntegration
    PluginManagerIntegration ..|> QtWayland_plugin_manager_v1

    PluginManagerCallback ..|> QObject
    PluginManagerCallback ..|> QtWayland_plugin_manager_callback_v1

    PluginManagerIntegration --> PluginManagerCallback : creates
Loading

File-Level Changes

Change Details Files
Extend plugin-manager Wayland protocol with a move_xembed_window request and generic async callback interface.
  • Add move_xembed_window request to plugin_manager_v1 interface, including xembed_winid, plugin_id, item_key, and a callback new_id argument.
  • Introduce plugin_manager_callback_v1 interface with destroy request and done event for signaling async completion.
src/protocol/plugin-manager-v1.xml
Expose a moveXembedWindow API in PluginManagerIntegration backed by the new Wayland protocol callback interface.
  • Add moveXembedWindow method that creates a PluginManagerCallback and calls move_xembed_window on the Wayland protocol object.
  • Introduce PluginManagerCallback class implementing QtWayland::plugin_manager_callback_v1 and emitting a Qt signal on done.
  • Declare a static PluginManagerIntegration *s_instance member for potential singleton-style access.
src/tray-wayland-integration/pluginmanagerintegration.cpp
src/tray-wayland-integration/pluginmanagerintegration_p.h
Prepare XembedProtocolHandler for using the new move_xembed_window request under Wayland sessions.
  • Include plugin.h to access Plugin::EmbedPlugin.
  • Add Wayland-specific branch in updateEmbedWindowPosForGetInputEvent that looks up the EmbedPlugin for the current window and will use move_xembed_window instead of direct X11 moves (currently left as a TODO).
  • Retain existing X11 window move behavior for non-Wayland sessions.
plugins/application-tray/xembedprotocolhandler.cpp

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link

@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.

Hey - I've found 2 issues, and left some high level feedback:

  • The new moveXembedWindow helper allocates a PluginManagerCallback but never passes a callback object to the Wayland move_xembed_window request (which expects a new_id), so the callback will never be wired up to protocol events; consider using the generated request overload that takes a plugin_manager_callback_v1 and binding it to the PluginManagerCallback instance.
  • Ownership and lifetime of PluginManagerCallback are unclear: moveXembedWindow returns a raw pointer that is never parented or deleted, which risks a leak; consider giving it a QObject parent (e.g., the caller or PluginManagerIntegration) or returning a smart pointer.
  • The Wayland branch in XembedProtocolHandler::updateEmbedWindowPosForGetInputEvent currently contains only a TODO and does not use the new protocol/methods, leaving Wayland behavior effectively unchanged; if this is intended to be usable now, wire it up to PluginManagerIntegration::moveXembedWindow with the retrieved plugin_id and item_key.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The new `moveXembedWindow` helper allocates a `PluginManagerCallback` but never passes a `callback` object to the Wayland `move_xembed_window` request (which expects a `new_id`), so the callback will never be wired up to protocol events; consider using the generated request overload that takes a `plugin_manager_callback_v1` and binding it to the `PluginManagerCallback` instance.
- Ownership and lifetime of `PluginManagerCallback` are unclear: `moveXembedWindow` returns a raw pointer that is never parented or deleted, which risks a leak; consider giving it a QObject parent (e.g., the caller or `PluginManagerIntegration`) or returning a smart pointer.
- The Wayland branch in `XembedProtocolHandler::updateEmbedWindowPosForGetInputEvent` currently contains only a TODO and does not use the new protocol/methods, leaving Wayland behavior effectively unchanged; if this is intended to be usable now, wire it up to `PluginManagerIntegration::moveXembedWindow` with the retrieved `plugin_id` and `item_key`.

## Individual Comments

### Comment 1
<location> `src/tray-wayland-integration/pluginmanagerintegration.cpp:51-54` </location>
<code_context>
     request_message(plugin_id, item_key, msg);
 }

+PluginManagerCallback *PluginManagerIntegration::moveXembedWindow(uint32_t xembedWinId, const QString &pluginId, const QString &itemKey)
+{
+    auto callback = new PluginManagerCallback();
+    move_xembed_window(xembedWinId, pluginId, itemKey);
+    return callback;
+}
</code_context>

<issue_to_address>
**issue (bug_risk):** The Wayland callback object is never wired to the `move_xembed_window` request, so it will never receive `done` events.

Here you allocate a `PluginManagerCallback` but never pass it to the Wayland `move_xembed_window` request, so its `plugin_manager_callback_v1_done()` will never be called. You should use the generated API overload that accepts a `plugin_manager_callback_v1 *` (or equivalent) and construct `PluginManagerCallback` with the proxy returned from `move_xembed_window`, for example:

```cpp
auto callback = new PluginManagerCallback(this, move_xembed_window(xembedWinId, pluginId, itemKey));
return callback;
```

Adjust the exact construction to match your generated bindings, ensuring the `new_id` callback proxy is bound to `PluginManagerCallback`.
</issue_to_address>

### Comment 2
<location> `src/tray-wayland-integration/pluginmanagerintegration_p.h:48-52` </location>
<code_context>
+    static PluginManagerIntegration *s_instance;
 };
+
+class PluginManagerCallback : public QObject, public QtWayland::plugin_manager_callback_v1
+{
+    Q_OBJECT
+public:
+    PluginManagerCallback();
+    ~PluginManagerCallback();
+
</code_context>

<issue_to_address>
**issue (bug_risk):** `PluginManagerCallback`'s construction doesn’t initialize the underlying Wayland proxy, which can break the generated base class expectations.

The generated `QtWayland::plugin_manager_callback_v1` is meant to be constructed with a valid `wl_registry`/`wl_proxy` (or via the `new_id` factory), not default-constructed. With the current empty ctor, the base may hold a null/invalid proxy and `plugin_manager_callback_v1_done()` could be called on an unbound object.

To avoid this, consider:
- Removing the public default constructor, and
- Adding a constructor that takes the handle returned for the `callback` `new_id` of `move_xembed_window` (e.g. a `struct ::wl_proxy *` or forwarding to the appropriate base-class ctor),
so the instance is always bound to the correct Wayland object.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@deepin-bot
Copy link

deepin-bot bot commented Jan 15, 2026

TAG Bot

New tag: 2.0.22
DISTRIBUTION: unstable
Suggest: synchronizing this PR through rebase #415

@BLumia BLumia force-pushed the protocol-move-xembed-window branch from b90a156 to 058940d Compare January 16, 2026 08:16
@deepin-ci-robot
Copy link

deepin pr auto review

Git Diff 代码审查报告

总体评估

这段代码主要实现了在 Wayland 会话下移动 XEmbed 窗口的功能,通过添加新的 Wayland 协议请求来替代 X11 会话下的直接窗口移动方法。整体实现思路正确,但在代码完整性、错误处理和资源管理方面存在一些问题。

详细审查意见

1. 语法逻辑问题

  1. 未完成的代码实现

    if (qgetenv("XDG_SESSION_TYPE") == "wayland") {
        // Get `plugin_id` and `item_key` from EmbedPlugin.
        auto plugin = Plugin::EmbedPlugin::get(window()->windowHandle());
        // use move_xembed_window to move m_containerWid to plugin_id.
        // TODO: ...?
    }
    • Wayland 分支中的代码未完成,只获取了 plugin 对象但没有实际调用移动窗口的方法
    • TODO 注释表明这是待完成的功能,但提交了未完成的代码
  2. 静态成员变量声明但未定义

    class PluginManagerIntegration : public QtWaylandClient::QWaylandShellIntegratio
    // ...
    private:
        // ...
        static PluginManagerIntegration *s_instance;
    };
    • 声明了静态成员变量 s_instance 但在代码中没有看到定义和初始化

2. 代码质量问题

  1. 命名不一致

    struct ::wl_callback *PluginManagerIntegration::moveXembedWindow(uint32_t xembedWinId, const QString &pluginId, const QString &itemKey)
    • 函数名使用驼峰命名法 moveXembedWindow,而协议方法名使用下划线命名法 move_xembed_window
    • 参数命名不一致:pluginIditemKey 使用驼峰命名法,而协议中是 plugin_iditem_key
  2. 缺少错误处理

    • Plugin::EmbedPlugin::get() 可能返回空指针,但没有进行空指针检查
    • Wayland 回调对象没有设置回调处理函数,无法知道移动操作是否成功
  3. 资源管理问题

    struct ::wl_callback *PluginManagerIntegration::moveXembedWindow(uint32_t xembedWinId, const QString &pluginId, const QString &itemKey)
    {
        auto callback = move_xembed_window(xembedWinId, pluginId, itemKey);
        return callback;
    }
    • 返回的 wl_callback 对象没有明确说明由谁负责释放
    • 调用者可能不知道需要释放这个资源

3. 代码性能问题

  1. 频繁的环境变量查询
    if (qgetenv("XDG_SESSION_TYPE") == "wayland")
    • 每次调用 updateEmbedWindowPosForGetInputEvent() 都会查询环境变量
    • 建议在类初始化时缓存会话类型,避免重复查询

4. 代码安全问题

  1. 缺少参数验证

    • moveXembedWindow 方法没有验证传入的窗口 ID 是否有效
    • 没有验证 pluginIditemKey 是否为空或格式是否正确
  2. 协议安全性

    • Wayland 协议请求没有添加权限检查,任何插件都可以移动其他插件的窗口
    • 建议添加权限验证机制

5. 其他问题

  1. CMakeLists.txt 修改

    qt_generate_wayland_protocol_client_sources(dockpluginmanager
    NO_INCLUDE_CORE_ONLY
    FILES
        ${CMAKE_CURRENT_SOURCE_DIR}/../protocol/plugin-manager-v1.xml
    )
    • 添加了 NO_INCLUDE_CORE_ONLY 选项,但没有说明原因
    • 需要确认这个修改是否会影响其他功能
  2. 头文件包含

    #include "plugin.h"
    • 添加了新的头文件包含,但没有在 diff 中看到这个文件的内容
    • 需要确认这个头文件是否存在且包含正确

改进建议

  1. 完成 Wayland 分支中的代码实现,确保功能完整
  2. 添加错误处理和空指针检查
  3. 统一命名风格,建议遵循 Qt 的命名规范
  4. 明确资源管理责任,确保 wl_callback 对象被正确释放
  5. 缓存会话类型,避免重复查询环境变量
  6. 添加参数验证和权限检查
  7. 定义并初始化静态成员变量 s_instance
  8. 为 Wayland 回调添加处理函数,以便获取操作结果
  9. 添加必要的文档注释,说明函数用途、参数和返回值
  10. 考虑添加单元测试,确保新功能的正确性

示例改进代码

// 在类初始化时缓存会话类型
class XembedProtocolHandler {
    // ...
private:
    bool m_isWaylandSession = qgetenv("XDG_SESSION_TYPE") == "wayland";
};

QPoint XembedProtocolHandler::updateEmbedWindowPosForGetInputEvent()
{
    if (m_isWaylandSession) {
        auto plugin = Plugin::EmbedPlugin::get(window()->windowHandle());
        if (!plugin) {
            qWarning() << "Failed to get EmbedPlugin";
            return QPoint();
        }
        
        auto pluginId = plugin->pluginId();
        auto itemKey = plugin->itemKey();
        
        if (pluginId.isEmpty() || itemKey.isEmpty()) {
            qWarning() << "Invalid plugin_id or item_key";
            return QPoint();
        }
        
        // 创建回调处理函数
        auto callback = plugin->moveXembedWindow(m_containerWid, pluginId, itemKey);
        if (!callback) {
            qWarning() << "Failed to move xembed window";
            return QPoint();
        }
        
        // 设置回调处理函数
        wl_callback_add_listener(callback, &callbackListener, this);
        
        // 保存回调对象以便后续释放
        m_pendingCallbacks.append(callback);
    } else {
        QPoint p = UTIL->getMousePos();
        UTIL->moveX11Window(m_containerWid, p.x(), p.y());
    }

    // make window normal and above for get input
    UTIL->setX11WindowInputShape(m_containerWid, QSize(1, 1));
    
    return p;
}

总结

这段代码实现了在 Wayland 会话下移动 XEmbed 窗口的功能,但存在未完成的代码实现、错误处理不足、资源管理不明确等问题。建议在提交前完成代码实现,添加必要的错误处理和资源管理,并进行充分的测试。

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.

2 participants