Skip to content

fix: enable touch scrolling in launcher#764

Merged
fly602 merged 1 commit into
linuxdeepin:masterfrom
fly602:master
May 25, 2026
Merged

fix: enable touch scrolling in launcher#764
fly602 merged 1 commit into
linuxdeepin:masterfrom
fly602:master

Conversation

@fly602
Copy link
Copy Markdown
Contributor

@fly602 fly602 commented May 21, 2026

  1. Update the icon press handling in AppListView.qml and FreeSortListView.qml.
  2. Detect synthesized mouse events generated from touch input by checking mouse.source.
  3. When the event comes from touch rather than a real mouse, mark it as not accepted and return early so the parent Flickable can handle vertical scrolling.
  4. Keep the existing left-click image grab and subsequent interaction logic unchanged for real mouse input.
  5. This change is necessary because launcher icons were consuming touch-generated press events, which blocked swipe up/down gestures and prevented smooth scrolling in the app list.

Log: Enabled vertical touch scrolling on launcher app icons

Influence:

  1. Verify that swiping up and down directly on launcher icons scrolls the app list smoothly.
  2. Verify that mouse left-click behavior on icons is unchanged, including image grab related interactions.
  3. Test long-press behavior on touch devices to ensure it does not regress unexpectedly.
  4. Verify scrolling behavior in both AppListView and FreeSortListView.
  5. Test with real mouse input and touch input separately to confirm correct event routing.
  6. Check that icon click, drag, and reorder related interactions still work as expected after the event acceptance change.

fix: 启动器支持图标区域触控滑动

  1. 更新了 AppListView.qml 和 FreeSortListView.qml 中的图标按下事件处理 逻辑。
  2. 通过检查 mouse.source 来识别由触摸输入合成的鼠标事件。
  3. 当事件来源于触摸而不是真实鼠标时,将事件设置为不接受并提前返回,让父 级 Flickable 接管上下滑动处理。
  4. 对真实鼠标输入,保留原有的左键截图抓取及后续交互逻辑不变。
  5. 之所以需要此修改,是因为启动器图标此前会消费触摸生成的按下事件,导致 用户在图标区域上下滑动时手势被拦截,应用列表无法顺畅滚动。

Log: 已支持在启动器应用图标区域进行上下触控滑动

Influence:

  1. 验证在启动器图标区域直接上下滑动时,应用列表能够平滑滚动。
  2. 验证鼠标左键点击图标的行为保持不变,包括相关的图像抓取交互。
  3. 在触屏设备上测试长按行为,确认没有引入异常回归。
  4. 分别验证 AppListView 和 FreeSortListView 中的滚动表现。
  5. 使用真实鼠标输入和触摸输入分别测试,确认事件分发符合预期。
  6. 检查图标点击、拖拽、自由排序等相关交互在事件接受逻辑调整后仍然正常。

PMS: BUG-362161
Change-Id: I54e01447f677a2275ab285c576dabbf84799f5f5

Summary by Sourcery

Bug Fixes:

  • Prevent touch-generated press events on launcher icons from blocking vertical scrolling in AppListView and FreeSortListView.

@sourcery-ai
Copy link
Copy Markdown

sourcery-ai Bot commented May 21, 2026

Reviewer's guide (collapsed on small PRs)

Reviewer's Guide

Adds touch-awareness to launcher icon press handling so that touch-generated mouse events are not consumed by item delegates, allowing Flickable to handle vertical scrolling while preserving existing left-click behavior for real mouse input.

Sequence diagram for touch vs mouse press handling in launcher icon views

sequenceDiagram
    actor User
    participant TouchInput
    participant IconMouseArea as IconMouseArea_onPressed
    participant Flickable

    User ->> TouchInput: touch press on icon
    TouchInput ->> IconMouseArea: onPressed(mouse)

    alt [mouse.source != 0]
        IconMouseArea ->> IconMouseArea: mouse.accepted = false
        IconMouseArea -->> Flickable: return
        Flickable ->> Flickable: handle vertical scrolling
    else [mouse.source == 0]
        IconMouseArea ->> IconMouseArea: isTouchLongPressed = false
        IconMouseArea ->> IconMouseArea: grabToImage(callback)
        IconMouseArea ->> Flickable: (existing icon interactions)
    end
