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 /* This can't be used here - new_type can be over 256!
100 * LOOKUP_TYPE_NODE (node, new_type);
101 * Code copied from above (we may assume we are all right here):
106 node = type_nodes + new_type;
109 node->type = new_type;
117 if (n_type_nodes == 0)
121 g_assert (sizeof (GtkType) >= 4);
123 zero = gtk_type_node_next_and_invalidate ();
124 g_assert (zero == NULL);
126 type_name_2_type_ht = g_hash_table_new ((GHashFunc) gtk_type_name_hash,
127 (GCompareFunc) gtk_type_name_compare);
129 gtk_type_init_builtin_types ();
134 gtk_type_set_chunk_alloc (GtkType type,
139 LOOKUP_TYPE_NODE (node, type);
140 g_return_if_fail (node != NULL);
141 g_return_if_fail (node->chunk_alloc_locked == FALSE);
145 g_mem_chunk_destroy (node->mem_chunk);
146 node->mem_chunk = NULL;
150 node->mem_chunk = g_mem_chunk_new (node->type_info.type_name,
151 node->type_info.object_size,
152 node->type_info.object_size * n_chunks,
157 gtk_type_create (GtkType parent_type,
159 GtkTypeInfo *type_info)
161 GtkTypeNode *new_node;
165 if (g_hash_table_lookup (type_name_2_type_ht, type_name))
167 g_warning ("gtk_type_create(): type `%s' already exists.", type_name);
173 GtkTypeNode *tmp_node;
175 LOOKUP_TYPE_NODE (tmp_node, parent_type);
178 g_warning ("gtk_type_create(): unknown parent type `%u'.", parent_type);
183 /* relookup pointers afterwards.
185 new_node = gtk_type_node_next_and_invalidate ();
189 new_node->type = GTK_TYPE_MAKE (parent_type, new_node->type);
190 LOOKUP_TYPE_NODE (parent, parent_type);
194 g_assert (new_node->type <= 0xff);
198 new_node->type_info = *type_info;
199 new_node->type_info.type_name = type_name;
200 /* new_node->type_info.reserved_1 = NULL; */
201 new_node->type_info.reserved_2 = NULL;
202 new_node->n_supers = parent ? parent->n_supers + 1 : 0;
203 new_node->chunk_alloc_locked = FALSE;
204 new_node->supers = g_new0 (GtkType, new_node->n_supers + 1);
205 new_node->parent_type = parent_type;
206 new_node->klass = NULL;
207 new_node->children_types = NULL;
208 new_node->mem_chunk = NULL;
211 parent->children_types = g_list_append (parent->children_types, GUINT_TO_POINTER (new_node->type));
214 for (i = 0; i < new_node->n_supers + 1; i++)
216 new_node->supers[i] = parent->type;
217 LOOKUP_TYPE_NODE (parent, parent->parent_type);
220 g_hash_table_insert (type_name_2_type_ht, new_node->type_info.type_name, GUINT_TO_POINTER (new_node->type));
222 return new_node->type;
226 gtk_type_unique (GtkType parent_type,
227 GtkTypeInfo *type_info)
232 g_return_val_if_fail (type_info != NULL, 0);
233 g_return_val_if_fail (type_info->type_name != NULL, 0);
235 if (n_type_nodes == 0)
238 type_name = g_strdup (type_info->type_name);
240 /* relookup pointers afterwards.
242 new_type = gtk_type_create (parent_type, type_name, type_info);
251 gtk_type_name (GtkType type)
255 LOOKUP_TYPE_NODE (node, type);
258 return node->type_info.type_name;
264 gtk_type_from_name (const gchar *name)
266 if (type_name_2_type_ht)
270 type = GPOINTER_TO_UINT (g_hash_table_lookup (type_name_2_type_ht, (gpointer) name));
279 gtk_type_parent (GtkType type)
283 LOOKUP_TYPE_NODE (node, type);
285 return node->parent_type;
291 gtk_type_parent_class (GtkType type)
295 LOOKUP_TYPE_NODE (node, type);
296 g_return_val_if_fail (node != NULL, NULL);
300 LOOKUP_TYPE_NODE (node, node->parent_type);
307 gtk_type_class_init (type);
308 LOOKUP_TYPE_NODE (node, type);
319 gtk_type_class (GtkType type)
323 LOOKUP_TYPE_NODE (node, type);
324 g_return_val_if_fail (node != NULL, NULL);
329 gtk_type_class_init (type);
330 LOOKUP_TYPE_NODE (node, type);
337 gtk_type_new (GtkType type)
340 GtkTypeObject *tobject;
343 LOOKUP_TYPE_NODE (node, type);
344 g_return_val_if_fail (node != NULL, NULL);
349 klass = gtk_type_class (type);
350 LOOKUP_TYPE_NODE (node, type);
352 node->chunk_alloc_locked = TRUE;
355 tobject = g_mem_chunk_alloc0 (node->mem_chunk);
357 tobject = g_malloc0 (node->type_info.object_size);
359 /* we need to call the base classes' object_init_func for derived
360 * objects with the object's ->klass field still pointing to the
361 * corresponding base class, otherwise overridden class functions
362 * could get called with partly-initialized objects. the real object
363 * class is passed as second argment to the initializers.
371 supers = node->supers;
372 for (i = node->n_supers; i > 0; i--)
374 LOOKUP_TYPE_NODE (pnode, supers[i]);
375 if (pnode->type_info.object_init_func)
377 tobject->klass = pnode->klass;
378 pnode->type_info.object_init_func (tobject, klass);
381 LOOKUP_TYPE_NODE (node, type);
383 tobject->klass = klass;
384 if (node->type_info.object_init_func)
386 node->type_info.object_init_func (tobject, klass);
387 tobject->klass = klass;
394 gtk_type_free (GtkType type,
399 g_return_if_fail (mem != NULL);
400 LOOKUP_TYPE_NODE (node, type);
401 g_return_if_fail (node != NULL);
404 g_mem_chunk_free (node->mem_chunk, mem);
410 gtk_type_children_types (GtkType type)
414 LOOKUP_TYPE_NODE (node, type);
416 return node->children_types;
422 gtk_type_describe_heritage (GtkType type)
427 LOOKUP_TYPE_NODE (node, type);
431 if (node->type_info.type_name)
434 node->type_info.type_name);
436 g_message ("%s<unnamed type>",
440 LOOKUP_TYPE_NODE (node, node->parent_type);
445 gtk_type_describe_tree (GtkType type,
450 LOOKUP_TYPE_NODE (node, type);
454 static gint indent = 0;
460 gstring = g_string_new ("");
462 for (i = 0; i < indent; i++)
463 g_string_append_c (gstring, ' ');
465 if (node->type_info.type_name)
466 g_string_append (gstring, node->type_info.type_name);
468 g_string_append (gstring, "<unnamed type>");
471 g_string_sprintfa (gstring, " (%d bytes)", node->type_info.object_size);
473 g_message ("%s", gstring->str);
474 g_string_free (gstring, TRUE);
479 for (list = node->children_types; list; list = list->next)
480 gtk_type_describe_tree (GPOINTER_TO_UINT (list->data), show_size);
487 gtk_type_is_a (GtkType type,
490 if (type == is_a_type)
494 register GtkTypeNode *node;
496 LOOKUP_TYPE_NODE (node, type);
499 register GtkTypeNode *a_node;
501 LOOKUP_TYPE_NODE (a_node, is_a_type);
504 if (a_node->n_supers <= node->n_supers)
505 return node->supers[node->n_supers - a_node->n_supers] == is_a_type;
514 gtk_type_class_init (GtkType type)
518 /* we need to relookup nodes everytime we called an external function */
519 LOOKUP_TYPE_NODE (node, type);
521 if (!node->klass && node->type_info.class_size)
523 GtkTypeClass *type_class;
524 GtkTypeNode *base_node;
527 if (node->type_info.class_size < sizeof (GtkTypeClass))
528 g_warning ("The `%s' class is too small to inherit from GtkTypeClass",
529 node->type_info.type_name);
531 node->klass = g_malloc0 (node->type_info.class_size);
533 if (node->parent_type)
537 LOOKUP_TYPE_NODE (parent, node->parent_type);
539 if (node->type_info.class_size < parent->type_info.class_size)
540 g_warning ("The `%s' class is smaller than its parent class `%s'",
541 node->type_info.type_name,
542 parent->type_info.type_name);
546 gtk_type_class_init (parent->type);
547 LOOKUP_TYPE_NODE (node, type);
548 LOOKUP_TYPE_NODE (parent, node->parent_type);
552 memcpy (node->klass, parent->klass, parent->type_info.class_size);
555 type_class = node->klass;
556 type_class->type = node->type;
558 /* stack all base class initialization functions, so we
559 * call them in ascending order.
565 if (base_node->type_info.base_class_init_func)
566 slist = g_slist_prepend (slist, base_node->type_info.base_class_init_func);
567 LOOKUP_TYPE_NODE (base_node, base_node->parent_type);
573 for (walk = slist; walk; walk = walk->next)
575 register GtkClassInitFunc base_class_init;
577 base_class_init = walk->data;
578 base_class_init (node->klass);
579 LOOKUP_TYPE_NODE (node, type);
581 g_slist_free (slist);
584 if (node->type_info.class_init_func)
585 node->type_info.class_init_func (node->klass);
590 gtk_type_descriptive_name (GtkType type)
594 name = gtk_type_name (type);
602 gtk_type_check_object_cast (GtkTypeObject *type_object,
607 g_warning ("invalid cast from (NULL) pointer to `%s'",
608 gtk_type_descriptive_name (cast_type));
611 if (!type_object->klass)
613 g_warning ("invalid unclassed pointer in cast to `%s'",
614 gtk_type_descriptive_name (cast_type));
617 /* currently, GTK_TYPE_OBJECT is the lowest fundamental type
618 * dominator for types that introduce classes.
620 if (type_object->klass->type < GTK_TYPE_OBJECT)
622 g_warning ("invalid class type `%s' in cast to `%s'",
623 gtk_type_descriptive_name (type_object->klass->type),
624 gtk_type_descriptive_name (cast_type));
627 if (!gtk_type_is_a (type_object->klass->type, cast_type))
629 g_warning ("invalid cast from `%s' to `%s'",
630 gtk_type_descriptive_name (type_object->klass->type),
631 gtk_type_descriptive_name (cast_type));
639 gtk_type_check_class_cast (GtkTypeClass *klass,
644 g_warning ("invalid class cast from (NULL) pointer to `%s'",
645 gtk_type_descriptive_name (cast_type));
648 /* currently, GTK_TYPE_OBJECT is the lowest fundamental type
649 * dominator for types that introduce classes.
651 if (klass->type < GTK_TYPE_OBJECT)
653 g_warning ("invalid class type `%s' in class cast to `%s'",
654 gtk_type_descriptive_name (klass->type),
655 gtk_type_descriptive_name (cast_type));
658 if (!gtk_type_is_a (klass->type, cast_type))
660 g_warning ("invalid class cast from `%s' to `%s'",
661 gtk_type_descriptive_name (klass->type),
662 gtk_type_descriptive_name (cast_type));
670 gtk_type_enum_get_values (GtkType enum_type)
672 if (GTK_FUNDAMENTAL_TYPE (enum_type) == GTK_TYPE_ENUM ||
673 GTK_FUNDAMENTAL_TYPE (enum_type) == GTK_TYPE_FLAGS)
677 LOOKUP_TYPE_NODE (node, enum_type);
679 return (GtkEnumValue*) node->type_info.reserved_1;
682 g_warning ("gtk_type_enum_get_values(): type `%s' is not derived from `GtkEnum' or `GtkFlags'",
683 gtk_type_name (enum_type));
689 gtk_type_flags_get_values (GtkType flags_type)
691 return gtk_type_enum_get_values (flags_type);
695 gtk_type_enum_find_value (GtkType enum_type,
696 const gchar *value_name)
698 g_return_val_if_fail (value_name != NULL, NULL);
700 if (GTK_FUNDAMENTAL_TYPE (enum_type) == GTK_TYPE_ENUM ||
701 GTK_FUNDAMENTAL_TYPE (enum_type) == GTK_TYPE_FLAGS)
705 vals = gtk_type_enum_get_values (enum_type);
707 while (vals->value_name)
709 if (strcmp (vals->value_name, value_name) == 0 ||
710 strcmp (vals->value_nick, value_name) == 0)
716 g_warning ("gtk_type_enum_find_value(): type `%s' is not derived from `GtkEnum' or `GtkFlags'",
717 gtk_type_name (enum_type));
723 gtk_type_flags_find_value (GtkType flag_type,
724 const gchar *value_name)
726 g_return_val_if_fail (value_name != NULL, NULL);
728 return gtk_type_enum_find_value (flag_type, value_name);
731 typedef struct _GtkTypeVarargType GtkTypeVarargType;
732 struct _GtkTypeVarargType
734 GtkType foreign_type;
735 GtkType varargs_type;
738 static GtkTypeVarargType *vararg_types = NULL;
739 static guint n_vararg_types = 0;
742 gtk_type_set_varargs_type (GtkType foreign_type,
743 GtkType varargs_type)
745 g_return_if_fail (foreign_type == GTK_FUNDAMENTAL_TYPE (foreign_type));
746 g_return_if_fail (foreign_type > GTK_TYPE_FUNDAMENTAL_LAST);
748 if (!((varargs_type >= GTK_TYPE_STRUCTURED_FIRST &&
749 varargs_type <= GTK_TYPE_STRUCTURED_LAST) ||
750 (varargs_type >= GTK_TYPE_FLAT_FIRST &&
751 varargs_type <= GTK_TYPE_FLAT_LAST) ||
752 varargs_type == GTK_TYPE_NONE))
754 g_warning ("invalid varargs type `%s' for fundamental type `%s'",
755 gtk_type_name (varargs_type),
756 gtk_type_name (foreign_type));
759 if (gtk_type_get_varargs_type (foreign_type))
761 g_warning ("varargs type is already registered for fundamental type `%s'",
762 gtk_type_name (foreign_type));
767 vararg_types = g_realloc (vararg_types, sizeof (GtkTypeVarargType) * n_vararg_types);
769 vararg_types[n_vararg_types - 1].foreign_type = foreign_type;
770 vararg_types[n_vararg_types - 1].varargs_type = varargs_type;
774 gtk_type_get_varargs_type (GtkType foreign_type)
779 type = GTK_FUNDAMENTAL_TYPE (foreign_type);
780 if (type <= GTK_TYPE_FUNDAMENTAL_LAST)
783 for (i = 0; i < n_vararg_types; i++)
784 if (vararg_types[i].foreign_type == type)
785 return vararg_types[i].varargs_type;
790 static inline GtkType
791 gtk_type_register_intern (gchar *name,
793 GtkEnumValue *values)
798 info.type_name = name;
799 info.object_size = 0;
801 info.class_init_func = NULL;
802 info.object_init_func = NULL;
803 info.reserved_1 = values;
804 info.reserved_2 = NULL;
806 /* relookup pointers afterwards.
808 type_id = gtk_type_create (parent, name, &info);
810 if (type_id && values)
814 /* check for proper type consistency and NULL termination
817 g_assert (GTK_FUNDAMENTAL_TYPE (type_id) == GTK_TYPE_ENUM ||
818 GTK_FUNDAMENTAL_TYPE (type_id) == GTK_TYPE_FLAGS);
821 while (values[i].value_name)
824 g_assert (values[i].value_name == NULL && values[i].value_nick == NULL);
831 gtk_type_register_enum (const gchar *type_name,
832 GtkEnumValue *values)
837 g_return_val_if_fail (type_name != NULL, 0);
839 name = g_strdup (type_name);
841 /* relookup pointers afterwards.
843 type_id = gtk_type_register_intern (name, GTK_TYPE_ENUM, values);
852 gtk_type_register_flags (const gchar *type_name,
853 GtkFlagValue *values)
858 g_return_val_if_fail (type_name != NULL, 0);
860 name = g_strdup (type_name);
862 /* relookup pointers afterwards.
864 type_id = gtk_type_register_intern (name, GTK_TYPE_FLAGS, values);
873 gtk_type_name_hash (const char *key)
879 result += (result << 3) + *key++;
885 gtk_type_name_compare (const char *a,
888 return (strcmp (a, b) == 0);
891 extern void gtk_object_init_type (void);
893 #include "makeenums.h" /* include for various places
894 * with enum definitions
896 #include "gtktypebuiltins_vars.c" /* type variable declarations
898 #include "gtktypebuiltins_evals.c" /* enum value definition arrays
902 gtk_type_init_builtin_types (void)
904 /* GTK_TYPE_INVALID has typeid 0. The first type id returned by
905 * gtk_type_unique is 1, which is GTK_TYPE_NONE. And so on.
911 } fundamental_info[] = {
912 { GTK_TYPE_NONE, "void" },
913 { GTK_TYPE_CHAR, "gchar" },
914 { GTK_TYPE_UCHAR, "guchar" },
915 { GTK_TYPE_BOOL, "gboolean" },
916 { GTK_TYPE_INT, "gint" },
917 { GTK_TYPE_UINT, "guint" },
918 { GTK_TYPE_LONG, "glong" },
919 { GTK_TYPE_ULONG, "gulong" },
920 { GTK_TYPE_FLOAT, "gfloat" },
921 { GTK_TYPE_DOUBLE, "gdouble" },
922 { GTK_TYPE_STRING, "GtkString" },
923 { GTK_TYPE_ENUM, "GtkEnum" },
924 { GTK_TYPE_FLAGS, "GtkFlags" },
925 { GTK_TYPE_BOXED, "GtkBoxed" },
926 { GTK_TYPE_POINTER, "gpointer" },
928 { GTK_TYPE_SIGNAL, "GtkSignal" },
929 { GTK_TYPE_ARGS, "GtkArgs" },
930 { GTK_TYPE_CALLBACK, "GtkCallback" },
931 { GTK_TYPE_C_CALLBACK, "GtkCCallback" },
932 { GTK_TYPE_FOREIGN, "GtkForeign" },
938 GtkEnumValue *values;
939 } builtin_info[GTK_TYPE_NUM_BUILTINS + 1] = {
940 #include "gtktypebuiltins_ids.c" /* type entries */
945 for (i = 0; i < sizeof (fundamental_info) / sizeof (fundamental_info[0]); i++)
949 /* relookup pointers afterwards.
951 type_id = gtk_type_register_intern (fundamental_info[i].name, GTK_TYPE_INVALID, NULL);
953 g_assert (type_id == fundamental_info[i].type_id);
956 gtk_object_init_type ();
958 for (i = 0; i < GTK_TYPE_NUM_BUILTINS; i++)
962 g_assert (builtin_info[i].type_name != NULL);
964 /* relookup pointers afterwards.
966 type_id = gtk_type_register_intern (builtin_info[i].type_name,
967 builtin_info[i].parent,
968 builtin_info[i].values);
970 g_assert (type_id != GTK_TYPE_INVALID);
972 (*builtin_info[i].type_id) = type_id;
977 gtk_identifier_get_type (void)
979 static GtkType identifier_type = 0;
981 if (!identifier_type)
982 identifier_type = gtk_type_register_intern ("GtkIdentifier", GTK_TYPE_STRING, NULL);
984 return identifier_type;