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@xxxxxxxxxx > https://www.redhat.com/mailman/listinfo/virt-tools-list
Attachment:
pgpeKrJm_tU4b.pgp
Description: PGP signature