From e3288f246b44ba2b6d90b90eb99ab61f496d8d57 Mon Sep 17 00:00:00 2001
From: Friedemann Kleint <Friedemann.Kleint@digia.com>
Date: Wed, 9 Dec 2015 18:06:20 +0100
Subject: [PATCH] Windows: Restore window geometry after
 normal->maximized->fullscreen->normal.

- Do not save geometry when going from maximized->fullscreen
- Use SW_SHOWNA instead SW_SHOWNOACTIVATE as otherwise the
  maximized geometry is restored.
- Add a test for Windows.

Task-number: QTBUG-49709
Change-Id: Ic81e7398ee90d499a50b02192a45cb09276a2105
Reviewed-by: Joerg Bornemann <joerg.bornemann@theqtcompany.com>
---
 .../platforms/windows/qwindowswindow.cpp      |  4 +-
 tests/auto/gui/kernel/qwindow/tst_qwindow.cpp | 67 +++++++++++++++++++
 2 files changed, 69 insertions(+), 2 deletions(-)

diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp
index 5aae1aafc50..cac8ec5ecca 100644
--- a/src/plugins/platforms/windows/qwindowswindow.cpp
+++ b/src/plugins/platforms/windows/qwindowswindow.cpp
@@ -1720,7 +1720,7 @@ void QWindowsWindow::setWindowState_sys(Qt::WindowState newState)
             if (!m_savedStyle) {
                 m_savedStyle = style();
 #ifndef Q_OS_WINCE
-                if (oldState == Qt::WindowMinimized) {
+                if (oldState == Qt::WindowMinimized || oldState == Qt::WindowMaximized) {
                     const QRect nf = normalFrameGeometry(m_data.hwnd);
                     if (nf.isValid())
                         m_savedFrameGeometry = nf;
@@ -1771,7 +1771,7 @@ void QWindowsWindow::setWindowState_sys(Qt::WindowState newState)
             // preserve maximized state
             if (visible) {
                 setFlag(WithinMaximize);
-                ShowWindow(m_data.hwnd, (newState == Qt::WindowMaximized) ? SW_MAXIMIZE : SW_SHOWNOACTIVATE);
+                ShowWindow(m_data.hwnd, (newState == Qt::WindowMaximized) ? SW_MAXIMIZE : SW_SHOWNA);
                 clearFlag(WithinMaximize);
             }
             m_savedStyle = 0;
diff --git a/tests/auto/gui/kernel/qwindow/tst_qwindow.cpp b/tests/auto/gui/kernel/qwindow/tst_qwindow.cpp
index 2219306b814..a89f0da4d27 100644
--- a/tests/auto/gui/kernel/qwindow/tst_qwindow.cpp
+++ b/tests/auto/gui/kernel/qwindow/tst_qwindow.cpp
@@ -95,6 +95,8 @@ private slots:
     void windowsTransientChildren();
     void requestUpdate();
     void initTestCase();
+    void stateChange_data();
+    void stateChange();
     void cleanup();
 
 private:
@@ -272,6 +274,18 @@ static inline bool qFuzzyCompareWindowPosition(const QPoint &p1, const QPoint p2
     return (p1 - p2).manhattanLength() <= fuzz;
 }
 
+static inline bool qFuzzyCompareWindowSize(const QSize &s1, const QSize &s2, int fuzz)
+{
+    const int manhattanLength = qAbs(s1.width() - s2.width()) + qAbs(s1.height() - s2.height());
+    return manhattanLength <= fuzz;
+}
+
+static inline bool qFuzzyCompareWindowGeometry(const QRect &r1, const QRect &r2, int fuzz)
+{
+    return qFuzzyCompareWindowPosition(r1.topLeft(), r2.topLeft(), fuzz)
+        && qFuzzyCompareWindowSize(r1.size(), r2.size(), fuzz);
+}
+
 static QString msgPointMismatch(const QPoint &p1, const QPoint p2)
 {
     QString result;
@@ -279,6 +293,13 @@ static QString msgPointMismatch(const QPoint &p1, const QPoint p2)
     return result;
 }
 
+static QString msgRectMismatch(const QRect &r1, const QRect &r2)
+{
+    QString result;
+    QDebug(&result) << r1 << "!=" << r2;
+    return result;
+}
+
 void tst_QWindow::positioning()
 {
     if (!QGuiApplicationPrivate::platformIntegration()->hasCapability(
@@ -394,6 +415,52 @@ void tst_QWindow::positioningDuringMinimized()
     QTRY_COMPARE(window.geometry(), newGeometry);
 }
 
+// QTBUG-49709: Verify that the normal geometry is correctly restored
+// when executing a sequence of window state changes. So far, Windows
+// only where state changes have immediate effect.
+
+typedef QList<Qt::WindowState> WindowStateList;
+
+Q_DECLARE_METATYPE(WindowStateList)
+
+void tst_QWindow::stateChange_data()
+{
+    QTest::addColumn<WindowStateList>("stateSequence");
+
+    QTest::newRow("normal->min->normal") <<
+        (WindowStateList() << Qt::WindowMinimized << Qt::WindowNoState);
+    QTest::newRow("normal->maximized->normal") <<
+        (WindowStateList() << Qt::WindowMaximized << Qt::WindowNoState);
+    QTest::newRow("normal->fullscreen->normal") <<
+        (WindowStateList() << Qt::WindowFullScreen << Qt::WindowNoState);
+    QTest::newRow("normal->maximized->fullscreen->normal") <<
+        (WindowStateList() << Qt::WindowMaximized << Qt::WindowFullScreen << Qt::WindowNoState);
+}
+
+void tst_QWindow::stateChange()
+{
+    QFETCH(WindowStateList, stateSequence);
+
+    if (QGuiApplication::platformName().compare(QLatin1String("windows"), Qt::CaseInsensitive))
+        QSKIP("Windows-only test");
+
+    Window window;
+    window.setTitle(QLatin1String(QTest::currentTestFunction()) + QLatin1Char(' ') + QLatin1String(QTest::currentDataTag()));
+    const QRect normalGeometry(m_availableTopLeft + QPoint(40, 40), m_testWindowSize);
+    window.setGeometry(normalGeometry);
+    //  explicitly use non-fullscreen show. show() can be fullscreen on some platforms
+    window.showNormal();
+    QVERIFY(QTest::qWaitForWindowExposed(&window));
+    foreach (Qt::WindowState state, stateSequence) {
+        window.setWindowState(state);
+        QCoreApplication::processEvents();
+    }
+    const QRect geometry = window.geometry();
+    const int fuzz = int(QHighDpiScaling::factor(&window));
+    QVERIFY2(qFuzzyCompareWindowGeometry(geometry, normalGeometry, fuzz),
+             qPrintable(msgRectMismatch(geometry, normalGeometry)));
+}
+
 class PlatformWindowFilter : public QObject
 {
     Q_OBJECT
-- 
GitLab