diff options
author | Shawn Rutledge <shawn.rutledge@qt.io> | 2020-09-18 21:59:48 +0200 |
---|---|---|
committer | Shawn Rutledge <shawn.rutledge@qt.io> | 2020-09-26 09:56:23 +0200 |
commit | 0bd86b0e2ee67c3f99b8a9712c743c25c8be39b8 (patch) | |
tree | 6b5f7c898366871cf65ae30c5ca943a45e5c9d47 | |
parent | 26e5788a273b8614e9b9e701d29a7b6c77adacc0 (diff) |
Handle ungrab and grab-cancel consistently; inform handlers
Call onGrabChanged on Pointer Handlers during grab transitions:
this was missing in a97759a336c597327cb82eebc9f45c793aec32c9.
Flickable needs to receive an ungrab by child-event-filtering,
in order to set its pressed state back to false (as in the
cancelOnHide autotest). This is best done as a result of the
QPointingDevice::grabChanged signal, while trying to send the ungrab
to the item that was the grabber, rather than as a special case.
Thus, QQuickWindowPrivate::onGrabChanged (the handler for the
QPointingDevice::grabChanged signal) is now the only place from which
we call QQuickItem::mouseUngrabEvent() and touchUngrabEvent().
But the result is that they are called in more cases than before,
so some tests need adjustment. touchUngrabEvent() is not sent
unless the event is available and we can verify that all points
have been released. This is important for MultiPointTouchArea:
it will react by ending interaction with all points at once.
Another thing that's important to MPTA and multi-touch handlers is that
QQuickWindowPrivate::deliverPointerEvent() must not clear grabbers of
points that are not yet released, in the case that only some points are.
QQuickWindowPrivate::removeGrabber() now calls
QPointingDevicePrivate::removeGrabber() with its optional cancel
argument, so that it will emit either a cancel or an ungrab transition.
That's only relevant for Pointer Handlers, whereas QQuickItem
mouseUngrabEvent and touchUngrabEvent don't make a distinction.
Task-number: QTBUG-86729
Change-Id: Idf03aef2e2182398e0fc4a606c0ddbb2aaed5681
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
11 files changed, 50 insertions, 76 deletions
diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp index de43f2fb7d..d482dcdfca 100644 --- a/src/quick/items/qquickitem.cpp +++ b/src/quick/items/qquickitem.cpp @@ -6058,7 +6058,7 @@ bool QQuickItemPrivate::setEffectiveVisibleRecur(bool newEffectiveVisible) if (window) { QQuickWindowPrivate *windowPriv = QQuickWindowPrivate::get(window); - windowPriv->removeGrabber(q); + windowPriv->removeGrabber(q, true, true, true); } bool childVisibilityChanged = false; @@ -6105,7 +6105,7 @@ void QQuickItemPrivate::setEffectiveEnableRecur(QQuickItem *scope, bool newEffec if (window) { QQuickWindowPrivate *windowPriv = QQuickWindowPrivate::get(window); - windowPriv->removeGrabber(q); + windowPriv->removeGrabber(q, true, true, true); if (scope && !effectiveEnable && activeFocus) { windowPriv->clearFocusInScope( scope, q, Qt::OtherFocusReason, QQuickWindowPrivate::DontChangeFocusProperty | QQuickWindowPrivate::DontChangeSubFocusItem); diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index b32b40e8fd..a2cf478f68 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -1049,14 +1049,14 @@ bool QQuickWindowPrivate::deliverTouchAsMouse(QQuickItem *item, QTouchEvent *poi but if not all points are released, it cannot be sure whether to call touchUngrabEvent() or not; so we have to do it here. */ -void QQuickWindowPrivate::removeGrabber(QQuickItem *grabber, bool mouse, bool touch) +void QQuickWindowPrivate::removeGrabber(QQuickItem *grabber, bool mouse, bool touch, bool cancel) { Q_Q(QQuickWindow); if (eventsInDelivery.isEmpty()) { // do it the expensive way for (auto dev : knownPointingDevices) { auto devPriv = QPointingDevicePrivate::get(const_cast<QPointingDevice *>(dev)); - devPriv->removeGrabber(grabber); + devPriv->removeGrabber(grabber, cancel); } return; } @@ -1084,19 +1084,6 @@ void QQuickWindowPrivate::removeGrabber(QQuickItem *grabber, bool mouse, bool to } } -void QQuickWindowPrivate::sendUngrabEvent(QQuickItem *grabber, bool touch) -{ - if (!grabber) - return; - QEvent e(QEvent::UngrabMouse); - hasFiltered.clear(); - if (!sendFilteredMouseEvent(&e, grabber, grabber->parentItem())) { - grabber->mouseUngrabEvent(); - if (touch) - grabber->touchUngrabEvent(); - } -} - /*! \internal Translates QEventPoint::scenePosition() in \a touchEvent to this window. @@ -2265,11 +2252,6 @@ bool QQuickWindowPrivate::deliverTouchCancelEvent(QTouchEvent *event) { qCDebug(DBG_TOUCH) << event; - if (isDeliveringTouchAsMouse()) { - if (QQuickItem *grabber = qmlobject_cast<QQuickItem *>(event->exclusiveGrabber(touchMouseId))) - sendUngrabEvent(grabber, true); - } - // An incoming TouchCancel event will typically not contain any points, // but sendTouchCancelEvent() adds the points that have grabbers to the event. // Deliver it to all items and handlers that have active touches. @@ -2579,14 +2561,41 @@ void QQuickWindowPrivate::onGrabChanged(QObject *grabber, QPointingDevice::GrabT const QPointerEvent *event, const QEventPoint &point) { qCDebug(lcPtrGrab) << grabber << transition << event << point; - // event can be null, if the signal was emitted from QPointingDevicePrivate::removeGrabber(grabber) - switch (transition) { - case QPointingDevice::UngrabExclusive: - if (point.device()->type() == QInputDevice::DeviceType::Mouse || isDeliveringTouchAsMouse()) - sendUngrabEvent(qobject_cast<QQuickItem *>(grabber), isDeliveringTouchAsMouse()); - break; - default: - break; + // note: event can be null, if the signal was emitted from QPointingDevicePrivate::removeGrabber(grabber) + if (auto *handler = qmlobject_cast<QQuickPointerHandler *>(grabber)) { + handler->onGrabChanged(handler, transition, const_cast<QPointerEvent *>(event), + const_cast<QEventPoint &>(point)); + } else { + switch (transition) { + case QPointingDevice::CancelGrabExclusive: + case QPointingDevice::UngrabExclusive: + if (auto *item = qmlobject_cast<QQuickItem *>(grabber)) { + bool filtered = false; + if (isDeliveringTouchAsMouse() || + point.device()->type() == QInputDevice::DeviceType::Mouse || + point.device()->type() == QInputDevice::DeviceType::TouchPad) { + QEvent e(QEvent::UngrabMouse); + hasFiltered.clear(); + filtered = sendFilteredMouseEvent(&e, item, item->parentItem()); + if (!filtered) + item->mouseUngrabEvent(); + } + if (point.device()->type() == QInputDevice::DeviceType::TouchScreen && event) { + bool allReleased = true; + for (const auto &pt : event->points()) { + if (pt.state() != QEventPoint::State::Released) { + allReleased = false; + break; + } + } + if (allReleased) + item->touchUngrabEvent(); + } + } + break; + default: + break; + } } } @@ -2627,8 +2636,10 @@ void QQuickWindowPrivate::deliverPointerEvent(QPointerEvent *event) if (isTouchEvent(event)) { for (int i = 0; i < event->pointCount(); ++i) { auto &point = event->point(i); - event->setExclusiveGrabber(point, nullptr); - event->clearPassiveGrabbers(point); + if (point.state() == QEventPoint::State::Released) { + event->setExclusiveGrabber(point, nullptr); + event->clearPassiveGrabbers(point); + } } // never allow touch->mouse synthesis to persist either cancelTouchMouseSynthesis(); diff --git a/src/quick/items/qquickwindow_p.h b/src/quick/items/qquickwindow_p.h index 632cf1b6da..81c0ebef45 100644 --- a/src/quick/items/qquickwindow_p.h +++ b/src/quick/items/qquickwindow_p.h @@ -170,8 +170,7 @@ public: QPointF lastMousePosition; bool deliverTouchAsMouse(QQuickItem *item, QTouchEvent *pointerEvent); void translateTouchEvent(QTouchEvent *touchEvent); - void removeGrabber(QQuickItem *grabber, bool mouse = true, bool touch = true); - void sendUngrabEvent(QQuickItem *grabber, bool touch); + void removeGrabber(QQuickItem *grabber, bool mouse = true, bool touch = true, bool cancel = false); void onGrabChanged(QObject *grabber, QPointingDevice::GrabTransition transition, const QPointerEvent *event, const QEventPoint &point); static QMouseEvent *cloneMouseEvent(QMouseEvent *event, QPointF *transformedLocalPos = nullptr); void deliverToPassiveGrabbers(const QVector<QPointer<QObject> > &passiveGrabbers, QPointerEvent *pointerEvent); diff --git a/tests/auto/quick/pointerhandlers/flickableinterop/BLACKLIST b/tests/auto/quick/pointerhandlers/flickableinterop/BLACKLIST index 75d596fcab..92903955ac 100644 --- a/tests/auto/quick/pointerhandlers/flickableinterop/BLACKLIST +++ b/tests/auto/quick/pointerhandlers/flickableinterop/BLACKLIST @@ -1,14 +1,7 @@ [touchAndDragHandlerOnFlickable] windows gcc opensuse-leap -* # QTBUG-86729 [touchDragFlickableBehindSlider] windows gcc [touchDragFlickableBehindButton] windows gcc -[dragHandlerInSiblingStealingGrabFromMouseAreaViaTouch] -* # QTBUG-86729 -[mouseDragFlickableBehindButton] -* # QTBUG-86729 -[touchDragFlickableBehindButton] -* # QTBUG-86729 diff --git a/tests/auto/quick/pointerhandlers/qquickdraghandler/BLACKLIST b/tests/auto/quick/pointerhandlers/qquickdraghandler/BLACKLIST deleted file mode 100644 index e8ceb1c2a7..0000000000 --- a/tests/auto/quick/pointerhandlers/qquickdraghandler/BLACKLIST +++ /dev/null @@ -1,8 +0,0 @@ -[mouseClickButton] # QTBUG-86729 -* -[touchPassiveGrabbers] -* # QTBUG-86729 -[touchDragMultiSliders] -* # QTBUG-86729 -[snapMode] -* # QTBUG-86729 diff --git a/tests/auto/quick/pointerhandlers/qquickpinchhandler/BLACKLIST b/tests/auto/quick/pointerhandlers/qquickpinchhandler/BLACKLIST deleted file mode 100644 index 9dfa00a2be..0000000000 --- a/tests/auto/quick/pointerhandlers/qquickpinchhandler/BLACKLIST +++ /dev/null @@ -1,2 +0,0 @@ -[scaleThreeFingers] -* # QTBUG-86729 diff --git a/tests/auto/quick/pointerhandlers/qquickpointerhandler/BLACKLIST b/tests/auto/quick/pointerhandlers/qquickpointerhandler/BLACKLIST index 9a443d66b4..0fa9daa4cf 100644 --- a/tests/auto/quick/pointerhandlers/qquickpointerhandler/BLACKLIST +++ b/tests/auto/quick/pointerhandlers/qquickpointerhandler/BLACKLIST @@ -1,6 +1,4 @@ -[touchReleaseOutside] -* # QTBUG-86729 [mouseEventDelivery] -* # QTBUG-86729 +macos # QTBUG-86729 [touchEventDelivery] -* # QTBUG-86729 +macos # QTBUG-86729 diff --git a/tests/auto/quick/pointerhandlers/qquickpointhandler/BLACKLIST b/tests/auto/quick/pointerhandlers/qquickpointhandler/BLACKLIST index abeff5b725..3dd33b0a09 100644 --- a/tests/auto/quick/pointerhandlers/qquickpointhandler/BLACKLIST +++ b/tests/auto/quick/pointerhandlers/qquickpointhandler/BLACKLIST @@ -1,6 +1,2 @@ [pressedMultipleButtons] # QTBUG-86729 * -[singleTouch] -* # QTBUG-86729 -[simultaneousMultiTouch] -* # QTBUG-86729 diff --git a/tests/auto/quick/pointerhandlers/qquicktaphandler/BLACKLIST b/tests/auto/quick/pointerhandlers/qquicktaphandler/BLACKLIST index 4f25e9ba97..b26e383304 100644 --- a/tests/auto/quick/pointerhandlers/qquicktaphandler/BLACKLIST +++ b/tests/auto/quick/pointerhandlers/qquicktaphandler/BLACKLIST @@ -1,10 +1,2 @@ -[mouseGesturePolicyDragThreshold] # QTBUG-86729 -* -[touchGesturePolicyDragThreshold] -* # QTBUG-86729 -[touchMouseGesturePolicyDragThreshold] -* # QTBUG-86729 -[buttonsMultiTouch] -* # QTBUG-86729 [componentUserBehavioralOverride] * # QTBUG-86729 diff --git a/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp b/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp index 0a75690904..94f2451c97 100644 --- a/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp +++ b/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp @@ -123,7 +123,6 @@ protected: void touchUngrabEvent() override { ++ungrabs; - QVERIFY(m_active); emit ungrabbed(); m_active = false; emit activeChanged(); @@ -2022,9 +2021,9 @@ void tst_qquickflickable::nestedSliderUsingTouch_data() QTest::addColumn<int>("releases"); QTest::addColumn<int>("ungrabs"); - QTest::newRow("keepBoth") << true << true << 8 << 1 << 0; - QTest::newRow("keepMouse") << true << false << 8 << 1 << 0; - QTest::newRow("keepTouch") << false << true << 8 << 1 << 0; + QTest::newRow("keepBoth") << true << true << 8 << 1 << 1; + QTest::newRow("keepMouse") << true << false << 8 << 1 << 1; + QTest::newRow("keepTouch") << false << true << 8 << 1 << 1; QTest::newRow("keepNeither") << false << false << 5 << 0 << 1; } @@ -2064,7 +2063,7 @@ void tst_qquickflickable::nestedSliderUsingTouch() QTest::touchEvent(window, touchDevice).move(0, p0, window); QQuickTouchUtils::flush(window); } - QCOMPARE(tda->active(), !ungrabs); + QCOMPARE(tda->active(), keepMouseGrab | keepTouchGrab); QTest::touchEvent(window, touchDevice).release(0, p0, window); QQuickTouchUtils::flush(window); QTRY_COMPARE(tda->touchPointStates.first(), QEventPoint::State::Pressed); diff --git a/tests/auto/quick/qquickmultipointtoucharea/BLACKLIST b/tests/auto/quick/qquickmultipointtoucharea/BLACKLIST index b70e5bc3b8..f356dfb29a 100644 --- a/tests/auto/quick/qquickmultipointtoucharea/BLACKLIST +++ b/tests/auto/quick/qquickmultipointtoucharea/BLACKLIST @@ -13,8 +13,6 @@ sles * # QTBUG-86729 [stationaryTouchWithChangingPressure] # QTBUG-86729 * -[cancel] -* # QTBUG-86729 [inFlickable] * # QTBUG-86729 [inFlickable2] @@ -23,5 +21,3 @@ sles * # QTBUG-86729 [reuse] * # QTBUG-86729 -[signalTest] -* # QTBUG-86729 |