supporting notifications from backends
- From: Mark McLoughlin <mark skynet ie>
- To: Cyrille Moureaux <Cyrille Moureaux Sun COM>
- Cc: gconf-list gnome org
- Subject: supporting notifications from backends
- Date: Thu, 25 Mar 2004 17:54:35 +0000
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]