[Telepathy-commits] [telepathy-glib/master] TpConnectionManager: add API to become "ready"

Simon McVittie simon.mcvittie at collabora.co.uk
Thu Feb 12 09:56:02 PST 2009


---
 docs/reference/telepathy-glib-sections.txt |    2 +
 telepathy-glib/connection-manager.c        |  148 +++++++++++++++++++++++++++-
 telepathy-glib/connection-manager.h        |    7 ++
 3 files changed, 153 insertions(+), 4 deletions(-)

diff --git a/docs/reference/telepathy-glib-sections.txt b/docs/reference/telepathy-glib-sections.txt
index 95ffa36..d419c3f 100644
--- a/docs/reference/telepathy-glib-sections.txt
+++ b/docs/reference/telepathy-glib-sections.txt
@@ -2450,6 +2450,8 @@ TpConnectionManagerParam
 TpConnectionManagerClass
 TpCMInfoSource
 tp_connection_manager_new
+TpConnectionManagerWhenReadyCb
+tp_connection_manager_call_when_ready
 tp_connection_manager_activate
 tp_connection_manager_check_valid_name
 tp_connection_manager_check_valid_protocol_name
diff --git a/telepathy-glib/connection-manager.c b/telepathy-glib/connection-manager.c
index 12b7b02..fc210b6 100644
--- a/telepathy-glib/connection-manager.c
+++ b/telepathy-glib/connection-manager.c
@@ -209,12 +209,143 @@ struct _TpConnectionManagerPrivate {
      * progress (will replace ->protocols when finished).
      * Otherwise NULL */
     GPtrArray *found_protocols;
+
+    /* list of WhenReadyContext */
+    GList *waiting_for_ready;
 };
 
 G_DEFINE_TYPE (TpConnectionManager,
     tp_connection_manager,
     TP_TYPE_PROXY);
 
+typedef struct {
+    TpConnectionManager *cm;
+    TpConnectionManagerWhenReadyCb callback;
+    gpointer user_data;
+    GDestroyNotify destroy;
+    GObject *weak_object;
+} WhenReadyContext;
+
+static void
+when_ready_context_free (gpointer d)
+{
+  WhenReadyContext *c = d;
+
+  if (c->cm != NULL)
+    {
+      g_object_unref (c->cm);
+      c->cm = NULL;
+    }
+
+  if (c->destroy != NULL)
+    c->destroy (c->user_data);
+
+  g_slice_free (WhenReadyContext, c);
+}
+
+static void
+when_ready_context_cancel (gpointer d,
+                           GObject *corpse)
+{
+  WhenReadyContext *c = d;
+
+  g_assert (c->weak_object == corpse);
+  c->weak_object = NULL;
+  c->callback = NULL;
+
+  if (c->destroy != NULL)
+    {
+      c->destroy (c->user_data);
+      c->destroy = NULL;
+    }
+
+  if (c->cm != NULL)
+    {
+      g_object_unref (c->cm);
+      c->cm = NULL;
+    }
+}
+
+static gboolean
+when_ready_context_complete (gpointer d)
+{
+  WhenReadyContext *c = d;
+
+  if (c->callback != NULL)
+    c->callback (c->cm, NULL, c->user_data, c->weak_object);
+
+  return FALSE;
+}
+
+static void
+tp_connection_manager_ready_or_failed (TpConnectionManager *self,
+                                       const GError *error)
+{
+  GList *waiters = self->priv->waiting_for_ready;
+  GList *link;
+
+  self->priv->waiting_for_ready = NULL;
+
+  if (self->info_source > TP_CM_INFO_SOURCE_NONE)
+    {
+      /* we have info already, so suppress any error and return the old info */
+      error = NULL;
+    }
+  else
+    {
+      g_assert (error != NULL);
+    }
+
+  for (link = waiters; link != NULL; link = g_list_next (link))
+    {
+      WhenReadyContext *c = link->data;
+
+      if (c->callback != NULL)
+        c->callback (c->cm, error, c->user_data, c->weak_object);
+
+      when_ready_context_free (c);
+      link->data = NULL;
+    }
+
+  g_list_free (waiters);
+}
+
+void
+tp_connection_manager_call_when_ready (TpConnectionManager *self,
+                                       TpConnectionManagerWhenReadyCb callback,
+                                       gpointer user_data,
+                                       GDestroyNotify destroy,
+                                       GObject *weak_object)
+{
+  WhenReadyContext *c;
+
+  g_return_if_fail (TP_IS_CONNECTION_MANAGER (self));
+  g_return_if_fail (callback != NULL);
+
+  c = g_slice_new0 (WhenReadyContext);
+
+  c->cm = g_object_ref (self);
+  c->callback = callback;
+  c->user_data = user_data;
+  c->destroy = destroy;
+  c->weak_object = weak_object;
+
+  if (weak_object != NULL)
+    {
+      g_object_weak_ref (weak_object, when_ready_context_cancel, c);
+    }
+
+  if (self->info_source != TP_CM_INFO_SOURCE_NONE)
+    {
+      g_idle_add_full (G_PRIORITY_HIGH, when_ready_context_complete,
+          c, when_ready_context_free);
+      return;
+    }
+
+  self->priv->waiting_for_ready = g_list_append (self->priv->waiting_for_ready,
+      c);
+}
+
 static void tp_connection_manager_continue_introspection
     (TpConnectionManager *self);
 
