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

Reply via email to