[Spice-devel] [PATCH 2/4] util: add spice_g_signal_connect_object
Marc-André Lureau
marcandre.lureau at gmail.com
Thu Sep 22 16:22:42 PDT 2011
This is a copy of telepathy-glib tp_g_signal_connect_object.
That function allows to connect object's signals without
having to worry much about emitter/observer lifetime.
It handles automatic disconnection for us, no need to track
all the handlers id. Nice!
---
gtk/spice-util-priv.h | 5 ++
gtk/spice-util.c | 106 +++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 111 insertions(+), 0 deletions(-)
diff --git a/gtk/spice-util-priv.h b/gtk/spice-util-priv.h
index 90b437c..1f9778c 100644
--- a/gtk/spice-util-priv.h
+++ b/gtk/spice-util-priv.h
@@ -23,6 +23,11 @@
G_BEGIN_DECLS
gboolean spice_strv_contains(const GStrv strv, const gchar *str);
+gulong spice_g_signal_connect_object(gpointer instance,
+ const gchar *detailed_signal,
+ GCallback c_handler,
+ gpointer gobject,
+ GConnectFlags connect_flags);
G_END_DECLS
diff --git a/gtk/spice-util.c b/gtk/spice-util.c
index d3097ca..fb5767b 100644
--- a/gtk/spice-util.c
+++ b/gtk/spice-util.c
@@ -1,6 +1,7 @@
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
Copyright (C) 2010 Red Hat, Inc.
+ Copyright © 2006-2010 Collabora Ltd. <http://www.collabora.co.uk/>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
@@ -74,3 +75,108 @@ gboolean spice_strv_contains(const GStrv strv, const gchar *str)
return FALSE;
}
+
+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);
+}
+
+/* Copied from tp_g_signal_connect_object. See documentation. */
+G_GNUC_INTERNAL
+gulong spice_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);
+ g_return_val_if_fail (
+ (connect_flags & ~(G_CONNECT_AFTER|G_CONNECT_SWAPPED)) == 0, 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, (connect_flags & G_CONNECT_AFTER) ? TRUE : FALSE);
+
+ 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;
+}
--
1.7.6.2
More information about the Spice-devel
mailing list