xcb: Delete touch points without target windows

When XCB_INPUT_TOUCH_BEGIN closes a popup, we then receive
XCB_INPUT_TOUCH_END, and cannot find a target window (because it's
destroyed). If we don't deliver it, we need to at least clear the
stored point from QPointingDevicePrivate::activePoints. Then when
we deliver the next touch press, m_fakeMouseSourcePointId also
needs to be reset.

It's now even more paramount that autotests (and real-world
touchscreens) must never omit any active touchpoint from a touch event.
If a point doesn't move, it must be included in the QTouchEvent, with
Stationary state. If not, QGuiApp::processTouchEvent() could generate
multiple TouchBegin events in a row, which gets other bits of logic
confused, here and there.

Fixes: QTBUG-94557
Fixes: QTBUG-98519
Fixes: QTBUG-102751
Fixes: QTBUG-103706
Pick-to: 6.2 6.3 5.15
Change-Id: Ia95e410a2bb8bc7784aa5d296fac2b89e53a9f55
Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
This commit is contained in:
Tang Haixiang 2021-06-18 14:29:01 +08:00 committed by Shawn Rutledge
parent 9af1f3557a
commit efc02f9cc3
4 changed files with 46 additions and 4 deletions

View File

@ -2984,7 +2984,7 @@ void QGuiApplicationPrivate::processTouchEvent(QWindowSystemInterfacePrivate::To
QEvent::Type mouseEventType = QEvent::MouseMove;
Qt::MouseButton button = Qt::NoButton;
Qt::MouseButtons buttons = Qt::LeftButton;
if (eventType == QEvent::TouchBegin && m_fakeMouseSourcePointId < 0) {
if (eventType == QEvent::TouchBegin || m_fakeMouseSourcePointId < 0) {
m_fakeMouseSourcePointId = touchEvent.point(0).id();
qCDebug(lcPtrDispatch) << "synthesizing mouse events from touchpoint" << m_fakeMouseSourcePointId;
}

View File

@ -748,8 +748,12 @@ void QXcbConnection::xi2HandleEvent(xcb_ge_event_t *event)
event->event_type, xiDeviceEvent->sequence, xiDeviceEvent->detail,
fixed1616ToReal(xiDeviceEvent->event_x), fixed1616ToReal(xiDeviceEvent->event_y),
fixed1616ToReal(xiDeviceEvent->root_x), fixed1616ToReal(xiDeviceEvent->root_y),xiDeviceEvent->event);
if (QXcbWindow *platformWindow = platformWindowFromId(xiDeviceEvent->event))
if (QXcbWindow *platformWindow = platformWindowFromId(xiDeviceEvent->event)) {
xi2ProcessTouch(xiDeviceEvent, platformWindow);
} else { // When the window cannot be matched, delete it from touchPoints
if (TouchDeviceData *dev = touchDeviceForId(xiDeviceEvent->sourceid))
dev->touchPoints.remove((xiDeviceEvent->detail % INT_MAX));
}
break;
}
} else if (xiEnterEvent && eventListener) {

View File

@ -1157,14 +1157,18 @@ void tst_QWindow::touchToMouseTranslation()
QVERIFY(QTest::qWaitForWindowExposed(&window));
QList<QWindowSystemInterface::TouchPoint> points;
QWindowSystemInterface::TouchPoint tp1, tp2;
QWindowSystemInterface::TouchPoint tp1, tp2, tp3;
const QRectF pressArea(101, 102, 4, 4);
const QRectF pressArea1(107, 110, 4, 4);
const QRectF moveArea(105, 108, 4, 4);
tp1.id = 1;
tp1.state = QEventPoint::State::Pressed;
tp1.area = QHighDpi::toNativePixels(pressArea, &window);
tp2.id = 2;
tp2.state = QEventPoint::State::Pressed;
tp3.id = 3;
tp3.state = QEventPoint::State::Pressed;
tp3.area = QHighDpi::toNativePixels(pressArea1, &window);
points << tp1 << tp2;
QWindowSystemInterface::handleTouchEvent(&window, touchDevice, points);
// Now an update but with changed list order. The mouse event should still
@ -1246,6 +1250,40 @@ void tst_QWindow::touchToMouseTranslation()
QWindowSystemInterface::handleTouchEvent(&window, touchDevice, points);
QCoreApplication::processEvents();
QTRY_COMPARE(window.mouseReleaseButton, 1);
points.clear();
points.append(tp1);
points[0].state = QEventPoint::State::Pressed;
QWindowSystemInterface::handleTouchEvent(&window, touchDevice, points);
QCoreApplication::processEvents();
points.clear();
points.append(tp2);
points[0].state = QEventPoint::State::Pressed;
QWindowSystemInterface::handleTouchEvent(&window, touchDevice, points);
QCoreApplication::processEvents();
points.clear();
points.append(tp3);
points[0].state = QEventPoint::State::Pressed;
QWindowSystemInterface::handleTouchEvent(&window, touchDevice, points);
QCoreApplication::processEvents();
QTRY_COMPARE(window.mousePressButton, 1);
points.clear();
points.append(tp2);
points[0].state = QEventPoint::State::Released;
QWindowSystemInterface::handleTouchEvent(&window, touchDevice, points);
QCoreApplication::processEvents();
points.clear();
points.append(tp3);
points[0].state = QEventPoint::State::Released;
QWindowSystemInterface::handleTouchEvent(&window, touchDevice, points);
QCoreApplication::processEvents();
points.clear();
points.append(tp1);
points[0].state = QEventPoint::State::Released;
QWindowSystemInterface::handleTouchEvent(&window, touchDevice, points);
QCoreApplication::processEvents();
QTRY_COMPARE(window.mouseReleaseButton, 1);
}
void tst_QWindow::touchToMouseTranslationForDevices()

View File

@ -269,7 +269,7 @@ void tst_QGestureRecognizer::swipeGesture()
// Press point #3
points.append(points.last() + fingerDistance);
swipeSequence.press(points.size() - 1, points.last(), &widget);
swipeSequence.stationary(0).stationary(1).press(points.size() - 1, points.last(), &widget);
swipeSequence.commit();
Q_ASSERT(points.size() == swipePoints);