@@ -331,8 +462,12 @@ tp_connection_manager_free_protocols (GPtrArray *protocols)
   g_ptr_array_free (protocols, TRUE);
 }
 
+static void tp_connection_manager_ready_or_failed (TpConnectionManager *self,
+                                       const GError *error);
+
 static void
-tp_connection_manager_end_introspection (TpConnectionManager *self)
+tp_connection_manager_end_introspection (TpConnectionManager *self,
+                                         const GError *error)
 {
   guint i;
 
@@ -354,6 +489,7 @@ tp_connection_manager_end_introspection (TpConnectionManager *self)
     }
 
   g_signal_emit (self, signals[SIGNAL_GOT_INFO], 0, self->info_source);
+  tp_connection_manager_ready_or_failed (self, error);
 }
 
 static void
@@ -378,7 +514,7 @@ tp_connection_manager_continue_introspection (TpConnectionManager *self)
           self->priv->protocols->pdata;
 
       self->info_source = TP_CM_INFO_SOURCE_LIVE;
-      tp_connection_manager_end_introspection (self);
+      tp_connection_manager_end_introspection (self, NULL);
 
       return;
     }
@@ -413,7 +549,7 @@ tp_connection_manager_got_protocols (TpConnectionManager *self,
           g_signal_emit (self, signals[SIGNAL_EXITED], 0);
         }
 
-      tp_connection_manager_end_introspection (self);
+      tp_connection_manager_end_introspection (self, error);
       return;
     }
 
@@ -471,10 +607,13 @@ tp_connection_manager_name_owner_changed_cb (TpDBusDaemon *bus,
 
   if (new_owner[0] == '\0')
     {
+      GError e = { TP_DBUS_ERRORS, TP_DBUS_ERROR_NAME_OWNER_LOST,
+          "Connection manager process exited during introspection" };
+
       self->running = FALSE;
 
       /* cancel pending introspection, if any */
-      tp_connection_manager_end_introspection (self);
+      tp_connection_manager_end_introspection (self, &e);
 
       g_signal_emit (self, signals[SIGNAL_EXITED], 0);
     }
@@ -973,6 +1112,7 @@ tp_connection_manager_idle_read_manager_file (gpointer data)
 
               g_signal_emit (self, signals[SIGNAL_GOT_INFO], 0,
                   self->info_source);
+              tp_connection_manager_ready_or_failed (self, NULL);
             }
         }
 
diff --git a/telepathy-glib/connection-manager.h b/telepathy-glib/connection-manager.h
index 85d1581..cc2a357 100644
--- a/telepathy-glib/connection-manager.h
+++ b/telepathy-glib/connection-manager.h
@@ -116,6 +116,13 @@ void tp_list_connection_managers (TpDBusDaemon *bus_daemon,
     gpointer user_data, GDestroyNotify destroy,
     GObject *weak_object);
 
+typedef void (*TpConnectionManagerWhenReadyCb) (TpConnectionManager *self,
+    const GError *error, gpointer user_data, GObject *weak_object);
+
+void tp_connection_manager_call_when_ready (TpConnectionManager *self,
+    TpConnectionManagerWhenReadyCb callback,
+    gpointer user_data, GDestroyNotify destroy, GObject *weak_object);
+
 gboolean tp_connection_manager_check_valid_name (const gchar *name,
     GError **error);
 
-- 
1.5.6.5




More information about the telepathy-commits mailing list