diff options
Diffstat (limited to 'camel/camel-object.c')
-rw-r--r-- | camel/camel-object.c | 1106 |
1 files changed, 0 insertions, 1106 deletions
diff --git a/camel/camel-object.c b/camel/camel-object.c deleted file mode 100644 index c04415cce9..0000000000 --- a/camel/camel-object.c +++ /dev/null @@ -1,1106 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* camel-object.c: Base class for Camel */ - -/* - * Author: - * Dan Winship <danw@ximian.com> - * - * Copyright 2000 Ximian, Inc. (www.ximian.com) - * - * 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. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <string.h> -#include "camel-object.h" - -#ifdef ENABLE_THREADS -#include <pthread.h> -#include <e-util/e-msgport.h> -#endif - -/* I just mashed the keyboard for these... */ -#define CAMEL_OBJECT_MAGIC_VALUE 0x77A344EF -#define CAMEL_OBJECT_CLASS_MAGIC_VALUE 0xEE26A990 -#define CAMEL_OBJECT_FINALIZED_VALUE 0x84AC3656 -#define CAMEL_OBJECT_CLASS_FINALIZED_VALUE 0x7621ABCD - -#define DEFAULT_PREALLOCS 8 - -#define BAST_CASTARD 1 /* Define to return NULL when casts fail */ - -#define NULL_PREP_VALUE ((gpointer)make_global_classfuncs) /* See camel_object_class_declare_event */ - -/* ** Quickie type system ************************************************* */ - -typedef struct _CamelTypeInfo -{ - CamelType self; - CamelType parent; - const gchar *name; - - size_t instance_size; - GMemChunk *instance_chunk; - CamelObjectInitFunc instance_init; - CamelObjectFinalizeFunc instance_finalize; - GList *free_instances; - - size_t classfuncs_size; - CamelObjectClassInitFunc class_init; - CamelObjectClassFinalizeFunc class_finalize; - CamelObjectClass *global_classfuncs; -} -CamelTypeInfo; - -/* A 'locked' hooklist, that is only allocated on demand */ -typedef struct _CamelHookList { - EMutex *lock; - - unsigned int depth:30; /* recursive event depth */ - unsigned int flags:2; /* flags, see below */ - - unsigned int list_length; - struct _CamelHookPair *list; -} CamelHookList; - -#define CAMEL_HOOK_PAIR_REMOVED (1<<0) - -/* a 'hook pair', actually a hook tuple, we just store all hooked events in the same list, - and just comapre as we go, rather than storing separate lists for each hook type - - the name field just points directly to the key field in the class's preplist hashtable. - This way we can just use a direct pointer compare when scanning it, and also saves - copying the string */ -typedef struct _CamelHookPair -{ - struct _CamelHookPair *next; /* next MUST be the first member */ - - unsigned int flags; /* removed, etc */ - - const char *name; /* points to the key field in the classes preplist, static memory */ - CamelObjectEventHookFunc func; - void *data; -} CamelHookPair; - -/* ************************************************************************ */ - -static void camel_type_lock_up (void); -static void camel_type_lock_down (void); - -static void obj_init (CamelObject * obj); -static void obj_finalize (CamelObject * obj); -static void obj_class_init (CamelObjectClass * class); -static void obj_class_finalize (CamelObjectClass * class); - -static gboolean shared_is_of_type (CamelObjectShared * sh, CamelType ctype, - gboolean is_obj); -static void make_global_classfuncs (CamelTypeInfo * type_info); - -static void camel_object_free_hooks(CamelObject *o); - -/* ************************************************************************ */ - -G_LOCK_DEFINE_STATIC (type_system); -G_LOCK_DEFINE_STATIC (type_system_level); -static GPrivate *type_system_locklevel = NULL; - -G_LOCK_DEFINE_STATIC (refcount); - -static gboolean type_system_initialized = FALSE; -static GHashTable *ctype_to_typeinfo = NULL; -static const CamelType camel_object_type = 1; -static CamelType cur_max_type = CAMEL_INVALID_TYPE; - -/* ************************************************************************ */ - -#define LOCK_VAL (GPOINTER_TO_INT (g_private_get (type_system_locklevel))) -#define LOCK_SET( val ) g_private_set (type_system_locklevel, GINT_TO_POINTER (val)) - -static void -camel_type_lock_up (void) -{ - G_LOCK (type_system_level); - - if (type_system_locklevel == NULL) - type_system_locklevel = g_private_new (GINT_TO_POINTER (0)); - - if (LOCK_VAL == 0) { - G_UNLOCK (type_system_level); - G_LOCK (type_system); - G_LOCK (type_system_level); - } - - LOCK_SET (LOCK_VAL + 1); - - G_UNLOCK (type_system_level); -} - -static void -camel_type_lock_down (void) -{ - G_LOCK (type_system_level); - - if (type_system_locklevel == NULL) { - g_warning - ("camel_type_lock_down: lock down before a lock up?"); - type_system_locklevel = g_private_new (GINT_TO_POINTER (0)); - G_UNLOCK (type_system_level); - return; - } - - LOCK_SET (LOCK_VAL - 1); - - if (LOCK_VAL == 0) - G_UNLOCK (type_system); - - G_UNLOCK (type_system_level); -} - -void -camel_type_init (void) -{ - CamelTypeInfo *obj_info; - - camel_type_lock_up (); - - if (type_system_initialized) { - g_warning - ("camel_type_init: type system already initialized."); - camel_type_lock_down (); - return; - } - - type_system_initialized = TRUE; - ctype_to_typeinfo = g_hash_table_new (g_direct_hash, g_direct_equal); - - obj_info = g_new (CamelTypeInfo, 1); - obj_info->self = camel_object_type; - obj_info->parent = CAMEL_INVALID_TYPE; - obj_info->name = "CamelObject"; - - obj_info->instance_size = sizeof (CamelObject); - obj_info->instance_chunk = - g_mem_chunk_create (CamelObject, DEFAULT_PREALLOCS, - G_ALLOC_ONLY); - obj_info->instance_init = obj_init; - obj_info->instance_finalize = obj_finalize; - obj_info->free_instances = NULL; - - obj_info->classfuncs_size = sizeof (CamelObjectClass); - obj_info->class_init = obj_class_init; - obj_info->class_finalize = obj_class_finalize; - - g_hash_table_insert (ctype_to_typeinfo, - GINT_TO_POINTER (CAMEL_INVALID_TYPE), NULL); - g_hash_table_insert (ctype_to_typeinfo, - GINT_TO_POINTER (camel_object_type), obj_info); - - /* Sigh. Ugly */ - make_global_classfuncs (obj_info); - - cur_max_type = camel_object_type; - - camel_type_lock_down (); -} - -CamelType -camel_type_register (CamelType parent, const gchar * name, - size_t instance_size, size_t classfuncs_size, - CamelObjectClassInitFunc class_init, - CamelObjectClassFinalizeFunc class_finalize, - CamelObjectInitFunc instance_init, - CamelObjectFinalizeFunc instance_finalize) -{ - CamelTypeInfo *parent_info; - CamelTypeInfo *obj_info; - gchar *chunkname; - - g_return_val_if_fail (parent != CAMEL_INVALID_TYPE, - CAMEL_INVALID_TYPE); - g_return_val_if_fail (name, CAMEL_INVALID_TYPE); - g_return_val_if_fail (instance_size, CAMEL_INVALID_TYPE); - g_return_val_if_fail (classfuncs_size, CAMEL_INVALID_TYPE); - - camel_type_lock_up (); - - if (type_system_initialized == FALSE) { - G_UNLOCK (type_system); - camel_type_init (); - G_LOCK (type_system); - } - - parent_info = - g_hash_table_lookup (ctype_to_typeinfo, - GINT_TO_POINTER (parent)); - - if (parent_info == NULL) { - g_warning - ("camel_type_register: no such parent type %d of class `%s'", - parent, name); - camel_type_lock_down (); - return CAMEL_INVALID_TYPE; - } - - if (parent_info->instance_size > instance_size) { - g_warning - ("camel_type_register: instance of class `%s' would be smaller than parent `%s'", - name, parent_info->name); - camel_type_lock_down (); - return CAMEL_INVALID_TYPE; - } - - if (parent_info->classfuncs_size > classfuncs_size) { - g_warning - ("camel_type_register: classfuncs of class `%s' would be smaller than parent `%s'", - name, parent_info->name); - camel_type_lock_down (); - return CAMEL_INVALID_TYPE; - } - - cur_max_type++; - - obj_info = g_new (CamelTypeInfo, 1); - obj_info->self = cur_max_type; - obj_info->parent = parent; - obj_info->name = name; - - obj_info->instance_size = instance_size; - chunkname = - g_strdup_printf ("chunk for instances of Camel type `%s'", - name); - obj_info->instance_chunk = - g_mem_chunk_new (chunkname, instance_size, - instance_size * DEFAULT_PREALLOCS, - G_ALLOC_ONLY); - g_free (chunkname); - obj_info->instance_init = instance_init; - obj_info->instance_finalize = instance_finalize; - obj_info->free_instances = NULL; - - obj_info->classfuncs_size = classfuncs_size; - obj_info->class_init = class_init; - obj_info->class_finalize = class_finalize; - - g_hash_table_insert (ctype_to_typeinfo, - GINT_TO_POINTER (obj_info->self), obj_info); - - /* Sigh. Ugly. */ - make_global_classfuncs (obj_info); - - camel_type_lock_down (); - return obj_info->self; -} - -CamelObjectClass * -camel_type_get_global_classfuncs (CamelType type) -{ - CamelTypeInfo *type_info; - - g_return_val_if_fail (type != CAMEL_INVALID_TYPE, NULL); - - camel_type_lock_up (); - type_info = - g_hash_table_lookup (ctype_to_typeinfo, - GINT_TO_POINTER (type)); - camel_type_lock_down (); - - g_return_val_if_fail (type_info != NULL, NULL); - - return type_info->global_classfuncs; -} - -const gchar * -camel_type_to_name (CamelType type) -{ - CamelTypeInfo *type_info; - - g_return_val_if_fail (type != CAMEL_INVALID_TYPE, - "(the invalid type)"); - - camel_type_lock_up (); - type_info = - g_hash_table_lookup (ctype_to_typeinfo, - GINT_TO_POINTER (type)); - camel_type_lock_down (); - - g_return_val_if_fail (type_info != NULL, - "(a bad type parameter was specified)"); - - return type_info->name; -} - -/* ** The CamelObject ***************************************************** */ - -static void -obj_init (CamelObject * obj) -{ - obj->s.magic = CAMEL_OBJECT_MAGIC_VALUE; - obj->ref_count = 1; - obj->hooks = NULL; - obj->in_event = 0; - obj->destroying = 0; -} - -static void -obj_finalize (CamelObject * obj) -{ - g_return_if_fail (obj->s.magic == CAMEL_OBJECT_MAGIC_VALUE); - g_return_if_fail (obj->ref_count == 0); - g_return_if_fail (obj->in_event == 0); - - obj->s.magic = CAMEL_OBJECT_FINALIZED_VALUE; - - camel_object_free_hooks(obj); -} - -static void -obj_class_init (CamelObjectClass * class) -{ - class->s.magic = CAMEL_OBJECT_CLASS_MAGIC_VALUE; - - camel_object_class_declare_event (class, "finalize", NULL); -} - -static void -obj_class_finalize (CamelObjectClass * class) -{ - g_return_if_fail (class->s.magic == CAMEL_OBJECT_CLASS_MAGIC_VALUE); - - class->s.magic = CAMEL_OBJECT_CLASS_FINALIZED_VALUE; - - if (class->event_to_preplist) { - /* FIXME: This leaks the preplist slist entries */ - g_hash_table_foreach (class->event_to_preplist, - (GHFunc) g_free, NULL); - g_hash_table_destroy (class->event_to_preplist); - class->event_to_preplist = NULL; - } -} - -CamelType -camel_object_get_type (void) -{ - if (type_system_initialized == FALSE) - camel_type_init (); - - return camel_object_type; -} - -CamelObject * -camel_object_new (CamelType type) -{ - CamelTypeInfo *type_info; - GSList *parents = NULL; - GSList *head = NULL; - CamelObject *instance; - - g_return_val_if_fail (type != CAMEL_INVALID_TYPE, NULL); - - /* Look up the type */ - - camel_type_lock_up (); - - type_info = - g_hash_table_lookup (ctype_to_typeinfo, - GINT_TO_POINTER (type)); - - if (type_info == NULL) { - g_warning - ("camel_object_new: trying to create object of invalid type %d", - type); - camel_type_lock_down (); - return NULL; - } - - /* Grab an instance out of the freed ones if possible, alloc otherwise */ - - if (type_info->free_instances) { - GList *first; - - first = g_list_first (type_info->free_instances); - instance = first->data; - type_info->free_instances = - g_list_remove_link (type_info->free_instances, first); - g_list_free_1 (first); - memset (instance, 0, type_info->instance_size); - } else { - instance = g_mem_chunk_alloc0 (type_info->instance_chunk); - } - - /* Init the instance and classfuncs a bit */ - - instance->s.type = type; - instance->classfuncs = type_info->global_classfuncs; - - /* Loop through the parents in simplest -> most complex order, initing the class and instance. - - * When parent = CAMEL_INVALID_TYPE and we're at the end of the line, _lookup returns NULL - * because we inserted it as corresponding to CAMEL_INVALID_TYPE. Clever, eh? - */ - - while (type_info) { - parents = g_slist_prepend (parents, type_info); - type_info = - g_hash_table_lookup (ctype_to_typeinfo, - GINT_TO_POINTER (type_info-> - parent)); - } - - head = parents; - - for (; parents && parents->data; parents = parents->next) { - CamelTypeInfo *thisinfo; - - thisinfo = parents->data; - if (thisinfo->instance_init) - (thisinfo->instance_init) (instance); - } - - g_slist_free (head); - - camel_type_lock_down (); - return instance; -} - -#ifdef camel_object_ref -#undef camel_object_ref -#endif - -void -camel_object_ref (CamelObject * obj) -{ - g_return_if_fail (CAMEL_IS_OBJECT (obj)); - - G_LOCK (refcount); - obj->ref_count++; - G_UNLOCK (refcount); -} - -#ifdef camel_object_unref -#undef camel_object_unref -#endif - -void -camel_object_unref (CamelObject * obj) -{ - CamelTypeInfo *type_info; - CamelTypeInfo *iter; - GSList *parents = NULL; - GSList *head = NULL; - - g_return_if_fail (CAMEL_IS_OBJECT (obj)); - - G_LOCK (refcount); - obj->ref_count--; - - if (obj->ref_count > 0) { - G_UNLOCK (refcount); - return; - } - - G_UNLOCK (refcount); - - /* If the object already had its last unref, do not begin the - * destruction process again. This can happen if, for example, - * the object sends an event in its finalize handler (vfolders - * do this). - */ - - if (obj->destroying) - return; - - obj->destroying = 1; - - /* Send the finalize event */ - - camel_object_trigger_event (obj, "finalize", NULL); - - /* Destroy it! hahaha! */ - - camel_type_lock_up (); - - type_info = - g_hash_table_lookup (ctype_to_typeinfo, - GINT_TO_POINTER (obj->s.type)); - - if (type_info == NULL) { - g_warning - ("camel_object_unref: seemingly valid object has a bad type %d", - obj->s.type); - camel_type_lock_down (); - return; - } - - /* Loop through the parents in most complex -> simplest order, finalizing the class - * and instance. - * - * When parent = CAMEL_INVALID_TYPE and we're at the end of the line, _lookup returns NULL - * because we inserted it as corresponding to CAMEL_INVALID_TYPE. Clever, eh? - * - * Use iter to preserve type_info for free_{instance,classfunc}s - */ - - iter = type_info; - - while (iter) { - parents = g_slist_prepend (parents, iter); - iter = - g_hash_table_lookup (ctype_to_typeinfo, - GINT_TO_POINTER (iter->parent)); - } - - /* ok, done with the type stuff, and our data pointers - * won't go bad. */ - camel_type_lock_down (); - - parents = g_slist_reverse (parents); - head = parents; - - for (; parents && parents->data; parents = parents->next) { - CamelTypeInfo *thisinfo; - - thisinfo = parents->data; - if (thisinfo->instance_finalize) - (thisinfo->instance_finalize) (obj); - } - - g_slist_free (head); - - /* Sanity check */ - - if (obj->ref_count != 0) - g_warning ("camel_object_unref: destroyed object %s at %p somehow got" - " referenced in destruction chain.", - camel_type_to_name (obj->s.type), - obj); - - /* A little bit of cleaning up. - - * Don't erase the type, so we can peek at it if a finalized object - * is check_cast'ed somewhere. Fill it with gunk to help detect - * other invalid ref's of it. - */ - - memset (obj, 0xEB, type_info->instance_size); - obj->s.type = type_info->self; - obj->s.magic = CAMEL_OBJECT_FINALIZED_VALUE; - - /* Tuck away the pointer for use in a new object */ - - camel_type_lock_up (); - - type_info->free_instances = - g_list_prepend (type_info->free_instances, obj); - - camel_type_lock_down (); -} - -gboolean -camel_object_is_of_type (CamelObject * obj, CamelType ctype) -{ - return shared_is_of_type ((CamelObjectShared *) obj, ctype, TRUE); -} - -gboolean -camel_object_class_is_of_type (CamelObjectClass * class, CamelType ctype) -{ - return shared_is_of_type ((CamelObjectShared *) class, ctype, FALSE); -} - -#ifdef BAST_CASTARD -#define ERRVAL NULL -#else -#define ERRVAL obj -#endif - -CamelObject * -camel_object_check_cast (CamelObject * obj, CamelType ctype) -{ - if (shared_is_of_type ((CamelObjectShared *) obj, ctype, TRUE)) - return obj; - return ERRVAL; -} - -CamelObjectClass * -camel_object_class_check_cast (CamelObjectClass * class, CamelType ctype) -{ - if (shared_is_of_type ((CamelObjectShared *) class, ctype, FALSE)) - return class; - return ERRVAL; -} - -#undef ERRVAL - -gchar * -camel_object_describe (CamelObject * obj) -{ - if (obj == NULL) - return g_strdup ("a NULL pointer"); - - if (obj->s.magic == CAMEL_OBJECT_MAGIC_VALUE) { - return g_strdup_printf ("an instance of `%s' at %p", - camel_type_to_name (obj->s.type), - obj); - } else if (obj->s.magic == CAMEL_OBJECT_FINALIZED_VALUE) { - return g_strdup_printf ("a finalized instance of `%s' at %p", - camel_type_to_name (obj->s.type), - obj); - } else if (obj->s.magic == CAMEL_OBJECT_CLASS_MAGIC_VALUE) { - return g_strdup_printf ("the classfuncs of `%s' at %p", - camel_type_to_name (obj->s.type), - obj); - } else if (obj->s.magic == CAMEL_OBJECT_CLASS_FINALIZED_VALUE) { - return - g_strdup_printf - ("the finalized classfuncs of `%s' at %p", - camel_type_to_name (obj->s.type), obj); - } - - return g_strdup ("not a CamelObject"); -} - -/* This is likely to be called in the class_init callback, - * and the type will likely be somewhat uninitialized. - * Is this a problem? We'll see.... - */ -void -camel_object_class_declare_event (CamelObjectClass * class, - const gchar * name, - CamelObjectEventPrepFunc prep) -{ - g_return_if_fail (CAMEL_IS_OBJECT_CLASS (class)); - g_return_if_fail (name); - - if (class->event_to_preplist == NULL) - class->event_to_preplist = - g_hash_table_new (g_str_hash, g_str_equal); - else if (g_hash_table_lookup (class->event_to_preplist, name) != NULL) { - g_warning - ("camel_object_class_declare_event: event `%s' already declared for `%s'", - name, camel_type_to_name (class->s.type)); - return; - } - - /* AIEEEEEEEEEEEEEEEEEEEEEE - - * I feel so naughty. Since it's valid to declare an event and not - * provide a hook, it should be valid to insert a NULL value into - * the table. However, then our lookup in trigger_event would be - * ambiguous, not telling us whether the event is undefined or whether - * it merely has no hook. - * - * So we create an 'NULL prep' value that != NULL... specifically, it - * equals the address of one of our static functions , because that - * can't possibly be your hook. - * - * Just don't forget to check for the 'evil value' and it'll work, - * I promise. - */ - - if (prep == NULL) - prep = NULL_PREP_VALUE; - - g_hash_table_insert (class->event_to_preplist, g_strdup (name), prep); -} - -/* free hook data */ -static void camel_object_free_hooks(CamelObject *o) -{ - CamelHookPair *pair, *next; - - if (o->hooks) { - - g_assert(o->hooks->depth == 0); - g_assert((o->hooks->flags & CAMEL_HOOK_PAIR_REMOVED) == 0); - - pair = o->hooks->list; - while (pair) { - next = pair->next; - g_free(pair); - pair = next; - } - e_mutex_destroy(o->hooks->lock); - g_free(o->hooks); - o->hooks = NULL; - } -} - -/* return (allocate if required) the object's hook list, locking at the same time */ -static CamelHookList *camel_object_get_hooks(CamelObject *o) -{ -#ifdef ENABLE_THREADS - static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; -#endif - CamelHookList *hooks; - - /* if we have it, we dont have to do any other locking, - otherwise use a global lock to setup the object's hook data */ -#ifdef ENABLE_THREADS - if (o->hooks == NULL) { - pthread_mutex_lock(&lock); -#endif - if (o->hooks == NULL) { - hooks = g_malloc(sizeof(*o->hooks)); -#ifdef ENABLE_THREADS - hooks->lock = e_mutex_new(E_MUTEX_REC); -#endif - hooks->flags = 0; - hooks->depth = 0; - hooks->list_length = 0; - hooks->list = NULL; - o->hooks = hooks; - } -#ifdef ENABLE_THREADS - pthread_mutex_unlock(&lock); - } -#endif - -#ifdef ENABLE_THREADS - e_mutex_lock(o->hooks->lock); -#endif - return o->hooks; -} - -/* unlock object hooks' list */ -#ifdef ENABLE_THREADS -#define camel_object_unget_hooks(o) (e_mutex_unlock((CAMEL_OBJECT(o)->hooks->lock))) -#else -#define camel_object_unget_hooks(o) -#endif - -void -camel_object_hook_event (CamelObject * obj, const char * name, - CamelObjectEventHookFunc func, void *data) -{ - CamelHookPair *pair; - const char *prepname; - CamelObjectEventPrepFunc prep; - CamelHookList *hooks; - - g_return_if_fail (CAMEL_IS_OBJECT (obj)); - g_return_if_fail (name != NULL); - g_return_if_fail (func != NULL); - - /* first, does this event exist? */ - if (obj->classfuncs->event_to_preplist == NULL - || !g_hash_table_lookup_extended(obj->classfuncs->event_to_preplist, name, - (void **)&prepname, (void **)&prep)) { - g_warning("camel_object_hook_event: trying to hook event `%s' in class `%s' with no defined events.", - name, camel_type_to_name (obj->s.type)); - return; - } - - /* setup hook pair */ - pair = g_malloc(sizeof(*pair)); - pair->name = prepname; /* effectively static! */ - pair->func = func; - pair->data = data; - pair->flags = 0; - - /* get the hook list object, locked, link in new event hook, unlock */ - hooks = camel_object_get_hooks(obj); - pair->next = hooks->list; - hooks->list = pair; - hooks->list_length++; - camel_object_unget_hooks(obj); -} - -void -camel_object_unhook_event (CamelObject * obj, const char * name, - CamelObjectEventHookFunc func, void *data) -{ - char *prepname; - CamelObjectEventPrepFunc prep; - CamelHookList *hooks; - CamelHookPair *pair, *parent; - - g_return_if_fail (CAMEL_IS_OBJECT (obj)); - g_return_if_fail (name != NULL); - g_return_if_fail (func != NULL); - - if (obj->hooks == NULL) { - g_warning("camel_object_unhook_event: trying to unhook `%s` from an instance of `%s' with no hooks", - name, camel_type_to_name(obj->s.type)); - return; - } - - /* get event name static pointer */ - if (obj->classfuncs->event_to_preplist == NULL - || !g_hash_table_lookup_extended(obj->classfuncs->event_to_preplist, name, - (void **)&prepname, (void **)&prep)) { - g_warning("camel_object_hook_event: trying to hook event `%s' in class `%s' with no defined events.", - name, camel_type_to_name (obj->s.type)); - return; - } - - /* scan hooks for this event, remove it, or flag it if we're busy */ - hooks = camel_object_get_hooks(obj); - parent = (CamelHookPair *)&hooks->list; - pair = parent->next; - while (pair) { - if (pair->name == prepname - && pair->func == func - && pair->data == data - && (pair->flags & CAMEL_HOOK_PAIR_REMOVED) == 0) { - if (hooks->depth > 0) { - pair->flags |= CAMEL_HOOK_PAIR_REMOVED; - hooks->flags |= CAMEL_HOOK_PAIR_REMOVED; - } else { - parent->next = pair->next; - g_free(pair); - hooks->list_length--; - } - camel_object_unget_hooks(obj); - return; - } - parent = pair; - pair = pair->next; - } - camel_object_unget_hooks(obj); - - g_warning("camel_object_unhook_event: cannot find hook/data pair %p/%p in an instance of `%s' attached to `%s'", - func, data, camel_type_to_name (obj->s.type), name); -} - -void -camel_object_trigger_event (CamelObject * obj, const char * name, void *event_data) -{ - CamelObjectEventPrepFunc prep; - const char *prepname; - CamelHookList *hooks; - CamelHookPair *pair, **pairs, *parent; - int i, size; - - g_return_if_fail (CAMEL_IS_OBJECT (obj)); - g_return_if_fail (name); - - /* get event name static pointer/prep func */ - if (obj->classfuncs->event_to_preplist == NULL - || !g_hash_table_lookup_extended(obj->classfuncs->event_to_preplist, name, - (void **)&prepname, (void **)&prep)) { - g_warning("camel_object_hook_event: trying to hook event `%s' in class `%s' with no defined events.", - name, camel_type_to_name (obj->s.type)); - return; - } - - /* try prep function, if false, then quit */ - if (prep != NULL_PREP_VALUE && !prep(obj, event_data)) - return; - - /* also, no hooks, dont bother going further */ - if (obj->hooks == NULL) - return; - - /* lock the object for hook emission */ - camel_object_ref(obj); - hooks = camel_object_get_hooks(obj); - - if (hooks->list) { - /* first, copy the items in the list, and say we're in an event */ - hooks->depth++; - pair = hooks->list; - size = 0; - pairs = alloca(sizeof(pairs[0]) * hooks->list_length); - while (pair) { - if (pair->name == prepname) - pairs[size++] = pair; - pair = pair->next; - } - - /* now execute the events we have, if they haven't been removed during our calls */ - for (i=0;i<size;i++) { - pair = pairs[i]; - if ((pair->flags & CAMEL_HOOK_PAIR_REMOVED) == 0) - (pair->func) (obj, event_data, pair->data); - } - hooks->depth--; - - /* and if we're out of any events, then clean up any pending removes */ - if (hooks->depth == 0 && (hooks->flags & CAMEL_HOOK_PAIR_REMOVED)) { - parent = (CamelHookPair *)&hooks->list; - pair = parent->next; - while (pair) { - if (pair->flags & CAMEL_HOOK_PAIR_REMOVED) { - parent->next = pair->next; - g_free(pair); - hooks->list_length--; - } else { - parent = pair; - } - pair = parent->next; - } - hooks->flags &= ~CAMEL_HOOK_PAIR_REMOVED; - } - } - - camel_object_unget_hooks(obj); - camel_object_unref(obj); -} - -/* ** Static helpers ****************************************************** */ - -static gboolean -shared_is_of_type (CamelObjectShared * sh, CamelType ctype, gboolean is_obj) -{ - CamelTypeInfo *type_info; - gchar *targtype; - - if (is_obj) - targtype = "instance"; - else - targtype = "classdata"; - - if (ctype == CAMEL_INVALID_TYPE) { - g_warning - ("shared_is_of_type: trying to cast to CAMEL_INVALID_TYPE"); - return FALSE; - } - - if (sh == NULL) { - g_warning - ("shared_is_of_type: trying to cast NULL to %s of `%s'", - targtype, camel_type_to_name (ctype)); - return FALSE; - } - - if (sh->magic == CAMEL_OBJECT_FINALIZED_VALUE) { - g_warning - ("shared_is_of_type: trying to cast finalized instance " - "of `%s' into %s of `%s'", - camel_type_to_name (sh->type), targtype, - camel_type_to_name (ctype)); - return FALSE; - } - - if (sh->magic == CAMEL_OBJECT_CLASS_FINALIZED_VALUE) { - g_warning - ("shared_is_of_type: trying to cast finalized classdata " - "of `%s' into %s of `%s'", - camel_type_to_name (sh->type), targtype, - camel_type_to_name (ctype)); - return FALSE; - } - - if (is_obj) { - if (sh->magic == CAMEL_OBJECT_CLASS_MAGIC_VALUE) { - g_warning - ("shared_is_of_type: trying to cast classdata " - "of `%s' into instance of `%s'", - camel_type_to_name (sh->type), - camel_type_to_name (ctype)); - return FALSE; - } - - if (sh->magic != CAMEL_OBJECT_MAGIC_VALUE) { - g_warning - ("shared_is_of_type: trying to cast junk data " - "into instance of `%s'", - camel_type_to_name (ctype)); - return FALSE; - } - } else { - if (sh->magic == CAMEL_OBJECT_MAGIC_VALUE) { - g_warning - ("shared_is_of_type: trying to cast instance " - "of `%s' into classdata of `%s'", - camel_type_to_name (sh->type), - camel_type_to_name (ctype)); - return FALSE; - } - - if (sh->magic != CAMEL_OBJECT_CLASS_MAGIC_VALUE) { - g_warning - ("shared_is_of_type: trying to cast junk data " - "into classdata of `%s'", - camel_type_to_name (ctype)); - return FALSE; - } - } - - camel_type_lock_up (); - - type_info = - g_hash_table_lookup (ctype_to_typeinfo, - GINT_TO_POINTER (sh->type)); - - if (type_info == NULL) { - g_warning ("shared_is_of_type: seemingly valid %s has " - "bad type %d.", targtype, sh->type); - camel_type_lock_down (); - return FALSE; - } - - while (type_info) { - if (type_info->self == ctype) { - camel_type_lock_down (); - return TRUE; - } - - type_info = - g_hash_table_lookup (ctype_to_typeinfo, - GINT_TO_POINTER (type_info-> - parent)); - } - - /* this isn't an error, e.g. CAMEL_IS_FOLDER(folder), its upto the - caller to handle the false case */ - /*g_warning - ("shared_is_of_type: %s of `%s' (@%p) is not also %s of `%s'", - targtype, camel_type_to_name (sh->type), sh, targtype, - camel_type_to_name (ctype));*/ - - camel_type_lock_down (); - return FALSE; -} - -static void -make_global_classfuncs (CamelTypeInfo * type_info) -{ - CamelObjectClass *funcs; - GSList *parents; - GSList *head; - - g_assert (type_info); - - funcs = g_malloc0 (type_info->classfuncs_size); - funcs->s.type = type_info->self; - - type_info->global_classfuncs = funcs; - - parents = NULL; - while (type_info) { - parents = g_slist_prepend (parents, type_info); - type_info = - g_hash_table_lookup (ctype_to_typeinfo, - GINT_TO_POINTER (type_info-> - parent)); - } - - head = parents; - - for (; parents && parents->data; parents = parents->next) { - CamelTypeInfo *thisinfo; - - thisinfo = parents->data; - if (thisinfo->class_init) - (thisinfo->class_init) (funcs); - } - - g_slist_free (head); -} |