Details
-
Bug
-
Resolution: Duplicate
-
P2: Important
-
None
-
6.3.0
-
None
Description
I have desktop setup consisting of 2 screens and a layout like on image below
Screen scales:
#1 - 175%
#2 - 100%
and there is no any environment varialbe set that affects scaling.
Application creates QScreen object for each screen in order : #2, #1
Let's see what is happening on application start.
First, QHighDpiScaling::initHighDpiScaling() is called and it initializes static member QHighDpiScaling::m_active
// Set initial active state
m_active = m_globalScalingActive || m_usePlatformPluginDpi;
_*where _m_usePlatformPluginDpi* is true by default.
Then QScreen for display #2 is created in QWindowSystemInterface::handleScreenAdded(). Functions inside QScreen construction initilizes geometry of the screen object which are in independent device units. It's important to note that at this moment QHighDpiScaling::m_active is true and returned scale factor is correct (which is 1.0 in fact). After that QHighDpiScaling::updateHighDpiScaling() is called.
QHighDpiScaling::updateHighDpiScaling() updates value of QHighDpiScaling::m_active with code:
// Check if any screens (now) has a scale factor != 1 and set // m_platformPluginDpiScalingActive if so. if (m_usePlatformPluginDpi && !m_platformPluginDpiScalingActive ) { const auto screens = QGuiApplication::screens(); for (QScreen *screen : screens) { if (!qFuzzyCompare(screenSubfactor(screen->handle()), qreal(1))) { m_platformPluginDpiScalingActive = true; break; } } } m_active = m_globalScalingActive || m_screenFactorSet || m_platformPluginDpiScalingActive;
At this moment QGuiApplication::screens() contains only one screen with scale factor == 1.0. So, here is important that _m_platformPluginDpiScalingActive_ is false (2 others bool variables also false) and as result m_active becomes false too.
Next we go to creation of next QScreen object for display #1. And here initialization of screen geometry goes wrong. Geometry is calculated by function QPlatformScreen::
deviceIndependentGeometry().
QRect QPlatformScreen::deviceIndependentGeometry() const { qreal scaleFactor = QHighDpiScaling::factor(this); QRect nativeGeometry = geometry(); return QRect(nativeGeometry.topLeft(), QHighDpi::fromNative(nativeGeometry.size(), scaleFactor)); }
And here qreal scaleFactor = QHighDpiScaling::factor(this); instead of scale equal to 1.75 returns 1.0. And the reason is that QHighDpiScaling::m_active is false and 1.0 is a fallback value.
Possible solution
Call QHighDpiScaling::updateHighDpiScaling() after creation of all QScreen objects and not after each one.
Temporary fix
Call QHighDpiScaling::setGlobalFactor() to set some custom scale factor and then call second one with scale == 1.0. Call of this function leads to recalculation of screens geometry.
Test project
Attachments contains test project to reproduce the bug.
main.cpp contains defs that can be enabled/disabled. Without temporary fix application outputs:
"\\\\.\\DISPLAY2" QRect(0,0 3440x1440) "\\\\.\\DISPLAY1" QRect(-1920,0 1920x1080)
With temporary fix:
"\\\\.\\DISPLAY2" QRect(0,0 3440x1440) "\\\\.\\DISPLAY1" QRect(-1920,0 1097x617)