/srv/mercurial-server/detachablepurple: ae34e9f420df: Rewritten ...

Gilles Bedel gillux at cpw.pidgin.im
Fri Jun 15 22:01:34 EDT 2012


Changeset: ae34e9f420dfa47064981a9dcb38ac10b67d80f5
Author:	 Gilles Bedel <gillux at cpw.pidgin.im>
Date:	 2012-05-12 20:13 +0000
Branch:	 cpw.gillux.detachablepurple
URL: http://hg.pidgin.im/srv/mercurial-server/detachablepurple/rev/ae34e9f420df

Description:

Rewritten the GetAllAccounts D-Bus method implementation of
PurpleConstructor. It's now GVariant-based, simpler and cleaner. :-)

diffstat:

 libpurple/dbus/constructor.c   |  411 ++++++++++++++--------------------------
 libpurple/dbus/constructor.xml |    2 +-
 2 files changed, 144 insertions(+), 269 deletions(-)

diffs (truncated from 476 to 300 lines):

diff --git a/libpurple/dbus/constructor.c b/libpurple/dbus/constructor.c
--- a/libpurple/dbus/constructor.c
+++ b/libpurple/dbus/constructor.c
@@ -34,6 +34,8 @@
 #include "debug.h"
 #include "marshallers.h"
 
+#include "glib-2.30.h" /* g_dbus_gvariant_to_gvalue() */
+
 /**
  * PurpleConstructor, a dummy class to remotely create and load gobjects over DBus.
  *
@@ -59,23 +61,6 @@
 
 G_DEFINE_TYPE(PurpleConstructor, purple_constructor, PURPLE_TYPE_OBJECT)
 
-/* DBus transfered data formats */
-#define DBUS_STRUCT_PROPERTY \
-( \
-	dbus_g_type_get_struct("GValueArray", \
-		G_TYPE_STRING, G_TYPE_VALUE, G_TYPE_INVALID) \
-)
-#define DBUS_COLLECTION_PROPS \
-( \
-	dbus_g_type_get_collection("GPtrArray", \
-		DBUS_STRUCT_PROPERTY) \
-)
-#define DBUS_STRUCT_ACCOUNT \
-( \
-	dbus_g_type_get_struct("GValueArray", \
-		G_TYPE_STRING, DBUS_COLLECTION_PROPS, G_TYPE_INVALID) \
-)
-
 static GVariant* purple_constructor_get_all_accounts(void);
 
 static char*
@@ -114,6 +99,8 @@
 	/* Both client and daemon can build this well-known name. */
 	pobjclass->build_dbus_path = purple_constructor_build_dbus_path;
 	if (purple_core_is_daemon_mode()) {
+		purple_object_bind_dbus_callback(pobjclass, "GetAllAccounts",
+		                                 (GCallback)purple_constructor_get_all_accounts);
 		/**
 		 * Add dbus stuff to this gobject.
 		 */
@@ -188,279 +175,167 @@
 	}
 }
 
-/**
- * A callback used in pack_accounts_cb().
- * Packs the given prop_name named property into a
- * { prop_name, prop_gvalue } dbus structure and append it in props_pack.
+/* Creates a new proxy gobject of type_name, initializing its properties with
+ * what's in props, and sets its object path to dbus_path.
  */
