[Development] What to expect from QIcon/the icon engine on screen changes

Elvis Stansvik elvstone at gmail.com
Sat Apr 6 10:40:46 CEST 2019


Hi all,

I'm looking for someone who knows the inner workings of QIcon and the
icon engines.

In our application, we almost exclusively use SVG icons, and we use a
single SVG file for each icon (no @2x versions) that we try to design
to work reasonably well at all sizes, since we do not have the
resources to make custom variations for each target size.

We put these SVG icons into an XDG icon theme, that we ship inside the
application resources (.qrc) in the expected XDG layout and with an
icon theme index file. We can then use
QIcon::fromTheme("our-app-some-icon") to reference an icon (either
through the .ui file or in code).

The problem we've run into is that when the application is launched in
a mixed-DPI setup, for example a retina Mac laptop with an external
lower-DPI monitor, the icons appear too large and get cropped. In
effect, it seems to always use the DPI of the primary screen (the
built-in retina screen) when calculating the size of the pixmaps it
generates for the icons.

To work around this, we've had to put in special code in all of our
widgets that use icons. The code reacts to screen change events (or
changes to the underlying QWindow in some cases), and in that code, go
through each and every one of our icons and do this monkey dance:

        auto pixmap = someButton->icon().pixmap(someButton->iconSize());
        pixmap.setDevicePixelRatio(window()->windowHandle()->screen()->devicePixelRatio());
        someButton->setIcon(QIcon(pixmap));

So essentially taking the pixmap out of the icon, set its DPR to that
of the current screen, and then set that pixmap back on the icon.

This "works", the icons now look correct on both the retina screen and
the external one, and adjust themselves when the application is moved
back and forth, or when the external monitor is activated/deactivated.

But surely this kludge should not be necessary? We've provided Qt with
an SVG, so it should be able to work out on its own that the screen
has changed, and regenerate an appropriate pixmap in response to that?

Some more details:

- We are running with the Qt::AA_UseHighDpiPixmaps application
attribute turned on. I'm not sure this is relevant for this issue
though, because AFAIK that attribute is only about picking 2x versions
of icons (we have a couple of those, where we have PNGs with 2x
versions).

- We are not running with Qt's built-in scaling activated, but relying
on the Mac platform scaling (I'm not even sure Qt's built-in scaling
is applicable on Mac). The application runs with
NSHighResolutionCapable set to True in its Info.plist (which I also
think is the default nowadays).

- I have not investigated yet whether this problem also occurs on a
mixed-DPI Linux setup, with Qt's high-dpi scaling activated. Nor have
I checked if it happens on Windows using it's artificial "screen
scaling" (we do not use Qt's built-in scaling on Windows either,
trying to follow the advise in the docs to avoid that for new
applications). So for now this is only about Mac retina + external
monitor.

Any advise on this would be highly appreciated, because the code
required to re-trigger pixmap generation on screen changes is a real
kludge all over our code base, and often it happens that we add
buttons et.c. with icons, but forget to update this machinery.

I'm not at the office at the moment, but can provide a little test
program that mimics what we're doing on Monday.

Thanks in advance,
Elvis


More information about the Development mailing list