From 190bfbae64006216b4114a02153c60d604ac24f7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=B8rgen=20Lind?= <jorgen.lind@digia.com>
Date: Tue, 21 Oct 2014 13:47:01 +0200
Subject: [PATCH] Ensure that a leave event is sent to a popup that is being
 closed

If a context menu contains a menu item which will open a dialog, the
context menu will never get the leave event, which might leave the menu
in an invalid state.

Synthetic leave events are sent to windows, but not to popups that are
blocked by modal dialogs. Hovever, a popup is removed from the popup
stack in QApplication before it receives the leave event. Therefore
always give popups events, even when they are not visible.

Task-number: QTBUG-38021
Change-Id: I63f6febed44f1e7c8f29e7a09af07f32b4ddbc82
Reviewed-by: Shawn Rutledge <shawn.rutledge@digia.com>
---
 src/gui/kernel/qguiapplication.cpp   | 9 ++-------
 src/gui/kernel/qwindow_p.h           | 4 ++++
 src/widgets/kernel/qapplication.cpp  | 3 ++-
 src/widgets/kernel/qwidgetwindow.cpp | 1 +
 4 files changed, 9 insertions(+), 8 deletions(-)

diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp
index 2e050572c1a..c5e7fb523d1 100644
--- a/src/gui/kernel/qguiapplication.cpp
+++ b/src/gui/kernel/qguiapplication.cpp
@@ -216,11 +216,6 @@ static inline void clearFontUnlocked()
     QGuiApplicationPrivate::app_font = 0;
 }
 
-static inline bool isPopupWindow(const QWindow *w)
-{
-    return (w->flags() & Qt::WindowType_Mask) == Qt::Popup;
-}
-
 // Geometry specification for top level windows following the convention of the
 // -geometry command line arguments in X11 (see XParseGeometry).
 struct QWindowGeometrySpecification
@@ -672,7 +667,7 @@ static void updateBlockedStatusRecursion(QWindow *window, bool shouldBeBlocked)
 void QGuiApplicationPrivate::updateBlockedStatus(QWindow *window)
 {
     bool shouldBeBlocked = false;
-    if (!isPopupWindow(window) && !self->modalWindowList.isEmpty())
+    if (!QWindowPrivate::get(window)->isPopup() && !self->modalWindowList.isEmpty())
         shouldBeBlocked = self->isWindowBlocked(window);
     updateBlockedStatusRecursion(window, shouldBeBlocked);
 }
@@ -682,7 +677,7 @@ void QGuiApplicationPrivate::showModalWindow(QWindow *modal)
     self->modalWindowList.prepend(modal);
 
     // Send leave for currently entered window if it should be blocked
-    if (currentMouseWindow && !isPopupWindow(currentMouseWindow)) {
+    if (currentMouseWindow && !QWindowPrivate::get(currentMouseWindow)->isPopup()) {
         bool shouldBeBlocked = self->isWindowBlocked(currentMouseWindow);
         if (shouldBeBlocked) {
             // Remove the new window from modalWindowList temporarily so leave can go through
diff --git a/src/gui/kernel/qwindow_p.h b/src/gui/kernel/qwindow_p.h
index ea0bb75d85f..40f23b1c36e 100644
--- a/src/gui/kernel/qwindow_p.h
+++ b/src/gui/kernel/qwindow_p.h
@@ -137,6 +137,10 @@ public:
 
     virtual void clearFocusObject();
 
+    bool isPopup() const { return (windowFlags & Qt::WindowType_Mask) == Qt::Popup; }
+
+    static QWindowPrivate *get(QWindow *window) { return window->d_func(); }
+
     QWindow::SurfaceType surfaceType;
     Qt::WindowFlags windowFlags;
     QWindow *parentWindow;
diff --git a/src/widgets/kernel/qapplication.cpp b/src/widgets/kernel/qapplication.cpp
index 6df1d735a1f..9abec13b5be 100644
--- a/src/widgets/kernel/qapplication.cpp
+++ b/src/widgets/kernel/qapplication.cpp
@@ -64,6 +64,7 @@
 #include <QtWidgets/qgraphicsproxywidget.h>
 #include <QtGui/qstylehints.h>
 #include <QtGui/qinputmethod.h>
+#include <QtGui/private/qwindow_p.h>
 #include <qpa/qplatformtheme.h>
 #ifndef QT_NO_WHATSTHIS
 #include <QtWidgets/QWhatsThis>
@@ -2489,7 +2490,7 @@ bool QApplicationPrivate::isWindowBlocked(QWindow *window, QWindow **blockingWin
     }
     QWidget *popupWidget = QApplication::activePopupWidget();
     QWindow *popupWindow = popupWidget ? popupWidget->windowHandle() : 0;
-    if (popupWindow == window) {
+    if (popupWindow == window || (!popupWindow && QWindowPrivate::get(window)->isPopup())) {
         *blockingWindow = 0;
         return false;
     }
diff --git a/src/widgets/kernel/qwidgetwindow.cpp b/src/widgets/kernel/qwidgetwindow.cpp
index d40fc84d778..7b52638e28e 100644
--- a/src/widgets/kernel/qwidgetwindow.cpp
+++ b/src/widgets/kernel/qwidgetwindow.cpp
@@ -403,6 +403,7 @@ void QWidgetWindow::handleMouseEvent(QMouseEvent *event)
             QGuiApplicationPrivate::setMouseEventSource(&e, QGuiApplicationPrivate::mouseEventSource(event));
             e.setTimestamp(event->timestamp());
             QApplicationPrivate::sendMouseEvent(receiver, &e, alien, m_widget, &qt_button_down, qt_last_mouse_receiver);
+            qt_last_mouse_receiver = receiver;
         } else {
             // close disabled popups when a mouse button is pressed or released
             switch (event->type()) {
-- 
GitLab