Windows: Prevent hidden transient children from being re-shown by Windows.

Bring back code from Qt 4 to handle WM_SHOWWINDOW / SW_PARENTOPENING
correctly.

Task-number: QTBUG-40696
Change-Id: If018bf90573f495dbe32d0c46f522ccde0691ebb
Reviewed-by: Laszlo Agocs <laszlo.agocs@digia.com>
bb10
Friedemann Kleint 2014-08-28 12:59:14 +02:00
parent 2d12ef0be0
commit 4354fef3d4
3 changed files with 70 additions and 4 deletions

View File

@ -77,6 +77,7 @@ enum WindowsEventType // Simplify event types
LeaveEvent = WindowEventFlag + 5,
CloseEvent = WindowEventFlag + 6,
ShowEvent = WindowEventFlag + 7,
ShowEventOnParentRestoring = WindowEventFlag + 20,
HideEvent = WindowEventFlag + 8,
DestroyEvent = WindowEventFlag + 9,
MoveEvent = WindowEventFlag + 10,
@ -128,7 +129,7 @@ enum ProcessDpiAwareness
} // namespace QtWindows
inline QtWindows::WindowsEventType windowsEventType(UINT message, WPARAM wParamIn)
inline QtWindows::WindowsEventType windowsEventType(UINT message, WPARAM wParamIn, LPARAM lParamIn)
{
switch (message) {
case WM_PAINT:
@ -156,7 +157,9 @@ inline QtWindows::WindowsEventType windowsEventType(UINT message, WPARAM wParamI
case WM_MOVE:
return QtWindows::MoveEvent;
case WM_SHOWWINDOW:
return wParamIn ? QtWindows::ShowEvent : QtWindows::HideEvent;
if (wParamIn)
return lParamIn == SW_PARENTOPENING ? QtWindows::ShowEventOnParentRestoring : QtWindows::ShowEvent;
return QtWindows::HideEvent;
case WM_SIZE:
return QtWindows::ResizeEvent;
case WM_NCCALCSIZE:

View File

@ -1052,6 +1052,12 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
case QtWindows::FocusOutEvent:
handleFocusEvent(et, platformWindow);
return true;
case QtWindows::ShowEventOnParentRestoring: // QTBUG-40696, prevent Windows from re-showing hidden transient children (dialogs).
if (!platformWindow->window()->isVisible()) {
*result = 0;
return true;
}
break;
case QtWindows::HideEvent:
platformWindow->handleHidden();
return false;// Indicate transient children should be hidden by windows (SW_PARENTCLOSING)
@ -1243,7 +1249,7 @@ void QWindowsContext::setAsyncExpose(bool value)
extern "C" LRESULT QT_WIN_CALLBACK qWindowsWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
LRESULT result;
const QtWindows::WindowsEventType et = windowsEventType(message, wParam);
const QtWindows::WindowsEventType et = windowsEventType(message, wParam, lParam);
const bool handled = QWindowsContext::instance()->windowsProc(hwnd, message, et, wParam, lParam, &result);
if (QWindowsContext::verbose > 1 && lcQpaEvents().isDebugEnabled()) {
if (const char *eventName = QWindowsGuiEventDispatcher::windowsMessageName(message)) {

View File

@ -39,10 +39,11 @@
**
****************************************************************************/
#include <qwindow.h>
#include <qrasterwindow.h>
#include <qpa/qwindowsysteminterface.h>
#include <qpa/qplatformintegration.h>
#include <private/qguiapplication_p.h>
#include <QtGui/QPainter>
#include <QtTest/QtTest>
@ -51,6 +52,8 @@
#if defined(Q_OS_QNX)
#include <QOpenGLContext>
#elif defined(Q_OS_WIN) && !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT)
# include <QtCore/qt_windows.h>
#endif
// For QSignalSpy slot connections.
@ -94,6 +97,7 @@ private slots:
void modalWithChildWindow();
void modalWindowModallity();
void modalWindowPosition();
void windowsTransientChildren();
void initTestCase();
void cleanup();
@ -1539,6 +1543,59 @@ void tst_QWindow::modalWindowPosition()
QCOMPARE(window.geometry(), origGeo);
}
class ColoredWindow : public QRasterWindow {
public:
explicit ColoredWindow(const QColor &color, QWindow *parent = 0) : QRasterWindow(parent), m_color(color) {}
void paintEvent(QPaintEvent *) Q_DECL_OVERRIDE
{
QPainter p(this);
p.fillRect(QRect(QPoint(0, 0), size()), m_color);
}
private:
const QColor m_color;
};
static bool isNativeWindowVisible(const QWindow *window)
{
#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT)
return IsWindowVisible(reinterpret_cast<HWND>(window->winId()));
#else
Q_UNIMPLEMENTED();
return window->isVisible();
#endif
}
void tst_QWindow::windowsTransientChildren()
{
if (QGuiApplication::platformName().compare(QStringLiteral("windows"), Qt::CaseInsensitive))
QSKIP("Windows only test");
ColoredWindow mainWindow(Qt::yellow);
mainWindow.setGeometry(QRect(m_availableTopLeft + QPoint(100, 100), m_testWindowSize));
mainWindow.setTitle(QStringLiteral("Main"));
ColoredWindow child(Qt::blue, &mainWindow);
child.setGeometry(QRect(QPoint(0, 0), m_testWindowSize / 2));
ColoredWindow dialog(Qt::red);
dialog.setGeometry(QRect(m_availableTopLeft + QPoint(200, 200), m_testWindowSize));
dialog.setTitle(QStringLiteral("Dialog"));
dialog.setTransientParent(&mainWindow);
mainWindow.show();
child.show();
dialog.show();
QVERIFY(QTest::qWaitForWindowExposed(&dialog));
mainWindow.setWindowState(Qt::WindowMinimized);
QVERIFY(!isNativeWindowVisible(&dialog));
dialog.hide();
mainWindow.setWindowState(Qt::WindowNoState);
// QTBUG-40696, transient children hidden by Qt should not be re-shown by Windows.
QVERIFY(!isNativeWindowVisible(&dialog));
QVERIFY(isNativeWindowVisible(&child)); // Real children should be visible.
}
#include <tst_qwindow.moc>
QTEST_MAIN(tst_QWindow)