Editing Documentation/Maemo 5 Developer Guide/Using Generic Platform Components/Application Preferences-Gconf

Warning: You are not logged in. Your IP address will be recorded in this page's edit history.

Warning: This page is 97 kilobytes long; some browsers may have problems editing pages approaching or longer than 32kb. Please consider breaking the page into smaller sections.

The edit can be undone. Please check the comparison below to verify that this is what you want to do, and then save the changes below to finish undoing the edit.
Latest revision Your text
Line 1: Line 1:
-
[http://projects.gnome.org/gconf/ GConf] is used by the GNOME desktop environment for storing shared configuration settings for the desktop and applications. The daemon process GConfd follows the changes in the database. When a change occurs in the database, the daemon applies the new settings to the applications using them. For example, the control panel application uses GConf.
+
= Application Preferences - GConf=
-
If settings are used only by a single application, GLib utility for .ini style files should be used instead. Applications should naturally have working default settings. Settings should be saved only when the user changes them.  
+
GConf is used by the GNOME desktop environment for storing shared configuration settings for the desktop and applications. The daemon process GConfd follows the changes in the database. When a change occurs in the database, the daemon applies the new settings to the applications using them. For example, the control panel application uses GConf.
-
This chapter uses the following examples:
+
If settings are used only by a single application, Glib utility for .ini style files should be used instead. Applications should naturally have working default settings. Settings should be saved only when the user changes them.
-
* [https://vcs.maemo.org/svn/maemoexamples/tags/maemo_5.0/support-libraries/hildon_helloworld-9.c hildon_helloworld-9.c]
+
 
-
* [https://vcs.maemo.org/svn/maemoexamples/tags/maemo_5.0/gconf-listener/ gconf-listener]
+
This chapter uses the following example:
 +
*[https://vcs.maemo.org/svn/maemoexamples/tags/maemo_5.0/support-libraries/hildon_helloworld-9.c hildon_helloworld-9.c]
 +
*[https://vcs.maemo.org/svn/maemoexamples/tags/maemo_5.0/gconf-listener/ gconf-listener]
==GConf Basics==
==GConf Basics==
Line 21: Line 23:
The GConf model consists of two parts: the GConf client library (which will be used here) and the GConf server daemon that is the guardian and reader/writer of the back-end databases. In a regular GNOME environment, the client communicates with the server either by using the Bonobo library (lightweight object IPC mechanism) or D-Bus.
The GConf model consists of two parts: the GConf client library (which will be used here) and the GConf server daemon that is the guardian and reader/writer of the back-end databases. In a regular GNOME environment, the client communicates with the server either by using the Bonobo library (lightweight object IPC mechanism) or D-Bus.
-
As Bonobo is not used in Maemo (it is quite heavy, even if lightweight), the client will communicate with the server using D-Bus. This also allows the daemon to be started on demand, when there is at least one client wanting to use that service (this is a feature of D-Bus). The communication mechanism is encapsulated by the GConf client library, and as such, will be transparent.
+
As Bonobo is not used in maemo (it is quite heavy, even if lightweight), the client will communicate with the server using D-Bus. This also allows the daemon to be started on demand, when there is at least one client wanting to use that service (this is a feature of D-Bus). The communication mechanism is encapsulated by the GConf client library, and as such, will be transparent.
In order to read or write the preference database, it is necessary to decide on the key to use to access the application values. The database namespace is hierarchical, and uses the '/'-character to implement this hierarchy, starting from a root location similar to UNIX file system namespace.
In order to read or write the preference database, it is necessary to decide on the key to use to access the application values. The database namespace is hierarchical, and uses the '/'-character to implement this hierarchy, starting from a root location similar to UNIX file system namespace.
-
Each application will use its own "directory" under <code>/apps/Maemo/appname/</code>. N.B. Even when the word "directory" is seen in connection to GConf, one has to be careful to distinguish '''real directories''' from '''preference namespaces''' inside the GConf namespace. The <code>/apps/Maemo/appname/</code> above is in the GConf namespace, so there will not actually be a physical directory called <code>/apps/</code> on a system.
+
Each application will use its own "directory" under '''/apps/Maemo/appname/'''. N.B. Even when the word "directory" is seen in connection to GConf, one has to be careful to distinguish '''real directories''' from '''preference namespaces''' inside the GConf namespace. The /apps/Maemo/appname/ above is in the GConf namespace, so there will not actually be a physical directory called '''/apps/''' on a system.
-
The keys should be named according to the platform guidelines. The current guideline is that each application should store its configuration keys under <code>/apps/Maemo/appname/</code>, where <code>appname</code> is the name of the application. There is no central registry on the names in use currently, so names should be selected carefully. Key names should all be lowercase, with underscore used to separate multiple words. Also, ASCII should be used, since GConf does not support localization for key names (it does for key values, but that is not covered in this material).
+
The keys should be named according to the platform guidelines. The current guideline is that each application should store its configuration keys under '''/apps/Maemo/appname/''', where appname is the name of the application. There is no central registry on the names in use currently, so names should be selected carefully. Key names should all be lowercase, with underscore used to separate multiple words. Also, ASCII should be used, since GConf does not support localization for key names (it does for key values, but that is not covered in this material).
GConf values are typed, which means that it is necessary to select the type for the data that the key is supposed to hold.
GConf values are typed, which means that it is necessary to select the type for the data that the key is supposed to hold.
Line 33: Line 35:
The following types are supported for values in GConf:
The following types are supported for values in GConf:
-
* <code>gint</code> (32-bit signed)
+
* gint (32-bit signed)
-
* <code>gboolean</code>
+
* gboolean
-
* <code>gchar</code> (ASCII/ISO 8859-1/UTF-8 C string)
+
* gchar (ASCII/ISO 8859-1/UTF-8 C string)
-
* <code>gfloat</code> (with the limitation that the resolution is not guaranteed nor specified by GConf because of portability issues)
+
* gfloat (with the limitation that the resolution is not guaranteed nor specified by GConf because of portability issues)
* a list of values of one type
* a list of values of one type
* a pair of values, each having their own type (useful for storing "mapping" data)
* a pair of values, each having their own type (useful for storing "mapping" data)
Line 42: Line 44:
What is missing from the above list is storing binary data (for a good reason). The type system is also fairly limited. This is on purpose, so that complex configurations (like the Apache HTTP daemon uses, or Samba) are not attempted using GConf.
What is missing from the above list is storing binary data (for a good reason). The type system is also fairly limited. This is on purpose, so that complex configurations (like the Apache HTTP daemon uses, or Samba) are not attempted using GConf.
-
There is a diagnostic and administration tool called <code>gconftool-2</code> that is also available in the SDK. It can be used to set and unset keys, as well as display their current contents.
+
There is a diagnostic and administration tool called gconftool-2 that is also available in the SDK. It can be used to set and unset keys, as well as display their current contents.
Some examples of using gconftool-2 (on the SDK):
Some examples of using gconftool-2 (on the SDK):
-
* Displaying the contents of all keys stored under <code>/apps/</code> (listing cut for brevity)
+
* Displaying the contents of all keys stored under '''/apps/''' (listing cut for brevity) <br /><br />
-
 
+
-
<pre>
+
[sbox-DIABLO_X86: ~] &gt; run-standalone.sh gconftool-2 -R /apps
-
[sbox-DIABLO_X86: ~] > run-standalone.sh gconftool-2 -R /apps
+
  /apps/osso:
-
/apps/osso:
+
  /apps/osso/inputmethod:
-
  /apps/osso/inputmethod:
+
    launch_finger_kb_on_select = true
-
  launch_finger_kb_on_select = true
+
    input_method_plugin = himExample_vkb
-
  input_method_plugin = himExample_vkb
+
    available_languages = [en_GB]
-
  available_languages = [en_GB]
+
    use_finger_kb = true
-
  use_finger_kb = true
+
    /apps/osso/inputmethod/hildon-im-languages:
-
  /apps/osso/inputmethod/hildon-im-languages:
+
    language-0 = en_GB
-
    language-0 = en_GB
+
    current = 0
-
    current = 0
+
    language-1 =
-
    language-1 =
+
    list = []
-
    list = []
+
  /apps/osso/fontconfig:
-
  /apps/osso/fontconfig:
+
    font_scaling_factor = Schema (type: `float' list_type:
-
  font_scaling_factor = Schema (type: `float' list_type:
+
    '*invalid*' car_type: '*invalid*' cdr_type: '*invalid*'
-
    '*invalid*' car_type: '*invalid*' cdr_type: '*invalid*'
+
    locale: `C')
-
    locale: `C')
+
  /apps/osso/apps:
-
  /apps/osso/apps:
+
    /apps/osso/apps/controlpanel:
-
  /apps/osso/apps/controlpanel:
+
    groups = [copa_ia_general,copa_ia_connectivity,
-
    groups = [copa_ia_general,copa_ia_connectivity,
+
              copa_ia_personalisation]
-
              copa_ia_personalisation]
+
    icon_size = false
-
    icon_size = false
+
    group_ids = [general,connectivity,personalisation]
-
    group_ids = [general,connectivity,personalisation]
+
  /apps/osso/osso:
-
  /apps/osso/osso:
+
    /apps/osso/osso/thumbnailers:
-
  /apps/osso/osso/thumbnailers:
+
    /apps/osso/osso/thumbnailers/audio@x-mp3:
-
    /apps/osso/osso/thumbnailers/audio@x-mp3:
+
      command = /usr/bin/hildon-thumb-libid3
-
    command = /usr/bin/hildon-thumb-libid3
+
    /apps/osso/osso/thumbnailers/audio@x-m4a:
-
    /apps/osso/osso/thumbnailers/audio@x-m4a:
+
      command = /usr/bin/hildon-thumb-libid3
-
    command = /usr/bin/hildon-thumb-libid3
+
    /apps/osso/osso/thumbnailers/audio@mp3:
-
    /apps/osso/osso/thumbnailers/audio@mp3:
+
      command = /usr/bin/hildon-thumb-libid3
-
    command = /usr/bin/hildon-thumb-libid3
+
    /apps/osso/osso/thumbnailers/audio@x-mp2:
-
    /apps/osso/osso/thumbnailers/audio@x-mp2:
+
      command = /usr/bin/hildon-thumb-libid3
-
    command = /usr/bin/hildon-thumb-libid3
+
-
</pre>
+
-
* Creating and setting the value to a new key.
+
* Creating and setting the value to a new key. <br /><br />
   
   
  [sbox-DIABLO_X86: ~] &gt; run-standalone.sh gconftool-2  \
  [sbox-DIABLO_X86: ~] &gt; run-standalone.sh gconftool-2  \
   --set /apps/Maemo/testing/testkey --type=int 5
   --set /apps/Maemo/testing/testkey --type=int 5
-
* Listing all keys under the namespace <code>/apps/Maemo/testing</code>.
+
* Listing all keys under the namespace '''/apps/Maemo/testing'''. <br /><br />
   
   
  [sbox-DIABLO_X86: ~] &gt; run-standalone.sh gconftool-2  \
  [sbox-DIABLO_X86: ~] &gt; run-standalone.sh gconftool-2  \
Line 94: Line 94:
   testkey = 5
   testkey = 5
-
* Removing the last key will also remove the key directory.
+
* Removing the last key will also remove the key directory. <br /><br />
   
   
  [sbox-DIABLO_X86: ~] &gt; run-standalone.sh gconftool-2  \
  [sbox-DIABLO_X86: ~] &gt; run-standalone.sh gconftool-2  \
Line 101: Line 101:
   -R /apps/Maemo/testing
   -R /apps/Maemo/testing
-
* Removing whole key hierarchies is also possible.
+
* Removing whole key hierarchies is also possible. <br /><br />
   
   
  [sbox-DIABLO_X86: ~] &gt; run-standalone.sh gconftool-2  \
  [sbox-DIABLO_X86: ~] &gt; run-standalone.sh gconftool-2  \
   --recursive-unset /apps/Maemo/testing
   --recursive-unset /apps/Maemo/testing
-
For more detailed information, please see [http://maemo.org/api_refs/5.0/5.0-final/gconf2/ Gconf API documentation].
+
 
 +
For more detailed information, please see [http://maemo.org/api_refs/5.0/beta/gconf2/ Gconf API documentation].
==  Using GConf to read and write preferences ==
==  Using GConf to read and write preferences ==
 +
 +
Section ''Application Settings'' [/node9.html#sec:application_settings [[Image:crossref.png|[*]]]] of chapter ''Application Development'' in Maemo Reference Manual presents a short introductory example of gconf usage. The following example is a bit more complicated.
The example is required to:
The example is required to:
Line 115: Line 118:
* Load the color preference on application startup.
* Load the color preference on application startup.
-
Even if GConf concepts seem to be logical, it can be seen that using GConf will require one to learn some new things (e.g. the <code>GError</code>-object). Since the GConf client code is in its own library, the relevant compiler flags and library options need to be added again. The pkg-config package name is <code>gconf-2.0</code> hildon_helloworld-9.c
+
Even if GConf concepts seem to be logical, it can be seen that using GConf will require one to learn some new things (e.g. the GError-object). Since the GConf client code is in its own library, the relevant compiler flags and library options need to be added again. The pkg-config package name is gconf-2.0 hildon_helloworld-9.c
-
<source lang="c">
+
<tt><span>''<span><font color="#9A1900">/**</font></span>''</span>
-
/**
+
  <span>''<span><font color="#9A1900"> * hildon_helloworld-9.c</font></span>''</span>
-
  * hildon_helloworld-9.c
+
  <span>''<span><font color="#9A1900"> *</font></span>''</span>
-
  *
+
  <span>''<span><font color="#9A1900"> * This maemo code example is licensed under a MIT-style license,</font></span>''</span>
-
  * This maemo code example is licensed under a MIT-style license,
+
  <span>''<span><font color="#9A1900"> * that can be found in the file called "License" in the same</font></span>''</span>
-
  * that can be found in the file called "License" in the same
+
  <span>''<span><font color="#9A1900"> * directory as this file.</font></span>''</span>
-
  * directory as this file.
+
  <span>''<span><font color="#9A1900"> * Copyright (c) 2007-2008 Nokia Corporation. All rights reserved.</font></span>''</span>
-
  * Copyright (c) 2007-2008 Nokia Corporation. All rights reserved.
+
  <span>''<span><font color="#9A1900"> *</font></span>''</span>
-
  *
+
  <span>''<span><font color="#9A1900"> * We'll store the color that the user selects into a GConf</font></span>''</span>
-
  * We'll store the color that the user selects into a GConf
+
  <span>''<span><font color="#9A1900"> * preference. In fact, we'll have three settings, one for each</font></span>''</span>
-
  * preference. In fact, we'll have three settings, one for each
+
  <span>''<span><font color="#9A1900"> * channel of the color (red, green and blue).</font></span>''</span>
-
  * channel of the color (red, green and blue).
+
  <span>''<span><font color="#9A1900"> *</font></span>''</span>
-
  *
+
  <span>''<span><font color="#9A1900"> * Look for lines with "NEW" or "MODIFIED" in them.</font></span>''</span>
-
  * Look for lines with "NEW" or "MODIFIED" in them.
+
  <span>''<span><font color="#9A1900"> */</font></span>''</span>
-
  */
+
-
 
+
<span>'''<span><font color="#000080"><nowiki>#include</nowiki></font></span>'''</span> <span><font color="#FF0000">&lt;stdlib.h&gt;</font></span>
-
#include <stdlib.h>
+
<span>'''<span><font color="#000080"><nowiki>#include</nowiki></font></span>'''</span> <span><font color="#FF0000">&lt;hildon/hildon-program.h&gt;</font></span>
-
#include <hildon/hildon-program.h>
+
<span>'''<span><font color="#000080"><nowiki>#include</nowiki></font></span>'''</span> <span><font color="#FF0000">&lt;hildon/hildon-color-button.h&gt;</font></span>
-
#include <hildon/hildon-color-button.h>
+
<span>'''<span><font color="#000080"><nowiki>#include</nowiki></font></span>'''</span> <span><font color="#FF0000">&lt;hildon/hildon-find-toolbar.h&gt;</font></span>
-
#include <hildon/hildon-find-toolbar.h>
+
<span>'''<span><font color="#000080"><nowiki>#include</nowiki></font></span>'''</span> <span><font color="#FF0000">&lt;hildon/hildon-file-chooser-dialog.h&gt;</font></span>
-
#include <hildon/hildon-file-chooser-dialog.h>
+
<span>'''<span><font color="#000080"><nowiki>#include</nowiki></font></span>'''</span> <span><font color="#FF0000">&lt;hildon/hildon-banner.h&gt;</font></span>
-
#include <hildon/hildon-banner.h>
+
<span>'''<span><font color="#000080"><nowiki>#include</nowiki></font></span>'''</span> <span><font color="#FF0000">&lt;libgnomevfs/gnome-vfs.h&gt;</font></span>
-
#include <libgnomevfs/gnome-vfs.h>
+
<span>''<span><font color="#9A1900">/* Include the prototypes for GConf client functions (NEW). */</font></span>''</span>
-
/* Include the prototypes for GConf client functions (NEW). */
+
<span>'''<span><font color="#000080"><nowiki>#include</nowiki></font></span>'''</span> <span><font color="#FF0000">&lt;gconf/gconf-client.h&gt;</font></span>
-
#include <gconf/gconf-client.h>
+
-
 
+
<span>''<span><font color="#9A1900">/* The application name -part of the GConf namespace (NEW). */</font></span>''</span>
-
/* The application name -part of the GConf namespace (NEW). */
+
<span>'''<span><font color="#000080"><nowiki>#define</nowiki></font></span>'''</span> APP_NAME <span><font color="#FF0000">"hildon_hello"</font></span>
-
#define APP_NAME "hildon_hello"
+
<span>''<span><font color="#9A1900">/* This will be the root "directory" for our preferences (NEW). */</font></span>''</span>
-
/* This will be the root "directory" for our preferences (NEW). */
+
<span>'''<span><font color="#000080"><nowiki>#define</nowiki></font></span>'''</span> GC_ROOT  <span><font color="#FF0000">"/apps/Maemo/"</font></span> APP_NAME <span><font color="#FF0000">"/"</font></span>
-
#define GC_ROOT  "/apps/Maemo/" APP_NAME "/"
+
-
 
+
  <span>''<span><font color="#9A1900">/*... Listing cut for brevity ...*/</font></span>''</span>
-
  /*... Listing cut for brevity ...*/
+
-
 
+
<span>''<span><font color="#9A1900">/**</font></span>''</span>
-
/**
+
  <span>''<span><font color="#9A1900"> * NEW</font></span>''</span>
-
  * NEW
+
  <span>''<span><font color="#9A1900"> *</font></span>''</span>
-
  *
+
  <span>''<span><font color="#9A1900"> * Utility function to store the given color into our application</font></span>''</span>
-
  * Utility function to store the given color into our application
+
  <span>''<span><font color="#9A1900"> * preferences. We could use a list of integers as well, but we'll</font></span>''</span>
-
  * preferences. We could use a list of integers as well, but we'll
+
  <span>''<span><font color="#9A1900"> * settle for three separate properties; one for each of RGB</font></span>''</span>
-
  * settle for three separate properties; one for each of RGB
+
  <span>''<span><font color="#9A1900"> * channels.</font></span>''</span>
-
  * channels.
+
  <span>''<span><font color="#9A1900"> *</font></span>''</span>
-
  *
+
  <span>''<span><font color="#9A1900"> * The config keys that will be used are 'red', 'green' and 'blue'.</font></span>''</span>
-
  * The config keys that will be used are 'red', 'green' and 'blue'.
+
  <span>''<span><font color="#9A1900"> *</font></span>''</span>
-
  *
+
  <span>''<span><font color="#9A1900"> * NOTE:</font></span>''</span>
-
  * NOTE:
+
  <span>''<span><font color="#9A1900"> *  We're doing things very non-optimally. If our application would</font></span>''</span>
-
  *  We're doing things very non-optimally. If our application would
+
  <span>''<span><font color="#9A1900"> *  have multiple preference settings, and we would like to know</font></span>''</span>
-
  *  have multiple preference settings, and we would like to know
+
  <span>''<span><font color="#9A1900"> *  when someone will change them (external program, another</font></span>''</span>
-
  *  when someone will change them (external program, another
+
  <span>''<span><font color="#9A1900"> *  instance of our program, etc), we'd have to keep a reference to</font></span>''</span>
-
  *  instance of our program, etc), we'd have to keep a reference to
+
  <span>''<span><font color="#9A1900"> *  the GConf client connection. Listening for changes in</font></span>''</span>
-
  *  the GConf client connection. Listening for changes in
+
  <span>''<span><font color="#9A1900"> *  preferences would also require a callback registration, but this</font></span>''</span>
-
  *  preferences would also require a callback registration, but this
+
  <span>''<span><font color="#9A1900"> *  is covered in the "maemo Platform Development" material.</font></span>''</span>
-
  *  is covered in the "maemo Platform Development" material.
+
  <span>''<span><font color="#9A1900"> */</font></span>''</span>
-
  */
+
<span>'''<span><font color="#0000FF">static</font></span>'''</span> <span><font color="#009900">void</font></span> <span>'''<span><font color="#000000">confStoreColor</font></span>'''</span><span><font color="#990000">(</font></span><span>'''<span><font color="#0000FF">const</font></span>'''</span> GdkColor<span><font color="#990000"><nowiki>*</nowiki></font></span> color<span><font color="#990000">)</font></span> <span><font color="#FF0000">{</font></span>
-
static void confStoreColor(const GdkColor* color) {
+
-
 
+
  <span>''<span><font color="#9A1900">/* We'll store the pointer to the GConf connection here. */</font></span>''</span>
-
  /* We'll store the pointer to the GConf connection here. */
+
  GConfClient<span><font color="#990000"><nowiki>*</nowiki></font></span> gcClient <span><font color="#990000"><nowiki>=</nowiki></font></span> NULL<span><font color="#990000"><nowiki>;</nowiki></font></span>
-
  GConfClient* gcClient = NULL;
+
-
 
+
  <span>''<span><font color="#9A1900">/* Make sure that no NULLs are passed for the color. GdkColor is</font></span>''</span>
-
  /* Make sure that no NULLs are passed for the color. GdkColor is
+
<span>''<span><font color="#9A1900">    not a proper GObject, so there is no GDK_IS_COLOR macro. */</font></span>''</span>
-
    not a proper GObject, so there is no GDK_IS_COLOR macro. */
+
  <span>'''<span><font color="#000000">g_assert</font></span>'''</span><span><font color="#990000">(</font></span>color<span><font color="#990000">);</font></span>
-
   g_assert(color);
+
-
 
+
  <span>'''<span><font color="#000000">g_print</font></span>'''</span><span><font color="#990000">(</font></span><span><font color="#FF0000">"confStoreColor: invoked</font></span><span><font color="#CC33CC">\n</font></span><span><font color="#FF0000">"</font></span><span><font color="#990000">);</font></span>
-
   g_print("confStoreColor: invoked\n");
+
 +
  <span>''<span><font color="#9A1900">/* Open a connection to gconfd-2 (via D-Bus in maemo). The GConf</font></span>''</span>
 +
<span>''<span><font color="#9A1900">    API doesn't say whether this function can ever return NULL or</font></span>''</span>
 +
<span>''<span><font color="#9A1900">    how it will behave in error conditions. */</font></span>''</span>
 +
  gcClient <span><font color="#990000"><nowiki>=</nowiki></font></span> <span>'''<span><font color="#000000">gconf_client_get_default</font></span>'''</span><span><font color="#990000">();</font></span>
 +
  <span>''<span><font color="#9A1900">/* We make sure that it's a valid GConf-client object. */</font></span>''</span>
 +
  <span>'''<span><font color="#000000">g_assert</font></span>'''</span><span><font color="#990000">(</font></span><span>'''<span><font color="#000000">GCONF_IS_CLIENT</font></span>'''</span><span><font color="#990000">(</font></span>gcClient<span><font color="#990000">));</font></span>
 +
 +
  <span>''<span><font color="#9A1900">/* Store the values. */</font></span>''</span>
 +
  <span>'''<span><font color="#0000FF">if</font></span>'''</span> <span><font color="#990000">(!</font></span><span>'''<span><font color="#000000">gconf_client_set_int</font></span>'''</span><span><font color="#990000">(</font></span>gcClient<span><font color="#990000">,</font></span> GC_ROOT <span><font color="#FF0000">"red"</font></span><span><font color="#990000">,</font></span> color<span><font color="#990000">-&gt;</font></span>red<span><font color="#990000">,</font></span>
 +
                            NULL<span><font color="#990000">))</font></span> <span><font color="#FF0000">{</font></span>
 +
    <span>'''<span><font color="#000000">g_warning</font></span>'''</span><span><font color="#990000">(</font></span><span><font color="#FF0000">" failed to set %s/red to %d</font></span><span><font color="#CC33CC">\n</font></span><span><font color="#FF0000">"</font></span><span><font color="#990000">,</font></span> GC_ROOT<span><font color="#990000">,</font></span> color<span><font color="#990000">-&gt;</font></span>red<span><font color="#990000">);</font></span>
 +
  <span><font color="#FF0000">}</font></span>
 +
  <span>'''<span><font color="#0000FF">if</font></span>'''</span> <span><font color="#990000">(!</font></span><span>'''<span><font color="#000000">gconf_client_set_int</font></span>'''</span><span><font color="#990000">(</font></span>gcClient<span><font color="#990000">,</font></span> GC_ROOT <span><font color="#FF0000">"green"</font></span><span><font color="#990000">,</font></span> color<span><font color="#990000">-&gt;</font></span>green<span><font color="#990000">,</font></span>
 +
                            NULL<span><font color="#990000">))</font></span> <span><font color="#FF0000">{</font></span>
 +
    <span>'''<span><font color="#000000">g_warning</font></span>'''</span><span><font color="#990000">(</font></span><span><font color="#FF0000">" failed to set %s/green to %d</font></span><span><font color="#CC33CC">\n</font></span><span><font color="#FF0000">"</font></span><span><font color="#990000">,</font></span> GC_ROOT<span><font color="#990000">,</font></span>
 +
              color<span><font color="#990000">-&gt;</font></span>green<span><font color="#990000">);</font></span>
 +
  <span><font color="#FF0000">}</font></span>
 +
  <span>'''<span><font color="#0000FF">if</font></span>'''</span> <span><font color="#990000">(!</font></span><span>'''<span><font color="#000000">gconf_client_set_int</font></span>'''</span><span><font color="#990000">(</font></span>gcClient<span><font color="#990000">,</font></span> GC_ROOT <span><font color="#FF0000">"blue"</font></span><span><font color="#990000">,</font></span> color<span><font color="#990000">-&gt;</font></span>blue<span><font color="#990000">,</font></span>
 +
                            NULL<span><font color="#990000">))</font></span> <span><font color="#FF0000">{</font></span>
 +
    <span>'''<span><font color="#000000">g_warning</font></span>'''</span><span><font color="#990000">(</font></span><span><font color="#FF0000">" failed to set %s/blue to %d</font></span><span><font color="#CC33CC">\n</font></span><span><font color="#FF0000">"</font></span><span><font color="#990000">,</font></span> GC_ROOT<span><font color="#990000">,</font></span>
 +
              color<span><font color="#990000">-&gt;</font></span>blue<span><font color="#990000">);</font></span>
 +
  <span><font color="#FF0000">}</font></span>
 +
 +
  <span>''<span><font color="#9A1900">/* Release the GConf client object (with GObject-unref). */</font></span>''</span>
 +
  <span>'''<span><font color="#000000">g_object_unref</font></span>'''</span><span><font color="#990000">(</font></span>gcClient<span><font color="#990000">);</font></span>
 +
  gcClient <span><font color="#990000"><nowiki>=</nowiki></font></span> NULL<span><font color="#990000"><nowiki>;</nowiki></font></span>
 +
<span><font color="#FF0000">}</font></span>
 +
 +
<span>''<span><font color="#9A1900">/**</font></span>''</span>
 +
<span>''<span><font color="#9A1900"> * NEW</font></span>''</span>
 +
<span>''<span><font color="#9A1900"> *</font></span>''</span>
 +
<span>''<span><font color="#9A1900"> * A utility function to get an integer but also return the status</font></span>''</span>
 +
<span>''<span><font color="#9A1900"> * whether the requested key existed or not.</font></span>''</span>
 +
<span>''<span><font color="#9A1900"> *</font></span>''</span>
 +
<span>''<span><font color="#9A1900"> * NOTE:</font></span>''</span>
 +
<span>''<span><font color="#9A1900"> *   It's also possible to use gconf_client_get_int(), but it's not</font></span>''</span>
 +
<span>''<span><font color="#9A1900"> *  possible to then know whether they key existed or not, because</font></span>''</span>
 +
<span>''<span><font color="#9A1900"> *  the function will return 0 if the key doesn't exist (and if the</font></span>''</span>
 +
<span>''<span><font color="#9A1900"> *  value is 0, how could you tell these two conditions apart?).</font></span>''</span>
 +
<span>''<span><font color="#9A1900"> *</font></span>''</span>
 +
<span>''<span><font color="#9A1900"> * Parameters:</font></span>''</span>
 +
<span>''<span><font color="#9A1900"> * - GConfClient: the client object to use</font></span>''</span>
 +
<span>''<span><font color="#9A1900"> * - const gchar*: the key</font></span>''</span>
 +
<span>''<span><font color="#9A1900"> * - gint*: the address to store the integer to if the key exists</font></span>''</span>
 +
<span>''<span><font color="#9A1900"> *</font></span>''</span>
 +
<span>''<span><font color="#9A1900"> * Returns:</font></span>''</span>
 +
<span>''<span><font color="#9A1900"> * - TRUE: if integer has been updated with a value from GConf.</font></span>''</span>
 +
<span>''<span><font color="#9A1900"> *  FALSE: there was no such key or it wasn't an integer.</font></span>''</span>
 +
<span>''<span><font color="#9A1900"> */</font></span>''</span>
 +
<span>'''<span><font color="#0000FF">static</font></span>'''</span> gboolean <span>'''<span><font color="#000000">confGetInt</font></span>'''</span><span><font color="#990000">(</font></span>GConfClient<span><font color="#990000"><nowiki>*</nowiki></font></span> gcClient<span><font color="#990000">,</font></span> <span>'''<span><font color="#0000FF">const</font></span>'''</span> gchar<span><font color="#990000"><nowiki>*</nowiki></font></span> key<span><font color="#990000">,</font></span>
 +
                            gint<span><font color="#990000"><nowiki>*</nowiki></font></span> number<span><font color="#990000">)</font></span> <span><font color="#FF0000">{</font></span>
 +
 +
  <span>''<span><font color="#9A1900">/* This will hold the type/value pair at some point. */</font></span>''</span>
 +
  GConfValue<span><font color="#990000"><nowiki>*</nowiki></font></span> val <span><font color="#990000"><nowiki>=</nowiki></font></span> NULL<span><font color="#990000"><nowiki>;</nowiki></font></span>
 +
  <span>''<span><font color="#9A1900">/* Return flag (tells the caller whether this function wrote behind</font></span>''</span>
 +
<span>''<span><font color="#9A1900">    the 'number' pointer or not). */</font></span>''</span>
 +
  gboolean hasChanged <span><font color="#990000"><nowiki>=</nowiki></font></span> FALSE<span><font color="#990000"><nowiki>;</nowiki></font></span>
 +
 +
  <span>''<span><font color="#9A1900">/* Try to get the type/value from the GConf DB.</font></span>''</span>
 +
<span>''<span><font color="#9A1900">    NOTE:</font></span>''</span>
 +
<span>''<span><font color="#9A1900">      We're using a version of the getter that will not return any</font></span>''</span>
 +
<span>''<span><font color="#9A1900">      defaults (if a schema would specify one). Instead, it will</font></span>''</span>
 +
<span>''<span><font color="#9A1900">      return the value if one has been set (or NULL).</font></span>''</span>
 +
 +
<span>''<span><font color="#9A1900">    We're not really interested in errors as this will return a NULL</font></span>''</span>
 +
<span>''<span><font color="#9A1900">    in case of missing keys or errors and that is quite enough for</font></span>''</span>
 +
<span>''<span><font color="#9A1900">    us. */</font></span>''</span>
 +
  val <span><font color="#990000"><nowiki>=</nowiki></font></span> <span>'''<span><font color="#000000">gconf_client_get_without_default</font></span>'''</span><span><font color="#990000">(</font></span>gcClient<span><font color="#990000">,</font></span> key<span><font color="#990000">,</font></span> NULL<span><font color="#990000">);</font></span>
 +
  <span>'''<span><font color="#0000FF">if</font></span>'''</span> <span><font color="#990000">(</font></span>val <span><font color="#990000"><nowiki>==</nowiki></font></span> NULL<span><font color="#990000">)</font></span> <span><font color="#FF0000">{</font></span>
 +
    <span>''<span><font color="#9A1900">/* Key wasn't found, no need to touch anything. */</font></span>''</span>
 +
    <span>'''<span><font color="#000000">g_warning</font></span>'''</span><span><font color="#990000">(</font></span><span><font color="#FF0000">"confGetInt: key %s not found</font></span><span><font color="#CC33CC">\n</font></span><span><font color="#FF0000">"</font></span><span><font color="#990000">,</font></span> key<span><font color="#990000">);</font></span>
 +
    <span>'''<span><font color="#0000FF">return</font></span>'''</span> FALSE<span><font color="#990000"><nowiki>;</nowiki></font></span>
 +
  <span><font color="#FF0000">}</font></span>
 +
 +
  <span>''<span><font color="#9A1900">/* Check whether the value stored behind the key is an integer. If</font></span>''</span>
 +
<span>''<span><font color="#9A1900">    it is not, we issue a warning, but return normally. */</font></span>''</span>
 +
  <span>'''<span><font color="#0000FF">if</font></span>'''</span> <span><font color="#990000">(</font></span>val<span><font color="#990000">-&gt;</font></span>type <span><font color="#990000"><nowiki>==</nowiki></font></span> GCONF_VALUE_INT<span><font color="#990000">)</font></span> <span><font color="#FF0000">{</font></span>
 +
    <span>''<span><font color="#9A1900">/* It's an integer, get it and store. */</font></span>''</span>
 +
    <span><font color="#990000"><nowiki>*</nowiki></font></span>number <span><font color="#990000"><nowiki>=</nowiki></font></span> <span>'''<span><font color="#000000">gconf_value_get_int</font></span>'''</span><span><font color="#990000">(</font></span>val<span><font color="#990000">);</font></span>
 +
    <span>''<span><font color="#9A1900">/* Mark that we've changed the integer behind 'number'. */</font></span>''</span>
 +
    hasChanged <span><font color="#990000"><nowiki>=</nowiki></font></span> TRUE<span><font color="#990000"><nowiki>;</nowiki></font></span>
 +
  <span><font color="#FF0000">}</font></span> <span>'''<span><font color="#0000FF">else</font></span>'''</span> <span><font color="#FF0000">{</font></span>
 +
    <span>'''<span><font color="#000000">g_warning</font></span>'''</span><span><font color="#990000">(</font></span><span><font color="#FF0000">"confGetInt: key %s is not an integer</font></span><span><font color="#CC33CC">\n</font></span><span><font color="#FF0000">"</font></span><span><font color="#990000">,</font></span> key<span><font color="#990000">);</font></span>
 +
  <span><font color="#FF0000">}</font></span>
 +
 +
  <span>''<span><font color="#9A1900">/* Free the type/value-pair. */</font></span>''</span>
 +
  <span>'''<span><font color="#000000">gconf_value_free</font></span>'''</span><span><font color="#990000">(</font></span>val<span><font color="#990000">);</font></span>
 +
  val <span><font color="#990000"><nowiki>=</nowiki></font></span> NULL<span><font color="#990000"><nowiki>;</nowiki></font></span>
 +
 +
  <span>'''<span><font color="#0000FF">return</font></span>'''</span> hasChanged<span><font color="#990000"><nowiki>;</nowiki></font></span>
 +
<span><font color="#FF0000">}</font></span>
 +
 +
<span>''<span><font color="#9A1900">/**</font></span>''</span>
 +
<span>''<span><font color="#9A1900"> * NEW</font></span>''</span>
 +
<span>''<span><font color="#9A1900"> *</font></span>''</span>
 +
<span>''<span><font color="#9A1900"> * Utility function to change the given color into the one that is</font></span>''</span>
 +
<span>''<span><font color="#9A1900"> * specified in application preferences.</font></span>''</span>
 +
<span>''<span><font color="#9A1900"> *</font></span>''</span>
 +
<span>''<span><font color="#9A1900"> * If some key is missing, that channel is left untouched. The</font></span>''</span>
 +
<span>''<span><font color="#9A1900"> * function also checks for proper values for the channels so that</font></span>''</span>
 +
<span>''<span><font color="#9A1900"> * invalid values are not accepted (guint16 range of GdkColor).</font></span>''</span>
 +
<span>''<span><font color="#9A1900"> *</font></span>''</span>
 +
<span>''<span><font color="#9A1900"> * Parameters:</font></span>''</span>
 +
<span>''<span><font color="#9A1900"> * - GdkColor*: the color structure to modify if changed from prefs.</font></span>''</span>
 +
<span>''<span><font color="#9A1900"> *</font></span>''</span>
 +
<span>''<span><font color="#9A1900"> * Returns:</font></span>''</span>
 +
<span>''<span><font color="#9A1900"> * - TRUE if the color was been changed by this routine.</font></span>''</span>
 +
<span>''<span><font color="#9A1900"> *  FALSE if the color wasn't changed (there was an error or the</font></span>''</span>
 +
<span>''<span><font color="#9A1900"> *  color was already exactly the same as in the preferences).</font></span>''</span>
 +
<span>''<span><font color="#9A1900"> */</font></span>''</span>
 +
<span>'''<span><font color="#0000FF">static</font></span>'''</span> gboolean <span>'''<span><font color="#000000">confLoadCurrentColor</font></span>'''</span><span><font color="#990000">(</font></span>GdkColor<span><font color="#990000"><nowiki>*</nowiki></font></span> color<span><font color="#990000">)</font></span> <span><font color="#FF0000">{</font></span>
 +
 +
  GConfClient<span><font color="#990000"><nowiki>*</nowiki></font></span> gcClient <span><font color="#990000"><nowiki>=</nowiki></font></span> NULL<span><font color="#990000"><nowiki>;</nowiki></font></span>
 +
  <span>''<span><font color="#9A1900">/* Temporary holders for the pref values. */</font></span>''</span>
 +
  gint red <span><font color="#990000"><nowiki>=</nowiki></font></span> <span><font color="#990000">-</font></span><span><font color="#993399">1</font></span><span><font color="#990000"><nowiki>;</nowiki></font></span>
 +
  gint green <span><font color="#990000"><nowiki>=</nowiki></font></span> <span><font color="#990000">-</font></span><span><font color="#993399">1</font></span><span><font color="#990000"><nowiki>;</nowiki></font></span>
 +
  gint blue <span><font color="#990000"><nowiki>=</nowiki></font></span> <span><font color="#990000">-</font></span><span><font color="#993399">1</font></span><span><font color="#990000"><nowiki>;</nowiki></font></span>
 +
  <span>''<span><font color="#9A1900">/* Temp variable to hold whether the color has changed. */</font></span>''</span>
 +
  gboolean hasChanged <span><font color="#990000"><nowiki>=</nowiki></font></span> FALSE<span><font color="#990000"><nowiki>;</nowiki></font></span>
 +
 +
  <span>'''<span><font color="#000000">g_assert</font></span>'''</span><span><font color="#990000">(</font></span>color<span><font color="#990000">);</font></span>
 +
 +
  <span>'''<span><font color="#000000">g_print</font></span>'''</span><span><font color="#990000">(</font></span><span><font color="#FF0000">"confLoadCurrentColor: invoked</font></span><span><font color="#CC33CC">\n</font></span><span><font color="#FF0000">"</font></span><span><font color="#990000">);</font></span>
 +
 +
  <span>''<span><font color="#9A1900">/* Open a connection to gconfd-2 (via d-bus). */</font></span>''</span>
 +
  gcClient <span><font color="#990000"><nowiki>=</nowiki></font></span> <span>'''<span><font color="#000000">gconf_client_get_default</font></span>'''</span><span><font color="#990000">();</font></span>
 +
  <span>''<span><font color="#9A1900">/* Make sure that it's a valid GConf-client object. */</font></span>''</span>
 +
  <span>'''<span><font color="#000000">g_assert</font></span>'''</span><span><font color="#990000">(</font></span><span>'''<span><font color="#000000">GCONF_IS_CLIENT</font></span>'''</span><span><font color="#990000">(</font></span>gcClient<span><font color="#990000">));</font></span>
 +
 +
  <span>'''<span><font color="#0000FF">if</font></span>'''</span> <span><font color="#990000">(</font></span><span>'''<span><font color="#000000">confGetInt</font></span>'''</span><span><font color="#990000">(</font></span>gcClient<span><font color="#990000">,</font></span> GC_ROOT <span><font color="#FF0000">"red"</font></span><span><font color="#990000">,</font></span> <span><font color="#990000">&amp;</font></span>red<span><font color="#990000">))</font></span> <span><font color="#FF0000">{</font></span>
 +
    <span>''<span><font color="#9A1900">/* We got the value successfully, now clamp it. */</font></span>''</span>
 +
    <span>'''<span><font color="#000000">g_print</font></span>'''</span><span><font color="#990000">(</font></span><span><font color="#FF0000">" got red = %d, "</font></span><span><font color="#990000">,</font></span> red<span><font color="#990000">);</font></span>
 +
    <span>''<span><font color="#9A1900">/* We got a value, so let's limit it between 0 and 65535 (the</font></span>''</span>
 +
<span>''<span><font color="#9A1900">      legal range for guint16). We use the CLAMP macro from GLib for</font></span>''</span>
 +
<span>''<span><font color="#9A1900">      this. */</font></span>''</span>
 +
    red <span><font color="#990000"><nowiki>=</nowiki></font></span> <span>'''<span><font color="#000000">CLAMP</font></span>'''</span><span><font color="#990000">(</font></span>red<span><font color="#990000">,</font></span> <span><font color="#993399">0</font></span><span><font color="#990000">,</font></span> G_MAXUINT16<span><font color="#990000">);</font></span>
 +
    <span>'''<span><font color="#000000">g_print</font></span>'''</span><span><font color="#990000">(</font></span><span><font color="#FF0000">"after clamping = %d</font></span><span><font color="#CC33CC">\n</font></span><span><font color="#FF0000">"</font></span><span><font color="#990000">,</font></span> red<span><font color="#990000">);</font></span>
 +
    <span>''<span><font color="#9A1900">/* Update &amp; mark that at least this component changed. */</font></span>''</span>
 +
    color<span><font color="#990000">-&gt;</font></span>red <span><font color="#990000"><nowiki>=</nowiki></font></span> <span><font color="#990000">(</font></span>guint16<span><font color="#990000">)</font></span>red<span><font color="#990000"><nowiki>;</nowiki></font></span>
 +
    hasChanged <span><font color="#990000"><nowiki>=</nowiki></font></span> TRUE<span><font color="#990000"><nowiki>;</nowiki></font></span>
 +
  <span><font color="#FF0000">}</font></span>
 +
  <span>''<span><font color="#9A1900">/* Repeat the same logic for the green component. */</font></span>''</span>
 +
  <span>'''<span><font color="#0000FF">if</font></span>'''</span> <span><font color="#990000">(</font></span><span>'''<span><font color="#000000">confGetInt</font></span>'''</span><span><font color="#990000">(</font></span>gcClient<span><font color="#990000">,</font></span> GC_ROOT <span><font color="#FF0000">"green"</font></span><span><font color="#990000">,</font></span> <span><font color="#990000">&amp;</font></span>green<span><font color="#990000">))</font></span> <span><font color="#FF0000">{</font></span>
 +
    <span>'''<span><font color="#000000">g_print</font></span>'''</span><span><font color="#990000">(</font></span><span><font color="#FF0000">" got green = %d, "</font></span><span><font color="#990000">,</font></span> green<span><font color="#990000">);</font></span>
 +
    green <span><font color="#990000"><nowiki>=</nowiki></font></span> <span>'''<span><font color="#000000">CLAMP</font></span>'''</span><span><font color="#990000">(</font></span>green<span><font color="#990000">,</font></span> <span><font color="#993399">0</font></span><span><font color="#990000">,</font></span> G_MAXUINT16<span><font color="#990000">);</font></span>
 +
    <span>'''<span><font color="#000000">g_print</font></span>'''</span><span><font color="#990000">(</font></span><span><font color="#FF0000">"after clamping = %d</font></span><span><font color="#CC33CC">\n</font></span><span><font color="#FF0000">"</font></span><span><font color="#990000">,</font></span> green<span><font color="#990000">);</font></span>
 +
    color<span><font color="#990000">-&gt;</font></span>green <span><font color="#990000"><nowiki>=</nowiki></font></span> <span><font color="#990000">(</font></span>guint16<span><font color="#990000">)</font></span>green<span><font color="#990000"><nowiki>;</nowiki></font></span>
 +
    hasChanged <span><font color="#990000"><nowiki>=</nowiki></font></span> TRUE<span><font color="#990000"><nowiki>;</nowiki></font></span>
 +
  <span><font color="#FF0000">}</font></span>
 +
  <span>''<span><font color="#9A1900">/* Repeat the same logic for the last component (blue). */</font></span>''</span>
 +
  <span>'''<span><font color="#0000FF">if</font></span>'''</span> <span><font color="#990000">(</font></span><span>'''<span><font color="#000000">confGetInt</font></span>'''</span><span><font color="#990000">(</font></span>gcClient<span><font color="#990000">,</font></span> GC_ROOT <span><font color="#FF0000">"blue"</font></span><span><font color="#990000">,</font></span> <span><font color="#990000">&amp;</font></span>blue<span><font color="#990000">))</font></span> <span><font color="#FF0000">{</font></span>
 +
    <span>'''<span><font color="#000000">g_print</font></span>'''</span><span><font color="#990000">(</font></span><span><font color="#FF0000">" got blue = %d, "</font></span><span><font color="#990000">,</font></span> blue<span><font color="#990000">);</font></span>
 +
    blue <span><font color="#990000"><nowiki>=</nowiki></font></span> <span>'''<span><font color="#000000">CLAMP</font></span>'''</span><span><font color="#990000">(</font></span>blue<span><font color="#990000">,</font></span> <span><font color="#993399">0</font></span><span><font color="#990000">,</font></span> G_MAXUINT16<span><font color="#990000">);</font></span>
 +
    <span>'''<span><font color="#000000">g_print</font></span>'''</span><span><font color="#990000">(</font></span><span><font color="#FF0000">"after clamping = %d</font></span><span><font color="#CC33CC">\n</font></span><span><font color="#FF0000">"</font></span><span><font color="#990000">,</font></span> blue<span><font color="#990000">);</font></span>
 +
    color<span><font color="#990000">-&gt;</font></span>blue <span><font color="#990000"><nowiki>=</nowiki></font></span> <span><font color="#990000">(</font></span>guint16<span><font color="#990000">)</font></span>blue<span><font color="#990000"><nowiki>;</nowiki></font></span>
 +
    hasChanged <span><font color="#990000"><nowiki>=</nowiki></font></span> TRUE<span><font color="#990000"><nowiki>;</nowiki></font></span>
 +
  <span><font color="#FF0000">}</font></span>
 +
 +
  <span>''<span><font color="#9A1900">/* Release the client object (with GObject-unref). */</font></span>''</span>
 +
  <span>'''<span><font color="#000000">g_object_unref</font></span>'''</span><span><font color="#990000">(</font></span>gcClient<span><font color="#990000">);</font></span>
 +
  gcClient <span><font color="#990000"><nowiki>=</nowiki></font></span> NULL<span><font color="#990000"><nowiki>;</nowiki></font></span>
 +
 +
  <span>''<span><font color="#9A1900">/* Return status if the color was been changed by this routine. */</font></span>''</span>
 +
  <span>'''<span><font color="#0000FF">return</font></span>'''</span> hasChanged<span><font color="#990000"><nowiki>;</nowiki></font></span>
 +
<span><font color="#FF0000">}</font></span>
 +
 +
<span>''<span><font color="#9A1900">/**</font></span>''</span>
 +
<span>''<span><font color="#9A1900"> * MODIFIED</font></span>''</span>
 +
<span>''<span><font color="#9A1900"> *</font></span>''</span>
 +
<span>''<span><font color="#9A1900"> * Invoked when the user selects a color (or will cancel the dialog).</font></span>''</span>
 +
<span>''<span><font color="#9A1900"> *</font></span>''</span>
 +
<span>''<span><font color="#9A1900"> * Will also write the color to preferences (GConf) each time the</font></span>''</span>
 +
<span>''<span><font color="#9A1900"> * color changes. We'll compare whether it has really changed (to</font></span>''</span>
 +
<span>''<span><font color="#9A1900"> * avoid writing to GConf is nothing really changed).</font></span>''</span>
 +
<span>''<span><font color="#9A1900"> */</font></span>''</span>
 +
<span>'''<span><font color="#0000FF">static</font></span>'''</span> <span><font color="#009900">void</font></span> <span>'''<span><font color="#000000">cbActionColorChanged</font></span>'''</span><span><font color="#990000">(</font></span>HildonColorButton<span><font color="#990000"><nowiki>*</nowiki></font></span> colorButton<span><font color="#990000">,</font></span>
 +
                                  ApplicationState<span><font color="#990000"><nowiki>*</nowiki></font></span> app<span><font color="#990000">)</font></span> <span><font color="#FF0000">{</font></span>
 +
 +
  <span>''<span><font color="#9A1900">/* Local variables that we'll need to handle the change (NEW). */</font></span>''</span>
 +
  gboolean hasChanged <span><font color="#990000"><nowiki>=</nowiki></font></span> FALSE<span><font color="#990000"><nowiki>;</nowiki></font></span>
 +
  GdkColor newColor <span><font color="#990000"><nowiki>=</nowiki></font></span> <span><font color="#FF0000">{}</font></span><span><font color="#990000"><nowiki>;</nowiki></font></span>
 +
  GdkColor<span><font color="#990000"><nowiki>*</nowiki></font></span> curColor <span><font color="#990000"><nowiki>=</nowiki></font></span> NULL<span><font color="#990000"><nowiki>;</nowiki></font></span>
 +
 +
  <span>'''<span><font color="#000000">g_assert</font></span>'''</span><span><font color="#990000">(</font></span>app <span><font color="#990000"><nowiki>!=</nowiki></font></span> NULL<span><font color="#990000">);</font></span>
 +
 +
  <span>'''<span><font color="#000000">g_print</font></span>'''</span><span><font color="#990000">(</font></span><span><font color="#FF0000">"cbActionColorChanged invoked</font></span><span><font color="#CC33CC">\n</font></span><span><font color="#FF0000">"</font></span><span><font color="#990000">);</font></span>
 +
  <span>''<span><font color="#9A1900">/* Retrieve the new color from the color button (NEW). */</font></span>''</span>
 +
  <span>'''<span><font color="#000000">hildon_color_button_get_color</font></span>'''</span><span><font color="#990000">(</font></span>colorButton<span><font color="#990000">,</font></span> <span><font color="#990000">&amp;</font></span>newColor<span><font color="#990000">);</font></span>
 +
  <span>''<span><font color="#9A1900">/* Just an alias to save some typing (could also use</font></span>''</span>
 +
<span>''<span><font color="#9A1900">    app-&gt;currentColor) (NEW). */</font></span>''</span>
 +
  curColor <span><font color="#990000"><nowiki>=</nowiki></font></span> <span><font color="#990000">&amp;</font></span>app<span><font color="#990000">-&gt;</font></span>currentColor<span><font color="#990000"><nowiki>;</nowiki></font></span>
 +
 +
  <span>''<span><font color="#9A1900">/* Check whether the color really changed (NEW). */</font></span>''</span>
 +
  <span>'''<span><font color="#0000FF">if</font></span>'''</span> <span><font color="#990000">((</font></span>newColor<span><font color="#990000">.</font></span>red   <span><font color="#990000"><nowiki>!=</nowiki></font></span> curColor<span><font color="#990000">-&gt;</font></span>red<span><font color="#990000">)</font></span> <span><font color="#990000"><nowiki>||</nowiki></font></span>
 +
      <span><font color="#990000">(</font></span>newColor<span><font color="#990000">.</font></span>green <span><font color="#990000"><nowiki>!=</nowiki></font></span> curColor<span><font color="#990000">-&gt;</font></span>green<span><font color="#990000">)</font></span> <span><font color="#990000"><nowiki>||</nowiki></font></span>
 +
      <span><font color="#990000">(</font></span>newColor<span><font color="#990000">.</font></span>blue  <span><font color="#990000"><nowiki>!=</nowiki></font></span> curColor<span><font color="#990000">-&gt;</font></span>blue<span><font color="#990000">))</font></span> <span><font color="#FF0000">{</font></span>
 +
    hasChanged <span><font color="#990000"><nowiki>=</nowiki></font></span> TRUE<span><font color="#990000"><nowiki>;</nowiki></font></span>
 +
  <span><font color="#FF0000">}</font></span>
 +
  <span>'''<span><font color="#0000FF">if</font></span>'''</span> <span><font color="#990000">(!</font></span>hasChanged<span><font color="#990000">)</font></span> <span><font color="#FF0000">{</font></span>
 +
    <span>'''<span><font color="#000000">g_print</font></span>'''</span><span><font color="#990000">(</font></span><span><font color="#FF0000">" color not really changed</font></span><span><font color="#CC33CC">\n</font></span><span><font color="#FF0000">"</font></span><span><font color="#990000">);</font></span>
 +
    <span>'''<span><font color="#0000FF">return</font></span>'''</span><span><font color="#990000"><nowiki>;</nowiki></font></span>
 +
  <span><font color="#FF0000">}</font></span>
 +
  <span>''<span><font color="#9A1900">/* Color really changed, store to preferences (NEW). */</font></span>''</span>
 +
  <span>'''<span><font color="#000000">g_print</font></span>'''</span><span><font color="#990000">(</font></span><span><font color="#FF0000">" color changed, storing into preferences.. </font></span><span><font color="#CC33CC">\n</font></span><span><font color="#FF0000">"</font></span><span><font color="#990000">);</font></span>
 +
  <span>'''<span><font color="#000000">confStoreColor</font></span>'''</span><span><font color="#990000">(&amp;</font></span>newColor<span><font color="#990000">);</font></span>
 +
  <span>'''<span><font color="#000000">g_print</font></span>'''</span><span><font color="#990000">(</font></span><span><font color="#FF0000">" done.</font></span><span><font color="#CC33CC">\n</font></span><span><font color="#FF0000">"</font></span><span><font color="#990000">);</font></span>
 +
 +
  <span>''<span><font color="#9A1900">/* Update the changed color into the application state. */</font></span>''</span>
 +
  app<span><font color="#990000">-&gt;</font></span>currentColor <span><font color="#990000"><nowiki>=</nowiki></font></span> newColor<span><font color="#990000"><nowiki>;</nowiki></font></span>
 +
<span><font color="#FF0000">}</font></span>
 +
 +
  <span>''<span><font color="#9A1900">/*... Listing cut for brevity ...*/</font></span>''</span>
 +
 +
<span>''<span><font color="#9A1900">/**</font></span>''</span>
 +
<span>''<span><font color="#9A1900"> * MODIFIED</font></span>''</span>
 +
<span>''<span><font color="#9A1900"> *</font></span>''</span>
 +
<span>''<span><font color="#9A1900"> * The color of the color button will be loaded from the application</font></span>''</span>
 +
<span>''<span><font color="#9A1900"> * preferences (or keep the default if preferences have no setting).</font></span>''</span>
 +
<span>''<span><font color="#9A1900"> */</font></span>''</span>
 +
<span>'''<span><font color="#0000FF">static</font></span>'''</span> GtkWidget<span><font color="#990000"><nowiki>*</nowiki></font></span> <span>'''<span><font color="#000000">buildToolbar</font></span>'''</span><span><font color="#990000">(</font></span>ApplicationState<span><font color="#990000"><nowiki>*</nowiki></font></span> app<span><font color="#990000">)</font></span> <span><font color="#FF0000">{</font></span>
 +
 +
  GtkToolbar<span><font color="#990000"><nowiki>*</nowiki></font></span>  toolbar <span><font color="#990000"><nowiki>=</nowiki></font></span> NULL<span><font color="#990000"><nowiki>;</nowiki></font></span>
 +
  GtkToolItem<span><font color="#990000"><nowiki>*</nowiki></font></span> tbOpen <span><font color="#990000"><nowiki>=</nowiki></font></span> NULL<span><font color="#990000"><nowiki>;</nowiki></font></span>
 +
  GtkToolItem<span><font color="#990000"><nowiki>*</nowiki></font></span> tbSave <span><font color="#990000"><nowiki>=</nowiki></font></span> NULL<span><font color="#990000"><nowiki>;</nowiki></font></span>
 +
  GtkToolItem<span><font color="#990000"><nowiki>*</nowiki></font></span> tbSep <span><font color="#990000"><nowiki>=</nowiki></font></span> NULL<span><font color="#990000"><nowiki>;</nowiki></font></span>
 +
  GtkToolItem<span><font color="#990000"><nowiki>*</nowiki></font></span> tbFind <span><font color="#990000"><nowiki>=</nowiki></font></span> NULL<span><font color="#990000"><nowiki>;</nowiki></font></span>
 +
  GtkToolItem<span><font color="#990000"><nowiki>*</nowiki></font></span> tbColorButton <span><font color="#990000"><nowiki>=</nowiki></font></span> NULL<span><font color="#990000"><nowiki>;</nowiki></font></span>
 +
  GtkWidget<span><font color="#990000"><nowiki>*</nowiki></font></span>  colorButton <span><font color="#990000"><nowiki>=</nowiki></font></span> NULL<span><font color="#990000"><nowiki>;</nowiki></font></span>
 +
 +
  <span>'''<span><font color="#000000">g_assert</font></span>'''</span><span><font color="#990000">(</font></span>app <span><font color="#990000"><nowiki>!=</nowiki></font></span> NULL<span><font color="#990000">);</font></span>
 +
 +
  tbOpen <span><font color="#990000"><nowiki>=</nowiki></font></span> <span>'''<span><font color="#000000">gtk_tool_button_new_from_stock</font></span>'''</span><span><font color="#990000">(</font></span>GTK_STOCK_OPEN<span><font color="#990000">);</font></span>
 +
  tbSave <span><font color="#990000"><nowiki>=</nowiki></font></span> <span>'''<span><font color="#000000">gtk_tool_button_new_from_stock</font></span>'''</span><span><font color="#990000">(</font></span>GTK_STOCK_SAVE<span><font color="#990000">);</font></span>
 +
  tbSep  <span><font color="#990000"><nowiki>=</nowiki></font></span> <span>'''<span><font color="#000000">gtk_separator_tool_item_new</font></span>'''</span><span><font color="#990000">();</font></span>
 +
  tbFind <span><font color="#990000"><nowiki>=</nowiki></font></span> <span>'''<span><font color="#000000">gtk_tool_button_new_from_stock</font></span>'''</span><span><font color="#990000">(</font></span>GTK_STOCK_FIND<span><font color="#990000">);</font></span>
 +
 +
  tbColorButton <span><font color="#990000"><nowiki>=</nowiki></font></span> <span>'''<span><font color="#000000">gtk_tool_item_new</font></span>'''</span><span><font color="#990000">();</font></span>
 +
  colorButton <span><font color="#990000"><nowiki>=</nowiki></font></span> <span>'''<span><font color="#000000">hildon_color_button_new</font></span>'''</span><span><font color="#990000">();</font></span>
 +
  <span>''<span><font color="#9A1900">/* Copy the color from the color button into the application state.</font></span>''</span>
 +
<span>''<span><font color="#9A1900">    This is done to detect whether the color in preferences matches</font></span>''</span>
 +
<span>''<span><font color="#9A1900">    the default color or not (NEW). */</font></span>''</span>
 +
  <span>'''<span><font color="#000000">hildon_color_button_get_color</font></span>'''</span><span><font color="#990000">(</font></span><span>'''<span><font color="#000000">HILDON_COLOR_BUTTON</font></span>'''</span><span><font color="#990000">(</font></span>colorButton<span><font color="#990000">),</font></span>
 +
                                <span><font color="#990000">&amp;</font></span>app<span><font color="#990000">-&gt;</font></span>currentColor<span><font color="#990000">);</font></span>
 +
  <span>''<span><font color="#9A1900">/* Load preferences and change the color if necessary. */</font></span>''</span>
 +
  <span>'''<span><font color="#000000">g_print</font></span>'''</span><span><font color="#990000">(</font></span><span><font color="#FF0000">"buildToolbar: loading color pref.</font></span><span><font color="#CC33CC">\n</font></span><span><font color="#FF0000">"</font></span><span><font color="#990000">);</font></span>
 +
  <span>'''<span><font color="#0000FF">if</font></span>'''</span> <span><font color="#990000">(</font></span><span>'''<span><font color="#000000">confLoadCurrentColor</font></span>'''</span><span><font color="#990000">(&amp;</font></span>app<span><font color="#990000">-&gt;</font></span>currentColor<span><font color="#990000">))</font></span> <span><font color="#FF0000">{</font></span>
 +
    <span>'''<span><font color="#000000">g_print</font></span>'''</span><span><font color="#990000">(</font></span><span><font color="#FF0000">" color not same as default one</font></span><span><font color="#CC33CC">\n</font></span><span><font color="#FF0000">"</font></span><span><font color="#990000">);</font></span>
 +
    <span>'''<span><font color="#000000">hildon_color_button_set_color</font></span>'''</span><span><font color="#990000">(</font></span><span>'''<span><font color="#000000">HILDON_COLOR_BUTTON</font></span>'''</span><span><font color="#990000">(</font></span>colorButton<span><font color="#990000">),</font></span>
 +
                                  <span><font color="#990000">&amp;</font></span>app<span><font color="#990000">-&gt;</font></span>currentColor<span><font color="#990000">);</font></span>
 +
  <span><font color="#FF0000">}</font></span> <span>'''<span><font color="#0000FF">else</font></span>'''</span> <span><font color="#FF0000">{</font></span>
 +
    <span>'''<span><font color="#000000">g_print</font></span>'''</span><span><font color="#990000">(</font></span><span><font color="#FF0000">" loaded color same as default</font></span><span><font color="#CC33CC">\n</font></span><span><font color="#FF0000">"</font></span><span><font color="#990000">);</font></span>
 +
  <span><font color="#FF0000">}</font></span>
 +
  <span>'''<span><font color="#000000">gtk_container_add</font></span>'''</span><span><font color="#990000">(</font></span><span>'''<span><font color="#000000">GTK_CONTAINER</font></span>'''</span><span><font color="#990000">(</font></span>tbColorButton<span><font color="#990000">),</font></span> colorButton<span><font color="#990000">);</font></span>
 +
 +
  <span>''<span><font color="#9A1900">/*... Listing cut for brevity ...*/</font></span>''</span>
 +
 +
<span><font color="#FF0000">}</font></span></tt>
-
  /* Open a connection to gconfd-2 (via D-Bus in maemo). The GConf
+
Since the graphical appearance of the program does not change (except that the ColorButton will display the correct initial color), a look will be taken at the stdout display of the program.
-
    API doesn't say whether this function can ever return NULL or
+
-
    how it will behave in error conditions. */
+
-
  gcClient = gconf_client_get_default();
+
-
  /* We make sure that it's a valid GConf-client object. */
+
-
  g_assert(GCONF_IS_CLIENT(gcClient));
+
-
  /* Store the values. */
+
[sbox-DIABLO_X86: ~/appdev] &gt; run-standalone.sh ./hildon_helloworld-9
-
  if (!gconf_client_set_int(gcClient, GC_ROOT "red", color->red,
+
buildToolbar: loading color pref.
-
                            NULL)) {
+
confLoadCurrentColor: invoked
-
    g_warning(" failed to set %s/red to %d\n", GC_ROOT, color->red);
+
hildon_helloworld-9[19840]: GLIB WARNING ** default -  
-
   }
+
   confGetInt: key /apps/Maemo/hildon_hello/red not found
-
  if (!gconf_client_set_int(gcClient, GC_ROOT "green", color->green,
+
hildon_helloworld-9[19840]: GLIB WARNING ** default -  
-
                            NULL)) {
+
  confGetInt: key /apps/Maemo/hildon_hello/green not found
-
    g_warning(" failed to set %s/green to %d\n", GC_ROOT,
+
hildon_helloworld-9[19840]: GLIB WARNING ** default -  
-
              color->green);
+
   confGetInt: key /apps/Maemo/hildon_hello/blue not found
-
   }
+
   loaded color same as default
-
   if (!gconf_client_set_int(gcClient, GC_ROOT "blue", color->blue,
+
main: calling gtk_main
-
                            NULL)) {
+
cbActionMainToolbarToggle invoked
-
    g_warning(" failed to set %s/blue to %d\n", GC_ROOT,
+
cbActionColorChanged invoked
-
              color->blue);
+
  color changed, storing into preferences..
-
   }
+
confStoreColor: invoked
 +
   done.
 +
main: returned from gtk_main and exiting with success
-
  /* Release the GConf client object (with GObject-unref). */
 
-
  g_object_unref(gcClient);
 
-
  gcClient = NULL;
 
-
}
 
-
 
-
/**
 
-
* NEW
 
-
*
 
-
* A utility function to get an integer but also return the status
 
-
* whether the requested key existed or not.
 
-
*
 
-
* NOTE:
 
-
*  It's also possible to use gconf_client_get_int(), but it's not
 
-
*  possible to then know whether they key existed or not, because
 
-
*  the function will return 0 if the key doesn't exist (and if the
 
-
*  value is 0, how could you tell these two conditions apart?).
 
-
*
 
-
* Parameters:
 
-
* - GConfClient: the client object to use
 
-
* - const gchar*: the key
 
-
* - gint*: the address to store the integer to if the key exists
 
-
*
 
-
* Returns:
 
-
* - TRUE: if integer has been updated with a value from GConf.
 
-
*  FALSE: there was no such key or it wasn't an integer.
 
-
*/
 
-
static gboolean confGetInt(GConfClient* gcClient, const gchar* key,
 
-
                          gint* number) {
 
-
 
-
  /* This will hold the type/value pair at some point. */
 
-
  GConfValue* val = NULL;
 
-
  /* Return flag (tells the caller whether this function wrote behind
 
-
    the 'number' pointer or not). */
 
-
  gboolean hasChanged = FALSE;
 
-
 
-
  /* Try to get the type/value from the GConf DB.
 
-
    NOTE:
 
-
      We're using a version of the getter that will not return any
 
-
      defaults (if a schema would specify one). Instead, it will
 
-
      return the value if one has been set (or NULL).
 
-
 
-
    We're not really interested in errors as this will return a NULL
 
-
    in case of missing keys or errors and that is quite enough for
 
-
    us. */
 
-
  val = gconf_client_get_without_default(gcClient, key, NULL);
 
-
  if (val == NULL) {
 
-
    /* Key wasn't found, no need to touch anything. */
 
-
    g_warning("confGetInt: key %s not found\n", key);
 
-
    return FALSE;
 
-
  }
 
-
 
-
  /* Check whether the value stored behind the key is an integer. If
 
-
    it is not, we issue a warning, but return normally. */
 
-
  if (val->type == GCONF_VALUE_INT) {
 
-
    /* It's an integer, get it and store. */
 
-
    *number = gconf_value_get_int(val);
 
-
    /* Mark that we've changed the integer behind 'number'. */
 
-
    hasChanged = TRUE;
 
-
  } else {
 
-
    g_warning("confGetInt: key %s is not an integer\n", key);
 
-
  }
 
-
 
-
  /* Free the type/value-pair. */
 
-
  gconf_value_free(val);
 
-
  val = NULL;
 
-
 
-
  return hasChanged;
 
-
}
 
-
 
-
/**
 
-
* NEW
 
-
*
 
-
* Utility function to change the given color into the one that is
 
-
* specified in application preferences.
 
-
*
 
-
* If some key is missing, that channel is left untouched. The
 
-
* function also checks for proper values for the channels so that
 
-
* invalid values are not accepted (guint16 range of GdkColor).
 
-
*
 
-
* Parameters:
 
-
* - GdkColor*: the color structure to modify if changed from prefs.
 
-
*
 
-
* Returns:
 
-
* - TRUE if the color was been changed by this routine.
 
-
*  FALSE if the color wasn't changed (there was an error or the
 
-
*  color was already exactly the same as in the preferences).
 
-
*/
 
-
static gboolean confLoadCurrentColor(GdkColor* color) {
 
-
 
-
  GConfClient* gcClient = NULL;
 
-
  /* Temporary holders for the pref values. */
 
-
  gint red = -1;
 
-
  gint green = -1;
 
-
  gint blue = -1;
 
-
  /* Temp variable to hold whether the color has changed. */
 
-
  gboolean hasChanged = FALSE;
 
-
 
-
  g_assert(color);
 
-
 
-
  g_print("confLoadCurrentColor: invoked\n");
 
-
 
-
  /* Open a connection to gconfd-2 (via d-bus). */
 
-
  gcClient = gconf_client_get_default();
 
-
  /* Make sure that it's a valid GConf-client object. */
 
-
  g_assert(GCONF_IS_CLIENT(gcClient));
 
-
 
-
  if (confGetInt(gcClient, GC_ROOT "red", &red)) {
 
-
    /* We got the value successfully, now clamp it. */
 
-
    g_print(" got red = %d, ", red);
 
-
    /* We got a value, so let's limit it between 0 and 65535 (the
 
-
      legal range for guint16). We use the CLAMP macro from GLib for
 
-
      this. */
 
-
    red = CLAMP(red, 0, G_MAXUINT16);
 
-
    g_print("after clamping = %d\n", red);
 
-
    /* Update & mark that at least this component changed. */
 
-
    color->red = (guint16)red;
 
-
    hasChanged = TRUE;
 
-
  }
 
-
  /* Repeat the same logic for the green component. */
 
-
  if (confGetInt(gcClient, GC_ROOT "green", &green)) {
 
-
    g_print(" got green = %d, ", green);
 
-
    green = CLAMP(green, 0, G_MAXUINT16);
 
-
    g_print("after clamping = %d\n", green);
 
-
    color->green = (guint16)green;
 
-
    hasChanged = TRUE;
 
-
  }
 
-
  /* Repeat the same logic for the last component (blue). */
 
-
  if (confGetInt(gcClient, GC_ROOT "blue", &blue)) {
 
-
    g_print(" got blue = %d, ", blue);
 
-
    blue = CLAMP(blue, 0, G_MAXUINT16);
 
-
    g_print("after clamping = %d\n", blue);
 
-
    color->blue = (guint16)blue;
 
-
    hasChanged = TRUE;
 
-
  }
 
-
 
-
  /* Release the client object (with GObject-unref). */
 
-
  g_object_unref(gcClient);
 
-
  gcClient = NULL;
 
-
 
-
  /* Return status if the color was been changed by this routine. */
 
-
  return hasChanged;
 
-
}
 
-
 
-
/**
 
-
* MODIFIED
 
-
*
 
-
* Invoked when the user selects a color (or will cancel the dialog).
 
-
*
 
-
* Will also write the color to preferences (GConf) each time the
 
-
* color changes. We'll compare whether it has really changed (to
 
-
* avoid writing to GConf is nothing really changed).
 
-
*/
 
-
static void cbActionColorChanged(HildonColorButton* colorButton,
 
-
                                ApplicationState* app) {
 
-
 
-
  /* Local variables that we'll need to handle the change (NEW). */
 
-
  gboolean hasChanged = FALSE;
 
-
  GdkColor newColor = {};
 
-
  GdkColor* curColor = NULL;
 
-
 
-
  g_assert(app != NULL);
 
-
 
-
  g_print("cbActionColorChanged invoked\n");
 
-
  /* Retrieve the new color from the color button (NEW). */
 
-
  hildon_color_button_get_color(colorButton, &newColor);
 
-
  /* Just an alias to save some typing (could also use
 
-
    app->currentColor) (NEW). */
 
-
  curColor = &app->currentColor;
 
-
 
-
  /* Check whether the color really changed (NEW). */
 
-
  if ((newColor.red  != curColor->red) ||
 
-
      (newColor.green != curColor->green) ||
 
-
      (newColor.blue  != curColor->blue)) {
 
-
    hasChanged = TRUE;
 
-
  }
 
-
  if (!hasChanged) {
 
-
    g_print(" color not really changed\n");
 
-
    return;
 
-
  }
 
-
  /* Color really changed, store to preferences (NEW). */
 
-
  g_print(" color changed, storing into preferences.. \n");
 
-
  confStoreColor(&newColor);
 
-
  g_print(" done.\n");
 
-
 
-
  /* Update the changed color into the application state. */
 
-
  app->currentColor = newColor;
 
-
}
 
-
 
-
  /*... Listing cut for brevity ...*/
 
-
 
-
/**
 
-
* MODIFIED
 
-
*
 
-
* The color of the color button will be loaded from the application
 
-
* preferences (or keep the default if preferences have no setting).
 
-
*/
 
-
static GtkWidget* buildToolbar(ApplicationState* app) {
 
-
 
-
  GtkToolbar*  toolbar = NULL;
 
-
  GtkToolItem* tbOpen = NULL;
 
-
  GtkToolItem* tbSave = NULL;
 
-
  GtkToolItem* tbSep = NULL;
 
-
  GtkToolItem* tbFind = NULL;
 
-
  GtkToolItem* tbColorButton = NULL;
 
-
  GtkWidget*  colorButton = NULL;
 
-
 
-
  g_assert(app != NULL);
 
-
 
-
  tbOpen = gtk_tool_button_new_from_stock(GTK_STOCK_OPEN);
 
-
  tbSave = gtk_tool_button_new_from_stock(GTK_STOCK_SAVE);
 
-
  tbSep  = gtk_separator_tool_item_new();
 
-
  tbFind = gtk_tool_button_new_from_stock(GTK_STOCK_FIND);
 
-
 
-
  tbColorButton = gtk_tool_item_new();
 
-
  colorButton = hildon_color_button_new();
 
-
  /* Copy the color from the color button into the application state.
 
-
    This is done to detect whether the color in preferences matches
 
-
    the default color or not (NEW). */
 
-
  hildon_color_button_get_color(HILDON_COLOR_BUTTON(colorButton),
 
-
                                &app->currentColor);
 
-
  /* Load preferences and change the color if necessary. */
 
-
  g_print("buildToolbar: loading color pref.\n");
 
-
  if (confLoadCurrentColor(&app->currentColor)) {
 
-
    g_print(" color not same as default one\n");
 
-
    hildon_color_button_set_color(HILDON_COLOR_BUTTON(colorButton),
 
-
                                  &app->currentColor);
 
-
  } else {
 
-
    g_print(" loaded color same as default\n");
 
-
  }
 
-
  gtk_container_add(GTK_CONTAINER(tbColorButton), colorButton);
 
-
 
-
  /*... Listing cut for brevity ...*/
 
-
 
-
}
 
-
</source>
 
-
 
-
Since the graphical appearance of the program does not change (except that the <code>ColorButton</code> will display the correct initial color), a look will be taken at the stdout display of the program.
 
-
 
-
<pre>
 
-
[sbox-DIABLO_X86: ~/appdev] &gt; run-standalone.sh ./hildon_helloworld-9
 
-
buildToolbar: loading color pref.
 
-
confLoadCurrentColor: invoked
 
-
hildon_helloworld-9[19840]: GLIB WARNING ** default -
 
-
confGetInt: key /apps/Maemo/hildon_hello/red not found
 
-
hildon_helloworld-9[19840]: GLIB WARNING ** default -
 
-
confGetInt: key /apps/Maemo/hildon_hello/green not found
 
-
hildon_helloworld-9[19840]: GLIB WARNING ** default -
 
-
confGetInt: key /apps/Maemo/hildon_hello/blue not found
 
-
loaded color same as default
 
-
main: calling gtk_main
 
-
cbActionMainToolbarToggle invoked
 
-
cbActionColorChanged invoked
 
-
color changed, storing into preferences..
 
-
confStoreColor: invoked
 
-
done.
 
-
main: returned from gtk_main and exiting with success
 
-
</pre>
 
When running the program for the first time, warnings about the missing keys can be expected (since the values were not present in GConf).
When running the program for the first time, warnings about the missing keys can be expected (since the values were not present in GConf).
Line 465: Line 465:
Run the program again and exit:
Run the program again and exit:
-
<pre>
+
[sbox-DIABLO_X86: ~/appdev] &gt; run-standalone.sh ./hildon_helloworld-9
-
[sbox-DIABLO_X86: ~/appdev] &gt; run-standalone.sh ./hildon_helloworld-9
+
buildToolbar: loading color pref.
-
buildToolbar: loading color pref.
+
confLoadCurrentColor: invoked
-
confLoadCurrentColor: invoked
+
  got red = 65535, after clamping = 65535
-
got red = 65535, after clamping = 65535
+
  got green = 65535, after clamping = 65535
-
got green = 65535, after clamping = 65535
+
  got blue = 0, after clamping = 0
-
got blue = 0, after clamping = 0
+
  color not same as default one
-
color not same as default one
+
main: calling gtk_main
-
main: calling gtk_main
+
main: returned from gtk_main and exiting with success
-
main: returned from gtk_main and exiting with success
+
 
-
</pre>
+
The next step is to remove one key (red), and run the program again (this is to test and verify that the logic works):
The next step is to remove one key (red), and run the program again (this is to test and verify that the logic works):
-
 
+
-
<pre>
+
[sbox-DIABLO_X86: ~/appdev] &gt; run-standalone.sh gconftool-2  \
-
[sbox-DIABLO_X86: ~/appdev] &gt; run-standalone.sh gconftool-2  \
+
  --unset /apps/Maemo/hildon_hello/red
-
--unset /apps/Maemo/hildon_hello/red
+
[sbox-DIABLO_X86: ~/appdev] &gt; run-standalone.sh gconftool-2  \
-
[sbox-DIABLO_X86: ~/appdev] &gt; run-standalone.sh gconftool-2  \
+
  -R /apps/Maemo/hildon_hello
-
-R /apps/Maemo/hildon_hello
+
  green = 65535
-
green = 65535
+
  blue = 0
-
blue = 0
+
[sbox-DIABLO_X86: ~/appdev] &gt; run-standalone.sh ./hildon_helloworld-9
-
[sbox-DIABLO_X86: ~/appdev] &gt; run-standalone.sh ./hildon_helloworld-9
+
buildToolbar: loading color pref.
-
buildToolbar: loading color pref.
+
confLoadCurrentColor: invoked
-
confLoadCurrentColor: invoked
+
hildon_helloworld-9[19924]: GLIB WARNING ** default -
-
hildon_helloworld-9[19924]: GLIB WARNING ** default -
+
  confGetInt: key /apps/Maemo/hildon_hello/red not found
-
confGetInt: key /apps/Maemo/hildon_hello/red not found
+
  got green = 65535, after clamping = 65535
-
got green = 65535, after clamping = 65535
+
  got blue = 0, after clamping = 0
-
got blue = 0, after clamping = 0
+
  color not same as default one
-
color not same as default one
+
main: calling gtk_main
-
main: calling gtk_main
+
main: returned from gtk_main and exiting with success
-
main: returned from gtk_main and exiting with success
+
-
</pre>
+
==  Asynchronous GConf ==
==  Asynchronous GConf ==
Line 506: Line 503:
When the configuration needs for the service are simple, and reacting to configuration changes in "realtime" is desired, it is advisable to use GConf. Also, people tend to use GConf when they are too lazy to write their own configuration file parsers (although there is a simple one in GLib), or too lazy to write the GUI part to change the settings. This example program will simulate the first case, and react to changes in a subset of GConf configuration name space when the changes happen.
When the configuration needs for the service are simple, and reacting to configuration changes in "realtime" is desired, it is advisable to use GConf. Also, people tend to use GConf when they are too lazy to write their own configuration file parsers (although there is a simple one in GLib), or too lazy to write the GUI part to change the settings. This example program will simulate the first case, and react to changes in a subset of GConf configuration name space when the changes happen.
-
The application will be interested in two string values; one to set the device to use for communication (connection), and the other to set the communication parameters for the device (connectionparams). Since this example will be concentrating on just the change notifications, the program logic is simplified by omitting the proper set-up code in the program. This means that it is necessary to set up some values to the GConf keys prior to running the program. For this, <code>gconftool-2</code> will be used, and a target has been prepared in the '''Makefile''' just for this (see section [[Documentation/Maemo 5 Developer Guide/GNU Build System#GNU Make and Makefiles|GNU Make and Makefiles]] if necessary): gconf-listener/Makefile
+
The application will be interested in two string values; one to set the device to use for communication (connection), and the other to set the communication parameters for the device (connectionparams). Since this example will be concentrating on just the change notifications, the program logic is simplified by omitting the proper set-up code in the program. This means that it is necessary to set up some values to the GConf keys prior to running the program. For this, gconftool-2 will be used, and a target has been prepared in the '''Makefile''' just for this (see section [http://wiki.maemo.org/Documentation/Maemo_5_Developer_Guide/GNU_Build_System#GNU_Make_and_Makefiles GNU Make and Makefiles] if necessary): gconf-listener/Makefile
-
<source lang="make">
+
<tt><span>''<span><font color="#9A1900"><nowiki># Define a variable for this so that the GConf root may be changed</nowiki></font></span>''</span>
-
# Define a variable for this so that the GConf root may be changed
+
gconf_root <span><font color="#990000"><nowiki>:=</nowiki></font></span> /apps/Maemo/platdev_ex
-
gconf_root := /apps/Maemo/platdev_ex
+
-
 
+
<span>''<span><font color="#9A1900"><nowiki># ... Listing cut for brevity ...</nowiki></font></span>''</span>
-
# ... Listing cut for brevity ...
+
 +
<span>''<span><font color="#9A1900"><nowiki># This will setup the keys into default values.</nowiki></font></span>''</span>
 +
<span>''<span><font color="#9A1900"><nowiki># It will first do a clear to remove any existing keys.</nowiki></font></span>''</span>
 +
primekeys<span><font color="#990000"><nowiki>:</nowiki></font></span> clearkeys
 +
        gconftool-<span><font color="#993399">2</font></span> -set -type string <span><font color="#990000">\</font></span>
 +
                    <span><font color="#009900">$(gconf_root)</font></span>/connection btcomm0
 +
        gconftool-<span><font color="#993399">2</font></span> -set -type string <span><font color="#990000">\</font></span>
 +
                    <span><font color="#009900">$(gconf_root)</font></span>/connectionparams <span><font color="#993399">9600</font></span><span><font color="#990000">,</font></span><span><font color="#993399">8</font></span><span><font color="#990000">,</font></span>N<span><font color="#990000">,</font></span><span><font color="#993399">1</font></span>
 +
 +
<span>''<span><font color="#9A1900"><nowiki># Remove all application keys</nowiki></font></span>''</span>
 +
clearkeys<span><font color="#990000"><nowiki>:</nowiki></font></span>
 +
        @gconftool-<span><font color="#993399">2</font></span> -recursive-unset <span><font color="#009900">$(gconf_root)</font></span>
 +
 +
<span>''<span><font color="#9A1900"><nowiki># Dump all application keys</nowiki></font></span>''</span>
 +
dumpkeys<span><font color="#990000"><nowiki>:</nowiki></font></span>
 +
        @echo Keys under <span><font color="#009900">$(gconf_root)</font></span><span><font color="#990000"><nowiki>:</nowiki></font></span>
 +
        @gconftool-<span><font color="#993399">2</font></span> -recursive-list <span><font color="#009900">$(gconf_root)</font></span>
 +
</tt>
-
# This will setup the keys into default values.
+
The next step is to prepare the keyspace by running the primekeys target, and to verify that it succeeds by running the dumpkeys target:
-
# It will first do a clear to remove any existing keys.
+
-
primekeys: clearkeys
+
-
        gconftool-2 -set -type string \
+
-
                    $(gconf_root)/connection btcomm0
+
-
        gconftool-2 -set -type string \
+
-
                    $(gconf_root)/connectionparams 9600,8,N,1
+
-
# Remove all application keys
+
  [sbox-DIABLO_X86: ~/gconf-listener] &gt; make primekeys
-
clearkeys:
+
-
        @gconftool-2 -recursive-unset $(gconf_root)
+
-
 
+
-
# Dump all application keys
+
-
dumpkeys:
+
-
        @echo Keys under $(gconf_root):
+
-
        @gconftool-2 -recursive-list $(gconf_root)
+
-
</source>
+
-
 
+
-
The next step is to prepare the keyspace by running the <code>primekeys</code> target, and to verify that it succeeds by running the <code>dumpkeys</code> target:
+
-
 
+
-
<pre>
+
-
  [sbox-DIABLO_X86: ~/gconf-listener] > make primekeys
+
  gconftool-2 --set --type string \
  gconftool-2 --set --type string \
             /apps/Maemo/platdev_ex/connection btcomm0
             /apps/Maemo/platdev_ex/connection btcomm0
  gconftool-2 --set --type string \
  gconftool-2 --set --type string \
             /apps/Maemo/platdev_ex/connectionparams 9600,8,N,1
             /apps/Maemo/platdev_ex/connectionparams 9600,8,N,1
-
  [sbox-DIABLO_X86: ~/gconf-listener] > make dumpkeys
+
  [sbox-DIABLO_X86: ~/gconf-listener] &gt; make dumpkeys
  Keys under /apps/Maemo/platdev_ex:
  Keys under /apps/Maemo/platdev_ex:
   connectionparams = 9600,8,N,1
   connectionparams = 9600,8,N,1
   connection = btcomm0
   connection = btcomm0
-
</pre>
 
===  Implementing Notifications on Changes in GConf ===
===  Implementing Notifications on Changes in GConf ===
Line 550: Line 544:
The first step here is to take care of the necessary header information. The GConf namespace settings have been all implemented using cpp macros, so that one can easily change the prefix of the name space if required later on. gconf-listener/gconf-key-watch.c
The first step here is to take care of the necessary header information. The GConf namespace settings have been all implemented using cpp macros, so that one can easily change the prefix of the name space if required later on. gconf-listener/gconf-key-watch.c
-
<source lang="c">
+
<tt><span>'''<span><font color="#000080"><nowiki>#include</nowiki></font></span>'''</span> <span><font color="#FF0000">&lt;glib.h&gt;</font></span>
-
#include <glib.h>
+
<span>'''<span><font color="#000080"><nowiki>#include</nowiki></font></span>'''</span> <span><font color="#FF0000">&lt;gconf/gconf-client.h&gt;</font></span>
-
#include <gconf/gconf-client.h>
+
<span>'''<span><font color="#000080"><nowiki>#include</nowiki></font></span>'''</span> <span><font color="#FF0000">&lt;string.h&gt;</font></span> <span>''<span><font color="#9A1900">/* strcmp */</font></span>''</span>
-
#include <string.h> /* strcmp */
+
-
 
+
<span>''<span><font color="#9A1900">/* As per maemo Coding Style and Guidelines document, we use the</font></span>''</span>
-
/* As per maemo Coding Style and Guidelines document, we use the
+
<span>''<span><font color="#9A1900">  /apps/Maemo/ -prefix.</font></span>''</span>
-
  /apps/Maemo/ -prefix.
+
<span>''<span><font color="#9A1900">  NOTE: There is no central registry (as of this moment) that you</font></span>''</span>
-
  NOTE: There is no central registry (as of this moment) that you
+
<span>''<span><font color="#9A1900">        could check that your application name doesn't collide with</font></span>''</span>
-
        could check that your application name doesn't collide with
+
<span>''<span><font color="#9A1900">        other application names, so caution is advised! */</font></span>''</span>
-
        other application names, so caution is advised! */
+
<span>'''<span><font color="#000080"><nowiki>#define</nowiki></font></span>'''</span> SERVICE_GCONF_ROOT <span><font color="#FF0000">"/apps/Maemo/platdev_ex"</font></span>
-
#define SERVICE_GCONF_ROOT "/apps/Maemo/platdev_ex"
+
-
 
+
<span>''<span><font color="#9A1900">/* We define the names of the keys symbolically so that we may change</font></span>''</span>
-
/* We define the names of the keys symbolically so that we may change
+
<span>''<span><font color="#9A1900">  them later if necessary, and so that the GConf "root directory" for</font></span>''</span>
-
  them later if necessary, and so that the GConf "root directory" for
+
<span>''<span><font color="#9A1900">  our application will be automatically prefixed to the paths. */</font></span>''</span>
-
  our application will be automatically prefixed to the paths. */
+
<span>'''<span><font color="#000080"><nowiki>#define</nowiki></font></span>'''</span> SERVICE_KEY_CONNECTION <span><font color="#990000">\</font></span>
-
#define SERVICE_KEY_CONNECTION \
+
        SERVICE_GCONF_ROOT <span><font color="#FF0000">"/connection"</font></span>
-
        SERVICE_GCONF_ROOT "/connection"
+
<span>'''<span><font color="#000080"><nowiki>#define</nowiki></font></span>'''</span> SERVICE_KEY_CONNECTIONPARAMS <span><font color="#990000">\</font></span>
-
#define SERVICE_KEY_CONNECTIONPARAMS \
+
        SERVICE_GCONF_ROOT <span><font color="#FF0000">"/connectionparams"</font></span></tt>
-
        SERVICE_GCONF_ROOT "/connectionparams"
+
-
</source>
+
The main starts innocently enough, by creating a GConf client object (that encapsulates the connection to the GConf daemon), and then displays the two values on output: gconf-listener/gconf-key-watch.c
The main starts innocently enough, by creating a GConf client object (that encapsulates the connection to the GConf daemon), and then displays the two values on output: gconf-listener/gconf-key-watch.c
-
<source lang="c">
+
<tt><span><font color="#009900">int</font></span> <span>'''<span><font color="#000000">main</font></span>'''</span> <span><font color="#990000">(</font></span><span><font color="#009900">int</font></span> argc<span><font color="#990000">,</font></span> <span><font color="#009900">char</font></span><span><font color="#990000"><nowiki>**</nowiki></font></span> argv<span><font color="#990000">)</font></span> <span><font color="#FF0000">{</font></span>
-
int main (int argc, char** argv) {
+
  <span>''<span><font color="#9A1900">/* Will hold reference to the GConfClient object. */</font></span>''</span>
-
  /* Will hold reference to the GConfClient object. */
+
  GConfClient<span><font color="#990000"><nowiki>*</nowiki></font></span> client <span><font color="#990000"><nowiki>=</nowiki></font></span> NULL<span><font color="#990000"><nowiki>;</nowiki></font></span>
-
  GConfClient* client = NULL;
+
  <span>''<span><font color="#9A1900">/* Initialize this to NULL so that we'll know whether an error</font></span>''</span>
-
  /* Initialize this to NULL so that we'll know whether an error
+
<span>''<span><font color="#9A1900">    occurred or not (and we don't have an existing GError object</font></span>''</span>
-
    occurred or not (and we don't have an existing GError object
+
<span>''<span><font color="#9A1900">    anyway at this point). */</font></span>''</span>
-
    anyway at this point). */
+
  GError<span><font color="#990000"><nowiki>*</nowiki></font></span> error <span><font color="#990000"><nowiki>=</nowiki></font></span> NULL<span><font color="#990000"><nowiki>;</nowiki></font></span>
-
  GError* error = NULL;
+
  <span>''<span><font color="#9A1900">/* This will hold a reference to the mainloop object. */</font></span>''</span>
-
  /* This will hold a reference to the mainloop object. */
+
  GMainLoop<span><font color="#990000"><nowiki>*</nowiki></font></span> mainloop <span><font color="#990000"><nowiki>=</nowiki></font></span> NULL<span><font color="#990000"><nowiki>;</nowiki></font></span>
-
  GMainLoop* mainloop = NULL;
+
 +
  <span>'''<span><font color="#000000">g_print</font></span>'''</span><span><font color="#990000">(</font></span>PROGNAME <span><font color="#FF0000">":main Starting.</font></span><span><font color="#CC33CC">\n</font></span><span><font color="#FF0000">"</font></span><span><font color="#990000">);</font></span>
 +
 +
  <span>''<span><font color="#9A1900">/* Must be called to initialize GType system. The API reference for</font></span>''</span>
 +
<span>''<span><font color="#9A1900">    gconf_client_get_default() insists.</font></span>''</span>
 +
<span>''<span><font color="#9A1900">    NOTE: Using gconf_init() is deprecated! */</font></span>''</span>
 +
  <span>'''<span><font color="#000000">g_type_init</font></span>'''</span><span><font color="#990000">();</font></span>
 +
 +
  <span>''<span><font color="#9A1900">/* Create a new mainloop structure that we'll use. Use default</font></span>''</span>
 +
<span>''<span><font color="#9A1900">    context (NULL) and set the 'running' flag to FALSE. */</font></span>''</span>
 +
  mainloop <span><font color="#990000"><nowiki>=</nowiki></font></span> <span>'''<span><font color="#000000">g_main_loop_new</font></span>'''</span><span><font color="#990000">(</font></span>NULL<span><font color="#990000">,</font></span> FALSE<span><font color="#990000">);</font></span>
 +
  <span>'''<span><font color="#0000FF">if</font></span>'''</span> <span><font color="#990000">(</font></span>mainloop <span><font color="#990000"><nowiki>==</nowiki></font></span> NULL<span><font color="#990000">)</font></span> <span><font color="#FF0000">{</font></span>
 +
    <span>'''<span><font color="#000000">g_error</font></span>'''</span><span><font color="#990000">(</font></span>PROGNAME <span><font color="#FF0000">": Failed to create mainloop!</font></span><span><font color="#CC33CC">\n</font></span><span><font color="#FF0000">"</font></span><span><font color="#990000">);</font></span>
 +
  <span><font color="#FF0000">}</font></span>
 +
 +
  <span>''<span><font color="#9A1900">/* Create a new GConfClient object using the default settings. */</font></span>''</span>
 +
  client <span><font color="#990000"><nowiki>=</nowiki></font></span> <span>'''<span><font color="#000000">gconf_client_get_default</font></span>'''</span><span><font color="#990000">();</font></span>
 +
  <span>'''<span><font color="#0000FF">if</font></span>'''</span> <span><font color="#990000">(</font></span>client <span><font color="#990000"><nowiki>==</nowiki></font></span> NULL<span><font color="#990000">)</font></span> <span><font color="#FF0000">{</font></span>
 +
    <span>'''<span><font color="#000000">g_error</font></span>'''</span><span><font color="#990000">(</font></span>PROGNAME <span><font color="#FF0000">": Failed to create GConfClient!</font></span><span><font color="#CC33CC">\n</font></span><span><font color="#FF0000">"</font></span><span><font color="#990000">);</font></span>
 +
  <span><font color="#FF0000">}</font></span>
 +
 +
  <span>'''<span><font color="#000000">g_print</font></span>'''</span><span><font color="#990000">(</font></span>PROGNAME <span><font color="#FF0000">":main GType and GConfClient initialized.</font></span><span><font color="#CC33CC">\n</font></span><span><font color="#FF0000">"</font></span><span><font color="#990000">);</font></span>
 +
 +
  <span>''<span><font color="#9A1900">/* Display the starting values for the two keys. */</font></span>''</span>
 +
  <span>'''<span><font color="#000000">dispStringKey</font></span>'''</span><span><font color="#990000">(</font></span>client<span><font color="#990000">,</font></span> SERVICE_KEY_CONNECTION<span><font color="#990000">);</font></span>
 +
  <span>'''<span><font color="#000000">dispStringKey</font></span>'''</span><span><font color="#990000">(</font></span>client<span><font color="#990000">,</font></span> SERVICE_KEY_CONNECTIONPARAMS<span><font color="#990000">);</font></span></tt>
-
  g_print(PROGNAME ":main Starting.\n");
+
The dispStringKey utility is rather simple as well, building on the GConf material that was covered in the previous section [localhost#sec:using_gconf_to_read_write_pref 9.3.2]<nowiki>: </nowiki>gconf-listener/gconf-key-watch.c
-
  /* Must be called to initialize GType system. The API reference for
+
<tt><span>''<span><font color="#9A1900">/**</font></span>''</span>
-
    gconf_client_get_default() insists.
+
<span>''<span><font color="#9A1900"> * Utility to retrieve a string key and display it.</font></span>''</span>
-
    NOTE: Using gconf_init() is deprecated! */
+
  <span>''<span><font color="#9A1900"> * (Just as a small refresher on the API.)</font></span>''</span>
-
  g_type_init();
+
  <span>''<span><font color="#9A1900"> */</font></span>''</span>
-
 
+
<span>'''<span><font color="#0000FF">static</font></span>'''</span> <span><font color="#009900">void</font></span> <span>'''<span><font color="#000000">dispStringKey</font></span>'''</span><span><font color="#990000">(</font></span>GConfClient<span><font color="#990000"><nowiki>*</nowiki></font></span> client<span><font color="#990000">,</font></span>
-
  /* Create a new mainloop structure that we'll use. Use default
+
                          <span>'''<span><font color="#0000FF">const</font></span>'''</span> gchar<span><font color="#990000"><nowiki>*</nowiki></font></span> keyname<span><font color="#990000">)</font></span> <span><font color="#FF0000">{</font></span>
-
    context (NULL) and set the 'running' flag to FALSE. */
+
-
  mainloop = g_main_loop_new(NULL, FALSE);
+
  <span>''<span><font color="#9A1900">/* This will hold the string value of the key. It will be</font></span>''</span>
-
  if (mainloop == NULL) {
+
<span>''<span><font color="#9A1900">    dynamically allocated for us, so we need to release it ourselves</font></span>''</span>
-
    g_error(PROGNAME ": Failed to create mainloop!\n");
+
<span>''<span><font color="#9A1900">    when done (before returning). */</font></span>''</span>
-
  }
+
  gchar<span><font color="#990000"><nowiki>*</nowiki></font></span> valueStr <span><font color="#990000"><nowiki>=</nowiki></font></span> NULL<span><font color="#990000"><nowiki>;</nowiki></font></span>
-
 
+
-
  /* Create a new GConfClient object using the default settings. */
+
  <span>''<span><font color="#9A1900">/* We're not interested in the errors themselves (the last</font></span>''</span>
-
  client = gconf_client_get_default();
+
<span>''<span><font color="#9A1900">    parameter), but the function will return NULL if there is one,</font></span>''</span>
-
  if (client == NULL) {
+
<span>''<span><font color="#9A1900">    so we just end in that case. */</font></span>''</span>
-
    g_error(PROGNAME ": Failed to create GConfClient!\n");
+
  valueStr <span><font color="#990000"><nowiki>=</nowiki></font></span> <span>'''<span><font color="#000000">gconf_client_get_string</font></span>'''</span><span><font color="#990000">(</font></span>client<span><font color="#990000">,</font></span> keyname<span><font color="#990000">,</font></span> NULL<span><font color="#990000">);</font></span>
-
  }
+
-
 
+
  <span>'''<span><font color="#0000FF">if</font></span>'''</span> <span><font color="#990000">(</font></span>valueStr <span><font color="#990000"><nowiki>==</nowiki></font></span> NULL<span><font color="#990000">)</font></span> <span><font color="#FF0000">{</font></span>
-
  g_print(PROGNAME ":main GType and GConfClient initialized.\n");
+
    <span>'''<span><font color="#000000">g_error</font></span>'''</span><span><font color="#990000">(</font></span>PROGNAME <span><font color="#FF0000">": No string value for %s. Quitting</font></span><span><font color="#CC33CC">\n</font></span><span><font color="#FF0000">"</font></span><span><font color="#990000">,</font></span> keyname<span><font color="#990000">);</font></span>
-
 
+
    <span>''<span><font color="#9A1900">/* Application terminates. */</font></span>''</span>
-
  /* Display the starting values for the two keys. */
+
  <span><font color="#FF0000">}</font></span>
-
  dispStringKey(client, SERVICE_KEY_CONNECTION);
+
-
  dispStringKey(client, SERVICE_KEY_CONNECTIONPARAMS);
+
  <span>'''<span><font color="#000000">g_print</font></span>'''</span><span><font color="#990000">(</font></span>PROGNAME <span><font color="#FF0000">": Value for key '%s' is set to '%s'</font></span><span><font color="#CC33CC">\n</font></span><span><font color="#FF0000">"</font></span><span><font color="#990000">,</font></span>
-
</source>
+
          keyname<span><font color="#990000">,</font></span> valueStr<span><font color="#990000">);</font></span>
-
 
+
-
The <code>dispStringKey</code> utility is rather simple as well, building on the GConf material that was covered in the [[#Using GConf to read and write preferences|previous section]]: gconf-listener/gconf-key-watch.c
+
  <span>''<span><font color="#9A1900">/* Normally one would want to use the value for something beyond</font></span>''</span>
-
 
+
<span>''<span><font color="#9A1900">    just displaying it, but since this code doesn't, we release the</font></span>''</span>
-
<source lang="c">
+
<span>''<span><font color="#9A1900">    allocated value string. */</font></span>''</span>
-
/**
+
  <span>'''<span><font color="#000000">g_free</font></span>'''</span><span><font color="#990000">(</font></span>valueStr<span><font color="#990000">);</font></span>
-
* Utility to retrieve a string key and display it.
+
<span><font color="#FF0000">}</font></span></tt>
-
  * (Just as a small refresher on the API.)
+
-
  */
+
-
static void dispStringKey(GConfClient* client,
+
-
                          const gchar* keyname) {
+
-
 
+
-
  /* This will hold the string value of the key. It will be
+
-
    dynamically allocated for us, so we need to release it ourselves
+
-
    when done (before returning). */
+
-
  gchar* valueStr = NULL;
+
-
 
+
-
  /* We're not interested in the errors themselves (the last
+
-
    parameter), but the function will return NULL if there is one,
+
-
    so we just end in that case. */
+
-
  valueStr = gconf_client_get_string(client, keyname, NULL);
+
-
 
+
-
  if (valueStr == NULL) {
+
-
    g_error(PROGNAME ": No string value for %s. Quitting\n", keyname);
+
-
    /* Application terminates. */
+
-
  }
+
-
 
+
-
  g_print(PROGNAME ": Value for key '%s' is set to '%s'\n",
+
-
          keyname, valueStr);
+
-
 
+
-
  /* Normally one would want to use the value for something beyond
+
-
    just displaying it, but since this code doesn't, we release the
+
-
    allocated value string. */
+
-
  g_free(valueStr);
+
-
}
+
-
</source>
+
Next, the GConf client is told to attach itself to a specific name space part that this example is going to operate with: gconf-listener/gconf-key-watch.c
Next, the GConf client is told to attach itself to a specific name space part that this example is going to operate with: gconf-listener/gconf-key-watch.c
-
<source lang="c">
+
<tt>  <span>''<span><font color="#9A1900">/**</font></span>''</span>
-
/**
+
  <span>''<span><font color="#9A1900">  * Register directory to watch for changes. This will then tell</font></span>''</span>
-
  * Register directory to watch for changes. This will then tell
+
  <span>''<span><font color="#9A1900">  * GConf to watch for changes in this namespace, and cause the</font></span>''</span>
-
  * GConf to watch for changes in this namespace, and cause the
+
  <span>''<span><font color="#9A1900">  * "value-changed"-signal to be emitted. We won't be using that</font></span>''</span>
-
  * "value-changed"-signal to be emitted. We won't be using that
+
  <span>''<span><font color="#9A1900">  * mechanism, but will opt to a more modern (and potentially more</font></span>''</span>
-
  * mechanism, but will opt to a more modern (and potentially more
+
  <span>''<span><font color="#9A1900">  * scalable solution). The directory needs to be added to the</font></span>''</span>
-
  * scalable solution). The directory needs to be added to the
+
  <span>''<span><font color="#9A1900">  * watch list in either case.</font></span>''</span>
-
  * watch list in either case.
+
  <span>''<span><font color="#9A1900">  *</font></span>''</span>
-
  *
+
  <span>''<span><font color="#9A1900">  * When adding directories, you can sometimes optimize your program</font></span>''</span>
-
  * When adding directories, you can sometimes optimize your program
+
  <span>''<span><font color="#9A1900">  * performance by asking GConfClient to preload some (or all) keys</font></span>''</span>
-
  * performance by asking GConfClient to preload some (or all) keys
+
  <span>''<span><font color="#9A1900">  * under a specific directory. This is done via the preload_type</font></span>''</span>
-
  * under a specific directory. This is done via the preload_type
+
  <span>''<span><font color="#9A1900">  * parameter (we use GCONF_CLIENT_PRELOAD_NONE below). Since our</font></span>''</span>
-
  * parameter (we use GCONF_CLIENT_PRELOAD_NONE below). Since our
+
  <span>''<span><font color="#9A1900">  * program will only listen for changes, we don't want to use extra</font></span>''</span>
-
  * program will only listen for changes, we don't want to use extra
+
  <span>''<span><font color="#9A1900">  * memory to keep the keys cached.</font></span>''</span>
-
  * memory to keep the keys cached.
+
  <span>''<span><font color="#9A1900">  *</font></span>''</span>
-
  *
+
  <span>''<span><font color="#9A1900">  * Parameters:</font></span>''</span>
-
  * Parameters:
+
  <span>''<span><font color="#9A1900">  * - client: GConf-client object</font></span>''</span>
-
  * - client: GConf-client object
+
  <span>''<span><font color="#9A1900">  * - SERVICEPATH: the name of the GConf namespace to follow</font></span>''</span>
-
  * - SERVICEPATH: the name of the GConf namespace to follow
+
  <span>''<span><font color="#9A1900">  * - GCONF_CLIENT_PRELOAD_NONE: do not preload any of contents</font></span>''</span>
-
  * - GCONF_CLIENT_PRELOAD_NONE: do not preload any of contents
+
  <span>''<span><font color="#9A1900">  * - error: where to store the pointer to allocated GError on</font></span>''</span>
-
  * - error: where to store the pointer to allocated GError on
+
  <span>''<span><font color="#9A1900">  *          errors.</font></span>''</span>
-
  *          errors.
+
  <span>''<span><font color="#9A1900">  */</font></span>''</span>
-
  */
+
  <span>'''<span><font color="#000000">gconf_client_add_dir</font></span>'''</span><span><font color="#990000">(</font></span>client<span><font color="#990000">,</font></span>
-
gconf_client_add_dir(client,
+
                        SERVICE_GCONF_ROOT<span><font color="#990000">,</font></span>
-
                    SERVICE_GCONF_ROOT,
+
                        GCONF_CLIENT_PRELOAD_NONE<span><font color="#990000">,</font></span>
-
                    GCONF_CLIENT_PRELOAD_NONE,
+
                        <span><font color="#990000">&amp;</font></span>error<span><font color="#990000">);</font></span>
-
                    &error);
+
-
 
+
  <span>'''<span><font color="#0000FF">if</font></span>'''</span> <span><font color="#990000">(</font></span>error <span><font color="#990000"><nowiki>!=</nowiki></font></span> NULL<span><font color="#990000">)</font></span> <span><font color="#FF0000">{</font></span>
-
if (error != NULL) {
+
    <span>'''<span><font color="#000000">g_error</font></span>'''</span><span><font color="#990000">(</font></span>PROGNAME <span><font color="#FF0000">": Failed to add a watch to GCClient: %s</font></span><span><font color="#CC33CC">\n</font></span><span><font color="#FF0000">"</font></span><span><font color="#990000">,</font></span>
-
  g_error(PROGNAME ": Failed to add a watch to GCClient: %s\n",
+
            error<span><font color="#990000">-&gt;</font></span>message<span><font color="#990000">);</font></span>
-
          error->message);
+
    <span>''<span><font color="#9A1900">/* Normally we'd also release the allocated GError, but since</font></span>''</span>
-
  /* Normally we'd also release the allocated GError, but since
+
<span>''<span><font color="#9A1900">      this program will terminate on g_error, we won't do that.</font></span>''</span>
-
    this program will terminate on g_error, we won't do that.
+
<span>''<span><font color="#9A1900">      Hence the next line is commented. */</font></span>''</span>
-
    Hence the next line is commented. */
+
    <span>''<span><font color="#9A1900">/* g_error_free(error); */</font></span>''</span>
-
  /* g_error_free(error); */
+
-
 
+
    <span>''<span><font color="#9A1900">/* When you want to release the error if it has been allocated,</font></span>''</span>
-
  /* When you want to release the error if it has been allocated,
+
<span>''<span><font color="#9A1900">      or just continue if not, use g_clear_error(&amp;error); */</font></span>''</span>
-
    or just continue if not, use g_clear_error(&error); */
+
  <span><font color="#FF0000">}</font></span>
-
}
+
-
 
+
  <span>'''<span><font color="#000000">g_print</font></span>'''</span><span><font color="#990000">(</font></span>PROGNAME <span><font color="#FF0000">":main Added "</font></span> SERVICE_GCONF_ROOT <span><font color="#FF0000">".</font></span><span><font color="#CC33CC">\n</font></span><span><font color="#FF0000">"</font></span><span><font color="#990000">);</font></span></tt>
-
g_print(PROGNAME ":main Added " SERVICE_GCONF_ROOT ".\n");
+
-
</source>
+
Proceeding with the callback function registration, we have: gconf-listener/gconf-key-watch.c
Proceeding with the callback function registration, we have: gconf-listener/gconf-key-watch.c
-
<source lang="c">
+
<tt>  <span>''<span><font color="#9A1900">/* Register our interest (in the form of a callback function) for</font></span>''</span>
-
/* Register our interest (in the form of a callback function) for
+
<span>''<span><font color="#9A1900">    any changes under the namespace that we just added.</font></span>''</span>
-
  any changes under the namespace that we just added.
+
-
 
+
<span>''<span><font color="#9A1900">    Parameters:</font></span>''</span>
-
  Parameters:
+
<span>''<span><font color="#9A1900">    - client: GConfClient object.</font></span>''</span>
-
  - client: GConfClient object.
+
<span>''<span><font color="#9A1900">    - SERVICEPATH: namespace under which we can get notified for</font></span>''</span>
-
  - SERVICEPATH: namespace under which we can get notified for
+
<span>''<span><font color="#9A1900">                    changes.</font></span>''</span>
-
                  changes.
+
<span>''<span><font color="#9A1900">    - gconf_notify_func: callback that will be called on changes.</font></span>''</span>
-
  - gconf_notify_func: callback that will be called on changes.
+
<span>''<span><font color="#9A1900">    - NULL: user-data pointer (not used here).</font></span>''</span>
-
  - NULL: user-data pointer (not used here).
+
<span>''<span><font color="#9A1900">    - NULL: function to call on user-data when notify is removed or</font></span>''</span>
-
  - NULL: function to call on user-data when notify is removed or
+
<span>''<span><font color="#9A1900">            GConfClient destroyed. NULL for none (since we don't</font></span>''</span>
-
          GConfClient destroyed. NULL for none (since we don't
+
<span>''<span><font color="#9A1900">            have user-data anyway).</font></span>''</span>
-
          have user-data anyway).
+
<span>''<span><font color="#9A1900">    - error: return location for an allocated GError.</font></span>''</span>
-
  - error: return location for an allocated GError.
+
-
 
+
<span>''<span><font color="#9A1900">    Returns:</font></span>''</span>
-
  Returns:
+
<span>''<span><font color="#9A1900">    guint: an ID for this notification so that we could remove it</font></span>''</span>
-
  guint: an ID for this notification so that we could remove it
+
<span>''<span><font color="#9A1900">            later with gconf_client_notify_remove(). We're not going</font></span>''</span>
-
          later with gconf_client_notify_remove(). We're not going
+
<span>''<span><font color="#9A1900">            to use it so we don't store it anywhere. */</font></span>''</span>
-
          to use it so we don't store it anywhere. */
+
  <span>'''<span><font color="#000000">gconf_client_notify_add</font></span>'''</span><span><font color="#990000">(</font></span>client<span><font color="#990000">,</font></span> SERVICE_GCONF_ROOT<span><font color="#990000">,</font></span>
-
gconf_client_notify_add(client, SERVICE_GCONF_ROOT,
+
                          keyChangeCallback<span><font color="#990000">,</font></span> NULL<span><font color="#990000">,</font></span> NULL<span><font color="#990000">,</font></span> <span><font color="#990000">&amp;</font></span>error<span><font color="#990000">);</font></span>
-
                        keyChangeCallback, NULL, NULL, &error);
+
  <span>'''<span><font color="#0000FF">if</font></span>'''</span> <span><font color="#990000">(</font></span>error <span><font color="#990000"><nowiki>!=</nowiki></font></span> NULL<span><font color="#990000">)</font></span> <span><font color="#FF0000">{</font></span>
-
if (error != NULL) {
+
    <span>'''<span><font color="#000000">g_error</font></span>'''</span><span><font color="#990000">(</font></span>PROGNAME <span><font color="#FF0000">": Failed to add register the callback: %s</font></span><span><font color="#CC33CC">\n</font></span><span><font color="#FF0000">"</font></span><span><font color="#990000">,</font></span>
-
  g_error(PROGNAME ": Failed to add register the callback: %s\n",
+
            error<span><font color="#990000">-&gt;</font></span>message<span><font color="#990000">);</font></span>
-
          error->message);
+
    <span>''<span><font color="#9A1900">/* Program terminates. */</font></span>''</span>
-
  /* Program terminates. */
+
  <span><font color="#FF0000">}</font></span>
-
}
+
-
 
+
  <span>'''<span><font color="#000000">g_print</font></span>'''</span><span><font color="#990000">(</font></span>PROGNAME <span><font color="#FF0000">":main CB registered &amp; starting main loop</font></span><span><font color="#CC33CC">\n</font></span><span><font color="#FF0000">"</font></span><span><font color="#990000">);</font></span></tt>
-
g_print(PROGNAME ":main CB registered & starting main loop\n");
+
-
</source>
+
When dealing with regular desktop software, one could use multiple callback functions; one for each key to track. However, this would require implementing multiple callback functions, and this runs a risk of enlarging the size of the code. For this reason, the example code uses one callback function, which will internally multiplex between the two keys (by using strcmp): gconf-listener/gconf-key-watch.c
When dealing with regular desktop software, one could use multiple callback functions; one for each key to track. However, this would require implementing multiple callback functions, and this runs a risk of enlarging the size of the code. For this reason, the example code uses one callback function, which will internally multiplex between the two keys (by using strcmp): gconf-listener/gconf-key-watch.c
-
<source lang="c">
+
<tt><span>''<span><font color="#9A1900">/**</font></span>''</span>
-
/**
+
  <span>''<span><font color="#9A1900"> * Callback called when a key in watched directory changes.</font></span>''</span>
-
  * Callback called when a key in watched directory changes.
+
  <span>''<span><font color="#9A1900"> * Prototype for the callback must be compatible with</font></span>''</span>
-
  * Prototype for the callback must be compatible with
+
  <span>''<span><font color="#9A1900"> * GConfClientNotifyFunc (for ref).</font></span>''</span>
-
  * GConfClientNotifyFunc (for ref).
+
  <span>''<span><font color="#9A1900"> *</font></span>''</span>
-
  *
+
  <span>''<span><font color="#9A1900"> * It will find out which key changed (using strcmp, since the same</font></span>''</span>
-
  * It will find out which key changed (using strcmp, since the same
+
  <span>''<span><font color="#9A1900"> * callback is used to track both keys) and the display the new value</font></span>''</span>
-
  * callback is used to track both keys) and the display the new value
+
  <span>''<span><font color="#9A1900"> * of the key.</font></span>''</span>
-
  * of the key.
+
  <span>''<span><font color="#9A1900"> *</font></span>''</span>
-
  *
+
  <span>''<span><font color="#9A1900"> * The changed key/value pair will be communicated in the entry</font></span>''</span>
-
  * The changed key/value pair will be communicated in the entry
+
  <span>''<span><font color="#9A1900"> * parameter. userData will be NULL (can be set on notify_add [in</font></span>''</span>
-
  * parameter. userData will be NULL (can be set on notify_add [in
+
  <span>''<span><font color="#9A1900"> * main]). Normally the application state would be carried within the</font></span>''</span>
-
  * main]). Normally the application state would be carried within the
+
  <span>''<span><font color="#9A1900"> * userData parameter, so that this callback could then modify the</font></span>''</span>
-
  * userData parameter, so that this callback could then modify the
+
  <span>''<span><font color="#9A1900"> * view based on the change. Since this program does not have a state,</font></span>''</span>
-
  * view based on the change. Since this program does not have a state,
+
  <span>''<span><font color="#9A1900"> * there is little that we can do within the function (it will abort</font></span>''</span>
-
  * there is little that we can do within the function (it will abort
+
  <span>''<span><font color="#9A1900"> * the program on errors though).</font></span>''</span>
-
  * the program on errors though).
+
  <span>''<span><font color="#9A1900"> */</font></span>''</span>
-
  */
+
<span>'''<span><font color="#0000FF">static</font></span>'''</span> <span><font color="#009900">void</font></span> <span>'''<span><font color="#000000">keyChangeCallback</font></span>'''</span><span><font color="#990000">(</font></span>GConfClient<span><font color="#990000"><nowiki>*</nowiki></font></span> client<span><font color="#990000">,</font></span>
-
static void keyChangeCallback(GConfClient* client,
+
                              guint        cnxn_id<span><font color="#990000">,</font></span>
-
                              guint        cnxn_id,
+
                              GConfEntry<span><font color="#990000"><nowiki>*</nowiki></font></span> entry<span><font color="#990000">,</font></span>
-
                              GConfEntry*  entry,
+
                              gpointer    userData<span><font color="#990000">)</font></span> <span><font color="#FF0000">{</font></span>
-
                              gpointer    userData) {
+
 +
  <span>''<span><font color="#9A1900">/* This will hold the pointer to the value. */</font></span>''</span>
 +
  <span>'''<span><font color="#0000FF">const</font></span>'''</span> GConfValue<span><font color="#990000"><nowiki>*</nowiki></font></span> value <span><font color="#990000"><nowiki>=</nowiki></font></span> NULL<span><font color="#990000"><nowiki>;</nowiki></font></span>
 +
  <span>''<span><font color="#9A1900">/* This will hold a pointer to the name of the key that changed. */</font></span>''</span>
 +
  <span>'''<span><font color="#0000FF">const</font></span>'''</span> gchar<span><font color="#990000"><nowiki>*</nowiki></font></span> keyname <span><font color="#990000"><nowiki>=</nowiki></font></span> NULL<span><font color="#990000"><nowiki>;</nowiki></font></span>
 +
  <span>''<span><font color="#9A1900">/* This will hold a dynamically allocated human-readable</font></span>''</span>
 +
<span>''<span><font color="#9A1900">    representation of the changed value. */</font></span>''</span>
 +
  gchar<span><font color="#990000"><nowiki>*</nowiki></font></span> strValue <span><font color="#990000"><nowiki>=</nowiki></font></span> NULL<span><font color="#990000"><nowiki>;</nowiki></font></span>
 +
 +
  <span>'''<span><font color="#000000">g_print</font></span>'''</span><span><font color="#990000">(</font></span>PROGNAME <span><font color="#FF0000">": keyChangeCallback invoked.</font></span><span><font color="#CC33CC">\n</font></span><span><font color="#FF0000">"</font></span><span><font color="#990000">);</font></span>
 +
 +
  <span>''<span><font color="#9A1900">/* Get a pointer to the key (this is not a copy). */</font></span>''</span>
 +
  keyname <span><font color="#990000"><nowiki>=</nowiki></font></span> <span>'''<span><font color="#000000">gconf_entry_get_key</font></span>'''</span><span><font color="#990000">(</font></span>entry<span><font color="#990000">);</font></span>
 +
 +
  <span>''<span><font color="#9A1900">/* It will be quite fatal if after change we cannot retrieve even</font></span>''</span>
 +
<span>''<span><font color="#9A1900">    the name for the gconf entry, so we error out here. */</font></span>''</span>
 +
  <span>'''<span><font color="#0000FF">if</font></span>'''</span> <span><font color="#990000">(</font></span>keyname <span><font color="#990000"><nowiki>==</nowiki></font></span> NULL<span><font color="#990000">)</font></span> <span><font color="#FF0000">{</font></span>
 +
    <span>'''<span><font color="#000000">g_error</font></span>'''</span><span><font color="#990000">(</font></span>PROGNAME <span><font color="#FF0000">": Couldn't get the key name!</font></span><span><font color="#CC33CC">\n</font></span><span><font color="#FF0000">"</font></span><span><font color="#990000">);</font></span>
 +
    <span>''<span><font color="#9A1900">/* Application terminates. */</font></span>''</span>
 +
  <span><font color="#FF0000">}</font></span>
 +
 +
  <span>''<span><font color="#9A1900">/* Get a pointer to the value from changed entry. */</font></span>''</span>
 +
  value <span><font color="#990000"><nowiki>=</nowiki></font></span> <span>'''<span><font color="#000000">gconf_entry_get_value</font></span>'''</span><span><font color="#990000">(</font></span>entry<span><font color="#990000">);</font></span>
 +
 +
  <span>''<span><font color="#9A1900">/* If we get a NULL as the value, it means that the value either has</font></span>''</span>
 +
<span>''<span><font color="#9A1900">    not been set, or is at default. As a precaution we assume that</font></span>''</span>
 +
<span>''<span><font color="#9A1900">    this cannot ever happen, and will abort if it does.</font></span>''</span>
 +
<span>''<span><font color="#9A1900">    NOTE: A real program should be more resilient in this case, but</font></span>''</span>
 +
<span>''<span><font color="#9A1900">          the problem is: what is the correct action in this case?</font></span>''</span>
 +
<span>''<span><font color="#9A1900">          This is not always simple to decide.</font></span>''</span>
 +
<span>''<span><font color="#9A1900">    NOTE: You can trip this assert with 'make primekeys', since that</font></span>''</span>
 +
<span>''<span><font color="#9A1900">          will first remove all the keys (which causes the CB to</font></span>''</span>
 +
<span>''<span><font color="#9A1900">          be invoked, and abort here). */</font></span>''</span>
 +
  <span>'''<span><font color="#000000">g_assert</font></span>'''</span><span><font color="#990000">(</font></span>value <span><font color="#990000"><nowiki>!=</nowiki></font></span> NULL<span><font color="#990000">);</font></span>
 +
 +
  <span>''<span><font color="#9A1900">/* Check that it looks like a valid type for the value. */</font></span>''</span>
 +
  <span>'''<span><font color="#0000FF">if</font></span>'''</span> <span><font color="#990000">(!</font></span><span>'''<span><font color="#000000">GCONF_VALUE_TYPE_VALID</font></span>'''</span><span><font color="#990000">(</font></span>value<span><font color="#990000">-&gt;</font></span>type<span><font color="#990000">))</font></span> <span><font color="#FF0000">{</font></span>
 +
    <span>'''<span><font color="#000000">g_error</font></span>'''</span><span><font color="#990000">(</font></span>PROGNAME <span><font color="#FF0000">": Invalid type for gconfvalue!</font></span><span><font color="#CC33CC">\n</font></span><span><font color="#FF0000">"</font></span><span><font color="#990000">);</font></span>
 +
  <span><font color="#FF0000">}</font></span>
 +
 +
  <span>''<span><font color="#9A1900">/* Create a human readable representation of the value. Since this</font></span>''</span>
 +
<span>''<span><font color="#9A1900">    will be a new string created just for us, we'll need to be</font></span>''</span>
 +
<span>''<span><font color="#9A1900">    careful and free it later. */</font></span>''</span>
 +
  strValue <span><font color="#990000"><nowiki>=</nowiki></font></span> <span>'''<span><font color="#000000">gconf_value_to_string</font></span>'''</span><span><font color="#990000">(</font></span>value<span><font color="#990000">);</font></span>
 +
 +
  <span>''<span><font color="#9A1900">/* Print out a message (depending on which of the tracked keys</font></span>''</span>
 +
<span>''<span><font color="#9A1900">    change. */</font></span>''</span>
 +
  <span>'''<span><font color="#0000FF">if</font></span>'''</span> <span><font color="#990000">(</font></span><span>'''<span><font color="#000000">strcmp</font></span>'''</span><span><font color="#990000">(</font></span>keyname<span><font color="#990000">,</font></span> SERVICE_KEY_CONNECTION<span><font color="#990000">)</font></span> <span><font color="#990000"><nowiki>==</nowiki></font></span> <span><font color="#993399">0</font></span><span><font color="#990000">)</font></span> <span><font color="#FF0000">{</font></span>
 +
    <span>'''<span><font color="#000000">g_print</font></span>'''</span><span><font color="#990000">(</font></span>PROGNAME <span><font color="#FF0000">": Connection type setting changed: [%s]</font></span><span><font color="#CC33CC">\n</font></span><span><font color="#FF0000">"</font></span><span><font color="#990000">,</font></span>
 +
            strValue<span><font color="#990000">);</font></span>
 +
  <span><font color="#FF0000">}</font></span> <span>'''<span><font color="#0000FF">else</font></span>'''</span> <span>'''<span><font color="#0000FF">if</font></span>'''</span> <span><font color="#990000">(</font></span><span>'''<span><font color="#000000">strcmp</font></span>'''</span><span><font color="#990000">(</font></span>keyname<span><font color="#990000">,</font></span> SERVICE_KEY_CONNECTIONPARAMS<span><font color="#990000">)</font></span> <span><font color="#990000"><nowiki>==</nowiki></font></span> <span><font color="#993399">0</font></span><span><font color="#990000">)</font></span> <span><font color="#FF0000">{</font></span>
 +
    <span>'''<span><font color="#000000">g_print</font></span>'''</span><span><font color="#990000">(</font></span>PROGNAME <span><font color="#FF0000">": Connection params setting changed: [%s]</font></span><span><font color="#CC33CC">\n</font></span><span><font color="#FF0000">"</font></span><span><font color="#990000">,</font></span>
 +
            strValue<span><font color="#990000">);</font></span>
 +
  <span><font color="#FF0000">}</font></span> <span>'''<span><font color="#0000FF">else</font></span>'''</span> <span><font color="#FF0000">{</font></span>
 +
    <span>'''<span><font color="#000000">g_print</font></span>'''</span><span><font color="#990000">(</font></span>PROGNAME <span><font color="#FF0000">":Unknown key: %s (value: [%s])</font></span><span><font color="#CC33CC">\n</font></span><span><font color="#FF0000">"</font></span><span><font color="#990000">,</font></span> keyname<span><font color="#990000">,</font></span>
 +
            strValue<span><font color="#990000">);</font></span>
 +
  <span><font color="#FF0000">}</font></span>
 +
 +
  <span>''<span><font color="#9A1900">/* Free the string representation of the value. */</font></span>''</span>
 +
  <span>'''<span><font color="#000000">g_free</font></span>'''</span><span><font color="#990000">(</font></span>strValue<span><font color="#990000">);</font></span>
 +
 +
  <span>'''<span><font color="#000000">g_print</font></span>'''</span><span><font color="#990000">(</font></span>PROGNAME <span><font color="#FF0000">": keyChangeCallback done.</font></span><span><font color="#CC33CC">\n</font></span><span><font color="#FF0000">"</font></span><span><font color="#990000">);</font></span>
 +
<span><font color="#FF0000">}</font></span></tt>
-
  /* This will hold the pointer to the value. */
+
The complications in the above code rise from the fact that GConf communicates values using a GValue structure, which can carry values of any simple type. Since GConf (or the user for that matter) cannot be completely trusted to return the correct type for the value, it is necessary to be extra careful, and not assume that it will always be a string. GConf also supports "default" values, which are communicated to the application using NULLs, so it is also necessary to guard against that. Especially since the application does not provide a schema for the configuration space that would contain the default values.
-
  const GConfValue* value = NULL;
+
-
  /* This will hold a pointer to the name of the key that changed. */
+
-
  const gchar* keyname = NULL;
+
-
  /* This will hold a dynamically allocated human-readable
+
-
    representation of the changed value. */
+
-
  gchar* strValue = NULL;
+
-
  g_print(PROGNAME ": keyChangeCallback invoked.\n");
+
The next step is to build and test the program. The program will be started on the background, so that gconftool-2 can be used to see how the program reacts to changing parameters:
-
  /* Get a pointer to the key (this is not a copy). */
+
<nowiki>
-
  keyname = gconf_entry_get_key(entry);
+
[sbox-DIABLO_X86: ~/gconf-listener] &gt; make
 +
cc -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/gconf/2 \
 +
    -I/usr/include/dbus-1.0 -I/usr/lib/dbus-1.0/include -Wall -g \
 +
    -DPROGNAME=\"gconf-key-watch\" gconf-key-watch.c -o gconf-key-watch \
 +
    -lgconf-2 -ldbus-glib-1 -ldbus-1 -lgobject-2.0 -lglib-2.0
 +
[sbox-DIABLO_X86: ~/gconf-listener] &gt; run-standalone.sh ./gconf-key-watch &amp;
 +
[2] 21385
 +
gconf-key-watch:main Starting.
 +
gconf-key-watch:main GType and GConfClient initialized.
 +
gconf-key-watch: Value for key '/apps/Maemo/platdev_ex/connection'
 +
  is set to 'btcomm0'
 +
gconf-key-watch: Value for key '/apps/Maemo/platdev_ex/connectionparams'
 +
  is set to '9600,8,N,1'
 +
gconf-key-watch:main Added /apps/Maemo/platdev_ex.
 +
gconf-key-watch:main CB registered &amp; starting main loop
 +
[sbox-DIABLO_X86: ~/gconf-listener] &gt; gconftool-2 --set --type string \
 +
  /apps/Maemo/platdev_ex/connection ttyS0
 +
gconf-key-watch: keyChangeCallback invoked.
 +
gconf-key-watch: Connection type setting changed: [ttyS0]
 +
gconf-key-watch: keyChangeCallback done.
 +
[sbox-DIABLO_X86: ~/gconf-listener] &gt; gconftool-2 --set --type string \
 +
  /apps/Maemo/platdev_ex/connectionparams ''
 +
gconf-key-watch: keyChangeCallback invoked.
 +
gconf-key-watch: Connection params setting changed: []
 +
gconf-key-watch: keyChangeCallback done.
 +
</nowiki>
-
  /* It will be quite fatal if after change we cannot retrieve even
 
-
    the name for the gconf entry, so we error out here. */
 
-
  if (keyname == NULL) {
 
-
    g_error(PROGNAME ": Couldn't get the key name!\n");
 
-
    /* Application terminates. */
 
-
  }
 
-
 
-
  /* Get a pointer to the value from changed entry. */
 
-
  value = gconf_entry_get_value(entry);
 
-
 
-
  /* If we get a NULL as the value, it means that the value either has
 
-
    not been set, or is at default. As a precaution we assume that
 
-
    this cannot ever happen, and will abort if it does.
 
-
    NOTE: A real program should be more resilient in this case, but
 
-
          the problem is: what is the correct action in this case?
 
-
          This is not always simple to decide.
 
-
    NOTE: You can trip this assert with 'make primekeys', since that
 
-
          will first remove all the keys (which causes the CB to
 
-
          be invoked, and abort here). */
 
-
  g_assert(value != NULL);
 
-
 
-
  /* Check that it looks like a valid type for the value. */
 
-
  if (!GCONF_VALUE_TYPE_VALID(value->type)) {
 
-
    g_error(PROGNAME ": Invalid type for gconfvalue!\n");
 
-
  }
 
-
 
-
  /* Create a human readable representation of the value. Since this
 
-
    will be a new string created just for us, we'll need to be
 
-
    careful and free it later. */
 
-
  strValue = gconf_value_to_string(value);
 
-
 
-
  /* Print out a message (depending on which of the tracked keys
 
-
    change. */
 
-
  if (strcmp(keyname, SERVICE_KEY_CONNECTION) == 0) {
 
-
    g_print(PROGNAME ": Connection type setting changed: [%s]\n",
 
-
            strValue);
 
-
  } else if (strcmp(keyname, SERVICE_KEY_CONNECTIONPARAMS) == 0) {
 
-
    g_print(PROGNAME ": Connection params setting changed: [%s]\n",
 
-
            strValue);
 
-
  } else {
 
-
    g_print(PROGNAME ":Unknown key: %s (value: [%s])\n", keyname,
 
-
            strValue);
 
-
  }
 
-
 
-
  /* Free the string representation of the value. */
 
-
  g_free(strValue);
 
-
 
-
  g_print(PROGNAME ": keyChangeCallback done.\n");
 
-
}
 
-
</source>
 
-
 
-
The complications in the above code rise from the fact that GConf communicates values using a <code>GValue</code> structure, which can carry values of any simple type. Since GConf (or the user for that matter) cannot be completely trusted to return the correct type for the value, it is necessary to be extra careful, and not assume that it will always be a string. GConf also supports "default" values, which are communicated to the application using <code>NULL</code>s, so it is also necessary to guard against that. Especially since the application does not provide a schema for the configuration space that would contain the default values.
 
-
 
-
The next step is to build and test the program. The program will be started on the background, so that <code>gconftool-2</code> can be used to see how the program reacts to changing parameters:
 
-
 
-
<pre>
 
-
[sbox-DIABLO_X86: ~/gconf-listener] > make
 
-
cc -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/gconf/2 \
 
-
  -I/usr/include/dbus-1.0 -I/usr/lib/dbus-1.0/include -Wall -g \
 
-
  -DPROGNAME=\"gconf-key-watch\" gconf-key-watch.c -o gconf-key-watch \
 
-
  -lgconf-2 -ldbus-glib-1 -ldbus-1 -lgobject-2.0 -lglib-2.0
 
-
[sbox-DIABLO_X86: ~/gconf-listener] &gt; run-standalone.sh ./gconf-key-watch &amp;
 
-
[2] 21385
 
-
gconf-key-watch:main Starting.
 
-
gconf-key-watch:main GType and GConfClient initialized.
 
-
gconf-key-watch: Value for key '/apps/Maemo/platdev_ex/connection'
 
-
is set to 'btcomm0'
 
-
gconf-key-watch: Value for key '/apps/Maemo/platdev_ex/connectionparams'
 
-
is set to '9600,8,N,1'
 
-
gconf-key-watch:main Added /apps/Maemo/platdev_ex.
 
-
gconf-key-watch:main CB registered & starting main loop
 
-
[sbox-DIABLO_X86: ~/gconf-listener] > gconftool-2 --set --type string \
 
-
  /apps/Maemo/platdev_ex/connection ttyS0
 
-
gconf-key-watch: keyChangeCallback invoked.
 
-
gconf-key-watch: Connection type setting changed: [ttyS0]
 
-
gconf-key-watch: keyChangeCallback done.
 
-
[sbox-DIABLO_X86: ~/gconf-listener] > gconftool-2 --set --type string \
 
-
  /apps/Maemo/platdev_ex/connectionparams ''
 
-
gconf-key-watch: keyChangeCallback invoked.
 
-
gconf-key-watch: Connection params setting changed: []
 
-
gconf-key-watch: keyChangeCallback done.
 
-
</pre>
 
The latter change is somewhat problematic (which the code needs to deal with as well). It is necessary to decide how to react to values that are of the correct type, but with senseless values. GConf in itself does not provide syntax checking for the values, or any semantic checking support. It is recommended that configuration changes will only be reacted to when they pass some internal (to the application) logic that will check their validity, both at syntax level and also at semantic level.
The latter change is somewhat problematic (which the code needs to deal with as well). It is necessary to decide how to react to values that are of the correct type, but with senseless values. GConf in itself does not provide syntax checking for the values, or any semantic checking support. It is recommended that configuration changes will only be reacted to when they pass some internal (to the application) logic that will check their validity, both at syntax level and also at semantic level.
Line 848: Line 831:
One option would also be resetting the value back to a valid value, whenever the program detects an invalid value set attempt. This will lead to a lot of problems, if the value is set programmatically from another program that will obey the same rule, so it is not advisable. Quitting the program on invalid values is also an option that should not be used, since the restricted environment does not provide many ways to inform the user that the program has quit.
One option would also be resetting the value back to a valid value, whenever the program detects an invalid value set attempt. This will lead to a lot of problems, if the value is set programmatically from another program that will obey the same rule, so it is not advisable. Quitting the program on invalid values is also an option that should not be used, since the restricted environment does not provide many ways to inform the user that the program has quit.
-
An additional possible problem is having multiple keys that are all "related" to a single setting or action. It is necessary to decide, how to deal with changes across multiple GConf keys that are related, yet changed separately. The two key example code demonstrates the inherent problem: should the server re-initialize the (theoretic) connection, when the connection key is changed, or when the connectionparams key is changed? If the connection is re-initialized when either of the keys is changed, then the connection will be re-initialized twice when both are changed "simultaneously" (user presses "Apply" on a settings dialog, or gconftool-2 is run and sets both keys). It is easy to see how this might be an even larger problem, if instead of two keys, there were five per connection. GConf and the <code>GConfClient</code> <code>GObject</code> wrapper that has been used here do not support "configuration set transactions", which would allow setting and processing multiple related keys using an atomic model. The example program ignores this issue completely.
+
An additional possible problem is having multiple keys that are all "related" to a single setting or action. It is necessary to decide, how to deal with changes across multiple GConf keys that are related, yet changed separately. The two key example code demonstrates the inherent problem: should the server re-initialize the (theoretic) connection, when the connection key is changed, or when the connectionparams key is changed? If the connection is re-initialized when either of the keys is changed, then the connection will be re-initialized twice when both are changed "simultaneously" (user presses "Apply" on a settings dialog, or gconftool-2 is run and sets both keys). It is easy to see how this might be an even larger problem, if instead of two keys, there were five per connection. GConf and the GConfClient GObject wrapper that has been used here do not support "configuration set transactions", which would allow setting and processing multiple related keys using an atomic model. The example program ignores this issue completely.
The next step is to test how the program (which is still running) reacts to other problematic situations:
The next step is to test how the program (which is still running) reacts to other problematic situations:
-
<pre>
+
[sbox-DIABLO_X86: ~/gconf-listener] &gt; gconftool-2 --set --type int \
-
[sbox-DIABLO_X86: ~/gconf-listener] > gconftool-2 --set --type int \
+
  /apps/Maemo/platdev_ex/connectionparams 5
-
  /apps/Maemo/platdev_ex/connectionparams 5
+
gconf-key-watch: keyChangeCallback invoked.
-
gconf-key-watch: keyChangeCallback invoked.
+
gconf-key-watch: Connection params setting changed: [5]
-
gconf-key-watch: Connection params setting changed: [5]
+
gconf-key-watch: keyChangeCallback done.
-
gconf-key-watch: keyChangeCallback done.
+
[sbox-DIABLO_X86: ~/gconf-listener] &gt; gconftool-2 --set --type boolean \
-
[sbox-DIABLO_X86: ~/gconf-listener] > gconftool-2 --set --type boolean \
+
  /apps/Maemo/platdev_ex/connectionparams true
-
  /apps/Maemo/platdev_ex/connectionparams true
+
gconf-key-watch: keyChangeCallback invoked.
-
gconf-key-watch: keyChangeCallback invoked.
+
gconf-key-watch: Connection params setting changed: [true]
-
gconf-key-watch: Connection params setting changed: [true]
+
gconf-key-watch: keyChangeCallback done.
-
gconf-key-watch: keyChangeCallback done.
+
 
-
</pre>
+
The next example removes the configuration keys, while the program is still running:
The next example removes the configuration keys, while the program is still running:
-
<pre>
+
[sbox-DIABLO_X86: ~/gconf-listener] &gt; make clearkeys
-
[sbox-DIABLO_X86: ~/gconf-listener] > make clearkeys
+
gconf-key-watch: keyChangeCallback invoked.
-
gconf-key-watch: keyChangeCallback invoked.
+
gconf-key-watch[21403]: GLIB ERROR ** default -  
-
gconf-key-watch[21403]: GLIB ERROR ** default -  
+
  file gconf-key-watch.c: line 129 (keyChangeCallback):
-
  file gconf-key-watch.c: line 129 (keyChangeCallback):
+
  assertion failed: (value != NULL)
-
  assertion failed: (value != NULL)
+
aborting...
-
aborting...
+
/usr/bin/run-standalone.sh: line 11: 21403 Aborted (core dumped) "$@"
-
/usr/bin/run-standalone.sh: line 11: 21403 Aborted (core dumped) "$@"
+
[1]+  Exit 134 run-standalone.sh ./gconf-key-watch
-
[1]+  Exit 134 run-standalone.sh ./gconf-key-watch
+
-
</pre>
+
-
Since the code (in the callback function) contains an assert that checks for non-<code>NULL</code> values, it will abort when the key is removed, and that causes the value to go to <code>NULL</code>. So the abortion in the above case is expected.
 
-
[[Category:Development]]
+
Since the code (in the callback function) contains an assert that checks for non-NULL values, it will abort when the key is removed, and that causes the value to go to NULL. So the abortion in the above case is expected.
-
[[Category:Documentation]]
+
-
[[Category:Fremantle]]
+

Learn more about Contributing to the wiki.


Please note that all contributions to maemo.org wiki may be edited, altered, or removed by other contributors. If you do not want your writing to be edited mercilessly, then do not submit it here.
You are also promising us that you wrote this yourself, or copied it from a public domain or similar free resource (see maemo.org wiki:Copyrights for details). Do not submit copyrighted work without permission!


Cancel | Editing help (opens in new window)