Skip to content

fix: add touch screen support for dock menu#1510

Merged
18202781743 merged 1 commit intolinuxdeepin:masterfrom
18202781743:master
Mar 17, 2026
Merged

fix: add touch screen support for dock menu#1510
18202781743 merged 1 commit intolinuxdeepin:masterfrom
18202781743:master

Conversation

@18202781743
Copy link
Contributor

@18202781743 18202781743 commented Mar 17, 2026

  1. Added a new function requestShowDockMenu() to centralize dock menu
    display logic
  2. Implemented TapHandler for touch screen devices to handle both tap
    and long press gestures
  3. Tap gesture now closes popups and deactivates view without opening
    menu
  4. Long press gesture triggers the dock menu (same as right-click on
    mouse)
  5. Refactored existing mouse click handler to use the new
    requestShowDockMenu() function

Log: Touch screen users can now open dock menu via long press gesture

Influence:

  1. Test touch screen interaction with dock panel - verify tap closes
    popups
  2. Verify long press on touch screen opens dock menu correctly
  3. Test mouse right-click still works as before to open dock menu
  4. Verify mouse left-click behavior remains unchanged
  5. Test that popups close properly on both touch tap and mouse click
  6. Verify dock menu doesn't open unintentionally on regular taps

fix: 为任务栏菜单添加触摸屏支持

  1. 新增 requestShowDockMenu() 函数集中处理任务栏菜单显示逻辑
  2. 为触摸屏设备实现 TapHandler 以处理点击和长按手势
  3. 点击手势现在会关闭弹窗并停用视图而不打开菜单
  4. 长按手势触发任务栏菜单(与鼠标右键点击相同)
  5. 重构现有的鼠标点击处理程序以使用新的 requestShowDockMenu() 函数

Log: 触摸屏用户现在可以通过长按手势打开任务栏菜单

Influence:

  1. 测试触摸屏与任务栏面板的交互 - 验证点击会关闭弹窗
  2. 验证触摸屏长按能正确打开任务栏菜单
  3. 测试鼠标右键点击仍然可以正常打开任务栏菜单
  4. 验证鼠标左键点击行为保持不变
  5. 测试弹窗在触摸点击和鼠标点击时都能正确关闭
  6. 验证任务栏菜单不会在常规点击时意外打开

PMS: BUG-352989

Summary by Sourcery

Add touch-screen support for opening dock and app item context menus while centralizing dock menu display logic.

New Features:

  • Enable dock panel context menu to be opened via long-press gestures on touch-screen devices.
  • Allow app item context menus to be triggered by long-press on touch screens in addition to mouse right-click.

Enhancements:

  • Extract common dock menu display behavior into a reusable requestShowDockMenu() helper in the main dock QML.
  • Refactor app item context menu opening into a reusable requestAppItemMenu() helper shared by mouse and touch interactions.

1. Added a new function requestShowDockMenu() to centralize dock menu
display logic
2. Implemented TapHandler for touch screen devices to handle both tap
and long press gestures
3. Tap gesture now closes popups and deactivates view without opening
menu
4. Long press gesture triggers the dock menu (same as right-click on
mouse)
5. Refactored existing mouse click handler to use the new
requestShowDockMenu() function

Log: Touch screen users can now open dock menu via long press gesture

Influence:
1. Test touch screen interaction with dock panel - verify tap closes
popups
2. Verify long press on touch screen opens dock menu correctly
3. Test mouse right-click still works as before to open dock menu
4. Verify mouse left-click behavior remains unchanged
5. Test that popups close properly on both touch tap and mouse click
6. Verify dock menu doesn't open unintentionally on regular taps

fix: 为任务栏菜单添加触摸屏支持

1. 新增 requestShowDockMenu() 函数集中处理任务栏菜单显示逻辑
2. 为触摸屏设备实现 TapHandler 以处理点击和长按手势
3. 点击手势现在会关闭弹窗并停用视图而不打开菜单
4. 长按手势触发任务栏菜单(与鼠标右键点击相同)
5. 重构现有的鼠标点击处理程序以使用新的 requestShowDockMenu() 函数

