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

View File

@@ -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> 2007-02-08 Stefan Kost <ensonic@users.sf.net>
* gobject/tut_gobject.xml: * gobject/tut_gobject.xml:

View File

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

View File

@@ -1,5 +1,5 @@
<?xml version='1.0' encoding="ISO-8859-1"?> <?xml version='1.0' encoding="ISO-8859-1"?>
<chapter id="chapter-signal"> <chapter id="chapter-signal">
<title>The GObject messaging system</title> <title>The GObject messaging system</title>
<sect1 id="closure"> <sect1 id="closure">
@@ -48,8 +48,8 @@ return_type function_callback (... , gpointer user_data);
<listitem><para> <listitem><para>
Invocation (<function><link linkend="g-closure-invoke">g_closure_invoke</link></function>): this is what closures 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 were created for: they hide the details of callback invocation from the
callback invocator. callback invocator.</para>
</para></listitem> </listitem>
<listitem><para> <listitem><para>
Notification: the closure notifies listeners of certain events such as Notification: the closure notifies listeners of certain events such as
closure invocation, closure invalidation and closure finalization. Listeners closure invocation, closure invalidation and closure finalization. Listeners
@@ -64,8 +64,8 @@ return_type function_callback (... , gpointer user_data);
<footnote><para> <footnote><para>
Closures are refcounted and notify listeners of their destruction in a two-stage Closures are refcounted and notify listeners of their destruction in a two-stage
process: the invalidation notifiers are invoked before the finalization notifiers. process: the invalidation notifiers are invoked before the finalization notifiers.
</para></footnote> </para></footnote></para>
</para></listitem> </listitem>
</itemizedlist> </itemizedlist>
</para> </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 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> 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 :). functions (which will be presented a bit later :).
<programlisting> <programlisting>
GClosure* g_cclosure_new (GCallback callback_func, GClosure* g_cclosure_new (GCallback callback_func,
gpointer user_data, gpointer user_data,
GClosureNotify destroy_data); GClosureNotify destroy_data);
@@ -86,7 +86,7 @@ GClosure* g_cclosure_new_swap (GCallback callback_func,
GClosureNotify destroy_data); GClosureNotify destroy_data);
GClosure* g_signal_type_cclosure_new (GType itype, GClosure* g_signal_type_cclosure_new (GType itype,
guint struct_offset); guint struct_offset);
</programlisting> </programlisting>
</para> </para>
<para> <para>
@@ -125,7 +125,7 @@ GClosure* g_signal_type_cclosure_new (GType itype,
<para> <para>
The following code implements a simple marshaller in C for a C function which takes an The following code implements a simple marshaller in C for a C function which takes an
integer as first parameter and returns void. integer as first parameter and returns void.
<programlisting> <programlisting>
g_cclosure_marshal_VOID__INT (GClosure *closure, g_cclosure_marshal_VOID__INT (GClosure *closure,
GValue *return_value, GValue *return_value,
guint n_param_values, guint n_param_values,
@@ -151,7 +151,7 @@ g_cclosure_marshal_VOID__INT (GClosure *closure,
g_marshal_value_peek_int (param_values + 1), g_marshal_value_peek_int (param_values + 1),
data2); data2);
} }
</programlisting> </programlisting>
</para> </para>
<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>. and removed with <function><link linkend="g-signal-remove-emission-hook">g_signal_remove_emission_hook</link></function>.
</para> </para>
<para>
</para>
</sect2> </sect2>
<sect2 id="signal-emission"> <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). (even though they are connected to a signal which is being emitted).
</para> </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 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 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, 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. to only one property to filter most events before receiving them.
</para> </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. this optional filtering.
</para> </para>
</sect2> </sect2>
</sect1> </sect1>
</chapter> </chapter>

View File

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

View File

