Make an implicit grab on TouchBegin for a widget subscribed to a gesture
A receiver of TouchUpdate and TouchEnd events is determined either as a widget which has an implicit grab for the touch point or as a visible widget if there are no implicit grabs. The events are sent if the receiver has accepted TouchBegin event or if it is subscribed to a gesture. Before sending the events to the widget they are delivered to the gesture manager. Thus, in order to detect gestures for the widget, it must own an implicit grab or be a visible widget. It can happen that the parent widget is subscribed to a gesture, but doesn't accept TouchBegin event, as in the case of QScrollArea. Then it will not get an implicit grab and gesture detection will be impossible. Activate an implicit grab for such widgets. Also don't send TouchUpdate and TouchEnd to them, because it's against the documentation. Task-number: QTBUG-43277 Change-Id: Id767583991def6d76c48ad15eb39af822cad115d Reviewed-by: Shawn Rutledge <shawn.rutledge@theqtcompany.com>bb10
parent
00f1c4ac3a
commit
559152d911
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Reference in New Issue