diff options
author | Richard Moe Gustavsen <richard.gustavsen@qt.io> | 2021-02-25 17:43:36 +0100 |
---|---|---|
committer | Shawn Rutledge <shawn.rutledge@qt.io> | 2021-07-01 20:24:06 +0200 |
commit | bbcc2657fa0dbf715e6db7d675662e4be94a1e04 (patch) | |
tree | 4260c416ba53668b00e90666b86c4155b49fee4e /src/quick/util/qquickdeliveryagent_p_p.h | |
parent | 9d9ebbff2fa8735f749322300a43e1f161129480 (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.h | 7 |
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); |