1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
20 #include "gtktypeutils.h"
23 #define TYPE_NODES_BLOCK_SIZE (200)
25 typedef struct _GtkTypeNode GtkTypeNode;
30 GtkTypeInfo type_info;
32 guint chunk_alloc_locked : 1;
36 GList *children_types;
41 #define LOOKUP_TYPE_NODE(node_var, type) { \
44 register GtkType sqn = GTK_TYPE_SEQNO (type); \
45 if (sqn < n_type_nodes) \
46 node_var = type_nodes + sqn; \
54 static void gtk_type_class_init (GtkType node_type);
55 static guint gtk_type_name_hash (const char *key);
56 static gint gtk_type_name_compare (const char *a,
58 static void gtk_type_init_builtin_types (void);
60 static GtkTypeNode *type_nodes = NULL;
61 static guint n_type_nodes = 0;
62 static GHashTable *type_name_2_type_ht = NULL;
66 gtk_type_node_next_and_invalidate (void)
68 static guint n_free_type_nodes = 0;
69 register GtkTypeNode *node;
70 register GtkType new_type;
72 /* don't keep *any* GtkTypeNode pointers across invokation of this function!!!
75 if (n_free_type_nodes == 0)
82 size = n_type_nodes + TYPE_NODES_BLOCK_SIZE;
83 size *= sizeof (GtkTypeNode);
89 type_nodes = g_realloc (type_nodes, size);
91 n_free_type_nodes = size / sizeof (GtkTypeNode) - n_type_nodes;
93 memset (type_nodes + n_type_nodes, 0, n_free_type_nodes * sizeof (GtkTypeNode));
96 new_type = n_type_nodes++;
99 LOOKUP_TYPE_NODE (node, new_type);
101 node->type = new_type;
109 if (n_type_nodes == 0)
113 g_assert (sizeof (GtkType) >= 4);
115 zero = gtk_type_node_next_and_invalidate ();
116 g_assert (zero == NULL);
118 type_name_2_type_ht = g_hash_table_new ((GHashFunc) gtk_type_name_hash,
119 (GCompareFunc) gtk_type_name_compare);
121 gtk_type_init_builtin_types ();
126 gtk_type_set_chunk_alloc (GtkType type,
131 LOOKUP_TYPE_NODE (node, type);
132 g_return_if_fail (node != NULL);
133 g_return_if_fail (node->chunk_alloc_locked == FALSE);
137 g_mem_chunk_destroy (node->mem_chunk);
138 node->mem_chunk = NULL;
142 node->mem_chunk = g_mem_chunk_new (node->type_info.type_name,
143 node->type_info.object_size,
144 node->type_info.object_size * n_chunks,
149 gtk_type_create (GtkType parent_type,
151 GtkTypeInfo *type_info)
153 GtkTypeNode *new_node;
157 if (g_hash_table_lookup (type_name_2_type_ht, type_name))
159 g_warning ("gtk_type_create(): type `%s' already exists.", type_name);
165 GtkTypeNode *tmp_node;
167 LOOKUP_TYPE_NODE (tmp_node, parent_type);
170 g_warning ("gtk_type_create(): unknown parent type `%u'.", parent_type);
175 /* relookup pointers afterwards.
177 new_node = gtk_type_node_next_and_invalidate ();
181 new_node->type = GTK_TYPE_MAKE (parent_type, new_node->type);
182 LOOKUP_TYPE_NODE (parent, parent_type);
186 g_assert (new_node->type <= 0xff);
190 new_node->type_info = *type_info;
191 new_node->type_info.type_name = type_name;
192 /* new_node->type_info.reserved_1 = NULL; */
193 new_node->type_info.reserved_2 = NULL;
194 new_node->n_supers = parent ? parent->n_supers + 1 : 0;
195 new_node->chunk_alloc_locked = FALSE;
196 new_node->supers = g_new0 (GtkType, new_node->n_supers + 1);
197 new_node->parent_type = parent_type;
198 new_node->klass = NULL;
199 new_node->children_types = NULL;
200 new_node->mem_chunk = NULL;
203 parent->children_types = g_list_append (parent->children_types, GUINT_TO_POINTER (new_node->type));
206 for (i = 0; i < new_node->n_supers + 1; i++)
208 new_node->supers[i] = parent->type;
209 LOOKUP_TYPE_NODE (parent, parent->parent_type);
212 g_hash_table_insert (type_name_2_type_ht, new_node->type_info.type_name, GUINT_TO_POINTER (new_node->type));
214 return new_node->type;
218 gtk_type_unique (GtkType parent_type,
219 GtkTypeInfo *type_info)
224 g_return_val_if_fail (type_info != NULL, 0);
225 g_return_val_if_fail (type_info->type_name != NULL, 0);
227 if (n_type_nodes == 0)
230 type_name = g_strdup (type_info->type_name);
232 /* relookup pointers afterwards.
234 new_type = gtk_type_create (parent_type, type_name, type_info);
243 gtk_type_name (GtkType type)
247 LOOKUP_TYPE_NODE (node, type);
250 return node->type_info.type_name;
256 gtk_type_from_name (const gchar *name)
258 if (type_name_2_type_ht)
262 type = GPOINTER_TO_UINT (g_hash_table_lookup (type_name_2_type_ht, (gpointer) name));
271 gtk_type_parent (GtkType type)
275 LOOKUP_TYPE_NODE (node, type);
277 return node->parent_type;
283 gtk_type_parent_class (GtkType type)
287 LOOKUP_TYPE_NODE (node, type);
288 g_return_val_if_fail (node != NULL, NULL);
292 LOOKUP_TYPE_NODE (node, node->parent_type);
299 gtk_type_class_init (type);
300 LOOKUP_TYPE_NODE (node, type);
311 gtk_type_class (GtkType type)
315 LOOKUP_TYPE_NODE (node, type);
316 g_return_val_if_fail (node != NULL, NULL);
321 gtk_type_class_init (type);
322 LOOKUP_TYPE_NODE (node, type);
329 gtk_type_new (GtkType type)
332 GtkTypeObject *tobject;
336 LOOKUP_TYPE_NODE (node, type);
337 g_return_val_if_fail (node != NULL, NULL);
339 klass = gtk_type_class (type);
340 node->chunk_alloc_locked = TRUE;
344 tobject = g_mem_chunk_alloc (node->mem_chunk);
345 memset (tobject, 0, node->type_info.object_size);
348 tobject = g_malloc0 (node->type_info.object_size);
350 /* we need to call the base classes' object_init_func for derived
351 * objects with the object's ->klass field still pointing to the
352 * corresponding base class, otherwise overridden class functions
353 * could get called with partly-initialized objects.
355 for (i = node->n_supers; i > 0; i--)
359 LOOKUP_TYPE_NODE (pnode, node->supers[i]);
360 if (pnode->type_info.object_init_func)
362 tobject->klass = pnode->klass;
363 pnode->type_info.object_init_func (tobject);
366 tobject->klass = klass;
367 if (node->type_info.object_init_func)
368 node->type_info.object_init_func (tobject);
374 gtk_type_free (GtkType type,
379 g_return_if_fail (mem != NULL);
380 LOOKUP_TYPE_NODE (node, type);
381 g_return_if_fail (node != NULL);
384 g_mem_chunk_free (node->mem_chunk, mem);
390 gtk_type_children_types (GtkType type)
394 LOOKUP_TYPE_NODE (node, type);
396 return node->children_types;
402 gtk_type_describe_heritage (GtkType type)
407 LOOKUP_TYPE_NODE (node, type);
411 if (node->type_info.type_name)
414 node->type_info.type_name);
416 g_message ("%s<unnamed type>",
420 LOOKUP_TYPE_NODE (node, node->parent_type);
425 gtk_type_describe_tree (GtkType type,
430 LOOKUP_TYPE_NODE (node, type);
434 static gint indent = 0;
440 gstring = g_string_new ("");
442 for (i = 0; i < indent; i++)
443 g_string_append_c (gstring, ' ');
445 if (node->type_info.type_name)
446 g_string_append (gstring, node->type_info.type_name);
448 g_string_append (gstring, "<unnamed type>");
451 g_string_sprintfa (gstring, " (%d bytes)", node->type_info.object_size);
453 g_message ("%s", gstring->str);
454 g_string_free (gstring, TRUE);
459 for (list = node->children_types; list; list = list->next)
460 gtk_type_describe_tree (GPOINTER_TO_UINT (list->data), show_size);
467 gtk_type_is_a (GtkType type,
470 if (type == is_a_type)
474 register GtkTypeNode *node;
476 LOOKUP_TYPE_NODE (node, type);
479 register GtkTypeNode *a_node;
481 LOOKUP_TYPE_NODE (a_node, is_a_type);
484 if (a_node->n_supers <= node->n_supers)
485 return node->supers[node->n_supers - a_node->n_supers] == is_a_type;
494 gtk_type_class_init (GtkType type)
498 /* we need to relookup nodes everytime we called an external function */
499 LOOKUP_TYPE_NODE (node, type);
501 if (!node->klass && node->type_info.class_size)
503 GtkTypeClass *type_class;
504 GtkTypeNode *base_node;
507 if (node->type_info.class_size < sizeof (GtkTypeClass))
508 g_warning ("The `%s' class is too small to inherit from GtkTypeClass",
509 node->type_info.type_name);
511 node->klass = g_malloc0 (node->type_info.class_size);
513 if (node->parent_type)
517 LOOKUP_TYPE_NODE (parent, node->parent_type);
519 if (node->type_info.class_size < parent->type_info.class_size)
520 g_warning ("The `%s' class is smaller than its parent class `%s'",
521 node->type_info.type_name,
522 parent->type_info.type_name);
526 gtk_type_class_init (parent->type);
527 LOOKUP_TYPE_NODE (node, type);
528 LOOKUP_TYPE_NODE (parent, node->parent_type);
532 memcpy (node->klass, parent->klass, parent->type_info.class_size);
535 type_class = node->klass;
536 type_class->type = node->type;
538 /* stack all base class initialization functions, so we
539 * call them in ascending order.
545 if (base_node->type_info.base_class_init_func)
546 slist = g_slist_prepend (slist, base_node->type_info.base_class_init_func);
547 LOOKUP_TYPE_NODE (base_node, base_node->parent_type);
553 for (walk = slist; walk; walk = walk->next)
555 register GtkClassInitFunc base_class_init;
557 base_class_init = walk->data;
558 base_class_init (node->klass);
559 LOOKUP_TYPE_NODE (node, type);
561 g_slist_free (slist);
564 if (node->type_info.class_init_func)
565 node->type_info.class_init_func (node->klass);
570 gtk_type_descriptive_name (GtkType type)
574 name = gtk_type_name (type);
582 gtk_type_check_object_cast (GtkTypeObject *type_object,
587 g_warning ("invalid cast from (NULL) pointer to `%s'",
588 gtk_type_descriptive_name (cast_type));
591 if (!type_object->klass)
593 g_warning ("invalid unclassed pointer in cast to `%s'",
594 gtk_type_descriptive_name (cast_type));
597 /* currently, GTK_TYPE_OBJECT is the lowest fundamental type
598 * dominator for types that introduce classes.
600 if (type_object->klass->type < GTK_TYPE_OBJECT)
602 g_warning ("invalid class type `%s' in cast to `%s'",
603 gtk_type_descriptive_name (type_object->klass->type),
604 gtk_type_descriptive_name (cast_type));
607 if (!gtk_type_is_a (type_object->klass->type, cast_type))
609 g_warning ("invalid cast from `%s' to `%s'",
610 gtk_type_descriptive_name (type_object->klass->type),
611 gtk_type_descriptive_name (cast_type));
619 gtk_type_check_class_cast (GtkTypeClass *klass,
624 g_warning ("invalid class cast from (NULL) pointer to `%s'",
625 gtk_type_descriptive_name (cast_type));
628 /* currently, GTK_TYPE_OBJECT is the lowest fundamental type
629 * dominator for types that introduce classes.
631 if (klass->type < GTK_TYPE_OBJECT)
633 g_warning ("invalid class type `%s' in class cast to `%s'",
634 gtk_type_descriptive_name (klass->type),
635 gtk_type_descriptive_name (cast_type));
638 if (!gtk_type_is_a (klass->type, cast_type))
640 g_warning ("invalid class cast from `%s' to `%s'",
641 gtk_type_descriptive_name (klass->type),
642 gtk_type_descriptive_name (cast_type));
650 gtk_type_enum_get_values (GtkType enum_type)
652 if (GTK_FUNDAMENTAL_TYPE (enum_type) == GTK_TYPE_ENUM ||
653 GTK_FUNDAMENTAL_TYPE (enum_type) == GTK_TYPE_FLAGS)
657 LOOKUP_TYPE_NODE (node, enum_type);
659 return (GtkEnumValue*) node->type_info.reserved_1;
662 g_warning ("gtk_type_enum_get_values(): type `%s' is not derived from `GtkEnum' or `GtkFlags'",
663 gtk_type_name (enum_type));
669 gtk_type_flags_get_values (GtkType flags_type)
671 return gtk_type_enum_get_values (flags_type);
675 gtk_type_enum_find_value (GtkType enum_type,
676 const gchar *value_name)
678 g_return_val_if_fail (value_name != NULL, NULL);
680 if (GTK_FUNDAMENTAL_TYPE (enum_type) == GTK_TYPE_ENUM ||
681 GTK_FUNDAMENTAL_TYPE (enum_type) == GTK_TYPE_FLAGS)
685 vals = gtk_type_enum_get_values (enum_type);
687 while (vals->value_name)
689 if (strcmp (vals->value_name, value_name) == 0 ||
690 strcmp (vals->value_nick, value_name) == 0)
696 g_warning ("gtk_type_enum_find_value(): type `%s' is not derived from `GtkEnum' or `GtkFlags'",
697 gtk_type_name (enum_type));
703 gtk_type_flags_find_value (GtkType flag_type,
704 const gchar *value_name)
706 g_return_val_if_fail (value_name != NULL, NULL);
708 return gtk_type_enum_find_value (flag_type, value_name);
711 typedef struct _GtkTypeVarargType GtkTypeVarargType;
712 struct _GtkTypeVarargType
714 GtkType foreign_type;
715 GtkType varargs_type;
718 static GtkTypeVarargType *vararg_types = NULL;
719 static guint n_vararg_types = 0;
722 gtk_type_set_varargs_type (GtkType foreign_type,
723 GtkType varargs_type)
725 g_return_if_fail (foreign_type == GTK_FUNDAMENTAL_TYPE (foreign_type));
726 g_return_if_fail (foreign_type > GTK_TYPE_FUNDAMENTAL_LAST);
728 if (!((varargs_type >= GTK_TYPE_STRUCTURED_FIRST &&
729 varargs_type <= GTK_TYPE_STRUCTURED_LAST) ||
730 (varargs_type >= GTK_TYPE_FLAT_FIRST &&
731 varargs_type <= GTK_TYPE_FLAT_LAST) ||
732 varargs_type == GTK_TYPE_NONE))
734 g_warning ("invalid varargs type `%s' for fundamental type `%s'",
735 gtk_type_name (varargs_type),
736 gtk_type_name (foreign_type));
739 if (gtk_type_get_varargs_type (foreign_type))
741 g_warning ("varargs type is already registered for fundamental type `%s'",
742 gtk_type_name (foreign_type));
747 vararg_types = g_realloc (vararg_types, sizeof (GtkTypeVarargType) * n_vararg_types);
749 vararg_types[n_vararg_types - 1].foreign_type = foreign_type;
750 vararg_types[n_vararg_types - 1].varargs_type = varargs_type;
754 gtk_type_get_varargs_type (GtkType foreign_type)
759 type = GTK_FUNDAMENTAL_TYPE (foreign_type);
760 if (type <= GTK_TYPE_FUNDAMENTAL_LAST)
763 for (i = 0; i < n_vararg_types; i++)
764 if (vararg_types[i].foreign_type == type)
765 return vararg_types[i].varargs_type;
770 static inline GtkType
771 gtk_type_register_intern (gchar *name,
773 GtkEnumValue *values)
778 info.type_name = name;
779 info.object_size = 0;
781 info.class_init_func = NULL;
782 info.object_init_func = NULL;
783 info.reserved_1 = values;
784 info.reserved_2 = NULL;
786 /* relookup pointers afterwards.
788 type_id = gtk_type_create (parent, name, &info);
790 if (type_id && values)
794 /* check for proper type consistency and NULL termination
797 g_assert (GTK_FUNDAMENTAL_TYPE (type_id) == GTK_TYPE_ENUM ||
798 GTK_FUNDAMENTAL_TYPE (type_id) == GTK_TYPE_FLAGS);
801 while (values[i].value_name)
804 g_assert (values[i].value_name == NULL && values[i].value_nick == NULL);
811 gtk_type_register_enum (const gchar *type_name,
812 GtkEnumValue *values)
817 g_return_val_if_fail (type_name != NULL, 0);
819 name = g_strdup (type_name);
821 /* relookup pointers afterwards.
823 type_id = gtk_type_register_intern (name, GTK_TYPE_ENUM, values);
832 gtk_type_register_flags (const gchar *type_name,
833 GtkFlagValue *values)
838 g_return_val_if_fail (type_name != NULL, 0);
840 name = g_strdup (type_name);
842 /* relookup pointers afterwards.
844 type_id = gtk_type_register_intern (name, GTK_TYPE_FLAGS, values);
853 gtk_type_name_hash (const char *key)
859 result += (result << 3) + *key++;
865 gtk_type_name_compare (const char *a,
868 return (strcmp (a, b) == 0);
871 extern void gtk_object_init_type (void);
873 #include "makeenums.h" /* include for various places
874 * with enum definitions
876 #include "gtktypebuiltins_vars.c" /* type variable declarations
878 #include "gtktypebuiltins_evals.c" /* enum value definition arrays
882 gtk_type_init_builtin_types (void)
884 /* GTK_TYPE_INVALID has typeid 0. The first type id returned by
885 * gtk_type_unique is 1, which is GTK_TYPE_NONE. And so on.
891 } fundamental_info[] = {
892 { GTK_TYPE_NONE, "void" },
893 { GTK_TYPE_CHAR, "gchar" },
894 { GTK_TYPE_UCHAR, "guchar" },
895 { GTK_TYPE_BOOL, "gboolean" },
896 { GTK_TYPE_INT, "gint" },
897 { GTK_TYPE_UINT, "guint" },
898 { GTK_TYPE_LONG, "glong" },
899 { GTK_TYPE_ULONG, "gulong" },
900 { GTK_TYPE_FLOAT, "gfloat" },
901 { GTK_TYPE_DOUBLE, "gdouble" },
902 { GTK_TYPE_STRING, "GtkString" },
903 { GTK_TYPE_ENUM, "GtkEnum" },
904 { GTK_TYPE_FLAGS, "GtkFlags" },
905 { GTK_TYPE_BOXED, "GtkBoxed" },
906 { GTK_TYPE_POINTER, "gpointer" },
908 { GTK_TYPE_SIGNAL, "GtkSignal" },
909 { GTK_TYPE_ARGS, "GtkArgs" },
910 { GTK_TYPE_CALLBACK, "GtkCallback" },
911 { GTK_TYPE_C_CALLBACK, "GtkCCallback" },
912 { GTK_TYPE_FOREIGN, "GtkForeign" },
918 GtkEnumValue *values;
919 } builtin_info[GTK_TYPE_NUM_BUILTINS + 1] = {
920 #include "gtktypebuiltins_ids.c" /* type entries */
925 for (i = 0; i < sizeof (fundamental_info) / sizeof (fundamental_info[0]); i++)
929 /* relookup pointers afterwards.
931 type_id = gtk_type_register_intern (fundamental_info[i].name, GTK_TYPE_INVALID, NULL);
933 g_assert (type_id == fundamental_info[i].type_id);
936 gtk_object_init_type ();
938 for (i = 0; i < GTK_TYPE_NUM_BUILTINS; i++)
942 g_assert (builtin_info[i].type_name != NULL);
944 /* relookup pointers afterwards.
946 type_id = gtk_type_register_intern (builtin_info[i].type_name,
947 builtin_info[i].parent,
948 builtin_info[i].values);
950 g_assert (type_id != GTK_TYPE_INVALID);
952 (*builtin_info[i].type_id) = type_id;
957 gtk_identifier_get_type (void)
959 static GtkType identifier_type = 0;
961 if (!identifier_type)
962 identifier_type = gtk_type_register_intern ("GtkIdentifier", GTK_TYPE_STRING, NULL);
964 return identifier_type;