[Telepathy-commits] [telepathy-glib/master] TpChannel: call GetAll for Channel properties before falling back to the spec-0.16.x-style separate methods
Simon McVittie
simon.mcvittie at collabora.co.uk
Fri Nov 28 07:05:12 PST 2008
---
telepathy-glib/channel.c | 282 ++++++++++++++++++++++++++++++++++++----------
1 files changed, 222 insertions(+), 60 deletions(-)
diff --git a/telepathy-glib/channel.c b/telepathy-glib/channel.c
index bd8e4a6..6775db8 100644
--- a/telepathy-glib/channel.c
+++ b/telepathy-glib/channel.c
@@ -300,11 +300,22 @@ tp_channel_get_property (GObject *object,
}
+/* These functions, maybe_set_whatever, ignore attempts to set a null value.
+ * This means we can indiscriminately set everything from every source
+ * (channel-properties, other construct-time properties, GetAll fast path,
+ * 0.16.x slow path), and if only one of the sources supplied a value, it'll
+ * still all be fine. */
+
+
static void
-_tp_channel_set_channel_type (TpChannel *self,
- GQuark q)
+_tp_channel_maybe_set_channel_type (TpChannel *self,
+ const gchar *type)
{
GValue *value;
+ GQuark q = g_quark_from_string (type);
+
+ if (type == NULL)
+ return;
self->priv->channel_type = q;
value = tp_g_value_slice_new (G_TYPE_STRING);
@@ -315,27 +326,61 @@ _tp_channel_set_channel_type (TpChannel *self,
static void
-_tp_channel_set_interfaces (TpChannel *self,
- const gchar **interfaces)
+_tp_channel_maybe_set_handle (TpChannel *self,
+ TpHandle handle,
+ gboolean valid)
+{
+ if (valid)
+ {
+ GValue *value = tp_g_value_slice_new (G_TYPE_UINT);
+
+ g_value_set_uint (value, handle);
+ self->priv->handle = handle;
+ g_hash_table_insert (self->priv->channel_properties,
+ g_strdup (TP_IFACE_CHANNEL ".TargetHandle"), value);
+ }
+}
+
+
+static void
+_tp_channel_maybe_set_handle_type (TpChannel *self,
+ TpHandleType handle_type,
+ gboolean valid)
+{
+ if (valid)
+ {
+ GValue *value = tp_g_value_slice_new (G_TYPE_UINT);
+
+ g_value_set_uint (value, handle_type);
+ self->priv->handle_type = handle_type;
+ g_hash_table_insert (self->priv->channel_properties,
+ g_strdup (TP_IFACE_CHANNEL ".TargetHandleType"), value);
+ }
+}
+
+
+static void
+_tp_channel_maybe_set_interfaces (TpChannel *self,
+ const gchar **interfaces)
{
GValue *value;
const gchar **iter;
- if (interfaces != NULL)
+ if (interfaces == NULL)
+ return;
+
+ for (iter = interfaces; *iter != NULL; iter++)
{
- for (iter = interfaces; *iter != NULL; iter++)
- {
- DEBUG ("- %s", *iter);
+ DEBUG ("- %s", *iter);
- if (tp_dbus_check_valid_interface_name (*iter, NULL))
- {
- GQuark q = g_quark_from_string (*iter);
- tp_proxy_add_interface_by_id ((TpProxy *) self, q);
- }
- else
- {
- DEBUG ("\tInterface %s not valid, ignoring it", *iter);
- }
+ if (tp_dbus_check_valid_interface_name (*iter, NULL))
+ {
+ GQuark q = g_quark_from_string (*iter);
+ tp_proxy_add_interface_by_id ((TpProxy *) self, q);
+ }
+ else
+ {
+ DEBUG ("\tInterface %s not valid, ignoring it", *iter);
}
}
@@ -362,35 +407,17 @@ tp_channel_set_property (GObject *object,
break;
case PROP_CHANNEL_TYPE:
- _tp_channel_set_channel_type (self,
- g_quark_from_string (g_value_get_string (value)));
+ _tp_channel_maybe_set_channel_type (self, g_value_get_string (value));
break;
case PROP_HANDLE_TYPE:
- {
- guint new_value = g_value_get_uint (value);
-
- /* An unfortunate collision between the default value in
- * TpChannelIface (0), and the default we want (-1), means that
- * we have to pass TP_UNKNOWN_HANDLE_TYPE to the constructor
- * explicitly, even if providing channel-properties. We don't
- * want an unknown value from handle-type to override a known value
- * from channel-properties. */
- if (new_value != TP_UNKNOWN_HANDLE_TYPE)
- {
- self->priv->handle_type = new_value;
- g_hash_table_insert (self->priv->channel_properties,
- g_strdup (TP_IFACE_CHANNEL ".TargetHandleType"),
- tp_g_value_slice_dup (value));
- }
- }
+ _tp_channel_maybe_set_handle_type (self, g_value_get_uint (value),
+ (g_value_get_uint (value) != TP_UNKNOWN_HANDLE_TYPE));
break;
case PROP_HANDLE:
- self->priv->handle = g_value_get_uint (value);
- g_hash_table_insert (self->priv->channel_properties,
- g_strdup (TP_IFACE_CHANNEL ".TargetHandle"),
- tp_g_value_slice_dup (value));
+ _tp_channel_maybe_set_handle (self, g_value_get_uint (value),
+ (g_value_get_uint (value) != 0));
break;
case PROP_CHANNEL_PROPERTIES:
@@ -401,31 +428,25 @@ tp_channel_set_property (GObject *object,
/* default value at construct time is NULL, we need to ignore that */
if (asv != NULL)
{
+ guint u;
+
tp_g_hash_table_update (self->priv->channel_properties,
asv, (GBoxedCopyFunc) g_strdup,
(GBoxedCopyFunc) tp_g_value_slice_dup);
- self->priv->handle_type = tp_asv_get_uint32 (
- self->priv->channel_properties,
+ u = tp_asv_get_uint32 (self->priv->channel_properties,
TP_IFACE_CHANNEL ".TargetHandleType", &valid);
+ _tp_channel_maybe_set_handle_type (self, u, valid);
- /* 0 is not actually the correct "unknown" value here, so
- * correct for it */
- if (!valid)
- {
- self->priv->handle_type = TP_UNKNOWN_HANDLE_TYPE;
- }
-
- self->priv->handle = tp_asv_get_uint32 (
- self->priv->channel_properties,
- TP_IFACE_CHANNEL ".TargetHandle", NULL);
+ u = tp_asv_get_uint32 (self->priv->channel_properties,
+ TP_IFACE_CHANNEL ".TargetHandle", &valid);
+ _tp_channel_maybe_set_handle (self, u, valid);
- _tp_channel_set_channel_type (self,
- g_quark_from_string (tp_asv_get_string (
- self->priv->channel_properties,
- TP_IFACE_CHANNEL ".ChannelType")));
+ _tp_channel_maybe_set_channel_type (self,
+ tp_asv_get_string (self->priv->channel_properties,
+ TP_IFACE_CHANNEL ".ChannelType"));
- _tp_channel_set_interfaces (self,
+ _tp_channel_maybe_set_interfaces (self,
tp_asv_get_boxed (self->priv->channel_properties,
TP_IFACE_CHANNEL ".Interfaces",
G_TYPE_STRV));
@@ -494,7 +515,7 @@ tp_channel_got_interfaces_cb (TpChannel *self,
return;
}
- _tp_channel_set_interfaces (self, interfaces);
+ _tp_channel_maybe_set_interfaces (self, interfaces);
/* FIXME: give subclasses a chance to influence the definition of "ready"
* now that we have our interfaces? */
@@ -529,7 +550,7 @@ tp_channel_got_channel_type_cb (TpChannel *self,
else if (tp_dbus_check_valid_interface_name (channel_type, &err2))
{
DEBUG ("%p: Introspected channel type %s", self, channel_type);
- _tp_channel_set_channel_type (self, g_quark_from_string (channel_type));
+ _tp_channel_maybe_set_channel_type (self, channel_type);
g_object_notify ((GObject *) self, "channel-type");
tp_proxy_add_interface_by_id ((TpProxy *) self,
@@ -626,6 +647,135 @@ _tp_channel_get_handle (TpChannel *self)
static void
+_tp_channel_got_properties (TpProxy *proxy,
+ GHashTable *asv,
+ const GError *error,
+ gpointer unused G_GNUC_UNUSED,
+ GObject *object G_GNUC_UNUSED)
+{
+ TpChannel *self = TP_CHANNEL (proxy);
+
+ if (error == NULL)
+ {
+ GValue *value;
+ gboolean valid;
+ guint u;
+ const gchar *s;
+ gboolean b;
+
+ DEBUG ("Received %u channel properties", g_hash_table_size (asv));
+
+ _tp_channel_maybe_set_channel_type (self,
+ tp_asv_get_string (asv, "ChannelType"));
+ _tp_channel_maybe_set_interfaces (self,
+ tp_asv_get_boxed (asv, "Interfaces", G_TYPE_STRV));
+
+ u = tp_asv_get_uint32 (asv, "TargetHandleType", &valid);
+ _tp_channel_maybe_set_handle_type (self, u, valid);
+
+ u = tp_asv_get_uint32 (asv, "TargetHandle", &valid);
+ _tp_channel_maybe_set_handle (self, u, valid);
+
+ s = tp_asv_get_string (asv, "TargetID");
+
+ if (s != NULL)
+ {
+ value = tp_g_value_slice_new (G_TYPE_STRING);
+ g_value_set_string (value, s);
+ g_hash_table_insert (self->priv->channel_properties,
+ g_strdup (TP_IFACE_CHANNEL ".TargetID"), value);
+ }
+
+ u = tp_asv_get_uint32 (asv, "InitiatorHandle", &valid);
+
+ if (valid)
+ {
+ value = tp_g_value_slice_new (G_TYPE_UINT);
+ g_value_set_uint (value, u);
+ g_hash_table_insert (self->priv->channel_properties,
+ g_strdup (TP_IFACE_CHANNEL ".InitiatorHandle"), value);
+ }
+
+ s = tp_asv_get_string (asv, "InitiatorID");
+
+ if (s != NULL)
+ {
+ value = tp_g_value_slice_new (G_TYPE_STRING);
+ g_value_set_string (value, s);
+ g_hash_table_insert (self->priv->channel_properties,
+ g_strdup (TP_IFACE_CHANNEL ".InitiatorID"), value);
+ }
+
+ b = tp_asv_get_boolean (asv, "Requested", &valid);
+
+ if (valid)
+ {
+ value = tp_g_value_slice_new (G_TYPE_BOOLEAN);
+ g_value_set_boolean (value, b);
+ g_hash_table_insert (self->priv->channel_properties,
+ g_strdup (TP_IFACE_CHANNEL ".Requested"), value);
+ }
+
+ g_object_notify ((GObject *) self, "channel-type");
+ g_object_notify ((GObject *) self, "handle-type");
+ g_object_notify ((GObject *) self, "handle");
+ }
+ else
+ {
+ /* GetAll failed; it's not mandatory, so continue with the separate
+ * (spec 0.16.x-style) method calls */
+ DEBUG ("GetAll failed, falling back to 0.16 API:"
+ " %s", error->message);
+ }
+
+ /* Either way, we'll fill in any other gaps in the properties, then
+ * continue with any other introspection */
+ _tp_channel_continue_introspection (self);
+}
+
+
+static void
+_tp_channel_get_properties (TpChannel *self)
+{
+ /* skip it if we already have all the details we want */
+ if (self->priv->handle_type != TP_UNKNOWN_HANDLE_TYPE
+ && (self->priv->handle != 0 ||
+ self->priv->handle_type == TP_HANDLE_TYPE_NONE)
+ && self->priv->channel_type != 0
+ /* currently we always re-fetch the interfaces later, so don't check:
+ && tp_asv_get_boxed (self->priv->channel_properties,
+ TP_IFACE_CHANNEL ".Interfaces", G_TYPE_STRV) != NULL
+ */
+ && tp_asv_get_string (self->priv->channel_properties,
+ TP_IFACE_CHANNEL ".TargetID") != NULL
+ && tp_asv_get_string (self->priv->channel_properties,
+ TP_IFACE_CHANNEL ".InitiatorID") != NULL
+ )
+ {
+ gboolean valid;
+
+ tp_asv_get_uint32 (self->priv->channel_properties, "InitiatorHandle",
+ &valid);
+
+ if (!valid)
+ goto missing;
+
+ tp_asv_get_boolean (self->priv->channel_properties, "Requested", &valid);
+
+ if (!valid)
+ goto missing;
+
+ _tp_channel_continue_introspection (self);
+ return;
+ }
+
+missing:
+ tp_cli_dbus_properties_call_get_all (self, -1,
+ TP_IFACE_CHANNEL, _tp_channel_got_properties, NULL, NULL, NULL);
+}
+
+
+static void
tp_channel_closed_cb (TpChannel *self,
gpointer user_data,
GObject *weak_object)
@@ -700,6 +850,11 @@ tp_channel_constructor (GType type,
self->priv->introspect_needed = g_queue_new ();
+ /* this does nothing if we already know all the Channel properties this
+ * code is aware of */
+ g_queue_push_tail (self->priv->introspect_needed,
+ _tp_channel_get_properties);
+
/* this does nothing if we already know the handle */
g_queue_push_tail (self->priv->introspect_needed,
_tp_channel_get_handle);
@@ -708,7 +863,9 @@ tp_channel_constructor (GType type,
g_queue_push_tail (self->priv->introspect_needed,
_tp_channel_get_channel_type);
- /* currently this always runs, regardless of anything else */
+ /* currently this always runs, regardless of anything else;
+ * this means the channel never becomes ready until we re-enter the
+ * main loop, and we always verify that the channel does actually exist */
g_queue_push_tail (self->priv->introspect_needed,
_tp_channel_get_interfaces);
@@ -1051,6 +1208,11 @@ tp_channel_new_from_properties (TpConnection *conn,
if (!tp_dbus_check_valid_object_path (object_path, error))
goto finally;
+ /* An unfortunate collision between the default value in
+ * TpChannelIface (0), and the default we want (-1), means that
+ * we have to pass TP_UNKNOWN_HANDLE_TYPE to the constructor
+ * explicitly, even if providing channel-properties. */
+
ret = TP_CHANNEL (g_object_new (TP_TYPE_CHANNEL,
"connection", conn,
"dbus-daemon", conn_proxy->dbus_daemon,
--
1.5.6.5
More information about the Telepathy-commits
mailing list