The art of using GSettings in a library

While providing GActions in a library can be done quite naturally, for GSettings it is more complicated.

To simplify, GSettings is used by GTK applications to store their settings. Libraries usually provide GObject properties, and the application can bind the properties to the corresponding GSettings key with the g_settings_bind() function. So far so good.

For the libdevhelp I wanted to go one step further, and provide a GSettings schema in the library itself.

Taking a step back – why?

It is no secret that the goal is to create a software product line. By being able to create new API browsers super easily. But there is already the Devhelp application, you say. Yes, and currently that application is still generic, it is suitable for any development platform as long as the API references follow a certain format (HTML pages plus a *.devhelp2 index file). But more features could be added to Devhelp, like downloading the API documentation for a certain development platform, or having a start page with the most common libraries. If those features are added directly to the Devhelp application, for the GNOME development platform, then the Devhelp application would no longer be suitable for other development communities, and we prefer to keep the door open.

So if several API browsers products are created on top of the libdevhelp, it would be nice to avoid work duplication, and this includes the GSettings handling.

Handling GSettings in a library

Who says GSettings says creating a GSettings schema. Who says GNOME library says parallel-installability for the different major versions of that library. Thus, the GSettings schemas must also be parallel-installable. Little problem: when migrating to a new major version, the user doesn’t want to lose all his/her settings.

And here is one thing that – in my humble opinion – GSettings doesn’t handle well: keys and settings migration. With the GSettings API the schema needs to be installed. In the situation of a migration, the old schema is usually not installed. So it’s a bit more difficult to get the values for the old keys.

Settings migration can be useful for applications too, when wanting to do refactorings in the GSettings schema, for example when renaming a key. Or when renaming the whole application.

The solution in the libdevhelp: have a relocatable schema. At runtime the schema is relocated to the desired path. And I’ve written a small utility, DhDconfMigration, to migrate individual keys when dconf is used as the GSettings backend (and now Flatpak applications are moving away from dconf, but the same principle can be applied to other GSettings backends). DhDconfMigration is currently used by GNOME LaTeX to migrate the settings from LaTeXila (the application has been renamed). But DhDconfMigration (or the same kind of utility for another backend) is not yet useful for the libdevhelp, it was written to ensure that migrating keys is possible if the need arises.

Another thing that I wanted to solve in the libdevhelp with regards to the GSettings handling: make the use of GSettings optional for certain keys, when an application doesn’t want to provide a setting for a certain feature. In that case, it’s the same as using a simple GObject property. So binding the property to the GSettings key is optional.

The result

The above explanation is maybe a little complicated, and you may think that putting GSettings in a library is over-engineered, but using the resulting libdevhelp API is actually very simple, and it simplifies the application(s) implementation, so all is good, right?

For those interested, I’ll let you browse the gschema and the API reference of DhSettingsBuilder and DhSettings. It uses the builder pattern described by Benjamin Otte. Other classes and widgets in the libdevhelp use DhSettings to access the settings. The solution is not perfect, there is room for improvement, but I think it’s a good enough solution. And good enough is.. good enough 🙂 The source code contains more comments and improvement ideas.

Leave a Reply

Your email address will not be published. Required fields are marked *