added support for a "default vtable" per interface, that interface vtables
authorTim Janik <timj@gtk.org>
Tue, 2 Sep 2003 17:57:22 +0000 (17:57 +0000)
committerTim Janik <timj@src.gnome.org>
Tue, 2 Sep 2003 17:57:22 +0000 (17:57 +0000)
Tue Sep  2 19:37:21 2003  Tim Janik  <timj@gtk.org>

        * gtype.[hc]: added support for a "default vtable" per interface,
        that interface vtables are initialized from.
        the default vtable is initialized and finalized through class_init,
        class_finalize and class_data from the interfaces GTypeInfo struct.
        (type_data_last_unref_Wm): unload child plugin before unreffing
        parent type.

        testifaceinit.c: minor fixups. fixed up base_init() assertions, since
        with a default vtable, base_init() may be called multiple times.
        added default initializer to iface1.

docs/reference/gobject/tmpl/enumerations_flags.sgml
docs/reference/gobject/tmpl/gtype.sgml
docs/reference/gobject/tmpl/param_value_types.sgml
gobject/ChangeLog
gobject/gtype.c
gobject/gtype.h
gobject/testifaceinit.c
tests/gobject/ifaceinit.c

index 02d7871..6f9462f 100644 (file)
@@ -154,7 +154,7 @@ Looks up a #GEnumValue by name.
 @enum_class: a #GEnumClass
 @name: the name to look up
 @Returns: the #GEnumValue with name @name, or %NULL if the enumeration doesn'
-t have a member with that name 
+t have a member with that name
 
 
 <!-- ##### FUNCTION g_enum_get_value_by_nick ##### -->
@@ -165,7 +165,7 @@ Looks up a #GEnumValue by nickname.
 @enum_class: a #GEnumClass
 @nick: the nickname to look up
 @Returns: the #GEnumValue with nickname @nick, or %NULL if the enumeration doesn'
-t have a member with that nickname 
+t have a member with that nickname
 
 
 <!-- ##### FUNCTION g_flags_get_first_value ##### -->
@@ -174,7 +174,7 @@ Returns the first #GFlagsValue which is set in @value.
 </para>
 
 @flags_class: a #GFlagsClass
-@value: the value 
+@value: the value
 @Returns: the first #GFlagsValue which is set in @value, or %NULL if none is set
 
 
@@ -186,7 +186,7 @@ Looks up a #GFlagsValue by name.
 @flags_class: a #GFlagsClass
 @name: the name to look up
 @Returns: the #GFlagsValue with name @name, or %NULL if there is no flag with
-that name 
+that name
 
 
 <!-- ##### FUNCTION g_flags_get_value_by_nick ##### -->
@@ -197,7 +197,7 @@ Looks up a #GFlagsValue by nickname.
 @flags_class: a #GFlagsClass
 @nick: the nickname to look up
 @Returns: the #GFlagsValue with nickname @nick, or %NULL if there is no flag
-with that nickname 
+with that nickname
 
 
 <!-- ##### FUNCTION g_enum_register_static ##### -->
index eddb371..605a11f 100644 (file)
@@ -473,6 +473,7 @@ class_init function with g_type_class_add_private().
 @g_type: the type identifying which private data to retrieve.
 @c_type: The C type for the private structure.
 
+
 <!-- ##### MACRO G_TYPE_CHECK_INSTANCE ##### -->
 <para>
 
@@ -746,6 +747,7 @@ my_object_get_some_field (MyObject *my_object)
 @g_class: class structure for an instantiatable type
 @private_size: size of private structure.
 
+
 <!-- ##### FUNCTION g_type_interface_peek ##### -->
 <para>
 Returns the #GTypeInterface structure of an interface to which the passed in 
@@ -1469,3 +1471,6 @@ mode: sgml
 sgml-parent-document: ("../gobject-docs.sgml" "book" "refsect2" "")
 End:
 -->
+
+
+
index da9afc5..157a6c6 100644 (file)
@@ -914,7 +914,7 @@ See g_param_spec_internal() for details on property names.
 @name:          canonical name of the property specified
 @nick:          nick name for the property specified
 @blurb:         description of the property specified
-@enum_type:     a #GType derived from %G_TYPE_ENUM 
+@enum_type:     a #GType derived from %G_TYPE_ENUM
 @default_value: default value for the property specified
 @flags:         flags for the property specified
 @Returns:  a newly created parameter specification
