docs: Replace Maman in the tutorial with a more meaningful example

Change it to a running example of a file viewer application with a file
class and various derived classes and related interfaces. Hopefully the
reader can relate to this a little better than to their maman.

https://bugzilla.gnome.org/show_bug.cgi?id=753935
This commit is contained in:
Philip Withnall
2015-10-18 19:34:44 +01:00
parent 419f57137a
commit bf33f1d98d
3 changed files with 547 additions and 432 deletions

View File

@@ -55,68 +55,68 @@
<para> <para>
Objects which inherit from GObject are allowed to override this Objects which inherit from GObject are allowed to override this
constructed class method. constructed class method.
The example below shows how <type>MamanBar</type> overrides the parent's construction process: The example below shows how <type>ViewerFile</type> overrides the parent's construction process:
<informalexample><programlisting> <informalexample><programlisting>
#define MAMAN_TYPE_BAR maman_bar_get_type () #define VIEWER_TYPE_FILE viewer_file_get_type ()
G_DECLARE_FINAL_TYPE (MamanBar, maman_bar, MAMAN, BAR, GObject) G_DECLARE_FINAL_TYPE (ViewerFile, viewer_file, VIEWER, FILE, GObject)
struct _MamanBar struct _ViewerFile
{ {
GObject parent_instance; GObject parent_instance;
/* instance members */ /* instance members */
}; };
/* will create maman_bar_get_type and set maman_bar_parent_class */ /* will create viewer_file_get_type and set viewer_file_parent_class */
G_DEFINE_TYPE (MamanBar, maman_bar, G_TYPE_OBJECT); G_DEFINE_TYPE (ViewerFile, viewer_file, G_TYPE_OBJECT)
static void static void
maman_bar_constructed (GObject *obj) viewer_file_constructed (GObject *obj)
{ {
/* update the object state depending on constructor properties */ /* update the object state depending on constructor properties */
/* Always chain up to the parent constructed function to complete object /* Always chain up to the parent constructed function to complete object
* initialisation. */ * initialisation. */
G_OBJECT_CLASS (maman_bar_parent_class)-&gt;constructed (obj); G_OBJECT_CLASS (viewer_file_parent_class)-&gt;constructed (obj);
} }
static void static void
maman_bar_class_init (MamanBarClass *klass) viewer_file_class_init (ViewerFileClass *klass)
{ {
GObjectClass *object_class = G_OBJECT_CLASS (klass); GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class-&gt;constructed = maman_bar_constructed; object_class-&gt;constructed = viewer_file_constructed;
} }
static void static void
maman_bar_init (MamanBar *self) viewer_file_init (ViewerFile *self)
{ {
/* initialize the object */ /* initialize the object */
} }
</programlisting></informalexample> </programlisting></informalexample>
If the user instantiates an object <type>MamanBar</type> with: If the user instantiates an object <type>ViewerFile</type> with:
<informalexample><programlisting> <informalexample><programlisting>
MamanBar *bar = g_object_new (MAMAN_TYPE_BAR, NULL); ViewerFile *file = g_object_new (VIEWER_TYPE_FILE, NULL);
</programlisting></informalexample> </programlisting></informalexample>
If this is the first instantiation of such an object, the If this is the first instantiation of such an object, the
<function>maman_bar_class_init</function> function will be invoked <function>viewer_file_class_init</function> function will be invoked
after any <function>maman_bar_base_class_init</function> function. after any <function>viewer_file_base_class_init</function> function.
This will make sure the class structure of this new object is This will make sure the class structure of this new object is
correctly initialized. Here, <function>maman_bar_class_init</function> correctly initialized. Here, <function>viewer_file_class_init</function>
is expected to override the object's class methods and setup the is expected to override the object's class methods and setup the
class' own methods. In the example above, the constructor method is class' own methods. In the example above, the constructor method is
the only overridden method: it is set to the only overridden method: it is set to
<function>maman_bar_constructor</function>. <function>viewer_file_constructor</function>.
</para> </para>
<para> <para>
Once <function><link linkend="g-object-new">g_object_new</link></function> has obtained a reference to an initialized Once <function><link linkend="g-object-new">g_object_new</link></function> has obtained a reference to an initialized
class structure, it invokes its constructor method to create an instance of the new class structure, it invokes its constructor method to create an instance of the new
object, if the constructor has been overridden in <function>maman_bar_class_init</function>. object, if the constructor has been overridden in <function>viewer_file_class_init</function>.
Overridden constructors must chain up to their parents constructor. In Overridden constructors must chain up to their parents constructor. In
order to find the parent class and chain up to the parent class order to find the parent class and chain up to the parent class
constructor, we can use the <literal>maman_bar_parent_class</literal> constructor, we can use the <literal>viewer_file_parent_class</literal>
pointer that has been set up for us by the pointer that has been set up for us by the
<link linkend="G-DEFINE-TYPE:CAPS"><literal>G_DEFINE_TYPE</literal></link> <link linkend="G-DEFINE-TYPE:CAPS"><literal>G_DEFINE_TYPE</literal></link>
macro. macro.
@@ -467,32 +467,32 @@ MamanBar *bar = g_object_new (MAMAN_TYPE_BAR, NULL);
enum enum
{ {
PROP_MAMAN_NAME = 1, PROP_FILENAME = 1,
PROP_PAPA_NUMBER, PROP_ZOOM_LEVEL,
N_PROPERTIES N_PROPERTIES
}; };
static GParamSpec *obj_properties[N_PROPERTIES] = { NULL, }; static GParamSpec *obj_properties[N_PROPERTIES] = { NULL, };
static void static void
maman_bar_set_property (GObject *object, viewer_file_set_property (GObject *object,
guint property_id, guint property_id,
const GValue *value, const GValue *value,
GParamSpec *pspec) GParamSpec *pspec)
{ {
MamanBar *self = MAMAN_BAR (object); ViewerFile *self = VIEWER_FILE (object);
switch (property_id) switch (property_id)
{ {
case PROP_MAMAN_NAME: case PROP_FILENAME:
g_free (self-&gt;priv-&gt;name); g_free (self-&gt;priv-&gt;filename);
self-&gt;priv-&gt;name = g_value_dup_string (value); self-&gt;priv-&gt;filename = g_value_dup_string (value);
g_print ("maman: %s\n", self-&gt;priv-&gt;name); g_print ("filename: %s\n", self-&gt;priv-&gt;filename);
break; break;
case PROP_PAPA_NUMBER: case PROP_ZOOM_LEVEL:
self-&gt;priv-&gt;papa_number = g_value_get_uchar (value); self-&gt;priv-&gt;zoom_level = g_value_get_uint (value);
g_print ("papa: &percnt;u\n", self-&gt;priv-&gt;papa_number); g_print ("zoom level: &percnt;u\n", self-&gt;priv-&gt;zoom_level);
break; break;
default: default:
@@ -503,21 +503,21 @@ maman_bar_set_property (GObject *object,
} }
static void static void
maman_bar_get_property (GObject *object, viewer_file_get_property (GObject *object,
guint property_id, guint property_id,
GValue *value, GValue *value,
GParamSpec *pspec) GParamSpec *pspec)
{ {
MamanBar *self = MAMAN_BAR (object); ViewerFile *self = VIEWER_FILE (object);
switch (property_id) switch (property_id)
{ {
case PROP_MAMAN_NAME: case PROP_FILENAME:
g_value_set_string (value, self-&gt;priv-&gt;name); g_value_set_string (value, self-&gt;priv-&gt;filename);
break; break;
case PROP_PAPA_NUMBER: case PROP_ZOOM_LEVEL:
g_value_set_uchar (value, self-&gt;priv-&gt;papa_number); g_value_set_uint (value, self-&gt;priv-&gt;zoom_level);
break; break;
default: default:
@@ -528,28 +528,28 @@ maman_bar_get_property (GObject *object,
} }
static void static void
maman_bar_class_init (MamanBarClass *klass) viewer_file_class_init (ViewerFileClass *klass)
{ {
GObjectClass *object_class = G_OBJECT_CLASS (klass); GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class-&gt;set_property = maman_bar_set_property; object_class-&gt;set_property = viewer_file_set_property;
object_class-&gt;get_property = maman_bar_get_property; object_class-&gt;get_property = viewer_file_get_property;
obj_properties[PROP_MAMAN_NAME] = obj_properties[PROP_FILENAME] =
g_param_spec_string ("maman-name", g_param_spec_string ("filename",
"Maman construct prop", "Filename",
"Set maman's name", "Name of the file to load and display from.",
"no-name-set" /* default value */, NULL /* default value */,
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE)); G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
obj_properties[PROP_PAPA_NUMBER] = obj_properties[PROP_ZOOM_LEVEL] =
g_param_spec_uchar ("papa-number", g_param_spec_uint ("zoom-level",
"Number of current Papa", "Zoom level",
"Set/Get papa's number", "Zoom level to view the file at.",
0 /* minimum value */, 0 /* minimum value */,
10 /* maximum value */, 10 /* maximum value */,
2 /* default value */, 2 /* default value */,
G_PARAM_READWRITE)); G_PARAM_READWRITE));
g_object_class_install_properties (object_class, g_object_class_install_properties (object_class,
N_PROPERTIES, N_PROPERTIES,
@@ -560,15 +560,15 @@ maman_bar_class_init (MamanBarClass *klass)
/* Use */ /* Use */
/************************************************/ /************************************************/
GObject *bar; ViewerFile *file;
GValue val = G_VALUE_INIT; GValue val = G_VALUE_INIT;
bar = g_object_new (MAMAN_TYPE_BAR, NULL); file = g_object_new (VIEWER_TYPE_FILE, NULL);
g_value_init (&amp;val, G_TYPE_CHAR); g_value_init (&amp;val, G_TYPE_UINT);
g_value_set_char (&amp;val, 11); g_value_set_char (&amp;val, 11);
g_object_set_property (G_OBJECT (bar), "papa-number", &amp;val); g_object_set_property (G_OBJECT (file), "zoom-level", &amp;val);
g_value_unset (&amp;val); g_value_unset (&amp;val);
</programlisting></informalexample> </programlisting></informalexample>
@@ -577,7 +577,7 @@ g_value_unset (&amp;val);
<para> <para>
<function><link linkend="g-object-set-property">g_object_set_property</link></function> first ensures a property <function><link linkend="g-object-set-property">g_object_set_property</link></function> first ensures a property
with this name was registered in bar's <function>class_init</function> handler. If so it walks the class hierarchy, with this name was registered in <emphasis>file</emphasis>'s <function>class_init</function> handler. If so it walks the class hierarchy,
from bottom-most most-derived type, to top-most fundamental type to find the class from bottom-most most-derived type, to top-most fundamental type to find the class
which registered that property. It then tries to convert the user-provided which registered that property. It then tries to convert the user-provided
<link linkend="GValue"><type>GValue</type></link> <link linkend="GValue"><type>GValue</type></link>
@@ -615,13 +615,13 @@ g_value_unset (&amp;val);
If the user's GValue had been set to a valid value, <function><link linkend="g-object-set-property">g_object_set_property</link></function> If the user's GValue had been set to a valid value, <function><link linkend="g-object-set-property">g_object_set_property</link></function>
would have proceeded with calling the object's would have proceeded with calling the object's
<function>set_property</function> class method. Here, since our <function>set_property</function> class method. Here, since our
implementation of <type>Foo</type> did override this method, execution would jump to implementation of <type>ViewerFile</type> did override this method, execution would jump to
<function>foo_set_property</function> after having retrieved from the <function>viewer_file_set_property</function> after having retrieved from the
<link linkend="GParamSpec"><type>GParamSpec</type></link> the <emphasis>param_id</emphasis> <link linkend="GParamSpec"><type>GParamSpec</type></link> the <emphasis>param_id</emphasis>
<footnote> <footnote>
<para> <para>
It should be noted that the param_id used here need only to uniquely identify each It should be noted that the param_id used here need only to uniquely identify each
<link linkend="GParamSpec"><type>GParamSpec</type></link> within the <type>FooClass</type> such that the switch <link linkend="GParamSpec"><type>GParamSpec</type></link> within the <type>ViewerFileClass</type> such that the switch
used in the set and get methods actually works. Of course, this locally-unique used in the set and get methods actually works. Of course, this locally-unique
integer is purely an optimization: it would have been possible to use a set of integer is purely an optimization: it would have been possible to use a set of
<emphasis>if (strcmp (a, b) == 0) {} else if (strcmp (a, b) == 0) {}</emphasis> statements. <emphasis>if (strcmp (a, b) == 0) {} else if (strcmp (a, b) == 0) {}</emphasis> statements.
@@ -667,11 +667,11 @@ g_value_unset (&amp;val);
<function><link linkend="g-object-set-valist">g_object_set_valist</link></function> (variadic version) functions can be used to set <function><link linkend="g-object-set-valist">g_object_set_valist</link></function> (variadic version) functions can be used to set
multiple properties at once. The client code shown above can then be re-written as: multiple properties at once. The client code shown above can then be re-written as:
<informalexample><programlisting> <informalexample><programlisting>
MamanBar *foo; ViewerFile *file;
foo = /* */; file = /* */;
g_object_set (G_OBJECT (foo), g_object_set (G_OBJECT (file),
"papa-number", 2, "zoom-level", 6,
"maman-name", "test", "filename", "~/some-file.txt",
NULL); NULL);
</programlisting></informalexample> </programlisting></informalexample>
This saves us from managing the GValues that we were needing to handle when using This saves us from managing the GValues that we were needing to handle when using

View File

@@ -154,9 +154,9 @@ static void test_object (void)
GObject *obj; GObject *obj;
GValue obj_vala = G_VALUE_INIT; GValue obj_vala = G_VALUE_INIT;
GValue obj_valb = G_VALUE_INIT; GValue obj_valb = G_VALUE_INIT;
obj = g_object_new (MAMAN_TYPE_BAR, NULL); obj = g_object_new (VIEWER_TYPE_FILE, NULL);
g_value_init (&amp;obj_vala, MAMAN_TYPE_BAR); g_value_init (&amp;obj_vala, VIEWER_TYPE_FILE);
g_value_set_object (&amp;obj_vala, obj); g_value_set_object (&amp;obj_vala, obj);
g_value_init (&amp;obj_valb, G_TYPE_OBJECT); g_value_init (&amp;obj_valb, G_TYPE_OBJECT);
@@ -164,7 +164,7 @@ static void test_object (void)
/* g_value_copy's semantics for G_TYPE_OBJECT types is to copy the reference. /* g_value_copy's semantics for G_TYPE_OBJECT types is to copy the reference.
* This function thus calls g_object_ref. * This function thus calls g_object_ref.
* It is interesting to note that the assignment works here because * It is interesting to note that the assignment works here because
* MAMAN_TYPE_BAR is a G_TYPE_OBJECT. * VIEWER_TYPE_FILE is a G_TYPE_OBJECT.
*/ */
g_value_copy (&amp;obj_vala, &amp;obj_valb); g_value_copy (&amp;obj_vala, &amp;obj_valb);
@@ -206,27 +206,20 @@ static void test_object (void)
</para></listitem> </para></listitem>
<listitem><para> <listitem><para>
Use the <function>object_method</function> pattern for function names: to invoke Use the <function>object_method</function> pattern for function names: to invoke
the method named foo on an instance of object type bar, call the method named <function>save</function> on an instance of object type <type>file</type>, call
<function>bar_foo</function>. <function>file_save</function>.
</para></listitem> </para></listitem>
<listitem><para>Use prefixing to avoid namespace conflicts with other projects. <listitem><para>Use prefixing to avoid namespace conflicts with other projects.
If your library (or application) is named <emphasis>Maman</emphasis>, If your library (or application) is named <emphasis>Viewer</emphasis>,
<footnote> prefix all your function names with <emphasis>viewer_</emphasis>.
<para> For example: <function>viewer_object_method</function>.
<emphasis>Maman</emphasis> is the French word for <emphasis>mum</emphasis>
or <emphasis>mother</emphasis> — nothing more and nothing less.
</para>
</footnote>
prefix all your function names with <emphasis>maman_</emphasis>.
For example: <function>maman_object_method</function>.
</para></listitem> </para></listitem>
<listitem><para>Create a macro named <function>PREFIX_TYPE_OBJECT</function> which always <listitem><para>Create a macro named <function>PREFIX_TYPE_OBJECT</function> which always
returns the GType for the associated object type. For an object of type returns the GType for the associated object type. For an object of type
<emphasis>Bar</emphasis> in a library prefixed by <emphasis>maman</emphasis>, <emphasis>File</emphasis> in the <emphasis>Viewer</emphasis> namespace,
use: <function>MAMAN_TYPE_BAR</function>. use: <function>VIEWER_TYPE_FILE</function>.
This macro is implemented using a function named This macro is implemented using a function named
<function>prefix_object_get_type</function>. <function>prefix_object_get_type</function>; for example, <function>viewer_file_get_type</function>.
</para></listitem> </para></listitem>
<listitem> <listitem>
<para> <para>
@@ -241,25 +234,28 @@ static void test_object (void)
dynamic type safety by doing runtime checks. It is possible to disable the dynamic dynamic type safety by doing runtime checks. It is possible to disable the dynamic
type checks in production builds (see <link linkend="glib-building">building GLib</link>). type checks in production builds (see <link linkend="glib-building">building GLib</link>).
For example, we would create For example, we would create
<function>MAMAN_BAR (obj)</function> to keep the previous example. <function>VIEWER_FILE (obj)</function> to keep the previous example.
</para></listitem> </para></listitem>
<listitem><para><function>PREFIX_OBJECT_CLASS (klass)</function>, which <listitem><para><function>PREFIX_OBJECT_CLASS (klass)</function>, which
is strictly equivalent to the previous casting macro: it does static casting with is strictly equivalent to the previous casting macro: it does static casting with
dynamic type checking of class structures. It is expected to return a pointer dynamic type checking of class structures. It is expected to return a pointer
to a class structure of type <type>PrefixObjectClass</type>. An example is: to a class structure of type <type>PrefixObjectClass</type>. An example is:
<function>MAMAN_BAR_CLASS</function>. <function>VIEWER_FILE_CLASS</function>.
</para></listitem> </para></listitem>
<listitem><para><function>PREFIX_IS_BAR (obj)</function>, which <listitem><para><function>PREFIX_IS_OBJECT (obj)</function>, which
returns a <type>gboolean</type> which indicates whether the input returns a <type>gboolean</type> which indicates whether the input
object instance pointer is non-<type>NULL</type> and of type BAR. object instance pointer is non-<type>NULL</type> and of type <type>OBJECT</type>.
For example, <function>VIEWER_IS_FILE</function>.
</para></listitem> </para></listitem>
<listitem><para><function>PREFIX_IS_OBJECT_CLASS (klass)</function>, which returns a boolean <listitem><para><function>PREFIX_IS_OBJECT_CLASS (klass)</function>, which returns a boolean
if the input class pointer is a pointer to a class of type OBJECT. if the input class pointer is a pointer to a class of type OBJECT.
For example, <function>VIEWER_IS_FILE_CLASS</function>.
</para></listitem> </para></listitem>
<listitem><para><function>PREFIX_OBJECT_GET_CLASS (obj)</function>, <listitem><para><function>PREFIX_OBJECT_GET_CLASS (obj)</function>,
which returns the class pointer associated to an instance of a given type. This macro which returns the class pointer associated to an instance of a given type. This macro
is used for static and dynamic type safety purposes (just like the previous casting is used for static and dynamic type safety purposes (just like the previous casting
macros). macros).
For example, <function>VIEWER_FILE_GET_CLASS</function>.
</para></listitem> </para></listitem>
</itemizedlist> </itemizedlist>
</listitem> </listitem>
@@ -268,8 +264,8 @@ static void test_object (void)
macros are provided in <filename>gtype.h</filename>. For the example we used above, we would macros are provided in <filename>gtype.h</filename>. For the example we used above, we would
write the following trivial code to declare the macros: write the following trivial code to declare the macros:
<informalexample><programlisting> <informalexample><programlisting>
#define MAMAN_TYPE_BAR maman_bar_get_type () #define VIEWER_TYPE_FILE viewer_file_get_type ()
G_DECLARE_FINAL_TYPE (MamanBar, maman_bar, MAMAN, BAR, GObject) G_DECLARE_FINAL_TYPE (ViewerFile, viewer_file, VIEWER, FILE, GObject)
</programlisting></informalexample> </programlisting></informalexample>
</para> </para>
@@ -278,15 +274,15 @@ G_DECLARE_FINAL_TYPE (MamanBar, maman_bar, MAMAN, BAR, GObject)
<function><link linkend="G-DEFINE-TYPE:CAPS">G_DEFINE_TYPE</link></function> <function><link linkend="G-DEFINE-TYPE:CAPS">G_DEFINE_TYPE</link></function>
macro to define a class: macro to define a class:
<informalexample><programlisting> <informalexample><programlisting>
G_DEFINE_TYPE (MamanBar, maman_bar, G_TYPE_OBJECT) G_DEFINE_TYPE (ViewerFile, viewer_file, G_TYPE_OBJECT)
</programlisting></informalexample> </programlisting></informalexample>
</para> </para>
<para> <para>
Otherwise, the <function>maman_bar_get_type</function> function must be Otherwise, the <function>viewer_file_get_type</function> function must be
implemented manually: implemented manually:
<informalexample><programlisting> <informalexample><programlisting>
GType maman_bar_get_type (void) GType viewer_file_get_type (void)
{ {
static GType type = 0; static GType type = 0;
if (type == 0) { if (type == 0) {
@@ -294,7 +290,7 @@ GType maman_bar_get_type (void)
/* You fill this structure. */ /* You fill this structure. */
}; };
type = g_type_register_static (G_TYPE_OBJECT, type = g_type_register_static (G_TYPE_OBJECT,
"MamanBarType", "ViewerFile",
&amp;info, 0); &amp;info, 0);
} }
return type; return type;
@@ -384,45 +380,51 @@ GType maman_bar_get_type (void)
<informalexample><programlisting> <informalexample><programlisting>
typedef struct { typedef struct {
GObject parent; GObject parent;
/* instance members */ /* instance members */
int field_a; gchar *filename;
} MamanBar; } ViewerFile;
typedef struct { typedef struct {
GObjectClass parent; GObjectClass parent;
/* class members */ /* class members */
void (*do_action_public_virtual) (MamanBar *self, guint8 i); /* the first is public, pure and virtual */
void (*open) (ViewerFile *self,
GError **error);
void (*do_action_public_pure_virtual) (MamanBar *self, guint8 i); /* the second is public and virtual */
} MamanBarClass; void (*close) (ViewerFile *self,
GError **error);
} ViewerFileClass;
#define MAMAN_TYPE_BAR (maman_bar_get_type ()) #define VIEWER_TYPE_FILE (viewer_file_get_type ())
GType GType
maman_bar_get_type (void) viewer_file_get_type (void)
{ {
static GType type = 0; static GType type = 0;
if (type == 0) { if (type == 0) {
const GTypeInfo info = { const GTypeInfo info = {
sizeof (MamanBarClass), sizeof (ViewerFileClass),
NULL, /* base_init */ NULL, /* base_init */
NULL, /* base_finalize */ NULL, /* base_finalize */
(GClassInitFunc) foo_class_init, (GClassInitFunc) viewer_file_class_init,
NULL, /* class_finalize */ NULL, /* class_finalize */
NULL, /* class_data */ NULL, /* class_data */
sizeof (MamanBar), sizeof (ViewerFile),
0, /* n_preallocs */ 0, /* n_preallocs */
(GInstanceInitFunc) NULL /* instance_init */ (GInstanceInitFunc) NULL /* instance_init */
}; };
type = g_type_register_static (G_TYPE_OBJECT, type = g_type_register_static (G_TYPE_OBJECT,
"BarType", "ViewerFile",
&amp;info, 0); &amp;info, 0);
} }
return type; return type;
} }
</programlisting></informalexample> </programlisting></informalexample>
Upon the first call to <function>maman_bar_get_type</function>, the type named Upon the first call to <function>viewer_file_get_type</function>, the type named
<emphasis>BarType</emphasis> will be registered in the type system as inheriting <emphasis>ViewerFile</emphasis> will be registered in the type system as inheriting
from the type <emphasis>G_TYPE_OBJECT</emphasis>. from the type <emphasis>G_TYPE_OBJECT</emphasis>.
</para> </para>
@@ -650,28 +652,37 @@ B *b;
classed type which derives from classed type which derives from
<link linkend="GTypeInterface"><type>GTypeInterface</type></link>. The following piece of code declares such an interface. <link linkend="GTypeInterface"><type>GTypeInterface</type></link>. The following piece of code declares such an interface.
<informalexample><programlisting> <informalexample><programlisting>
#define MAMAN_TYPE_IBAZ maman_ibaz_get_type () #define VIEWER_TYPE_EDITABLE viewer_editable_get_type ()
G_DECLARE_INTERFACE(MamanIbaz, maman_ibaz, MAMAN, IBAZ, GObject) G_DECLARE_INTERFACE (ViewerEditable, viewer_editable, VIEWER, EDITABLE, GObject)
struct _MamanIbazInterface { struct _ViewerEditableInterface {
GTypeInterface parent; GTypeInterface parent;
void (*do_action) (MamanIbaz *self); void (*save) (ViewerEditable *self,
GError **error);
}; };
void maman_ibaz_do_action (MamanIbaz *self); void viewer_editable_save (ViewerEditable *self,
GError **error);
</programlisting></informalexample> </programlisting></informalexample>
The interface function, <function>maman_ibaz_do_action</function> is implemented The interface function, <function>viewer_editable_save</function> is implemented
in a pretty simple way: in a pretty simple way:
<informalexample><programlisting> <informalexample><programlisting>
void maman_ibaz_do_action (MamanIbaz *self) void
viewer_editable_save (ViewerEditable *self,
GError **error)
{ {
g_return_if_fail (MAMAN_IS_IBAZ (self)); ViewerEditableinterface *iface;
MAMAN_IBAZ_GET_INTERFACE (self)->do_action (self); g_return_if_fail (VIEWER_IS_EDITABLE (self));
g_return_if_fail (error == NULL || *error == NULL);
iface = VIEWER_EDITABLE_GET_INTERFACE (self);
g_return_if_fail (iface->save != NULL);
iface->save (self);
} }
</programlisting></informalexample> </programlisting></informalexample>
<function>maman_ibaz_get_type</function> registers a type named <emphasis>MamanIbaz</emphasis> <function>viewer_editable_get_type</function> registers a type named <emphasis>ViewerEditable</emphasis>
which inherits from <type>G_TYPE_INTERFACE</type>. All interfaces must which inherits from <type>G_TYPE_INTERFACE</type>. All interfaces must
be children of <type>G_TYPE_INTERFACE</type> in the inheritance tree. be children of <type>G_TYPE_INTERFACE</type> in the inheritance tree.
</para> </para>
@@ -681,7 +692,7 @@ void maman_ibaz_do_action (MamanIbaz *self)
a <link linkend="GTypeInterface"><type>GTypeInterface</type></link> structure. The interface structure is expected to a <link linkend="GTypeInterface"><type>GTypeInterface</type></link> structure. The interface structure is expected to
contain the function pointers of the interface methods. It is good style to contain the function pointers of the interface methods. It is good style to
define helper functions for each of the interface methods which simply call define helper functions for each of the interface methods which simply call
the interface's method directly: <function>maman_ibaz_do_action</function> the interface's method directly: <function>viewer_editable_save</function>
is one of these. is one of these.
</para> </para>
@@ -691,20 +702,20 @@ void maman_ibaz_do_action (MamanIbaz *self)
to implement an interface: to implement an interface:
<informalexample><programlisting> <informalexample><programlisting>
static void static void
maman_baz_do_action (MamanIbaz *self) viewer_file_save (ViewerEditable *self)
{ {
g_print ("Baz implementation of Ibaz interface Action.\n"); g_print ("File implementation of editable interface save method.\n");
} }
static void static void
maman_ibaz_interface_init (MamanIbazInterface *iface) viewer_file_editable_interface_init (ViewerEditableInterface *iface)
{ {
iface->do_action = maman_baz_do_action; iface->save = viewer_file_save;
} }
G_DEFINE_TYPE_WITH_CODE (MamanBaz, maman_baz, G_TYPE_OBJECT, G_DEFINE_TYPE_WITH_CODE (ViewerFile, viewer_file, VIEWER_TYPE_FILE,
G_IMPLEMENT_INTERFACE (MAMAN_TYPE_IBAZ, G_IMPLEMENT_INTERFACE (VIEWER_TYPE_EDITABLE,
maman_ibaz_interface_init)); viewer_file_editable_interface_init));
</programlisting></informalexample> </programlisting></informalexample>
</para> </para>
@@ -712,51 +723,52 @@ G_DEFINE_TYPE_WITH_CODE (MamanBaz, maman_baz, G_TYPE_OBJECT,
If your code does have special requirements, you must write a custom If your code does have special requirements, you must write a custom
<function>get_type</function> function to register your GType which <function>get_type</function> function to register your GType which
inherits from some <link linkend="GObject"><type>GObject</type></link> inherits from some <link linkend="GObject"><type>GObject</type></link>
and which implements the interface <type>MamanIbaz</type>. For and which implements the interface <type>ViewerEditable</type>. For
example, this code registers a new <type>MamanBaz</type> class which example, this code registers a new <type>ViewerFile</type> class which
implements <type>MamanIbaz</type>: implements <type>ViewerEditable</type>:
<informalexample><programlisting> <informalexample><programlisting>
static void static void
maman_baz_do_action (MamanIbaz *self) viewer_file_save (ViewerEditable *editable)
{ {
g_print ("Baz implementation of Ibaz interface Action.\n"); g_print ("File implementation of editable interface save method.\n");
} }
static void static void
baz_interface_init (gpointer g_iface, viewer_file_editable_interface_init (gpointer g_iface,
gpointer iface_data) gpointer iface_data)
{ {
MamanIbazInterface *iface = (MamanIbazInterface *)g_iface; ViewerEditableInterface *iface = g_iface;
iface->do_action = maman_baz_do_action;
iface->save = viewer_file_save;
} }
GType GType
maman_baz_get_type (void) viewer_file_get_type (void)
{ {
static GType type = 0; static GType type = 0;
if (type == 0) { if (type == 0) {
const GTypeInfo info = { const GTypeInfo info = {
sizeof (MamanBazClass), sizeof (ViewerFileClass),
NULL, /* base_init */ NULL, /* base_init */
NULL, /* base_finalize */ NULL, /* base_finalize */
NULL, /* class_init */ NULL, /* class_init */
NULL, /* class_finalize */ NULL, /* class_finalize */
NULL, /* class_data */ NULL, /* class_data */
sizeof (MamanBaz), sizeof (ViewerFile),
0, /* n_preallocs */ 0, /* n_preallocs */
NULL /* instance_init */ NULL /* instance_init */
}; };
const GInterfaceInfo ibaz_info = { const GInterfaceInfo editable_info = {
(GInterfaceInitFunc) baz_interface_init, /* interface_init */ (GInterfaceInitFunc) viewer_file_editable_interface_init, /* interface_init */
NULL, /* interface_finalize */ NULL, /* interface_finalize */
NULL /* interface_data */ NULL /* interface_data */
}; };
type = g_type_register_static (G_TYPE_OBJECT, type = g_type_register_static (VIEWER_TYPE_FILE,
"MamanBazType", "ViewerFile",
&amp;info, 0); &amp;info, 0);
g_type_add_interface_static (type, g_type_add_interface_static (type,
MAMAN_TYPE_IBAZ, VIEWER_TYPE_EDITABLE,
&amp;ibaz_info); &amp;editable_info);
} }
return type; return type;
} }
@@ -824,12 +836,12 @@ struct _GInterfaceInfo
<link linkend="G-DEFINE-INTERFACE:CAPS">G_DEFINE_INTERFACE</link> <link linkend="G-DEFINE-INTERFACE:CAPS">G_DEFINE_INTERFACE</link>
which can be used to define the interface: which can be used to define the interface:
<informalexample><programlisting> <informalexample><programlisting>
G_DEFINE_INTERFACE (MamanIbaz, maman_ibaz, G_TYPE_OBJECT); G_DEFINE_INTERFACE (ViewerEditable, viewer_editable, G_TYPE_OBJECT);
static void static void
maman_ibaz_default_init (MamanIbazInterface *iface) viewer_editable_default_init (ViewerEditableInterface *iface)
{ {
/* add properties and signals here, will only called once */ /* add properties and signals here, will only be called once */
} }
</programlisting></informalexample> </programlisting></informalexample>
</para> </para>
@@ -838,15 +850,15 @@ maman_ibaz_default_init (MamanIbazInterface *iface)
Or you can do that yourself in a GType function for your interface: Or you can do that yourself in a GType function for your interface:
<informalexample><programlisting> <informalexample><programlisting>
GType GType
maman_ibaz_get_type (void) viewer_editable_get_type (void)
{ {
static volatile gsize type_id = 0; static volatile gsize type_id = 0;
if (g_once_init_enter (&amp;type_id)) { if (g_once_init_enter (&amp;type_id)) {
const GTypeInfo info = { const GTypeInfo info = {
sizeof (MamanIbazInterface), sizeof (ViewerEditableInterface),
NULL, /* base_init */ NULL, /* base_init */
NULL, /* base_finalize */ NULL, /* base_finalize */
maman_ibaz_default_init, /* class_init */ viewer_editable_default_init, /* class_init */
NULL, /* class_finalize */ NULL, /* class_finalize */
NULL, /* class_data */ NULL, /* class_data */
0, /* instance_size */ 0, /* instance_size */
@@ -854,15 +866,15 @@ maman_ibaz_get_type (void)
NULL /* instance_init */ NULL /* instance_init */
}; };
GType type = g_type_register_static (G_TYPE_INTERFACE, GType type = g_type_register_static (G_TYPE_INTERFACE,
"MamanIbaz", "ViewerEditable",
&amp;info, 0); &amp;info, 0);
g_once_init_leave (&amp;type_id, type); g_once_init_leave (&amp;type_id, type);
} }
return type_id; return type_id;
} }
static void static void
maman_ibaz_default_init (MamanIbazInterface *iface) viewer_editable_default_init (ViewerEditableInterface *iface)
{ {
/* add properties and signals here, will only called once */ /* add properties and signals here, will only called once */
} }

File diff suppressed because it is too large Load Diff