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