first stab at documenting elements
[platform/upstream/gst-common.git] / gstdoc-scangobj
1 #!/usr/bin/perl -w
2 # -*- cperl -*-
3 #
4 # gtk-doc - GTK DocBook documentation generator.
5 # Copyright (C) 1998  Damon Chaplin
6 #
7 # This program is free software; you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; either version 2 of the License, or
10 # (at your option) any later version.
11 #
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 # GNU General Public License for more details.
16 #
17 # You should have received a copy of the GNU General Public License
18 # along with this program; if not, write to the Free Software
19 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 #
21
22 #
23 # This gets information about object heirarchies and signals
24 # by compiling a small C program. CFLAGS and LDFLAGS must be
25 # set appropriately before running this script.
26 #
27 # NOTE: the lookup_signal_arg_names() function contains the argument names of
28 #       standard GTK signal handlers. This may need to be updated for new
29 #       GTK signals or Gnome widget signals.
30
31 use Getopt::Long;
32
33 unshift @INC, '/usr/share/gtk-doc/data';
34 require "gtkdoc-common.pl";
35
36 # Options
37
38 # name of documentation module
39 my $MODULE;
40 my $OUTPUT_DIR;
41 my $PRINT_VERSION;
42 my $PRINT_HELP;
43 my $TYPE_INIT_FUNC="g_type_init ()";
44
45 # --nogtkinit is deprecated, as it is the default now anyway.
46 %optctl = (module => \$MODULE,
47            types => \$TYPES_FILE,
48            nogtkinit => \$NO_GTK_INIT,
49            'type-init-func' => \$TYPE_INIT_FUNC,
50            'output-dir' => \$OUTPUT_DIR,
51            'version' => \$PRINT_VERSION,
52            'help' => \$PRINT_HELP);
53            
54 GetOptions(\%optctl, "module=s", "types:s", "output-dir:s", "nogtkinit", "type-init-func:s", "version", "help");
55
56 if ($NO_GTK_INIT) {
57   # Do nothing. This just avoids a warning.
58 }
59
60 if ($PRINT_VERSION) {
61     print "1.3\n";
62     exit 0;
63 }
64
65 if (!$MODULE) {
66     $PRINT_HELP = 1;
67 }
68
69 if ($PRINT_HELP) {
70     print "gtkdoc-scangobj version 1.3\n";
71     print "\n--module=MODULE_NAME  Name of the doc module being parsed";
72     print "\n--types=FILE          The name of the file to store the types in";
73     print "\n--type-init-func=FUNC The init function to call instead of g_type_init ()";
74     print "\n--output-dir=DIRNAME  The directory where the results are stored";
75     print "\n--version             Print the version of this program";
76     print "\n--help                Print this help\n";
77     exit 0;
78 }
79
80 $OUTPUT_DIR = $OUTPUT_DIR ? $OUTPUT_DIR : ".";
81
82 # THOMAS: dynamic types; only use types file for headers
83  $TYPES_FILE = $TYPES_FILE ? $TYPES_FILE : "$OUTPUT_DIR/$MODULE.types";
84
85 open TYPES, $TYPES_FILE || die "Cannot open $TYPES_FILE: $!\n";
86 open OUTPUT, ">$MODULE-scan.c" || die "Cannot open $MODULE-scan.c: $!\n";
87
88 my $old_signals_filename = "$OUTPUT_DIR/$MODULE.signals";
89 my $new_signals_filename = "$OUTPUT_DIR/$MODULE.signals.new";
90 my $old_hierarchy_filename = "$OUTPUT_DIR/$MODULE.hierarchy";
91 my $new_hierarchy_filename = "$OUTPUT_DIR/$MODULE.hierarchy.new";
92 my $old_interfaces_filename = "$OUTPUT_DIR/$MODULE.interfaces";
93 my $new_interfaces_filename = "$OUTPUT_DIR/$MODULE.interfaces.new";
94 my $old_prerequisites_filename = "$OUTPUT_DIR/$MODULE.prerequisites";
95 my $new_prerequisites_filename = "$OUTPUT_DIR/$MODULE.prerequisites.new";
96 my $old_args_filename = "$OUTPUT_DIR/$MODULE.args";
97 my $new_args_filename = "$OUTPUT_DIR/$MODULE.args.new";
98
99 # write a C program to scan the types
100
101 $includes = "";
102 #@types = ();
103
104 for (<TYPES>) {
105     if (/^#include/) {
106         $includes .= $_;
107 #    } elsif (/^%/) {
108 #       next;
109 #    } elsif (/^\s*$/) {
110 #       next;
111 #    } else {
112 #       chomp;
113 #       push @types, $_;
114     }
115 }
116
117 #$ntypes = @types + 1;
118
119 print OUTPUT <<EOT;
120 #include <string.h>
121 #include <stdlib.h>
122 #include <stdio.h>
123
124 $includes
125 #ifdef GTK_IS_WIDGET_CLASS
126 #include <gtk/gtkversion.h>
127 #endif
128 gint num_object_types = 0;
129 GType *object_types = NULL;
130
131 static GType *
132 get_object_types (void)
133 {
134     GList *plugins = NULL;
135     GList *factories = NULL;
136     GList *l;
137     GstElementFactory *factory = NULL;
138
139     gint i = 0;
140
141     /* get the number of types from the registry */
142     plugins = gst_registry_pool_plugin_list ();
143
144     while (plugins) {
145       GList *features;
146       GstPlugin *plugin;
147
148       plugin = (GstPlugin *) (plugins->data);
149       plugins = g_list_next (plugins);
150
151       features = gst_plugin_get_feature_list (plugin);
152       while (features) {
153         GstPluginFeature *feature;
154         feature = GST_PLUGIN_FEATURE (features->data);
155         if (!gst_plugin_feature_ensure_loaded (feature)) {
156           g_warning ("Could not load plugin feature %s",
157                      gst_plugin_feature_get_name (feature));
158         }
159
160         if (GST_IS_ELEMENT_FACTORY (feature)) {
161           factory = GST_ELEMENT_FACTORY (feature);
162           factories = g_list_append (factories, factory);
163         }
164         features = g_list_next (features);
165       }
166     }
167
168     num_object_types = g_list_length (factories);
169     g_debug ("number of element factories: %d", g_list_length (factories));
170
171     /* allocate the object_types array to hold them */
172     object_types = g_new0 (GType, g_list_length (factories));
173
174     l = factories;
175     i = 0;
176
177     /* fill it */
178     while (l) {
179       GType type;
180       factory = GST_ELEMENT_FACTORY (l->data);
181       g_debug ("adding type for factory %s", gst_element_factory_get_longname (factory));
182       type = gst_element_factory_get_element_type (factory);
183       g_debug ("adding type %p", (void *) type);
184       object_types[i] = type;
185       i++;
186       l = g_list_next (l);
187     }
188 EOT
189
190 print OUTPUT <<EOT;
191
192     /* Need to make sure all the types are loaded in and initialize
193      * their signals and properties.
194      */
195     g_debug ("class reffing");
196
197     for (i=0; i < num_object_types; i++) {
198       if (G_TYPE_IS_CLASSED (object_types[i]))
199         g_type_class_ref (object_types[i]);
200     }
201
202     return object_types;
203 }
204
205 /*
206  * This uses GTK type functions to output signal prototypes and the widget
207  * hierarchy.
208  */
209
210 /* The output files */
211 gchar *signals_filename = "$new_signals_filename";
212 gchar *hierarchy_filename = "$new_hierarchy_filename";
213 gchar *interfaces_filename = "$new_interfaces_filename";
214 gchar *prerequisites_filename = "$new_prerequisites_filename";
215 gchar *args_filename = "$new_args_filename";
216
217
218 static void output_signals (void);
219 static void output_widget_signals (FILE *fp,
220                                    GType object_type);
221 static void output_widget_signal (FILE *fp,
222                                   GType object_type,
223                                   const gchar *object_class_name,
224                                   guint signal_id);
225 static const gchar * get_type_name (GType type,
226                                     gboolean * is_pointer);
227 static gchar * get_gdk_event (const gchar * signal_name);
228 static gchar ** lookup_signal_arg_names (const gchar * type,
229                                          const gchar * signal_name);
230
231 static void output_widget_hierarchy (void);
232 static void output_hierarchy (FILE *fp,
233                               GType type,
234                               guint level);
235
236 static void output_widget_interfaces (void);
237 static void output_interfaces (FILE *fp,
238                                GType type);
239
240 static void output_interface_prerequisites (void);
241 static void output_prerequisites (FILE *fp,
242                                   GType type);
243
244 static void output_args (void);
245 static void output_widget_args (FILE *fp, GType object_type);
246
247 int
248 main (int argc, char *argv[])
249 {
250   $TYPE_INIT_FUNC;
251
252   get_object_types ();
253
254   g_debug ("output signals");
255   output_signals ();
256   g_debug ("output widget hierarchy");
257   output_widget_hierarchy ();
258   output_widget_interfaces ();
259   output_interface_prerequisites ();
260   g_debug ("output args");
261   output_args ();
262
263   return 0;
264 }
265
266
267 static void
268 output_signals (void)
269 {
270   FILE *fp;
271   gint i;
272
273   fp = fopen (signals_filename, "w");
274   if (fp == NULL)
275     {
276       g_warning ("Couldn't open output file: %s", signals_filename);
277       return;
278     }
279
280   for (i = 0; i < num_object_types; i++)
281     output_widget_signals (fp, object_types[i]);
282
283   fclose (fp);
284 }
285
286 static gint
287 compare_signals (const void *a, const void *b)
288 {
289   const guint *signal_a = a;
290   const guint *signal_b = b;
291
292   return strcmp (g_signal_name (*signal_a), g_signal_name (*signal_b));
293 }
294
295 /* This outputs all the signals of one widget. */
296 static void
297 output_widget_signals (FILE *fp, GType object_type)
298 {
299   const gchar *object_class_name;
300   guint *signals, n_signals;
301   guint sig;
302
303   if (G_TYPE_IS_INSTANTIATABLE (object_type) ||
304       G_TYPE_IS_INTERFACE (object_type))
305     {
306
307       object_class_name = g_type_name (object_type);
308
309       signals = g_signal_list_ids (object_type, &n_signals);
310       qsort (signals, n_signals, sizeof (guint), compare_signals);
311
312       for (sig = 0; sig < n_signals; sig++)
313         {
314            output_widget_signal (fp, object_type, object_class_name,
315                                  signals[sig]);
316         }
317       g_free (signals);
318    }
319 }
320
321
322 /* This outputs one signal. */
323 static void
324 output_widget_signal (FILE *fp,
325                       GType object_type,
326                       const gchar *object_name,
327                       guint signal_id)
328 {
329   GSignalQuery query_info;
330   const gchar *type_name, *ret_type, *object_arg;
331   gchar *pos, *arg_name, *object_arg_lower;
332   gboolean is_pointer;
333   gchar ret_type_buffer[1024], buffer[1024];
334   guint i, param;
335   gchar **arg_names;
336   gint param_num, widget_num, event_num, callback_num;
337   gint *arg_num;
338   gchar signal_name[128];
339
340
341   /*  g_print ("Object: %s Type: %i Signal: %u\\n", object_name, object_type,
342       signal_id);*/
343
344   param_num = 1;
345   widget_num = event_num = callback_num = 0;
346
347   g_signal_query (signal_id, &query_info);
348
349   /* Output the return type and function name. */
350   ret_type = get_type_name (query_info.return_type & ~G_SIGNAL_TYPE_STATIC_SCOPE, &is_pointer);
351   sprintf (ret_type_buffer, "%s%s", ret_type, is_pointer ? "*" : "");
352
353   /* Output the signal object type and the argument name. We assume the
354      type is a pointer - I think that is OK. We remove "Gtk" or "Gnome" and
355      convert to lower case for the argument name. */
356   pos = buffer;
357   sprintf (pos, "%s ", object_name);
358   pos += strlen (pos);
359
360   if (!strncmp (object_name, "Gtk", 3))
361       object_arg = object_name + 3;
362   else if (!strncmp (object_name, "Gnome", 5))
363       object_arg = object_name + 5;
364   else
365       object_arg = object_name;
366
367   object_arg_lower = g_ascii_strdown (object_arg, -1);
368   sprintf (pos, "*%s\\n", object_arg_lower);
369   pos += strlen (pos);
370   if (!strncmp (object_arg_lower, "widget", 6))
371     widget_num = 2;
372   g_free(object_arg_lower);
373
374   /* Convert signal name to use underscores rather than dashes '-'. */
375   strcpy (signal_name, query_info.signal_name);
376   for (i = 0; signal_name[i]; i++)
377     {
378       if (signal_name[i] == '-')
379         signal_name[i] = '_';
380     }
381
382   /* Output the signal parameters. */
383   arg_names = lookup_signal_arg_names (object_name, signal_name);
384
385   for (param = 0; param < query_info.n_params; param++)
386     {
387       if (arg_names)
388         {
389           sprintf (pos, "%s\\n", arg_names[param]);
390           pos += strlen (pos);
391         }
392       else
393         {
394           type_name = get_type_name (query_info.param_types[param] & ~G_SIGNAL_TYPE_STATIC_SCOPE, &is_pointer);
395
396           /* Most arguments to the callback are called "arg1", "arg2", etc.
397              GdkWidgets are called "widget", "widget2", ...
398              GdkEvents are called "event", "event2", ...
399              GtkCallbacks are called "callback", "callback2", ... */
400           if (!strcmp (type_name, "GtkWidget"))
401             {
402               arg_name = "widget";
403               arg_num = &widget_num;
404             }
405           else if (!strcmp (type_name, "GdkEvent"))
406             {
407               type_name = get_gdk_event (signal_name);
408               arg_name = "event";
409               arg_num = &event_num;
410               is_pointer = TRUE;
411             }
412           else if (!strcmp (type_name, "GtkCallback")
413                    || !strcmp (type_name, "GtkCCallback"))
414             {
415               arg_name = "callback";
416               arg_num = &callback_num;
417             }
418           else
419             {
420               arg_name = "arg";
421               arg_num = &param_num;
422             }
423           sprintf (pos, "%s ", type_name);
424           pos += strlen (pos);
425
426           if (!arg_num || *arg_num == 0)
427             sprintf (pos, "%s%s\\n", is_pointer ? "*" : " ", arg_name);
428           else
429             sprintf (pos, "%s%s%i\\n", is_pointer ? "*" : " ", arg_name,
430                      *arg_num);
431           pos += strlen (pos);
432
433           if (arg_num)
434             {
435               if (*arg_num == 0)
436                 *arg_num = 2;
437               else
438                 *arg_num += 1;
439             }
440         }
441     }
442
443   fprintf (fp,
444            "<SIGNAL>\\n<NAME>%s::%s</NAME>\\n<RETURNS>%s</RETURNS>\\n%s</SIGNAL>\\n\\n",
445            object_name, query_info.signal_name, ret_type_buffer, buffer);
446 }
447
448
449 /* Returns the type name to use for a signal argument or return value, given
450    the GtkType from the signal info. It also sets is_pointer to TRUE if the
451    argument needs a '*' since it is a pointer. */
452 static const gchar *
453 get_type_name (GType type, gboolean * is_pointer)
454 {
455   const gchar *type_name;
456
457   *is_pointer = FALSE;
458   type_name = g_type_name (type);
459
460   switch (type) {
461   case G_TYPE_NONE:
462   case G_TYPE_CHAR:
463   case G_TYPE_UCHAR:
464   case G_TYPE_BOOLEAN:
465   case G_TYPE_INT:
466   case G_TYPE_UINT:
467   case G_TYPE_LONG:
468   case G_TYPE_ULONG:
469   case G_TYPE_FLOAT:
470   case G_TYPE_DOUBLE:
471   case G_TYPE_POINTER:
472     /* These all have normal C type names so they are OK. */
473     return type_name;
474
475   case G_TYPE_STRING:
476     /* A GtkString is really a gchar*. */
477     *is_pointer = TRUE;
478     return "gchar";
479
480   case G_TYPE_ENUM:
481   case G_TYPE_FLAGS:
482     /* We use a gint for both of these. Hopefully a subtype with a decent
483        name will be registered and used instead, as GTK+ does itself. */
484     return "gint";
485
486   case G_TYPE_BOXED:
487     /* The boxed type shouldn't be used itself, only subtypes. Though we
488        return 'gpointer' just in case. */
489     return "gpointer";
490
491   case G_TYPE_PARAM:
492     /* A GParam is really a GParamSpec*. */
493     *is_pointer = TRUE;
494     return "GParamSpec";
495
496   default:
497     break;
498   }
499
500   /* For all GtkObject subclasses we can use the class name with a "*",
501      e.g. 'GtkWidget *'. */
502   if (g_type_is_a (type, G_TYPE_OBJECT))
503     *is_pointer = TRUE;
504
505   /* All boxed subtypes will be pointers as well. */
506   if (g_type_is_a (type, G_TYPE_BOXED))
507     *is_pointer = TRUE;
508
509   /* All pointer subtypes will be pointers as well. */
510   if (g_type_is_a (type, G_TYPE_POINTER))
511     *is_pointer = TRUE;
512
513   return type_name;
514 }
515
516
517 static gchar *
518 get_gdk_event (const gchar * signal_name)
519 {
520   static gchar *GbGDKEvents[] =
521   {
522     "button_press_event", "GdkEventButton",
523     "button_release_event", "GdkEventButton",
524     "motion_notify_event", "GdkEventMotion",
525     "delete_event", "GdkEvent",
526     "destroy_event", "GdkEvent",
527     "expose_event", "GdkEventExpose",
528     "key_press_event", "GdkEventKey",
529     "key_release_event", "GdkEventKey",
530     "enter_notify_event", "GdkEventCrossing",
531     "leave_notify_event", "GdkEventCrossing",
532     "configure_event", "GdkEventConfigure",
533     "focus_in_event", "GdkEventFocus",
534     "focus_out_event", "GdkEventFocus",
535     "map_event", "GdkEvent",
536     "unmap_event", "GdkEvent",
537     "property_notify_event", "GdkEventProperty",
538     "selection_clear_event", "GdkEventSelection",
539     "selection_request_event", "GdkEventSelection",
540     "selection_notify_event", "GdkEventSelection",
541     "proximity_in_event", "GdkEventProximity",
542     "proximity_out_event", "GdkEventProximity",
543     "drag_begin_event", "GdkEventDragBegin",
544     "drag_request_event", "GdkEventDragRequest",
545     "drag_end_event", "GdkEventDragRequest",
546     "drop_enter_event", "GdkEventDropEnter",
547     "drop_leave_event", "GdkEventDropLeave",
548     "drop_data_available_event", "GdkEventDropDataAvailable",
549     "other_event", "GdkEventOther",
550     "client_event", "GdkEventClient",
551     "no_expose_event", "GdkEventNoExpose",
552     "visibility_notify_event", "GdkEventVisibility",
553     "window_state_event", "GdkEventWindowState",
554     "scroll_event", "GdkEventScroll",
555     NULL
556   };
557
558   gint i;
559
560   for (i = 0; GbGDKEvents[i]; i += 2)
561     {
562       if (!strcmp (signal_name, GbGDKEvents[i]))
563         return GbGDKEvents[i + 1];
564     }
565   return "GdkEvent";
566 }
567
568
569 /* This returns argument names to use for some known GTK signals.
570     It is passed a widget name, e.g. 'GtkCList' and a signal name, e.g.
571     'select_row' and it returns a pointer to an array of argument types and
572     names. */
573 static gchar **
574 lookup_signal_arg_names (const gchar * type, const gchar * signal_name)
575 {
576   /* Each arg array starts with the object type name and the signal name,
577      and then signal arguments follow. */
578   static gchar *GbArgTable[][16] =
579   {
580     {"GtkCList", "select_row",
581      "gint             row",
582      "gint             column",
583      "GdkEventButton  *event"},
584     {"GtkCList", "unselect_row",
585      "gint             row",
586      "gint             column",
587      "GdkEventButton  *event"},
588     {"GtkCList", "click_column",
589      "gint             column"},
590
591     {"GtkCList", "resize_column",
592      "gint             column",
593      "gint             width"},
594
595     {"GtkCList", "extend_selection",
596      "GtkScrollType    scroll_type",
597      "gfloat           position",
598      "gboolean         auto_start_selection"},
599     {"GtkCList", "scroll_vertical",
600      "GtkScrollType    scroll_type",
601      "gfloat           position"},
602     {"GtkCList", "scroll_horizontal",
603      "GtkScrollType    scroll_type",
604      "gfloat           position"},
605
606     {"GtkCTree", "tree_select_row",
607      "GtkCTreeNode    *node",
608      "gint             column"},
609     {"GtkCTree", "tree_unselect_row",
610      "GtkCTreeNode    *node",
611      "gint             column"},
612     {"GtkCTree", "tree_expand",
613      "GtkCTreeNode    *node"},
614     {"GtkCTree", "tree_collapse",
615      "GtkCTreeNode    *node"},
616     {"GtkCTree", "tree_move",
617      "GtkCTreeNode    *node",
618      "GtkCTreeNode    *new_parent",
619      "GtkCTreeNode    *new_sibling"},
620     {"GtkCTree", "change_focus_row_expansion",
621      "GtkCTreeExpansionType expansion"},
622
623     {"GtkEditable", "insert_text",
624      "gchar           *new_text",
625      "gint             new_text_length",
626      "gint            *position"},
627     {"GtkEditable", "delete_text",
628      "gint             start_pos",
629      "gint             end_pos"},
630     {"GtkEditable", "set_editable",
631      "gboolean         is_editable"},
632     {"GtkEditable", "move_cursor",
633      "gint             x",
634      "gint             y"},
635     {"GtkEditable", "move_word",
636      "gint             num_words"},
637     {"GtkEditable", "move_page",
638      "gint             x",
639      "gint             y"},
640     {"GtkEditable", "move_to_row",
641      "gint             row"},
642     {"GtkEditable", "move_to_column",
643      "gint             column"},
644
645     {"GtkEditable", "kill_char",
646      "gint             direction"},
647     {"GtkEditable", "kill_word",
648      "gint             direction"},
649     {"GtkEditable", "kill_line",
650      "gint             direction"},
651
652
653     {"GtkInputDialog", "enable_device",
654      "GdkDevice       *deviceid"},
655     {"GtkInputDialog", "disable_device",
656      "GdkDevice       *deviceid"},
657
658     {"GtkListItem", "extend_selection",
659      "GtkScrollType    scroll_type",
660      "gfloat           position",
661      "gboolean         auto_start_selection"},
662     {"GtkListItem", "scroll_vertical",
663      "GtkScrollType    scroll_type",
664      "gfloat           position"},
665     {"GtkListItem", "scroll_horizontal",
666      "GtkScrollType    scroll_type",
667      "gfloat           position"},
668
669     {"GtkMenuShell", "move_current",
670      "GtkMenuDirectionType direction"},
671     {"GtkMenuShell", "activate_current",
672      "gboolean         force_hide"},
673
674
675     {"GtkNotebook", "switch_page",
676      "GtkNotebookPage *page",
677      "guint            page_num"},
678     {"GtkStatusbar", "text_pushed",
679      "guint            context_id",
680      "gchar           *text"},
681     {"GtkStatusbar", "text_popped",
682      "guint            context_id",
683      "gchar           *text"},
684     {"GtkTipsQuery", "widget_entered",
685      "GtkWidget       *widget",
686      "gchar           *tip_text",
687      "gchar           *tip_private"},
688     {"GtkTipsQuery", "widget_selected",
689      "GtkWidget       *widget",
690      "gchar           *tip_text",
691      "gchar           *tip_private",
692      "GdkEventButton  *event"},
693     {"GtkToolbar", "orientation_changed",
694      "GtkOrientation   orientation"},
695     {"GtkToolbar", "style_changed",
696      "GtkToolbarStyle  style"},
697     {"GtkWidget", "draw",
698      "GdkRectangle    *area"},
699     {"GtkWidget", "size_request",
700      "GtkRequisition  *requisition"},
701     {"GtkWidget", "size_allocate",
702      "GtkAllocation   *allocation"},
703     {"GtkWidget", "state_changed",
704      "GtkStateType     state"},
705     {"GtkWidget", "style_set",
706      "GtkStyle        *previous_style"},
707
708     {"GtkWidget", "install_accelerator",
709      "gchar           *signal_name",
710      "gchar            key",
711      "gint             modifiers"},
712
713     {"GtkWidget", "add_accelerator",
714      "guint            accel_signal_id",
715      "GtkAccelGroup   *accel_group",
716      "guint            accel_key",
717      "GdkModifierType  accel_mods",
718      "GtkAccelFlags    accel_flags"},
719
720     {"GtkWidget", "parent_set",
721      "GtkObject       *old_parent"},
722
723     {"GtkWidget", "remove_accelerator",
724      "GtkAccelGroup   *accel_group",
725      "guint            accel_key",
726      "GdkModifierType  accel_mods"},
727     {"GtkWidget", "debug_msg",
728      "gchar           *message"},
729     {"GtkWindow", "move_resize",
730      "gint            *x",
731      "gint            *y",
732      "gint             width",
733      "gint             height"},
734     {"GtkWindow", "set_focus",
735      "GtkWidget       *widget"},
736
737     {"GtkWidget", "selection_get",
738      "GtkSelectionData *data",
739      "guint            info",
740      "guint            time"},
741     {"GtkWidget", "selection_received",
742      "GtkSelectionData *data",
743      "guint            time"},
744
745     {"GtkWidget", "drag_begin",
746      "GdkDragContext  *drag_context"},
747     {"GtkWidget", "drag_end",
748      "GdkDragContext  *drag_context"},
749     {"GtkWidget", "drag_data_delete",
750      "GdkDragContext  *drag_context"},
751     {"GtkWidget", "drag_leave",
752      "GdkDragContext  *drag_context",
753      "guint            time"},
754     {"GtkWidget", "drag_motion",
755      "GdkDragContext  *drag_context",
756      "gint             x",
757      "gint             y",
758      "guint            time"},
759     {"GtkWidget", "drag_drop",
760      "GdkDragContext  *drag_context",
761      "gint             x",
762      "gint             y",
763      "guint            time"},
764     {"GtkWidget", "drag_data_get",
765      "GdkDragContext  *drag_context",
766      "GtkSelectionData *data",
767      "guint            info",
768      "guint            time"},
769     {"GtkWidget", "drag_data_received",
770      "GdkDragContext  *drag_context",
771      "gint             x",
772      "gint             y",
773      "GtkSelectionData *data",
774      "guint            info",
775      "guint            time"},
776
777     {NULL}
778   };
779
780   gint i;
781
782   for (i = 0; GbArgTable[i][0]; i++)
783     {
784 #if 1
785       if (!strcmp (type, GbArgTable[i][0])
786           && !strcmp (signal_name, GbArgTable[i][1]))
787         return &GbArgTable[i][2];
788 #endif
789     }
790   return NULL;
791 }
792
793 /* This outputs the hierarchy of all widgets which have been initialized,
794    i.e. by calling their XXX_get_type() initialization function. */
795 static void
796 output_widget_hierarchy (void)
797 {
798   FILE *fp;
799
800   fp = fopen (hierarchy_filename, "w");
801   if (fp == NULL)
802     {
803       g_warning ("Couldn't open output file: %s", hierarchy_filename);
804       return;
805     }
806   output_hierarchy (fp, G_TYPE_OBJECT, 0);
807   output_hierarchy (fp, G_TYPE_INTERFACE, 0);
808   fclose (fp);
809 }
810
811 /* This is called recursively to output the hierarchy of a widget. */
812 static void
813 output_hierarchy (FILE  *fp,
814                   GType  type,
815                   guint   level)
816 {
817   guint i;
818   GType *children;
819   guint n_children;
820
821   if (!type)
822     return;
823
824   for (i = 0; i < level; i++)
825     fprintf (fp, "  ");
826   fprintf (fp, g_type_name (type));
827   fprintf (fp, "\\n");
828
829   children = g_type_children (type, &n_children);
830
831   for (i=0; i < n_children; i++)
832     output_hierarchy (fp, children[i], level + 1);
833
834   g_free (children);
835 }
836
837 static void output_widget_interfaces (void)
838 {
839   FILE *fp;
840
841   fp = fopen (interfaces_filename, "w");
842   if (fp == NULL)
843     {
844       g_warning ("Couldn't open output file: %s", interfaces_filename);
845       return;
846     }
847   output_interfaces (fp, G_TYPE_OBJECT);
848   fclose (fp);
849 }
850
851 static void
852 output_interfaces (FILE  *fp,
853                    GType  type)
854 {
855   guint i;
856   GType *children, *interfaces;
857   guint n_children, n_interfaces;
858
859   if (!type)
860     return;
861
862   interfaces = g_type_interfaces (type, &n_interfaces);
863
864   if (n_interfaces > 0)
865     {
866       fprintf (fp, g_type_name (type));
867       for (i=0; i < n_interfaces; i++)
868           fprintf (fp, " %s", g_type_name (interfaces[i]));
869       fprintf (fp, "\\n");
870      }
871   g_free (interfaces);
872
873   children = g_type_children (type, &n_children);
874
875   for (i=0; i < n_children; i++)
876     output_interfaces (fp, children[i]);
877
878   g_free (children);
879 }
880
881 static void output_interface_prerequisites (void)
882 {
883   FILE *fp;
884
885   fp = fopen (prerequisites_filename, "w");
886   if (fp == NULL)
887     {
888       g_warning ("Couldn't open output file: %s", prerequisites_filename);
889       return;
890     }
891   output_prerequisites (fp, G_TYPE_INTERFACE);
892   fclose (fp);
893 }
894
895 static void
896 output_prerequisites (FILE  *fp,
897                       GType  type)
898 {
899 #if GLIB_CHECK_VERSION(2,1,0)
900   guint i;
901   GType *children, *prerequisites;
902   guint n_children, n_prerequisites;
903
904   if (!type)
905     return;
906
907   prerequisites = g_type_interface_prerequisites (type, &n_prerequisites);
908
909   if (n_prerequisites > 0)
910     {
911       fprintf (fp, g_type_name (type));
912       for (i=0; i < n_prerequisites; i++)
913           fprintf (fp, " %s", g_type_name (prerequisites[i]));
914       fprintf (fp, "\\n");
915      }
916   g_free (prerequisites);
917
918   children = g_type_children (type, &n_children);
919
920   for (i=0; i < n_children; i++)
921     output_prerequisites (fp, children[i]);
922
923   g_free (children);
924 #endif
925 }
926
927 static void
928 output_args (void)
929 {
930   FILE *fp;
931   gint i;
932
933   fp = fopen (args_filename, "w");
934   if (fp == NULL)
935     {
936       g_warning ("Couldn't open output file: %s", args_filename);
937       return;
938     }
939
940   for (i = 0; i < num_object_types; i++)
941     output_widget_args (fp, object_types[i]);
942
943   fclose (fp);
944 }
945
946 static gint
947 compare_param_specs (const void *a, const void *b)
948 {
949   GParamSpec *spec_a = *(GParamSpec **)a;
950   GParamSpec *spec_b = *(GParamSpec **)b;
951
952   return strcmp (g_param_spec_get_name (spec_a), g_param_spec_get_name (spec_b));
953 }
954
955 /* Its common to have unsigned properties restricted
956  * to the signed range. Therefore we make this look
957  * a bit nicer by spelling out the max constants.
958  */
959
960 static gchar*
961 describe_double_constant (gdouble value)
962 {
963   gchar *desc;
964
965   if (value == G_MAXDOUBLE)
966     desc = g_strdup ("G_MAXDOUBLE");
967   else if (value == G_MINDOUBLE)
968     desc = g_strdup ("G_MINDOUBLE");
969   else if (value == -G_MAXDOUBLE)
970     desc = g_strdup ("-G_MAXDOUBLE");
971   else if (value == G_MAXFLOAT)
972     desc = g_strdup ("G_MAXFLOAT");
973   else if (value == G_MINFLOAT)
974     desc = g_strdup ("G_MINFLOAT");
975   else if (value == -G_MAXFLOAT)
976     desc = g_strdup ("-G_MAXFLOAT");
977   else
978     desc = g_strdup_printf ("%lg", value);
979
980   return desc;
981 }
982
983 static gchar*
984 describe_signed_constant (gint64 value)
985 {
986   gchar *desc;
987
988   if (value == G_MAXINT)
989     desc = g_strdup ("G_MAXINT");
990   else if (value == G_MININT)
991     desc = g_strdup ("G_MININT");
992   else if (value == G_MAXUINT)
993     desc = g_strdup ("G_MAXUINT");
994   else if (value == G_MAXLONG)
995     desc = g_strdup ("G_MAXLONG");
996   else if (value == G_MINLONG)
997     desc = g_strdup ("G_MINLONG");
998   else if (value == G_MAXULONG)
999     desc = g_strdup ("G_MAXULONG");
1000   else if (value == G_MAXINT64)
1001     desc = g_strdup ("G_MAXINT64");
1002   else if (value == G_MININT64)
1003     desc = g_strdup ("G_MININT64");
1004   else
1005     desc = g_strdup_printf ("%" G_GINT64_FORMAT, value);
1006
1007   return desc;
1008 }
1009
1010 static gchar*
1011 describe_unsigned_constant (guint64 value)
1012 {
1013   gchar *desc;
1014
1015   if (value == G_MAXINT)
1016     desc = g_strdup ("G_MAXINT");
1017   else if (value == G_MININT)
1018     desc = g_strdup ("G_MININT");
1019   else if (value == G_MAXUINT)
1020     desc = g_strdup ("G_MAXUINT");
1021   else if (value == G_MAXLONG)
1022     desc = g_strdup ("G_MAXLONG");
1023   else if (value == G_MINLONG)
1024     desc = g_strdup ("G_MINLONG");
1025   else if (value == G_MAXULONG)
1026     desc = g_strdup ("G_MAXULONG");
1027   else if (value == G_MAXINT64)
1028     desc = g_strdup ("G_MAXINT64");
1029   else if (value == G_MININT64)
1030     desc = g_strdup ("G_MININT64");
1031   else if (value == G_MAXUINT64)
1032     desc = g_strdup ("G_MAXUINT64");
1033   else
1034     desc = g_strdup_printf ("%" G_GUINT64_FORMAT, value);
1035
1036   return desc;
1037 }
1038
1039 static gchar*
1040 describe_type (GParamSpec *spec)
1041 {
1042   gchar *desc;
1043   gchar *lower;
1044   gchar *upper;
1045
1046   if (G_IS_PARAM_SPEC_CHAR (spec))
1047     {
1048       GParamSpecChar *pspec = G_PARAM_SPEC_CHAR (spec);
1049
1050       lower = describe_signed_constant (pspec->minimum);
1051       upper = describe_signed_constant (pspec->maximum);
1052       if (pspec->minimum == G_MININT8 && pspec->maximum == G_MAXINT8)
1053         desc = g_strdup ("");
1054       else if (pspec->minimum == G_MININT8)
1055         desc = g_strdup_printf ("<= %s", upper);
1056       else if (pspec->maximum == G_MAXINT8)
1057         desc = g_strdup_printf (">= %s", lower);
1058       else
1059         desc = g_strdup_printf ("[%s,%s]", lower, upper);
1060       g_free (lower);
1061       g_free (upper);
1062     }
1063   else if (G_IS_PARAM_SPEC_UCHAR (spec))
1064     {
1065       GParamSpecUChar *pspec = G_PARAM_SPEC_UCHAR (spec);
1066
1067       lower = describe_unsigned_constant (pspec->minimum);
1068       upper = describe_unsigned_constant (pspec->maximum);
1069       if (pspec->minimum == 0 && pspec->maximum == G_MAXUINT8)
1070         desc = g_strdup ("");
1071       else if (pspec->minimum == 0)
1072         desc = g_strdup_printf ("<= %s", upper);
1073       else if (pspec->maximum == G_MAXUINT8)
1074         desc = g_strdup_printf (">= %s", lower);
1075       else
1076         desc = g_strdup_printf ("[%s,%s]", lower, upper);
1077       g_free (lower);
1078       g_free (upper);
1079     }
1080   else if (G_IS_PARAM_SPEC_INT (spec))
1081     {
1082       GParamSpecInt *pspec = G_PARAM_SPEC_INT (spec);
1083
1084       lower = describe_signed_constant (pspec->minimum);
1085       upper = describe_signed_constant (pspec->maximum);
1086       if (pspec->minimum == G_MININT && pspec->maximum == G_MAXINT)
1087         desc = g_strdup ("");
1088       else if (pspec->minimum == G_MININT)
1089         desc = g_strdup_printf ("<= %s", upper);
1090       else if (pspec->maximum == G_MAXINT)
1091         desc = g_strdup_printf (">= %s", lower);
1092       else
1093         desc = g_strdup_printf ("[%s,%s]", lower, upper);
1094       g_free (lower);
1095       g_free (upper);
1096     }
1097   else if (G_IS_PARAM_SPEC_UINT (spec))
1098     {
1099       GParamSpecUInt *pspec = G_PARAM_SPEC_UINT (spec);
1100
1101       lower = describe_unsigned_constant (pspec->minimum);
1102       upper = describe_unsigned_constant (pspec->maximum);
1103       if (pspec->minimum == 0 && pspec->maximum == G_MAXUINT)
1104         desc = g_strdup ("");
1105       else if (pspec->minimum == 0)
1106         desc = g_strdup_printf ("<= %s", upper);
1107       else if (pspec->maximum == G_MAXUINT)
1108         desc = g_strdup_printf (">= %s", lower);
1109       else
1110         desc = g_strdup_printf ("[%s,%s]", lower, upper);
1111       g_free (lower);
1112       g_free (upper);
1113     }
1114   else if (G_IS_PARAM_SPEC_LONG (spec))
1115     {
1116       GParamSpecLong *pspec = G_PARAM_SPEC_LONG (spec);
1117
1118       lower = describe_signed_constant (pspec->minimum);
1119       upper = describe_signed_constant (pspec->maximum);
1120       if (pspec->minimum == G_MINLONG && pspec->maximum == G_MAXLONG)
1121         desc = g_strdup ("");
1122       else if (pspec->minimum == G_MINLONG)
1123         desc = g_strdup_printf ("<= %s", upper);
1124       else if (pspec->maximum == G_MAXLONG)
1125         desc = g_strdup_printf (">= %s", lower);
1126       else
1127         desc = g_strdup_printf ("[%s,%s]", lower, upper);
1128       g_free (lower);
1129       g_free (upper);
1130     }
1131   else if (G_IS_PARAM_SPEC_ULONG (spec))
1132     {
1133       GParamSpecULong *pspec = G_PARAM_SPEC_ULONG (spec);
1134       gchar *upper;
1135
1136       lower = describe_unsigned_constant (pspec->minimum);
1137       upper = describe_unsigned_constant (pspec->maximum);
1138       if (pspec->minimum == 0 && pspec->maximum == G_MAXULONG)
1139         desc = g_strdup ("");
1140       else if (pspec->minimum == 0)
1141         desc = g_strdup_printf ("<= %s", upper);
1142       else if (pspec->maximum == G_MAXULONG)
1143         desc = g_strdup_printf (">= %s", lower);
1144       else
1145         desc = g_strdup_printf ("[%s,%s]", lower, upper);
1146       g_free (lower);
1147       g_free (upper);
1148     }
1149   else if (G_IS_PARAM_SPEC_INT64 (spec))
1150     {
1151       GParamSpecInt64 *pspec = G_PARAM_SPEC_INT64 (spec);
1152
1153       lower = describe_signed_constant (pspec->minimum);
1154       upper = describe_signed_constant (pspec->maximum);
1155       if (pspec->minimum == G_MININT64 && pspec->maximum == G_MAXINT64)
1156         desc = g_strdup ("");
1157       else if (pspec->minimum == G_MININT64)
1158         desc = g_strdup_printf ("<= %s", upper);
1159       else if (pspec->maximum == G_MAXINT64)
1160         desc = g_strdup_printf (">= %s", lower);
1161       else
1162         desc = g_strdup_printf ("[%s,%s]", lower, upper);
1163       g_free (lower);
1164       g_free (upper);
1165     }
1166   else if (G_IS_PARAM_SPEC_UINT64 (spec))
1167     {
1168       GParamSpecUInt64 *pspec = G_PARAM_SPEC_UINT64 (spec);
1169
1170       lower = describe_unsigned_constant (pspec->minimum);
1171       upper = describe_unsigned_constant (pspec->maximum);
1172       if (pspec->minimum == 0 && pspec->maximum == G_MAXUINT64)
1173         desc = g_strdup ("");
1174       else if (pspec->minimum == 0)
1175         desc = g_strdup_printf ("<= %s", upper);
1176       else if (pspec->maximum == G_MAXUINT64)
1177         desc = g_strdup_printf (">= %s", lower);
1178       else
1179         desc = g_strdup_printf ("[%s,%s]", lower, upper);
1180       g_free (lower);
1181       g_free (upper);
1182     }
1183   else if (G_IS_PARAM_SPEC_FLOAT (spec))
1184     {
1185       GParamSpecFloat *pspec = G_PARAM_SPEC_FLOAT (spec);
1186
1187       lower = describe_double_constant (pspec->minimum);
1188       upper = describe_double_constant (pspec->maximum);
1189       if (pspec->minimum == -G_MAXFLOAT && pspec->maximum == G_MAXFLOAT)
1190         desc = g_strdup ("");
1191       else if (pspec->minimum == -G_MAXFLOAT)
1192         desc = g_strdup_printf ("<= %s", upper);
1193       else if (pspec->maximum == G_MAXFLOAT)
1194         desc = g_strdup_printf (">= %s", lower);
1195       else
1196         desc = g_strdup_printf ("[%s,%s]", lower, upper);
1197       g_free (lower);
1198       g_free (upper);
1199     }
1200   else if (G_IS_PARAM_SPEC_DOUBLE (spec))
1201     {
1202       GParamSpecDouble *pspec = G_PARAM_SPEC_DOUBLE (spec);
1203
1204       lower = describe_double_constant (pspec->minimum);
1205       upper = describe_double_constant (pspec->maximum);
1206       if (pspec->minimum == -G_MAXDOUBLE && pspec->maximum == G_MAXDOUBLE)
1207         desc = g_strdup ("");
1208       else if (pspec->minimum == -G_MAXDOUBLE)
1209         desc = g_strdup_printf ("<= %s", upper);
1210       else if (pspec->maximum == G_MAXDOUBLE)
1211         desc = g_strdup_printf (">= %s", lower);
1212       else
1213         desc = g_strdup_printf ("[%s,%s]", lower, upper);
1214       g_free (lower);
1215       g_free (upper);
1216     }
1217   else
1218     {
1219       desc = g_strdup ("");
1220     }
1221
1222   return desc;
1223 }
1224
1225 static gchar*
1226 describe_default (GParamSpec *spec)
1227 {
1228   gchar *desc;
1229
1230   if (G_IS_PARAM_SPEC_CHAR (spec))
1231     {
1232       GParamSpecChar *pspec = G_PARAM_SPEC_CHAR (spec);
1233
1234       desc = g_strdup_printf ("%d", pspec->default_value);
1235     }
1236   else if (G_IS_PARAM_SPEC_UCHAR (spec))
1237     {
1238       GParamSpecUChar *pspec = G_PARAM_SPEC_UCHAR (spec);
1239
1240       desc = g_strdup_printf ("%u", pspec->default_value);
1241     }
1242   else if (G_IS_PARAM_SPEC_BOOLEAN (spec))
1243     {
1244       GParamSpecBoolean *pspec = G_PARAM_SPEC_BOOLEAN (spec);
1245
1246       desc = g_strdup_printf ("%s", pspec->default_value ? "TRUE" : "FALSE");
1247     }
1248   else if (G_IS_PARAM_SPEC_INT (spec))
1249     {
1250       GParamSpecInt *pspec = G_PARAM_SPEC_INT (spec);
1251
1252       desc = g_strdup_printf ("%d", pspec->default_value);
1253     }
1254   else if (G_IS_PARAM_SPEC_UINT (spec))
1255     {
1256       GParamSpecUInt *pspec = G_PARAM_SPEC_UINT (spec);
1257
1258       desc = g_strdup_printf ("%u", pspec->default_value);
1259     }
1260   else if (G_IS_PARAM_SPEC_LONG (spec))
1261     {
1262       GParamSpecLong *pspec = G_PARAM_SPEC_LONG (spec);
1263
1264       desc = g_strdup_printf ("%ld", pspec->default_value);
1265     }
1266   else if (G_IS_PARAM_SPEC_LONG (spec))
1267     {
1268       GParamSpecULong *pspec = G_PARAM_SPEC_ULONG (spec);
1269
1270       desc = g_strdup_printf ("%lu", pspec->default_value);
1271     }
1272   else if (G_IS_PARAM_SPEC_INT64 (spec))
1273     {
1274       GParamSpecInt64 *pspec = G_PARAM_SPEC_INT64 (spec);
1275
1276       desc = g_strdup_printf ("%" G_GINT64_FORMAT, pspec->default_value);
1277     }
1278   else if (G_IS_PARAM_SPEC_UINT64 (spec))
1279     {
1280       GParamSpecUInt64 *pspec = G_PARAM_SPEC_UINT64 (spec);
1281
1282       desc = g_strdup_printf ("%" G_GUINT64_FORMAT, pspec->default_value);
1283     }
1284   else if (G_IS_PARAM_SPEC_UNICHAR (spec))
1285     {
1286       GParamSpecUnichar *pspec = G_PARAM_SPEC_UNICHAR (spec);
1287
1288       if (g_unichar_isprint (pspec->default_value))
1289         desc = g_strdup_printf ("'%c'", pspec->default_value);
1290       else
1291         desc = g_strdup_printf ("%u", pspec->default_value);
1292     }
1293   else if (G_IS_PARAM_SPEC_ENUM (spec))
1294     {
1295       GParamSpecEnum *pspec = G_PARAM_SPEC_ENUM (spec);
1296
1297       GEnumValue *value = g_enum_get_value (pspec->enum_class, pspec->default_value);
1298       if (value)
1299         desc = g_strdup_printf ("%s", value->value_name);
1300       else
1301         desc = g_strdup_printf ("%d", pspec->default_value);
1302     }
1303   else if (G_IS_PARAM_SPEC_FLAGS (spec))
1304     {
1305       GParamSpecFlags *pspec = G_PARAM_SPEC_FLAGS (spec);
1306       guint default_value;
1307       GString *acc;
1308
1309       default_value = pspec->default_value;
1310       acc = g_string_new ("");
1311
1312       while (default_value)
1313         {
1314           GFlagsValue *value = g_flags_get_first_value (pspec->flags_class, default_value);
1315
1316           if (!value)
1317             break;
1318
1319           if (acc->len > 0)
1320             g_string_append (acc, "|");
1321           g_string_append (acc, value->value_name);
1322
1323           default_value &= ~value->value;
1324         }
1325
1326       if (default_value == 0)
1327         desc = g_string_free (acc, FALSE);
1328       else
1329         {
1330           desc = g_strdup_printf ("%d", pspec->default_value);
1331           g_string_free (acc, TRUE);
1332         }
1333     }
1334   else if (G_IS_PARAM_SPEC_FLOAT (spec))
1335     {
1336       GParamSpecFloat *pspec = G_PARAM_SPEC_FLOAT (spec);
1337
1338       desc = g_strdup_printf ("%g", pspec->default_value);
1339     }
1340   else if (G_IS_PARAM_SPEC_DOUBLE (spec))
1341     {
1342       GParamSpecDouble *pspec = G_PARAM_SPEC_DOUBLE (spec);
1343
1344       desc = g_strdup_printf ("%lg", pspec->default_value);
1345     }
1346   else if (G_IS_PARAM_SPEC_STRING (spec))
1347     {
1348       GParamSpecString *pspec = G_PARAM_SPEC_STRING (spec);
1349
1350       if (pspec->default_value)
1351         {
1352           gchar *esc = g_strescape (pspec->default_value, NULL);
1353
1354           desc = g_strdup_printf ("\\"%s\\"", esc);
1355
1356           g_free (esc);
1357         }
1358       else
1359         desc = g_strdup_printf ("NULL");
1360     }
1361   else
1362     {
1363       desc = g_strdup ("");
1364     }
1365
1366   return desc;
1367 }
1368
1369
1370 static void
1371 output_widget_args (FILE *fp, GType object_type)
1372 {
1373   gpointer class;
1374   const gchar *object_class_name;
1375   guint arg;
1376   gchar flags[16], *pos;
1377   GParamSpec **properties;
1378   guint n_properties;
1379   gboolean child_prop;
1380   gboolean style_prop;
1381   gchar *type_desc;
1382   gchar *default_value;
1383
1384   if (G_TYPE_IS_CLASSED (object_type))
1385     {
1386       class = g_type_class_peek (object_type);
1387       if (!class)
1388         return;
1389
1390       properties = g_object_class_list_properties (class, &n_properties);
1391     }
1392 #if GLIB_MAJOR_VERSION > 2 || (GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION >= 3)
1393   else if (G_TYPE_IS_INTERFACE (object_type))
1394     {
1395       class = g_type_default_interface_ref (object_type);
1396
1397       if (!class)
1398         return;
1399
1400       properties = g_object_interface_list_properties (class, &n_properties);
1401     }
1402 #endif
1403   else
1404     return;
1405
1406   object_class_name = g_type_name (object_type);
1407
1408   child_prop = FALSE;
1409   style_prop = FALSE;
1410
1411   while (TRUE) {
1412     qsort (properties, n_properties, sizeof (GParamSpec *), compare_param_specs);
1413     for (arg = 0; arg < n_properties; arg++)
1414       {
1415         GParamSpec *spec = properties[arg];
1416         const gchar *nick, *blurb, *dot;
1417
1418         if (spec->owner_type != object_type)
1419           continue;
1420
1421         pos = flags;
1422         /* We use one-character flags for simplicity. */
1423         if (child_prop && !style_prop)
1424           *pos++ = 'c';
1425         if (style_prop)
1426           *pos++ = 's';
1427         if (spec->flags & G_PARAM_READABLE)
1428           *pos++ = 'r';
1429         if (spec->flags & G_PARAM_WRITABLE)
1430           *pos++ = 'w';
1431         if (spec->flags & G_PARAM_CONSTRUCT)
1432           *pos++ = 'x';
1433         if (spec->flags & G_PARAM_CONSTRUCT_ONLY)
1434           *pos++ = 'X';
1435         *pos = 0;
1436
1437         nick = g_param_spec_get_nick (spec);
1438         blurb = g_param_spec_get_blurb (spec);
1439
1440         dot = "";
1441         if (blurb) {
1442           int str_len = strlen (blurb);
1443           if (str_len > 0  && blurb[str_len - 1] != '.')
1444             dot = ".";
1445         }
1446
1447         type_desc = describe_type (spec);
1448         default_value = describe_default (spec);
1449         fprintf (fp, "<ARG>\\n<NAME>%s::%s</NAME>\\n<TYPE>%s</TYPE>\\n<RANGE>%s</RANGE>\\n<FLAGS>%s</FLAGS>\\n<NICK>%s</NICK>\\n<BLURB>%s%s</BLURB>\\n<DEFAULT>%s</DEFAULT>\\n</ARG>\\n\\n",
1450                  object_class_name, g_param_spec_get_name (spec), g_type_name (spec->value_type), type_desc, flags, nick ? nick : "(null)", blurb ? blurb : "(null)", dot, default_value);
1451         g_free (type_desc);
1452         g_free (default_value);
1453       }
1454
1455     g_free (properties);
1456
1457 #ifdef GTK_IS_CONTAINER_CLASS
1458     if (!child_prop && GTK_IS_CONTAINER_CLASS (class)) {
1459       properties = gtk_container_class_list_child_properties (class, &n_properties);
1460       child_prop = TRUE;
1461       continue;
1462     }
1463 #endif
1464
1465 #ifdef GTK_IS_WIDGET_CLASS
1466 #if GTK_CHECK_VERSION(2,1,0)
1467     if (!style_prop && GTK_IS_WIDGET_CLASS (class)) {
1468       properties = gtk_widget_class_list_style_properties (GTK_WIDGET_CLASS (class), &n_properties);
1469       style_prop = TRUE;
1470       continue;
1471     }
1472 #endif
1473 #endif
1474
1475     break;
1476   }
1477 }
1478 EOT
1479
1480 close OUTPUT;
1481
1482 # Compile and run our file
1483
1484 $CC = $ENV{CC} ? $ENV{CC} : "gcc";
1485 $LD = $ENV{LD} ? $ENV{LD} : $CC;
1486 $CFLAGS = $ENV{CFLAGS} ? $ENV{CFLAGS} : "";
1487 $LDFLAGS = $ENV{LDFLAGS} ? $ENV{LDFLAGS} : "";
1488
1489 my $o_file;
1490 if ($CC =~ /libtool/) {
1491   $o_file  = "$MODULE-scan.lo"
1492 } else {
1493   $o_file = "$MODULE-scan.o"
1494 }
1495
1496 $command = "$CC $CFLAGS -c -o $o_file $MODULE-scan.c && $LD -o $MODULE-scan $o_file $LDFLAGS";
1497
1498 system($command) == 0 or die "Compilation of scanner failed\n";
1499
1500 system("./$MODULE-scan") == 0 or die "Scan failed\n";
1501
1502 unlink "./$MODULE-scan.c", "./$MODULE-scan.o", "./$MODULE-scan.lo", "./$MODULE-scan";
1503
1504 &UpdateFileIfChanged ($old_signals_filename, $new_signals_filename, 0);
1505 &UpdateFileIfChanged ($old_hierarchy_filename, $new_hierarchy_filename, 0);
1506 &UpdateFileIfChanged ($old_interfaces_filename, $new_interfaces_filename, 0);
1507 &UpdateFileIfChanged ($old_prerequisites_filename, $new_prerequisites_filename, 0);
1508 &UpdateFileIfChanged ($old_args_filename, $new_args_filename, 0);
1509
1510