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