Get Hired

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.

An icon theme

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.

icon-theme.cache

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.

I went ahead and "reverse engineered" the GTK+ icon cache format in order to implement it in Qt. Having GTK+s' source code available to browse clearly helped.

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)

Conclusion

Thank you for reading so far. The summary is that Qt 5.7 will automatically use the GTK+ icon caches. Browse the source of QIconCacheGtkReader if you are interrested.

Woboq is a software company that specializes in development and consulting around Qt and C++. Hire us!

If you like this blog and want to read similar articles, consider subscribing via our RSS feed, by e-mail or follow us on twitter or add us on G+.

Submit on reddit Submit on reddit Tweet about it Share on Facebook Post on Google+

Article posted by Olivier Goffart on 16 June 2016

Get notified when we post a new interesting article!

© 2016 Woboq GmbH