First steps with GSettings

We sometimes get questions about GSettings in #gtk+, and whether it is a good idea to use this API for ‘simple’ cases. The answer is a very clear Yes, in my opinion, and this article is trying to explain why.

Benefits

One of the nice things about GSettings is that it is a high-level API with backends for various native configuration systems. So, if you ever get around to porting your application to OS X or Windows, your application will automatically use the expected platform API to store its settings (the registry on Windows, and plists on OS X).

And even if your application will never be ported to those platforms, the dconf backend that is used on Linux has powerful features such as profiles and locks that let system administrators configure your application without you having to worry about it.

The documentation for GSettings unfortunately makes it appear more complicated than it is, since it doesn’t really try to hide the powerful features that are available to you (profiles, vendor overrides, translated defaults, complex types, bindings, etc).

So, here is a guide to first steps with GSettings, in a simple case.

Getting started

Lets get started with the simplest possible setting: a boolean.

The biggest hurdle to overcome is that GSettings insists on having a schema, which defines the datatype and default value for each key.

<schemalist>
  <schema path="/org/gnome/recipes/"       
         id="org.gnome.Recipes">
    <key type="b" name="use-metric">
      <default>true</default>
      <summary>Prefer metric units</summary>
      <description>
        This key determines whether values
        such as temperatures or weights will
        be displayed in metric units.
      </description>
    </key>
  </schema>
</schemalist>

Schemas need to be installed (the advantage of this is that tools such as dconf-editor can use the schema information). If you are using autotools, this is supported with macros. Just add

GLIB_GSETTINGS

to your configure.ac, and

gsettings_SCHEMAS = org.gnome.Recipes.gschema.xml
@GSETTINGS_RULES@

to Makefile.am. The setup with meson is similar.

Now that we’ve defined our key, we can obtain its value like this:

s = g_settings_new ("org.gnome.Recipes");
if (g_settings_get_boolean (s, "use-metric"))
  g_print ("Using metric units");

and we can set it like this:

s = g_settings_new ("org.gnome.Recipes");g_settings_set_boolean (s, "use-metric", TRUE);

Using GSettings for other basic types such as integers, floating point numbers, strings, etc. is very similar. Just use the appropriate getters and setters.

You may be wondering about the settings objects that we are creating here. It is fine to just create these whenever you need them. You can also create a global singleton if you prefer, but there is not real need to do so unless you want to monitor the setting for changes.

Next Steps: complex types

Beyond basic types, you have the full power of the GVariant type system available to store complex types. For example, if you need to store information about a circle in the plane, you could store it as a triple of type (ddd) storing the x, y coordinates of the center and the radius.

To handle settings with complex types in your code, use g_settings_get() and g_settings_set(), which return and accept the value in the form of a GVariant.

Next Steps: relocatable schemas

If your application uses accounts, you may want to look at relocatable schemas. A relocatable schema is what you need when you need multiple instances of the same configuration, stored separately. A typical example for this is accounts: your application allows to create more than one, and each of them has the same kind of configuration information associated with it.

GSettings handles this by omitting the path in the schema:

<schemalist>
  <schema id="org.gnome.Recipes.User">
    <key type="b" name="use-metric">
      <default>true</default>
    </key>
  </schema>
</schemalist>

Instead, we need to specify a path when we create the GSettings object:

s = g_settings_new_with_path ("org.gnome.Recipes.User",
                              "/org/gnome/Recipes/Account/mclasen");
if (g_settings_get_boolean (s, "use-metric"))
  g_print ("User mclasen is using metric units");

It is up to you to come up with a schema to map your accounts to unique paths.

Stumbling blocks

There are a few things to be aware of when using GSettings. One is that GLib needs to be able to find the compiled schema at runtime. This can be an issue when running your application out of the build directory without installing it. To handle this situation, you can set the GSETTINGS_SCHEMA_DIR environment variable to tell GLib where to find the compiled schema:

GSETTINGS_SCHEMA_DIR=build/data ./build/src/gnome-recipes

Another stumbling block is that GSettings reads the default values in the XML in the form of a serialized GVariant. This can be a bit surprising for the common case of a string, since it means that we need to put quotes around the string:

<default>'celsius'</default>

But these are minor issues, and easily avoided once you know about them.

2 thoughts on “First steps with GSettings”

  1. Are compiled schema files architecture-independent? Is the binary format stable across versions?

    I ask because I’m working on a Python app that uses GSettings, and I’m trying to figure out packaging (e.g. can I make pip install gtimelog work?).

  2. The format is the same that is used to store dconf databases: gvdb. So yes, it is stable. It is architecture-independent in the sense that we can read it, regardless on which architecture it was written. But it is written in native endianness.

Leave a Reply

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