This commit is contained in:
Ryan Lortie 2013-04-05 13:34:42 -04:00
parent 5154a15277
commit c3279dd6a4
4 changed files with 138 additions and 18 deletions

View File

@ -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

View File

@ -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,

View File

@ -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;
}

View File

@ -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