@@ -979,7 +979,6 @@ properties.
 @flags_class: the #GFlagsClass for the flags
 @default_value:   default value for the property specified
 
-
 <!-- ##### FUNCTION g_param_spec_flags ##### -->
 <para>
 Creates a new #GParamSpecEnum instance specifying a %G_TYPE_FLAGS
@@ -992,7 +991,7 @@ See g_param_spec_internal() for details on property names.
 @name:          canonical name of the property specified
 @nick:          nick name for the property specified
 @blurb:         description of the property specified
-@flags_type:     a #GType derived from %G_TYPE_FLAGS 
+@flags_type:     a #GType derived from %G_TYPE_FLAGS
 @default_value: default value for the property specified
 @flags:         flags for the property specified
 @Returns:  a newly created parameter specification
@@ -1110,8 +1109,8 @@ This is an internal function introduced mainly for C marshallers.
 
 @value:   a valid #GValue of type %G_TYPE_STRING
 @v_string: duplicated unowned string to be set
-
-@value:  a valid #GValue 
+<!-- # Unused Parameters # -->
+@value:  a valid #GValue
 @v_string: string to be set
 
 
@@ -1172,7 +1171,6 @@ properties.
 
 @parent_instance: private #GParamSpec portion
 
-
 <!-- ##### FUNCTION g_param_spec_param ##### -->
 <para>
 Creates a new #GParamSpecParam instance specifying a %G_TYPE_PARAM
@@ -1186,9 +1184,10 @@ See g_param_spec_internal() for details on property names.
 @nick:          nick name for the property specified
 @blurb:         description of the property specified
 @param_type:    a #GType derived from %G_TYPE_PARAM
-@default_value: default value for the property specified
 @flags:         flags for the property specified
 @Returns:  a newly created parameter specification
+<!-- # Unused Parameters # -->
+@default_value: default value for the property specified
 
 
 <!-- ##### FUNCTION g_value_set_param ##### -->
@@ -1257,6 +1256,7 @@ The #GType of #GParamSpecBoxed.
 </para>
 
 
+
 <!-- ##### STRUCT GParamSpecBoxed ##### -->
 <para>
 A #GParamSpec derived structure that contains the meta data for boxed properties.
@@ -1368,7 +1368,6 @@ A #GParamSpec derived structure that contains the meta data for pointer properti
 
 @parent_instance: private #GParamSpec portion
 
-
 <!-- ##### FUNCTION g_param_spec_pointer ##### -->
 <para>
 Creates a new #GParamSpecPoiner instance specifying a pointer property.
@@ -1440,7 +1439,6 @@ A #GParamSpec derived structure that contains the meta data for object propertie
 
 @parent_instance: private #GParamSpec portion
 
-
 <!-- ##### FUNCTION g_param_spec_object ##### -->
 <para>
 Creates a new #GParamSpecBoxed instance specifying a %G_TYPE_OBJECT 
index 6d3e511..a34f2ea 100644 (file)
@@ -1,3 +1,16 @@
+Tue Sep  2 19:37:21 2003  Tim Janik  <timj@gtk.org>
+
+       * gtype.[hc]: added support for a "default vtable" per interface,
+       that interface vtables are initialized from.
+       the default vtable is initialized and finalized through class_init,
+       class_finalize and class_data from the interfaces GTypeInfo struct.
+       (type_data_last_unref_Wm): unload child plugin before unreffing
+       parent type.
+
+       testifaceinit.c: minor fixups. fixed up base_init() assertions, since
+       with a default vtable, base_init() may be called multiple times.
+       added default initializer to iface1.
+
 Tue Sep  2 14:53:41 2003  Tim Janik  <timj@gtk.org>
 
        * gobject-query.c (main): fix iterating over fundamental types.
index 46a5c8b..2c78542 100644 (file)
@@ -241,6 +241,10 @@ struct _IFaceData
   guint16            vtable_size;
   GBaseInitFunc      vtable_init_base;
   GBaseFinalizeFunc  vtable_finalize_base;
