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>
* gio/gio-sections.txt: Add g_content_type_guess_for_tree

View File

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

View File

@ -78,14 +78,14 @@ return_type function_callback (... , gpointer user_data);
which have a pretty minimal API or the even simpler <function><link linkend="g-signal-connect">g_signal_connect</link></function>
functions (which will be presented a bit later :).
<programlisting>
GClosure* g_cclosure_new (GCallback callback_func,
gpointer user_data,
GClosureNotify destroy_data);
GClosure* g_cclosure_new_swap (GCallback callback_func,
gpointer user_data,
GClosureNotify destroy_data);
GClosure* g_signal_type_cclosure_new (GType itype,
guint struct_offset);
GClosure *g_cclosure_new (GCallback callback_func,
gpointer user_data,
GClosureNotify destroy_data);
GClosure *g_cclosure_new_swap (GCallback callback_func,
gpointer user_data,
GClosureNotify destroy_data);
GClosure *g_signal_type_cclosure_new (GType itype,
guint struct_offset);
</programlisting>
</para>
@ -203,16 +203,16 @@ return_type function_callback (gpointer instance, ... , gpointer user_data);
To register a new signal on an existing type, we can use any of <function><link linkend="g-signal-newv">g_signal_newv</link></function>,
<function><link linkend="g-signal-new-valist">g_signal_new_valist</link></function> or <function><link linkend="g-signal-new">g_signal_new</link></function> functions:
<programlisting>
guint g_signal_newv (const gchar *signal_name,
GType itype,
GSignalFlags signal_flags,
GClosure *class_closure,
GSignalAccumulator accumulator,
gpointer accu_data,
GSignalCMarshaller c_marshaller,
GType return_type,
guint n_params,
GType *param_types);
guint g_signal_newv (const gchar *signal_name,
GType itype,
GSignalFlags signal_flags,
GClosure *class_closure,
GSignalAccumulator accumulator,
gpointer accu_data,
GSignalCMarshaller c_marshaller,
GType return_type,
guint n_params,
GType *param_types);
</programlisting>
The number of parameters to these functions is a bit intimidating but they are relatively
simple:
@ -308,10 +308,10 @@ guint g_signal_newv (const gchar *signal_name,
Signal emission is done through the use of the <function><link linkend="g-signal-emit">g_signal_emit</link></function> family
of functions.
<programlisting>
void g_signal_emitv (const GValue *instance_and_params,
guint signal_id,
GQuark detail,
GValue *return_value);
void g_signal_emitv (const GValue *instance_and_params,
guint signal_id,
GQuark detail,
GValue *return_value);
</programlisting>
<itemizedlist>
<listitem><para>

View File

@ -787,7 +787,7 @@ struct _GInterfaceInfo
When an instantiable classed type which registered an interface implementation
is created for the first time, its class structure is initialized following the process
described in <xref linkend="gtype-instantiable-classed"/>. Once the class structure is
initialized,the function <function>type_class_init_Wm</function> (implemented in <filename>
initialized, the function <function>type_class_init_Wm</function> (implemented in <filename>
gtype.c</filename>) initializes the interface implementations associated with
that type by calling <function>type_iface_vtable_init_Wm</function> for each
interface.

File diff suppressed because it is too large Load Diff