cpw.gillux.detachablepurple: f53ace82: Rewritten the GetAllAccounts D-Bus metho...
gillux at soc.pidgin.im
gillux at soc.pidgin.im
Sat May 12 16:56:48 EDT 2012
----------------------------------------------------------------------
Revision: f53ace8239cc403b8c3b0f96ea236cdf2eb3f123
Parent: d463ee6521874098ff99fcd5585b9ed4ae453739
Author: gillux at soc.pidgin.im
Date: 05/12/12 16:13:24
Branch: im.pidgin.cpw.gillux.detachablepurple
URL: http://d.pidgin.im/viewmtn/revision/info/f53ace8239cc403b8c3b0f96ea236cdf2eb3f123
Changelog:
Rewritten the GetAllAccounts D-Bus method implementation of
PurpleConstructor. It's now GVariant-based, simpler and cleaner. :-)
Changes against parent d463ee6521874098ff99fcd5585b9ed4ae453739
patched libpurple/dbus/constructor.c
patched libpurple/dbus/constructor.xml
-------------- next part --------------
============================================================
--- libpurple/dbus/constructor.c 1380e91ead82f2ac7053453f30fca9072c48dd88
+++ libpurple/dbus/constructor.c c23b1c484d68df283c332481d25003b7da7fe34f
@@ -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_
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 @@ static void purple_constructor_class_ini
/* 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 @@ DBUS_purple_constructor_new_account(Purp
}
}
-/**
- * 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 void
-pack_account_prop_cb(char *prop_name, PurpleAccount *acc, GPtrArray *props_pack)
+static gpointer
+purple_constructor_new_proxy_object(gchar *type_name, char *dbus_path, GVariant *props)
{
- GValue prop = {0, };
- GValue prop_val = {0, };
- GValue prop_val2 = {0, };
- GParamSpec *prop_spec;
- gboolean ok;
+ GType type;
+ GParameter *params;
+ guint n_params, i = 0;
+ GVariantIter iter;
+ GVariant *prop;
+ const gchar *prop_name;
+ GVariant *prop_value;
+ gpointer object;
- /* 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));
+ /* Retreive the type. */
+ type = g_type_from_name(type_name);
+ g_return_val_if_fail(type != 0, NULL);
- /* 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);
+ /* 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;
- 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);
+ /* 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);
}
- g_value_unset(&prop_val);
- /* 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);
+ /* Create this object with the given properties. */
+ object = g_object_newv(type, n_params, params);
- /* Finally append this fresh struct to the array */
- g_ptr_array_add(props_pack, g_value_get_boxed(&prop));
+ /* 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;
}
-/**
- * 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.
- */
-static void
-pack_accounts_cb(PurpleAccount *acc, GPtrArray *accounts_pack, GPtrArray *exported_props)
+/* Packs all the exported properties of a PurpleObject into an a(sv) GVariant. */
+static GVariant*
+pack_pobject_properties(PurpleObject *pobject)
{
- GValue acc_props = {0, };
+ GVariantBuilder builder;
+ GParamSpec *pspec;
+ GVariant *prop;
+ GDBusPropertyInfo **props_info;
char *prop_name;
- GPtrArray* props_pack = g_ptr_array_new();
- int i;
- gboolean ok;
- g_return_if_fail(props_pack != NULL);
+ 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;
- /* 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));
+ pspec = g_object_class_find_property(G_OBJECT_GET_CLASS(G_OBJECT(pobject)),
+ prop_name);
+ if (!pspec)
+ continue;
- /* 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);
+ 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);
}
-
- /* 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_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.
- */
-gboolean
-DBUS_purple_constructor_get_all_accounts(PurpleConstructor* con, GPtrArray** accounts, GError** error)
+static GVariant*
+pack_account(PurpleAccount *account)
{
- 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;
-
- if (!exported_props) {
- /* Grab all the properties names */
- interface = purple_object_get_dbus_obj_interface(PURPLE_OBJECT(acc));
- exported_props = purple_object_get_dbus_props(
- PURPLE_TYPE_ACCOUNT, interface);
-
- }
- pack_accounts_cb(acc, *accounts, exported_props);
- }
- g_ptr_array_foreach(exported_props, (GFunc)g_free, NULL);
- g_ptr_array_free(exported_props, TRUE);
-
- return TRUE;
+ PurpleObject *pobj = PURPLE_OBJECT(account);
+ return g_variant_new("(o at a(sv))",
+ purple_object_get_dbus_path(pobj),
+ pack_pobject_properties(pobj));
}
-/**
- * A callback used in load_accounts_cb().
- * Unpacks the { prop_name, prop_gvalue } dbus structure and set
- * the prop_name property in the given account.
- */
+/* Unpacks a GVariant-packed account and creates local PurpleAccounts
+ * that will act as proxy objects. */
static void
-load_account_prop_cb(GValueArray* box, PurpleAccount* account)
+load_account(GVariant *account)
{
- char* prop_name;
- GValue value_box = {0, };
- GValue *prop_val;
- GValue prop_val2 = {0, };
- GParamSpec *pspec;
+ PurpleAccount *paccount;
+ GVariant *props;
+ gchar *dbus_path;
- /* Each property consists of a DBUS_STRUCT_PROPERTY */
- g_value_init(&value_box, DBUS_STRUCT_PROPERTY);
- g_value_set_boxed(&value_box, box);
+ g_variant_get(account, "(o at a(sv))", &dbus_path, &props);
- dbus_g_type_struct_get(&value_box, 0, &prop_name, 1, &prop_val,
- G_MAXUINT);
+ paccount = purple_constructor_new_proxy_object("PurpleAccount", dbus_path, props);
+ g_variant_unref(props);
- pspec = g_object_class_find_property(G_OBJECT_GET_CLASS(account),
- prop_name);
- g_value_init(&prop_val2, G_PARAM_SPEC_VALUE_TYPE(pspec));
- if (G_TYPE_IS_OBJECT(G_PARAM_SPEC_VALUE_TYPE(pspec))
- && G_VALUE_HOLDS_STRING(prop_val)) {
- /* Convert dbus path names into gobjects. */
- g_value_transform(prop_val, &prop_val2);
- } else {
- /* Regular value. */
- g_value_copy(prop_val, &prop_val2);
- }
- g_object_set_property(G_OBJECT(account), prop_name, prop_val);
+ purple_object_set_dbus_path(PURPLE_OBJECT(paccount), dbus_path);
+ g_free(dbus_path);
- g_free(prop_name);
- g_value_unset(&value_box);
- g_value_unset(prop_val);
+ 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 helper function used in DBUS_purple_constructor_get_all_accounts().
- * Finds a property named prop_name in prop_array array of structs.
+ * 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 GValue*
-get_prop_by_name(GPtrArray *prop_array, char *prop_name)
+static GVariant*
+purple_constructor_get_all_accounts(void)
{
- int i;
- GValue val = {0, };
- GValue value_box = {0, };
+ GVariantBuilder builder;
+ GList *all = purple_accounts_all();;
- g_value_init(&value_box, DBUS_STRUCT_PROPERTY);
- g_value_init(&val, G_TYPE_STRING);
-
- for (i = 0; i < prop_array->len; i++) {
- g_value_set_boxed(&value_box, prop_array->pdata[i]);
- dbus_g_type_struct_get_member(&value_box, 0, &val);
- if (purple_strequal(g_value_get_string(&val), prop_name)) {
- g_value_unset(&val);
- g_value_init(&val, G_TYPE_VALUE);
- dbus_g_type_struct_get_member(&value_box, 1, &val);
- g_value_unset(&value_box);
- return g_value_get_boxed(&val);
- }
+ /* 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;
}
- g_value_unset(&value_box);
- return NULL;
+ return g_variant_new("(@a(oa(sv)))", g_variant_builder_end(&builder));
}
/**
- * A callback used in purple_accounts_get_all_RPC().
- * Unpacks the { dbus_path, protocol_id, account_struct } dbus structure and construct
- * a new account based on these informations.
+ * 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.
*/
-static void
-load_accounts_cb(GValueArray* box)
-{
- GValue val = {0, };
- PurpleAccount *acc;
- char *protocol_id;
- GPtrArray *prop_array;
- GValue *username;
- PurpleRunningMode mode;
-
- /* Each account consists of a DBUS_STRUCT_ACCOUNT */
- g_value_init(&val, DBUS_STRUCT_ACCOUNT);
- g_value_set_boxed(&val, box);
- dbus_g_type_struct_get(&val,
- 0, &protocol_id, 1, &prop_array, G_MAXUINT);
-
- /* First get the username, it is needed to construct the account */
- username = get_prop_by_name(prop_array, "username");
- if (!username) {
- purple_debug_warning("dbus",
- "Couldn't load the account: username not found\n");
- return;
- }
- /* Temporarly go in mirror mode, and it will create a local account */
- mode = purple_core_get_running_mode();
- purple_core_set_running_mode(PURPLE_RUN_MIRROR_MODE);
- acc = purple_account_new(g_value_get_string(username), protocol_id);
-
- /* Then load the others properties. Keep the mirror mode here,
- * otherwise it will try to remotely set the properties.
- */
- g_ptr_array_foreach(prop_array, (GFunc)load_account_prop_cb, acc);
- purple_core_set_running_mode(mode);
-
- g_free(protocol_id);
- g_value_unset(username);
- g_ptr_array_free(prop_array, TRUE);
- g_value_unset(&val);
- g_value_array_free(box);
-}
-
void
purple_accounts_get_all_RPC(void)
{
PurpleConstructor* con = purple_constructor_get_instance();
- DBusGProxy *proxy = purple_object_get_dbus_obj_proxy(PURPLE_OBJECT(con));
- GError *error = NULL;
- GPtrArray* accounts;
+ GVariant *ret, *accounts, *account;
+ GVariantIter iter;
- /* In remote mode accounts are already loaded by the daemon.
- * We need to get those here.
- */
- if(!im_pidgin_purple_constructor_get_all_accounts(proxy, &accounts, &error)) {
- PURPLE_RPC_FAILED(purple_constructor_get_all_accounts, error);
- return;
+ /* Download all the accounts. */
+ ret = purple_object_dbus_call(PURPLE_OBJECT(con), "GetAllAccounts");
+ g_variant_get(ret, "(@a(oa(sv)))", &accounts);
+
+ /* Unpack all this data. */
+ g_variant_iter_init(&iter, accounts);
+ while ((account = g_variant_iter_next_value(&iter)) != NULL) {
+ load_account(account);
+ g_variant_unref(account);
}
-
- g_ptr_array_foreach(accounts, (GFunc)load_accounts_cb, NULL);
- purple_debug_info("dbus",
- "Loaded %i remote account(s).\n", accounts->len);
-
- g_ptr_array_free(accounts, TRUE);
+ purple_debug_info("dbus", "Loaded %d accounts.\n", g_variant_n_children(accounts));
+ g_variant_unref(accounts);
}
============================================================
--- libpurple/dbus/constructor.xml 89633f956f700cee79554af90843fcbcc5802810
+++ libpurple/dbus/constructor.xml cc0ef12d7ab746dee94647f3630be6b242af8ff5
@@ -8,7 +8,7 @@
<arg type="s" name="protocol_id" direction="in" />
</method>
<method name="GetAllAccounts">
- <arg type="a(sa(sv))" name="accounts" direction="out" />
+ <arg type="a(oa(sv))" name="accounts" direction="out" />
</method>
<signal name="PurpleConnectionCreated">
More information about the Commits
mailing list