From 4354fef3d4c45a9ac1c01cf99627aad6d3b4d68d Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Thu, 28 Aug 2014 12:59:14 +0200 Subject: [PATCH] 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 --- .../platforms/windows/qtwindowsglobal.h | 7 ++- .../platforms/windows/qwindowscontext.cpp | 8 ++- tests/auto/gui/kernel/qwindow/tst_qwindow.cpp | 59 ++++++++++++++++++- 3 files changed, 70 insertions(+), 4 deletions(-) diff --git a/src/plugins/platforms/windows/qtwindowsglobal.h b/src/plugins/platforms/windows/qtwindowsglobal.h index 1b2502af10..8c361d72ca 100644 --- a/src/plugins/platforms/windows/qtwindowsglobal.h +++ b/src/plugins/platforms/windows/qtwindowsglobal.h @@ -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: diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp index b6a9f28aed..132f224382 100644 --- a/src/plugins/platforms/windows/qwindowscontext.cpp +++ b/src/plugins/platforms/windows/qwindowscontext.cpp @@ -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)) { diff --git a/tests/auto/gui/kernel/qwindow/tst_qwindow.cpp b/tests/auto/gui/kernel/qwindow/tst_qwindow.cpp index 0686ca792c..25e5255189 100644 --- a/tests/auto/gui/kernel/qwindow/tst_qwindow.cpp +++ b/tests/auto/gui/kernel/qwindow/tst_qwindow.cpp @@ -39,10 +39,11 @@ ** ****************************************************************************/ -#include +#include #include #include #include +#include #include @@ -51,6 +52,8 @@ #if defined(Q_OS_QNX) #include +#elif defined(Q_OS_WIN) && !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT) +# include #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(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 QTEST_MAIN(tst_QWindow)