Skip to content

fix: prevent window move and double-page flick on Treeland - #432

Open
JWWTSL wants to merge 2 commits into
linuxdeepin:masterfrom
JWWTSL:fix/bug-345097-treeland-drag
Open

JWWTSL wants to merge 2 commits into
linuxdeepin:masterfrom
JWWTSL:fix/bug-345097-treeland-drag

Conversation

@JWWTSL

@JWWTSL JWWTSL commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor
  1. Record the press position before filtering the first out-of-range move, and disable system window move while the image content holds the pointer.
  2. Pin PathView navigation to a single committed page per left-button gesture, clear leftover drag state on hover/release at the window boundary, and only treat left-button moves as boundary drags.

Log: Fix the viewer window following the pointer and double-page flick on Treeland

Influence:

  1. Verify dragging inside the image no longer moves the window.

  2. Verify a fast drag advances at most one page.

  3. Verify the first and last pages no longer show blank pages when dragging.

  4. Verify normal paging and window move still work.

  5. 记录按下位置后再过滤首个越界移动;图片内容持有指针时禁用系统窗口移动。

  6. 一次左键手势最多翻一页,松开或悬停在边界时清理残留拖拽状态,仅左键移动才当作边界拖拽。

Log: 修复看图窗口跟随指针移动与快速拖拽连翻两页的问题

Influence:

  1. 图片内容区域拖拽,确认窗口不再跟随移动。
  2. 快速拖拽,确认最多翻一页。
  3. 首末页拖拽,确认不再出现空白页。
  4. 确认正常翻页与窗口移动不受影响。

PMS: BUG-345097

Summary by Sourcery

Prevent Treeland pointer gestures from moving the viewer window or causing multiple page advances during a single drag.

Bug Fixes:

  • Prevent image dragging from moving the viewer window on Treeland, including when pointer-release events are lost.
  • Ensure boundary drags advance at most one page and do not expose blank pages at the first or last image.
  • Clear stale drag state on release, hover, cancellation, or window deactivation, and restrict boundary navigation to left-button gestures.

Enhancements:

  • Preserve normal image paging and title-bar window movement while adding safer gesture handling.

Tests:

  • Expand PathView range-handler coverage for press-position filtering, button-specific movement, boundary behavior, and window-level drag-state cleanup.

Record press position before filtering the first out-of-range move.\nDisable system move while the image content holds the pointer.\n\nLog: 修复看图内容拖拽移动窗口与首尾空白页\nPMS: BUG-345097\nInfluence: 图片翻页边界与内容区拖拽手势。
Pin PathView navigation to a single committed page per left-button gesture,
clear leftover drag state on hover/release at the window boundary, and only
treat left-button moves as boundary drags.

修复 Treeland 看图拖动:一次左键手势最多翻一页,松开/悬停不再拖动图片。

Log: 修复看图窗口跟随移动与快速拖拽连翻两页
PMS: BUG-345097
Influence: 图片拖拽翻页、窗口移动与首末页边界行为。
@deepin-ci-robot

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: JWWTSL

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

@sourcery-ai

sourcery-ai Bot commented Oct 28, 2026

Copy link
Copy Markdown

Reviewer's Guide

The PR coordinates QML gesture state, PathView clamping, and C++ event filtering to keep image drags from moving the Treeland window, limit fast gestures to one page, eliminate blank edge pages, and recover safely when pointer-release events are lost.

Sequence diagram for guarded image dragging on Treeland

sequenceDiagram
    actor User
    participant ImageInputHandler
    participant Window as ApplicationWindow
    participant PathViewRangeHandler
    participant Treeland

    User->>ImageInputHandler: MouseButtonPress
    ImageInputHandler->>Window: imagePointerDown = true
    Window->>Treeland: DWindow.enableSystemMove = false
    User->>PathViewRangeHandler: MouseMove with LeftButton
    PathViewRangeHandler->>PathViewRangeHandler: Capture press position and check boundary
    alt Out-of-range drag
        PathViewRangeHandler-->>Treeland: Consume move
    else Valid drag
        PathViewRangeHandler-->>ImageInputHandler: Allow image navigation
    end
    User->>Window: MouseButtonRelease
    Window->>Window: imagePointerDown = false
    Window->>Treeland: DWindow.enableSystemMove = true
Loading

Sequence diagram for single-page PathView navigation

sequenceDiagram
    actor User
    participant PathView
    participant ImageViewer
    participant ViewModel

    User->>PathView: Left-button drag
    PathView->>ImageViewer: beginBoundaryDrag()
    ImageViewer->>ImageViewer: Capture boundary availability
    PathView->>ImageViewer: currentIndex change
    ImageViewer->>ViewModel: previousImage() or nextImage()
    ImageViewer->>ImageViewer: navigationCommitted = true
    PathView->>ImageViewer: Additional flick movement
    ImageViewer->>PathView: Clamp to committedIndex()
    User->>PathView: Release
    PathView->>ImageViewer: onMovementEnded
    ImageViewer->>ImageViewer: Clear boundary drag state
