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