Log: 触摸屏用户现在可以通过长按手势打开任务栏菜单

Influence:
1. 测试触摸屏与任务栏面板的交互 - 验证点击会关闭弹窗
2. 验证触摸屏长按能正确打开任务栏菜单
3. 测试鼠标右键点击仍然可以正常打开任务栏菜单
4. 验证鼠标左键点击行为保持不变
5. 测试弹窗在触摸点击和鼠标点击时都能正确关闭
6. 验证任务栏菜单不会在常规点击时意外打开

PMS: BUG-352989
@sourcery-ai
Copy link

sourcery-ai bot commented Mar 17, 2026

Reviewer's Guide

Adds touch-screen support for opening dock and app item menus by centralizing dock menu display logic and introducing touch/gesture handlers, while keeping existing mouse behavior intact.

Sequence diagram for dock menu mouse and touch interactions

sequenceDiagram
    actor User
    participant DockWindow
    participant MouseArea
    participant TapHandler
    participant Panel
    participant MenuHelper
    participant DockMenuLoader
    participant HideTimer

    rect rgb(230,230,255)
        User->>MouseArea: Mouse right-click
        MouseArea->>MenuHelper: closeCurrent()
        MouseArea->>DockMenuLoader: active = true
        alt button is Qt.RightButton and lastActive != dockMenuLoader.item
            MouseArea->>DockWindow: requestShowDockMenu()
            DockWindow->>Panel: requestClosePopup()
            DockWindow->>DockWindow: viewDeactivated()
            DockWindow->>HideTimer: stop()
            DockWindow->>MenuHelper: openMenu(dockMenuLoader.item)
        end
    end

    rect rgb(230,255,230)
        User->>TapHandler: Tap (touch)
        TapHandler->>MenuHelper: closeCurrent()
        TapHandler->>DockMenuLoader: active = true
        TapHandler->>Panel: requestClosePopup()
        TapHandler->>DockWindow: viewDeactivated()
        note over DockWindow,MenuHelper: Tap closes popups and deactivates view, does not open dock menu
    end

    rect rgb(255,230,230)
        User->>TapHandler: Long press (touch)
        TapHandler->>MenuHelper: closeCurrent()
        TapHandler->>DockMenuLoader: active = true
        alt lastActive != dockMenuLoader.item
            TapHandler->>DockWindow: requestShowDockMenu()
            DockWindow->>Panel: requestClosePopup()
            DockWindow->>DockWindow: viewDeactivated()
            DockWindow->>HideTimer: stop()
            DockWindow->>MenuHelper: openMenu(dockMenuLoader.item)
        end
    end
Loading

Updated class diagram for dock and app item menu helpers

classDiagram
    class DockWindow {
        +requestShowDockMenu()
    }

    class TapHandlerDock {
        +onTapped(eventPoint, button)
        +onLongPressed()
    }

    class MouseAreaDock {
        +onClicked(mouse)
    }

    class AppItem {
        +requestAppItemMenu()
    }

    class MouseAreaAppItem {
        +onPressAndHold(mouse)
        +onClicked(mouse)
    }

    class Panel {
        +requestClosePopup()
    }

    class MenuHelper {
        +closeCurrent()
        +openMenu(menuItem)
        +activeMenu
    }

    class DockMenuLoader {
        +active
        +item
    }

    class ContextMenuLoader {
        +trashEmpty
        +active
        +item
    }

    DockWindow --> Panel : uses
    DockWindow --> MenuHelper : uses
    DockWindow --> DockMenuLoader : uses
    DockWindow --> TapHandlerDock : contains
    DockWindow --> MouseAreaDock : contains

    TapHandlerDock --> Panel : uses
    TapHandlerDock --> MenuHelper : uses
    TapHandlerDock --> DockMenuLoader : uses

    MouseAreaDock --> MenuHelper : uses
    MouseAreaDock --> DockMenuLoader : uses
    MouseAreaDock --> DockWindow : calls requestShowDockMenu

    AppItem --> ContextMenuLoader : uses
    AppItem --> MenuHelper : uses

    MouseAreaAppItem --> AppItem : calls requestAppItemMenu
    MouseAreaAppItem --> ContextMenuLoader : uses
    MouseAreaAppItem --> MenuHelper : uses
