1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 2010 Carlos Garnacho <carlosg@gnome.org>
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 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
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
22 #include "gtkstylepropertyprivate.h"
29 #include <gdk-pixbuf/gdk-pixbuf.h>
30 #include <cairo-gobject.h>
32 #include "gtkcssprovider.h"
33 #include "gtkcssparserprivate.h"
34 #include "gtkcsstypesprivate.h"
36 /* the actual parsers we have */
37 #include "gtkanimationdescription.h"
38 #include "gtkbindings.h"
39 #include "gtk9slice.h"
40 #include "gtkgradient.h"
41 #include "gtkshadowprivate.h"
42 #include "gtkthemingengine.h"
43 #include "gtktypebuiltins.h"
45 static GHashTable *parse_funcs = NULL;
46 static GHashTable *print_funcs = NULL;
47 static GHashTable *properties = NULL;
50 register_conversion_function (GType type,
51 GtkStyleParseFunc parse,
52 GtkStylePrintFunc print)
55 g_hash_table_insert (parse_funcs, GSIZE_TO_POINTER (type), parse);
57 g_hash_table_insert (print_funcs, GSIZE_TO_POINTER (type), print);
61 string_append_double (GString *string,
64 char buf[G_ASCII_DTOSTR_BUF_SIZE];
66 g_ascii_dtostr (buf, sizeof (buf), d);
67 g_string_append (string, buf);
71 string_append_string (GString *str,
76 g_string_append_c (str, '"');
79 len = strcspn (string, "\"\n\r\f");
80 g_string_append (str, string);
87 g_string_append (str, "\\A ");
90 g_string_append (str, "\\D ");
93 g_string_append (str, "\\C ");
96 g_string_append (str, "\\\"");
99 g_assert_not_reached ();
104 g_string_append_c (str, '"');
107 /*** IMPLEMENTATIONS ***/
110 rgba_value_parse (GtkCssParser *parser,
114 GtkSymbolicColor *symbolic;
117 symbolic = _gtk_css_parser_read_symbolic_color (parser);
118 if (symbolic == NULL)
121 if (gtk_symbolic_color_resolve (symbolic, NULL, &rgba))
123 g_value_set_boxed (value, &rgba);
124 gtk_symbolic_color_unref (symbolic);
128 g_value_unset (value);
129 g_value_init (value, GTK_TYPE_SYMBOLIC_COLOR);
130 g_value_take_boxed (value, symbolic);
137 rgba_value_print (const GValue *value,
140 const GdkRGBA *rgba = g_value_get_boxed (value);
143 g_string_append (string, "none");
146 char *s = gdk_rgba_to_string (rgba);
147 g_string_append (string, s);
153 color_value_parse (GtkCssParser *parser,
157 GtkSymbolicColor *symbolic;
160 symbolic = _gtk_css_parser_read_symbolic_color (parser);
161 if (symbolic == NULL)
164 if (gtk_symbolic_color_resolve (symbolic, NULL, &rgba))
168 color.red = rgba.red * 65535. + 0.5;
169 color.green = rgba.green * 65535. + 0.5;
170 color.blue = rgba.blue * 65535. + 0.5;
172 g_value_set_boxed (value, &color);
176 g_value_unset (value);
177 g_value_init (value, GTK_TYPE_SYMBOLIC_COLOR);
178 g_value_take_boxed (value, symbolic);
185 color_value_print (const GValue *value,
188 const GdkColor *color = g_value_get_boxed (value);
191 g_string_append (string, "none");
194 char *s = gdk_color_to_string (color);
195 g_string_append (string, s);
201 symbolic_color_value_parse (GtkCssParser *parser,
205 GtkSymbolicColor *symbolic;
207 symbolic = _gtk_css_parser_read_symbolic_color (parser);
208 if (symbolic == NULL)
211 g_value_take_boxed (value, symbolic);
216 symbolic_color_value_print (const GValue *value,
219 GtkSymbolicColor *symbolic = g_value_get_boxed (value);
221 if (symbolic == NULL)
222 g_string_append (string, "none");
225 char *s = gtk_symbolic_color_to_string (symbolic);
226 g_string_append (string, s);
232 font_family_parse (GtkCssParser *parser,
239 /* We don't special case generic families. Pango should do
242 names = g_ptr_array_new ();
245 name = _gtk_css_parser_try_ident (parser, TRUE);
248 GString *string = g_string_new (name);
250 while ((name = _gtk_css_parser_try_ident (parser, TRUE)))
252 g_string_append_c (string, ' ');
253 g_string_append (string, name);
256 name = g_string_free (string, FALSE);
260 name = _gtk_css_parser_read_string (parser);
263 g_ptr_array_free (names, TRUE);
268 g_ptr_array_add (names, name);
269 } while (_gtk_css_parser_try (parser, ",", TRUE));
271 /* NULL-terminate array */
272 g_ptr_array_add (names, NULL);
273 g_value_set_boxed (value, g_ptr_array_free (names, FALSE));
278 font_family_value_print (const GValue *value,
281 const char **names = g_value_get_boxed (value);
283 if (names == NULL || *names == NULL)
285 g_string_append (string, "none");
289 string_append_string (string, *names);
293 g_string_append (string, ", ");
294 string_append_string (string, *names);
300 font_description_value_parse (GtkCssParser *parser,
304 PangoFontDescription *font_desc;
307 str = _gtk_css_parser_read_value (parser);
311 font_desc = pango_font_description_from_string (str);
313 g_value_take_boxed (value, font_desc);
318 font_description_value_print (const GValue *value,
321 const PangoFontDescription *desc = g_value_get_boxed (value);
324 g_string_append (string, "none");
327 char *s = pango_font_description_to_string (desc);
328 g_string_append (string, s);
334 boolean_value_parse (GtkCssParser *parser,
338 if (_gtk_css_parser_try (parser, "true", TRUE) ||
339 _gtk_css_parser_try (parser, "1", TRUE))
341 g_value_set_boolean (value, TRUE);
344 else if (_gtk_css_parser_try (parser, "false", TRUE) ||
345 _gtk_css_parser_try (parser, "0", TRUE))
347 g_value_set_boolean (value, FALSE);
352 _gtk_css_parser_error (parser, "Expected a boolean value");
358 boolean_value_print (const GValue *value,
361 if (g_value_get_boolean (value))
362 g_string_append (string, "true");
364 g_string_append (string, "false");
368 int_value_parse (GtkCssParser *parser,
374 if (!_gtk_css_parser_try_int (parser, &i))
376 _gtk_css_parser_error (parser, "Expected a valid integer value");
380 g_value_set_int (value, i);
385 int_value_print (const GValue *value,
388 g_string_append_printf (string, "%d", g_value_get_int (value));
392 uint_value_parse (GtkCssParser *parser,
398 if (!_gtk_css_parser_try_uint (parser, &u))
400 _gtk_css_parser_error (parser, "Expected a valid unsigned value");
404 g_value_set_uint (value, u);
409 uint_value_print (const GValue *value,
412 g_string_append_printf (string, "%u", g_value_get_uint (value));
416 double_value_parse (GtkCssParser *parser,
422 if (!_gtk_css_parser_try_double (parser, &d))
424 _gtk_css_parser_error (parser, "Expected a number");
428 g_value_set_double (value, d);
433 double_value_print (const GValue *value,
436 string_append_double (string, g_value_get_double (value));
440 float_value_parse (GtkCssParser *parser,
446 if (!_gtk_css_parser_try_double (parser, &d))
448 _gtk_css_parser_error (parser, "Expected a number");
452 g_value_set_float (value, d);
457 float_value_print (const GValue *value,
460 string_append_double (string, g_value_get_float (value));
464 string_value_parse (GtkCssParser *parser,
468 char *str = _gtk_css_parser_read_string (parser);
473 g_value_take_string (value, str);
478 string_value_print (const GValue *value,
481 string_append_string (str, g_value_get_string (value));
485 theming_engine_value_parse (GtkCssParser *parser,
489 GtkThemingEngine *engine;
492 str = _gtk_css_parser_try_ident (parser, TRUE);
495 _gtk_css_parser_error (parser, "Expected a valid theme name");
499 engine = gtk_theming_engine_load (str);
502 _gtk_css_parser_error (parser, "Themeing engine '%s' not found", str);
507 g_value_set_object (value, engine);
513 theming_engine_value_print (const GValue *value,
516 GtkThemingEngine *engine;
519 engine = g_value_get_object (value);
521 g_string_append (string, "none");
524 /* XXX: gtk_theming_engine_get_name()? */
525 g_object_get (engine, "name", &name, NULL);
526 g_string_append (string, name);
532 animation_description_value_parse (GtkCssParser *parser,
536 GtkAnimationDescription *desc;
539 str = _gtk_css_parser_read_value (parser);
543 desc = _gtk_animation_description_from_string (str);
548 _gtk_css_parser_error (parser, "Invalid animation description");
552 g_value_take_boxed (value, desc);
557 animation_description_value_print (const GValue *value,
560 GtkAnimationDescription *desc = g_value_get_boxed (value);
563 g_string_append (string, "none");
565 _gtk_animation_description_print (desc, string);
569 border_value_parse (GtkCssParser *parser,
573 GtkBorder border = { 0, };
576 for (i = 0; i < G_N_ELEMENTS (numbers); i++)
578 if (!_gtk_css_parser_try_uint (parser, &numbers[i]))
581 /* XXX: shouldn't allow spaces here? */
582 _gtk_css_parser_try (parser, "px", TRUE);
587 _gtk_css_parser_error (parser, "Expected valid border");
591 border.top = numbers[0];
593 border.right = numbers[1];
595 border.right = border.top;
597 border.bottom = numbers[2];
599 border.bottom = border.top;
601 border.left = numbers[3];
603 border.left = border.right;
605 g_value_set_boxed (value, &border);
610 border_value_print (const GValue *value, GString *string)
612 const GtkBorder *border = g_value_get_boxed (value);
615 g_string_append (string, "none");
616 else if (border->left != border->right)
617 g_string_append_printf (string, "%d %d %d %d", border->top, border->right, border->bottom, border->left);
618 else if (border->top != border->bottom)
619 g_string_append_printf (string, "%d %d %d", border->top, border->right, border->bottom);
620 else if (border->top != border->left)
621 g_string_append_printf (string, "%d %d", border->top, border->right);
623 g_string_append_printf (string, "%d", border->top);
627 gradient_value_parse (GtkCssParser *parser,
631 GtkGradient *gradient;
632 cairo_pattern_type_t type;
636 if (!_gtk_css_parser_try (parser, "-gtk-gradient", TRUE))
638 _gtk_css_parser_error (parser,
639 "Expected '-gtk-gradient'");
643 if (!_gtk_css_parser_try (parser, "(", TRUE))
645 _gtk_css_parser_error (parser,
646 "Expected '(' after '-gtk-gradient'");
650 /* Parse gradient type */
651 if (_gtk_css_parser_try (parser, "linear", TRUE))
652 type = CAIRO_PATTERN_TYPE_LINEAR;
653 else if (_gtk_css_parser_try (parser, "radial", TRUE))
654 type = CAIRO_PATTERN_TYPE_RADIAL;
657 _gtk_css_parser_error (parser,
658 "Gradient type must be 'radial' or 'linear'");
662 /* Parse start/stop position parameters */
663 for (i = 0; i < 2; i++)
665 if (! _gtk_css_parser_try (parser, ",", TRUE))
667 _gtk_css_parser_error (parser,
672 if (_gtk_css_parser_try (parser, "left", TRUE))
674 else if (_gtk_css_parser_try (parser, "right", TRUE))
676 else if (_gtk_css_parser_try (parser, "center", TRUE))
678 else if (!_gtk_css_parser_try_double (parser, &coords[i * 3]))
680 _gtk_css_parser_error (parser,
681 "Expected a valid X coordinate");
685 if (_gtk_css_parser_try (parser, "top", TRUE))
686 coords[i * 3 + 1] = 0;
687 else if (_gtk_css_parser_try (parser, "bottom", TRUE))
688 coords[i * 3 + 1] = 1;
689 else if (_gtk_css_parser_try (parser, "center", TRUE))
690 coords[i * 3 + 1] = 0.5;
691 else if (!_gtk_css_parser_try_double (parser, &coords[i * 3 + 1]))
693 _gtk_css_parser_error (parser,
694 "Expected a valid Y coordinate");
698 if (type == CAIRO_PATTERN_TYPE_RADIAL)
701 if (! _gtk_css_parser_try (parser, ",", TRUE))
703 _gtk_css_parser_error (parser,
708 if (! _gtk_css_parser_try_double (parser, &coords[(i * 3) + 2]))
710 _gtk_css_parser_error (parser,
711 "Expected a numer for the radius");
717 if (type == CAIRO_PATTERN_TYPE_LINEAR)
718 gradient = gtk_gradient_new_linear (coords[0], coords[1], coords[3], coords[4]);
720 gradient = gtk_gradient_new_radial (coords[0], coords[1], coords[2],
721 coords[3], coords[4], coords[5]);
723 while (_gtk_css_parser_try (parser, ",", TRUE))
725 GtkSymbolicColor *color;
728 if (_gtk_css_parser_try (parser, "from", TRUE))
732 if (!_gtk_css_parser_try (parser, "(", TRUE))
734 gtk_gradient_unref (gradient);
735 _gtk_css_parser_error (parser,
741 else if (_gtk_css_parser_try (parser, "to", TRUE))
745 if (!_gtk_css_parser_try (parser, "(", TRUE))
747 gtk_gradient_unref (gradient);
748 _gtk_css_parser_error (parser,
754 else if (_gtk_css_parser_try (parser, "color-stop", TRUE))
756 if (!_gtk_css_parser_try (parser, "(", TRUE))
758 gtk_gradient_unref (gradient);
759 _gtk_css_parser_error (parser,
764 if (!_gtk_css_parser_try_double (parser, &position))
766 gtk_gradient_unref (gradient);
767 _gtk_css_parser_error (parser,
768 "Expected a valid number");
772 if (!_gtk_css_parser_try (parser, ",", TRUE))
774 gtk_gradient_unref (gradient);
775 _gtk_css_parser_error (parser,
782 gtk_gradient_unref (gradient);
783 _gtk_css_parser_error (parser,
784 "Not a valid color-stop definition");
788 color = _gtk_css_parser_read_symbolic_color (parser);
791 gtk_gradient_unref (gradient);
795 gtk_gradient_add_color_stop (gradient, position, color);
796 gtk_symbolic_color_unref (color);
798 if (!_gtk_css_parser_try (parser, ")", TRUE))
800 gtk_gradient_unref (gradient);
801 _gtk_css_parser_error (parser,
807 if (!_gtk_css_parser_try (parser, ")", TRUE))
809 gtk_gradient_unref (gradient);
810 _gtk_css_parser_error (parser,
815 g_value_take_boxed (value, gradient);
820 gradient_value_print (const GValue *value,
823 GtkGradient *gradient = g_value_get_boxed (value);
825 if (gradient == NULL)
826 g_string_append (string, "none");
829 char *s = gtk_gradient_to_string (gradient);
830 g_string_append (string, s);
836 gtk_css_parse_url (GtkCssParser *parser,
842 if (_gtk_css_parser_try (parser, "url", FALSE))
844 if (!_gtk_css_parser_try (parser, "(", TRUE))
846 _gtk_css_parser_skip_whitespace (parser);
847 if (_gtk_css_parser_try (parser, "(", TRUE))
851 error = g_error_new_literal (GTK_CSS_PROVIDER_ERROR,
852 GTK_CSS_PROVIDER_ERROR_DEPRECATED,
853 "Whitespace between 'url' and '(' is not allowed");
855 _gtk_css_parser_take_error (parser, error);
859 _gtk_css_parser_error (parser, "Expected '(' after 'url'");
864 path = _gtk_css_parser_read_string (parser);
868 if (!_gtk_css_parser_try (parser, ")", TRUE))
870 _gtk_css_parser_error (parser, "No closing ')' found for 'url'");
877 path = _gtk_css_parser_try_name (parser, TRUE);
880 _gtk_css_parser_error (parser, "Not a valid url");
885 file = g_file_resolve_relative_path (base, path);
892 pattern_value_parse (GtkCssParser *parser,
896 if (_gtk_css_parser_begins_with (parser, '-'))
898 g_value_unset (value);
899 g_value_init (value, GTK_TYPE_GRADIENT);
900 return gradient_value_parse (parser, base, value);
904 GError *error = NULL;
908 cairo_surface_t *surface;
909 cairo_pattern_t *pattern;
911 cairo_matrix_t matrix;
913 file = gtk_css_parse_url (parser, base);
917 path = g_file_get_path (file);
918 g_object_unref (file);
920 pixbuf = gdk_pixbuf_new_from_file (path, &error);
924 _gtk_css_parser_take_error (parser, error);
928 surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
929 gdk_pixbuf_get_width (pixbuf),
930 gdk_pixbuf_get_height (pixbuf));
931 cr = cairo_create (surface);
932 gdk_cairo_set_source_pixbuf (cr, pixbuf, 0, 0);
934 pattern = cairo_pattern_create_for_surface (surface);
936 cairo_matrix_init_scale (&matrix,
937 gdk_pixbuf_get_width (pixbuf),
938 gdk_pixbuf_get_height (pixbuf));
939 cairo_pattern_set_matrix (pattern, &matrix);
941 cairo_surface_destroy (surface);
943 g_object_unref (pixbuf);
945 g_value_take_boxed (value, pattern);
952 shadow_value_parse (GtkCssParser *parser,
957 gdouble hoffset, voffset, blur, spread;
958 GtkSymbolicColor *color;
961 shadow = _gtk_shadow_new ();
965 inset = _gtk_css_parser_try (parser, "inset", TRUE);
967 if (!_gtk_css_parser_try_double (parser, &hoffset) ||
968 !_gtk_css_parser_try_double (parser, &voffset))
970 _gtk_css_parser_error (parser, "Horizontal and vertical offsets are required");
971 _gtk_shadow_unref (shadow);
975 if (!_gtk_css_parser_try_double (parser, &blur))
978 if (!_gtk_css_parser_try_double (parser, &spread))
981 /* XXX: the color is optional and UA-defined if it's missing,
982 * but it doesn't really make sense for us...
984 color = _gtk_css_parser_read_symbolic_color (parser);
988 _gtk_shadow_unref (shadow);
992 _gtk_shadow_append (shadow,
997 gtk_symbolic_color_unref (color);
1000 while (_gtk_css_parser_try (parser, ",", TRUE));
1002 g_value_take_boxed (value, shadow);
1007 shadow_value_print (const GValue *value,
1012 shadow = g_value_get_boxed (value);
1015 g_string_append (string, "none");
1017 _gtk_shadow_print (shadow, string);
1021 slice_value_parse (GtkCssParser *parser,
1025 gdouble distance_top, distance_bottom;
1026 gdouble distance_left, distance_right;
1027 GtkSliceSideModifier mods[2];
1031 GError *error = NULL;
1035 /* Parse image url */
1036 file = gtk_css_parse_url (parser, base);
1040 if (!_gtk_css_parser_try_double (parser, &distance_top) ||
1041 !_gtk_css_parser_try_double (parser, &distance_right) ||
1042 !_gtk_css_parser_try_double (parser, &distance_bottom) ||
1043 !_gtk_css_parser_try_double (parser, &distance_left))
1045 _gtk_css_parser_error (parser, "Expected a number");
1046 g_object_unref (file);
1050 for (i = 0; i < 2; i++)
1052 if (_gtk_css_parser_try (parser, "stretch", TRUE))
1053 mods[i] = GTK_SLICE_STRETCH;
1054 else if (_gtk_css_parser_try (parser, "repeat", TRUE))
1055 mods[i] = GTK_SLICE_REPEAT;
1058 mods[1] = mods[0] = GTK_SLICE_STRETCH;
1065 path = g_file_get_path (file);
1066 g_object_unref (file);
1067 pixbuf = gdk_pixbuf_new_from_file (path, &error);
1071 _gtk_css_parser_take_error (parser, error);
1075 slice = _gtk_9slice_new (pixbuf,
1076 distance_top, distance_bottom,
1077 distance_left, distance_right,
1079 g_object_unref (pixbuf);
1081 g_value_take_boxed (value, slice);
1086 enum_value_parse (GtkCssParser *parser,
1090 GEnumClass *enum_class;
1091 GEnumValue *enum_value;
1094 str = _gtk_css_parser_try_ident (parser, TRUE);
1097 _gtk_css_parser_error (parser, "Expected an identifier");
1101 enum_class = g_type_class_ref (G_VALUE_TYPE (value));
1102 enum_value = g_enum_get_value_by_nick (enum_class, str);
1105 g_value_set_enum (value, enum_value->value);
1107 _gtk_css_parser_error (parser,
1108 "Unknown value '%s' for enum type '%s'",
1109 str, g_type_name (G_VALUE_TYPE (value)));
1111 g_type_class_unref (enum_class);
1114 return enum_value != NULL;
1118 enum_value_print (const GValue *value,
1121 GEnumClass *enum_class;
1122 GEnumValue *enum_value;
1124 enum_class = g_type_class_ref (G_VALUE_TYPE (value));
1125 enum_value = g_enum_get_value (enum_class, g_value_get_enum (value));
1127 g_string_append (string, enum_value->value_nick);
1129 g_type_class_unref (enum_class);
1133 flags_value_parse (GtkCssParser *parser,
1137 GFlagsClass *flags_class;
1138 GFlagsValue *flag_value;
1142 flags_class = g_type_class_ref (G_VALUE_TYPE (value));
1145 str = _gtk_css_parser_try_ident (parser, TRUE);
1148 _gtk_css_parser_error (parser, "Expected an identifier");
1149 g_type_class_unref (flags_class);
1153 flag_value = g_flags_get_value_by_nick (flags_class, str);
1156 _gtk_css_parser_error (parser,
1157 "Unknown flag value '%s' for type '%s'",
1158 str, g_type_name (G_VALUE_TYPE (value)));
1159 /* XXX Do we want to return FALSE here? We can get
1160 * forward-compatibility for new values this way
1163 g_type_class_unref (flags_class);
1169 while (_gtk_css_parser_try (parser, ",", FALSE));
1171 g_type_class_unref (flags_class);
1173 g_value_set_enum (value, flags);
1179 flags_value_print (const GValue *value,
1182 GFlagsClass *flags_class;
1185 flags_class = g_type_class_ref (G_VALUE_TYPE (value));
1186 flags = g_value_get_flags (value);
1188 for (i = 0; i < flags_class->n_values; i++)
1190 GFlagsValue *flags_value = &flags_class->values[i];
1192 if (flags & flags_value->value)
1194 if (string->len != 0)
1195 g_string_append (string, ", ");
1197 g_string_append (string, flags_value->value_nick);
1201 g_type_class_unref (flags_class);
1205 bindings_value_parse (GtkCssParser *parser,
1210 GtkBindingSet *binding_set;
1213 array = g_ptr_array_new ();
1216 name = _gtk_css_parser_try_ident (parser, TRUE);
1219 _gtk_css_parser_error (parser, "Not a valid binding name");
1220 g_ptr_array_free (array, TRUE);
1224 binding_set = gtk_binding_set_find (name);
1228 _gtk_css_parser_error (parser, "No binding set named '%s'", name);
1233 g_ptr_array_add (array, binding_set);
1236 while (_gtk_css_parser_try (parser, ",", TRUE));
1238 g_value_take_boxed (value, array);
1244 bindings_value_print (const GValue *value,
1250 array = g_value_get_boxed (value);
1252 for (i = 0; i < array->len; i++)
1254 GtkBindingSet *binding_set = g_ptr_array_index (array, i);
1257 g_string_append (string, ", ");
1258 g_string_append (string, binding_set->set_name);
1263 border_corner_radius_value_parse (GtkCssParser *parser,
1267 GtkCssBorderCornerRadius corner;
1269 if (!_gtk_css_parser_try_double (parser, &corner.horizontal))
1271 _gtk_css_parser_error (parser, "Expected a number");
1274 else if (corner.horizontal < 0)
1277 if (!_gtk_css_parser_try_double (parser, &corner.vertical))
1278 corner.vertical = corner.horizontal;
1279 else if (corner.vertical < 0)
1282 g_value_set_boxed (value, &corner);
1286 _gtk_css_parser_error (parser, "Border radius values cannot be negative");
1291 border_corner_radius_value_print (const GValue *value,
1294 GtkCssBorderCornerRadius *corner;
1296 corner = g_value_get_boxed (value);
1300 g_string_append (string, "none");
1304 string_append_double (string, corner->horizontal);
1305 if (corner->horizontal != corner->vertical)
1307 g_string_append_c (string, ' ');
1308 string_append_double (string, corner->vertical);
1313 border_radius_value_parse (GtkCssParser *parser,
1317 GtkCssBorderRadius border;
1319 if (!_gtk_css_parser_try_double (parser, &border.top_left.horizontal))
1321 _gtk_css_parser_error (parser, "Expected a number");
1324 else if (border.top_left.horizontal < 0)
1327 if (_gtk_css_parser_try_double (parser, &border.top_right.horizontal))
1329 if (border.top_right.horizontal < 0)
1331 if (_gtk_css_parser_try_double (parser, &border.bottom_right.horizontal))
1333 if (border.bottom_right.horizontal < 0)
1335 if (!_gtk_css_parser_try_double (parser, &border.bottom_left.horizontal))
1336 border.bottom_left.horizontal = border.top_right.horizontal;
1337 else if (border.bottom_left.horizontal < 0)
1342 border.bottom_right.horizontal = border.top_left.horizontal;
1343 border.bottom_left.horizontal = border.top_right.horizontal;
1348 border.top_right.horizontal = border.top_left.horizontal;
1349 border.bottom_right.horizontal = border.top_left.horizontal;
1350 border.bottom_left.horizontal = border.top_left.horizontal;
1353 if (_gtk_css_parser_try (parser, "/", TRUE))
1355 if (!_gtk_css_parser_try_double (parser, &border.top_left.vertical))
1357 _gtk_css_parser_error (parser, "Expected a number");
1360 else if (border.top_left.vertical < 0)
1363 if (_gtk_css_parser_try_double (parser, &border.top_right.vertical))
1365 if (border.top_right.vertical < 0)
1367 if (_gtk_css_parser_try_double (parser, &border.bottom_right.vertical))
1369 if (border.bottom_right.vertical < 0)
1371 if (!_gtk_css_parser_try_double (parser, &border.bottom_left.vertical))
1372 border.bottom_left.vertical = border.top_right.vertical;
1373 else if (border.bottom_left.vertical < 0)
1378 border.bottom_right.vertical = border.top_left.vertical;
1379 border.bottom_left.vertical = border.top_right.vertical;
1384 border.top_right.vertical = border.top_left.vertical;
1385 border.bottom_right.vertical = border.top_left.vertical;
1386 border.bottom_left.vertical = border.top_left.vertical;
1391 border.top_left.vertical = border.top_left.horizontal;
1392 border.top_right.vertical = border.top_right.horizontal;
1393 border.bottom_right.vertical = border.bottom_right.horizontal;
1394 border.bottom_left.vertical = border.bottom_left.horizontal;
1397 /* border-radius is an int property for backwards-compat reasons */
1398 g_value_unset (value);
1399 g_value_init (value, GTK_TYPE_CSS_BORDER_RADIUS);
1400 g_value_set_boxed (value, &border);
1405 _gtk_css_parser_error (parser, "Border radius values cannot be negative");
1410 border_radius_value_print (const GValue *value,
1413 GtkCssBorderRadius *border;
1415 border = g_value_get_boxed (value);
1419 g_string_append (string, "none");
1423 string_append_double (string, border->top_left.horizontal);
1424 if (border->top_left.horizontal != border->top_right.horizontal ||
1425 border->top_left.horizontal != border->bottom_right.horizontal ||
1426 border->top_left.horizontal != border->bottom_left.horizontal)
1428 g_string_append_c (string, ' ');
1429 string_append_double (string, border->top_right.horizontal);
1430 if (border->top_left.horizontal != border->bottom_right.horizontal ||
1431 border->top_right.horizontal != border->bottom_left.horizontal)
1433 g_string_append_c (string, ' ');
1434 string_append_double (string, border->bottom_right.horizontal);
1435 if (border->top_right.horizontal != border->bottom_left.horizontal)
1437 g_string_append_c (string, ' ');
1438 string_append_double (string, border->bottom_left.horizontal);
1443 if (border->top_left.horizontal != border->top_left.vertical ||
1444 border->top_right.horizontal != border->top_right.vertical ||
1445 border->bottom_right.horizontal != border->bottom_right.vertical ||
1446 border->bottom_left.horizontal != border->bottom_left.vertical)
1448 g_string_append (string, " / ");
1449 string_append_double (string, border->top_left.vertical);
1450 if (border->top_left.vertical != border->top_right.vertical ||
1451 border->top_left.vertical != border->bottom_right.vertical ||
1452 border->top_left.vertical != border->bottom_left.vertical)
1454 g_string_append_c (string, ' ');
1455 string_append_double (string, border->top_right.vertical);
1456 if (border->top_left.vertical != border->bottom_right.vertical ||
1457 border->top_right.vertical != border->bottom_left.vertical)
1459 g_string_append_c (string, ' ');
1460 string_append_double (string, border->bottom_right.vertical);
1461 if (border->top_right.vertical != border->bottom_left.vertical)
1463 g_string_append_c (string, ' ');
1464 string_append_double (string, border->bottom_left.vertical);
1475 unpack_border (const GValue *value,
1482 GParameter *parameter = g_new0 (GParameter, 4);
1483 GtkBorder *border = g_value_get_boxed (value);
1485 parameter[0].name = top;
1486 g_value_init (¶meter[0].value, G_TYPE_INT);
1487 g_value_set_int (¶meter[0].value, border->top);
1488 parameter[1].name = left;
1489 g_value_init (¶meter[1].value, G_TYPE_INT);
1490 g_value_set_int (¶meter[1].value, border->left);
1491 parameter[2].name = bottom;
1492 g_value_init (¶meter[2].value, G_TYPE_INT);
1493 g_value_set_int (¶meter[2].value, border->bottom);
1494 parameter[3].name = right;
1495 g_value_init (¶meter[3].value, G_TYPE_INT);
1496 g_value_set_int (¶meter[3].value, border->right);
1503 pack_border (GValue *value,
1504 GtkStyleProperties *props,
1505 GtkStateFlags state,
1514 gtk_style_properties_get (props,
1527 g_value_set_boxed (value, &border);
1531 unpack_border_width (const GValue *value,
1534 return unpack_border (value, n_params,
1535 "border-top-width", "border-left-width",
1536 "border-bottom-width", "border-right-width");
1540 pack_border_width (GValue *value,
1541 GtkStyleProperties *props,
1542 GtkStateFlags state)
1544 pack_border (value, props, state,
1545 "border-top-width", "border-left-width",
1546 "border-bottom-width", "border-right-width");
1550 unpack_padding (const GValue *value,
1553 return unpack_border (value, n_params,
1554 "padding-top", "padding-left",
1555 "padding-bottom", "padding-right");
1559 pack_padding (GValue *value,
1560 GtkStyleProperties *props,
1561 GtkStateFlags state)
1563 pack_border (value, props, state,
1564 "padding-top", "padding-left",
1565 "padding-bottom", "padding-right");
1569 unpack_margin (const GValue *value,
1572 return unpack_border (value, n_params,
1573 "margin-top", "margin-left",
1574 "margin-bottom", "margin-right");
1578 pack_margin (GValue *value,
1579 GtkStyleProperties *props,
1580 GtkStateFlags state)
1582 pack_border (value, props, state,
1583 "margin-top", "margin-left",
1584 "margin-bottom", "margin-right");
1588 unpack_border_radius (const GValue *value,
1591 GParameter *parameter = g_new0 (GParameter, 4);
1592 GtkCssBorderRadius *border;
1594 if (G_VALUE_HOLDS_BOXED (value))
1595 border = g_value_get_boxed (value);
1599 parameter[0].name = "border-top-left-radius";
1600 g_value_init (¶meter[0].value, GTK_TYPE_CSS_BORDER_CORNER_RADIUS);
1601 parameter[1].name = "border-top-right-radius";
1602 g_value_init (¶meter[1].value, GTK_TYPE_CSS_BORDER_CORNER_RADIUS);
1603 parameter[2].name = "border-bottom-right-radius";
1604 g_value_init (¶meter[2].value, GTK_TYPE_CSS_BORDER_CORNER_RADIUS);
1605 parameter[3].name = "border-bottom-left-radius";
1606 g_value_init (¶meter[3].value, GTK_TYPE_CSS_BORDER_CORNER_RADIUS);
1609 g_value_set_boxed (¶meter[0].value, &border->top_left);
1610 g_value_set_boxed (¶meter[1].value, &border->top_right);
1611 g_value_set_boxed (¶meter[2].value, &border->bottom_right);
1612 g_value_set_boxed (¶meter[3].value, &border->bottom_left);
1620 pack_border_radius (GValue *value,
1621 GtkStyleProperties *props,
1622 GtkStateFlags state)
1624 GtkCssBorderCornerRadius *top_left;
1626 /* NB: We are an int property, so we have to resolve to an int here.
1627 * So we just resolve to an int. We pick one and stick to it.
1628 * Lesson learned: Don't query border-radius shorthand, query the
1629 * real properties instead. */
1630 gtk_style_properties_get (props,
1632 "border-top-left-radius", &top_left,
1636 g_value_set_int (value, top_left->horizontal);
1642 unpack_font_description (const GValue *value,
1645 GParameter *parameter = g_new0 (GParameter, 5);
1646 PangoFontDescription *description;
1650 /* For backwards compat, we only unpack values that are indeed set.
1651 * For strict CSS conformance we need to unpack all of them.
1652 * Note that we do set all of them in the parse function, so it
1653 * will not have effects when parsing CSS files. It will though
1654 * for custom style providers.
1657 description = g_value_get_boxed (value);
1661 mask = pango_font_description_get_set_fields (description);
1665 if (mask & PANGO_FONT_MASK_FAMILY)
1667 GPtrArray *strv = g_ptr_array_new ();
1669 g_ptr_array_add (strv, g_strdup (pango_font_description_get_family (description)));
1670 g_ptr_array_add (strv, NULL);
1671 parameter[n].name = "font-family";
1672 g_value_init (¶meter[n].value, G_TYPE_STRV);
1673 g_value_take_boxed (¶meter[n].value,
1674 g_ptr_array_free (strv, FALSE));
1678 if (mask & PANGO_FONT_MASK_STYLE)
1680 parameter[n].name = "font-style";
1681 g_value_init (¶meter[n].value, PANGO_TYPE_STYLE);
1682 g_value_set_enum (¶meter[n].value,
1683 pango_font_description_get_style (description));
1687 if (mask & PANGO_FONT_MASK_VARIANT)
1689 parameter[n].name = "font-variant";
1690 g_value_init (¶meter[n].value, PANGO_TYPE_VARIANT);
1691 g_value_set_enum (¶meter[n].value,
1692 pango_font_description_get_variant (description));
1696 if (mask & PANGO_FONT_MASK_WEIGHT)
1698 parameter[n].name = "font-weight";
1699 g_value_init (¶meter[n].value, PANGO_TYPE_WEIGHT);
1700 g_value_set_enum (¶meter[n].value,
1701 pango_font_description_get_weight (description));
1705 if (mask & PANGO_FONT_MASK_SIZE)
1707 parameter[n].name = "font-size";
1708 g_value_init (¶meter[n].value, G_TYPE_DOUBLE);
1709 g_value_set_double (¶meter[n].value,
1710 (double) pango_font_description_get_size (description) / PANGO_SCALE);
1720 pack_font_description (GValue *value,
1721 GtkStyleProperties *props,
1722 GtkStateFlags state)
1724 PangoFontDescription *description;
1727 PangoVariant variant;
1731 gtk_style_properties_get (props,
1733 "font-family", &families,
1734 "font-style", &style,
1735 "font-variant", &variant,
1736 "font-weight", &weight,
1740 description = pango_font_description_new ();
1741 /* xxx: Can we set all the families here somehow? */
1743 pango_font_description_set_family (description, families[0]);
1744 pango_font_description_set_size (description, round (size * PANGO_SCALE));
1745 pango_font_description_set_style (description, style);
1746 pango_font_description_set_variant (description, variant);
1747 pango_font_description_set_weight (description, weight);
1751 g_value_take_boxed (value, description);
1757 css_string_funcs_init (void)
1759 if (G_LIKELY (parse_funcs != NULL))
1762 parse_funcs = g_hash_table_new (NULL, NULL);
1763 print_funcs = g_hash_table_new (NULL, NULL);
1765 register_conversion_function (GDK_TYPE_RGBA,
1768 register_conversion_function (GDK_TYPE_COLOR,
1771 register_conversion_function (GTK_TYPE_SYMBOLIC_COLOR,
1772 symbolic_color_value_parse,
1773 symbolic_color_value_print);
1774 register_conversion_function (PANGO_TYPE_FONT_DESCRIPTION,
1775 font_description_value_parse,
1776 font_description_value_print);
1777 register_conversion_function (G_TYPE_BOOLEAN,
1778 boolean_value_parse,
1779 boolean_value_print);
1780 register_conversion_function (G_TYPE_INT,
1783 register_conversion_function (G_TYPE_UINT,
1786 register_conversion_function (G_TYPE_DOUBLE,
1788 double_value_print);
1789 register_conversion_function (G_TYPE_FLOAT,
1792 register_conversion_function (G_TYPE_STRING,
1794 string_value_print);
1795 register_conversion_function (GTK_TYPE_THEMING_ENGINE,
1796 theming_engine_value_parse,
1797 theming_engine_value_print);
1798 register_conversion_function (GTK_TYPE_ANIMATION_DESCRIPTION,
1799 animation_description_value_parse,
1800 animation_description_value_print);
1801 register_conversion_function (GTK_TYPE_BORDER,
1803 border_value_print);
1804 register_conversion_function (GTK_TYPE_GRADIENT,
1805 gradient_value_parse,
1806 gradient_value_print);
1807 register_conversion_function (CAIRO_GOBJECT_TYPE_PATTERN,
1808 pattern_value_parse,
1810 register_conversion_function (GTK_TYPE_9SLICE,
1813 register_conversion_function (GTK_TYPE_SHADOW,
1815 shadow_value_print);
1816 register_conversion_function (G_TYPE_ENUM,
1819 register_conversion_function (G_TYPE_FLAGS,
1825 _gtk_style_property_parse_value (const GtkStyleProperty *property,
1827 GtkCssParser *parser,
1830 GtkStyleParseFunc func;
1832 g_return_val_if_fail (value != NULL, FALSE);
1833 g_return_val_if_fail (parser != NULL, FALSE);
1835 css_string_funcs_init ();
1839 if (_gtk_css_parser_try (parser, "none", TRUE))
1841 /* Insert the default value, so it has an opportunity
1842 * to override other style providers when merged
1844 g_param_value_set_default (property->pspec, value);
1847 else if (property->property_parse_func)
1849 GError *error = NULL;
1853 value_str = _gtk_css_parser_read_value (parser);
1854 if (value_str == NULL)
1857 success = (*property->property_parse_func) (value_str, value, &error);
1864 func = property->parse_func;
1870 func = g_hash_table_lookup (parse_funcs,
1871 GSIZE_TO_POINTER (G_VALUE_TYPE (value)));
1873 func = g_hash_table_lookup (parse_funcs,
1874 GSIZE_TO_POINTER (g_type_fundamental (G_VALUE_TYPE (value))));
1878 _gtk_css_parser_error (parser,
1879 "Cannot convert to type '%s'",
1880 g_type_name (G_VALUE_TYPE (value)));
1884 return (*func) (parser, base, value);
1888 _gtk_style_property_print_value (const GtkStyleProperty *property,
1889 const GValue *value,
1892 GtkStylePrintFunc func;
1894 css_string_funcs_init ();
1897 func = property->print_func;
1902 func = g_hash_table_lookup (print_funcs,
1903 GSIZE_TO_POINTER (G_VALUE_TYPE (value)));
1905 func = g_hash_table_lookup (print_funcs,
1906 GSIZE_TO_POINTER (g_type_fundamental (G_VALUE_TYPE (value))));
1910 char *s = g_strdup_value_contents (value);
1911 g_string_append (string, s);
1916 func (value, string);
1920 _gtk_style_property_default_value (const GtkStyleProperty *property,
1921 GtkStyleProperties *properties,
1924 if (property->default_value_func)
1925 property->default_value_func (properties, value);
1926 else if (property->pspec->value_type == GTK_TYPE_THEMING_ENGINE)
1927 g_value_set_object (value, gtk_theming_engine_load (NULL));
1928 else if (property->pspec->value_type == PANGO_TYPE_FONT_DESCRIPTION)
1929 g_value_take_boxed (value, pango_font_description_from_string ("Sans 10"));
1930 else if (property->pspec->value_type == GDK_TYPE_RGBA)
1933 gdk_rgba_parse (&color, "pink");
1934 g_value_set_boxed (value, &color);
1936 else if (property->pspec->value_type == GTK_TYPE_BORDER)
1938 g_value_take_boxed (value, gtk_border_new ());
1941 g_param_value_set_default (property->pspec, value);
1945 _gtk_style_property_is_inherit (const GtkStyleProperty *property)
1947 g_return_val_if_fail (property != NULL, FALSE);
1949 return property->flags & GTK_STYLE_PROPERTY_INHERIT ||
1950 gtk_style_param_get_inherit (property->pspec);
1954 _gtk_style_property_is_shorthand (const GtkStyleProperty *property)
1956 g_return_val_if_fail (property != NULL, FALSE);
1958 return property->pack_func != NULL;
1962 _gtk_style_property_unpack (const GtkStyleProperty *property,
1963 const GValue *value,
1966 g_return_val_if_fail (property != NULL, NULL);
1967 g_return_val_if_fail (property->unpack_func != NULL, NULL);
1968 g_return_val_if_fail (value != NULL, NULL);
1969 g_return_val_if_fail (n_params != NULL, NULL);
1971 return property->unpack_func (value, n_params);
1975 _gtk_style_property_pack (const GtkStyleProperty *property,
1976 GtkStyleProperties *props,
1977 GtkStateFlags state,
1980 g_return_if_fail (property != NULL);
1981 g_return_if_fail (property->pack_func != NULL);
1982 g_return_if_fail (GTK_IS_STYLE_PROPERTIES (props));
1983 g_return_if_fail (G_IS_VALUE (value));
1985 property->pack_func (value, props, state);
1989 gtk_style_property_init (void)
1993 if (G_LIKELY (properties))
1996 /* stuff is never freed, so no need for free functions */
1997 properties = g_hash_table_new (g_str_hash, g_str_equal);
1999 /* note that gtk_style_properties_register_property() calls this function,
2000 * so make sure we're sanely inited to avoid infloops */
2002 pspec = g_param_spec_boxed ("color",
2006 gtk_style_param_set_inherit (pspec, TRUE);
2007 gtk_style_properties_register_property (NULL, pspec);
2009 gtk_style_properties_register_property (NULL,
2010 g_param_spec_boxed ("background-color",
2015 pspec = g_param_spec_boxed ("font-family",
2019 gtk_style_param_set_inherit (pspec, TRUE);
2020 _gtk_style_property_register (pspec,
2026 font_family_value_print,
2028 pspec = g_param_spec_enum ("font-style",
2032 PANGO_STYLE_NORMAL, 0);
2033 gtk_style_param_set_inherit (pspec, TRUE);
2034 gtk_style_properties_register_property (NULL, pspec);
2035 pspec = g_param_spec_enum ("font-variant",
2039 PANGO_VARIANT_NORMAL, 0);
2040 gtk_style_param_set_inherit (pspec, TRUE);
2041 gtk_style_properties_register_property (NULL, pspec);
2042 /* xxx: need to parse this properly, ie parse the numbers */
2043 pspec = g_param_spec_enum ("font-weight",
2047 PANGO_WEIGHT_NORMAL, 0);
2048 gtk_style_param_set_inherit (pspec, TRUE);
2049 gtk_style_properties_register_property (NULL, pspec);
2050 pspec = g_param_spec_double ("font-size",
2053 0, G_MAXDOUBLE, 0, 0);
2054 gtk_style_param_set_inherit (pspec, TRUE);
2055 gtk_style_properties_register_property (NULL, pspec);
2056 pspec = g_param_spec_boxed ("font",
2059 PANGO_TYPE_FONT_DESCRIPTION, 0);
2060 gtk_style_param_set_inherit (pspec, TRUE);
2061 _gtk_style_property_register (pspec,
2064 unpack_font_description,
2065 pack_font_description,
2066 font_description_value_parse,
2067 font_description_value_print,
2070 pspec = g_param_spec_boxed ("text-shadow",
2073 GTK_TYPE_SHADOW, 0);
2074 gtk_style_param_set_inherit (pspec, TRUE);
2075 gtk_style_properties_register_property (NULL, pspec);
2077 gtk_style_properties_register_property (NULL,
2078 g_param_spec_int ("margin-top",
2081 0, G_MAXINT, 0, 0));
2082 gtk_style_properties_register_property (NULL,
2083 g_param_spec_int ("margin-left",
2086 0, G_MAXINT, 0, 0));
2087 gtk_style_properties_register_property (NULL,
2088 g_param_spec_int ("margin-bottom",
2091 0, G_MAXINT, 0, 0));
2092 gtk_style_properties_register_property (NULL,
2093 g_param_spec_int ("margin-right",
2096 0, G_MAXINT, 0, 0));
2097 _gtk_style_property_register (g_param_spec_boxed ("margin",
2100 GTK_TYPE_BORDER, 0),
2108 gtk_style_properties_register_property (NULL,
2109 g_param_spec_int ("padding-top",
2112 0, G_MAXINT, 0, 0));
2113 gtk_style_properties_register_property (NULL,
2114 g_param_spec_int ("padding-left",
2117 0, G_MAXINT, 0, 0));
2118 gtk_style_properties_register_property (NULL,
2119 g_param_spec_int ("padding-bottom",
2121 "Padding at bottom",
2122 0, G_MAXINT, 0, 0));
2123 gtk_style_properties_register_property (NULL,
2124 g_param_spec_int ("padding-right",
2127 0, G_MAXINT, 0, 0));
2128 _gtk_style_property_register (g_param_spec_boxed ("padding",
2131 GTK_TYPE_BORDER, 0),
2139 gtk_style_properties_register_property (NULL,
2140 g_param_spec_int ("border-top-width",
2142 "Border width at top",
2143 0, G_MAXINT, 0, 0));
2144 gtk_style_properties_register_property (NULL,
2145 g_param_spec_int ("border-left-width",
2146 "border left width",
2147 "Border width at left",
2148 0, G_MAXINT, 0, 0));
2149 gtk_style_properties_register_property (NULL,
2150 g_param_spec_int ("border-bottom-width",
2151 "border bottom width",
2152 "Border width at bottom",
2153 0, G_MAXINT, 0, 0));
2154 gtk_style_properties_register_property (NULL,
2155 g_param_spec_int ("border-right-width",
2156 "border right width",
2157 "Border width at right",
2158 0, G_MAXINT, 0, 0));
2159 _gtk_style_property_register (g_param_spec_boxed ("border-width",
2161 "Border width, in pixels",
2162 GTK_TYPE_BORDER, 0),
2165 unpack_border_width,
2171 _gtk_style_property_register (g_param_spec_boxed ("border-top-left-radius",
2172 "Border top left radius",
2173 "Border radius of top left corner, in pixels",
2174 GTK_TYPE_CSS_BORDER_CORNER_RADIUS, 0),
2179 border_corner_radius_value_parse,
2180 border_corner_radius_value_print,
2182 _gtk_style_property_register (g_param_spec_boxed ("border-top-right-radius",
2183 "Border top right radius",
2184 "Border radius of top right corner, in pixels",
2185 GTK_TYPE_CSS_BORDER_CORNER_RADIUS, 0),
2190 border_corner_radius_value_parse,
2191 border_corner_radius_value_print,
2193 _gtk_style_property_register (g_param_spec_boxed ("border-bottom-right-radius",
2194 "Border bottom right radius",
2195 "Border radius of bottom right corner, in pixels",
2196 GTK_TYPE_CSS_BORDER_CORNER_RADIUS, 0),
2201 border_corner_radius_value_parse,
2202 border_corner_radius_value_print,
2204 _gtk_style_property_register (g_param_spec_boxed ("border-bottom-left-radius",
2205 "Border bottom left radius",
2206 "Border radius of bottom left corner, in pixels",
2207 GTK_TYPE_CSS_BORDER_CORNER_RADIUS, 0),
2212 border_corner_radius_value_parse,
2213 border_corner_radius_value_print,
2215 _gtk_style_property_register (g_param_spec_int ("border-radius",
2217 "Border radius, in pixels",
2221 unpack_border_radius,
2223 border_radius_value_parse,
2224 border_radius_value_print,
2227 gtk_style_properties_register_property (NULL,
2228 g_param_spec_enum ("border-style",
2231 GTK_TYPE_BORDER_STYLE,
2232 GTK_BORDER_STYLE_NONE, 0));
2233 gtk_style_properties_register_property (NULL,
2234 g_param_spec_boxed ("border-color",
2238 gtk_style_properties_register_property (NULL,
2239 g_param_spec_boxed ("background-image",
2242 CAIRO_GOBJECT_TYPE_PATTERN, 0));
2243 gtk_style_properties_register_property (NULL,
2244 g_param_spec_boxed ("border-image",
2247 GTK_TYPE_9SLICE, 0));
2248 gtk_style_properties_register_property (NULL,
2249 g_param_spec_object ("engine",
2252 GTK_TYPE_THEMING_ENGINE, 0));
2253 gtk_style_properties_register_property (NULL,
2254 g_param_spec_boxed ("transition",
2255 "Transition animation description",
2256 "Transition animation description",
2257 GTK_TYPE_ANIMATION_DESCRIPTION, 0));
2259 /* Private property holding the binding sets */
2260 _gtk_style_property_register (g_param_spec_boxed ("gtk-key-bindings",
2263 G_TYPE_PTR_ARRAY, 0),
2268 bindings_value_parse,
2269 bindings_value_print,
2273 const GtkStyleProperty *
2274 _gtk_style_property_lookup (const char *name)
2276 gtk_style_property_init ();
2278 return g_hash_table_lookup (properties, name);
2282 _gtk_style_property_register (GParamSpec *pspec,
2283 GtkStylePropertyFlags flags,
2284 GtkStylePropertyParser property_parse_func,
2285 GtkStyleUnpackFunc unpack_func,
2286 GtkStylePackFunc pack_func,
2287 GtkStyleParseFunc parse_func,
2288 GtkStylePrintFunc print_func,
2289 GtkStyleDefaultValueFunc default_value_func)
2291 const GtkStyleProperty *existing;
2292 GtkStyleProperty *node;
2294 g_return_if_fail ((pack_func == NULL) == (unpack_func == NULL));
2296 gtk_style_property_init ();
2298 existing = _gtk_style_property_lookup (pspec->name);
2299 if (existing != NULL)
2301 g_warning ("Property \"%s\" was already registered with type %s",
2302 pspec->name, g_type_name (existing->pspec->value_type));
2306 node = g_slice_new0 (GtkStyleProperty);
2307 node->flags = flags;
2308 node->pspec = pspec;
2309 node->property_parse_func = property_parse_func;
2310 node->pack_func = pack_func;
2311 node->unpack_func = unpack_func;
2312 node->parse_func = parse_func;
2313 node->print_func = print_func;
2314 node->default_value_func = default_value_func;
2316 g_hash_table_insert (properties, pspec->name, node);