[glib/wip/gobjectnew: 4/4] params



commit c3279dd6a4bc27b06c271e5d8e41a8fb8057c786
Author: Ryan Lortie <desrt desrt ca>
Date:   Fri Apr 5 13:34:42 2013 -0400

    params

 gobject/gparam.c      | 92 ++++++++++++++++++++++++++++++++++++++++++++++-----
 gobject/gparam.h      |  2 ++
 gobject/gparamspecs.c | 51 +++++++++++++++++++++++++---
 gobject/gparamspecs.h | 11 +++---
 4 files changed, 138 insertions(+), 18 deletions(-)
---
diff --git a/gobject/gparam.c b/gobject/gparam.c
index 08f694d..0ead45f 100644
--- a/gobject/gparam.c
+++ b/gobject/gparam.c
@@ -545,18 +545,44 @@ g_param_spec_steal_qdata (GParamSpec *pspec,
  * g_param_spec_get_redirect_target:
  * @pspec: a #GParamSpec
  *
- * If the paramspec redirects operations to another paramspec,
- * returns that paramspec. Redirect is used typically for
- * providing a new implementation of a property in a derived
- * type while preserving all the properties from the parent
- * type. Redirection is established by creating a property
- * of type #GParamSpecOverride. See g_object_class_override_property()
- * for an example of the use of this capability.
+ * Finds a #GParamSpec that is somehow related to @pspec.
+ *
+ * This function is confusing and annoying and has many caveats.  You
+ * should probably not use it.  Just about the only thing that it is
+ * useful for is to ascertain the type of #GParamSpec that originally
+ * defined an interface and in that case what you probably really want
+ * to know anyway can be obtained with G_PARAM_SPEC_VALUE_TYPE().
+ *
+ * For most #GParamSpec types this function returns %NULL.
+ *
+ * For #GParamSpecOverride, this function returns the highest-level
+ * #GParamSpec from which the chain of overrides derives.  This is not,
+ * however, the same as finding the #GParamSpec that originally defined
+ * the interface that @pspec is implementing because it's possible to
+ * directly create a new #GParamSpec and install it on an interface that
+ * already has the same type of parameter, without #GParamSpecOverride,
+ * in which case this function will return %NULL.  There is no general
+ * mechanism for answering the question of "what class or interface is
+ * this property defined on?" and in some cases it's possible that a
+ * property is defined in multiple places.  One example is two
+ * properties of the same name and compatible types defined on two
+ * separate interfaces, both of which are implemented by an object.
+ * Another example is a property defined as read-only by a parent class
+ * and then having writability added by a subclass, in which case the
+ * 'readable' and 'writable' parts of the property are split across two
+ * separate interfaces.
+ *
+ * For #GParamSpecDefault, this function returns the highest-level
+ * #GParamSpec from which the chain of overrides of its corresponding
+ * implementation #GParamSpec derives.  For #GParamSpecDefault you are
+ * probably more interested in using g_param_spec_get_implementation(),
+ * which returns the @pspec defined by the class which is implementing
+ * the property (ie: the class that will receive the property get/set
+ * calls).
  *
  * Since: 2.4
  *
- * Returns: (transfer none): paramspec to which requests on this
- *          paramspec should be redirected, or %NULL if none.
+ * Returns: (transfer none): a #GParamSpec as above, or %NULL
  */
 GParamSpec*
 g_param_spec_get_redirect_target (GParamSpec *pspec)
@@ -567,13 +593,61 @@ g_param_spec_get_redirect_target (GParamSpec *pspec)
     {
       GParamSpecOverride *ospec = G_PARAM_SPEC_OVERRIDE (pspec);
 
+      /* No need to recurse: overridden was already fully-dereferenced
+       * when the GParmaSpecOverride was created.
+       */
       return ospec->overridden;
     }
+  else if (G_IS_PARAM_SPEC_DEFAULT (pspec))
+    {
+      GParamSpecDefault *dspec = G_PARAM_SPEC_DEFAULT (pspec);
+      GParamSpec *override;
+
+      override = g_param_spec_get_redirect_target (dspec->implementation);
+
+      return override ? override : dspec->implementation;
+    }
   else
     return NULL;
 }
 
 /**
+ * g_param_spec_get_implementation:
+ * @pspec: a #GParamSpec
+ *
+ * Gets the #GParamSpec defined by the class which implements the
+ * property described by @pspec.
+ *
+ * This is the class that will receive the property get/set calls when
+ * the parameter is used.
+ *
+ * In most cases, this function will just return @pspec itself.  The
+ * case where this is not true is if @pspec is a #GParamSpecDefault.  In
+ * that case, @pspec was defined by a subclass of the class that
+ * actually implements the property in order to override its default
+ * value; the original @pspec defined by the implementing class will be
+ * returned.
+ *
+ * Returns: (transfer none): the implementation #GParamSpec
+ *
+ * Since: 2.38
+ */
+GParamSpec *
+g_param_spec_get_implementation (GParamSpec *pspec)
+{
+  g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), NULL);
+
+  if (G_IS_PARAM_SPEC_DEFAULT (pspec))
+    {
+      GParamSpecDefault *dspec = G_PARAM_SPEC_DEFAULT (pspec);
+
+      pspec = dspec->implementation;
+    }
+
+  return pspec;
+}
+
+/**
  * g_param_value_set_default:
  * @pspec: a valid #GParamSpec
  * @value: a #GValue of correct type for @pspec
diff --git a/gobject/gparam.h b/gobject/gparam.h
index 315c428..7e198fa 100644
--- a/gobject/gparam.h
+++ b/gobject/gparam.h
@@ -298,6 +298,8 @@ gpointer        g_param_spec_steal_qdata    (GParamSpec    *pspec,
                                                 GQuark         quark);
 GLIB_AVAILABLE_IN_ALL
 GParamSpec*     g_param_spec_get_redirect_target (GParamSpec   *pspec);
+GLIB_AVAILABLE_IN_2_38
+GParamSpec*     g_param_spec_get_implementation  (GParamSpec   *pspec);
 
 GLIB_AVAILABLE_IN_ALL
 void           g_param_value_set_default       (GParamSpec    *pspec,
diff --git a/gobject/gparamspecs.c b/gobject/gparamspecs.c
index 1481486..57d993d 100644
--- a/gobject/gparamspecs.c
+++ b/gobject/gparamspecs.c
@@ -1067,7 +1067,7 @@ param_default_init (GParamSpec *pspec)
 static void
 param_default_finalize (GParamSpec *pspec)
 {
-  GParamSpecDefault *dspec = G_PARAM_SPEC_OVERRIDE (pspec);
+  GParamSpecDefault *dspec = G_PARAM_SPEC_DEFAULT (pspec);
   GParamSpecClass *parent_class = g_type_class_peek (g_type_parent (G_TYPE_PARAM_OVERRIDE));
 
   if (dspec->implementation)
@@ -1085,16 +1085,16 @@ static void
 param_default_set_default (GParamSpec *pspec,
                            GValue     *value)
 {
-  GParamSpecDefault *dspec = G_PARAM_SPEC_OVERRIDE (pspec);
+  GParamSpecDefault *dspec = G_PARAM_SPEC_DEFAULT (pspec);
 
-  g_value_copy (&dpspec->default_value, value);
+  g_value_copy (&dspec->default_value, value);
 }
 
 static gboolean
 param_default_validate (GParamSpec *pspec,
                         GValue     *value)
 {
-  GParamSpecDefault *dspec = G_PARAM_SPEC_OVERRIDE (pspec);
+  GParamSpecDefault *dspec = G_PARAM_SPEC_DEFAULT (pspec);
 
   return g_param_value_validate (dspec->implementation, value);
 }
@@ -1104,7 +1104,7 @@ param_default_values_cmp (GParamSpec   *pspec,
                           const GValue *value1,
                           const GValue *value2)
 {
-  GParamSpecDefault *dspec = G_PARAM_SPEC_OVERRIDE (pspec);
+  GParamSpecDefault *dspec = G_PARAM_SPEC_DEFAULT (pspec);
 
   return g_param_values_cmp (dspec->implementation, value1, value2);
 }
@@ -2589,3 +2589,44 @@ g_param_spec_variant (const gchar        *name,
 
   return G_PARAM_SPEC (vspec);
 }
+
+GParamSpec *
+g_param_spec_default (GParamSpec   *implementation,
+                      const GValue *new_value)
+{
+  GParamSpecDefault *dspec;
+  GParamSpec *pspec;
+  GValue my_copy;
+
+  g_return_val_if_fail (G_IS_PARAM_SPEC (implementation), NULL);
+  g_return_val_if_fail (G_VALUE_HOLDS (new_value, G_PARAM_SPEC_VALUE_TYPE (implementation)), NULL);
+
+  while (TRUE)
+    {
+      GParamSpec *indirect = g_param_spec_get_implementation (implementation);
+      if (indirect)
+        implementation = indirect;
+      else
+        break;
+    }
+
+  g_value_copy (new_value, &my_copy);
+  if (g_param_value_validate (implementation, &my_copy))
+    {
+      gchar *new_str = g_strdup_value_contents (new_value);
+
+      g_critical ("%s: invalid new default value (%s) given for the override to property `%s' of type `%s'",
+                  G_STRFUNC, new_str, implementation->name, g_type_name (G_PARAM_SPEC_VALUE_TYPE 
(implementation)));
+      g_value_unset (&my_copy);
+      g_free (new_str);
+      return NULL;
+    }
+
+  dspec = g_param_spec_internal (G_TYPE_PARAM_DEFAULT, implementation->name, NULL, NULL, 
implementation->flags);
+  pspec = G_PARAM_SPEC (dspec);
+  pspec->value_type = G_PARAM_SPEC_VALUE_TYPE (implementation);
+  dspec->implementation = g_param_spec_ref (implementation);
+  dspec->default_value = my_copy;
+
+  return pspec;
+}
diff --git a/gobject/gparamspecs.h b/gobject/gparamspecs.h
index a7fc97f..86a7f5e 100644
--- a/gobject/gparamspecs.h
+++ b/gobject/gparamspecs.h
@@ -1024,14 +1024,14 @@ struct _GParamSpecVariant
  *
  * Since: 2.38
  */
-struct _GParamSpecVariant
+struct _GParamSpecDefault
 {
   GParamSpec    parent_instance;
-  GVariantType *type;
-  GVariant     *default_value;
+  GParamSpec   *implementation;
+  GValue        default_value;
 
   /*< private >*/
-  gpointer      padding[4];
+  gpointer      padding[2];
 };
 
 /* --- GParamSpec prototypes --- */
@@ -1192,6 +1192,9 @@ GParamSpec*       g_param_spec_variant     (const gchar        *name,
                                          const GVariantType *type,
                                          GVariant           *default_value,
                                          GParamFlags         flags);
+GLIB_AVAILABLE_IN_2_38
+GParamSpec*     g_param_spec_default     (GParamSpec         *implementation,
+                                          const GValue       *new_value);
 
 /* --- internal --- */
 /* We prefix variable declarations so they can


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]