1
0
mirror of https://gitlab.gnome.org/GNOME/glib.git synced 2025-06-11 15:13:46 +02:00

Format XML to be more editable. Describe Interfaces better. Add a footnote

* gobject/tut_gobject.xml:
* gobject/tut_gsignal.xml:
* gobject/tut_gtype.xml:
* gobject/tut_howto.xml:
* gobject/tut_intro.xml:
* gobject/tut_tools.xml:
Format XML to be more editable. Describe Interfaces better. Add a
footnote at first occurance of 'maman_'.

svn path=/trunk/; revision=5334
This commit is contained in:
Stefan Kost 2007-02-10 22:08:42 +00:00
parent bdca945da3
commit 8ec7d6ca3f
7 changed files with 2209 additions and 2193 deletions

@ -1,3 +1,14 @@
2007-02-11 Stefan Kost <ensonic@users.sf.net>
* gobject/tut_gobject.xml:
* gobject/tut_gsignal.xml:
* gobject/tut_gtype.xml:
* gobject/tut_howto.xml:
* gobject/tut_intro.xml:
* gobject/tut_tools.xml:
Format XML to be more editable. Describe Interfaces better. Add a
footnote at first occurance of 'maman_'.
2007-02-08 Stefan Kost <ensonic@users.sf.net>
* gobject/tut_gobject.xml:

