]> Pileus Git - ~andy/gtk/blob - gtk/gtktypeutils.c
Initial revision
[~andy/gtk] / gtk / gtktypeutils.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
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.
8  *
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.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the Free
16  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17  */
18 #include <string.h>
19 #include "gtkobject.h"
20 #include "gtktypeutils.h"
21
22
23 typedef struct _GtkTypeNode GtkTypeNode;
24
25 struct _GtkTypeNode
26 {
27   GtkType type;
28   gint init_class;
29   gpointer klass;
30   GtkTypeInfo type_info;
31   GtkTypeNode *parent;
32   GList *children;
33 };
34
35
36 static void  gtk_type_insert       (guint        parent_type,
37                                     GtkType      type,
38                                     GtkTypeInfo *type_info);
39 static void  gtk_type_class_init   (GtkTypeNode *node);
40 static void  gtk_type_object_init  (GtkTypeNode *node,
41                                     gpointer     object);
42 static guint gtk_type_hash         (GtkType     *key);
43 static gint  gtk_type_compare      (GtkType     *a,
44                                     GtkType     *b);
45 static guint gtk_type_name_hash    (const char  *key);
46 static gint  gtk_type_name_compare (const char  *a,
47                                     const char  *b);
48 static void  gtk_type_init_builtin_types ();
49
50
51 static int initialize = TRUE;
52 static GHashTable *type_hash_table = NULL;
53 static GHashTable *name_hash_table = NULL;
54
55
56 void
57 gtk_type_init ()
58 {
59   if (initialize)
60     {
61       g_assert (sizeof (GtkType) >= 4);
62
63       initialize = FALSE;
64       type_hash_table = g_hash_table_new ((GHashFunc) gtk_type_hash,
65                                           (GCompareFunc) gtk_type_compare);
66       name_hash_table = g_hash_table_new ((GHashFunc) gtk_type_name_hash,
67                                           (GCompareFunc) gtk_type_name_compare);
68       gtk_type_init_builtin_types ();
69     }
70 }
71
72 GtkType
73 gtk_type_unique (GtkType      parent_type,
74                  GtkTypeInfo *type_info)
75 {
76   static guint next_seqno = 0;
77   GtkType new_type;
78
79   g_return_val_if_fail (type_info != NULL, 0);
80
81   if (initialize)
82     gtk_type_init ();
83
84   next_seqno++;
85   if (parent_type == GTK_TYPE_INVALID)
86     new_type = next_seqno;
87   else
88     new_type = GTK_TYPE_MAKE (GTK_FUNDAMENTAL_TYPE (parent_type), next_seqno);
89   gtk_type_insert (parent_type, new_type, type_info);
90
91   return new_type;
92 }
93
94 gchar*
95 gtk_type_name (GtkType type)
96 {
97   GtkTypeNode *node;
98
99   if (initialize)
100     gtk_type_init ();
101
102   node = g_hash_table_lookup (type_hash_table, &type);
103
104   if (node)
105     return node->type_info.type_name;
106
107   return NULL;
108 }
109
110 GtkType
111 gtk_type_from_name (const gchar *name)
112 {
113   GtkTypeNode *node;
114
115   if (initialize)
116     gtk_type_init ();
117
118   node = g_hash_table_lookup (name_hash_table, (gpointer) name);
119
120   if (node)
121     return node->type;
122
123   return 0;
124 }
125
126 GtkType
127 gtk_type_parent (GtkType type)
128 {
129   GtkTypeNode *node;
130
131   if (initialize)
132     gtk_type_init ();
133
134   node = g_hash_table_lookup (type_hash_table, &type);
135
136   if (node && node->parent)
137     return node->parent->type;
138
139   return 0;
140 }
141
142 gpointer
143 gtk_type_class (GtkType type)
144 {
145   GtkTypeNode *node;
146
147   if (initialize)
148     gtk_type_init ();
149
150   node = g_hash_table_lookup (type_hash_table, &type);
151   g_return_val_if_fail (node != NULL, NULL);
152
153   if (node->init_class)
154     gtk_type_class_init (node);
155
156   return node->klass;
157 }
158
159 gpointer
160 gtk_type_new (GtkType type)
161 {
162   GtkTypeNode *node;
163   gpointer object;
164
165   if (initialize)
166     gtk_type_init ();
167
168   node = g_hash_table_lookup (type_hash_table, &type);
169   g_return_val_if_fail (node != NULL, NULL);
170
171   object = g_new0 (guchar, node->type_info.object_size);
172   ((GtkObject*) object)->klass = gtk_type_class (type);
173   gtk_type_object_init (node, object);
174
175   return object;
176 }
177
178 void
179 gtk_type_describe_heritage (GtkType type)
180 {
181   GtkTypeNode *node;
182   gint first;
183
184   if (initialize)
185     gtk_type_init ();
186
187   node = g_hash_table_lookup (type_hash_table, &type);
188   first = TRUE;
189
190   while (node)
191     {
192       if (first)
193         {
194           first = FALSE;
195           g_print ("is a ");
196         }
197
198       if (node->type_info.type_name)
199         g_print ("%s\n", node->type_info.type_name);
200       else
201         g_print ("<unnamed type>\n");
202
203       node = node->parent;
204     }
205 }
206
207 void
208 gtk_type_describe_tree (GtkType type,
209                         gint  show_size)
210 {
211   static gint indent = 0;
212   GtkTypeNode *node;
213   GtkTypeNode *child;
214   GList *children;
215   gint old_indent;
216   gint i;
217
218   if (initialize)
219     gtk_type_init ();
220
221   node = g_hash_table_lookup (type_hash_table, &type);
222
223   for (i = 0; i < indent; i++)
224     g_print (" ");
225
226   if (node->type_info.type_name)
227     g_print ("%s", node->type_info.type_name);
228   else
229     g_print ("<unnamed type>");
230
231   if (show_size)
232     g_print (" ( %d bytes )\n", node->type_info.object_size);
233   else
234     g_print ("\n");
235
236   old_indent = indent;
237   indent += 4;
238
239   children = node->children;
240   while (children)
241     {
242       child = children->data;
243       children = children->next;
244
245       gtk_type_describe_tree (child->type, show_size);
246     }
247
248   indent = old_indent;
249 }
250
251 gint
252 gtk_type_is_a (GtkType type,
253                GtkType is_a_type)
254 {
255   GtkTypeNode *node;
256
257   if (initialize)
258     gtk_type_init ();
259
260   node = g_hash_table_lookup (type_hash_table, &type);
261
262   while (node)
263     {
264       if (node->type == is_a_type)
265         return TRUE;
266       node = node->parent;
267     }
268
269   return FALSE;
270 }
271
272 void
273 gtk_type_set_arg (GtkObject *object,
274                   GtkType      type,
275                   GtkArg    *arg)
276 {
277   GtkTypeNode *node;
278
279   if (initialize)
280     gtk_type_init ();
281
282   node = g_hash_table_lookup (type_hash_table, &type);
283
284   if (node->type_info.arg_func)
285     (* node->type_info.arg_func) (object, arg);
286 }
287
288 static void
289 gtk_type_insert (GtkType        parent_type,
290                  GtkType        type,
291                  GtkTypeInfo   *type_info)
292 {
293   GtkTypeNode *node;
294   GtkTypeNode *parent;
295
296   parent = g_hash_table_lookup (type_hash_table, &parent_type);
297
298   node = g_new (GtkTypeNode, 1);
299   node->type = type;
300   node->init_class = TRUE;
301   node->klass = NULL;
302   node->type_info = *type_info;
303   node->parent = parent;
304   node->children = NULL;
305
306   if (node->parent)
307     node->parent->children = g_list_append (node->parent->children, node);
308
309   g_hash_table_insert (type_hash_table, &node->type, node);
310   g_hash_table_insert (name_hash_table, node->type_info.type_name, node);
311 }
312
313 static void
314 gtk_type_class_init (GtkTypeNode *node)
315 {
316   GtkObjectClass *object_class;
317
318   if (node->init_class)
319     {
320       node->init_class = FALSE;
321       node->klass = g_new0 (guchar, node->type_info.class_size);
322
323       if (node->parent)
324         {
325           if (node->parent->init_class)
326             gtk_type_class_init (node->parent);
327
328           memcpy (node->klass, node->parent->klass, node->parent->type_info.class_size);
329         }
330
331       object_class = node->klass;
332       object_class->type = node->type;
333
334       if (node->type_info.class_init_func)
335         (* node->type_info.class_init_func) (node->klass);
336     }
337 }
338
339 static void
340 gtk_type_object_init (GtkTypeNode *node,
341                       gpointer     object)
342 {
343   if (node->parent)
344     gtk_type_object_init (node->parent, object);
345
346   if (node->type_info.object_init_func)
347     (* node->type_info.object_init_func) (object);
348 }
349
350 static guint
351 gtk_type_hash (GtkType *key)
352 {
353   return GTK_TYPE_SEQNO (*key);
354 }
355
356 static gint
357 gtk_type_compare (GtkType *a,
358                   GtkType *b)
359 {
360   g_return_val_if_fail(a != NULL && b != NULL, 0);
361   return (*a == *b);
362 }
363
364 static guint
365 gtk_type_name_hash (const char *key)
366 {
367   guint result;
368
369   result = 0;
370   while (*key)
371     result += (result << 3) + *key++;
372
373   return result;
374 }
375
376 static gint
377 gtk_type_name_compare (const char *a,
378                        const char *b)
379 {
380   return (strcmp (a, b) == 0);
381 }
382
383 static GtkType
384 gtk_type_register_builtin (char   *name,
385                            GtkType parent)
386 {
387   GtkTypeInfo info;
388
389   info.type_name = name;
390   info.object_size = info.class_size = 0;
391   info.class_init_func = NULL;
392   info.object_init_func = NULL;
393   info.arg_func = NULL;
394
395   return gtk_type_unique (parent, &info);
396 }
397
398 extern void gtk_object_init_type ();
399
400 GtkType gtk_type_builtins[GTK_TYPE_NUM_BUILTINS];
401
402 static void
403 gtk_type_init_builtin_types ()
404 {
405   /* GTK_TYPE_INVALID has typeid 0.  The first type id returned by
406      gtk_type_unique is 1, which is GTK_TYPE_NONE.  And so on. */
407
408   static struct {
409     GtkType enum_id;
410     gchar *name;
411   } fundamental_info[] = {
412     { GTK_TYPE_NONE, "void" },
413     { GTK_TYPE_CHAR, "char" },
414     { GTK_TYPE_BOOL, "bool" },
415     { GTK_TYPE_INT, "int" },
416     { GTK_TYPE_UINT, "uint" },
417     { GTK_TYPE_LONG, "long" },
418     { GTK_TYPE_ULONG, "ulong" },
419     { GTK_TYPE_FLOAT, "float" },
420     { GTK_TYPE_STRING, "string" },
421     { GTK_TYPE_ENUM, "enum" },
422     { GTK_TYPE_FLAGS, "flags" },
423     { GTK_TYPE_BOXED, "boxed" },
424     { GTK_TYPE_FOREIGN, "foreign" },
425     { GTK_TYPE_CALLBACK, "callback" },
426     { GTK_TYPE_ARGS, "args" },
427
428     { GTK_TYPE_POINTER, "pointer" },
429     { GTK_TYPE_SIGNAL, "signal" },
430     { GTK_TYPE_C_CALLBACK, "c_callback" }
431   };
432
433   static struct {
434     char *name;
435     GtkType parent;
436   } builtin_info[] = {
437 #include "gtktypebuiltins.c"
438     { NULL }
439   };
440
441   int i;
442
443   for (i = 0; i < sizeof (fundamental_info)/sizeof(fundamental_info[0]); i++)
444     {
445       GtkType id;
446       id = gtk_type_register_builtin (fundamental_info[i].name,
447                                       GTK_TYPE_INVALID);
448       g_assert (id == fundamental_info[i].enum_id);
449     }
450
451   gtk_object_init_type ();
452
453   for (i = 0; builtin_info[i].name; i++)
454     {
455       gtk_type_builtins[i] =
456         gtk_type_register_builtin (builtin_info[i].name,
457                                    builtin_info[i].parent);
458     }
459 }