From 536e1cccf15963b586f3112a0654ddc0d101fa69 Mon Sep 17 00:00:00 2001 From: Daniel d'Andrada <daniel.dandrada@canonical.com> Date: Tue, 12 Nov 2013 11:47:32 -0200 Subject: [PATCH] Fix delivery of QEvents to QQuickItems Make them go through QObject::event() and comply to filtering from objects passsed to QObject::installEventFilter() Task-number: QTBUG-32004 Change-Id: Ib6972e7f5e588bee986ae5f2d69aa6fccb58af95 Reviewed-by: J-P Nurmi <jpnurmi@digia.com> Reviewed-by: Alan Alpert <aalpert@blackberry.com> Reviewed-by: Frederik Gladhorn <frederik.gladhorn@digia.com> --- src/quick/items/qquickitem.cpp | 176 +++++++----------- src/quick/items/qquickitem_p.h | 10 - src/quick/items/qquickwindow.cpp | 46 ++--- .../quick/qquickwindow/tst_qquickwindow.cpp | 97 ++++++++++ 4 files changed, 188 insertions(+), 141 deletions(-) diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp index c11bf904be..65322f6de4 100644 --- a/src/quick/items/qquickitem.cpp +++ b/src/quick/items/qquickitem.cpp @@ -4472,96 +4472,6 @@ void QQuickItemPrivate::deliverInputMethodEvent(QInputMethodEvent *e) } #endif // QT_NO_IM -void QQuickItemPrivate::deliverFocusEvent(QFocusEvent *e) -{ - Q_Q(QQuickItem); - - if (e->type() == QEvent::FocusIn) { - q->focusInEvent(e); - } else { - q->focusOutEvent(e); - } -} - -void QQuickItemPrivate::deliverMouseEvent(QMouseEvent *e) -{ - Q_Q(QQuickItem); - - Q_ASSERT(e->isAccepted()); - - switch (e->type()) { - default: - Q_ASSERT(!"Unknown event type"); - case QEvent::MouseMove: - q->mouseMoveEvent(e); - break; - case QEvent::MouseButtonPress: - q->mousePressEvent(e); - break; - case QEvent::MouseButtonRelease: - q->mouseReleaseEvent(e); - break; - case QEvent::MouseButtonDblClick: - q->mouseDoubleClickEvent(e); - break; - } -} - -#ifndef QT_NO_WHEELEVENT -void QQuickItemPrivate::deliverWheelEvent(QWheelEvent *e) -{ - Q_Q(QQuickItem); - q->wheelEvent(e); -} -#endif - -void QQuickItemPrivate::deliverTouchEvent(QTouchEvent *e) -{ - Q_Q(QQuickItem); - q->touchEvent(e); -} - -void QQuickItemPrivate::deliverHoverEvent(QHoverEvent *e) -{ - Q_Q(QQuickItem); - switch (e->type()) { - default: - Q_ASSERT(!"Unknown event type"); - case QEvent::HoverEnter: - q->hoverEnterEvent(e); - break; - case QEvent::HoverLeave: - q->hoverLeaveEvent(e); - break; - case QEvent::HoverMove: - q->hoverMoveEvent(e); - break; - } -} - -#ifndef QT_NO_DRAGANDDROP -void QQuickItemPrivate::deliverDragEvent(QEvent *e) -{ - Q_Q(QQuickItem); - switch (e->type()) { - default: - Q_ASSERT(!"Unknown event type"); - case QEvent::DragEnter: - q->dragEnterEvent(static_cast<QDragEnterEvent *>(e)); - break; - case QEvent::DragLeave: - q->dragLeaveEvent(static_cast<QDragLeaveEvent *>(e)); - break; - case QEvent::DragMove: - q->dragMoveEvent(static_cast<QDragMoveEvent *>(e)); - break; - case QEvent::Drop: - q->dropEvent(static_cast<QDropEvent *>(e)); - break; - } -} -#endif // QT_NO_DRAGANDDROP - /*! Called when \a change occurs for this item. @@ -6983,18 +6893,17 @@ QRectF QQuickItem::mapRectFromScene(const QRectF &rect) const */ bool QQuickItem::event(QEvent *ev) { + Q_D(QQuickItem); + + switch (ev->type()) { #if 0 - if (ev->type() == QEvent::PolishRequest) { - Q_D(QQuickItem); + case QEvent::PolishRequest: d->polishScheduled = false; updatePolish(); - return true; - } else { - return QObject::event(ev); - } + break; #endif #ifndef QT_NO_IM - if (ev->type() == QEvent::InputMethodQuery) { + case QEvent::InputMethodQuery: { QInputMethodQueryEvent *query = static_cast<QInputMethodQueryEvent *>(ev); Qt::InputMethodQueries queries = query->queries(); for (uint i = 0; i < 32; ++i) { @@ -7005,17 +6914,76 @@ bool QQuickItem::event(QEvent *ev) } } query->accept(); - return true; - } else if (ev->type() == QEvent::InputMethod) { + break; + } + case QEvent::InputMethod: inputMethodEvent(static_cast<QInputMethodEvent *>(ev)); - return true; - } else + break; #endif // QT_NO_IM - if (ev->type() == QEvent::StyleAnimationUpdate) { + case QEvent::TouchBegin: + case QEvent::TouchUpdate: + case QEvent::TouchEnd: + case QEvent::TouchCancel: + touchEvent(static_cast<QTouchEvent*>(ev)); + break; + case QEvent::StyleAnimationUpdate: update(); - return true; + break; + case QEvent::HoverEnter: + hoverEnterEvent(static_cast<QHoverEvent*>(ev)); + break; + case QEvent::HoverLeave: + hoverLeaveEvent(static_cast<QHoverEvent*>(ev)); + break; + case QEvent::HoverMove: + hoverMoveEvent(static_cast<QHoverEvent*>(ev)); + break; + case QEvent::KeyPress: + case QEvent::KeyRelease: + d->deliverKeyEvent(static_cast<QKeyEvent*>(ev)); + break; + case QEvent::FocusIn: + focusInEvent(static_cast<QFocusEvent*>(ev)); + break; + case QEvent::FocusOut: + focusOutEvent(static_cast<QFocusEvent*>(ev)); + break; + case QEvent::MouseMove: + mouseMoveEvent(static_cast<QMouseEvent*>(ev)); + break; + case QEvent::MouseButtonPress: + mousePressEvent(static_cast<QMouseEvent*>(ev)); + break; + case QEvent::MouseButtonRelease: + mouseReleaseEvent(static_cast<QMouseEvent*>(ev)); + break; + case QEvent::MouseButtonDblClick: + mouseDoubleClickEvent(static_cast<QMouseEvent*>(ev)); + break; +#ifndef QT_NO_WHEELEVENT + case QEvent::Wheel: + wheelEvent(static_cast<QWheelEvent*>(ev)); + break; +#endif +#ifndef QT_NO_DRAGANDDROP + case QEvent::DragEnter: + dragEnterEvent(static_cast<QDragEnterEvent*>(ev)); + break; + case QEvent::DragLeave: + dragLeaveEvent(static_cast<QDragLeaveEvent*>(ev)); + break; + case QEvent::DragMove: + dragMoveEvent(static_cast<QDragMoveEvent*>(ev)); + break; + case QEvent::Drop: + dropEvent(static_cast<QDropEvent*>(ev)); + break; +#endif // QT_NO_DRAGANDDROP + default: + return QObject::event(ev); } - return QObject::event(ev); + + return true; } #ifndef QT_NO_DEBUG_STREAM diff --git a/src/quick/items/qquickitem_p.h b/src/quick/items/qquickitem_p.h index 7faf39f8e5..ccf949ee8b 100644 --- a/src/quick/items/qquickitem_p.h +++ b/src/quick/items/qquickitem_p.h @@ -540,16 +540,6 @@ public: #ifndef QT_NO_IM void deliverInputMethodEvent(QInputMethodEvent *); #endif - void deliverFocusEvent(QFocusEvent *); - void deliverMouseEvent(QMouseEvent *); -#ifndef QT_NO_WHEELEVENT - void deliverWheelEvent(QWheelEvent *); -#endif - void deliverTouchEvent(QTouchEvent *); - void deliverHoverEvent(QHoverEvent *); -#ifndef QT_NO_DRAGANDDROP - void deliverDragEvent(QEvent *); -#endif bool calcEffectiveVisible() const; bool setEffectiveVisibleRecur(bool); diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index a993889c45..10906dd64c 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -524,7 +524,7 @@ bool QQuickWindowPrivate::translateTouchToMouse(QQuickItem *item, QTouchEvent *e item->grabMouse(); item->grabTouchPoints(QVector<int>() << touchMouseId); - QQuickItemPrivate::get(item)->deliverMouseEvent(mousePress.data()); + QCoreApplication::sendEvent(item, mousePress.data()); event->setAccepted(mousePress->isAccepted()); if (!mousePress->isAccepted()) { touchMouseId = -1; @@ -537,7 +537,7 @@ bool QQuickWindowPrivate::translateTouchToMouse(QQuickItem *item, QTouchEvent *e if (mousePress->isAccepted() && checkIfDoubleClicked(event->timestamp())) { QScopedPointer<QMouseEvent> mouseDoubleClick(touchToMouseEvent(QEvent::MouseButtonDblClick, p, event, item)); - QQuickItemPrivate::get(item)->deliverMouseEvent(mouseDoubleClick.data()); + QCoreApplication::sendEvent(item, mouseDoubleClick.data()); event->setAccepted(mouseDoubleClick->isAccepted()); if (mouseDoubleClick->isAccepted()) { return true; @@ -558,7 +558,7 @@ bool QQuickWindowPrivate::translateTouchToMouse(QQuickItem *item, QTouchEvent *e if (p.state() & Qt::TouchPointMoved) { if (mouseGrabberItem) { QScopedPointer<QMouseEvent> me(touchToMouseEvent(QEvent::MouseMove, p, event, mouseGrabberItem)); - QQuickItemPrivate::get(item)->deliverMouseEvent(me.data()); + QCoreApplication::sendEvent(item, me.data()); event->setAccepted(me->isAccepted()); if (me->isAccepted()) { itemForTouchPointId[p.id()] = mouseGrabberItem; // N.B. the mouseGrabberItem may be different after returning from sendEvent() @@ -588,7 +588,7 @@ bool QQuickWindowPrivate::translateTouchToMouse(QQuickItem *item, QTouchEvent *e touchMouseId = -1; if (mouseGrabberItem) { QScopedPointer<QMouseEvent> me(touchToMouseEvent(QEvent::MouseButtonRelease, p, event, mouseGrabberItem)); - QQuickItemPrivate::get(item)->deliverMouseEvent(me.data()); + QCoreApplication::sendEvent(item, me.data()); if (mouseGrabberItem) // might have ungrabbed due to event mouseGrabberItem->ungrabMouse(); return me->isAccepted(); @@ -1807,11 +1807,11 @@ bool QQuickWindowPrivate::deliverMatchingPointsToItem(QQuickItem *item, QTouchEv itemForTouchPointId[id] = item; // Deliver the touch event to the given item - QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item); - itemPrivate->deliverTouchEvent(touchEvent.data()); + QCoreApplication::sendEvent(item, touchEvent.data()); touchEventAccepted = touchEvent->isAccepted(); // If the touch event wasn't accepted, synthesize a mouse event and see if the item wants it. + QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item); if (!touchEventAccepted && (itemPrivate->acceptedMouseButtons() & Qt::LeftButton)) { // send mouse event event->setAccepted(translateTouchToMouse(item, event)); @@ -2229,16 +2229,12 @@ bool QQuickWindow::sendEvent(QQuickItem *item, QEvent *e) case QEvent::KeyPress: case QEvent::KeyRelease: e->accept(); - QQuickItemPrivate::get(item)->deliverKeyEvent(static_cast<QKeyEvent *>(e)); + QCoreApplication::sendEvent(item, e); while (!e->isAccepted() && (item = item->parentItem())) { e->accept(); - QQuickItemPrivate::get(item)->deliverKeyEvent(static_cast<QKeyEvent *>(e)); + QCoreApplication::sendEvent(item, e); } break; - case QEvent::FocusIn: - case QEvent::FocusOut: - QQuickItemPrivate::get(item)->deliverFocusEvent(static_cast<QFocusEvent *>(e)); - break; case QEvent::MouseButtonPress: case QEvent::MouseButtonRelease: case QEvent::MouseButtonDblClick: @@ -2247,7 +2243,7 @@ bool QQuickWindow::sendEvent(QQuickItem *item, QEvent *e) if (!d->sendFilteredMouseEvent(item->parentItem(), item, e)) { // accept because qml items by default accept and have to explicitly opt out of accepting e->accept(); - QQuickItemPrivate::get(item)->deliverMouseEvent(static_cast<QMouseEvent *>(e)); + QCoreApplication::sendEvent(item, e); } break; case QEvent::UngrabMouse: @@ -2258,30 +2254,26 @@ bool QQuickWindow::sendEvent(QQuickItem *item, QEvent *e) break; #ifndef QT_NO_WHEELEVENT case QEvent::Wheel: - QQuickItemPrivate::get(item)->deliverWheelEvent(static_cast<QWheelEvent *>(e)); - break; #endif +#ifndef QT_NO_DRAGANDDROP + case QEvent::DragEnter: + case QEvent::DragMove: + case QEvent::DragLeave: + case QEvent::Drop: +#endif + case QEvent::FocusIn: + case QEvent::FocusOut: case QEvent::HoverEnter: case QEvent::HoverLeave: case QEvent::HoverMove: - QQuickItemPrivate::get(item)->deliverHoverEvent(static_cast<QHoverEvent *>(e)); + case QEvent::TouchCancel: + QCoreApplication::sendEvent(item, e); break; case QEvent::TouchBegin: case QEvent::TouchUpdate: case QEvent::TouchEnd: d->sendFilteredTouchEvent(item->parentItem(), item, static_cast<QTouchEvent *>(e)); break; - case QEvent::TouchCancel: - QQuickItemPrivate::get(item)->deliverTouchEvent(static_cast<QTouchEvent *>(e)); - break; -#ifndef QT_NO_DRAGANDDROP - case QEvent::DragEnter: - case QEvent::DragMove: - case QEvent::DragLeave: - case QEvent::Drop: - QQuickItemPrivate::get(item)->deliverDragEvent(e); - break; -#endif default: break; } diff --git a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp index 984881c8da..1d9beedbab 100644 --- a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp +++ b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp @@ -250,6 +250,18 @@ int TestTouchItem::mousePressNum = 0; int TestTouchItem::mouseMoveNum = 0; int TestTouchItem::mouseReleaseNum = 0; +class EventFilter : public QObject +{ +public: + bool eventFilter(QObject *watched, QEvent *event) { + Q_UNUSED(watched); + events.append(event->type()); + return false; + } + + QList<int> events; +}; + class ConstantUpdateItem : public QQuickItem { Q_OBJECT @@ -330,6 +342,10 @@ private slots: void crashWhenHoverItemDeleted(); + void qobjectEventFilter_touch(); + void qobjectEventFilter_key(); + void qobjectEventFilter_mouse(); + #ifndef QT_NO_CURSOR void cursor(); #endif @@ -922,6 +938,9 @@ void tst_qquickwindow::mouseFiltering() QTRY_COMPARE(middleItem->mousePressId, 1); QTRY_COMPARE(bottomItem->mousePressId, 2); QTRY_COMPARE(topItem->mousePressId, 3); + + // clean up mouse press state for the next tests + QTest::mouseRelease(window, Qt::LeftButton, 0, pos); } void tst_qquickwindow::qmlCreation() @@ -1525,6 +1544,84 @@ void tst_qquickwindow::crashWhenHoverItemDeleted() } } +// QTBUG-32004 +void tst_qquickwindow::qobjectEventFilter_touch() +{ + QQuickWindow window; + + window.resize(250, 250); + window.setPosition(100, 100); + window.show(); + QVERIFY(QTest::qWaitForWindowExposed(&window)); + + TestTouchItem *item = new TestTouchItem(window.contentItem()); + item->setSize(QSizeF(150, 150)); + + EventFilter eventFilter; + item->installEventFilter(&eventFilter); + + QPointF pos(10, 10); + + // press single point + QTest::touchEvent(&window, touchDevice).press(0, item->mapToScene(pos).toPoint(), &window); + + QCOMPARE(eventFilter.events.count(), 1); + QCOMPARE(eventFilter.events.first(), (int)QEvent::TouchBegin); +} + +// QTBUG-32004 +void tst_qquickwindow::qobjectEventFilter_key() +{ + QQuickWindow window; + + window.resize(250, 250); + window.setPosition(100, 100); + window.show(); + QVERIFY(QTest::qWaitForWindowExposed(&window)); + + TestTouchItem *item = new TestTouchItem(window.contentItem()); + item->setSize(QSizeF(150, 150)); + item->setFocus(true); + + EventFilter eventFilter; + item->installEventFilter(&eventFilter); + + QTest::keyPress(&window, Qt::Key_A); + + // NB: It may also receive some QKeyEvent(ShortcutOverride) which we're not interested in + QVERIFY(eventFilter.events.contains((int)QEvent::KeyPress)); + eventFilter.events.clear(); + + QTest::keyRelease(&window, Qt::Key_A); + + QVERIFY(eventFilter.events.contains((int)QEvent::KeyRelease)); +} + +// QTBUG-32004 +void tst_qquickwindow::qobjectEventFilter_mouse() +{ + QQuickWindow window; + + window.resize(250, 250); + window.setPosition(100, 100); + window.show(); + QVERIFY(QTest::qWaitForWindowExposed(&window)); + + TestTouchItem *item = new TestTouchItem(window.contentItem()); + item->setSize(QSizeF(150, 150)); + + EventFilter eventFilter; + item->installEventFilter(&eventFilter); + + QPoint point = item->mapToScene(QPointF(10, 10)).toPoint(); + QTest::mousePress(&window, Qt::LeftButton, Qt::NoModifier, point); + + QVERIFY(eventFilter.events.contains((int)QEvent::MouseButtonPress)); + + // clean up mouse press state for the next tests + QTest::mouseRelease(&window, Qt::LeftButton, Qt::NoModifier, point); +} + QTEST_MAIN(tst_qquickwindow) #include "tst_qquickwindow.moc" -- GitLab