Skip to content

fix: handle touch outside popup on X11#1604

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

fix: handle touch outside popup on X11#1604
fly602 merged 1 commit into
linuxdeepin:masterfrom
fly602:master

Conversation

@fly602
Copy link
Copy Markdown
Contributor

@fly602 fly602 commented May 21, 2026

  1. Add QTouchEvent handling to MouseGrabEventFilter in frame/ utility_x11.cpp.
  2. Detect QEvent::TouchBegin and read the first touch point's global position.
  3. When the touch happens outside the target popup window geometry, emit outsideMousePressed() and consume the event.
  4. Keep the existing mouse-based outside-click logic unchanged while extending the same close-popup behavior to touch input.
  5. This fixes an issue on touch-screen devices where, after the plugin area context menu was shown, tapping other areas of the taskbar did not respond because touch interactions outside the popup were not being handled.

Log: Fixed taskbar touch no-response issue when plugin area context menu is open

Influence:

  1. On an X11 touch-screen device, open the plugin area context menu and tap outside the popup on different taskbar areas; verify the popup closes and the tapped area responds correctly.
  2. Verify existing mouse behavior is unchanged: right-click to open the menu, then click outside to close it.
  3. Test tapping inside the popup to confirm normal menu interaction is preserved.
  4. Test repeated open/close operations with both mouse and touch input to ensure there are no stuck grab states or lost events.
  5. Verify no regressions for non-touch environments on X11.

fix: 处理 X11 下弹窗外部触控关闭逻辑

  1. 在 frame/utility_x11.cpp 的 MouseGrabEventFilter 中新增 QTouchEvent 处理逻辑。
  2. 检测 QEvent::TouchBegin,并读取第一个触控点的全局坐标。
  3. 当触控位置位于目标弹窗窗口几何范围之外时,触发 outsideMousePressed() 并消费该事件。
  4. 在保留原有鼠标外部点击处理逻辑不变的基础上,将相同的关闭弹窗行为扩展 到触控输入。
  5. 该修改修复了触控屏设备上插件区域右键菜单弹出后,点击任务栏其他区域无 响应的问题,原因是此前未处理弹窗外部的触控事件。

Log: 修复插件区域右键菜单打开时任务栏触控无响应问题

Influence:

  1. 在 X11 触控屏设备上打开插件区域右键菜单后,点击弹窗外的不同任务栏区 域,确认弹窗会关闭且被点击区域能够正常响应。
  2. 验证现有鼠标行为不受影响:右键打开菜单后,鼠标点击外部仍可正常关闭。
  3. 测试在弹窗内部点击,确认菜单本身的交互仍然正常。
  4. 使用鼠标和触控反复执行打开/关闭操作,确认不存在 grab 状态残留或事件丢 失问题。
  5. 验证 X11 非触控环境下无回归。

PMS: BUG-362159
Change-Id: I3c6ed96f01408c3c966f17ae7b999858c0c9ec46

Summary by Sourcery

Handle touch interactions outside popup windows on X11 so that popups close consistently for both mouse and touch input.

Bug Fixes:

  • Fix unresponsive taskbar taps when a plugin area context menu is open on X11 by treating outside touches like outside mouse clicks.

Enhancements:

  • Extend the existing mouse grab event filter to process touch begin events and detect touches outside the target window.

@sourcery-ai
Copy link
Copy Markdown

sourcery-ai Bot commented May 21, 2026

Reviewer's guide (collapsed on small PRs)

Reviewer's Guide

Extends the X11 MouseGrabEventFilter to handle touch events (QTouchEvent::TouchBegin) so that touches outside a popup window close it, matching existing mouse outside-click behavior, while updating the file copyright header years.

Sequence diagram for touch-based popup closing on X11

sequenceDiagram
    actor User
    participant QApplication
    participant MouseGrabEventFilter
    participant PopupWindow

    User ->> QApplication: QTouchEvent TouchBegin
    QApplication ->> MouseGrabEventFilter: eventFilter(watched, event)
    alt event.type is QEvent_TouchBegin
        MouseGrabEventFilter ->> MouseGrabEventFilter: touchEvent.points().first()
        MouseGrabEventFilter ->> MouseGrabEventFilter: m_target.geometry().contains(pos.toPoint())
        alt [touch outside popup geometry]
            MouseGrabEventFilter ->> PopupWindow: outsideMousePressed
            MouseGrabEventFilter -->> QApplication: return true
        else [touch inside popup geometry]
            MouseGrabEventFilter -->> QApplication: return false
        end
    else other event types
        MouseGrabEventFilter -->> QApplication: return false
    end
