aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard Moe Gustavsen <richard.gustavsen@qt.io>2022-03-16 13:14:38 +0100
committerRichard Moe Gustavsen <richard.gustavsen@qt.io>2022-04-03 07:11:50 +0000
commit21b0c3ed9f4a94bdd843c3be1bb95e7d96246f6c (patch)
tree1fe7ad56eb4e263ecbe56f8b0cc4c554ec7e030c
parent55ac0e04f5a8fe403a393a70c0dc53f8a5998bee (diff)
QQuickDeliverAgent: don't propagate hover to siblings
From testing Qt 6.1, hover events should not propagate between siblings. As soon as a leaf item is found that receives a hover events, the event should only propagate up the parent chain starting from the leaf item. Change-Id: I7448f5322f529addb2260b0ee2b02d2cfadb55e1 Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Mitch Curtis <mitch.curtis@qt.io> Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io> (cherry picked from commit 499828b855d125ac236917f6ed01d8f1e7d88505) Reviewed-by: Richard Moe Gustavsen <richard.gustavsen@qt.io>
-rw-r--r--src/quick/util/qquickdeliveryagent.cpp13
-rw-r--r--src/quick/util/qquickdeliveryagent_p_p.h1
-rw-r--r--tests/auto/quick/pointerhandlers/qquickhoverhandler/BLACKLIST8
-rw-r--r--tests/auto/quick/pointerhandlers/qquickhoverhandler/tst_qquickhoverhandler.cpp8
-rw-r--r--tests/auto/quick/qquickdeliveryagent/tst_qquickdeliveryagent.cpp91
5 files changed, 109 insertions, 12 deletions
diff --git a/src/quick/util/qquickdeliveryagent.cpp b/src/quick/util/qquickdeliveryagent.cpp
index 36f1128a39..20faa23a09 100644
--- a/src/quick/util/qquickdeliveryagent.cpp
+++ b/src/quick/util/qquickdeliveryagent.cpp
@@ -990,6 +990,7 @@ bool QQuickDeliveryAgentPrivate::deliverHoverEvent(
// list at the end of this function and look for items with an old hoverId,
// remove them from the list, and update their state accordingly.
currentHoverId++;
+ hoveredLeafItemFound = false;
const bool itemsWasHovered = !hoverItems.isEmpty();
deliverHoverEventRecursive(rootItem, scenePos, lastScenePos, modifiers, timestamp);
@@ -1037,6 +1038,11 @@ bool QQuickDeliveryAgentPrivate::deliverHoverEvent(
end up as the only one hovered. Any other HoverHandler that may be a child
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.
+
+ 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.
*/
bool QQuickDeliveryAgentPrivate::deliverHoverEventRecursive(
QQuickItem *item, const QPointF &scenePos, const QPointF &lastScenePos,
@@ -1066,6 +1072,10 @@ bool QQuickDeliveryAgentPrivate::deliverHoverEventRecursive(
// Stop propagation / recursion
return true;
}
+ if (hoveredLeafItemFound) {
+ // Don't propagate to siblings, only to ancestors
+ break;
+ }
}
// All decendants have been visited.
@@ -1098,6 +1108,9 @@ 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) {
diff --git a/src/quick/util/qquickdeliveryagent_p_p.h b/src/quick/util/qquickdeliveryagent_p_p.h
index 3e551beb27..b962864103 100644
--- a/src/quick/util/qquickdeliveryagent_p_p.h
+++ b/src/quick/util/qquickdeliveryagent_p_p.h
@@ -120,6 +120,7 @@ public:
bool allowChildEventFiltering = true;
bool allowDoubleClick = true;
bool frameSynchronousHoverEnabled = true;
+ bool hoveredLeafItemFound = false;
bool isSubsceneAgent = false;
static bool subsceneAgentsExist;
diff --git a/tests/auto/quick/pointerhandlers/qquickhoverhandler/BLACKLIST b/tests/auto/quick/pointerhandlers/qquickhoverhandler/BLACKLIST
index 62a6c67407..c815c0baf9 100644
--- a/tests/auto/quick/pointerhandlers/qquickhoverhandler/BLACKLIST
+++ b/tests/auto/quick/pointerhandlers/qquickhoverhandler/BLACKLIST
@@ -1,10 +1,2 @@
[movingItemWithHoverHandler]
macos # Can't move cursor (QTBUG-76312)
-
-# QTBUG-98492
-[mouseAreaAndUnderlyingHoverHandler]
-macos
-
-# QTBUG-98492
-[hoverHandlerAndUnderlyingMouseArea]
-macos
diff --git a/tests/auto/quick/pointerhandlers/qquickhoverhandler/tst_qquickhoverhandler.cpp b/tests/auto/quick/pointerhandlers/qquickhoverhandler/tst_qquickhoverhandler.cpp
index b26a055e60..d4ce666c4d 100644
--- a/tests/auto/quick/pointerhandlers/qquickhoverhandler/tst_qquickhoverhandler.cpp
+++ b/tests/auto/quick/pointerhandlers/qquickhoverhandler/tst_qquickhoverhandler.cpp
@@ -272,8 +272,8 @@ void tst_HoverHandler::hoverHandlerAndUnderlyingMouseArea()
#endif
QTest::mouseMove(window, buttonCenter);
- QCOMPARE(bottomSidebarMA->hovered(), true);
- QCOMPARE(sidebarHoveredSpy.count(), 1);
+ QCOMPARE(bottomSidebarMA->hovered(), false);
+ QCOMPARE(sidebarHoveredSpy.count(), 2);
QCOMPARE(buttonHH->isHovered(), true);
QCOMPARE(buttonHoveredSpy.count(), 1);
#if QT_CONFIG(cursor)
@@ -282,7 +282,7 @@ void tst_HoverHandler::hoverHandlerAndUnderlyingMouseArea()
QTest::mouseMove(window, rightOfButton);
QCOMPARE(bottomSidebarMA->hovered(), true);
- QCOMPARE(sidebarHoveredSpy.count(), 1);
+ QCOMPARE(sidebarHoveredSpy.count(), 3);
QCOMPARE(buttonHH->isHovered(), false);
QCOMPARE(buttonHoveredSpy.count(), 2);
#if QT_CONFIG(cursor)
@@ -291,7 +291,7 @@ void tst_HoverHandler::hoverHandlerAndUnderlyingMouseArea()
QTest::mouseMove(window, outOfSidebar);
QCOMPARE(bottomSidebarMA->hovered(), false);
- QCOMPARE(sidebarHoveredSpy.count(), 2);
+ QCOMPARE(sidebarHoveredSpy.count(), 4);
QCOMPARE(buttonHH->isHovered(), false);
QCOMPARE(buttonHoveredSpy.count(), 2);
#if QT_CONFIG(cursor)
diff --git a/tests/auto/quick/qquickdeliveryagent/tst_qquickdeliveryagent.cpp b/tests/auto/quick/qquickdeliveryagent/tst_qquickdeliveryagent.cpp
index 2de8f403d1..ac00cfede7 100644
--- a/tests/auto/quick/qquickdeliveryagent/tst_qquickdeliveryagent.cpp
+++ b/tests/auto/quick/qquickdeliveryagent/tst_qquickdeliveryagent.cpp
@@ -62,6 +62,26 @@ struct ViewportTransformHelper : public QQuickDeliveryAgent::Transform
}
};
+struct HoverItem : public QQuickItem
+{
+ HoverItem(QQuickItem *parent) : QQuickItem(parent){}
+ void hoverEnterEvent(QHoverEvent *e) override
+ {
+ hoverEnter = true;
+ e->setAccepted(block);
+ }
+
+ void hoverLeaveEvent(QHoverEvent *e) override
+ {
+ hoverLeave = true;
+ e->setAccepted(block);
+ }
+
+ bool hoverEnter = false;
+ bool hoverLeave = false;
+ bool block = false;
+};
+
// A QQuick3DViewport simulator
class SubsceneRootItem : public QQuickShaderEffectSource
{
@@ -135,6 +155,9 @@ private slots:
void passiveGrabberOrder();
void tapHandlerDoesntOverrideSubsceneGrabber();
void touchCompression();
+ void hoverPropagation_nested_data();
+ void hoverPropagation_nested();
+ void hoverPropagation_siblings();
private:
QScopedPointer<QPointingDevice> touchDevice = QScopedPointer<QPointingDevice>(QTest::createTouchDevice());
@@ -278,6 +301,74 @@ void tst_qquickdeliveryagent::touchCompression()
QCOMPARE(agentPriv->compressedTouchCount, 0);
}
+void tst_qquickdeliveryagent::hoverPropagation_nested_data()
+{
+ QTest::addColumn<bool>("block");
+ QTest::newRow("block=false") << false;
+ QTest::newRow("block=true") << true;
+}
+
+void tst_qquickdeliveryagent::hoverPropagation_nested()
+{
+ QFETCH(bool, block);
+
+ QQuickWindow window;
+ window.resize(200, 200);
+ window.show();
+ QVERIFY(QTest::qWaitForWindowActive(&window));
+
+ HoverItem child(window.contentItem());
+ child.setAcceptHoverEvents(true);
+ child.setWidth(100);
+ child.setHeight(100);
+
+ HoverItem grandChild(&child);
+ grandChild.setAcceptHoverEvents(true);
+ grandChild.block = block;
+ grandChild.setWidth(100);
+ grandChild.setHeight(100);
+
+ // Start by moving the mouse to the window
+ QTest::mouseMove(&window, QPoint(150, 150));
+ QCOMPARE(child.hoverEnter, false);
+ QCOMPARE(grandChild.hoverEnter, false);
+
+ // Move the mouse inside the items. If block is true, only
+ // the grandchild should be hovered. Otherwise both.
+ QTest::mouseMove(&window, QPoint(50, 50));
+ QCOMPARE(child.hoverEnter, !block);
+ QCOMPARE(grandChild.hoverEnter, true);
+}
+
+void tst_qquickdeliveryagent::hoverPropagation_siblings()
+{
+ QQuickWindow window;
+ window.resize(200, 200);
+ window.show();
+ QVERIFY(QTest::qWaitForWindowActive(&window));
+
+ HoverItem sibling1(window.contentItem());
+ sibling1.setAcceptHoverEvents(true);
+ sibling1.setWidth(100);
+ sibling1.setHeight(100);
+
+ HoverItem sibling2(window.contentItem());
+ sibling2.setAcceptHoverEvents(true);
+ sibling2.setWidth(100);
+ sibling2.setHeight(100);
+
+ // Start by moving the mouse to the window
+ QTest::mouseMove(&window, QPoint(150, 150));
+ QCOMPARE(sibling1.hoverEnter, false);
+ QCOMPARE(sibling2.hoverEnter, false);
+
+ // Move the mouse inside the items. Only the
+ // sibling on the top should receive hover
+ QTest::mouseMove(&window, QPoint(50, 50));
+ QCOMPARE(sibling1.hoverEnter, false);
+ QCOMPARE(sibling2.hoverEnter, true);
+}
+
QTEST_MAIN(tst_qquickdeliveryagent)
#include "tst_qquickdeliveryagent.moc"