QIcon::fromTheme uses GTK+'s icon cache in Qt 5.7

When you pass a name to
QIcon::fromTheme,
Qt needs to look up in the different folders
in order to know which theme contains the given icon and at which size. This might mean a lot
disk access needs to be done only in order to find out if the file exists. Applications such as
KMail can have
hundreds of icons for each of their menu actions.
In the KF5 port of KMail, 30% of its start-up time was spent loading those icons.

With Qt 5.7, the GTK+ icon cache will be used to speedup the
loading of icons.

Freedesktop icon themes

QIcon::fromTheme loads an icon as specified by the
Freedesktop
Icon Theme Specification and
Icon Naming Specification. It specifies the icon themes used by Linux desktops.
In summary, an icon theme consists of many folders containing the icons in PNG or SVG format.
Each folder contains the icon for a particular size and type. The type might be one of
"mimetypes", "actions", "apps". Size are usually all the common sizes. This represents quite a lot
of directories per theme. On my computer, Gnome's default theme has 106 folders; the Oxygen theme has 166;
Breeze has 56; hicolor has 483.
A theme can also specify one or several fallback themes. Icons which cannot be found in a given theme
need to be looked up in the fallback themes until an icon is found. The last resort fallback theme
is always "hicolor".

Icon names can contains dashes (-). The dash is used to separate levels of specificity.
For example, if the name to look up is "input-mouse-usb", and that this icon does not exist in the theme,
"input-mouse" will be looked up instead, until an icon is found.

The nature of these themes and the way icon are looked up implies that the icon engine needs to look at
many directories for the existence of files. This is especially true for filenames with many dashes, that might not
exist at all. This implies a lot of
stat() calls on the hard drive.

Icon Theme Cache

For the above reasons, desktop environments have been using caches to speed up icon loading.
In KDE4, KDE's KIconLoader used a shared memory mapped pixmap cache, where the
loaded icon data was shared across processes
(KPixmapCache).
When an application requested an icon of a given size, the cache was queried whether this icon for this size is
available. This gave good result at the time in KDE applications. However, this can't be used by pure Qt
applications. When running the KDE's Plasma desktop, the platform theme integration plugin can use
KIconLoader to load
icons which only works when running on Plasma. This caching is anyway not working well with
QIcon::fromTheme
because we need to know if a QIcon is null or not, and this forces a lookup regardless of the cache.

GTK+ also speeds up the icon lookup using a cache. They have a tool (gtk-update-icon-cache)
that generates a icon-theme.cache file for each theme. This file contains a hash table for fast lookup to
know if an icon is in the theme or not and at which size.
The icon cache is system-wide, and usually generated by the distribution's package manager.

Qt can now use GTK+ cache files

The question I asked myself is how to improve the performance of
QIcon::fromTheme
?
It is clear that we need to use a cache. Should we try to use the KDE pixmap cache?
I decided against the KDE pixmap cache because the cache is, in my opinion, at the wrong level.
We don't want to cache the icon data, we want to cache a way to get from the icon name to the right file.
The cache is also storing some other assets, we might get cache misses more often than we should.

The GTK+ cache is solving the right problem: It is system wide and most Linux distributions
already generate it. So I thought, we should just re-use the same cache.

Does that mean that Qt now depends on GTK+?

No, the use of this cache is optional. If the cache is not found or out of date, Qt will ignore the
cache and do the full look-ups as before.

How do I make sure the cache is used?

Every time you install an application that adds or removes icons from one of the themes, the
cache needs to be updated. Qt looks at the modification time of the directories, if any directory is
newer than the cache, the cache will not be used. You need to run gtk-update-icon-cache
after installing new icons, but most distributions take care of this for you.

How do I update the cache?

Run this command for every theme:

gtk-update-icon-cache /usr/share/icons/<theme-name> -i -t -f

-i makes it not include the image data into the cache (Qt does not
make use of that)