=== Released 2.2.0 ===
[platform/upstream/glib.git] / gobject / gtype.c
index 49d7fda..9742239 100644 (file)
@@ -16,6 +16,7 @@
  * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
  * Boston, MA 02111-1307, USA.
  */
+#include        <config.h>
 #include       "gtype.h"
 
 /*
@@ -137,6 +138,8 @@ static inline void                  type_set_qdata_W                (TypeNode               *node,
                                                                         gpointer                data);
 static IFaceHolder*                    type_iface_peek_holder_L        (TypeNode               *iface,
                                                                         GType                   instance_type);
+static gboolean                                type_node_is_a_L                (TypeNode               *node,
+                                                                        TypeNode               *iface_node);
 
 
 /* --- structures --- */
@@ -381,8 +384,8 @@ type_node_fundamental_new_W (GType                 ftype,
   g_assert ((ftype & TYPE_ID_MASK) == 0);
   g_assert (ftype <= G_TYPE_FUNDAMENTAL_MAX);
   
-  if (ftype == static_fundamental_next)
-    static_fundamental_next += 1 << G_TYPE_FUNDAMENTAL_SHIFT;
+  if (ftype >> G_TYPE_FUNDAMENTAL_SHIFT == static_fundamental_next)
+    static_fundamental_next++;
   
   type_flags &= TYPE_FUNDAMENTAL_FLAG_MASK;
   
@@ -471,7 +474,7 @@ type_lookup_prerequisite_L (TypeNode *iface,
   return FALSE;
 }
 
-static inline gchar*
+static gchar*
 type_descriptive_name_I (GType type)
 {
   if (type)
@@ -776,6 +779,9 @@ check_add_interface_L (GType instance_type,
   TypeNode *iface = lookup_type_node_I (iface_type);
   IFaceEntry *entry;
   TypeNode *tnode;
+  GType *prerequisites;
+  guint i;
+
   
   if (!node || !node->is_instantiatable)
     {
@@ -822,6 +828,19 @@ check_add_interface_L (GType instance_type,
                 NODE_NAME (tnode));
       return FALSE;
     }
+  prerequisites = IFACE_NODE_PREREQUISITES (iface);
+  for (i = 0; i < IFACE_NODE_N_PREREQUISITES (iface); i++)
+    {
+      tnode = lookup_type_node_I (prerequisites[i]);
+      if (!type_node_is_a_L (node, tnode))
+       {
+         g_warning ("cannot add interface type `%s' to type `%s' which does not conform to prerequisite `%s'",
+                    NODE_NAME (iface),
+                    NODE_NAME (node),
+                    NODE_NAME (tnode));
+         return FALSE;
+       }
+    }
   return TRUE;
 }
 
@@ -1127,6 +1146,17 @@ type_iface_add_prerequisite_W (TypeNode *iface,
     type_iface_add_prerequisite_W (lookup_type_node_I (dependants[i]), prerequisite_node);
 }
 
+/**
+ * g_type_interface_add_prerequisite:
+ * @interface_type: #GType value of an interface type.
+ * @prerequisite_type: #GType value of an interface or instantiatable type.
+ * 
+ * Adds @prerequisite_type to the list of prerequisites of @interface_type.
+ * This means that any type implementing @interface_type must also implement
+ * @prerequisite_type. Prerequisites can be thought of as an alternative to
+ * interface derivation (which GType doesn't support). An interface can have
+ * at most one instantiatable prerequisite type.
+ **/
 void
 g_type_interface_add_prerequisite (GType interface_type,
                                   GType prerequisite_type)
@@ -1184,13 +1214,12 @@ g_type_interface_add_prerequisite (GType interface_type,
     }
   else if (NODE_IS_IFACE (prerequisite_node))
     {
-      GType *dependants;
-      guint n_dependants, i;
+      GType *prerequisites;
+      guint i;
       
-      dependants = iface_node_get_dependants_array_L (prerequisite_node);
-      n_dependants = dependants ? dependants[0] : 0;
-      for (i = 1; i <= n_dependants; i++)
-       type_iface_add_prerequisite_W (iface, lookup_type_node_I (dependants[i]));
+      prerequisites = IFACE_NODE_PREREQUISITES (prerequisite_node);
+      for (i = 0; i < IFACE_NODE_N_PREREQUISITES (prerequisite_node); i++)
+       type_iface_add_prerequisite_W (iface, lookup_type_node_I (prerequisites[i]));
       type_iface_add_prerequisite_W (iface, prerequisite_node);
       G_WRITE_UNLOCK (&type_rw_lock);
     }
@@ -1203,6 +1232,64 @@ g_type_interface_add_prerequisite (GType interface_type,
     }
 }
 
+/**
+ * g_type_interface_prerequisites:
+ * @interface_type: an interface type
+ * @n_prerequisites: location to return the number of prerequisites, or %NULL
+ * 
+ * Returns the prerequisites of an interfaces type.
+ * 
+ * Return value: a newly-allocated zero-terminated array of #GType containing 
+ * the prerequisites of @interface_type
+ *
+ * Since: 2.2
+ **/
+GType* /* free result */
+g_type_interface_prerequisites (GType  interface_type,
+                               guint *n_prerequisites)
+{
+  TypeNode *iface;
+  
+  g_return_val_if_fail (G_TYPE_IS_INTERFACE (interface_type), NULL);
+
+  iface = lookup_type_node_I (interface_type);
+  if (iface)
+    {
+      GType *types;
+      TypeNode *inode = NULL;
+      guint i, n = 0;
+      
+      G_READ_LOCK (&type_rw_lock);
+      types = g_new0 (GType, IFACE_NODE_N_PREREQUISITES (iface) + 1);
+      for (i = 0; i < IFACE_NODE_N_PREREQUISITES (iface); i++)
+       {
+         GType prerequisite = IFACE_NODE_PREREQUISITES (iface)[i];
+         TypeNode *node = lookup_type_node_I (prerequisite);
+         if (node->is_instantiatable &&
+             (!inode || type_node_is_a_L (node, inode)))
+           inode = node;
+         else
+           types[n++] = NODE_TYPE (node);
+       }
+      if (inode)
+       types[n++] = NODE_TYPE (inode);
+      
+      if (n_prerequisites)
+       *n_prerequisites = n;
+      G_READ_UNLOCK (&type_rw_lock);
+      
+      return types;
+    }
+  else
+    {
+      if (n_prerequisites)
+       *n_prerequisites = 0;
+      
+      return NULL;
+    }
+}
+
+
 static IFaceHolder*
 type_iface_peek_holder_L (TypeNode *iface,
                          GType     instance_type)
@@ -1359,7 +1446,9 @@ g_type_free_instance (GTypeInstance *instance)
     }
   
   instance->g_class = NULL;
