supporting notifications from backends



Hi Cyrille,
	So, I spent some time mulling over your patch for bug #107692[1],
reminding myself of GConf's weird internal semantics and trying to
figure out whether we were missing any obvious corner cases.

	Your patch generally looks good. I've made some changes:

  + Extended the backend vtable rather than adding a new one

  + Removed the init_listeners function as we don't have an initial
    listeners list (as you say) and its more usual to allow different 
    callbacks per-listener, even if we don't use them.

  + Added an identifier for each listener which we can use in order to 
    remove the listeners. Its just re-using the client listener id. 
    Since the backend can be used multiple times in a single stack, the 
    listener id will only be unique within the context of a single 
    GConfSource.

  + Fixed a leak of the ConfigValue in source_notify_cb()

  + Added a FIXME to source_notify_cb(). Basically, we should be able to
    prevent notifying the client of a change if the change won't 
    actually cause the client to see a different value. I'm going to try
    and get the patch in #88829 merged soon too and we should be able to
    re-use some of that to fix this. See gconf_sources_is_affected() in
    the patch with that bug.

  + Added documentation and cleaned up the coding style a bit

	That patch is attached below. Let me know if you see any problems with
it.

Thanks,
Mark.

[1] - http://bugzilla.gnome.org/show_bug.cgi?id=107692
[2] - http://bugzilla.gnome.org/show_bug.cgi?id=88829

Index: backends/markup-backend.c
===================================================================
RCS file: /home/markmc/gnome-devel/local-repository/gconf/backends/markup-backend.c,v
retrieving revision 1.8
diff -u -p -r1.8 markup-backend.c
--- backends/markup-backend.c	24 Mar 2004 20:03:01 -0000	1.8
+++ backends/markup-backend.c	25 Mar 2004 15:04:24 -0000
@@ -151,7 +151,9 @@ static GConfBackendVTable markup_vtable 
   sync_all,
   destroy_source,
   clear_cache,
-  blow_away_locks
+  blow_away_locks,
+  NULL, /* add_listener */
+  NULL /* remove_listener */
 };
 
 static void          
Index: backends/xml-backend.c
===================================================================
RCS file: /home/markmc/gnome-devel/local-repository/gconf/backends/xml-backend.c,v
retrieving revision 1.86
diff -u -p -r1.86 xml-backend.c
--- backends/xml-backend.c	24 Mar 2004 20:03:01 -0000	1.86
+++ backends/xml-backend.c	25 Mar 2004 15:04:47 -0000
@@ -228,7 +228,9 @@ static GConfBackendVTable xml_vtable = {
   sync_all,
   destroy_source,
   clear_cache,
-  blow_away_locks
+  blow_away_locks,
+  NULL, /* add_listener */
+  NULL /* remove_listener */
 };
 
 static void          
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.8
diff -u -p -r1.8 gconf-backend.sgml
--- doc/gconf/tmpl/gconf-backend.sgml	24 Mar 2004 20:03:05 -0000	1.8
+++ doc/gconf/tmpl/gconf-backend.sgml	25 Mar 2004 15:54:26 -0000
@@ -23,13 +23,23 @@ called gconf_backend_get_vtable() that r
 </para>
 
 <para>
-Here are the methods the backend must implement, and their specification:
+Here is the specification of the vtable members:
 
 <informaltable pgwide="1" frame="none">
 <tgroup cols="2"><colspec colwidth="2*"/><colspec colwidth="8*"/>
 <tbody>
 
 <row>
+<entry>@vtable_size</entry> 
+<entry>
+The size of the vtable structure. This is used by the daemon to ensure that
+a mismatch between the version of GConf the backend was compiled against and
+the version the daemon was compiled against can be handled gracefully. Set
+this field to sizeof (GConfBackendVtable).
+</entry>
+</row>
+ 
+<row>
 <entry>@shutdown</entry> 
 <entry>Called prior to unloading the dynamic
 module. Should ensure that no functions or static/global variables from the
@@ -227,7 +237,67 @@ Should destroy a source obtained with @r
 
 </row>
  
