summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/widgets/kernel/qapplication.cpp52
-rw-r--r--src/widgets/kernel/qapplication_p.h1
-rw-r--r--tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp48
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;