mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-08-18 14:48:53 +02:00
Get rid of a bunch of Maman stuff, and use the new macros and functions instead of the existing GParamSpec API. https://bugzilla.gnome.org/show_bug.cgi?id=648526
675 lines
30 KiB
XML
675 lines
30 KiB
XML
<?xml version='1.0' encoding="ISO-8859-1"?>
|
|
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
|
|
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
|
]>
|
|
<chapter id="chapter-gobject">
|
|
<title>The GObject base class</title>
|
|
|
|
<para>
|
|
The previous chapter discussed the details of GLib's Dynamic Type System.
|
|
The GObject library also contains an implementation for a base fundamental
|
|
type named <link linkend="GObject"><type>GObject</type></link>.
|
|
</para>
|
|
|
|
<para>
|
|
<link linkend="GObject"><type>GObject</type></link> is a fundamental classed instantiable type. It implements:
|
|
<itemizedlist>
|
|
<listitem><para>Memory management with reference counting</para></listitem>
|
|
<listitem><para>Construction/Destruction of instances</para></listitem>
|
|
<listitem><para>Generic per-object properties with set/get function pairs</para></listitem>
|
|
<listitem><para>Easy use of signals</para></listitem>
|
|
</itemizedlist>
|
|
All the GNOME libraries which use the GLib type system (like GTK+ and GStreamer)
|
|
inherit from <link linkend="GObject"><type>GObject</type></link> which is why it is important to understand
|
|
the details of how it works.
|
|
</para>
|
|
|
|
<sect1 id="gobject-instantiation">
|
|
<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:
|
|
<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'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.
|
|
</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:
|
|
<programlisting>
|
|
GObject *(* constructor) (GType gtype,
|
|
guint n_properties,
|
|
GObjectConstructParam *properties);
|
|
</programlisting>
|
|
</para>
|
|
|
|
<para>
|
|
The example below shows how <type>MamanBar</type> overrides the parent's constructor:
|
|
<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_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;
|
|
|
|
struct _MamanBar
|
|
{
|
|
GObject parent_instance;
|
|
|
|
/* instance members */
|
|
};
|
|
|
|
struct _MamanBarClass
|
|
{
|
|
GObjectClass parent_class;
|
|
|
|
/* class members */
|
|
};
|
|
|
|
/* 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 gtype,
|
|
guint n_properties,
|
|
GObjectConstructParam *properties)
|
|
{
|
|
GObject *obj;
|
|
|
|
{
|
|
/* Always chain up to the parent constructor */
|
|
obj = G_OBJECT_CLASS (maman_bar_parent_class)->constructor (gtype, n_properties, properties);
|
|
}
|
|
|
|
/* update the object state depending on constructor properties */
|
|
|
|
return obj;
|
|
}
|
|
|
|
static void
|
|
maman_bar_class_init (MamanBarClass *klass)
|
|
{
|
|
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
|
|
|
gobject_class->constructor = maman_bar_constructor;
|
|
}
|
|
|
|
static void
|
|
maman_bar_init (MamanBar *self)
|
|
{
|
|
/* initialize the object */
|
|
}
|
|
|
|
</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_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>
|
|
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
|
|
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. 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>
|
|
Finally, at one point or another, <function>g_object_constructor</function> is invoked
|
|
by the last constructor in the chain. This function allocates the object's instance' buffer
|
|
through <function><link linkend="g-type-create-instance">g_type_create_instance</link></function>
|
|
which means that the instance_init function is invoked at this point if one
|
|
was registered. After instance_init returns, the object is fully initialized and should be
|
|
ready to answer any user-request. When <function><link linkend="g-type-create-instance">g_type_create_instance</link></function>
|
|
returns, <function>g_object_constructor</function> sets the construction properties
|
|
(i.e. the properties which were given to <function><link linkend="g-object-new">g_object_new</link></function>) and returns
|
|
to the user's constructor which is then allowed to do useful instance initialization...
|
|
</para>
|
|
|
|
<para>
|
|
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>
|
|
<table id="gobject-construction-table">
|
|
<title><function><link linkend="g-object-new">g_object_new</link></function></title>
|
|
<tgroup cols="3">
|
|
<colspec colwidth="*" colnum="1" align="left"/>
|
|
<colspec colwidth="*" colnum="2" align="left"/>
|
|
<colspec colwidth="8*" colnum="3" align="left"/>
|
|
|
|
<thead>
|
|
<row>
|
|
<entry>Invocation time</entry>
|
|
<entry>Function Invoked</entry>
|
|
<entry>Function's parameters</entry>
|
|
<entry>Remark</entry>
|
|
</row>
|
|
</thead>
|
|
<tbody>
|
|
<row>
|
|
<entry morerows="3">First call to <function><link linkend="g-object-new">g_object_new</link></function> for target type</entry>
|
|
<entry>target type's base_init function</entry>
|
|
<entry>On the inheritance tree of classes from fundamental type to target type.
|
|
base_init is invoked once for each class structure.</entry>
|
|
<entry>
|
|
I have no real idea on how this can be used. If you have a good real-life
|
|
example of how a class' base_init can be used, please, let me know.
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<!--entry>First call to <function><link linkend="g-object-new">g_object_new</link></function> for target type</entry-->
|
|
<entry>target type's class_init function</entry>
|
|
<entry>On target type's class structure</entry>
|
|
<entry>
|
|
Here, you should make sure to initialize or override class methods (that is,
|
|
assign to each class' method its function pointer) and create the signals and
|
|
the properties associated to your object.
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<!--entry>First call to <function><link linkend="g-object-new">g_object_new</link></function> for target type</entry-->
|
|
<entry>interface' base_init function</entry>
|
|
<entry>On interface' vtable</entry>
|
|
<entry></entry>
|
|
</row>
|
|
<row>
|
|
<!--entry>First call to <function><link linkend="g-object-new">g_object_new</link></function> for target type</entry-->
|
|
<entry>interface' interface_init function</entry>
|
|
<entry>On interface' vtable</entry>
|
|
<entry></entry>
|
|
</row>
|
|
<row>
|
|
<entry morerows="1">Each call to <function><link linkend="g-object-new">g_object_new</link></function> for target type</entry>
|
|
<entry>target type's class constructor method: GObjectClass->constructor</entry>
|
|
<entry>On object's instance</entry>
|
|
<entry>
|
|
If you need to complete the object initialization after all the construction properties
|
|
are set, override the constructor method and make sure to chain up to the object's
|
|
parent class before doing your own initialization.
|
|
In doubt, do not override the constructor method.
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<!--entry>Each call to <function><link linkend="g-object-new">g_object_new</link></function> for target type</entry-->
|
|
<entry>type's instance_init function</entry>
|
|
<entry>On the inheritance tree of classes from fundamental type to target type.
|
|
the instance_init provided for each type is invoked once for each instance
|
|
structure.</entry>
|
|
<entry>
|
|
Provide an instance_init function to initialize your object before its construction
|
|
properties are set. This is the preferred way to initialize a GObject instance.
|
|
This function is equivalent to C++ constructors.
|
|
</entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</table>
|
|
</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
|
|
<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.
|
|
</para>
|
|
</sect1>
|
|
|
|
<sect1 id="gobject-memory">
|
|
<title>Object memory management</title>
|
|
|
|
<para>
|
|
The memory-management API for GObjects is a bit complicated but the idea behind it
|
|
is pretty simple: the goal is to provide a flexible model based on reference counting
|
|
which can be integrated in applications which use or require different memory management
|
|
models (such as garbage collection). The methods which are used to
|
|
manipulate this reference count are described below.
|
|
<programlisting>
|
|
/*
|
|
Refcounting
|
|
*/
|
|
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);
|
|
/*
|
|
* Cycle handling
|
|
*/
|
|
void g_object_run_dispose (GObject *object);
|
|
</programlisting>
|
|
</para>
|
|
|
|
<sect2 id="gobject-memory-refcount">
|
|
<title>Reference count</title>
|
|
|
|
<para>
|
|
The functions <function><link linkend="g-object-ref">g_object_ref</link></function>/<function><link linkend="g-object-unref">g_object_unref</link></function> respectively
|
|
increase and decrease the reference count.These functions are thread-safe as of GLib 2.8.
|
|
The reference count is, unsurprisingly, initialized to one by
|
|
<function><link linkend="g-object-new">g_object_new</link></function> which means that the caller
|
|
is currently the sole owner of the newly-created reference.
|
|
When the reference count reaches zero, that is,
|
|
when <function><link linkend="g-object-unref">g_object_unref</link></function> is called by the last client holding
|
|
a reference to the object, the <emphasis>dispose</emphasis> and the
|
|
<emphasis>finalize</emphasis> class methods are invoked.
|
|
</para>
|
|
<para>
|
|
Finally, after <emphasis>finalize</emphasis> is invoked,
|
|
<function><link linkend="g-type-free-instance">g_type_free_instance</link></function> is called to free the object instance.
|
|
Depending on the memory allocation policy decided when the type was registered (through
|
|
one of the <function>g_type_register_*</function> functions), the object's instance
|
|
memory will be freed or returned to the object pool for this type.
|
|
Once the object has been freed, if it was the last instance of the type, the type's class
|
|
will be destroyed as described in <xref linkend="gtype-instantiable-classed"/> and
|
|
<xref linkend="gtype-non-instantiable-classed"/>.
|
|
</para>
|
|
|
|
<para>
|
|
The table below summarizes the destruction process of a GObject:
|
|
<table id="gobject-destruction-table">
|
|
<title><function><link linkend="g-object-unref">g_object_unref</link></function></title>
|
|
<tgroup cols="3">
|
|
<colspec colwidth="*" colnum="1" align="left"/>
|
|
<colspec colwidth="*" colnum="2" align="left"/>
|
|
<colspec colwidth="8*" colnum="3" align="left"/>
|
|
|
|
<thead>
|
|
<row>
|
|
<entry>Invocation time</entry>
|
|
<entry>Function Invoked</entry>
|
|
<entry>Function's parameters</entry>
|
|
<entry>Remark</entry>
|
|
</row>
|
|
</thead>
|
|
<tbody>
|
|
<row>
|
|
<entry morerows="1">Last call to <function><link linkend="g-object-unref">g_object_unref</link></function> for an instance
|
|
of target type
|
|
</entry>
|
|
<entry>target type's dispose class function</entry>
|
|
<entry>GObject instance</entry>
|
|
<entry>
|
|
When dispose ends, the object should not hold any reference to any other
|
|
member object. The object is also expected to be able to answer client
|
|
method invocations (with possibly an error code but no memory violation)
|
|
until finalize is executed. dispose can be executed more than once.
|
|
dispose should chain up to its parent implementation just before returning
|
|
to the caller.
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<!--entry>Last call to <function><link linkend="g-object-unref">g_object_unref</link></function> for an instance
|
|
of target type
|
|
</entry-->
|
|
<entry>target type's finalize class function</entry>
|
|
<entry>GObject instance</entry>
|
|
<entry>
|
|
Finalize is expected to complete the destruction process initiated by
|
|
dispose. It should complete the object's destruction. finalize will be
|
|
executed only once.
|
|
finalize should chain up to its parent implementation just before returning
|
|
to the caller.
|
|
The reason why the destruction process is split is two different phases is
|
|
explained in <xref linkend="gobject-memory-cycles"/>.
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry morerows="3">Last call to <function><link linkend="g-object-unref">g_object_unref</link></function> for the last
|
|
instance of target type
|
|
</entry>
|
|
<entry>interface' interface_finalize function</entry>
|
|
<entry>On interface' vtable</entry>
|
|
<entry>Never used in practice. Unlikely you will need it.</entry>
|
|
</row>
|
|
<row>
|
|
<!--entry>Last call to <function><link linkend="g-object-unref">g_object_unref</link></function>for the last
|
|
instance of target type
|
|
</entry-->
|
|
<entry>interface' base_finalize function</entry>
|
|
<entry>On interface' vtable</entry>
|
|
<entry>Never used in practice. Unlikely you will need it.</entry>
|
|
</row>
|
|
<row>
|
|
<!--entry>Last call to <function><link linkend="g-object-unref">g_object_unref</link></function> for the last
|
|
instance of target type
|
|
</entry-->
|
|
<entry>target type's class_finalize function</entry>
|
|
<entry>On target type's class structure</entry>
|
|
<entry>Never used in practice. Unlikely you will need it.</entry>
|
|
</row>
|
|
<row>
|
|
<!--entry>Last call to <function><link linkend="g-object-unref">g_object_unref</link></function> for the last
|
|
instance of target type
|
|
</entry-->
|
|
<entry>type's base_finalize function</entry>
|
|
<entry>On the inheritance tree of classes from fundamental type to target type.
|
|
base_init is invoked once for each class structure.</entry>
|
|
<entry>Never used in practice. Unlikely you will need it.</entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</table>
|
|
</para>
|
|
|
|
</sect2>
|
|
|
|
<sect2 id="gobject-memory-weakref">
|
|
<title>Weak References</title>
|
|
|
|
<para>
|
|
Weak References are used to monitor object finalization:
|
|
<function><link linkend="g-object-weak-ref">g_object_weak_ref</link></function> adds a monitoring callback which does
|
|
not hold a reference to the object but which is invoked when the object runs
|
|
its dispose method. As such, each weak ref can be invoked more than once upon
|
|
object finalization (since dispose can run more than once during object
|
|
finalization).
|
|
</para>
|
|
|
|
<para>
|
|
<function><link linkend="g-object-weak-unref">g_object_weak_unref</link></function> can be used to remove a monitoring
|
|
callback from the object.
|
|
</para>
|
|
|
|
<para>
|
|
Weak References are also used to implement <function><link linkend="g-object-add-weak-pointer">g_object_add_weak_pointer</link></function>
|
|
and <function><link linkend="g-object-remove-weak-pointer">g_object_remove_weak_pointer</link></function>. These functions add a weak reference
|
|
to the object they are applied to which makes sure to nullify the pointer given by the user
|
|
when object is finalized.
|
|
</para>
|
|
|
|
</sect2>
|
|
|
|
<sect2 id="gobject-memory-cycles">
|
|
<title>Reference counts and cycles</title>
|
|
|
|
<para>
|
|
Note: the following section was inspired by James Henstridge. I guess this means that
|
|
all praise and all curses will be directly forwarded to him.
|
|
</para>
|
|
|
|
<para>
|
|
GObject's memory management model was designed to be easily integrated in existing code
|
|
using garbage collection. This is why the destruction process is split in two phases:
|
|
the first phase, executed in the dispose handler is supposed to release all references
|
|
to other member objects. The second phase, executed by the finalize handler is supposed
|
|
to complete the object's destruction process. Object methods should be able to run
|
|
without program error (that is, without segfault :) in-between the two phases.
|
|
</para>
|
|
|
|
<para>
|
|
This two-step destruction process is very useful to break reference counting cycles.
|
|
While the detection of the cycles is up to the external code, once the cycles have been
|
|
detected, the external code can invoke <function><link linkend="g-object-run-dispose">g_object_run_dispose</link></function> which
|
|
will indeed break any existing cycles since it will run the dispose handler associated
|
|
to the object and thus release all references to other objects.
|
|
</para>
|
|
|
|
<para>
|
|
Attentive readers might now have understood one of the rules about the dispose handler
|
|
we stated a bit sooner: the dispose handler can be invoked multiple times. Let's say we
|
|
have a reference count cycle: object A references B which itself references object A.
|
|
Let's say we have detected the cycle and we want to destroy the two objects. One way to
|
|
do this would be to invoke <function><link linkend="g-object-run-dispose">g_object_run_dispose</link></function> on one of the
|
|
objects.
|
|
</para>
|
|
|
|
<para>
|
|
If object A releases all its references to all objects, this means it releases its
|
|
reference to object B. If object B was not owned by anyone else, this is its last
|
|
reference count which means this last unref runs B's dispose handler which, in turn,
|
|
releases B's reference on object A. If this is A's last reference count, this last
|
|
unref runs A's dispose handler which is running for the second time before
|
|
A's finalize handler is invoked !
|
|
</para>
|
|
|
|
<para>
|
|
The above example, which might seem a bit contrived can really happen if your
|
|
GObject's are being handled by language bindings. I would thus suggest the rules stated above
|
|
for object destruction are closely followed. Otherwise, <emphasis>Bad Bad Things</emphasis>
|
|
will happen.
|
|
</para>
|
|
</sect2>
|
|
</sect1>
|
|
|
|
<sect1 id="gobject-properties">
|
|
<title>Object properties</title>
|
|
|
|
<para>
|
|
One of GObject's nice features is its generic get/set mechanism for object
|
|
properties. When an object
|
|
is instantiated, the object's class_init handler should be used to register
|
|
the object's properties with the <function>G_DEFINE_PROPERTIES</function>
|
|
macro.
|
|
</para>
|
|
|
|
<para>
|
|
The best way to understand how object properties work is by looking at a real example
|
|
on how it is used:
|
|
<informalexample><programlisting>
|
|
typedef struct {
|
|
char *name;
|
|
gint age;
|
|
} PersonPrivate;
|
|
|
|
G_DEFINE_TYPE_WITH_PRIVATE (Person, person, G_TYPE_OBJECT)
|
|
|
|
static void
|
|
person_finalize (GObject *gobject)
|
|
{
|
|
PersonPrivate *priv = person_get_instance_private ((Person *) gobject);
|
|
|
|
g_free (priv->name);
|
|
|
|
G_OBJECT_CLASS (person_parent_class)->finalize (gobject);
|
|
}
|
|
|
|
static void
|
|
person_class_init (PersonClass *klass)
|
|
{
|
|
G_OBJECT_CLASS (klass)->finalize = person_finalize;
|
|
|
|
G_DEFINE_PROPERTIES (Person, person, klass,
|
|
G_DEFINE_PROPERTY (Person, string, name, G_PROPERTY_READWRITE | G_PROPERTY_COPY_SET)
|
|
G_DEFINE_PROPERTY (Person, uint, age, G_PROPERTY_READWRITE))
|
|
}
|
|
</programlisting></informalexample>
|
|
The code above will add two properties, <emphasis>name</emphasis> and
|
|
<emphasis>age</emphasis> to the <emphasis>Person</emphasis> class;
|
|
the name property is a string, and the age property is a generic unsigned
|
|
integer. Both properties are readable and writable. Additionally, the name
|
|
property is implemented by copying the string passed to the setter, but
|
|
the get function will return a pointer. By default, the properties will
|
|
be stored inside the private data structure on a Person instance, using
|
|
the given field name.
|
|
</para>
|
|
|
|
<para>
|
|
Once we define the properties, their types, their access semantics,
|
|
and their visibility, we can access them through the generic GObject
|
|
API:
|
|
<informalexample><programlisting>
|
|
Person *person;
|
|
|
|
person = g_object_new (person_get_type (), NULL);
|
|
|
|
g_object_set (person,
|
|
"name", "Rupert S. Monkey",
|
|
"age", 33,
|
|
NULL);
|
|
</programlisting></informalexample>
|
|
The code above will set the two properties on the <emphasis>person</emphasis>
|
|
instance.
|
|
</para>
|
|
|
|
<para>
|
|
It should be noted that using the generic GObject API should not be the
|
|
common pattern for setting properties in C. The generic API uses variadic
|
|
arguments, which have side effects in terms of error handling, type
|
|
inference, and argument termination; those side effects can lead to
|
|
hard to track bugs. One option to avoid the variadic arguments API is to
|
|
use the GValue-based one, e.g.
|
|
<informalexample><programlisting>
|
|
GValue name_value = G_VALUE_INIT;
|
|
GValue age_value = G_VALUE_INIT;
|
|
|
|
g_value_init (&name_value, G_TYPE_STRING);
|
|
g_value_set_string (&name_value, "Rupert S. Monkey");
|
|
|
|
g_value_init (&age_value, G_TYPE_INT);
|
|
g_value_set_int (&age_value, 33);
|
|
|
|
g_object_set_property (G_OBJECT (person), "name", &name_value);
|
|
g_object_set_property (G_OBJECT (person), "age", &age_value);
|
|
|
|
g_value_unset (&name_value);
|
|
g_value_unset (&age_value);
|
|
</programlisting></informalexample>
|
|
But, as you can see from the example above, the amount of code necessary
|
|
balloons rapidly out of control.
|
|
</para>
|
|
|
|
<para>
|
|
The preferred way to access properties on a GObject is to use accessor
|
|
functions, which guarantee type safety when compiling code, and avoid
|
|
large amounts of code. For instance:
|
|
<informalexample><programlisting>
|
|
void
|
|
person_set_name (Person *person, const char *name)
|
|
{
|
|
GProperty *property;
|
|
|
|
property = g_object_class_find_property (G_OBJECT_GET_CLASS (person), "name");
|
|
g_property_set (property, person, name);
|
|
}
|
|
|
|
const char *
|
|
person_get_name (Person *person)
|
|
{
|
|
PersonPrivate *priv = person_get_instance_private (person);
|
|
|
|
return priv->name;
|
|
}
|
|
</programlisting></informalexample>
|
|
</para>
|
|
|
|
<para>
|
|
GObject provides pre-processor macros to simplify the developer's job at
|
|
creating these functions, which result in cleaner and simpler code; for
|
|
instance, the example above can be effectively replaced by a single
|
|
macro:
|
|
<informalexample><programlisting>
|
|
G_DEFINE_PROPERTY_GET_SET (Person, person, const char *, name)
|
|
</programlisting></informalexample>
|
|
The macro above will generate both the get function and the set one.
|
|
</para>
|
|
|
|
<sect2>
|
|
<title>Property notification and binding</title>
|
|
|
|
<para>
|
|
Every time a property is set to a new value, GObject will emit a signal
|
|
called <emphasis>notify</emphasis>; this signal can be used to update
|
|
ancillary code every time the state of an instance changes; for instance,
|
|
it is possible to update the text field of a GUI with the content of the
|
|
person's name, if the Person instance is changed by another part of the
|
|
GUI, or by another source.
|
|
</para>
|
|
|
|
<para>
|
|
The notification signal is detailed with the name of the property which
|
|
has changed, so it's possible to subscribe to changes to specific
|
|
properties, for instance:
|
|
<informalexample><programlisting>
|
|
static void
|
|
on_name_change (GObject *gobject,
|
|
GParamSpec *pspec,
|
|
gpointer user_data)
|
|
{
|
|
Person *person = (Person *) gobject;
|
|
GtkLabel *label = user_data;
|
|
|
|
gtk_label_set_text (label, person_get_name (person));
|
|
}
|
|
|
|
...
|
|
g_signal_connect (person, "notify::name", G_CALLBACK (on_name_change), ui_label);
|
|
...
|
|
</programlisting></informalexample>
|
|
The code above will update the contents of a GtkLabel using the name
|
|
property every time the property changes.
|
|
</para>
|
|
|
|
<para>
|
|
It is also possible to use the property bindings to tie together a
|
|
property on a source instance and a property on a target instance.
|
|
In the example above, we could bind together the name property on a
|
|
Person instance to the text property on a GtkLabel instance:
|
|
<informalexample><programlisting>
|
|
g_object_bind_property (person, "name", label, "text", G_BINDING_DEFAULT);
|
|
</programlisting></informalexample>
|
|
Thus removing the need to have an explicit function doing so.
|
|
</para>
|
|
|
|
</sect2>
|
|
|
|
</sect1>
|
|
|
|
</chapter>
|