mirror of
				https://gitlab.gnome.org/GNOME/glib.git
				synced 2025-10-31 08:22:16 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			1721 lines
		
	
	
		
			64 KiB
		
	
	
	
		
			XML
		
	
	
	
	
	
			
		
		
	
	
			1721 lines
		
	
	
		
			64 KiB
		
	
	
	
		
			XML
		
	
	
	
	
	
| <?xml version='1.0' encoding="ISO-8859-1"?>
 | |
| <!DOCTYPE part PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN" 
 | |
|                "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" [
 | |
| ]>
 | |
| <part label="IV">
 | |
|   <title>Tutorial</title>
 | |
|   <partintro>
 | |
|     <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>
 | |
|   </partintro>
 | |
| 
 | |
| <chapter id="howto-gobject">
 | |
|   <title>How to define and implement a new GObject</title>
 | |
|   
 | |
|   <para>
 | |
|     Clearly, this is one of the most common questions 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.
 | |
|   </para>
 | |
| 
 | |
|   <sect1 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>
 | |
|       Some people like the first two solutions better: it makes reading file
 | |
|       names easier for those with poor eyesight.
 | |
|     </para>
 | |
| 
 | |
|     <para>
 | |
|       When you need some private (internal) declarations in several
 | |
|       (sub)classes, you can define them in a private header file which
 | |
|       is often named by appending the <emphasis>private</emphasis> keyword
 | |
|       to the public header name. For example, one could use
 | |
|       <filename>maman-bar-private.h</filename>,
 | |
|       <filename>maman_bar_private.h</filename> or
 | |
|       <filename>mamanbarprivate.h</filename>. Typically, such private header
 | |
|       files are not installed.
 | |
|     </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 one of 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.
 | |
|  */
 | |
| 
 | |
| /* inclusion guard */
 | |
| #ifndef __MAMAN_BAR_H__
 | |
| #define __MAMAN_BAR_H__
 | |
| 
 | |
| #include <glib-object.h>
 | |
| /*
 | |
|  * Potentially, include other headers on which this header depends.
 | |
|  */
 | |
| 
 | |
| /*
 | |
|  * Type macros.
 | |
|  */
 | |
| #define MAMAN_TYPE_BAR                  (maman_bar_get_type ())
 | |
| #define MAMAN_BAR(obj)                  (G_TYPE_CHECK_INSTANCE_CAST ((obj), MAMAN_TYPE_BAR, MamanBar))
 | |
| #define MAMAN_IS_BAR(obj)               (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MAMAN_TYPE_BAR))
 | |
| #define MAMAN_BAR_CLASS(klass)          (G_TYPE_CHECK_CLASS_CAST ((klass), MAMAN_TYPE_BAR, MamanBarClass))
 | |
| #define MAMAN_IS_BAR_CLASS(klass)       (G_TYPE_CHECK_CLASS_TYPE ((klass), MAMAN_TYPE_BAR))
 | |
| #define MAMAN_BAR_GET_CLASS(obj)        (G_TYPE_INSTANCE_GET_CLASS ((obj), MAMAN_TYPE_BAR, MamanBarClass))
 | |
| 
 | |
| typedef struct _MamanBar        MamanBar;
 | |
| typedef struct _MamanBarClass   MamanBarClass;
 | |
| 
 | |
| struct _MamanBar
 | |
| {
 | |
|   GObject parent_instance;
 | |
| 
 | |
|   /* instance members */
 | |
| };
 | |
| 
 | |
| struct _MamanBarClass
 | |
| {
 | |
|   GObjectClass parent_class;
 | |
| 
 | |
|   /* class members */
 | |
| };
 | |
| 
 | |
| /* used by MAMAN_TYPE_BAR */
 | |
| GType maman_bar_get_type (void);
 | |
| 
 | |
| /*
 | |
|  * Method definitions.
 | |
|  */
 | |
| 
 | |
| #endif /* __MAMAN_BAR_H__ */
 | |
| </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_instance;
 | |
| 
 | |
|   /*< 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 url="http://www.gotw.ca/gotw/024.htm">Compilation Firewalls</ulink>
 | |
|             and <ulink url="http://www.gotw.ca/gotw/028.htm">The Fast Pimpl Idiom</ulink>:
 | |
|             he summarizes the different issues better than I will).
 | |
| <programlisting>
 | |
| typedef struct _MamanBarPrivate MamanBarPrivate;
 | |
| 
 | |
| struct _MamanBar
 | |
| {
 | |
|   GObject parent_instance;
 | |
|     
 | |
|   /*< private >*/
 | |
|   MamanBarPrivate *priv;
 | |
| };
 | |
| </programlisting>
 | |
|             <note><simpara>Do not call this <varname>private</varname>, as
 | |
|             that is a registered c++ keyword.</simpara></note>
 | |
| 
 | |
|             The private structure is then defined in the .c file, using the
 | |
|             g_type_class_add_private() function to notify the presence of
 | |
|             a private memory area for each instance and it can either
 | |
|             be retrieved using <function>G_TYPE_INSTANCE_GET_PRIVATE()</function>
 | |
|             each time is needed, or assigned to the <literal>priv</literal>
 | |
|             member of the instance structure inside the object's
 | |
|             <function>init</function> function.
 | |
| <programlisting>
 | |
