[dconf] factor-out common client-side code
- From: Ryan Lortie <ryanl src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [dconf] factor-out common client-side code
- Date: Fri, 21 May 2010 16:18:45 +0000 (UTC)
commit 86bff9e98374d13d74dd59316f8bc8575a7671e1
Author: Ryan Lortie <desrt desrt ca>
Date: Fri May 21 12:18:10 2010 -0400
factor-out common client-side code
Preparing for creating standalone client-side library.
client/dconf-client.c | 172 +++++++++++++
client/dconf-client.h | 74 ++++++
configure.ac | 2 +-
gsettings/Makefile.am | 6 +-
gsettings/dconfdatabase.c | 489 --------------------------------------
gsettings/dconfdatabase.h | 55 -----
gsettings/dconfsettingsbackend.c | 353 ++++++++++++++++++++++++++--
service/service.c | 2 +-
8 files changed, 583 insertions(+), 570 deletions(-)
---
diff --git a/client/dconf-client.c b/client/dconf-client.c
new file mode 100644
index 0000000..d1a959c
--- /dev/null
+++ b/client/dconf-client.c
@@ -0,0 +1,172 @@
+
+#include "dconf-client.h"
+#include <gvdb/gvdb-reader.h>
+
+struct _DConfClient
+{
+ gint ref_count;
+};
+
+DConfClient *
+dconf_client_new (DConfClientServiceFunc service_func)
+{
+ DConfClient *client;
+
+ client = g_slice_new (DConfClient);
+ client->ref_count = 1;
+
+ return client;
+}
+
+DConfClient *
+dconf_client_ref (DConfClient *client)
+{
+ g_atomic_int_inc (&client->ref_count);
+
+ return client;
+}
+
+void
+dconf_client_unref (DConfClient *client)
+{
+ if (g_atomic_int_dec_and_test (&client->ref_count))
+ g_slice_free (DConfClient, client);
+}
+
+GVariant *
+dconf_client_read (DConfClient *client,
+ const gchar *key,
+ const GVariantType *required_type,
+ DConfClientReadType type)
+{
+ GvdbTable *table;
+ GVariant *value;
+ gchar *filename;
+
+ if (type == DCONF_CLIENT_READ_RESET)
+ return NULL;
+
+ filename = g_build_filename (g_get_user_config_dir (), "dconf", NULL);
+ table = gvdb_table_new (filename, FALSE, NULL);
+ g_free (filename);
+
+ value = gvdb_table_get_value (table, key, NULL);
+
+ gvdb_table_unref (table);
+
+ return value;
+}
+
+static void
+dconf_client_make_match_rule (DConfClient *client,
+ DConfClientMessage *dccm,
+ const gchar *name)
+{
+ gchar *rule;
+
+ rule = g_strdup_printf ("interface='ca.desrt.dconf.Writer',"
+ "arg1path='%s'", name);
+ dccm->bus_type = 'e';
+ dccm->destination = "org.freedesktop.DBus";
+ dccm->object_path = "/";
+ dccm->interface = "org.freedesktop.DBus";
+ dccm->body = g_variant_ref_sink (g_variant_new ("(s)", rule));
+ g_free (rule);
+}
+
+void
+dconf_client_watch (DConfClient *client,
+ DConfClientMessage *dccm,
+ const gchar *name)
+{
+ dconf_client_make_match_rule (client, dccm, name);
+ dccm->method = "AddMatch";
+}
+
+void
+dconf_client_unwatch (DConfClient *client,
+ DConfClientMessage *dccm,
+ const gchar *name)
+{
+ dconf_client_make_match_rule (client, dccm, name);
+ dccm->method = "RemoveMatch";
+}
+
+gboolean
+dconf_client_is_writable (DConfClient *client,
+ DConfClientMessage *dccm,
+ const gchar *name)
+{
+ dccm->bus_type = 'e';
+ dccm->body = NULL;
+
+ return TRUE;
+}
+
+static GVariant *
+fake_maybe (GVariant *value)
+{
+ GVariantBuilder builder;
+
+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("av"));
+
+ if (value != NULL)
+ g_variant_builder_add (&builder, "v", value);
+
+ return g_variant_builder_end (&builder);
+}
+
+static void
+dconf_client_dccm (DConfClient *client,
+ DConfClientMessage *dccm,
+ const gchar *method,
+ const gchar *format_string,
+ ...)
+{
+ va_list ap;
+
+ dccm->bus_type = 'e';
+ dccm->destination = "ca.desrt.dconf";
+ dccm->object_path = "/";
+ dccm->interface = "ca.desrt.dconf.Writer";
+ dccm->method = method;
+
+ va_start (ap, format_string);
+ dccm->body = g_variant_ref_sink (g_variant_new_va (format_string,
+ NULL, &ap));
+ va_end (ap);
+}
+
+gboolean
+dconf_client_write (DConfClient *client,
+ DConfClientMessage *dccm,
+ const gchar *name,
+ GVariant *value)
+{
+ dconf_client_dccm (client, dccm,
+ "Write", "(s av)",
+ name, fake_maybe (value));
+
+ return TRUE;
+}
+
+gboolean
+dconf_client_write_many (DConfClient *client,
+ DConfClientMessage *dccm,
+ const gchar *prefix,
+ const gchar * const *keys,
+ GVariant **values)
+{
+ GVariantBuilder builder;
+ gsize i;
+
+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(sav)"));
+
+ for (i = 0; keys[i]; i++)
+ g_variant_builder_add (&builder, "(s av)",
+ keys[i], fake_maybe (values[i]));
+
+ dconf_client_dccm (client, dccm, "Merge", "(sa(sav))", prefix, &builder);
+
+ return TRUE;
+}
diff --git a/client/dconf-client.h b/client/dconf-client.h
new file mode 100644
index 0000000..b6ae36a
--- /dev/null
+++ b/client/dconf-client.h
@@ -0,0 +1,74 @@
+#ifndef _dconf_client_h_
+#define _dconf_client_h_
+
+#include <glib.h>
+
+typedef struct _DConfClient DConfClient;
+typedef struct _DConfClientResetList DConfClientResetList;
+
+typedef enum
+{
+ DCONF_CLIENT_READ_NORMAL,
+ DCONF_CLIENT_READ_SET,
+ DCONF_CLIENT_READ_RESET
+} DConfClientReadType;
+
+typedef struct
+{
+ gint bus_type;
+ const gchar *destination;
+ const gchar *object_path;
+ const gchar *interface;
+ const gchar *method;
+ GVariant *body;
+} DConfClientMessage;
+
+
+
+typedef GVariant * (*DConfClientServiceFunc) (DConfClient *client,
+ DConfClientMessage *message);
+
+DConfClient * dconf_client_new (DConfClientServiceFunc service_func);
+void dconf_client_unref (DConfClient *client);
+DConfClient * dconf_client_ref (DConfClient *client);
+
+GVariant * dconf_client_read (DConfClient *client,
+ const gchar *key,
+ const GVariantType *required_type,
+ DConfClientReadType type);
+gchar ** dconf_client_list (DConfClient *client,
+ const gchar *path,
+ DConfClientResetList *resets);
+
+void dconf_client_get_service_info (DConfClient *client,
+ const gchar **bus_type,
+ const gchar **destination,
+ const gchar **object_path);
+gboolean dconf_client_is_writable (DConfClient *client,
+ DConfClientMessage *message,
+ const gchar *name);
+gboolean dconf_client_write (DConfClient *client,
+ DConfClientMessage *message,
+ const gchar *key,
+ GVariant *value);
+gboolean dconf_client_write_tree (DConfClient *client,
+ DConfClientMessage *message,
+ GTree *tree);
+void dconf_client_watch (DConfClient *client,
+ DConfClientMessage *message,
+ const gchar *name);
+void dconf_client_unwatch (DConfClient *client,
+ DConfClientMessage *message,
+ const gchar *name);
+void dconf_client_decode_notify (DConfClient *client,
+ const gchar **prefix,
+ const gchar ***keys,
+ GVariant *body);
+
+void dconf_client_reset_list_init (DConfClientResetList *resets,
+ const gchar * const *list);
+void dconf_client_reset_list_add (DConfClientResetList *resets,
+ const gchar *item);
+void dconf_client_reset_list_clear (DConfClientResetList *resets);
+
+#endif /* _dconf_client_h_ */
diff --git a/configure.ac b/configure.ac
index a928b5e..3307de3 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,4 +1,4 @@
-AC_INIT(dconf, 0.3)
+AC_INIT(dconf, 0.3.1)
AM_INIT_AUTOMAKE
AM_SILENT_RULES
AC_PROG_LIBTOOL
diff --git a/gsettings/Makefile.am b/gsettings/Makefile.am
index 00795cb..c19a92f 100644
--- a/gsettings/Makefile.am
+++ b/gsettings/Makefile.am
@@ -1,13 +1,13 @@
-AM_CFLAGS = $(gio_CFLAGS) -I$(top_srcdir)/gvdb
+AM_CFLAGS = $(gio_CFLAGS) -I$(top_srcdir)
giomodules_LTLIBRARIES = libdconfsettings.la
libdconfsettings_la_LIBADD = $(gio_LIBS)
libdconfsettings_la_LDFLAGS = -module -avoid-version -shared
libdconfsettings_la_SOURCES = \
+ ../client/dconf-client.h\
+ ../client/dconf-client.c\
../gvdb/gvdb-reader.c \
- dconfdatabase.h \
- dconfdatabase.c \
dconfsettingsbackend.c
install-data-hook:
diff --git a/gsettings/dconfsettingsbackend.c b/gsettings/dconfsettingsbackend.c
index d5ef40d..0c49865 100644
--- a/gsettings/dconfsettingsbackend.c
+++ b/gsettings/dconfsettingsbackend.c
@@ -21,23 +21,226 @@
#define G_SETTINGS_ENABLE_BACKEND
#include <gio/gsettingsbackend.h>
+#include <client/dconf-client.h>
#include <gio/gio.h>
-#include "dconfdatabase.h"
+#include <string.h>
typedef GSettingsBackendClass DConfSettingsBackendClass;
+typedef struct _Outstanding Outstanding;
typedef struct
{
GSettingsBackend backend;
+ GStaticMutex lock;
- DConfDatabase *database;
+ DConfClient *client;
+
+ Outstanding *outstanding;
+ GDBusConnection *bus;
+ guint64 anti_expose;
} DConfSettingsBackend;
G_DEFINE_TYPE (DConfSettingsBackend,
dconf_settings_backend,
G_TYPE_SETTINGS_BACKEND)
+
+struct _Outstanding
+{
+ Outstanding *next;
+
+ volatile guint32 serial;
+
+ gchar *reset_path, *set_key;
+ GVariant *set_value;
+
+ GTree *tree;
+};
+
+static volatile guint32 *
+dconf_settings_backend_new_outstanding (DConfSettingsBackend *dcsb,
+ const gchar *set_key,
+ GVariant *set_value,
+ GTree *tree)
+{
+ Outstanding *outstanding;
+
+ outstanding = g_slice_new (Outstanding);
+ outstanding->reset_path = NULL;
+ outstanding->set_key = NULL;
+
+ if (!set_key || g_str_has_suffix (set_key, "/"))
+ {
+ g_assert (set_value == NULL);
+ outstanding->reset_path = g_strdup (set_key);
+ }
+ else
+ outstanding->set_key = g_strdup (set_key);
+
+ outstanding->serial = 0;
+
+ if (set_value)
+ outstanding->set_value = g_variant_ref_sink (set_value);
+ else
+ outstanding->set_value = NULL;
+
+ if (tree)
+ outstanding->tree = g_tree_ref (tree);
+ else
+ outstanding->tree = NULL;
+
+ g_static_mutex_lock (&dcsb->lock);
+ outstanding->next = dcsb->outstanding;
+ dcsb->outstanding = outstanding;
+ g_static_mutex_unlock (&dcsb->lock);
+
+ return &outstanding->serial;
+}
+
+static gboolean
+dconf_settings_backend_remove_outstanding (DConfSettingsBackend *dcsb,
+ GDBusMessage *message,
+ guint64 *anti_expose)
+{
+ gboolean found = FALSE;
+ Outstanding **node;
+ guint32 serial;
+
+ if G_LIKELY (dcsb->outstanding == NULL)
+ return FALSE;
+
+ serial = g_dbus_message_get_reply_serial (message);
+
+ if (serial == 0)
+ return FALSE;
+
+ g_static_mutex_lock (&dcsb->lock);
+
+ /* this could be made more asymptotically efficient by using a queue
+ * or a double-linked list with a 'tail' pointer but the usual case
+ * here will be one outstanding item and very rarely more than a few.
+ *
+ * so we scan...
+ */
+ for (node = &dcsb->outstanding; *node; node = &(*node)->next)
+ if ((*node)->serial == serial)
+ {
+ Outstanding *tmp;
+
+ tmp = *node;
+ *node = tmp->next;
+
+ g_static_mutex_unlock (&dcsb->lock);
+
+ g_variant_get (g_dbus_message_get_body (message), "(t)", anti_expose);
+
+ g_free (tmp->reset_path);
+ g_free (tmp->set_key);
+
+ if (tmp->set_value)
+ g_variant_unref (tmp->set_value);
+
+ if (tmp->tree)
+ g_tree_unref (tmp->tree);
+
+ found = TRUE;
+ break;
+ }
+
+ g_static_mutex_unlock (&dcsb->lock);
+
+ return found;
+}
+
+static gboolean
+dconf_settings_backend_scan_outstanding_tree (GTree *tree,
+ const gchar *key,
+ gsize key_length,
+ gpointer *value)
+{
+ gchar *mykey;
+
+ mykey = g_alloca (key_length + 1);
+ memcpy (mykey, key, key_length + 1);
+
+ while (!g_tree_lookup_extended (tree, mykey, NULL, value) &&
+ --key_length)
+ {
+ while (mykey[key_length - 1] != '/')
+ key_length--;
+
+ mykey[key_length] = '\0';
+ }
+
+ return key_length != 0;
+}
+
+static gboolean
+dconf_settings_backend_scan_outstanding (DConfSettingsBackend *backend,
+ const gchar *key,
+ GVariant **value)
+{
+ gboolean found = FALSE;
+ Outstanding *node;
+ gsize length;
+
+ length = strlen (key);
+
+ if G_LIKELY (backend->outstanding == NULL)
+ return FALSE;
+
+ g_static_mutex_lock (&backend->lock);
+
+ for (node = backend->outstanding; node; node = node->next)
+ {
+ if (node->reset_path)
+ {
+ if (g_str_has_prefix (key, node->reset_path))
+ {
+ *value = NULL;
+ found = TRUE;
+ break;
+ }
+ }
+
+ else if (node->set_key)
+ {
+ if (strcmp (key, node->set_key) == 0)
+ {
+ if (node->set_value != NULL)
+ *value = g_variant_ref (node->set_value);
+ else
+ *value = NULL;
+
+ found = TRUE;
+ break;
+ }
+ }
+
+ else
+ {
+ gpointer result;
+
+ if (dconf_settings_backend_scan_outstanding_tree (node->tree, key,
+ length, &result))
+ {
+ if (result)
+ *value = g_variant_ref (result);
+ else
+ *value = NULL;
+
+ found = TRUE;
+ break;
+ }
+ }
+ }
+
+ g_static_mutex_unlock (&backend->lock);
+
+ return found;
+}
+
static GVariant *
dconf_settings_backend_read (GSettingsBackend *backend,
const gchar *key,
@@ -45,21 +248,68 @@ dconf_settings_backend_read (GSettingsBackend *backend,
gboolean default_value)
{
DConfSettingsBackend *dcsb = (DConfSettingsBackend *) backend;
+ DConfClientReadType type;
+
+ if (!default_value)
+ {
+ GVariant *value;
- if (default_value)
- return NULL;
+ if (dconf_settings_backend_scan_outstanding (dcsb, key, &value))
+ return value;
- return dconf_database_read (dcsb->database, key);
+ type = DCONF_CLIENT_READ_NORMAL;
+ }
+ else
+ type = DCONF_CLIENT_READ_RESET;
+
+ return dconf_client_read (dcsb->client, key, expected_type, type);
}
-static gchar **
-dconf_settings_backend_list (GSettingsBackend *backend,
- const gchar *path,
- gsize *length)
+static void
+dconf_settings_backend_send (GDBusConnection *bus,
+ DConfClientMessage *dccm,
+ volatile guint32 *serial)
{
- DConfSettingsBackend *dcsb = (DConfSettingsBackend *) backend;
+ GDBusMessage *message;
+
+ message = g_dbus_message_new_method_call (dccm->destination,
+ dccm->object_path,
+ dccm->interface,
+ dccm->method);
+ g_dbus_message_set_body (message, dccm->body);
+
+ if (serial)
+ g_dbus_connection_send_message (bus, message, serial, NULL);
+ else
+ g_dbus_connection_send_message_with_reply_sync (bus, message, -1,
+ NULL, NULL, NULL);
+
+ g_variant_unref (dccm->body);
+ g_object_unref (message);
+}
+
+static gboolean
+dconf_settings_backend_get_bus (GDBusConnection **bus,
+ DConfClientMessage *dccm)
+{
+ switch (dccm->bus_type)
+ {
+ case 'e':
+ *bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
+ break;
+
+ case 'y':
+ *bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL);
+ break;
- return dconf_database_list (dcsb->database, path, length);
+ default:
+ g_assert_not_reached ();
+ }
+
+ if (*bus == NULL && dccm->body)
+ g_variant_unref (dccm->body);
+
+ return *bus != NULL;
}
static gboolean
@@ -69,8 +319,27 @@ dconf_settings_backend_write (GSettingsBackend *backend,
gpointer origin_tag)
{
DConfSettingsBackend *dcsb = (DConfSettingsBackend *) backend;
+ DConfClientMessage message;
+ volatile guint32 *serial;
+ GDBusConnection *bus;
+
+ if (!dconf_client_write (dcsb->client, &message, path_or_key, value))
+ return FALSE;
- dconf_database_write (dcsb->database, path_or_key, value, origin_tag);
+ if (!dconf_settings_backend_get_bus (&bus, &message))
+ return FALSE;
+
+ serial = dconf_settings_backend_new_outstanding (dcsb,
+ path_or_key,
+ value,
+ NULL);
+
+ dconf_settings_backend_send (bus, &message, serial);
+
+ if (g_str_has_suffix (path_or_key, "/"))
+ g_settings_backend_changed_path (backend, path_or_key, origin_tag);
+ else
+ g_settings_backend_changed (backend, path_or_key, origin_tag);
return TRUE;
}
@@ -81,10 +350,35 @@ dconf_settings_backend_write_tree (GSettingsBackend *backend,
gpointer origin_tag)
{
DConfSettingsBackend *dcsb = (DConfSettingsBackend *) backend;
+ DConfClientMessage message;
+ volatile guint32 *serial;
+ GDBusConnection *bus;
+ const gchar **keys;
+ GVariant **values;
+ gchar *prefix;
- dconf_database_write_tree (dcsb->database, tree, origin_tag);
+ g_settings_backend_flatten_tree (tree, &prefix, &keys, &values);
- return TRUE;
+ if (dconf_client_write_many (dcsb->client, &message, prefix, keys, values))
+ {
+ if (dconf_settings_backend_get_bus (&bus, &message))
+ {
+ serial = dconf_settings_backend_new_outstanding (dcsb, NULL,
+ NULL, tree);
+
+ dconf_settings_backend_send (bus, &message, serial);
+
+ g_settings_backend_keys_changed (backend, prefix, keys, origin_tag);
+
+ return TRUE;
+ }
+ }
+
+ g_free (prefix);
+ g_free (values);
+ g_free (keys);
+
+ return FALSE;
}
static void
@@ -92,14 +386,21 @@ dconf_settings_backend_reset (GSettingsBackend *backend,
const gchar *path_or_key,
gpointer origin_tag)
{
- dconf_settings_backend_write (backend, path_or_key, NULL, origin_tag);
+ g_assert_not_reached ();
}
static gboolean
dconf_settings_backend_get_writable (GSettingsBackend *backend,
- const gchar *key)
+ const gchar *name)
{
- return TRUE;
+ DConfSettingsBackend *dcsb = (DConfSettingsBackend *) backend;
+ DConfClientMessage message;
+ GDBusConnection *bus;
+
+ if (!dconf_client_is_writable (dcsb->client, &message, name))
+ return FALSE;
+
+ return dconf_settings_backend_get_bus (&bus, &message);
}
static void
@@ -107,8 +408,13 @@ dconf_settings_backend_subscribe (GSettingsBackend *backend,
const gchar *name)
{
DConfSettingsBackend *dcsb = (DConfSettingsBackend *) backend;
+ DConfClientMessage message;
+ GDBusConnection *bus;
- dconf_database_subscribe (dcsb->database, name);
+ dconf_client_watch (dcsb->client, &message, name);
+
+ if (dconf_settings_backend_get_bus (&bus, &message))
+ dconf_settings_backend_send (bus, &message, NULL);
}
static void
@@ -116,8 +422,13 @@ dconf_settings_backend_unsubscribe (GSettingsBackend *backend,
const gchar *name)
{
DConfSettingsBackend *dcsb = (DConfSettingsBackend *) backend;
+ DConfClientMessage message;
+ GDBusConnection *bus;
+
+ dconf_client_unwatch (dcsb->client, &message, name);
- dconf_database_unsubscribe (dcsb->database, name);
+ if (dconf_settings_backend_get_bus (&bus, &message))
+ dconf_settings_backend_send (bus, &message, NULL);
}
static void
@@ -128,14 +439,14 @@ dconf_settings_backend_sync (GSettingsBackend *backend)
static void
dconf_settings_backend_init (DConfSettingsBackend *dcsb)
{
- dcsb->database = dconf_database_get_for_backend (dcsb);
+ dcsb->client = dconf_client_new (NULL);
}
static void
dconf_settings_backend_class_init (GSettingsBackendClass *class)
{
class->read = dconf_settings_backend_read;
- class->list = dconf_settings_backend_list;
+ // class->list = dconf_settings_backend_list;
class->write = dconf_settings_backend_write;
class->write_keys = dconf_settings_backend_write_tree;
class->reset = dconf_settings_backend_reset;
diff --git a/service/service.c b/service/service.c
index 05bc697..aa01705 100644
--- a/service/service.c
+++ b/service/service.c
@@ -204,7 +204,7 @@ method_call (GDBusConnection *connection,
serial, key, none),
NULL);
}
- else if (strcmp (method_name, "Merge"))
+ else if (strcmp (method_name, "Merge") == 0)
{
GError *error = NULL;
const gchar *prefix;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]