Loading

File-Level Changes

Change Details Files
Extend MouseGrabEventFilter to close popups on touch events outside the target window, mirroring existing mouse outside-click behavior.
  • Include QTouchEvent in the X11 utility implementation to enable touch event handling.
  • In MouseGrabEventFilter::eventFilter, add a QEvent::TouchBegin branch that inspects the first touch point's global position.
  • Compare the touch position against the target window geometry and, when outside, log a debug message, emit outsideMousePressed(), and consume the event by returning true.
  • Leave existing mouse-based grab and outside-click handling unchanged to preserve current behavior on non-touch systems.
frame/utility_x11.cpp
Update copyright header years for the X11 utility source file.
  • Adjust SPDX-FileCopyrightText range from 2024 to 2024 - 2026.
frame/utility_x11.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
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 touch handling only considers QEvent::TouchBegin and the first touch point; if multi-touch or subsequent TouchUpdate events can occur outside the popup, consider whether they should also trigger the outside-close behavior to avoid edge cases.
  • The new touch branch assumes m_target is valid and uses geometry() directly; if there are code paths where the filter might outlive or be detached from m_target, add a defensive null/visibility check similar to whatever is used for the existing mouse logic.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The touch handling only considers QEvent::TouchBegin and the first touch point; if multi-touch or subsequent TouchUpdate events can occur outside the popup, consider whether they should also trigger the outside-close behavior to avoid edge cases.
- The new touch branch assumes m_target is valid and uses geometry() directly; if there are code paths where the filter might outlive or be detached from m_target, add a defensive null/visibility check similar to whatever is used for the existing mouse logic.

## Individual Comments

