[Telepathy-commits] [telepathy-glib/master] channelspecific example: port channel factory to TpChannelManager
Simon McVittie
simon.mcvittie at collabora.co.uk
Wed Jan 7 07:24:50 PST 2009
---
examples/cm/channelspecific/conn.c | 9 +-
examples/cm/channelspecific/room-factory.c | 252 ++++++++++++++++++++--------
2 files changed, 191 insertions(+), 70 deletions(-)
diff --git a/examples/cm/channelspecific/conn.c b/examples/cm/channelspecific/conn.c
index b65a706..a2cdc49 100644
--- a/examples/cm/channelspecific/conn.c
+++ b/examples/cm/channelspecific/conn.c
@@ -18,6 +18,7 @@
#include <telepathy-glib/dbus.h>
#include <telepathy-glib/errors.h>
#include <telepathy-glib/handle-repo-dynamic.h>
+#include <telepathy-glib/interfaces.h>
#include "room-factory.h"
@@ -197,7 +198,7 @@ create_handle_repos (TpBaseConnection *conn,
}
static GPtrArray *
-create_channel_factories (TpBaseConnection *conn)
+create_channel_managers (TpBaseConnection *conn)
{
GPtrArray *ret = g_ptr_array_sized_new (1);
@@ -244,6 +245,9 @@ shut_down (TpBaseConnection *conn)
static void
example_csh_connection_class_init (ExampleCSHConnectionClass *klass)
{
+ static const gchar *interfaces_always_present[] = {
+ TP_IFACE_CONNECTION_INTERFACE_REQUESTS,
+ NULL };
TpBaseConnectionClass *base_class =
(TpBaseConnectionClass *) klass;
GObjectClass *object_class = (GObjectClass *) klass;
@@ -256,9 +260,10 @@ example_csh_connection_class_init (ExampleCSHConnectionClass *klass)
base_class->create_handle_repos = create_handle_repos;
base_class->get_unique_connection_name = get_unique_connection_name;
- base_class->create_channel_factories = create_channel_factories;
+ base_class->create_channel_managers = create_channel_managers;
base_class->start_connecting = start_connecting;
base_class->shut_down = shut_down;
+ base_class->interfaces_always_present = interfaces_always_present;
param_spec = g_param_spec_string ("account", "Account name",
"The username of this user", NULL,
diff --git a/examples/cm/channelspecific/room-factory.c b/examples/cm/channelspecific/room-factory.c
index 2dab379..e585d66 100644
--- a/examples/cm/channelspecific/room-factory.c
+++ b/examples/cm/channelspecific/room-factory.c
@@ -1,7 +1,7 @@
/*
* room-factory.c: example channel factory for chatrooms
*
- * Copyright (C) 2007 Collabora Ltd. <http://www.collabora.co.uk/>
+ * Copyright (C) 2007-2008 Collabora Ltd. <http://www.collabora.co.uk/>
* Copyright (C) 2007 Nokia Corporation
*
* Copying and distribution of this file, with or without modification,
@@ -20,15 +20,13 @@
#include "room.h"
-/* FIXME: we really ought to have a base class in the library for this,
- * it's such a common pattern... */
-
-static void iface_init (gpointer iface, gpointer data);
+static void channel_manager_iface_init (gpointer, gpointer);
G_DEFINE_TYPE_WITH_CODE (ExampleCSHRoomFactory,
example_csh_room_factory,
G_TYPE_OBJECT,
- G_IMPLEMENT_INTERFACE (TP_TYPE_CHANNEL_FACTORY_IFACE, iface_init))
+ G_IMPLEMENT_INTERFACE (TP_TYPE_CHANNEL_MANAGER,
+ channel_manager_iface_init))
/* type definition stuff */
@@ -44,6 +42,7 @@ struct _ExampleCSHRoomFactoryPrivate
/* GUINT_TO_POINTER (room handle) => ExampleCSHRoomChannel */
GHashTable *channels;
+ gulong status_changed_id;
};
static void
@@ -56,12 +55,14 @@ example_csh_room_factory_init (ExampleCSHRoomFactory *self)
NULL, g_object_unref);
}
+static void example_csh_room_factory_close_all (ExampleCSHRoomFactory *self);
+
static void
dispose (GObject *object)
{
ExampleCSHRoomFactory *self = EXAMPLE_CSH_ROOM_FACTORY (object);
- tp_channel_factory_iface_close_all ((TpChannelFactoryIface *) object);
+ example_csh_room_factory_close_all (self);
g_assert (self->priv->channels == NULL);
((GObjectClass *) example_csh_room_factory_parent_class)->dispose (object);
@@ -107,11 +108,38 @@ set_property (GObject *object,
}
static void
+status_changed_cb (TpBaseConnection *conn,
+ guint status,
+ guint reason,
+ ExampleCSHRoomFactory *self)
+{
+ if (status == TP_CONNECTION_STATUS_DISCONNECTED)
+ example_csh_room_factory_close_all (self);
+}
+
+static void
+constructed (GObject *object)
+{
+ ExampleCSHRoomFactory *self = EXAMPLE_CSH_ROOM_FACTORY (object);
+ void (*chain_up) (GObject *) =
+ ((GObjectClass *) example_csh_room_factory_parent_class)->constructed;
+
+ if (chain_up != NULL)
+ {
+ chain_up (object);
+ }
+
+ self->priv->status_changed_id = g_signal_connect (self->priv->conn,
+ "status-changed", (GCallback) status_changed_cb, self);
+}
+
+static void
example_csh_room_factory_class_init (ExampleCSHRoomFactoryClass *klass)
{
GParamSpec *param_spec;
GObjectClass *object_class = (GObjectClass *) klass;
+ object_class->constructed = constructed;
object_class->dispose = dispose;
object_class->get_property = get_property;
object_class->set_property = set_property;
@@ -127,10 +155,8 @@ example_csh_room_factory_class_init (ExampleCSHRoomFactoryClass *klass)
}
static void
-example_csh_room_factory_close_all (TpChannelFactoryIface *iface)
+example_csh_room_factory_close_all (ExampleCSHRoomFactory *self)
{
- ExampleCSHRoomFactory *self = EXAMPLE_CSH_ROOM_FACTORY (iface);
-
if (self->priv->channels != NULL)
{
GHashTable *tmp = self->priv->channels;
@@ -138,43 +164,43 @@ example_csh_room_factory_close_all (TpChannelFactoryIface *iface)
self->priv->channels = NULL;
g_hash_table_destroy (tmp);
}
-}
-
-struct _ForeachData
-{
- gpointer user_data;
- TpChannelFunc callback;
-};
-static void
-foreach_helper (gpointer key,
- gpointer value,
- gpointer user_data)
-{
- struct _ForeachData *data = user_data;
- TpChannelIface *chan = TP_CHANNEL_IFACE (value);
-
- data->callback (chan, data->user_data);
+ if (self->priv->status_changed_id != 0)
+ {
+ g_signal_handler_disconnect (self->priv->conn,
+ self->priv->status_changed_id);
+ self->priv->status_changed_id = 0;
+ }
}
static void
-example_csh_room_factory_foreach (TpChannelFactoryIface *iface,
- TpChannelFunc callback,
- gpointer user_data)
+example_csh_room_factory_foreach_channel (TpChannelManager *manager,
+ TpExportableChannelFunc callback,
+ gpointer user_data)
{
- ExampleCSHRoomFactory *self = EXAMPLE_CSH_ROOM_FACTORY (iface);
- struct _ForeachData data = { user_data, callback };
+ ExampleCSHRoomFactory *self = EXAMPLE_CSH_ROOM_FACTORY (manager);
+ GHashTableIter iter;
+ gpointer handle, channel;
+
+ g_hash_table_iter_init (&iter, self->priv->channels);
- g_hash_table_foreach (self->priv->channels, foreach_helper, &data);
+ while (g_hash_table_iter_next (&iter, &handle, &channel))
+ {
+ callback (TP_EXPORTABLE_CHANNEL (channel), user_data);
+ }
}
static void
-channel_closed_cb (ExampleCSHRoomChannel *chan, ExampleCSHRoomFactory *self)
+channel_closed_cb (ExampleCSHRoomChannel *chan,
+ ExampleCSHRoomFactory *self)
{
- TpHandle handle;
+ tp_channel_manager_emit_channel_closed_for_object (self,
+ TP_EXPORTABLE_CHANNEL (chan));
if (self->priv->channels != NULL)
{
+ TpHandle handle;
+
g_object_get (chan,
"handle", &handle,
NULL);
@@ -184,10 +210,14 @@ channel_closed_cb (ExampleCSHRoomChannel *chan, ExampleCSHRoomFactory *self)
}
static ExampleCSHRoomChannel *
-new_channel (ExampleCSHRoomFactory *self, TpHandle handle)
+new_channel (ExampleCSHRoomFactory *self,
+ TpHandle handle,
+ TpHandle initiator,
+ gpointer request_token)
{
ExampleCSHRoomChannel *chan;
gchar *object_path;
+ GSList *requests = NULL;
object_path = g_strdup_printf ("%s/CSHRoomChannel%u",
self->priv->conn->object_path, handle);
@@ -196,6 +226,7 @@ new_channel (ExampleCSHRoomFactory *self, TpHandle handle)
"connection", self->priv->conn,
"object-path", object_path,
"handle", handle,
+ /* FIXME: initiator */
NULL);
g_free (object_path);
@@ -204,57 +235,142 @@ new_channel (ExampleCSHRoomFactory *self, TpHandle handle)
g_hash_table_insert (self->priv->channels, GUINT_TO_POINTER (handle), chan);
- tp_channel_factory_iface_emit_new_channel (self, (TpChannelIface *) chan,
- NULL);
+ if (request_token != NULL)
+ requests = g_slist_prepend (requests, request_token);
+
+ tp_channel_manager_emit_new_channel (self, TP_EXPORTABLE_CHANNEL (chan),
+ requests);
+ g_slist_free (requests);
return chan;
}
-static TpChannelFactoryRequestStatus
-example_csh_room_factory_request (TpChannelFactoryIface *iface,
- const gchar *chan_type,
- TpHandleType handle_type,
- guint handle,
- gpointer request_id,
- TpChannelIface **ret,
- GError **error)
+static const gchar * const fixed_properties[] = {
+ TP_IFACE_CHANNEL ".ChannelType",
+ TP_IFACE_CHANNEL ".TargetHandleType",
+ NULL
+};
+
+static const gchar * const allowed_properties[] = {
+ TP_IFACE_CHANNEL ".TargetHandle",
+ TP_IFACE_CHANNEL ".TargetID",
+ NULL
+};
+
+static void
+example_csh_room_factory_foreach_channel_class (TpChannelManager *manager,
+ TpChannelManagerChannelClassFunc func,
+ gpointer user_data)
+{
+ GHashTable *table = g_hash_table_new_full (g_str_hash, g_str_equal,
+ NULL, (GDestroyNotify) tp_g_value_slice_free);
+ GValue *value;
+
+ value = tp_g_value_slice_new (G_TYPE_STRING);
+ g_value_set_static_string (value, TP_IFACE_CHANNEL_TYPE_TEXT);
+ g_hash_table_insert (table, TP_IFACE_CHANNEL ".ChannelType", value);
+
+ value = tp_g_value_slice_new (G_TYPE_UINT);
+ g_value_set_uint (value, TP_HANDLE_TYPE_ROOM);
+ g_hash_table_insert (table, TP_IFACE_CHANNEL ".TargetHandleType", value);
+
+ func (manager, table, allowed_properties, user_data);
+
+ g_hash_table_destroy (table);
+}
+
+static gboolean
+example_csh_room_factory_request (ExampleCSHRoomFactory *self,
+ gpointer request_token,
+ GHashTable *request_properties,
+ gboolean require_new)
{
- ExampleCSHRoomFactory *self = EXAMPLE_CSH_ROOM_FACTORY (iface);
+ TpHandle handle;
ExampleCSHRoomChannel *chan;
- TpChannelFactoryRequestStatus status;
- TpHandleRepoIface *room_repo = tp_base_connection_get_handles
- (self->priv->conn, TP_HANDLE_TYPE_ROOM);
+ GError *error = NULL;
+
+ if (tp_strdiff (tp_asv_get_string (request_properties,
+ TP_IFACE_CHANNEL ".ChannelType"),
+ TP_IFACE_CHANNEL_TYPE_TEXT))
+ {
+ return FALSE;
+ }
- if (tp_strdiff (chan_type, TP_IFACE_CHANNEL_TYPE_TEXT))
- return TP_CHANNEL_FACTORY_REQUEST_STATUS_NOT_IMPLEMENTED;
+ if (tp_asv_get_uint32 (request_properties,
+ TP_IFACE_CHANNEL ".TargetHandleType", NULL) != TP_HANDLE_TYPE_ROOM)
+ {
+ return FALSE;
+ }
- if (handle_type != TP_HANDLE_TYPE_ROOM)
- return TP_CHANNEL_FACTORY_REQUEST_STATUS_NOT_IMPLEMENTED;
+ handle = tp_asv_get_uint32 (request_properties,
+ TP_IFACE_CHANNEL ".TargetHandle", NULL);
+ g_assert (handle != 0);
- if (!tp_handle_is_valid (room_repo, handle, error))
- return TP_CHANNEL_FACTORY_REQUEST_STATUS_ERROR;
+ if (tp_channel_manager_asv_has_unknown_properties (request_properties,
+ fixed_properties, allowed_properties, &error))
+ {
+ goto error;
+ }
chan = g_hash_table_lookup (self->priv->channels, GUINT_TO_POINTER (handle));
- status = TP_CHANNEL_FACTORY_REQUEST_STATUS_EXISTING;
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,
+ request_token);
+ }
+ else if (require_new)
+ {
+ g_set_error (&error, TP_ERRORS, TP_ERROR_NOT_AVAILABLE,
+ "A Text channel for room #%u already exists", handle);
+ goto error;
+ }
+ else
+ {
+ tp_channel_manager_emit_request_already_satisfied (self,
+ request_token, TP_EXPORTABLE_CHANNEL (chan));
}
- g_assert (chan != NULL);
- *ret = TP_CHANNEL_IFACE (chan);
- return status;
+ return TRUE;
+
+error:
+ tp_channel_manager_emit_request_failed (self, request_token,
+ error->domain, error->code, error->message);
+ g_error_free (error);
+ return TRUE;
}
-static void
-iface_init (gpointer iface,
- gpointer data)
+static gboolean
+example_csh_room_factory_create_channel (TpChannelManager *manager,
+ gpointer request_token,
+ GHashTable *request_properties)
+{
+ return example_csh_room_factory_request (
+ EXAMPLE_CSH_ROOM_FACTORY (manager), request_token,
+ request_properties, TRUE);
+}
+
+static gboolean
+example_csh_room_factory_ensure_channel (TpChannelManager *manager,
+ gpointer request_token,
+ GHashTable *request_properties)
{
- TpChannelFactoryIfaceClass *klass = iface;
+ return example_csh_room_factory_request (
+ EXAMPLE_CSH_ROOM_FACTORY (manager), request_token,
+ request_properties, FALSE);
+}
- klass->close_all = example_csh_room_factory_close_all;
- klass->foreach = example_csh_room_factory_foreach;
- klass->request = example_csh_room_factory_request;
+static void
+channel_manager_iface_init (gpointer g_iface,
+ gpointer data G_GNUC_UNUSED)
+{
+ TpChannelManagerIface *iface = g_iface;
+
+ iface->foreach_channel = example_csh_room_factory_foreach_channel;
+ iface->foreach_channel_class =
+ example_csh_room_factory_foreach_channel_class;
+ iface->create_channel = example_csh_room_factory_create_channel;
+ iface->ensure_channel = example_csh_room_factory_ensure_channel;
+ /* In this channel manager, Request has the same semantics as Ensure */
+ iface->request_channel = example_csh_room_factory_ensure_channel;
}
--
1.5.6.5
More information about the Telepathy-commits
mailing list