~ubuntu-branches/ubuntu/quantal/gconf/quantal

« back to all changes in this revision

Viewing changes to wrappers/gtk/gconf-client.c

  • Committer: Bazaar Package Importer
  • Author(s): Takuo KITAME
  • Date: 2002-03-17 01:51:39 UTC
  • Revision ID: james.westby@ubuntu.com-20020317015139-z4f8fdg1hoe049g0
Tags: upstream-1.0.9
ImportĀ upstreamĀ versionĀ 1.0.9

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 
2
/* GConf
 
3
 * Copyright (C) 1999, 2000, 2000 Red Hat Inc.
 
4
 *
 
5
 * This library is free software; you can redistribute it and/or
 
6
 * modify it under the terms of the GNU Library General Public
 
7
 * License as published by the Free Software Foundation; either
 
8
 * version 2 of the License, or (at your option) any later version.
 
9
 *
 
10
 * This library is distributed in the hope that it will be useful,
 
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
13
 * Library General Public License for more details.
 
14
 *
 
15
 * You should have received a copy of the GNU Library General Public
 
16
 * License along with this library; if not, write to the
 
17
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 
18
 * Boston, MA 02111-1307, USA.
 
19
 */
 
20
 
 
21
#include <stdio.h>
 
22
#include "gconf-client.h"
 
23
#include <gtk/gtksignal.h>
 
24
#include <gtk/gtktypeutils.h>
 
25
#include <gconf/gconf-internals.h>
 
26
 
 
27
/*
 
28
 * Error handler override
 
29
 */
 
30
 
 
31
static GConfClientErrorHandlerFunc global_error_handler = NULL;
 
32
 
 
33
void
 
34
gconf_client_set_global_default_error_handler(GConfClientErrorHandlerFunc func)
 
35
{
 
36
  global_error_handler = func;
 
37
}
 
38
 
 
39
/*
 
40
 * CacheEntry
 
41
 */ 
 
42
 
 
43
typedef struct _CacheEntry CacheEntry;
 
44
 
 
45
struct _CacheEntry {
 
46
  GConfValue* value;
 
47
  /* Whether "value" was a default from a schema; i.e.
 
48
     if this is TRUE, then value wasn't set, we just used
 
49
     a default. */
 
50
  guint is_default : 1;
 
51
  guint is_writable : 1;
 
52
};
 
53
 
 
54
static CacheEntry* cache_entry_new(GConfValue* val,
 
55
                                   gboolean is_default,
 
56
                                   gboolean is_writable);
 
57
static void        cache_entry_destroy(CacheEntry* ce);
 
58
 
 
59
/*
 
60
 * Dir object (for list of directories we're watching)
 
61
 */
 
62
 
 
63
typedef struct _Dir Dir;
 
64
 
 
65
struct _Dir {
 
66
  gchar* name;
 
67
  guint notify_id;
 
68
  /* number of times this dir has been added */
 
69
  guint add_count;
 
70
};
 
71
 
 
72
static Dir* dir_new(const gchar* name, guint notify_id);
 
73
static void dir_destroy(Dir* d);
 
74
 
 
75
/*
 
76
 * Listener object
 
77
 */
 
78
 
 
79
typedef struct _Listener Listener;
 
80
 
 
81
struct _Listener {
 
82
  GConfClientNotifyFunc func;
 
83
  gpointer data;
 
84
  GFreeFunc destroy_notify;
 
85
};
 
86
 
 
87
static Listener* listener_new(GConfClientNotifyFunc func,
 
88
                              GFreeFunc destroy_notify,
 
89
                              gpointer data);
 
90
 
 
91
static void listener_destroy(Listener* l);
 
92
 
 
93
/*
 
94
 * GConfClient proper
 
95
 */
 
96
 
 
97
 
 
98
enum {
 
99
  VALUE_CHANGED,
 
100
  UNRETURNED_ERROR,
 
101
  ERROR,
 
102
  LAST_SIGNAL
 
103
};
 
104
 
 
105
static void         register_client   (GConfClient *client);
 
106
static GConfClient *lookup_client     (GConfEngine *engine);
 
107
static void         unregister_client (GConfClient *client);
 
108
 
 
109
static void gconf_client_class_init (GConfClientClass *klass);
 
110
static void gconf_client_init       (GConfClient      *client);
 
111
static void gconf_client_real_unreturned_error (GConfClient* client, GError* error);
 
112
static void gconf_client_real_error            (GConfClient* client, GError* error);
 
113
static void gconf_client_finalize              (GtkObject* object); 
 
114
 
 
115
static void gconf_client_cache                 (GConfClient* client,
 
116
                                                const gchar* key,
 
117
                                                gboolean is_default,
 
118
                                                gboolean is_writable,
 
119
                                                GConfValue* value); /* takes ownership of value */
 
120
 
 
121
static gboolean gconf_client_lookup         (GConfClient* client,
 
122
                                             const gchar* key,
 
123
                                             gboolean use_default,
 
124
                                             gboolean* is_default,
 
125
                                             gboolean* is_writable,
 
126
                                             GConfValue** valp);
 
127
 
 
128
static void gconf_client_real_remove_dir    (GConfClient* client,
 
129
                                             Dir* d,
 
130
                                             GError** err);
 
131
 
 
132
static GConfValue* get (GConfClient  *client,
 
133
                        const gchar  *key,
 
134
                        gboolean      use_default,
 
135
                        gboolean     *is_default_retloc,
 
136
                        gboolean     *is_writable_retloc,
 
137
                        GError      **error);
 
138
 
 
139
 
 
140
static guint client_signals[LAST_SIGNAL] = { 0 };
 
141
static GtkObjectClass* parent_class = NULL;
 
142
 
 
143
GtkType
 
144
gconf_client_get_type (void)
 
145
{
 
146
  static GtkType client_type = 0;
 
147
 
 
148
  if (!client_type)
 
149
    {
 
150
      static const GtkTypeInfo client_info =
 
151
      {
 
152
        "GConfClient",
 
153
        sizeof (GConfClient),
 
154
        sizeof (GConfClientClass),
 
155
        (GtkClassInitFunc) gconf_client_class_init,
 
156
        (GtkObjectInitFunc) gconf_client_init,
 
157
        /* reserved_1 */ NULL,
 
158
        /* reserved_2 */ NULL,
 
159
        (GtkClassInitFunc) NULL,
 
160
      };
 
161
 
 
162
      client_type = gtk_type_unique (GTK_TYPE_OBJECT, &client_info);
 
163
    }
 
164
 
 
165
  return client_type;
 
166
}
 
167
 
 
168
static void
 
169
gconf_client_class_init (GConfClientClass *class)
 
170
{
 
171
  GtkObjectClass *object_class;
 
172
 
 
173
  object_class = (GtkObjectClass*) class;
 
174
 
 
175
  parent_class = gtk_type_class (gtk_object_get_type ());
 
176
  
 
177
  client_signals[VALUE_CHANGED] =
 
178
    gtk_signal_new ("value_changed",
 
179
                    GTK_RUN_LAST,
 
180
                    object_class->type,
 
181
                    GTK_SIGNAL_OFFSET (GConfClientClass, value_changed),
 
182
                    gtk_marshal_NONE__POINTER_POINTER,
 
183
                    GTK_TYPE_NONE, 2, GTK_TYPE_POINTER, GTK_TYPE_POINTER);
 
184
  
 
185
  client_signals[UNRETURNED_ERROR] =
 
186
    gtk_signal_new ("unreturned_error",
 
187
                    GTK_RUN_LAST,
 
188
                    object_class->type,
 
189
                    GTK_SIGNAL_OFFSET (GConfClientClass, unreturned_error),
 
190
                    gtk_marshal_NONE__POINTER,
 
191
                    GTK_TYPE_NONE, 1, GTK_TYPE_POINTER);
 
192
 
 
193
  client_signals[ERROR] =
 
194
    gtk_signal_new ("error",
 
195
                    GTK_RUN_LAST,
 
196
                    object_class->type,
 
197
                    GTK_SIGNAL_OFFSET (GConfClientClass, error),
 
198
                    gtk_marshal_NONE__POINTER,
 
199
                    GTK_TYPE_NONE, 1, GTK_TYPE_POINTER);
 
200
  
 
201
  gtk_object_class_add_signals (object_class, client_signals, LAST_SIGNAL);
 
202
 
 
203
  class->value_changed    = NULL;
 
204
  class->unreturned_error = gconf_client_real_unreturned_error;
 
205
  class->error            = gconf_client_real_error;
 
206
  
 
207
  object_class->finalize  = gconf_client_finalize;
 
208
}
 
209
 
 
210
static void
 
211
gconf_client_init (GConfClient *client)
 
212
{
 
213
  client->engine = NULL;
 
214
  client->error_mode = GCONF_CLIENT_HANDLE_UNRETURNED;
 
215
  client->dir_hash = g_hash_table_new(g_str_hash, g_str_equal);
 
216
  client->cache_hash = g_hash_table_new(g_str_hash, g_str_equal);
 
217
  /* We create the listeners only if they're actually used */
 
218
  client->listeners = NULL;
 
219
}
 
220
 
 
221
static gboolean
 
222
destroy_dir_foreach_remove(gpointer key, gpointer value, gpointer user_data)
 
223
{
 
224
  GConfClient *client = user_data;
 
225
  Dir* d = value;
 
226
  
 
227
  /* remove notify for this dir */
 
228
  
 
229
  if(d->notify_id != 0)
 
230
          gconf_engine_notify_remove(client->engine, d->notify_id);
 
231
  d->notify_id = 0;
 
232
 
 
233
  dir_destroy(value);
 
234
 
 
235
  return TRUE;
 
236
}
 
237
 
 
238
static void
 
