Make tst_qwidget pass on High-DPI screens (Windows)
- Move the fuzz check introduced by 63090627220a6209652d236cf991305fbeb188b8 to a shared header for reuse. Use it in in more places to account for rounding errors introduced by odd window frame sizes when scaling is active. - Use the test widget size to ensure windows do not violate the minimum decorated window size on Windows when scaling is inactive on large monitors. Task-number: QTBUG-46615 Change-Id: Icf803a4bc2c275eadb8f98e60b08e39b2ebebedd Reviewed-by: Oliver Wolff <oliver.wolff@qt.io>
This commit is contained in:
parent
085d1335d1
commit
67c569add0
109
tests/auto/shared/highdpi.h
Normal file
109
tests/auto/shared/highdpi.h
Normal file
@ -0,0 +1,109 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2019 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the test suite of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef HIGHDPI_H
|
||||
#define HIGHDPI_H
|
||||
|
||||
#include <QtCore/qbytearray.h>
|
||||
#include <QtCore/qpoint.h>
|
||||
#include <QtCore/qrect.h>
|
||||
#include <QtCore/qsize.h>
|
||||
|
||||
// Helpers for comparing geometries a that may go through scaling in the
|
||||
// platform plugin with fuzz (pass rounded-down device pixel ratios or
|
||||
// scaling factors). Error message for use with QVERIFY2() are also provided.
|
||||
|
||||
class HighDpi
|
||||
{
|
||||
public:
|
||||
HighDpi() = delete;
|
||||
HighDpi(const HighDpi &) = delete;
|
||||
HighDpi &operator=(const HighDpi &) = delete;
|
||||
HighDpi(HighDpi &&) = delete;
|
||||
HighDpi &operator=(HighDpi &&) = delete;
|
||||
~HighDpi() = delete;
|
||||
|
||||
static int manhattanDelta(const QPoint &p1, const QPoint p2)
|
||||
{
|
||||
return (p1 - p2).manhattanLength();
|
||||
}
|
||||
|
||||
static bool fuzzyCompare(const QPoint &p1, const QPoint p2, int fuzz)
|
||||
{
|
||||
return manhattanDelta(p1, p2) <= fuzz;
|
||||
}
|
||||
|
||||
static QByteArray msgPointMismatch(const QPoint &p1, const QPoint p2)
|
||||
{
|
||||
return QByteArray::number(p1.x()) + ',' + QByteArray::number(p1.y())
|
||||
+ " != " + QByteArray::number(p2.x()) + ',' + QByteArray::number(p2.y())
|
||||
+ ", manhattanLength=" + QByteArray::number(manhattanDelta(p1, p2));
|
||||
}
|
||||
|
||||
// Compare a size that may go through scaling in the platform plugin with fuzz.
|
||||
|
||||
static inline int manhattanDelta(const QSize &s1, const QSize &s2)
|
||||
{
|
||||
return qAbs(s1.width() - s2.width()) + qAbs(s1.height() - s2.height());
|
||||
}
|
||||
|
||||
static inline bool fuzzyCompare(const QSize &s1, const QSize &s2, int fuzz)
|
||||
{
|
||||
return manhattanDelta(s1, s2) <= fuzz;
|
||||
}
|
||||
|
||||
static QByteArray msgSizeMismatch(const QSize &s1, const QSize &s2)
|
||||
{
|
||||
return QByteArray::number(s1.width()) + 'x' + QByteArray::number(s1.height())
|
||||
+ " != " + QByteArray::number(s2.width()) + 'x' + QByteArray::number(s2.height())
|
||||
+ ", manhattanLength=" + QByteArray::number(manhattanDelta(s1, s2));
|
||||
}
|
||||
|
||||
// Compare a geometry that may go through scaling in the platform plugin with fuzz.
|
||||
|
||||
static inline bool fuzzyCompare(const QRect &r1, const QRect &r2, int fuzz)
|
||||
{
|
||||
return manhattanDelta(r1.topLeft(), r2.topLeft()) <= fuzz
|
||||
&& manhattanDelta(r1.size(), r2.size()) <= fuzz;
|
||||
}
|
||||
|
||||
static QByteArray msgRectMismatch(const QRect &r1, const QRect &r2)
|
||||
{
|
||||
return formatRect(r1) + " != " + formatRect(r2);
|
||||
}
|
||||
|
||||
private:
|
||||
static QByteArray formatRect(const QRect &r)
|
||||
{
|
||||
return QByteArray::number(r.width()) + 'x' + QByteArray::number(r.height())
|
||||
+ (r.left() < 0 ? '-' : '+') + QByteArray::number(r.left())
|
||||
+ (r.top() < 0 ? '-' : '+') + QByteArray::number(r.top());
|
||||
}
|
||||
};
|
||||
|
||||
#endif // HIGHDPI_H
|
@ -26,6 +26,7 @@
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "../../../shared/highdpi.h"
|
||||
|
||||
#include <qboxlayout.h>
|
||||
#include <qapplication.h>
|
||||
@ -140,19 +141,6 @@ static QByteArray msgComparisonFailed(T v1, const char *op, T v2)
|
||||
return s.toLocal8Bit();
|
||||
}
|
||||
|
||||
// Compare a window position that may go through scaling in the platform plugin with fuzz.
|
||||
static inline bool qFuzzyCompareWindowPosition(const QPoint &p1, const QPoint p2, int fuzz)
|
||||
{
|
||||
return (p1 - p2).manhattanLength() <= fuzz;
|
||||
}
|
||||
|
||||
static QString msgPointMismatch(const QPoint &p1, const QPoint p2)
|
||||
{
|
||||
QString result;
|
||||
QDebug(&result) << p1 << "!=" << p2 << ", manhattanLength=" << (p1 - p2).manhattanLength();
|
||||
return result;
|
||||
}
|
||||
|
||||
class tst_QWidget : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
@ -416,6 +404,7 @@ private:
|
||||
QPoint m_safeCursorPos;
|
||||
const bool m_windowsAnimationsEnabled;
|
||||
QTouchDevice *m_touchScreen;
|
||||
const int m_fuzz;
|
||||
};
|
||||
|
||||
bool tst_QWidget::ensureScreenSize(int width, int height)
|
||||
@ -574,6 +563,7 @@ tst_QWidget::tst_QWidget()
|
||||
, m_safeCursorPos(0, 0)
|
||||
, m_windowsAnimationsEnabled(windowsAnimationsEnabled())
|
||||
, m_touchScreen(QTest::createTouchDevice())
|
||||
, m_fuzz(int(QGuiApplication::primaryScreen()->devicePixelRatio()))
|
||||
{
|
||||
if (m_windowsAnimationsEnabled) // Disable animations which can interfere with screen grabbing in moveChild(), showAndMoveChild()
|
||||
setWindowsAnimationsEnabled(false);
|
||||
@ -2047,10 +2037,9 @@ void tst_QWidget::windowState()
|
||||
|
||||
widget1.setWindowState(widget1.windowState() ^ Qt::WindowMaximized);
|
||||
QTest::qWait(100);
|
||||
const int fuzz = int(QHighDpiScaling::factor(widget1.windowHandle()));
|
||||
QVERIFY(!(widget1.windowState() & Qt::WindowMaximized));
|
||||
QTRY_VERIFY2(qFuzzyCompareWindowPosition(widget1.pos(), pos, fuzz),
|
||||
qPrintable(msgPointMismatch(widget1.pos(), pos)));
|
||||
QTRY_VERIFY2(HighDpi::fuzzyCompare(widget1.pos(), pos, m_fuzz),
|
||||
qPrintable(HighDpi::msgPointMismatch(widget1.pos(), pos)));
|
||||
QCOMPARE(widget1.windowHandle()->windowState(), Qt::WindowNoState);
|
||||
|
||||
widget1.setWindowState(Qt::WindowMinimized);
|
||||
@ -2071,8 +2060,8 @@ void tst_QWidget::windowState()
|
||||
widget1.setWindowState(widget1.windowState() ^ Qt::WindowMaximized);
|
||||
QTest::qWait(100);
|
||||
QVERIFY(!(widget1.windowState() & (Qt::WindowMinimized|Qt::WindowMaximized)));
|
||||
QTRY_VERIFY2(qFuzzyCompareWindowPosition(widget1.pos(), pos, fuzz),
|
||||
qPrintable(msgPointMismatch(widget1.pos(), pos)));
|
||||
QTRY_VERIFY2(HighDpi::fuzzyCompare(widget1.pos(), pos, m_fuzz),
|
||||
qPrintable(HighDpi::msgPointMismatch(widget1.pos(), pos)));
|
||||
QCOMPARE(widget1.windowHandle()->windowState(), Qt::WindowNoState);
|
||||
|
||||
widget1.setWindowState(Qt::WindowFullScreen);
|
||||
@ -2093,8 +2082,8 @@ void tst_QWidget::windowState()
|
||||
widget1.setWindowState(Qt::WindowNoState);
|
||||
QTest::qWait(100);
|
||||
VERIFY_STATE(Qt::WindowNoState);
|
||||
QTRY_VERIFY2(qFuzzyCompareWindowPosition(widget1.pos(), pos, fuzz),
|
||||
qPrintable(msgPointMismatch(widget1.pos(), pos)));
|
||||
QTRY_VERIFY2(HighDpi::fuzzyCompare(widget1.pos(), pos, m_fuzz),
|
||||
qPrintable(HighDpi::msgPointMismatch(widget1.pos(), pos)));
|
||||
QCOMPARE(widget1.windowHandle()->windowState(), Qt::WindowNoState);
|
||||
|
||||
widget1.setWindowState(Qt::WindowFullScreen);
|
||||
@ -2127,8 +2116,8 @@ void tst_QWidget::windowState()
|
||||
QVERIFY(!(widget1.windowState() & stateMask));
|
||||
QCOMPARE(widget1.windowHandle()->windowState(), Qt::WindowNoState);
|
||||
|
||||
QTRY_VERIFY2(qFuzzyCompareWindowPosition(widget1.pos(), pos, fuzz),
|
||||
qPrintable(msgPointMismatch(widget1.pos(), pos)));
|
||||
QTRY_VERIFY2(HighDpi::fuzzyCompare(widget1.pos(), pos, m_fuzz),
|
||||
qPrintable(HighDpi::msgPointMismatch(widget1.pos(), pos)));
|
||||
QTRY_COMPARE(widget1.size(), size);
|
||||
}
|
||||
|
||||
@ -2321,7 +2310,7 @@ void tst_QWidget::resizeEvent()
|
||||
{
|
||||
QWidget wParent;
|
||||
wParent.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
|
||||
wParent.resize(200, 200);
|
||||
wParent.resize(m_testWidgetSize);
|
||||
ResizeWidget wChild(&wParent);
|
||||
wParent.show();
|
||||
QVERIFY(QTest::qWaitForWindowExposed(&wParent));
|
||||
@ -2339,7 +2328,7 @@ void tst_QWidget::resizeEvent()
|
||||
{
|
||||
ResizeWidget wTopLevel;
|
||||
wTopLevel.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
|
||||
wTopLevel.resize(200, 200);
|
||||
wTopLevel.resize(m_testWidgetSize);
|
||||
wTopLevel.show();
|
||||
QVERIFY(QTest::qWaitForWindowExposed(&wTopLevel));
|
||||
if (m_platform == QStringLiteral("winrt"))
|
||||
@ -2377,17 +2366,20 @@ void tst_QWidget::showMinimized()
|
||||
#ifdef Q_OS_WINRT
|
||||
QEXPECT_FAIL("", "Winrt does not support move and resize", Abort);
|
||||
#endif
|
||||
QCOMPARE(plain.pos(), pos);
|
||||
QVERIFY2(HighDpi::fuzzyCompare(plain.pos(), pos, m_fuzz),
|
||||
qPrintable(HighDpi::msgPointMismatch(plain.pos(), pos)));
|
||||
|
||||
plain.showNormal();
|
||||
QVERIFY(!plain.isMinimized());
|
||||
QVERIFY(plain.isVisible());
|
||||
QCOMPARE(plain.pos(), pos);
|
||||
QVERIFY2(HighDpi::fuzzyCompare(plain.pos(), pos, m_fuzz),
|
||||
qPrintable(HighDpi::msgPointMismatch(plain.pos(), pos)));
|
||||
|
||||
plain.showMinimized();
|
||||
QVERIFY(plain.isMinimized());
|
||||
QVERIFY(plain.isVisible());
|
||||
QCOMPARE(plain.pos(), pos);
|
||||
QVERIFY2(HighDpi::fuzzyCompare(plain.pos(), pos, m_fuzz),
|
||||
qPrintable(HighDpi::msgPointMismatch(plain.pos(), pos)));
|
||||
|
||||
plain.hide();
|
||||
QVERIFY(plain.isMinimized());
|
||||
@ -2779,7 +2771,9 @@ void tst_QWidget::setGeometry()
|
||||
tlw.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
|
||||
QWidget child(&tlw);
|
||||
|
||||
QRect tr(100,100,200,200);
|
||||
const QPoint topLeft = QGuiApplication::primaryScreen()->availableGeometry().topLeft();
|
||||
const QSize initialSize = 2 * m_testWidgetSize;
|
||||
QRect tr(topLeft + QPoint(100,100), initialSize);
|
||||
QRect cr(50,50,50,50);
|
||||
tlw.setGeometry(tr);
|
||||
child.setGeometry(cr);
|
||||
@ -2790,8 +2784,7 @@ void tst_QWidget::setGeometry()
|
||||
QCOMPARE(child.geometry(), cr);
|
||||
|
||||
tlw.setParent(nullptr, Qt::Window|Qt::FramelessWindowHint);
|
||||
tr = QRect(0,0,100,100);
|
||||
tr.moveTopLeft(QGuiApplication::primaryScreen()->availableGeometry().topLeft());
|
||||
tr = QRect(topLeft, initialSize / 2);
|
||||
tlw.setGeometry(tr);
|
||||
QCOMPARE(tlw.geometry(), tr);
|
||||
tlw.showNormal();
|
||||
@ -3263,7 +3256,8 @@ void tst_QWidget::saveRestoreGeometry()
|
||||
|
||||
if (m_platform == QStringLiteral("winrt"))
|
||||
QEXPECT_FAIL("", "WinRT does not support move/resize", Abort);
|
||||
QTRY_COMPARE(widget.pos(), position);
|
||||
QTRY_VERIFY2(HighDpi::fuzzyCompare(widget.pos(), position, m_fuzz),
|
||||
qPrintable(HighDpi::msgPointMismatch(widget.pos(), position)));
|
||||
QCOMPARE(widget.size(), size);
|
||||
savedGeometry = widget.saveGeometry();
|
||||
}
|
||||
@ -3291,10 +3285,12 @@ void tst_QWidget::saveRestoreGeometry()
|
||||
QVERIFY(QTest::qWaitForWindowExposed(&widget));
|
||||
QApplication::processEvents();
|
||||
|
||||
QTRY_COMPARE(widget.pos(), position);
|
||||
QVERIFY2(HighDpi::fuzzyCompare(widget.pos(), position, m_fuzz),
|
||||
qPrintable(HighDpi::msgPointMismatch(widget.pos(), position)));
|
||||
QCOMPARE(widget.size(), size);
|
||||
widget.show();
|
||||
QCOMPARE(widget.pos(), position);
|
||||
QVERIFY2(HighDpi::fuzzyCompare(widget.pos(), position, m_fuzz),
|
||||
qPrintable(HighDpi::msgPointMismatch(widget.pos(), position)));
|
||||
QCOMPARE(widget.size(), size);
|
||||
}
|
||||
|
||||
@ -3408,6 +3404,9 @@ void tst_QWidget::restoreVersion1Geometry()
|
||||
QFETCH(QSize, expectedSize);
|
||||
QFETCH(QRect, expectedNormalGeometry);
|
||||
|
||||
if (m_platform == QLatin1String("windows") && QGuiApplication::primaryScreen()->geometry().width() > 2000)
|
||||
QSKIP("Skipping due to minimum decorated window size on Windows");
|
||||
|
||||
// WindowActive is uninteresting for this test
|
||||
const Qt::WindowStates WindowStateMask = Qt::WindowFullScreen | Qt::WindowMaximized | Qt::WindowMinimized;
|
||||
|
||||
@ -4988,7 +4987,8 @@ void tst_QWidget::windowMoveResize()
|
||||
widget.showNormal();
|
||||
|
||||
QTest::qWait(10);
|
||||
QTRY_COMPARE(widget.pos(), rect.topLeft());
|
||||
QTRY_VERIFY2(HighDpi::fuzzyCompare(widget.pos(), rect.topLeft(), m_fuzz),
|
||||
qPrintable(HighDpi::msgPointMismatch(widget.pos(), rect.topLeft())));
|
||||
// Windows: Minimum size of decorated windows.
|
||||
const bool expectResizeFail = (!windowFlags && (rect.width() < 160 || rect.height() < 40))
|
||||
&& m_platform == QStringLiteral("windows");
|
||||
|
Loading…
x
Reference in New Issue
Block a user