现在的位置: 首页 > 综合 > 正文

GSettings 稍长一点的简介和用法

2018年07月08日 ⁄ 综合 ⁄ 共 4616字 ⁄ 字号 评论关闭

GSettings 稍长一点的简介和用法

NOV 28TH, 2011 | COMMENTS

从wpblog中备份。

GSettings 是什么?

简单地说,GSettings 就是 GLib/GNOME 中类似 Windows 注册表的东西,虽然注册表并不好,但是 GSettings 与注册表有一点不一样,就是注册表可以任意修改,你一句话就能增加一个注册表项,一行字就能删掉一个根,而且其内容也是可任意改的,这个你能当二进制输入,一句话又变成整数了,看上去很方便,实际上对搜索效率有致命伤害,而且为什么书店中有那么多“Windows 实用技巧”的书?为什么还有 Windows 优化大师这样的软件?就是因为它是可变的!而 Windows 默认又该死地没有写出来!

GSettings 就不一样了,它是固定的,也就是说,它与你的代码没有必然联系,你可以建立一堆表项,但不用,但不管怎么说,你都没法直接用代码生成项。

其实 GSettings 有 Windows 注册表的后端,所以你用它,可移植性仍然可以保证!

GSettings 在哪里?

囧,不就在你电脑里吗?从 GLib 2.26 起,GLib 的家族成员——GIO 就已经附带起 GSettings 了,完全不用手动安装了,而且,GNOME 3 的所有家族成员已经全部转投 GSettings 了(所以只要你有 GNOME 3,就不用考虑这些事情),据说 GConf2 的速度很慢,而且也难用,所以他们又鼓捣了一个 dconf,这个玩意就是 GSettings 的核心了。

话虽这么说,但我却从未在 GSettings 的源代码里发现和 dconf 有关的任何东西……

dconf 是一个低级的、快速的配置系统,我看了一些 API,那玩意根本不是给人用的,不过这也没什么关系,GSettings 已经帮我们打理好了。

怎么生成“项”啊?

GSettings 项目是由一个叫 schema 的文件所声明的(下文意译为“规范”),这是一个灰常正规的 XML 文件。请看下面的这个示例:

1
2
3
4
5
6
7
8
9
10
<?xml version="1.0" encoding="UTF-8"?>
<schemalist>
  <schema path="/apps/telepathy-logger/" id="org.freedesktop.Telepathy.Logger">
    <key type="b" name="enabled">
      <default>true</default>
      <summary>Enable logging</summary>
      <description>Globally enable or disable the Telepathy logger system. Setting it to "false" will completely disable all logging.</description>
    </key>
  </schema>
</schemalist>

这是我找到的真实的 Telepathy-Logger 的 GSettings 规范,这太易懂了,我没必要做过多解说了。需要注意的是,如果你想让你的 GSettings 配置能让 dconf-editor所读取,那么你必须指定 path属性。

还有两点要注意啊:(1)path 必须是两头都有 /,不然它会恶狠狠地告诉你:校验失败!(2)这个文件的扩展名必须是 gschema.xml,否则下面的内容就是废话。

好吧,其实我上面有意忽略了一个事实,虽然规范文件是 XML 所写,但是,GSettings 只认二进制的文件!这个二进制的文件是通过一个叫做
glib-compile-schemas 的编译器生成的。你可以尝试如下语句刷新系统 GSettings 规范文件:

1
glib-compile-schemas /usr/share/glib-2.0/schemas

这个命令并不完全正确,参见 glib-compile-schemas 的手册页,GSettings 会读取 XDG_DATA_DIRS 下的 glib-2.0/schemas。一般情况下,我们使用的是 /usr/share/glib-2.0/schemas 和 /usr/local/share/glib-2.0/schemas。

简单地说,你首先应该写一个 XML 规范文件,将它复制入 GSettings 会读取的一个文件夹,然后用 glib-compile-schemas 将它安装即可。

不安装的后果只有一个:abort。

如何操作我的 GSettings 项目?

准确说……你可以任意修改 GSettings,不管它是否是你的。通过看 GSettings 的 API 文档,我们可以及其容易地了解到,一个 GSettings 就是一个 GObject 对象,所以是非常易用的!

创建一个新 GSettings 对象

通过使用 GObject 和 GTK+ 的经验,我们首先锁定以下 API:

1
2
3
4
5
6
7
8
9
GSettings *              g_settings_new                 (const gchar *schema);
GSettings *              g_settings_new_with_path       (const gchar *schema,
                                                         const gchar *path);
GSettings *              g_settings_new_with_backend    (const gchar *schema,
                                                         GSettingsBackend *backend);
GSettings *              g_settings_new_with_backend_and_path
                                                        (const gchar *schema,
                                                         GSettingsBackend *backend,
                                                         const gchar *path);

