Skip to content

feat: support KWin split menus in QML title bars - #688

Merged
18202781743 merged 1 commit into
linuxdeepin:masterfrom
18202781743:kwin-split-menu
Sep 20, 2026
Merged

18202781743 merged 1 commit into
linuxdeepin:masterfrom
18202781743:kwin-split-menu

Conversation

@18202781743

@18202781743 18202781743 commented Sep 11, 2026 •

Copy link
Copy Markdown
Contributor

为 QML TitleBar/WindowButtonGroup 增加 splitScreenEnabled,并在最大化按钮悬停或长按时请求 KWin 分屏菜单。普通点击保持最大化/还原行为;长按成功后释放不触发最大化;不支持平台接口时正常点击行为不受影响。

DQuickWindowAttached 直接封装平台函数调用,不经过 dtkgui。客户端处理按钮交互和功能禁用时的收起请求,窗口关闭/消失后的菜单清理由窗管负责。

关联平台接口:linuxdeepin/dde-qtplatform-plugins#345

验证:实现工作目录中 Qt5/Qt6 构建通过(最多 6 个核心);QML 无界面测试 8 项通过(包含初始化/清理,覆盖普通点击、长按、悬停离开、功能禁用及不支持的平台)。PR 基于最新 master,差异检查通过;真实 KWin 桌面显示效果尚未实测。

Summary by Sourcery

Enable KWin split-screen menus from QML title-bar maximize buttons without disrupting existing window-state controls.

New Features:

  • Add configurable split-screen menu support to QML title bars and window button groups.
  • Request the platform split-screen menu when the maximize button is hovered or long-pressed while preserving normal maximize and restore clicks.

Bug Fixes:

  • Prevent a successful long-press split-menu interaction from also triggering the maximize action.
  • Gracefully retain existing button behavior when split-screen platform APIs are unavailable.

Enhancements:

  • Centralize split-menu display and cleanup through DQuickWindowAttached with validation of window and button state.
  • Handle split-menu dismissal when the button is released, canceled, hidden, disabled, or the feature is turned off.

@sourcery-ai

sourcery-ai Bot commented Sep 11, 2026

Copy link
Copy Markdown

Reviewer's Guide

Adds configurable KWin split-menu support to QML title bars by combining maximize-button hover/long-press interaction with direct platform-function calls, while retaining existing maximize/restore behavior on unsupported platforms and ordinary clicks.

Sequence diagram for QML split-menu interaction

sequenceDiagram
    participant User
    participant MaximizeButton
    participant DQuickWindowAttached
    participant Platform

    alt Hover for 700ms or hold for 300ms
        User->>MaximizeButton: hover or press
        MaximizeButton->>DQuickWindowAttached: showSplitMenu(maxOrWindedBtn)
        DQuickWindowAttached->>Platform: _d_supportSplitMenu(wid)
        alt Platform supports split menu
            DQuickWindowAttached->>Platform: _d_showSplitMenu(wid, rect)
            Platform-->>DQuickWindowAttached: menu shown
        else Unsupported or invalid window/button
            DQuickWindowAttached-->>MaximizeButton: false
        end
    else Ordinary click
        User->>MaximizeButton: click
        MaximizeButton->>MaximizeButton: maxOrWinded()
    end
    alt Menu requested
        User->>MaximizeButton: release or leave button
        MaximizeButton->>DQuickWindowAttached: hideSplitMenu(delay)
        DQuickWindowAttached->>Platform: _d_hideSplitMenu(wid, delay)
    end
Loading

File-Level Changes

Change Details Files
Expose split-screen configuration through the QML title-bar component hierarchy.
  • Add enabled property at title-bar and button-group levels.
  • Forward the property to the maximize button group.
qt6/src/qml/TitleBar.qml
qt6/src/qml/WindowButtonGroup.qml
Add hover and long-press interaction handling for the maximize button while preserving normal click behavior.
  • Request the split menu after hover or a 300 ms press.
  • Suppress maximize/restore after a successful long press.
  • Cancel or hide the menu when the pointer leaves, interaction ends, visibility changes, or the feature is disabled.
  • Keep ordinary clicks functional when split menus are disabled or unsupported.
