summaryrefslogtreecommitdiff
path: root/doc/intro-article.sgml
blob: 08f39f9e6e292fefa1f3d25f8d18a03925df39e8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
<!DOCTYPE Article PUBLIC "-//Davenport//DTD DocBook V3.0//EN"[
]>

<article lang="en" id="index">
  <artheader>
    <date>2000-2-22</date>
    <authorgroup>
      <author>
	<surname>Pennington</surname>
	<firstname>Havoc</firstname> 
	<affiliation>
	  <address>
	    <email>hp@redhat.com</email>
	  </address>
	</affiliation>
      </author>
    </authorgroup>
    <copyright>
      <year>2000</year>
      <holder>Havoc Pennington</holder>
    </copyright>
    <title>Introduction to the GConf library 
    </title> 
    <titleabbrev>GConf introduction</titleabbrev>
    <abstract>
      <para>
        This article introduces the concepts behind the GConf
        configuration library scheduled to ship with the next major
        revision of the GNOME development environment.
      </para>
    </abstract>
  </artheader>
  
  <sect1 id="whatis">
    <title>Introduction: What is GConf?</title>

    <para>
      GConf is a configuration data storage mechanism scheduled to
      ship with GNOME 2.0. GConf does work without GNOME however; it
      can be used with plain GTK+, Xlib, KDE, or even text mode
      applications as well. As of March 2000, there is no stable
      release of GConf yet, but the library is feature-complete.
    </para>
    
    <para>
      The GNOME desktop is currently in the Windows 3.1 era with
      respect to application configuration data; applications store 
      their configuration in flat .INI-style files. Windows later
      introduced a more sophisticated solution, the Registry. However, 
      the Registry still has a number of shortcomings:
      <itemizedlist>
        <listitem>
          <para>It's very difficult to manage a large number of
          computers; system administrators can't install defaults,
          or push changes out to multiple user computers. Proprietary 
            add-on tools exist that try to resolve this problem in 
            various (rather frightening) ways.
          </para>
          </listitem>
        <listitem>
          <para>
            The registry contains lots of undocumented,
            cryptically-formatted data, and regedit is therefore
            dangerous and difficult to use.
          </para>
          </listitem>
        <listitem>
          <para>
            The registry becomes corrupted, and this tends to destroy
            the whole operating system installation.
          </para>
          </listitem>
      </itemizedlist>
    </para>
    
    <para>
      GConf attempts to leapfrog the registry concept. It's a
      <emphasis>library</emphasis> which provides a simple
      configuration data storage interface to applications, and also
      an <emphasis>architecture</emphasis> that tries to make things
      easy for system administrators.
    </para>

    <para>
      Here are some of the features of GConf:
      <itemizedlist>
	<listitem>
	  <para>
            Replaceable backend architecture. GConf currently has a single
            backend that stores configuration data in XML-format text files;
            however, the architecture allows a Registry-like binary database
            backend, an LDAP backend, or even a full-blown SQL database backend.
            The backend used is configurable by the system administrator. This
            is a valuable feature for IS deparatments managing large numbers of
            computers.
	  </para>
	</listitem>

	<listitem>
	  <para>
            Configuration key documentation. Applications can install
            documentation along with their configuration data, explaining the
            possible settings and the effect of each configuration key.  A
            regedit-style tool can display this documentation, making it much
            easier to customize applications without breaking them. The GConf
            database also stores useful meta-information such as the application
            that owns a key, when the key was last changed, etc.
	  </para>
	</listitem>

	<listitem>
	  <para>
            Data change notification service. If configuration data is 
            changed, all interested applications are notified. 
            The notification service works across the network,
            affecting all login sessions for a single user.  
          </para>

          <para>
            This means that programs built from components (where each component
            may be in a separate process) are much easier to write, because if
            one component changes a setting the others can discover the change
            and update themselves. For example, GNOME's new Nautilus file
            manager is actually a collection of applications, including an
            embedded web browser, and various navigation components. The
            components communicate via CORBA. However, you want a single
            preferences dialog located in the top-level "shell" component.
            Without GConf, a custom protocol would have to be invented for 
            each preferences setting, to notify embedded components of changes
            to user preferences.
          </para>

          <para>
            Notification is also useful if multiple application instances are
            running.  GNOME 2.0 uses this feature to let user interface
            configuration take effect on-the-fly without restarting any
            applications; if you turn off toolbar icons, for example, toolbar
            icons will immediately disappear in all running apps.
	  </para>
	</listitem>

	<listitem>
	  <para>
            The client API is very abstract, which allows us to change
            its implementation at a later time without a big headache.
            Because a good implementation is a complex problem, this
            is important. I also like to think the API is simple to
            use.
	  </para>
	</listitem>

	<listitem>
	  <para>
            GConf does proper locking so that the configuration data 
            doesn't get corrupted when multiple applications try to
            use it.
	  </para>
	</listitem>
      </itemizedlist>
    </para>
    
  </sect1>

  <sect1 id="impl">
    <title>Implementation Overview</title>
    <para>
    </para>
    <sect2 id="keysvalues">
      <title>Keys and Values</title>
      <para>
        GConf is not a full-blown database by any means. It stores
        simple key-value pairs. This keeps the implementation simple
        and efficient. In particular, the following database features
        are not currently implemented:

        <itemizedlist>

          <listitem>
            <para>
              Queries
            </para>
          </listitem>

          <listitem>
            <para>
              Efficient storage of large chunks of data (such as entire documents)
            </para>
          </listitem>

          <listitem>
            <para>
              Transactions
            </para>
          </listitem>

        </itemizedlist>
        
        Applications that require these sophisticated features should use LDAP
        or a full-scale database. Transactions may be added eventually, and are
        currently in the API in the form of the
        <structname>GConfChangeSet</structname> object, but for now change sets
        are not stored atomically.
      </para>

      <para>
        A GConf key looks like a UNIX filename. Keys are organized
        into "directories" just as UNIX files are. For example, the
        <literal>/desktop</literal> directory stores desktop settings,
        and the hypothetical
        key <literal>/desktop/standard/background-color</literal> might
        store the color of the desktop background. The GConf
        documentation establishes a number of conventional directory
        names; you should follow the guidelines in the documentation
        when naming your application keys.        
      </para>

      <para>
        Values have types; the primitive types are integers, booleans, strings,
        and floating point numbers. Also, lists and pairs of primitive types are
        possible. Recursive types (list of list) are not permitted. Types have
        no size restriction; strings can be as long as you like, though
        unreasonably large strings (such as an entire XML document) will cause 
        performance problems.
      </para>

    </sect2>

    <sect2 id="gconfd">
      <title>Configuration Server</title>

      <para>
        GConf is implemented as a per-user daemon called
        <application>gconfd</application>.
        <application>gconfd</application> actually accesses the user's
        configuration backends by dynamically loading the appropriate
        backend modules. <application>gconfd</application> is also in
        charge of sending out notifications to interested applications
        when configuration values are modified.
      </para>

      <para>
        One <application>gconfd</application> should exist per user at
        any given time. If a user logs in to two machines
        simultaneously, <application>gconfd</application> will run on
        the first machine, and the second machine will access it over
        the network.
      </para>

      <para>
        <application>gconfd</application> talks to applications using
        CORBA as a transport. This is purely an implementation detail;
        a custom protocol over sockets could have been used or could
        be used in the future. Directly accessing the CORBA interface
        is <emphasis>not</emphasis> supported. Application programmers
        do not see CORBA while using GConf.
      </para>
      
      <para>
        In general, <application>gconfd</application> is not visible
        to the application programmer. It is automatically launched as
        required. (Internally, the OAF object activation framework is
        used to obtain an object reference for the
        <application>gconfd</application> CORBA server.)
      </para>

      <para>
        Because all database access goes via
        <application>gconfd</application>, locking is not really an
        issue. <application>gconfd</application> also aggressively
        caches configuration values, because all applications can
        share the same cache.
      </para>

    </sect2>

    <sect2 id="schemas">
      <title>Schemas</title>

      <para>
        In addition to the primitive types mentioned earlier (integer, string,
        etc.) the GConf database can store a <firstterm>schema</firstterm>. A
        schema is a description of a key; it includes a short description of the
        key, a longer documentation paragraph, the type of the key, a default
        value for the key, and the name of the application owning the
        key. Schemas are primarily intended for use by a regedit-style tool;
        such a tool can display the documentation for a key, and validate the
        type of any values you enter for the key.
      </para>

      <para>
        Because schemas are simply values in the database, they can be
        referenced by key name. Conventionally, all schemas are below
        the <literal>/schemas</literal> toplevel directory.
      </para>

      <para>
        Applications come with a special <firstterm>schema file</firstterm>
        which encodes the schema information in a human-editable text
        format. When the application is installed, the
        <application>gconftool</application> program shipped with GConf is used
        to insert the schema information into the GConf database. Also, all
        applications should install their schema file to a system-wide directory
        (specified in the GConf documentation). This allows system
        administrators to re-install all schemas into a different GConf backend
        with a single command (something like <literal>gconftool
        --install-schema-file /etc/gconf/schemas/*</literal>).
      </para>

    </sect2>

  </sect1>

  <sect1 id="api">
    <title>Application Programming</title>

    <para>
      GConf makes it as simple as possible for application programmers
      to store and retrieve their configuration data. However, the 
      general structure of configuration data storage and retrieval
      is somewhat different from the one you might use with
      configuration files.      
    </para>

    <sect2 id="mvc">
      <title>Model-View-Controller Architecture</title>
      <para>
        Applications using GConf effectively should structure their preferences
        and configuration code according to the famous
        <firstterm>Model-View-Controller</firstterm> (MVC) design pattern. In
        this pattern, your application contains three separate objects:

        <orderedlist>
          <listitem>
            <para>
              The <firstterm>model</firstterm> traditionally models 
              a real-world object; but more generally, it is the 
              data you are planning to present to the user and allow 
              the user to edit. In the GConf case, the model is 
              the configuration database (in the big picture) and a
              particular configuration key (from a smaller-scale point
              of view). For example, the configuration key <filename>
                /desktop/gnome/menus/show-icons</filename> can be 
              thought of as a model; it stores a boolean value
              indicating whether to show icons next to menu items
              in GNOME menus.
              </para>
            </listitem>
          <listitem>
            <para>
              The <firstterm>view</firstterm> somehow displays or
              represents your model. It receives some sort of
              notification when the model changes, and updates 
              itself accordingly. For example, the GNOME menu item
              widgets listen for changes to the  <filename>
                /desktop/gnome/menus/show-icons</filename>
              configuration key, and show or hide icons accordingly. 
              An important point about views is that there can be more
              than one of them; you can have many menu items, 
              without changing the model.
            </para>
            </listitem>
          <listitem>
            <para>
              The <firstterm>controller</firstterm> modifies the
              model. In the menu icons example, a GNOME control panel
              might be the controller; users use it to set the
              <filename>/desktop/gnome/menus/show-icons</filename> key
              to true or false.
            </para>
            </listitem>

          </orderedlist>              
      </para>
      
      <para>
        An MVC architecture has a number of advantages. Most notably,
        it encourages code reuse and modularity; you can have any
        number of views, and different types of views, without
        changing the model or the controller; you can have any number
        of controllers, and different types of controller, without
        changing the model or the view. The main controller may be the
        GNOME control panel, but if the key is changed by some other
        application, that will also work properly. The primary view
        may be the GNOME menu item code, but if some different menu
        item code wanted to monitor and honor this setting, it could
        certainly do so.
      </para>

      <para>
        GConf implements an exciting enhancement to the basic MVC
        pattern: the model is process-transparent. That is, the view
        and controller have no knowledge of which process contains the
        model; if you set a configuration key, then all views in all
        interested processes will be notified of the change.  In a
        world of component technology, this is extremely useful.
      </para>

      <para>
        All buzz-acronyms aside, all MVC means for you as an
        application programmer is that every section of code only has
        to be concerned with <emphasis>directly related</emphasis>
        configuration issues. For example, the menu item code only
        monitors the keys that affect how menu items are displayed. It
        is not concerned with any other keys, or with setting or
        saving that setting.
      </para>

      <para>
        In contrast, with a simple configuration file, typically you
        have a global data structure which stores all your
        preferences, and you load and save it as a single unit. To add
        a setting, you have to modify the global structure. Whenever
        you load settings, you have to add code to the global
        preferences code that knows about all the interested parts of
        the program and notifies them (via some ad-hoc
        mechanism). It's kind of unpleasant and leads to poor
        modularity in a single process; but once multiple processes
        are involved, coming up with a suitable ad-hoc mechanism for
        change notification becomes a really significant
        problem.
      </para>

    </sect2>

    <sect2 id="datatypes">
      <title>Major Data Types</title>

      <sect3 id="gconfengine">
      <title><structname>GConfEngine</structname></title>

        <para>
          A <structname>GConfEngine</structname> represents a
          configuration database (normally a connection to
          <application>gconfd</application>). You can store values in
          a <structname>GConfEngine</structname>, and retrieve values
          from one. You can also ask a
          <structname>GConfEngine</structname> to monitor a key or
          directory for changes, and invoke an application-supplied
          callback if changes occur. Each time you ask a
          <structname>GConfEngine</structname> to notify you of
          changes, it registers a request for notification with
          <application>gconfd</application>. Thus, notification
          requests are relatively expensive. With
          <structname>GConfClient</structname>, they are relatively
          cheap.
        </para>
      </sect3>

      <sect3>
        <title><structname>GConfClient</structname></title>
        <para>
          <structname>GConfClient</structname> is located in a separate library
          from GConf itself, because to use it you must link with
          GTK+. <structname>GConfClient</structname> derives from
          <structname>GtkObject</structname> and is a wrapper for the
          <structname>GConfEngine</structname> type.  It adds a few nice
          features:
          <itemizedlist>
            <listitem>
              <para>
                It can keep a client-side cache of values. Sometimes 
                this is just memory overhead, so you'll want to turn
                it off. However, if you access the same keys
                frequently it can be a performance win.                
              </para>
            </listitem>
            <listitem>
              <para>
                It can do client-side notification request dispatching. This
                means that if you want to monitor the keys
                <literal>/foo/bar</literal> and <literal>/foo/baz</literal>,
                <structname>GConfClient</structname> registers a single
                notification request with <application>gconfd</application>;
                when the notification comes from
                <application>gconfd</application>,
                <structname>GConfClient</structname> decides which key has
                changed and dispatches to the proper application callback. With
                <structname>GConfEngine</structname>, each callback involves
                registering a request with <application>gconfd</application>.
              </para>
            </listitem>
            <listitem>
              <para>
                It uses the GTK signal system. Instead of using
                GConf's custom callback API for notification, you can
                simply connect to a <literal>"value_changed"</literal>
                signal. 
              </para>
            </listitem>
            <listitem>
              <para>
                Finally, <structname>GConfClient</structname> provides
                default error handlers. This allows you to ignore
                errors, and let <structname>GConfClient</structname> 
                present them to the user via an error dialog.
              </para>
            </listitem>
          </itemizedlist>
        </para>
      </sect3>

      <sect3>
        <title><structname>GConfValue</structname></title>
        <para>
          When GConf needs to pass around a dynamically-typed value
          retrieved from or to be stored in the database, it uses a
          type-tagged union called
          <structname>GConfValue</structname>.  For example, the
          <function>gconf_engine_get ()</function> function takes a
          <structname>GConfEngine</structname> and a key name as
          arguments and returns a
          <structname>GConfValue</structname>. There are also
          convenience wrappers such as
          <function>gconf_engine_get_string()</function> and
          <function>gconf_engine_get_int()</function> that allow you to avoid
          the pesky <structname>GConfValue</structname> union.
        </para>
      </sect3>

      <sect3>
        <title><structname>GConfChangeSet</structname></title>
        <para>
          Modifications to the GConf database can be grouped into 
          <firstterm>change sets</firstterm>, or collections of changes.
          A change is a new value for a key, or a directive to unset a key's 
          current value. For now, the <structname>GConfChangeSet</structname>
          is primarily a convenience mechanism for managing the set of 
          changes a user has made via a preferences dialog. However, in the 
          future committing a change set may be an atomic operation (that is,
          GConf could be extended to support transactions).
        </para>
      </sect3>

      <sect3>
        <title><structname>GError</structname></title>
        <para>
          If you explicitly handle errors, rather than allowing the 
          <structname>GConfClient</structname> default error handler
          to report them to the user, you receive information about 
          an error in an object called
          <structname>GError</structname>. This contains a verbose
          error description, and an error code number.
        </para>
      </sect3>

    </sect2>

    <sect2 id="integration">
      <title>GNOME Integration</title>
      
      <para>
        Version 2.0 of GNOME automatically integrates with GConf, 
        making it simpler to use the library. It does the following:
        <itemizedlist>
          <listitem>
            <para>
              Keeps a global <structname>GConfClient</structname>
              that's easy to access with a
              <function>gnome_get_gconf_client()</function>
              function.
            </para>
          </listitem>
          <listitem>
            <para>
              Automatically uses GNOME dialogs for default error handling.
            </para>
          </listitem>
          <listitem>
            <para>
              Provides convenience functions to extract and insert 
              a <structname>GConfValue</structname> from various kinds
              of widget. For example, there is a function to 
              get the string inside a
              <structname>GtkEntry</structname> 
              as a <structname>GConfValue</structname>.
            </para>
          </listitem>
        </itemizedlist>

      </para>

    </sect2>

  </sect1>

  <sect1 id="example">
    <title>Coding Example</title>

    <para>
      This section contains two simple example programs; one displays
      the value of a key (and updates the displayed value when the key
      changes), and the other allows you to change the value of the
      same key. These examples should make the MVC architecture more
      concrete, and give you a general idea how the GConf API works.
    </para>

    <para>
      Although the examples use <structname>GConfClient</structname>,
      remember that it's also possible to use
      <structname>GConfEngine</structname> directly, to avoid linking
      to GTK. Also, in the next version of GTK and glib the object
      system will be moved to glib, so
      <structname>GConfClient</structname> can move to the main GConf
      library.
    </para>

    <sect2>
      <title>A Simple View</title>

      <para>
        This program creates a <structname>GtkLabel</structname> that
        displays the current value of the key
        <literal>/extra/test/directory/key</literal>. (By the way,
        directories do have conventional names, described in the GConf
        documentation; in this case, the directory
        <literal>/extra</literal> is similar to the
        <literal>X-</literal> prefix used in mail headers and MIME
        types, that is, it's for nonstandard extensions to the
        standard. Here our "nonstandard extension" is a trivial little
        test program.)
      </para>

      <para>
        I won't explain all the details of this program, since this
        article is just a general overview of GConf rather than a 
        full tutorial; the GConf documentation goes into detail 
        about the functions and data types you see here.
      </para>

      <para>
        <programlisting>
/* A very simple program that monitors a single key for changes. */

#include &lt;gconf/gconf-client.h&gt;
#include &lt;gtk/gtk.h&gt;

void
key_changed_callback(GConfClient* client,
                     guint cnxn_id,
                     const gchar* key,
                     GConfValue* value,
                     gboolean is_default,
                     gpointer user_data)
{
  GtkWidget* label;
  
  label = GTK_WIDGET(user_data);

  if (value == NULL)
    {
      gtk_label_set(GTK_LABEL(label), "&lt;unset&gt;");
    }
  else
    {
      if (value-&gt;type == GCONF_VALUE_STRING)
        {
          gtk_label_set(GTK_LABEL(label), gconf_value_string(value));
        }
      else
        {
          gtk_label_set(GTK_LABEL(label), "&lt;wrong type&gt;");
        }
    }
}

int
main(int argc, char** argv)
{
  GtkWidget* window;
  GtkWidget* label;
  GConfClient* client;
  gchar* str;
  
  gtk_init(&amp;argc, &amp;argv);
  gconf_init(argc, argv, NULL);

  client = gconf_client_get_default();
  
  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);

  str = gconf_client_get_string(client, "/extra/test/directory/key",
                                NULL);
  
  label = gtk_label_new(str ? str : "&lt;unset&gt;");

  if (str)
    g_free(str);
  
  gtk_container_add(GTK_CONTAINER(window), label);

  gconf_client_add_dir(client,
                       "/extra/test/directory",
                       GCONF_CLIENT_PRELOAD_NONE,
                       NULL);

  gconf_client_notify_add(client, "/extra/test/directory/key",
                          key_changed_callback,
                          label,
                          NULL, NULL);
  
  gtk_widget_show_all(window);

  gtk_main();

  return 0;
}
        </programlisting>
      </para>

    </sect2>
    
    <sect2>
      <title>A Simple Controller</title>

      <para>
        This controller pops up a window with an entry box; if you
        type in the entry box and press return, the box contents will
        become the new value of the key
        <literal>/extra/test/directory/key</literal>. If you have the
        view program running, then its label should update to reflect 
        the new value.
      </para>

      <para>
        Again, see the GConf documentation for full details.
      </para>


      <para>
        <programlisting>
