diff options
-rw-r--r-- | src/quick/items/qquickflickable.cpp | 5 | ||||
-rw-r--r-- | src/quick/items/qquickitem.cpp | 10 | ||||
-rw-r--r-- | src/quick/items/qquickwindow.cpp | 34 | ||||
-rw-r--r-- | src/quick/items/qquickwindow_p.h | 1 | ||||
-rw-r--r-- | tests/auto/quick/qquickitem/tst_qquickitem.cpp | 15 | ||||
-rw-r--r-- | tests/auto/quick/touchmouse/tst_touchmouse.cpp | 100 |
6 files changed, 147 insertions, 18 deletions
diff --git a/src/quick/items/qquickflickable.cpp b/src/quick/items/qquickflickable.cpp index 15627aad84..fa18d4aa30 100644 --- a/src/quick/items/qquickflickable.cpp +++ b/src/quick/items/qquickflickable.cpp @@ -2048,12 +2048,13 @@ bool QQuickFlickable::sendMouseEvent(QQuickItem *item, QMouseEvent *event) if ((grabber && stealThisEvent && !grabber->keepMouseGrab() && grabber != this) || grabberDisabled) { d->clearDelayedPress(); grabMouse(); + } else if (d->delayedPressEvent) { + grabMouse(); } - // Do not accept this event when filtering, as this would force the mouse grab to the child const bool filtered = stealThisEvent || d->delayedPressEvent || grabberDisabled; if (filtered) { - event->setAccepted(false); + event->setAccepted(true); } return filtered; } else if (d->lastPosTime != -1) { diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp index a0329f7afc..f565fba1bb 100644 --- a/src/quick/items/qquickitem.cpp +++ b/src/quick/items/qquickitem.cpp @@ -6629,15 +6629,7 @@ void QQuickItem::grabMouse() if (!d->window) return; QQuickWindowPrivate *windowPriv = QQuickWindowPrivate::get(d->window); - if (windowPriv->mouseGrabberItem == this) - return; - - QQuickItem *oldGrabber = windowPriv->mouseGrabberItem; - windowPriv->mouseGrabberItem = this; - if (oldGrabber) { - QEvent ev(QEvent::UngrabMouse); - d->window->sendEvent(oldGrabber, &ev); - } + windowPriv->setMouseGrabber(this); } /*! diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index dfc70d7e68..f355afcea5 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -599,6 +599,28 @@ bool QQuickWindowPrivate::translateTouchToMouse(QQuickItem *item, QTouchEvent *e return false; } +void QQuickWindowPrivate::setMouseGrabber(QQuickItem *grabber) +{ + Q_Q(QQuickWindow); + if (mouseGrabberItem == grabber) + return; + + QQuickItem *oldGrabber = mouseGrabberItem; + mouseGrabberItem = grabber; + + if (touchMouseId != -1) { + // update the touch item for mouse touch id to the new grabber + itemForTouchPointId.remove(touchMouseId); + if (grabber) + itemForTouchPointId[touchMouseId] = grabber; + } + + if (oldGrabber) { + QEvent ev(QEvent::UngrabMouse); + q->sendEvent(oldGrabber, &ev); + } +} + void QQuickWindowPrivate::transformTouchPoints(QList<QTouchEvent::TouchPoint> &touchPoints, const QTransform &transform) { QMatrix4x4 transformMatrix(transform); @@ -1221,8 +1243,11 @@ bool QQuickWindow::event(QEvent *e) case QEvent::TouchEnd: { QTouchEvent *touch = static_cast<QTouchEvent*>(e); d->translateTouchEvent(touch); - // return in order to avoid the QWindow::event below - return d->deliverTouchEvent(touch); + d->deliverTouchEvent(touch); + // we consume all touch events ourselves to avoid duplicate + // mouse delivery by QtGui mouse synthesis + e->accept(); + return true; } break; case QEvent::TouchCancel: @@ -1776,7 +1801,10 @@ bool QQuickWindowPrivate::deliverMatchingPointsToItem(QQuickItem *item, QTouchEv // First check whether the parent wants to be a filter, // and if the parent accepts the event we are done. if (sendFilteredTouchEvent(item->parentItem(), item, event)) { - event->accept(); + // If the touch was accepted (regardless by whom or in what form), + // update acceptedNewPoints + foreach (int id, matchingNewPoints) + acceptedNewPoints->insert(id); return true; } diff --git a/src/quick/items/qquickwindow_p.h b/src/quick/items/qquickwindow_p.h index c23745b5f1..418633b6ac 100644 --- a/src/quick/items/qquickwindow_p.h +++ b/src/quick/items/qquickwindow_p.h @@ -127,6 +127,7 @@ public: QPointF lastMousePosition; bool translateTouchToMouse(QQuickItem *item, QTouchEvent *event); void translateTouchEvent(QTouchEvent *touchEvent); + void setMouseGrabber(QQuickItem *grabber); static void transformTouchPoints(QList<QTouchEvent::TouchPoint> &touchPoints, const QTransform &transform); static QMouseEvent *cloneMouseEvent(QMouseEvent *event, QPointF *transformedLocalPos = 0); bool deliverInitialMousePressEvent(QQuickItem *, QMouseEvent *); diff --git a/tests/auto/quick/qquickitem/tst_qquickitem.cpp b/tests/auto/quick/qquickitem/tst_qquickitem.cpp index 2c6dcd72ba..ad3c4fc208 100644 --- a/tests/auto/quick/qquickitem/tst_qquickitem.cpp +++ b/tests/auto/quick/qquickitem/tst_qquickitem.cpp @@ -1310,7 +1310,10 @@ void tst_qquickitem::touchEventAcceptIgnore() bool accepted = window.event(&event); QVERIFY(item->touchEventReached); - QCOMPARE(accepted && event.isAccepted(), itemSupportsTouch); + + // always true because QtQuick always eats touch events so as to not + // allow QtGui to synthesise them for us. + QCOMPARE(accepted && event.isAccepted(), true); } { QTouchEvent::TouchPoint point; @@ -1330,7 +1333,10 @@ void tst_qquickitem::touchEventAcceptIgnore() bool accepted = window.event(&event); QCOMPARE(item->touchEventReached, itemSupportsTouch); - QCOMPARE(accepted && event.isAccepted(), itemSupportsTouch); + + // always true because QtQuick always eats touch events so as to not + // allow QtGui to synthesise them for us. + QCOMPARE(accepted && event.isAccepted(), true); } { QTouchEvent::TouchPoint point; @@ -1350,7 +1356,10 @@ void tst_qquickitem::touchEventAcceptIgnore() bool accepted = window.event(&event); QCOMPARE(item->touchEventReached, itemSupportsTouch); - QCOMPARE(accepted && event.isAccepted(), itemSupportsTouch); + + // always true because QtQuick always eats touch events so as to not + // allow QtGui to synthesise them for us. + QCOMPARE(accepted && event.isAccepted(), true); } } diff --git a/tests/auto/quick/touchmouse/tst_touchmouse.cpp b/tests/auto/quick/touchmouse/tst_touchmouse.cpp index 6cf0aa4749..5b4ad0ffa3 100644 --- a/tests/auto/quick/touchmouse/tst_touchmouse.cpp +++ b/tests/auto/quick/touchmouse/tst_touchmouse.cpp @@ -154,6 +154,7 @@ private slots: void mouseOverTouch(); void buttonOnFlickable(); + void buttonOnDelayedPressFlickable(); void buttonOnTouch(); void pinchOnFlickable(); @@ -162,9 +163,22 @@ private slots: void tapOnDismissiveTopMouseAreaClicksBottomOne(); +protected: + bool eventFilter(QObject *, QEvent *event) + { + if (event->type() == QEvent::MouseButtonPress || + event->type() == QEvent::MouseMove || + event->type() == QEvent::MouseButtonRelease) { + QMouseEvent *me = static_cast<QMouseEvent*>(event); + filteredEventList.append(Event(me->type(), me->pos(), me->globalPos())); + } + return false; + } + private: QQuickView *createView(); QTouchDevice *device; + QList<Event> filteredEventList; }; QQuickView *tst_TouchMouse::createView() @@ -496,7 +510,7 @@ void tst_TouchMouse::buttonOnFlickable() QCOMPARE(eventItem1->eventList.size(), 0); QPoint p1 = QPoint(20, 130); QTest::touchEvent(window, device).press(0, p1, window); - QCOMPARE(eventItem1->eventList.size(), 2); + QTRY_COMPARE(eventItem1->eventList.size(), 2); QCOMPARE(eventItem1->eventList.at(0).type, QEvent::TouchBegin); QCOMPARE(eventItem1->eventList.at(1).type, QEvent::MouseButtonPress); QTest::touchEvent(window, device).release(0, p1, window); @@ -559,12 +573,96 @@ void tst_TouchMouse::buttonOnFlickable() QCOMPARE(eventItem1->eventList.at(3).type, QEvent::MouseMove); QCOMPARE(windowPriv->mouseGrabberItem, flickable); + QCOMPARE(windowPriv->touchMouseId, 0); + QCOMPARE(windowPriv->itemForTouchPointId[0], flickable); QVERIFY(flickable->isMovingVertically()); QTest::touchEvent(window, device).release(0, p3, window); delete window; } +void tst_TouchMouse::buttonOnDelayedPressFlickable() +{ + // flickable - height 500 / 1000 + // - eventItem1 y: 100, height 100 + // - eventItem2 y: 300, height 100 + + qApp->setAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents, true); + filteredEventList.clear(); + + QQuickView *window = createView(); + + window->setSource(testFileUrl("buttononflickable.qml")); + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window)); + window->requestActivate(); + QVERIFY(QTest::qWaitForWindowActive(window)); + QVERIFY(window->rootObject() != 0); + + QQuickFlickable *flickable = window->rootObject()->findChild<QQuickFlickable*>("flickable"); + QVERIFY(flickable); + + window->installEventFilter(this); + + flickable->setPressDelay(60); + + // should a mouse area button be clickable on top of flickable? yes :) + EventItem *eventItem1 = window->rootObject()->findChild<EventItem*>("eventItem1"); + QVERIFY(eventItem1); + eventItem1->setAcceptedMouseButtons(Qt::LeftButton); + eventItem1->acceptMouse = true; + + // should a touch button be touchable on top of flickable? yes :) + EventItem *eventItem2 = window->rootObject()->findChild<EventItem*>("eventItem2"); + QVERIFY(eventItem2); + QCOMPARE(eventItem2->eventList.size(), 0); + eventItem2->acceptTouch = true; + + // wait to avoid getting a double click event + QTest::qWait(qApp->styleHints()->mouseDoubleClickInterval() + 10); + + // check that flickable moves - mouse button + QCOMPARE(eventItem1->eventList.size(), 0); + QPoint p1 = QPoint(10, 110); + QTest::touchEvent(window, device).press(0, p1, window); + // Flickable initially steals events + QCOMPARE(eventItem1->eventList.size(), 0); + // but we'll get the delayed mouse press after a delay + QTRY_COMPARE(eventItem1->eventList.size(), 1); + QCOMPARE(eventItem1->eventList.at(0).type, QEvent::MouseButtonPress); + + // eventItem1 should have the mouse grab, and have moved the itemForTouchPointId + // for the touchMouseId to the new grabber. + QQuickWindowPrivate *windowPriv = QQuickWindowPrivate::get(window); + QCOMPARE(windowPriv->touchMouseId, 0); + QCOMPARE(windowPriv->itemForTouchPointId[0], eventItem1); + QCOMPARE(windowPriv->mouseGrabberItem, eventItem1); + + p1 += QPoint(0, -10); + QPoint p2 = p1 + QPoint(0, -10); + QPoint p3 = p2 + QPoint(0, -10); + QTest::qWait(10); + QTest::touchEvent(window, device).move(0, p1, window); + QTest::qWait(10); + QTest::touchEvent(window, device).move(0, p2, window); + QTest::qWait(10); + QTest::touchEvent(window, device).move(0, p3, window); + QVERIFY(flickable->isMovingVertically()); + + // flickable should have the mouse grab, and have moved the itemForTouchPointId + // for the touchMouseId to the new grabber. + QCOMPARE(windowPriv->mouseGrabberItem, flickable); + QCOMPARE(windowPriv->touchMouseId, 0); + QCOMPARE(windowPriv->itemForTouchPointId[0], flickable); + + QTest::touchEvent(window, device).release(0, p3, window); + + // We should not have received any synthesised mouse events from Qt gui. + QCOMPARE(filteredEventList.count(), 0); + + delete window; +} + void tst_TouchMouse::buttonOnTouch() { // 400x800 |