+static gpointer
+purple_constructor_new_proxy_object(gchar *type_name, char *dbus_path, GVariant *props)
+{
+	GType type;
+	GParameter *params;
+	guint n_params, i = 0;
+	GVariantIter iter;
+	GVariant *prop;
+	const gchar *prop_name;
+	GVariant *prop_value;
+	gpointer object;
+
+	/* Retreive the type. */
+	type = g_type_from_name(type_name);
+	g_return_val_if_fail(type != 0, NULL);
+
+	/* Parse the given properties and build the parmas array. */
+	g_variant_iter_init(&iter, props);
+	n_params = g_variant_iter_n_children(&iter);
+	params = g_new0(GParameter, n_params);
+	while ((prop = g_variant_iter_next_value(&iter)) != NULL && i < n_params) {
+		g_variant_get(prop, "(sv)", &prop_name, &prop_value);
+		params[i].name = prop_name;
+
+		/* Maybe convert object path names into object references. */
+		if (g_variant_is_of_type(prop_value, G_VARIANT_TYPE_OBJECT_PATH)) {
+			const gchar *path = g_variant_get_string(prop_value, NULL);
+			GObject *obj = purple_dbus_get_gobject_by_path(path);
+			g_value_init(&params[i].value, G_TYPE_OBJECT);
+			g_value_set_object(&params[i].value, obj);
+		} else {
+			g_dbus_gvariant_to_gvalue(prop_value, &params[i].value);
+		}
+		i++;
+
+		g_variant_unref(prop_value);
+		g_variant_unref(prop);
+	}
+
+	/* Create this object with the given properties. */
+	object = g_object_newv(type, n_params, params);
+
+	/* Free all these temporary data. */
+	while (n_params--) {
+		g_free((gchar*)params[n_params].name);
+		g_value_unset(&params[n_params].value);
+	}
+	g_free(params);
+
+	return object;
+}
+
+/* Packs all the exported properties of a PurpleObject into an a(sv) GVariant. */
+static GVariant*
+pack_pobject_properties(PurpleObject *pobject)
+{
+	GVariantBuilder builder;
+	GParamSpec *pspec;
+	GVariant *prop;
+	GDBusPropertyInfo **props_info;
+	char *prop_name;
+
+	g_variant_builder_init(&builder, G_VARIANT_TYPE_ARRAY);
+	props_info = PURPLE_OBJECT_GET_CLASS(pobject)->dbus_ifaceinfo->properties;
+	for (; *props_info; props_info++) {
+		prop_name = (*props_info)->name;
+		if (!prop_name)
+			continue;
+
+		pspec = g_object_class_find_property(G_OBJECT_GET_CLASS(G_OBJECT(pobject)),
+		                                     prop_name);
+		if (!pspec)
+			continue;
+
+		prop = purple_object_get_dbus_property(pobject, prop_name);
+		if (!prop)
+			continue;
+		prop = g_variant_new("(sv)", prop_name, prop);
+		g_variant_builder_add_value(&builder, prop);
+	}
+	return g_variant_builder_end(&builder);
+}
+
+static GVariant*
+pack_account(PurpleAccount *account)
+{
+	PurpleObject *pobj = PURPLE_OBJECT(account);
+	return g_variant_new("(o at a(sv))",
+	                     purple_object_get_dbus_path(pobj),
+	                     pack_pobject_properties(pobj));
+}
+
+/* Unpacks a GVariant-packed account and creates local PurpleAccounts
+ * that will act as proxy objects. */
 static void
-pack_account_prop_cb(char *prop_name, PurpleAccount *acc, GPtrArray *props_pack)
+load_account(GVariant *account)
 {
-	GValue prop = {0, };
-	GValue prop_val = {0, };
-	GValue prop_val2 = {0, };
-	GParamSpec *prop_spec;
-	gboolean ok;
+	PurpleAccount *paccount;
+	GVariant *props;
+	gchar *dbus_path;
 
-	/* Each property consists of a DBUS_STRUCT_PROPERTY */
-	g_value_init(&prop, DBUS_STRUCT_PROPERTY);
-	g_value_take_boxed(&prop, dbus_g_type_specialized_construct(
-			DBUS_STRUCT_PROPERTY));
+	g_variant_get(account, "(o at a(sv))", &dbus_path, &props);
 
-	/* First find out the property GType */
-	prop_spec = g_object_class_find_property(G_OBJECT_GET_CLASS(acc),
-						prop_name);
-	g_return_if_fail(prop_spec != NULL);
-	g_value_init(&prop_val, G_PARAM_SPEC_VALUE_TYPE(prop_spec));
-	/* Then get it */
-	g_object_get_property(G_OBJECT(acc), prop_name,	&prop_val);
+	paccount = purple_constructor_new_proxy_object("PurpleAccount", dbus_path, props);
+	g_variant_unref(props);
 
-	if (G_VALUE_HOLDS_OBJECT(&prop_val)) {
-		/* Convert gobjects into dbus path names. */
-		g_value_init(&prop_val2, G_TYPE_STRING);
-		g_value_transform(&prop_val, &prop_val2);
-	} else {
-		/* Regular value. */
-		g_value_init(&prop_val2, G_VALUE_TYPE(&prop_val));
-		g_value_copy(&prop_val, &prop_val2);
-	}
-	g_value_unset(&prop_val);
+	purple_object_set_dbus_path(PURPLE_OBJECT(paccount), dbus_path);
+	g_free(dbus_path);
 
-	/* Setup the DBus struct, with our extracted data */
-	ok = dbus_g_type_struct_set(&prop,
-				0, prop_name,
-				1, &prop_val2,
-				G_MAXUINT);
-	g_value_unset(&prop_val2);
-	g_return_if_fail(ok == TRUE);
-
-	/* Finally append this fresh struct to the array */
-	g_ptr_array_add(props_pack, g_value_get_boxed(&prop));
+	purple_account_dbus_init(paccount);
+	/* This signal will add our new account in the account list. */
+	g_signal_emit_by_name(G_OBJECT(paccount), "new");
+	purple_object_set_synchronized(PURPLE_OBJECT(paccount), TRUE);	
 }
 
 /**
- * A callback used in DBUS_purple_constructor_get_all_accounts().
- * Packs the given acc account into a { dbus_path, protocol_id, account_struct }
- * dbus structure and append it in accounts_pack.
+ * This is what is actually executed on the daemon side when someone calls
+ * the dbus method GetAllAccounts. It packs the accounts and their properties
+ * in the gdbus data format.
  */