Loading

File-Level Changes

Change Details Files
Prevent synthesized touch mouse presses on launcher icons from being consumed so Flickable can handle vertical scrolling.
  • Added a mouse.source check in item delegate onPressed handlers to distinguish real mouse from touch-generated events.
  • When the event is identified as coming from touch, mark it as not accepted and return early so the parent Flickable can process scroll gestures.
  • Kept existing left-button grabToImage and subsequent interaction logic intact for real mouse input.
qml/windowed/FreeSortListView.qml
qml/windowed/AppListView.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

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.

Hey - I've found 1 issue, and left some high level feedback:

  • The mouse.source !== 0 check uses a magic number; consider comparing against the appropriate Qt.MouseEventSource enum (e.g., Qt.MouseEventNotSynthesized) to make the intent clearer and less fragile to Qt changes.
  • The new onPressed logic to ignore synthesized touch events is duplicated in both AppListView.qml and FreeSortListView.qml; consider extracting this into a shared helper or component to keep the behavior consistent and easier to maintain.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The `mouse.source !== 0` check uses a magic number; consider comparing against the appropriate `Qt.MouseEventSource` enum (e.g., `Qt.MouseEventNotSynthesized`) to make the intent clearer and less fragile to Qt changes.
- The new `onPressed` logic to ignore synthesized touch events is duplicated in both `AppListView.qml` and `FreeSortListView.qml`; consider extracting this into a shared helper or component to keep the behavior consistent and easier to maintain.

## Individual Comments