### Comment 1
<location path="frame/utility_x11.cpp" line_range="128-129" />
<code_context>
+        QTouchEvent *touchEvent = static_cast<QTouchEvent *>(event);
+        if (!touchEvent->points().isEmpty()) {
+            QEventPoint pt = touchEvent->points().first();
+            const auto bounding = m_target->geometry();
+            const auto pos = pt.globalPosition();
+            if (!bounding.contains(pos.toPoint())) {
+                qCDebug(dsLog) << "touch outside menu window:" << m_target->winId();
</code_context>
<issue_to_address>
**issue (bug_risk):** Mixing widget-local geometry with global coordinates may mis-detect outside touches

`m_target->geometry()` is in the parent widget’s coordinate system, but `pt.globalPosition()` is in global screen coordinates. Using them together in `bounding.contains()` can misclassify touches when the window moves or is embedded. Either compare in global coordinates (e.g. `m_target->frameGeometry()`) or first map the global point into the target’s coordinates with `m_target->mapFromGlobal(pos.toPoint())` before calling `rect().contains(...)`.
</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 frame/utility_x11.cpp Outdated
1. Add QTouchEvent handling to MouseGrabEventFilter in frame/
utility_x11.cpp.
2. Detect QEvent::TouchBegin and read the first touch point's global
position.
3. When the touch happens outside the target popup window geometry, emit
outsideMousePressed() and consume the event.
4. Keep the existing mouse-based outside-click logic unchanged while
extending the same close-popup behavior to touch input.
5. This fixes an issue on touch-screen devices where, after the plugin
area context menu was shown, tapping other areas of the taskbar did
not respond because touch interactions outside the popup were not being
handled.

Log: Fixed taskbar touch no-response issue when plugin area context menu
is open

Influence:
1. On an X11 touch-screen device, open the plugin area context menu
and tap outside the popup on different taskbar areas; verify the popup
closes and the tapped area responds correctly.
2. Verify existing mouse behavior is unchanged: right-click to open the
menu, then click outside to close it.
3. Test tapping inside the popup to confirm normal menu interaction
is preserved.
4. Test repeated open/close operations with both mouse and touch input
to ensure there are no stuck grab states or lost events.
5. Verify no regressions for non-touch environments on X11.

fix: 处理 X11 下弹窗外部触控关闭逻辑

1. 在 frame/utility_x11.cpp 的 MouseGrabEventFilter 中新增 QTouchEvent
处理逻辑。
2. 检测 QEvent::TouchBegin,并读取第一个触控点的全局坐标。
3. 当触控位置位于目标弹窗窗口几何范围之外时,触发 outsideMousePressed()
并消费该事件。
4. 在保留原有鼠标外部点击处理逻辑不变的基础上,将相同的关闭弹窗行为扩展
到触控输入。
5. 该修改修复了触控屏设备上插件区域右键菜单弹出后,点击任务栏其他区域无
响应的问题,原因是此前未处理弹窗外部的触控事件。

Log: 修复插件区域右键菜单打开时任务栏触控无响应问题

Influence:
1. 在 X11 触控屏设备上打开插件区域右键菜单后,点击弹窗外的不同任务栏区
域,确认弹窗会关闭且被点击区域能够正常响应。
2. 验证现有鼠标行为不受影响:右键打开菜单后,鼠标点击外部仍可正常关闭。
3. 测试在弹窗内部点击,确认菜单本身的交互仍然正常。
4. 使用鼠标和触控反复执行打开/关闭操作,确认不存在 grab 状态残留或事件丢
失问题。
5. 验证 X11 非触控环境下无回归。

PMS: BUG-362159
Change-Id: I3c6ed96f01408c3c966f17ae7b999858c0c9ec46
@deepin-ci-robot
Copy link
Copy Markdown

deepin pr auto review

你好!我是CodeGeeX,你的智能编程助手。我已经仔细审查了你提供的 Git Diff。

本次修改主要实现了两个目标:一是增加了对触摸事件(QEvent::TouchBegin)的处理,以支持在触摸屏上点击弹窗外部时关闭弹窗;二是将窗口几何坐标的获取从 geometry() 统一替换为 frameGeometry(),以修复在包含窗口装饰(如标题栏)时全局坐标比较不准确的问题。

整体修改逻辑清晰,但在代码安全(健壮性)逻辑一致性代码性能方面,我提出以下改进意见:

1. 代码安全与健壮性

问题: 在新增的 TouchBegin 事件处理逻辑中,直接对 touchEvent 进行了 static_cast 且未做空指针检查,同时也未对 m_target 进行有效性检查。

QTouchEvent *touchEvent = static_cast<QTouchEvent *>(event);
if (!touchEvent->points().isEmpty()) { ... }

风险: 虽然 Qt 的事件系统通常会保证事件类型匹配,但 static_cast 不具备运行时类型安全检查。如果 m_target 在事件传递过程中被意外销毁,会导致空指针解引用崩溃。

改进建议: 使用 dynamic_cast 并增加空指针校验,与 m_target 的安全检查保持一致。

} else if (event->type() == QEvent::TouchBegin) {
    QTouchEvent *touchEvent = dynamic_cast<QTouchEvent *>(event);
    if (touchEvent && m_target && !touchEvent->points().isEmpty()) {
        // ... 逻辑处理
    }
}

2. 逻辑一致性

问题: 在原有的 mousePressEventtrySelectGrabWindow 中,有一个特殊的判断逻辑:e->position().toPoint().isNull() && !pos.isNull()。这通常是为了兼容某些平台下鼠标事件的异常坐标偏移。
然而,在新增的 TouchBegin 处理中,并没有类似的兼容性判断,只是单纯地判断了 !bounding.contains(pos.toPoint())

风险: 如果在 X11 平台下,触摸屏驱动或 Qt 的事件转换同样存在坐标异常(例如 position() 为空而 globalPosition() 有效),当前的触摸逻辑可能会误判,导致弹窗无法正常关闭或异常关闭。

改进建议: 建议将触摸事件的判断逻辑与鼠标事件对齐,保持平台行为的一致性:

const auto pos = pt.globalPosition();
if ((pt.position().toPoint().isNull() && !pos.isNull()) ||
    !bounding.contains(pos.toPoint())) {
    qCDebug(dsLog) << "touch outside menu window:" << m_target->winId();
    emit outsideMousePressed();
    return true;
}

3. 代码性能

问题:trySelectGrabWindow 的循环中:

for (auto item : Utility::instance()->allChildrenWindows(m_target)) {

风险: auto item 会导致 QList 中的指针(假设是 QWidget*QWindow*)发生不必要的拷贝。虽然指针拷贝开销极小,但作为遍历习惯,应按引用或指针传递以避免潜在的深拷贝风险(如果未来容器类型发生变化)。

改进建议: 使用 const auto & 或直接使用原始指针类型 auto *

for (auto *item : Utility::instance()->allChildrenWindows(m_target)) {

4. 代码质量与可维护性

问题: 修改后,mousePressEventtrySelectGrabWindow 和新增的 Touch 逻辑中,反复出现了相同的边界判断代码:

const auto bounding = m_target->frameGeometry();
const auto pos = ...;
if ((... .isNull() && !pos.isNull()) || !bounding.contains(pos.toPoint())) { ... }

风险: 违反了 DRY (Don't Repeat Yourself) 原则。如果未来坐标判定逻辑需要调整(例如改用浮点数判定以支持高分辨率),需要同时修改多处,容易遗漏。

改进建议: 可以考虑提取一个私有方法,例如 isOutsideTarget(const QPointF &localPos, const QPointF &globalPos),将核心判断逻辑内聚:

bool MouseGrabEventFilter::isOutsideTarget(const QPointF &localPos, const QPointF &globalPos) const {
    if (!m_target) return true;
    const auto bounding = m_target->frameGeometry();
    if ((localPos.toPoint().isNull() && !globalPos.isNull()) ||
        !bounding.contains(globalPos.toPoint())) {
        return true;
    }
    return false;
}

然后在各处直接调用 isOutsideTarget(pt.position(), pt.globalPosition()) 即可。


综合改进后的代码示例

结合以上意见,改进后的核心代码部分如下:

// 在头文件中建议添加私有方法声明
// bool isOutsideTarget(const QPointF &localPos, const QPointF &globalPos) const;

bool MouseGrabEventFilter::eventFilter(QObject *watched, QEvent *event)
{
    if (event->type() == QEvent::MouseButtonPress) {
        if (isMainWindow()) {
            trySelectGrabWindow(static_cast<QMouseEvent *>(event));
        }
    } else if (event->type() == QEvent::TouchBegin) {
        // 增加类型安全检查与空指针保护
        QTouchEvent *touchEvent = dynamic_cast<QTouchEvent *>(event);
        if (touchEvent && m_target && !touchEvent->points().isEmpty()) {
            QEventPoint pt = touchEvent->points().first();
            // 逻辑与鼠标事件保持一致
            if (isOutsideTarget(pt.position(), pt.globalPosition())) {
                qCDebug(dsLog) << "touch outside menu window:" << m_target->winId();
                emit outsideMousePressed();
                return true;
            }
        }
    }
    return false;
}

void MouseGrabEventFilter::mousePressEvent(QMouseEvent *e)
{
    if (isOutsideTarget(e->position(), e->globalPosition())) {
        emit outsideMousePressed();
    }
}

bool MouseGrabEventFilter::trySelectGrabWindow(QMouseEvent *e)
{
    if (isOutsideTarget(e->position(), e->globalPosition())) {
        for (auto *item : Utility::instance()->allChildrenWindows(m_target)) { // 使用 auto* 避免拷贝
            if (!item->isVisible() || isMainWindow(item))
                continue;
            // Use frameGeometry() for child windows too
            if (item->frameGeometry().contains(e->globalPosition().toPoint())) {
                qCDebug(dsLog) << "grab mouse for the window:" << item->winId();
                m_target->setMouseGrabEnabled(false);
                item->setMouseGrabEnabled(true);
                return true; // 假设原代码此处有 return 逻辑,或者放在循环外
            }
        }
    }
    return false; // 假设原代码有默认返回值
}

// 新增的辅助函数
bool MouseGrabEventFilter::isOutsideTarget(const QPointF &localPos, const QPointF &globalPos) const
{
    if (!m_target) return true;
    const auto bounding = m_target->frameGeometry();
    return (localPos.toPoint().isNull() && !globalPos.isNull()) ||
           !bounding.contains(globalPos.toPoint());
}

希望这些建议能帮助你进一步提升代码质量!如果有任何疑问,欢迎继续交流。

@deepin-ci-robot
Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: 18202781743, 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 263f2ec into linuxdeepin:master May 21, 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