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