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.
33 unshift @INC, '@PACKAGE_DATA_DIR@';
34 require "gtkdoc-common.pl";
38 # name of documentation module
43 %optctl = (module => \$MODULE,
44 types => \$TYPES_FILE,
45 nogtkinit => \$NO_GTK_INIT,
46 'output-dir' => \$OUTPUT_DIR,
47 'version' => \$PRINT_VERSION);
49 GetOptions(\%optctl, "module=s", "types:s", "output-dir:s", "nogtkinit", "version");
56 $OUTPUT_DIR = $OUTPUT_DIR ? $OUTPUT_DIR : ".";
58 $TYPES_FILE = $TYPES_FILE ? $TYPES_FILE : "$OUTPUT_DIR/$MODULE.types";
60 open (TYPES, $TYPES_FILE) || die "Cannot open $TYPES_FILE: $!\n";
61 open (OUTPUT, ">$MODULE-scan.c") || die "Cannot open $MODULE-scan.c: $!\n";
63 my $old_signals_filename = "$OUTPUT_DIR/$MODULE.signals";
64 my $new_signals_filename = "$OUTPUT_DIR/$MODULE.signals.new";
65 my $old_hierarchy_filename = "$OUTPUT_DIR/$MODULE.hierarchy";
66 my $new_hierarchy_filename = "$OUTPUT_DIR/$MODULE.hierarchy.new";
67 my $old_args_filename = "$OUTPUT_DIR/$MODULE.args";
68 my $new_args_filename = "$OUTPUT_DIR/$MODULE.args.new";
70 # write a C program to scan the types
97 GtkType object_types[$ntypes];
100 get_object_types (void)
106 print OUTPUT " object_types[i++] = $_ ();\n";
116 * This uses GTK type functions to output signal prototypes and the widget
120 /* The output files */
121 gchar *signals_filename = "$new_signals_filename";
122 gchar *hierarchy_filename = "$new_hierarchy_filename";
123 gchar *args_filename = "$new_args_filename";
126 static void output_signals (void);
127 static void output_widget_signals (FILE *fp,
128 GtkType object_type);
129 static void output_widget_signal (FILE *fp,
131 gchar *object_class_name,
133 static gchar * get_type_name (GtkType type,
134 gboolean * is_pointer);
135 static gchar * get_gdk_event (const gchar * signal_name);
136 static gchar ** lookup_signal_arg_names (gchar * type,
137 const gchar * signal_name);
139 static void output_widget_hierarchy (void);
140 static void output_hierarchy (FILE *fp,
144 static void output_args (void);
145 static void output_widget_args (FILE *fp, GtkType object_type);
148 main (int argc, char *argv[])
158 gtk_init (&argc, &argv);
166 output_widget_hierarchy ();
174 output_signals (void)
179 fp = fopen (signals_filename, "w");
182 g_warning ("Couldn't open output file: %s : %s", signals_filename, strerror(errno));
186 for (i = 0; object_types[i]; i++)
187 output_widget_signals (fp, object_types[i]);
193 /* This outputs all the signals of one widget. */
195 output_widget_signals (FILE *fp, GtkType object_type)
197 GtkObjectClass *class;
198 gchar *object_class_name;
201 class = gtk_type_class (object_type);
202 if (!class || class->nsignals == 0)
205 object_class_name = gtk_type_name (object_type);
207 for (sig = 0; sig < class->nsignals; sig++)
209 if (!class->signals[sig])
211 /*g_print ("Signal slot [%u] is empty\\n", sig);*/
215 output_widget_signal (fp, object_type, object_class_name,
216 class->signals[sig]);
221 /* This outputs one signal. */
223 output_widget_signal (FILE *fp,
228 GtkSignalQuery *query_info;
229 gchar *ret_type, *pos, *type_name, *arg_name, *object_arg, *object_arg_start;
231 gchar ret_type_buffer[1024], buffer[1024];
234 gint param_num, widget_num, event_num, callback_num;
236 gchar signal_name[128];
239 /* g_print ("Object: %s Type: %i Signal: %u\\n", object_name, object_type,
243 widget_num = event_num = callback_num = 0;
245 query_info = gtk_signal_query (signal_id);
246 if (query_info == NULL)
248 g_warning ("Couldn't query signal");
252 /* Output the return type and function name. */
253 ret_type = get_type_name (query_info->return_val, &is_pointer);
254 sprintf (ret_type_buffer, "%s%s", ret_type, is_pointer ? "*" : "");
256 /* Output the signal object type and the argument name. We assume the
257 type is a pointer - I think that is OK. We remove "Gtk" or "Gnome" and
258 convert to lower case for the argument name. */
260 sprintf (pos, "%s ", object_name);
263 if (!strncmp (object_name, "Gtk", 3))
264 object_arg = object_name + 3;
265 else if (!strncmp (object_name, "Gnome", 5))
266 object_arg = object_name + 5;
268 object_arg = object_name;
270 object_arg_start = pos;
271 sprintf (pos, "*%s\\n", object_arg);
273 g_strdown (object_arg_start);
274 if (!strcmp (object_arg_start, "widget"))
277 /* Convert signal name to use underscores rather than dashes '-'. */
278 strcpy (signal_name, query_info->signal_name);
279 for (i = 0; signal_name[i]; i++)
281 if (signal_name[i] == '-')
282 signal_name[i] = '_';
285 /* Output the signal parameters. */
286 arg_names = lookup_signal_arg_names (object_name, signal_name);
288 for (param = 0; param < query_info->nparams; param++)
292 sprintf (pos, "%s\\n", arg_names[param]);
297 type_name = get_type_name (query_info->params[param], &is_pointer);
299 /* Most arguments to the callback are called "arg1", "arg2", etc.
300 GdkWidgets are called "widget", "widget2", ...
301 GdkEvents are called "event", "event2", ...
302 GtkCallbacks are called "callback", "callback2", ... */
303 if (!strcmp (type_name, "GtkWidget"))
306 arg_num = &widget_num;
308 else if (!strcmp (type_name, "GdkEvent"))
310 type_name = get_gdk_event (signal_name);
312 arg_num = &event_num;
315 else if (!strcmp (type_name, "GtkCallback")
316 || !strcmp (type_name, "GtkCCallback"))
318 arg_name = "callback";
319 arg_num = &callback_num;
324 arg_num = ¶m_num;
326 sprintf (pos, "%s ", type_name);
329 if (!arg_num || *arg_num == 0)
330 sprintf (pos, "%s%s\\n", is_pointer ? "*" : " ", arg_name);
332 sprintf (pos, "%s%s%i\\n", is_pointer ? "*" : " ", arg_name,
342 "<SIGNAL>\\n<NAME>%s::%s</NAME>\\n<RETURNS>%s</RETURNS>\\n%s</SIGNAL>\\n\\n",
343 object_name, query_info->signal_name, ret_type_buffer, buffer);
348 /* Returns the type name to use for a signal argument or return value, given
349 the GtkType from the signal info. It also sets is_pointer to TRUE if the
350 argument needs a '*' since it is a pointer. */
352 get_type_name (GtkType type, gboolean * is_pointer)
357 type_name = gtk_type_name (type);
369 case GTK_TYPE_DOUBLE:
370 case GTK_TYPE_POINTER:
371 /* These all have normal C type names so they are OK. */
374 case GTK_TYPE_STRING:
375 /* A GtkString is really a gchar*. */
381 /* We use a gint for both of these. Hopefully a subtype with a decent
382 name will be registered and used instead, as GTK+ does itself. */
386 /* A boxed value is just an opaque pointer, I think. */
389 case GTK_TYPE_SIGNAL:
391 case GTK_TYPE_FOREIGN:
392 case GTK_TYPE_CALLBACK:
393 case GTK_TYPE_C_CALLBACK:
394 /* FIXME: These are wrong. I think they expand into more than 1 argument.
395 See the GtkArg struct in gtktypeutils.h and gtkargcollector.c.
396 Fortunately I doubt anything uses these as signal args. */
403 /* For all GtkObject subclasses we can use the class name with a "*",
404 e.g. 'GtkWidget *'. */
405 if (gtk_type_is_a (type, GTK_TYPE_OBJECT))
413 get_gdk_event (const gchar * signal_name)
415 static gchar *GbGDKEvents[] =
417 "button_press_event", "GdkEventButton",
418 "button_release_event", "GdkEventButton",
419 "motion_notify_event", "GdkEventMotion",
420 "delete_event", "GdkEvent",
421 "destroy_event", "GdkEvent",
422 "expose_event", "GdkEventExpose",
423 "key_press_event", "GdkEventKey",
424 "key_release_event", "GdkEventKey",
425 "enter_notify_event", "GdkEventCrossing",
426 "leave_notify_event", "GdkEventCrossing",
427 "configure_event", "GdkEventConfigure",
428 "focus_in_event", "GdkEventFocus",
429 "focus_out_event", "GdkEventFocus",
430 "map_event", "GdkEvent",
431 "unmap_event", "GdkEvent",
432 "property_notify_event", "GdkEventProperty",
433 "selection_clear_event", "GdkEventSelection",
434 "selection_request_event", "GdkEventSelection",
435 "selection_notify_event", "GdkEventSelection",
436 "proximity_in_event", "GdkEventProximity",
437 "proximity_out_event", "GdkEventProximity",
438 "drag_begin_event", "GdkEventDragBegin",
439 "drag_request_event", "GdkEventDragRequest",
440 "drag_end_event", "GdkEventDragRequest",
441 "drop_enter_event", "GdkEventDropEnter",
442 "drop_leave_event", "GdkEventDropLeave",
443 "drop_data_available_event", "GdkEventDropDataAvailable",
444 "other_event", "GdkEventOther",
445 "client_event", "GdkEventClient",
446 "no_expose_event", "GdkEventNoExpose",
447 "visibility_notify_event", "GdkEventVisibility",
448 "window_state_event", "GdkEventWindowState",
449 "scroll_event", "GdkEventScroll",
455 for (i = 0; GbGDKEvents[i]; i += 2)
457 if (!strcmp (signal_name, GbGDKEvents[i]))
458 return GbGDKEvents[i + 1];
464 /* This returns argument names to use for some known GTK signals.
465 It is passed a widget name, e.g. 'GtkCList' and a signal name, e.g.
466 'select_row' and it returns a pointer to an array of argument types and
469 lookup_signal_arg_names (gchar * type, const gchar * signal_name)
471 /* Each arg array starts with the object type name and the signal name,
472 and then signal arguments follow. */
473 static gchar *GbArgTable[][16] =
475 {"GtkCList", "select_row",
478 "GdkEventButton *event"},
479 {"GtkCList", "unselect_row",
482 "GdkEventButton *event"},
483 {"GtkCList", "click_column",
486 {"GtkCList", "resize_column",
490 {"GtkCList", "extend_selection",
491 "GtkScrollType scroll_type",
493 "gboolean auto_start_selection"},
494 {"GtkCList", "scroll_vertical",
495 "GtkScrollType scroll_type",
497 {"GtkCList", "scroll_horizontal",
498 "GtkScrollType scroll_type",
500 {"GtkContainer", "focus",
501 "GtkDirectionType direction"},
502 {"GtkCTree", "tree_select_row",
505 {"GtkCTree", "tree_unselect_row",
509 {"GtkCTree", "tree_expand",
511 {"GtkCTree", "tree_collapse",
513 {"GtkCTree", "tree_move",
516 "GList *new_sibling"},
517 {"GtkCTree", "change_focus_row_expansion",
518 "GtkCTreeExpansionType expansion"},
520 {"GtkEditable", "insert_text",
522 "gint new_text_length",
524 {"GtkEditable", "delete_text",
527 {"GtkEditable", "set_editable",
528 "gboolean is_editable"},
529 {"GtkEditable", "move_cursor",
532 {"GtkEditable", "move_word",
534 {"GtkEditable", "move_page",
537 {"GtkEditable", "move_to_row",
539 {"GtkEditable", "move_to_column",
542 {"GtkEditable", "kill_char",
544 {"GtkEditable", "kill_word",
546 {"GtkEditable", "kill_line",
550 {"GtkInputDialog", "enable_device",
552 {"GtkInputDialog", "disable_device",
555 {"GtkListItem", "extend_selection",
556 "GtkScrollType scroll_type",
558 "gboolean auto_start_selection"},
559 {"GtkListItem", "scroll_vertical",
560 "GtkScrollType scroll_type",
562 {"GtkListItem", "scroll_horizontal",
563 "GtkScrollType scroll_type",
566 {"GtkMenuShell", "move_current",
567 "GtkMenuDirectionType direction"},
568 {"GtkMenuShell", "activate_current",
569 "gboolean force_hide"},
572 {"GtkNotebook", "switch_page",
573 "GtkNotebookPage *page",
575 {"GtkStatusbar", "text_pushed",
578 {"GtkStatusbar", "text_popped",
581 {"GtkTipsQuery", "widget_entered",
584 "gchar *tip_private"},
585 {"GtkTipsQuery", "widget_selected",
588 "gchar *tip_private",
589 "GdkEventButton *event"},
590 {"GtkToolbar", "orientation_changed",
591 "GtkOrientation orientation"},
592 {"GtkToolbar", "style_changed",
593 "GtkToolbarStyle style"},
594 {"GtkWidget", "draw",
595 "GdkRectangle *area"},
596 {"GtkWidget", "size_request",
597 "GtkRequisition *requisition"},
598 {"GtkWidget", "size_allocate",
599 "GtkAllocation *allocation"},
600 {"GtkWidget", "state_changed",
601 "GtkStateType state"},
602 {"GtkWidget", "style_set",
603 "GtkStyle *previous_style"},
605 {"GtkWidget", "install_accelerator",
606 "gchar *signal_name",
610 {"GtkWidget", "add_accelerator",
611 "guint accel_signal_id",
612 "GtkAccelGroup *accel_group",
614 "GdkModifierType accel_mods",
615 "GtkAccelFlags accel_flags"},
617 {"GtkWidget", "parent_set",
618 "GtkObject *old_parent"},
620 {"GtkWidget", "remove_accelerator",
621 "GtkAccelGroup *accel_group",
623 "GdkModifierType accel_mods"},
624 {"GtkWidget", "debug_msg",
626 {"GtkWindow", "move_resize",
631 {"GtkWindow", "set_focus",
632 "GtkWidget *widget"},
634 {"GtkWidget", "selection_get",
635 "GtkSelectionData *data",
638 {"GtkWidget", "selection_received",
639 "GtkSelectionData *data",
642 {"GtkWidget", "drag_begin",
643 "GdkDragContext *drag_context"},
644 {"GtkWidget", "drag_end",
645 "GdkDragContext *drag_context"},
646 {"GtkWidget", "drag_data_delete",
647 "GdkDragContext *drag_context"},
648 {"GtkWidget", "drag_leave",
649 "GdkDragContext *drag_context",
651 {"GtkWidget", "drag_motion",
652 "GdkDragContext *drag_context",
656 {"GtkWidget", "drag_drop",
657 "GdkDragContext *drag_context",
661 {"GtkWidget", "drag_data_get",
662 "GdkDragContext *drag_context",
663 "GtkSelectionData *data",
666 {"GtkWidget", "drag_data_received",
667 "GdkDragContext *drag_context",
670 "GtkSelectionData *data",
679 for (i = 0; GbArgTable[i][0]; i++)
681 if (!strcmp (type, GbArgTable[i][0])
682 && !strcmp (signal_name, GbArgTable[i][1]))
683 return &GbArgTable[i][2];
689 /* This outputs the hierarchy of all widgets which have been initialized,
690 i.e. by calling their XXX_get_type() initialization function. */
692 output_widget_hierarchy (void)
696 fp = fopen (hierarchy_filename, "w");
699 g_warning ("Couldn't open output file: %s : %s", hierarchy_filename, strerror(errno));
702 output_hierarchy (fp, GTK_TYPE_OBJECT, 0);
707 /* This is called recursively to output the hierarchy of a widget. */
709 output_hierarchy (FILE *fp,
719 for (i = 0; i < level; i++)
721 fprintf (fp, "%s\\n", gtk_type_name (type));
723 list = gtk_type_children_types (type);
727 GtkType child = (GtkType) list->data;
728 output_hierarchy (fp, child, level + 1);
740 fp = fopen (args_filename, "w");
743 g_warning ("Couldn't open output file: %s : %s", args_filename, strerror(errno));
747 for (i = 0; object_types[i]; i++)
748 output_widget_args (fp, object_types[i]);
755 output_widget_args (FILE *fp, GtkType object_type)
757 GtkObjectClass *class;
758 gchar *object_class_name;
763 gchar flags[16], *pos;
765 class = gtk_type_class (object_type);
769 object_class_name = gtk_type_name (object_type);
771 args = gtk_object_query_args (class->type, &arg_flags, &n_args);
773 for (arg = 0; arg < n_args; arg++)
776 /* We use one-character flags for simplicity. */
777 if (arg_flags[arg] & GTK_ARG_READABLE)
779 if (arg_flags[arg] & GTK_ARG_WRITABLE)
781 if (arg_flags[arg] & GTK_ARG_CONSTRUCT)
783 if (arg_flags[arg] & GTK_ARG_CONSTRUCT_ONLY)
785 if (arg_flags[arg] & GTK_ARG_CHILD_ARG)
789 fprintf (fp, "<ARG>\\n<NAME>%s</NAME>\\n<TYPE>%s</TYPE>\\n<FLAGS>%s</FLAGS>\\n</ARG>\\n\\n",
790 args[arg].name, gtk_type_name (args[arg].type), flags);
800 # Compile and run our file
802 $CC = $ENV{CC} ? $ENV{CC} : "gcc";
803 $LD = $ENV{LD} ? $ENV{LD} : $CC;
804 $CFLAGS = $ENV{CFLAGS} ? $ENV{CFLAGS} : "";
805 $LDFLAGS = $ENV{LDFLAGS} ? $ENV{LDFLAGS} : "";
808 if ($CC =~ /libtool/) {
809 $o_file = "$MODULE-scan.lo"
811 $o_file = "$MODULE-scan.o"
814 print "gtk-doc: Compiling scanner\n";
815 $command = "$CC $CFLAGS -c -o $o_file $MODULE-scan.c";
816 system($command) == 0 or die "Compilation of scanner failed: $!\n";
818 print "gtk-doc: Linking scanner\n";
819 $command = "$LD -o $MODULE-scan $o_file $LDFLAGS";
820 system($command) == 0 or die "Linking of scanner failed: $!\n";
822 print "gtk-doc: Running scanner $MODULE-scan\n";
823 system("sh -c ./$MODULE-scan") == 0 or die "Scan failed: $!\n";
825 unlink "./$MODULE-scan.c", "./$MODULE-scan.o", "./$MODULE-scan.lo", "./$MODULE-scan";
827 &UpdateFileIfChanged ($old_signals_filename, $new_signals_filename, 0);
828 &UpdateFileIfChanged ($old_hierarchy_filename, $new_hierarchy_filename, 0);
829 &UpdateFileIfChanged ($old_args_filename, $new_args_filename, 0);