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.