</table>
</chapter>
-
- <chapter>
- <title>Migrating from GnomeVFS to GIO</title>
-
- <table id="gnome-vfs-vs-gio">
- <title>Comparison of GnomeVFS and GIO concepts</title>
- <tgroup cols="2">
- <thead>
- <row><entry>GnomeVFS</entry><entry>GIO</entry></row>
- </thead>
- <tbody>
- <row><entry>GnomeVFSURI</entry><entry>GFile</entry></row>
- <row><entry>GnomeVFSFileInfo</entry><entry>GFileInfo</entry></row>
- <row><entry>GnomeVFSResult</entry><entry>GError, with G_IO_ERROR values</entry></row>
- <row><entry>GnomeVFSHandle & GnomeVFSAsyncHandle</entry><entry>GInputStream or GOutputStream</entry></row>
- <row><entry>GnomeVFSDirectoryHandle</entry><entry>GFileEnumerator</entry></row>
- <row><entry>mime type</entry><entry>content type</entry></row>
- <row><entry>GnomeVFSMonitor</entry><entry>GFileMonitor</entry></row>
- <row><entry>GnomeVFSVolumeMonitor</entry><entry>GVolumeMonitor</entry></row>
- <row><entry>GnomeVFSVolume</entry><entry>GMount</entry></row>
- <row><entry>GnomeVFSDrive</entry><entry>GVolume</entry></row>
- <row><entry>-</entry><entry>GDrive</entry></row>
- <row><entry>GnomeVFSContext</entry><entry>GCancellable</entry></row>
- <row><entry>gnome_vfs_async_cancel</entry><entry>g_cancellable_cancel</entry></row>
- </tbody>
- </tgroup>
- </table>
-
- <section>
- <title>Trash handling</title>
-
- <para>
- The handling of trashed files has been changed in GIO, compared
- to gnome-vfs. gnome-vfs has a home-grown trash implementation that
- predates the freedesktop.org <ulink url="http://www.freedesktop.org/wiki/Specifications/trash-spec">Desktop Trash Can</ulink> specification
- that is implemented in GIO. The location for storing trashed files
- has changed from <filename>$HOME/.Trash</filename> to
- <filename>$HOME/.local/share/Trash</filename> (or more correctly
- <filename>$XDG_DATA_HOME/Trash</filename>), which means that
- there is a need for migrating files that have been trashed by
- gnome-vfs to the new location.
- </para>
- <para>
- In gnome-vfs, the <filename>trash://</filename> scheme offering a
- merged view of all trash directories was implemented in nautilus,
- and trash-handling applications had to find and monitor all trash
- directories themselves. With GIO, the <filename>trash://</filename>
- implementation has been moved to gvfs and applications can simply
- monitor that location:
- </para>
-<informalexample><programlisting>
-static void
-file_changed (GFileMonitor *file_monitor,
- GFile *child,
- GFile *other_file,
- GFileMonitorEvent event_type,
- gpointer user_data)
-{
- switch (event_type)
- {
- case G_FILE_MONITOR_EVENT_DELETED:
- g_print ("'%s' removed from trash\n", g_file_get_basename (child));
- break;
- case G_FILE_MONITOR_EVENT_CREATED:
- g_print ("'%s' added to trash\n", g_file_get_basename (child));
- break;
- default: ;
- }
-}
-
-static void
-start_monitoring_trash (void)
-{
- GFile *file;
- GFileMonitor *monitor;
-
- file = g_file_new_for_uri ("trash://");
- monitor = g_file_monitor_directory (file, 0, NULL, NULL);
- g_object_unref (file);
-
- g_signal_connect (monitor, "changed", G_CALLBACK (file_changed), NULL);
-
- /* ... */
-
-}
-</programlisting></informalexample>
- <para>
- GIO exposes some useful metadata about trashed files. There are
- trash::orig-path and trash::deletion-date attributes. The
- standard::icon attribute of the <filename>trash://</filename>
- itself provides a suitable icon for displaying the trash can on
- the desktop. If you are using this icon, make sure to monitor
- this attribute for changes, since the icon may be updated to
- reflect that state of the trash can.
- </para>
- <para>
- Moving a file to the trash is much simpler with GIO. Instead of
- using gnome_vfs_find_directory() with %GNOME_VFS_DIRECTORY_KIND_TRASH
- to find out where to move the trashed file, just use the g_file_trash()
- function.
- </para>
- </section>
-
- <section>
- <title>Operations on multiple files</title>
-
- <para>
- gnome-vfs has the dreaded gnome_vfs_xfer_uri_list() function which
- has tons of options and offers the equivalent of cp, mv, ln, mkdir
- and rm at the same time.
- </para>
- <para>
- GIO offers a much simpler I/O scheduler functionality instead, that
- lets you schedule a function to be called in a separate thread, or
- if threads are not available, as an idle in the mainloop.
- See g_io_scheduler_push_job().
- </para>
-
- </section>
-
- <section>
- <title>Mime monitoring</title>
-
- <para>
- gnome-vfs offered a way to monitor the association between mime types
- and default handlers for changes, with the #GnomeVFSMIMEMonitor object.
- GIO does not offer a replacement for this functionality at this time,
- since we have not found a compelling use case where
- #GnomeVFSMIMEMonitor was used. If you think you have such a use
- case, please report it at
- <ulink url="http://bugzilla.gnome.org">bugzilla.gnome.org</ulink>.
- </para>
- </section>
- </chapter>
-
- <chapter>
- <title>Migrating from GConf to GSettings</title>
-
- <section>
- <title>Before you start</title>
-
- <para>
- 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.
- </para>
- <para>
- It is always a good idea to have a look at how others have handled
- similar problems before. An examplaric conversion can be found e.g.
- in the <ulink url="http://git.gnome.org/browse/gnome-utils/log/?h=gsettings-tutorial">gsettings-tutorial</ulink> branch of gnome-utils.
- </para>
- </section>
-
- <section>
- <title>Conceptual differences</title>
-
- <para>
- 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.
- </para>
- <para>
- 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'.
- </para>
- <para>
- 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.
- </para>
- </section>
-
- <section>
- <title>GConfClient (and GConfBridge) API conversion</title>
-
- <para>
- Most people use GConf via the high-level #GConfClient API.
- The corresponding API is the #GSettings object. While not
- every GConfClient function has a direct GSettings equivalent,
- many do:
- <table id="gconf-client-vs-gsettings">
- <tgroup cols="2">
- <thead>
- <row><entry>GConfClient</entry><entry>GSettings</entry></row>
- </thead>
- <tbody>
- <row><entry>gconf_client_get_default()</entry><entry>no direct equivalent,
- instead you call g_settings_new() for the schemas you use</entry></row>
- <row><entry>gconf_client_set()</entry><entry>g_settings_set()</entry></row>
- <row><entry>gconf_client_get()</entry><entry>g_settings_get()</entry></row>
- <row><entry>gconf_client_get_bool()</entry><entry>g_settings_get_boolean()</entry></row>
- <row><entry>gconf_client_set_bool()</entry><entry>g_settings_set_boolean()</entry></row>
- <row><entry>gconf_client_get_int()</entry><entry>g_settings_get_int()</entry></row>
- <row><entry>gconf_client_set_int()</entry><entry>g_settings_set_int()</entry></row>
- <row><entry>gconf_client_get_float()</entry><entry>g_settings_get_double()</entry></row>
- <row><entry>gconf_client_set_float()</entry><entry>g_settings_set_double()</entry></row>
- <row><entry>gconf_client_get_string()</entry><entry>g_settings_get_string()</entry></row>
- <row><entry>gconf_client_set_string()</entry><entry>g_settings_set_string()</entry></row>
- <row><entry>gconf_client_get_list()</entry><entry>for string lists, see g_settings_get_strv(), else see g_settings_get_value() and #GVariant API</entry></row>
- <row><entry>gconf_client_set_list()</entry><entry>for string lists, see g_settings_set_strv(), else see g_settings_set_value() and #GVariant API</entry></row>
- <row><entry>gconf_entry_get_is_writable()</entry><entry>g_settings_is_writable()</entry></row>
- <row><entry>gconf_client_notify_add()</entry><entry>not required, the #GSettings::changed signal is emitted automatically</entry></row>
- <row><entry>gconf_client_add_dir()</entry><entry>not required, each GSettings instance automatically watches all keys in its path</entry></row>
- <row><entry>#GConfChangeSet</entry><entry>g_settings_delay(), g_settings_apply()</entry></row>
- <row><entry>gconf_client_get_default_from_schema()</entry><entry>no equivalent, applications are expected to know their schema</entry></row>
- <row><entry>gconf_client_all_entries()</entry><entry>no equivalent, applications are expected to know their schema, and GSettings does not allow schema-less entries</entry></row>
- <row><entry>gconf_client_get_without_default()</entry><entry>no equivalent</entry></row>
- <row><entry>gconf_bridge_bind_property()</entry><entry>g_settings_bind()</entry></row>
- <row><entry>gconf_bridge_bind_property_full()</entry><entry>g_settings_bind_with_mapping()</entry></row>
- </tbody>
- </tgroup>
- </table>
- </para>
- <para>
- GConfBridge was a third-party library that used GConf to bind an object property
- to a particular configuration key. GSettings offers this service itself.
- </para>
- <para>
- 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.
- </para>
- <para>
- 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.
- </para>
- </section>
-
- <section>
- <title>Change notification</title>
-
- <para>
- 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.
- </para>
- <para>
- The #GSettings::changed signal is emitted for each changed key.
- There is also a #GSettings::change-event signal that you can handle
- if you need to see groups of keys that get changed at the same time.
- </para>
- <para>
- GSettings also notifies you about changes in writability of keys,
- with the #GSettings::writable-changed signal (and the
- #GSettings::writable-change-event signal).
- </para>
- </section>
-
- <section><title>Change sets</title>
- <para>
- GConf has a 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).
- </para>
- <para>
- Instead of a separate object to represent a change set, GSettings has a
- 'delayed-apply' mode, which can be turned on for a GSettings object by
- calling g_settings_delay(). In this mode, changes done to the GSettings
- object are not applied - they are still visible when calling g_settings_get()
- <emphasis>on the same object</emphasis>, but not to other GSettings instances
- or even other processes.
- </para>
- <para>
- To apply the pending changes all at once (GSettings <emphasis>does</emphasis>
- atomicity here), call g_settings_apply(). To revert the pending changes,
- call g_settings_revert() or just drop the reference to the #GSettings object.
- </para>
- </section>
-
- <section>
- <title>Schema conversion</title>
-
- <para>
- If you are porting your application from GConf, most likely you already
- have a GConf schema. GIO comes with a commandline tool
- <link linkend="gsettings-schema-convert">gsettings-schema-convert</link>
- that can help with the task of converting a GConf schema into
- an equivalent GSettings schema. The tool is not perfect and
- may need assistence in some cases.
- </para>
- <example><title>An example for using gsettings-schema-convert</title>
- <para>Running <userinput>gsettings-schema-convert --gconf --xml --schema-id "org.gnome.font-rendering" --output org.gnome.font-rendering.gschema.xml destop_gnome_font_rendering.schemas</userinput> on the following <filename>desktop_gnome_font_rendering.schemas</filename> file:
- <programlisting>
-<![CDATA[
-<?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>
-]]>
-</programlisting>
-produces a <filename>org.gnome.font-rendering.gschema.xml</filename> file with the following content:
-<programlisting>
-<![CDATA[
-<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>
-]]>
-</programlisting>
-</para>
- </example>
-
- <para>
- 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 DBus bus name, 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
- <filename>.gschema.xml</filename>. It is recommended to simply
- use the schema id as the filename, followed by this extension,
- e.g. <filename>org.gnome.font-rendering.gschema.xml</filename>.
- </para>
-
- <para>
- The XML source file for your GSettings schema needs to get installed
- into <filename>$datadir/glib-2.0/schemas</filename>, and needs to be
- compiled into a binary form. At runtime, GSettings looks for compiled
- schemas in the <filename>glib-2.0/schemas</filename> subdirectories
- of all <envar>XDG_DATA_DIRS</envar> directories, so if you install
- your schema in a different location, you need to set the
- <envar>XDG_DATA_DIRS</envar> environment variable appropriately.
- </para>
- <para>
- Schemas are compiled into binary form by the
- <link linkend="glib-compile-schemas">glib-compile-schemas</link> utility.
- GIO provides a <literal>gschema_compile</literal>
- variable for the schema compiler, which can be used in
- <filename>configure.in</filename> as follows:
-<programlisting>
-GLIB_GSETTINGS
-</programlisting>
- The corresponding <filename>Makefile.am</filename> fragment looks like
- this:
-<programlisting>
-# gsettingsschemadir and gschema_compile are defined by the GLIB_GSETTINGS
-# macro in configure.ac
-gsettingsschema_DATA = my.app.gschema.xml
-# This rule will check your schemas for validity before installation
-@GSETTINGS_CHECK_RULE@
-if GSETTINGS_SCHEMAS_INSTALL
-install-data-hook:
- $(GLIB_COMPILE_SCHEMAS) $(DESTDIR)$(gsettingsschemadir)
-endif
-</programlisting>
- </para>
-
- <para>
- 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.
- <programlisting>
-<![CDATA[
-<type>string</type>
-<default>rgb</default>
-]]>
- </programlisting>
- becomes
- <programlisting>
-<![CDATA[
-<key name="rgba-order" type="s">
- <default>'rgb'</default> <!-- note quotes -->
-</key>
-]]>
- </programlisting>
- </para>
- <para>
- 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
- <programlisting>
-<![CDATA[
-<key>/schemas/desktop/gnome/font_rendering/antialiasing</key>
-]]>
- </programlisting>
- becomes
- <programlisting>
-<![CDATA[
-<schema id="org.gnome.font" path="/desktop/gnome/font_rendering/">
- <key name="antialiasing" type="s">
-]]>
- </programlisting>
- </para>
- <para>
- 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 <tag class="attribute">gettext-domain</tag>
- attribute. Therefore, when converting localized defaults in GConf,
- <programlisting>
-<![CDATA[
-<key>/schemas/apps/my_app/font_size</key>
- <locale name="C">
- <default>18</default>
- </locale>
- <locale name="be">
- <default>24</default>
- </locale>
-</key>
-]]>
- </programlisting>
- becomes
- <programlisting>
-<![CDATA[
-<schema id="..." gettext-domain="your-domain">
- ...
-<key name="font-size" type="i">
- <default l10n="messages" context="font_size">18</default>
-</key>
-]]>
- </programlisting>
- Note how we used the context attribute to add msgctxt - "18" is not a
- good string to look up in gettext by itself. Also note that the value
- 24 is not present in the schema anymore. It has to be added to the
- gettext catalog for "be" instead.
- </para>
- <para>
- GSettings schemas have optional <tag class="starttag">summary</tag> and
- <tag class="starttag">description</tag> elements for each key which
- correspond to the <tag class="starttag">short</tag> and
- <tag class="starttag">long</tag> elements in the GConf schema and
- will be used in similar ways by a future gsettings-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. Translations for these strings will also be handled
- via gettext, so you should arrange for these strings to be
- extracted into your gettext catalog.
- </para>
- <para>
- 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 '-'.
- </para>
- <para>
- 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
- <option>--allow-any-name</option> with the
- <link linkend="glib-compile-schemas">glib-compile-schemas</link> 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.
- </para>
- </section>
-
- <section><title>Data conversion</title>
- <para>
- 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 <envar>GSETTINGS_BACKEND</envar>
- to 'gconf', e.g. by using
-<programlisting>
- g_setenv ("GSETTINGS_BACKEND", "gconf", TRUE);
-</programlisting>
- early on in your program. Note that this backend is meant purely
- as a transition tool, and should not be used in production.
- </para>
- <para>
- GConf also comes with a utility called
- <command>gsettings-data-convert</command>, 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.
- </para>
- <para>
- To make use of this utility, you must install a keyfile in the
- directory <filename>/usr/share/GConf/gsettings</filename> which
- lists the GSettings keys and GConf paths to map to each other, for
- each schema that you want to migrate user data for.
- </para>
- <para>
- Here is an example:
- <programlisting>
-<![CDATA[
-[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
-]]>
- </programlisting>
- 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.
- </para>
- <para>
- 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.
- </para>
- <para>
- There are some limitations: <command>gsettings-data-convert</command>
- does not do any transformation of the values. And it does not handle
- complex GConf types other than lists of strings or integers.
- </para>
- <para>
- 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.
- </para>
- </section>
- </chapter>
-
</part>