[gtk/docs-gtk-org] gio: Add the GConf migration guide



commit 86a147c060cfaf44edf039e1ee45132fc2d99d74
Author: Emmanuele Bassi <ebassi gnome org>
Date:   Thu Nov 25 12:36:36 2021 +0000

    gio: Add the GConf migration guide

 glib/gio/gio.toml.in        |   1 +
 glib/gio/meson.build        |   1 +
 glib/gio/migrating-gconf.md | 462 ++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 464 insertions(+)
---
diff --git a/glib/gio/gio.toml.in b/glib/gio/gio.toml.in
index 665e277e44..e68046c75e 100644
--- a/glib/gio/gio.toml.in
+++ b/glib/gio/gio.toml.in
@@ -36,6 +36,7 @@ show_class_hierarchy = true
 urlmap_file = "urlmap.js"
 # The same order will be used when generating the index
 content_files = [
+  "migrating-gconf.md",
   "migrating-gnome-vfs.md",
 ]
 content_images = [
diff --git a/glib/gio/meson.build b/glib/gio/meson.build
index 2985d14da1..ce955b446b 100644
--- a/glib/gio/meson.build
+++ b/glib/gio/meson.build
@@ -1,4 +1,5 @@
 expand_content_files = [
+  'migrating-gconf.md',
   'migrating-gnome-vfs.md',
 ]
 
diff --git a/glib/gio/migrating-gconf.md b/glib/gio/migrating-gconf.md
new file mode 100644
index 0000000000..e6f9505979
--- /dev/null
+++ b/glib/gio/migrating-gconf.md
@@ -0,0 +1,462 @@
+Title: Migrating from GConf to GSettings
+
+# Migrating from GConf to GSettings
+
+## Before you start
+
+Converting individual applications and their settings from GConf to
+GSettings can be done at will. But desktop-wide settings like font or theme
+settings often have consumers in multiple modules. Therefore, some
+consideration has to go into making sure that all users of a setting are
+converted to GSettings at the same time or that the program responsible for
+configuring that setting continues to update the value in both places.
+
+It is always a good idea to have a look at how others have handled similar
+problems before.
+
+## Conceptual differences
+
+Conceptually, GConf and GSettings are fairly similar. Both have a concept of
+pluggable backends. Both keep information about keys and their types in
+schemas. Both have a concept of mandatory values, which lets you implement
+lock-down.
+
+There are some differences in the approach to schemas. GConf installs the
+schemas into the database and has API to handle schema information
+(`gconf_client_get_default_from_schema()`, `gconf_value_get_schema()`, etc).
+GSettings on the other hand assumes that an application knows its own
+schemas, and does not provide API to handle schema information at runtime.
+GSettings is also more strict about requiring a schema whenever you want to
+read or write a key. To deal with more free-form information that would
+appear in schema-less entries in GConf, GSettings allows for schemas to be
+'relocatable'.
+
+One difference in the way applications interact with their settings is that
+with GConf you interact with a tree of settings (ie the keys you pass to
+functions when reading or writing values are actually paths with the actual
+name of the key as the last element. With GSettings, you create a GSettings
+object which has an implicit prefix that determines where the settings get
+stored in the global tree of settings, but the keys you pass when reading or
+writing values are just the key names, not the full path.
+
+## GConfClient (and GConfBridge) API conversion
+
+Most people use GConf via the high-level `GConfClient` API. The
+corresponding API is the [class@Gio.Settings object]. While not every
+`GConfClient` function has a direct GSettings equivalent, many do:
+
+| GConfClient | GSettings |
+|-------------|-----------|
+| `gconf_client_get_default()` | no direct equivalent, instead you call [`ctor Gio Settings new`] for the 
schemas you use |
+| `gconf_client_set()` | [`method Gio Settings set`] |
+| `gconf_client_get()` | `g_settings_get()` |
+| `gconf_client_get_bool()` | `g_settings_get_boolean()` |
+| `gconf_client_set_bool()` | `g_settings_set_boolean()` |
+| `gconf_client_get_int()` | `g_settings_get_int()` |
+| `gconf_client_set_int()` | `g_settings_set_int()` |
+| `gconf_client_get_float()` | `g_settings_get_double()` |
+| `gconf_client_set_float()` | `g_settings_set_double()` |
+| `gconf_client_get_string()` | `g_settings_get_string()` |
+| `gconf_client_set_string()` | `g_settings_set_string()` |
+| `gconf_client_get_list()` | for string lists, see `g_settings_get_strv()`, else see 
`g_settings_get_value()` and GVariant API |
+| `gconf_client_set_list()` | for string lists, see `g_settings_set_strv()`, else see 
`g_settings_set_value()` and GVariant API |
+| `gconf_entry_get_is_writable()` | `g_settings_is_writable()` |
+| `gconf_client_notify_add()` | not required, the “changed” signal is emitted automatically |
+| `gconf_client_add_dir()` | not required, each GSettings instance automatically watches all keys in its 
path |
+| `GConfChangeSet` | `g_settings_delay()`, `g_settings_apply()` |
+| `gconf_client_get_default_from_schema()` | no equivalent, applications are expected to know their schema |
+| `gconf_client_all_entries()` | no equivalent, applications are expected to know their schema, and 
GSettings does not allow schema-less entries |
+| `gconf_client_get_without_default()` | no equivalent |
+| `gconf_bridge_bind_property()` | `g_settings_bind()` |
+| `gconf_bridge_bind_property_full()` | `g_settings_bind_with_mapping()` |
+
+GConfBridge was a third-party library that used GConf to bind an object
+property to a particular configuration key. GSettings offers this service
+itself.
+
+There is a pattern that is sometimes used for GConf, where a setting can
+have explicit 'value A', explicit 'value B' or 'use the system default'.
+With GConf, 'use the system default' is sometimes implemented by unsetting
+the user value. This is not possible in GSettings, since it does not have
+API to determine if a value is the default and does not let you unset
+values. The recommended way (and much clearer) way in which this can be
+implemented in GSettings is to have a separate 'use-system-default' boolean
+setting.
+
+## Change notification
+
+GConf requires you to call `gconf_client_add_dir()` and
+`gconf_client_notify_add()` to get change notification. With GSettings, this
+is not necessary; signals get emitted automatically for every change.
+
+The [signal@Gio.Settings::changed] signal is emitted for each changed key.
+There is also a [`signal@Gio.Settings::change-event`] signal that you can
+handle if you need to see groups of keys that get changed at the same time.
+
+GSettings also notifies you about changes in writability of keys, with the
+[signal@Gio.Settings::writable-changed] signal (and the
+[signal@Gio.Settings::writable-change-event] signal).
+
+## Change sets
+
+GConf has a concept of a set of changes which can be applied or reverted at
+once: `GConfChangeSet` (GConf doesn't actually apply changes atomically,
+which is one of its shortcomings).
+
+Instead of a separate object to represent a change set, GSettings has a
+'delayed-apply' mode, which can be turned on for a [class@Gio.Settings]
+object by calling [method@Gio.Settings.delay]. In this mode, changes done to
+the GSettings object are not applied - they are still visible when calling
+[method Gio Settings get] on the same object, but not to other GSettings
+instances or even other processes.
+
+To apply the pending changes all at once (GSettings does atomicity here),
+call [method@Gio.Settings.apply]. To revert the pending changes, call
+[method@Gio.Settings.revert] or just drop the reference to the GSettings
+object.
+
+## Schema conversion
+
+If you are porting your application from GConf, most likely you already have
+a GConf schema. GConf comes with a commandline tool
+`gsettings-schema-convert` that can help with the task of converting a GConf
+schema into an equivalent GSettings schema. The tool is not perfect and may
+need assistance in some cases.
+
+### An example for using gsettings-schema-convert
+
+Running `gsettings-schema-convert --gconf --xml --schema-id
+"org.gnome.font-rendering" --output org.gnome.font-rendering.gschema.xml
+destop_gnome_font_rendering.schemas` on the following
+`desktop_gnome_font_rendering.schemas` file:
+
+```xml
+<?xml version="1.0"?>
+<gconfschemafile>
+    <schemalist>
+        <schema>
+            <key>/schemas/desktop/gnome/font_rendering/dpi</key>
+            <applyto>/desktop/gnome/font_rendering/dpi</applyto>
+            <owner>gnome</owner>
+            <type>int</type>
+            <default>96</default>
+            <locale name="C">
+                <short>DPI</short>
+                <long>The resolution used for converting font sizes to pixel sizes, in dots per inch.</long>
+            </locale>
+        </schema>
+    </schemalist>
+</gconfschemafile>
+```
+
+produces an `org.gnome.font-rendering.gschema.xml` file with the following content:
+
+```xml
+<schemalist>
+  <schema id="org.gnome.font-rendering" path="/desktop/gnome/font_rendering/">
+    <key name="dpi" type="i">
+      <default>96</default>
+      <summary>DPI</summary>
+      <description>The resolution used for converting font sizes to pixel sizes, in dots per 
inch.</description>
+    </key>
+  </schema>
+</schemalist>
+```
+
+GSettings schemas are identified at runtime by their id (as specified in the
+XML source file). It is recommended to use a dotted name as schema id,
+similar in style to a D-Bus bus name, e.g. "org.gnome.SessionManager". In
+cases where the settings are general and not specific to one application,
+the id should not use StudlyCaps, e.g. "org.gnome.font-rendering". The
+filename used for the XML schema source is immaterial, but schema compiler
+expects the files to have the extension `.gschema.xml`. It is recommended to
+simply use the schema id as the filename, followed by this extension, e.g.
+`org.gnome.SessionManager.gschema.xml`.
+
+The XML source file for your GSettings schema needs to get installed into
+`$datadir/glib-2.0/schemas`, and needs to be compiled into a binary form. At
+runtime, GSettings looks for compiled schemas in the `glib-2.0/schemas`
+subdirectories of all `XDG_DATA_DIRS` directories, so if you install your
+schema in a different location, you need to set the `XDG_DATA_DIRS`
+environment variable appropriately.
+
+Schemas are compiled into binary form by the `glib-compile-schemas` utility.
+GIO provides a `glib_compile_schemas` variable in its pkg-config file
+pointing to the schema compiler binary.
+
+### Using schemas with Meson
+
+You should use `install_data()` to install the `.gschema.xml` file in the
+correct directory, e.g.
+
+```
+install_data('my.app.gschema.xml', install_dir: get_option('datadir') / 'glib-2.0/schemas')
+```
+
+Schema compilation is done at installation time; if you are using Meson 0.57 or newer, you can use the 
`gnome.post_install()` function from the GNOME module:
+
+```
+gnome.post_install(glib_compile_schemas: true)
+```
+
+Alternatively, you can use `meson.add_install_script()` and the following
+Python script:
+
+```py
+#!/usr/bin/env python3
+# build-aux/compile-schemas.py
+
+import os
+import subprocess
+
+install_prefix = os.environ['MESON_INSTALL_PREFIX']
+schemadir = os.path.join(install_prefix, 'share', 'glib-2.0', 'schemas')
+
+if not os.environ.get('DESTDIR'):
+    print('Compiling gsettings schemas...')
+    subprocess.call(['glib-compile-schemas', schemadir])
+```
+
+```
+meson.add_install_script('build-aux/compile-schemas.py')
+```
+
+### Using schemas with Autotools
+
+GLib provides m4 macros for hiding the various complexities and reduce the
+chances of getting things wrong.
+
+To handle schemas in your Autotools build, start by adding this to your
+`configure.ac`:
+
+```
+GLIB_GSETTINGS
+```
+
+Then add this fragment to your `Makefile.am`:
+
+```
+# gsettings_SCHEMAS is a list of all the schemas you want to install
+gsettings_SCHEMAS = my.app.gschema.xml
+
+# include the appropriate makefile rules for schema handling
+@GSETTINGS_RULES@
+```
+
+This is not sufficient on its own. You need to mention what the source of
+the `my.app.gschema.xml` file is. If the schema file is distributed directly
+with your project's tarball then a mention in `EXTRA_DIST` is appropriate. If
+the schema file is generated from another source then you will need the
+appropriate rule for that, plus probably an item in `EXTRA_DIST` for the
+source files used by that rule.
+
+One possible pitfall in doing schema conversion is that the default values
+in GSettings schemas are parsed by the GVariant parser. This means that
+strings need to include quotes in the XML. Also note that the types are now
+specified as GVariant type strings.
+
+```xml
+<type>string</type>
+<default>rgb</default>
+```
+
+becomes
+
+```xml
+<key name="rgba-order" type="s">
+  <default>'rgb'</default> <!-- note quotes -->
+</key>
+```
+
+Another possible complication is that GConf specifies full paths for each
+key, while a GSettings schema has a 'path' attribute that contains the
+prefix for all the keys in the schema, and individual keys just have a
+simple name. So
+
+```xml
+<key>/schemas/desktop/gnome/font_rendering/antialiasing</key>
+```
+
+becomes
+
+```xml
+<schema id="org.gnome.font" path="/desktop/gnome/font_rendering/">
+  <key name="antialiasing" type="s">
+```
+
+
+Default values can be localized in both GConf and GSettings schemas, but
+GSettings uses gettext for the localization. You can specify the gettext
+domain to use in the gettext-domain attribute. Therefore, when converting
+localized defaults in GConf,
+
+```xml
+<key>/schemas/apps/my_app/font_size</key>
+  <locale name="C">
+    <default>18</default>
+  </locale>
+  <locale name="be">
+    <default>24</default>
+  </locale>
+</key>
+```
+
+becomes
+
+```xml
+<schema id="..." gettext-domain="your-domain">
+ ...
+<key name="font-size" type="i">
+  <default l10n="messages" context="font_size">18</default>
+</key>
+```
+
+GSettings uses gettext for translation of default values. The string that is
+translated is exactly the string that appears inside of the `<default>`
+element. This includes the quotation marks that appear around strings.
+Default values must be marked with the l10n attribute in the `<default>` tag,
+which should be set as equal to 'messages' or 'time' depending on the
+desired category. An optional translation context can also be specified with
+the context attribute, as in the example. This is usually recommended, since
+the string "18" is not particularly easy to translate without context. The
+translated version of the default value should be stored in the specified
+gettext-domain. Care must be taken during translation to ensure that all
+translated values remain syntactically valid; mistakes here will cause
+runtime errors.
+
+GSettings schemas have optional `<summary>` and `<description>` elements for
+each key which correspond to the `<short>` and `<long>` elements in the
+GConf schema and can be used in the same way by a GUI editor, so you should
+use the same conventions for them: The summary is just a short label with no
+punctuation, the description can be one or more complete sentences. If
+multiple paragraphs are desired for the description, the paragraphs should
+be separated by a completely empty line.
+
+Translations for these strings will also be handled via gettext, so you
+should arrange for these strings to be extracted into your gettext catalog.
+Gettext supports GSettings schemas natively since version 0.19, so all you
+have to do is add the XML schema file to the list of translatable files
+inside your `POTFILES.in`.
+
+GSettings is a bit more restrictive about key names than GConf. Key names in
+GSettings can be at most 32 characters long, and must only consist of
+lowercase characters, numbers and dashes, with no consecutive dashes. The
+first character must not be a number or dash, and the last character cannot
+be '-'.
+
+If you are using the GConf backend for GSettings during the transition, you
+may want to keep your key names the same they were in GConf, so that
+existing settings in the users GConf database are preserved. You can achieve
+this by using the `--allow-any-name` with the `glib-compile-schemas` schema
+compiler. Note that this option is only meant to ease the process of porting
+your application, allowing parts of your application to continue to access
+GConf and parts to use GSettings. By the time you have finished porting your
+application you must ensure that all key names are valid.
+
+## Data conversion
+
+GConf comes with a GSettings backend that can be used to facility the
+transition to the GSettings API until you are ready to make the jump to a
+different backend (most likely dconf). To use it, you need to set the
+`GSETTINGS_BACKEND` to 'gconf', e.g. by using
+
+```c
+g_setenv ("GSETTINGS_BACKEND", "gconf", TRUE);
+```
+
+early on in your program. Note that this backend is meant purely as a
+transition tool, and should not be used in production.
+
+GConf also comes with a utility called `gsettings-data-convert`, which is
+designed to help with the task of migrating user settings from GConf into
+another GSettings backend. It can be run manually, but it is designed to be
+executed automatically, every time a user logs in. It keeps track of the
+data migrations that it has already done, and it is harmless to run it more
+than once.
+
+To make use of this utility, you must install a keyfile in the directory
+`/usr/share/GConf/gsettings` which lists the GSettings keys and GConf paths
+to map to each other, for each schema that you want to migrate user data
+for.
+
+Here is an example:
+
+```
+[org.gnome.fonts]
+antialiasing = /desktop/gnome/font_rendering/antialiasing
+dpi = /desktop/gnome/font_rendering/dpi
+hinting = /desktop/gnome/font_rendering/hinting
+rgba-order = /desktop/gnome/font_rendering/rgba_order
+
+[apps.myapp:/path/to/myapps/]
+some-odd-key1 = /apps/myapp/some_ODD-key1
+```
+
+The last key demonstrates that it may be necessary to modify the key name to
+comply with stricter GSettings key name rules. Of course, that means your
+application must use the new key names when looking up settings in
+GSettings.
+
+The last group in the example also shows how to handle the case of
+'relocatable' schemas, which don't have a fixed path. You can specify the
+path to use in the group name, separated by a colon.
+
+There are some limitations: `gsettings-data-convert` does not do any
+transformation of the values. And it does not handle complex GConf types
+other than lists of strings or integers.
+
+**Don't forget to require GConf 2.31.1 or newer in your configure script if
+you are making use of the GConf backend or the conversion utility.**
+
+If, as an application developer, you are interested in manually ensuring
+that `gsettings-data-convert` has been invoked (for example, to deal with the
+case where the user is logged in during a distribution upgrade or for
+non-XDG desktop environments which do not run the command as an autostart)
+you may invoke it manually during your program initialisation. This is not
+recommended for all application authors -- it is your choice if this use
+case concerns you enough.
+
+Internally, `gsettings-data-convert` uses a keyfile to track which settings
+have been migrated. The following code fragment will check that keyfile to
+see if your data conversion script has been run yet and, if not, will
+attempt to invoke the tool to run it. You should adapt it to your
+application as you see fit.
+
+```c
+static void
+ensure_migrated (const gchar *name)
+{
+  gboolean needed = TRUE;
+  GKeyFile *kf;
+  gchar **list;
+  gsize i, n;
+
+  kf = g_key_file_new ();
+
+  g_key_file_load_from_data_dirs (kf, "gsettings-data-convert",
+                                  NULL, G_KEY_FILE_NONE, NULL);
+  list = g_key_file_get_string_list (kf, "State", "converted", &n, NULL);
+
+  if (list)
+    {
+      for (i = 0; i < n; i++)
+        if (strcmp (list[i], name) == 0)
+          {
+            needed = FALSE;
+            break;
+          }
+
+      g_strfreev (list);
+    }
+
+  g_key_file_free (kf);
+
+  if (needed)
+    g_spawn_command_line_sync ("gsettings-data-convert",
+                               NULL, NULL, NULL, NULL);
+}
+```
+
+Although there is the possibility that the `gsettings-data-convert` script
+will end up running multiple times concurrently with this approach, it is
+believed that this is safe.


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]