-static void
-pack_accounts_cb(PurpleAccount *acc, GPtrArray *accounts_pack, GPtrArray *exported_props)
+static GVariant*
+purple_constructor_get_all_accounts(void)
 {
-	GValue acc_props = {0, };
-	char *prop_name;
-	GPtrArray* props_pack = g_ptr_array_new();
-	int i;
-	gboolean ok;
+	GVariantBuilder builder;
+	GList *all = purple_accounts_all();;
 
-	g_return_if_fail(props_pack != NULL);
-
-	/* Each account consists of a DBUS_STRUCT_ACCOUNT */
-	g_value_init(&acc_props, DBUS_STRUCT_ACCOUNT);
-	g_value_set_boxed(&acc_props,
-			dbus_g_type_specialized_construct(DBUS_STRUCT_ACCOUNT));
-
-	/* Fill props_pack with every property of acc */
-	for (i = 0; i < exported_props->len; i++) {
-		prop_name = exported_props->pdata[i];
-		pack_account_prop_cb(prop_name, acc, props_pack);
+	/* Pack every account into an array of accounts. */
+	g_variant_builder_init(&builder, G_VARIANT_TYPE_ARRAY);
+	while (all) {
+		PurpleAccount *account = all->data;
+		g_variant_builder_add_value(&builder, pack_account(account));
+		all = all->next;
 	}
-
-	/* Setup the DBus struct, with our extracted data */
-	ok = dbus_g_type_struct_set(&acc_props,
-				0, purple_account_get_protocol_id(acc),
-				1, props_pack,
-				G_MAXUINT);
-	g_ptr_array_foreach(props_pack, (GFunc)g_value_array_free, NULL);
-	g_ptr_array_free(props_pack, TRUE);
-	g_return_if_fail(ok == TRUE);
-
-	/* Finally append this fresh struct to the array */
-	g_ptr_array_add(accounts_pack, g_value_get_boxed(&acc_props));
+	return g_variant_new("(@a(oa(sv)))", g_variant_builder_end(&builder));
 }
 
 /**
- * This is what is actually called when someone calls the dbus method
- * GetAllAccounts. It packs the accounts and their properties in the
- * glib-dbus data format.
+ * This is what a client calls when it wants to call the dbus method
+ * GetAllAccounts. It unpacks the gdbus formatted data and creates proxy
+ * PurpleAccounts.
  */
-gboolean
-DBUS_purple_constructor_get_all_accounts(PurpleConstructor* con, GPtrArray** accounts, GError** error)
-{
-	PurpleAccount *acc;
-	GPtrArray *exported_props = NULL;
-	GList *glist_accs;
-	char *interface;
-
-	/* We send an array of accounts. The complete data format, as
-	 * defined in dbus-constructor.h, is something like :
-	 * GPtrArray *account = [
-	 *     struct {
-	 *         char      *protocol_id; // Needed to properly g_object_new()
-	 *         GPtrArray *properties [
-	 *             struct {
-	 *                char   *property_name;
-	 *                GValue *property_value; 
-	 *             }
-	 *         ];
-	 *     }
-	 * ]
-	 */
-	*accounts = g_ptr_array_new();
-	g_return_val_if_fail(*accounts != NULL, FALSE);
-
-	/* Fill *accounts with every account */
-	glist_accs = purple_accounts_all();
-	for (; glist_accs; glist_accs = glist_accs->next) {
-		acc = glist_accs->data;
-



More information about the Commits mailing list