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"
24 #define TYPE_NODES_BLOCK_SIZE (200)
26 typedef struct _GtkTypeNode GtkTypeNode;
31 GtkTypeInfo type_info;
33 guint chunk_alloc_locked : 1;
37 GList *children_types;
42 #define LOOKUP_TYPE_NODE(node_var, type) { \
45 register GtkType sqn = GTK_TYPE_SEQNO (type); \
46 if (sqn < n_type_nodes) \
47 node_var = type_nodes + sqn; \
55 static void gtk_type_class_init (GtkTypeNode *node);
56 static guint gtk_type_name_hash (const char *key);
57 static gint gtk_type_name_compare (const char *a,
59 static void gtk_type_init_builtin_types (void);
61 static GtkTypeNode *type_nodes = NULL;
62 static guint n_type_nodes = 0;
63 static GHashTable *type_name_2_type_ht = NULL;
64 static const gchar *key_enum_vals = "gtk-type-enum-values";
65 static guint key_id_enum_vals = 0;
69 gtk_type_node_next_and_invalidate (void)
71 static guint n_free_type_nodes = 0;
72 register GtkTypeNode *node;
73 register GtkType new_type;
75 /* don't keep *any* GtkTypeNode pointers across invokation of this function!!!
78 if (n_free_type_nodes == 0)
85 size = n_type_nodes + TYPE_NODES_BLOCK_SIZE;
86 size *= sizeof (GtkTypeNode);
92 type_nodes = g_realloc (type_nodes, size);
94 n_free_type_nodes = size / sizeof (GtkTypeNode) - n_type_nodes;
96 memset (type_nodes + n_type_nodes, 0, n_free_type_nodes * sizeof (GtkTypeNode));
99 new_type = n_type_nodes++;
102 LOOKUP_TYPE_NODE (node, new_type);
104 node->type = new_type;
112 if (n_type_nodes == 0)
116 g_assert (sizeof (GtkType) >= 4);
118 zero = gtk_type_node_next_and_invalidate ();
119 g_assert (zero == NULL);
121 type_name_2_type_ht = g_hash_table_new ((GHashFunc) gtk_type_name_hash,
122 (GCompareFunc) gtk_type_name_compare);
124 gtk_type_init_builtin_types ();
129 gtk_type_set_chunk_alloc (GtkType type,
134 LOOKUP_TYPE_NODE (node, type);
135 g_return_if_fail (node != NULL);
136 g_return_if_fail (node->chunk_alloc_locked == FALSE);
140 g_mem_chunk_destroy (node->mem_chunk);
141 node->mem_chunk = NULL;
145 node->mem_chunk = g_mem_chunk_new (node->type_info.type_name,
146 node->type_info.object_size,
147 node->type_info.object_size * n_chunks,
152 gtk_type_unique (GtkType parent_type,
153 GtkTypeInfo *type_info)
155 GtkTypeNode *new_node;
159 g_return_val_if_fail (type_info != NULL, 0);
161 if (n_type_nodes == 0)
164 if (g_hash_table_lookup (type_name_2_type_ht, type_info->type_name))
166 g_warning ("gtk_type_unique(): type `%s' already exists.", type_info->type_name);
171 GtkTypeNode *tmp_node;
173 LOOKUP_TYPE_NODE (tmp_node, parent_type);
176 g_warning ("gtk_type_unique(): unknown parent type `%u'.", parent_type);
181 /* relookup pointer afterwards.
183 new_node = gtk_type_node_next_and_invalidate ();
187 new_node->type = GTK_TYPE_MAKE (parent_type, new_node->type);
188 LOOKUP_TYPE_NODE (parent, parent_type);
192 g_assert (new_node->type <= 0xff);
196 new_node->type_info = *type_info;
197 new_node->type_info.type_name = g_strdup (type_info->type_name);
198 new_node->n_supers = parent ? parent->n_supers + 1 : 0;
199 new_node->chunk_alloc_locked = FALSE;
200 new_node->supers = g_new0 (GtkType, new_node->n_supers + 1);
201 new_node->parent_type = parent_type;
202 new_node->klass = NULL;
203 new_node->children_types = NULL;
204 new_node->mem_chunk = NULL;
207 parent->children_types = g_list_append (parent->children_types, GUINT_TO_POINTER (new_node->type));
210 for (i = 0; i < new_node->n_supers + 1; i++)
212 new_node->supers[i] = parent->type;
213 LOOKUP_TYPE_NODE (parent, parent->parent_type);
216 g_hash_table_insert (type_name_2_type_ht, new_node->type_info.type_name, GUINT_TO_POINTER (new_node->type));
218 return new_node->type;
222 gtk_type_name (GtkType type)
226 LOOKUP_TYPE_NODE (node, type);
229 return node->type_info.type_name;
235 gtk_type_from_name (const gchar *name)
237 if (type_name_2_type_ht)
241 type = GPOINTER_TO_UINT (g_hash_table_lookup (type_name_2_type_ht, (gpointer) name));
250 gtk_type_parent (GtkType type)
254 LOOKUP_TYPE_NODE (node, type);
256 return node->parent_type;
262 gtk_type_parent_class (GtkType type)
266 LOOKUP_TYPE_NODE (node, type);
267 g_return_val_if_fail (node != NULL, NULL);
271 LOOKUP_TYPE_NODE (node, node->parent_type);
276 gtk_type_class_init (node);
286 gtk_type_class (GtkType type)
290 LOOKUP_TYPE_NODE (node, type);
291 g_return_val_if_fail (node != NULL, NULL);
294 gtk_type_class_init (node);
300 gtk_type_new (GtkType type)
307 LOOKUP_TYPE_NODE (node, type);
308 g_return_val_if_fail (node != NULL, NULL);
310 klass = gtk_type_class (type);
311 node->chunk_alloc_locked = TRUE;
314 object = g_mem_chunk_alloc (node->mem_chunk);
315 memset (object, 0, node->type_info.object_size);
318 object = g_malloc0 (node->type_info.object_size);
319 object->klass = klass;
321 for (i = node->n_supers; i > 0; i--)
325 LOOKUP_TYPE_NODE (pnode, node->supers[i]);
326 if (pnode->type_info.object_init_func)
327 (* pnode->type_info.object_init_func) (object);
329 if (node->type_info.object_init_func)
330 (* node->type_info.object_init_func) (object);
336 gtk_type_free (GtkType type,
341 g_return_if_fail (mem != NULL);
342 LOOKUP_TYPE_NODE (node, type);
343 g_return_if_fail (node != NULL);
346 g_mem_chunk_free (node->mem_chunk, mem);
352 gtk_type_describe_heritage (GtkType type)
357 LOOKUP_TYPE_NODE (node, type);
368 if (node->type_info.type_name)
369 g_print ("%s\n", node->type_info.type_name);
371 g_print ("<unnamed type>\n");
373 LOOKUP_TYPE_NODE (node, node->parent_type);
378 gtk_type_describe_tree (GtkType type,
383 LOOKUP_TYPE_NODE (node, type);
387 static gint indent = 0;
392 for (i = 0; i < indent; i++)
395 if (node->type_info.type_name)
396 g_print ("%s", node->type_info.type_name);
398 g_print ("(no-name)");
401 g_print (" ( %d bytes )\n", node->type_info.object_size);
408 for (list = node->children_types; list; list = list->next)
409 gtk_type_describe_tree (GPOINTER_TO_UINT (list->data), show_size);
416 gtk_type_is_a (GtkType type,
419 if (type == is_a_type)
423 register GtkTypeNode *node;
425 LOOKUP_TYPE_NODE (node, type);
428 register GtkTypeNode *a_node;
430 LOOKUP_TYPE_NODE (a_node, is_a_type);
433 if (a_node->n_supers <= node->n_supers)
434 return node->supers[node->n_supers - a_node->n_supers] == is_a_type;
443 gtk_type_get_arg (GtkObject *object,
450 g_return_if_fail (object != NULL);
451 g_return_if_fail (arg != NULL);
453 LOOKUP_TYPE_NODE (node, type);
455 if (node && node->type_info.arg_get_func)
456 (* node->type_info.arg_get_func) (object, arg, arg_id);
458 arg->type = GTK_TYPE_INVALID;
462 gtk_type_set_arg (GtkObject *object,
469 g_return_if_fail (object != NULL);
470 g_return_if_fail (arg != NULL);
472 LOOKUP_TYPE_NODE (node, type);
474 if (node && node->type_info.arg_set_func)
475 (* node->type_info.arg_set_func) (object, arg, arg_id);
479 gtk_arg_copy (GtkArg *src_arg,
482 g_return_val_if_fail (src_arg != NULL, NULL);
486 dest_arg = g_new0 (GtkArg, 1);
487 dest_arg->name = src_arg->name;
490 dest_arg->type = src_arg->type;
491 dest_arg->d = src_arg->d;
493 if (src_arg->type == GTK_TYPE_STRING)
494 dest_arg->d.string_data = g_strdup (src_arg->d.string_data);
500 gtk_enum_get_values (GtkType enum_type)
502 if (gtk_type_is_a (enum_type, GTK_TYPE_ENUM) ||
503 gtk_type_is_a (enum_type, GTK_TYPE_FLAGS))
504 return g_dataset_id_get_data (gtk_type_name (enum_type), key_id_enum_vals);
506 g_warning ("gtk_enum_get_values(): type `%s' is not derived from `enum' or `flags'",
507 gtk_type_name (enum_type));
513 gtk_enum_set_values (GtkType enum_type,
514 GtkEnumValue *values)
516 if (!key_id_enum_vals)
517 key_id_enum_vals = g_dataset_force_id (key_enum_vals);
519 if (gtk_type_is_a (enum_type, GTK_TYPE_ENUM) ||
520 gtk_type_is_a (enum_type, GTK_TYPE_FLAGS))
524 type_name = gtk_type_name (enum_type);
525 if (g_dataset_id_get_data (type_name, key_id_enum_vals))
526 g_warning ("gtk_enum_set_values(): enum values for `%s' are already set",
529 g_dataset_id_set_data (type_name,
535 g_warning ("gtk_enum_set_values(): type `%s' is not derived from `enum' or `flags'",
536 gtk_type_name (enum_type));
540 gtk_type_class_init (GtkTypeNode *node)
542 if (!node->klass && node->type_info.class_size)
544 node->klass = g_malloc0 (node->type_info.class_size);
546 if (node->parent_type)
550 LOOKUP_TYPE_NODE (parent, node->parent_type);
552 gtk_type_class_init (parent);
555 memcpy (node->klass, parent->klass, parent->type_info.class_size);
558 if (gtk_type_is_a (node->type, GTK_TYPE_OBJECT))
560 GtkObjectClass *object_class;
562 /* FIXME: this initialization needs to be done through
563 * a function pointer someday.
565 g_assert (node->type_info.class_size >= sizeof (GtkObjectClass));
567 object_class = node->klass;
568 object_class->type = node->type;
569 object_class->signals = NULL;
570 object_class->nsignals = 0;
571 object_class->n_args = 0;
574 if (node->type_info.class_init_func)
575 (* node->type_info.class_init_func) (node->klass);
580 gtk_type_name_hash (const char *key)
586 result += (result << 3) + *key++;
592 gtk_type_name_compare (const char *a,
595 return (strcmp (a, b) == 0);
599 gtk_type_register_builtin (char *name,
604 info.type_name = name;
605 info.object_size = info.class_size = 0;
606 info.class_init_func = NULL;
607 info.object_init_func = NULL;
608 info.arg_set_func = NULL;
609 info.arg_get_func = NULL;
611 return gtk_type_unique (parent, &info);
614 extern void gtk_object_init_type (void);
616 GtkType gtk_type_builtins[GTK_TYPE_NUM_BUILTINS];
618 #include "makeenums.h" /* include for various places with enum definitions */
619 #include "gtktypebuiltins1.c"
622 gtk_type_init_builtin_types (void)
624 /* GTK_TYPE_INVALID has typeid 0. The first type id returned by
625 * gtk_type_unique is 1, which is GTK_TYPE_NONE. And so on.
631 } fundamental_info[] = {
632 { GTK_TYPE_NONE, "void" },
633 { GTK_TYPE_CHAR, "char" },
634 { GTK_TYPE_BOOL, "bool" },
635 { GTK_TYPE_INT, "int" },
636 { GTK_TYPE_UINT, "uint" },
637 { GTK_TYPE_LONG, "long" },
638 { GTK_TYPE_ULONG, "ulong" },
639 { GTK_TYPE_FLOAT, "float" },
640 { GTK_TYPE_DOUBLE, "double" },
641 { GTK_TYPE_STRING, "string" },
642 { GTK_TYPE_ENUM, "enum" },
643 { GTK_TYPE_FLAGS, "flags" },
644 { GTK_TYPE_BOXED, "boxed" },
645 { GTK_TYPE_FOREIGN, "foreign" },
646 { GTK_TYPE_CALLBACK, "callback" },
647 { GTK_TYPE_ARGS, "args" },
649 { GTK_TYPE_POINTER, "pointer" },
650 { GTK_TYPE_SIGNAL, "signal" },
651 { GTK_TYPE_C_CALLBACK, "c_callback" }
656 GtkEnumValue *values;
658 #include "gtktypebuiltins2.c"
663 for (i = 0; i < sizeof (fundamental_info) / sizeof (fundamental_info[0]); i++)
667 id = gtk_type_register_builtin (fundamental_info[i].name,
669 g_assert (id == fundamental_info[i].type_id);
672 gtk_object_init_type ();
674 for (i = 0; builtin_info[i].name; i++)
676 gtk_type_builtins[i] =
677 gtk_type_register_builtin (builtin_info[i].name,
678 builtin_info[i].parent);
679 if (gtk_type_is_a (gtk_type_builtins[i], GTK_TYPE_ENUM) ||
680 gtk_type_is_a (gtk_type_builtins[i], GTK_TYPE_FLAGS))
681 gtk_enum_set_values (gtk_type_builtins[i], builtin_info[i].values);