From acba30a9ebc5b80041d5d882ca70bf5940ffbdfb Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Thu, 4 Nov 2004 14:52:33 +0000 Subject: [PATCH] integrate patch from Stefan Kost --- docs/reference/gobject/tut_gobject.xml | 31 ++--- docs/reference/gobject/tut_gtype.xml | 15 +-- docs/reference/gobject/tut_howto.xml | 200 +++++++++++++++++++++++++++++++-- 3 files changed, 218 insertions(+), 28 deletions(-) diff --git a/docs/reference/gobject/tut_gobject.xml b/docs/reference/gobject/tut_gobject.xml index 0d3fd3a..15c198a 100644 --- a/docs/reference/gobject/tut_gobject.xml +++ b/docs/reference/gobject/tut_gobject.xml @@ -28,16 +28,18 @@ 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 - has been correctly initialized by glib's type system and then invoke at one - point or another the constructor class method which is used to: + 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 memory through g_type_create_instance, + Allocate and clear memory through g_type_create_instance, Initialize the object' 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. @@ -56,7 +58,7 @@ #define MAMAN_TYPE_BAR (maman_bar_get_type ()) #define MAMAN_BAR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MAMAN_TYPE_BAR, MamanBar)) #define MAMAN_BAR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MAMAN_TYPE_BAR, MamanBarClass)) -#define MAMAN_IS_BAR(obj) (G_TYPE_CHECK_TYPE ((obj), MAMAN_TYPE_BAR)) +#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)) @@ -285,7 +287,8 @@ MamanBar *bar = g_object_new (MAMAN_TYPE_BAR, NULL); The memory-management API for GObjects is a bit complicated but the idea behind it is pretty simple: the goal is to provide a flexible model based on reference counting which can be integrated in applications which use or require different memory management - models (such as garbage collection, aso...) + models (such as garbage collection, aso...). The methods which are used to + manipulate this reference count are described below. /* Refcounting @@ -319,10 +322,12 @@ void g_object_run_dispose (GObject *object); Reference count - g_object_ref/g_object_unref respectively + The functions g_object_ref/g_object_unref respectively increase and decrease the reference count. None of these function is thread-safe. The reference count is, unsurprisingly, initialized to one by - g_object_new. When the reference count reaches zero, that is, + g_object_new which means that the caller + is currenly the sole owner of the newly-created reference. + When the reference count reaches zero, that is, when g_object_unref is called by the last client holding a reference to the object, the dispose and the finalize class methods are invoked. @@ -334,8 +339,8 @@ void g_object_run_dispose (GObject *object); one of the g_type_register_* functions), the object's instance memory will be freed or returned to the object pool for this type. Once the object has been freed, if it was the last instance of the type, the type's class - will be destroyed as described in and - . + will be destroyed as described in and + . @@ -383,7 +388,7 @@ void g_object_run_dispose (GObject *object); finalize should chain up to its parent implementation just before returning to the caller. The reason why the destruction process is split is two different phases is - explained in . + explained in . @@ -521,7 +526,7 @@ void g_object_run_dispose (GObject *object); enum { MAMAN_BAR_CONSTRUCT_NAME = 1, - MAMAN_BAR_PAPA_NUMBER = 2, + MAMAN_BAR_PAPA_NUMBER, }; static void @@ -554,7 +559,7 @@ maman_bar_set_property (GObject *object, break; default: /* We don't have any other property... */ - g_assert (FALSE); + G_OBJECT_WARN_INVALID_PROPERTY_ID(object,property_id,pspec); break; } } @@ -578,7 +583,7 @@ maman_bar_get_property (GObject *object, break; default: /* We don't have any other property... */ - g_assert (FALSE); + G_OBJECT_WARN_INVALID_PROPERTY_ID(object,property_id,pspec); break; } } diff --git a/docs/reference/gobject/tut_gtype.xml b/docs/reference/gobject/tut_gtype.xml index 59fd5ac..9c81144 100644 --- a/docs/reference/gobject/tut_gtype.xml +++ b/docs/reference/gobject/tut_gtype.xml @@ -282,10 +282,11 @@ struct _GTypeValueTable #define MAMAN_BAR_TYPE (maman_bar_get_type ()) #define MAMAN_BAR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MAMAN_BAR_TYPE, MamanBar)) #define MAMAN_BAR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MAMAN_BAR_TYPE, MamanBarClass)) -#define MAMAN_IS_BAR(obj) (G_TYPE_CHECK_TYPE ((obj), MAMAN_BAR_TYPE)) +#define MAMAN_IS_BAR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MAMAN_BAR_TYPE)) #define MAMAN_IS_BAR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MAMAN_BAR_TYPE)) #define MAMAN_BAR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MAMAN_BAR_TYPE, MamanBarClass)) + Stick to the naming klass as class is a registered c++ keyword. @@ -609,7 +610,7 @@ The class initialization process is entirely implemented in First call to g_type_create_instance for target type interface initialization, see - + Each call to g_type_create_instance for target type @@ -619,7 +620,7 @@ The class initialization process is entirely implemented in Last call to g_type_free_instance for target type interface destruction, see - + @@ -646,7 +647,7 @@ The class initialization process is entirely implemented in GType's Interfaces are very similar to Java's interfaces. To declare one of these you have to register a non-instantiable classed type which derives from - GTypeInterface. The following piece of code declares such an interface. + GTypeInterface. The following piece of code declares such an interface. #define MAMAN_IBAZ_TYPE (maman_ibaz_get_type ()) #define MAMAN_IBAZ(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MAMAN_IBAZ_TYPE, MamanIbaz)) @@ -765,7 +766,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 + described in . Once the class structure is 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 @@ -857,7 +858,7 @@ maman_ibaz_base_init (gpointer g_class) It is highly unlikely (ie: I do not know of anyone who actually used it) you will ever need other more fancy things such as the ones described in the - following section (). + following section (). @@ -879,7 +880,7 @@ maman_ibaz_base_init (gpointer g_class) Again, it is important to understand, as in - , + , that both interface_finalize and base_finalize are invoked exactly once for the destruction of each implementation of an interface. Thus, if you were to use one of these functions, you would need to use a static integer variable diff --git a/docs/reference/gobject/tut_howto.xml b/docs/reference/gobject/tut_howto.xml index 6b3f63f..be5c35e 100644 --- a/docs/reference/gobject/tut_howto.xml +++ b/docs/reference/gobject/tut_howto.xml @@ -78,6 +78,15 @@ + 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 onf of the following conventions: pick one and stick to it. @@ -143,8 +152,10 @@ 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 http://www.gotw.ca/publications/mill04.htm: Herb summarizes the different - issues better than I will): + 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 { @@ -154,6 +165,7 @@ struct _MamanBar { 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. @@ -436,7 +448,7 @@ 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 http://www.cplusplus.com/doc/tutorial/ to refresh their + write C++ code recently can refer to e.g. http://www.cplusplus.com/doc/tutorial/ to refresh their memories.) @@ -931,8 +943,6 @@ 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 @@ -1039,6 +1049,172 @@ maman_bar_get_type (void) + + 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 , + 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 + + That really is one line extended to six for the sake of clarity + + + line in the maman_ibaz_base_init + + The gobject_install_property can also be called from class_init but it must not be called after that point. + + + as shown below: + +static void +maman_ibaz_base_init (gpointer g_class) +{ + static gboolean initialized = FALSE; + + if (!initialized) { + /* create interface signals here. */ + + g_object_interface_install_property (g_class, + g_param_spec_string ("name", + "maman_ibaz_name", + "Name of the MamanIbaz", + "maman", + G_PARAM_READWRITE)); + initialized = TRUE; + } +} + + + + One point worth noting is that the declared property wasn't assigned an + integer ID. The reason being that integer IDs of properities 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. + + + 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 snipet + shows the modifications needed in the MamanBaz declaration and + implementation above: + + +struct _MamanBaz { + GObject parent; + gint instance_member; + gchar *name; /* placeholder for property */ +}; + +enum +{ + ARG_0, + ARG_NAME +}; + +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 */ + 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; +} + +static void +maman_baz_class_init (MamanBazClass * klass) +{ + GObjectClass *gobject_class; + + gobject_class = (GObjectClass *) klass; + + parent_class = g_type_class_ref (G_TYPE_OBJECT); + + 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; + } +} + + + + + + +