diff --git a/src/app/GUI/GradientWidgets/gradientslistwidget.cpp b/src/app/GUI/GradientWidgets/gradientslistwidget.cpp index 2a24a4931..e3bc35ac5 100755 --- a/src/app/GUI/GradientWidgets/gradientslistwidget.cpp +++ b/src/app/GUI/GradientWidgets/gradientslistwidget.cpp @@ -51,9 +51,9 @@ void GradientsListWidget::resizeEvent(QResizeEvent *e) { const QSize size = e->size(); mDisplayedGradients->setMinimumHeight(size.height()); mDisplayedGradients->updateHeight(); - const int scrollBarWidth = verticalScrollBar()->width(); + /*const int scrollBarWidth = verticalScrollBar()->width(); const int availableWidth = size.width() - scrollBarWidth; - mDisplayedGradients->setFixedWidth(availableWidth); + mDisplayedGradients->setFixedWidth(availableWidth);*/ } void GradientsListWidget::showEvent(QShowEvent *e) { diff --git a/src/app/GUI/alignwidget.cpp b/src/app/GUI/alignwidget.cpp index a2438890a..d487bc61e 100644 --- a/src/app/GUI/alignwidget.cpp +++ b/src/app/GUI/alignwidget.cpp @@ -29,6 +29,8 @@ #include #include +#include "GUI/global.h" + AlignWidget::AlignWidget(QWidget* const parent) : QWidget(parent) , mAlignPivot(nullptr) @@ -47,6 +49,7 @@ AlignWidget::AlignWidget(QWidget* const parent) combosLay->addWidget(new QLabel(tr("Align"))); mAlignPivot = new QComboBox(this); + mAlignPivot->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding); mAlignPivot->setFocusPolicy(Qt::NoFocus); mAlignPivot->addItem(tr("Geometry")); mAlignPivot->addItem(tr("Pivot")); @@ -54,6 +57,7 @@ AlignWidget::AlignWidget(QWidget* const parent) combosLay->addWidget(new QLabel(tr("Relative to"))); mRelativeTo = new QComboBox(this); + mRelativeTo->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding); mRelativeTo->setFocusPolicy(Qt::NoFocus); mRelativeTo->addItem(tr("Scene")); mRelativeTo->addItem(tr("Last Selected")); @@ -63,7 +67,7 @@ AlignWidget::AlignWidget(QWidget* const parent) mainLayout->addLayout(buttonsLay); mainLayout->addStretch(); - int buttonSize = 20; + int buttonSize = eSizesUI::button; const auto leftButton = new QPushButton(this); leftButton->setFocusPolicy(Qt::NoFocus); diff --git a/src/app/GUI/canvaswindowevents.cpp b/src/app/GUI/canvaswindowevents.cpp index 3a6a8d341..0c8b1d872 100755 --- a/src/app/GUI/canvaswindowevents.cpp +++ b/src/app/GUI/canvaswindowevents.cpp @@ -87,6 +87,7 @@ void CanvasWindow::fitCanvasToSize() translateView({(widWidth - canvasSize.width() * minScale) * 0.5, (widHeight - canvasSize.height() * minScale) * 0.5}); mViewTransform.scale(minScale, minScale); + update(); } void CanvasWindow::zoomInView() diff --git a/src/app/GUI/timelinedockwidget.cpp b/src/app/GUI/timelinedockwidget.cpp index 4cb999a8e..a4ccc1581 100755 --- a/src/app/GUI/timelinedockwidget.cpp +++ b/src/app/GUI/timelinedockwidget.cpp @@ -82,10 +82,6 @@ TimelineDockWidget::TimelineDockWidget(Document& document, mMainLayout->setSpacing(0); mMainLayout->setMargin(0); - const QSize iconSize(AppSupport::getSettings("ui", - "timelineToolbarIconSize", - QSize(24, 24)).toSize()); - mFrameRewindAct = new QAction(QIcon::fromTheme("rewind"), tr("Rewind"), this); @@ -203,8 +199,6 @@ TimelineDockWidget::TimelineDockWidget(Document& document, mToolBar = new QToolBar(this); mToolBar->setMovable(false); - mToolBar->setIconSize(iconSize); - mRenderProgress = new QProgressBar(this); mRenderProgress->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); diff --git a/src/app/GUI/welcomedialog.cpp b/src/app/GUI/welcomedialog.cpp index 5dedaecd4..233bffd8a 100755 --- a/src/app/GUI/welcomedialog.cpp +++ b/src/app/GUI/welcomedialog.cpp @@ -29,7 +29,6 @@ #include #include #include -#include #include "appsupport.h" @@ -64,30 +63,34 @@ WelcomeDialog::WelcomeDialog(QMenu *recentMenu, AppSupport::getAppName())); const auto buttonWid = new QWidget(this); + buttonWid->setContentsMargins(0, 0, 0, 0); const auto buttonLay = new QHBoxLayout(buttonWid); + buttonLay->setMargin(0); - const auto newButton = new QPushButton(/*QIcon::fromTheme("file_blank"),*/ - tr("New"), - this); - newButton->setObjectName("WelcomeNewButton"); + const auto newButton = new QPushButton(tr("New"), this); + newButton->setObjectName("WelcomeButton"); newButton->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding); connect(newButton, &QPushButton::released, newFunc); - const auto openButton = new QToolButton(this); - openButton->setObjectName("WelcomeOpenButton"); + const auto openButton = new QPushButton(this); + openButton->setObjectName("WelcomeButton"); openButton->setText(tr("Open")); - //openButton->setIcon(QIcon::fromTheme("file_folder")); openButton->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding); - //openButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); - openButton->setPopupMode(QToolButton::MenuButtonPopup); - openButton->setMenu(recentMenu); connect(openButton, &QPushButton::released, openFunc); + const auto recentButton = new QPushButton(tr("Open Recent"), this); + recentButton->setSizePolicy(QSizePolicy::Preferred, + QSizePolicy::Preferred); + recentButton->setContentsMargins(0, 0, 0, 0); + recentButton->setObjectName("WelcomeRecentButton"); + recentButton->setMenu(recentMenu); + thisLay->addWidget(mainWid, 0, Qt::AlignHCenter | Qt::AlignVCenter); sceneLay->addWidget(logoLabel); sceneLay->addWidget(buttonWid); + sceneLay->addWidget(recentButton); buttonLay->addWidget(newButton); buttonLay->addWidget(openButton); mainLay->addWidget(sceneWid); diff --git a/src/app/friction.qss b/src/app/friction.qss index 24b370d79..b3b8c5ec9 100644 --- a/src/app/friction.qss +++ b/src/app/friction.qss @@ -44,7 +44,8 @@ QToolBar#ViewerDrawBar, QComboBox#blendModeCombo, QWidget#menuBarWidget QPushButton, -QLineEdit#SearchLine { +QLineEdit#SearchLine, +AlignWidget QComboBox { background-color: rgb(23, 23, 28); } @@ -80,8 +81,7 @@ QSpinBox#SpinBoxNoButtons::down-button { width: 0; } -QPushButton#WelcomeNewButton, -QToolButton#WelcomeOpenButton { +QPushButton#WelcomeButton { padding: 0.25em; border: 2px solid #666; border-radius: 10%; @@ -89,20 +89,28 @@ QToolButton#WelcomeOpenButton { font-weight: bold; } -QPushButton#WelcomeNewButton:hover, -QToolButton#WelcomeOpenButton:hover { +QPushButton#WelcomeButton:hover { border-color: #ebebeb; } -QToolButton#WelcomeOpenButton::menu-button { - padding-right: 0.5em; - border-top-right: 2px solid #ebebeb; - border-bottom-right: 2px solid #ebebeb; - border-top-right-radius: 10%; - border-bottom-right-radius: 10%; +QPushButton#WelcomeRecentButton { + padding: 0.25em; + border: none; + border-radius: 10%; color: #ebebeb; + font-weight: bold; +} + +QPushButton#WelcomeRecentButton:hover { + border: 2px solid #ebebeb; } -QToolButton#WelcomeOpenButton[popupMode="1"] { - padding-right: 0.5em; +AlignWidget QPushButton { + background-color: none; + border: 0; + border-radius: 10%; +} + +QCheckBox::indicator:unchecked:hover { + background-color: rgb(112, 8, 10); } diff --git a/src/app/main.cpp b/src/app/main.cpp index c38e14a68..b9f0671a0 100755 --- a/src/app/main.cpp +++ b/src/app/main.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include "hardwareinfo.h" #include "Private/esettings.h" @@ -149,15 +150,17 @@ int main(int argc, char *argv[]) HardwareInfo::sGpuVendor()); OS_FONT = QApplication::font(); - eSizesUI::font.setEvaluator([/*&settings*/]() { + eSizesUI::font.setEvaluator([]() { + double dpi = (qApp->desktop()->logicalDpiX() / 96.0); + qDebug() << "DPI" << dpi; const auto fm = QFontMetrics(OS_FONT); - const qreal scaling = qBound(0.5, /*settings.fInterfaceScaling*/1.0, 1.5); + const qreal scaling = qBound(0.5, dpi, 1.5); return qRound(fm.height()*scaling); }); eSizesUI::widget.setEvaluator([]() { return eSizesUI::font.size()*4/3; }); - /*QObject::connect(&eSizesUI::font, &SizeSetter::sizeChanged, + QObject::connect(&eSizesUI::font, &SizeSetter::sizeChanged, &eSizesUI::widget, &SizeSetter::updateSize); eSizesUI::font.add(&app, [&app](const int size) { const auto fm = QFontMetrics(OS_FONT); @@ -169,7 +172,7 @@ int main(int argc, char *argv[]) font.setPixelSize(qRound(mult*OS_FONT.pixelSize())); } app.setFont(font); - });*/ + }); eSizesUI::widget.add(&eSizesUI::button, [](const int size) { eSizesUI::button.set(qRound(size*1.1)); diff --git a/src/patches/qt/README.md b/src/patches/qt/README.md index 7a8803084..8fa4e409b 100644 --- a/src/patches/qt/README.md +++ b/src/patches/qt/README.md @@ -1,4 +1,4 @@ # Qt 5.12.12 patches -Patches used in releases of Friction. +Patches used in Windows releases of Friction. diff --git a/src/patches/qt/hidpi.patch b/src/patches/qt/hidpi.patch new file mode 100644 index 000000000..baedfca4b --- /dev/null +++ b/src/patches/qt/hidpi.patch @@ -0,0 +1,2273 @@ +From 26a7cc5c8f97c0a4fc38d67fcf46da9648dd4f6d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Morten=20Johan=20S=C3=B8rvig?= +Date: Mon, 25 Apr 2016 09:27:48 +0200 +Subject: [PATCH 37/47] Compute logical DPI on a per-screen basis + +The logical DPI reported to applications is the platform screen +logical DPI divided by the platform screen scale factor. + +Use the screen in question when calculating the DPI instead of +the values from the main screen. + +QHighDpiScaling::logicalDpi now takes a QScreen pointer. + +Done-with: Friedemann Kleint +Task-number: QTBUG-53022 +Change-Id: I0f62b5878c37e3488e9a8cc48aef183ff822d0c4 +Reviewed-by: Friedemann Kleint +(cherry picked from commit dd9da0441b18d1946a7b3d28e4e8819b1921de6f) +--- + src/gui/kernel/qhighdpiscaling.cpp | 20 +++++++++----------- + src/gui/kernel/qhighdpiscaling_p.h | 2 +- + src/gui/kernel/qscreen.cpp | 6 +++--- + 3 files changed, 13 insertions(+), 15 deletions(-) + +diff --git a/src/gui/kernel/qhighdpiscaling.cpp b/src/gui/kernel/qhighdpiscaling.cpp +index 64f1397771..95790b96a9 100644 +--- a/src/gui/kernel/qhighdpiscaling.cpp ++++ b/src/gui/kernel/qhighdpiscaling.cpp +@@ -226,7 +226,6 @@ bool QHighDpiScaling::m_usePixelDensity = false; // use scale factor from platfo + bool QHighDpiScaling::m_pixelDensityScalingActive = false; // pixel density scale factor > 1 + bool QHighDpiScaling::m_globalScalingActive = false; // global scale factor is active + bool QHighDpiScaling::m_screenFactorSet = false; // QHighDpiScaling::setScreenFactor has been used +-QDpi QHighDpiScaling::m_logicalDpi = QDpi(-1,-1); // The scaled logical DPI of the primary screen + + /* + Initializes the QHighDpiScaling global variables. Called before the +@@ -314,14 +313,6 @@ void QHighDpiScaling::updateHighDpiScaling() + } + } + m_active = m_globalScalingActive || m_screenFactorSet || m_pixelDensityScalingActive; +- +- QScreen *primaryScreen = QGuiApplication::primaryScreen(); +- if (!primaryScreen) +- return; +- QPlatformScreen *platformScreen = primaryScreen->handle(); +- qreal sf = screenSubfactor(platformScreen); +- QDpi primaryDpi = platformScreen->logicalDpi(); +- m_logicalDpi = QDpi(primaryDpi.first / sf, primaryDpi.second / sf); + } + + /* +@@ -447,9 +438,16 @@ qreal QHighDpiScaling::screenSubfactor(const QPlatformScreen *screen) + return factor; + } + +-QDpi QHighDpiScaling::logicalDpi() ++QDpi QHighDpiScaling::logicalDpi(const QScreen *screen) + { +- return m_logicalDpi; ++ // (Note: m_active test is performed at call site.) ++ if (!screen) ++ return QDpi(96, 96); ++ ++ qreal platformScreenfactor = screenSubfactor(screen->handle()); ++ QDpi platformScreenDpi = screen->handle()->logicalDpi(); ++ return QDpi(platformScreenDpi.first / platformScreenfactor, ++ platformScreenDpi.second / platformScreenfactor); + } + + QHighDpiScaling::ScaleAndOrigin QHighDpiScaling::scaleAndOrigin(const QPlatformScreen *platformScreen, QPoint *nativePosition) +diff --git a/src/gui/kernel/qhighdpiscaling_p.h b/src/gui/kernel/qhighdpiscaling_p.h +index 674b737808..e578625305 100644 +--- a/src/gui/kernel/qhighdpiscaling_p.h ++++ b/src/gui/kernel/qhighdpiscaling_p.h +@@ -98,7 +98,7 @@ public: + static QPoint mapPositionToNative(const QPoint &pos, const QPlatformScreen *platformScreen); + static QPoint mapPositionToGlobal(const QPoint &pos, const QPoint &windowGlobalPosition, const QWindow *window); + static QPoint mapPositionFromGlobal(const QPoint &pos, const QPoint &windowGlobalPosition, const QWindow *window); +- static QDpi logicalDpi(); ++ static QDpi logicalDpi(const QScreen *screen); + + private: + static qreal screenSubfactor(const QPlatformScreen *screen); +diff --git a/src/gui/kernel/qscreen.cpp b/src/gui/kernel/qscreen.cpp +index f208eb02be..82ee62e6b4 100644 +--- a/src/gui/kernel/qscreen.cpp ++++ b/src/gui/kernel/qscreen.cpp +@@ -279,7 +279,7 @@ qreal QScreen::logicalDotsPerInchX() const + { + Q_D(const QScreen); + if (QHighDpiScaling::isActive()) +- return QHighDpiScaling::logicalDpi().first; ++ return QHighDpiScaling::logicalDpi(this).first; + return d->logicalDpi.first; + } + +@@ -295,7 +295,7 @@ qreal QScreen::logicalDotsPerInchY() const + { + Q_D(const QScreen); + if (QHighDpiScaling::isActive()) +- return QHighDpiScaling::logicalDpi().second; ++ return QHighDpiScaling::logicalDpi(this).second; + return d->logicalDpi.second; + } + +@@ -314,7 +314,7 @@ qreal QScreen::logicalDotsPerInchY() const + qreal QScreen::logicalDotsPerInch() const + { + Q_D(const QScreen); +- QDpi dpi = QHighDpiScaling::isActive() ? QHighDpiScaling::logicalDpi() : d->logicalDpi; ++ QDpi dpi = QHighDpiScaling::isActive() ? QHighDpiScaling::logicalDpi(this) : d->logicalDpi; + return (dpi.first + dpi.second) * qreal(0.5); + } + +-- +2.20.1.windows.1 + +From 328000e223dad2d9cf0f4a8bf9eadeed03303af1 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Morten=20Johan=20S=C3=B8rvig?= +Date: Mon, 25 Apr 2016 11:31:34 +0200 +Subject: [PATCH 38/47] Update Dpi and scale factor computation + +Remove pixelScale() in favor of logicalBaseDpi(). Compute scale factor +based on logical DPI and logical base DPI, or optionally based on the +physical DPI. + +Add policies for running the scale factor and adjusting the logical +DPI reported to the application. The policies are set via environment +variables: + + QT_SCALE_FACTOR_ROUNDING_POLICY=Round|Ceil|Floor|RoundPreferFloor|PassThrough + QT_DPI_ADJUSTMENT_POLICY=AdjustDpi|DontAdjustDpi|AdjustUpOnly + QT_USE_PHYSICAL_DPI=0|1 + +Done-with: Friedemann Kleint +Task-number: QTBUG-53022 +Change-Id: I4846f223186df665eb0a9c827eaef0a96d1f458f +Reviewed-by: Friedemann Kleint +(cherry picked from commit 900f2cb6f7070b4d426f3b83787ac489b8a2e827) +--- + src/gui/kernel/qhighdpiscaling.cpp | 234 ++++++++++++++++-- + src/gui/kernel/qhighdpiscaling_p.h | 29 +++ + src/gui/kernel/qplatformscreen.cpp | 14 ++ + src/gui/kernel/qplatformscreen.h | 1 + + .../android/qandroidplatformscreen.cpp | 8 +- + .../android/qandroidplatformscreen.h | 2 +- + src/plugins/platforms/cocoa/qcocoascreen.h | 1 + + .../platforms/windows/qwindowsscreen.cpp | 9 - + .../platforms/windows/qwindowsscreen.h | 2 +- + src/plugins/platforms/xcb/qxcbscreen.cpp | 13 - + src/plugins/platforms/xcb/qxcbscreen.h | 3 +- + tests/manual/highdpi/highdpi.pro | 1 + + 12 files changed, 264 insertions(+), 53 deletions(-) + +diff --git a/src/gui/kernel/qhighdpiscaling.cpp b/src/gui/kernel/qhighdpiscaling.cpp +index 95790b96a9..7ffbfbe1e5 100644 +--- a/src/gui/kernel/qhighdpiscaling.cpp ++++ b/src/gui/kernel/qhighdpiscaling.cpp +@@ -46,6 +46,9 @@ + #include + + #include ++#include ++ ++#include + + QT_BEGIN_NAMESPACE + +@@ -56,6 +59,18 @@ static const char legacyDevicePixelEnvVar[] = "QT_DEVICE_PIXEL_RATIO"; + static const char scaleFactorEnvVar[] = "QT_SCALE_FACTOR"; + static const char autoScreenEnvVar[] = "QT_AUTO_SCREEN_SCALE_FACTOR"; + static const char screenFactorsEnvVar[] = "QT_SCREEN_SCALE_FACTORS"; ++static const char scaleFactorRoundingPolicyEnvVar[] = "QT_SCALE_FACTOR_ROUNDING_POLICY"; ++static const char dpiAdjustmentPolicyEnvVar[] = "QT_DPI_ADJUSTMENT_POLICY"; ++static const char usePhysicalDpiEnvVar[] = "QT_USE_PHYSICAL_DPI"; ++ ++// Reads and interprets the given environment variable as a bool, ++// returns the default value if not set. ++static bool qEnvironmentVariableAsBool(const char *name, bool defaultValue) ++{ ++ bool ok = false; ++ int value = qEnvironmentVariableIntValue(name, &ok); ++ return ok ? value > 0 : defaultValue; ++} + + static inline qreal initialGlobalScaleFactor() + { +@@ -249,6 +264,191 @@ static inline bool usePixelDensity() + qgetenv(legacyDevicePixelEnvVar).compare("auto", Qt::CaseInsensitive) == 0); + } + ++qreal QHighDpiScaling::rawScaleFactor(const QPlatformScreen *screen) ++{ ++ // Determine if physical DPI should be used ++ static const bool usePhysicalDpi = qEnvironmentVariableAsBool(usePhysicalDpiEnvVar, false); ++ ++ // Calculate scale factor beased on platform screen DPI values ++ qreal factor; ++ QDpi platformBaseDpi = screen->logicalBaseDpi(); ++ if (usePhysicalDpi) { ++ qreal platformPhysicalDpi = screen->screen()->physicalDotsPerInch(); ++ factor = qreal(platformPhysicalDpi) / qreal(platformBaseDpi.first); ++ } else { ++ QDpi platformLogicalDpi = screen->logicalDpi(); ++ factor = qreal(platformLogicalDpi.first) / qreal(platformBaseDpi.first); ++ } ++ ++ return factor; ++} ++ ++template ++struct EnumLookup ++{ ++ const char *name; ++ EnumType value; ++}; ++ ++template ++static bool operator==(const EnumLookup &e1, const EnumLookup &e2) ++{ ++ return qstricmp(e1.name, e2.name) == 0; ++} ++ ++template ++static QByteArray joinEnumValues(const EnumLookup *i1, const EnumLookup *i2) ++{ ++ QByteArray result; ++ for (; i1 < i2; ++i1) { ++ if (!result.isEmpty()) ++ result += QByteArrayLiteral(", "); ++ result += i1->name; ++ } ++ return result; ++} ++ ++using ScaleFactorRoundingPolicyLookup = EnumLookup; ++ ++static const ScaleFactorRoundingPolicyLookup scaleFactorRoundingPolicyLookup[] = ++{ ++ {"Round", QHighDpiScaling::HighDpiScaleFactorRoundingPolicy::Round}, ++ {"Ceil", QHighDpiScaling::HighDpiScaleFactorRoundingPolicy::Ceil}, ++ {"Floor", QHighDpiScaling::HighDpiScaleFactorRoundingPolicy::Floor}, ++ {"RoundPreferFloor", QHighDpiScaling::HighDpiScaleFactorRoundingPolicy::RoundPreferFloor}, ++ {"PassThrough", QHighDpiScaling::HighDpiScaleFactorRoundingPolicy::PassThrough} ++}; ++ ++static QHighDpiScaling::HighDpiScaleFactorRoundingPolicy ++ lookupScaleFactorRoundingPolicy(const QByteArray &v) ++{ ++ auto end = std::end(scaleFactorRoundingPolicyLookup); ++ auto it = std::find(std::begin(scaleFactorRoundingPolicyLookup), end, ++ ScaleFactorRoundingPolicyLookup{v.constData(), QHighDpiScaling::HighDpiScaleFactorRoundingPolicy::Unset}); ++ return it != end ? it->value : QHighDpiScaling::HighDpiScaleFactorRoundingPolicy::Unset; ++} ++ ++using DpiAdjustmentPolicyLookup = EnumLookup; ++ ++static const DpiAdjustmentPolicyLookup dpiAdjustmentPolicyLookup[] = ++{ ++ {"AdjustDpi", QHighDpiScaling::DpiAdjustmentPolicy::Enabled}, ++ {"DontAdjustDpi", QHighDpiScaling::DpiAdjustmentPolicy::Disabled}, ++ {"AdjustUpOnly", QHighDpiScaling::DpiAdjustmentPolicy::UpOnly} ++}; ++ ++static QHighDpiScaling::DpiAdjustmentPolicy ++ lookupDpiAdjustmentPolicy(const QByteArray &v) ++{ ++ auto end = std::end(dpiAdjustmentPolicyLookup); ++ auto it = std::find(std::begin(dpiAdjustmentPolicyLookup), end, ++ DpiAdjustmentPolicyLookup{v.constData(), QHighDpiScaling::DpiAdjustmentPolicy::Unset}); ++ return it != end ? it->value : QHighDpiScaling::DpiAdjustmentPolicy::Unset; ++} ++ ++qreal QHighDpiScaling::roundScaleFactor(qreal rawFactor) ++{ ++ // Apply scale factor rounding policy. Using mathematically correct rounding ++ // may not give the most desirable visual results, especially for ++ // critical fractions like .5. In general, rounding down results in visual ++ // sizes that are smaller than the ideal size, and opposite for rounding up. ++ // Rounding down is then preferable since "small UI" is a more acceptable ++ // high-DPI experience than "large UI". ++ static auto scaleFactorRoundingPolicy = HighDpiScaleFactorRoundingPolicy::Unset; ++ ++ // Determine rounding policy ++ if (scaleFactorRoundingPolicy == HighDpiScaleFactorRoundingPolicy::Unset) { ++ // Check environment ++ if (qEnvironmentVariableIsSet(scaleFactorRoundingPolicyEnvVar)) { ++ QByteArray policyText = qgetenv(scaleFactorRoundingPolicyEnvVar); ++ auto policyEnumValue = lookupScaleFactorRoundingPolicy(policyText); ++ if (policyEnumValue != HighDpiScaleFactorRoundingPolicy::Unset) { ++ scaleFactorRoundingPolicy = policyEnumValue; ++ } else { ++ auto values = joinEnumValues(std::begin(scaleFactorRoundingPolicyLookup), ++ std::end(scaleFactorRoundingPolicyLookup)); ++ qWarning("Unknown scale factor rounding policy: %s. Supported values are: %s.", ++ policyText.constData(), values.constData()); ++ } ++ } else { ++ // Set default policy if no environment variable is set. ++ scaleFactorRoundingPolicy = HighDpiScaleFactorRoundingPolicy::RoundPreferFloor; ++ } ++ } ++ ++ // Apply rounding policy. ++ qreal roundedFactor = rawFactor; ++ switch (scaleFactorRoundingPolicy) { ++ case HighDpiScaleFactorRoundingPolicy::Round: ++ roundedFactor = qRound(rawFactor); ++ break; ++ case HighDpiScaleFactorRoundingPolicy::Ceil: ++ roundedFactor = qCeil(rawFactor); ++ break; ++ case HighDpiScaleFactorRoundingPolicy::Floor: ++ roundedFactor = qFloor(rawFactor); ++ break; ++ case HighDpiScaleFactorRoundingPolicy::RoundPreferFloor: ++ // Round up for .75 and higher. This favors "small UI" over "large UI". ++ roundedFactor = rawFactor - qFloor(rawFactor) < 0.75 ++ ? qFloor(rawFactor) : qCeil(rawFactor); ++ break; ++ case HighDpiScaleFactorRoundingPolicy::PassThrough: ++ case HighDpiScaleFactorRoundingPolicy::Unset: ++ break; ++ } ++ ++ // Don't round down to to zero; clamp the minimum (rounded) factor to 1. ++ // This is not a common case but can happen if a display reports a very ++ // low DPI. ++ if (scaleFactorRoundingPolicy != HighDpiScaleFactorRoundingPolicy::PassThrough) ++ roundedFactor = qMax(roundedFactor, qreal(1)); ++ ++ return roundedFactor; ++} ++ ++QDpi QHighDpiScaling::effectiveLogicalDpi(const QPlatformScreen *screen, qreal rawFactor, qreal roundedFactor) ++{ ++ // Apply DPI adjustment policy, if needed. If enabled this will change the ++ // reported logical DPI to account for the difference between the rounded ++ // scale factor and the actual scale factor. The effect is that text size ++ // will be correct for the screen dpi, but may be (slightly) out of sync ++ // with the rest of the UI. The amount of out-of-synch-ness depends on how ++ // well user code handles a non-standard DPI values, but since the ++ // adjustment is small (typically +/- 48 max) this might be OK. ++ static auto dpiAdjustmentPolicy = DpiAdjustmentPolicy::Unset; ++ ++ // Determine adjustment policy. ++ if (dpiAdjustmentPolicy == DpiAdjustmentPolicy::Unset) { ++ if (qEnvironmentVariableIsSet(dpiAdjustmentPolicyEnvVar)) { ++ QByteArray policyText = qgetenv(dpiAdjustmentPolicyEnvVar); ++ auto policyEnumValue = lookupDpiAdjustmentPolicy(policyText); ++ if (policyEnumValue != DpiAdjustmentPolicy::Unset) { ++ dpiAdjustmentPolicy = policyEnumValue; ++ } else { ++ auto values = joinEnumValues(std::begin(dpiAdjustmentPolicyLookup), ++ std::end(dpiAdjustmentPolicyLookup)); ++ qWarning("Unknown DPI adjustment policy: %s. Supported values are: %s.", ++ policyText.constData(), values.constData()); ++ } ++ } ++ if (dpiAdjustmentPolicy == DpiAdjustmentPolicy::Unset) ++ dpiAdjustmentPolicy = DpiAdjustmentPolicy::UpOnly; ++ } ++ ++ // Apply adjustment policy. ++ const QDpi baseDpi = screen->logicalBaseDpi(); ++ const qreal dpiAdjustmentFactor = rawFactor / roundedFactor; ++ ++ // Return the base DPI for cases where there is no adjustment ++ if (dpiAdjustmentPolicy == DpiAdjustmentPolicy::Disabled) ++ return baseDpi; ++ if (dpiAdjustmentPolicy == DpiAdjustmentPolicy::UpOnly && dpiAdjustmentFactor < 1) ++ return baseDpi; ++ ++ return QDpi(baseDpi.first * dpiAdjustmentFactor, baseDpi.second * dpiAdjustmentFactor); ++} ++ + void QHighDpiScaling::initHighDpiScaling() + { + // Determine if there is a global scale factor set. +@@ -259,8 +459,6 @@ void QHighDpiScaling::initHighDpiScaling() + + m_pixelDensityScalingActive = false; //set in updateHighDpiScaling below + +- // we update m_active in updateHighDpiScaling, but while we create the +- // screens, we have to assume that m_usePixelDensity implies scaling + m_active = m_globalScalingActive || m_usePixelDensity; + } + +@@ -312,7 +510,7 @@ void QHighDpiScaling::updateHighDpiScaling() + ++i; + } + } +- m_active = m_globalScalingActive || m_screenFactorSet || m_pixelDensityScalingActive; ++ m_active = m_globalScalingActive || m_usePixelDensity; + } + + /* +@@ -413,22 +611,8 @@ qreal QHighDpiScaling::screenSubfactor(const QPlatformScreen *screen) + { + qreal factor = qreal(1.0); + if (screen) { +- if (m_usePixelDensity) { +- qreal pixelDensity = screen->pixelDensity(); +- +- // Pixel density reported by the screen is sometimes not precise enough, +- // so recalculate it: divide px (physical pixels) by dp (device-independent pixels) +- // for both width and height, and then use the average if it is different from +- // the one initially reported by the screen +- QRect screenGeometry = screen->geometry(); +- qreal wFactor = qreal(screenGeometry.width()) / qRound(screenGeometry.width() / pixelDensity); +- qreal hFactor = qreal(screenGeometry.height()) / qRound(screenGeometry.height() / pixelDensity); +- qreal averageDensity = (wFactor + hFactor) / 2; +- if (!qFuzzyCompare(pixelDensity, averageDensity)) +- pixelDensity = averageDensity; +- +- factor *= pixelDensity; +- } ++ if (m_usePixelDensity) ++ factor *= roundScaleFactor(rawScaleFactor(screen)); + if (m_screenFactorSet) { + QVariant screenFactor = screen->screen()->property(scaleFactorProperty); + if (screenFactor.isValid()) +@@ -441,13 +625,15 @@ qreal QHighDpiScaling::screenSubfactor(const QPlatformScreen *screen) + QDpi QHighDpiScaling::logicalDpi(const QScreen *screen) + { + // (Note: m_active test is performed at call site.) +- if (!screen) ++ if (!screen || !screen->handle()) + return QDpi(96, 96); + +- qreal platformScreenfactor = screenSubfactor(screen->handle()); +- QDpi platformScreenDpi = screen->handle()->logicalDpi(); +- return QDpi(platformScreenDpi.first / platformScreenfactor, +- platformScreenDpi.second / platformScreenfactor); ++ if (!m_usePixelDensity) ++ return screen->handle()->logicalDpi(); ++ ++ const qreal scaleFactor = rawScaleFactor(screen->handle()); ++ const qreal roundedScaleFactor = roundScaleFactor(scaleFactor); ++ return effectiveLogicalDpi(screen->handle(), scaleFactor, roundedScaleFactor); + } + + QHighDpiScaling::ScaleAndOrigin QHighDpiScaling::scaleAndOrigin(const QPlatformScreen *platformScreen, QPoint *nativePosition) +diff --git a/src/gui/kernel/qhighdpiscaling_p.h b/src/gui/kernel/qhighdpiscaling_p.h +index e578625305..e24628a69a 100644 +--- a/src/gui/kernel/qhighdpiscaling_p.h ++++ b/src/gui/kernel/qhighdpiscaling_p.h +@@ -72,7 +72,33 @@ typedef QPair QDpi; + + #ifndef QT_NO_HIGHDPISCALING + class Q_GUI_EXPORT QHighDpiScaling { ++ Q_GADGET + public: ++ enum class HighDpiScaleFactorRoundingPolicy { ++ Unset, ++ Round, ++ Ceil, ++ Floor, ++ RoundPreferFloor, ++ PassThrough ++ }; ++ Q_ENUM(HighDpiScaleFactorRoundingPolicy) ++ ++ enum class DpiAdjustmentPolicy { ++ Unset, ++ Enabled, ++ Disabled, ++ UpOnly ++ }; ++ Q_ENUM(DpiAdjustmentPolicy) ++ ++ QHighDpiScaling() = delete; ++ ~QHighDpiScaling() = delete; ++ QHighDpiScaling(const QHighDpiScaling &) = delete; ++ QHighDpiScaling &operator=(const QHighDpiScaling &) = delete; ++ QHighDpiScaling(QHighDpiScaling &&) = delete; ++ QHighDpiScaling &operator=(QHighDpiScaling &&) = delete; ++ + static void initHighDpiScaling(); + static void updateHighDpiScaling(); + static void setGlobalFactor(qreal factor); +@@ -101,6 +127,9 @@ public: + static QDpi logicalDpi(const QScreen *screen); + + private: ++ static qreal rawScaleFactor(const QPlatformScreen *screen); ++ static qreal roundScaleFactor(qreal rawFactor); ++ static QDpi effectiveLogicalDpi(const QPlatformScreen *screen, qreal rawFactor, qreal roundedFactor); + static qreal screenSubfactor(const QPlatformScreen *screen); + + static qreal m_factor; +diff --git a/src/gui/kernel/qplatformscreen.cpp b/src/gui/kernel/qplatformscreen.cpp +index 21ae75ba8f..ff76528a0e 100644 +--- a/src/gui/kernel/qplatformscreen.cpp ++++ b/src/gui/kernel/qplatformscreen.cpp +@@ -197,6 +197,20 @@ QDpi QPlatformScreen::logicalDpi() const + 25.4 * s.height() / ps.height()); + } + ++/*! ++ Reimplement to return the base logical DPI for the platform. This ++ DPI value should correspond to a standard-DPI (1x) display. The ++ default implementation returns 96. ++ ++ QtGui will use this value (together with logicalDpi) to compute ++ the scale factor when high-DPI scaling is enabled: ++ factor = logicalDPI / baseDPI ++*/ ++QDpi QPlatformScreen::logicalBaseDpi() const ++{ ++ return QDpi(96, 96); ++} ++ + /*! + Reimplement this function in subclass to return the device pixel ratio + for the screen. This is the ratio between physical pixels and the +diff --git a/src/gui/kernel/qplatformscreen.h b/src/gui/kernel/qplatformscreen.h +index e9d64c8a29..63b5d5a4a7 100644 +--- a/src/gui/kernel/qplatformscreen.h ++++ b/src/gui/kernel/qplatformscreen.h +@@ -113,6 +113,7 @@ public: + + virtual QSizeF physicalSize() const; + virtual QDpi logicalDpi() const; ++ virtual QDpi logicalBaseDpi() const; + virtual qreal devicePixelRatio() const; + virtual qreal pixelDensity() const; + +diff --git a/src/plugins/platforms/android/qandroidplatformscreen.cpp b/src/plugins/platforms/android/qandroidplatformscreen.cpp +index 7dc8bb8080..80757c2135 100644 +--- a/src/plugins/platforms/android/qandroidplatformscreen.cpp ++++ b/src/plugins/platforms/android/qandroidplatformscreen.cpp +@@ -401,15 +401,17 @@ void QAndroidPlatformScreen::doRedraw() + m_dirtyRect = QRect(); + } + ++static const int androidLogicalDpi = 72; ++ + QDpi QAndroidPlatformScreen::logicalDpi() const + { +- qreal lDpi = QtAndroid::scaledDensity() * 72; ++ qreal lDpi = QtAndroid::scaledDensity() * androidLogicalDpi; + return QDpi(lDpi, lDpi); + } + +-qreal QAndroidPlatformScreen::pixelDensity() const ++QDpi QAndroidPlatformScreen::logicalBaseDpi() const + { +- return QtAndroid::pixelDensity(); ++ return QDpi(androidLogicalDpi, androidLogicalDpi); + } + + Qt::ScreenOrientation QAndroidPlatformScreen::orientation() const +diff --git a/src/plugins/platforms/android/qandroidplatformscreen.h b/src/plugins/platforms/android/qandroidplatformscreen.h +index f15aeae3fd..5dc158e351 100644 +--- a/src/plugins/platforms/android/qandroidplatformscreen.h ++++ b/src/plugins/platforms/android/qandroidplatformscreen.h +@@ -103,7 +103,7 @@ protected: + + private: + QDpi logicalDpi() const override; +- qreal pixelDensity() const override; ++ QDpi logicalBaseDpi() const override; + Qt::ScreenOrientation orientation() const override; + Qt::ScreenOrientation nativeOrientation() const override; + void surfaceChanged(JNIEnv *env, jobject surface, int w, int h) override; +diff --git a/src/plugins/platforms/cocoa/qcocoascreen.h b/src/plugins/platforms/cocoa/qcocoascreen.h +index 9ded98df32..a73b97c771 100644 +--- a/src/plugins/platforms/cocoa/qcocoascreen.h ++++ b/src/plugins/platforms/cocoa/qcocoascreen.h +@@ -64,6 +64,7 @@ public: + qreal devicePixelRatio() const override; + QSizeF physicalSize() const override { return m_physicalSize; } + QDpi logicalDpi() const override { return m_logicalDpi; } ++ QDpi logicalBaseDpi() const override { return m_logicalDpi; } + qreal refreshRate() const override { return m_refreshRate; } + QString name() const override { return m_name; } + QPlatformCursor *cursor() const override { return m_cursor; } +diff --git a/src/plugins/platforms/windows/qwindowsscreen.cpp b/src/plugins/platforms/windows/qwindowsscreen.cpp +index 46e107d75e..88881e9cab 100644 +--- a/src/plugins/platforms/windows/qwindowsscreen.cpp ++++ b/src/plugins/platforms/windows/qwindowsscreen.cpp +@@ -257,15 +257,6 @@ QWindow *QWindowsScreen::windowAt(const QPoint &screenPoint, unsigned flags) + return result; + } + +-qreal QWindowsScreen::pixelDensity() const +-{ +- // QTBUG-49195: Use logical DPI instead of physical DPI to calculate +- // the pixel density since it is reflects the Windows UI scaling. +- // High DPI auto scaling should be disabled when the user chooses +- // small fonts on a High DPI monitor, resulting in lower logical DPI. +- return qMax(1, qRound(logicalDpi().first / 96)); +-} +- + /*! + \brief Determine siblings in a virtual desktop system. + +diff --git a/src/plugins/platforms/windows/qwindowsscreen.h b/src/plugins/platforms/windows/qwindowsscreen.h +index 3eb2d35b27..c3cb87d3b7 100644 +--- a/src/plugins/platforms/windows/qwindowsscreen.h ++++ b/src/plugins/platforms/windows/qwindowsscreen.h +@@ -87,7 +87,7 @@ public: + QImage::Format format() const override { return m_data.format; } + QSizeF physicalSize() const override { return m_data.physicalSizeMM; } + QDpi logicalDpi() const override { return m_data.dpi; } +- qreal pixelDensity() const override; ++ QDpi logicalBaseDpi() const override { return QDpi(96, 96); }; + qreal devicePixelRatio() const override { return 1.0; } + qreal refreshRate() const override { return m_data.refreshRateHz; } + QString name() const override { return m_data.name; } +diff --git a/src/plugins/platforms/xcb/qxcbscreen.cpp b/src/plugins/platforms/xcb/qxcbscreen.cpp +index 39e83e0451..ab5faa7212 100644 +--- a/src/plugins/platforms/xcb/qxcbscreen.cpp ++++ b/src/plugins/platforms/xcb/qxcbscreen.cpp +@@ -679,11 +679,6 @@ QDpi QXcbScreen::logicalDpi() const + return m_virtualDesktop->dpi(); + } + +-qreal QXcbScreen::pixelDensity() const +-{ +- return m_pixelDensity; +-} +- + QPlatformCursor *QXcbScreen::cursor() const + { + return m_cursor; +@@ -747,14 +742,6 @@ void QXcbScreen::updateGeometry(const QRect &geometry, uint8_t rotation) + if (m_sizeMillimeters.isEmpty()) + m_sizeMillimeters = sizeInMillimeters(geometry.size(), m_virtualDesktop->dpi()); + +- qreal dpi = forcedDpi(); +- if (dpi <= 0) +- dpi = geometry.width() / physicalSize().width() * qreal(25.4); +- +- // Use 128 as a reference DPI on small screens. This favors "small UI" over "large UI". +- qreal referenceDpi = physicalSize().width() <= 320 ? 128 : 96; +- +- m_pixelDensity = qMax(1, qRound(dpi/referenceDpi)); + m_geometry = geometry; + m_availableGeometry = geometry & m_virtualDesktop->workArea(); + QWindowSystemInterface::handleScreenGeometryChange(QPlatformScreen::screen(), m_geometry, m_availableGeometry); +diff --git a/src/plugins/platforms/xcb/qxcbscreen.h b/src/plugins/platforms/xcb/qxcbscreen.h +index ec3b07bfb7..62931d2500 100644 +--- a/src/plugins/platforms/xcb/qxcbscreen.h ++++ b/src/plugins/platforms/xcb/qxcbscreen.h +@@ -161,7 +161,7 @@ public: + QImage::Format format() const override; + QSizeF physicalSize() const override { return m_sizeMillimeters; } + QDpi logicalDpi() const override; +- qreal pixelDensity() const override; ++ QDpi logicalBaseDpi() const override { return QDpi(96, 96); }; + QPlatformCursor *cursor() const override; + qreal refreshRate() const override { return m_refreshRate; } + Qt::ScreenOrientation orientation() const override { return m_orientation; } +@@ -227,7 +227,6 @@ private: + Qt::ScreenOrientation m_orientation = Qt::PrimaryOrientation; + QXcbCursor *m_cursor; + int m_refreshRate = 60; +- int m_pixelDensity = 1; + QEdidParser m_edid; + }; + +diff --git a/tests/manual/highdpi/highdpi.pro b/tests/manual/highdpi/highdpi.pro +index 9db083cd82..2de8ed3bb5 100644 +--- a/tests/manual/highdpi/highdpi.pro ++++ b/tests/manual/highdpi/highdpi.pro +@@ -15,3 +15,4 @@ HEADERS += \ + RESOURCES += \ + highdpi.qrc + ++DEFINES += HAVE_SCREEN_BASE_DPI +-- +2.20.1.windows.1 + +From a1f512aa3c0b32c597661aba5561541113144dc9 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Morten=20Johan=20S=C3=B8rvig?= +Date: Thu, 2 Jun 2016 09:52:21 +0200 +Subject: [PATCH 39/47] Move QT_FONT_DPI to cross-platform code + +This makes it possible to test the effects of setting +Qt::AA_HighDpiScaling/QT_AUTO_SCREEN_SCALE_FACTOR, with different DPI +values on all platforms. + +This also makes it possible to access the actual DPI values reported +by the OS/WS via the QPlatformScreen API. + +A drawback is that there is no single place to check the environment +variable; currently done in three places. This may be +further simplified later on. + +Done-with: Friedemann Kleint +Task-number: QTBUG-53022 +Change-Id: Idd6463219d3ae58fe0ab72c17686cce2eb9dbadd +Reviewed-by: Friedemann Kleint +(cherry picked from commit 70a893e9bee7c1b8994a1218038a302e406d0aa3) +--- + src/gui/kernel/qhighdpiscaling.cpp | 4 ++-- + src/gui/kernel/qplatformscreen.cpp | 8 ++++++++ + src/gui/kernel/qplatformscreen.h | 2 ++ + src/gui/kernel/qscreen.cpp | 7 +++++-- + src/gui/kernel/qwindowsysteminterface.cpp | 4 ++-- + src/plugins/platforms/xcb/qxcbscreen.cpp | 4 ---- + 6 files changed, 19 insertions(+), 10 deletions(-) + +diff --git a/src/gui/kernel/qhighdpiscaling.cpp b/src/gui/kernel/qhighdpiscaling.cpp +index 7ffbfbe1e5..c8a2634929 100644 +--- a/src/gui/kernel/qhighdpiscaling.cpp ++++ b/src/gui/kernel/qhighdpiscaling.cpp +@@ -276,7 +276,7 @@ qreal QHighDpiScaling::rawScaleFactor(const QPlatformScreen *screen) + qreal platformPhysicalDpi = screen->screen()->physicalDotsPerInch(); + factor = qreal(platformPhysicalDpi) / qreal(platformBaseDpi.first); + } else { +- QDpi platformLogicalDpi = screen->logicalDpi(); ++ const QDpi platformLogicalDpi = QPlatformScreen::overrideDpi(screen->logicalDpi()); + factor = qreal(platformLogicalDpi.first) / qreal(platformBaseDpi.first); + } + +@@ -629,7 +629,7 @@ QDpi QHighDpiScaling::logicalDpi(const QScreen *screen) + return QDpi(96, 96); + + if (!m_usePixelDensity) +- return screen->handle()->logicalDpi(); ++ return QPlatformScreen::overrideDpi(screen->handle()->logicalDpi()); + + const qreal scaleFactor = rawScaleFactor(screen->handle()); + const qreal roundedScaleFactor = roundScaleFactor(scaleFactor); +diff --git a/src/gui/kernel/qplatformscreen.cpp b/src/gui/kernel/qplatformscreen.cpp +index ff76528a0e..9e684c9fbf 100644 +--- a/src/gui/kernel/qplatformscreen.cpp ++++ b/src/gui/kernel/qplatformscreen.cpp +@@ -197,6 +197,14 @@ QDpi QPlatformScreen::logicalDpi() const + 25.4 * s.height() / ps.height()); + } + ++// Helper function for accessing the platform screen logical dpi ++// which accounts for QT_FONT_DPI. ++QPair QPlatformScreen::overrideDpi(const QPair &in) ++{ ++ static const int overrideDpi = qEnvironmentVariableIntValue("QT_FONT_DPI"); ++ return overrideDpi > 0 ? QDpi(overrideDpi, overrideDpi) : in; ++} ++ + /*! + Reimplement to return the base logical DPI for the platform. This + DPI value should correspond to a standard-DPI (1x) display. The +diff --git a/src/gui/kernel/qplatformscreen.h b/src/gui/kernel/qplatformscreen.h +index 63b5d5a4a7..32e6bf7ec7 100644 +--- a/src/gui/kernel/qplatformscreen.h ++++ b/src/gui/kernel/qplatformscreen.h +@@ -159,6 +159,8 @@ public: + // The platform screen's geometry in device independent coordinates + QRect deviceIndependentGeometry() const; + ++ static QDpi overrideDpi(const QDpi &in); ++ + protected: + void resizeMaximizedWindows(); + +diff --git a/src/gui/kernel/qscreen.cpp b/src/gui/kernel/qscreen.cpp +index 82ee62e6b4..b856435f67 100644 +--- a/src/gui/kernel/qscreen.cpp ++++ b/src/gui/kernel/qscreen.cpp +@@ -84,8 +84,11 @@ void QScreenPrivate::setPlatformScreen(QPlatformScreen *screen) + platformScreen->d_func()->screen = q; + orientation = platformScreen->orientation(); + geometry = platformScreen->deviceIndependentGeometry(); +- availableGeometry = QHighDpi::fromNative(platformScreen->availableGeometry(), QHighDpiScaling::factor(platformScreen), geometry.topLeft()); +- logicalDpi = platformScreen->logicalDpi(); ++ availableGeometry = QHighDpi::fromNative(platformScreen->availableGeometry(), ++ QHighDpiScaling::factor(platformScreen), geometry.topLeft()); ++ ++ logicalDpi = QPlatformScreen::overrideDpi(platformScreen->logicalDpi()); ++ + refreshRate = platformScreen->refreshRate(); + // safeguard ourselves against buggy platform behavior... + if (refreshRate < 1.0) +diff --git a/src/gui/kernel/qwindowsysteminterface.cpp b/src/gui/kernel/qwindowsysteminterface.cpp +index 5caf4802a0..7ce0e6b0ef 100644 +--- a/src/gui/kernel/qwindowsysteminterface.cpp ++++ b/src/gui/kernel/qwindowsysteminterface.cpp +@@ -871,8 +871,8 @@ void QWindowSystemInterface::handleScreenGeometryChange(QScreen *screen, const Q + + void QWindowSystemInterface::handleScreenLogicalDotsPerInchChange(QScreen *screen, qreal dpiX, qreal dpiY) + { +- QWindowSystemInterfacePrivate::ScreenLogicalDotsPerInchEvent *e = +- new QWindowSystemInterfacePrivate::ScreenLogicalDotsPerInchEvent(screen, dpiX, dpiY); // ### tja ++ const QDpi effectiveDpi = QPlatformScreen::overrideDpi(QDpi{dpiX, dpiY}); ++ auto e = new QWindowSystemInterfacePrivate::ScreenLogicalDotsPerInchEvent(screen, effectiveDpi.first, effectiveDpi.second); + QWindowSystemInterfacePrivate::handleWindowSystemEvent(e); + } + +diff --git a/src/plugins/platforms/xcb/qxcbscreen.cpp b/src/plugins/platforms/xcb/qxcbscreen.cpp +index ab5faa7212..ccd1a672bc 100644 +--- a/src/plugins/platforms/xcb/qxcbscreen.cpp ++++ b/src/plugins/platforms/xcb/qxcbscreen.cpp +@@ -660,10 +660,6 @@ QImage::Format QXcbScreen::format() const + + int QXcbScreen::forcedDpi() const + { +- static const int overrideDpi = qEnvironmentVariableIntValue("QT_FONT_DPI"); +- if (overrideDpi) +- return overrideDpi; +- + const int forcedDpi = m_virtualDesktop->forcedDpi(); + if (forcedDpi > 0) + return forcedDpi; +-- +2.20.1.windows.1 + +From f2b8beb68acb5acedc418c7c140d964a4c5df6f7 Mon Sep 17 00:00:00 2001 +From: Friedemann Kleint +Date: Wed, 27 Feb 2019 08:46:47 +0100 +Subject: [PATCH 40/47] Update QT_SCREEN_SCALE_FACTORS +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Store name->factor associations in a global QHash instead of on the +QScreen object, making them survive QScreen object deletion, for +example on disconnect/ connect cycles. + +Make factors set with QT_SCREEN_SCALE_FACTORS override the screen +factors computed from platform plugin DPI values. This matches the use +case for QT_SCREEN_SCALE_FACTORS (but not the general scale factors +combine by multiplication”principle) + +Done-with: Friedemann Kleint +Task-number: QTBUG-53022 +Change-Id: I12771249314ab0c073e609d62f57ac0d18d3b6ce +Reviewed-by: Friedemann Kleint +(cherry picked from commit 35da4eeba263db411d929fd278a4617dd7cf5c22) +--- + src/gui/kernel/qhighdpiscaling.cpp | 61 ++++++++++++++++++++++-------- + src/gui/kernel/qhighdpiscaling_p.h | 2 +- + 2 files changed, 46 insertions(+), 17 deletions(-) + +diff --git a/src/gui/kernel/qhighdpiscaling.cpp b/src/gui/kernel/qhighdpiscaling.cpp +index c8a2634929..3de67d5cfa 100644 +--- a/src/gui/kernel/qhighdpiscaling.cpp ++++ b/src/gui/kernel/qhighdpiscaling.cpp +@@ -63,6 +63,12 @@ static const char scaleFactorRoundingPolicyEnvVar[] = "QT_SCALE_FACTOR_ROUNDING_ + static const char dpiAdjustmentPolicyEnvVar[] = "QT_DPI_ADJUSTMENT_POLICY"; + static const char usePhysicalDpiEnvVar[] = "QT_USE_PHYSICAL_DPI"; + ++// Per-screen scale factors for named screens set with QT_SCREEN_SCALE_FACTORS ++// are stored here. Use a global hash to keep the factor across screen ++// disconnect/connect cycles where the screen object may be deleted. ++typedef QHash QScreenScaleFactorHash; ++Q_GLOBAL_STATIC(QScreenScaleFactorHash, qNamedScreenScaleFactors); ++ + // Reads and interprets the given environment variable as a bool, + // returns the default value if not set. + static bool qEnvironmentVariableAsBool(const char *name, bool defaultValue) +@@ -480,20 +486,19 @@ void QHighDpiScaling::updateHighDpiScaling() + int i = 0; + const auto specs = qgetenv(screenFactorsEnvVar).split(';'); + for (const QByteArray &spec : specs) { +- QScreen *screen = 0; + int equalsPos = spec.lastIndexOf('='); +- double factor = 0; ++ qreal factor = 0; + if (equalsPos > 0) { + // support "name=factor" + QByteArray name = spec.mid(0, equalsPos); + QByteArray f = spec.mid(equalsPos + 1); + bool ok; + factor = f.toDouble(&ok); +- if (ok) { ++ if (ok && factor > 0 ) { + const auto screens = QGuiApplication::screens(); + for (QScreen *s : screens) { + if (s->name() == QString::fromLocal8Bit(name)) { +- screen = s; ++ setScreenFactor(s, factor); + break; + } + } +@@ -502,11 +507,11 @@ void QHighDpiScaling::updateHighDpiScaling() + // listing screens in order + bool ok; + factor = spec.toDouble(&ok); +- if (ok && i < QGuiApplication::screens().count()) +- screen = QGuiApplication::screens().at(i); ++ if (ok && factor > 0 && i < QGuiApplication::screens().count()) { ++ QScreen *screen = QGuiApplication::screens().at(i); ++ setScreenFactor(screen, factor); ++ } + } +- if (screen) +- setScreenFactor(screen, factor); + ++i; + } + } +@@ -542,7 +547,14 @@ void QHighDpiScaling::setScreenFactor(QScreen *screen, qreal factor) + m_screenFactorSet = true; + m_active = true; + } +- screen->setProperty(scaleFactorProperty, QVariant(factor)); ++ ++ // Prefer associating the factor with screen name over the object ++ // since the screen object may be deleted on screen disconnects. ++ const QString name = screen->name(); ++ if (name.isEmpty()) ++ screen->setProperty(scaleFactorProperty, QVariant(factor)); ++ else ++ qNamedScreenScaleFactors()->insert(name, factor); + + // hack to force re-evaluation of screen geometry + if (screen->handle()) +@@ -610,15 +622,32 @@ QPoint QHighDpiScaling::mapPositionFromGlobal(const QPoint &pos, const QPoint &w + qreal QHighDpiScaling::screenSubfactor(const QPlatformScreen *screen) + { + qreal factor = qreal(1.0); +- if (screen) { +- if (m_usePixelDensity) +- factor *= roundScaleFactor(rawScaleFactor(screen)); +- if (m_screenFactorSet) { +- QVariant screenFactor = screen->screen()->property(scaleFactorProperty); +- if (screenFactor.isValid()) +- factor *= screenFactor.toReal(); ++ if (!screen) ++ return factor; ++ ++ // Unlike the other code where factors are combined by multiplication, ++ // factors from QT_SCREEN_SCALE_FACTORS takes precedence over the factor ++ // computed from platform plugin DPI. The rationale is that the user is ++ // setting the factor to override erroneous DPI values. ++ bool screenPropertyUsed = false; ++ if (m_screenFactorSet) { ++ // Check if there is a factor set on the screen object or associated ++ // with the screen name. These are mutually exclusive, so checking ++ // order is not significant. ++ QVariant byIndex = screen->screen()->property(scaleFactorProperty); ++ auto byNameIt = qNamedScreenScaleFactors()->constFind(screen->name()); ++ if (byIndex.isValid()) { ++ screenPropertyUsed = true; ++ factor = byIndex.toReal(); ++ } else if (byNameIt != qNamedScreenScaleFactors()->cend()) { ++ screenPropertyUsed = true; ++ factor = *byNameIt; + } + } ++ ++ if (!screenPropertyUsed && m_usePixelDensity) ++ factor = roundScaleFactor(rawScaleFactor(screen)); ++ + return factor; + } + +diff --git a/src/gui/kernel/qhighdpiscaling_p.h b/src/gui/kernel/qhighdpiscaling_p.h +index e24628a69a..9c24fa506d 100644 +--- a/src/gui/kernel/qhighdpiscaling_p.h ++++ b/src/gui/kernel/qhighdpiscaling_p.h +@@ -102,7 +102,7 @@ public: + static void initHighDpiScaling(); + static void updateHighDpiScaling(); + static void setGlobalFactor(qreal factor); +- static void setScreenFactor(QScreen *window, qreal factor); ++ static void setScreenFactor(QScreen *screen, qreal factor); + + static bool isActive() { return m_active; } + +-- +2.20.1.windows.1 + +From 1f0d4dcf4688864c3313ca4ec512d4094e58ad32 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Morten=20Johan=20S=C3=B8rvig?= +Date: Thu, 10 Nov 2016 14:17:53 +0100 +Subject: [PATCH 41/47] Deprecate QT_AUTO_SCREEN_SCALE_FACTOR +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Replace by QT_ENABLE_HIGHDPI_SCALING. + +QT_AUTO_SCREEN_SCALE_FACTOR has the usability problem that it mixes +enabling the high-DPI scaling mode with the method of getting screen +scale factors (“auto”). Due to this, it ends up with a slightly +strange name. + +QT_ENABLE_HIGHDPI_SCALING matches the C++ option +(Qt::AA_EnableHighDPiScaling), and leaves the scale factor acquisition +method unspecified, possibly to be set by some other means (like +QT_SCREEN_SCALE_FACTORS). + +Done-with: Friedemann Kleint +Task-number: QTBUG-53022 +Change-Id: I30033d91175a00db7837efc9c48c33396f5f0449 +Reviewed-by: Friedemann Kleint +(cherry picked from commit 1de8b01d2b6db8a4fe2eddd0c595d9e680964db5) +--- + src/gui/kernel/qhighdpiscaling.cpp | 29 +++++++++++++++++++++++------ + 1 file changed, 23 insertions(+), 6 deletions(-) + +diff --git a/src/gui/kernel/qhighdpiscaling.cpp b/src/gui/kernel/qhighdpiscaling.cpp +index 3de67d5cfa..4a9c9a9934 100644 +--- a/src/gui/kernel/qhighdpiscaling.cpp ++++ b/src/gui/kernel/qhighdpiscaling.cpp +@@ -56,8 +56,10 @@ Q_LOGGING_CATEGORY(lcScaling, "qt.scaling"); + + #ifndef QT_NO_HIGHDPISCALING + static const char legacyDevicePixelEnvVar[] = "QT_DEVICE_PIXEL_RATIO"; ++static const char legacyAutoScreenEnvVar[] = "QT_AUTO_SCREEN_SCALE_FACTOR"; ++ ++static const char enableHighDpiScalingEnvVar[] = "QT_ENABLE_HIGHDPI_SCALING"; + static const char scaleFactorEnvVar[] = "QT_SCALE_FACTOR"; +-static const char autoScreenEnvVar[] = "QT_AUTO_SCREEN_SCALE_FACTOR"; + static const char screenFactorsEnvVar[] = "QT_SCREEN_SCALE_FACTORS"; + static const char scaleFactorRoundingPolicyEnvVar[] = "QT_SCALE_FACTOR_ROUNDING_POLICY"; + static const char dpiAdjustmentPolicyEnvVar[] = "QT_DPI_ADJUSTMENT_POLICY"; +@@ -90,17 +92,24 @@ static inline qreal initialGlobalScaleFactor() + result = f; + } + } else { ++ // Check for deprecated environment variables. + if (qEnvironmentVariableIsSet(legacyDevicePixelEnvVar)) { + qWarning("Warning: %s is deprecated. Instead use:\n" + " %s to enable platform plugin controlled per-screen factors.\n" +- " %s to set per-screen factors.\n" ++ " %s to set per-screen DPI.\n" + " %s to set the application global scale factor.", +- legacyDevicePixelEnvVar, autoScreenEnvVar, screenFactorsEnvVar, scaleFactorEnvVar); ++ legacyDevicePixelEnvVar, legacyAutoScreenEnvVar, screenFactorsEnvVar, scaleFactorEnvVar); + + int dpr = qEnvironmentVariableIntValue(legacyDevicePixelEnvVar); + if (dpr > 0) + result = dpr; + } ++ ++ if (qEnvironmentVariableIsSet(legacyAutoScreenEnvVar)) { ++ qWarning("Warning: %s is deprecated. Instead use:\n" ++ " %s to enable platform plugin controlled per-screen factors.", ++ legacyAutoScreenEnvVar, enableHighDpiScalingEnvVar); ++ } + } + return result; + } +@@ -258,16 +267,24 @@ static inline bool usePixelDensity() + // Determine if we should set a scale factor based on the pixel density + // reported by the platform plugin. There are several enablers and several + // disablers. A single disable may veto all other enablers. ++ ++ // First, check of there is an explicit disable. + if (QCoreApplication::testAttribute(Qt::AA_DisableHighDpiScaling)) + return false; + bool screenEnvValueOk; +- const int screenEnvValue = qEnvironmentVariableIntValue(autoScreenEnvVar, &screenEnvValueOk); ++ const int screenEnvValue = qEnvironmentVariableIntValue(legacyAutoScreenEnvVar, &screenEnvValueOk); + if (screenEnvValueOk && screenEnvValue < 1) + return false; ++ bool enableEnvValueOk; ++ const int enableEnvValue = qEnvironmentVariableIntValue(enableHighDpiScalingEnvVar, &enableEnvValueOk); ++ if (enableEnvValueOk && enableEnvValue < 1) ++ return false; ++ ++ // Then return if there was an enable. + return QCoreApplication::testAttribute(Qt::AA_EnableHighDpiScaling) + || (screenEnvValueOk && screenEnvValue > 0) +- || (qEnvironmentVariableIsSet(legacyDevicePixelEnvVar) && +- qgetenv(legacyDevicePixelEnvVar).compare("auto", Qt::CaseInsensitive) == 0); ++ || (enableEnvValueOk && enableEnvValue > 0) ++ || (qEnvironmentVariableIsSet(legacyDevicePixelEnvVar) && qgetenv(legacyDevicePixelEnvVar).toLower() == "auto"); + } + + qreal QHighDpiScaling::rawScaleFactor(const QPlatformScreen *screen) +-- +2.20.1.windows.1 + +From befc66fd17772478fbb1212831dba86048e707ac Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Morten=20Johan=20S=C3=B8rvig?= +Date: Sat, 7 Oct 2017 01:35:29 +0200 +Subject: [PATCH 42/47] Add high-DPI scale factor rounding policy C++ API + +This API enables tuning of how Qt rounds fractional scale factors, and +corresponds to the QT_SCALE_FACTOR_ROUNDING_POLICY environment +variable + +New API: + Qt::HighDPiScaleFactorRoundingPolicy + QGuiApplication::setHighDpiScaleFactorRoundingPolicy() + QGuiApplication::highDpiScaleFactorRoundingPolicy() + +Done-with: Friedemann Kleint +Task-number: QTBUG-53022 +Change-Id: Ic360f26a173caa757e4ebde35ce08a6b74290b7d +Reviewed-by: Friedemann Kleint +(cherry picked from commit f1e40dd6d6968c59885231f61f94787abd4cf783) +--- + src/corelib/global/qnamespace.h | 10 +++++++ + src/corelib/global/qnamespace.qdoc | 22 ++++++++++++++ + src/gui/kernel/qguiapplication.cpp | 44 ++++++++++++++++++++++++++++ + src/gui/kernel/qguiapplication.h | 3 ++ + src/gui/kernel/qguiapplication_p.h | 1 + + src/gui/kernel/qhighdpiscaling.cpp | 47 +++++++++++++++++------------- + src/gui/kernel/qhighdpiscaling_p.h | 10 ------- + 7 files changed, 106 insertions(+), 31 deletions(-) + +diff --git a/src/corelib/global/qnamespace.h b/src/corelib/global/qnamespace.h +index 3ab9921986..423c9b4a5b 100644 +--- a/src/corelib/global/qnamespace.h ++++ b/src/corelib/global/qnamespace.h +@@ -1728,6 +1728,15 @@ public: + ChecksumItuV41 + }; + ++ enum class HighDpiScaleFactorRoundingPolicy { ++ Unset, ++ Round, ++ Ceil, ++ Floor, ++ RoundPreferFloor, ++ PassThrough ++ }; ++ + #ifndef Q_QDOC + // NOTE: Generally, do not add QT_Q_ENUM if a corresponding Q_Q_FLAG exists. + QT_Q_ENUM(ScrollBarPolicy) +@@ -1813,6 +1822,7 @@ public: + QT_Q_ENUM(MouseEventSource) + QT_Q_FLAG(MouseEventFlag) + QT_Q_ENUM(ChecksumType) ++ QT_Q_ENUM(HighDpiScaleFactorRoundingPolicy) + QT_Q_ENUM(TabFocusBehavior) + #endif // Q_DOC + +diff --git a/src/corelib/global/qnamespace.qdoc b/src/corelib/global/qnamespace.qdoc +index 5bba8c5fe5..cce67eb376 100644 +--- a/src/corelib/global/qnamespace.qdoc ++++ b/src/corelib/global/qnamespace.qdoc +@@ -3252,3 +3252,25 @@ + + \value ChecksumItuV41 Checksum calculation based on ITU-V.41. + */ ++ ++/*! ++ \enum Qt::HighDpiScaleFactorRoundingPolicy ++ \since 5.14 ++ ++ This enum describes the possible High-DPI scale factor rounding policies, which ++ decide how non-integer scale factors (such as Windows 150%) are handled. ++ ++ The active policy is set by calling QGuiApplication::setHighDdpiScaleFactorRoundingPolicy() before ++ the application object is created, or by setting the QT_SCALE_FACTOR_ROUNDING_POLICY ++ environment variable. ++ ++ \sa QGuiApplication::setHighDdpiScaleFactorRoundingPolicy() ++ \sa AA_EnableHighDpiScaling. ++ ++ \omitvalue Unset ++ \value Round Round up for .5 and above. ++ \value Ceil Always round up. ++ \value Floor Always round down. ++ \value RoundPreferFloor Round up for .75 and above. ++ \value PassThrough Don't round. ++*/ +diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp +index a86bd22588..9a409d0288 100644 +--- a/src/gui/kernel/qguiapplication.cpp ++++ b/src/gui/kernel/qguiapplication.cpp +@@ -146,6 +146,8 @@ QString QGuiApplicationPrivate::styleOverride; + + Qt::ApplicationState QGuiApplicationPrivate::applicationState = Qt::ApplicationInactive; + ++Qt::HighDpiScaleFactorRoundingPolicy QGuiApplicationPrivate::highDpiScaleFactorRoundingPolicy = ++ Qt::HighDpiScaleFactorRoundingPolicy::RoundPreferFloor; + bool QGuiApplicationPrivate::highDpiScalingUpdated = false; + + QPointer QGuiApplicationPrivate::currentDragWindow; +@@ -685,6 +687,8 @@ QGuiApplication::~QGuiApplication() + QGuiApplicationPrivate::lastCursorPosition = {qInf(), qInf()}; + QGuiApplicationPrivate::currentMousePressWindow = QGuiApplicationPrivate::currentMouseWindow = nullptr; + QGuiApplicationPrivate::applicationState = Qt::ApplicationInactive; ++ QGuiApplicationPrivate::highDpiScaleFactorRoundingPolicy = ++ Qt::HighDpiScaleFactorRoundingPolicy::RoundPreferFloor; + QGuiApplicationPrivate::highDpiScalingUpdated = false; + QGuiApplicationPrivate::currentDragWindow = nullptr; + QGuiApplicationPrivate::tabletDevicePoints.clear(); +@@ -3522,6 +3526,46 @@ Qt::ApplicationState QGuiApplication::applicationState() + return QGuiApplicationPrivate::applicationState; + } + ++/*! ++ \since 5.14 ++ ++ Sets the high-DPI scale factor rounding policy for the application. The ++ policy decides how non-integer scale factors (such as Windows 150%) are ++ handled, for applications that have AA_EnableHighDpiScaling enabled. ++ ++ The two principal options are whether fractional scale factors should ++ be rounded to an integer or not. Keeping the scale factor as-is will ++ make the user interface size match the OS setting exactly, but may cause ++ painting errors, for example with the Windows style. ++ ++ If rounding is wanted, then which type of rounding should be decided ++ next. Mathematically correct rounding is supported but may not give ++ the best visual results: Consider if you want to render 1.5x as 1x ++ ("small UI") or as 2x ("large UI"). See the Qt::HighDpiScaleFactorRoundingPolicy ++ enum for a complete list of all options. ++ ++ This function must be called before creating the application object, ++ and can be overridden by setting the QT_SCALE_FACTOR_ROUNDING_POLICY ++ environment variable. The QGuiApplication::highDpiScaleFactorRoundingPolicy() ++ accessor will reflect the environment, if set. ++ ++ The default value is Qt::HighDpiScaleFactorRoundingPolicy::RoundPreferFloor. ++*/ ++void QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy policy) ++{ ++ QGuiApplicationPrivate::highDpiScaleFactorRoundingPolicy = policy; ++} ++ ++/*! ++ \since 5.14 ++ ++ Returns the high-DPI scale factor rounding policy. ++*/ ++Qt::HighDpiScaleFactorRoundingPolicy QGuiApplication::highDpiScaleFactorRoundingPolicy() ++{ ++ return QGuiApplicationPrivate::highDpiScaleFactorRoundingPolicy; ++} ++ + /*! + \since 5.2 + \fn void QGuiApplication::applicationStateChanged(Qt::ApplicationState state) +diff --git a/src/gui/kernel/qguiapplication.h b/src/gui/kernel/qguiapplication.h +index 02dffef0fe..2814ba1d1b 100644 +--- a/src/gui/kernel/qguiapplication.h ++++ b/src/gui/kernel/qguiapplication.h +@@ -156,6 +156,9 @@ public: + + static Qt::ApplicationState applicationState(); + ++ static void setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy policy); ++ static Qt::HighDpiScaleFactorRoundingPolicy highDpiScaleFactorRoundingPolicy(); ++ + static int exec(); + bool notify(QObject *, QEvent *) override; + +diff --git a/src/gui/kernel/qguiapplication_p.h b/src/gui/kernel/qguiapplication_p.h +index ca7af43706..aaf6dd4c58 100644 +--- a/src/gui/kernel/qguiapplication_p.h ++++ b/src/gui/kernel/qguiapplication_p.h +@@ -216,6 +216,7 @@ public: + static QPointer currentMouseWindow; + static QPointer currentMousePressWindow; + static Qt::ApplicationState applicationState; ++ static Qt::HighDpiScaleFactorRoundingPolicy highDpiScaleFactorRoundingPolicy; + static bool highDpiScalingUpdated; + static QPointer currentDragWindow; + +diff --git a/src/gui/kernel/qhighdpiscaling.cpp b/src/gui/kernel/qhighdpiscaling.cpp +index 4a9c9a9934..c031885d5d 100644 +--- a/src/gui/kernel/qhighdpiscaling.cpp ++++ b/src/gui/kernel/qhighdpiscaling.cpp +@@ -331,24 +331,24 @@ static QByteArray joinEnumValues(const EnumLookup *i1, const EnumLooku + return result; + } + +-using ScaleFactorRoundingPolicyLookup = EnumLookup; ++using ScaleFactorRoundingPolicyLookup = EnumLookup; + + static const ScaleFactorRoundingPolicyLookup scaleFactorRoundingPolicyLookup[] = + { +- {"Round", QHighDpiScaling::HighDpiScaleFactorRoundingPolicy::Round}, +- {"Ceil", QHighDpiScaling::HighDpiScaleFactorRoundingPolicy::Ceil}, +- {"Floor", QHighDpiScaling::HighDpiScaleFactorRoundingPolicy::Floor}, +- {"RoundPreferFloor", QHighDpiScaling::HighDpiScaleFactorRoundingPolicy::RoundPreferFloor}, +- {"PassThrough", QHighDpiScaling::HighDpiScaleFactorRoundingPolicy::PassThrough} ++ {"Round", Qt::HighDpiScaleFactorRoundingPolicy::Round}, ++ {"Ceil", Qt::HighDpiScaleFactorRoundingPolicy::Ceil}, ++ {"Floor", Qt::HighDpiScaleFactorRoundingPolicy::Floor}, ++ {"RoundPreferFloor", Qt::HighDpiScaleFactorRoundingPolicy::RoundPreferFloor}, ++ {"PassThrough", Qt::HighDpiScaleFactorRoundingPolicy::PassThrough} + }; + +-static QHighDpiScaling::HighDpiScaleFactorRoundingPolicy ++static Qt::HighDpiScaleFactorRoundingPolicy + lookupScaleFactorRoundingPolicy(const QByteArray &v) + { + auto end = std::end(scaleFactorRoundingPolicyLookup); + auto it = std::find(std::begin(scaleFactorRoundingPolicyLookup), end, +- ScaleFactorRoundingPolicyLookup{v.constData(), QHighDpiScaling::HighDpiScaleFactorRoundingPolicy::Unset}); +- return it != end ? it->value : QHighDpiScaling::HighDpiScaleFactorRoundingPolicy::Unset; ++ ScaleFactorRoundingPolicyLookup{v.constData(), Qt::HighDpiScaleFactorRoundingPolicy::Unset}); ++ return it != end ? it->value : Qt::HighDpiScaleFactorRoundingPolicy::Unset; + } + + using DpiAdjustmentPolicyLookup = EnumLookup; +@@ -377,15 +377,15 @@ qreal QHighDpiScaling::roundScaleFactor(qreal rawFactor) + // sizes that are smaller than the ideal size, and opposite for rounding up. + // Rounding down is then preferable since "small UI" is a more acceptable + // high-DPI experience than "large UI". +- static auto scaleFactorRoundingPolicy = HighDpiScaleFactorRoundingPolicy::Unset; ++ static auto scaleFactorRoundingPolicy = Qt::HighDpiScaleFactorRoundingPolicy::Unset; + + // Determine rounding policy +- if (scaleFactorRoundingPolicy == HighDpiScaleFactorRoundingPolicy::Unset) { ++ if (scaleFactorRoundingPolicy == Qt::HighDpiScaleFactorRoundingPolicy::Unset) { + // Check environment + if (qEnvironmentVariableIsSet(scaleFactorRoundingPolicyEnvVar)) { + QByteArray policyText = qgetenv(scaleFactorRoundingPolicyEnvVar); + auto policyEnumValue = lookupScaleFactorRoundingPolicy(policyText); +- if (policyEnumValue != HighDpiScaleFactorRoundingPolicy::Unset) { ++ if (policyEnumValue != Qt::HighDpiScaleFactorRoundingPolicy::Unset) { + scaleFactorRoundingPolicy = policyEnumValue; + } else { + auto values = joinEnumValues(std::begin(scaleFactorRoundingPolicyLookup), +@@ -393,38 +393,43 @@ qreal QHighDpiScaling::roundScaleFactor(qreal rawFactor) + qWarning("Unknown scale factor rounding policy: %s. Supported values are: %s.", + policyText.constData(), values.constData()); + } ++ } ++ ++ // Check application object if no environment value was set. ++ if (scaleFactorRoundingPolicy == Qt::HighDpiScaleFactorRoundingPolicy::Unset) { ++ scaleFactorRoundingPolicy = QGuiApplication::highDpiScaleFactorRoundingPolicy(); + } else { +- // Set default policy if no environment variable is set. +- scaleFactorRoundingPolicy = HighDpiScaleFactorRoundingPolicy::RoundPreferFloor; ++ // Make application setting reflect environment ++ QGuiApplication::setHighDpiScaleFactorRoundingPolicy(scaleFactorRoundingPolicy); + } + } + + // Apply rounding policy. + qreal roundedFactor = rawFactor; + switch (scaleFactorRoundingPolicy) { +- case HighDpiScaleFactorRoundingPolicy::Round: ++ case Qt::HighDpiScaleFactorRoundingPolicy::Round: + roundedFactor = qRound(rawFactor); + break; +- case HighDpiScaleFactorRoundingPolicy::Ceil: ++ case Qt::HighDpiScaleFactorRoundingPolicy::Ceil: + roundedFactor = qCeil(rawFactor); + break; +- case HighDpiScaleFactorRoundingPolicy::Floor: ++ case Qt::HighDpiScaleFactorRoundingPolicy::Floor: + roundedFactor = qFloor(rawFactor); + break; +- case HighDpiScaleFactorRoundingPolicy::RoundPreferFloor: ++ case Qt::HighDpiScaleFactorRoundingPolicy::RoundPreferFloor: + // Round up for .75 and higher. This favors "small UI" over "large UI". + roundedFactor = rawFactor - qFloor(rawFactor) < 0.75 + ? qFloor(rawFactor) : qCeil(rawFactor); + break; +- case HighDpiScaleFactorRoundingPolicy::PassThrough: +- case HighDpiScaleFactorRoundingPolicy::Unset: ++ case Qt::HighDpiScaleFactorRoundingPolicy::PassThrough: ++ case Qt::HighDpiScaleFactorRoundingPolicy::Unset: + break; + } + + // Don't round down to to zero; clamp the minimum (rounded) factor to 1. + // This is not a common case but can happen if a display reports a very + // low DPI. +- if (scaleFactorRoundingPolicy != HighDpiScaleFactorRoundingPolicy::PassThrough) ++ if (scaleFactorRoundingPolicy != Qt::HighDpiScaleFactorRoundingPolicy::PassThrough) + roundedFactor = qMax(roundedFactor, qreal(1)); + + return roundedFactor; +diff --git a/src/gui/kernel/qhighdpiscaling_p.h b/src/gui/kernel/qhighdpiscaling_p.h +index 9c24fa506d..f58944a7d2 100644 +--- a/src/gui/kernel/qhighdpiscaling_p.h ++++ b/src/gui/kernel/qhighdpiscaling_p.h +@@ -74,16 +74,6 @@ typedef QPair QDpi; + class Q_GUI_EXPORT QHighDpiScaling { + Q_GADGET + public: +- enum class HighDpiScaleFactorRoundingPolicy { +- Unset, +- Round, +- Ceil, +- Floor, +- RoundPreferFloor, +- PassThrough +- }; +- Q_ENUM(HighDpiScaleFactorRoundingPolicy) +- + enum class DpiAdjustmentPolicy { + Unset, + Enabled, +-- +2.20.1.windows.1 + +From a1d02092cd8aa9bd940bb6b744166ad9411a69a4 Mon Sep 17 00:00:00 2001 +From: Friedemann Kleint +Date: Tue, 3 Sep 2019 13:43:58 +0200 +Subject: [PATCH 43/47] QtGui: Refactor parsing of the High DPI scaling env + variables +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Use qEnvironmentVariable() where applicable and refactor the +parsing of QT_SCREEN_SCALE_FACTORS to use QStringRef. + +Task-number: QTBUG-53022 +Change-Id: I8956c6cecd7b634679eb5e66d2a87cccaf9e7936 +Reviewed-by: Morten Johan Sørvig +(cherry picked from commit 18088d4706bdd2fefafe7dbb44dc467126f2c795) +--- + src/gui/kernel/qhighdpiscaling.cpp | 19 ++++++++++--------- + 1 file changed, 10 insertions(+), 9 deletions(-) + +diff --git a/src/gui/kernel/qhighdpiscaling.cpp b/src/gui/kernel/qhighdpiscaling.cpp +index c031885d5d..ec4feeba8b 100644 +--- a/src/gui/kernel/qhighdpiscaling.cpp ++++ b/src/gui/kernel/qhighdpiscaling.cpp +@@ -86,7 +86,7 @@ static inline qreal initialGlobalScaleFactor() + qreal result = 1; + if (qEnvironmentVariableIsSet(scaleFactorEnvVar)) { + bool ok; +- const qreal f = qgetenv(scaleFactorEnvVar).toDouble(&ok); ++ const qreal f = qEnvironmentVariable(scaleFactorEnvVar).toDouble(&ok); + if (ok && f > 0) { + qCDebug(lcScaling) << "Apply " << scaleFactorEnvVar << f; + result = f; +@@ -284,7 +284,8 @@ static inline bool usePixelDensity() + return QCoreApplication::testAttribute(Qt::AA_EnableHighDpiScaling) + || (screenEnvValueOk && screenEnvValue > 0) + || (enableEnvValueOk && enableEnvValue > 0) +- || (qEnvironmentVariableIsSet(legacyDevicePixelEnvVar) && qgetenv(legacyDevicePixelEnvVar).toLower() == "auto"); ++ || (qEnvironmentVariableIsSet(legacyDevicePixelEnvVar) ++ && qEnvironmentVariable(legacyDevicePixelEnvVar).compare(QLatin1String("auto"), Qt::CaseInsensitive) == 0); + } + + qreal QHighDpiScaling::rawScaleFactor(const QPlatformScreen *screen) +@@ -506,20 +507,20 @@ void QHighDpiScaling::updateHighDpiScaling() + } + if (qEnvironmentVariableIsSet(screenFactorsEnvVar)) { + int i = 0; +- const auto specs = qgetenv(screenFactorsEnvVar).split(';'); +- for (const QByteArray &spec : specs) { +- int equalsPos = spec.lastIndexOf('='); ++ const QString spec = qEnvironmentVariable(screenFactorsEnvVar); ++ const auto specs = spec.splitRef(QLatin1Char(';')); ++ for (const QStringRef &spec : specs) { ++ int equalsPos = spec.lastIndexOf(QLatin1Char('=')); + qreal factor = 0; + if (equalsPos > 0) { + // support "name=factor" +- QByteArray name = spec.mid(0, equalsPos); +- QByteArray f = spec.mid(equalsPos + 1); + bool ok; +- factor = f.toDouble(&ok); ++ const auto name = spec.left(equalsPos); ++ factor = spec.mid(equalsPos + 1).toDouble(&ok); + if (ok && factor > 0 ) { + const auto screens = QGuiApplication::screens(); + for (QScreen *s : screens) { +- if (s->name() == QString::fromLocal8Bit(name)) { ++ if (s->name() == name) { + setScreenFactor(s, factor); + break; + } +-- +2.20.1.windows.1 + +From dbb7b892861a702ad9bc9bd3cccacd4e943dbe54 Mon Sep 17 00:00:00 2001 +From: Vitaly Fanaskov +Date: Fri, 25 Oct 2019 14:47:15 +0200 +Subject: [PATCH 44/47] QHighDpiScaling: fix potential null pointer dereference + +It's not guaranteed that QPlatformScreen::screen should always return a +valid pointer. Furthermore, you can run into this situation with, for +example, two screens setup. + +Task-number: QTBUG-53022 +Change-Id: Ic23bb2c30b1245f98a793a44cc5e0b39f9afac4b +Reviewed-by: Friedemann Kleint +(cherry picked from commit ed20f3209804d865804f9eb14c3fcfb4b7941140) +--- + src/gui/kernel/qhighdpiscaling.cpp | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/src/gui/kernel/qhighdpiscaling.cpp b/src/gui/kernel/qhighdpiscaling.cpp +index ec4feeba8b..0ac4928504 100644 +--- a/src/gui/kernel/qhighdpiscaling.cpp ++++ b/src/gui/kernel/qhighdpiscaling.cpp +@@ -657,7 +657,8 @@ qreal QHighDpiScaling::screenSubfactor(const QPlatformScreen *screen) + // Check if there is a factor set on the screen object or associated + // with the screen name. These are mutually exclusive, so checking + // order is not significant. +- QVariant byIndex = screen->screen()->property(scaleFactorProperty); ++ auto qScreen = screen->screen(); ++ auto byIndex = qScreen ? qScreen->property(scaleFactorProperty) : QVariant(); + auto byNameIt = qNamedScreenScaleFactors()->constFind(screen->name()); + if (byIndex.isValid()) { + screenPropertyUsed = true; +-- +2.20.1.windows.1 + +From 1492decc76d6cbb8d86bb5146ff2e1dae365df96 Mon Sep 17 00:00:00 2001 +From: Vitaly Fanaskov +Date: Wed, 6 Nov 2019 21:37:48 +0100 +Subject: [PATCH 45/47] QHighDpiScaling: impove readability of screenSubfactor + method + +Task-number: QTBUG-53022 +Change-Id: Idae4379dd78d3125c375fad37a5a3af5bbcdc51e +Reviewed-by: Friedemann Kleint +(cherry picked from commit a866055d18b2c2efc0f3cf5307d8eac78cce26eb) +--- + src/gui/kernel/qhighdpiscaling.cpp | 21 +++++++++++---------- + 1 file changed, 11 insertions(+), 10 deletions(-) + +diff --git a/src/gui/kernel/qhighdpiscaling.cpp b/src/gui/kernel/qhighdpiscaling.cpp +index 0ac4928504..fe9ac85c7d 100644 +--- a/src/gui/kernel/qhighdpiscaling.cpp ++++ b/src/gui/kernel/qhighdpiscaling.cpp +@@ -644,7 +644,7 @@ QPoint QHighDpiScaling::mapPositionFromGlobal(const QPoint &pos, const QPoint &w + + qreal QHighDpiScaling::screenSubfactor(const QPlatformScreen *screen) + { +- qreal factor = qreal(1.0); ++ auto factor = qreal(1.0); + if (!screen) + return factor; + +@@ -657,15 +657,16 @@ qreal QHighDpiScaling::screenSubfactor(const QPlatformScreen *screen) + // Check if there is a factor set on the screen object or associated + // with the screen name. These are mutually exclusive, so checking + // order is not significant. +- auto qScreen = screen->screen(); +- auto byIndex = qScreen ? qScreen->property(scaleFactorProperty) : QVariant(); +- auto byNameIt = qNamedScreenScaleFactors()->constFind(screen->name()); +- if (byIndex.isValid()) { +- screenPropertyUsed = true; +- factor = byIndex.toReal(); +- } else if (byNameIt != qNamedScreenScaleFactors()->cend()) { +- screenPropertyUsed = true; +- factor = *byNameIt; ++ if (auto qScreen = screen->screen()) { ++ auto screenFactor = qScreen->property(scaleFactorProperty).toReal(&screenPropertyUsed); ++ if (screenPropertyUsed) ++ factor = screenFactor; ++ } ++ ++ if (!screenPropertyUsed) { ++ auto byNameIt = qNamedScreenScaleFactors()->constFind(screen->name()); ++ if ((screenPropertyUsed = byNameIt != qNamedScreenScaleFactors()->cend())) ++ factor = *byNameIt; + } + } + +-- +2.20.1.windows.1 + +From da873ea0ac11df032f82e080996737ebd291b577 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Morten=20Johan=20S=C3=B8rvig?= +Date: Tue, 1 Dec 2020 15:24:23 +0100 +Subject: [PATCH 46/47] Windows: Add support for PerMonitorV2 DPI awareness +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Add support for opting in to PerMonitorV2 DPI awareness +on the command line: + -platform windows:dpiawareness=3 + +This mode is supported on Windows 10 and up. Setting it +requires using the new SetProcessDpiAwarenessContext +API, which can be resolved from user32.dll. + +Task-number: QTBUG-68712 +Change-Id: I37821e27a67e08c2e9fef25e494cfd7abed13314 +Reviewed-by: Tor Arne Vestbø +(cherry picked from commit c35643dba3efabaf3fa036895f152bf5b8725f5e) +--- + .../platforms/windows/qtwindowsglobal.h | 11 +++++++++- + .../platforms/windows/qwindowscontext.cpp | 22 +++++++++++++++++++ + .../platforms/windows/qwindowscontext.h | 5 +++++ + .../platforms/windows/qwindowsintegration.cpp | 19 +++++++++++----- + 4 files changed, 51 insertions(+), 6 deletions(-) + +diff --git a/src/plugins/platforms/windows/qtwindowsglobal.h b/src/plugins/platforms/windows/qtwindowsglobal.h +index 985f13bdc5..573a8d07c8 100644 +--- a/src/plugins/platforms/windows/qtwindowsglobal.h ++++ b/src/plugins/platforms/windows/qtwindowsglobal.h +@@ -76,6 +76,14 @@ + # define WM_POINTERHWHEEL 0x024F + #endif // WM_POINTERUPDATE + ++#if !defined(_DPI_AWARENESS_CONTEXTS_) ++# define DPI_AWARENESS_CONTEXT_UNAWARE ((HANDLE)-1) ++# define DPI_AWARENESS_CONTEXT_SYSTEM_AWARE ((HANDLE)-2) ++# define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE ((HANDLE)-3) ++# define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 ((HANDLE)-4) ++# define DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED ((HANDLE)-5) ++#endif ++ + QT_BEGIN_NAMESPACE + + namespace QtWindows +@@ -167,7 +175,8 @@ enum ProcessDpiAwareness + { + ProcessDpiUnaware, + ProcessSystemDpiAware, +- ProcessPerMonitorDpiAware ++ ProcessPerMonitorDpiAware, ++ ProcessPerMonitorV2DpiAware // Qt extension (not in Process_DPI_Awareness) + }; + + } // namespace QtWindows +diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp +index 38b9823d6b..25faa73374 100644 +--- a/src/plugins/platforms/windows/qwindowscontext.cpp ++++ b/src/plugins/platforms/windows/qwindowscontext.cpp +@@ -189,6 +189,7 @@ void QWindowsUser32DLL::init() + { + QSystemLibrary library(QStringLiteral("user32")); + setProcessDPIAware = (SetProcessDPIAware)library.resolve("SetProcessDPIAware"); ++ setProcessDpiAwarenessContext = (SetProcessDpiAwarenessContext)library.resolve("SetProcessDpiAwarenessContext"); + + addClipboardFormatListener = (AddClipboardFormatListener)library.resolve("AddClipboardFormatListener"); + removeClipboardFormatListener = (RemoveClipboardFormatListener)library.resolve("RemoveClipboardFormatListener"); +@@ -273,8 +274,11 @@ struct QWindowsContextPrivate { + const HRESULT m_oleInitializeResult; + QWindow *m_lastActiveWindow = nullptr; + bool m_asyncExpose = false; ++ static bool m_v2DpiAware; + }; + ++bool QWindowsContextPrivate::m_v2DpiAware = false; ++ + QWindowsContextPrivate::QWindowsContextPrivate() + : m_oleInitializeResult(OleInitialize(nullptr)) + { +@@ -425,6 +429,23 @@ void QWindowsContext::setProcessDpiAwareness(QtWindows::ProcessDpiAwareness dpiA + } + } + ++void QWindowsContext::setProcessDpiV2Awareness() ++{ ++ qCDebug(lcQpaWindows) << __FUNCTION__; ++ const BOOL ok = QWindowsContext::user32dll.setProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2); ++ if (ok) { ++ QWindowsContextPrivate::m_v2DpiAware = true; ++ } else { ++ const HRESULT errorCode = GetLastError(); ++ // E_ACCESSDENIED means set externally (MSVC manifest or external app loading Qt plugin). ++ // Silence warning in that case unless debug is enabled. ++ if (errorCode != E_ACCESSDENIED || lcQpaWindows().isDebugEnabled()) { ++ qWarning().noquote().nospace() << "setProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2) failed: " ++ << QWindowsContext::comErrorString(errorCode); ++ } ++ } ++} ++ + QWindowsContext *QWindowsContext::instance() + { + return m_instance; +@@ -991,6 +1012,7 @@ static inline bool resizeOnDpiChanged(const QWindow *w) + bool QWindowsContext::shouldHaveNonClientDpiScaling(const QWindow *window) + { + return QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows10 ++ && !QWindowsContextPrivate::m_v2DpiAware // V2 implies NonClientDpiScaling; no need to enable + && window->isTopLevel() + && !window->property(QWindowsWindow::embeddedNativeParentHandleProperty).isValid() + #if QT_CONFIG(opengl) // /QTBUG-62901, EnableNonClientDpiScaling has problems with GL +diff --git a/src/plugins/platforms/windows/qwindowscontext.h b/src/plugins/platforms/windows/qwindowscontext.h +index 4908f14629..012dd4e75d 100644 +--- a/src/plugins/platforms/windows/qwindowscontext.h ++++ b/src/plugins/platforms/windows/qwindowscontext.h +@@ -98,6 +98,7 @@ struct QWindowsUser32DLL + typedef BOOL (WINAPI *GetPointerPenInfoHistory)(UINT32, UINT32 *, PVOID); + typedef BOOL (WINAPI *SkipPointerFrameMessages)(UINT32); + typedef BOOL (WINAPI *SetProcessDPIAware)(); ++ typedef BOOL (WINAPI *SetProcessDpiAwarenessContext)(HANDLE); + typedef BOOL (WINAPI *AddClipboardFormatListener)(HWND); + typedef BOOL (WINAPI *RemoveClipboardFormatListener)(HWND); + typedef BOOL (WINAPI *GetDisplayAutoRotationPreferences)(DWORD *); +@@ -123,6 +124,9 @@ struct QWindowsUser32DLL + // Windows Vista onwards + SetProcessDPIAware setProcessDPIAware = nullptr; + ++ // Windows 10 version 1703 onwards ++ SetProcessDpiAwarenessContext setProcessDpiAwarenessContext = nullptr; ++ + // Clipboard listeners are present on Windows Vista onwards + // but missing in MinGW 4.9 stub libs. Can be removed in MinGW 5. + AddClipboardFormatListener addClipboardFormatListener = nullptr; +@@ -222,6 +226,7 @@ public: + void setTabletAbsoluteRange(int a); + void setProcessDpiAwareness(QtWindows::ProcessDpiAwareness dpiAwareness); + static int processDpiAwareness(); ++ void setProcessDpiV2Awareness(); + + void setDetectAltGrModifier(bool a); + +diff --git a/src/plugins/platforms/windows/qwindowsintegration.cpp b/src/plugins/platforms/windows/qwindowsintegration.cpp +index 47b2bbeb02..8923972d49 100644 +--- a/src/plugins/platforms/windows/qwindowsintegration.cpp ++++ b/src/plugins/platforms/windows/qwindowsintegration.cpp +@@ -210,7 +210,7 @@ static inline unsigned parseOptions(const QStringList ¶mList, + options |= QWindowsIntegration::DontPassOsMouseEventsSynthesizedFromTouch; + } else if (parseIntOption(param, QLatin1String("verbose"), 0, INT_MAX, &QWindowsContext::verbose) + || parseIntOption(param, QLatin1String("tabletabsoluterange"), 0, INT_MAX, tabletAbsoluteRange) +- || parseIntOption(param, QLatin1String("dpiawareness"), QtWindows::ProcessDpiUnaware, QtWindows::ProcessPerMonitorDpiAware, dpiAwareness)) { ++ || parseIntOption(param, QLatin1String("dpiawareness"), QtWindows::ProcessDpiUnaware, QtWindows::ProcessPerMonitorV2DpiAware, dpiAwareness)) { + } else if (param == QLatin1String("menus=native")) { + options |= QWindowsIntegration::AlwaysUseNativeMenus; + } else if (param == QLatin1String("menus=none")) { +@@ -259,10 +259,19 @@ QWindowsIntegrationPrivate::QWindowsIntegrationPrivate(const QStringList ¶mL + + if (!dpiAwarenessSet) { // Set only once in case of repeated instantiations of QGuiApplication. + if (!QCoreApplication::testAttribute(Qt::AA_PluginApplication)) { +- m_context.setProcessDpiAwareness(dpiAwareness); +- qCDebug(lcQpaWindows) +- << __FUNCTION__ << "DpiAwareness=" << dpiAwareness +- << "effective process DPI awareness=" << QWindowsContext::processDpiAwareness(); ++ ++ // DpiAwareV2 requires using new API ++ bool hasDpiAwarenessContext = QWindowsContext::user32dll.setProcessDpiAwarenessContext != nullptr; ++ if (dpiAwareness == QtWindows::ProcessPerMonitorV2DpiAware && hasDpiAwarenessContext) { ++ m_context.setProcessDpiV2Awareness(); ++ qCDebug(lcQpaWindows) ++ << __FUNCTION__ << "DpiAwareness: DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2"; ++ } else { ++ m_context.setProcessDpiAwareness(dpiAwareness); ++ qCDebug(lcQpaWindows) ++ << __FUNCTION__ << "DpiAwareness=" << dpiAwareness ++ << "effective process DPI awareness=" << QWindowsContext::processDpiAwareness(); ++ } + } + dpiAwarenessSet = true; + } +-- +2.20.1.windows.1 + +From af038fed43912698170de6b637ddfc286ec82e0c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Morten=20Johan=20S=C3=B8rvig?= +Date: Thu, 21 Jan 2021 14:17:28 +0100 +Subject: [PATCH 47/47] Windows: Change default to ProcessPerMonitorV2DpiAware +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Fixes: QTBUG-68712 +Change-Id: Id73c4a5422e50b5bee2160468feb4d2f09c5461a +Reviewed-by: Tor Arne Vestbø +(cherry picked from commit d66cb667efbc33b3a81ecc495e90a2e2f44616b2) +--- + src/plugins/platforms/windows/qwindowsintegration.cpp | 9 +++++---- + 1 file changed, 5 insertions(+), 4 deletions(-) + +diff --git a/src/plugins/platforms/windows/qwindowsintegration.cpp b/src/plugins/platforms/windows/qwindowsintegration.cpp +index 8923972d49..9c2f3c43d7 100644 +--- a/src/plugins/platforms/windows/qwindowsintegration.cpp ++++ b/src/plugins/platforms/windows/qwindowsintegration.cpp +@@ -230,9 +230,11 @@ QWindowsIntegrationPrivate::QWindowsIntegrationPrivate(const QStringList ¶mL + + static bool dpiAwarenessSet = false; + int tabletAbsoluteRange = -1; +- // Default to per-monitor awareness to avoid being scaled when monitors with different DPI +- // are connected to Windows 8.1 +- QtWindows::ProcessDpiAwareness dpiAwareness = QtWindows::ProcessPerMonitorDpiAware; ++ static bool hasDpiAwarenessContext = QWindowsContext::user32dll.setProcessDpiAwarenessContext != nullptr; ++ // Default to per-monitor-v2 awareness (if available) ++ QtWindows::ProcessDpiAwareness dpiAwareness = hasDpiAwarenessContext ? ++ QtWindows::ProcessPerMonitorV2DpiAware : QtWindows::ProcessPerMonitorDpiAware; ++ + m_options = parseOptions(paramList, &tabletAbsoluteRange, &dpiAwareness); + QWindowsFontDatabase::setFontOptions(m_options); + +@@ -261,7 +263,6 @@ QWindowsIntegrationPrivate::QWindowsIntegrationPrivate(const QStringList ¶mL + if (!QCoreApplication::testAttribute(Qt::AA_PluginApplication)) { + + // DpiAwareV2 requires using new API +- bool hasDpiAwarenessContext = QWindowsContext::user32dll.setProcessDpiAwarenessContext != nullptr; + if (dpiAwareness == QtWindows::ProcessPerMonitorV2DpiAware && hasDpiAwarenessContext) { + m_context.setProcessDpiV2Awareness(); + qCDebug(lcQpaWindows) +-- +2.20.1.windows.1 + +From 1bac06d0ee5c12a53dc9191b91e56207e089f8ea Mon Sep 17 00:00:00 2001 +From: Joni Poikelin +Date: Thu, 3 Jan 2019 11:52:15 +0200 +Subject: [PATCH 1/3] Add faster path for scaling QRegion with multiple regions + +Fixes: QTBUG-72821 +Change-Id: Ic4fa349087239337a77b0e280be551b46c75af71 +Reviewed-by: Giuseppe D'Angelo +(cherry picked from commit 64fab8f7e2d225e37aa731db7501b5d5b82eab64) +--- + src/gui/painting/qtransform.cpp | 19 ++++++- + .../auto/gui/painting/qregion/tst_qregion.cpp | 55 +++++++++++++++++++ + 2 files changed, 72 insertions(+), 2 deletions(-) + +diff --git a/src/gui/painting/qtransform.cpp b/src/gui/painting/qtransform.cpp +index 040d33fc2a..6354b154c5 100644 +--- a/src/gui/painting/qtransform.cpp ++++ b/src/gui/painting/qtransform.cpp +@@ -1517,8 +1517,23 @@ QRegion QTransform::map(const QRegion &r) const + return copy; + } + +- if (t == TxScale && r.rectCount() == 1) +- return QRegion(mapRect(r.boundingRect())); ++ if (t == TxScale) { ++ QRegion res; ++ if (m11() < 0 || m22() < 0) { ++ for (const QRect &rect : r) ++ res += mapRect(rect); ++ } else { ++ QVarLengthArray rects; ++ rects.reserve(r.rectCount()); ++ for (const QRect &rect : r) { ++ QRect nr = mapRect(rect); ++ if (!nr.isEmpty()) ++ rects.append(nr); ++ } ++ res.setRects(rects.constData(), rects.count()); ++ } ++ return res; ++ } + + QPainterPath p = map(qt_regionToPath(r)); + return p.toFillPolygon(QTransform()).toPolygon(); +diff --git a/tests/auto/gui/painting/qregion/tst_qregion.cpp b/tests/auto/gui/painting/qregion/tst_qregion.cpp +index 5256fbd1dc..24c4583819 100644 +--- a/tests/auto/gui/painting/qregion/tst_qregion.cpp ++++ b/tests/auto/gui/painting/qregion/tst_qregion.cpp +@@ -84,6 +84,8 @@ private slots: + #endif + + void regionFromPath(); ++ void scaleRegions_data(); ++ void scaleRegions(); + + #ifdef QT_BUILD_INTERNAL + void regionToPath_data(); +@@ -973,6 +975,59 @@ void tst_QRegion::regionFromPath() + } + } + ++void tst_QRegion::scaleRegions_data() ++{ ++ QTest::addColumn("scale"); ++ QTest::addColumn>("inputRects"); ++ QTest::addColumn>("expectedRects"); ++ ++ QTest::newRow("1.0 single") << 1.0 ++ << QVector{ QRect(10, 10, 20, 20) } ++ << QVector{ QRect(10, 10, 20, 20) }; ++ QTest::newRow("1.0 multi") << 1.0 ++ << QVector{ QRect(10, 10, 20, 20), QRect(40, 10, 20, 20) } ++ << QVector{ QRect(10, 10, 20, 20), QRect(40, 10, 20, 20) }; ++ QTest::newRow("2.0 single") << 2.0 ++ << QVector{ QRect(10, 10, 20, 20) } ++ << QVector{ QRect(20, 20, 40, 40) }; ++ QTest::newRow("2.0 multi") << 2.0 ++ << QVector{ QRect(10, 10, 20, 20), QRect(40, 10, 20, 20) } ++ << QVector{ QRect(20, 20, 40, 40), QRect(80, 20, 40, 40) }; ++ QTest::newRow("-1.0 single") << -1.0 ++ << QVector{ QRect(10, 10, 20, 20) } ++ << QVector{ QRect(-30, -30, 20, 20) }; ++ QTest::newRow("-1.0 multi") << -1.0 ++ << QVector{ QRect(10, 10, 20, 20), QRect(40, 10, 20, 20) } ++ << QVector{ QRect(-60, -30, 20, 20), QRect(-30, -30, 20, 20) }; ++ QTest::newRow("-2.0 single") << -2.0 ++ << QVector{ QRect(10, 10, 20, 20) } ++ << QVector{ QRect(-60, -60, 40, 40) }; ++ QTest::newRow("-2.0 multi") << -2.0 ++ << QVector{ QRect(10, 10, 20, 20), QRect(40, 10, 20, 20) } ++ << QVector{ QRect(-120, -60, 40, 40), QRect(-60, -60, 40, 40) }; ++} ++ ++void tst_QRegion::scaleRegions() ++{ ++ QFETCH(qreal, scale); ++ QFETCH(QVector, inputRects); ++ QFETCH(QVector, expectedRects); ++ ++ QRegion region; ++ region.setRects(inputRects.constData(), inputRects.size()); ++ ++ QRegion expected(expectedRects.first()); ++ expected.setRects(expectedRects.constData(), expectedRects.size()); ++ ++ QTransform t; ++ t.scale(scale, scale); ++ ++ auto result = t.map(region); ++ ++ QCOMPARE(result.rectCount(), expectedRects.size()); ++ QCOMPARE(result, expected); ++} ++ + Q_DECLARE_METATYPE(QPainterPath) + + #ifdef QT_BUILD_INTERNAL +-- +2.24.1.windows.2 + +From 038da48a6c2279f4964e8f82635bd2ae606ce518 Mon Sep 17 00:00:00 2001 +From: Eirik Aavitsland +Date: Thu, 17 Oct 2019 13:25:06 +0200 +Subject: [PATCH 2/3] Fix: QPainter off-by-one clipping for some non-integer + scalings + +For some scalings, setClipRect(QRect) would produce a clip one pixel +different from setClipRect(QRectF) because of different +rounding. Ditto for setClipRegion. Fix by making sure to transform +QRectFs instead of QRects. + +Fixes: QTBUG-78962 +Fixes: QTBUG-78963 +Change-Id: I0be721133858c30769ec6d81e978962a3d6b70cf +Reviewed-by: Christoph Cullmann +Reviewed-by: Allan Sandfeld Jensen +(cherry picked from commit 19f29802bf7daafacd0fd824c2a1349e80eac536) +--- + src/gui/painting/qpaintengine_raster.cpp | 2 +- + src/gui/painting/qtransform.cpp | 4 +- + .../gui/painting/qpainter/tst_qpainter.cpp | 49 ++++++++++++++++++- + 3 files changed, 51 insertions(+), 4 deletions(-) + +diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp +index 4dfdf20bf0..99ed691135 100644 +--- a/src/gui/painting/qpaintengine_raster.cpp ++++ b/src/gui/painting/qpaintengine_raster.cpp +@@ -1341,7 +1341,7 @@ void QRasterPaintEngine::clip(const QRect &rect, Qt::ClipOperation op) + QPaintEngineEx::clip(rect, op); + return; + +- } else if (!setClipRectInDeviceCoords(s->matrix.mapRect(rect), op)) { ++ } else if (!setClipRectInDeviceCoords(s->matrix.mapRect(QRectF(rect)).toRect(), op)) { + QPaintEngineEx::clip(rect, op); + return; + } +diff --git a/src/gui/painting/qtransform.cpp b/src/gui/painting/qtransform.cpp +index 6354b154c5..336493d7c5 100644 +--- a/src/gui/painting/qtransform.cpp ++++ b/src/gui/painting/qtransform.cpp +@@ -1521,12 +1521,12 @@ QRegion QTransform::map(const QRegion &r) const + QRegion res; + if (m11() < 0 || m22() < 0) { + for (const QRect &rect : r) +- res += mapRect(rect); ++ res += mapRect(QRectF(rect)).toRect(); + } else { + QVarLengthArray rects; + rects.reserve(r.rectCount()); + for (const QRect &rect : r) { +- QRect nr = mapRect(rect); ++ QRect nr = mapRect(QRectF(rect)).toRect(); + if (!nr.isEmpty()) + rects.append(nr); + } +diff --git a/tests/auto/gui/painting/qpainter/tst_qpainter.cpp b/tests/auto/gui/painting/qpainter/tst_qpainter.cpp +index bc0baed15c..bdac1c2430 100644 +--- a/tests/auto/gui/painting/qpainter/tst_qpainter.cpp ++++ b/tests/auto/gui/painting/qpainter/tst_qpainter.cpp +@@ -153,10 +153,10 @@ private slots: + void clippedLines(); + void clippedPolygon_data(); + void clippedPolygon(); +- + void clippedText(); + + void clipBoundingRect(); ++ void transformedClip(); + + void setOpacity_data(); + void setOpacity(); +@@ -4533,6 +4533,53 @@ void tst_QPainter::clipBoundingRect() + + } + ++void tst_QPainter::transformedClip() ++{ ++ QImage img(8, 4, QImage::Format_ARGB32_Premultiplied); ++ QImage img2(img.size(), img.format()); ++ QRect clip(0, 0, 2, 1); ++ QTransform xf; ++ xf.translate(0.2, 0); ++ xf.scale(2.2, 1); ++ // setClipRect(QRectF) ++ { ++ img.fill(Qt::green); ++ QPainter p(&img); ++ p.setTransform(xf); ++ p.setClipRect(QRectF(clip)); ++ p.fillRect(img.rect(), Qt::white); ++ } ++ // setClipRect(QRect) ++ { ++ img2.fill(Qt::green); ++ QPainter p(&img2); ++ p.setTransform(xf); ++ p.setClipRect(clip); ++ p.fillRect(img2.rect(), Qt::white); ++ QCOMPARE(img, img2); ++ } ++ // setClipRegion ++ { ++ img2.fill(Qt::green); ++ QPainter p(&img2); ++ p.setTransform(xf); ++ p.setClipRegion(QRegion(clip) + QRect(0, 3, 1, 1)); // dummy extra rect to avoid single-rect codepath ++ p.fillRect(img2.rect(), Qt::white); ++ QCOMPARE(img.copy(0, 0, 8, 2), img2.copy(0, 0, 8, 2)); ++ } ++ // setClipPath ++ { ++ img2.fill(Qt::green); ++ QPainter p(&img2); ++ p.setTransform(xf); ++ QPainterPath path; ++ path.addRect(clip); ++ p.setClipPath(path); ++ p.fillRect(img2.rect(), Qt::white); ++ QCOMPARE(img, img2); ++ } ++} ++ + #if defined(Q_OS_MAC) + // Only Mac supports sub pixel positions in raster engine currently + void tst_QPainter::drawText_subPixelPositionsInRaster_qtbug5053() +-- +2.24.1.windows.2 + +From b9570898b780f9981010fb07f49875ad55467e4a Mon Sep 17 00:00:00 2001 +From: Tang HaiXiang +Date: Fri, 24 Jul 2020 16:48:36 +0800 +Subject: [PATCH 3/3] Fix under non-integer scaling incorrect update area + +Given some decimal scaling, the clipping of the QRegion/QRect passed to the QRegion/QRect done inside paintEvent cannot handle the decimal scaling. +Solved by only converting QRect to a certain QRectF and calling QRectF overload instead of QRect. + +Fixes: QTBUG-82601 +Fixes: QTBUG-64854 +Change-Id: I0d8f4193aabfc0d917612db68d2a39ebb726fa2f +Reviewed-by: Eirik Aavitsland +(cherry picked from commit b4aee30692c166025b4e2283c19dbc1247bcce54) +Reviewed-by: Qt Cherry-pick Bot +(cherry picked from commit 5de4b9b1e5eb1ae8d922ee96d88eb6bba05b2b45) +--- + src/gui/kernel/qhighdpiscaling_p.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/gui/kernel/qhighdpiscaling_p.h b/src/gui/kernel/qhighdpiscaling_p.h +index f58944a7d2..dd30b1e758 100644 +--- a/src/gui/kernel/qhighdpiscaling_p.h ++++ b/src/gui/kernel/qhighdpiscaling_p.h +@@ -204,7 +204,7 @@ inline QRegion scale(const QRegion ®ion, qreal scaleFactor, QPoint origin = Q + + QRegion scaled; + for (const QRect &rect : region) +- scaled += scale(rect, scaleFactor, origin); ++ scaled += scale(QRectF(rect), scaleFactor, origin).toRect(); + return scaled; + } + +-- +2.24.1.windows.2 + +From 86c5197abc5e4f4314a14eb8a36ff0432817c7d2 Mon Sep 17 00:00:00 2001 +From: Friedemann Kleint +Date: Thu, 12 Sep 2019 08:54:58 +0200 +Subject: [PATCH 2/5] Windows QPA: Fix missing resize when changing the scale + factor +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Do not suppress the resize event caused by the handling of +WM_DPICHANGED unless the screen really changed. + +Fixes: QTBUG-76510 +Change-Id: I8b9ae41ad7deb863c1633ec5901bc04304b2165c +Reviewed-by: Tor Arne Vestbø +(cherry picked from commit 2dd781df87b98697c815183e4abeb226577230ab) +--- + src/plugins/platforms/windows/qwindowswindow.cpp | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp +index adf0f918ca..bba01b9818 100644 +--- a/src/plugins/platforms/windows/qwindowswindow.cpp ++++ b/src/plugins/platforms/windows/qwindowswindow.cpp +@@ -1897,8 +1897,10 @@ void QWindowsWindow::handleGeometryChange() + { + const QRect previousGeometry = m_data.geometry; + m_data.geometry = geometry_sys(); +- if (testFlag(WithinDpiChanged)) +- return; // QGuiApplication will send resize ++ if (testFlag(WithinDpiChanged) ++ && QWindowsContext::instance()->screenManager().screenForHwnd(m_data.hwnd) != screen()) { ++ return; // QGuiApplication will send resize when screen actually changes ++ } + QWindowSystemInterface::handleGeometryChange(window(), m_data.geometry); + // QTBUG-32121: OpenGL/normal windows (with exception of ANGLE) do not receive + // expose events when shrinking, synthesize. +-- +2.24.1.windows.2 + +From 60f67a2cb5f3c1148ef6b5803183f46b2b3f9478 Mon Sep 17 00:00:00 2001 +From: Oliver Wolff +Date: Fri, 21 Feb 2020 09:10:28 +0100 +Subject: [PATCH 3/5] qwindowswindow: Fix screen changes between different DPI + screens for native windows +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +When asynchronous events are used for notifications about screen changes +it is possible that we run into a race condition where the scale factor +has not yet been updated for the new screen. This results in a wrong +geometry being set for the window that is moved between the screens. +We do not have that problem with synchronous events. + +Change-Id: I4eb6d2a7cb49517d271901b479f973e273a0926a +Amends: 7eed1e40d4d3b6a066bac52995eed7e75d17de2d +Task-number: QTBUG-65580 +Fixes: QTBUG-82312 +Reviewed-by: Friedemann Kleint +Reviewed-by: Tor Arne Vestbø +(cherry picked from commit 529cfe4e22cc02dc7c29f653e8ff23656aa16ff9) +--- + src/plugins/platforms/windows/qwindowswindow.cpp | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp +index bba01b9818..a3374a237d 100644 +--- a/src/plugins/platforms/windows/qwindowswindow.cpp ++++ b/src/plugins/platforms/windows/qwindowswindow.cpp +@@ -1887,10 +1887,8 @@ void QWindowsWindow::checkForScreenChanged(ScreenChangeMode mode) + qCDebug(lcQpaWindows).noquote().nospace() << __FUNCTION__ + << ' ' << window() << " \"" << (currentScreen ? currentScreen->name() : QString()) + << "\"->\"" << newScreen->name() << '"'; +- if (mode == FromGeometryChange) +- setFlag(SynchronousGeometryChangeEvent); + updateFullFrameMargins(); +- QWindowSystemInterface::handleWindowScreenChanged(window(), newScreen->screen()); ++ QWindowSystemInterface::handleWindowScreenChanged(window(), newScreen->screen()); + } + + void QWindowsWindow::handleGeometryChange() +-- +2.24.1.windows.2 + +From 2901b92720135e8e2f0d2a1266826c6b47163875 Mon Sep 17 00:00:00 2001 +From: Friedemann Kleint +Date: Tue, 14 Apr 2020 11:03:32 +0200 +Subject: [PATCH 4/5] Windows QPA: Fix geometry when firing a full expose +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +There are several places in the code where a full expose +event is fired, but the geometry in logical coordinates is +used (pre-dating High DPI scaling). Fix by introducing a +helper function for it. + +Task-number: QTBUG-83449 +Change-Id: Ie8bb306de0b9b2b85306ed1bb6ba71181b76a958 +Reviewed-by: André de la Rocha +Reviewed-by: Oliver Wolff +(cherry picked from commit 4bb803477bacc70f756b1aaea9e048b2bae0fa6a) +--- + src/plugins/platforms/windows/qwindowswindow.cpp | 13 +++++++++---- + src/plugins/platforms/windows/qwindowswindow.h | 1 + + 2 files changed, 10 insertions(+), 4 deletions(-) + +diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp +index a3374a237d..1a78c692b1 100644 +--- a/src/plugins/platforms/windows/qwindowswindow.cpp ++++ b/src/plugins/platforms/windows/qwindowswindow.cpp +@@ -1341,6 +1341,11 @@ void QWindowsWindow::fireExpose(const QRegion ®ion, bool force) + QWindowSystemInterface::handleExposeEvent(window(), region); + } + ++void QWindowsWindow::fireFullExpose(bool force) ++{ ++ fireExpose(QRect(QPoint(0, 0), m_data.geometry.size()), force); ++} ++ + void QWindowsWindow::destroyWindow() + { + qCDebug(lcQpaWindows) << __FUNCTION__ << this << window() << m_data.hwnd; +@@ -1501,7 +1506,7 @@ void QWindowsWindow::setVisible(bool visible) + // over the rendering of the window + // There is nobody waiting for this, so we don't need to flush afterwards. + if (isLayered()) +- fireExpose(QRect(0, 0, win->width(), win->height())); ++ fireFullExpose(); + // QTBUG-44928, QTBUG-7386: This is to resolve the problem where popups are + // opened from the system tray and not being implicitly activated + +@@ -1906,7 +1911,7 @@ void QWindowsWindow::handleGeometryChange() + && m_data.geometry.size() != previousGeometry.size() // Exclude plain move + // One dimension grew -> Windows will send expose, no need to synthesize. + && !(m_data.geometry.width() > previousGeometry.width() || m_data.geometry.height() > previousGeometry.height())) { +- fireExpose(QRect(QPoint(0, 0), m_data.geometry.size()), true); ++ fireFullExpose(true); + } + + const bool wasSync = testFlag(SynchronousGeometryChangeEvent); +@@ -2094,7 +2099,7 @@ void QWindowsWindow::handleWindowStateChange(Qt::WindowStates state) + QWindow *w = window(); + bool exposeEventsSent = false; + if (isLayered()) { +- fireExpose(QRegion(0, 0, w->width(), w->height())); ++ fireFullExpose(); + exposeEventsSent = true; + } + const QWindowList allWindows = QGuiApplication::allWindows(); +@@ -2102,7 +2107,7 @@ void QWindowsWindow::handleWindowStateChange(Qt::WindowStates state) + if (child != w && child->isVisible() && child->transientParent() == w) { + QWindowsWindow *platformWindow = QWindowsWindow::windowsWindowOf(child); + if (platformWindow && platformWindow->isLayered()) { +- platformWindow->fireExpose(QRegion(0, 0, child->width(), child->height())); ++ platformWindow->fireFullExpose(); + exposeEventsSent = true; + } + } +diff --git a/src/plugins/platforms/windows/qwindowswindow.h b/src/plugins/platforms/windows/qwindowswindow.h +index ce67e46df3..9fb4492150 100644 +--- a/src/plugins/platforms/windows/qwindowswindow.h ++++ b/src/plugins/platforms/windows/qwindowswindow.h +@@ -361,6 +361,7 @@ private: + void handleWindowStateChange(Qt::WindowStates state); + inline void destroyIcon(); + void fireExpose(const QRegion ®ion, bool force=false); ++ void fireFullExpose(bool force=false); + + mutable QWindowsWindowData m_data; + QPointer m_menuBar; +-- +2.24.1.windows.2 + +From 8b6300ddaf36b11ab54a504f438c96c19e545f7d Mon Sep 17 00:00:00 2001 +From: Friedemann Kleint +Date: Tue, 14 Apr 2020 08:09:04 +0200 +Subject: [PATCH 5/5] Windows QPA: Fix restoring from fullscreen in High DPI + setups + +The logic for checking whether the saved geometry (native pixels) +is still within a screen compared them against logical coordinates. +Work with the platform screen geometry instead. + +Fixes: QTBUG-83448 +Change-Id: Ib68f967d1a33a490f88a7bec6dcc788788a10389 +Reviewed-by: Oliver Wolff +(cherry picked from commit c92fedd761206231f13838528943619b84df55bf) +--- + src/plugins/platforms/windows/qwindowswindow.cpp | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp +index 1a78c692b1..66f0d3cb39 100644 +--- a/src/plugins/platforms/windows/qwindowswindow.cpp ++++ b/src/plugins/platforms/windows/qwindowswindow.cpp +@@ -2221,8 +2221,10 @@ void QWindowsWindow::setWindowState_sys(Qt::WindowStates newState) + if (!screen) + screen = QGuiApplication::primaryScreen(); + // That area of the virtual desktop might not be covered by a screen anymore. +- if (!screen->geometry().intersects(m_savedFrameGeometry)) +- m_savedFrameGeometry.moveTo(screen->geometry().topLeft()); ++ if (const auto platformScreen = screen->handle()) { ++ if (!platformScreen->geometry().intersects(m_savedFrameGeometry)) ++ m_savedFrameGeometry.moveTo(platformScreen->geometry().topLeft()); ++ } + + if (newState & Qt::WindowMinimized) { + setMinimizedGeometry(m_data.hwnd, m_savedFrameGeometry); +-- +2.24.1.windows.2 +