+static void weak_object_notify (gpointer data,
+ GObject *old_object);
+
+static ReadyCbData *
+ready_cb_data_new (EmpathyTpTube *self,
+ EmpathyTpTubeReadyCb *callback,
+ gpointer user_data,
+ GDestroyNotify destroy,
+ GObject *weak_object)
+{
+ ReadyCbData *d = g_slice_new0 (ReadyCbData);
+ d->callback = callback;
+ d->user_data = user_data;
+ d->destroy = destroy;
+ d->weak_object = weak_object;
+
+ if (weak_object != NULL)
+ g_object_weak_ref (weak_object, weak_object_notify, self);
+
+ return d;
+}
+
+static void
+ready_cb_data_free (ReadyCbData *data,
+ EmpathyTpTube *self)
+{
+ if (data->destroy != NULL)
+ data->destroy (data->user_data);
+
+ if (data->weak_object != NULL)
+ g_object_weak_unref (data->weak_object,
+ weak_object_notify, self);
+
+ g_slice_free (ReadyCbData, data);
+}
+
+static void
+weak_object_notify (gpointer data,
+ GObject *old_object)
+{
+ EmpathyTpTube *self = EMPATHY_TP_TUBE (data);
+ EmpathyTpTubePriv *priv = GET_PRIV (self);
+ GSList *l, *ln;
+
+ for (l = priv->ready_callbacks ; l != NULL ; l = ln )
+ {
+ ReadyCbData *d = (ReadyCbData *) l->data;
+ ln = g_slist_next (l);
+
+ if (d->weak_object == old_object)
+ {
+ ready_cb_data_free (d, self);
+ priv->ready_callbacks = g_slist_delete_link (priv->ready_callbacks,
+ l);
+ }
+ }
+}
+
+
+static void
+tube_is_ready (EmpathyTpTube *self,
+ const GError *error)
+{
+ EmpathyTpTubePriv *priv = GET_PRIV (self);
+ GSList *l;
+
+ priv->ready = TRUE;
+
+ for (l = priv->ready_callbacks ; l != NULL ; l = g_slist_next (l))
+ {
+ ReadyCbData *data = (ReadyCbData *) l->data;
+
+ data->callback (self, error, data->user_data, data->weak_object);
+ ready_cb_data_free (data, self);
+ }
+
+ g_slist_free (priv->ready_callbacks);
+ priv->ready_callbacks = NULL;
+}
+