1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /* camel-object.c: Base class for Camel */
6 * Dan Winship <danw@ximian.com>
8 * Copyright 2000 Ximian, Inc. (www.ximian.com)
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of version 2 of the GNU General Public
12 * License as published by the Free Software Foundation.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
30 #include "camel-object.h"
34 #include <e-util/e-msgport.h>
37 /* I just mashed the keyboard for these... */
38 #define CAMEL_OBJECT_MAGIC_VALUE 0x77A344EF
39 #define CAMEL_OBJECT_CLASS_MAGIC_VALUE 0xEE26A990
40 #define CAMEL_OBJECT_FINALIZED_VALUE 0x84AC3656
41 #define CAMEL_OBJECT_CLASS_FINALIZED_VALUE 0x7621ABCD
43 #define DEFAULT_PREALLOCS 8
45 #define BAST_CASTARD 1 /* Define to return NULL when casts fail */
47 #define NULL_PREP_VALUE ((gpointer)make_global_classfuncs) /* See camel_object_class_declare_event */
49 /* ** Quickie type system ************************************************* */
51 typedef struct _CamelTypeInfo
58 GMemChunk *instance_chunk;
59 CamelObjectInitFunc instance_init;
60 CamelObjectFinalizeFunc instance_finalize;
61 GList *free_instances;
63 size_t classfuncs_size;
64 CamelObjectClassInitFunc class_init;
65 CamelObjectClassFinalizeFunc class_finalize;
66 CamelObjectClass *global_classfuncs;
70 /* A 'locked' hooklist, that is only allocated on demand */
71 typedef struct _CamelHookList {
74 unsigned int depth:30; /* recursive event depth */
75 unsigned int flags:2; /* flags, see below */
77 unsigned int list_length;
78 struct _CamelHookPair *list;
81 #define CAMEL_HOOK_PAIR_REMOVED (1<<0)
83 /* a 'hook pair', actually a hook tuple, we just store all hooked events in the same list,
84 and just comapre as we go, rather than storing separate lists for each hook type
86 the name field just points directly to the key field in the class's preplist hashtable.
87 This way we can just use a direct pointer compare when scanning it, and also saves
89 typedef struct _CamelHookPair
91 struct _CamelHookPair *next; /* next MUST be the first member */
93 unsigned int flags; /* removed, etc */
95 const char *name; /* points to the key field in the classes preplist, static memory */
96 CamelObjectEventHookFunc func;
100 /* ************************************************************************ */
102 static void camel_type_lock_up (void);
103 static void camel_type_lock_down (void);
105 static void obj_init (CamelObject * obj);
106 static void obj_finalize (CamelObject * obj);
107 static void obj_class_init (CamelObjectClass * class);
108 static void obj_class_finalize (CamelObjectClass * class);
110 static gboolean shared_is_of_type (CamelObjectShared * sh, CamelType ctype,
112 static void make_global_classfuncs (CamelTypeInfo * type_info);
114 static void camel_object_free_hooks(CamelObject *o);
116 /* ************************************************************************ */
118 G_LOCK_DEFINE_STATIC (type_system);
119 G_LOCK_DEFINE_STATIC (type_system_level);
120 static GPrivate *type_system_locklevel = NULL;
122 G_LOCK_DEFINE_STATIC (refcount);
124 static gboolean type_system_initialized = FALSE;
125 static GHashTable *ctype_to_typeinfo = NULL;
126 static GHashTable *name_to_typeinfo = NULL;
127 static const CamelType camel_object_type = 1;
128 static CamelType cur_max_type = CAMEL_INVALID_TYPE;
130 /* ************************************************************************ */
132 #define LOCK_VAL (GPOINTER_TO_INT (g_private_get (type_system_locklevel)))
133 #define LOCK_SET( val ) g_private_set (type_system_locklevel, GINT_TO_POINTER (val))
136 camel_type_lock_up (void)
138 G_LOCK (type_system_level);
140 if (type_system_locklevel == NULL)
141 type_system_locklevel = g_private_new (GINT_TO_POINTER (0));
144 G_UNLOCK (type_system_level);
145 G_LOCK (type_system);
146 G_LOCK (type_system_level);
149 LOCK_SET (LOCK_VAL + 1);
151 G_UNLOCK (type_system_level);
155 camel_type_lock_down (void)
157 G_LOCK (type_system_level);
159 if (type_system_locklevel == NULL) {
161 ("camel_type_lock_down: lock down before a lock up?");
162 type_system_locklevel = g_private_new (GINT_TO_POINTER (0));
163 G_UNLOCK (type_system_level);
167 LOCK_SET (LOCK_VAL - 1);
170 G_UNLOCK (type_system);
172 G_UNLOCK (type_system_level);
176 camel_type_init (void)
178 CamelTypeInfo *obj_info;
180 camel_type_lock_up ();
182 if (type_system_initialized) {
183 g_warning ("camel_type_init: type system already initialized.");
184 camel_type_lock_down ();
188 type_system_initialized = TRUE;
189 ctype_to_typeinfo = g_hash_table_new (g_direct_hash, g_direct_equal);
190 name_to_typeinfo = g_hash_table_new (g_str_hash, g_str_equal);
192 obj_info = g_new (CamelTypeInfo, 1);
193 obj_info->self = camel_object_type;
194 obj_info->parent = CAMEL_INVALID_TYPE;
195 obj_info->name = "CamelObject";
197 obj_info->instance_size = sizeof (CamelObject);
198 obj_info->instance_chunk =
199 g_mem_chunk_create (CamelObject, DEFAULT_PREALLOCS,
201 obj_info->instance_init = obj_init;
202 obj_info->instance_finalize = obj_finalize;
203 obj_info->free_instances = NULL;
205 obj_info->classfuncs_size = sizeof (CamelObjectClass);
206 obj_info->class_init = obj_class_init;
207 obj_info->class_finalize = obj_class_finalize;
209 g_hash_table_insert (ctype_to_typeinfo,
210 GINT_TO_POINTER (CAMEL_INVALID_TYPE), NULL);
211 g_hash_table_insert (ctype_to_typeinfo,
212 GINT_TO_POINTER (camel_object_type), obj_info);
213 g_hash_table_insert (name_to_typeinfo, (gpointer) obj_info->name, obj_info);
216 make_global_classfuncs (obj_info);
218 cur_max_type = camel_object_type;
220 camel_type_lock_down ();
224 camel_type_register (CamelType parent, const gchar * name,
225 size_t instance_size, size_t classfuncs_size,
226 CamelObjectClassInitFunc class_init,
227 CamelObjectClassFinalizeFunc class_finalize,
228 CamelObjectInitFunc instance_init,
229 CamelObjectFinalizeFunc instance_finalize)
231 CamelTypeInfo *parent_info;
232 CamelTypeInfo *obj_info;
235 g_return_val_if_fail (parent != CAMEL_INVALID_TYPE,
237 g_return_val_if_fail (name, CAMEL_INVALID_TYPE);
238 g_return_val_if_fail (instance_size, CAMEL_INVALID_TYPE);
239 g_return_val_if_fail (classfuncs_size, CAMEL_INVALID_TYPE);
241 camel_type_lock_up ();
243 if (type_system_initialized == FALSE) {
244 G_UNLOCK (type_system);
246 G_LOCK (type_system);
249 obj_info = g_hash_table_lookup (name_to_typeinfo, name);
250 if (obj_info != NULL) {
251 /* looks like we've already registered this type... */
252 camel_type_lock_down ();
253 return obj_info->self;
257 g_hash_table_lookup (ctype_to_typeinfo,
258 GINT_TO_POINTER (parent));
260 if (parent_info == NULL) {
262 ("camel_type_register: no such parent type %d of class `%s'",
264 camel_type_lock_down ();
265 return CAMEL_INVALID_TYPE;
268 if (parent_info->instance_size > instance_size) {
270 ("camel_type_register: instance of class `%s' would be smaller than parent `%s'",
271 name, parent_info->name);
272 camel_type_lock_down ();
273 return CAMEL_INVALID_TYPE;
276 if (parent_info->classfuncs_size > classfuncs_size) {
278 ("camel_type_register: classfuncs of class `%s' would be smaller than parent `%s'",
279 name, parent_info->name);
280 camel_type_lock_down ();
281 return CAMEL_INVALID_TYPE;
286 obj_info = g_new (CamelTypeInfo, 1);
287 obj_info->self = cur_max_type;
288 obj_info->parent = parent;
289 obj_info->name = name;
291 obj_info->instance_size = instance_size;
293 g_strdup_printf ("chunk for instances of Camel type `%s'",
295 obj_info->instance_chunk =
296 g_mem_chunk_new (chunkname, instance_size,
297 instance_size * DEFAULT_PREALLOCS,
300 obj_info->instance_init = instance_init;
301 obj_info->instance_finalize = instance_finalize;
302 obj_info->free_instances = NULL;
304 obj_info->classfuncs_size = classfuncs_size;
305 obj_info->class_init = class_init;
306 obj_info->class_finalize = class_finalize;
308 g_hash_table_insert (ctype_to_typeinfo,
309 GINT_TO_POINTER (obj_info->self), obj_info);
310 g_hash_table_insert (name_to_typeinfo, (gpointer) obj_info->name, obj_info);
313 make_global_classfuncs (obj_info);
315 camel_type_lock_down ();
316 return obj_info->self;
320 camel_type_get_global_classfuncs (CamelType type)
322 CamelTypeInfo *type_info;
324 g_return_val_if_fail (type != CAMEL_INVALID_TYPE, NULL);
326 camel_type_lock_up ();
328 g_hash_table_lookup (ctype_to_typeinfo,
329 GINT_TO_POINTER (type));
330 camel_type_lock_down ();
332 g_return_val_if_fail (type_info != NULL, NULL);
334 return type_info->global_classfuncs;
338 camel_type_to_name (CamelType type)
340 CamelTypeInfo *type_info;
342 g_return_val_if_fail (type != CAMEL_INVALID_TYPE,
343 "(the invalid type)");
345 camel_type_lock_up ();
347 g_hash_table_lookup (ctype_to_typeinfo,
348 GINT_TO_POINTER (type));
349 camel_type_lock_down ();
351 g_return_val_if_fail (type_info != NULL,
352 "(a bad type parameter was specified)");
354 return type_info->name;
357 /* ** The CamelObject ***************************************************** */
360 obj_init (CamelObject * obj)
362 obj->s.magic = CAMEL_OBJECT_MAGIC_VALUE;
370 obj_finalize (CamelObject * obj)
372 g_return_if_fail (obj->s.magic == CAMEL_OBJECT_MAGIC_VALUE);
373 g_return_if_fail (obj->ref_count == 0);
374 g_return_if_fail (obj->in_event == 0);
376 obj->s.magic = CAMEL_OBJECT_FINALIZED_VALUE;
378 camel_object_free_hooks(obj);
382 obj_class_init (CamelObjectClass * class)
384 class->s.magic = CAMEL_OBJECT_CLASS_MAGIC_VALUE;
386 camel_object_class_declare_event (class, "finalize", NULL);
390 obj_class_finalize (CamelObjectClass * class)
392 g_return_if_fail (class->s.magic == CAMEL_OBJECT_CLASS_MAGIC_VALUE);
394 class->s.magic = CAMEL_OBJECT_CLASS_FINALIZED_VALUE;
396 if (class->event_to_preplist) {
397 /* FIXME: This leaks the preplist slist entries */
398 g_hash_table_foreach (class->event_to_preplist,
399 (GHFunc) g_free, NULL);
400 g_hash_table_destroy (class->event_to_preplist);
401 class->event_to_preplist = NULL;
406 camel_object_get_type (void)
408 if (type_system_initialized == FALSE)
411 return camel_object_type;
415 camel_object_new (CamelType type)
417 CamelTypeInfo *type_info;
418 GSList *parents = NULL;
420 CamelObject *instance;
422 g_return_val_if_fail (type != CAMEL_INVALID_TYPE, NULL);
424 /* Look up the type */
426 camel_type_lock_up ();
429 g_hash_table_lookup (ctype_to_typeinfo,
430 GINT_TO_POINTER (type));
432 if (type_info == NULL) {
434 ("camel_object_new: trying to create object of invalid type %d",
436 camel_type_lock_down ();
440 /* Grab an instance out of the freed ones if possible, alloc otherwise */
442 if (type_info->free_instances) {
445 first = g_list_first (type_info->free_instances);
446 instance = first->data;
447 type_info->free_instances =
448 g_list_remove_link (type_info->free_instances, first);
449 g_list_free_1 (first);
450 memset (instance, 0, type_info->instance_size);
452 instance = g_mem_chunk_alloc0 (type_info->instance_chunk);
455 /* Init the instance and classfuncs a bit */
457 instance->s.type = type;
458 instance->classfuncs = type_info->global_classfuncs;
460 /* Loop through the parents in simplest -> most complex order, initing the class and instance.
462 * When parent = CAMEL_INVALID_TYPE and we're at the end of the line, _lookup returns NULL
463 * because we inserted it as corresponding to CAMEL_INVALID_TYPE. Clever, eh?
467 parents = g_slist_prepend (parents, type_info);
469 g_hash_table_lookup (ctype_to_typeinfo,
470 GINT_TO_POINTER (type_info->
476 for (; parents && parents->data; parents = parents->next) {
477 CamelTypeInfo *thisinfo;
479 thisinfo = parents->data;
480 if (thisinfo->instance_init)
481 (thisinfo->instance_init) (instance);
486 camel_type_lock_down ();
490 #ifdef camel_object_ref
491 #undef camel_object_ref
495 camel_object_ref (CamelObject * obj)
497 g_return_if_fail (CAMEL_IS_OBJECT (obj));
504 #ifdef camel_object_unref
505 #undef camel_object_unref
509 camel_object_unref (CamelObject * obj)
511 CamelTypeInfo *type_info;
513 GSList *parents = NULL;
516 g_return_if_fail (CAMEL_IS_OBJECT (obj));
521 if (obj->ref_count > 0) {
528 /* If the object already had its last unref, do not begin the
529 * destruction process again. This can happen if, for example,
530 * the object sends an event in its finalize handler (vfolders
539 /* Send the finalize event */
541 camel_object_trigger_event (obj, "finalize", NULL);
543 /* Destroy it! hahaha! */
545 camel_type_lock_up ();
548 g_hash_table_lookup (ctype_to_typeinfo,
549 GINT_TO_POINTER (obj->s.type));
551 if (type_info == NULL) {
553 ("camel_object_unref: seemingly valid object has a bad type %d",
555 camel_type_lock_down ();
559 /* Loop through the parents in most complex -> simplest order, finalizing the class
562 * When parent = CAMEL_INVALID_TYPE and we're at the end of the line, _lookup returns NULL
563 * because we inserted it as corresponding to CAMEL_INVALID_TYPE. Clever, eh?
565 * Use iter to preserve type_info for free_{instance,classfunc}s
571 parents = g_slist_prepend (parents, iter);
573 g_hash_table_lookup (ctype_to_typeinfo,
574 GINT_TO_POINTER (iter->parent));
577 /* ok, done with the type stuff, and our data pointers
579 camel_type_lock_down ();
581 parents = g_slist_reverse (parents);
584 for (; parents && parents->data; parents = parents->next) {
585 CamelTypeInfo *thisinfo;
587 thisinfo = parents->data;
588 if (thisinfo->instance_finalize)
589 (thisinfo->instance_finalize) (obj);
596 if (obj->ref_count != 0)
597 g_warning ("camel_object_unref: destroyed object %s at %p somehow got"
598 " referenced in destruction chain.",
599 camel_type_to_name (obj->s.type),
602 /* A little bit of cleaning up.
604 * Don't erase the type, so we can peek at it if a finalized object
605 * is check_cast'ed somewhere. Fill it with gunk to help detect
606 * other invalid ref's of it.
609 memset (obj, 0xEB, type_info->instance_size);
610 obj->s.type = type_info->self;
611 obj->s.magic = CAMEL_OBJECT_FINALIZED_VALUE;
613 /* Tuck away the pointer for use in a new object */
615 camel_type_lock_up ();
617 type_info->free_instances =
618 g_list_prepend (type_info->free_instances, obj);
620 camel_type_lock_down ();
624 camel_object_is_of_type (CamelObject * obj, CamelType ctype)
626 return shared_is_of_type ((CamelObjectShared *) obj, ctype, TRUE);
630 camel_object_class_is_of_type (CamelObjectClass * class, CamelType ctype)
632 return shared_is_of_type ((CamelObjectShared *) class, ctype, FALSE);
642 camel_object_check_cast (CamelObject * obj, CamelType ctype)
644 if (shared_is_of_type ((CamelObjectShared *) obj, ctype, TRUE))
650 camel_object_class_check_cast (CamelObjectClass * class, CamelType ctype)
652 if (shared_is_of_type ((CamelObjectShared *) class, ctype, FALSE))
660 camel_object_describe (CamelObject * obj)
663 return g_strdup ("a NULL pointer");
665 if (obj->s.magic == CAMEL_OBJECT_MAGIC_VALUE) {
666 return g_strdup_printf ("an instance of `%s' at %p",
667 camel_type_to_name (obj->s.type),
669 } else if (obj->s.magic == CAMEL_OBJECT_FINALIZED_VALUE) {
670 return g_strdup_printf ("a finalized instance of `%s' at %p",
671 camel_type_to_name (obj->s.type),
673 } else if (obj->s.magic == CAMEL_OBJECT_CLASS_MAGIC_VALUE) {
674 return g_strdup_printf ("the classfuncs of `%s' at %p",
675 camel_type_to_name (obj->s.type),
677 } else if (obj->s.magic == CAMEL_OBJECT_CLASS_FINALIZED_VALUE) {
680 ("the finalized classfuncs of `%s' at %p",
681 camel_type_to_name (obj->s.type), obj);
684 return g_strdup ("not a CamelObject");
687 /* This is likely to be called in the class_init callback,
688 * and the type will likely be somewhat uninitialized.
689 * Is this a problem? We'll see....
692 camel_object_class_declare_event (CamelObjectClass * class,
694 CamelObjectEventPrepFunc prep)
696 g_return_if_fail (CAMEL_IS_OBJECT_CLASS (class));
697 g_return_if_fail (name);
699 if (class->event_to_preplist == NULL)
700 class->event_to_preplist =
701 g_hash_table_new (g_str_hash, g_str_equal);
702 else if (g_hash_table_lookup (class->event_to_preplist, name) != NULL) {
704 ("camel_object_class_declare_event: event `%s' already declared for `%s'",
705 name, camel_type_to_name (class->s.type));
709 /* AIEEEEEEEEEEEEEEEEEEEEEE
711 * I feel so naughty. Since it's valid to declare an event and not
712 * provide a hook, it should be valid to insert a NULL value into
713 * the table. However, then our lookup in trigger_event would be
714 * ambiguous, not telling us whether the event is undefined or whether
715 * it merely has no hook.
717 * So we create an 'NULL prep' value that != NULL... specifically, it
718 * equals the address of one of our static functions , because that
719 * can't possibly be your hook.
721 * Just don't forget to check for the 'evil value' and it'll work,
726 prep = NULL_PREP_VALUE;
728 g_hash_table_insert (class->event_to_preplist, g_strdup (name), prep);
732 static void camel_object_free_hooks(CamelObject *o)
734 CamelHookPair *pair, *next;
738 g_assert(o->hooks->depth == 0);
739 g_assert((o->hooks->flags & CAMEL_HOOK_PAIR_REMOVED) == 0);
741 pair = o->hooks->list;
747 e_mutex_destroy(o->hooks->lock);
753 /* return (allocate if required) the object's hook list, locking at the same time */
754 static CamelHookList *camel_object_get_hooks(CamelObject *o)
756 #ifdef ENABLE_THREADS
757 static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
759 CamelHookList *hooks;
761 /* if we have it, we dont have to do any other locking,
762 otherwise use a global lock to setup the object's hook data */
763 #ifdef ENABLE_THREADS
764 if (o->hooks == NULL) {
765 pthread_mutex_lock(&lock);
767 if (o->hooks == NULL) {
768 hooks = g_malloc(sizeof(*o->hooks));
769 #ifdef ENABLE_THREADS
770 hooks->lock = e_mutex_new(E_MUTEX_REC);
774 hooks->list_length = 0;
778 #ifdef ENABLE_THREADS
779 pthread_mutex_unlock(&lock);
783 #ifdef ENABLE_THREADS
784 e_mutex_lock(o->hooks->lock);
789 /* unlock object hooks' list */
790 #ifdef ENABLE_THREADS
791 #define camel_object_unget_hooks(o) (e_mutex_unlock((CAMEL_OBJECT(o)->hooks->lock)))
793 #define camel_object_unget_hooks(o)
797 camel_object_hook_event (CamelObject * obj, const char * name,
798 CamelObjectEventHookFunc func, void *data)
801 const char *prepname;
802 CamelObjectEventPrepFunc prep;
803 CamelHookList *hooks;
805 g_return_if_fail (CAMEL_IS_OBJECT (obj));
806 g_return_if_fail (name != NULL);
807 g_return_if_fail (func != NULL);
809 /* first, does this event exist? */
810 if (obj->classfuncs->event_to_preplist == NULL
811 || !g_hash_table_lookup_extended(obj->classfuncs->event_to_preplist, name,
812 (void **)&prepname, (void **)&prep)) {
813 g_warning("camel_object_hook_event: trying to hook event `%s' in class `%s' with no defined events.",
814 name, camel_type_to_name (obj->s.type));
818 /* setup hook pair */
819 pair = g_malloc(sizeof(*pair));
820 pair->name = prepname; /* effectively static! */
825 /* get the hook list object, locked, link in new event hook, unlock */
826 hooks = camel_object_get_hooks(obj);
827 pair->next = hooks->list;
829 hooks->list_length++;
830 camel_object_unget_hooks(obj);
834 camel_object_unhook_event (CamelObject * obj, const char * name,
835 CamelObjectEventHookFunc func, void *data)
838 CamelObjectEventPrepFunc prep;
839 CamelHookList *hooks;
840 CamelHookPair *pair, *parent;
842 g_return_if_fail (CAMEL_IS_OBJECT (obj));
843 g_return_if_fail (name != NULL);
844 g_return_if_fail (func != NULL);
846 if (obj->hooks == NULL) {
847 g_warning("camel_object_unhook_event: trying to unhook `%s` from an instance of `%s' with no hooks",
848 name, camel_type_to_name(obj->s.type));
852 /* get event name static pointer */
853 if (obj->classfuncs->event_to_preplist == NULL
854 || !g_hash_table_lookup_extended(obj->classfuncs->event_to_preplist, name,
855 (void **)&prepname, (void **)&prep)) {
856 g_warning("camel_object_hook_event: trying to hook event `%s' in class `%s' with no defined events.",
857 name, camel_type_to_name (obj->s.type));
861 /* scan hooks for this event, remove it, or flag it if we're busy */
862 hooks = camel_object_get_hooks(obj);
863 parent = (CamelHookPair *)&hooks->list;
866 if (pair->name == prepname
867 && pair->func == func
868 && pair->data == data
869 && (pair->flags & CAMEL_HOOK_PAIR_REMOVED) == 0) {
870 if (hooks->depth > 0) {
871 pair->flags |= CAMEL_HOOK_PAIR_REMOVED;
872 hooks->flags |= CAMEL_HOOK_PAIR_REMOVED;
874 parent->next = pair->next;
876 hooks->list_length--;
878 camel_object_unget_hooks(obj);
884 camel_object_unget_hooks(obj);
886 g_warning("camel_object_unhook_event: cannot find hook/data pair %p/%p in an instance of `%s' attached to `%s'",
887 func, data, camel_type_to_name (obj->s.type), name);
891 camel_object_trigger_event (CamelObject * obj, const char * name, void *event_data)
893 CamelObjectEventPrepFunc prep;
894 const char *prepname;
895 CamelHookList *hooks;
896 CamelHookPair *pair, **pairs, *parent;
899 g_return_if_fail (CAMEL_IS_OBJECT (obj));
900 g_return_if_fail (name);
902 /* get event name static pointer/prep func */
903 if (obj->classfuncs->event_to_preplist == NULL
904 || !g_hash_table_lookup_extended(obj->classfuncs->event_to_preplist, name,
905 (void **)&prepname, (void **)&prep)) {
906 g_warning("camel_object_hook_event: trying to hook event `%s' in class `%s' with no defined events.",
907 name, camel_type_to_name (obj->s.type));
911 /* try prep function, if false, then quit */
912 if (prep != NULL_PREP_VALUE && !prep(obj, event_data))
915 /* also, no hooks, dont bother going further */
916 if (obj->hooks == NULL)
919 /* lock the object for hook emission */
920 camel_object_ref(obj);
921 hooks = camel_object_get_hooks(obj);
924 /* first, copy the items in the list, and say we're in an event */
928 pairs = alloca(sizeof(pairs[0]) * hooks->list_length);
930 if (pair->name == prepname)
931 pairs[size++] = pair;
935 /* now execute the events we have, if they haven't been removed during our calls */
936 for (i=0;i<size;i++) {
938 if ((pair->flags & CAMEL_HOOK_PAIR_REMOVED) == 0)
939 (pair->func) (obj, event_data, pair->data);
943 /* and if we're out of any events, then clean up any pending removes */
944 if (hooks->depth == 0 && (hooks->flags & CAMEL_HOOK_PAIR_REMOVED)) {
945 parent = (CamelHookPair *)&hooks->list;
948 if (pair->flags & CAMEL_HOOK_PAIR_REMOVED) {
949 parent->next = pair->next;
951 hooks->list_length--;
957 hooks->flags &= ~CAMEL_HOOK_PAIR_REMOVED;
961 camel_object_unget_hooks(obj);
962 camel_object_unref(obj);
965 /* ** Static helpers ****************************************************** */
968 shared_is_of_type (CamelObjectShared * sh, CamelType ctype, gboolean is_obj)
970 CamelTypeInfo *type_info;
974 targtype = "instance";
976 targtype = "classdata";
978 if (ctype == CAMEL_INVALID_TYPE) {
980 ("shared_is_of_type: trying to cast to CAMEL_INVALID_TYPE");
986 ("shared_is_of_type: trying to cast NULL to %s of `%s'",
987 targtype, camel_type_to_name (ctype));
991 if (sh->magic == CAMEL_OBJECT_FINALIZED_VALUE) {
993 ("shared_is_of_type: trying to cast finalized instance "
994 "of `%s' into %s of `%s'",
995 camel_type_to_name (sh->type), targtype,
996 camel_type_to_name (ctype));
1000 if (sh->magic == CAMEL_OBJECT_CLASS_FINALIZED_VALUE) {
1002 ("shared_is_of_type: trying to cast finalized classdata "
1003 "of `%s' into %s of `%s'",
1004 camel_type_to_name (sh->type), targtype,
1005 camel_type_to_name (ctype));
1010 if (sh->magic == CAMEL_OBJECT_CLASS_MAGIC_VALUE) {
1012 ("shared_is_of_type: trying to cast classdata "
1013 "of `%s' into instance of `%s'",
1014 camel_type_to_name (sh->type),
1015 camel_type_to_name (ctype));
1019 if (sh->magic != CAMEL_OBJECT_MAGIC_VALUE) {
1021 ("shared_is_of_type: trying to cast junk data "
1022 "into instance of `%s'",
1023 camel_type_to_name (ctype));
1027 if (sh->magic == CAMEL_OBJECT_MAGIC_VALUE) {
1029 ("shared_is_of_type: trying to cast instance "
1030 "of `%s' into classdata of `%s'",
1031 camel_type_to_name (sh->type),
1032 camel_type_to_name (ctype));
1036 if (sh->magic != CAMEL_OBJECT_CLASS_MAGIC_VALUE) {
1038 ("shared_is_of_type: trying to cast junk data "
1039 "into classdata of `%s'",
1040 camel_type_to_name (ctype));
1045 camel_type_lock_up ();
1048 g_hash_table_lookup (ctype_to_typeinfo,
1049 GINT_TO_POINTER (sh->type));
1051 if (type_info == NULL) {
1052 g_warning ("shared_is_of_type: seemingly valid %s has "
1053 "bad type %d.", targtype, sh->type);
1054 camel_type_lock_down ();
1059 if (type_info->self == ctype) {
1060 camel_type_lock_down ();
1065 g_hash_table_lookup (ctype_to_typeinfo,
1066 GINT_TO_POINTER (type_info->
1070 /* this isn't an error, e.g. CAMEL_IS_FOLDER(folder), its upto the
1071 caller to handle the false case */
1073 ("shared_is_of_type: %s of `%s' (@%p) is not also %s of `%s'",
1074 targtype, camel_type_to_name (sh->type), sh, targtype,
1075 camel_type_to_name (ctype));*/
1077 camel_type_lock_down ();
1082 make_global_classfuncs (CamelTypeInfo * type_info)
1084 CamelObjectClass *funcs;
1088 g_assert (type_info);
1090 funcs = g_malloc0 (type_info->classfuncs_size);
1091 funcs->s.type = type_info->self;
1093 type_info->global_classfuncs = funcs;
1097 parents = g_slist_prepend (parents, type_info);
1099 g_hash_table_lookup (ctype_to_typeinfo,
1100 GINT_TO_POINTER (type_info->
1106 for (; parents && parents->data; parents = parents->next) {
1107 CamelTypeInfo *thisinfo;
1109 thisinfo = parents->data;
1110 if (thisinfo->class_init)
1111 (thisinfo->class_init) (funcs);
1114 g_slist_free (head);