GtkStyleProperties: Use GParamSpec for properties registration.

This commit is contained in:
Carlos Garnacho 2010-11-13 19:53:36 +01:00
parent 1c847d9c21
commit 62ee0956e3
5 changed files with 176 additions and 131 deletions

View File

@ -2758,7 +2758,7 @@ parse_rule (GtkCssProvider *css_provider,
{ {
const gchar *value_str = NULL; const gchar *value_str = NULL;
GtkStylePropertyParser parse_func = NULL; GtkStylePropertyParser parse_func = NULL;
GType prop_type; GParamSpec *pspec;
GError *error = NULL; GError *error = NULL;
gchar *prop; gchar *prop;
@ -2782,19 +2782,19 @@ parse_rule (GtkCssProvider *css_provider,
value_str = g_strstrip (scanner->value.v_identifier); value_str = g_strstrip (scanner->value.v_identifier);
if (gtk_style_properties_lookup_property (prop, &prop_type, &parse_func)) if (gtk_style_properties_lookup_property (prop, &parse_func, &pspec))
{ {
GValue *val; GValue *val;
val = g_slice_new0 (GValue); val = g_slice_new0 (GValue);
g_value_init (val, prop_type); g_value_init (val, pspec->value_type);
if (strcmp (value_str, "none") == 0) if (strcmp (value_str, "none") == 0)
{ {
/* Remove/unset the current value */ /* Remove/unset the current value */
g_hash_table_remove (priv->cur_properties, prop); g_hash_table_remove (priv->cur_properties, prop);
} }
else if (prop_type == G_TYPE_STRING) else if (pspec->value_type == G_TYPE_STRING)
{ {
g_value_set_string (val, value_str); g_value_set_string (val, value_str);
g_hash_table_insert (priv->cur_properties, prop, val); g_hash_table_insert (priv->cur_properties, prop, val);

View File

@ -40,8 +40,7 @@ typedef struct ValueData ValueData;
struct PropertyNode struct PropertyNode
{ {
GQuark property_quark; GQuark property_quark;
GType property_type; GParamSpec *pspec;
GValue default_value;
GtkStylePropertyParser parse_func; GtkStylePropertyParser parse_func;
}; };
@ -76,33 +75,78 @@ static void
gtk_style_properties_class_init (GtkStylePropertiesClass *klass) gtk_style_properties_class_init (GtkStylePropertiesClass *klass)
{ {
GObjectClass *object_class = G_OBJECT_CLASS (klass); GObjectClass *object_class = G_OBJECT_CLASS (klass);
GValue val = { 0 };
object_class->finalize = gtk_style_properties_finalize; object_class->finalize = gtk_style_properties_finalize;
/* Initialize default property set */ /* Initialize default property set */
gtk_style_properties_register_property ("color", GDK_TYPE_RGBA, NULL, NULL); gtk_style_properties_register_property (NULL,
gtk_style_properties_register_property ("background-color", GDK_TYPE_RGBA, NULL, NULL); g_param_spec_boxed ("color",
"Foreground color",
"Foreground color",
GDK_TYPE_RGBA, 0));
gtk_style_properties_register_property (NULL,
g_param_spec_boxed ("background-color",
"Background color",
"Background color",
GDK_TYPE_RGBA, 0));
gtk_style_properties_register_property ("font", PANGO_TYPE_FONT_DESCRIPTION, NULL, NULL); gtk_style_properties_register_property (NULL,
g_param_spec_boxed ("font",
"Font Description",
"Font Description",
PANGO_TYPE_FONT_DESCRIPTION, 0));
gtk_style_properties_register_property ("margin", GTK_TYPE_BORDER, NULL, NULL); gtk_style_properties_register_property (NULL,
gtk_style_properties_register_property ("padding", GTK_TYPE_BORDER, NULL, NULL); g_param_spec_boxed ("margin",
"Margin",
gtk_style_properties_register_property ("border-width", G_TYPE_INT, NULL, NULL); "Margin",
gtk_style_properties_register_property ("border-radius", G_TYPE_INT, NULL, NULL); GTK_TYPE_BORDER, 0));
gtk_style_properties_register_property ("border-style", GTK_TYPE_BORDER_STYLE, NULL, NULL); gtk_style_properties_register_property (NULL,
gtk_style_properties_register_property ("border-color", GDK_TYPE_RGBA, NULL, NULL); g_param_spec_boxed ("padding",
"Padding",
gtk_style_properties_register_property ("background-image", CAIRO_GOBJECT_TYPE_PATTERN, NULL, NULL); "Padding",
gtk_style_properties_register_property ("border-image", GTK_TYPE_9SLICE, NULL, NULL); GTK_TYPE_BORDER, 0));
gtk_style_properties_register_property (NULL,
g_value_init (&val, GTK_TYPE_THEMING_ENGINE); g_param_spec_int ("border-width",
g_value_set_object (&val, (GObject *) gtk_theming_engine_load (NULL)); "Border width",
gtk_style_properties_register_property ("engine", GTK_TYPE_THEMING_ENGINE, &val, NULL); "Border width, in pixels",
g_value_unset (&val); 0, G_MAXINT, 0, 0));
gtk_style_properties_register_property (NULL,
gtk_style_properties_register_property ("transition", GTK_TYPE_ANIMATION_DESCRIPTION, NULL, NULL); g_param_spec_int ("border-radius",
"Border radius",
"Border radius, in pixels",
0, G_MAXINT, 0, 0));
gtk_style_properties_register_property (NULL,
g_param_spec_enum ("border-style",
"Border style",
"Border style",
GTK_TYPE_BORDER_STYLE,
GTK_BORDER_STYLE_NONE, 0));
gtk_style_properties_register_property (NULL,
g_param_spec_boxed ("border-color",
"Border color",
"Border color",
GDK_TYPE_RGBA, 0));
gtk_style_properties_register_property (NULL,
g_param_spec_boxed ("background-image",
"Background Image",
"Background Image",
CAIRO_GOBJECT_TYPE_PATTERN, 0));
gtk_style_properties_register_property (NULL,
g_param_spec_boxed ("border-image",
"Border Image",
"Border Image",
GTK_TYPE_9SLICE, 0));
gtk_style_properties_register_property (NULL,
g_param_spec_object ("engine",
"Theming Engine",
"Theming Engine",
GTK_TYPE_THEMING_ENGINE, 0));
gtk_style_properties_register_property (NULL,
g_param_spec_boxed ("transition",
"Transition animation description",
"Transition animation description",
GTK_TYPE_ANIMATION_DESCRIPTION, 0));
g_type_class_add_private (object_class, sizeof (GtkStylePropertiesPrivate)); g_type_class_add_private (object_class, sizeof (GtkStylePropertiesPrivate));
} }
@ -198,7 +242,6 @@ property_data_get_value (PropertyData *data,
{ {
ValueData new = { 0 }; ValueData new = { 0 };
//val_data = &g_array_index (data->values, ValueData, pos);
new.state = state; new.state = state;
g_array_insert_val (data->values, pos, new); g_array_insert_val (data->values, pos, new);
} }
@ -333,10 +376,8 @@ property_node_lookup (GQuark quark)
/** /**
* gtk_style_properties_register_property: * gtk_style_properties_register_property:
* @property_name: property name to register
* @type: #GType the property will hold
* @default_value: default value for this property
* @parse_func: parsing function to use, or %NULL * @parse_func: parsing function to use, or %NULL
* @pspec: the #GParamSpec for the new property
* *
* Registers a property so it can be used in the CSS file format. * Registers a property so it can be used in the CSS file format.
* This function is the low-level equivalent of * This function is the low-level equivalent of
@ -346,42 +387,29 @@ property_node_lookup (GQuark quark)
* Since: 3.0 * Since: 3.0
**/ **/
void void
gtk_style_properties_register_property (const gchar *property_name, gtk_style_properties_register_property (GtkStylePropertyParser parse_func,
GType type, GParamSpec *pspec)
const GValue *default_value,
GtkStylePropertyParser parse_func)
{ {
PropertyNode *node, new = { 0 }; PropertyNode *node, new = { 0 };
GQuark quark; GQuark quark;
gint i; gint i;
g_return_if_fail (property_name != NULL); g_return_if_fail (G_IS_PARAM_SPEC (pspec));
g_return_if_fail (type != 0);
if (G_UNLIKELY (!properties)) if (G_UNLIKELY (!properties))
properties = g_array_new (FALSE, TRUE, sizeof (PropertyNode)); properties = g_array_new (FALSE, TRUE, sizeof (PropertyNode));
quark = g_quark_try_string (property_name); quark = g_quark_from_string (pspec->name);
if ((node = property_node_lookup (quark)) != NULL) if ((node = property_node_lookup (quark)) != NULL)
{ {
g_warning ("Property \"%s\" was already registered with type %s", g_warning ("Property \"%s\" was already registered with type %s",
property_name, g_type_name (node->property_type)); pspec->name, g_type_name (node->pspec->value_type));
return; return;
} }
quark = g_quark_from_string (property_name);
new.property_quark = quark; new.property_quark = quark;
new.property_type = type; new.pspec = pspec;
if (default_value)
{
g_value_init (&new.default_value, G_VALUE_TYPE (default_value));
g_value_copy (default_value, &new.default_value);
}
else
g_value_init (&new.default_value, type);
if (parse_func) if (parse_func)
new.parse_func = parse_func; new.parse_func = parse_func;
@ -400,11 +428,11 @@ gtk_style_properties_register_property (const gchar *property_name,
/** /**
* gtk_style_properties_lookup_property: * gtk_style_properties_lookup_property:
* @property_name: property name to look up * @property_name: property name to look up
* @type: (out): return location for the looked up property type * @parse_func: (out): return location for the parse function
* @parse_func: (out): return value for the parse function * @pspec: (out): return location for the #GParamSpec
* *
* Returns %TRUE if a property has been registered, if @type or * Returns %TRUE if a property has been registered, if @pspec or
* @parse_func are not %NULL, the property #GType and parsing function * @parse_func are not %NULL, the #GParamSpec and parsing function
* will be respectively returned. * will be respectively returned.
* *
* Returns: %TRUE if the property is registered, %FALSE otherwise * Returns: %TRUE if the property is registered, %FALSE otherwise
@ -412,9 +440,9 @@ gtk_style_properties_register_property (const gchar *property_name,
* Since: 3.0 * Since: 3.0
**/ **/
gboolean gboolean
gtk_style_properties_lookup_property (const gchar *property_name, gtk_style_properties_lookup_property (const gchar *property_name,
GType *type, GtkStylePropertyParser *parse_func,
GtkStylePropertyParser *parse_func) GParamSpec **pspec)
{ {
PropertyNode *node; PropertyNode *node;
GtkStylePropertiesClass *klass; GtkStylePropertiesClass *klass;
@ -439,8 +467,8 @@ gtk_style_properties_lookup_property (const gchar *property_name,
if (node->property_quark == quark) if (node->property_quark == quark)
{ {
if (type) if (pspec)
*type = node->property_type; *pspec = node->pspec;
if (parse_func) if (parse_func)
*parse_func = node->parse_func; *parse_func = node->parse_func;
@ -572,22 +600,22 @@ gtk_style_properties_set_property (GtkStyleProperties *props,
return; return;
} }
if (node->property_type == GDK_TYPE_RGBA || if (node->pspec->value_type == GDK_TYPE_RGBA ||
node->property_type == GDK_TYPE_COLOR) node->pspec->value_type == GDK_TYPE_COLOR)
{ {
/* Allow GtkSymbolicColor as well */ /* Allow GtkSymbolicColor as well */
g_return_if_fail (value_type == GDK_TYPE_RGBA || g_return_if_fail (value_type == GDK_TYPE_RGBA ||
value_type == GDK_TYPE_COLOR || value_type == GDK_TYPE_COLOR ||
value_type == GTK_TYPE_SYMBOLIC_COLOR); value_type == GTK_TYPE_SYMBOLIC_COLOR);
} }
else if (node->property_type == CAIRO_GOBJECT_TYPE_PATTERN) else if (node->pspec->value_type == CAIRO_GOBJECT_TYPE_PATTERN)
{ {
/* Allow GtkGradient as a substitute */ /* Allow GtkGradient as a substitute */
g_return_if_fail (value_type == CAIRO_GOBJECT_TYPE_PATTERN || g_return_if_fail (value_type == CAIRO_GOBJECT_TYPE_PATTERN ||
value_type == GTK_TYPE_GRADIENT); value_type == GTK_TYPE_GRADIENT);
} }
else else
g_return_if_fail (node->property_type == value_type); g_return_if_fail (node->pspec->value_type == value_type);
priv = props->priv; priv = props->priv;
prop = g_hash_table_lookup (priv->properties, prop = g_hash_table_lookup (priv->properties,
@ -670,7 +698,7 @@ gtk_style_properties_set_valist (GtkStyleProperties *props,
if (G_IS_VALUE (val)) if (G_IS_VALUE (val))
g_value_unset (val); g_value_unset (val);
g_value_init (val, node->property_type); g_value_init (val, node->pspec->value_type);
G_VALUE_COLLECT (val, args, 0, &error); G_VALUE_COLLECT (val, args, 0, &error);
if (error) if (error)
@ -765,6 +793,18 @@ resolve_gradient (GtkStyleProperties *props,
return TRUE; return TRUE;
} }
static void
lookup_default_value (PropertyNode *node,
GValue *value)
{
g_value_init (value, node->pspec->value_type);
if (node->pspec->value_type == GTK_TYPE_THEMING_ENGINE)
g_value_set_object (value, gtk_theming_engine_load (NULL));
else
g_param_value_set_default (node->pspec, value);
}
/** /**
* gtk_style_properties_get_property: * gtk_style_properties_get_property:
* @props: a #GtkStyleProperties * @props: a #GtkStyleProperties
@ -809,23 +849,18 @@ gtk_style_properties_get_property (GtkStyleProperties *props,
if (!prop) if (!prop)
return FALSE; return FALSE;
g_value_init (value, node->property_type); g_value_init (value, node->pspec->value_type);
val = property_data_match_state (prop, state); val = property_data_match_state (prop, state);
if (!val) if (val && G_VALUE_TYPE (val) == GTK_TYPE_SYMBOLIC_COLOR)
val = &node->default_value;
g_return_val_if_fail (G_IS_VALUE (val), FALSE);
if (G_VALUE_TYPE (val) == GTK_TYPE_SYMBOLIC_COLOR)
{ {
if (node->property_type == GDK_TYPE_RGBA) if (node->pspec->value_type == GDK_TYPE_RGBA)
{ {
if (!resolve_color (props, val)) if (!resolve_color (props, val))
return FALSE; return FALSE;
} }
else if (node->property_type == GDK_TYPE_COLOR) else if (node->pspec->value_type == GDK_TYPE_COLOR)
{ {
if (!resolve_color_rgb (props, val)) if (!resolve_color_rgb (props, val))
return FALSE; return FALSE;
@ -833,15 +868,27 @@ gtk_style_properties_get_property (GtkStyleProperties *props,
else else
return FALSE; return FALSE;
} }
else if (G_VALUE_TYPE (val) == GTK_TYPE_GRADIENT) else if (val && G_VALUE_TYPE (val) == GTK_TYPE_GRADIENT)
{ {
g_return_val_if_fail (node->property_type == CAIRO_GOBJECT_TYPE_PATTERN, FALSE); g_return_val_if_fail (node->pspec->value_type == CAIRO_GOBJECT_TYPE_PATTERN, FALSE);
if (!resolve_gradient (props, val)) if (!resolve_gradient (props, val))
return FALSE; return FALSE;
} }
g_value_copy (val, value); if (val)
{
g_param_value_validate (node->pspec, val);
g_value_copy (val, value);
}
else
{
GValue default_value = { 0 };
lookup_default_value (node, &default_value);
g_value_copy (&default_value, value);
g_value_unset (&default_value);
}
return TRUE; return TRUE;
} }
@ -890,32 +937,41 @@ gtk_style_properties_get_valist (GtkStyleProperties *props,
if (prop) if (prop)
val = property_data_match_state (prop, state); val = property_data_match_state (prop, state);
if (!val) if (val && G_VALUE_TYPE (val) == GTK_TYPE_SYMBOLIC_COLOR)
val = &node->default_value;
if (G_VALUE_TYPE (val) == GTK_TYPE_SYMBOLIC_COLOR)
{ {
gboolean resolved; gboolean resolved;
if (node->property_type == GDK_TYPE_RGBA) if (node->pspec->value_type == GDK_TYPE_RGBA)
resolved = resolve_color (props, val); resolved = resolve_color (props, val);
else if (node->property_type == GDK_TYPE_COLOR) else if (node->pspec->value_type == GDK_TYPE_COLOR)
resolved = resolve_color_rgb (props, val); resolved = resolve_color_rgb (props, val);
else else
resolved = FALSE; resolved = FALSE;
if (!resolved) if (!resolved)
val = &node->default_value; val = NULL;
} }
else if (G_VALUE_TYPE (val) == GTK_TYPE_GRADIENT) else if (val && G_VALUE_TYPE (val) == GTK_TYPE_GRADIENT)
{ {
g_return_if_fail (node->property_type == CAIRO_GOBJECT_TYPE_PATTERN); g_return_if_fail (node->pspec->value_type == CAIRO_GOBJECT_TYPE_PATTERN);
if (!resolve_gradient (props, val)) if (!resolve_gradient (props, val))
val = &node->default_value; val = NULL;
} }
G_VALUE_LCOPY (val, args, 0, &error); if (val)
{
g_param_value_validate (node->pspec, val);
G_VALUE_LCOPY (val, args, 0, &error);
}
else
{
GValue default_value = { 0 };
lookup_default_value (node, &default_value);
G_VALUE_LCOPY (&default_value, args, 0, &error);
g_value_unset (&default_value);
}
if (error) if (error)
{ {

View File

@ -55,13 +55,11 @@ typedef gboolean (* GtkStylePropertyParser) (const gchar *string,
GType gtk_style_properties_get_type (void) G_GNUC_CONST; GType gtk_style_properties_get_type (void) G_GNUC_CONST;
/* Functions to register style properties */ /* Functions to register style properties */
void gtk_style_properties_register_property (const gchar *property_name, void gtk_style_properties_register_property (GtkStylePropertyParser parse_func,
GType type, GParamSpec *pspec);
const GValue *default_value, gboolean gtk_style_properties_lookup_property (const gchar *property_name,
GtkStylePropertyParser parse_func); GtkStylePropertyParser *parse_func,
gboolean gtk_style_properties_lookup_property (const gchar *property_name, GParamSpec **pspec);
GType *type,
GtkStylePropertyParser *parse_func);
GtkStyleProperties * gtk_style_properties_new (void); GtkStyleProperties * gtk_style_properties_new (void);

View File

@ -327,16 +327,15 @@ _gtk_theming_engine_set_context (GtkThemingEngine *engine,
/** /**
* gtk_theming_engine_register_property: * gtk_theming_engine_register_property:
* @engine: a #GtkThemingEngine * @engine: a #GtkThemingEngine
* @property_name: property name to register * @namespace: namespace for the property name
* @type: #GType the property will hold
* @default_value: default value for this property
* @parse_func: parsing function to use, or %NULL * @parse_func: parsing function to use, or %NULL
* @pspec: the #GParamSpec for the new property
* *
* Registers a property so it can be used in the CSS file format, * Registers a property so it can be used in the CSS file format,
* on the CSS file the property will look like * on the CSS file the property will look like
* "-${engine-object-name}-${@property_name}". being * "-${@namespace}-${property_name}". being
* ${engine-object-name} either the GtkThemingEngine:name property * ${property_name} the given to @pspec. @namespace will usually
* or G_OBJECT_TYPE_NAME(engine) if the property is unset. * be the theme engine name.
* *
* For any type a @parse_func may be provided, being this function * For any type a @parse_func may be provided, being this function
* used for turning any property value (between ':' and ';') in * used for turning any property value (between ':' and ';') in
@ -345,18 +344,21 @@ _gtk_theming_engine_set_context (GtkThemingEngine *engine,
* cases. * cases.
* *
* <note> * <note>
* This function needs to be called only once during theming * Engines must ensure property registration happens exactly once,
* engine object initialization. * usually GTK+ deals with theming engines as singletons, so this
* should be guaranteed to happen once, but bear this in mind
* when creating #GtkThemeEngine<!-- -->s yourself.
* </note> * </note>
* *
* <note> * <note>
* In order to make use of the custom registered properties in * In order to make use of the custom registered properties in
* the CSS file, make sure the engine is loaded first either in * the CSS file, make sure the engine is loaded first by specifying
* a previous rule or within the same one. * the engine property, either in a previous rule or within the same
* one.
* <programlisting> * <programlisting>
* &ast; { * &ast; {
* engine: someengine; * engine: someengine;
* SomeEngine-custom-property: 2; * -SomeEngine-custom-property: 2;
* } * }
* </programlisting> * </programlisting>
* </note> * </note>
@ -364,31 +366,22 @@ _gtk_theming_engine_set_context (GtkThemingEngine *engine,
* Since: 3.0 * Since: 3.0
**/ **/
void void
gtk_theming_engine_register_property (GtkThemingEngine *engine, gtk_theming_engine_register_property (const gchar *namespace,
const gchar *property_name, GtkStylePropertyParser parse_func,
GType type, GParamSpec *pspec)
const GValue *default_value,
GtkStylePropertyParser parse_func)
{ {
GtkThemingEnginePrivate *priv;
const gchar *engine_name;
gchar *name; gchar *name;
g_return_if_fail (GTK_IS_THEMING_ENGINE (engine)); g_return_if_fail (namespace != NULL);
g_return_if_fail (property_name != NULL); g_return_if_fail (strchr (namespace, ' ') == NULL);
g_return_if_fail (type != G_TYPE_INVALID); g_return_if_fail (G_IS_PARAM_SPEC (pspec));
g_return_if_fail (default_value == NULL || G_IS_VALUE (default_value));
priv = engine->priv; /* FIXME: hack hack hack, replacing pspec->name to include namespace */
name = g_strdup_printf ("-%s-%s", namespace, pspec->name);
g_free (pspec->name);
pspec->name = name;
if (priv->name) gtk_style_properties_register_property (parse_func, pspec);
engine_name = priv->name;
else
engine_name = G_OBJECT_TYPE_NAME (engine);
name = g_strdup_printf ("-%s-%s", engine_name, property_name);
gtk_style_properties_register_property (name, type, default_value, parse_func);
g_free (name);
} }
/** /**

View File

@ -171,11 +171,9 @@ GType gtk_theming_engine_get_type (void) G_GNUC_CONST;
void _gtk_theming_engine_set_context (GtkThemingEngine *engine, void _gtk_theming_engine_set_context (GtkThemingEngine *engine,
GtkStyleContext *context); GtkStyleContext *context);
void gtk_theming_engine_register_property (GtkThemingEngine *engine, void gtk_theming_engine_register_property (const gchar *namespace,
const gchar *property_name, GtkStylePropertyParser parse_func,
GType type, GParamSpec *pspec);
const GValue *default_value,
GtkStylePropertyParser parse_func);
void gtk_theming_engine_get_property (GtkThemingEngine *engine, void gtk_theming_engine_get_property (GtkThemingEngine *engine,
const gchar *property, const gchar *property,
@ -202,7 +200,7 @@ G_CONST_RETURN GtkWidgetPath * gtk_theming_engine_get_path (GtkThemingEngine *en
gboolean gtk_theming_engine_has_class (GtkThemingEngine *engine, gboolean gtk_theming_engine_has_class (GtkThemingEngine *engine,
const gchar *style_class); const gchar *style_class);
gboolean gtk_theming_engine_has_region (GtkThemingEngine *engine, gboolean gtk_theming_engine_has_region (GtkThemingEngine *engine,
const gchar *style_class, const gchar *style_region,
GtkRegionFlags *flags); GtkRegionFlags *flags);
GtkStateFlags gtk_theming_engine_get_state (GtkThemingEngine *engine); GtkStateFlags gtk_theming_engine_get_state (GtkThemingEngine *engine);