From c3279dd6a4bc27b06c271e5d8e41a8fb8057c786 Mon Sep 17 00:00:00 2001 From: Ryan Lortie Date: Fri, 5 Apr 2013 13:34:42 -0400 Subject: [PATCH] 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 08f694d2e..0ead45ff1 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,12 +593,60 @@ 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 diff --git a/gobject/gparam.h b/gobject/gparam.h index 315c428e4..7e198fab6 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 148148628..57d993d42 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 a7fc97fb8..86a7f5e4c 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