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)
+{
+
+}
+
+
+
+
+