| #define MAMAN_BAR_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), MAMAN_TYPE_BAR, MamanBarPrivate))
 | |
| 
 | |
| struct _MamanBarPrivate
 | |
| {
 | |
|   int hsize;
 | |
| }
 | |
| 
 | |
| static void
 | |
| maman_bar_class_init (MamanBarClass *klass)
 | |
| {
 | |
|   g_type_class_add_private (klass, sizeof (MamanBarPrivate));
 | |
| }
 | |
| 
 | |
| static void
 | |
| maman_bar_init (MamanBar *self)
 | |
| {
 | |
|   MamanBarPrivate *priv;
 | |
| 
 | |
|   self->priv = priv = MAMAN_BAR_GET_PRIVATE (self);
 | |
| 
 | |
|   priv->hsize = 42;
 | |
| }
 | |
| </programlisting>
 | |
|           </para></listitem>
 | |
| 
 | |
|           <listitem><para>
 | |
|             You don't need to free or allocate the private structure, only the
 | |
|             objects or pointers that it may contain. Another advantage of this
 | |
|             to the previous version is that is lessens memory fragmentation,
 | |
|             as the public and private parts of the instance memory are
 | |
|             allocated at once.
 | |
|           </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, as always, 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>
 | |
|       
 | |
|   </sect1>
 | |
| 
 | |
|   <sect1 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
 | |
|       <literal>#include "maman-bar.h"</literal> or as complicated as tens
 | |
|       of #include lines ending with <literal>#include "maman-bar.h"</literal>:
 | |
| <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>
 | |
|       Call the <function>G_DEFINE_TYPE</function> macro using the name
 | |
|       of the type, the prefix of the functions and the parent GType to
 | |
|       reduce the amount of boilerplate needed. This macro will:
 | |
| 
 | |
|       <itemizedlist>
 | |
|         <listitem><simpara>implement the <function>maman_bar_get_type</function>
 | |
|         function</simpara></listitem>
 | |
|         <listitem><simpara>define a parent class pointer accessible from
 | |
|         the whole .c file</simpara></listitem>
 | |
|       </itemizedlist>
 | |
| 
 | |
| <programlisting>
 | |
| G_DEFINE_TYPE (MamanBar, maman_bar, G_TYPE_OBJECT);
 | |
| </programlisting>
 | |
|     </para>
 | |
| 
 | |
|     <para>
 | |
|       It is also possible to use the
 | |
|       <function>G_DEFINE_TYPE_WITH_CODE</function> macro to control the
 | |
|       get_type function implementation - for instance, to add a call to
 | |
|       <function>G_IMPLEMENT_INTERFACE</function> macro which will
 | |
|       call the <function>g_type_implement_interface</function> function.
 | |
|     </para>
 | |
|   </sect1>
 | |
| 
 | |
|   <sect1 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 instantiation 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><link linkend="g-object-new">g_object_new</link></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 (MamanBar *self)
 | |
| {
 | |
|   self->priv = MAMAN_BAR_GET_PRIVATE (self); 
 | |
| 
 | |
|   /* initialize all public and private members to reasonable default values. */
 | |
| 
 | |
|   /* If you need specific construction properties to complete initialization,
 | |
|    * delay initialization completion until the property is set. 
 | |
|    */
 | |
| }
 | |
| </programlisting>
 | |
|     </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 
 | |
|       <link linkend="GParamSpec"><type>GParamSpec</type></link> 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 *pspec;
 | |
| 
 | |
|   gobject_class->set_property = bar_set_property;
 | |
|   gobject_class->get_property = bar_get_property;
 | |
| 
 | |
|   pspec = 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,
 | |
|                                    pspec);
 | |
| }
 | |
| </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><link linkend="g-object-new">g_object_new</link></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-instantiation"/> or, more simply, using
 | |
|       the constructed class method available since GLib 2.12.
 | |
|     </para>
 | |
|   </sect1>
 | |
| 
 | |
|   <sect1 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><link linkend="g-object-unref">g_object_unref</link></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 might be split in two different
 | |
|       phases: dispose and the finalize.
 | |
| <programlisting>
 | |
| #define MAMAN_BAR_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), MAMAN_TYPE_BAR, MamanBarPrivate))
 | |
| 
 | |
| struct _MamanBarPrivate
 | |
| {
 | |
|   GObject *an_object;
 | |
| 
 | |
|   gchar *a_string;
 | |
| };
 | |
| 
 | |
| G_DEFINE_TYPE (MamanBar, maman_bar, G_TYPE_OBJECT);
 | |
| 
 | |
| static void
 | |
| maman_bar_dispose (GObject *gobject)
 | |
| {
 | |
|   MamanBar *self = MAMAN_BAR (gobject);
 | |
| 
 | |
|   /* 
 | |
|    * 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.
 | |
|    */
 | |
| 
 | |
|   /* dispose might be called multiple times, so we must guard against
 | |
|    * calling g_object_unref() on an invalid GObject.
 | |
|    */
 | |
|   if (self->priv->an_object)
 | |
|     {
 | |
|       g_object_unref (self->priv->an_object);
 | |
| 
 | |
|       self->priv->an_object = NULL;
 | |
|     }
 | |
| 
 | |
|   /* Chain up to the parent class */
 | |
|   G_OBJECT_CLASS (maman_bar_parent_class)->dispose (gobject);
 | |
| }
 | |
