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