| <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> |
| |
| |
| |
| |
| |