diff options
author | Axel Spoerl <axel.spoerl@qt.io> | 2022-12-13 10:43:26 +0100 |
---|---|---|
committer | Axel Spoerl <axel.spoerl@qt.io> | 2022-12-16 22:58:11 +0100 |
commit | 5edb71c6d4cb0051d27d023ddcd180c5f59f2725 (patch) | |
tree | 0da5eda94d2e30808e3945e067237b6351b4cde5 /tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp | |
parent | 4ccb10dc918c3d4d01afa1ad718a24eb5fa49a3c (diff) |
Fix QWidget::restoreGeometry when restored geometry is off screen
If a widget's geometry is restored to a screen, which is smaller than
the one it was saved from,
- the widget could appear (partly) off screen
- the widget's title bar and resize handles could be inaccessible
This patch refactors and documents checkRestoredGeometry.
In a first step, the restored geometry's size is checked against
a given screen size. It is corrected if necessary.
In a second step, the restored geometry is moved inside the screen,
if necessary.
It makes the function a static member of QWidgetPrivate in order to
expose it for auto testing and adds a respective test function to
tst_QWidget.
Fixes: QTBUG-77385
Fixes: QTBUG-4397
Task-number: QTBUG-69104
Pick-to: 6.5 6.4
Change-Id: I7172e27bfef86d82cd51de70b40de42e8895bae6
Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io>
Diffstat (limited to 'tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp')
-rw-r--r-- | tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp | 73 |
1 files changed, 73 insertions, 0 deletions
diff --git a/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp b/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp index 0b495b2379..7e7cc8da7c 100644 --- a/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp +++ b/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp @@ -195,6 +195,8 @@ private slots: void saveRestoreGeometry(); void restoreVersion1Geometry_data(); void restoreVersion1Geometry(); + void restoreGeometryAfterScreenChange_data(); + void restoreGeometryAfterScreenChange(); void widgetAt(); #ifdef Q_OS_MACOS @@ -434,6 +436,15 @@ private: QPointingDevice *m_touchScreen; const int m_fuzz; QPalette simplePalette(); + +private: + enum class ScreenPosition { + OffAbove, + OffLeft, + OffBelow, + OffRight, + Contained + }; }; // Testing get/set functions @@ -4245,6 +4256,68 @@ void tst_QWidget::restoreVersion1Geometry() #endif } +void tst_QWidget::restoreGeometryAfterScreenChange_data() +{ + QTest::addColumn<ScreenPosition>("screenPosition"); + QTest::addColumn<int>("deltaWidth"); + QTest::addColumn<int>("deltaHeight"); + QTest::addColumn<int>("frameMargin"); + QTest::addColumn<bool>("outside"); + + QTest::newRow("offAboveLarge") << ScreenPosition::OffAbove << 200 << 250 << 20 << true; + QTest::newRow("fitting") << ScreenPosition::Contained << 80 << 80 << 20 << false; + QTest::newRow("offRightWide") << ScreenPosition::OffRight << 150 << 80 << 20 << false; + QTest::newRow("offLeftFitting") << ScreenPosition::OffLeft << 70 << 70 << 20 << true; + QTest::newRow("offBelowHigh") << ScreenPosition::OffBelow << 80 << 200 << 20 << false; +} + +void tst_QWidget::restoreGeometryAfterScreenChange() +{ + const QList<QScreen *> &screens = QApplication::screens(); + QVERIFY2(!screens.isEmpty(), "No screens found."); + const QRect screenGeometry = screens.at(0)->geometry(); + + QFETCH(ScreenPosition, screenPosition); + QFETCH(int, deltaWidth); + QFETCH(int, deltaHeight); + QFETCH(int, frameMargin); + QFETCH(bool, outside); + + QRect restoredGeometry = screenGeometry; + restoredGeometry.setHeight(screenGeometry.height() * deltaHeight / 100); + restoredGeometry.setWidth(screenGeometry.width() * deltaWidth / 100); + const float moveMargin = outside ? 1.2 : 0.75; + + switch (screenPosition) { + case ScreenPosition::OffLeft: + restoredGeometry.setLeft(restoredGeometry.width() * (-moveMargin)); + break; + case ScreenPosition::OffAbove: + restoredGeometry.setTop(restoredGeometry.height() * (-moveMargin)); + break; + case ScreenPosition::OffRight: + restoredGeometry.setRight(restoredGeometry.width() * moveMargin); + break; + case ScreenPosition::OffBelow: + restoredGeometry.setBottom(restoredGeometry.height() * moveMargin); + break; + case ScreenPosition::Contained: + break; + } + + // If restored geometry fits into screen and has not been moved, + // it is changed only by frame margin plus one pixel at each edge + const QRect originalGeometry = restoredGeometry.adjusted(1, frameMargin + 1, 1, frameMargin + 1); + + QWidgetPrivate::checkRestoredGeometry(screenGeometry, &restoredGeometry, frameMargin); + + if (deltaHeight < 100 && deltaWidth < 100 && screenPosition == ScreenPosition::Contained) + QCOMPARE(originalGeometry, restoredGeometry); + + // new geometry has to fit on the screen + QVERIFY(screenGeometry.contains(restoredGeometry)); +} + void tst_QWidget::widgetAt() { #ifdef Q_OS_MACOS |