API to allow constructing arbitrary stacks of sources



Hi,
	I've gone back over a long standing patch[1] of mine which allows you
to construct a GConfEngine from an arbitrary stack of sources -
basically the same effect as editing the path file, but without editing
the path file ... if you get my meaning ... :-)

	The idea is that we could start making gconf-editor into a much more
useful sysadmin tool where you could setup some new configuration
sources and try things out before pushing it out to users.

	It really just adds a single new public function:

GConfEngine* gconf_engine_get_for_addresses (GSList *addresses,
                                             GError** err);

	However, a lot of internals are re-factored by the patch. Attaching it
here so people can look over it if they like. I'd really appreciate some
more eyes on it.

Thanks,
Mark.

[1] - http://bugzilla.gnome.org/show_bug.cgi?id=88829
Index: ChangeLog
===================================================================
RCS file: /home/markmc/gnome-devel/local-repository/gconf/ChangeLog,v
retrieving revision 1.495
retrieving revision 1.496
diff -u -p -r1.495 -r1.496
--- ChangeLog	29 Mar 2004 13:48:07 -0000	1.495
+++ ChangeLog	29 Mar 2004 14:44:10 -0000	1.496
@@ -1,1 +1,82 @@
+2004-03-29  Mark McLoughlin  <mark skynet ie>
+
+	* gconf/gconf-engine.h: add gconf_engine_get_for_addresses()
+	and gconf_engine_get_local_for_addresses().
+	
+	* gconf/gconf.c:
+	(gconf_engine_connect): implement setting up a database from
+	an arbitrary stack of sources.
+	(register_engine): use the concatenation of addresses for the key.
+	(unregister_engine): free the persistent address and address list on
+	unregistering.
+	(lookup_engine): use the concatenation of addresses for the key.
+	(gconf_engine_get_local_for_addresses): add.
+	(gconf_engine_get_for_address): update for register_engine change.
+	(gconf_engine_get_for_addresses): impl support for remote composite dbs.
+	(update_listener): update for the fact that listeners are now saved using
+	the persistent name.
+	
+	* gconf/GConfX.idl: extend the ConfigServer interface
+	by adding ConfigServer2 inherting from ConfigServer.
+	Add ConfigServer2::get_database_for_addresses().
+	
+	* gconf/gconf-backend.c:
+	(gconf_address_valid), (gconf_get_backend): check the backend
+	address doesn't contain any special characters.
+	
+	* gconf/gconf-database.[ch]:
+	(source_notify_cb): don't notify unless this change could
+	actually cause a change for the client.
+	(gconf_database_notify_listeners): impl. notifying "other"
+	listeners - clients listening on other stacks which contains
+	any of the modified sources.
+	(gconf_database_set), (gconf_database_unset): keep track of
+	the sources modified by the change and update for the
+	notify_listeners change.
+	(gconf_database_recursive_unset): ditto and upd. for the
+	change in the listeners list returned by
+	gconf_sources_recursive_unset().
+	(gconf_database_get_persistent_name): make the persistent
+	name a concatenation of the individual addresses instead
+	of the first address.
+	
+	* gconf/gconf-internals.[ch]:
+	(gconf_address_list_get_persistent_name): impl method similar
+	to gconf_database_get_persistent_name, except concatenate
+	the addresses from a GSList.
+	(gconf_persistent_name_get_address_list): do the reverse.
+	(gconf_address_list_free): free the list of strings.
+
+	* gconf/gconf-sources.[ch]:
+	(gconf_sources_new_from_source): allow creating an empty source
+	list.
+	(gconf_sources_set_value),
+	(gconf_sources_unset_value): return the sources modified by
+	the change.
+	(prepend_unset_notify), (recursive_unset_helper),
+	(gconf_sources_recursive_unset): return a list of GConfUnsetNotifys
+	which contains both the key and the modified source.
+	(get_address_resource): copy and paste of gconf_address_resource
+	except it doesn't dup the return value.
+	(gconf_sources_is_affected): figure out if a change to a particular
+	key in one source affects the key with a particular stack of sources.
+	
+	* gconf/gconfd.[ch]: impl ConfigServer2 inheritance.
+	(gconfd_get_database): upd for obtain_database change.
+	(gconfd_get_composite_database): implement.
+	(init_databases): rename dbs_by_address to dbs_by_addresses.
+	(set_default_database): register the default db like the others.
+	(register_database): use the persistent name as the key.
+	(unregister_database): ditto.
+	(lookup_database): ditto.
+	(obtain_database): use a list of addresses, not a single one.
+	(gconfd_notify_other_listeners): impl notifying listeners
+	on GConfDatabases other than the one which was changed.
+	(listener_logentry_restore_and_destroy_foreach): restore by
+	splitting the address list string.
+
+	* gconf/gconftool.c: (main): enable --config-source without
+	--direct as it works better now. Also allow --config-source
+	to be an address list.
+	
Index: doc/gconf/tmpl/gconf-backend.sgml
===================================================================
RCS file: /home/markmc/gnome-devel/local-repository/gconf/doc/gconf/tmpl/gconf-backend.sgml,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -p -r1.9 -r1.10
--- doc/gconf/tmpl/gconf-backend.sgml	25 Mar 2004 17:59:07 -0000	1.9
+++ doc/gconf/tmpl/gconf-backend.sgml	29 Mar 2004 14:44:19 -0000	1.10
@@ -321,6 +321,7 @@ by the integer supplied.
 @destroy_source: 
 @clear_cache: 
 @blow_away_locks: 
+ set_notify_func: 
 @add_listener: 
 @remove_listener: 
 
Index: doc/gconf/tmpl/gconf-sources.sgml
===================================================================
RCS file: /home/markmc/gnome-devel/local-repository/gconf/doc/gconf/tmpl/gconf-sources.sgml,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -p -r1.7 -r1.8
--- doc/gconf/tmpl/gconf-sources.sgml	7 Dec 2001 04:42:36 -0000	1.7
+++ doc/gconf/tmpl/gconf-sources.sgml	29 Mar 2004 14:44:20 -0000	1.8
@@ -109,6 +109,7 @@ gconf-sources
 @sources: 
 @key: 
 @value: 
+ modified_sources: 
 @err: 
 
 
@@ -120,6 +121,7 @@ gconf-sources
 @sources: 
 @key: 
 @locale: 
+ modified_sources: 
 @err: 
 
 
Index: gconf/GConfX.idl
===================================================================
RCS file: /home/markmc/gnome-devel/local-repository/gconf/gconf/GConfX.idl,v
retrieving revision 1.48
retrieving revision 1.49
diff -u -p -r1.48 -r1.49
--- gconf/GConfX.idl	15 Jan 2002 02:01:06 -0000	1.48
+++ gconf/GConfX.idl	29 Mar 2004 14:44:29 -0000	1.49
@@ -261,3 +261,8 @@ interface ConfigServer {
   void shutdown();
 };
 
