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