Skip to content

feat(wm-helper): support system window menu on treeland/wayland#380

Merged
mhduiy merged 1 commit into
linuxdeepin:masterfrom
mhduiy:titleContextMenu
May 11, 2026
Merged

feat(wm-helper): support system window menu on treeland/wayland#380
mhduiy merged 1 commit into
linuxdeepin:masterfrom
mhduiy:titleContextMenu

Conversation

@mhduiy
Copy link
Copy Markdown
Contributor

@mhduiy mhduiy commented May 11, 2026

  1. Add Wayland-specific path for popupSystemWindowMenu
  2. Show window menu via QWaylandShellSurface for treeland compositor
  3. Include necessary Qt Wayland private headers

Log: Add Wayland window menu support for treeland compositor

feat(wm-helper): 支持 treeland/wayland 系统窗口菜单

  1. 为 popupSystemWindowMenu 添加 Wayland 专用路径
  2. 通过 QWaylandShellSurface 为 treeland 合成器显示窗口菜单
  3. 引入必要的 Qt Wayland 私有头文件

Log: 为 treeland 合成器添加 Wayland 窗口菜单支持
PMS: TASK-389419

1. Add Wayland-specific path for popupSystemWindowMenu
2. Show window menu via QWaylandShellSurface for treeland compositor
3. Include necessary Qt Wayland private headers

Log: Add Wayland window menu support for treeland compositor

feat(wm-helper): 支持 treeland/wayland 系统窗口菜单

1. 为 popupSystemWindowMenu 添加 Wayland 专用路径
2. 通过 QWaylandShellSurface 为 treeland 合成器显示窗口菜单
3. 引入必要的 Qt Wayland 私有头文件

Log: 为 treeland 合成器添加 Wayland 窗口菜单支持
PMS: TASK-389419
@deepin-ci-robot
Copy link
Copy Markdown
Contributor

deepin pr auto review

你好!我是CodeGeeX。我已仔细审查了你提供的 Git Diff。本次修改主要是在 DWindowManagerHelper::popupSystemWindowMenu 函数中增加了对 Wayland (Treeland) 平台的支持,通过调用 Qt Wayland 的私有 API 来实现弹出系统窗口菜单的功能。

以下是我从语法逻辑、代码质量、代码性能和代码安全四个维度提出的审查意见和改进建议:

1. 语法与逻辑

  • 潜在的空指针解引用
    在新增代码的 if (window && window->handle()) 判断中,虽然检查了 windowhandle() 是否为空,但在函数的最后一行原有代码中:
    return callPlatformFunction<void, void(*)(quint32)>(_popupSystemWindowMenu, quint32(window->handle()->winId()));
    如果在非 Wayland 平台下,传入的 window 为空或 handle() 未创建,这里会直接发生空指针解引用崩溃。虽然这不是本次修改引入的,但本次修改完善了 Wayland 分支的空指针检查,却留下了 X11 分支的隐患,建议一并修复。
  • 类型转换安全性
    使用 dynamic_cast 进行向下转型是正确的选择,但如果没有开启 RTTI 或者由于某些原因转换失败,dynamic_cast 会返回 nullptr。当前代码没有对转换后的 wlWindow 进行空指针检查就直接调用了 shellSurface()
  • Wayland 集成类型转换
    static_cast<QtWaylandClient::QWaylandIntegration*>(QGuiApplicationPrivate::platformIntegration()) 使用了 static_cast。如果当前平台不是 Wayland 但由于某种原因走入了此分支(例如环境变量欺骗),static_cast 会导致未定义行为。建议使用 dynamic_cast 并做检查,或者确认外层的 IsWaylandPlatform 判断已经足够严格。

