2 * Copyright © 2011 Red Hat Inc.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 * Authors: Benjamin Otte <otte@gnome.org>
23 #include "gtkcssstylepropertyprivate.h"
25 #include "gtkcssstylefuncsprivate.h"
26 #include "gtkcsstypesprivate.h"
28 #include "gtkprivatetypebuiltins.h"
29 #include "gtkstylepropertiesprivate.h"
32 #include <cairo-gobject.h>
33 #include "gtkgradient.h"
34 #include "gtkshadowprivate.h"
35 #include "gtkwin32themeprivate.h"
45 G_DEFINE_TYPE (GtkCssStyleProperty, _gtk_css_style_property, GTK_TYPE_STYLE_PROPERTY)
48 gtk_css_style_property_constructed (GObject *object)
50 GtkCssStyleProperty *property = GTK_CSS_STYLE_PROPERTY (object);
51 GtkCssStylePropertyClass *klass = GTK_CSS_STYLE_PROPERTY_GET_CLASS (property);
53 property->id = klass->style_properties->len;
54 g_ptr_array_add (klass->style_properties, property);
56 G_OBJECT_CLASS (_gtk_css_style_property_parent_class)->constructed (object);
60 gtk_css_style_property_set_property (GObject *object,
65 GtkCssStyleProperty *property = GTK_CSS_STYLE_PROPERTY (object);
66 const GValue *initial;
71 property->inherit = g_value_get_boolean (value);
74 initial = g_value_get_boxed (value);
76 g_value_init (&property->initial_value, G_VALUE_TYPE (initial));
77 g_value_copy (initial, &property->initial_value);
80 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
86 gtk_css_style_property_get_property (GObject *object,
91 GtkCssStyleProperty *property = GTK_CSS_STYLE_PROPERTY (object);
96 g_value_set_boolean (value, property->id);
99 g_value_set_boolean (value, property->inherit);
102 g_value_set_boxed (value, &property->initial_value);
105 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
111 _gtk_css_style_property_assign (GtkStyleProperty *property,
112 GtkStyleProperties *props,
116 _gtk_style_properties_set_property_by_property (props,
117 GTK_CSS_STYLE_PROPERTY (property),
123 _gtk_style_property_default_value (GtkStyleProperty *property,
124 GtkStyleProperties *properties,
128 g_value_copy (_gtk_css_style_property_get_initial_value (GTK_CSS_STYLE_PROPERTY (property)), value);
132 resolve_color (GtkStyleProperties *props,
137 /* Resolve symbolic color to GdkRGBA */
138 if (!gtk_symbolic_color_resolve (g_value_get_boxed (value), props, &color))
141 /* Store it back, this is where GdkRGBA caching happens */
142 g_value_unset (value);
143 g_value_init (value, GDK_TYPE_RGBA);
144 g_value_set_boxed (value, &color);
150 resolve_color_rgb (GtkStyleProperties *props,
153 GdkColor color = { 0 };
156 if (!gtk_symbolic_color_resolve (g_value_get_boxed (value), props, &rgba))
159 color.red = rgba.red * 65535. + 0.5;
160 color.green = rgba.green * 65535. + 0.5;
161 color.blue = rgba.blue * 65535. + 0.5;
163 g_value_unset (value);
164 g_value_init (value, GDK_TYPE_COLOR);
165 g_value_set_boxed (value, &color);
171 resolve_win32_theme_part (GtkStyleProperties *props,
174 GtkStylePropertyContext *context)
176 GtkWin32ThemePart *part;
177 cairo_pattern_t *pattern;
179 part = g_value_get_boxed (value);
183 pattern = _gtk_win32_theme_part_render (part, context->width, context->height);
185 g_value_take_boxed (value_out, pattern);
192 resolve_gradient (GtkStyleProperties *props,
195 cairo_pattern_t *gradient;
197 if (!gtk_gradient_resolve (g_value_get_boxed (value), props, &gradient))
200 /* Store it back, this is where cairo_pattern_t caching happens */
201 g_value_unset (value);
202 g_value_init (value, CAIRO_GOBJECT_TYPE_PATTERN);
203 g_value_take_boxed (value, gradient);
209 resolve_shadow (GtkStyleProperties *props,
212 GtkShadow *resolved, *base;
214 base = g_value_get_boxed (value);
219 if (_gtk_shadow_get_resolved (base))
222 resolved = _gtk_shadow_resolve (base, props);
223 if (resolved == NULL)
226 g_value_take_boxed (value, resolved);
232 _gtk_style_property_resolve (GtkStyleProperty *property,
233 GtkStyleProperties *props,
235 GtkStylePropertyContext *context,
239 if (G_VALUE_TYPE (val) == GTK_TYPE_CSS_SPECIAL_VALUE)
241 GtkCssSpecialValue special = g_value_get_enum (val);
246 case GTK_CSS_CURRENT_COLOR:
247 g_assert (_gtk_style_property_get_value_type (property) == GDK_TYPE_RGBA);
248 gtk_style_properties_get_property (props, "color", state, val);
250 case GTK_CSS_INHERIT:
251 case GTK_CSS_INITIAL:
253 g_assert_not_reached ();
256 else if (G_VALUE_TYPE (val) == GTK_TYPE_SYMBOLIC_COLOR)
258 if (_gtk_style_property_get_value_type (property) == GDK_TYPE_RGBA)
260 if (resolve_color (props, val))
263 else if (_gtk_style_property_get_value_type (property) == GDK_TYPE_COLOR)
265 if (resolve_color_rgb (props, val))
270 g_value_init (val, _gtk_style_property_get_value_type (property));
271 _gtk_style_property_default_value (property, props, state, val);
273 else if (G_VALUE_TYPE (val) == GDK_TYPE_RGBA)
275 if (g_value_get_boxed (val) == NULL)
276 _gtk_style_property_default_value (property, props, state, val);
278 else if (G_VALUE_TYPE (val) == GTK_TYPE_GRADIENT)
280 g_return_if_fail (_gtk_style_property_get_value_type (property) == CAIRO_GOBJECT_TYPE_PATTERN);
282 if (!resolve_gradient (props, val))
285 g_value_init (val, CAIRO_GOBJECT_TYPE_PATTERN);
286 _gtk_style_property_default_value (property, props, state, val);
289 else if (G_VALUE_TYPE (val) == GTK_TYPE_SHADOW)
291 if (!resolve_shadow (props, val))
292 _gtk_style_property_default_value (property, props, state, val);
294 else if (G_VALUE_TYPE (val) == GTK_TYPE_WIN32_THEME_PART)
296 if (resolve_win32_theme_part (props, val, val_out, context))
297 return; /* Don't copy val, this sets val_out */
298 _gtk_style_property_default_value (property, props, state, val);
302 g_value_copy (val, val_out);
306 _gtk_css_style_property_query (GtkStyleProperty *property,
307 GtkStyleProperties *props,
309 GtkStylePropertyContext *context,
314 val = _gtk_style_properties_peek_property (props, GTK_CSS_STYLE_PROPERTY (property), state);
316 _gtk_style_property_resolve (property, props, state, context, (GValue *) val, value);
318 _gtk_style_property_default_value (property, props, state, value);
322 gtk_css_style_property_parse_value (GtkStyleProperty *property,
324 GtkCssParser *parser,
329 if (_gtk_css_parser_try (parser, "initial", TRUE))
331 /* the initial value can be explicitly specified with the
332 * ‘initial’ keyword which all properties accept.
334 g_value_init (value, GTK_TYPE_CSS_SPECIAL_VALUE);
335 g_value_set_enum (value, GTK_CSS_INITIAL);
338 else if (_gtk_css_parser_try (parser, "inherit", TRUE))
340 /* All properties accept the ‘inherit’ value which
341 * explicitly specifies that the value will be determined
342 * by inheritance. The ‘inherit’ value can be used to
343 * strengthen inherited values in the cascade, and it can
344 * also be used on properties that are not normally inherited.
346 g_value_init (value, GTK_TYPE_CSS_SPECIAL_VALUE);
347 g_value_set_enum (value, GTK_CSS_INHERIT);
350 else if (property->property_parse_func)
352 GError *error = NULL;
355 value_str = _gtk_css_parser_read_value (parser);
356 if (value_str == NULL)
359 g_value_init (value, _gtk_style_property_get_value_type (property));
360 success = (*property->property_parse_func) (value_str, value, &error);
364 g_value_unset (value);
369 g_value_init (value, _gtk_style_property_get_value_type (property));
370 if (property->parse_func)
371 success = (* property->parse_func) (parser, base, value);
373 success = _gtk_css_style_parse_value (value, parser, base);
376 g_value_unset (value);
382 _gtk_css_style_property_class_init (GtkCssStylePropertyClass *klass)
384 GObjectClass *object_class = G_OBJECT_CLASS (klass);
385 GtkStylePropertyClass *property_class = GTK_STYLE_PROPERTY_CLASS (klass);
387 object_class->constructed = gtk_css_style_property_constructed;
388 object_class->set_property = gtk_css_style_property_set_property;
389 object_class->get_property = gtk_css_style_property_get_property;
391 g_object_class_install_property (object_class,
393 g_param_spec_uint ("id",
395 P_("The numeric id for quick access"),
398 g_object_class_install_property (object_class,
400 g_param_spec_boolean ("inherit",
402 P_("Set if the value is inherited by default"),
404 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
405 g_object_class_install_property (object_class,
407 g_param_spec_boxed ("initial-value",
409 P_("The initial specified value used for this property"),
411 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
413 property_class->assign = _gtk_css_style_property_assign;
414 property_class->query = _gtk_css_style_property_query;
415 property_class->parse_value = gtk_css_style_property_parse_value;
417 klass->style_properties = g_ptr_array_new ();
422 _gtk_css_style_property_init (GtkCssStyleProperty *style_property)
427 * _gtk_css_style_property_get_n_properties:
429 * Gets the number of style properties. This number can increase when new
430 * theme engines are loaded. Shorthand properties are not included here.
432 * Returns: The number of style properties.
435 _gtk_css_style_property_get_n_properties (void)
437 GtkCssStylePropertyClass *klass;
439 klass = g_type_class_peek (GTK_TYPE_CSS_STYLE_PROPERTY);
441 return klass->style_properties->len;
445 * _gtk_css_style_property_lookup_by_id:
446 * @id: the id of the property
448 * Gets the style property with the given id. All style properties (but not
449 * shorthand properties) are indexable by id so that it's easy to use arrays
450 * when doing style lookups.
452 * Returns: (transfer none): The style property with the given id
454 GtkCssStyleProperty *
455 _gtk_css_style_property_lookup_by_id (guint id)
457 GtkCssStylePropertyClass *klass;
459 klass = g_type_class_peek (GTK_TYPE_CSS_STYLE_PROPERTY);
461 return g_ptr_array_index (klass->style_properties, id);
465 * _gtk_css_style_property_is_inherit:
466 * @property: the property
468 * Queries if the given @property is inherited. See
469 * <ulink url="http://www.w3.org/TR/css3-cascade/#inheritance>
470 * the CSS documentation</ulink> for an explanation of this concept.
472 * Returns: %TRUE if the property is inherited by default.
475 _gtk_css_style_property_is_inherit (GtkCssStyleProperty *property)
477 g_return_val_if_fail (GTK_IS_CSS_STYLE_PROPERTY (property), 0);
479 return property->inherit;
483 * _gtk_css_style_property_get_id:
484 * @property: the property
486 * Gets the id for the given property. IDs are used to allow using arrays
489 * Returns: The id of the property
492 _gtk_css_style_property_get_id (GtkCssStyleProperty *property)
494 g_return_val_if_fail (GTK_IS_CSS_STYLE_PROPERTY (property), 0);
500 * _gtk_css_style_property_get_initial_value:
501 * @property: the property
503 * Queries the initial value of the given @property. See
504 * <ulink url="http://www.w3.org/TR/css3-cascade/#intial>
505 * the CSS documentation</ulink> for an explanation of this concept.
507 * Returns: a reference to the initial value. The value will never change.
510 _gtk_css_style_property_get_initial_value (GtkCssStyleProperty *property)
512 g_return_val_if_fail (GTK_IS_CSS_STYLE_PROPERTY (property), NULL);
514 return &property->initial_value;
518 * _gtk_css_style_property_print_value:
519 * @property: the property
520 * @value: the value to print
521 * @string: the string to print to
523 * Prints @value to the given @string in CSS format. The @value must be a
524 * valid specified value as parsed using the parse functions or as assigned
525 * via _gtk_style_property_assign().
528 _gtk_css_style_property_print_value (GtkCssStyleProperty *property,
532 g_return_if_fail (GTK_IS_CSS_STYLE_PROPERTY (property));
533 g_return_if_fail (value != NULL);
534 g_return_if_fail (string != NULL);
536 if (G_VALUE_HOLDS (value, GTK_TYPE_CSS_SPECIAL_VALUE))
538 GEnumClass *enum_class;
539 GEnumValue *enum_value;
541 enum_class = g_type_class_ref (GTK_TYPE_CSS_SPECIAL_VALUE);
542 enum_value = g_enum_get_value (enum_class, g_value_get_enum (value));
544 g_string_append (string, enum_value->value_nick);
546 g_type_class_unref (enum_class);
548 else if (GTK_STYLE_PROPERTY (property)->print_func)
549 (* GTK_STYLE_PROPERTY (property)->print_func) (value, string);
551 _gtk_css_style_print_value (value, string);