Add a long annotated parameter description (regression test for #613611)
[gtk-doc.git] / gtkdoc-scangobj.in
blob0593dbf354eb9a297ed411389c668305100e2630
1 #!@PERL@ -w
2 # -*- cperl -*-
4 # gtk-doc - GTK DocBook documentation generator.
5 # Copyright (C) 1998  Damon Chaplin
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.
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.
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
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.
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 #       FIXME: this is only needed for undocumented signals, we should remove
31 #       the list as its totally undermaintained anyway
33 use Getopt::Long;
35 push @INC, '@PACKAGE_DATA_DIR@';
36 require "gtkdoc-common.pl";
38 # Options
40 # name of documentation module
41 my $MODULE;
42 my $OUTPUT_DIR;
43 my $PRINT_VERSION;
44 my $PRINT_HELP;
45 my $TYPE_INIT_FUNC="g_type_init(); g_type_class_ref(G_TYPE_OBJECT)";
46 my $QUERY_CHILD_PROPERTIES;
48 # --nogtkinit is deprecated, as it is the default now anyway.
49 %optctl = (module => \$MODULE,
50            types => \$TYPES_FILE,
51            nogtkinit => \$NO_GTK_INIT,
52            'type-init-func' => \$TYPE_INIT_FUNC,
53            'query-child-properties' => \$QUERY_CHILD_PROPERTIES,
54            'output-dir' => \$OUTPUT_DIR,
55            'version' => \$PRINT_VERSION,
56            'help' => \$PRINT_HELP);
57            
58 GetOptions(\%optctl, "module=s", "types:s", "output-dir:s", "nogtkinit", "type-init-func:s", "query-child-properties:s", "version", "help");
60 if ($NO_GTK_INIT) {
61   # Do nothing. This just avoids a warning.
62   # the option is not used anymore
65 if ($PRINT_VERSION) {
66     print "@VERSION@\n";
67     exit 0;
70 if (!$MODULE) {
71     $PRINT_HELP = 1;
74 if ($PRINT_HELP) {
75     print <<EOF;
76 gtkdoc-scangobj version @VERSION@ - introspect g-objects
78 --module=MODULE_NAME          Name of the doc module being parsed
79 --types=FILE                  The name of the file to store the types in
80 --type-init-func=FUNC         The init function to call instead of g_type_init()
81 --query-child-properties=FUNC A function that returns a list of child
82                               properties for a class
83 --output-dir=DIRNAME          The directory where the results are stored
84 --version                     Print the version of this program
85 --help                        Print this help
86 EOF
87     exit 0;
90 $OUTPUT_DIR = $OUTPUT_DIR ? $OUTPUT_DIR : ".";
92 $TYPES_FILE = $TYPES_FILE ? $TYPES_FILE : "$OUTPUT_DIR/$MODULE.types";
94 open (TYPES, $TYPES_FILE) || die "Cannot open $TYPES_FILE: $!\n";
95 open (OUTPUT, ">$MODULE-scan.c") || die "Cannot open $MODULE-scan.c: $!\n";
97 my $old_signals_filename = "$OUTPUT_DIR/$MODULE.signals";
98 my $new_signals_filename = "$OUTPUT_DIR/$MODULE.signals.new";
99 my $old_hierarchy_filename = "$OUTPUT_DIR/$MODULE.hierarchy";
100 my $new_hierarchy_filename = "$OUTPUT_DIR/$MODULE.hierarchy.new";
101 my $old_interfaces_filename = "$OUTPUT_DIR/$MODULE.interfaces";
102 my $new_interfaces_filename = "$OUTPUT_DIR/$MODULE.interfaces.new";
103 my $old_prerequisites_filename = "$OUTPUT_DIR/$MODULE.prerequisites";
104 my $new_prerequisites_filename = "$OUTPUT_DIR/$MODULE.prerequisites.new";
105 my $old_args_filename = "$OUTPUT_DIR/$MODULE.args";
106 my $new_args_filename = "$OUTPUT_DIR/$MODULE.args.new";
108 # write a C program to scan the types
110 $includes = "";
111 @types = ();
113 for (<TYPES>) {
114     if (/^#include/) {
115         $includes .= $_;
116     } elsif (/^gnome_keyring_item_info_get_type$/) {
117         # HACK: This isn't really a GObject type so skip it.
118         next;
119     } elsif (/^%/) {
120         next;
121     } elsif (/^\s*$/) {
122         next;
123     } else {
124         chomp;
125         push @types, $_;
126     }
129 $ntypes = @types + 1;
131 print OUTPUT <<EOT;
132 #include <string.h>
133 #include <stdlib.h>
134 #include <stdio.h>
135 #include <errno.h>
136 #include <glib-object.h>
140 if ($includes) {
141     print OUTPUT $includes;
142 } else {
143     for (@types) {
144         print OUTPUT "extern GType $_ (void);\n";
145     }
148 if ($QUERY_CHILD_PROPERTIES) {
149   print OUTPUT <<EOT;
150 extern GParamSpec** $QUERY_CHILD_PROPERTIES (gpointer class, guint *n_properties);
154 print OUTPUT <<EOT;
156 #ifdef GTK_IS_WIDGET_CLASS
157 #include <gtk/gtk.h>
158 #endif
159 GType object_types[$ntypes];
161 static GType *
162 get_object_types (void)
164     gpointer g_object_class;
165     gint i = 0;
168 for (@types) {
169     print OUTPUT "    object_types[i++] = $_ ();\n";
172 print OUTPUT <<EOT;
173     object_types[i] = 0;
175     /* reference the GObjectClass to initialize the param spec pool
176      * potentially needed by interfaces. See http://bugs.gnome.org/571820 */
177     g_object_class = g_type_class_ref (G_TYPE_OBJECT);
179     /* Need to make sure all the types are loaded in and initialize
180      * their signals and properties.
181      */
182     for (i=0; object_types[i]; i++)
183       {
184         if (G_TYPE_IS_CLASSED (object_types[i]))
185           g_type_class_ref (object_types[i]);
186         if (G_TYPE_IS_INTERFACE (object_types[i]))
187           g_type_default_interface_ref (object_types[i]);
188       }
190     g_type_class_unref (g_object_class);
192     return object_types;
196  * This uses GObject type functions to output signal prototypes and the object
197  * hierarchy.
198  */
200 /* The output files */
201 const gchar *signals_filename = "$new_signals_filename";
202 const gchar *hierarchy_filename = "$new_hierarchy_filename";
203 const gchar *interfaces_filename = "$new_interfaces_filename";
204 const gchar *prerequisites_filename = "$new_prerequisites_filename";
205 const gchar *args_filename = "$new_args_filename";
208 static void output_signals (void);
209 static void output_object_signals (FILE *fp,
210                                    GType object_type);
211 static void output_object_signal (FILE *fp,
212                                   const gchar *object_class_name,
213                                   guint signal_id);
214 static const gchar * get_type_name (GType type,
215                                     gboolean * is_pointer);
216 static const gchar * get_gdk_event (const gchar * signal_name);
217 static const gchar ** lookup_signal_arg_names (const gchar * type,
218                                                const gchar * signal_name);
220 static void output_object_hierarchy (void);
221 static void output_hierarchy (FILE *fp,
222                               GType type,
223                               guint level);
225 static void output_object_interfaces (void);
226 static void output_interfaces (FILE *fp,
227                                GType type);
229 static void output_interface_prerequisites (void);
230 static void output_prerequisites (FILE *fp,
231                                   GType type);
233 static void output_args (void);
234 static void output_object_args (FILE *fp, GType object_type);
237 main (int argc, char *argv[])
239   $TYPE_INIT_FUNC;
241   get_object_types ();
243   output_signals ();
244   output_object_hierarchy ();
245   output_object_interfaces ();
246   output_interface_prerequisites ();
247   output_args ();
249   return 0;
253 static void
254 output_signals (void)
256   FILE *fp;
257   gint i;
259   fp = fopen (signals_filename, "w");
260   if (fp == NULL)
261     {
262       g_warning ("Couldn't open output file: %s : %s", signals_filename, g_strerror(errno));
263       return;
264     }
266   for (i = 0; object_types[i]; i++)
267     output_object_signals (fp, object_types[i]);
269   fclose (fp);
272 static gint
273 compare_signals (const void *a, const void *b)
275   const guint *signal_a = a;
276   const guint *signal_b = b;
278   return strcmp (g_signal_name (*signal_a), g_signal_name (*signal_b));
281 /* This outputs all the signals of one object. */
282 static void
283 output_object_signals (FILE *fp, GType object_type)
285   const gchar *object_class_name;
286   guint *signals, n_signals;
287   guint sig;
289   if (G_TYPE_IS_INSTANTIATABLE (object_type) ||
290       G_TYPE_IS_INTERFACE (object_type))
291     {
293       object_class_name = g_type_name (object_type);
295       signals = g_signal_list_ids (object_type, &n_signals);
296       qsort (signals, n_signals, sizeof (guint), compare_signals);
298       for (sig = 0; sig < n_signals; sig++)
299         {
300            output_object_signal (fp, object_class_name, signals[sig]);
301         }
302       g_free (signals);
303    }
307 /* This outputs one signal. */
308 static void
309 output_object_signal (FILE *fp,
310                       const gchar *object_name,
311                       guint signal_id)
313   GSignalQuery query_info;
314   const gchar *type_name, *ret_type, *object_arg, *arg_name;
315   gchar *pos, *object_arg_lower;
316   gboolean is_pointer;                                   
317   gchar buffer[1024];
318   guint i, param;
319   const gchar **arg_names;
320   gint param_num, widget_num, event_num, callback_num;
321   gint *arg_num;
322   gchar signal_name[128];
323   gchar flags[16];
325   /*  g_print ("Object: %s Signal: %u\\n", object_name, signal_id);*/
327   param_num = 1;
328   widget_num = event_num = callback_num = 0;
330   g_signal_query (signal_id, &query_info);
332   /* Output the signal object type and the argument name. We assume the
333      type is a pointer - I think that is OK. We remove "Gtk" or "Gnome" and
334      convert to lower case for the argument name. */
335   pos = buffer;
336   sprintf (pos, "%s ", object_name);
337   pos += strlen (pos);
339   /* Try to come up with a sensible variable name for the first arg
340    * I chops off 2 know prefixes :/ and makes the name lowercase
341    * It should replace lowercase -> uppercase with '_'
342    * GFileMonitor -> file_monitor
343    * GIOExtensionPoint -> extension_point
344    * GtkTreeView -> tree_view
345    * if 2nd char is upper case too
346    *   search for first lower case and go back one char
347    * else
348    *   search for next upper case
349    */
350   if (!strncmp (object_name, "Gtk", 3))
351       object_arg = object_name + 3;
352   else if (!strncmp (object_name, "Gnome", 5))
353       object_arg = object_name + 5;
354   else
355       object_arg = object_name;
357   object_arg_lower = g_ascii_strdown (object_arg, -1);
358   sprintf (pos, "*%s\\n", object_arg_lower);
359   pos += strlen (pos);
360   if (!strncmp (object_arg_lower, "widget", 6))
361     widget_num = 2;
362   g_free(object_arg_lower);
364   /* Convert signal name to use underscores rather than dashes '-'. */
365   strncpy (signal_name, query_info.signal_name, 127);
366   signal_name[127] = '\\0';
367   for (i = 0; signal_name[i]; i++)
368     {
369       if (signal_name[i] == '-')
370         signal_name[i] = '_';
371     }
373   /* Output the signal parameters. */
374   arg_names = lookup_signal_arg_names (object_name, signal_name);
376   for (param = 0; param < query_info.n_params; param++)
377     {
378       if (arg_names)
379         {
380           sprintf (pos, "%s\\n", arg_names[param]);
381           pos += strlen (pos);
382         }
383       else
384         {
385           type_name = get_type_name (query_info.param_types[param] & ~G_SIGNAL_TYPE_STATIC_SCOPE, &is_pointer);
387           /* Most arguments to the callback are called "arg1", "arg2", etc.
388              GdkWidgets are called "widget", "widget2", ...
389              GdkEvents are called "event", "event2", ...
390              GtkCallbacks are called "callback", "callback2", ... */
391           if (!strcmp (type_name, "GtkWidget"))
392             {
393               arg_name = "widget";
394               arg_num = &widget_num;
395             }
396           else if (!strcmp (type_name, "GdkEvent"))
397             {
398               type_name = get_gdk_event (signal_name);
399               arg_name = "event";
400               arg_num = &event_num;
401               is_pointer = TRUE;
402             }
403           else if (!strcmp (type_name, "GtkCallback")
404                    || !strcmp (type_name, "GtkCCallback"))
405             {
406               arg_name = "callback";
407               arg_num = &callback_num;
408             }
409           else
410             {
411               arg_name = "arg";
412               arg_num = &param_num;
413             }
414           sprintf (pos, "%s ", type_name);
415           pos += strlen (pos);
417           if (!arg_num || *arg_num == 0)
418             sprintf (pos, "%s%s\\n", is_pointer ? "*" : " ", arg_name);
419           else
420             sprintf (pos, "%s%s%i\\n", is_pointer ? "*" : " ", arg_name,
421                      *arg_num);
422           pos += strlen (pos);
424           if (arg_num)
425             {
426               if (*arg_num == 0)
427                 *arg_num = 2;
428               else
429                 *arg_num += 1;
430             }
431         }
432     }
434   pos = flags;
435   /* We use one-character flags for simplicity. */
436   if (query_info.signal_flags & G_SIGNAL_RUN_FIRST)
437     *pos++ = 'f';
438   if (query_info.signal_flags & G_SIGNAL_RUN_LAST)
439     *pos++ = 'l';
440   if (query_info.signal_flags & G_SIGNAL_RUN_CLEANUP)
441     *pos++ = 'c';
442   if (query_info.signal_flags & G_SIGNAL_NO_RECURSE)
443     *pos++ = 'r';
444   if (query_info.signal_flags & G_SIGNAL_DETAILED)
445     *pos++ = 'd';
446   if (query_info.signal_flags & G_SIGNAL_ACTION)
447     *pos++ = 'a';
448   if (query_info.signal_flags & G_SIGNAL_NO_HOOKS)
449     *pos++ = 'h';
450   *pos = 0;
452   /* Output the return type and function name. */
453   ret_type = get_type_name (query_info.return_type & ~G_SIGNAL_TYPE_STATIC_SCOPE, &is_pointer);
455   fprintf (fp,
456            "<SIGNAL>\\n<NAME>%s::%s</NAME>\\n<RETURNS>%s%s</RETURNS>\\n<FLAGS>%s</FLAGS>\\n%s</SIGNAL>\\n\\n",
457            object_name, query_info.signal_name, ret_type, is_pointer ? "*" : "", flags, buffer);
461 /* Returns the type name to use for a signal argument or return value, given
462    the GtkType from the signal info. It also sets is_pointer to TRUE if the
463    argument needs a '*' since it is a pointer. */
464 static const gchar *
465 get_type_name (GType type, gboolean * is_pointer)
467   const gchar *type_name;
469   *is_pointer = FALSE;
470   type_name = g_type_name (type);
472   switch (type) {
473   case G_TYPE_NONE:
474   case G_TYPE_CHAR:
475   case G_TYPE_UCHAR:
476   case G_TYPE_BOOLEAN:
477   case G_TYPE_INT:
478   case G_TYPE_UINT:
479   case G_TYPE_LONG:
480   case G_TYPE_ULONG:
481   case G_TYPE_FLOAT:
482   case G_TYPE_DOUBLE:
483   case G_TYPE_POINTER:
484     /* These all have normal C type names so they are OK. */
485     return type_name;
487   case G_TYPE_STRING:
488     /* A GtkString is really a gchar*. */
489     *is_pointer = TRUE;
490     return "gchar";
492   case G_TYPE_ENUM:
493   case G_TYPE_FLAGS:
494     /* We use a gint for both of these. Hopefully a subtype with a decent
495        name will be registered and used instead, as GTK+ does itself. */
496     return "gint";
498   case G_TYPE_BOXED:
499     /* The boxed type shouldn't be used itself, only subtypes. Though we
500        return 'gpointer' just in case. */
501     return "gpointer";
503   case G_TYPE_PARAM:
504     /* A GParam is really a GParamSpec*. */
505     *is_pointer = TRUE;
506     return "GParamSpec";
508   default:
509     break;
510   }
512   /* For all GObject subclasses we can use the class name with a "*",
513      e.g. 'GtkWidget *'. */
514   if (g_type_is_a (type, G_TYPE_OBJECT))
515     *is_pointer = TRUE;
516   
517   /* Also catch non GObject root types */
518   if (G_TYPE_IS_CLASSED (type))
519     *is_pointer = TRUE;
520   
521   /* All boxed subtypes will be pointers as well. */
522   if (g_type_is_a (type, G_TYPE_BOXED))
523     *is_pointer = TRUE;
525   /* All pointer subtypes will be pointers as well. */
526   if (g_type_is_a (type, G_TYPE_POINTER))
527     *is_pointer = TRUE;
529   /* But enums are not */
530   if (g_type_is_a (type, G_TYPE_ENUM) ||
531       g_type_is_a (type, G_TYPE_FLAGS))
532     *is_pointer = FALSE;
534   return type_name;
538 static const gchar *
539 get_gdk_event (const gchar * signal_name)
541   static const gchar *GbGDKEvents[] =
542   {
543     "button_press_event", "GdkEventButton",
544     "button_release_event", "GdkEventButton",
545     "motion_notify_event", "GdkEventMotion",
546     "delete_event", "GdkEvent",
547     "destroy_event", "GdkEvent",
548     "expose_event", "GdkEventExpose",
549     "key_press_event", "GdkEventKey",
550     "key_release_event", "GdkEventKey",
551     "enter_notify_event", "GdkEventCrossing",
552     "leave_notify_event", "GdkEventCrossing",
553     "configure_event", "GdkEventConfigure",
554     "focus_in_event", "GdkEventFocus",
555     "focus_out_event", "GdkEventFocus",
556     "map_event", "GdkEvent",
557     "unmap_event", "GdkEvent",
558     "property_notify_event", "GdkEventProperty",
559     "selection_clear_event", "GdkEventSelection",
560     "selection_request_event", "GdkEventSelection",
561     "selection_notify_event", "GdkEventSelection",
562     "proximity_in_event", "GdkEventProximity",
563     "proximity_out_event", "GdkEventProximity",
564     "drag_begin_event", "GdkEventDragBegin",
565     "drag_request_event", "GdkEventDragRequest",
566     "drag_end_event", "GdkEventDragRequest",
567     "drop_enter_event", "GdkEventDropEnter",
568     "drop_leave_event", "GdkEventDropLeave",
569     "drop_data_available_event", "GdkEventDropDataAvailable",
570     "other_event", "GdkEventOther",
571     "client_event", "GdkEventClient",
572     "no_expose_event", "GdkEventNoExpose",
573     "visibility_notify_event", "GdkEventVisibility",
574     "window_state_event", "GdkEventWindowState",
575     "scroll_event", "GdkEventScroll",
576     NULL
577   };
579   gint i;
581   for (i = 0; GbGDKEvents[i]; i += 2)
582     {
583       if (!strcmp (signal_name, GbGDKEvents[i]))
584         return GbGDKEvents[i + 1];
585     }
586   return "GdkEvent";
590 /* This returns argument names to use for some known GTK signals.
591     It is passed a widget name, e.g. 'GtkCList' and a signal name, e.g.
592     'select_row' and it returns a pointer to an array of argument types and
593     names. */
594 static const gchar **
595 lookup_signal_arg_names (const gchar * type, const gchar * signal_name)
597   /* Each arg array starts with the object type name and the signal name,
598      and then signal arguments follow. */
599   static const gchar *GbArgTable[][16] =
600   {
601     {"GtkCList", "select_row",
602      "gint             row",
603      "gint             column",
604      "GdkEventButton  *event"},
605     {"GtkCList", "unselect_row",
606      "gint             row",
607      "gint             column",
608      "GdkEventButton  *event"},
609     {"GtkCList", "click_column",
610      "gint             column"},
612     {"GtkCList", "resize_column",
613      "gint             column",
614      "gint             width"},
616     {"GtkCList", "extend_selection",
617      "GtkScrollType    scroll_type",
618      "gfloat           position",
619      "gboolean         auto_start_selection"},
620     {"GtkCList", "scroll_vertical",
621      "GtkScrollType    scroll_type",
622      "gfloat           position"},
623     {"GtkCList", "scroll_horizontal",
624      "GtkScrollType    scroll_type",
625      "gfloat           position"},
627     {"GtkCTree", "tree_select_row",
628      "GtkCTreeNode    *node",
629      "gint             column"},
630     {"GtkCTree", "tree_unselect_row",
631      "GtkCTreeNode    *node",
632      "gint             column"},
633     {"GtkCTree", "tree_expand",
634      "GtkCTreeNode    *node"},
635     {"GtkCTree", "tree_collapse",
636      "GtkCTreeNode    *node"},
637     {"GtkCTree", "tree_move",
638      "GtkCTreeNode    *node",
639      "GtkCTreeNode    *new_parent",
640      "GtkCTreeNode    *new_sibling"},
641     {"GtkCTree", "change_focus_row_expansion",
642      "GtkCTreeExpansionType expansion"},
644     {"GtkEditable", "insert_text",
645      "gchar           *new_text",
646      "gint             new_text_length",
647      "gint            *position"},
648     {"GtkEditable", "delete_text",
649      "gint             start_pos",
650      "gint             end_pos"},
651     {"GtkEditable", "set_editable",
652      "gboolean         is_editable"},
653     {"GtkEditable", "move_cursor",
654      "gint             x",
655      "gint             y"},
656     {"GtkEditable", "move_word",
657      "gint             num_words"},
658     {"GtkEditable", "move_page",
659      "gint             x",
660      "gint             y"},
661     {"GtkEditable", "move_to_row",
662      "gint             row"},
663     {"GtkEditable", "move_to_column",
664      "gint             column"},
666     {"GtkEditable", "kill_char",
667      "gint             direction"},
668     {"GtkEditable", "kill_word",
669      "gint             direction"},
670     {"GtkEditable", "kill_line",
671      "gint             direction"},
674     {"GtkInputDialog", "enable_device",
675      "GdkDevice       *deviceid"},
676     {"GtkInputDialog", "disable_device",
677      "GdkDevice       *deviceid"},
679     {"GtkListItem", "extend_selection",
680      "GtkScrollType    scroll_type",
681      "gfloat           position",
682      "gboolean         auto_start_selection"},
683     {"GtkListItem", "scroll_vertical",
684      "GtkScrollType    scroll_type",
685      "gfloat           position"},
686     {"GtkListItem", "scroll_horizontal",
687      "GtkScrollType    scroll_type",
688      "gfloat           position"},
690     {"GtkMenuShell", "move_current",
691      "GtkMenuDirectionType direction"},
692     {"GtkMenuShell", "activate_current",
693      "gboolean         force_hide"},
696     {"GtkNotebook", "switch_page",
697      "GtkNotebookPage *page",
698      "guint            page_num"},
699     {"GtkStatusbar", "text_pushed",
700      "guint            context_id",
701      "gchar           *text"},
702     {"GtkStatusbar", "text_popped",
703      "guint            context_id",
704      "gchar           *text"},
705     {"GtkTipsQuery", "widget_entered",
706      "GtkWidget       *widget",
707      "gchar           *tip_text",
708      "gchar           *tip_private"},
709     {"GtkTipsQuery", "widget_selected",
710      "GtkWidget       *widget",
711      "gchar           *tip_text",
712      "gchar           *tip_private",
713      "GdkEventButton  *event"},
714     {"GtkToolbar", "orientation_changed",
715      "GtkOrientation   orientation"},
716     {"GtkToolbar", "style_changed",
717      "GtkToolbarStyle  style"},
718     {"GtkWidget", "draw",
719      "GdkRectangle    *area"},
720     {"GtkWidget", "size_request",
721      "GtkRequisition  *requisition"},
722     {"GtkWidget", "size_allocate",
723      "GtkAllocation   *allocation"},
724     {"GtkWidget", "state_changed",
725      "GtkStateType     state"},
726     {"GtkWidget", "style_set",
727      "GtkStyle        *previous_style"},
729     {"GtkWidget", "install_accelerator",
730      "gchar           *signal_name",
731      "gchar            key",
732      "gint             modifiers"},
734     {"GtkWidget", "add_accelerator",
735      "guint            accel_signal_id",
736      "GtkAccelGroup   *accel_group",
737      "guint            accel_key",
738      "GdkModifierType  accel_mods",
739      "GtkAccelFlags    accel_flags"},
741     {"GtkWidget", "parent_set",
742      "GtkObject       *old_parent"},
744     {"GtkWidget", "remove_accelerator",
745      "GtkAccelGroup   *accel_group",
746      "guint            accel_key",
747      "GdkModifierType  accel_mods"},
748     {"GtkWidget", "debug_msg",
749      "gchar           *message"},
750     {"GtkWindow", "move_resize",
751      "gint            *x",
752      "gint            *y",
753      "gint             width",
754      "gint             height"},
755     {"GtkWindow", "set_focus",
756      "GtkWidget       *widget"},
758     {"GtkWidget", "selection_get",
759      "GtkSelectionData *data",
760      "guint            info",
761      "guint            time"},
762     {"GtkWidget", "selection_received",
763      "GtkSelectionData *data",
764      "guint            time"},
766     {"GtkWidget", "drag_begin",
767      "GdkDragContext  *drag_context"},
768     {"GtkWidget", "drag_end",
769      "GdkDragContext  *drag_context"},
770     {"GtkWidget", "drag_data_delete",
771      "GdkDragContext  *drag_context"},
772     {"GtkWidget", "drag_leave",
773      "GdkDragContext  *drag_context",
774      "guint            time"},
775     {"GtkWidget", "drag_motion",
776      "GdkDragContext  *drag_context",
777      "gint             x",
778      "gint             y",
779      "guint            time"},
780     {"GtkWidget", "drag_drop",
781      "GdkDragContext  *drag_context",
782      "gint             x",
783      "gint             y",
784      "guint            time"},
785     {"GtkWidget", "drag_data_get",
786      "GdkDragContext  *drag_context",
787      "GtkSelectionData *data",
788      "guint            info",
789      "guint            time"},
790     {"GtkWidget", "drag_data_received",
791      "GdkDragContext  *drag_context",
792      "gint             x",
793      "gint             y",
794      "GtkSelectionData *data",
795      "guint            info",
796      "guint            time"},
798     {NULL}
799   };
801   gint i;
803   for (i = 0; GbArgTable[i][0]; i++)
804     {
805 #if 1
806       if (!strcmp (type, GbArgTable[i][0])
807           && !strcmp (signal_name, GbArgTable[i][1]))
808         return &GbArgTable[i][2];
809 #endif
810     }
811   return NULL;
814 /* This outputs the hierarchy of all objects which have been initialized,
815    i.e. by calling their XXX_get_type() initialization function. */
816 static void
817 output_object_hierarchy (void)
819   FILE *fp;
820   gint i;
822   fp = fopen (hierarchy_filename, "w");
823   if (fp == NULL)
824     {
825       g_warning ("Couldn't open output file: %s : %s", hierarchy_filename, g_strerror(errno));
826       return;
827     }
828   output_hierarchy (fp, G_TYPE_OBJECT, 0);
829   output_hierarchy (fp, G_TYPE_INTERFACE, 0);
830   
831   for (i=0; object_types[i]; i++) {
832     if (!g_type_parent (object_types[i]) &&
833       (object_types[i] != G_TYPE_OBJECT) &&
834       (object_types[i] != G_TYPE_INTERFACE)
835     ) {
836       output_hierarchy (fp, object_types[i], 0);
837     }
838   }
840   fclose (fp);
843 /* This is called recursively to output the hierarchy of a widget. */
844 static void
845 output_hierarchy (FILE  *fp,
846                   GType  type,
847                   guint   level)
849   guint i;
850   GType *children;
851   guint n_children;
853   if (!type)
854     return;
856   for (i = 0; i < level; i++)
857     fprintf (fp, "  ");
858   fprintf (fp, "%s\\n", g_type_name (type));
859   
860   children = g_type_children (type, &n_children);
862   for (i=0; i < n_children; i++)
863     output_hierarchy (fp, children[i], level + 1);
865   g_free (children);
868 static void output_object_interfaces (void)
870   guint i;
871   FILE *fp;
873   fp = fopen (interfaces_filename, "w");
874   if (fp == NULL)
875     {
876       g_warning ("Couldn't open output file: %s : %s", interfaces_filename, g_strerror(errno));
877       return;
878     }
879   output_interfaces (fp, G_TYPE_OBJECT);
881   for (i = 0; object_types[i]; i++)
882     {
883       if (!g_type_parent (object_types[i]) &&
884           (object_types[i] != G_TYPE_OBJECT) &&
885           G_TYPE_IS_INSTANTIATABLE (object_types[i]))
886         {
887           output_interfaces (fp, object_types[i]);
888         }
889     }
890   fclose (fp);
893 static void
894 output_interfaces (FILE  *fp,
895                    GType  type)
897   guint i;
898   GType *children, *interfaces;
899   guint n_children, n_interfaces;
901   if (!type)
902     return;
904   interfaces = g_type_interfaces (type, &n_interfaces);
906   if (n_interfaces > 0)
907     {
908       fprintf (fp, "%s", g_type_name (type));
909       for (i=0; i < n_interfaces; i++)
910           fprintf (fp, " %s", g_type_name (interfaces[i]));
911       fprintf (fp, "\\n");
912      }
913   g_free (interfaces);
915   children = g_type_children (type, &n_children);
917   for (i=0; i < n_children; i++)
918     output_interfaces (fp, children[i]);
920   g_free (children);
923 static void output_interface_prerequisites (void)
925   FILE *fp;
927   fp = fopen (prerequisites_filename, "w");
928   if (fp == NULL)
929     {
930       g_warning ("Couldn't open output file: %s : %s", prerequisites_filename, g_strerror(errno));
931       return;
932     }
933   output_prerequisites (fp, G_TYPE_INTERFACE);
934   fclose (fp);
937 static void
938 output_prerequisites (FILE  *fp,
939                       GType  type)
941 #if GLIB_CHECK_VERSION(2,1,0)
942   guint i;
943   GType *children, *prerequisites;
944   guint n_children, n_prerequisites;
946   if (!type)
947     return;
949   prerequisites = g_type_interface_prerequisites (type, &n_prerequisites);
951   if (n_prerequisites > 0)
952     {
953       fprintf (fp, "%s", g_type_name (type));
954       for (i=0; i < n_prerequisites; i++)
955           fprintf (fp, " %s", g_type_name (prerequisites[i]));
956       fprintf (fp, "\\n");
957      }
958   g_free (prerequisites);
960   children = g_type_children (type, &n_children);
962   for (i=0; i < n_children; i++)
963     output_prerequisites (fp, children[i]);
965   g_free (children);
966 #endif
969 static void
970 output_args (void)
972   FILE *fp;
973   gint i;
975   fp = fopen (args_filename, "w");
976   if (fp == NULL)
977     {
978       g_warning ("Couldn't open output file: %s : %s", args_filename, g_strerror(errno));
979       return;
980     }
982   for (i = 0; object_types[i]; i++) {
983     output_object_args (fp, object_types[i]);
984   }
986   fclose (fp);
989 static gint
990 compare_param_specs (const void *a, const void *b)
992   GParamSpec *spec_a = *(GParamSpec **)a;
993   GParamSpec *spec_b = *(GParamSpec **)b;
995   return strcmp (g_param_spec_get_name (spec_a), g_param_spec_get_name (spec_b));
998 /* Its common to have unsigned properties restricted
999  * to the signed range. Therefore we make this look
1000  * a bit nicer by spelling out the max constants.
1001  */
1003 /* Don't use "==" with floats, it might trigger a gcc warning.  */
1004 #define GTKDOC_COMPARE_FLOAT(x, y) (x <= y && x >= y)
1006 static gchar*
1007 describe_double_constant (gdouble value)
1009   gchar *desc;
1011   if (GTKDOC_COMPARE_FLOAT (value, G_MAXDOUBLE))
1012     desc = g_strdup ("G_MAXDOUBLE");
1013   else if (GTKDOC_COMPARE_FLOAT (value, G_MINDOUBLE))
1014     desc = g_strdup ("G_MINDOUBLE");
1015   else if (GTKDOC_COMPARE_FLOAT (value, -G_MAXDOUBLE))
1016     desc = g_strdup ("-G_MAXDOUBLE");
1017   else if (GTKDOC_COMPARE_FLOAT (value, G_MAXFLOAT))
1018     desc = g_strdup ("G_MAXFLOAT");
1019   else if (GTKDOC_COMPARE_FLOAT (value, G_MINFLOAT))
1020     desc = g_strdup ("G_MINFLOAT");
1021   else if (GTKDOC_COMPARE_FLOAT (value, -G_MAXFLOAT))
1022     desc = g_strdup ("-G_MAXFLOAT");
1023   else
1024     desc = g_strdup_printf ("%lg", value);
1026   return desc;
1029 static gchar*
1030 describe_signed_constant (gsize size, gint64 value)
1032   gchar *desc = NULL;
1034   switch (size) {
1035     case 2:
1036       if (sizeof (int) == 2) {
1037         if (value == G_MAXINT)
1038           desc = g_strdup ("G_MAXINT");
1039         else if (value == G_MININT)
1040           desc = g_strdup ("G_MININT");
1041         else if (value == (gint64)G_MAXUINT)
1042           desc = g_strdup ("G_MAXUINT");
1043       }
1044       break;
1045     case 4:
1046       if (sizeof (int) == 4) {
1047         if (value == G_MAXINT)
1048           desc = g_strdup ("G_MAXINT");
1049         else if (value == G_MININT)
1050           desc = g_strdup ("G_MININT");
1051         else if (value == (gint64)G_MAXUINT)
1052           desc = g_strdup ("G_MAXUINT");
1053       }
1054       if (value == G_MAXLONG)
1055         desc = g_strdup ("G_MAXLONG");
1056       else if (value == G_MINLONG)
1057         desc = g_strdup ("G_MINLONG");
1058       else if (value == (gint64)G_MAXULONG)
1059         desc = g_strdup ("G_MAXULONG");
1060       break;
1061     case 8:
1062       if (value == G_MAXINT64)
1063         desc = g_strdup ("G_MAXINT64");
1064       else if (value == G_MININT64)
1065         desc = g_strdup ("G_MININT64");
1066       break;
1067     default:
1068       break;
1069   }
1070   if (!desc)
1071     desc = g_strdup_printf ("%" G_GINT64_FORMAT, value);
1073   return desc;
1076 static gchar*
1077 describe_unsigned_constant (gsize size, guint64 value)
1079   gchar *desc = NULL;
1081   switch (size) {
1082     case 2:
1083       if (sizeof (int) == 2) {
1084         if (value == (guint64)G_MAXINT)
1085           desc = g_strdup ("G_MAXINT");
1086         else if (value == G_MAXUINT)
1087           desc = g_strdup ("G_MAXUINT");
1088       }
1089       break;
1090     case 4:
1091       if (sizeof (int) == 4) {
1092         if (value == (guint64)G_MAXINT)
1093           desc = g_strdup ("G_MAXINT");
1094         else if (value == G_MAXUINT)
1095           desc = g_strdup ("G_MAXUINT");
1096       }
1097       if (value == (guint64)G_MAXLONG)
1098         desc = g_strdup ("G_MAXLONG");
1099       else if (value == G_MAXULONG)
1100         desc = g_strdup ("G_MAXULONG");
1101       break;
1102     case 8:
1103       if (value == G_MAXINT64)
1104         desc = g_strdup ("G_MAXINT64");
1105       else if (value == G_MAXUINT64)
1106         desc = g_strdup ("G_MAXUINT64");
1107       break;
1108     default:
1109       break;
1110   }
1111   if (!desc)
1112     desc = g_strdup_printf ("%" G_GUINT64_FORMAT, value);
1114   return desc;
1117 static gchar*
1118 describe_type (GParamSpec *spec)
1120   gchar *desc;
1121   gchar *lower;
1122   gchar *upper;
1124   if (G_IS_PARAM_SPEC_CHAR (spec))
1125     {
1126       GParamSpecChar *pspec = G_PARAM_SPEC_CHAR (spec);
1128       lower = describe_signed_constant (sizeof(gchar), pspec->minimum);
1129       upper = describe_signed_constant (sizeof(gchar), pspec->maximum);
1130       if (pspec->minimum == G_MININT8 && pspec->maximum == G_MAXINT8)
1131         desc = g_strdup ("");
1132       else if (pspec->minimum == G_MININT8)
1133         desc = g_strdup_printf ("<= %s", upper);
1134       else if (pspec->maximum == G_MAXINT8)
1135         desc = g_strdup_printf (">= %s", lower);
1136       else
1137         desc = g_strdup_printf ("[%s,%s]", lower, upper);
1138       g_free (lower);
1139       g_free (upper);
1140     }
1141   else if (G_IS_PARAM_SPEC_UCHAR (spec))
1142     {
1143       GParamSpecUChar *pspec = G_PARAM_SPEC_UCHAR (spec);
1145       lower = describe_unsigned_constant (sizeof(guchar), pspec->minimum);
1146       upper = describe_unsigned_constant (sizeof(guchar), pspec->maximum);
1147       if (pspec->minimum == 0 && pspec->maximum == G_MAXUINT8)
1148         desc = g_strdup ("");
1149       else if (pspec->minimum == 0)
1150         desc = g_strdup_printf ("<= %s", upper);
1151       else if (pspec->maximum == G_MAXUINT8)
1152         desc = g_strdup_printf (">= %s", lower);
1153       else
1154         desc = g_strdup_printf ("[%s,%s]", lower, upper);
1155       g_free (lower);
1156       g_free (upper);
1157     }
1158   else if (G_IS_PARAM_SPEC_INT (spec))
1159     {
1160       GParamSpecInt *pspec = G_PARAM_SPEC_INT (spec);
1162       lower = describe_signed_constant (sizeof(gint), pspec->minimum);
1163       upper = describe_signed_constant (sizeof(gint), pspec->maximum);
1164       if (pspec->minimum == G_MININT && pspec->maximum == G_MAXINT)
1165         desc = g_strdup ("");
1166       else if (pspec->minimum == G_MININT)
1167         desc = g_strdup_printf ("<= %s", upper);
1168       else if (pspec->maximum == G_MAXINT)
1169         desc = g_strdup_printf (">= %s", lower);
1170       else
1171         desc = g_strdup_printf ("[%s,%s]", lower, upper);
1172       g_free (lower);
1173       g_free (upper);
1174     }
1175   else if (G_IS_PARAM_SPEC_UINT (spec))
1176     {
1177       GParamSpecUInt *pspec = G_PARAM_SPEC_UINT (spec);
1179       lower = describe_unsigned_constant (sizeof(guint), pspec->minimum);
1180       upper = describe_unsigned_constant (sizeof(guint), pspec->maximum);
1181       if (pspec->minimum == 0 && pspec->maximum == G_MAXUINT)
1182         desc = g_strdup ("");
1183       else if (pspec->minimum == 0)
1184         desc = g_strdup_printf ("<= %s", upper);
1185       else if (pspec->maximum == G_MAXUINT)
1186         desc = g_strdup_printf (">= %s", lower);
1187       else
1188         desc = g_strdup_printf ("[%s,%s]", lower, upper);
1189       g_free (lower);
1190       g_free (upper);
1191     }
1192   else if (G_IS_PARAM_SPEC_LONG (spec))
1193     {
1194       GParamSpecLong *pspec = G_PARAM_SPEC_LONG (spec);
1196       lower = describe_signed_constant (sizeof(glong), pspec->minimum);
1197       upper = describe_signed_constant (sizeof(glong), pspec->maximum);
1198       if (pspec->minimum == G_MINLONG && pspec->maximum == G_MAXLONG)
1199         desc = g_strdup ("");
1200       else if (pspec->minimum == G_MINLONG)
1201         desc = g_strdup_printf ("<= %s", upper);
1202       else if (pspec->maximum == G_MAXLONG)
1203         desc = g_strdup_printf (">= %s", lower);
1204       else
1205         desc = g_strdup_printf ("[%s,%s]", lower, upper);
1206       g_free (lower);
1207       g_free (upper);
1208     }
1209   else if (G_IS_PARAM_SPEC_ULONG (spec))
1210     {
1211       GParamSpecULong *pspec = G_PARAM_SPEC_ULONG (spec);
1213       lower = describe_unsigned_constant (sizeof(gulong), pspec->minimum);
1214       upper = describe_unsigned_constant (sizeof(gulong), pspec->maximum);
1215       if (pspec->minimum == 0 && pspec->maximum == G_MAXULONG)
1216         desc = g_strdup ("");
1217       else if (pspec->minimum == 0)
1218         desc = g_strdup_printf ("<= %s", upper);
1219       else if (pspec->maximum == G_MAXULONG)
1220         desc = g_strdup_printf (">= %s", lower);
1221       else
1222         desc = g_strdup_printf ("[%s,%s]", lower, upper);
1223       g_free (lower);
1224       g_free (upper);
1225     }
1226   else if (G_IS_PARAM_SPEC_INT64 (spec))
1227     {
1228       GParamSpecInt64 *pspec = G_PARAM_SPEC_INT64 (spec);
1230       lower = describe_signed_constant (sizeof(gint64), pspec->minimum);
1231       upper = describe_signed_constant (sizeof(gint64), pspec->maximum);
1232       if (pspec->minimum == G_MININT64 && pspec->maximum == G_MAXINT64)
1233         desc = g_strdup ("");
1234       else if (pspec->minimum == G_MININT64)
1235         desc = g_strdup_printf ("<= %s", upper);
1236       else if (pspec->maximum == G_MAXINT64)
1237         desc = g_strdup_printf (">= %s", lower);
1238       else
1239         desc = g_strdup_printf ("[%s,%s]", lower, upper);
1240       g_free (lower);
1241       g_free (upper);
1242     }
1243   else if (G_IS_PARAM_SPEC_UINT64 (spec))
1244     {
1245       GParamSpecUInt64 *pspec = G_PARAM_SPEC_UINT64 (spec);
1247       lower = describe_unsigned_constant (sizeof(guint64), pspec->minimum);
1248       upper = describe_unsigned_constant (sizeof(guint64), pspec->maximum);
1249       if (pspec->minimum == 0 && pspec->maximum == G_MAXUINT64)
1250         desc = g_strdup ("");
1251       else if (pspec->minimum == 0)
1252         desc = g_strdup_printf ("<= %s", upper);
1253       else if (pspec->maximum == G_MAXUINT64)
1254         desc = g_strdup_printf (">= %s", lower);
1255       else
1256         desc = g_strdup_printf ("[%s,%s]", lower, upper);
1257       g_free (lower);
1258       g_free (upper);
1259     }
1260   else if (G_IS_PARAM_SPEC_FLOAT (spec))
1261     {
1262       GParamSpecFloat *pspec = G_PARAM_SPEC_FLOAT (spec);
1264       lower = describe_double_constant (pspec->minimum);
1265       upper = describe_double_constant (pspec->maximum);
1266       if (GTKDOC_COMPARE_FLOAT (pspec->minimum, -G_MAXFLOAT))
1267         {
1268           if (GTKDOC_COMPARE_FLOAT (pspec->maximum, G_MAXFLOAT))
1269             desc = g_strdup ("");
1270           else
1271             desc = g_strdup_printf ("<= %s", upper);
1272         }
1273       else if (GTKDOC_COMPARE_FLOAT (pspec->maximum, G_MAXFLOAT))
1274         desc = g_strdup_printf (">= %s", lower);
1275       else
1276         desc = g_strdup_printf ("[%s,%s]", lower, upper);
1277       g_free (lower);
1278       g_free (upper);
1279     }
1280   else if (G_IS_PARAM_SPEC_DOUBLE (spec))
1281     {
1282       GParamSpecDouble *pspec = G_PARAM_SPEC_DOUBLE (spec);
1284       lower = describe_double_constant (pspec->minimum);
1285       upper = describe_double_constant (pspec->maximum);
1286       if (GTKDOC_COMPARE_FLOAT (pspec->minimum, -G_MAXDOUBLE))
1287         {
1288           if (GTKDOC_COMPARE_FLOAT (pspec->maximum, G_MAXDOUBLE))
1289             desc = g_strdup ("");
1290           else
1291             desc = g_strdup_printf ("<= %s", upper);
1292         }
1293       else if (GTKDOC_COMPARE_FLOAT (pspec->maximum, G_MAXDOUBLE))
1294         desc = g_strdup_printf (">= %s", lower);
1295       else
1296         desc = g_strdup_printf ("[%s,%s]", lower, upper);
1297       g_free (lower);
1298       g_free (upper);
1299     }
1300   else
1301     {
1302       desc = g_strdup ("");
1303     }
1305   return desc;
1308 static gchar*
1309 describe_default (GParamSpec *spec)
1311   gchar *desc;
1313   if (G_IS_PARAM_SPEC_CHAR (spec))
1314     {
1315       GParamSpecChar *pspec = G_PARAM_SPEC_CHAR (spec);
1317       desc = g_strdup_printf ("%d", pspec->default_value);
1318     }
1319   else if (G_IS_PARAM_SPEC_UCHAR (spec))
1320     {
1321       GParamSpecUChar *pspec = G_PARAM_SPEC_UCHAR (spec);
1323       desc = g_strdup_printf ("%u", pspec->default_value);
1324     }
1325   else if (G_IS_PARAM_SPEC_BOOLEAN (spec))
1326     {
1327       GParamSpecBoolean *pspec = G_PARAM_SPEC_BOOLEAN (spec);
1329       desc = g_strdup_printf ("%s", pspec->default_value ? "TRUE" : "FALSE");
1330     }
1331   else if (G_IS_PARAM_SPEC_INT (spec))
1332     {
1333       GParamSpecInt *pspec = G_PARAM_SPEC_INT (spec);
1335       desc = g_strdup_printf ("%d", pspec->default_value);
1336     }
1337   else if (G_IS_PARAM_SPEC_UINT (spec))
1338     {
1339       GParamSpecUInt *pspec = G_PARAM_SPEC_UINT (spec);
1341       desc = g_strdup_printf ("%u", pspec->default_value);
1342     }
1343   else if (G_IS_PARAM_SPEC_LONG (spec))
1344     {
1345       GParamSpecLong *pspec = G_PARAM_SPEC_LONG (spec);
1347       desc = g_strdup_printf ("%ld", pspec->default_value);
1348     }
1349   else if (G_IS_PARAM_SPEC_LONG (spec))
1350     {
1351       GParamSpecULong *pspec = G_PARAM_SPEC_ULONG (spec);
1353       desc = g_strdup_printf ("%lu", pspec->default_value);
1354     }
1355   else if (G_IS_PARAM_SPEC_INT64 (spec))
1356     {
1357       GParamSpecInt64 *pspec = G_PARAM_SPEC_INT64 (spec);
1359       desc = g_strdup_printf ("%" G_GINT64_FORMAT, pspec->default_value);
1360     }
1361   else if (G_IS_PARAM_SPEC_UINT64 (spec))
1362     {
1363       GParamSpecUInt64 *pspec = G_PARAM_SPEC_UINT64 (spec);
1365       desc = g_strdup_printf ("%" G_GUINT64_FORMAT, pspec->default_value);
1366     }
1367   else if (G_IS_PARAM_SPEC_UNICHAR (spec))
1368     {
1369       GParamSpecUnichar *pspec = G_PARAM_SPEC_UNICHAR (spec);
1371       if (g_unichar_isprint (pspec->default_value))
1372         desc = g_strdup_printf ("'%c'", pspec->default_value);
1373       else
1374         desc = g_strdup_printf ("%u", pspec->default_value);
1375     }
1376   else if (G_IS_PARAM_SPEC_ENUM (spec))
1377     {
1378       GParamSpecEnum *pspec = G_PARAM_SPEC_ENUM (spec);
1380       GEnumValue *value = g_enum_get_value (pspec->enum_class, pspec->default_value);
1381       if (value)
1382         desc = g_strdup_printf ("%s", value->value_name);
1383       else
1384         desc = g_strdup_printf ("%d", pspec->default_value);
1385     }
1386   else if (G_IS_PARAM_SPEC_FLAGS (spec))
1387     {
1388       GParamSpecFlags *pspec = G_PARAM_SPEC_FLAGS (spec);
1389       guint default_value;
1390       GString *acc;
1392       default_value = pspec->default_value;
1393       acc = g_string_new ("");
1395       while (default_value)
1396         {
1397           GFlagsValue *value = g_flags_get_first_value (pspec->flags_class, default_value);
1399           if (!value)
1400             break;
1402           if (acc->len > 0)
1403             g_string_append (acc, "|");
1404           g_string_append (acc, value->value_name);
1406           default_value &= ~value->value;
1407         }
1409       if (default_value == 0)
1410         desc = g_string_free (acc, FALSE);
1411       else
1412         {
1413           desc = g_strdup_printf ("%d", pspec->default_value);
1414           g_string_free (acc, TRUE);
1415         }
1416     }
1417   else if (G_IS_PARAM_SPEC_FLOAT (spec))
1418     {
1419       GParamSpecFloat *pspec = G_PARAM_SPEC_FLOAT (spec);
1421       desc = g_strdup_printf ("%g", pspec->default_value);
1422     }
1423   else if (G_IS_PARAM_SPEC_DOUBLE (spec))
1424     {
1425       GParamSpecDouble *pspec = G_PARAM_SPEC_DOUBLE (spec);
1427       desc = g_strdup_printf ("%lg", pspec->default_value);
1428     }
1429   else if (G_IS_PARAM_SPEC_STRING (spec))
1430     {
1431       GParamSpecString *pspec = G_PARAM_SPEC_STRING (spec);
1433       if (pspec->default_value)
1434         {
1435           gchar *esc = g_strescape (pspec->default_value, NULL);
1437           desc = g_strdup_printf ("\\"%s\\"", esc);
1439           g_free (esc);
1440         }
1441       else
1442         desc = g_strdup_printf ("NULL");
1443     }
1444   else
1445     {
1446       desc = g_strdup ("");
1447     }
1449   return desc;
1453 static void
1454 output_object_args (FILE *fp, GType object_type)
1456   gpointer class;
1457   const gchar *object_class_name;
1458   guint arg;
1459   gchar flags[16], *pos;
1460   GParamSpec **properties;
1461   guint n_properties;
1462   gboolean child_prop;
1463   gboolean style_prop;
1464   gboolean is_pointer;
1465   const gchar *type_name;
1466   gchar *type_desc;
1467   gchar *default_value;
1469   if (G_TYPE_IS_OBJECT (object_type))
1470     {
1471       class = g_type_class_peek (object_type);
1472       if (!class)
1473         return;
1475       properties = g_object_class_list_properties (class, &n_properties);
1476     }
1477 #if GLIB_MAJOR_VERSION > 2 || (GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION >= 3)
1478   else if (G_TYPE_IS_INTERFACE (object_type))
1479     {
1480       class = g_type_default_interface_ref (object_type);
1482       if (!class)
1483         return;
1485       properties = g_object_interface_list_properties (class, &n_properties);
1486     }
1487 #endif
1488   else
1489     return;
1491   object_class_name = g_type_name (object_type);
1493   child_prop = FALSE;
1494   style_prop = FALSE;
1496   while (TRUE) {
1497     qsort (properties, n_properties, sizeof (GParamSpec *), compare_param_specs);
1498     for (arg = 0; arg < n_properties; arg++)
1499       {
1500         GParamSpec *spec = properties[arg];
1501         const gchar *nick, *blurb, *dot;
1503         if (spec->owner_type != object_type)
1504           continue;
1506         pos = flags;
1507         /* We use one-character flags for simplicity. */
1508         if (child_prop && !style_prop)
1509           *pos++ = 'c';
1510         if (style_prop)
1511           *pos++ = 's';
1512         if (spec->flags & G_PARAM_READABLE)
1513           *pos++ = 'r';
1514         if (spec->flags & G_PARAM_WRITABLE)
1515           *pos++ = 'w';
1516         if (spec->flags & G_PARAM_CONSTRUCT)
1517           *pos++ = 'x';
1518         if (spec->flags & G_PARAM_CONSTRUCT_ONLY)
1519           *pos++ = 'X';
1520         *pos = 0;
1522         nick = g_param_spec_get_nick (spec);
1523         blurb = g_param_spec_get_blurb (spec);
1525         dot = "";
1526         if (blurb) {
1527           int str_len = strlen (blurb);
1528           if (str_len > 0  && blurb[str_len - 1] != '.')
1529             dot = ".";
1530         }
1532         type_desc = describe_type (spec);
1533         default_value = describe_default (spec);
1534         type_name = get_type_name (spec->value_type, &is_pointer);
1535         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",
1536                  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);
1537         g_free (type_desc);
1538         g_free (default_value);
1539       }
1541     g_free (properties);
1543 #ifdef GTK_IS_CONTAINER_CLASS
1544     if (!child_prop && GTK_IS_CONTAINER_CLASS (class)) {
1545       properties = gtk_container_class_list_child_properties (class, &n_properties);
1546       child_prop = TRUE;
1547       continue;
1548     }
1549 #endif
1551 #ifdef GTK_IS_WIDGET_CLASS
1552 #if GTK_CHECK_VERSION(2,1,0)
1553     if (!style_prop && GTK_IS_WIDGET_CLASS (class)) {
1554       properties = gtk_widget_class_list_style_properties (GTK_WIDGET_CLASS (class), &n_properties);
1555       style_prop = TRUE;
1556       continue;
1557     }
1558 #endif
1559 #endif
1563 if ($QUERY_CHILD_PROPERTIES) {
1564   print OUTPUT <<EOT;
1565     if (!child_prop) {
1566       properties = $QUERY_CHILD_PROPERTIES (class, &n_properties);
1567       if (properties) {
1568         child_prop = TRUE;
1569         continue;
1570       }
1571    }
1576 print OUTPUT <<EOT;
1577     break;
1578   }
1582 close OUTPUT;
1584 # Compile and run our file
1586 $CC = $ENV{CC} ? $ENV{CC} : "gcc";
1587 $LD = $ENV{LD} ? $ENV{LD} : $CC;
1588 $CFLAGS = $ENV{CFLAGS} ? $ENV{CFLAGS} : "";
1589 $LDFLAGS = $ENV{LDFLAGS} ? $ENV{LDFLAGS} : "";
1590 $RUN = $ENV{RUN} ? $ENV{RUN} : "";
1592 my $o_file;
1593 if ($CC =~ /libtool/) {
1594   $o_file  = "$MODULE-scan.lo"
1595 } else {
1596   $o_file = "$MODULE-scan.o"
1599 print "gtk-doc: Compiling scanner\n";
1600 $command = "$CC $CFLAGS -c -o $o_file $MODULE-scan.c";
1601 system("($command)") == 0 or die "Compilation of scanner failed: $!\n";
1603 print "gtk-doc: Linking scanner\n";
1604 $command = "$LD -o $MODULE-scan $o_file $LDFLAGS";
1605 system("($command)") == 0 or die "Linking of scanner failed: $!\n";
1607 print "gtk-doc: Running scanner $MODULE-scan\n";
1608 system("($RUN ./$MODULE-scan)") == 0 or die "Scan failed: $!\n";
1611 if (!defined($ENV{"GTK_DOC_KEEP_INTERMEDIATE"})) {
1612   unlink "./$MODULE-scan.c", "./$MODULE-scan.o", "./$MODULE-scan.lo", "./$MODULE-scan";
1615 &UpdateFileIfChanged ($old_signals_filename, $new_signals_filename, 0);
1616 &UpdateFileIfChanged ($old_hierarchy_filename, $new_hierarchy_filename, 0);
1617 &UpdateFileIfChanged ($old_interfaces_filename, $new_interfaces_filename, 0);
1618 &UpdateFileIfChanged ($old_prerequisites_filename, $new_prerequisites_filename, 0);
1619 &UpdateFileIfChanged ($old_args_filename, $new_args_filename, 0);