diff options
author | Peter Williams <peterw@src.gnome.org> | 2000-08-11 01:30:50 +0800 |
---|---|---|
committer | Peter Williams <peterw@src.gnome.org> | 2000-08-11 01:30:50 +0800 |
commit | 8cb514d6dd9497893a35a089d07a132d51263ee7 (patch) | |
tree | 9f4e5d1f929da7e0be900919753d419fe4c9c61a /camel/camel-object.c | |
parent | bcbb63c59f80eb4e684036c5ef58ab141fb01b03 (diff) | |
download | gsoc2013-evolution-8cb514d6dd9497893a35a089d07a132d51263ee7.tar gsoc2013-evolution-8cb514d6dd9497893a35a089d07a132d51263ee7.tar.gz gsoc2013-evolution-8cb514d6dd9497893a35a089d07a132d51263ee7.tar.bz2 gsoc2013-evolution-8cb514d6dd9497893a35a089d07a132d51263ee7.tar.lz gsoc2013-evolution-8cb514d6dd9497893a35a089d07a132d51263ee7.tar.xz gsoc2013-evolution-8cb514d6dd9497893a35a089d07a132d51263ee7.tar.zst gsoc2013-evolution-8cb514d6dd9497893a35a089d07a132d51263ee7.zip |
Merge with camel-async.
svn path=/trunk/; revision=4687
Diffstat (limited to 'camel/camel-object.c')
-rw-r--r-- | camel/camel-object.c | 949 |
1 files changed, 931 insertions, 18 deletions
diff --git a/camel/camel-object.c b/camel/camel-object.c index 3edce10d8a..849d47612e 100644 --- a/camel/camel-object.c +++ b/camel/camel-object.c @@ -26,32 +26,945 @@ #include <config.h> #include "camel-object.h" +/* 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; + +typedef struct _CamelHookPair +{ + CamelObjectEventHookFunc func; + gpointer user_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); + +/* ************************************************************************ */ + +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_object_init (gpointer object, gpointer klass) +camel_type_lock_up (void) { - GTK_OBJECT_UNSET_FLAGS (object, GTK_FLOATING); + 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); } -GtkType -camel_object_get_type (void) +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)); + 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) { - static GtkType camel_object_type = 0; + 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 (!camel_object_type) { - GtkTypeInfo camel_object_info = - { - "CamelObject", - sizeof (CamelObject), - sizeof (CamelObjectClass), - (GtkClassInitFunc) NULL, - (GtkObjectInitFunc) camel_object_init, - /* reserved_1 */ NULL, - /* reserved_2 */ NULL, - (GtkClassInitFunc) NULL, - }; + 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)); - camel_object_type = gtk_type_unique (gtk_object_get_type (), &camel_object_info); + 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->event_to_hooklist = NULL; + obj->in_event = 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; + + if (obj->event_to_hooklist) { + g_hash_table_foreach (obj->event_to_hooklist, (GHFunc) g_free, + NULL); + g_hash_table_destroy (obj->event_to_hooklist); + obj->event_to_hooklist = NULL; + } +} + +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) { + 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); + } 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; +} + +void +camel_object_ref (CamelObject * obj) +{ + g_return_if_fail (CAMEL_IS_OBJECT (obj)); + + G_LOCK (refcount); + obj->ref_count++; + G_UNLOCK (refcount); +} + +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); + + /* Oh no! We want to emit a "finalized" event, but that function refs the object + * because it's not supposed to get finalized in an event, but it is being finalized + * right now, and AAUGH AAUGH AUGH AUGH! + * + * So we don't call camel_object_trigger_event. We do it ourselves. We even know + * that CamelObject doesn't provide a prep for the finalized event, so we plunge + * right in and call our hooks. + * + * And there was much rejoicing. + */ + +#define hooklist parents /*cough */ + + if (obj->event_to_hooklist) { + CamelHookPair *pair; + + hooklist = + g_hash_table_lookup (obj->event_to_hooklist, + "finalize"); + + while (hooklist && hooklist->data) { + pair = hooklist->data; + (pair->func) (obj, NULL, pair->user_data); + hooklist = hooklist->next; + } + } + + hooklist = NULL; /* Don't mess with this line */ + +#undef hooklist + + /* 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)); + } + + 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); + + /* 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. + */ + + memset (obj, 0, 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 */ + + 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); +} + +void +camel_object_hook_event (CamelObject * obj, const gchar * name, + CamelObjectEventHookFunc hook, gpointer user_data) +{ + GSList *hooklist; + CamelHookPair *pair; + + g_return_if_fail (CAMEL_IS_OBJECT (obj)); + g_return_if_fail (name); + g_return_if_fail (hook); + + if (obj->event_to_hooklist == NULL) + obj->event_to_hooklist = + g_hash_table_new (g_str_hash, g_str_equal); + + pair = g_new (CamelHookPair, 1); + pair->func = hook; + pair->user_data = user_data; + + hooklist = g_hash_table_lookup (obj->event_to_hooklist, name); + hooklist = g_slist_prepend (hooklist, pair); + g_hash_table_insert (obj->event_to_hooklist, g_strdup (name), + hooklist); +} + +void +camel_object_unhook_event (CamelObject * obj, const gchar * name, + CamelObjectEventHookFunc hook, gpointer user_data) +{ + GSList *hooklist; + GSList *head; + + g_return_if_fail (CAMEL_IS_OBJECT (obj)); + g_return_if_fail (name); + g_return_if_fail (hook); + + if (obj->event_to_hooklist == NULL) { + g_warning + ("camel_object_unhook_event: trying to unhook `%s' from an instance " + "of `%s' with no hooks attached", name, + camel_type_to_name (obj->s.type)); + return; + } + + hooklist = g_hash_table_lookup (obj->event_to_hooklist, name); + + if (hooklist == NULL) { + g_warning + ("camel_object_unhook_event: trying to unhook `%s' from an instance " + "of `%s' with no hooks attached to that event.", + name, camel_type_to_name (obj->s.type)); + return; + } + + head = hooklist; + + while (hooklist) { + CamelHookPair *pair = (CamelHookPair *) hooklist->data; + + if (pair->func == hook && pair->user_data == user_data) { + g_free (hooklist->data); + head = g_slist_remove_link (head, hooklist); + g_slist_free_1 (hooklist); + g_hash_table_insert (obj->event_to_hooklist, name, + head); + return; + } + + hooklist = hooklist->next; + } + + g_warning + ("camel_object_unhook_event: cannot find hook/data pair %p/%p in an " + "instance of `%s' attached to `%s'", hook, user_data, + camel_type_to_name (obj->s.type), name); +} + +void +camel_object_trigger_event (CamelObject * obj, const gchar * name, + gpointer event_data) +{ + GSList *hooklist; + CamelHookPair *pair; + CamelObjectEventPrepFunc prep; + + g_return_if_fail (CAMEL_IS_OBJECT (obj)); + g_return_if_fail (name); + + if (obj->in_event) { + g_warning + ("camel_object_trigger_event: trying to trigger `%s' in class " + "`%s' while already triggering another event", name, + camel_type_to_name (obj->s.type)); + return; + } + + if (obj->classfuncs->event_to_preplist == NULL) { + g_warning + ("camel_object_trigger_event: trying to trigger `%s' in class " + "`%s' with no defined events.", name, + camel_type_to_name (obj->s.type)); + return; + } + + prep = g_hash_table_lookup (obj->classfuncs->event_to_preplist, name); + + if (prep == NULL) { + g_warning + ("camel_object_trigger_event: trying to trigger undefined " + "event `%s' in class `%s'.", name, + camel_type_to_name (obj->s.type)); + return; + } + + /* Ref so that it can't get destroyed in the event, which would + * be Bad. And it's a valid ref anyway... + */ + + camel_object_ref (obj); + obj->in_event = 1; + + if ((prep != NULL_PREP_VALUE && !prep (obj, event_data)) + || obj->event_to_hooklist == NULL) { + obj->in_event = 0; + camel_object_unref (obj); + return; + } + + hooklist = g_hash_table_lookup (obj->event_to_hooklist, name); + + while (hooklist && hooklist->data) { + pair = hooklist->data; + (pair->func) (obj, event_data, pair->user_data); + hooklist = hooklist->next; + } + + obj->in_event = 0; + 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)); + } + + 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); +} |