+  GClassInitFunc     dflt_init;
+  GClassFinalizeFunc dflt_finalize;
+  gconstpointer      dflt_data;
+  gpointer           dflt_vtable;
 };
 struct _ClassData
 {
@@ -736,9 +740,9 @@ check_type_info_I (TypeNode        *pnode,
       return FALSE;
     }
   /* check class & interface members */
-  if (!(finfo->type_flags & G_TYPE_FLAG_CLASSED) &&
+  if (!((finfo->type_flags & G_TYPE_FLAG_CLASSED) || is_interface) &&
       (info->class_init || info->class_finalize || info->class_data ||
-       (!is_interface && (info->class_size || info->base_init || info->base_finalize))))
+       info->class_size || info->base_init || info->base_finalize))
     {
       if (pnode)
        g_warning ("cannot create class for `%s', derived from non-classed parent type `%s'",
@@ -985,6 +989,10 @@ type_data_make_W (TypeNode              *node,
       data->iface.vtable_size = info->class_size;
       data->iface.vtable_init_base = info->base_init;
       data->iface.vtable_finalize_base = info->base_finalize;
+      data->iface.dflt_init = info->class_init;
+      data->iface.dflt_finalize = info->class_finalize;
+      data->iface.dflt_data = info->class_data;
+      data->iface.dflt_vtable = NULL;
     }
   else
     {
@@ -1581,6 +1589,31 @@ g_type_free_instance (GTypeInstance *instance)
   g_type_class_unref (class);
 }
 
+static void
+type_iface_ensure_dflt_vtable_Wm (TypeNode *iface)
+{
+  g_assert (iface->data);
+
+  if (!iface->data->iface.dflt_vtable)
+    {
+      GTypeInterface *vtable = g_malloc0 (iface->data->iface.vtable_size);
+      iface->data->iface.dflt_vtable = vtable;
+      vtable->g_type = NODE_TYPE (iface);
+      vtable->g_instance_type = 0;
+      if (iface->data->iface.vtable_init_base ||
+          iface->data->iface.dflt_init)
+        {
+          G_WRITE_UNLOCK (&type_rw_lock);
+          if (iface->data->iface.vtable_init_base)
+            iface->data->iface.vtable_init_base (vtable);
+          if (iface->data->iface.dflt_init)
+            iface->data->iface.dflt_init (vtable, (gpointer) iface->data->iface.dflt_data);
+          G_WRITE_LOCK (&type_rw_lock);
+        }
+    }
+}
+
+
 /* This is called to allocate and do the first part of initializing
  * the interface vtable; type_iface_vtable_iface_init_Wm() does the remainder.
  *
@@ -1593,7 +1626,7 @@ static gboolean
 type_iface_vtable_base_init_Wm (TypeNode *iface,
                                TypeNode *node)
 {
-  IFaceEntry *entry = type_lookup_iface_entry_L (node, iface);
+  IFaceEntry *entry;
   IFaceHolder *iholder;
   GTypeInterface *vtable = NULL;
   TypeNode *pnode;
@@ -1602,7 +1635,11 @@ type_iface_vtable_base_init_Wm (TypeNode *iface,
   iholder = type_iface_retrieve_holder_info_Wm (iface, NODE_TYPE (node), TRUE);
   if (!iholder)
     return FALSE;      /* we don't modify write lock upon FALSE */
-  
+
+  type_iface_ensure_dflt_vtable_Wm (iface);
+
+  entry = type_lookup_iface_entry_L (node, iface);
+
   g_assert (iface->data && entry && entry->vtable == NULL && iholder && iholder->info);
   
   pnode = lookup_type_node_I (NODE_PARENT_TYPE (node));
@@ -1614,7 +1651,7 @@ type_iface_vtable_base_init_Wm (TypeNode *iface,
        vtable = g_memdup (pentry->vtable, iface->data->iface.vtable_size);
     }
   if (!vtable)
-    vtable = g_malloc0 (iface->data->iface.vtable_size);
+    vtable = g_memdup (iface->data->iface.dflt_vtable, iface->data->iface.vtable_size);
   entry->vtable = vtable;
   vtable->g_type = NODE_TYPE (iface);
   vtable->g_instance_type = NODE_TYPE (node);
@@ -1622,8 +1659,7 @@ type_iface_vtable_base_init_Wm (TypeNode *iface,
   if (iface->data->iface.vtable_init_base)
     {
       G_WRITE_UNLOCK (&type_rw_lock);
-      if (iface->data->iface.vtable_init_base)
-       iface->data->iface.vtable_init_base (vtable);
+      iface->data->iface.vtable_init_base (vtable);
       G_WRITE_LOCK (&type_rw_lock);
     }
   return TRUE; /* initialized the vtable */
@@ -1930,7 +1966,6 @@ type_data_finalize_class_U (TypeNode  *node,
     if (bnode->data->class.class_finalize_base)
       bnode->data->class.class_finalize_base (class);
   
-  class->g_type = 0;
   g_free (cdata->class);
 }
 
@@ -1999,22 +2034,37 @@ type_data_last_unref_Wm (GType    type,
          type_data_finalize_class_U (node, &tdata->class);
          G_WRITE_LOCK (&type_rw_lock);
        }
+      else if (NODE_IS_IFACE (node) && tdata->iface.dflt_vtable)
+        {
+          node->mutatable_check_cache = FALSE;
+          node->data = NULL;
+          if (tdata->iface.dflt_finalize || tdata->iface.vtable_finalize_base)
+            {
+              G_WRITE_UNLOCK (&type_rw_lock);
+              if (tdata->iface.dflt_finalize)
+                tdata->iface.dflt_finalize (tdata->iface.dflt_vtable, (gpointer) tdata->iface.dflt_data);
+              if (tdata->iface.vtable_finalize_base)
+                tdata->iface.vtable_finalize_base (tdata->iface.dflt_vtable);
+              G_WRITE_LOCK (&type_rw_lock);
+            }
+          g_free (tdata->iface.dflt_vtable);
+        }
       else
-       {
-         node->mutatable_check_cache = FALSE;
-         node->data = NULL;
-       }
-      
-      /* freeing tdata->common.value_table and its contents is taking care of
+        {
+          node->mutatable_check_cache = FALSE;
+          node->data = NULL;
+        }
+
+      /* freeing tdata->common.value_table and its contents is taken care of
        * by allocating it in one chunk with tdata
        */
       g_free (tdata);
       
-      if (ptype)
-       type_data_unref_Wm (lookup_type_node_I (ptype), FALSE);
       G_WRITE_UNLOCK (&type_rw_lock);
       g_type_plugin_unuse (node->plugin);
       G_WRITE_LOCK (&type_rw_lock);
+      if (ptype)
+       type_data_unref_Wm (lookup_type_node_I (ptype), FALSE);
     }
 }
 
index 5aff33e..c762c80 100644 (file)
@@ -234,7 +234,7 @@ struct _GTypeInfo
   GBaseInitFunc          base_init;
   GBaseFinalizeFunc      base_finalize;
   
-  /* classed types, instantiated types */
+  /* interface types, classed types, instantiated types */
   GClassInitFunc         class_init;
   GClassFinalizeFunc     class_finalize;
   gconstpointer          class_data;
index 94154ce..c25bb29 100644 (file)
@@ -28,7 +28,7 @@
  * The test defines 5 interfaces:
  * 
  * - TestIface1 is added before the class is initialized
- * - TestIface2 is added in base_object_baes_init()
+ * - TestIface2 is added in base_object_base_init()
  * - TestIface3 is added in test_iface1_base_init()
  * - TestIface4 is added in test_object_class_init()
  * - TestIface5 is added in test_object_test_iface1_init()
@@ -66,7 +66,7 @@ prefix ## _get_type (void)                                    \
   return object_type;                                          \
 }
 