239
gconf_client_finalize (GtkObject* object)
 
240
{
 
241
  GConfClient* client = GCONF_CLIENT(object);
 
242
 
 
243
  g_hash_table_foreach_remove(client->dir_hash,
 
244
                              destroy_dir_foreach_remove, client);
 
245
  
 
246
  gconf_client_clear_cache(client);
 
247
  
 
248
  if (client->listeners != NULL)
 
249
    {
 
250
      gconf_listeners_free(client->listeners);
 
251
      client->listeners = NULL;
 
252
    }
 
253
 
 
254
  g_hash_table_destroy(client->dir_hash);
 
255
  client->dir_hash = NULL;
 
256
  
 
257
  g_hash_table_destroy(client->cache_hash);
 
258
  client->cache_hash = NULL;
 
259
 
 
260
  unregister_client (client);
 
261
  
 
262
  if (client->engine != NULL)
 
263
    {
 
264
      gconf_engine_unref(client->engine);
 
265
      client->engine = NULL;
 
266
    }
 
267
 
 
268
  if (parent_class->finalize)
 
269
    (*parent_class->finalize)(object);
 
270
}
 
271
 
 
272
/*
 
273
 * Default error handlers
 
274
 */
 
275
 
 
276
static void
 
277
gconf_client_real_unreturned_error (GConfClient* client, GError* error)
 
278
{
 
279
  if (client->error_mode == GCONF_CLIENT_HANDLE_UNRETURNED)
 
280
    {
 
281
      if (global_error_handler != NULL)
 
282
        {
 
283
          (*global_error_handler) (client, error);
 
284
        }
 
285
      else
 
286
        {
 
287
          fprintf (stderr, _("GConf Error: %s\n"),
 
288
                   error->message);
 
289
        }
 
290
    }
 
291
}
 
292
 
 
293
static void
 
294
gconf_client_real_error            (GConfClient* client, GError* error)
 
295
{
 
296
  if (client->error_mode == GCONF_CLIENT_HANDLE_ALL)
 
297
    {
 
298
      if (global_error_handler != NULL)
 
299
        {
 
300
          (*global_error_handler) (client, error);
 
301
        }
 
302
      else
 
303
        {
 
304
          fprintf (stderr, _("GConf Error: %s\n"),
 
305
                   error->message);
 
306
        }
 
307
    }
 
308
}
 
309
 
 
310
/* Emit the proper signals for the error, and fill in err */
 
311
static gboolean
 
312
handle_error(GConfClient* client, GError* error, GError** err)
 
313
{
 
314
  if (error != NULL)
 
315
    {
 
316
      gconf_client_error(client, error);
 
317
      
 
318
      if (err == NULL)
 
319
        {
 
320
          gconf_client_unreturned_error(client, error);
 
321
 
 
322
          g_error_free(error);
 
323
        }
 
324
      else
 
325
        *err = error;
 
326
 
 
327
      return TRUE;
 
328
    }
 
329
  else
 
330
    return FALSE;
 
331
}
 
332
 
 
333
struct client_and_val {
 
334
  GConfClient* client;
 
335
  GConfEntry* entry;
 
336
};
 
337
 
 
338
static void
 
339
notify_listeners_callback(GConfListeners* listeners,
 
340
                          const gchar* key,
 
341
                          guint cnxn_id,
 
342
                          gpointer listener_data,
 
343
                          gpointer user_data)
 
344
{
 
345
  struct client_and_val* cav = user_data;
 
346
  Listener* l = listener_data;
 
347
  
 
348
  g_return_if_fail(cav != NULL);
 
349
  g_return_if_fail(cav->client != NULL);
 
350
  g_return_if_fail(GCONF_IS_CLIENT(cav->client));
 
351
  g_return_if_fail(l != NULL);
 
352
  g_return_if_fail(l->func != NULL);
 
353
 
 
354
  (*l->func)(cav->client, cnxn_id, cav->entry, l->data);
 
355
}
 
356
 
 
357
static void
 
358
notify_from_server_callback(GConfEngine* conf, guint cnxn_id,
 
359
                            GConfEntry *entry,
 
360
                            gpointer user_data)
 
361
{
 
362
  GConfClient* client = user_data;
 
363
 
 
364
  g_return_if_fail(client != NULL);
 
365
  g_return_if_fail(GCONF_IS_CLIENT(client));
 
366
  g_return_if_fail(client->engine == conf);
 
367
 
 
368
  /* First do the caching, so that state is sane for the
 
369
   * listeners or functions connected to value_changed.
 
370
   * We know this key is under a directory in our dir list.
 
371
   */
 
372
  gconf_client_cache(client,
 
373
                     entry->key,
 
374
                     entry->is_default,
 
375
                     entry->is_writable,
 
376
                     entry->value ? gconf_value_copy(entry->value) : NULL);
 
377
 
 
378
  /* Emit the value_changed signal before notifying specific listeners;
 
379
   * I'm not sure there's a reason this matters though
 
380
   */
 
381
  gconf_client_value_changed(client,
 
382
                             entry->key,
 
383
                             entry->value);
 
384
 
 
385
  /* Now notify our listeners, if any */
 
386
  if (client->listeners != NULL)
 
387
    {
 
388
      struct client_and_val cav;
 
389
 
 
390
      cav.client = client;
 
391
      cav.entry = entry;
 
392
      
 
393
      gconf_listeners_notify(client->listeners,
 
394
                             entry->key,
 
395
                             notify_listeners_callback,
 
396
                             &cav);
 
397
    }
 
398
}
 
399
 
 
400
/*
 
401
 * Public API
 
402
 */
 
403
 
 
404
GConfClient*
 
405
gconf_client_get_default (void)
 
406
{
 
407
  GConfClient *client;
 
408
  GConfEngine *engine;
 
409
  
 
410
  g_return_val_if_fail(gconf_is_initialized(), NULL);
 
411
 
 
412
  engine = gconf_engine_get_default ();
 
413
  
 
414
  client = lookup_client (engine);
 
415
  if (client)
 
416
    {
 
417
      g_assert (client->engine == engine);
 
418
      gtk_object_ref (GTK_OBJECT (client));
 
419
      gconf_engine_unref (engine);
 
420
      return client;
 
421
    }
 
422
  else
 
423
    {
 
424
      client = gtk_type_new (gconf_client_get_type ());
 
425
 
 
426
      /* Emulate GObject */
 
427
      gtk_object_ref (GTK_OBJECT (client));
 
428
      gtk_object_sink (GTK_OBJECT (client));
 
429
 
 
430
      client->engine = engine;
 
431
      register_client (client);
 
432
    }
 
433
  
 
434
  return client;
 
435
}
 
436
 
 
437
GConfClient*
 
438
gconf_client_get_for_engine (GConfEngine* engine)
 
439
{
 
440
  GConfClient *client;
 
441
 
 
442
  g_return_val_if_fail(gconf_is_initialized(), NULL);
 
443
 
 
444
  client = lookup_client (engine);
 
445
  if (client)
 
446
    {
 
447
      g_assert (client->engine == engine);
 
448
      gtk_object_ref (GTK_OBJECT (client));
 
449
      return client;
 
450
    }
 
451
  else
 
452
    {
 
453
      client = gtk_type_new (gconf_client_get_type ());
 
454
 
 
455
      /* Emulate GObject */
 
456
      gtk_object_ref (GTK_OBJECT (client));
 
457
      gtk_object_sink (GTK_OBJECT (client));
 
458
      
 
459
      client->engine = engine;
 
460
 
 
461
      gconf_engine_ref(client->engine);
 
462
 
 
463
      register_client (client);
 
464
    }
 
465
  
 
466
  return client;
 
467
}
 
468
 
 
469
typedef struct {
 
470
  GConfClient *client;
 
471
  Dir *lower_dir;
 
472
  const char *dirname;
 
473
} OverlapData;
 
474
 
 
475
static void
 
476
foreach_setup_overlap(gpointer key, gpointer value, gpointer user_data)
 
477
{
 
478
  GConfClient *client;
 
479
  Dir *dir = value;
 
480
  OverlapData * od = user_data;
 
481
 
 
482
  client = od->client;
 
483
 
 
484
  /* if we have found the first (well there is only one anyway) directory
 
485
   * that includes us that has a notify handler
 
486
   */
 
487
#ifdef GCONF_ENABLE_DEBUG
 
488
  if (dir->notify_id != 0 &&
 
489
      gconf_key_is_below(dir->name, od->dirname))
 
490
    {
 
491
      g_assert(od->lower_dir == NULL);
 
492
      od->lower_dir = dir;
 
493
    }
 
494
#else
 
495
  if (od->lower_dir == NULL &&
 
496
      dir->notify_id != 0 &&
 
497
      gconf_key_is_below(dir->name, od->dirname))
 
498
      od->lower_dir = dir;
 
499
#endif
 
500
  /* if we have found a directory that we include and it has
 
501
   * a notify_id, remove the notify handler now
 
502
   * FIXME: this is a race, from now on we can miss notifies, it is
 
503
   * not an incredible amount of time so this is not a showstopper */
 
504
  else if (dir->notify_id != 0 &&
 
505
           gconf_key_is_below (od->dirname, dir->name))
 
506
    {
 
507
      gconf_engine_notify_remove (client->engine, dir->notify_id);
 
508
      dir->notify_id = 0;
 
509
    }
 
510
}
 
511
 
 
512
static Dir *
 
513
setup_overlaps(GConfClient* client, const gchar* dirname)
 
514
{
 
515
  OverlapData od;
 
516
 
 
517
  od.client = client;
 
518
  od.lower_dir = NULL;
 
519
  od.dirname = dirname;
 
520
 
 
521
  g_hash_table_foreach(client->dir_hash, foreach_setup_overlap, &od);
 
522
 
 
523
  return od.lower_dir;
 
524
}
 
