Imported Upstream version 2.67.2
[platform/upstream/glib.git] / docs / reference / gobject / tut_gobject.xml
index 4c5e707..0423a38 100644 (file)
@@ -1,18 +1,18 @@
-<?xml version='1.0' encoding="ISO-8859-1"?>
-<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN" 
-               "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" [
+<?xml version='1.0' encoding="UTF-8"?>
+<!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 two previous chapters discussed the details of GLib's Dynamic Type System
-    and its signal control system. The GObject library also contains an implementation
-    for a base fundamental type named <type><link linkend="GObject">GObject</link></type>.
+    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>
-    <type><link linkend="GObject">GObject</link></type> is a fundamental classed instantiable type. It implements:
+    <link linkend="GObject"><type>GObject</type></link> is a fundamental classed instantiatable type. It implements:
     <itemizedlist>
       <listitem><para>Memory management with reference counting</para></listitem>
       <listitem><para>Construction/Destruction of instances</para></listitem>
@@ -20,7 +20,7 @@
       <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 <type><link linkend="GObject">GObject</link></type> which is why it is important to understand
+    inherit from <link linkend="GObject"><type>GObject</type></link> which is why it is important to understand
     the details of how it works.
   </para>
 
     </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>
+      Once all construction operations have been completed and constructor
+      properties set, the constructed class method is called.
     </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
+      Objects which inherit from GObject are allowed to override this
+      constructed class method.
+      The example below shows how <type>ViewerFile</type> overrides the parent's construction process:
+<informalexample><programlisting>
+#define VIEWER_TYPE_FILE viewer_file_get_type ()
+G_DECLARE_FINAL_TYPE (ViewerFile, viewer_file, VIEWER, FILE, GObject)
+
+struct _ViewerFile
 {
   GObject parent_instance;
 
   /* instance members */
+  gchar *filename;
+  guint zoom_level;
 };
 
-struct _MamanBarClass
-{
-  GObjectClass parent_class;
+/* will create viewer_file_get_type and set viewer_file_parent_class */
+G_DEFINE_TYPE (ViewerFile, viewer_file, G_TYPE_OBJECT)
 
-  /* class members */
-};
+static void
+viewer_file_constructed (GObject *obj)
+{
+  /* update the object state depending on constructor properties */
 
-/* will create maman_bar_get_type and set maman_bar_parent_class */
-G_DEFINE_TYPE (MamanBar, maman_bar, G_TYPE_OBJECT);
+  /* Always chain up to the parent constructed function to complete object
+   * initialisation. */
+  G_OBJECT_CLASS (viewer_file_parent_class)-&gt;constructed (obj);
+}
 
-static GObject *
-maman_bar_constructor (GType                  gtype,
-                       guint                  n_properties,
-                       GObjectConstructParam *properties)
+static void
+viewer_file_finalize (GObject *obj)
 {
-  GObject *obj;
-
-  {
-    /* Always chain up to the parent constructor */
-    MamanBarClass *klass;
-    GObjectClass *parent_class;  
-    parent_class = G_OBJECT_CLASS (maman_bar_parent_class);
-    obj = parent_class-&gt;constructor (gtype, n_properties, properties);
-  }
-  
-  /* update the object state depending on constructor properties */
+  ViewerFile *self = VIEWER_FILE (obj);
 
-  return obj;
+  g_free (self->filename);
+
+  /* Always chain up to the parent finalize function to complete object
+   * destruction. */
+  G_OBJECT_CLASS (viewer_file_parent_class)-&gt;finalize (obj);
 }
 
 static void
-maman_bar_class_init (MamanBarClass *klass)
+viewer_file_class_init (ViewerFileClass *klass)
 {
-  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
-  gobject_class-&gt;constructor = maman_bar_constructor;
+  object_class-&gt;constructed = viewer_file_constructed;
+  object_class-&gt;finalize = viewer_file_finalize;
 }
 
 static void
-maman_bar_init (MamanBar *self)
+viewer_file_init (ViewerFile *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>        
+</programlisting></informalexample>
+      If the user instantiates an object <type>ViewerFile</type> with:
+<informalexample><programlisting>
+ViewerFile *file = g_object_new (VIEWER_TYPE_FILE, NULL);
+</programlisting></informalexample>        
       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.
+      <function>viewer_file_class_init</function> function will be invoked
+      after any <function>viewer_file_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>
+      correctly initialized. Here, <function>viewer_file_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>.
+      class' own methods. In the example above, the <literal>constructed</literal>
+      method is the only overridden method: it is set to
+      <function>viewer_file_constructed</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
+      object, if the constructor has been overridden in <function>viewer_file_class_init</function>.
+      Overridden constructors must chain up to their 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>
+      constructor, we can use the <literal>viewer_file_parent_class</literal>
       pointer that has been set up for us by the
-      <literal>G_DEFINE_TYPE</literal> macro.
+      <link linkend="G-DEFINE-TYPE:CAPS"><literal>G_DEFINE_TYPE</literal></link>
+      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 
+      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>
+      which means that the <function>instance_init</function> function is invoked at this point if one
+      was registered. After <function>instance_init</function> returns, the object is fully initialized and should be 
+      ready to have its methods called by the user. 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...
+      to the user's constructor.
     </para>
 
     <para>
@@ -180,7 +168,7 @@ MamanBar *bar = g_object_new (MAMAN_TYPE_BAR, NULL);
           <thead>
             <row>
               <entry>Invocation time</entry>
-              <entry>Function Invoked</entry>
+              <entry>Function invoked</entry>
               <entry>Function's parameters</entry>
               <entry>Remark</entry>
             </row>
@@ -188,17 +176,14 @@ MamanBar *bar = g_object_new (MAMAN_TYPE_BAR, NULL);
           <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>target type's <function>base_init</function> 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>
+                <function>base_init</function> is invoked once for each class structure.</entry>
+              <entry>Never used in practice. Unlikely you will need it.</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>target type's <function>class_init</function> function</entry>
               <entry>On target type's class structure</entry>
               <entry>
                 Here, you should make sure to initialize or override class methods (that is,
@@ -208,39 +193,49 @@ MamanBar *bar = g_object_new (MAMAN_TYPE_BAR, NULL);
             </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>interface's <function>base_init</function> function</entry>
+              <entry>On interface's 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>interface's <function>interface_init</function> function</entry>
+              <entry>On interface's 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 morerows="2">Each call to <function><link linkend="g-object-new">g_object_new</link></function> for target type</entry>
+              <entry>target type's class <function>constructor</function> method: <function>GObjectClass->constructor</function></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
+                If you need to handle construct properties in a custom way, or implement a singleton class, 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>type's <function>instance_init</function> 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 
+              the <function>instance_init</function> 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
+                Provide an <function>instance_init</function> 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>
+            <row>
+              <!--entry>Each call to <function><link linkend="g-object-new">g_object_new</link></function> for target type</entry-->
+              <entry>target type's class <function>constructed</function> method: <function>GObjectClass->constructed</function></entry>
+              <entry>On object's instance</entry>
+              <entry>
+                If you need to perform object initialization steps after all construct properties have been set.
+                This is the final step in the object initialization process, and is only called if the <function>constructor</function>
+                method returned a new object instance (rather than, for example, an existing singleton).
+              </entry>
+            </row>
           </tbody>
         </tgroup>
       </table>
@@ -249,12 +244,12 @@ MamanBar *bar = g_object_new (MAMAN_TYPE_BAR, NULL);
     <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
+      method is called <emphasis>before</emphasis> the GType's <function>instance_init</function>
+      function (since <function><link linkend="g-type-create-instance">g_type_create_instance</link></function> which calls <function>instance_init</function> 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
+      run <emphasis>after</emphasis> GType's <function>instance_init</function> function since the
       user-provided constructor <emphasis>must</emphasis> (you've been warned)
       chain up <emphasis>before</emphasis> doing anything useful.
     </para>
@@ -267,36 +262,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...). The methods which are used to
+      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">
@@ -304,10 +271,16 @@ void g_object_run_dispose         (GObject     *object);
 
       <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 
+        increase and decrease the reference count. These functions are
+        thread-safe.
+        <function><link linkend="g-clear-object">g_clear_object</link></function>
+        is a convenience wrapper around <function>g_object_unref</function>
+        which also clears the pointer passed to it.
+      </para>
+      <para>
+        The reference count is 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.
+        is currently the sole owner of the newly-created reference. (If the object is derived from <link linkend="GInitiallyUnowned"><type>GInitiallyUnowned</type></link>, this reference count is <link linkend="floating-ref">floating</link>.)
         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 
@@ -320,8 +293,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"/> and 
-          <xref linkend="gtype-non-instantiable-classed"/>.
+        will be destroyed as described in <xref linkend="gtype-instantiatable-classed"/> and
+          <xref linkend="gtype-non-instantiatable-classed"/>.
       </para>
 
       <para>
@@ -336,7 +309,7 @@ void g_object_run_dispose         (GObject     *object);
             <thead>
               <row>
                 <entry>Invocation time</entry>
-                <entry>Function Invoked</entry>
+                <entry>Function invoked</entry>
                 <entry>Function's parameters</entry>
                 <entry>Remark</entry>
               </row>
@@ -377,23 +350,23 @@ void g_object_run_dispose         (GObject     *object);
                 <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>interface's <function>interface_finalize</function> function</entry>
+                <entry>On interface's 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>interface's <function>base_finalize</function> function</entry>
+                <entry>On interface's 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>target type's <function>class_finalize</function> function</entry>
                 <entry>On target type's class structure</entry>
                 <entry>Never used in practice. Unlikely you will need it.</entry>
               </row>
@@ -401,9 +374,9 @@ void g_object_run_dispose         (GObject     *object);
                 <!--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>type's <function>base_finalize</function> 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>
+                  <function>base_init</function> is invoked once for each class structure.</entry>
                 <entry>Never used in practice. Unlikely you will need it.</entry>
               </row>
             </tbody>
@@ -417,7 +390,7 @@ void g_object_run_dispose         (GObject     *object);
       <title>Weak References</title>
     
       <para>
-      Weak References are used to monitor object finalization: 
+      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
@@ -431,45 +404,44 @@ void g_object_run_dispose         (GObject     *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>
+        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>
-  
+
+      <para>
+        Similarly, <link linkend="GWeakRef"><type>GWeakRef</type></link> can be
+        used to implement weak references if thread safety is required.
+      </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.
+        without program error 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-dispose">g_object_dispose</link></function> which 
+        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
+        This explains one of the rules about the dispose handler stated earlier:
+        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-dispose">g_object_dispose</link></function> on one of the 
+        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>
   
@@ -483,10 +455,9 @@ void g_object_run_dispose         (GObject     *object);
       </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.
+        The above example, which might seem a bit contrived, can really happen if
+        GObjects are being handled by language bindings — hence the rules for
+        object destruction should be closely followed.
       </para>
     </sect2>
   </sect1>
@@ -497,46 +468,46 @@ void g_object_run_dispose         (GObject     *object);
     <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 <function><link linkend="g-object-class-install-property">g_object_class_install_property</link></function>
-      (implemented in <filename>gobject.c</filename>).
+      is instantiated, the object's <function>class_init</function> handler should be used to register
+      the object's properties with <function><link linkend="g-object-class-install-properties">g_object_class_install_properties</link></function>.
     </para>
   
     <para>
       The best way to understand how object properties work is by looking at a real example
-      on how it is used:
-<programlisting>
+      of how it is used:
+<informalexample><programlisting>
 /************************************************/
 /* Implementation                               */
 /************************************************/
 
-enum
+typedef enum
 {
-  PROP_0,
+  PROP_FILENAME = 1,
+  PROP_ZOOM_LEVEL,
+  N_PROPERTIES
+} ViewerFileProperty;
 
-  PROP_MAMAN_NAME,
-  PROP_PAPA_NUMBER
-};
+static GParamSpec *obj_properties[N_PROPERTIES] = { NULL, };
 
 static void
-maman_bar_set_property (GObject      *object,
-                        guint         property_id,
-                        const GValue *value,
-                        GParamSpec   *pspec)
+viewer_file_set_property (GObject      *object,
+                          guint         property_id,
+                          const GValue *value,
+                          GParamSpec   *pspec)
 {
-  MamanBar *self = MAMAN_BAR (object);
+  ViewerFile *self = VIEWER_FILE (object);
 
-  switch (property_id)
+  switch ((ViewerFileProperty) 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);
+    case PROP_FILENAME:
+      g_free (self-&gt;filename);
+      self-&gt;filename = g_value_dup_string (value);
+      g_print ("filename: %s\n", self-&gt;filename);
       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);
+    case PROP_ZOOM_LEVEL:
+      self-&gt;zoom_level = g_value_get_uint (value);
+      g_print ("zoom level: &percnt;u\n", self-&gt;zoom_level);
       break;
 
     default:
@@ -547,21 +518,21 @@ maman_bar_set_property (GObject      *object,
 }
 
 static void
-maman_bar_get_property (GObject    *object,
-                        guint       property_id,
-                        GValue     *value,
-                        GParamSpec *pspec)
+viewer_file_get_property (GObject    *object,
+                          guint       property_id,
+                          GValue     *value,
+                          GParamSpec *pspec)
 {
-  MamanBar *self = MAMAN_BAR (object);
+  ViewerFile *self = VIEWER_FILE (object);
 
-  switch (property_id)
+  switch ((ViewerFileProperty) property_id)
     {
-    case PROP_MAMAN_NAME:
-      g_value_set_string (value, self-&gt;priv-&gt;name);
+    case PROP_FILENAME:
+      g_value_set_string (value, self-&gt;filename);
       break;
 
-    case PROP_PAPA_NUMBER:
-      g_value_set_uchar (value, self-&gt;priv-&gt;papa_number);
+    case PROP_ZOOM_LEVEL:
+      g_value_set_uint (value, self-&gt;zoom_level);
       break;
 
     default:
@@ -572,66 +543,65 @@ maman_bar_get_property (GObject    *object,
 }
 
 static void
-maman_bar_class_init (MamanBarClass *klass)
+viewer_file_class_init (ViewerFileClass *klass)
 {
-  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
-  GParamSpec *pspec;
-
-  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",
-                               "Set maman's name",
-                               "no-name-set" /* default value */,
-                               G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
-  g_object_class_install_property (gobject_class,
-                                   PROP_MAMAN_NAME,
-                                   pspec);
-
-  pspec = g_param_spec_uchar ("papa-number",
-                              "Number of current Papa",
-                              "Set/Get papa's number",
-                              0  /* minimum value */,
-                              10 /* maximum value */,
-                              2  /* default value */,
-                              G_PARAM_READWRITE);
-  g_object_class_install_property (gobject_class,
-                                   PROP_PAPA_NUMBER,
-                                   pspec);
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class-&gt;set_property = viewer_file_set_property;
+  object_class-&gt;get_property = viewer_file_get_property;
+
+  obj_properties[PROP_FILENAME] =
+    g_param_spec_string ("filename",
+                         "Filename",
+                         "Name of the file to load and display from.",
+                         NULL  /* default value */,
+                         G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
+
+  obj_properties[PROP_ZOOM_LEVEL] =
+    g_param_spec_uint ("zoom-level",
+                       "Zoom level",
+                       "Zoom level to view the file at.",
+                       0  /* minimum value */,
+                       10 /* maximum value */,
+                       2  /* default value */,
+                       G_PARAM_READWRITE);
+
+  g_object_class_install_properties (object_class,
+                                     N_PROPERTIES,
+                                     obj_properties);
 }
 
 /************************************************/
 /* Use                                          */
 /************************************************/
 
-GObject *bar;
-GValue val = { 0, };
+ViewerFile *file;
+GValue val = G_VALUE_INIT;
 
-bar = g_object_new (MAMAN_TYPE_SUBBAR, NULL);
+file = g_object_new (VIEWER_TYPE_FILE, NULL);
 
-g_value_init (&amp;val, G_TYPE_CHAR);
+g_value_init (&amp;val, G_TYPE_UINT);
 g_value_set_char (&amp;val, 11);
 
-g_object_set_property (G_OBJECT (bar), "papa-number", &amp;val);
+g_object_set_property (G_OBJECT (file), "zoom-level", &amp;val);
 
 g_value_unset (&amp;val);
-</programlisting>
-      The client code just above looks simple but a lot of things happen under the hood:
+</programlisting></informalexample>
+      The client code above looks simple but a lot of things happen under the hood:
     </para>
   
     <para>
       <function><link linkend="g-object-set-property">g_object_set_property</link></function> first ensures a property
-      with this name was registered in bar's class_init handler. If so, it calls
-      <function><link linkend="object-set-property">object_set_property</link></function> which first walks the class hierarchy,
-      from bottom, most derived type, to top, fundamental type to find the class
-      which registered that property. It then tries to convert the user-provided GValue
-      into a GValue whose type is that of the associated property.
+      with this name was registered in <emphasis>file</emphasis>'s <function>class_init</function> handler. If so it walks the class hierarchy,
+      from bottom-most most-derived type, to top-most fundamental type to find the class
+      which registered that property. It then tries to convert the user-provided
+      <link linkend="GValue"><type>GValue</type></link>
+      into a <type>GValue</type> whose type is that of the associated property.
     </para>
-  
+
     <para>
-      If the user provides a signed char GValue, as is shown
-      here, and if the object's property was registered as an unsigned int, 
+      If the user provides a <type>signed char</type> <type>GValue</type>, as is shown
+      here, and if the object's property was registered as an <type>unsigned int</type>,
       <function><link linkend="g-value-transform">g_value_transform</link></function> will try to transform the input signed char into
       an unsigned int. Of course, the success of the transformation depends on the availability
       of the required transform function. In practice, there will almost always be a transformation
@@ -644,27 +614,29 @@ g_value_unset (&amp;val);
     </para>
   
     <para>
-      After transformation, the <type><link linkend="GValue">GValue</link></type> is validated by 
+      After transformation, the <link linkend="GValue"><type>GValue</type></link> is validated by 
       <function><link linkend="g-param-value-validate">g_param_value_validate</link></function> which makes sure the user's
-      data stored in the <type><link linkend="GValue">GValue</link></type> matches the characteristics specified by
-      the property's <type><link linkend="GParamSpec">GParamSpec</link></type>.  Here, the <type><link linkend="GParamSpec">GParamSpec</link></type> we 
-      provided in class_init has a validation function which makes sure that the GValue
+      data stored in the <link linkend="GValue"><type>GValue</type></link> matches the characteristics specified by
+      the property's <link linkend="GParamSpec"><type>GParamSpec</type></link>.
+      Here, the <link linkend="GParamSpec"><type>GParamSpec</type></link> we 
+      provided in <function>class_init</function> has a validation function which makes sure that the GValue
       contains a value which respects the minimum and maximum bounds of the 
-      <type><link linkend="GParamSpec">GParamSpec</link></type>. In the example above, the client's GValue does not
+      <link linkend="GParamSpec"><type>GParamSpec</type></link>. In the example above, the client's GValue does not
       respect these constraints (it is set to 11, while the maximum is 10). As such, the
       <function><link linkend="g-object-set-property">g_object_set_property</link></function> function will return with an error.
     </para>
   
     <para>
       If the user's GValue had been set to a valid value, <function><link linkend="g-object-set-property">g_object_set_property</link></function>
-      would have proceeded with calling the object's set_property class method. Here, since our
-      implementation of Foo did override this method, the code path would jump to
-      <function>foo_set_property</function> after having retrieved from the 
-      <type><link linkend="GParamSpec">GParamSpec</link></type> the <emphasis>param_id</emphasis>
+      would have proceeded with calling the object's
+      <function>set_property</function> class method. Here, since our
+      implementation of <type>ViewerFile</type> did override this method, execution would jump to
+      <function>viewer_file_set_property</function> after having retrieved from the 
+      <link linkend="GParamSpec"><type>GParamSpec</type></link> the <emphasis>param_id</emphasis>
       <footnote>
         <para>
           It should be noted that the param_id used here need only to uniquely identify each 
-          <type><link linkend="GParamSpec">GParamSpec</link></type> within the <type><link linkend="FooClass">FooClass</link></type> such that the switch
+          <link linkend="GParamSpec"><type>GParamSpec</type></link> within the <type>ViewerFileClass</type> such that the switch
           used in the set and get methods actually works. Of course, this locally-unique 
           integer is purely an optimization: it would have been possible to use a set of 
           <emphasis>if (strcmp (a, b) == 0) {} else if (strcmp (a, b) == 0) {}</emphasis> statements.
@@ -675,20 +647,23 @@ g_value_unset (&amp;val);
     </para>
   
     <para>
-      Once the property has been set by the object's set_property class method, the code path
-      returns to <function><link linkend="g-object-set-property">g_object_set_property</link></function> which calls 
-      <function><link linkend="g-object-notify-queue-thaw">g_object_notify_queue_thaw</link></function>. This function makes sure that
+      Once the property has been set by the object's
+      <function>set_property</function> class method, execution
+      returns to <function><link linkend="g-object-set-property">g_object_set_property</link></function> which makes sure that
       the "notify" signal is emitted on the object's instance with the changed property as
       parameter unless notifications were frozen by <function><link linkend="g-object-freeze-notify">g_object_freeze_notify</link></function>.
     </para>
   
     <para>
       <function><link linkend="g-object-thaw-notify">g_object_thaw_notify</link></function> can be used to re-enable notification of 
-      property modifications through the "notify" signal. It is important to remember that
+      property modifications through the
+      <link linkend="GObject-notify"><type>“notify”</type></link> signal. It is important to remember that
       even if properties are changed while property change notification is frozen, the "notify"
       signal will be emitted once for each of these changed properties as soon as the property
-      change notification is thawed: no property change is lost for the "notify" signal. Signal
-      can only be delayed by the notification freezing mechanism.
+      change notification is thawed: no property change is lost for the "notify"
+      signal, although multiple notifications for a single property are
+      compressed. Signals can only be delayed by the notification freezing
+      mechanism.
     </para>
     
     <para>
@@ -704,41 +679,44 @@ g_value_unset (&amp;val);
   
       <para>
         It is interesting to note that the <function><link linkend="g-object-set">g_object_set</link></function> and 
-        <function><link linkend="g-object-set-valist">g_object_set_valist</link></function> (vararg version) functions can be used to set
+        <function><link linkend="g-object-set-valist">g_object_set_valist</link></function> (variadic version) functions can be used to set
         multiple properties at once. The client code shown above can then be re-written as:
-<programlisting>
-MamanBar *foo;
-foo = /* */;
-g_object_set (G_OBJECT (foo),
-              "papa-number", 2
-              "maman-name", "test", 
+<informalexample><programlisting>
+ViewerFile *file;
+file = /* */;
+g_object_set (G_OBJECT (file),
+              "zoom-level", 6
+              "filename", "~/some-file.txt", 
               NULL);
-</programlisting>
+</programlisting></informalexample>
         This saves us from managing the GValues that we were needing to handle when using
         <function><link linkend="g-object-set-property">g_object_set_property</link></function>.
         The code above will trigger one notify signal emission for each property modified.
       </para>
     
       <para>
-        Of course, the _get versions are also available: <function><link linkend="g-object-get">g_object_get</link></function>
-        and <function><link linkend="g-object-get-valist">g_object_get_valist</link></function> (vararg version) can be used to get numerous
+        Equivalent <function>_get</function> versions are also available:
+        <function><link linkend="g-object-get">g_object_get</link></function>
+        and <function><link linkend="g-object-get-valist">g_object_get_valist</link></function> (variadic version) can be used to get numerous
         properties at once.
       </para>
       
       <para>
-        These high level functions have one drawback - they don't provide a return result.
+        These high level functions have one drawback — they don't provide a return value.
         One should pay attention to the argument types and ranges when using them.
-        A known source of errors is to e.g. pass a gfloat instead of a gdouble and thus
-        shifting all subsequent parameters by four bytes. Also forgetting the terminating
-        NULL will lead to unexpected behaviour.
+        A known source of errors is to pass a different type from what the
+        property expects; for instance, passing an integer when the property
+        expects a floating point value and thus shifting all subsequent parameters
+        by some number of bytes. Also forgetting the terminating
+        <literal>NULL</literal> will lead to undefined behaviour.
       </para>
     
       <para>
-        Really attentive readers now understand how <function><link linkend="g-object-new">g_object_new</link></function>,
+        This explains how <function><link linkend="g-object-new">g_object_new</link></function>,
         <function><link linkend="g-object-newv">g_object_newv</link></function> and <function><link linkend="g-object-new-valist">g_object_new_valist</link></function> 
         work: they parse the user-provided variable number of parameters and invoke
         <function><link linkend="g-object-set">g_object_set</link></function> on the parameters only after the object has been successfully constructed.
-        Of course, the "notify" signal will be emitted for each property set.
+        The "notify" signal will be emitted for each property set.
       </para>
     
     </sect2>