@@ -1,3 +1,4 @@
<?xml version='1.0' encoding="ISO-8859-1"?>
<partintro> <partintro>
<para> <para>
This chapter tries to answer the real-life questions of users and presents This chapter tries to answer the real-life questions of users and presents
@@ -6,11 +7,7 @@
</para> </para>
</partintro> </partintro>
<!-- <chapter id="howto-gobject">
Howto GObject
-->
<chapter id="howto-gobject">
<title>How To define and implement a new GObject?</title> <title>How To define and implement a new GObject?</title>
<para> <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. programming idiom is often used, this section attemps to explain how to implement it.
</para> </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 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. access the original class function pointer and invoke it directly.
<footnote> <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, 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 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 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> </sect1>
</chapter> </chapter>
<!-- End Howto GObject -->
<!--
End Howto GObject
-->
<!-- <chapter id="howto-interface">
Howto Interfaces
-->
<chapter id="howto-interface">
<title>How To define and implement Interfaces?</title> <title>How To define and implement Interfaces?</title>
<sect1 id="howto-interface-define"> <sect1 id="howto-interface-define">
@@ -982,18 +974,20 @@ baz_instance_init (GTypeInstance *instance,
but it could :) but it could :)
</para> </para>
</sect1> </sect1>
<sect1> <sect1>
<title>Interface definition prerequisites</title> <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 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 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. I1, and if interface I1 has a prerequisite on interface I2, A has to implement both I1 and I2.
</para> </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: interface I2. The example below shows the GObject equivalent:
<programlisting> <programlisting>
@@ -1031,7 +1025,6 @@ ibaz_interface_init (gpointer g_iface,
iface->do_action = (void (*) (MamanIbaz *self))ibaz_do_action; iface->do_action = (void (*) (MamanIbaz *self))ibaz_do_action;
} }
static void static void
bar_instance_init (GTypeInstance *instance, bar_instance_init (GTypeInstance *instance,
gpointer g_class) gpointer g_class)
@@ -1040,7 +1033,6 @@ bar_instance_init (GTypeInstance *instance,
self->instance_member = 0x666; self->instance_member = 0x666;
} }
GType GType
maman_bar_get_type (void) 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 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 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. no prerequisites and then on the others.
</para> </para>
<para> <para>
Complete source code showing how to define the MamanIbar interface which requires MamanIbaz and how to 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>. and <filename>sample/interface/maman-bar.{h|c}</filename>.
</para> </para>
</sect1> </sect1>
<sect1 id="howto-interface-properties"> <sect1 id="howto-interface-properties">
<title>Interface Properties</title> <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 Declaration of the interface properties is similar to declaring the properties of
ordinary GObject types as explained in <xref linkend="gobject-properties"/>, 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 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>. declare the properties instead of <function><link linkend="g-object-class-install-property">g_object_class_install_property</link></function>.
</para> </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 <type>maman_ibaz</type> interface example code above, we only need to add one
<footnote> <footnote>
<para> <para>
@@ -1139,13 +1133,15 @@ maman_ibaz_base_init (gpointer g_iface)
</programlisting> </programlisting>
</para> </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 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, inside the get and set methods and since interfaces do not implement properties,
there is no need to assign integer IDs to interface properties. there is no need to assign integer IDs to interface properties.
</para> </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 An implementer shall declare and define it's properties in the usual way as
explained in <xref linkend="gobject-properties"/>, except for one small explained in <xref linkend="gobject-properties"/>, except for one small
change: it shall declare the properties of the interface it implements using 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> </programlisting>
</para> </para>
</sect1> </sect1>
</chapter> </chapter>
<!-- End Howto Interfaces -->
<!-- <chapter id="howto-signals">
End Howto Interfaces
-->
<!--
start Howto Signals
-->
<chapter id="howto-signals">
<title>Howto create and use signals</title> <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. just emit events which can be received by numerous clients.
</para> </para>
<sect1 id="howto-simple-signals"> <sect1 id="howto-simple-signals">
<title>Simple use of signals</title> <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 <para>
MamanFile object, and if this object has a write method, we might wish to be notified whenever someone The most basic use of signals is to implement simple event notification: for example, if we have a
uses this method. The code below shows how the user can connect a callback to the write signal. Full code MamanFile object, and if this object has a write method, we might wish to be notified whenever someone
for this simple example is located in <filename>sample/signal/maman-file.{h|c}</filename> and uses this method. The code below shows how the user can connect a callback to the write signal. Full code
in <filename>sample/signal/test.c</filename> for this simple example is located in <filename>sample/signal/maman-file.{h|c}</filename> and
in <filename>sample/signal/test.c</filename>
<programlisting> <programlisting>
file = g_object_new (MAMAN_FILE_TYPE, NULL); 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); maman_file_write (file, buffer, 50);
</programlisting> </programlisting>
</para> </para>
<para> <para>
The <type>MamanFile</type> signal is registered in the class_init function: The <type>MamanFile</type> signal is registered in the class_init function:
<programlisting> <programlisting>
klass->write_signal_id = klass->write_signal_id =
g_signal_newv ("write", g_signal_newv ("write",
@@ -1325,7 +1311,7 @@ klass->write_signal_id =
0 /* n_params */, 0 /* n_params */,
NULL /* param_types */); NULL /* param_types */);
</programlisting> </programlisting>
and the signal is emited in <function>maman_file_write</function>: and the signal is emited in <function>maman_file_write</function>:
<programlisting> <programlisting>
void maman_file_write (MamanFile *self, guint8 *buffer, guint32 size) 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); NULL);
} }
</programlisting> </programlisting>
As shown above, you can safely set the details parameter to zero if you do not know what it can be used for. 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"/> 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.
</para> </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> <para>
<title>How to provide more flexibility to users?</title> 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 <para>
even more flexibility to this file change notification mechanism. One of the key ideas is to make the process To integrate the process of writing the data to the file into the signal emission mechanism, we can
of writing data to the file part of the signal emission process to allow users to be notified either register a default class closure for this signal which will be invoked during the signal emission, just like
before or after the data is written to the file. any other user-connected signal handler.
</para> </para>
<para>To integrate the process of writing the data to the file into the signal emission mechanism, we can <para>
register a default class closure for this signal which will be invoked during the signal emission, just like The first step to implement this idea is to change the signature of the signal: we need to pass
any other user-connected signal handler. around the buffer to write and its size. To do this, we use our own marshaller which will be generated
</para> 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> <programlisting>
VOID:POINTER,UINT VOID:POINTER,UINT
</programlisting> </programlisting>
and use the Makefile provided in <filename>sample/signal/Makefile</filename> to generate the file named 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-marshall.c</filename>. This C file is finally included in
<filename>maman-file-complex.c</filename>. <filename>maman-file-complex.c</filename>.
</para> </para>
<para>Once the marshaller is present, we register the signal and its marshaller in the class_init function <para>
of the object <type>MamanFileComplex</type> (full source for this object is included in Once the marshaller is present, we register the signal and its marshaller in the class_init function
<filename>sample/signal/maman-file-complex.{h|c}</filename>): of the object <type>MamanFileComplex</type> (full source for this object is included in
<filename>sample/signal/maman-file-complex.{h|c}</filename>):
<programlisting> <programlisting>
GClosure *default_closure; GClosure *default_closure;
GType param_types[2]; GType param_types[2];
@@ -1405,13 +1393,13 @@ klass->write_signal_id =
2 /* n_params */, 2 /* n_params */,
param_types /* param_types */); param_types /* param_types */);
</programlisting> </programlisting>
The code shown above first creates the closure which contains the code to complete the file write. This 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. closure is registered as the default class_closure of the newly created signal.
</para> </para>
<para> <para>
Of course, you need to implement completely the code for the default closure since I just provided Of course, you need to implement completely the code for the default closure since I just provided
a skeleton: a skeleton:
<programlisting> <programlisting>
static void static void
default_write_signal_handler (GObject *obj, guint8 *buffer, guint size, gpointer user_data) 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); g_print ("default signal handler: 0x%x %u\n", buffer, size);
} }
</programlisting> </programlisting>
</para> </para>
<para>Finally, the client code must invoke the <function>maman_file_complex_write</function> function which <para>
triggers the signal emission: Finally, the client code must invoke the <function>maman_file_complex_write</function> function which
triggers the signal emission:
<programlisting> <programlisting>
void maman_file_complex_write (MamanFileComplex *self, guint8 *buffer, guint size) 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); buffer, size);
} }
</programlisting> </programlisting>
</para> </para>
<para>The client code (as shown in <filename>sample/signal/test.c</filename> and below) can now connect signal handlers before <para>
and after the file write is completed: since the default signal handler which does the write itself runs during the The client code (as shown in <filename>sample/signal/test.c</filename> and below) can now connect signal handlers before
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 after the file write is completed: since the default signal handler which does the write itself runs during the
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 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>
which emits signals, I would thus urge you to create all your signals with the G_SIGNAL_RUN_LAST such that your users 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
have a maximum of flexibility as to when to get the event. Here, we combined it with G_SIGNAL_NO_RECURSE and which emits signals, I would thus urge you to create all your signals with the G_SIGNAL_RUN_LAST such that your users
G_SIGNAL_NO_HOOKS to ensure our users will not try to do really weird things with our GObject. I strongly advise you have a maximum of flexibility as to when to get the event. Here, we combined it with G_SIGNAL_NO_RECURSE and
to do the same unless you really know why (in which case you really know the inner workings of GSignal by heart and G_SIGNAL_NO_HOOKS to ensure our users will not try to do really weird things with our GObject. I strongly advise you
you are not reading this). to do the same unless you really know why (in which case you really know the inner workings of GSignal by heart and
</para> you are not reading this).
</para>
<para> <para>
<programlisting> <programlisting>
static void complex_write_event_before (GObject *file, guint8 *buffer, guint size, gpointer user_data) 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)); g_object_unref (G_OBJECT (file));
} }
</programlisting> </programlisting>
The code above generates the following output on my machine: The code above generates the following output on my machine:
<programlisting> <programlisting>
Complex Write event before: 0xbfffe280, 50 Complex Write event before: 0xbfffe280, 50
default signal handler: 0xbfffe280 50 default signal handler: 0xbfffe280 50
Complex Write event after: 0xbfffe280, 50 Complex Write event after: 0xbfffe280, 50
</programlisting> </programlisting>
</para> </para>
<sect2> <sect2>
@@ -1592,12 +1582,10 @@ klass->write_signal_id =
</sect2> </sect2>
</sect1>
</sect1>
<sect1>
<sect1>
<title>How users can abuse signals (and why some think it is good)</title> <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 <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. This will make you feel good and eleet.
</para> </para>
<para>The users can: <para>
The users can:
<itemizedlist> <itemizedlist>
<listitem><para>stop the emission of the signal at anytime</para></listitem> <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 <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> </itemizedlist>
</para> </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 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 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 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). write if he wishes to).
</para> </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 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. it further.
</para> </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 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. 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 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. handler to ensure the integrity of the parent object.
</para> </para>
<para>Overriding a class method and chaining up was demonstrated in <xref linkend="howto-gobject-methods"/> <para>
which is why I won't bother to show exactly how to do it here again.</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> </chapter>
@@ -1723,10 +1716,3 @@ g_object_do_class_init (GObjectClass *class)
</sect2> </sect2>
--> -->
<!--
<capter1 id="howto-doc">
<title>How to generate API documentation for your type?</title>
</chapter>
-->

View File

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

View File

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