diff options
-rw-r--r-- | src/widgets/kernel/qapplication.cpp | 52 | ||||
-rw-r--r-- | src/widgets/kernel/qapplication_p.h | 1 | ||||
-rw-r--r-- | tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp | 48 |
3 files changed, 93 insertions, 8 deletions
diff --git a/src/widgets/kernel/qapplication.cpp b/src/widgets/kernel/qapplication.cpp index 50e5ccf938..f7d4139ed8 100644 --- a/src/widgets/kernel/qapplication.cpp +++ b/src/widgets/kernel/qapplication.cpp @@ -3548,6 +3548,10 @@ bool QApplication::notify(QObject *receiver, QEvent *e) QApplicationPrivate::giveFocusAccordingToFocusPolicy(widget, e, localPos); } +#ifndef QT_NO_GESTURES + QPointer<QWidget> gesturePendingWidget; +#endif + while (widget) { // first, try to deliver the touch event acceptTouchEvents = widget->testAttribute(Qt::WA_AcceptTouchEvents); @@ -3565,14 +3569,16 @@ bool QApplication::notify(QObject *receiver, QEvent *e) touchEvent->spont = false; if (res && eventAccepted) { // the first widget to accept the TouchBegin gets an implicit grab. - for (int i = 0; i < touchEvent->touchPoints().count(); ++i) { - const QTouchEvent::TouchPoint &touchPoint = touchEvent->touchPoints().at(i); - d->activeTouchPoints[QGuiApplicationPrivate::ActiveTouchPointsKey(touchEvent->device(), touchPoint.id())].target = widget; - } - break; - } else if (p.isNull() || widget->isWindow() || widget->testAttribute(Qt::WA_NoMousePropagation)) { + d->activateImplicitTouchGrab(widget, touchEvent); break; } +#ifndef QT_NO_GESTURES + if (gesturePendingWidget.isNull() && widget && QGestureManager::gesturePending(widget)) + gesturePendingWidget = widget; +#endif + if (p.isNull() || widget->isWindow() || widget->testAttribute(Qt::WA_NoMousePropagation)) + break; + QPoint offset = widget->pos(); widget = widget->parentWidget(); touchEvent->setTarget(widget); @@ -3586,9 +3592,27 @@ bool QApplication::notify(QObject *receiver, QEvent *e) } } +#ifndef QT_NO_GESTURES + if (!eventAccepted && !gesturePendingWidget.isNull()) { + // the first widget subscribed to a gesture gets an implicit grab + d->activateImplicitTouchGrab(gesturePendingWidget, touchEvent); + } +#endif + touchEvent->setAccepted(eventAccepted); break; } + case QEvent::TouchUpdate: + case QEvent::TouchEnd: + { + QWidget *widget = static_cast<QWidget *>(receiver); + // We may get here if the widget is subscribed to a gesture, + // but has not accepted TouchBegin. Propagate touch events + // only if TouchBegin has been accepted. + if (widget && widget->testAttribute(Qt::WA_WState_AcceptedTouchBeginEvent)) + res = d->notify_helper(widget, e); + break; + } case QEvent::RequestSoftwareInputPanel: inputMethod()->show(); break; @@ -4328,6 +4352,17 @@ QWidget *QApplicationPrivate::findClosestTouchPointTarget(QTouchDevice *device, return static_cast<QWidget *>(closestTarget); } +void QApplicationPrivate::activateImplicitTouchGrab(QWidget *widget, QTouchEvent *touchEvent) +{ + if (touchEvent->type() != QEvent::TouchBegin) + return; + + for (int i = 0, tc = touchEvent->touchPoints().count(); i < tc; ++i) { + const QTouchEvent::TouchPoint &touchPoint = touchEvent->touchPoints().at(i); + activeTouchPoints[QGuiApplicationPrivate::ActiveTouchPointsKey(touchEvent->device(), touchPoint.id())].target = widget; + } +} + bool QApplicationPrivate::translateRawTouchEvent(QWidget *window, QTouchDevice *device, const QList<QTouchEvent::TouchPoint> &touchPoints, @@ -4458,10 +4493,11 @@ bool QApplicationPrivate::translateRawTouchEvent(QWidget *window, || QGestureManager::gesturePending(widget) #endif ) { - if (touchEvent.type() == QEvent::TouchEnd) - widget->setAttribute(Qt::WA_WState_AcceptedTouchBeginEvent, false); if (QApplication::sendSpontaneousEvent(widget, &touchEvent) && touchEvent.isAccepted()) accepted = true; + // widget can be deleted on TouchEnd + if (touchEvent.type() == QEvent::TouchEnd && !widget.isNull()) + widget->setAttribute(Qt::WA_WState_AcceptedTouchBeginEvent, false); } break; } diff --git a/src/widgets/kernel/qapplication_p.h b/src/widgets/kernel/qapplication_p.h index 4cce2d84e8..cb158011f0 100644 --- a/src/widgets/kernel/qapplication_p.h +++ b/src/widgets/kernel/qapplication_p.h @@ -282,6 +282,7 @@ public: QWidget *findClosestTouchPointTarget(QTouchDevice *device, const QTouchEvent::TouchPoint &touchPoint); void appendTouchPoint(const QTouchEvent::TouchPoint &touchPoint); void removeTouchPoint(int touchPointId); + void activateImplicitTouchGrab(QWidget *widget, QTouchEvent *touchBeginEvent); static bool translateRawTouchEvent(QWidget *widget, QTouchDevice *device, const QList<QTouchEvent::TouchPoint> &touchPoints, diff --git a/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp b/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp index 293689bff3..fb3e644a5c 100644 --- a/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp +++ b/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp @@ -447,6 +447,7 @@ private slots: void touchEventSynthesizedMouseEvent(); void touchUpdateOnNewTouch(); + void touchEventsForGesturePendingWidgets(); void styleSheetPropagation(); @@ -9788,6 +9789,7 @@ public: m_touchUpdateCount(0), m_touchEndCount(0), m_touchEventCount(0), + m_gestureEventCount(0), m_acceptTouch(false), m_mouseEventCount(0), m_acceptMouse(true) @@ -9825,6 +9827,9 @@ protected: else e->ignore(); return true; + case QEvent::Gesture: + ++m_gestureEventCount; + return true; case QEvent::MouseButtonPress: case QEvent::MouseMove: @@ -9847,6 +9852,7 @@ public: int m_touchUpdateCount; int m_touchEndCount; int m_touchEventCount; + int m_gestureEventCount; bool m_acceptTouch; int m_mouseEventCount; bool m_acceptMouse; @@ -10002,6 +10008,48 @@ void tst_QWidget::touchUpdateOnNewTouch() QCOMPARE(widget.m_touchEndCount, 1); } +void tst_QWidget::touchEventsForGesturePendingWidgets() +{ + QTouchDevice *device = new QTouchDevice; + device->setType(QTouchDevice::TouchScreen); + QWindowSystemInterface::registerTouchDevice(device); + + TouchMouseWidget parent; + TouchMouseWidget child(&parent); + parent.grabGesture(Qt::TapAndHoldGesture); + parent.show(); + + QWindow* window = parent.windowHandle(); + QVERIFY(QTest::qWaitForWindowExposed(window)); + QTest::qWait(500); // needed for QApplication::topLevelAt(), which is used by QGestureManager + QCOMPARE(child.m_touchEventCount, 0); + QCOMPARE(child.m_gestureEventCount, 0); + QCOMPARE(parent.m_touchEventCount, 0); + QCOMPARE(parent.m_gestureEventCount, 0); + QTest::touchEvent(window, device).press(0, QPoint(20, 20), window); + QCOMPARE(child.m_touchEventCount, 0); + QCOMPARE(child.m_gestureEventCount, 0); + QCOMPARE(parent.m_touchBeginCount, 1); // QTapAndHoldGestureRecognizer::create() sets Qt::WA_AcceptTouchEvents + QCOMPARE(parent.m_touchUpdateCount, 0); + QCOMPARE(parent.m_touchEndCount, 0); + QCOMPARE(parent.m_gestureEventCount, 0); + QTest::touchEvent(window, device).move(0, QPoint(25, 25), window); + QCOMPARE(child.m_touchEventCount, 0); + QCOMPARE(child.m_gestureEventCount, 0); + QCOMPARE(parent.m_touchBeginCount, 1); + QCOMPARE(parent.m_touchUpdateCount, 0); + QCOMPARE(parent.m_touchEndCount, 0); + QCOMPARE(parent.m_gestureEventCount, 0); + QTest::qWait(1000); + QTest::touchEvent(window, device).release(0, QPoint(25, 25), window); + QCOMPARE(child.m_touchEventCount, 0); + QCOMPARE(child.m_gestureEventCount, 0); + QCOMPARE(parent.m_touchBeginCount, 1); + QCOMPARE(parent.m_touchUpdateCount, 0); + QCOMPARE(parent.m_touchEndCount, 0); + QVERIFY(parent.m_gestureEventCount > 0); +} + void tst_QWidget::styleSheetPropagation() { QTableView tw; |