Supporting desktop themes via the content interface


I’ve been experimenting with using the new content interface as a way of handling themes, and have got to a point where other people might find it interesting. The good news is that it looks like the new version of the content interface is sufficient for this use case.

For the experiment, I put together a set of snap packages whose snapcraft.yaml files can be found here:

… and binaries here:

Since there are no store assertions, it is necessary to connect up the content interfaces after installing the snaps:

snap connect gtk3-demo:gtk3-themes ubuntu-themes:gtk3-themes
snap connect gtk3-demo:icon-themes ubuntu-themes:icon-themes
snap connect gtk3-demo:gtk3-themes adwaita-theme:gtk3-themes
snap connect gtk3-demo:icon-themes adwaita-theme:icon-themes
snap connect gtk3-demo:gtk3-themes evopop-theme:gtk3-themes

(yes, this is connecting the plugs to multiple slots simultaneously). At this point, the gtk3-demo snap can use any of the themes provided by the theme snaps. For example, I can launch it with the EvoPop theme:

GTK_THEME=EvoPop snap run gtk3-demo

To get this to work, I use the content interface plugs to populate $SNAP/share/themes and $SNAP/share/icons with the data from the themes:

$ snap run --shell gtk3-demo
$ ls $SNAP/share/themes
Adwaita  Adwaita-dark  Ambiance  EvoPop  EvoPop-Azure  Radiance
$ ls $SNAP/share/icons
Adwaita  Humanity  Humanity-Dark  ubuntu-mono-dark  ubuntu-mono-light

If I install more themes providing the gtk3-themes slot and connect them up to the app, they will be visible too. This has a few benefits:

  1. there is no need for application snaps to have knowledge of individual themes: the single plug acts as an extension point for all themes.
  2. since we can connect all installed theme snaps up at once, we can support multi-user systems where different users have picked different themes. There’s no need to e.g. replug all the interfaces on login.

So where do we go from here?

Good experience for default themes

Without store support, we can’t easily determine which snap provides which themes. However, we could package the default themes of major Linux distros together and make that snap the default provider for the plug on the app.

When snapd gains support for automatically installing snaps required to satisfy content plugs, it would also handle this default themes snap.

This would not preclude the packaging of additional themes as their own snaps: we just wouldn’t have a way to automatically install said snaps. This might not be so bad in the short term, since users will generally need to install additional themes manually anyway.

Developer experience

As you can see in my sample gtk3-demo snapcraft.yaml file, I had to add extra boilerplate plug definitions to support this. It would be nice to avoid this, since it adds another opportunity to introduce errors.

I think we could improve this with a fairly simple modification to Snapcraft:

  1. allow plugs and slots sections under each part in snapcraft.yaml.
  2. when constructing the meta/snap.yaml file, iterate through each part level plug or slot:
    • if a plug/slot of the same name doesn’t exist, copy it up to the top level
    • if there is an existing definition, perform a deep comparison with the top level version and error out if they differ.

This would make it possible for a cloud part to introduce new plug/slot definitions into projects that use them.

What about Qt apps?

There’s two basic modes that a Qt app can run in:

  1. use the platform theme plugin
  2. use some other platform theme plugin

Case (1) is what you’d normally see when running Qt apps on GTK based desktops (GNOME 3, Unity, Mate, Budgie, etc). Since it defers to the GTK theme, it will work just as well as any GTK app.

Case (2) is what you’d see on a KDE desktop. Instead, the theme is implemented by a shared library that needs to be provided via a Qt plugins directory hierarchy.

If we can share individual files via the content interface, we might be able to present all platform theme shared libraries in a single directory. If not, then we’d probably need to rely on desktop-launch to construct a QT_PLUGIN_PATH based on the directories made available by the content interface.

Libreoffice snap: missing features and known bugs
Auto-connection of gtk3-themes, icon-themes, and sound-themes interfaces
Evince snap does not open comic book file (cbr) while deb does so

Finally, i have been waiting for this :heart_eyes:

Edited: It would be hard updating default themes snap, as i have seen themes maintainer usually release update frequently. e.g, Adapta… and the size of the snap be will big.


Following on from discussion at the current sprint, we will be creating a snap that can act as the “default provider” for the theme plug and contain the default themes for common Linux distros.

This will not preclude third party theme authors from publishing theme snaps independently, but will allow snapd to install a useful set of themes when the user first installs an application that supports plugging themes.

The skeleton of this snap can be found here:

With GTK and icon themes for Ubuntu, Fedora/vanilla GNOME, and Solus, the snap totals 27 MB. Most of that is icons, so the cost of adding more distro themes will mostly depend on how different their icons are.

To get some idea of how this will affect overall disk space, I looked at the Slack snap as an example of a snap that is bundling some theme data. A .tar.gz file of its usr/share/themes and usr/share/icons directories comes out to about 7 MB, so with four such applications installed, this would be disk space neutral. The exact point where it starts saving space will really depend on how many distro default themes we end up shipping this way.

Snap application and snap themes
Snap application and snap themes

So freaking awesome. Can’t wait for it


Adapta is pretty common theme now a days
Add that too and Add some Cursor Icons also

Adapta Theme

Breeze-Snow (Cursor Theme)
Bibata Cursor


Do you think we can start to use this in our snaps to day and what’s the way to specify the dependency to it ? I’d like to test it on a snap which is only one the edge channel for now.


We are drafting our initial proposal still for a snapcraft templates feature which should be considered to solve this particular problem.