2011-04-08 14:08:28 +00:00
|
|
|
/* GTK - The GIMP Toolkit
|
|
|
|
* Copyright (C) 2010 Carlos Garnacho <carlosg@gnome.org>
|
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
|
|
|
#include "gtkcssstringfuncsprivate.h"
|
|
|
|
|
|
|
|
#include <errno.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#include <gdk-pixbuf/gdk-pixbuf.h>
|
|
|
|
#include <cairo-gobject.h>
|
|
|
|
|
|
|
|
#include "gtkcssprovider.h"
|
2011-04-14 02:47:18 +00:00
|
|
|
#include "gtkcssparserprivate.h"
|
2011-04-08 14:08:28 +00:00
|
|
|
|
|
|
|
/* the actual parsers we have */
|
|
|
|
#include "gtkanimationdescription.h"
|
2011-05-18 16:03:23 +00:00
|
|
|
#include "gtkbindings.h"
|
2011-04-08 14:08:28 +00:00
|
|
|
#include "gtk9slice.h"
|
|
|
|
#include "gtkgradient.h"
|
|
|
|
#include "gtkthemingengine.h"
|
|
|
|
|
2011-05-18 16:32:22 +00:00
|
|
|
typedef gboolean (* ParseFunc) (GtkCssParser *parser,
|
2011-04-08 14:08:28 +00:00
|
|
|
GFile *base,
|
2011-05-18 16:32:22 +00:00
|
|
|
GValue *value);
|
2011-04-08 14:08:28 +00:00
|
|
|
typedef char * (* ToStringFunc) (const GValue *value);
|
|
|
|
|
2011-05-18 16:32:22 +00:00
|
|
|
static GHashTable *parse_funcs = NULL;
|
2011-04-08 14:08:28 +00:00
|
|
|
static GHashTable *to_string_funcs = NULL;
|
|
|
|
|
|
|
|
static void
|
|
|
|
register_conversion_function (GType type,
|
2011-05-18 16:32:22 +00:00
|
|
|
ParseFunc parse,
|
2011-04-08 14:08:28 +00:00
|
|
|
ToStringFunc to_string)
|
|
|
|
{
|
2011-05-18 16:32:22 +00:00
|
|
|
if (parse)
|
|
|
|
g_hash_table_insert (parse_funcs, GSIZE_TO_POINTER (type), parse);
|
2011-04-08 14:08:28 +00:00
|
|
|
if (to_string)
|
|
|
|
g_hash_table_insert (to_string_funcs, GSIZE_TO_POINTER (type), to_string);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*** IMPLEMENTATIONS ***/
|
|
|
|
|
|
|
|
static gboolean
|
2011-05-18 16:32:22 +00:00
|
|
|
rgba_value_parse (GtkCssParser *parser,
|
|
|
|
GFile *base,
|
|
|
|
GValue *value)
|
2011-04-08 14:08:28 +00:00
|
|
|
{
|
|
|
|
GtkSymbolicColor *symbolic;
|
|
|
|
GdkRGBA rgba;
|
|
|
|
|
2011-05-18 16:32:22 +00:00
|
|
|
symbolic = _gtk_css_parser_read_symbolic_color (parser);
|
2011-04-08 14:08:28 +00:00
|
|
|
if (symbolic == NULL)
|
|
|
|
return FALSE;
|
|
|
|
|
2011-05-18 11:15:05 +00:00
|
|
|
if (gtk_symbolic_color_resolve (symbolic, NULL, &rgba))
|
|
|
|
{
|
|
|
|
g_value_set_boxed (value, &rgba);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
g_value_unset (value);
|
|
|
|
g_value_init (value, GTK_TYPE_SYMBOLIC_COLOR);
|
|
|
|
g_value_take_boxed (value, symbolic);
|
|
|
|
}
|
|
|
|
|
2011-04-08 14:08:28 +00:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static char *
|
|
|
|
rgba_value_to_string (const GValue *value)
|
|
|
|
{
|
|
|
|
const GdkRGBA *rgba = g_value_get_boxed (value);
|
|
|
|
|
|
|
|
if (rgba == NULL)
|
|
|
|
return g_strdup ("none");
|
|
|
|
|
|
|
|
return gdk_rgba_to_string (rgba);
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
2011-05-18 16:32:22 +00:00
|
|
|
color_value_parse (GtkCssParser *parser,
|
|
|
|
GFile *base,
|
|
|
|
GValue *value)
|
2011-04-08 14:08:28 +00:00
|
|
|
{
|
|
|
|
GtkSymbolicColor *symbolic;
|
2011-05-18 11:15:05 +00:00
|
|
|
GdkRGBA rgba;
|
2011-04-08 14:08:28 +00:00
|
|
|
|
2011-05-18 16:32:22 +00:00
|
|
|
symbolic = _gtk_css_parser_read_symbolic_color (parser);
|
2011-04-08 14:08:28 +00:00
|
|
|
if (symbolic == NULL)
|
|
|
|
return FALSE;
|
|
|
|
|
2011-05-18 11:15:05 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2011-04-08 14:08:28 +00:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static char *
|
|
|
|
color_value_to_string (const GValue *value)
|
|
|
|
{
|
|
|
|
const GdkColor *color = g_value_get_boxed (value);
|
|
|
|
|
|
|
|
if (color == NULL)
|
|
|
|
return g_strdup ("none");
|
|
|
|
|
|
|
|
return gdk_color_to_string (color);
|
|
|
|
}
|
|
|
|
|
2011-05-18 16:32:22 +00:00
|
|
|
static gboolean
|
|
|
|
symbolic_color_value_parse (GtkCssParser *parser,
|
|
|
|
GFile *base,
|
|
|
|
GValue *value)
|
2011-04-08 14:08:28 +00:00
|
|
|
{
|
|
|
|
GtkSymbolicColor *symbolic;
|
|
|
|
|
2011-05-18 16:32:22 +00:00
|
|
|
symbolic = _gtk_css_parser_read_symbolic_color (parser);
|
2011-04-08 14:08:28 +00:00
|
|
|
if (symbolic == NULL)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
g_value_take_boxed (value, symbolic);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static char *
|
|
|
|
symbolic_color_value_to_string (const GValue *value)
|
|
|
|
{
|
|
|
|
GtkSymbolicColor *symbolic = g_value_get_boxed (value);
|
|
|
|
|
|
|
|
if (symbolic == NULL)
|
|
|
|
return g_strdup ("none");
|
|
|
|
|
|
|
|
return gtk_symbolic_color_to_string (symbolic);
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
2011-05-18 16:32:22 +00:00
|
|
|
font_description_value_parse (GtkCssParser *parser,
|
|
|
|
GFile *base,
|
|
|
|
GValue *value)
|
2011-04-08 14:08:28 +00:00
|
|
|
{
|
|
|
|
PangoFontDescription *font_desc;
|
2011-05-18 16:32:22 +00:00
|
|
|
char *str;
|
|
|
|
|
|
|
|
str = _gtk_css_parser_read_value (parser);
|
|
|
|
if (str == NULL)
|
|
|
|
return FALSE;
|
2011-04-08 14:08:28 +00:00
|
|
|
|
|
|
|
font_desc = pango_font_description_from_string (str);
|
2011-05-18 16:32:22 +00:00
|
|
|
g_free (str);
|
2011-04-08 14:08:28 +00:00
|
|
|
g_value_take_boxed (value, font_desc);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static char *
|
|
|
|
font_description_value_to_string (const GValue *value)
|
|
|
|
{
|
|
|
|
const PangoFontDescription *desc = g_value_get_boxed (value);
|
|
|
|
|
|
|
|
if (desc == NULL)
|
|
|
|
return g_strdup ("none");
|
|
|
|
|
|
|
|
return pango_font_description_to_string (desc);
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
2011-05-18 16:32:22 +00:00
|
|
|
boolean_value_parse (GtkCssParser *parser,
|
|
|
|
GFile *base,
|
|
|
|
GValue *value)
|
2011-04-08 14:08:28 +00:00
|
|
|
{
|
2011-05-18 16:32:22 +00:00
|
|
|
if (_gtk_css_parser_try (parser, "true", TRUE) ||
|
|
|
|
_gtk_css_parser_try (parser, "1", TRUE))
|
2011-04-08 14:08:28 +00:00
|
|
|
{
|
|
|
|
g_value_set_boolean (value, TRUE);
|
|
|
|
return TRUE;
|
|
|
|
}
|
2011-05-18 16:32:22 +00:00
|
|
|
else if (_gtk_css_parser_try (parser, "false", TRUE) ||
|
|
|
|
_gtk_css_parser_try (parser, "0", TRUE))
|
2011-04-08 14:08:28 +00:00
|
|
|
{
|
|
|
|
g_value_set_boolean (value, FALSE);
|
|
|
|
return TRUE;
|
|
|
|
}
|
2011-05-18 16:32:22 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
_gtk_css_parser_error (parser, "Expected a boolean value");
|
|
|
|
return FALSE;
|
|
|
|
}
|
2011-04-08 14:08:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static char *
|
|
|
|
boolean_value_to_string (const GValue *value)
|
|
|
|
{
|
|
|
|
if (g_value_get_boolean (value))
|
|
|
|
return g_strdup ("true");
|
|
|
|
else
|
|
|
|
return g_strdup ("false");
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
2011-05-18 16:32:22 +00:00
|
|
|
int_value_parse (GtkCssParser *parser,
|
|
|
|
GFile *base,
|
|
|
|
GValue *value)
|
2011-04-08 14:08:28 +00:00
|
|
|
{
|
2011-05-18 16:32:22 +00:00
|
|
|
gint i;
|
2011-04-08 14:08:28 +00:00
|
|
|
|
2011-05-18 16:32:22 +00:00
|
|
|
if (!_gtk_css_parser_try_int (parser, &i))
|
2011-04-08 14:08:28 +00:00
|
|
|
{
|
2011-05-18 16:32:22 +00:00
|
|
|
_gtk_css_parser_error (parser, "Expected a valid integer value");
|
2011-04-08 14:08:28 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_value_set_int (value, i);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static char *
|
|
|
|
int_value_to_string (const GValue *value)
|
|
|
|
{
|
|
|
|
return g_strdup_printf ("%d", g_value_get_int (value));
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
2011-05-18 16:32:22 +00:00
|
|
|
uint_value_parse (GtkCssParser *parser,
|
|
|
|
GFile *base,
|
|
|
|
GValue *value)
|
2011-04-08 14:08:28 +00:00
|
|
|
{
|
2011-05-18 16:32:22 +00:00
|
|
|
guint u;
|
2011-04-14 02:47:18 +00:00
|
|
|
|
2011-05-18 16:32:22 +00:00
|
|
|
if (!_gtk_css_parser_try_uint (parser, &u))
|
2011-04-08 14:08:28 +00:00
|
|
|
{
|
2011-05-18 16:32:22 +00:00
|
|
|
_gtk_css_parser_error (parser, "Expected a valid unsigned value");
|
2011-04-08 14:08:28 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_value_set_uint (value, u);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static char *
|
|
|
|
uint_value_to_string (const GValue *value)
|
|
|
|
{
|
|
|
|
return g_strdup_printf ("%u", g_value_get_uint (value));
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
2011-05-18 16:32:22 +00:00
|
|
|
double_value_parse (GtkCssParser *parser,
|
|
|
|
GFile *base,
|
|
|
|
GValue *value)
|
2011-04-08 14:08:28 +00:00
|
|
|
{
|
2011-05-18 16:32:22 +00:00
|
|
|
gdouble d;
|
2011-04-08 14:08:28 +00:00
|
|
|
|
2011-05-18 16:32:22 +00:00
|
|
|
if (!_gtk_css_parser_try_double (parser, &d))
|
2011-04-08 14:08:28 +00:00
|
|
|
{
|
2011-05-18 16:32:22 +00:00
|
|
|
_gtk_css_parser_error (parser, "Expected a number");
|
2011-04-08 14:08:28 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_value_set_double (value, d);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static char *
|
|
|
|
double_value_to_string (const GValue *value)
|
|
|
|
{
|
|
|
|
char buf[G_ASCII_DTOSTR_BUF_SIZE];
|
|
|
|
|
|
|
|
g_ascii_dtostr (buf, sizeof (buf), g_value_get_double (value));
|
|
|
|
|
|
|
|
return g_strdup (buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
2011-05-18 16:32:22 +00:00
|
|
|
float_value_parse (GtkCssParser *parser,
|
|
|
|
GFile *base,
|
|
|
|
GValue *value)
|
2011-04-08 14:08:28 +00:00
|
|
|
{
|
2011-05-18 16:32:22 +00:00
|
|
|
gdouble d;
|
2011-04-08 14:08:28 +00:00
|
|
|
|
2011-05-18 16:32:22 +00:00
|
|
|
if (!_gtk_css_parser_try_double (parser, &d))
|
2011-04-08 14:08:28 +00:00
|
|
|
{
|
2011-05-18 16:32:22 +00:00
|
|
|
_gtk_css_parser_error (parser, "Expected a number");
|
2011-04-08 14:08:28 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_value_set_float (value, d);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static char *
|
|
|
|
float_value_to_string (const GValue *value)
|
|
|
|
{
|
|
|
|
char buf[G_ASCII_DTOSTR_BUF_SIZE];
|
|
|
|
|
|
|
|
g_ascii_dtostr (buf, sizeof (buf), g_value_get_float (value));
|
|
|
|
|
|
|
|
return g_strdup (buf);
|
|
|
|
}
|
|
|
|
|
2011-04-12 02:26:10 +00:00
|
|
|
static gboolean
|
2011-05-18 16:32:22 +00:00
|
|
|
string_value_parse (GtkCssParser *parser,
|
|
|
|
GFile *base,
|
|
|
|
GValue *value)
|
2011-04-12 02:26:10 +00:00
|
|
|
{
|
2011-05-18 16:32:22 +00:00
|
|
|
char *str = _gtk_css_parser_read_string (parser);
|
2011-04-12 02:26:10 +00:00
|
|
|
|
2011-05-18 16:32:22 +00:00
|
|
|
if (str == NULL)
|
2011-04-12 02:26:10 +00:00
|
|
|
return FALSE;
|
|
|
|
|
2011-05-18 16:32:22 +00:00
|
|
|
g_value_take_string (value, str);
|
2011-04-12 02:26:10 +00:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static char *
|
|
|
|
string_value_to_string (const GValue *value)
|
|
|
|
{
|
|
|
|
const char *string;
|
|
|
|
gsize len;
|
|
|
|
GString *str;
|
|
|
|
|
|
|
|
string = g_value_get_string (value);
|
|
|
|
str = g_string_new ("\"");
|
|
|
|
|
|
|
|
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, '"');
|
|
|
|
return g_string_free (str, FALSE);
|
|
|
|
}
|
|
|
|
|
2011-04-08 14:08:28 +00:00
|
|
|
static gboolean
|
2011-05-18 16:32:22 +00:00
|
|
|
theming_engine_value_parse (GtkCssParser *parser,
|
|
|
|
GFile *base,
|
|
|
|
GValue *value)
|
2011-04-08 14:08:28 +00:00
|
|
|
{
|
|
|
|
GtkThemingEngine *engine;
|
2011-05-18 16:32:22 +00:00
|
|
|
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;
|
|
|
|
}
|
2011-04-08 14:08:28 +00:00
|
|
|
|
|
|
|
engine = gtk_theming_engine_load (str);
|
|
|
|
if (engine == NULL)
|
|
|
|
{
|
2011-05-18 16:32:22 +00:00
|
|
|
_gtk_css_parser_error (parser, "Themeing engine '%s' not found", str);
|
|
|
|
g_free (str);
|
2011-04-08 14:08:28 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_value_set_object (value, engine);
|
2011-05-18 16:32:22 +00:00
|
|
|
g_free (str);
|
2011-04-08 14:08:28 +00:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static char *
|
|
|
|
theming_engine_value_to_string (const GValue *value)
|
|
|
|
{
|
|
|
|
GtkThemingEngine *engine;
|
|
|
|
char *name;
|
|
|
|
|
|
|
|
engine = g_value_get_object (value);
|
|
|
|
if (engine == NULL)
|
|
|
|
return g_strdup ("none");
|
|
|
|
|
|
|
|
/* XXX: gtk_theming_engine_get_name()? */
|
|
|
|
g_object_get (engine, "name", &name, NULL);
|
|
|
|
|
|
|
|
return name;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
2011-05-18 16:32:22 +00:00
|
|
|
animation_description_value_parse (GtkCssParser *parser,
|
|
|
|
GFile *base,
|
|
|
|
GValue *value)
|
2011-04-08 14:08:28 +00:00
|
|
|
{
|
|
|
|
GtkAnimationDescription *desc;
|
2011-05-18 16:32:22 +00:00
|
|
|
char *str;
|
|
|
|
|
|
|
|
str = _gtk_css_parser_read_value (parser);
|
|
|
|
if (str == NULL)
|
|
|
|
return FALSE;
|
2011-04-08 14:08:28 +00:00
|
|
|
|
|
|
|
desc = _gtk_animation_description_from_string (str);
|
2011-05-18 16:32:22 +00:00
|
|
|
g_free (str);
|
2011-04-08 14:08:28 +00:00
|
|
|
|
|
|
|
if (desc == NULL)
|
2011-05-18 16:32:22 +00:00
|
|
|
{
|
|
|
|
_gtk_css_parser_error (parser, "Invalid animation description");
|
|
|
|
return FALSE;
|
|
|
|
}
|
2011-04-08 14:08:28 +00:00
|
|
|
|
|
|
|
g_value_take_boxed (value, desc);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static char *
|
|
|
|
animation_description_value_to_string (const GValue *value)
|
|
|
|
{
|
|
|
|
GtkAnimationDescription *desc = g_value_get_boxed (value);
|
|
|
|
|
|
|
|
if (desc == NULL)
|
|
|
|
return g_strdup ("none");
|
|
|
|
|
|
|
|
return _gtk_animation_description_to_string (desc);
|
|
|
|
}
|
|
|
|
|
2011-05-18 16:32:22 +00:00
|
|
|
static gboolean
|
|
|
|
border_value_parse (GtkCssParser *parser,
|
|
|
|
GFile *base,
|
|
|
|
GValue *value)
|
2011-04-08 14:08:28 +00:00
|
|
|
{
|
2011-05-18 16:32:22 +00:00
|
|
|
GtkBorder border = { 0, };
|
|
|
|
guint i, numbers[4];
|
2011-04-08 14:08:28 +00:00
|
|
|
|
2011-05-18 16:32:22 +00:00
|
|
|
for (i = 0; i < G_N_ELEMENTS (numbers); i++)
|
2011-04-08 14:08:28 +00:00
|
|
|
{
|
2011-05-18 16:32:22 +00:00
|
|
|
if (!_gtk_css_parser_try_uint (parser, &numbers[i]))
|
|
|
|
break;
|
2011-04-08 14:08:28 +00:00
|
|
|
|
2011-05-18 16:32:22 +00:00
|
|
|
/* XXX: shouldn't allow spaces here? */
|
|
|
|
_gtk_css_parser_try (parser, "px", TRUE);
|
2011-04-08 14:08:28 +00:00
|
|
|
}
|
|
|
|
|
2011-05-18 16:32:22 +00:00
|
|
|
if (i == 0)
|
2011-04-08 14:08:28 +00:00
|
|
|
{
|
2011-05-18 16:32:22 +00:00
|
|
|
_gtk_css_parser_error (parser, "Expected valid border");
|
2011-04-08 14:08:28 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2011-05-18 16:32:22 +00:00
|
|
|
border.top = numbers[0];
|
|
|
|
if (i > 1)
|
|
|
|
border.right = numbers[1];
|
2011-04-08 14:08:28 +00:00
|
|
|
else
|
2011-05-18 16:32:22 +00:00
|
|
|
border.right = border.top;
|
|
|
|
if (i > 2)
|
|
|
|
border.bottom = numbers[2];
|
2011-04-08 14:08:28 +00:00
|
|
|
else
|
2011-05-18 16:32:22 +00:00
|
|
|
border.bottom = border.top;
|
|
|
|
if (i > 3)
|
|
|
|
border.left = numbers[3];
|
2011-04-08 14:08:28 +00:00
|
|
|
else
|
2011-05-18 16:32:22 +00:00
|
|
|
border.left = border.right;
|
2011-04-08 14:08:28 +00:00
|
|
|
|
2011-05-18 16:32:22 +00:00
|
|
|
g_value_set_boxed (value, &border);
|
2011-04-08 14:08:28 +00:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static char *
|
|
|
|
border_value_to_string (const GValue *value)
|
|
|
|
{
|
|
|
|
const GtkBorder *border = g_value_get_boxed (value);
|
|
|
|
|
|
|
|
if (border == NULL)
|
|
|
|
return g_strdup ("none");
|
|
|
|
else if (border->left != border->right)
|
|
|
|
return g_strdup_printf ("%d %d %d %d", border->top, border->right, border->bottom, border->left);
|
|
|
|
else if (border->top != border->bottom)
|
|
|
|
return g_strdup_printf ("%d %d %d", border->top, border->right, border->bottom);
|
|
|
|
else if (border->top != border->left)
|
|
|
|
return g_strdup_printf ("%d %d", border->top, border->right);
|
|
|
|
else
|
|
|
|
return g_strdup_printf ("%d", border->top);
|
|
|
|
}
|
|
|
|
|
2011-05-18 16:32:22 +00:00
|
|
|
static gboolean
|
|
|
|
gradient_value_parse (GtkCssParser *parser,
|
|
|
|
GFile *base,
|
|
|
|
GValue *value)
|
2011-04-08 14:08:28 +00:00
|
|
|
{
|
|
|
|
GtkGradient *gradient;
|
|
|
|
cairo_pattern_type_t type;
|
|
|
|
gdouble coords[6];
|
|
|
|
guint i;
|
|
|
|
|
2011-04-14 02:47:18 +00:00
|
|
|
if (!_gtk_css_parser_try (parser, "-gtk-gradient", TRUE))
|
2011-04-08 14:08:28 +00:00
|
|
|
{
|
2011-04-14 02:47:18 +00:00
|
|
|
_gtk_css_parser_error (parser,
|
|
|
|
"Expected '-gtk-gradient'");
|
2011-05-18 16:32:22 +00:00
|
|
|
return FALSE;
|
2011-04-08 14:08:28 +00:00
|
|
|
}
|
|
|
|
|
2011-04-14 02:47:18 +00:00
|
|
|
if (!_gtk_css_parser_try (parser, "(", TRUE))
|
2011-04-08 14:08:28 +00:00
|
|
|
{
|
2011-04-14 02:47:18 +00:00
|
|
|
_gtk_css_parser_error (parser,
|
|
|
|
"Expected '(' after '-gtk-gradient'");
|
2011-05-18 16:32:22 +00:00
|
|
|
return FALSE;
|
2011-04-08 14:08:28 +00:00
|
|
|
}
|
2011-04-14 02:47:18 +00:00
|
|
|
|
|
|
|
/* 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;
|
2011-04-08 14:08:28 +00:00
|
|
|
else
|
|
|
|
{
|
2011-04-14 02:47:18 +00:00
|
|
|
_gtk_css_parser_error (parser,
|
|
|
|
"Gradient type must be 'radial' or 'linear'");
|
2011-05-18 16:32:22 +00:00
|
|
|
return FALSE;
|
2011-04-08 14:08:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Parse start/stop position parameters */
|
|
|
|
for (i = 0; i < 2; i++)
|
|
|
|
{
|
2011-04-14 02:47:18 +00:00
|
|
|
if (! _gtk_css_parser_try (parser, ",", TRUE))
|
2011-04-08 14:08:28 +00:00
|
|
|
{
|
2011-04-14 02:47:18 +00:00
|
|
|
_gtk_css_parser_error (parser,
|
|
|
|
"Expected ','");
|
2011-05-18 16:32:22 +00:00
|
|
|
return FALSE;
|
2011-04-08 14:08:28 +00:00
|
|
|
}
|
|
|
|
|
2011-04-14 02:47:18 +00:00
|
|
|
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]))
|
2011-04-08 14:08:28 +00:00
|
|
|
{
|
2011-04-14 02:47:18 +00:00
|
|
|
_gtk_css_parser_error (parser,
|
|
|
|
"Expected a valid X coordinate");
|
2011-05-18 16:32:22 +00:00
|
|
|
return FALSE;
|
2011-04-08 14:08:28 +00:00
|
|
|
}
|
|
|
|
|
2011-04-14 02:47:18 +00:00
|
|
|
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]))
|
2011-04-08 14:08:28 +00:00
|
|
|
{
|
2011-04-14 02:47:18 +00:00
|
|
|
_gtk_css_parser_error (parser,
|
|
|
|
"Expected a valid Y coordinate");
|
2011-05-18 16:32:22 +00:00
|
|
|
return FALSE;
|
2011-04-08 14:08:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (type == CAIRO_PATTERN_TYPE_RADIAL)
|
|
|
|
{
|
|
|
|
/* Parse radius */
|
2011-04-14 02:47:18 +00:00
|
|
|
if (! _gtk_css_parser_try (parser, ",", TRUE))
|
2011-04-08 14:08:28 +00:00
|
|
|
{
|
2011-04-14 02:47:18 +00:00
|
|
|
_gtk_css_parser_error (parser,
|
|
|
|
"Expected ','");
|
2011-05-18 16:32:22 +00:00
|
|
|
return FALSE;
|
2011-04-08 14:08:28 +00:00
|
|
|
}
|
|
|
|
|
2011-04-14 02:47:18 +00:00
|
|
|
if (! _gtk_css_parser_try_double (parser, &coords[(i * 3) + 2]))
|
|
|
|
{
|
|
|
|
_gtk_css_parser_error (parser,
|
|
|
|
"Expected a numer for the radius");
|
2011-05-18 16:32:22 +00:00
|
|
|
return FALSE;
|
2011-04-14 02:47:18 +00:00
|
|
|
}
|
2011-04-08 14:08:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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]);
|
|
|
|
|
2011-04-14 02:47:18 +00:00
|
|
|
while (_gtk_css_parser_try (parser, ",", TRUE))
|
2011-04-08 14:08:28 +00:00
|
|
|
{
|
|
|
|
GtkSymbolicColor *color;
|
|
|
|
gdouble position;
|
|
|
|
|
2011-04-14 02:47:18 +00:00
|
|
|
if (_gtk_css_parser_try (parser, "from", TRUE))
|
2011-04-08 14:08:28 +00:00
|
|
|
{
|
|
|
|
position = 0;
|
|
|
|
|
2011-04-14 02:47:18 +00:00
|
|
|
if (!_gtk_css_parser_try (parser, "(", TRUE))
|
2011-04-08 14:08:28 +00:00
|
|
|
{
|
2011-04-14 02:47:18 +00:00
|
|
|
gtk_gradient_unref (gradient);
|
|
|
|
_gtk_css_parser_error (parser,
|
|
|
|
"Expected '('");
|
2011-05-18 16:32:22 +00:00
|
|
|
return FALSE;
|
2011-04-08 14:08:28 +00:00
|
|
|
}
|
2011-04-14 02:47:18 +00:00
|
|
|
|
2011-04-08 14:08:28 +00:00
|
|
|
}
|
2011-04-14 02:47:18 +00:00
|
|
|
else if (_gtk_css_parser_try (parser, "to", TRUE))
|
2011-04-08 14:08:28 +00:00
|
|
|
{
|
|
|
|
position = 1;
|
|
|
|
|
2011-04-14 02:47:18 +00:00
|
|
|
if (!_gtk_css_parser_try (parser, "(", TRUE))
|
2011-04-08 14:08:28 +00:00
|
|
|
{
|
2011-04-14 02:47:18 +00:00
|
|
|
gtk_gradient_unref (gradient);
|
|
|
|
_gtk_css_parser_error (parser,
|
|
|
|
"Expected '('");
|
2011-05-18 16:32:22 +00:00
|
|
|
return FALSE;
|
2011-04-08 14:08:28 +00:00
|
|
|
}
|
2011-04-14 02:47:18 +00:00
|
|
|
|
2011-04-08 14:08:28 +00:00
|
|
|
}
|
2011-04-14 02:47:18 +00:00
|
|
|
else if (_gtk_css_parser_try (parser, "color-stop", TRUE))
|
2011-04-08 14:08:28 +00:00
|
|
|
{
|
2011-04-14 02:47:18 +00:00
|
|
|
if (!_gtk_css_parser_try (parser, "(", TRUE))
|
2011-04-08 14:08:28 +00:00
|
|
|
{
|
2011-04-14 02:47:18 +00:00
|
|
|
gtk_gradient_unref (gradient);
|
|
|
|
_gtk_css_parser_error (parser,
|
|
|
|
"Expected '('");
|
2011-05-18 16:32:22 +00:00
|
|
|
return FALSE;
|
2011-04-08 14:08:28 +00:00
|
|
|
}
|
|
|
|
|
2011-04-14 02:47:18 +00:00
|
|
|
if (!_gtk_css_parser_try_double (parser, &position))
|
|
|
|
{
|
|
|
|
gtk_gradient_unref (gradient);
|
|
|
|
_gtk_css_parser_error (parser,
|
|
|
|
"Expected a valid number");
|
2011-05-18 16:32:22 +00:00
|
|
|
return FALSE;
|
2011-04-14 02:47:18 +00:00
|
|
|
}
|
2011-04-08 14:08:28 +00:00
|
|
|
|
2011-04-14 02:47:18 +00:00
|
|
|
if (!_gtk_css_parser_try (parser, ",", TRUE))
|
2011-04-08 14:08:28 +00:00
|
|
|
{
|
2011-04-14 02:47:18 +00:00
|
|
|
gtk_gradient_unref (gradient);
|
|
|
|
_gtk_css_parser_error (parser,
|
|
|
|
"Expected a comma");
|
2011-05-18 16:32:22 +00:00
|
|
|
return FALSE;
|
2011-04-08 14:08:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2011-04-14 02:47:18 +00:00
|
|
|
gtk_gradient_unref (gradient);
|
|
|
|
_gtk_css_parser_error (parser,
|
|
|
|
"Not a valid color-stop definition");
|
2011-05-18 16:32:22 +00:00
|
|
|
return FALSE;
|
2011-04-08 14:08:28 +00:00
|
|
|
}
|
|
|
|
|
2011-04-14 02:47:18 +00:00
|
|
|
color = _gtk_css_parser_read_symbolic_color (parser);
|
|
|
|
if (color == NULL)
|
2011-04-08 14:08:28 +00:00
|
|
|
{
|
2011-04-14 02:47:18 +00:00
|
|
|
gtk_gradient_unref (gradient);
|
2011-05-18 16:32:22 +00:00
|
|
|
return FALSE;
|
2011-04-08 14:08:28 +00:00
|
|
|
}
|
|
|
|
|
2011-04-14 02:47:18 +00:00
|
|
|
gtk_gradient_add_color_stop (gradient, position, color);
|
|
|
|
gtk_symbolic_color_unref (color);
|
2011-04-08 14:08:28 +00:00
|
|
|
|
2011-04-14 02:47:18 +00:00
|
|
|
if (!_gtk_css_parser_try (parser, ")", TRUE))
|
2011-04-08 14:08:28 +00:00
|
|
|
{
|
2011-04-14 02:47:18 +00:00
|
|
|
gtk_gradient_unref (gradient);
|
|
|
|
_gtk_css_parser_error (parser,
|
|
|
|
"Expected ')'");
|
2011-05-18 16:32:22 +00:00
|
|
|
return FALSE;
|
2011-04-08 14:08:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-04-14 02:47:18 +00:00
|
|
|
if (!_gtk_css_parser_try (parser, ")", TRUE))
|
2011-04-08 14:08:28 +00:00
|
|
|
{
|
2011-04-14 02:47:18 +00:00
|
|
|
gtk_gradient_unref (gradient);
|
|
|
|
_gtk_css_parser_error (parser,
|
|
|
|
"Expected ')'");
|
2011-05-18 16:32:22 +00:00
|
|
|
return FALSE;
|
2011-04-08 14:08:28 +00:00
|
|
|
}
|
|
|
|
|
2011-04-14 02:47:18 +00:00
|
|
|
g_value_set_boxed (value, gradient);
|
2011-04-08 14:08:28 +00:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static char *
|
|
|
|
gradient_value_to_string (const GValue *value)
|
|
|
|
{
|
|
|
|
GtkGradient *gradient = g_value_get_boxed (value);
|
|
|
|
|
|
|
|
if (gradient == NULL)
|
|
|
|
return g_strdup ("none");
|
|
|
|
|
|
|
|
return gtk_gradient_to_string (gradient);
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
2011-05-18 16:32:22 +00:00
|
|
|
pattern_value_parse (GtkCssParser *parser,
|
|
|
|
GFile *base,
|
|
|
|
GValue *value)
|
2011-04-08 14:08:28 +00:00
|
|
|
{
|
2011-05-18 16:32:22 +00:00
|
|
|
if (_gtk_css_parser_begins_with (parser, '-'))
|
2011-04-08 14:08:28 +00:00
|
|
|
{
|
|
|
|
g_value_unset (value);
|
|
|
|
g_value_init (value, GTK_TYPE_GRADIENT);
|
2011-05-18 16:32:22 +00:00
|
|
|
return gradient_value_parse (parser, base, value);
|
2011-04-08 14:08:28 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2011-05-18 16:32:22 +00:00
|
|
|
GError *error = NULL;
|
2011-04-08 14:08:28 +00:00
|
|
|
gchar *path;
|
|
|
|
GdkPixbuf *pixbuf;
|
|
|
|
GFile *file;
|
2011-05-18 16:32:22 +00:00
|
|
|
cairo_surface_t *surface;
|
|
|
|
cairo_pattern_t *pattern;
|
|
|
|
cairo_t *cr;
|
|
|
|
cairo_matrix_t matrix;
|
2011-04-08 14:08:28 +00:00
|
|
|
|
2011-05-18 16:32:22 +00:00
|
|
|
file = _gtk_css_parse_url (parser, base);
|
2011-04-08 14:08:28 +00:00
|
|
|
if (file == NULL)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
path = g_file_get_path (file);
|
|
|
|
g_object_unref (file);
|
|
|
|
|
2011-05-18 16:32:22 +00:00
|
|
|
pixbuf = gdk_pixbuf_new_from_file (path, &error);
|
2011-04-08 14:08:28 +00:00
|
|
|
g_free (path);
|
|
|
|
if (pixbuf == NULL)
|
2011-05-18 16:32:22 +00:00
|
|
|
{
|
|
|
|
_gtk_css_parser_take_error (parser, error);
|
|
|
|
return FALSE;
|
|
|
|
}
|
2011-04-08 14:08:28 +00:00
|
|
|
|
|
|
|
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 gboolean
|
2011-05-18 16:32:22 +00:00
|
|
|
slice_value_parse (GtkCssParser *parser,
|
|
|
|
GFile *base,
|
|
|
|
GValue *value)
|
2011-04-08 14:08:28 +00:00
|
|
|
{
|
|
|
|
gdouble distance_top, distance_bottom;
|
|
|
|
gdouble distance_left, distance_right;
|
|
|
|
GtkSliceSideModifier mods[2];
|
|
|
|
GdkPixbuf *pixbuf;
|
|
|
|
Gtk9Slice *slice;
|
|
|
|
GFile *file;
|
2011-05-18 16:32:22 +00:00
|
|
|
GError *error = NULL;
|
|
|
|
gint i;
|
2011-04-08 14:08:28 +00:00
|
|
|
char *path;
|
|
|
|
|
|
|
|
/* Parse image url */
|
2011-05-18 16:32:22 +00:00
|
|
|
file = _gtk_css_parse_url (parser, base);
|
2011-04-08 14:08:28 +00:00
|
|
|
if (!file)
|
|
|
|
return FALSE;
|
|
|
|
|
2011-05-18 16:32:22 +00:00
|
|
|
if (!_gtk_css_parser_try_double (parser, &distance_top) ||
|
|
|
|
!_gtk_css_parser_try_double (parser, &distance_right) ||
|
|
|
|
!_gtk_css_parser_try_double (parser, &distance_bottom) ||
|
|
|
|
!_gtk_css_parser_try_double (parser, &distance_left))
|
2011-04-08 14:08:28 +00:00
|
|
|
{
|
2011-05-18 16:32:22 +00:00
|
|
|
_gtk_css_parser_error (parser, "Expected a number");
|
2011-04-08 14:08:28 +00:00
|
|
|
g_object_unref (file);
|
2011-05-18 16:32:22 +00:00
|
|
|
return FALSE;
|
2011-04-08 14:08:28 +00:00
|
|
|
}
|
|
|
|
|
2011-05-18 16:32:22 +00:00
|
|
|
for (i = 0; i < 2; i++)
|
2011-04-08 14:08:28 +00:00
|
|
|
{
|
2011-05-18 16:32:22 +00:00
|
|
|
if (_gtk_css_parser_try (parser, "stretch", TRUE))
|
|
|
|
mods[i] = GTK_SLICE_STRETCH;
|
|
|
|
else if (_gtk_css_parser_try (parser, "repeat", TRUE))
|
|
|
|
mods[i] = GTK_SLICE_REPEAT;
|
|
|
|
else if (i == 0)
|
|
|
|
{
|
|
|
|
mods[1] = mods[0] = GTK_SLICE_STRETCH;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
mods[i] = mods[0];
|
2011-04-08 14:08:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
path = g_file_get_path (file);
|
2011-05-18 16:32:22 +00:00
|
|
|
g_object_unref (file);
|
|
|
|
pixbuf = gdk_pixbuf_new_from_file (path, &error);
|
2011-04-08 14:08:28 +00:00
|
|
|
g_free (path);
|
|
|
|
if (!pixbuf)
|
2011-05-18 16:32:22 +00:00
|
|
|
{
|
|
|
|
_gtk_css_parser_take_error (parser, error);
|
|
|
|
return FALSE;
|
|
|
|
}
|
2011-04-08 14:08:28 +00:00
|
|
|
|
|
|
|
slice = _gtk_9slice_new (pixbuf,
|
|
|
|
distance_top, distance_bottom,
|
|
|
|
distance_left, distance_right,
|
|
|
|
mods[0], mods[1]);
|
|
|
|
g_object_unref (pixbuf);
|
|
|
|
|
|
|
|
g_value_take_boxed (value, slice);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
2011-05-18 16:32:22 +00:00
|
|
|
enum_value_parse (GtkCssParser *parser,
|
|
|
|
GFile *base,
|
|
|
|
GValue *value)
|
2011-04-08 14:08:28 +00:00
|
|
|
{
|
|
|
|
GEnumClass *enum_class;
|
|
|
|
GEnumValue *enum_value;
|
2011-05-18 16:32:22 +00:00
|
|
|
char *str;
|
2011-04-08 14:08:28 +00:00
|
|
|
|
2011-05-18 16:32:22 +00:00
|
|
|
str = _gtk_css_parser_try_ident (parser, TRUE);
|
|
|
|
if (str == NULL)
|
2011-04-08 14:08:28 +00:00
|
|
|
{
|
2011-05-18 16:32:22 +00:00
|
|
|
_gtk_css_parser_error (parser, "Expected an identifier");
|
2011-04-08 14:08:28 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
2011-05-18 16:32:22 +00:00
|
|
|
|
|
|
|
enum_class = g_type_class_ref (G_VALUE_TYPE (value));
|
|
|
|
enum_value = g_enum_get_value_by_nick (enum_class, str);
|
|
|
|
|
|
|
|
if (enum_value)
|
|
|
|
g_value_set_enum (value, enum_value->value);
|
|
|
|
else
|
|
|
|
_gtk_css_parser_error (parser,
|
|
|
|
"Unknown value '%s' for enum type '%s'",
|
|
|
|
str, g_type_name (G_VALUE_TYPE (value)));
|
2011-04-08 14:08:28 +00:00
|
|
|
|
|
|
|
g_type_class_unref (enum_class);
|
2011-05-18 16:32:22 +00:00
|
|
|
g_free (str);
|
|
|
|
|
|
|
|
return enum_value != NULL;
|
2011-04-08 14:08:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static char *
|
|
|
|
enum_value_to_string (const GValue *value)
|
|
|
|
{
|
|
|
|
GEnumClass *enum_class;
|
|
|
|
GEnumValue *enum_value;
|
|
|
|
char *s;
|
|
|
|
|
|
|
|
enum_class = g_type_class_ref (G_VALUE_TYPE (value));
|
|
|
|
enum_value = g_enum_get_value (enum_class, g_value_get_enum (value));
|
|
|
|
|
|
|
|
s = g_strdup (enum_value->value_nick);
|
|
|
|
|
|
|
|
g_type_class_unref (enum_class);
|
|
|
|
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
2011-05-18 16:32:22 +00:00
|
|
|
flags_value_parse (GtkCssParser *parser,
|
|
|
|
GFile *base,
|
|
|
|
GValue *value)
|
2011-04-08 14:08:28 +00:00
|
|
|
{
|
|
|
|
GFlagsClass *flags_class;
|
|
|
|
GFlagsValue *flag_value;
|
|
|
|
guint flags = 0;
|
2011-05-18 16:32:22 +00:00
|
|
|
char *str;
|
2011-04-08 14:08:28 +00:00
|
|
|
|
|
|
|
flags_class = g_type_class_ref (G_VALUE_TYPE (value));
|
|
|
|
|
2011-05-18 16:32:22 +00:00
|
|
|
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;
|
|
|
|
}
|
2011-04-08 14:08:28 +00:00
|
|
|
|
2011-05-18 16:32:22 +00:00
|
|
|
flag_value = g_flags_get_value_by_nick (flags_class, str);
|
2011-04-08 14:08:28 +00:00
|
|
|
if (!flag_value)
|
|
|
|
{
|
2011-05-18 16:32:22 +00:00
|
|
|
_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);
|
2011-04-08 14:08:28 +00:00
|
|
|
g_type_class_unref (flags_class);
|
|
|
|
return FALSE;
|
|
|
|
}
|
2011-05-18 16:32:22 +00:00
|
|
|
|
|
|
|
g_free (str);
|
2011-04-08 14:08:28 +00:00
|
|
|
}
|
2011-05-18 16:32:22 +00:00
|
|
|
while (_gtk_css_parser_try (parser, ",", FALSE));
|
2011-04-08 14:08:28 +00:00
|
|
|
|
|
|
|
g_type_class_unref (flags_class);
|
|
|
|
|
|
|
|
g_value_set_enum (value, flags);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static char *
|
|
|
|
flags_value_to_string (const GValue *value)
|
|
|
|
{
|
|
|
|
GFlagsClass *flags_class;
|
|
|
|
GString *string;
|
|
|
|
guint i, flags;
|
|
|
|
|
|
|
|
flags_class = g_type_class_ref (G_VALUE_TYPE (value));
|
|
|
|
flags = g_value_get_flags (value);
|
|
|
|
string = g_string_new (NULL);
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
return g_string_free (string, FALSE);
|
|
|
|
}
|
|
|
|
|
2011-05-18 16:03:23 +00:00
|
|
|
static gboolean
|
2011-05-18 16:32:22 +00:00
|
|
|
bindings_value_parse (GtkCssParser *parser,
|
|
|
|
GFile *base,
|
|
|
|
GValue *value)
|
2011-05-18 16:03:23 +00:00
|
|
|
{
|
|
|
|
GPtrArray *array;
|
2011-05-18 16:32:22 +00:00
|
|
|
GtkBindingSet *binding_set;
|
|
|
|
char *name;
|
2011-05-18 16:03:23 +00:00
|
|
|
|
|
|
|
array = g_ptr_array_new ();
|
|
|
|
|
2011-05-18 16:32:22 +00:00
|
|
|
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;
|
|
|
|
}
|
2011-05-18 16:03:23 +00:00
|
|
|
|
2011-05-18 16:32:22 +00:00
|
|
|
binding_set = gtk_binding_set_find (name);
|
2011-05-18 16:03:23 +00:00
|
|
|
|
|
|
|
if (!binding_set)
|
2011-05-18 16:32:22 +00:00
|
|
|
{
|
|
|
|
_gtk_css_parser_error (parser, "No binding set named '%s'", name);
|
|
|
|
g_free (name);
|
|
|
|
continue;
|
|
|
|
}
|
2011-05-18 16:03:23 +00:00
|
|
|
|
|
|
|
g_ptr_array_add (array, binding_set);
|
2011-05-18 16:32:22 +00:00
|
|
|
g_free (name);
|
2011-05-18 16:03:23 +00:00
|
|
|
}
|
2011-05-18 16:32:22 +00:00
|
|
|
while (_gtk_css_parser_try (parser, ",", TRUE));
|
2011-05-18 16:03:23 +00:00
|
|
|
|
|
|
|
g_value_take_boxed (value, array);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static char *
|
|
|
|
bindings_value_to_string (const GValue *value)
|
|
|
|
{
|
|
|
|
GPtrArray *array;
|
|
|
|
GString *str;
|
|
|
|
guint i;
|
|
|
|
|
|
|
|
array = g_value_get_boxed (value);
|
|
|
|
str = g_string_new (NULL);
|
|
|
|
|
|
|
|
for (i = 0; i < array->len; i++)
|
|
|
|
{
|
|
|
|
GtkBindingSet *binding_set = g_ptr_array_index (array, i);
|
|
|
|
|
|
|
|
if (i > 0)
|
|
|
|
g_string_append (str, ", ");
|
|
|
|
g_string_append (str, binding_set->set_name);
|
|
|
|
}
|
|
|
|
|
|
|
|
return g_string_free (str, FALSE);
|
|
|
|
}
|
|
|
|
|
2011-04-08 14:08:28 +00:00
|
|
|
/*** API ***/
|
|
|
|
|
|
|
|
static void
|
|
|
|
css_string_funcs_init (void)
|
|
|
|
{
|
2011-05-18 16:32:22 +00:00
|
|
|
if (G_LIKELY (parse_funcs != NULL))
|
2011-04-08 14:08:28 +00:00
|
|
|
return;
|
|
|
|
|
2011-05-18 16:32:22 +00:00
|
|
|
parse_funcs = g_hash_table_new (NULL, NULL);
|
2011-04-08 14:08:28 +00:00
|
|
|
to_string_funcs = g_hash_table_new (NULL, NULL);
|
|
|
|
|
|
|
|
register_conversion_function (GDK_TYPE_RGBA,
|
2011-05-18 16:32:22 +00:00
|
|
|
rgba_value_parse,
|
2011-04-08 14:08:28 +00:00
|
|
|
rgba_value_to_string);
|
|
|
|
register_conversion_function (GDK_TYPE_COLOR,
|
2011-05-18 16:32:22 +00:00
|
|
|
color_value_parse,
|
2011-04-08 14:08:28 +00:00
|
|
|
color_value_to_string);
|
|
|
|
register_conversion_function (GTK_TYPE_SYMBOLIC_COLOR,
|
2011-05-18 16:32:22 +00:00
|
|
|
symbolic_color_value_parse,
|
2011-04-08 14:08:28 +00:00
|
|
|
symbolic_color_value_to_string);
|
|
|
|
register_conversion_function (PANGO_TYPE_FONT_DESCRIPTION,
|
2011-05-18 16:32:22 +00:00
|
|
|
font_description_value_parse,
|
2011-04-08 14:08:28 +00:00
|
|
|
font_description_value_to_string);
|
|
|
|
register_conversion_function (G_TYPE_BOOLEAN,
|
2011-05-18 16:32:22 +00:00
|
|
|
boolean_value_parse,
|
2011-04-08 14:08:28 +00:00
|
|
|
boolean_value_to_string);
|
|
|
|
register_conversion_function (G_TYPE_INT,
|
2011-05-18 16:32:22 +00:00
|
|
|
int_value_parse,
|
2011-04-08 14:08:28 +00:00
|
|
|
int_value_to_string);
|
|
|
|
register_conversion_function (G_TYPE_UINT,
|
2011-05-18 16:32:22 +00:00
|
|
|
uint_value_parse,
|
2011-04-08 14:08:28 +00:00
|
|
|
uint_value_to_string);
|
|
|
|
register_conversion_function (G_TYPE_DOUBLE,
|
2011-05-18 16:32:22 +00:00
|
|
|
double_value_parse,
|
2011-04-08 14:08:28 +00:00
|
|
|
double_value_to_string);
|
|
|
|
register_conversion_function (G_TYPE_FLOAT,
|
2011-05-18 16:32:22 +00:00
|
|
|
float_value_parse,
|
2011-04-08 14:08:28 +00:00
|
|
|
float_value_to_string);
|
2011-04-12 02:26:10 +00:00
|
|
|
register_conversion_function (G_TYPE_STRING,
|
2011-05-18 16:32:22 +00:00
|
|
|
string_value_parse,
|
2011-04-12 02:26:10 +00:00
|
|
|
string_value_to_string);
|
2011-04-08 14:08:28 +00:00
|
|
|
register_conversion_function (GTK_TYPE_THEMING_ENGINE,
|
2011-05-18 16:32:22 +00:00
|
|
|
theming_engine_value_parse,
|
2011-04-08 14:08:28 +00:00
|
|
|
theming_engine_value_to_string);
|
|
|
|
register_conversion_function (GTK_TYPE_ANIMATION_DESCRIPTION,
|
2011-05-18 16:32:22 +00:00
|
|
|
animation_description_value_parse,
|
2011-04-08 14:08:28 +00:00
|
|
|
animation_description_value_to_string);
|
|
|
|
register_conversion_function (GTK_TYPE_BORDER,
|
2011-05-18 16:32:22 +00:00
|
|
|
border_value_parse,
|
2011-04-08 14:08:28 +00:00
|
|
|
border_value_to_string);
|
|
|
|
register_conversion_function (GTK_TYPE_GRADIENT,
|
2011-05-18 16:32:22 +00:00
|
|
|
gradient_value_parse,
|
2011-04-08 14:08:28 +00:00
|
|
|
gradient_value_to_string);
|
|
|
|
register_conversion_function (CAIRO_GOBJECT_TYPE_PATTERN,
|
2011-05-18 16:32:22 +00:00
|
|
|
pattern_value_parse,
|
2011-04-08 14:08:28 +00:00
|
|
|
NULL);
|
|
|
|
register_conversion_function (GTK_TYPE_9SLICE,
|
2011-05-18 16:32:22 +00:00
|
|
|
slice_value_parse,
|
2011-04-08 14:08:28 +00:00
|
|
|
NULL);
|
|
|
|
register_conversion_function (G_TYPE_ENUM,
|
2011-05-18 16:32:22 +00:00
|
|
|
enum_value_parse,
|
2011-04-08 14:08:28 +00:00
|
|
|
enum_value_to_string);
|
|
|
|
register_conversion_function (G_TYPE_FLAGS,
|
2011-05-18 16:32:22 +00:00
|
|
|
flags_value_parse,
|
2011-04-08 14:08:28 +00:00
|
|
|
flags_value_to_string);
|
2011-05-18 16:03:23 +00:00
|
|
|
register_conversion_function (G_TYPE_PTR_ARRAY,
|
2011-05-18 16:32:22 +00:00
|
|
|
bindings_value_parse,
|
2011-05-18 16:03:23 +00:00
|
|
|
bindings_value_to_string);
|
2011-04-08 14:08:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
gboolean
|
2011-05-18 16:32:22 +00:00
|
|
|
_gtk_css_value_parse (GValue *value,
|
|
|
|
GtkCssParser *parser,
|
|
|
|
GFile *base)
|
2011-04-08 14:08:28 +00:00
|
|
|
{
|
2011-05-18 16:32:22 +00:00
|
|
|
ParseFunc func;
|
2011-04-08 14:08:28 +00:00
|
|
|
|
2011-05-18 16:32:22 +00:00
|
|
|
g_return_val_if_fail (value != NULL, FALSE);
|
|
|
|
g_return_val_if_fail (parser != NULL, FALSE);
|
2011-04-08 14:08:28 +00:00
|
|
|
|
|
|
|
css_string_funcs_init ();
|
|
|
|
|
2011-05-18 16:32:22 +00:00
|
|
|
func = g_hash_table_lookup (parse_funcs,
|
2011-04-08 14:08:28 +00:00
|
|
|
GSIZE_TO_POINTER (G_VALUE_TYPE (value)));
|
|
|
|
if (func == NULL)
|
2011-05-18 16:32:22 +00:00
|
|
|
func = g_hash_table_lookup (parse_funcs,
|
2011-04-08 14:08:28 +00:00
|
|
|
GSIZE_TO_POINTER (g_type_fundamental (G_VALUE_TYPE (value))));
|
|
|
|
|
|
|
|
if (func == NULL)
|
|
|
|
{
|
2011-05-18 16:32:22 +00:00
|
|
|
_gtk_css_parser_error (parser,
|
|
|
|
"Cannot convert to type '%s'",
|
|
|
|
g_type_name (G_VALUE_TYPE (value)));
|
2011-04-08 14:08:28 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2011-05-18 16:32:22 +00:00
|
|
|
return (*func) (parser, base, value);
|
2011-04-08 14:08:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
char *
|
|
|
|
_gtk_css_value_to_string (const GValue *value)
|
|
|
|
{
|
|
|
|
ToStringFunc func;
|
|
|
|
|
|
|
|
css_string_funcs_init ();
|
|
|
|
|
|
|
|
func = g_hash_table_lookup (to_string_funcs,
|
|
|
|
GSIZE_TO_POINTER (G_VALUE_TYPE (value)));
|
|
|
|
if (func == NULL)
|
|
|
|
func = g_hash_table_lookup (to_string_funcs,
|
|
|
|
GSIZE_TO_POINTER (g_type_fundamental (G_VALUE_TYPE (value))));
|
|
|
|
|
|
|
|
if (func)
|
|
|
|
return func (value);
|
|
|
|
|
|
|
|
return g_strdup_value_contents (value);
|
|
|
|
}
|
|
|
|
|
|
|
|
GFile *
|
2011-05-18 16:32:22 +00:00
|
|
|
_gtk_css_parse_url (GtkCssParser *parser,
|
|
|
|
GFile *base)
|
2011-04-08 14:08:28 +00:00
|
|
|
{
|
2011-05-18 16:32:22 +00:00
|
|
|
gchar *path;
|
2011-04-08 14:08:28 +00:00
|
|
|
GFile *file;
|
|
|
|
|
2011-05-18 16:32:22 +00:00
|
|
|
if (_gtk_css_parser_try (parser, "url", FALSE))
|
2011-04-08 14:08:28 +00:00
|
|
|
{
|
2011-05-18 16:32:22 +00:00
|
|
|
if (!_gtk_css_parser_try (parser, "(", TRUE))
|
2011-04-08 14:08:28 +00:00
|
|
|
{
|
2011-05-18 16:32:22 +00:00
|
|
|
_gtk_css_parser_skip_whitespace (parser);
|
|
|
|
if (_gtk_css_parser_try (parser, "(", TRUE))
|
2011-04-08 14:08:28 +00:00
|
|
|
{
|
2011-05-18 16:32:22 +00:00
|
|
|
GError *error;
|
|
|
|
|
|
|
|
error = g_error_new_literal (GTK_CSS_PROVIDER_ERROR,
|
|
|
|
GTK_CSS_PROVIDER_ERROR_DEPRECATED,
|
|
|
|
"Whitespace between 'url' and '(' is not allowed");
|
|
|
|
|
|
|
|
_gtk_css_parser_take_error (parser, error);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
_gtk_css_parser_error (parser, "Expected '(' after 'url'");
|
2011-04-08 14:08:28 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
2011-05-18 16:32:22 +00:00
|
|
|
|
|
|
|
path = _gtk_css_parser_read_string (parser);
|
|
|
|
if (path == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (!_gtk_css_parser_try (parser, ")", TRUE))
|
2011-04-08 14:08:28 +00:00
|
|
|
{
|
2011-05-18 16:32:22 +00:00
|
|
|
_gtk_css_parser_error (parser, "No closing ')' found for 'url'");
|
|
|
|
g_free (path);
|
2011-04-08 14:08:28 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2011-05-18 16:32:22 +00:00
|
|
|
path = _gtk_css_parser_try_name (parser, TRUE);
|
|
|
|
if (path == NULL)
|
|
|
|
{
|
|
|
|
_gtk_css_parser_error (parser, "Not a valid url");
|
|
|
|
return NULL;
|
|
|
|
}
|
2011-04-08 14:08:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
file = g_file_resolve_relative_path (base, path);
|
|
|
|
g_free (path);
|
|
|
|
|
|
|
|
return file;
|
|
|
|
}
|