From aba6cea90e023c99ac55b0e8dcdeae0af8305ef2 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Wed, 3 Apr 2019 16:16:19 +0200 Subject: In response to touch cancel, don't just ungrab, send an ungrab event MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit QQuickWindowPrivate::sendUngrabEvent() sends an UngrabMouse event, and that can be filtered by parent filters. If a touch cancel happens to a MouseArea in a ListView delegate, we need the ListView to filter the UngrabMouse event so that QQuickFlickable::childMouseEventFilter() will call QQuickFlickable::mouseUngrabEvent() and QQuickFlickablePrivate::cancelInteraction() will set pressed to false. The pressed state became true because Flickable filtered the press event; so for symmetry, it also needs to filter the touch cancel (in the form of a mouse ungrab), to avoid being stuck in a state where it can't move programmatically. Fixes: QTBUG-74679 Change-Id: I6c0ed364d2bc1f45c7e7b17846a09f6b53f91d0a Reviewed-by: Qt CI Bot Reviewed-by: Jan Arve Sæther --- .../qquicklistview/data/delegateWithMouseArea.qml | 29 ++++++++++++++++++ .../quick/qquicklistview/tst_qquicklistview.cpp | 34 ++++++++++++++++++++++ 2 files changed, 63 insertions(+) create mode 100644 tests/auto/quick/qquicklistview/data/delegateWithMouseArea.qml (limited to 'tests') diff --git a/tests/auto/quick/qquicklistview/data/delegateWithMouseArea.qml b/tests/auto/quick/qquicklistview/data/delegateWithMouseArea.qml new file mode 100644 index 0000000000..e0b8222bfb --- /dev/null +++ b/tests/auto/quick/qquicklistview/data/delegateWithMouseArea.qml @@ -0,0 +1,29 @@ +import QtQuick 2.12 + +ListView { + id: root + objectName: "view" + width: 600 + height: 600 + model: 3 + snapMode: ListView.SnapOneItem + boundsBehavior: Flickable.StopAtBounds + highlightRangeMode: ListView.StrictlyEnforceRange + preferredHighlightBegin: 0 + preferredHighlightEnd: 0 + highlightMoveDuration: 100 + delegate: Rectangle { + id: delegateRect + width: 500 + height: 500 + color: Qt.rgba(Math.random(), Math.random(), Math.random(), 1) + Text { + text: index + font.pixelSize: 128 + anchors.centerIn: parent + } + MouseArea { + anchors.fill: parent + } + } +} diff --git a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp index ff796a5bd8..fddba77f35 100644 --- a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp +++ b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -273,6 +274,7 @@ private slots: void addOnCompleted(); void setPositionOnLayout(); + void touchCancel(); private: template void items(const QUrl &source); @@ -328,6 +330,7 @@ private: QQuickView *m_view; QString testForView; + QTouchDevice *touchDevice = QTest::createTouchDevice(); }; class TestObject : public QObject @@ -8944,6 +8947,37 @@ void tst_QQuickListView::useDelegateChooserWithoutDefault() window->show(); }; +void tst_QQuickListView::touchCancel() // QTBUG-74679 +{ + QScopedPointer window(createView()); + window->setSource(testFileUrl("delegateWithMouseArea.qml")); + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window.data())); + + QQuickListView *listview = qobject_cast(window->rootObject()); + QVERIFY(listview); + QQuickMouseArea *mouseArea = listview->currentItem()->findChild(); + QVERIFY(mouseArea); + + QPoint p1(300, 300); + QTest::touchEvent(window.data(), touchDevice).press(0, p1, window.data()); + QQuickTouchUtils::flush(window.data()); + QTRY_VERIFY(mouseArea->pressed()); + // and because Flickable filtered it, QQuickFlickablePrivate::pressed + // should be true, but it's not easily tested here + + QTouchEvent cancelEvent(QEvent::TouchCancel); + cancelEvent.setDevice(touchDevice); + QCoreApplication::sendEvent(window.data(), &cancelEvent); + // now QQuickWindowPrivate::sendUngrabEvent() will be called, Flickable will filter it, + // QQuickFlickablePrivate::pressed will be set to false, and that will allow setCurrentIndex() to make it move + QQuickTouchUtils::flush(window.data()); + + listview->setCurrentIndex(1); + // ensure that it actually moves (animates) to the second delegate + QTRY_COMPARE(listview->contentY(), 500.0); +} + QTEST_MAIN(tst_QQuickListView) #include "tst_qquicklistview.moc" -- cgit v1.2.3