QGuiAppPrivate::processMouseEvent: don't assume eventpoint didn't move

During delivery of a pointer event, another type might be synthesized
from it; and we are not yet "done" with all access to the original event
until the delivery of the synthesized event is completed. Further,
there could be a nested event loop if exec() is called on a dialog.
If QPointingDevicePrivate::pointById() causes activePoints to grow
(for example if we handle a fresh incoming touch event in the nested
event loop), reallocation could cause the persistentPoint reference near
the top of processMouseEvent() to be dangling by the time we get to the
bottom; so we need to call queryPointById() again to be sure to get the
persistent QEventPoint that is actually used in the current mouse event
to ungrab.

Fixes: QTBUG-97157
Pick-to: 6.2 6.3
Change-Id: Ib3b90eef5db691675b03474fd75981e972d11d2d
Reviewed-by: Marc Mutz <marc.mutz@qt.io>
This commit is contained in:
Shawn Rutledge 2022-02-03 21:47:00 +01:00
parent 26a0638222
commit bd71fb2514

View File

@ -2173,13 +2173,12 @@ void QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::Mo
QPointF localPoint = e->localPos;
bool doubleClick = false;
auto persistentEPD = devPriv->pointById(0);
const auto &persistentPoint = persistentEPD->eventPoint;
if (mouseMove) {
QGuiApplicationPrivate::lastCursorPosition = globalPoint;
const auto doubleClickDistance = (e->device && e->device->type() == QInputDevice::DeviceType::Mouse ?
mouseDoubleClickDistance : touchDoubleTapDistance);
const auto pressPos = persistentPoint.globalPressPosition();
const auto pressPos = persistentEPD->eventPoint.globalPressPosition();
if (qAbs(globalPoint.x() - pressPos.x()) > doubleClickDistance ||
qAbs(globalPoint.y() - pressPos.y()) > doubleClickDistance)
mousePressButton = Qt::NoButton;
@ -2187,7 +2186,8 @@ void QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::Mo
mouse_buttons = e->buttons;
if (mousePress) {
ulong doubleClickInterval = static_cast<ulong>(QGuiApplication::styleHints()->mouseDoubleClickInterval());
doubleClick = e->timestamp - persistentPoint.pressTimestamp() < doubleClickInterval && button == mousePressButton;
doubleClick = e->timestamp - persistentEPD->eventPoint.pressTimestamp()
< doubleClickInterval && button == mousePressButton;
mousePressButton = button;
}
}
@ -2231,9 +2231,11 @@ void QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::Mo
#endif
QMouseEvent ev(type, localPoint, localPoint, globalPoint, button, e->buttons, e->modifiers, e->source, device);
Q_ASSERT(devPriv->pointById(0) == persistentEPD); // we don't expect reallocation in QPlatformCursor::pointerEvenmt()
// restore globalLastPosition to avoid invalidating the velocity calculations,
// because the QPlatformCursor mouse event above was in native coordinates
QMutableEventPoint::setGlobalLastPosition(persistentEPD->eventPoint, lastGlobalPosition);
persistentEPD = nullptr; // incoming and synth events can cause reallocation during delivery, so don't use this again
// ev now contains a detached copy of the QEventPoint from QPointingDevicePrivate::activePoints
ev.setTimestamp(e->timestamp);
if (window->d_func()->blockedByModalWindow && !qApp->d_func()->popupActive()) {
@ -2290,8 +2292,10 @@ void QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::Mo
}
}
if (type == QEvent::MouseButtonRelease && e->buttons == Qt::NoButton) {
ev.setExclusiveGrabber(persistentPoint, nullptr);
ev.clearPassiveGrabbers(persistentPoint);
if (auto *persistentEPD = devPriv->queryPointById(0)) {
ev.setExclusiveGrabber(persistentEPD->eventPoint, nullptr);
ev.clearPassiveGrabbers(persistentEPD->eventPoint);
}
}
}