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>
This commit is contained in:
Jørgen Lind 2014-10-21 13:47:01 +02:00
parent ef25d2efdb
commit 190bfbae64
4 changed files with 9 additions and 8 deletions

View File

@ -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

View File

@ -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;

View File

@ -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;
}

View File

@ -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()) {