[Development] Wayland: getting a screen's fractional scale before the first window exists
Jamie Fitzgerald
jfitz1994 at pm.me
Sat Aug 8 00:34:46 CEST 2026
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
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.qt-project.org/pipermail/development/attachments/20260807/a709c9d7/attachment-0001.htm>
More information about the Development
mailing list