2. 代码质量

  • 嵌套过深
    新增的代码存在 4 层 if 嵌套,这降低了代码的可读性。建议使用提前返回策略来扁平化代码结构。
  • 依赖 Qt 私有 API
    引入了 4 个 <private/...> 头文件。依赖 Qt 私有 API 会导致代码与特定的 Qt 版本强绑定,未来 Qt 升级(尤其是 Qt 6 到 Qt 7,或者 Qt Wayland 内部重构)时极易导致编译失败。建议:
    1. 在注释中明确标注依赖的 Qt 版本范围。
    2. 在 CMake 或 qmake 构建脚本中做好版本兼容性检查。
  • 魔法字符串/硬编码
    IsWaylandPlatform 的判断逻辑与具体的 Wayland 实现绑定。如果未来支持新的 Wayland 合成器,这里的逻辑可能需要修改。

3. 代码性能

  • 平台判断的开销
    DGuiApplicationHelper::testAttribute 通常是一个轻量级的查询,但在高频调用的场景下,如果每次都需要做类型转换和属性查询,会有微小的性能损耗。对于弹出菜单这种低频用户交互操作,目前的性能是完全可接受的,无需过度优化。

4. 代码安全

  • Wayland 协议安全
    调用 showWindowMenu 需要确保是在合法的用户交互(如鼠标右键事件)中触发的。Wayland 协议对弹出菜单有严格的时序和权限要求,如果随意调用,Wayland 合成器可能会直接断开客户端的连接。请确保此函数的调用上下文是安全的。
  • 私有 API 的稳定性风险
    如前所述,私有 API 没有向后兼容的承诺。这属于架构层面的安全性/稳定性风险。

改进后的代码建议

综合以上分析,我为你重构了这部分代码,主要改进点包括:减少嵌套、增加空指针保护、修复原有代码的潜在崩溃

#ifndef DTK_DISABLE_TREELAND
#include "plugins/platform/treeland/dtreelandwindowmanagerhelper.h"
#include <private/qguiapplication_p.h>
#include <private/qwaylandwindow_p.h>
#include <private/qwaylandshellsurface_p.h>
#include <private/qwaylandintegration_p.h>
#endif

DGUI_BEGIN_NAMESPACE

// ... 省略其他代码 ...

void DWindowManagerHelper::popupSystemWindowMenu(const QWindow *window)
{
#ifndef DTK_DISABLE_TREELAND
    if (DGuiApplicationHelper::testAttribute(DGuiApplicationHelper::IsWaylandPlatform)) {
        // 1. 提前返回 空指针检查
        if (!window || !window->handle()) {
            return;
        }

        // 2. 使用 dynamic_cast 安全转换,并检查结果
        auto *wlWindow = dynamic_cast<QtWaylandClient::QWaylandWindow*>(window->handle());
        if (!wlWindow) {
            return;
        }

        auto *shellSurface = wlWindow->shellSurface();
        if (!shellSurface) {
            return;
        }

        // 3. 使用 dynamic_cast 替代 static_cast 防御未定义行为,或者确信 IsWaylandPlatform 已保证安全
        // 如果 IsWaylandPlatform 绝对可靠,static_cast 也可以,但 dynamic_cast 更防御性
        auto *wlIntegration = dynamic_cast<QtWaylandClient::QWaylandIntegration*>(
            QGuiApplicationPrivate::platformIntegration());
        if (!wlIntegration) {
            return;
        }

        auto *defaultDevice = wlIntegration->display() ? wlIntegration->display()->defaultInputDevice() : nullptr;
        if (defaultDevice) {
            shellSurface->showWindowMenu(defaultDevice);
        }
        
        return;
    }
#endif
    
    // 修复原有代码的潜在空指针解引用崩溃
    if (!window || !window->handle()) {
        return;
    }
    
    return callPlatformFunction<void, void(*)(quint32)>(_popupSystemWindowMenu, quint32(window->handle()->winId()));
}

总结

本次修改的方向是正确的,填补了 Wayland 平台下系统窗口菜单的功能缺失。主要需要关注的是私有 API 的长期维护成本以及代码的防御性编程(空指针检查)。建议在合并前确认对 Qt 私有 API 的依赖是否符合项目的长期维护策略。

@deepin-ci-robot
Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: 18202781743, mhduiy

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

@mhduiy mhduiy merged commit e907303 into linuxdeepin:master May 11, 2026
21 of 22 checks passed
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.

3 participants