Skip to content

Instantly share code, notes, and snippets.

@shundhammer
Last active September 13, 2022 11:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save shundhammer/79d534b8452554b16fb2f667f58290f9 to your computer and use it in GitHub Desktop.
Save shundhammer/79d534b8452554b16fb2f667f58290f9 to your computer and use it in GitHub Desktop.
YaST Qt, HiDPI and Fonts

YaST Qt, HiDPI and Fonts

Links

Bugzilla

Web

Latest News

We are now setting those environment variables directly:

QT_SCALE_FACTOR=1.75

(for 168 dpi)

QT_SCALE_FACTOR_ROUNDING_POLICY="PassThrough"

(to avoid rounding)

We are no longer setting the Xft.dpi X resource.

If the monitor reports no reasonable EDID, boot the installation ISO with your real monitor width in millimeters (use an old-fashioned ruler to measure it):

YAST_MON_WIDTH_MM=260

More details: yast/yast-installation#1057

Older Notes

Source Code

Qt HiDPI Interfaces

Related Qt Environment Variables

  • QT_SCALE_FACTOR
  • QT_SCALE_FACTOR_ROUNDING_POLICY
    • Round
    • Ceil
    • Floor
    • RoundPreferFloor
    • PassThrough
  • QT_SCREEN_SCALE_FACTORS
  • QT_USE_PHYSICAL_DPI
  • QT_FONT_DPI
  • QT_DPI_ADJUSTMENT_POLICY
  • QT_ENABLE_HIGHDPI_SCALING

  • QT_AUTO_SCREEN_SCALE_FACTOR (X11 only, deprecated on all other platforms)
  • QT_DEVICE_PIXEL_RATIO (deprecated)

Notes

Common HiDPI Resolutions

  • 2560x1080 UW-UXGA
  • 2560x1440 WQHD, 1440p
  • 2560x1600 WQXGA
  • 3200x1600 QHD+
  • 3440x1440 UW-QHD
  • 3840x1600 UW-QHD+
  • 3840x2160 QFHD, 4K, UltraHD, UHD-1
  • 3840x2400 WQUXGA
  • 4096x2160 DCI 4K
  • 5120x2880 5K

Common DPI Values

All multiples of 48

  • 96 (min for YaST)
  • 144
  • 192
  • 240
  • 288 (max for YaST)
  • 336
  • 384

Notes from Digging in the Qt Sources

  • We set Qt::AA_DisableHighDpiScaling, so in gui/kernel/qhighdpiscaling.cpp

    • QHighDpiScaling::m_usePixelDensity is true,
    • usePixelDensity() returns true
    • QHighDpiScaling::m_pixelDensityScalingActive is true,
    • QHighDpiScaling::m_active is true
  • By default, Qt rounds the scale factor to an integer; so in practice, it's either 1.0 or 2.0.

  • We set the Xft.dpi X resource, so in plugins/platforms/xcb/qxcbscreen.cpp the value is picked up in QXcbVirtualDesktop::readXResources(), so it is returned by

    • QXcbVirtualDesktop::m_forcedDpi
    • QXcbVirtualDesktop::forcedDpi()
    • QXcbScreen::forcedDpi()
    • QXcbScreen::logicalDpi()

    and QWindowSystemInterface::handleScreenLogicalDotsPerInchChange() is called with that value.

  • logicalBaseDpi() has a default implementation in gui/kernel/qplatformscreen.h as QDpi( 96, 96 ), and the xcb platform (X11) overrides it with the same value in platforms/xcb/qxcbscreen.h.

  • The ratio between that logicalBaseDpi (a default value of 96 dpi) and the logicalDpi() value (i.e. what we set in the Xft.dpi X resource based on what xrandr tells us) is the raw scale factor:

    factor = qreal(platformLogicalDpi.first) / qreal(platformBaseDpi.first);

    e.g. 144 / 96 = 1.5

    which is then rounded to the next integer value, i.e. 2 in this case.

y2logs

y2logs Tarball from Comment #2 (jsudermann)

Xorg.0.log

[    82.995] (II) modeset(0): clock: 152.8 MHz   Image Size:  344 x 193 mm
[    82.995] (II) modeset(0): h_active: 1920  h_sync: 2000  h_sync_end 2054 h_blank_end 2250 h_border: 0
[    82.995] (II) modeset(0): v_active: 1080  v_sync: 1086  v_sync_end 1094 v_blanking: 1132 v_border: 0

y2start.log

Stage [call]: Monitor size: eDP-1 connected primary 1920x1080+0+0 (normal left inverted right x axis y axis) 344mm x 193mm
Stage [call]: Monitor width mm: 344
Stage [call]: Monitor width px: 1920
Stage [call]: Monitor dpi: 144
Stage [call]: Xft.dpi set to: 144

y2log

2022-04-29 14:43:46 <1> install(4700) [qt-ui]

  YQUI.cc(calcDefaultSize):370 -fullscreen: using 960 x 540 for `opt(`defaultsize)
  YQUI.cc(calcDefaultSize):404 Default size: 960 x 540
  YQApplication.cc(pickAutoFonts):471 Selecting auto fonts - normal: 10, heading: 12 (bold)
  YQApplication.cc(currentFont):339 Loaded 10 pixel font: Sans Serif,-1,10,5,50,0,0,0,0,0
YQUI.cc(calcDefaultSize):370 -fullscreen: using 960 x 540 for `opt(`defaultsize)

?!? Why does it use 960 x 540 for fullscreen?

https://github.com/libyui/libyui/blob/master/libyui-qt/src/YQUI.cc#L370

    QSize availableSize = screen->availableSize();

