Ensure that HoverHandler reacts if a touchpoint moves out of bounds

We rely on QQuickDeliveryAgentPrivate::flushFrameSynchronousEvents()
mostly, but it doesn't get invoked without a window update request.
So there is a special case when a touchpoint moves _out_ of an item
that has a HoverHandler but is not reacting to touch in other ways:
we just need to send another artificial hover event for each touchpoint
to each hovered item to inform handlers about the new hover position.

Fixes: QTBUG-120346
Pick-to: 6.2 6.5 6.6 6.7
Change-Id: I479362a2663943eb495fe0be418009165c7134bd
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Santhosh Kumar <santhosh.kumar.selvaraj@qt.io>
This commit is contained in:
Shawn Rutledge 2023-12-27 21:08:40 -07:00
parent 57f5f462fc
commit ff4c2c311f
3 changed files with 70 additions and 0 deletions

View File

@ -2092,6 +2092,16 @@ void QQuickDeliveryAgentPrivate::deliverUpdatedPoints(QPointerEvent *event)
}
if (!relevantPassiveGrabbers.isEmpty())
deliverToPassiveGrabbers(relevantPassiveGrabbers, event);
// Ensure that HoverHandlers are updated, in case no items got dirty so far and there's no update request
if (event->type() == QEvent::TouchUpdate) {
for (auto hoverItem : hoverItems) {
if (auto item = hoverItem.first) {
deliverHoverEventToItem(item, point.scenePosition(), point.sceneLastPosition(),
event->modifiers(), event->timestamp(), false);
}
}
}
}
if (done)

View File

@ -0,0 +1,17 @@
import QtQuick
Item {
width: 320
height: 240
Rectangle {
width: 100
height: 100
anchors.centerIn: parent
color: hh.hovered ? "lightsteelblue" : "beige"
HoverHandler {
id: hh
}
}
}

View File

@ -49,9 +49,12 @@ private slots:
void addHandlerFromCpp();
void ensureHoverHandlerWorksWhenItemHasHoverDisabled();
void changeCursor();
void touchDrag();
private:
void createView(QScopedPointer<QQuickView> &window, const char *fileName);
QScopedPointer<QPointingDevice> touchscreen = QScopedPointer<QPointingDevice>(QTest::createTouchDevice());
};
void tst_HoverHandler::createView(QScopedPointer<QQuickView> &window, const char *fileName)
@ -700,6 +703,46 @@ void tst_HoverHandler::changeCursor()
#endif
}
void tst_HoverHandler::touchDrag()
{
QQuickView window;
QVERIFY(QQuickTest::showView(window, testFileUrl("hoverHandler.qml")));
const QQuickItem *root = window.rootObject();
QQuickHoverHandler *handler = root->findChild<QQuickHoverHandler *>();
QVERIFY(handler);
// polishAndSync() calls flushFrameSynchronousEvents() before emitting afterAnimating()
QSignalSpy frameSyncSpy(&window, &QQuickWindow::afterAnimating);
const QPoint out(root->width() - 1, root->height() / 2);
QPoint in(root->width() / 2, root->height() / 2);
QTest::touchEvent(&window, touchscreen.get()).press(0, out, &window);
QQuickTouchUtils::flush(&window);
QCOMPARE(handler->isHovered(), false);
frameSyncSpy.clear();
QTest::touchEvent(&window, touchscreen.get()).move(0, in, &window);
QQuickTouchUtils::flush(&window);
QTRY_COMPARE(handler->isHovered(), true);
QCOMPARE(handler->point().scenePosition(), in);
in += {10, 10};
QTest::touchEvent(&window, touchscreen.get()).move(0, in, &window);
QQuickTouchUtils::flush(&window);
// ensure that the color change is visible
QTRY_COMPARE_GE(frameSyncSpy.size(), 1);
QCOMPARE(handler->isHovered(), true);
QCOMPARE(handler->point().scenePosition(), in);
QTest::touchEvent(&window, touchscreen.get()).move(0, out, &window);
QQuickTouchUtils::flush(&window);
QTRY_COMPARE_GE(frameSyncSpy.size(), 2);
QCOMPARE(handler->isHovered(), false);
QTest::touchEvent(&window, touchscreen.get()).release(0, out, &window);
}
QTEST_MAIN(tst_HoverHandler)
#include "tst_qquickhoverhandler.moc"