Add a new GParamSpecOverride type that is a pointer to a different
authorOwen Taylor <otaylor@redhat.com>
Tue, 21 Oct 2003 19:12:27 +0000 (19:12 +0000)
committerOwen Taylor <otaylor@src.gnome.org>
Tue, 21 Oct 2003 19:12:27 +0000 (19:12 +0000)
Tue Oct 14 17:40:19 2003  Owen Taylor  <otaylor@redhat.com>

        * gparamspecs.[ch]: Add a new GParamSpecOverride type
        that is a pointer to a different paramspec in a parent
        class or interface.

        * gparam.[ch]: Add g_paramspec_get_redirect_target()
        which follows GParamSpecOverride to the real property.
        Make g_param_spec_pool_list() hand redirections,
        properties on interfaces.

        * gobject.[ch] gobjectnotifyqueue.c: Add
        g_object_interface_install_property,
        g_object_interface_find_property,
        g_object_interface_list_properties(). Redirect virtually all
        publically exposed GParamSpec's to the redirect target if
        any. (->constructor is the exception.)
        (#105894)

gobject/ChangeLog
gobject/gobject.c
gobject/gobject.h
gobject/gobjectnotifyqueue.c
gobject/gparam.c
gobject/gparam.h
gobject/gparamspecs.c
gobject/gparamspecs.h

index 1f0ed81..785bbc8 100644 (file)
@@ -1,3 +1,22 @@
+Tue Oct 14 17:40:19 2003  Owen Taylor  <otaylor@redhat.com>
+
+       * gparamspecs.[ch]: Add a new GParamSpecOverride type
+       that is a pointer to a different paramspec in a parent
+       class or interface.
+
+       * gparam.[ch]: Add g_paramspec_get_redirect_target()
+       which follows GParamSpecOverride to the real property.
+       Make g_param_spec_pool_list() hand redirections, 
+       properties on interfaces.
+
+       * gobject.[ch] gobjectnotifyqueue.c: Add
+       g_object_interface_install_property,
+       g_object_interface_find_property,
+       g_object_interface_list_properties(). Redirect virtually all
+       publically exposed GParamSpec's to the redirect target if
+       any. (->constructor is the exception.)
+       (#105894)
+
 Mon Oct 20 22:06:12 2003  Matthias Clasen  <maclas@gmx.de>
 
        * gobject.h (struct  _GObjectClass): Add /*< public >*/
index d172e59..1964901 100644 (file)
@@ -97,6 +97,9 @@ static inline void       object_set_property          (GObject        *object,
                                                         const GValue   *value,
                                                         GObjectNotifyQueue *nqueue);
 
+static void object_interface_check_properties           (gpointer        func_data,
+                                                        gpointer        g_iface);
+
 
 /* --- variables --- */
 static GQuark              quark_closure_array = 0;
@@ -256,6 +259,30 @@ g_object_do_class_init (GObjectClass *class)
                  g_cclosure_marshal_VOID__PARAM,
                  G_TYPE_NONE,
                  1, G_TYPE_PARAM);
+
+  /* Install a check function that we'll use to verify that classes that
+   * implement an interface implement all properties for that interface
+   */
+  g_type_add_interface_check (NULL, object_interface_check_properties);
+}
+
+static void
+install_property_internal (GType       g_type,
+                          guint       property_id,
+                          GParamSpec *pspec)
+{
+  if (g_param_spec_pool_lookup (pspec_pool, pspec->name, g_type, FALSE))
+    {
+      g_warning ("When installing property: type `%s' already has a property named `%s'",
+                g_type_name (g_type),
+                pspec->name);
+      return;
+    }
+
+  g_param_spec_ref (pspec);
+  g_param_spec_sink (pspec);
+  PARAM_SPEC_SET_PARAM_ID (pspec, property_id);
+  g_param_spec_pool_insert (pspec_pool, pspec, g_type);
 }
 
 void
