/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
Copyright (C) 2010 Red Hat, Inc.
Copyright © 2006-2010 Collabora Ltd.
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 .
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include
#include "spice-util.h"
/**
* SECTION:spice-util
* @short_description: version and debugging functions
* @title: Utilities
* @section_id:
* @stability: Stable
* @include: spice-util.h
*
* Various functions for debugging and informational purposes.
*/
static gboolean debugFlag = FALSE;
/**
* spice_util_set_debug:
* @enabled: %TRUE or %FALSE
*
* Enable or disable Spice-GTK debugging messages.
**/
void spice_util_set_debug(gboolean enabled)
{
debugFlag = enabled;
}
gboolean spice_util_get_debug(void)
{
return debugFlag || g_getenv("SPICE_DEBUG") != NULL;
}
/**
* spice_util_get_version_string:
*
* Returns: Spice-GTK version as a const string.
**/
const gchar *spice_util_get_version_string(void)
{
return VERSION;
}
G_GNUC_INTERNAL
gboolean spice_strv_contains(const GStrv strv, const gchar *str)
{
int i;
if (strv == NULL)
return FALSE;
for (i = 0; strv[i] != NULL; i++)
if (g_str_equal(strv[i], str))
return TRUE;
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;
}