+<row>
+<entry>@clear_cache</entry>
+
+<entry>
+Discard any cached data after saving the data to permanent storage.
+</entry>
+
+</row>
+ 
+<row>
+<entry>@blow_away_locks</entry>
+
+<entry>
+Unconditionally discard any locks whether they are stale or otherwise in
+order to force the backend to be able to obtain access to its data store.
+</entry>
+
+</row>
+ 
+<row>
+<entry>@add_listener</entry>
+
+<entry>
+If it is possible for entries to be changed concurrently by another
+daemon, the backend may support notifying the daemon (and any listening
+clients) of such changes. This function should add a listener to a
+section of the tree and when any of the following events occur, the
+backend should invoke the notify function with the key that has changed:
+ <itemizedlist mark="bullet">
+  <listitem>
+    <para>If the entry is set or unset</para>
+  </listitem>
+  <listitem>
+    <para>If the entry's value changes</para>
+  </listitem>
+  <listitem>
+    <para>If the entry's schema name changes</para>
+  </listitem>
+  <listitem>
+    <para>
+      If the entry is a schema and its value in <emphasis>any</emphasis>
+      locale changes
+    </para>
+  </listitem>
+ </itemizedlist>
+Note, the backend should <emphasis>not</emphasis> notify the daemon of
+any changes that originated from the daemon itself.
+</entry>
+
+</row>
+
+<row>
+<entry>@remove_listener</entry>
+
+<entry>
+Remove a listener added with @add_listener. The listener is identified
+by the integer supplied.
+</entry>
 
+</row>
+ 
 </tbody></tgroup></informaltable>
 </para>
 
@@ -251,6 +321,8 @@ Should destroy a source obtained with @r
 @destroy_source: 
 @clear_cache: 
 @blow_away_locks: 
+ add_listener: 
+ remove_listener: 
 
 <!-- ##### STRUCT GConfBackend ##### -->
 <para>
Index: gconf/gconf-backend.h
===================================================================
RCS file: /home/markmc/gnome-devel/local-repository/gconf/gconf/gconf-backend.h,v
retrieving revision 1.31
diff -u -p -r1.31 gconf-backend.h
--- gconf/gconf-backend.h	24 Mar 2004 20:03:09 -0000	1.31
+++ gconf/gconf-backend.h	25 Mar 2004 14:27:40 -0000
@@ -133,6 +133,15 @@ struct _GConfBackendVTable {
 
   /* used by gconf-sanity-check */
   void                (* blow_away_locks) (const char *address);
+
+  void                (* add_listener)    (GConfSource           *source,
+					   guint                  id,
+					   const gchar           *namespace_section,
+					   GConfSourceNotifyFunc  notify_func,
+					   gpointer               user_data);
+
+  void                (* remove_listener) (GConfSource           *source,
+					   guint                  id);
 };
 
 struct _GConfBackend {
Index: gconf/gconf-database.c
===================================================================
RCS file: /home/markmc/gnome-devel/local-repository/gconf/gconf/gconf-database.c,v
retrieving revision 1.33
diff -u -p -r1.33 gconf-database.c
--- gconf/gconf-database.c	24 Mar 2004 20:03:10 -0000	1.33
+++ gconf/gconf-database.c	25 Mar 2004 15:03:23 -0000
@@ -1027,6 +1027,60 @@ gconf_database_schedule_sync(GConfDataba
     }
 }
 
