| <?xml version='1.0' encoding="ISO-8859-1"?> |
| <!DOCTYPE part PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN" |
| "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" [ |
| ]> |
| <part label="IV"> |
| <title>Tutorial</title> |
| <partintro> |
| <para> |
| This chapter tries to answer the real-life questions of users and presents |
| the most common scenario use cases I could come up with. |
| The use cases are presented from most likely to less likely. |
| </para> |
| </partintro> |
| |
| <chapter id="howto-gobject"> |
| <title>How to define and implement a new GObject</title> |
| |
| <para> |
| Clearly, this is one of the most common questions people ask: they just |
| want to crank code and implement a subclass of a GObject. Sometimes because |
| they want to create their own class hierarchy, sometimes because they want |
| to subclass one of GTK+'s widget. This chapter will focus on the |
| implementation of a subtype of GObject. |
| </para> |
| |
| <sect1 id="howto-gobject-header"> |
| <title>Boilerplate header code</title> |
| |
| <para> |
| The first step before writing the code for your GObject is to write the |
| type's header which contains the needed type, function and macro |
| definitions. Each of these elements is nothing but a convention which |
| is followed not only by GTK+'s code but also by most users of GObject. |
| If you feel the need not to obey the rules stated below, think about it |
| twice: |
| <itemizedlist> |
| <listitem><para>If your users are a bit accustomed to GTK+ code or any |
| GLib code, they will be a bit surprised and getting used to the |
| conventions you decided upon will take time (money) and will make them |
| grumpy (not a good thing)</para></listitem> |
| <listitem><para>You must assess the fact that these conventions might |
| have been designed by both smart and experienced people: maybe they |
| were at least partly right. Try to put your ego aside.</para></listitem> |
| </itemizedlist> |
| </para> |
| |
| <para> |
| Pick a name convention for your headers and source code and stick to it: |
| <itemizedlist> |
| <listitem><para>use a dash to separate the prefix from the typename: |
| <filename>maman-bar.h</filename> and <filename>maman-bar.c</filename> |
| (this is the convention used by Nautilus and most GNOME libraries).</para></listitem> |
| <listitem><para>use an underscore to separate the prefix from the |
| typename: <filename>maman_bar.h</filename> and |
| <filename>maman_bar.c</filename>.</para></listitem> |
| <listitem><para>Do not separate the prefix from the typename: |
| <filename>mamanbar.h</filename> and <filename>mamanbar.c</filename>. |
| (this is the convention used by GTK+)</para></listitem> |
| </itemizedlist> |
| I personally like the first solution better: it makes reading file names |
| easier for those with poor eyesight like me. |
| </para> |
| |
| <para> |
| When you need some private (internal) declarations in several |
| (sub)classes, you can define them in a private header file which |
| is often named by appending the <emphasis>private</emphasis> keyword |
| to the public header name. For example, one could use |
| <filename>maman-bar-private.h</filename>, |
| <filename>maman_bar_private.h</filename> or |
| <filename>mamanbarprivate.h</filename>. Typically, such private header |
| files are not installed. |
| </para> |
| |
| <para> |
| The basic conventions for any header which exposes a GType are described |
| in <xref linkend="gtype-conventions"/>. Most GObject-based code also |
| obeys one of of the following conventions: pick one and stick to it. |
| <itemizedlist> |
| <listitem><para> |
| If you want to declare a type named bar with prefix maman, name the type instance |
| <function>MamanBar</function> and its class <function>MamanBarClass</function> |
| (name is case-sensitive). It is customary to declare them with code similar to the |
| following: |
| <programlisting> |
| /* |
| * Copyright/Licensing information. |
| */ |
| |
| /* inclusion guard */ |
| #ifndef __MAMAN_BAR_H__ |
| #define __MAMAN_BAR_H__ |
| |
| #include <glib-object.h> |
| /* |
| * Potentially, include other headers on which this header depends. |
| */ |
| |
| /* |
| * Type macros. |
| */ |
| #define MAMAN_TYPE_BAR (maman_bar_get_type ()) |
| #define MAMAN_BAR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MAMAN_TYPE_BAR, MamanBar)) |
| #define MAMAN_IS_BAR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MAMAN_TYPE_BAR)) |
| #define MAMAN_BAR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MAMAN_TYPE_BAR, MamanBarClass)) |
| #define MAMAN_IS_BAR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MAMAN_TYPE_BAR)) |
| #define MAMAN_BAR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MAMAN_TYPE_BAR, MamanBarClass)) |
| |
| typedef struct _MamanBar MamanBar; |
| typedef struct _MamanBarClass MamanBarClass; |
| |
| struct _MamanBar |
| { |
| GObject parent_instance; |
| |
| /* instance members */ |
| }; |
| |
| struct _MamanBarClass |
| { |
| GObjectClass parent_class; |
| |
| /* class members */ |
| }; |
| |
| /* used by MAMAN_TYPE_BAR */ |
| GType maman_bar_get_type (void); |
| |
| /* |
| * Method definitions. |
| */ |
| |
| #endif /* __MAMAN_BAR_H__ */ |
| </programlisting> |
| </para></listitem> |
| <listitem><para> |
| Most GTK+ types declare their private fields in the public header |
| with a /* private */ comment, relying on their user's intelligence |
| not to try to play with these fields. Fields not marked private |
| are considered public by default. The /* protected */ comment |
| (same semantics as those of C++) is also used, mainly in the GType |
| library, in code written by Tim Janik. |
| <programlisting> |
| struct _MamanBar |
| { |
| GObject parent_instance; |
| |
| /*< private >*/ |
| int hsize; |
| }; |
| </programlisting> |
| </para></listitem> |
| <listitem><para> |
| All of Nautilus code and a lot of GNOME libraries use private |
| indirection members, as described by Herb Sutter in his Pimpl |
| articles(see <ulink url="http://www.gotw.ca/gotw/024.htm">Compilation Firewalls</ulink> |
| and <ulink url="http://www.gotw.ca/gotw/028.htm">The Fast Pimpl Idiom</ulink>: |
| he summarizes the different issues better than I will). |
| <programlisting> |
| typedef struct _MamanBarPrivate MamanBarPrivate; |
| |
| struct _MamanBar |
| { |
| GObject parent_instance; |
| |
| /*< private >*/ |
| MamanBarPrivate *priv; |
| }; |
| </programlisting> |
| <note><simpara>Do not call this <varname>private</varname>, as |
| that is a registered c++ keyword.</simpara></note> |
| |
| The private structure is then defined in the .c file, using the |
| g_type_class_add_private() function to notify the presence of |
| a private memory area for each instance and it can either |
| be retrieved using <function>G_TYPE_INSTANCE_GET_PRIVATE()</function> |
| each time is needed, or assigned to the <literal>priv</literal> |
| member of the instance structure inside the object's |
| <function>init</function> function. |
| <programlisting> |
| #define MAMAN_BAR_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), MAMAN_TYPE_BAR, MamanBarPrivate)) |
| |
| struct _MamanBarPrivate |
| { |
| int hsize; |
| } |
| |
| static void |
| maman_bar_class_init (MamanBarClass *klass) |
| { |
| g_type_class_add_private (klass, sizeof (MamanBarPrivate)); |
| } |
| |
| static void |
| maman_bar_init (MamanBar *self) |
| { |
| MamanBarPrivate *priv; |
| |
| self->priv = priv = MAMAN_BAR_GET_PRIVATE (self); |
| |
| priv->hsize = 42; |
| } |
| </programlisting> |
| </para></listitem> |
| |
| <listitem><para> |
| You don't need to free or allocate the private structure, only the |
| objects or pointers that it may contain. Another advantage of this |
| to the previous version is that is lessens memory fragmentation, |
| as the public and private parts of the instance memory are |
| allocated at once. |
| </para></listitem> |
| </itemizedlist> |
| </para> |
| |
| <para> |
| Finally, there are different header include conventions. Again, pick one |
| and stick to it. I personally use indifferently any of the two, depending |
| on the codebase I work on: the rule, as always, is consistency. |
| <itemizedlist> |
| <listitem><para> |
| Some people add at the top of their headers a number of #include |
| directives to pull in all the headers needed to compile client |
| code. This allows client code to simply #include "maman-bar.h". |
| </para></listitem> |
| <listitem><para> |
| Other do not #include anything and expect the client to #include |
| themselves the headers they need before including your header. This |
| speeds up compilation because it minimizes the amount of |
| pre-processor work. This can be used in conjunction with the |
| re-declaration of certain unused types in the client code to |
| minimize compile-time dependencies and thus speed up compilation. |
| </para></listitem> |
| </itemizedlist> |
| </para> |
| |
| </sect1> |
| |
| <sect1 id="howto-gobject-code"> |
| <title>Boilerplate code</title> |
| |
| <para> |
| In your code, the first step is to #include the needed headers: depending |
| on your header include strategy, this can be as simple as |
| <literal>#include "maman-bar.h"</literal> or as complicated as tens |
| of #include lines ending with <literal>#include "maman-bar.h"</literal>: |
| <programlisting> |
| /* |
| * Copyright information |
| */ |
| |
| #include "maman-bar.h" |
| |
| /* If you use Pimpls, include the private structure |
| * definition here. Some people create a maman-bar-private.h header |
| * which is included by the maman-bar.c file and which contains the |
| * definition for this private structure. |
| */ |
| struct _MamanBarPrivate { |
| int member_1; |
| /* stuff */ |
| }; |
| |
| /* |
| * forward definitions |
| */ |
| </programlisting> |
| </para> |
| |
| <para> |
| Call the <function>G_DEFINE_TYPE</function> macro using the name |
| of the type, the prefix of the functions and the parent GType to |
| reduce the amount of boilerplate needed. This macro will: |
| |
| <itemizedlist> |
| <listitem><simpara>implement the <function>maman_bar_get_type</function> |
| function</simpara></listitem> |
| <listitem><simpara>define a parent class pointer accessible from |
| the whole .c file</simpara></listitem> |
| </itemizedlist> |
| |
| <programlisting> |
| G_DEFINE_TYPE (MamanBar, maman_bar, G_TYPE_OBJECT); |
| </programlisting> |
| </para> |
| |
| <para> |
| It is also possible to use the |
| <function>G_DEFINE_TYPE_WITH_CODE</function> macro to control the |
| get_type function implementation - for instance, to add a call to |
| <function>G_IMPLEMENT_INTERFACE</function> macro which will |
| call the <function>g_type_implement_interface</function> function. |
| </para> |
| </sect1> |
| |
| <sect1 id="howto-gobject-construction"> |
| <title>Object Construction</title> |
| |
| <para> |
| People often get confused when trying to construct their GObjects because of the |
| sheer number of different ways to hook into the objects's construction process: it is |
| difficult to figure which is the <emphasis>correct</emphasis>, recommended way. |
| </para> |
| |
| <para> |
| <xref linkend="gobject-construction-table"/> shows what user-provided functions |
| are invoked during object instantiation and in which order they are invoked. |
| A user looking for the equivalent of the simple C++ constructor function should use |
| the instance_init method. It will be invoked after all the parent's instance_init |
| functions have been invoked. It cannot take arbitrary construction parameters |
| (as in C++) but if your object needs arbitrary parameters to complete initialization, |
| you can use construction properties. |
| </para> |
| |
| <para> |
| Construction properties will be set only after all instance_init functions have run. |
| No object reference will be returned to the client of <function><link linkend="g-object-new">g_object_new</link></function> |
| until all the construction properties have been set. |
| </para> |
| |
| <para> |
| As such, I would recommend writing the following code first: |
| <programlisting> |
| static void |
| maman_bar_init (MamanBar *self) |
| { |
| self->priv = MAMAN_BAR_GET_PRIVATE (self); |
| |
| /* initialize all public and private members to reasonable default values. */ |
| |
| /* If you need specific construction properties to complete initialization, |
| * delay initialization completion until the property is set. |
| */ |
| } |
| </programlisting> |
| </para> |
| |
| <para> |
| Now, if you need special construction properties, install the properties in the class_init function, |
| override the set and get methods and implement the get and set methods as described in |
| <xref linkend="gobject-properties"/>. Make sure that these properties use a construct only |
| <type><link linkend="GParamSpec">GParamSpec</link></type> 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><link linkend="g-object-new">g_object_new</link></function> |
| with the required construction properties, these will be initialized with the default values. |
| </para> |
| |
| <para> |
| I consider good taste to halt program execution if a construction property is set its |
| default value. This allows you to catch client code which does not give a reasonable |
| value to the construction properties. Of course, you are free to disagree but you |
| should have a good reason to do so. |
| </para> |
| |
| <para> |
| Some people sometimes need to construct their object but only after |
| the construction properties have been set. This is possible through |
| the use of the constructor class method as described in |
| <xref linkend="gobject-instantiation"/> or, more simply, using |
| the constructed class method available since GLib 2.12. |
| </para> |
| </sect1> |
| |
| <sect1 id="howto-gobject-destruction"> |
| <title>Object Destruction</title> |
| |
| <para> |
| Again, it is often difficult to figure out which mechanism to use to |
| hook into the object's destruction process: when the last |
| <function><link linkend="g-object-unref">g_object_unref</link></function> |
| function call is made, a lot of things happen as described in |
| <xref linkend="gobject-destruction-table"/>. |
| </para> |
| |
| <para> |
| The destruction process of your object might be split in two different |
| phases: dispose and the finalize. |
| <programlisting> |
| #define MAMAN_BAR_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), MAMAN_TYPE_BAR, MamanBarPrivate)) |
| |
| struct _MamanBarPrivate |
| { |
| GObject *an_object; |
| |
| gchar *a_string; |
| }; |
| |
| G_DEFINE_TYPE (MamanBar, maman_bar, G_TYPE_OBJECT); |
| |
| static void |
| maman_bar_dispose (GObject *gobject) |
| { |
| MamanBar *self = MAMAN_BAR (gobject); |
| |
| /* |
| * In dispose, you are supposed to free all types referenced from this |
| * object which might themselves hold a reference to self. Generally, |
| * the most simple solution is to unref all members on which you own a |
| * reference. |
| */ |
| |
| /* dispose might be called multiple times, so we must guard against |
| * calling g_object_unref() on an invalid GObject. |
| */ |
| if (self->priv->an_object) |
| { |
| g_object_unref (self->priv->an_object); |
| |
| self->priv->an_object = NULL; |
| } |
| |
| /* Chain up to the parent class */ |
| G_OBJECT_CLASS (maman_bar_parent_class)->dispose (gobject); |
| } |
| |
| static void |
| maman_bar_finalize (GObject *gobject) |
| { |
| MamanBar *self = MAMAN_BAR (gobject); |
| |
| g_free (self->priv->a_string); |
| |
| /* Chain up to the parent class */ |
| G_OBJECT_CLASS (maman_bar_parent_class)->finalize (gobject); |
| } |
| |
| static void |
| maman_bar_class_init (MamanBarClass *klass) |
| { |
| GObjectClass *gobject_class = G_OBJECT_CLASS (klass); |
| |
| gobject_class->dispose = maman_bar_dispose; |
| gobject_class->finalize = maman_bar_finalize; |
| |
| g_type_class_add_private (klass, sizeof (MamanBarPrivate)); |
| } |
| |
| static void |
| maman_bar_init (MamanBar *self); |
| { |
| self->priv = MAMAN_BAR_GET_PRIVATE (self); |
| |
| self->priv->an_object = g_object_new (MAMAN_TYPE_BAZ, NULL); |
| self->priv->a_string = g_strdup ("Maman"); |
| } |
| </programlisting> |
| </para> |
| |
| <para> |
| Add similar code to your GObject, make sure the code still builds |
| and runs: dispose and finalize must be called during the last unref. |
| </para> |
| |
| <para> |
| It is possible that object methods might be invoked after dispose is |
| run and before finalize runs. GObject does not consider this to be a |
| program error: you must gracefully detect this and neither crash nor |
| warn the user. |
| </para> |
| </sect1> |
| |
| <sect1 id="howto-gobject-methods"> |
| <title>Object methods</title> |
| |
| <para> |
| Just as with C++, there are many different ways to define object |
| methods and extend them: the following list and sections draw on |
| C++ vocabulary. (Readers are expected to know basic C++ buzzwords. |
| Those who have not had to write C++ code recently can refer to e.g. |
| <ulink url="http://www.cplusplus.com/doc/tutorial/"/> to refresh |
| their memories.) |
| <itemizedlist> |
| <listitem><para> |
| non-virtual public methods, |
| </para></listitem> |
| <listitem><para> |
| virtual public methods and |
| </para></listitem> |
| <listitem><para> |
| virtual private methods |
| </para></listitem> |
| </itemizedlist> |
| </para> |
| |
| <sect2> |
| <title>Non-virtual public methods</title> |
| |
| <para> |
| These are the simplest: you want to provide a simple method which |
| can act on your object. All you need to do is to provide a function |
| prototype in the header and an implementation of that prototype |
| in the source file. |
| <programlisting> |
| /* declaration in the header. */ |
| void maman_bar_do_action (MamanBar *self, /* parameters */); |
| |
| /* implementation in the source file */ |
| void |
| maman_bar_do_action (MamanBar *self, /* parameters */) |
| { |
| g_return_if_fail (MAMAN_IS_BAR (self)); |
| |
| /* do stuff here. */ |
| } |
| </programlisting> |
| </para> |
| |
| <para>There is really nothing scary about this.</para> |
| </sect2> |
| |
| <sect2> |
| <title>Virtual public methods</title> |
| |
| <para> |
| This is the preferred way to create polymorphic GObjects. All you |
| need to do is to define the common method and its class function in |
| the public header, implement the common method in the source file |
| and re-implement the class function in each object which inherits |
| from you. |
| <programlisting> |
| /* declaration in maman-bar.h. */ |
| struct _MamanBarClass |
| { |
| GObjectClass parent_class; |
| |
| /* stuff */ |
| void (*do_action) (MamanBar *self, /* parameters */); |
| }; |
| |
| void maman_bar_do_action (MamanBar *self, /* parameters */); |
| |
| /* implementation in maman-bar.c */ |
| void |
| maman_bar_do_action (MamanBar *self, /* parameters */) |
| { |
| g_return_if_fail (MAMAN_IS_BAR (self)); |
| |
| MAMAN_BAR_GET_CLASS (self)->do_action (self, /* parameters */); |
| } |
| </programlisting> |
| The code above simply redirects the do_action call to the relevant |
| class function. Some users, concerned about performance, do not |
| provide the <function>maman_bar_do_action</function> wrapper function |
| and require users to dereference the class pointer themselves. This |
| is not such a great idea in terms of encapsulation and makes it |
| difficult to change the object's implementation afterwards, should |
| this be needed. |
| </para> |
| |
| <para> |
| Other users, also concerned by performance issues, declare |
| the <function>maman_bar_do_action</function> function inline in the |
| header file. This, however, makes it difficult to change the |
| object's implementation later (although easier than requiring users |
| to directly dereference the class function) and is often difficult |
| to write in a portable way (the <emphasis>inline</emphasis> keyword |
| is part of the C99 standard but not every compiler supports it). |
| </para> |
| |
| <para> |
| In doubt, unless a user shows you hard numbers about the performance |
| cost of the function call, just implement <function>maman_bar_do_action</function> |
| in the source file. |
| </para> |
| |
| <para> |
| Please, note that it is possible for you to provide a default |
| implementation for this class method in the object's |
| <function>class_init</function> function: initialize the |
| klass->do_action field to a pointer to the actual implementation. |
| You can also make this class method pure virtual by initializing |
| the klass->do_action field to NULL: |
| <programlisting> |
| static void |
| maman_bar_real_do_action_two (MamanBar *self, /* parameters */) |
| { |
| /* Default implementation for the virtual method. */ |
| } |
| |
| static void |
| maman_bar_class_init (BarClass *klass) |
| { |
| /* pure virtual method: mandates implementation in children. */ |
| klass->do_action_one = NULL; |
| |
| /* merely virtual method. */ |
| klass->do_action_two = maman_bar_real_do_action_two; |
| } |
| |
| void |
| maman_bar_do_action_one (MamanBar *self, /* parameters */) |
| { |
| g_return_if_fail (MAMAN_IS_BAR (self)); |
| |
| MAMAN_BAR_GET_CLASS (self)->do_action_one (self, /* parameters */); |
| } |
| |
| void |
| maman_bar_do_action_two (MamanBar *self, /* parameters */) |
| { |
| g_return_if_fail (MAMAN_IS_BAR (self)); |
| |
| MAMAN_BAR_GET_CLASS (self)->do_action_two (self, /* parameters */); |
| } |
| </programlisting> |
| </para> |
| </sect2> |
| |
| <sect2> |
| <title>Virtual private Methods</title> |
| |
| <para> |
| These are very similar to Virtual Public methods. They just don't |
| have a public function to call the function directly. The header |
| file contains only a declaration of the class function: |
| <programlisting> |
| /* declaration in maman-bar.h. */ |
| struct _MamanBarClass |
| { |
| GObjectClass parent; |
| |
| /* stuff */ |
| void (* helper_do_specific_action) (MamanBar *self, /* parameters */); |
| }; |
| |
| void maman_bar_do_any_action (MamanBar *self, /* parameters */); |
| </programlisting> |
| These class functions are often used to delegate part of the job |
| to child classes: |
| <programlisting> |
| /* this accessor function is static: it is not exported outside of this file. */ |
| static void |
| maman_bar_do_specific_action (MamanBar *self, /* parameters */) |
| { |
| MAMAN_BAR_GET_CLASS (self)->do_specific_action (self, /* parameters */); |
| } |
| |
| void |
| maman_bar_do_any_action (MamanBar *self, /* parameters */) |
| { |
| /* random code here */ |
| |
| /* |
| * Try to execute the requested action. Maybe the requested action |
| * cannot be implemented here. So, we delegate its implementation |
| * to the child class: |
| */ |
| maman_bar_do_specific_action (self, /* parameters */); |
| |
| /* other random code here */ |
| } |
| </programlisting> |
| </para> |
| |
| <para> |
| Again, it is possible to provide a default implementation for this |
| private virtual class function: |
| <programlisting> |
| static void |
| maman_bar_class_init (MamanBarClass *klass) |
| { |
| /* pure virtual method: mandates implementation in children. */ |
| klass->do_specific_action_one = NULL; |
| |
| /* merely virtual method. */ |
| klass->do_specific_action_two = maman_bar_real_do_specific_action_two; |
| } |
| </programlisting> |
| </para> |
| |
| <para> |
| Children can then implement the subclass with code such as: |
| <programlisting> |
| static void |
| maman_bar_subtype_class_init (MamanBarSubTypeClass *klass) |
| { |
| MamanBarClass *bar_class = MAMAN_BAR_CLASS (klass); |
| |
| /* implement pure virtual class function. */ |
| bar_class->do_specific_action_one = maman_bar_subtype_do_specific_action_one; |
| } |
| </programlisting> |
| </para> |
| </sect2> |
| </sect1> |
| |
| <sect1 id="howto-gobject-chainup"> |
| <title>Chaining up</title> |
| |
| <para>Chaining up is often loosely defined by the following set of |
| conditions: |
| <itemizedlist> |
| <listitem><para>Parent class A defines a public virtual method named <function>foo</function> and |
| provides a default implementation.</para></listitem> |
| <listitem><para>Child class B re-implements method <function>foo</function>.</para></listitem> |
| <listitem><para>In the method B::foo, the child class B calls its parent class method A::foo.</para></listitem> |
| </itemizedlist> |
| There are many uses to this idiom: |
| <itemizedlist> |
| <listitem><para>You need to change the behaviour of a class without modifying its code. You create |
| a subclass to inherit its implementation, re-implement a public virtual method to modify the behaviour |
| slightly and chain up to ensure that the previous behaviour is not really modified, just extended. |
| </para></listitem> |
| <listitem><para>You are lazy, you have access to the source code of the parent class but you don't want |
| to modify it to add method calls to new specialized method calls: it is faster to hack the child class |
| to chain up than to modify the parent to call down.</para></listitem> |
| <listitem><para>You need to implement the Chain Of Responsibility pattern: each object of the inheritance |
| tree chains up to its parent (typically, at the beginning or the end of the method) to ensure that |
| they each handler is run in turn.</para></listitem> |
| </itemizedlist> |
| I am personally not really convinced any of the last two uses are really a good idea but since this |
| programming idiom is often used, this section attempts to explain how to implement it. |
| </para> |
| |
| <para> |
| To explicitly chain up to the implementation of the virtual method in the parent class, |
| you first need a handle to the original parent class structure. This pointer can then be used to |
| access the original class function pointer and invoke it directly. |
| <footnote> |
| <para> |
| The <emphasis>original</emphasis> adjective used in this sentence is not innocuous. To fully |
| understand its meaning, you need to recall how class structures are initialized: for each object type, |
| the class structure associated to this object is created by first copying the class structure of its |
| parent type (a simple <function>memcpy</function>) and then by invoking the class_init callback on |
| the resulting class structure. Since the class_init callback is responsible for overwriting the class structure |
| with the user re-implementations of the class methods, we cannot merely use the modified copy of the parent class |
| structure stored in our derived instance. We want to get a copy of the class structure of an instance of the parent |
| class. |
| </para> |
| </footnote> |
| </para> |
| |
| <para>The function <function><link linkend="g-type-class-peek-parent">g_type_class_peek_parent</link></function> is used to access the original parent |
| class structure. Its input is a pointer to the class of the derived object and it returns a pointer |
| to the original parent class structure. The code below shows how you could use it: |
| <programlisting> |
| static void |
| b_method_to_call (B *obj, int a) |
| { |
| BClass *klass; |
| AClass *parent_class; |
| |
| klass = B_GET_CLASS (obj); |
| parent_class = g_type_class_peek_parent (klass); |
| |
| /* do stuff before chain up */ |
| |
| parent_class->method_to_call (obj, a); |
| |
| /* do stuff after chain up */ |
| } |
| </programlisting> |
| </para> |
| |
| </sect1> |
| |
| </chapter> |
| <!-- End Howto GObject --> |
| |
| <chapter id="howto-interface"> |
| <title>How to define and implement interfaces</title> |
| |
| <sect1 id="howto-interface-define"> |
| <title>How to define interfaces</title> |
| |
| <para> |
| The bulk of interface definition has already been shown in <xref linkend="gtype-non-instantiable-classed"/> |
| but I feel it is needed to show exactly how to create an interface. |
| </para> |
| |
| <para> |
| As above, the first step is to get the header right: |
| <programlisting> |
| #ifndef __MAMAN_IBAZ_H__ |
| #define __MAMAN_IBAZ_H__ |
| |
| #include <glib-object.h> |
| |
| #define MAMAN_TYPE_IBAZ (maman_ibaz_get_type ()) |
| #define MAMAN_IBAZ(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MAMAN_TYPE_IBAZ, MamanIbaz)) |
| #define MAMAN_IS_IBAZ(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MAMAN_TYPE_IBAZ)) |
| #define MAMAN_IBAZ_GET_INTERFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), MAMAN_TYPE_IBAZ, MamanIbazInterface)) |
| |
| |
| typedef struct _MamanIbaz MamanIbaz; /* dummy object */ |
| typedef struct _MamanIbazInterface MamanIbazInterface; |
| |
| struct _MamanIbazInterface |
| { |
| GTypeInterface parent_iface; |
| |
| void (*do_action) (MamanIbaz *self); |
| }; |
| |
| GType maman_ibaz_get_type (void); |
| |
| void maman_ibaz_do_action (MamanIbaz *self); |
| |
| #endif /* __MAMAN_IBAZ_H__ */ |
| </programlisting> |
| This code is the same as the code for a normal <type><link linkend="GType">GType</link></type> |
| which derives from a <type><link linkend="GObject">GObject</link></type> except for a few details: |
| <itemizedlist> |
| <listitem><para> |
| The <function>_GET_CLASS</function> macro is called <function>_GET_INTERFACE</function> |
| and not implemented with <function><link linkend="G_TYPE_INSTANCE_GET_CLASS">G_TYPE_INSTANCE_GET_CLASS</link></function> |
| but with <function><link linkend="G_TYPE_INSTANCE_GET_INTERFACE">G_TYPE_INSTANCE_GET_INTERFACE</link></function>. |
| </para></listitem> |
| <listitem><para> |
| The instance type, <type>MamanIbaz</type> is not fully defined: it is |
| used merely as an abstract type which represents an instance of |
| whatever object which implements the interface. |
| </para></listitem> |
| <listitem><para> |
| The parent of the <type>MamanIbazInterface</type> is not |
| <type>GObjectClass</type> but <type>GTypeInterface</type>. |
| </para></listitem> |
| </itemizedlist> |
| </para> |
| |
| <para> |
| The implementation of the <type>MamanIbaz</type> type itself is trivial: |
| <itemizedlist> |
| <listitem><para><function>maman_ibaz_get_type</function> registers the |
| type in the type system. |
| </para></listitem> |
| <listitem><para><function>maman_ibaz_base_init</function> is expected |
| to register the interface's signals if there are any (we will see a bit |
| (later how to use them). Make sure to use a static local boolean variable |
| to make sure not to run the initialization code twice (as described in |
| <xref linkend="gtype-non-instantiable-classed-init"/>, |
| <function>base_init</function> is run once for each interface implementation |
| instantiation)</para></listitem> |
| <listitem><para><function>maman_ibaz_do_action</function> dereferences |
| the class structure to access its associated class function and calls it. |
| </para></listitem> |
| </itemizedlist> |
| <programlisting> |
| static void |
| maman_ibaz_base_init (gpointer g_class) |
| { |
| static gboolean is_initialized = FALSE; |
| |
| if (!is_initialized) |
| { |
| /* add properties and signals to the interface here */ |
| |
| is_initialized = TRUE; |
| } |
| } |
| |
| GType |
| maman_ibaz_get_type (void) |
| { |
| static GType iface_type = 0; |
| if (iface_type == 0) |
| { |
| static const GTypeInfo info = { |
| sizeof (MamanIbazInterface), |
| maman_ibaz_base_init, /* base_init */ |
| NULL, /* base_finalize */ |
| }; |
| |
| iface_type = g_type_register_static (G_TYPE_INTERFACE, "MamanIbaz", |
| &info, 0); |
| } |
| |
| return iface_type; |
| } |
| |
| void |
| maman_ibaz_do_action (MamanIbaz *self) |
| { |
| g_return_if_fail (MAMAN_IS_IBAZ (self)); |
| |
| MAMAN_IBAZ_GET_INTERFACE (self)->do_action (self); |
| } |
| </programlisting> |
| </para> |
| </sect1> |
| |
| <sect1 id="howto-interface-implement"> |
| <title>How To define implement an Interface?</title> |
| |
| <para> |
| Once the interface is defined, implementing it is rather trivial. |
| </para> |
| |
| <para> |
| The first step is to define a normal GObject class, like: |
| <programlisting> |
| #ifndef __MAMAN_BAZ_H__ |
| #define __MAMAN_BAZ_H__ |
| |
| #include <glib-object.h> |
| |
| #define MAMAN_TYPE_BAZ (maman_baz_get_type ()) |
| #define MAMAN_BAZ(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MAMAN_TYPE_BAZ, Mamanbaz)) |
| #define MAMAN_IS_BAZ(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MAMAN_TYPE_BAZ)) |
| #define MAMAN_BAZ_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MAMAN_TYPE_BAZ, MamanbazClass)) |
| #define MAMAN_IS_BAZ_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MAMAN_TYPE_BAZ)) |
| #define MAMAN_BAZ_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MAMAN_TYPE_BAZ, MamanbazClass)) |
| |
| |
| typedef struct _MamanBaz MamanBaz; |
| typedef struct _MamanBazClass MamanBazClass; |
| |
| struct _MamanBaz |
| { |
| GObject parent_instance; |
| |
| int instance_member; |
| }; |
| |
| struct _MamanBazClass |
| { |
| GObjectClass parent_class; |
| }; |
| |
| GType maman_baz_get_type (void); |
| |
| #endif /* __MAMAN_BAZ_H__ */ |
| </programlisting> |
| There is clearly nothing specifically weird or scary about this header: |
| it does not define any weird API or derives from a weird type. |
| </para> |
| |
| <para> |
| The second step is to implement <type>MamanBaz</type> by defining |
| its GType. Instead of using <function>G_DEFINE_TYPE</function> we |
| use <function>G_DEFINE_TYPE_WITH_CODE</function> and the |
| <function>G_IMPLEMENT_INTERFACE</function> macros. |
| <programlisting> |
| static void maman_ibaz_interface_init (MamanIbazInterface *iface); |
| |
| G_DEFINE_TYPE_WITH_CODE (MamanBar, maman_bar, G_TYPE_OBJECT, |
| G_IMPLEMENT_INTERFACE (MAMAN_TYPE_IBAZ, |
| maman_ibaz_interface_init)); |
| </programlisting> |
| This definition is very much like all the similar functions we looked |
| at previously. The only interface-specific code present here is the call |
| to <function>G_IMPLEMENT_INTERFACE</function>. |
| </para> |
| |
| <note><para>Classes can implement multiple interfaces by using multiple |
| calls to <function>G_IMPLEMENT_INTERFACE</function> inside the call |
| to <function>G_DEFINE_TYPE_WITH_CODE</function>.</para></note> |
| |
| <para> |
| <function>maman_baz_interface_init</function>, the interface |
| initialization function: inside it every virtual method of the interface |
| must be assigned to its implementation: |
| <programlisting> |
| static void |
| maman_baz_do_action (MamanBaz *self) |
| { |
| g_print ("Baz implementation of IBaz interface Action: 0x%x.\n", |
| self->instance_member); |
| } |
| |
| static void |
| maman_ibaz_interface_init (MamanIbazInterface *iface) |
| { |
| iface->do_action = baz_do_action; |
| } |
| |
| static void |
| maman_baz_init (MamanBaz *self) |
| { |
| MamanBaz *self = MAMAN_BAZ (instance); |
| self->instance_member = 0xdeadbeaf; |
| } |
| </programlisting> |
| </para> |
| |
| </sect1> |
| |
| <sect1> |
| <title>Interface definition prerequisites</title> |
| |
| <para> |
| To specify that an interface requires the presence of other interfaces |
| when implemented, GObject introduces the concept of |
| <emphasis>prerequisites</emphasis>: it is possible to associate |
| a list of prerequisite interfaces to an interface. For example, if |
| object A wishes to implement interface I1, and if interface I1 has a |
| prerequisite on interface I2, A has to implement both I1 and I2. |
| </para> |
| |
| <para> |
| The mechanism described above is, in practice, very similar to |
| Java's interface I1 extends interface I2. The example below shows |
| the GObject equivalent: |
| <programlisting> |
| /* inside the GType function of the MamanIbar interface */ |
| type = g_type_register_static (G_TYPE_INTERFACE, "MamanIbar", &info, 0); |
| |
| /* Make the MamanIbar interface require MamanIbaz interface. */ |
| g_type_interface_add_prerequisite (type, MAMAN_TYPE_IBAZ); |
| </programlisting> |
| The code shown above adds the MamanIbaz interface to the list of |
| prerequisites of MamanIbar while the code below shows how an |
| implementation can implement both interfaces and register their |
| implementations: |
| <programlisting> |
| static void |
| maman_ibar_do_another_action (MamanIbar *ibar) |
| { |
| MamanBar *self = MAMAN_BAR (ibar); |
| |
| g_print ("Bar implementation of IBar interface Another Action: 0x%x.\n", |
| self->instance_member); |
| } |
| |
| static void |
| maman_ibar_interface_init (MamanIbarInterface *iface) |
| { |
| iface->do_another_action = maman_ibar_do_another_action; |
| } |
| |
| static void |
| maman_ibaz_do_action (MamanIbaz *ibaz) |
| { |
| MamanBar *self = MAMAN_BAR (ibaz); |
| |
| g_print ("Bar implementation of IBaz interface Action: 0x%x.\n", |
| self->instance_member); |
| } |
| |
| static void |
| maman_ibaz_interface_init (MamanIbazInterface *iface) |
| { |
| iface->do_action = maman_ibaz_do_action; |
| } |
| |
| static void |
| maman_bar_class_init (MamanBarClass *klass) |
| { |
| |
| } |
| |
| static void |
| maman_bar_init (MamanBar *self) |
| { |
| self->instance_member = 0x666; |
| } |
| |
| G_DEFINE_TYPE_WITH_CODE (MamanBar, maman_bar, G_TYPE_OBJECT, |
| G_IMPLEMENT_INTERFACE (MAMAN_TYPE_IBAZ, |
| maman_ibaz_interface_init) |
| G_IMPLEMENT_INTERFACE (MAMAN_TYPE_IBAR, |
| maman_ibar_interface_init)); |
| </programlisting> |
| It is very important to notice that the order in which interface |
| implementations are added to the main object is not random: |
| <function><link linkend="g-type-add-interface-static">g_type_add_interface_static</link></function>, |
| which is called by <function>G_IMPLEMENT_INTERFACE</function>, must be |
| invoked first on the interfaces which have no prerequisites and then on |
| the others. |
| </para> |
| </sect1> |
| |
| <sect1 id="howto-interface-properties"> |
| <title>Interface Properties</title> |
| |
| <para> |
| Starting from version 2.4 of GLib, GObject interfaces can also have |
| properties. Declaration of the interface properties is similar to |
| declaring the properties of ordinary GObject types as explained in |
| <xref linkend="gobject-properties"/>, |
| except that <function><link linkend="g-object-interface-install-property">g_object_interface_install_property</link></function> is used to |
| declare the properties instead of <function><link linkend="g-object-class-install-property">g_object_class_install_property</link></function>. |
| </para> |
| |
| <para> |
| To include a property named 'name' of type <type>string</type> in the |
| <type>maman_ibaz</type> interface example code above, we only need to |
| add one |
| <footnote> |
| <para> |
| That really is one line extended to six for the sake of clarity |
| </para> |
| </footnote> |
| line in the <function>maman_ibaz_base_init</function> |
| <footnote> |
| <para> |
| The <function><link linkend="g-object-interface-install-property">g_object_interface_install_property</link></function> |
| can also be called from <function>class_init</function> but it must |
| not be called after that point. |
| </para> |
| </footnote> |
| as shown below: |
| <programlisting> |
| static void |
| maman_ibaz_base_init (gpointer g_iface) |
| { |
| static gboolean is_initialized = FALSE; |
| |
| if (!is_initialized) |
| { |
| g_object_interface_install_property (g_iface, |
| g_param_spec_string ("name", |
| "Name", |
| "Name of the MamanIbaz", |
| "maman", |
| G_PARAM_READWRITE)); |
| is_initialized = TRUE; |
| } |
| } |
| </programlisting> |
| </para> |
| |
| <para> |
| One point worth noting is that the declared property wasn't assigned an |
| integer ID. The reason being that integer IDs of properties are used |
| only inside the get and set methods and since interfaces do not |
| implement properties, there is no need to assign integer IDs to |
| interface properties. |
| </para> |
| |
| <para> |
| An implementation shall declare and define it's properties in the usual |
| way as explained in <xref linkend="gobject-properties"/>, except for one |
| small change: it must declare the properties of the interface it |
| implements using <function><link linkend="g-object-class-override-property">g_object_class_override_property</link></function> |
| instead of <function><link linkend="g-object-class-install-property">g_object_class_install_property</link></function>. |
| The following code snippet shows the modifications needed in the |
| <type>MamanBaz</type> declaration and implementation above: |
| <programlisting> |
| |
| struct _MamanBaz |
| { |
| GObject parent_instance; |
| |
| gint instance_member; |
| gchar *name; |
| }; |
| |
| enum |
| { |
| PROP_0, |
| |
| PROP_NAME |
| }; |
| |
| static void |
| maman_baz_set_property (GObject *object, |
| guint property_id, |
| const GValue *value, |
| GParamSpec *pspec) |
| { |
| MamanBaz *baz = MAMAN_BAZ (object); |
| GObject *obj; |
| |
| switch (prop_id) |
| { |
| case ARG_NAME: |
| g_free (baz->name); |
| baz->name = g_value_dup_string (value); |
| break; |
| |
| default: |
| G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
| break; |
| } |
| } |
| |
| static void |
| maman_baz_get_property (GObject *object, |
| guint prop_id, |
| GValue *value, |
| GParamSpec *pspec) |
| { |
| MamanBaz *baz = MAMAN_BAZ (object); |
| |
| switch (prop_id) |
| { |
| case ARG_NAME: |
| g_value_set_string (value, baz->name); |
| break; |
| |
| default: |
| G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
| break; |
| } |
| } |
| |
| static void |
| maman_baz_class_init (MamanBazClass *klass) |
| { |
| GObjectClass *gobject_class = G_OBJECT_CLASS (klass); |
| |
| gobject_class->set_property = maman_baz_set_property; |
| gobject_class->get_property = maman_baz_get_property; |
| |
| g_object_class_override_property (gobject_class, PROP_NAME, "name"); |
| } |
| |
| </programlisting> |
| </para> |
| |
| </sect1> |
| </chapter> |
| <!-- End Howto Interfaces --> |
| |
| <chapter id="howto-signals"> |
| <title>How to create and use signals</title> |
| |
| <para> |
| The signal system which was built in GType is pretty complex and |
| flexible: it is possible for its users to connect at runtime any |
| number of callbacks (implemented in any language for which a binding |
| exists) |
| <footnote> |
| <para>A Python callback can be connected to any signal on any |
| C-based GObject. |
| </para> |
| </footnote> |
| to any signal and to stop the emission of any signal at any |
| state of the signal emission process. This flexibility makes it |
| possible to use GSignal for much more than just emit signals which |
| can be received by numerous clients. |
| </para> |
| |
| <sect1 id="howto-simple-signals"> |
| <title>Simple use of signals</title> |
| |
| <para> |
| The most basic use of signals is to implement simple event |
| notification: for example, if we have a MamanFile object, and |
| if this object has a write method, we might wish to be notified |
| whenever someone has changed something via our MamanFile instance. |
| The code below shows how the user can connect a callback to the |
| "changed" signal. |
| <programlisting> |
| file = g_object_new (MAMAN_FILE_TYPE, NULL); |
| |
| g_signal_connect (file, "changed", G_CALLBACK (changed_event), NULL); |
| |
| maman_file_write (file, buffer, strlen (buffer)); |
| </programlisting> |
| </para> |
| |
| <para> |
| The <type>MamanFile</type> signal is registered in the class_init |
| function: |
| <programlisting> |
| file_signals[CHANGED] = |
| g_signal_newv ("changed", |
| G_TYPE_FROM_CLASS (gobject_class), |
| G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, |
| NULL /* closure */, |
| NULL /* accumulator */, |
| NULL /* accumulator data */, |
| g_cclosure_marshal_VOID__VOID, |
| G_TYPE_NONE /* return_type */, |
| 0 /* n_params */, |
| NULL /* param_types */); |
| </programlisting> |
| and the signal is emitted in <function>maman_file_write</function>: |
| <programlisting> |
| void |
| maman_file_write (MamanFile *self, |
| const guchar *buffer, |
| gssize size) |
| { |
| /* First write data. */ |
| |
| /* Then, notify user of data written. */ |
| g_signal_emit (self, file_signals[CHANGED], 0 /* details */); |
| } |
| </programlisting> |
| As shown above, you can safely set the details parameter to zero if |
| you do not know what it can be used for. For a discussion of what you |
| could used it for, see <xref linkend="signal-detail"/> |
| </para> |
| |
| <para> |
| The signature of the signal handler in the above example is defined as |
| <function>g_cclosure_marshal_VOID__VOID</function>. Its name follows |
| a simple convention which encodes the function parameter and return value |
| types in the function name. Specifically, the value in front of the |
| double underscore is the type of the return value, while the value(s) |
| after the double underscore denote the parameter types. |
| </para> |
| |
| <para> |
| The header <filename>gobject/gmarshal.h</filename> defines a set of |
| commonly needed closures that one can use. If you want to have complex |
| marshallers for your signals you should probably use glib-genmarshal |
| to autogenerate them from a file containing their return and |
| parameter types. |
| </para> |
| </sect1> |
| |
| <!-- |
| this is utterly wrong and should be completely removed - or rewritten |
| with a better example than writing a buffer using synchronous signals. |
| |
| <sect1> |
| <title>How to provide more flexibility to users?</title> |
| |
| <para> |
| The previous implementation does the job but the signal facility of |
| GObject can be used to provide even more flexibility to this file |
| change notification mechanism. One of the key ideas is to make the |
| process of writing data to the file part of the signal emission |
| process to allow users to be notified either before or after the |
| data is written to the file. |
| </para> |
| |
| <para> |
| To integrate the process of writing the data to the file into the |
| signal emission mechanism, we can register a default class closure |
| for this signal which will be invoked during the signal emission, |
| just like any other user-connected signal handler. |
| </para> |
| |
| <para> |
| The first step to implement this idea is to change the signature of |
| the signal: we need to pass around the buffer to write and its size. |
| To do this, we use our own marshaller which will be generated |
| through GLib's glib-genmarshal tool. We thus create a file named <filename>marshall.list</filename> which contains |
| the following single line: |
| <programlisting> |
| VOID:POINTER,UINT |
| </programlisting> |
| and use the Makefile provided in <filename>sample/signal/Makefile</filename> to generate the file named |
| <filename>maman-file-complex-marshall.c</filename>. This C file is finally included in |
| <filename>maman-file-complex.c</filename>. |
| </para> |
| |
| <para> |
| Once the marshaller is present, we register the signal and its marshaller in the class_init function |
| of the object <type>MamanFileComplex</type> (full source for this object is included in |
| <filename>sample/signal/maman-file-complex.{h|c}</filename>): |
| <programlisting> |
| GClosure *default_closure; |
| GType param_types[2]; |
| |
| default_closure = g_cclosure_new (G_CALLBACK (default_write_signal_handler), |
| (gpointer)0xdeadbeaf /* user_data */, |
| NULL /* destroy_data */); |
| |
| param_types[0] = G_TYPE_POINTER; |
| param_types[1] = G_TYPE_UINT; |
| klass->write_signal_id = |
| g_signal_newv ("write", |
| G_TYPE_FROM_CLASS (g_class), |
| G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, |
| default_closure /* class closure */, |
| NULL /* accumulator */, |
| NULL /* accu_data */, |
| maman_file_complex_VOID__POINTER_UINT, |
| G_TYPE_NONE /* return_type */, |
| 2 /* n_params */, |
| param_types /* param_types */); |
| </programlisting> |
| The code shown above first creates the closure which contains the code to complete the file write. This |
| closure is registered as the default class_closure of the newly created signal. |
| </para> |
| |
| <para> |
| Of course, you need to implement completely the code for the default closure since I just provided |
| a skeleton: |
| <programlisting> |
| static void |
| default_write_signal_handler (GObject *obj, guint8 *buffer, guint size, gpointer user_data) |
| { |
| g_assert (user_data == (gpointer)0xdeadbeaf); |
| /* Here, we trigger the real file write. */ |
| g_print ("default signal handler: 0x%x %u\n", buffer, size); |
| } |
| </programlisting> |
| </para> |
| |
| <para> |
| Finally, the client code must invoke the <function>maman_file_complex_write</function> function which |
| triggers the signal emission: |
| <programlisting> |
| void maman_file_complex_write (MamanFileComplex *self, guint8 *buffer, guint size) |
| { |
| /* trigger event */ |
| g_signal_emit (self, |
| MAMAN_FILE_COMPLEX_GET_CLASS (self)->write_signal_id, |
| 0, /* details */ |
| buffer, size); |
| } |
| </programlisting> |
| </para> |
| |
| <para> |
| The client code (as shown in <filename>sample/signal/test.c</filename> and below) can now connect signal handlers before |
| and after the file write is completed: since the default signal handler which does the write itself runs during the |
| RUN_LAST phase of the signal emission, it will run after all handlers connected with <function><link linkend="g-signal-connect">g_signal_connect</link></function> |
| and before all handlers connected with <function><link linkend="g-signal-connect-after">g_signal_connect_after</link></function>. If you intent to write a GObject |
| which emits signals, I would thus urge you to create all your signals with the G_SIGNAL_RUN_LAST such that your users |
| have a maximum of flexibility as to when to get the event. Here, we combined it with G_SIGNAL_NO_RECURSE and |
| G_SIGNAL_NO_HOOKS to ensure our users will not try to do really weird things with our GObject. I strongly advise you |
| to do the same unless you really know why (in which case you really know the inner workings of GSignal by heart and |
| you are not reading this). |
| </para> |
| |
| <para> |
| <programlisting> |
| static void complex_write_event_before (GObject *file, guint8 *buffer, guint size, gpointer user_data) |
| { |
| g_assert (user_data == NULL); |
| g_print ("Complex Write event before: 0x%x, %u\n", buffer, size); |
| } |
| |
| static void complex_write_event_after (GObject *file, guint8 *buffer, guint size, gpointer user_data) |
| { |
| g_assert (user_data == NULL); |
| g_print ("Complex Write event after: 0x%x, %u\n", buffer, size); |
| } |
| |
| static void test_file_complex (void) |
| { |
| guint8 buffer[100]; |
| GObject *file; |
| |
| file = g_object_new (MAMAN_FILE_COMPLEX_TYPE, NULL); |
| |
| g_signal_connect (G_OBJECT (file), "write", |
| (GCallback)complex_write_event_before, |
| NULL); |
| |
| g_signal_connect_after (G_OBJECT (file), "write", |
| (GCallback)complex_write_event_after, |
| NULL); |
| |
| maman_file_complex_write (MAMAN_FILE_COMPLEX (file), buffer, 50); |
| |
| g_object_unref (G_OBJECT (file)); |
| } |
| </programlisting> |
| The code above generates the following output on my machine: |
| <programlisting> |
| Complex Write event before: 0xbfffe280, 50 |
| default signal handler: 0xbfffe280 50 |
| Complex Write event after: 0xbfffe280, 50 |
| </programlisting> |
| </para> |
| |
| --> |
| |
| <!-- |
| this is also utterly wrong on so many levels that I don't even want |
| to enumerate them. it's also full of completely irrelevant footnotes |
| about personal preferences demonstrating a severe lack of whatsoever |
| clue. the whole idea of storing the signal ids inside the Class |
| structure is so fundamentally flawed that I'll require a frontal |
| lobotomy just to forget I've ever seen it. |
| |
| <sect2> |
| <title>How most people do the same thing with less code</title> |
| |
| <para>For many historic reasons related to how the ancestor of GObject used to work in GTK+ 1.x versions, |
| there is a much <emphasis>simpler</emphasis> |
| <footnote> |
| <para>I personally think that this method is horribly mind-twisting: it adds a new indirection |
| which unnecessarily complicates the overall code path. However, because this method is widely used |
| by all of GTK+ and GObject code, readers need to understand it. The reason why this is done that way |
| in most of GTK+ is related to the fact that the ancestor of GObject did not provide any other way to |
| create a signal with a default handler than this one. Some people have tried to justify that it is done |
| that way because it is better, faster (I am extremely doubtful about the faster bit. As a matter of fact, |
| the better bit also mystifies me ;-). I have the feeling no one really knows and everyone does it |
| because they copy/pasted code from code which did the same. It is probably better to leave this |
| specific trivia to hacker legends domain... |
| </para> |
| </footnote> |
| way to create a signal with a default handler than to create |
| a closure by hand and to use the <function><link linkend="g-signal-newv">g_signal_newv</link></function>. |
| </para> |
| |
| <para>For example, <function><link linkend="g-signal-new">g_signal_new</link></function> can be used to create a signal which uses a default |
| handler which is stored in the class structure of the object. More specifically, the class structure |
| contains a function pointer which is accessed during signal emission to invoke the default handler and |
| the user is expected to provide to <function><link linkend="g-signal-new">g_signal_new</link></function> the offset from the start of the |
| class structure to the function pointer. |
| <footnote> |
| <para>I would like to point out here that the reason why the default handler of a signal is named everywhere |
| a class_closure is probably related to the fact that it used to be really a function pointer stored in |
| the class structure. |
| </para> |
| </footnote> |
| </para> |
| |
| <para>The following code shows the declaration of the <type>MamanFileSimple</type> class structure which contains |
| the <function>write</function> function pointer. |
| <programlisting> |
| struct _MamanFileSimpleClass { |
| GObjectClass parent; |
| |
| guint write_signal_id; |
| |
| /* signal default handlers */ |
| void (*write) (MamanFileSimple *self, guint8 *buffer, guint size); |
| }; |
| </programlisting> |
| The <function>write</function> function pointer is initialized in the class_init function of the object |
| to <function>default_write_signal_handler</function>: |
| <programlisting> |
| static void |
| maman_file_simple_class_init (gpointer g_class, |
| gpointer g_class_data) |
| { |
| GObjectClass *gobject_class = G_OBJECT_CLASS (g_class); |
| MamanFileSimpleClass *klass = MAMAN_FILE_SIMPLE_CLASS (g_class); |
| |
| klass->write = default_write_signal_handler; |
| </programlisting> |
| Finally, the signal is created with <function><link linkend="g-signal-new">g_signal_new</link></function> in the same class_init function: |
| <programlisting> |
| klass->write_signal_id = |
| g_signal_new ("write", |
| G_TYPE_FROM_CLASS (g_class), |
| G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, |
| G_STRUCT_OFFSET (MamanFileSimpleClass, write), |
| NULL /* accumulator */, |
| NULL /* accu_data */, |
| maman_file_complex_VOID__POINTER_UINT, |
| G_TYPE_NONE /* return_type */, |
| 2 /* n_params */, |
| G_TYPE_POINTER, |
| G_TYPE_UINT); |
| </programlisting> |
| Of note, here, is the 4th argument to the function: it is an integer calculated by the <function><link linkend="G-STRUCT-OFFSET">G_STRUCT_OFFSET</link></function> |
| macro which indicates the offset of the member <emphasis>write</emphasis> from the start of the |
| <type>MamanFileSimpleClass</type> class structure. |
| <footnote> |
| <para>GSignal uses this offset to create a special wrapper closure |
| which first retrieves the target function pointer before calling it. |
| </para> |
| </footnote> |
| </para> |
| |
| <para> |
| While the complete code for this type of default handler looks less cluttered as shown in |
| <filename>sample/signal/maman-file-simple.{h|c}</filename>, it contains numerous subtleties. |
| The main subtle point which everyone must be aware of is that the signature of the default |
| handler created that way does not have a user_data argument: |
| <function>default_write_signal_handler</function> is different in |
| <filename>sample/signal/maman-file-complex.c</filename> and in |
| <filename>sample/signal/maman-file-simple.c</filename>. |
| </para> |
| |
| <para>If you have doubts about which method to use, I would advise you to use the second one which |
| involves <function><link linkend="g-signal-new">g_signal_new</link></function> rather than <function><link linkend="g-signal-newv">g_signal_newv</link></function>: |
| it is better to write code which looks like the vast majority of other GTK+/GObject code than to |
| do it your own way. However, now, you know why. |
| </para> |
| |
| </sect2> |
| |
| </sect1> |
| --> |
| |
| <!-- |
| yet another pointless section. if we are scared of possible abuses |
| from the users then we should not be mentioning it inside a tutorial |
| for beginners. but, obviously, there's nothing to be afraid of - it's |
| just that this section must be completely reworded. |
| |
| <sect1> |
| <title>How users can abuse signals (and why some think it is good)</title> |
| |
| <para>Now that you know how to create signals to which the users can connect easily and at any point in |
| the signal emission process thanks to <function><link linkend="g-signal-connect">g_signal_connect</link></function>, |
| <function><link linkend="g-signal-connect-after">g_signal_connect_after</link></function> and G_SIGNAL_RUN_LAST, it is time to look into how your |
| users can and will screw you. This is also interesting to know how you too, can screw other people. |
| This will make you feel good and eleet. |
| </para> |
| |
| <para> |
| The users can: |
| <itemizedlist> |
| <listitem><para>stop the emission of the signal at anytime</para></listitem> |
| <listitem><para>override the default handler of the signal if it is stored as a function |
| pointer in the class structure (which is the preferred way to create a default signal handler, |
| as discussed in the previous section).</para></listitem> |
| </itemizedlist> |
| </para> |
| |
| <para> |
| In both cases, the original programmer should be as careful as possible to write code which is |
| resistant to the fact that the default handler of the signal might not able to run. This is obviously |
| not the case in the example used in the previous sections since the write to the file depends on whether |
| or not the default handler runs (however, this might be your goal: to allow the user to prevent the file |
| write if he wishes to). |
| </para> |
| |
| <para> |
| If all you want to do is to stop the signal emission from one of the callbacks you connected yourself, |
| you can call <function><link linkend="g-signal-stop-by-name">g_signal_stop_by_name</link></function>. Its use is very simple which is why I won't detail |
| it further. |
| </para> |
| |
| <para> |
| If the signal's default handler is just a class function pointer, it is also possible to override |
| it yourself from the class_init function of a type which derives from the parent. That way, when the signal |
| is emitted, the parent class will use the function provided by the child as a signal default handler. |
| Of course, it is also possible (and recommended) to chain up from the child to the parent's default signal |
| handler to ensure the integrity of the parent object. |
| </para> |
| |
| <para> |
| Overriding a class method and chaining up was demonstrated in <xref linkend="howto-gobject-methods"/> |
| which is why I won't bother to show exactly how to do it here again. |
| </para> |
| |
| </sect1> |
| |
| --> |
| |
| </chapter> |
| |
| <!-- |
| <sect2> |
| <title>Warning on signal creation and default closure</title> |
| |
| <para> |
| Most of the existing code I have seen up to now (in both GTK+, GNOME libraries and |
| many GTK+ and GNOME applications) using signals uses a small |
| variation of the default handler pattern I have shown in the previous section. |
| </para> |
| |
| <para> |
| Usually, the <function><link linkend="g-signal-new">g_signal_new</link></function> function is preferred over |
| <function><link linkend="g-signal-newv">g_signal_newv</link></function>. When <function><link linkend="g-signal-new">g_signal_new</link></function> |
| is used, the default closure is exported as a class function. For example, |
| <filename>gobject.h</filename> contains the declaration of <type><link linkend="GObjectClass">GObjectClass</link></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><link linkend="g-object-do-class-init">g_object_do_class_init</link></function> function |
| registers the <emphasis>notify</emphasis> signal and initializes this class function |
| to NULL: |
| <programlisting> |
| static void |
| g_object_do_class_init (GObjectClass *class) |
| { |
| |
| /* Stuff */ |
| |
| class->notify = NULL; |
| |
| gobject_signals[NOTIFY] = |
| g_signal_new ("notify", |
| G_TYPE_FROM_CLASS (class), |
| G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE | G_SIGNAL_DETAILED | G_SIGNAL_NO_HOOKS, |
| G_STRUCT_OFFSET (GObjectClass, notify), |
| NULL, NULL, |
| g_cclosure_marshal_VOID__PARAM, |
| G_TYPE_NONE, |
| 1, G_TYPE_PARAM); |
| } |
| </programlisting> |
| <function><link linkend="g-signal-new">g_signal_new</link></function> creates a <type><link linkend="GClosure">GClosure</link></type> which dereferences the |
| type's class structure to access the class function pointer and invoke it if it not NULL. The |
| class function is ignored it is set to NULL. |
| </para> |
| |
| <para> |
| To understand the reason for such a complex scheme to access the signal's default handler, |
| you must remember the whole reason for the use of these signals. The goal here is to delegate |
| a part of the process to the user without requiring the user to subclass the object to override |
| one of the class functions. The alternative to subclassing, that is, the use of signals |
| to delegate processing to the user, is, however, a bit less optimal in terms of speed: rather |
| than just dereferencing a function pointer in a class structure, you must start the whole |
| process of signal emission which is a bit heavyweight. |
| </para> |
| |
| <para> |
| This is why some people decided to use class functions for some signal's default handlers: |
| rather than having users connect a handler to the signal and stop the signal emission |
| from within that handler, you just need to override the default class function which is |
| supposedly more efficient. |
| </para> |
| |
| </sect2> |
| --> |
| </part> |