diff --git a/gtk/gtkcssprovider.c b/gtk/gtkcssprovider.c index 0f220e3138..1b856c36af 100644 --- a/gtk/gtkcssprovider.c +++ b/gtk/gtkcssprovider.c @@ -2758,7 +2758,7 @@ parse_rule (GtkCssProvider *css_provider, { const gchar *value_str = NULL; GtkStylePropertyParser parse_func = NULL; - GType prop_type; + GParamSpec *pspec; GError *error = NULL; gchar *prop; @@ -2782,19 +2782,19 @@ parse_rule (GtkCssProvider *css_provider, 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; val = g_slice_new0 (GValue); - g_value_init (val, prop_type); + g_value_init (val, pspec->value_type); if (strcmp (value_str, "none") == 0) { /* Remove/unset the current value */ 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_hash_table_insert (priv->cur_properties, prop, val); diff --git a/gtk/gtkstyleproperties.c b/gtk/gtkstyleproperties.c index d5cc2b73d9..3adad1f373 100644 --- a/gtk/gtkstyleproperties.c +++ b/gtk/gtkstyleproperties.c @@ -40,8 +40,7 @@ typedef struct ValueData ValueData; struct PropertyNode { GQuark property_quark; - GType property_type; - GValue default_value; + GParamSpec *pspec; GtkStylePropertyParser parse_func; }; @@ -76,33 +75,78 @@ static void gtk_style_properties_class_init (GtkStylePropertiesClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); - GValue val = { 0 }; object_class->finalize = gtk_style_properties_finalize; /* Initialize default property set */ - gtk_style_properties_register_property ("color", GDK_TYPE_RGBA, NULL, NULL); - gtk_style_properties_register_property ("background-color", GDK_TYPE_RGBA, NULL, NULL); + gtk_style_properties_register_property (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 ("padding", GTK_TYPE_BORDER, NULL, NULL); - - gtk_style_properties_register_property ("border-width", G_TYPE_INT, NULL, NULL); - gtk_style_properties_register_property ("border-radius", G_TYPE_INT, NULL, NULL); - gtk_style_properties_register_property ("border-style", GTK_TYPE_BORDER_STYLE, NULL, NULL); - gtk_style_properties_register_property ("border-color", GDK_TYPE_RGBA, NULL, NULL); - - gtk_style_properties_register_property ("background-image", CAIRO_GOBJECT_TYPE_PATTERN, NULL, NULL); - gtk_style_properties_register_property ("border-image", GTK_TYPE_9SLICE, NULL, NULL); - - g_value_init (&val, GTK_TYPE_THEMING_ENGINE); - g_value_set_object (&val, (GObject *) gtk_theming_engine_load (NULL)); - gtk_style_properties_register_property ("engine", GTK_TYPE_THEMING_ENGINE, &val, NULL); - g_value_unset (&val); - - gtk_style_properties_register_property ("transition", GTK_TYPE_ANIMATION_DESCRIPTION, NULL, NULL); + gtk_style_properties_register_property (NULL, + g_param_spec_boxed ("margin", + "Margin", + "Margin", + GTK_TYPE_BORDER, 0)); + gtk_style_properties_register_property (NULL, + g_param_spec_boxed ("padding", + "Padding", + "Padding", + GTK_TYPE_BORDER, 0)); + gtk_style_properties_register_property (NULL, + g_param_spec_int ("border-width", + "Border width", + "Border width, in pixels", + 0, G_MAXINT, 0, 0)); + gtk_style_properties_register_property (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)); } @@ -198,7 +242,6 @@ property_data_get_value (PropertyData *data, { ValueData new = { 0 }; - //val_data = &g_array_index (data->values, ValueData, pos); new.state = state; g_array_insert_val (data->values, pos, new); } @@ -333,10 +376,8 @@ property_node_lookup (GQuark quark) /** * 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 + * @pspec: the #GParamSpec for the new property * * Registers a property so it can be used in the CSS file format. * This function is the low-level equivalent of @@ -346,42 +387,29 @@ property_node_lookup (GQuark quark) * Since: 3.0 **/ void -gtk_style_properties_register_property (const gchar *property_name, - GType type, - const GValue *default_value, - GtkStylePropertyParser parse_func) +gtk_style_properties_register_property (GtkStylePropertyParser parse_func, + GParamSpec *pspec) { PropertyNode *node, new = { 0 }; GQuark quark; gint i; - g_return_if_fail (property_name != NULL); - g_return_if_fail (type != 0); + g_return_if_fail (G_IS_PARAM_SPEC (pspec)); if (G_UNLIKELY (!properties)) 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) { 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; } - quark = g_quark_from_string (property_name); - new.property_quark = quark; - new.property_type = type; - - 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); + new.pspec = pspec; if (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: * @property_name: property name to look up - * @type: (out): return location for the looked up property type - * @parse_func: (out): return value for the parse function + * @parse_func: (out): return location for the parse function + * @pspec: (out): return location for the #GParamSpec * - * Returns %TRUE if a property has been registered, if @type or - * @parse_func are not %NULL, the property #GType and parsing function + * Returns %TRUE if a property has been registered, if @pspec or + * @parse_func are not %NULL, the #GParamSpec and parsing function * will be respectively returned. * * 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 **/ gboolean -gtk_style_properties_lookup_property (const gchar *property_name, - GType *type, - GtkStylePropertyParser *parse_func) +gtk_style_properties_lookup_property (const gchar *property_name, + GtkStylePropertyParser *parse_func, + GParamSpec **pspec) { PropertyNode *node; GtkStylePropertiesClass *klass; @@ -439,8 +467,8 @@ gtk_style_properties_lookup_property (const gchar *property_name, if (node->property_quark == quark) { - if (type) - *type = node->property_type; + if (pspec) + *pspec = node->pspec; if (parse_func) *parse_func = node->parse_func; @@ -572,22 +600,22 @@ gtk_style_properties_set_property (GtkStyleProperties *props, return; } - if (node->property_type == GDK_TYPE_RGBA || - node->property_type == GDK_TYPE_COLOR) + if (node->pspec->value_type == GDK_TYPE_RGBA || + node->pspec->value_type == GDK_TYPE_COLOR) { /* Allow GtkSymbolicColor as well */ g_return_if_fail (value_type == GDK_TYPE_RGBA || value_type == GDK_TYPE_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 */ g_return_if_fail (value_type == CAIRO_GOBJECT_TYPE_PATTERN || value_type == GTK_TYPE_GRADIENT); } else - g_return_if_fail (node->property_type == value_type); + g_return_if_fail (node->pspec->value_type == value_type); priv = props->priv; prop = g_hash_table_lookup (priv->properties, @@ -670,7 +698,7 @@ gtk_style_properties_set_valist (GtkStyleProperties *props, if (G_IS_VALUE (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); if (error) @@ -765,6 +793,18 @@ resolve_gradient (GtkStyleProperties *props, 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: * @props: a #GtkStyleProperties @@ -809,23 +849,18 @@ gtk_style_properties_get_property (GtkStyleProperties *props, if (!prop) return FALSE; - g_value_init (value, node->property_type); + g_value_init (value, node->pspec->value_type); val = property_data_match_state (prop, state); - if (!val) - val = &node->default_value; - - g_return_val_if_fail (G_IS_VALUE (val), FALSE); - - if (G_VALUE_TYPE (val) == GTK_TYPE_SYMBOLIC_COLOR) + if (val && 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)) 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)) return FALSE; @@ -833,15 +868,27 @@ gtk_style_properties_get_property (GtkStyleProperties *props, else 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)) 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; } @@ -890,32 +937,41 @@ gtk_style_properties_get_valist (GtkStyleProperties *props, if (prop) val = property_data_match_state (prop, state); - if (!val) - val = &node->default_value; - - if (G_VALUE_TYPE (val) == GTK_TYPE_SYMBOLIC_COLOR) + if (val && G_VALUE_TYPE (val) == GTK_TYPE_SYMBOLIC_COLOR) { gboolean resolved; - if (node->property_type == GDK_TYPE_RGBA) + if (node->pspec->value_type == GDK_TYPE_RGBA) 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); else resolved = FALSE; 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)) - 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) { diff --git a/gtk/gtkstyleproperties.h b/gtk/gtkstyleproperties.h index b12c223b1b..ec772338a9 100644 --- a/gtk/gtkstyleproperties.h +++ b/gtk/gtkstyleproperties.h @@ -55,13 +55,11 @@ typedef gboolean (* GtkStylePropertyParser) (const gchar *string, GType gtk_style_properties_get_type (void) G_GNUC_CONST; /* Functions to register style properties */ -void gtk_style_properties_register_property (const gchar *property_name, - GType type, - const GValue *default_value, - GtkStylePropertyParser parse_func); -gboolean gtk_style_properties_lookup_property (const gchar *property_name, - GType *type, - GtkStylePropertyParser *parse_func); +void gtk_style_properties_register_property (GtkStylePropertyParser parse_func, + GParamSpec *pspec); +gboolean gtk_style_properties_lookup_property (const gchar *property_name, + GtkStylePropertyParser *parse_func, + GParamSpec **pspec); GtkStyleProperties * gtk_style_properties_new (void); diff --git a/gtk/gtkthemingengine.c b/gtk/gtkthemingengine.c index c007274ccc..8a29167fc1 100644 --- a/gtk/gtkthemingengine.c +++ b/gtk/gtkthemingengine.c @@ -327,16 +327,15 @@ _gtk_theming_engine_set_context (GtkThemingEngine *engine, /** * gtk_theming_engine_register_property: * @engine: a #GtkThemingEngine - * @property_name: property name to register - * @type: #GType the property will hold - * @default_value: default value for this property + * @namespace: namespace for the property name * @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, * on the CSS file the property will look like - * "-${engine-object-name}-${@property_name}". being - * ${engine-object-name} either the GtkThemingEngine:name property - * or G_OBJECT_TYPE_NAME(engine) if the property is unset. + * "-${@namespace}-${property_name}". being + * ${property_name} the given to @pspec. @namespace will usually + * be the theme engine name. * * For any type a @parse_func may be provided, being this function * used for turning any property value (between ':' and ';') in @@ -345,18 +344,21 @@ _gtk_theming_engine_set_context (GtkThemingEngine *engine, * cases. * * - * This function needs to be called only once during theming - * engine object initialization. + * Engines must ensure property registration happens exactly once, + * usually GTK+ deals with theming engines as singletons, so this + * should be guaranteed to happen once, but bear this in mind + * when creating #GtkThemeEngines yourself. * * * * In order to make use of the custom registered properties in - * the CSS file, make sure the engine is loaded first either in - * a previous rule or within the same one. + * the CSS file, make sure the engine is loaded first by specifying + * the engine property, either in a previous rule or within the same + * one. * * * { * engine: someengine; - * SomeEngine-custom-property: 2; + * -SomeEngine-custom-property: 2; * } * * @@ -364,31 +366,22 @@ _gtk_theming_engine_set_context (GtkThemingEngine *engine, * Since: 3.0 **/ void -gtk_theming_engine_register_property (GtkThemingEngine *engine, - const gchar *property_name, - GType type, - const GValue *default_value, - GtkStylePropertyParser parse_func) +gtk_theming_engine_register_property (const gchar *namespace, + GtkStylePropertyParser parse_func, + GParamSpec *pspec) { - GtkThemingEnginePrivate *priv; - const gchar *engine_name; gchar *name; - g_return_if_fail (GTK_IS_THEMING_ENGINE (engine)); - g_return_if_fail (property_name != NULL); - g_return_if_fail (type != G_TYPE_INVALID); - g_return_if_fail (default_value == NULL || G_IS_VALUE (default_value)); + g_return_if_fail (namespace != NULL); + g_return_if_fail (strchr (namespace, ' ') == NULL); + g_return_if_fail (G_IS_PARAM_SPEC (pspec)); - 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) - 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); + gtk_style_properties_register_property (parse_func, pspec); } /** diff --git a/gtk/gtkthemingengine.h b/gtk/gtkthemingengine.h index 3b45fb0abb..784737f2de 100644 --- a/gtk/gtkthemingengine.h +++ b/gtk/gtkthemingengine.h @@ -171,11 +171,9 @@ GType gtk_theming_engine_get_type (void) G_GNUC_CONST; void _gtk_theming_engine_set_context (GtkThemingEngine *engine, GtkStyleContext *context); -void gtk_theming_engine_register_property (GtkThemingEngine *engine, - const gchar *property_name, - GType type, - const GValue *default_value, - GtkStylePropertyParser parse_func); +void gtk_theming_engine_register_property (const gchar *namespace, + GtkStylePropertyParser parse_func, + GParamSpec *pspec); void gtk_theming_engine_get_property (GtkThemingEngine *engine, 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, const gchar *style_class); gboolean gtk_theming_engine_has_region (GtkThemingEngine *engine, - const gchar *style_class, + const gchar *style_region, GtkRegionFlags *flags); GtkStateFlags gtk_theming_engine_get_state (GtkThemingEngine *engine);