X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=gtk%2Fgtkstyleproperty.c;h=74245d6ce2b59bbcdeee637bed9822123643a8b6;hb=563eb60666d9f72c38d7542b0ab37841e6aac488;hp=0aed2163407a19cb94bf890e658291f71c88d17f;hpb=8fb4b1373079503686d7cfd8f23290b0c47c2126;p=~andy%2Fgtk diff --git a/gtk/gtkstyleproperty.c b/gtk/gtkstyleproperty.c index 0aed21634..74245d6ce 100644 --- a/gtk/gtkstyleproperty.c +++ b/gtk/gtkstyleproperty.c @@ -12,3162 +12,281 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * License along with this library. If not, see . */ #include "config.h" #include "gtkstylepropertyprivate.h" -#include -#include -#include -#include - -#include -#include - -#include "gtkcssprovider.h" -#include "gtkcssparserprivate.h" -#include "gtkcsstypesprivate.h" - -/* the actual parsers we have */ -#include "gtkanimationdescription.h" -#include "gtkbindings.h" -#include "gtkborderimageprivate.h" -#include "gtkgradient.h" -#include "gtkshadowprivate.h" -#include "gtkthemingengine.h" -#include "gtktypebuiltins.h" -#include "gtkwin32themeprivate.h" - -/* this is in case round() is not provided by the compiler, - * such as in the case of C89 compilers, like MSVC - */ -#include "fallback-c89.c" - -static GHashTable *parse_funcs = NULL; -static GHashTable *print_funcs = NULL; -static GHashTable *properties = NULL; - -static void -register_conversion_function (GType type, - GtkStyleParseFunc parse, - GtkStylePrintFunc print) -{ - if (parse) - g_hash_table_insert (parse_funcs, GSIZE_TO_POINTER (type), parse); - if (print) - g_hash_table_insert (print_funcs, GSIZE_TO_POINTER (type), print); -} - -static void -string_append_double (GString *string, - double d) -{ - char buf[G_ASCII_DTOSTR_BUF_SIZE]; - - g_ascii_dtostr (buf, sizeof (buf), d); - g_string_append (string, buf); -} - -static void -string_append_string (GString *str, - const char *string) -{ - gsize len; - - g_string_append_c (str, '"'); - - do { - len = strcspn (string, "\"\n\r\f"); - g_string_append (str, string); - string += len; - switch (*string) - { - case '\0': - break; - case '\n': - g_string_append (str, "\\A "); - break; - case '\r': - g_string_append (str, "\\D "); - break; - case '\f': - g_string_append (str, "\\C "); - break; - case '\"': - g_string_append (str, "\\\""); - break; - default: - g_assert_not_reached (); - break; - } - } while (*string); - - g_string_append_c (str, '"'); -} - -/*** IMPLEMENTATIONS ***/ - -static gboolean -enum_parse (GtkCssParser *parser, - GType type, - int *res) -{ - char *str; - - if (_gtk_css_parser_try_enum (parser, type, res)) - return TRUE; - - str = _gtk_css_parser_try_ident (parser, TRUE); - if (str == NULL) - { - _gtk_css_parser_error (parser, "Expected an identifier"); - return FALSE; - } - - _gtk_css_parser_error (parser, - "Unknown value '%s' for enum type '%s'", - str, g_type_name (type)); - g_free (str); - - return FALSE; -} - -static void -enum_print (int value, - GType type, - GString *string) -{ - GEnumClass *enum_class; - GEnumValue *enum_value; - - enum_class = g_type_class_ref (type); - enum_value = g_enum_get_value (enum_class, value); - - g_string_append (string, enum_value->value_nick); - - g_type_class_unref (enum_class); -} - -static gboolean -rgba_value_parse (GtkCssParser *parser, - GFile *base, - GValue *value) -{ - GtkSymbolicColor *symbolic; - GdkRGBA rgba; - - symbolic = _gtk_css_parser_read_symbolic_color (parser); - if (symbolic == NULL) - return FALSE; - - if (gtk_symbolic_color_resolve (symbolic, NULL, &rgba)) - { - g_value_set_boxed (value, &rgba); - gtk_symbolic_color_unref (symbolic); - } - else - { - g_value_unset (value); - g_value_init (value, GTK_TYPE_SYMBOLIC_COLOR); - g_value_take_boxed (value, symbolic); - } - - return TRUE; -} - -static void -rgba_value_print (const GValue *value, - GString *string) -{ - const GdkRGBA *rgba = g_value_get_boxed (value); - - if (rgba == NULL) - g_string_append (string, "none"); - else - { - char *s = gdk_rgba_to_string (rgba); - g_string_append (string, s); - g_free (s); - } -} - -static gboolean -color_value_parse (GtkCssParser *parser, - GFile *base, - GValue *value) -{ - GtkSymbolicColor *symbolic; - GdkRGBA rgba; - - symbolic = _gtk_css_parser_read_symbolic_color (parser); - if (symbolic == NULL) - return FALSE; - - if (gtk_symbolic_color_resolve (symbolic, NULL, &rgba)) - { - GdkColor color; - - color.red = rgba.red * 65535. + 0.5; - color.green = rgba.green * 65535. + 0.5; - color.blue = rgba.blue * 65535. + 0.5; - - g_value_set_boxed (value, &color); - } - else - { - g_value_unset (value); - g_value_init (value, GTK_TYPE_SYMBOLIC_COLOR); - g_value_take_boxed (value, symbolic); - } - - return TRUE; -} - -static void -color_value_print (const GValue *value, - GString *string) -{ - const GdkColor *color = g_value_get_boxed (value); - - if (color == NULL) - g_string_append (string, "none"); - else - { - char *s = gdk_color_to_string (color); - g_string_append (string, s); - g_free (s); - } -} - -static gboolean -symbolic_color_value_parse (GtkCssParser *parser, - GFile *base, - GValue *value) -{ - GtkSymbolicColor *symbolic; - - symbolic = _gtk_css_parser_read_symbolic_color (parser); - if (symbolic == NULL) - return FALSE; - - g_value_take_boxed (value, symbolic); - return TRUE; -} - -static void -symbolic_color_value_print (const GValue *value, - GString *string) -{ - GtkSymbolicColor *symbolic = g_value_get_boxed (value); - - if (symbolic == NULL) - g_string_append (string, "none"); - else - { - char *s = gtk_symbolic_color_to_string (symbolic); - g_string_append (string, s); - g_free (s); - } -} - -static gboolean -font_family_parse (GtkCssParser *parser, - GFile *base, - GValue *value) -{ - GPtrArray *names; - char *name; - - /* We don't special case generic families. Pango should do - * that for us */ - - names = g_ptr_array_new (); - - do { - name = _gtk_css_parser_try_ident (parser, TRUE); - if (name) - { - GString *string = g_string_new (name); - g_free (name); - while ((name = _gtk_css_parser_try_ident (parser, TRUE))) - { - g_string_append_c (string, ' '); - g_string_append (string, name); - g_free (name); - } - name = g_string_free (string, FALSE); - } - else - { - name = _gtk_css_parser_read_string (parser); - if (name == NULL) - { - g_ptr_array_free (names, TRUE); - return FALSE; - } - } - - g_ptr_array_add (names, name); - } while (_gtk_css_parser_try (parser, ",", TRUE)); - - /* NULL-terminate array */ - g_ptr_array_add (names, NULL); - g_value_set_boxed (value, g_ptr_array_free (names, FALSE)); - return TRUE; -} - -static void -font_family_value_print (const GValue *value, - GString *string) -{ - const char **names = g_value_get_boxed (value); - - if (names == NULL || *names == NULL) - { - g_string_append (string, "none"); - return; - } - - string_append_string (string, *names); - names++; - while (*names) - { - g_string_append (string, ", "); - string_append_string (string, *names); - names++; - } -} - -static gboolean -font_description_value_parse (GtkCssParser *parser, - GFile *base, - GValue *value) -{ - PangoFontDescription *font_desc; - guint mask; - char *str; - - str = _gtk_css_parser_read_value (parser); - if (str == NULL) - return FALSE; - - font_desc = pango_font_description_from_string (str); - mask = pango_font_description_get_set_fields (font_desc); - /* These values are not really correct, - * but the fields must be set, so we set them to something */ - if ((mask & PANGO_FONT_MASK_FAMILY) == 0) - pango_font_description_set_family_static (font_desc, "Sans"); - if ((mask & PANGO_FONT_MASK_SIZE) == 0) - pango_font_description_set_size (font_desc, 10 * PANGO_SCALE); - g_free (str); - g_value_take_boxed (value, font_desc); - return TRUE; -} - -static void -font_description_value_print (const GValue *value, - GString *string) -{ - const PangoFontDescription *desc = g_value_get_boxed (value); - - if (desc == NULL) - g_string_append (string, "none"); - else - { - char *s = pango_font_description_to_string (desc); - g_string_append (string, s); - g_free (s); - } -} - -static gboolean -boolean_value_parse (GtkCssParser *parser, - GFile *base, - GValue *value) -{ - if (_gtk_css_parser_try (parser, "true", TRUE) || - _gtk_css_parser_try (parser, "1", TRUE)) - { - g_value_set_boolean (value, TRUE); - return TRUE; - } - else if (_gtk_css_parser_try (parser, "false", TRUE) || - _gtk_css_parser_try (parser, "0", TRUE)) - { - g_value_set_boolean (value, FALSE); - return TRUE; - } - else - { - _gtk_css_parser_error (parser, "Expected a boolean value"); - return FALSE; - } -} - -static void -boolean_value_print (const GValue *value, - GString *string) -{ - if (g_value_get_boolean (value)) - g_string_append (string, "true"); - else - g_string_append (string, "false"); -} - -static gboolean -int_value_parse (GtkCssParser *parser, - GFile *base, - GValue *value) -{ - gint i; - - if (_gtk_css_parser_begins_with (parser, '-')) - { - int res = _gtk_win32_theme_int_parse (parser, base, &i); - if (res >= 0) - { - g_value_set_int (value, i); - return res > 0; - } - /* < 0 => continue */ - } - - if (!_gtk_css_parser_try_int (parser, &i)) - { - _gtk_css_parser_error (parser, "Expected a valid integer value"); - return FALSE; - } - - g_value_set_int (value, i); - return TRUE; -} - -static void -int_value_print (const GValue *value, - GString *string) -{ - g_string_append_printf (string, "%d", g_value_get_int (value)); -} - -static gboolean -uint_value_parse (GtkCssParser *parser, - GFile *base, - GValue *value) -{ - guint u; - - if (!_gtk_css_parser_try_uint (parser, &u)) - { - _gtk_css_parser_error (parser, "Expected a valid unsigned value"); - return FALSE; - } - - g_value_set_uint (value, u); - return TRUE; -} - -static void -uint_value_print (const GValue *value, - GString *string) -{ - g_string_append_printf (string, "%u", g_value_get_uint (value)); -} - -static gboolean -double_value_parse (GtkCssParser *parser, - GFile *base, - GValue *value) -{ - gdouble d; - - if (!_gtk_css_parser_try_double (parser, &d)) - { - _gtk_css_parser_error (parser, "Expected a number"); - return FALSE; - } - - g_value_set_double (value, d); - return TRUE; -} - -static void -double_value_print (const GValue *value, - GString *string) -{ - string_append_double (string, g_value_get_double (value)); -} - -static gboolean -float_value_parse (GtkCssParser *parser, - GFile *base, - GValue *value) -{ - gdouble d; - - if (!_gtk_css_parser_try_double (parser, &d)) - { - _gtk_css_parser_error (parser, "Expected a number"); - return FALSE; - } - - g_value_set_float (value, d); - return TRUE; -} - -static void -float_value_print (const GValue *value, - GString *string) -{ - string_append_double (string, g_value_get_float (value)); -} - -static gboolean -string_value_parse (GtkCssParser *parser, - GFile *base, - GValue *value) -{ - char *str = _gtk_css_parser_read_string (parser); - - if (str == NULL) - return FALSE; - - g_value_take_string (value, str); - return TRUE; -} - -static void -string_value_print (const GValue *value, - GString *str) -{ - string_append_string (str, g_value_get_string (value)); -} - -static gboolean -theming_engine_value_parse (GtkCssParser *parser, - GFile *base, - GValue *value) -{ - GtkThemingEngine *engine; - char *str; - - str = _gtk_css_parser_try_ident (parser, TRUE); - if (str == NULL) - { - _gtk_css_parser_error (parser, "Expected a valid theme name"); - return FALSE; - } - - engine = gtk_theming_engine_load (str); - if (engine == NULL) - { - _gtk_css_parser_error (parser, "Themeing engine '%s' not found", str); - g_free (str); - return FALSE; - } - - g_value_set_object (value, engine); - g_free (str); - return TRUE; -} - -static void -theming_engine_value_print (const GValue *value, - GString *string) -{ - GtkThemingEngine *engine; - char *name; - - engine = g_value_get_object (value); - if (engine == NULL) - g_string_append (string, "none"); - else - { - /* XXX: gtk_theming_engine_get_name()? */ - g_object_get (engine, "name", &name, NULL); - g_string_append (string, name ? name : "none"); - g_free (name); - } -} - -static gboolean -animation_description_value_parse (GtkCssParser *parser, - GFile *base, - GValue *value) -{ - GtkAnimationDescription *desc; - char *str; - - str = _gtk_css_parser_read_value (parser); - if (str == NULL) - return FALSE; - - desc = _gtk_animation_description_from_string (str); - g_free (str); - - if (desc == NULL) - { - _gtk_css_parser_error (parser, "Invalid animation description"); - return FALSE; - } - - g_value_take_boxed (value, desc); - return TRUE; -} - -static void -animation_description_value_print (const GValue *value, - GString *string) -{ - GtkAnimationDescription *desc = g_value_get_boxed (value); - - if (desc == NULL) - g_string_append (string, "none"); - else - _gtk_animation_description_print (desc, string); -} - -static gboolean -border_value_parse (GtkCssParser *parser, - GFile *base, - GValue *value) -{ - GtkBorder border = { 0, }; - guint i, numbers[4]; - - for (i = 0; i < G_N_ELEMENTS (numbers); i++) - { - if (_gtk_css_parser_begins_with (parser, '-')) - { - /* These are strictly speaking signed, but we want to be able to use them - for unsigned types too, as the actual ranges of values make this safe */ - int res = _gtk_win32_theme_int_parse (parser, base, (int *)&numbers[i]); - - if (res == 0) /* Parse error, report */ - return FALSE; - - if (res < 0) /* Nothing known to expand */ - break; - } - else - { - if (!_gtk_css_parser_try_uint (parser, &numbers[i])) - break; - - /* XXX: shouldn't allow spaces here? */ - _gtk_css_parser_try (parser, "px", TRUE); - } - } - - if (i == 0) - { - _gtk_css_parser_error (parser, "Expected valid border"); - return FALSE; - } - - border.top = numbers[0]; - if (i > 1) - border.right = numbers[1]; - else - border.right = border.top; - if (i > 2) - border.bottom = numbers[2]; - else - border.bottom = border.top; - if (i > 3) - border.left = numbers[3]; - else - border.left = border.right; - - g_value_set_boxed (value, &border); - return TRUE; -} - -static void -border_value_print (const GValue *value, GString *string) -{ - const GtkBorder *border = g_value_get_boxed (value); - - if (border == NULL) - g_string_append (string, "none"); - else if (border->left != border->right) - g_string_append_printf (string, "%d %d %d %d", border->top, border->right, border->bottom, border->left); - else if (border->top != border->bottom) - g_string_append_printf (string, "%d %d %d", border->top, border->right, border->bottom); - else if (border->top != border->left) - g_string_append_printf (string, "%d %d", border->top, border->right); - else - g_string_append_printf (string, "%d", border->top); -} - -static gboolean -gradient_value_parse (GtkCssParser *parser, - GFile *base, - GValue *value) -{ - GtkGradient *gradient; - cairo_pattern_type_t type; - gdouble coords[6]; - guint i; - - if (!_gtk_css_parser_try (parser, "-gtk-gradient", TRUE)) - { - _gtk_css_parser_error (parser, - "Expected '-gtk-gradient'"); - return FALSE; - } - - if (!_gtk_css_parser_try (parser, "(", TRUE)) - { - _gtk_css_parser_error (parser, - "Expected '(' after '-gtk-gradient'"); - return FALSE; - } - - /* Parse gradient type */ - if (_gtk_css_parser_try (parser, "linear", TRUE)) - type = CAIRO_PATTERN_TYPE_LINEAR; - else if (_gtk_css_parser_try (parser, "radial", TRUE)) - type = CAIRO_PATTERN_TYPE_RADIAL; - else - { - _gtk_css_parser_error (parser, - "Gradient type must be 'radial' or 'linear'"); - return FALSE; - } - - /* Parse start/stop position parameters */ - for (i = 0; i < 2; i++) - { - if (! _gtk_css_parser_try (parser, ",", TRUE)) - { - _gtk_css_parser_error (parser, - "Expected ','"); - return FALSE; - } - - if (_gtk_css_parser_try (parser, "left", TRUE)) - coords[i * 3] = 0; - else if (_gtk_css_parser_try (parser, "right", TRUE)) - coords[i * 3] = 1; - else if (_gtk_css_parser_try (parser, "center", TRUE)) - coords[i * 3] = 0.5; - else if (!_gtk_css_parser_try_double (parser, &coords[i * 3])) - { - _gtk_css_parser_error (parser, - "Expected a valid X coordinate"); - return FALSE; - } - - if (_gtk_css_parser_try (parser, "top", TRUE)) - coords[i * 3 + 1] = 0; - else if (_gtk_css_parser_try (parser, "bottom", TRUE)) - coords[i * 3 + 1] = 1; - else if (_gtk_css_parser_try (parser, "center", TRUE)) - coords[i * 3 + 1] = 0.5; - else if (!_gtk_css_parser_try_double (parser, &coords[i * 3 + 1])) - { - _gtk_css_parser_error (parser, - "Expected a valid Y coordinate"); - return FALSE; - } - - if (type == CAIRO_PATTERN_TYPE_RADIAL) - { - /* Parse radius */ - if (! _gtk_css_parser_try (parser, ",", TRUE)) - { - _gtk_css_parser_error (parser, - "Expected ','"); - return FALSE; - } - - if (! _gtk_css_parser_try_double (parser, &coords[(i * 3) + 2])) - { - _gtk_css_parser_error (parser, - "Expected a numer for the radius"); - return FALSE; - } - } - } - - if (type == CAIRO_PATTERN_TYPE_LINEAR) - gradient = gtk_gradient_new_linear (coords[0], coords[1], coords[3], coords[4]); - else - gradient = gtk_gradient_new_radial (coords[0], coords[1], coords[2], - coords[3], coords[4], coords[5]); - - while (_gtk_css_parser_try (parser, ",", TRUE)) - { - GtkSymbolicColor *color; - gdouble position; - - if (_gtk_css_parser_try (parser, "from", TRUE)) - { - position = 0; - - if (!_gtk_css_parser_try (parser, "(", TRUE)) - { - gtk_gradient_unref (gradient); - _gtk_css_parser_error (parser, - "Expected '('"); - return FALSE; - } - - } - else if (_gtk_css_parser_try (parser, "to", TRUE)) - { - position = 1; - - if (!_gtk_css_parser_try (parser, "(", TRUE)) - { - gtk_gradient_unref (gradient); - _gtk_css_parser_error (parser, - "Expected '('"); - return FALSE; - } - - } - else if (_gtk_css_parser_try (parser, "color-stop", TRUE)) - { - if (!_gtk_css_parser_try (parser, "(", TRUE)) - { - gtk_gradient_unref (gradient); - _gtk_css_parser_error (parser, - "Expected '('"); - return FALSE; - } - - if (!_gtk_css_parser_try_double (parser, &position)) - { - gtk_gradient_unref (gradient); - _gtk_css_parser_error (parser, - "Expected a valid number"); - return FALSE; - } - - if (!_gtk_css_parser_try (parser, ",", TRUE)) - { - gtk_gradient_unref (gradient); - _gtk_css_parser_error (parser, - "Expected a comma"); - return FALSE; - } - } - else - { - gtk_gradient_unref (gradient); - _gtk_css_parser_error (parser, - "Not a valid color-stop definition"); - return FALSE; - } - - color = _gtk_css_parser_read_symbolic_color (parser); - if (color == NULL) - { - gtk_gradient_unref (gradient); - return FALSE; - } - - gtk_gradient_add_color_stop (gradient, position, color); - gtk_symbolic_color_unref (color); - - if (!_gtk_css_parser_try (parser, ")", TRUE)) - { - gtk_gradient_unref (gradient); - _gtk_css_parser_error (parser, - "Expected ')'"); - return FALSE; - } - } - - if (!_gtk_css_parser_try (parser, ")", TRUE)) - { - gtk_gradient_unref (gradient); - _gtk_css_parser_error (parser, - "Expected ')'"); - return FALSE; - } - - g_value_take_boxed (value, gradient); - return TRUE; -} - -static void -gradient_value_print (const GValue *value, - GString *string) -{ - GtkGradient *gradient = g_value_get_boxed (value); - - if (gradient == NULL) - g_string_append (string, "none"); - else - { - char *s = gtk_gradient_to_string (gradient); - g_string_append (string, s); - g_free (s); - } -} - -static GFile * -gtk_css_parse_url (GtkCssParser *parser, - GFile *base) -{ - gchar *path; - GFile *file; - - if (_gtk_css_parser_try (parser, "url", FALSE)) - { - if (!_gtk_css_parser_try (parser, "(", TRUE)) - { - _gtk_css_parser_skip_whitespace (parser); - if (_gtk_css_parser_try (parser, "(", TRUE)) - { - GError *error; - - error = g_error_new_literal (GTK_CSS_PROVIDER_ERROR, - GTK_CSS_PROVIDER_ERROR_DEPRECATED, - "Whitespace between 'url' and '(' is deprecated"); - - _gtk_css_parser_take_error (parser, error); - } - else - { - _gtk_css_parser_error (parser, "Expected '(' after 'url'"); - return NULL; - } - } - - path = _gtk_css_parser_read_string (parser); - if (path == NULL) - return NULL; - - if (!_gtk_css_parser_try (parser, ")", TRUE)) - { - _gtk_css_parser_error (parser, "No closing ')' found for 'url'"); - g_free (path); - return NULL; - } - } - else - { - path = _gtk_css_parser_try_name (parser, TRUE); - if (path == NULL) - { - _gtk_css_parser_error (parser, "Not a valid url"); - return NULL; - } - } - - file = g_file_resolve_relative_path (base, path); - g_free (path); - - return file; -} - -static gboolean -pattern_value_parse (GtkCssParser *parser, - GFile *base, - GValue *value) -{ - if (_gtk_css_parser_begins_with (parser, '-')) - { - int res; - res = _gtk_win32_theme_part_parse (parser, base, value); - if (res >= 0) - return res > 0; - /* < 0 => continue */ - g_value_unset (value); - g_value_init (value, GTK_TYPE_GRADIENT); - return gradient_value_parse (parser, base, value); - } - else - { - GError *error = NULL; - gchar *path; - GdkPixbuf *pixbuf; - GFile *file; - cairo_surface_t *surface; - cairo_pattern_t *pattern; - cairo_t *cr; - cairo_matrix_t matrix; - - file = gtk_css_parse_url (parser, base); - if (file == NULL) - return FALSE; - - path = g_file_get_path (file); - g_object_unref (file); - - pixbuf = gdk_pixbuf_new_from_file (path, &error); - g_free (path); - if (pixbuf == NULL) - { - _gtk_css_parser_take_error (parser, error); - return FALSE; - } - - surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, - gdk_pixbuf_get_width (pixbuf), - gdk_pixbuf_get_height (pixbuf)); - cr = cairo_create (surface); - gdk_cairo_set_source_pixbuf (cr, pixbuf, 0, 0); - cairo_paint (cr); - pattern = cairo_pattern_create_for_surface (surface); - - cairo_matrix_init_scale (&matrix, - gdk_pixbuf_get_width (pixbuf), - gdk_pixbuf_get_height (pixbuf)); - cairo_pattern_set_matrix (pattern, &matrix); - - cairo_surface_destroy (surface); - cairo_destroy (cr); - g_object_unref (pixbuf); - - g_value_take_boxed (value, pattern); - } - - return TRUE; -} - -static cairo_status_t -surface_write (void *closure, - const unsigned char *data, - unsigned int length) -{ - g_byte_array_append (closure, data, length); - - return CAIRO_STATUS_SUCCESS; -} - -static void -surface_print (cairo_surface_t *surface, - GString * string) -{ -#if CAIRO_HAS_PNG_FUNCTIONS - GByteArray *array; - char *base64; - - array = g_byte_array_new (); - cairo_surface_write_to_png_stream (surface, surface_write, array); - base64 = g_base64_encode (array->data, array->len); - g_byte_array_free (array, TRUE); - - g_string_append (string, "url(\"data:image/png;base64,"); - g_string_append (string, base64); - g_string_append (string, "\")"); - - g_free (base64); -#else - g_string_append (string, "none /* you need cairo png functions enabled to make this work */"); -#endif -} - -static void -pattern_value_print (const GValue *value, - GString *string) -{ - cairo_pattern_t *pattern; - cairo_surface_t *surface; - - pattern = g_value_get_boxed (value); - - if (pattern == NULL) - { - g_string_append (string, "none"); - return; - } - - switch (cairo_pattern_get_type (pattern)) - { - case CAIRO_PATTERN_TYPE_SURFACE: - if (cairo_pattern_get_surface (pattern, &surface) != CAIRO_STATUS_SUCCESS) - { - g_assert_not_reached (); - } - surface_print (surface, string); - break; - case CAIRO_PATTERN_TYPE_SOLID: - case CAIRO_PATTERN_TYPE_LINEAR: - case CAIRO_PATTERN_TYPE_RADIAL: - default: - g_assert_not_reached (); - break; - } -} - -static gboolean -shadow_value_parse (GtkCssParser *parser, - GFile *base, - GValue *value) -{ - gboolean have_inset, have_color, have_lengths; - gdouble hoffset, voffset, blur, spread; - GtkSymbolicColor *color; - GtkShadow *shadow; - guint i; - - shadow = _gtk_shadow_new (); - - do - { - have_inset = have_lengths = have_color = FALSE; - - for (i = 0; i < 3; i++) - { - if (!have_inset && - _gtk_css_parser_try (parser, "inset", TRUE)) - { - have_inset = TRUE; - continue; - } - - if (!have_lengths && - _gtk_css_parser_try_double (parser, &hoffset)) - { - have_lengths = TRUE; - - if (!_gtk_css_parser_try_double (parser, &voffset)) - { - _gtk_css_parser_error (parser, "Horizontal and vertical offsets are required"); - _gtk_shadow_unref (shadow); - return FALSE; - } - - if (!_gtk_css_parser_try_double (parser, &blur)) - blur = 0; - - if (!_gtk_css_parser_try_double (parser, &spread)) - spread = 0; - - continue; - } - - if (!have_color) - { - have_color = TRUE; - - /* XXX: the color is optional and UA-defined if it's missing, - * but it doesn't really make sense for us... - */ - color = _gtk_css_parser_read_symbolic_color (parser); - - if (color == NULL) - { - _gtk_shadow_unref (shadow); - return FALSE; - } - } - } - - if (!have_color || !have_lengths) - { - _gtk_css_parser_error (parser, "Must specify at least color and offsets"); - _gtk_shadow_unref (shadow); - return FALSE; - } - - _gtk_shadow_append (shadow, - hoffset, voffset, - blur, spread, - have_inset, color); - - gtk_symbolic_color_unref (color); - - } - while (_gtk_css_parser_try (parser, ",", TRUE)); - - g_value_take_boxed (value, shadow); - return TRUE; -} - -static void -shadow_value_print (const GValue *value, - GString *string) -{ - GtkShadow *shadow; - - shadow = g_value_get_boxed (value); - - if (shadow == NULL) - g_string_append (string, "none"); - else - _gtk_shadow_print (shadow, string); -} - -static gboolean -background_repeat_value_parse (GtkCssParser *parser, - GFile *file, - GValue *value) -{ - GtkCssBackgroundRepeat repeat; - GtkCssBackgroundRepeatStyle style; - - if (_gtk_css_parser_try (parser, "repeat", TRUE)) - style = GTK_CSS_BACKGROUND_REPEAT_STYLE_REPEAT; - else if (_gtk_css_parser_try (parser, "no-repeat", TRUE)) - style = GTK_CSS_BACKGROUND_REPEAT_STYLE_NO_REPEAT; - else - style = GTK_CSS_BACKGROUND_REPEAT_STYLE_NONE; - - repeat.repeat = style; - - g_value_set_boxed (value, &repeat); - - return TRUE; -} - -static const gchar * -background_repeat_style_to_string (GtkCssBackgroundRepeatStyle repeat) -{ - switch (repeat) - { - case GTK_CSS_BACKGROUND_REPEAT_STYLE_REPEAT: - return "repeat"; - case GTK_CSS_BACKGROUND_REPEAT_STYLE_NO_REPEAT: - return "no-repeat"; - default: - return NULL; - } -} - -static void -background_repeat_value_print (const GValue *value, - GString *string) -{ - GtkCssBackgroundRepeat *repeat; - - repeat = g_value_get_boxed (value); - - g_string_append (string, background_repeat_style_to_string (repeat->repeat)); -} - -static gboolean -border_image_repeat_value_parse (GtkCssParser *parser, - GFile *file, - GValue *value) -{ - GtkCssBorderImageRepeat image_repeat; - GtkCssBorderRepeatStyle styles[2]; - gint i; - - for (i = 0; i < 2; i++) - { - if (_gtk_css_parser_try (parser, "stretch", TRUE)) - styles[i] = GTK_CSS_REPEAT_STYLE_NONE; - else if (_gtk_css_parser_try (parser, "repeat", TRUE)) - styles[i] = GTK_CSS_REPEAT_STYLE_REPEAT; - else if (_gtk_css_parser_try (parser, "round", TRUE)) - styles[i] = GTK_CSS_REPEAT_STYLE_ROUND; - else if (_gtk_css_parser_try (parser, "space", TRUE)) - styles[i] = GTK_CSS_REPEAT_STYLE_SPACE; - else if (i == 0) - { - styles[1] = styles[0] = GTK_CSS_REPEAT_STYLE_NONE; - break; - } - else - styles[i] = styles[0]; - } - - image_repeat.hrepeat = styles[0]; - image_repeat.vrepeat = styles[1]; - - g_value_set_boxed (value, &image_repeat); - - return TRUE; -} - -static const gchar * -border_image_repeat_style_to_string (GtkCssBorderRepeatStyle repeat) -{ - switch (repeat) - { - case GTK_CSS_REPEAT_STYLE_NONE: - return "stretch"; - case GTK_CSS_REPEAT_STYLE_REPEAT: - return "repeat"; - case GTK_CSS_REPEAT_STYLE_ROUND: - return "round"; - case GTK_CSS_REPEAT_STYLE_SPACE: - return "space"; - default: - return NULL; - } -} - -static void -border_image_repeat_value_print (const GValue *value, - GString *string) -{ - GtkCssBorderImageRepeat *image_repeat; - - image_repeat = g_value_get_boxed (value); - - g_string_append (string, border_image_repeat_style_to_string (image_repeat->hrepeat)); - if (image_repeat->hrepeat != image_repeat->vrepeat) - { - g_string_append (string, " "); - g_string_append (string, border_image_repeat_style_to_string (image_repeat->vrepeat)); - } -} - -static gboolean -border_image_value_parse (GtkCssParser *parser, - GFile *base, - GValue *value) -{ - GValue temp = G_VALUE_INIT; - cairo_pattern_t *pattern = NULL; - gconstpointer *boxed = NULL; - GType boxed_type; - GtkBorder slice, *width = NULL, *parsed_slice; - GtkCssBorderImageRepeat repeat, *parsed_repeat; - gboolean retval = FALSE; - GtkBorderImage *image = NULL; - - g_value_init (&temp, CAIRO_GOBJECT_TYPE_PATTERN); - - if (!pattern_value_parse (parser, base, &temp)) - return FALSE; - - boxed_type = G_VALUE_TYPE (&temp); - if (boxed_type != CAIRO_GOBJECT_TYPE_PATTERN) - boxed = g_value_dup_boxed (&temp); - else - pattern = g_value_dup_boxed (&temp); - - g_value_unset (&temp); - g_value_init (&temp, GTK_TYPE_BORDER); - - if (!border_value_parse (parser, base, &temp)) - goto out; - - parsed_slice = g_value_get_boxed (&temp); - slice = *parsed_slice; - - if (_gtk_css_parser_try (parser, "/", TRUE)) - { - g_value_unset (&temp); - g_value_init (&temp, GTK_TYPE_BORDER); - - if (!border_value_parse (parser, base, &temp)) - goto out; - - width = g_value_dup_boxed (&temp); - } - - g_value_unset (&temp); - g_value_init (&temp, GTK_TYPE_CSS_BORDER_IMAGE_REPEAT); - - if (!border_image_repeat_value_parse (parser, base, &temp)) - goto out; - - parsed_repeat = g_value_get_boxed (&temp); - repeat = *parsed_repeat; - - g_value_unset (&temp); - - if (boxed != NULL) - image = _gtk_border_image_new_for_boxed (boxed_type, boxed, &slice, width, &repeat); - else if (pattern != NULL) - image = _gtk_border_image_new (pattern, &slice, width, &repeat); - - if (image != NULL) - { - retval = TRUE; - g_value_take_boxed (value, image); - } - - out: - if (pattern != NULL) - cairo_pattern_destroy (pattern); - - if (boxed != NULL) - g_boxed_free (boxed_type, boxed); - - if (width != NULL) - gtk_border_free (width); - - return retval; -} - -static gboolean -enum_value_parse (GtkCssParser *parser, - GFile *base, - GValue *value) -{ - int v; - - if (enum_parse (parser, G_VALUE_TYPE (value), &v)) - { - g_value_set_enum (value, v); - return TRUE; - } - - return FALSE; -} - -static void -enum_value_print (const GValue *value, - GString *string) -{ - enum_print (g_value_get_enum (value), G_VALUE_TYPE (value), string); -} - -static gboolean -flags_value_parse (GtkCssParser *parser, - GFile *base, - GValue *value) -{ - GFlagsClass *flags_class; - GFlagsValue *flag_value; - guint flags = 0; - char *str; - - flags_class = g_type_class_ref (G_VALUE_TYPE (value)); - - do { - str = _gtk_css_parser_try_ident (parser, TRUE); - if (str == NULL) - { - _gtk_css_parser_error (parser, "Expected an identifier"); - g_type_class_unref (flags_class); - return FALSE; - } - - flag_value = g_flags_get_value_by_nick (flags_class, str); - if (!flag_value) - { - _gtk_css_parser_error (parser, - "Unknown flag value '%s' for type '%s'", - str, g_type_name (G_VALUE_TYPE (value))); - /* XXX Do we want to return FALSE here? We can get - * forward-compatibility for new values this way - */ - g_free (str); - g_type_class_unref (flags_class); - return FALSE; - } - - g_free (str); - } - while (_gtk_css_parser_try (parser, ",", FALSE)); - - g_type_class_unref (flags_class); - - g_value_set_enum (value, flags); - - return TRUE; -} - -static void -flags_value_print (const GValue *value, - GString *string) -{ - GFlagsClass *flags_class; - guint i, flags; - - flags_class = g_type_class_ref (G_VALUE_TYPE (value)); - flags = g_value_get_flags (value); - - for (i = 0; i < flags_class->n_values; i++) - { - GFlagsValue *flags_value = &flags_class->values[i]; - - if (flags & flags_value->value) - { - if (string->len != 0) - g_string_append (string, ", "); - - g_string_append (string, flags_value->value_nick); - } - } - - g_type_class_unref (flags_class); -} - -static gboolean -bindings_value_parse (GtkCssParser *parser, - GFile *base, - GValue *value) -{ - GPtrArray *array; - GtkBindingSet *binding_set; - char *name; - - array = g_ptr_array_new (); - - do { - name = _gtk_css_parser_try_ident (parser, TRUE); - if (name == NULL) - { - _gtk_css_parser_error (parser, "Not a valid binding name"); - g_ptr_array_free (array, TRUE); - return FALSE; - } - - binding_set = gtk_binding_set_find (name); - - if (!binding_set) - { - _gtk_css_parser_error (parser, "No binding set named '%s'", name); - g_free (name); - continue; - } - - g_ptr_array_add (array, binding_set); - g_free (name); - } - while (_gtk_css_parser_try (parser, ",", TRUE)); - - g_value_take_boxed (value, array); - - return TRUE; -} - -static void -bindings_value_print (const GValue *value, - GString *string) -{ - GPtrArray *array; - guint i; - - array = g_value_get_boxed (value); - - for (i = 0; i < array->len; i++) - { - GtkBindingSet *binding_set = g_ptr_array_index (array, i); - - if (i > 0) - g_string_append (string, ", "); - g_string_append (string, binding_set->set_name); - } -} - -static gboolean -border_corner_radius_value_parse (GtkCssParser *parser, - GFile *base, - GValue *value) -{ - GtkCssBorderCornerRadius corner; - - if (!_gtk_css_parser_try_double (parser, &corner.horizontal)) - { - _gtk_css_parser_error (parser, "Expected a number"); - return FALSE; - } - else if (corner.horizontal < 0) - goto negative; - - if (!_gtk_css_parser_try_double (parser, &corner.vertical)) - corner.vertical = corner.horizontal; - else if (corner.vertical < 0) - goto negative; - - g_value_set_boxed (value, &corner); - return TRUE; - -negative: - _gtk_css_parser_error (parser, "Border radius values cannot be negative"); - return FALSE; -} - -static void -border_corner_radius_value_print (const GValue *value, - GString *string) -{ - GtkCssBorderCornerRadius *corner; - - corner = g_value_get_boxed (value); - - if (corner == NULL) - { - g_string_append (string, "none"); - return; - } - - string_append_double (string, corner->horizontal); - if (corner->horizontal != corner->vertical) - { - g_string_append_c (string, ' '); - string_append_double (string, corner->vertical); - } -} - -static gboolean -border_radius_value_parse (GtkCssParser *parser, - GFile *base, - GValue *value) -{ - GtkCssBorderRadius border; - - if (!_gtk_css_parser_try_double (parser, &border.top_left.horizontal)) - { - _gtk_css_parser_error (parser, "Expected a number"); - return FALSE; - } - else if (border.top_left.horizontal < 0) - goto negative; - - if (_gtk_css_parser_try_double (parser, &border.top_right.horizontal)) - { - if (border.top_right.horizontal < 0) - goto negative; - if (_gtk_css_parser_try_double (parser, &border.bottom_right.horizontal)) - { - if (border.bottom_right.horizontal < 0) - goto negative; - if (!_gtk_css_parser_try_double (parser, &border.bottom_left.horizontal)) - border.bottom_left.horizontal = border.top_right.horizontal; - else if (border.bottom_left.horizontal < 0) - goto negative; - } - else - { - border.bottom_right.horizontal = border.top_left.horizontal; - border.bottom_left.horizontal = border.top_right.horizontal; - } - } - else - { - border.top_right.horizontal = border.top_left.horizontal; - border.bottom_right.horizontal = border.top_left.horizontal; - border.bottom_left.horizontal = border.top_left.horizontal; - } - - if (_gtk_css_parser_try (parser, "/", TRUE)) - { - if (!_gtk_css_parser_try_double (parser, &border.top_left.vertical)) - { - _gtk_css_parser_error (parser, "Expected a number"); - return FALSE; - } - else if (border.top_left.vertical < 0) - goto negative; - - if (_gtk_css_parser_try_double (parser, &border.top_right.vertical)) - { - if (border.top_right.vertical < 0) - goto negative; - if (_gtk_css_parser_try_double (parser, &border.bottom_right.vertical)) - { - if (border.bottom_right.vertical < 0) - goto negative; - if (!_gtk_css_parser_try_double (parser, &border.bottom_left.vertical)) - border.bottom_left.vertical = border.top_right.vertical; - else if (border.bottom_left.vertical < 0) - goto negative; - } - else - { - border.bottom_right.vertical = border.top_left.vertical; - border.bottom_left.vertical = border.top_right.vertical; - } - } - else - { - border.top_right.vertical = border.top_left.vertical; - border.bottom_right.vertical = border.top_left.vertical; - border.bottom_left.vertical = border.top_left.vertical; - } - } - else - { - border.top_left.vertical = border.top_left.horizontal; - border.top_right.vertical = border.top_right.horizontal; - border.bottom_right.vertical = border.bottom_right.horizontal; - border.bottom_left.vertical = border.bottom_left.horizontal; - } - - /* border-radius is an int property for backwards-compat reasons */ - g_value_unset (value); - g_value_init (value, GTK_TYPE_CSS_BORDER_RADIUS); - g_value_set_boxed (value, &border); - - return TRUE; - -negative: - _gtk_css_parser_error (parser, "Border radius values cannot be negative"); - return FALSE; -} - -static void -border_radius_value_print (const GValue *value, - GString *string) -{ - GtkCssBorderRadius *border; - - border = g_value_get_boxed (value); - - if (border == NULL) - { - g_string_append (string, "none"); - return; - } - - string_append_double (string, border->top_left.horizontal); - if (border->top_left.horizontal != border->top_right.horizontal || - border->top_left.horizontal != border->bottom_right.horizontal || - border->top_left.horizontal != border->bottom_left.horizontal) - { - g_string_append_c (string, ' '); - string_append_double (string, border->top_right.horizontal); - if (border->top_left.horizontal != border->bottom_right.horizontal || - border->top_right.horizontal != border->bottom_left.horizontal) - { - g_string_append_c (string, ' '); - string_append_double (string, border->bottom_right.horizontal); - if (border->top_right.horizontal != border->bottom_left.horizontal) - { - g_string_append_c (string, ' '); - string_append_double (string, border->bottom_left.horizontal); - } - } - } - - if (border->top_left.horizontal != border->top_left.vertical || - border->top_right.horizontal != border->top_right.vertical || - border->bottom_right.horizontal != border->bottom_right.vertical || - border->bottom_left.horizontal != border->bottom_left.vertical) - { - g_string_append (string, " / "); - string_append_double (string, border->top_left.vertical); - if (border->top_left.vertical != border->top_right.vertical || - border->top_left.vertical != border->bottom_right.vertical || - border->top_left.vertical != border->bottom_left.vertical) - { - g_string_append_c (string, ' '); - string_append_double (string, border->top_right.vertical); - if (border->top_left.vertical != border->bottom_right.vertical || - border->top_right.vertical != border->bottom_left.vertical) - { - g_string_append_c (string, ' '); - string_append_double (string, border->bottom_right.vertical); - if (border->top_right.vertical != border->bottom_left.vertical) - { - g_string_append_c (string, ' '); - string_append_double (string, border->bottom_left.vertical); - } - } - } - - } -} - -static gboolean -transparent_color_value_parse (GtkCssParser *parser, - GFile *base, - GValue *value) -{ - if (_gtk_css_parser_try (parser, "transparent", TRUE)) - { - GdkRGBA transparent = { 0, 0, 0, 0 }; - - g_value_set_boxed (value, &transparent); - - return TRUE; - } - - return rgba_value_parse (parser, base, value); -} - -static gboolean -border_color_shorthand_value_parse (GtkCssParser *parser, - GFile *base, - GValue *value) -{ - GtkSymbolicColor *symbolic; - GPtrArray *array; - - array = g_ptr_array_new_with_free_func ((GDestroyNotify) gtk_symbolic_color_unref); - - do - { - if (_gtk_css_parser_try (parser, "transparent", TRUE)) - { - GdkRGBA transparent = { 0, 0, 0, 0 }; - - symbolic = gtk_symbolic_color_new_literal (&transparent); - } - else - { - symbolic = _gtk_css_parser_read_symbolic_color (parser); - - if (symbolic == NULL) - return FALSE; - } - - g_ptr_array_add (array, symbolic); - } - while (array->len < 4 && - !_gtk_css_parser_is_eof (parser) && - !_gtk_css_parser_begins_with (parser, ';') && - !_gtk_css_parser_begins_with (parser, '}')); - - switch (array->len) - { - default: - g_assert_not_reached (); - break; - case 1: - g_ptr_array_add (array, gtk_symbolic_color_ref (g_ptr_array_index (array, 0))); - /* fall through */ - case 2: - g_ptr_array_add (array, gtk_symbolic_color_ref (g_ptr_array_index (array, 0))); - /* fall through */ - case 3: - g_ptr_array_add (array, gtk_symbolic_color_ref (g_ptr_array_index (array, 1))); - /* fall through */ - case 4: - break; - } - - g_value_unset (value); - g_value_init (value, G_TYPE_PTR_ARRAY); - g_value_take_boxed (value, array); - - return TRUE; -} - -/*** PACKING ***/ - -static GParameter * -unpack_border (const GValue *value, - guint *n_params, - const char *top, - const char *left, - const char *bottom, - const char *right) -{ - GParameter *parameter = g_new0 (GParameter, 4); - GtkBorder *border = g_value_get_boxed (value); - - parameter[0].name = top; - g_value_init (¶meter[0].value, G_TYPE_INT); - g_value_set_int (¶meter[0].value, border->top); - parameter[1].name = left; - g_value_init (¶meter[1].value, G_TYPE_INT); - g_value_set_int (¶meter[1].value, border->left); - parameter[2].name = bottom; - g_value_init (¶meter[2].value, G_TYPE_INT); - g_value_set_int (¶meter[2].value, border->bottom); - parameter[3].name = right; - g_value_init (¶meter[3].value, G_TYPE_INT); - g_value_set_int (¶meter[3].value, border->right); - - *n_params = 4; - return parameter; -} - -static void -pack_border (GValue *value, - GtkStyleProperties *props, - GtkStateFlags state, - const char *top, - const char *left, - const char *bottom, - const char *right) -{ - GtkBorder border; - int t, l, b, r; - - gtk_style_properties_get (props, - state, - top, &t, - left, &l, - bottom, &b, - right, &r, - NULL); - - border.top = t; - border.left = l; - border.bottom = b; - border.right = r; - - g_value_set_boxed (value, &border); -} - -static GParameter * -unpack_border_width (const GValue *value, - guint *n_params) -{ - return unpack_border (value, n_params, - "border-top-width", "border-left-width", - "border-bottom-width", "border-right-width"); -} - -static void -pack_border_width (GValue *value, - GtkStyleProperties *props, - GtkStateFlags state, - GtkStylePropertyContext *context) -{ - pack_border (value, props, state, - "border-top-width", "border-left-width", - "border-bottom-width", "border-right-width"); -} - -static GParameter * -unpack_padding (const GValue *value, - guint *n_params) -{ - return unpack_border (value, n_params, - "padding-top", "padding-left", - "padding-bottom", "padding-right"); -} +#include "gtkcssprovider.h" +#include "gtkcssparserprivate.h" +#include "gtkcssshorthandpropertyprivate.h" +#include "gtkcssstylefuncsprivate.h" +#include "gtkcssstylepropertyprivate.h" +#include "gtkcsstypesprivate.h" +#include "gtkintl.h" +#include "gtkprivatetypebuiltins.h" +#include "gtkstylepropertiesprivate.h" -static void -pack_padding (GValue *value, - GtkStyleProperties *props, - GtkStateFlags state, - GtkStylePropertyContext *context) -{ - pack_border (value, props, state, - "padding-top", "padding-left", - "padding-bottom", "padding-right"); -} +enum { + PROP_0, + PROP_NAME, + PROP_VALUE_TYPE +}; -static GParameter * -unpack_margin (const GValue *value, - guint *n_params) -{ - return unpack_border (value, n_params, - "margin-top", "margin-left", - "margin-bottom", "margin-right"); -} +G_DEFINE_ABSTRACT_TYPE (GtkStyleProperty, _gtk_style_property, G_TYPE_OBJECT) static void -pack_margin (GValue *value, - GtkStyleProperties *props, - GtkStateFlags state, - GtkStylePropertyContext *context) -{ - pack_border (value, props, state, - "margin-top", "margin-left", - "margin-bottom", "margin-right"); -} - -static GParameter * -unpack_border_radius (const GValue *value, - guint *n_params) +gtk_style_property_finalize (GObject *object) { - GParameter *parameter = g_new0 (GParameter, 4); - GtkCssBorderRadius *border; - - if (G_VALUE_HOLDS_BOXED (value)) - border = g_value_get_boxed (value); - else - border = NULL; + GtkStyleProperty *property = GTK_STYLE_PROPERTY (object); - parameter[0].name = "border-top-left-radius"; - g_value_init (¶meter[0].value, GTK_TYPE_CSS_BORDER_CORNER_RADIUS); - parameter[1].name = "border-top-right-radius"; - g_value_init (¶meter[1].value, GTK_TYPE_CSS_BORDER_CORNER_RADIUS); - parameter[2].name = "border-bottom-right-radius"; - g_value_init (¶meter[2].value, GTK_TYPE_CSS_BORDER_CORNER_RADIUS); - parameter[3].name = "border-bottom-left-radius"; - g_value_init (¶meter[3].value, GTK_TYPE_CSS_BORDER_CORNER_RADIUS); - if (border) - { - g_value_set_boxed (¶meter[0].value, &border->top_left); - g_value_set_boxed (¶meter[1].value, &border->top_right); - g_value_set_boxed (¶meter[2].value, &border->bottom_right); - g_value_set_boxed (¶meter[3].value, &border->bottom_left); - } + g_warning ("finalizing %s `%s', how could this happen?", G_OBJECT_TYPE_NAME (object), property->name); - *n_params = 4; - return parameter; + G_OBJECT_CLASS (_gtk_style_property_parent_class)->finalize (object); } static void -pack_border_radius (GValue *value, - GtkStyleProperties *props, - GtkStateFlags state, - GtkStylePropertyContext *context) -{ - GtkCssBorderCornerRadius *top_left; - - /* NB: We are an int property, so we have to resolve to an int here. - * So we just resolve to an int. We pick one and stick to it. - * Lesson learned: Don't query border-radius shorthand, query the - * real properties instead. */ - gtk_style_properties_get (props, - state, - "border-top-left-radius", &top_left, - NULL); - - if (top_left) - g_value_set_int (value, top_left->horizontal); - - g_free (top_left); -} - -static GParameter * -unpack_font_description (const GValue *value, - guint *n_params) +gtk_style_property_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) { - GParameter *parameter = g_new0 (GParameter, 5); - PangoFontDescription *description; - PangoFontMask mask; - guint n; - - /* For backwards compat, we only unpack values that are indeed set. - * For strict CSS conformance we need to unpack all of them. - * Note that we do set all of them in the parse function, so it - * will not have effects when parsing CSS files. It will though - * for custom style providers. - */ + GtkStyleProperty *property = GTK_STYLE_PROPERTY (object); + GtkStylePropertyClass *klass = GTK_STYLE_PROPERTY_GET_CLASS (property); - description = g_value_get_boxed (value); - n = 0; - - if (description) - mask = pango_font_description_get_set_fields (description); - else - mask = 0; - - if (mask & PANGO_FONT_MASK_FAMILY) - { - GPtrArray *strv = g_ptr_array_new (); - - g_ptr_array_add (strv, g_strdup (pango_font_description_get_family (description))); - g_ptr_array_add (strv, NULL); - parameter[n].name = "font-family"; - g_value_init (¶meter[n].value, G_TYPE_STRV); - g_value_take_boxed (¶meter[n].value, - g_ptr_array_free (strv, FALSE)); - n++; - } - - if (mask & PANGO_FONT_MASK_STYLE) - { - parameter[n].name = "font-style"; - g_value_init (¶meter[n].value, PANGO_TYPE_STYLE); - g_value_set_enum (¶meter[n].value, - pango_font_description_get_style (description)); - n++; - } - - if (mask & PANGO_FONT_MASK_VARIANT) - { - parameter[n].name = "font-variant"; - g_value_init (¶meter[n].value, PANGO_TYPE_VARIANT); - g_value_set_enum (¶meter[n].value, - pango_font_description_get_variant (description)); - n++; - } - - if (mask & PANGO_FONT_MASK_WEIGHT) + switch (prop_id) { - parameter[n].name = "font-weight"; - g_value_init (¶meter[n].value, PANGO_TYPE_WEIGHT); - g_value_set_enum (¶meter[n].value, - pango_font_description_get_weight (description)); - n++; - } - - if (mask & PANGO_FONT_MASK_SIZE) - { - parameter[n].name = "font-size"; - g_value_init (¶meter[n].value, G_TYPE_DOUBLE); - g_value_set_double (¶meter[n].value, - (double) pango_font_description_get_size (description) / PANGO_SCALE); - n++; + case PROP_NAME: + property->name = g_value_dup_string (value); + g_assert (property->name); + g_assert (g_hash_table_lookup (klass->properties, property->name) == NULL); + g_hash_table_insert (klass->properties, property->name, property); + break; + case PROP_VALUE_TYPE: + property->value_type = g_value_get_gtype (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; } - - *n_params = n; - - return parameter; } static void -pack_font_description (GValue *value, - GtkStyleProperties *props, - GtkStateFlags state, - GtkStylePropertyContext *context) -{ - PangoFontDescription *description; - char **families; - PangoStyle style; - PangoVariant variant; - PangoWeight weight; - double size; - - gtk_style_properties_get (props, - state, - "font-family", &families, - "font-style", &style, - "font-variant", &variant, - "font-weight", &weight, - "font-size", &size, - NULL); - - description = pango_font_description_new (); - /* xxx: Can we set all the families here somehow? */ - if (families) - pango_font_description_set_family (description, families[0]); - pango_font_description_set_size (description, round (size * PANGO_SCALE)); - pango_font_description_set_style (description, style); - pango_font_description_set_variant (description, variant); - pango_font_description_set_weight (description, weight); - - g_strfreev (families); - - g_value_take_boxed (value, description); -} - -static GParameter * -unpack_border_color (const GValue *value, - guint *n_params) +gtk_style_property_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) { - GParameter *parameter = g_new0 (GParameter, 4); - GType type; - - type = G_VALUE_TYPE (value); - if (type == G_TYPE_PTR_ARRAY) - type = GTK_TYPE_SYMBOLIC_COLOR; + GtkStyleProperty *property = GTK_STYLE_PROPERTY (object); - parameter[0].name = "border-top-color"; - g_value_init (¶meter[0].value, type); - parameter[1].name = "border-right-color"; - g_value_init (¶meter[1].value, type); - parameter[2].name = "border-bottom-color"; - g_value_init (¶meter[2].value, type); - parameter[3].name = "border-left-color"; - g_value_init (¶meter[3].value, type); - - if (G_VALUE_TYPE (value) == G_TYPE_PTR_ARRAY) - { - GPtrArray *array = g_value_get_boxed (value); - guint i; - - for (i = 0; i < 4; i++) - g_value_set_boxed (¶meter[i].value, g_ptr_array_index (array, i)); - } - else + switch (prop_id) { - /* can be RGBA or symbolic color */ - gpointer p = g_value_get_boxed (value); - - g_value_set_boxed (¶meter[0].value, p); - g_value_set_boxed (¶meter[1].value, p); - g_value_set_boxed (¶meter[2].value, p); - g_value_set_boxed (¶meter[3].value, p); + case PROP_NAME: + g_value_set_string (value, property->name); + break; + case PROP_VALUE_TYPE: + g_value_set_gtype (value, property->value_type); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; } - - *n_params = 4; - return parameter; -} - -static void -pack_border_color (GValue *value, - GtkStyleProperties *props, - GtkStateFlags state, - GtkStylePropertyContext *context) -{ - /* NB: We are a color property, so we have to resolve to a color here. - * So we just resolve to a color. We pick one and stick to it. - * Lesson learned: Don't query border-color shorthand, query the - * real properties instead. */ - g_value_unset (value); - gtk_style_properties_get_property (props, "border-top-color", state, value); -} - -/*** UNSET FUNCS ***/ - -static void -unset_font_description (GtkStyleProperties *props, - GtkStateFlags state) -{ - gtk_style_properties_unset_property (props, "font-family", state); - gtk_style_properties_unset_property (props, "font-style", state); - gtk_style_properties_unset_property (props, "font-variant", state); - gtk_style_properties_unset_property (props, "font-weight", state); - gtk_style_properties_unset_property (props, "font-size", state); -} - -static void -unset_margin (GtkStyleProperties *props, - GtkStateFlags state) -{ - gtk_style_properties_unset_property (props, "margin-top", state); - gtk_style_properties_unset_property (props, "margin-right", state); - gtk_style_properties_unset_property (props, "margin-bottom", state); - gtk_style_properties_unset_property (props, "margin-left", state); -} - -static void -unset_padding (GtkStyleProperties *props, - GtkStateFlags state) -{ - gtk_style_properties_unset_property (props, "padding-top", state); - gtk_style_properties_unset_property (props, "padding-right", state); - gtk_style_properties_unset_property (props, "padding-bottom", state); - gtk_style_properties_unset_property (props, "padding-left", state); -} - -static void -unset_border_width (GtkStyleProperties *props, - GtkStateFlags state) -{ - gtk_style_properties_unset_property (props, "border-top-width", state); - gtk_style_properties_unset_property (props, "border-right-width", state); - gtk_style_properties_unset_property (props, "border-bottom-width", state); - gtk_style_properties_unset_property (props, "border-left-width", state); -} - -static void -unset_border_radius (GtkStyleProperties *props, - GtkStateFlags state) -{ - gtk_style_properties_unset_property (props, "border-top-right-radius", state); - gtk_style_properties_unset_property (props, "border-bottom-right-radius", state); - gtk_style_properties_unset_property (props, "border-bottom-left-radius", state); - gtk_style_properties_unset_property (props, "border-top-left-radius", state); -} - -static void -unset_border_color (GtkStyleProperties *props, - GtkStateFlags state) -{ - gtk_style_properties_unset_property (props, "border-top-color", state); - gtk_style_properties_unset_property (props, "border-right-color", state); - gtk_style_properties_unset_property (props, "border-bottom-color", state); - gtk_style_properties_unset_property (props, "border-left-color", state); -} - -static void -unset_border_image (GtkStyleProperties *props, - GtkStateFlags state) -{ - gtk_style_properties_unset_property (props, "border-image-source", state); - gtk_style_properties_unset_property (props, "border-image-slice", state); - gtk_style_properties_unset_property (props, "border-image-repeat", state); - gtk_style_properties_unset_property (props, "border-image-width", state); } -/*** default values ***/ - static void -border_image_width_default_value (GtkStyleProperties *props, - GtkStateFlags state, - GValue *value) +_gtk_style_property_class_init (GtkStylePropertyClass *klass) { -} + GObjectClass *object_class = G_OBJECT_CLASS (klass); -static void -background_color_default_value (GtkStyleProperties *props, - GtkStateFlags state, - GValue *value) -{ - GdkRGBA transparent_black = { 0, 0, 0, 0 }; + object_class->finalize = gtk_style_property_finalize; + object_class->set_property = gtk_style_property_set_property; + object_class->get_property = gtk_style_property_get_property; - g_value_set_boxed (value, &transparent_black); -} + g_object_class_install_property (object_class, + PROP_NAME, + g_param_spec_string ("name", + P_("Property name"), + P_("The name of the property"), + NULL, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + g_object_class_install_property (object_class, + PROP_VALUE_TYPE, + g_param_spec_gtype ("value-type", + P_("Value type"), + P_("The value type returned by GtkStyleContext"), + G_TYPE_NONE, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); -static void -border_color_default_value (GtkStyleProperties *props, - GtkStateFlags state, - GValue *value) -{ - g_value_unset (value); - gtk_style_properties_get_property (props, "color", state, value); + klass->properties = g_hash_table_new (g_str_hash, g_str_equal); } -/*** API ***/ - static void -css_string_funcs_init (void) +_gtk_style_property_init (GtkStyleProperty *property) { - if (G_LIKELY (parse_funcs != NULL)) - return; - - parse_funcs = g_hash_table_new (NULL, NULL); - print_funcs = g_hash_table_new (NULL, NULL); - - register_conversion_function (GDK_TYPE_RGBA, - rgba_value_parse, - rgba_value_print); - register_conversion_function (GDK_TYPE_COLOR, - color_value_parse, - color_value_print); - register_conversion_function (GTK_TYPE_SYMBOLIC_COLOR, - symbolic_color_value_parse, - symbolic_color_value_print); - register_conversion_function (PANGO_TYPE_FONT_DESCRIPTION, - font_description_value_parse, - font_description_value_print); - register_conversion_function (G_TYPE_BOOLEAN, - boolean_value_parse, - boolean_value_print); - register_conversion_function (G_TYPE_INT, - int_value_parse, - int_value_print); - register_conversion_function (G_TYPE_UINT, - uint_value_parse, - uint_value_print); - register_conversion_function (G_TYPE_DOUBLE, - double_value_parse, - double_value_print); - register_conversion_function (G_TYPE_FLOAT, - float_value_parse, - float_value_print); - register_conversion_function (G_TYPE_STRING, - string_value_parse, - string_value_print); - register_conversion_function (GTK_TYPE_THEMING_ENGINE, - theming_engine_value_parse, - theming_engine_value_print); - register_conversion_function (GTK_TYPE_ANIMATION_DESCRIPTION, - animation_description_value_parse, - animation_description_value_print); - register_conversion_function (GTK_TYPE_BORDER, - border_value_parse, - border_value_print); - register_conversion_function (GTK_TYPE_GRADIENT, - gradient_value_parse, - gradient_value_print); - register_conversion_function (CAIRO_GOBJECT_TYPE_PATTERN, - pattern_value_parse, - pattern_value_print); - register_conversion_function (GTK_TYPE_BORDER_IMAGE, - border_image_value_parse, - NULL); - register_conversion_function (GTK_TYPE_CSS_BORDER_IMAGE_REPEAT, - border_image_repeat_value_parse, - border_image_repeat_value_print); - register_conversion_function (GTK_TYPE_SHADOW, - shadow_value_parse, - shadow_value_print); - register_conversion_function (G_TYPE_ENUM, - enum_value_parse, - enum_value_print); - register_conversion_function (G_TYPE_FLAGS, - flags_value_parse, - flags_value_print); - register_conversion_function (GTK_TYPE_CSS_BACKGROUND_REPEAT, - background_repeat_value_parse, - background_repeat_value_print); + property->value_type = G_TYPE_NONE; } -gboolean -_gtk_style_property_parse_value (const GtkStyleProperty *property, - GValue *value, - GtkCssParser *parser, - GFile *base) +/** + * _gtk_style_property_parse_value: + * @property: the property + * @parser: the parser to parse from + * + * Tries to parse the given @property from the given @parser into + * @value. The type that @value will be assigned is dependant on + * the parser and no assumptions must be made about it. If the + * parsing fails, %FALSE will be returned and @value will be + * left uninitialized. + * + * Only if @property is a #GtkCssShorthandProperty, the @value will + * always be a #GtkCssValue whose values can be queried with + * _gtk_css_array_value_get_nth(). + * + * Returns: %NULL on failure or the parsed #GtkCssValue + **/ +GtkCssValue * +_gtk_style_property_parse_value (GtkStyleProperty *property, + GtkCssParser *parser) { - GtkStyleParseFunc func; - - g_return_val_if_fail (value != NULL, FALSE); - g_return_val_if_fail (parser != NULL, FALSE); - - css_string_funcs_init (); + GtkStylePropertyClass *klass; - if (property) - { - if (_gtk_css_parser_try (parser, "none", TRUE)) - { - /* Insert the default value, so it has an opportunity - * to override other style providers when merged - */ - g_param_value_set_default (property->pspec, value); - return TRUE; - } - else if (property->property_parse_func) - { - GError *error = NULL; - char *value_str; - gboolean success; - - value_str = _gtk_css_parser_read_value (parser); - if (value_str == NULL) - return FALSE; - - success = (*property->property_parse_func) (value_str, value, &error); - - g_free (value_str); - - return success; - } - - func = property->parse_func; - } - else - func = NULL; - - if (func == NULL) - func = g_hash_table_lookup (parse_funcs, - GSIZE_TO_POINTER (G_VALUE_TYPE (value))); - if (func == NULL) - func = g_hash_table_lookup (parse_funcs, - GSIZE_TO_POINTER (g_type_fundamental (G_VALUE_TYPE (value)))); + g_return_val_if_fail (GTK_IS_STYLE_PROPERTY (property), NULL); + g_return_val_if_fail (parser != NULL, NULL); - if (func == NULL) - { - _gtk_css_parser_error (parser, - "Cannot convert to type '%s'", - g_type_name (G_VALUE_TYPE (value))); - return FALSE; - } + klass = GTK_STYLE_PROPERTY_GET_CLASS (property); - return (*func) (parser, base, value); + return klass->parse_value (property, parser); } +/** + * _gtk_style_property_assign: + * @property: the property + * @props: The properties to assign to + * @state: The state to assign + * @value: (out): the #GValue with the value to be + * assigned + * + * This function is called by gtk_style_properties_set() and in + * turn gtk_style_context_set() and similar functions to set the + * value from code using old APIs. + **/ void -_gtk_style_property_print_value (const GtkStyleProperty *property, - const GValue *value, - GString *string) +_gtk_style_property_assign (GtkStyleProperty *property, + GtkStyleProperties *props, + GtkStateFlags state, + const GValue *value) { - GtkStylePrintFunc func; + GtkStylePropertyClass *klass; - css_string_funcs_init (); - - if (property) - func = property->print_func; - else - func = NULL; + g_return_if_fail (GTK_IS_STYLE_PROPERTY (property)); + g_return_if_fail (GTK_IS_STYLE_PROPERTIES (props)); + g_return_if_fail (value != NULL); - if (func == NULL) - func = g_hash_table_lookup (print_funcs, - GSIZE_TO_POINTER (G_VALUE_TYPE (value))); - if (func == NULL) - func = g_hash_table_lookup (print_funcs, - GSIZE_TO_POINTER (g_type_fundamental (G_VALUE_TYPE (value)))); + klass = GTK_STYLE_PROPERTY_GET_CLASS (property); - if (func == NULL) - { - char *s = g_strdup_value_contents (value); - g_string_append (string, s); - g_free (s); - return; - } - - func (value, string); + klass->assign (property, props, state, value); } +/** + * _gtk_style_property_query: + * @property: the property + * @value: (out): an uninitialized #GValue to be filled with the + * contents of the lookup + * @query_func: The function to use to query properties + * @query_data: The data to pass to @query_func + * + * This function is called by gtk_style_properties_get() and in + * turn gtk_style_context_get() and similar functions to get the + * value to return to code using old APIs. + **/ void -_gtk_style_property_default_value (const GtkStyleProperty *property, - GtkStyleProperties *properties, - GtkStateFlags state, - GValue *value) -{ - if (property->default_value_func) - property->default_value_func (properties, state, value); - else if (property->pspec->value_type == GTK_TYPE_THEMING_ENGINE) - g_value_set_object (value, gtk_theming_engine_load (NULL)); - else if (property->pspec->value_type == PANGO_TYPE_FONT_DESCRIPTION) - g_value_take_boxed (value, pango_font_description_from_string ("Sans 10")); - else if (property->pspec->value_type == GDK_TYPE_RGBA) - { - GdkRGBA color; - gdk_rgba_parse (&color, "pink"); - g_value_set_boxed (value, &color); - } - else if (property->pspec->value_type == GTK_TYPE_BORDER) - { - g_value_take_boxed (value, gtk_border_new ()); - } - else - g_param_value_set_default (property->pspec, value); -} - -gboolean -_gtk_style_property_is_inherit (const GtkStyleProperty *property) -{ - g_return_val_if_fail (property != NULL, FALSE); - - return property->flags & GTK_STYLE_PROPERTY_INHERIT ? TRUE : FALSE; -} - -static gboolean -resolve_color (GtkStyleProperties *props, - GValue *value) -{ - GdkRGBA color; - - /* Resolve symbolic color to GdkRGBA */ - if (!gtk_symbolic_color_resolve (g_value_get_boxed (value), props, &color)) - return FALSE; - - /* Store it back, this is where GdkRGBA caching happens */ - g_value_unset (value); - g_value_init (value, GDK_TYPE_RGBA); - g_value_set_boxed (value, &color); - - return TRUE; -} - -static gboolean -resolve_color_rgb (GtkStyleProperties *props, - GValue *value) -{ - GdkColor color = { 0 }; - GdkRGBA rgba; - - if (!gtk_symbolic_color_resolve (g_value_get_boxed (value), props, &rgba)) - return FALSE; - - color.red = rgba.red * 65535. + 0.5; - color.green = rgba.green * 65535. + 0.5; - color.blue = rgba.blue * 65535. + 0.5; - - g_value_unset (value); - g_value_init (value, GDK_TYPE_COLOR); - g_value_set_boxed (value, &color); - - return TRUE; -} - -static gboolean -resolve_win32_theme_part (GtkStyleProperties *props, - GValue *value, - GValue *value_out, - GtkStylePropertyContext *context) -{ - GtkWin32ThemePart *part; - cairo_pattern_t *pattern; - - part = g_value_get_boxed (value); - if (part == NULL) - return FALSE; - - pattern = _gtk_win32_theme_part_render (part, context->width, context->height); - - g_value_take_boxed (value_out, pattern); - - return TRUE; -} - - -static gboolean -resolve_gradient (GtkStyleProperties *props, - GValue *value) -{ - cairo_pattern_t *gradient; - - if (!gtk_gradient_resolve (g_value_get_boxed (value), props, &gradient)) - return FALSE; - - /* Store it back, this is where cairo_pattern_t caching happens */ - g_value_unset (value); - g_value_init (value, CAIRO_GOBJECT_TYPE_PATTERN); - g_value_take_boxed (value, gradient); - - return TRUE; -} - -static gboolean -resolve_shadow (GtkStyleProperties *props, - GValue *value) +_gtk_style_property_query (GtkStyleProperty *property, + GValue *value, + GtkStyleQueryFunc query_func, + gpointer query_data) { - GtkShadow *resolved, *base; - - base = g_value_get_boxed (value); + GtkStylePropertyClass *klass; - if (base == NULL) - return TRUE; - - if (_gtk_shadow_get_resolved (base)) - return TRUE; + g_return_if_fail (value != NULL); + g_return_if_fail (GTK_IS_STYLE_PROPERTY (property)); + g_return_if_fail (query_func != NULL); - resolved = _gtk_shadow_resolve (base, props); - if (resolved == NULL) - return FALSE; + klass = GTK_STYLE_PROPERTY_GET_CLASS (property); - g_value_take_boxed (value, resolved); - - return TRUE; + return klass->query (property, value, query_func, query_data); } void -_gtk_style_property_resolve (const GtkStyleProperty *property, - GtkStyleProperties *props, - GtkStateFlags state, - GtkStylePropertyContext *context, - GValue *val, - GValue *val_out) -{ - if (G_VALUE_TYPE (val) == GTK_TYPE_SYMBOLIC_COLOR) - { - if (property->pspec->value_type == GDK_TYPE_RGBA) - { - if (resolve_color (props, val)) - goto out; - } - else if (property->pspec->value_type == GDK_TYPE_COLOR) - { - if (resolve_color_rgb (props, val)) - goto out; - } - - g_value_unset (val); - g_value_init (val, property->pspec->value_type); - _gtk_style_property_default_value (property, props, state, val); - } - else if (G_VALUE_TYPE (val) == GDK_TYPE_RGBA) - { - if (g_value_get_boxed (val) == NULL) - _gtk_style_property_default_value (property, props, state, val); - } - else if (G_VALUE_TYPE (val) == GTK_TYPE_GRADIENT) - { - g_return_if_fail (property->pspec->value_type == CAIRO_GOBJECT_TYPE_PATTERN); - - if (!resolve_gradient (props, val)) - { - g_value_unset (val); - g_value_init (val, CAIRO_GOBJECT_TYPE_PATTERN); - _gtk_style_property_default_value (property, props, state, val); - } - } - else if (G_VALUE_TYPE (val) == GTK_TYPE_SHADOW) - { - if (!resolve_shadow (props, val)) - _gtk_style_property_default_value (property, props, state, val); - } - else if (G_VALUE_TYPE (val) == GTK_TYPE_WIN32_THEME_PART) - { - if (resolve_win32_theme_part (props, val, val_out, context)) - return; /* Don't copy val, this sets val_out */ - _gtk_style_property_default_value (property, props, state, val); - } - - out: - g_value_copy (val, val_out); -} - -gboolean -_gtk_style_property_is_shorthand (const GtkStyleProperty *property) -{ - g_return_val_if_fail (property != NULL, FALSE); - - return property->pack_func != NULL; -} - -GParameter * -_gtk_style_property_unpack (const GtkStyleProperty *property, - const GValue *value, - guint *n_params) +_gtk_style_property_init_properties (void) { - g_return_val_if_fail (property != NULL, NULL); - g_return_val_if_fail (property->unpack_func != NULL, NULL); - g_return_val_if_fail (value != NULL, NULL); - g_return_val_if_fail (n_params != NULL, NULL); + static gboolean initialized = FALSE; - return property->unpack_func (value, n_params); -} + if (G_LIKELY (initialized)) + return; -void -_gtk_style_property_pack (const GtkStyleProperty *property, - GtkStyleProperties *props, - GtkStateFlags state, - GtkStylePropertyContext *context, - GValue *value) -{ - g_return_if_fail (property != NULL); - g_return_if_fail (property->pack_func != NULL); - g_return_if_fail (GTK_IS_STYLE_PROPERTIES (props)); - g_return_if_fail (G_IS_VALUE (value)); + initialized = TRUE; - property->pack_func (value, props, state, context); + _gtk_css_style_property_init_properties (); + /* initialize shorthands last, they depend on the real properties existing */ + _gtk_css_shorthand_property_init_properties (); } -static void -gtk_style_property_init (void) +/** + * _gtk_style_property_lookup: + * @name: name of the property to lookup + * + * Looks up the CSS property with the given @name. If no such + * property exists, %NULL is returned. + * + * Returns: (transfer none): The property or %NULL if no + * property with the given name exists. + **/ +GtkStyleProperty * +_gtk_style_property_lookup (const char *name) { - if (G_LIKELY (properties)) - return; - - /* stuff is never freed, so no need for free functions */ - properties = g_hash_table_new (g_str_hash, g_str_equal); - - /* note that gtk_style_properties_register_property() calls this function, - * so make sure we're sanely inited to avoid infloops */ - - _gtk_style_property_register (g_param_spec_boxed ("color", - "Foreground color", - "Foreground color", - GDK_TYPE_RGBA, 0), - GTK_STYLE_PROPERTY_INHERIT, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL); - _gtk_style_property_register (g_param_spec_boxed ("background-color", - "Background color", - "Background color", - GDK_TYPE_RGBA, 0), - 0, - NULL, - NULL, - NULL, - transparent_color_value_parse, - NULL, - background_color_default_value, - NULL); - - _gtk_style_property_register (g_param_spec_boxed ("font-family", - "Font family", - "Font family", - G_TYPE_STRV, 0), - GTK_STYLE_PROPERTY_INHERIT, - NULL, - NULL, - NULL, - font_family_parse, - font_family_value_print, - NULL, - NULL); - _gtk_style_property_register (g_param_spec_enum ("font-style", - "Font style", - "Font style", - PANGO_TYPE_STYLE, - PANGO_STYLE_NORMAL, 0), - GTK_STYLE_PROPERTY_INHERIT, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL); - _gtk_style_property_register (g_param_spec_enum ("font-variant", - "Font variant", - "Font variant", - PANGO_TYPE_VARIANT, - PANGO_VARIANT_NORMAL, 0), - GTK_STYLE_PROPERTY_INHERIT, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL); - /* xxx: need to parse this properly, ie parse the numbers */ - _gtk_style_property_register (g_param_spec_enum ("font-weight", - "Font weight", - "Font weight", - PANGO_TYPE_WEIGHT, - PANGO_WEIGHT_NORMAL, 0), - GTK_STYLE_PROPERTY_INHERIT, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL); - _gtk_style_property_register (g_param_spec_double ("font-size", - "Font size", - "Font size", - 0, G_MAXDOUBLE, 0, 0), - GTK_STYLE_PROPERTY_INHERIT, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL); - _gtk_style_property_register (g_param_spec_boxed ("font", - "Font Description", - "Font Description", - PANGO_TYPE_FONT_DESCRIPTION, 0), - GTK_STYLE_PROPERTY_INHERIT, - NULL, - unpack_font_description, - pack_font_description, - font_description_value_parse, - font_description_value_print, - NULL, - unset_font_description); + GtkStylePropertyClass *klass; - _gtk_style_property_register (g_param_spec_boxed ("text-shadow", - "Text shadow", - "Text shadow", - GTK_TYPE_SHADOW, 0), - GTK_STYLE_PROPERTY_INHERIT, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL); + g_return_val_if_fail (name != NULL, NULL); - _gtk_style_property_register (g_param_spec_boxed ("icon-shadow", - "Icon shadow", - "Icon shadow", - GTK_TYPE_SHADOW, 0), - GTK_STYLE_PROPERTY_INHERIT, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL); + _gtk_style_property_init_properties (); - gtk_style_properties_register_property (NULL, - g_param_spec_boxed ("box-shadow", - "Box shadow", - "Box shadow", - GTK_TYPE_SHADOW, 0)); - gtk_style_properties_register_property (NULL, - g_param_spec_int ("margin-top", - "margin top", - "Margin at top", - 0, G_MAXINT, 0, 0)); - gtk_style_properties_register_property (NULL, - g_param_spec_int ("margin-left", - "margin left", - "Margin at left", - 0, G_MAXINT, 0, 0)); - gtk_style_properties_register_property (NULL, - g_param_spec_int ("margin-bottom", - "margin bottom", - "Margin at bottom", - 0, G_MAXINT, 0, 0)); - gtk_style_properties_register_property (NULL, - g_param_spec_int ("margin-right", - "margin right", - "Margin at right", - 0, G_MAXINT, 0, 0)); - _gtk_style_property_register (g_param_spec_boxed ("margin", - "Margin", - "Margin", - GTK_TYPE_BORDER, 0), - 0, - NULL, - unpack_margin, - pack_margin, - NULL, - NULL, - NULL, - unset_margin); - gtk_style_properties_register_property (NULL, - g_param_spec_int ("padding-top", - "padding top", - "Padding at top", - 0, G_MAXINT, 0, 0)); - gtk_style_properties_register_property (NULL, - g_param_spec_int ("padding-left", - "padding left", - "Padding at left", - 0, G_MAXINT, 0, 0)); - gtk_style_properties_register_property (NULL, - g_param_spec_int ("padding-bottom", - "padding bottom", - "Padding at bottom", - 0, G_MAXINT, 0, 0)); - gtk_style_properties_register_property (NULL, - g_param_spec_int ("padding-right", - "padding right", - "Padding at right", - 0, G_MAXINT, 0, 0)); - _gtk_style_property_register (g_param_spec_boxed ("padding", - "Padding", - "Padding", - GTK_TYPE_BORDER, 0), - 0, - NULL, - unpack_padding, - pack_padding, - NULL, - NULL, - NULL, - unset_padding); - gtk_style_properties_register_property (NULL, - g_param_spec_int ("border-top-width", - "border top width", - "Border width at top", - 0, G_MAXINT, 0, 0)); - gtk_style_properties_register_property (NULL, - g_param_spec_int ("border-left-width", - "border left width", - "Border width at left", - 0, G_MAXINT, 0, 0)); - gtk_style_properties_register_property (NULL, - g_param_spec_int ("border-bottom-width", - "border bottom width", - "Border width at bottom", - 0, G_MAXINT, 0, 0)); - gtk_style_properties_register_property (NULL, - g_param_spec_int ("border-right-width", - "border right width", - "Border width at right", - 0, G_MAXINT, 0, 0)); - _gtk_style_property_register (g_param_spec_boxed ("border-width", - "Border width", - "Border width, in pixels", - GTK_TYPE_BORDER, 0), - 0, - NULL, - unpack_border_width, - pack_border_width, - NULL, - NULL, - NULL, - unset_border_width); + klass = g_type_class_peek (GTK_TYPE_STYLE_PROPERTY); - _gtk_style_property_register (g_param_spec_boxed ("border-top-left-radius", - "Border top left radius", - "Border radius of top left corner, in pixels", - GTK_TYPE_CSS_BORDER_CORNER_RADIUS, 0), - 0, - NULL, - NULL, - NULL, - border_corner_radius_value_parse, - border_corner_radius_value_print, - NULL, - NULL); - _gtk_style_property_register (g_param_spec_boxed ("border-top-right-radius", - "Border top right radius", - "Border radius of top right corner, in pixels", - GTK_TYPE_CSS_BORDER_CORNER_RADIUS, 0), - 0, - NULL, - NULL, - NULL, - border_corner_radius_value_parse, - border_corner_radius_value_print, - NULL, - NULL); - _gtk_style_property_register (g_param_spec_boxed ("border-bottom-right-radius", - "Border bottom right radius", - "Border radius of bottom right corner, in pixels", - GTK_TYPE_CSS_BORDER_CORNER_RADIUS, 0), - 0, - NULL, - NULL, - NULL, - border_corner_radius_value_parse, - border_corner_radius_value_print, - NULL, - NULL); - _gtk_style_property_register (g_param_spec_boxed ("border-bottom-left-radius", - "Border bottom left radius", - "Border radius of bottom left corner, in pixels", - GTK_TYPE_CSS_BORDER_CORNER_RADIUS, 0), - 0, - NULL, - NULL, - NULL, - border_corner_radius_value_parse, - border_corner_radius_value_print, - NULL, - NULL); - _gtk_style_property_register (g_param_spec_int ("border-radius", - "Border radius", - "Border radius, in pixels", - 0, G_MAXINT, 0, 0), - 0, - NULL, - unpack_border_radius, - pack_border_radius, - border_radius_value_parse, - border_radius_value_print, - NULL, - unset_border_radius); - - 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_property_register (g_param_spec_boxed ("border-top-color", - "Border top color", - "Border top color", - GDK_TYPE_RGBA, 0), - 0, - NULL, - NULL, - NULL, - transparent_color_value_parse, - NULL, - border_color_default_value, - NULL); - _gtk_style_property_register (g_param_spec_boxed ("border-right-color", - "Border right color", - "Border right color", - GDK_TYPE_RGBA, 0), - 0, - NULL, - NULL, - NULL, - transparent_color_value_parse, - NULL, - border_color_default_value, - NULL); - _gtk_style_property_register (g_param_spec_boxed ("border-bottom-color", - "Border bottom color", - "Border bottom color", - GDK_TYPE_RGBA, 0), - 0, - NULL, - NULL, - NULL, - transparent_color_value_parse, - NULL, - border_color_default_value, - NULL); - _gtk_style_property_register (g_param_spec_boxed ("border-left-color", - "Border left color", - "Border left color", - GDK_TYPE_RGBA, 0), - 0, - NULL, - NULL, - NULL, - transparent_color_value_parse, - NULL, - border_color_default_value, - NULL); - _gtk_style_property_register (g_param_spec_boxed ("border-color", - "Border color", - "Border color", - GDK_TYPE_RGBA, 0), - 0, - NULL, - unpack_border_color, - pack_border_color, - border_color_shorthand_value_parse, - NULL, - NULL, - unset_border_color); - - 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 ("background-repeat", - "Background repeat", - "Background repeat", - GTK_TYPE_CSS_BACKGROUND_REPEAT, 0)); - - gtk_style_properties_register_property (NULL, - g_param_spec_boxed ("border-image-source", - "Border image source", - "Border image source", - CAIRO_GOBJECT_TYPE_PATTERN, 0)); - gtk_style_properties_register_property (NULL, - g_param_spec_boxed ("border-image-repeat", - "Border image repeat", - "Border image repeat", - GTK_TYPE_CSS_BORDER_IMAGE_REPEAT, 0)); - gtk_style_properties_register_property (NULL, - g_param_spec_boxed ("border-image-slice", - "Border image slice", - "Border image slice", - GTK_TYPE_BORDER, 0)); - _gtk_style_property_register (g_param_spec_boxed ("border-image-width", - "Border image width", - "Border image width", - GTK_TYPE_BORDER, 0), - 0, - NULL, - NULL, - NULL, - NULL, - NULL, - border_image_width_default_value, - NULL); - _gtk_style_property_register (g_param_spec_boxed ("border-image", - "Border Image", - "Border Image", - GTK_TYPE_BORDER_IMAGE, 0), - 0, - NULL, - _gtk_border_image_unpack, - _gtk_border_image_pack, - NULL, - NULL, - NULL, - unset_border_image); - 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)); - - /* Private property holding the binding sets */ - _gtk_style_property_register (g_param_spec_boxed ("gtk-key-bindings", - "Key bindings", - "Key bindings", - G_TYPE_PTR_ARRAY, 0), - 0, - NULL, - NULL, - NULL, - bindings_value_parse, - bindings_value_print, - NULL, - NULL); + return g_hash_table_lookup (klass->properties, name); } -const GtkStyleProperty * -_gtk_style_property_lookup (const char *name) +/** + * _gtk_style_property_get_name: + * @property: the property to query + * + * Gets the name of the given property. + * + * Returns: the name of the property + **/ +const char * +_gtk_style_property_get_name (GtkStyleProperty *property) { - gtk_style_property_init (); + g_return_val_if_fail (GTK_IS_STYLE_PROPERTY (property), NULL); - return g_hash_table_lookup (properties, name); + return property->name; } -void -_gtk_style_property_register (GParamSpec *pspec, - GtkStylePropertyFlags flags, - GtkStylePropertyParser property_parse_func, - GtkStyleUnpackFunc unpack_func, - GtkStylePackFunc pack_func, - GtkStyleParseFunc parse_func, - GtkStylePrintFunc print_func, - GtkStyleDefaultValueFunc default_value_func, - GtkStyleUnsetFunc unset_func) +/** + * _gtk_style_property_get_value_type: + * @property: the property to query + * + * Gets the value type of the @property, if the property is usable + * in public API via _gtk_style_property_assign() and + * _gtk_style_property_query(). If the @property is not usable in that + * way, %G_TYPE_NONE is returned. + * + * Returns: the value type in use or %G_TYPE_NONE if none. + **/ +GType +_gtk_style_property_get_value_type (GtkStyleProperty *property) { - const GtkStyleProperty *existing; - GtkStyleProperty *node; - - g_return_if_fail ((pack_func == NULL) == (unpack_func == NULL)); - - gtk_style_property_init (); - - existing = _gtk_style_property_lookup (pspec->name); - if (existing != NULL) - { - g_warning ("Property \"%s\" was already registered with type %s", - pspec->name, g_type_name (existing->pspec->value_type)); - return; - } - - node = g_slice_new0 (GtkStyleProperty); - node->flags = flags; - node->pspec = pspec; - node->property_parse_func = property_parse_func; - node->pack_func = pack_func; - node->unpack_func = unpack_func; - node->parse_func = parse_func; - node->print_func = print_func; - node->default_value_func = default_value_func; - node->unset_func = unset_func; + g_return_val_if_fail (GTK_IS_STYLE_PROPERTY (property), G_TYPE_NONE); - /* pspec owns name */ - g_hash_table_insert (properties, (gchar *)pspec->name, node); + return property->value_type; }