diff --git a/docs/reference/gobject/tut_gtype.xml b/docs/reference/gobject/tut_gtype.xml index 477a7feaa..479537e98 100644 --- a/docs/reference/gobject/tut_gtype.xml +++ b/docs/reference/gobject/tut_gtype.xml @@ -322,8 +322,9 @@ GType maman_bar_get_type (void) - When having no special requirements you also can use the G_DEFINE_TYPE - macro: + If you have no special requirements you can use the + G_DEFINE_TYPE + macro to define a class: G_DEFINE_TYPE (MamanBar, maman_bar, G_TYPE_OBJECT) @@ -688,7 +689,7 @@ void maman_ibaz_do_action (MamanIbaz *self) MAMAN_IBAZ_GET_INTERFACE (self)->do_action (self); } - maman_ibaz_get_type registers a type named MamanIBaz + maman_ibaz_get_type registers a type named MamanIbaz which inherits from G_TYPE_INTERFACE. All interfaces must be children of G_TYPE_INTERFACE in the inheritance tree. @@ -706,14 +707,13 @@ void maman_ibaz_do_action (MamanIbaz *self) Once an interface type is registered, you must register implementations for these interfaces. The function named maman_baz_get_type registers a new GType named MamanBaz which inherits from GObject and which - implements the interface MamanIBaz. + implements the interface MamanIbaz. static void maman_baz_do_action (MamanIbaz *self) { - g_print ("Baz implementation of IBaz interface Action.\n"); + g_print ("Baz implementation of Ibaz interface Action.\n"); } - static void baz_interface_init (gpointer g_iface, gpointer iface_data) @@ -728,7 +728,7 @@ maman_baz_get_type (void) static GType type = 0; if (type == 0) { const GTypeInfo info = { - sizeof (MamanBazInterface), + sizeof (MamanBazClass), NULL, /* base_init */ NULL, /* base_finalize */ NULL, /* class_init */ @@ -771,22 +771,38 @@ struct _GInterfaceInfo }; + - When having no special requirements you also can use the G_DEFINE_INTERFACE macro: + If you have no special requirements you can use the + G_IMPLEMENT_INTERFACE macro + to implement an interface: -G_DEFINE_INTERFACE (MamanBaz, maman_baz, G_TYPE_OBJECT) +static void +maman_baz_do_action (MamanIbaz *self) +{ + g_print ("Baz implementation of Ibaz interface Action.\n"); +} + +static void +maman_ibaz_interface_init (MamanIbazInterface *iface) +{ + iface->do_action = maman_baz_do_action; +} + +G_DEFINE_TYPE_WITH_CODE (MamanBaz, maman_baz, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (MAMAN_TYPE_IBAZ, + maman_ibaz_interface_init)); - Interface Initialization - 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 . + When an instantiable classed type which implements an interface + (either directly or by inheriting an implementation from a superclass) + is created for the first time, its class structure is initialized + following the process described in . After that, the interface implementations associated with the type are initialized. @@ -802,28 +818,65 @@ G_DEFINE_INTERFACE (MamanBaz, maman_baz, G_TYPE_OBJECT) - Finally, the interface' most-derived base_init function and then + The interface's base_init function is called, + and then the interface's default_init is invoked. + Finally if the type has registered an implementation of the interface, the implementation's interface_init - function are invoked. It is important to understand that if there are multiple - implementations of an interface the base_init and - interface_init functions will be - invoked once for each implementation initialized. + function is invoked. If there are multiple implementations of an + interface the base_init and + interface_init functions will be invoked once + for each implementation initialized. - It is thus common for base_init functions to hold a local static boolean variable - which makes sure that the interface type is initialized only once even if there are - multiple implementations of the interface: + It is thus recommended to use a default_init function to + initialize an interface. This function is called only once for the interface no + matter how many implementations there are. The + default_init function is declared by + G_DEFINE_INTERFACE + which can be used to define the interface: -static void -maman_ibaz_base_init (gpointer g_iface) -{ - static gboolean initialized = FALSE; +G_DEFINE_INTERFACE (MamanIbaz, maman_ibaz, G_TYPE_OBJECT); - if (!initialized) { - /* create interface signals here. */ - initialized = TRUE; +static void +maman_ibaz_default_init (MamanIbazInterface *iface) +{ + /* add properties and signals here, will only called once */ +} + + + + + Or you can do that yourself in a GType function for your interface: + +GType +maman_ibaz_get_type (void) +{ + static volatile gsize type_id = 0; + if (g_once_init_enter (&type_id)) { + const GTypeInfo info = { + sizeof (MamanIbazInterface), + NULL, /* base_init */ + NULL, /* base_finalize */ + maman_ibaz_default_init, /* class_init */ + NULL, /* class_finalize */ + NULL, /* class_data */ + 0, /* instance_size */ + 0, /* n_preallocs */ + NULL /* instance_init */ + }; + GType type = g_type_register_static (G_TYPE_INTERFACE, + "MamanIbaz", + &info, 0); + g_once_init_leave (&type_id, type); } + return type_id; +} + +static void +maman_ibaz_default_init (MamanIbazInterface *iface) +{ + /* add properties and signals here, will only called once */ } @@ -835,7 +888,6 @@ maman_ibaz_base_init (gpointer g_iface) - The above process can be summarized as follows: Interface Initialization @@ -853,24 +905,31 @@ maman_ibaz_base_init (gpointer g_iface) - First call to g_type_create_instance for type - implementing interface + First call to g_type_create_instance + for any type implementing interface - interface' base_init function - On interface' vtable - Register interface' signals here (use a local static - boolean variable as described above to make sure not to register them - twice.). + interface's base_init function + On interface's vtable + Rarely necessary to use this. Called once per instantiated classed type implementing the interface. - - interface' interface_init function - On interface' vtable + First call to g_type_create_instance + for each type implementing interface + + interface's default_init function + On interface's vtable + Register interface's signals, properties, etc. here. Will be called once. + + + First call to g_type_create_instance + for any type implementing interface + + implementation's interface_init function + On interface's vtable - Initialize interface' implementation. That is, initialize the interface - method pointers in the interface structure to the function's implementation. + Initialize interface implementation. Called for each class that that + implements the interface. Initialize the interface method pointers + in the interface structure to the implementing class's implementation. diff --git a/docs/reference/gobject/tut_howto.xml b/docs/reference/gobject/tut_howto.xml index 4401ad6a7..744552bc2 100644 --- a/docs/reference/gobject/tut_howto.xml +++ b/docs/reference/gobject/tut_howto.xml @@ -794,7 +794,7 @@ b_method_to_call (B *obj, int a) How to define and implement interfaces - How to define interfaces + How to define an interface The bulk of interface definition has already been shown in @@ -802,7 +802,8 @@ b_method_to_call (B *obj, int a) - As above, the first step is to get the header right: + As above, the first step is to get the header right. This interface + defines two methods: #ifndef __MAMAN_IBAZ_H__ #define __MAMAN_IBAZ_H__ @@ -823,11 +824,13 @@ struct _MamanIbazInterface GTypeInterface parent_iface; void (*do_action) (MamanIbaz *self); + void (*do_something) (MamanIbaz *self); }; GType maman_ibaz_get_type (void); -void maman_ibaz_do_action (MamanIbaz *self); +void maman_ibaz_do_action (MamanIbaz *self); +void maman_ibaz_do_something (MamanIbaz *self); #endif /* __MAMAN_IBAZ_H__ */ @@ -854,51 +857,28 @@ void maman_ibaz_do_action (MamanIbaz *self); The implementation of the MamanIbaz type itself is trivial: - maman_ibaz_get_type registers the - type in the type system. + G_DEFINE_INTERFACE + creates a maman_ibaz_get_type function which registers the + type in the type system. The third argument is used to define a + prerequisite interface + (which we'll talk about more later). Just pass 0 for this + argument when an interface has no prerequisite. - maman_ibaz_base_init is expected + maman_ibaz_default_init 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 - , - 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. + later how to use them). + The interface methods maman_ibaz_do_action + and maman_ibaz_do_something dereference the interface + structure to access its associated interface function and call it. +G_DEFINE_INTERFACE (MamanIbaz, maman_ibaz, 0); + static void -maman_ibaz_base_init (gpointer g_class) +maman_ibaz_default_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) - { - 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; + /* add properties and signals to the interface here */ } void @@ -908,12 +888,20 @@ maman_ibaz_do_action (MamanIbaz *self) MAMAN_IBAZ_GET_INTERFACE (self)->do_action (self); } + +void +maman_ibaz_do_something (MamanIbaz *self) +{ + g_return_if_fail (MAMAN_IS_IBAZ (self)); + + MAMAN_IBAZ_GET_INTERFACE (self)->do_something (self); +} - How To define implement an Interface? + How to implement an interface Once the interface is defined, implementing it is rather trivial. @@ -954,15 +942,22 @@ 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. + it does not define any weird API or derive 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. + 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); @@ -971,13 +966,15 @@ G_DEFINE_TYPE_WITH_CODE (MamanBar, maman_bar, G_TYPE_OBJECT, maman_ibaz_interface_init)); 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. + 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. + Classes can implement multiple interfaces by using multiple calls to + G_IMPLEMENT_INTERFACE + inside the call to + G_DEFINE_TYPE_WITH_CODE + maman_baz_interface_init, the interface @@ -987,14 +984,22 @@ G_DEFINE_TYPE_WITH_CODE (MamanBar, maman_bar, G_TYPE_OBJECT, static void maman_baz_do_action (MamanBaz *self) { - g_print ("Baz implementation of IBaz interface Action: 0x%x.\n", + g_print ("Baz implementation of Ibaz interface Action: 0x%x.\n", + self->instance_member); +} + +static void +maman_baz_do_something (MamanBaz *self) +{ + g_print ("Baz implementation of Ibaz interface Something: 0x%x.\n", self->instance_member); } static void maman_ibaz_interface_init (MamanIbazInterface *iface) { - iface->do_action = baz_do_action; + iface->do_action = maman_baz_do_action; + iface->do_something = maman_baz_do_something; } static void @@ -1005,17 +1010,16 @@ maman_baz_init (MamanBaz *self) } - - + 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 + a list of prerequisite types 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. @@ -1025,16 +1029,15 @@ maman_baz_init (MamanBaz *self) 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); +/* Make the MamanIbar interface require MamanIbaz interface. */ +G_DEFINE_INTERFACE (MamanIbar, maman_ibar, 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: + In the G_DEFINE_INTERFACE + call above, the third parameter defines the prerequisite type. This + is the GType of either an interface or a class. In this case + the MamanIbaz interface is a prerequisite of the MamanIbar. The code + below shows how an implementation can implement both interfaces and + register their implementations: static void maman_ibar_do_another_action (MamanIbar *ibar) @@ -1056,7 +1059,16 @@ maman_ibaz_do_action (MamanIbaz *ibaz) { MamanBar *self = MAMAN_BAR (ibaz); - g_print ("Bar implementation of IBaz interface Action: 0x%x.\n", + g_print ("Bar implementation of Ibaz interface Action: 0x%x.\n", + self->instance_member); +} + +static void +maman_ibaz_do_something (MamanIbaz *ibaz) +{ + MamanBar *self = MAMAN_BAR (ibaz); + + g_print ("Bar implementation of Ibaz interface Something: 0x%x.\n", self->instance_member); } @@ -1064,6 +1076,7 @@ static void maman_ibaz_interface_init (MamanIbazInterface *iface) { iface->do_action = maman_ibaz_do_action; + iface->do_something = maman_ibaz_do_something; } static void @@ -1087,22 +1100,24 @@ G_DEFINE_TYPE_WITH_CODE (MamanBar, maman_bar, G_TYPE_OBJECT, 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 + which is called by + G_IMPLEMENT_INTERFACE, + must be invoked first on the interfaces which have no prerequisites and then on the others. - Interface Properties + Interface properties - Starting from version 2.4 of GLib, GObject interfaces can also have + 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. + , except that + g_object_interface_install_property + is used to declare the properties instead of + g_object_class_install_property. @@ -1114,31 +1129,17 @@ G_DEFINE_TYPE_WITH_CODE (MamanBar, maman_bar, G_TYPE_OBJECT, That really is one line extended to six for the sake of clarity - 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. - - - as shown below: + line in the maman_ibaz_default_init as shown below: static void -maman_ibaz_base_init (gpointer g_iface) +maman_ibaz_default_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; - } + g_object_interface_install_property (g_iface, + g_param_spec_string ("name", + "Name", + "Name of the MamanIbaz", + "maman", + G_PARAM_READWRITE)); } @@ -1152,9 +1153,9 @@ maman_ibaz_base_init (gpointer g_iface) - An implementation shall declare and define it's properties in the usual + An implementation declares and defines it's properties in the usual way as explained in , except for one - small change: it must declare the properties of the interface it + small change: it can 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 @@ -1233,6 +1234,118 @@ maman_baz_class_init (MamanBazClass *klass) + + + Overriding interface methods + + + If a base class already implements an interface, and in a derived + class you wish to implement the same interface overriding only certain + methods of that interface, you just reimplement the interface and + set only the interface methods you wish to override. + + + + In this example MamanDerivedBaz is derived from MamanBaz. Both + implement the MamanIbaz interface. MamanDerivedBaz only implements one + method of the MamanIbaz interface and uses the base class implementation + of the other. + +static void +maman_derived_ibaz_do_action (MamanIbaz *ibaz) +{ + MamanDerivedBaz *self = MAMAN_DERIVED_BAZ (ibaz); + g_print ("DerivedBaz implementation of Ibaz interface Action\n"); +} + +static void +maman_derived_ibaz_interface_init (MamanIbazInterface *iface) +{ + /* Override the implementation of do_action */ + iface->do_action = maman_derived_ibaz_do_action; + + /* + * We simply leave iface->do_something alone, it is already set to the + * base class implementation. + */ +} + +G_DEFINE_TYPE_WITH_CODE (MamanDerivedBaz, maman_derived_baz, MAMAN_TYPE_BAZ, + G_IMPLEMENT_INTERFACE (MAMAN_TYPE_IBAZ, + maman_derived_ibaz_interface_init) + +static void +maman_derived_baz_class_init (MamanDerivedBazClass *klass) +{ + +} + +static void +maman_derived_baz_init (MamanDerivedBaz *self) +{ + +} + + + + + To access the base class interface implementation use + g_type_interface_peek_parent + from within an interface's default_init function. + + + + If you wish to call the base class implementation of an interface + method from an derived class where than interface method has been + overridden then you can stash away the pointer returned from + g_type_interface_peek_parent + in a global variable. + + + + In this example MamanDerivedBaz overides the + do_action interface method. In it's overridden method + it calls the base class implementation of the same interface method. + +static MamanIbazInterface *maman_ibaz_parent_interface = NULL; + +static void +maman_derived_ibaz_do_action (MamanIbaz *ibaz) +{ + MamanDerivedBaz *self = MAMAN_DERIVED_BAZ (ibaz); + g_print ("DerivedBaz implementation of Ibaz interface Action\n"); + + /* Now we call the base implementation */ + maman_ibaz_parent_interface->do_action (ibaz); +} + +static void +maman_derived_ibaz_interface_init (MamanIbazInterface *iface) +{ + maman_ibaz_parent_interface = g_type_interface_peek_parent (iface); + iface->do_action = maman_derived_ibaz_do_action; +} + +G_DEFINE_TYPE_WITH_CODE (MamanDerivedBaz, maman_derived_baz, MAMAN_TYPE_BAZ, + G_IMPLEMENT_INTERFACE (MAMAN_TYPE_IBAZ, + maman_derived_ibaz_interface_init) + +static void +maman_derived_baz_class_init (MamanDerivedBazClass *klass) +{ + +} + +static void +maman_derived_baz_init (MamanDerivedBaz *self) +{ + +} + + + + +