525
 
 
526
void
 
527
gconf_client_add_dir     (GConfClient* client,
 
528
                          const gchar* dirname,
 
529
                          GConfClientPreloadType preload,
 
530
                          GError** err)
 
531
{
 
532
  Dir* d;
 
533
  guint notify_id = 0;
 
534
  GError* error = NULL;
 
535
 
 
536
  g_return_if_fail(gconf_valid_key(dirname, NULL));
 
537
  
 
538
  d = g_hash_table_lookup (client->dir_hash, dirname);
 
539
 
 
540
  if (d == NULL)
 
541
    {
 
542
      Dir *overlap_dir;
 
543
 
 
544
      overlap_dir = setup_overlaps (client, dirname);
 
545
 
 
546
      /* only if there is no directory that includes us
 
547
       * already add a notify
 
548
       */
 
549
      if (overlap_dir == NULL)
 
550
        {
 
551
 
 
552
          notify_id = gconf_engine_notify_add (client->engine,
 
553
                                               dirname,
 
554
                                               notify_from_server_callback,
 
555
                                               client,
 
556
                                               &error);
 
557
      
 
558
          /* We got a notify ID or we got an error, not both */
 
559
          g_return_if_fail( (notify_id != 0 && error == NULL) ||
 
560
                            (notify_id == 0 && error != NULL) );
 
561
      
 
562
      
 
563
          if (handle_error(client, error, err))
 
564
            return;
 
565
 
 
566
          g_assert(error == NULL);
 
567
        }
 
568
      else
 
569
        {
 
570
          notify_id = 0;
 
571
        }
 
572
      
 
573
      d = dir_new(dirname, notify_id);
 
574
 
 
575
      g_hash_table_insert(client->dir_hash, d->name, d);
 
576
 
 
577
      gconf_client_preload(client, dirname, preload, &error);
 
578
 
 
579
      handle_error(client, error, err);
 
580
    }
 
581
 
 
582
  g_assert(d != NULL);
 
583
 
 
584
  d->add_count += 1;
 
585
}
 
586
 
 
587
typedef struct {
 
588
  GConfClient *client;
 
589
  GError *error;
 
590
} AddNotifiesData;
 
591
 
 
592
static void
 
593
foreach_add_notifies(gpointer key, gpointer value, gpointer user_data)
 
594
{
 
595
  AddNotifiesData *ad = user_data;
 
596
  GConfClient *client;
 
597
  Dir *dir = value;
 
598
 
 
599
  client = ad->client;
 
600
 
 
601
  if (ad->error != NULL)
 
602
    return;
 
603
 
 
604
  if (dir->notify_id == 0)
 
605
    {
 
606
      Dir *overlap_dir;
 
607
      overlap_dir = setup_overlaps(client, dir->name);
 
608
 
 
609
      /* only if there is no directory that includes us
 
610
       * already add a notify */
 
611
      if (overlap_dir == NULL)
 
612
        {
 
613
          dir->notify_id = gconf_engine_notify_add(client->engine,
 
614
                                            dir->name,
 
615
                                            notify_from_server_callback,
 
616
                                            client,
 
617
                                            &ad->error);
 
618
 
 
619
          /* We got a notify ID or we got an error, not both */
 
620
          g_return_if_fail( (dir->notify_id != 0 && ad->error == NULL) ||
 
621
                            (dir->notify_id == 0 && ad->error != NULL) );
 
622
 
 
623
          /* if error is returned, then we'll just ignore
 
624
           * things until the end */
 
625
        }
 
626
    }
 
627
}
 
628
 
 
629
static void
 
630
gconf_client_real_remove_dir    (GConfClient* client,
 
631
                                 Dir* d,
 
632
                                 GError** err)
 
633
{
 
634
  AddNotifiesData ad;
 
635
 
 
636
  g_return_if_fail(d != NULL);
 
637
  g_return_if_fail(d->add_count == 0);
 
638
  
 
639
  g_hash_table_remove(client->dir_hash, d->name);
 
640
  
 
641
  /* remove notify for this dir */
 
642
  
 
643
  if (d->notify_id != 0)
 
644
    gconf_engine_notify_remove(client->engine, d->notify_id);
 
645
  d->notify_id = 0;
 
646
  
 
647
  dir_destroy(d);
 
648
 
 
649
  ad.client = client;
 
650
  ad.error = NULL;
 
651
 
 
652
  g_hash_table_foreach(client->dir_hash, foreach_add_notifies, &ad);
 
653
 
 
654
  handle_error(client, ad.error, err);
 
655
}
 
656
 
 
657
void
 
658
gconf_client_remove_dir  (GConfClient* client,
 
659
                          const gchar* dirname,
 
660
                          GError** err)
 
661
{
 
662
  Dir* found = NULL;
 
663
 
 
664
  found = g_hash_table_lookup(client->dir_hash,
 
665
                              dirname);
 
666
  
 
667
  if (found != NULL)
 
668
    {
 
669
      g_return_if_fail(found->add_count > 0);
 
670
 
 
671
      found->add_count -= 1;
 
672
 
 
673
      if (found->add_count == 0) 
 
674
        gconf_client_real_remove_dir(client, found, err);
 
675
    }
 
676
#ifndef G_DISABLE_CHECKS
 
677
  else
 
678
    g_warning("Directory `%s' was not being monitored by GConfClient %p",
 
679
              dirname, client);
 
680
#endif
 
681
}
 
682
 
 
683
 
 
684
guint
 
685
gconf_client_notify_add(GConfClient* client,
 
686
                        const gchar* namespace_section,
 
687
                        GConfClientNotifyFunc func,
 
688
                        gpointer user_data,
 
689
                        GFreeFunc destroy_notify,
 
690
                        GError** err)
 
691
{
 
692
  guint cnxn_id = 0;
 
693
  
 
694
  g_return_val_if_fail(client != NULL, 0);
 
695
  g_return_val_if_fail(GCONF_IS_CLIENT(client), 0);
 
696
 
 
697
  if (client->listeners == NULL)
 
698
    client->listeners = gconf_listeners_new();
 
699
  
 
700
  cnxn_id = gconf_listeners_add (client->listeners,
 
701
                                 namespace_section,
 
702
                                 listener_new (func, destroy_notify, user_data),
 
703
                                 (GFreeFunc)listener_destroy);
 
704
 
 
705
  return cnxn_id;
 
706
}
 
707
 
 
708
void
 
709
gconf_client_notify_remove  (GConfClient* client,
 
710
                             guint cnxn)
 
711
{
 
712
  g_return_if_fail(client != NULL);
 
713
  g_return_if_fail(GCONF_IS_CLIENT(client));
 
714
  g_return_if_fail(client->listeners != NULL);
 
715
  
 
716
  gconf_listeners_remove(client->listeners, cnxn);
 
717
  
 
718
  if (gconf_listeners_count(client->listeners) == 0)
 
719
    {
 
720
      gconf_listeners_free(client->listeners);
 
721
      client->listeners = NULL;
 
722
    }
 
723
}
 
724
 
 
725
void
 
726
gconf_client_set_error_handling(GConfClient* client,
 
727
                                GConfClientErrorHandlingMode mode)
 
728
{
 
729
  g_return_if_fail(client != NULL);
 
730
  g_return_if_fail(GCONF_IS_CLIENT(client));
 
731
 
 
732
  client->error_mode = mode;
 
733
}
 
734
 
 
735
static gboolean
 
736
clear_cache_foreach(gchar* key, CacheEntry* ce, GConfClient* client)
 
737
{
 
738
  g_free(key);
 
739
  cache_entry_destroy(ce);
 
740
 
 
741
  return TRUE;
 
742
}
 
743
 
 
744
void
 
745
gconf_client_clear_cache(GConfClient* client)
 
746
{
 
747
  g_return_if_fail(client != NULL);
 
748
  g_return_if_fail(GCONF_IS_CLIENT(client));
 
749
  
 
750
  g_hash_table_foreach_remove(client->cache_hash, (GHRFunc)clear_cache_foreach,
 
751
                              client);
 
752
 
 
753
  g_assert(g_hash_table_size(client->cache_hash) == 0);
 
754
}
 
755
 
 
756
static void
 
757
cache_pairs_in_dir(GConfClient* client, const gchar* path);
 
758
 
 
759
static void 
 
760
recurse_subdir_list(GConfClient* client, GSList* subdirs, const gchar* parent)
 
761
{
 
762
  GSList* tmp;
 
763
 
 
764
  tmp = subdirs;
 
765
  
 
766
  while (tmp != NULL)
 
767
    {
 
768
      gchar* s = tmp->data;
 
769
      gchar* full = gconf_concat_dir_and_key(parent, s);
 
770
      
 
771
      cache_pairs_in_dir(client, full);
 
772
 
 
773
      recurse_subdir_list(client, gconf_engine_all_dirs(client->engine, full, NULL), full);
 
774
 
 
775
      g_free(s);
 
776
      g_free(full);
 
777
      
 
778
      tmp = g_slist_next(tmp);
 
779
    }
 
780
  
 
781
  g_slist_free(subdirs);
 
782
}
 
783
 
 
784
static void 
 
785
cache_pairs_in_dir(GConfClient* client, const gchar* dir)
 
