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
|
|
|
*
|
|
|
|
* Copyright (C) 2004-2005 by Yevgen Muntyan <muntyan@math.tamu.edu>
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* 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
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
if (!closure->valid)
|
|
|
|
moo_closure_invalidate (closure);
|
|
|
|
|
|
|
|
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;
|
|
|
|
if (!closure->in_call && closure->destroy)
|
|
|
|
closure->destroy (closure);
|
|
|
|
}
|
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
|
|
|
|
2005-11-19 19:59:01 -08:00
|
|
|
if (!type)
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
GValue ret_val;
|
2005-06-22 11:20:32 -07:00
|
|
|
|
2005-11-19 19:59:01 -08:00
|
|
|
if (closure->ret_type != G_TYPE_NONE)
|
|
|
|
{
|
|
|
|
ret_val.g_type = 0;
|
|
|
|
g_value_init (&ret_val, closure->ret_type);
|
|
|
|
}
|
2005-06-22 11:20:32 -07:00
|
|
|
|
2005-11-19 19:59:01 -08:00
|
|
|
g_object_ref (closure->object->target);
|
|
|
|
g_signal_emit (closure->object->target, closure->signal_id, 0);
|
|
|
|
g_object_unref (closure->object->target);
|
2005-06-22 11:20:32 -07:00
|
|
|
|
2005-11-19 19:59:01 -08:00
|
|
|
if (closure->ret_type != G_TYPE_NONE)
|
|
|
|
g_value_unset (&ret_val);
|
2005-06-22 11:20:32 -07:00
|
|
|
}
|
2005-11-14 21:56:39 -08: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_object_ref (object);
|
|
|
|
g_signal_emit_by_name (object, closure->signal, &ret);
|
|
|
|
g_object_unref (object);
|
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;
|
|
|
|
moo_object_ptr_free (cl->object);
|
|
|
|
g_free (cl->signal);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
object_died (MooClosureSignal *cl)
|
2005-06-22 11:20:32 -07:00
|
|
|
{
|
2005-11-19 19:59:01 -08:00
|
|
|
moo_object_ptr_free (cl->object);
|
|
|
|
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
|
|
|
{
|
2005-11-19 19:59:01 -08:00
|
|
|
guint signal_id;
|
|
|
|
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);
|
|
|
|
|
|
|
|
cl->object = moo_object_ptr_new (object, (GWeakNotify) object_died, cl);
|
|
|
|
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;
|
|
|
|
moo_object_ptr_free (cl->object);
|
|
|
|
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;
|
|
|
|
moo_object_ptr_free (tmp);
|
|
|
|
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);
|
|
|
|
cl->object = moo_object_ptr_new (object,
|
|
|
|
(GWeakNotify) closure_simple_object_died,
|
|
|
|
cl);
|
|
|
|
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*
|
|
|
|
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;
|
|
|
|
ptr->target = NULL;
|
|
|
|
ptr->notify (ptr->notify_data, object);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
MooObjectPtr*
|
|
|
|
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);
|
2005-11-19 19:59:01 -08:00
|
|
|
g_return_val_if_fail (notify != NULL, NULL);
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
moo_object_ptr_die (MooObjectPtr *ptr)
|
|
|
|
{
|
|
|
|
if (ptr)
|
|
|
|
{
|
|
|
|
if (ptr->target)
|
|
|
|
g_object_weak_unref (ptr->target, (GWeakNotify) object_ptr_object_died, ptr);
|
|
|
|
ptr->target = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
moo_object_ptr_free (MooObjectPtr *ptr)
|
|
|
|
{
|
|
|
|
moo_object_ptr_die (ptr);
|
|
|
|
g_free (ptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* kate: strip on; indent-width 4; */
|