qt6/src/qml/WindowButtonGroup.qml
Implement platform-function based split-menu display and lifecycle management for QML windows.
  • Validate the window and button, resolve platform callbacks, and pass the button's global logical rectangle to the platform.
  • Track the owning window ID and support immediate or delayed menu hiding.
  • Expose the operations through DQuickWindowAttached without routing through dtkgui.
src/dquickwindow.cpp
src/dquickwindow.h
src/private/dquickwindow_p.h

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

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Hey - I've found 1 issue

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="qt6/src/qml/WindowButtonGroup.qml" line_range="131-136" />
<code_context>
+                control.maxOrWinded()
+            __longPressed = false
+        }
+        onVisibleChanged: {
+            if (!visible) {
+                hoverTimer.stop()
+                holdTimer.stop()
+                __menuRequested = false
+            }
+        }
+        onEnabledChanged: if (!enabled) hideSplitMenu(false)
</code_context>
<issue_to_address>
**issue (bug_risk):** When the maximize button becomes invisible while a split menu is open, this handler stops the timers and clears `__menuRequested` without calling `hideSplitMenu`, so the platform menu remains visible and the client loses the state needed to hide it.

**Triggers:** When the window enters fullscreen or another state that makes `maxOrWindedBtn.visible` false after the split menu has been shown.

**Suggested fix:** Call `hideSplitMenu(false)` (or an appropriate delayed hide) before clearing the request state when the button becomes invisible, and handle window visibility changes explicitly if they do not change the button's `visible` property.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨

