[virt-tools-list] [PATCH virt-viewer 03/19] spice: disconnect signal handlers when either object is destroyed
Marc-André Lureau
marcandre.lureau at gmail.com
Mon Jul 16 16:57:38 UTC 2012
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.
---
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
More information about the virt-tools-list
mailing list