-#define DEFINE_IFACE(name, prefix, base_init)                  \
+#define DEFINE_IFACE(name, prefix, base_init, dflt_init)       \
 GType                                                          \
 prefix ## _get_type (void)                                     \
 {                                                              \
@@ -79,6 +79,7 @@ prefix ## _get_type (void)                                    \
        sizeof (name ## Class),                                 \
        (GBaseInitFunc) base_init,                              \
        (GBaseFinalizeFunc) NULL,                               \
+       (GClassInitFunc) dflt_init,                             \
       };                                                       \
                                                                \
       iface_type = g_type_register_static (G_TYPE_INTERFACE,   \
@@ -98,6 +99,7 @@ struct _TestIfaceClass
   GTypeInterface base_iface;
   guint val;
   guint base_val;
+  guint default_val;
 };
 
 #define TEST_TYPE_IFACE1           (test_iface1_get_type ())
@@ -105,9 +107,10 @@ struct _TestIfaceClass
 typedef struct _TestIface1      TestIface1;
 typedef struct _TestIfaceClass  TestIface1Class;
 
-static void test_iface1_base_init (TestIface1Class *iface);
+static void test_iface1_base_init    (TestIface1Class *iface);
+static void test_iface1_default_init (TestIface1Class *iface, gpointer class_data);
 
-static DEFINE_IFACE(TestIface1, test_iface1, test_iface1_base_init)
+static DEFINE_IFACE(TestIface1, test_iface1, test_iface1_base_init, test_iface1_default_init)
 
 #define TEST_TYPE_IFACE2           (test_iface2_get_type ())
 #define TEST_IFACE2_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), TEST_TYPE_IFACE2, TestIface2Class))
@@ -116,7 +119,7 @@ typedef struct _TestIfaceClass  TestIface2Class;
 
 static void test_iface2_base_init (TestIface2Class *iface);
 
-static DEFINE_IFACE(TestIface2, test_iface2, test_iface2_base_init)
+static DEFINE_IFACE(TestIface2, test_iface2, test_iface2_base_init, NULL)
 
 #define TEST_TYPE_IFACE3           (test_iface3_get_type ())
 #define TEST_IFACE3_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), TEST_TYPE_IFACE3, TestIface3Class))
@@ -125,7 +128,7 @@ typedef struct _TestIfaceClass  TestIface3Class;
 
 static void  test_iface3_base_init (TestIface3Class *iface);
 
-static DEFINE_IFACE(TestIface3, test_iface3, test_iface3_base_init)
+static DEFINE_IFACE(TestIface3, test_iface3, test_iface3_base_init, NULL)
 
 #define TEST_TYPE_IFACE4           (test_iface4_get_type ())
 #define TEST_IFACE4_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), TEST_TYPE_IFACE4, TestIface4Class))
@@ -134,7 +137,7 @@ typedef struct _TestIfaceClass  TestIface4Class;
 
 static void  test_iface4_base_init (TestIface4Class *iface);
 
-static DEFINE_IFACE(TestIface4, test_iface4, test_iface4_base_init)
+static DEFINE_IFACE(TestIface4, test_iface4, test_iface4_base_init, NULL)
 
 #define TEST_TYPE_IFACE5           (test_iface5_get_type ())
 #define TEST_IFACE5_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), TEST_TYPE_IFACE5, TestIface5Class))
@@ -143,7 +146,7 @@ typedef struct _TestIfaceClass  TestIface5Class;
 
 static void  test_iface5_base_init (TestIface5Class *iface);
 
-static DEFINE_IFACE(TestIface5, test_iface5, test_iface5_base_init)
+static DEFINE_IFACE(TestIface5, test_iface5, test_iface5_base_init, NULL)
 
 #define TEST_TYPE_IFACE6           (test_iface6_get_type ())
 #define TEST_IFACE6_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), TEST_TYPE_IFACE6, TestIface6Class))
@@ -152,7 +155,7 @@ typedef struct _TestIfaceClass  TestIface6Class;
 
 static void  test_iface6_base_init (TestIface6Class *iface);
 
-static DEFINE_IFACE(TestIface6, test_iface6, test_iface6_base_init)
+static DEFINE_IFACE(TestIface6, test_iface6, test_iface6_base_init, NULL)
 
 /*
  * BaseObject, a parent class for TestObject
@@ -187,9 +190,20 @@ struct _TestObjectClass
 };
 
 #define TEST_CALLED_ONCE() G_STMT_START { \
-  static gboolean called = FALSE;         \
-  g_assert (!called);                     \
-  called = TRUE;                          \
+  static gboolean called = 0;           \
+  g_assert (!called);                   \
+  called = TRUE;                        \
+} G_STMT_END
+
+#define CHECK_IFACE_TWICE(iface) G_STMT_START {                                 \
+  static guint n_calls = 0;                                                     \
+  n_calls++;                                                                    \
+  g_assert (n_calls <= 2);                                                      \
+  g_assert (G_TYPE_IS_INTERFACE (((GTypeInterface*) iface)->g_type));           \
+  if (n_calls == 1)                                                             \
+    g_assert (((GTypeInterface*) iface)->g_instance_type == 0);                 \
+  else                                                                          \
+    g_assert (G_TYPE_IS_OBJECT (((GTypeInterface*) iface)->g_instance_type));   \
 } G_STMT_END
 
 #define ADD_IFACE(n)  G_STMT_START {                           \
@@ -219,12 +233,15 @@ static void
 test_object_test_iface1_init (TestIface1Class *iface)
 {
   TEST_CALLED_ONCE();
-  
+
+  g_assert (iface->default_val == 0x111111);
+
   iface->val = 0x10001;
 
   ADD_IFACE(5);
 
   iface1 = TRUE;
+  g_print ("interface1 object initializer\n");
 }
 
 static void
@@ -278,21 +295,48 @@ test_object_test_iface6_init (TestIface6Class *iface)
 }
 
 static void
-test_iface1_base_init (TestIface1Class *iface)
+test_iface1_default_init (TestIface1Class *iface,
+                          gpointer         class_data)
 {
   TEST_CALLED_ONCE();
+  g_assert (iface->base_iface.g_type == TEST_TYPE_IFACE1);
+  g_assert (iface->base_iface.g_instance_type == 0);
+  g_assert (iface->base_val == 0x110011);
+  g_assert (iface->val == 0);
+  g_assert (iface->default_val == 0);
+  iface->default_val = 0x111111;
+  g_print ("interface1 default initializer\n");
+}
 
-  iface->base_val = 0x110011;
-  
-  ADD_IFACE(3);
+static void
+test_iface1_base_init (TestIface1Class *iface)
+{
+  static guint n_calls = 0;
+  n_calls++;
+  g_assert (n_calls <= 2);
+
+  if (n_calls == 1)
+    {
+      iface->base_val = 0x110011;
+      g_assert (iface->default_val == 0);
+    }
+  else
+    {
+      g_assert (iface->base_val == 0x110011);
+      g_assert (iface->default_val == 0x111111);
+    }
+
+  if (n_calls == 1)
+    ADD_IFACE(3);
   
   base1 = TRUE;
+  g_print ("interface1 base initializer\n");
 }
 
 static void
 test_iface2_base_init (TestIface2Class *iface)
 {
-  TEST_CALLED_ONCE();
+  CHECK_IFACE_TWICE (iface);
 
   iface->base_val = 0x220022;
   
@@ -302,7 +346,7 @@ test_iface2_base_init (TestIface2Class *iface)
 static void
 test_iface3_base_init (TestIface3Class *iface)
 {
-  TEST_CALLED_ONCE();
+  CHECK_IFACE_TWICE (iface);
 
   iface->base_val = 0x330033;
   
@@ -312,7 +356,7 @@ test_iface3_base_init (TestIface3Class *iface)
 static void
 test_iface4_base_init (TestIface4Class *iface)
 {
-  TEST_CALLED_ONCE();
+  CHECK_IFACE_TWICE (iface);
 
   iface->base_val = 0x440044;
 
@@ -322,7 +366,7 @@ test_iface4_base_init (TestIface4Class *iface)
 static void
 test_iface5_base_init (TestIface5Class *iface)
 {
-  TEST_CALLED_ONCE();
+  CHECK_IFACE_TWICE (iface);
 
   iface->base_val = 0x550055;
 
@@ -332,7 +376,7 @@ test_iface5_base_init (TestIface5Class *iface)
 static void
 test_iface6_base_init (TestIface6Class *iface)
 {
-  TEST_CALLED_ONCE();
+  CHECK_IFACE_TWICE (iface);
 
   iface->base_val = 0x660066;
   
@@ -424,5 +468,7 @@ main (int   argc,
   iface = TEST_IFACE6_GET_CLASS (object);
   g_assert (iface && iface->val == 0x60006 && iface->base_val == 0x660066);
 
+  g_print ("testifaceinit: all done.\n");
+
   return 0;
 }
index 94154ce..c25bb29 100644 (file)
@@ -28,7 +28,7 @@
  * The test defines 5 interfaces:
  * 
  * - TestIface1 is added before the class is initialized
- * - TestIface2 is added in base_object_baes_init()
+ * - TestIface2 is added in base_object_base_init()
  * - TestIface3 is added in test_iface1_base_init()
  * - TestIface4 is added in test_object_class_init()
  * - TestIface5 is added in test_object_test_iface1_init()
@@ -66,7 +66,7 @@ prefix ## _get_type (void)                                    \
   return object_type;                                          \
 }
 
-#define DEFINE_IFACE(name, prefix, base_init)                  \
+#define DEFINE_IFACE(name, prefix, base_init, dflt_init)       \
 GType                                                          \
 prefix ## _get_type (void)                                     \
 {                                                              \
@@ -79,6 +79,7 @@ prefix ## _get_type (void)                                    \
        sizeof (name ## Class),                                 \
        (GBaseInitFunc) base_init,                              \
        (GBaseFinalizeFunc) NULL,                               \
+       (GClassInitFunc) dflt_init,                             \
       };                                                       \
                                                                \
       iface_type = g_type_register_static (G_TYPE_INTERFACE,   \
@@ -98,6 +99,7 @@ struct _TestIfaceClass
   GTypeInterface base_iface;
   guint val;
   guint base_val;
+  guint default_val;
 };
 
 #define TEST_TYPE_IFACE1           (test_iface1_get_type ())
@@ -105,9 +107,10 @@ struct _TestIfaceClass
 typedef struct _TestIface1      TestIface1;
 typedef struct _TestIfaceClass  TestIface1Class;
 
-static void test_iface1_base_init (TestIface1Class *iface);
+static void test_iface1_base_init    (TestIface1Class *iface);
+static void test_iface1_default_init (TestIface1Class *iface, gpointer class_data);
 
-static DEFINE_IFACE(TestIface1, test_iface1, test_iface1_base_init)
+static DEFINE_IFACE(TestIface1, test_iface1, test_iface1_base_init, test_iface1_default_init)
 
 #define TEST_TYPE_IFACE2           (test_iface2_get_type ())
 #define TEST_IFACE2_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), TEST_TYPE_IFACE2, TestIface2Class))
@@ -116,7 +119,7 @@ typedef struct _TestIfaceClass  TestIface2Class;
 
 static void test_iface2_base_init (TestIface2Class *iface);
 
-static DEFINE_IFACE(TestIface2, test_iface2, test_iface2_base_init)
+static DEFINE_IFACE(TestIface2, test_iface2, test_iface2_base_init, NULL)
 
 #define TEST_TYPE_IFACE3           (test_iface3_get_type ())
 #define TEST_IFACE3_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), TEST_TYPE_IFACE3, TestIface3Class))
@@ -125,7 +128,7 @@ typedef struct _TestIfaceClass  TestIface3Class;
 
 static void  test_iface3_base_init (TestIface3Class *iface);
 
-static DEFINE_IFACE(TestIface3, test_iface3, test_iface3_base_init)
+static DEFINE_IFACE(TestIface3, test_iface3, test_iface3_base_init, NULL)
 
 #define TEST_TYPE_IFACE4           (test_iface4_get_type ())
 #define TEST_IFACE4_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), TEST_TYPE_IFACE4, TestIface4Class))
@@ -134,7 +137,7 @@ typedef struct _TestIfaceClass  TestIface4Class;
 
 static void  test_iface4_base_init (TestIface4Class *iface);
 
-static DEFINE_IFACE(TestIface4, test_iface4, test_iface4_base_init)
+static DEFINE_IFACE(TestIface4, test_iface4, test_iface4_base_init, NULL)
 
 #define TEST_TYPE_IFACE5           (test_iface5_get_type ())
 #define TEST_IFACE5_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), TEST_TYPE_IFACE5, TestIface5Class))
@@ -143,7 +146,7 @@ typedef struct _TestIfaceClass  TestIface5Class;
 
 static void  test_iface5_base_init (TestIface5Class *iface);
 
-static DEFINE_IFACE(TestIface5, test_iface5, test_iface5_base_init)
+static DEFINE_IFACE(TestIface5, test_iface5, test_iface5_base_init, NULL)
 
 #define TEST_TYPE_IFACE6           (test_iface6_get_type ())
 #define TEST_IFACE6_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), TEST_TYPE_IFACE6, TestIface6Class))
@@ -152,7 +155,7 @@ typedef struct _TestIfaceClass  TestIface6Class;
 
 static void  test_iface6_base_init (TestIface6Class *iface);
 
-static DEFINE_IFACE(TestIface6, test_iface6, test_iface6_base_init)
+static DEFINE_IFACE(TestIface6, test_iface6, test_iface6_base_init, NULL)
 
 /*
  * BaseObject, a parent class for TestObject
@@ -187,9 +190,20 @@ struct _TestObjectClass
 };
 
 #define TEST_CALLED_ONCE() G_STMT_START { \
-  static gboolean called = FALSE;         \
-  g_assert (!called);                     \
-  called = TRUE;                          \
+  static gboolean called = 0;           \
+  g_assert (!called);                   \
+  called = TRUE;                        \
+} G_STMT_END
+
+#define CHECK_IFACE_TWICE(iface) G_STMT_START {                                 \
+  static guint n_calls = 0;                                                     \
+  n_calls++;                                                                    \
+  g_assert (n_calls <= 2);                                                      \
+  g_assert (G_TYPE_IS_INTERFACE (((GTypeInterface*) iface)->g_type));           \
+  if (n_calls == 1)                                                             \
+    g_assert (((GTypeInterface*) iface)->g_instance_type == 0);                 \
+  else                                                                          \
+    g_assert (G_TYPE_IS_OBJECT (((GTypeInterface*) iface)->g_instance_type));   \
 } G_STMT_END
 
 #define ADD_IFACE(n)  G_STMT_START {                           \
@@ -219,12 +233,15 @@ static void
 test_object_test_iface1_init (TestIface1Class *iface)
 {
   TEST_CALLED_ONCE();
-  
+
+  g_assert (iface->default_val == 0x111111);
+
   iface->val = 0x10001;
 
   ADD_IFACE(5);
 
   iface1 = TRUE;
+  g_print ("interface1 object initializer\n");
 }
 
 static void
@@ -278,21 +295,48 @@ test_object_test_iface6_init (TestIface6Class *iface)
 }
 
 static void
-test_iface1_base_init (TestIface1Class *iface)
+test_iface1_default_init (TestIface1Class *iface,
+                          gpointer         class_data)
 {
   TEST_CALLED_ONCE();
+  g_assert (iface->base_iface.g_type == TEST_TYPE_IFACE1);
+  g_assert (iface->base_iface.g_instance_type == 0);
+  g_assert (iface->base_val == 0x110011);
+  g_assert (iface->val == 0);
+  g_assert (iface->default_val == 0);
+  iface->default_val = 0x111111;
+  g_print ("interface1 default initializer\n");
+}
 
-  iface->base_val = 0x110011;
-  
-  ADD_IFACE(3);
+static void
+test_iface1_base_init (TestIface1Class *iface)
+{
+  static guint n_calls = 0;
+  n_calls++;
+  g_assert (n_calls <= 2);
+
+  if (n_calls == 1)
+    {
+      iface->base_val = 0x110011;
+      g_assert (iface->default_val == 0);
+    }
+  else
+    {
+      g_assert (iface->base_val == 0x110011);
+      g_assert (iface->default_val == 0x111111);
+    }
+
+  if (n_calls == 1)
+    ADD_IFACE(3);
   
   base1 = TRUE;
+  g_print ("interface1 base initializer\n");
 }
 
 static void
 test_iface2_base_init (TestIface2Class *iface)
 {
-  TEST_CALLED_ONCE();
+  CHECK_IFACE_TWICE (iface);
 
   iface->base_val = 0x220022;
   
@@ -302,7 +346,7 @@ test_iface2_base_init (TestIface2Class *iface)
 static void
 test_iface3_base_init (TestIface3Class *iface)
 {
-  TEST_CALLED_ONCE();
+  CHECK_IFACE_TWICE (iface);
 
   iface->base_val = 0x330033;
   
@@ -312,7 +356,7 @@ test_iface3_base_init (TestIface3Class *iface)
 static void
 test_iface4_base_init (TestIface4Class *iface)
 {
-  TEST_CALLED_ONCE();
+  CHECK_IFACE_TWICE (iface);
 
   iface->base_val = 0x440044;
 
@@ -322,7 +366,7 @@ test_iface4_base_init (TestIface4Class *iface)
 static void
 test_iface5_base_init (TestIface5Class *iface)
 {
-  TEST_CALLED_ONCE();
+  CHECK_IFACE_TWICE (iface);
 
   iface->base_val = 0x550055;
 
@@ -332,7 +376,7 @@ test_iface5_base_init (TestIface5Class *iface)
 static void
 test_iface6_base_init (TestIface6Class *iface)
 {
-  TEST_CALLED_ONCE();
+  CHECK_IFACE_TWICE (iface);
 
   iface->base_val = 0x660066;
   
@@ -424,5 +468,7 @@ main (int   argc,
   iface = TEST_IFACE6_GET_CLASS (object);
   g_assert (iface && iface->val == 0x60006 && iface->base_val == 0x660066);
 
+  g_print ("testifaceinit: all done.\n");
+
   return 0;
 }