786
{
 
787
  GSList* pairs;
 
788
  GSList* tmp;
 
789
  GError* error = NULL;
 
790
 
 
791
  pairs = gconf_engine_all_entries(client->engine, dir, &error);
 
792
          
 
793
  if (error != NULL)
 
794
    {
 
795
      fprintf(stderr, _("GConf warning: failure listing pairs in `%s': %s"),
 
796
              dir, error->message);
 
797
      g_error_free(error);
 
798
      error = NULL;
 
799
    }
 
800
 
 
801
  if (pairs != NULL)
 
802
    {
 
803
      tmp = pairs;
 
804
 
 
805
      while (tmp != NULL)
 
806
        {
 
807
          GConfEntry* pair = tmp->data;
 
808
          
 
809
          gconf_client_cache(client,
 
810
                             gconf_entry_get_key (pair),
 
811
                             gconf_entry_get_is_default(pair),
 
812
                             gconf_entry_get_is_writable(pair),
 
813
                             gconf_entry_steal_value(pair));
 
814
 
 
815
          gconf_entry_free(pair);
 
816
 
 
817
          tmp = g_slist_next(tmp);
 
818
        }
 
819
 
 
820
      g_slist_free(pairs);
 
821
    }
 
822
}
 
823
 
 
824
void
 
825
gconf_client_preload    (GConfClient* client,
 
826
                         const gchar* dirname,
 
827
                         GConfClientPreloadType type,
 
828
                         GError** err)
 
829
{
 
830
 
 
831
  g_return_if_fail(client != NULL);
 
832
  g_return_if_fail(GCONF_IS_CLIENT(client));
 
833
  g_return_if_fail(dirname != NULL);
 
834
 
 
835
#ifdef GCONF_ENABLE_DEBUG
 
836
  if (g_hash_table_lookup(client->dir_hash, dirname) == NULL)
 
837
    {
 
838
      g_warning("Can only preload directories you've added with gconf_client_add_dir()");
 
839
      return;
 
840
    }
 
841
#endif
 
842
  
 
843
  switch (type)
 
844
    {
 
845
    case GCONF_CLIENT_PRELOAD_NONE:
 
846
      /* nothing */
 
847
      break;
 
848
 
 
849
    case GCONF_CLIENT_PRELOAD_ONELEVEL:
 
850
      {
 
851
        GSList* subdirs;
 
852
        
 
853
        subdirs = gconf_engine_all_dirs(client->engine, dirname, NULL);
 
854
        
 
855
        cache_pairs_in_dir(client, dirname);
 
856
      }
 
857
      break;
 
858
 
 
859
    case GCONF_CLIENT_PRELOAD_RECURSIVE:
 
860
      {
 
861
        GSList* subdirs;
 
862
        
 
863
        subdirs = gconf_engine_all_dirs(client->engine, dirname, NULL);
 
864
        
 
865
        cache_pairs_in_dir(client, dirname);
 
866
          
 
867
        recurse_subdir_list(client, subdirs, dirname);
 
868
      }
 
869
      break;
 
870
 
 
871
    default:
 
872
      g_assert_not_reached();
 
873
      break;
 
874
    }
 
875
}
 
876
 
 
877
/*
 
878
 * Basic key-manipulation facilities
 
879
 */
 
880
 
 
881
void
 
882
gconf_client_set             (GConfClient* client,
 
883
                              const gchar* key,
 
884
                              GConfValue* val,
 
885
                              GError** err)
 
886
{
 
887
  GError* error = NULL;
 
888
  
 
889
  gconf_engine_set (client->engine, key, val, &error);
 
890
 
 
891
  handle_error(client, error, err);
 
892
}
 
893
 
 
894
gboolean
 
895
gconf_client_unset          (GConfClient* client,
 
896
                             const gchar* key, GError** err)
 
897
{
 
898
  GError* error = NULL;
 
899
  
 
900
  gconf_engine_unset(client->engine, key, &error);
 
901
 
 
902
  handle_error(client, error, err);
 
903
 
 
904
  if (error != NULL)
 
905
    return FALSE;
 
906
  else
 
907
    return TRUE;
 
908
}
 
909
 
 
910
GSList*
 
911
gconf_client_all_entries    (GConfClient* client,
 
912
                             const gchar* dir, GError** err)
 
913
{
 
914
  GError* error = NULL;
 
915
  GSList* retval;
 
916
  
 
917
  retval = gconf_engine_all_entries(client->engine, dir, &error);
 
918
 
 
919
  handle_error(client, error, err);
 
920
 
 
921
  return retval;
 
922
}
 
923
 
 
924
GSList*
 
925
gconf_client_all_dirs       (GConfClient* client,
 
926
                             const gchar* dir, GError** err)
 
927
{
 
928
  GError* error = NULL;
 
929
  GSList* retval;
 
930
  
 
931
  retval = gconf_engine_all_dirs(client->engine, dir, &error);
 
932
 
 
933
  handle_error(client, error, err);
 
934
 
 
935
  return retval;
 
936
}
 
937
 
 
938
void
 
939
gconf_client_suggest_sync   (GConfClient* client,
 
940
                             GError** err)
 
941
{
 
942
  GError* error = NULL;
 
943
  
 
944
  gconf_engine_suggest_sync(client->engine, &error);
 
945
 
 
946
  handle_error(client, error, err);
 
947
}
 
948
 
 
949
gboolean
 
950
gconf_client_dir_exists     (GConfClient* client,
 
951
                             const gchar* dir, GError** err)
 
952
{
 
953
  GError* error = NULL;
 
954
  gboolean retval;
 
955
  
 
956
  retval = gconf_engine_dir_exists(client->engine, dir, &error);
 
957
 
 
958
  handle_error(client, error, err);
 
959
 
 
960
  return retval;
 
961
}
 
962
 
 
963
gboolean
 
964
gconf_client_key_is_writable(GConfClient* client,
 
965
                             const gchar* key,
 
966
                             GError**     err)
 
967
{
 
968
  GError* error = NULL;
 
969
  GConfValue* val = NULL;
 
970
  gboolean is_writable = TRUE;
 
971
  
 
972
  g_return_val_if_fail(err == NULL || *err == NULL, FALSE);
 
973
  
 
974
  val = get (client, key, TRUE,
 
975
             NULL, &is_writable, &error);
 
976
 
 
977
  if (val == NULL && error != NULL)
 
978
    handle_error(client, error, err);
 
979
  else
 
980
    g_assert(error == NULL);
 
981
 
 
982
  /* FIXME we could avoid creating this value at all if
 
983
   * we were somewhat less lame.
 
984
   */
 
985
  if (val)
 
986
    gconf_value_free (val);
 
987
  
 
988
  return is_writable;
 
989
}
 
990
 
 
991
static gboolean
 
992
check_type(const gchar* key, GConfValue* val, GConfValueType t, GError** err)
 
993
{
 
994
  if (val->type != t)
 
995
    {
 
996
      gconf_set_error(err, GCONF_ERROR_TYPE_MISMATCH,
 
997
                      _("Expected `%s' got `%s' for key %s"),
 
998
                      gconf_value_type_to_string(t),
 
999
                      gconf_value_type_to_string(val->type),
 
1000
                      key);
 
1001
      return FALSE;
 
1002
    }
 
1003
  else
 
1004
    return TRUE;
 
1005
}
 
1006
 
 
1007
static GConfValue*
 
1008
get (GConfClient *client,
 
1009
     const gchar *key,
 
1010
     gboolean     use_default,
 
1011
     gboolean    *is_default_retloc,
 
1012
     gboolean    *is_writable_retloc,
 
1013
     GError     **error)
 
1014
{
 
1015
  GConfValue* val = NULL;
 
1016
  gboolean is_default = FALSE;
 
1017
  gboolean is_writable = TRUE;
 
1018
  
 
1019
  g_return_val_if_fail(client != NULL, NULL);
 
1020
  g_return_val_if_fail(GCONF_IS_CLIENT(client), NULL);
 
1021
  g_return_val_if_fail(error != NULL, NULL);
 
1022
  g_return_val_if_fail(*error == NULL, NULL);
 
1023
  
 
1024
  /* Check our client-side cache */
 
1025
  if (gconf_client_lookup(client, key, use_default,
 
1026
                          &is_default,
 
1027
                          &is_writable,
 
1028
                          &val))
 
1029
    {
 
1030
      if (is_default_retloc)
 
1031
        *is_default_retloc = is_default;
 
1032
 
 
1033
      if (is_writable_retloc)
 
1034
        *is_writable_retloc = is_writable;
 
1035
      
 
1036
      /* may be NULL of course */
 
1037
      return val ? gconf_value_copy (val) : NULL;
 
1038
    }
 
1039
      
 
1040
  g_assert(val == NULL); /* if it was in the cache we should have returned */
 
1041
 
 
1042
  /* Check the GConfEngine */
 
1043
  val = gconf_engine_get_full(client->engine, key,
 
1044
                              gconf_current_locale(),
 
1045
                              use_default, &is_default, &is_writable,
 
1046
                              error);
 
1047
 
 
1048
  if (is_default_retloc)
 
1049
    *is_default_retloc = is_default;
 
1050
 
 
1051
  if (is_writable_retloc)
 
1052
    *is_writable_retloc = is_writable;
 
1053
  
 
1054
  if (*error != NULL)
 
1055
    {
 
1056
      g_return_val_if_fail(val == NULL, NULL);
 
1057
      return NULL;
 
1058
    }
 
1059
  else
 
1060
    {
 
1061
      /* Cache this value, if it's in our directory list. FIXME could
 
1062
       * speed this up.
 
1063
       */
 
1064
      gchar* parent = g_strdup(key);
 
1065
      gchar* end;
 
1066
 
 
1067
      end = strrchr(parent, '/');
 
1068
 
 
1069
      while (end && parent != end)
 
1070
        {
 
1071
          *end = '\0';
 
1072
          
 
1073
          if (g_hash_table_lookup(client->dir_hash, parent) != NULL)
 
1074
            {
 
1075
              /* cache a copy of val */
 
1076
              gconf_client_cache (client, key, is_default, is_writable,
 
1077
                                  val ? gconf_value_copy (val) : NULL);
 
1078
              break;
 
1079
            }
 
1080
          
 
1081
          end = strrchr(parent, '/');
 
1082
        }
 
1083
 
 
1084
      g_free(parent);
 
1085
 
 
1086
      /* We don't own val, we're returning this copy belonging
 
1087
       * to the caller
 
1088
       */
 
1089
      return val;
 
1090
    }
 
1091
}
 