/* A very simple program that sets a single key value when you type
   it in an entry and press return */

#include &lt;gconf/gconf-client.h&gt;
#include &lt;gtk/gtk.h&gt;

void
entry_activated_callback(GtkWidget* entry, gpointer user_data)
{
  GConfClient* client;
  gchar* str;
  
  client = GCONF_CLIENT(user_data);

  str = gtk_editable_get_chars(GTK_EDITABLE(entry), 0, -1);

  gconf_client_set_string(client, "/extra/test/directory/key",
                          str, NULL);

  g_free(str);
}

int
main(int argc, char** argv)
{
  GtkWidget* window;
  GtkWidget* entry;
  GConfClient* client;

  gtk_init(&amp;argc, &amp;argv);
  gconf_init(argc, argv, NULL);
  
  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  entry = gtk_entry_new();

  gtk_container_add(GTK_CONTAINER(window), entry);  

  client = gconf_client_get_default();

  gconf_client_add_dir(client,
                       "/extra/test/directory",
                       GCONF_CLIENT_PRELOAD_NONE,
                       NULL);


  gtk_signal_connect(GTK_OBJECT(entry), "activate",
                     GTK_SIGNAL_FUNC(entry_activated_callback),
                     client);
  
  gtk_widget_show_all(window);

  gtk_main();

  return 0;
}
        </programlisting>
      </para>

    </sect2>

  </sect1>

  <appendix id="links">
    <title>Other Resources</title>
    <para>
      <itemizedlist>
	<listitem>
	  <para>
	    <ulink url="http://developer.gnome.org">GNOME Developer Site</ulink>
	  </para>
	</listitem>
	<listitem>
	  <para>
	    <ulink url="http://developer.gnome.org/doc/API/gconf/index.html">GConf Documentation</ulink>
	  </para>
	</listitem>
      </itemizedlist>
    </para>
  </appendix>
  
</article>