aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrew den Exter <andrew.den.exter@jollamobile.com>2015-09-28 17:57:51 +1000
committerAndrew den Exter <andrew.den.exter@qinetic.com.au>2015-10-12 05:58:57 +0000
commitc95fbaf3698b5766e16aa1685136b539ab56a8c4 (patch)
tree754133f9f35728a253e82f1b53962892201c1f76
parent8e7d1a91196197eee4e45bbfa9886ab935e2b67c (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.cpp6
-rw-r--r--src/quick/items/qquickflickable_p_p.h1
-rw-r--r--src/quick/items/qquickitem.cpp1
-rw-r--r--src/quick/items/qquickitem_p.h1
-rw-r--r--src/quick/items/qquickwindow.cpp6
-rw-r--r--tests/auto/quick/qquickflickable/data/nestedPressDelay.qml10
-rw-r--r--tests/auto/quick/qquickflickable/tst_qquickflickable.cpp43
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()
{