diff options
author | Mathieu Lacage <mathieu@src.gnome.org> | 2004-01-22 18:39:45 +0000 |
---|---|---|
committer | Mathieu Lacage <mathieu@src.gnome.org> | 2004-01-22 18:39:45 +0000 |
commit | e992ea6fb6c67fff97ce4a792f6d666c27c7cc22 (patch) | |
tree | 8431447013120f6a1da799c563f7f9f896317439 | |
parent | 1107a9f41a3103bfdcac3b07537f16fa386b35f6 (diff) |
Initial revision
-rw-r--r-- | docs/reference/gobject/tut_gobject.xml | 737 | ||||
-rw-r--r-- | docs/reference/gobject/tut_gsignal.xml | 520 | ||||
-rw-r--r-- | docs/reference/gobject/tut_gtype.xml | 907 | ||||
-rw-r--r-- | docs/reference/gobject/tut_howto.xml | 1452 | ||||
-rw-r--r-- | docs/reference/gobject/tut_intro.xml | 160 |
5 files changed, 3776 insertions, 0 deletions
diff --git a/docs/reference/gobject/tut_gobject.xml b/docs/reference/gobject/tut_gobject.xml new file mode 100644 index 000000000..1ee22d4b5 --- /dev/null +++ b/docs/reference/gobject/tut_gobject.xml @@ -0,0 +1,737 @@ +<?xml version='1.0' encoding="ISO-8859-1"?> + + <chapter id="chapter-gobject"> + <title>GObject: what brings everything together.</title> + + <para> + 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>GObject</type>. + </para> + + <para> + <type>GObject</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 GTK objects and all of the objects in Gnome libraries which use the glib type + system inherit from <type>GObject</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> + The <function>g_object_new</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 + has 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 memory through <function>g_type_create_instance</function>, + </para></listitem> + <listitem><para> + Initialize the object' instance with the construction properties. + </para></listitem> + </itemizedlist> + </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> + GObject* (*constructor) (GType type, + guint n_construct_properties, + GObjectConstructParam *construct_properties); +</programlisting> + </para> + + <para> + The example below shows how <type>MamanBar</type> overrides the parent's constructor: +<programlisting> +#define MAMAN_BAR_TYPE (maman_bar_get_type ()) +#define MAMAN_BAR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MAMAN_BAR_TYPE, MamanBar)) +#define MAMAN_BAR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MAMAN_BAR_TYPE, MamanBarClass)) +#define MAMAN_IS_BAR(obj) (G_TYPE_CHECK_TYPE ((obj), MAMAN_BAR_TYPE)) +#define MAMAN_IS_BAR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MAMAN_BAR_TYPE)) +#define MAMAN_BAR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MAMAN_BAR_TYPE, MamanBarClass)) + +typedef struct _MamanBar MamanBar; +typedef struct _MamanBarClass MamanBarClass; + +struct _MamanBar { + GObject parent; + /* instance members */ +}; + +struct _MamanBarClass { + GObjectClass parent; + + /* class members */ +}; + +/* used by MAMAN_BAR_TYPE */ +GType maman_bar_get_type (void); + +static GObject * +maman_bar_constructor (GType type, + guint n_construct_properties, + GObjectConstructParam *construct_properties) +{ + GObject *obj; + + { + /* Invoke parent constructor. */ + MamanBarClass *klass; + GObjectClass *parent_class; + klass = MAMAN_BAR_CLASS (g_type_class_peek (MAMAN_BAR_TYPE)); + parent_class = G_OBJECT_CLASS (g_type_class_peek_parent (klass)); + obj = parent_class->constructor (type, + n_construct_properties, + construct_properties); + } + + /* do stuff. */ + + return obj; +} + +static void +maman_bar_instance_init (GTypeInstance *instance, + gpointer g_class) +{ + MamanBar *self = (MamanBar *)instance; + /* do stuff */ +} + +static void +maman_bar_class_init (gpointer g_class, + gpointer g_class_data) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (g_class); + MamanBarClass *klass = MAMAN_BAR_CLASS (g_class); + + gobject_class->constructor = maman_bar_constructor; +} + +GType maman_bar_get_type (void) +{ + static GType type = 0; + if (type == 0) { + static const GTypeInfo info = { + sizeof (MamanBarClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + maman_bar_class_init, /* class_init */ + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (MamanBar), + 0, /* n_preallocs */ + maman_bar_instance_init /* instance_init */ + }; + type = g_type_register_static (G_TYPE_OBJECT, + "MamanBarType", + &info, 0); + } + return type; +} +</programlisting> + If the user instantiates an object <type>MamanBar</type> with: +<programlisting> +MamanBar *bar = g_object_new (MAMAN_BAR_TYPE, NULL); +</programlisting> + 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. + 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 + 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>. + </para> + + <para> + Once <function>g_object_new</function> has obtained a reference to an initialized + 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> + 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 + 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> + 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 + <function>g_type_class_peek</function> and <function>g_type_class_peek_parent</function> functions. + </para> + + <para> + 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 + through <function>g_type_create_instance</function> + 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 + ready to answer any user-request. When <function>g_type_create_instance</function> + returns, <function>g_object_constructor</function> sets the construction properties + (ie: the properties which were given to <function>g_object_new</function>) and returns + to the user's constructor which is then allowed to do useful instance initialization... + </para> + + <para> + 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 + lists the functions invoked by <function>g_object_new</function> and their order of + invocation. + </para> + + <para> + The array below lists the functions invoked by <function>g_object_new</function> and + their order of invocation: + + <table id="gobject-construction-table"> + <title><function>g_object_new</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>First call to <function>g_object_new</function> for target type</entry> + <entry>target type's base_init 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> + 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. + </entry> + </row> + <row> + <entry>First call to <function>g_object_new</function> for target type</entry> + <entry>target type's class_init function</entry> + <entry>On target type's class structure</entry> + <entry> + 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 + the properties associated to your object. + </entry> + </row> + <row> + <entry>First call to <function>g_object_new</function> for target type</entry> + <entry>interface' base_init function</entry> + <entry>On interface' vtable</entry> + <entry></entry> + </row> + <row> + <entry>First call to <function>g_object_new</function> for target type</entry> + <entry>interface' interface_init function</entry> + <entry>On interface' vtable</entry> + <entry></entry> + </row> + <row> + <entry>Each call to <function>g_object_new</function> for target type</entry> + <entry>target type's class constructor method: GObjectClass->constructor</entry> + <entry>On object's instance</entry> + <entry> + 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 + parent class before doing your own initialization. + In doubt, do not override the constructor method. + </entry> + </row> + <row> + <entry>Each call to <function>g_object_new</function> for target type</entry> + <entry>type's instance_init function</entry> + <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 + structure.</entry> + <entry> + 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. + This function is equivalent to C++ constructors. + </entry> + </row> + </tbody> + </tgroup> + </table> + </para> + + <para> + Readers should feel concerned about one little twist in the order in which functions + are invoked: while, technically, the class' constructor method is called + <emphasis>before</emphasis> the GType's instance_init function (since + <function>g_type_create_instance</function> which calls instance_init is called by + <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 + which runs in a user-provided constructor will always run <emphasis>after</emphasis> + GType's instance_init function since the user-provided constructor + <emphasis>must</emphasis> (you've been warned) chain up <emphasis>before</emphasis> + doing anything useful. + </para> + </sect1> + + <sect1 id="gobject-memory"> + <title>Object memory management</title> + + <para> + 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 + which can be integrated in applications which use or require different memory management + models (such as garbage collection, aso...) +<programlisting> +/* + Refcounting +*/ +gpointer g_object_ref (gpointer object); +void g_object_unref (gpointer object); + +/* + Weak References +*/ +typedef void (*GWeakNotify) (gpointer data, + GObject *where_the_object_was); +void g_object_weak_ref (GObject *object, + GWeakNotify notify, + gpointer data); +void g_object_weak_unref (GObject *object, + GWeakNotify notify, + gpointer data); +void g_object_add_weak_pointer (GObject *object, + gpointer *weak_pointer_location); +void g_object_remove_weak_pointer (GObject *object, + gpointer *weak_pointer_location); +/* + Cycle handling +*/ +void g_object_run_dispose (GObject *object); +</programlisting> + </para> + + <sect2 id="gobject-memory-refcount"> + <title>Reference count</title> + + <para> + <function>g_object_ref</function>/<function>g_object_unref</function> respectively + increase and decrease the reference count. None of these function is thread-safe. + The reference count is, unsurprisingly, initialized to one by + <function>g_object_new</function>. When the reference count reaches zero, that is, + when <function>g_object_unref</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>g_type_free_instance</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"></xref> and + <xref linkend="gtype-non-instantiable-classed"></xref>. + </para> + + <para> + The table below summarizes the destruction process of a GObject: + <table id="gobject-destruction-table"> + <title><function>g_object_unref</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>Last call to <function>g_object_unref</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>g_object_unref</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"></xref>. + </entry> + </row> + <row> + <entry>Last call to <function>g_object_unref</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>g_object_unref</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>g_object_unref</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>g_object_unref</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>g_object_weak_ref</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>g_object_weak_unref</function> can be used to remove a monitoring + callback from the object. + </para> + + <para> + Weak References are also used to implement <function>g_object_add_weak_pointer</function> + and <function>g_object_remove_weak_pointer</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> + + </sect2> + + <sect2 id="gobject-memory-cycles"> + <title>Reference counts and cycles</title> + + <para> + 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. + </para> + + <para> + 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: + 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 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. + </para> + + <para> + 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 + detected, the external code can invoke <function>g_object_dispose</function> which + 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. + </para> + + <para> + 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 + 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 + do this would be to invoke <function>g_object_dispose</function> on one of the + objects. + </para> + + <para> + 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 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 + unref runs A's dispose handler which is running for the second time before + A's finalize handler is invoked ! + </para> + + <para> + The above example, which might seem a bit contrived can really happen if your + GObject's are being by language bindings. I would thus suggest the rules stated above + for object destruction are closely followed. Otherwise, <emphasis>Bad Bad Things</emphasis> + will happen. + </para> + </sect2> + </sect1> + + <sect1 id="gobject-properties"> + <title>Object properties</title> + + <para> + One of GObject's nice features is its generic get/set mechanism. When an object + is instanciated, the object's class_init handler should be used to register + the object's properties with <function>g_object_class_install_property</function> + (implemented in <filename>gobject.c</filename>). + </para> + + <para> + The best way to understand how object properties work is by looking at a real example + on how it is used: +<programlisting> +/************************************************/ +/* Implementation */ +/************************************************/ + +enum { + MAMAN_BAR_CONSTRUCT_NAME = 1, + MAMAN_BAR_PAPA_NUMBER = 2, +}; + +static void +maman_bar_instance_init (GTypeInstance *instance, + gpointer g_class) +{ + MamanBar *self = (MamanBar *)instance; +} + + +static void +maman_bar_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + MamanBar *self = (MamanBar *) object; + + switch (property_id) { + case MAMAN_BAR_CONSTRUCT_NAME: { + g_free (self->private->name); + self->private->name = g_value_dup_string (value); + g_print ("maman: %s\n",self->private->name); + } + break; + case MAMAN_BAR_PAPA_NUMBER: { + self->private->papa_number = g_value_get_uchar (value); + g_print ("papa: %u\n",self->private->papa_number); + } + break; + default: + /* We don't have any other property... */ + g_assert (FALSE); + break; + } +} + +static void +maman_bar_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + MamanBar *self = (MamanBar *) object; + + switch (property_id) { + case MAMAN_BAR_CONSTRUCT_NAME: { + g_value_set_string (value, self->private->name); + } + break; + case MAMAN_BAR_PAPA_NUMBER: { + g_value_set_uchar (value, self->private->papa_number); + } + break; + default: + /* We don't have any other property... */ + g_assert (FALSE); + break; + } +} + +static void +maman_bar_class_init (gpointer g_class, + gpointer g_class_data) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (g_class); + MamanBarClass *klass = MAMAN_BAR_CLASS (g_class); + GParamSpec *pspec; + + gobject_class->set_property = maman_bar_set_property; + gobject_class->get_property = maman_bar_get_property; + + pspec = g_param_spec_string ("maman-name", + "Maman construct prop", + "Set maman's name", + "no-name-set" /* default value */, + G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE); + g_object_class_install_property (gobject_class, + MAMAN_BAR_CONSTRUCT_NAME, + pspec); + + pspec = g_param_spec_uchar ("papa-number", + "Number of current Papa", + "Set/Get papa's number", + 0 /* minimum value */, + 10 /* maximum value */, + 2 /* default value */, + G_PARAM_READWRITE); + g_object_class_install_property (gobject_class, + MAMAN_BAR_PAPA_NUMBER, + pspec); +} + +/************************************************/ +/* Use */ +/************************************************/ + +GObject *bar; +GValue val = {0,}; +bar = g_object_new (MAMAN_SUBBAR_TYPE, NULL); +g_value_init (&val, G_TYPE_CHAR); +g_value_set_char (&val, 11); +g_object_set_property (G_OBJECT (bar), "papa-number", &val); +</programlisting> + The client code just above looks simple but a lot of things happen under the hood: + </para> + + <para> + <function>g_object_set_property</function> first ensures a property + with this name was registered in bar's class_init handler. If so, it calls + <function>object_set_property</function> which first walks the class hierarchy, + from bottom, most derived type, to top, fundamental type to find the class + which registered that property. It then tries to convert the user-provided GValue + into a GValue whose type if that of the associated property. + </para> + + <para> + If the user provides a signed char GValue, as is shown + here, and if the object's property was registered as an unsigned int, + <function>g_value_transform</function> will try to transform the input signed char into + an unsigned int. Of course, the success of the transformation depends on the availability + of the required transform function. In practice, there will almost always be a transformation + <footnote> + <para>Its behaviour might not be what you expect but it is up to you to actually avoid + relying on these transformations. + </para> + </footnote> + which matches and conversion will be caried out if needed. + </para> + + <para> + After transformation, the <type>GValue</type> is validated by + <function>g_param_value_validate</function> which makes sure the user's + data stored in the <type>GValue</type> matches the characteristics specified by + the property's <type>GParamSpec</type>. Here, the <type>GParamSpec</type> we + provided in class_init has a validation function which makes sure that the GValue + contains a value which respects the minimum and maximum bounds of the + <type>GParamSpec</type>. In the example above, the client's GValue does not + respect these constraints (it is set to 11, while the maximum is 10). As such, the + <function>g_object_set_property</function> function will return with an error. + </para> + + <para> + If the user's GValue had been set to a valid value, <function>object_set_property</function> + would have proceeded with calling the object's set_property class method. Here, since our + implementation of Foo did override this method, the code path would jump to + <function>foo_set_property</function> after having retrieved from the + <type>GParamSpec</type> the <emphasis>param_id</emphasis> + <footnote> + <para> + It should be noted that the param_id used here need only to uniquely identify each + <type>GParamSpec</type> within the <type>FooClass</type> such that the switch + 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 + <emphasis>if (strcmp (a, b) == 0) {} else if (strcmp (a, b) == 0) {}</emphasis> statements. + </para> + </footnote> + which had been stored by + <function>g_object_class_install_property</function>. + </para> + + <para> + Once the property has been set by the object's set_property class method, the code path + returns to <function>g_object_set_property</function> which calls + <function>g_object_notify_queue_thaw</function>. This function makes sure that + the "notify" signal is emitted on the object's instance with the changed property as + parameter unless notifications were frozen by <function>g_object_freeze_notify</function>. + </para> + + <para> + <function>g_object_thaw_notify</function> can be used to re-enable notification of + property modifications through the "notify" signal. It is important to remember that + even if properties are changed while property change notification is frozen, the "notify" + signal will be emitted once for each of these changed properties as soon as the property + change notification is thawn: no property change is lost for the "notify" signal. Signal + can only be delayed by the notification freezing mechanism. + </para> + + <para> + It is interesting to note that the <function>g_object_set</function> and + <function>g_object_set_valist</function> (vararg version) functions can be used to set + multiple properties at once. The client code shown above can then be re-written as: +<programlisting> +MamanBar *foo; +foo = /* */; +g_object_set (G_OBJECT (foo), + "papa-number", 2, + "maman-name", "test", + NULL); +</programlisting> + The code above will trigger one notify signal emission for each property modified. + </para> + + <para> + Of course, the _get versions are also available: <function>g_object_get</function> + and <function>g_object_get_valist</function> (vararg version) can be used to get numerous + properties at once. + </para> + + <para> + Really attentive readers now understand how <function>g_object_new</function>, + <function>g_object_newv</function> and <function>g_object_new_valist</function> + work: they parse the user-provided variable number of parameters and invoke + <function>g_object_set</function> on each pair of parameters only after the object has been successfully constructed. + Of course, the "notify" signal will be emitted for each property set. + </para> + + </sect1> + + </chapter> + + + + diff --git a/docs/reference/gobject/tut_gsignal.xml b/docs/reference/gobject/tut_gsignal.xml new file mode 100644 index 000000000..2a658c857 --- /dev/null +++ b/docs/reference/gobject/tut_gsignal.xml @@ -0,0 +1,520 @@ +<?xml version='1.0' encoding="ISO-8859-1"?> + <chapter id="chapter-signal"> + <title>Signals</title> + + <sect1 id="closure"> + <title>Closures</title> + + <para> + Closures are central to the concept of asynchronous signal delivery + 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 + which contains three objects: + <itemizedlist> + <listitem><para>a function pointer (the callback itself) whose prototype looks like: +<programlisting> +return_type function_callback (... , gpointer user_data); +</programlisting> + </para></listitem> + <listitem><para> + the user_data pointer which is passed to the callback upon invocation of the closure + </para></listitem> + <listitem><para> + a function pointer which represents the destructor of the closure: whenever the + closure's refcount reaches zero, this function will be called before the closure + structure is freed. + </para></listitem> + </itemizedlist> + </para> + + <para> + The <type>GClosure</type> structure represents the common functionality of all + closure implementations: there exist 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>GCClosure</type> type which + is a specific implementation of closures to be used with C/C++ callbacks. + </para> + <para> + A <type>GClosure</type> provides simple services: + <itemizedlist> + <listitem><para> + Invocation (<function>g_closure_invoke</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>g_closure_add_finalize_notifier</function> + (finalization notification), <function>g_closure_add_invalidate_notifier</function> + (invalidation notification) and + <function>g_closure_add_marshal_guards</function> (invocation notification). + There exist symmetric de-registration functions for finalization and invalidation + events (<function>g_closure_remove_finalize_notifier</function> and + <function>g_closure_remove_invalidate_notifier</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>GCClosure</type>s + which have a pretty minimal API or the even simpler <function>g_signal_connect</function> + functions (which will be presented a bit later :). + <programlisting> +GClosure* g_cclosure_new (GCallback callback_func, + gpointer user_data, + GClosureNotify destroy_data); +GClosure* g_cclosure_new_swap (GCallback callback_func, + gpointer user_data, + GClosureNotify destroy_data); +GClosure* g_signal_type_cclosure_new (GType itype, + guint struct_offset); + </programlisting> + </para> + + <para> + <function>g_cclosure_new</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 + is finalized (second stage of the destruction process), it will invoke the destroy_data function + if the user has supplied one. + </para> + + <para> + <function>g_cclosure_new_swap</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 + last parameter as with <function>g_cclosure_new</function>). When the closure + is finalized (second stage of the destruction process), it will invoke the destroy_data + function if the user has supplied one. + </para> + </sect2> + + <sect2> + <title>non-C closures (for the fearless).</title> + + <para> + 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 + the correct stack frame for the called function and executing a <emphasis>call</emphasis> + assembly instruction. + </para> + + <para> + 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 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. + </para> + + <para> + The following code implements a simple marshaller in C for a C function which takes an + integer as first parameter and returns void. + <programlisting> +g_cclosure_marshal_VOID__INT (GClosure *closure, + GValue *return_value, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint, + gpointer marshal_data) +{ + typedef void (*GMarshalFunc_VOID__INT) (gpointer data1, + gint arg_1, + gpointer data2); + register GMarshalFunc_VOID__INT callback; + register GCClosure *cc = (GCClosure*) closure; + register gpointer data1, data2; + + g_return_if_fail (n_param_values == 2); + + data1 = g_value_peek_pointer (param_values + 0); + data2 = closure->data; + + callback = (GMarshalFunc_VOID__INT) (marshal_data ? marshal_data : cc->callback); + + callback (data1, + g_marshal_value_peek_int (param_values + 1), + 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 tupple which is the equivalent structure in python (you can + look in <function>pyg_closure_marshal</function> in <filename>pygtype.c</filename> + in the <emphasis>pygtk</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> + </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>g_signal_newv</function>, + <function>g_signal_new_valist</function> or <function>g_signal_new</function> functions: +<programlisting> +guint g_signal_newv (const gchar *signal_name, + GType itype, + GSignalFlags signal_flags, + GClosure *class_closure, + GSignalAccumulator accumulator, + gpointer accu_data, + GSignalCMarshaller c_marshaller, + GType return_type, + guint n_params, + GType *param_types); +</programlisting> + The number of parameters to these functions is a bit intimidating but they are relatively + simple: + <itemizedlist> + <listitem><para> + signal_name: is a string which can be used to uniquely identify a given signal. + </para></listitem> + <listitem><para> + itype: is the instance type on which this signal can be emitted. + </para></listitem> + <listitem><para> + signal_flags: partly defines the order in which closures which were connected to the + signal are invoked. + </para></listitem> + <listitem><para> + 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 + moment where this closure is invoked compared to other closures connected to that + signal depends partly on the signal_flags. + </para></listitem> + <listitem><para> + 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 + 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. + </para></listitem> + <listitem><para> + accumulator_data: this pointer will be passed down to each invocation of the + accumulator during emission. + </para></listitem> + <listitem><para> + c_marshaller: this is the default C marshaller for any closure which is connected to + this signal. + </para></listitem> + <listitem><para> + return_type: this is the type of the return value of the signal. + </para></listitem> + <listitem><para> + n_params: this is the number of parameters this signal takes. + </para></listitem> + <listitem><para> + 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. + </para></listitem> + </itemizedlist> + </para> + + <para> + 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 + order in which the closures connected to this signal will be invoked. + </para> + + </sect2> + + <sect2 id="signal-connection"> + <title>Signal connection</title> + + <para> + If you want to connect to a signal with a closure, you have three possibilities: + <itemizedlist> + <listitem><para> + 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 + of a given signal on all the instances of the type which supports that signal. + </para></listitem> + <listitem><para> + You can use <function>g_signal_override_class_closure</function> which + 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. + This function is of use only to language bindings. + </para></listitem> + <listitem><para> + You can register a closure with the <function>g_signal_connect</function> + 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. + </para></listitem> + </itemizedlist> + 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 + 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. + Emission hooks are connected with <function>g_signal_add_emission_hook</function> + and removed with <function>g_signal_remove_emission_hook</function>. + </para> + + <para> + </para> + + </sect2> + + <sect2 id="signal-emission"> + <title>Signal emission</title> + + <para> + Signal emission is done through the use of the <function>g_signal_emit</function> family + of functions. +<programlisting> +void g_signal_emitv (const GValue *instance_and_params, + guint signal_id, + GQuark detail, + GValue *return_value); +</programlisting> + <itemizedlist> + <listitem><para> + The instance_and_params array of GValues contains the list of input + parameters to the signal. The first element of the array is the + instance pointer on which to invoke the signal. The following elements of + the array contain the list of parameters to the signal. + </para></listitem> + <listitem><para> + signal_id identifies the signal to invoke. + </para></listitem> + <listitem><para> + 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 + 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 + more details about this parameter. + </para></listitem> + <listitem><para> + 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, + this accumulator is used to calculate the return_value as a function of the return + values of all the closures invoked during emission. + <footnote><para> + James (again!!) gives a few non-trivial examples of accumulators: + <quote> + For instance, you may have an accumulator that ignores NULL returns from + closures, and only accumulates the non-NULL ones. Another accumulator may try + to return the list of values returned by the closures. + </quote> + </para></footnote> + If no closure is invoked during + emission, the return_value is nonetheless initialized to zero/null. + </para></listitem> + </itemizedlist> + </para> + + <para> + Internally, the GValue array is passed to the emission function proper, + <function>signal_emit_unlocked_R</function> (implemented in <filename>gsignal.c</filename>). + Signal emission can be decomposed in 5 steps: + <itemizedlist> + <listitem><para> + <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, + the class_closure is invoked. Jump to <emphasis>EMISSION_HOOK</emphasis> state. + </para></listitem> + <listitem><para> + <emphasis>EMISSION_HOOK</emphasis>: if any emission hook was added to + the signal, they are invoked from first to last added. Accumulate return values + and jump to <emphasis>HANDLER_RUN_FIRST</emphasis> state. + </para></listitem> + <listitem><para> + <emphasis>HANDLER_RUN_FIRST</emphasis>: if any closure were connected + with the <function>g_signal_connect</function> family of + functions, and if they are not blocked (with the <function>g_signal_handler_block</function> + family of functions) they are run here, from first to last connected. + Jump to <emphasis>RUN_LAST</emphasis> state. + </para></listitem> + <listitem><para> + <emphasis>RUN_LAST</emphasis>: if the G_SIGNAL_RUN_LAST + flag was set during registration and if a class_closure + was set, it is invoked here. Jump to + <emphasis>HANDLER_RUN_LAST</emphasis> state. + </para></listitem> + <listitem><para> + <emphasis>HANDLER_RUN_LAST</emphasis>: if any closure were connected + with the <function>g_signal_connect_after</function> family of + 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. + Jump to <emphasis>RUN_CLEANUP</emphasis> state. + </para></listitem> + <listitem><para> + <emphasis>RUN_CLEANUP</emphasis>: if the G_SIGNAL_RUN_CLEANUP flag + was set during registration and if a class_closure was set, + it is invoked here. Signal emission is completed here. + </para></listitem> + </itemizedlist> + </para> + + <para> + If, at any point during emission (except in RUN_CLEANUP state), one of the + closures or emission hook stops the signal emission with + <function>g_signal_stop</function>, emission jumps to CLEANUP state. + </para> + + <para> + 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 + the RUN_FIRST state. + </para> + + <para> + The accumulator function is invoked in all states, after invocation + of each closure (except in EMISSION_HOOK and CLEANUP). It accumulates + 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. + </para> + + <para> + If no accumulator function was provided, the value returned by the last handler + run will be returned by <function>g_signal_emit</function>. + </para> + + </sect2> + + + <sect2 id="signal-detail"> + <title>The <emphasis>detail</emphasis> argument</title> + + <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 + but it is always there, under one form or another. + </para> + + <para> + Of the three main connection functions, + only one has an explicit detail parameter as a <type>GQuark</type> + <footnote> + <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 + <function>g_quark_from_string</function> and <function>g_quark_to_string</function>. + </para> + </footnote>: +<programlisting> +gulong g_signal_connect_closure_by_id (gpointer instance, + guint signal_id, + GQuark detail, + GClosure *closure, + gboolean after); +</programlisting> + The two other functions hide the detail parameter in the signal name identification: +<programlisting> +gulong g_signal_connect_closure (gpointer instance, + const gchar *detailed_signal, + GClosure *closure, + gboolean after); +gulong g_signal_connect_data (gpointer instance, + const gchar *detailed_signal, + GCallback c_handler, + gpointer data, + GClosureNotify destroy_data, + GConnectFlags connect_flags); +</programlisting> + 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 + <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</emphasis> with the <emphasis>cursor_position</emphasis> name. + Internally, the detail string is transformed to a GQuark if it is present. + </para> + + <para> + Of the four main signal emission functions, three have an explicit detail parameter as a + <type>GQuark</type> again: +<programlisting> +void g_signal_emitv (const GValue *instance_and_params, + guint signal_id, + GQuark detail, + GValue *return_value); +void g_signal_emit_valist (gpointer instance, + guint signal_id, + GQuark detail, + va_list var_args); +void g_signal_emit (gpointer instance, + guint signal_id, + GQuark detail, + ...); +</programlisting> + The fourth function hides it in its signal name parameter: +<programlisting> +void g_signal_emit_by_name (gpointer instance, + const gchar *detailed_signal, + ...); +</programlisting> + The format of the detailed_signal parameter is exactly the same as the format used by + the <function>g_signal_connect</function> functions: <emphasis>signal_name::detail_name</emphasis>. + </para> + + <para> + 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. The closures which provided a detail will not + be invoked (even though they are connected to a signal which is being emitted) if their detail + does not match the detail provided by the user. + </para> + + <para>This completely optional filtering mechanism is mainly used as an optimization for signals + which are often emitted for many different reasons: the clients can filter out which events they are + interested into before the closure's marshalling code runs. For example, this is used extensively + by the <emphasis>notify</emphasis> signal of GObject: whenever a property is modified on a GObject, + instead of just emitting the <emphasis>notify</emphasis> signal, GObject associates as a detail to this + signal emission the name of the property modified. This allows clients who wish to be notified of changes + 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 + this optional filtering. + </para> + + </sect2> + + </sect1> + </chapter> diff --git a/docs/reference/gobject/tut_gtype.xml b/docs/reference/gobject/tut_gtype.xml new file mode 100644 index 000000000..0ba06be15 --- /dev/null +++ b/docs/reference/gobject/tut_gtype.xml @@ -0,0 +1,907 @@ +<?xml version='1.0' encoding="ISO-8859-1"?> + <chapter> + <title>The Glib Dynamic Type System</title> + + <para> + A type, as manipulated by the Glib type system, is much more generic than what + is usually understood as an Object type. It is best explained by looking at the + structure and the functions used to register new types in the type system. + <programlisting> +typedef struct _GTypeInfo GTypeInfo; +struct _GTypeInfo +{ + /* interface types, classed types, instantiated types */ + guint16 class_size; + + GBaseInitFunc base_init; + GBaseFinalizeFunc base_finalize; + + /* classed types, instantiated types */ + GClassInitFunc class_init; + GClassFinalizeFunc class_finalize; + gconstpointer class_data; + + /* instantiated types */ + guint16 instance_size; + guint16 n_preallocs; + GInstanceInitFunc instance_init; + + /* value handling */ + const GTypeValueTable *value_table; +}; +GType g_type_register_static (GType parent_type, + const gchar *type_name, + const GTypeInfo *info, + GTypeFlags flags); +GType g_type_register_fundamental (GType type_id, + const gchar *type_name, + const GTypeInfo *info, + const GTypeFundamentalInfo *finfo, + GTypeFlags flags); + </programlisting> + </para> + + <para> + <function>g_type_register_static</function> and + <function>g_type_register_fundamental</function> + are the C functions, defined in + <filename>gtype.h</filename> and implemented in <filename>gtype.c</filename> + which you should use to register a new type in the program's type system. + It is not likely you will ever need to use + <function>g_type_register_fundamental</function> (you have to be Tim Janik + to do that) but in case you want to, the last chapter explains how to create + new fundamental types. + <footnote> + <para> + Please, note that there exist another registration function: the + <function>g_type_register_dynamic</function>. We will not discuss this + function here since its use is very similar to the <function>_static</function> + version. + </para> + </footnote> + </para> + + <para> + Fundamental types are top-level types which do not derive from any other type + while other non-fundamental types derive from other types. + Upon initialization by <function>g_type_init</function>, the type system not + only initializes its internal data structures but it also registers a number of core + types: some of these are fundamental types. Others are types derived from these + fundamental types. + </para> + + <para> + Fundamental and non-Fundamental types are defined by: + <itemizedlist> + <listitem><para> + class size: the class_size field in <type>GTypeInfo</type>. + </para></listitem> + <listitem><para> + class initialization functions (C++ constructor): the base_init and + class_init fields in <type>GTypeInfo</type>. + </para></listitem> + <listitem><para> + class destruction functions (C++ destructor): the base_finalize and + class_finalize fields in <type>GTypeInfo</type>. + </para></listitem> + <listitem><para> + instance size (C++ parameter to new): the instance_size field in + <type>GTypeInfo</type>. + </para></listitem> + <listitem><para> + instanciation policy (C++ type of new operator): the n_preallocs + field in <type>GTypeInfo</type>. + </para></listitem> + <listitem><para> + copy functions (C++ copy operators): the value_table field in + <type>GTypeInfo</type>. + </para></listitem> + <listitem><para> + XXX: <type>GTypeFlags</type>. + </para></listitem> + </itemizedlist> + Fundamental types are also defined by a set of <type>GTypeFundamentalFlags</type> + which are stored in a <type>GTypeFundamentalInfo</type>. + Non-Fundamental types are furthermore defined by the type of their parent which is + passed as the parent_type parameter to <function>g_type_register_static</function> + and <function>g_type_register_dynamic</function>. + </para> + + <sect1 id="gtype-copy"> + <title>Copy functions</title> + + <para> + The major common point between <emphasis>all</emphasis> glib types (fundamental and + non-fundamental, classed and non-classed, instantiable and non-instantiable) is that + they can all be manipulated through a single API to copy/assign them. + </para> + + <para> + The <type>GValue</type> structure is used as an abstract container for all of these + types. Its simplistic API (defined in <filename>gobject/gvalue.h</filename>) can be + used to invoke the value_table functions registered + during type registration: for example <function>g_value_copy</function> copies the + content of a <type>GValue</type> to another <type>GValue</type>. This is similar + to a C++ assignment which invokes the C++ copy operator to modify the default + bit-by-bit copy semantics of C++/C structures/classes. + </para> + + <para> + The following code shows shows you can copy around a 64 bit integer, as well as a <type>GObject</type> + instance pointer (sample code for this is located in the source tarball for this document in + <filename>sample/gtype/test.c</filename>): +<programlisting> +static void test_int (void) +{ + GValue a_value = {0, }; + GValue b_value = {0, }; + guint64 a, b; + + a = 0xdeadbeaf; + + g_value_init (&a_value, G_TYPE_UINT64); + g_value_set_uint64 (&a_value, a); + + g_value_init (&b_value, G_TYPE_UINT64); + g_value_copy (&a_value, &b_value); + + b = g_value_get_uint64 (&b_value); + + if (a == b) { + g_print ("Yay !! 10 lines of code to copy around a uint64.\n"); + } else { + g_print ("Are you sure this is not a Z80 ?\n"); + } +} + +static void test_object (void) +{ + GObject *obj; + GValue obj_vala = {0, }; + GValue obj_valb = {0, }; + obj = g_object_new (MAMAN_BAR_TYPE, NULL); + + g_value_init (&obj_vala, MAMAN_BAR_TYPE); + g_value_set_object (&obj_vala, obj); + + g_value_init (&obj_valb, G_TYPE_OBJECT); + + /* g_value_copy's semantics for G_TYPE_OBJECT types is to copy the reference. + This function thus calls g_object_ref. + It is interesting to note that the assignment works here because + MAMAN_BAR_TYPE is a G_TYPE_OBJECT. + */ + g_value_copy (&obj_vala, &obj_valb); + + g_object_unref (G_OBJECT (obj)); + g_object_unref (G_OBJECT (obj)); +} +</programlisting> + The important point about the above code is that the exact semantic of the copy calls + is undefined since they depend on the implementation of the copy function. Certain + copy functions might decide to allocate a new chunk of memory and then to copy the + data from the source to the destination. Others might want to simply increment + the reference count of the instance and copy the reference to the new GValue. + </para> + + <para> + The value_table used to specify these assignment functions is defined in + <filename>gtype.h</filename> and is thoroughly described in the + API documentation provided with GObject (for once ;-) which is why we will + not detail its exact semantics. + <programlisting> +typedef struct _GTypeValueTable GTypeValueTable; +struct _GTypeValueTable +{ + void (*value_init) (GValue *value); + void (*value_free) (GValue *value); + void (*value_copy) (const GValue *src_value, + GValue *dest_value); + /* varargs functionality (optional) */ + gpointer (*value_peek_pointer) (const GValue *value); + gchar *collect_format; + gchar* (*collect_value) (GValue *value, + guint n_collect_values, + GTypeCValue *collect_values, + guint collect_flags); + gchar *lcopy_format; + gchar* (*lcopy_value) (const GValue *value, + guint n_collect_values, + GTypeCValue *collect_values, + guint collect_flags); +}; + </programlisting> + Interestingly, it is also very unlikely + you will ever need to specify a value_table during type registration + because these value_tables are inherited from the parent types for + non-fundamental types which means that unless you want to write a + fundamental type (not a great idea !), you will not need to provide + a new value_table since you will inherit the value_table structure + from your parent type. + </para> + </sect1> + + <sect1 id="gtype-conventions"> + <title>Conventions</title> + + + <para> + There are a number of conventions users are expected to follow when creating new types + which are to be exported in a header file: + <itemizedlist> + <listitem><para> + Use the <function>object_method</function> pattern for function names: to invoke + the method named foo on an instance of object type bar, call + <function>bar_foo</function>. + </para></listitem> + <listitem><para>Use prefixing to avoid namespace conflicts with other projects. + If your library (or application) is named <emphasis>Maman</emphasis>, + prefix all your function names with <emphasis>maman_</emphasis>. + For example: <function>maman_object_method</function>. + </para></listitem> + <listitem><para>Create a macro named <function>PREFIX_OBJECT_TYPE</function> which always + returns the Gtype for the associated object type. For an object of type + <emphasis>Bar</emphasis> in a libray prefixed by <emphasis>maman</emphasis>, + use: <function>MAMAN_BAR_TYPE</function>. + It is common although not a convention to implement this macro using either a global + static variable or a function named <function>prefix_object_get_type</function>. + We will follow the function pattern wherever possible in this document. + </para></listitem> + <listitem><para>Create a macro named <function>PREFIX_OBJECT (obj)</function> which + returns a pointer of type <type>PrefixObject</type>. This macro is used to enforce + static type safety by doing explicit casts wherever needed. It also enforces + dynamic type safety by doing runtime checks. It is expected that in production + builds, the dynamic type checks are disabled: they should be used only in + development environments. For example, we would create + <function>MAMAN_BAR (obj)</function> to keep the previous example. + </para></listitem> + <listitem><para>If the type is classed, create a macro named + <function>PREFIX_OBJECT_CLASS (klass)</function>. This macro + is strictly equivalent to the previous casting macro: it does static casting with + dynamic type checking of class structures. It is expected to return a pointer + to a class structure of type <type>PrefixObjectClass</type>. Again, an example is: + <function>MAMAN_BAR_CLASS</function>.</para></listitem> + <listitem><para>Create a macro named <function>PREFIX_IS_BAR (obj)</function>: this macro is expected + to return a <type>gboolean</type> which indicates whether or not the input + object instance pointer of type BAR.</para></listitem> + <listitem><para>If the type is classed, create a macro named + <function>PREFIX_IS_OBJECT_CLASS (klass)</function> which, as above, returns a boolean + if the input class pointer is a pointer to a class of type OBJECT. + </para></listitem> + <listitem><para>If the type is classed, create a macro named + <function>PREFIX_OBJECT_GET_CLASS (obj)</function> + which returns the class pointer associated to an instance of a given type. This macro + is used for static and dynamic type safety purposes (just like the previous casting + macros).</para></listitem> + </itemizedlist> + The implementation of these macros is pretty straightforward: a number of simple-to-use + macros are provided in <filename>gtype.h</filename>. For the example we used above, we would + write the following trivial code to declare the macros: +<programlisting> +#define MAMAN_BAR_TYPE (maman_bar_get_type ()) +#define MAMAN_BAR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MAMAN_BAR_TYPE, MamanBar)) +#define MAMAN_BAR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MAMAN_BAR_TYPE, MamanBarClass)) +#define MAMAN_IS_BAR(obj) (G_TYPE_CHECK_TYPE ((obj), MAMAN_BAR_TYPE)) +#define MAMAN_IS_BAR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MAMAN_BAR_TYPE)) +#define MAMAN_BAR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MAMAN_BAR_TYPE, MamanBarClass)) +</programlisting> + </para> + + <para> + The following code shows how to implement the <function>maman_bar_get_type</function> + function: +<programlisting> +GType maman_bar_get_type (void) +{ + static GType type = 0; + if (type == 0) { + static const GTypeInfo info = { + /* You fill this structure. */ + }; + type = g_type_register_static (G_TYPE_OBJECT, + "MamanBarType", + &info, 0); + } + return type; +} +</programlisting> + </para> + + </sect1> + + <sect1 id="gtype-non-instantiable"> + <title>Non-Instantiable non-classed fundamental types</title> + + <para> + A lot of types are not instantiable by the type system and do not have + a class. Most of these types are fundamental trivial types such as <emphasis>gchar</emphasis>, + registered in <function>g_value_types_init</function> (in <filename>gvaluetypes.c</filename>). + </para> + + <para> + To register such a type in the type system, you just need to fill the + <type>GTypeInfo</type> structure with zeros since these types are also most of the time + fundamental: + <programlisting> + GTypeInfo info = { + 0, /* class_size */ + NULL, /* base_init */ + NULL, /* base_destroy */ + NULL, /* class_init */ + NULL, /* class_destroy */ + NULL, /* class_data */ + 0, /* instance_size */ + 0, /* n_preallocs */ + NULL, /* instance_init */ + NULL, /* value_table */ + }; + static const GTypeValueTable value_table = { + value_init_long0, /* value_init */ + NULL, /* value_free */ + value_copy_long0, /* value_copy */ + NULL, /* value_peek_pointer */ + "i", /* collect_format */ + value_collect_int, /* collect_value */ + "p", /* lcopy_format */ + value_lcopy_char, /* lcopy_value */ + }; + info.value_table = &value_table; + type = g_type_register_fundamental (G_TYPE_CHAR, "gchar", &info, &finfo, 0); + </programlisting> + </para> + + + <para> + Having non-instantiable types might seem a bit useless: what good is a type + if you cannot instanciate an instance of that type ? Most of these types + are used in conjunction with <type>GValue</type>s: a GValue is initialized + with an integer or a string and it is passed around by using the registered + type's value_table. <type>GValue</type>s (and by extension these trivial fundamental + types) are most useful when used in conjunction with object properties and signals. + </para> + + </sect1> + + <sect1 id="gtype-instantiable-classed"> + <title>Instantiable classed types: objects</title> + + <para> + Types which are registered with a class and are declared instantiable are + what most closely resembles an <emphasis>object</emphasis>. The code below + shows how you could register such a type in the type system: +<programlisting> +typedef struct { + Object parent; + /* instance members */ + int field_a; +} MamanBar; + +struct _MamanBarClass { + GObjectClass parent; + /* class members */ + void (*do_action_public_virtual) (MamanBar *self, guint8 i); + + void (*do_action_public_pure_virtual) (MamanBar *self, guint8 i); +}; + +#define MAMAN_BAR_TYPE (maman_bar_get_type ()) + +GType +maman_bar_get_type (void) +{ + static GType type = 0; + if (type == 0) { + static const GTypeInfo info = { + sizeof (MamanBarClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc) foo_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (MamanBar), + 0, /* n_preallocs */ + (GInstanceInitFunc) NULL /* instance_init */ + }; + type = g_type_register_fundamental (G_TYPE_OBJECT, + "BarType", + &info, 0); + } + return type; +} +</programlisting> + Upon the first call to <function>maman_bar_get_type</function>, the type named + <emphasis>BarType</emphasis> will be registered in the type system as inheriting + from the type <emphasis>G_TYPE_OBJECT</emphasis>. + </para> + + <para> + Every object must define two structures: its class structure and its + instance structure. All class structures must contain as first member + a <type>GTypeClass</type> structure. All instance structures must contain as first + member a <type>GTypeInstance</type> structure. The declaration of these C types, + coming from <filename>gtype.h</filename> is shown below: +<programlisting> +struct _GTypeClass +{ + GType g_type; +}; +struct _GTypeInstance +{ + GTypeClass *g_class; +}; +</programlisting> + These constraints allow the type system to make sure that every object instance + (identified by a pointer to the object's instance structure) contains in its + first bytes a pointer to the object's class structure. + </para> + <para> + This relationship is best explained by an example: let's take object B which + inherits from object A: +<programlisting> +/* A definitions */ +typedef struct { + GTypeInstance parent; + int field_a; + int field_b; +} A; +typedef struct { + GTypeClass parent_class; + void (*method_a) (void); + void (*method_b) (void); +} AClass; + +/* B definitions. */ +typedef struct { + A parent; + int field_c; + int field_d; +} B; +typedef struct { + AClass parent_class; + void (*method_c) (void); + void (*method_d) (void); +} BClass; +</programlisting> + The C standard mandates that the first field of a C structure is stored starting + in the first byte of the buffer used to hold the structure's fields in memory. + This means that the first field of an instance of an object B is A's first field + which in turn is GTypeInstance's first field which in turn is g_class, a pointer + to B's class structure. + </para> + + <para> + Thanks to these simple conditions, it is possible to detect the type of every + object instance by doing: +<programlisting> +B *b; +b->parent.parent_class->g_class.g_type +</programlisting> + or, more quickly: +<programlisting> +B *b; +((GTypeInstance*)b)->g_class.g_type +</programlisting> + </para> + + <para> + Instanciation of these types can be done with <function>g_type_create_instance</function>: +<programlisting> +GTypeInstance* g_type_create_instance (GType type); +void g_type_free_instance (GTypeInstance *instance); +</programlisting> + <function>g_type_create_instance</function> will lookup the type information + structure associated to the type requested. Then, the instance size and instanciation + policy (if the n_preallocs field is set to a non-zero value, the type system allocates + the object's instance structures in chunks rather than mallocing for every instance) + declared by the user are used to get a buffer to hold the object's instance + structure. + </para> + + <para> + If this is the first instance of the object ever created, the type system must create + a class structure: it allocates a buffer to hold the object's class structure and + initializes it. It first copies the parent's class structure over this structure + (if there is no parent, it initializes it to zero). It then invokes the + base_class_initialization functions (<type>GBaseInitFunc</type>) from topmost + fundamental object to bottom-most most derived object. The object's class_init + (<type>GClassInitFunc</type>) function is invoked afterwards to complete + initialization of the class structure. + Finally, the object's interfaces are initialized (we will discuss interface initialization + in more detail later). +<footnote id="class-init"> +<para> +The class initialization process is entirely implemented in +<function>type_class_init_Wm</function> in <filename>gtype.c</filename>. +</para> +</footnote> + </para> + + <para> + Once the type system has a pointer to an initialized class structure, it sets the object's + instance class pointer to the object's class structure and invokes the object's + instance_init (<type>GInstanceInitFunc</type>)functions, from top-most fundamental + type to bottom-most most derived type. + </para> + + <para> + Object instance destruction through <function>g_type_free_instance</function> is very simple: + the instance structure is returned to the instance pool if there is one and if this was the + last living instance of the object, the class is destroyed. + </para> + + <para> + Class destruction (called finalization in Gtype) is the symmetric process of the initialization: + it is implemented in <function>type_data_finalize_class_U</function> (in <filename>gtype.c + </filename>, as usual...). Interfaces are first destroyed. Then, the most derived + class_finalize (<type>ClassFinalizeFunc</type>) function is invoked. The + base_class_finalize (<type>GBaseFinalizeFunc</type>) functions are + Finally invoked from bottom-most most-derived type to top-most fundamental type and + the class structure is freed. + </para> + + <para> + As many readers have now understood it, the base initialization/finalization process is + very similar to the C++ Constructor/Destructor paradigm. However, it is very different + in that, in C++, class constructors are automatically edited at compile + time by the compiler to ensure that classes are correctly initialized before + running the user-provided constructor code itself. With GObject, users must provide both + the class and instance initialization functions. + Similarly, GTypes have no instance destruction mechanism. It is + the user's responsibility to implement correct destruction semantics on top + of the existing GType code. (this is what GObject does. See + <xref linkend="chapter-gobject"></xref>) + </para> + + <para> + The instanciation/finalization process can be summarized as follows: + <table> + <title>GType Instantiation/Finalization</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> + </row> + </thead> + <tbody> + <row> + <entry>First call to <function>g_type_create_instance</function> for target type</entry> + <entry>type's base_init 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> + </row> + <row> + <entry>First call to <function>g_type_create_instance</function> for target type</entry> + <entry>target type's class_init function</entry> + <entry>On target type's class structure</entry> + </row> + <row> + <entry>First call to <function>g_type_create_instance</function> for target type</entry> + <entry colspan="2">interface initialization, see + <xref linkend="gtype-non-instantiable-classed-init"></xref></entry> + </row> + <row> + <entry>Each call to <function>g_type_create_instance</function> for target type</entry> + <entry>target type's instance_init function</entry> + <entry>On object's instance</entry> + </row> + <row> + <entry>Last call to <function>g_type_free_instance</function> for target type</entry> + <entry colspan="2">interface destruction, see + <xref linkend="gtype-non-instantiable-classed-dest"></xref></entry> + <entry></entry> + </row> + <row> + <entry>Last call to <function>g_type_free_instance</function> for target type</entry> + <entry>target type's class_finalize function</entry> + <entry>On target type's class structure</entry> + </row> + <row> + <entry>Last call to <function>g_type_free_instance</function> for 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> + </row> + </tbody> + </tgroup> + </table> + </para> + + </sect1> + + <sect1 id="gtype-non-instantiable-classed"> + <title>Non-instantiable classed types: Interfaces.</title> + + <para> + GType's Interfaces are very similar to Java's interfaces. To declare one of these + you have to register a non-instantiable classed type which derives from + GTypeInterface. The following piece of code declares such an interface. +<programlisting> +#define MAMAN_IBAZ_TYPE (maman_ibaz_get_type ()) +#define MAMAN_IBAZ(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MAMAN_IBAZ_TYPE, MamanIbaz)) +#define MAMAN_IBAZ_CLASS(vtable) (G_TYPE_CHECK_CLASS_CAST ((vtable), MAMAN_IBAZ_TYPE, MamanIbazClass)) +#define MAMAN_IS_IBAZ(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MAMAN_IBAZ_TYPE)) +#define MAMAN_IS_IBAZ_CLASS(vtable) (G_TYPE_CHECK_CLASS_TYPE ((vtable), MAMAN_IBAZ_TYPE)) +#define MAMAN_IBAZ_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), MAMAN_IBAZ_TYPE, MamanIbazClass)) + +typedef struct _MamanIbaz MamanIbaz; /* dummy object */ +typedef struct _MamanIbazClass MamanIbazClass; + +struct _MamanIbazClass { + GTypeInterface parent; + + void (*do_action) (MamanIbaz *self); +}; + +GType maman_ibaz_get_type (void); + +void maman_ibaz_do_action (MamanIbaz *self); +</programlisting> + The interface function, <function>maman_ibaz_do_action</function> is implemented + in a pretty simple way: +<programlisting> +void maman_ibaz_do_action (MamanIbaz *self) +{ + MAMAN_IBAZ_GET_CLASS (self)->do_action (self); +} +</programlisting> + <function>maman_ibaz_get_gtype</function> registers a type named <emphasis>MamanIBaz</emphasis> + which inherits from G_TYPE_INTERFACE. All interfaces must be children of G_TYPE_INTERFACE in the + inheritance tree. + </para> + + <para> + An interface is defined by only one structure which must contain as first member + a <type>GTypeInterface</type> structure. The interface structure is expected to + contain the function pointers of the interface methods. It is good style to + define helper functions for each of the interface methods which simply call + the interface' method directly: <function>maman_ibaz_do_action</function> + is one of these. + </para> + + <para> + Once an interface type is registered, you must register implementations for these + interfaces. The function named <function>maman_baz_get_type</function> registers + a new GType named MamanBaz which inherits from <type>GObject</type> and which + implements the interface <type>MamanIBaz</type>. +<programlisting> +static void maman_baz_do_action (MamanIbaz *self) +{ + g_print ("Baz implementation of IBaz interface Action.\n"); +} + + +static void +baz_interface_init (gpointer g_iface, + gpointer iface_data) +{ + MamanIbazClass *klass = (MamanIbazClass *)g_iface; + klass->do_action = maman_baz_do_action; +} + +GType +maman_baz_get_type (void) +{ + static GType type = 0; + if (type == 0) { + static const GTypeInfo info = { + sizeof (MamanBazClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + NULL, /* class_init */ + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (MamanBaz), + 0, /* n_preallocs */ + NULL /* instance_init */ + }; + static const GInterfaceInfo ibaz_info = { + (GInterfaceInitFunc) baz_interface_init, /* interface_init */ + NULL, /* interface_finalize */ + NULL /* interface_data */ + }; + type = g_type_register_static (G_TYPE_OBJECT, + "MamanBazType", + &info, 0); + g_type_add_interface_static (type, + MAMAN_IBAZ_TYPE, + &ibaz_info); + } + return type; +} +</programlisting> + </para> + + <para> + <function>g_type_add_interface_static</function> records in the type system that + a given type implements also <type>FooInterface</type> + (<function>foo_interface_get_type</function> returns the type of + <type>FooInterface</type>). The <type>GInterfaceInfo</type> structure holds + information about the implementation of the interface: +<programlisting> +struct _GInterfaceInfo +{ + GInterfaceInitFunc interface_init; + GInterfaceFinalizeFunc interface_finalize; + gpointer interface_data; +}; +</programlisting> + </para> + + <sect2 id="gtype-non-instantiable-classed-init"> + <title>Interface Initialization</title> + + <para> + When an instantiable classed type which registered an interface implementation + is created for the first time, its class structure is initialized following the process + described in <xref linkend="gtype-instantiable-classed"></xref>. Once the class structure is + initialized,the function <function>type_class_init_Wm</function> (implemented in <filename> + gtype.c</filename>) initializes the interface implementations associated with + that type by calling <function>type_iface_vtable_init_Wm</function> for each + interface. + </para> + + <para> + First a memory buffer is allocated to hold the interface structure. The parent's + interface structure is then copied over to the new interface structure (the parent + interface is already initialized at that point). If there is no parent interface, + the interface structure is initialized with zeros. The g_type and the g_instance_type + fields are then initialized: g_type is set to the type of the most-derived interface + and g_instance_type is set to the type of the most derived type which implements + this interface. + </para> + + <para> + Finally, the interface' most-derived <function>base_init</function> function and then + the implementation's <function>interface_init</function> + function are invoked. It is important to understand that if there are multiple + implementations of an interface the <function>base_init</function> and + <function>interface_init</function> functions will be + invoked once for each implementation initialized. + </para> + + <para> + It is thus common for base_init functions to hold a local static boolean variable + which makes sure that the interface type is initialized only once even if there are + multiple implementations of the interface: +<programlisting> +static void +maman_ibaz_base_init (gpointer g_class) +{ + static gboolean initialized = FALSE; + + if (!initialized) { + /* create interface signals here. */ + initialized = TRUE; + } +} +</programlisting> + </para> + + <para> + If you have found the stuff about interface hairy, you are right: it is hairy but + there is not much I can do about it. What I can do is summarize what you need to know + about interfaces: + </para> + + <para> + The above process can be summarized as follows: + <table> + <title><function>Interface Initialization</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>First call to <function>g_type_create_instance</function> for type + implementing interface</entry> + <entry>interface' base_init function</entry> + <entry>On interface' vtable</entry> + <entry>Register interface' signals here (use a local static + boolean variable as described above to make sure not to register them + twice.).</entry> + </row> + <row> + <entry>First call to <function>g_type_create_instance</function> for type + implementing interface</entry> + <entry>interface' interface_init function</entry> + <entry>On interface' vtable</entry> + <entry> + Initialize interface' implementation. That is, initialize the interface + method pointers in the interface structure to the function's implementation. + </entry> + </row> + </tbody> + </tgroup> + </table> + It is highly unlikely (ie: I do not know of <emphasis>anyone</emphasis> who actually + used it) you will ever need other more fancy things such as the ones described in the + following section (<xref linkend="gtype-non-instantiable-classed-dest"></xref>). + </para> + + </sect2> + + <sect2 id="gtype-non-instantiable-classed-dest"> + <title>Interface Destruction</title> + + <para> + When the last instance of an instantiable type which registered an interface implementation + is destroyed, the interface's implementations associated to the type are destroyed by + <function>type_iface_vtable_finalize_Wm</function> (in <filename>gtype.c</filename>). + </para> + + <para> + <function>type_iface_vtable_finalize_Wm</function> invokes first the implementation's + <function>interface_finalize</function> function and then the interface's most-derived + <function>base_finalize</function> function. + </para> + + <para> + Again, it is important to understand, as in + <xref linkend="gtype-non-instantiable-classed-init"></xref>, + that both <function>interface_finalize</function> and <function>base_finalize</function> + are invoked exactly once for the destruction of each implementation of an interface. Thus, + if you were to use one of these functions, you would need to use a static integer variable + which would hold the number of instances of implementations of an interface such that + the interface's class is destroyed only once (when the integer variable reaches zero). + </para> + + <para> + The above process can be summarized as follows: + <table> + <title><function>Interface Finalization</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> + </row> + </thead> + <tbody> + <row> + <entry>Last call to <function>g_type_free_instance</function> for type + implementing interface</entry> + <entry>interface' interface_finalize function</entry> + <entry>On interface' vtable</entry> + </row> + <row> + <entry>Last call to <function>g_type_free_instance</function>for type + implementing interface</entry> + <entry>interface' base_finalize function</entry> + <entry>On interface' vtable</entry> + </row> + </tbody> + </tgroup> + </table> + </para> + + <para> + Now that you have read this section, you can forget about it. Please, forget it + <emphasis>as soon as possible</emphasis>. + </para> + + </sect2> + + </sect1> + + </chapter> diff --git a/docs/reference/gobject/tut_howto.xml b/docs/reference/gobject/tut_howto.xml new file mode 100644 index 000000000..3c465cac8 --- /dev/null +++ b/docs/reference/gobject/tut_howto.xml @@ -0,0 +1,1452 @@ +<chapter id="howto"> + <title>How To ?</title> + + <para> + This chapter tries to answer the real-life questions of users and presents + the most common scenario use-cases I could come up with. + The use-cases are presented from most likely to less likely. + </para> + +<!-- + Howto GObject +--> + + <sect1 id="howto-gobject"> + <title>How To define and implement a new GObject ?</title> + + <para> + Clearly, this is one of the most common question people ask: they just want to crank code and + implement a subclass of a GObject. Sometimes because they want to create their own class hierarchy, + sometimes because they want to subclass one of GTK+'s widget. This chapter will focus on the + implementation of a subtype of GObject. The sample source code + associated to this section can be found in the documentation's source tarball, in the + <filename>sample/gobject</filename> directory: + <itemizedlist> + <listitem><para><filename>maman-bar.{h|c}</filename>: this is the source for a object which derives from + <type>GObject</type> and which shows how to declare different types of methods on the object. + </para></listitem> + <listitem><para><filename>maman-subbar.{h|c}</filename>: this is the source for a object which derives from + <type>MamanBar</type> and which shows how to override some of its parent's methods. + </para></listitem> + <listitem><para><filename>maman-foo.{h|c}</filename>: this is the source for an object which derives from + <type>GObject</type> and which declares a signal. + </para></listitem> + <listitem><para><filename>test.c</filename>: this is the main source which instantiates an instance of + type and exercises their API. + </para></listitem> + </itemizedlist> + </para> + + <sect2 id="howto-gobject-header"> + <title>Boilerplate header code</title> + + <para> + The first step before writing the code for your GObject is to write the type's header which contains + the needed type, function and macro definitions. Each of these elements is nothing but a convention + which is followed not only by GTK+'s code but also by most users of GObject. If you feel the need + not to obey the rules stated below, think about it twice: + <itemizedlist> + <listitem><para>If your users are a bit accustomed to GTK+ code or any Glib code, they will + be a bit surprised and getting used to the conventions you decided upon will take time (money) and + will make them grumpy (not a good thing) + </para></listitem> + <listitem><para> + You must assess the fact that these conventions might have been designed by both smart + and experienced people: maybe they were at least partly right. Try to put your ego aside. + </para></listitem> + </itemizedlist> + </para> + + <para> + Pick a name convention for your headers and source code and stick to it: + <itemizedlist> + <listitem><para> + use a dash to separate the prefix from the typename: <filename>maman-bar.h</filename> and + <filename>maman-bar.c</filename> (this is the convention used by Nautilus and most Gnome libraries). + </para></listitem> + <listitem><para> + use an underscore to separate the prefix from the typename: <filename>maman_bar.h</filename> and + <filename>maman_bar.c</filename>. + </para></listitem> + <listitem><para> + Do not separate the prefix from the typename: <filename>mamanbar.h</filename> and + <filename>mamanbar.c</filename>. (this is the convention used by GTK+) + </para></listitem> + </itemizedlist> + I personally like the first solution better: it makes reading file names easier for those with poor + eyesight like me. + </para> + + <para> + The basic conventions for any header which exposes a GType are described in + <xref linkend="gtype-conventions"/>. Most GObject-based code also obeys onf of the following + conventions: pick one and stick to it. + <itemizedlist> + <listitem><para> + If you want to declare a type named bar with prefix maman, name the type instance + <function>MamanBar</function> and its class <function>MamanBarClass</function> + (name is case-sensitive). It is customary to declare them with code similar to the + following: +<programlisting> +/* + * Copyright/Licensing information. + */ + +#ifndef MAMAN_BAR_H +#define MAMAN_BAR_H + +/* + * Potentially, include other headers on which this header depends. + */ + + +/* + * Type macros. + */ + +typedef struct _MamanBar MamanBar; +typedef struct _MamanBarClass MamanBarClass; + +struct _MamanBar { + GObject parent; + /* instance members */ +}; + +struct _MamanBarClass { + GObjectClass parent; + /* class members */ +}; + +/* used by MAMAN_BAR_TYPE */ +GType maman_bar_get_type (void); + +/* + * Method definitions. + */ + +#endif +</programlisting> + </para></listitem> + <listitem><para> + Most GTK+ types declare their private fields in the public header with a /* private */ comment, + relying on their user's intelligence not to try to play with these fields. Fields not marked private + are considered public by default. The /* protected */ comment (same semantics as those of C++) + is also used, mainly in the GType library, in code written by Tim Janik. +<programlisting> +struct _MamanBar { + GObject parent; + + /* private */ + int hsize; +}; +</programlisting> + </para></listitem> + <listitem><para> + All of Nautilus code and a lot of Gnome libraries use private indirection members, as described + by Herb Sutter in his Pimpl articles (see <ulink></ulink>: Herb summarizes the different + issues better than I will): +<programlisting> +typedef struct _MamanBarPrivate MamanBarPrivate; +struct _MamanBar { + GObject parent; + + /* private */ + MamanBarPrivate *priv; +}; +</programlisting> + The private structure is then defined in the .c file, instantiated in the object's XXX + function and destroyed in the object's XXX function. + </para></listitem> + </itemizedlist> + </para> + + <para> + Finally, there are different header include conventions. Again, pick one and stick to it. I personally + use indifferently any of the two, depending on the codebase I work on: the rule is consistency. + <itemizedlist> + <listitem><para> + Some people add at the top of their headers a number of #include directives to pull in + all the headers needed to compile client code. This allows client code to simply + #include "maman-bar.h". + </para></listitem> + <listitem><para> + Other do not #include anything and expect the client to #include themselves the headers + they need before including your header. This speeds up compilation because it minimizes the + amount of pre-processor work. This can be used in conjunction with the re-declaration of certain + unused types in the client code to minimize compile-time dependencies and thus speed up + compilation. + </para></listitem> + </itemizedlist> + </para> + + </sect2> + + <sect2 id="howto-gobject-code"> + <title>Boilerplate code</title> + + <para> + In your code, the first step is to #include the needed headers: depending on your header include strategy, this + can be as simple as #include "maman-bar.h" or as complicated as tens of #include lines ending with + #include "maman-bar.h": +<programlisting> +/* + * Copyright information + */ + +#include "maman-bar.h" + +/* If you use Pimpls, include the private structure + * definition here. Some people create a maman-bar-private.h header + * which is included by the maman-bar.c file and which contains the + * definition for this private structure. + */ +struct _MamanBarPrivate { + int member_1; + /* stuff */ +}; + +/* + * forward definitions + */ +</programlisting> + </para> + + <para> + Implement <function>maman_bar_get_type</function> and make sure the code compiles: +<programlisting> +GType +maman_bar_get_type (void) +{ + static GType type = 0; + if (type == 0) { + static const GTypeInfo info = { + sizeof (MamanBarClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + NULL, /* class_init */ + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (MamanBar), + 0, /* n_preallocs */ + NULL /* instance_init */ + }; + type = g_type_register_static (G_TYPE_OBJECT, + "MamanBarType", + &info, 0); + } + return type; +} +</programlisting> + </para> + </sect2> + + <sect2 id="howto-gobject-construction"> + <title>Object Construction</title> + + <para> + People often get confused when trying to construct their GObjects because of the + sheer number of different ways to hook into the objects's construction process: it is + difficult to figure which is the <emphasis>correct</emphasis>, recommended way. + </para> + + <para> + <xref linkend="gobject-construction-table"/> shows what user-provided functions + are invoked during object instanciation and in which order they are invoked. + A user looking for the equivalent of the simple C++ constructor function should use + the instance_init method. It will be invoked after all the parent's instance_init + functions have been invoked. It cannot take arbitrary construction parameters + (as in C++) but if your object needs arbitrary parameters to complete initialization, + you can use construction properties. + </para> + + <para> + Construction properties will be set only after all instance_init functions have run. + No object reference will be returned to the client of <function>g_object_new></function> + until all the construction properties have been set. + </para> + + <para> + As such, I would recommend writing the following code first: +<programlisting> +static void +maman_bar_init (GTypeInstance *instance, + gpointer g_class) +{ + MamanBar *self = (MamanBar *)instance; + self->private = g_new0 (MamanBarPrivate, 1); + + /* initialize all public and private members to reasonable default values. */ + /* If you need specific consruction properties to complete initialization, + * delay initialization completion until the property is set. + */ +} +</programlisting> + And make sure that you set <function>maman_bar_init</function> as the type's instance_init function + in <function>maman_bar_get_type</function>. Make sure the code builds and runs: create an instance + of the object and make sure <function>maman_bar_init</function> is called (add a + <function>g_print</function> call in it). + </para> + + <para> + Now, if you need special construction properties, install the properties in the class_init function, + override the set and get methods and implement the get and set methods as described in + <xref linkend="gobject-properties"/>. Make sure that these properties use a construct only + pspec by setting the param spec's flag field to G_PARAM_CONSTRUCT_ONLY: this helps + GType ensure that these properties are not set again later by malicious user code. +<programlisting> +static void +bar_class_init (MamanBarClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GParamSpec *maman_param_spec; + + gobject_class->set_property = bar_set_property; + gobject_class->get_property = bar_get_property; + + maman_param_spec = g_param_spec_string ("maman", + "Maman construct prop", + "Set maman's name", + "no-name-set" /* default value */, + G_PARAM_CONSTRUCT_ONLY |G_PARAM_READWRITE); + + g_object_class_install_property (gobject_class, + PROP_MAMAN, + maman_param_spec); +} +</programlisting> + If you need this, make sure you can build and run code similar to the code shown above. Make sure + your construct properties can set correctly during construction, make sure you cannot set them + afterwards and make sure that if your users do not call <function>g_object_new</function> + with the required construction properties, these will be initialized with the default values. + </para> + + <para> + I consider good taste to halt program execution if a construction property is set its + default value. This allows you to catch client code which does not give a reasonable + value to the construction properties. Of course, you are free to disagree but you + should have a good reason to do so. + </para> + + <para>Some people sometimes need to construct their object but only after the construction properties + have been set. This is possible through the use of the constructor class method as described in + <xref linkend="gobject-instanciation"/>. However, I have yet to see <emphasis>any</emphasis> reasonable + use of this feature. As such, to initialize your object instances, use by default the base_init function + and construction properties. + </para> + </sect2> + + <sect2 id="howto-gobject-destruction"> + <title>Object Destruction</title> + + <para> + Again, it is often difficult to figure out which mechanism to use to hook into the object's + destruction process: when the last <function>g_object_unref</function> function call is made, + a lot of things happen as described in <xref linkend="gobject-destruction-table"/>. + </para> + + <para> + The destruction process of your object must be split is two different phases: you must override + both the dispose and the finalize class methods. +<programlisting> +struct _MamanBarPrivate { + gboolean dispose_has_run; +}; + +static void +bar_dispose (MamanBar *self) +{ + if (self->private->dispose_has_run) { + /* If dispose did already run, return. */ + return; + } + /* Make sure dispose does not run twice. */ + object->private->dispose_has_run = TRUE; + + /* + * In dispose, you are supposed to free all types referenced from this + * object which might themselves hold a reference to self. Generally, + * the most simple solution is to unref all members on which you own a + * reference. + */ +} + +static void +bar_finalize (MamanBar *self) +{ + /* + * Here, complete object destruction. + * You might not need to do much... + */ + g_free (self->private); +} + +static void +bar_class_init (BarClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->dispose = bar_dispose; + gobject_class->finalize = bar_finalize; +} + +static void +maman_bar_init (GTypeInstance *instance, + gpointer g_class) +{ + MamanBar *self = (MamanBar *)instance; + self->private = g_new0 (MamanBarPrivate, 1); + self->private->dispose_has_run = FALSE; +} +</programlisting> + </para> + + <para> + Add similar code to your GObject, make sure the code still builds and runs: dispose and finalize must be called + during the last unref. + It is possible that object methods might be invoked after dispose is run and before finalize runs. GObject + does not consider this to be a program error: you must gracefully detect this and neither crash nor warn + the user. To do this, you need something like the following code at the start of each object method, to make + sure the object's data is still valid before manipulating it: +<programlisting> +if (self->private->dispose_has_run) { + /* Dispose has run. Data is not valid anymore. */ + return; +} +</programlisting> + </para> + </sect2> + + <sect2 id="howto-gobject-methods"> + <title>Object methods</title> + + <para> + Just as with C++, there are many different ways to define object + methods and extend them: the following list and sections draw on C++ vocabulary. + (Readers are expected to know basic C++ buzzwords. Those who have not had to + write C++ code recently can refer to <ulink>XXXX</ulink> to refresh their + memories.) + <itemizedlist> + <listitem><para> + non-virtual public methods, + </para></listitem> + <listitem><para> + virtual public methods and + </para></listitem> + <listitem><para> + virtual private methods + </para></listitem> + </itemizedlist> + </para> + + <sect3> + <title>non-virtual public methods</title> + + <para> + These are the simplest: you want to provide a simple method which can act on your object. All you need + to do is to provide a function prototype in the header and an implementation of that prototype + in the source file. +<programlisting> +/* declaration in the header. */ +void maman_bar_do_action (MamanBar *self, /* parameters */); +/* implementation in the source file */ +void maman_bar_do_action (MamanBar *self, /* parameters */) +{ + /* do stuff here. */ +} +</programlisting> + </para> + + <para>There is really nothing scary about this.</para> + </sect3> + + <sect3> + <title>Virtual Public methods</title> + + <para> + This is the preferred way to create polymorphic GObjects. All you need to do is to + define the common method and its class function in the public header, implement the + common method in the source file and re-implement the class function in each object + which inherits from you. +<programlisting> +/* declaration in maman-bar.h. */ +struct _MamanBarClass { + GObjectClass parent; + + /* stuff */ + void (*do_action) (MamanBar *self, /* parameters */); +}; +void maman_bar_do_action (MamanBar *self, /* parameters */); +/* implementation in maman-bar.c */ +void maman_bar_do_action (MamanBar *self, /* parameters */) +{ + MAMAN_BAR_GET_CLASS (self)->do_action (self, /* parameters */); +} +</programlisting> + The code above simply redirects the do_action call to the relevant class function. Some users, + concerned about performance, do not provide the <function>maman_bar_do_action</function> + wrapper function and require users to de-reference the class pointer themselves. This is not such + a great idea in terms of encapsulation and makes it difficult to change the object's implementation + afterwards, should this be needed. + </para> + + <para> + Other users, also concerned by performance issues, declare the <function>maman_bar_do_action</function> + function inline in the header file. This, however, makes it difficult to change the + object's implementation later (although easier than requiring users to directly de-reference the class + function) and is often difficult to write in a portable way (the <emphasis>inline</emphasis> keyword + is not part of the C standard). + </para> + + <para> + In doubt, unless a user shows you hard numbers about the performance cost of the function call, + just <function>maman_bar_do_action</function> in the source file. + </para> + + <para> + Please, note that it is possible for you to provide a default implementation for this class method in + the object's class_init function: initialize the klass->do_action field to a pointer to the actual + implementation. You can also make this class method pure virtual by initializing the klass->do_action + field to NULL: +<programlisting> +static void +maman_bar_real_do_action_two (MamanBar *self, /* parameters */) +{ + /* Default implementation for the virtual method. */ +} + +static void +maman_bar_class_init (BarClass *klass) +{ + /* pure virtual method: mandates implementation in children. */ + klass->do_action_one = NULL; + /* merely virtual method. */ + klass->do_action_two = maman_bar_real_do_action_two; +} + +void maman_bar_do_action_one (MamanBar *self, /* parameters */) +{ + MAMAN_BAR_GET_CLASS (self)->do_action_one (self, /* parameters */); +} +void maman_bar_do_action_two (MamanBar *self, /* parameters */) +{ + MAMAN_BAR_GET_CLASS (self)->do_action_two (self, /* parameters */); +} +</programlisting> + </para> + </sect3> + + <sect3> + <title>Virtual Private Methods</title> + + <para> + These are very similar to Virtual Public methods. They just don't have a public function to call the + function directly. The header file contains only a declaration of the class function: +<programlisting> +/* declaration in maman-bar.h. */ +struct _MamanBarClass { + GObjectClass parent; + + /* stuff */ + void (*helper_do_specific_action) (MamanBar *self, /* parameters */); +}; +void maman_bar_do_any_action (MamanBar *self, /* parameters */); +</programlisting> + These class functions are often used to delegate part of the job to child classes: +<programlisting> +/* this accessor function is static: it is not exported outside of this file. */ +static void +maman_bar_do_specific_action (MamanBar *self, /* parameters */) +{ + MAMAN_BAR_GET_CLASS (self)->do_specific_action (self, /* parameters */); +} + +void maman_bar_do_any_action (MamanBar *self, /* parameters */) +{ + /* random code here */ + + /* + * Try to execute the requested action. Maybe the requested action cannot be implemented + * here. So, we delegate its implementation to the child class: + */ + maman_bar_do_specific_action (self, /* parameters */); + + /* other random code here */ +} +</programlisting> + </para> + + <para> + Again, it is possible to provide a default implementation for this private virtual class function: +<programlisting> +static void +maman_bar_class_init (MamanBarClass *klass) +{ + /* pure virtual method: mandates implementation in children. */ + klass->do_specific_action_one = NULL; + /* merely virtual method. */ + klass->do_specific_action_two = maman_bar_real_do_specific_action_two; +} +</programlisting> + </para> + + <para> + Children can then implement the subclass with code such as: +<programlisting> +static void +maman_bar_subtype_class_init (MamanBarSubTypeClass *klass) +{ + MamanBarClass *bar_class = MAMAN_BAR_CLASS (klass); + /* implement pure virtual class function. */ + bar_class->do_specific_action_one = maman_bar_subtype_do_specific_action_one; +} +</programlisting> + </para> + + <para> + Finally, it is interesting to note that, just like in C++, it is possible + to make each object class method chain to its parent class method: +<programlisting> +static void +maman_bar_real_do_action_two (MamanBar *self, /* parameters */) +{ + MamanBarClass *bar_class = g_type_class_peek_parent (klass); + /* chain up */ + bar_class->do_action (self, /* parameters */); + + /* do local stuff here. */ +} + +static void +maman_bar_subtype_class_init (MamanBarSubTypeClass *klass) +{ + MamanBarClass *bar_class = MAMAN_BAR_CLASS (klass); + /* implement pure virtual class function. */ + bar_class->do_specific_action_one = maman_bar_subtype_do_specific_action_one; +} +</programlisting> + </para> + </sect3> + </sect2> + + + </sect1> + +<!-- + End Howto GObject +--> + + +<!-- + Howto Interfaces +--> + + <sect1 id="howto-interface"> + <title>How To define and implement Interfaces ?</title> + + <sect2 id="howto-interface-define"> + <title>How To define Interfaces ?</title> + + <para> + The bulk of interface definition has already been shown in <xref linkend="gtype-non-instantiable-classed"/> + but I feel it is needed to show exactly how to create an interface. The sample source code + associated to this section can be found in the documentation's source tarball, in the + <filename>sample/interface/maman-ibaz.{h|c}</filename> file. + </para> + + <para> + As above, the first step is to get the header right: +<programlisting> +#ifndef MAMAN_IBAZ_H +#define MAMAN_IBAZ_H + +#include <glib-object.h> + +#define MAMAN_IBAZ_TYPE (maman_ibaz_get_type ()) +#define MAMAN_IBAZ(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MAMAN_IBAZ_TYPE, MamanIbaz)) +#define MAMAN_IBAZ_CLASS(vtable) (G_TYPE_CHECK_CLASS_CAST ((vtable), MAMAN_IBAZ_TYPE, MamanIbazClass)) +#define MAMAN_IS_IBAZ(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MAMAN_IBAZ_TYPE)) +#define MAMAN_IS_IBAZ_CLASS(vtable) (G_TYPE_CHECK_CLASS_TYPE ((vtable), MAMAN_IBAZ_TYPE)) +#define MAMAN_IBAZ_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), MAMAN_IBAZ_TYPE, MamanIbazClass)) + + +typedef struct _MamanIbaz MamanIbaz; /* dummy object */ +typedef struct _MamanIbazClass MamanIbazClass; + +struct _MamanIbazClass { + GTypeInterface parent; + + void (*do_action) (MamanIbaz *self); +}; + +GType maman_ibaz_get_type (void); + +void maman_ibaz_do_action (MamanIbaz *self); + +#endif //MAMAN_IBAZ_H +</programlisting> + This code is almost exactly similar to the code for a normal <type>GType</type> + which derives from a <type>GObject</type> except for a few details: + <itemizedlist> + <listitem><para> + The <function>_GET_CLASS</function> macro is not implemented with + <function>G_TYPE_INSTANCE_GET_CLASS</function> but with <function>G_TYPE_INSTANCE_GET_INTERFACE</function>. + </para></listitem> + <listitem><para> + The instance type, <type>MamanIbaz</type> is not fully defined: it is used merely as an abstract + type which represents an instance of whatever object which implements the interface. + </para></listitem> + </itemizedlist> + </para> + + <para> + The implementation of the <type>MamanIbaz</type> type itself is trivial: + <itemizedlist> + <listitem><para><function>maman_ibaz_get_type</function> registers the + type in the type system. + </para></listitem> + <listitem><para><function>maman_ibaz_base_init</function> is expected + to register the interface's signals if there are any (we will see a bit + (later how to use them). Make sure to use a static local boolean variable + to make sure not to run the initialization code twice (as described in + <xref linkend="gtype-non-instantiable-classed-init"/>, + <function>base_init</function> is run once for each interface implementation + instanciation)</para></listitem> + <listitem><para><function>maman_ibaz_do_action</function> de-references the class + structure to access its associated class function and calls it. + </para></listitem> + </itemizedlist> +<programlisting> +static void +maman_ibaz_base_init (gpointer g_class) +{ + static gboolean initialized = FALSE; + + if (!initialized) { + /* create interface signals here. */ + initialized = TRUE; + } +} + +GType +maman_ibaz_get_type (void) +{ + static GType type = 0; + if (type == 0) { + static const GTypeInfo info = { + sizeof (MamanIbazClass), + maman_ibaz_base_init, /* base_init */ + NULL, /* base_finalize */ + NULL, /* class_init */ + NULL, /* class_finalize */ + NULL, /* class_data */ + 0, + 0, /* n_preallocs */ + NULL /* instance_init */ + }; + type = g_type_register_static (G_TYPE_INTERFACE, "MamanIbaz", &info, 0); + } + return type; +} + +void maman_ibaz_do_action (MamanIbaz *self) +{ + MAMAN_IBAZ_GET_CLASS (self)->do_action (self); +} +</programlisting> + </para> + </sect2> + + <sect2 id="howto-interface-implement"> + <title>How To define and implement an implementation of an Interface ?</title> + + <para> + Once the interface is defined, implementing it is rather trivial. Source code showing how to do this + for the <type>IBaz</type> interface defined in the previous section is located in + <filename>sample/interface/maman-baz.{h|c}</filename>. + </para> + + <para> + The first step is to define a normal GType. Here, we have decided to use a GType which derives from + GObject. Its name is <type>MamanBaz</type>: +<programlisting> +#ifndef MAMAN_BAZ_H +#define MAMAN_BAZ_H + +#include <glib-object.h> + +#define MAMAN_BAZ_TYPE (maman_baz_get_type ()) +#define MAMAN_BAZ(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MAMAN_BAZ_TYPE, Mamanbaz)) +#define MAMAN_BAZ_CLASS(vtable) (G_TYPE_CHECK_CLASS_CAST ((vtable), MAMAN_BAZ_TYPE, MamanbazClass)) +#define MAMAN_IS_BAZ(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MAMAN_BAZ_TYPE)) +#define MAMAN_IS_BAZ_CLASS(vtable) (G_TYPE_CHECK_CLASS_TYPE ((vtable), MAMAN_BAZ_TYPE)) +#define MAMAN_BAZ_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((inst), MAMAN_BAZ_TYPE, MamanbazClass)) + + +typedef struct _MamanBaz MamanBaz; +typedef struct _MamanBazClass MamanBazClass; + +struct _MamanBaz { + GObject parent; + int instance_member; +}; + +struct _MamanBazClass { + GObjectClass parent; +}; + +GType maman_baz_get_type (void); + + +#endif //MAMAN_BAZ_H +</programlisting> + There is clearly nothing specifically weird or scary about this header: it does not define any weird API + or derives from a weird type. + </para> + + <para> + The second step is to implement <function>maman_baz_get_type</function>: +<programlisting> +GType +maman_baz_get_type (void) +{ + static GType type = 0; + if (type == 0) { + static const GTypeInfo info = { + sizeof (MamanBazClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + NULL, /* class_init */ + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (MamanBaz), + 0, /* n_preallocs */ + baz_instance_init /* instance_init */ + }; + static const GInterfaceInfo ibaz_info = { + (GInterfaceInitFunc) baz_interface_init, /* interface_init */ + NULL, /* interface_finalize */ + NULL /* interface_data */ + }; + type = g_type_register_static (G_TYPE_OBJECT, + "MamanBazType", + &info, 0); + g_type_add_interface_static (type, + MAMAN_IBAZ_TYPE, + &ibaz_info); + } + return type; +} +</programlisting> + This function is very much like all the similar functions we looked at previously. The only interface-specific + code present here is the call to <function>g_type_add_interface_static</function> which is used to inform + the type system that this just-registered <type>GType</type> also implements the interface + <function>MAMAN_IBAZ_TYPE</function>. + </para> + + <para> + <function>baz_interface_init</function>, the interface initialization function, is also pretty simple: +<programlisting> +static void baz_do_action (MamanBaz *self) +{ + g_print ("Baz implementation of IBaz interface Action: 0x%x.\n", self->instance_member); +} +static void +baz_interface_init (gpointer g_iface, + gpointer iface_data) +{ + MamanIbazClass *klass = (MamanIbazClass *)g_iface; + klass->do_action = (void (*) (MamanIbaz *self))baz_do_action; +} +static void +baz_instance_init (GTypeInstance *instance, + gpointer g_class) +{ + MamanBaz *self = (MamanBaz *)instance; + self->instance_member = 0xdeadbeaf; +} +</programlisting> + <function>baz_interface_init</function> merely initializes the interface methods to the implementations + defined by <type>MamanBaz</type>: <function>maman_baz_do_action</function> does nothing very useful + but it could :) + </para> + +</sect2> + +<sect2> + <title>Interface definition prerequisites</title> + + + + <para>To specify that an interface requires the presence of other interfaces when implemented, + GObject introduces the concept of <emphasis>prerequisites</emphasis>: it is possible to associate + a list of prerequisite interfaces to an interface. For example, if object A wishes to implement interface + I1, and if interface I1 has a prerequisite on interface I2, A has to implement both I1 and I2. + </para> + + <para>The mechanism described above is, in practice, very similar to Java's interface I1 extends + interface I2. The example below shows the GObject equivalent: + +<programlisting> + type = g_type_register_static (G_TYPE_INTERFACE, "MamanIbar", &info, 0); + /* Make the MamanIbar interface require MamanIbaz interface. */ + g_type_interface_add_prerequisite (type, MAMAN_IBAZ_TYPE); +</programlisting> + The code shown above adds the MamanIbaz interface to the list of prerequisites of MamanIbar while the + code below shows how an implementation can implement both interfaces and register their implementations: +<programlisting> +static void ibar_do_another_action (MamanBar *self) +{ + g_print ("Bar implementation of IBar interface Another Action: 0x%x.\n", self->instance_member); +} + +static void +ibar_interface_init (gpointer g_iface, + gpointer iface_data) +{ + MamanIbarClass *klass = (MamanIbarClass *)g_iface; + klass->do_another_action = (void (*) (MamanIbar *self))ibar_do_another_action; +} + + +static void ibaz_do_action (MamanBar *self) +{ + g_print ("Bar implementation of IBaz interface Action: 0x%x.\n", self->instance_member); +} + +static void +ibaz_interface_init (gpointer g_iface, + gpointer iface_data) +{ + MamanIbazClass *klass = (MamanIbazClass *)g_iface; + klass->do_action = (void (*) (MamanIbaz *self))ibaz_do_action; +} + + +static void +bar_instance_init (GTypeInstance *instance, + gpointer g_class) +{ + MamanBar *self = (MamanBar *)instance; + self->instance_member = 0x666; +} + + +GType +maman_bar_get_type (void) +{ + static GType type = 0; + if (type == 0) { + static const GTypeInfo info = { + sizeof (MamanBarClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + NULL, /* class_init */ + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (MamanBar), + 0, /* n_preallocs */ + bar_instance_init /* instance_init */ + }; + static const GInterfaceInfo ibar_info = { + (GInterfaceInitFunc) ibar_interface_init, /* interface_init */ + NULL, /* interface_finalize */ + NULL /* interface_data */ + }; + static const GInterfaceInfo ibaz_info = { + (GInterfaceInitFunc) ibaz_interface_init, /* interface_init */ + NULL, /* interface_finalize */ + NULL /* interface_data */ + }; + type = g_type_register_static (G_TYPE_OBJECT, + "MamanBarType", + &info, 0); + g_type_add_interface_static (type, + MAMAN_IBAZ_TYPE, + &ibaz_info); + g_type_add_interface_static (type, + MAMAN_IBAR_TYPE, + &ibar_info); + } + return type; +} +</programlisting> + It is very important to notice that the order in which interface implementations are added to the main object + is not random: <function>g_type_interface_static</function> must be invoked first on the interfaces which have + no prerequisites and then on the others. +</para> + + <para> + Complete source code showing how to define the MamanIbar interface which requires MamanIbaz and how to + implement the MamanIbar interface is located in <filename>sample/interface/maman-ibar.{h|c}</filename> + and <filename>sample/interface/maman-bar.{h|c}</filename>. + </para> + +</sect2> + + </sect1> + +<!-- + End Howto Interfaces +--> + + +<!-- + start Howto Signals +--> + + + <sect1 id="howto-signals"> + <title>Howto create and use signals</title> + + + <para> + The signal system which was built in GType is pretty complex and flexible: it is possible for its users + to connect at runtime any number of callbacks (implemented in any language for which a binding exists) + <footnote> + <para>A python callback can be connected to any signal on any C-based GObject. + </para> + </footnote> + + to any signal and to stop the emission of any signal at any + state of the signal emission process. This flexibility makes it possible to use GSignal for much more than + just emit events which can be received by numerous clients. + </para> + +<sect2> +<title>Simple use of signals</title> + +<para>The most basic use of signals is to implement simple event notification: for example, if we have a +MamanFile object, and if this object has a write method, we might wish to be notified whenever someone +uses this method. The code below shows how the user can connect a callback to the write signal. Full code +for this simple example is located in <filename>sample/signal/maman-file.{h|c}</filename> and +in <filename>sample/signal/test.c</filename> +<programlisting> + file = g_object_new (MAMAN_FILE_TYPE, NULL); + + g_signal_connect (G_OBJECT (file), "write", + (GCallback)write_event, + NULL); + + maman_file_write (file, buffer, 50); +</programlisting> +</para> + +<para> +The <type>MamanFile</type> signal is registered in the class_init function: +<programlisting> + klass->write_signal_id = + g_signal_newv ("write", + G_TYPE_FROM_CLASS (g_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, + NULL /* class closure */, + NULL /* accumulator */, + NULL /* accu_data */, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE /* return_type */, + 0 /* n_params */, + NULL /* param_types */); +</programlisting> +and the signal is emited in <function>maman_file_write</function>: +<programlisting> +void maman_file_write (MamanFile *self, guint8 *buffer, guint32 size) +{ + /* First write data. */ + /* Then, notify user of data written. */ + g_signal_emit (self, MAMAN_FILE_GET_CLASS (self)->write_signal_id, + 0 /* details */, + NULL); +} +</programlisting> +As shown above, you can safely set the details parameter to zero if you do not know what it can be used for. +For a discussion of what you could used it for, see <xref linkend="signal-detail"/> +</para> + +<para> +</para> + +</sect2> + + +<sect2> +<title>How to provide more flexibility to users ?</title> + +<para>The previous implementation does the job but the signal facility of GObject can be used to provide +even more flexibility to this file change notification mechanism. One of the key ideas is to make the process +of writing data to the file part of the signal emission process to allow users to be notified either +before or after the data is written to the file. +</para> + +<para>To integrate the process of writing the data to the file into the signal emission mechanism, we can +register a default class closure for this signal which will be invoked during the signal emission, just like +any other user-connected signal handler. +</para> + +<para>The first step to implement this idea is to change the signature of the signal: we need to pass +around the buffer to write and its size. To do this, we use our own marshaller which will be generated +through glib's genmarshall tool. We thus create a file named <filename>marshall.list</filename> which contains +the following single line: +<programlisting> +VOID:POINTER,UINT +</programlisting> +and use the Makefile provided in <filename>sample/signal/Makefile</filename> to generate the file named +<filename>maman-file-complex-marshall.c</filename>. This C file is finally included in +<filename>maman-file-complex.c</filename>. +</para> + +<para>Once the marshaller is present, we register the signal and its marshaller in the class_init function +of the object <type>MamanFileComplex</type> (full source for this object is included in +<filename>sample/signal/maman-file-complex.{h|c}</filename>): +<programlisting> + GClosure *default_closure; + GType param_types[2]; + + default_closure = g_cclosure_new (G_CALLBACK (default_write_signal_handler), + (gpointer)0xdeadbeaf /* user_data */, + NULL /* destroy_data */); + + param_types[0] = G_TYPE_POINTER; + param_types[1] = G_TYPE_UINT; + klass->write_signal_id = + g_signal_newv ("write", + G_TYPE_FROM_CLASS (g_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, + default_closure /* class closure */, + NULL /* accumulator */, + NULL /* accu_data */, + maman_file_complex_VOID__POINTER_UINT, + G_TYPE_NONE /* return_type */, + 2 /* n_params */, + param_types /* param_types */); +</programlisting> +The code shown above first creates the closure which contains the code to complete the file write. This +closure is registered as the default class_closure of the newly created signal. +</para> + +<para> +Of course, you need to implement completely the code for the default closure since I just provided +a skeleton: +<programlisting> +static void +default_write_signal_handler (GObject *obj, guint8 *buffer, guint size, gpointer user_data) +{ + g_assert (user_data == (gpointer)0xdeadbeaf); + /* Here, we trigger the real file write. */ + g_print ("default signal handler: 0x%x %u\n", buffer, size); +} +</programlisting> +</para> + +<para>Finally, the client code must invoke the <function>maman_file_complex_write</function> function which +triggers the signal emission: +<programlisting> +void maman_file_complex_write (MamanFileComplex *self, guint8 *buffer, guint size) +{ + /* trigger event */ + g_signal_emit (self, + MAMAN_FILE_COMPLEX_GET_CLASS (self)->write_signal_id, + 0, /* details */ + buffer, size); +} +</programlisting> +</para> + +<para>The client code (as shown in <filename>sample/signal/test.c</filename> and below) can now connect signal handlers before +and after the file write is completed: since the default signal handler which does the write itself runs during the +RUN_LAST phase of the signal emission, it will run after all handlers connected with <function>g_signal_connect</function> +and before all handlers connected with <function>g_signal_connect_after</function>. If you intent to write a GObject +which emits signals, I would thus urge you to create all your signals with the G_SIGNAL_RUN_LAST such that your users +have a maximum of flexibility as to when to get the event. Here, we combined it with G_SIGNAL_NO_RECURSE and +G_SIGNAL_NO_HOOKS to ensure our users will not try to do really weird things with our GObject. I strongly advise you +to do the same unless you really know why (in which case you really know the inner workings of GSignal by heart and +you are not reading this). +</para> + +<para> +<programlisting> +static void complex_write_event_before (GObject *file, guint8 *buffer, guint size, gpointer user_data) +{ + g_assert (user_data == NULL); + g_print ("Complex Write event before: 0x%x, %u\n", buffer, size); +} + +static void complex_write_event_after (GObject *file, guint8 *buffer, guint size, gpointer user_data) +{ + g_assert (user_data == NULL); + g_print ("Complex Write event after: 0x%x, %u\n", buffer, size); +} + +static void test_file_complex (void) +{ + guint8 buffer[100]; + GObject *file; + + file = g_object_new (MAMAN_FILE_COMPLEX_TYPE, NULL); + + g_signal_connect (G_OBJECT (file), "write", + (GCallback)complex_write_event_before, + NULL); + + g_signal_connect_after (G_OBJECT (file), "write", + (GCallback)complex_write_event_after, + NULL); + + maman_file_complex_write (MAMAN_FILE_COMPLEX (file), buffer, 50); + + g_object_unref (G_OBJECT (file)); +} +</programlisting> +The code above generates the following output on my machine: +<programlisting> +Complex Write event before: 0xbfffe280, 50 +default signal handler: 0xbfffe280 50 +Complex Write event after: 0xbfffe280, 50 +</programlisting> +</para> + + + <sect3> + <title>How most people do the same thing with less code</title> + + <para>For many historic reasons related to how the ancestor of GObject used to work in GTK+ 1.x versions, + there is a much <emphasis>simpler</emphasis> + <footnote> + <para>I personally think that this method is horribly mind-twisting: it adds a new indirection + which unecessarily complicates the overall code path. However, because this method is widely used + by all of GTK+ and GObject code, readers need to understand it. The reason why this is done that way + in most of GTK+ is related to the fact that the ancestor of GObject did not provide any other way to + create a signal with a default handler than this one. Some people have tried to justify that it is done + that way because it is better, faster (I am extremly doubtfull about the faster bit. As a matter of fact, + the better bit also mystifies me ;-). I have the feeling no one really knows and everyone does it + because they copy/pasted code from code which did the same. It is probably better to leave this + specific trivia to hacker legends domain... + </para> + </footnote> + way to create a signal with a default handler than to create + a closure by hand and to use the <function>g_signal_newv</function>. + </para> + + <para>For example, <function>g_signal_new</function> can be used to create a signal which uses a default + handler which is stored in the class structure of the object. More specifically, the class structure + contains a function pointer which is accessed during signal emission to invoke the default handler and + the user is expected to provide to <function>g_signal_new</function> the offset from the start of the + class structure to the function pointer. + <footnote> + <para>I would like to point out here that the reason why the default handler of a signal is named everywhere + a class_closure is probably related to the fact that it used to be really a function pointer stored in + the class structure. + </para> + </footnote> + </para> + + <para>The following code shows the declaration of the <type>MamanFileSimple</type> class structure which contains + the <function>write</function> function pointer. +<programlisting> +struct _MamanFileSimpleClass { + GObjectClass parent; + + guint write_signal_id; + + /* signal default handlers */ + void (*write) (MamanFileSimple *self, guint8 *buffer, guint size); +}; +</programlisting> + The <function>write</function> function pointer is initialied in the class_init function of the object + to <function>default_write_signal_handler</function>: +<programlisting> +static void +maman_file_simple_class_init (gpointer g_class, + gpointer g_class_data) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (g_class); + MamanFileSimpleClass *klass = MAMAN_FILE_SIMPLE_CLASS (g_class); + + klass->write = default_write_signal_handler; +</programlisting> + Finally, the signal is created with <function>g_signal_new</function> in the same class_init function: +<programlisting> + klass->write_signal_id = + g_signal_new ("write", + G_TYPE_FROM_CLASS (g_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, + G_STRUCT_OFFSET (MamanFileSimpleClass, write), + NULL /* accumulator */, + NULL /* accu_data */, + maman_file_complex_VOID__POINTER_UINT, + G_TYPE_NONE /* return_type */, + 2 /* n_params */, + G_TYPE_POINTER, + G_TYPE_UINT); +</programlisting> + Of note, here, is the 4th argument to the function: it is an integer calculated by the <function>G_STRUCT_OFFSET</function> + macro which indicates the offset of the member <emphasis>write</emphasis> from the start of the + <type>MamanFileSimpleClass</type> class structure. + <footnote> + <para>GSignal uses this offset to create a special wrapper closure + which first retrieves the target function pointer before calling it. + </para> + </footnote> + </para> + + <para> + While the complete code for this type of default handler looks less clutered as shown in + <filename>sample/signal/maman-file-simple.{h|c}</filename>, it contains numerous subtleties. + The main subtle point which everyone must be aware of is that the signature of the default + handler created that way does not have a user_data argument: + <function>default_write_signal_handler</function> is different in + <filename>sample/signal/maman-file-complex.c</filename> and in + <filename>sample/signal/maman-file-simple.c</filename>. + </para> + + <para>If you have doubts about which method to use, I would advise you to use the second one which + involves <function>g_signal_new</function> rather than <function>g_signal_newv</function>: + it is better to write code which looks like the vast majority of other GTK+/Gobject code than to + do it your own way. However, now, you know why. + </para> + + </sect3> + + +</sect2> + + + +<sect2> + <title>How users can abuse signals (and why some think it is good)</title> + + <para>Now that you know how to create signals to which the users can connect easily and at any point in + the signal emission process thanks to <function>g_signal_connect</function>, + <function>g_signal_connect_after</function> and G_SIGNAL_RUN_LAST, it is time to look into how your + users can and will screw you. This is also interesting to know how you too, can screw other people. + This will make you feel good and eleet. + </para> + + <para>The users can: + <itemizedlist> + <listitem><para>stop the emission of the signal at anytime</para></listitem> + <listitem><para>override the default handler of the signal if it is stored as a function + pointer in the class structure (which is the prefered way to create a default signal handler, + as discussed in the previous section).</para></listitem> + </itemizedlist> + </para> + + <para>In both cases, the original programmer should be as careful as possible to write code which is + resistant to the fact that the default handler of the signal might not able to run. This is obviously + not the case in the example used in the previous sections since the write to the file depends on whether + or not the default handler runs (however, this might be your goal: to allow the user to prevent the file + write if he wishes to). + </para> + + <para>If all you want to do is to stop the signal emission from one of the callbacks you connected yourself, + you can call <function>g_signal_stop_by_name</function>. Its use is very simple which is why I won't detail + it further. + </para> + + <para>If the signal's default handler is just a class function pointer, it is also possible to override + it yourself from the class_init function of a type which derives from the parent. That way, when the signal + is emitted, the parent class will use the function provided by the child as a signal default handler. + Of course, it is also possible (and recommended) to chain up from the child to the parent's default signal + handler to ensure the integrity of the parent object. + </para> + + <para>Overriding a class method and chaining up was demonstrated in <xref linkend="howto-gobject-methods"/> + which is why I won't bother to show exactly how to do it here again.</para> + + +</sect2> + +</sect1> + +<!-- + <sect3> + <title>Warning on signal creation and default closure</title> + + <para> + Most of the existing code I have seen up to now (in both GTK+, Gnome libraries and + many GTK+ and Gnome applications) using signals uses a small + variation of the default handler pattern I have shown in the previous section. + </para> + + <para> + Usually, the <function>g_signal_new</function> function is preferred over + <function>g_signal_newv</function>. When <function>g_signal_new</function> + is used, the default closure is exported as a class function. For example, + <filename>gobject.h</filename> contains the declaration of <type>GObjectClass</type> + whose notify class function is the default handler for the <emphasis>notify</emphasis> + signal: +<programlisting> +struct _GObjectClass +{ + GTypeClass g_type_class; + + /* class methods and other stuff. */ + + /* signals */ + void (*notify) (GObject *object, + GParamSpec *pspec); +}; +</programlisting> + </para> + + <para> + <filename>gobject.c</filename>'s <function>g_object_do_class_init</function> function + registers the <emphasis>notify</emphasis> signal and initializes this class function + to NULL: +<programlisting> +static void +g_object_do_class_init (GObjectClass *class) +{ + + /* Stuff */ + + class->notify = NULL; + + gobject_signals[NOTIFY] = + g_signal_new ("notify", + G_TYPE_FROM_CLASS (class), + G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE | G_SIGNAL_DETAILED | G_SIGNAL_NO_HOOKS, + G_STRUCT_OFFSET (GObjectClass, notify), + NULL, NULL, + g_cclosure_marshal_VOID__PARAM, + G_TYPE_NONE, + 1, G_TYPE_PARAM); +} +</programlisting> + <function>g_signal_new</function> creates a <type>GClosure</type> which de-references the + type's class structure to access the class function pointer and invoke it if it not NULL. The + class function is ignored it is set to NULL. + </para> + + <para> + To understand the reason for such a complex scheme to access the signal's default handler, + you must remember the whole reason for the use of these signals. The goal here is to delegate + a part of the process to the user without requiring the user to subclass the object to override + one of the class functions. The alternative to subclassing, that is, the use of signals + to delegate processing to the user, is, however, a bit less optimal in terms of speed: rather + than just de-referencing a function pointer in a class structure, you must start the whole + process of signal emission which is a bit heavyweight. + </para> + + <para> + This is why some people decided to use class functions for some signal's default handlers: + rather than having users connect a handler to the signal and stop the signal emission + from within that handler, you just need to override the default class function which is + supposedly more efficient. + </para> + + </sect3> +--> + + +<!-- + <sect1 id="howto-doc"> + <title>How to generate API documentation for your type ?</title> + + </sect1> +--> + + </chapter> + + + + + diff --git a/docs/reference/gobject/tut_intro.xml b/docs/reference/gobject/tut_intro.xml new file mode 100644 index 000000000..b8bcb1659 --- /dev/null +++ b/docs/reference/gobject/tut_intro.xml @@ -0,0 +1,160 @@ +<chapter> +<title>Introduction</title> + +<para> +GObject, and its lower-level type system, GType, are used by GTK+ and most Gnome libraries to +provide: +<itemizedlist> +<listitem><para>object-oriented C-based APIs and</para></listitem> +<listitem><para>automatic transparent API bindings to other compiled +or interpreted languages.</para></listitem> +</itemizedlist> +</para> + +<para>A lot of programmers are used to work with compiled-only or dynamically interpreted-only +languages and do not understand the challenges associated with cross-language interoperability. +This introduction tries to provide an insight into these challenges and describes briefly +the solution choosen by GLib. +</para> + +<sect1> +<title>Data types and programming</title> + +<para> +One could say (I have seen such definitions used in some textbooks on programming language theory) +that a programming language is merely a way to create data types and manipulate them. Most languages +provide a number of language-native types and a few primitives to create more complex types based +on these primitive types. +</para> + +<para> +In C, the language provides types such as <emphasis>char</emphasis>, <emphasis>long</emphasis>, +<emphasis>pointer</emphasis>. During compilation of C code, the compiler maps these +language types to the compiler's target architecture machine types. If you are using a C interpreter +(I have never seen one myself but it is possible :), the interpreter (the program which interprets +the source code and executes it) maps the language types to the machine types of the target machine at +runtime, during the program execution (or just before execution if it uses a Just In Time compiler engine). +</para> + +<para>Perl and Python which are interpreted languages do not really provide type definitions similar +to those used by C. Perl and Python programmers manipulate variables and the type of the variables +is decided only upon the first assignment or upon the first use which forces a type on the variable. +The interpreter also often provides a lot of automatic conversions from one type to the other. For example, +in Perl, a variable which holds an integer can be automatically converted to a string given the +required context: +<programlisting> +my $tmp = 10; +print "this is an integer converted to a string:" . $tmp . "\n"; +</programlisting> +Of course, it is also often possible to explicitely specify conversions when the default conversions provided +by the language are not intuitive. +</para> + +</sect1> + +<sect1> +<title>Exporting a C API</title> + +<para>C APIs are defined by a set of functions and global variables which are usually exported from a +binary. C functions have an arbitrary number of arguments and one return value. Each function is thus +uniquely identified by the function name and the set of C types which describe the function arguments +and return value. The global variables exported by the API are similarly identified by their name and +their type. +</para> + +<para> +A C API is thus merely defined by a set of names to which a set of types are associated. If you know the +function calling convention and the mapping of the C types to the machine types used by the platform you +are on, you can resolve the name of each function to find where the code associated to this function +is located in memory, and then construct a valid argument list for the function. Finally, all you have to +do is triger a call to the target C function with the argument list. +</para> + +<para> +For the sake of discussion, here is a sample C function and the associated 32 bit x86 +assembly code generated by gcc on my linux box: +<programlisting> +static void function_foo (int foo) +{} + +int main (int argc, char *argv[]) +{ + + function_foo (10); + + return 0; +} + +push $0xa +call 0x80482f4 <function_foo> +</programlisting> +The assembly code shown above is pretty straightforward: the first instruction pushes +the hexadecimal value 0xa (decimal value 10) as a 32 bit integer on the stack and calls +<function>function_foo</function>. As you can see, C function calls are implemented by +gcc by native function calls (this is probably the fastest implementation possible). +</para> + +<para> +Now, let's say we want to call the C function <function>function_foo</function> from +a python program. To do this, the python interpreter needs to: +<itemizedlist> +<listitem><para>Find where the function is located. This means probably find the binary generated by the C compiler +which exports this functions.</para></listitem> +<listitem><para>Load the code of the function in executable memory.</para></listitem> +<listitem><para>Convert the python parameters to C-compatible parameters before calling +the function.</para></listitem> +<listitem><para>Call the function with the right calling convention</para></listitem> +<listitem><para>Convert the return values of the C function to python-compatible +variables to return them to the python code.</para></listitem> +</itemizedlist> +</para> + +<para>The process described above is pretty complex and there are a lot of ways to make it entirely automatic +and transparent to the C and the Python programmers: +<itemizedlist> +<listitem><para>The first solution is to write by hand a lot of glue code, once for each function exported or imported, +which does the python to C parameter conversion and the C to python return value conversion. This glue code is then +linked with the interpreter which allows python programs to call a python functions which delegates the work to the +C function.</para></listitem> +<listitem><para>Another nicer solution is to automatically generate the glue code, once for each function exported or +imported, with a special compiler which +reads the original function signature.</para></listitem> +<listitem><para>The solution used by GLib is to use the GType library which holds at runtime a description of +all the objects manipulated by the programmer. This so-called <emphasis>dynamic type</emphasis><footnote> +<para> + There are numerous different implementations of dynamic type systems: all C++ + compilers have one, Java and .NET have one too. A dynamic type system allows you + to get information about every instantiated object at runtime. It can be implemented + by a process-specific database: every new object created registers the characteristics + of its associated type in the type system. It can also be implemented by introspection + interfaces. The common point between all these different type systems and implementations + is that they all allow you to query for object metadata at runtime. +</para> +</footnote> + + library is then +used by special generic glue code to automatically convert function parameters and function caling 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> + +Currently, there exist at least Python and Perl glue code which makes it possible to use +C objects written with GType directly in Python or Perl, without any further work. +</para> + + +</sect1> + + +</chapter> |