summaryrefslogtreecommitdiff
path: root/src/spice-util-glib.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/spice-util-glib.c')
-rw-r--r--src/spice-util-glib.c233
1 files changed, 233 insertions, 0 deletions
diff --git a/src/spice-util-glib.c b/src/spice-util-glib.c
new file mode 100644
index 0000000..561171b
--- /dev/null
+++ b/src/spice-util-glib.c
@@ -0,0 +1,233 @@
+/*
+ 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
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+#include "config.h"
+
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <glib.h>
+#include <glib-object.h>
+#include "spice-common.h"
+#include "spice-util-priv.h"
+#include "spice-util.h"
+#include "spice-util-priv.h"
+
+static GOnce debug_once = G_ONCE_INIT;
+
+static void spice_util_enable_debug_messages(void)
+{
+ const gchar *doms = g_getenv("G_MESSAGES_DEBUG");
+ if (!doms) {
+ g_setenv("G_MESSAGES_DEBUG", G_LOG_DOMAIN, 1);
+ } else if (g_str_equal(doms, "all")) {
+ return;
+ } else if (!strstr(doms, G_LOG_DOMAIN)) {
+ gchar *newdoms = g_strdup_printf("%s %s", doms, G_LOG_DOMAIN);
+ g_setenv("G_MESSAGES_DEBUG", newdoms, 1);
+ g_free(newdoms);
+ }
+}
+
+/**
+ * spice_glib_set_debug:
+ * @enabled: %TRUE or %FALSE
+ *
+ * Enable or disable Spice-GTK debugging messages.
+ **/
+void spice_glib_set_debug(gboolean enabled)
+{
+ /* Make sure debug_once has been initialised
+ * with the value of SPICE_DEBUG already, otherwise
+ * spice_util_get_debug() may overwrite the value
+ * that was just set using spice_util_set_debug()
+ */
+ spice_glib_get_debug();
+
+ if (enabled) {
+ spice_util_enable_debug_messages();
+ }
+
+ debug_once.retval = GINT_TO_POINTER(enabled);
+}
+
+static gpointer getenv_debug(gpointer data)
+{
+ gboolean debug;
+
+ debug = (g_getenv("SPICE_DEBUG") != NULL);
+ if (debug)
+ spice_util_enable_debug_messages();
+
+ return GINT_TO_POINTER(debug);
+}
+
+gboolean spice_glib_get_debug(void)
+{
+ g_once(&debug_once, getenv_debug, NULL);
+
+ return GPOINTER_TO_INT(debug_once.retval);
+}
+
+/**
+ * spice_glib_get_version_string:
+ *
+ * Gets the version string
+ *
+ * Returns: Spice-GTK version as a const string.
+ **/
+const gchar *spice_glib_get_version_string(void)
+{
+ return VERSION;
+}
+
+/**
+ * spice_glib_uuid_to_string:
+ * @uuid: (array fixed-size=16): UUID byte array
+ *
+ * Creates a string representation of @uuid, of the form
+ * "06e023d5-86d8-420e-8103-383e4566087a"
+ *
+ * Returns: A string that should be freed with g_free().
+ * Since: 0.43
+ **/
+gchar* spice_glib_uuid_to_string(const guint8 uuid[16])
+{
+ return g_strdup_printf(UUID_FMT, uuid[0], uuid[1],
+ uuid[2], uuid[3], uuid[4], uuid[5],
+ uuid[6], uuid[7], uuid[8], uuid[9],
+ uuid[10], uuid[11], uuid[12], uuid[13],
+ uuid[14], uuid[15]);
+}
+
+typedef struct {
+ GObject *instance;
+ GObject *observer;
+ GClosure *closure;
+ gulong handler_id;
+} WeakHandlerCtx;
+
+static WeakHandlerCtx *
+whc_new (GObject *instance,
+ GObject *observer)
+{
+ WeakHandlerCtx *ctx = g_new0 (WeakHandlerCtx, 1);
+
+ ctx->instance = instance;
+ ctx->observer = observer;
+
+ return ctx;
+}
+
+static void
+whc_free (WeakHandlerCtx *ctx)
+{
+ g_free (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. */
+/**
+ * spice_glib_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.
+ * Since: 0.43
+ */
+gulong spice_glib_signal_connect_object (gpointer instance,
+ const gchar *detailed_signal,
+ GCallback c_handler,
+ gpointer gobject,
+ GConnectFlags connect_flags)
+{
+ GObject *instance_obj = G_OBJECT (instance);
+
+ 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);
+
+ WeakHandlerCtx *ctx = whc_new (instance_obj, gobject);
+ 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;
+}