### Comment 1
<location path="qml/windowed/FreeSortListView.qml" line_range="354-358" />
<code_context>

                     onPressed: function (mouse) {
+                        // 触屏合成的鼠标事件不接受,交给 Flickable 处理滚动
+                        if (mouse.source !== undefined && mouse.source !== 0) {
+                            mouse.accepted = false
+                            return
+                        }
</code_context>
<issue_to_address>
**suggestion:** Avoid using a magic number for the mouse source and rely on the Qt enum instead.

Using `0` here ties the logic to the enum’s current numeric value and reduces readability. Please compare against `Qt.MouseEventNotSynthesized` (or the relevant enum) instead so the intent is clear and the code remains correct if the enum values change.

```suggestion
                        // 触屏合成的鼠标事件不接受,交给 Flickable 处理滚动
                        if (mouse.source !== undefined && mouse.source !== Qt.MouseEventNotSynthesized) {
                            mouse.accepted = false
                            return
                        }
```
</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.

Comment thread qml/windowed/FreeSortListView.qml
1. Update the icon press handling in AppListView.qml and
FreeSortListView.qml.
2. Detect synthesized mouse events generated from touch input by
checking mouse.source.
3. When the event comes from touch rather than a real mouse, mark it
as not accepted and return early so the parent Flickable can handle
vertical scrolling.
4. Keep the existing left-click image grab and subsequent interaction
logic unchanged for real mouse input.
5. This change is necessary because launcher icons were consuming
touch-generated press events, which blocked swipe up/down gestures and
prevented smooth scrolling in the app list.

Log: Enabled vertical touch scrolling on launcher app icons

Influence:
1. Verify that swiping up and down directly on launcher icons scrolls
the app list smoothly.
2. Verify that mouse left-click behavior on icons is unchanged,
including image grab related interactions.
3. Test long-press behavior on touch devices to ensure it does not
regress unexpectedly.
4. Verify scrolling behavior in both AppListView and FreeSortListView.
5. Test with real mouse input and touch input separately to confirm
correct event routing.
6. Check that icon click, drag, and reorder related interactions still
work as expected after the event acceptance change.

fix: 启动器支持图标区域触控滑动

1. 更新了 AppListView.qml 和 FreeSortListView.qml 中的图标按下事件处理
逻辑。
2. 通过检查 mouse.source 来识别由触摸输入合成的鼠标事件。
3. 当事件来源于触摸而不是真实鼠标时,将事件设置为不接受并提前返回,让父
级 Flickable 接管上下滑动处理。
4. 对真实鼠标输入,保留原有的左键截图抓取及后续交互逻辑不变。
5. 之所以需要此修改,是因为启动器图标此前会消费触摸生成的按下事件,导致
用户在图标区域上下滑动时手势被拦截,应用列表无法顺畅滚动。

Log: 已支持在启动器应用图标区域进行上下触控滑动

Influence:
1. 验证在启动器图标区域直接上下滑动时,应用列表能够平滑滚动。
2. 验证鼠标左键点击图标的行为保持不变,包括相关的图像抓取交互。
3. 在触屏设备上测试长按行为,确认没有引入异常回归。
4. 分别验证 AppListView 和 FreeSortListView 中的滚动表现。
5. 使用真实鼠标输入和触摸输入分别测试,确认事件分发符合预期。
6. 检查图标点击、拖拽、自由排序等相关交互在事件接受逻辑调整后仍然正常。

PMS: BUG-362161
Change-Id: I54e01447f677a2275ab285c576dabbf84799f5f5
@deepin-ci-robot
Copy link
Copy Markdown

deepin pr auto review

你好!我是CodeGeeX。我已仔细审查了你提供的 Git Diff 代码。这次修改主要针对 QML 中的 MouseAreaTapHandler 的交互逻辑,特别是处理触屏设备上的点击、长按、拖拽与滚动的冲突问题。

整体来看,这次重构的方向非常好,通过将触屏的点击逻辑移至 TapHandler.onTapped,并利用 mouse.source 过滤触屏合成的鼠标事件,优雅地解决了之前用 isTouchLongPressed 状态变量来防抖的冗余逻辑。

以下是针对语法逻辑、代码质量、代码性能和代码安全方面的详细审查意见和改进建议:

1. 语法与逻辑

问题:TapHandler.onTapped 的信号参数不匹配
在两处修改中,TapHandleronTapped 信号处理函数写成了 onTapped: function(eventPoint, buttons) { ... }
但在 Qt QML 语法中,TapHandler.onTapped 的信号签名只传递一个 eventPoint 参数(类型为 QQuickEventPoint),并没有 buttons 参数。虽然 QML 允许信号处理函数声明多余的无用参数而不会报错,但这会引起误解,且无法获取预期的按键状态。

  • 改进建议:移除多余的 buttons 参数。如果需要检查按键,应通过 TapHandlerpressedButtons 属性获取。
    // 修改前
    onTapped: function(eventPoint, buttons) {
        launchApp(desktopId)
    }
    
    // 修改后
    onTapped: function(eventPoint) {
        launchApp(desktopId)
    }

问题:mouse.source 的判断逻辑存在潜在风险
修改中使用了 if (mouse.source !== undefined && mouse.source !== Qt.MouseEventNotSynthesized) 来过滤触屏合成的鼠标事件。这个逻辑在大多数情况下有效,但存在两个隐患:

  1. 在较旧版本的 Qt 中,原生鼠标事件的 mouse.source 可能也是 undefined,此时该逻辑会意外地 mouse.accepted = false,导致原生鼠标点击失效(无法触发拖拽,无法弹出右键菜单)。
  2. 判断条件略显冗长。
  • 改进建议:更严谨的做法是显式判断 mouse.source 是否为触屏合成事件。在 Qt 中,触屏合成的鼠标事件来源通常是 Qt.MouseEventSynthesizedByQtQt.MouseEventSynthesizedBySystem
    onPressed: function (mouse) {
        // 显式拒绝由触屏合成的鼠标事件,交由 Flickable 处理滚动
        if (mouse.source === Qt.MouseEventSynthesizedByQt || mouse.source === Qt.MouseEventSynthesizedBySystem) {
            mouse.accepted = false
            return
        }
        // ... 原有逻辑
    }

2. 代码质量

优点:消除了状态变量,降低了复杂度
移除 isTouchLongPressed 标志位是一个非常棒的改进。之前在 MouseAreaTapHandler 之间共享状态不仅破坏了单一职责原则,还容易出现状态不同步的 Bug(例如由于异常中断导致状态未重置)。现在的逻辑职责更加清晰:

  • TapHandler:专职处理触屏的点击和长按。
  • MouseArea:专职处理鼠标的点击、右键菜单和拖拽准备(grabToImage)。

建议:补充代码注释
虽然新逻辑更清晰,但 MouseAreaTapHandler 并存且处理不同输入源的设计在 QML 中属于相对高级且容易让人迷惑的用法。建议在代码块顶部补充简要注释,说明设计意图,方便后续维护者理解。

// MouseArea 负责处理原生鼠标输入(拖拽、右键菜单),
// TapHandler 负责处理触屏输入(点击启动、长按菜单),
// 通过在 MouseArea onPressed 中拒绝触屏合成事件,避免冲突并将滚动交还给 Flickable。

3. 代码性能

风险:grabToImage 的异步回调与拖拽状态管理
MouseArea.onPressed 中调用了 itemDelegate.contentItem.grabToImage。这是一个异步操作,会在 GPU 渲染完成后回调设置 Drag.imageSource
如果在图片尚未 Grab 完成时用户就开始拖拽,可能会导致拖拽图片为空或使用旧图片。此外,每次 Press 都进行 Grab 会带来一定的 CPU/GPU 开销。

  • 改进建议(视具体业务情况而定)
    如果应用图标在列表中是静态的,最佳实践是在组件加载完成(Component.onCompleted)或数据更新时生成一次 Drag Image 并缓存,而不是在每次 onPressed 时实时生成。如果必须实时生成,需确保在拖拽开始时校验图片是否已就绪。

4. 代码安全

风险:QML 上下文属性的隐式依赖
代码中直接调用了 launchApp(desktopId)launchItem(),以及 showContextMenu(...)。这些函数没有在 Diff 中看到显式的定义或导入,说明它们很可能是通过 QML 根上下文(Context Property)或者上层组件注入的。

这种强依赖上下文环境的写法在 QML 中虽然常见,但属于“弱类型安全”,如果重构了后端注入逻辑,QML 运行时才会报错(Property 'launchApp' of object is not a function)。

  • 改进建议
    1. 确保这些函数在组件内部有 required property 声明,或者通过明确的信号抛出给父组件处理(这更符合 QML 的组件化设计原则)。
    2. 例如,可以将 onTapped 改为发射信号:signal appLaunched(string id),然后在父组件中连接处理逻辑,这样能提升组件的复用性和安全性。

综合修改建议示例 (以 AppListView.qml 为例)

                     // MouseArea 负责处理原生鼠标输入(拖拽、右键菜单),
                     // TapHandler 负责处理触屏输入(点击启动、长按菜单),
                     // 通过在 MouseArea onPressed 中拒绝触屏合成事件,避免冲突并将滚动交还给 Flickable。
                     MouseArea {
                     // ... 其他属性
                     TapHandler {
                         acceptedDevices: PointerDevice.TouchScreen
                         gesturePolicy: TapHandler.DragThreshold
                         // 修复:移除不存在的 buttons 参数
                         onTapped: function(eventPoint) {
                             launchApp(desktopId)
                         }
                         onLongPressed: {
                             showContextMenu(itemDelegate, model)
                         }
                     }
 
                     onPressed: function (mouse) {
                         // 修复:显式判断触屏合成事件,避免误杀原生鼠标事件
                         if (mouse.source === Qt.MouseEventSynthesizedByQt || mouse.source === Qt.MouseEventSynthesizedBySystem) {
                             mouse.accepted = false
                             return
                         }
                         if (mouse.button === Qt.LeftButton) {
                             itemDelegate.contentItem.grabToImage(function(result) {
                                 itemDelegate.Drag.imageSource = result.url
                             })
                         }
                     }
                     onClicked: function (mouse) {
                         if (mouse.button === Qt.RightButton) {
                             showContextMenu(itemDelegate, model)
                             baseLayer.focus = true
                         }
                     }

总体而言,你的重构思路非常正确,大大提升了代码的健壮性和可读性。只需修复上述几个小细节,代码将会更加规范和安全。

@deepin-ci-robot
Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

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

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

@fly602 fly602 merged commit f86bd7a into linuxdeepin:master May 25, 2026
11 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