[Telepathy-commits] [telepathy-glib/master] Echo CM: implement TpExportableChannel, respawning, and (#if'd out) Destroyable
Simon McVittie
simon.mcvittie at collabora.co.uk
Thu Oct 30 07:05:22 PDT 2008
---
examples/cm/echo/chan.c | 140 ++++++++++++++++++++++++++++++++++++++------
examples/cm/echo/factory.c | 21 +++++--
2 files changed, 138 insertions(+), 23 deletions(-)
diff --git a/examples/cm/echo/chan.c b/examples/cm/echo/chan.c
index 37f55bb..0a7b938 100644
--- a/examples/cm/echo/chan.c
+++ b/examples/cm/echo/chan.c
@@ -30,7 +30,15 @@ G_DEFINE_TYPE_WITH_CODE (ExampleEchoChannel,
tp_dbus_properties_mixin_iface_init);
G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL, channel_iface_init);
G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_TYPE_TEXT, text_iface_init);
- G_IMPLEMENT_INTERFACE (TP_TYPE_CHANNEL_IFACE, NULL))
+ G_IMPLEMENT_INTERFACE (TP_TYPE_CHANNEL_IFACE, NULL);
+ G_IMPLEMENT_INTERFACE (TP_TYPE_EXPORTABLE_CHANNEL, NULL))
+
+/* FIXME: when supported, add:
+static void channel_iface_init (gpointer iface, gpointer data);
+
+ G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_INTERFACE_DESTROYABLE,
+ destroyable_iface_init);
+*/
/* type definition stuff */
@@ -46,6 +54,8 @@ enum
PROP_INITIATOR_ID,
PROP_CONNECTION,
PROP_INTERFACES,
+ PROP_CHANNEL_DESTROYED,
+ PROP_CHANNEL_PROPERTIES,
N_PROPS
};
@@ -54,6 +64,7 @@ struct _ExampleEchoChannelPrivate
TpBaseConnection *conn;
gchar *object_path;
TpHandle handle;
+ TpHandle initiator;
/* These are really booleans, but gboolean is signed. Thanks, GLib */
unsigned closed:1;
@@ -61,6 +72,7 @@ struct _ExampleEchoChannelPrivate
};
static const char * example_echo_channel_interfaces[] = { NULL };
+/* FIXME: when supported, add TP_IFACE_CHANNEL_INTERFACE_DESTROYABLE */
static void
example_echo_channel_init (ExampleEchoChannel *self)
@@ -84,6 +96,9 @@ constructor (GType type,
tp_handle_ref (contact_repo, self->priv->handle);
+ if (self->priv->initiator != 0)
+ tp_handle_ref (contact_repo, self->priv->initiator);
+
bus = tp_get_bus ();
dbus_g_connection_register_g_object (bus, self->priv->object_path, object);
@@ -131,27 +146,21 @@ get_property (GObject *object,
}
break;
case PROP_REQUESTED:
- /* this example CM doesn't yet support other contacts initiating
- * chats with us, so the only way a channel can exist is if the
- * user asked for it */
- g_value_set_boolean (value, TRUE);
+ g_value_set_boolean (value,
+ (self->priv->initiator == self->priv->conn->self_handle));
break;
case PROP_INITIATOR_HANDLE:
- /* this example CM doesn't yet support other contacts initiating
- * chats with us, so the only way a channel can exist is if the
- * user asked for it */
- g_value_set_uint (value, self->priv->conn->self_handle);
+ g_value_set_uint (value, self->priv->initiator);
break;
case PROP_INITIATOR_ID:
{
- /* this example CM doesn't yet support other contacts initiating
- * chats with us, so the only way a channel can exist is if the
- * user asked for it */
TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (
self->priv->conn, TP_HANDLE_TYPE_CONTACT);
g_value_set_string (value,
- tp_handle_inspect (contact_repo, self->priv->conn->self_handle));
+ self->priv->initiator == 0
+ ? ""
+ : tp_handle_inspect (contact_repo, self->priv->initiator));
}
break;
case PROP_CONNECTION:
@@ -160,6 +169,22 @@ get_property (GObject *object,
case PROP_INTERFACES:
g_value_set_boxed (value, example_echo_channel_interfaces);
break;
+ case PROP_CHANNEL_DESTROYED:
+ g_value_set_boolean (value, self->priv->closed);
+ break;
+ case PROP_CHANNEL_PROPERTIES:
+ g_value_take_boxed (value,
+ tp_dbus_properties_mixin_make_properties_hash (object,
+ TP_IFACE_CHANNEL, "ChannelType",
+ TP_IFACE_CHANNEL, "TargetHandleType",
+ TP_IFACE_CHANNEL, "TargetHandle",
+ TP_IFACE_CHANNEL, "TargetID",
+ TP_IFACE_CHANNEL, "InitiatorHandle",
+ TP_IFACE_CHANNEL, "InitiatorID",
+ TP_IFACE_CHANNEL, "Requested",
+ TP_IFACE_CHANNEL, "Interfaces",
+ NULL));
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
@@ -186,6 +211,10 @@ set_property (GObject *object,
*/
self->priv->handle = g_value_get_uint (value);
break;
+ case PROP_INITIATOR_HANDLE:
+ /* likewise */
+ self->priv->initiator = g_value_get_uint (value);
+ break;
case PROP_HANDLE_TYPE:
case PROP_CHANNEL_TYPE:
/* these properties are writable in the interface, but not actually
@@ -212,6 +241,7 @@ dispose (GObject *object)
if (!self->priv->closed)
{
+ self->priv->closed = TRUE;
tp_svc_channel_emit_closed (self);
}
@@ -226,6 +256,10 @@ finalize (GObject *object)
(self->priv->conn, TP_HANDLE_TYPE_CONTACT);
tp_handle_unref (contact_handles, self->priv->handle);
+
+ if (self->priv->initiator != 0)
+ tp_handle_unref (contact_handles, self->priv->initiator);
+
g_free (self->priv->object_path);
tp_text_mixin_finalize (object);
@@ -274,6 +308,11 @@ example_echo_channel_class_init (ExampleEchoChannelClass *klass)
"handle-type");
g_object_class_override_property (object_class, PROP_HANDLE, "handle");
+ g_object_class_override_property (object_class, PROP_CHANNEL_DESTROYED,
+ "channel-destroyed");
+ g_object_class_override_property (object_class, PROP_CHANNEL_PROPERTIES,
+ "channel-properties");
+
param_spec = g_param_spec_object ("connection", "TpBaseConnection object",
"Connection object that owns this channel",
TP_TYPE_BASE_CONNECTION,
@@ -295,7 +334,7 @@ example_echo_channel_class_init (ExampleEchoChannelClass *klass)
param_spec = g_param_spec_uint ("initiator-handle", "Initiator's handle",
"The contact who initiated the channel",
0, G_MAXUINT32, 0,
- G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+ G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
g_object_class_install_property (object_class, PROP_INITIATOR_HANDLE,
param_spec);
@@ -321,17 +360,55 @@ example_echo_channel_class_init (ExampleEchoChannelClass *klass)
}
static void
-channel_close (TpSvcChannel *iface,
- DBusGMethodInvocation *context)
+example_echo_channel_close (ExampleEchoChannel *self)
{
- ExampleEchoChannel *self = EXAMPLE_ECHO_CHANNEL (iface);
+ GObject *object = (GObject *) self;
if (!self->priv->closed)
{
- self->priv->closed = TRUE;
+ TpHandle first_sender;
+
+ /* The factory wants to be able to respawn the channel if it has pending
+ * messages. When respawned, the channel must have the initiator set
+ * to the contact who sent us those messages (if it isn't already),
+ * and the messages must be marked as having been rescued so they
+ * don't get logged twice. */
+ if (tp_text_mixin_has_pending_messages (object, &first_sender))
+ {
+ if (self->priv->initiator != first_sender)
+ {
+ TpHandleRepoIface *contact_repo = tp_base_connection_get_handles
+ (self->priv->conn, TP_HANDLE_TYPE_CONTACT);
+ TpHandle old_initiator = self->priv->initiator;
+
+ if (first_sender != 0)
+ tp_handle_ref (contact_repo, first_sender);
+
+ self->priv->initiator = first_sender;
+
+ if (old_initiator != 0)
+ tp_handle_unref (contact_repo, old_initiator);
+ }
+
+ tp_text_mixin_set_rescued (object);
+ }
+ else
+ {
+ /* No pending messages, so it's OK to really close */
+ self->priv->closed = TRUE;
+ }
+
tp_svc_channel_emit_closed (self);
}
+}
+
+static void
+channel_close (TpSvcChannel *iface,
+ DBusGMethodInvocation *context)
+{
+ ExampleEchoChannel *self = EXAMPLE_ECHO_CHANNEL (iface);
+ example_echo_channel_close (self);
tp_svc_channel_return_from_close (context);
}
@@ -432,3 +509,30 @@ text_iface_init (gpointer iface,
IMPLEMENT (send);
#undef IMPLEMENT
}
+
+/* FIXME: enable this when Destroyable is supported */
+#if 0
+static void
+destroyable_destroy (TpSvcChannelInterfaceDestroyable *iface,
+ DBusGMethodInvocation *context)
+{
+ ExampleEchoChannel *self = EXAMPLE_ECHO_CHANNEL (iface);
+
+ tp_text_mixin_clear ((GObject *) self);
+ example_echo_channel_close (self);
+ g_assert (self->priv->closed);
+ tp_svc_channel_return_from_close (context);
+}
+
+static void
+destroyable_iface_init (gpointer iface,
+ gpointer data)
+{
+ TpSvcChannelInterfaceDestroyableClass *klass = iface;
+
+#define IMPLEMENT(x) \
+ tp_svc_channel_interface_destroyable_implement_##x (klass, destroyable_##x)
+ IMPLEMENT (destroy);
+#undef IMPLEMENT
+}
+#endif
diff --git a/examples/cm/echo/factory.c b/examples/cm/echo/factory.c
index b03f59c..3a934f2 100644
--- a/examples/cm/echo/factory.c
+++ b/examples/cm/echo/factory.c
@@ -173,20 +173,30 @@ example_echo_factory_foreach (TpChannelFactoryIface *iface,
static void
channel_closed_cb (ExampleEchoChannel *chan, ExampleEchoFactory *self)
{
- TpHandle handle;
-
if (self->priv->channels != NULL)
{
+ TpHandle handle;
+ gboolean really_destroyed;
+
g_object_get (chan,
"handle", &handle,
+ "channel-destroyed", &really_destroyed,
NULL);
- g_hash_table_remove (self->priv->channels, GUINT_TO_POINTER (handle));
+ /* Re-announce the channel if it's not yet ready to go away (pending
+ * messages) */
+ if (really_destroyed)
+ g_hash_table_remove (self->priv->channels, GUINT_TO_POINTER (handle));
+ else
+ tp_channel_manager_emit_new_channel (self,
+ TP_EXPORTABLE_CHANNEL (chan), NULL);
}
}
static ExampleEchoChannel *
-new_channel (ExampleEchoFactory *self, TpHandle handle)
+new_channel (ExampleEchoFactory *self,
+ TpHandle handle,
+ TpHandle initiator)
{
ExampleEchoChannel *chan;
gchar *object_path;
@@ -198,6 +208,7 @@ new_channel (ExampleEchoFactory *self, TpHandle handle)
"connection", self->priv->conn,
"object-path", object_path,
"handle", handle,
+ "initiator-handle", initiator,
NULL);
g_free (object_path);
@@ -242,7 +253,7 @@ example_echo_factory_request (TpChannelFactoryIface *iface,
if (chan == NULL)
{
status = TP_CHANNEL_FACTORY_REQUEST_STATUS_CREATED;
- chan = new_channel (self, handle);
+ chan = new_channel (self, handle, self->priv->conn->self_handle);
}
g_assert (chan != NULL);
--
1.5.6.5
More information about the Telepathy-commits
mailing list