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