[Telepathy-commits] [telepathy-mission-control/master] Invoke observers

Alberto Mardegan alberto.mardegan at nokia.com
Mon Nov 3 01:42:39 PST 2008


Activate the observers before running the handlers. Calling the handlers is
moved to a separate function, which is invoked in a callback as a result of a
count (cliant_locks variable) getting back to 0.
---
 src/mcd-dispatcher.c |  121 +++++++++++++++++++++++++++++++++++++++++++++++---
 1 files changed, 114 insertions(+), 7 deletions(-)

diff --git a/src/mcd-dispatcher.c b/src/mcd-dispatcher.c
index f7901fa..d5b0438 100644
--- a/src/mcd-dispatcher.c
+++ b/src/mcd-dispatcher.c
@@ -70,6 +70,13 @@ struct _McdDispatcherContext
     McdChannel *main_channel;
     McdDispatchOperation *operation;
 
+    /* This variable is the count of locks that must be removed before handlers
+     * can be invoked. Each call to an observer increments this count (and
+     * decrements it on return), and for unrequested channels we have an
+     * approver lock, too.
+     * When the variable gets back to 0, handlers are run. */
+    gint client_locks;
+
     gchar *protocol;
 
     /* State-machine internal data fields: */
@@ -1078,19 +1085,13 @@ mcd_dispatcher_run_handler (McdDispatcherContext *context,
     return unhandled;
 }
 
-/* Happens at the end of successful filter chain execution (empty chain
- * is always successful)
- */
 static void
-mcd_dispatcher_run_clients (McdDispatcherContext *context)
+mcd_dispatcher_run_handlers (McdDispatcherContext *context)
 {
     const GList *channels;
     GList *unhandled = NULL;
 
     mcd_dispatcher_context_ref (context);
-    /* TODO: start observers */
-
-    /* TODO: for non requested channels, start approvers */
 
     /* call mcd_dispatcher_run_handler until there are no unhandled channels */
     channels = mcd_dispatcher_context_get_channels (context);
@@ -1111,6 +1112,112 @@ mcd_dispatcher_run_clients (McdDispatcherContext *context)
 }
 
 static void
+mcd_dispatcher_context_release_client_lock (McdDispatcherContext *context)
+{
+    g_return_if_fail (context->client_locks > 0);
+    g_debug ("%s called on %p, locks = %d", G_STRFUNC,
+             context, context->client_locks);
+    context->client_locks--;
+    if (context->client_locks == 0)
+    {
+        /* no observers left, let's go on with the dispatching */
+        mcd_dispatcher_run_handlers (context);
+    }
+}
+
+static void
+observe_channels_cb (TpProxy *proxy, const GError *error,
+                     gpointer user_data, GObject *weak_object)
+{
+    McdDispatcherContext *context = user_data;
+
+    /* we display the error just for debugging, but we don't really care */
+    if (error)
+        g_debug ("Observer returned error: %s", error->message);
+
+    mcd_dispatcher_context_release_client_lock (context);
+}
+
+static void
+mcd_dispatcher_run_observers (McdDispatcherContext *context)
+{
+    McdDispatcherPrivate *priv = context->dispatcher->priv;
+    McdClient *handler = NULL;
+    const GList *cl, *channels;
+    GList *list;
+    GHashTable *observer_info;
+
+    channels = context->channels;
+    observer_info = NULL;
+
+    for (list = priv->clients; list != NULL; list = list->next)
+    {
+        McdClient *client = list->data;
+        GList *observed = NULL;
+        McdConnection *connection;
+        McdAccount *account;
+        const gchar *account_path, *connection_path;
+        GPtrArray *channels_array;
+
+        if (!client->proxy ||
+            !(client->interfaces & MCD_CLIENT_OBSERVER))
+            continue;
+
+        for (cl = channels; cl != NULL; cl = cl->next)
+        {
+            McdChannel *channel = MCD_CHANNEL (cl->data);
+
+            if (match_filters (channel, client->handler_filters))
+                observed = g_list_prepend (observed, channel);
+        }
+        if (!observed) continue;
+
+        /* build up the parameters and invoke the observer */
+        connection = mcd_dispatcher_context_get_connection (context);
+        g_assert (connection != NULL);
+        connection_path = mcd_connection_get_object_path (connection);
+
+        account = mcd_connection_get_account (connection);
+        g_assert (account != NULL);
+        account_path = mcd_account_get_object_path (account);
+
+        /* TODO: there's room for optimization here: reuse the channels_array,
+         * if the observed list is the same */
+        channels_array = _mcd_channel_details_build_from_list (observed);
+
+        context->client_locks++;
+        mcd_dispatcher_context_ref (context);
+        mc_cli_client_observer_call_observe_channels (handler->proxy, -1,
+            account_path, connection_path, channels_array, observer_info,
+            observe_channels_cb,
+            context, (GDestroyNotify)mcd_dispatcher_context_unref,
+            (GObject *)context->dispatcher);
+
+        _mcd_channel_details_free (channels_array);
+
+        g_list_free (observed);
+    }
+}
+
+/* Happens at the end of successful filter chain execution (empty chain
+ * is always successful)
+ */
+static void
+mcd_dispatcher_run_clients (McdDispatcherContext *context)
+{
+    mcd_dispatcher_context_ref (context);
+    context->client_locks = 1; /* we release this lock at the end of the
+                                    function */
+
+    mcd_dispatcher_run_observers (context);
+
+    /* TODO: for non requested channels, start approvers */
+
+    mcd_dispatcher_context_release_client_lock (context);
+    mcd_dispatcher_context_unref (context);
+}
+
+static void
 _mcd_dispatcher_drop_channel_handler (McdDispatcherContext * context)
 {
     McdChannel *channel;
-- 
1.5.6.5




More information about the Telepathy-commits mailing list