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