-  memset (instance, 0xaa, node->data->instance.instance_size); /* FIXME: debugging hack */
+#ifdef G_ENABLE_DEBUG  
+  memset (instance, 0xaa, node->data->instance.instance_size); /* debugging hack */
+#endif  
   if (node->data->instance.n_preallocs)
     {
       G_WRITE_LOCK (&type_rw_lock);
@@ -1535,34 +1624,33 @@ type_class_init_Wm (TypeNode   *node,
 static void
 type_data_finalize_class_ifaces_Wm (TypeNode *node)
 {
-  IFaceEntry *entry;
   guint i;
-  
+
   g_assert (node->is_instantiatable && node->data && node->data->class.class && node->data->common.ref_count == 0);
-  
+
   g_message ("finalizing interfaces for %sClass `%s'",
             type_descriptive_name_I (NODE_FUNDAMENTAL_TYPE (node)),
             type_descriptive_name_I (NODE_TYPE (node)));
-  
-  for (entry = NULL, i = 0; i < CLASSED_NODE_N_IFACES (node); i++)
-    if (CLASSED_NODE_IFACES_ENTRIES (node)[i].vtable &&
-       CLASSED_NODE_IFACES_ENTRIES (node)[i].vtable->g_instance_type == NODE_TYPE (node))
-      entry = CLASSED_NODE_IFACES_ENTRIES (node) + i;
-  while (entry)
+
+ reiterate:
+  for (i = 0; i < CLASSED_NODE_N_IFACES (node); i++)
     {
-      if (!type_iface_vtable_finalize_Wm (lookup_type_node_I (entry->iface_type), node, entry->vtable))
+      IFaceEntry *entry = CLASSED_NODE_IFACES_ENTRIES (node) + i;
+      if (entry->vtable)
        {
-         /* type_iface_vtable_finalize_Wm() doesn't modify write lock upon FALSE,
-          * iface vtable came from parent
-          */
-         entry->vtable = NULL;
+          if (type_iface_vtable_finalize_Wm (lookup_type_node_I (entry->iface_type), node, entry->vtable))
+            {
+              /* refetch entries, IFACES_ENTRIES might be modified */
+              goto reiterate;
+            }
+          else
+            {
+              /* type_iface_vtable_finalize_Wm() doesn't modify write lock upon FALSE,
+               * iface vtable came from parent
+               */
+              entry->vtable = NULL;
+            }
        }
-      
-      /* refetch entry, IFACES_ENTRIES might be modified */
-      for (entry = NULL, i = 0; i < CLASSED_NODE_N_IFACES (node); i++)
-       if (CLASSED_NODE_IFACES_ENTRIES (node)[i].vtable &&
-           CLASSED_NODE_IFACES_ENTRIES (node)[i].vtable->g_instance_type == NODE_TYPE (node))
-         entry = CLASSED_NODE_IFACES_ENTRIES (node) + i;
     }
 }
 
@@ -1872,6 +1960,16 @@ g_type_add_interface_static (GType                 instance_type,
   G_WRITE_UNLOCK (&type_rw_lock);
 }
 
+/**
+ * g_type_add_interface_dynamic:
+ * @instance_type: the #GType value of an instantiable type.
+ * @interface_type: the #GType value of an interface type.
+ * @plugin: the #GTypePlugin structure to retrieve the #GInterfaceInfo from.
+ * 
+ * Adds the dynamic @interface_type to @instantiable_type. The information
+ * contained in the #GTypePlugin structure pointed to by @plugin
+ * is used to manage the relationship.
+ **/
 void
 g_type_add_interface_dynamic (GType        instance_type,
                              GType        interface_type,
@@ -2062,6 +2160,19 @@ g_type_interface_peek (gpointer instance_class,
   return vtable;
 }
 
+/**
+ * g_type_interface_peek_parent:
+ * @g_iface: A #GTypeInterface structure.
+ * 
+ * Returns the corresponding #GTypeInterface structure of the parent type
+ * of the instance type to which @g_iface belongs. This is useful when 
+ * deriving the implementation of an interface from the parent type and 
+ * then possibly overriding some methods. 
+ * 
+ * Return value: The corresponding #GTypeInterface structure of the parent type
+ * of the instance type to which @g_iface belongs, or %NULL if the parent type
+ * doesn't conform to the interface.
+ **/
 gpointer
 g_type_interface_peek_parent (gpointer g_iface)
 {
@@ -2180,11 +2291,12 @@ g_type_next_base (GType type,
 }
 
 static inline gboolean
-type_node_is_a_U (TypeNode *node,
-                 TypeNode *iface_node,
-                 /*        support_inheritance */
-                 gboolean  support_interfaces,
-                 gboolean  support_prerequisites)
+type_node_check_conformities_UorL (TypeNode *node,
+                                  TypeNode *iface_node,
+                                  /*        support_inheritance */
+                                  gboolean  support_interfaces,
+                                  gboolean  support_prerequisites,
+                                  gboolean  have_lock)
 {
   gboolean match;
   
@@ -2198,16 +2310,34 @@ type_node_is_a_U (TypeNode *node,
   match = FALSE;
   if (support_interfaces || support_prerequisites)
     {
-      G_READ_LOCK (&type_rw_lock);
+      if (!have_lock)
+       G_READ_LOCK (&type_rw_lock);
       if (support_interfaces && type_lookup_iface_entry_L (node, iface_node))
        match = TRUE;
       else if (support_prerequisites && type_lookup_prerequisite_L (node, NODE_TYPE (iface_node)))
        match = TRUE;
-      G_READ_UNLOCK (&type_rw_lock);
+      if (!have_lock)
+       G_READ_UNLOCK (&type_rw_lock);
     }
   return match;
 }
 
+static gboolean
+type_node_is_a_L (TypeNode *node,
+                 TypeNode *iface_node)
+{
+  return type_node_check_conformities_UorL (node, iface_node, TRUE, TRUE, TRUE);
+}
+
+static inline gboolean
+type_node_conforms_to_U (TypeNode *node,
+                        TypeNode *iface_node,
+                        gboolean  support_interfaces,
+                        gboolean  support_prerequisites)
+{
+  return type_node_check_conformities_UorL (node, iface_node, support_interfaces, support_prerequisites, FALSE);
+}
+
 gboolean
 g_type_is_a (GType type,
             GType iface_type)
@@ -2217,7 +2347,7 @@ g_type_is_a (GType type,
   
   node = lookup_type_node_I (type);
   iface_node = lookup_type_node_I (iface_type);
-  is_a = node && iface_node && type_node_is_a_U (node, iface_node, TRUE, TRUE);
+  is_a = node && iface_node && type_node_conforms_to_U (node, iface_node, TRUE, TRUE);
   
   return is_a;
 }
@@ -2331,6 +2461,16 @@ type_get_qdata_L (TypeNode *node,
   return NULL;
 }
 
+/**
+ * g_type_get_qdata:
+ * @type: a #GType
+ * @quark: a #GQuark id to identify the data
+ * 
+ * Obtains data which has previously been attached to @type
+ * with g_type_set_qdata().
+ * 
+ * Return value: the data, or %NULL if no data was found
+ **/
 gpointer
 g_type_get_qdata (GType  type,
                  GQuark quark)
@@ -2388,6 +2528,14 @@ type_set_qdata_W (TypeNode *node,
   qdata[i].data = data;
 }
 
+/**
+ * g_type_set_qdata:
+ * @type: a #GType 
+ * @quark: a #GQuark id to identify the data
+ * @data: the data
+ * 
+ * Attaches arbitrary data to a type.
+ **/
 void
 g_type_set_qdata (GType    type,
                  GQuark   quark,
@@ -2424,6 +2572,18 @@ type_add_flags_W (TypeNode  *node,
   type_set_qdata_W (node, static_quark_type_flags, GUINT_TO_POINTER (dflags));
 }
 
+/**
+ * g_type_query:
+ * @type: the #GType value of a static, classed type.
+ * @query: A user provided structure that is filled in with constant values 
+ *         upon success.
+ * 
+ * Queries the type system for information about a specific type. 
+ * This function will fill in a user-provided structure to hold type-specific 
+ * information. If an invalid #GType is passed in, the @type member of the 
+ * #GTypeQuery is 0. All members filled into the #GTypeQuery structure should
+ * be considered constant and have to be left untouched.
+ **/
 void
 g_type_query (GType       type,
              GTypeQuery *query)
@@ -2499,6 +2659,19 @@ g_type_get_plugin (GType type)
   return node ? node->plugin : NULL;
 }
 
+/**
+ * g_type_interface_get_plugin:
+ * @instance_type: the #GType value of an instantiatable type.
+ * @interface_type: the #GType value of an interface type.
+ * 
+ * Returns the #GTypePlugin structure for the dynamic interface 
+ * @interface_type which has been added to @instance_type, or 
+ * %NULL if @interface_type has not been added to @instance_type or does 
+ * not have a #GTypePlugin structure. See g_type_add_interface_dynamic().
+ * 
+ * Return value: the #GTypePlugin for the dynamic interface @interface_type
+ * of @instance_type.
+ **/
 GTypePlugin*
 g_type_interface_get_plugin (GType instance_type,
                             GType interface_type)
@@ -2543,7 +2716,7 @@ g_type_fundamental_next (void)
   G_READ_LOCK (&type_rw_lock);
   type = static_fundamental_next;
   G_READ_UNLOCK (&type_rw_lock);
-  
+  type = G_TYPE_MAKE_FUNDAMENTAL (type);
   return type <= G_TYPE_FUNDAMENTAL_MAX ? type : 0;
 }
 
@@ -2567,7 +2740,7 @@ g_type_check_instance_is_a (GTypeInstance *type_instance,
   
   node = lookup_type_node_I (type_instance->g_class->g_type);
   iface = lookup_type_node_I (iface_type);
-  check = node && node->is_instantiatable && iface && type_node_is_a_U (node, iface, TRUE, FALSE);
+  check = node && node->is_instantiatable && iface && type_node_conforms_to_U (node, iface, TRUE, FALSE);
   
   return check;
 }
@@ -2584,7 +2757,7 @@ g_type_check_class_is_a (GTypeClass *type_class,
   
   node = lookup_type_node_I (type_class->g_type);
   iface = lookup_type_node_I (is_a_type);
-  check = node && node->is_classed && iface && type_node_is_a_U (node, iface, FALSE, FALSE);
+  check = node && node->is_classed && iface && type_node_conforms_to_U (node, iface, FALSE, FALSE);
   
   return check;
 }
@@ -2603,7 +2776,7 @@ g_type_check_instance_cast (GTypeInstance *type_instance,
          node = lookup_type_node_I (type_instance->g_class->g_type);
          is_instantiatable = node && node->is_instantiatable;
          iface = lookup_type_node_I (iface_type);
-         check = is_instantiatable && iface && type_node_is_a_U (node, iface, TRUE, FALSE);
+         check = is_instantiatable && iface && type_node_conforms_to_U (node, iface, TRUE, FALSE);
          if (check)
            return type_instance;
          
@@ -2620,9 +2793,6 @@ g_type_check_instance_cast (GTypeInstance *type_instance,
        g_warning ("invalid unclassed pointer in cast to `%s'",
                   type_descriptive_name_I (iface_type));
     }
-  else
-    g_warning ("invalid cast from (NULL) pointer to `%s'",
-              type_descriptive_name_I (iface_type));
   
   return type_instance;
 }
@@ -2639,7 +2809,7 @@ g_type_check_class_cast (GTypeClass *type_class,
       node = lookup_type_node_I (type_class->g_type);
       is_classed = node && node->is_classed;
       iface = lookup_type_node_I (is_a_type);
-      check = is_classed && iface && type_node_is_a_U (node, iface, FALSE, FALSE);
+      check = is_classed && iface && type_node_conforms_to_U (node, iface, FALSE, FALSE);
       if (check)
        return type_class;