integrate patch from Stefan Kost

This commit is contained in:
Mathieu Lacage 2004-11-04 14:52:33 +00:00
parent 475bad0c7f
commit acba30a9eb
3 changed files with 218 additions and 28 deletions

View File

@ -28,16 +28,18 @@
<para>
The <function>g_object_new</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
has been correctly initialized by glib's type system and then invoke at one
point or another the constructor class method which is used to:
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 memory through <function>g_type_create_instance</function>,
Allocate and clear memory through <function>g_type_create_instance</function>,
</para></listitem>
<listitem><para>
Initialize the object' 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>
@ -56,7 +58,7 @@
#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_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MAMAN_TYPE_BAR, MamanBarClass))
#define MAMAN_IS_BAR(obj) (G_TYPE_CHECK_TYPE ((obj), MAMAN_TYPE_BAR))
#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))
@ -285,7 +287,8 @@ MamanBar *bar = g_object_new (MAMAN_TYPE_BAR, NULL);
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, aso...)
models (such as garbage collection, aso...). The methods which are used to
manipulate this reference count are described below.
<programlisting>
/*
Refcounting
@ -319,10 +322,12 @@ void g_object_run_dispose (GObject *object);
<title>Reference count</title>
<para>
<function>g_object_ref</function>/<function>g_object_unref</function> respectively
The functions <function>g_object_ref</function>/<function>g_object_unref</function> respectively
increase and decrease the reference count. None of these function is thread-safe.
The reference count is, unsurprisingly, initialized to one by
<function>g_object_new</function>. When the reference count reaches zero, that is,
<function>g_object_new</function> which means that the caller
is currenly the sole owner of the newly-created reference.
When the reference count reaches zero, that is,
when <function>g_object_unref</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.
@ -334,8 +339,8 @@ void g_object_run_dispose (GObject *object);
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"></xref> and
<xref linkend="gtype-non-instantiable-classed"></xref>.
will be destroyed as described in <xref linkend="gtype-instantiable-classed"/> and
<xref linkend="gtype-non-instantiable-classed"/>.
</para>
<para>
@ -383,7 +388,7 @@ void g_object_run_dispose (GObject *object);
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"></xref>.
explained in <xref linkend="gobject-memory-cycles"/>.
</entry>
</row>
<row>
@ -521,7 +526,7 @@ void g_object_run_dispose (GObject *object);
enum {
MAMAN_BAR_CONSTRUCT_NAME = 1,
MAMAN_BAR_PAPA_NUMBER = 2,
MAMAN_BAR_PAPA_NUMBER,
};
static void
@ -554,7 +559,7 @@ maman_bar_set_property (GObject *object,
break;
default:
/* We don't have any other property... */
g_assert (FALSE);
G_OBJECT_WARN_INVALID_PROPERTY_ID(object,property_id,pspec);
break;
}
}
@ -578,7 +583,7 @@ maman_bar_get_property (GObject *object,
break;
default:
/* We don't have any other property... */
g_assert (FALSE);
G_OBJECT_WARN_INVALID_PROPERTY_ID(object,property_id,pspec);
break;
}
}

View File