| 
 | |
| static void
 | |
| maman_bar_finalize (GObject *gobject)
 | |
| {
 | |
|   MamanBar *self = MAMAN_BAR (gobject);
 | |
| 
 | |
|   g_free (self->priv->a_string);
 | |
| 
 | |
|   /* Chain up to the parent class */
 | |
|   G_OBJECT_CLASS (maman_bar_parent_class)->finalize (gobject);
 | |
| }
 | |
| 
 | |
| static void
 | |
| maman_bar_class_init (MamanBarClass *klass)
 | |
| {
 | |
|   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
 | |
| 
 | |
|   gobject_class->dispose = maman_bar_dispose;
 | |
|   gobject_class->finalize = maman_bar_finalize;
 | |
| 
 | |
|   g_type_class_add_private (klass, sizeof (MamanBarPrivate));
 | |
| }
 | |
| 
 | |
| static void
 | |
| maman_bar_init (MamanBar *self);
 | |
| {
 | |
|   self->priv = MAMAN_BAR_GET_PRIVATE (self);
 | |
| 
 | |
|   self->priv->an_object = g_object_new (MAMAN_TYPE_BAZ, NULL);
 | |
|   self->priv->a_string = g_strdup ("Maman");
 | |
| }
 | |
| </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.
 | |
|     </para>
 | |
| 
 | |
|     <para>
 | |
|       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.
 | |
|     </para>
 | |
|   </sect1>
 | |
| 
 | |
|   <sect1 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 e.g.
 | |
|       <ulink url="http://www.cplusplus.com/doc/tutorial/"/> 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>
 | |
| 
 | |
|     <sect2>
 | |
|       <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 */)
 | |
| {
 | |
|   g_return_if_fail (MAMAN_IS_BAR (self));
 | |
| 
 | |
|   /* do stuff here. */
 | |
| }
 | |
| </programlisting>
 | |
|       </para>
 | |
| 
 | |
|       <para>There is really nothing scary about this.</para>
 | |
|     </sect2>
 | |
| 
 | |
|     <sect2>
 | |
|       <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_class;
 | |
| 
 | |
|   /* 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 */)
 | |
| {
 | |
|   g_return_if_fail (MAMAN_IS_BAR (self));
 | |
| 
 | |
|   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 dereference 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 dereference the class function) and is often difficult
 | |
|         to write in a portable way (the <emphasis>inline</emphasis> keyword
 | |
|         is part of the C99 standard but not every compiler supports it).
 | |
|       </para>
 | |
| 
 | |
|       <para>
 | |
|         In doubt, unless a user shows you hard numbers about the performance
 | |
|         cost of the function call, just implement <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
 | |
|         <function>class_init</function> 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 */)
 | |
| {
 | |
|   g_return_if_fail (MAMAN_IS_BAR (self));
 | |
| 
 | |
|   MAMAN_BAR_GET_CLASS (self)->do_action_one (self, /* parameters */);
 | |
| }
 | |
| 
 | |
| void
 | |
| maman_bar_do_action_two (MamanBar *self, /* parameters */)
 | |
| {
 | |
|   g_return_if_fail (MAMAN_IS_BAR (self));
 | |
| 
 | |
|   MAMAN_BAR_GET_CLASS (self)->do_action_two (self, /* parameters */);
 | |
| }
 | |
| </programlisting>
 | |
|       </para>
 | |
|     </sect2>
 | |
| 
 | |
|     <sect2>
 | |
|       <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>
 | |
|     </sect2>
 | |
|   </sect1>
 | |
| 
 | |
|   <sect1 id="howto-gobject-chainup">
 | |
|     <title>Chaining up</title>
 | |
|     
 | |
|     <para>Chaining up is often loosely defined by the following set of
 | |
|     conditions:
 | |
|       <itemizedlist>
 | |
|         <listitem><para>Parent class A defines a public virtual method named <function>foo</function> and 
 | |
|         provides a default implementation.</para></listitem>
 | |
|         <listitem><para>Child class B re-implements method <function>foo</function>.</para></listitem>
 | |
|         <listitem><para>In the method B::foo, the child class B calls its parent class method A::foo.</para></listitem>
 | |
|       </itemizedlist>
 | |
|       There are many uses to this idiom:
 | |
|       <itemizedlist>
 | |
|         <listitem><para>You need to change the behaviour of a class without modifying its code. You create
 | |
|           a subclass to inherit its implementation, re-implement a public virtual method to modify the behaviour
 | |
|           slightly and chain up to ensure that the previous behaviour is not really modified, just extended.
 | |
|           </para></listitem>
 | |
|         <listitem><para>You are lazy, you have access to the source code of the parent class but you don't want 
 | |
|           to modify it to add method calls to new specialized method calls: it is faster to hack the child class
 | |
|           to chain up than to modify the parent to call down.</para></listitem>
 | |
|         <listitem><para>You need to implement the Chain Of Responsibility pattern: each object of the inheritance
 | |
|           tree chains up to its parent (typically, at the beginning or the end of the method) to ensure that
 | |
|           they each handler is run in turn.</para></listitem>
 | |
|       </itemizedlist>
 | |
|       I am personally not really convinced any of the last two uses are really a good idea but since this
 | |
