mirror of
				https://gitlab.gnome.org/GNOME/glib.git
				synced 2025-11-01 00:42:16 +01:00 
			
		
		
		
	
		
			
	
	
		
			1453 lines
		
	
	
		
			55 KiB
		
	
	
	
		
			XML
		
	
	
	
	
	
		
		
			
		
	
	
			1453 lines
		
	
	
		
			55 KiB
		
	
	
	
		
			XML
		
	
	
	
	
	
|   | <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> | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 |