mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2024-12-26 15:36:14 +01:00
docs: Various wording changes in the GObject how-to
• Consistently make all titles sentence case • Fix various typos • Remove an unnecessary footnote • Remove first person phrasing https://bugzilla.gnome.org/show_bug.cgi?id=744060
This commit is contained in:
parent
f1287a9b2f
commit
2e4700d52b
@ -16,11 +16,8 @@
|
||||
<title>How to define and implement a new GObject</title>
|
||||
|
||||
<para>
|
||||
Clearly, this is one of the most common questions people ask: they just
|
||||
want to crank code and implement a subclass of a GObject. Sometimes because
|
||||
they want to create their own class hierarchy, sometimes because they want
|
||||
to subclass one of GTK+'s widget. This chapter will focus on the
|
||||
implementation of a subtype of GObject.
|
||||
This chapter focuses on the implementation of a subtype of GObject, for
|
||||
example to create a custom class hierarchy, or to subclass a GTK+ widget.
|
||||
</para>
|
||||
|
||||
<sect1 id="howto-gobject-header">
|
||||
@ -261,7 +258,7 @@ G_DEFINE_TYPE_WITH_PRIVATE (MamanBar, maman_bar, G_TYPE_OBJECT)
|
||||
</sect1>
|
||||
|
||||
<sect1 id="howto-gobject-construction">
|
||||
<title>Object Construction</title>
|
||||
<title>Object construction</title>
|
||||
|
||||
<para>
|
||||
People often get confused when trying to construct their GObjects because of the
|
||||
@ -296,7 +293,7 @@ G_DEFINE_TYPE_WITH_PRIVATE (MamanBar, maman_bar, G_TYPE_OBJECT)
|
||||
</para>
|
||||
|
||||
<para>
|
||||
As such, I would recommend writing the following code first:
|
||||
You should write the following code first:
|
||||
<informalexample><programlisting>
|
||||
G_DEFINE_TYPE_WITH_PRIVATE (MamanBar, maman_bar, G_TYPE_OBJECT)
|
||||
|
||||
@ -365,10 +362,10 @@ bar_class_init (MamanBarClass *klass)
|
||||
of a type only after the properties passed to the constructors have been
|
||||
set. This is possible through the use of the <function>constructor()</function>
|
||||
class method as described in <xref linkend="gobject-instantiation"/> or,
|
||||
more simply, using the <function>constructed()</function> class method
|
||||
available since GLib 2.12. Note that the <function>constructed()</function>
|
||||
more simply, using the <function>constructed()</function> class method.
|
||||
Note that the <function>constructed()</function>
|
||||
virtual function will only be invoked after the properties marked as
|
||||
<function>G_PARAM_CONSTRUCT_ONLY</function>s or
|
||||
<function>G_PARAM_CONSTRUCT_ONLY</function> or
|
||||
<function>G_PARAM_CONSTRUCT</function> have been consumed, but
|
||||
before the regular properties passed to <function>g_object_new()</function>
|
||||
have been set.
|
||||
@ -376,7 +373,7 @@ bar_class_init (MamanBarClass *klass)
|
||||
</sect1>
|
||||
|
||||
<sect1 id="howto-gobject-destruction">
|
||||
<title>Object Destruction</title>
|
||||
<title>Object destruction</title>
|
||||
|
||||
<para>
|
||||
Again, it is often difficult to figure out which mechanism to use to
|
||||
@ -387,11 +384,12 @@ bar_class_init (MamanBarClass *klass)
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The destruction process of your object might be split in two different
|
||||
phases: dispose and the finalize. This split is necessary to handle
|
||||
The destruction process of your object is in two phases: dispose and
|
||||
finalize. This split is necessary to handle
|
||||
potential cycles due to the nature of the reference counting mechanism
|
||||
used by GObject, as well as dealing with temporary vivification of
|
||||
used by GObject, as well as dealing with temporary revival of
|
||||
instances in case of signal emission during the destruction sequence.
|
||||
See <xref linkend="gobject-memory-cycles"/> for more information.
|
||||
<informalexample><programlisting>
|
||||
struct _MamanBarPrivate
|
||||
{
|
||||
@ -463,7 +461,7 @@ maman_bar_init (MamanBar *self);
|
||||
It is possible that object methods might be invoked after dispose is
|
||||
run and before finalize runs. GObject does not consider this to be a
|
||||
program error: you must gracefully detect this and neither crash nor
|
||||
warn the user, by having a disposed instance revert to an inhert state.
|
||||
warn the user, by having a disposed instance revert to an inert state.
|
||||
</para>
|
||||
</sect1>
|
||||
|
||||
@ -494,8 +492,8 @@ maman_bar_init (MamanBar *self);
|
||||
<title>Non-virtual public methods</title>
|
||||
|
||||
<para>
|
||||
These are the simplest: you want to provide a simple method which
|
||||
can act on your object. All you need to do is to provide a function
|
||||
These are the simplest, providing a simple method which
|
||||
acts on the object. Provide a function
|
||||
prototype in the header and an implementation of that prototype
|
||||
in the source file.
|
||||
<informalexample><programlisting>
|
||||
@ -572,7 +570,7 @@ maman_bar_do_action (MamanBar *self, /* parameters */)
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Please, note that it is possible for you to provide a default
|
||||
It is possible to provide a default
|
||||
implementation for this class method in the object's
|
||||
<function>class_init</function> function: initialize the
|
||||
<function>klass->do_action</function> field to a pointer to the
|
||||
@ -716,17 +714,19 @@ maman_bar_subtype_class_init (MamanBarSubTypeClass *klass)
|
||||
<listitem><para>Parent class A defines a public virtual method named <function>foo</function> and
|
||||
provides a default implementation.</para></listitem>
|
||||
<listitem><para>Child class B re-implements method <function>foo</function>.</para></listitem>
|
||||
<listitem><para>In the method B::foo, the child class B calls its parent class method A::foo.</para></listitem>
|
||||
<listitem><para>B’s implementation of <function>foo</function> calls (‘chains up to’) its parent class A’s implementation of <function>foo</function>.</para></listitem>
|
||||
</itemizedlist>
|
||||
There are various uses to this idiom:
|
||||
There are various uses of this idiom:
|
||||
<itemizedlist>
|
||||
<listitem><para>You need to extend the behaviour of a class without modifying its code. You create
|
||||
a subclass to inherit its implementation, re-implement a public virtual method to modify the behaviour
|
||||
and chain up to ensure that the previous behaviour is not really modified, just extended.
|
||||
</para></listitem>
|
||||
<listitem><para>You need to implement the Chain Of Responsibility pattern: each object of the inheritance
|
||||
<listitem><para>You need to implement the
|
||||
<ulink url="http://en.wikipedia.org/wiki/Chain-of-responsibility_pattern">Chain
|
||||
Of Responsibility pattern</ulink>: each object of the inheritance
|
||||
tree chains up to its parent (typically, at the beginning or the end of the method) to ensure that
|
||||
they each handler is run in turn.</para></listitem>
|
||||
each handler is run in turn.</para></listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
|
||||
@ -737,24 +737,22 @@ maman_bar_subtype_class_init (MamanBarSubTypeClass *klass)
|
||||
<footnote>
|
||||
<para>
|
||||
The <emphasis>original</emphasis> adjective used in this sentence is not innocuous. To fully
|
||||
understand its meaning, you need to recall how class structures are initialized: for each object type,
|
||||
the class structure associated to this object is created by first copying the class structure of its
|
||||
parent type (a simple <function>memcpy</function>) and then by invoking the class_init callback on
|
||||
the resulting class structure. Since the class_init callback is responsible for overwriting the class structure
|
||||
with the user re-implementations of the class methods, we cannot merely use the modified copy of the parent class
|
||||
structure stored in our derived instance. We want to get a copy of the class structure of an instance of the parent
|
||||
class.
|
||||
understand its meaning, recall how class structures are initialized: for each object type,
|
||||
the class structure associated with this object is created by first copying the class structure of its
|
||||
parent type (a simple <function>memcpy</function>) and then by invoking the <function>class_init</function> callback on
|
||||
the resulting class structure. Since the <function>class_init</function> callback is responsible for overwriting the class structure
|
||||
with the user re-implementations of the class methods, the modified copy of the parent class
|
||||
structure stored in the derived instance cannot be used. A copy of the class structure of an instance of the parent
|
||||
class is needed.
|
||||
</para>
|
||||
</footnote>
|
||||
</para>
|
||||
|
||||
<para>The function <function><link linkend="g-type-class-peek-parent">g_type_class_peek_parent</link></function>
|
||||
is used to access the original parent class structure. Its input is a
|
||||
pointer to the class of the derived object and it returns a pointer to
|
||||
the original parent class structure. Instead of using this function
|
||||
directly, though, use the <function>parent_class</function>
|
||||
pointer created and initialized by the <function>G_DEFINE_TYPE_*</function> family of
|
||||
macros, for instance:
|
||||
<para>
|
||||
Use the <function>parent_class</function> pointer created and initialized
|
||||
by the
|
||||
<link linkend="G-DEFINE-TYPE:CAPS"><function>G_DEFINE_TYPE</function></link>
|
||||
family of macros, for instance:
|
||||
<informalexample><programlisting>
|
||||
static void
|
||||
b_method_to_call (B *obj, int a)
|
||||
@ -785,12 +783,13 @@ b_method_to_call (B *obj, int a)
|
||||
<title>Defining interfaces</title>
|
||||
|
||||
<para>
|
||||
The bulk of interface definition has already been shown in <xref linkend="gtype-non-instantiable-classed"/>
|
||||
but I feel it is needed to show exactly how to create an interface.
|
||||
The theory behind how GObject interfaces work is given in
|
||||
<xref linkend="gtype-non-instantiable-classed"/>; this section covers how to
|
||||
define and implement an interface.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
As above, the first step is to get the header right. This interface
|
||||
The first step is to get the header right. This interface
|
||||
defines two methods:
|
||||
<informalexample><programlisting>
|
||||
#ifndef __MAMAN_IBAZ_H__
|
||||
@ -896,56 +895,18 @@ maman_ibaz_do_something (MamanIbaz *self)
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The first step is to define a normal GObject class, like:
|
||||
<informalexample><programlisting>
|
||||
#ifndef __MAMAN_BAZ_H__
|
||||
#define __MAMAN_BAZ_H__
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
#define MAMAN_TYPE_BAZ (maman_baz_get_type ())
|
||||
#define MAMAN_BAZ(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MAMAN_TYPE_BAZ, Mamanbaz))
|
||||
#define MAMAN_IS_BAZ(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MAMAN_TYPE_BAZ))
|
||||
#define MAMAN_BAZ_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MAMAN_TYPE_BAZ, MamanbazClass))
|
||||
#define MAMAN_IS_BAZ_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MAMAN_TYPE_BAZ))
|
||||
#define MAMAN_BAZ_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MAMAN_TYPE_BAZ, MamanbazClass))
|
||||
|
||||
|
||||
typedef struct _MamanBaz MamanBaz;
|
||||
typedef struct _MamanBazClass MamanBazClass;
|
||||
|
||||
struct _MamanBaz
|
||||
{
|
||||
GObject parent_instance;
|
||||
|
||||
gint instance_member;
|
||||
};
|
||||
|
||||
struct _MamanBazClass
|
||||
{
|
||||
GObjectClass parent_class;
|
||||
};
|
||||
|
||||
GType maman_baz_get_type (void);
|
||||
|
||||
#endif /* __MAMAN_BAZ_H__ */
|
||||
</programlisting></informalexample>
|
||||
<!-- Ha ha! "nothing weird or scary". I actually laughed out loud. Oh boy.
|
||||
The fact that we're so intimate with GObject that all this doesn't look
|
||||
wierd, that's the scary thing. :) -->
|
||||
There is clearly nothing specifically weird or scary about this header:
|
||||
it does not define any weird API or derive from a weird type.
|
||||
The first step is to define a normal final GObject class exactly as in
|
||||
<xref linkend="howto-gobject-header"/>.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The second step is to implement <type>MamanBaz</type> by defining
|
||||
its <type>GType</type>. Instead of using
|
||||
<function><link linkend="G-DEFINE-TYPE:CAPS">G_DEFINE_TYPE</link></function>,
|
||||
use
|
||||
it using
|
||||
<function><link linkend="G-DEFINE-TYPE-WITH-CODE:CAPS">G_DEFINE_TYPE_WITH_CODE</link></function>
|
||||
and the
|
||||
and
|
||||
<function><link linkend="G-IMPLEMENT-INTERFACE:CAPS">G_IMPLEMENT_INTERFACE</link></function>
|
||||
macros.
|
||||
instead of
|
||||
<function><link linkend="G-DEFINE-TYPE:CAPS">G_DEFINE_TYPE</link></function>:
|
||||
<informalexample><programlisting>
|
||||
static void maman_ibaz_interface_init (MamanIbazInterface *iface);
|
||||
|
||||
@ -953,8 +914,8 @@ G_DEFINE_TYPE_WITH_CODE (MamanBar, maman_bar, G_TYPE_OBJECT,
|
||||
G_IMPLEMENT_INTERFACE (MAMAN_TYPE_IBAZ,
|
||||
maman_ibaz_interface_init))
|
||||
</programlisting></informalexample>
|
||||
This definition is very much like all the similar functions we looked
|
||||
at previously. The only interface-specific code present here is the call to
|
||||
This definition is very much like all the similar functions seen
|
||||
previously. The only interface-specific code present here is the use of
|
||||
<function><link linkend="G-IMPLEMENT-INTERFACE:CAPS">G_IMPLEMENT_INTERFACE</link></function>.
|
||||
</para>
|
||||
|
||||
@ -1111,14 +1072,9 @@ G_DEFINE_TYPE_WITH_CODE (MamanBar, maman_bar, G_TYPE_OBJECT,
|
||||
|
||||
<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_default_init</function> as shown below:
|
||||
<type>MamanIbaz</type> interface example code above, we only need to
|
||||
add one call in <function>maman_ibaz_default_init</function> as shown
|
||||
below:
|
||||
<informalexample><programlisting>
|
||||
static void
|
||||
maman_ibaz_default_init (MamanIbazInteface *iface)
|
||||
@ -1136,9 +1092,10 @@ maman_ibaz_default_init (MamanIbazInteface *iface)
|
||||
<para>
|
||||
One point worth noting is that the declared property wasn't assigned an
|
||||
integer ID. The reason being that integer IDs of properties are used
|
||||
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.
|
||||
only inside the <function>get_property</function> and
|
||||
<function>set_property</function> virtual methods. Since interfaces
|
||||
declare but do not <emphasis>implement</emphasis> properties, there is no
|
||||
need to assign integer IDs to them.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
@ -1226,10 +1183,10 @@ maman_baz_class_init (MamanBazClass *klass)
|
||||
<title>Overriding interface methods</title>
|
||||
|
||||
<para>
|
||||
If a base class already implements an interface, and in a derived
|
||||
class you wish to implement the same interface overriding only certain
|
||||
methods of that interface, you just reimplement the interface and
|
||||
set only the interface methods you wish to override.
|
||||
If a base class already implements an interface and a derived
|
||||
class needs to implement the same interface but needs to override certain
|
||||
methods, you must reimplement the interface and set only the interface
|
||||
methods which need overriding.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
@ -1283,9 +1240,9 @@ maman_derived_baz_init (MamanDerivedBaz *self)
|
||||
</para>
|
||||
|
||||
<para>
|
||||
If you wish to call the base class implementation of an interface
|
||||
To call the base class implementation of an interface
|
||||
method from an derived class where than interface method has been
|
||||
overridden then you can stash away the pointer returned from
|
||||
overridden, stash away the pointer returned from
|
||||
<function><link linkend="g-type-interface-peek-parent">g_type_interface_peek_parent</link></function>
|
||||
in a global variable.
|
||||
</para>
|
||||
@ -1339,7 +1296,7 @@ maman_derived_baz_init (MamanDerivedBaz *self)
|
||||
<title>How to create and use signals</title>
|
||||
|
||||
<para>
|
||||
The signal system which was built in GType is pretty complex and
|
||||
The signal system in GType is pretty complex and
|
||||
flexible: it is possible for its users to connect at runtime any
|
||||
number of callbacks (implemented in any language for which a binding
|
||||
exists)
|
||||
@ -1350,24 +1307,24 @@ maman_derived_baz_init (MamanDerivedBaz *self)
|
||||
</footnote>
|
||||
to any signal and to stop the emission of any signal at any
|
||||
state of the signal emission process. This flexibility makes it
|
||||
possible to use GSignal for much more than just emit signals which
|
||||
can be received by numerous clients.
|
||||
possible to use GSignal for much more than just emitting signals to
|
||||
multiple clients.
|
||||
</para>
|
||||
|
||||
<sect1 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 MamanFile object, and
|
||||
if this object has a write method, we might wish to be notified
|
||||
whenever someone has changed something via our MamanFile instance.
|
||||
The most basic use of signals is to implement event
|
||||
notification. For example, given a <type>MamanFile</type> object with
|
||||
a <function>write</function> method, a signal could be emitted whenever
|
||||
the file is changed using that method.
|
||||
The code below shows how the user can connect a callback to the
|
||||
"changed" signal.
|
||||
<informalexample><programlisting>
|
||||
file = g_object_new (MAMAN_FILE_TYPE, NULL);
|
||||
|
||||
g_signal_connect (file, "changed", G_CALLBACK (changed_event), NULL);
|
||||
g_signal_connect (file, "changed", (GCallback) changed_event, NULL);
|
||||
|
||||
maman_file_write (file, buffer, strlen (buffer));
|
||||
</programlisting></informalexample>
|
||||
@ -1396,32 +1353,26 @@ maman_file_write (MamanFile *self,
|
||||
const guchar *buffer,
|
||||
gssize size)
|
||||
{
|
||||
g_return_if_fail (MAMAN_IS_FILE (self));
|
||||
g_return_if_fail (buffer != NULL || size == 0);
|
||||
|
||||
/* First write data. */
|
||||
|
||||
/* Then, notify user of data written. */
|
||||
g_signal_emit (self, file_signals[CHANGED], 0 /* details */);
|
||||
}
|
||||
</programlisting></informalexample>
|
||||
As shown above, you can safely set the details parameter to zero if
|
||||
you do not know what it can be used for. For a discussion of what you
|
||||
could used it for, see <xref linkend="signal-detail"/>
|
||||
As shown above, the details parameter can safely be set to zero if no
|
||||
detail needs to be conveyed. For a discussion of what it can be used for,
|
||||
see <xref linkend="signal-detail"/>
|
||||
</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 in front of the
|
||||
double underscore is the type of the return value, while the value(s)
|
||||
after the double underscore denote the parameter types.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The header <filename>gobject/gmarshal.h</filename> defines a set of
|
||||
commonly needed closures that one can use. If you want to have complex
|
||||
marshallers for your signals you should probably use glib-genmarshal
|
||||
to autogenerate them from a file containing their return and
|
||||
parameter types.
|
||||
The C signal marshaller should always be
|
||||
<function>g_cclosure_marshal_generic</function>, which implements generic
|
||||
conversion of arrays of parameters to C callback invocations. GLib used to
|
||||
use type-specific generated marshallers, but that has been deprecated in
|
||||
favour of the generic marshaller.
|
||||
</para>
|
||||
</sect1>
|
||||
</chapter>
|
||||
|
Loading…
Reference in New Issue
Block a user