qquickwindow: Clear hover when a window is hidden

This fixes a bug in the following sequence:
 - user opens a window
 - the window is hidden whilst under the mouse
 - later the window is reopened without the mouse being under the window
- with the lastMousePosition set an item underneath where the mouse
used to be gets activated.

On X11 we get a Leave event for the hidden window, this is not true for
wayland.

Pick-to: 6.5
Change-Id: Ib14e8dbe29f1ad9a71a488b671d226be1d017b8d
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>
This commit is contained in:
David Edmundson 2023-01-30 16:38:38 +00:00
parent 4f465236f2
commit 40889ffe52
4 changed files with 71 additions and 0 deletions

View File

@ -198,6 +198,8 @@ void QQuickWindow::showEvent(QShowEvent *)
void QQuickWindow::hideEvent(QHideEvent *)
{
Q_D(QQuickWindow);
if (auto da = d->deliveryAgentPrivate())
da->handleWindowHidden(this);
if (d->windowManager)
d->windowManager->hide(this);
}

View File

@ -1321,6 +1321,13 @@ void QQuickDeliveryAgentPrivate::handleWindowDeactivate(QQuickWindow *win)
}
}
void QQuickDeliveryAgentPrivate::handleWindowHidden(QQuickWindow *win)
{
qCDebug(lcFocus) << "hidden" << win->title();
clearHover();
lastMousePosition = QPointF();
}
bool QQuickDeliveryAgentPrivate::allUpdatedPointsAccepted(const QPointerEvent *ev)
{
for (auto &point : ev->points()) {

View File

@ -131,6 +131,7 @@ public:
void flushFrameSynchronousEvents(QQuickWindow *win);
void deliverDelayedTouchEvent();
void handleWindowDeactivate(QQuickWindow *win);
void handleWindowHidden(QQuickWindow *win);
// utility functions that used to be in QQuickPointerEvent et al.
bool allUpdatedPointsAccepted(const QPointerEvent *ev);

View File

@ -138,6 +138,8 @@ private slots:
void hoverPropagation_nested_data();
void hoverPropagation_nested();
void hoverPropagation_siblings();
void hoverEnterOnItemMove();
void hoverEnterOnItemMoveAfterHide();
private:
QScopedPointer<QPointingDevice> touchDevice = QScopedPointer<QPointingDevice>(QTest::createTouchDevice());
@ -521,6 +523,65 @@ void tst_qquickdeliveryagent::hoverPropagation_siblings()
QCOMPARE(sibling2.hoverEnter, true);
}
void tst_qquickdeliveryagent::hoverEnterOnItemMove()
{
QQuickWindow window;
auto deliveryAgent = QQuickWindowPrivate::get(&window)->deliveryAgentPrivate();
window.resize(200, 200);
window.show();
QVERIFY(QTest::qWaitForWindowExposed(&window));
// start with the mouse in the bottom right
QTest::mouseMove(&window, QPoint(150, 150));
HoverItem hoverItem(window.contentItem());
hoverItem.setAcceptHoverEvents(true);
hoverItem.setWidth(100);
hoverItem.setHeight(100);
deliveryAgent->flushFrameSynchronousEvents(&window);
QCOMPARE(hoverItem.hoverEnter, false);
// move the item so the mouse is now inside where the mouse was
hoverItem.setX(100);
hoverItem.setY(100);
deliveryAgent->flushFrameSynchronousEvents(&window);
QCOMPARE(hoverItem.hoverEnter, true);
}
void tst_qquickdeliveryagent::hoverEnterOnItemMoveAfterHide()
{
QQuickWindow window;
auto deliveryAgent = QQuickWindowPrivate::get(&window)->deliveryAgentPrivate();
window.resize(200, 200);
window.show();
QVERIFY(QTest::qWaitForWindowExposed(&window));
// start with the mouse in the bottom right
QTest::mouseMove(&window, QPoint(149, 149));
HoverItem hoverItem(window.contentItem());
hoverItem.setAcceptHoverEvents(true);
hoverItem.setWidth(100);
hoverItem.setHeight(100);
deliveryAgent->flushFrameSynchronousEvents(&window);
QCOMPARE(hoverItem.hoverEnter, false);
window.hide();
window.show();
QVERIFY(QTest::qWaitForWindowExposed(&window));
QCOMPARE(hoverItem.hoverEnter, false);
// move the item so the mouse is now inside where the mouse was
hoverItem.setX(100);
hoverItem.setY(100);
deliveryAgent->flushFrameSynchronousEvents(&window);
QCOMPARE(hoverItem.hoverEnter, false);
}
QTEST_MAIN(tst_qquickdeliveryagent)
#include "tst_qquickdeliveryagent.moc"