|       programming idiom is often used, this section attempts to explain how to implement it.
 | |
|     </para>
 | |
| 
 | |
|     <para>
 | |
|       To explicitly chain up to the implementation of the virtual method in the parent class, 
 | |
|       you first need a handle to the original parent class structure. This pointer can then be used to 
 | |
|       access the original class function pointer and invoke it directly.
 | |
|       <footnote>
 | |
|         <para>
 | |
|           The <emphasis>original</emphasis> adjective used in this sentence is not innocuous. To fully 
 | |
|           understand its meaning, you need to recall how class structures are initialized: for each object type,
 | |
|           the class structure associated to this object is created by first copying the class structure of its 
 | |
|           parent type (a simple <function>memcpy</function>) and then by invoking the class_init callback on 
 | |
|           the resulting class structure. Since the class_init callback is responsible for overwriting the class structure
 | |
|           with the user re-implementations of the class methods, we cannot merely use the modified copy of the parent class
 | |
|           structure stored in our derived instance. We want to get a copy of the class structure of an instance of the parent 
 | |
|           class.
 | |
|         </para>
 | |
|       </footnote>
 | |
|     </para>
 | |
|     
 | |
|     <para>The function <function><link linkend="g-type-class-peek-parent">g_type_class_peek_parent</link></function> is used to access the original parent 
 | |
|     class structure. Its input is a pointer to the class of the derived object and it returns a pointer
 | |
|     to the original parent class structure. The code below shows how you could use it:
 | |
| <programlisting>
 | |
| static void
 | |
| b_method_to_call (B *obj, int a)
 | |
| {
 | |
|   BClass *klass;
 | |
|   AClass *parent_class;
 | |
| 
 | |
|   klass = B_GET_CLASS (obj);
 | |
|   parent_class = g_type_class_peek_parent (klass);
 | |
| 
 | |
|   /* do stuff before chain up */
 | |
| 
 | |
|   parent_class->method_to_call (obj, a);
 | |
| 
 | |
|   /* do stuff after chain up */
 | |
| }
 | |
| </programlisting>
 | |
|   </para>
 | |
| 
 | |
|   </sect1>
 | |
| 
 | |
| </chapter>
 | |
| <!-- End Howto GObject -->
 | |
| 
 | |
| <chapter id="howto-interface">
 | |
|   <title>How to define and implement interfaces</title>
 | |
| 
 | |
|   <sect1 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.
 | |
|   </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_TYPE_IBAZ                 (maman_ibaz_get_type ())
 | |
| #define MAMAN_IBAZ(obj)                 (G_TYPE_CHECK_INSTANCE_CAST ((obj), MAMAN_TYPE_IBAZ, MamanIbaz))
 | |
| #define MAMAN_IS_IBAZ(obj)              (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MAMAN_TYPE_IBAZ))
 | |
| #define MAMAN_IBAZ_GET_INTERFACE(inst)  (G_TYPE_INSTANCE_GET_INTERFACE ((inst), MAMAN_TYPE_IBAZ, MamanIbazInterface))
 | |
| 
 | |
| 
 | |
| typedef struct _MamanIbaz               MamanIbaz; /* dummy object */
 | |
| typedef struct _MamanIbazInterface      MamanIbazInterface;
 | |
| 
 | |
| struct _MamanIbazInterface
 | |
| {
 | |
|   GTypeInterface parent_iface;
 | |
| 
 | |
|   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 the same as the code for a normal <link linkend="GType"><type>GType</type></link>
 | |
|     which derives from a <link linkend="GObject"><type>GObject</type></link> except for a few details:
 | |
|     <itemizedlist>
 | |
|       <listitem><para>
 | |
|         The <function>_GET_CLASS</function> macro is called <function>_GET_INTERFACE</function>
 | |
|                   and not implemented with <function><link linkend="G_TYPE_INSTANCE_GET_CLASS">G_TYPE_INSTANCE_GET_CLASS</link></function>
 | |
|                   but with <function><link linkend="G_TYPE_INSTANCE_GET_INTERFACE">G_TYPE_INSTANCE_GET_INTERFACE</link></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>
 | |
|       <listitem><para>
 | |
|         The parent of the <type>MamanIbazInterface</type> is not
 | |
|         <type>GObjectClass</type> but <type>GTypeInterface</type>.
 | |
|       </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 
 | |
|       instantiation)</para></listitem>
 | |
|       <listitem><para><function>maman_ibaz_do_action</function> dereferences
 | |
|       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 is_initialized = FALSE;
 | |
| 
 | |
|   if (!is_initialized)
 | |
|     {
 | |
|       /* add properties and signals to the interface here */
 | |
| 
 | |
|       is_initialized = TRUE;
 | |
|     }
 | |
| }
 | |
| 
 | |
| GType
 | |
| maman_ibaz_get_type (void)
 | |
| {
 | |
|   static GType iface_type = 0;
 | |
|   if (iface_type == 0)
 | |
|     {
 | |
|       static const GTypeInfo info = {
 | |
|         sizeof (MamanIbazInterface),
 | |
|         maman_ibaz_base_init,   /* base_init */
 | |
|         NULL,   /* base_finalize */
 | |
|       };
 | |
| 
 | |
|       iface_type = g_type_register_static (G_TYPE_INTERFACE, "MamanIbaz",
 | |
|                                            &info, 0);
 | |
|     }
 | |
| 
 | |
|   return iface_type;
 | |
| }
 | |
