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;
36 GList *children_types;
40 #define LOOKUP_TYPE_NODE(node_var, type) { \
43 register GtkType sqn = GTK_TYPE_SEQNO (type); \
44 if (sqn < n_type_nodes) \
45 node_var = type_nodes + sqn; \
53 static void gtk_type_class_init (GtkTypeNode *node);
54 static guint gtk_type_name_hash (const char *key);
55 static gint gtk_type_name_compare (const char *a,
57 static void gtk_type_init_builtin_types (void);
59 static GtkTypeNode *type_nodes = NULL;
60 static guint n_type_nodes = 0;
61 static GHashTable *type_name_2_type_ht = NULL;
65 gtk_type_node_next_and_invalidate (void)
67 static guint n_free_type_nodes = 0;
68 register GtkTypeNode *node;
69 register GtkType new_type;
71 /* don't keep *any* GtkTypeNode pointers across invokation of this function!!!
74 if (n_free_type_nodes == 0)
81 size = n_type_nodes + TYPE_NODES_BLOCK_SIZE;
82 size *= sizeof (GtkTypeNode);
88 type_nodes = g_realloc (type_nodes, size);
90 n_free_type_nodes = size / sizeof (GtkTypeNode) - n_type_nodes;
92 memset (type_nodes + n_type_nodes, 0, n_free_type_nodes * sizeof (GtkTypeNode));
95 new_type = n_type_nodes++;
98 LOOKUP_TYPE_NODE (node, new_type);
100 node->type = new_type;
108 if (n_type_nodes == 0)
112 g_assert (sizeof (GtkType) >= 4);
114 zero = gtk_type_node_next_and_invalidate ();
115 g_assert (zero == NULL);
117 type_name_2_type_ht = g_hash_table_new ((GHashFunc) gtk_type_name_hash,
118 (GCompareFunc) gtk_type_name_compare);
120 gtk_type_init_builtin_types ();
125 gtk_type_unique (GtkType parent_type,
126 GtkTypeInfo *type_info)
128 GtkTypeNode *new_node;
132 g_return_val_if_fail (type_info != NULL, 0);
134 if (n_type_nodes == 0)
137 if (g_hash_table_lookup (type_name_2_type_ht, type_info->type_name))
139 g_warning ("gtk_type_unique(): type `%s' already exists.", type_info->type_name);
144 GtkTypeNode *tmp_node;
146 LOOKUP_TYPE_NODE (tmp_node, parent_type);
149 g_warning ("gtk_type_unique(): unknown parent type `%u'.", parent_type);
154 /* relookup pointer afterwards.
156 new_node = gtk_type_node_next_and_invalidate ();
160 new_node->type = GTK_TYPE_MAKE (parent_type, new_node->type);
161 LOOKUP_TYPE_NODE (parent, parent_type);
165 g_assert (new_node->type <= 0xff);
169 new_node->type_info = *type_info;
170 new_node->type_info.type_name = g_strdup (type_info->type_name);
171 new_node->n_supers = parent ? parent->n_supers + 1 : 0;
172 new_node->supers = g_new0 (GtkType, new_node->n_supers + 1);
173 new_node->parent_type = parent_type;
174 new_node->klass = NULL;
175 new_node->children_types = NULL;
178 parent->children_types = g_list_append (parent->children_types, (gpointer) new_node->type);
181 for (i = 0; i < new_node->n_supers + 1; i++)
183 new_node->supers[i] = parent->type;
184 LOOKUP_TYPE_NODE (parent, parent->parent_type);
187 g_hash_table_insert (type_name_2_type_ht, new_node->type_info.type_name, (gpointer) new_node->type);
189 return new_node->type;
193 gtk_type_name (GtkType type)
197 LOOKUP_TYPE_NODE (node, type);
200 return node->type_info.type_name;
206 gtk_type_from_name (const gchar *name)
208 if (type_name_2_type_ht)
212 type = (GtkType) g_hash_table_lookup (type_name_2_type_ht, (gpointer) name);
221 gtk_type_parent (GtkType type)
225 LOOKUP_TYPE_NODE (node, type);
227 return node->parent_type;
233 gtk_type_parent_class (GtkType type)
237 LOOKUP_TYPE_NODE (node, type);
238 g_return_val_if_fail (node != NULL, NULL);
242 LOOKUP_TYPE_NODE (node, node->parent_type);
247 gtk_type_class_init (node);
257 gtk_type_class (GtkType type)
261 LOOKUP_TYPE_NODE (node, type);
262 g_return_val_if_fail (node != NULL, NULL);
265 gtk_type_class_init (node);
271 gtk_type_new (GtkType type)
278 LOOKUP_TYPE_NODE (node, type);
279 g_return_val_if_fail (node != NULL, NULL);
281 klass = gtk_type_class (type);
282 object = g_malloc0 (node->type_info.object_size);
283 object->klass = klass;
285 for (i = node->n_supers; i > 0; i--)
289 LOOKUP_TYPE_NODE (pnode, node->supers[i]);
290 if (pnode->type_info.object_init_func)
291 (* pnode->type_info.object_init_func) (object);
293 if (node->type_info.object_init_func)
294 (* node->type_info.object_init_func) (object);
300 gtk_type_describe_heritage (GtkType type)
305 LOOKUP_TYPE_NODE (node, type);
316 if (node->type_info.type_name)
317 g_print ("%s\n", node->type_info.type_name);
319 g_print ("<unnamed type>\n");
321 LOOKUP_TYPE_NODE (node, node->parent_type);
326 gtk_type_describe_tree (GtkType type,
331 LOOKUP_TYPE_NODE (node, type);
335 static gint indent = 0;
340 for (i = 0; i < indent; i++)
343 if (node->type_info.type_name)
344 g_print ("%s", node->type_info.type_name);
346 g_print ("(no-name)");
349 g_print (" ( %d bytes )\n", node->type_info.object_size);
356 for (list = node->children_types; list; list = list->next)
357 gtk_type_describe_tree ((GtkType) list->data, show_size);
364 gtk_type_is_a (GtkType type,
367 register GtkTypeNode *node;
369 /* we already check for type==is_a_type in the
370 * wrapper macro GTK_TYPE_IS_A()
373 LOOKUP_TYPE_NODE (node, type);
376 register GtkTypeNode *a_node;
378 LOOKUP_TYPE_NODE (a_node, is_a_type);
381 if (a_node->n_supers <= node->n_supers)
382 return node->supers[node->n_supers - a_node->n_supers] == is_a_type;
390 gtk_type_get_arg (GtkObject *object,
397 g_return_if_fail (object != NULL);
398 g_return_if_fail (arg != NULL);
400 LOOKUP_TYPE_NODE (node, type);
402 if (node && node->type_info.arg_get_func)
403 (* node->type_info.arg_get_func) (object, arg, arg_id);
405 arg->type = GTK_TYPE_INVALID;
409 gtk_type_set_arg (GtkObject *object,
416 g_return_if_fail (object != NULL);
417 g_return_if_fail (arg != NULL);
419 LOOKUP_TYPE_NODE (node, type);
421 if (node && node->type_info.arg_set_func)
422 (* node->type_info.arg_set_func) (object, arg, arg_id);
426 gtk_arg_copy (GtkArg *src_arg,
429 g_return_val_if_fail (src_arg != NULL, NULL);
433 dest_arg = g_new0 (GtkArg, 1);
434 dest_arg->name = src_arg->name;
437 dest_arg->type = src_arg->type;
438 dest_arg->d = src_arg->d;
440 if (src_arg->type == GTK_TYPE_STRING)
441 dest_arg->d.string_data = g_strdup (src_arg->d.string_data);
447 gtk_type_class_init (GtkTypeNode *node)
449 if (!node->klass && node->type_info.class_size)
451 node->klass = g_new0 (guchar, node->type_info.class_size);
453 if (node->parent_type)
457 LOOKUP_TYPE_NODE (parent, node->parent_type);
459 gtk_type_class_init (parent);
462 memcpy (node->klass, parent->klass, parent->type_info.class_size);
465 if (GTK_TYPE_IS_A (node->type, GTK_TYPE_OBJECT))
467 GtkObjectClass *object_class;
469 /* FIXME: this initialization needs to be done through
470 * a function pointer someday.
472 g_assert (node->type_info.class_size >= sizeof (GtkObjectClass));
474 object_class = node->klass;
475 object_class->type = node->type;
476 object_class->signals = NULL;
477 object_class->nsignals = 0;
478 object_class->n_args = 0;
481 if (node->type_info.class_init_func)
482 (* node->type_info.class_init_func) (node->klass);
487 gtk_type_name_hash (const char *key)
493 result += (result << 3) + *key++;
499 gtk_type_name_compare (const char *a,
502 return (strcmp (a, b) == 0);
506 gtk_type_register_builtin (char *name,
511 info.type_name = name;
512 info.object_size = info.class_size = 0;
513 info.class_init_func = NULL;
514 info.object_init_func = NULL;
515 info.arg_set_func = NULL;
516 info.arg_get_func = NULL;
518 return gtk_type_unique (parent, &info);
521 extern void gtk_object_init_type (void);
523 GtkType gtk_type_builtins[GTK_TYPE_NUM_BUILTINS];
526 gtk_type_init_builtin_types (void)
528 /* GTK_TYPE_INVALID has typeid 0. The first type id returned by
529 gtk_type_unique is 1, which is GTK_TYPE_NONE. And so on. */
534 } fundamental_info[] = {
535 { GTK_TYPE_NONE, "void" },
536 { GTK_TYPE_CHAR, "char" },
537 { GTK_TYPE_BOOL, "bool" },
538 { GTK_TYPE_INT, "int" },
539 { GTK_TYPE_UINT, "uint" },
540 { GTK_TYPE_LONG, "long" },
541 { GTK_TYPE_ULONG, "ulong" },
542 { GTK_TYPE_FLOAT, "float" },
543 { GTK_TYPE_DOUBLE, "double" },
544 { GTK_TYPE_STRING, "string" },
545 { GTK_TYPE_ENUM, "enum" },
546 { GTK_TYPE_FLAGS, "flags" },
547 { GTK_TYPE_BOXED, "boxed" },
548 { GTK_TYPE_FOREIGN, "foreign" },
549 { GTK_TYPE_CALLBACK, "callback" },
550 { GTK_TYPE_ARGS, "args" },
552 { GTK_TYPE_POINTER, "pointer" },
553 { GTK_TYPE_SIGNAL, "signal" },
554 { GTK_TYPE_C_CALLBACK, "c_callback" }
561 #include "gtktypebuiltins.c"
567 for (i = 0; i < sizeof (fundamental_info) / sizeof (fundamental_info[0]); i++)
570 id = gtk_type_register_builtin (fundamental_info[i].name,
572 g_assert (id == fundamental_info[i].enum_id);
575 gtk_object_init_type ();
577 for (i = 0; builtin_info[i].name; i++)
579 gtk_type_builtins[i] =
580 gtk_type_register_builtin (builtin_info[i].name,
581 builtin_info[i].parent);