medit/moo/mooutils/mooclosure.c

335 lines
12 KiB
C

/*
* mooutils/mooclosure.c
*
* 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"
#include "mooutils/moocompat.h"
static void moo_closure_class_init (MooClosureClass *klass);
static GObject *moo_closure_constructor (GType type,
guint n_construct_properties,
GObjectConstructParam *construct_param);
static void moo_closure_init (MooClosure *closure);
static void moo_closure_finalize (GObject *object);
static void moo_closure_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec);
static void moo_closure_invoke_real (MooClosure *closure);
static void moo_closure_object_destroyed (MooClosure *closure,
gpointer object);
enum {
PROP_0,
PROP_OBJECT,
PROP_SIGNAL,
PROP_CALLBACK,
PROP_PROXY_FUNC,
PROP_DATA
};
enum {
INVOKE,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL] = {0};
G_DEFINE_TYPE(MooClosure, moo_closure, GTK_TYPE_OBJECT)
static void moo_closure_class_init (MooClosureClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
gobject_class->constructor = moo_closure_constructor;
gobject_class->finalize = moo_closure_finalize;
gobject_class->set_property = moo_closure_set_property;
klass->invoke = moo_closure_invoke_real;
g_object_class_install_property (gobject_class,
PROP_OBJECT,
g_param_spec_boolean
("object",
"object",
"object",
FALSE,
G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property (gobject_class,
PROP_SIGNAL,
g_param_spec_string
("signal",
"signal",
"signal",
NULL,
G_PARAM_WRITABLE | G_PARAM_CONSTRUCT));
g_object_class_install_property (gobject_class,
PROP_CALLBACK,
g_param_spec_pointer
("callback",
"callback",
"callback",
G_PARAM_WRITABLE | G_PARAM_CONSTRUCT));
g_object_class_install_property (gobject_class,
PROP_PROXY_FUNC,
g_param_spec_pointer
("proxy-func",
"proxy-func",
"proxy-func",
G_PARAM_WRITABLE | G_PARAM_CONSTRUCT));
g_object_class_install_property (gobject_class,
PROP_DATA,
g_param_spec_pointer
("data",
"data",
"data",
G_PARAM_WRITABLE | G_PARAM_CONSTRUCT));
signals[INVOKE] =
g_signal_new ("invoke",
G_OBJECT_CLASS_TYPE (klass),
(GSignalFlags) (G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
G_STRUCT_OFFSET (MooClosureClass, invoke),
NULL, NULL,
_moo_marshal_VOID__VOID,
G_TYPE_NONE, 0);
}
static void moo_closure_init (MooClosure *closure)
{
closure->callback = NULL;
closure->proxy_func = NULL;
closure->object = FALSE;
closure->signal = NULL;
closure->data = NULL;
closure->valid = TRUE;
closure->constructed = FALSE;
}
static GObject *moo_closure_constructor (GType type,
guint n_construct_properties,
GObjectConstructParam *construct_param)
{
GObject *object;
MooClosure *closure;
object = G_OBJECT_CLASS (moo_closure_parent_class)->constructor (
type, n_construct_properties, construct_param);
g_return_val_if_fail (object != NULL, NULL);
closure = MOO_CLOSURE (object);
if (closure->object && closure->data)
g_object_weak_ref (G_OBJECT (closure->data),
(GWeakNotify) moo_closure_object_destroyed,
closure);
closure->constructed = TRUE;
return object;
}
static void moo_closure_finalize (GObject *object)
{
MooClosure *closure = MOO_CLOSURE (object);
g_return_if_fail (closure != NULL);
if (closure->object && G_IS_OBJECT (closure->data) && closure->valid)
g_object_weak_unref (G_OBJECT (closure->data),
(GWeakNotify) moo_closure_object_destroyed,
closure);
g_free (closure->signal);
closure->valid = FALSE;
G_OBJECT_CLASS (moo_closure_parent_class)->finalize (object);
}
static void moo_closure_invoke_real (MooClosure *closure)
{
gpointer data = closure->data;
g_return_if_fail (closure->valid);
g_return_if_fail (closure->callback || closure->signal);
if (closure->proxy_func) {
data = closure->proxy_func (closure->data);
g_return_if_fail (G_IS_OBJECT (data));
}
if (closure->signal) {
g_object_ref (G_OBJECT (data));
g_signal_emit_by_name (data, closure->signal);
g_object_unref (G_OBJECT (data));
}
else if (closure->object) {
g_object_ref (G_OBJECT (data));
closure->callback (data);
g_object_unref (G_OBJECT (data));
}
else {
closure->callback (data);
}
}
void moo_closure_invoke (MooClosure *closure)
{
g_return_if_fail (MOO_IS_CLOSURE (closure));
g_signal_emit (closure, signals[INVOKE], 0);
}
static void moo_closure_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
MooClosure *closure = MOO_CLOSURE (object);
switch (prop_id)
{
case PROP_OBJECT:
closure->object = g_value_get_boolean (value);
break;
case PROP_SIGNAL:
g_free (closure->signal);
closure->signal = g_strdup (g_value_get_string (value));
if (closure->signal) closure->object = TRUE;
break;
case PROP_CALLBACK:
closure->callback = (void(*)(gpointer))g_value_get_pointer (value);
break;
case PROP_PROXY_FUNC:
closure->proxy_func = (gpointer(*)(gpointer))g_value_get_pointer (value);
break;
case PROP_DATA:
if (!closure->constructed) {
closure->data = g_value_get_pointer (value);
}
else {
if (closure->data && closure->object) {
g_object_weak_unref (G_OBJECT (closure->data),
(GWeakNotify) moo_closure_object_destroyed,
closure);
}
closure->data = g_value_get_pointer (value);
if (closure->data && closure->object) {
g_object_weak_ref (G_OBJECT (closure->data),
(GWeakNotify) moo_closure_object_destroyed,
closure);
}
}
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
void moo_closure_invalidate (MooClosure *closure)
{
g_return_if_fail (MOO_IS_CLOSURE (closure));
if (closure->object && G_IS_OBJECT (closure->data))
g_object_weak_unref (G_OBJECT (closure->data),
(GWeakNotify) moo_closure_object_destroyed,
closure);
closure->data = NULL;
closure->object = FALSE;
closure->valid = FALSE;
}
static void moo_closure_object_destroyed (MooClosure *closure,
G_GNUC_UNUSED gpointer object)
{
g_assert (closure->data == object);
closure->object = FALSE;
moo_closure_invalidate (closure);
}
MooClosure *moo_closure_new (GCallback callback_func,
gpointer data)
{
return MOO_CLOSURE (g_object_new (MOO_TYPE_CLOSURE,
"callback", callback_func,
"data", data,
NULL));
}
MooClosure *moo_closure_new_object (GCallback callback_func,
gpointer object)
{
g_return_val_if_fail (callback_func != NULL, NULL);
g_return_val_if_fail (G_IS_OBJECT (object), NULL);
return MOO_CLOSURE (g_object_new (MOO_TYPE_CLOSURE,
"callback", callback_func,
"data", object,
"object", TRUE,
NULL));
}
MooClosure *moo_closure_new_signal (const char *signal,
gpointer object)
{
g_return_val_if_fail (signal != NULL, NULL);
g_return_val_if_fail (G_IS_OBJECT (object), NULL);
return MOO_CLOSURE (g_object_new (MOO_TYPE_CLOSURE,
"signal", signal,
"data", object,
NULL));
}
MooClosure *moo_closure_new_proxy (GCallback callback_func,
GCallback proxy_func,
gpointer object)
{
g_return_val_if_fail (callback_func != NULL && proxy_func != NULL, NULL);
g_return_val_if_fail (G_IS_OBJECT (object), NULL);
return MOO_CLOSURE (g_object_new (MOO_TYPE_CLOSURE,
"callback", callback_func,
"proxy_func", proxy_func,
"data", object,
"object", TRUE,
NULL));
}
MooClosure *moo_closure_new_proxy_signal (const char *signal,
GCallback proxy_func,
gpointer object)
{
g_return_val_if_fail (signal != NULL && proxy_func != NULL, NULL);
g_return_val_if_fail (G_IS_OBJECT (object), NULL);
return MOO_CLOSURE (g_object_new (MOO_TYPE_CLOSURE,
"signal", signal,
"proxy_func", proxy_func,
"data", object,
"object", TRUE,
NULL));
}