mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-09-28 01:57:14 +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:
@@ -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:
|
||||||
|
@@ -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", &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>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@@ -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>
|
||||||
|
|
||||||
|
@@ -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.
|
||||||
|
@@ -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>
|
|
||||||
-->
|
|
||||||
|
@@ -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 <function_foo>
|
call 0x80482f4 <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>
|
||||||
|
@@ -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.
|
||||||
|
Reference in New Issue
Block a user