]> Pileus Git - ~andy/gtk/blob - gtk/gtkobject.c
main part for GtkArgSetFunc/GtkArgGetFunc implementation.
[~andy/gtk] / gtk / gtkobject.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 <stdarg.h>
19 #include <string.h>
20 #include "gtkobject.h"
21 #include "gtksignal.h"
22
23
24 #define OBJECT_DATA_ID_CHUNK  1024
25
26
27 enum {
28   DESTROY,
29   LAST_SIGNAL
30 };
31 enum {
32   ARG_0,
33   ARG_USER_DATA,
34   ARG_SIGNAL
35 };
36
37
38 typedef struct _GtkObjectData  GtkObjectData;
39 typedef struct _GtkArgInfo     GtkArgInfo;
40
41 struct _GtkObjectData
42 {
43   guint id;
44   gpointer data;
45   GtkObjectData *next;
46 };
47
48 struct _GtkArgInfo
49 {
50   char *name;
51   GtkType type;
52   GtkType class_type;
53   guint arg_id;
54 };
55
56
57 static void           gtk_object_class_init    (GtkObjectClass *klass);
58 static void           gtk_object_init          (GtkObject      *object);
59 static void           gtk_object_set_arg       (GtkObject      *object,
60                                                 GtkArg         *arg,
61                                                 guint           arg_id);
62 static void           gtk_real_object_destroy  (GtkObject      *object);
63 static void           gtk_object_data_init     (void);
64 static GtkObjectData* gtk_object_data_new      (void);
65 static void           gtk_object_data_destroy  (GtkObjectData  *odata);
66 static guint*         gtk_object_data_id_alloc (void);
67 GtkArg*               gtk_object_collect_args  (gint    *nargs,
68                                                 va_list  args1,
69                                                 va_list  args2);
70
71
72 static gint object_signals[LAST_SIGNAL] = { 0 };
73
74 static gint object_data_init = TRUE;
75 static GHashTable *object_data_ht = NULL;
76 static GMemChunk *object_data_mem_chunk = NULL;
77 static GtkObjectData *object_data_free_list = NULL;
78 static GSList *object_data_id_list = NULL;
79 static gint object_data_id_index = 0;
80
81 static GHashTable *arg_info_ht = NULL;
82
83 static const char *user_data_key = "user_data";
84
85
86 /*****************************************
87  * gtk_object_get_type:
88  *
89  *   arguments:
90  *
91  *   results:
92  *     The type identifier for GtkObject's
93  *****************************************/
94
95 void
96 gtk_object_init_type ()
97 {
98   GtkType object_type = 0;
99   GtkTypeInfo object_info =
100   {
101     "GtkObject",
102     sizeof (GtkObject),
103     sizeof (GtkObjectClass),
104     (GtkClassInitFunc) gtk_object_class_init,
105     (GtkObjectInitFunc) gtk_object_init,
106     gtk_object_set_arg,
107     NULL,
108   };
109
110   object_type = gtk_type_unique (0, &object_info);
111   g_assert (object_type == GTK_TYPE_OBJECT);
112 }
113
114 GtkType
115 gtk_object_get_type ()
116 {
117   return GTK_TYPE_OBJECT;
118 }
119
120 /*****************************************
121  * gtk_object_class_init:
122  *
123  *   arguments:
124  *
125  *   results:
126  *****************************************/
127
128 static void
129 gtk_object_class_init (GtkObjectClass *class)
130 {
131   class->signals = NULL;
132   class->nsignals = 0;
133
134   gtk_object_add_arg_type ("GtkObject::user_data", GTK_TYPE_POINTER, ARG_USER_DATA);
135   gtk_object_add_arg_type ("GtkObject::signal", GTK_TYPE_SIGNAL, ARG_SIGNAL);
136
137   object_signals[DESTROY] =
138     gtk_signal_new ("destroy",
139                     GTK_RUN_LAST,
140                     class->type,
141                     GTK_SIGNAL_OFFSET (GtkObjectClass, destroy),
142                     gtk_signal_default_marshaller,
143                     GTK_TYPE_NONE, 0);
144
145   gtk_object_class_add_signals (class, object_signals, LAST_SIGNAL);
146
147   class->destroy = gtk_real_object_destroy;
148 }
149
150 /*****************************************
151  * gtk_object_init:
152  *
153  *   arguments:
154  *
155  *   results:
156  *****************************************/
157
158 static void
159 gtk_object_init (GtkObject *object)
160 {
161   object->flags = 0;
162   object->ref_count = 0;
163   object->object_data = NULL;
164 }
165
166 /*****************************************
167  * gtk_object_arg:
168  *
169  *   arguments:
170  *
171  *   results:
172  *****************************************/
173
174 static void
175 gtk_object_set_arg (GtkObject *object,
176                     GtkArg    *arg,
177                     guint      arg_id)
178 {
179   switch (arg_id)
180     {
181     case ARG_USER_DATA:
182       gtk_object_set_user_data (object, GTK_VALUE_POINTER (*arg));
183       break;
184     case ARG_SIGNAL:
185       if ((arg->name[11 + 6] != ':') || (arg->name[11 + 7] != ':'))
186         {
187           g_print ("invalid signal argument: \"%s\"\n", arg->name);
188           return;
189         }
190       gtk_signal_connect (object, arg->name + 11 + 8,
191                           (GtkSignalFunc) GTK_VALUE_SIGNAL (*arg).f,
192                           GTK_VALUE_SIGNAL (*arg).d);
193       break;
194     default:
195       g_assert_not_reached ();
196     }
197 }
198
199 /*****************************************
200  * gtk_object_class_add_signals:
201  *
202  *   arguments:
203  *
204  *   results:
205  *****************************************/
206
207 void
208 gtk_object_class_add_signals (GtkObjectClass *class,
209                               gint           *signals,
210                               gint            nsignals)
211 {
212   gint *new_signals;
213   gint i;
214
215   g_return_if_fail (class != NULL);
216
217   new_signals = g_new (gint, class->nsignals + nsignals);
218   for (i = 0; i < class->nsignals; i++)
219     new_signals[i] = class->signals[i];
220   for (i = 0; i < nsignals; i++)
221     new_signals[class->nsignals + i] = signals[i];
222
223   class->signals = new_signals;
224   class->nsignals += nsignals;
225 }
226
227 /*****************************************
228  * gtk_object_ref:
229  *
230  *   arguments:
231  *
232  *   results:
233  *****************************************/
234
235 void
236 gtk_object_ref (GtkObject *object)
237 {
238   g_return_if_fail (object != NULL);
239   g_return_if_fail (GTK_IS_OBJECT (object));
240
241   object->ref_count += 1;
242 }
243
244 /*****************************************
245  * gtk_object_unref:
246  *
247  *   arguments:
248  *
249  *   results:
250  *****************************************/
251
252 void
253 gtk_object_unref (GtkObject *object)
254 {
255   g_return_if_fail (object != NULL);
256   g_return_if_fail (GTK_IS_OBJECT (object));
257
258   if (object->ref_count > 0)
259     object->ref_count -= 1;
260 }
261
262 /*****************************************
263  * gtk_object_new:
264  *
265  *   arguments:
266  *
267  *   results:
268  *****************************************/
269
270 GtkObject*
271 gtk_object_new (guint type,
272                 ...)
273 {
274   GtkObject *obj;
275   GtkArg *args;
276   gint nargs;
277   va_list args1;
278   va_list args2;
279
280   obj = gtk_type_new (type);
281
282   va_start (args1, type);
283   va_start (args2, type);
284
285   args = gtk_object_collect_args (&nargs, args1, args2);
286   gtk_object_setv (obj, nargs, args);
287   g_free (args);
288
289   va_end (args1);
290   va_end (args2);
291
292   return obj;
293 }
294
295 /*****************************************
296  * gtk_object_newv:
297  *
298  *   arguments:
299  *
300  *   results:
301  *****************************************/
302
303 GtkObject*
304 gtk_object_newv (guint   type,
305                  gint    nargs,
306                  GtkArg *args)
307 {
308   gpointer obj;
309
310   obj = gtk_type_new (type);
311   gtk_object_setv (obj, nargs, args);
312
313   return obj;
314 }
315
316 /*****************************************
317  * gtk_object_set:
318  *
319  *   arguments:
320  *
321  *   results:
322  *****************************************/
323
324 void
325 gtk_object_set (GtkObject *obj,
326                 ...)
327 {
328   GtkArg *args;
329   gint nargs;
330   va_list args1;
331   va_list args2;
332
333   g_return_if_fail (obj != NULL);
334
335   va_start (args1, obj);
336   va_start (args2, obj);
337
338   args = gtk_object_collect_args (&nargs, args1, args2);
339   gtk_object_setv (obj, nargs, args);
340   g_free (args);
341
342   va_end (args1);
343   va_end (args2);
344 }
345
346 /*****************************************
347  * gtk_object_setv:
348  *
349  *   arguments:
350  *
351  *   results:
352  *****************************************/
353
354 void
355 gtk_object_setv (GtkObject *obj,
356                  gint       nargs,
357                  GtkArg    *args)
358 {
359   int i;
360
361   g_return_if_fail (obj != NULL);
362
363   if (!arg_info_ht)
364     return;
365
366   for (i = 0; i < nargs; i++)
367     {
368       GtkArgInfo *info;
369       gchar *lookup_name;
370       gchar *d;
371
372       lookup_name = g_strdup (args[i].name);
373       d = strchr (lookup_name, ':');
374       if (d && d[1] == ':')
375         {
376           d = strchr (d + 2, ':');
377           if (d)
378             *d = 0;
379
380           info = g_hash_table_lookup (arg_info_ht, lookup_name);
381         }
382       else
383         info = NULL;
384
385       if (!info)
386         {
387           g_warning ("invalid arg name: \"%s\"\n", lookup_name);
388           continue;
389         }
390       g_free (lookup_name);
391
392       gtk_type_set_arg (obj, info->class_type, &args[i], info->arg_id);
393     }
394 }
395
396 /*****************************************
397  * gtk_object_add_arg_type:
398  *
399  *   arguments:
400  *
401  *   results:
402  *****************************************/
403
404 void
405 gtk_object_add_arg_type (const char *arg_name,
406                          GtkType     arg_type,
407                          guint       arg_id)
408 {
409   GtkArgInfo *info;
410   gchar class_part[1024];
411   gchar *arg_part;
412   GtkType class_type;
413
414   g_return_if_fail (arg_id > 0);
415   
416   arg_part = strchr (arg_name, ':');
417   if (!arg_part || (arg_part[0] != ':') || (arg_part[1] != ':'))
418     {
419       g_warning ("invalid arg name: \"%s\"\n", arg_name);
420       return;
421     }
422
423   strncpy (class_part, arg_name, (glong) (arg_part - arg_name));
424   class_part[(glong) (arg_part - arg_name)] = '\0';
425
426   class_type = gtk_type_from_name (class_part);
427   if (!class_type)
428     {
429       g_warning ("invalid class name in arg: \"%s\"\n", arg_name);
430       return;
431     }
432
433   info = g_new (GtkArgInfo, 1);
434   info->name = g_strdup (arg_name);
435   info->type = arg_type;
436   info->class_type = class_type;
437   info->arg_id = arg_id;
438
439   if (!arg_info_ht)
440     arg_info_ht = g_hash_table_new (g_string_hash, g_string_equal);
441
442   g_hash_table_insert (arg_info_ht, info->name, info);
443 }
444
445 /*****************************************
446  * gtk_object_get_arg_type:
447  *
448  *   arguments:
449  *
450  *   results:
451  *****************************************/
452
453 GtkType
454 gtk_object_get_arg_type (const char *arg_name)
455 {
456   GtkArgInfo *info;
457   char buffer[1024];
458   char *t;
459
460   if (!arg_info_ht)
461     return GTK_TYPE_INVALID;
462
463   t = strchr (arg_name, ':');
464   if (!t || (t[0] != ':') || (t[1] != ':'))
465     {
466       g_warning ("invalid arg name: \"%s\"\n", arg_name);
467       return GTK_TYPE_INVALID;
468     }
469
470   t = strchr (t + 2, ':');
471   if (t)
472     {
473       strncpy (buffer, arg_name, (long) (t - arg_name));
474       buffer[(long) (t - arg_name)] = '\0';
475       arg_name = buffer;
476     }
477
478   info = g_hash_table_lookup (arg_info_ht, (gpointer) arg_name);
479   if (info)
480     return info->type;
481
482   return GTK_TYPE_INVALID;
483 }
484
485 /*****************************************
486  * gtk_object_destroy:
487  *
488  *   arguments:
489  *
490  *   results:
491  *****************************************/
492
493 void
494 gtk_object_destroy (GtkObject *object)
495 {
496   g_return_if_fail (object != NULL);
497   g_return_if_fail (GTK_IS_OBJECT (object));
498
499   if ((object->ref_count > 0) || GTK_OBJECT_IN_CALL (object))
500     {
501       GTK_OBJECT_SET_FLAGS (object, GTK_NEED_DESTROY);
502     }
503   else
504     {
505       GTK_OBJECT_UNSET_FLAGS (object, GTK_NEED_DESTROY);
506       GTK_OBJECT_SET_FLAGS (object, GTK_BEING_DESTROYED);
507
508       gtk_signal_emit (object, object_signals[DESTROY]);
509     }
510 }
511
512 /*****************************************
513  * gtk_object_set_data:
514  *
515  *   arguments:
516  *
517  *   results:
518  *****************************************/
519
520 void
521 gtk_object_set_data (GtkObject   *object,
522                      const gchar *key,
523                      gpointer     data)
524 {
525   GtkObjectData *odata;
526   GtkObjectData *prev;
527   guint *id;
528
529   g_return_if_fail (object != NULL);
530   g_return_if_fail (GTK_IS_OBJECT (object));
531   g_return_if_fail (key != NULL);
532
533   if (object_data_init)
534     gtk_object_data_init ();
535
536   id = g_hash_table_lookup (object_data_ht, (gpointer) key);
537
538   if (!data)
539     {
540       if (id)
541         {
542           prev = NULL;
543           odata = object->object_data;
544
545           while (odata)
546             {
547               if (odata->id == *id)
548                 {
549                   if (prev)
550                     prev->next = odata->next;
551                   if (odata == object->object_data)
552                     object->object_data = odata->next;
553
554                   gtk_object_data_destroy (odata);
555                   break;
556                 }
557
558               prev = odata;
559               odata = odata->next;
560             }
561         }
562     }
563   else
564     {
565       if (!id)
566         {
567           id = gtk_object_data_id_alloc ();
568           g_hash_table_insert (object_data_ht, (gpointer) key, id);
569         }
570
571       odata = object->object_data;
572       while (odata)
573         {
574           if (odata->id == *id)
575             {
576               odata->data = data;
577               return;
578             }
579
580           odata = odata->next;
581         }
582
583       odata = gtk_object_data_new ();
584       odata->id = *id;
585       odata->data = data;
586
587       odata->next = object->object_data;
588       object->object_data = odata;
589     }
590 }
591
592 /*****************************************
593  * gtk_object_get_data:
594  *
595  *   arguments:
596  *
597  *   results:
598  *****************************************/
599
600 gpointer
601 gtk_object_get_data (GtkObject   *object,
602                      const gchar *key)
603 {
604   GtkObjectData *odata;
605   guint *id;
606
607   g_return_val_if_fail (object != NULL, NULL);
608   g_return_val_if_fail (GTK_IS_OBJECT (object), NULL);
609   g_return_val_if_fail (key != NULL, NULL);
610
611   if (object_data_init)
612     gtk_object_data_init ();
613
614   id = g_hash_table_lookup (object_data_ht, (gpointer) key);
615   if (id)
616     {
617       odata = object->object_data;
618       while (odata)
619         {
620           if (odata->id == *id)
621             return odata->data;
622           odata = odata->next;
623         }
624     }
625
626   return NULL;
627 }
628
629 /*****************************************
630  * gtk_object_remove_data:
631  *
632  *   arguments:
633  *
634  *   results:
635  *****************************************/
636
637 void
638 gtk_object_remove_data (GtkObject   *object,
639                         const gchar *key)
640 {
641   g_return_if_fail (object != NULL);
642   g_return_if_fail (GTK_IS_OBJECT (object));
643   g_return_if_fail (key != NULL);
644
645   gtk_object_set_data (object, key, NULL);
646 }
647
648 /*****************************************
649  * gtk_object_set_user_data:
650  *
651  *   arguments:
652  *
653  *   results:
654  *****************************************/
655
656 void
657 gtk_object_set_user_data (GtkObject *object,
658                           gpointer   data)
659 {
660   g_return_if_fail (object != NULL);
661   g_return_if_fail (GTK_IS_OBJECT (object));
662
663   gtk_object_set_data (object, user_data_key, data);
664 }
665
666 /*****************************************
667  * gtk_object_get_user_data:
668  *
669  *   arguments:
670  *
671  *   results:
672  *****************************************/
673
674 gpointer
675 gtk_object_get_user_data (GtkObject *object)
676 {
677   g_return_val_if_fail (object != NULL, NULL);
678   g_return_val_if_fail (GTK_IS_OBJECT (object), NULL);
679
680   return gtk_object_get_data (object, user_data_key);
681 }
682
683 /*****************************************
684  * gtk_object_check_cast:
685  *
686  *   arguments:
687  *
688  *   results:
689  *****************************************/
690
691 GtkObject*
692 gtk_object_check_cast (GtkObject *obj,
693                        GtkType    cast_type)
694 {
695   if (obj && obj->klass && !gtk_type_is_a (obj->klass->type, cast_type))
696     {
697       gchar *from_name = gtk_type_name (obj->klass->type);
698       gchar *to_name = gtk_type_name (cast_type);
699
700       g_warning ("invalid cast from \"%s\" to \"%s\"",
701                  from_name ? from_name : "(unknown)",
702                  to_name ? to_name : "(unknown)");
703     }
704
705   return obj;
706 }
707
708 /*****************************************
709  * gtk_object_check_class_cast:
710  *
711  *   arguments:
712  *
713  *   results:
714  *****************************************/
715
716 GtkObjectClass*
717 gtk_object_check_class_cast (GtkObjectClass *klass,
718                              GtkType         cast_type)
719 {
720   if (klass && !gtk_type_is_a (klass->type, cast_type))
721     g_warning ("invalid cast from \"%sClass\" to \"%sClass\"",
722                gtk_type_name (klass->type),
723                gtk_type_name (cast_type));
724
725   return klass;
726 }
727
728 /*****************************************
729  * gtk_real_object_destroy:
730  *
731  *   arguments:
732  *
733  *   results:
734  *****************************************/
735
736 static void
737 gtk_real_object_destroy (GtkObject *object)
738 {
739   GtkObjectData *odata;
740
741   g_return_if_fail (object != NULL);
742   g_return_if_fail (GTK_IS_OBJECT (object));
743
744   gtk_signal_handlers_destroy (object);
745
746   if (object->object_data)
747     {
748       odata = object->object_data;
749       while (odata->next)
750         odata = odata->next;
751
752       odata->next = object_data_free_list;
753       object_data_free_list = object->object_data;
754     }
755
756   g_free (object);
757 }
758
759 /*****************************************
760  * gtk_object_data_init:
761  *
762  *   arguments:
763  *
764  *   results:
765  *****************************************/
766
767 static void
768 gtk_object_data_init ()
769 {
770   if (object_data_init)
771     {
772       object_data_init = FALSE;
773
774       object_data_ht = g_hash_table_new (g_string_hash, g_string_equal);
775     }
776 }
777
778 /*****************************************
779  * gtk_object_data_new:
780  *
781  *   arguments:
782  *
783  *   results:
784  *****************************************/
785
786 static GtkObjectData*
787 gtk_object_data_new ()
788 {
789   GtkObjectData *odata;
790
791   if (!object_data_mem_chunk)
792     object_data_mem_chunk = g_mem_chunk_new ("object data mem chunk",
793                                              sizeof (GtkObjectData),
794                                              1024, G_ALLOC_AND_FREE);
795
796   odata = g_chunk_new (GtkObjectData, object_data_mem_chunk);
797
798   odata->id = 0;
799   odata->data = NULL;
800   odata->next = NULL;
801
802   return odata;
803 }
804
805 /*****************************************
806  * gtk_object_data_destroy:
807  *
808  *   arguments:
809  *
810  *   results:
811  *****************************************/
812
813 static void
814 gtk_object_data_destroy (GtkObjectData *odata)
815 {
816   g_return_if_fail (odata != NULL);
817
818   g_mem_chunk_free (object_data_mem_chunk, odata);
819 }
820
821 /*****************************************
822  * gtk_object_data_id_alloc:
823  *
824  *   arguments:
825  *
826  *   results:
827  *****************************************/
828
829 static guint*
830 gtk_object_data_id_alloc ()
831 {
832   static guint next_id = 1;
833   guint *ids;
834
835   if (!object_data_id_list ||
836       (object_data_id_index == OBJECT_DATA_ID_CHUNK))
837     {
838       ids = g_new (guint, OBJECT_DATA_ID_CHUNK);
839       object_data_id_index = 0;
840       object_data_id_list = g_slist_prepend (object_data_id_list, ids);
841     }
842   else
843     {
844       ids = object_data_id_list->data;
845     }
846
847   ids[object_data_id_index] = next_id++;
848   return &ids[object_data_id_index++];
849 }
850
851 /*****************************************
852  * gtk_object_collect_args:
853  *
854  *   arguments:
855  *
856  *   results:
857  *****************************************/
858
859 GtkArg*
860 gtk_object_collect_args (gint    *nargs,
861                          va_list  args1,
862                          va_list  args2)
863 {
864   GtkArg *args;
865   GtkType type;
866   char *name;
867   int done;
868   int i, n;
869
870   n = 0;
871   done = FALSE;
872
873   while (!done)
874     {
875       name = va_arg (args1, char *);
876       if (!name)
877         {
878           done = TRUE;
879           continue;
880         }
881
882       type = gtk_object_get_arg_type (name);
883
884       switch (GTK_FUNDAMENTAL_TYPE (type))
885         {
886         case GTK_TYPE_INVALID:
887           g_warning ("invalid arg name: \"%s\" %x\n", name, type);
888           (void) va_arg (args1, long);
889           continue;
890         case GTK_TYPE_NONE:
891           break;
892         case GTK_TYPE_CHAR:
893         case GTK_TYPE_BOOL:
894         case GTK_TYPE_INT:
895         case GTK_TYPE_UINT:
896         case GTK_TYPE_ENUM:
897         case GTK_TYPE_FLAGS:
898           (void) va_arg (args1, gint);
899           break;
900         case GTK_TYPE_LONG:
901         case GTK_TYPE_ULONG:
902           (void) va_arg (args1, glong);
903           break;
904         case GTK_TYPE_FLOAT:
905           (void) va_arg (args1, gfloat);
906           break;
907         case GTK_TYPE_STRING:
908           (void) va_arg (args1, gchar*);
909           break;
910         case GTK_TYPE_POINTER:
911         case GTK_TYPE_BOXED:
912           (void) va_arg (args1, gpointer);
913           break;
914         case GTK_TYPE_SIGNAL:
915           (void) va_arg (args1, GtkFunction);
916           (void) va_arg (args1, gpointer);
917           break;
918         case GTK_TYPE_FOREIGN:
919           (void) va_arg (args1, gpointer);
920           (void) va_arg (args1, GtkDestroyNotify);
921           break;
922         case GTK_TYPE_CALLBACK:
923           (void) va_arg (args1, GtkCallbackMarshal);
924           (void) va_arg (args1, gpointer);
925           (void) va_arg (args1, GtkDestroyNotify);
926           break;
927         case GTK_TYPE_C_CALLBACK:
928           (void) va_arg (args1, GtkFunction);
929           (void) va_arg (args1, gpointer);
930           break;
931         case GTK_TYPE_ARGS:
932           (void) va_arg (args1, gint);
933           (void) va_arg (args1, GtkArg*);
934           break;
935         case GTK_TYPE_OBJECT:
936           (void) va_arg (args1, GtkObject*);
937           break;
938         default:
939           g_error ("unsupported type %s in args", gtk_type_name (type));
940           break;
941         }
942
943       n += 1;
944     }
945
946   *nargs = n;
947   args = NULL;
948
949   if (n > 0)
950     {
951       args = g_new0 (GtkArg, n);
952
953       for (i = 0; i < n; i++)
954         {
955           args[i].name = va_arg (args2, char *);
956           args[i].type = gtk_object_get_arg_type (args[i].name);
957
958           switch (GTK_FUNDAMENTAL_TYPE (args[i].type))
959             {
960             case GTK_TYPE_INVALID:
961               (void) va_arg (args2, long);
962               i -= 1;
963               continue;
964             case GTK_TYPE_NONE:
965               break;
966             case GTK_TYPE_CHAR:
967               GTK_VALUE_CHAR(args[i]) = va_arg (args2, gint);
968               break;
969             case GTK_TYPE_BOOL:
970               GTK_VALUE_BOOL(args[i]) = va_arg (args2, gint);
971               break;
972             case GTK_TYPE_INT:
973               GTK_VALUE_INT(args[i]) = va_arg (args2, gint);
974               break;
975             case GTK_TYPE_UINT:
976               GTK_VALUE_UINT(args[i]) = va_arg (args2, guint);
977               break;
978             case GTK_TYPE_ENUM:
979               GTK_VALUE_ENUM(args[i]) = va_arg (args2, gint);
980               break;
981             case GTK_TYPE_FLAGS:
982               GTK_VALUE_FLAGS(args[i]) = va_arg (args2, gint);
983               break;
984             case GTK_TYPE_LONG:
985               GTK_VALUE_LONG(args[i]) = va_arg (args2, glong);
986               break;
987             case GTK_TYPE_ULONG:
988               GTK_VALUE_ULONG(args[i]) = va_arg (args2, gulong);
989               break;
990             case GTK_TYPE_FLOAT:
991               GTK_VALUE_FLOAT(args[i]) = va_arg (args2, gfloat);
992               break;
993             case GTK_TYPE_STRING:
994               GTK_VALUE_STRING(args[i]) = va_arg (args2, gchar*);
995               break;
996             case GTK_TYPE_POINTER:
997               GTK_VALUE_POINTER(args[i]) = va_arg (args2, gpointer);
998               break;
999             case GTK_TYPE_BOXED:
1000               GTK_VALUE_BOXED(args[i]) = va_arg (args2, gpointer);
1001               break;
1002             case GTK_TYPE_SIGNAL:
1003               GTK_VALUE_SIGNAL(args[i]).f = va_arg (args2, GtkFunction);
1004               GTK_VALUE_SIGNAL(args[i]).d = va_arg (args2, gpointer);
1005               break;
1006             case GTK_TYPE_FOREIGN:
1007               GTK_VALUE_FOREIGN(args[i]).data = va_arg (args2, gpointer);
1008               GTK_VALUE_FOREIGN(args[i]).notify =
1009                 va_arg (args2, GtkDestroyNotify);
1010               break;
1011             case GTK_TYPE_CALLBACK:
1012               GTK_VALUE_CALLBACK(args[i]).marshal =
1013                 va_arg (args2, GtkCallbackMarshal);
1014               GTK_VALUE_CALLBACK(args[i]).data = va_arg (args2, gpointer);
1015               GTK_VALUE_CALLBACK(args[i]).notify =
1016                 va_arg (args2, GtkDestroyNotify);
1017               break;
1018             case GTK_TYPE_C_CALLBACK:
1019               GTK_VALUE_C_CALLBACK(args[i]).func = va_arg (args2, GtkFunction);
1020               GTK_VALUE_C_CALLBACK(args[i]).func_data =
1021                 va_arg (args2, gpointer);
1022               break;
1023             case GTK_TYPE_ARGS:
1024               GTK_VALUE_ARGS(args[i]).n_args = va_arg (args2, gint);
1025               GTK_VALUE_ARGS(args[i]).args = va_arg (args2, GtkArg*);
1026               break;
1027             case GTK_TYPE_OBJECT:
1028               GTK_VALUE_OBJECT(args[i]) = va_arg (args2, GtkObject*);
1029               g_assert (GTK_VALUE_OBJECT(args[i]) == NULL ||
1030                         GTK_CHECK_TYPE (GTK_VALUE_OBJECT(args[i]),
1031                                         args[i].type));
1032               break;
1033             default:
1034               g_error ("unsupported type %s in args",
1035                        gtk_type_name (args[i].type));
1036               break;
1037             }
1038         }
1039     }
1040
1041   return args;
1042 }