乐趣区

GSettings-简介

GSettings 实际上是一套可使用多个 storage backendsAPI,默认使用 dconf 作为 backend,也可以使用 keyfile 作为 backend

但由于 gio 提供了 GKeyFile 结构来处理 keyfile 文件,所以解析 keyfile 文件时很少通过 GSettings API,在这里只介绍使用 dconf 作为 backend 的使用方法。


dconf

dconf 是一个底层的配置管理系统,被设计用来作为 GSettingsbackend,并提供了图形化的配置管理工具 dconf-editor,具有以下特点:

  • 检索快速

    dconf 使用 gvdb(GVariant Database file) 格式的二进制文件存储数据,它是一个简单的数据库,以路径映射的方式存储 key,检索高效。默认的文件路径为:~/.config/dconf/user

  • 支持改变通知

    dconf 支持在 key 发生改变时发出通知


配置文件

GSettings 的配置文件是 xml 格式的,文件需以 .gschema.xml 结尾,文件名通常与 id 相同。配置文件安装在 /usr/share/glib-2.0/schemas/ 目录下,手动添加进去的文件需要执行 sudo glib-complie-schemas /usr/share/glib-2.0/schemas 让其生效。

文件内容简要格式如下:

<?xml version="1.0" encoding="UTF-8"?>
<schemalist>
    <schema path=""id="">
        <key type=""name="">
            <default></default>
            <summary></summary>
            <description></description>
        </key>
    </schema>
</schemalist>

可以看到一个文件里可以包含多个 schema,每个 schema 可由多个 key 组成。详细说明如下:

  • id

    schema 中的 id 需要在整个配置系统中是唯一的,不然执行 glib-compile-schemas 时会忽略重复的 idid 的开头通常使用与应用相关的域名

  • path

    schema 中的 path 必须是以 / 开头并且以 / 结尾,不能包含连续的 / , path 用于指定在 storage 中存储路径,可以与 id 不一致

  • name

    key 的名称,需要在此 schema 中是唯一的,name 的值由小写字母、数字和 - 组成,并且开头必须是小写字母,不能以 - 结尾,也不能出现连续的 -

  • type

    key 的类型,需要是 GVariant 支持的类型,除了可以使用基本的类型外,也可按照 GVariant 的方式组合类型

  • default

    key 的默认值

  • summary

    key 的简单描述

  • description

    key 的详细描述


下面给出一个例子:

schema 文件:

<?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>

程序代码如下:

/**
 * Copyright (C) 2019 jouyouyun <jouyouwen717@gmail.com>
 *
 * 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;
}

注意: 在使用接口调用时,需要确保 schemakey 存在,不然会触发 段错误


Relocatable Schema

通常一个 id 对应一个固定的 path,但也可以没有,即不设置 path,这样就是一个可重定位的 schema。这个特性对于可变的配置很有用,如用户自定义的快捷键:快捷键的个数是不可知,这时可利用这个特性先声明一个快捷键 schema 作为模板,然后动态创建多个 path 来使用。示例如下:

schema 文件如下:

<?xml version="1.0" encoding="UTF-8"?>
<schemalist>
    <schema id="com.deepin.test.keybind">
        <key type="s"  name="name">
            <default>''</default>
            <summary>Shortcut name.</summary>
            <description>Shortcut name.</description>
        </key>
        <key type="as"  name="shortcuts">
            <default>['']</default>
            <summary>Shortcut keys.</summary>
            <description>Shortcut keys.</description>
        </key>
        <key type="s"  name="action">
            <default>''</default>
            <summary>Shortcut action.</summary>
            <description>Shortcut action.</description>
        </key>
        <key type="s"  name="description">
            <default>''</default>
            <summary>Shortcut description.</summary>
            <description>Shortcut description.</description>
        </key>
    </schema>
</schemalist>

程序代码如下:

/**
 * Copyright (C) 2019 jouyouyun <jouyouwen717@gmail.com>
 *
 * 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 支持 override 机制,可以更改默认值。

通常 key 的默认值在文件中已经指定,但有时不同的版本上需要的默认值不同,这时 override 机制就很有用,可以在不修改配置文件的情况下更改默认值。

override 文件以 数字_ 开头,并以 .gschema.override 结尾,数字为两位整数,数值越大优先级越高。

override 文件同样安装在 /usr/share/glib-2.0/schemas 目录下,并需要使用 glib-compile-schemas 编译。

override 文件的格式如下:

[schema id]
key=value

如更改 com.deepin.testinterval 的默认值为 30,则内容如下:

[com.deepin.test]
interval=30

然后执行:

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 改变信号

GSettings 提供了 changed 信号来发送 key 改变的事件,如有需要可监听此信号。


工具

glib-sompile-schemas {#glib-sompile-schemas}

编译 schema 文件的命令

dconf-editor {#dconf-editor}

dconf 的图形工具,根据 path 检索,可管理 key

devhelp

一款 API 文档查看工具,安装了 libglib2.0-docs 后,可在 devhelp 中查看 GSettingsAPI 文档

gsettings

这是一个 gsettings 的配置管理工具,下面介绍一些常用的子命令,详细用法请查看 man 手册:

  • list-schemas

    列出所有已安装并有固定 pathschema

  • list-relocatable-schemas

    列出所有已安装却没有固定 pathschema

  • list-keys

    列出指定 schema 中的所有 key

  • list-recursively

    列出指定 schema 中的所有 key 及其 value,若 schema 未指定,则列出所有 schema

  • get

    获取指定 schema 中指定 key 的值

  • set

    设置指定 schema 中指定 key 的值

  • reset

    重置指定 schema 中指定 key 的值,即恢复默认值

  • monitor

    监听指定 schema 中指定 key 的改变,不指定时监听所有的


参考资料

  • dconf
  • GSettings
  • GSettings API
  • GVariant Format Strings
退出移动版