mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2024-11-10 11:26:16 +01:00
integrate patch from Stefan Kost
This commit is contained in:
parent
475bad0c7f
commit
acba30a9eb
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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",
|
||||
&info, 0);
|
||||
g_type_add_interface_static (type,
|
||||
MAMAN_TYPE_IBAZ,
|
||||
&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>
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user