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