summaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authorVolker Hilsheimer <volker.hilsheimer@qt.io>2021-10-04 21:39:31 +0200
committerVolker Hilsheimer <volker.hilsheimer@qt.io>2021-10-16 09:46:22 +0200
commit32edae5e268b968aff82f0713612eff2feffb4e1 (patch)
treefe97e538232807fdd5e87a0312f7cf94ffa81087 /tests
parent553a1c48fd7a9078c1a33ad0829eaa84f0afb670 (diff)
Fix restoring main window state for maximized/fullscreen windows
On systems that asynchronously resize the window to maximized or full screen state, the window will become visible in its normal geometry before it gets the final size by the windowing system. This might cause multiple resize events, to each of which the widget's layout responds with a call to its setGeometry implementation. The QMainWindowLayout is special in that it will shrink dock widgets if there is not enough space for them, but it doesn't grow them back once there is. With the initial resize event being for a smaller size than what was restored, the state is not restored correctly, but remains in the state that fit into the smallest size with which setGeometry got called. To fix this, we have to keep the restored state around until the window either gets a size that is large enough for it to fit, or until we can be reasonably certain that the windowing system is done resizing the window while transitioning it to the maximized or full screen state. Since across the various platforms and windowing systems there is no reliable way to know when the window reaches its final size, we have to use a timer that we (re)start for each call to setGeometry with a size that's not large enough. Once the timer times out, we have to give up; then the last layout state calculated is the final state. To calculate the size of the layout, introduce a function to the QDockAreaLayout that returns the size required for the current sizes of the docks. Refactor sizeHint and minimumSize (which were identical) into a helper template that takes member-function pointers to call the respective method from the dock area layout's content items. Add a test case for various permutations of the scenario. The timeout of 150ms is based on running this test case repeatedly on various desktop platforms and X11 window managers. Fixes: QTBUG-46620 Change-Id: I489675c2c40d3308ac8194aeb4267172b2fb38be Reviewed-by: Albert Astals Cid <albert.astals.cid@kdab.com> Reviewed-by: Lars Knoll <lars.knoll@qt.io> Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Diffstat (limited to 'tests')
-rw-r--r--tests/auto/widgets/widgets/qmainwindow/tst_qmainwindow.cpp65
1 files changed, 65 insertions, 0 deletions
diff --git a/tests/auto/widgets/widgets/qmainwindow/tst_qmainwindow.cpp b/tests/auto/widgets/widgets/qmainwindow/tst_qmainwindow.cpp
index b31acb2b7a..e30df32d5d 100644
--- a/tests/auto/widgets/widgets/qmainwindow/tst_qmainwindow.cpp
+++ b/tests/auto/widgets/widgets/qmainwindow/tst_qmainwindow.cpp
@@ -126,6 +126,8 @@ private slots:
void dockWidgetArea();
void restoreState();
void restoreStateFromPreviousVersion();
+ void restoreStateSizeChanged_data();
+ void restoreStateSizeChanged();
void createPopupMenu();
void hideBeforeLayout();
#ifdef QT_BUILD_INTERNAL
@@ -1391,6 +1393,67 @@ void tst_QMainWindow::restoreStateFromPreviousVersion()
}
+void tst_QMainWindow::restoreStateSizeChanged_data()
+{
+ QTest::addColumn<Qt::WindowState>("saveState");
+ QTest::addColumn<Qt::WindowState>("showState");
+ QTest::addColumn<bool>("sameSize");
+
+ QTest::addRow("fullscreen") << Qt::WindowFullScreen << Qt::WindowFullScreen << true;
+ QTest::addRow("maximized") << Qt::WindowMaximized << Qt::WindowMaximized << true;
+ QTest::addRow("maximized->normal") << Qt::WindowMaximized << Qt::WindowNoState << false;
+ QTest::addRow("fullscreen->normal") << Qt::WindowFullScreen << Qt::WindowNoState << false;
+ QTest::addRow("fullscreen->maximized") << Qt::WindowFullScreen << Qt::WindowMaximized << false;
+ QTest::addRow("maximized->fullscreen") << Qt::WindowMaximized << Qt::WindowFullScreen << true;
+}
+
+void tst_QMainWindow::restoreStateSizeChanged()
+{
+ QFETCH(Qt::WindowState, saveState);
+ QFETCH(Qt::WindowState, showState);
+ QFETCH(bool, sameSize);
+
+ auto createMainWindow = []{
+ QMainWindow *mainWindow = new QMainWindow;
+ mainWindow->move(QGuiApplication::primaryScreen()->availableGeometry().topLeft());
+ mainWindow->setCentralWidget(new QLabel("X"));
+ QDockWidget *dockWidget = new QDockWidget;
+ dockWidget->setObjectName("Dock Widget");
+ mainWindow->addDockWidget(Qt::LeftDockWidgetArea, dockWidget);
+ return mainWindow;
+ };
+
+ QByteArray geometryData;
+ QByteArray stateData;
+ int dockWidgetWidth = 0;
+ QRect normalGeometry;
+
+ {
+ auto mainWindow = QScopedPointer<QMainWindow>(createMainWindow());
+ mainWindow->setWindowState(saveState);
+ mainWindow->show();
+ QVERIFY(QTest::qWaitForWindowExposed(mainWindow.data()));
+ dockWidgetWidth = mainWindow->width() - 100;
+ QDockWidget *dockWidget = mainWindow->findChild<QDockWidget*>("Dock Widget");
+ mainWindow->resizeDocks({dockWidget}, {dockWidgetWidth}, Qt::Horizontal);
+ geometryData = mainWindow->saveGeometry();
+ stateData = mainWindow->saveState();
+ normalGeometry = mainWindow->normalGeometry();
+ }
+
+ auto mainWindow = QScopedPointer<QMainWindow>(createMainWindow());
+ mainWindow->restoreGeometry(geometryData);
+ mainWindow->restoreState(stateData);
+ mainWindow->setWindowState(showState);
+ mainWindow->show();
+ QVERIFY(QTest::qWaitForWindowExposed(mainWindow.data()));
+
+ QDockWidget *dockWidget = mainWindow->findChild<QDockWidget*>("Dock Widget");
+ QVERIFY(dockWidget);
+ QCOMPARE(mainWindow->normalGeometry().size(), normalGeometry.size());
+ if (sameSize)
+ QTRY_COMPARE(dockWidget->width(), dockWidgetWidth);
+}
void tst_QMainWindow::createPopupMenu()
{
@@ -1692,6 +1755,7 @@ void tst_QMainWindow::saveRestore()
adw.apply(&mainWindow);
mainWindow.show();
+
mainWindow.restoreState(stateData);
COMPARE_DOCK_WIDGET_GEOS(dockWidgetGeos, dockWidgetGeometries(&mainWindow));
@@ -1710,6 +1774,7 @@ void tst_QMainWindow::saveRestore()
mainWindow.restoreState(stateData);
mainWindow.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&mainWindow));
COMPARE_DOCK_WIDGET_GEOS(dockWidgetGeos, dockWidgetGeometries(&mainWindow));
}
}