From adae2cf59bba32b7fdd0afb5b10056cd4105fddb Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Fri, 18 Jul 2008 17:55:13 +0000 Subject: [PATCH] Updates svn path=/trunk/; revision=7201 --- docs/reference/ChangeLog | 7 + docs/reference/gobject/tut_gobject.xml | 310 +++--- docs/reference/gobject/tut_gsignal.xml | 44 +- docs/reference/gobject/tut_gtype.xml | 2 +- docs/reference/gobject/tut_howto.xml | 1217 ++++++++++++------------ 5 files changed, 780 insertions(+), 800 deletions(-) diff --git a/docs/reference/ChangeLog b/docs/reference/ChangeLog index ff003deba..00690cf05 100644 --- a/docs/reference/ChangeLog +++ b/docs/reference/ChangeLog @@ -1,3 +1,10 @@ +2008-07-18 Matthias Clasen + + Bug 530759 – update the gobject tutorial to the XXI century + + * gobject/*: Some updates to the tutorial. Patch by Emmanuele + Bassi. + 2008-07-18 Matthias Clasen * gio/gio-sections.txt: Add g_content_type_guess_for_tree diff --git a/docs/reference/gobject/tut_gobject.xml b/docs/reference/gobject/tut_gobject.xml index 5d02f27c8..61fe4b74c 100644 --- a/docs/reference/gobject/tut_gobject.xml +++ b/docs/reference/gobject/tut_gobject.xml @@ -25,29 +25,33 @@ Object instantiation - The g_object_new family of functions can be used to instantiate any - GType which inherits from the GObject base type. All these functions make sure the class - and instance structures have been correctly initialized by glib's type system and - then invoke at one point or another the constructor class method which is used to: + The g_object_new + family of functions can be used to instantiate any GType which inherits + from the GObject base type. All these functions make sure the class and + instance structures have been correctly initialized by GLib's type system + and then invoke at one point or another the constructor class method + which is used to: Allocate and clear memory through g_type_create_instance, - Initialize the object' instance with the construction properties. + Initialize the object's instance with the construction properties. Although one can expect all class and instance members (except the fields - pointing to the parents) to be set to zero, some consider it good practice to explicitly set them. + pointing to the parents) to be set to zero, some consider it good practice + to explicitly set them. - Objects which inherit from GObject are allowed to override this constructor class method: - they should however chain to their parent constructor method before doing so: + Objects which inherit from GObject are allowed to override this + constructor class method: they should however chain to their parent + constructor method before doing so: - GObject* (*constructor) (GType type, - guint n_construct_properties, - GObjectConstructParam *construct_properties); + GObject *(* constructor) (GType gtype, + guint n_properties, + GObjectConstructParam *properties); @@ -56,101 +60,79 @@ #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(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MAMAN_TYPE_BAR)) -#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)) +#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; +typedef struct _MamanBar MamanBar; +typedef struct _MamanBarClass MamanBarClass; + +struct _MamanBar +{ + GObject parent_instance; -struct _MamanBar { - GObject parent; /* instance members */ }; -struct _MamanBarClass { - GObjectClass parent; +struct _MamanBarClass +{ + GObjectClass parent_class; /* class members */ }; -/* used by MAMAN_TYPE_BAR */ -GType maman_bar_get_type (void); +/* will create maman_bar_get_type and set maman_bar_parent_class */ +G_DEFINE_TYPE (MamanBar, maman_bar, G_TYPE_OBJECT); static GObject * -maman_bar_constructor (GType type, - guint n_construct_properties, - GObjectConstructParam *construct_properties) +maman_bar_constructor (GType gtype, + guint n_properties, + GObjectConstructParam *properties) { GObject *obj; { - /* Invoke parent constructor. */ + /* Always chain up to the parent constructor */ MamanBarClass *klass; GObjectClass *parent_class; - klass = MAMAN_BAR_CLASS (g_type_class_peek (MAMAN_TYPE_BAR)); - parent_class = G_OBJECT_CLASS (g_type_class_peek_parent (klass)); - obj = parent_class->constructor (type, - n_construct_properties, - construct_properties); + parent_class = G_OBJECT_CLASS (maman_bar_parent_class); + obj = parent_class->constructor (gtype, n_properties, properties); } - /* do stuff. */ + /* update the object state depending on constructor properties */ return obj; } static void -maman_bar_instance_init (GTypeInstance *instance, - gpointer g_class) +maman_bar_class_init (MamanBarClass *klass) { - MamanBar *self = (MamanBar *)instance; - /* do stuff */ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->constructor = maman_bar_constructor; } static void -maman_bar_class_init (gpointer g_class, - gpointer g_class_data) +maman_bar_init (MamanBar *self) { - GObjectClass *gobject_class = G_OBJECT_CLASS (g_class); - MamanBarClass *klass = MAMAN_BAR_CLASS (g_class); - - gobject_class->constructor = maman_bar_constructor; + /* initialize the object */ } -GType maman_bar_get_type (void) -{ - static GType type = 0; - if (type == 0) { - static const GTypeInfo info = { - sizeof (MamanBarClass), - NULL, /* base_init */ - NULL, /* base_finalize */ - maman_bar_class_init, /* class_init */ - NULL, /* class_finalize */ - NULL, /* class_data */ - sizeof (MamanBar), - 0, /* n_preallocs */ - maman_bar_instance_init /* instance_init */ - }; - type = g_type_register_static (G_TYPE_OBJECT, - "MamanBarType", - &info, 0); - } - return type; -} If the user instantiates an object MamanBar with: MamanBar *bar = g_object_new (MAMAN_TYPE_BAR, NULL); - If this is the first instantiation of such an object, the maman_b_class_init - function will be invoked after any maman_b_base_class_init function. - This will make sure the class structure of this new object is correctly initialized. Here, - maman_bar_class_init is expected to override the object's class methods - and setup the class' own methods. In the example above, the constructor method is the only - overridden method: it is set to maman_bar_constructor. + If this is the first instantiation of such an object, the + maman_bar_class_init function will be invoked + after any maman_bar_base_class_init function. + This will make sure the class structure of this new object is + correctly initialized. Here, maman_bar_class_init + is expected to override the object's class methods and setup the + class' own methods. In the example above, the constructor method is + the only overridden method: it is set to + maman_bar_constructor. @@ -158,12 +140,11 @@ MamanBar *bar = g_object_new (MAMAN_TYPE_BAR, NULL); class structure, it invokes its constructor method to create an instance of the new object. Since it has just been overridden by maman_bar_class_init to maman_bar_constructor, the latter is called and, because it - was implemented correctly, it chains up to its parent's constructor. The problem here - is how we can find the parent constructor. An approach (used in GTK+ source code) would be - to save the original constructor in a static variable from maman_bar_class_init - and then to re-use it from maman_bar_constructor. This is clearly possible - and very simple but I was told it was not nice and the preferred way is to use the - g_type_class_peek and g_type_class_peek_parent functions. + was implemented correctly, it chains up to its parent's constructor. In + order to find the parent class and chain up to the parent class + constructor, we can use the maman_bar_parent_class + pointer that has been set up for us by the + G_DEFINE_TYPE macro. @@ -179,16 +160,13 @@ MamanBar *bar = g_object_new (MAMAN_TYPE_BAR, NULL); - The process described above might seem a bit complicated (it is actually - overly complicated in my opinion..) but it can be summarized easily by the table below which - lists the functions invoked by g_object_new and their order of - invocation. + The process described above might seem a bit complicated, but it can be + summarized easily by the table below which lists the functions invoked + by g_object_new + and their order of invocation: - The array below lists the functions invoked by g_object_new and - their order of invocation: - <function><link linkend="g-object-new">g_object_new</link></function> @@ -266,16 +244,16 @@ MamanBar *bar = g_object_new (MAMAN_TYPE_BAR, NULL); - Readers should feel concerned about one little twist in the order in which functions - are invoked: while, technically, the class' constructor method is called - before the GType's instance_init function (since - g_type_create_instance which calls instance_init is called by + Readers should feel concerned about one little twist in the order in + which functions are invoked: while, technically, the class' constructor + method is called before the GType's instance_init + function (since g_type_create_instance which calls instance_init is called by g_object_constructor which is the top-level class - constructor method and to which users are expected to chain to), the user's code - which runs in a user-provided constructor will always run after - GType's instance_init function since the user-provided constructor - must (you've been warned) chain up before - doing anything useful. + constructor method and to which users are expected to chain to), the + user's code which runs in a user-provided constructor will always + run after GType's instance_init function since the + user-provided constructor must (you've been warned) + chain up before doing anything useful. @@ -296,24 +274,25 @@ gpointer g_object_ref (gpointer object); void g_object_unref (gpointer object); /* - Weak References -*/ -typedef void (*GWeakNotify) (gpointer data, - GObject *where_the_object_was); -void g_object_weak_ref (GObject *object, - GWeakNotify notify, - gpointer data); -void g_object_weak_unref (GObject *object, - GWeakNotify notify, - gpointer data); -void g_object_add_weak_pointer (GObject *object, - gpointer *weak_pointer_location); -void g_object_remove_weak_pointer (GObject *object, - gpointer *weak_pointer_location); + * Weak References + */ +typedef void (*GWeakNotify) (gpointer data, + GObject *where_the_object_was); + +void g_object_weak_ref (GObject *object, + GWeakNotify notify, + gpointer data); +void g_object_weak_unref (GObject *object, + GWeakNotify notify, + gpointer data); +void g_object_add_weak_pointer (GObject *object, + gpointer *weak_pointer_location); +void g_object_remove_weak_pointer (GObject *object, + gpointer *weak_pointer_location); /* - Cycle handling -*/ -void g_object_run_dispose (GObject *object); + * Cycle handling + */ +void g_object_run_dispose (GObject *object); @@ -528,17 +507,13 @@ void g_object_run_dispose (GObject *object); /* Implementation */ /************************************************/ -enum { - MAMAN_BAR_CONSTRUCT_NAME = 1, - MAMAN_BAR_PAPA_NUMBER, -}; - -static void -maman_bar_instance_init (GTypeInstance *instance, - gpointer g_class) +enum { - MamanBar *self = (MamanBar *)instance; -} + PROP_0, + + PROP_MAMAN_NAME, + PROP_PAPA_NUMBER +}; static void maman_bar_set_property (GObject *object, @@ -546,61 +521,61 @@ maman_bar_set_property (GObject *object, const GValue *value, GParamSpec *pspec) { - MamanBar *self = (MamanBar *) object; + MamanBar *self = MAMAN_BAR (object); - switch (property_id) { - case MAMAN_BAR_CONSTRUCT_NAME: { - g_free (self->priv->name); - self->priv->name = g_value_dup_string (value); - g_print ("maman: %s\n",self->priv->name); - } - break; - case MAMAN_BAR_PAPA_NUMBER: { - self->priv->papa_number = g_value_get_uchar (value); - g_print ("papa: %u\n",self->priv->papa_number); - } - break; - default: - /* We don't have any other property... */ - G_OBJECT_WARN_INVALID_PROPERTY_ID(object,property_id,pspec); - break; - } + switch (property_id) + { + case PROP_MAMAN_NAME: + g_free (self->priv->name); + self->priv->name = g_value_dup_string (value); + g_print ("maman: %s\n", self->priv->name); + break; + + case PROP_PAPA_NUMBER: + self->priv->papa_number = g_value_get_uchar (value); + g_print ("papa: %u\n", self->priv->papa_number); + break; + + default: + /* We don't have any other property... */ + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } } static void -maman_bar_get_property (GObject *object, - guint property_id, - GValue *value, - GParamSpec *pspec) +maman_bar_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) { - MamanBar *self = (MamanBar *) object; + MamanBar *self = MAMAN_BAR (object); - switch (property_id) { - case MAMAN_BAR_CONSTRUCT_NAME: { - g_value_set_string (value, self->priv->name); - } - break; - case MAMAN_BAR_PAPA_NUMBER: { - g_value_set_uchar (value, self->priv->papa_number); - } - break; - default: - /* We don't have any other property... */ - G_OBJECT_WARN_INVALID_PROPERTY_ID(object,property_id,pspec); - break; - } + switch (property_id) + { + case PROP_MAMAN_NAME: + g_value_set_string (value, self->priv->name); + break; + + case PROP_PAPA_NUMBER: + g_value_set_uchar (value, self->priv->papa_number); + break; + + default: + /* We don't have any other property... */ + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } } static void -maman_bar_class_init (gpointer g_class, - gpointer g_class_data) +maman_bar_class_init (MamanBarClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (g_class); - MamanBarClass *klass = MAMAN_BAR_CLASS (g_class); GParamSpec *pspec; - gobject_class->set_property = maman_bar_set_property; - gobject_class->get_property = maman_bar_get_property; + gobject_class->set_property = maman_bar_set_property; + gobject_class->get_property = maman_bar_get_property; pspec = g_param_spec_string ("maman-name", "Maman construct prop", @@ -608,7 +583,7 @@ maman_bar_class_init (gpointer g_class, "no-name-set" /* default value */, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE); g_object_class_install_property (gobject_class, - MAMAN_BAR_CONSTRUCT_NAME, + PROP_MAMAN_NAME_NAME, pspec); pspec = g_param_spec_uchar ("papa-number", @@ -619,7 +594,7 @@ maman_bar_class_init (gpointer g_class, 2 /* default value */, G_PARAM_READWRITE); g_object_class_install_property (gobject_class, - MAMAN_BAR_PAPA_NUMBER, + PROP_PAPA_NUMBER, pspec); } @@ -628,11 +603,16 @@ maman_bar_class_init (gpointer g_class, /************************************************/ GObject *bar; -GValue val = {0,}; +GValue val = { 0, }; + bar = g_object_new (MAMAN_TYPE_SUBBAR, NULL); + g_value_init (&val, G_TYPE_CHAR); g_value_set_char (&val, 11); + g_object_set_property (G_OBJECT (bar), "papa-number", &val); + +g_value_unset (&val); The client code just above looks simple but a lot of things happen under the hood: @@ -765,7 +745,3 @@ g_object_set (G_OBJECT (foo), - - - - diff --git a/docs/reference/gobject/tut_gsignal.xml b/docs/reference/gobject/tut_gsignal.xml index 748b0a5bf..c372b8849 100644 --- a/docs/reference/gobject/tut_gsignal.xml +++ b/docs/reference/gobject/tut_gsignal.xml @@ -78,14 +78,14 @@ return_type function_callback (... , gpointer user_data); which have a pretty minimal API or the even simpler g_signal_connect functions (which will be presented a bit later :). -GClosure* g_cclosure_new (GCallback callback_func, - gpointer user_data, - GClosureNotify destroy_data); -GClosure* g_cclosure_new_swap (GCallback callback_func, - gpointer user_data, - GClosureNotify destroy_data); -GClosure* g_signal_type_cclosure_new (GType itype, - guint struct_offset); +GClosure *g_cclosure_new (GCallback callback_func, + gpointer user_data, + GClosureNotify destroy_data); +GClosure *g_cclosure_new_swap (GCallback callback_func, + gpointer user_data, + GClosureNotify destroy_data); +GClosure *g_signal_type_cclosure_new (GType itype, + guint struct_offset); @@ -203,16 +203,16 @@ return_type function_callback (gpointer instance, ... , gpointer user_data); To register a new signal on an existing type, we can use any of g_signal_newv, g_signal_new_valist or g_signal_new functions: -guint g_signal_newv (const gchar *signal_name, - GType itype, - GSignalFlags signal_flags, - GClosure *class_closure, - GSignalAccumulator accumulator, - gpointer accu_data, - GSignalCMarshaller c_marshaller, - GType return_type, - guint n_params, - GType *param_types); +guint g_signal_newv (const gchar *signal_name, + GType itype, + GSignalFlags signal_flags, + GClosure *class_closure, + GSignalAccumulator accumulator, + gpointer accu_data, + GSignalCMarshaller c_marshaller, + GType return_type, + guint n_params, + GType *param_types); The number of parameters to these functions is a bit intimidating but they are relatively simple: @@ -308,10 +308,10 @@ guint g_signal_newv (const gchar *signal_name, Signal emission is done through the use of the g_signal_emit family of functions. -void g_signal_emitv (const GValue *instance_and_params, - guint signal_id, - GQuark detail, - GValue *return_value); +void g_signal_emitv (const GValue *instance_and_params, + guint signal_id, + GQuark detail, + GValue *return_value); diff --git a/docs/reference/gobject/tut_gtype.xml b/docs/reference/gobject/tut_gtype.xml index 2f75f2443..d9c9bf233 100644 --- a/docs/reference/gobject/tut_gtype.xml +++ b/docs/reference/gobject/tut_gtype.xml @@ -787,7 +787,7 @@ struct _GInterfaceInfo When an instantiable classed type which registered an interface implementation is created for the first time, its class structure is initialized following the process described in . Once the class structure is - initialized,the function type_class_init_Wm (implemented in + initialized, the function type_class_init_Wm (implemented in gtype.c) initializes the interface implementations associated with that type by calling type_iface_vtable_init_Wm for each interface. diff --git a/docs/reference/gobject/tut_howto.xml b/docs/reference/gobject/tut_howto.xml index ac98aeb78..1785ce8dc 100644 --- a/docs/reference/gobject/tut_howto.xml +++ b/docs/reference/gobject/tut_howto.xml @@ -11,81 +11,66 @@ How to define and implement a new GObject - 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. The sample source code - associated with this section can be found in the documentation's source tarball, in the - sample/gobject directory: - - maman-bar.{h|c}: this is the source for a object which derives from - GObject and which shows how to declare different types of methods on the object. - - maman-subbar.{h|c}: this is the source for a object which derives from - MamanBar and which shows how to override some of its parent's methods. - - maman-foo.{h|c}: this is the source for an object which derives from - GObject and which declares a signal. - - test.c: this is the main source which instantiates an instance of - type and exercises their API. - - + 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. Boilerplate header code - 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: + 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: - 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) - - - 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. - + 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) + 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. Pick a name convention for your headers and source code and stick to it: - - use a dash to separate the prefix from the typename: maman-bar.h and - maman-bar.c (this is the convention used by Nautilus and most GNOME libraries). - - - use an underscore to separate the prefix from the typename: maman_bar.h and - maman_bar.c. - - - Do not separate the prefix from the typename: mamanbar.h and - mamanbar.c. (this is the convention used by GTK+) - + use a dash to separate the prefix from the typename: + maman-bar.h and maman-bar.c + (this is the convention used by Nautilus and most GNOME libraries). + use an underscore to separate the prefix from the + typename: maman_bar.h and + maman_bar.c. + Do not separate the prefix from the typename: + mamanbar.h and mamanbar.c. + (this is the convention used by GTK+) - I personally like the first solution better: it makes reading file names easier for those with poor - eyesight like me. + I personally like the first solution better: it makes reading file names + easier for those with poor eyesight like me. - 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 private keyword to the public header name. - For example, one could use maman-bar-private.h, - maman_bar_private.h or mamanbarprivate.h. - Typically, such private header files are not installed. + 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 private keyword + to the public header name. For example, one could use + maman-bar-private.h, + maman_bar_private.h or + mamanbarprivate.h. Typically, such private header + files are not installed. - The basic conventions for any header which exposes a GType are described in - . Most GObject-based code also obeys one of of the following - conventions: pick one and stick to it. + The basic conventions for any header which exposes a GType are described + in . Most GObject-based code also + obeys one of of the following conventions: pick one and stick to it. If you want to declare a type named bar with prefix maman, name the type instance @@ -97,9 +82,11 @@ * Copyright/Licensing information. */ -#ifndef MAMAN_BAR_H -#define MAMAN_BAR_H +/* inclusion guard */ +#ifndef __MAMAN_BAR_H__ +#define __MAMAN_BAR_H__ +#include <glib-object.h> /* * Potentially, include other headers on which this header depends. */ @@ -107,17 +94,27 @@ /* * 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; +typedef struct _MamanBar MamanBar; +typedef struct _MamanBarClass MamanBarClass; + +struct _MamanBar +{ + GObject parent_instance; -struct _MamanBar { - GObject parent; /* instance members */ }; -struct _MamanBarClass { - GObjectClass parent; +struct _MamanBarClass +{ + GObjectClass parent_class; + /* class members */ }; @@ -128,17 +125,20 @@ GType maman_bar_get_type (void); * Method definitions. */ -#endif +#endif /* __MAMAN_BAR_H__ */ - 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. + 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. -struct _MamanBar { - GObject parent; +struct _MamanBar +{ + GObject parent_instance; /*< private >*/ int hsize; @@ -146,92 +146,85 @@ struct _MamanBar { - All of Nautilus code and a lot of GNOME libraries use private indirection members, as described - by Herb Sutter in his Pimpl articles - (see Compilation Firewalls - and The Fast Pimpl Idiom - : he summarizes the different issues better than I will). + All of Nautilus code and a lot of GNOME libraries use private + indirection members, as described by Herb Sutter in his Pimpl + articles(see Compilation Firewalls + and The Fast Pimpl Idiom: + he summarizes the different issues better than I will). typedef struct _MamanBarPrivate MamanBarPrivate; -struct _MamanBar { - GObject parent; + +struct _MamanBar +{ + GObject parent_instance; /*< private >*/ MamanBarPrivate *priv; }; - Do not call this private, as that is a registered c++ keyword. - The private structure is then defined in the .c file, instantiated in the object's - init function and destroyed in the object's finalize function. + Do not call this private, as + that is a registered c++ keyword. + + 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 G_TYPE_INSTANCE_GET_PRIVATE() + each time is needed, or assigned to the priv + member of the instance structure inside the object's + init function. -static void -maman_bar_finalize (GObject *object) { - MamanBar *self = MAMAN_BAR (object); - /* do stuff */ - g_free (self->priv); +#define MAMAN_BAR_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), MAMAN_TYPE_BAR, MamanBarPrivate)) + +struct _MamanBarPrivate +{ + int hsize; } static void -maman_bar_init (GTypeInstance *instance, gpointer g_class) { - MamanBar *self = MAMAN_BAR (instance); - self->priv = g_new0 (MamanBarPrivate,1); - /* do stuff */ +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; } - A similar alternative, available since GLib version 2.4, is to define a private structure in the .c file, - declare it as a private structure in maman_bar_class_init using - g_type_class_add_private. - Instead of allocating memory in maman_bar_init a pointer to the private memory area is - stored in the instance to allow convenient access to this structure. - A private structure will then be attached to each newly created object by the GObject system. - 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. - -typedef struct _MamanBarPrivate MamanBarPrivate; - -struct _MamanBarPrivate { - int private_field; -}; - -static void -maman_bar_class_init (MamanBarClass *klass) -{ - ... - g_type_class_add_private (klass, sizeof (MamanBarPrivate)); - ... -} - -static void -maman_bar_init (GTypeInstance *instance, gpointer g_class) { - MamanBar *self = MAMAN_BAR (instance); - self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, MAMAN_TYPE_BAR, MamanBarPrivate); - /* do stuff */ -} - + 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. - - 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. + 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. - 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". + 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". - 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. + 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. @@ -242,9 +235,10 @@ maman_bar_init (GTypeInstance *instance, gpointer g_class) { Boilerplate code - 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": + 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": /* * Copyright information @@ -269,32 +263,29 @@ struct _MamanBarPrivate { - Implement maman_bar_get_type and make sure the code compiles: + Call the G_DEFINE_TYPE 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: + + + implement the maman_bar_get_type + function + define a parent class pointer accessible from + the whole .c file + + -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; -} +G_DEFINE_TYPE (MamanBar, maman_bar, G_TYPE_OBJECT); + + + It is also possible to use the + G_DEFINE_TYPE_WITH_CODE macro to control the + get_type function implementation - for instance, to add a call to + G_IMPLEMENT_INTERFACE macro which will + call the g_type_implement_interface function. + @@ -326,22 +317,17 @@ maman_bar_get_type (void) As such, I would recommend writing the following code first: static void -maman_bar_init (GTypeInstance *instance, - gpointer g_class) +maman_bar_init (MamanBar *self) { - MamanBar *self = (MamanBar *)instance; - self->private = g_new0 (MamanBarPrivate, 1); + self->private = 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. */ } - And make sure that you set maman_bar_init as the type's instance_init function - in maman_bar_get_type. Make sure the code builds and runs: create an instance - of the object and make sure maman_bar_init is called (add a - g_print call in it). @@ -364,8 +350,7 @@ bar_class_init (MamanBarClass *klass) "Maman construct prop", "Set maman's name", "no-name-set" /* default value */, - G_PARAM_CONSTRUCT_ONLY |G_PARAM_READWRITE); - + G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE); g_object_class_install_property (gobject_class, PROP_MAMAN, maman_param_spec); @@ -384,44 +369,45 @@ bar_class_init (MamanBarClass *klass) should have a good reason to do so. - 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 - . However, I have yet to see any reasonable - use of this feature. As such, to initialize your object instances, use by default the base_init function - and construction properties. - + + 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 + or, more simply, using + the constructed class method available since GLib 2.12. + Object Destruction - Again, it is often difficult to figure out which mechanism to use to hook into the object's - destruction process: when the last g_object_unref function call is made, - a lot of things happen as described in . + Again, it is often difficult to figure out which mechanism to use to + hook into the object's destruction process: when the last + g_object_unref + function call is made, a lot of things happen as described in + . - The destruction process of your object must be split is two different phases: you must override - both the dispose and the finalize class methods. + The destruction process of your object might be split in two different + phases: dispose and the finalize. -struct _MamanBarPrivate { - gboolean dispose_has_run; +#define MAMAN_BAR_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), MAMAN_TYPE_BAR, MamanBarPrivate)) + +struct _MamanBarPrivate +{ + GObject *an_object; + + gchar *a_string; }; -static GObjectClass *parent_class = NULL; +G_DEFINE_TYPE (MamanBar, maman_bar, G_TYPE_OBJECT); static void -bar_dispose (GObject *obj) +maman_bar_dispose (GObject *gobject) { - MamanBar *self = (MamanBar *)obj; - - if (self->priv->dispose_has_run) { - /* If dispose did already run, return. */ - return; - } - /* Make sure dispose does not run twice. */ - object->priv->dispose_has_run = TRUE; + MamanBar *self = MAMAN_BAR (gobject); /* * In dispose, you are supposed to free all types referenced from this @@ -430,56 +416,63 @@ bar_dispose (GObject *obj) * reference. */ - /* Chain up to the parent class */ - G_OBJECT_CLASS (parent_class)->dispose (obj); + /* 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 -bar_finalize (GObject *obj) +maman_bar_finalize (GObject *gobject) { - MamanBar *self = (MamanBar *)obj; + MamanBar *self = MAMAN_BAR (gobject); - /* Chain up to the parent class */ - G_OBJECT_CLASS (parent_class)->finalize (obj); + g_free (self->priv->a_string); + + /* Chain up to the parent class */ + G_OBJECT_CLASS (maman_bar_parent_class)->finalize (gobject); } static void -bar_class_init (BarClass *klass) +maman_bar_class_init (MamanBarClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - gobject_class->dispose = bar_dispose; - gobject_class->finalize = bar_finalize; + gobject_class->dispose = maman_bar_dispose; + gobject_class->finalize = maman_bar_finalize; - parent_class = g_type_class_peek_parent (klass); - g_type_class_add_private(klass,sizeof(MamanBarPrivate)); + g_type_class_add_private (klass, sizeof (MamanBarPrivate)); } static void -maman_bar_init (GTypeInstance *instance, - gpointer g_class) +maman_bar_init (MamanBar *self); { - MamanBar *self = (MamanBar *)instance; - self->priv = G_TYPE_INSTANCE_GET_PRIVATE(self, BT_TYPE_PATTERN, BtPatternPrivate); - self->priv->dispose_has_run = FALSE; + 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"); } - 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: - -if (self->private->dispose_has_run) { - /* Dispose has run. Data is not valid anymore. */ - return; -} - + 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. @@ -488,10 +481,11 @@ if (self->private->dispose_has_run) { 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. to refresh their - memories.) + 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. + to refresh + their memories.) non-virtual public methods, @@ -509,15 +503,20 @@ if (self->private->dispose_has_run) { Non-virtual public methods - 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 + 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. /* 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 */) +void +maman_bar_do_action (MamanBar *self, /* parameters */) { + g_return_if_fail (MAMAN_IS_BAR (self)); + /* do stuff here. */ } @@ -530,52 +529,66 @@ void maman_bar_do_action (MamanBar *self, /* parameters */) Virtual public methods - 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. + 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. /* declaration in maman-bar.h. */ -struct _MamanBarClass { - GObjectClass parent; +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 */) +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 */); } - The code above simply redirects the do_action call to the relevant class function. Some users, - concerned about performance, do not provide the maman_bar_do_action - 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. + The code above simply redirects the do_action call to the relevant + class function. Some users, concerned about performance, do not + provide the maman_bar_do_action 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. - Other users, also concerned by performance issues, declare the maman_bar_do_action - 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 inline keyword - is not part of the C standard). + Other users, also concerned by performance issues, declare + the maman_bar_do_action 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 inline keyword + is part of the C99 standard but not every compiler supports it). - In doubt, unless a user shows you hard numbers about the performance cost of the function call, - just maman_bar_do_action in the source file. + In doubt, unless a user shows you hard numbers about the performance + cost of the function call, just implement maman_bar_do_action + in the source file. - 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: + 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: -static void +static void maman_bar_real_do_action_two (MamanBar *self, /* parameters */) { /* Default implementation for the virtual method. */ @@ -586,16 +599,24 @@ 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 */) +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 */) + +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 */); } @@ -606,19 +627,23 @@ void maman_bar_do_action_two (MamanBar *self, /* parameters */) Virtual private Methods - 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: + 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: /* declaration in maman-bar.h. */ -struct _MamanBarClass { +struct _MamanBarClass +{ GObjectClass parent; /* stuff */ - void (*helper_do_specific_action) (MamanBar *self, /* parameters */); + void (* helper_do_specific_action) (MamanBar *self, /* parameters */); }; + void maman_bar_do_any_action (MamanBar *self, /* parameters */); - These class functions are often used to delegate part of the job to child classes: + These class functions are often used to delegate part of the job + to child classes: /* this accessor function is static: it is not exported outside of this file. */ static void @@ -627,13 +652,15 @@ 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 */) +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: + * 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 */); @@ -643,13 +670,15 @@ void maman_bar_do_any_action (MamanBar *self, /* parameters */) - Again, it is possible to provide a default implementation for this private virtual class function: + Again, it is possible to provide a default implementation for this + private virtual class function: 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; } @@ -663,6 +692,7 @@ 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; } @@ -674,7 +704,8 @@ maman_bar_subtype_class_init (MamanBarSubTypeClass *klass) Chaining up - Chaining up is often loosely defined by the following set of conditions: + Chaining up is often loosely defined by the following set of + conditions: Parent class A defines a public virtual method named foo and provides a default implementation. @@ -725,18 +756,17 @@ 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 */ } - A lot of people who use this idiom in GTK+ store the parent class structure pointer in a global static - variable to avoid the costly call to g_type_class_peek_parent for each function call. - Typically, the class_init callback initializes the global static variable. gtk/gtkhscale.c - does this. @@ -744,7 +774,6 @@ b_method_to_call (B *obj, int a) - How to define and implement interfaces @@ -753,30 +782,29 @@ b_method_to_call (B *obj, int a) The bulk of interface definition has already been shown in - 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 - sample/interface/maman-ibaz.{h|c} file. + but I feel it is needed to show exactly how to create an interface. As above, the first step is to get the header right: -#ifndef MAMAN_IBAZ_H -#define MAMAN_IBAZ_H +#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)) +#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; +typedef struct _MamanIbaz MamanIbaz; /* dummy object */ +typedef struct _MamanIbazInterface MamanIbazInterface; -struct _MamanIbazInterface { - GTypeInterface parent; +struct _MamanIbazInterface +{ + GTypeInterface parent_iface; void (*do_action) (MamanIbaz *self); }; @@ -785,7 +813,7 @@ GType maman_ibaz_get_type (void); void maman_ibaz_do_action (MamanIbaz *self); -#endif /*MAMAN_IBAZ_H*/ +#endif /* __MAMAN_IBAZ_H__ */ This code is the same as the code for a normal GType which derives from a GObject except for a few details: @@ -796,8 +824,13 @@ void maman_ibaz_do_action (MamanIbaz *self); but with G_TYPE_INSTANCE_GET_INTERFACE. - The instance type, MamanIbaz is not fully defined: it is used merely as an abstract - type which represents an instance of whatever object which implements the interface. + The instance type, MamanIbaz is not fully defined: it is + used merely as an abstract type which represents an instance of + whatever object which implements the interface. + + + The parent of the MamanIbazInterface is not + GObjectClass but GTypeInterface. @@ -815,45 +848,48 @@ void maman_ibaz_do_action (MamanIbaz *self); , base_init is run once for each interface implementation instantiation) - maman_ibaz_do_action dereferences the class - structure to access its associated class function and calls it. + maman_ibaz_do_action dereferences + the class structure to access its associated class function and calls it. static void maman_ibaz_base_init (gpointer g_class) { - static gboolean initialized = FALSE; + static gboolean is_initialized = FALSE; - if (!initialized) { - /* create interface signals here. */ - initialized = TRUE; - } + if (!is_initialized) + { + /* add properties and signals to the interface here */ + + is_initialized = TRUE; + } } GType maman_ibaz_get_type (void) { - static GType type = 0; - if (type == 0) { - static const GTypeInfo info = { - sizeof (MamanIbazInterface), - 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); - } + 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 type; } -void maman_ibaz_do_action (MamanIbaz *self) +void +maman_ibaz_do_action (MamanIbaz *self) { + g_return_if_fail (MAMAN_IS_IBAZ (self)); + MAMAN_IBAZ_GET_INTERFACE (self)->do_action (self); } @@ -864,114 +900,94 @@ void maman_ibaz_do_action (MamanIbaz *self) How To define implement an Interface? - Once the interface is defined, implementing it is rather trivial. Source code showing how to do this - for the IBaz interface defined in the previous section is located in - sample/interface/maman-baz.{h|c}. + Once the interface is defined, implementing it is rather trivial. - The first step is to define a normal GType. Here, we have decided to use a GType which derives from - GObject. Its name is MamanBaz: + The first step is to define a normal GObject class, like: -#ifndef MAMAN_BAZ_H -#define MAMAN_BAZ_H +#ifndef __MAMAN_BAZ_H__ +#define __MAMAN_BAZ_H__ -#include <glib-object.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_BAZ_CLASS(vtable) (G_TYPE_CHECK_CLASS_CAST ((vtable), MAMAN_TYPE_BAZ, MamanbazClass)) #define MAMAN_IS_BAZ(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MAMAN_TYPE_BAZ)) -#define MAMAN_IS_BAZ_CLASS(vtable) (G_TYPE_CHECK_CLASS_TYPE ((vtable), MAMAN_TYPE_BAZ)) -#define MAMAN_BAZ_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((inst), MAMAN_TYPE_BAZ, MamanbazClass)) +#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; +typedef struct _MamanBaz MamanBaz; +typedef struct _MamanBazClass MamanBazClass; + +struct _MamanBaz +{ + GObject parent_instance; -struct _MamanBaz { - GObject parent; int instance_member; }; -struct _MamanBazClass { - GObjectClass parent; +struct _MamanBazClass +{ + GObjectClass parent_class; }; GType maman_baz_get_type (void); +#endif /* __MAMAN_BAZ_H__ */ + + There is clearly nothing specifically weird or scary about this header: + it does not define any weird API or derives from a weird type. + + + + The second step is to implement MamanBaz by defining + its GType. Instead of using G_DEFINE_TYPE we + use G_DEFINE_TYPE_WITH_CODE and the + G_IMPLEMENT_INTERFACE macros. + +static void maman_ibaz_interface_init (MamanIbazInterface *iface); -#endif //MAMAN_BAZ_H +G_DEFINE_TYPE_WITH_CODE (MamanBar, maman_bar, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (MAMAN_TYPE_IBAZ, + maman_ibaz_interface_init)); - There is clearly nothing specifically weird or scary about this header: it does not define any weird API - or derives from a weird type. + 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 G_IMPLEMENT_INTERFACE. + + Classes can implement multiple interfaces by using multiple + calls to G_IMPLEMENT_INTERFACE inside the call + to G_DEFINE_TYPE_WITH_CODE. - The second step is to implement maman_baz_get_type: + maman_baz_interface_init, the interface + initialization function: inside it every virtual method of the interface + must be assigned to its implementation: -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_TYPE_IBAZ, - &ibaz_info); - } - return type; -} - - 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 g_type_add_interface_static which is used to inform - the type system that this just-registered GType also implements the interface - MAMAN_TYPE_IBAZ. - - - - baz_interface_init, the interface initialization function, is also pretty simple: - -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) +maman_baz_do_action (MamanBaz *self) { - MamanIbazInteface *iface = (MamanIbazInteface *)g_iface; - iface->do_action = (void (*) (MamanIbaz *self))baz_do_action; + g_print ("Baz implementation of IBaz interface Action: 0x%x.\n", + self->instance_member); } + static void -baz_instance_init (GTypeInstance *instance, - gpointer g_class) +maman_ibaz_interface_init (MamanIbazInterface *iface) { - MamanBaz *self = MAMAN_BAZ(instance); + iface->do_action = baz_do_action; +} + +static void +maman_baz_init (MamanBaz *self) +{ + MamanBaz *self = MAMAN_BAZ (instance); self->instance_member = 0xdeadbeaf; } - baz_interface_init merely initializes the interface methods to the implementations - defined by MamanBaz: maman_baz_do_action does nothing very useful - but it could :) @@ -980,125 +996,103 @@ baz_instance_init (GTypeInstance *instance, Interface definition prerequisites - To specify that an interface requires the presence of other interfaces when implemented, - GObject introduces the concept of prerequisites: 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. + To specify that an interface requires the presence of other interfaces + when implemented, GObject introduces the concept of + prerequisites: 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. - The mechanism described above is, in practice, very similar to Java's interface I1 extends - interface I2. The example below shows the GObject equivalent: - + The mechanism described above is, in practice, very similar to + Java's interface I1 extends interface I2. The example below shows + the GObject equivalent: + /* 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); - 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: + 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: -static void ibar_do_another_action (MamanBar *self) +static void +maman_ibar_do_another_action (MamanIbar *ibar) { - g_print ("Bar implementation of IBar interface Another Action: 0x%x.\n", self->instance_member); + MamanBar *self = MAMAN_BAR (ibar); + + 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) +maman_ibar_interface_init (MamanIbarInterface *iface) { - MamanIbarInterface *iface = (MamanIbarInterface *)g_iface; - iface->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); + iface->do_another_action = maman_ibar_do_another_action; } static void -ibaz_interface_init (gpointer g_iface, - gpointer iface_data) +maman_ibaz_do_action (MamanIbaz *ibaz) { - MamanIbazInterface *iface = (MamanIbazInterface *)g_iface; - iface->do_action = (void (*) (MamanIbaz *self))ibaz_do_action; + MamanBar *self = MAMAN_BAR (ibaz); + + g_print ("Bar implementation of IBaz interface Action: 0x%x.\n", + self->instance_member); } static void -bar_instance_init (GTypeInstance *instance, - gpointer g_class) +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) { - 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_TYPE_IBAZ, - &ibaz_info); - g_type_add_interface_static (type, - MAMAN_TYPE_IBAR, - &ibar_info); - } - return type; -} +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)); - It is very important to notice that the order in which interface implementations are added to the main object - is not random: g_type_add_interface_static must be invoked first on the interfaces which have - no prerequisites and then on the others. + It is very important to notice that the order in which interface + implementations are added to the main object is not random: + g_type_add_interface_static, + which is called by G_IMPLEMENT_INTERFACE, must be + invoked first on the interfaces which have no prerequisites and then on + the others. - - - Complete source code showing how to define the MamanIbar interface which requires MamanIbaz and how to - implement the MamanIbar interface is located in sample/interface/maman-ibar.{h|c} - and sample/interface/maman-bar.{h|c}. - - Interface Properties - 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 , + 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 + , except that g_object_interface_install_property is used to declare the properties instead of g_object_class_install_property. To include a property named 'name' of type string in the - maman_ibaz interface example code above, we only need to add one + maman_ibaz interface example code above, we only need to + add one That really is one line extended to six for the sake of clarity @@ -1107,8 +1101,9 @@ maman_bar_get_type (void) line in the maman_ibaz_base_init - The g_object_interface_install_property can also be called from - class_init but it must not be called after that point. + The g_object_interface_install_property + can also be called from class_init but it must + not be called after that point. as shown below: @@ -1116,140 +1111,106 @@ maman_bar_get_type (void) static void maman_ibaz_base_init (gpointer g_iface) { - static gboolean initialized = FALSE; + static gboolean is_initialized = FALSE; - if (!initialized) { - /* create interface signals here. */ - - g_object_interface_install_property (g_iface, - g_param_spec_string ("name", - "maman_ibaz_name", - "Name of the MamanIbaz", - "maman", - G_PARAM_READWRITE)); - initialized = TRUE; - } + 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; + } } One point worth noting is that the declared property wasn't assigned an - integer ID. The reason being that integer IDs of properties are utilized 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. + 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. - The story for the implementers of the interface is also quite trivial. - An implementer shall declare and define it's properties in the usual way as - explained in , except for one small - change: it shall declare the properties of the interface it implements using - g_object_class_override_property instead of - g_object_class_install_property. The following code snippet - shows the modifications needed in the MamanBaz declaration and - implementation above: + An implementation shall declare and define it's properties in the usual + way as explained in , except for one + small change: it must declare the properties of the interface it + implements using g_object_class_override_property + instead of g_object_class_install_property. + The following code snippet shows the modifications needed in the + MamanBaz declaration and implementation above: -struct _MamanBaz { - GObject parent; +struct _MamanBaz +{ + GObject parent_instance; + gint instance_member; - gchar *name; /* placeholder for property */ + gchar *name; }; enum { - ARG_0, - ARG_NAME + PROP_0, + + PROP_NAME }; -GType -maman_baz_get_type (void) +static void +maman_baz_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) { - static GType type = 0; - if (type == 0) { - static const GTypeInfo info = { - sizeof (MamanBazClass), - NULL, /* base_init */ - NULL, /* base_finalize */ - baz_class_init, /* 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_TYPE_IBAZ, - &ibaz_info); - } - return type; + 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_class_init (MamanBazClass * klass) +maman_baz_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) { - GObjectClass *gobject_class; + MamanBaz *baz = MAMAN_BAZ (object); - gobject_class = (GObjectClass *) klass; + switch (prop_id) + { + case ARG_NAME: + g_value_set_string (value, baz->name); + break; - parent_class = g_type_class_ref (G_TYPE_OBJECT); + 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, ARG_NAME, "name"); -} - -static void -maman_baz_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec) -{ - MamanBaz *baz; - GObject *obj; - - /* it's not null if we got it, but it might not be ours */ - g_return_if_fail (G_IS_MAMAN_BAZ (object)); - - baz = MAMAN_BAZ (object); - - switch (prop_id) { - case ARG_NAME: - baz->name = g_value_get_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; - - /* it's not null if we got it, but it might not be ours */ - g_return_if_fail (G_IS_TEXT_PLUGIN (object)); - - 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; - } + g_object_class_override_property (gobject_class, PROP_NAME, "name"); } @@ -1262,50 +1223,52 @@ maman_baz_get_property (GObject * object, guint prop_id, How to create and use signals - - 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) + 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) - A Python callback can be connected to any signal on any C-based GObject. + A Python callback can be connected to any signal on any + C-based GObject. - 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. + 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. - Simple use of signals + Simple use of signals - 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 sample/signal/maman-file.{h|c} and - in sample/signal/test.c + 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. file = g_object_new (MAMAN_FILE_TYPE, NULL); -g_signal_connect (G_OBJECT (file), "write", - (GCallback)write_event, - NULL); +g_signal_connect (file, "changed", G_CALLBACK (changed_event), NULL); -maman_file_write (file, buffer, 50); +maman_file_write (file, buffer, strlen (buffer)); - The MamanFile signal is registered in the class_init function: + The MamanFile signal is registered in the class_init + function: -klass->write_signal_id = - g_signal_newv ("write", - G_TYPE_FROM_CLASS (g_class), +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 /* class closure */, + NULL /* closure */, NULL /* accumulator */, - NULL /* accu_data */, + NULL /* accumulator data */, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE /* return_type */, 0 /* n_params */, @@ -1313,51 +1276,68 @@ klass->write_signal_id = and the signal is emitted in maman_file_write: -void maman_file_write (MamanFile *self, guint8 *buffer, guint32 size) +void +maman_file_write (MamanFile *self, + const guchar *buffer, + gssize 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); + g_signal_emit (self, file_signals[CHANGED], 0 /* details */); } - 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 + 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 The signature of the signal handler in the above example is defined as g_cclosure_marshal_VOID__VOID. 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. - The header gobject/gmarshal.h defines a set of commonly - needed closures that one can use. + 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. + + + + The header gobject/gmarshal.h 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. + + + + +