Loading

File-Level Changes

Change Details Files
Centralize dock menu display logic into a reusable helper function and reuse it for mouse and touch paths.
  • Introduce requestShowDockMenu() to encapsulate popup closing, view deactivation, timer stopping, and dock menu opening.
  • Refactor right-click mouse handler to invoke the new requestShowDockMenu() instead of duplicating inline logic.
panels/dock/package/main.qml
Add explicit touch-screen gesture handling for the dock background to distinguish tap vs long press.
  • Add TapHandler limited to touch-screen devices to handle tap and long press events on the dock area.
  • Make tap gestures close current menu/popup and deactivate the view without opening the dock menu.
  • Make long-press gestures open the dock menu using the same centralized logic as right-click, avoiding reopening when already active.
panels/dock/package/main.qml
Unify app item context menu opening logic for both mouse and touch (long-press).
  • Introduce requestAppItemMenu() helper to prepare and open the app item context menu.
  • Wire mouse right-click to requestAppItemMenu() instead of inlining the menu setup.
  • Add onPressAndHold handler for touch with Qt.NoButton to open the app item context menu on long press.
panels/dock/taskmanager/package/AppItem.qml

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

@deepin-ci-robot
Copy link

deepin pr auto review

这段代码主要实现了 Dock(任务栏)和 AppItem(应用图标)在鼠标右键点击和触摸屏长按时的菜单显示逻辑,以及触摸屏点击时的行为。以下是对这段代码的详细审查和改进建议:

1. 语法逻辑

1.1 main.qml - requestShowDockMenu 函数

  • 观察:代码将原本内联的关闭弹窗、停止计时器、打开菜单的逻辑提取到了 requestShowDockMenu 函数中。这是一个很好的重构,提高了代码复用性。
  • 潜在问题:该函数被鼠标右键点击和触摸屏长按两个地方调用。
    • TapHandleronLongPressed 中,调用前先执行了 MenuHelper.closeCurrent()dockMenuLoader.active = true
    • 而在 TapHandleronTapped 中,也执行了 MenuHelper.closeCurrent()dockMenuLoader.active = true(以及 Panel.requestClosePopup()),但没有调用 requestShowDockMenu
    • 这意味着触摸屏短按(点击)会关闭菜单并激活 Loader,但不会打开菜单。这看起来像是一个半实现的逻辑,或者是专门用于"点击空白处关闭菜单"的逻辑。如果是后者,dockMenuLoader.active = true 可能是不必要的,除非是为了预热。
  • 改进建议
    • 确认 onTapped 中的 dockMenuLoader.active = true 是否必须。如果只是为了关闭菜单,可以移除这行代码以节省资源。
    • 如果 onTapped 旨在处理点击空白处,建议添加注释说明其意图。

1.2 main.qml - TapHandler

  • 观察:新增了 TapHandler 来处理触摸屏事件。
  • 潜在问题onTapped 的签名是 function(eventPoint, button),但在 TapHandler 中,onTapped 实际上接收的是 eventPoint 对象,并没有第二个 button 参数。button 属性通常存在于 MouseEvent 中。
  • 改进建议
    • 修正 onTapped 的函数签名,改为 onTapped: function(eventPoint) 或直接使用 onTapped: eventPoint => { ... }
    • 如果需要判断按键(虽然触摸屏通常没有),应通过 eventPoint.point.device.pointerType 等属性判断,而不是不存在的 button 参数。