1092
     
 
1093
static GConfValue*
 
1094
gconf_client_get_full        (GConfClient* client,
 
1095
                              const gchar* key, const gchar* locale,
 
1096
                              gboolean use_schema_default,
 
1097
                              gboolean* value_is_default,
 
1098
                              gboolean* value_is_writable,
 
1099
                              GError** err)
 
1100
{
 
1101
  GError* error = NULL;
 
1102
  GConfValue* val = NULL;
 
1103
  gboolean is_default = FALSE;
 
1104
  gboolean is_writable = TRUE;
 
1105
  
 
1106
  g_return_val_if_fail(err == NULL || *err == NULL, NULL);
 
1107
 
 
1108
  if (locale != NULL)
 
1109
    g_warning("haven't implemented getting a specific locale in GConfClient");
 
1110
  
 
1111
  val = get(client, key, use_schema_default,
 
1112
            &is_default, &is_writable, &error);
 
1113
 
 
1114
  if (val == NULL && error != NULL)
 
1115
    handle_error(client, error, err);
 
1116
  else
 
1117
    g_assert(error == NULL);
 
1118
 
 
1119
 
 
1120
  if (value_is_default)
 
1121
    *value_is_default = is_default;
 
1122
 
 
1123
  if (value_is_writable)
 
1124
    *value_is_writable = is_writable;
 
1125
 
 
1126
  return val;
 
1127
}
 
1128
 
 
1129
GConfEntry*
 
1130
gconf_client_get_entry (GConfClient* client,
 
1131
                        const gchar* key,
 
1132
                        const gchar* locale,
 
1133
                        gboolean use_schema_default,
 
1134
                        GError** err)
 
1135
{
 
1136
  GError* error = NULL;
 
1137
  GConfValue* val = NULL;
 
1138
  gboolean is_default = FALSE;
 
1139
  gboolean is_writable = TRUE;
 
1140
  GConfEntry *entry;
 
1141
  
 
1142
  g_return_val_if_fail(err == NULL || *err == NULL, NULL);
 
1143
 
 
1144
  if (locale != NULL)
 
1145
    g_warning("haven't implemented getting a specific locale in GConfClient");
 
1146
  
 
1147
  val = get(client, key, use_schema_default,
 
1148
            &is_default, &is_writable, &error);
 
1149
 
 
1150
  if (val == NULL && error != NULL)
 
1151
    handle_error(client, error, err);
 
1152
  else
 
1153
    g_assert(error == NULL);
 
1154
 
 
1155
  entry = gconf_entry_new_nocopy (g_strdup (key), val);
 
1156
  entry->is_default = is_default;
 
1157
  entry->is_writable = is_writable;
 
1158
  
 
1159
  return entry;
 
1160
}
 
1161
 
 
1162
GConfValue*
 
1163
gconf_client_get             (GConfClient* client,
 
1164
                              const gchar* key,
 
1165
                              GError** err)
 
1166
{
 
1167
  return gconf_client_get_full(client, key, NULL, TRUE, NULL, NULL, err);
 
1168
}
 
1169
 
 
1170
GConfValue*
 
1171
gconf_client_get_without_default  (GConfClient* client,
 
1172
                                   const gchar* key,
 
1173
                                   GError** err)
 
1174
{
 
1175
  return gconf_client_get_full(client, key, NULL, FALSE, NULL, NULL, err);
 
1176
}
 
1177
 
 
1178
GConfValue*
 
1179
gconf_client_get_default_from_schema (GConfClient* client,
 
1180
                                      const gchar* key,
 
1181
                                      GError** err)
 
1182
{
 
1183
  GError* error = NULL;
 
1184
  GConfValue* val = NULL;
 
1185
  gboolean is_default = FALSE;
 
1186
  
 
1187
  g_return_val_if_fail(err == NULL || *err == NULL, NULL);  
 
1188
  g_return_val_if_fail(client != NULL, NULL);
 
1189
  g_return_val_if_fail(GCONF_IS_CLIENT(client), NULL);
 
1190
  
 
1191
  /* Check our client-side cache to see if the default is the same as
 
1192
   the regular value (FIXME put a default_value field in the
 
1193
   CacheEntry and store both, lose the is_default flag in CacheEntry) */
 
1194
  if (gconf_client_lookup(client, key, TRUE,
 
1195
                          &is_default,
 
1196
                          NULL,
 
1197
                          &val))
 
1198
    {        
 
1199
      if (is_default)
 
1200
        return val ? gconf_value_copy(val) : NULL;
 
1201
    }
 
1202
 
 
1203
  /* Check the GConfEngine */
 
1204
  val = gconf_engine_get_default_from_schema(client->engine, key,
 
1205
                                             &error);
 
1206
  
 
1207
  if (error != NULL)
 
1208
    {
 
1209
      g_assert(val == NULL);
 
1210
      handle_error(client, error, err);
 
1211
      return NULL;
 
1212
    }
 
1213
  else
 
1214
    {
 
1215
      /* FIXME eventually we'll cache the value
 
1216
         by adding a field to CacheEntry */
 
1217
      return val;
 
1218
    }
 
1219
}
 
1220
 
 
1221
gdouble
 
1222
gconf_client_get_float (GConfClient* client, const gchar* key,
 
1223
                        GError** err)
 
1224
{
 
1225
  static const gdouble def = 0.0;
 
1226
  GError* error = NULL;
 
1227
  GConfValue* val;
 
1228
 
 
1229
  g_return_val_if_fail(err == NULL || *err == NULL, 0.0);
 
1230
  
 
1231
  val = get(client, key, TRUE, NULL, NULL, &error);
 
1232
 
 
1233
  if (val != NULL)
 
1234
    {
 
1235
      gdouble retval = def;
 
1236
 
 
1237
      g_assert(error == NULL);
 
1238
      
 
1239
      if (check_type(key, val, GCONF_VALUE_FLOAT, &error))
 
1240
        retval = gconf_value_get_float(val);
 
1241
      else
 
1242
        handle_error(client, error, err);
 
1243
 
 
1244
      gconf_value_free(val);
 
1245
 
 
1246
      return retval;
 
1247
    }
 
1248
  else
 
1249
    {
 
1250
      if (error != NULL)
 
1251
        handle_error(client, error, err);
 
1252
      return def;
 
1253
    }
 
1254
}
 
1255
 
 
1256
gint
 
1257
gconf_client_get_int   (GConfClient* client, const gchar* key,
 
1258
                        GError** err)
 
1259
{
 
1260
  static const gint def = 0;
 
1261
  GError* error = NULL;
 
1262
  GConfValue* val;
 
1263
 
 
1264
  g_return_val_if_fail(err == NULL || *err == NULL, 0);
 
1265
 
 
1266
  val = get(client, key, TRUE, NULL, NULL, &error);
 
1267
 
 
1268
  if (val != NULL)
 
1269
    {
 
1270
      gint retval = def;
 
1271
 
 
1272
      g_assert(error == NULL);
 
1273
      
 
1274
      if (check_type(key, val, GCONF_VALUE_INT, &error))
 
1275
        retval = gconf_value_get_int(val);
 
1276
      else
 
1277
        handle_error(client, error, err);
 
1278
 
 
1279
      gconf_value_free(val);
 
1280
 
 
1281
      return retval;
 
1282
    }
 
1283
  else
 
1284
    {
 
1285
      if (error != NULL)
 
1286
        handle_error(client, error, err);
 
1287
      return def;
 
1288
    }
 
1289
}
 
1290
 
 
1291
gchar*
 
1292
gconf_client_get_string(GConfClient* client, const gchar* key,
 
1293
                        GError** err)
 
1294
{
 
1295
  static const gchar* def = NULL;
 
1296
  GError* error = NULL;
 
1297
  GConfValue* val;
 
1298
 
 
1299
  g_return_val_if_fail(err == NULL || *err == NULL, NULL);
 
1300
  
 
1301
  val = get(client, key, TRUE, NULL, NULL, &error);
 
1302
 
 
1303
  if (val != NULL)
 
1304
    {
 
1305
      gchar* retval = NULL;
 
1306
 
 
1307
      g_assert(error == NULL);
 
1308
      
 
1309
      if (check_type(key, val, GCONF_VALUE_STRING, &error))
 
1310
        /* we cheat here (look below) so we have to cast this */
 
1311
        retval = (gchar *)gconf_value_get_string(val);
 
1312
      else
 
1313
        handle_error(client, error, err);
 
1314
 
 
1315
      /* This is a cheat; don't copy */
 
1316
      if (retval != NULL)
 
1317
        val->d.string_data = NULL; /* don't delete the string we are returning */
 
1318
      else
 
1319
        retval = def ? g_strdup(def) : NULL;
 
1320
      
 
1321
      gconf_value_free(val);
 
1322
 
 
1323
      return retval;
 
1324
    }
 
1325
  else
 
1326
    {
 
1327
      if (error != NULL)
 
1328
        handle_error(client, error, err);
 
1329
      return def ? g_strdup(def) : NULL;
 
1330
    }
 
1331
}
 
1332
 
 
1333
 
 
1334
gboolean
 
1335
gconf_client_get_bool  (GConfClient* client, const gchar* key,
 
1336
                        GError** err)
 
