aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShawn Rutledge <shawn.rutledge@qt.io>2024-02-16 20:21:32 -0700
committerQt Cherry-pick Bot <cherrypick_bot@qt-project.org>2024-02-22 21:13:18 +0000
commit56c0a6f66e92a07e6427fd3b9ba0b6eed1934674 (patch)
treea7792ed3def106f2501f024384af1204d12bea5a
parent49e9a9a94269a6e70c2de5681584a241b2da3063 (diff)
HoverHandler: setHovered(false) for any pointer event outside bounds
8e822e981d91e688799c8670f11dfdf6aaf9e0d1 was expecting HoverHandler to receive a QTabletEvent when hover leaves. That worked before bbcc2657fa0dbf715e6db7d675662e4be94a1e04: a HoverHandler had a passive grab, so it would receive the next QTabletEvent that moved outside the item. Now that we stopped doing passive grabs, the event that indicates that the cursor is leaving the item is always a QMouseEvent sent from QQuickDeliveryAgentPrivate::deliverHoverEvent(). If the mouse event says the cursor is outside the item, it doesn't matter what device it came from: this handler is no longer hovered. But as before, if the position is still inside, and a particular HoverHandler is hovered because a tablet stylus was previously detected, do not un-hover merely because of a synth-mouse event at the same position. Amends 79893e1773be9d04208243cb88c1daf793d830a4 Fixes: QTBUG-116505 Task-number: QTBUG-101932 Pick-to: 6.5 Change-Id: Id0b622fad524ae4be8b37b9cb55e68384056964a Reviewed-by: Doris Verria <doris.verria@qt.io> Reviewed-by: Richard Moe Gustavsen <richard.gustavsen@qt.io> Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> (cherry picked from commit 5a762ba09cdeb8df5cf54ce562bc60dfcc11c97f) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org> (cherry picked from commit 688bd00cc7e8ad173fb007cd07a593a01a049098)
-rw-r--r--src/quick/handlers/qquickhoverhandler.cpp5
-rw-r--r--tests/auto/quick/pointerhandlers/qquickhoverhandler/data/hoverDeviceCursors.qml80
-rw-r--r--tests/auto/quick/pointerhandlers/qquickhoverhandler/tst_qquickhoverhandler.cpp11
3 files changed, 57 insertions, 39 deletions
diff --git a/src/quick/handlers/qquickhoverhandler.cpp b/src/quick/handlers/qquickhoverhandler.cpp
index 1643f89fea..c6dbd46e0b 100644
--- a/src/quick/handlers/qquickhoverhandler.cpp
+++ b/src/quick/handlers/qquickhoverhandler.cpp
@@ -145,7 +145,8 @@ bool QQuickHoverHandler::wantsPointerEvent(QPointerEvent *event)
if (event->isSinglePointEvent() && static_cast<QSinglePointEvent *>(event)->button())
return false;
auto &point = event->point(0);
- if (QQuickPointerDeviceHandler::wantsPointerEvent(event) && wantsEventPoint(event, point) && parentContains(point)) {
+ const bool inside = parentContains(point);
+ if (QQuickPointerDeviceHandler::wantsPointerEvent(event) && wantsEventPoint(event, point) && inside) {
// assume this is a mouse or tablet event, so there's only one point
setPointId(point.id());
return true;
@@ -162,7 +163,7 @@ bool QQuickHoverHandler::wantsPointerEvent(QPointerEvent *event)
// But after kCursorOverrideTimeout ms, QQuickItemPrivate::effectiveCursorHandler()
// will ignore it, just in case there is no QQuickPointerTabletEvent to unset it.
// For example, a tablet proximity leave event could occur, but we don't deliver it to the window.
- if (!(m_hoveredTablet && QQuickDeliveryAgentPrivate::isMouseEvent(event)))
+ if (!inside || !(m_hoveredTablet && QQuickDeliveryAgentPrivate::isMouseEvent(event)))
setHovered(false);
return false;
diff --git a/tests/auto/quick/pointerhandlers/qquickhoverhandler/data/hoverDeviceCursors.qml b/tests/auto/quick/pointerhandlers/qquickhoverhandler/data/hoverDeviceCursors.qml
index edb56ffdc6..48e130a35e 100644
--- a/tests/auto/quick/pointerhandlers/qquickhoverhandler/data/hoverDeviceCursors.qml
+++ b/tests/auto/quick/pointerhandlers/qquickhoverhandler/data/hoverDeviceCursors.qml
@@ -3,47 +3,53 @@ import QtQuick
Item {
width: 200; height: 200
- HoverHandler {
- objectName: "stylus"
- acceptedDevices: PointerDevice.Stylus
- acceptedPointerTypes: PointerDevice.Pen
- cursorShape: Qt.CrossCursor
- }
+ Rectangle {
+ width: 100; height: 100
+ anchors.centerIn: parent
+ border.color: "black"
- HoverHandler {
- objectName: "stylus eraser"
- acceptedDevices: PointerDevice.Stylus
- acceptedPointerTypes: PointerDevice.Eraser
- cursorShape: Qt.PointingHandCursor
- }
+ HoverHandler {
+ objectName: "stylus"
+ acceptedDevices: PointerDevice.Stylus
+ acceptedPointerTypes: PointerDevice.Pen
+ cursorShape: Qt.CrossCursor
+ }
- HoverHandler {
- objectName: "airbrush"
- acceptedDevices: PointerDevice.Airbrush
- acceptedPointerTypes: PointerDevice.Pen
- cursorShape: Qt.BusyCursor
- }
+ HoverHandler {
+ objectName: "stylus eraser"
+ acceptedDevices: PointerDevice.Stylus
+ acceptedPointerTypes: PointerDevice.Eraser
+ cursorShape: Qt.PointingHandCursor
+ }
- HoverHandler {
- objectName: "airbrush eraser"
- acceptedDevices: PointerDevice.Airbrush
- acceptedPointerTypes: PointerDevice.Eraser
- cursorShape: Qt.OpenHandCursor
- }
+ HoverHandler {
+ objectName: "airbrush"
+ acceptedDevices: PointerDevice.Airbrush
+ acceptedPointerTypes: PointerDevice.Pen
+ cursorShape: Qt.BusyCursor
+ }
- HoverHandler {
- objectName: "mouse"
- acceptedDevices: PointerDevice.Mouse
- // acceptedPointerTypes can be omitted because Mouse is not ambiguous.
- // When a genuine mouse move is sent, there's a conflict, and this one should win.
- cursorShape: Qt.IBeamCursor
- }
+ HoverHandler {
+ objectName: "airbrush eraser"
+ acceptedDevices: PointerDevice.Airbrush
+ acceptedPointerTypes: PointerDevice.Eraser
+ cursorShape: Qt.OpenHandCursor
+ }
+
+ HoverHandler {
+ objectName: "mouse"
+ acceptedDevices: PointerDevice.Mouse
+ // acceptedPointerTypes can be omitted because Mouse is not ambiguous.
+ // When a genuine mouse move is sent, there's a conflict, and this one should win.
+ cursorShape: Qt.IBeamCursor
+ }
- HoverHandler {
- objectName: "conflictingMouse"
- acceptedDevices: PointerDevice.Mouse
- // acceptedPointerTypes can be omitted because Mouse is not ambiguous.
- // When a genuine mouse move is sent, there's a conflict, and this one should lose.
- cursorShape: Qt.ClosedHandCursor
+ HoverHandler {
+ objectName: "conflictingMouse"
+ acceptedDevices: PointerDevice.Mouse
+ // acceptedPointerTypes can be omitted because Mouse is not ambiguous.
+ // When a genuine mouse move is sent, there's a conflict, and this one should lose.
+ cursorShape: Qt.ClosedHandCursor
+ }
}
}
diff --git a/tests/auto/quick/pointerhandlers/qquickhoverhandler/tst_qquickhoverhandler.cpp b/tests/auto/quick/pointerhandlers/qquickhoverhandler/tst_qquickhoverhandler.cpp
index ace99daa6a..920bf77978 100644
--- a/tests/auto/quick/pointerhandlers/qquickhoverhandler/tst_qquickhoverhandler.cpp
+++ b/tests/auto/quick/pointerhandlers/qquickhoverhandler/tst_qquickhoverhandler.cpp
@@ -571,6 +571,17 @@ void tst_HoverHandler::deviceCursor()
QCOMPARE(eraserHandler->isHovered(), false);
QCOMPARE(aibrushHandler->isHovered(), false);
QCOMPARE(airbrushEraserHandler->isHovered(), true); // there was no fresh QTabletEvent to tell it not to be hovered
+
+ // hover with the stylus again, then move the mouse outside the handlers' parent item
+ testStylusDevice(QInputDevice::DeviceType::Stylus, QPointingDevice::PointerType::Pen,
+ Qt::CrossCursor, stylusHandler);
+ QTest::mouseMove(&window, QPoint(180, 180));
+ // the mouse has left the item: all its HoverHandlers should be unhovered (QTBUG-116505)
+ QCOMPARE(stylusHandler->isHovered(), false);
+ QCOMPARE(eraserHandler->isHovered(), false);
+ QCOMPARE(aibrushHandler->isHovered(), false);
+ QCOMPARE(airbrushEraserHandler->isHovered(), false);
+ QCOMPARE(mouseHandler->isHovered(), false);
}
void tst_HoverHandler::addHandlerFromCpp()