]> Pileus Git - ~andy/gtk/blob - gtk/gtktypeutils.c
2891e7c301cd1e47d9d952b4d34e51ddfcb5c533
[~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 (void);
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_get_arg (GtkObject   *object,
274                   GtkType      type,
275                   GtkArg      *arg,
276                   guint        arg_id)
277 {
278   GtkTypeNode *node;
279
280   g_return_if_fail (object != NULL);
281   g_return_if_fail (arg != NULL);
282
283   if (initialize)
284     gtk_type_init ();
285
286   node = g_hash_table_lookup (type_hash_table, &type);
287
288   if (node && node->type_info.arg_get_func)
289     (* node->type_info.arg_get_func) (object, arg, arg_id);
290   else
291     arg->type = GTK_TYPE_INVALID;
292 }
293
294 void
295 gtk_type_set_arg (GtkObject *object,
296                   GtkType    type,
297                   GtkArg    *arg,
298                   guint      arg_id)
299 {
300   GtkTypeNode *node;
301
302   g_return_if_fail (object != NULL);
303   g_return_if_fail (arg != NULL);
304
305   if (initialize)
306     gtk_type_init ();
307
308   node = g_hash_table_lookup (type_hash_table, &type);
309
310   if (node && node->type_info.arg_set_func)
311     (* node->type_info.arg_set_func) (object, arg, arg_id);
312 }
313
314 GtkArg*
315 gtk_arg_copy (GtkArg         *src_arg,
316               GtkArg         *dest_arg)
317 {
318   g_return_val_if_fail (src_arg != NULL, NULL);
319
320   if (!dest_arg)
321     {
322       dest_arg = g_new0 (GtkArg, 1);
323       dest_arg->name = src_arg->name;
324     }
325
326   dest_arg->type = src_arg->type;
327   dest_arg->d = src_arg->d;
328
329   if (src_arg->type == GTK_TYPE_STRING)
330     dest_arg->d.string_data = g_strdup (src_arg->d.string_data);
331
332   return dest_arg;
333 }
334
335 static void
336 gtk_type_insert (GtkType        parent_type,
337                  GtkType        type,
338                  GtkTypeInfo   *type_info)
339 {
340   GtkTypeNode *node;
341   GtkTypeNode *parent;
342
343   parent = g_hash_table_lookup (type_hash_table, &parent_type);
344
345   node = g_new (GtkTypeNode, 1);
346   node->type = type;
347   node->init_class = TRUE;
348   node->klass = NULL;
349   node->type_info = *type_info;
350   node->parent = parent;
351   node->children = NULL;
352
353   if (node->parent)
354     node->parent->children = g_list_append (node->parent->children, node);
355
356   g_hash_table_insert (type_hash_table, &node->type, node);
357   g_hash_table_insert (name_hash_table, node->type_info.type_name, node);
358 }
359
360 static void
361 gtk_type_class_init (GtkTypeNode *node)
362 {
363   GtkObjectClass *object_class;
364
365   if (node->init_class)
366     {
367       node->init_class = FALSE;
368       node->klass = g_new0 (guchar, node->type_info.class_size);
369
370       if (node->parent)
371         {
372           if (node->parent->init_class)
373             gtk_type_class_init (node->parent);
374
375           memcpy (node->klass, node->parent->klass, node->parent->type_info.class_size);
376         }
377
378       object_class = node->klass;
379       object_class->type = node->type;
380       object_class->signals = NULL;
381       object_class->nsignals = 0;
382       object_class->n_args = 0;
383
384       if (node->type_info.class_init_func)
385         (* node->type_info.class_init_func) (node->klass);
386     }
387 }
388
389 static void
390 gtk_type_object_init (GtkTypeNode *node,
391                       gpointer     object)
392 {
393   if (node->parent)
394     gtk_type_object_init (node->parent, object);
395
396   if (node->type_info.object_init_func)
397     (* node->type_info.object_init_func) (object);
398 }
399
400 static guint
401 gtk_type_hash (GtkType *key)
402 {
403   return GTK_TYPE_SEQNO (*key);
404 }
405
406 static gint
407 gtk_type_compare (GtkType *a,
408                   GtkType *b)
409 {
410   g_return_val_if_fail(a != NULL && b != NULL, 0);
411   return (*a == *b);
412 }
413
414 static guint
415 gtk_type_name_hash (const char *key)
416 {
417   guint result;
418
419   result = 0;
420   while (*key)
421     result += (result << 3) + *key++;
422
423   return result;
424 }
425
426 static gint
427 gtk_type_name_compare (const char *a,
428                        const char *b)
429 {
430   return (strcmp (a, b) == 0);
431 }
432
433 static GtkType
434 gtk_type_register_builtin (char   *name,
435                            GtkType parent)
436 {
437   GtkTypeInfo info;
438
439   info.type_name = name;
440   info.object_size = info.class_size = 0;
441   info.class_init_func = NULL;
442   info.object_init_func = NULL;
443   info.arg_set_func = NULL;
444   info.arg_get_func = NULL;
445
446   return gtk_type_unique (parent, &info);
447 }
448
449 extern void gtk_object_init_type (void);
450
451 GtkType gtk_type_builtins[GTK_TYPE_NUM_BUILTINS];
452
453 static void
454 gtk_type_init_builtin_types ()
455 {
456   /* GTK_TYPE_INVALID has typeid 0.  The first type id returned by
457      gtk_type_unique is 1, which is GTK_TYPE_NONE.  And so on. */
458
459   static struct {
460     GtkType enum_id;
461     gchar *name;
462   } fundamental_info[] = {
463     { GTK_TYPE_NONE, "void" },
464     { GTK_TYPE_CHAR, "char" },
465     { GTK_TYPE_BOOL, "bool" },
466     { GTK_TYPE_INT, "int" },
467     { GTK_TYPE_UINT, "uint" },
468     { GTK_TYPE_LONG, "long" },
469     { GTK_TYPE_ULONG, "ulong" },
470     { GTK_TYPE_FLOAT, "float" },
471     { GTK_TYPE_DOUBLE, "double" },
472     { GTK_TYPE_STRING, "string" },
473     { GTK_TYPE_ENUM, "enum" },
474     { GTK_TYPE_FLAGS, "flags" },
475     { GTK_TYPE_BOXED, "boxed" },
476     { GTK_TYPE_FOREIGN, "foreign" },
477     { GTK_TYPE_CALLBACK, "callback" },
478     { GTK_TYPE_ARGS, "args" },
479
480     { GTK_TYPE_POINTER, "pointer" },
481     { GTK_TYPE_SIGNAL, "signal" },
482     { GTK_TYPE_C_CALLBACK, "c_callback" }
483   };
484
485   static struct {
486     char *name;
487     GtkType parent;
488   } builtin_info[] = {
489 #include "gtktypebuiltins.c"
490     { NULL }
491   };
492
493   int i;
494
495   for (i = 0; i < sizeof (fundamental_info)/sizeof(fundamental_info[0]); i++)
496     {
497       GtkType id;
498       id = gtk_type_register_builtin (fundamental_info[i].name,
499                                       GTK_TYPE_INVALID);
500       g_assert (id == fundamental_info[i].enum_id);
501     }
502
503   gtk_object_init_type ();
504
505   for (i = 0; builtin_info[i].name; i++)
506     {
507       gtk_type_builtins[i] =
508         gtk_type_register_builtin (builtin_info[i].name,
509                                    builtin_info[i].parent);
510     }
511 }