[Telepathy-commits] [telepathy-mission-control/master] Run the channel handler until there are no unhandled channels

Alberto Mardegan alberto.mardegan at nokia.com
Mon Nov 17 00:05:19 PST 2008


Call mcd_dispatcher_run_handler() from inside a loop, until there are no
unhandled channels.
Make mcd_dispatcher_run_handler() return the list of unhandled channels.
---
 src/mcd-dispatcher.c |  121 +++++++++++++++++++++++++++++++++++++++++++-------
 1 files changed, 105 insertions(+), 16 deletions(-)

diff --git a/src/mcd-dispatcher.c b/src/mcd-dispatcher.c
index 7ab15c4..6b41942 100644
--- a/src/mcd-dispatcher.c
+++ b/src/mcd-dispatcher.c
@@ -64,6 +64,7 @@ struct _McdDispatcherContext
     McdDispatcher *dispatcher;
 
     GList *channels;
+    McdChannel *main_channel;
 
     gchar *protocol;
 
@@ -174,6 +175,8 @@ enum _McdDispatcherSignalType
 static guint mcd_dispatcher_signals[LAST_SIGNAL] = { 0 };
 
 static void mcd_dispatcher_context_free (McdDispatcherContext * ctx);
+static void mcd_dispatcher_context_set_channel (McdDispatcherContext *context,
+                                                McdChannel *channel);
 
 typedef void (*tp_ch_handle_channel_reply) (DBusGProxy *proxy, GError *error, gpointer userdata);
 
@@ -852,30 +855,70 @@ handle_channels_cb (TpProxy *proxy, const GError *error, gpointer user_data,
     mcd_dispatcher_context_free (context);
 }
 
-static void
-mcd_dispatcher_run_handler (McdDispatcherContext *context)
+/*
+ * mcd_dispatcher_run_handler:
+ * @context: the #McdDispatcherContext.
+ * @channels: a #GList of #McdChannel elements to be handled.
+ *
+ * This functions tries to find a handler to handle @channels, and invokes its
+ * HandleChannels method. It returns a list of channels that are still
+ * unhandled.
+ */
+static GList *
+mcd_dispatcher_run_handler (McdDispatcherContext *context,
+                            const GList *channels)
 {
     McdDispatcherPrivate *priv = context->dispatcher->priv;
     McdClient *handler = NULL;
+    gint num_channels_best, num_channels;
+    const GList *cl;
     GList *list;
+    GList *handled_best = NULL, *unhandled;
 
     /* TODO: in the McdDispatcherContext there should be a hint on what handler
      * to invoke */
+    num_channels_best = 0;
     for (list = priv->clients; list != NULL; list = list->next)
     {
         McdClient *client = list->data;
-        McdChannel *channel;
+        GList *handled = NULL;
 
-        /* TODO: support more than one channel */
-        channel = mcd_dispatcher_context_get_channel (context);
+        if (!client->proxy ||
+            !(client->interfaces & MCD_CLIENT_HANDLER))
+            continue;
 
-        if (client->proxy &&
-            client->interfaces & MCD_CLIENT_HANDLER &&
-            match_filters (channel, client->handler_filters))
+        /* count the number of channels supported by this handler; we try to
+         * send the channels to the handler that can handle the most */
+        num_channels = 0;
+        for (cl = channels; cl != NULL; cl = cl->next)
         {
+            McdChannel *channel = MCD_CHANNEL (cl->data);
+
+            if (match_filters (channel, client->handler_filters))
+            {
+                num_channels++;
+                handled = g_list_prepend (handled, channel);
+            }
+        }
+
+        if (num_channels > num_channels_best)
+        {
+            /* this is the best candidate handler so far; remember also the
+             * list of channels it cannot handle */
             handler = client;
-            break;
+            g_list_free (handled_best);
+            handled_best = handled;
         }
+        else
+            g_list_free (handled);
+    }
+
+    /* build the list of unhandled channels */
+    unhandled = NULL;
+    for (cl = channels; cl != NULL; cl = cl->next)
+    {
+        if (!g_list_find (handled_best, cl->data))
+            unhandled = g_list_prepend (unhandled, cl->data);
     }
 
     if (handler)
@@ -884,7 +927,7 @@ mcd_dispatcher_run_handler (McdDispatcherContext *context)
         McdConnection *connection;
         McdAccount *account;
         const gchar *account_path, *connection_path;
-        GPtrArray *channels, *satisfied_requests;
+        GPtrArray *channels_array, *satisfied_requests;
 
         connection = mcd_dispatcher_context_get_connection (context);
         g_assert (connection != NULL);
@@ -894,23 +937,31 @@ mcd_dispatcher_run_handler (McdDispatcherContext *context)
         g_assert (account != NULL);
         account_path = mcd_account_get_object_path (account);
 
-        channels = _mcd_channel_details_build_from_list (context->channels);
+        channels_array = _mcd_channel_details_build_from_list (handled_best);
 
         satisfied_requests = g_ptr_array_new (); /* TODO */
         user_action_time = 0; /* TODO: if we have a CDO, get it from there */
         mc_cli_client_handler_call_handle_channels (handler->proxy, -1,
             account_path, connection_path,
-            channels, satisfied_requests, user_action_time,
+            channels_array, satisfied_requests, user_action_time,
             handle_channels_cb, context, NULL, (GObject *)context->dispatcher);
 
         g_ptr_array_free (satisfied_requests, TRUE);
-        _mcd_channel_details_free (channels);
+        _mcd_channel_details_free (channels_array);
     }
     else
     {
         g_debug ("Client.Handler not found, invoking old-style handler");
-        start_old_channel_handler (context);
+        for (cl = unhandled; cl != NULL; cl = cl->next)
+        {
+            mcd_dispatcher_context_set_channel (context,
+                                                MCD_CHANNEL (cl->data));
+            start_old_channel_handler (context);
+        }
+        g_list_free (unhandled);
+        unhandled = NULL;
     }
