【Deepin Sharing】How to use GSettings

image.png

GSettings is actually a set of APIs that can use multiple storage backends. By default, dconf is used as backend, and keyfile can also be used as backend.

However, since gio provides the GKeyFile structure to process keyfile files, the GSettings API is rarely used when parsing keyfile files. Only the use of dconf as backend is introduced here.

Dconf dconf is a low-level configuration management system designed to be used as the backend of GSettings and provides a graphical configuration management tool dconf-editor with the following features:

1.Retrieval fast dconf uses gvdb (GVariant Database file) format binary file to store data, it is a simple database that stores keys in the way of path mapping, and retrieval is efficient. The default file path is: ~/.config/dconf/user

2.Support for change notification dconf supports notification when key changes

Configuration File

The configuration file of GSettings is in xml format, the file needs to end with .gschema.xml, and the file name is usually the same as the id. The configuration file is installed in the /usr/share/glib-2.0/schemas/ directory. The manually added files need to execute sudo glib-complie-schemas /usr/share/glib-2.0/schemas to make it take effect.

The brief format of the file content is as follows:

```<?xml version="1.0" encoding="UTF-8"?>

You can see that a file can contain multiple schemas, and each schema can be composed of multiple keys. Details are as follows:

1.The id in the id schema needs to be unique in the entire configuration system, otherwise the duplicate id will be ignored when glib-compile-schemas is executed; the beginning of the id usually uses the domain name related to the application

2.The path in the path schema must start with / and end with /, and cannot contain continuous / , path is used to specify the path to be stored in storage, which can be inconsistent with id

3.The name of the name key, which needs to be unique in this schema, the value of name consists of lowercase letters, numbers and -, and must start with lowercase letters, cannot end with -, and cannot appear consecutive -

4.The type of the type key needs to be a type supported by GVariant. In addition to using basic types, you can also combine types in the way of GVariant

5.the default value of the default key

6.A brief description of the summary key

7.A detailed description of the description key

An example is given below:

schema file:

```<?xml version="1.0" encoding="UTF-8"?>
<schemalist>
    <enum id="com.deepin.test.LogLevel">
        <value nick="debug" value="1" />
        <value nick="info" value="2" />
        <value nick="fatal" value="3" />
    </enum>

    <schema path="/com/deepin/test/" id="com.deepin.test">
        <key type="b"  name="enabled">
            <default>true</default>
            <summary>Enable this module.</summary>
            <description>Whether enable this module.</description>
        </key>
        <key enum="com.deepin.test.LogLevel" name="loglevel">
            <default>'info'</default>
            <summary>Log level.</summary>
            <description>Log level.</description>
        </key>
        <key type="i" name="interval">
            <default>10</default>
            <range min="0" max="60" />
            <summary>Timer duration.</summary>
            <description>Timer duration.</description>
        </key>
        <key type="(ii)" name="size">
            <default>(800,600)</default>
            <summary>The window size.</summary>
            <description>The window size.</description>
        </key>
    </schema>
</schemalist>

The program code is as follows:

 * Copyright (C) 2019 >
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * example.c -- An example for gsettings.
 *
 * compile:
 *    gcc -Wall -g example.c `pkg-config --libs --cflags gio-2.0`
 *
 */
#include <gio/gio.h>

int
main(int argc, char *argv[])
{
    GSettings *gs;
    gboolean enabled;
    gint loglevel, interval, width, height;

    // if failed, will segmetfault
    gs = g_settings_new("com.deepin.test");

    enabled = g_settings_get_boolean(gs, "enabled");
    g_print("Enabled: %d\n", enabled);

    loglevel = g_settings_get_enum(gs, "loglevel");
    g_print("Log level: %d\n", loglevel);

    interval = g_settings_get_int(gs, "interval");
    g_print("Timer duration: %d\n", interval);

    g_settings_get(gs, "size", "(ii)", &width, &height);
    g_print("Width: %d, height: %d\n", width, height);

    g_object_unref(gs);
    return 0;
}

Note: When using the interface call, you need to ensure that the schema and key exist, otherwise a segmentation fault will be triggered.

Relocatable Schema Usually an id corresponds to a fixed path , but it can also be absent, that is, no path is set, so it is a relocatable schema . This feature is useful for variable configurations, such as user-defined shortcut keys: the number of shortcut keys is unknown. In this case, you can use this feature to declare a shortcut key schema as a template, and then dynamically create multiple paths to use . An example is as follows:

The schema file is as follows:

```<?xml version="1.0" encoding="UTF-8"?>

''

Shortcut name. Shortcut name. [''] Shortcut keys. Shortcut keys. '' Shortcut action. Shortcut action. '' Shortcut description. Shortcut description.

The program code is as follows:


```/**
 * Copyright (C) 2019 >
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * relocatable.c -- An example for gsettings relocatable path.
 *
 * compile:
 *    gcc -Wall -g relocatable.c `pkg-config --libs --cflags gio-2.0`
 */