| 
 | |
| void
 | |
| maman_ibaz_do_action (MamanIbaz *self)
 | |
| {
 | |
|   g_return_if_fail (MAMAN_IS_IBAZ (self));
 | |
| 
 | |
|   MAMAN_IBAZ_GET_INTERFACE (self)->do_action (self);
 | |
| }
 | |
| </programlisting>
 | |
|     </para>
 | |
|   </sect1>
 | |
|   
 | |
|   <sect1 id="howto-interface-implement">
 | |
|     <title>How To define implement an Interface?</title>
 | |
|   
 | |
|     <para>
 | |
|       Once the interface is defined, implementing it is rather trivial.
 | |
|     </para>
 | |
|   
 | |
|     <para>
 | |
|       The first step is to define a normal GObject class, like:
 | |
| <programlisting>
 | |
| #ifndef __MAMAN_BAZ_H__
 | |
| #define __MAMAN_BAZ_H__
 | |
| 
 | |
| #include <glib-object.h>
 | |
| 
 | |
| #define MAMAN_TYPE_BAZ             (maman_baz_get_type ())
 | |
| #define MAMAN_BAZ(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), MAMAN_TYPE_BAZ, Mamanbaz))
 | |
| #define MAMAN_IS_BAZ(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MAMAN_TYPE_BAZ))
 | |
| #define MAMAN_BAZ_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), MAMAN_TYPE_BAZ, MamanbazClass))
 | |
| #define MAMAN_IS_BAZ_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), MAMAN_TYPE_BAZ))
 | |
| #define MAMAN_BAZ_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), MAMAN_TYPE_BAZ, MamanbazClass))
 | |
| 
 | |
| 
 | |
| typedef struct _MamanBaz        MamanBaz;
 | |
| typedef struct _MamanBazClass   MamanBazClass;
 | |
| 
 | |
| struct _MamanBaz
 | |
| {
 | |
|   GObject parent_instance;
 | |
| 
 | |
|   int instance_member;
 | |
| };
 | |
| 
 | |
| struct _MamanBazClass
 | |
| {
 | |
|   GObjectClass parent_class;
 | |
| };
 | |
| 
 | |
| 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 <type>MamanBaz</type> by defining
 | |
|       its GType. Instead of using <function>G_DEFINE_TYPE</function> we
 | |
|       use <function>G_DEFINE_TYPE_WITH_CODE</function> and the
 | |
|       <function>G_IMPLEMENT_INTERFACE</function> macros.
 | |
| <programlisting>
 | |
| static void maman_ibaz_interface_init (MamanIbazInterface *iface);
 | |
| 
 | |
| G_DEFINE_TYPE_WITH_CODE (MamanBar, maman_bar, G_TYPE_OBJECT,
 | |
|                          G_IMPLEMENT_INTERFACE (MAMAN_TYPE_IBAZ,
 | |
|                                                 maman_ibaz_interface_init));
 | |
| </programlisting>
 | |
|       This definition 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_IMPLEMENT_INTERFACE</function>. 
 | |
|     </para>
 | |
| 
 | |
|     <note><para>Classes can implement multiple interfaces by using multiple
 | |
|     calls to <function>G_IMPLEMENT_INTERFACE</function> inside the call
 | |
|     to <function>G_DEFINE_TYPE_WITH_CODE</function>.</para></note>
 | |
|   
 | |
|     <para>
 | |
|       <function>maman_baz_interface_init</function>, the interface
 | |
|       initialization function: inside it every virtual method of the interface
 | |
|       must be assigned to its implementation:
 | |
| <programlisting>
 | |
| static void
 | |
| maman_baz_do_action (MamanBaz *self)
 | |
| {
 | |
|   g_print ("Baz implementation of IBaz interface Action: 0x%x.\n",
 | |
|            self->instance_member);
 | |
| }
 | |
| 
 | |
| static void
 | |
| maman_ibaz_interface_init (MamanIbazInterface *iface)
 | |
| {
 | |
|   iface->do_action = baz_do_action;
 | |
| }
 | |
| 
 | |
| static void
 | |
| maman_baz_init (MamanBaz *self)
 | |
| {
 | |
|   MamanBaz *self = MAMAN_BAZ (instance);
 | |
|   self->instance_member = 0xdeadbeaf;
 | |
| }
 | |
| </programlisting>
 | |
|     </para>
 | |
|   
 | |
|   </sect1>
 | |
|   
 | |
|   <sect1>
 | |
|     <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>
 | |
|   /* inside the GType function of the MamanIbar interface */
 | |
|   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_TYPE_IBAZ);
 | |
| </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
 | |
| maman_ibar_do_another_action (MamanIbar *ibar)
 | |
| {
 | |
|   MamanBar *self = MAMAN_BAR (ibar);
 | |
| 
 | |
|   g_print ("Bar implementation of IBar interface Another Action: 0x%x.\n",
 | |
|            self->instance_member);
 | |
| }
 | |
| 
 | |
| static void
 | |
| maman_ibar_interface_init (MamanIbarInterface *iface)
 | |