+    return unhandled;
 }
 
 /* Happens at the end of successful filter chain execution (empty chain
@@ -919,11 +970,28 @@ mcd_dispatcher_run_handler (McdDispatcherContext *context)
 static void
 mcd_dispatcher_run_clients (McdDispatcherContext *context)
 {
+    const GList *channels;
+    GList *unhandled = NULL;
+
     /* TODO: start observers */
 
     /* TODO: for non requested channels, start approvers */
 
-    mcd_dispatcher_run_handler (context);
+    /* call mcd_dispatcher_run_handler until there are no unhandled channels */
+    channels = mcd_dispatcher_context_get_channels (context);
+    while (channels)
+    {
+        g_list_free (unhandled);
+        unhandled = mcd_dispatcher_run_handler (context, channels);
+        if (g_list_length (unhandled) >= g_list_length ((GList *)channels))
+        {
+            /* this could really be an assertion, but just to be on the safe
+             * side... */
+            g_warning ("Number of unhandled channels not decreasing!");
+            break;
+        }
+        channels = unhandled;
+    }
 }
 
 static void
@@ -1643,11 +1711,32 @@ mcd_dispatcher_context_get_connection_object (McdDispatcherContext * ctx)
     return tp_conn;
 }
 
+/*
+ * mcd_dispatcher_context_set_channel:
+ *
+ * Sets the channel to be considered the main channel of the dispatcher
+ * context, that is the one that will be retrieved with
+ * mcd_dispatcher_context_get_channel(). It's useful only for compatibility
+ * with the old code.
+ */
+static void
+mcd_dispatcher_context_set_channel (McdDispatcherContext *context,
+                                    McdChannel *channel)
+{
+    g_return_if_fail (context != NULL);
+    g_return_if_fail (channel != NULL);
+
+    context->main_channel = channel;
+}
+
 McdChannel *
 mcd_dispatcher_context_get_channel (McdDispatcherContext * ctx)
 {
     g_return_val_if_fail (ctx, 0);
-    return ctx->channels ? MCD_CHANNEL (ctx->channels->data) : NULL;
+    if (ctx->main_channel)
+        return ctx->main_channel;
+    else
+        return ctx->channels ? MCD_CHANNEL (ctx->channels->data) : NULL;
 }
 
 /**
-- 
1.5.6.5




More information about the Telepathy-commits mailing list