medit/moo/mooutils/mooclosure.c

371 lines
7.9 KiB
C
Raw Normal View History

2005-06-22 11:20:32 -07:00
/*
2005-11-19 19:59:01 -08:00
* mooclosure.c
2005-06-22 11:20:32 -07:00
*
2007-06-24 10:56:20 -07:00
* Copyright (C) 2004-2007 by Yevgen Muntyan <muntyan@math.tamu.edu>
2005-06-22 11:20:32 -07:00
*
2007-06-24 10:56:20 -07:00
* 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.
2005-06-22 11:20:32 -07:00
*
* See COPYING file that comes with this distribution.
*/
#include "mooutils/mooclosure.h"
#include "mooutils/moomarshals.h"
2005-11-19 19:59:01 -08:00
MooClosure*
moo_closure_alloc (gsize size,
MooClosureCall call,
MooClosureDestroy destroy)
{
MooClosure *cl;
2005-06-22 11:20:32 -07:00
2005-11-19 19:59:01 -08:00
g_return_val_if_fail (size >= sizeof(MooClosure), NULL);
g_return_val_if_fail (call != NULL, NULL);
2005-06-22 11:20:32 -07:00
2005-11-19 19:59:01 -08:00
cl = g_malloc0 (size);
cl->call = call;
cl->destroy = destroy;
cl->ref_count = 1;
cl->floating = TRUE;
cl->valid = TRUE;
2005-06-22 11:20:32 -07:00
2005-11-19 19:59:01 -08:00
return cl;
}
2005-06-22 11:20:32 -07:00
2005-11-19 19:59:01 -08:00
MooClosure *
moo_closure_ref (MooClosure *closure)
{
if (closure)
closure->ref_count++;
return closure;
}
2005-06-22 11:20:32 -07:00
2005-11-19 19:59:01 -08:00
void
moo_closure_unref (MooClosure *closure)
{
if (closure && !--closure->ref_count)
{
moo_closure_invalidate (closure);
g_free (closure);
}
}
2005-06-22 11:20:32 -07:00
2005-11-19 19:59:01 -08:00
void
moo_closure_sink (MooClosure *closure)
{
g_return_if_fail (closure != NULL);
if (closure->floating)
{
closure->floating = FALSE;
moo_closure_unref (closure);
}
}
2005-06-22 11:20:32 -07:00
2006-05-08 21:57:16 -07:00
MooClosure *
moo_closure_ref_sink (MooClosure *closure)
{
moo_closure_ref (closure);
moo_closure_sink (closure);
return closure;
}
2005-11-19 19:59:01 -08:00
void
moo_closure_invoke (MooClosure *closure)
2005-06-22 11:20:32 -07:00
{
2005-11-19 19:59:01 -08:00
g_return_if_fail (closure != NULL);
if (closure->valid)
{
moo_closure_ref (closure);
closure->in_call = TRUE;
closure->call (closure);
closure->in_call = FALSE;
2007-08-06 11:17:25 -07:00
if (!closure->valid && closure->destroy)
closure->destroy (closure);
2005-11-19 19:59:01 -08:00
moo_closure_unref (closure);
}
2005-06-22 11:20:32 -07:00
}
2005-11-19 19:59:01 -08:00
void
moo_closure_invalidate (MooClosure *closure)
2005-06-22 11:20:32 -07:00
{
2005-11-19 19:59:01 -08:00
if (closure && closure->valid)
{
closure->valid = FALSE;
2007-08-06 11:17:25 -07:00
2005-11-19 19:59:01 -08:00
if (!closure->in_call && closure->destroy)
2007-08-06 11:17:25 -07:00
{
2005-11-19 19:59:01 -08:00
closure->destroy (closure);
2007-08-06 11:17:25 -07:00
closure->destroy = (MooClosureDestroy) 0xdeadbeef;
}
2005-11-19 19:59:01 -08:00
}
2005-06-22 11:20:32 -07:00
}
2005-11-19 19:59:01 -08:00
GType
moo_closure_get_type (void)
2005-06-22 11:20:32 -07:00
{
2005-11-19 19:59:01 -08:00
static GType type = 0;
2005-06-22 11:20:32 -07:00
2006-12-30 20:18:14 -08:00
if (G_UNLIKELY (!type))
2005-11-19 19:59:01 -08:00
type = g_boxed_type_register_static ("MooClosure",
(GBoxedCopyFunc) moo_closure_ref,
(GBoxedFreeFunc) moo_closure_unref);
2005-06-22 11:20:32 -07:00
2005-11-19 19:59:01 -08:00
return type;
2005-06-22 11:20:32 -07:00
}
2005-11-19 19:59:01 -08:00
/******************************************************************/
/* MooClosureSignal
*/
typedef struct
2005-06-22 11:20:32 -07:00
{
2005-11-19 19:59:01 -08:00
MooClosure parent;
MooObjectPtr *object;
guint signal_id;
char *signal;
GType ret_type;
gpointer (*proxy) (gpointer);
} MooClosureSignal;
2005-06-22 11:20:32 -07:00
2005-11-19 19:59:01 -08:00
static void
moo_closure_signal_call (MooClosure *cl)
2005-06-22 11:20:32 -07:00
{
2005-11-19 19:59:01 -08:00
MooClosureSignal *closure = (MooClosureSignal*) cl;
if (!closure->proxy)
{
2006-04-20 01:57:05 -07:00
gboolean ret;
g_signal_emit (closure->object->target, closure->signal_id, 0, &ret);
2005-06-22 11:20:32 -07:00
}
else
{
2005-11-19 19:59:01 -08:00
gboolean ret;
gpointer object = closure->proxy (closure->object->target);
g_return_if_fail (object != NULL);
g_signal_emit_by_name (object, closure->signal, &ret);
2005-06-22 11:20:32 -07:00
}
}
2005-11-19 19:59:01 -08:00
static void
moo_closure_signal_destroy (MooClosure *closure)
{
MooClosureSignal *cl = (MooClosureSignal*) closure;
2006-11-03 23:03:45 -08:00
_moo_object_ptr_free (cl->object);
2005-11-19 19:59:01 -08:00
g_free (cl->signal);
}
static void
object_died (MooClosureSignal *cl)
2005-06-22 11:20:32 -07:00
{
2006-11-03 23:03:45 -08:00
_moo_object_ptr_free (cl->object);
2005-11-19 19:59:01 -08:00
cl->object = NULL;
moo_closure_invalidate ((MooClosure*) cl);
2005-06-22 11:20:32 -07:00
}
2005-11-19 19:59:01 -08:00
static MooClosure*
moo_closure_signal_new (gpointer object,
const char *signal,
GCallback proxy_func)
2005-06-22 11:20:32 -07:00
{
guint signal_id = 0;
2005-11-19 19:59:01 -08:00
GSignalQuery query;
MooClosureSignal *cl;
g_return_val_if_fail (G_IS_OBJECT (object), NULL);
g_return_val_if_fail (signal != NULL, NULL);
if (!proxy_func)
{
signal_id = g_signal_lookup (signal, G_OBJECT_TYPE (object));
g_return_val_if_fail (signal_id != 0, NULL);
g_signal_query (signal_id, &query);
2005-06-22 11:20:32 -07:00
2005-11-19 19:59:01 -08:00
if (query.n_params > 0)
{
g_warning ("%s: implement me", G_STRLOC);
return NULL;
}
}
cl = moo_closure_new (MooClosureSignal,
moo_closure_signal_call,
moo_closure_signal_destroy);
2006-11-03 23:03:45 -08:00
cl->object = _moo_object_ptr_new (object, (GWeakNotify) object_died, cl);
2005-11-19 19:59:01 -08:00
cl->proxy = (gpointer (*) (gpointer)) proxy_func;
cl->signal = g_strdup (signal);
if (!proxy_func)
2005-06-22 11:20:32 -07:00
{
2005-11-19 19:59:01 -08:00
cl->signal_id = signal_id;
cl->ret_type = query.return_type & ~(G_SIGNAL_TYPE_STATIC_SCOPE);
2005-06-22 11:20:32 -07:00
}
2005-11-19 19:59:01 -08:00
return (MooClosure*) cl;
2005-06-22 11:20:32 -07:00
}
2005-11-19 19:59:01 -08:00
/******************************************************************/
/* MooClosureSimple
*/
typedef struct
{
MooClosure parent;
MooObjectPtr *object;
gpointer (*proxy) (gpointer);
void (*callback) (gpointer);
} MooClosureSimple;
static void
moo_closure_simple_call (MooClosure *closure)
2005-06-22 11:20:32 -07:00
{
2005-11-19 19:59:01 -08:00
MooClosureSimple *cl = (MooClosureSimple*) closure;
gpointer data = cl->object->target;
if (cl->proxy)
data = cl->proxy (cl->object->target);
g_object_ref (data);
cl->callback (data);
g_object_unref (data);
2005-06-22 11:20:32 -07:00
}
2005-11-19 19:59:01 -08:00
static void
moo_closure_simple_destroy (MooClosure *closure)
{
MooClosureSimple *cl = (MooClosureSimple*) closure;
2006-11-03 23:03:45 -08:00
_moo_object_ptr_free (cl->object);
2005-11-19 19:59:01 -08:00
cl->object = NULL;
}
static void
closure_simple_object_died (MooClosureSimple *cl)
2005-06-22 11:20:32 -07:00
{
2005-11-19 19:59:01 -08:00
MooObjectPtr *tmp = cl->object;
cl->object = NULL;
2006-11-03 23:03:45 -08:00
_moo_object_ptr_free (tmp);
2005-11-19 19:59:01 -08:00
moo_closure_invalidate ((MooClosure*)cl);
2005-06-22 11:20:32 -07:00
}
2005-11-19 19:59:01 -08:00
static MooClosure*
moo_closure_simple_new (gpointer object,
GCallback callback,
GCallback proxy_func)
2005-06-22 11:20:32 -07:00
{
2005-11-19 19:59:01 -08:00
MooClosureSimple *cl;
cl = moo_closure_new (MooClosureSimple,
moo_closure_simple_call,
moo_closure_simple_destroy);
2006-11-03 23:03:45 -08:00
cl->object = _moo_object_ptr_new (object,
(GWeakNotify) closure_simple_object_died,
cl);
2005-11-19 19:59:01 -08:00
cl->callback = (void (*) (gpointer)) callback;
cl->proxy = (gpointer (*) (gpointer)) proxy_func;
return (MooClosure*) cl;
2005-06-22 11:20:32 -07:00
}
2005-11-19 19:59:01 -08:00
MooClosure*
2006-11-03 23:03:45 -08:00
_moo_closure_new_simple (gpointer object,
const char *signal,
GCallback callback,
GCallback proxy_func)
2005-06-22 11:20:32 -07:00
{
g_return_val_if_fail (G_IS_OBJECT (object), NULL);
2005-11-19 19:59:01 -08:00
g_return_val_if_fail (callback || signal, NULL);
g_return_val_if_fail (!callback || !signal, NULL);
if (signal)
return moo_closure_signal_new (object, signal, proxy_func);
else
2005-11-21 00:02:23 -08:00
return moo_closure_simple_new (object, callback, proxy_func);
2005-06-22 11:20:32 -07:00
}
2005-11-19 19:59:01 -08:00
/******************************************************************/
/* MooObjectPtr
*/
static void
object_ptr_object_died (MooObjectPtr *ptr)
{
GObject *object = ptr->target;
2005-11-19 19:59:01 -08:00
ptr->target = NULL;
if (ptr->notify)
ptr->notify (ptr->notify_data, object);
2005-11-19 19:59:01 -08:00
}
MooObjectPtr*
2006-11-03 23:03:45 -08:00
_moo_object_ptr_new (GObject *object,
GWeakNotify notify,
gpointer data)
2005-06-22 11:20:32 -07:00
{
2005-11-19 19:59:01 -08:00
MooObjectPtr *ptr;
2005-06-22 11:20:32 -07:00
g_return_val_if_fail (G_IS_OBJECT (object), NULL);
g_return_val_if_fail (notify != NULL || data == NULL, NULL);
2005-11-19 19:59:01 -08:00
ptr = g_new (MooObjectPtr, 1);
ptr->target = object;
ptr->notify = notify;
ptr->notify_data = data;
g_object_weak_ref (object, (GWeakNotify) object_ptr_object_died, ptr);
return ptr;
2005-06-22 11:20:32 -07:00
}
2005-11-19 19:59:01 -08:00
static void
2006-11-03 23:03:45 -08:00
_moo_object_ptr_die (MooObjectPtr *ptr)
2005-11-19 19:59:01 -08:00
{
if (ptr)
{
if (ptr->target)
g_object_weak_unref (ptr->target, (GWeakNotify) object_ptr_object_died, ptr);
ptr->target = NULL;
}
}
void
2006-11-03 23:03:45 -08:00
_moo_object_ptr_free (MooObjectPtr *ptr)
2005-11-19 19:59:01 -08:00
{
2006-11-03 23:03:45 -08:00
_moo_object_ptr_die (ptr);
2005-11-19 19:59:01 -08:00
g_free (ptr);
}
/* kate: strip on; indent-width 4; */