1.3 AppItem.qml - requestAppItemMenu 函数

  • 观察:类似于 main.qml,提取了菜单显示逻辑。
  • 逻辑一致性:在 MouseAreaonPressAndHold 中,检查了 mouse.button === Qt.NoButton。这是正确的,因为 onPressAndHold 在触摸屏触发时通常没有鼠标按钮。

2. 代码质量

  • 代码复用:提取 requestShowDockMenurequestAppItemMenu 函数极大地提高了代码的可维护性,减少了重复代码。这是一个很好的实践。
  • 注释maybe has popup visible, close it. 注释有点非正式。建议改为更专业的描述,例如:// Ensure any active popups are closed before showing the dock menu.
  • 变量作用域:在 TapHandleronLongPressed 中定义了 let lastActive,但在 onTapped 中也定义了。这没问题,但可以考虑如果逻辑更复杂时,将通用逻辑提取出来。

3. 代码性能

  • Loader 激活
    • main.qmlTapHandler 中,onTappedonLongPressed 都设置了 dockMenuLoader.active = true。如果菜单组件很重,频繁激活可能会影响性能。但考虑到这是用户交互触发的,通常是可以接受的。
    • AppItem.qml 中,requestAppItemMenu 负责激活 contextMenuLoader。逻辑清晰。
  • 事件处理
    • TapHandler 是 QML 中处理触摸和点击的现代方式,比旧的 MouseArea 更高效且更适合混合输入设备。这里的使用是合理的。

4. 代码安全

  • 空指针检查
    • MenuHelper.openMenu(dockMenuLoader.item)MenuHelper.openMenu(contextMenuLoader.item) 假设 dockMenuLoader.itemcontextMenuLoader.item 在调用时已经存在。
    • 由于在调用前都设置了 .active = true,且 Loader 是同步加载(默认情况),通常 item 会立即可用。但如果组件加载非常慢,或者 Loader 被设置为异步,这里可能会有风险。
  • 改进建议
    • 虽然当前逻辑下风险较低,但为了防御性编程,可以添加检查:
      if (dockMenuLoader.item) {
          MenuHelper.openMenu(dockMenuLoader.item)
      }
    • 或者利用 Loader 的 onLoaded 信号来确保组件已完全加载后再打开菜单。

5. 综合改进代码示例

针对 main.qml 的改进建议:

// ... Window { ...

    function requestShowDockMenu() {
        // Ensure any active popups are closed before showing the dock menu
        Panel.requestClosePopup()
        viewDeactivated()
        hideTimer.stop()
        
        // Ensure the loader is active (defensive check)
        dockMenuLoader.active = true
        
        // Check if the item is ready before opening
        if (dockMenuLoader.status === Loader.Ready && dockMenuLoader.item) {
            MenuHelper.openMenu(dockMenuLoader.item)
        }
    }

    // ... MouseArea { ...
        onClicked: function (mouse) {
            let lastActive = MenuHelper.activeMenu
            // Close current menu logic...
            MenuHelper.closeCurrent()
            
            // Activate loader (pre-load)
            dockMenuLoader.active = true
            
            if (mouse.button === Qt.RightButton && lastActive !== dockMenuLoader.item) {
                requestShowDockMenu()
            }
            if (mouse.button === Qt.LeftButton) {
                // try to close popup when clicked empty, because dock does not have focus.
                Panel.requestClosePopup()
                viewDeactivated()
            }
        }
    // ... } ...

    //Touch screen click
    TapHandler {
        acceptedButtons: Qt.NoButton
        acceptedDevices: PointerDevice.TouchScreen
        
        // Corrected signature: eventPoint is the argument
        onTapped: function(eventPoint) {
            // Logic to handle tap (e.g., close menu)
            // Removed redundant dockMenuLoader.active = true if not needed for just closing
            MenuHelper.closeCurrent()
            Panel.requestClosePopup()
            viewDeactivated()
        }
        
        onLongPressed: {
            let lastActive = MenuHelper.activeMenu
            MenuHelper.closeCurrent()
            // Ensure loader is active
            dockMenuLoader.active = true
            if (lastActive !== dockMenuLoader.item) {
                requestShowDockMenu()
            }
        }
    }
