mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-02-02 17:26:17 +01:00
Fix up GObject interface documentation
* Document how to override interfaces already implemented in a base class, and also call those base class implementations from a derived reimplementation. * Don't recomend people use base_init() style functions to initialize interface signals and properties, use default_init() aka class_init() instead (as G_DEFINE_INTERFACE() uses). * The above solves the interface init called multiple times problem, so remove some needless naysaying about that. * Document default_init() in the interface initialization discussion * Linkify more stuff. * Remove some crud and typos https://bugzilla.gnome.org/show_bug.cgi?id=675504
This commit is contained in:
parent
2cf9608d48
commit
3b0f1cc432
@ -322,8 +322,9 @@ GType maman_bar_get_type (void)
|
||||
</para>
|
||||
|
||||
<para>
|
||||
When having no special requirements you also can use the <function>G_DEFINE_TYPE</function>
|
||||
macro:
|
||||
If you have no special requirements you can use the
|
||||
<function><link linkend="G-DEFINE-TYPE:CAPS">G_DEFINE_TYPE</link></function>
|
||||
macro to define a class:
|
||||
<programlisting>
|
||||
G_DEFINE_TYPE (MamanBar, maman_bar, G_TYPE_OBJECT)
|
||||
</programlisting>
|
||||
@ -688,7 +689,7 @@ void maman_ibaz_do_action (MamanIbaz *self)
|
||||
MAMAN_IBAZ_GET_INTERFACE (self)->do_action (self);
|
||||
}
|
||||
</programlisting>
|
||||
<function>maman_ibaz_get_type</function> registers a type named <emphasis>MamanIBaz</emphasis>
|
||||
<function>maman_ibaz_get_type</function> registers a type named <emphasis>MamanIbaz</emphasis>
|
||||
which inherits from G_TYPE_INTERFACE. All interfaces must be children of G_TYPE_INTERFACE in the
|
||||
inheritance tree.
|
||||
</para>
|
||||
@ -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 <function>maman_baz_get_type</function> registers
|
||||
a new GType named MamanBaz which inherits from <link linkend="GObject"><type>GObject</type></link> and which
|
||||
implements the interface <type>MamanIBaz</type>.
|
||||
implements the interface <type>MamanIbaz</type>.
|
||||
<programlisting>
|
||||
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
|
||||
};
|
||||
</programlisting>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
When having no special requirements you also can use the <function>G_DEFINE_INTERFACE</function> macro:
|
||||
If you have no special requirements you can use the
|
||||
<link linkend="G-IMPLEMENT-INTERFACE:CAPS">G_IMPLEMENT_INTERFACE</link> macro
|
||||
to implement an interface:
|
||||
<programlisting>
|
||||
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));
|
||||
</programlisting>
|
||||
</para>
|
||||
|
||||
|
||||
<sect2 id="gtype-non-instantiable-classed-init">
|
||||
<title>Interface Initialization</title>
|
||||
|
||||
<para>
|
||||
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 <xref linkend="gtype-instantiable-classed"/>.
|
||||
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 <xref linkend="gtype-instantiable-classed"/>.
|
||||
After that, the interface implementations associated with
|
||||
the type are initialized.
|
||||
</para>
|
||||
@ -802,28 +818,65 @@ G_DEFINE_INTERFACE (MamanBaz, maman_baz, G_TYPE_OBJECT)
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Finally, the interface' most-derived <function>base_init</function> function and then
|
||||
The interface's <function>base_init</function> function is called,
|
||||
and then the interface's <function>default_init</function> is invoked.
|
||||
Finally if the type has registered an implementation of the interface,
|
||||
the implementation's <function>interface_init</function>
|
||||
function are invoked. It is important to understand that if there are multiple
|
||||
implementations of an interface the <function>base_init</function> and
|
||||
<function>interface_init</function> functions will be
|
||||
invoked once for each implementation initialized.
|
||||
function is invoked. If there are multiple implementations of an
|
||||
interface the <function>base_init</function> and
|
||||
<function>interface_init</function> functions will be invoked once
|
||||
for each implementation initialized.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
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 <function>default_init</function> function to
|
||||
initialize an interface. This function is called only once for the interface no
|
||||
matter how many implementations there are. The
|
||||
<function>default_init</function> function is declared by
|
||||
<link linkend="G-DEFINE-INTERFACE:CAPS">G_DEFINE_INTERFACE</link>
|
||||
which can be used to define the interface:
|
||||
<programlisting>
|
||||
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 */
|
||||
}
|
||||
</programlisting>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Or you can do that yourself in a GType function for your interface:
|
||||
<programlisting>
|
||||
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 */
|
||||
}
|
||||
</programlisting>
|
||||
</para>
|
||||
@ -835,7 +888,6 @@ maman_ibaz_base_init (gpointer g_iface)
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The above process can be summarized as follows:
|
||||
<table id="ginterface-init-table">
|
||||
<title>Interface Initialization</title>
|
||||
<tgroup cols="3">
|
||||
@ -853,24 +905,31 @@ maman_ibaz_base_init (gpointer g_iface)
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry morerows="1">First call to <function><link linkend="g-type-create-instance">g_type_create_instance</link></function> for type
|
||||
implementing interface
|
||||
<entry>First call to <function><link linkend="g-type-create-instance">g_type_create_instance</link></function>
|
||||
for <emphasis>any</emphasis> type implementing interface
|
||||
</entry>
|
||||
<entry>interface' base_init function</entry>
|
||||
<entry>On interface' vtable</entry>
|
||||
<entry>Register interface' signals here (use a local static
|
||||
boolean variable as described above to make sure not to register them
|
||||
twice.).</entry>
|
||||
<entry>interface's <function>base_init</function> function</entry>
|
||||
<entry>On interface's vtable</entry>
|
||||
<entry>Rarely necessary to use this. Called once per instantiated classed type implementing the interface.</entry>
|
||||
</row>
|
||||
<row>
|
||||
<!--entry>First call to <function><link linkend="g-type-create-instance">g_type_create_instance</link></function> for type
|
||||
implementing interface
|
||||
</entry-->
|
||||
<entry>interface' interface_init function</entry>
|
||||
<entry>On interface' vtable</entry>
|
||||
<entry>First call to <function><link linkend="g-type-create-instance">g_type_create_instance</link></function>
|
||||
for <emphasis>each</emphasis> type implementing interface
|
||||
</entry>
|
||||
<entry>interface's <function>default_init</function> function</entry>
|
||||
<entry>On interface's vtable</entry>
|
||||
<entry>Register interface's signals, properties, etc. here. Will be called once.</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>First call to <function><link linkend="g-type-create-instance">g_type_create_instance</link></function>
|
||||
for <emphasis>any</emphasis> type implementing interface
|
||||
</entry>
|
||||
<entry>implementation's <function>interface_init</function> function</entry>
|
||||
<entry>On interface's vtable</entry>
|
||||
<entry>
|
||||
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.
|
||||
</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
|
@ -794,7 +794,7 @@ b_method_to_call (B *obj, int a)
|
||||
<title>How to define and implement interfaces</title>
|
||||
|
||||
<sect1 id="howto-interface-define">
|
||||
<title>How to define interfaces</title>
|
||||
<title>How to define an interface</title>
|
||||
|
||||
<para>
|
||||
The bulk of interface definition has already been shown in <xref linkend="gtype-non-instantiable-classed"/>
|
||||
@ -802,7 +802,8 @@ b_method_to_call (B *obj, int a)
|
||||
</para>
|
||||
|
||||
<para>
|
||||
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:
|
||||
<programlisting>
|
||||
#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_something (MamanIbaz *self);
|
||||
|
||||
#endif /* __MAMAN_IBAZ_H__ */
|
||||
</programlisting>
|
||||
@ -854,51 +857,28 @@ void maman_ibaz_do_action (MamanIbaz *self);
|
||||
<para>
|
||||
The implementation of the <type>MamanIbaz</type> type itself is trivial:
|
||||
<itemizedlist>
|
||||
<listitem><para><function>maman_ibaz_get_type</function> registers the
|
||||
type in the type system.
|
||||
<listitem><para><function><link linkend="G-DEFINE-INTERFACE:CAPS">G_DEFINE_INTERFACE</link></function>
|
||||
creates a <function>maman_ibaz_get_type</function> function which registers the
|
||||
type in the type system. The third argument is used to define a
|
||||
<link linkend="howto-interface-prerequisite">prerequisite interface</link>
|
||||
(which we'll talk about more later). Just pass <code>0</code> for this
|
||||
argument when an interface has no prerequisite.
|
||||
</para></listitem>
|
||||
<listitem><para><function>maman_ibaz_base_init</function> is expected
|
||||
<listitem><para><function>maman_ibaz_default_init</function> is expected
|
||||
to register the interface's signals if there are any (we will see a bit
|
||||
(later how to use them). Make sure to use a static local boolean variable
|
||||
to make sure not to run the initialization code twice (as described in
|
||||
<xref linkend="gtype-non-instantiable-classed-init"/>,
|
||||
<function>base_init</function> is run once for each interface implementation
|
||||
instantiation)</para></listitem>
|
||||
<listitem><para><function>maman_ibaz_do_action</function> dereferences
|
||||
the class structure to access its associated class function and calls it.
|
||||
later how to use them).</para></listitem>
|
||||
<listitem><para>The interface methods <function>maman_ibaz_do_action</function>
|
||||
and <function>maman_ibaz_do_something</function> dereference the interface
|
||||
structure to access its associated interface function and call it.
|
||||
</para></listitem>
|
||||
</itemizedlist>
|
||||
<programlisting>
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
</programlisting>
|
||||
</para>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="howto-interface-implement">
|
||||
<title>How To define implement an Interface?</title>
|
||||
<title>How to implement an interface</title>
|
||||
|
||||
<para>
|
||||
Once the interface is defined, implementing it is rather trivial.
|
||||
@ -954,15 +942,22 @@ GType maman_baz_get_type (void);
|
||||
|
||||
#endif /* __MAMAN_BAZ_H__ */
|
||||
</programlisting>
|
||||
<!-- Ha ha! "nothing weird or scary". I actually laughed out loud. Oh boy.
|
||||
The fact that we're so intimate with GObject that all this doesn't look
|
||||
wierd, that's the scary thing. :) -->
|
||||
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.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The second step is to implement <type>MamanBaz</type> by defining
|
||||
its GType. Instead of using <function>G_DEFINE_TYPE</function> we
|
||||
use <function>G_DEFINE_TYPE_WITH_CODE</function> and the
|
||||
<function>G_IMPLEMENT_INTERFACE</function> macros.
|
||||
its GType. Instead of using
|
||||
<function><link linkend="G-DEFINE-TYPE:CAPS">G_DEFINE_TYPE</link></function>
|
||||
we use
|
||||
<function><link linkend="G-DEFINE-TYPE-WITH-CODE:CAPS">G_DEFINE_TYPE_WITH_CODE</link></function>
|
||||
and the
|
||||
<function><link linkend="G-IMPLEMENT-INTERFACE:CAPS">G_IMPLEMENT_INTERFACE</link></function>
|
||||
macros.
|
||||
<programlisting>
|
||||
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));
|
||||
</programlisting>
|
||||
This definition is very much like all the similar functions we looked
|
||||
at previously. The only interface-specific code present here is the call
|
||||
to <function>G_IMPLEMENT_INTERFACE</function>.
|
||||
at previously. The only interface-specific code present here is the call to
|
||||
<function><link linkend="G-IMPLEMENT-INTERFACE:CAPS">G_IMPLEMENT_INTERFACE</link></function>.
|
||||
</para>
|
||||
|
||||
<note><para>Classes can implement multiple interfaces by using multiple
|
||||
calls to <function>G_IMPLEMENT_INTERFACE</function> inside the call
|
||||
to <function>G_DEFINE_TYPE_WITH_CODE</function>.</para></note>
|
||||
<note><para>Classes can implement multiple interfaces by using multiple calls to
|
||||
<function><link linkend="G-IMPLEMENT-INTERFACE:CAPS">G_IMPLEMENT_INTERFACE</link></function>
|
||||
inside the call to
|
||||
<function><link linkend="G-DEFINE-TYPE-WITH-CODE:CAPS">G_DEFINE_TYPE_WITH_CODE</link></function>
|
||||
</para></note>
|
||||
|
||||
<para>
|
||||
<function>maman_baz_interface_init</function>, 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)
|
||||
}
|
||||
</programlisting>
|
||||
</para>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1>
|
||||
<sect1 id="howto-interface-prerequisite">
|
||||
<title>Interface definition prerequisites</title>
|
||||
|
||||
<para>
|
||||
To specify that an interface requires the presence of other interfaces
|
||||
when implemented, GObject introduces the concept of
|
||||
<emphasis>prerequisites</emphasis>: it is possible to associate
|
||||
a list of prerequisite interfaces to an interface. For example, if
|
||||
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.
|
||||
</para>
|
||||
@ -1025,16 +1029,15 @@ maman_baz_init (MamanBaz *self)
|
||||
Java's interface I1 extends interface I2. The example below shows
|
||||
the GObject equivalent:
|
||||
<programlisting>
|
||||
/* inside the GType function of the MamanIbar interface */
|
||||
type = g_type_register_static (G_TYPE_INTERFACE, "MamanIbar", &info, 0);
|
||||
|
||||
/* Make the MamanIbar interface require MamanIbaz interface. */
|
||||
g_type_interface_add_prerequisite (type, MAMAN_TYPE_IBAZ);
|
||||
/* Make the MamanIbar interface require MamanIbaz interface. */
|
||||
G_DEFINE_INTERFACE (MamanIbar, maman_ibar, MAMAN_TYPE_IBAZ);
|
||||
</programlisting>
|
||||
The code shown above adds the MamanIbaz interface to the list of
|
||||
prerequisites of MamanIbar while the code below shows how an
|
||||
implementation can implement both interfaces and register their
|
||||
implementations:
|
||||
In the <function><link linkend="G-DEFINE-INTERFACE:CAPS">G_DEFINE_INTERFACE</link></function>
|
||||
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:
|
||||
<programlisting>
|
||||
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:
|
||||
<function><link linkend="g-type-add-interface-static">g_type_add_interface_static</link></function>,
|
||||
which is called by <function>G_IMPLEMENT_INTERFACE</function>, must be
|
||||
invoked first on the interfaces which have no prerequisites and then on
|
||||
which is called by
|
||||
<function><link linkend="G-DEFINE-INTERFACE:CAPS">G_IMPLEMENT_INTERFACE</link></function>,
|
||||
must be invoked first on the interfaces which have no prerequisites and then on
|
||||
the others.
|
||||
</para>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="howto-interface-properties">
|
||||
<title>Interface Properties</title>
|
||||
<title>Interface properties</title>
|
||||
|
||||
<para>
|
||||
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
|
||||
<xref linkend="gobject-properties"/>,
|
||||
except that <function><link linkend="g-object-interface-install-property">g_object_interface_install_property</link></function> is used to
|
||||
declare the properties instead of <function><link linkend="g-object-class-install-property">g_object_class_install_property</link></function>.
|
||||
<xref linkend="gobject-properties"/>, except that
|
||||
<function><link linkend="g-object-interface-install-property">g_object_interface_install_property</link></function>
|
||||
is used to declare the properties instead of
|
||||
<function><link linkend="g-object-class-install-property">g_object_class_install_property</link></function>.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
@ -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
|
||||
</para>
|
||||
</footnote>
|
||||
line in the <function>maman_ibaz_base_init</function>
|
||||
<footnote>
|
||||
<para>
|
||||
The <function><link linkend="g-object-interface-install-property">g_object_interface_install_property</link></function>
|
||||
can also be called from <function>class_init</function> but it must
|
||||
not be called after that point.
|
||||
</para>
|
||||
</footnote>
|
||||
as shown below:
|
||||
line in the <function>maman_ibaz_default_init</function> as shown below:
|
||||
<programlisting>
|
||||
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;
|
||||
}
|
||||
}
|
||||
</programlisting>
|
||||
</para>
|
||||
@ -1152,9 +1153,9 @@ maman_ibaz_base_init (gpointer g_iface)
|
||||
</para>
|
||||
|
||||
<para>
|
||||
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 <xref linkend="gobject-properties"/>, 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 <function><link linkend="g-object-class-override-property">g_object_class_override_property</link></function>
|
||||
instead of <function><link linkend="g-object-class-install-property">g_object_class_install_property</link></function>.
|
||||
The following code snippet shows the modifications needed in the
|
||||
@ -1233,6 +1234,118 @@ maman_baz_class_init (MamanBazClass *klass)
|
||||
</para>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="howto-interface-override">
|
||||
<title>Overriding interface methods</title>
|
||||
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
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.
|
||||
<programlisting>
|
||||
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)
|
||||
{
|
||||
|
||||
}
|
||||
</programlisting>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
To access the base class interface implementation use
|
||||
<function><link linkend="g-type-interface-peek-parent">g_type_interface_peek_parent</link></function>
|
||||
from within an interface's <function>default_init</function> function.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
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
|
||||
<function><link linkend="g-type-interface-peek-parent">g_type_interface_peek_parent</link></function>
|
||||
in a global variable.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
In this example MamanDerivedBaz overides the
|
||||
<function>do_action</function> interface method. In it's overridden method
|
||||
it calls the base class implementation of the same interface method.
|
||||
<programlisting>
|
||||
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)
|
||||
{
|
||||
|
||||
}
|
||||
</programlisting>
|
||||
</para>
|
||||
|
||||
</sect1>
|
||||
|
||||
</chapter>
|
||||
<!-- End Howto Interfaces -->
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user