@ -1,6 +1,5 @@
<?xml version='1.0' encoding="ISO-8859-1"?>
<chapter id="chapter-gobject">
<chapter id="chapter-gobject">
<title>The GObject base class</title>
<para>
@ -541,7 +540,6 @@ maman_bar_instance_init (GTypeInstance *instance,
MamanBar *self = (MamanBar *)instance;
}
static void
maman_bar_set_property (GObject *object,
guint property_id,
@ -721,7 +719,6 @@ g_object_set_property (G_OBJECT (bar), "papa-number", &amp;val);
<sect2 id="gobject-multi-properties">
<title>Accessing multiple properties at once</title>
<para>
It is interesting to note that the <function><link linkend="g-object-set">g_object_set</link></function> and
<function><link linkend="g-object-set-valist">g_object_set_valist</link></function> (vararg version) functions can be used to set
@ -765,10 +762,9 @@ g_object_set (G_OBJECT (foo),
<!-- @todo tell here about how to pass use handle properties in derived classe -->
</sect1>
</chapter>
</chapter>

@ -1,5 +1,5 @@
<?xml version='1.0' encoding="ISO-8859-1"?>
<chapter id="chapter-signal">
<chapter id="chapter-signal">
<title>The GObject messaging system</title>
<sect1 id="closure">
@ -48,8 +48,8 @@ return_type function_callback (... , gpointer user_data);
<listitem><para>
Invocation (<function><link linkend="g-closure-invoke">g_closure_invoke</link></function>): this is what closures
were created for: they hide the details of callback invocation from the
callback invocator.
</para></listitem>
callback invocator.</para>
</listitem>
<listitem><para>
Notification: the closure notifies listeners of certain events such as
closure invocation, closure invalidation and closure finalization. Listeners
@ -64,8 +64,8 @@ return_type function_callback (... , gpointer user_data);
<footnote><para>
Closures are refcounted and notify listeners of their destruction in a two-stage
process: the invalidation notifiers are invoked before the finalization notifiers.
</para></footnote>
</para></listitem>
</para></footnote></para>
</listitem>
</itemizedlist>
</para>
@ -77,7 +77,7 @@ return_type function_callback (... , gpointer user_data);
to connect a callback to a given event, you will either use the simple <type><link linkend="GCClosure">GCClosure</link></type>s
which have a pretty minimal API or the even simpler <function><link linkend="g-signal-connect">g_signal_connect</link></function>
functions (which will be presented a bit later :).
<programlisting>
<programlisting>
GClosure* g_cclosure_new (GCallback callback_func,
gpointer user_data,
GClosureNotify destroy_data);
@ -86,7 +86,7 @@ GClosure* g_cclosure_new_swap (GCallback callback_func,
GClosureNotify destroy_data);
GClosure* g_signal_type_cclosure_new (GType itype,
guint struct_offset);
</programlisting>
</programlisting>
</para>
<para>
@ -125,7 +125,7 @@ GClosure* g_signal_type_cclosure_new (GType itype,
<para>
The following code implements a simple marshaller in C for a C function which takes an
integer as first parameter and returns void.
<programlisting>
<programlisting>
g_cclosure_marshal_VOID__INT (GClosure *closure,
GValue *return_value,
guint n_param_values,
@ -151,7 +151,7 @@ g_cclosure_marshal_VOID__INT (GClosure *closure,
g_marshal_value_peek_int (param_values + 1),
data2);
}
</programlisting>
</programlisting>
</para>
<para>
@ -299,9 +299,6 @@ guint g_signal_newv (const gchar *signal_name,
and removed with <function><link linkend="g-signal-remove-emission-hook">g_signal_remove_emission_hook</link></function>.
</para>
<para>
</para>
</sect2>
<sect2 id="signal-emission">
@ -501,7 +498,8 @@ void g_signal_emit_by_name (gpointer instance,
(even though they are connected to a signal which is being emitted).
</para>
<para>This completely optional filtering mechanism is mainly used as an optimization for signals
<para>
This completely optional filtering mechanism is mainly used as an optimization for signals
which are often emitted for many different reasons: the clients can filter out which events they are
interested into before the closure's marshalling code runs. For example, this is used extensively
by the <emphasis>notify</emphasis> signal of GObject: whenever a property is modified on a GObject,
@ -510,11 +508,13 @@ void g_signal_emit_by_name (gpointer instance,
to only one property to filter most events before receiving them.
</para>
<para>As a simple rule, users can and should set the detail parameter to zero: this will disable completely
<para>
As a simple rule, users can and should set the detail parameter to zero: this will disable completely
this optional filtering.
</para>
</sect2>
</sect1>
</chapter>
</chapter>

@ -1,5 +1,5 @@
<?xml version='1.0' encoding="ISO-8859-1"?>
<chapter>
<chapter id="chapter-gtype">
<title>The Glib Dynamic Type System</title>
<para>
@ -236,6 +236,13 @@ struct _GTypeValueTable
</para></listitem>
<listitem><para>Use prefixing to avoid namespace conflicts with other projects.
If your library (or application) is named <emphasis>Maman</emphasis>,
<footnote>
<para>
<emphasis>Maman</emphasis> is the french word for <emphasis>mum</emphasis>
or <emphasis>mother</emphasis> - nothing more and nothing less.
</para>
</footnote>
prefix all your function names with <emphasis>maman_</emphasis>.
For example: <function>maman_object_method</function>.
</para></listitem>
@ -496,6 +503,9 @@ B *b;
</programlisting>
</para>
<sect2 id="gtype-instantiable-classed-init-done">
<title>Initialization and Destruction</title>
<para>
Instanciation of these types can be done with
<function><link linkend="g-type-create-instance">g_type_create_instance</link></function>:
@ -522,12 +532,12 @@ void g_type_free_instance (GTypeInstance *instance);
initialization of the class structure.
Finally, the object's interfaces are initialized (we will discuss interface initialization
in more detail later).
<footnote id="class-init">
<para>
The class initialization process is entirely implemented in
<function>type_class_init_Wm</function> in <filename>gtype.c</filename>.
</para>
</footnote>
<footnote id="class-init">
<para>
The class initialization process is entirely implemented in
<function>type_class_init_Wm</function> in <filename>gtype.c</filename>.
</para>
</footnote>
</para>
<para>
@ -543,6 +553,7 @@ The class initialization process is entirely implemented in
last living instance of the object, the class is destroyed.
</para>
<para>
Class destruction
<footnote>
@ -642,6 +653,8 @@ The class initialization process is entirely implemented in
</table>
</para>
</sect2>
</sect1>
<sect1 id="gtype-non-instantiable-classed">
@ -650,6 +663,9 @@ The class initialization process is entirely implemented in
<para>
GType's Interfaces are very similar to Java's interfaces. They allow
to describe a common API that several classes will adhere to.
Imagine the play, pause and stop buttons on hifi equipment - those can
be seen as a playback interface. Once you know what the do, you can
control your cd-player, mp3-player or anything that uses these symbols.
To declare an interfacce you have to register a non-instantiable
classed type which derives from
<type><link linkend="GTypeInterface">GTypeInterface</link></type>. The following piece of code declares such an interface.

@ -1,3 +1,4 @@
<?xml version='1.0' encoding="ISO-8859-1"?>
<partintro>
<para>
This chapter tries to answer the real-life questions of users and presents
@ -6,11 +7,7 @@
</para>
</partintro>
<!--
Howto GObject
-->
<chapter id="howto-gobject">
<chapter id="howto-gobject">
<title>How To define and implement a new GObject?</title>
<para>
@ -701,11 +698,13 @@ maman_bar_subtype_class_init (MamanBarSubTypeClass *klass)
programming idiom is often used, this section attemps to explain how to implement it.
</para>
<para>To explicitely chain up to the implementation of the virtual method in the parent class,
<para>
To explicitely chain up to the implementation of the virtual method in the parent class,
you first need a handle to the original parent class structure. This pointer can then be used to
access the original class function pointer and invoke it directly.
<footnote>
<para>The <emphasis>original</emphasis> adjective used in this sentence is not innocuous. To fully
<para>
The <emphasis>original</emphasis> adjective used in this sentence is not innocuous. To fully
understand its meaning, you need to recall how class structures are initialized: for each object type,
the class structure associated to this object is created by first copying the class structure of its
parent type (a simple <function>memcpy</function>) and then by invoking the class_init callback on
@ -742,18 +741,11 @@ b_method_to_call (B *obj, int a)
</sect1>
</chapter>
<!--
End Howto GObject
-->
</chapter>
<!-- End Howto GObject -->
<!--
Howto Interfaces
-->
<chapter id="howto-interface">
<chapter id="howto-interface">
<title>How To define and implement Interfaces?</title>
<sect1 id="howto-interface-define">
@ -982,18 +974,20 @@ baz_instance_init (GTypeInstance *instance,
but it could :)
</para>
</sect1>
</sect1>
<sect1>
<sect1>
<title>Interface definition prerequisites</title>
<para>To specify that an interface requires the presence of other interfaces when implemented,
<para>
To specify that an interface requires the presence of other interfaces when implemented,
GObject introduces the concept of <emphasis>prerequisites</emphasis>: it is possible to associate
a list of prerequisite interfaces to an interface. For example, if object A wishes to implement interface
I1, and if interface I1 has a prerequisite on interface I2, A has to implement both I1 and I2.
</para>
<para>The mechanism described above is, in practice, very similar to Java's interface I1 extends
<para>
The mechanism described above is, in practice, very similar to Java's interface I1 extends
interface I2. The example below shows the GObject equivalent:
<programlisting>
@ -1031,7 +1025,6 @@ ibaz_interface_init (gpointer g_iface,
iface->do_action = (void (*) (MamanIbaz *self))ibaz_do_action;
}
static void
bar_instance_init (GTypeInstance *instance,
gpointer g_class)
@ -1040,7 +1033,6 @@ bar_instance_init (GTypeInstance *instance,
self->instance_member = 0x666;
}
GType
maman_bar_get_type (void)
{
@ -1083,7 +1075,7 @@ maman_bar_get_type (void)
It is very important to notice that the order in which interface implementations are added to the main object
is not random: <function><link linkend="g-type-add-interface-static">g_type_add_interface_static</link></function> must be invoked first on the interfaces which have
no prerequisites and then on the others.
</para>
</para>
<para>
Complete source code showing how to define the MamanIbar interface which requires MamanIbaz and how to
@ -1091,19 +1083,21 @@ maman_bar_get_type (void)
and <filename>sample/interface/maman-bar.{h|c}</filename>.
</para>
</sect1>
</sect1>
<sect1 id="howto-interface-properties">
<sect1 id="howto-interface-properties">
<title>Interface Properties</title>
<para>Starting from version 2.4 of glib, GObject interfaces can also have properties.
<para>
Starting from version 2.4 of glib, GObject interfaces can also have properties.
Declaration of the interface properties is similar to declaring the properties of
ordinary GObject types as explained in <xref linkend="gobject-properties"/>,
except that <function><link linkend="g-object-interface-install-property">g_object_interface_install_property</link></function> is used to
declare the properties instead of <function><link linkend="g-object-class-install-property">g_object_class_install_property</link></function>.
</para>
<para>To include a property named 'name' of type <type>string</type> in the
<para>
To include a property named 'name' of type <type>string</type> in the
<type>maman_ibaz</type> interface example code above, we only need to add one
<footnote>
<para>
@ -1139,13 +1133,15 @@ maman_ibaz_base_init (gpointer g_iface)
</programlisting>
</para>
<para>One point worth noting is that the declared property wasn't assigned an
<para>
One point worth noting is that the declared property wasn't assigned an
integer ID. The reason being that integer IDs of properities are utilized only
inside the get and set methods and since interfaces do not implement properties,
there is no need to assign integer IDs to interface properties.
</para>
<para>The story for the implementers of the interface is also quite trivial.
<para>
The story for the implementers of the interface is also quite trivial.
An implementer shall declare and define it's properties in the usual way as
explained in <xref linkend="gobject-properties"/>, except for one small
change: it shall declare the properties of the interface it implements using
@ -1259,22 +1255,11 @@ maman_baz_get_property (GObject * object, guint prop_id,
</programlisting>
</para>
</sect1>
</sect1>
</chapter>
<!-- End Howto Interfaces -->
<!--
End Howto Interfaces
-->
<!--
start Howto Signals
-->
<chapter id="howto-signals">
<chapter id="howto-signals">
<title>Howto create and use signals</title>
@ -1291,14 +1276,15 @@ maman_baz_get_property (GObject * object, guint prop_id,
just emit events which can be received by numerous clients.
</para>
<sect1 id="howto-simple-signals">
<title>Simple use of signals</title>
<sect1 id="howto-simple-signals">
<title>Simple use of signals</title>
<para>The most basic use of signals is to implement simple event notification: for example, if we have a
MamanFile object, and if this object has a write method, we might wish to be notified whenever someone
uses this method. The code below shows how the user can connect a callback to the write signal. Full code
for this simple example is located in <filename>sample/signal/maman-file.{h|c}</filename> and
in <filename>sample/signal/test.c</filename>
<para>
The most basic use of signals is to implement simple event notification: for example, if we have a
MamanFile object, and if this object has a write method, we might wish to be notified whenever someone
uses this method. The code below shows how the user can connect a callback to the write signal. Full code
for this simple example is located in <filename>sample/signal/maman-file.{h|c}</filename> and
in <filename>sample/signal/test.c</filename>
<programlisting>
file = g_object_new (MAMAN_FILE_TYPE, NULL);
@ -1308,10 +1294,10 @@ g_signal_connect (G_OBJECT (file), "write",
maman_file_write (file, buffer, 50);
</programlisting>
</para>
</para>
<para>
The <type>MamanFile</type> signal is registered in the class_init function:
<para>
The <type>MamanFile</type> signal is registered in the class_init function:
<programlisting>
klass->write_signal_id =
g_signal_newv ("write",
@ -1325,7 +1311,7 @@ klass->write_signal_id =
0 /* n_params */,
NULL /* param_types */);
</programlisting>
and the signal is emited in <function>maman_file_write</function>:
and the signal is emited in <function>maman_file_write</function>:
<programlisting>
void maman_file_write (MamanFile *self, guint8 *buffer, guint32 size)
{
@ -1336,53 +1322,55 @@ void maman_file_write (MamanFile *self, guint8 *buffer, guint32 size)
NULL);
}
</programlisting>
As shown above, you can safely set the details parameter to zero if you do not know what it can be used for.
For a discussion of what you could used it for, see <xref linkend="signal-detail"/>
</para>
<para>
The signature of the signal handler in the above example is defined as
<function>g_cclosure_marshal_VOID__VOID</function>. Its name follows
a simple convention which encodes the function parameter and return value
types in the function name. Specifically, the value infront of the double
underscore is the type of the return value, while the value(s) after the
double underscore denote the parameter types.
The header <filename>gobject/gmarshal.h</filename> defines a set of commonly
needed closures that one can use.
As shown above, you can safely set the details parameter to zero if you do not know what it can be used for.
For a discussion of what you could used it for, see <xref linkend="signal-detail"/>
</para>
</sect1>
<para>
The signature of the signal handler in the above example is defined as
<function>g_cclosure_marshal_VOID__VOID</function>. Its name follows
a simple convention which encodes the function parameter and return value
types in the function name. Specifically, the value infront of the double
underscore is the type of the return value, while the value(s) after the
double underscore denote the parameter types.
The header <filename>gobject/gmarshal.h</filename> defines a set of commonly
needed closures that one can use.
</para>
</sect1>
<sect1>
<title>How to provide more flexibility to users?</title>
<sect1>
<title>How to provide more flexibility to users?</title>
<para>
The previous implementation does the job but the signal facility of GObject can be used to provide
even more flexibility to this file change notification mechanism. One of the key ideas is to make the process
of writing data to the file part of the signal emission process to allow users to be notified either
before or after the data is written to the file.
</para>
<para>The previous implementation does the job but the signal facility of GObject can be used to provide
even more flexibility to this file change notification mechanism. One of the key ideas is to make the process
of writing data to the file part of the signal emission process to allow users to be notified either
before or after the data is written to the file.
</para>
<para>
To integrate the process of writing the data to the file into the signal emission mechanism, we can
register a default class closure for this signal which will be invoked during the signal emission, just like
any other user-connected signal handler.
</para>
<para>To integrate the process of writing the data to the file into the signal emission mechanism, we can
register a default class closure for this signal which will be invoked during the signal emission, just like
any other user-connected signal handler.
</para>
<para>The first step to implement this idea is to change the signature of the signal: we need to pass
around the buffer to write and its size. To do this, we use our own marshaller which will be generated
through glib's genmarshall tool. We thus create a file named <filename>marshall.list</filename> which contains
the following single line:
<para>
The first step to implement this idea is to change the signature of the signal: we need to pass
around the buffer to write and its size. To do this, we use our own marshaller which will be generated
through glib's genmarshall tool. We thus create a file named <filename>marshall.list</filename> which contains
the following single line:
<programlisting>
VOID:POINTER,UINT
</programlisting>
and use the Makefile provided in <filename>sample/signal/Makefile</filename> to generate the file named
<filename>maman-file-complex-marshall.c</filename>. This C file is finally included in
<filename>maman-file-complex.c</filename>.
</para>
and use the Makefile provided in <filename>sample/signal/Makefile</filename> to generate the file named
<filename>maman-file-complex-marshall.c</filename>. This C file is finally included in
<filename>maman-file-complex.c</filename>.
</para>
<para>Once the marshaller is present, we register the signal and its marshaller in the class_init function
of the object <type>MamanFileComplex</type> (full source for this object is included in
<filename>sample/signal/maman-file-complex.{h|c}</filename>):
<para>
Once the marshaller is present, we register the signal and its marshaller in the class_init function
of the object <type>MamanFileComplex</type> (full source for this object is included in
<filename>sample/signal/maman-file-complex.{h|c}</filename>):
<programlisting>
GClosure *default_closure;
GType param_types[2];
@ -1405,13 +1393,13 @@ klass->write_signal_id =
2 /* n_params */,
param_types /* param_types */);
</programlisting>
The code shown above first creates the closure which contains the code to complete the file write. This
closure is registered as the default class_closure of the newly created signal.
</para>
The code shown above first creates the closure which contains the code to complete the file write. This
closure is registered as the default class_closure of the newly created signal.
</para>
<para>
Of course, you need to implement completely the code for the default closure since I just provided
a skeleton:
<para>
Of course, you need to implement completely the code for the default closure since I just provided
a skeleton:
<programlisting>
static void
default_write_signal_handler (GObject *obj, guint8 *buffer, guint size, gpointer user_data)
@ -1421,10 +1409,11 @@ default_write_signal_handler (GObject *obj, guint8 *buffer, guint size, gpointer
g_print ("default signal handler: 0x%x %u\n", buffer, size);
}
</programlisting>
</para>
</para>
<para>Finally, the client code must invoke the <function>maman_file_complex_write</function> function which
triggers the signal emission:
<para>
Finally, the client code must invoke the <function>maman_file_complex_write</function> function which
triggers the signal emission:
<programlisting>
void maman_file_complex_write (MamanFileComplex *self, guint8 *buffer, guint size)
{
@ -1435,20 +1424,21 @@ void maman_file_complex_write (MamanFileComplex *self, guint8 *buffer, guint siz
buffer, size);
}
</programlisting>
</para>
</para>
<para>The client code (as shown in <filename>sample/signal/test.c</filename> and below) can now connect signal handlers before
and after the file write is completed: since the default signal handler which does the write itself runs during the
RUN_LAST phase of the signal emission, it will run after all handlers connected with <function><link linkend="g-signal-connect">g_signal_connect</link></function>
and before all handlers connected with <function><link linkend="g-signal-connect-after">g_signal_connect_after</link></function>. If you intent to write a GObject
which emits signals, I would thus urge you to create all your signals with the G_SIGNAL_RUN_LAST such that your users
have a maximum of flexibility as to when to get the event. Here, we combined it with G_SIGNAL_NO_RECURSE and
G_SIGNAL_NO_HOOKS to ensure our users will not try to do really weird things with our GObject. I strongly advise you
to do the same unless you really know why (in which case you really know the inner workings of GSignal by heart and
you are not reading this).
</para>
<para>
The client code (as shown in <filename>sample/signal/test.c</filename> and below) can now connect signal handlers before
and after the file write is completed: since the default signal handler which does the write itself runs during the
RUN_LAST phase of the signal emission, it will run after all handlers connected with <function><link linkend="g-signal-connect">g_signal_connect</link></function>
and before all handlers connected with <function><link linkend="g-signal-connect-after">g_signal_connect_after</link></function>. If you intent to write a GObject
which emits signals, I would thus urge you to create all your signals with the G_SIGNAL_RUN_LAST such that your users
have a maximum of flexibility as to when to get the event. Here, we combined it with G_SIGNAL_NO_RECURSE and
G_SIGNAL_NO_HOOKS to ensure our users will not try to do really weird things with our GObject. I strongly advise you
to do the same unless you really know why (in which case you really know the inner workings of GSignal by heart and
you are not reading this).
</para>
<para>
<para>
<programlisting>
static void complex_write_event_before (GObject *file, guint8 *buffer, guint size, gpointer user_data)
{
@ -1482,13 +1472,13 @@ static void test_file_complex (void)
g_object_unref (G_OBJECT (file));
}
</programlisting>
The code above generates the following output on my machine:
The code above generates the following output on my machine:
<programlisting>
Complex Write event before: 0xbfffe280, 50
default signal handler: 0xbfffe280 50
Complex Write event after: 0xbfffe280, 50
</programlisting>
</para>
</para>
<sect2>
@ -1592,12 +1582,10 @@ klass->write_signal_id =
</sect2>
</sect1>
</sect1>
<sect1>
<sect1>
<title>How users can abuse signals (and why some think it is good)</title>
<para>Now that you know how to create signals to which the users can connect easily and at any point in
@ -1607,7 +1595,8 @@ klass->write_signal_id =
This will make you feel good and eleet.
</para>
<para>The users can:
<para>
The users can:
<itemizedlist>
<listitem><para>stop the emission of the signal at anytime</para></listitem>
<listitem><para>override the default handler of the signal if it is stored as a function
@ -1616,30 +1605,34 @@ klass->write_signal_id =
</itemizedlist>
</para>
<para>In both cases, the original programmer should be as careful as possible to write code which is
<para>
In both cases, the original programmer should be as careful as possible to write code which is
resistant to the fact that the default handler of the signal might not able to run. This is obviously
not the case in the example used in the previous sections since the write to the file depends on whether
or not the default handler runs (however, this might be your goal: to allow the user to prevent the file
write if he wishes to).
</para>
<para>If all you want to do is to stop the signal emission from one of the callbacks you connected yourself,
<para>
If all you want to do is to stop the signal emission from one of the callbacks you connected yourself,
you can call <function><link linkend="g-signal-stop-by-name">g_signal_stop_by_name</link></function>. Its use is very simple which is why I won't detail
it further.
</para>
<para>If the signal's default handler is just a class function pointer, it is also possible to override
<para>
If the signal's default handler is just a class function pointer, it is also possible to override
it yourself from the class_init function of a type which derives from the parent. That way, when the signal
is emitted, the parent class will use the function provided by the child as a signal default handler.
Of course, it is also possible (and recommended) to chain up from the child to the parent's default signal
handler to ensure the integrity of the parent object.
</para>
<para>Overriding a class method and chaining up was demonstrated in <xref linkend="howto-gobject-methods"/>
which is why I won't bother to show exactly how to do it here again.</para>
<para>
Overriding a class method and chaining up was demonstrated in <xref linkend="howto-gobject-methods"/>
which is why I won't bother to show exactly how to do it here again.
</para>
</sect1>
</sect1>
</chapter>
@ -1723,10 +1716,3 @@ g_object_do_class_init (GObjectClass *class)
</sect2>
-->
<!--
<capter1 id="howto-doc">
<title>How to generate API documentation for your type?</title>
</chapter>
-->

@ -1,85 +1,90 @@
<chapter>
<title>Background</title>
<?xml version='1.0' encoding="ISO-8859-1"?>
<chapter id="chapter-intro">
<title>Background</title>
<para>
GObject, and its lower-level type system, GType, are used by GTK+ and most GNOME libraries to
provide:
<itemizedlist>
<listitem><para>object-oriented C-based APIs and</para></listitem>
<listitem><para>automatic transparent API bindings to other compiled
or interpreted languages.</para></listitem>
</itemizedlist>
</para>
<para>
GObject, and its lower-level type system, GType, are used by GTK+ and most GNOME libraries to
provide:
<itemizedlist>
<listitem><para>object-oriented C-based APIs and</para></listitem>
<listitem><para>automatic transparent API bindings to other compiled
or interpreted languages.</para></listitem>
</itemizedlist>
</para>
<para>A lot of programmers are used to work with compiled-only or dynamically interpreted-only
languages and do not understand the challenges associated with cross-language interoperability.
This introduction tries to provide an insight into these challenges. describes briefly
the solution choosen by GLib.
</para>
<para>
A lot of programmers are used to work with compiled-only or dynamically interpreted-only
languages and do not understand the challenges associated with cross-language interoperability.
This introduction tries to provide an insight into these challenges. describes briefly
the solution choosen by GLib.
</para>
<para>The following chapters go into greater detail into how GType and GObject work and
how you can use them as a C programmer. It is useful to keep in mind that
allowing access to C objects from other interpreted languages was one of the major design
goals: this can often explain the sometimes rather convoluted APIs and features present
in this library.
</para>
<para>
The following chapters go into greater detail into how GType and GObject work and
how you can use them as a C programmer. It is useful to keep in mind that
allowing access to C objects from other interpreted languages was one of the major design
goals: this can often explain the sometimes rather convoluted APIs and features present
in this library.
</para>
<sect1>
<title>Data types and programming</title>
<sect1>
<title>Data types and programming</title>
<para>
One could say (I have seen such definitions used in some textbooks on programming language theory)
that a programming language is merely a way to create data types and manipulate them. Most languages
provide a number of language-native types and a few primitives to create more complex types based
on these primitive types.
</para>
<para>
One could say (I have seen such definitions used in some textbooks on programming language theory)
that a programming language is merely a way to create data types and manipulate them. Most languages
provide a number of language-native types and a few primitives to create more complex types based
on these primitive types.
</para>
<para>
In C, the language provides types such as <emphasis>char</emphasis>, <emphasis>long</emphasis>,
<emphasis>pointer</emphasis>. During compilation of C code, the compiler maps these
language types to the compiler's target architecture machine types. If you are using a C interpreter
(I have never seen one myself but it is possible :), the interpreter (the program which interprets
the source code and executes it) maps the language types to the machine types of the target machine at
runtime, during the program execution (or just before execution if it uses a Just In Time compiler engine).
</para>
<para>
In C, the language provides types such as <emphasis>char</emphasis>, <emphasis>long</emphasis>,
<emphasis>pointer</emphasis>. During compilation of C code, the compiler maps these
language types to the compiler's target architecture machine types. If you are using a C interpreter
(I have never seen one myself but it is possible :), the interpreter (the program which interprets
the source code and executes it) maps the language types to the machine types of the target machine at
runtime, during the program execution (or just before execution if it uses a Just In Time compiler engine).
</para>
<para>Perl and Python which are interpreted languages do not really provide type definitions similar
to those used by C. Perl and Python programmers manipulate variables and the type of the variables
is decided only upon the first assignment or upon the first use which forces a type on the variable.
The interpreter also often provides a lot of automatic conversions from one type to the other. For example,
in Perl, a variable which holds an integer can be automatically converted to a string given the
required context:
<para>
Perl and Python which are interpreted languages do not really provide type definitions similar
to those used by C. Perl and Python programmers manipulate variables and the type of the variables
is decided only upon the first assignment or upon the first use which forces a type on the variable.
The interpreter also often provides a lot of automatic conversions from one type to the other. For example,
in Perl, a variable which holds an integer can be automatically converted to a string given the
required context:
<programlisting>
my $tmp = 10;
print "this is an integer converted to a string:" . $tmp . "\n";
</programlisting>
Of course, it is also often possible to explicitely specify conversions when the default conversions provided
by the language are not intuitive.
</para>
Of course, it is also often possible to explicitely specify conversions when the default conversions provided
by the language are not intuitive.
</para>
</sect1>
</sect1>
<sect1>
<title>Exporting a C API</title>
<sect1>
<title>Exporting a C API</title>
<para>C APIs are defined by a set of functions and global variables which are usually exported from a
binary. C functions have an arbitrary number of arguments and one return value. Each function is thus
uniquely identified by the function name and the set of C types which describe the function arguments
and return value. The global variables exported by the API are similarly identified by their name and
their type.
</para>
<para>
C APIs are defined by a set of functions and global variables which are usually exported from a
binary. C functions have an arbitrary number of arguments and one return value. Each function is thus
uniquely identified by the function name and the set of C types which describe the function arguments
and return value. The global variables exported by the API are similarly identified by their name and
their type.
</para>
<para>
A C API is thus merely defined by a set of names to which a set of types are associated. If you know the
function calling convention and the mapping of the C types to the machine types used by the platform you
are on, you can resolve the name of each function to find where the code associated to this function
is located in memory, and then construct a valid argument list for the function. Finally, all you have to
do is triger a call to the target C function with the argument list.
</para>
<para>
A C API is thus merely defined by a set of names to which a set of types are associated. If you know the
function calling convention and the mapping of the C types to the machine types used by the platform you
are on, you can resolve the name of each function to find where the code associated to this function
is located in memory, and then construct a valid argument list for the function. Finally, all you have to
do is triger a call to the target C function with the argument list.
</para>
<para>
For the sake of discussion, here is a sample C function and the associated 32 bit x86
assembly code generated by gcc on my linux box:
<para>
For the sake of discussion, here is a sample C function and the associated 32 bit x86
assembly code generated by gcc on my linux box:
<programlisting>
static void function_foo (int foo)
{}
@ -95,40 +100,42 @@ int main (int argc, char *argv[])
push $0xa
call 0x80482f4 &lt;function_foo>
</programlisting>
The assembly code shown above is pretty straightforward: the first instruction pushes
the hexadecimal value 0xa (decimal value 10) as a 32 bit integer on the stack and calls
<function>function_foo</function>. As you can see, C function calls are implemented by
gcc by native function calls (this is probably the fastest implementation possible).
</para>
The assembly code shown above is pretty straightforward: the first instruction pushes
the hexadecimal value 0xa (decimal value 10) as a 32 bit integer on the stack and calls
<function>function_foo</function>. As you can see, C function calls are implemented by
gcc by native function calls (this is probably the fastest implementation possible).
</para>
<para>
Now, let's say we want to call the C function <function>function_foo</function> from
a python program. To do this, the python interpreter needs to:
<itemizedlist>
<listitem><para>Find where the function is located. This means probably find the binary generated by the C compiler
which exports this functions.</para></listitem>
<listitem><para>Load the code of the function in executable memory.</para></listitem>
<listitem><para>Convert the python parameters to C-compatible parameters before calling
the function.</para></listitem>
<listitem><para>Call the function with the right calling convention</para></listitem>
<listitem><para>Convert the return values of the C function to python-compatible
variables to return them to the python code.</para></listitem>
</itemizedlist>
</para>
<para>
Now, let's say we want to call the C function <function>function_foo</function> from
a python program. To do this, the python interpreter needs to:
<itemizedlist>
<listitem><para>Find where the function is located. This means probably find the binary generated by the C compiler
which exports this functions.</para></listitem>
<listitem><para>Load the code of the function in executable memory.</para></listitem>
<listitem><para>Convert the python parameters to C-compatible parameters before calling
the function.</para></listitem>
<listitem><para>Call the function with the right calling convention</para></listitem>
<listitem><para>Convert the return values of the C function to python-compatible
variables to return them to the python code.</para></listitem>
</itemizedlist>
</para>
<para>The process described above is pretty complex and there are a lot of ways to make it entirely automatic
and transparent to the C and the Python programmers:
<itemizedlist>
<listitem><para>The first solution is to write by hand a lot of glue code, once for each function exported or imported,
which does the python to C parameter conversion and the C to python return value conversion. This glue code is then
linked with the interpreter which allows python programs to call a python functions which delegates the work to the
C function.</para></listitem>
<listitem><para>Another nicer solution is to automatically generate the glue code, once for each function exported or
imported, with a special compiler which
reads the original function signature.</para></listitem>
<listitem><para>The solution used by GLib is to use the GType library which holds at runtime a description of
all the objects manipulated by the programmer. This so-called <emphasis>dynamic type</emphasis><footnote>
<para>
<para>
The process described above is pretty complex and there are a lot of ways to make it entirely automatic
and transparent to the C and the Python programmers:
<itemizedlist>
<listitem><para>The first solution is to write by hand a lot of glue code, once for each function exported or imported,
which does the python to C parameter conversion and the C to python return value conversion. This glue code is then
linked with the interpreter which allows python programs to call a python functions which delegates the work to the
C function.</para></listitem>
<listitem><para>Another nicer solution is to automatically generate the glue code, once for each function exported or
imported, with a special compiler which
reads the original function signature.</para></listitem>
<listitem><para>The solution used by GLib is to use the GType library which holds at runtime a description of
all the objects manipulated by the programmer. This so-called <emphasis>dynamic type</emphasis>
<footnote>
<para>
There are numerous different implementations of dynamic type systems: all C++
compilers have one, Java and .NET have one too. A dynamic type system allows you
to get information about every instantiated object at runtime. It can be implemented
@ -136,16 +143,14 @@ all the objects manipulated by the programmer. This so-called <emphasis>dynamic
of its associated type in the type system. It can also be implemented by introspection
interfaces. The common point between all these different type systems and implementations
is that they all allow you to query for object metadata at runtime.
</para>
</footnote>
library is then
used by special generic glue code to automatically convert function parameters and function calling conventions
between different runtime domains.</para></listitem>
</itemizedlist>
The greatest advantage of the solution implemented by GType is that the glue code sitting at the runtime domain
boundaries is written once: the figure below states this more clearly.
<figure>
</para>
</footnote>
library is then used by special generic glue code to automatically convert function parameters and
function calling conventions between different runtime domains.</para></listitem>
</itemizedlist>
The greatest advantage of the solution implemented by GType is that the glue code sitting at the runtime domain
boundaries is written once: the figure below states this more clearly.
<figure>
<mediaobject>
<imageobject> <!-- this is for HTML output -->
<imagedata fileref="glue.png" format="PNG" align="center"/>
@ -154,20 +159,21 @@ boundaries is written once: the figure below states this more clearly.
<imagedata fileref="glue.jpg" format="JPG" align="center"/>
</imageobject>
</mediaobject>
</figure>
</figure>
Currently, there exist at least Python and Perl generic glue code which makes it possible to use
C objects written with GType directly in Python or Perl, with a minimum amount of work: there
is no need to generate huge amounts of glue code either automatically or by hand.
</para>
Currently, there exist at least Python and Perl generic glue code which makes it possible to use
C objects written with GType directly in Python or Perl, with a minimum amount of work: there
is no need to generate huge amounts of glue code either automatically or by hand.
</para>
<para>Although that goal was arguably laudable, its pursuit has had a major influence on
the whole GType/GObject library. C programmers are likely to be puzzled at the complexity
of the features exposed in the following chapters if they forget that the GType/GObject library
was not only designed to offer OO-like features to C programmers but also transparent
cross-language interoperability.
</para>
<para>
Although that goal was arguably laudable, its pursuit has had a major influence on
the whole GType/GObject library. C programmers are likely to be puzzled at the complexity
of the features exposed in the following chapters if they forget that the GType/GObject library
was not only designed to offer OO-like features to C programmers but also transparent
cross-language interoperability.
</para>
</sect1>
</sect1>
</chapter>

@ -1,3 +1,4 @@
<?xml version='1.0' encoding="ISO-8859-1"?>
<partintro>
<para>
Several useful developer tools have been build around GObject technology.