From fb23d24e0f3d875d5451336b351ac5a9ef641ca2 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Tue, 13 Apr 2021 22:21:36 +0200 Subject: Clear passive grabbers on press in QQWindow not in DeliveryAgent In case the window's main scene and a subscene both contain handlers, and one of the handlers in the main scene takes a passive grab on press, we don't want to lose it while we are delivering to the subscene. For example in Qt Quick 3D's dynamictexture example, if you click on one of the doors, the TapHandler in the View3D grabs on press; but the door also has a 2D subscene, which allows dragging (either dragging one yellow note item, or flicking the ListView). If you drag, the TapHandler does not detect a tap; if you tap, nothing gets dragged. So this is an example of a cooperative scenario involving multiple DeliveryAgents at the same time: a passive grab can occur in the main scene, an exclusive grab can occur in the subscene, and they don't interfere with each other. But if we clear the passive grab while delivering to the subscene, the TapHandler does not get a chance to detect a tap. So we should do that only once, when the window receives the press event. Amends 68c103225f4e8bd6c1b18ef547108fd60f398c0f Task-number: QTBUG-92944 Change-Id: I9f064764a17b1efe758909f61fca6658f65d43e5 Reviewed-by: Andy Nichols (cherry picked from commit 48b1c59b65332b773eb51d25c422b53dbd3d6762) Reviewed-by: Qt Cherry-pick Bot --- src/quick/items/qquickwindow.cpp | 15 ++++++++++++--- src/quick/util/qquickdeliveryagent.cpp | 2 -- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index 697e5b3410..58fa4cffa6 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -1367,6 +1367,8 @@ bool QQuickWindow::event(QEvent *e) if (!ptda) ptda = da; if (ptda) { + if (pt.state() == QEventPoint::Pressed) + pe->clearPassiveGrabbers(pt); auto danpit = deliveryAgentsNeedingPoints.find(ptda); if (danpit == deliveryAgentsNeedingPoints.end()) { deliveryAgentsNeedingPoints.insert(ptda, QList() << pt); @@ -1398,10 +1400,17 @@ bool QQuickWindow::event(QEvent *e) } if (ret) return true; - } else if (pe->pointCount() && !pe->isBeginEvent()) { + } else if (pe->pointCount()) { // single-point event - if (auto *ptda = QQuickDeliveryAgent::grabberAgent(pe, pe->points().first())) - da = ptda; + 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. // TODO should we deliver to all DAs at once then, since we don't know which one should get it? diff --git a/src/quick/util/qquickdeliveryagent.cpp b/src/quick/util/qquickdeliveryagent.cpp index 5c4b228dab..2fd5cab9a2 100644 --- a/src/quick/util/qquickdeliveryagent.cpp +++ b/src/quick/util/qquickdeliveryagent.cpp @@ -1736,8 +1736,6 @@ bool QQuickDeliveryAgentPrivate::deliverPressOrReleaseEvent(QPointerEvent *event } for (int i = 0; i < event->pointCount(); ++i) { auto &point = event->point(i); - if (point.state() == QEventPoint::Pressed) - event->clearPassiveGrabbers(point); QVector targetItemsForPoint = pointerTargets(rootItem, event, point, !isTouch, isTouch); if (targetItems.count()) { targetItems = mergePointerTargets(targetItems, targetItemsForPoint); -- cgit v1.2.3