aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick/util/qquickdeliveryagent_p_p.h
diff options
context:
space:
mode:
authorRichard Moe Gustavsen <richard.gustavsen@qt.io>2021-02-25 17:43:36 +0100
committerShawn Rutledge <shawn.rutledge@qt.io>2021-07-01 20:24:06 +0200
commitbbcc2657fa0dbf715e6db7d675662e4be94a1e04 (patch)
tree4260c416ba53668b00e90666b86c4155b49fee4e /src/quick/util/qquickdeliveryagent_p_p.h
parent9d9ebbff2fa8735f749322300a43e1f161129480 (diff)
QQuickHoverHandler: don't use passive grabs
QQuickDeliveryAgent will clear the list of passive grabbers when we deliver: 1. a QPointerEvent::isEndEvent() from deliverPointerEvent() 2. a QEventPoint::Pressed event from deliverPressOrReleaseEvent() In other words, QQuickDeliveryAgent will clear the list of grabbers whenever it receives a mouse press or release. This doesn't work well with hover handlers, which were using passive grabs to ensure receiving updates: they also lost their grabs on press and release. This has some implications: 1. the list of hover items (QQuickDeliveryAgentPrivate::hoverItems) will no longer be in sync with the items we deliver events to. 2. a hover handler stacked underneath another hover handler will stop working. The reason is that QQuickDeliveryAgent detects that hoverItems is not empty, and as such, assumes that all handlers will receive events from their passive grabs. (which is no longer the case after the clear) So letting hover handlers rely on passive grabbing currently fails. It was also confusing that we delivered some of the hover events from deliverHoverEvent(), and others from passive grabs in deliverPointerEvent(). In Qt Quick 3D, when the hover is delivered because of a passive grab, we need to use sceneTransform; but when picking is done, the transform was already done at the same time. But hover events that come from flushFrameSynchronousEvents() always need to go through picking, and that happens frequently, so it's more consistent if we just rely on it all the time. In addition, the previous solution was assuming that only one leaf item would be under the mouse. This fails when you have siblings that overlap (and each sibling has HoverHandlers). While we could try to be more careful about when, and which, grabbers we clear here and there from QQuickDeliveryAgent, it seems better to dodge the whole passive grabber logic for hover handlers, and instead send all hover events directly from deliverHoverEvent(). This because we anyway need to traverse all the items in the application on each pointer move to check if new items are being hovered. So we might as well send out hover events in the same go. That way the logic becomes a bit easier to follow, and don't need to worry about keeping the hoveredItems list in sync with passive grabbing. tst_qquickhoverhandler: hoverHandlerAndUnderlyingMouseArea: - HoverHandlers have (conceptually) never stopped hover events from propagating to the parent. Still, this test checks that a MouseArea underneath a HoverHandler is not hovered. Since this now actually works, the test is changed. mouseAreaAndUnderlyingHoverHandler: - MouseArea now accepts hover events, which will stop propagation. This is done to preserve the same behavior as before. But this also means that a MouseArea that has another MouseArea as a direct child (which was a special case from before) will no longer get hover events after the child has accepted them. For the same reason, an item's HoverHandlers will also not get hover events if there is a child that is accepting them, as in this test case. Fixes: QTBUG-34882 Fixes: QTBUG-63670 Pick-to: 6.2 Change-Id: Id38042bcbd1c3ca5403b4b81b875b84196fcfc76 Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
Diffstat (limited to 'src/quick/util/qquickdeliveryagent_p_p.h')
-rw-r--r--src/quick/util/qquickdeliveryagent_p_p.h7
1 files changed, 5 insertions, 2 deletions
diff --git a/src/quick/util/qquickdeliveryagent_p_p.h b/src/quick/util/qquickdeliveryagent_p_p.h
index 0d7d5fb71d..f9095158e8 100644
--- a/src/quick/util/qquickdeliveryagent_p_p.h
+++ b/src/quick/util/qquickdeliveryagent_p_p.h
@@ -105,13 +105,14 @@ public:
#endif
QQuickItem *lastUngrabbed = nullptr;
QStack<QPointerEvent *> eventsInDelivery;
- QList<QPointer<QQuickItem>> hoverItems;
+ QFlatMap<QPointer<QQuickItem>, uint> hoverItems;
QVector<QQuickItem *> hasFiltered; // during event delivery to a single receiver, the filtering parents for which childMouseEventFilter was already called
QVector<QQuickItem *> skipDelivery; // during delivery of one event to all receivers, Items to which we know delivery is no longer necessary
QScopedPointer<QMutableTouchEvent> delayedTouch;
QList<const QPointingDevice *> knownPointingDevices;
+ uint currentHoverId = 0;
#if QT_CONFIG(wheelevent)
uint lastWheelEventAccepted = 0;
#endif
@@ -189,7 +190,9 @@ public:
QVector<QQuickItem *> mergePointerTargets(const QVector<QQuickItem *> &list1, const QVector<QQuickItem *> &list2) const;
// hover delivery
- bool deliverHoverEvent(QQuickItem *, const QPointF &scenePos, const QPointF &lastScenePos, Qt::KeyboardModifiers modifiers, ulong timestamp, bool &accepted);
+ bool deliverHoverEvent(const QPointF &scenePos, const QPointF &lastScenePos, Qt::KeyboardModifiers modifiers, ulong timestamp);
+ bool deliverHoverEventRecursive(QQuickItem *, const QPointF &scenePos, const QPointF &lastScenePos, Qt::KeyboardModifiers modifiers, ulong timestamp);
+ bool deliverHoverEventToItem(QQuickItem *item, const QPointF &scenePos, const QPointF &lastScenePos, Qt::KeyboardModifiers modifiers, ulong timestamp, bool clearHover);
bool sendHoverEvent(QEvent::Type, QQuickItem *, const QPointF &scenePos, const QPointF &lastScenePos,
Qt::KeyboardModifiers modifiers, ulong timestamp);
bool clearHover(ulong timestamp = 0);