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 --- src/quick/items/qquickwindow.cpp | 4 +-- .../qquicklistview/data/delegateWithMouseArea.qml | 29 ++++++++++++++++++ .../quick/qquicklistview/tst_qquicklistview.cpp | 34 ++++++++++++++++++++++ 3 files changed, 65 insertions(+), 2 deletions(-) create mode 100644 tests/auto/quick/qquicklistview/data/delegateWithMouseArea.qml diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index fa9aa88faa..c6bfcaa647 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -2017,8 +2017,8 @@ bool QQuickWindowPrivate::deliverTouchCancelEvent(QTouchEvent *event) qCDebug(DBG_TOUCH) << event; Q_Q(QQuickWindow); - if (q->mouseGrabberItem()) - q->mouseGrabberItem()->ungrabMouse(); + if (QQuickItem *grabber = q->mouseGrabberItem()) + sendUngrabEvent(grabber, true); cancelTouchMouseSynthesis(); // A TouchCancel event will typically not contain any points. 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 --- src/quick/handlers/qquickdraghandler.cpp | 7 ++--- .../qquickdraghandler/data/dragMargin.qml | 36 ++++++++++++++++++++++ .../qquickdraghandler/tst_qquickdraghandler.cpp | 33 ++++++++++++++++++++ 3 files changed, 72 insertions(+), 4 deletions(-) create mode 100644 tests/auto/quick/pointerhandlers/qquickdraghandler/data/dragMargin.qml diff --git a/src/quick/handlers/qquickdraghandler.cpp b/src/quick/handlers/qquickdraghandler.cpp index 48f0599284..e5531369cf 100644 --- a/src/quick/handlers/qquickdraghandler.cpp +++ b/src/quick/handlers/qquickdraghandler.cpp @@ -112,14 +112,13 @@ QPointF QQuickDragHandler::targetCentroidPosition() void QQuickDragHandler::onGrabChanged(QQuickPointerHandler *grabber, QQuickEventPoint::GrabTransition transition, QQuickEventPoint *point) { QQuickMultiPointHandler::onGrabChanged(grabber, transition, point); - if (grabber == this && transition == QQuickEventPoint::GrabExclusive) { + if (grabber == this && transition == QQuickEventPoint::GrabExclusive && target()) { // In case the grab got handed over from another grabber, we might not get the Press. if (!m_pressedInsideTarget) { - if (target()) + if (target() != parentItem()) m_pressTargetPos = QPointF(target()->width(), target()->height()) / 2; } else if (m_pressTargetPos.isNull()) { - if (target()) - m_pressTargetPos = targetCentroidPosition(); + m_pressTargetPos = targetCentroidPosition(); } } } 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 b150debb687fda0387716b8b4eca08033da6b654 Mon Sep 17 00:00:00 2001 From: Kai Koehne Date: Fri, 5 Apr 2019 12:20:55 +0200 Subject: Fix clang-cl compiler warnings clang-cl.exe 8.0.0 warns: qv4internalclass_p.h(460,19): warning: unqualified friend declaration referring to type outside of the nearest enclosing namespace is a Microsoft extension; add a nested name specifier [-Wmicrosoft-unqualified-friend] The warning is most likely bogus (otherwise the code wouldn't compile on other platforms. But it's arguably not a bad idea to just qualify the friend declaration. Change-Id: Ia34119661c29cd8619adec70e9999cab2605ff32 Reviewed-by: Ulf Hermann --- src/qml/jsruntime/qv4internalclass_p.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qml/jsruntime/qv4internalclass_p.h b/src/qml/jsruntime/qv4internalclass_p.h index 42b61218a5..7bb10f47a3 100644 --- a/src/qml/jsruntime/qv4internalclass_p.h +++ b/src/qml/jsruntime/qv4internalclass_p.h @@ -457,7 +457,7 @@ private: InternalClass *addMemberImpl(PropertyKey identifier, PropertyAttributes data, InternalClassEntry *entry); void removeChildEntry(InternalClass *child); - friend struct ExecutionEngine; + friend struct ::QV4::ExecutionEngine; }; inline -- cgit v1.2.3 From 651177db69a61278da5bc1b2434b8e7f291d5636 Mon Sep 17 00:00:00 2001 From: Rolf Eike Beer Date: Tue, 19 Mar 2019 11:56:11 +0100 Subject: QSGDefaultContext: sort GL_EXTENSIONS before printing them Change-Id: Ia57d037901327ca44e7758c09398dd51dc621319 Reviewed-by: Simon Hausmann --- src/quick/scenegraph/qsgdefaultcontext.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/quick/scenegraph/qsgdefaultcontext.cpp b/src/quick/scenegraph/qsgdefaultcontext.cpp index 1124bf1727..5813844cd2 100644 --- a/src/quick/scenegraph/qsgdefaultcontext.cpp +++ b/src/quick/scenegraph/qsgdefaultcontext.cpp @@ -62,6 +62,8 @@ #include +#include + QT_BEGIN_NAMESPACE namespace QSGMultisampleAntialiasing { @@ -158,11 +160,9 @@ void QSGDefaultContext::renderContextInitialized(QSGRenderContext *renderContext qCDebug(QSG_LOG_INFO, "GL_RENDERER: %s", (const char*)funcs->glGetString(GL_RENDERER)); qCDebug(QSG_LOG_INFO, "GL_VERSION: %s", (const char*)funcs->glGetString(GL_VERSION)); - QSet exts = openglRenderContext->openglContext()->extensions(); - QByteArray all; - for (const QByteArray &e : qAsConst(exts)) - all += ' ' + e; - qCDebug(QSG_LOG_INFO, "GL_EXTENSIONS: %s", all.constData()); + QByteArrayList exts = openglRenderContext->openglContext()->extensions().toList(); + std::sort(exts.begin(), exts.end()); + qCDebug(QSG_LOG_INFO, "GL_EXTENSIONS: %s", exts.join(' ').constData()); qCDebug(QSG_LOG_INFO, "Max Texture Size: %d", openglRenderContext->maxTextureSize()); qCDebug(QSG_LOG_INFO, "Debug context: %s", format.testOption(QSurfaceFormat::DebugContext) ? "true" : "false"); -- 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 --- src/qml/jsruntime/qv4runtime.cpp | 1 + tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp | 17 +++++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp index 85d06bcabe..6a242ba5f6 100644 --- a/src/qml/jsruntime/qv4runtime.cpp +++ b/src/qml/jsruntime/qv4runtime.cpp @@ -1942,6 +1942,7 @@ ReturnedValue Runtime::method_div(const Value &left, const Value &right) int lval = left.integerValue(); int rval = right.integerValue(); if (rval != 0 // division by zero should result in a NaN + && !(lval == std::numeric_limits::min() && rval == -1) // doesn't fit in int && (lval % rval == 0) // fractions can't be stored in an int && !(lval == 0 && rval < 0)) // 0 / -something results in -0.0 return Encode(int(lval / rval)); 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 From 4b6832828e04a9806aaf345da5f456817dd3970b Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Mon, 8 Apr 2019 15:39:45 +0200 Subject: Don't use delegate model types on -no-feature-delegate-model Fixes: QTBUG-74884 Change-Id: I7a675f6ef41937cef0f8e67960486c5b022d735c Reviewed-by: Simon Hausmann --- src/qml/types/qqmlmodelsmodule.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/qml/types/qqmlmodelsmodule.cpp b/src/qml/types/qqmlmodelsmodule.cpp index 30915d96fd..bb72771cd9 100644 --- a/src/qml/types/qqmlmodelsmodule.cpp +++ b/src/qml/types/qqmlmodelsmodule.cpp @@ -72,9 +72,11 @@ void QQmlModelsModule::defineLabsModule() { const char uri[] = "Qt.labs.qmlmodels"; +#if QT_CONFIG(qml_delegate_model) qmlRegisterUncreatableType(uri, 1, 0, "AbstractDelegateComponent", QQmlAbstractDelegateComponent::tr("Cannot create instance of abstract class AbstractDelegateComponent.")); qmlRegisterType(uri, 1, 0, "DelegateChooser"); qmlRegisterType(uri, 1, 0, "DelegateChoice"); +#endif } QT_END_NAMESPACE -- cgit v1.2.3