@ -282,10 +282,11 @@ struct _GTypeValueTable
#define MAMAN_BAR_TYPE (maman_bar_get_type ())
#define MAMAN_BAR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MAMAN_BAR_TYPE, MamanBar))
#define MAMAN_BAR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MAMAN_BAR_TYPE, MamanBarClass))
#define MAMAN_IS_BAR(obj) (G_TYPE_CHECK_TYPE ((obj), MAMAN_BAR_TYPE))
#define MAMAN_IS_BAR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MAMAN_BAR_TYPE))
#define MAMAN_IS_BAR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MAMAN_BAR_TYPE))
#define MAMAN_BAR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MAMAN_BAR_TYPE, MamanBarClass))
</programlisting>
<note>Stick to the naming <code>klass</code> as <code>class</code> is a registered c++ keyword.</note>
</para>
<para>
@ -609,7 +610,7 @@ The class initialization process is entirely implemented in
<row>
<entry>First call to <function>g_type_create_instance</function> for target type</entry>
<entry colspan="2">interface initialization, see
<xref linkend="gtype-non-instantiable-classed-init"></xref></entry>
<xref linkend="gtype-non-instantiable-classed-init"/></entry>
</row>
<row>
<entry>Each call to <function>g_type_create_instance</function> for target type</entry>
@ -619,7 +620,7 @@ The class initialization process is entirely implemented in
<row>
<entry>Last call to <function>g_type_free_instance</function> for target type</entry>
<entry colspan="2">interface destruction, see
<xref linkend="gtype-non-instantiable-classed-dest"></xref></entry>
<xref linkend="gtype-non-instantiable-classed-dest"/></entry>
<entry></entry>
</row>
<row>
@ -646,7 +647,7 @@ The class initialization process is entirely implemented in
<para>
GType's Interfaces are very similar to Java's interfaces. To declare one of these
you have to register a non-instantiable classed type which derives from
GTypeInterface. The following piece of code declares such an interface.
<type>GTypeInterface</type>. The following piece of code declares such an interface.
<programlisting>
#define MAMAN_IBAZ_TYPE (maman_ibaz_get_type ())
#define MAMAN_IBAZ(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MAMAN_IBAZ_TYPE, MamanIbaz))
@ -765,7 +766,7 @@ struct _GInterfaceInfo
<para>
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"></xref>. Once the class structure is
described in <xref linkend="gtype-instantiable-classed"/>. Once the class structure is
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
@ -857,7 +858,7 @@ maman_ibaz_base_init (gpointer g_class)
</table>
It is highly unlikely (ie: I do not know of <emphasis>anyone</emphasis> who actually
used it) you will ever need other more fancy things such as the ones described in the
following section (<xref linkend="gtype-non-instantiable-classed-dest"></xref>).
following section (<xref linkend="gtype-non-instantiable-classed-dest"/>).
</para>
</sect2>
@ -879,7 +880,7 @@ maman_ibaz_base_init (gpointer g_class)
<para>
Again, it is important to understand, as in
<xref linkend="gtype-non-instantiable-classed-init"></xref>,
<xref linkend="gtype-non-instantiable-classed-init"/>,
that both <function>interface_finalize</function> and <function>base_finalize</function>
are invoked exactly once for the destruction of each implementation of an interface. Thus,
if you were to use one of these functions, you would need to use a static integer variable

View File

