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: * g_param_spec_get_redirect_target:
* @pspec: a #GParamSpec * @pspec: a #GParamSpec
* *
* If the paramspec redirects operations to another paramspec, * Finds a #GParamSpec that is somehow related to @pspec.
* returns that paramspec. Redirect is used typically for *
* providing a new implementation of a property in a derived * This function is confusing and annoying and has many caveats. You
* type while preserving all the properties from the parent * should probably not use it. Just about the only thing that it is
* type. Redirection is established by creating a property * useful for is to ascertain the type of #GParamSpec that originally
* of type #GParamSpecOverride. See g_object_class_override_property() * defined an interface and in that case what you probably really want
* for an example of the use of this capability. * 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 * Since: 2.4
* *
* Returns: (transfer none): paramspec to which requests on this * Returns: (transfer none): a #GParamSpec as above, or %NULL
* paramspec should be redirected, or %NULL if none.
*/ */
GParamSpec* GParamSpec*
g_param_spec_get_redirect_target (GParamSpec *pspec) 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); GParamSpecOverride *ospec = G_PARAM_SPEC_OVERRIDE (pspec);
/* No need to recurse: overridden was already fully-dereferenced
* when the GParmaSpecOverride was created.
*/
return ospec->overridden; 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 else
return NULL; 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: * g_param_value_set_default:
* @pspec: a valid #GParamSpec * @pspec: a valid #GParamSpec

View File

@ -298,6 +298,8 @@ gpointer g_param_spec_steal_qdata (GParamSpec *pspec,
GQuark quark); GQuark quark);
GLIB_AVAILABLE_IN_ALL GLIB_AVAILABLE_IN_ALL
GParamSpec* g_param_spec_get_redirect_target (GParamSpec *pspec); 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 GLIB_AVAILABLE_IN_ALL
void g_param_value_set_default (GParamSpec *pspec, void g_param_value_set_default (GParamSpec *pspec,

View File

@ -1067,7 +1067,7 @@ param_default_init (GParamSpec *pspec)
static void static void
param_default_finalize (GParamSpec *pspec) 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)); GParamSpecClass *parent_class = g_type_class_peek (g_type_parent (G_TYPE_PARAM_OVERRIDE));
if (dspec->implementation) if (dspec->implementation)
@ -1085,16 +1085,16 @@ static void
param_default_set_default (GParamSpec *pspec, param_default_set_default (GParamSpec *pspec,
GValue *value) 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 static gboolean
param_default_validate (GParamSpec *pspec, param_default_validate (GParamSpec *pspec,
GValue *value) GValue *value)
{ {
GParamSpecDefault *dspec = G_PARAM_SPEC_OVERRIDE (pspec); GParamSpecDefault *dspec = G_PARAM_SPEC_DEFAULT (pspec);
return g_param_value_validate (dspec->implementation, value); return g_param_value_validate (dspec->implementation, value);
} }
@ -1104,7 +1104,7 @@ param_default_values_cmp (GParamSpec *pspec,
const GValue *value1, const GValue *value1,
const GValue *value2) 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); 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); 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 * Since: 2.38
*/ */
struct _GParamSpecVariant struct _GParamSpecDefault
{ {
GParamSpec parent_instance; GParamSpec parent_instance;
GVariantType *type; GParamSpec *implementation;
GVariant *default_value; GValue default_value;
/*< private >*/ /*< private >*/
gpointer padding[4]; gpointer padding[2];
}; };
/* --- GParamSpec prototypes --- */ /* --- GParamSpec prototypes --- */
@ -1192,6 +1192,9 @@ GParamSpec* g_param_spec_variant (const gchar *name,
const GVariantType *type, const GVariantType *type,
GVariant *default_value, GVariant *default_value,
GParamFlags flags); GParamFlags flags);
GLIB_AVAILABLE_IN_2_38
GParamSpec* g_param_spec_default (GParamSpec *implementation,
const GValue *new_value);
/* --- internal --- */ /* --- internal --- */
/* We prefix variable declarations so they can /* We prefix variable declarations so they can