summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRyan Lortie <desrt@desrt.ca>2012-07-11 12:38:11 -0400
committerRyan Lortie <desrt@desrt.ca>2012-07-11 12:39:56 -0400
commit2108640d5a5188873cee73d0c776ab4b4def855d (patch)
tree56575d62021397d51d6b95c58de26b68395a2483
parentd25575211d27852df6fd2fbe5eaa9ed985fafbf0 (diff)
downloaddconf-2108640d5a5188873cee73d0c776ab4b4def855d.tar.gz
dbus-1/: rewrite against the new engine
Delete the copy of the old engine code that was kept in dbus-1/. Split the parts that interact with libdbus-1 into a separate file called dconf-libdbus-1.c and create a static library for it (to facilitate testing). Adjust the remaining code (which is now the user-facing DConfDBusClient API) to the new engine.
-rw-r--r--dbus-1/.gitignore2
-rw-r--r--dbus-1/Makefile.am29
-rw-r--r--dbus-1/dconf-dbus-1.c632
-rw-r--r--dbus-1/dconf-engine.c769
-rw-r--r--dbus-1/dconf-engine.h144
-rw-r--r--dbus-1/dconf-libdbus-1.c352
-rw-r--r--dbus-1/dconf-libdbus-1.h11
7 files changed, 434 insertions, 1505 deletions
diff --git a/dbus-1/.gitignore b/dbus-1/.gitignore
index 32072d0..36fad9e 100644
--- a/dbus-1/.gitignore
+++ b/dbus-1/.gitignore
@@ -1,3 +1,5 @@
+libdconf-libdbus-1.a
+libdconf-libdbus-1-shared.a
libdconf-dbus-1.so
libdconf-dbus-1.so.0
libdconf-dbus-1.so.0.0.0
diff --git a/dbus-1/Makefile.am b/dbus-1/Makefile.am
index 74ec56d..7444c17 100644
--- a/dbus-1/Makefile.am
+++ b/dbus-1/Makefile.am
@@ -1,7 +1,14 @@
include $(top_srcdir)/Makefile.gtester
-AM_CFLAGS = -std=c89 -Wall -Wmissing-prototypes -Wwrite-strings -fPIC -DPIC
-INCLUDES = -I$(top_srcdir)/common -I$(top_srcdir)/gvdb -I$(top_srcdir)/engine $(dbus_CFLAGS) $(glib_CFLAGS)
+noinst_LIBRARIES = libdconf-libdbus-1.a libdconf-libdbus-1-shared.a
+
+libdconf_libdbus_1_a_CFLAGS = $(dbus_CFLAGS) $(glib_CFLAGS)
+libdconf_libdbus_1_a_SOURCES = \
+ dconf-libdbus-1.h \
+ dconf-libdbus-1.c
+
+libdconf_libdbus_1_shared_a_CFLAGS = $(libdconf_libdbus_1_a_CFLAGS) -fPIC -DPIC
+libdconf_libdbus_1_shared_a_SOURCES = $(libdconf_libdbus_1_a_SOURCES)
dconf_dbus_1includedir = $(includedir)/dconf-dbus-1
dconf_dbus_1include_HEADERS = dconf-dbus-1.h
@@ -12,15 +19,19 @@ pkgconfig_DATA = dconf-dbus-1.pc
shlibdir = $(libdir)
shlib_PROGRAMS = libdconf-dbus-1.so.0.0.0
-libdconf_dbus_1_so_0_0_0_LDADD = $(glib_LIBS) $(dbus_LIBS) ../common/libdconf-common-shared.a
+libdconf_dbus_1_so_0_0_0_CFLAGS = $(dbus_CFLAGS) $(gio_CFLAGS) -fPIC -DPIC
+libdconf_dbus_1_so_0_0_0_LDADD = \
+ ../engine/libdconf-engine-shared.a \
+ ../common/libdconf-common-hidden.a \
+ ./libdconf-libdbus-1-shared.a \
+ ../gvdb/libgvdb-shared.a \
+ ../shm/libdconf-shm-shared.a \
+ $(dbus_LIBS) \
+ $(glib_LIBS)
libdconf_dbus_1_so_0_0_0_LDFLAGS = -shared -Wl,-soname=libdconf-dbus-1.so.0
-libdconf_dbus_1_so_0_0_0_SOURCES = \
- dconf-engine.h \
- dconf-engine.c \
- ../gvdb/gvdb-reader.c \
- dconf-dbus-1.c
+libdconf_dbus_1_so_0_0_0_SOURCES = dconf-dbus-1.c
-noinst_DATA = libdconf-dbus-1.so libdconf-dbus-1.so.0
+nodist_noinst_DATA = libdconf-dbus-1.so libdconf-dbus-1.so.0
libdconf-dbus-1.so.0 libdconf-dbus-1.so: libdconf-dbus-1.so.0.0.0
$(AM_V_GEN) ln -fs libdconf-dbus-1.so.0.0.0 $@
diff --git a/dbus-1/dconf-dbus-1.c b/dbus-1/dconf-dbus-1.c
index 50dc0f8..bc3aec6 100644
--- a/dbus-1/dconf-dbus-1.c
+++ b/dbus-1/dconf-dbus-1.c
@@ -19,465 +19,61 @@
#include "dconf-dbus-1.h"
-#include <dconf-engine.h>
+#include "../engine/dconf-engine.h"
#include <string.h>
-typedef struct _Outstanding Outstanding;
-
struct _DConfDBusClient
{
- DBusConnection *session_bus;
- DBusConnection *system_bus;
+ DConfEngine *engine;
GSList *watches;
gint ref_count;
-
- Outstanding *outstanding;
- gchar *anti_expose_tag;
-
- DConfEngine *engine;
-};
-
-static void
-dconf_dbus_client_add_value_to_iter (DBusMessageIter *iter,
- GVariant *value)
-{
- GVariantClass class;
-
- class = g_variant_classify (value);
-
- switch (class)
- {
- case G_VARIANT_CLASS_BOOLEAN:
- {
- dbus_bool_t boolean;
-
- boolean = g_variant_get_boolean (value);
- dbus_message_iter_append_basic (iter, 'b', &boolean);
- }
- break;
-
- case G_VARIANT_CLASS_BYTE:
- case G_VARIANT_CLASS_INT16:
- case G_VARIANT_CLASS_UINT16:
- case G_VARIANT_CLASS_INT32:
- case G_VARIANT_CLASS_UINT32:
- case G_VARIANT_CLASS_INT64:
- case G_VARIANT_CLASS_UINT64:
- case G_VARIANT_CLASS_DOUBLE:
- dbus_message_iter_append_basic (iter, class,
- g_variant_get_data (value));
- break;
-
- case G_VARIANT_CLASS_STRING:
- case G_VARIANT_CLASS_OBJECT_PATH:
- case G_VARIANT_CLASS_SIGNATURE:
- {
- const gchar *str;
-
- str = g_variant_get_string (value, NULL);
- dbus_message_iter_append_basic (iter, class, &str);
- }
- break;
-
- case G_VARIANT_CLASS_ARRAY:
- {
- const gchar *contained;
- DBusMessageIter sub;
- gint i, n;
-
- contained = g_variant_get_type_string (value) + 1;
- n = g_variant_n_children (value);
- dbus_message_iter_open_container (iter, 'a', contained, &sub);
- for (i = 0; i < n; i++)
- {
- GVariant *child;
-
- child = g_variant_get_child_value (value, i);
- dconf_dbus_client_add_value_to_iter (&sub, child);
- g_variant_unref (child);
- }
-
- dbus_message_iter_close_container (iter, &sub);
- }
- break;
-
- case G_VARIANT_CLASS_TUPLE:
- {
- DBusMessageIter sub;
- gint i, n;
-
- n = g_variant_n_children (value);
- dbus_message_iter_open_container (iter, 'r', NULL, &sub);
- for (i = 0; i < n; i++)
- {
- GVariant *child;
-
- child = g_variant_get_child_value (value, i);
- dconf_dbus_client_add_value_to_iter (&sub, child);
- g_variant_unref (child);
- }
-
- dbus_message_iter_close_container (iter, &sub);
- }
- break;
-
- case G_VARIANT_CLASS_DICT_ENTRY:
- {
- DBusMessageIter sub;
- gint i;
-
- dbus_message_iter_open_container (iter, 'e', NULL, &sub);
- for (i = 0; i < 2; i++)
- {
- GVariant *child;
-
- child = g_variant_get_child_value (value, i);
- dconf_dbus_client_add_value_to_iter (&sub, child);
- g_variant_unref (child);
- }
-
- dbus_message_iter_close_container (iter, &sub);
- }
- break;
-
- case G_VARIANT_CLASS_VARIANT:
- {
- DBusMessageIter sub;
- GVariant *child;
-
- child = g_variant_get_variant (value);
- dbus_message_iter_open_container (iter, 'v',
- g_variant_get_type_string (child),
- &sub);
- dconf_dbus_client_add_value_to_iter (&sub, child);
- dbus_message_iter_close_container (iter, &sub);
- g_variant_unref (child);
- }
- break;
-
- default:
- g_assert_not_reached ();
- }
-}
-
-static void
-dconf_dbus_client_send (DConfDBusClient *dcdbc,
- DConfEngineMessage *dcem,
- DBusPendingCallNotifyFunction callback,
- gpointer user_data)
-{
- DBusConnection *connection;
- gint i;
-
- for (i = 0; i < dcem->n_messages; i++)
- {
- switch (dcem->bus_types[i])
- {
- case 'e':
- connection = dcdbc->session_bus;
- break;
-
- case 'y':
- connection = dcdbc->system_bus;
- break;
-
- default:
- g_assert_not_reached ();
- }
-
- if (connection == NULL && callback != NULL)
- callback (NULL, user_data);
-
- if (connection != NULL)
- {
- DBusPendingCall *pending;
- DBusMessageIter diter;
- DBusMessage *message;
- GVariantIter giter;
- GVariant *child;
-
- message = dbus_message_new_method_call (dcem->bus_name,
- dcem->object_path,
- dcem->interface_name,
- dcem->method_name);
-
- dbus_message_iter_init_append (message, &diter);
- g_variant_iter_init (&giter, dcem->parameters[i]);
-
- while ((child = g_variant_iter_next_value (&giter)))
- {
- dconf_dbus_client_add_value_to_iter (&diter, child);
- g_variant_unref (child);
- }
-
- dbus_connection_send_with_reply (connection, message,
- &pending, 120000);
- dbus_pending_call_set_notify (pending, callback, user_data, NULL);
- dbus_message_unref (message);
- }
- }
-}
-
-static GVariant *
-dconf_dbus_client_send_finish (DBusPendingCall *pending)
-{
- DBusMessage *message;
- GVariant *result;
-
- if (pending == NULL)
- return NULL;
-
- message = dbus_pending_call_steal_reply (pending);
- dbus_pending_call_unref (pending);
-
- /* We only have to deal with two types of replies: () and (s) */
- if (dbus_message_has_signature (message, "s"))
- {
- dbus_message_get_args (message, NULL,
- DBUS_TYPE_STRING, &result,
- DBUS_TYPE_INVALID);
- result = g_variant_new ("(s)", result);
- }
- else
- result = g_variant_new ("()");
-
- dbus_message_unref (message);
-
- return result;
-}
-
-struct _Outstanding
-{
- Outstanding *next;
-
- DConfDBusClient *dcdbc;
- DConfEngineMessage dcem;
-
- gchar *set_key;
- GVariant *set_value;
- GTree *tree;
};
-static void
-dconf_dbus_client_outstanding_returned (DBusPendingCall *pending,
- gpointer user_data)
-{
- Outstanding *outstanding = user_data;
- DConfDBusClient *dcdbc;
- GVariant *reply;
-
- dcdbc = outstanding->dcdbc;
-
- /* One way or another we no longer need this hooked into the list.
- */
- {
- Outstanding **tmp;
-
- for (tmp = &dcdbc->outstanding; tmp; tmp = &(*tmp)->next)
- if (*tmp == outstanding)
- {
- *tmp = outstanding->next;
- break;
- }
- }
-
- reply = dconf_dbus_client_send_finish (pending);
-
- if (reply)
- {
- /* Success.
- *
- * We want to ensure that we don't emit an extra change
- * notification signal when we see the signal that the service is
- * about to send, so store the tag so we know to ignore it when
- * the signal comes.
- *
- * No thread safety issue here since this variable is only
- * accessed from the worker thread.
- */
- g_free (dcdbc->anti_expose_tag);
-
- if (g_variant_is_of_type (reply, G_VARIANT_TYPE ("(s)")))
- g_variant_get_child (reply, 0, "s", dcdbc->anti_expose_tag);
-
- g_variant_unref (reply);
- }
- else
- {
- /* An error of some kind.
- *
- * We already removed the outstanding entry from the list, so the
- * unmodified database is now visible to the client. Change
- * notify so that they see it.
- */
- if (outstanding->set_key)
- /* XXX emit */;
- else
- /* XXX emit */;
- }
-
- dconf_engine_message_destroy (&outstanding->dcem);
- dconf_dbus_client_unref (outstanding->dcdbc);
- g_free (outstanding->set_key);
-
- if (outstanding->set_value)
- g_variant_unref (outstanding->set_value);
-
- if (outstanding->tree)
- g_tree_unref (outstanding->tree);
-
- g_slice_free (Outstanding, outstanding);
-}
-
-static void
-dconf_dbus_client_queue (DConfDBusClient *dcdbc,
- DConfEngineMessage *dcem,
- const gchar *set_key,
- GVariant *set_value,
- GTree *tree)
-{
- Outstanding *outstanding;
-
- outstanding = g_slice_new (Outstanding);
- outstanding->dcdbc = dconf_dbus_client_ref (dcdbc);
- outstanding->dcem = *dcem;
-
- outstanding->set_key = g_strdup (set_key);
- outstanding->set_value = set_value ? g_variant_ref_sink (set_value) : NULL;
- outstanding->tree = tree ? g_tree_ref (tree) : NULL;
-
- outstanding->next = dcdbc->outstanding;
- dcdbc->outstanding = outstanding;
-
- dconf_dbus_client_send (outstanding->dcdbc,
- &outstanding->dcem,
- dconf_dbus_client_outstanding_returned,
- outstanding);
-}
-
-static gboolean
-dconf_dbus_client_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_dbus_client_scan_outstanding (DConfDBusClient *dcdbc,
- const gchar *key,
- GVariant **value)
-{
- gboolean found = FALSE;
- Outstanding *node;
- gsize length;
-
- length = strlen (key);
-
- if G_LIKELY (dcdbc->outstanding == NULL)
- return FALSE;
-
- for (node = dcdbc->outstanding; node; node = node->next)
- {
- 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_dbus_client_scan_outstanding_tree (node->tree, key,
- length, &result))
- {
- if (result)
- *value = g_variant_ref (result);
- else
- *value = NULL;
-
- found = TRUE;
- break;
- }
- }
- }
-
- return found;
-}
-
-/* Watches are reference counted because they can be held both by the
- * list of watches and by the pending watch registration. In the normal
- * case, the registration completes before the watch is unsubscribed
- * from but it might be the case that the watch is unsubscribed from
- * before the AddMatch completes. For that reason, either thing could
- * be responsible for freeing the watch structure; we solve that
- * ambiguity using a reference count.
- *
- * We just initially set it to 2, since these are the only two users.
- * That way we can skip having the ref() function.
- */
typedef struct
{
- DConfDBusClient *dcdbc;
- gchar *name;
+ gchar *path;
DConfDBusNotify notify;
gpointer user_data;
- guint64 initial_state;
- gint ref_count;
} Watch;
-
-
-static void
-dconf_dbus_emit_change (DConfDBusClient *dcdbc,
- const gchar *key)
+void
+dconf_engine_change_notify (DConfEngine *engine,
+ const gchar *prefix,
+ const gchar * const *changes,
+ const gchar *tag,
+ gpointer user_data)
{
+ DConfDBusClient *dcdbc = user_data;
+ gchar **my_changes;
+ gint n_changes;
GSList *iter;
+ gint i;
+
+ n_changes = g_strv_length ((gchar **) changes);
+ my_changes = g_new (gchar *, n_changes);
+
+ for (i = 0; i < n_changes; i++)
+ my_changes[i] = g_strconcat (prefix, changes[i], NULL);
+ my_changes[i] = NULL;
for (iter = dcdbc->watches; iter; iter = iter->next)
{
Watch *watch = iter->data;
- if (g_str_has_prefix (key, watch->name))
- watch->notify (dcdbc, key, watch->user_data);
+ for (i = 0; i < n_changes; i++)
+ if (g_str_has_prefix (my_changes[i], watch->path))
+ watch->notify (dcdbc, my_changes[i], watch->user_data);
}
+
+ g_strfreev (my_changes);
}
GVariant *
dconf_dbus_client_read (DConfDBusClient *dcdbc,
const gchar *key)
{
- GVariant *value;
-
- if (dconf_dbus_client_scan_outstanding (dcdbc, key, &value))
- return value;
-
- return dconf_engine_read (dcdbc->engine, key);
+ return dconf_engine_read (dcdbc->engine, NULL, key);
}
gboolean
@@ -485,102 +81,32 @@ dconf_dbus_client_write (DConfDBusClient *dcdbc,
const gchar *key,
GVariant *value)
{
- DConfEngineMessage dcem;
+ DConfChangeset *changeset;
+ gboolean success;
- if (!dconf_engine_write (dcdbc->engine, key, value, &dcem, NULL))
- return FALSE;
+ changeset = dconf_changeset_new_write (key, value);
+ success = dconf_engine_change_fast (dcdbc->engine, changeset, NULL);
+ dconf_changeset_unref (changeset);
- dconf_dbus_client_queue (dcdbc, &dcem, key, value, NULL);
- dconf_dbus_emit_change (dcdbc, key);
-
- return TRUE;
+ return success;
}
-static Watch *
-watch_new (DConfDBusClient *dcdbc,
- const gchar *name,
- DConfDBusNotify notify,
- gpointer user_data)
+void
+dconf_dbus_client_subscribe (DConfDBusClient *dcdbc,
+ const gchar *path,
+ DConfDBusNotify notify,
+ gpointer user_data)
{
Watch *watch;
watch = g_slice_new (Watch);
- watch->dcdbc = dconf_dbus_client_ref (dcdbc);
- watch->user_data = user_data;
- watch->name = g_strdup (name);
+ watch->path = g_strdup (path);
watch->notify = notify;
-
- watch->initial_state = dconf_engine_get_state (dcdbc->engine);
- watch->ref_count = 2;
+ watch->user_data = user_data;
dcdbc->watches = g_slist_prepend (dcdbc->watches, watch);
- return watch;
-}
-
-static void
-watch_unref (Watch *watch)
-{
- if (--watch->ref_count == 0)
- {
- dconf_dbus_client_unref (watch->dcdbc);
- g_free (watch->name);
- g_slice_free (Watch, watch);
- }
-}
-
-static void
-add_match_done (DBusPendingCall *pending,
- gpointer user_data)
-{
- Watch *watch = user_data;
- GVariant *reply;
-
- reply = dconf_dbus_client_send_finish (pending);
-
- if (reply == NULL)
- {
- /* This is extremely unlikely to happen and it happens
- * asynchronous to the user's call. Since the user doesn't know
- * that it happened, we pretend that it didn't (ie: we leave the
- * watch structure in the list).
- */
-
- g_critical ("DBus AddMatch for dconf path '%s'", watch->name);
- watch_unref (watch);
-
- return;
- }
-
- else
- g_variant_unref (reply); /* it is just an empty tuple */
-
- /* In the normal case we're done.
- *
- * There is a fleeting chance, however, that the database has changed
- * in the meantime. In that case we can only assume that the subject
- * of this watch changed in that time period and emit a signal to that
- * effect.
- */
- if (dconf_engine_get_state (watch->dcdbc->engine) != watch->initial_state)
- watch->notify (watch->dcdbc, watch->name, watch->user_data);
-
- watch_unref (watch);
-}
-
-void
-dconf_dbus_client_subscribe (DConfDBusClient *dcdbc,
- const gchar *name,
- DConfDBusNotify notify,
- gpointer user_data)
-{
- DConfEngineMessage dcem;
- Watch *watch;
-
- watch = watch_new (dcdbc, name, notify, user_data);
- dconf_engine_watch (dcdbc->engine, name, &dcem);
- dconf_dbus_client_send (dcdbc, &dcem, add_match_done, watch);
- dconf_engine_message_destroy (&dcem);
+ dconf_engine_watch_fast (dcdbc->engine, path);
}
void
@@ -588,7 +114,6 @@ dconf_dbus_client_unsubscribe (DConfDBusClient *dcdbc,
DConfDBusNotify notify,
gpointer user_data)
{
- DConfEngineMessage dcem;
GSList **ptr;
for (ptr = &dcdbc->watches; *ptr; ptr = &(*ptr)->next)
@@ -598,12 +123,9 @@ dconf_dbus_client_unsubscribe (DConfDBusClient *dcdbc,
if (watch->notify == notify && watch->user_data == user_data)
{
*ptr = g_slist_remove_link (*ptr, *ptr);
-
- dconf_engine_unwatch (dcdbc->engine, watch->name, &dcem);
- dconf_dbus_client_send (dcdbc, &dcem, NULL, NULL);
- dconf_engine_message_destroy (&dcem);
- watch_unref (watch);
-
+ dconf_engine_unwatch_fast (dcdbc->engine, watch->path);
+ g_free (watch->path);
+ g_slice_free (Watch, watch);
return;
}
}
@@ -614,54 +136,7 @@ dconf_dbus_client_unsubscribe (DConfDBusClient *dcdbc,
gboolean
dconf_dbus_client_has_pending (DConfDBusClient *dcdbc)
{
- return dcdbc->outstanding != NULL;
-}
-
-static DBusHandlerResult
-dconf_dbus_client_filter (DBusConnection *connection,
- DBusMessage *message,
- void *user_data)
-{
- DConfDBusClient *dcdbc = user_data;
-
- if (dbus_message_is_signal (message, "ca.desrt.dconf.Writer", "Notify") &&
- dbus_message_has_signature (message, "sass"))
- {
- DBusMessageIter iter, sub;
- const gchar *path, *tag;
-
- dbus_message_iter_init (message, &iter);
- dbus_message_iter_get_basic (&iter, &path);
- dbus_message_iter_next (&iter);
- dbus_message_iter_recurse (&iter, &sub);
- dbus_message_iter_next (&iter);
- dbus_message_iter_get_basic (&iter, &tag);
- dbus_message_iter_next (&iter);
-
- /* Only emit the event if it hasn't been anti-exposed */
- if (dcdbc->anti_expose_tag == NULL ||
- strcmp (tag, dcdbc->anti_expose_tag) != 0)
- {
- /* Empty list means that only one key changed */
- if (!dbus_message_iter_get_arg_type (&sub))
- dconf_dbus_emit_change (dcdbc, path);
-
- while (dbus_message_iter_get_arg_type (&sub) == 's')
- {
- const gchar *item;
- gchar *full;
-
- dbus_message_iter_get_basic (&sub, &item);
- full = g_strconcat (path, item, NULL);
- dconf_dbus_emit_change (dcdbc, full);
- g_free (full);
-
- dbus_message_iter_next (&sub);
- }
- }
- }
-
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ return dconf_engine_has_outstanding (dcdbc->engine);
}
DConfDBusClient *
@@ -677,18 +152,14 @@ dconf_dbus_client_new (const gchar *profile,
if (system == NULL)
system = dbus_bus_get (DBUS_BUS_SYSTEM, NULL);
+ dconf_libdbus_1_provide_bus (G_BUS_TYPE_SESSION, session);
+ dconf_libdbus_1_provide_bus (G_BUS_TYPE_SYSTEM, system);
+
dcdbc = g_slice_new (DConfDBusClient);
- dcdbc->engine = dconf_engine_new (profile);
- dcdbc->system_bus = dbus_connection_ref (system);
- dcdbc->session_bus = dbus_connection_ref (session);
- dcdbc->anti_expose_tag = NULL;
- dcdbc->outstanding = NULL;
+ dcdbc->engine = dconf_engine_new (dcdbc, NULL);
dcdbc->watches = NULL;
dcdbc->ref_count = 1;
- dbus_connection_add_filter (system, dconf_dbus_client_filter, dcdbc, NULL);
- dbus_connection_add_filter (session, dconf_dbus_client_filter, dcdbc, NULL);
-
return dcdbc;
}
@@ -697,12 +168,7 @@ dconf_dbus_client_unref (DConfDBusClient *dcdbc)
{
if (--dcdbc->ref_count == 0)
{
- dbus_connection_remove_filter (dcdbc->session_bus,
- dconf_dbus_client_filter, dcdbc);
- dbus_connection_remove_filter (dcdbc->system_bus,
- dconf_dbus_client_filter, dcdbc);
- dbus_connection_unref (dcdbc->session_bus);
- dbus_connection_unref (dcdbc->system_bus);
+ g_return_if_fail (dcdbc->watches == NULL);
g_slice_free (DConfDBusClient, dcdbc);
}
diff --git a/dbus-1/dconf-engine.c b/dbus-1/dconf-engine.c
deleted file mode 100644
index f6a1f6a..0000000
--- a/dbus-1/dconf-engine.c
+++ /dev/null
@@ -1,769 +0,0 @@
-/*
- * Copyright © 2010 Codethink Limited
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the licence, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- *
- * Author: Ryan Lortie <desrt@desrt.ca>
- */
-
-#define _XOPEN_SOURCE 600
-#include "dconf-engine.h"
-#include <gvdb-reader.h>
-#include <string.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/mman.h>
-
-void
-dconf_engine_message_destroy (DConfEngineMessage *dcem)
-{
- gint i;
-
- for (i = 0; dcem->parameters[i]; i++)
- g_variant_unref (dcem->parameters[i]);
- g_free (dcem->parameters);
-}
-
-void
-dconf_engine_message_copy (DConfEngineMessage *orig,
- DConfEngineMessage *copy)
-{
- gint i, n;
-
- *copy = *orig;
-
- for (n = 0; orig->parameters[n]; n++);
- copy->parameters = g_new (GVariant *, n + 1);
- for (i = 0; i < n; i++)
- copy->parameters[i] = g_variant_ref (orig->parameters[i]);
- copy->parameters[i] = NULL;
-}
-
-static gchar *
-dconf_shmdir_from_environment (void)
-{
- gchar *result;
-
- result = g_build_filename (g_get_user_runtime_dir (), "dconf", NULL);
-
- if (g_mkdir_with_parents (result, 0700) != 0)
- g_critical ("unable to create '%s'; dconf will not work properly.", result);
-
- return result;
-}
-
-static const gchar *
-dconf_engine_get_session_dir (void)
-{
- static const gchar *session_dir;
- static gsize initialised;
-
- if (g_once_init_enter (&initialised))
- {
- session_dir = dconf_shmdir_from_environment ();
- g_once_init_leave (&initialised, 1);
- }
-
- return session_dir;
-}
-
-struct _DConfEngine
-{
- GMutex lock;
- guint64 state;
-
-
- GvdbTable **gvdbs;
- GvdbTable **lock_tables;
- guint8 **shm;
- gchar **object_paths;
- gchar *bus_types;
- gchar **names;
- gint n_dbs;
-};
-
-static void
-dconf_engine_setup_user (DConfEngine *engine,
- gint i)
-{
- /* invariant: we never have user gvdb without shm */
- g_assert ((engine->gvdbs[i] == NULL) >= (engine->shm[i] == NULL));
-
- if (engine->names[i])
- {
- const gchar *session_dir = dconf_engine_get_session_dir ();
-
- if (session_dir)
- {
- gchar *filename;
- gint fd;
-
- filename = g_build_filename (session_dir,
- engine->names[i],
- NULL);
- fd = open (filename, O_RDWR | O_CREAT, 0600);
- g_free (filename);
-
- if (fd >= 0)
- {
- if (ftruncate (fd, 1) == 0)
- {
- engine->shm[i] = mmap (NULL, 1, PROT_READ, MAP_SHARED, fd, 0);
-
- if (engine->shm[i] == MAP_FAILED)
- engine->shm[i] = NULL;
- }
-
- close (fd);
- }
- }
-
- if (engine->shm[i])
- {
- gchar *filename;
-
- filename = g_build_filename (g_get_user_config_dir (),
- "dconf",
- engine->names[i],
- NULL);
- engine->gvdbs[i] = gvdb_table_new (filename, FALSE, NULL);
- g_free (filename);
- }
- }
-
- g_assert ((engine->gvdbs[i] == NULL) >= (engine->shm[i] == NULL));
-}
-
-static void
-dconf_engine_refresh_user (DConfEngine *engine,
- gint i)
-{
- g_assert ((engine->gvdbs[i] == NULL) >= (engine->shm[i] == NULL));
-
- /* if we failed the first time, fail forever */
- if (engine->shm[i] && *engine->shm[i] == 1)
- {
- if (engine->gvdbs[i])
- {
- gvdb_table_unref (engine->gvdbs[i]);
- engine->gvdbs[i] = NULL;
- }
-
- munmap (engine->shm[i], 1);
- engine->shm[i] = NULL;
-
- dconf_engine_setup_user (engine, i);
- engine->state++;
- }
-
- g_assert ((engine->gvdbs[i] == NULL) >= (engine->shm[i] == NULL));
-}
-
-static void
-dconf_engine_refresh_system (DConfEngine *engine,
- gint i)
-{
- if (engine->gvdbs[i] && !gvdb_table_is_valid (engine->gvdbs[i]))
- {
- if (engine->lock_tables[i])
- {
- gvdb_table_unref (engine->lock_tables[i]);
- engine->lock_tables[i] = NULL;
- }
-
- gvdb_table_unref (engine->gvdbs[i]);
- engine->gvdbs[i] = NULL;
- }
-
- if (engine->gvdbs[i] == NULL)
- {
- gchar *filename = g_build_filename ("/etc/dconf/db",
- engine->names[i], NULL);
- engine->gvdbs[i] = gvdb_table_new (filename, TRUE, NULL);
- if (engine->gvdbs[i] == NULL)
- g_error ("Unable to open '%s', specified in dconf profile\n",
- filename);
- engine->lock_tables[i] = gvdb_table_get_table (engine->gvdbs[i],
- ".locks");
- g_free (filename);
- engine->state++;
- }
-}
-
-static void
-dconf_engine_refresh (DConfEngine *engine)
-{
- gint i;
-
- for (i = 0; i < engine->n_dbs; i++)
- if (engine->bus_types[i] == 'e')
- dconf_engine_refresh_user (engine, i);
- else
- dconf_engine_refresh_system (engine, i);
-}
-
-static void
-dconf_engine_setup (DConfEngine *engine)
-{
- gint i;
-
- for (i = 0; i < engine->n_dbs; i++)
- if (engine->bus_types[i] == 'e')
- dconf_engine_setup_user (engine, i);
- else
- dconf_engine_refresh_system (engine, i);
-}
-
-guint64
-dconf_engine_get_state (DConfEngine *engine)
-{
- guint64 state;
-
- g_mutex_lock (&engine->lock);
-
- dconf_engine_refresh (engine);
- state = engine->state;
-
- g_mutex_unlock (&engine->lock);
-
- return state;
-}
-
-static gboolean
-dconf_engine_load_profile (const gchar *profile,
- gchar **bus_types,
- gchar ***names,
- gint *n_dbs,
- GError **error)
-{
- gchar *filename;
- gint allocated;
- char line[80];
- FILE *f;
-
- /* DCONF_PROFILE starting with '/' gives an absolute path to a profile */
- if (profile[0] != '/')
- filename = g_build_filename ("/etc/dconf/profile", profile, NULL);
- else
- filename = g_strdup (profile);
-
- f = fopen (filename, "r");
-
- if (f == NULL)
- {
- gint saved_errno = errno;
-
- g_set_error (error, G_FILE_ERROR,
- g_file_error_from_errno (saved_errno),
- "open '%s': %s", filename, g_strerror (saved_errno));
- g_free (filename);
- return FALSE;
- }
-
- allocated = 4;
- *bus_types = g_new (gchar, allocated);
- *names = g_new (gchar *, allocated);
- *n_dbs = 0;
-
- /* quick and dirty is good enough for now */
- while (fgets (line, sizeof line, f))
- {
- const gchar *end;
- const gchar *sep;
-
- end = strchr (line, '\n');
-
- if (end == NULL)
- g_error ("long line in %s", filename);
-
- if (end == line)
- continue;
-
- if (line[0] == '#')
- continue;
-
- if (*n_dbs == allocated)
- {
- allocated *= 2;
- *names = g_renew (gchar *, *names, allocated);
- *bus_types = g_renew (gchar, *bus_types, allocated);
- }
-
- sep = strchr (line, ':');
-
- if (sep)
- {
- /* strings MUST be 'user-db' or 'system-db'. we do the check
- * this way here merely because it is the fastest.
- */
- (*bus_types)[*n_dbs] = (line[0] == 'u') ? 'e' : 'y';
- (*names)[*n_dbs] = g_strndup (sep + 1, end - (sep + 1));
- }
- else
- {
- /* default is for first DB to be user and rest to be system */
- (*bus_types)[*n_dbs] = (*n_dbs == 0) ? 'e' : 'y';
- (*names)[*n_dbs] = g_strndup (line, end - line);
- }
-
- (*n_dbs)++;
- }
-
- *bus_types = g_renew (gchar, *bus_types, *n_dbs);
- *names = g_renew (gchar *, *names, *n_dbs);
- g_free (filename);
- fclose (f);
-
- return TRUE;
-}
-
-DConfEngine *
-dconf_engine_new (const gchar *profile)
-{
- DConfEngine *engine;
- gint i;
-
- engine = g_slice_new (DConfEngine);
- g_mutex_init (&engine->lock);
-
- if (profile == NULL)
- profile = getenv ("DCONF_PROFILE");
-
- if (profile)
- {
- GError *error = NULL;
-
- if (!dconf_engine_load_profile (profile, &engine->bus_types, &engine->names, &engine->n_dbs, &error))
- g_error ("Error loading dconf profile '%s': %s\n",
- profile, error->message);
- }
- else
- {
- if (!dconf_engine_load_profile ("user", &engine->bus_types, &engine->names, &engine->n_dbs, NULL))
- {
- engine->names = g_new (gchar *, 1);
- engine->names[0] = g_strdup ("user");
- engine->bus_types = g_strdup ("e");
- engine->n_dbs = 1;
- }
- }
-
- if (strcmp (engine->names[0], "-") == 0)
- {
- g_free (engine->names[0]);
- engine->names[0] = NULL;
- }
-
- engine->object_paths = g_new (gchar *, engine->n_dbs);
- engine->gvdbs = g_new0 (GvdbTable *, engine->n_dbs);
- engine->lock_tables = g_new0 (GvdbTable *, engine->n_dbs);
- engine->shm = g_new0 (guint8 *, engine->n_dbs);
- engine->state = 0;
-
- for (i = 0; i < engine->n_dbs; i++)
- if (engine->names[i])
- engine->object_paths[i] = g_strjoin (NULL,
- "/ca/desrt/dconf/Writer/",
- engine->names[i],
- NULL);
- else
- engine->object_paths[i] = NULL;
-
- dconf_engine_setup (engine);
-
- return engine;
-}
-
-void
-dconf_engine_free (DConfEngine *engine)
-{
- gint i;
-
- for (i = 0; i < engine->n_dbs; i++)
- {
- g_free (engine->object_paths[i]);
- g_free (engine->names[i]);
-
- if (engine->gvdbs[i])
- gvdb_table_unref (engine->gvdbs[i]);
-
- if (engine->lock_tables[i])
- gvdb_table_unref (engine->lock_tables[i]);
-
- if (engine->shm[i])
- munmap (engine->shm[i], 1);
- }
-
-
- g_mutex_clear (&engine->lock);
-
- g_free (engine->object_paths);
- g_free (engine->bus_types);
- g_free (engine->names);
- g_free (engine->gvdbs);
- g_free (engine->lock_tables);
- g_free (engine->shm);
-
- g_slice_free (DConfEngine, engine);
-}
-
-static GVariant *
-dconf_engine_read_internal (DConfEngine *engine,
- const gchar *key,
- gboolean user,
- gboolean system)
-{
- GVariant *value = NULL;
- gint lowest;
- gint limit;
- gint i;
-
- g_mutex_lock (&engine->lock);
-
- dconf_engine_refresh (engine);
-
- /* Bound the search space depending on the databases that we are
- * interested in.
- */
- limit = system ? engine->n_dbs : 1;
- lowest = user ? 0 : 1;
-
- /* We want i equal to the index of the highest database containing a
- * lock, or i == lowest if there is no lock. For that reason, we
- * don't actually check the lowest database for a lock. That makes
- * sense, because even if it had a lock, it would not change our
- * search policy (which would be to check the lowest one first).
- *
- * Note that we intentionally dishonour 'limit' here -- we want to
- * ensure that values in the user database are always ignored when
- * locks are present.
- */
- for (i = MAX (engine->n_dbs - 1, lowest); lowest < i; i--)
- if (engine->lock_tables[i] != NULL &&
- gvdb_table_has_value (engine->lock_tables[i], key))
- break;
-
- while (i < limit && value == NULL)
- {
- if (engine->gvdbs[i] != NULL)
- value = gvdb_table_get_value (engine->gvdbs[i], key);
- i++;
- }
-
- g_mutex_unlock (&engine->lock);
-
- return value;
-}
-
-GVariant *
-dconf_engine_read (DConfEngine *engine,
- const gchar *key)
-{
- return dconf_engine_read_internal (engine, key, TRUE, TRUE);
-}
-
-GVariant *
-dconf_engine_read_default (DConfEngine *engine,
- const gchar *key)
-{
- return dconf_engine_read_internal (engine, key, FALSE, TRUE);
-}
-
-GVariant *
-dconf_engine_read_no_default (DConfEngine *engine,
- const gchar *key)
-{
- return dconf_engine_read_internal (engine, key, TRUE, FALSE);
-}
-
-static void
-dconf_engine_make_match_rule (DConfEngine *engine,
- DConfEngineMessage *dcem,
- const gchar *name,
- const gchar *method_name)
-{
- gint i;
-
- dcem->bus_name = "org.freedesktop.DBus";
- dcem->object_path = "/org/freedesktop/DBus";
- dcem->interface_name = "org.freedesktop.DBus";
- dcem->method_name = method_name;
-
- dcem->parameters = g_new (GVariant *, engine->n_dbs + 1);
- for (i = 0; i < engine->n_dbs; i++)
- {
- gchar *rule;
-
- rule = g_strdup_printf ("type='signal',"
- "interface='ca.desrt.dconf.Writer',"
- "path='%s',"
- "arg0path='%s'",
- engine->object_paths[i],
- name);
- dcem->parameters[i] = g_variant_new ("(s)", rule);
- g_variant_ref_sink (dcem->parameters[i]);
- g_free (rule);
- }
- dcem->parameters[i] = NULL;
-
- dcem->bus_types = engine->bus_types;
- dcem->n_messages = engine->n_dbs;
- dcem->reply_type = G_VARIANT_TYPE_UNIT;
-}
-
-void
-dconf_engine_watch (DConfEngine *engine,
- const gchar *name,
- DConfEngineMessage *dcem)
-{
- dconf_engine_make_match_rule (engine, dcem, name, "AddMatch");
-}
-
-void
-dconf_engine_unwatch (DConfEngine *engine,
- const gchar *name,
- DConfEngineMessage *dcem)
-{
- dconf_engine_make_match_rule (engine, dcem, name, "RemoveMatch");
-}
-
-gboolean
-dconf_engine_is_writable (DConfEngine *engine,
- const gchar *name)
-{
- gboolean writable = TRUE;
-
- /* Only check if we have more than one database */
- if (engine->n_dbs > 1)
- {
- gint i;
-
- g_mutex_lock (&engine->lock);
-
- dconf_engine_refresh (engine);
-
- /* Don't check for locks in the top database (i == 0). */
- for (i = engine->n_dbs - 1; 0 < i; i--)
- if (engine->lock_tables[i] != NULL &&
- gvdb_table_has_value (engine->lock_tables[i], name))
- {
- writable = FALSE;
- break;
- }
-
- g_mutex_unlock (&engine->lock);
- }
-
- return writable;
-}
-
-/* be conservative and fast: false negatives are OK */
-static gboolean
-is_dbusable (GVariant *value)
-{
- const gchar *type;
-
- type = g_variant_get_type_string (value);
-
- /* maybe definitely won't work.
- * variant? too lazy to check inside...
- */
- if (strchr (type, 'v') || strchr (type, 'm'))
- return FALSE;
-
- /* XXX: we could also check for '{}' not inside an array...
- * but i'm not sure we want to support that anyway.
- */
-
- /* this will avoid any too-deeply-nested limits */
- return strlen (type) < 32;
-}
-
-static GVariant *
-fake_maybe (GVariant *value)
-{
- GVariantBuilder builder;
-
- g_variant_builder_init (&builder, G_VARIANT_TYPE ("av"));
-
- if (value != NULL)
- {
- if (is_dbusable (value))
- g_variant_builder_add (&builder, "v", value);
-
- else
- {
- GVariant *variant;
- GVariant *ay;
-
- variant = g_variant_new_variant (value);
- ay = g_variant_new_from_data (G_VARIANT_TYPE_BYTESTRING,
- g_variant_get_data (variant),
- g_variant_get_size (variant),
- TRUE,
- (GDestroyNotify) g_variant_unref,
- variant);
- g_variant_builder_add (&builder, "v", ay);
-
- g_variant_builder_add (&builder, "v",
- g_variant_new_string ("serialised GVariant"));
- }
- }
-
- return g_variant_builder_end (&builder);
-}
-
-static void
-dconf_engine_dcem (DConfEngine *engine,
- DConfEngineMessage *dcem,
- const gchar *method_name,
- const gchar *format_string,
- ...)
-{
- va_list ap;
-
- dcem->bus_name = "ca.desrt.dconf";
- dcem->object_path = engine->object_paths[0];
- dcem->interface_name = "ca.desrt.dconf.Writer";
- dcem->method_name = method_name;
- dcem->parameters = g_new (GVariant *, 2);
- dcem->n_messages = 1;
-
- va_start (ap, format_string);
- dcem->parameters[0] = g_variant_new_va (format_string, NULL, &ap);
- g_variant_ref_sink (dcem->parameters[0]);
- dcem->parameters[1] = NULL;
- va_end (ap);
-
- dcem->bus_types = engine->bus_types;
- dcem->reply_type = G_VARIANT_TYPE ("(s)");
-}
-
-gboolean
-dconf_engine_write (DConfEngine *engine,
- const gchar *name,
- GVariant *value,
- DConfEngineMessage *dcem,
- GError **error)
-{
- dconf_engine_dcem (engine, dcem,
- "Write", "(s@av)",
- name, fake_maybe (value));
-
- return TRUE;
-}
-
-gboolean
-dconf_engine_write_many (DConfEngine *engine,
- const gchar *prefix,
- const gchar * const *keys,
- GVariant **values,
- DConfEngineMessage *dcem,
- GError **error)
-{
- 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_engine_dcem (engine, dcem, "WriteMany", "(sa(sav))", prefix, &builder);
-
- return TRUE;
-}
-
-gchar **
-dconf_engine_list (DConfEngine *engine,
- const gchar *dir,
- gint *length)
-{
- gchar **list;
-
- g_mutex_lock (&engine->lock);
-
- dconf_engine_refresh (engine);
-
- if (engine->gvdbs[0])
- list = gvdb_table_list (engine->gvdbs[0], dir);
- else
- list = NULL;
-
- if (list == NULL)
- list = g_new0 (char *, 1);
-
- if (length)
- *length = g_strv_length (list);
-
- g_mutex_unlock (&engine->lock);
-
- return list;
-}
-
-gboolean
-dconf_engine_decode_notify (DConfEngine *engine,
- const gchar *anti_expose,
- const gchar **path,
- const gchar ***rels,
- guint bus_type,
- const gchar *sender,
- const gchar *iface,
- const gchar *method,
- GVariant *body)
-{
- if (strcmp (iface, "ca.desrt.dconf.Writer") || strcmp (method, "Notify"))
- return FALSE;
-
- if (!g_variant_is_of_type (body, G_VARIANT_TYPE ("(sass)")))
- return FALSE;
-
- if (anti_expose)
- {
- const gchar *ae;
-
- g_variant_get_child (body, 2, "&s", &ae);
-
- if (strcmp (ae, anti_expose) == 0)
- return FALSE;
- }
-
- g_variant_get (body, "(&s^a&ss)", path, rels, NULL);
-
- return TRUE;
-}
-
-gboolean
-dconf_engine_decode_writability_notify (const gchar **path,
- const gchar *iface,
- const gchar *method,
- GVariant *body)
-{
- if (strcmp (iface, "ca.desrt.dconf.Writer") ||
- strcmp (method, "WritabilityNotify"))
- return FALSE;
-
- if (!g_variant_is_of_type (body, G_VARIANT_TYPE ("(s)")))
- return FALSE;
-
- g_variant_get_child (body, 0, "&s", path);
-
- return TRUE;
-}
diff --git a/dbus-1/dconf-engine.h b/dbus-1/dconf-engine.h
deleted file mode 100644
index 25de43d..0000000
--- a/dbus-1/dconf-engine.h
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * Copyright © 2010 Codethink Limited
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the licence, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- *
- * Author: Ryan Lortie <desrt@desrt.ca>
- */
-
-#ifndef __dconf_engine_h__
-#define __dconf_engine_h__
-
-#include <glib.h>
-
-typedef struct _DConfEngine DConfEngine;
-
-/**
- * DConfEngineMessage:
- *
- * This structure represents a number of DBus method call messages that #DConfEngine would like to send.
- *
- * #DConfEngine itself is unaware of a particular DBus or main loop implementation. As such, all requests are
- * synchronous and non-blocking, but most of them produce a #DConfEngineMessage describing messages that must be
- * sent in order for the operation to be completed.
- *
- * @bus_name, @object_path, @interface_name, @method_name specify the respective header fields of the method
- * call. These are always equal for all of the calls contained within a single #DConfEngineMessage.
- *
- * @reply_type is the expected reply type of the method call. This is also the same for all calls contained
- * within a single #DConfEngineMessage.
- *
- * @n_messages is the number of messages to send.
- *
- * @bus_types and @parameters are both arrays, of length @n_messages. Each element of @bus_type is the bus type
- * to send each method call on and each of @parameters is the body of that call. The reason that there may be
- * several messages is that a single dconf "watch" operation may need to send multiple DBus "AddMatch" calls
- * (and usually to multiple busses).
- *
- * Each element in @bus_types is either 'y' for system bus or 'e' for session bus.
- *
- * A #DConfEngineMessage is always stack-allocated by the caller. It must be cleared using
- * dconf_engine_message_destroy() when done. It may be copied using dconf_engine_message_copy().
- */
-typedef struct
-{
- const gchar *bus_name;
- const gchar *object_path;
- const gchar *interface_name;
- const gchar *method_name;
-
- gint n_messages;
- GVariant **parameters;
- const gchar *bus_types;
-
- const GVariantType *reply_type;
-} DConfEngineMessage;
-
-G_GNUC_INTERNAL
-void dconf_engine_message_copy (DConfEngineMessage *orig,
- DConfEngineMessage *copy);
-G_GNUC_INTERNAL
-void dconf_engine_message_destroy (DConfEngineMessage *message);
-
-G_GNUC_INTERNAL
-DConfEngine * dconf_engine_new (const gchar *profile);
-G_GNUC_INTERNAL
-DConfEngine * dconf_engine_new_for_db (const gchar *db_name);
-G_GNUC_INTERNAL
-guint64 dconf_engine_get_state (DConfEngine *engine);
-
-G_GNUC_INTERNAL
-void dconf_engine_free (DConfEngine *engine);
-
-G_GNUC_INTERNAL
-GVariant * dconf_engine_read (DConfEngine *engine,
- const gchar *key);
-G_GNUC_INTERNAL
-GVariant * dconf_engine_read_default (DConfEngine *engine,
- const gchar *key);
-G_GNUC_INTERNAL
-GVariant * dconf_engine_read_no_default (DConfEngine *engine,
- const gchar *key);
-G_GNUC_INTERNAL
-gchar ** dconf_engine_list (DConfEngine *engine,
- const gchar *path,
- gint *length);
-
-G_GNUC_INTERNAL
-void dconf_engine_get_service_info (DConfEngine *engine,
- const gchar **bus_type,
- const gchar **destination,
- const gchar **object_path);
-G_GNUC_INTERNAL
-gboolean dconf_engine_is_writable (DConfEngine *engine,
- const gchar *name);
-G_GNUC_INTERNAL
-gboolean dconf_engine_write (DConfEngine *engine,
- const gchar *key,
- GVariant *value,
- DConfEngineMessage *message,
- GError **error);
-G_GNUC_INTERNAL
-gboolean dconf_engine_write_many (DConfEngine *engine,
- const gchar *prefix,
- const gchar * const *keys,
- GVariant **values,
- DConfEngineMessage *message,
- GError **error);
-G_GNUC_INTERNAL
-void dconf_engine_watch (DConfEngine *engine,
- const gchar *name,
- DConfEngineMessage *message);
-G_GNUC_INTERNAL
-void dconf_engine_unwatch (DConfEngine *engine,
- const gchar *name,
- DConfEngineMessage *message);
-G_GNUC_INTERNAL
-gboolean dconf_engine_decode_notify (DConfEngine *engine,
- const gchar *anti_expose,
- const gchar **prefix,
- const gchar ***keys,
- guint bus_type,
- const gchar *sender,
- const gchar *interface,
- const gchar *member,
- GVariant *body);
-G_GNUC_INTERNAL
-gboolean dconf_engine_decode_writability_notify (const gchar **path,
- const gchar *iface,
- const gchar *method,
- GVariant *body);
-#endif /* __dconf_engine_h__ */
diff --git a/dbus-1/dconf-libdbus-1.c b/dbus-1/dconf-libdbus-1.c
new file mode 100644
index 0000000..aedc2cf
--- /dev/null
+++ b/dbus-1/dconf-libdbus-1.c
@@ -0,0 +1,352 @@
+/**
+ * Copyright © 2010 Canonical Limited
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the licence, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Ryan Lortie <desrt@desrt.ca>
+ **/
+
+#include "dconf-libdbus-1.h"
+
+#include "../engine/dconf-engine.h"
+
+#include <string.h>
+
+static DBusConnection *dconf_libdbus_1_buses[5];
+
+struct _DConfDBusClient
+{
+ DConfEngine *engine;
+ GSList *watches;
+ gint ref_count;
+};
+
+#define DCONF_LIBDBUS_1_ERROR (g_quark_from_static_string("DCONF_LIBDBUS_1_ERROR"))
+#define DCONF_LIBDBUS_1_ERROR_FAILED 0
+
+static DBusMessage *
+dconf_libdbus_1_new_method_call (const gchar *bus_name,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *method_name,
+ GVariant *parameters)
+{
+ DBusMessageIter dbus_iter;
+ DBusMessage *message;
+ GVariantIter iter;
+ GVariant *child;
+
+ g_variant_ref_sink (parameters);
+
+ message = dbus_message_new_method_call (bus_name, object_path, interface_name, method_name);
+ dbus_message_iter_init_append (message, &dbus_iter);
+ g_variant_iter_init (&iter, parameters);
+
+ while ((child = g_variant_iter_next_value (&iter)))
+ {
+ if (g_variant_is_of_type (child, G_VARIANT_TYPE_STRING))
+ {
+ const gchar *str;
+
+ str = g_variant_get_string (child, NULL);
+ dbus_message_iter_append_basic (&dbus_iter, DBUS_TYPE_STRING, &str);
+ }
+
+ else
+ {
+ const guint8 *bytes;
+ gsize n_elements;
+
+ g_assert (g_variant_is_of_type (child, G_VARIANT_TYPE_BYTESTRING));
+
+ bytes = g_variant_get_fixed_array (child, &n_elements, sizeof (guint8));
+ dbus_message_iter_append_fixed_array (&dbus_iter, DBUS_TYPE_BYTE, &bytes, n_elements);
+ }
+
+ g_variant_unref (child);
+ }
+
+ g_variant_unref (parameters);
+
+ return message;
+}
+
+static GVariant *
+dconf_libdbus_1_get_message_body (DBusMessage *message,
+ GError **error)
+{
+ GVariantBuilder builder;
+ const gchar *signature;
+ DBusMessageIter iter;
+
+ /* We support two types: strings and arrays of strings.
+ *
+ * It's very simple to detect if the message contains only these
+ * types: check that the signature contains only the letters "a" and
+ * "s" and that it does not contain "aa".
+ */
+ signature = dbus_message_get_signature (message);
+ if (signature[strspn(signature, "as")] != '\0' || strstr (signature, "aa"))
+ {
+ g_set_error (error, DCONF_LIBDBUS_1_ERROR, DCONF_LIBDBUS_1_ERROR_FAILED,
+ "unable to handle message type '(%s)'", signature);
+ return NULL;
+ }
+
+ g_variant_builder_init (&builder, G_VARIANT_TYPE_TUPLE);
+ dbus_message_iter_init (message, &iter);
+ while (dbus_message_iter_get_arg_type (&iter))
+ {
+ const gchar *string;
+
+ if (dbus_message_iter_get_arg_type (&iter) == DBUS_TYPE_STRING)
+ {
+ dbus_message_iter_get_basic (&iter, &string);
+ g_variant_builder_add (&builder, "s", string);
+ }
+ else
+ {
+ DBusMessageIter sub;
+
+ g_assert (dbus_message_iter_get_arg_type (&iter) == DBUS_TYPE_ARRAY &&
+ dbus_message_iter_get_element_type (&iter) == DBUS_TYPE_STRING);
+
+ g_variant_builder_open (&builder, G_VARIANT_TYPE_STRING_ARRAY);
+ dbus_message_iter_recurse (&iter, &sub);
+
+ while (dbus_message_iter_get_arg_type (&sub))
+ {
+ const gchar *string;
+ dbus_message_iter_get_basic (&sub, &string);
+ g_variant_builder_add (&builder, "s", string);
+ dbus_message_iter_next (&sub);
+ }
+
+ g_variant_builder_close (&builder);
+ }
+ dbus_message_iter_next (&iter);
+ }
+
+ return g_variant_ref_sink (g_variant_builder_end (&builder));
+}
+
+static GVariant *
+dconf_libdbus_1_interpret_result (DBusMessage *result,
+ const GVariantType *expected_type,
+ GError **error)
+{
+ GVariant *reply;
+
+ if (dbus_message_get_type (result) == DBUS_MESSAGE_TYPE_ERROR)
+ {
+ const gchar *errstr = "(no message)";
+
+ dbus_message_get_args (result, NULL, DBUS_TYPE_STRING, &errstr, DBUS_TYPE_INVALID);
+ g_set_error (error, DCONF_LIBDBUS_1_ERROR, DCONF_LIBDBUS_1_ERROR_FAILED,
+ "%s: %s", dbus_message_get_error_name (result), errstr);
+ return NULL;
+ }
+
+ reply = dconf_libdbus_1_get_message_body (result, error);
+
+ if (reply && expected_type && !g_variant_is_of_type (reply, expected_type))
+ {
+ gchar *expected_string;
+
+ expected_string = g_variant_type_dup_string (expected_type);
+ g_set_error (error, DCONF_LIBDBUS_1_ERROR, DCONF_LIBDBUS_1_ERROR_FAILED,
+ "received reply '%s' is not of the expected type %s",
+ g_variant_get_type_string (reply), expected_string);
+ g_free (expected_string);
+
+ g_variant_unref (reply);
+ reply = NULL;
+ }
+
+ return reply;
+}
+
+static void
+dconf_libdbus_1_method_call_done (DBusPendingCall *pending,
+ gpointer user_data)
+{
+ DConfEngineCallHandle *handle = user_data;
+ const GVariantType *expected_type;
+ DBusMessage *message;
+ GError *error = NULL;
+ GVariant *reply;
+
+ if (pending == NULL)
+ return;
+
+ message = dbus_pending_call_steal_reply (pending);
+ dbus_pending_call_unref (pending);
+
+ expected_type = dconf_engine_call_handle_get_expected_type (handle);
+ reply = dconf_libdbus_1_interpret_result (message, expected_type, &error);
+ dbus_message_unref (message);
+
+ dconf_engine_call_handle_reply (handle, reply, error);
+
+ if (reply)
+ g_variant_unref (reply);
+ if (error)
+ g_error_free (error);
+}
+
+gboolean
+dconf_engine_dbus_call_async_func (GBusType bus_type,
+ const gchar *bus_name,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *method_name,
+ GVariant *parameters,
+ DConfEngineCallHandle *handle,
+ GError **error)
+{
+ DBusConnection *connection;
+ DBusPendingCall *pending;
+ DBusMessage *message;
+
+ g_assert_cmpint (bus_type, <, G_N_ELEMENTS (dconf_libdbus_1_buses));
+ connection = dconf_libdbus_1_buses[bus_type];
+ g_assert (connection != NULL);
+
+ message = dconf_libdbus_1_new_method_call (bus_name, object_path, interface_name, method_name, parameters);
+ dbus_connection_send_with_reply (connection, message, &pending, -1);
+ dbus_pending_call_set_notify (pending, dconf_libdbus_1_method_call_done, handle, NULL);
+ dbus_message_unref (message);
+
+ return TRUE;
+}
+
+static void
+dconf_libdbus_1_convert_error (DBusError *dbus_error,
+ GError **error)
+{
+ g_set_error (error, DCONF_LIBDBUS_1_ERROR, DCONF_LIBDBUS_1_ERROR_FAILED,
+ "%s: %s", dbus_error->name, dbus_error->message);
+}
+
+GVariant *
+dconf_engine_dbus_call_sync_func (GBusType bus_type,
+ const gchar *bus_name,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *method_name,
+ GVariant *parameters,
+ const GVariantType *expected_type,
+ GError **error)
+{
+ DBusConnection *connection;
+ DBusMessage *message;
+ DBusError dbus_error;
+ DBusMessage *result;
+ GVariant *reply;
+
+ g_assert_cmpint (bus_type, <, G_N_ELEMENTS (dconf_libdbus_1_buses));
+ connection = dconf_libdbus_1_buses[bus_type];
+ g_assert (connection != NULL);
+
+ dbus_error_init (&dbus_error);
+ message = dconf_libdbus_1_new_method_call (bus_name, object_path, interface_name, method_name, parameters);
+ result = dbus_connection_send_with_reply_and_block (connection, message, -1, &dbus_error);
+ dbus_message_unref (message);
+
+ if (result == NULL)
+ {
+ dconf_libdbus_1_convert_error (&dbus_error, error);
+ dbus_error_free (&dbus_error);
+ return NULL;
+ }
+
+ reply = dconf_libdbus_1_interpret_result (result, expected_type, error);
+ dbus_message_unref (result);
+
+ return reply;
+}
+
+static DBusHandlerResult
+dconf_libdbus_1_filter (DBusConnection *connection,
+ DBusMessage *message,
+ gpointer user_data)
+{
+ GBusType bus_type = GPOINTER_TO_INT (user_data);
+
+ if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_SIGNAL)
+ {
+ const gchar *interface;
+
+ interface = dbus_message_get_interface (message);
+
+ if (interface && g_str_equal (interface, "ca.desrt.dconf.Writer"))
+ {
+ GVariant *parameters;
+
+ parameters = dconf_libdbus_1_get_message_body (message, NULL);
+
+ if (parameters != NULL)
+ {
+ dconf_engine_handle_dbus_signal (bus_type,
+ dbus_message_get_sender (message),
+ dbus_message_get_path (message),
+ dbus_message_get_member (message),
+ parameters);
+ g_variant_unref (parameters);
+ }
+ }
+ }
+
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+void
+dconf_libdbus_1_provide_bus (GBusType bus_type,
+ DBusConnection *connection)
+{
+ g_assert_cmpint (bus_type, <, G_N_ELEMENTS (dconf_libdbus_1_buses));
+
+ if (!dconf_libdbus_1_buses[bus_type])
+ {
+ dconf_libdbus_1_buses[bus_type] = dbus_connection_ref (connection);
+ dbus_connection_add_filter (connection, dconf_libdbus_1_filter, GINT_TO_POINTER (bus_type), NULL);
+ }
+}
+
+#ifndef PIC
+static gboolean
+dconf_libdbus_1_check_connection (gpointer user_data)
+{
+ DBusConnection *connection = user_data;
+
+ dbus_connection_read_write (connection, 0);
+ dbus_connection_dispatch (connection);
+
+ return G_SOURCE_CONTINUE;
+}
+
+void
+dconf_engine_dbus_init_for_testing (void)
+{
+ DBusConnection *session;
+ DBusConnection *system;
+
+ dconf_libdbus_1_provide_bus (G_BUS_TYPE_SESSION, session = dbus_bus_get (DBUS_BUS_SESSION, NULL));
+ dconf_libdbus_1_provide_bus (G_BUS_TYPE_SYSTEM, system = dbus_bus_get (DBUS_BUS_SYSTEM, NULL));
+
+ /* "mainloop integration" */
+ g_timeout_add (1, dconf_libdbus_1_check_connection, session);
+ g_timeout_add (1, dconf_libdbus_1_check_connection, system);
+}
+#endif
diff --git a/dbus-1/dconf-libdbus-1.h b/dbus-1/dconf-libdbus-1.h
new file mode 100644
index 0000000..201096a
--- /dev/null
+++ b/dbus-1/dconf-libdbus-1.h
@@ -0,0 +1,11 @@
+#ifndef __dconf_libdbus_1_h__
+#define __dconf_libdbus_1_h__
+
+#include <dbus/dbus.h>
+#include <gio/gio.h>
+
+G_GNUC_INTERNAL
+void dconf_libdbus_1_provide_bus (GBusType bus_type,
+ DBusConnection *connection);
+
+#endif /* __dconf_libdbus_1_h__ */