diff --git a/src/widgets/kernel/qapplication.cpp b/src/widgets/kernel/qapplication.cpp index 0fa3c6a3d7..fa381e796c 100644 --- a/src/widgets/kernel/qapplication.cpp +++ b/src/widgets/kernel/qapplication.cpp @@ -3159,8 +3159,9 @@ 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); + // the first widget subscribed to a gesture gets an implicit grab for all + // points, also for events and event points that have not been accepted. + d->activateImplicitTouchGrab(gesturePendingWidget, touchEvent, QApplicationPrivate::GrabAllPoints); } #endif @@ -3851,16 +3852,18 @@ QWidget *QApplicationPrivate::findClosestTouchPointTarget(const QPointingDevice return static_cast(closestTarget); } -void QApplicationPrivate::activateImplicitTouchGrab(QWidget *widget, QTouchEvent *touchEvent) +void QApplicationPrivate::activateImplicitTouchGrab(QWidget *widget, QTouchEvent *touchEvent, + ImplicitTouchGrabMode grabMode) { if (touchEvent->type() != QEvent::TouchBegin) return; // If the widget dispatched the event further (see QGraphicsProxyWidget), then - // there might already be an implicit grabber. Don't override that. + // there might already be an implicit grabber. Don't override that. A widget that + // has partially recognized a gesture needs to grab all points. for (int i = 0; i < touchEvent->pointCount(); ++i) { auto &mep = QMutableEventPoint::from(touchEvent->point(i)); - if (!mep.target() && mep.isAccepted()) + if (!mep.target() && (mep.isAccepted() || grabMode == GrabAllPoints)) mep.setTarget(widget); } // TODO setExclusiveGrabber() to be consistent with Qt Quick? diff --git a/src/widgets/kernel/qapplication_p.h b/src/widgets/kernel/qapplication_p.h index 6bb1f35d1b..155081fd79 100644 --- a/src/widgets/kernel/qapplication_p.h +++ b/src/widgets/kernel/qapplication_p.h @@ -248,7 +248,9 @@ public: QWidget *findClosestTouchPointTarget(const QPointingDevice *device, const QEventPoint &touchPoint); void appendTouchPoint(const QEventPoint &touchPoint); void removeTouchPoint(int touchPointId); - void activateImplicitTouchGrab(QWidget *widget, QTouchEvent *touchBeginEvent); + enum ImplicitTouchGrabMode { GrabAcceptedPoints, GrabAllPoints }; + void activateImplicitTouchGrab(QWidget *widget, QTouchEvent *touchBeginEvent, + ImplicitTouchGrabMode grabMode = GrabAcceptedPoints); static bool translateRawTouchEvent(QWidget *widget, const QTouchEvent *touchEvent); static void translateTouchCancel(const QPointingDevice *device, ulong timestamp); diff --git a/tests/auto/widgets/kernel/qgesturerecognizer/tst_qgesturerecognizer.cpp b/tests/auto/widgets/kernel/qgesturerecognizer/tst_qgesturerecognizer.cpp index b65f6a5ff6..9687601158 100644 --- a/tests/auto/widgets/kernel/qgesturerecognizer/tst_qgesturerecognizer.cpp +++ b/tests/auto/widgets/kernel/qgesturerecognizer/tst_qgesturerecognizer.cpp @@ -53,6 +53,7 @@ private Q_SLOTS: void pinchGesture(); void swipeGesture_data(); void swipeGesture(); + void touchReplay(); #endif // !QT_NO_GESTURES private: @@ -326,6 +327,25 @@ void tst_QGestureRecognizer::swipeGesture() } } +void tst_QGestureRecognizer::touchReplay() +{ + const Qt::GestureType gestureType = Qt::TapGesture; + QWidget parent; + TestWidget widget(GestureTypeVector(1, gestureType)); + widget.setParent(&parent); + widget.setGeometry(0, 0, 100, 100); + parent.adjustSize(); + parent.show(); + QVERIFY(QTest::qWaitForWindowActive(&parent)); + + QWindow* windowHandle = parent.window()->windowHandle(); + const QPoint globalPos = QPoint(42, 16); + QTest::touchEvent(windowHandle, m_touchDevice).press(1, globalPos); + QTest::touchEvent(windowHandle, m_touchDevice).release(1, globalPos); + + QVERIFY(widget.gestureReceived(gestureType)); +} + #endif // !QT_NO_GESTURES QTEST_MAIN(tst_QGestureRecognizer)