mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-08-20 15:48:54 +02:00
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:
@@ -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)->constructed (obj);
|
G_OBJECT_CLASS (viewer_file_parent_class)->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->constructed = maman_bar_constructed;
|
object_class->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 parent’s constructor. In
|
Overridden constructors must chain up to their parent’s 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->priv->name);
|
g_free (self->priv->filename);
|
||||||
self->priv->name = g_value_dup_string (value);
|
self->priv->filename = g_value_dup_string (value);
|
||||||
g_print ("maman: %s\n", self->priv->name);
|
g_print ("filename: %s\n", self->priv->filename);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PROP_PAPA_NUMBER:
|
case PROP_ZOOM_LEVEL:
|
||||||
self->priv->papa_number = g_value_get_uchar (value);
|
self->priv->zoom_level = g_value_get_uint (value);
|
||||||
g_print ("papa: %u\n", self->priv->papa_number);
|
g_print ("zoom level: %u\n", self->priv->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->priv->name);
|
g_value_set_string (value, self->priv->filename);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PROP_PAPA_NUMBER:
|
case PROP_ZOOM_LEVEL:
|
||||||
g_value_set_uchar (value, self->priv->papa_number);
|
g_value_set_uint (value, self->priv->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->set_property = maman_bar_set_property;
|
object_class->set_property = viewer_file_set_property;
|
||||||
object_class->get_property = maman_bar_get_property;
|
object_class->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 (&val, G_TYPE_CHAR);
|
g_value_init (&val, G_TYPE_UINT);
|
||||||
g_value_set_char (&val, 11);
|
g_value_set_char (&val, 11);
|
||||||
|
|
||||||
g_object_set_property (G_OBJECT (bar), "papa-number", &val);
|
g_object_set_property (G_OBJECT (file), "zoom-level", &val);
|
||||||
|
|
||||||
g_value_unset (&val);
|
g_value_unset (&val);
|
||||||
</programlisting></informalexample>
|
</programlisting></informalexample>
|
||||||
@@ -577,7 +577,7 @@ g_value_unset (&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 (&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 (&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
|
||||||
|
@@ -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 (&obj_vala, MAMAN_TYPE_BAR);
|
g_value_init (&obj_vala, VIEWER_TYPE_FILE);
|
||||||
g_value_set_object (&obj_vala, obj);
|
g_value_set_object (&obj_vala, obj);
|
||||||
|
|
||||||
g_value_init (&obj_valb, G_TYPE_OBJECT);
|
g_value_init (&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 (&obj_vala, &obj_valb);
|
g_value_copy (&obj_vala, &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",
|
||||||
&info, 0);
|
&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",
|
||||||
&info, 0);
|
&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",
|
||||||
&info, 0);
|
&info, 0);
|
||||||
g_type_add_interface_static (type,
|
g_type_add_interface_static (type,
|
||||||
MAMAN_TYPE_IBAZ,
|
VIEWER_TYPE_EDITABLE,
|
||||||
&ibaz_info);
|
&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 (&type_id)) {
|
if (g_once_init_enter (&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",
|
||||||
&info, 0);
|
&info, 0);
|
||||||
g_once_init_leave (&type_id, type);
|
g_once_init_leave (&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
Reference in New Issue
Block a user