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