+interface ConfigServer2 : ConfigServer {
+  typedef sequence<string> AddressList;
+
+  ConfigDatabase get_database_for_addresses (in AddressList addresses);
+};
Index: gconf/gconf-backend.c
===================================================================
RCS file: /home/markmc/gnome-devel/local-repository/gconf/gconf/gconf-backend.c,v
retrieving revision 1.24
retrieving revision 1.25
diff -u -p -r1.24 -r1.25
--- gconf/gconf-backend.c	29 Mar 2004 13:48:11 -0000	1.24
+++ gconf/gconf-backend.c	29 Mar 2004 14:44:29 -0000	1.25
@@ -26,6 +26,46 @@
 #include <sys/stat.h>
 #include <unistd.h>
 
+
+/* Don't allow special characters in configuration source addresses.
+ * The important one here is not to allow ';' because we use that
+ * internally as a list delimiter. See GCONF_DATABASE_LIST_DELIM
+ */
+static const char invalid_chars[] = " \t\r\n\"$&<>,+=#!()'|{}[]?~`;%\\";
+
+static gboolean
+gconf_address_valid (const char  *address,
+		     char      **why_invalid)
+{
+  const char *s;
+
+  g_return_val_if_fail (address != NULL, FALSE);
+
+  if (why_invalid)
+    *why_invalid = NULL;
+
+  s = address;
+  while (*s)
+    {
+      const char *inv = invalid_chars;
+
+      while (*inv)
+	{
+	  if (*inv == *s)
+	    {
+	      if (why_invalid)
+		*why_invalid = g_strdup_printf(_("`%c' is an invalid character in a configuration storage address"), *s);
+	      return FALSE;
+	    }
+	  ++inv;
+	}
+
+      ++s;
+    }
+
+  return TRUE;
+}
+
 gchar* 
 gconf_address_backend(const gchar* address)
 {
@@ -239,11 +279,23 @@ gconf_get_backend(const gchar* address, 
 {
   GConfBackend* backend;
   gchar* name;
+  gchar* why_invalid;
 
   if (loaded_backends == NULL)
     {
       loaded_backends = g_hash_table_new(g_str_hash, g_str_equal);
     }
+
+  why_invalid = NULL;
+  if (!gconf_address_valid (address, &why_invalid))
+    {
+      g_assert (why_invalid != NULL);
+      gconf_set_error (err, GCONF_ERROR_BAD_ADDRESS, _("Bad address `%s': %s"),
+		       address, why_invalid);
+      g_free (why_invalid);
+      return NULL;
+    }
+
   name = gconf_address_backend(address);
       
   if (name == NULL)
Index: gconf/gconf-database.c
===================================================================
RCS file: /home/markmc/gnome-devel/local-repository/gconf/gconf/gconf-database.c,v
retrieving revision 1.36
retrieving revision 1.37
diff -u -p -r1.36 -r1.37
--- gconf/gconf-database.c	29 Mar 2004 09:47:34 -0000	1.36
+++ gconf/gconf-database.c	29 Mar 2004 14:44:30 -0000	1.37
@@ -1039,51 +1039,51 @@ source_notify_cb (GConfSource   *source,
 		  const gchar   *location,
 		  GConfDatabase *db)
 {
-  GConfValue  *value;
-  ConfigValue *cvalue;
-  GError      *error;
-  gboolean     is_default;
-  gboolean     is_writable;
-
   g_return_if_fail (source != NULL);
   g_return_if_fail (location != NULL);
   g_return_if_fail (db != NULL);
 
-  error = NULL;
-  is_default = is_writable = FALSE;
-
-  /* FIXME: only notify if this location isn't already set
-   *        in a source above this one.
-   */
-
-  value = gconf_database_query_value (db,
-				      location,
-				      NULL,
-				      TRUE,
-				      NULL,
-				      &is_default,
-				      &is_writable,
-				      &error);
-  if (error != NULL)
+  if (gconf_sources_is_affected (db->sources, source, location))
     {
-      gconf_log (GCL_WARNING,
-		 _("Error obtaining new value for `%s' after change notification from backend `%s': %s"),
-		 location,
-		 source->address,
-		 error->message);
-      g_error_free (error);
-      return;
-    }
+      GConfValue  *value;
+      ConfigValue *cvalue;
+      GError      *error;
+      gboolean     is_default;
+      gboolean     is_writable;
 
-  cvalue = gconf_corba_value_from_gconf_value (value);
-  gconf_database_notify_listeners (db,
-				   location,
-				   cvalue,
-				   is_default,
-				   is_writable);
+      error = NULL;
+      is_default = is_writable = FALSE;
 
-  CORBA_free (cvalue);
-  gconf_value_free (value);
+      value = gconf_database_query_value (db,
+					  location,
+					  NULL,
+					  TRUE,
+					  NULL,
+					  &is_default,
+					  &is_writable,
+					  &error);
+      if (error != NULL)
+	{
+	  gconf_log (GCL_WARNING,
+		     _("Error obtaining new value for `%s' after change notification from backend `%s': %s"),
+		     location,
+		     source->address,
+		     error->message);
+	  g_error_free (error);
+	  return;
+	}
+
+      cvalue = gconf_corba_value_from_gconf_value (value);
+      gconf_database_notify_listeners (db,
+				       NULL,
+				       location,
+				       cvalue,
+				       is_default,
+				       is_writable,
+				       FALSE);
+      CORBA_free (cvalue);
+      gconf_value_free (value);
+    }
 }
 
 CORBA_unsigned_long
@@ -1245,10 +1245,12 @@ notify_listeners_cb(GConfListeners* list
 
 void
 gconf_database_notify_listeners (GConfDatabase       *db,
+				 GConfSources        *modified_sources,
                                  const gchar         *key,
                                  const ConfigValue   *value,
                                  gboolean             is_default,
-                                 gboolean             is_writable)
+                                 gboolean             is_writable,
+				 gboolean             notify_others)
 {
   ListenerNotifyClosure closure;
   GSList* tmp;
@@ -1278,6 +1280,16 @@ gconf_database_notify_listeners (GConfDa
 
       tmp = g_slist_next(tmp);
     }
+
+  if (notify_others)
+    {
+      g_return_if_fail (modified_sources != NULL);
+
+      gconfd_notify_other_listeners (db, modified_sources, key);
+
+      g_list_free (modified_sources->sources);
+      g_free (modified_sources);
+    }
 }
 
 GConfValue*
@@ -1338,6 +1350,7 @@ gconf_database_set   (GConfDatabase     
                       GError        **err)
 {
   GError *error = NULL;
+  GConfSources *modified_sources;
   
   g_assert(db->listeners != NULL);
   g_return_if_fail(err == NULL || *err == NULL);
@@ -1349,10 +1362,12 @@ gconf_database_set   (GConfDatabase     
   gconf_log(GCL_DEBUG, "Received request to set key `%s'", key);
 #endif
   
-  gconf_sources_set_value(db->sources, key, value, &error);
+  gconf_sources_set_value(db->sources, key, value, &modified_sources, &error);
 
   if (error)
     {
+      g_assert (modified_sources == NULL);
+
       gconf_log(GCL_ERR, _("Error setting value for `%s': %s"),
                 key, error->message);
       
@@ -1364,14 +1379,16 @@ gconf_database_set   (GConfDatabase     
     {
       gconf_database_schedule_sync(db);
       
-      gconf_database_notify_listeners(db, key, cvalue,
-                                      /* Can't possibly be the default,
-                                         since we just set it,
-                                         and must be writable since
-                                         setting it succeeded.
-                                      */
-                                      FALSE,
-                                      TRUE);
+      /* Can't possibly be the default, since we just set it,
+       * and must be writable since setting it succeeded.
+       */
+      gconf_database_notify_listeners (db,
+				       modified_sources,
+				       key,
+				       cvalue,
+                                       FALSE,
+				       TRUE,
+				       TRUE);
     }
 }
 
@@ -1383,6 +1400,7 @@ gconf_database_unset (GConfDatabase     
 {
   ConfigValue* val;
   GError* error = NULL;
+  GConfSources *modified_sources;
   
   g_return_if_fail(err == NULL || *err == NULL);
   
@@ -1392,10 +1410,12 @@ gconf_database_unset (GConfDatabase     
   
   gconf_log(GCL_DEBUG, "Received request to unset key `%s'", key);
 
-  gconf_sources_unset_value(db->sources, key, locale, &error);
+  gconf_sources_unset_value(db->sources, key, locale, &modified_sources, &error);
 
   if (error != NULL)
     {
+      g_assert (modified_sources == NULL);
+
       gconf_log(GCL_ERR, _("Error unsetting `%s': %s"),
                 key, error->message);
 
@@ -1440,8 +1460,13 @@ gconf_database_unset (GConfDatabase     
           
       gconf_database_schedule_sync(db);
 
-      gconf_database_notify_listeners(db, key, val, TRUE, is_writable);
-      
+      gconf_database_notify_listeners(db,
+				      modified_sources,
+				      key,
+				      val,
+				      TRUE,
+				      is_writable,
+				      TRUE);
       CORBA_free(val);
     }
 }
@@ -1476,6 +1501,8 @@ gconf_database_recursive_unset (GConfDat
    */
   if (error != NULL)
     {
+      g_assert (notifies == NULL);
+
       gconf_log (GCL_ERR, _("Error unsetting \"%s\": %s"),
                  key, error->message);
 
@@ -1494,12 +1521,11 @@ gconf_database_recursive_unset (GConfDat
       const gchar* locale_list[] = { NULL, NULL };
       gboolean is_writable = TRUE;
       gboolean is_default = TRUE;
-      char *notify_key = tmp->data;
-      
+      GConfUnsetNotify *notify = tmp->data;
 
       locale_list[0] = locale;
       new_value = gconf_database_query_value (db,
-                                              notify_key,
+                                              notify->key,
                                               locale_list,
                                               TRUE,
                                               NULL,
@@ -1509,7 +1535,7 @@ gconf_database_recursive_unset (GConfDat
 
       if (error)
         gconf_log (GCL_ERR, _("Error getting new value for \"%s\": %s"),
-                   notify_key, error->message);
+                   notify->key, error->message);
       g_propagate_error (err, error);
       error = NULL;
       
@@ -1525,11 +1551,17 @@ gconf_database_recursive_unset (GConfDat
           
       gconf_database_schedule_sync (db);
 
-      gconf_database_notify_listeners (db, notify_key, val,
-                                       is_default, is_writable);
+      gconf_database_notify_listeners (db,
+				       notify->modified_sources,
+				       notify->key,
+				       val,
+                                       is_default,
+				       is_writable,
+				       TRUE);
       
       CORBA_free (val);
-      g_free (notify_key);
+      g_free (notify->key);
+      g_free (notify);
       
       tmp = tmp->next;
     }
@@ -1709,17 +1741,43 @@ gconf_database_clear_cache (GConfDatabas
   gconf_sources_clear_cache(db->sources);
 }
 
-const gchar*
+const gchar *
 gconf_database_get_persistent_name (GConfDatabase *db)
 {
-  if (db->persistent_name == NULL)
+  GList   *tmp;
+  GString *str = NULL;
+
+  if (db->persistent_name != NULL)
+    return db->persistent_name;
+
+  if (db->sources == NULL || db->sources->sources == NULL)
+    {
+      db->persistent_name = g_strdup ("empty");
+      return db->persistent_name;
+    }
+
+  tmp = db->sources->sources;
+  while (tmp != NULL)
     {
-      if (db->sources->sources)
-        db->persistent_name =
-          g_strdup (((GConfSource*)db->sources->sources->data)->address);
+      GConfSource *source = tmp->data;
+
+      if (str == NULL)
+	{
+	  str = g_string_new (source->address);
+	}
       else
-        db->persistent_name = g_strdup ("empty");
+        {
+          g_string_append_c (str, GCONF_DATABASE_LIST_DELIM);
+          g_string_append (str, source->address);
+        }
+
+      tmp = tmp->next;
     }
+
+  g_assert (str != NULL);
+
+  db->persistent_name = str->str;
+  g_string_free (str, FALSE);
 
   return db->persistent_name;
 }
Index: gconf/gconf-database.h
===================================================================
RCS file: /home/markmc/gnome-devel/local-repository/gconf/gconf/gconf-database.h,v
retrieving revision 1.11
retrieving revision 1.12
diff -u -p -r1.11 -r1.12
--- gconf/gconf-database.h	9 Sep 2002 20:13:47 -0000	1.11
+++ gconf/gconf-database.h	29 Mar 2004 14:44:30 -0000	1.12
@@ -70,11 +70,12 @@ CORBA_unsigned_long gconf_database_readd
                                                      const gchar         *where);
 
 void                gconf_database_notify_listeners (GConfDatabase       *db,
+                                                     GConfSources        *modified_sources,
                                                      const gchar         *key,
                                                      const ConfigValue   *value,
                                                      gboolean             is_default,
-                                                     gboolean             is_writable);
-
+                                                     gboolean             is_writable,
+                                                     gboolean             notify_others);
 
 GConfValue* gconf_database_query_value         (GConfDatabase  *db,
                                                 const gchar    *key,
Index: gconf/gconf-engine.h
===================================================================
RCS file: /home/markmc/gnome-devel/local-repository/gconf/gconf/gconf-engine.h,v
retrieving revision 1.10
retrieving revision 1.11
diff -u -p -r1.10 -r1.11
--- gconf/gconf-engine.h	17 Sep 2000 00:55:01 -0000	1.10
+++ gconf/gconf-engine.h	29 Mar 2004 14:44:31 -0000	1.11
@@ -36,11 +36,16 @@ GConfEngine* gconf_engine_get_default   
 /* returns NULL on error; requests single specified source */
 GConfEngine* gconf_engine_get_for_address (const gchar* address,
                                            GError** err);
+GConfEngine* gconf_engine_get_for_addresses (GSList *addresses,
+                                             GError** err);
 void         gconf_engine_unref           (GConfEngine* conf);
 void         gconf_engine_ref             (GConfEngine* conf);
 
 #ifdef GCONF_ENABLE_INTERNALS
-GConfEngine* gconf_engine_get_local      (const gchar* address, GError** err);
+GConfEngine *gconf_engine_get_local               (const char  *address,
+						   GError     **err);
+GConfEngine *gconf_engine_get_local_for_addresses (GSList      *addresses,
+						   GError     **err);
 #endif
 
 /* For use by language bindings only, will be deprecated in GNOME 2.0
Index: gconf/gconf-internals.c
===================================================================
RCS file: /home/markmc/gnome-devel/local-repository/gconf/gconf/gconf-internals.c,v
retrieving revision 1.121
retrieving revision 1.122
diff -u -p -r1.121 -r1.122
--- gconf/gconf-internals.c	22 Oct 2003 21:03:08 -0000	1.121
+++ gconf/gconf-internals.c	29 Mar 2004 14:44:31 -0000	1.122
@@ -917,6 +917,82 @@ gconf_load_source_path(const gchar* file
   return l;
 }
 
+char *
+gconf_address_list_get_persistent_name (GSList *addresses)
+{
+  GSList  *tmp;
+  GString *str = NULL;
+
+  if (!addresses)
+    {
+      return g_strdup ("empty");
+    }
+
+  tmp = addresses;
+  while (tmp != NULL)
+    {
+      const char *address = tmp->data;
+
+      if (str == NULL)
+	{
+	  str = g_string_new (address);
+	}
+      else
+        {
+          g_string_append_c (str, GCONF_DATABASE_LIST_DELIM);
+          g_string_append (str, address);
+        }
+
+      tmp = tmp->next;
+    }
+
+  return g_string_free (str, FALSE);
+}
+
+GSList *
+gconf_persistent_name_get_address_list (const char *persistent_name)
+{
+  char   delim [2] = { GCONF_DATABASE_LIST_DELIM, '\0' };
+  char **address_vector;
+
+  address_vector = g_strsplit (persistent_name, delim, -1);
+  if (address_vector != NULL)
+    {
+      GSList  *retval = NULL;
+      int      i;
+
+      i = 0;
+      while (address_vector [i] != NULL)
+        {
+          retval = g_slist_append (retval, g_strdup (address_vector [i]));
+          ++i;
+        }
+
+      g_strfreev (address_vector);
+
+      return retval;
+    }
+  else
+    {
+      return g_slist_append (NULL, g_strdup (persistent_name));
+    }
+}
+
+void
+gconf_address_list_free (GSList *addresses)
+{
+  GSList *tmp;
+
+  tmp = addresses;
+  while (tmp != NULL)
+    {
+      g_free (tmp->data);
+      tmp = tmp->next;
+    }
+
+  g_slist_free (addresses);
+}
+
 /* This should also support concatting filesystem dirs and keys, 
    or dir and subdir.
 */
Index: gconf/gconf-internals.h
===================================================================
RCS file: /home/markmc/gnome-devel/local-repository/gconf/gconf/gconf-internals.h,v
retrieving revision 1.77
retrieving revision 1.78
diff -u -p -r1.77 -r1.78
--- gconf/gconf-internals.h	27 Mar 2003 10:14:47 -0000	1.77
+++ gconf/gconf-internals.h	29 Mar 2004 14:44:32 -0000	1.78
@@ -39,6 +39,8 @@
 #include "gconf-sources.h"
 #include "GConfX.h"
 
+#define GCONF_DATABASE_LIST_DELIM ';'
+
 gchar*       gconf_key_directory  (const gchar* key);
 const gchar* gconf_key_key        (const gchar* key);
 
@@ -66,6 +68,10 @@ GConfSchema*  gconf_schema_from_corba_sc
 
 gchar* gconf_object_to_string (CORBA_Object obj,
                                GError **err);
+
+char   *gconf_address_list_get_persistent_name (GSList     *addresses);
+GSList *gconf_persistent_name_get_address_list (const char *persistent_name);
+void    gconf_address_list_free                (GSList     *addresses);
 
 const gchar*   gconf_value_type_to_string   (GConfValueType  type);
 GConfValueType gconf_value_type_from_string (const gchar    *str);
Index: gconf/gconf-sources.c
===================================================================
RCS file: /home/markmc/gnome-devel/local-repository/gconf/gconf/gconf-sources.c,v
retrieving revision 1.47
retrieving revision 1.48
diff -u -p -r1.47 -r1.48
--- gconf/gconf-sources.c	29 Mar 2004 09:47:34 -0000	1.47
+++ gconf/gconf-sources.c	29 Mar 2004 14:44:32 -0000	1.48
@@ -77,7 +77,7 @@ gconf_source_free (GConfSource* source)
   g_return_if_fail(source != NULL);
 
   backend = source->backend;
-  
+
   (*source->backend->vtable.destroy_source)(source);
   
   /* Remove ref held by the source. */
@@ -418,7 +418,8 @@ gconf_sources_new_from_source       (GCo
   
   sources = g_new0(GConfSources, 1);
 
-  sources->sources = g_list_append(NULL, source);
+  if (source)
+    sources->sources = g_list_append(NULL, source);
 
   return sources;
 }
@@ -663,6 +664,7 @@ void
 gconf_sources_set_value   (GConfSources* sources,
                            const gchar* key,
                            const GConfValue* value,
+			   GConfSources **modified_sources,
                            GError** err)
 {
   GList* tmp;
@@ -670,6 +672,9 @@ gconf_sources_set_value   (GConfSources*
   g_return_if_fail(sources != NULL);
   g_return_if_fail(key != NULL);
   g_return_if_fail((err == NULL) || (*err == NULL));
+
+  if (modified_sources)
+    *modified_sources = NULL;
   
   if (!gconf_key_check(key, err))
     return;
@@ -699,7 +704,11 @@ gconf_sources_set_value   (GConfSources*
         {
           /* source was writable, err may be set */
           gconf_log (GCL_DEBUG, "%s was writable in %s", key, src->address);
-          return;
+	  if (modified_sources)
+	    {
+	      *modified_sources = gconf_sources_new_from_source (src);
+	    }
+	  return;
         }
       else
         {
@@ -737,6 +746,7 @@ void
 gconf_sources_unset_value   (GConfSources* sources,
                              const gchar* key,
                              const gchar* locale,
+			     GConfSources **modified_sources,
                              GError** err)
 {
   /* We unset in every layer we can write to... */
@@ -768,12 +778,40 @@ gconf_sources_unset_value   (GConfSource
                   return;
                 }
             }
+
+	  if (modified_sources)
+	    {
+	      if (*modified_sources)
+		{
+		  *modified_sources = gconf_sources_new_from_source (src);
+		}
+	      else
+		{
+		  (*modified_sources)->sources =
+		    g_list_prepend ((*modified_sources)->sources, src);
+		}
+	    }
         }
       
       tmp = g_list_next(tmp);
     }
 }
 
+static GSList *
+prepend_unset_notify (GSList       *notifies,
+		      GConfSources *modified_sources,
+		      char         *key)
+{
+  GConfUnsetNotify *notify;
+
+  notify = g_new0 (GConfUnsetNotify, 1);
+
+  notify->modified_sources = modified_sources;
+  notify->key              = key;
+
+  return g_slist_append (notifies, notify);
+}
+
 static void
 recursive_unset_helper (GConfSources   *sources,
                         const char     *key,
@@ -787,6 +825,14 @@ recursive_unset_helper (GConfSources   *
   GSList* entries;
   GSList* tmp;
   const char *locales[2] = { NULL, NULL };
+  GConfSources* modified_sources;
+  GConfSources** modifiedp = NULL;
+
+  if (notifies)
+    {
+      modified_sources = NULL;
+      modifiedp = &modified_sources;
+    }
   
   err = NULL;
   
@@ -849,16 +895,19 @@ recursive_unset_helper (GConfSources   *
       while (tmp != NULL)
         {
           GConfEntry* entry = tmp->data;
-          char *full = gconf_concat_dir_and_key (key,
-                                                 gconf_entry_get_key (entry));
+          char *full, *freeme;
+
+	  full = freeme = gconf_concat_dir_and_key (key,
+						    gconf_entry_get_key (entry));
           
-          if (notifies)
-            *notifies = g_slist_prepend (*notifies, g_strdup (full));
           
-          gconf_sources_unset_value (sources,
-                                     full,
-                                     locale,
-                                     &err);
+          gconf_sources_unset_value (sources, full, locale, modifiedp, &err);
+          if (notifies)
+	    {
+	      *notifies = prepend_unset_notify (*notifies, modified_sources, full);
+	      freeme = NULL;
+	    }
+
           if (err != NULL)
             {
               gconf_log (GCL_DEBUG, "Error unsetting '%s': %s\n",
@@ -890,7 +939,7 @@ recursive_unset_helper (GConfSources   *
             }
           
           gconf_entry_free (entry);
-          g_free (full);
+          g_free (freeme);
           
           tmp = g_slist_next (tmp);
         }
@@ -898,10 +947,13 @@ recursive_unset_helper (GConfSources   *
       g_slist_free (entries);
     }
 
+  gconf_sources_unset_value (sources, key, locale, modifiedp, &err);
   if (notifies)
-    *notifies = g_slist_prepend (*notifies, g_strdup (key));
-  
-  gconf_sources_unset_value (sources, key, locale, &err);
+    {
+      *notifies = prepend_unset_notify (*notifies,
+					modified_sources,
+					g_strdup (key));
+    }
   
   if (err != NULL)
     {
@@ -935,7 +987,28 @@ gconf_sources_recursive_unset (GConfSour
                           notifies, &first_error);
 
   if (first_error)
-    g_propagate_error (err, first_error);
+    {
+      if (notifies != NULL && *notifies != NULL)
+	{
+	  GSList *tmp;
+
+	  tmp = *notifies;
+	  while (tmp != NULL)
+	    {
+	      GConfUnsetNotify *notify = tmp->data;
+
+	      g_free (notify->key);
+	      g_free (notify);
+
+	      tmp = tmp->next;
+	    }
+
+	  g_slist_free (*notifies);
+	  *notifies = NULL;
+	}
+
+      g_propagate_error (err, first_error);
+    }
 }
 
 gboolean
@@ -1636,4 +1709,72 @@ gconf_sources_remove_listener (GConfSour
 
       tmp = tmp->next;
     }
+}
+
+/* Non-allocating variant of gconf_address_resource()
+ */
+static const char *
+get_address_resource (const char *address)
+{
+  const char *start;
+
+  g_return_val_if_fail (address != NULL, NULL);
+
+  start = strchr (address, ':');
+  if (start != NULL)
+    {
+      start = strchr (++start, ':');
+
+      if (start != NULL)
+        start++;
+    }
+
+  return start;
+}
+
+/* Return TRUE if
+ *  1. @sources contains @modified_src and
+ *  2. @key is not set in any source above @modified_src.
+ */
+gboolean
+gconf_sources_is_affected (GConfSources *sources,
+                           GConfSource  *modified_src,
+                           const char   *key)
+{
+  const char *modified_resource;
+  GList      *tmp;
+
+  modified_resource = get_address_resource (modified_src->address);
+
+  tmp = sources->sources;
+  while (tmp != NULL)
+    {
+      GConfSource *source = tmp->data;
+
+      if (source->backend == modified_src->backend &&
+          strcmp (modified_resource, get_address_resource (source->address)) == 0)
+        break;
+
+      tmp = tmp->next;
+    }
+
+  if (tmp)
+    {
+      tmp = tmp->prev;
+      while (tmp != NULL)
+	{
+	  GConfValue *val;
+
+	  val = gconf_source_query_value (tmp->data, key, NULL, NULL, NULL);
+	  if (val != NULL)
+	    {
+	      gconf_value_free (val);
+	      return FALSE;
+	    }
+
+	  tmp = tmp->prev;
+	}
+    }
+
+  return TRUE;
 }
Index: gconf/gconf-sources.h
===================================================================
RCS file: /home/markmc/gnome-devel/local-repository/gconf/gconf/gconf-sources.h,v
retrieving revision 1.23
retrieving revision 1.24
diff -u -p -r1.23 -r1.24
--- gconf/gconf-sources.h	29 Mar 2004 09:47:34 -0000	1.23
+++ gconf/gconf-sources.h	29 Mar 2004 14:44:33 -0000	1.24
@@ -65,9 +65,15 @@ typedef struct _GConfSources GConfSource
 
 struct _GConfSources {
   GList* sources;
-  
 };
 
+typedef struct
+{
+  GConfSources *modified_sources;
+  char         *key;
+} GConfUnsetNotify;
+
+
 /* Even on error, this gives you an empty source list, i.e.  never
    returns NULL but may set the error if some addresses weren't
    resolved and may contain no sources.  */
@@ -87,10 +93,12 @@ GConfValue*   gconf_sources_query_value 
 void          gconf_sources_set_value          (GConfSources  *sources,
                                                 const gchar   *key,
                                                 const GConfValue *value,
+						GConfSources **modified_sources,
                                                 GError   **err);
 void          gconf_sources_unset_value        (GConfSources  *sources,
                                                 const gchar   *key,
                                                 const gchar   *locale,
+						GConfSources **modified_sources,
                                                 GError   **err);
 void          gconf_sources_recursive_unset    (GConfSources  *sources,
                                                 const gchar   *key,
@@ -137,5 +145,9 @@ void          gconf_sources_add_listener
 					        const gchar           *location);
 void          gconf_sources_remove_listener    (GConfSources          *sources,
 						guint                  id);
+
+gboolean      gconf_sources_is_affected        (GConfSources *sources,
+						GConfSource  *modified_src,
+						const char   *key);
 
 #endif
Index: gconf/gconf.c
===================================================================
RCS file: /home/markmc/gnome-devel/local-repository/gconf/gconf/gconf.c,v
retrieving revision 1.144
retrieving revision 1.145
diff -u -p -r1.144 -r1.145
--- gconf/gconf.c	22 Oct 2003 21:03:08 -0000	1.144
+++ gconf/gconf.c	29 Mar 2004 14:44:33 -0000	1.145
@@ -80,10 +80,15 @@ struct _GConfEngine {
      local engines don't do notification! */
   GConfSources* local_sources;
   
-  /* An address if this is not the default engine;
+  /* A list of addresses that make up this db
+   * if this is not the default engine;
    * NULL if it's the default
    */
-  gchar *address;
+  GSList *addresses;
+
+  /* A concatentation of the addresses above.
+   */
+  char *persistent_address;
 
   gpointer user_data;
   GDestroyNotify dnotify;
@@ -147,7 +152,7 @@ static ConfigDatabase gconf_engine_get_d
 
 static void         register_engine           (GConfEngine    *conf);
 static void         unregister_engine         (GConfEngine    *conf);
-static GConfEngine *lookup_engine             (const gchar    *address);
+static GConfEngine *lookup_engine             (GSList         *addresses);
 static GConfEngine *lookup_engine_by_database (ConfigDatabase  db);
 
 
@@ -320,9 +325,40 @@ gconf_engine_connect (GConfEngine *conf,
     return FALSE; /* Error should already be set */
 
   if (conf->is_default)
-    db = ConfigServer_get_default_database (cs, &ev);      
+    {
+      db = ConfigServer_get_default_database (cs, &ev);      
+    }
+  else if (conf->addresses->next == NULL) /* single element list */
+    {
+      db = ConfigServer_get_database (cs, conf->addresses->data, &ev);
+    }
   else
-    db = ConfigServer_get_database (cs, conf->address, &ev);
+    {
+      ConfigServer2_AddressList *address_list;
+      GSList                    *tmp;
+      int                        i;
+
+      address_list = ConfigServer2_AddressList__alloc ();
+      address_list->_length  = address_list->_maximum = g_slist_length (conf->addresses);
+      address_list->_buffer  = ConfigServer2_AddressList_allocbuf (address_list->_length);
+      address_list->_release = CORBA_TRUE;
+
+      i = 0;
+      tmp = conf->addresses;
+      while (tmp != NULL)
+        {
+          g_assert (i < address_list->_length);
+
+          address_list->_buffer [i] = CORBA_string_dup (tmp->data);
+
+          tmp = tmp->next;
+          i++;
+        }
+
+      db = ConfigServer2_get_database_for_addresses ((ConfigServer2) cs, address_list, &ev);
+
+      CORBA_free (address_list);
+    }
 
   if (gconf_server_broken(&ev))
     {
@@ -343,7 +379,7 @@ gconf_engine_connect (GConfEngine *conf,
       if (err)
         *err = gconf_error_new(GCONF_ERROR_BAD_ADDRESS,
                                _("Server couldn't resolve the address `%s'"),
-                               conf->address ? conf->address : "default");
+                               conf->persistent_address);
           
       return FALSE;
     }
@@ -375,21 +411,29 @@ static GHashTable *engines_by_address = 
 static void
 register_engine (GConfEngine *conf)
 {
-  g_return_if_fail (conf->address != NULL);
+  g_return_if_fail (conf->addresses != NULL);
+
+  g_assert (conf->persistent_address == NULL);
+
+  conf->persistent_address = 
+          gconf_address_list_get_persistent_name (conf->addresses);
 
   if (engines_by_address == NULL)
     engines_by_address = g_hash_table_new (g_str_hash, g_str_equal);
 
-  g_hash_table_insert (engines_by_address, conf->address, conf);
+  g_hash_table_insert (engines_by_address, conf->persistent_address, conf);
 }
 
 static void
 unregister_engine (GConfEngine *conf)
 {
-  g_return_if_fail (conf->address != NULL);
   g_return_if_fail (engines_by_address != NULL);
+
+  g_assert (conf->persistent_address != NULL);
   
-  g_hash_table_remove (engines_by_address, conf->address);
+  g_hash_table_remove (engines_by_address, conf->persistent_address);
+  g_free (conf->persistent_address);
+  conf->persistent_address = NULL;
 
   if (g_hash_table_size (engines_by_address) == 0)
     {
@@ -400,12 +444,23 @@ unregister_engine (GConfEngine *conf)
 }
 
 static GConfEngine *
-lookup_engine (const gchar *address)
+lookup_engine (GSList *addresses)
 {
-  if (engines_by_address)
-    return g_hash_table_lookup (engines_by_address, address);
-  else
-    return NULL;
+  if (engines_by_address != NULL)
+    {
+      GConfEngine *retval;
+      char        *key;
+
+      key = gconf_address_list_get_persistent_name (addresses);
+
+      retval = g_hash_table_lookup (engines_by_address, key);
+
+      g_free (key);
+
+      return retval;
+    }
+
+  return NULL;
 }
 
 
@@ -437,6 +492,24 @@ gconf_engine_get_local      (const gchar
   return conf;
 }
 
+GConfEngine *
+gconf_engine_get_local_for_addresses (GSList  *addresses,
+				      GError **err)
+{
+  GConfEngine *conf;
+
+  g_return_val_if_fail (addresses != NULL, NULL);
+  g_return_val_if_fail (err == NULL || *err == NULL, NULL);
+  
+  conf = gconf_engine_blank (FALSE);
+
+  conf->local_sources = gconf_sources_new_from_addresses (addresses, err);
+
+  g_assert (gconf_engine_is_local (conf));
+  
+  return conf;
+}
+
 GConfEngine*
 gconf_engine_get_default (void)
 {
@@ -466,18 +539,64 @@ gconf_engine_get_default (void)
 }
 
 GConfEngine*
-gconf_engine_get_for_address (const gchar* address, GError** err)
+gconf_engine_get_for_address (const char  *address,
+			      GError     **err)
+{
+  GConfEngine *conf;
+  GSList      *addresses;
+
+  addresses = g_slist_append (NULL, g_strdup (address));
+
+  conf = lookup_engine (addresses);
+
+  if (conf == NULL)
+    {
+      conf = gconf_engine_blank (TRUE);
+
+      conf->is_default = FALSE;
+      conf->addresses = addresses;
+
+      if (!gconf_engine_connect (conf, TRUE, err))
+        {
+          gconf_engine_unref (conf);
+          return NULL;
+        }
+
+      register_engine (conf);
+    }
+  else
+    {
+      g_free (addresses->data);
+      g_slist_free (addresses);
+      conf->refcount += 1;
+    }
+  
+  return conf;
+}
+
+GConfEngine*
+gconf_engine_get_for_addresses (GSList *addresses, GError** err)
 {
   GConfEngine* conf;
 
-  conf = lookup_engine (address);
+  conf = lookup_engine (addresses);
 
   if (conf == NULL)
     {
-      conf = gconf_engine_blank(TRUE);
+      GSList *tmp;
+
+      conf = gconf_engine_blank (TRUE);
 
       conf->is_default = FALSE;
-      conf->address = g_strdup (address);
+      conf->addresses = NULL;
+
+      tmp = addresses;
+      while (tmp != NULL)
+        {
+          conf->addresses = g_slist_append (conf->addresses,
+                                            g_strdup (tmp->data));
+          tmp = tmp->next;
+        }
 
       if (!gconf_engine_connect (conf, TRUE, err))
         {
@@ -568,10 +687,16 @@ gconf_engine_unref(GConfEngine* conf)
               (* conf->dnotify) (conf->user_data);
             }
           
-          /* do this after removing the notifications,
-             to avoid funky race conditions */
-          if (conf->address)
-            unregister_engine (conf);
+          if (conf->addresses)
+	    {
+	      gconf_address_list_free (conf->addresses);
+	      conf->addresses = NULL;
+	    }
+
+	  if (conf->persistent_address)
+	    {
+	      unregister_engine (conf);
+	    }
 
           /* Release the ConfigDatabase */
           gconf_engine_detach (conf);
@@ -1096,7 +1221,7 @@ gconf_engine_set (GConfEngine* conf, con
     {
       GError* error = NULL;
       
-      gconf_sources_set_value(conf->local_sources, key, value, &error);
+      gconf_sources_set_value(conf->local_sources, key, value, NULL, &error);
 
       if (error != NULL)
         {
@@ -1174,7 +1299,7 @@ gconf_engine_unset (GConfEngine* conf, c
     {
       GError* error = NULL;
       
-      gconf_sources_unset_value(conf->local_sources, key, NULL, &error);
+      gconf_sources_unset_value(conf->local_sources, key, NULL, NULL, &error);
 
       if (error != NULL)
         {
@@ -2302,7 +2427,15 @@ update_listener (PortableServer_Servant 
       if (strcmp (address, "def") == 0)
         conf = default_engine;
       else
-        conf = lookup_engine (address);
+        {
+          GSList  *addresses;
+
+          addresses = gconf_persistent_name_get_address_list (address);
+    
+          conf = lookup_engine (addresses);
+    
+          gconf_address_list_free (addresses);
+        }
 
       if (conf)
         gconf_engine_set_database (conf,
Index: gconf/gconfd.c
===================================================================
RCS file: /home/markmc/gnome-devel/local-repository/gconf/gconf/gconfd.c,v
retrieving revision 1.137
retrieving revision 1.138
diff -u -p -r1.137 -r1.138
--- gconf/gconfd.c	22 Oct 2003 21:03:08 -0000	1.137
+++ gconf/gconfd.c	29 Mar 2004 14:44:34 -0000	1.138
@@ -103,8 +103,8 @@ static void                 shutdown_dat
 static void                 set_default_database (GConfDatabase* db);
 static void                 register_database (GConfDatabase* db);
 static void                 unregister_database (GConfDatabase* db);
-static GConfDatabase*       lookup_database (const gchar *address);
-static GConfDatabase*       obtain_database (const gchar *address,
+static GConfDatabase*       lookup_database (GSList *addresses);
+static GConfDatabase*       obtain_database (GSList *addresses,
                                              GError **err);
 static void                 drop_old_databases (void);
 static gboolean             no_databases_in_use (void);
@@ -124,7 +124,7 @@ static gboolean in_shutdown = FALSE;
  * CORBA goo
  */
 
-static ConfigServer server = CORBA_OBJECT_NIL;
+static ConfigServer2 server = CORBA_OBJECT_NIL;
 static PortableServer_POA the_poa;
 static GConfLock *daemon_lock = NULL;
 
@@ -137,6 +137,11 @@ gconfd_get_database(PortableServer_Serva
                     const CORBA_char* address,
                     CORBA_Environment* ev);
 
+static ConfigDatabase
+gconfd_get_database_for_addresses (PortableServer_Servant           servant,
+				   const ConfigServer2_AddressList *addresses,
+				   CORBA_Environment               *ev);
+
 static void
 gconfd_add_client (PortableServer_Servant servant,
                    const ConfigListener client,
@@ -169,8 +174,13 @@ static POA_ConfigServer__epv server_epv 
   gconfd_shutdown
 };
 
-static POA_ConfigServer__vepv poa_server_vepv = { &base_epv, &server_epv };
-static POA_ConfigServer poa_server_servant = { NULL, &poa_server_vepv };
+static POA_ConfigServer2__epv server2_epv = { 
+  NULL,
+  gconfd_get_database_for_addresses
+};
+
+static POA_ConfigServer2__vepv poa_server_vepv = { &base_epv, &server_epv, &server2_epv };
+static POA_ConfigServer2 poa_server_servant = { NULL, &poa_server_vepv };
 
 static ConfigDatabase
 gconfd_get_default_database(PortableServer_Servant servant,
@@ -195,19 +205,51 @@ gconfd_get_database(PortableServer_Serva
                     CORBA_Environment* ev)
 {
   GConfDatabase *db;
+  GSList *addresses;
   GError* error = NULL;  
 
   if (gconfd_check_in_shutdown (ev))
     return CORBA_OBJECT_NIL;
   
-  db = obtain_database (address, &error);
+  addresses = g_slist_append (NULL, (char *) address);
+  db = obtain_database (addresses, &error);
+  g_slist_free (addresses);
 
   if (db != NULL)
     return CORBA_Object_duplicate (db->objref, ev);
-  else if (gconf_set_exception(&error, ev))
-    return CORBA_OBJECT_NIL;
-  else
+
+  gconf_set_exception (&error, ev);
+
+  return CORBA_OBJECT_NIL;
+}
+
+static ConfigDatabase
+gconfd_get_database_for_addresses (PortableServer_Servant           servant,
+				   const ConfigServer2_AddressList *seq,
+				   CORBA_Environment               *ev)
+{
+  GConfDatabase  *db;
+  GSList         *addresses = NULL;
+  GError         *error = NULL;  
+  int             i;
+
+  if (gconfd_check_in_shutdown (ev))
     return CORBA_OBJECT_NIL;
+
+  i = 0;
+  while (i < seq->_length)
+    addresses = g_slist_append (addresses, seq->_buffer [i++]);
+
+  db = obtain_database (addresses, &error);
+
+  g_slist_free (addresses);
+
+  if (db != NULL)
+    return CORBA_Object_duplicate (db->objref, ev);
+
+  gconf_set_exception (&error, ev);
+
+  return CORBA_OBJECT_NIL;
 }
 
 static void
@@ -613,7 +655,7 @@ main(int argc, char** argv)
 
   orb = gconf_orb_get ();
   
-  POA_ConfigServer__init (&poa_server_servant, &ev);
+  POA_ConfigServer2__init (&poa_server_servant, &ev);
   
   the_poa = (PortableServer_POA)CORBA_ORB_resolve_initial_references(orb, "RootPOA", &ev);
   PortableServer_POAManager_activate(PortableServer_POA__get_the_POAManager(the_poa, &ev), &ev);
@@ -835,7 +877,7 @@ gconf_main_is_running (void)
  */
 
 static GList* db_list = NULL;
-static GHashTable* dbs_by_address = NULL;
+static GHashTable* dbs_by_addresses = NULL;
 static GConfDatabase *default_db = NULL;
 
 static void
@@ -844,13 +886,9 @@ init_databases (void)
   gconfd_need_log_cleanup ();
   
   g_assert(db_list == NULL);
-  g_assert(dbs_by_address == NULL);
+  g_assert(dbs_by_addresses == NULL);
   
-  dbs_by_address = g_hash_table_new (g_str_hash, g_str_equal);
-
-  /* Default database isn't in the address hash since it has
-     multiple addresses in a stack
-  */
+  dbs_by_addresses = g_hash_table_new (g_str_hash, g_str_equal);
 }
 
 static void
@@ -859,10 +897,8 @@ set_default_database (GConfDatabase* db)
   gconfd_need_log_cleanup ();
   
   default_db = db;
-  
-  /* Default database isn't in the address hash since it has
-     multiple addresses in a stack
-  */
+
+  register_database (db);
 }
 
 static void
@@ -871,9 +907,9 @@ register_database (GConfDatabase *db)
   gconfd_need_log_cleanup ();
   
   if (db->sources->sources)
-    safe_g_hash_table_insert(dbs_by_address,
-                             ((GConfSource*)db->sources->sources->data)->address,
-                             db);
+    safe_g_hash_table_insert (dbs_by_addresses,
+			      (char *) gconf_database_get_persistent_name (db),
+			      db);
   
   db_list = g_list_prepend (db_list, db);
 }
@@ -884,8 +920,10 @@ unregister_database (GConfDatabase *db)
   gconfd_need_log_cleanup ();
   
   if (db->sources->sources)
-    g_hash_table_remove(dbs_by_address,
-                        ((GConfSource*)(db->sources->sources->data))->address);
+    {
+      g_hash_table_remove (dbs_by_addresses,
+			   gconf_database_get_persistent_name (db));
+    }
 
   db_list = g_list_remove (db_list, db);
 
@@ -893,32 +931,37 @@ unregister_database (GConfDatabase *db)
 }
 
 static GConfDatabase*
-lookup_database (const gchar *address)
+lookup_database (GSList *addresses)
 {
-  if (address == NULL)
+  GConfDatabase *retval;
+  char          *key;
+
+  if (addresses == NULL)
     return default_db;
-  else
-    return g_hash_table_lookup (dbs_by_address, address);
+
+  key = gconf_address_list_get_persistent_name (addresses);
+
+  retval = g_hash_table_lookup (dbs_by_addresses, key);
+
+  g_free (key);
+
+  return retval;
 }
 
 static GConfDatabase*
-obtain_database (const gchar *address,
+obtain_database (GSList  *addresses,
                  GError **err)
 {
-  
   GConfSources* sources;
-  GSList* addresses = NULL;
   GError* error = NULL;
   GConfDatabase *db;
 
-  db = lookup_database (address);
+  db = lookup_database (addresses);
 
   if (db)
     return db;
 
-  addresses = g_slist_append(addresses, g_strdup(address));
   sources = gconf_sources_new_from_addresses(addresses, &error);
-  g_slist_free (addresses);
 
   if (error != NULL)
     {
@@ -1005,10 +1048,10 @@ shutdown_databases (void)
   g_list_free (db_list);
   db_list = NULL;
 
-  if (dbs_by_address)
-    g_hash_table_destroy(dbs_by_address);
+  if (dbs_by_addresses)
+    g_hash_table_destroy(dbs_by_addresses);
 
-  dbs_by_address = NULL;
+  dbs_by_addresses = NULL;
 
   if (default_db)
     gconf_database_free (default_db);
@@ -1026,6 +1069,76 @@ no_databases_in_use (void)
     gconf_listeners_count (default_db->listeners) == 0;
 }
 
+void
+gconfd_notify_other_listeners (GConfDatabase *modified_db,
+			       GConfSources  *modified_sources,
+                               const char    *key)
+{
+  GList *tmp;
+
+  if (!modified_sources)
+    return;
+  
+  tmp = db_list;
+  while (tmp != NULL)
+    {
+      GConfDatabase *db = tmp->data;
+
+      if (db != modified_db)
+	{
+	  GList *tmp2;
+
+	  tmp2 = modified_sources->sources;
+	  while (tmp2)
+	    {
+	      GConfSource *modified_source = tmp2->data;
+
+	      if (gconf_sources_is_affected (db->sources, modified_source, key))
+		{
+		  GConfValue  *value;
+		  ConfigValue *cvalue;
+		  GError      *error;
+		  gboolean     is_default;
+		  gboolean     is_writable;
+
+		  error = NULL;
+		  value = gconf_database_query_value (db,
+						      key,
+						      NULL,
+						      TRUE,
+						      NULL,
+						      &is_default,
+						      &is_writable,
+						      &error);
+		  if (error != NULL)
+		    {
+		      gconf_log (GCL_WARNING,
+				 _("Error obtaining new value for `%s': %s"),
+				 key, error->message);
+		      g_error_free (error);
+		      return;
+		    }
+
+		  cvalue = gconf_corba_value_from_gconf_value (value);
+		  gconf_database_notify_listeners (db,
+						   NULL,
+						   key,
+						   cvalue,
+						   is_default,
+						   is_writable,
+						   FALSE);
+		  CORBA_free (cvalue);
+		  gconf_value_free (value);
+		}
+
+	      tmp2 = tmp2->next;
+	    }
+	}
+
+      tmp = tmp->next;
+    }
+}
+
 /*
  * Cleanup
  */
@@ -1841,12 +1954,20 @@ listener_logentry_restore_and_destroy_fo
                                                gpointer data)
 {
   ListenerLogEntry *lle = key;
-  GConfDatabase *db;
+  GConfDatabase *db = NULL;
   
   if (strcmp (lle->address, "def") == 0)
     db = default_db;
   else
-    db = obtain_database (lle->address, NULL);
+    {
+      GSList *addresses;
+
+      addresses = gconf_persistent_name_get_address_list (lle->address);
+
+      db = obtain_database (addresses, NULL);
+
+      gconf_address_list_free (addresses);
+    }
   
   if (db == NULL)
     {
Index: gconf/gconfd.h
===================================================================
RCS file: /home/markmc/gnome-devel/local-repository/gconf/gconf/gconfd.h,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -p -r1.7 -r1.8
--- gconf/gconfd.h	22 Oct 2003 21:03:09 -0000	1.7
+++ gconf/gconfd.h	29 Mar 2004 14:44:34 -0000	1.8
@@ -44,6 +44,10 @@ gboolean gconfd_logfile_change_listener 
 
 gboolean gconfd_check_in_shutdown (CORBA_Environment *ev);
 
+void gconfd_notify_other_listeners (GConfDatabase *modified_db,
+				    GConfSources  *modified_sources,
+                                    const char    *key);
+
 void gconfd_need_log_cleanup (void);
 
 #ifdef __cplusplus
Index: gconf/gconftool.c
===================================================================
RCS file: /home/markmc/gnome-devel/local-repository/gconf/gconf/gconftool.c,v
retrieving revision 1.87
retrieving revision 1.88
diff -u -p -r1.87 -r1.88
--- gconf/gconftool.c	27 Oct 2003 18:11:18 -0000	1.87
+++ gconf/gconftool.c	29 Mar 2004 14:44:35 -0000	1.88
@@ -703,12 +703,6 @@ main (int argc, char** argv)
       return 1;
     }
 
-  if (config_source && !use_local_source)
-    {
-      g_printerr (_("You should use --direct when using a non-default configuration source\n"));
-      return 1;
-    }
-  
   if (!gconf_init(argc, argv, &err))
     {
       g_printerr (_("Failed to init GConf: %s\n"), err->message);
@@ -780,10 +774,16 @@ main (int argc, char** argv)
     conf = gconf_engine_get_default();
   else
     {
+      GSList *addresses;
+
+      addresses = gconf_persistent_name_get_address_list (config_source);
+
       if (use_local_source)
-        conf = gconf_engine_get_local(config_source, &err);
+        conf = gconf_engine_get_local_for_addresses (addresses, &err);
       else
-        conf = gconf_engine_get_for_address(config_source, &err);
+        conf = gconf_engine_get_for_addresses (addresses, &err);
+
+      gconf_address_list_free (addresses);
     }
   
   if (conf == NULL)


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