summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShawn Rutledge <shawn.rutledge@qt.io>2021-04-19 15:44:45 +0200
committerQt Cherry-pick Bot <cherrypick_bot@qt-project.org>2021-05-05 09:20:44 +0000
commitafec4d5bb0440e290128250a176a42c459cc5b52 (patch)
treedefadd604117f534a2d63dcbc4825580dec356cd
parentfd469b45100074e44e8bfb57e732b25a29dc2acd (diff)
Store memory of grabbing agents in EventPointData
QQuickDeliveryAgentPrivate::grabberAgent(event, point) was too naive: it's not only that each point could be delivered by a different agent, but also each point could have an exclusive grab in the context of one agent and multiple passive grabs in the contexts of different agents. E.g. in qtquick3d/examples/quick3d/dynamictexture, many grabs can occur if you press on a door: the View3D has a TapHandler to pick the door, so that you can click to open; each Panel has a TapHandler to defocus whichever TextArea has focus; there is a ListView for dragging through the panel delegates sideways; if you press on a yellow note, its DragHandler prepares to start dragging; etc. So at least, a TapHandler in the subscene and the other one in the View3D need to get passive grabs, and need to receive the release event in the correct coordinate system, to detect taps. When we apply the sceneTransform of a particular agent before re-delivering an update or a release, based on the grab, it has to be in the correct coordinate system for that grabber. So on grab, we use EventPointData::exclusiveGrabberContext or passiveGrabbersContext to store the pointer to the QQDeliveryAgent that was doing the delivery when the grab occurred. When we deliver the next event to a grabber, we also look up the correct DA to do the delivery. This gets done twice: once in QQuickWindow::event() to find the DAs that need to handle the event, and in QQDeliveryAgentPriv::deliverUpdatedPoints() to ignore passive grabbers for which a different DA is responsible. The failsafe "never allow any kind of grab to persist after release" is moved to QQuickWindow::event because we don't want to do it prematurely in a subscene agent, and ATM we don't require the main DA to deliver last: it depends on the order in EventPointData::passiveGrabbersContext. QQuickPointerHandler::onGrabChanged() should only be called from the relevant DA, to avoid overreaction: that is, the DA that is delivering an event at the time the grab occurs. QQDelAgentPrivate::onGrabChanged() gets called on all DA instances, but only one of them is supposed to store itself as the assigned DA for handling a particular point ID. It's not always the same as QQuickItemPrivate::deliveryAgent(): that goes astray when the same 2D subscene is mapped to the main scene and also onto multiple QQ3D models. In that case, if the user interacts directly with the 2D scene, the main DA should be assigned; or if the user interacts with one of the mapped subscenes, its DA should be assigned. We have to stop delivering to subscenes when the event is accepted, at least, because of the usual convention that delivery is done when the event remains accepted rather than being purposely ignored. So in the dynamictexture example, if you click on a TextEdit on one of the doors, it receives the event first (because it's on top) and accepts it; that stops delivery in QQuickDeliveryAgentPrivate::deliverPressOrReleaseEvent(), and now also stops QQuickWindow::event() from visiting the next subscene, or the main scene, so that the TapHandler in the View3D doesn't get clicked, and the doors don't open. Task-number: QTBUG-92944 Change-Id: I1b4520b665e58874d17a936024cf62e4c7175d8e Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Andy Nichols <andy.nichols@qt.io> (cherry picked from commit 5c08e911375966761ee8e4d7cd425120985876e2) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
-rw-r--r--src/quick/items/qquickwindow.cpp144
-rw-r--r--src/quick/util/qquickdeliveryagent.cpp143
-rw-r--r--src/quick/util/qquickdeliveryagent_p.h2
-rw-r--r--src/quick/util/qquickdeliveryagent_p_p.h6
4 files changed, 163 insertions, 132 deletions
diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp
index e0c87b4435..6d602a3810 100644
--- a/src/quick/items/qquickwindow.cpp
+++ b/src/quick/items/qquickwindow.cpp
@@ -90,6 +90,7 @@ QT_BEGIN_NAMESPACE
Q_DECLARE_LOGGING_CATEGORY(lcMouse)
Q_DECLARE_LOGGING_CATEGORY(lcTouch)
+Q_DECLARE_LOGGING_CATEGORY(lcPtr)
Q_LOGGING_CATEGORY(lcDirty, "qt.quick.dirty")
Q_LOGGING_CATEGORY(lcTransient, "qt.quick.window.transient")
@@ -1354,19 +1355,15 @@ bool QQuickWindow::event(QEvent *e)
for (pt : pe->points()) would only iterate once, so we might as well skip that logic.
*/
auto pe = static_cast<QPointerEvent *>(e);
- if (pe->pointCount() > 1) {
- bool ret = false;
- Q_ASSERT(QQuickDeliveryAgentPrivate::isTouchEvent(pe));
- // Split up the multi-point event according to the relevant QQuickDeliveryAgent that should deliver to each existing grabber
- // but send ungrabbed points to d->deliveryAgent()
- QFlatMap<QQuickDeliveryAgent*, QList<QEventPoint>> deliveryAgentsNeedingPoints;
- QEventPoint::States eventStates;
- for (const auto &pt : pe->points()) {
- eventStates |= pt.state();
- auto *ptda = QQuickDeliveryAgent::grabberAgent(pe, pt);
- if (!ptda)
- ptda = da;
- if (ptda) {
+ if (pe->pointCount()) {
+ if (QQuickDeliveryAgentPrivate::subsceneAgentsExist) {
+ bool ret = false;
+ // Split up the multi-point event according to the relevant QQuickDeliveryAgent that should deliver to each existing grabber
+ // but send ungrabbed points to d->deliveryAgent()
+ QFlatMap<QQuickDeliveryAgent*, QList<QEventPoint>> deliveryAgentsNeedingPoints;
+ QEventPoint::States eventStates;
+
+ auto insert = [&](QQuickDeliveryAgent *ptda, const QEventPoint &pt) {
if (pt.state() == QEventPoint::Pressed)
pe->clearPassiveGrabbers(pt);
auto danpit = deliveryAgentsNeedingPoints.find(ptda);
@@ -1375,47 +1372,98 @@ bool QQuickWindow::event(QEvent *e)
} else {
danpit.value().append(pt);
}
+ };
+
+ for (const auto &pt : pe->points()) {
+ eventStates |= pt.state();
+ auto epd = QPointingDevicePrivate::get(const_cast<QPointingDevice*>(pe->pointingDevice()))->queryPointById(pt.id());
+ Q_ASSERT(epd);
+ bool foundAgent = false;
+ if (!epd->exclusiveGrabber.isNull() && !epd->exclusiveGrabberContext.isNull()) {
+ if (auto ptda = qobject_cast<QQuickDeliveryAgent *>(epd->exclusiveGrabberContext.data())) {
+ insert(ptda, pt);
+ qCDebug(lcPtr) << pe->type() << "point" << pt.id() << pt.state()
+ << "@" << pt.scenePosition() << "will be re-delivered via known grabbing agent" << ptda << "to" << epd->exclusiveGrabber.data();
+ foundAgent = true;
+ }
+ }
+ for (auto pgda : epd->passiveGrabbersContext) {
+ if (auto ptda = qobject_cast<QQuickDeliveryAgent *>(pgda.data())) {
+ insert(ptda, pt);
+ qCDebug(lcPtr) << pe->type() << "point" << pt.id() << pt.state()
+ << "@" << pt.scenePosition() << "will be re-delivered via known passive-grabbing agent" << ptda;
+ foundAgent = true;
+ }
+ }
+ // fallback: if we didn't find remembered/known grabber agent(s), expect the root DA to handle it
+ if (!foundAgent)
+ insert(da, pt);
}
- }
- // Make new touch events for each subscene, the same way QQuickItemPrivate::localizedTouchEvent() does it
- for (auto daAndPoints : deliveryAgentsNeedingPoints) {
- // if all points have the same state, set the event type accordingly
- QEvent::Type eventType = pe->type();
- switch (eventStates) {
- case QEventPoint::State::Pressed:
- eventType = QEvent::TouchBegin;
- break;
- case QEventPoint::State::Released:
- eventType = QEvent::TouchEnd;
- break;
- default:
- eventType = QEvent::TouchUpdate;
- break;
+ for (auto daAndPoints : deliveryAgentsNeedingPoints) {
+ if (pe->pointCount() > 1) {
+ Q_ASSERT(QQuickDeliveryAgentPrivate::isTouchEvent(pe));
+ // if all points have the same state, set the event type accordingly
+ QEvent::Type eventType = pe->type();
+ switch (eventStates) {
+ case QEventPoint::State::Pressed:
+ eventType = QEvent::TouchBegin;
+ break;
+ case QEventPoint::State::Released:
+ eventType = QEvent::TouchEnd;
+ break;
+ default:
+ eventType = QEvent::TouchUpdate;
+ break;
+ }
+ // Make a new touch event for the subscene, the same way QQuickItemPrivate::localizedTouchEvent() does it
+ QMutableTouchEvent te(eventType, pe->pointingDevice(), pe->modifiers(), daAndPoints.second);
+ te.setTimestamp(pe->timestamp());
+ te.accept();
+ qCDebug(lcTouch) << daAndPoints.first << "shall now receive" << &te;
+ ret = daAndPoints.first->event(&te) || ret;
+ } else {
+ qCDebug(lcPtr) << daAndPoints.first << "shall now receive" << pe;
+ ret = daAndPoints.first->event(pe) || ret;
+ }
+ if (pe->isAccepted())
+ break;
+ }
+
+ if (ret)
+ return true;
+ } else {
+ for (const auto &pt : pe->points()) {
+ if (pt.state() == QEventPoint::Pressed)
+ pe->clearPassiveGrabbers(pt);
}
- QMutableTouchEvent te(eventType, pe->pointingDevice(), pe->modifiers(), daAndPoints.second);
- te.setTimestamp(pe->timestamp());
- te.accept();
- qCDebug(lcTouch) << "subscene touch:" << daAndPoints.first << "shall now receive" << &te;
- ret = daAndPoints.first->event(&te) || ret;
- }
- if (ret)
- return true;
- } else if (pe->pointCount()) {
- // single-point event
- const auto &pt = pe->points().first();
- if (pt.state() == QEventPoint::Pressed)
- pe->clearPassiveGrabbers(pt);
- // it would be nice to just use "else" here, but
- // isBeginEvent() is not quite the same check as pt.state() != Pressed
- if (!pe->isBeginEvent()) {
- if (auto *ptda = QQuickDeliveryAgent::grabberAgent(pe, pe->points().first()))
- da = ptda;
}
}
- // else if it has no points, it's probably a TouchCancel, and DeliveryAgent needs to handle it.
+
+ // If it has no points, it's probably a TouchCancel, and DeliveryAgent needs to handle it.
+ // If we didn't handle it in the block above, handle it now.
// TODO should we deliver to all DAs at once then, since we don't know which one should get it?
// or fix QTBUG-90851 so that the event always has points?
- if (da && da->event(e))
+ bool ret = (da && da->event(e));
+
+ // failsafe: never allow any kind of grab to persist after release
+ if (pe->isEndEvent()) {
+ if (pe->isSinglePointEvent()) {
+ if (static_cast<QSinglePointEvent *>(pe)->buttons() == Qt::NoButton) {
+ auto &firstPt = pe->point(0);
+ pe->setExclusiveGrabber(firstPt, nullptr);
+ pe->clearPassiveGrabbers(firstPt);
+ }
+ } else {
+ for (auto &point : pe->points()) {
+ if (point.state() == QEventPoint::State::Released) {
+ pe->setExclusiveGrabber(point, nullptr);
+ pe->clearPassiveGrabbers(point);
+ }
+ }
+ }
+ }
+
+ if (ret)
return true;
} else if (e->isInputEvent()) {
if (da && da->event(e))
diff --git a/src/quick/util/qquickdeliveryagent.cpp b/src/quick/util/qquickdeliveryagent.cpp
index 673bc1a009..a38ac410d4 100644
--- a/src/quick/util/qquickdeliveryagent.cpp
+++ b/src/quick/util/qquickdeliveryagent.cpp
@@ -70,6 +70,9 @@ Q_LOGGING_CATEGORY(lcFocus, "qt.quick.focus")
extern Q_GUI_EXPORT bool qt_sendShortcutOverrideEvent(QObject *o, ulong timestamp, int k, Qt::KeyboardModifiers mods, const QString &text = QString(), bool autorep = false, ushort count = 1);
+bool QQuickDeliveryAgentPrivate::subsceneAgentsExist(false);
+QQuickDeliveryAgent *QQuickDeliveryAgentPrivate::currentEventDeliveryAgent(nullptr);
+
void QQuickDeliveryAgentPrivate::touchToMouseEvent(QEvent::Type type, const QEventPoint &p, const QTouchEvent *touchEvent, QMutableSinglePointEvent *mouseEvent)
{
Q_ASSERT(QCoreApplication::testAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents));
@@ -267,6 +270,7 @@ bool QQuickDeliveryAgentPrivate::deliverTouchAsMouse(QQuickItem *item, QTouchEve
*/
void QQuickDeliveryAgentPrivate::removeGrabber(QQuickItem *grabber, bool mouse, bool touch, bool cancel)
{
+ Q_Q(QQuickDeliveryAgent);
if (eventsInDelivery.isEmpty()) {
// do it the expensive way
for (auto dev : knownPointingDevices) {
@@ -278,7 +282,7 @@ void QQuickDeliveryAgentPrivate::removeGrabber(QQuickItem *grabber, bool mouse,
auto eventInDelivery = eventsInDelivery.top();
if (Q_LIKELY(mouse) && eventInDelivery) {
auto epd = mousePointData();
- if (epd && epd->exclusiveGrabber == grabber) {
+ if (epd && epd->exclusiveGrabber == grabber && epd->exclusiveGrabberContext.data() == q) {
QQuickItem *oldGrabber = qobject_cast<QQuickItem *>(epd->exclusiveGrabber);
qCDebug(lcMouseTarget) << "removeGrabber" << oldGrabber << "-> null";
eventInDelivery->setExclusiveGrabber(epd->eventPoint, nullptr);
@@ -639,21 +643,6 @@ QQuickDeliveryAgent::Transform::~Transform()
{
}
-/*! \internal
- Returns the QQuickDeliveryAgent instance that we remember was delivering the
- given \a pt at the time that it was grabbed. Failing that, choose a suitable agent.
-*/
-QQuickDeliveryAgent *QQuickDeliveryAgent::grabberAgent(QPointerEvent *pe, const QEventPoint &pt)
-{
- auto devExtra = QQuickDeliveryAgentPrivate::deviceExtra(pe->device());
- QQuickDeliveryAgent *ret = devExtra->grabbedEventPointDeliveryAgents.value(pt.id());
- if (ret) {
- qCDebug(lcPtr) << pe->type() << "point" << pt.id() << pt.state()
- << "@" << pt.scenePosition() << "will be re-delivered via known agent" << ret;
- }
- return ret;
-}
-
QQuickItem *QQuickDeliveryAgent::rootItem() const
{
Q_D(const QQuickDeliveryAgent);
@@ -678,6 +667,8 @@ void QQuickDeliveryAgent::setSceneTransform(QQuickDeliveryAgent::Transform *tran
bool QQuickDeliveryAgent::event(QEvent *ev)
{
Q_D(QQuickDeliveryAgent);
+ d->currentEventDeliveryAgent = this;
+ auto cleanup = qScopeGuard([d] { d->currentEventDeliveryAgent = nullptr; });
switch (ev->type()) {
case QEvent::MouseButtonPress:
@@ -843,23 +834,12 @@ QQuickDeliveryAgentPrivate::QQuickDeliveryAgentPrivate(QQuickItem *root) :
#if QT_CONFIG(quick_draganddrop)
dragGrabber = new QQuickDragGrabber;
#endif
+ if (isSubsceneAgent)
+ subsceneAgentsExist = true;
}
QQuickDeliveryAgentPrivate::~QQuickDeliveryAgentPrivate()
{
- Q_Q(QQuickDeliveryAgent);
- for (auto dev : knownPointingDevices) {
- auto devPriv = QPointingDevicePrivate::get(dev);
- if (devPriv->qqExtra) {
- auto &flatmap = static_cast<QQuickPointingDeviceExtra *>(devPriv->qqExtra)->grabbedEventPointDeliveryAgents;
- for (auto it = flatmap.begin(); it != flatmap.end(); ) {
- if (it.value() == q)
- it = flatmap.erase(it);
- else
- ++it;
- }
- }
- }
#if QT_CONFIG(quick_draganddrop)
delete dragGrabber;
dragGrabber = nullptr;
@@ -1094,6 +1074,7 @@ void QQuickDeliveryAgentPrivate::deliverDelayedTouchEvent()
*/
void QQuickDeliveryAgentPrivate::handleWindowDeactivate(QQuickWindow *win)
{
+ Q_Q(QQuickDeliveryAgent);
qCDebug(lcFocus) << "deactivated" << win->title();
const auto inputDevices = QInputDevice::devices();
for (auto device : inputDevices) {
@@ -1105,7 +1086,7 @@ void QQuickDeliveryAgentPrivate::handleWindowDeactivate(QQuickWindow *win)
if (QQuickItem *item = qmlobject_cast<QQuickItem *>(epd.exclusiveGrabber.data()))
relevant = (item->window() == win);
else if (QQuickPointerHandler *handler = qmlobject_cast<QQuickPointerHandler *>(epd.exclusiveGrabber.data()))
- relevant = (handler->parentItem()->window() == win);
+ relevant = (handler->parentItem()->window() == win && epd.exclusiveGrabberContext.data() == q);
if (relevant)
devPriv->setExclusiveGrabber(nullptr, epd.eventPoint, nullptr);
}
@@ -1421,19 +1402,21 @@ void QQuickDeliveryAgentPrivate::onGrabChanged(QObject *grabber, QPointingDevice
const bool grabGained = (transition == QPointingDevice::GrabTransition::GrabExclusive ||
transition == QPointingDevice::GrabTransition::GrabPassive);
- QQuickDeliveryAgent *subsceneAgent = nullptr;
+ QQuickDeliveryAgent *deliveryAgent = nullptr;
// note: event can be null, if the signal was emitted from QPointingDevicePrivate::removeGrabber(grabber)
if (auto *handler = qmlobject_cast<QQuickPointerHandler *>(grabber)) {
- handler->onGrabChanged(handler, transition, const_cast<QPointerEvent *>(event),
- const_cast<QEventPoint &>(point));
- if (isSubsceneAgent) {
- auto itemPriv = QQuickItemPrivate::get(handler->parentItem());
+ auto itemPriv = QQuickItemPrivate::get(handler->parentItem());
+ deliveryAgent = itemPriv->deliveryAgent();
+ if (deliveryAgent == q) {
+ handler->onGrabChanged(handler, transition, const_cast<QPointerEvent *>(event),
+ const_cast<QEventPoint &>(point));
+ }
+ if (grabGained) {
// An item that is NOT a subscene root needs to track whether it got a grab via a subscene delivery agent,
// whereas the subscene root item already knows it has its own DA.
- if (grabGained && (!itemPriv->extra.isAllocated() || !itemPriv->extra->subsceneDeliveryAgent))
+ if (isSubsceneAgent && (!itemPriv->extra.isAllocated() || !itemPriv->extra->subsceneDeliveryAgent))
itemPriv->maybeHasSubsceneDeliveryAgent = true;
- subsceneAgent = itemPriv->deliveryAgent();
}
} else {
switch (transition) {
@@ -1471,32 +1454,39 @@ void QQuickDeliveryAgentPrivate::onGrabChanged(QObject *grabber, QPointingDevice
break;
}
auto grabberItem = static_cast<QQuickItem *>(grabber); // cannot be a handler: we checked above
- if (isSubsceneAgent && grabberItem) {
+ if (grabberItem) {
auto itemPriv = QQuickItemPrivate::get(grabberItem);
+ deliveryAgent = itemPriv->deliveryAgent();
// An item that is NOT a subscene root needs to track whether it got a grab via a subscene delivery agent,
// whereas the subscene root item already knows it has its own DA.
- if (grabGained && (!itemPriv->extra.isAllocated() || !itemPriv->extra->subsceneDeliveryAgent))
+ if (isSubsceneAgent && grabGained && (!itemPriv->extra.isAllocated() || !itemPriv->extra->subsceneDeliveryAgent))
itemPriv->maybeHasSubsceneDeliveryAgent = true;
- subsceneAgent = itemPriv->deliveryAgent();
}
}
- if (subsceneAgent == q && event && event->device()) {
- auto devExtra = QQuickDeliveryAgentPrivate::deviceExtra(event->device());
- QFlatMap<int, QQuickDeliveryAgent*> &agentMap = devExtra->grabbedEventPointDeliveryAgents;
- // workaround for QFlatMap error: somehow having a local copy of id makes insert() happy (move semantics?) otherwise we get
- // no matching function for call to ‘QList<int>::insert(QFlatMap<int, QQuickDeliveryAgent*>::iterator&, std::remove_reference<int&>::type)’
- const int id = point.id();
- if (grabGained) {
- // If any grab is gained while a subscene agent is delivering an event,
- // the same agent should keep delivering all subsequent events containing that QEventPoint.
- qCDebug(lcPtr) << "remembering that" << q << "handles point" << id << "after" << transition;
- agentMap.insert(id, q);
- } else if (!event->exclusiveGrabber(point) && event->passiveGrabbers(point).isEmpty()) {
- // If all grabs are lost, we can forget the fact that a particular agent was handling a particular point.
- // If the event point ID appears again in a later event, it will be delivered via the main window's delivery agent by default.
- qCDebug(lcPtr) << "dissociating" << q << "from point" << id << "after" << transition;
- agentMap.remove(id);
+ if (currentEventDeliveryAgent == q && event && event->device()) {
+ auto epd = QPointingDevicePrivate::get(const_cast<QPointingDevice*>(event->pointingDevice()))->queryPointById(point.id());
+ Q_ASSERT(epd);
+ switch (transition) {
+ case QPointingDevice::GrabPassive: {
+ QPointingDevicePrivate::setPassiveGrabberContext(epd, grabber, q);
+ qCDebug(lcPtr) << "remembering that" << q << "handles point" << point.id() << "after" << transition;
+ } break;
+ case QPointingDevice::GrabExclusive:
+ epd->exclusiveGrabberContext = q;
+ qCDebug(lcPtr) << "remembering that" << q << "handles point" << point.id() << "after" << transition;
+ break;
+ case QPointingDevice::CancelGrabExclusive:
+ case QPointingDevice::UngrabExclusive:
+ // taken care of in QPointingDevicePrivate::setExclusiveGrabber(,,nullptr), removeExclusiveGrabber()
+ break;
+ case QPointingDevice::UngrabPassive:
+ case QPointingDevice::CancelGrabPassive:
+ // taken care of in QPointingDevicePrivate::removePassiveGrabber(), clearPassiveGrabbers()
+ break;
+ case QPointingDevice::OverrideGrabPassive:
+ // not in use at this time
+ break;
}
}
}
@@ -1557,27 +1547,9 @@ void QQuickDeliveryAgentPrivate::deliverPointerEvent(QPointerEvent *event)
if (event->isEndEvent())
deliverPressOrReleaseEvent(event, true);
- // failsafe: never allow any kind of grab or point-agent association to persist after release
- if (event->isEndEvent()) {
- auto &agentMap = QQuickDeliveryAgentPrivate::deviceExtra(event->device())->grabbedEventPointDeliveryAgents;
- if (isTouchEvent(event)) {
- for (int i = 0; i < event->pointCount(); ++i) {
- auto &point = event->point(i);
- if (point.state() == QEventPoint::State::Released) {
- event->setExclusiveGrabber(point, nullptr);
- event->clearPassiveGrabbers(point);
- agentMap.remove(point.id());
- }
- }
- // never allow touch->mouse synthesis to persist either
- cancelTouchMouseSynthesis();
- } else if (static_cast<QSinglePointEvent *>(event)->buttons() == Qt::NoButton) {
- auto &firstPt = event->point(0);
- event->setExclusiveGrabber(firstPt, nullptr);
- event->clearPassiveGrabbers(firstPt);
- agentMap.remove(firstPt.id());
- }
- }
+ // failsafe: never allow touch->mouse synthesis to persist after release
+ if (event->isEndEvent() && isTouchEvent(event))
+ cancelTouchMouseSynthesis();
eventsInDelivery.pop();
if (sceneTransform) {
@@ -1668,6 +1640,7 @@ QVector<QQuickItem *> QQuickDeliveryAgentPrivate::mergePointerTargets(const QVec
*/
void QQuickDeliveryAgentPrivate::deliverUpdatedPoints(QPointerEvent *event)
{
+ Q_Q(const QQuickDeliveryAgent);
bool done = false;
const auto grabbers = exclusiveGrabbers(event);
hasFiltered.clear();
@@ -1693,8 +1666,20 @@ void QQuickDeliveryAgentPrivate::deliverUpdatedPoints(QPointerEvent *event)
}
// Deliver to each eventpoint's passive grabbers (but don't visit any handler more than once)
- for (auto &point : event->points())
- deliverToPassiveGrabbers(event->passiveGrabbers(point), event);
+ for (auto &point : event->points()) {
+ auto epd = QPointingDevicePrivate::get(event->pointingDevice())->queryPointById(point.id());
+ if (Q_UNLIKELY(!epd)) {
+ qWarning() << "point is not in activePoints" << point;
+ continue;
+ }
+ QList<QPointer<QObject>> relevantPassiveGrabbers;
+ for (int i = 0; i < epd->passiveGrabbersContext.count(); ++i) {
+ if (epd->passiveGrabbersContext.at(i).data() == q)
+ relevantPassiveGrabbers << epd->passiveGrabbers.at(i);
+ }
+ if (!relevantPassiveGrabbers.isEmpty())
+ deliverToPassiveGrabbers(relevantPassiveGrabbers, event);
+ }
if (done)
return;
diff --git a/src/quick/util/qquickdeliveryagent_p.h b/src/quick/util/qquickdeliveryagent_p.h
index 41b3a5390b..9b73d9b9b9 100644
--- a/src/quick/util/qquickdeliveryagent_p.h
+++ b/src/quick/util/qquickdeliveryagent_p.h
@@ -79,8 +79,6 @@ public:
explicit QQuickDeliveryAgent(QQuickItem *rootItem);
virtual ~QQuickDeliveryAgent();
- static QQuickDeliveryAgent *grabberAgent(QPointerEvent *pe, const QEventPoint &pt);
-
QQuickItem *rootItem() const;
void setSceneTransform(Transform *transform);
diff --git a/src/quick/util/qquickdeliveryagent_p_p.h b/src/quick/util/qquickdeliveryagent_p_p.h
index faf7f6318f..ad1eece36e 100644
--- a/src/quick/util/qquickdeliveryagent_p_p.h
+++ b/src/quick/util/qquickdeliveryagent_p_p.h
@@ -72,9 +72,6 @@ class QQuickWindow;
struct QQuickPointingDeviceExtra {
// used in QQuickPointerHandlerPrivate::deviceDeliveryTargets
QVector<QObject *> deliveryTargets;
- // memory of which agent was delivering when each QEventPoint was grabbed
- // TODO maybe add QEventPointPrivate::qqExtra, or sth in QPointingDevicePrivate::EventPointData
- QFlatMap<int, QQuickDeliveryAgent*> grabbedEventPointDeliveryAgents;
};
class Q_QUICK_PRIVATE_EXPORT QQuickDeliveryAgentPrivate : public QObjectPrivate
@@ -121,6 +118,9 @@ public:
bool frameSynchronousHoverEnabled = true;
bool isSubsceneAgent = false;
+ static bool subsceneAgentsExist;
+ // QQuickDeliveryAgent::event() sets this to the one that's currently (trying to) handle the event
+ static QQuickDeliveryAgent *currentEventDeliveryAgent;
Qt::FocusReason lastFocusReason = Qt::OtherFocusReason;
int pointerEventRecursionGuard = 0;