From c6f88a807c9872f81000dc01de94145022bc76c5 Mon Sep 17 00:00:00 2001 From: Richard Moe Gustavsen Date: Tue, 17 Oct 2023 14:51:21 +0200 Subject: [PATCH] QQuickFlickable: release drag if receiving QEvent::TouchCancel MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If a TouchCancel event is sent to a Flickable, it should abort any current dragging operation done by the user. This patch will ensure that we do so. Fixes: QTBUG-117160 Change-Id: Iff332e597a0502396c2fd0e4988f01ab2119314d Reviewed-by: Jan Arve Sæther Reviewed-by: Seokha Ko Reviewed-by: Shawn Rutledge (cherry picked from commit 5093e4c24347a2044e23ba057c0dfdc64df5019d) Reviewed-by: Qt Cherry-pick Bot (cherry picked from commit 3544aae7286902d22b5bdd3a0d5ee89578ce8814) --- src/quick/items/qquickflickable.cpp | 9 ++++++ .../qquickflickable/tst_qquickflickable.cpp | 29 +++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/src/quick/items/qquickflickable.cpp b/src/quick/items/qquickflickable.cpp index 7eac4fe471..cda8e62587 100644 --- a/src/quick/items/qquickflickable.cpp +++ b/src/quick/items/qquickflickable.cpp @@ -1546,6 +1546,15 @@ void QQuickFlickable::mouseReleaseEvent(QMouseEvent *event) void QQuickFlickable::touchEvent(QTouchEvent *event) { Q_D(QQuickFlickable); + + if (event->type() == QEvent::TouchCancel) { + if (d->interactive && d->wantsPointerEvent(event)) + d->cancelInteraction(); + else + QQuickItem::touchEvent(event); + return; + } + bool unhandled = false; const auto &firstPoint = event->points().first(); switch (firstPoint.state()) { diff --git a/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp b/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp index 7c0bdcadea..37810c967d 100644 --- a/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp +++ b/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp @@ -224,6 +224,7 @@ private slots: void setContentPositionWhileDragging(); void coalescedMove(); void onlyOneMove(); + void touchCancel(); private: void flickWithTouch(QQuickWindow *window, const QPoint &from, const QPoint &to); @@ -3236,6 +3237,34 @@ void tst_qquickflickable::onlyOneMove() QCOMPARE(flickEndedSpy.size(), 1); } +void tst_qquickflickable::touchCancel() +{ + QQuickView window; + QVERIFY(QQuickTest::showView(window, testFileUrl("flickable03.qml"))); + QQuickViewTestUtils::centerOnScreen(&window); + QVERIFY(window.isVisible()); + + QQuickFlickable *flickable = qobject_cast(window.rootObject()); + QVERIFY(flickable != nullptr); + + QSignalSpy movementStartedSpy(flickable, SIGNAL(movementStarted())); + QSignalSpy movementEndedSpy(flickable, SIGNAL(movementEnded())); + + int touchPosY = 10; + QTest::touchEvent(&window, touchDevice).press(0, {10, touchPosY}).commit(); + QQuickTouchUtils::flush(&window); + + for (int i = 0; i < 3; ++i) { + touchPosY += qApp->styleHints()->startDragDistance(); + QTest::touchEvent(&window, touchDevice).move(0, {10, touchPosY}).commit(); + QQuickTouchUtils::flush(&window); + } + + QTRY_COMPARE(movementStartedSpy.size(), 1); + QWindowSystemInterface::handleTouchCancelEvent(nullptr, touchDevice); + QTRY_COMPARE(movementEndedSpy.size(), 1); +} + QTEST_MAIN(tst_qquickflickable) #include "tst_qquickflickable.moc"