inspect
is the C part of the GObject type
inspector. Its
role is identical to gtk-doc's MODULE-scan
auxiliary
binary built by gtkdoc-scangobj
: given a list of types, use
GObject inspection means to find about inheritance, signals, properties, … of
these types and dump them in parseable text form.
Built by standard automake rules, unconditionally if possible (if documentation generation is enabled of course). The Makefile should just state something like:
BUILT_SOURCES = inspect.c noinst_PROGRAMS = inspect inspect_SOURCES = inspect.c inspect_LDADD = $(PROJECT_LIBS) inspect.c: deps $(YAGDOC_MKINSPECT)
and the documentation build rules will depend on inspect
.
To avoid chicken and egg problems, dependencies on Gtk+ devel files and
frequent rebuilds, inspect
uses introspection in addition to
inspection. Its source code is essentially constant (most customizations
will be things set up once in project's lifetime). It takes the list of
types to inspect from the standard input and dlopen()
s self to
dynamically find the type functions, to find out whether it was linked with
Gtk+, whether functions such as
gtk_widget_class_list_style_properties()
are available, etc.
The user just has to add all necessary libraries to LDADD
.
This means GModule and -export-dynamic
must work. However,
these featues work on all interesting platforms (-export-dynamic
is a requirement for Glade signal autoconnection too).
If GObject inspection is not required/desirable, inspect
can
be changed into a dummy binary by not defining preprocessor symbol
YAGDOC_INSPECT
. In this case not even any GLib headers are
included, therefore it is possible to build inspect
always.
All inspection results are dumped to the standard output. Since there are different kinds of information, the output has “sections”. This should somewhat reduce the clutter.
The following output sections exist:
Section | Format | Description |
---|---|---|
Types |
type_name get_type_function_name | Association between get-type functions and type names. This section (obviously) includes only types given on standard input – the names of other get-type functions are neither useful nor possible to obtain. This section has no direct gtk-doc equivalent. |
Flags |
type_name
< flags> |
Type flags:f – fundamental,d – derivable,D – deep derivable,i – instantiable,n – interface,a – abstract,c – classed,v – has value table,V – is value type.This section has no direct gtk-doc equivalent. |
Signals |
type_name
signal_name
< flags>
return_type
argument_type… |
All signals, possible flags are:f – run first,l – run last,c – run cleanup,r – no recurse,d – detailed,a – action,h – no hooks.Equivalent to MODULE.signals . |
Children |
type_name child_type_name… | All types derived from a type, roughly equivalent to
MODULE.hierarchy . |
Interfaces |
type_name interface_type_name… | All interfaces a type implements, identical to
MODULE.interfaces . |
Prerequisites |
interface_type_name req_type_name… | Interface implementation prerequisites, identical to
MODULE.prerequisites . |
Properties |
type_name
property_name
< flags>
property_type_name
" blurb"
default_value
value_constraints |
All properties, possible flags are:r – read,w – write,c – construction,C – construction only.Equivalent to a part of MODULE.args . |
Child Properties |
see Properties |
Printed if at least one of inspected types is a GtkContainer
subclass. Equivalent to a part of MODULE.args . |
Style Properties |
see Properties |
Printed if at least one of inspected types is a GtkWidget
subclass. Equivalent to a part of MODULE.args . |
Foo Properties |
see Properties |
Extension properties, each new property type gets its own section. This section has no direct gtk-doc equivalent. |
Bindings |
type_name
" key"
signal_name( args…) |
Default bindings. Printed if at least one of inspected types is a GtkWidget subclass. This section has no direct gtk-doc equivalent. |
Non-object and non-interface types are included in the output too. It is up to the output processor what it will do with this information (for instance showing hierarchy for boxed types does not sound like a bad idea).
To be able to list briefly inherited signals and properties in object sections, the inheritance tree is repeatedly scanned and all new parent, children and interface types found are added until the process converges (usually it takes 4 steps). The type hierarchy is also always populated with
G_TYPE_ENUM
G_TYPE_FLAGS
G_TYPE_BOXED
G_TYPE_PARAM
G_TYPE_POINTER
G_TYPE_OBJECT
G_TYPE_INTERFACE
root types. This means that the output typically contains information about lot more types than just those requested.
Several extension points, i.e. places in the C code where the user can want to insert hooks into (as opposed to Python postprocessing which is much easier for simple tranforms) have been identified:
Initialization function, many projects think they need this and a few actually do. The default
#ifdef G_THREADS_ENABLED g_thread_init(NULL); #endif g_type_init(); g_type_class_ref(G_TYPE_OBJECT);
essentially worked with everything I tried.
g_thread_init(NULL)
does no harm for libraries not using
threads and is normally sufficient for those that do,g_type_init()
is needed for object inspection to work,g_type_class_ref(G_TYPE_OBJECT)
forces initialization of
GObject class, without this interface inspection can fail if things occur in
a wrong order.It is called as init(&argc, &argv)
therefore
library initialization functions that require command line arguments can get
them. Extensions are done by replacing it completely.
Special properties, some projects may make use of this. Child and style properties of Gtk+ widgets are also implemented as special properties, though they are built in. They are defined with a struct
typedef struct { const gchar *name; const gchar *req_type_name; GType req_type; const gchar *query_func_name; QueryPropertiesFunc query_func; } PropertiesSpec;
where name
will appear in the section title,
req_type_name
is the name of the type the inspected type must
be a subclass of to be inspected for this special property,
query_func_name
is the name of the property query function with
the same prototype as g_object_class_list_properties()
:
typedef GParamSpec** (*QueryPropertiesFunc)(gpointer class, guint *nproperties);
Fields req_type
and query_func
are filled
dynamically and should be set to zeroes.
For instance the definitions of child and style special properties are:
{ "Child", "GtkContainer", 0, "gtk_container_class_list_child_properties", NULL, }, { "Style", "GtkWidget", 0, "gtk_widget_class_list_style_properties", NULL, },
Property descriptors, projects will seldom need such extension because new fundamental param specs are rare. These are functions of the type
typedef gboolean (*DescribePropertyFunc)(const GParamSpec *paramspec, gchar **default_value, gchar **constraints);
that describe the default value and constraints of properties (more precisely GParamSpec subclasses). The constraints string can be probably abused for other things too (especially when coupled with a Python hook).
The thread initialization in the default function requires GThread. Do any platforms exist where GModule works but GThread does not? This may need rethink.
On systems with LD_PRELOAD
or a similar feature and working
inter-library dependencies, inspect
does not need to be linked
with the inspected libraries at all. Just run
LD_PRELOAD=/usr/lib64/libgimpui-2.0.so inspect <<<gimp_preview_get_type
to inspect GimpPreview.
Unfortunately while this is fun to play with, it probably cannot be used
generally due to limited portability and the fact that if yagdoc came with an
universal inspect
excetuable, it would have to be linked with
GModule and GObject and therefore GLib could not use yagdoc – without causing
cyclic dependencies. Obviously, we cannot obtain GModule symbols by
introspection (unless we use libltdl or platform dlopen() equivalent
directly).