[virt-tools-list] [PATCH virt-viewer 03/19] spice: disconnect signal handlers when either object is destroyed
Christophe Fergeau
cfergeau at redhat.com
Tue Jul 17 08:37:23 UTC 2012
On Mon, Jul 16, 2012 at 06:57:38PM +0200, Marc-André Lureau wrote:
> Use virt_viewer_signal_connect_object(), a copy of telepathy
> utility function tp_g_signal_connect_object(). This function
> will take care of removing signal handler if any of emitter or
> attached object are destroyed.
Why do you need to do this? Are you seeing concrete issues? Or will it be
needed by subsequent changes?
Christophe
> ---
> src/virt-viewer-display-spice.c | 26 ++++-----
> src/virt-viewer-util.c | 117 +++++++++++++++++++++++++++++++++++++++
> src/virt-viewer-util.h | 6 ++
> 3 files changed, 135 insertions(+), 14 deletions(-)
>
> diff --git a/src/virt-viewer-display-spice.c b/src/virt-viewer-display-spice.c
> index 0b6949b..7bf9a9a 100644
> --- a/src/virt-viewer-display-spice.c
> +++ b/src/virt-viewer-display-spice.c
> @@ -219,10 +219,10 @@ virt_viewer_display_spice_new(VirtViewerSessionSpice *session,
> self->priv->display = spice_display_new(s, channelid);
> g_object_unref(s);
>
> - g_signal_connect(channel, "display-primary-create",
> - G_CALLBACK(primary_create), self);
> - g_signal_connect(channel, "display-mark",
> - G_CALLBACK(display_mark), self);
> + virt_viewer_signal_connect_object(channel, "display-primary-create",
> + G_CALLBACK(primary_create), self, 0);
> + virt_viewer_signal_connect_object(channel, "display-mark",
> + G_CALLBACK(display_mark), self, 0);
>
> gtk_container_add(GTK_CONTAINER(self), g_object_ref(self->priv->display));
> gtk_widget_show(GTK_WIDGET(self->priv->display));
> @@ -233,19 +233,17 @@ virt_viewer_display_spice_new(VirtViewerSessionSpice *session,
> "scaling", TRUE,
> NULL);
>
> - g_signal_connect(self->priv->display,
> - "keyboard-grab",
> - G_CALLBACK(virt_viewer_display_spice_keyboard_grab), self);
> - g_signal_connect(self->priv->display,
> - "mouse-grab",
> - G_CALLBACK(virt_viewer_display_spice_mouse_grab), self);
> - g_signal_connect(self,
> - "size-allocate",
> - G_CALLBACK(virt_viewer_display_spice_size_allocate), self);
> + virt_viewer_signal_connect_object(self->priv->display, "keyboard-grab",
> + G_CALLBACK(virt_viewer_display_spice_keyboard_grab), self, 0);
> + virt_viewer_signal_connect_object(self->priv->display, "mouse-grab",
> + G_CALLBACK(virt_viewer_display_spice_mouse_grab), self, 0);
> + virt_viewer_signal_connect_object(self, "size-allocate",
> + G_CALLBACK(virt_viewer_display_spice_size_allocate), self, 0);
>
>
> app = virt_viewer_session_get_app(VIRT_VIEWER_SESSION(session));
> - g_signal_connect(app, "notify::enable-accel", G_CALLBACK(enable_accel_changed), self);
> + virt_viewer_signal_connect_object(app, "notify::enable-accel",
> + G_CALLBACK(enable_accel_changed), self, 0);
> enable_accel_changed(app, NULL, self);
>
> return GTK_WIDGET(self);
> diff --git a/src/virt-viewer-util.c b/src/virt-viewer-util.c
> index c1182af..9a163fa 100644
> --- a/src/virt-viewer-util.c
> +++ b/src/virt-viewer-util.c
> @@ -136,6 +136,123 @@ virt_viewer_util_extract_host(const char *uristr,
> return 0;
> }
>
> +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 G_GNUC_UNUSED)
> +{
> + 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 G_GNUC_UNUSED)
> +{
> + 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 G_GNUC_UNUSED)
> +{
> + 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. */
> +/**
> + * virt_viewer_signal_connect_object: (skip)
> + * @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 #GConnectFlags.
> + *
> + * Similar to g_signal_connect_object() but will delete connection
> + * when any of the objects is destroyed.
> + *
> + * Returns: the handler id.
> + */
> +gulong virt_viewer_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;
> +}
> +
> +
> /*
> * Local variables:
> * c-indent-level: 4
> diff --git a/src/virt-viewer-util.h b/src/virt-viewer-util.h
> index 3a40651..38c8078 100644
> --- a/src/virt-viewer-util.h
> +++ b/src/virt-viewer-util.h
> @@ -40,6 +40,12 @@ int virt_viewer_util_extract_host(const char *uristr,
> char **user,
> int *port);
>
> +gulong virt_viewer_signal_connect_object(gpointer instance,
> + const gchar *detailed_signal,
> + GCallback c_handler,
> + gpointer gobject,
> + GConnectFlags connect_flags);
> +
> #endif
>
> /*
> --
> 1.7.10.4
>
> _______________________________________________
> virt-tools-list mailing list
> virt-tools-list at redhat.com
> https://www.redhat.com/mailman/listinfo/virt-tools-list
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: not available
URL: <http://listman.redhat.com/archives/virt-tools-list/attachments/20120717/65d4cb47/attachment.sig>
More information about the virt-tools-list
mailing list