Linux, Icons, Pain, and Triumph

A few months ago I was working on Poki Launcher[1], my application launcher for Linux. An application launcher needs to enumerate all of the installed apps on the system. The way this is done is described by the Free Desktop desktop entry specification. While researching this and working on my app I realized that, since I wanted to display app's icons in my launcher, I would also need an implementation of the Free Desktop icon theme specification[2].

I don't want to go too deeply into what the Free Desktop icon theme specification is, but briefly, it allows an app that wants to display an icon for an app to find an icon of the right size, for some value of right, and find an icon from a given theme. Most apps ship with their own icons, it's part of their branding. But having all of the app icons on you system having been created by different people with different design sensibilities can be vary dissonant visually. This is why we have icon themes. Icon themes are a groups of icons for various apps that all look good together and have a similar design. The icon theme specification describes how these themes are structured and installed so they can override the default icons.

Getting back to the story, I needed a way to look up these icons and I couldn't find a Rust library to do so. So I endeavored to write my own implementation in Rust. Following the free desktop spec and looking at gnomes implementation I decided I needed to cache a bunch of data about these themes to make look ups FAST. I needed to parse these index files to find out where the icons I wanted where. They where basically ini files so I pulled in an ini parser I was using in Poki Launcher. I parsed all of the index files and created efficient lookup structures of all of the icons and cached them to disk using Cap'n Proto which serialized and de-serialized instantly! I wrote benchmarks and everything. This was going to be fast. And it was horribly slow. Now, loading the cache files and doing the look ups was fast, but generating the cache files took several seconds for larger themes. And the cache files where huge, tens of megabytes.

Discouraged I looked for other solutions and eventually I figured out how to get Qt's icon lookup functionality to work from Rust and used that for Poki Launcher. But now, a few months later and the problem is still nagging at me. The frontier yet untamed. There was still no Rust library for doing icon look ups on Linux. So about two weeks ago I decided to take another crack at the problem. This time with a different design in mind.

I still wanted it to be fast, but I wanted to take a different approach to it. This time I decided to forgo caching all together, at least initially, and just try to do the look up as fast as I could. I decided to write my own ini parser that was would only do what I needed it to and avoid coping a lot of data around. I also tried memory mapping the index files. The rest was fairly straight forward and I'm happy to say I got the library work. And it is pretty fast! I haven't done any formal benchmarking yet but using the time command on Linux it can find all the icons for Firefox in around than 0.01 on average. Obviously this isn't very scientific and I'll need to do more work to really optimize it but I feel good about the work thus far.

If your interested I've dubbed the library linicon[3] and put it on crates.io I've also written C ffi bindings for it[4].

[1] https://git.sr.ht/~zethra/poki-launcher [2] https://specifications.freedesktop.org/icon-theme-spec/icon-theme-spec-latest.html#context [3] https://git.sr.ht/~zethra/linicon [4] https://git.sr.ht/~zethra/linicon-ffi