[Spice-devel] [PATCH 2/4] util: add spice_g_signal_connect_object
Hans de Goede
hdegoede at redhat.com
Fri Sep 23 00:27:55 PDT 2011
ACK.
On 09/23/2011 01:22 AM, Marc-André Lureau wrote:
> 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;
> +}
More information about the Spice-devel
mailing list