[telepathy-glib/master] Added tp_g_signal_connect_object() as public api.

David Laban david.laban at collabora.co.uk
Wed Nov 18 09:49:13 PST 2009


Basically like g_signal_connect_object() but less leaky.
---
 docs/reference/telepathy-glib-sections.txt |    1 +
 telepathy-glib/util.c                      |  128 ++++++++++++++++++++++++++++
 telepathy-glib/util.h                      |    4 +
 telepathy-glib/versions/0.10.0.abi         |    5 +
 4 files changed, 138 insertions(+), 0 deletions(-)
 create mode 100644 telepathy-glib/versions/0.10.0.abi

diff --git a/docs/reference/telepathy-glib-sections.txt b/docs/reference/telepathy-glib-sections.txt
index 2c1df5e..a62fd9e 100644
--- a/docs/reference/telepathy-glib-sections.txt
+++ b/docs/reference/telepathy-glib-sections.txt
@@ -1086,6 +1086,7 @@ tp_escape_as_identifier
 tp_strv_contains
 tp_g_key_file_get_int64
 tp_g_key_file_get_uint64
+tp_g_signal_connect_object
 </SECTION>
 
 <SECTION>
diff --git a/telepathy-glib/util.c b/telepathy-glib/util.c
index b8f66f2..391ae10 100644
--- a/telepathy-glib/util.c
+++ b/telepathy-glib/util.c
@@ -810,6 +810,134 @@ tp_g_key_file_get_uint64 (GKeyFile *key_file,
   return v;
 }
 
