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 "gtkobject.h"
21 #include "gtktypeutils.h"
22 #include "gtkcontainer.h"
25 #define TYPE_NODES_BLOCK_SIZE (200)
27 typedef struct _GtkTypeNode GtkTypeNode;
32 GtkTypeInfo type_info;
34 guint chunk_alloc_locked : 1;
38 GList *children_types;
43 #define LOOKUP_TYPE_NODE(node_var, type) { \
46 register GtkType sqn = GTK_TYPE_SEQNO (type); \
47 if (sqn < n_type_nodes) \
48 node_var = type_nodes + sqn; \
56 static void gtk_type_class_init (GtkType node_type);
57 static guint gtk_type_name_hash (const char *key);
58 static gint gtk_type_name_compare (const char *a,
60 static void gtk_type_init_builtin_types (void);
62 static GtkTypeNode *type_nodes = NULL;
63 static guint n_type_nodes = 0;
64 static GHashTable *type_name_2_type_ht = NULL;
68 gtk_type_node_next_and_invalidate (void)
70 static guint n_free_type_nodes = 0;
71 register GtkTypeNode *node;
72 register GtkType new_type;
74 /* don't keep *any* GtkTypeNode pointers across invokation of this function!!!
77 if (n_free_type_nodes == 0)
84 size = n_type_nodes + TYPE_NODES_BLOCK_SIZE;
85 size *= sizeof (GtkTypeNode);
91 type_nodes = g_realloc (type_nodes, size);
93 n_free_type_nodes = size / sizeof (GtkTypeNode) - n_type_nodes;
95 memset (type_nodes + n_type_nodes, 0, n_free_type_nodes * sizeof (GtkTypeNode));
98 new_type = n_type_nodes++;
101 LOOKUP_TYPE_NODE (node, new_type);
103 node->type = new_type;
111 if (n_type_nodes == 0)
115 g_assert (sizeof (GtkType) >= 4);
117 zero = gtk_type_node_next_and_invalidate ();
118 g_assert (zero == NULL);
120 type_name_2_type_ht = g_hash_table_new ((GHashFunc) gtk_type_name_hash,
121 (GCompareFunc) gtk_type_name_compare);
123 gtk_type_init_builtin_types ();
128 gtk_type_set_chunk_alloc (GtkType type,
133 LOOKUP_TYPE_NODE (node, type);
134 g_return_if_fail (node != NULL);
135 g_return_if_fail (node->chunk_alloc_locked == FALSE);
139 g_mem_chunk_destroy (node->mem_chunk);
140 node->mem_chunk = NULL;
144 node->mem_chunk = g_mem_chunk_new (node->type_info.type_name,
145 node->type_info.object_size,
146 node->type_info.object_size * n_chunks,
151 gtk_type_create (GtkType parent_type,
153 GtkTypeInfo *type_info)
155 GtkTypeNode *new_node;
159 if (g_hash_table_lookup (type_name_2_type_ht, type_name))
161 g_warning ("gtk_type_create(): type `%s' already exists.", type_name);
167 GtkTypeNode *tmp_node;
169 LOOKUP_TYPE_NODE (tmp_node, parent_type);
172 g_warning ("gtk_type_create(): unknown parent type `%u'.", parent_type);
177 /* relookup pointers afterwards.
179 new_node = gtk_type_node_next_and_invalidate ();
183 new_node->type = GTK_TYPE_MAKE (parent_type, new_node->type);
184 LOOKUP_TYPE_NODE (parent, parent_type);
188 g_assert (new_node->type <= 0xff);
192 new_node->type_info = *type_info;
193 new_node->type_info.type_name = type_name;
194 /* new_node->type_info.reserved_1 = NULL; */
195 new_node->type_info.reserved_2 = NULL;
196 new_node->n_supers = parent ? parent->n_supers + 1 : 0;
197 new_node->chunk_alloc_locked = FALSE;
198 new_node->supers = g_new0 (GtkType, new_node->n_supers + 1);
199 new_node->parent_type = parent_type;
200 new_node->klass = NULL;
201 new_node->children_types = NULL;
202 new_node->mem_chunk = NULL;
205 parent->children_types = g_list_append (parent->children_types, GUINT_TO_POINTER (new_node->type));
208 for (i = 0; i < new_node->n_supers + 1; i++)
210 new_node->supers[i] = parent->type;
211 LOOKUP_TYPE_NODE (parent, parent->parent_type);
214 g_hash_table_insert (type_name_2_type_ht, new_node->type_info.type_name, GUINT_TO_POINTER (new_node->type));
216 return new_node->type;
220 gtk_type_unique (GtkType parent_type,
221 GtkTypeInfo *type_info)
226 g_return_val_if_fail (type_info != NULL, 0);
227 g_return_val_if_fail (type_info->type_name != NULL, 0);
229 if (n_type_nodes == 0)
232 type_name = g_strdup (type_info->type_name);
234 /* relookup pointers afterwards.
236 new_type = gtk_type_create (parent_type, type_name, type_info);
245 gtk_type_name (GtkType type)
249 LOOKUP_TYPE_NODE (node, type);
252 return node->type_info.type_name;
258 gtk_type_from_name (const gchar *name)
260 if (type_name_2_type_ht)
264 type = GPOINTER_TO_UINT (g_hash_table_lookup (type_name_2_type_ht, (gpointer) name));
273 gtk_type_parent (GtkType type)
277 LOOKUP_TYPE_NODE (node, type);
279 return node->parent_type;
285 gtk_type_parent_class (GtkType type)
289 LOOKUP_TYPE_NODE (node, type);
290 g_return_val_if_fail (node != NULL, NULL);
294 LOOKUP_TYPE_NODE (node, node->parent_type);
301 gtk_type_class_init (type);
302 LOOKUP_TYPE_NODE (node, type);
313 gtk_type_class (GtkType type)
317 LOOKUP_TYPE_NODE (node, type);
318 g_return_val_if_fail (node != NULL, NULL);
323 gtk_type_class_init (type);
324 LOOKUP_TYPE_NODE (node, type);
331 gtk_type_new (GtkType type)
338 LOOKUP_TYPE_NODE (node, type);
339 g_return_val_if_fail (node != NULL, NULL);
341 klass = gtk_type_class (type);
342 node->chunk_alloc_locked = TRUE;
345 object = g_mem_chunk_alloc (node->mem_chunk);
346 memset (object, 0, node->type_info.object_size);
349 object = g_malloc0 (node->type_info.object_size);
351 /* we need to call the base classes' object_init_func for derived
352 * objects with the object's ->klass field still pointing to the
353 * corresponding base class, otherwise overridden class functions
354 * could get called with partly-initialized objects.
356 for (i = node->n_supers; i > 0; i--)
360 LOOKUP_TYPE_NODE (pnode, node->supers[i]);
361 if (pnode->type_info.object_init_func)
363 object->klass = pnode->klass;
364 pnode->type_info.object_init_func (object);
367 object->klass = klass;
368 if (node->type_info.object_init_func)
369 node->type_info.object_init_func (object);
375 gtk_type_free (GtkType type,
380 g_return_if_fail (mem != NULL);
381 LOOKUP_TYPE_NODE (node, type);
382 g_return_if_fail (node != NULL);
385 g_mem_chunk_free (node->mem_chunk, mem);
391 gtk_type_children_types (GtkType type)
395 LOOKUP_TYPE_NODE (node, type);
397 return node->children_types;
403 gtk_type_describe_heritage (GtkType type)
408 LOOKUP_TYPE_NODE (node, type);
419 if (node->type_info.type_name)
420 g_message ("%s\n", node->type_info.type_name);
422 g_message ("<unnamed type>\n");
424 LOOKUP_TYPE_NODE (node, node->parent_type);
429 gtk_type_describe_tree (GtkType type,
434 LOOKUP_TYPE_NODE (node, type);
438 static gint indent = 0;
443 for (i = 0; i < indent; i++)
446 if (node->type_info.type_name)
447 g_message ("%s", node->type_info.type_name);
449 g_message ("(no-name)");
452 g_message (" ( %d bytes )\n", node->type_info.object_size);
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 GtkObjectClass *object_class;
504 GtkTypeNode *base_node;
507 g_assert (node->type_info.class_size >= sizeof (GtkObjectClass));
509 node->klass = g_malloc0 (node->type_info.class_size);
511 if (node->parent_type)
515 LOOKUP_TYPE_NODE (parent, node->parent_type);
518 gtk_type_class_init (parent->type);
519 LOOKUP_TYPE_NODE (node, type);
520 LOOKUP_TYPE_NODE (parent, node->parent_type);
524 memcpy (node->klass, parent->klass, parent->type_info.class_size);
527 object_class = node->klass;
528 object_class->type = node->type;
530 /* stack all base class initialization functions, so we
531 * call them in ascending order.
537 if (base_node->type_info.base_class_init_func)
538 slist = g_slist_prepend (slist, base_node->type_info.base_class_init_func);
539 LOOKUP_TYPE_NODE (base_node, base_node->parent_type);
545 for (walk = slist; walk; walk = walk->next)
547 register GtkClassInitFunc base_class_init;
549 base_class_init = walk->data;
550 base_class_init (node->klass);
551 LOOKUP_TYPE_NODE (node, type);
553 g_slist_free (slist);
556 if (node->type_info.class_init_func)
557 node->type_info.class_init_func (node->klass);
562 gtk_type_enum_get_values (GtkType enum_type)
564 if (GTK_FUNDAMENTAL_TYPE (enum_type) == GTK_TYPE_ENUM ||
565 GTK_FUNDAMENTAL_TYPE (enum_type) == GTK_TYPE_FLAGS)
569 LOOKUP_TYPE_NODE (node, enum_type);
571 return (GtkEnumValue*) node->type_info.reserved_1;
574 g_warning ("gtk_type_enum_get_values(): type `%s' is not derived from `GtkEnum' or `GtkFlags'",
575 gtk_type_name (enum_type));
581 gtk_type_flags_get_values (GtkType flags_type)
583 return gtk_type_enum_get_values (flags_type);
587 gtk_type_enum_find_value (GtkType enum_type,
588 const gchar *value_name)
590 g_return_val_if_fail (value_name != NULL, NULL);
592 if (GTK_FUNDAMENTAL_TYPE (enum_type) == GTK_TYPE_ENUM ||
593 GTK_FUNDAMENTAL_TYPE (enum_type) == GTK_TYPE_FLAGS)
597 vals = gtk_type_enum_get_values (enum_type);
600 if (strcmp (vals->value_name, value_name) == 0 ||
601 strcmp (vals->value_nick, value_name) == 0)
607 g_warning ("gtk_type_enum_find_value(): type `%s' is not derived from `GtkEnum' or `GtkFlags'",
608 gtk_type_name (enum_type));
614 gtk_type_flags_find_value (GtkType flag_type,
615 const gchar *value_name)
617 g_return_val_if_fail (value_name != NULL, NULL);
619 return gtk_type_enum_find_value (flag_type, value_name);
622 static inline GtkType
623 gtk_type_register_intern (gchar *name,
625 GtkEnumValue *values)
630 info.type_name = name;
631 info.object_size = 0;
633 info.class_init_func = NULL;
634 info.object_init_func = NULL;
635 info.reserved_1 = values;
636 info.reserved_2 = NULL;
638 /* relookup pointers afterwards.
640 type_id = gtk_type_create (parent, name, &info);
642 if (type_id && values)
646 /* check for proper type consistency and NULL termination
649 g_assert (GTK_FUNDAMENTAL_TYPE (type_id) == GTK_TYPE_ENUM ||
650 GTK_FUNDAMENTAL_TYPE (type_id) == GTK_TYPE_FLAGS);
653 while (values[i].value_name)
656 g_assert (values[i].value_name == NULL && values[i].value_nick == NULL);
663 gtk_type_register_enum (const gchar *type_name,
664 GtkEnumValue *values)
669 g_return_val_if_fail (type_name != NULL, 0);
671 name = g_strdup (type_name);
673 /* relookup pointers afterwards.
675 type_id = gtk_type_register_intern (name, GTK_TYPE_ENUM, values);
684 gtk_type_register_flags (const gchar *type_name,
685 GtkFlagValue *values)
690 g_return_val_if_fail (type_name != NULL, 0);
692 name = g_strdup (type_name);
694 /* relookup pointers afterwards.
696 type_id = gtk_type_register_intern (name, GTK_TYPE_FLAGS, values);
705 gtk_type_name_hash (const char *key)
711 result += (result << 3) + *key++;
717 gtk_type_name_compare (const char *a,
720 return (strcmp (a, b) == 0);
723 extern void gtk_object_init_type (void);
725 #include "makeenums.h" /* include for various places
726 * with enum definitions
728 #include "gtktypebuiltins_vars.c" /* type variable declarations
730 #include "gtktypebuiltins_evals.c" /* enum value definition arrays
734 gtk_type_init_builtin_types (void)
736 /* GTK_TYPE_INVALID has typeid 0. The first type id returned by
737 * gtk_type_unique is 1, which is GTK_TYPE_NONE. And so on.
743 } fundamental_info[] = {
744 { GTK_TYPE_NONE, "void" },
745 { GTK_TYPE_CHAR, "gchar" },
746 { GTK_TYPE_UCHAR, "guchar" },
747 { GTK_TYPE_BOOL, "gboolean" },
748 { GTK_TYPE_INT, "gint" },
749 { GTK_TYPE_UINT, "guint" },
750 { GTK_TYPE_LONG, "glong" },
751 { GTK_TYPE_ULONG, "gulong" },
752 { GTK_TYPE_FLOAT, "gfloat" },
753 { GTK_TYPE_DOUBLE, "gdouble" },
754 { GTK_TYPE_STRING, "GtkString" },
755 { GTK_TYPE_ENUM, "GtkEnum" },
756 { GTK_TYPE_FLAGS, "GtkFlags" },
757 { GTK_TYPE_BOXED, "GtkBoxed" },
758 { GTK_TYPE_POINTER, "gpointer" },
760 { GTK_TYPE_SIGNAL, "GtkSignal" },
761 { GTK_TYPE_ARGS, "GtkArgs" },
762 { GTK_TYPE_CALLBACK, "GtkCallback" },
763 { GTK_TYPE_C_CALLBACK, "GtkCCallback" },
764 { GTK_TYPE_FOREIGN, "GtkForeign" },
770 GtkEnumValue *values;
771 } builtin_info[GTK_TYPE_NUM_BUILTINS + 1] = {
772 #include "gtktypebuiltins_ids.c" /* type entries */
777 for (i = 0; i < sizeof (fundamental_info) / sizeof (fundamental_info[0]); i++)
781 /* relookup pointers afterwards.
783 type_id = gtk_type_register_intern (fundamental_info[i].name, GTK_TYPE_INVALID, NULL);
785 g_assert (type_id == fundamental_info[i].type_id);
788 gtk_object_init_type ();
790 for (i = 0; i < GTK_TYPE_NUM_BUILTINS; i++)
794 g_assert (builtin_info[i].type_name != NULL);
796 /* relookup pointers afterwards.
798 type_id = gtk_type_register_intern (builtin_info[i].type_name,
799 builtin_info[i].parent,
800 builtin_info[i].values);
802 g_assert (type_id != GTK_TYPE_INVALID);
804 (*builtin_info[i].type_id) = type_id;
809 gtk_identifier_get_type (void)
811 static GtkType identifier_type = 0;
813 if (!identifier_type)
814 identifier_type = gtk_type_register_intern ("GtkIdentifier", GTK_TYPE_STRING, NULL);
816 return identifier_type;