#include <stdio.h>
#include <gio/gio.h>

static void set_keybind(GSettings *gs);
static void get_keybind(GSettings *gs);

static void
set_keybind(GSettings *gs)
{
    gboolean ok;

    ok = g_settings_set_string(gs, "name", "test");
    if (!ok) {
        g_warning("Failed to set name to 'test'");
    }

    const gchar *shortcuts[] = {"Control-Alt-T", "Super-T", NULL};
    ok = g_settings_set_strv(gs, "shortcuts", shortcuts);
    if (!ok) {
        g_warning("Failed to set shortcuts");
    }
    ok = g_settings_set_string(gs, "action", "terminator");
    if (!ok) {
        g_warning("Failed to set action to 'terminator'");
    }
    ok = g_settings_set_string(gs, "description", "the shortcuts for terminator");
    if (!ok) {
        g_warning("Failed to set description to 'the shortcuts for terminator'");
    }
}

static void
get_keybind(GSettings *gs)
{
    gchar *name, *action, *desc;
    gchar **shortcuts = NULL;

    name = g_settings_get_string(gs, "name");
    if (name) {
        g_print("Shortcut name: %s\n", name);
        g_free(name);
    }

    shortcuts = g_settings_get_strv(gs, "shortcuts");
    if (shortcuts) {
        int i = 0;
        g_print("Shortcut key: ");
        for (; shortcuts[i]; i++) {
            if (i != 0) {
                g_print(", ");
            }
            g_print("%s", shortcuts[i]);
            g_free(shortcuts[i]);
        }
        g_print("\n");
        g_free(shortcuts);
    }

    action = g_settings_get_string(gs, "action");
    if (action) {
        g_print("Shortcut action: %s\n", action);
        g_free(action);
    }

    desc = g_settings_get_string(gs, "description");
    if (desc) {
        g_print("Shortcut desc: %s\n", desc);
        g_free(desc);
    }
}

int
main(int argc, char *argv[])
{
    if (argc != 3) {
        g_print("Usage: %s <action> <keybind id>\n"
                "\taction: get or set\n"
                "\tkeybind id: a non-negative integer\n", argv[0]);
        return 0;
    }

    GSettings *gs;
    gchar buf[1024] = {0};

    if (sprintf(buf, "/com/deepin/test/keybind/%s/", argv[2]) < 0) {
        g_error("Failed to combains path: %s\n", argv[2]);
        return -1;
    }
    gs = g_settings_new_with_path("com.deepin.test.keybind", buf);

    if (g_strcmp0(argv[1], "set") == 0) {
        set_keybind(gs);
    } else if (g_strcmp0(argv[1], "get") == 0) {
        get_keybind(gs);
    } else {
        g_warning("invalid action: %s", argv[1]);
    }

    g_object_unref(gs);
    g_settings_sync();
    return 0;
}

override gsettings supports an override mechanism, which can change the default value.

Usually the default value of the key has been specified in the file, but sometimes different versions require different default values. In this case, the override mechanism is very useful, and the default value can be changed without modifying the configuration file.

The override file starts with a number_ and ends with .gschema.override. The number is a two-digit integer. The higher the number, the higher the priority.

The override file is also installed in the /usr/share/glib-2.0/schemas directory and needs to be compiled with glib-compile-schemas.

The format of the override file is as follows:

[schema id] key=value If you change the default value of interval in com.deepin.test to 30 , the content is as follows:

[com.deepin.test] interval=30 Then execute:

sudo cp ./90_com.deepin.test.gschema.override /usr/share/glib-2.0/schemas/ sudo glib-compile-schemas /usr/share/glib-2.0/schemas key change signal

GSettings provides the changed signal to send key changed events, listen for this signal if needed.

Tool

glib-compile-schemas Command to compile schema file

dconf-editor Graphical tool for dconf, retrieved by path, manages keys

devhelp An API documentation viewing tool, after installing libglib2.0-docs, you can view the API documentation of GSettings in devhelp

gsettings This is a configuration management tool of gsettings. Some commonly used subcommands are described below. For detailed usage, please refer to the man manual:

1.list-schemas lists all installed schemas with a fixed path

2.list-relocatable-schemas list all installed schemas without a fixed path

3.list-keys lists all keys in the specified schema

4.list-recursively lists all keys and their values in the specified schema, if schema is not specified, lists all schemas

5.get Gets the value of the specified key in the specified schema

6.set sets the value of the specified key in the specified schema

7.reset resets the value of the specified key in the specified schema, that is, restores the default value

8.monitor listens for changes of the specified key in the specified schema, and listens for all changes when not specified