integrate patch from Stefan Kost
authorMathieu Lacage <mathieu@src.gnome.org>
Thu, 4 Nov 2004 14:52:33 +0000 (14:52 +0000)
committerMathieu Lacage <mathieu@src.gnome.org>
Thu, 4 Nov 2004 14:52:33 +0000 (14:52 +0000)
docs/reference/gobject/tut_gobject.xml
docs/reference/gobject/tut_gtype.xml
docs/reference/gobject/tut_howto.xml

index 0d3fd3a..15c198a 100644 (file)
       <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;
   }
 }
index 59fd5ac..9c81144 100644 (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
index 6b3f63f..be5c35e 100644 (file)
       </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
         conventions: pick one and stick to it.
@@ -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>