HighDPI in KDE Applications

Recently I was asked about the state of High DPI in KDE Applications, by someone with a fancy screen.

In Plasma we have our own solution for solving the HighDPI problem, as we were working with new code where we provide the styling, this is all fairly straightforward. However, this doesn't work for applications which have a lot of existing code we need to bring this feature to.

This upcoming release of Qt (5.4) brings us everything we need to support High DPI in our applications. It's not going to be useful for end users just now, but this is a time where we need each and every developer to start getting interested and making sure their applications are ready.

Support requires at least one line of change in every application.

High DPI in Qt

Normally my application, will look something like this. On my screen this is fine,if you see this on a high DPI screen everything will be tiny.



If we change the DPI used in the fonts we, naturally, get bigger fonts. More usable, but all of the other controls are still hilariously small as they haven't changed. This is our current state.



Device Independent Pixels

Qt borrowed a concept used in Android and iOS of separating the pixel sizes we use in the code, to the actual pixel density on the screen.

From a programming perspective we keep coding like everything is in 96dpi like a normal desktop display, but underneath all co-ordinates and graphics will be doubled or quadrupled to scale up to the device resolution.

This API at a Qt level works per screen; with every screen having it's own independent scaling factor. However, in the X backend for Qt 5.4 it's loaded from an environment variable that applies to all screens. Not ideal, but better than nothing.

This gives a result, that is now usable, but very blocky and pixelated.
(you may need to click the image to really see this)



This blockiness problem is also solved. Whenever we create a pixmap we can make sure we provide graphics that have a higher size in device pixels than their size in user space.

To quote the QPixmap documentation, "For example, painting on a 200x200 image if with a ratio of 2.0 will result in effective (device-independent) painting bounds of 100x100.".

With "pixel" now meaning one of two things can get confusing very quickly.

As you might imagine, all of this wizardry under the scenes means it's moderated likely to break at least some applications. As Qt follows the rule of never breaking existing application it requires each and every application to opt in.

I added a command line flag --highdpi to oxygen-demo, the application in the screenshots, to enable the scaling support and test both side-by-side which finally leaves us with:



There were no additional changes to oxygen demo to make this work yet we see we're using high resolution pixmaps on the icons and on the clear buttons in the text field.

How to make sure your app works with Qt's high DPI

1) Port to Qt5
If you're putting it off porting because you're scared of regressions. The reality is over time you will have more bugs from not porting. Without Qt5 we don't get /any/ scaling. Not even the blocky version.

2) Opt in to the high DPI pixmap support
Add:

app.setAttribute(Qt::AA_UseHighDpiPixmaps, true);

to your main function

3) Port code
If you don't do any low level work with unusual QPainter painting, provide any of your own pixmaps or load textures in QQuickItems, everything will just work.

Most likely your app will have something broken. Useful links are here and here.

4) Test
I only have a poor person's screen, but it's still easy(ish) to test:

  • Change the DPI under system settings -> font -> force font DPI to 192
  • Set the environment variable QT_DEVICE_PIXEL_RATIO=2

On a normal screen everything will appear massive, but hopefully also super smooth.