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