@@ -276,18 +303,8 @@ g_object_class_install_property (GObjectClass *class,
   if (pspec->flags & (G_PARAM_CONSTRUCT | G_PARAM_CONSTRUCT_ONLY))
     g_return_if_fail (pspec->flags & G_PARAM_WRITABLE);
 
-  if (g_param_spec_pool_lookup (pspec_pool, pspec->name, G_OBJECT_CLASS_TYPE (class), FALSE))
-    {
-      g_warning (G_STRLOC ": class `%s' already contains a property named `%s'",
-                G_OBJECT_CLASS_NAME (class),
-                pspec->name);
-      return;
-    }
+  install_property_internal (G_OBJECT_CLASS_TYPE (class), property_id, pspec);
 
-  g_param_spec_ref (pspec);
-  g_param_spec_sink (pspec);
-  PARAM_SPEC_SET_PARAM_ID (pspec, property_id);
-  g_param_spec_pool_insert (pspec_pool, pspec, G_OBJECT_CLASS_TYPE (class));
   if (pspec->flags & (G_PARAM_CONSTRUCT | G_PARAM_CONSTRUCT_ONLY))
     class->construct_properties = g_slist_prepend (class->construct_properties, pspec);
 
@@ -299,17 +316,110 @@ g_object_class_install_property (GObjectClass *class,
     class->construct_properties = g_slist_remove (class->construct_properties, pspec);
 }
 
+void
+g_object_interface_install_property (gpointer      g_iface,
+                                    GParamSpec   *pspec)
+{
+  GTypeInterface *iface_class = g_iface;
+       
+  g_return_if_fail (G_TYPE_IS_INTERFACE (iface_class->g_type));
+  g_return_if_fail (G_IS_PARAM_SPEC (pspec));
+  g_return_if_fail (!G_IS_PARAM_SPEC_OVERRIDE (pspec)); /* paranoid */
+  g_return_if_fail (PARAM_SPEC_PARAM_ID (pspec) == 0); /* paranoid */
+                   
+  install_property_internal (iface_class->g_type, 0, pspec);
+}
+
 GParamSpec*
 g_object_class_find_property (GObjectClass *class,
                              const gchar  *property_name)
 {
+  GParamSpec *pspec;
+  GParamSpec *redirect;
+       
   g_return_val_if_fail (G_IS_OBJECT_CLASS (class), NULL);
   g_return_val_if_fail (property_name != NULL, NULL);
   
+  pspec = g_param_spec_pool_lookup (pspec_pool,
+                                   property_name,
+                                   G_OBJECT_CLASS_TYPE (class),
+                                   TRUE);
+  if (pspec)
+    {
+      redirect = g_param_spec_get_redirect_target (pspec);
+      if (redirect)
+       return redirect;
+      else
+       return pspec;
+    }
+  else
+    return NULL;
+}
+
+GParamSpec*
+g_object_interface_find_property (gpointer      g_iface,
+                                 const gchar  *property_name)
+{
+  GTypeInterface *iface_class = g_iface;
+       
+  g_return_val_if_fail (G_TYPE_IS_INTERFACE (iface_class->g_type), NULL);
+  g_return_val_if_fail (property_name != NULL, NULL);
+  
   return g_param_spec_pool_lookup (pspec_pool,
                                   property_name,
-                                  G_OBJECT_CLASS_TYPE (class),
-                                  TRUE);
+                                  iface_class->g_type,
+                                  FALSE);
+}
+
+void
+g_object_class_override_property (GObjectClass *oclass,
+                                 guint         property_id,
+                                 const gchar  *name)
+{
+  GParamSpec *overridden = NULL;
+  GParamSpec *new;
+  GType parent_type;
+  
+  g_return_if_fail (G_IS_OBJECT_CLASS (oclass));
+  g_return_if_fail (property_id > 0);
+  g_return_if_fail (name != NULL);
+
+  /* Find the overridden property; first check parent types
+   */
+  parent_type = g_type_parent (G_OBJECT_CLASS_TYPE (oclass));
+  if (parent_type != G_TYPE_NONE)
+    overridden = g_param_spec_pool_lookup (pspec_pool,
+                                          name,
+                                          parent_type,
+                                          TRUE);
+  if (!overridden)
+    {
+      GType *ifaces;
+      guint n_ifaces;
+      
+      /* Now check interfaces
+       */
+      ifaces = g_type_interfaces (G_OBJECT_CLASS_TYPE (oclass), &n_ifaces);
+      while (n_ifaces-- && !overridden)
+       {
+         overridden = g_param_spec_pool_lookup (pspec_pool,
+                                                name,
+                                                ifaces[n_ifaces],
+                                                FALSE);
+       }
+      
+      g_free (ifaces);
+    }
+
+  if (!overridden)
+    {
+      g_warning ("%s: Can't find property to override for '%s::%s'",
+                G_STRLOC, G_OBJECT_CLASS_NAME (oclass), name);
+      return;
+    }
+
+  new = g_param_spec_override (name, overridden);
+  g_object_class_install_property (oclass, property_id, new);
 }
 
 GParamSpec** /* free result */
