diff options
author | Andrew den Exter <andrew.den.exter@jollamobile.com> | 2015-09-28 17:57:51 +1000 |
---|---|---|
committer | Andrew den Exter <andrew.den.exter@qinetic.com.au> | 2015-10-12 05:58:57 +0000 |
commit | c95fbaf3698b5766e16aa1685136b539ab56a8c4 (patch) | |
tree | 754133f9f35728a253e82f1b53962892201c1f76 | |
parent | 8e7d1a91196197eee4e45bbfa9886ab935e2b67c (diff) |
Don't send delayed mouse presses to ancestors of the replaying Flickable.
If a Flickable delayed a mouse press event and then replayed it later,
ancestor items of that Flickable would receive the press twice:
once when filtering events of the Flickable, and again when the event
was replayed to a descendent of the Flickable. Extend the protection
against a Flickable receiving that repeat event to all ancestor items
so this doesn't happen.
Change-Id: I438c146130c24a7d47e9e8712a1ab08f3d915a06
Reviewed-by: Shawn Rutledge <shawn.rutledge@theqtcompany.com>
Reviewed-by: Martin Jones <martin.jones@qinetic.com.au>
-rw-r--r-- | src/quick/items/qquickflickable.cpp | 6 | ||||
-rw-r--r-- | src/quick/items/qquickflickable_p_p.h | 1 | ||||
-rw-r--r-- | src/quick/items/qquickitem.cpp | 1 | ||||
-rw-r--r-- | src/quick/items/qquickitem_p.h | 1 | ||||
-rw-r--r-- | src/quick/items/qquickwindow.cpp | 6 | ||||
-rw-r--r-- | tests/auto/quick/qquickflickable/data/nestedPressDelay.qml | 10 | ||||
-rw-r--r-- | tests/auto/quick/qquickflickable/tst_qquickflickable.cpp | 43 |
7 files changed, 58 insertions, 10 deletions
diff --git a/src/quick/items/qquickflickable.cpp b/src/quick/items/qquickflickable.cpp index bef766a516..9d6c51f37a 100644 --- a/src/quick/items/qquickflickable.cpp +++ b/src/quick/items/qquickflickable.cpp @@ -218,7 +218,7 @@ QQuickFlickablePrivate::QQuickFlickablePrivate() , hMoved(false), vMoved(false) , stealMouse(false), pressed(false) , scrollingPhase(false), interactive(true), calcVelocity(false) - , pixelAligned(false), replayingPressEvent(false) + , pixelAligned(false) , lastPosTime(-1) , lastPressTime(0) , deceleration(QML_FLICK_DEFAULTDECELERATION) @@ -2202,10 +2202,6 @@ bool QQuickFlickable::sendMouseEvent(QQuickItem *item, QMouseEvent *event) d->handleMouseMoveEvent(mouseEvent.data()); break; case QEvent::MouseButtonPress: - // Don't process a replayed event during replay - if (d->replayingPressEvent) - return false; - d->handleMousePressEvent(mouseEvent.data()); d->captureDelayedPress(item, event); stealThisEvent = d->stealMouse; // Update stealThisEvent in case changed by function call above diff --git a/src/quick/items/qquickflickable_p_p.h b/src/quick/items/qquickflickable_p_p.h index 65bb3e802d..9d75533c8a 100644 --- a/src/quick/items/qquickflickable_p_p.h +++ b/src/quick/items/qquickflickable_p_p.h @@ -211,7 +211,6 @@ public: bool interactive : 1; bool calcVelocity : 1; bool pixelAligned : 1; - bool replayingPressEvent : 1; QElapsedTimer timer; qint64 lastPosTime; qint64 lastPressTime; diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp index fdbd4c90a3..e646d59976 100644 --- a/src/quick/items/qquickitem.cpp +++ b/src/quick/items/qquickitem.cpp @@ -3077,6 +3077,7 @@ QQuickItemPrivate::QQuickItemPrivate() , implicitAntialiasing(false) , antialiasingValid(false) , isTabFence(false) + , replayingPressEvent(false) , dirtyAttributes(0) , nextDirtyItem(0) , prevDirtyItem(0) diff --git a/src/quick/items/qquickitem_p.h b/src/quick/items/qquickitem_p.h index 6670975f20..9172f7eff1 100644 --- a/src/quick/items/qquickitem_p.h +++ b/src/quick/items/qquickitem_p.h @@ -433,6 +433,7 @@ public: // when any of the item's descendants gets focus, the item constrains the tab // focus chain and prevents tabbing outside. bool isTabFence:1; + bool replayingPressEvent:1; enum DirtyType { TransformOrigin = 0x00000001, diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index 18ffcb3732..98d16709b7 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -2449,9 +2449,11 @@ bool QQuickWindowPrivate::sendFilteredMouseEvent(QQuickItem *target, QQuickItem if (!target) return false; - bool filtered = false; - QQuickItemPrivate *targetPrivate = QQuickItemPrivate::get(target); + if (targetPrivate->replayingPressEvent) + return false; + + bool filtered = false; if (targetPrivate->filtersChildMouseEvents && !hasFiltered->contains(target)) { hasFiltered->insert(target); if (target->childMouseEventFilter(item, event)) diff --git a/tests/auto/quick/qquickflickable/data/nestedPressDelay.qml b/tests/auto/quick/qquickflickable/data/nestedPressDelay.qml index 742656641f..bdb866ce65 100644 --- a/tests/auto/quick/qquickflickable/data/nestedPressDelay.qml +++ b/tests/auto/quick/qquickflickable/data/nestedPressDelay.qml @@ -8,12 +8,18 @@ Flickable { contentHeight: 320 flickableDirection: Flickable.HorizontalFlick pressDelay: 10000 - Rectangle { + MouseArea { + objectName: "filteringMouseArea" x: 20 y: 20 width: 400 height: 300 - color: "yellow" + drag.filterChildren: true + Rectangle { + id: rectangle + color: "yellow" + anchors.fill: parent + } Flickable { objectName: "innerFlickable" anchors.fill: parent diff --git a/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp b/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp index f7267800c9..dc7171746c 100644 --- a/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp +++ b/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp @@ -67,6 +67,7 @@ private slots: void flickDeceleration(); void pressDelay(); void nestedPressDelay(); + void filterReplayedPress(); void nestedClickThenFlick(); void flickableDirection(); void resizeContent(); @@ -522,6 +523,48 @@ void tst_qquickflickable::nestedPressDelay() QTest::mouseRelease(window.data(), Qt::LeftButton, 0, QPoint(90, 150)); } +void tst_qquickflickable::filterReplayedPress() +{ + QScopedPointer<QQuickView> window(new QQuickView); + window->setSource(testFileUrl("nestedPressDelay.qml")); + QTRY_COMPARE(window->status(), QQuickView::Ready); + QQuickViewTestUtil::centerOnScreen(window.data()); + QQuickViewTestUtil::moveMouseAway(window.data()); + window->show(); + QVERIFY(QTest::qWaitForWindowActive(window.data())); + QVERIFY(window->rootObject() != 0); + + QQuickFlickable *outer = qobject_cast<QQuickFlickable*>(window->rootObject()); + QVERIFY(outer != 0); + + QQuickFlickable *inner = window->rootObject()->findChild<QQuickFlickable*>("innerFlickable"); + QVERIFY(inner != 0); + + QQuickItem *filteringMouseArea = outer->findChild<QQuickItem *>("filteringMouseArea"); + QVERIFY(filteringMouseArea); + + moveAndPress(window.data(), QPoint(150, 150)); + // the MouseArea filtering the Flickable is pressed immediately. + QCOMPARE(filteringMouseArea->property("pressed").toBool(), true); + + // Some event causes the mouse area to set keepMouseGrab. + filteringMouseArea->setKeepMouseGrab(true); + QCOMPARE(filteringMouseArea->keepMouseGrab(), true); + + // The inner pressDelay will prevail (50ms, vs. 10sec) + // QTRY_VERIFY() has 5sec timeout, so will timeout well within 10sec. + QTRY_VERIFY(outer->property("pressed").toBool()); + + // The replayed press event isn't delivered to parent items of the + // flickable with the press delay, and the state of the parent mouse + // area is therefore unaffected. + QCOMPARE(filteringMouseArea->property("pressed").toBool(), true); + QCOMPARE(filteringMouseArea->keepMouseGrab(), true); + + QTest::mouseRelease(window.data(), Qt::LeftButton, 0, QPoint(150, 150)); +} + + // QTBUG-37316 void tst_qquickflickable::nestedClickThenFlick() { |