1337
{
 
1338
  static const gboolean def = FALSE;
 
1339
  GError* error = NULL;
 
1340
  GConfValue* val;
 
1341
 
 
1342
  g_return_val_if_fail(err == NULL || *err == NULL, FALSE);
 
1343
 
 
1344
  val = get(client, key, TRUE, NULL, NULL, &error);  
 
1345
 
 
1346
  if (val != NULL)
 
1347
    {
 
1348
      gboolean retval = def;
 
1349
 
 
1350
      g_assert(error == NULL);
 
1351
      
 
1352
      if (check_type(key, val, GCONF_VALUE_BOOL, &error))
 
1353
        retval = gconf_value_get_bool(val);
 
1354
      else
 
1355
        handle_error(client, error, err);
 
1356
 
 
1357
      gconf_value_free(val);
 
1358
 
 
1359
      return retval;
 
1360
    }
 
1361
  else
 
1362
    {
 
1363
      if (error != NULL)
 
1364
        handle_error(client, error, err);
 
1365
      return def;
 
1366
    }
 
1367
}
 
1368
 
 
1369
GConfSchema*
 
1370
gconf_client_get_schema  (GConfClient* client,
 
1371
                          const gchar* key, GError** err)
 
1372
{
 
1373
  GError* error = NULL;
 
1374
  GConfValue* val;
 
1375
 
 
1376
  g_return_val_if_fail(err == NULL || *err == NULL, NULL);
 
1377
 
 
1378
  val = get(client, key, TRUE, NULL, NULL, &error);
 
1379
 
 
1380
  if (val != NULL)
 
1381
    {
 
1382
      GConfSchema* retval = NULL;
 
1383
 
 
1384
      g_assert(error == NULL);
 
1385
      
 
1386
      if (check_type(key, val, GCONF_VALUE_SCHEMA, &error))
 
1387
        retval = gconf_value_get_schema(val);
 
1388
      else
 
1389
        handle_error(client, error, err);
 
1390
 
 
1391
      /* This is a cheat; don't copy */
 
1392
      if (retval != NULL)
 
1393
        val->d.schema_data = NULL; /* don't delete the schema */
 
1394
      
 
1395
      gconf_value_free(val);
 
1396
 
 
1397
      return retval;
 
1398
    }
 
1399
  else
 
1400
    {
 
1401
      if (error != NULL)
 
1402
        handle_error(client, error, err);
 
1403
      return NULL;
 
1404
    }
 
1405
}
 
1406
 
 
1407
GSList*
 
1408
gconf_client_get_list    (GConfClient* client, const gchar* key,
 
1409
                          GConfValueType list_type, GError** err)
 
1410
{
 
1411
  GError* error = NULL;
 
1412
  GConfValue* val;
 
1413
 
 
1414
  g_return_val_if_fail(err == NULL || *err == NULL, NULL);
 
1415
 
 
1416
  val = get(client, key, TRUE, NULL, NULL, &error);
 
1417
 
 
1418
  if (val != NULL)
 
1419
    {
 
1420
      GSList* retval;
 
1421
 
 
1422
      g_assert(error == NULL);
 
1423
 
 
1424
      /* This function checks the type and destroys "val" */
 
1425
      retval = gconf_value_list_to_primitive_list_destructive(val, list_type, &error);
 
1426
 
 
1427
      if (error != NULL)
 
1428
        {
 
1429
          g_assert(retval == NULL);
 
1430
          handle_error(client, error, err);
 
1431
          return NULL;
 
1432
        }
 
1433
      else
 
1434
        return retval;
 
1435
    }
 
1436
  else
 
1437
    {
 
1438
      if (error != NULL)
 
1439
        handle_error(client, error, err);
 
1440
      return NULL;
 
1441
    }
 
1442
}
 
1443
 
 
1444
gboolean
 
1445
gconf_client_get_pair    (GConfClient* client, const gchar* key,
 
1446
                          GConfValueType car_type, GConfValueType cdr_type,
 
1447
                          gpointer car_retloc, gpointer cdr_retloc,
 
1448
                          GError** err)
 
1449
{
 
1450
  GError* error = NULL;
 
1451
  GConfValue* val;
 
1452
 
 
1453
  g_return_val_if_fail(err == NULL || *err == NULL, FALSE);
 
1454
 
 
1455
  val = get(client, key, TRUE, NULL, NULL, &error);  
 
1456
 
 
1457
  if (val != NULL)
 
1458
    {
 
1459
      g_assert(error == NULL);
 
1460
 
 
1461
      /* This function checks the type and destroys "val" */
 
1462
      if (gconf_value_pair_to_primitive_pair_destructive(val, car_type, cdr_type,
 
1463
                                                         car_retloc, cdr_retloc,
 
1464
                                                         &error))
 
1465
        {
 
1466
          g_assert(error == NULL);
 
1467
          return TRUE;
 
1468
        }
 
1469
      else
 
1470
        {
 
1471
          g_assert(error != NULL);
 
1472
          handle_error(client, error, err);
 
1473
          return FALSE;
 
1474
        }
 
1475
    }
 
1476
  else
 
1477
    {
 
1478
      if (error != NULL)
 
1479
        {
 
1480
          handle_error(client, error, err);
 
1481
          return FALSE;
 
1482
        }
 
1483
      else
 
1484
        return TRUE;
 
1485
    }
 
1486
 
 
1487
}
 
1488
 
 
1489
 
 
1490
/*
 
1491
 * For the set functions, we just set normally, and wait for the
 
1492
 * notification to come back from the server before we update
 
1493
 * our cache. This may be the wrong thing; maybe we should
 
1494
 * update immediately?
 
1495
 * Problem with delayed update: user calls set() then get(),
 
1496
 *  results in weirdness
 
1497
 * Problem with with regular update: get() before the notify
 
1498
 *  is out of sync with the listening parts of the application
 
1499
 * 
 
1500
 * It is somewhat academic now anyway because the _set() call
 
1501
 * won't return until all the notifications have happened, so the
 
1502
 * notify signal will be emitted inside the set() call.
 
1503
 */
 
1504
 
 
1505
gboolean
 
1506
gconf_client_set_float   (GConfClient* client, const gchar* key,
 
1507
                          gdouble val, GError** err)
 
1508
{
 
1509
  GError* error = NULL;
 
1510
  
 
1511
  g_return_val_if_fail(client != NULL, FALSE);
 
1512
  g_return_val_if_fail(GCONF_IS_CLIENT(client), FALSE);  
 
1513
  g_return_val_if_fail(key != NULL, FALSE);
 
1514
  
 
1515
  if (gconf_engine_set_float(client->engine, key, val, &error))
 
1516
    return TRUE;
 
1517
  else
 
1518
    {
 
1519
      handle_error(client, error, err);
 
1520
      return FALSE;
 
1521
    }
 
1522
}
 
1523
 
 
1524
gboolean
 
1525
gconf_client_set_int     (GConfClient* client, const gchar* key,
 
1526
                          gint val, GError** err)
 
1527
{
 
1528
  GError* error = NULL;
 
1529
  
 
1530
  g_return_val_if_fail(client != NULL, FALSE);
 
1531
  g_return_val_if_fail(GCONF_IS_CLIENT(client), FALSE);  
 
1532
  g_return_val_if_fail(key != NULL, FALSE);
 
1533
  
 
1534
  if (gconf_engine_set_int(client->engine, key, val, &error))
 
1535
    return TRUE;
 
1536
  else
 
1537
    {
 
1538
      handle_error(client, error, err);
 
1539
      return FALSE;
 
1540
    }
 
1541
}
 
1542
 
 
1543
gboolean
 
1544
gconf_client_set_string  (GConfClient* client, const gchar* key,
 
1545
                          const gchar* val, GError** err)
 
1546
{
 
1547
  GError* error = NULL;
 
1548
  
 
1549
  g_return_val_if_fail(client != NULL, FALSE);
 
1550
  g_return_val_if_fail(GCONF_IS_CLIENT(client), FALSE);  
 
1551
  g_return_val_if_fail(key != NULL, FALSE);
 
1552
  g_return_val_if_fail(val != NULL, FALSE);
 
1553
  
 
1554
  if (gconf_engine_set_string(client->engine, key, val, &error))
 
1555
    return TRUE;
 
1556
  else
 
1557
    {
 
1558
      handle_error(client, error, err);
 
1559
      return FALSE;
 
1560
    }
 
1561
}
 
1562
 
 
1563
gboolean
 
1564
gconf_client_set_bool    (GConfClient* client, const gchar* key,
 
1565
                          gboolean val, GError** err)
 
1566
{
 
1567
  GError* error = NULL;
 
1568
  
 
1569
  g_return_val_if_fail(client != NULL, FALSE);
 
1570
  g_return_val_if_fail(GCONF_IS_CLIENT(client), FALSE);  
 
1571
  g_return_val_if_fail(key != NULL, FALSE);
 
1572
  
 
1573
  if (gconf_engine_set_bool(client->engine, key, val, &error))
 
1574
    return TRUE;
 
1575
  else
 
1576
    {
 
1577
      handle_error(client, error, err);
 
1578
      return FALSE;
 
1579
    }
 
1580
}
 
1581
 
 
1582
gboolean
 
1583
gconf_client_set_schema  (GConfClient* client, const gchar* key,
 
1584
                          GConfSchema* val, GError** err)
 
1585
{
 
1586
  GError* error = NULL;
 
1587
  
 
1588
  g_return_val_if_fail(client != NULL, FALSE);
 
1589
  g_return_val_if_fail(GCONF_IS_CLIENT(client), FALSE);  
 
1590
  g_return_val_if_fail(key != NULL, FALSE);
 
1591
  g_return_val_if_fail(val != NULL, FALSE);
 
1592
  
 
1593
  if (gconf_engine_set_schema(client->engine, key, val, &error))
 
1594
    return TRUE;
 
1595
  else
 
1596
    {
 
1597
      handle_error(client, error, err);
 
1598
      return FALSE;
 
1599
    }
 
1600
}
 