+static void
+source_notify_cb (GConfSource   *source,
+		  const gchar   *location,
+		  GConfDatabase *db)
+{
+  GConfValue  *value;
+  ConfigValue *cvalue;
+  GError      *error;
+  gchar       *schema_name;
+  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;
+  schema_name = 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,
+				      &schema_name,
+				      &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,
+				   location,
+				   cvalue,
+				   is_default,
+				   is_writable);
+
+  CORBA_free (cvalue);
+  gconf_value_free (value);
+}
+
 CORBA_unsigned_long
 gconf_database_readd_listener   (GConfDatabase       *db,
                                  ConfigListener       who,
@@ -1047,6 +1101,12 @@ gconf_database_readd_listener   (GConfDa
   cnxn = gconf_listeners_add (db->listeners, where, l,
                               (GFreeFunc)listener_destroy);
 
+  gconf_sources_add_listener (db->sources,
+			      cnxn,
+			      where,
+			      (GConfSourceNotifyFunc) source_notify_cb,
+			      db);
+
   if (l->name == NULL)
     l->name = g_strdup_printf ("%u", cnxn);
   
@@ -1130,6 +1190,8 @@ gconf_database_remove_listener (GConfDat
       g_error_free (err);
     }
   
+  gconf_sources_remove_listener (db->sources, cnxn);
+
   /* calls destroy notify */
   gconf_listeners_remove (db->listeners, cnxn);
 }
Index: gconf/gconf-sources.c
===================================================================
RCS file: /home/markmc/gnome-devel/local-repository/gconf/gconf/gconf-sources.c,v
retrieving revision 1.44
diff -u -p -r1.44 gconf-sources.c
--- gconf/gconf-sources.c	24 Mar 2004 20:03:10 -0000	1.44
+++ gconf/gconf-sources.c	25 Mar 2004 14:33:48 -0000
@@ -288,6 +288,39 @@ gconf_source_sync_all         (GConfSour
   return (*source->backend->vtable.sync_all)(source, err);
 }
 
+static void
+gconf_source_add_listener (GConfSource           *source,
+			   guint                  id,
+			   const gchar           *namespace_section,
+			   GConfSourceNotifyFunc  notify_func,
+			   gpointer               user_data)
+{
+  g_return_if_fail (source != NULL);
+  g_return_if_fail (id > 0);
+
+  if (source->backend->vtable.add_listener)
+    {
+      (*source->backend->vtable.add_listener) (source,
+					       id,
+					       namespace_section,
+					       notify_func,
+					       user_data);
+    }
+}
+
+static void
+gconf_source_remove_listener (GConfSource *source,
+			      guint        id)
+{
+  g_return_if_fail (source != NULL);
+  g_return_if_fail (id > 0);
+
+  if (source->backend->vtable.remove_listener)
+    {
+      (*source->backend->vtable.remove_listener) (source, id);
+    }
+}
+
 /*
  *   Source stacks
  */
@@ -1548,5 +1581,49 @@ gconf_sources_query_default_value(GConfS
       gconf_meta_info_free(mi);
       
       return NULL;
+    }
+}
+
+void
+gconf_sources_add_listener (GConfSources          *sources,
+			    guint                  id,
+			    const gchar           *namespace_section,
+			    GConfSourceNotifyFunc  notify_func,
+			    gpointer               user_data)
+{
+  GList *tmp;
+
+  tmp = sources->sources;
+
+  while (sources != NULL)
+    {
+      GConfSource *source = tmp->data;
+
+      gconf_source_add_listener (source,
+				 id,
+				 namespace_section,
+				 notify_func,
+				 user_data);
+
+
+      tmp = tmp->next;
+    }
+}
+
+void
+gconf_sources_remove_listener (GConfSources *sources,
+			       guint         id)
+{
+  GList *tmp;
+
+  tmp = sources->sources;
+
+  while (sources != NULL)
+    {
+      GConfSource *source = tmp->data;
+
+      gconf_source_remove_listener (source, id);
+
+      tmp = tmp->next;
     }
 }
Index: gconf/gconf-sources.h
===================================================================
RCS file: /home/markmc/gnome-devel/local-repository/gconf/gconf/gconf-sources.h,v
retrieving revision 1.21
diff -u -p -r1.21 gconf-sources.h
--- gconf/gconf-sources.h	18 Jun 2003 10:39:40 -0000	1.21
+++ gconf/gconf-sources.h	25 Mar 2004 14:28:07 -0000
@@ -24,6 +24,7 @@
 #include <glib.h>
 #include "gconf-error.h"
 #include "gconf-value.h"
+#include "gconf-listeners.h"
 
 /* Sources are not interchangeable; different backend engines will return 
  * GConfSource with different private elements.
@@ -50,6 +51,10 @@ typedef enum {
   GCONF_SOURCE_ALL_FLAGS = ((1 << 0) | (1 << 1))
 } GConfSourceFlags;
 
+typedef void (* GConfSourceNotifyFunc) (GConfSource *source,
+					const gchar *location,
+					gpointer     user_data);
+
 GConfSource*  gconf_resolve_address         (const gchar* address,
                                              GError** err);
 
@@ -124,11 +129,12 @@ GConfValue*   gconf_sources_query_defaul
                                                 gboolean* is_writable,
                                                 GError** err);
 
-#endif
-
-
-
-
-
-
+void          gconf_sources_add_listener       (GConfSources          *sources,
+						guint                  id,
+					        const gchar           *location,
+					        GConfSourceNotifyFunc  notify_func,
+					        gpointer               user_data);
+void          gconf_sources_remove_listener    (GConfSources          *sources,
+						guint                  id);
 
+#endif





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