Improve Qt::WA_UnderMouse accuracy
authorMiikka Heikkinen <miikka.heikkinen@digia.com>
Fri, 12 Oct 2012 12:28:55 +0000 (15:28 +0300)
committerThe Qt Project <gerrit-noreply@qt-project.org>
Mon, 15 Oct 2012 19:11:57 +0000 (21:11 +0200)
Qt::WA_UnderMouse is set/cleared when widgets get enter/leave events.
When there is a popup active, Qt::WA_UnderMouse should always report
false, but this was not happening, because existing state was not
cleared when popup was opened.

Dispatch a leave event for last mouse receiver when a popup is
opened to update the Qt::WA_UnderMouse state. This is roughly
equivalent to what happens on Qt4.

Task-number: QTBUG-27478
Change-Id: I7739e75727213e748ab2f42f1027d32325d89fb0
Reviewed-by: Friedemann Kleint <Friedemann.Kleint@digia.com>
Reviewed-by: Marc Mutz <marc.mutz@kdab.com>
src/widgets/kernel/qapplication_qpa.cpp
tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp

index 6b04c18..5dc68e4 100644 (file)
@@ -77,6 +77,7 @@ extern QWidget *qt_button_down;
 extern QWidget *qt_popup_down;
 extern bool qt_replay_popup_mouse_event;
 int openPopupCount = 0;
+extern QPointer<QWidget> qt_last_mouse_receiver;
 
 void QApplicationPrivate::createEventDispatcher()
 {
@@ -249,6 +250,12 @@ void QApplicationPrivate::openPopup(QWidget *popup)
             QApplication::sendEvent(fw, &e);
         }
     }
+
+    // Dispatch leave for last mouse receiver to update undermouse states
+    if (qt_last_mouse_receiver && !QWidget::mouseGrabber()) {
+        QApplicationPrivate::dispatchEnterLeave(0, qt_last_mouse_receiver.data());
+        qt_last_mouse_receiver = 0;
+    }
 }
 
 void QApplicationPrivate::initializeMultitouch_sys()
index 07ed38f..b4f31ac 100644 (file)
@@ -353,6 +353,7 @@ private slots:
 #ifndef QTEST_NO_CURSOR
     void syntheticEnterLeave();
     void taskQTBUG_4055_sendSyntheticEnterLeave();
+    void underMouse();
 #endif
     void windowFlags();
     void initialPosForDontShowOnScreenWidgets();
@@ -9598,5 +9599,86 @@ void tst_QWidget::styleSheetPropagation()
     }
 }
 
+#ifndef QTEST_NO_CURSOR
+void tst_QWidget::underMouse()
+{
+    // Move the mouse cursor to a safe location
+    QCursor::setPos(0,0);
+
+    QWidget topLevelWidget;
+    QLineEdit childWidget1(&topLevelWidget);
+    QLineEdit childWidget2(&topLevelWidget);
+    QWidget popupWidget(0, Qt::Popup);
+
+    topLevelWidget.setObjectName("topLevelWidget");
+    childWidget1.setObjectName("childWidget1");
+    childWidget2.setObjectName("childWidget2");
+    popupWidget.setObjectName("popupWidget");
+
+    topLevelWidget.setGeometry(100, 100, 300, 300);
+    childWidget1.setGeometry(20, 20, 100, 100);
+    childWidget2.setGeometry(20, 120, 100, 100);
+    popupWidget.setGeometry(50, 100, 50, 50);
+
+    topLevelWidget.show();
+    QVERIFY(QTest::qWaitForWindowExposed(&topLevelWidget));
+    QWindow *window = topLevelWidget.windowHandle();
+
+    QPoint outsideWindowPoint(30, -10);
+    QPoint inWindowPoint(30, 10);
+    QPoint child1Point(30, 50);
+    QPoint child2Point(30, 150);
+
+    // Outside window
+    QTest::mouseMove(window, outsideWindowPoint);
+    QVERIFY(!topLevelWidget.underMouse());
+    QVERIFY(!childWidget1.underMouse());
+    QVERIFY(!childWidget2.underMouse());
+
+    // Enter window, outside children
+    // Note: QTest::mouseMove will not generate enter events for windows, so send one explicitly
+    QWindowSystemInterface::handleEnterEvent(window);
+    QTest::mouseMove(window, inWindowPoint);
+    QVERIFY(topLevelWidget.underMouse());
+    QVERIFY(!childWidget1.underMouse());
+    QVERIFY(!childWidget2.underMouse());
+
+    // In childWidget1
+    QTest::mouseMove(window, child1Point);
+    QVERIFY(topLevelWidget.underMouse());
+    QVERIFY(childWidget1.underMouse());
+    QVERIFY(!childWidget2.underMouse());
+
+    // In childWidget2
+    QTest::mouseMove(window, child2Point);
+    QVERIFY(topLevelWidget.underMouse());
+    QVERIFY(!childWidget1.underMouse());
+    QVERIFY(childWidget2.underMouse());
+
+    // Throw up a popup window
+    popupWidget.show();
+    QVERIFY(QTest::qWaitForWindowExposed(&popupWidget));
+    QWindow *popupWindow = popupWidget.windowHandle();
+    QVERIFY(popupWindow);
+    QVERIFY(QApplication::activePopupWidget() == &popupWidget);
+
+    // If there is an active popup, undermouse should not be reported (QTBUG-27478)
+    QVERIFY(!topLevelWidget.underMouse());
+    QVERIFY(!childWidget1.underMouse());
+    QVERIFY(!childWidget2.underMouse());
+
+    // Moving around while popup active should not change undermouse either
+    QTest::mouseMove(popupWindow, popupWindow->mapFromGlobal(window->mapToGlobal(inWindowPoint)));
+    QVERIFY(!topLevelWidget.underMouse());
+    QVERIFY(!childWidget1.underMouse());
+    QVERIFY(!childWidget2.underMouse());
+
+    QTest::mouseMove(popupWindow, popupWindow->mapFromGlobal(window->mapToGlobal(child1Point)));
+    QVERIFY(!topLevelWidget.underMouse());
+    QVERIFY(!childWidget1.underMouse());
+    QVERIFY(!childWidget2.underMouse());
+}
+#endif // QTEST_NO_CURSOR
+
 QTEST_MAIN(tst_QWidget)
 #include "tst_qwidget.moc"