diff options
author | Antti Määttä <antti.maatta@qt.io> | 2022-06-15 10:52:20 +0300 |
---|---|---|
committer | Qt Cherry-pick Bot <cherrypick_bot@qt-project.org> | 2022-06-22 13:44:36 +0000 |
commit | 5b30ba3436c6602760832420d04e44589f0d9f5a (patch) | |
tree | 5fff804da57a58d077c9734946e7de287696067e | |
parent | 6c19574d1686f512d27de846b200f61ddbfd8488 (diff) |
Handle unprocessed pressed case in Flickable
Handle case where Flickable filters a pressed event before the receiver
has decided whether it wants to keep the grab. That causes the Flickable
to not process the press event, but still processes all the later
events.
This happens when the receiver is MouseArea so add special case
for it in Flickable, where we start the drag if all conditions are met.
Fixes: QTBUG-38765
Fixes: QTBUG-74842
Change-Id: I2e02042cb496e9eb3b7b5da824e56f76ee76ccbb
Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
(cherry picked from commit d7b5a485583004ad6a1374a50b7c3f6cab00aca3)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
-rw-r--r-- | src/quick/items/qquickflickable.cpp | 23 | ||||
-rw-r--r-- | tests/auto/quick/qquickflickable/data/nestedmouseareapce.qml | 26 | ||||
-rw-r--r-- | tests/auto/quick/qquickflickable/tst_qquickflickable.cpp | 22 |
3 files changed, 69 insertions, 2 deletions
diff --git a/src/quick/items/qquickflickable.cpp b/src/quick/items/qquickflickable.cpp index 51fa6d324a..721dba1769 100644 --- a/src/quick/items/qquickflickable.cpp +++ b/src/quick/items/qquickflickable.cpp @@ -7,6 +7,8 @@ #include "qquickwindow.h" #include "qquickwindow_p.h" #include "qquickevents_p_p.h" +#include "qquickmousearea_p.h" +#include "qquickdrag_p.h" #include <QtQuick/private/qquickpointerhandler_p.h> #include <QtQuick/private/qquicktransition_p.h> @@ -2517,6 +2519,23 @@ bool QQuickFlickable::filterPointerEvent(QQuickItem *receiver, QPointerEvent *ev bool receiverDisabled = receiver && !receiver->isEnabled(); bool stealThisEvent = d->stealMouse; bool receiverKeepsGrab = receiver && (receiver->keepMouseGrab() || receiver->keepTouchGrab()); + bool receiverRelinquishGrab = false; + + // Special case for MouseArea, try to guess what it does with the event + if (auto *mouseArea = qmlobject_cast<QQuickMouseArea *>(receiver)) { + bool preventStealing = mouseArea->preventStealing(); + if (mouseArea->drag() && mouseArea->drag()->target()) + preventStealing = true; + if (!preventStealing && receiverKeepsGrab) { + receiverRelinquishGrab = !receiverDisabled + || (QQuickDeliveryAgentPrivate::isMouseEvent(event) + && firstPoint.state() == QEventPoint::State::Pressed + && (receiver->acceptedMouseButtons() & static_cast<QMouseEvent *>(event)->button())); + if (receiverRelinquishGrab) + receiverKeepsGrab = false; + } + } + if ((stealThisEvent || contains(localPos)) && (!receiver || !receiverKeepsGrab || receiverDisabled)) { QScopedPointer<QPointerEvent> localizedEvent(QQuickDeliveryAgentPrivate::clonePointerEvent(event, localPos)); localizedEvent->setAccepted(false); @@ -2527,7 +2546,7 @@ bool QQuickFlickable::filterPointerEvent(QQuickItem *receiver, QPointerEvent *ev case QEventPoint::State::Pressed: d->handlePressEvent(localizedEvent.data()); d->captureDelayedPress(receiver, event); - stealThisEvent = d->stealMouse; // Update stealThisEvent in case changed by function call above + stealThisEvent = d->stealMouse; // Update stealThisEvent in case changed by handlePressEvent break; case QEventPoint::State::Released: d->handleReleaseEvent(localizedEvent.data()); @@ -2544,7 +2563,7 @@ bool QQuickFlickable::filterPointerEvent(QQuickItem *receiver, QPointerEvent *ev event->setExclusiveGrabber(firstPoint, this); } - const bool filtered = stealThisEvent || d->delayedPressEvent || receiverDisabled; + const bool filtered = !receiverRelinquishGrab && (stealThisEvent || d->delayedPressEvent || receiverDisabled); if (filtered) { event->setAccepted(true); } diff --git a/tests/auto/quick/qquickflickable/data/nestedmouseareapce.qml b/tests/auto/quick/qquickflickable/data/nestedmouseareapce.qml new file mode 100644 index 0000000000..b36df04d45 --- /dev/null +++ b/tests/auto/quick/qquickflickable/data/nestedmouseareapce.qml @@ -0,0 +1,26 @@ +import QtQuick 2.0 + +Flickable { + id: outer + objectName: "flickable" + width: 400 + height: 400 + contentX: 50 + contentY: 50 + contentWidth: 500 + contentHeight: 500 + + Rectangle { + objectName: "nested" + x: 100 + y: 100 + width: 300 + height: 300 + + color: "yellow" + MouseArea { + anchors.fill: parent + propagateComposedEvents: true + } + } +} diff --git a/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp b/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp index 0e0b5f0606..c55537364c 100644 --- a/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp +++ b/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp @@ -192,6 +192,7 @@ private slots: void stopAtBounds(); void stopAtBounds_data(); void nestedMouseAreaUsingTouch(); + void nestedMouseAreaPropagateComposedEvents(); void nestedSliderUsingTouch(); void nestedSliderUsingTouch_data(); void pressDelayWithLoader(); @@ -2099,6 +2100,27 @@ void tst_qquickflickable::nestedMouseAreaUsingTouch() QVERIFY(nested->y() < 100.0); } +void tst_qquickflickable::nestedMouseAreaPropagateComposedEvents() +{ + QScopedPointer<QQuickView> window(new QQuickView); + window->setSource(testFileUrl("nestedmouseareapce.qml")); + QTRY_COMPARE(window->status(), QQuickView::Ready); + QQuickViewTestUtils::centerOnScreen(window.data()); + QQuickViewTestUtils::moveMouseAway(window.data()); + window->show(); + QVERIFY(window->rootObject() != nullptr); + QVERIFY(QTest::qWaitForWindowActive(window.data())); + + QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(window->rootObject()); + QVERIFY(flickable != nullptr); + + QCOMPARE(flickable->contentY(), 50.0f); + flickWithTouch(window.data(), QPoint(100, 300), QPoint(100, 200)); + + // flickable should have moved + QVERIFY(!qFuzzyCompare(flickable->contentY(), 50.0)); +} + void tst_qquickflickable::nestedSliderUsingTouch_data() { QTest::addColumn<bool>("keepMouseGrab"); |