[Telepathy-commits] [telepathy-glib/master] TpChannel: add tp_channel_new_from_properties (fd.o #17427) and tp_channel_borrow_immutable_properties
Simon McVittie
simon.mcvittie at collabora.co.uk
Fri Nov 28 07:05:13 PST 2008
---
telepathy-glib/channel-internal.h | 2 +
telepathy-glib/channel.c | 286 ++++++++++++++++++++++++++++++++----
telepathy-glib/channel.h | 5 +
3 files changed, 261 insertions(+), 32 deletions(-)
diff --git a/telepathy-glib/channel-internal.h b/telepathy-glib/channel-internal.h
index 3a07beb..bc0eeb1 100644
--- a/telepathy-glib/channel-internal.h
+++ b/telepathy-glib/channel-internal.h
@@ -45,6 +45,8 @@ struct _TpChannelPrivate {
GQuark channel_type;
TpHandleType handle_type;
TpHandle handle;
+ /* owned string (iface + "." + prop) => slice-allocated GValue */
+ GHashTable *channel_properties;
TpHandle group_self_handle;
TpChannelGroupFlags group_flags;
diff --git a/telepathy-glib/channel.c b/telepathy-glib/channel.c
index de1531b..bd8e4a6 100644
--- a/telepathy-glib/channel.c
+++ b/telepathy-glib/channel.c
@@ -23,8 +23,10 @@
#include <telepathy-glib/channel-iface.h>
#include <telepathy-glib/dbus.h>
+#include <telepathy-glib/gtypes.h>
#include <telepathy-glib/interfaces.h>
#include <telepathy-glib/proxy-subclass.h>
+#include <telepathy-glib/util.h>
#define DEBUG_FLAG TP_DEBUG_CHANNEL
#include "telepathy-glib/debug-internal.h"
@@ -83,6 +85,7 @@ enum
PROP_HANDLE_TYPE,
PROP_HANDLE,
PROP_CHANNEL_READY,
+ PROP_CHANNEL_PROPERTIES,
PROP_GROUP_SELF_HANDLE,
PROP_GROUP_FLAGS,
N_PROPS
@@ -223,6 +226,38 @@ tp_channel_borrow_connection (TpChannel *self)
}
+/**
+ * tp_channel_borrow_immutable_properties:
+ * @self: a channel
+ *
+ * Returns the immutable D-Bus properties of this channel, the same as
+ * #TpChannel:channel-properties.
+ *
+ * The returned hash table should not be altered, and is not necessarily
+ * valid after the main loop is next re-entered. Copy it with
+ * g_boxed_copy() (its type is %TP_HASH_TYPE_QUALIFIED_PROPERTY_VALUE_MAP)
+ * if a copy that remains valid must be kept.
+ *
+ * If the #TpChannel:channel-properties property was not set during
+ * construction (e.g. by calling tp_channel_new_from_properties()), a
+ * reasonable but possibly incomplete version will be made up from the values
+ * of individual properties; reading this property repeatedly may yield
+ * progressively more complete values until #TpChannel:channel-ready
+ * becomes %TRUE.
+ *
+ * Returns: a #GHashTable where the keys are strings,
+ * D-Bus interface name + "." + property name, and the values are #GValue
+ * instances
+ */
+GHashTable *
+tp_channel_borrow_immutable_properties (TpChannel *self)
+{
+ g_return_val_if_fail (TP_IS_CHANNEL (self), NULL);
+
+ return self->priv->channel_properties;
+}
+
+
static void
tp_channel_get_property (GObject *object,
guint property_id,
@@ -249,6 +284,9 @@ tp_channel_get_property (GObject *object,
case PROP_HANDLE:
g_value_set_uint (value, self->priv->handle);
break;
+ case PROP_CHANNEL_PROPERTIES:
+ g_value_set_boxed (value, self->priv->channel_properties);
+ break;
case PROP_GROUP_SELF_HANDLE:
g_value_set_uint (value, self->priv->group_self_handle);
break;
@@ -261,6 +299,54 @@ tp_channel_get_property (GObject *object,
}
}
+
+static void
+_tp_channel_set_channel_type (TpChannel *self,
+ GQuark q)
+{
+ GValue *value;
+
+ self->priv->channel_type = q;
+ value = tp_g_value_slice_new (G_TYPE_STRING);
+ g_value_set_static_string (value, g_quark_to_string (q));
+ g_hash_table_insert (self->priv->channel_properties,
+ g_strdup (TP_IFACE_CHANNEL ".ChannelType"), value);
+}
+
+
+static void
+_tp_channel_set_interfaces (TpChannel *self,
+ const gchar **interfaces)
+{
+ GValue *value;
+ const gchar **iter;
+
+ if (interfaces != NULL)
+ {
+ for (iter = interfaces; *iter != NULL; 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);
+ }
+ }
+ }
+
+ value = tp_g_value_slice_new (G_TYPE_STRV);
+ g_value_set_boxed (value, interfaces);
+ g_hash_table_insert (self->priv->channel_properties,
+ g_strdup (TP_IFACE_CHANNEL ".Interfaces"),
+ value);
+}
+
+
static void
tp_channel_set_property (GObject *object,
guint property_id,
@@ -274,17 +360,77 @@ tp_channel_set_property (GObject *object,
case PROP_CONNECTION:
self->priv->connection = TP_CONNECTION (g_value_dup_object (value));
break;
+
case PROP_CHANNEL_TYPE:
- /* can only be set in constructor */
- g_assert (self->priv->channel_type == 0);
- self->priv->channel_type = g_quark_from_string (g_value_get_string (
- value));
+ _tp_channel_set_channel_type (self,
+ g_quark_from_string (g_value_get_string (value)));
break;
+
case PROP_HANDLE_TYPE:
- self->priv->handle_type = g_value_get_uint (value);
+ {
+ 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));
+ }
+ }
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));
+ break;
+
+ case PROP_CHANNEL_PROPERTIES:
+ {
+ GHashTable *asv = g_value_get_boxed (value);
+ gboolean valid;
+
+ /* default value at construct time is NULL, we need to ignore that */
+ if (asv != NULL)
+ {
+ 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,
+ TP_IFACE_CHANNEL ".TargetHandleType", &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);
+
+ _tp_channel_set_channel_type (self,
+ g_quark_from_string (tp_asv_get_string (
+ self->priv->channel_properties,
+ TP_IFACE_CHANNEL ".ChannelType")));
+
+ _tp_channel_set_interfaces (self,
+ tp_asv_get_boxed (self->priv->channel_properties,
+ TP_IFACE_CHANNEL ".Interfaces",
+ G_TYPE_STRV));
+ }
+ }
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -313,6 +459,8 @@ _tp_channel_abort_introspection (TpChannel *self,
void
_tp_channel_continue_introspection (TpChannel *self)
{
+ DEBUG ("%p", self);
+
g_assert (self->priv->introspect_needed != NULL);
if (g_queue_peek_head (self->priv->introspect_needed) == NULL)
@@ -346,31 +494,7 @@ tp_channel_got_interfaces_cb (TpChannel *self,
return;
}
- if (interfaces != NULL)
- {
- const gchar **iter;
-
- for (iter = interfaces; *iter != NULL; 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);
-
- if (q == TP_IFACE_QUARK_CHANNEL_INTERFACE_GROUP)
- {
- g_queue_push_tail (self->priv->introspect_needed,
- _tp_channel_get_group_properties);
- }
- }
- else
- {
- DEBUG ("\tInterface %s not valid, ignoring it", *iter);
- }
- }
- }
+ _tp_channel_set_interfaces (self, interfaces);
/* FIXME: give subclasses a chance to influence the definition of "ready"
* now that we have our interfaces? */
@@ -382,6 +506,8 @@ tp_channel_got_interfaces_cb (TpChannel *self,
static void
_tp_channel_get_interfaces (TpChannel *self)
{
+ DEBUG ("%p", self);
+
tp_cli_channel_call_get_interfaces (self, -1,
tp_channel_got_interfaces_cb, NULL, NULL, NULL);
}
@@ -403,7 +529,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);
- self->priv->channel_type = g_quark_from_string (channel_type);
+ _tp_channel_set_channel_type (self, g_quark_from_string (channel_type));
g_object_notify ((GObject *) self, "channel-type");
tp_proxy_add_interface_by_id ((TpProxy *) self,
@@ -425,11 +551,14 @@ _tp_channel_get_channel_type (TpChannel *self)
{
if (self->priv->channel_type == 0)
{
+ DEBUG ("%p: calling GetChannelType", self);
tp_cli_channel_call_get_channel_type (self, -1,
tp_channel_got_channel_type_cb, NULL, NULL, NULL);
}
else
{
+ DEBUG ("%p: channel type %s already determined", self,
+ g_quark_to_string (self->priv->channel_type));
tp_proxy_add_interface_by_id ((TpProxy *) self,
self->priv->channel_type);
_tp_channel_continue_introspection (self);
@@ -447,10 +576,23 @@ tp_channel_got_handle_cb (TpChannel *self,
{
if (error == NULL)
{
+ GValue *value;
+
DEBUG ("%p: Introspected handle #%d of type %d", self, handle,
handle_type);
self->priv->handle_type = handle_type;
self->priv->handle = handle;
+
+ value = tp_g_value_slice_new (G_TYPE_UINT);
+ g_value_set_uint (value, handle_type);
+ g_hash_table_insert (self->priv->channel_properties,
+ g_strdup (TP_IFACE_CHANNEL ".TargetHandleType"), value);
+
+ value = tp_g_value_slice_new (G_TYPE_UINT);
+ g_value_set_uint (value, handle);
+ g_hash_table_insert (self->priv->channel_properties,
+ g_strdup (TP_IFACE_CHANNEL ".TargetHandle"), value);
+
g_object_notify ((GObject *) self, "handle-type");
g_object_notify ((GObject *) self, "handle");
@@ -470,11 +612,14 @@ _tp_channel_get_handle (TpChannel *self)
|| (self->priv->handle == 0 &&
self->priv->handle_type != TP_HANDLE_TYPE_NONE))
{
+ DEBUG ("%p: calling GetHandle", self);
tp_cli_channel_call_get_handle (self, -1,
tp_channel_got_handle_cb, NULL, NULL, NULL);
}
else
{
+ DEBUG ("%p: handle already known to be %u of type %u", self,
+ self->priv->handle, self->priv->handle_type);
_tp_channel_continue_introspection (self);
}
}
@@ -555,14 +700,21 @@ tp_channel_constructor (GType type,
self->priv->introspect_needed = g_queue_new ();
+ /* this does nothing if we already know the handle */
+ g_queue_push_tail (self->priv->introspect_needed,
+ _tp_channel_get_handle);
+
+ /* this does nothing if we already know the channel type */
g_queue_push_tail (self->priv->introspect_needed,
_tp_channel_get_channel_type);
+ /* currently this always runs, regardless of anything else */
g_queue_push_tail (self->priv->introspect_needed,
_tp_channel_get_interfaces);
+ /* this needs doing *after* GetInterfaces so we know whether we're a group */
g_queue_push_tail (self->priv->introspect_needed,
- _tp_channel_get_handle);
+ _tp_channel_get_group_properties);
_tp_channel_continue_introspection (self);
@@ -579,6 +731,8 @@ tp_channel_init (TpChannel *self)
self->priv->channel_type = 0;
self->priv->handle_type = TP_UNKNOWN_HANDLE_TYPE;
self->priv->handle = 0;
+ self->priv->channel_properties = g_hash_table_new_full (g_str_hash,
+ g_str_equal, g_free, (GDestroyNotify) tp_g_value_slice_free);
}
static void
@@ -646,6 +800,9 @@ tp_channel_finalize (GObject *object)
self->priv->introspect_needed = NULL;
}
+ g_assert (self->priv->channel_properties != NULL);
+ g_hash_table_destroy (self->priv->channel_properties);
+
((GObjectClass *) tp_channel_parent_class)->finalize (object);
}
@@ -712,6 +869,27 @@ tp_channel_class_init (TpChannelClass *klass)
"handle");
/**
+ * TpChannel:channel-properties:
+ *
+ * The immutable D-Bus properties of this channel, represented by a
+ * #GHashTable where the keys are D-Bus interface name + "." + property
+ * name, and the values are #GValue instances.
+ *
+ * Read-only except during construction. If this is not provided
+ * during construction, a reasonable (but possibly incomplete) version
+ * will be made up from the values of individual properties; reading this
+ * property repeatedly may yield progressively more complete values until
+ * #TpChannel:channel-ready becomes %TRUE.
+ */
+ param_spec = g_param_spec_boxed ("channel-properties",
+ "Immutable D-Bus properties",
+ "A map D-Bus interface + \".\" + property name => GValue",
+ TP_HASH_TYPE_QUALIFIED_PROPERTY_VALUE_MAP,
+ G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (object_class, PROP_CHANNEL_PROPERTIES,
+ param_spec);
+
+ /**
* TpChannel:channel-ready:
*
* Initially %FALSE; changes to %TRUE when introspection of the channel
@@ -842,6 +1020,50 @@ tp_channel_class_init (TpChannelClass *klass)
G_TYPE_UINT);
}
+
+/**
+ * tp_channel_new_from_properties:
+ * @conn: a connection; may not be %NULL
+ * @object_path: the object path of the channel; may not be %NULL
+ * @immutable_properties: the immutable properties of the channel,
+ * as signalled by the NewChannel D-Bus signal or returned by the
+ * CreateChannel and EnsureChannel D-Bus methods: a mapping from
+ * strings (D-Bus interface name + "." + property name) to #GValue instances
+ * @error: used to indicate the error if %NULL is returned
+ *
+ * <!-- -->
+ *
+ * Returns: a new channel proxy, or %NULL on invalid arguments
+ */
+TpChannel *
+tp_channel_new_from_properties (TpConnection *conn,
+ const gchar *object_path,
+ const GHashTable *immutable_properties,
+ GError **error)
+{
+ TpProxy *conn_proxy = (TpProxy *) conn;
+ TpChannel *ret = NULL;
+
+ g_return_val_if_fail (TP_IS_CONNECTION (conn), NULL);
+ g_return_val_if_fail (object_path != NULL, NULL);
+ g_return_val_if_fail (immutable_properties != NULL, NULL);
+
+ if (!tp_dbus_check_valid_object_path (object_path, error))
+ goto finally;
+
+ ret = TP_CHANNEL (g_object_new (TP_TYPE_CHANNEL,
+ "connection", conn,
+ "dbus-daemon", conn_proxy->dbus_daemon,
+ "bus-name", conn_proxy->bus_name,
+ "object-path", object_path,
+ "handle-type", (guint) TP_UNKNOWN_HANDLE_TYPE,
+ "channel-properties", immutable_properties,
+ NULL));
+
+finally:
+ return ret;
+}
+
/**
* tp_channel_new:
* @conn: a connection; may not be %NULL
diff --git a/telepathy-glib/channel.h b/telepathy-glib/channel.h
index 0fee3c8..34dcfc3 100644
--- a/telepathy-glib/channel.h
+++ b/telepathy-glib/channel.h
@@ -76,6 +76,10 @@ TpChannel *tp_channel_new (TpConnection *conn,
TpHandleType optional_handle_type, TpHandle optional_handle,
GError **error);
+TpChannel *tp_channel_new_from_properties (TpConnection *conn,
+ const gchar *object_path, const GHashTable *immutable_properties,
+ GError **error);
+
gboolean tp_channel_run_until_ready (TpChannel *self, GError **error,
GMainLoop **loop);
@@ -92,6 +96,7 @@ const gchar *tp_channel_get_channel_type (TpChannel *self);
GQuark tp_channel_get_channel_type_id (TpChannel *self);
TpHandle tp_channel_get_handle (TpChannel *self, TpHandleType *handle_type);
TpConnection *tp_channel_borrow_connection (TpChannel *self);
+GHashTable *tp_channel_borrow_immutable_properties (TpChannel *self);
TpHandle tp_channel_group_get_self_handle (TpChannel *self);
TpChannelGroupFlags tp_channel_group_get_flags (TpChannel *self);
--
1.5.6.5
More information about the Telepathy-commits
mailing list