Released 1.2.
[gtk-doc.git] / gtkdoc-scangobj.in
blob258a6ac8a024b8da1c163d449cb3819b61b53741
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 ()";
45 # --nogtkinit is deprecated, as it is the default now anyway.
46 %optctl = (module => \$MODULE,
47            types => \$TYPES_FILE,
48            nogtkinit => \$NO_GTK_INIT,
49            'type-init-func' => \$TYPE_INIT_FUNC,
50            'output-dir' => \$OUTPUT_DIR,
51            'version' => \$PRINT_VERSION,
52            'help' => \$PRINT_HELP);
53            
54 GetOptions(\%optctl, "module=s", "types:s", "output-dir:s", "nogtkinit", "type-init-func:s", "version", "help");
56 if ($NO_GTK_INIT) {
57   # Do nothing. This just avoids a warning.
60 if ($PRINT_VERSION) {
61     print "@VERSION@\n";
62     exit 0;
65 if (!$MODULE) {
66     $PRINT_HELP = 1;
69 if ($PRINT_HELP) {
70     print "gtkdoc-scangobj version @VERSION@\n";
71     print "\n--module=MODULE_NAME  Name of the doc module being parsed";
72     print "\n--types=FILE          The name of the file to store the types in";
73     print "\n--type-init-func=FUNC The init function to call instead of g_type_init ()";
74     print "\n--output-dir=DIRNAME  The directory where the results are stored";
75     print "\n--version             Print the version of this program";
76     print "\n--help                Print this help\n";
77     exit 0;
80 $OUTPUT_DIR = $OUTPUT_DIR ? $OUTPUT_DIR : ".";
82 $TYPES_FILE = $TYPES_FILE ? $TYPES_FILE : "$OUTPUT_DIR/$MODULE.types";
84 open TYPES, $TYPES_FILE || die "Cannot open $TYPES_FILE: $!\n";
85 open OUTPUT, ">$MODULE-scan.c" || die "Cannot open $MODULE-scan.c: $!\n";
87 my $old_signals_filename = "$OUTPUT_DIR/$MODULE.signals";
88 my $new_signals_filename = "$OUTPUT_DIR/$MODULE.signals.new";
89 my $old_hierarchy_filename = "$OUTPUT_DIR/$MODULE.hierarchy";
90 my $new_hierarchy_filename = "$OUTPUT_DIR/$MODULE.hierarchy.new";
91 my $old_interfaces_filename = "$OUTPUT_DIR/$MODULE.interfaces";
92 my $new_interfaces_filename = "$OUTPUT_DIR/$MODULE.interfaces.new";
93 my $old_prerequisites_filename = "$OUTPUT_DIR/$MODULE.prerequisites";
94 my $new_prerequisites_filename = "$OUTPUT_DIR/$MODULE.prerequisites.new";
95 my $old_args_filename = "$OUTPUT_DIR/$MODULE.args";
96 my $new_args_filename = "$OUTPUT_DIR/$MODULE.args.new";
98 # write a C program to scan the types
100 $includes = "";
101 @types = ();
103 for (<TYPES>) {
104     if (/^#include/) {
105         $includes .= $_;
106     } elsif (/^%/) {
107         next;
108     } elsif (/^\s*$/) {
109         next;
110     } else {
111         chomp;
112         push @types, $_;
113     }
116 $ntypes = @types + 1;
118 print OUTPUT <<EOT;
119 #include <string.h>
120 #include <stdlib.h>
121 #include <stdio.h>
123 $includes
124 #ifdef GTK_IS_WIDGET_CLASS
125 #include <gtk/gtkversion.h>
126 #endif
127 GType object_types[$ntypes];
129 static GType *
130 get_object_types (void)
132     gint i = 0;
135 for (@types) {
136     print OUTPUT "    object_types[i++] = $_ ();\n";
139 print OUTPUT <<EOT;
140     object_types[i] = 0;
142     /* Need to make sure all the types are loaded in and initialize
143      * their signals and properties.
144      */
145     for (i=0; object_types[i]; i++)
146       if (G_TYPE_IS_CLASSED (object_types[i]))
147       g_type_class_ref (object_types[i]);
149     return object_types;
153  * This uses GTK type functions to output signal prototypes and the widget
154  * hierarchy.
155  */
157 /* The output files */
158 gchar *signals_filename = "$new_signals_filename";
159 gchar *hierarchy_filename = "$new_hierarchy_filename";
160 gchar *interfaces_filename = "$new_interfaces_filename";
161 gchar *prerequisites_filename = "$new_prerequisites_filename";
162 gchar *args_filename = "$new_args_filename";
165 static void output_signals (void);
166 static void output_widget_signals (FILE *fp,
167                                    GType object_type);
168 static void output_widget_signal (FILE *fp,
169                                   GType object_type,
170                                   const gchar *object_class_name,
171                                   guint signal_id);
172 static const gchar * get_type_name (GType type,
173                                     gboolean * is_pointer);
174 static gchar * get_gdk_event (const gchar * signal_name);
175 static gchar ** lookup_signal_arg_names (const gchar * type,
176                                          const gchar * signal_name);
178 static void output_widget_hierarchy (void);
179 static void output_hierarchy (FILE *fp,
180                               GType type,
181                               gint level);
183 static void output_widget_interfaces (void);
184 static void output_interfaces (FILE *fp,
185                                GType type);
187 static void output_interface_prerequisites (void);
188 static void output_prerequisites (FILE *fp,
189                                   GType type);
191 static void output_args (void);
192 static void output_widget_args (FILE *fp, GType object_type);
195 main (int argc, char *argv[])
197   $TYPE_INIT_FUNC;
199   get_object_types ();
201   output_signals ();
202   output_widget_hierarchy ();
203   output_widget_interfaces ();
204   output_interface_prerequisites ();
205   output_args ();
207   return 0;
211 static void
212 output_signals (void)
214   FILE *fp;
215   gint i;
217   fp = fopen (signals_filename, "w");
218   if (fp == NULL)
219     {
220       g_warning ("Couldn't open output file: %s", signals_filename);
221       return;
222     }
224   for (i = 0; object_types[i]; i++)
225     output_widget_signals (fp, object_types[i]);
227   fclose (fp);
230 static gint
231 compare_signals (const void *a, const void *b)
233   const guint *signal_a = a;
234   const guint *signal_b = b;
236   return strcmp (g_signal_name (*signal_a), g_signal_name (*signal_b));
239 /* This outputs all the signals of one widget. */
240 static void
241 output_widget_signals (FILE *fp, GType object_type)
243   const gchar *object_class_name;
244   guint *signals, n_signals;
245   guint sig;
247   if (G_TYPE_IS_INSTANTIATABLE (object_type) ||
248       G_TYPE_IS_INTERFACE (object_type))
249     {
251       object_class_name = g_type_name (object_type);
253       signals = g_signal_list_ids (object_type, &n_signals);
254       qsort (signals, n_signals, sizeof (guint), compare_signals);
256       for (sig = 0; sig < n_signals; sig++)
257         {
258            output_widget_signal (fp, object_type, object_class_name,
259                                  signals[sig]);
260         }
261       g_free (signals);
262    }
266 /* This outputs one signal. */
267 static void
268 output_widget_signal (FILE *fp,
269                       GType object_type,
270                       const gchar *object_name,
271                       guint signal_id)
273   GSignalQuery query_info;
274   const gchar *type_name, *ret_type, *object_arg;
275   gchar *pos, *arg_name, *object_arg_lower;
276   gboolean is_pointer;
277   gchar ret_type_buffer[1024], buffer[1024];
278   gint i, param;
279   gchar **arg_names;
280   gint param_num, widget_num, event_num, callback_num;
281   gint *arg_num;
282   gchar signal_name[128];
285   /*  g_print ("Object: %s Type: %i Signal: %u\\n", object_name, object_type,
286       signal_id);*/
288   param_num = 1;
289   widget_num = event_num = callback_num = 0;
291   g_signal_query (signal_id, &query_info);
293   /* Output the return type and function name. */
294   ret_type = get_type_name (query_info.return_type & ~G_SIGNAL_TYPE_STATIC_SCOPE, &is_pointer);
295   sprintf (ret_type_buffer, "%s%s", ret_type, is_pointer ? "*" : "");
297   /* Output the signal object type and the argument name. We assume the
298      type is a pointer - I think that is OK. We remove "Gtk" or "Gnome" and
299      convert to lower case for the argument name. */
300   pos = buffer;
301   sprintf (pos, "%s ", object_name);
302   pos += strlen (pos);
304   if (!strncmp (object_name, "Gtk", 3))
305       object_arg = object_name + 3;
306   else if (!strncmp (object_name, "Gnome", 5))
307       object_arg = object_name + 5;
308   else
309       object_arg = object_name;
311   object_arg_lower = g_ascii_strdown (object_arg, -1);
312   sprintf (pos, "*%s\\n", object_arg_lower);
313   pos += strlen (pos);
314   if (!strncmp (object_arg_lower, "widget", 6))
315     widget_num = 2;
316   g_free(object_arg_lower);
318   /* Convert signal name to use underscores rather than dashes '-'. */
319   strcpy (signal_name, query_info.signal_name);
320   for (i = 0; signal_name[i]; i++)
321     {
322       if (signal_name[i] == '-')
323         signal_name[i] = '_';
324     }
326   /* Output the signal parameters. */
327   arg_names = lookup_signal_arg_names (object_name, signal_name);
329   for (param = 0; param < query_info.n_params; param++)
330     {
331       if (arg_names)
332         {
333           sprintf (pos, "%s\\n", arg_names[param]);
334           pos += strlen (pos);
335         }
336       else
337         {
338           type_name = get_type_name (query_info.param_types[param] & ~G_SIGNAL_TYPE_STATIC_SCOPE, &is_pointer);
340           /* Most arguments to the callback are called "arg1", "arg2", etc.
341              GdkWidgets are called "widget", "widget2", ...
342              GdkEvents are called "event", "event2", ...
343              GtkCallbacks are called "callback", "callback2", ... */
344           if (!strcmp (type_name, "GtkWidget"))
345             {
346               arg_name = "widget";
347               arg_num = &widget_num;
348             }
349           else if (!strcmp (type_name, "GdkEvent"))
350             {
351               type_name = get_gdk_event (signal_name);
352               arg_name = "event";
353               arg_num = &event_num;
354               is_pointer = TRUE;
355             }
356           else if (!strcmp (type_name, "GtkCallback")
357                    || !strcmp (type_name, "GtkCCallback"))
358             {
359               arg_name = "callback";
360               arg_num = &callback_num;
361             }
362           else
363             {
364               arg_name = "arg";
365               arg_num = &param_num;
366             }
367           sprintf (pos, "%s ", type_name);
368           pos += strlen (pos);
370           if (!arg_num || *arg_num == 0)
371             sprintf (pos, "%s%s\\n", is_pointer ? "*" : " ", arg_name);
372           else
373             sprintf (pos, "%s%s%i\\n", is_pointer ? "*" : " ", arg_name,
374                      *arg_num);
375           pos += strlen (pos);
377           if (arg_num)
378             {
379               if (*arg_num == 0)
380                 *arg_num = 2;
381               else
382                 *arg_num += 1;
383             }
384         }
385     }
387   fprintf (fp,
388            "<SIGNAL>\\n<NAME>%s::%s</NAME>\\n<RETURNS>%s</RETURNS>\\n%s</SIGNAL>\\n\\n",
389            object_name, query_info.signal_name, ret_type_buffer, buffer);
393 /* Returns the type name to use for a signal argument or return value, given
394    the GtkType from the signal info. It also sets is_pointer to TRUE if the
395    argument needs a '*' since it is a pointer. */
396 static const gchar *
397 get_type_name (GType type, gboolean * is_pointer)
399   const gchar *type_name;
401   *is_pointer = FALSE;
402   type_name = g_type_name (type);
404   switch (type) {
405   case G_TYPE_NONE:
406   case G_TYPE_CHAR:
407   case G_TYPE_UCHAR:
408   case G_TYPE_BOOLEAN:
409   case G_TYPE_INT:
410   case G_TYPE_UINT:
411   case G_TYPE_LONG:
412   case G_TYPE_ULONG:
413   case G_TYPE_FLOAT:
414   case G_TYPE_DOUBLE:
415   case G_TYPE_POINTER:
416     /* These all have normal C type names so they are OK. */
417     return type_name;
419   case G_TYPE_STRING:
420     /* A GtkString is really a gchar*. */
421     *is_pointer = TRUE;
422     return "gchar";
424   case G_TYPE_ENUM:
425   case G_TYPE_FLAGS:
426     /* We use a gint for both of these. Hopefully a subtype with a decent
427        name will be registered and used instead, as GTK+ does itself. */
428     return "gint";
430   case G_TYPE_BOXED:
431     /* The boxed type shouldn't be used itself, only subtypes. Though we
432        return 'gpointer' just in case. */
433     return "gpointer";
435   case G_TYPE_PARAM:
436     /* A GParam is really a GParamSpec*. */
437     *is_pointer = TRUE;
438     return "GParamSpec";
440   default:
441     break;
442   }
444   /* For all GtkObject subclasses we can use the class name with a "*",
445      e.g. 'GtkWidget *'. */
446   if (g_type_is_a (type, G_TYPE_OBJECT))
447     *is_pointer = TRUE;
449   /* All boxed subtypes will be pointers as well. */
450   if (g_type_is_a (type, G_TYPE_BOXED))
451     *is_pointer = TRUE;
453   /* All pointer subtypes will be pointers as well. */
454   if (g_type_is_a (type, G_TYPE_POINTER))
455     *is_pointer = TRUE;
457   return type_name;
461 static gchar *
462 get_gdk_event (const gchar * signal_name)
464   static gchar *GbGDKEvents[] =
465   {
466     "button_press_event", "GdkEventButton",
467     "button_release_event", "GdkEventButton",
468     "motion_notify_event", "GdkEventMotion",
469     "delete_event", "GdkEvent",
470     "destroy_event", "GdkEvent",
471     "expose_event", "GdkEventExpose",
472     "key_press_event", "GdkEventKey",
473     "key_release_event", "GdkEventKey",
474     "enter_notify_event", "GdkEventCrossing",
475     "leave_notify_event", "GdkEventCrossing",
476     "configure_event", "GdkEventConfigure",
477     "focus_in_event", "GdkEventFocus",
478     "focus_out_event", "GdkEventFocus",
479     "map_event", "GdkEvent",
480     "unmap_event", "GdkEvent",
481     "property_notify_event", "GdkEventProperty",
482     "selection_clear_event", "GdkEventSelection",
483     "selection_request_event", "GdkEventSelection",
484     "selection_notify_event", "GdkEventSelection",
485     "proximity_in_event", "GdkEventProximity",
486     "proximity_out_event", "GdkEventProximity",
487     "drag_begin_event", "GdkEventDragBegin",
488     "drag_request_event", "GdkEventDragRequest",
489     "drag_end_event", "GdkEventDragRequest",
490     "drop_enter_event", "GdkEventDropEnter",
491     "drop_leave_event", "GdkEventDropLeave",
492     "drop_data_available_event", "GdkEventDropDataAvailable",
493     "other_event", "GdkEventOther",
494     "client_event", "GdkEventClient",
495     "no_expose_event", "GdkEventNoExpose",
496     NULL
497   };
499   gint i;
501   for (i = 0; GbGDKEvents[i]; i += 2)
502     {
503       if (!strcmp (signal_name, GbGDKEvents[i]))
504         return GbGDKEvents[i + 1];
505     }
506   return "GdkEvent";
510 /* This returns argument names to use for some known GTK signals.
511     It is passed a widget name, e.g. 'GtkCList' and a signal name, e.g.
512     'select_row' and it returns a pointer to an array of argument types and
513     names. */
514 static gchar **
515 lookup_signal_arg_names (const gchar * type, const gchar * signal_name)
517   /* Each arg array starts with the object type name and the signal name,
518      and then signal arguments follow. */
519   static gchar *GbArgTable[][16] =
520   {
521     {"GtkCList", "select_row",
522      "gint             row",
523      "gint             column",
524      "GdkEventButton  *event"},
525     {"GtkCList", "unselect_row",
526      "gint             row",
527      "gint             column",
528      "GdkEventButton  *event"},
529     {"GtkCList", "click_column",
530      "gint             column"},
532     {"GtkCList", "resize_column",
533      "gint             column",
534      "gint             width"},
536     {"GtkCList", "extend_selection",
537      "GtkScrollType    scroll_type",
538      "gfloat           position",
539      "gboolean         auto_start_selection"},
540     {"GtkCList", "scroll_vertical",
541      "GtkScrollType    scroll_type",
542      "gfloat           position"},
543     {"GtkCList", "scroll_horizontal",
544      "GtkScrollType    scroll_type",
545      "gfloat           position"},
547     {"GtkCTree", "tree_select_row",
548      "GtkCTreeNode    *node",
549      "gint             column"},
550     {"GtkCTree", "tree_unselect_row",
551      "GtkCTreeNode    *node",
552      "gint             column"},
553     {"GtkCTree", "tree_expand",
554      "GtkCTreeNode    *node"},
555     {"GtkCTree", "tree_collapse",
556      "GtkCTreeNode    *node"},
557     {"GtkCTree", "tree_move",
558      "GtkCTreeNode    *node",
559      "GtkCTreeNode    *new_parent",
560      "GtkCTreeNode    *new_sibling"},
561     {"GtkCTree", "change_focus_row_expansion",
562      "GtkCTreeExpansionType expansion"},
564     {"GtkEditable", "insert_text",
565      "gchar           *new_text",
566      "gint             new_text_length",
567      "gint            *position"},
568     {"GtkEditable", "delete_text",
569      "gint             start_pos",
570      "gint             end_pos"},
571     {"GtkEditable", "set_editable",
572      "gboolean         is_editable"},
573     {"GtkEditable", "move_cursor",
574      "gint             x",
575      "gint             y"},
576     {"GtkEditable", "move_word",
577      "gint             num_words"},
578     {"GtkEditable", "move_page",
579      "gint             x",
580      "gint             y"},
581     {"GtkEditable", "move_to_row",
582      "gint             row"},
583     {"GtkEditable", "move_to_column",
584      "gint             column"},
586     {"GtkEditable", "kill_char",
587      "gint             direction"},
588     {"GtkEditable", "kill_word",
589      "gint             direction"},
590     {"GtkEditable", "kill_line",
591      "gint             direction"},
594     {"GtkInputDialog", "enable_device",
595      "GdkDevice       *deviceid"},
596     {"GtkInputDialog", "disable_device",
597      "GdkDevice       *deviceid"},
599     {"GtkListItem", "extend_selection",
600      "GtkScrollType    scroll_type",
601      "gfloat           position",
602      "gboolean         auto_start_selection"},
603     {"GtkListItem", "scroll_vertical",
604      "GtkScrollType    scroll_type",
605      "gfloat           position"},
606     {"GtkListItem", "scroll_horizontal",
607      "GtkScrollType    scroll_type",
608      "gfloat           position"},
610     {"GtkMenuShell", "move_current",
611      "GtkMenuDirectionType direction"},
612     {"GtkMenuShell", "activate_current",
613      "gboolean         force_hide"},
616     {"GtkNotebook", "switch_page",
617      "GtkNotebookPage *page",
618      "guint            page_num"},
619     {"GtkStatusbar", "text_pushed",
620      "guint            context_id",
621      "gchar           *text"},
622     {"GtkStatusbar", "text_popped",
623      "guint            context_id",
624      "gchar           *text"},
625     {"GtkTipsQuery", "widget_entered",
626      "GtkWidget       *widget",
627      "gchar           *tip_text",
628      "gchar           *tip_private"},
629     {"GtkTipsQuery", "widget_selected",
630      "GtkWidget       *widget",
631      "gchar           *tip_text",
632      "gchar           *tip_private",
633      "GdkEventButton  *event"},
634     {"GtkToolbar", "orientation_changed",
635      "GtkOrientation   orientation"},
636     {"GtkToolbar", "style_changed",
637      "GtkToolbarStyle  style"},
638     {"GtkWidget", "draw",
639      "GdkRectangle    *area"},
640     {"GtkWidget", "size_request",
641      "GtkRequisition  *requisition"},
642     {"GtkWidget", "size_allocate",
643      "GtkAllocation   *allocation"},
644     {"GtkWidget", "state_changed",
645      "GtkStateType     state"},
646     {"GtkWidget", "style_set",
647      "GtkStyle        *previous_style"},
649     {"GtkWidget", "install_accelerator",
650      "gchar           *signal_name",
651      "gchar            key",
652      "gint             modifiers"},
654     {"GtkWidget", "add_accelerator",
655      "guint            accel_signal_id",
656      "GtkAccelGroup   *accel_group",
657      "guint            accel_key",
658      "GdkModifierType  accel_mods",
659      "GtkAccelFlags    accel_flags"},
661     {"GtkWidget", "parent_set",
662      "GtkObject       *old_parent"},
664     {"GtkWidget", "remove_accelerator",
665      "GtkAccelGroup   *accel_group",
666      "guint            accel_key",
667      "GdkModifierType  accel_mods"},
668     {"GtkWidget", "debug_msg",
669      "gchar           *message"},
670     {"GtkWindow", "move_resize",
671      "gint            *x",
672      "gint            *y",
673      "gint             width",
674      "gint             height"},
675     {"GtkWindow", "set_focus",
676      "GtkWidget       *widget"},
678     {"GtkWidget", "selection_get",
679      "GtkSelectionData *data",
680      "guint            info",
681      "guint            time"},
682     {"GtkWidget", "selection_received",
683      "GtkSelectionData *data",
684      "guint            time"},
686     {"GtkWidget", "drag_begin",
687      "GdkDragContext  *drag_context"},
688     {"GtkWidget", "drag_end",
689      "GdkDragContext  *drag_context"},
690     {"GtkWidget", "drag_data_delete",
691      "GdkDragContext  *drag_context"},
692     {"GtkWidget", "drag_leave",
693      "GdkDragContext  *drag_context",
694      "guint            time"},
695     {"GtkWidget", "drag_motion",
696      "GdkDragContext  *drag_context",
697      "gint             x",
698      "gint             y",
699      "guint            time"},
700     {"GtkWidget", "drag_drop",
701      "GdkDragContext  *drag_context",
702      "gint             x",
703      "gint             y",
704      "guint            time"},
705     {"GtkWidget", "drag_data_get",
706      "GdkDragContext  *drag_context",
707      "GtkSelectionData *data",
708      "guint            info",
709      "guint            time"},
710     {"GtkWidget", "drag_data_received",
711      "GdkDragContext  *drag_context",
712      "gint             x",
713      "gint             y",
714      "GtkSelectionData *data",
715      "guint            info",
716      "guint            time"},
718     {NULL}
719   };
721   gint i;
723   for (i = 0; GbArgTable[i][0]; i++)
724     {
725 #if 1
726       if (!strcmp (type, GbArgTable[i][0])
727           && !strcmp (signal_name, GbArgTable[i][1]))
728         return &GbArgTable[i][2];
729 #endif
730     }
731   return NULL;
734 /* This outputs the hierarchy of all widgets which have been initialized,
735    i.e. by calling their XXX_get_type() initialization function. */
736 static void
737 output_widget_hierarchy (void)
739   FILE *fp;
741   fp = fopen (hierarchy_filename, "w");
742   if (fp == NULL)
743     {
744       g_warning ("Couldn't open output file: %s", hierarchy_filename);
745       return;
746     }
747   output_hierarchy (fp, G_TYPE_OBJECT, 0);
748   output_hierarchy (fp, G_TYPE_INTERFACE, 0);
749   fclose (fp);
752 /* This is called recursively to output the hierarchy of a widget. */
753 static void
754 output_hierarchy (FILE  *fp,
755                   GType  type,
756                   gint   level)
758   guint i;
759   GType *children;
760   guint n_children;
762   if (!type)
763     return;
765   for (i = 0; i < level; i++)
766     fprintf (fp, "  ");
767   fprintf (fp, g_type_name (type));
768   fprintf (fp, "\\n");
770   children = g_type_children (type, &n_children);
772   for (i=0; i < n_children; i++)
773     output_hierarchy (fp, children[i], level + 1);
775   g_free (children);
778 static void output_widget_interfaces (void)
780   FILE *fp;
782   fp = fopen (interfaces_filename, "w");
783   if (fp == NULL)
784     {
785       g_warning ("Couldn't open output file: %s", interfaces_filename);
786       return;
787     }
788   output_interfaces (fp, G_TYPE_OBJECT);
789   fclose (fp);
792 static void
793 output_interfaces (FILE  *fp,
794                    GType  type)
796   guint i;
797   GType *children, *interfaces;
798   guint n_children, n_interfaces;
800   if (!type)
801     return;
803   interfaces = g_type_interfaces (type, &n_interfaces);
805   if (n_interfaces > 0)
806     {
807       fprintf (fp, g_type_name (type));
808       for (i=0; i < n_interfaces; i++)
809           fprintf (fp, " %s", g_type_name (interfaces[i]));
810       fprintf (fp, "\\n");
811      }
812   g_free (interfaces);
814   children = g_type_children (type, &n_children);
816   for (i=0; i < n_children; i++)
817     output_interfaces (fp, children[i]);
819   g_free (children);
822 static void output_interface_prerequisites (void)
824   FILE *fp;
826   fp = fopen (prerequisites_filename, "w");
827   if (fp == NULL)
828     {
829       g_warning ("Couldn't open output file: %s", prerequisites_filename);
830       return;
831     }
832   output_prerequisites (fp, G_TYPE_INTERFACE);
833   fclose (fp);
836 static void
837 output_prerequisites (FILE  *fp,
838                       GType  type)
840 #if GLIB_CHECK_VERSION(2,1,0)
841   guint i;
842   GType *children, *prerequisites;
843   guint n_children, n_prerequisites;
845   if (!type)
846     return;
848   prerequisites = g_type_interface_prerequisites (type, &n_prerequisites);
850   if (n_prerequisites > 0)
851     {
852       fprintf (fp, g_type_name (type));
853       for (i=0; i < n_prerequisites; i++)
854           fprintf (fp, " %s", g_type_name (prerequisites[i]));
855       fprintf (fp, "\\n");
856      }
857   g_free (prerequisites);
859   children = g_type_children (type, &n_children);
861   for (i=0; i < n_children; i++)
862     output_prerequisites (fp, children[i]);
864   g_free (children);
865 #endif
868 static void
869 output_args (void)
871   FILE *fp;
872   gint i;
874   fp = fopen (args_filename, "w");
875   if (fp == NULL)
876     {
877       g_warning ("Couldn't open output file: %s", args_filename);
878       return;
879     }
881   for (i = 0; object_types[i]; i++)
882     output_widget_args (fp, object_types[i]);
884   fclose (fp);
887 static gint
888 compare_param_specs (const void *a, const void *b)
890   GParamSpec *spec_a = *(GParamSpec **)a;
891   GParamSpec *spec_b = *(GParamSpec **)b;
893   return strcmp (g_param_spec_get_name (spec_a), g_param_spec_get_name (spec_b));
896 static void
897 output_widget_args (FILE *fp, GType object_type)
899   gpointer class;
900   const gchar *object_class_name;
901   gint arg;
902   gchar flags[16], *pos;
903   GParamSpec **properties;
904   guint n_properties;
905   gboolean child_prop;
906   gboolean style_prop;
908   if (G_TYPE_IS_CLASSED (object_type))
909     {
910       class = g_type_class_peek (object_type);
911       if (!class)
912         return;
914       properties = g_object_class_list_properties (class, &n_properties);
915     }
916 #if GLIB_MAJOR_VERSION > 2 || (GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION >= 3)
917   else if (G_TYPE_IS_INTERFACE (object_type))
918     {
919       class = g_type_default_interface_ref (object_type);
921       if (!class)
922         return;
924       properties = g_object_interface_list_properties (class, &n_properties);
925     }
926 #endif
927   else
928     return;
930   object_class_name = g_type_name (object_type);
932   child_prop = FALSE;
933   style_prop = FALSE;
935   while (TRUE) {
936     qsort (properties, n_properties, sizeof (GParamSpec *), compare_param_specs);
937     for (arg = 0; arg < n_properties; arg++)
938       {
939         GParamSpec *spec = properties[arg];
940         const gchar *nick, *blurb, *dot;
942         if (spec->owner_type != object_type)
943           continue;
945         pos = flags;
946         /* We use one-character flags for simplicity. */
947         if (child_prop && !style_prop)
948           *pos++ = 'c';
949         if (style_prop)
950           *pos++ = 's';
951         if (spec->flags & G_PARAM_READABLE)
952           *pos++ = 'r';
953         if (spec->flags & G_PARAM_WRITABLE)
954           *pos++ = 'w';
955         if (spec->flags & G_PARAM_CONSTRUCT)
956           *pos++ = 'x';
957         if (spec->flags & G_PARAM_CONSTRUCT_ONLY)
958           *pos++ = 'X';
959         *pos = 0;
961         nick = g_param_spec_get_nick (spec);
962         blurb = g_param_spec_get_blurb (spec);
964         dot = "";
965         if (blurb) {
966           int str_len = strlen (blurb);
967           if (str_len > 0  && blurb[str_len - 1] != '.')
968             dot = ".";
969         }
971         fprintf (fp, "<ARG>\\n<NAME>%s::%s</NAME>\\n<TYPE>%s</TYPE>\\n<FLAGS>%s</FLAGS>\\n<NICK>%s</NICK>\\n<BLURB>%s%s</BLURB>\\n</ARG>\\n\\n",
972                  object_class_name, g_param_spec_get_name (spec), g_type_name (spec->value_type), flags, nick ? nick : "(null)", blurb ? blurb : "(null)", dot);
973       }
975     g_free (properties);
977 #ifdef GTK_IS_CONTAINER_CLASS
978     if (!child_prop && GTK_IS_CONTAINER_CLASS (class)) {
979       properties = gtk_container_class_list_child_properties (class, &n_properties);
980       child_prop = TRUE;
981       continue;
982     }
983 #endif
985 #ifdef GTK_IS_WIDGET_CLASS
986 #if GTK_CHECK_VERSION(2,1,0)
987     if (!style_prop && GTK_IS_WIDGET_CLASS (class)) {
988       properties = gtk_widget_class_list_style_properties (GTK_WIDGET_CLASS (class), &n_properties);
989       style_prop = TRUE;
990       continue;
991     }
992 #endif
993 #endif
995     break;
996   }
1000 close OUTPUT;
1002 # Compile and run our file
1004 $CC = $ENV{CC} ? $ENV{CC} : "gcc";
1005 $LD = $ENV{LD} ? $ENV{LD} : $CC;
1006 $CFLAGS = $ENV{CFLAGS} ? $ENV{CFLAGS} : "";
1007 $LDFLAGS = $ENV{LDFLAGS} ? $ENV{LDFLAGS} : "";
1009 my $o_file;
1010 if ($CC =~ /libtool/) {
1011   $o_file  = "$MODULE-scan.lo"
1012 } else {
1013   $o_file = "$MODULE-scan.o"
1016 $command = "$CC $CFLAGS -c -o $o_file $MODULE-scan.c && $LD -o $MODULE-scan $o_file $LDFLAGS";
1018 system($command) == 0 or die "Compilation of scanner failed\n";
1020 system("./$MODULE-scan") == 0 or die "Scan failed\n";
1022 unlink "./$MODULE-scan.c", "./$MODULE-scan.o", "./$MODULE-scan.lo", "./$MODULE-scan";
1024 &UpdateFileIfChanged ($old_signals_filename, $new_signals_filename, 0);
1025 &UpdateFileIfChanged ($old_hierarchy_filename, $new_hierarchy_filename, 0);
1026 &UpdateFileIfChanged ($old_interfaces_filename, $new_interfaces_filename, 0);
1027 &UpdateFileIfChanged ($old_prerequisites_filename, $new_prerequisites_filename, 0);
1028 &UpdateFileIfChanged ($old_args_filename, $new_args_filename, 0);