[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