@@ -330,6 +440,25 @@ g_object_class_list_properties (GObjectClass *class,
   return pspecs;
 }
 
+GParamSpec** /* free result */
+g_object_interface_list_properties (gpointer      g_iface,
+                                   guint        *n_properties_p)
+{
+  GTypeInterface *iface_class = g_iface;
+  GParamSpec **pspecs;
+  guint n;
+
+  g_return_val_if_fail (G_TYPE_IS_INTERFACE (iface_class->g_type), NULL);
+
+  pspecs = g_param_spec_pool_list (pspec_pool,
+                                  iface_class->g_type,
+                                  &n);
+  if (n_properties_p)
+    *n_properties_p = n;
+
+  return pspecs;
+}
+
 static void
 g_object_init (GObject *object)
 {
@@ -491,10 +620,15 @@ g_object_notify (GObject     *object,
     return;
   
   g_object_ref (object);
+  /* We don't need to get the redirect target
+   * (by, e.g. calling g_object_class_find_property())
+   * because g_object_notify_queue_add() does that
+   */
   pspec = g_param_spec_pool_lookup (pspec_pool,
                                    property_name,
                                    G_OBJECT_TYPE (object),
                                    TRUE);
+
   if (!pspec)
     g_warning ("%s: object class `%s' has no property named `%s'",
               G_STRLOC,
@@ -535,8 +669,14 @@ object_get_property (GObject     *object,
                     GValue      *value)
 {
   GObjectClass *class = g_type_class_peek (pspec->owner_type);
+  guint param_id = PARAM_SPEC_PARAM_ID (pspec);
+  GParamSpec *redirect;
+
+  redirect = g_param_spec_get_redirect_target (pspec);
+  if (redirect)
+    pspec = redirect;    
   
-  class->get_property (object, PARAM_SPEC_PARAM_ID (pspec), value, pspec);
+  class->get_property (object, param_id, value, pspec);
 }
 
 static inline void
@@ -547,6 +687,12 @@ object_set_property (GObject             *object,
 {
   GValue tmp_value = { 0, };
   GObjectClass *class = g_type_class_peek (pspec->owner_type);
+  guint param_id = PARAM_SPEC_PARAM_ID (pspec);
+  GParamSpec *redirect;
+
+  redirect = g_param_spec_get_redirect_target (pspec);
+  if (redirect)
+    pspec = redirect;
 
   /* provide a copy to work from, convert (if necessary) and validate */
   g_value_init (&tmp_value, G_PARAM_SPEC_VALUE_TYPE (pspec));
@@ -568,12 +714,93 @@ object_set_property (GObject             *object,
     }
   else
     {
-      class->set_property (object, PARAM_SPEC_PARAM_ID (pspec), &tmp_value, pspec);
+      class->set_property (object, param_id, &tmp_value, pspec);
       g_object_notify_queue_add (object, nqueue, pspec);
     }
   g_value_unset (&tmp_value);
 }
 
+static void
+object_interface_check_properties (gpointer func_data,
+                                  gpointer g_iface)
+{
+  GTypeInterface *iface_class = g_iface;
+  GObjectClass *class = g_type_class_peek (iface_class->g_instance_type);
+  GType iface_type = iface_class->g_type;
+  GParamSpec **pspecs;
+  guint n;
+
+  if (!G_IS_OBJECT_CLASS (class))
+    return;
+
+  pspecs = g_param_spec_pool_list (pspec_pool, iface_type, &n);
+
+  while (n--)
+    {
+      GParamSpec *class_pspec = g_param_spec_pool_lookup (pspec_pool,
+                                                         pspecs[n]->name,
+                                                         G_OBJECT_CLASS_TYPE (class),
+                                                         TRUE);
+      
+      if (!class_pspec)
+       {
+         g_critical ("Object class %s doesn't implement property "
+                     "'%s' from interface '%s'",
+                     g_type_name (G_OBJECT_CLASS_TYPE (class)),
+                     pspecs[n]->name,
+                     g_type_name (iface_type));
+
+         continue;
+       }
+
+      /* The implementation paramspec must have a less restrictive
+       * type than the interface parameter spec for set() and a
+       * more restrictive type for get(). We just require equality,
+       * rather than doing something more complicated checking
+       * the READABLE and WRITABLE flags. We also simplify here
+       * by only checking the value type, not the G_PARAM_SPEC_TYPE.
+       */
+      if (class_pspec &&
+         !g_type_is_a (G_PARAM_SPEC_VALUE_TYPE (pspecs[n]),
+                       G_PARAM_SPEC_VALUE_TYPE (class_pspec)))
+       {
+         g_critical ("Property '%s' on class '%s' has type '%s' "
+                     "which is different from the type '%s', "
+                     "of the property on interface '%s'\n",
+                     pspecs[n]->name,
+                     g_type_name (G_OBJECT_CLASS_TYPE (class)),
+                     g_type_name (G_PARAM_SPEC_VALUE_TYPE (class_pspec)),
+                     g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspecs[n])),
+                     g_type_name (iface_type));
+       }
+      
+#define SUBSET(a,b,mask) (((a) & ~(b) & (mask)) == 0)
+      
+      /* CONSTRUCT and CONSTRUCT_ONLY add restrictions.
+       * READABLE and WRITABLE remove restrictions. The implementation
+       * paramspec must have less restrictive flags.
+       */
+      if (class_pspec &&
+         (!SUBSET (class_pspec->flags,
+                   pspecs[n]->flags,
+                   G_PARAM_CONSTRUCT | G_PARAM_CONSTRUCT_ONLY) ||
+          !SUBSET (pspecs[n]->flags,
+                   class_pspec->flags,
+                   G_PARAM_READABLE | G_PARAM_WRITABLE)))
+       {
+         g_critical ("Flags for property '%s' on class '%s' "
+                     "are not compatible with the property on"
+                     "interface '%s'\n",
+                     pspecs[n]->name,
+                     g_type_name (G_OBJECT_CLASS_TYPE (class)),
+                     g_type_name (iface_type));
+       }
+#undef SUBSET    
+    }
+  
+  g_free (pspecs);
+}
+
 gpointer
 g_object_new (GType       object_type,
              const gchar *first_property_name,
index 733ce0a..6522a00 100644 (file)
@@ -118,6 +118,17 @@ GParamSpec* g_object_class_find_property      (GObjectClass   *oclass,
                                               const gchar    *property_name);
 GParamSpec**g_object_class_list_properties    (GObjectClass   *oclass,
                                               guint          *n_properties);
+void        g_object_class_override_property  (GObjectClass   *oclass,
+                                              guint           property_id,
+                                              const gchar    *name);
+
+void        g_object_interface_install_property (gpointer     g_iface,
+                                                GParamSpec  *pspec);
+GParamSpec* g_object_interface_find_property    (gpointer     g_iface,
+                                                const gchar *property_name);
+GParamSpec**g_object_interface_list_properties  (gpointer     g_iface,
+                                                guint       *n_properties_p);
+
 gpointer    g_object_new                      (GType           object_type,
                                               const gchar    *first_property_name,
                                               ...);
index 03db5c2..c816a86 100644 (file)
@@ -142,8 +142,14 @@ g_object_notify_queue_add (GObject            *object,
 {
   if (pspec->flags & G_PARAM_READABLE)
     {
+      GParamSpec *redirect;
+
       g_return_if_fail (nqueue->n_pspecs < 65535);
-      
+
+      redirect = g_param_spec_get_redirect_target (pspec);
+      if (redirect)
+       pspec = redirect;
+           
       /* we do the deduping in _thaw */
       nqueue->pspecs = g_slist_prepend (nqueue->pspecs, pspec);
       nqueue->n_pspecs++;
index da5123e..f2edcbb 100644 (file)
@@ -22,7 +22,7 @@
  */
 
 #include       "gparam.h"
-
+#include        "gparamspecs.h"
 
 #include       "gvaluecollector.h"
 #include       <string.h>
@@ -246,7 +246,18 @@ g_param_spec_get_nick (GParamSpec *pspec)
 {
   g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), NULL);
 
-  return pspec->_nick ? pspec->_nick : pspec->name;
+  if (pspec->_nick)
+    return pspec->_nick;
+  else
+    {
+      GParamSpec *redirect_target;
+
+      redirect_target = g_param_spec_get_redirect_target (pspec);
+      if (redirect_target && redirect_target->_nick)
+       return redirect_target->_nick;
+    }
+
+  return pspec->name;
 }
 
 G_CONST_RETURN gchar*
@@ -254,7 +265,18 @@ g_param_spec_get_blurb (GParamSpec *pspec)
 {
   g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), NULL);
 
-  return pspec->_blurb;
+  if (pspec->_blurb)
+    return pspec->_blurb;
+  else
+    {
+      GParamSpec *redirect_target;
+
+      redirect_target = g_param_spec_get_redirect_target (pspec);
+      if (redirect_target && redirect_target->_blurb)
+       return redirect_target->_blurb;
+    }
+
+  return NULL;
 }
 
 static void
@@ -339,6 +361,21 @@ g_param_spec_steal_qdata (GParamSpec *pspec,
   return g_datalist_id_remove_no_notify (&pspec->qdata, quark);
 }
 
+GParamSpec*
+g_param_spec_get_redirect_target (GParamSpec *pspec)
+{
+  g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), NULL);
+
+  if (G_IS_PARAM_SPEC_OVERRIDE (pspec))
+    {
+      GParamSpecOverride *ospec = G_PARAM_SPEC_OVERRIDE (pspec);
+
+      return ospec->overridden;
+    }
+  else
+    return NULL;
+}
+
 void
 g_param_value_set_default (GParamSpec *pspec,
                           GValue     *value)