| {
 | |
|   iface->do_another_action = maman_ibar_do_another_action;
 | |
| }
 | |
| 
 | |
| static void
 | |
| maman_ibaz_do_action (MamanIbaz *ibaz)
 | |
| {
 | |
|   MamanBar *self = MAMAN_BAR (ibaz);
 | |
| 
 | |
|   g_print ("Bar implementation of IBaz interface Action: 0x%x.\n",
 | |
|            self->instance_member);
 | |
| }
 | |
| 
 | |
| static void
 | |
| maman_ibaz_interface_init (MamanIbazInterface *iface)
 | |
| {
 | |
|   iface->do_action = maman_ibaz_do_action;
 | |
| }
 | |
| 
 | |
| static void
 | |
| maman_bar_class_init (MamanBarClass *klass)
 | |
| {
 | |
| 
 | |
| }
 | |
| 
 | |
| static void
 | |
| maman_bar_init (MamanBar *self)
 | |
| {
 | |
|   self->instance_member = 0x666;
 | |
| }
 | |
| 
 | |
| G_DEFINE_TYPE_WITH_CODE (MamanBar, maman_bar, G_TYPE_OBJECT,
 | |
|                          G_IMPLEMENT_INTERFACE (MAMAN_TYPE_IBAZ,
 | |
|                                                 maman_ibaz_interface_init)
 | |
|                          G_IMPLEMENT_INTERFACE (MAMAN_TYPE_IBAR,
 | |
|                                                 maman_ibar_interface_init));
 | |
| </programlisting>
 | |
|       It is very important to notice that the order in which interface
 | |
|       implementations are added to the main object is not random:
 | |
|       <function><link linkend="g-type-add-interface-static">g_type_add_interface_static</link></function>,
 | |
|       which is called by <function>G_IMPLEMENT_INTERFACE</function>, must be
 | |
|       invoked first on the interfaces which have no prerequisites and then on
 | |
|       the others.
 | |
|     </para>
 | |
|   </sect1>
 | |
|   
 | |
|   <sect1 id="howto-interface-properties">
 | |
|     <title>Interface Properties</title>
 | |
|   
 | |
|     <para>
 | |
|       Starting from version 2.4 of GLib, GObject interfaces can also have
 | |
|       properties. Declaration of the interface properties is similar to
 | |
|       declaring the properties of ordinary GObject types as explained in
 | |
|       <xref linkend="gobject-properties"/>, 
 | |
|       except that <function><link linkend="g-object-interface-install-property">g_object_interface_install_property</link></function> is used to 
 | |
|       declare the properties instead of <function><link linkend="g-object-class-install-property">g_object_class_install_property</link></function>.
 | |
|     </para>
 | |
|   
 | |
|     <para>
 | |
|       To include a property named 'name' of type <type>string</type> in the 
 | |
|       <type>maman_ibaz</type> interface example code above, we only need to
 | |
|       add one 
 | |
|       <footnote>
 | |
|         <para>
 | |
|           That really is one line extended to six for the sake of clarity
 | |
|         </para>
 | |
|       </footnote>  
 | |
|       line in the <function>maman_ibaz_base_init</function>
 | |
|       <footnote>
 | |
|         <para>
 | |
|           The <function><link linkend="g-object-interface-install-property">g_object_interface_install_property</link></function>
 | |
|           can also be called from <function>class_init</function> but it must
 | |
|           not be called after that point.
 | |
|         </para>
 | |
|       </footnote>
 | |
|       as shown below:
 | |
| <programlisting>
 | |
| static void
 | |
| maman_ibaz_base_init (gpointer g_iface)
 | |
| {
 | |
|   static gboolean is_initialized = FALSE;
 | |
| 
 | |
|   if (!is_initialized)
 | |
|     {
 | |
|       g_object_interface_install_property (g_iface,
 | |
|                                            g_param_spec_string ("name",
 | |
|                                                                 "Name",
 | |
|                                                                 "Name of the MamanIbaz",
 | |
|                                                                 "maman",
 | |
|                                                                 G_PARAM_READWRITE));
 | |
|       is_initialized = TRUE;
 | |
|     }
 | |
| }
 | |
| </programlisting>
 | |
|     </para>
 | |
|   
 | |
|     <para>
 | |
|       One point worth noting is that the declared property wasn't assigned an 
 | |
|       integer ID. The reason being that integer IDs of properties are used
 | |
|       only inside the get and set methods and since interfaces do not
 | |
|       implement properties, there is no need to assign integer IDs to
 | |
|       interface properties.
 | |
|     </para>
 | |
|     
 | |
|     <para>
 | |
|       An implementation shall declare and define it's properties in the usual
 | |
|       way as explained in <xref linkend="gobject-properties"/>, except for one
 | |
|       small change: it must declare the properties of the interface it
 | |
|       implements using <function><link linkend="g-object-class-override-property">g_object_class_override_property</link></function>
 | |
|       instead of <function><link linkend="g-object-class-install-property">g_object_class_install_property</link></function>.
 | |
|       The following code snippet shows the modifications needed in the
 | |
|       <type>MamanBaz</type> declaration and implementation above:
 | |
| <programlisting>
 | |
| 
 | |
| struct _MamanBaz
 | |
| {
 | |
|   GObject parent_instance;
 | |
| 
 | |
|   gint instance_member;
 | |
|   gchar *name;
 | |
| };
 | |
