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/auto') 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 From 0c02691f7ba646e782b04347fde3d75f9582b317 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Fri, 5 Apr 2019 15:00:59 +0200 Subject: If DragHandler is dragged within its margin, don't jump MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Not being pressed inside the target is a necessary but not sufficient reason to reset m_pressTargetPos to the center of the target. The intention was rather to make the target jump into position when the parent was a different item: e.g. if a Slider has a DragHandler whose target is the slider's knob, you can start dragging anywhere on the whole Slider but you want the knob to jump to the cursor position when the drag begins. While we're at it, both branches of the if in onGrabChanged() are checking that target() isn't null, so we can move that check out. Fixes: QTBUG-74966 Change-Id: I05be11d27422b070d941b9e43d4e1157e071c3a5 Reviewed-by: Jan Arve Sæther --- .../qquickdraghandler/data/dragMargin.qml | 36 ++++++++++++++++++++++ .../qquickdraghandler/tst_qquickdraghandler.cpp | 33 ++++++++++++++++++++ 2 files changed, 69 insertions(+) create mode 100644 tests/auto/quick/pointerhandlers/qquickdraghandler/data/dragMargin.qml (limited to 'tests/auto') diff --git a/tests/auto/quick/pointerhandlers/qquickdraghandler/data/dragMargin.qml b/tests/auto/quick/pointerhandlers/qquickdraghandler/data/dragMargin.qml new file mode 100644 index 0000000000..e5ca681bd5 --- /dev/null +++ b/tests/auto/quick/pointerhandlers/qquickdraghandler/data/dragMargin.qml @@ -0,0 +1,36 @@ +import QtQuick 2.12 + +Rectangle { + color: "#333" + width: 480; height: 480 + + Rectangle { + color: "#112" + width: 100 + height: 100 + x: 50; y: 50 + + DragHandler { + id: dragHandler + margin: 20 + } + + Rectangle { + id: rect + anchors.fill: parent + anchors.margins: -dragHandler.margin + color: "transparent" + border.color: "cyan" + border.width: 2 + radius: 10 + antialiasing: true + + Text { + color: "cyan" + text: "drag this margin area" + font.pixelSize: 10 + anchors.horizontalCenter: parent.horizontalCenter + } + } + } +} diff --git a/tests/auto/quick/pointerhandlers/qquickdraghandler/tst_qquickdraghandler.cpp b/tests/auto/quick/pointerhandlers/qquickdraghandler/tst_qquickdraghandler.cpp index eb210c2112..cc8c567e5c 100644 --- a/tests/auto/quick/pointerhandlers/qquickdraghandler/tst_qquickdraghandler.cpp +++ b/tests/auto/quick/pointerhandlers/qquickdraghandler/tst_qquickdraghandler.cpp @@ -55,6 +55,7 @@ private slots: void defaultPropertyValues(); void touchDrag(); void mouseDrag(); + void dragFromMargin(); void touchDragMulti(); void touchDragMultiSliders_data(); void touchDragMultiSliders(); @@ -251,6 +252,38 @@ void tst_DragHandler::mouseDrag() QCOMPARE(centroidChangedSpy.count(), 5); } +void tst_DragHandler::dragFromMargin() // QTBUG-74966 +{ + const int dragThreshold = QGuiApplication::styleHints()->startDragDistance(); + QScopedPointer windowPtr; + createView(windowPtr, "dragMargin.qml"); + QQuickView * window = windowPtr.data(); + + QQuickItem *draggableItem = window->rootObject()->childItems().first(); + QVERIFY(draggableItem); + QQuickDragHandler *dragHandler = draggableItem->findChild(); + QVERIFY(dragHandler); + + QPointF originalPos = draggableItem->position(); + QPointF scenePressPos = originalPos - QPointF(10, 0); + QPoint p1 = scenePressPos.toPoint(); + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1); + QVERIFY(!dragHandler->active()); + QCOMPARE(dragHandler->centroid().scenePosition(), scenePressPos); + QCOMPARE(dragHandler->centroid().scenePressPosition(), scenePressPos); + p1 += QPoint(dragThreshold * 2, 0); + QTest::mouseMove(window, p1); + QTRY_VERIFY(dragHandler->active()); + QCOMPARE(dragHandler->centroid().scenePressPosition(), scenePressPos); + QCOMPARE(dragHandler->centroid().sceneGrabPosition(), p1); + QCOMPARE(dragHandler->translation().x(), 0.0); // hmm that's odd + QCOMPARE(dragHandler->translation().y(), 0.0); + QCOMPARE(draggableItem->position(), originalPos + QPointF(dragThreshold * 2, 0)); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1); + QTRY_VERIFY(!dragHandler->active()); + QCOMPARE(dragHandler->centroid().pressedButtons(), Qt::NoButton); +} + void tst_DragHandler::touchDragMulti() { const int dragThreshold = QGuiApplication::styleHints()->startDragDistance(); -- cgit v1.2.3 From 78787011651692b64bef19f6bec03d0dbf390e18 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Mon, 8 Apr 2019 14:45:23 +0200 Subject: Avoid INT_MIN % -1 and INT_MIN / -1 Those throw arithmetic exceptions as the result doesn't fit into an integer. Fixes: QTBUG-75030 Change-Id: Ibd978848f42cf1c9da1e4af2dc9d7da123ef8f5a Reviewed-by: Simon Hausmann --- tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'tests/auto') diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp index d8784f4855..0e8844d23f 100644 --- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp +++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp @@ -366,6 +366,7 @@ private slots: void tailCallWithArguments(); void deleteSparseInIteration(); void saveAccumulatorBeforeToInt32(); + void intMinDividedByMinusOne(); private: // static void propertyVarWeakRefCallback(v8::Persistent object, void* parameter); @@ -8941,6 +8942,22 @@ void tst_qqmlecmascript::saveAccumulatorBeforeToInt32() QCOMPARE(value.toString(), QLatin1String("RangeError: Maximum call stack size exceeded.")); } +void tst_qqmlecmascript::intMinDividedByMinusOne() +{ + QQmlEngine engine; + QQmlComponent component(&engine); + component.setData(QByteArray("import QtQml 2.2\n" + "QtObject {\n" + " property int intMin: -2147483648\n" + " property int minusOne: -1\n" + " property double doesNotFitInInt: intMin / minusOne\n" + "}"), QUrl()); + QVERIFY(component.isReady()); + QScopedPointer object(component.create()); + QVERIFY(!object.isNull()); + QCOMPARE(object->property("doesNotFitInInt").toUInt(), 2147483648u); +} + QTEST_MAIN(tst_qqmlecmascript) #include "tst_qqmlecmascript.moc" -- cgit v1.2.3