// ... } ...

针对 AppItem.qml 的改进建议:

// ... Item { ...

    function requestAppItemMenu() {
        contextMenuLoader.trashEmpty = TaskManager.isTrashEmpty()
        contextMenuLoader.active = true
        
        // Defensive check for loader status
        if (contextMenuLoader.status === Loader.Ready && contextMenuLoader.item) {
            MenuHelper.openMenu(contextMenuLoader.item)
        }
    }

    // ... MouseArea { ...
        onClicked: function (mouse) {
            let index = root.modelIndex;
            if (mouse.button === Qt.RightButton) {
                requestAppItemMenu()
            } else {
                // ... existing logic ...
            }
        }
        
        // touchscreen long press.
        onPressAndHold: function (mouse) {
            if (mouse.button === Qt.NoButton) {
                requestAppItemMenu()
            }
        }
    // ... } ...
// ... } ...

总结

这段代码主要增加了对触摸屏的支持,并优化了菜单显示的逻辑。整体结构是合理的,但在细节上(如函数签名、注释风格、防御性检查)还有提升空间。建议采纳上述关于 TapHandler 参数修正和 Loader 状态检查的建议,以提高代码的健壮性和可读性。

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 1 issue, and left some high level feedback:

  • In both the TapHandler.onTapped handler and the long-press handler you introduce a local lastActive variable that is never used, which can be removed to avoid confusion and keep the gesture handlers minimal.
  • The new helper functions (e.g., requestShowDockMenu, requestAppItemMenu) only cover part of the previously duplicated sequences (e.g., dockMenuLoader.active = true is still repeated at each call site); consider moving all shared steps into the helpers so callers don’t need to remember the correct activation order.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In both the TapHandler.onTapped handler and the long-press handler you introduce a local `lastActive` variable that is never used, which can be removed to avoid confusion and keep the gesture handlers minimal.
- The new helper functions (e.g., `requestShowDockMenu`, `requestAppItemMenu`) only cover part of the previously duplicated sequences (e.g., `dockMenuLoader.active = true` is still repeated at each call site); consider moving all shared steps into the helpers so callers don’t need to remember the correct activation order.

## Individual Comments

### Comment 1
<location path="panels/dock/taskmanager/package/AppItem.qml" line_range="461-463" />
<code_context>
             closeItemPreview()
         }
+        // touchscreen long press.
+        onPressAndHold: function (mouse) {
+            if (mouse.button === Qt.NoButton) {
+                requestAppItemMenu()
+            }
+        }
</code_context>
<issue_to_address>
**suggestion (bug_risk):** Consider making the touch-only PressAndHold guard more explicit and resilient

Using `mouse.button === Qt.NoButton` as a proxy for touch is a bit implicit and may break if event semantics change. If you only want touch long‑press, consider checking `mouse.source` / device type (if available) or wiring this through a dedicated touch handler (e.g., `TapHandler` long‑press, as in the dock) so the intent is explicit and less prone to misfiring on non‑touch input.

Suggested implementation:

```
        // touch long-press: open app item menu explicitly for touch input
        TapHandler {
            id: touchLongPressHandler
            acceptedDevices: PointerDevice.TouchScreen
            acceptedButtons: Qt.LeftButton
            gesturePolicy: TapHandler.ReleaseWithinBounds
            onLongPressed: requestAppItemMenu()
        }

```

If `TapHandler` and `PointerDevice` are not yet available in this file, ensure the root of `AppItem.qml` imports a recent enough QtQuick version (e.g. `import QtQuick 2.12` or later) where `TapHandler` and the `PointerDevice` attached type are provided. No other behavioral changes are required; the long-press is now explicitly touch-only instead of inferred via `mouse.button === Qt.NoButton`.
</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-ci-robot
Copy link

[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 7fdfaef into linuxdeepin:master Mar 17, 2026
10 of 12 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