blob: 906857c99425b2b61131a7c6cdc188171076f09a [file] [log] [blame]
Olivier Naudan2556a702012-04-16 08:57:32 -04001#!/usr/bin/env perl
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
Sebastian Dröge6bf128e2013-07-14 12:07:04 +020019# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
Olivier Naudan2556a702012-04-16 08:57:32 -040020#
21
22#
23# This gets information about object hierarchies and signals
24# by compiling a small C program. CFLAGS and LDFLAGS must be
25# set appropriately before running this script.
26#
27
28use Getopt::Long;
29
30my $GTK_DOC_PREFIX=`pkg-config --variable prefix gtk-doc`;
31if ($GTK_DOC_PREFIX) {
32 chomp $GTK_DOC_PREFIX;
33 #print "Adding $GTK_DOC_PREFIX/share/gtk-doc/data to \@INC\n";
34 unshift @INC, "$GTK_DOC_PREFIX/share/gtk-doc/data";
35} else {
36 unshift @INC, '/usr/share/gtk-doc/data';
37}
38require "gtkdoc-common.pl";
39
40# Options
41
42# name of documentation module
43my $MODULE;
44my $OUTPUT_DIR;
45my $INSPECT_DIR;
46my $VERBOSE;
47my $PRINT_VERSION;
48my $PRINT_HELP;
49my $TYPE_INIT_FUNC="g_type_init ()";
50
51# --nogtkinit is deprecated, as it is the default now anyway.
52%optctl = (module => \$MODULE,
53 source => \$SOURCE,
54 types => \$TYPES_FILE,
55 nogtkinit => \$NO_GTK_INIT,
56 'type-init-func' => \$TYPE_INIT_FUNC,
57 'output-dir' => \$OUTPUT_DIR,
58 'inspect-dir' => \$INSPECT_DIR,
59 'verbose' => \$VERBOSE,
60 'version' => \$PRINT_VERSION,
61 'help' => \$PRINT_HELP);
62
63GetOptions(\%optctl, "module=s", "source=s", "types:s", "output-dir:s", "inspect-dir:s", "nogtkinit", "type-init-func:s", "verbose", "version", "help");
64
65if ($NO_GTK_INIT) {
66 # Do nothing. This just avoids a warning.
67 # the option is not used anymore
68}
69
70if ($PRINT_VERSION) {
71 print "1.5\n";
72 exit 0;
73}
74
75if (!$MODULE) {
76 $PRINT_HELP = 1;
77}
78
79if ($PRINT_HELP) {
80 print <<EOF;
81gstdoc-scangobj version 1.5 - introspect gstreamer-plugins
82
83--module=MODULE_NAME Name of the doc module being parsed
84--source=SOURCE_NAME Name of the source module for plugins
85--types=FILE The name of the file to store the types in
86--type-init-func=FUNC The init function to call instead of g_type_init()
87--output-dir=DIRNAME The directory where the results are stored
88--inspect-dir=DIRNAME The directory where the plugin inspect data is stored
89--verbose Print extra output while processing
90--version Print the version of this program
91--help Print this help
92EOF
93 exit 0;
94}
95
96$OUTPUT_DIR = $OUTPUT_DIR ? $OUTPUT_DIR : ".";
97
98$TYPES_FILE = $TYPES_FILE ? $TYPES_FILE : "$OUTPUT_DIR/$MODULE.types";
99
100open (TYPES, $TYPES_FILE) || die "Cannot open $TYPES_FILE: $!\n";
101open (OUTPUT, ">$MODULE-scan.c") || die "Cannot open $MODULE-scan.c: $!\n";
102
103my $old_signals_filename = "$OUTPUT_DIR/$MODULE.signals";
104my $new_signals_filename = "$OUTPUT_DIR/$MODULE.signals.new";
105my $old_hierarchy_filename = "$OUTPUT_DIR/$MODULE.hierarchy";
106my $new_hierarchy_filename = "$OUTPUT_DIR/$MODULE.hierarchy.new";
107my $old_interfaces_filename = "$OUTPUT_DIR/$MODULE.interfaces";
108my $new_interfaces_filename = "$OUTPUT_DIR/$MODULE.interfaces.new";
109my $old_prerequisites_filename = "$OUTPUT_DIR/$MODULE.prerequisites";
110my $new_prerequisites_filename = "$OUTPUT_DIR/$MODULE.prerequisites.new";
111my $old_args_filename = "$OUTPUT_DIR/$MODULE.args";
112my $new_args_filename = "$OUTPUT_DIR/$MODULE.args.new";
Sebastian Dröged8a669d2015-08-19 14:01:25 +0300113my $old_sections_filename = "$OUTPUT_DIR/$MODULE-sections";
114my $new_sections_filename = "$OUTPUT_DIR/$MODULE-sections.new";
Olivier Naudan2556a702012-04-16 08:57:32 -0400115
116my $debug_log="g_message";
117if (!defined($VERBOSE) or $VERBOSE eq "0") {
118 $debug_log="//$debug_log";
119}
120
121# write a C program to scan the types
122
123$includes = "";
124@types = ();
125@impl_types = ();
126
127for (<TYPES>) {
128 if (/^#include/) {
129 $includes .= $_;
130 } elsif (/^%/) {
131 next;
132 } elsif (/^\s*$/) {
133 next;
134 } elsif (/^type:(.*)$/) {
135 $t = $1;
136 chomp $t;
137 push @impl_types, $t;
138 } else {
139 chomp;
140 push @types, $_;
141 }
142}
143
144$ntypes = @types + @impl_types + 1;
145
146print OUTPUT <<EOT;
147
148/* file generated by common/gstdoc-scangobj */
149
150#include <string.h>
151#include <stdlib.h>
152#include <stdio.h>
153#include <errno.h>
154
Sebastian Drögef10bf612014-05-03 19:34:29 +0200155#include <gst/gst.h>
156EOT
157
158if ($includes) {
159 print OUTPUT $includes;
160} else {
161 for (@types) {
162 print OUTPUT "extern GType $_ (void);\n";
163 }
164}
165
166print OUTPUT <<EOT;
Olivier Naudan2556a702012-04-16 08:57:32 -0400167
168#ifdef GTK_IS_WIDGET_CLASS
169#include <gtk/gtkversion.h>
170#endif
171
172static GType *object_types = NULL;
173
174static GString *xmlstr = NULL;
175
176static const gchar*
177xmlprint (gint indent, const gchar *tag, const gchar *data)
178{
179 const gchar indent_str[] = " ";
180
181 /* reset */
182 g_string_truncate (xmlstr, 0);
183 g_string_append_len (xmlstr, indent_str, MIN (indent, strlen (indent_str)));
184 g_string_append_printf (xmlstr, "<%s>", tag);
185
186 if (data) {
187 gchar *s;
188
189 s = g_markup_escape_text (data, -1);
190 g_string_append (xmlstr, s);
191 g_free (s);
192 }
193
194 g_string_append_printf (xmlstr, "</%s>\\n", tag);
195 return xmlstr->str;
196}
197
198static gint
199gst_feature_sort_compare (gconstpointer a, gconstpointer b)
200{
201 const gchar *name_a = gst_plugin_feature_get_name ((GstPluginFeature *) a);
202 const gchar *name_b = gst_plugin_feature_get_name ((GstPluginFeature *) b);
203 return strcmp (name_a, name_b);
204}
205
206static gint
207static_pad_template_compare (gconstpointer a, gconstpointer b)
208{
209 GstStaticPadTemplate *spt_a = (GstStaticPadTemplate *) a;
210 GstStaticPadTemplate *spt_b = (GstStaticPadTemplate *) b;
211
212 /* we want SINK before SRC (enum is UNKNOWN, SRC, SINK) */
213 if (spt_a->direction != spt_b->direction)
214 return spt_b->direction - spt_a->direction;
215
216 /* we want ALWAYS first, SOMETIMES second, REQUEST last
217 * (enum is ALWAYS, SOMETIMES, REQUEST) */
218 if (spt_a->presence != spt_b->presence)
219 return spt_a->presence - spt_b->presence;
220
221 return strcmp (spt_a->name_template, spt_b->name_template);
222}
223
224static GType *
225get_object_types (void)
226{
227 gpointer g_object_class;
228 GList *plugins = NULL;
229 GList *factories = NULL;
230 GList *l;
231 GstElementFactory *factory = NULL;
232 GType type;
233 gint i = 0;
234 gboolean reinspect;
235
236 /* get a list of features from plugins in our source module */
237 plugins = gst_registry_get_plugin_list (gst_registry_get ());
238
239 xmlstr = g_string_new ("");
240
241 reinspect = !g_file_test ("scanobj-build.stamp", G_FILE_TEST_EXISTS);
242
243 while (plugins) {
244 GList *features;
245 GstPlugin *plugin;
246 const gchar *source;
247 FILE *inspect = NULL;
248 gchar *inspect_name;
249
250 plugin = (GstPlugin *) (plugins->data);
251 plugins = g_list_next (plugins);
252 source = gst_plugin_get_source (plugin);
253 if (!source || strcmp (source, "$SOURCE") != 0) {
254 continue;
255 }
256
257 /* skip static coreelements plugin with pipeline and bin element factory */
258 if (gst_plugin_get_filename (plugin) == NULL)
259 continue;
260
Sebastian Dröge1e844f12012-06-08 13:25:41 +0200261 $debug_log ("plugin: %s source: %s", gst_plugin_get_name (plugin), source);
Olivier Naudan2556a702012-04-16 08:57:32 -0400262
263 if (reinspect) {
Sebastian Dröge1e844f12012-06-08 13:25:41 +0200264 gchar *basename;
265
Olivier Naudan2556a702012-04-16 08:57:32 -0400266 inspect_name = g_strdup_printf ("$INSPECT_DIR" G_DIR_SEPARATOR_S "plugin-%s.xml",
Sebastian Dröge1e844f12012-06-08 13:25:41 +0200267 gst_plugin_get_name (plugin));
Olivier Naudan2556a702012-04-16 08:57:32 -0400268 inspect = fopen (inspect_name, "w");
269 if (inspect == NULL) {
270 g_error ("Could not open %s for writing: %s\\n", inspect_name,
271 g_strerror (errno));
272 }
273 g_free (inspect_name);
274
Sebastian Dröge1e844f12012-06-08 13:25:41 +0200275 basename = g_path_get_basename (gst_plugin_get_filename (plugin));
276
Olivier Naudan2556a702012-04-16 08:57:32 -0400277 /* output plugin data */
278 fputs ("<plugin>\\n",inspect);
Sebastian Dröge1e844f12012-06-08 13:25:41 +0200279 fputs (xmlprint(2, "name", gst_plugin_get_name (plugin)),inspect);
280 fputs (xmlprint(2, "description", gst_plugin_get_description (plugin)),inspect);
281 fputs (xmlprint(2, "filename", gst_plugin_get_filename (plugin)),inspect);
282 fputs (xmlprint(2, "basename", basename),inspect);
283 fputs (xmlprint(2, "version", gst_plugin_get_version (plugin)),inspect);
284 fputs (xmlprint(2, "license", gst_plugin_get_license (plugin)),inspect);
285 fputs (xmlprint(2, "source", gst_plugin_get_source (plugin)),inspect);
286 fputs (xmlprint(2, "package", gst_plugin_get_package (plugin)),inspect);
287 fputs (xmlprint(2, "origin", gst_plugin_get_origin (plugin)),inspect);
Olivier Naudan2556a702012-04-16 08:57:32 -0400288 fputs (" <elements>\\n", inspect);
Sebastian Dröge1e844f12012-06-08 13:25:41 +0200289
290 g_free (basename);
Olivier Naudan2556a702012-04-16 08:57:32 -0400291 }
292
293 features =
294 gst_registry_get_feature_list_by_plugin (gst_registry_get (),
Sebastian Dröge1e844f12012-06-08 13:25:41 +0200295 gst_plugin_get_name (plugin));
Olivier Naudan2556a702012-04-16 08:57:32 -0400296
297 /* sort factories by feature->name */
298 features = g_list_sort (features, gst_feature_sort_compare);
299
300 while (features) {
301 GstPluginFeature *feature;
302 feature = GST_PLUGIN_FEATURE (features->data);
303 feature = gst_plugin_feature_load (feature);
304 if (!feature) {
305 g_warning ("Could not load plugin feature %s",
306 gst_plugin_feature_get_name (feature));
307 }
308
309 if (GST_IS_ELEMENT_FACTORY (feature)) {
310 const gchar *pad_dir[] = { "unknown","source","sink" };
311 const gchar *pad_pres[] = { "always","sometimes","request" };
312 GList *pads, *pad;
313
314 $debug_log (" feature: %s", gst_plugin_feature_get_name (feature));
315
316 factory = GST_ELEMENT_FACTORY (feature);
317 factories = g_list_prepend (factories, factory);
318
319 if (reinspect) {
320 /* output element data */
321 fputs (" <element>\\n", inspect);
322 fputs (xmlprint(6, "name", gst_plugin_feature_get_name (feature)),inspect);
Sebastian Dröge6bf128e2013-07-14 12:07:04 +0200323 fputs (xmlprint(6, "longname", gst_element_factory_get_metadata (factory, GST_ELEMENT_METADATA_LONGNAME)),inspect);
324 fputs (xmlprint(6, "class", gst_element_factory_get_metadata (factory, GST_ELEMENT_METADATA_KLASS)),inspect);
325 fputs (xmlprint(6, "description", gst_element_factory_get_metadata (factory, GST_ELEMENT_METADATA_DESCRIPTION)),inspect);
326 fputs (xmlprint(6, "author", gst_element_factory_get_metadata (factory, GST_ELEMENT_METADATA_AUTHOR)),inspect);
Olivier Naudan2556a702012-04-16 08:57:32 -0400327 fputs (" <pads>\\n", inspect);
328
329 /* output pad-template data */
330 pads = g_list_copy ((GList *) gst_element_factory_get_static_pad_templates (factory));
331 pads = g_list_sort (pads, static_pad_template_compare);
332 for (pad = pads; pad != NULL; pad = pad->next) {
333 GstStaticPadTemplate *pt = pad->data;
334
335 fputs (" <caps>\\n", inspect);
336 fputs (xmlprint(10, "name", pt->name_template),inspect);
337 fputs (xmlprint(10, "direction", pad_dir[pt->direction]),inspect);
338 fputs (xmlprint(10, "presence", pad_pres[pt->presence]),inspect);
339 fputs (xmlprint(10, "details", pt->static_caps.string),inspect);
340 fputs (" </caps>\\n", inspect);
341 }
342 g_list_free (pads);
343 fputs (" </pads>\\n </element>\\n", inspect);
344 }
345 }
346 features = g_list_next (features);
347 }
348
349 if (reinspect) {
350 fputs (" </elements>\\n</plugin>", inspect);
351 fclose (inspect);
352 }
353 }
354
355 g_string_free (xmlstr, TRUE);
356
357 $debug_log ("number of element factories: %d", g_list_length (factories));
358
359 /* allocate the object_types array to hold them */
360 object_types = g_new0 (GType, g_list_length (factories)+$ntypes+1);
361
362 l = factories;
363 i = 0;
364
365 /* fill it */
366 while (l) {
367 factory = GST_ELEMENT_FACTORY (l->data);
368 type = gst_element_factory_get_element_type (factory);
369 if (type != 0) {
Sebastian Dröge6bf128e2013-07-14 12:07:04 +0200370 $debug_log ("adding type for factory %s", gst_element_factory_get_metadata (factory, GST_ELEMENT_METADATA_LONGNAME));
Olivier Naudan2556a702012-04-16 08:57:32 -0400371 object_types[i++] = type;
372 } else {
373 g_message ("type info for factory %s not found",
Sebastian Dröge6bf128e2013-07-14 12:07:04 +0200374 gst_element_factory_get_metadata (factory, GST_ELEMENT_METADATA_LONGNAME));
Olivier Naudan2556a702012-04-16 08:57:32 -0400375 }
376 l = g_list_next (l);
377 }
378
379EOT
380
381# get_type functions:
382for (@types) {
383print OUTPUT <<EOT;
384 type = $_ ();
385 if (type == 0) {
386 g_message ("$_ () didn't return a valid type");
387 }
388 else {
389 object_types[i++] = type;
390 }
391EOT
392}
393
394# Implicit types retrieved from GLib:
395for (@impl_types) {
396print OUTPUT <<EOT;
397 type = g_type_from_name ("$_");
398 if (type == 0) {
399 g_message ("Implicit type $_ not found");
400 }
401 else {
402 object_types[i++] = type;
403 }
404EOT
405}
406
407print OUTPUT <<EOT;
408
409 object_types[i] = 0;
410
411 /* reference the GObjectClass to initialize the param spec pool
412 * potentially needed by interfaces. See http://bugs.gnome.org/571820 */
413 g_object_class = g_type_class_ref (G_TYPE_OBJECT);
414
415 /* Need to make sure all the types are loaded in and initialize
416 * their signals and properties.
417 */
418 for (i=0; object_types[i]; i++)
419 {
420 if (G_TYPE_IS_CLASSED (object_types[i]))
421 g_type_class_ref (object_types[i]);
422 if (G_TYPE_IS_INTERFACE (object_types[i]))
423 g_type_default_interface_ref (object_types[i]);
424 }
425
426 g_type_class_unref (g_object_class);
427
428 return object_types;
429}
430
431/*
432 * This uses GObject type functions to output signal prototypes and the object
433 * hierarchy.
434 */
435
436/* The output files */
437const gchar *signals_filename = "$new_signals_filename";
438const gchar *hierarchy_filename = "$new_hierarchy_filename";
439const gchar *interfaces_filename = "$new_interfaces_filename";
440const gchar *prerequisites_filename = "$new_prerequisites_filename";
441const gchar *args_filename = "$new_args_filename";
Sebastian Dröged8a669d2015-08-19 14:01:25 +0300442const gchar *sections_filename = "$new_sections_filename";
Olivier Naudan2556a702012-04-16 08:57:32 -0400443
444
445static void output_signals (void);
Sebastian Dröged8a669d2015-08-19 14:01:25 +0300446static void output_object_signals (FILE *fp, GType object_type);
447static void output_object_signal (FILE *fp, const gchar *object_class_name,
Olivier Naudan2556a702012-04-16 08:57:32 -0400448 guint signal_id);
Sebastian Dröged8a669d2015-08-19 14:01:25 +0300449static const gchar * get_type_name (GType type, gboolean * is_pointer);
Olivier Naudan2556a702012-04-16 08:57:32 -0400450static void output_object_hierarchy (void);
Sebastian Dröged8a669d2015-08-19 14:01:25 +0300451static void output_hierarchy (FILE *fp, GType type, guint level);
Olivier Naudan2556a702012-04-16 08:57:32 -0400452
453static void output_object_interfaces (void);
Sebastian Dröged8a669d2015-08-19 14:01:25 +0300454static void output_interfaces (FILE *fp, GType type);
Olivier Naudan2556a702012-04-16 08:57:32 -0400455
456static void output_interface_prerequisites (void);
Sebastian Dröged8a669d2015-08-19 14:01:25 +0300457static void output_prerequisites (FILE *fp, GType type);
Olivier Naudan2556a702012-04-16 08:57:32 -0400458
459static void output_args (void);
460static void output_object_args (FILE *fp, GType object_type);
461
Sebastian Dröged8a669d2015-08-19 14:01:25 +0300462static void output_sections (void);
463static void output_object_section (FILE *fp, GType object_type);
464
465
Olivier Naudan2556a702012-04-16 08:57:32 -0400466int
Sebastian Drögef10bf612014-05-03 19:34:29 +0200467main (G_GNUC_UNUSED int argc, G_GNUC_UNUSED char *argv[])
Olivier Naudan2556a702012-04-16 08:57:32 -0400468{
Olivier Naudan2556a702012-04-16 08:57:32 -0400469 $TYPE_INIT_FUNC;
470
471 get_object_types ();
472
473 output_signals ();
474 output_object_hierarchy ();
475 output_object_interfaces ();
476 output_interface_prerequisites ();
477 output_args ();
Sebastian Dröged8a669d2015-08-19 14:01:25 +0300478
479 output_sections ();
Olivier Naudan2556a702012-04-16 08:57:32 -0400480
481 return 0;
482}
483
484
485static void
486output_signals (void)
487{
488 FILE *fp;
489 gint i;
490
491 fp = fopen (signals_filename, "w");
492 if (fp == NULL)
493 {
494 g_warning ("Couldn't open output file: %s : %s", signals_filename, g_strerror(errno));
495 return;
496 }
497
498 for (i = 0; object_types[i]; i++)
499 output_object_signals (fp, object_types[i]);
500
501 fclose (fp);
502}
503
504static gint
505compare_signals (const void *a, const void *b)
506{
507 const guint *signal_a = a;
508 const guint *signal_b = b;
509
510 return strcmp (g_signal_name (*signal_a), g_signal_name (*signal_b));
511}
512
513/* This outputs all the signals of one object. */
514static void
515output_object_signals (FILE *fp, GType object_type)
516{
517 const gchar *object_class_name;
518 guint *signals, n_signals;
519 guint sig;
520
521 if (G_TYPE_IS_INSTANTIATABLE (object_type) ||
522 G_TYPE_IS_INTERFACE (object_type))
523 {
524
525 object_class_name = g_type_name (object_type);
526
527 signals = g_signal_list_ids (object_type, &n_signals);
528 qsort (signals, n_signals, sizeof (guint), compare_signals);
529
530 for (sig = 0; sig < n_signals; sig++)
531 {
532 output_object_signal (fp, object_class_name, signals[sig]);
533 }
534 g_free (signals);
535 }
536}
537
538
539/* This outputs one signal. */
540static void
541output_object_signal (FILE *fp,
542 const gchar *object_name,
543 guint signal_id)
544{
545 GSignalQuery query_info;
546 const gchar *type_name, *ret_type, *object_arg, *arg_name;
547 gchar *pos, *object_arg_lower;
548 gboolean is_pointer;
549 gchar buffer[1024];
550 guint i, param;
551 gint param_num, widget_num, event_num, callback_num;
552 gint *arg_num;
553 gchar signal_name[128];
554 gchar flags[16];
555
556 $debug_log ("Object: %s Signal: %u", object_name, signal_id);
557
558 param_num = 1;
559 widget_num = event_num = callback_num = 0;
560
561 g_signal_query (signal_id, &query_info);
562
563 /* Output the signal object type and the argument name. We assume the
564 type is a pointer - I think that is OK. We remove "Gtk" or "Gnome" and
565 convert to lower case for the argument name. */
566 pos = buffer;
567 sprintf (pos, "%s ", object_name);
568 pos += strlen (pos);
569
570 /* Try to come up with a sensible variable name for the first arg
571 * It chops off 2 know prefixes :/ and makes the name lowercase
572 * It should replace lowercase -> uppercase with '_'
573 * GFileMonitor -> file_monitor
574 * GIOExtensionPoint -> extension_point
575 * GtkTreeView -> tree_view
576 * if 2nd char is upper case too
577 * search for first lower case and go back one char
578 * else
579 * search for next upper case
580 */
581 if (!strncmp (object_name, "Gtk", 3))
582 object_arg = object_name + 3;
583 else if (!strncmp (object_name, "Gnome", 5))
584 object_arg = object_name + 5;
585 else
586 object_arg = object_name;
587
588 object_arg_lower = g_ascii_strdown (object_arg, -1);
589 sprintf (pos, "*%s\\n", object_arg_lower);
590 pos += strlen (pos);
591 if (!strncmp (object_arg_lower, "widget", 6))
592 widget_num = 2;
593 g_free(object_arg_lower);
594
595 /* Convert signal name to use underscores rather than dashes '-'. */
596 strncpy (signal_name, query_info.signal_name, 127);
597 signal_name[127] = '\\0';
598 for (i = 0; signal_name[i]; i++)
599 {
600 if (signal_name[i] == '-')
601 signal_name[i] = '_';
602 }
603
604 /* Output the signal parameters. */
605 for (param = 0; param < query_info.n_params; param++)
606 {
607 type_name = get_type_name (query_info.param_types[param] & ~G_SIGNAL_TYPE_STATIC_SCOPE, &is_pointer);
608
609 /* Most arguments to the callback are called "arg1", "arg2", etc.
610 GtkWidgets are called "widget", "widget2", ...
611 GtkCallbacks are called "callback", "callback2", ... */
612 if (!strcmp (type_name, "GtkWidget"))
613 {
614 arg_name = "widget";
615 arg_num = &widget_num;
616 }
617 else if (!strcmp (type_name, "GtkCallback")
618 || !strcmp (type_name, "GtkCCallback"))
619 {
620 arg_name = "callback";
621 arg_num = &callback_num;
622 }
623 else
624 {
625 arg_name = "arg";
626 arg_num = &param_num;
627 }
628 sprintf (pos, "%s ", type_name);
629 pos += strlen (pos);
630
631 if (!arg_num || *arg_num == 0)
632 sprintf (pos, "%s%s\\n", is_pointer ? "*" : " ", arg_name);
633 else
634 sprintf (pos, "%s%s%i\\n", is_pointer ? "*" : " ", arg_name,
635 *arg_num);
636 pos += strlen (pos);
637
638 if (arg_num)
639 {
640 if (*arg_num == 0)
641 *arg_num = 2;
642 else
643 *arg_num += 1;
644 }
645 }
646
647 pos = flags;
648 /* We use one-character flags for simplicity. */
649 if (query_info.signal_flags & G_SIGNAL_RUN_FIRST)
650 *pos++ = 'f';
651 if (query_info.signal_flags & G_SIGNAL_RUN_LAST)
652 *pos++ = 'l';
653 if (query_info.signal_flags & G_SIGNAL_RUN_CLEANUP)
654 *pos++ = 'c';
655 if (query_info.signal_flags & G_SIGNAL_NO_RECURSE)
656 *pos++ = 'r';
657 if (query_info.signal_flags & G_SIGNAL_DETAILED)
658 *pos++ = 'd';
659 if (query_info.signal_flags & G_SIGNAL_ACTION)
660 *pos++ = 'a';
661 if (query_info.signal_flags & G_SIGNAL_NO_HOOKS)
662 *pos++ = 'h';
663 *pos = 0;
664
665 /* Output the return type and function name. */
666 ret_type = get_type_name (query_info.return_type & ~G_SIGNAL_TYPE_STATIC_SCOPE, &is_pointer);
667
668 fprintf (fp,
669 "<SIGNAL>\\n<NAME>%s::%s</NAME>\\n<RETURNS>%s%s</RETURNS>\\n<FLAGS>%s</FLAGS>\\n%s</SIGNAL>\\n\\n",
670 object_name, query_info.signal_name, ret_type, is_pointer ? "*" : "", flags, buffer);
671}
672
673
674/* Returns the type name to use for a signal argument or return value, given
675 the GtkType from the signal info. It also sets is_pointer to TRUE if the
676 argument needs a '*' since it is a pointer. */
677static const gchar *
678get_type_name (GType type, gboolean * is_pointer)
679{
680 const gchar *type_name;
681
682 *is_pointer = FALSE;
683 type_name = g_type_name (type);
684
685 switch (type) {
686 case G_TYPE_NONE:
687 case G_TYPE_CHAR:
688 case G_TYPE_UCHAR:
689 case G_TYPE_BOOLEAN:
690 case G_TYPE_INT:
691 case G_TYPE_UINT:
692 case G_TYPE_LONG:
693 case G_TYPE_ULONG:
694 case G_TYPE_FLOAT:
695 case G_TYPE_DOUBLE:
696 case G_TYPE_POINTER:
697 /* These all have normal C type names so they are OK. */
698 return type_name;
699
700 case G_TYPE_STRING:
701 /* A GtkString is really a gchar*. */
702 *is_pointer = TRUE;
703 return "gchar";
704
705 case G_TYPE_ENUM:
706 case G_TYPE_FLAGS:
707 /* We use a gint for both of these. Hopefully a subtype with a decent
708 name will be registered and used instead, as GTK+ does itself. */
709 return "gint";
710
711 case G_TYPE_BOXED:
712 /* The boxed type shouldn't be used itself, only subtypes. Though we
713 return 'gpointer' just in case. */
714 return "gpointer";
715
716 case G_TYPE_PARAM:
717 /* A GParam is really a GParamSpec*. */
718 *is_pointer = TRUE;
719 return "GParamSpec";
720
721#if GLIB_CHECK_VERSION (2, 25, 9)
722 case G_TYPE_VARIANT:
723 *is_pointer = TRUE;
724 return "GVariant";
725#endif
726
727default:
728 break;
729 }
730
731 /* For all GObject subclasses we can use the class name with a "*",
732 e.g. 'GtkWidget *'. */
733 if (g_type_is_a (type, G_TYPE_OBJECT))
734 *is_pointer = TRUE;
735
736 /* Also catch non GObject root types */
737 if (G_TYPE_IS_CLASSED (type))
738 *is_pointer = TRUE;
739
740 /* All boxed subtypes will be pointers as well. */
741 /* Exception: GStrv */
742 if (g_type_is_a (type, G_TYPE_BOXED) &&
743 !g_type_is_a (type, G_TYPE_STRV))
744 *is_pointer = TRUE;
745
746 /* All pointer subtypes will be pointers as well. */
747 if (g_type_is_a (type, G_TYPE_POINTER))
748 *is_pointer = TRUE;
749
750 /* But enums are not */
751 if (g_type_is_a (type, G_TYPE_ENUM) ||
752 g_type_is_a (type, G_TYPE_FLAGS))
753 *is_pointer = FALSE;
754
755 return type_name;
756}
757
758
759/* This outputs the hierarchy of all objects which have been initialized,
760 i.e. by calling their XXX_get_type() initialization function. */
761static void
762output_object_hierarchy (void)
763{
764 FILE *fp;
765 gint i,j;
766 GType root, type;
767 GType root_types[$ntypes] = { G_TYPE_INVALID, };
768
769 fp = fopen (hierarchy_filename, "w");
770 if (fp == NULL)
771 {
772 g_warning ("Couldn't open output file: %s : %s", hierarchy_filename, g_strerror(errno));
773 return;
774 }
775 output_hierarchy (fp, G_TYPE_OBJECT, 0);
776 output_hierarchy (fp, G_TYPE_INTERFACE, 0);
777
778 for (i=0; object_types[i]; i++) {
779 root = object_types[i];
780 while ((type = g_type_parent (root))) {
781 root = type;
782 }
783 if ((root != G_TYPE_OBJECT) && (root != G_TYPE_INTERFACE)) {
784 for (j=0; root_types[j]; j++) {
785 if (root == root_types[j]) {
786 root = G_TYPE_INVALID; break;
787 }
788 }
789 if(root) {
790 root_types[j] = root;
791 output_hierarchy (fp, root, 0);
792 }
793 }
794 }
795
796 fclose (fp);
797}
798
799static int
800compare_types (const void *a, const void *b)
801{
802 const char *na = g_type_name (*((GType *)a));
803 const char *nb = g_type_name (*((GType *)b));
804
805 return g_strcmp0 (na, nb);
806}
807
808
809/* This is called recursively to output the hierarchy of a object. */
810static void
811output_hierarchy (FILE *fp,
812 GType type,
813 guint level)
814{
815 guint i;
816 GType *children;
817 guint n_children;
818
819 if (!type)
820 return;
821
822 for (i = 0; i < level; i++)
823 fprintf (fp, " ");
824 fprintf (fp, "%s\\n", g_type_name (type));
825
826 children = g_type_children (type, &n_children);
827 qsort (children, n_children, sizeof (GType), compare_types);
828
829
830 for (i=0; i < n_children; i++)
831 output_hierarchy (fp, children[i], level + 1);
832
833 g_free (children);
834}
835
836static void output_object_interfaces (void)
837{
838 guint i;
839 FILE *fp;
840
841 fp = fopen (interfaces_filename, "w");
842 if (fp == NULL)
843 {
844 g_warning ("Couldn't open output file: %s : %s", interfaces_filename, g_strerror(errno));
845 return;
846 }
847 output_interfaces (fp, G_TYPE_OBJECT);
848
849 for (i = 0; object_types[i]; i++)
850 {
851 if (!g_type_parent (object_types[i]) &&
852 (object_types[i] != G_TYPE_OBJECT) &&
853 G_TYPE_IS_INSTANTIATABLE (object_types[i]))
854 {
855 output_interfaces (fp, object_types[i]);
856 }
857 }
858 fclose (fp);
859}
860
861static void
862output_interfaces (FILE *fp,
863 GType type)
864{
865 guint i;
866 GType *children, *interfaces;
867 guint n_children, n_interfaces;
868
869 if (!type)
870 return;
871
872 interfaces = g_type_interfaces (type, &n_interfaces);
873
874 if (n_interfaces > 0)
875 {
876 fprintf (fp, "%s", g_type_name (type));
877 for (i=0; i < n_interfaces; i++)
878 fprintf (fp, " %s", g_type_name (interfaces[i]));
879 fprintf (fp, "\\n");
880 }
881 g_free (interfaces);
882
883 children = g_type_children (type, &n_children);
884
885 for (i=0; i < n_children; i++)
886 output_interfaces (fp, children[i]);
887
888 g_free (children);
889}
890
891static void output_interface_prerequisites (void)
892{
893 FILE *fp;
894
895 fp = fopen (prerequisites_filename, "w");
896 if (fp == NULL)
897 {
898 g_warning ("Couldn't open output file: %s : %s", prerequisites_filename, g_strerror(errno));
899 return;
900 }
901 output_prerequisites (fp, G_TYPE_INTERFACE);
902 fclose (fp);
903}
904
905static void
906output_prerequisites (FILE *fp,
907 GType type)
908{
909#if GLIB_CHECK_VERSION(2,1,0)
910 guint i;
911 GType *children, *prerequisites;
912 guint n_children, n_prerequisites;
913
914 if (!type)
915 return;
916
917 prerequisites = g_type_interface_prerequisites (type, &n_prerequisites);
918
919 if (n_prerequisites > 0)
920 {
921 fprintf (fp, "%s", g_type_name (type));
922 for (i=0; i < n_prerequisites; i++)
923 fprintf (fp, " %s", g_type_name (prerequisites[i]));
924 fprintf (fp, "\\n");
925 }
926 g_free (prerequisites);
927
928 children = g_type_children (type, &n_children);
929
930 for (i=0; i < n_children; i++)
931 output_prerequisites (fp, children[i]);
932
933 g_free (children);
934#endif
935}
936
937static void
938output_args (void)
939{
940 FILE *fp;
941 gint i;
942
943 fp = fopen (args_filename, "w");
944 if (fp == NULL)
945 {
946 g_warning ("Couldn't open output file: %s : %s", args_filename, g_strerror(errno));
947 return;
948 }
949
950 for (i = 0; object_types[i]; i++) {
951 output_object_args (fp, object_types[i]);
952 }
953
954 fclose (fp);
955}
956
957static gint
958compare_param_specs (const void *a, const void *b)
959{
960 GParamSpec *spec_a = *(GParamSpec **)a;
961 GParamSpec *spec_b = *(GParamSpec **)b;
962
963 return strcmp (g_param_spec_get_name (spec_a), g_param_spec_get_name (spec_b));
964}
965
966/* Its common to have unsigned properties restricted
967 * to the signed range. Therefore we make this look
968 * a bit nicer by spelling out the max constants.
969 */
970
971/* Don't use "==" with floats, it might trigger a gcc warning. */
972#define GTKDOC_COMPARE_FLOAT(x, y) (x <= y && x >= y)
973
974static gchar*
975describe_double_constant (gdouble value)
976{
977 gchar *desc;
978
979 if (GTKDOC_COMPARE_FLOAT (value, G_MAXDOUBLE))
980 desc = g_strdup ("G_MAXDOUBLE");
981 else if (GTKDOC_COMPARE_FLOAT (value, G_MINDOUBLE))
982 desc = g_strdup ("G_MINDOUBLE");
983 else if (GTKDOC_COMPARE_FLOAT (value, -G_MAXDOUBLE))
984 desc = g_strdup ("-G_MAXDOUBLE");
985 else if (GTKDOC_COMPARE_FLOAT (value, G_MAXFLOAT))
986 desc = g_strdup ("G_MAXFLOAT");
987 else if (GTKDOC_COMPARE_FLOAT (value, G_MINFLOAT))
988 desc = g_strdup ("G_MINFLOAT");
989 else if (GTKDOC_COMPARE_FLOAT (value, -G_MAXFLOAT))
990 desc = g_strdup ("-G_MAXFLOAT");
991 else{
992 /* make sure floats are output with a decimal dot irrespective of
993 * current locale. Use formatd since we want human-readable numbers
994 * and do not need the exact same bit representation when deserialising */
995 desc = g_malloc0 (G_ASCII_DTOSTR_BUF_SIZE);
996 g_ascii_formatd (desc, G_ASCII_DTOSTR_BUF_SIZE, "%g", value);
997 }
998
999 return desc;
1000}
1001
1002static gchar*
1003describe_signed_constant (gsize size, gint64 value)
1004{
1005 gchar *desc = NULL;
1006
1007 switch (size) {
1008 case 8:
1009 if (value == G_MAXINT64)
1010 desc = g_strdup ("G_MAXINT64");
1011 else if (value == G_MININT64)
1012 desc = g_strdup ("G_MININT64");
1013 /* fall through */
1014 case 4:
1015 if (sizeof (int) == 4) {
1016 if (value == G_MAXINT)
1017 desc = g_strdup ("G_MAXINT");
1018 else if (value == G_MININT)
1019 desc = g_strdup ("G_MININT");
1020 else if (value == (gint64)G_MAXUINT)
1021 desc = g_strdup ("G_MAXUINT");
1022 }
1023 if (value == G_MAXLONG)
1024 desc = g_strdup ("G_MAXLONG");
1025 else if (value == G_MINLONG)
1026 desc = g_strdup ("G_MINLONG");
1027 else if (value == (gint64)G_MAXULONG)
1028 desc = g_strdup ("G_MAXULONG");
1029 /* fall through */
1030 case 2:
1031 if (sizeof (int) == 2) {
1032 if (value == G_MAXINT)
1033 desc = g_strdup ("G_MAXINT");
1034 else if (value == G_MININT)
1035 desc = g_strdup ("G_MININT");
1036 else if (value == (gint64)G_MAXUINT)
1037 desc = g_strdup ("G_MAXUINT");
1038 }
1039 break;
1040 default:
1041 break;
1042 }
1043 if (!desc)
1044 desc = g_strdup_printf ("%" G_GINT64_FORMAT, value);
1045
1046 return desc;
1047}
1048
1049static gchar*
1050describe_unsigned_constant (gsize size, guint64 value)
1051{
1052 gchar *desc = NULL;
1053
1054 switch (size) {
1055 case 8:
1056 if (value == G_MAXINT64)
1057 desc = g_strdup ("G_MAXINT64");
1058 else if (value == G_MAXUINT64)
1059 desc = g_strdup ("G_MAXUINT64");
1060 /* fall through */
1061 case 4:
1062 if (sizeof (int) == 4) {
1063 if (value == (guint64)G_MAXINT)
1064 desc = g_strdup ("G_MAXINT");
1065 else if (value == G_MAXUINT)
1066 desc = g_strdup ("G_MAXUINT");
1067 }
1068 if (value == (guint64)G_MAXLONG)
1069 desc = g_strdup ("G_MAXLONG");
1070 else if (value == G_MAXULONG)
1071 desc = g_strdup ("G_MAXULONG");
1072 /* fall through */
1073 case 2:
1074 if (sizeof (int) == 2) {
1075 if (value == (guint64)G_MAXINT)
1076 desc = g_strdup ("G_MAXINT");
1077 else if (value == G_MAXUINT)
1078 desc = g_strdup ("G_MAXUINT");
1079 }
1080 break;
1081 default:
1082 break;
1083 }
1084 if (!desc)
1085 desc = g_strdup_printf ("%" G_GUINT64_FORMAT, value);
1086
1087 return desc;
1088}
1089
1090static gchar*
1091describe_type (GParamSpec *spec)
1092{
1093 gchar *desc;
1094 gchar *lower;
1095 gchar *upper;
1096
1097 if (G_IS_PARAM_SPEC_CHAR (spec))
1098 {
1099 GParamSpecChar *pspec = G_PARAM_SPEC_CHAR (spec);
1100
1101 lower = describe_signed_constant (sizeof(gchar), pspec->minimum);
1102 upper = describe_signed_constant (sizeof(gchar), pspec->maximum);
1103 if (pspec->minimum == G_MININT8 && pspec->maximum == G_MAXINT8)
1104 desc = g_strdup ("");
1105 else if (pspec->minimum == G_MININT8)
1106 desc = g_strdup_printf ("<= %s", upper);
1107 else if (pspec->maximum == G_MAXINT8)
1108 desc = g_strdup_printf (">= %s", lower);
1109 else
1110 desc = g_strdup_printf ("[%s,%s]", lower, upper);
1111 g_free (lower);
1112 g_free (upper);
1113 }
1114 else if (G_IS_PARAM_SPEC_UCHAR (spec))
1115 {
1116 GParamSpecUChar *pspec = G_PARAM_SPEC_UCHAR (spec);
1117
1118 lower = describe_unsigned_constant (sizeof(guchar), pspec->minimum);
1119 upper = describe_unsigned_constant (sizeof(guchar), pspec->maximum);
1120 if (pspec->minimum == 0 && pspec->maximum == G_MAXUINT8)
1121 desc = g_strdup ("");
1122 else if (pspec->minimum == 0)
1123 desc = g_strdup_printf ("<= %s", upper);
1124 else if (pspec->maximum == G_MAXUINT8)
1125 desc = g_strdup_printf (">= %s", lower);
1126 else
1127 desc = g_strdup_printf ("[%s,%s]", lower, upper);
1128 g_free (lower);
1129 g_free (upper);
1130 }
1131 else if (G_IS_PARAM_SPEC_INT (spec))
1132 {
1133 GParamSpecInt *pspec = G_PARAM_SPEC_INT (spec);
1134
1135 lower = describe_signed_constant (sizeof(gint), pspec->minimum);
1136 upper = describe_signed_constant (sizeof(gint), pspec->maximum);
1137 if (pspec->minimum == G_MININT && pspec->maximum == G_MAXINT)
1138 desc = g_strdup ("");
1139 else if (pspec->minimum == G_MININT)
1140 desc = g_strdup_printf ("<= %s", upper);
1141 else if (pspec->maximum == G_MAXINT)
1142 desc = g_strdup_printf (">= %s", lower);
1143 else
1144 desc = g_strdup_printf ("[%s,%s]", lower, upper);
1145 g_free (lower);
1146 g_free (upper);
1147 }
1148 else if (G_IS_PARAM_SPEC_UINT (spec))
1149 {
1150 GParamSpecUInt *pspec = G_PARAM_SPEC_UINT (spec);
1151
1152 lower = describe_unsigned_constant (sizeof(guint), pspec->minimum);
1153 upper = describe_unsigned_constant (sizeof(guint), pspec->maximum);
1154 if (pspec->minimum == 0 && pspec->maximum == G_MAXUINT)
1155 desc = g_strdup ("");
1156 else if (pspec->minimum == 0)
1157 desc = g_strdup_printf ("<= %s", upper);
1158 else if (pspec->maximum == G_MAXUINT)
1159 desc = g_strdup_printf (">= %s", lower);
1160 else
1161 desc = g_strdup_printf ("[%s,%s]", lower, upper);
1162 g_free (lower);
1163 g_free (upper);
1164 }
1165 else if (G_IS_PARAM_SPEC_LONG (spec))
1166 {
1167 GParamSpecLong *pspec = G_PARAM_SPEC_LONG (spec);
1168
1169 lower = describe_signed_constant (sizeof(glong), pspec->minimum);
1170 upper = describe_signed_constant (sizeof(glong), pspec->maximum);
1171 if (pspec->minimum == G_MINLONG && pspec->maximum == G_MAXLONG)
1172 desc = g_strdup ("");
1173 else if (pspec->minimum == G_MINLONG)
1174 desc = g_strdup_printf ("<= %s", upper);
1175 else if (pspec->maximum == G_MAXLONG)
1176 desc = g_strdup_printf (">= %s", lower);
1177 else
1178 desc = g_strdup_printf ("[%s,%s]", lower, upper);
1179 g_free (lower);
1180 g_free (upper);
1181 }
1182 else if (G_IS_PARAM_SPEC_ULONG (spec))
1183 {
1184 GParamSpecULong *pspec = G_PARAM_SPEC_ULONG (spec);
1185
1186 lower = describe_unsigned_constant (sizeof(gulong), pspec->minimum);
1187 upper = describe_unsigned_constant (sizeof(gulong), pspec->maximum);
1188 if (pspec->minimum == 0 && pspec->maximum == G_MAXULONG)
1189 desc = g_strdup ("");
1190 else if (pspec->minimum == 0)
1191 desc = g_strdup_printf ("<= %s", upper);
1192 else if (pspec->maximum == G_MAXULONG)
1193 desc = g_strdup_printf (">= %s", lower);
1194 else
1195 desc = g_strdup_printf ("[%s,%s]", lower, upper);
1196 g_free (lower);
1197 g_free (upper);
1198 }
1199 else if (G_IS_PARAM_SPEC_INT64 (spec))
1200 {
1201 GParamSpecInt64 *pspec = G_PARAM_SPEC_INT64 (spec);
1202
1203 lower = describe_signed_constant (sizeof(gint64), pspec->minimum);
1204 upper = describe_signed_constant (sizeof(gint64), pspec->maximum);
1205 if (pspec->minimum == G_MININT64 && pspec->maximum == G_MAXINT64)
1206 desc = g_strdup ("");
1207 else if (pspec->minimum == G_MININT64)
1208 desc = g_strdup_printf ("<= %s", upper);
1209 else if (pspec->maximum == G_MAXINT64)
1210 desc = g_strdup_printf (">= %s", lower);
1211 else
1212 desc = g_strdup_printf ("[%s,%s]", lower, upper);
1213 g_free (lower);
1214 g_free (upper);
1215 }
1216 else if (G_IS_PARAM_SPEC_UINT64 (spec))
1217 {
1218 GParamSpecUInt64 *pspec = G_PARAM_SPEC_UINT64 (spec);
1219
1220 lower = describe_unsigned_constant (sizeof(guint64), pspec->minimum);
1221 upper = describe_unsigned_constant (sizeof(guint64), pspec->maximum);
1222 if (pspec->minimum == 0 && pspec->maximum == G_MAXUINT64)
1223 desc = g_strdup ("");
1224 else if (pspec->minimum == 0)
1225 desc = g_strdup_printf ("<= %s", upper);
1226 else if (pspec->maximum == G_MAXUINT64)
1227 desc = g_strdup_printf (">= %s", lower);
1228 else
1229 desc = g_strdup_printf ("[%s,%s]", lower, upper);
1230 g_free (lower);
1231 g_free (upper);
1232 }
1233 else if (G_IS_PARAM_SPEC_FLOAT (spec))
1234 {
1235 GParamSpecFloat *pspec = G_PARAM_SPEC_FLOAT (spec);
1236
1237 lower = describe_double_constant (pspec->minimum);
1238 upper = describe_double_constant (pspec->maximum);
1239 if (GTKDOC_COMPARE_FLOAT (pspec->minimum, -G_MAXFLOAT))
1240 {
1241 if (GTKDOC_COMPARE_FLOAT (pspec->maximum, G_MAXFLOAT))
1242 desc = g_strdup ("");
1243 else
1244 desc = g_strdup_printf ("<= %s", upper);
1245 }
1246 else if (GTKDOC_COMPARE_FLOAT (pspec->maximum, G_MAXFLOAT))
1247 desc = g_strdup_printf (">= %s", lower);
1248 else
1249 desc = g_strdup_printf ("[%s,%s]", lower, upper);
1250 g_free (lower);
1251 g_free (upper);
1252 }
1253 else if (G_IS_PARAM_SPEC_DOUBLE (spec))
1254 {
1255 GParamSpecDouble *pspec = G_PARAM_SPEC_DOUBLE (spec);
1256
1257 lower = describe_double_constant (pspec->minimum);
1258 upper = describe_double_constant (pspec->maximum);
1259 if (GTKDOC_COMPARE_FLOAT (pspec->minimum, -G_MAXDOUBLE))
1260 {
1261 if (GTKDOC_COMPARE_FLOAT (pspec->maximum, G_MAXDOUBLE))
1262 desc = g_strdup ("");
1263 else
1264 desc = g_strdup_printf ("<= %s", upper);
1265 }
1266 else if (GTKDOC_COMPARE_FLOAT (pspec->maximum, G_MAXDOUBLE))
1267 desc = g_strdup_printf (">= %s", lower);
1268 else
1269 desc = g_strdup_printf ("[%s,%s]", lower, upper);
1270 g_free (lower);
1271 g_free (upper);
1272 }
1273#if GLIB_CHECK_VERSION (2, 12, 0)
1274 else if (G_IS_PARAM_SPEC_GTYPE (spec))
1275 {
1276 GParamSpecGType *pspec = G_PARAM_SPEC_GTYPE (spec);
1277 gboolean is_pointer;
1278
1279 desc = g_strdup (get_type_name (pspec->is_a_type, &is_pointer));
1280 }
1281#endif
1282#if GLIB_CHECK_VERSION (2, 25, 9)
1283 else if (G_IS_PARAM_SPEC_VARIANT (spec))
1284 {
1285 GParamSpecVariant *pspec = G_PARAM_SPEC_VARIANT (spec);
1286 gchar *variant_type;
1287
1288 variant_type = g_variant_type_dup_string (pspec->type);
1289 desc = g_strdup_printf ("GVariant<%s>", variant_type);
1290 g_free (variant_type);
1291 }
1292#endif
1293 else
1294 {
1295 desc = g_strdup ("");
1296 }
1297
1298 return desc;
1299}
1300
1301static gchar*
1302describe_default (GParamSpec *spec)
1303{
1304 gchar *desc;
1305
1306 if (G_IS_PARAM_SPEC_CHAR (spec))
1307 {
1308 GParamSpecChar *pspec = G_PARAM_SPEC_CHAR (spec);
1309
1310 desc = g_strdup_printf ("%d", pspec->default_value);
1311 }
1312 else if (G_IS_PARAM_SPEC_UCHAR (spec))
1313 {
1314 GParamSpecUChar *pspec = G_PARAM_SPEC_UCHAR (spec);
1315
1316 desc = g_strdup_printf ("%u", pspec->default_value);
1317 }
1318 else if (G_IS_PARAM_SPEC_BOOLEAN (spec))
1319 {
1320 GParamSpecBoolean *pspec = G_PARAM_SPEC_BOOLEAN (spec);
1321
1322 desc = g_strdup_printf ("%s", pspec->default_value ? "TRUE" : "FALSE");
1323 }
1324 else if (G_IS_PARAM_SPEC_INT (spec))
1325 {
1326 GParamSpecInt *pspec = G_PARAM_SPEC_INT (spec);
1327
1328 desc = g_strdup_printf ("%d", pspec->default_value);
1329 }
1330 else if (G_IS_PARAM_SPEC_UINT (spec))
1331 {
1332 GParamSpecUInt *pspec = G_PARAM_SPEC_UINT (spec);
1333
1334 desc = g_strdup_printf ("%u", pspec->default_value);
1335 }
1336 else if (G_IS_PARAM_SPEC_LONG (spec))
1337 {
1338 GParamSpecLong *pspec = G_PARAM_SPEC_LONG (spec);
1339
1340 desc = g_strdup_printf ("%ld", pspec->default_value);
1341 }
1342 else if (G_IS_PARAM_SPEC_LONG (spec))
1343 {
1344 GParamSpecULong *pspec = G_PARAM_SPEC_ULONG (spec);
1345
1346 desc = g_strdup_printf ("%lu", pspec->default_value);
1347 }
1348 else if (G_IS_PARAM_SPEC_INT64 (spec))
1349 {
1350 GParamSpecInt64 *pspec = G_PARAM_SPEC_INT64 (spec);
1351
1352 desc = g_strdup_printf ("%" G_GINT64_FORMAT, pspec->default_value);
1353 }
1354 else if (G_IS_PARAM_SPEC_UINT64 (spec))
1355 {
1356 GParamSpecUInt64 *pspec = G_PARAM_SPEC_UINT64 (spec);
1357
1358 desc = g_strdup_printf ("%" G_GUINT64_FORMAT, pspec->default_value);
1359 }
1360 else if (G_IS_PARAM_SPEC_UNICHAR (spec))
1361 {
1362 GParamSpecUnichar *pspec = G_PARAM_SPEC_UNICHAR (spec);
1363
1364 if (g_unichar_isprint (pspec->default_value))
1365 desc = g_strdup_printf ("'%c'", pspec->default_value);
1366 else
1367 desc = g_strdup_printf ("%u", pspec->default_value);
1368 }
1369 else if (G_IS_PARAM_SPEC_ENUM (spec))
1370 {
1371 GParamSpecEnum *pspec = G_PARAM_SPEC_ENUM (spec);
1372
1373 GEnumValue *value = g_enum_get_value (pspec->enum_class, pspec->default_value);
1374 if (value)
1375 desc = g_strdup_printf ("%s", value->value_name);
1376 else
1377 desc = g_strdup_printf ("%d", pspec->default_value);
1378 }
1379 else if (G_IS_PARAM_SPEC_FLAGS (spec))
1380 {
1381 GParamSpecFlags *pspec = G_PARAM_SPEC_FLAGS (spec);
1382 guint default_value;
1383 GString *acc;
1384
1385 default_value = pspec->default_value;
1386 acc = g_string_new ("");
1387
1388 while (default_value)
1389 {
1390 GFlagsValue *value = g_flags_get_first_value (pspec->flags_class, default_value);
1391
1392 if (!value)
1393 break;
1394
1395 if (acc->len > 0)
1396 g_string_append (acc, "|");
1397 g_string_append (acc, value->value_name);
1398
1399 default_value &= ~value->value;
1400 }
1401
1402 if (default_value == 0)
1403 desc = g_string_free (acc, FALSE);
1404 else
1405 {
1406 desc = g_strdup_printf ("%d", pspec->default_value);
1407 g_string_free (acc, TRUE);
1408 }
1409 }
1410 else if (G_IS_PARAM_SPEC_FLOAT (spec))
1411 {
1412 GParamSpecFloat *pspec = G_PARAM_SPEC_FLOAT (spec);
1413
1414 /* make sure floats are output with a decimal dot irrespective of
1415 * current locale. Use formatd since we want human-readable numbers
1416 * and do not need the exact same bit representation when deserialising */
1417 desc = g_malloc0 (G_ASCII_DTOSTR_BUF_SIZE);
1418 g_ascii_formatd (desc, G_ASCII_DTOSTR_BUF_SIZE, "%g",
1419 pspec->default_value);
1420 }
1421 else if (G_IS_PARAM_SPEC_DOUBLE (spec))
1422 {
1423 GParamSpecDouble *pspec = G_PARAM_SPEC_DOUBLE (spec);
1424
1425 /* make sure floats are output with a decimal dot irrespective of
1426 * current locale. Use formatd since we want human-readable numbers
1427 * and do not need the exact same bit representation when deserialising */
1428 desc = g_malloc0 (G_ASCII_DTOSTR_BUF_SIZE);
1429 g_ascii_formatd (desc, G_ASCII_DTOSTR_BUF_SIZE, "%g",
1430 pspec->default_value);
1431 }
1432 else if (G_IS_PARAM_SPEC_STRING (spec))
1433 {
1434 GParamSpecString *pspec = G_PARAM_SPEC_STRING (spec);
1435
1436 if (pspec->default_value)
1437 {
1438 gchar *esc = g_strescape (pspec->default_value, NULL);
1439
1440 desc = g_strdup_printf ("\\"%s\\"", esc);
1441
1442 g_free (esc);
1443 }
1444 else
1445 desc = g_strdup_printf ("NULL");
1446 }
1447 else
1448 {
1449 desc = g_strdup ("");
1450 }
1451
1452 return desc;
1453}
1454
1455
1456static void
1457output_object_args (FILE *fp, GType object_type)
1458{
1459 gpointer class;
1460 const gchar *object_class_name;
1461 guint arg;
1462 gchar flags[16], *pos;
1463 GParamSpec **properties;
1464 guint n_properties;
1465 gboolean child_prop;
1466 gboolean style_prop;
1467 gboolean is_pointer;
1468 const gchar *type_name;
1469 gchar *type_desc;
1470 gchar *default_value;
1471
1472 if (G_TYPE_IS_OBJECT (object_type))
1473 {
1474 class = g_type_class_peek (object_type);
1475 if (!class)
1476 return;
1477
1478 properties = g_object_class_list_properties (class, &n_properties);
1479 }
1480#if GLIB_MAJOR_VERSION > 2 || (GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION >= 3)
1481 else if (G_TYPE_IS_INTERFACE (object_type))
1482 {
1483 class = g_type_default_interface_ref (object_type);
1484
1485 if (!class)
1486 return;
1487
1488 properties = g_object_interface_list_properties (class, &n_properties);
1489 }
1490#endif
1491 else
1492 return;
1493
1494 object_class_name = g_type_name (object_type);
1495
1496 child_prop = FALSE;
1497 style_prop = FALSE;
1498
1499 while (TRUE) {
1500 qsort (properties, n_properties, sizeof (GParamSpec *), compare_param_specs);
1501 for (arg = 0; arg < n_properties; arg++)
1502 {
1503 GParamSpec *spec = properties[arg];
1504 const gchar *nick, *blurb, *dot;
1505
1506 if (spec->owner_type != object_type)
1507 continue;
1508
1509 pos = flags;
1510 /* We use one-character flags for simplicity. */
1511 if (child_prop && !style_prop)
1512 *pos++ = 'c';
1513 if (style_prop)
1514 *pos++ = 's';
1515 if (spec->flags & G_PARAM_READABLE)
1516 *pos++ = 'r';
1517 if (spec->flags & G_PARAM_WRITABLE)
1518 *pos++ = 'w';
1519 if (spec->flags & G_PARAM_CONSTRUCT)
1520 *pos++ = 'x';
1521 if (spec->flags & G_PARAM_CONSTRUCT_ONLY)
1522 *pos++ = 'X';
1523 *pos = 0;
1524
1525 nick = g_param_spec_get_nick (spec);
1526 blurb = g_param_spec_get_blurb (spec);
1527
1528 dot = "";
1529 if (blurb) {
1530 int str_len = strlen (blurb);
1531 if (str_len > 0 && blurb[str_len - 1] != '.')
1532 dot = ".";
1533 }
1534
1535 type_desc = describe_type (spec);
1536 default_value = describe_default (spec);
1537 type_name = get_type_name (spec->value_type, &is_pointer);
1538 fprintf (fp, "<ARG>\\n<NAME>%s::%s</NAME>\\n<TYPE>%s%s</TYPE>\\n<RANGE>%s</RANGE>\\n<FLAGS>%s</FLAGS>\\n<NICK>%s</NICK>\\n<BLURB>%s%s</BLURB>\\n<DEFAULT>%s</DEFAULT>\\n</ARG>\\n\\n",
1539 object_class_name, g_param_spec_get_name (spec), type_name, is_pointer ? "*" : "", type_desc, flags, nick ? nick : "(null)", blurb ? blurb : "(null)", dot, default_value);
1540 g_free (type_desc);
1541 g_free (default_value);
1542 }
1543
1544 g_free (properties);
1545
1546#ifdef GTK_IS_CONTAINER_CLASS
1547 if (!child_prop && GTK_IS_CONTAINER_CLASS (class)) {
1548 properties = gtk_container_class_list_child_properties (class, &n_properties);
1549 child_prop = TRUE;
1550 continue;
1551 }
1552#endif
1553
1554#ifdef GTK_IS_CELL_AREA_CLASS
1555 if (!child_prop && GTK_IS_CELL_AREA_CLASS (class)) {
1556 properties = gtk_cell_area_class_list_cell_properties (class, &n_properties);
1557 child_prop = TRUE;
1558 continue;
1559 }
1560#endif
1561
1562#ifdef GTK_IS_WIDGET_CLASS
1563#if GTK_CHECK_VERSION(2,1,0)
1564 if (!style_prop && GTK_IS_WIDGET_CLASS (class)) {
1565 properties = gtk_widget_class_list_style_properties (GTK_WIDGET_CLASS (class), &n_properties);
1566 style_prop = TRUE;
1567 continue;
1568 }
1569#endif
1570#endif
1571
1572 break;
1573 }
1574}
Sebastian Dröged8a669d2015-08-19 14:01:25 +03001575
1576static void
1577output_sections (void)
1578{
1579 FILE *fp;
1580 gint i;
1581
1582 fp = fopen (sections_filename, "w");
1583 if (fp == NULL)
1584 {
1585 g_warning ("Couldn't open output file: %s : %s", sections_filename, g_strerror(errno));
1586 return;
1587 }
1588
1589 for (i = 0; object_types[i]; i++) { }
1590 qsort (object_types, i, sizeof (GType), compare_types);
1591
1592 for (i = 0; object_types[i]; i++) {
1593 output_object_section (fp, object_types[i]);
1594 }
1595
1596 fclose (fp);
1597}
1598
1599static gboolean
1600find_by_type (GstPluginFeature *f, gpointer data) {
1601 return (GST_IS_ELEMENT_FACTORY(f) &&
1602 ((GType)data == gst_element_factory_get_element_type (GST_ELEMENT_FACTORY(f))));
1603}
1604
1605static void
1606output_object_section (FILE *fp, GType object_type)
1607{
1608 /* e.g. GstFakeSink */
1609 const gchar *tn = g_type_name (object_type);
1610 const gchar *cct = &tn[3]; /* cut 'Gst' */
1611 gchar *title, *lct, *uct;
1612 gint i, j, l = strlen(cct);
1613 gpointer class;
1614 GParamSpec **properties;
1615 guint n_properties;
1616 const gchar *ptn;
1617 gchar *ptns;
1618 GString *strbuf = g_string_new (NULL);
1619 GList *fl;
1620 GstPluginFeature *f = NULL;
1621 gboolean need_unserscore = TRUE, have_abbrev = FALSE;
1622
1623 fl = gst_registry_feature_filter (gst_registry_get(), find_by_type, TRUE,
1624 (gpointer)object_type);
1625 if (fl) {
1626 f = fl->data;
1627 g_list_free(fl);
1628 }
1629 if (f) {
1630 title = g_strdup (gst_plugin_feature_get_name(f));
1631 g_object_unref (f);
1632 } else {
1633 title = g_ascii_strdown(cct, -1);
1634 }
1635
1636 /* turn CamelCase into '_' separated all lower, resulting string is atmost
1637 * twice as long, special casing for abbevs like GstTCPClientSink */
1638 lct = g_malloc(2*l);
1639 for (i = 0, j = 0; i < l; i++) {
1640 if (g_ascii_isupper (cct[i])) {
1641 if (need_unserscore) {
1642 if (i > 0) {
1643 lct[j++] = '_';
1644 }
1645 } else {
1646 have_abbrev = TRUE;
1647 }
1648 lct[j++] = g_ascii_tolower(cct[i]);
1649 need_unserscore = FALSE;
1650 } else {
1651 if (have_abbrev) {
1652 lct[j] = lct[j-1];
1653 lct[j-1] = '_';
1654 j++;
1655 have_abbrev = FALSE;
1656 }
1657 lct[j++] = cct[i];
1658 need_unserscore = TRUE;
1659 }
1660 }
1661 lct[j] = '\\0';
1662 uct = g_ascii_strup(lct, -1);
1663
1664 /* scan properties and find local enums */
1665 class = g_type_class_peek (object_type);
1666 properties = g_object_class_list_properties (class, &n_properties);
1667 qsort (properties, n_properties, sizeof (GParamSpec *), compare_param_specs);
1668 for (i = 0; i < n_properties; i++) {
1669 GParamSpec *spec = properties[i];
1670 if (!(G_IS_PARAM_SPEC_ENUM (spec) || G_IS_PARAM_SPEC_FLAGS (spec))) {
1671 continue;
1672 }
1673 ptn = g_type_name(spec->value_type);
1674 // does it start with tn?
1675 if (strncmp(tn, ptn, strlen(tn))) {
1676 continue;
1677 }
1678 g_string_append_c(strbuf, '\\n');
1679 g_string_append(strbuf, ptn);
1680 }
1681 ptns = g_string_free (strbuf, FALSE);
1682
1683 /* later we can remove the SUBSECTION Standart/Private, since we only need to
1684 * highlight what is public API */
1685 fprintf (fp, "<SECTION>\\n"
1686 "<FILE>element-%s</FILE>\\n"
1687 "<TITLE>%s</TITLE>\\n"
1688 "Gst%s%s\\n"
1689 "<SUBSECTION Standard>\\n"
1690 "Gst%sClass\\n"
1691 "GST_%s\\n"
1692 "GST_%s_CAST\\n"
1693 "GST_IS_%s\\n"
1694 "GST_%s_CLASS\\n"
1695 "GST_IS_%s_CLASS\\n"
1696 "GST_TYPE_%s\\n"
1697 "<SUBSECTION Private>\\n"
1698 "gst_%s_get_type\\n"
1699 "</SECTION>\\n\\n",
1700 title, title, cct, ptns,
1701 cct, uct, uct, uct, uct, uct, uct, lct);
1702 g_free (title);
1703 g_free (lct);
1704 g_free (uct);
1705 g_free (ptns);
1706}
1707
Olivier Naudan2556a702012-04-16 08:57:32 -04001708EOT
1709
1710close OUTPUT;
1711
1712# Compile and run our file
1713
1714$CC = $ENV{CC} ? $ENV{CC} : "gcc";
1715$LD = $ENV{LD} ? $ENV{LD} : $CC;
1716$CFLAGS = $ENV{CFLAGS} ? "$ENV{CFLAGS}" : "";
1717$LDFLAGS = $ENV{LDFLAGS} ? $ENV{LDFLAGS} : "";
1718
1719my $o_file;
1720if ($CC =~ /libtool/) {
1721 $o_file = "$MODULE-scan.lo"
1722} else {
1723 $o_file = "$MODULE-scan.o"
1724}
1725
1726my $stdout="";
1727if (!defined($VERBOSE) or $VERBOSE eq "0") {
1728 $stdout=">/dev/null";
1729}
1730
1731# Compiling scanner
1732$command = "$CC $stdout $CFLAGS -c -o $o_file $MODULE-scan.c";
1733system("($command)") == 0 or die "Compilation of scanner failed: $!\n";
1734
1735# Linking scanner
1736$command = "$LD $stdout -o $MODULE-scan $o_file $LDFLAGS";
1737system($command) == 0 or die "Linking of scanner failed: $!\n";
1738
1739# Running scanner $MODULE-scan ";
1740system("sh -c ./$MODULE-scan") == 0 or die "Scan failed: $!\n";
1741
1742if (!defined($ENV{"GTK_DOC_KEEP_INTERMEDIATE"})) {
1743 unlink "./$MODULE-scan.c", "./$MODULE-scan.o", "./$MODULE-scan.lo", "./$MODULE-scan";
1744}
1745
1746&UpdateFileIfChanged ($old_hierarchy_filename, $new_hierarchy_filename, 0);
1747# we will merge these in scangobj-merge.py
1748#&UpdateFileIfChanged ($old_interfaces_filename, $new_interfaces_filename, 0);
1749#&UpdateFileIfChanged ($old_prerequisites_filename, $new_prerequisites_filename, 0);
1750#&UpdateFileIfChanged ($old_signals_filename, $new_signals_filename, 0);
1751#&UpdateFileIfChanged ($old_args_filename, $new_args_filename, 0);
Sebastian Dröged8a669d2015-08-19 14:01:25 +03001752#&UpdateFileIfChanged ($old_sections_filename, $new_sections_filename, 0);