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