/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(¶ms[i].value, G_TYPE_OBJECT);
+ g_value_set_object(¶ms[i].value, obj);
+ } else {
+ g_dbus_gvariant_to_gvalue(prop_value, ¶ms[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(¶ms[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