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>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
When having no special requirements you also can use the <function>G_DEFINE_TYPE</function>
|
If you have no special requirements you can use the
|
||||||
macro:
|
<function><link linkend="G-DEFINE-TYPE:CAPS">G_DEFINE_TYPE</link></function>
|
||||||
|
macro to define a class:
|
||||||
<programlisting>
|
<programlisting>
|
||||||
G_DEFINE_TYPE (MamanBar, maman_bar, G_TYPE_OBJECT)
|
G_DEFINE_TYPE (MamanBar, maman_bar, G_TYPE_OBJECT)
|
||||||
</programlisting>
|
</programlisting>
|
||||||
@ -688,7 +689,7 @@ void maman_ibaz_do_action (MamanIbaz *self)
|
|||||||
MAMAN_IBAZ_GET_INTERFACE (self)->do_action (self);
|
MAMAN_IBAZ_GET_INTERFACE (self)->do_action (self);
|
||||||
}
|
}
|
||||||
</programlisting>
|
</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
|
which inherits from G_TYPE_INTERFACE. All interfaces must be children of G_TYPE_INTERFACE in the
|
||||||
inheritance tree.
|
inheritance tree.
|
||||||
</para>
|
</para>
|
||||||
@ -706,14 +707,13 @@ void maman_ibaz_do_action (MamanIbaz *self)
|
|||||||
Once an interface type is registered, you must register implementations for these
|
Once an interface type is registered, you must register implementations for these
|
||||||
interfaces. The function named <function>maman_baz_get_type</function> registers
|
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
|
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>
|
<programlisting>
|
||||||
static void maman_baz_do_action (MamanIbaz *self)
|
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
|
static void
|
||||||
baz_interface_init (gpointer g_iface,
|
baz_interface_init (gpointer g_iface,
|
||||||
gpointer iface_data)
|
gpointer iface_data)
|
||||||
@ -728,7 +728,7 @@ maman_baz_get_type (void)
|
|||||||
static GType type = 0;
|
static GType type = 0;
|
||||||
if (type == 0) {
|
if (type == 0) {
|
||||||
const GTypeInfo info = {
|
const GTypeInfo info = {
|
||||||
sizeof (MamanBazInterface),
|
sizeof (MamanBazClass),
|
||||||
NULL, /* base_init */
|
NULL, /* base_init */
|
||||||
NULL, /* base_finalize */
|
NULL, /* base_finalize */
|
||||||
NULL, /* class_init */
|
NULL, /* class_init */
|
||||||
@ -771,22 +771,38 @@ struct _GInterfaceInfo
|
|||||||
};
|
};
|
||||||
</programlisting>
|
</programlisting>
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<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>
|
<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>
|
</programlisting>
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
|
||||||
<sect2 id="gtype-non-instantiable-classed-init">
|
<sect2 id="gtype-non-instantiable-classed-init">
|
||||||
<title>Interface Initialization</title>
|
<title>Interface Initialization</title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
When an instantiable classed type which registered an interface
|
When an instantiable classed type which implements an interface
|
||||||
implementation is created for the first time, its class structure
|
(either directly or by inheriting an implementation from a superclass)
|
||||||
is initialized following the process
|
is created for the first time, its class structure is initialized
|
||||||
described in <xref linkend="gtype-instantiable-classed"/>.
|
following the process described in <xref linkend="gtype-instantiable-classed"/>.
|
||||||
After that, the interface implementations associated with
|
After that, the interface implementations associated with
|
||||||
the type are initialized.
|
the type are initialized.
|
||||||
</para>
|
</para>
|
||||||
@ -802,28 +818,65 @@ G_DEFINE_INTERFACE (MamanBaz, maman_baz, G_TYPE_OBJECT)
|
|||||||
</para>
|
</para>
|
||||||
|
|
||||||
<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>
|
the implementation's <function>interface_init</function>
|
||||||
function are invoked. It is important to understand that if there are multiple
|
function is invoked. If there are multiple implementations of an
|
||||||
implementations of an interface the <function>base_init</function> and
|
interface the <function>base_init</function> and
|
||||||
<function>interface_init</function> functions will be
|
<function>interface_init</function> functions will be invoked once
|
||||||
invoked once for each implementation initialized.
|
for each implementation initialized.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
It is thus common for base_init functions to hold a local static boolean variable
|
It is thus recommended to use a <function>default_init</function> function to
|
||||||
which makes sure that the interface type is initialized only once even if there are
|
initialize an interface. This function is called only once for the interface no
|
||||||
multiple implementations of the interface:
|
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>
|
<programlisting>
|
||||||
static void
|
G_DEFINE_INTERFACE (MamanIbaz, maman_ibaz, G_TYPE_OBJECT);
|
||||||
maman_ibaz_base_init (gpointer g_iface)
|
|
||||||
{
|
|
||||||
static gboolean initialized = FALSE;
|
|
||||||
|
|
||||||
if (!initialized) {
|
static void
|
||||||
/* create interface signals here. */
|
maman_ibaz_default_init (MamanIbazInterface *iface)
|
||||||
initialized = TRUE;
|
{
|
||||||
|
/* 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>
|
</programlisting>
|
||||||
</para>
|
</para>
|
||||||
@ -835,7 +888,6 @@ maman_ibaz_base_init (gpointer g_iface)
|
|||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
The above process can be summarized as follows:
|
|
||||||
<table id="ginterface-init-table">
|
<table id="ginterface-init-table">
|
||||||
<title>Interface Initialization</title>
|
<title>Interface Initialization</title>
|
||||||
<tgroup cols="3">
|
<tgroup cols="3">
|
||||||
@ -853,24 +905,31 @@ maman_ibaz_base_init (gpointer g_iface)
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<row>
|
<row>
|
||||||
<entry morerows="1">First call to <function><link linkend="g-type-create-instance">g_type_create_instance</link></function> for type
|
<entry>First call to <function><link linkend="g-type-create-instance">g_type_create_instance</link></function>
|
||||||
implementing interface
|
for <emphasis>any</emphasis> type implementing interface
|
||||||
</entry>
|
</entry>
|
||||||
<entry>interface' base_init function</entry>
|
<entry>interface's <function>base_init</function> function</entry>
|
||||||
<entry>On interface' vtable</entry>
|
<entry>On interface's vtable</entry>
|
||||||
<entry>Register interface' signals here (use a local static
|
<entry>Rarely necessary to use this. Called once per instantiated classed type implementing the interface.</entry>
|
||||||
boolean variable as described above to make sure not to register them
|
|
||||||
twice.).</entry>
|
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<!--entry>First call to <function><link linkend="g-type-create-instance">g_type_create_instance</link></function> for type
|
<entry>First call to <function><link linkend="g-type-create-instance">g_type_create_instance</link></function>
|
||||||
implementing interface
|
for <emphasis>each</emphasis> type implementing interface
|
||||||
</entry-->
|
</entry>
|
||||||
<entry>interface' interface_init function</entry>
|
<entry>interface's <function>default_init</function> function</entry>
|
||||||
<entry>On interface' vtable</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>
|
<entry>
|
||||||
Initialize interface' implementation. That is, initialize the interface
|
Initialize interface implementation. Called for each class that that
|
||||||
method pointers in the interface structure to the function's implementation.
|
implements the interface. Initialize the interface method pointers
|
||||||
|
in the interface structure to the implementing class's implementation.
|
||||||
</entry>
|
</entry>
|
||||||
</row>
|
</row>
|
||||||
</tbody>
|
</tbody>
|
||||||
|
@ -794,7 +794,7 @@ b_method_to_call (B *obj, int a)
|
|||||||
<title>How to define and implement interfaces</title>
|
<title>How to define and implement interfaces</title>
|
||||||
|
|
||||||
<sect1 id="howto-interface-define">
|
<sect1 id="howto-interface-define">
|
||||||
<title>How to define interfaces</title>
|
<title>How to define an interface</title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
The bulk of interface definition has already been shown in <xref linkend="gtype-non-instantiable-classed"/>
|
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>
|
||||||
|
|
||||||
<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>
|
<programlisting>
|
||||||
#ifndef __MAMAN_IBAZ_H__
|
#ifndef __MAMAN_IBAZ_H__
|
||||||
#define __MAMAN_IBAZ_H__
|
#define __MAMAN_IBAZ_H__
|
||||||
@ -823,11 +824,13 @@ struct _MamanIbazInterface
|
|||||||
GTypeInterface parent_iface;
|
GTypeInterface parent_iface;
|
||||||
|
|
||||||
void (*do_action) (MamanIbaz *self);
|
void (*do_action) (MamanIbaz *self);
|
||||||
|
void (*do_something) (MamanIbaz *self);
|
||||||
};
|
};
|
||||||
|
|
||||||
GType maman_ibaz_get_type (void);
|
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__ */
|
#endif /* __MAMAN_IBAZ_H__ */
|
||||||
</programlisting>
|
</programlisting>
|
||||||
@ -854,51 +857,28 @@ void maman_ibaz_do_action (MamanIbaz *self);
|
|||||||
<para>
|
<para>
|
||||||
The implementation of the <type>MamanIbaz</type> type itself is trivial:
|
The implementation of the <type>MamanIbaz</type> type itself is trivial:
|
||||||
<itemizedlist>
|
<itemizedlist>
|
||||||
<listitem><para><function>maman_ibaz_get_type</function> registers the
|
<listitem><para><function><link linkend="G-DEFINE-INTERFACE:CAPS">G_DEFINE_INTERFACE</link></function>
|
||||||
type in the type system.
|
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>
|
</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
|
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
|
later how to use them).</para></listitem>
|
||||||
to make sure not to run the initialization code twice (as described in
|
<listitem><para>The interface methods <function>maman_ibaz_do_action</function>
|
||||||
<xref linkend="gtype-non-instantiable-classed-init"/>,
|
and <function>maman_ibaz_do_something</function> dereference the interface
|
||||||
<function>base_init</function> is run once for each interface implementation
|
structure to access its associated interface function and call it.
|
||||||
instantiation)</para></listitem>
|
|
||||||
<listitem><para><function>maman_ibaz_do_action</function> dereferences
|
|
||||||
the class structure to access its associated class function and calls it.
|
|
||||||
</para></listitem>
|
</para></listitem>
|
||||||
</itemizedlist>
|
</itemizedlist>
|
||||||
<programlisting>
|
<programlisting>
|
||||||
|
G_DEFINE_INTERFACE (MamanIbaz, maman_ibaz, 0);
|
||||||
|
|
||||||
static void
|
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 */
|
/* 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
|
void
|
||||||
@ -908,12 +888,20 @@ maman_ibaz_do_action (MamanIbaz *self)
|
|||||||
|
|
||||||
MAMAN_IBAZ_GET_INTERFACE (self)->do_action (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>
|
</programlisting>
|
||||||
</para>
|
</para>
|
||||||
</sect1>
|
</sect1>
|
||||||
|
|
||||||
<sect1 id="howto-interface-implement">
|
<sect1 id="howto-interface-implement">
|
||||||
<title>How To define implement an Interface?</title>
|
<title>How to implement an interface</title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Once the interface is defined, implementing it is rather trivial.
|
Once the interface is defined, implementing it is rather trivial.
|
||||||
@ -954,15 +942,22 @@ GType maman_baz_get_type (void);
|
|||||||
|
|
||||||
#endif /* __MAMAN_BAZ_H__ */
|
#endif /* __MAMAN_BAZ_H__ */
|
||||||
</programlisting>
|
</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:
|
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>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
The second step is to implement <type>MamanBaz</type> by defining
|
The second step is to implement <type>MamanBaz</type> by defining
|
||||||
its GType. Instead of using <function>G_DEFINE_TYPE</function> we
|
its GType. Instead of using
|
||||||
use <function>G_DEFINE_TYPE_WITH_CODE</function> and the
|
<function><link linkend="G-DEFINE-TYPE:CAPS">G_DEFINE_TYPE</link></function>
|
||||||
<function>G_IMPLEMENT_INTERFACE</function> macros.
|
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>
|
<programlisting>
|
||||||
static void maman_ibaz_interface_init (MamanIbazInterface *iface);
|
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));
|
maman_ibaz_interface_init));
|
||||||
</programlisting>
|
</programlisting>
|
||||||
This definition is very much like all the similar functions we looked
|
This definition is very much like all the similar functions we looked
|
||||||
at previously. The only interface-specific code present here is the call
|
at previously. The only interface-specific code present here is the call to
|
||||||
to <function>G_IMPLEMENT_INTERFACE</function>.
|
<function><link linkend="G-IMPLEMENT-INTERFACE:CAPS">G_IMPLEMENT_INTERFACE</link></function>.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<note><para>Classes can implement multiple interfaces by using multiple
|
<note><para>Classes can implement multiple interfaces by using multiple calls to
|
||||||
calls to <function>G_IMPLEMENT_INTERFACE</function> inside the call
|
<function><link linkend="G-IMPLEMENT-INTERFACE:CAPS">G_IMPLEMENT_INTERFACE</link></function>
|
||||||
to <function>G_DEFINE_TYPE_WITH_CODE</function>.</para></note>
|
inside the call to
|
||||||
|
<function><link linkend="G-DEFINE-TYPE-WITH-CODE:CAPS">G_DEFINE_TYPE_WITH_CODE</link></function>
|
||||||
|
</para></note>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
<function>maman_baz_interface_init</function>, the interface
|
<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
|
static void
|
||||||
maman_baz_do_action (MamanBaz *self)
|
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);
|
self->instance_member);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
maman_ibaz_interface_init (MamanIbazInterface *iface)
|
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
|
static void
|
||||||
@ -1005,17 +1010,16 @@ maman_baz_init (MamanBaz *self)
|
|||||||
}
|
}
|
||||||
</programlisting>
|
</programlisting>
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
</sect1>
|
</sect1>
|
||||||
|
|
||||||
<sect1>
|
<sect1 id="howto-interface-prerequisite">
|
||||||
<title>Interface definition prerequisites</title>
|
<title>Interface definition prerequisites</title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
To specify that an interface requires the presence of other interfaces
|
To specify that an interface requires the presence of other interfaces
|
||||||
when implemented, GObject introduces the concept of
|
when implemented, GObject introduces the concept of
|
||||||
<emphasis>prerequisites</emphasis>: it is possible to associate
|
<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
|
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.
|
prerequisite on interface I2, A has to implement both I1 and I2.
|
||||||
</para>
|
</para>
|
||||||
@ -1025,16 +1029,15 @@ maman_baz_init (MamanBaz *self)
|
|||||||
Java's interface I1 extends interface I2. The example below shows
|
Java's interface I1 extends interface I2. The example below shows
|
||||||
the GObject equivalent:
|
the GObject equivalent:
|
||||||
<programlisting>
|
<programlisting>
|
||||||
/* inside the GType function of the MamanIbar interface */
|
/* Make the MamanIbar interface require MamanIbaz interface. */
|
||||||
type = g_type_register_static (G_TYPE_INTERFACE, "MamanIbar", &info, 0);
|
G_DEFINE_INTERFACE (MamanIbar, maman_ibar, MAMAN_TYPE_IBAZ);
|
||||||
|
|
||||||
/* Make the MamanIbar interface require MamanIbaz interface. */
|
|
||||||
g_type_interface_add_prerequisite (type, MAMAN_TYPE_IBAZ);
|
|
||||||
</programlisting>
|
</programlisting>
|
||||||
The code shown above adds the MamanIbaz interface to the list of
|
In the <function><link linkend="G-DEFINE-INTERFACE:CAPS">G_DEFINE_INTERFACE</link></function>
|
||||||
prerequisites of MamanIbar while the code below shows how an
|
call above, the third parameter defines the prerequisite type. This
|
||||||
implementation can implement both interfaces and register their
|
is the GType of either an interface or a class. In this case
|
||||||
implementations:
|
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>
|
<programlisting>
|
||||||
static void
|
static void
|
||||||
maman_ibar_do_another_action (MamanIbar *ibar)
|
maman_ibar_do_another_action (MamanIbar *ibar)
|
||||||
@ -1056,7 +1059,16 @@ maman_ibaz_do_action (MamanIbaz *ibaz)
|
|||||||
{
|
{
|
||||||
MamanBar *self = MAMAN_BAR (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);
|
self->instance_member);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1064,6 +1076,7 @@ static void
|
|||||||
maman_ibaz_interface_init (MamanIbazInterface *iface)
|
maman_ibaz_interface_init (MamanIbazInterface *iface)
|
||||||
{
|
{
|
||||||
iface->do_action = maman_ibaz_do_action;
|
iface->do_action = maman_ibaz_do_action;
|
||||||
|
iface->do_something = maman_ibaz_do_something;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
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
|
It is very important to notice that the order in which interface
|
||||||
implementations are added to the main object is not random:
|
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>,
|
<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
|
which is called by
|
||||||
invoked first on the interfaces which have no prerequisites and then on
|
<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.
|
the others.
|
||||||
</para>
|
</para>
|
||||||
</sect1>
|
</sect1>
|
||||||
|
|
||||||
<sect1 id="howto-interface-properties">
|
<sect1 id="howto-interface-properties">
|
||||||
<title>Interface Properties</title>
|
<title>Interface properties</title>
|
||||||
|
|
||||||
<para>
|
<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
|
properties. Declaration of the interface properties is similar to
|
||||||
declaring the properties of ordinary GObject types as explained in
|
declaring the properties of ordinary GObject types as explained in
|
||||||
<xref linkend="gobject-properties"/>,
|
<xref linkend="gobject-properties"/>, except that
|
||||||
except that <function><link linkend="g-object-interface-install-property">g_object_interface_install_property</link></function> is used to
|
<function><link linkend="g-object-interface-install-property">g_object_interface_install_property</link></function>
|
||||||
declare the properties instead of <function><link linkend="g-object-class-install-property">g_object_class_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>
|
||||||
|
|
||||||
<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
|
That really is one line extended to six for the sake of clarity
|
||||||
</para>
|
</para>
|
||||||
</footnote>
|
</footnote>
|
||||||
line in the <function>maman_ibaz_base_init</function>
|
line in the <function>maman_ibaz_default_init</function> as shown below:
|
||||||
<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:
|
|
||||||
<programlisting>
|
<programlisting>
|
||||||
static void
|
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_object_interface_install_property (g_iface,
|
||||||
g_param_spec_string ("name",
|
g_param_spec_string ("name",
|
||||||
"Name",
|
"Name",
|
||||||
"Name of the MamanIbaz",
|
"Name of the MamanIbaz",
|
||||||
"maman",
|
"maman",
|
||||||
G_PARAM_READWRITE));
|
G_PARAM_READWRITE));
|
||||||
is_initialized = TRUE;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</programlisting>
|
</programlisting>
|
||||||
</para>
|
</para>
|
||||||
@ -1152,9 +1153,9 @@ maman_ibaz_base_init (gpointer g_iface)
|
|||||||
</para>
|
</para>
|
||||||
|
|
||||||
<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
|
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>
|
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>.
|
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
|
The following code snippet shows the modifications needed in the
|
||||||
@ -1233,6 +1234,118 @@ maman_baz_class_init (MamanBazClass *klass)
|
|||||||
</para>
|
</para>
|
||||||
|
|
||||||
</sect1>
|
</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>
|
</chapter>
|
||||||
<!-- End Howto Interfaces -->
|
<!-- End Howto Interfaces -->
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user