+typedef struct {
+    GObject *instance;
+    GObject *observer;
+    GClosure *closure;
+    gulong handler_id;
+} WeakHandlerCtx;
+
+static WeakHandlerCtx *
+whc_new (GObject *instance,
+         GObject *observer)
+{
+  WeakHandlerCtx *ctx = g_slice_new0 (WeakHandlerCtx);
+
+  ctx->instance = instance;
+  ctx->observer = observer;
+
+  return ctx;
+}
+
+static void
+whc_free (WeakHandlerCtx *ctx)
+{
+  g_slice_free (WeakHandlerCtx, ctx);
+}
+
+static void observer_destroyed_cb (gpointer, GObject *);
+static void closure_invalidated_cb (gpointer, GClosure *);
+
+/*
+ * If signal handlers are removed before the object is destroyed, this
+ * callback will never get triggered.
+ */
+static void
+instance_destroyed_cb (gpointer ctx_,
+    GObject *where_the_instance_was)
+{
+  WeakHandlerCtx *ctx = ctx_;
+
+  /* No need to disconnect the signal here, the instance has gone away. */
+  g_object_weak_unref (ctx->observer, observer_destroyed_cb, ctx);
+  g_closure_remove_invalidate_notifier (ctx->closure, ctx,
+      closure_invalidated_cb);
+  whc_free (ctx);
+}
+
+/* Triggered when the observer is destroyed. */
+static void
+observer_destroyed_cb (gpointer ctx_,
+    GObject *where_the_observer_was)
+{
+  WeakHandlerCtx *ctx = ctx_;
+
+  g_closure_remove_invalidate_notifier (ctx->closure, ctx,
+      closure_invalidated_cb);
+  g_signal_handler_disconnect (ctx->instance, ctx->handler_id);
+  g_object_weak_unref (ctx->instance, instance_destroyed_cb, ctx);
+  whc_free (ctx);
+}
+
+/* Triggered when either object is destroyed or the handler is disconnected. */
+static void
+closure_invalidated_cb (gpointer ctx_,
+    GClosure *where_the_closure_was)
+{
+  WeakHandlerCtx *ctx = ctx_;
+
+  g_object_weak_unref (ctx->instance, instance_destroyed_cb, ctx);
+  g_object_weak_unref (ctx->observer, observer_destroyed_cb, ctx);
+  whc_free (ctx);
+}
+
+/**
+ * tp_g_signal_connect_object:
+ * @instance: the instance to connect to.
+ * @detailed_signal: a string of the form "signal-name::detail".
+ * @c_handler: the #GCallback to connect.
+ * @gobject: the object to pass as data to @c_handler.
+ * @connect_flags: a combination of #GConnnectFlags.
+ *
+ * Connects a #GCallback function to a signal for a particular object, as if
+ * with g_signal_connect(). Additionally, arranges for the signal handler to be
+ * disconnected if @observer is destroyed.
+ *
+ * This is similar to g_signal_connect_data(), but uses a closure which
+ * ensures that the @gobject stays alive during the call to @c_handler
+ * by temporarily adding a reference count to @gobject.
+ *
+ * This is similar to g_signal_connect_object(), but doesn't have the
+ * documented bug that everyone is too scared to fix. Also, it does not allow
+ * you to pass in NULL as @gobject
+ *
+ * This is intended to be a convenient way for objects to use themselves as
+ * user_data for callbacks without having to explicitly disconnect all the
+ * handlers in their finalizers.
+ *
+ * Returns: the handler id.
+ */
+gulong
+tp_g_signal_connect_object (gpointer instance,
+    const gchar *detailed_signal,
+    GCallback c_handler,
+    gpointer gobject,
+    GConnectFlags connect_flags)
+{
+  GObject *instance_obj = G_OBJECT (instance);
+  WeakHandlerCtx *ctx = whc_new (instance_obj, gobject);
+
+  g_return_val_if_fail (G_TYPE_CHECK_INSTANCE (instance), 0);
+  g_return_val_if_fail (detailed_signal != NULL, 0);
+  g_return_val_if_fail (c_handler != NULL, 0);
+  g_return_val_if_fail (G_IS_OBJECT (gobject), 0);
+
+  if (connect_flags & G_CONNECT_SWAPPED)
+    ctx->closure = g_cclosure_new_object_swap (c_handler, gobject);
+  else
+    ctx->closure = g_cclosure_new_object (c_handler, gobject);
+
+  ctx->handler_id = g_signal_connect_closure (instance, detailed_signal,
+      ctx->closure, 0);
+
+  g_object_weak_ref (instance_obj, instance_destroyed_cb, ctx);
+  g_object_weak_ref (gobject, observer_destroyed_cb, ctx);
+  g_closure_add_invalidate_notifier (ctx->closure, ctx,
+      closure_invalidated_cb);
+
+  return ctx->handler_id;
+}
+
 /*
  * _tp_quark_array_copy:
  * @quarks: A 0-terminated list of quarks to copy
diff --git a/telepathy-glib/util.h b/telepathy-glib/util.h
index 1cd3df2..4c2abe6 100644
--- a/telepathy-glib/util.h
+++ b/telepathy-glib/util.h
@@ -73,6 +73,10 @@ gint64 tp_g_key_file_get_int64 (GKeyFile *key_file, const gchar *group_name,
 guint64 tp_g_key_file_get_uint64 (GKeyFile *key_file, const gchar *group_name,
     const gchar *key, GError **error);
 
+gulong tp_g_signal_connect_object (gpointer instance,
+    const gchar *detailed_signal, GCallback c_handler, gpointer gobject,
+    GConnectFlags connect_flags);
+
 G_END_DECLS
 
 #undef  __TP_IN_UTIL_H__
diff --git a/telepathy-glib/versions/0.10.0.abi b/telepathy-glib/versions/0.10.0.abi
new file mode 100644
index 0000000..62fca7e
--- /dev/null
+++ b/telepathy-glib/versions/0.10.0.abi
@@ -0,0 +1,5 @@
+Version: TELEPATHY_GLIB_0.9.0
+Extends: TELEPATHY_GLIB_0.7.37
+Release: 0.9.0
+
+tp_g_signal_connect_object
-- 
1.5.6.5




More information about the telepathy-commits mailing list