So Qt thinks we are in HiDPI mode, scaling everything? It's using half the resolution values of 1920 x 1080 in both dimensions.

And we also requested only a moderate font size: 10 px for normal text, 12 px for headings.

@joseivanlopez
Copy link

Result of xrandr on Dell XPS 13 9310:

Screen 0: minimum 16 x 16, current 3840 x 2400, maximum 32767 x 32767
XWAYLAND0 connected primary 3840x2400+0+0 (normal left inverted right x axis y axis) 290mm x 180mm
   3840x2400     59.99*+
   2048x1536     59.95
   1920x1440     59.90
   1600x1200     59.87
   1440x1080     59.99
   1400x1050     59.98
   1280x1024     59.89
   1280x960      59.94
   1152x864      59.96
   1024x768      59.92
   800x600       59.86
   640x480       59.38
   320x240       59.52
   2560x1600     59.94
   1920x1200     59.88
   1680x1050     59.95
   1440x900      59.89
   1280x800      59.81
   720x480       59.71
   640x400       59.95
   320x200       58.96
   3840x2160     59.98
   3200x1800     59.96
   2880x1620     59.96
   2560x1440     59.96
   2048x1152     59.90
   1920x1080     59.96
   1600x900      59.95
   1368x768      59.88
   1280x720      59.86
   1024x576      59.90
   864x486       59.92
   720x400       59.55
   640x350       59.77

@shundhammer
Copy link
Author

shundhammer commented Sep 6, 2022

On @joseivanlopez 's setup, this would be 3840x2400 on a 290mm x 180mm screen, i.e. 336 dpi.

@joseivanlopez
Copy link

And

xrdb -query | grep dpi
xft.dpi:     192

@shundhammer
Copy link
Author

Tried booting a Leap 15.4 ISO in VirtualBox with boot parameters:

  • edid=1920x1080,344x193 - worked nicely; no HiDPI detected (which was correct); reasonable font sizes; but 0mm x 0mm screen (?)
  • edid=3840x2400,290x180 - arrived correctly (as far as I can tell), was logged in y2start.log, but the resolution fell back to 800x600, and the physical size was also 0mm x 0mm (?)

Notice that changing the maximum resolution in the VirtualBox preferences is needed for this to have any effect.

vbox-display-pref

@shundhammer
Copy link
Author

https://bugzilla.suse.com/show_bug.cgi?id=1199020#c60

AFAICS we have two heuristics which are now (since the introduction of that scale factor rounding) defeating each other:

  • We calculate a DPI value from the physical screen dimensions in millimeters that "xrandr" reports and "clean it up", i.e. we make sure it's a number that can be divided by 48 (but no less than 96), i.e. one of 96, 144, 192, 240, 288 (but no more than that) and set the "Xft.dpi" X resource to that value.

  • Qt reads that X resource and stores the value as QXcbScreen::logicalDpi()

  • It uses that value and a default dpi value of 96 to calculate a scaling factor, e.g. 144 / 96 = 1.5 (which would be a reasonable factor)

  • It uses its new default rounding policy for that factor to round it to the next integer number; in this case 2.

  • It now uses that nicely rounded scaling factor for everything: Window size, widget sizes including borders and line widths; and fonts.

As a result, the fonts are now insanely oversized; no longer 150% of what we previously used, but 200%. And since all other geometry values in our YaST Qt UI depend on the font sizes, everything becomes way too large: Static texts, buttons, list content, everything.

@shundhammer
Copy link
Author

shundhammer commented Sep 12, 2022

We (@joseivanlopez and I) just did some experiments with his real hardware, that Dell XPS 13 9310 with a real HiDPI display with 3840x2400 on a 290mm x 180mm screen, i.e. 336 dpi. We used the latest TW NET ISO from opensuse.org.

By default, the fonts were way too small; Qt did not consider that a HiDPI setup and left everything as it was, i.e. the Qt UI got a screen->availableSize() of 3840x2400 (which it then reported as opt(defaultsize), as expected). There was no scaling done by Qt, even though the y2start.log reported a calculated 336 dpi, capped at 288 dpi (as expected); which should have resulted in a Qt scale factor of 288 / 96 = 3. But it used a scale factor of 1.

Then we tried passing some kernel parameters that, as we were told, would end up in the environment:

  • QT_SCALE_FACTOR_ROUNDING_POLICY=PassThrough

    which changed nothing at all;

  • QT_SCREEN_SCALE_FACTORS=4

    which did have an effect; the fonts now were quite large (a bit too large), and opt(defaultsize) now was 1/4 of the physical resolution, as expected (3840 / 4 = 960 and 2400 / 4 = 600).

Maybe we should ditch that indirect Xft.dpi mumbo-jumbo and simply set QT_SCREEN_SCALE_FACTORS directly from the yast2 start script; maybe with also setting QT_SCALE_FACTOR_ROUNDING_POLICY=PassThrough.

@shundhammer
Copy link
Author

@shundhammer
Copy link
Author

shundhammer commented Sep 13, 2022

Overriding the Monitor Size in mm and Script Debug Mode

With that PR, this is now also debuggable, and a user can override the monitor width in mm from the kernel command line of the installation media:

Boot with

YAST_MON_WIDTH_MM=200

(replace "200" with the real value, of course)

or start the script in debug mode with

FAKE_MON_WIDTH_MM=200 ./YaST2.call

Then it will only calculate the DPI and the scale factor, show them on stdout and then exit. Remember to also check /var/log/YaST2/y2start.log.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment