g/: fix properly for new API; make update in plugins dir now works
[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   /* All boxed subtypes will be pointers as well. */
517   if (g_type_is_a (type, G_TYPE_BOXED))
518     *is_pointer = TRUE;
519
520   /* All pointer subtypes will be pointers as well. */
521   if (g_type_is_a (type, G_TYPE_POINTER))
522     *is_pointer = TRUE;
523
524   return type_name;
525 }
526
527
528 static gchar *
529 get_gdk_event (const gchar * signal_name)
530 {
531   static gchar *GbGDKEvents[] =
532   {
533     "button_press_event", "GdkEventButton",
534     "button_release_event", "GdkEventButton",
535     "motion_notify_event", "GdkEventMotion",
536     "delete_event", "GdkEvent",
537     "destroy_event", "GdkEvent",
538     "expose_event", "GdkEventExpose",
539     "key_press_event", "GdkEventKey",
540     "key_release_event", "GdkEventKey",
541     "enter_notify_event", "GdkEventCrossing",
542     "leave_notify_event", "GdkEventCrossing",
543     "configure_event", "GdkEventConfigure",
544     "focus_in_event", "GdkEventFocus",
545     "focus_out_event", "GdkEventFocus",
546     "map_event", "GdkEvent",
547     "unmap_event", "GdkEvent",
548     "property_notify_event", "GdkEventProperty",
549     "selection_clear_event", "GdkEventSelection",
550     "selection_request_event", "GdkEventSelection",
551     "selection_notify_event", "GdkEventSelection",
552     "proximity_in_event", "GdkEventProximity",
553     "proximity_out_event", "GdkEventProximity",
554     "drag_begin_event", "GdkEventDragBegin",
555     "drag_request_event", "GdkEventDragRequest",
556     "drag_end_event", "GdkEventDragRequest",
557     "drop_enter_event", "GdkEventDropEnter",
558     "drop_leave_event", "GdkEventDropLeave",
559     "drop_data_available_event", "GdkEventDropDataAvailable",
560     "other_event", "GdkEventOther",
561     "client_event", "GdkEventClient",
562     "no_expose_event", "GdkEventNoExpose",
563     "visibility_notify_event", "GdkEventVisibility",
564     "window_state_event", "GdkEventWindowState",
565     "scroll_event", "GdkEventScroll",
566     NULL
567   };
568
569   gint i;
570
571   for (i = 0; GbGDKEvents[i]; i += 2)
572     {
573       if (!strcmp (signal_name, GbGDKEvents[i]))
574         return GbGDKEvents[i + 1];
575     }
576   return "GdkEvent";
577 }
578
579
580 /* This returns argument names to use for some known GTK signals.
581     It is passed a widget name, e.g. 'GtkCList' and a signal name, e.g.
582     'select_row' and it returns a pointer to an array of argument types and
583     names. */
584 static gchar **
585 lookup_signal_arg_names (const gchar * type, const gchar * signal_name)
586 {
587   /* Each arg array starts with the object type name and the signal name,
588      and then signal arguments follow. */
589   static gchar *GbArgTable[][16] =
590   {
591     {"GtkCList", "select_row",
592      "gint             row",
593      "gint             column",
594      "GdkEventButton  *event"},
595     {"GtkCList", "unselect_row",
596      "gint             row",
597      "gint             column",
598      "GdkEventButton  *event"},
599     {"GtkCList", "click_column",
600      "gint             column"},
601
602     {"GtkCList", "resize_column",
603      "gint             column",
604      "gint             width"},
605
606     {"GtkCList", "extend_selection",
607      "GtkScrollType    scroll_type",
608      "gfloat           position",
609      "gboolean         auto_start_selection"},
610     {"GtkCList", "scroll_vertical",
611      "GtkScrollType    scroll_type",
612      "gfloat           position"},
613     {"GtkCList", "scroll_horizontal",
614      "GtkScrollType    scroll_type",
615      "gfloat           position"},
616
617     {"GtkCTree", "tree_select_row",
618      "GtkCTreeNode    *node",
619      "gint             column"},
620     {"GtkCTree", "tree_unselect_row",
621      "GtkCTreeNode    *node",
622      "gint             column"},
623     {"GtkCTree", "tree_expand",
624      "GtkCTreeNode    *node"},
625     {"GtkCTree", "tree_collapse",
626      "GtkCTreeNode    *node"},
627     {"GtkCTree", "tree_move",
628      "GtkCTreeNode    *node",
629      "GtkCTreeNode    *new_parent",
630      "GtkCTreeNode    *new_sibling"},
631     {"GtkCTree", "change_focus_row_expansion",
632      "GtkCTreeExpansionType expansion"},
633
634     {"GtkEditable", "insert_text",
635      "gchar           *new_text",
636      "gint             new_text_length",
637      "gint            *position"},
638     {"GtkEditable", "delete_text",
639      "gint             start_pos",
640      "gint             end_pos"},
641     {"GtkEditable", "set_editable",
642      "gboolean         is_editable"},
643     {"GtkEditable", "move_cursor",
644      "gint             x",
645      "gint             y"},
646     {"GtkEditable", "move_word",
647      "gint             num_words"},
648     {"GtkEditable", "move_page",
649      "gint             x",
650      "gint             y"},
651     {"GtkEditable", "move_to_row",
652      "gint             row"},
653     {"GtkEditable", "move_to_column",
654      "gint             column"},
655
656     {"GtkEditable", "kill_char",
657      "gint             direction"},
658     {"GtkEditable", "kill_word",
659      "gint             direction"},
660     {"GtkEditable", "kill_line",
661      "gint             direction"},
662
663
664     {"GtkInputDialog", "enable_device",
665      "GdkDevice       *deviceid"},
666     {"GtkInputDialog", "disable_device",
667      "GdkDevice       *deviceid"},
668
669     {"GtkListItem", "extend_selection",
670      "GtkScrollType    scroll_type",
671      "gfloat           position",
672      "gboolean         auto_start_selection"},
673     {"GtkListItem", "scroll_vertical",
674      "GtkScrollType    scroll_type",
675      "gfloat           position"},
676     {"GtkListItem", "scroll_horizontal",
677      "GtkScrollType    scroll_type",
678      "gfloat           position"},
679
680     {"GtkMenuShell", "move_current",
681      "GtkMenuDirectionType direction"},
682     {"GtkMenuShell", "activate_current",
683      "gboolean         force_hide"},
684
685
686     {"GtkNotebook", "switch_page",
687      "GtkNotebookPage *page",
688      "guint            page_num"},
689     {"GtkStatusbar", "text_pushed",
690      "guint            context_id",
691      "gchar           *text"},
692     {"GtkStatusbar", "text_popped",
693      "guint            context_id",
694      "gchar           *text"},
695     {"GtkTipsQuery", "widget_entered",
696      "GtkWidget       *widget",
697      "gchar           *tip_text",
698      "gchar           *tip_private"},
699     {"GtkTipsQuery", "widget_selected",
700      "GtkWidget       *widget",
701      "gchar           *tip_text",
702      "gchar           *tip_private",
703      "GdkEventButton  *event"},
704     {"GtkToolbar", "orientation_changed",
705      "GtkOrientation   orientation"},
706     {"GtkToolbar", "style_changed",
707      "GtkToolbarStyle  style"},
708     {"GtkWidget", "draw",
709      "GdkRectangle    *area"},
710     {"GtkWidget", "size_request",
711      "GtkRequisition  *requisition"},
712     {"GtkWidget", "size_allocate",
713      "GtkAllocation   *allocation"},
714     {"GtkWidget", "state_changed",
715      "GtkStateType     state"},
716     {"GtkWidget", "style_set",
717      "GtkStyle        *previous_style"},
718
719     {"GtkWidget", "install_accelerator",
720      "gchar           *signal_name",
721      "gchar            key",
722      "gint             modifiers"},
723
724     {"GtkWidget", "add_accelerator",
725      "guint            accel_signal_id",
726      "GtkAccelGroup   *accel_group",
727      "guint            accel_key",
728      "GdkModifierType  accel_mods",
729      "GtkAccelFlags    accel_flags"},
730
731     {"GtkWidget", "parent_set",
732      "GtkObject       *old_parent"},
733
734     {"GtkWidget", "remove_accelerator",
735      "GtkAccelGroup   *accel_group",
736      "guint            accel_key",
737      "GdkModifierType  accel_mods"},
738     {"GtkWidget", "debug_msg",
739      "gchar           *message"},
740     {"GtkWindow", "move_resize",
741      "gint            *x",
742      "gint            *y",
743      "gint             width",
744      "gint             height"},
745     {"GtkWindow", "set_focus",
746      "GtkWidget       *widget"},
747
748     {"GtkWidget", "selection_get",
749      "GtkSelectionData *data",
750      "guint            info",
751      "guint            time"},
752     {"GtkWidget", "selection_received",
753      "GtkSelectionData *data",
754      "guint            time"},
755
756     {"GtkWidget", "drag_begin",
757      "GdkDragContext  *drag_context"},
758     {"GtkWidget", "drag_end",
759      "GdkDragContext  *drag_context"},
760     {"GtkWidget", "drag_data_delete",
761      "GdkDragContext  *drag_context"},
762     {"GtkWidget", "drag_leave",
763      "GdkDragContext  *drag_context",
764      "guint            time"},
765     {"GtkWidget", "drag_motion",
766      "GdkDragContext  *drag_context",
767      "gint             x",
768      "gint             y",
769      "guint            time"},
770     {"GtkWidget", "drag_drop",
771      "GdkDragContext  *drag_context",
772      "gint             x",
773      "gint             y",
774      "guint            time"},
775     {"GtkWidget", "drag_data_get",
776      "GdkDragContext  *drag_context",
777      "GtkSelectionData *data",
778      "guint            info",
779      "guint            time"},
780     {"GtkWidget", "drag_data_received",
781      "GdkDragContext  *drag_context",
782      "gint             x",
783      "gint             y",
784      "GtkSelectionData *data",
785      "guint            info",
786      "guint            time"},
787
788     {NULL}
789   };
790
791   gint i;
792
793   for (i = 0; GbArgTable[i][0]; i++)
794     {
795 #if 1
796       if (!strcmp (type, GbArgTable[i][0])
797           && !strcmp (signal_name, GbArgTable[i][1]))
798         return &GbArgTable[i][2];
799 #endif
800     }
801   return NULL;
802 }
803
804 /* This outputs the hierarchy of all widgets which have been initialized,
805    i.e. by calling their XXX_get_type() initialization function. */
806 static void
807 output_widget_hierarchy (void)
808 {
809   FILE *fp;
810
811   fp = fopen (hierarchy_filename, "w");
812   if (fp == NULL)
813     {
814       g_warning ("Couldn't open output file: %s", hierarchy_filename);
815       return;
816     }
817   output_hierarchy (fp, G_TYPE_OBJECT, 0);
818   output_hierarchy (fp, G_TYPE_INTERFACE, 0);
819   fclose (fp);
820 }
821
822 /* This is called recursively to output the hierarchy of a widget. */
823 static void
824 output_hierarchy (FILE  *fp,
825                   GType  type,
826                   guint   level)
827 {
828   guint i;
829   GType *children;
830   guint n_children;
831
832   if (!type)
833     return;
834
835   for (i = 0; i < level; i++)
836     fprintf (fp, "  ");
837   fprintf (fp, g_type_name (type));
838   fprintf (fp, "\\n");
839
840   children = g_type_children (type, &n_children);
841
842   for (i=0; i < n_children; i++)
843     output_hierarchy (fp, children[i], level + 1);
844
845   g_free (children);
846 }
847
848 static void output_widget_interfaces (void)
849 {
850   FILE *fp;
851
852   fp = fopen (interfaces_filename, "w");
853   if (fp == NULL)
854     {
855       g_warning ("Couldn't open output file: %s", interfaces_filename);
856       return;
857     }
858   output_interfaces (fp, G_TYPE_OBJECT);
859   fclose (fp);
860 }
861
862 static void
863 output_interfaces (FILE  *fp,
864                    GType  type)
865 {
866   guint i;
867   GType *children, *interfaces;
868   guint n_children, n_interfaces;
869
870   if (!type)
871     return;
872
873   interfaces = g_type_interfaces (type, &n_interfaces);
874
875   if (n_interfaces > 0)
876     {
877       fprintf (fp, g_type_name (type));
878       for (i=0; i < n_interfaces; i++)
879           fprintf (fp, " %s", g_type_name (interfaces[i]));
880       fprintf (fp, "\\n");
881      }
882   g_free (interfaces);
883
884   children = g_type_children (type, &n_children);
885
886   for (i=0; i < n_children; i++)
887     output_interfaces (fp, children[i]);
888
889   g_free (children);
890 }
891
892 static void output_interface_prerequisites (void)
893 {
894   FILE *fp;
895
896   fp = fopen (prerequisites_filename, "w");
897   if (fp == NULL)
898     {
899       g_warning ("Couldn't open output file: %s", prerequisites_filename);
900       return;
901     }
902   output_prerequisites (fp, G_TYPE_INTERFACE);
903   fclose (fp);
904 }
905
906 static void
907 output_prerequisites (FILE  *fp,
908                       GType  type)
909 {
910 #if GLIB_CHECK_VERSION(2,1,0)
911   guint i;
912   GType *children, *prerequisites;
913   guint n_children, n_prerequisites;
914
915   if (!type)
916     return;
917
918   prerequisites = g_type_interface_prerequisites (type, &n_prerequisites);
919
920   if (n_prerequisites > 0)
921     {
922       fprintf (fp, g_type_name (type));
923       for (i=0; i < n_prerequisites; i++)
924           fprintf (fp, " %s", g_type_name (prerequisites[i]));
925       fprintf (fp, "\\n");
926      }
927   g_free (prerequisites);
928
929   children = g_type_children (type, &n_children);
930
931   for (i=0; i < n_children; i++)
932     output_prerequisites (fp, children[i]);
933
934   g_free (children);
935 #endif
936 }
937
938 static void
939 output_args (void)
940 {
941   FILE *fp;
942   gint i;
943
944   fp = fopen (args_filename, "w");
945   if (fp == NULL)
946     {
947       g_warning ("Couldn't open output file: %s", args_filename);
948       return;
949     }
950
951   for (i = 0; i < num_object_types; i++)
952     output_widget_args (fp, object_types[i]);
953
954   fclose (fp);
955 }
956
957 static gint
958 compare_param_specs (const void *a, const void *b)
959 {
960   GParamSpec *spec_a = *(GParamSpec **)a;
961   GParamSpec *spec_b = *(GParamSpec **)b;
962
963   return strcmp (g_param_spec_get_name (spec_a), g_param_spec_get_name (spec_b));
964 }
965
966 /* Its common to have unsigned properties restricted
967  * to the signed range. Therefore we make this look
968  * a bit nicer by spelling out the max constants.
969  */
970
971 static gchar*
972 describe_double_constant (gdouble value)
973 {
974   gchar *desc;
975
976   if (value == G_MAXDOUBLE)
977     desc = g_strdup ("G_MAXDOUBLE");
978   else if (value == G_MINDOUBLE)
979     desc = g_strdup ("G_MINDOUBLE");
980   else if (value == -G_MAXDOUBLE)
981     desc = g_strdup ("-G_MAXDOUBLE");
982   else if (value == G_MAXFLOAT)
983     desc = g_strdup ("G_MAXFLOAT");
984   else if (value == G_MINFLOAT)
985     desc = g_strdup ("G_MINFLOAT");
986   else if (value == -G_MAXFLOAT)
987     desc = g_strdup ("-G_MAXFLOAT");
988   else
989     desc = g_strdup_printf ("%lg", value);
990
991   return desc;
992 }
993
994 static gchar*
995 describe_signed_constant (gint64 value)
996 {
997   gchar *desc;
998
999   if (value == G_MAXINT)
1000     desc = g_strdup ("G_MAXINT");
1001   else if (value == G_MININT)
1002     desc = g_strdup ("G_MININT");
1003   else if (value == G_MAXUINT)
1004     desc = g_strdup ("G_MAXUINT");
1005   else if (value == G_MAXLONG)
1006     desc = g_strdup ("G_MAXLONG");
1007   else if (value == G_MINLONG)
1008     desc = g_strdup ("G_MINLONG");
1009   else if (value == G_MAXULONG)
1010     desc = g_strdup ("G_MAXULONG");
1011   else if (value == G_MAXINT64)
1012     desc = g_strdup ("G_MAXINT64");
1013   else if (value == G_MININT64)
1014     desc = g_strdup ("G_MININT64");
1015   else
1016     desc = g_strdup_printf ("%" G_GINT64_FORMAT, value);
1017
1018   return desc;
1019 }
1020
1021 static gchar*
1022 describe_unsigned_constant (guint64 value)
1023 {
1024   gchar *desc;
1025
1026   if (value == G_MAXINT)
1027     desc = g_strdup ("G_MAXINT");
1028   else if (value == G_MININT)
1029     desc = g_strdup ("G_MININT");
1030   else if (value == G_MAXUINT)
1031     desc = g_strdup ("G_MAXUINT");
1032   else if (value == G_MAXLONG)
1033     desc = g_strdup ("G_MAXLONG");
1034   else if (value == G_MINLONG)
1035     desc = g_strdup ("G_MINLONG");
1036   else if (value == G_MAXULONG)
1037     desc = g_strdup ("G_MAXULONG");
1038   else if (value == G_MAXINT64)
1039     desc = g_strdup ("G_MAXINT64");
1040   else if (value == G_MININT64)
1041     desc = g_strdup ("G_MININT64");
1042   else if (value == G_MAXUINT64)
1043     desc = g_strdup ("G_MAXUINT64");
1044   else
1045     desc = g_strdup_printf ("%" G_GUINT64_FORMAT, value);
1046
1047   return desc;
1048 }
1049
1050 static gchar*
1051 describe_type (GParamSpec *spec)
1052 {
1053   gchar *desc;
1054   gchar *lower;
1055   gchar *upper;
1056
1057   if (G_IS_PARAM_SPEC_CHAR (spec))
1058     {
1059       GParamSpecChar *pspec = G_PARAM_SPEC_CHAR (spec);
1060
1061       lower = describe_signed_constant (pspec->minimum);
1062       upper = describe_signed_constant (pspec->maximum);
1063       if (pspec->minimum == G_MININT8 && pspec->maximum == G_MAXINT8)
1064         desc = g_strdup ("");
1065       else if (pspec->minimum == G_MININT8)
1066         desc = g_strdup_printf ("<= %s", upper);
1067       else if (pspec->maximum == G_MAXINT8)
1068         desc = g_strdup_printf (">= %s", lower);
1069       else
1070         desc = g_strdup_printf ("[%s,%s]", lower, upper);
1071       g_free (lower);
1072       g_free (upper);
1073     }
1074   else if (G_IS_PARAM_SPEC_UCHAR (spec))
1075     {
1076       GParamSpecUChar *pspec = G_PARAM_SPEC_UCHAR (spec);
1077
1078       lower = describe_unsigned_constant (pspec->minimum);
1079       upper = describe_unsigned_constant (pspec->maximum);
1080       if (pspec->minimum == 0 && pspec->maximum == G_MAXUINT8)
1081         desc = g_strdup ("");
1082       else if (pspec->minimum == 0)
1083         desc = g_strdup_printf ("<= %s", upper);
1084       else if (pspec->maximum == G_MAXUINT8)
1085         desc = g_strdup_printf (">= %s", lower);
1086       else
1087         desc = g_strdup_printf ("[%s,%s]", lower, upper);
1088       g_free (lower);
1089       g_free (upper);
1090     }
1091   else if (G_IS_PARAM_SPEC_INT (spec))
1092     {
1093       GParamSpecInt *pspec = G_PARAM_SPEC_INT (spec);
1094
1095       lower = describe_signed_constant (pspec->minimum);
1096       upper = describe_signed_constant (pspec->maximum);
1097       if (pspec->minimum == G_MININT && pspec->maximum == G_MAXINT)
1098         desc = g_strdup ("");
1099       else if (pspec->minimum == G_MININT)
1100         desc = g_strdup_printf ("<= %s", upper);
1101       else if (pspec->maximum == G_MAXINT)
1102         desc = g_strdup_printf (">= %s", lower);
1103       else
1104         desc = g_strdup_printf ("[%s,%s]", lower, upper);
1105       g_free (lower);
1106       g_free (upper);
1107     }
1108   else if (G_IS_PARAM_SPEC_UINT (spec))
1109     {
1110       GParamSpecUInt *pspec = G_PARAM_SPEC_UINT (spec);
1111
1112       lower = describe_unsigned_constant (pspec->minimum);
1113       upper = describe_unsigned_constant (pspec->maximum);
1114       if (pspec->minimum == 0 && pspec->maximum == G_MAXUINT)
1115         desc = g_strdup ("");
1116       else if (pspec->minimum == 0)
1117         desc = g_strdup_printf ("<= %s", upper);
1118       else if (pspec->maximum == G_MAXUINT)
1119         desc = g_strdup_printf (">= %s", lower);
1120       else
1121         desc = g_strdup_printf ("[%s,%s]", lower, upper);
1122       g_free (lower);
1123       g_free (upper);
1124     }
1125   else if (G_IS_PARAM_SPEC_LONG (spec))
1126     {
1127       GParamSpecLong *pspec = G_PARAM_SPEC_LONG (spec);
1128
1129       lower = describe_signed_constant (pspec->minimum);
1130       upper = describe_signed_constant (pspec->maximum);
1131       if (pspec->minimum == G_MINLONG && pspec->maximum == G_MAXLONG)
1132         desc = g_strdup ("");
1133       else if (pspec->minimum == G_MINLONG)
1134         desc = g_strdup_printf ("<= %s", upper);
1135       else if (pspec->maximum == G_MAXLONG)
1136         desc = g_strdup_printf (">= %s", lower);
1137       else
1138         desc = g_strdup_printf ("[%s,%s]", lower, upper);
1139       g_free (lower);
1140       g_free (upper);
1141     }
1142   else if (G_IS_PARAM_SPEC_ULONG (spec))
1143     {
1144       GParamSpecULong *pspec = G_PARAM_SPEC_ULONG (spec);
1145       gchar *upper;
1146
1147       lower = describe_unsigned_constant (pspec->minimum);
1148       upper = describe_unsigned_constant (pspec->maximum);
1149       if (pspec->minimum == 0 && pspec->maximum == G_MAXULONG)
1150         desc = g_strdup ("");
1151       else if (pspec->minimum == 0)
1152         desc = g_strdup_printf ("<= %s", upper);
1153       else if (pspec->maximum == G_MAXULONG)
1154         desc = g_strdup_printf (">= %s", lower);
1155       else
1156         desc = g_strdup_printf ("[%s,%s]", lower, upper);
1157       g_free (lower);
1158       g_free (upper);
1159     }
1160   else if (G_IS_PARAM_SPEC_INT64 (spec))
1161     {
1162       GParamSpecInt64 *pspec = G_PARAM_SPEC_INT64 (spec);
1163
1164       lower = describe_signed_constant (pspec->minimum);
1165       upper = describe_signed_constant (pspec->maximum);
1166       if (pspec->minimum == G_MININT64 && pspec->maximum == G_MAXINT64)
1167         desc = g_strdup ("");
1168       else if (pspec->minimum == G_MININT64)
1169         desc = g_strdup_printf ("<= %s", upper);
1170       else if (pspec->maximum == G_MAXINT64)
1171         desc = g_strdup_printf (">= %s", lower);
1172       else
1173         desc = g_strdup_printf ("[%s,%s]", lower, upper);
1174       g_free (lower);
1175       g_free (upper);
1176     }
1177   else if (G_IS_PARAM_SPEC_UINT64 (spec))
1178     {
1179       GParamSpecUInt64 *pspec = G_PARAM_SPEC_UINT64 (spec);
1180
1181       lower = describe_unsigned_constant (pspec->minimum);
1182       upper = describe_unsigned_constant (pspec->maximum);
1183       if (pspec->minimum == 0 && pspec->maximum == G_MAXUINT64)
1184         desc = g_strdup ("");
1185       else if (pspec->minimum == 0)
1186         desc = g_strdup_printf ("<= %s", upper);
1187       else if (pspec->maximum == G_MAXUINT64)
1188         desc = g_strdup_printf (">= %s", lower);
1189       else
1190         desc = g_strdup_printf ("[%s,%s]", lower, upper);
1191       g_free (lower);
1192       g_free (upper);
1193     }
1194   else if (G_IS_PARAM_SPEC_FLOAT (spec))
1195     {
1196       GParamSpecFloat *pspec = G_PARAM_SPEC_FLOAT (spec);
1197
1198       lower = describe_double_constant (pspec->minimum);
1199       upper = describe_double_constant (pspec->maximum);
1200       if (pspec->minimum == -G_MAXFLOAT && pspec->maximum == G_MAXFLOAT)
1201         desc = g_strdup ("");
1202       else if (pspec->minimum == -G_MAXFLOAT)
1203         desc = g_strdup_printf ("<= %s", upper);
1204       else if (pspec->maximum == G_MAXFLOAT)
1205         desc = g_strdup_printf (">= %s", lower);
1206       else
1207         desc = g_strdup_printf ("[%s,%s]", lower, upper);
1208       g_free (lower);
1209       g_free (upper);
1210     }
1211   else if (G_IS_PARAM_SPEC_DOUBLE (spec))
1212     {
1213       GParamSpecDouble *pspec = G_PARAM_SPEC_DOUBLE (spec);
1214
1215       lower = describe_double_constant (pspec->minimum);
1216       upper = describe_double_constant (pspec->maximum);
1217       if (pspec->minimum == -G_MAXDOUBLE && pspec->maximum == G_MAXDOUBLE)
1218         desc = g_strdup ("");
1219       else if (pspec->minimum == -G_MAXDOUBLE)
1220         desc = g_strdup_printf ("<= %s", upper);
1221       else if (pspec->maximum == G_MAXDOUBLE)
1222         desc = g_strdup_printf (">= %s", lower);
1223       else
1224         desc = g_strdup_printf ("[%s,%s]", lower, upper);
1225       g_free (lower);
1226       g_free (upper);
1227     }
1228   else
1229     {
1230       desc = g_strdup ("");
1231     }
1232
1233   return desc;
1234 }
1235
1236 static gchar*
1237 describe_default (GParamSpec *spec)
1238 {
1239   gchar *desc;
1240
1241   if (G_IS_PARAM_SPEC_CHAR (spec))
1242     {
1243       GParamSpecChar *pspec = G_PARAM_SPEC_CHAR (spec);
1244
1245       desc = g_strdup_printf ("%d", pspec->default_value);
1246     }
1247   else if (G_IS_PARAM_SPEC_UCHAR (spec))
1248     {
1249       GParamSpecUChar *pspec = G_PARAM_SPEC_UCHAR (spec);
1250
1251       desc = g_strdup_printf ("%u", pspec->default_value);
1252     }
1253   else if (G_IS_PARAM_SPEC_BOOLEAN (spec))
1254     {
1255       GParamSpecBoolean *pspec = G_PARAM_SPEC_BOOLEAN (spec);
1256
1257       desc = g_strdup_printf ("%s", pspec->default_value ? "TRUE" : "FALSE");
1258     }
1259   else if (G_IS_PARAM_SPEC_INT (spec))
1260     {
1261       GParamSpecInt *pspec = G_PARAM_SPEC_INT (spec);
1262
1263       desc = g_strdup_printf ("%d", pspec->default_value);
1264     }
1265   else if (G_IS_PARAM_SPEC_UINT (spec))
1266     {
1267       GParamSpecUInt *pspec = G_PARAM_SPEC_UINT (spec);
1268
1269       desc = g_strdup_printf ("%u", pspec->default_value);
1270     }
1271   else if (G_IS_PARAM_SPEC_LONG (spec))
1272     {
1273       GParamSpecLong *pspec = G_PARAM_SPEC_LONG (spec);
1274
1275       desc = g_strdup_printf ("%ld", pspec->default_value);
1276     }
1277   else if (G_IS_PARAM_SPEC_LONG (spec))
1278     {
1279       GParamSpecULong *pspec = G_PARAM_SPEC_ULONG (spec);
1280
1281       desc = g_strdup_printf ("%lu", pspec->default_value);
1282     }
1283   else if (G_IS_PARAM_SPEC_INT64 (spec))
1284     {
1285       GParamSpecInt64 *pspec = G_PARAM_SPEC_INT64 (spec);
1286
1287       desc = g_strdup_printf ("%" G_GINT64_FORMAT, pspec->default_value);
1288     }
1289   else if (G_IS_PARAM_SPEC_UINT64 (spec))
1290     {
1291       GParamSpecUInt64 *pspec = G_PARAM_SPEC_UINT64 (spec);
1292
1293       desc = g_strdup_printf ("%" G_GUINT64_FORMAT, pspec->default_value);
1294     }
1295   else if (G_IS_PARAM_SPEC_UNICHAR (spec))
1296     {
1297       GParamSpecUnichar *pspec = G_PARAM_SPEC_UNICHAR (spec);
1298
1299       if (g_unichar_isprint (pspec->default_value))
1300         desc = g_strdup_printf ("'%c'", pspec->default_value);
1301       else
1302         desc = g_strdup_printf ("%u", pspec->default_value);
1303     }
1304   else if (G_IS_PARAM_SPEC_ENUM (spec))
1305     {
1306       GParamSpecEnum *pspec = G_PARAM_SPEC_ENUM (spec);
1307
1308       GEnumValue *value = g_enum_get_value (pspec->enum_class, pspec->default_value);
1309       if (value)
1310         desc = g_strdup_printf ("%s", value->value_name);
1311       else
1312         desc = g_strdup_printf ("%d", pspec->default_value);
1313     }
1314   else if (G_IS_PARAM_SPEC_FLAGS (spec))
1315     {
1316       GParamSpecFlags *pspec = G_PARAM_SPEC_FLAGS (spec);
1317       guint default_value;
1318       GString *acc;
1319
1320       default_value = pspec->default_value;
1321       acc = g_string_new ("");
1322
1323       while (default_value)
1324         {
1325           GFlagsValue *value = g_flags_get_first_value (pspec->flags_class, default_value);
1326
1327           if (!value)
1328             break;
1329
1330           if (acc->len > 0)
1331             g_string_append (acc, "|");
1332           g_string_append (acc, value->value_name);
1333
1334           default_value &= ~value->value;
1335         }
1336
1337       if (default_value == 0)
1338         desc = g_string_free (acc, FALSE);
1339       else
1340         {
1341           desc = g_strdup_printf ("%d", pspec->default_value);
1342           g_string_free (acc, TRUE);
1343         }
1344     }
1345   else if (G_IS_PARAM_SPEC_FLOAT (spec))
1346     {
1347       GParamSpecFloat *pspec = G_PARAM_SPEC_FLOAT (spec);
1348
1349       desc = g_strdup_printf ("%g", pspec->default_value);
1350     }
1351   else if (G_IS_PARAM_SPEC_DOUBLE (spec))
1352     {
1353       GParamSpecDouble *pspec = G_PARAM_SPEC_DOUBLE (spec);
1354
1355       desc = g_strdup_printf ("%lg", pspec->default_value);
1356     }
1357   else if (G_IS_PARAM_SPEC_STRING (spec))
1358     {
1359       GParamSpecString *pspec = G_PARAM_SPEC_STRING (spec);
1360
1361       if (pspec->default_value)
1362         {
1363           gchar *esc = g_strescape (pspec->default_value, NULL);
1364
1365           desc = g_strdup_printf ("\\"%s\\"", esc);
1366
1367           g_free (esc);
1368         }
1369       else
1370         desc = g_strdup_printf ("NULL");
1371     }
1372   else
1373     {
1374       desc = g_strdup ("");
1375     }
1376
1377   return desc;
1378 }
1379
1380
1381 static void
1382 output_widget_args (FILE *fp, GType object_type)
1383 {
1384   gpointer class;
1385   const gchar *object_class_name;
1386   guint arg;
1387   gchar flags[16], *pos;
1388   GParamSpec **properties;
1389   guint n_properties;
1390   gboolean child_prop;
1391   gboolean style_prop;
1392   gchar *type_desc;
1393   gchar *default_value;
1394
1395   if (G_TYPE_IS_CLASSED (object_type))
1396     {
1397       class = g_type_class_peek (object_type);
1398       if (!class)
1399         return;
1400
1401       properties = g_object_class_list_properties (class, &n_properties);
1402     }
1403 #if GLIB_MAJOR_VERSION > 2 || (GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION >= 3)
1404   else if (G_TYPE_IS_INTERFACE (object_type))
1405     {
1406       class = g_type_default_interface_ref (object_type);
1407
1408       if (!class)
1409         return;
1410
1411       properties = g_object_interface_list_properties (class, &n_properties);
1412     }
1413 #endif
1414   else
1415     return;
1416
1417   object_class_name = g_type_name (object_type);
1418
1419   child_prop = FALSE;
1420   style_prop = FALSE;
1421
1422   while (TRUE) {
1423     qsort (properties, n_properties, sizeof (GParamSpec *), compare_param_specs);
1424     for (arg = 0; arg < n_properties; arg++)
1425       {
1426         GParamSpec *spec = properties[arg];
1427         const gchar *nick, *blurb, *dot;
1428
1429         if (spec->owner_type != object_type)
1430           continue;
1431
1432         pos = flags;
1433         /* We use one-character flags for simplicity. */
1434         if (child_prop && !style_prop)
1435           *pos++ = 'c';
1436         if (style_prop)
1437           *pos++ = 's';
1438         if (spec->flags & G_PARAM_READABLE)
1439           *pos++ = 'r';
1440         if (spec->flags & G_PARAM_WRITABLE)
1441           *pos++ = 'w';
1442         if (spec->flags & G_PARAM_CONSTRUCT)
1443           *pos++ = 'x';
1444         if (spec->flags & G_PARAM_CONSTRUCT_ONLY)
1445           *pos++ = 'X';
1446         *pos = 0;
1447
1448         nick = g_param_spec_get_nick (spec);
1449         blurb = g_param_spec_get_blurb (spec);
1450
1451         dot = "";
1452         if (blurb) {
1453           int str_len = strlen (blurb);
1454           if (str_len > 0  && blurb[str_len - 1] != '.')
1455             dot = ".";
1456         }
1457
1458         type_desc = describe_type (spec);
1459         default_value = describe_default (spec);
1460         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",
1461                  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);
1462         g_free (type_desc);
1463         g_free (default_value);
1464       }
1465
1466     g_free (properties);
1467
1468 #ifdef GTK_IS_CONTAINER_CLASS
1469     if (!child_prop && GTK_IS_CONTAINER_CLASS (class)) {
1470       properties = gtk_container_class_list_child_properties (class, &n_properties);
1471       child_prop = TRUE;
1472       continue;
1473     }
1474 #endif
1475
1476 #ifdef GTK_IS_WIDGET_CLASS
1477 #if GTK_CHECK_VERSION(2,1,0)
1478     if (!style_prop && GTK_IS_WIDGET_CLASS (class)) {
1479       properties = gtk_widget_class_list_style_properties (GTK_WIDGET_CLASS (class), &n_properties);
1480       style_prop = TRUE;
1481       continue;
1482     }
1483 #endif
1484 #endif
1485
1486     break;
1487   }
1488 }
1489 EOT
1490
1491 close OUTPUT;
1492
1493 # Compile and run our file
1494
1495 $CC = $ENV{CC} ? $ENV{CC} : "gcc";
1496 $LD = $ENV{LD} ? $ENV{LD} : $CC;
1497 $CFLAGS = $ENV{CFLAGS} ? "$ENV{CFLAGS} -Wall -g" : "-Wall -g";
1498 $LDFLAGS = $ENV{LDFLAGS} ? $ENV{LDFLAGS} : "";
1499
1500 my $o_file;
1501 if ($CC =~ /libtool/) {
1502   $o_file  = "$MODULE-scan.lo"
1503 } else {
1504   $o_file = "$MODULE-scan.o"
1505 }
1506
1507 $command = "$CC $CFLAGS -c -o $o_file $MODULE-scan.c && $LD -o $MODULE-scan $o_file $LDFLAGS";
1508
1509 system($command) == 0 or die "Compilation of scanner failed\n";
1510
1511 system("./$MODULE-scan") == 0 or die "Scan failed\n";
1512
1513 unlink "./$MODULE-scan.c", "./$MODULE-scan.o", "./$MODULE-scan.lo", "./$MODULE-scan";
1514
1515 #&UpdateFileIfChanged ($old_signals_filename, $new_signals_filename, 0);
1516 #&UpdateFileIfChanged ($old_hierarchy_filename, $new_hierarchy_filename, 0);
1517 #&UpdateFileIfChanged ($old_interfaces_filename, $new_interfaces_filename, 0);
1518 #&UpdateFileIfChanged ($old_prerequisites_filename, $new_prerequisites_filename, 0);
1519 #&UpdateFileIfChanged ($old_args_filename, $new_args_filename, 0);
1520
1521