Loading

File-Level Changes

Change Details Files
Prevent image gestures from being interpreted as system window moves, including lost-release and boundary cases.
  • Track left-button image presses through a window-level flag and disable automatic system movement while active.
  • Add release, hover, and window-deactivation cleanup via QML handlers and a QQuickWindow event filter.
  • Explicitly start system movement only from the empty title-bar surface.
  • Capture the press position before filtering boundary motion and consume forbidden moves instead of passing them to the compositor.
src/main.cpp
src/qml/FullImageView.qml
src/qml/Utils/ImageInputHandler.qml
src/qml/ViewTopTitle.qml
src/qml/main.qml
src/src/declarative/pathviewrangehandler.cpp
src/src/declarative/pathviewrangehandler.h
Constrain each left-button PathView gesture to one committed page and prevent invalid edge navigation or residual momentum.
  • Track boundary-drag state, press-time page availability, direction, and committed navigation state.
  • Clamp PathView offset at first/last-page boundaries and pin momentum to the committed page after navigation.
  • Clear drag and navigation guards when movement ends, or defer cleanup until taps and settled gestures are complete.
  • Handle both PathView and delegate MouseArea input paths through shared window pointer state.
src/qml/ImageViewer.qml
src/qml/FullImageView.qml
src/qml/Utils/ImageInputHandler.qml
Expand regression coverage for press-based boundary filtering and window-level drag-state recovery.
  • Verify the first out-of-range move is filtered from the recorded press, including a press at coordinate (0,0).
  • Verify hover, right-button movement, non-target movement, and accepted-event semantics.
  • Verify left release, hover without buttons, and window deactivation clear the shared drag state while left-button movement preserves it.
tests/src/test_pathviewrangehandler.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

@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 reviewed your changes and they look great!


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

@deepin-ci-robot

Copy link
Copy Markdown

deepin pr auto review

🤖 AI 代码审查报告

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

Pass


📊 总体评价

项目 结果
审查结论 代码审查通过
评分详情 本 PR 修复 PathView 边界拖拽导航在快速甩动下的多个交互缺陷(BUG-345097), 包括双翻页、丢失释放事件导致拖拽残留、(0,0) 基点误判、悬停/右键误触发拖拽、 以及 Treeland 窗口移动冲突。代码注释详尽、测试覆盖全面、逻辑边界处理完善, 无安全漏洞。存在少量轻微问题(返回值依赖、魔法数字、setProperty 开销), 不影响功能正确性。

🔍 详细分析

1. 语法逻辑 ✅

评价: 语法正确,逻辑清晰 ✅ 通过

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

建议: ['确认 IV.GControl.nextImage()/previousImage() 返回布尔值,或在 QML 层显式处理 undefined 返回值', '可考虑在 beginBoundaryDrag 入口加 if (boundaryDragActive) return; 防御重复调用']


2. 代码质量 ✅

评价: 代码结构清晰,注释完整 ✅ 通过

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

建议: ['为 distance 阈值添加注释或提取为命名常量,说明为何以 1 为单位距离阈值', '考虑将 onOffsetChanged 的钳位逻辑提取为独立函数以降低嵌套深度']


3. 代码性能 ✅

评价: 性能良好,资源使用合理 ✅ 通过

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

建议: ['可考虑缓存 QQuickWindow 的 imagePointerDown 属性索引或使用 QML 直接绑定替代 setProperty,但当前实现开销可忽略']


4. 代码安全 🔒

评价: 存在0个安全漏洞 ✅ 通过

🔐 发现 0 个安全漏洞

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

建议: []


💡 改进建议代码示例

// ImageViewer.qml — 为 distance 阈值添加注释并防御重复调用
function beginBoundaryDrag() {
    if (boundaryDragActive)
        return; // 防御 TapHandler + Connections 重复调用
    boundaryDragOffset = offset;
    pressProxyIndex = IV.GControl.viewModel.currentIndex;
    canDragPrevious = IV.GControl.hasPreviousImage;
    canDragNext = IV.GControl.hasNextImage;
    navigationCommitted = false;
    committedDirection = 0;
    boundaryDragActive = true;
}

// onOffsetChanged 中为阈值添加注释
// threshold = 1: PathView 以 delegate 宽度为偏移单位,
// |distance| > 1 表示已越过相邻 delegate 边界
var DRAG_THRESHOLD = 1;
if (distance > DRAG_THRESHOLD) {
    offset = (boundaryDragOffset + 1) % count;
} else if (distance < -DRAG_THRESHOLD) {
    offset = (boundaryDragOffset - 1 + count) % count;
}

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

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.

2 participants