@@ -793,10 +830,10 @@ pspec_compare_id (gconstpointer a,
 }
 
 static inline GSList*
-pspec_list_remove_overridden (GSList     *plist,
-                             GHashTable *ht,
-                             GType       owner_type,
-                             guint      *n_p)
+pspec_list_remove_overridden_and_redirected (GSList     *plist,
+                                            GHashTable *ht,
+                                            GType       owner_type,
+                                            guint      *n_p)
 {
   GSList *rlist = NULL;
 
@@ -804,9 +841,31 @@ pspec_list_remove_overridden (GSList     *plist,
     {
       GSList *tmp = plist->next;
       GParamSpec *pspec = plist->data;
+      GParamSpec *found;
+      gboolean remove = FALSE;
+
+      /* Remove paramspecs that are redirected, and also paramspecs
+       * that have are overridden by non-redirected properties.
+       * The idea is to get the single paramspec for each name that
+       * best corresponds to what the application sees.
+       */
+      if (g_param_spec_get_redirect_target (pspec))
+       remove = TRUE;
+      else
+       {
+         found = param_spec_ht_lookup (ht, pspec->name, owner_type, TRUE);
+         if (found != pspec)
+           {
+             GParamSpec *redirect = g_param_spec_get_redirect_target (found);
+             if (redirect != pspec)
+               remove = TRUE;
+           }
+       }
 
-      if (param_spec_ht_lookup (ht, pspec->name, owner_type, TRUE) != pspec)
-       g_slist_free_1 (plist);
+      if (remove)
+       {
+         g_slist_free_1 (plist);
+       }
       else
        {
          plist->next = rlist;
@@ -830,12 +889,42 @@ pool_depth_list (gpointer key,
 
   if (g_type_is_a (owner_type, pspec->owner_type))
     {
-      guint d = g_type_depth (pspec->owner_type);
+      if (G_TYPE_IS_INTERFACE (pspec->owner_type))
+       {
+         slists[0] = g_slist_prepend (slists[0], pspec);
+       }
+      else
+       {
+         guint d = g_type_depth (pspec->owner_type);
 
-      slists[d - 1] = g_slist_prepend (slists[d - 1], pspec);
+         slists[d - 1] = g_slist_prepend (slists[d - 1], pspec);
+       }
     }
 }
 
+/* We handle interfaces specially since we don't want to
+ * count interface prerequsites like normal inheritance;
+ * the property comes from the direct inheritance from
+ * the prerequisite class, not from the interface that
+ * prerequires it.
+ * 
+ * also 'depth' isn't a meaningful concept for interface
+ * prerequites.
+ */
+static void
+pool_depth_list_for_interface (gpointer key,
+                              gpointer value,
+                              gpointer user_data)
+{
+  GParamSpec *pspec = value;
+  gpointer *data = user_data;
+  GSList **slists = data[0];
+  GType owner_type = (GType) data[1];
+
+  if (pspec->owner_type == owner_type)
+    slists[0] = g_slist_prepend (slists[0], pspec);
+}
+
 GParamSpec** /* free result */
 g_param_spec_pool_list (GParamSpecPool *pool,
                        GType           owner_type,
@@ -856,10 +945,15 @@ g_param_spec_pool_list (GParamSpecPool *pool,
   slists = g_new0 (GSList*, d);
   data[0] = slists;
   data[1] = (gpointer) owner_type;
-  g_hash_table_foreach (pool->hash_table, pool_depth_list, &data);
-  for (i = 0; i < d - 1; i++)
-    slists[i] = pspec_list_remove_overridden (slists[i], pool->hash_table, owner_type, n_pspecs_p);
-  *n_pspecs_p += g_slist_length (slists[i]);
+
+  g_hash_table_foreach (pool->hash_table,
+                       G_TYPE_IS_INTERFACE (owner_type) ?
+                          pool_depth_list_for_interface :
+                          pool_depth_list,
+                       &data);
+  
+  for (i = 0; i < d; i++)
+    slists[i] = pspec_list_remove_overridden_and_redirected (slists[i], pool->hash_table, owner_type, n_pspecs_p);
   pspecs = g_new (GParamSpec*, *n_pspecs_p + 1);
   p = pspecs;
   for (i = 0; i < d; i++)
index 024a44a..f86ebdd 100644 (file)
@@ -73,7 +73,7 @@ struct _GParamSpec
   gchar         *name;
   GParamFlags    flags;
   GType                 value_type;
-  GType                 owner_type;    /* class using this property */
+  GType                 owner_type;    /* class or interface using this property */
 
   /*< private >*/
   gchar         *_nick;
@@ -122,6 +122,8 @@ void            g_param_spec_set_qdata_full (GParamSpec    *pspec,
                                                 GDestroyNotify destroy);
 gpointer        g_param_spec_steal_qdata       (GParamSpec    *pspec,
                                                 GQuark         quark);
+GParamSpec*     g_param_spec_get_redirect_target (GParamSpec   *pspec);
+
 void           g_param_value_set_default       (GParamSpec    *pspec,
                                                 GValue        *value);
 gboolean       g_param_value_defaults          (GParamSpec    *pspec,
index 45d90de..93f9b9d 100644 (file)
@@ -966,6 +966,54 @@ param_object_values_cmp (GParamSpec   *pspec,
   return p1 < p2 ? -1 : p1 > p2;
 }
 
+static void
+param_override_init (GParamSpec *pspec)
+{
+  /* GParamSpecOverride *ospec = G_PARAM_SPEC_OVERRIDE (pspec); */
+}
+
+static void
+param_override_finalize (GParamSpec *pspec)
+{
+  GParamSpecOverride *ospec = G_PARAM_SPEC_OVERRIDE (pspec);
+  GParamSpecClass *parent_class = g_type_class_peek (g_type_parent (G_TYPE_PARAM_OVERRIDE));
+  
+  if (ospec->overridden)
+    {
+      g_param_spec_unref (ospec->overridden);
+      ospec->overridden = NULL;
+    }
+  
+  parent_class->finalize (pspec);
+}
+
+static void
+param_override_set_default (GParamSpec *pspec,
+                           GValue     *value)
+{
+  GParamSpecOverride *ospec = G_PARAM_SPEC_OVERRIDE (pspec);
+
+  g_param_value_set_default (ospec->overridden, value);
+}
+
+static gboolean
+param_override_validate (GParamSpec *pspec,
+                        GValue     *value)
+{
+  GParamSpecOverride *ospec = G_PARAM_SPEC_OVERRIDE (pspec);
+  
+  return g_param_value_validate (ospec->overridden, value);
+}
+
+static gint
+param_override_values_cmp (GParamSpec   *pspec,
+                          const GValue *value1,
+                          const GValue *value2)
+{
+  GParamSpecOverride *ospec = G_PARAM_SPEC_OVERRIDE (pspec);
+
+  return g_param_values_cmp (ospec->overridden, value1, value2);
+}
 
 /* --- type initialization --- */
 GType *g_param_spec_types = NULL;
@@ -973,7 +1021,7 @@ GType *g_param_spec_types = NULL;
 void
 g_param_spec_types_init (void) /* sync with gtype.c */
 {
-  const guint n_types = 20;
+  const guint n_types = 21;
   GType type, *spec_types, *spec_types_bound;
 
   g_param_spec_types = g_new0 (GType, n_types);
@@ -1341,6 +1389,24 @@ g_param_spec_types_init (void)   /* sync with gtype.c */
     g_assert (type == G_TYPE_PARAM_OBJECT);
   }
 
+  /* G_TYPE_PARAM_OVERRIDE
+   */
+  {
+    static const GParamSpecTypeInfo pspec_info = {
+      sizeof (GParamSpecOverride), /* instance_size */
+      16,                        /* n_preallocs */
+      param_override_init,      /* instance_init */
+      G_TYPE_NONE,              /* value_type */
+      param_override_finalize,  /* finalize */
+      param_override_set_default, /* value_set_default */
+      param_override_validate,   /* value_validate */
+      param_override_values_cmp,  /* values_cmp */
+    };
+    type = g_param_type_register_static ("GParamOverride", &pspec_info);
+    *spec_types++ = type;
+    g_assert (type == G_TYPE_PARAM_OVERRIDE);
+  }
+
   g_assert (spec_types == spec_types_bound);
 }
 
@@ -1831,3 +1897,33 @@ g_param_spec_object (const gchar *name,
   
   return G_PARAM_SPEC (ospec);
 }
+
+GParamSpec*
+g_param_spec_override (const gchar *name,
+                      GParamSpec  *overridden)
+{
+  GParamSpec *pspec;
+  
+  g_return_val_if_fail (name != NULL, NULL);
+  g_return_val_if_fail (G_IS_PARAM_SPEC (overridden), NULL);
+  
+  /* Dereference further redirections for property that was passed in
+   */
+  while (TRUE)
+    {
+      GParamSpec *indirect = g_param_spec_get_redirect_target (overridden);
+      if (indirect)
+       overridden = indirect;
+      else
+       break;
+    }
+
+  pspec = g_param_spec_internal (G_TYPE_PARAM_OVERRIDE,
+                                name, NULL, NULL,
+                                overridden->flags);
+  
+  pspec->value_type = G_PARAM_SPEC_VALUE_TYPE (overridden);
+  G_PARAM_SPEC_OVERRIDE (pspec)->overridden = g_param_spec_ref (overridden);
+
+  return pspec;
+}
index 6d354b7..137e1d0 100644 (file)
@@ -93,6 +93,9 @@ G_BEGIN_DECLS
 #define        G_TYPE_PARAM_OBJECT                (g_param_spec_types[19])
 #define G_IS_PARAM_SPEC_OBJECT(pspec)      (G_TYPE_CHECK_INSTANCE_TYPE ((pspec), G_TYPE_PARAM_OBJECT))
 #define G_PARAM_SPEC_OBJECT(pspec)         (G_TYPE_CHECK_INSTANCE_CAST ((pspec), G_TYPE_PARAM_OBJECT, GParamSpecObject))
+#define        G_TYPE_PARAM_OVERRIDE              (g_param_spec_types[20])
+#define G_IS_PARAM_SPEC_OVERRIDE(pspec)    (G_TYPE_CHECK_INSTANCE_TYPE ((pspec), G_TYPE_PARAM_OVERRIDE))
+#define G_PARAM_SPEC_OVERRIDE(pspec)       (G_TYPE_CHECK_INSTANCE_CAST ((pspec), G_TYPE_PARAM_OVERRIDE, GParamSpecOverride))
 
 
 /* --- typedefs & structures --- */
@@ -116,6 +119,7 @@ typedef struct _GParamSpecBoxed      GParamSpecBoxed;
 typedef struct _GParamSpecPointer    GParamSpecPointer;
 typedef struct _GParamSpecValueArray GParamSpecValueArray;
 typedef struct _GParamSpecObject     GParamSpecObject;
+typedef struct _GParamSpecOverride   GParamSpecOverride;
 
 struct _GParamSpecChar
 {
@@ -258,6 +262,12 @@ struct _GParamSpecObject
 {
   GParamSpec    parent_instance;
 };
+struct _GParamSpecOverride
+{
+  /*< private >*/
+  GParamSpec    parent_instance;
+  GParamSpec   *overridden;
+};
 
 /* --- GParamSpec prototypes --- */
 GParamSpec*    g_param_spec_char        (const gchar    *name,
@@ -382,6 +392,8 @@ GParamSpec* g_param_spec_object      (const gchar    *name,
                                          GType           object_type,
                                          GParamFlags     flags);
 
+GParamSpec*     g_param_spec_override    (const gchar    *name,
+                                         GParamSpec     *overridden);
 
 /* --- internal --- */
 /* We prefix variable declarations so they can