diff options
author | Shawn Rutledge <shawn.rutledge@qt.io> | 2021-11-29 20:26:03 +0100 |
---|---|---|
committer | Qt Cherry-pick Bot <cherrypick_bot@qt-project.org> | 2022-02-04 05:41:32 +0000 |
commit | ee68d19b1dc786eba66629b63648d93d60b18c9d (patch) | |
tree | 3c905d196b5930ab951262f1df270ddfb04d5313 /src/quick/util/qquickdeliveryagent.cpp | |
parent | cee33a6d621e1b3ec0fe120efe15ef4910b9c35f (diff) |
Detach QEventPoint instances during touch compression; test & docs
If we don't detach, they could be modified between the time that the
event is stored (delayed) until it's delivered.
QQuickDeliveryAgentPrivate::compressTouchEvent() had no explicit test
coverage until now; in fact, most tests call QQuickTouchUtils::flush()
after every touch event to ensure that it gets delivered immediately.
Also add internal docs.
Fixes: QTBUG-97185
Fixes: QTBUG-98486
Fixes: QTBUG-98543
Change-Id: I6fd76651ca6fbf15169c44d4d9dbbeb7dc7e3a71
Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
Reviewed-by: Jan Arve Sæther <jan-arve.saether@qt.io>
(cherry picked from commit d08038ba7015dc681c95654f7fe5e54b60c2e55c)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
Diffstat (limited to 'src/quick/util/qquickdeliveryagent.cpp')
-rw-r--r-- | src/quick/util/qquickdeliveryagent.cpp | 42 |
1 files changed, 40 insertions, 2 deletions
diff --git a/src/quick/util/qquickdeliveryagent.cpp b/src/quick/util/qquickdeliveryagent.cpp index 931d27726b..643225ed8e 100644 --- a/src/quick/util/qquickdeliveryagent.cpp +++ b/src/quick/util/qquickdeliveryagent.cpp @@ -1209,6 +1209,7 @@ void QQuickDeliveryAgentPrivate::deliverDelayedTouchEvent() // event loop recursions (e.g if it the touch starts a dnd session). QScopedPointer<QTouchEvent> e(delayedTouch.take()); qCDebug(lcTouchCmprs) << "delivering" << e.data(); + compressedTouchCount = 0; deliverPointerEvent(e.data()); } @@ -1365,10 +1366,35 @@ QQuickPointingDeviceExtra *QQuickDeliveryAgentPrivate::deviceExtra(const QInputD return extra; } +/*! + \internal + This function is called from handleTouchEvent() in case a series of touch + events containing only \c Updated and \c Stationary points arrives within a + short period of time. (Some touchscreens are more "jittery" than others.) + + It would be a waste of CPU time to deliver events and have items in the + scene getting modified more often than once per frame; so here we try to + coalesce the series of updates into a single event containing all updates + that occur within one frame period, and deliverDelayedTouchEvent() is + called from flushFrameSynchronousEvents() to send that single event. This + is the reason why touch compression lives here so far, instead of in a + lower layer: the render loop updates the scene in sync with the screen's + vsync, and flushFrameSynchronousEvents() is called from there (for example + from QSGThreadedRenderLoop::polishAndSync(), and equivalent places in other + render loops). It would be preferable to move this code down to a lower + level eventually, though, because it's not fundamentally a Qt Quick concern. + + This optimization can be turned off by setting the environment variable + \c QML_NO_TOUCH_COMPRESSION. + + Returns \c true if "done", \c false if the caller needs to finish the + \a event delivery. +*/ bool QQuickDeliveryAgentPrivate::compressTouchEvent(QTouchEvent *event) { QEventPoint::States states = event->touchPointStates(); if (states.testFlag(QEventPoint::State::Pressed) || states.testFlag(QEventPoint::State::Released)) { + qCDebug(lcTouchCmprs) << "no compression" << event; // we can only compress an event that doesn't include any pressed or released points return false; } @@ -1376,7 +1402,12 @@ bool QQuickDeliveryAgentPrivate::compressTouchEvent(QTouchEvent *event) if (!delayedTouch) { delayedTouch.reset(new QMutableTouchEvent(event->type(), event->pointingDevice(), event->modifiers(), event->points())); delayedTouch->setTimestamp(event->timestamp()); - qCDebug(lcTouchCmprs) << "delayed" << delayedTouch.data(); + for (qsizetype i = 0; i < delayedTouch->pointCount(); ++i) { + auto &tp = delayedTouch->point(i); + QMutableEventPoint::detach(tp); + } + ++compressedTouchCount; + qCDebug(lcTouchCmprs) << "delayed" << compressedTouchCount << delayedTouch.data(); if (QQuickWindow *window = rootItem->window()) window->maybeUpdate(); return true; @@ -1410,7 +1441,14 @@ bool QQuickDeliveryAgentPrivate::compressTouchEvent(QTouchEvent *event) // TODO optimize, or move event compression elsewhere delayedTouch.reset(new QMutableTouchEvent(event->type(), event->pointingDevice(), event->modifiers(), tpts)); delayedTouch->setTimestamp(event->timestamp()); - qCDebug(lcTouchCmprs) << "coalesced" << delayedTouch.data(); + for (qsizetype i = 0; i < delayedTouch->pointCount(); ++i) { + auto &tp = delayedTouch->point(i); + QMutableEventPoint::detach(tp); + } + ++compressedTouchCount; + qCDebug(lcTouchCmprs) << "coalesced" << compressedTouchCount << delayedTouch.data(); + if (QQuickWindow *window = rootItem->window()) + window->maybeUpdate(); return true; } } |