1601
 
 
1602
gboolean
 
1603
gconf_client_set_list    (GConfClient* client, const gchar* key,
 
1604
                          GConfValueType list_type,
 
1605
                          GSList* list,
 
1606
                          GError** err)
 
1607
{
 
1608
  GError* error = NULL;
 
1609
  
 
1610
  g_return_val_if_fail(client != NULL, FALSE);
 
1611
  g_return_val_if_fail(GCONF_IS_CLIENT(client), FALSE);  
 
1612
  g_return_val_if_fail(key != NULL, FALSE);
 
1613
  
 
1614
  if (gconf_engine_set_list(client->engine, key, list_type, list, &error))
 
1615
    return TRUE;
 
1616
  else
 
1617
    {
 
1618
      handle_error(client, error, err);
 
1619
      return FALSE;
 
1620
    }
 
1621
}
 
1622
 
 
1623
gboolean
 
1624
gconf_client_set_pair    (GConfClient* client, const gchar* key,
 
1625
                          GConfValueType car_type, GConfValueType cdr_type,
 
1626
                          gconstpointer address_of_car,
 
1627
                          gconstpointer address_of_cdr,
 
1628
                          GError** err)
 
1629
{
 
1630
  GError* error = NULL;
 
1631
  
 
1632
  g_return_val_if_fail(client != NULL, FALSE);
 
1633
  g_return_val_if_fail(GCONF_IS_CLIENT(client), FALSE);  
 
1634
  g_return_val_if_fail(key != NULL, FALSE);
 
1635
  
 
1636
  if (gconf_engine_set_pair(client->engine, key, car_type, cdr_type,
 
1637
                     address_of_car, address_of_cdr, &error))
 
1638
    return TRUE;
 
1639
  else
 
1640
    {
 
1641
      handle_error(client, error, err);
 
1642
      return FALSE;
 
1643
    }
 
1644
}
 
1645
 
 
1646
 
 
1647
/*
 
1648
 * Functions to emit signals
 
1649
 */
 
1650
 
 
1651
void
 
1652
gconf_client_error                  (GConfClient* client, GError* error)
 
1653
{
 
1654
  g_return_if_fail(client != NULL);
 
1655
  g_return_if_fail(GCONF_IS_CLIENT(client));
 
1656
  
 
1657
  gtk_signal_emit(GTK_OBJECT(client), client_signals[ERROR], error);
 
1658
}
 
1659
 
 
1660
void
 
1661
gconf_client_unreturned_error       (GConfClient* client, GError* error)
 
1662
{
 
1663
  g_return_if_fail(client != NULL);
 
1664
  g_return_if_fail(GCONF_IS_CLIENT(client));
 
1665
 
 
1666
  gtk_signal_emit(GTK_OBJECT(client), client_signals[UNRETURNED_ERROR], error);
 
1667
}
 
1668
 
 
1669
void
 
1670
gconf_client_value_changed          (GConfClient* client,
 
1671
                                     const gchar* key,
 
1672
                                     GConfValue* value)
 
1673
{
 
1674
  g_return_if_fail(client != NULL);
 
1675
  g_return_if_fail(GCONF_IS_CLIENT(client));
 
1676
  g_return_if_fail(key != NULL);
 
1677
  
 
1678
  gtk_signal_emit(GTK_OBJECT(client), client_signals[VALUE_CHANGED],
 
1679
                  key, value);
 
1680
}
 
1681
 
 
1682
/*
 
1683
 * Internal utility
 
1684
 */
 
1685
 
 
1686
static void
 
1687
gconf_client_cache (GConfClient* client,
 
1688
                    const gchar* key,
 
1689
                    gboolean is_default,
 
1690
                    gboolean is_writable,
 
1691
                    GConfValue* value)
 
1692
{
 
1693
  /* Remember: value may be NULL */
 
1694
  
 
1695
  gpointer oldkey = NULL, oldval = NULL;
 
1696
 
 
1697
  if (g_hash_table_lookup_extended(client->cache_hash, key, &oldkey, &oldval))
 
1698
    {
 
1699
      /* Already have a value, update it */
 
1700
      CacheEntry* ce = oldval;
 
1701
 
 
1702
      g_assert(ce != NULL);
 
1703
 
 
1704
      if (ce->value != NULL)
 
1705
        gconf_value_free(ce->value);
 
1706
 
 
1707
      ce->value = value;
 
1708
      ce->is_default = is_default;
 
1709
      ce->is_writable = is_writable;
 
1710
    }
 
1711
  else
 
1712
    {
 
1713
      /* Create a new entry */
 
1714
      CacheEntry* ce = cache_entry_new(value, is_default, is_writable);
 
1715
      g_hash_table_insert(client->cache_hash, g_strdup(key), ce);
 
1716
    }
 
1717
}
 
1718
 
 
1719
static gboolean
 
1720
gconf_client_lookup         (GConfClient* client,
 
1721
                             const gchar* key,
 
1722
                             gboolean use_default,
 
1723
                             gboolean* is_default,
 
1724
                             gboolean* is_writable,
 
1725
                             GConfValue** valp)
 
1726
{
 
1727
  CacheEntry* ce;
 
1728
 
 
1729
  g_return_val_if_fail(valp != NULL, FALSE);
 
1730
  g_return_val_if_fail(*valp == NULL, FALSE);
 
1731
  
 
1732
  ce = g_hash_table_lookup(client->cache_hash, key);
 
1733
 
 
1734
  if (ce != NULL)
 
1735
    {
 
1736
      if (ce->is_default)
 
1737
        {
 
1738
          *is_default = TRUE;
 
1739
          
 
1740
          if (use_default)
 
1741
            *valp = ce->value;            
 
1742
          else
 
1743
            *valp = NULL;
 
1744
        }
 
1745
      else
 
1746
        {
 
1747
          *is_default = FALSE;
 
1748
 
 
1749
          *valp = ce->value;
 
1750
        }
 
1751
 
 
1752
      if (is_writable)
 
1753
        *is_writable = ce->is_writable;
 
1754
      
 
1755
      return TRUE;
 
1756
    }
 
1757
  else
 
1758
    return FALSE;
 
1759
}
 
1760
 
 
1761
 
 
1762
/*
 
1763
 * CacheEntry
 
1764
 */ 
 
1765
 
 
1766
static CacheEntry*
 
1767
cache_entry_new(GConfValue* val,
 
1768
                gboolean is_default, gboolean is_writable)
 
1769
{
 
1770
  CacheEntry* ce;
 
1771
 
 
1772
  ce = g_new(CacheEntry, 1);
 
1773
 
 
1774
  /* val may be NULL */
 
1775
  ce->value = val;
 
1776
  ce->is_default = is_default;
 
1777
  ce->is_writable = is_writable;
 
1778
  
 
1779
  return ce;
 
1780
}
 
1781
 
 
1782
static void
 
1783
cache_entry_destroy(CacheEntry* ce)
 
1784
{
 
1785
  g_return_if_fail(ce != NULL);
 
1786
  
 
1787
  if (ce->value != NULL)
 
1788
    gconf_value_free(ce->value);
 
1789
 
 
1790
  g_free(ce);
 
1791
}
 
1792
 
 
1793
/*
 
1794
 * Dir
 
1795
 */
 
1796
 
 
1797
static Dir*
 
1798
dir_new(const gchar* name, guint notify_id)
 
1799
{
 
1800
  Dir* d;
 
1801
 
 
1802
  d = g_new(Dir, 1);
 
1803
 
 
1804
  d->name = g_strdup(name);
 
1805
  d->notify_id = notify_id;
 
1806
  d->add_count = 0;
 
1807
  
 
1808
  return d;
 
1809
}
 
1810
 
 
1811
static void
 
1812
dir_destroy(Dir* d)
 
1813
{
 
1814
  g_return_if_fail(d != NULL);
 
1815
  g_return_if_fail(d->notify_id == 0);
 
1816
  
 
1817
  g_free(d->name);
 
1818
  g_free(d);
 
1819
}
 
1820
 
 
1821
/*
 
1822
 * Listener
 
1823
 */
 
1824
 
 
1825
static Listener* 
 
1826
listener_new(GConfClientNotifyFunc func,
 
1827
             GFreeFunc destroy_notify,
 
1828
             gpointer data)
 
1829
{
 
1830
  Listener* l;
 
1831
 
 
1832
  l = g_new(Listener, 1);
 
1833
 
 
1834
  l->func = func;
 
1835
  l->data = data;
 
1836
  l->destroy_notify = destroy_notify;
 
1837
  
 
1838
  return l;
 
1839
}
 
1840
 
 
1841
static void
 
1842
listener_destroy(Listener* l)
 
1843
{
 
1844
  g_return_if_fail(l != NULL);
 
1845
 
 
1846
  if (l->destroy_notify)
 
1847
    (* l->destroy_notify) (l->data);
 
1848
  
 
1849
  g_free(l);
 
1850
}
 
1851
 
 
1852
/*
 
1853
 * Change sets
 
1854
 */
 
1855
 
 
1856
 
 
1857
struct CommitData {
 
1858
  GConfClient* client;
 
1859
  GError* error;
 
1860
  GSList* remove_list;
 
1861
  gboolean remove_committed;
 
1862
};
 
1863
 
 
1864
static void
 
1865
commit_foreach (GConfChangeSet* cs,
 
1866
                const gchar* key,
 
1867
                GConfValue* value,
 
1868
                gpointer user_data)
 
