diff options
-rw-r--r-- | src/quick/items/qquickitem.cpp | 6 | ||||
-rw-r--r-- | src/quick/util/qquickdeliveryagent.cpp | 25 | ||||
-rw-r--r-- | tests/auto/quick/qquickwindow/tst_qquickwindow.cpp | 109 |
3 files changed, 81 insertions, 59 deletions
diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp index 58fb51e98a..6e71f64b9c 100644 --- a/src/quick/items/qquickitem.cpp +++ b/src/quick/items/qquickitem.cpp @@ -4358,7 +4358,11 @@ void QQuickItem::dropEvent(QDropEvent *event) This method will only be called if filtersChildMouseEvents() is \c true. Return \c true if the specified \a event should not be passed on to the - specified child \a item, and \c false otherwise. + specified child \a item, and \c false otherwise. If you return \c true, you + should also \l {QEvent::accept()}{accept} or \l {QEvent::ignore()}{ignore} + the \a event, to signal if event propagation should stop or continue. + The \a event will, however, always be sent to all childMouseEventFilters + up the parent chain. \note Despite the name, this function filters all QPointerEvent instances during delivery to all children (typically mouse, touch, and tablet diff --git a/src/quick/util/qquickdeliveryagent.cpp b/src/quick/util/qquickdeliveryagent.cpp index e2bb83e638..4672a16aec 100644 --- a/src/quick/util/qquickdeliveryagent.cpp +++ b/src/quick/util/qquickdeliveryagent.cpp @@ -2609,15 +2609,18 @@ bool QQuickDeliveryAgentPrivate::sendFilteredPointerEventImpl(QPointerEvent *eve QQuickItemPrivate::get(receiver)->localizedTouchEvent(static_cast<QTouchEvent *>(event), true, &filteringParentTouchEvent); if (filteringParentTouchEvent.type() != QEvent::None) { qCDebug(lcTouch) << "letting parent" << filteringParent << "filter for" << receiver << &filteringParentTouchEvent; - if (filteringParent->childMouseEventFilter(receiver, &filteringParentTouchEvent)) { + filtered = filteringParent->childMouseEventFilter(receiver, &filteringParentTouchEvent); + if (filtered) { qCDebug(lcTouch) << "touch event intercepted by childMouseEventFilter of " << filteringParent; + event->setAccepted(filteringParentTouchEvent.isAccepted()); skipDelivery.append(filteringParent); - for (auto point : filteringParentTouchEvent.points()) { - const QQuickItem *exclusiveGrabber = qobject_cast<const QQuickItem *>(event->exclusiveGrabber(point)); - if (!exclusiveGrabber || !exclusiveGrabber->keepTouchGrab()) - event->setExclusiveGrabber(point, filteringParent); + if (event->isAccepted()) { + for (auto point : filteringParentTouchEvent.points()) { + const QQuickItem *exclusiveGrabber = qobject_cast<const QQuickItem *>(event->exclusiveGrabber(point)); + if (!exclusiveGrabber || !exclusiveGrabber->keepTouchGrab()) + event->setExclusiveGrabber(point, filteringParent); + } } - return true; } else if (Q_LIKELY(QCoreApplication::testAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents)) && !filteringParent->acceptTouchEvents()) { qCDebug(lcTouch) << "touch event NOT intercepted by childMouseEventFilter of " << filteringParent @@ -2653,17 +2656,17 @@ bool QQuickDeliveryAgentPrivate::sendFilteredPointerEventImpl(QPointerEvent *eve // touchMouseId and touchMouseDevice must be set, even if it's only temporarily and isn't grabbed. touchMouseId = tp.id(); touchMouseDevice = event->pointingDevice(); - if (filteringParent->childMouseEventFilter(receiver, &mouseEvent)) { + filtered = filteringParent->childMouseEventFilter(receiver, &mouseEvent); + if (filtered) { qCDebug(lcTouch) << "touch event intercepted as synth mouse event by childMouseEventFilter of " << filteringParent; + event->setAccepted(mouseEvent.isAccepted()); skipDelivery.append(filteringParent); - if (t != QEvent::MouseButtonRelease) { + if (event->isAccepted() && event->isBeginEvent()) { qCDebug(lcTouchTarget) << "TP (mouse)" << Qt::hex << tp.id() << "->" << filteringParent; filteringParentTouchEvent.setExclusiveGrabber(tp, filteringParent); touchMouseUnset = false; // We want to leave touchMouseId and touchMouseDevice set - if (mouseEvent.isAccepted()) - filteringParent->grabMouse(); + filteringParent->grabMouse(); } - filtered = true; } if (touchMouseUnset) // Now that we're done sending a synth mouse event, and it wasn't grabbed, diff --git a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp index 0df13c5087..cb59b275a5 100644 --- a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp +++ b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp @@ -3299,57 +3299,48 @@ public: */ bool testFilterPreConditions() const { return !m_filterNotPreAccepted; } static QVector<DeliveryRecord> &deliveryList() { return m_deliveryList; } - static QSet<QEvent::Type> &includedEventTypes() + static void setExpectedDeliveryList(const QVector<DeliveryRecord> &v) { m_expectedDeliveryList = v; } + + bool isRelevant(QQuickItem *receiver, QEvent *e) { - if (m_includedEventTypes.isEmpty()) - m_includedEventTypes << QEvent::MouseButtonPress; - return m_includedEventTypes; + if (receiver->acceptTouchEvents()) + return e->type() == QEvent::TouchBegin; + return e->type() == QEvent::MouseButtonPress; } - static void setExpectedDeliveryList(const QVector<DeliveryRecord> &v) { m_expectedDeliveryList = v; } protected: bool childMouseEventFilter(QQuickItem *i, QEvent *e) override { + if (!isRelevant(i, e)) + return QQuickRectangle::childMouseEventFilter(i, e); + appendEvent(this, i, e); - switch (e->type()) { - case QEvent::MouseButtonPress: - if (!e->isAccepted()) - m_filterNotPreAccepted = true; - e->setAccepted(m_filterAccepts); - // qCDebug(lcTests) << objectName() << i->objectName(); - return m_filterReturns; - default: - break; - } - return QQuickRectangle::childMouseEventFilter(i, e); + if (!e->isAccepted()) + m_filterNotPreAccepted = true; + e->setAccepted(m_filterAccepts); + return m_filterReturns; } bool event(QEvent *e) override { + if (!isRelevant(this, e)) + QQuickRectangle::event(e); + appendEvent(nullptr, this, e); - switch (e->type()) { - case QEvent::MouseButtonPress: - // qCDebug(lcTests) << objectName(); - e->setAccepted(m_eventAccepts); - return true; - default: - break; - } - return QQuickRectangle::event(e); + e->setAccepted(m_eventAccepts); + return true; } private: static void appendEvent(QQuickItem *filter, QQuickItem *receiver, QEvent *event) { - if (includedEventTypes().contains(event->type())) { - auto record = DeliveryRecord(filter ? filter->objectName() : QString(), receiver ? receiver->objectName() : QString()); - int i = m_deliveryList.size(); - if (m_expectedDeliveryList.size() > i && m_expectedDeliveryList[i] == record) - qCDebug(lcTests).noquote().nospace() << i << ": " << record; - else - qCDebug(lcTests).noquote().nospace() << i << ": " << record - << ", expected " << (m_expectedDeliveryList.size() > i ? m_expectedDeliveryList[i].toString() : QLatin1String("nothing")) << " <---"; - m_deliveryList << record; - } + auto record = DeliveryRecord(filter ? filter->objectName() : QString(), receiver ? receiver->objectName() : QString()); + int i = m_deliveryList.size(); + if (m_expectedDeliveryList.size() > i && m_expectedDeliveryList[i] == record) + qCDebug(lcTests).noquote().nospace() << i << ": " << record; + else + qCDebug(lcTests).noquote().nospace() << i << ": " << record + << ", expected " << (m_expectedDeliveryList.size() > i ? m_expectedDeliveryList[i].toString() : QLatin1String("nothing")) << " <---"; + m_deliveryList << record; } bool m_eventAccepts; bool m_filterReturns; @@ -3359,12 +3350,10 @@ private: // list of (filtering-parent . receiver) pairs static DeliveryRecordVector m_expectedDeliveryList; static DeliveryRecordVector m_deliveryList; - static QSet<QEvent::Type> m_includedEventTypes; }; DeliveryRecordVector EventItem::m_expectedDeliveryList; DeliveryRecordVector EventItem::m_deliveryList; -QSet<QEvent::Type> EventItem::m_includedEventTypes; typedef QVector<const char*> CharStarVector; @@ -3389,11 +3378,17 @@ void tst_qquickwindow::testChildMouseEventFilter_data() // r0->r1->r2->r3 // QTest::addColumn<QPoint>("mousePos"); + QTest::addColumn<QString>("eventMode"); QTest::addColumn<InputState>("inputState"); QTest::addColumn<DeliveryRecordVector>("expectedDeliveryOrder"); - QTest::newRow("if filtered and rejected, do not deliver it to the item that filtered it") + for (const QString &eventMode : {"mouse", "touch", "touchToMouse"}) { + + #define desc(txt) qPrintable(QString("%1 events, ").arg(eventMode) + txt) + + QTest::newRow(desc("if filtered and rejected, do not deliver it to the item that filtered it")) << QPoint(100, 100) + << eventMode << InputState({ // | event() | child mouse filter // +---------+---------+---------+--------- @@ -3411,8 +3406,9 @@ void tst_qquickwindow::testChildMouseEventFilter_data() << DeliveryRecord("r1") ); - QTest::newRow("no filtering, no accepting") + QTest::newRow(desc("no filtering, no accepting")) << QPoint(100, 100) + << eventMode << InputState({ // | event() | child mouse filter // +---------+---------+---------+--------- @@ -3431,8 +3427,9 @@ void tst_qquickwindow::testChildMouseEventFilter_data() << DeliveryRecord("root") ); - QTest::newRow("all filtering, no accepting") + QTest::newRow(desc("all filtering, no accepting")) << QPoint(100, 100) + << eventMode << InputState({ // | event() | child mouse filter // +---------+---------+---------+--------- @@ -3458,8 +3455,9 @@ void tst_qquickwindow::testChildMouseEventFilter_data() ); - QTest::newRow("some filtering, no accepting") + QTest::newRow(desc("some filtering, no accepting")) << QPoint(100, 100) + << eventMode << InputState({ // | event() | child mouse filter // +---------+---------+---------+--------- @@ -3483,8 +3481,9 @@ void tst_qquickwindow::testChildMouseEventFilter_data() << DeliveryRecord("root") ); - QTest::newRow("r1 accepts") + QTest::newRow(desc("r1 accepts")) << QPoint(100, 100) + << eventMode << InputState({ // | event() | child mouse filter // +---------+---------+---------+--------- @@ -3506,8 +3505,9 @@ void tst_qquickwindow::testChildMouseEventFilter_data() << DeliveryRecord("r1") ); - QTest::newRow("r1 rejects and filters") + QTest::newRow(desc("r1 rejects and filters")) << QPoint(100, 100) + << eventMode << InputState({ // | event() | child mouse filter // +---------+---------+---------+--------- @@ -3530,12 +3530,13 @@ void tst_qquickwindow::testChildMouseEventFilter_data() << DeliveryRecord("r0") << DeliveryRecord("root") ); - + } } void tst_qquickwindow::testChildMouseEventFilter() { QFETCH(QPoint, mousePos); + QFETCH(QString, eventMode); QFETCH(InputState, inputState); QFETCH(DeliveryRecordVector, expectedDeliveryOrder); @@ -3550,21 +3551,28 @@ void tst_qquickwindow::testChildMouseEventFilter() QScopedPointer<EventFilter> rootFilter(new EventFilter); root->installEventFilter(rootFilter.data()); + const bool useMouseEvents = eventMode == "mouse"; + const bool acceptTouchEvents = eventMode == "touch"; + // Create 4 items; each item a child of the previous item. EventItem *r[4]; r[0] = new EventItem(root); r[0]->setColor(QColor(0x404040)); r[0]->setWidth(200); r[0]->setHeight(200); + r[0]->setAcceptTouchEvents(acceptTouchEvents); r[1] = new EventItem(r[0]); r[1]->setColor(QColor(0x606060)); + r[1]->setAcceptTouchEvents(acceptTouchEvents); r[2] = new EventItem(r[1]); r[2]->setColor(Qt::red); + r[2]->setAcceptTouchEvents(acceptTouchEvents); r[3] = new EventItem(r[2]); r[3]->setColor(Qt::green); + r[3]->setAcceptTouchEvents(acceptTouchEvents); for (uint i = 0; i < sizeof(r)/sizeof(EventItem*); ++i) { r[i]->setEventAccepts(inputState.r[i].eventAccepts); @@ -3581,7 +3589,11 @@ void tst_qquickwindow::testChildMouseEventFilter() DeliveryRecordVector &actualDeliveryOrder = EventItem::deliveryList(); actualDeliveryOrder.clear(); - QTest::mousePress(&window, Qt::LeftButton, Qt::NoModifier, mousePos); + + if (useMouseEvents) + QTest::mousePress(&window, Qt::LeftButton, Qt::NoModifier, mousePos); + else + QTest::touchEvent(&window, touchDevice).press(0, mousePos, &window); // Check if event got delivered to the root item. If so, append it to the list of items the event got delivered to if (rootFilter->events.contains(QEvent::MouseButtonPress)) @@ -3597,8 +3609,11 @@ void tst_qquickwindow::testChildMouseEventFilter() QVERIFY(item->testFilterPreConditions()); } - // "restore" mouse state - QTest::mouseRelease(&window, Qt::LeftButton, Qt::NoModifier, mousePos); + // "restore" mouse/touch state + if (useMouseEvents) + QTest::mouseRelease(&window, Qt::LeftButton, Qt::NoModifier, mousePos); + else + QTest::touchEvent(&window, touchDevice).release(0, mousePos, &window); } void tst_qquickwindow::cleanupGrabsOnRelease() |