Comment on lines +131 to +136
onVisibleChanged: {
if (!visible) {
hoverTimer.stop()
holdTimer.stop()
__menuRequested = false
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

issue (bug_risk): When the maximize button becomes invisible while a split menu is open, this handler stops the timers and clears __menuRequested without calling hideSplitMenu, so the platform menu remains visible and the client loses the state needed to hide it.

Triggers: When the window enters fullscreen or another state that makes maxOrWindedBtn.visible false after the split menu has been shown.

Suggested fix: Call hideSplitMenu(false) (or an appropriate delayed hide) before clearing the request state when the button becomes invisible, and handle window visibility changes explicitly if they do not change the button's visible property.

@18202781743
18202781743 force-pushed the kwin-split-menu branch 3 times, most recently from f17e312 to 4dbe183 Compare September 14, 2026 07:16
1. Add splitScreenEnabled property to TitleBar and WindowButtonGroup
components
2. Implement showSplitMenu and hideSplitMenu methods in
DQuickWindowAttached
3. Add platform function bindings for _d_supportSplitMenu,
_d_showSplitMenu, and _d_hideSplitMenu
4. Add hover timer (700ms) and hold timer (300ms) to trigger split menu
on maximize button
5. Track splitMenuWindowId in DQuickWindowPrivate to manage menu state
6. Handle menu lifecycle on hover, press, release, cancel, visibility
and enabled changes
7. Map button geometry to global coordinates for menu positioning

Log: Added split screen menu triggered by hovering or long-pressing the
maximize button

Influence:
1. Test hovering over maximize button for 700ms to show split screen
menu
2. Test long-pressing maximize button for 300ms to trigger split menu
3. Verify normal click behavior on maximize button still works when not
long-pressed
4. Test menu hides on mouse leave and when splitScreenEnabled is set
to false
5. Verify split menu only appears when platform supports
_d_supportSplitMenu
6. Test split menu positioning aligns with the maximize button location
7. Verify menu interaction works correctly in embed mode and fullscreen
scenarios
8. Test behavior when window is not visible or button is disabled

feat: 为标题栏添加分屏菜单

1. 在 TitleBar 和 WindowButtonGroup 组件中添加 splitScreenEnabled 属性
2. 在 DQuickWindowAttached 中实现 showSplitMenu 和 hideSplitMenu 方法
3. 添加 _d_supportSplitMenu、_d_showSplitMenu 和 _d_hideSplitMenu 平台函
数绑定
4. 为最大化按钮添加悬停定时器(700ms)和长按定时器(300ms)以触发分屏
菜单
5. 在 DQuickWindowPrivate 中跟踪 splitMenuWindowId 以管理菜单状态
6. 在悬停、按下、释放、取消、可见性和启用状态变化时处理菜单生命周期
7. 将按钮几何位置映射到全局坐标以定位菜单

Log: 新增通过悬停或长按最大化按钮触发的分屏菜单

Influence:
1. 测试悬停最大化按钮 700ms 后显示分屏菜单
2. 测试长按最大化按钮 300ms 触发分屏菜单
3. 验证非长按时最大化按钮的正常点击行为仍然有效
4. 测试鼠标离开和 splitScreenEnabled 设为 false 时菜单隐藏
5. 验证仅在平台支持 _d_supportSplitMenu 时才显示分屏菜单
6. 测试分屏菜单位置是否与最大化按钮位置对齐
7. 验证嵌入模式和全屏场景下菜单交互正常
8. 测试窗口不可见或按钮禁用时的行为

PMS: BUG-370181
@deepin-ci-robot

Copy link
Copy Markdown
Contributor

deepin pr auto review

🤖 AI 代码审查报告

总体评分: 98 分 (通过阈值: 70分)

Pass


📊 总体评价

项目 结果
审查结论 代码审查通过
评分详情 总体评分 98 分,大于 70 分通过阈值,代码质量符合要求。代码实现了 KWin 分屏菜单功能,逻辑清晰,安全无漏洞。

🔍 详细分析

1. 语法逻辑 ✅

评价: 优秀 ✅ 通过

潜在问题:
✅ 未发现明显问题

建议: 代码语法正确,逻辑清晰。状态管理(__longPressed、__menuRequested)设计合理,定时器交互协调良好,边界条件处理完善(按钮不可见、不可用、平台不支持等情况均有处理)。showSplitMenu 中 __menuRequested 标志有效防止重复调用平台函数,hideSplitMenu 在延迟模式下保留 splitMenuWindowId 以支持后续关闭操作。


2. 代码质量 ✅

评价: 优秀 ✅ 通过

潜在问题:

  1. qt6/src/qml/WindowButtonGroup.qml:94 - QML函数 showSplitMenu() 和 hideSplitMenu() 缺少文档注释,建议添加函数行为说明
  2. qt6/src/qml/WindowButtonGroup.qml:152 - 定时器间隔 700ms 和 300ms 为魔法数字,建议提取为命名常量

建议: 建议为 QML 新增函数添加文档注释,说明函数用途和参数含义。定时器间隔可提取为属性常量以提高可维护性。C++ 代码注释良好,命名规范符合 Qt 风格。


3. 代码性能 ✅

评价: 优秀 ✅ 通过

潜在问题:
✅ 未发现明显问题

建议: 性能良好,基于定时器的方案高效无轮询。__menuRequested 标志有效防止重复平台函数调用,各函数中提前返回减少了不必要的计算。平台函数通过局部变量缓存避免重复查询。


4. 代码安全 🔒

评价: 优秀 ✅ 通过

🔐 发现 0 个安全漏洞

安全漏洞详情:
✅ 未发现安全漏洞

建议: 代码安全合规,无安全漏洞。reinterpret_cast 平台函数模式是 Qt 标准用法,平台函数由平台插件注册而非用户输入控制。所有输入来自 Qt 内部事件系统,无注入攻击面。splitMenuWindowId 为内部标识符,非用户可控。


💡 改进建议代码示例

// 建议为 QML 函数添加文档注释

/**
 * 显示分屏菜单
 * 当 splitScreenEnabled 为 true 且按钮可见、可用时,
 * 通过平台函数显示分屏菜单
 * @returns {bool} 菜单是否成功显示
 */
function showSplitMenu() {
    if (!control.splitScreenEnabled || !visible || !enabled)
        return false
    if (!__menuRequested)
        __menuRequested = control.__dwindow.showSplitMenu(maxOrWindedBtn)
    return __menuRequested
}

// 建议提取定时器间隔为常量
property int hoverDelay: 700  // 悬停触发延迟(ms)
property int holdDelay: 300   // 长按触发延迟(ms)

本报告由 AI 代码审查工具自动生成

@deepin-ci-robot

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: 18202781743, 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

@18202781743
18202781743 merged commit 660a12b into linuxdeepin:master Sep 20, 2026
19 of 20 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