gtkdoc-check: Add a test checking if all XML files are included in main file
[gtk-doc.git] / gtkdoc-scangobj.in
blob1977ed255b8fc2d174d3e47792cb6b8bcccf46a5
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 #if GLIB_CHECK_VERSION (2, 25, 9)
509   case G_TYPE_VARIANT:
510     *is_pointer = TRUE;
511     return "GVariant";
512 #endif
514 default:
515     break;
516   }
518   /* For all GObject subclasses we can use the class name with a "*",
519      e.g. 'GtkWidget *'. */
520   if (g_type_is_a (type, G_TYPE_OBJECT))
521     *is_pointer = TRUE;
522   
523   /* Also catch non GObject root types */
524   if (G_TYPE_IS_CLASSED (type))
525     *is_pointer = TRUE;
526   
527   /* All boxed subtypes will be pointers as well. */
528   /* Exception: GStrv */
529   if (g_type_is_a (type, G_TYPE_BOXED) &&
530       !g_type_is_a (type, G_TYPE_STRV))
531     *is_pointer = TRUE;
533   /* All pointer subtypes will be pointers as well. */
534   if (g_type_is_a (type, G_TYPE_POINTER))
535     *is_pointer = TRUE;
537   /* But enums are not */
538   if (g_type_is_a (type, G_TYPE_ENUM) ||
539       g_type_is_a (type, G_TYPE_FLAGS))
540     *is_pointer = FALSE;
542   return type_name;
546 static const gchar *
547 get_gdk_event (const gchar * signal_name)
549   static const gchar *GbGDKEvents[] =
550   {
551     "button_press_event", "GdkEventButton",
552     "button_release_event", "GdkEventButton",
553     "motion_notify_event", "GdkEventMotion",
554     "delete_event", "GdkEvent",
555     "destroy_event", "GdkEvent",
556     "expose_event", "GdkEventExpose",
557     "key_press_event", "GdkEventKey",
558     "key_release_event", "GdkEventKey",
559     "enter_notify_event", "GdkEventCrossing",
560     "leave_notify_event", "GdkEventCrossing",
561     "configure_event", "GdkEventConfigure",
562     "focus_in_event", "GdkEventFocus",
563     "focus_out_event", "GdkEventFocus",
564     "map_event", "GdkEvent",
565     "unmap_event", "GdkEvent",
566     "property_notify_event", "GdkEventProperty",
567     "selection_clear_event", "GdkEventSelection",
568     "selection_request_event", "GdkEventSelection",
569     "selection_notify_event", "GdkEventSelection",
570     "proximity_in_event", "GdkEventProximity",
571     "proximity_out_event", "GdkEventProximity",
572     "drag_begin_event", "GdkEventDragBegin",
573     "drag_request_event", "GdkEventDragRequest",
574     "drag_end_event", "GdkEventDragRequest",
575     "drop_enter_event", "GdkEventDropEnter",
576     "drop_leave_event", "GdkEventDropLeave",
577     "drop_data_available_event", "GdkEventDropDataAvailable",
578     "other_event", "GdkEventOther",
579     "client_event", "GdkEventClient",
580     "no_expose_event", "GdkEventNoExpose",
581     "visibility_notify_event", "GdkEventVisibility",
582     "window_state_event", "GdkEventWindowState",
583     "scroll_event", "GdkEventScroll",
584     NULL
585   };
587   gint i;
589   for (i = 0; GbGDKEvents[i]; i += 2)
590     {
591       if (!strcmp (signal_name, GbGDKEvents[i]))
592         return GbGDKEvents[i + 1];
593     }
594   return "GdkEvent";
598 /* This returns argument names to use for some known GTK signals.
599     It is passed a widget name, e.g. 'GtkCList' and a signal name, e.g.
600     'select_row' and it returns a pointer to an array of argument types and
601     names. */
602 static const gchar **
603 lookup_signal_arg_names (const gchar * type, const gchar * signal_name)
605   /* Each arg array starts with the object type name and the signal name,
606      and then signal arguments follow. */
607   static const gchar *GbArgTable[][16] =
608   {
609     {"GtkCList", "select_row",
610      "gint             row",
611      "gint             column",
612      "GdkEventButton  *event"},
613     {"GtkCList", "unselect_row",
614      "gint             row",
615      "gint             column",
616      "GdkEventButton  *event"},
617     {"GtkCList", "click_column",
618      "gint             column"},
620     {"GtkCList", "resize_column",
621      "gint             column",
622      "gint             width"},
624     {"GtkCList", "extend_selection",
625      "GtkScrollType    scroll_type",
626      "gfloat           position",
627      "gboolean         auto_start_selection"},
628     {"GtkCList", "scroll_vertical",
629      "GtkScrollType    scroll_type",
630      "gfloat           position"},
631     {"GtkCList", "scroll_horizontal",
632      "GtkScrollType    scroll_type",
633      "gfloat           position"},
635     {"GtkCTree", "tree_select_row",
636      "GtkCTreeNode    *node",
637      "gint             column"},
638     {"GtkCTree", "tree_unselect_row",
639      "GtkCTreeNode    *node",
640      "gint             column"},
641     {"GtkCTree", "tree_expand",
642      "GtkCTreeNode    *node"},
643     {"GtkCTree", "tree_collapse",
644      "GtkCTreeNode    *node"},
645     {"GtkCTree", "tree_move",
646      "GtkCTreeNode    *node",
647      "GtkCTreeNode    *new_parent",
648      "GtkCTreeNode    *new_sibling"},
649     {"GtkCTree", "change_focus_row_expansion",
650      "GtkCTreeExpansionType expansion"},
652     {"GtkEditable", "insert_text",
653      "gchar           *new_text",
654      "gint             new_text_length",
655      "gint            *position"},
656     {"GtkEditable", "delete_text",
657      "gint             start_pos",
658      "gint             end_pos"},
659     {"GtkEditable", "set_editable",
660      "gboolean         is_editable"},
661     {"GtkEditable", "move_cursor",
662      "gint             x",
663      "gint             y"},
664     {"GtkEditable", "move_word",
665      "gint             num_words"},
666     {"GtkEditable", "move_page",
667      "gint             x",
668      "gint             y"},
669     {"GtkEditable", "move_to_row",
670      "gint             row"},
671     {"GtkEditable", "move_to_column",
672      "gint             column"},
674     {"GtkEditable", "kill_char",
675      "gint             direction"},
676     {"GtkEditable", "kill_word",
677      "gint             direction"},
678     {"GtkEditable", "kill_line",
679      "gint             direction"},
682     {"GtkInputDialog", "enable_device",
683      "GdkDevice       *deviceid"},
684     {"GtkInputDialog", "disable_device",
685      "GdkDevice       *deviceid"},
687     {"GtkListItem", "extend_selection",
688      "GtkScrollType    scroll_type",
689      "gfloat           position",
690      "gboolean         auto_start_selection"},
691     {"GtkListItem", "scroll_vertical",
692      "GtkScrollType    scroll_type",
693      "gfloat           position"},
694     {"GtkListItem", "scroll_horizontal",
695      "GtkScrollType    scroll_type",
696      "gfloat           position"},
698     {"GtkMenuShell", "move_current",
699      "GtkMenuDirectionType direction"},
700     {"GtkMenuShell", "activate_current",
701      "gboolean         force_hide"},
704     {"GtkNotebook", "switch_page",
705      "GtkNotebookPage *page",
706      "guint            page_num"},
707     {"GtkStatusbar", "text_pushed",
708      "guint            context_id",
709      "gchar           *text"},
710     {"GtkStatusbar", "text_popped",
711      "guint            context_id",
712      "gchar           *text"},
713     {"GtkTipsQuery", "widget_entered",
714      "GtkWidget       *widget",
715      "gchar           *tip_text",
716      "gchar           *tip_private"},
717     {"GtkTipsQuery", "widget_selected",
718      "GtkWidget       *widget",
719      "gchar           *tip_text",
720      "gchar           *tip_private",
721      "GdkEventButton  *event"},
722     {"GtkToolbar", "orientation_changed",
723      "GtkOrientation   orientation"},
724     {"GtkToolbar", "style_changed",
725      "GtkToolbarStyle  style"},
726     {"GtkWidget", "draw",
727      "GdkRectangle    *area"},
728     {"GtkWidget", "size_request",
729      "GtkRequisition  *requisition"},
730     {"GtkWidget", "size_allocate",
731      "GtkAllocation   *allocation"},
732     {"GtkWidget", "state_changed",
733      "GtkStateType     state"},
734     {"GtkWidget", "style_set",
735      "GtkStyle        *previous_style"},
737     {"GtkWidget", "install_accelerator",
738      "gchar           *signal_name",
739      "gchar            key",
740      "gint             modifiers"},
742     {"GtkWidget", "add_accelerator",
743      "guint            accel_signal_id",
744      "GtkAccelGroup   *accel_group",
745      "guint            accel_key",
746      "GdkModifierType  accel_mods",
747      "GtkAccelFlags    accel_flags"},
749     {"GtkWidget", "parent_set",
750      "GtkObject       *old_parent"},
752     {"GtkWidget", "remove_accelerator",
753      "GtkAccelGroup   *accel_group",
754      "guint            accel_key",
755      "GdkModifierType  accel_mods"},
756     {"GtkWidget", "debug_msg",
757      "gchar           *message"},
758     {"GtkWindow", "move_resize",
759      "gint            *x",
760      "gint            *y",
761      "gint             width",
762      "gint             height"},
763     {"GtkWindow", "set_focus",
764      "GtkWidget       *widget"},
766     {"GtkWidget", "selection_get",
767      "GtkSelectionData *data",
768      "guint            info",
769      "guint            time"},
770     {"GtkWidget", "selection_received",
771      "GtkSelectionData *data",
772      "guint            time"},
774     {"GtkWidget", "drag_begin",
775      "GdkDragContext  *drag_context"},
776     {"GtkWidget", "drag_end",
777      "GdkDragContext  *drag_context"},
778     {"GtkWidget", "drag_data_delete",
779      "GdkDragContext  *drag_context"},
780     {"GtkWidget", "drag_leave",
781      "GdkDragContext  *drag_context",
782      "guint            time"},
783     {"GtkWidget", "drag_motion",
784      "GdkDragContext  *drag_context",
785      "gint             x",
786      "gint             y",
787      "guint            time"},
788     {"GtkWidget", "drag_drop",
789      "GdkDragContext  *drag_context",
790      "gint             x",
791      "gint             y",
792      "guint            time"},
793     {"GtkWidget", "drag_data_get",
794      "GdkDragContext  *drag_context",
795      "GtkSelectionData *data",
796      "guint            info",
797      "guint            time"},
798     {"GtkWidget", "drag_data_received",
799      "GdkDragContext  *drag_context",
800      "gint             x",
801      "gint             y",
802      "GtkSelectionData *data",
803      "guint            info",
804      "guint            time"},
806     {NULL}
807   };
809   gint i;
811   for (i = 0; GbArgTable[i][0]; i++)
812     {
813 #if 1
814       if (!strcmp (type, GbArgTable[i][0])
815           && !strcmp (signal_name, GbArgTable[i][1]))
816         return &GbArgTable[i][2];
817 #endif
818     }
819   return NULL;
822 /* This outputs the hierarchy of all objects which have been initialized,
823    i.e. by calling their XXX_get_type() initialization function. */
824 static void
825 output_object_hierarchy (void)
827   FILE *fp;
828   gint i;
830   fp = fopen (hierarchy_filename, "w");
831   if (fp == NULL)
832     {
833       g_warning ("Couldn't open output file: %s : %s", hierarchy_filename, g_strerror(errno));
834       return;
835     }
836   output_hierarchy (fp, G_TYPE_OBJECT, 0);
837   output_hierarchy (fp, G_TYPE_INTERFACE, 0);
838   
839   for (i=0; object_types[i]; i++) {
840     if (!g_type_parent (object_types[i]) &&
841       (object_types[i] != G_TYPE_OBJECT) &&
842       (object_types[i] != G_TYPE_INTERFACE)
843     ) {
844       output_hierarchy (fp, object_types[i], 0);
845     }
846   }
848   fclose (fp);
851 /* This is called recursively to output the hierarchy of a widget. */
852 static void
853 output_hierarchy (FILE  *fp,
854                   GType  type,
855                   guint   level)
857   guint i;
858   GType *children;
859   guint n_children;
861   if (!type)
862     return;
864   for (i = 0; i < level; i++)
865     fprintf (fp, "  ");
866   fprintf (fp, "%s\\n", g_type_name (type));
867   
868   children = g_type_children (type, &n_children);
870   for (i=0; i < n_children; i++)
871     output_hierarchy (fp, children[i], level + 1);
873   g_free (children);
876 static void output_object_interfaces (void)
878   guint i;
879   FILE *fp;
881   fp = fopen (interfaces_filename, "w");
882   if (fp == NULL)
883     {
884       g_warning ("Couldn't open output file: %s : %s", interfaces_filename, g_strerror(errno));
885       return;
886     }
887   output_interfaces (fp, G_TYPE_OBJECT);
889   for (i = 0; object_types[i]; i++)
890     {
891       if (!g_type_parent (object_types[i]) &&
892           (object_types[i] != G_TYPE_OBJECT) &&
893           G_TYPE_IS_INSTANTIATABLE (object_types[i]))
894         {
895           output_interfaces (fp, object_types[i]);
896         }
897     }
898   fclose (fp);
901 static void
902 output_interfaces (FILE  *fp,
903                    GType  type)
905   guint i;
906   GType *children, *interfaces;
907   guint n_children, n_interfaces;
909   if (!type)
910     return;
912   interfaces = g_type_interfaces (type, &n_interfaces);
914   if (n_interfaces > 0)
915     {
916       fprintf (fp, "%s", g_type_name (type));
917       for (i=0; i < n_interfaces; i++)
918           fprintf (fp, " %s", g_type_name (interfaces[i]));
919       fprintf (fp, "\\n");
920      }
921   g_free (interfaces);
923   children = g_type_children (type, &n_children);
925   for (i=0; i < n_children; i++)
926     output_interfaces (fp, children[i]);
928   g_free (children);
931 static void output_interface_prerequisites (void)
933   FILE *fp;
935   fp = fopen (prerequisites_filename, "w");
936   if (fp == NULL)
937     {
938       g_warning ("Couldn't open output file: %s : %s", prerequisites_filename, g_strerror(errno));
939       return;
940     }
941   output_prerequisites (fp, G_TYPE_INTERFACE);
942   fclose (fp);
945 static void
946 output_prerequisites (FILE  *fp,
947                       GType  type)
949 #if GLIB_CHECK_VERSION(2,1,0)
950   guint i;
951   GType *children, *prerequisites;
952   guint n_children, n_prerequisites;
954   if (!type)
955     return;
957   prerequisites = g_type_interface_prerequisites (type, &n_prerequisites);
959   if (n_prerequisites > 0)
960     {
961       fprintf (fp, "%s", g_type_name (type));
962       for (i=0; i < n_prerequisites; i++)
963           fprintf (fp, " %s", g_type_name (prerequisites[i]));
964       fprintf (fp, "\\n");
965      }
966   g_free (prerequisites);
968   children = g_type_children (type, &n_children);
970   for (i=0; i < n_children; i++)
971     output_prerequisites (fp, children[i]);
973   g_free (children);
974 #endif
977 static void
978 output_args (void)
980   FILE *fp;
981   gint i;
983   fp = fopen (args_filename, "w");
984   if (fp == NULL)
985     {
986       g_warning ("Couldn't open output file: %s : %s", args_filename, g_strerror(errno));
987       return;
988     }
990   for (i = 0; object_types[i]; i++) {
991     output_object_args (fp, object_types[i]);
992   }
994   fclose (fp);
997 static gint
998 compare_param_specs (const void *a, const void *b)
1000   GParamSpec *spec_a = *(GParamSpec **)a;
1001   GParamSpec *spec_b = *(GParamSpec **)b;
1003   return strcmp (g_param_spec_get_name (spec_a), g_param_spec_get_name (spec_b));
1006 /* Its common to have unsigned properties restricted
1007  * to the signed range. Therefore we make this look
1008  * a bit nicer by spelling out the max constants.
1009  */
1011 /* Don't use "==" with floats, it might trigger a gcc warning.  */
1012 #define GTKDOC_COMPARE_FLOAT(x, y) (x <= y && x >= y)
1014 static gchar*
1015 describe_double_constant (gdouble value)
1017   gchar *desc;
1019   if (GTKDOC_COMPARE_FLOAT (value, G_MAXDOUBLE))
1020     desc = g_strdup ("G_MAXDOUBLE");
1021   else if (GTKDOC_COMPARE_FLOAT (value, G_MINDOUBLE))
1022     desc = g_strdup ("G_MINDOUBLE");
1023   else if (GTKDOC_COMPARE_FLOAT (value, -G_MAXDOUBLE))
1024     desc = g_strdup ("-G_MAXDOUBLE");
1025   else if (GTKDOC_COMPARE_FLOAT (value, G_MAXFLOAT))
1026     desc = g_strdup ("G_MAXFLOAT");
1027   else if (GTKDOC_COMPARE_FLOAT (value, G_MINFLOAT))
1028     desc = g_strdup ("G_MINFLOAT");
1029   else if (GTKDOC_COMPARE_FLOAT (value, -G_MAXFLOAT))
1030     desc = g_strdup ("-G_MAXFLOAT");
1031   else
1032     desc = g_strdup_printf ("%lg", value);
1034   return desc;
1037 static gchar*
1038 describe_signed_constant (gsize size, gint64 value)
1040   gchar *desc = NULL;
1042   switch (size) {
1043     case 2:
1044       if (sizeof (int) == 2) {
1045         if (value == G_MAXINT)
1046           desc = g_strdup ("G_MAXINT");
1047         else if (value == G_MININT)
1048           desc = g_strdup ("G_MININT");
1049         else if (value == (gint64)G_MAXUINT)
1050           desc = g_strdup ("G_MAXUINT");
1051       }
1052       break;
1053     case 4:
1054       if (sizeof (int) == 4) {
1055         if (value == G_MAXINT)
1056           desc = g_strdup ("G_MAXINT");
1057         else if (value == G_MININT)
1058           desc = g_strdup ("G_MININT");
1059         else if (value == (gint64)G_MAXUINT)
1060           desc = g_strdup ("G_MAXUINT");
1061       }
1062       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 == (gint64)G_MAXULONG)
1067         desc = g_strdup ("G_MAXULONG");
1068       break;
1069     case 8:
1070       if (value == G_MAXINT64)
1071         desc = g_strdup ("G_MAXINT64");
1072       else if (value == G_MININT64)
1073         desc = g_strdup ("G_MININT64");
1074       break;
1075     default:
1076       break;
1077   }
1078   if (!desc)
1079     desc = g_strdup_printf ("%" G_GINT64_FORMAT, value);
1081   return desc;
1084 static gchar*
1085 describe_unsigned_constant (gsize size, guint64 value)
1087   gchar *desc = NULL;
1089   switch (size) {
1090     case 2:
1091       if (sizeof (int) == 2) {
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       break;
1098     case 4:
1099       if (sizeof (int) == 4) {
1100         if (value == (guint64)G_MAXINT)
1101           desc = g_strdup ("G_MAXINT");
1102         else if (value == G_MAXUINT)
1103           desc = g_strdup ("G_MAXUINT");
1104       }
1105       if (value == (guint64)G_MAXLONG)
1106         desc = g_strdup ("G_MAXLONG");
1107       else if (value == G_MAXULONG)
1108         desc = g_strdup ("G_MAXULONG");
1109       break;
1110     case 8:
1111       if (value == G_MAXINT64)
1112         desc = g_strdup ("G_MAXINT64");
1113       else if (value == G_MAXUINT64)
1114         desc = g_strdup ("G_MAXUINT64");
1115       break;
1116     default:
1117       break;
1118   }
1119   if (!desc)
1120     desc = g_strdup_printf ("%" G_GUINT64_FORMAT, value);
1122   return desc;
1125 static gchar*
1126 describe_type (GParamSpec *spec)
1128   gchar *desc;
1129   gchar *lower;
1130   gchar *upper;
1132   if (G_IS_PARAM_SPEC_CHAR (spec))
1133     {
1134       GParamSpecChar *pspec = G_PARAM_SPEC_CHAR (spec);
1136       lower = describe_signed_constant (sizeof(gchar), pspec->minimum);
1137       upper = describe_signed_constant (sizeof(gchar), pspec->maximum);
1138       if (pspec->minimum == G_MININT8 && pspec->maximum == G_MAXINT8)
1139         desc = g_strdup ("");
1140       else if (pspec->minimum == G_MININT8)
1141         desc = g_strdup_printf ("<= %s", upper);
1142       else if (pspec->maximum == G_MAXINT8)
1143         desc = g_strdup_printf (">= %s", lower);
1144       else
1145         desc = g_strdup_printf ("[%s,%s]", lower, upper);
1146       g_free (lower);
1147       g_free (upper);
1148     }
1149   else if (G_IS_PARAM_SPEC_UCHAR (spec))
1150     {
1151       GParamSpecUChar *pspec = G_PARAM_SPEC_UCHAR (spec);
1153       lower = describe_unsigned_constant (sizeof(guchar), pspec->minimum);
1154       upper = describe_unsigned_constant (sizeof(guchar), pspec->maximum);
1155       if (pspec->minimum == 0 && pspec->maximum == G_MAXUINT8)
1156         desc = g_strdup ("");
1157       else if (pspec->minimum == 0)
1158         desc = g_strdup_printf ("<= %s", upper);
1159       else if (pspec->maximum == G_MAXUINT8)
1160         desc = g_strdup_printf (">= %s", lower);
1161       else
1162         desc = g_strdup_printf ("[%s,%s]", lower, upper);
1163       g_free (lower);
1164       g_free (upper);
1165     }
1166   else if (G_IS_PARAM_SPEC_INT (spec))
1167     {
1168       GParamSpecInt *pspec = G_PARAM_SPEC_INT (spec);
1170       lower = describe_signed_constant (sizeof(gint), pspec->minimum);
1171       upper = describe_signed_constant (sizeof(gint), pspec->maximum);
1172       if (pspec->minimum == G_MININT && pspec->maximum == G_MAXINT)
1173         desc = g_strdup ("");
1174       else if (pspec->minimum == G_MININT)
1175         desc = g_strdup_printf ("<= %s", upper);
1176       else if (pspec->maximum == G_MAXINT)
1177         desc = g_strdup_printf (">= %s", lower);
1178       else
1179         desc = g_strdup_printf ("[%s,%s]", lower, upper);
1180       g_free (lower);
1181       g_free (upper);
1182     }
1183   else if (G_IS_PARAM_SPEC_UINT (spec))
1184     {
1185       GParamSpecUInt *pspec = G_PARAM_SPEC_UINT (spec);
1187       lower = describe_unsigned_constant (sizeof(guint), pspec->minimum);
1188       upper = describe_unsigned_constant (sizeof(guint), pspec->maximum);
1189       if (pspec->minimum == 0 && pspec->maximum == G_MAXUINT)
1190         desc = g_strdup ("");
1191       else if (pspec->minimum == 0)
1192         desc = g_strdup_printf ("<= %s", upper);
1193       else if (pspec->maximum == G_MAXUINT)
1194         desc = g_strdup_printf (">= %s", lower);
1195       else
1196         desc = g_strdup_printf ("[%s,%s]", lower, upper);
1197       g_free (lower);
1198       g_free (upper);
1199     }
1200   else if (G_IS_PARAM_SPEC_LONG (spec))
1201     {
1202       GParamSpecLong *pspec = G_PARAM_SPEC_LONG (spec);
1204       lower = describe_signed_constant (sizeof(glong), pspec->minimum);
1205       upper = describe_signed_constant (sizeof(glong), pspec->maximum);
1206       if (pspec->minimum == G_MINLONG && pspec->maximum == G_MAXLONG)
1207         desc = g_strdup ("");
1208       else if (pspec->minimum == G_MINLONG)
1209         desc = g_strdup_printf ("<= %s", upper);
1210       else if (pspec->maximum == G_MAXLONG)
1211         desc = g_strdup_printf (">= %s", lower);
1212       else
1213         desc = g_strdup_printf ("[%s,%s]", lower, upper);
1214       g_free (lower);
1215       g_free (upper);
1216     }
1217   else if (G_IS_PARAM_SPEC_ULONG (spec))
1218     {
1219       GParamSpecULong *pspec = G_PARAM_SPEC_ULONG (spec);
1221       lower = describe_unsigned_constant (sizeof(gulong), pspec->minimum);
1222       upper = describe_unsigned_constant (sizeof(gulong), pspec->maximum);
1223       if (pspec->minimum == 0 && pspec->maximum == G_MAXULONG)
1224         desc = g_strdup ("");
1225       else if (pspec->minimum == 0)
1226         desc = g_strdup_printf ("<= %s", upper);
1227       else if (pspec->maximum == G_MAXULONG)
1228         desc = g_strdup_printf (">= %s", lower);
1229       else
1230         desc = g_strdup_printf ("[%s,%s]", lower, upper);
1231       g_free (lower);
1232       g_free (upper);
1233     }
1234   else if (G_IS_PARAM_SPEC_INT64 (spec))
1235     {
1236       GParamSpecInt64 *pspec = G_PARAM_SPEC_INT64 (spec);
1238       lower = describe_signed_constant (sizeof(gint64), pspec->minimum);
1239       upper = describe_signed_constant (sizeof(gint64), pspec->maximum);
1240       if (pspec->minimum == G_MININT64 && pspec->maximum == G_MAXINT64)
1241         desc = g_strdup ("");
1242       else if (pspec->minimum == G_MININT64)
1243         desc = g_strdup_printf ("<= %s", upper);
1244       else if (pspec->maximum == G_MAXINT64)
1245         desc = g_strdup_printf (">= %s", lower);
1246       else
1247         desc = g_strdup_printf ("[%s,%s]", lower, upper);
1248       g_free (lower);
1249       g_free (upper);
1250     }
1251   else if (G_IS_PARAM_SPEC_UINT64 (spec))
1252     {
1253       GParamSpecUInt64 *pspec = G_PARAM_SPEC_UINT64 (spec);
1255       lower = describe_unsigned_constant (sizeof(guint64), pspec->minimum);
1256       upper = describe_unsigned_constant (sizeof(guint64), pspec->maximum);
1257       if (pspec->minimum == 0 && pspec->maximum == G_MAXUINT64)
1258         desc = g_strdup ("");
1259       else if (pspec->minimum == 0)
1260         desc = g_strdup_printf ("<= %s", upper);
1261       else if (pspec->maximum == G_MAXUINT64)
1262         desc = g_strdup_printf (">= %s", lower);
1263       else
1264         desc = g_strdup_printf ("[%s,%s]", lower, upper);
1265       g_free (lower);
1266       g_free (upper);
1267     }
1268   else if (G_IS_PARAM_SPEC_FLOAT (spec))
1269     {
1270       GParamSpecFloat *pspec = G_PARAM_SPEC_FLOAT (spec);
1272       lower = describe_double_constant (pspec->minimum);
1273       upper = describe_double_constant (pspec->maximum);
1274       if (GTKDOC_COMPARE_FLOAT (pspec->minimum, -G_MAXFLOAT))
1275         {
1276           if (GTKDOC_COMPARE_FLOAT (pspec->maximum, G_MAXFLOAT))
1277             desc = g_strdup ("");
1278           else
1279             desc = g_strdup_printf ("<= %s", upper);
1280         }
1281       else if (GTKDOC_COMPARE_FLOAT (pspec->maximum, G_MAXFLOAT))
1282         desc = g_strdup_printf (">= %s", lower);
1283       else
1284         desc = g_strdup_printf ("[%s,%s]", lower, upper);
1285       g_free (lower);
1286       g_free (upper);
1287     }
1288   else if (G_IS_PARAM_SPEC_DOUBLE (spec))
1289     {
1290       GParamSpecDouble *pspec = G_PARAM_SPEC_DOUBLE (spec);
1292       lower = describe_double_constant (pspec->minimum);
1293       upper = describe_double_constant (pspec->maximum);
1294       if (GTKDOC_COMPARE_FLOAT (pspec->minimum, -G_MAXDOUBLE))
1295         {
1296           if (GTKDOC_COMPARE_FLOAT (pspec->maximum, G_MAXDOUBLE))
1297             desc = g_strdup ("");
1298           else
1299             desc = g_strdup_printf ("<= %s", upper);
1300         }
1301       else if (GTKDOC_COMPARE_FLOAT (pspec->maximum, G_MAXDOUBLE))
1302         desc = g_strdup_printf (">= %s", lower);
1303       else
1304         desc = g_strdup_printf ("[%s,%s]", lower, upper);
1305       g_free (lower);
1306       g_free (upper);
1307     }
1308 #if GLIB_CHECK_VERSION (2, 12, 0)
1309   else if (G_IS_PARAM_SPEC_GTYPE (spec))
1310     {
1311       GParamSpecGType *pspec = G_PARAM_SPEC_GTYPE (spec);
1312       gboolean is_pointer;
1314       desc = g_strdup (get_type_name (pspec->is_a_type, &is_pointer));
1315     }
1316 #endif
1317 #if GLIB_CHECK_VERSION (2, 25, 9)
1318   else if (G_IS_PARAM_SPEC_VARIANT (spec))
1319     {
1320       GParamSpecVariant *pspec = G_PARAM_SPEC_VARIANT (spec);
1321       gchar *variant_type;
1323       variant_type = g_variant_type_dup_string (pspec->type);
1324       desc = g_strdup_printf ("GVariant<%s>", variant_type);
1325       g_free (variant_type);
1326     }
1327 #endif
1328   else
1329     {
1330       desc = g_strdup ("");
1331     }
1333   return desc;
1336 static gchar*
1337 describe_default (GParamSpec *spec)
1339   gchar *desc;
1341   if (G_IS_PARAM_SPEC_CHAR (spec))
1342     {
1343       GParamSpecChar *pspec = G_PARAM_SPEC_CHAR (spec);
1345       desc = g_strdup_printf ("%d", pspec->default_value);
1346     }
1347   else if (G_IS_PARAM_SPEC_UCHAR (spec))
1348     {
1349       GParamSpecUChar *pspec = G_PARAM_SPEC_UCHAR (spec);
1351       desc = g_strdup_printf ("%u", pspec->default_value);
1352     }
1353   else if (G_IS_PARAM_SPEC_BOOLEAN (spec))
1354     {
1355       GParamSpecBoolean *pspec = G_PARAM_SPEC_BOOLEAN (spec);
1357       desc = g_strdup_printf ("%s", pspec->default_value ? "TRUE" : "FALSE");
1358     }
1359   else if (G_IS_PARAM_SPEC_INT (spec))
1360     {
1361       GParamSpecInt *pspec = G_PARAM_SPEC_INT (spec);
1363       desc = g_strdup_printf ("%d", pspec->default_value);
1364     }
1365   else if (G_IS_PARAM_SPEC_UINT (spec))
1366     {
1367       GParamSpecUInt *pspec = G_PARAM_SPEC_UINT (spec);
1369       desc = g_strdup_printf ("%u", pspec->default_value);
1370     }
1371   else if (G_IS_PARAM_SPEC_LONG (spec))
1372     {
1373       GParamSpecLong *pspec = G_PARAM_SPEC_LONG (spec);
1375       desc = g_strdup_printf ("%ld", pspec->default_value);
1376     }
1377   else if (G_IS_PARAM_SPEC_LONG (spec))
1378     {
1379       GParamSpecULong *pspec = G_PARAM_SPEC_ULONG (spec);
1381       desc = g_strdup_printf ("%lu", pspec->default_value);
1382     }
1383   else if (G_IS_PARAM_SPEC_INT64 (spec))
1384     {
1385       GParamSpecInt64 *pspec = G_PARAM_SPEC_INT64 (spec);
1387       desc = g_strdup_printf ("%" G_GINT64_FORMAT, pspec->default_value);
1388     }
1389   else if (G_IS_PARAM_SPEC_UINT64 (spec))
1390     {
1391       GParamSpecUInt64 *pspec = G_PARAM_SPEC_UINT64 (spec);
1393       desc = g_strdup_printf ("%" G_GUINT64_FORMAT, pspec->default_value);
1394     }
1395   else if (G_IS_PARAM_SPEC_UNICHAR (spec))
1396     {
1397       GParamSpecUnichar *pspec = G_PARAM_SPEC_UNICHAR (spec);
1399       if (g_unichar_isprint (pspec->default_value))
1400         desc = g_strdup_printf ("'%c'", pspec->default_value);
1401       else
1402         desc = g_strdup_printf ("%u", pspec->default_value);
1403     }
1404   else if (G_IS_PARAM_SPEC_ENUM (spec))
1405     {
1406       GParamSpecEnum *pspec = G_PARAM_SPEC_ENUM (spec);
1408       GEnumValue *value = g_enum_get_value (pspec->enum_class, pspec->default_value);
1409       if (value)
1410         desc = g_strdup_printf ("%s", value->value_name);
1411       else
1412         desc = g_strdup_printf ("%d", pspec->default_value);
1413     }
1414   else if (G_IS_PARAM_SPEC_FLAGS (spec))
1415     {
1416       GParamSpecFlags *pspec = G_PARAM_SPEC_FLAGS (spec);
1417       guint default_value;
1418       GString *acc;
1420       default_value = pspec->default_value;
1421       acc = g_string_new ("");
1423       while (default_value)
1424         {
1425           GFlagsValue *value = g_flags_get_first_value (pspec->flags_class, default_value);
1427           if (!value)
1428             break;
1430           if (acc->len > 0)
1431             g_string_append (acc, "|");
1432           g_string_append (acc, value->value_name);
1434           default_value &= ~value->value;
1435         }
1437       if (default_value == 0)
1438         desc = g_string_free (acc, FALSE);
1439       else
1440         {
1441           desc = g_strdup_printf ("%d", pspec->default_value);
1442           g_string_free (acc, TRUE);
1443         }
1444     }
1445   else if (G_IS_PARAM_SPEC_FLOAT (spec))
1446     {
1447       GParamSpecFloat *pspec = G_PARAM_SPEC_FLOAT (spec);
1449       desc = g_strdup_printf ("%g", pspec->default_value);
1450     }
1451   else if (G_IS_PARAM_SPEC_DOUBLE (spec))
1452     {
1453       GParamSpecDouble *pspec = G_PARAM_SPEC_DOUBLE (spec);
1455       desc = g_strdup_printf ("%lg", pspec->default_value);
1456     }
1457   else if (G_IS_PARAM_SPEC_STRING (spec))
1458     {
1459       GParamSpecString *pspec = G_PARAM_SPEC_STRING (spec);
1461       if (pspec->default_value)
1462         {
1463           gchar *esc = g_strescape (pspec->default_value, NULL);
1465           desc = g_strdup_printf ("\\"%s\\"", esc);
1467           g_free (esc);
1468         }
1469       else
1470         desc = g_strdup_printf ("NULL");
1471     }
1472 #if GLIB_CHECK_VERSION (2, 25, 9)
1473   else if (G_IS_PARAM_SPEC_VARIANT (spec))
1474     {
1475       GParamSpecVariant *pspec = G_PARAM_SPEC_VARIANT (spec);
1477       if (pspec->default_value)
1478         desc = g_variant_print (pspec->default_value, TRUE);
1479       else
1480         desc = g_strdup ("NULL");
1481     }
1482 #endif
1483   else
1484     {
1485       desc = g_strdup ("");
1486     }
1488   return desc;
1492 static void
1493 output_object_args (FILE *fp, GType object_type)
1495   gpointer class;
1496   const gchar *object_class_name;
1497   guint arg;
1498   gchar flags[16], *pos;
1499   GParamSpec **properties;
1500   guint n_properties;
1501   gboolean child_prop;
1502   gboolean style_prop;
1503   gboolean is_pointer;
1504   const gchar *type_name;
1505   gchar *type_desc;
1506   gchar *default_value;
1508   if (G_TYPE_IS_OBJECT (object_type))
1509     {
1510       class = g_type_class_peek (object_type);
1511       if (!class)
1512         return;
1514       properties = g_object_class_list_properties (class, &n_properties);
1515     }
1516 #if GLIB_MAJOR_VERSION > 2 || (GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION >= 3)
1517   else if (G_TYPE_IS_INTERFACE (object_type))
1518     {
1519       class = g_type_default_interface_ref (object_type);
1521       if (!class)
1522         return;
1524       properties = g_object_interface_list_properties (class, &n_properties);
1525     }
1526 #endif
1527   else
1528     return;
1530   object_class_name = g_type_name (object_type);
1532   child_prop = FALSE;
1533   style_prop = FALSE;
1535   while (TRUE) {
1536     qsort (properties, n_properties, sizeof (GParamSpec *), compare_param_specs);
1537     for (arg = 0; arg < n_properties; arg++)
1538       {
1539         GParamSpec *spec = properties[arg];
1540         const gchar *nick, *blurb, *dot;
1542         if (spec->owner_type != object_type)
1543           continue;
1545         pos = flags;
1546         /* We use one-character flags for simplicity. */
1547         if (child_prop && !style_prop)
1548           *pos++ = 'c';
1549         if (style_prop)
1550           *pos++ = 's';
1551         if (spec->flags & G_PARAM_READABLE)
1552           *pos++ = 'r';
1553         if (spec->flags & G_PARAM_WRITABLE)
1554           *pos++ = 'w';
1555         if (spec->flags & G_PARAM_CONSTRUCT)
1556           *pos++ = 'x';
1557         if (spec->flags & G_PARAM_CONSTRUCT_ONLY)
1558           *pos++ = 'X';
1559         *pos = 0;
1561         nick = g_param_spec_get_nick (spec);
1562         blurb = g_param_spec_get_blurb (spec);
1564         dot = "";
1565         if (blurb) {
1566           int str_len = strlen (blurb);
1567           if (str_len > 0  && blurb[str_len - 1] != '.')
1568             dot = ".";
1569         }
1571         type_desc = describe_type (spec);
1572         default_value = describe_default (spec);
1573         type_name = get_type_name (spec->value_type, &is_pointer);
1574         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",
1575                  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);
1576         g_free (type_desc);
1577         g_free (default_value);
1578       }
1580     g_free (properties);
1582 #ifdef GTK_IS_CONTAINER_CLASS
1583     if (!child_prop && GTK_IS_CONTAINER_CLASS (class)) {
1584       properties = gtk_container_class_list_child_properties (class, &n_properties);
1585       child_prop = TRUE;
1586       continue;
1587     }
1588 #endif
1590 #ifdef GTK_IS_WIDGET_CLASS
1591 #if GTK_CHECK_VERSION(2,1,0)
1592     if (!style_prop && GTK_IS_WIDGET_CLASS (class)) {
1593       properties = gtk_widget_class_list_style_properties (GTK_WIDGET_CLASS (class), &n_properties);
1594       style_prop = TRUE;
1595       continue;
1596     }
1597 #endif
1598 #endif
1602 if ($QUERY_CHILD_PROPERTIES) {
1603   print OUTPUT <<EOT;
1604     if (!child_prop) {
1605       properties = $QUERY_CHILD_PROPERTIES (class, &n_properties);
1606       if (properties) {
1607         child_prop = TRUE;
1608         continue;
1609       }
1610    }
1615 print OUTPUT <<EOT;
1616     break;
1617   }
1621 close OUTPUT;
1623 # Compile and run our file
1625 $CC = $ENV{CC} ? $ENV{CC} : "gcc";
1626 $LD = $ENV{LD} ? $ENV{LD} : $CC;
1627 $CFLAGS = $ENV{CFLAGS} ? $ENV{CFLAGS} : "";
1628 $LDFLAGS = $ENV{LDFLAGS} ? $ENV{LDFLAGS} : "";
1629 $RUN = $ENV{RUN} ? $ENV{RUN} : "";
1631 my $o_file;
1632 if ($CC =~ /libtool/) {
1633   $o_file  = "$MODULE-scan.lo"
1634 } else {
1635   $o_file = "$MODULE-scan.o"
1638 print "gtk-doc: Compiling scanner\n";
1639 $command = "$CC $CFLAGS -c -o $o_file $MODULE-scan.c";
1640 system("($command)") == 0 or die "Compilation of scanner failed: $!\n";
1642 print "gtk-doc: Linking scanner\n";
1643 # FIXME: Can we turn off as-needed for the docs (or better fix it?)
1644 #$command = "$LD -Wl,--no-as-needed $o_file $LDFLAGS -o $MODULE-scan";
1645 $command = "$LD $o_file $LDFLAGS -o $MODULE-scan";
1646 system("($command)") == 0 or die "Linking of scanner failed: $!\n";
1648 print "gtk-doc: Running scanner $MODULE-scan\n";
1649 system("($RUN ./$MODULE-scan)") == 0 or die "Scan failed: $!\n";
1652 if (!defined($ENV{"GTK_DOC_KEEP_INTERMEDIATE"})) {
1653   unlink "./$MODULE-scan.c", "./$MODULE-scan.o", "./$MODULE-scan.lo", "./$MODULE-scan";
1656 &UpdateFileIfChanged ($old_signals_filename, $new_signals_filename, 0);
1657 &UpdateFileIfChanged ($old_hierarchy_filename, $new_hierarchy_filename, 0);
1658 &UpdateFileIfChanged ($old_interfaces_filename, $new_interfaces_filename, 0);
1659 &UpdateFileIfChanged ($old_prerequisites_filename, $new_prerequisites_filename, 0);
1660 &UpdateFileIfChanged ($old_args_filename, $new_args_filename, 0);