svn path=/trunk/; revision=7201
This commit is contained in:
Matthias Clasen 2008-07-18 17:55:13 +00:00
parent 3cb92eb95e
commit adae2cf59b
5 changed files with 780 additions and 800 deletions

View File

@ -1,3 +1,10 @@
2008-07-18 Matthias Clasen <mclasen@redhat.com>
Bug 530759 update the gobject tutorial to the XXI century
* gobject/*: Some updates to the tutorial. Patch by Emmanuele
Bassi.
2008-07-18 Matthias Clasen <mclasen@redhat.com> 2008-07-18 Matthias Clasen <mclasen@redhat.com>
* gio/gio-sections.txt: Add g_content_type_guess_for_tree * gio/gio-sections.txt: Add g_content_type_guess_for_tree

View File

@ -25,29 +25,33 @@
<title>Object instantiation</title> <title>Object instantiation</title>
<para> <para>
The <function><link linkend="g-object-new">g_object_new</link></function> family of functions can be used to instantiate any The <function><link linkend="g-object-new">g_object_new</link></function>
GType which inherits from the GObject base type. All these functions make sure the class family of functions can be used to instantiate any GType which inherits
and instance structures have been correctly initialized by glib's type system and from the GObject base type. All these functions make sure the class and
then invoke at one point or another the constructor class method which is used to: instance structures have been correctly initialized by GLib's type system
and then invoke at one point or another the constructor class method
which is used to:
<itemizedlist> <itemizedlist>
<listitem><para> <listitem><para>
Allocate and clear memory through <function><link linkend="g-type-create-instance">g_type_create_instance</link></function>, Allocate and clear memory through <function><link linkend="g-type-create-instance">g_type_create_instance</link></function>,
</para></listitem> </para></listitem>
<listitem><para> <listitem><para>
Initialize the object' instance with the construction properties. Initialize the object's instance with the construction properties.
</para></listitem> </para></listitem>
</itemizedlist> </itemizedlist>
Although one can expect all class and instance members (except the fields Although one can expect all class and instance members (except the fields
pointing to the parents) to be set to zero, some consider it good practice to explicitly set them. pointing to the parents) to be set to zero, some consider it good practice
to explicitly set them.
</para> </para>
<para> <para>
Objects which inherit from GObject are allowed to override this constructor class method: Objects which inherit from GObject are allowed to override this
they should however chain to their parent constructor method before doing so: constructor class method: they should however chain to their parent
constructor method before doing so:
<programlisting> <programlisting>
GObject* (*constructor) (GType type, GObject *(* constructor) (GType gtype,
guint n_construct_properties, guint n_properties,
GObjectConstructParam *construct_properties); GObjectConstructParam *properties);
</programlisting> </programlisting>
</para> </para>
@ -56,101 +60,79 @@
<programlisting> <programlisting>
#define MAMAN_TYPE_BAR (maman_bar_get_type ()) #define MAMAN_TYPE_BAR (maman_bar_get_type ())
#define MAMAN_BAR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MAMAN_TYPE_BAR, MamanBar)) #define MAMAN_BAR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MAMAN_TYPE_BAR, MamanBar))
#define MAMAN_BAR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MAMAN_TYPE_BAR, MamanBarClass))
#define MAMAN_IS_BAR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MAMAN_TYPE_BAR)) #define MAMAN_IS_BAR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MAMAN_TYPE_BAR))
#define MAMAN_BAR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MAMAN_TYPE_BAR, MamanBarClass))
#define MAMAN_IS_BAR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MAMAN_TYPE_BAR)) #define MAMAN_IS_BAR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MAMAN_TYPE_BAR))
#define MAMAN_BAR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MAMAN_TYPE_BAR, MamanBarClass)) #define MAMAN_BAR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MAMAN_TYPE_BAR, MamanBarClass))
typedef struct _MamanBar MamanBar; typedef struct _MamanBar MamanBar;
typedef struct _MamanBarClass MamanBarClass; typedef struct _MamanBarClass MamanBarClass;
struct _MamanBar { struct _MamanBar
GObject parent; {
GObject parent_instance;
/* instance members */ /* instance members */
}; };
struct _MamanBarClass { struct _MamanBarClass
GObjectClass parent; {
GObjectClass parent_class;
/* class members */ /* class members */
}; };
/* used by MAMAN_TYPE_BAR */ /* will create maman_bar_get_type and set maman_bar_parent_class */
GType maman_bar_get_type (void); G_DEFINE_TYPE (MamanBar, maman_bar, G_TYPE_OBJECT);
static GObject * static GObject *
maman_bar_constructor (GType type, maman_bar_constructor (GType gtype,
guint n_construct_properties, guint n_properties,
GObjectConstructParam *construct_properties) GObjectConstructParam *properties)
{ {
GObject *obj; GObject *obj;
{ {
/* Invoke parent constructor. */ /* Always chain up to the parent constructor */
MamanBarClass *klass; MamanBarClass *klass;
GObjectClass *parent_class; GObjectClass *parent_class;
klass = MAMAN_BAR_CLASS (g_type_class_peek (MAMAN_TYPE_BAR)); parent_class = G_OBJECT_CLASS (maman_bar_parent_class);
parent_class = G_OBJECT_CLASS (g_type_class_peek_parent (klass)); obj = parent_class-&gt;constructor (gtype, n_properties, properties);
obj = parent_class->constructor (type,
n_construct_properties,
construct_properties);
} }
/* do stuff. */ /* update the object state depending on constructor properties */
return obj; return obj;
} }
static void static void
maman_bar_instance_init (GTypeInstance *instance, maman_bar_class_init (MamanBarClass *klass)
gpointer g_class)
{ {
MamanBar *self = (MamanBar *)instance; GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
/* do stuff */
gobject_class-&gt;constructor = maman_bar_constructor;
} }
static void static void
maman_bar_class_init (gpointer g_class, maman_bar_init (MamanBar *self)
gpointer g_class_data)
{ {
GObjectClass *gobject_class = G_OBJECT_CLASS (g_class); /* initialize the object */
MamanBarClass *klass = MAMAN_BAR_CLASS (g_class);
gobject_class->constructor = maman_bar_constructor;
} }
GType maman_bar_get_type (void)
{
static GType type = 0;
if (type == 0) {
static const GTypeInfo info = {
sizeof (MamanBarClass),
NULL, /* base_init */
NULL, /* base_finalize */
maman_bar_class_init, /* class_init */
NULL, /* class_finalize */
NULL, /* class_data */
sizeof (MamanBar),
0, /* n_preallocs */
maman_bar_instance_init /* instance_init */
};
type = g_type_register_static (G_TYPE_OBJECT,
"MamanBarType",
&amp;info, 0);
}
return type;
}
</programlisting> </programlisting>
If the user instantiates an object <type>MamanBar</type> with: If the user instantiates an object <type>MamanBar</type> with:
<programlisting> <programlisting>
MamanBar *bar = g_object_new (MAMAN_TYPE_BAR, NULL); MamanBar *bar = g_object_new (MAMAN_TYPE_BAR, NULL);
</programlisting> </programlisting>
If this is the first instantiation of such an object, the <function>maman_b_class_init</function> If this is the first instantiation of such an object, the
function will be invoked after any <function>maman_b_base_class_init</function> function. <function>maman_bar_class_init</function> function will be invoked
This will make sure the class structure of this new object is correctly initialized. Here, after any <function>maman_bar_base_class_init</function> function.
<function>maman_bar_class_init</function> is expected to override the object's class methods This will make sure the class structure of this new object is
and setup the class' own methods. In the example above, the constructor method is the only correctly initialized. Here, <function>maman_bar_class_init</function>
overridden method: it is set to <function>maman_bar_constructor</function>. is expected to override the object's class methods and setup the
class' own methods. In the example above, the constructor method is
the only overridden method: it is set to
<function>maman_bar_constructor</function>.
</para> </para>
<para> <para>
@ -158,12 +140,11 @@ MamanBar *bar = g_object_new (MAMAN_TYPE_BAR, NULL);
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. Since it has just been overridden by <function>maman_bar_class_init</function> object. Since it has just been overridden by <function>maman_bar_class_init</function>
to <function>maman_bar_constructor</function>, the latter is called and, because it to <function>maman_bar_constructor</function>, the latter is called and, because it
was implemented correctly, it chains up to its parent's constructor. The problem here was implemented correctly, it chains up to its parent's constructor. In
is how we can find the parent constructor. An approach (used in GTK+ source code) would be order to find the parent class and chain up to the parent class
to save the original constructor in a static variable from <function>maman_bar_class_init</function> constructor, we can use the <literal>maman_bar_parent_class</literal>
and then to re-use it from <function>maman_bar_constructor</function>. This is clearly possible pointer that has been set up for us by the
and very simple but I was told it was not nice and the preferred way is to use the <literal>G_DEFINE_TYPE</literal> macro.
<function><link linkend="g-type-class-peek">g_type_class_peek</link></function> and <function><link linkend="g-type-class-peek-parent">g_type_class_peek_parent</link></function> functions.
</para> </para>
<para> <para>
@ -179,16 +160,13 @@ MamanBar *bar = g_object_new (MAMAN_TYPE_BAR, NULL);
</para> </para>
<para> <para>
The process described above might seem a bit complicated (it <emphasis>is</emphasis> actually The process described above might seem a bit complicated, but it can be
overly complicated in my opinion..) but it can be summarized easily by the table below which summarized easily by the table below which lists the functions invoked
lists the functions invoked by <function><link linkend="g-object-new">g_object_new</link></function> and their order of by <function><link linkend="g-object-new">g_object_new</link></function>
invocation. and their order of invocation:
</para> </para>
<para> <para>
The array below lists the functions invoked by <function><link linkend="g-object-new">g_object_new</link></function> and
their order of invocation:
<table id="gobject-construction-table"> <table id="gobject-construction-table">
<title><function><link linkend="g-object-new">g_object_new</link></function></title> <title><function><link linkend="g-object-new">g_object_new</link></function></title>
<tgroup cols="3"> <tgroup cols="3">
@ -266,16 +244,16 @@ MamanBar *bar = g_object_new (MAMAN_TYPE_BAR, NULL);
</para> </para>
<para> <para>
Readers should feel concerned about one little twist in the order in which functions Readers should feel concerned about one little twist in the order in
are invoked: while, technically, the class' constructor method is called which functions are invoked: while, technically, the class' constructor
<emphasis>before</emphasis> the GType's instance_init function (since method is called <emphasis>before</emphasis> the GType's instance_init
<function><link linkend="g-type-create-instance">g_type_create_instance</link></function> which calls instance_init is called by function (since <function><link linkend="g-type-create-instance">g_type_create_instance</link></function> which calls instance_init is called by
<function>g_object_constructor</function> which is the top-level class <function>g_object_constructor</function> which is the top-level class
constructor method and to which users are expected to chain to), the user's code constructor method and to which users are expected to chain to), the
which runs in a user-provided constructor will always run <emphasis>after</emphasis> user's code which runs in a user-provided constructor will always
GType's instance_init function since the user-provided constructor run <emphasis>after</emphasis> GType's instance_init function since the
<emphasis>must</emphasis> (you've been warned) chain up <emphasis>before</emphasis> user-provided constructor <emphasis>must</emphasis> (you've been warned)
doing anything useful. chain up <emphasis>before</emphasis> doing anything useful.
</para> </para>
</sect1> </sect1>
@ -296,10 +274,11 @@ gpointer g_object_ref (gpointer object);
void g_object_unref (gpointer object); void g_object_unref (gpointer object);
/* /*
Weak References * Weak References
*/ */
typedef void (*GWeakNotify) (gpointer data, typedef void (*GWeakNotify) (gpointer data,
GObject *where_the_object_was); GObject *where_the_object_was);
void g_object_weak_ref (GObject *object, void g_object_weak_ref (GObject *object,
GWeakNotify notify, GWeakNotify notify,
gpointer data); gpointer data);
@ -311,7 +290,7 @@ void g_object_add_weak_pointer (GObject *object,
void g_object_remove_weak_pointer (GObject *object, void g_object_remove_weak_pointer (GObject *object,
gpointer *weak_pointer_location); gpointer *weak_pointer_location);
/* /*
Cycle handling * Cycle handling
*/ */
void g_object_run_dispose (GObject *object); void g_object_run_dispose (GObject *object);
</programlisting> </programlisting>
@ -528,17 +507,13 @@ void g_object_run_dispose (GObject *object);
/* Implementation */ /* Implementation */
/************************************************/ /************************************************/
enum { enum
MAMAN_BAR_CONSTRUCT_NAME = 1,
MAMAN_BAR_PAPA_NUMBER,
};
static void
maman_bar_instance_init (GTypeInstance *instance,
gpointer g_class)
{ {
MamanBar *self = (MamanBar *)instance; PROP_0,
}
PROP_MAMAN_NAME,
PROP_PAPA_NUMBER
};
static void static void
maman_bar_set_property (GObject *object, maman_bar_set_property (GObject *object,
@ -546,20 +521,21 @@ maman_bar_set_property (GObject *object,
const GValue *value, const GValue *value,
GParamSpec *pspec) GParamSpec *pspec)
{ {
MamanBar *self = (MamanBar *) object; MamanBar *self = MAMAN_BAR (object);
switch (property_id) { switch (property_id)
case MAMAN_BAR_CONSTRUCT_NAME: { {
g_free (self->priv->name); case PROP_MAMAN_NAME:
self->priv->name = g_value_dup_string (value); g_free (self-&gt;priv-&gt;name);
g_print ("maman: %s\n",self->priv->name); self-&gt;priv-&gt;name = g_value_dup_string (value);
} g_print ("maman: %s\n", self-&gt;priv-&gt;name);
break; break;
case MAMAN_BAR_PAPA_NUMBER: {
self->priv->papa_number = g_value_get_uchar (value); case PROP_PAPA_NUMBER:
g_print ("papa: %u\n",self->priv->papa_number); self-&gt;priv-&gt;papa_number = g_value_get_uchar (value);
} g_print ("papa: &percnt;u\n", self-&gt;priv-&gt;papa_number);
break; break;
default: default:
/* We don't have any other property... */ /* We don't have any other property... */
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@ -573,17 +549,18 @@ maman_bar_get_property (GObject *object,
GValue *value, GValue *value,
GParamSpec *pspec) GParamSpec *pspec)
{ {
MamanBar *self = (MamanBar *) object; MamanBar *self = MAMAN_BAR (object);
switch (property_id) { switch (property_id)
case MAMAN_BAR_CONSTRUCT_NAME: { {
g_value_set_string (value, self->priv->name); case PROP_MAMAN_NAME:
} g_value_set_string (value, self-&gt;priv-&gt;name);
break; break;
case MAMAN_BAR_PAPA_NUMBER: {
g_value_set_uchar (value, self->priv->papa_number); case PROP_PAPA_NUMBER:
} g_value_set_uchar (value, self-&gt;priv-&gt;papa_number);
break; break;
default: default:
/* We don't have any other property... */ /* We don't have any other property... */
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@ -592,15 +569,13 @@ maman_bar_get_property (GObject *object,
} }
static void static void
maman_bar_class_init (gpointer g_class, maman_bar_class_init (MamanBarClass *klass)
gpointer g_class_data)
{ {
GObjectClass *gobject_class = G_OBJECT_CLASS (g_class); GObjectClass *gobject_class = G_OBJECT_CLASS (g_class);
MamanBarClass *klass = MAMAN_BAR_CLASS (g_class);
GParamSpec *pspec; GParamSpec *pspec;
gobject_class->set_property = maman_bar_set_property; gobject_class-&gt;set_property = maman_bar_set_property;
gobject_class->get_property = maman_bar_get_property; gobject_class-&gt;get_property = maman_bar_get_property;
pspec = g_param_spec_string ("maman-name", pspec = g_param_spec_string ("maman-name",
"Maman construct prop", "Maman construct prop",
@ -608,7 +583,7 @@ maman_bar_class_init (gpointer g_class,
"no-name-set" /* default value */, "no-name-set" /* default value */,
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE); G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
g_object_class_install_property (gobject_class, g_object_class_install_property (gobject_class,
MAMAN_BAR_CONSTRUCT_NAME, PROP_MAMAN_NAME_NAME,
pspec); pspec);
pspec = g_param_spec_uchar ("papa-number", pspec = g_param_spec_uchar ("papa-number",
@ -619,7 +594,7 @@ maman_bar_class_init (gpointer g_class,
2 /* default value */, 2 /* default value */,
G_PARAM_READWRITE); G_PARAM_READWRITE);
g_object_class_install_property (gobject_class, g_object_class_install_property (gobject_class,
MAMAN_BAR_PAPA_NUMBER, PROP_PAPA_NUMBER,
pspec); pspec);
} }
@ -629,10 +604,15 @@ maman_bar_class_init (gpointer g_class,
GObject *bar; GObject *bar;
GValue val = { 0, }; GValue val = { 0, };
bar = g_object_new (MAMAN_TYPE_SUBBAR, NULL); bar = g_object_new (MAMAN_TYPE_SUBBAR, NULL);
g_value_init (&amp;val, G_TYPE_CHAR); g_value_init (&amp;val, G_TYPE_CHAR);
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 (bar), "papa-number", &amp;val);
g_value_unset (&amp;val);
</programlisting> </programlisting>
The client code just above looks simple but a lot of things happen under the hood: The client code just above looks simple but a lot of things happen under the hood:
</para> </para>
@ -765,7 +745,3 @@ g_object_set (G_OBJECT (foo),
</sect1> </sect1>
</chapter> </chapter>

File diff suppressed because it is too large Load Diff