mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-06-07 05:10:08 +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:
parent
bdca945da3
commit
8ec7d6ca3f
@ -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,64 +1,63 @@
|
|||||||
<?xml version='1.0' encoding="ISO-8859-1"?>
|
<?xml version='1.0' encoding="ISO-8859-1"?>
|
||||||
|
<chapter id="chapter-gobject">
|
||||||
|
<title>The GObject base class</title>
|
||||||
|
|
||||||
<chapter id="chapter-gobject">
|
<para>
|
||||||
<title>The GObject base class</title>
|
The two previous chapters discussed the details of Glib's Dynamic Type System
|
||||||
|
and its signal control system. The GObject library also contains an implementation
|
||||||
|
for a base fundamental type named <type><link linkend="GObject">GObject</link></type>.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
<type><link linkend="GObject">GObject</link></type> is a fundamental classed instantiable type. It implements:
|
||||||
|
<itemizedlist>
|
||||||
|
<listitem><para>Memory management with reference counting</para></listitem>
|
||||||
|
<listitem><para>Construction/Destruction of instances</para></listitem>
|
||||||
|
<listitem><para>Generic per-object properties with set/get function pairs</para></listitem>
|
||||||
|
<listitem><para>Easy use of signals</para></listitem>
|
||||||
|
</itemizedlist>
|
||||||
|
All the GNOME libraries which use the GLib type system (like Gtk+ and GStreamer)
|
||||||
|
inherit from <type><link linkend="GObject">GObject</link></type> which is why it is important to understand
|
||||||
|
the details of how it works.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<sect1 id="gobject-instanciation">
|
||||||
|
<title>Object instanciation</title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
The two previous chapters discussed the details of Glib's Dynamic Type System
|
The <function><link linkend="g-object-new">g_object_new</link></function> family of functions can be used to instantiate any
|
||||||
and its signal control system. The GObject library also contains an implementation
|
GType which inherits from the GObject base type. All these functions make sure the class
|
||||||
for a base fundamental type named <type><link linkend="GObject">GObject</link></type>.
|
and instance structures have been correctly initialized by glib's type system and
|
||||||
</para>
|
then invoke at one point or another the constructor class method which is used to:
|
||||||
|
|
||||||
<para>
|
|
||||||
<type><link linkend="GObject">GObject</link></type> is a fundamental classed instantiable type. It implements:
|
|
||||||
<itemizedlist>
|
<itemizedlist>
|
||||||
<listitem><para>Memory management with reference counting</para></listitem>
|
<listitem><para>
|
||||||
<listitem><para>Construction/Destruction of instances</para></listitem>
|
Allocate and clear memory through <function><link linkend="g-type-create-instance">g_type_create_instance</link></function>,
|
||||||
<listitem><para>Generic per-object properties with set/get function pairs</para></listitem>
|
</para></listitem>
|
||||||
<listitem><para>Easy use of signals</para></listitem>
|
<listitem><para>
|
||||||
|
Initialize the object' instance with the construction properties.
|
||||||
|
</para></listitem>
|
||||||
</itemizedlist>
|
</itemizedlist>
|
||||||
All the GNOME libraries which use the GLib type system (like Gtk+ and GStreamer)
|
Although one can expect all class and instance members (except the fields
|
||||||
inherit from <type><link linkend="GObject">GObject</link></type> which is why it is important to understand
|
pointing to the parents) to be set to zero, some consider it good practice to explicitly set them.
|
||||||
the details of how it works.
|
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<sect1 id="gobject-instanciation">
|
<para>
|
||||||
<title>Object instanciation</title>
|
Objects which inherit from GObject are allowed to override this constructor class method:
|
||||||
|
they should however chain to their parent constructor method before doing so:
|
||||||
<para>
|
|
||||||
The <function><link linkend="g-object-new">g_object_new</link></function> family of functions can be used to instantiate any
|
|
||||||
GType which inherits from the GObject base type. All these functions make sure the class
|
|
||||||
and instance structures have been correctly initialized by glib's type system and
|
|
||||||
then invoke at one point or another the constructor class method which is used to:
|
|
||||||
<itemizedlist>
|
|
||||||
<listitem><para>
|
|
||||||
Allocate and clear memory through <function><link linkend="g-type-create-instance">g_type_create_instance</link></function>,
|
|
||||||
</para></listitem>
|
|
||||||
<listitem><para>
|
|
||||||
Initialize the object' instance with the construction properties.
|
|
||||||
</para></listitem>
|
|
||||||
</itemizedlist>
|
|
||||||
Although one can expect all class and instance members (except the fields
|
|
||||||
pointing to the parents) to be set to zero, some consider it good practice to explicitly set them.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
Objects which inherit from GObject are allowed to override this constructor class method:
|
|
||||||
they should however chain to their parent constructor method before doing so:
|
|
||||||
<programlisting>
|
<programlisting>
|
||||||
GObject* (*constructor) (GType type,
|
GObject* (*constructor) (GType type,
|
||||||
guint n_construct_properties,
|
guint n_construct_properties,
|
||||||
GObjectConstructParam *construct_properties);
|
GObjectConstructParam *construct_properties);
|
||||||
</programlisting>
|
</programlisting>
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
The example below shows how <type>MamanBar</type> overrides the parent's constructor:
|
The example below shows how <type>MamanBar</type> overrides the parent's constructor:
|
||||||
<programlisting>
|
<programlisting>
|
||||||
#define MAMAN_TYPE_BAR (maman_bar_get_type ())
|
#define MAMAN_TYPE_BAR (maman_bar_get_type ())
|
||||||
#define MAMAN_BAR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MAMAN_TYPE_BAR, MamanBar))
|
#define MAMAN_BAR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MAMAN_TYPE_BAR, MamanBar))
|
||||||
#define MAMAN_BAR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MAMAN_TYPE_BAR, MamanBarClass))
|
#define MAMAN_BAR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MAMAN_TYPE_BAR, MamanBarClass))
|
||||||
#define MAMAN_IS_BAR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MAMAN_TYPE_BAR))
|
#define MAMAN_IS_BAR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MAMAN_TYPE_BAR))
|
||||||
#define MAMAN_IS_BAR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MAMAN_TYPE_BAR))
|
#define MAMAN_IS_BAR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MAMAN_TYPE_BAR))
|
||||||
#define MAMAN_BAR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MAMAN_TYPE_BAR, MamanBarClass))
|
#define MAMAN_BAR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MAMAN_TYPE_BAR, MamanBarClass))
|
||||||
|
|
||||||
@ -142,153 +141,153 @@ GType maman_bar_get_type (void)
|
|||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
</programlisting>
|
</programlisting>
|
||||||
If the user instantiates an object <type>MamanBar</type> with:
|
If the user instantiates an object <type>MamanBar</type> with:
|
||||||
<programlisting>
|
<programlisting>
|
||||||
MamanBar *bar = g_object_new (MAMAN_TYPE_BAR, NULL);
|
MamanBar *bar = g_object_new (MAMAN_TYPE_BAR, NULL);
|
||||||
</programlisting>
|
</programlisting>
|
||||||
If this is the first instantiation of such an object, the <function>maman_b_class_init</function>
|
If this is the first instantiation of such an object, the <function>maman_b_class_init</function>
|
||||||
function will be invoked after any <function>maman_b_base_class_init</function> function.
|
function will be invoked after any <function>maman_b_base_class_init</function> function.
|
||||||
This will make sure the class structure of this new object is correctly initialized. Here,
|
This will make sure the class structure of this new object is correctly initialized. Here,
|
||||||
<function>maman_bar_class_init</function> is expected to override the object's class methods
|
<function>maman_bar_class_init</function> is expected to override the object's class methods
|
||||||
and setup the class' own methods. In the example above, the constructor method is the only
|
and setup the class' own methods. In the example above, the constructor method is the only
|
||||||
overridden method: it is set to <function>maman_bar_constructor</function>.
|
overridden method: it is set to <function>maman_bar_constructor</function>.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Once <function><link linkend="g-object-new">g_object_new</link></function> has obtained a reference to an initialized
|
Once <function><link linkend="g-object-new">g_object_new</link></function> has obtained a reference to an initialized
|
||||||
class structure, it invokes its constructor method to create an instance of the new
|
class structure, it invokes its constructor method to create an instance of the new
|
||||||
object. Since it has just been overridden by <function>maman_bar_class_init</function>
|
object. Since it has just been overridden by <function>maman_bar_class_init</function>
|
||||||
to <function>maman_bar_constructor</function>, the latter is called and, because it
|
to <function>maman_bar_constructor</function>, the latter is called and, because it
|
||||||
was implemented correctly, it chains up to its parent's constructor. The problem here
|
was implemented correctly, it chains up to its parent's constructor. The problem here
|
||||||
is how we can find the parent constructor. An approach (used in GTK+ source code) would be
|
is how we can find the parent constructor. An approach (used in GTK+ source code) would be
|
||||||
to save the original constructor in a static variable from <function>maman_bar_class_init</function>
|
to save the original constructor in a static variable from <function>maman_bar_class_init</function>
|
||||||
and then to re-use it from <function>maman_bar_constructor</function>. This is clearly possible
|
and then to re-use it from <function>maman_bar_constructor</function>. This is clearly possible
|
||||||
and very simple but I was told it was not nice and the prefered way is to use the
|
and very simple but I was told it was not nice and the prefered way is to use the
|
||||||
<function><link linkend="g-type-class-peek">g_type_class_peek</link></function> and <function><link linkend="g-type-class-peek-parent">g_type_class_peek_parent</link></function> functions.
|
<function><link linkend="g-type-class-peek">g_type_class_peek</link></function> and <function><link linkend="g-type-class-peek-parent">g_type_class_peek_parent</link></function> functions.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Finally, at one point or another, <function>g_object_constructor</function> is invoked
|
Finally, at one point or another, <function>g_object_constructor</function> is invoked
|
||||||
by the last constructor in the chain. This function allocates the object's instance' buffer
|
by the last constructor in the chain. This function allocates the object's instance' buffer
|
||||||
through <function><link linkend="g-type-create-instance">g_type_create_instance</link></function>
|
through <function><link linkend="g-type-create-instance">g_type_create_instance</link></function>
|
||||||
which means that the instance_init function is invoked at this point if one
|
which means that the instance_init function is invoked at this point if one
|
||||||
was registered. After instance_init returns, the object is fully initialized and should be
|
was registered. After instance_init returns, the object is fully initialized and should be
|
||||||
ready to answer any user-request. When <function><link linkend="g-type-create-instance">g_type_create_instance</link></function>
|
ready to answer any user-request. When <function><link linkend="g-type-create-instance">g_type_create_instance</link></function>
|
||||||
returns, <function>g_object_constructor</function> sets the construction properties
|
returns, <function>g_object_constructor</function> sets the construction properties
|
||||||
(ie: the properties which were given to <function><link linkend="g-object-new">g_object_new</link></function>) and returns
|
(ie: the properties which were given to <function><link linkend="g-object-new">g_object_new</link></function>) and returns
|
||||||
to the user's constructor which is then allowed to do useful instance initialization...
|
to the user's constructor which is then allowed to do useful instance initialization...
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
The process described above might seem a bit complicated (it <emphasis>is</emphasis> actually
|
The process described above might seem a bit complicated (it <emphasis>is</emphasis> actually
|
||||||
overly complicated in my opinion..) but it can be summarized easily by the table below which
|
overly complicated in my opinion..) but it can be summarized easily by the table below which
|
||||||
lists the functions invoked by <function><link linkend="g-object-new">g_object_new</link></function> and their order of
|
lists the functions invoked by <function><link linkend="g-object-new">g_object_new</link></function> and their order of
|
||||||
invocation.
|
invocation.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
The array below lists the functions invoked by <function><link linkend="g-object-new">g_object_new</link></function> and
|
The array below lists the functions invoked by <function><link linkend="g-object-new">g_object_new</link></function> and
|
||||||
their order of invocation:
|
their order of invocation:
|
||||||
|
|
||||||
<table id="gobject-construction-table">
|
<table id="gobject-construction-table">
|
||||||
<title><function><link linkend="g-object-new">g_object_new</link></function></title>
|
<title><function><link linkend="g-object-new">g_object_new</link></function></title>
|
||||||
<tgroup cols="3">
|
<tgroup cols="3">
|
||||||
<colspec colwidth="*" colnum="1" align="left"/>
|
<colspec colwidth="*" colnum="1" align="left"/>
|
||||||
<colspec colwidth="*" colnum="2" align="left"/>
|
<colspec colwidth="*" colnum="2" align="left"/>
|
||||||
<colspec colwidth="8*" colnum="3" align="left"/>
|
<colspec colwidth="8*" colnum="3" align="left"/>
|
||||||
|
|
||||||
<thead>
|
<thead>
|
||||||
<row>
|
<row>
|
||||||
<entry>Invocation time</entry>
|
<entry>Invocation time</entry>
|
||||||
<entry>Function Invoked</entry>
|
<entry>Function Invoked</entry>
|
||||||
<entry>Function's parameters</entry>
|
<entry>Function's parameters</entry>
|
||||||
<entry>Remark</entry>
|
<entry>Remark</entry>
|
||||||
</row>
|
</row>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<row>
|
<row>
|
||||||
<entry morerows="3">First call to <function><link linkend="g-object-new">g_object_new</link></function> for target type</entry>
|
<entry morerows="3">First call to <function><link linkend="g-object-new">g_object_new</link></function> for target type</entry>
|
||||||
<entry>target type's base_init function</entry>
|
<entry>target type's base_init function</entry>
|
||||||
<entry>On the inheritance tree of classes from fundamental type to target type.
|
<entry>On the inheritance tree of classes from fundamental type to target type.
|
||||||
base_init is invoked once for each class structure.</entry>
|
base_init is invoked once for each class structure.</entry>
|
||||||
<entry>
|
<entry>
|
||||||
I have no real idea on how this can be used. If you have a good real-life
|
I have no real idea on how this can be used. If you have a good real-life
|
||||||
example of how a class' base_init can be used, please, let me know.
|
example of how a class' base_init can be used, please, let me know.
|
||||||
</entry>
|
</entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<!--entry>First call to <function><link linkend="g-object-new">g_object_new</link></function> for target type</entry-->
|
<!--entry>First call to <function><link linkend="g-object-new">g_object_new</link></function> for target type</entry-->
|
||||||
<entry>target type's class_init function</entry>
|
<entry>target type's class_init function</entry>
|
||||||
<entry>On target type's class structure</entry>
|
<entry>On target type's class structure</entry>
|
||||||
<entry>
|
<entry>
|
||||||
Here, you should make sure to initialize or override class methods (that is,
|
Here, you should make sure to initialize or override class methods (that is,
|
||||||
assign to each class' method its function pointer) and create the signals and
|
assign to each class' method its function pointer) and create the signals and
|
||||||
the properties associated to your object.
|
the properties associated to your object.
|
||||||
</entry>
|
</entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<!--entry>First call to <function><link linkend="g-object-new">g_object_new</link></function> for target type</entry-->
|
<!--entry>First call to <function><link linkend="g-object-new">g_object_new</link></function> for target type</entry-->
|
||||||
<entry>interface' base_init function</entry>
|
<entry>interface' base_init function</entry>
|
||||||
<entry>On interface' vtable</entry>
|
<entry>On interface' vtable</entry>
|
||||||
<entry></entry>
|
<entry></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<!--entry>First call to <function><link linkend="g-object-new">g_object_new</link></function> for target type</entry-->
|
<!--entry>First call to <function><link linkend="g-object-new">g_object_new</link></function> for target type</entry-->
|
||||||
<entry>interface' interface_init function</entry>
|
<entry>interface' interface_init function</entry>
|
||||||
<entry>On interface' vtable</entry>
|
<entry>On interface' vtable</entry>
|
||||||
<entry></entry>
|
<entry></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry morerows="1">Each call to <function><link linkend="g-object-new">g_object_new</link></function> for target type</entry>
|
<entry morerows="1">Each call to <function><link linkend="g-object-new">g_object_new</link></function> for target type</entry>
|
||||||
<entry>target type's class constructor method: GObjectClass->constructor</entry>
|
<entry>target type's class constructor method: GObjectClass->constructor</entry>
|
||||||
<entry>On object's instance</entry>
|
<entry>On object's instance</entry>
|
||||||
<entry>
|
<entry>
|
||||||
If you need to complete the object initialization after all the construction properties
|
If you need to complete the object initialization after all the construction properties
|
||||||
are set, override the constructor method and make sure to chain up to the object's
|
are set, override the constructor method and make sure to chain up to the object's
|
||||||
parent class before doing your own initialization.
|
parent class before doing your own initialization.
|
||||||
In doubt, do not override the constructor method.
|
In doubt, do not override the constructor method.
|
||||||
</entry>
|
</entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<!--entry>Each call to <function><link linkend="g-object-new">g_object_new</link></function> for target type</entry-->
|
<!--entry>Each call to <function><link linkend="g-object-new">g_object_new</link></function> for target type</entry-->
|
||||||
<entry>type's instance_init function</entry>
|
<entry>type's instance_init function</entry>
|
||||||
<entry>On the inheritance tree of classes from fundamental type to target type.
|
<entry>On the inheritance tree of classes from fundamental type to target type.
|
||||||
the instance_init provided for each type is invoked once for each instance
|
the instance_init provided for each type is invoked once for each instance
|
||||||
structure.</entry>
|
structure.</entry>
|
||||||
<entry>
|
<entry>
|
||||||
Provide an instance_init function to initialize your object before its construction
|
Provide an instance_init function to initialize your object before its construction
|
||||||
properties are set. This is the preferred way to initialize a GObject instance.
|
properties are set. This is the preferred way to initialize a GObject instance.
|
||||||
This function is equivalent to C++ constructors.
|
This function is equivalent to C++ constructors.
|
||||||
</entry>
|
</entry>
|
||||||
</row>
|
</row>
|
||||||
</tbody>
|
</tbody>
|
||||||
</tgroup>
|
</tgroup>
|
||||||
</table>
|
</table>
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Readers should feel concerned about one little twist in the order in which functions
|
Readers should feel concerned about one little twist in the order in which functions
|
||||||
are invoked: while, technically, the class' constructor method is called
|
are invoked: while, technically, the class' constructor method is called
|
||||||
<emphasis>before</emphasis> the GType's instance_init function (since
|
<emphasis>before</emphasis> the GType's instance_init function (since
|
||||||
<function><link linkend="g-type-create-instance">g_type_create_instance</link></function> which calls instance_init is called by
|
<function><link linkend="g-type-create-instance">g_type_create_instance</link></function> which calls instance_init is called by
|
||||||
<function>g_object_constructor</function> which is the top-level class
|
<function>g_object_constructor</function> which is the top-level class
|
||||||
constructor method and to which users are expected to chain to), the user's code
|
constructor method and to which users are expected to chain to), the user's code
|
||||||
which runs in a user-provided constructor will always run <emphasis>after</emphasis>
|
which runs in a user-provided constructor will always run <emphasis>after</emphasis>
|
||||||
GType's instance_init function since the user-provided constructor
|
GType's instance_init function since the user-provided constructor
|
||||||
<emphasis>must</emphasis> (you've been warned) chain up <emphasis>before</emphasis>
|
<emphasis>must</emphasis> (you've been warned) chain up <emphasis>before</emphasis>
|
||||||
doing anything useful.
|
doing anything useful.
|
||||||
</para>
|
</para>
|
||||||
</sect1>
|
</sect1>
|
||||||
|
|
||||||
<sect1 id="gobject-memory">
|
<sect1 id="gobject-memory">
|
||||||
<title>Object memory management</title>
|
<title>Object memory management</title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
The memory-management API for GObjects is a bit complicated but the idea behind it
|
The memory-management API for GObjects is a bit complicated but the idea behind it
|
||||||
is pretty simple: the goal is to provide a flexible model based on reference counting
|
is pretty simple: the goal is to provide a flexible model based on reference counting
|
||||||
which can be integrated in applications which use or require different memory management
|
which can be integrated in applications which use or require different memory management
|
||||||
models (such as garbage collection, aso...). The methods which are used to
|
models (such as garbage collection, aso...). The methods which are used to
|
||||||
manipulate this reference count are described below.
|
manipulate this reference count are described below.
|
||||||
<programlisting>
|
<programlisting>
|
||||||
/*
|
/*
|
||||||
Refcounting
|
Refcounting
|
||||||
@ -299,14 +298,14 @@ void g_object_unref (gpointer object);
|
|||||||
/*
|
/*
|
||||||
Weak References
|
Weak References
|
||||||
*/
|
*/
|
||||||
typedef void (*GWeakNotify) (gpointer data,
|
typedef void (*GWeakNotify) (gpointer data,
|
||||||
GObject *where_the_object_was);
|
GObject *where_the_object_was);
|
||||||
void g_object_weak_ref (GObject *object,
|
void g_object_weak_ref (GObject *object,
|
||||||
GWeakNotify notify,
|
GWeakNotify notify,
|
||||||
gpointer data);
|
gpointer data);
|
||||||
void g_object_weak_unref (GObject *object,
|
void g_object_weak_unref (GObject *object,
|
||||||
GWeakNotify notify,
|
GWeakNotify notify,
|
||||||
gpointer data);
|
gpointer data);
|
||||||
void g_object_add_weak_pointer (GObject *object,
|
void g_object_add_weak_pointer (GObject *object,
|
||||||
gpointer *weak_pointer_location);
|
gpointer *weak_pointer_location);
|
||||||
void g_object_remove_weak_pointer (GObject *object,
|
void g_object_remove_weak_pointer (GObject *object,
|
||||||
@ -314,146 +313,146 @@ void g_object_remove_weak_pointer (GObject *object,
|
|||||||
/*
|
/*
|
||||||
Cycle handling
|
Cycle handling
|
||||||
*/
|
*/
|
||||||
void g_object_run_dispose (GObject *object);
|
void g_object_run_dispose (GObject *object);
|
||||||
</programlisting>
|
</programlisting>
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<sect2 id="gobject-memory-refcount">
|
<sect2 id="gobject-memory-refcount">
|
||||||
<title>Reference count</title>
|
<title>Reference count</title>
|
||||||
|
|
||||||
<para>
|
|
||||||
The functions <function><link linkend="g-object-ref">g_object_ref</link></function>/<function><link linkend="g-object-unref">g_object_unref</link></function> respectively
|
|
||||||
increase and decrease the reference count.These functions are thread-safe as of GLib 2.8.
|
|
||||||
The reference count is, unsurprisingly, initialized to one by
|
|
||||||
<function><link linkend="g-object-new">g_object_new</link></function> which means that the caller
|
|
||||||
is currenly the sole owner of the newly-created reference.
|
|
||||||
When the reference count reaches zero, that is,
|
|
||||||
when <function><link linkend="g-object-unref">g_object_unref</link></function> is called by the last client holding
|
|
||||||
a reference to the object, the <emphasis>dispose</emphasis> and the
|
|
||||||
<emphasis>finalize</emphasis> class methods are invoked.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
Finally, after <emphasis>finalize</emphasis> is invoked,
|
|
||||||
<function><link linkend="g-type-free-instance">g_type_free_instance</link></function> is called to free the object instance.
|
|
||||||
Depending on the memory allocation policy decided when the type was registered (through
|
|
||||||
one of the <function>g_type_register_*</function> functions), the object's instance
|
|
||||||
memory will be freed or returned to the object pool for this type.
|
|
||||||
Once the object has been freed, if it was the last instance of the type, the type's class
|
|
||||||
will be destroyed as described in <xref linkend="gtype-instantiable-classed"/> and
|
|
||||||
<xref linkend="gtype-non-instantiable-classed"/>.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
The table below summarizes the destruction process of a GObject:
|
|
||||||
<table id="gobject-destruction-table">
|
|
||||||
<title><function><link linkend="g-object-unref">g_object_unref</link></function></title>
|
|
||||||
<tgroup cols="3">
|
|
||||||
<colspec colwidth="*" colnum="1" align="left"/>
|
|
||||||
<colspec colwidth="*" colnum="2" align="left"/>
|
|
||||||
<colspec colwidth="8*" colnum="3" align="left"/>
|
|
||||||
|
|
||||||
<thead>
|
|
||||||
<row>
|
|
||||||
<entry>Invocation time</entry>
|
|
||||||
<entry>Function Invoked</entry>
|
|
||||||
<entry>Function's parameters</entry>
|
|
||||||
<entry>Remark</entry>
|
|
||||||
</row>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<row>
|
|
||||||
<entry morerows="1">Last call to <function><link linkend="g-object-unref">g_object_unref</link></function> for an instance
|
|
||||||
of target type
|
|
||||||
</entry>
|
|
||||||
<entry>target type's dispose class function</entry>
|
|
||||||
<entry>GObject instance</entry>
|
|
||||||
<entry>
|
|
||||||
When dispose ends, the object should not hold any reference to any other
|
|
||||||
member object. The object is also expected to be able to answer client
|
|
||||||
method invocations (with possibly an error code but no memory violation)
|
|
||||||
until finalize is executed. dispose can be executed more than once.
|
|
||||||
dispose should chain up to its parent implementation just before returning
|
|
||||||
to the caller.
|
|
||||||
</entry>
|
|
||||||
</row>
|
|
||||||
<row>
|
|
||||||
<!--entry>Last call to <function><link linkend="g-object-unref">g_object_unref</link></function> for an instance
|
|
||||||
of target type
|
|
||||||
</entry-->
|
|
||||||
<entry>target type's finalize class function</entry>
|
|
||||||
<entry>GObject instance</entry>
|
|
||||||
<entry>
|
|
||||||
Finalize is expected to complete the destruction process initiated by
|
|
||||||
dispose. It should complete the object's destruction. finalize will be
|
|
||||||
executed only once.
|
|
||||||
finalize should chain up to its parent implementation just before returning
|
|
||||||
to the caller.
|
|
||||||
The reason why the destruction process is split is two different phases is
|
|
||||||
explained in <xref linkend="gobject-memory-cycles"/>.
|
|
||||||
</entry>
|
|
||||||
</row>
|
|
||||||
<row>
|
|
||||||
<entry morerows="3">Last call to <function><link linkend="g-object-unref">g_object_unref</link></function> for the last
|
|
||||||
instance of target type
|
|
||||||
</entry>
|
|
||||||
<entry>interface' interface_finalize function</entry>
|
|
||||||
<entry>On interface' vtable</entry>
|
|
||||||
<entry>Never used in practice. Unlikely you will need it.</entry>
|
|
||||||
</row>
|
|
||||||
<row>
|
|
||||||
<!--entry>Last call to <function><link linkend="g-object-unref">g_object_unref</link></function>for the last
|
|
||||||
instance of target type
|
|
||||||
</entry-->
|
|
||||||
<entry>interface' base_finalize function</entry>
|
|
||||||
<entry>On interface' vtable</entry>
|
|
||||||
<entry>Never used in practice. Unlikely you will need it.</entry>
|
|
||||||
</row>
|
|
||||||
<row>
|
|
||||||
<!--entry>Last call to <function><link linkend="g-object-unref">g_object_unref</link></function> for the last
|
|
||||||
instance of target type
|
|
||||||
</entry-->
|
|
||||||
<entry>target type's class_finalize function</entry>
|
|
||||||
<entry>On target type's class structure</entry>
|
|
||||||
<entry>Never used in practice. Unlikely you will need it.</entry>
|
|
||||||
</row>
|
|
||||||
<row>
|
|
||||||
<!--entry>Last call to <function><link linkend="g-object-unref">g_object_unref</link></function> for the last
|
|
||||||
instance of target type
|
|
||||||
</entry-->
|
|
||||||
<entry>type's base_finalize function</entry>
|
|
||||||
<entry>On the inheritance tree of classes from fundamental type to target type.
|
|
||||||
base_init is invoked once for each class structure.</entry>
|
|
||||||
<entry>Never used in practice. Unlikely you will need it.</entry>
|
|
||||||
</row>
|
|
||||||
</tbody>
|
|
||||||
</tgroup>
|
|
||||||
</table>
|
|
||||||
</para>
|
|
||||||
|
|
||||||
</sect2>
|
|
||||||
|
|
||||||
<sect2 id="gobject-memory-weakref">
|
|
||||||
<title>Weak References</title>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
Weak References are used to monitor object finalization:
|
|
||||||
<function><link linkend="g-object-weak-ref">g_object_weak_ref</link></function> adds a monitoring callback which does
|
|
||||||
not hold a reference to the object but which is invoked when the object runs
|
|
||||||
its dispose method. As such, each weak ref can be invoked more than once upon
|
|
||||||
object finalization (since dispose can run more than once during object
|
|
||||||
finalization).
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
<function><link linkend="g-object-weak-unref">g_object_weak_unref</link></function> can be used to remove a monitoring
|
The functions <function><link linkend="g-object-ref">g_object_ref</link></function>/<function><link linkend="g-object-unref">g_object_unref</link></function> respectively
|
||||||
callback from the object.
|
increase and decrease the reference count.These functions are thread-safe as of GLib 2.8.
|
||||||
|
The reference count is, unsurprisingly, initialized to one by
|
||||||
|
<function><link linkend="g-object-new">g_object_new</link></function> which means that the caller
|
||||||
|
is currenly the sole owner of the newly-created reference.
|
||||||
|
When the reference count reaches zero, that is,
|
||||||
|
when <function><link linkend="g-object-unref">g_object_unref</link></function> is called by the last client holding
|
||||||
|
a reference to the object, the <emphasis>dispose</emphasis> and the
|
||||||
|
<emphasis>finalize</emphasis> class methods are invoked.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
Finally, after <emphasis>finalize</emphasis> is invoked,
|
||||||
|
<function><link linkend="g-type-free-instance">g_type_free_instance</link></function> is called to free the object instance.
|
||||||
|
Depending on the memory allocation policy decided when the type was registered (through
|
||||||
|
one of the <function>g_type_register_*</function> functions), the object's instance
|
||||||
|
memory will be freed or returned to the object pool for this type.
|
||||||
|
Once the object has been freed, if it was the last instance of the type, the type's class
|
||||||
|
will be destroyed as described in <xref linkend="gtype-instantiable-classed"/> and
|
||||||
|
<xref linkend="gtype-non-instantiable-classed"/>.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Weak References are also used to implement <function><link linkend="g-object-add-weak-pointer">g_object_add_weak_pointer</link></function>
|
The table below summarizes the destruction process of a GObject:
|
||||||
and <function><link linkend="g-object-remove-weak-pointer">g_object_remove_weak_pointer</link></function>. These functions add a weak reference
|
<table id="gobject-destruction-table">
|
||||||
to the object they are applied to which makes sure to nullify the pointer given by the user
|
<title><function><link linkend="g-object-unref">g_object_unref</link></function></title>
|
||||||
when object is finalized.
|
<tgroup cols="3">
|
||||||
|
<colspec colwidth="*" colnum="1" align="left"/>
|
||||||
|
<colspec colwidth="*" colnum="2" align="left"/>
|
||||||
|
<colspec colwidth="8*" colnum="3" align="left"/>
|
||||||
|
|
||||||
|
<thead>
|
||||||
|
<row>
|
||||||
|
<entry>Invocation time</entry>
|
||||||
|
<entry>Function Invoked</entry>
|
||||||
|
<entry>Function's parameters</entry>
|
||||||
|
<entry>Remark</entry>
|
||||||
|
</row>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<row>
|
||||||
|
<entry morerows="1">Last call to <function><link linkend="g-object-unref">g_object_unref</link></function> for an instance
|
||||||
|
of target type
|
||||||
|
</entry>
|
||||||
|
<entry>target type's dispose class function</entry>
|
||||||
|
<entry>GObject instance</entry>
|
||||||
|
<entry>
|
||||||
|
When dispose ends, the object should not hold any reference to any other
|
||||||
|
member object. The object is also expected to be able to answer client
|
||||||
|
method invocations (with possibly an error code but no memory violation)
|
||||||
|
until finalize is executed. dispose can be executed more than once.
|
||||||
|
dispose should chain up to its parent implementation just before returning
|
||||||
|
to the caller.
|
||||||
|
</entry>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<!--entry>Last call to <function><link linkend="g-object-unref">g_object_unref</link></function> for an instance
|
||||||
|
of target type
|
||||||
|
</entry-->
|
||||||
|
<entry>target type's finalize class function</entry>
|
||||||
|
<entry>GObject instance</entry>
|
||||||
|
<entry>
|
||||||
|
Finalize is expected to complete the destruction process initiated by
|
||||||
|
dispose. It should complete the object's destruction. finalize will be
|
||||||
|
executed only once.
|
||||||
|
finalize should chain up to its parent implementation just before returning
|
||||||
|
to the caller.
|
||||||
|
The reason why the destruction process is split is two different phases is
|
||||||
|
explained in <xref linkend="gobject-memory-cycles"/>.
|
||||||
|
</entry>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<entry morerows="3">Last call to <function><link linkend="g-object-unref">g_object_unref</link></function> for the last
|
||||||
|
instance of target type
|
||||||
|
</entry>
|
||||||
|
<entry>interface' interface_finalize function</entry>
|
||||||
|
<entry>On interface' vtable</entry>
|
||||||
|
<entry>Never used in practice. Unlikely you will need it.</entry>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<!--entry>Last call to <function><link linkend="g-object-unref">g_object_unref</link></function>for the last
|
||||||
|
instance of target type
|
||||||
|
</entry-->
|
||||||
|
<entry>interface' base_finalize function</entry>
|
||||||
|
<entry>On interface' vtable</entry>
|
||||||
|
<entry>Never used in practice. Unlikely you will need it.</entry>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<!--entry>Last call to <function><link linkend="g-object-unref">g_object_unref</link></function> for the last
|
||||||
|
instance of target type
|
||||||
|
</entry-->
|
||||||
|
<entry>target type's class_finalize function</entry>
|
||||||
|
<entry>On target type's class structure</entry>
|
||||||
|
<entry>Never used in practice. Unlikely you will need it.</entry>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<!--entry>Last call to <function><link linkend="g-object-unref">g_object_unref</link></function> for the last
|
||||||
|
instance of target type
|
||||||
|
</entry-->
|
||||||
|
<entry>type's base_finalize function</entry>
|
||||||
|
<entry>On the inheritance tree of classes from fundamental type to target type.
|
||||||
|
base_init is invoked once for each class structure.</entry>
|
||||||
|
<entry>Never used in practice. Unlikely you will need it.</entry>
|
||||||
|
</row>
|
||||||
|
</tbody>
|
||||||
|
</tgroup>
|
||||||
|
</table>
|
||||||
|
</para>
|
||||||
|
|
||||||
|
</sect2>
|
||||||
|
|
||||||
|
<sect2 id="gobject-memory-weakref">
|
||||||
|
<title>Weak References</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Weak References are used to monitor object finalization:
|
||||||
|
<function><link linkend="g-object-weak-ref">g_object_weak_ref</link></function> adds a monitoring callback which does
|
||||||
|
not hold a reference to the object but which is invoked when the object runs
|
||||||
|
its dispose method. As such, each weak ref can be invoked more than once upon
|
||||||
|
object finalization (since dispose can run more than once during object
|
||||||
|
finalization).
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
<function><link linkend="g-object-weak-unref">g_object_weak_unref</link></function> can be used to remove a monitoring
|
||||||
|
callback from the object.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Weak References are also used to implement <function><link linkend="g-object-add-weak-pointer">g_object_add_weak_pointer</link></function>
|
||||||
|
and <function><link linkend="g-object-remove-weak-pointer">g_object_remove_weak_pointer</link></function>. These functions add a weak reference
|
||||||
|
to the object they are applied to which makes sure to nullify the pointer given by the user
|
||||||
|
when object is finalized.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
</sect2>
|
</sect2>
|
||||||
@ -462,53 +461,53 @@ void g_object_run_dispose (GObject *object);
|
|||||||
<title>Reference counts and cycles</title>
|
<title>Reference counts and cycles</title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Note: the following section was inspired by James Henstridge. I guess this means that
|
Note: the following section was inspired by James Henstridge. I guess this means that
|
||||||
all praise and all curses will be directly forwarded to him.
|
all praise and all curses will be directly forwarded to him.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
GObject's memory management model was designed to be easily integrated in existing code
|
GObject's memory management model was designed to be easily integrated in existing code
|
||||||
using garbage collection. This is why the destruction process is split in two phases:
|
using garbage collection. This is why the destruction process is split in two phases:
|
||||||
the first phase, executed in the dispose handler is supposed to release all references
|
the first phase, executed in the dispose handler is supposed to release all references
|
||||||
to other member objects. The second phase, executed by the finalize handler is supposed
|
to other member objects. The second phase, executed by the finalize handler is supposed
|
||||||
to complete the object's destruction process. Object methods should be able to run
|
to complete the object's destruction process. Object methods should be able to run
|
||||||
without program error (that is, without segfault :) in-between the two phases.
|
without program error (that is, without segfault :) in-between the two phases.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
This two-step destruction process is very useful to break reference counting cycles.
|
This two-step destruction process is very useful to break reference counting cycles.
|
||||||
While the detection of the cycles is up to the external code, once the cycles have been
|
While the detection of the cycles is up to the external code, once the cycles have been
|
||||||
detected, the external code can invoke <function><link linkend="g-object-dispose">g_object_dispose</link></function> which
|
detected, the external code can invoke <function><link linkend="g-object-dispose">g_object_dispose</link></function> which
|
||||||
will indeed break any existing cycles since it will run the dispose handler associated
|
will indeed break any existing cycles since it will run the dispose handler associated
|
||||||
to the object and thus release all references to other objects.
|
to the object and thus release all references to other objects.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Attentive readers might now have understood one of the rules about the dispose handler
|
Attentive readers might now have understood one of the rules about the dispose handler
|
||||||
we stated a bit sooner: the dispose handler can be invoked multiple times. Let's say we
|
we stated a bit sooner: the dispose handler can be invoked multiple times. Let's say we
|
||||||
have a reference count cycle: object A references B which itself references object A.
|
have a reference count cycle: object A references B which itself references object A.
|
||||||
Let's say we have detected the cycle and we want to destroy the two objects. One way to
|
Let's say we have detected the cycle and we want to destroy the two objects. One way to
|
||||||
do this would be to invoke <function><link linkend="g-object-dispose">g_object_dispose</link></function> on one of the
|
do this would be to invoke <function><link linkend="g-object-dispose">g_object_dispose</link></function> on one of the
|
||||||
objects.
|
objects.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
If object A releases all its references to all objects, this means it releases its
|
If object A releases all its references to all objects, this means it releases its
|
||||||
reference to object B. If object B was not owned by anyone else, this is its last
|
reference to object B. If object B was not owned by anyone else, this is its last
|
||||||
reference count which means this last unref runs B's dispose handler which, in turn,
|
reference count which means this last unref runs B's dispose handler which, in turn,
|
||||||
releases B's reference on object A. If this is A's last reference count, this last
|
releases B's reference on object A. If this is A's last reference count, this last
|
||||||
unref runs A's dispose handler which is running for the second time before
|
unref runs A's dispose handler which is running for the second time before
|
||||||
A's finalize handler is invoked !
|
A's finalize handler is invoked !
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
The above example, which might seem a bit contrived can really happen if your
|
The above example, which might seem a bit contrived can really happen if your
|
||||||
GObject's are being handled by language bindings. I would thus suggest the rules stated above
|
GObject's are being handled by language bindings. I would thus suggest the rules stated above
|
||||||
for object destruction are closely followed. Otherwise, <emphasis>Bad Bad Things</emphasis>
|
for object destruction are closely followed. Otherwise, <emphasis>Bad Bad Things</emphasis>
|
||||||
will happen.
|
will happen.
|
||||||
</para>
|
</para>
|
||||||
</sect2>
|
</sect2>
|
||||||
</sect1>
|
</sect1>
|
||||||
|
|
||||||
<sect1 id="gobject-properties">
|
<sect1 id="gobject-properties">
|
||||||
<title>Object properties</title>
|
<title>Object properties</title>
|
||||||
@ -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,
|
||||||
@ -681,13 +679,13 @@ g_object_set_property (G_OBJECT (bar), "papa-number", &val);
|
|||||||
<function>foo_set_property</function> after having retrieved from the
|
<function>foo_set_property</function> after having retrieved from the
|
||||||
<type><link linkend="GParamSpec">GParamSpec</link></type> the <emphasis>param_id</emphasis>
|
<type><link linkend="GParamSpec">GParamSpec</link></type> the <emphasis>param_id</emphasis>
|
||||||
<footnote>
|
<footnote>
|
||||||
<para>
|
<para>
|
||||||
It should be noted that the param_id used here need only to uniquely identify each
|
It should be noted that the param_id used here need only to uniquely identify each
|
||||||
<type><link linkend="GParamSpec">GParamSpec</link></type> within the <type><link linkend="FooClass">FooClass</link></type> such that the switch
|
<type><link linkend="GParamSpec">GParamSpec</link></type> within the <type><link linkend="FooClass">FooClass</link></type> such that the switch
|
||||||
used in the set and get methods actually works. Of course, this locally-unique
|
used in the set and get methods actually works. Of course, this locally-unique
|
||||||
integer is purely an optimization: it would have been possible to use a set of
|
integer is purely an optimization: it would have been possible to use a set of
|
||||||
<emphasis>if (strcmp (a, b) == 0) {} else if (strcmp (a, b) == 0) {}</emphasis> statements.
|
<emphasis>if (strcmp (a, b) == 0) {} else if (strcmp (a, b) == 0) {}</emphasis> statements.
|
||||||
</para>
|
</para>
|
||||||
</footnote>
|
</footnote>
|
||||||
which had been stored by
|
which had been stored by
|
||||||
<function><link linkend="g-object-class-install-property">g_object_class_install_property</link></function>.
|
<function><link linkend="g-object-class-install-property">g_object_class_install_property</link></function>.
|
||||||
@ -719,13 +717,12 @@ g_object_set_property (G_OBJECT (bar), "papa-number", &val);
|
|||||||
</para>
|
</para>
|
||||||
|
|
||||||
<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
|
multiple properties at once. The client code shown above can then be re-written as:
|
||||||
multiple properties at once. The client code shown above can then be re-written as:
|
|
||||||
<programlisting>
|
<programlisting>
|
||||||
MamanBar *foo;
|
MamanBar *foo;
|
||||||
foo = /* */;
|
foo = /* */;
|
||||||
@ -734,41 +731,40 @@ g_object_set (G_OBJECT (foo),
|
|||||||
"maman-name", "test",
|
"maman-name", "test",
|
||||||
NULL);
|
NULL);
|
||||||
</programlisting>
|
</programlisting>
|
||||||
This saves us from managing the GValues that we were needing to handle when using
|
This saves us from managing the GValues that we were needing to handle when using
|
||||||
<function><link linkend="g-object-set-property">g_object_set_property</link></function>.
|
<function><link linkend="g-object-set-property">g_object_set_property</link></function>.
|
||||||
The code above will trigger one notify signal emission for each property modified.
|
The code above will trigger one notify signal emission for each property modified.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Of course, the _get versions are also available: <function><link linkend="g-object-get">g_object_get</link></function>
|
Of course, the _get versions are also available: <function><link linkend="g-object-get">g_object_get</link></function>
|
||||||
and <function><link linkend="g-object-get-valist">g_object_get_valist</link></function> (vararg version) can be used to get numerous
|
and <function><link linkend="g-object-get-valist">g_object_get_valist</link></function> (vararg version) can be used to get numerous
|
||||||
properties at once.
|
properties at once.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
These high level functions have one drawback - they don't provide a return result.
|
These high level functions have one drawback - they don't provide a return result.
|
||||||
One should pay attention to the argument types and ranges when using them.
|
One should pay attention to the argument types and ranges when using them.
|
||||||
A know source of errors is to e.g. pass a gfloat instead of a gdouble and thus
|
A know source of errors is to e.g. pass a gfloat instead of a gdouble and thus
|
||||||
shifting all subsequent parameters by four bytes. Also forgetting the terminating
|
shifting all subsequent parameters by four bytes. Also forgetting the terminating
|
||||||
NULL will lead to unexpected behaviour.
|
NULL will lead to unexpected behaviour.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Really attentive readers now understand how <function><link linkend="g-object-new">g_object_new</link></function>,
|
Really attentive readers now understand how <function><link linkend="g-object-new">g_object_new</link></function>,
|
||||||
<function><link linkend="g-object-newv">g_object_newv</link></function> and <function><link linkend="g-object-new-valist">g_object_new_valist</link></function>
|
<function><link linkend="g-object-newv">g_object_newv</link></function> and <function><link linkend="g-object-new-valist">g_object_new_valist</link></function>
|
||||||
work: they parse the user-provided variable number of parameters and invoke
|
work: they parse the user-provided variable number of parameters and invoke
|
||||||
<function><link linkend="g-object-set">g_object_set</link></function> on the parameters only after the object has been successfully constructed.
|
<function><link linkend="g-object-set">g_object_set</link></function> on the parameters only after the object has been successfully constructed.
|
||||||
Of course, the "notify" signal will be emitted for each property set.
|
Of course, the "notify" signal will be emitted for each property set.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|
||||||
<!-- @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,83 +1,83 @@
|
|||||||
<?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">
|
||||||
<title>Closures</title>
|
<title>Closures</title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Closures are central to the concept of asynchronous signal delivery
|
Closures are central to the concept of asynchronous signal delivery
|
||||||
which is widely used throughout GTK+ and GNOME applications. A Closure is an
|
which is widely used throughout GTK+ and GNOME applications. A Closure is an
|
||||||
abstraction, a generic representation of a callback. It is a small structure
|
abstraction, a generic representation of a callback. It is a small structure
|
||||||
which contains three objects:
|
which contains three objects:
|
||||||
<itemizedlist>
|
<itemizedlist>
|
||||||
<listitem><para>a function pointer (the callback itself) whose prototype looks like:
|
<listitem><para>a function pointer (the callback itself) whose prototype looks like:
|
||||||
<programlisting>
|
<programlisting>
|
||||||
return_type function_callback (... , gpointer user_data);
|
return_type function_callback (... , gpointer user_data);
|
||||||
</programlisting>
|
</programlisting>
|
||||||
|
</para></listitem>
|
||||||
|
<listitem><para>
|
||||||
|
the user_data pointer which is passed to the callback upon invocation of the closure
|
||||||
</para></listitem>
|
</para></listitem>
|
||||||
<listitem><para>
|
<listitem><para>
|
||||||
the user_data pointer which is passed to the callback upon invocation of the closure
|
a function pointer which represents the destructor of the closure: whenever the
|
||||||
</para></listitem>
|
closure's refcount reaches zero, this function will be called before the closure
|
||||||
<listitem><para>
|
structure is freed.
|
||||||
a function pointer which represents the destructor of the closure: whenever the
|
</para></listitem>
|
||||||
closure's refcount reaches zero, this function will be called before the closure
|
</itemizedlist>
|
||||||
structure is freed.
|
</para>
|
||||||
</para></listitem>
|
|
||||||
</itemizedlist>
|
<para>
|
||||||
</para>
|
The <type><link linkend="GClosure">GClosure</link></type> structure represents the common functionality of all
|
||||||
|
closure implementations: there exists a different Closure implementation for
|
||||||
|
each separate runtime which wants to use the GObject type system.
|
||||||
|
<footnote><para>
|
||||||
|
In Practice, Closures sit at the boundary of language runtimes: if you are
|
||||||
|
writing python code and one of your Python callback receives a signal from
|
||||||
|
one of GTK+ widgets, the C code in GTK+ needs to execute your Python
|
||||||
|
code. The Closure invoked by the GTK+ object invokes the Python callback:
|
||||||
|
it behaves as a normal C object for GTK+ and as a normal Python object for
|
||||||
|
python code.
|
||||||
|
</para></footnote>
|
||||||
|
The GObject library provides a simple <type><link linkend="GCClosure">GCClosure</link></type> type which
|
||||||
|
is a specific implementation of closures to be used with C/C++ callbacks.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
A <type><link linkend="GClosure">GClosure</link></type> provides simple services:
|
||||||
|
<itemizedlist>
|
||||||
|
<listitem><para>
|
||||||
|
Invocation (<function><link linkend="g-closure-invoke">g_closure_invoke</link></function>): this is what closures
|
||||||
|
were created for: they hide the details of callback invocation from the
|
||||||
|
callback invocator.</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem><para>
|
||||||
|
Notification: the closure notifies listeners of certain events such as
|
||||||
|
closure invocation, closure invalidation and closure finalization. Listeners
|
||||||
|
can be registered with <function><link linkend="g-closure-add-finalize-notifier">g_closure_add_finalize_notifier</link></function>
|
||||||
|
(finalization notification), <function><link linkend="g-closure-add-invalidate-notifier">g_closure_add_invalidate_notifier</link></function>
|
||||||
|
(invalidation notification) and
|
||||||
|
<function><link linkend="g-closure-add-marshal-guards">g_closure_add_marshal_guards</link></function> (invocation notification).
|
||||||
|
There exist symmetric de-registration functions for finalization and invalidation
|
||||||
|
events (<function><link linkend="g-closure-remove-finalize-notifier">g_closure_remove_finalize_notifier</link></function> and
|
||||||
|
<function><link linkend="g-closure-remove-invalidate-notifier">g_closure_remove_invalidate_notifier</link></function>) but not for the invocation
|
||||||
|
process.
|
||||||
|
<footnote><para>
|
||||||
|
Closures are refcounted and notify listeners of their destruction in a two-stage
|
||||||
|
process: the invalidation notifiers are invoked before the finalization notifiers.
|
||||||
|
</para></footnote></para>
|
||||||
|
</listitem>
|
||||||
|
</itemizedlist>
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<sect2>
|
||||||
|
<title>C Closures</title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
The <type><link linkend="GClosure">GClosure</link></type> structure represents the common functionality of all
|
If you are using C or C++
|
||||||
closure implementations: there exists a different Closure implementation for
|
to connect a callback to a given event, you will either use the simple <type><link linkend="GCClosure">GCClosure</link></type>s
|
||||||
each separate runtime which wants to use the GObject type system.
|
which have a pretty minimal API or the even simpler <function><link linkend="g-signal-connect">g_signal_connect</link></function>
|
||||||
<footnote><para>
|
functions (which will be presented a bit later :).
|
||||||
In Practice, Closures sit at the boundary of language runtimes: if you are
|
<programlisting>
|
||||||
writing python code and one of your Python callback receives a signal from
|
|
||||||
one of GTK+ widgets, the C code in GTK+ needs to execute your Python
|
|
||||||
code. The Closure invoked by the GTK+ object invokes the Python callback:
|
|
||||||
it behaves as a normal C object for GTK+ and as a normal Python object for
|
|
||||||
python code.
|
|
||||||
</para></footnote>
|
|
||||||
The GObject library provides a simple <type><link linkend="GCClosure">GCClosure</link></type> type which
|
|
||||||
is a specific implementation of closures to be used with C/C++ callbacks.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
A <type><link linkend="GClosure">GClosure</link></type> provides simple services:
|
|
||||||
<itemizedlist>
|
|
||||||
<listitem><para>
|
|
||||||
Invocation (<function><link linkend="g-closure-invoke">g_closure_invoke</link></function>): this is what closures
|
|
||||||
were created for: they hide the details of callback invocation from the
|
|
||||||
callback invocator.
|
|
||||||
</para></listitem>
|
|
||||||
<listitem><para>
|
|
||||||
Notification: the closure notifies listeners of certain events such as
|
|
||||||
closure invocation, closure invalidation and closure finalization. Listeners
|
|
||||||
can be registered with <function><link linkend="g-closure-add-finalize-notifier">g_closure_add_finalize_notifier</link></function>
|
|
||||||
(finalization notification), <function><link linkend="g-closure-add-invalidate-notifier">g_closure_add_invalidate_notifier</link></function>
|
|
||||||
(invalidation notification) and
|
|
||||||
<function><link linkend="g-closure-add-marshal-guards">g_closure_add_marshal_guards</link></function> (invocation notification).
|
|
||||||
There exist symmetric de-registration functions for finalization and invalidation
|
|
||||||
events (<function><link linkend="g-closure-remove-finalize-notifier">g_closure_remove_finalize_notifier</link></function> and
|
|
||||||
<function><link linkend="g-closure-remove-invalidate-notifier">g_closure_remove_invalidate_notifier</link></function>) but not for the invocation
|
|
||||||
process.
|
|
||||||
<footnote><para>
|
|
||||||
Closures are refcounted and notify listeners of their destruction in a two-stage
|
|
||||||
process: the invalidation notifiers are invoked before the finalization notifiers.
|
|
||||||
</para></footnote>
|
|
||||||
</para></listitem>
|
|
||||||
</itemizedlist>
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<sect2>
|
|
||||||
<title>C Closures</title>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
If you are using C or C++
|
|
||||||
to connect a callback to a given event, you will either use the simple <type><link linkend="GCClosure">GCClosure</link></type>s
|
|
||||||
which have a pretty minimal API or the even simpler <function><link linkend="g-signal-connect">g_signal_connect</link></function>
|
|
||||||
functions (which will be presented a bit later :).
|
|
||||||
<programlisting>
|
|
||||||
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,46 +86,46 @@ 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>
|
||||||
<function><link linkend="g-cclosure-new">g_cclosure_new</link></function> will create a new closure which can invoke the
|
<function><link linkend="g-cclosure-new">g_cclosure_new</link></function> will create a new closure which can invoke the
|
||||||
user-provided callback_func with the user-provided user_data as last parameter. When the closure
|
user-provided callback_func with the user-provided user_data as last parameter. When the closure
|
||||||
is finalized (second stage of the destruction process), it will invoke the destroy_data function
|
is finalized (second stage of the destruction process), it will invoke the destroy_data function
|
||||||
if the user has supplied one.
|
if the user has supplied one.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
<function><link linkend="g-cclosure-new-swap">g_cclosure_new_swap</link></function> will create a new closure which can invoke the
|
<function><link linkend="g-cclosure-new-swap">g_cclosure_new_swap</link></function> will create a new closure which can invoke the
|
||||||
user-provided callback_func with the user-provided user_data as first parameter (instead of being the
|
user-provided callback_func with the user-provided user_data as first parameter (instead of being the
|
||||||
last parameter as with <function><link linkend="g-cclosure-new">g_cclosure_new</link></function>). When the closure
|
last parameter as with <function><link linkend="g-cclosure-new">g_cclosure_new</link></function>). When the closure
|
||||||
is finalized (second stage of the destruction process), it will invoke the destroy_data
|
is finalized (second stage of the destruction process), it will invoke the destroy_data
|
||||||
function if the user has supplied one.
|
function if the user has supplied one.
|
||||||
</para>
|
</para>
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|
||||||
<sect2>
|
<sect2>
|
||||||
<title>non-C closures (for the fearless).</title>
|
<title>non-C closures (for the fearless).</title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
As was explained above, Closures hide the details of callback invocation. In C,
|
As was explained above, Closures hide the details of callback invocation. In C,
|
||||||
callback invocation is just like function invocation: it is a matter of creating
|
callback invocation is just like function invocation: it is a matter of creating
|
||||||
the correct stack frame for the called function and executing a <emphasis>call</emphasis>
|
the correct stack frame for the called function and executing a <emphasis>call</emphasis>
|
||||||
assembly instruction.
|
assembly instruction.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
C closure marshallers transform the array of GValues which represent
|
C closure marshallers transform the array of GValues which represent
|
||||||
the parameters to the target function into a C-style function parameter list, invoke
|
the parameters to the target function into a C-style function parameter list, invoke
|
||||||
the user-supplied C function with this new parameter list, get the return value of the
|
the user-supplied C function with this new parameter list, get the return value of the
|
||||||
function, transform it into a GValue and return this GValue to the marshaller caller.
|
function, transform it into a GValue and return this GValue to the marshaller caller.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<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,57 +151,57 @@ 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>
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
Of course, there exist other kinds of marshallers. For example, James Henstridge
|
|
||||||
wrote a generic Python marshaller which is used by all python Closures (a python closure
|
|
||||||
is used to have python-based callback be invoked by the closure invocation process).
|
|
||||||
This python marshaller transforms the input GValue list representing the function
|
|
||||||
parameters into a Python tuple which is the equivalent structure in python (you can
|
|
||||||
look in <function>pyg_closure_marshal</function> in <filename>pygtype.c</filename>
|
|
||||||
in the <emphasis>pygobject</emphasis> module in GNOME cvs server).
|
|
||||||
</para>
|
|
||||||
|
|
||||||
</sect2>
|
|
||||||
</sect1>
|
|
||||||
|
|
||||||
<sect1 id="signal">
|
|
||||||
<title>Signals</title>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
GObject's signals have nothing to do with standard UNIX signals: they connect
|
|
||||||
arbitrary application-specific events with any number of listeners.
|
|
||||||
For example, in GTK+, every user event (keystroke or mouse move) is received
|
|
||||||
from the X server and generates a GTK+ event under the form of a signal emission
|
|
||||||
on a given object instance.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
Each signal is registered in the type system together with the type on which
|
|
||||||
it can be emitted: users of the type are said to <emphasis>connect</emphasis>
|
|
||||||
to the signal on a given type instance when they register a closure to be
|
|
||||||
invoked upon the signal emission. Users can also emit the signal by themselves
|
|
||||||
or stop the emission of the signal from within one of the closures connected
|
|
||||||
to the signal.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
When a signal is emitted on a given type instance, all the closures
|
|
||||||
connected to this signal on this type instance will be invoked. All the closures
|
|
||||||
connected to such a signal represent callbacks whose signature looks like:
|
|
||||||
<programlisting>
|
|
||||||
return_type function_callback (gpointer instance, ... , gpointer user_data);
|
|
||||||
</programlisting>
|
</programlisting>
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<sect2 id="signal-registration">
|
<para>
|
||||||
<title>Signal registration</title>
|
Of course, there exist other kinds of marshallers. For example, James Henstridge
|
||||||
|
wrote a generic Python marshaller which is used by all python Closures (a python closure
|
||||||
|
is used to have python-based callback be invoked by the closure invocation process).
|
||||||
|
This python marshaller transforms the input GValue list representing the function
|
||||||
|
parameters into a Python tuple which is the equivalent structure in python (you can
|
||||||
|
look in <function>pyg_closure_marshal</function> in <filename>pygtype.c</filename>
|
||||||
|
in the <emphasis>pygobject</emphasis> module in GNOME cvs server).
|
||||||
|
</para>
|
||||||
|
|
||||||
<para>
|
</sect2>
|
||||||
To register a new signal on an existing type, we can use any of <function><link linkend="g-signal-newv">g_signal_newv</link></function>,
|
</sect1>
|
||||||
<function><link linkend="g-signal-new-valist">g_signal_new_valist</link></function> or <function><link linkend="g-signal-new">g_signal_new</link></function> functions:
|
|
||||||
|
<sect1 id="signal">
|
||||||
|
<title>Signals</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
GObject's signals have nothing to do with standard UNIX signals: they connect
|
||||||
|
arbitrary application-specific events with any number of listeners.
|
||||||
|
For example, in GTK+, every user event (keystroke or mouse move) is received
|
||||||
|
from the X server and generates a GTK+ event under the form of a signal emission
|
||||||
|
on a given object instance.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Each signal is registered in the type system together with the type on which
|
||||||
|
it can be emitted: users of the type are said to <emphasis>connect</emphasis>
|
||||||
|
to the signal on a given type instance when they register a closure to be
|
||||||
|
invoked upon the signal emission. Users can also emit the signal by themselves
|
||||||
|
or stop the emission of the signal from within one of the closures connected
|
||||||
|
to the signal.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
When a signal is emitted on a given type instance, all the closures
|
||||||
|
connected to this signal on this type instance will be invoked. All the closures
|
||||||
|
connected to such a signal represent callbacks whose signature looks like:
|
||||||
|
<programlisting>
|
||||||
|
return_type function_callback (gpointer instance, ... , gpointer user_data);
|
||||||
|
</programlisting>
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<sect2 id="signal-registration">
|
||||||
|
<title>Signal registration</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
To register a new signal on an existing type, we can use any of <function><link linkend="g-signal-newv">g_signal_newv</link></function>,
|
||||||
|
<function><link linkend="g-signal-new-valist">g_signal_new_valist</link></function> or <function><link linkend="g-signal-new">g_signal_new</link></function> functions:
|
||||||
<programlisting>
|
<programlisting>
|
||||||
guint g_signal_newv (const gchar *signal_name,
|
guint g_signal_newv (const gchar *signal_name,
|
||||||
GType itype,
|
GType itype,
|
||||||
@ -214,307 +214,307 @@ guint g_signal_newv (const gchar *signal_name,
|
|||||||
guint n_params,
|
guint n_params,
|
||||||
GType *param_types);
|
GType *param_types);
|
||||||
</programlisting>
|
</programlisting>
|
||||||
The number of parameters to these functions is a bit intimidating but they are relatively
|
The number of parameters to these functions is a bit intimidating but they are relatively
|
||||||
simple:
|
simple:
|
||||||
<itemizedlist>
|
<itemizedlist>
|
||||||
<listitem><para>
|
<listitem><para>
|
||||||
signal_name: is a string which can be used to uniquely identify a given signal.
|
signal_name: is a string which can be used to uniquely identify a given signal.
|
||||||
</para></listitem>
|
</para></listitem>
|
||||||
<listitem><para>
|
<listitem><para>
|
||||||
itype: is the instance type on which this signal can be emitted.
|
itype: is the instance type on which this signal can be emitted.
|
||||||
</para></listitem>
|
</para></listitem>
|
||||||
<listitem><para>
|
<listitem><para>
|
||||||
signal_flags: partly defines the order in which closures which were connected to the
|
signal_flags: partly defines the order in which closures which were connected to the
|
||||||
signal are invoked.
|
signal are invoked.
|
||||||
</para></listitem>
|
</para></listitem>
|
||||||
<listitem><para>
|
<listitem><para>
|
||||||
class_closure: this is the default closure for the signal: if it is not NULL upon
|
class_closure: this is the default closure for the signal: if it is not NULL upon
|
||||||
the signal emission, it will be invoked upon this emission of the signal. The
|
the signal emission, it will be invoked upon this emission of the signal. The
|
||||||
moment where this closure is invoked compared to other closures connected to that
|
moment where this closure is invoked compared to other closures connected to that
|
||||||
signal depends partly on the signal_flags.
|
signal depends partly on the signal_flags.
|
||||||
</para></listitem>
|
</para></listitem>
|
||||||
<listitem><para>
|
<listitem><para>
|
||||||
accumulator: this is a function pointer which is invoked after each closure
|
accumulator: this is a function pointer which is invoked after each closure
|
||||||
has been invoked. If it returns FALSE, signal emission is stopped. If it returns
|
has been invoked. If it returns FALSE, signal emission is stopped. If it returns
|
||||||
TRUE, signal emission proceeds normally. It is also used to compute the return
|
TRUE, signal emission proceeds normally. It is also used to compute the return
|
||||||
value of the signal based on the return value of all the invoked closures.
|
value of the signal based on the return value of all the invoked closures.
|
||||||
</para></listitem>
|
</para></listitem>
|
||||||
<listitem><para>
|
<listitem><para>
|
||||||
accumulator_data: this pointer will be passed down to each invocation of the
|
accumulator_data: this pointer will be passed down to each invocation of the
|
||||||
accumulator during emission.
|
accumulator during emission.
|
||||||
</para></listitem>
|
</para></listitem>
|
||||||
<listitem><para>
|
<listitem><para>
|
||||||
c_marshaller: this is the default C marshaller for any closure which is connected to
|
c_marshaller: this is the default C marshaller for any closure which is connected to
|
||||||
this signal.
|
this signal.
|
||||||
</para></listitem>
|
</para></listitem>
|
||||||
<listitem><para>
|
<listitem><para>
|
||||||
return_type: this is the type of the return value of the signal.
|
return_type: this is the type of the return value of the signal.
|
||||||
</para></listitem>
|
</para></listitem>
|
||||||
<listitem><para>
|
<listitem><para>
|
||||||
n_params: this is the number of parameters this signal takes.
|
n_params: this is the number of parameters this signal takes.
|
||||||
</para></listitem>
|
</para></listitem>
|
||||||
<listitem><para>
|
<listitem><para>
|
||||||
param_types: this is an array of GTypes which indicate the type of each parameter
|
param_types: this is an array of GTypes which indicate the type of each parameter
|
||||||
of the signal. The length of this array is indicated by n_params.
|
of the signal. The length of this array is indicated by n_params.
|
||||||
</para></listitem>
|
</para></listitem>
|
||||||
</itemizedlist>
|
</itemizedlist>
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
As you can see from the above definition, a signal is basically a description
|
As you can see from the above definition, a signal is basically a description
|
||||||
of the closures which can be connected to this signal and a description of the
|
of the closures which can be connected to this signal and a description of the
|
||||||
order in which the closures connected to this signal will be invoked.
|
order in which the closures connected to this signal will be invoked.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|
||||||
<sect2 id="signal-connection">
|
<sect2 id="signal-connection">
|
||||||
<title>Signal connection</title>
|
<title>Signal connection</title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
If you want to connect to a signal with a closure, you have three possibilities:
|
If you want to connect to a signal with a closure, you have three possibilities:
|
||||||
<itemizedlist>
|
<itemizedlist>
|
||||||
<listitem><para>
|
<listitem><para>
|
||||||
You can register a class closure at signal registration: this is a
|
You can register a class closure at signal registration: this is a
|
||||||
system-wide operation. i.e.: the class_closure will be invoked during each emission
|
system-wide operation. i.e.: the class_closure will be invoked during each emission
|
||||||
of a given signal on all the instances of the type which supports that signal.
|
of a given signal on all the instances of the type which supports that signal.
|
||||||
</para></listitem>
|
</para></listitem>
|
||||||
<listitem><para>
|
<listitem><para>
|
||||||
You can use <function><link linkend="g-signal-override-class-closure">g_signal_override_class_closure</link></function> which
|
You can use <function><link linkend="g-signal-override-class-closure">g_signal_override_class_closure</link></function> which
|
||||||
overrides the class_closure of a given type. It is possible to call this function
|
overrides the class_closure of a given type. It is possible to call this function
|
||||||
only on a derived type of the type on which the signal was registered.
|
only on a derived type of the type on which the signal was registered.
|
||||||
This function is of use only to language bindings.
|
This function is of use only to language bindings.
|
||||||
</para></listitem>
|
</para></listitem>
|
||||||
<listitem><para>
|
<listitem><para>
|
||||||
You can register a closure with the <function><link linkend="g-signal-connect">g_signal_connect</link></function>
|
You can register a closure with the <function><link linkend="g-signal-connect">g_signal_connect</link></function>
|
||||||
family of functions. This is an instance-specific operation: the closure
|
family of functions. This is an instance-specific operation: the closure
|
||||||
will be invoked only during emission of a given signal on a given instance.
|
will be invoked only during emission of a given signal on a given instance.
|
||||||
</para></listitem>
|
</para></listitem>
|
||||||
</itemizedlist>
|
</itemizedlist>
|
||||||
It is also possible to connect a different kind of callback on a given signal:
|
It is also possible to connect a different kind of callback on a given signal:
|
||||||
emission hooks are invoked whenever a given signal is emitted whatever the instance on
|
emission hooks are invoked whenever a given signal is emitted whatever the instance on
|
||||||
which it is emitted. Emission hooks are used for example to get all mouse_clicked
|
which it is emitted. Emission hooks are used for example to get all mouse_clicked
|
||||||
emissions in an application to be able to emit the small mouse click sound.
|
emissions in an application to be able to emit the small mouse click sound.
|
||||||
Emission hooks are connected with <function><link linkend="g-signal-add-emission-hook">g_signal_add_emission_hook</link></function>
|
Emission hooks are connected with <function><link linkend="g-signal-add-emission-hook">g_signal_add_emission_hook</link></function>
|
||||||
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>
|
</sect2>
|
||||||
</para>
|
|
||||||
|
|
||||||
</sect2>
|
<sect2 id="signal-emission">
|
||||||
|
<title>Signal emission</title>
|
||||||
|
|
||||||
<sect2 id="signal-emission">
|
<para>
|
||||||
<title>Signal emission</title>
|
Signal emission is done through the use of the <function><link linkend="g-signal-emit">g_signal_emit</link></function> family
|
||||||
|
of functions.
|
||||||
<para>
|
|
||||||
Signal emission is done through the use of the <function><link linkend="g-signal-emit">g_signal_emit</link></function> family
|
|
||||||
of functions.
|
|
||||||
<programlisting>
|
<programlisting>
|
||||||
void g_signal_emitv (const GValue *instance_and_params,
|
void g_signal_emitv (const GValue *instance_and_params,
|
||||||
guint signal_id,
|
guint signal_id,
|
||||||
GQuark detail,
|
GQuark detail,
|
||||||
GValue *return_value);
|
GValue *return_value);
|
||||||
</programlisting>
|
</programlisting>
|
||||||
<itemizedlist>
|
<itemizedlist>
|
||||||
<listitem><para>
|
<listitem><para>
|
||||||
The instance_and_params array of GValues contains the list of input
|
The instance_and_params array of GValues contains the list of input
|
||||||
parameters to the signal. The first element of the array is the
|
parameters to the signal. The first element of the array is the
|
||||||
instance pointer on which to invoke the signal. The following elements of
|
instance pointer on which to invoke the signal. The following elements of
|
||||||
the array contain the list of parameters to the signal.
|
the array contain the list of parameters to the signal.
|
||||||
</para></listitem>
|
</para></listitem>
|
||||||
<listitem><para>
|
<listitem><para>
|
||||||
signal_id identifies the signal to invoke.
|
signal_id identifies the signal to invoke.
|
||||||
</para></listitem>
|
</para></listitem>
|
||||||
<listitem><para>
|
<listitem><para>
|
||||||
detail identifies the specific detail of the signal to invoke. A detail is a kind of
|
detail identifies the specific detail of the signal to invoke. A detail is a kind of
|
||||||
magic token/argument which is passed around during signal emission and which is used
|
magic token/argument which is passed around during signal emission and which is used
|
||||||
by closures connected to the signal to filter out unwanted signal emissions. In most
|
by closures connected to the signal to filter out unwanted signal emissions. In most
|
||||||
cases, you can safely set this value to zero. See <xref linkend="signal-detail"/> for
|
cases, you can safely set this value to zero. See <xref linkend="signal-detail"/> for
|
||||||
more details about this parameter.
|
more details about this parameter.
|
||||||
</para></listitem>
|
</para></listitem>
|
||||||
<listitem><para>
|
<listitem><para>
|
||||||
return_value holds the return value of the last closure invoked during emission if
|
return_value holds the return value of the last closure invoked during emission if
|
||||||
no accumulator was specified. If an accumulator was specified during signal creation,
|
no accumulator was specified. If an accumulator was specified during signal creation,
|
||||||
this accumulator is used to calculate the return_value as a function of the return
|
this accumulator is used to calculate the return_value as a function of the return
|
||||||
values of all the closures invoked during emission.
|
values of all the closures invoked during emission.
|
||||||
<footnote><para>
|
<footnote><para>
|
||||||
James (again!!) gives a few non-trivial examples of accumulators:
|
James (again!!) gives a few non-trivial examples of accumulators:
|
||||||
<quote>
|
<quote>
|
||||||
For instance, you may have an accumulator that ignores NULL returns from
|
For instance, you may have an accumulator that ignores NULL returns from
|
||||||
closures, and only accumulates the non-NULL ones. Another accumulator may try
|
closures, and only accumulates the non-NULL ones. Another accumulator may try
|
||||||
to return the list of values returned by the closures.
|
to return the list of values returned by the closures.
|
||||||
</quote>
|
</quote>
|
||||||
</para></footnote>
|
</para></footnote>
|
||||||
If no closure is invoked during
|
If no closure is invoked during
|
||||||
emission, the return_value is nonetheless initialized to zero/null.
|
emission, the return_value is nonetheless initialized to zero/null.
|
||||||
</para></listitem>
|
</para></listitem>
|
||||||
</itemizedlist>
|
</itemizedlist>
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Internally, the GValue array is passed to the emission function proper,
|
Internally, the GValue array is passed to the emission function proper,
|
||||||
<function>signal_emit_unlocked_R</function> (implemented in <filename>gsignal.c</filename>).
|
<function>signal_emit_unlocked_R</function> (implemented in <filename>gsignal.c</filename>).
|
||||||
Signal emission can be decomposed in 5 steps:
|
Signal emission can be decomposed in 5 steps:
|
||||||
<itemizedlist>
|
<itemizedlist>
|
||||||
<listitem><para>
|
<listitem><para>
|
||||||
<emphasis>RUN_FIRST</emphasis>: if the G_SIGNAL_RUN_FIRST flag was used
|
<emphasis>RUN_FIRST</emphasis>: if the G_SIGNAL_RUN_FIRST flag was used
|
||||||
during signal registration and if there exist a class_closure for this signal,
|
during signal registration and if there exist a class_closure for this signal,
|
||||||
the class_closure is invoked. Jump to <emphasis>EMISSION_HOOK</emphasis> state.
|
the class_closure is invoked. Jump to <emphasis>EMISSION_HOOK</emphasis> state.
|
||||||
</para></listitem>
|
</para></listitem>
|
||||||
<listitem><para>
|
<listitem><para>
|
||||||
<emphasis>EMISSION_HOOK</emphasis>: if any emission hook was added to
|
<emphasis>EMISSION_HOOK</emphasis>: if any emission hook was added to
|
||||||
the signal, they are invoked from first to last added. Accumulate return values
|
the signal, they are invoked from first to last added. Accumulate return values
|
||||||
and jump to <emphasis>HANDLER_RUN_FIRST</emphasis> state.
|
and jump to <emphasis>HANDLER_RUN_FIRST</emphasis> state.
|
||||||
</para></listitem>
|
</para></listitem>
|
||||||
<listitem><para>
|
<listitem><para>
|
||||||
<emphasis>HANDLER_RUN_FIRST</emphasis>: if any closure were connected
|
<emphasis>HANDLER_RUN_FIRST</emphasis>: if any closure were connected
|
||||||
with the <function><link linkend="g-signal-connect">g_signal_connect</link></function> family of
|
with the <function><link linkend="g-signal-connect">g_signal_connect</link></function> family of
|
||||||
functions, and if they are not blocked (with the <function><link linkend="g-signal-handler-block">g_signal_handler_block</link></function>
|
functions, and if they are not blocked (with the <function><link linkend="g-signal-handler-block">g_signal_handler_block</link></function>
|
||||||
family of functions) they are run here, from first to last connected.
|
family of functions) they are run here, from first to last connected.
|
||||||
Jump to <emphasis>RUN_LAST</emphasis> state.
|
Jump to <emphasis>RUN_LAST</emphasis> state.
|
||||||
</para></listitem>
|
</para></listitem>
|
||||||
<listitem><para>
|
<listitem><para>
|
||||||
<emphasis>RUN_LAST</emphasis>: if the G_SIGNAL_RUN_LAST
|
<emphasis>RUN_LAST</emphasis>: if the G_SIGNAL_RUN_LAST
|
||||||
flag was set during registration and if a class_closure
|
flag was set during registration and if a class_closure
|
||||||
was set, it is invoked here. Jump to
|
was set, it is invoked here. Jump to
|
||||||
<emphasis>HANDLER_RUN_LAST</emphasis> state.
|
<emphasis>HANDLER_RUN_LAST</emphasis> state.
|
||||||
</para></listitem>
|
</para></listitem>
|
||||||
<listitem><para>
|
<listitem><para>
|
||||||
<emphasis>HANDLER_RUN_LAST</emphasis>: if any closure were connected
|
<emphasis>HANDLER_RUN_LAST</emphasis>: if any closure were connected
|
||||||
with the <function>g_signal_connect_after</function> family of
|
with the <function>g_signal_connect_after</function> family of
|
||||||
functions, if they were not invoked during HANDLER_RUN_FIRST and if they
|
functions, if they were not invoked during HANDLER_RUN_FIRST and if they
|
||||||
are not blocked, they are run here, from first to last connected.
|
are not blocked, they are run here, from first to last connected.
|
||||||
Jump to <emphasis>RUN_CLEANUP</emphasis> state.
|
Jump to <emphasis>RUN_CLEANUP</emphasis> state.
|
||||||
</para></listitem>
|
</para></listitem>
|
||||||
<listitem><para>
|
<listitem><para>
|
||||||
<emphasis>RUN_CLEANUP</emphasis>: if the G_SIGNAL_RUN_CLEANUP flag
|
<emphasis>RUN_CLEANUP</emphasis>: if the G_SIGNAL_RUN_CLEANUP flag
|
||||||
was set during registration and if a class_closure was set,
|
was set during registration and if a class_closure was set,
|
||||||
it is invoked here. Signal emission is completed here.
|
it is invoked here. Signal emission is completed here.
|
||||||
</para></listitem>
|
</para></listitem>
|
||||||
</itemizedlist>
|
</itemizedlist>
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
If, at any point during emission (except in RUN_CLEANUP state), one of the
|
If, at any point during emission (except in RUN_CLEANUP state), one of the
|
||||||
closures or emission hook stops the signal emission with
|
closures or emission hook stops the signal emission with
|
||||||
<function><link linkend="g-signal-stop">g_signal_stop</link></function>, emission jumps to CLEANUP state.
|
<function><link linkend="g-signal-stop">g_signal_stop</link></function>, emission jumps to CLEANUP state.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
If, at any point during emission, one of the closures or emission hook
|
If, at any point during emission, one of the closures or emission hook
|
||||||
emits the same signal on the same instance, emission is restarted from
|
emits the same signal on the same instance, emission is restarted from
|
||||||
the RUN_FIRST state.
|
the RUN_FIRST state.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
The accumulator function is invoked in all states, after invocation
|
The accumulator function is invoked in all states, after invocation
|
||||||
of each closure (except in EMISSION_HOOK and CLEANUP). It accumulates
|
of each closure (except in EMISSION_HOOK and CLEANUP). It accumulates
|
||||||
the closure return value into the signal return value and returns TRUE or
|
the closure return value into the signal return value and returns TRUE or
|
||||||
FALSE. If, at any point, it does not return TRUE, emission jumps to CLEANUP state.
|
FALSE. If, at any point, it does not return TRUE, emission jumps to CLEANUP state.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
If no accumulator function was provided, the value returned by the last handler
|
If no accumulator function was provided, the value returned by the last handler
|
||||||
run will be returned by <function><link linkend="g-signal-emit">g_signal_emit</link></function>.
|
run will be returned by <function><link linkend="g-signal-emit">g_signal_emit</link></function>.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|
||||||
|
|
||||||
<sect2 id="signal-detail">
|
<sect2 id="signal-detail">
|
||||||
<title>The <emphasis>detail</emphasis> argument</title>
|
<title>The <emphasis>detail</emphasis> argument</title>
|
||||||
|
|
||||||
<para>All the functions related to signal emission or signal connection have a parameter
|
<para>All the functions related to signal emission or signal connection have a parameter
|
||||||
named the <emphasis>detail</emphasis>. Sometimes, this parameter is hidden by the API
|
named the <emphasis>detail</emphasis>. Sometimes, this parameter is hidden by the API
|
||||||
but it is always there, under one form or another.
|
but it is always there, under one form or another.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Of the three main connection functions,
|
Of the three main connection functions,
|
||||||
only one has an explicit detail parameter as a <type><link linkend="GQuark">GQuark</link></type>
|
only one has an explicit detail parameter as a <type><link linkend="GQuark">GQuark</link></type>
|
||||||
<footnote>
|
<footnote>
|
||||||
<para>A GQuark is an integer which uniquely represents a string. It is possible to transform
|
<para>A GQuark is an integer which uniquely represents a string. It is possible to transform
|
||||||
back and forth between the integer and string representations with the functions
|
back and forth between the integer and string representations with the functions
|
||||||
<function><link linkend="g-quark-from-string">g_quark_from_string</link></function> and <function><link linkend="g-quark-to-string">g_quark_to_string</link></function>.
|
<function><link linkend="g-quark-from-string">g_quark_from_string</link></function> and <function><link linkend="g-quark-to-string">g_quark_to_string</link></function>.
|
||||||
</para>
|
</para>
|
||||||
</footnote>:
|
</footnote>:
|
||||||
<programlisting>
|
<programlisting>
|
||||||
gulong g_signal_connect_closure_by_id (gpointer instance,
|
gulong g_signal_connect_closure_by_id (gpointer instance,
|
||||||
guint signal_id,
|
guint signal_id,
|
||||||
GQuark detail,
|
GQuark detail,
|
||||||
GClosure *closure,
|
GClosure *closure,
|
||||||
gboolean after);
|
gboolean after);
|
||||||
</programlisting>
|
</programlisting>
|
||||||
The two other functions hide the detail parameter in the signal name identification:
|
The two other functions hide the detail parameter in the signal name identification:
|
||||||
<programlisting>
|
<programlisting>
|
||||||
gulong g_signal_connect_closure (gpointer instance,
|
gulong g_signal_connect_closure (gpointer instance,
|
||||||
const gchar *detailed_signal,
|
const gchar *detailed_signal,
|
||||||
GClosure *closure,
|
GClosure *closure,
|
||||||
gboolean after);
|
gboolean after);
|
||||||
gulong g_signal_connect_data (gpointer instance,
|
gulong g_signal_connect_data (gpointer instance,
|
||||||
const gchar *detailed_signal,
|
const gchar *detailed_signal,
|
||||||
GCallback c_handler,
|
GCallback c_handler,
|
||||||
gpointer data,
|
gpointer data,
|
||||||
GClosureNotify destroy_data,
|
GClosureNotify destroy_data,
|
||||||
GConnectFlags connect_flags);
|
GConnectFlags connect_flags);
|
||||||
</programlisting>
|
</programlisting>
|
||||||
Their detailed_signal parameter is a string which identifies the name of the signal
|
Their detailed_signal parameter is a string which identifies the name of the signal
|
||||||
to connect to. However, the format of this string is structured to look like
|
to connect to. However, the format of this string is structured to look like
|
||||||
<emphasis>signal_name::detail_name</emphasis>. Connecting to the signal
|
<emphasis>signal_name::detail_name</emphasis>. Connecting to the signal
|
||||||
named <emphasis>notify::cursor_position</emphasis> will actually connect to the signal
|
named <emphasis>notify::cursor_position</emphasis> will actually connect to the signal
|
||||||
named <emphasis>notify</emphasis> with the <emphasis>cursor_position</emphasis> name.
|
named <emphasis>notify</emphasis> with the <emphasis>cursor_position</emphasis> name.
|
||||||
Internally, the detail string is transformed to a GQuark if it is present.
|
Internally, the detail string is transformed to a GQuark if it is present.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Of the four main signal emission functions, three have an explicit detail parameter as a
|
Of the four main signal emission functions, three have an explicit detail parameter as a
|
||||||
<type><link linkend="GQuark">GQuark</link></type> again:
|
<type><link linkend="GQuark">GQuark</link></type> again:
|
||||||
<programlisting>
|
<programlisting>
|
||||||
void g_signal_emitv (const GValue *instance_and_params,
|
void g_signal_emitv (const GValue *instance_and_params,
|
||||||
guint signal_id,
|
guint signal_id,
|
||||||
GQuark detail,
|
GQuark detail,
|
||||||
GValue *return_value);
|
GValue *return_value);
|
||||||
void g_signal_emit_valist (gpointer instance,
|
void g_signal_emit_valist (gpointer instance,
|
||||||
guint signal_id,
|
guint signal_id,
|
||||||
GQuark detail,
|
GQuark detail,
|
||||||
va_list var_args);
|
va_list var_args);
|
||||||
void g_signal_emit (gpointer instance,
|
void g_signal_emit (gpointer instance,
|
||||||
guint signal_id,
|
guint signal_id,
|
||||||
GQuark detail,
|
GQuark detail,
|
||||||
...);
|
...);
|
||||||
</programlisting>
|
</programlisting>
|
||||||
The fourth function hides it in its signal name parameter:
|
The fourth function hides it in its signal name parameter:
|
||||||
<programlisting>
|
<programlisting>
|
||||||
void g_signal_emit_by_name (gpointer instance,
|
void g_signal_emit_by_name (gpointer instance,
|
||||||
const gchar *detailed_signal,
|
const gchar *detailed_signal,
|
||||||
...);
|
...);
|
||||||
</programlisting>
|
</programlisting>
|
||||||
The format of the detailed_signal parameter is exactly the same as the format used by
|
The format of the detailed_signal parameter is exactly the same as the format used by
|
||||||
the <function><link linkend="g-signal-connect">g_signal_connect</link></function> functions: <emphasis>signal_name::detail_name</emphasis>.
|
the <function><link linkend="g-signal-connect">g_signal_connect</link></function> functions: <emphasis>signal_name::detail_name</emphasis>.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
If a detail is provided by the user to the emission function, it is used during emission to match
|
If a detail is provided by the user to the emission function, it is used during emission to match
|
||||||
against the closures which also provide a detail.
|
against the closures which also provide a detail.
|
||||||
If the closures' detail does not match the detail provided by the user, they will not be invoked
|
If the closures' detail does not match the detail provided by the user, they will not be invoked
|
||||||
(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>
|
||||||
which are often emitted for many different reasons: the clients can filter out which events they are
|
This completely optional filtering mechanism is mainly used as an optimization for signals
|
||||||
interested into before the closure's marshalling code runs. For example, this is used extensively
|
which are often emitted for many different reasons: the clients can filter out which events they are
|
||||||
by the <emphasis>notify</emphasis> signal of GObject: whenever a property is modified on a GObject,
|
interested into before the closure's marshalling code runs. For example, this is used extensively
|
||||||
instead of just emitting the <emphasis>notify</emphasis> signal, GObject associates as a detail to this
|
by the <emphasis>notify</emphasis> signal of GObject: whenever a property is modified on a GObject,
|
||||||
signal emission the name of the property modified. This allows clients who wish to be notified of changes
|
instead of just emitting the <emphasis>notify</emphasis> signal, GObject associates as a detail to this
|
||||||
to only one property to filter most events before receiving them.
|
signal emission the name of the property modified. This allows clients who wish to be notified of changes
|
||||||
</para>
|
to only one property to filter most events before receiving them.
|
||||||
|
</para>
|
||||||
|
|
||||||
<para>As a simple rule, users can and should set the detail parameter to zero: this will disable completely
|
<para>
|
||||||
this optional filtering.
|
As a simple rule, users can and should set the detail parameter to zero: this will disable completely
|
||||||
</para>
|
this optional filtering.
|
||||||
|
</para>
|
||||||
|
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|
||||||
|
</sect1>
|
||||||
|
</chapter>
|
||||||
|
|
||||||
</sect1>
|
|
||||||
</chapter>
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -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,79 +100,80 @@ 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>
|
||||||
There are numerous different implementations of dynamic type systems: all C++
|
<footnote>
|
||||||
compilers have one, Java and .NET have one too. A dynamic type system allows you
|
<para>
|
||||||
to get information about every instantiated object at runtime. It can be implemented
|
There are numerous different implementations of dynamic type systems: all C++
|
||||||
by a process-specific database: every new object created registers the characteristics
|
compilers have one, Java and .NET have one too. A dynamic type system allows you
|
||||||
of its associated type in the type system. It can also be implemented by introspection
|
to get information about every instantiated object at runtime. It can be implemented
|
||||||
interfaces. The common point between all these different type systems and implementations
|
by a process-specific database: every new object created registers the characteristics
|
||||||
is that they all allow you to query for object metadata at runtime.
|
of its associated type in the type system. It can also be implemented by introspection
|
||||||
</para>
|
interfaces. The common point between all these different type systems and implementations
|
||||||
</footnote>
|
is that they all allow you to query for object metadata at runtime.
|
||||||
|
</para>
|
||||||
|
</footnote>
|
||||||
|
library is then used by special generic glue code to automatically convert function parameters and
|
||||||
|
function calling conventions between different runtime domains.</para></listitem>
|
||||||
|
</itemizedlist>
|
||||||
|
The greatest advantage of the solution implemented by GType is that the glue code sitting at the runtime domain
|
||||||
|
boundaries is written once: the figure below states this more clearly.
|
||||||
|
<figure>
|
||||||
|
<mediaobject>
|
||||||
|
<imageobject> <!-- this is for HTML output -->
|
||||||
|
<imagedata fileref="glue.png" format="PNG" align="center"/>
|
||||||
|
</imageobject>
|
||||||
|
<imageobject> <!-- this is for PDF output -->
|
||||||
|
<imagedata fileref="glue.jpg" format="JPG" align="center"/>
|
||||||
|
</imageobject>
|
||||||
|
</mediaobject>
|
||||||
|
</figure>
|
||||||
|
|
||||||
library is then
|
Currently, there exist at least Python and Perl generic glue code which makes it possible to use
|
||||||
used by special generic glue code to automatically convert function parameters and function calling conventions
|
C objects written with GType directly in Python or Perl, with a minimum amount of work: there
|
||||||
between different runtime domains.</para></listitem>
|
is no need to generate huge amounts of glue code either automatically or by hand.
|
||||||
</itemizedlist>
|
</para>
|
||||||
The greatest advantage of the solution implemented by GType is that the glue code sitting at the runtime domain
|
|
||||||
boundaries is written once: the figure below states this more clearly.
|
|
||||||
<figure>
|
|
||||||
<mediaobject>
|
|
||||||
<imageobject> <!-- this is for HTML output -->
|
|
||||||
<imagedata fileref="glue.png" format="PNG" align="center"/>
|
|
||||||
</imageobject>
|
|
||||||
<imageobject> <!-- this is for PDF output -->
|
|
||||||
<imagedata fileref="glue.jpg" format="JPG" align="center"/>
|
|
||||||
</imageobject>
|
|
||||||
</mediaobject>
|
|
||||||
</figure>
|
|
||||||
|
|
||||||
Currently, there exist at least Python and Perl generic glue code which makes it possible to use
|
<para>
|
||||||
C objects written with GType directly in Python or Perl, with a minimum amount of work: there
|
Although that goal was arguably laudable, its pursuit has had a major influence on
|
||||||
is no need to generate huge amounts of glue code either automatically or by hand.
|
the whole GType/GObject library. C programmers are likely to be puzzled at the complexity
|
||||||
</para>
|
of the features exposed in the following chapters if they forget that the GType/GObject library
|
||||||
|
was not only designed to offer OO-like features to C programmers but also transparent
|
||||||
|
cross-language interoperability.
|
||||||
|
</para>
|
||||||
|
|
||||||
<para>Although that goal was arguably laudable, its pursuit has had a major influence on
|
</sect1>
|
||||||
the whole GType/GObject library. C programmers are likely to be puzzled at the complexity
|
|
||||||
of the features exposed in the following chapters if they forget that the GType/GObject library
|
|
||||||
was not only designed to offer OO-like features to C programmers but also transparent
|
|
||||||
cross-language interoperability.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
</sect1>
|
|
||||||
|
|
||||||
</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.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user