Hi all,
I work on the Qt/Wayland side of LibreOffice's VCL plugin, and I'd like to ask
whether Qt could expose a screen's fractional scale before any window exists,
and if so, what shape you'd want it in.
Why it's needed: LibreOffice sizes its menus, toolbars and dialogs while
starting up, before it opens its first window. At that point
QScreen::devicePixelRatio() returns the integer wl_output scale, so on a 220%
desktop it reports 3 and the interface comes out about 1.36x too big. We
currently force Qt::HighDpiScaleFactorRoundingPolicy::Round and let the
compositor shrink the result, which wastes GPU work and softens everything. I
have a change under review in LibreOffice (208347, tdf#172896) that reads the
Wayland output directly instead, but our reviewer would rather we didn't carry
Wayland specific code if Qt could provide the value, which is why I'm asking
here first.
I've read 563344 ("Guess output devicePixelRatio from XdgOutput geometry"),
last updated June 2024, and 590173 ("Client: Get screen's fractional device
pixel ratio via xdg-output"), last updated October 2024. I'm not trying to
reopen those arguments. I have one case that wasn't discussed and some
measurements that may have moved the picture since.
The case: "use QWindow::devicePixelRatio() instead" has been the answer each
time, and for most applications it's the right one. It doesn't apply here
because there is no window yet. The layout happens before any surface is
committed, so wp_fractional_scale_v1's preferred_scale event (Morten's question
on 590173) hasn't arrived and can't.
The measurements: David's point on 590173 was that a slightly wrong scale is
worse than a rounded up one. I agree, so what I'd propose is a value that is
always checked, or reported as unavailable. The check is that the calculated
scale, rounded up, must equal the integer wl_output scale Qt already has.
Rather than assume that holds, I tested four compositors across seven output
configurations. KWin was on a real 4K panel, the rest headless. In every case
the calculated scale rounded up matched the integer wl_output scale:
-
KWin at 220%: calculated 2.20008, off by +0.00008
-
sway at 220%: calculated 2.20120, off by +0.00120
-
sway at 150%: calculated 1.50029, off by +0.00029
-
Hyprland at 240%: exact
-
mutter at 150%, 125% and 250%: exact in all three
So the worst error anywhere was 0.0012, about 0.05%. Mutter and Hyprland only
offer scales whose logical size divides evenly, so both come out exact. KWin
and sway accept arbitrary scales and round the logical size, which is the
entire source of the small errors above.
One thing I'd particularly like checked. QWaylandScreen::geometry() works
around mutter reporting a logical size equal to the native size (mutter issue
2631), which would make this calculation return 1.0. On mutter 50.3 I couldn't
reproduce that: it reported 2560x1440 at 1.5, 3072x1728 at 1.25 and 1536x864 at
2.5, all correctly divided. Issue 2631 says the problem only occurs when
scale-monitor-framebuffer is off, and mutter 50.3 answers "Unknown experimental
feature" when I try to enable it, which I read as it no longer being optional.
If that's right, xdgGeometryIsBogus now only covers older mutter, and the main
objection here is weaker than it was in 2024. I may be missing something and
would rather be told.
Limits of the above: only KWin was real hardware, the rest were headless
virtual outputs. I didn't test niri, labwc, wayfire or weston. And although
every compositor I tried reports the integer scale as the fractional scale
rounded up, I can't find anything in the protocol requiring it, so I'm treating
that as common practice rather than a guarantee.
So, which would you prefer? I'm happy to write whichever you think is right:
-
An accessor on the QWaylandScreen native interface returning the fractional
scale, or nothing when it can't be verified.
-
Something more primitive, such as the native pixel size, leaving the division
to the caller, so Qt isn't committing to a fractional scale at screen level.
-
Solving it in the protocol instead. David's closing note on 563344 pointed that
way and nothing seems to have filled the gap since. If that's still preferred,
I'd rather help push it there than add a workaround in Qt.
To be clear on scope: I'm only asking to read something Qt already knows
internally. I'm not proposing any change to what QScreen::devicePixelRatio()
returns or to how Qt scales anything, and nothing would behave differently
unless an application asks. Coupling those together seems to be part of why the
earlier attempts stalled.
I have a rough proof of concept against 6.9 and can put it on Gerrit as a work
in progress, and I'm happy to share the test setup behind that table if anyone
wants to reproduce it. I'm committed to finding a way to get this implemented
and will see it through however many revisions it takes.
Thanks for reading, Jamie Fitzgerald--
Development mailing list
[email protected]
https://lists.qt-project.org/listinfo/development