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