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 the GNU General Public License as
12 * published by the Free Software Foundation; either version 2 of the
13 * License, or (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
31 #include "camel-object.h"
33 /* I just mashed the keyboard for these... */
34 #define CAMEL_OBJECT_MAGIC_VALUE 0x77A344EF
35 #define CAMEL_OBJECT_CLASS_MAGIC_VALUE 0xEE26A990
36 #define CAMEL_OBJECT_FINALIZED_VALUE 0x84AC3656
37 #define CAMEL_OBJECT_CLASS_FINALIZED_VALUE 0x7621ABCD
39 #define DEFAULT_PREALLOCS 8
41 #define BAST_CASTARD 1 /* Define to return NULL when casts fail */
43 #define NULL_PREP_VALUE ((gpointer)make_global_classfuncs) /* See camel_object_class_declare_event */
45 /* ** Quickie type system ************************************************* */
47 typedef struct _CamelTypeInfo
54 GMemChunk *instance_chunk;
55 CamelObjectInitFunc instance_init;
56 CamelObjectFinalizeFunc instance_finalize;
57 GList *free_instances;
59 size_t classfuncs_size;
60 CamelObjectClassInitFunc class_init;
61 CamelObjectClassFinalizeFunc class_finalize;
62 CamelObjectClass *global_classfuncs;
66 typedef struct _CamelHookPair
68 CamelObjectEventHookFunc func;
73 /* ************************************************************************ */
75 static void camel_type_lock_up (void);
76 static void camel_type_lock_down (void);
78 static void obj_init (CamelObject * obj);
79 static void obj_finalize (CamelObject * obj);
80 static void obj_class_init (CamelObjectClass * class);
81 static void obj_class_finalize (CamelObjectClass * class);
83 static gboolean shared_is_of_type (CamelObjectShared * sh, CamelType ctype,
85 static void make_global_classfuncs (CamelTypeInfo * type_info);
87 /* ************************************************************************ */
89 G_LOCK_DEFINE_STATIC (type_system);
90 G_LOCK_DEFINE_STATIC (type_system_level);
91 static GPrivate *type_system_locklevel = NULL;
93 G_LOCK_DEFINE_STATIC (refcount);
95 static gboolean type_system_initialized = FALSE;
96 static GHashTable *ctype_to_typeinfo = NULL;
97 static const CamelType camel_object_type = 1;
98 static CamelType cur_max_type = CAMEL_INVALID_TYPE;
100 /* ************************************************************************ */
102 #define LOCK_VAL (GPOINTER_TO_INT (g_private_get (type_system_locklevel)))
103 #define LOCK_SET( val ) g_private_set (type_system_locklevel, GINT_TO_POINTER (val))
106 camel_type_lock_up (void)
108 G_LOCK (type_system_level);
110 if (type_system_locklevel == NULL)
111 type_system_locklevel = g_private_new (GINT_TO_POINTER (0));
114 G_UNLOCK (type_system_level);
115 G_LOCK (type_system);
116 G_LOCK (type_system_level);
119 LOCK_SET (LOCK_VAL + 1);
121 G_UNLOCK (type_system_level);
125 camel_type_lock_down (void)
127 G_LOCK (type_system_level);
129 if (type_system_locklevel == NULL) {
131 ("camel_type_lock_down: lock down before a lock up?");
132 type_system_locklevel = g_private_new (GINT_TO_POINTER (0));
133 G_UNLOCK (type_system_level);
137 LOCK_SET (LOCK_VAL - 1);
140 G_UNLOCK (type_system);
142 G_UNLOCK (type_system_level);
146 camel_type_init (void)
148 CamelTypeInfo *obj_info;
150 camel_type_lock_up ();
152 if (type_system_initialized) {
154 ("camel_type_init: type system already initialized.");
155 camel_type_lock_down ();
159 type_system_initialized = TRUE;
160 ctype_to_typeinfo = g_hash_table_new (g_direct_hash, g_direct_equal);
162 obj_info = g_new (CamelTypeInfo, 1);
163 obj_info->self = camel_object_type;
164 obj_info->parent = CAMEL_INVALID_TYPE;
165 obj_info->name = "CamelObject";
167 obj_info->instance_size = sizeof (CamelObject);
168 obj_info->instance_chunk =
169 g_mem_chunk_create (CamelObject, DEFAULT_PREALLOCS,
171 obj_info->instance_init = obj_init;
172 obj_info->instance_finalize = obj_finalize;
173 obj_info->free_instances = NULL;
175 obj_info->classfuncs_size = sizeof (CamelObjectClass);
176 obj_info->class_init = obj_class_init;
177 obj_info->class_finalize = obj_class_finalize;
179 g_hash_table_insert (ctype_to_typeinfo,
180 GINT_TO_POINTER (CAMEL_INVALID_TYPE), NULL);
181 g_hash_table_insert (ctype_to_typeinfo,
182 GINT_TO_POINTER (camel_object_type), obj_info);
185 make_global_classfuncs (obj_info);
187 cur_max_type = camel_object_type;
189 camel_type_lock_down ();
193 camel_type_register (CamelType parent, const gchar * name,
194 size_t instance_size, size_t classfuncs_size,
195 CamelObjectClassInitFunc class_init,
196 CamelObjectClassFinalizeFunc class_finalize,
197 CamelObjectInitFunc instance_init,
198 CamelObjectFinalizeFunc instance_finalize)
200 CamelTypeInfo *parent_info;
201 CamelTypeInfo *obj_info;
204 g_return_val_if_fail (parent != CAMEL_INVALID_TYPE,
206 g_return_val_if_fail (name, CAMEL_INVALID_TYPE);
207 g_return_val_if_fail (instance_size, CAMEL_INVALID_TYPE);
208 g_return_val_if_fail (classfuncs_size, CAMEL_INVALID_TYPE);
210 camel_type_lock_up ();
212 if (type_system_initialized == FALSE) {
213 G_UNLOCK (type_system);
215 G_LOCK (type_system);
219 g_hash_table_lookup (ctype_to_typeinfo,
220 GINT_TO_POINTER (parent));
222 if (parent_info == NULL) {
224 ("camel_type_register: no such parent type %d of class `%s'",
226 camel_type_lock_down ();
227 return CAMEL_INVALID_TYPE;
230 if (parent_info->instance_size > instance_size) {
232 ("camel_type_register: instance of class `%s' would be smaller than parent `%s'",
233 name, parent_info->name);
234 camel_type_lock_down ();
235 return CAMEL_INVALID_TYPE;
238 if (parent_info->classfuncs_size > classfuncs_size) {
240 ("camel_type_register: classfuncs of class `%s' would be smaller than parent `%s'",
241 name, parent_info->name);
242 camel_type_lock_down ();
243 return CAMEL_INVALID_TYPE;
248 obj_info = g_new (CamelTypeInfo, 1);
249 obj_info->self = cur_max_type;
250 obj_info->parent = parent;
251 obj_info->name = name;
253 obj_info->instance_size = instance_size;
255 g_strdup_printf ("chunk for instances of Camel type `%s'",
257 obj_info->instance_chunk =
258 g_mem_chunk_new (chunkname, instance_size,
259 instance_size * DEFAULT_PREALLOCS,
262 obj_info->instance_init = instance_init;
263 obj_info->instance_finalize = instance_finalize;
264 obj_info->free_instances = NULL;
266 obj_info->classfuncs_size = classfuncs_size;
267 obj_info->class_init = class_init;
268 obj_info->class_finalize = class_finalize;
270 g_hash_table_insert (ctype_to_typeinfo,
271 GINT_TO_POINTER (obj_info->self), obj_info);
274 make_global_classfuncs (obj_info);
276 camel_type_lock_down ();
277 return obj_info->self;
281 camel_type_get_global_classfuncs (CamelType type)
283 CamelTypeInfo *type_info;
285 g_return_val_if_fail (type != CAMEL_INVALID_TYPE, NULL);
287 camel_type_lock_up ();
289 g_hash_table_lookup (ctype_to_typeinfo,
290 GINT_TO_POINTER (type));
291 camel_type_lock_down ();
293 g_return_val_if_fail (type_info != NULL, NULL);
295 return type_info->global_classfuncs;
299 camel_type_to_name (CamelType type)
301 CamelTypeInfo *type_info;
303 g_return_val_if_fail (type != CAMEL_INVALID_TYPE,
304 "(the invalid type)");
306 camel_type_lock_up ();
308 g_hash_table_lookup (ctype_to_typeinfo,
309 GINT_TO_POINTER (type));
310 camel_type_lock_down ();
312 g_return_val_if_fail (type_info != NULL,
313 "(a bad type parameter was specified)");
315 return type_info->name;
318 /* ** The CamelObject ***************************************************** */
321 obj_init (CamelObject * obj)
323 obj->s.magic = CAMEL_OBJECT_MAGIC_VALUE;
325 obj->event_to_hooklist = NULL;
331 obj_finalize (CamelObject * obj)
333 g_return_if_fail (obj->s.magic == CAMEL_OBJECT_MAGIC_VALUE);
334 g_return_if_fail (obj->ref_count == 0);
335 g_return_if_fail (obj->in_event == 0);
337 obj->s.magic = CAMEL_OBJECT_FINALIZED_VALUE;
339 if (obj->event_to_hooklist) {
340 g_hash_table_foreach (obj->event_to_hooklist, (GHFunc) g_free, NULL);
341 g_hash_table_destroy (obj->event_to_hooklist);
342 obj->event_to_hooklist = NULL;
347 obj_class_init (CamelObjectClass * class)
349 class->s.magic = CAMEL_OBJECT_CLASS_MAGIC_VALUE;
351 camel_object_class_declare_event (class, "finalize", NULL);
355 obj_class_finalize (CamelObjectClass * class)
357 g_return_if_fail (class->s.magic == CAMEL_OBJECT_CLASS_MAGIC_VALUE);
359 class->s.magic = CAMEL_OBJECT_CLASS_FINALIZED_VALUE;
361 if (class->event_to_preplist) {
362 g_hash_table_foreach (class->event_to_preplist,
363 (GHFunc) g_free, NULL);
364 g_hash_table_destroy (class->event_to_preplist);
365 class->event_to_preplist = NULL;
370 camel_object_get_type (void)
372 if (type_system_initialized == FALSE)
375 return camel_object_type;
379 camel_object_new (CamelType type)
381 CamelTypeInfo *type_info;
382 GSList *parents = NULL;
384 CamelObject *instance;
386 g_return_val_if_fail (type != CAMEL_INVALID_TYPE, NULL);
388 /* Look up the type */
390 camel_type_lock_up ();
393 g_hash_table_lookup (ctype_to_typeinfo,
394 GINT_TO_POINTER (type));
396 if (type_info == NULL) {
398 ("camel_object_new: trying to create object of invalid type %d",
400 camel_type_lock_down ();
404 /* Grab an instance out of the freed ones if possible, alloc otherwise */
406 if (type_info->free_instances) {
409 first = g_list_first (type_info->free_instances);
410 instance = first->data;
411 type_info->free_instances =
412 g_list_remove_link (type_info->free_instances, first);
413 g_list_free_1 (first);
415 instance = g_mem_chunk_alloc0 (type_info->instance_chunk);
418 /* Init the instance and classfuncs a bit */
420 instance->s.type = type;
421 instance->classfuncs = type_info->global_classfuncs;
423 /* Loop through the parents in simplest -> most complex order, initing the class and instance.
425 * When parent = CAMEL_INVALID_TYPE and we're at the end of the line, _lookup returns NULL
426 * because we inserted it as corresponding to CAMEL_INVALID_TYPE. Clever, eh?
430 parents = g_slist_prepend (parents, type_info);
432 g_hash_table_lookup (ctype_to_typeinfo,
433 GINT_TO_POINTER (type_info->
439 for (; parents && parents->data; parents = parents->next) {
440 CamelTypeInfo *thisinfo;
442 thisinfo = parents->data;
443 if (thisinfo->instance_init)
444 (thisinfo->instance_init) (instance);
449 camel_type_lock_down ();
454 camel_object_ref (CamelObject * obj)
456 g_return_if_fail (CAMEL_IS_OBJECT (obj));
464 camel_object_unref (CamelObject * obj)
466 CamelTypeInfo *type_info;
468 GSList *parents = NULL;
471 g_return_if_fail (CAMEL_IS_OBJECT (obj));
476 if (obj->ref_count > 0) {
483 /* If the object already had its last unref, do not begin the
484 * destruction process again. This can happen if, for example,
485 * the object sends an event in its finalize handler (vfolders
494 /* Send the finalize event */
496 camel_object_trigger_event (obj, "finalize", NULL);
498 /* Destroy it! hahaha! */
500 camel_type_lock_up ();
503 g_hash_table_lookup (ctype_to_typeinfo,
504 GINT_TO_POINTER (obj->s.type));
506 if (type_info == NULL) {
508 ("camel_object_unref: seemingly valid object has a bad type %d",
510 camel_type_lock_down ();
514 /* Loop through the parents in most complex -> simplest order, finalizing the class
517 * When parent = CAMEL_INVALID_TYPE and we're at the end of the line, _lookup returns NULL
518 * because we inserted it as corresponding to CAMEL_INVALID_TYPE. Clever, eh?
520 * Use iter to preserve type_info for free_{instance,classfunc}s
526 parents = g_slist_prepend (parents, iter);
528 g_hash_table_lookup (ctype_to_typeinfo,
529 GINT_TO_POINTER (iter->parent));
532 parents = g_slist_reverse (parents);
535 for (; parents && parents->data; parents = parents->next) {
536 CamelTypeInfo *thisinfo;
538 thisinfo = parents->data;
539 if (thisinfo->instance_finalize)
540 (thisinfo->instance_finalize) (obj);
547 if (obj->ref_count != 0)
548 g_warning ("camel_object_unref: destroyed object %s at %p somehow got"
549 " referenced in destruction chain.",
550 camel_type_to_name (obj->s.type),
553 /* A little bit of cleaning up.
555 * Don't erase the type, so we can peek at it if a finalized object
556 * is check_cast'ed somewhere.
559 memset (obj, 0, type_info->instance_size);
560 obj->s.type = type_info->self;
561 obj->s.magic = CAMEL_OBJECT_FINALIZED_VALUE;
563 /* Tuck away the pointer for use in a new object */
565 type_info->free_instances =
566 g_list_prepend (type_info->free_instances, obj);
568 camel_type_lock_down ();
572 camel_object_is_of_type (CamelObject * obj, CamelType ctype)
574 return shared_is_of_type ((CamelObjectShared *) obj, ctype, TRUE);
578 camel_object_class_is_of_type (CamelObjectClass * class, CamelType ctype)
580 return shared_is_of_type ((CamelObjectShared *) class, ctype, FALSE);
590 camel_object_check_cast (CamelObject * obj, CamelType ctype)
592 if (shared_is_of_type ((CamelObjectShared *) obj, ctype, TRUE))
598 camel_object_class_check_cast (CamelObjectClass * class, CamelType ctype)
600 if (shared_is_of_type ((CamelObjectShared *) class, ctype, FALSE))
608 camel_object_describe (CamelObject * obj)
611 return g_strdup ("a NULL pointer");
613 if (obj->s.magic == CAMEL_OBJECT_MAGIC_VALUE) {
614 return g_strdup_printf ("an instance of `%s' at %p",
615 camel_type_to_name (obj->s.type),
617 } else if (obj->s.magic == CAMEL_OBJECT_FINALIZED_VALUE) {
618 return g_strdup_printf ("a finalized instance of `%s' at %p",
619 camel_type_to_name (obj->s.type),
621 } else if (obj->s.magic == CAMEL_OBJECT_CLASS_MAGIC_VALUE) {
622 return g_strdup_printf ("the classfuncs of `%s' at %p",
623 camel_type_to_name (obj->s.type),
625 } else if (obj->s.magic == CAMEL_OBJECT_CLASS_FINALIZED_VALUE) {
628 ("the finalized classfuncs of `%s' at %p",
629 camel_type_to_name (obj->s.type), obj);
632 return g_strdup ("not a CamelObject");
635 /* This is likely to be called in the class_init callback,
636 * and the type will likely be somewhat uninitialized.
637 * Is this a problem? We'll see....
640 camel_object_class_declare_event (CamelObjectClass * class,
642 CamelObjectEventPrepFunc prep)
644 g_return_if_fail (CAMEL_IS_OBJECT_CLASS (class));
645 g_return_if_fail (name);
647 if (class->event_to_preplist == NULL)
648 class->event_to_preplist =
649 g_hash_table_new (g_str_hash, g_str_equal);
650 else if (g_hash_table_lookup (class->event_to_preplist, name) != NULL) {
652 ("camel_object_class_declare_event: event `%s' already declared for `%s'",
653 name, camel_type_to_name (class->s.type));
657 /* AIEEEEEEEEEEEEEEEEEEEEEE
659 * I feel so naughty. Since it's valid to declare an event and not
660 * provide a hook, it should be valid to insert a NULL value into
661 * the table. However, then our lookup in trigger_event would be
662 * ambiguous, not telling us whether the event is undefined or whether
663 * it merely has no hook.
665 * So we create an 'NULL prep' value that != NULL... specifically, it
666 * equals the address of one of our static functions , because that
667 * can't possibly be your hook.
669 * Just don't forget to check for the 'evil value' and it'll work,
674 prep = NULL_PREP_VALUE;
676 g_hash_table_insert (class->event_to_preplist, g_strdup (name), prep);
680 camel_object_hook_event (CamelObject * obj, const gchar * name,
681 CamelObjectEventHookFunc hook, gpointer user_data)
685 gpointer old_name, old_hooklist;
687 g_return_if_fail (CAMEL_IS_OBJECT (obj));
688 g_return_if_fail (name);
689 g_return_if_fail (hook);
691 if (obj->event_to_hooklist == NULL)
692 obj->event_to_hooklist =
693 g_hash_table_new (g_str_hash, g_str_equal);
695 pair = g_new (CamelHookPair, 1);
697 pair->user_data = user_data;
699 if (g_hash_table_lookup_extended (obj->event_to_hooklist, name,
700 &old_name, &old_hooklist)) {
701 hooklist = g_slist_prepend (old_hooklist, pair);
702 g_hash_table_insert (obj->event_to_hooklist, old_name,
705 hooklist = g_slist_prepend (NULL, pair);
706 g_hash_table_insert (obj->event_to_hooklist, g_strdup (name),
712 camel_object_unhook_event (CamelObject * obj, const gchar * name,
713 CamelObjectEventHookFunc hook, gpointer user_data)
718 g_return_if_fail (CAMEL_IS_OBJECT (obj));
719 g_return_if_fail (name);
720 g_return_if_fail (hook);
722 if (obj->event_to_hooklist == NULL) {
724 ("camel_object_unhook_event: trying to unhook `%s' from an instance "
725 "of `%s' with no hooks attached", name,
726 camel_type_to_name (obj->s.type));
730 hooklist = g_hash_table_lookup (obj->event_to_hooklist, name);
732 if (hooklist == NULL) {
734 ("camel_object_unhook_event: trying to unhook `%s' from an instance "
735 "of `%s' with no hooks attached to that event.",
736 name, camel_type_to_name (obj->s.type));
743 CamelHookPair *pair = (CamelHookPair *) hooklist->data;
745 if (pair->func == hook && pair->user_data == user_data) {
746 g_free (hooklist->data);
747 head = g_slist_remove_link (head, hooklist);
748 g_slist_free_1 (hooklist);
749 g_hash_table_insert (obj->event_to_hooklist, (char *) name,
754 hooklist = hooklist->next;
758 ("camel_object_unhook_event: cannot find hook/data pair %p/%p in an "
759 "instance of `%s' attached to `%s'", hook, user_data,
760 camel_type_to_name (obj->s.type), name);
764 camel_object_trigger_event (CamelObject * obj, const gchar * name,
769 CamelObjectEventPrepFunc prep;
771 g_return_if_fail (CAMEL_IS_OBJECT (obj));
772 g_return_if_fail (name);
776 ("camel_object_trigger_event: trying to trigger `%s' in class "
777 "`%s' while already triggering another event", name,
778 camel_type_to_name (obj->s.type));
782 if (obj->classfuncs->event_to_preplist == NULL) {
784 ("camel_object_trigger_event: trying to trigger `%s' in class "
785 "`%s' with no defined events.", name,
786 camel_type_to_name (obj->s.type));
790 prep = g_hash_table_lookup (obj->classfuncs->event_to_preplist, name);
794 ("camel_object_trigger_event: trying to trigger undefined "
795 "event `%s' in class `%s'.", name,
796 camel_type_to_name (obj->s.type));
800 /* Ref so that it can't get destroyed in the event, which would
801 * be Bad. And it's a valid ref anyway...
804 camel_object_ref (obj);
807 if ((prep != NULL_PREP_VALUE && !prep (obj, event_data))
808 || obj->event_to_hooklist == NULL) {
810 camel_object_unref (obj);
814 hooklist = g_hash_table_lookup (obj->event_to_hooklist, name);
816 while (hooklist && hooklist->data) {
817 pair = hooklist->data;
818 (pair->func) (obj, event_data, pair->user_data);
819 hooklist = hooklist->next;
823 camel_object_unref (obj);
826 /* ** Static helpers ****************************************************** */
829 shared_is_of_type (CamelObjectShared * sh, CamelType ctype, gboolean is_obj)
831 CamelTypeInfo *type_info;
835 targtype = "instance";
837 targtype = "classdata";
839 if (ctype == CAMEL_INVALID_TYPE) {
841 ("shared_is_of_type: trying to cast to CAMEL_INVALID_TYPE");
847 ("shared_is_of_type: trying to cast NULL to %s of `%s'",
848 targtype, camel_type_to_name (ctype));
852 if (sh->magic == CAMEL_OBJECT_FINALIZED_VALUE) {
854 ("shared_is_of_type: trying to cast finalized instance "
855 "of `%s' into %s of `%s'",
856 camel_type_to_name (sh->type), targtype,
857 camel_type_to_name (ctype));
861 if (sh->magic == CAMEL_OBJECT_CLASS_FINALIZED_VALUE) {
863 ("shared_is_of_type: trying to cast finalized classdata "
864 "of `%s' into %s of `%s'",
865 camel_type_to_name (sh->type), targtype,
866 camel_type_to_name (ctype));
871 if (sh->magic == CAMEL_OBJECT_CLASS_MAGIC_VALUE) {
873 ("shared_is_of_type: trying to cast classdata "
874 "of `%s' into instance of `%s'",
875 camel_type_to_name (sh->type),
876 camel_type_to_name (ctype));
880 if (sh->magic != CAMEL_OBJECT_MAGIC_VALUE) {
882 ("shared_is_of_type: trying to cast junk data "
883 "into instance of `%s'",
884 camel_type_to_name (ctype));
888 if (sh->magic == CAMEL_OBJECT_MAGIC_VALUE) {
890 ("shared_is_of_type: trying to cast instance "
891 "of `%s' into classdata of `%s'",
892 camel_type_to_name (sh->type),
893 camel_type_to_name (ctype));
897 if (sh->magic != CAMEL_OBJECT_CLASS_MAGIC_VALUE) {
899 ("shared_is_of_type: trying to cast junk data "
900 "into classdata of `%s'",
901 camel_type_to_name (ctype));
906 camel_type_lock_up ();
909 g_hash_table_lookup (ctype_to_typeinfo,
910 GINT_TO_POINTER (sh->type));
912 if (type_info == NULL) {
913 g_warning ("shared_is_of_type: seemingly valid %s has "
914 "bad type %d.", targtype, sh->type);
915 camel_type_lock_down ();
920 if (type_info->self == ctype) {
921 camel_type_lock_down ();
926 g_hash_table_lookup (ctype_to_typeinfo,
927 GINT_TO_POINTER (type_info->
931 /* this isn't an error, e.g. CAMEL_IS_FOLDER(folder), its upto the
932 caller to handle the false case */
934 ("shared_is_of_type: %s of `%s' (@%p) is not also %s of `%s'",
935 targtype, camel_type_to_name (sh->type), sh, targtype,
936 camel_type_to_name (ctype));*/
938 camel_type_lock_down ();
943 make_global_classfuncs (CamelTypeInfo * type_info)
945 CamelObjectClass *funcs;
949 g_assert (type_info);
951 funcs = g_malloc0 (type_info->classfuncs_size);
952 funcs->s.type = type_info->self;
954 type_info->global_classfuncs = funcs;
958 parents = g_slist_prepend (parents, type_info);
960 g_hash_table_lookup (ctype_to_typeinfo,
961 GINT_TO_POINTER (type_info->
967 for (; parents && parents->data; parents = parents->next) {
968 CamelTypeInfo *thisinfo;
970 thisinfo = parents->data;
971 if (thisinfo->class_init)
972 (thisinfo->class_init) (funcs);