From ec73ca03610a4fbb14a3951eb18b6cbd5422b172 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Tue, 30 Sep 2025 21:35:12 +0200 Subject: [PATCH 2/2] QQuickPointerTouchEvent::reset: clear unused stored touchpoints m_touchPoints grows to hold the maximum number of touchpoints that have been used simultaneously so far. Usually they are inserted in order by pointID; however, the order of points in a touch event cannot be guaranteed. After they are populated in event-order by the bottom loop in QQuickPointerTouchEvent::reset(QEvent*), pointById() is used to look up the stored point for the event point, each time that it is needed. pointById() returns the first matching one: so in theory, other leftover instances in m_touchPoints are ignored. But in practice, when the number of touchpoints increases and then decreases, we could occasionally see the warning "TouchPointPressed without previous release event", indicating that before processing an incoming touch event, a stored point with the same pointID as an event point in Pressed state has a grabber already. The last time that point was released, the grabber was in fact cleared. But we could get into a state where m_touchPoints stores multiple points with the same ID (because of repeatedly "drumming" on the touchscreen with different numbers of fingers, or just letting a stray finger touch it while attempting a 3-finger gesture, so that touchpoints with the same low-numbered IDs get grabbed in different orders at different times); on release of each point, we clear its grabber in the first found instance; then the next event overwrites that instance with a point that has a different ID; then pointById() can find an older leftover instance in which the grabber was still set. So the simple fix is to reduce confusion by resetting unused stored points completely. Then the "pressed without previous release" warning should not happen. Fixes: QTBUG-140420 Change-Id: I30915249d9068ddaaee75adad992a3081dda2688 --- src/quick/items/qquickevents.cpp | 15 +++++++++++++++ src/quick/items/qquickevents_p_p.h | 1 + 2 files changed, 16 insertions(+) diff --git a/src/quick/items/qquickevents.cpp b/src/quick/items/qquickevents.cpp index 7fa1f4280f6..6f2d68782b3 100644 --- a/src/quick/items/qquickevents.cpp +++ b/src/quick/items/qquickevents.cpp @@ -1187,6 +1187,17 @@ QQuickEventTouchPoint::QQuickEventTouchPoint(QQuickPointerTouchEvent *parent) : QQuickEventPoint(parent), m_rotation(0), m_pressure(0) {} +void QQuickEventTouchPoint::reset() +{ + QQuickEventPoint::reset(Qt::TouchPointReleased, {}, 0, 0, {}); + m_exclusiveGrabber.clear(); + m_passiveGrabbers.clear(); + m_rotation = 0; + m_pressure = 0; + m_ellipseDiameters = {}; + m_uniqueId = {}; +} + void QQuickEventTouchPoint::reset(const QTouchEvent::TouchPoint &tp, ulong timestamp) { QQuickEventPoint::reset(tp.state(), tp.scenePos(), tp.id(), timestamp, tp.velocity()); @@ -1454,6 +1465,10 @@ QQuickPointerEvent *QQuickPointerTouchEvent::reset(QEvent *event) point->m_passiveGrabbers = preserved.passiveGrabbers; } } + // Reset remaining stored points, to indicate that they are no longer in use + for (int i = newPointCount; i < m_touchPoints.size(); ++i) + m_touchPoints.at(i)->reset(); + m_pointCount = newPointCount; return this; } diff --git a/src/quick/items/qquickevents_p_p.h b/src/quick/items/qquickevents_p_p.h index c3cc7d681e2..70286d8f2a3 100644 --- a/src/quick/items/qquickevents_p_p.h +++ b/src/quick/items/qquickevents_p_p.h @@ -378,6 +378,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickEventTouchPoint : public QQuickEventPoint public: QQuickEventTouchPoint(QQuickPointerTouchEvent *parent); + void reset(); void reset(const QTouchEvent::TouchPoint &tp, ulong timestamp); qreal rotation() const { return m_rotation; } -- 2.51.0