我们随时都应该只用前两个当中的一个,因为你不应该随意更换 GSettings 的后端,除非你知道这样做的后果。schema 这个参数有误导之嫌,因为它实际上是你在规范文件中指定的 id,除非你用了 with_path。

当然,这并不成问题,因为更换一个后端相当容易。为什么这样说?请看一下 GSettingsBackend 的 API 吧:

1
2
3
4
5
GSettingsBackend *       g_keyfile_settings_backend_new (const gchar *filename,
                                                         const gchar *root_path,
                                                         const gchar *root_group);
GSettingsBackend *       g_memory_settings_backend_new  (void);
GSettingsBackend *       g_null_settings_backend_new    (void);

也就是说,你几乎可以不费吹灰之力就能更换一种存储方式。不过似乎仍然需要安装一个规范。这三个函数都违背了
GObject 的命名方式,不值得提倡。
其实是相应的类名字不同,所以造成了这三个奇怪的命名。 PS:准确地说,这三种之中只有当你用键值文件作为后端时才有可能保存下来。当然,这在 Windows 下同样有作用!

……修改它!

是不是有点太快了?我们还除了建立一个 GSettings 对象什么都没做呢!嗯,是啊,这就是它的易用!

我翻阅了一下 GConf2 (GNOME 2 中的配置系统)的 API 文档,发现居然还有 GConfEngine、GConfClient 这样的东西,甚至还有 GConfValue 这样的类型(万能的容器类型,但是 GLib 中已经有类似的而且更好的东西了),其复杂程度可见一斑!

GSettings 的操作也是非常简单的,如 g_settings_get_int、g_settings_set_int,这样容易的操作,甚至通过更换后端来操作键值文件,都比直接用 GKeyFile 更加简单!如此地简单,甚至我不用多费口舌来讲解它。

如果一个你指定的键并不存在,程序会抛出(raise)一个 SIGABRT,你懂的。

GObject?

GObject,我就不多说了,但是,GSettings 有一个非常好的特性——将一个 GObject 对象与某个值绑定!这样一来我们就可以不用很麻烦地来创建对象、打开、读入、覆盖默认值、析构的时候再保存……虽然这在库中没有多大作用,但是在一个应用程序中作用就很大,如 Windows 上的某个程序(我真的忘了),会自动恢复到上次关闭时的大小、位置,这个特性对记忆用户习惯非常有用。

需要关注的是以下 API:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
void                g_settings_bind                     (GSettings *settings,
                                                         const gchar *key,
                                                         gpointer object,
                                                         const gchar *property,
                                                         GSettingsBindFlags flags);
void                g_settings_bind_with_mapping        (GSettings *settings,
                                                         const gchar *key,
                                                         gpointer object,
                                                         const gchar *property,
                                                         GSettingsBindFlags flags,
                                                         GSettingsBindGetMapping get_mapping,
                                                         GSettingsBindSetMapping set_mapping,
                                                         gpointer user_data,
                                                         GDestroyNotify destroy);
void                g_settings_bind_writable            (GSettings *settings,
                                                         const gchar *key,
                                                         gpointer object,
                                                         const gchar *property,
                                                         gboolean inverted);
void                g_settings_unbind                   (gpointer object,
                                                         const gchar *property);

bind 函数会将某个 GObject 对象属性与一个 GSettings 键绑定,unbind 是解绑定用的。

文档说,当某个 GObject 对象销毁后,unbind 会自动触发,所以不需要显式调用。

我们可以猜测,绑定后,如果写入一个值,GObject 对象会被更新,如果设置了 GObject 对象的属性,GSettings 也会更新。如果你需要自己的处理,那么可以试试第二个
API。

完成!

好了,我们的一切已经完成,那么如何保存下来呢?

吐槽一下 GKeyFile,要保存还得 to_data,然后手动打开文件,再保存。或许我还没有找到真正的方法。

知道 fflush 这个函数吗?我想你们都知道,其实它还有一个远方表兄叫做 fsync(),fsync() 的父亲是 sync()。sync()可牛了,能指示所有人都刷新,还同步了超级块。

GSettings 的老大当然也有这般本领,名字就叫 g_settings_sync,它也可牛了,能指示所有 GSettings 都同步到数据库里面去。你一声令下,多一句话都不用,直接就全部完成了。

好了,我们已经过河拆桥、卸磨杀驴地把 GSettings 利用完了,要灭掉它了,怎么办?凉拌炒鸡蛋!GObject对象一般都是怎样弄掉的?回忆一下
GObject 的内存管理,如果引用计数……对,就是引用计数!想起来了吧?直接 g_object_unref 掉就好了!

如果你发现某个 GObject 不听话没有给 _free 或 _close 类似的函数,简单了,直接 g_object_unref(),没出问题的话它就在劫难逃了。

 Nov 28th, 2011  Programminggioglibgsettings

抱歉!评论已关闭.