Windows QPA: Fix wrong scaling of fixed size in window creation phase

When a fixed size the window is moved to another screen
by QPlatformWindow::initialGeometry(), the size constraints
would be incorrectly scaled using the initial screen in the handling of
WM_GETMINMAXINFO.
To fix this, pass the resulting screen out of QPlatformWindow::initialGeometry()
and use it during the window creation phase.

Fixes: QTBUG-77307
Change-Id: I149a2a65e816da841a32abc14a495925bf9cc6f6
Reviewed-by: André de la Rocha <andre.rocha@qt.io>
Reviewed-by: Morten Johan Sørvig <morten.sorvig@qt.io>
This commit is contained in:
Friedemann Kleint 2019-11-01 11:15:32 +01:00
parent 1dd83dd202
commit 8f2db974ab
4 changed files with 44 additions and 16 deletions

View File

@ -694,9 +694,12 @@ static QSize fixInitialSize(QSize size, const QWindow *w,
However if the given window already has geometry which the application has However if the given window already has geometry which the application has
initialized, it takes priority. initialized, it takes priority.
*/ */
QRect QPlatformWindow::initialGeometry(const QWindow *w, QRect QPlatformWindow::initialGeometry(const QWindow *w, const QRect &initialGeometry,
const QRect &initialGeometry, int defaultWidth, int defaultHeight) int defaultWidth, int defaultHeight,
const QScreen **resultingScreenReturn)
{ {
if (resultingScreenReturn)
*resultingScreenReturn = w->screen();
if (!w->isTopLevel()) { if (!w->isTopLevel()) {
const qreal factor = QHighDpiScaling::factor(w); const qreal factor = QHighDpiScaling::factor(w);
const QSize size = fixInitialSize(QHighDpi::fromNative(initialGeometry.size(), factor), const QSize size = fixInitialSize(QHighDpi::fromNative(initialGeometry.size(), factor),
@ -712,6 +715,8 @@ QRect QPlatformWindow::initialGeometry(const QWindow *w,
: QGuiApplication::screenAt(initialGeometry.center()); : QGuiApplication::screenAt(initialGeometry.center());
if (!screen) if (!screen)
return initialGeometry; return initialGeometry;
if (resultingScreenReturn)
*resultingScreenReturn = screen;
// initialGeometry refers to window's screen // initialGeometry refers to window's screen
QRect rect(QHighDpi::fromNativePixels(initialGeometry, w)); QRect rect(QHighDpi::fromNativePixels(initialGeometry, w));
if (wp->resizeAutomatic) if (wp->resizeAutomatic)

View File

@ -63,6 +63,7 @@ QT_BEGIN_NAMESPACE
class QPlatformScreen; class QPlatformScreen;
class QPlatformWindowPrivate; class QPlatformWindowPrivate;
class QScreen;
class QWindow; class QWindow;
class QIcon; class QIcon;
class QRegion; class QRegion;
@ -142,8 +143,9 @@ public:
virtual void invalidateSurface(); virtual void invalidateSurface();
static QRect initialGeometry(const QWindow *w, static QRect initialGeometry(const QWindow *w, const QRect &initialGeometry,
const QRect &initialGeometry, int defaultWidth, int defaultHeight); int defaultWidth, int defaultHeight,
const QScreen **resultingScreenReturn = nullptr);
virtual void requestUpdate(); virtual void requestUpdate();
bool hasPendingUpdateRequest() const; bool hasPendingUpdateRequest() const;

View File

@ -759,7 +759,10 @@ QWindowsWindowData
const QString windowClassName = QWindowsContext::instance()->registerWindowClass(w); const QString windowClassName = QWindowsContext::instance()->registerWindowClass(w);
const QRect rect = QPlatformWindow::initialGeometry(w, data.geometry, defaultWindowWidth, defaultWindowHeight); const QScreen *screen{};
const QRect rect = QPlatformWindow::initialGeometry(w, data.geometry,
defaultWindowWidth, defaultWindowHeight,
&screen);
if (title.isEmpty() && (result.flags & Qt::WindowTitleHint)) if (title.isEmpty() && (result.flags & Qt::WindowTitleHint))
title = topLevel ? qAppName() : w->objectName(); title = topLevel ? qAppName() : w->objectName();
@ -769,7 +772,9 @@ QWindowsWindowData
// Capture events before CreateWindowEx() returns. The context is cleared in // Capture events before CreateWindowEx() returns. The context is cleared in
// the QWindowsWindow constructor. // the QWindowsWindow constructor.
const QWindowCreationContextPtr context(new QWindowCreationContext(w, data.geometry, rect, data.customMargins, style, exStyle)); const QWindowCreationContextPtr context(new QWindowCreationContext(w, screen, data.geometry,
rect, data.customMargins,
style, exStyle));
QWindowsContext::instance()->setWindowCreationContext(context); QWindowsContext::instance()->setWindowCreationContext(context);
const bool hasFrame = (style & (WS_DLGFRAME | WS_THICKFRAME)); const bool hasFrame = (style & (WS_DLGFRAME | WS_THICKFRAME));
@ -879,10 +884,10 @@ void WindowCreationData::initialize(const QWindow *w, HWND hwnd, bool frameChang
// Scaling helpers for size constraints. // Scaling helpers for size constraints.
static QSize toNativeSizeConstrained(QSize dip, const QWindow *w) static QSize toNativeSizeConstrained(QSize dip, const QScreen *s)
{ {
if (QHighDpiScaling::isActive()) { if (QHighDpiScaling::isActive()) {
const qreal factor = QHighDpiScaling::factor(w); const qreal factor = QHighDpiScaling::factor(s);
if (!qFuzzyCompare(factor, qreal(1))) { if (!qFuzzyCompare(factor, qreal(1))) {
if (dip.width() > 0 && dip.width() < QWINDOWSIZE_MAX) if (dip.width() > 0 && dip.width() < QWINDOWSIZE_MAX)
dip.setWidth(qRound(qreal(dip.width()) * factor)); dip.setWidth(qRound(qreal(dip.width()) * factor));
@ -995,11 +1000,12 @@ bool QWindowsGeometryHint::handleCalculateSize(const QMargins &customMargins, co
return true; return true;
} }
void QWindowsGeometryHint::frameSizeConstraints(const QWindow *w, const QMargins &margins, void QWindowsGeometryHint::frameSizeConstraints(const QWindow *w, const QScreen *screen,
const QMargins &margins,
QSize *minimumSize, QSize *maximumSize) QSize *minimumSize, QSize *maximumSize)
{ {
*minimumSize = toNativeSizeConstrained(w->minimumSize(), w); *minimumSize = toNativeSizeConstrained(w->minimumSize(), screen);
*maximumSize = toNativeSizeConstrained(w->maximumSize(), w); *maximumSize = toNativeSizeConstrained(w->maximumSize(), screen);
const int maximumWidth = qMax(maximumSize->width(), minimumSize->width()); const int maximumWidth = qMax(maximumSize->width(), minimumSize->width());
const int maximumHeight = qMax(maximumSize->height(), minimumSize->height()); const int maximumHeight = qMax(maximumSize->height(), minimumSize->height());
@ -1017,12 +1023,13 @@ void QWindowsGeometryHint::frameSizeConstraints(const QWindow *w, const QMargins
} }
void QWindowsGeometryHint::applyToMinMaxInfo(const QWindow *w, void QWindowsGeometryHint::applyToMinMaxInfo(const QWindow *w,
const QScreen *screen,
const QMargins &margins, const QMargins &margins,
MINMAXINFO *mmi) MINMAXINFO *mmi)
{ {
QSize minimumSize; QSize minimumSize;
QSize maximumSize; QSize maximumSize;
frameSizeConstraints(w, margins, &minimumSize, &maximumSize); frameSizeConstraints(w, screen, margins, &minimumSize, &maximumSize);
qCDebug(lcQpaWindows).nospace() << '>' << __FUNCTION__ << '<' << " min=" qCDebug(lcQpaWindows).nospace() << '>' << __FUNCTION__ << '<' << " min="
<< minimumSize.width() << ',' << minimumSize.height() << minimumSize.width() << ',' << minimumSize.height()
<< " max=" << maximumSize.width() << ',' << maximumSize.height() << " max=" << maximumSize.width() << ',' << maximumSize.height()
@ -1041,6 +1048,13 @@ void QWindowsGeometryHint::applyToMinMaxInfo(const QWindow *w,
qCDebug(lcQpaWindows).nospace() << '<' << __FUNCTION__ << " out " << *mmi; qCDebug(lcQpaWindows).nospace() << '<' << __FUNCTION__ << " out " << *mmi;
} }
void QWindowsGeometryHint::applyToMinMaxInfo(const QWindow *w,
const QMargins &margins,
MINMAXINFO *mmi)
{
applyToMinMaxInfo(w, w->screen(), margins, mmi);
}
bool QWindowsGeometryHint::positionIncludesFrame(const QWindow *w) bool QWindowsGeometryHint::positionIncludesFrame(const QWindow *w)
{ {
return qt_window_private(const_cast<QWindow *>(w))->positionPolicy return qt_window_private(const_cast<QWindow *>(w))->positionPolicy
@ -1226,11 +1240,12 @@ void QWindowsForeignWindow::setVisible(bool visible)
\ingroup qt-lighthouse-win \ingroup qt-lighthouse-win
*/ */
QWindowCreationContext::QWindowCreationContext(const QWindow *w, QWindowCreationContext::QWindowCreationContext(const QWindow *w, const QScreen *s,
const QRect &geometryIn, const QRect &geometry, const QRect &geometryIn, const QRect &geometry,
const QMargins &cm, const QMargins &cm,
DWORD style, DWORD exStyle) : DWORD style, DWORD exStyle) :
window(w), window(w),
screen(s),
requestedGeometryIn(geometryIn), requestedGeometryIn(geometryIn),
requestedGeometry(geometry), requestedGeometry(geometry),
obtainedPos(geometryIn.topLeft()), obtainedPos(geometryIn.topLeft()),
@ -1270,7 +1285,7 @@ QWindowCreationContext::QWindowCreationContext(const QWindow *w,
void QWindowCreationContext::applyToMinMaxInfo(MINMAXINFO *mmi) const void QWindowCreationContext::applyToMinMaxInfo(MINMAXINFO *mmi) const
{ {
QWindowsGeometryHint::applyToMinMaxInfo(window, margins + customMargins, mmi); QWindowsGeometryHint::applyToMinMaxInfo(window, screen, margins + customMargins, mmi);
} }
/*! /*!

View File

@ -66,9 +66,12 @@ struct QWindowsGeometryHint
static QMargins frame(const QWindow *w, const QRect &geometry, static QMargins frame(const QWindow *w, const QRect &geometry,
DWORD style, DWORD exStyle); DWORD style, DWORD exStyle);
static bool handleCalculateSize(const QMargins &customMargins, const MSG &msg, LRESULT *result); static bool handleCalculateSize(const QMargins &customMargins, const MSG &msg, LRESULT *result);
static void applyToMinMaxInfo(const QWindow *w, const QScreen *screen,
const QMargins &margins, MINMAXINFO *mmi);
static void applyToMinMaxInfo(const QWindow *w, const QMargins &margins, static void applyToMinMaxInfo(const QWindow *w, const QMargins &margins,
MINMAXINFO *mmi); MINMAXINFO *mmi);
static void frameSizeConstraints(const QWindow *w, const QMargins &margins, static void frameSizeConstraints(const QWindow *w, const QScreen *screen,
const QMargins &margins,
QSize *minimumSize, QSize *maximumSize); QSize *minimumSize, QSize *maximumSize);
static inline QPoint mapToGlobal(HWND hwnd, const QPoint &); static inline QPoint mapToGlobal(HWND hwnd, const QPoint &);
static inline QPoint mapToGlobal(const QWindow *w, const QPoint &); static inline QPoint mapToGlobal(const QWindow *w, const QPoint &);
@ -80,13 +83,16 @@ struct QWindowsGeometryHint
struct QWindowCreationContext struct QWindowCreationContext
{ {
explicit QWindowCreationContext(const QWindow *w, explicit QWindowCreationContext(const QWindow *w, const QScreen *s,
const QRect &geometryIn, const QRect &geometry, const QRect &geometryIn, const QRect &geometry,
const QMargins &customMargins, const QMargins &customMargins,
DWORD style, DWORD exStyle); DWORD style, DWORD exStyle);
void applyToMinMaxInfo(MINMAXINFO *mmi) const; void applyToMinMaxInfo(MINMAXINFO *mmi) const;
const QWindow *window; const QWindow *window;
// The screen to use to scale size constraints, etc. Might differ from the
// screen of the window after QPlatformWindow::initialGeometry() (QTBUG-77307).
const QScreen *screen;
QRect requestedGeometryIn; // QWindow scaled QRect requestedGeometryIn; // QWindow scaled
QRect requestedGeometry; // after QPlatformWindow::initialGeometry() QRect requestedGeometry; // after QPlatformWindow::initialGeometry()
QPoint obtainedPos; QPoint obtainedPos;