From bd71fb2514f49593c88b6c74d13c558d9a8601ea Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Thu, 3 Feb 2022 21:47:00 +0100 Subject: [PATCH] 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 --- src/gui/kernel/qguiapplication.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp index ecdf2c6959f..30c0a5fc868 100644 --- a/src/gui/kernel/qguiapplication.cpp +++ b/src/gui/kernel/qguiapplication.cpp @@ -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(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); + } } }