1869
{
 
1870
  struct CommitData* cd = user_data;
 
1871
 
 
1872
  g_assert(cd != NULL);
 
1873
 
 
1874
  if (cd->error != NULL)
 
1875
    return;
 
1876
  
 
1877
  if (value)
 
1878
    gconf_client_set   (cd->client, key, value, &cd->error);
 
1879
  else
 
1880
    gconf_client_unset (cd->client, key, &cd->error);
 
1881
 
 
1882
  if (cd->error == NULL && cd->remove_committed)
 
1883
    {
 
1884
      /* Bad bad bad; we keep the key reference, knowing that it's
 
1885
         valid until we modify the change set, to avoid string copies.  */
 
1886
      cd->remove_list = g_slist_prepend(cd->remove_list, (gchar*)key);
 
1887
    }
 
1888
}
 
1889
 
 
1890
gboolean
 
1891
gconf_client_commit_change_set   (GConfClient* client,
 
1892
                                  GConfChangeSet* cs,
 
1893
                                  gboolean remove_committed,
 
1894
                                  GError** err)
 
1895
{
 
1896
  struct CommitData cd;
 
1897
  GSList* tmp;
 
1898
 
 
1899
  g_return_val_if_fail(client != NULL, FALSE);
 
1900
  g_return_val_if_fail(GCONF_IS_CLIENT(client), FALSE);
 
1901
  g_return_val_if_fail(cs != NULL, FALSE);
 
1902
  g_return_val_if_fail(err == NULL || *err == NULL, FALSE);
 
1903
  
 
1904
  cd.client = client;
 
1905
  cd.error = NULL;
 
1906
  cd.remove_list = NULL;
 
1907
  cd.remove_committed = remove_committed;
 
1908
 
 
1909
  /* Because the commit could have lots of side
 
1910
     effects, this makes it safer */
 
1911
  gconf_change_set_ref(cs);
 
1912
  gtk_object_ref(GTK_OBJECT(client));
 
1913
  
 
1914
  gconf_change_set_foreach(cs, commit_foreach, &cd);
 
1915
 
 
1916
  tmp = cd.remove_list;
 
1917
  while (tmp != NULL)
 
1918
    {
 
1919
      const gchar* key = tmp->data;
 
1920
      
 
1921
      gconf_change_set_remove(cs, key);
 
1922
 
 
1923
      /* key is now invalid due to our little evil trick */
 
1924
 
 
1925
      tmp = g_slist_next(tmp);
 
1926
    }
 
1927
 
 
1928
  g_slist_free(cd.remove_list);
 
1929
  
 
1930
  gconf_change_set_unref(cs);
 
1931
  gtk_object_unref(GTK_OBJECT(client));
 
1932
 
 
1933
  if (cd.error != NULL)
 
1934
    {
 
1935
      if (err != NULL)
 
1936
        *err = cd.error;
 
1937
      else
 
1938
        g_error_free(cd.error);
 
1939
 
 
1940
      return FALSE;
 
1941
    }
 
1942
  else
 
1943
    {
 
1944
      g_assert((!remove_committed) ||
 
1945
               (gconf_change_set_size(cs) == 0));
 
1946
      
 
1947
      return TRUE;
 
1948
    }
 
1949
}
 
1950
 
 
1951
struct RevertData {
 
1952
  GConfClient* client;
 
1953
  GError* error;
 
1954
  GConfChangeSet* revert_set;
 
1955
};
 
1956
 
 
1957
static void
 
1958
revert_foreach (GConfChangeSet* cs,
 
1959
                const gchar* key,
 
1960
                GConfValue* value,
 
1961
                gpointer user_data)
 
1962
{
 
1963
  struct RevertData* rd = user_data;
 
1964
  GConfValue* old_value;
 
1965
  GError* error = NULL;
 
1966
  
 
1967
  g_assert(rd != NULL);
 
1968
 
 
1969
  if (rd->error != NULL)
 
1970
    return;
 
1971
 
 
1972
  old_value = gconf_client_get_without_default(rd->client, key, &error);
 
1973
 
 
1974
  if (error != NULL)
 
1975
    {
 
1976
      /* FIXME */
 
1977
      g_warning("error creating revert set: %s", error->message);
 
1978
      g_error_free(error);
 
1979
      error = NULL;
 
1980
    }
 
1981
  
 
1982
  if (old_value == NULL &&
 
1983
      value == NULL)
 
1984
    return; /* this commit will have no effect. */
 
1985
 
 
1986
  if (old_value == NULL)
 
1987
    gconf_change_set_unset(rd->revert_set, key);
 
1988
  else
 
1989
    gconf_change_set_set_nocopy(rd->revert_set, key, old_value);
 
1990
}
 
1991
 
 
1992
 
 
1993
GConfChangeSet*
 
1994
gconf_client_reverse_change_set  (GConfClient* client,
 
1995
                                         GConfChangeSet* cs,
 
1996
                                         GError** err)
 
1997
{
 
1998
  struct RevertData rd;
 
1999
 
 
2000
  rd.error = NULL;
 
2001
  rd.client = client;
 
2002
  rd.revert_set = gconf_change_set_new();
 
2003
 
 
2004
  /* we're emitting signals and such, avoid
 
2005
     nasty side effects with these.
 
2006
  */
 
2007
  gtk_object_ref(GTK_OBJECT(rd.client));
 
2008
  gconf_change_set_ref(cs);
 
2009
  
 
2010
  gconf_change_set_foreach(cs, revert_foreach, &rd);
 
2011
 
 
2012
  if (rd.error != NULL)
 
2013
    {
 
2014
      if (err != NULL)
 
2015
        *err = rd.error;
 
2016
      else
 
2017
        g_error_free(rd.error);
 
2018
    }
 
2019
 
 
2020
  gtk_object_unref(GTK_OBJECT(rd.client));
 
2021
  gconf_change_set_unref(cs);
 
2022
  
 
2023
  return rd.revert_set;
 
2024
}
 
2025
 
 
2026
 
 
2027
GConfChangeSet*
 
2028
gconf_client_change_set_from_currentv (GConfClient* client,
 
2029
                                              const gchar** keys,
 
2030
                                              GError** err)
 
2031
{
 
2032
  GConfValue* old_value;
 
2033
  GConfChangeSet* new_set;
 
2034
  const gchar** keyp;
 
2035
  
 
2036
  g_return_val_if_fail(err == NULL || *err == NULL, NULL);
 
2037
 
 
2038
  new_set = gconf_change_set_new();
 
2039
  
 
2040
  keyp = keys;
 
2041
 
 
2042
  while (*keyp != NULL)
 
2043
    {
 
2044
      GError* error = NULL;
 
2045
      const gchar* key = *keyp;
 
2046
      
 
2047
      old_value = gconf_client_get_without_default(client, key, &error);
 
2048
 
 
2049
      if (error != NULL)
 
2050
        {
 
2051
          /* FIXME */
 
2052
          g_warning("error creating change set from current keys: %s", error->message);
 
2053
          g_error_free(error);
 
2054
          error = NULL;
 
2055
        }
 
2056
      
 
2057
      if (old_value == NULL)
 
2058
        gconf_change_set_unset(new_set, key);
 
2059
      else
 
2060
        gconf_change_set_set_nocopy(new_set, key, old_value);
 
2061
 
 
2062
      ++keyp;
 
2063
    }
 
2064
 
 
2065
  return new_set;
 
2066
}
 
2067
 
 
2068
GConfChangeSet*
 
2069
gconf_client_change_set_from_current (GConfClient* client,
 
2070
                                             GError** err,
 
2071
                                             const gchar* first_key,
 
2072
                                             ...)
 
2073
{
 
2074
  GSList* keys = NULL;
 
2075
  va_list args;
 
2076
  const gchar* arg;
 
2077
  const gchar** vec;
 
2078
  GConfChangeSet* retval;
 
2079
  GSList* tmp;
 
2080
  guint i;
 
2081
  
 
2082
  g_return_val_if_fail(err == NULL || *err == NULL, NULL);
 
2083
 
 
2084
  va_start (args, first_key);
 
2085
 
 
2086
  arg = first_key;
 
2087
 
 
2088
  while (arg != NULL)
 
2089
    {
 
2090
      keys = g_slist_prepend(keys, (/*non-const*/gchar*)arg);
 
2091
 
 
2092
      arg = va_arg (args, const gchar*);
 
2093
    }
 
2094
  
 
2095
  va_end (args);
 
2096
 
 
2097
  vec = g_new0(const gchar*, g_slist_length(keys) + 1);
 
2098
 
 
2099
  i = 0;
 
2100
  tmp = keys;
 
2101
 
 
2102
  while (tmp != NULL)
 
2103
    {
 
2104
      vec[i] = tmp->data;
 
2105
      
 
2106
      ++i;
 
2107
      tmp = g_slist_next(tmp);
 
2108
    }
 
2109
 
 
2110
  g_slist_free(keys);
 
2111
  
 
2112
  retval = gconf_client_change_set_from_currentv(client, vec, err);
 
2113
  
 
2114
  g_free(vec);
 
2115
 
 
2116
  return retval;
 
2117
}
 
2118
 
 
2119
static GHashTable * clients = NULL;
 
2120
 
 
2121
static void
 
2122
register_client (GConfClient *client)
 
2123
{
 
2124
  if (clients == NULL)
 
2125
    clients = g_hash_table_new (NULL, NULL);
 
2126
 
 
2127
  g_hash_table_insert (clients, client->engine, client);
 
2128
}
 
2129
 
 
2130
static GConfClient *
 
2131
lookup_client (GConfEngine *engine)
 
2132
{
 
2133
  if (clients == NULL)
 
2134
    return NULL;
 
2135
  else
 
2136
    return g_hash_table_lookup (clients, engine);
 
2137
}
 
2138
 
 
2139
static void
 
2140
unregister_client (GConfClient *client)
 
2141
{
 
2142
  g_return_if_fail (clients != NULL);
 
2143
 
 
2144
  g_hash_table_remove (clients, client->engine);
 
2145
}