aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick/util/qquickdeliveryagent.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/quick/util/qquickdeliveryagent.cpp')
-rw-r--r--src/quick/util/qquickdeliveryagent.cpp104
1 files changed, 74 insertions, 30 deletions
diff --git a/src/quick/util/qquickdeliveryagent.cpp b/src/quick/util/qquickdeliveryagent.cpp
index ed34fbe8cf..e027ef8fdf 100644
--- a/src/quick/util/qquickdeliveryagent.cpp
+++ b/src/quick/util/qquickdeliveryagent.cpp
@@ -82,6 +82,7 @@ void QQuickDeliveryAgentPrivate::touchToMouseEvent(QEvent::Type type, const QEve
(type == QEvent::MouseButtonRelease ? Qt::NoButton : Qt::LeftButton),
touchEvent->modifiers(), Qt::MouseEventSynthesizedByQt);
ret.setAccepted(true); // this now causes the persistent touchpoint to be accepted too
+ ret.setTimestamp(touchEvent->timestamp());
*mouseEvent = ret;
}
@@ -1024,10 +1025,11 @@ bool QQuickDeliveryAgentPrivate::deliverHoverEvent(
accepted, recursion stops. Returns \c true in that case, or \c false if the
event is rejected.
- All items that have hover enabled (either explicitly, from
- setAcceptHoverEvents(), or implicitly by having HoverHandlers) will have
- the QQuickItemPrivate::hoverEnabled flag set. And all their anchestors will
- have the QQuickItemPrivate::subtreeHoverEnabledset. This function will
+ Each item that has hover enabled (from setAcceptHoverEvents()) has the
+ QQuickItemPrivate::hoverEnabled flag set. This only controls whether we
+ should send hover events to the item itself. (HoverHandlers no longer set
+ this flag.) When an item has hoverEnabled set, all its ancestors have the
+ QQuickItemPrivate::subtreeHoverEnabled set. This function will
follow the subtrees that have subtreeHoverEnabled by recursing into each
child with that flag set. And for each child (in addition to the item
itself) that also has hoverEnabled set, we call deliverHoverEventToItem()
@@ -1039,10 +1041,19 @@ bool QQuickDeliveryAgentPrivate::deliverHoverEvent(
of an item that is stacked underneath, will not. Note that since siblings
can overlap, there can be more than one leaf item under the mouse.
+ Note that HoverHandler doesn't set the hoverEnabled flag on the parent item.
+ But still, adding a HoverHandler to an item will set its subtreeHoverEnabled flag.
+ So all the propagation logic described above will otherwise be the same.
+ But the hoverEnabled flag can be used to resolve if subtreeHoverEnabled is on
+ because the application explicitly requested it (setAcceptHoverEvents()), or
+ indirectly, because the item has HoverHandlers.
+
For legacy reasons (Qt 6.1), as soon as we find a leaf item that has hover
enabled, and therefore receives the event, we stop recursing into the remaining
siblings (even if the event was ignored). This means that we only allow hover
events to propagate up the direct parent-child hierarchy, and not to siblings.
+ However, if the first candidate HoverHandler is disabled, delivery continues
+ to the next one, which may be a sibling (QTBUG-106548).
*/
bool QQuickDeliveryAgentPrivate::deliverHoverEventRecursive(
QQuickItem *item, const QPointF &scenePos, const QPointF &lastScenePos,
@@ -1080,8 +1091,7 @@ bool QQuickDeliveryAgentPrivate::deliverHoverEventRecursive(
// All decendants have been visited.
// Now deliver the event to the item
- if (itemPrivate->hoverEnabled)
- return deliverHoverEventToItem(item, scenePos, lastScenePos, modifiers, timestamp, false);
+ return deliverHoverEventToItem(item, scenePos, lastScenePos, modifiers, timestamp, false);
// Continue propagation / recursion
return false;
@@ -1108,14 +1118,17 @@ bool QQuickDeliveryAgentPrivate::deliverHoverEventToItem(
qCDebug(lcHoverTrace) << "item:" << item << "scene pos:" << scenePos << "localPos:" << localPos
<< "wasHovering:" << wasHovering << "isHovering:" << isHovering;
- if (isHovering)
- hoveredLeafItemFound = true;
-
- // Send enter/move/leave event to the item
bool accepted = false;
- if (isHovering && !clearHover) {
+
+ // Start by sending out enter/move/leave events to the item.
+ // Note that hoverEnabled only controls if we should send out hover events to the
+ // item itself. HoverHandlers are not included, and are dealt with separately below.
+ if (itemPrivate->hoverEnabled && isHovering && !clearHover) {
// Add the item to the list of hovered items (if it doesn't exist there
// from before), and update hoverId to mark that it's (still) hovered.
+ // Also set hoveredLeafItemFound, so that only propagate in a straight
+ // line towards the root from now on.
+ hoveredLeafItemFound = true;
hoverItems[item] = currentHoverId;
if (wasHovering)
accepted = sendHoverEvent(QEvent::HoverMove, item, scenePos, lastScenePos, modifiers, timestamp);
@@ -1130,6 +1143,7 @@ bool QQuickDeliveryAgentPrivate::deliverHoverEventToItem(
if (!itemPrivate->hasPointerHandlers())
return accepted;
+ // Next, send out hover events to the hover handlers.
// If the item didn't accept the hover event, 'accepted' is now false.
// Otherwise it's true, and then it should stay the way regardless of
// whether or not the hoverhandlers themselves are hovered.
@@ -1143,6 +1157,8 @@ bool QQuickDeliveryAgentPrivate::deliverHoverEventToItem(
for (QQuickPointerHandler *h : itemPrivate->extra->pointerHandlers) {
if (QQuickHoverHandler *hh = qmlobject_cast<QQuickHoverHandler *>(h)) {
+ if (!hh->isHovered())
+ continue;
hoverEvent.setAccepted(true);
QCoreApplication::sendEvent(hh, &hoverEvent);
}
@@ -1153,11 +1169,14 @@ bool QQuickDeliveryAgentPrivate::deliverHoverEventToItem(
for (QQuickPointerHandler *h : itemPrivate->extra->pointerHandlers) {
if (QQuickHoverHandler *hh = qmlobject_cast<QQuickHoverHandler *>(h)) {
+ if (!hh->enabled())
+ continue;
hoverEvent.setAccepted(true);
hh->handlePointerEvent(&hoverEvent);
if (hh->isHovered()) {
// Mark the whole item as updated, even if only the handler is
// actually in a hovered state (because of HoverHandler.margins)
+ hoveredLeafItemFound = true;
hoverItems[item] = currentHoverId;
if (hh->isBlocking()) {
qCDebug(lcHoverTrace) << "skipping rest of hover delivery due to blocking" << hh;
@@ -1313,6 +1332,15 @@ bool QQuickDeliveryAgentPrivate::anyPointGrabbed(const QPointerEvent *ev)
return false;
}
+bool QQuickDeliveryAgentPrivate::allPointsGrabbed(const QPointerEvent *ev)
+{
+ for (const auto &point : ev->points()) {
+ if (!ev->exclusiveGrabber(point) && ev->passiveGrabbers(point).isEmpty())
+ return false;
+ }
+ return true;
+}
+
bool QQuickDeliveryAgentPrivate::isMouseEvent(const QPointerEvent *ev)
{
switch (ev->type()) {
@@ -1405,6 +1433,11 @@ QQuickPointingDeviceExtra *QQuickDeliveryAgentPrivate::deviceExtra(const QInputD
*/
bool QQuickDeliveryAgentPrivate::compressTouchEvent(QTouchEvent *event)
{
+ // If this is a subscene agent, don't store any events, because
+ // flushFrameSynchronousEvents() is only called on the window's DA.
+ if (isSubsceneAgent)
+ return false;
+
QEventPoint::States states = event->touchPointStates();
if (states.testFlag(QEventPoint::State::Pressed) || states.testFlag(QEventPoint::State::Released)) {
qCDebug(lcTouchCmprs) << "no compression" << event;
@@ -1536,8 +1569,7 @@ void QQuickDeliveryAgentPrivate::handleMouseEvent(QMouseEvent *event)
case QEvent::MouseButtonDblClick:
Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMouseDoubleClick,
event->button(), event->buttons());
- if (allowDoubleClick)
- deliverPointerEvent(event);
+ deliverPointerEvent(event);
break;
case QEvent::MouseMove: {
Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMouseMove,
@@ -1913,7 +1945,7 @@ void QQuickDeliveryAgentPrivate::deliverUpdatedPoints(QPointerEvent *event)
return;
// If some points weren't grabbed, deliver only to non-grabber PointerHandlers in reverse paint order
- if (!event->allPointsGrabbed()) {
+ if (!allPointsGrabbed(event)) {
QVector<QQuickItem *> targetItems;
for (auto &point : event->points()) {
// Presses were delivered earlier; not the responsibility of deliverUpdatedTouchPoints.
@@ -1933,7 +1965,7 @@ void QQuickDeliveryAgentPrivate::deliverUpdatedPoints(QPointerEvent *event)
QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
localizePointerEvent(event, item);
itemPrivate->handlePointerEvent(event, true); // avoid re-delivering to grabbers
- if (event->allPointsGrabbed())
+ if (allPointsGrabbed(event))
break;
}
}
@@ -2017,11 +2049,9 @@ void QQuickDeliveryAgentPrivate::deliverMatchingPointsToItem(QQuickItem *item, b
// Let the Item's handlers (if any) have the event first.
// However, double click should never be delivered to handlers.
- if (pointerEvent->type() != QEvent::MouseButtonDblClick) {
- bool wasAccepted = pointerEvent->allPointsAccepted();
+ if (pointerEvent->type() != QEvent::MouseButtonDblClick)
itemPrivate->handlePointerEvent(pointerEvent);
- allowDoubleClick = wasAccepted || !(isMouse && pointerEvent->isBeginEvent() && pointerEvent->allPointsAccepted());
- }
+
if (handlersOnly)
return;
@@ -2154,6 +2184,7 @@ void QQuickDeliveryAgentPrivate::deliverDragEvent(QQuickDragGrabber *grabber, QE
QDragLeaveEvent leaveEvent;
for (; grabItem != grabber->end(); grabItem = grabber->release(grabItem))
QCoreApplication::sendEvent(**grabItem, &leaveEvent);
+ grabber->ignoreList().clear();
return;
} else {
QDragMoveEvent *moveEvent = static_cast<QDragMoveEvent *>(event);
@@ -2211,6 +2242,8 @@ void QQuickDeliveryAgentPrivate::deliverDragEvent(QQuickDragGrabber *grabber, QE
e->modifiers());
QQuickDropEventEx::copyActions(&enterEvent, *e);
event->setAccepted(deliverDragEvent(grabber, rootItem, &enterEvent));
+ } else {
+ grabber->ignoreList().clear();
}
}
@@ -2224,8 +2257,13 @@ bool QQuickDeliveryAgentPrivate::deliverDragEvent(
QPointF p = item->mapFromScene(event->position().toPoint());
bool itemContained = item->contains(p);
- if (!itemContained && itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) {
- return false;
+ const int itemIndex = grabber->ignoreList().indexOf(item);
+ if (!itemContained) {
+ if (itemIndex >= 0)
+ grabber->ignoreList().remove(itemIndex);
+
+ if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape)
+ return false;
}
QDragEnterEvent enterEvent(
@@ -2255,15 +2293,19 @@ bool QQuickDeliveryAgentPrivate::deliverDragEvent(
}
if (event->type() == QEvent::DragMove || itemPrivate->flags & QQuickItem::ItemAcceptsDrops) {
- if (event->type() == QEvent::DragEnter && formerTarget) {
- QQuickItem *formerTargetItem = qobject_cast<QQuickItem *>(formerTarget);
- if (formerTargetItem && currentGrabItems) {
- QDragLeaveEvent leaveEvent;
- QCoreApplication::sendEvent(formerTarget, &leaveEvent);
-
- // Remove the item from the currentGrabItems so a leave event won't be generated
- // later on
- currentGrabItems->removeAll(formerTarget);
+ if (event->type() == QEvent::DragEnter) {
+ if (formerTarget) {
+ QQuickItem *formerTargetItem = qobject_cast<QQuickItem *>(formerTarget);
+ if (formerTargetItem && currentGrabItems) {
+ QDragLeaveEvent leaveEvent;
+ QCoreApplication::sendEvent(formerTarget, &leaveEvent);
+
+ // Remove the item from the currentGrabItems so a leave event won't be generated
+ // later on
+ currentGrabItems->removeAll(formerTarget);
+ }
+ } else if (itemIndex >= 0) {
+ return false;
}
}
@@ -2279,6 +2321,8 @@ bool QQuickDeliveryAgentPrivate::deliverDragEvent(
grabber->grab(item);
grabber->setTarget(item);
return true;
+ } else if (itemIndex < 0) {
+ grabber->ignoreList().append(item);
}
} else {
return true;