[Telepathy-commits] [telepathy-mission-control/master] Implement calling of EnsureChannel
Alberto Mardegan
alberto.mardegan at nokia.com
Wed Nov 19 02:27:56 PST 2008
---
src/mcd-account-requests.c | 3 +-
src/mcd-channel.c | 102 ++++++++++++++++++++++++++++++++++++++++++++
src/mcd-channel.h | 5 ++
src/mcd-connection.c | 77 +++++++++++++++++++++++++++++---
src/mcd-dispatcher.c | 26 +++++++++++
src/mcd-dispatcher.h | 2 +
6 files changed, 205 insertions(+), 10 deletions(-)
diff --git a/src/mcd-account-requests.c b/src/mcd-account-requests.c
index 4932f06..5b3bfca 100644
--- a/src/mcd-account-requests.c
+++ b/src/mcd-account-requests.c
@@ -130,14 +130,13 @@ create_request (McdAccount *account, GHashTable *properties,
GHashTable *props;
McdDispatcher *dispatcher;
- /* TODO: handle use_existing */
-
/* We MUST deep-copy the hash-table, as we don't know how dbus-glib will
* free it */
props = _mcd_deepcopy_asv (properties);
channel = mcd_channel_new_request (props, user_time,
preferred_handler);
g_hash_table_unref (props);
+ _mcd_channel_set_request_use_existing (channel, use_existing);
rd = g_slice_new (McdRequestData);
rd->requestor_client_id = dbus_g_method_get_sender (context);
diff --git a/src/mcd-channel.c b/src/mcd-channel.c
index cbb5ff3..bd6697e 100644
--- a/src/mcd-channel.c
+++ b/src/mcd-channel.c
@@ -95,6 +95,8 @@ typedef struct
GHashTable *properties;
guint64 user_time;
gchar *preferred_handler;
+
+ gboolean use_existing;
} McdChannelRequestData;
enum _McdChannelSignalType
@@ -139,6 +141,9 @@ static guint last_req_id = 1;
static void _mcd_channel_release_tp_channel (McdChannel *channel,
gboolean close_channel);
+static void on_proxied_channel_status_changed (McdChannel *source,
+ McdChannelStatus status,
+ McdChannel *dest);
static void
channel_request_data_free (McdChannelRequestData *crd)
@@ -1293,6 +1298,43 @@ _mcd_channel_get_request_preferred_handler (McdChannel *channel)
return crd->preferred_handler;
}
+/*
+ * _mcd_channel_set_request_use_existing:
+ * @channel: the #McdChannel.
+ * @use_existing: %TRUE if @channel must be requested via EnsureChannel.
+ *
+ * Sets the use_existing flag on @channel request.
+ */
+void
+_mcd_channel_set_request_use_existing (McdChannel *channel,
+ gboolean use_existing)
+{
+ McdChannelRequestData *crd;
+
+ g_return_if_fail (MCD_IS_CHANNEL (channel));
+ crd = g_object_get_data ((GObject *)channel, CD_REQUEST);
+ if (G_UNLIKELY (!crd)) return;
+ crd->use_existing = use_existing;
+}
+
+/*
+ * _mcd_channel_get_request_use_existing:
+ * @channel: the #McdChannel.
+ *
+ * Returns: %TRUE if the channel musb be requested via EnsureChannel, %FALSE
+ * otherwise.
+ */
+gboolean
+_mcd_channel_get_request_use_existing (McdChannel *channel)
+{
+ McdChannelRequestData *crd;
+
+ g_return_val_if_fail (MCD_IS_CHANNEL (channel), FALSE);
+ crd = g_object_get_data ((GObject *)channel, CD_REQUEST);
+ if (G_UNLIKELY (!crd)) return FALSE;
+ return crd->use_existing;
+}
+
/**
* mcd_channel_is_requested:
* @channel: the #McdChannel.
@@ -1325,3 +1367,63 @@ mcd_channel_get_account (McdChannel *channel)
return NULL;
}
+static void
+copy_status (McdChannel *source, McdChannel *dest)
+{
+ McdChannelPrivate *src_priv, *dst_priv;
+
+ src_priv = source->priv;
+ dst_priv = dest->priv;
+ if (dst_priv->status != src_priv->status)
+ {
+ g_debug ("%s: source is %d, dest is %d", G_STRFUNC,
+ src_priv->status, dst_priv->status);
+ if (src_priv->status == MCD_CHANNEL_FAILED)
+ {
+ const GError *error;
+
+ error = _mcd_channel_get_error (source);
+ /* this also takes care of setting the status */
+ _mcd_channel_set_error (dest, g_error_copy (error));
+ }
+ else
+ mcd_channel_set_status (dest, src_priv->status);
+ }
+
+ if (dst_priv->status == MCD_CHANNEL_FAILED ||
+ dst_priv->status == MCD_CHANNEL_DISPATCHED)
+ {
+ /* the request is completed, we are not interested in monitor the
+ * channel anymore */
+ g_signal_handlers_disconnect_by_func
+ (source, on_proxied_channel_status_changed, dest);
+ mcd_mission_abort (MCD_MISSION (dest));
+ }
+}
+
+static void
+on_proxied_channel_status_changed (McdChannel *source,
+ McdChannelStatus status,
+ McdChannel *dest)
+{
+ copy_status (source, dest);
+}
+
+/*
+ * _mcd_channel_set_request_proxy:
+ * @channel: the requested #McdChannel.
+ * @source: the #McdChannel to be proxied.
+ *
+ * This function turns @channel into a proxy for @source: it listens to
+ * "status-changed" signals from @source and replicates them on @channel
+ */
+void
+_mcd_channel_set_request_proxy (McdChannel *channel, McdChannel *source)
+{
+ g_return_if_fail (MCD_IS_CHANNEL (channel));
+ g_return_if_fail (MCD_IS_CHANNEL (source));
+ copy_status (source, channel);
+ g_signal_connect (source, "status-changed",
+ G_CALLBACK (on_proxied_channel_status_changed), channel);
+}
+
diff --git a/src/mcd-channel.h b/src/mcd-channel.h
index bb129a2..c9421b9 100644
--- a/src/mcd-channel.h
+++ b/src/mcd-channel.h
@@ -129,6 +129,11 @@ GHashTable *_mcd_channel_get_requested_properties (McdChannel *channel);
const gchar *_mcd_channel_get_request_path (McdChannel *channel);
guint64 _mcd_channel_get_request_user_action_time (McdChannel *channel);
const gchar *_mcd_channel_get_request_preferred_handler (McdChannel *channel);
+void _mcd_channel_set_request_use_existing (McdChannel *channel,
+ gboolean use_existing);
+gboolean _mcd_channel_get_request_use_existing (McdChannel *channel);
+
+void _mcd_channel_set_request_proxy (McdChannel *channel, McdChannel *source);
void _mcd_channel_set_error (McdChannel *channel, GError *error);
const GError *_mcd_channel_get_error (McdChannel *channel);
diff --git a/src/mcd-connection.c b/src/mcd-connection.c
index ecc29c6..a194109 100644
--- a/src/mcd-connection.c
+++ b/src/mcd-connection.c
@@ -2002,12 +2002,11 @@ request_handles_cb (TpConnection *proxy, const GArray *handles,
}
static void
-create_channel_cb (TpConnection *proxy, const gchar *channel_path,
- GHashTable *properties, const GError *error,
- gpointer user_data, GObject *weak_object)
+common_request_channel_cb (TpConnection *proxy, gboolean yours,
+ const gchar *channel_path, GHashTable *properties,
+ const GError *error,
+ McdConnection *connection, McdChannel *channel)
{
- McdChannel *channel = MCD_CHANNEL (weak_object);
- McdConnection *connection = user_data;
McdConnectionPrivate *priv = connection->priv;
if (error != NULL)
@@ -2025,6 +2024,38 @@ create_channel_cb (TpConnection *proxy, const gchar *channel_path,
}
g_debug ("%s: %p, object %s", G_STRFUNC, channel, channel_path);
+ /* if this was a call to EnsureChannel, it can happen that the returned
+ * channel was already created before; in that case we keep the McdChannel
+ * alive only as a proxy for the status-changed signals from the "real"
+ * McdChannel */
+ if (_mcd_channel_get_request_use_existing (channel))
+ {
+ McdChannel *existing;
+ existing = find_channel_by_path (connection, channel_path);
+ if (existing)
+ {
+ /* Two possibilities:
+ *
+ * 1) if @existing is not yet in dispatched state, proxy the
+ * signals from @existing to this request (@channel).
+ *
+ * 2) if @existing is already dispatched, we must re-invoke its
+ * handler
+ */
+ if (mcd_channel_get_status (channel) == MCD_CHANNEL_DISPATCHED)
+ {
+ g_debug ("reinvoking handler on channel %p", existing);
+ _mcd_dispatcher_reinvoke_handler (priv->dispatcher, existing);
+ }
+ else
+ {
+ g_debug ("channel %p is proxying %p", channel, existing);
+ _mcd_channel_set_request_proxy (channel, existing);
+ }
+ return;
+ }
+ }
+
_mcd_channel_set_immutable_properties (channel,
_mcd_deepcopy_asv (properties));
/* Everything here is well and fine. We can create the channel. */
@@ -2038,6 +2069,27 @@ create_channel_cb (TpConnection *proxy, const gchar *channel_path,
* NewChannels signal */
}
+static void
+ensure_channel_cb (TpConnection *proxy, gboolean yours,
+ const gchar *channel_path, GHashTable *properties,
+ const GError *error,
+ gpointer user_data, GObject *weak_object)
+{
+ common_request_channel_cb (proxy, yours, channel_path, properties, error,
+ MCD_CONNECTION (user_data),
+ MCD_CHANNEL (weak_object));
+}
+
+static void
+create_channel_cb (TpConnection *proxy, const gchar *channel_path,
+ GHashTable *properties, const GError *error,
+ gpointer user_data, GObject *weak_object)
+{
+ common_request_channel_cb (proxy, TRUE, channel_path, properties, error,
+ MCD_CONNECTION (user_data),
+ MCD_CHANNEL (weak_object));
+}
+
static gboolean
request_channel_new_iface (McdConnection *connection, McdChannel *channel)
{
@@ -2045,9 +2097,18 @@ request_channel_new_iface (McdConnection *connection, McdChannel *channel)
GHashTable *properties;
properties = _mcd_channel_get_requested_properties (channel);
- tp_cli_connection_interface_requests_call_create_channel
- (priv->tp_conn, -1, properties, create_channel_cb, connection, NULL,
- (GObject *)channel);
+ if (_mcd_channel_get_request_use_existing (channel))
+ {
+ tp_cli_connection_interface_requests_call_ensure_channel
+ (priv->tp_conn, -1, properties, ensure_channel_cb,
+ connection, NULL, (GObject *)channel);
+ }
+ else
+ {
+ tp_cli_connection_interface_requests_call_create_channel
+ (priv->tp_conn, -1, properties, create_channel_cb,
+ connection, NULL, (GObject *)channel);
+ }
return TRUE;
}
diff --git a/src/mcd-dispatcher.c b/src/mcd-dispatcher.c
index 2ca7cc2..d5aff9c 100644
--- a/src/mcd-dispatcher.c
+++ b/src/mcd-dispatcher.c
@@ -2532,3 +2532,29 @@ mcd_dispatcher_add_filters (McdDispatcher *dispatcher,
filter->user_data);
}
+/*
+ * _mcd_dispatcher_reinvoke_handler:
+ * @dispatcher: The #McdDispatcher.
+ * @channel: a #McdChannel.
+ *
+ * Re-invoke the channel handler for @channel.
+ */
+void
+_mcd_dispatcher_reinvoke_handler (McdDispatcher *dispatcher,
+ McdChannel *channel)
+{
+ McdDispatcherContext *context;
+
+ /* Preparing and filling the context */
+ context = g_new0 (McdDispatcherContext, 1);
+ context->ref_count = 1;
+ context->dispatcher = dispatcher;
+ context->channels = g_list_prepend (NULL, channel);
+
+ /* We must ref() the channel, because
+ * mcd_dispatcher_context_unref() will unref() it */
+ g_object_ref (channel);
+ mcd_dispatcher_run_handlers (context);
+ mcd_dispatcher_context_unref (context);
+}
+
diff --git a/src/mcd-dispatcher.h b/src/mcd-dispatcher.h
index 080bcd4..3e15ed3 100644
--- a/src/mcd-dispatcher.h
+++ b/src/mcd-dispatcher.h
@@ -91,6 +91,8 @@ void _mcd_dispatcher_add_request (McdDispatcher *dispatcher,
McdAccount *account, McdChannel *channel);
void _mcd_dispatcher_send_channels (McdDispatcher *dispatcher,
GList *channels, gboolean requested);
+void _mcd_dispatcher_reinvoke_handler (McdDispatcher *dispatcher,
+ McdChannel *channel);
G_END_DECLS
--
1.5.6.5
More information about the Telepathy-commits
mailing list