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.

Expanding Amtk to support GUIs with headerbar

I initially created the Amtk library to still be able to conveniently create a traditional UI without using deprecated GTK+ APIs, for GNOME LaTeX. But when working on Devhelp (which has a modern UI with a GtkHeaderBar) I noticed that some pieces of information were duplicated in order to create the menus and the GtkShortcutsWindow.

So I’ve expanded Amtk to support GUIs with GtkHeaderBar and GtkShortcutsWindow, and ported Devhelp to Amtk. I’m quite happy with the result, there are fewer lines of code, it avoids information duplication, all the extra information about the GActions are centralized (so inconsistencies are easier to catch), and on top of that Amtk has been designed to be able to share the extra GActions information in a library, so it’ll be possible to provide a higher-level API for the libdevhelp.

Read the Amtk introduction for more details.

PS: oh, and I’ve moved Amtk to its own git repository now, it was initially developed inside Tepl.

Devhelp news

Some news for your beloved API documentation browser, Devhelp!

I’ve written recently a roadmap for Devhelp and its library. It serves as a good summary of what has been achieved recently, with some future plans. Most of what I’ve done so far are under-the-hood changes, so it’s not directly visible in the application, except – hopefully – the better quality/stability (I’ve discovered and fixed a lot of bugs when doing refactorings).

For more context, I started to contribute to Devhelp in 2015 to fix some annoying bugs (it’s an application that I use almost every day). Then I got hooked, I contributed more, became a co-maintainer last year, etc. Devhelp is a nice little project, I would like it to be better known and used more outside of GNOME development, for example for the Linux kernel now that they have a good API documentation infrastructure (it’s just a matter of generating *.devhelp2 index files alongside the HTML pages).