| 
 | |
| enum
 | |
| {
 | |
|   PROP_0,
 | |
| 
 | |
|   PROP_NAME
 | |
| };
 | |
| 
 | |
| static void
 | |
| maman_baz_set_property (GObject      *object,
 | |
|                         guint         property_id,
 | |
|                         const GValue *value,
 | |
|                         GParamSpec   *pspec)
 | |
| {
 | |
|   MamanBaz *baz = MAMAN_BAZ (object);
 | |
|   GObject *obj;
 | |
| 
 | |
|   switch (prop_id)
 | |
|     {
 | |
|     case ARG_NAME:
 | |
|       g_free (baz->name);
 | |
|       baz->name = g_value_dup_string (value);
 | |
|       break;
 | |
| 
 | |
|     default:
 | |
|       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 | |
|       break;
 | |
|     }
 | |
| }
 | |
| 
 | |
| static void
 | |
| maman_baz_get_property (GObject    *object,
 | |
|                         guint       prop_id,
 | |
|                         GValue     *value,
 | |
|                         GParamSpec *pspec)
 | |
| {
 | |
|   MamanBaz *baz = MAMAN_BAZ (object);
 | |
| 
 | |
|   switch (prop_id)
 | |
|     {
 | |
|     case ARG_NAME:
 | |
|       g_value_set_string (value, baz->name);
 | |
|       break;
 | |
| 
 | |
|     default:
 | |
|       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 | |
|       break;
 | |
|     }
 | |
| }
 | |
| 
 | |
| static void
 | |
| maman_baz_class_init (MamanBazClass *klass)
 | |
| {
 | |
|   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
 | |
| 
 | |
|   gobject_class->set_property = maman_baz_set_property;
 | |
|   gobject_class->get_property = maman_baz_get_property;
 | |
| 
 | |
|   g_object_class_override_property (gobject_class, PROP_NAME, "name");
 | |
| }
 | |
| 
 | |
| </programlisting>
 | |
|     </para>
 | |
|   
 | |
|   </sect1>
 | |
| </chapter>
 | |
| <!-- End Howto Interfaces -->
 | |
| 
 | |
| <chapter id="howto-signals">
 | |
|   <title>How to 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 signals which
 | |
|     can be received by numerous clients. 
 | |
|   </para>
 | |
| 
 | |
|   <sect1 id="howto-simple-signals">
 | |
|     <title>Simple use of signals</title>
 | |
| 
 | |
|     <para>
 | |
|       The most basic use of signals is to implement simple event
 | |
|       notification: for example, if we have a MamanFile object, and
 | |
|       if this object has a write method, we might wish to be notified
 | |
|       whenever someone has changed something via our MamanFile instance.
 | |
|       The code below shows how the user can connect a callback to the
 | |
|       "changed" signal.
 | |
| <programlisting>
 | |
| file = g_object_new (MAMAN_FILE_TYPE, NULL);
 | |
| 
 | |
| g_signal_connect (file, "changed", G_CALLBACK (changed_event), NULL);
 | |
| 
 | |
| maman_file_write (file, buffer, strlen (buffer));
 | |
| </programlisting>
 | |
|     </para>
 | |
|     
 | |
|     <para>
 | |
|       The <type>MamanFile</type> signal is registered in the class_init
 | |
|       function:
 | |
| <programlisting>
 | |
| file_signals[CHANGED] = 
 | |
|   g_signal_newv ("changed",
 | |
|                  G_TYPE_FROM_CLASS (gobject_class),
 | |
|                  G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
 | |
|                  NULL /* closure */,
 | |
|                  NULL /* accumulator */,
 | |
|                  NULL /* accumulator data */,
 | |
|                  g_cclosure_marshal_VOID__VOID,
 | |
|                  G_TYPE_NONE /* return_type */,
 | |
|                  0     /* n_params */,
 | |
|                  NULL  /* param_types */);
 | |
| </programlisting>
 | |
|       and the signal is emitted in <function>maman_file_write</function>:
 | |
| <programlisting>
 | |
| void
 | |
| maman_file_write (MamanFile    *self,
 | |
|                   const guchar *buffer,
 | |
|                   gssize        size)
 | |
| {
 | |
|   /* First write data. */
 | |
| 
 | |
|   /* Then, notify user of data written. */
 | |
|   g_signal_emit (self, file_signals[CHANGED], 0 /* details */);
 | |
| }
 | |
| </programlisting>
 | |
|       As shown above, you can safely set the details parameter to zero if
 | |
|       you do not know what it can be used for. For a discussion of what you
 | |
|       could used it for, see <xref linkend="signal-detail"/>
 | |
|     </para>
 | |
| 
 | |
|     <para>
 | |
|       The signature of the signal handler in the above example is defined as
 | |
|       <function>g_cclosure_marshal_VOID__VOID</function>. Its name follows
 | |
|       a simple convention which encodes the function parameter and return value
 | |
|       types in the function name. Specifically, the value in front of the
 | |
|       double underscore is the type of the return value, while the value(s)
 | |
|       after the double underscore denote the parameter types.
 | |
|     </para>
 | |
| 
 | |
|     <para>
 | |
|       The header <filename>gobject/gmarshal.h</filename> defines a set of
 | |
