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 "gtkcssstringfuncsprivate.h"
28 #include <gdk-pixbuf/gdk-pixbuf.h>
29 #include <cairo-gobject.h>
31 #include "gtkcssprovider.h"
33 /* the actual parsers we have */
34 #include "gtkanimationdescription.h"
35 #include "gtk9slice.h"
36 #include "gtkgradient.h"
37 #include "gtkthemingengine.h"
39 typedef gboolean (* FromStringFunc) (const char *str,
43 typedef char * (* ToStringFunc) (const GValue *value);
45 static GHashTable *from_string_funcs = NULL;
46 static GHashTable *to_string_funcs = NULL;
49 register_conversion_function (GType type,
50 FromStringFunc from_string,
51 ToStringFunc to_string)
54 g_hash_table_insert (from_string_funcs, GSIZE_TO_POINTER (type), from_string);
56 g_hash_table_insert (to_string_funcs, GSIZE_TO_POINTER (type), to_string);
60 set_default_error (GError **error,
64 GTK_CSS_PROVIDER_ERROR,
65 GTK_CSS_PROVIDER_ERROR_PROPERTY_VALUE,
66 "Could not convert property value to type '%s'",
71 /*** IMPLEMENTATIONS ***/
73 #define SKIP_SPACES(s) while (g_ascii_isspace (*(s))) (s)++
74 #define SKIP_SPACES_BACK(s) while (g_ascii_isspace (*(s))) (s)--
76 static GtkSymbolicColor *
77 symbolic_color_parse_str (const gchar *string,
80 GtkSymbolicColor *symbolic_color = NULL;
83 str = (gchar *) string;
94 while (*end == '-' || *end == '_' || g_ascii_isalnum (*end))
97 name = g_strndup (str, end - str);
98 symbolic_color = gtk_symbolic_color_new_name (name);
101 *end_ptr = (gchar *) end;
103 else if (g_str_has_prefix (str, "lighter") ||
104 g_str_has_prefix (str, "darker"))
106 GtkSymbolicColor *param_color;
107 gboolean is_lighter = FALSE;
109 is_lighter = g_str_has_prefix (str, "lighter");
112 str += strlen ("lighter");
114 str += strlen ("darker");
120 *end_ptr = (gchar *) str;
126 param_color = symbolic_color_parse_str (str, end_ptr);
133 *end_ptr = (gchar *) str;
137 gtk_symbolic_color_unref (param_color);
142 symbolic_color = gtk_symbolic_color_new_shade (param_color, 1.3);
144 symbolic_color = gtk_symbolic_color_new_shade (param_color, 0.7);
146 gtk_symbolic_color_unref (param_color);
149 else if (g_str_has_prefix (str, "shade") ||
150 g_str_has_prefix (str, "alpha"))
152 GtkSymbolicColor *param_color;
153 gboolean is_shade = FALSE;
156 is_shade = g_str_has_prefix (str, "shade");
159 str += strlen ("shade");
161 str += strlen ("alpha");
167 *end_ptr = (gchar *) str;
173 param_color = symbolic_color_parse_str (str, end_ptr);
183 gtk_symbolic_color_unref (param_color);
184 *end_ptr = (gchar *) str;
190 factor = g_ascii_strtod (str, end_ptr);
194 *end_ptr = (gchar *) str;
198 gtk_symbolic_color_unref (param_color);
203 symbolic_color = gtk_symbolic_color_new_shade (param_color, factor);
205 symbolic_color = gtk_symbolic_color_new_alpha (param_color, factor);
207 gtk_symbolic_color_unref (param_color);
210 else if (g_str_has_prefix (str, "mix"))
212 GtkSymbolicColor *color1, *color2;
215 str += strlen ("mix");
220 *end_ptr = (gchar *) str;
226 color1 = symbolic_color_parse_str (str, end_ptr);
236 gtk_symbolic_color_unref (color1);
237 *end_ptr = (gchar *) str;
243 color2 = symbolic_color_parse_str (str, end_ptr);
245 if (!color2 || *end_ptr[0] != ',')
247 gtk_symbolic_color_unref (color1);
256 gtk_symbolic_color_unref (color1);
257 gtk_symbolic_color_unref (color2);
258 *end_ptr = (gchar *) str;
264 factor = g_ascii_strtod (str, end_ptr);
268 *end_ptr = (gchar *) str;
272 gtk_symbolic_color_unref (color1);
273 gtk_symbolic_color_unref (color2);
277 symbolic_color = gtk_symbolic_color_new_mix (color1, color2, factor);
278 gtk_symbolic_color_unref (color1);
279 gtk_symbolic_color_unref (color2);
292 /* Color in hex format */
293 while (g_ascii_isxdigit (*end))
296 else if (g_str_has_prefix (str, "rgb"))
298 /* color in rgb/rgba format */
299 while (*end != ')' && *end != '\0')
308 while (*end != '\0' &&
309 (g_ascii_isalnum (*end) || *end == ' '))
313 color_str = g_strndup (str, end - str);
314 *end_ptr = (gchar *) end;
316 if (!gdk_rgba_parse (&color, color_str))
322 symbolic_color = gtk_symbolic_color_new_literal (&color);
326 return symbolic_color;
330 rgba_value_from_string (const char *str,
335 GtkSymbolicColor *symbolic;
338 if (gdk_rgba_parse (&rgba, str))
340 g_value_set_boxed (value, &rgba);
344 symbolic = _gtk_css_parse_symbolic_color (str, error);
345 if (symbolic == NULL)
348 g_value_unset (value);
349 g_value_init (value, GTK_TYPE_SYMBOLIC_COLOR);
350 g_value_take_boxed (value, symbolic);
355 rgba_value_to_string (const GValue *value)
357 const GdkRGBA *rgba = g_value_get_boxed (value);
360 return g_strdup ("none");
362 return gdk_rgba_to_string (rgba);
366 color_value_from_string (const char *str,
371 GtkSymbolicColor *symbolic;
374 if (gdk_color_parse (str, &color))
376 g_value_set_boxed (value, &color);
380 symbolic = _gtk_css_parse_symbolic_color (str, error);
381 if (symbolic == NULL)
384 g_value_unset (value);
385 g_value_init (value, GTK_TYPE_SYMBOLIC_COLOR);
386 g_value_take_boxed (value, symbolic);
391 color_value_to_string (const GValue *value)
393 const GdkColor *color = g_value_get_boxed (value);
396 return g_strdup ("none");
398 return gdk_color_to_string (color);
402 symbolic_color_value_from_string (const char *str,
407 GtkSymbolicColor *symbolic;
409 symbolic = _gtk_css_parse_symbolic_color (str, error);
410 if (symbolic == NULL)
413 g_value_take_boxed (value, symbolic);
418 symbolic_color_value_to_string (const GValue *value)
420 GtkSymbolicColor *symbolic = g_value_get_boxed (value);
422 if (symbolic == NULL)
423 return g_strdup ("none");
425 return gtk_symbolic_color_to_string (symbolic);
429 font_description_value_from_string (const char *str,
434 PangoFontDescription *font_desc;
436 font_desc = pango_font_description_from_string (str);
437 g_value_take_boxed (value, font_desc);
442 font_description_value_to_string (const GValue *value)
444 const PangoFontDescription *desc = g_value_get_boxed (value);
447 return g_strdup ("none");
449 return pango_font_description_to_string (desc);
453 boolean_value_from_string (const char *str,
458 if (g_ascii_strcasecmp (str, "true") == 0 ||
459 g_ascii_strcasecmp (str, "1") == 0)
461 g_value_set_boolean (value, TRUE);
464 else if (g_ascii_strcasecmp (str, "false") == 0 ||
465 g_ascii_strcasecmp (str, "0") == 0)
467 g_value_set_boolean (value, FALSE);
471 return set_default_error (error, G_VALUE_TYPE (value));
475 boolean_value_to_string (const GValue *value)
477 if (g_value_get_boolean (value))
478 return g_strdup ("true");
480 return g_strdup ("false");
484 int_value_from_string (const char *str,
492 i = g_ascii_strtoll (str, &end, 10);
495 return set_default_error (error, G_VALUE_TYPE (value));
497 if (i > G_MAXINT || i < G_MININT)
499 g_set_error_literal (error,
500 GTK_CSS_PROVIDER_ERROR,
501 GTK_CSS_PROVIDER_ERROR_PROPERTY_VALUE,
506 g_value_set_int (value, i);
511 int_value_to_string (const GValue *value)
513 return g_strdup_printf ("%d", g_value_get_int (value));
517 uint_value_from_string (const char *str,
525 u = g_ascii_strtoull (str, &end, 10);
528 return set_default_error (error, G_VALUE_TYPE (value));
532 g_set_error_literal (error,
533 GTK_CSS_PROVIDER_ERROR,
534 GTK_CSS_PROVIDER_ERROR_PROPERTY_VALUE,
539 g_value_set_uint (value, u);
544 uint_value_to_string (const GValue *value)
546 return g_strdup_printf ("%u", g_value_get_uint (value));
550 double_value_from_string (const char *str,
558 d = g_ascii_strtod (str, &end);
561 return set_default_error (error, G_VALUE_TYPE (value));
565 g_set_error_literal (error,
566 GTK_CSS_PROVIDER_ERROR,
567 GTK_CSS_PROVIDER_ERROR_PROPERTY_VALUE,
568 "Number not representable");
572 g_value_set_double (value, d);
577 double_value_to_string (const GValue *value)
579 char buf[G_ASCII_DTOSTR_BUF_SIZE];
581 g_ascii_dtostr (buf, sizeof (buf), g_value_get_double (value));
583 return g_strdup (buf);
587 float_value_from_string (const char *str,
595 d = g_ascii_strtod (str, &end);
598 return set_default_error (error, G_VALUE_TYPE (value));
602 g_set_error_literal (error,
603 GTK_CSS_PROVIDER_ERROR,
604 GTK_CSS_PROVIDER_ERROR_PROPERTY_VALUE,
605 "Number not representable");
609 g_value_set_float (value, d);
614 float_value_to_string (const GValue *value)
616 char buf[G_ASCII_DTOSTR_BUF_SIZE];
618 g_ascii_dtostr (buf, sizeof (buf), g_value_get_float (value));
620 return g_strdup (buf);
624 gtk_css_string_unescape (const char *string,
633 if (quote != '\'' && quote != '"')
635 g_set_error_literal (error,
636 GTK_CSS_PROVIDER_ERROR,
637 GTK_CSS_PROVIDER_ERROR_PROPERTY_VALUE,
638 "String value not properly quoted.");
642 str = g_string_new (NULL);
646 len = strcspn (string, "\\'\"\n\r\f");
648 g_string_append_len (str, string, len);
656 if (string[0] >= '0' && string[0] <= '9' &&
657 string[0] >= 'a' && string[0] <= 'f' &&
658 string[0] >= 'A' && string[0] <= 'F')
660 g_set_error_literal (error,
661 GTK_CSS_PROVIDER_ERROR,
662 GTK_CSS_PROVIDER_ERROR_PROPERTY_VALUE,
663 "FIXME: Implement unicode escape sequences.");
664 g_string_free (str, TRUE);
667 else if (string[0] == '\r' && string[1] == '\n')
669 else if (string[0] != '\r' && string[0] != '\n' && string[0] != '\f')
670 g_string_append_c (str, string[0]);
674 if (string[0] != quote)
676 g_string_append_c (str, string[0]);
682 return g_string_free (str, FALSE);
686 g_set_error_literal (error,
687 GTK_CSS_PROVIDER_ERROR,
688 GTK_CSS_PROVIDER_ERROR_PROPERTY_VALUE,
689 "Junk after end of string.");
690 g_string_free (str, TRUE);
696 g_set_error_literal (error,
697 GTK_CSS_PROVIDER_ERROR,
698 GTK_CSS_PROVIDER_ERROR_PROPERTY_VALUE,
699 "Missing end quote in string.");
700 g_string_free (str, TRUE);
703 g_set_error_literal (error,
704 GTK_CSS_PROVIDER_ERROR,
705 GTK_CSS_PROVIDER_ERROR_PROPERTY_VALUE,
706 "Invalid character in string. Must be escaped.");
707 g_string_free (str, TRUE);
714 g_assert_not_reached ();
719 string_value_from_string (const char *str,
724 char *unescaped = gtk_css_string_unescape (str, error);
726 if (unescaped == NULL)
729 g_value_take_string (value, unescaped);
734 string_value_to_string (const GValue *value)
740 string = g_value_get_string (value);
741 str = g_string_new ("\"");
744 len = strcspn (string, "\"\n\r\f");
745 g_string_append (str, string);
752 g_string_append (str, "\\A ");
755 g_string_append (str, "\\D ");
758 g_string_append (str, "\\C ");
761 g_string_append (str, "\\\"");
764 g_assert_not_reached ();
769 g_string_append_c (str, '"');
770 return g_string_free (str, FALSE);
774 theming_engine_value_from_string (const char *str,
779 GtkThemingEngine *engine;
781 engine = gtk_theming_engine_load (str);
785 GTK_CSS_PROVIDER_ERROR,
786 GTK_CSS_PROVIDER_ERROR_PROPERTY_VALUE,
787 "Themeing engine '%s' not found", str);
791 g_value_set_object (value, engine);
796 theming_engine_value_to_string (const GValue *value)
798 GtkThemingEngine *engine;
801 engine = g_value_get_object (value);
803 return g_strdup ("none");
805 /* XXX: gtk_theming_engine_get_name()? */
806 g_object_get (engine, "name", &name, NULL);
812 animation_description_value_from_string (const char *str,
817 GtkAnimationDescription *desc;
819 desc = _gtk_animation_description_from_string (str);
822 return set_default_error (error, G_VALUE_TYPE (value));
824 g_value_take_boxed (value, desc);
829 animation_description_value_to_string (const GValue *value)
831 GtkAnimationDescription *desc = g_value_get_boxed (value);
834 return g_strdup ("none");
836 return _gtk_animation_description_to_string (desc);
840 parse_border_value (const char *str,
847 d = g_ascii_strtoll (str, (char **) end, 10);
849 if (d > G_MAXINT16 || d < 0)
851 g_set_error_literal (error,
852 GTK_CSS_PROVIDER_ERROR,
853 GTK_CSS_PROVIDER_ERROR_PROPERTY_VALUE,
854 "Number out of range for border");
860 g_set_error_literal (error,
861 GTK_CSS_PROVIDER_ERROR,
862 GTK_CSS_PROVIDER_ERROR_PROPERTY_VALUE,
863 "No number given for border value");
867 /* Skip optional unit type.
868 * We only handle pixels at the moment.
870 if (strncmp (*end, "px", 2) == 0)
874 !g_ascii_isspace (**end))
876 g_set_error_literal (error,
877 GTK_CSS_PROVIDER_ERROR,
878 GTK_CSS_PROVIDER_ERROR_PROPERTY_VALUE,
879 "Junk at end of border value");
890 border_value_from_string (const char *str,
897 border = gtk_border_new ();
899 if (!parse_border_value (str, &border->top, &str, error))
903 border->right = border->top;
905 if (!parse_border_value (str, &border->right, &str, error))
909 border->bottom = border->top;
911 if (!parse_border_value (str, &border->bottom, &str, error))
915 border->left = border->right;
917 if (!parse_border_value (str, &border->left, &str, error))
922 g_set_error_literal (error,
923 GTK_CSS_PROVIDER_ERROR,
924 GTK_CSS_PROVIDER_ERROR_PROPERTY_VALUE,
925 "Junk at end of border value");
929 g_value_take_boxed (value, border);
934 border_value_to_string (const GValue *value)
936 const GtkBorder *border = g_value_get_boxed (value);
939 return g_strdup ("none");
940 else if (border->left != border->right)
941 return g_strdup_printf ("%d %d %d %d", border->top, border->right, border->bottom, border->left);
942 else if (border->top != border->bottom)
943 return g_strdup_printf ("%d %d %d", border->top, border->right, border->bottom);
944 else if (border->top != border->left)
945 return g_strdup_printf ("%d %d", border->top, border->right);
947 return g_strdup_printf ("%d", border->top);
951 gradient_value_from_string (const char *str,
956 GtkGradient *gradient;
957 cairo_pattern_type_t type;
962 str += strlen ("-gtk-gradient");
967 g_set_error_literal (error,
968 GTK_CSS_PROVIDER_ERROR,
969 GTK_CSS_PROVIDER_ERROR_PROPERTY_VALUE,
970 "Expected '(' after '-gtk-gradient'");
977 /* Parse gradient type */
978 if (g_str_has_prefix (str, "linear"))
980 type = CAIRO_PATTERN_TYPE_LINEAR;
981 str += strlen ("linear");
983 else if (g_str_has_prefix (str, "radial"))
985 type = CAIRO_PATTERN_TYPE_RADIAL;
986 str += strlen ("radial");
990 g_set_error_literal (error,
991 GTK_CSS_PROVIDER_ERROR,
992 GTK_CSS_PROVIDER_ERROR_PROPERTY_VALUE,
993 "Gradient type must be 'radial' or 'linear'");
999 /* Parse start/stop position parameters */
1000 for (i = 0; i < 2; i++)
1004 g_set_error_literal (error,
1005 GTK_CSS_PROVIDER_ERROR,
1006 GTK_CSS_PROVIDER_ERROR_PROPERTY_VALUE,
1014 if (strncmp (str, "left", 4) == 0)
1017 str += strlen ("left");
1019 else if (strncmp (str, "right", 5) == 0)
1022 str += strlen ("right");
1024 else if (strncmp (str, "center", 6) == 0)
1026 coords[i * 3] = 0.5;
1027 str += strlen ("center");
1031 coords[i * 3] = g_ascii_strtod (str, &end);
1034 return set_default_error (error, G_VALUE_TYPE (value));
1041 if (strncmp (str, "top", 3) == 0)
1043 coords[(i * 3) + 1] = 0;
1044 str += strlen ("top");
1046 else if (strncmp (str, "bottom", 6) == 0)
1048 coords[(i * 3) + 1] = 1;
1049 str += strlen ("bottom");
1051 else if (strncmp (str, "center", 6) == 0)
1053 coords[(i * 3) + 1] = 0.5;
1054 str += strlen ("center");
1058 coords[(i * 3) + 1] = g_ascii_strtod (str, &end);
1061 return set_default_error (error, G_VALUE_TYPE (value));
1068 if (type == CAIRO_PATTERN_TYPE_RADIAL)
1073 g_set_error_literal (error,
1074 GTK_CSS_PROVIDER_ERROR,
1075 GTK_CSS_PROVIDER_ERROR_PROPERTY_VALUE,
1083 coords[(i * 3) + 2] = g_ascii_strtod (str, &end);
1090 if (type == CAIRO_PATTERN_TYPE_LINEAR)
1091 gradient = gtk_gradient_new_linear (coords[0], coords[1], coords[3], coords[4]);
1093 gradient = gtk_gradient_new_radial (coords[0], coords[1], coords[2],
1094 coords[3], coords[4], coords[5]);
1098 GtkSymbolicColor *color;
1104 if (g_str_has_prefix (str, "from"))
1107 str += strlen ("from");
1112 g_object_unref (gradient);
1113 return set_default_error (error, G_VALUE_TYPE (value));
1116 else if (g_str_has_prefix (str, "to"))
1119 str += strlen ("to");
1124 g_object_unref (gradient);
1125 return set_default_error (error, G_VALUE_TYPE (value));
1128 else if (g_str_has_prefix (str, "color-stop"))
1130 str += strlen ("color-stop");
1135 g_object_unref (gradient);
1136 return set_default_error (error, G_VALUE_TYPE (value));
1142 position = g_ascii_strtod (str, &end);
1149 g_object_unref (gradient);
1150 return set_default_error (error, G_VALUE_TYPE (value));
1155 g_object_unref (gradient);
1156 return set_default_error (error, G_VALUE_TYPE (value));
1162 color = symbolic_color_parse_str (str, &end);
1170 gtk_symbolic_color_unref (color);
1171 g_object_unref (gradient);
1172 return set_default_error (error, G_VALUE_TYPE (value));
1180 gtk_gradient_add_color_stop (gradient, position, color);
1181 gtk_symbolic_color_unref (color);
1187 g_object_unref (gradient);
1188 return set_default_error (error, G_VALUE_TYPE (value));
1191 g_value_take_boxed (value, gradient);
1196 gradient_value_to_string (const GValue *value)
1198 GtkGradient *gradient = g_value_get_boxed (value);
1200 if (gradient == NULL)
1201 return g_strdup ("none");
1203 return gtk_gradient_to_string (gradient);
1207 pattern_value_from_string (const char *str,
1212 if (g_str_has_prefix (str, "-gtk-gradient"))
1214 g_value_unset (value);
1215 g_value_init (value, GTK_TYPE_GRADIENT);
1216 return gradient_value_from_string (str, base, value, error);
1224 file = _gtk_css_parse_url (base, str, NULL, error);
1228 path = g_file_get_path (file);
1229 g_object_unref (file);
1231 pixbuf = gdk_pixbuf_new_from_file (path, error);
1236 cairo_surface_t *surface;
1237 cairo_pattern_t *pattern;
1239 cairo_matrix_t matrix;
1241 surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
1242 gdk_pixbuf_get_width (pixbuf),
1243 gdk_pixbuf_get_height (pixbuf));
1244 cr = cairo_create (surface);
1245 gdk_cairo_set_source_pixbuf (cr, pixbuf, 0, 0);
1247 pattern = cairo_pattern_create_for_surface (surface);
1249 cairo_matrix_init_scale (&matrix,
1250 gdk_pixbuf_get_width (pixbuf),
1251 gdk_pixbuf_get_height (pixbuf));
1252 cairo_pattern_set_matrix (pattern, &matrix);
1254 cairo_surface_destroy (surface);
1256 g_object_unref (pixbuf);
1258 g_value_take_boxed (value, pattern);
1265 slice_value_from_string (const char *str,
1270 gdouble distance_top, distance_bottom;
1271 gdouble distance_left, distance_right;
1272 GtkSliceSideModifier mods[2];
1281 /* Parse image url */
1282 file = _gtk_css_parse_url (base, str, (char **) &str, error);
1288 /* Parse top/left/bottom/right distances */
1289 distance_top = g_ascii_strtod (str, (char **) &str);
1293 distance_right = g_ascii_strtod (str, (char **) &str);
1297 distance_bottom = g_ascii_strtod (str, (char **) &str);
1301 distance_left = g_ascii_strtod (str, (char **) &str);
1305 while (*str && i < 2)
1307 if (g_str_has_prefix (str, "stretch"))
1309 str += strlen ("stretch");
1310 mods[i] = GTK_SLICE_STRETCH;
1312 else if (g_str_has_prefix (str, "repeat"))
1314 str += strlen ("repeat");
1315 mods[i] = GTK_SLICE_REPEAT;
1319 g_object_unref (file);
1320 return set_default_error (error, G_VALUE_TYPE (value));
1329 g_object_unref (file);
1330 return set_default_error (error, G_VALUE_TYPE (value));
1335 /* Fill in second modifier, same as the first */
1339 path = g_file_get_path (file);
1340 pixbuf = gdk_pixbuf_new_from_file (path, error);
1345 slice = _gtk_9slice_new (pixbuf,
1346 distance_top, distance_bottom,
1347 distance_left, distance_right,
1349 g_object_unref (pixbuf);
1351 g_value_take_boxed (value, slice);
1356 enum_value_from_string (const char *str,
1361 GEnumClass *enum_class;
1362 GEnumValue *enum_value;
1364 enum_class = g_type_class_ref (G_VALUE_TYPE (value));
1365 enum_value = g_enum_get_value_by_nick (enum_class, str);
1370 GTK_CSS_PROVIDER_ERROR,
1371 GTK_CSS_PROVIDER_ERROR_FAILED,
1372 "Unknown value '%s' for enum type '%s'",
1373 str, g_type_name (G_VALUE_TYPE (value)));
1374 g_type_class_unref (enum_class);
1378 g_value_set_enum (value, enum_value->value);
1379 g_type_class_unref (enum_class);
1384 enum_value_to_string (const GValue *value)
1386 GEnumClass *enum_class;
1387 GEnumValue *enum_value;
1390 enum_class = g_type_class_ref (G_VALUE_TYPE (value));
1391 enum_value = g_enum_get_value (enum_class, g_value_get_enum (value));
1393 s = g_strdup (enum_value->value_nick);
1395 g_type_class_unref (enum_class);
1401 flags_value_from_string (const char *str,
1406 GFlagsClass *flags_class;
1407 GFlagsValue *flag_value;
1412 strv = g_strsplit (str, ",", -1);
1414 flags_class = g_type_class_ref (G_VALUE_TYPE (value));
1416 for (i = 0; strv[i]; i++)
1418 strv[i] = g_strstrip (strv[i]);
1420 flag_value = g_flags_get_value_by_nick (flags_class, strv[i]);
1424 GTK_CSS_PROVIDER_ERROR,
1425 GTK_CSS_PROVIDER_ERROR_PROPERTY_NAME,
1426 "Unknown flag value '%s' for type '%s'",
1427 strv[i], g_type_name (G_VALUE_TYPE (value)));
1428 g_type_class_unref (flags_class);
1432 flags |= flag_value->value;
1436 g_type_class_unref (flags_class);
1438 g_value_set_enum (value, flags);
1444 flags_value_to_string (const GValue *value)
1446 GFlagsClass *flags_class;
1450 flags_class = g_type_class_ref (G_VALUE_TYPE (value));
1451 flags = g_value_get_flags (value);
1452 string = g_string_new (NULL);
1454 for (i = 0; i < flags_class->n_values; i++)
1456 GFlagsValue *flags_value = &flags_class->values[i];
1458 if (flags & flags_value->value)
1460 if (string->len != 0)
1461 g_string_append (string, ", ");
1463 g_string_append (string, flags_value->value_nick);
1467 g_type_class_unref (flags_class);
1469 return g_string_free (string, FALSE);
1475 css_string_funcs_init (void)
1477 if (G_LIKELY (from_string_funcs != NULL))
1480 from_string_funcs = g_hash_table_new (NULL, NULL);
1481 to_string_funcs = g_hash_table_new (NULL, NULL);
1483 register_conversion_function (GDK_TYPE_RGBA,
1484 rgba_value_from_string,
1485 rgba_value_to_string);
1486 register_conversion_function (GDK_TYPE_COLOR,
1487 color_value_from_string,
1488 color_value_to_string);
1489 register_conversion_function (GTK_TYPE_SYMBOLIC_COLOR,
1490 symbolic_color_value_from_string,
1491 symbolic_color_value_to_string);
1492 register_conversion_function (PANGO_TYPE_FONT_DESCRIPTION,
1493 font_description_value_from_string,
1494 font_description_value_to_string);
1495 register_conversion_function (G_TYPE_BOOLEAN,
1496 boolean_value_from_string,
1497 boolean_value_to_string);
1498 register_conversion_function (G_TYPE_INT,
1499 int_value_from_string,
1500 int_value_to_string);
1501 register_conversion_function (G_TYPE_UINT,
1502 uint_value_from_string,
1503 uint_value_to_string);
1504 register_conversion_function (G_TYPE_DOUBLE,
1505 double_value_from_string,
1506 double_value_to_string);
1507 register_conversion_function (G_TYPE_FLOAT,
1508 float_value_from_string,
1509 float_value_to_string);
1510 register_conversion_function (G_TYPE_STRING,
1511 string_value_from_string,
1512 string_value_to_string);
1513 register_conversion_function (GTK_TYPE_THEMING_ENGINE,
1514 theming_engine_value_from_string,
1515 theming_engine_value_to_string);
1516 register_conversion_function (GTK_TYPE_ANIMATION_DESCRIPTION,
1517 animation_description_value_from_string,
1518 animation_description_value_to_string);
1519 register_conversion_function (GTK_TYPE_BORDER,
1520 border_value_from_string,
1521 border_value_to_string);
1522 register_conversion_function (GTK_TYPE_GRADIENT,
1523 gradient_value_from_string,
1524 gradient_value_to_string);
1525 register_conversion_function (CAIRO_GOBJECT_TYPE_PATTERN,
1526 pattern_value_from_string,
1528 register_conversion_function (GTK_TYPE_9SLICE,
1529 slice_value_from_string,
1531 register_conversion_function (G_TYPE_ENUM,
1532 enum_value_from_string,
1533 enum_value_to_string);
1534 register_conversion_function (G_TYPE_FLAGS,
1535 flags_value_from_string,
1536 flags_value_to_string);
1540 _gtk_css_value_from_string (GValue *value,
1545 FromStringFunc func;
1547 g_return_val_if_fail (string != NULL, FALSE);
1548 g_return_val_if_fail (string[0] != 0, FALSE);
1550 css_string_funcs_init ();
1552 func = g_hash_table_lookup (from_string_funcs,
1553 GSIZE_TO_POINTER (G_VALUE_TYPE (value)));
1555 func = g_hash_table_lookup (from_string_funcs,
1556 GSIZE_TO_POINTER (g_type_fundamental (G_VALUE_TYPE (value))));
1561 GTK_CSS_PROVIDER_ERROR,
1562 GTK_CSS_PROVIDER_ERROR_PROPERTY_VALUE,
1563 "Cannot convert to type '%s'",
1564 g_type_name (G_VALUE_TYPE (value)));
1568 return (*func) (string, base, value, error);
1572 _gtk_css_value_to_string (const GValue *value)
1576 css_string_funcs_init ();
1578 func = g_hash_table_lookup (to_string_funcs,
1579 GSIZE_TO_POINTER (G_VALUE_TYPE (value)));
1581 func = g_hash_table_lookup (to_string_funcs,
1582 GSIZE_TO_POINTER (g_type_fundamental (G_VALUE_TYPE (value))));
1585 return func (value);
1587 return g_strdup_value_contents (value);
1591 _gtk_css_parse_symbolic_color (const char *str,
1594 GtkSymbolicColor *color;
1597 color = symbolic_color_parse_str (str, &end);
1603 gtk_symbolic_color_unref (color);
1607 g_set_error_literal (error,
1608 GTK_CSS_PROVIDER_ERROR,
1609 GTK_CSS_PROVIDER_ERROR_PROPERTY_VALUE,
1610 "Failed to parse symbolic color");
1617 _gtk_css_parse_url (GFile *base,
1625 if (g_str_has_prefix (str, "url"))
1627 str += strlen ("url");
1632 g_set_error_literal (error,
1633 GTK_CSS_PROVIDER_ERROR,
1634 GTK_CSS_PROVIDER_ERROR_PROPERTY_VALUE,
1635 "Expected '(' after 'url'");
1639 chr = strchr (str, ')');
1642 g_set_error_literal (error,
1643 GTK_CSS_PROVIDER_ERROR,
1644 GTK_CSS_PROVIDER_ERROR_PROPERTY_VALUE,
1645 "No closing ')' found for 'url'");
1655 if (*str == '"' || *str == '\'')
1662 SKIP_SPACES_BACK (chr);
1664 if (*chr != *p || chr == p)
1666 g_set_error_literal (error,
1667 GTK_CSS_PROVIDER_ERROR,
1668 GTK_CSS_PROVIDER_ERROR_PROPERTY_VALUE,
1669 "Did not find closing quote for url");
1675 g_set_error_literal (error,
1676 GTK_CSS_PROVIDER_ERROR,
1677 GTK_CSS_PROVIDER_ERROR_PROPERTY_VALUE,
1678 "url not properly escaped");
1682 path = g_strndup (str, chr - str);
1687 path = g_strdup (str);
1689 *end = (gchar *) str + strlen (str);
1692 file = g_file_resolve_relative_path (base, path);