@ -77,6 +77,15 @@
eyesight like me.
</para>
<para>
When you need some private (internal) declarations in several (sub)classes,
you can define them in a private header file which is often named by
appending the <emphasis>private</emphasis> keyword to the public header name.
For example, one could use <filename>maman-bar-private.h</filename>,
<filename>maman_bar_private.h</filename> or <filename>mamanbarprivate.h</filename>.
Typically, such private header files are not installed.
</para>
<para>
The basic conventions for any header which exposes a GType are described in
<xref linkend="gtype-conventions"/>. Most GObject-based code also obeys onf of the following
@ -143,8 +152,10 @@ struct _MamanBar {
</para></listitem>
<listitem><para>
All of Nautilus code and a lot of Gnome libraries use private indirection members, as described
by Herb Sutter in his Pimpl articles (see <ulink>http://www.gotw.ca/publications/mill04.htm</ulink>: Herb summarizes the different
issues better than I will):
by Herb Sutter in his Pimpl articles
(see <ulink url="http://www.gotw.ca/gotw/024.htm">Compilation Firewalls</ulink>
and <ulink url="http://www.gotw.ca/gotw/028.htm">The Fast Pimpl Idiom</ulink>
: he summarizes the different issues better than I will).
<programlisting>
typedef struct _MamanBarPrivate MamanBarPrivate;
struct _MamanBar {
@ -154,6 +165,7 @@ struct _MamanBar {
MamanBarPrivate *priv;
};
</programlisting>
<note>Do not call this <code>private</code>, as that is a registered c++ keyword.</note>
The private structure is then defined in the .c file, instantiated in the object's
<function>init</function> function and destroyed in the object's <function>finalize</function> function.
<programlisting>
@ -436,7 +448,7 @@ if (self->private->dispose_has_run) {
Just as with C++, there are many different ways to define object
methods and extend them: the following list and sections draw on C++ vocabulary.
(Readers are expected to know basic C++ buzzwords. Those who have not had to
write C++ code recently can refer to <ulink>http://www.cplusplus.com/doc/tutorial/</ulink> to refresh their
write C++ code recently can refer to e.g. <ulink>http://www.cplusplus.com/doc/tutorial/</ulink> to refresh their
memories.)
<itemizedlist>
<listitem><para>
@ -931,8 +943,6 @@ baz_instance_init (GTypeInstance *instance,
<sect2>
<title>Interface definition prerequisites</title>
<para>To specify that an interface requires the presence of other interfaces when implemented,
GObject introduces the concept of <emphasis>prerequisites</emphasis>: it is possible to associate
a list of prerequisite interfaces to an interface. For example, if object A wishes to implement interface
@ -1039,6 +1049,172 @@ maman_bar_get_type (void)
</sect2>
<sect2 id="howto-interface-properties">
<title>Interface Properties</title>
<para>Starting from version 2.4 of glib, gobject interfaces can also have properties.
Declaration of the interface properties is similar to declaring the properties of
ordinary gobject types as explained in <xref linkend="gobject-properties"/>,
except that <function>g_object_interface_install_property</function> is used to
declare the properties instead of <function>g_object_class_install_property</function>.
</para>
<para>To include a property named 'name' of type <type>string</type> in the
<type>maman_ibaz</type> interface example code above, we only need to add one
<footnote>
<para>That really is one line extended to six for the sake of clarity
</para>
</footnote>
line in the <function>maman_ibaz_base_init</function>
<footnote>
<para>The gobject_install_property can also be called from <function>class_init</function> but it must not be called after that point.
</para>
</footnote>
as shown below:
<programlisting>
static void
maman_ibaz_base_init (gpointer g_class)
{
static gboolean initialized = FALSE;
if (!initialized) {
/* create interface signals here. */
g_object_interface_install_property (g_class,
g_param_spec_string ("name",
"maman_ibaz_name",
"Name of the MamanIbaz",
"maman",
G_PARAM_READWRITE));
initialized = TRUE;
}
}
</programlisting>
</para>
<para>One point worth noting is that the declared property wasn't assigned an
integer ID. The reason being that integer IDs of properities are utilized only
inside the get and set methods and since interfaces do not implement properties,
there is no need to assign integer IDs to interface properties.
</para>
<para>The story for the implementers of the interface is also quite trivial.
An implementer shall declare and define it's properties in the usual way as
explained in <xref linkend="gobject-properties"/>, except for one small
change: it shall declare the properties of the interface it implements using
<function>g_object_class_override_property</function> instead of
<function>g_object_class_install_property</function>. The following code snipet
shows the modifications needed in the <type>MamanBaz</type> declaration and
implementation above:
<programlisting>
struct _MamanBaz {
GObject parent;
gint instance_member;
gchar *name; /* placeholder for property */
};
enum
{
ARG_0,
ARG_NAME
};
GType
maman_baz_get_type (void)
{
static GType type = 0;
if (type == 0) {
static const GTypeInfo info = {
sizeof (MamanBazClass),
NULL, /* base_init */
NULL, /* base_finalize */
baz_class_init, /* class_init */
NULL, /* class_finalize */
NULL, /* class_data */
sizeof (MamanBaz),
0, /* n_preallocs */
baz_instance_init /* instance_init */
};
static const GInterfaceInfo ibaz_info = {
(GInterfaceInitFunc) baz_interface_init, /* interface_init */
NULL, /* interface_finalize */
NULL /* interface_data */
};
type = g_type_register_static (G_TYPE_OBJECT,
"MamanBazType",
&amp;info, 0);
g_type_add_interface_static (type,
MAMAN_TYPE_IBAZ,
&amp;ibaz_info);
}
return type;
}
static void
maman_baz_class_init (MamanBazClass * klass)
{
GObjectClass *gobject_class;
gobject_class = (GObjectClass *) klass;
parent_class = g_type_class_ref (G_TYPE_OBJECT);
gobject_class->set_property = maman_baz_set_property;
gobject_class->get_property = maman_baz_get_property;
g_object_class_override_property (gobject_class, ARG_NAME, "name");
}
static void
maman_baz_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
MamanBaz *baz;
GObject *obj;
/* it's not null if we got it, but it might not be ours */
g_return_if_fail (G_IS_MAMAN_BAZ (object));
baz = MAMAN_BAZ (object);
switch (prop_id) {
case ARG_NAME:
baz->name = g_value_get_string (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
maman_baz_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
MamanBaz *baz;
/* it's not null if we got it, but it might not be ours */
g_return_if_fail (G_IS_TEXT_PLUGIN (object));
baz = MAMAN_BAZ (object);
switch (prop_id) {
case ARG_NAME:
g_value_set_string (value, baz->name);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
</programlisting>
</para>
</sect2>
</sect1>
<!--
@ -1068,7 +1244,7 @@ maman_bar_get_type (void)
just emit events which can be received by numerous clients.
</para>
<sect2>
<sect2 id="howto-simple-signals">
<title>Simple use of signals</title>
<para>The most basic use of signals is to implement simple event notification: for example, if we have a
@ -1117,8 +1293,16 @@ As shown above, you can safely set the details parameter to zero if you do not k
For a discussion of what you could used it for, see <xref linkend="signal-detail"/>
</para>
<para>
</para>
<para>
The signature of the signal handler in the above example is defined as
<function>g_cclosure_marshal_VOID__VOID</function>. Its name follows
a simple convention which encodes the function parameter and return value
types in the function name. Specifically, the value infront of the double
underscore is the type of the return value, while the value(s) after the
double underscore denote the parameter types.
The header <filename>gobject/gmarshal.h</filename> defines a set of commonly
needed closures that one can use.
</para>
</sect2>