|       commonly needed closures that one can use. If you want to have complex
 | |
|       marshallers for your signals you should probably use glib-genmarshal
 | |
|       to autogenerate them from a file containing their return and
 | |
|       parameter types.
 | |
|     </para>
 | |
|   </sect1>
 | |
| 
 | |
| <!-- 
 | |
|   this is utterly wrong and should be completely removed - or rewritten
 | |
|   with a better example than writing a buffer using synchronous signals.
 | |
| 
 | |
|   <sect1>
 | |
|     <title>How to provide more flexibility to users?</title>
 | |
| 
 | |
|     <para>
 | |
|       The previous implementation does the job but the signal facility of
 | |
|       GObject can be used to provide even more flexibility to this file
 | |
|       change notification mechanism. One of the key ideas is to make the
 | |
|       process of writing data to the file part of the signal emission
 | |
|       process to allow users to be notified either before or after the
 | |
|       data is written to the file.
 | |
|     </para>
 | |
|     
 | |
|     <para>
 | |
|       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 glib-genmarshal 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><link linkend="g-signal-connect">g_signal_connect</link></function>
 | |
|       and before all handlers connected with <function><link linkend="g-signal-connect-after">g_signal_connect_after</link></function>. If you intent to write a GObject
 | |
|       which emits signals, I would thus urge you to create all your signals with the G_SIGNAL_RUN_LAST such that your users
 | |
|       have a maximum of flexibility as to when to get the event. Here, we combined it with G_SIGNAL_NO_RECURSE and 
 | |
|       G_SIGNAL_NO_HOOKS to ensure our users will not try to do really weird things with our GObject. I strongly advise you
 | |
|       to do the same unless you really know why (in which case you really know the inner workings of GSignal by heart and
 | |
|       you are not reading this).
 | |
|     </para>
 | |
|     
 | |
|     <para>
 | |
| <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>
 | |
| 
 | |
| -->
 | |
| 
 | |
| <!--
 | |
|   this is also utterly wrong on so many levels that I don't even want
 | |
|   to enumerate them. it's also full of completely irrelevant footnotes
 | |
|   about personal preferences demonstrating a severe lack of whatsoever
 | |
|   clue. the whole idea of storing the signal ids inside the Class
 | |
|   structure is so fundamentally flawed that I'll require a frontal
 | |
|   lobotomy just to forget I've ever seen it.
 | |
| 
 | |
|     <sect2>
 | |
|     <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 unnecessarily 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 extremely doubtful 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><link linkend="g-signal-newv">g_signal_newv</link></function>.
 | |
|       </para>
 | |
|     
 | |
|       <para>For example, <function><link linkend="g-signal-new">g_signal_new</link></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><link linkend="g-signal-new">g_signal_new</link></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 initialized 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><link linkend="g-signal-new">g_signal_new</link></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><link linkend="G-STRUCT-OFFSET">G_STRUCT_OFFSET</link></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 cluttered 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><link linkend="g-signal-new">g_signal_new</link></function> rather than <function><link linkend="g-signal-newv">g_signal_newv</link></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>
 | |
| 
 | |
|    </sect2>
 | |
| 
 | |
|   </sect1>
 | |
| -->
 | |
| 
 | |
| <!--
 | |
|   yet another pointless section. if we are scared of possible abuses
 | |
|   from the users then we should not be mentioning it inside a tutorial
 | |
|   for beginners. but, obviously, there's nothing to be afraid of - it's
 | |
|   just that this section must be completely reworded.
 | |
| 
 | |
|   <sect1>
 | |
|     <title>How users can abuse signals (and why some think it is good)</title>
 | |
| 
 | |
|     <para>Now that you know how to create signals to which the users can connect easily and at any point in
 | |
|       the signal emission process thanks to <function><link linkend="g-signal-connect">g_signal_connect</link></function>, 
 | |
|       <function><link linkend="g-signal-connect-after">g_signal_connect_after</link></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 preferred 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><link linkend="g-signal-stop-by-name">g_signal_stop_by_name</link></function>. Its use is very simple which is why I won't detail 
 | |
|       it further.
 | |
|     </para>
 | |
|     
 | |
|     <para>
 | |
|       If the signal's default handler is just a class function pointer, it is also possible to override 
 | |
|       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>
 | |
| 
 | |
|   </sect1>
 | |
| 
 | |
| -->
 | |
| 
 | |
| </chapter>
 | |
| 
 | |
| <!--
 | |
|   <sect2>
 | |
|     <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><link linkend="g-signal-new">g_signal_new</link></function> function is preferred over
 | |
|       <function><link linkend="g-signal-newv">g_signal_newv</link></function>. When <function><link linkend="g-signal-new">g_signal_new</link></function>
 | |
|       is used, the default closure is exported as a class function. For example,
 | |
|       <filename>gobject.h</filename> contains the declaration of <link linkend="GObjectClass"><type>GObjectClass</type></link>
 | |
|       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><link linkend="g-object-do-class-init">g_object_do_class_init</link></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><link linkend="g-signal-new">g_signal_new</link></function> creates a <link linkend="GClosure"><type>GClosure</type></link> which dereferences 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 dereferencing 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>
 | |
| 
 | |
|     </sect2>
 | |
| -->
 | |
| </part>
 |