#include "gtkanimationdescription.h"
#include "gtk9slice.h"
#include "gtkcssprovider.h"
+#include "gtkprivate.h"
/**
* SECTION:gtkcssprovider
* @Title: GtkCssProvider
* @See_also: #GtkStyleContext, #GtkStyleProvider
*
- * #GtkCssProvider is an object implementing #GtkStyleProvider, it is able
- * to parse <ulink url="http://www.w3.org/TR/CSS2">CSS</ulink>-like input
- * in order to style widgets.
+ * GtkCssProvider is an object implementing the #GtkStyleProvider interface.
+ * It is able to parse <ulink url="http://www.w3.org/TR/CSS2">CSS</ulink>-like
+ * input in order to style widgets.
*
* <refsect2 id="gtkcssprovider-files">
* <title>Default files</title>
* calling gtk_css_provider_load_from_file() and adding the provider with
* gtk_style_context_add_provider() or gtk_style_context_add_provider_for_screen().
* In addition, certain files will be read when GTK+ is initialized. First,
- * the file <filename><replaceable>HOME</replaceable>/.gtk-3.0.css</filename>
+ * the file <filename><envar>$XDG_CONFIG_HOME</envar>/gtk-3.0/gtk.css</filename>
* is loaded if it exists. Then, GTK+ tries to load
- * <filename><replaceable>HOME</replaceable>/.themes/<replaceable>theme-name</replaceable>/gtk-3.0/gtk.css</filename>,
+ * <filename><envar>$HOME</envar>/.themes/<replaceable>theme-name</replaceable>/gtk-3.0/gtk.css</filename>,
* falling back to
- * <filename><replaceable>GTK_DATA_PREFIX</replaceable>/share/themes/<replaceable>theme-name</replaceable>/gtk-3.0/gtk.css</filename>,
+ * <filename><replaceable>datadir</replaceable>/share/themes/<replaceable>theme-name</replaceable>/gtk-3.0/gtk.css</filename>,
* where <replaceable>theme-name</replaceable> is the name of the current theme
- * (see the #GtkSettings:gtk-theme-name setting) and <replaceable>GTK_DATA_PREFIX</replaceable>
+ * (see the #GtkSettings:gtk-theme-name setting) and <replaceable>datadir</replaceable>
* is the prefix configured when GTK+ was compiled, unless overridden by the
* <envar>GTK_DATA_PREFIX</envar> environment variable.
* </para>
* </para>
* <para>
* Refer to the documentation of individual widgets to learn which
- * style classes they define.
+ * style classes they define and see <xref linkend="gtkstylecontext-classes"/>
+ * for a list of all style classes used by GTK+ widgets.
* </para>
* <example>
* <title>Style classes in selectors</title>
* </para>
* <para>
* Refer to the documentation of individual widgets to learn which
- * regions and pseudo-classes they define.
+ * regions and pseudo-classes they define and see
+ * <xref linkend="gtkstylecontext-classes"/> for a list of all regions
+ * used by GTK+ widgets.
* </para>
* <example>
* <title>Regions in selectors</title>
* <tbody>
* <row>
* <entry>rgb(@r, @g, @b)</entry>
- * <entry>An opaque color; @r, @g, @b can be either integers between 0 and 255 or percentages</entry>
- * <entry>rgb(128, 10, 54)
- * rgb(20%, 30%, 0%)</entry>
+ * <entry>An opaque color; @r, @g, @b can be either integers between
+ * 0 and 255 or percentages</entry>
+ * <entry><literallayout>rgb(128, 10, 54)
+ * rgb(20%, 30%, 0%)</literallayout></entry>
* </row>
* <row>
* <entry>rgba(@r, @g, @b, @a)</entry>
- * <entry>A translucent color; @r, @g, @b are as in the previous row, @a is a floating point number between 0 and 1</entry>
- * <entry>rgba(255, 255, 0, 0.5)</entry>
+ * <entry>A translucent color; @r, @g, @b are as in the previous row,
+ * @a is a floating point number between 0 and 1</entry>
+ * <entry><literallayout>rgba(255, 255, 0, 0.5)</literallayout></entry>
* </row>
* <row>
* <entry>#@xxyyzz</entry>
- * <entry>An opaque color; @xx, @yy, @zz are hexadecimal numbers specifying @r, @g, @b
- * variants with between 1 and 4 hexadecimal digits per component are allowed</entry>
- * <entry>#ff12ab
- * #f0c</entry>
+ * <entry>An opaque color; @xx, @yy, @zz are hexadecimal numbers
+ * specifying @r, @g, @b variants with between 1 and 4
+ * hexadecimal digits per component are allowed</entry>
+ * <entry><literallayout>#ff12ab
+ * #f0c</literallayout></entry>
* </row>
* <row>
* <entry>@name</entry>
- * <entry>Reference to a color that has been defined with @define-color</entry>
+ * <entry>Reference to a color that has been defined with
+ * @define-color
+ * </entry>
* <entry>@bg_color</entry>
* </row>
* <row>
* <entry>mix(@color1, @color2, @f)</entry>
- * <entry>A linear combination of @color1 and @color2. @f is a floating point number between 0 and 1.</entry>
- * <entry>mix(#ff1e0a, @bg_color, 0.8)</entry>
+ * <entry>A linear combination of @color1 and @color2. @f is a
+ * floating point number between 0 and 1.</entry>
+ * <entry><literallayout>mix(#ff1e0a, @bg_color, 0.8)</literallayout></entry>
* </row>
* <row>
* <entry>shade(@color, @f)</entry>
- * <entry>A lighter or darker variant of @color. @f is a floating point number.</entry>
+ * <entry>A lighter or darker variant of @color. @f is a
+ * floating point number.
+ * </entry>
* <entry>shade(@fg_color, 0.5)</entry>
* </row>
* <row>
* </tgroup>
* </informaltable>
* </refsect2>
+ * <refsect2 id="gtkcssprovider-gradients">
+ * <title>Gradients</title>
+ * <para>
+ * Linear or radial Gradients can be used as background images.
+ * </para>
+ * <para>
+ * A linear gradient along the line from (@start_x, @start_y) to
+ * (@end_x, @end_y) is specified using the syntax
+ * <literallayout>-gtk-gradient (linear,
+ * @start_x @start_y, @end_x @end_y,
+ * color-stop (@position, @color),
+ * ...)</literallayout>
+ * where @start_x and @end_x can be either a floating point number between
+ * 0 and 1 or one of the special values 'left', 'right' or 'center', @start_y
+ * and @end_y can be either a floating point number between 0 and 1 or one
+ * of the special values 'top', 'bottom' or 'center', @position is a floating
+ * point number between 0 and 1 and @color is a color expression (see above).
+ * The color-stop can be repeated multiple times to add more than one color
+ * stop. 'from (@color)' and 'to (@color)' can be used as abbreviations for
+ * color stops with position 0 and 1, respectively.
+ * </para>
+ * <example>
+ * <title>A linear gradient</title>
+ * <inlinegraphic fileref="gradient1.png" format="PNG"/>
+ * <para>This gradient was specified with
+ * <literallayout>-gtk-gradient (linear,
+ * left top, right bottom,
+ * from(@yellow), to(@blue))</literallayout></para>
+ * </example>
+ * <example>
+ * <title>Another linear gradient</title>
+ * <inlinegraphic fileref="gradient2.png" format="PNG"/>
+ * <para>This gradient was specified with
+ * <literallayout>-gtk-gradient (linear,
+ * 0 0, 0 1,
+ * color-stop(0, @yellow),
+ * color-stop(0.2, @blue),
+ * color-stop(1, #0f0))</literallayout></para>
+ * </example>
+ * <para>
+ * A radial gradient along the two circles defined by (@start_x, @start_y,
+ * @start_radius) and (@end_x, @end_y, @end_radius) is specified using the
+ * syntax
+ * <literallayout>-gtk-gradient (radial,
+ * @start_x @start_y, @start_radius,
+ * @end_x @end_y, @end_radius,
+ * color-stop (@position, @color),
+ * ...)</literallayout>
+ * where @start_radius and @end_radius are floating point numbers and
+ * the other parameters are as before.
+ * </para>
+ * <example>
+ * <title>A radial gradient</title>
+ * <inlinegraphic fileref="gradient3.png" format="PNG"/>
+ * <para>This gradient was specified with
+ * <literallayout>-gtk-gradient (radial,
+ * center center, 0,
+ * center center, 1,
+ * from(@yellow), to(@green))</literallayout></para>
+ * </example>
+ * <example>
+ * <title>Another radial gradient</title>
+ * <inlinegraphic fileref="gradient4.png" format="PNG"/>
+ * <para>This gradient was specified with
+ * <literallayout>-gtk-gradient (radial,
+ * 0.4 0.4, 0.1,
+ * 0.6 0.6, 0.7,
+ * color-stop (0, #f00),
+ * color-stop (0.1, #a0f),
+ * color-stop (0.2, @yellow),
+ * color-stop (1, @green))</literallayout></para>
+ * </example>
+ * </refsect2>
+ * <refsect2 id="gtkcssprovider-slices">
+ * <title>Border images</title>
+ * <para>
+ * Images can be used in 'slices' for the purpose of creating scalable
+ * borders.
+ * </para>
+ * <inlinegraphic fileref="slices.png" format="PNG"/>
+ * <para>
+ * The syntax for specifying border images of this kind is:
+ * <literallayout>url(@path) @top @right @bottom @left [repeat|stretch]? [repeat|stretch]?</literallayout>
+ * The sizes of the 'cut off' portions are specified
+ * with the @top, @right, @bottom and @left parameters.
+ * The 'middle' sections can be repeated or stretched to create
+ * the desired effect, by adding the 'repeat' or 'stretch' options after
+ * the dimensions. If two options are specified, the first one affects
+ * the horizontal behaviour and the second one the vertical behaviour.
+ * If only one option is specified, it affects both.
+ * </para>
+ * <example>
+ * <title>A border image</title>
+ * <inlinegraphic fileref="border1.png" format="PNG"/>
+ * <para>This border image was specified with
+ * <literallayout>url("gradient1.png") 10 10 10 10</literallayout>
+ * </para>
+ * </example>
+ * <example>
+ * <title>A repeating border image</title>
+ * <inlinegraphic fileref="border2.png" format="PNG"/>
+ * <para>This border image was specified with
+ * <literallayout>url("gradient1.png") 10 10 10 10 repeat</literallayout>
+ * </para>
+ * </example>
+ * <example>
+ * <title>A stretched border image</title>
+ * <inlinegraphic fileref="border3.png" format="PNG"/>
+ * <para>This border image was specified with
+ * <literallayout>url("gradient1.png") 10 10 10 10 stretch</literallayout>
+ * </para>
+ * </example>
+ * </refsect2>
+ * <refsect2 id="gtkcssprovider-transitions">
+ * <para>Styles can specify transitions that will be used to create a gradual
+ * change in the appearance when a widget state changes. The following
+ * syntax is used to specify transitions:
+ * <literallayout>@duration [s|ms] [linear|ease|ease-in|ease-out|ease-in-out] [loop]?</literallayout>
+ * The @duration is the amount of time that the animation will take for
+ * a complete cycle from start to end. If the loop option is given, the
+ * animation will be repated until the state changes again.
+ * The option after the duration determines the transition function from a
+ * small set of predefined functions.
+ * <figure><title>Linear transition</title>
+ * <graphic fileref="linear.png" format="PNG"/>
+ * </figure>
+ * <figure><title>Ease transition</title>
+ * <graphic fileref="ease.png" format="PNG"/>
+ * </figure>
+ * <figure><title>Ease-in-out transition</title>
+ * <graphic fileref="ease-in-out.png" format="PNG"/>
+ * </figure>
+ * <figure><title>Ease-in transition</title>
+ * <graphic fileref="ease-in.png" format="PNG"/>
+ * </figure>
+ * <figure><title>Ease-out transition</title>
+ * <graphic fileref="ease-out.png" format="PNG"/>
+ * </figure>
+ * </para>
+ * </refsect2>
* <refsect2 id="gtkcssprovider-properties">
* <title>Supported properties</title>
* <para>
* <tbody>
* <row>
* <entry>engine</entry>
- * <entry><programlisting>engine-name</programlisting></entry>
+ * <entry>engine-name</entry>
* <entry>#GtkThemingEngine</entry>
- * <entry><programlisting>engine: clearlooks;</programlisting></entry>
+ * <entry>engine: clearlooks;
+ * engine: none; /* use the default (i.e. builtin) engine) */ </entry>
* </row>
* <row>
* <entry>background-color</entry>
- * <entry morerows="1"><programlisting>color</programlisting></entry>
- * <entry morerows="1">#GdkRGBA</entry>
- * <entry morerows="1">
- * <programlisting>
- * background-color: #fff;
- * color: @color-name;
- * background-color: shade (@color-name, 0.5);
- * color: mix (@color-name, #f0f, 0.8);</programlisting>
+ * <entry morerows="2">color (see above)</entry>
+ * <entry morerows="2">#GdkRGBA</entry>
+ * <entry morerows="2"><literallayout>background-color: #fff;
+ * color: &color1;
+ * background-color: shade (&color1, 0.5);
+ * color: mix (&color1, #f0f, 0.8);</literallayout>
* </entry>
* </row>
* <row>
* <entry>color</entry>
* </row>
* <row>
+ * <entry>border-color</entry>
+ * </row>
+ * <row>
* <entry>font</entry>
- * <entry><programlisting>family [style] [size]</programlisting></entry>
+ * <entry>@family [@style] [@size]</entry>
* <entry>#PangoFontDescription</entry>
- * <entry><programlisting>font: Sans 15;</programlisting></entry>
+ * <entry>font: Sans 15;</entry>
* </row>
* <row>
* <entry>margin</entry>
- * <entry morerows="1">
- * <programlisting>
- * width
- * vertical-width horizontal-width
- * top-width horizontal-width bottom-width
- * top-width right-width bottom-width left-width
- * </programlisting>
+ * <entry morerows="1"><literallayout>@width
+ * @vertical_width @horizontal_width
+ * @top_width @horizontal_width @bottom_width
+ * @top_width @right_width @bottom_width @left_width</literallayout>
* </entry>
* <entry morerows="1">#GtkBorder</entry>
- * <entry morerows="1">
- * <programlisting>
- * margin: 5;
+ * <entry morerows="1"><literallayout>margin: 5;
* margin: 5 10;
* margin: 5 10 3;
- * margin: 5 10 3 5;</programlisting>
+ * margin: 5 10 3 5;</literallayout>
* </entry>
* </row>
* <row>
* </row>
* <row>
* <entry>background-image</entry>
- * <entry>
- * <programlisting>
- * -gtk-gradient (linear,
- * starting-x-position starting-y-position,
- * ending-x-position ending-y-position,
- * [ [from|to] (color) |
- * color-stop (percentage, color) ] )
- *
- * -gtk-gradient (radial,
- * starting-x-position starting-y-position, starting-radius,
- * ending-x-position ending-y-position, ending-radius,
- * [ [from|to] (color) |
- * color-stop (percentage, color) ]* )</programlisting>
- * </entry>
+ * <entry><literallayout>gradient (see above) or
+ * url(@path)</literallayout></entry>
* <entry>#cairo_pattern_t</entry>
- * <entry>
- * <programlisting>
- * -gtk-gradient (linear,
+ * <entry><literallayout>-gtk-gradient (linear,
* left top, right top,
* from (#fff), to (#000));
* -gtk-gradient (linear, 0.0 0.5, 0.5 1.0,
* center center, 0.2,
* center center, 0.8,
* color-stop (0.0, #fff),
- * color-stop (1.0, #000));</programlisting>
+ * color-stop (1.0, #000));
+ * url ('background.png');</literallayout>
* </entry>
* </row>
* <row>
+ * <entry>border-width</entry>
+ * <entry>integer</entry>
+ * <entry>#gint</entry>
+ * <entry>border-width: 5;</entry>
+ * </row>
+ * <row>
+ * <entry>border-radius</entry>
+ * <entry>integer</entry>
+ * <entry>#gint</entry>
+ * <entry>border-radius: 5;</entry>
+ * </row>
+ * <row>
+ * <entry>border-style</entry>
+ * <entry>[none|solid|inset|outset]</entry>
+ * <entry>#GtkBorderStyle</entry>
+ * <entry>border-style: solid;</entry>
+ * </row>
+ * <row>
* <entry>border-image</entry>
- * <entry><programlisting>url([path]) top-distance right-distance bottom-distance left-distance horizontal-option vertical-option</programlisting></entry>
- * <entry></entry>
- * <entry>
- * <programlisting>
- * border-image: url ("/path/to/image.png") 3 4 3 4 stretch;
- * border-image: url ("/path/to/image.png") 3 4 4 3 repeat stretch;</programlisting>
+ * <entry><literallayout>border image (see above)</literallayout></entry>
+ * <entry>internal use only</entry>
+ * <entry><literallayout>border-image: url("/path/to/image.png") 3 4 3 4 stretch;
+ * border-image: url("/path/to/image.png") 3 4 4 3 repeat stretch;</literallayout>
* </entry>
* </row>
* <row>
* <entry>transition</entry>
- * <entry><programlisting>duration [s|ms] [linear|ease|ease-in|ease-out|ease-in-out] [loop]?</programlisting></entry>
- * <entry></entry>
- * <entry>
- * <programlisting>
- * transition: 150ms ease-in-out;
- * transition: 1s linear loop;</programlisting>
+ * <entry>transition (see above)</entry>
+ * <entry>internal use only</entry>
+ * <entry><literallayout>transition: 150ms ease-in-out;
+ * transition: 1s linear loop;</literallayout>
* </entry>
* </row>
* </tbody>
* </tgroup>
* </informaltable>
+ * <para>
+ * GtkThemingEngines can register their own, engine-specific style properties
+ * with the function gtk_theming_engine_register_property(). These properties
+ * can be set in CSS like other properties, using a name of the form
+ * <literallayout>-<replaceable>namespace</replaceable>-<replaceable>name</replaceable></literallayout>, where <replaceable>namespace</replaceable> is typically
+ * the name of the theming engine, and <replaceable>name</replaceable> is the
+ * name of the property. Style properties that have been registered by widgets
+ * using gtk_widget_class_install_style_property() can also be set in this
+ * way, using the widget class name for <replaceable>namespace</replaceable>.
+ * </para>
+ * <example>
+ * <title>Using engine-specific style properties</title>
+ * <programlisting>
+ * * {
+ * engine: clearlooks;
+ * border-radius: 4;
+ * -GtkPaned-handle-size: 6;
+ * -clearlooks-colorize-scrollbar: false;
+ * }
+ * </programlisting>
+ * </example>
* </refsect2>
*/
GScanner *scanner;
gchar *filename;
+ const gchar *buffer;
+ const gchar *value_pos;
+
GHashTable *symbolic_colors;
GPtrArray *selectors_info;
static void scanner_apply_scope (GScanner *scanner,
ParserScope scope);
-static gboolean css_provider_parse_value (GtkCssProvider *css_provider,
- const gchar *value_str,
- GValue *value);
+static gboolean css_provider_parse_value (GtkCssProvider *css_provider,
+ const gchar *value_str,
+ GValue *value,
+ GError **error);
static gboolean gtk_css_provider_load_from_path_internal (GtkCssProvider *css_provider,
const gchar *path,
gboolean reset,
GError **error);
-
GQuark
gtk_css_provider_error_quark (void)
{
{
GType type;
- type = gtk_widget_path_iter_get_widget_type (path, index);
+ type = gtk_widget_path_iter_get_object_type (path, index);
if (!g_type_is_a (type, elem->type))
return FALSE;
SelectorPath *selector)
{
GSList *elements = selector->elements;
- gboolean match = TRUE;
+ gboolean match = TRUE, first = TRUE, first_match = FALSE;
guint64 score = 0;
gint i;
match = compare_selector_element (path, i, elem, &elem_score);
+ if (match && first)
+ first_match = TRUE;
+
/* Only move on to the next index if there is no match
* with the current element (whether to continue or not
* handled right after in the combinator check), or a
score <<= 4;
score |= elem_score;
}
+
+ first = FALSE;
}
/* If there are pending selector
if (!match)
score = 0;
+ else if (first_match)
+ {
+ /* Assign more weight to these selectors
+ * that matched right from the first element.
+ */
+ score <<= 4;
+ }
return score;
}
static gboolean
gtk_css_provider_get_style_property (GtkStyleProvider *provider,
GtkWidgetPath *path,
+ GtkStateFlags state,
GParamSpec *pspec,
GValue *value)
{
info = &g_array_index (priority_info, StylePriorityInfo, i);
val = g_hash_table_lookup (info->style, prop_name);
- if (val)
+ if (val &&
+ (info->state == 0 ||
+ info->state == state ||
+ ((info->state & state) != 0 &&
+ (info->state & ~(state)) == 0)))
{
const gchar *val_str;
val_str = g_value_get_string (val);
found = TRUE;
- css_provider_parse_value (GTK_CSS_PROVIDER (provider), val_str, value);
+ css_provider_parse_value (GTK_CSS_PROVIDER (provider), val_str, value, NULL);
break;
}
}
if (scope == SCOPE_VALUE)
{
- scanner->config->cset_identifier_first = G_CSET_a_2_z "@#-_0123456789" G_CSET_A_2_Z;
- scanner->config->cset_identifier_nth = G_CSET_a_2_z "@#-_ 0123456789(),.%\t\n'\"" G_CSET_A_2_Z;
+ scanner->config->cset_identifier_first = G_CSET_a_2_z G_CSET_A_2_Z G_CSET_DIGITS "@#-_";
+ scanner->config->cset_identifier_nth = G_CSET_a_2_z G_CSET_A_2_Z G_CSET_DIGITS "@#-_ +(),.%\t\n'/\"";
scanner->config->scan_identifier_1char = TRUE;
}
else if (scope == SCOPE_SELECTOR)
{
scanner->config->cset_identifier_first = G_CSET_a_2_z G_CSET_A_2_Z "*@";
- scanner->config->cset_identifier_nth = G_CSET_a_2_z "-_#." G_CSET_A_2_Z;
+ scanner->config->cset_identifier_nth = G_CSET_a_2_z G_CSET_A_2_Z G_CSET_DIGITS "-_#.";
scanner->config->scan_identifier_1char = TRUE;
}
else if (scope == SCOPE_PSEUDO_CLASS ||
scope == SCOPE_NTH_CHILD ||
scope == SCOPE_DECLARATION)
{
- scanner->config->cset_identifier_first = G_CSET_a_2_z "-" G_CSET_A_2_Z;
- scanner->config->cset_identifier_nth = G_CSET_a_2_z "-" G_CSET_A_2_Z;
+ scanner->config->cset_identifier_first = G_CSET_a_2_z G_CSET_A_2_Z "-_";
+ scanner->config->cset_identifier_nth = G_CSET_a_2_z G_CSET_A_2_Z G_CSET_DIGITS "-_";
scanner->config->scan_identifier_1char = FALSE;
}
else
priv->state = NULL;
scanner_apply_scope (priv->scanner, SCOPE_SELECTOR);
+ priv->scanner->user_data = NULL;
+ priv->value_pos = NULL;
g_slist_foreach (priv->cur_selectors, (GFunc) selector_path_unref, NULL);
g_slist_free (priv->cur_selectors);
static GtkSymbolicColor *
symbolic_color_parse_str (const gchar *string,
- gchar **end_ptr)
+ gchar **end_ptr)
{
GtkSymbolicColor *symbolic_color = NULL;
gchar *str;
*end_ptr = (gchar *) str;
if (str[0] != ')')
- {
+ {
gtk_symbolic_color_unref (color1);
gtk_symbolic_color_unref (color2);
return NULL;
}
else
{
- /* color name? parse until first whitespace */
- while (*end != ' ' && *end != '\0')
+ /* Color name */
+ while (*end != '\0' &&
+ (g_ascii_isalnum (*end) || *end == ' '))
end++;
}
}
static GtkSymbolicColor *
-symbolic_color_parse (const gchar *str)
+symbolic_color_parse (const gchar *str,
+ GError **error)
{
GtkSymbolicColor *color;
gchar *end;
if (*end != '\0')
{
- g_message ("Error parsing symbolic color \"%s\", stopped at char %ld : '%c'",
- str, end - str, *end);
+ g_set_error_literal (error,
+ GTK_CSS_PROVIDER_ERROR,
+ GTK_CSS_PROVIDER_ERROR_FAILED,
+ "Could not parse symbolic color");
if (color)
{
else
{
coords[i * 3] = g_ascii_strtod (str, &end);
+
+ if (str == end)
+ {
+ *end_ptr = (gchar *) str;
+ return NULL;
+ }
+
str = end;
}
else
{
coords[(i * 3) + 1] = g_ascii_strtod (str, &end);
+
+ if (str == end)
+ {
+ *end_ptr = (gchar *) str;
+ return NULL;
+ }
+
str = end;
}
return gradient;
}
-static GtkGradient *
-gradient_parse (const gchar *str)
-{
- GtkGradient *gradient;
- gchar *end;
-
- gradient = gradient_parse_str (str, &end);
-
- if (*end != '\0')
- {
- g_message ("Error parsing pattern \"%s\", stopped at char %ld : '%c'",
- str, end - str, *end);
-
- if (gradient)
- {
- gtk_gradient_unref (gradient);
- gradient = NULL;
- }
- }
-
- return gradient;
-}
-
static gchar *
path_parse_str (GtkCssProvider *css_provider,
- const gchar *str,
- gchar **end_ptr)
+ const gchar *str,
+ gchar **end_ptr,
+ GError **error)
{
gchar *path, *chr;
+ const gchar *start, *end;
+ start = str;
if (g_str_has_prefix (str, "url"))
{
return NULL;
}
- chr = strrchr (str, ')');
-
+ chr = strchr (str, ')');
if (!chr)
{
*end_ptr = (gchar *) str;
return NULL;
}
+ end = chr + 1;
+
str++;
SKIP_SPACES (str);
if (*str == '"' || *str == '\'')
{
- gchar *p;
+ const gchar *p;
p = str;
str++;
if (*chr != *p || chr == p)
{
- *end_ptr = str;
+ *end_ptr = (gchar *)str;
return NULL;
}
}
else
{
- *end_ptr = str;
+ *end_ptr = (gchar *)str;
return NULL;
}
path = g_strndup (str, chr - str);
g_strstrip (path);
- *end_ptr = str + strlen (str);
+ *end_ptr = (gchar *)end;
}
else
{
path = g_strdup (str);
- *end_ptr = str + strlen (str);
+ *end_ptr = (gchar *)str + strlen (str);
}
/* Always return an absolute path */
if (!g_file_test (path, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR))
{
- g_warning ("File doesn't exist: %s\n", path);
+ g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_EXIST,
+ "File doesn't exist: %s", path);
g_free (path);
path = NULL;
+ *end_ptr = (gchar *)start;
}
return path;
}
static gchar *
-path_parse (GtkCssProvider *css_provider,
- const gchar *str)
+path_parse (GtkCssProvider *css_provider,
+ const gchar *str,
+ GError **error)
{
- gchar *path, *end;
+ gchar *path;
+ gchar *end;
- path = path_parse_str (css_provider, str, &end);
+ path = path_parse_str (css_provider, str, &end, error);
+
+ if (!path)
+ return NULL;
if (*end != '\0')
{
- g_message ("Error parsing file path \"%s\", stopped at char %ld : '%c'",
- str, end - str, *end);
-
- if (path)
- {
- g_free (path);
- path = NULL;
- }
+ g_set_error_literal (error,
+ GTK_CSS_PROVIDER_ERROR,
+ GTK_CSS_PROVIDER_ERROR_FAILED,
+ "Error parsing path");
+ g_free (path);
+ path = NULL;
}
return path;
static Gtk9Slice *
slice_parse_str (GtkCssProvider *css_provider,
const gchar *str,
- gchar **end_ptr)
+ gchar **end_ptr,
+ GError **error)
{
gdouble distance_top, distance_bottom;
gdouble distance_left, distance_right;
GtkSliceSideModifier mods[2];
- GError *error = NULL;
GdkPixbuf *pixbuf;
Gtk9Slice *slice;
gchar *path;
SKIP_SPACES (str);
/* Parse image url */
- path = path_parse_str (css_provider, str, end_ptr);
+ path = path_parse_str (css_provider, str, end_ptr, error);
if (!path)
return NULL;
SKIP_SPACES (str);
/* Parse top/left/bottom/right distances */
- distance_top = g_strtod (str, end_ptr);
+ distance_top = g_ascii_strtod (str, end_ptr);
str = *end_ptr;
SKIP_SPACES (str);
- distance_right = g_strtod (str, end_ptr);
+ distance_right = g_ascii_strtod (str, end_ptr);
str = *end_ptr;
SKIP_SPACES (str);
- distance_bottom = g_strtod (str, end_ptr);
+ distance_bottom = g_ascii_strtod (str, end_ptr);
str = *end_ptr;
SKIP_SPACES (str);
- distance_left = g_strtod (str, end_ptr);
+ distance_left = g_ascii_strtod (str, end_ptr);
str = *end_ptr;
SKIP_SPACES (str);
mods[1] = mods[0];
}
- pixbuf = gdk_pixbuf_new_from_file (path, &error);
+ pixbuf = gdk_pixbuf_new_from_file (path, error);
g_free (path);
- if (error)
+ if (!pixbuf)
{
- g_warning ("Pixbuf could not be loaded: %s\n", error->message);
- g_error_free (error);
*end_ptr = (gchar *) str;
return NULL;
}
- slice = gtk_9slice_new (pixbuf,
- distance_top, distance_bottom,
- distance_left, distance_right,
- mods[0], mods[1]);
+ slice = _gtk_9slice_new (pixbuf,
+ distance_top, distance_bottom,
+ distance_left, distance_right,
+ mods[0], mods[1]);
g_object_unref (pixbuf);
return slice;
}
-static Gtk9Slice *
-slice_parse (GtkCssProvider *css_provider,
- const gchar *str)
-{
- Gtk9Slice *slice;
- gchar *end;
-
- slice = slice_parse_str (css_provider, str, &end);
-
- if (*end != '\0')
- {
- g_message ("Error parsing sliced image \"%s\", stopped at char %ld : '%c'",
- str, end - str, *end);
-
- if (slice)
- {
- gtk_9slice_unref (slice);
- slice = NULL;
- }
- }
-
- return slice;
-}
-
static gdouble
unit_parse_str (const gchar *str,
gchar **end_str)
gdouble unit;
SKIP_SPACES (str);
- unit = g_strtod (str, end_str);
+ unit = g_ascii_strtod (str, end_str);
str = *end_str;
/* Now parse the unit type, if any. We
return border;
}
-static GtkBorder *
-border_parse (const gchar *str)
-{
- GtkBorder *border;
- gchar *end;
-
- border = border_parse_str (str, &end);
-
- if (*end != '\0')
- {
- g_message ("Error parsing border \"%s\", stopped at char %ld : '%c'",
- str, end - str, *end);
-
- if (border)
- gtk_border_free (border);
-
- return NULL;
- }
-
- return border;
-}
-
static gboolean
-css_provider_parse_value (GtkCssProvider *css_provider,
- const gchar *value_str,
- GValue *value)
+css_provider_parse_value (GtkCssProvider *css_provider,
+ const gchar *value_str,
+ GValue *value,
+ GError **error)
{
+ GtkCssProviderPrivate *priv;
GType type;
gboolean parsed = TRUE;
+ gchar *end = NULL;
+ priv = css_provider->priv;
type = G_VALUE_TYPE (value);
if (type == GDK_TYPE_RGBA ||
type == GDK_TYPE_COLOR)
{
- GdkRGBA color;
- GdkColor rgb;
+ GdkRGBA rgba;
+ GdkColor color;
if (type == GDK_TYPE_RGBA &&
- gdk_rgba_parse (&color, value_str))
- g_value_set_boxed (value, &color);
+ gdk_rgba_parse (&rgba, value_str))
+ g_value_set_boxed (value, &rgba);
else if (type == GDK_TYPE_COLOR &&
- gdk_color_parse (value_str, &rgb))
- g_value_set_boxed (value, &rgb);
+ gdk_color_parse (value_str, &color))
+ g_value_set_boxed (value, &color);
else
{
GtkSymbolicColor *symbolic_color;
- symbolic_color = symbolic_color_parse (value_str);
+ symbolic_color = symbolic_color_parse_str (value_str, &end);
- if (!symbolic_color)
- return FALSE;
-
- g_value_unset (value);
- g_value_init (value, GTK_TYPE_SYMBOLIC_COLOR);
- g_value_take_boxed (value, symbolic_color);
+ if (symbolic_color)
+ {
+ g_value_unset (value);
+ g_value_init (value, GTK_TYPE_SYMBOLIC_COLOR);
+ g_value_take_boxed (value, symbolic_color);
+ }
+ else
+ parsed = FALSE;
}
}
else if (type == PANGO_TYPE_FONT_DESCRIPTION)
GtkThemingEngine *engine;
engine = gtk_theming_engine_load (value_str);
- g_value_set_object (value, engine);
+ if (engine)
+ g_value_set_object (value, engine);
+ else
+ parsed = FALSE;
}
else if (type == GTK_TYPE_ANIMATION_DESCRIPTION)
{
GtkAnimationDescription *desc;
- desc = gtk_animation_description_from_string (value_str);
+ desc = _gtk_animation_description_from_string (value_str);
if (desc)
g_value_take_boxed (value, desc);
{
GtkBorder *border;
- border = border_parse (value_str);
+ border = border_parse_str (value_str, &end);
g_value_take_boxed (value, border);
}
else if (type == CAIRO_GOBJECT_TYPE_PATTERN)
{
GtkGradient *gradient;
- gradient = gradient_parse (value_str);
+ gradient = gradient_parse_str (value_str, &end);
if (gradient)
{
g_value_take_boxed (value, gradient);
}
else
- parsed = FALSE;
+ {
+ gchar *path;
+ GdkPixbuf *pixbuf;
+
+ g_clear_error (error);
+ path = path_parse_str (css_provider, value_str, &end, error);
+
+ if (path)
+ {
+ pixbuf = gdk_pixbuf_new_from_file (path, NULL);
+ g_free (path);
+
+ if (pixbuf)
+ {
+ cairo_surface_t *surface;
+ cairo_pattern_t *pattern;
+ cairo_t *cr;
+ cairo_matrix_t matrix;
+
+ 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);
+ }
+ else
+ parsed = FALSE;
+ }
+ else
+ parsed = FALSE;
+ }
}
else if (G_TYPE_IS_ENUM (type))
{
if (!enum_value)
{
- g_warning ("Unknown value '%s' for enum type '%s'",
- value_str, g_type_name (type));
+ g_set_error (error,
+ GTK_CSS_PROVIDER_ERROR,
+ GTK_CSS_PROVIDER_ERROR_FAILED,
+ "Unknown value '%s' for enum type '%s'",
+ value_str, g_type_name (type));
parsed = FALSE;
}
else
if (!flag_value)
{
- g_warning ("Unknown flag '%s' for type '%s'",
- value_str, g_type_name (type));
+ g_set_error (error,
+ GTK_CSS_PROVIDER_ERROR,
+ GTK_CSS_PROVIDER_ERROR_FAILED,
+ "Unknown flag '%s' for type '%s'",
+ value_str, g_type_name (type));
parsed = FALSE;
}
else
if (!flag_value)
{
- g_warning ("Unknown flag '%s' for type '%s'",
- value_str, g_type_name (type));
+ g_set_error (error,
+ GTK_CSS_PROVIDER_ERROR,
+ GTK_CSS_PROVIDER_ERROR_FAILED,
+ "Unknown flag '%s' for type '%s'",
+ value_str, g_type_name (type));
parsed = FALSE;
}
else
{
Gtk9Slice *slice;
- slice = slice_parse (css_provider, value_str);
+ slice = slice_parse_str (css_provider, value_str, &end, error);
if (slice)
g_value_take_boxed (value, slice);
}
else
{
- g_warning ("Cannot parse string '%s' for type %s", value_str, g_type_name (type));
+ g_set_error (error,
+ GTK_CSS_PROVIDER_ERROR,
+ GTK_CSS_PROVIDER_ERROR_FAILED,
+ "Cannot parse string '%s' for type %s",
+ value_str, g_type_name (type));
parsed = FALSE;
}
+ if (end && *end)
+ {
+ /* Set error position in the scanner
+ * according to what we've parsed so far
+ */
+ priv->value_pos += (end - value_str);
+
+ if (error && !*error)
+ g_set_error_literal (error,
+ GTK_CSS_PROVIDER_ERROR,
+ GTK_CSS_PROVIDER_ERROR_FAILED,
+ "Failed to parse value");
+ }
+
return parsed;
}
+static void
+scanner_report_warning (GtkCssProvider *css_provider,
+ GTokenType expected_token,
+ GError *error)
+{
+ GtkCssProviderPrivate *priv;
+ const gchar *line_end, *line_start;
+ const gchar *expected_str;
+ gchar buf[2], *line, *str;
+ guint pos;
+
+ priv = css_provider->priv;
+
+ if (error)
+ str = g_strdup (error->message);
+ else
+ {
+ if (priv->scanner->user_data)
+ expected_str = priv->scanner->user_data;
+ else
+ {
+ switch (expected_token)
+ {
+ case G_TOKEN_SYMBOL:
+ expected_str = "Symbol";
+ case G_TOKEN_IDENTIFIER:
+ expected_str = "Identifier";
+ default:
+ buf[0] = expected_token;
+ buf[1] = '\0';
+ expected_str = buf;
+ }
+ }
+
+ str = g_strdup_printf ("Parse error, expecting a %s '%s'",
+ (expected_str != buf) ? "valid" : "",
+ expected_str);
+ }
+
+ if (priv->value_pos)
+ line_start = priv->value_pos - 1;
+ else
+ line_start = priv->scanner->text - 1;
+
+ while (*line_start != '\n' &&
+ line_start != priv->buffer)
+ line_start--;
+
+ if (*line_start == '\n')
+ line_start++;
+
+ if (priv->value_pos)
+ pos = priv->value_pos - line_start + 1;
+ else
+ pos = priv->scanner->text - line_start - 1;
+
+ line_end = strchr (line_start, '\n');
+
+ if (line_end)
+ line = g_strndup (line_start, (line_end - line_start));
+ else
+ line = g_strdup (line_start);
+
+ g_message ("CSS: %s\n"
+ "%s, line %d, char %d:\n"
+ "%*c %s\n"
+ "%*c ^",
+ str, priv->scanner->input_name,
+ priv->scanner->line, priv->scanner->position,
+ 3, ' ', line,
+ 3 + pos, ' ');
+
+ g_free (line);
+ g_free (str);
+}
+
static GTokenType
-parse_rule (GtkCssProvider *css_provider,
- GScanner *scanner)
+parse_rule (GtkCssProvider *css_provider,
+ GScanner *scanner,
+ GError **error)
{
GtkCssProviderPrivate *priv;
GTokenType expected_token;
g_scanner_get_next_token (scanner);
if (scanner->token != G_TOKEN_IDENTIFIER)
- return G_TOKEN_IDENTIFIER;
+ {
+ scanner->user_data = "Color name";
+ return G_TOKEN_IDENTIFIER;
+ }
color_name = g_strdup (scanner->value.v_identifier);
css_provider_push_scope (css_provider, SCOPE_VALUE);
g_scanner_get_next_token (scanner);
if (scanner->token != G_TOKEN_IDENTIFIER)
- return G_TOKEN_IDENTIFIER;
+ {
+ scanner->user_data = "Color definition";
+ return G_TOKEN_IDENTIFIER;
+ }
color_str = g_strstrip (scanner->value.v_identifier);
- color = symbolic_color_parse (color_str);
+ color = symbolic_color_parse (color_str, error);
if (!color)
- return G_TOKEN_IDENTIFIER;
+ {
+ scanner->user_data = "Color definition";
+ return G_TOKEN_IDENTIFIER;
+ }
g_hash_table_insert (priv->symbolic_colors, color_name, color);
{
GScanner *scanner_backup;
GSList *state_backup;
- GError *error = NULL;
gboolean loaded;
- gchar *path;
+ gchar *path = NULL;
css_provider_push_scope (css_provider, SCOPE_VALUE);
g_scanner_get_next_token (scanner);
if (scanner->token == G_TOKEN_IDENTIFIER &&
g_str_has_prefix (scanner->value.v_identifier, "url"))
path = path_parse (css_provider,
- g_strstrip (scanner->value.v_identifier));
+ g_strstrip (scanner->value.v_identifier),
+ error);
else if (scanner->token == G_TOKEN_STRING)
path = path_parse (css_provider,
- g_strstrip (scanner->value.v_string));
- else
- return G_TOKEN_IDENTIFIER;
+ g_strstrip (scanner->value.v_string),
+ error);
if (path == NULL)
- return G_TOKEN_IDENTIFIER;
+ {
+ scanner->user_data = "File URL";
+ return G_TOKEN_IDENTIFIER;
+ }
css_provider_pop_scope (css_provider);
g_scanner_get_next_token (scanner);
/* FIXME: Avoid recursive importing */
loaded = gtk_css_provider_load_from_path_internal (css_provider, path,
- FALSE, &error);
+ FALSE, error);
/* Restore previous state */
css_provider_reset_parser (css_provider);
if (!loaded)
{
- g_warning ("Error loading imported file \"%s\": %s",
- path, (error) ? error->message : "");
- g_error_free (error);
+ scanner->user_data = "File URL";
return G_TOKEN_IDENTIFIER;
}
else
return G_TOKEN_NONE;
}
else
- return G_TOKEN_IDENTIFIER;
+ {
+ scanner->user_data = "Directive";
+ return G_TOKEN_IDENTIFIER;
+ }
}
expected_token = parse_selector (css_provider, scanner, &selector);
if (expected_token != G_TOKEN_NONE)
{
selector_path_unref (selector);
+ scanner->user_data = "Selector";
return expected_token;
}
if (expected_token != G_TOKEN_NONE)
{
selector_path_unref (selector);
+ scanner->user_data = "Selector";
return expected_token;
}
while (scanner->token == G_TOKEN_IDENTIFIER)
{
- const gchar *value_str = NULL;
+ gchar *value_str = NULL;
GtkStylePropertyParser parse_func = NULL;
GParamSpec *pspec;
- GError *error = NULL;
gchar *prop;
prop = g_strdup (scanner->value.v_identifier);
return ':';
}
+ priv->value_pos = priv->scanner->text;
+
css_provider_push_scope (css_provider, SCOPE_VALUE);
g_scanner_get_next_token (scanner);
if (scanner->token != G_TOKEN_IDENTIFIER)
{
g_free (prop);
+ scanner->user_data = "Property value";
return G_TOKEN_IDENTIFIER;
}
- value_str = g_strstrip (scanner->value.v_identifier);
+ value_str = scanner->value.v_identifier;
+ SKIP_SPACES (value_str);
+ g_strchomp (value_str);
if (gtk_style_properties_lookup_property (prop, &parse_func, &pspec))
{
g_value_set_string (val, value_str);
g_hash_table_insert (priv->cur_properties, prop, val);
}
- else if ((parse_func && (parse_func) (value_str, val, &error)) ||
- (!parse_func && css_provider_parse_value (css_provider, value_str, val)))
+ else if ((parse_func && (parse_func) (value_str, val, error)) ||
+ (!parse_func && css_provider_parse_value (css_provider, value_str, val, error)))
g_hash_table_insert (priv->cur_properties, prop, val);
else
{
- if (error)
- {
- g_message ("Error parsing property value: %s\n", error->message);
- g_error_free (error);
- }
-
g_value_unset (val);
g_slice_free (GValue, val);
g_free (prop);
+ scanner->user_data = "Property value";
return G_TOKEN_IDENTIFIER;
}
}
return G_TOKEN_NONE;
}
-static void
-scanner_msg (GScanner *scanner,
- gchar *message,
- gboolean is_error)
-{
- GError **error = scanner->user_data;
-
- g_set_error_literal (error,
- GTK_CSS_PROVIDER_ERROR,
- GTK_CSS_PROVIDER_ERROR_FAILED,
- message);
-}
-
static gboolean
parse_stylesheet (GtkCssProvider *css_provider,
GError **error)
{
GtkCssProviderPrivate *priv;
+ gboolean result;
+
+ result = TRUE;
priv = css_provider->priv;
g_scanner_get_next_token (priv->scanner);
while (!g_scanner_eof (priv->scanner))
{
GTokenType expected_token;
+ GError *err = NULL;
css_provider_reset_parser (css_provider);
- expected_token = parse_rule (css_provider, priv->scanner);
+ expected_token = parse_rule (css_provider, priv->scanner, &err);
if (expected_token != G_TOKEN_NONE)
{
+ /* If a GError was passed in, propagate the error and bail out,
+ * else report a warning and keep going
+ */
if (error != NULL)
{
- priv->scanner->msg_handler = scanner_msg;
- priv->scanner->user_data = error;
+ result = FALSE;
+ if (err)
+ g_propagate_error (error, err);
+ else
+ g_set_error_literal (error,
+ GTK_CSS_PROVIDER_ERROR,
+ GTK_CSS_PROVIDER_ERROR_FAILED,
+ "Error parsing stylesheet");
+ break;
}
-
- g_scanner_unexp_token (priv->scanner, expected_token,
- NULL, NULL, NULL,
- "Error parsing style resource", FALSE);
-
- if (error != NULL)
+ else
{
- priv->scanner->msg_handler = NULL;
- priv->scanner->user_data = NULL;
-
- return FALSE;
+ scanner_report_warning (css_provider, expected_token, err);
+ g_clear_error (&err);
}
while (!g_scanner_eof (priv->scanner) &&
g_scanner_get_next_token (priv->scanner);
}
- return TRUE;
+ return result;
}
/**
g_ptr_array_remove_range (priv->selectors_info, 0, priv->selectors_info->len);
priv->scanner->input_name = "-";
+ priv->buffer = data;
g_scanner_input_text (priv->scanner, data, (guint) length);
g_free (priv->filename);
priv->filename = NULL;
+ priv->buffer = NULL;
return parse_stylesheet (css_provider, error);
}
priv->filename = g_file_get_path (file);
priv->scanner->input_name = priv->filename;
+ priv->buffer = data;
g_scanner_input_text (priv->scanner, data, (guint) length);
ret = parse_stylesheet (css_provider, error);
+ priv->buffer = NULL;
g_free (data);
return ret;
}
priv->scanner->input_name = priv->filename;
+ priv->buffer = data;
g_scanner_input_text (priv->scanner, data, (guint) length);
ret = parse_stylesheet (css_provider, error);
+ priv->buffer = NULL;
g_mapped_file_unref (mapped_file);
return ret;
"@define-color tooltip_bg_color #eee1b3; \n"
"@define-color tooltip_fg_color #000; \n"
"\n"
+ "@define-color info_fg_color rgb (181, 171, 156);\n"
+ "@define-color info_bg_color rgb (252, 252, 189);\n"
+ "@define-color warning_fg_color rgb (173, 120, 41);\n"
+ "@define-color warning_bg_color rgb (250, 173, 61);\n"
+ "@define-color question_fg_color rgb (97, 122, 214);\n"
+ "@define-color question_bg_color rgb (138, 173, 212);\n"
+ "@define-color error_fg_color rgb (166, 38, 38);\n"
+ "@define-color error_bg_color rgb (237, 54, 54);\n"
+ "\n"
"*,\n"
"GtkTreeView > GtkButton {\n"
" background-color: @bg_color;\n"
" color: @fg_color;\n"
" border-color: shade (@bg_color, 0.6);\n"
- " padding: 2 2; \n"
+ " padding: 2;\n"
+ " border-width: 0;\n"
"}\n"
"\n"
"*:prelight {\n"
" color: @selected_fg_color;\n"
"}\n"
"\n"
+ ".expander {\n"
+ " color: #fff;\n"
+ "}\n"
+ "\n"
+ ".expander:prelight {\n"
+ " color: @text_color;\n"
+ "}\n"
+ "\n"
+ ".expander:active {\n"
+ " transition: 300ms linear;\n"
+ "}\n"
+ "\n"
"*:insensitive {\n"
+ " border-color: shade (@bg_color, 0.7);\n"
" background-color: shade (@bg_color, 0.9);\n"
" color: shade (@bg_color, 0.7);\n"
"}\n"
".tooltip {\n"
" background-color: @tooltip_bg_color; \n"
" color: @tooltip_fg_color; \n"
+ " border-color: @tooltip_fg_color; \n"
+ " border-width: 1;\n"
+ " border-style: solid;\n"
"}\n"
"\n"
".button,\n"
" background-color: shade (@base_color, 0.9);\n"
" color: shade (@base_color, 0.7);\n"
"}\n"
+ ".entry:active {\n"
+ " background-color: #c4c2bd;\n"
+ " color: #000;\n"
+ "}\n"
"\n"
- ".progressbar:prelight,\n"
+ ".progressbar,\n"
".entry.progressbar {\n"
" background-color: @selected_bg_color;\n"
" border-color: shade (@selected_bg_color, 0.7);\n"
".check:hover, .radio:hover {\n"
" background-color: @base_color;\n"
" border-color: @fg_color;\n"
- " color: @text_color;\n"
+ " color: @text_color;\n"
" border-style: solid;\n"
" border-width: 1;\n"
"}\n"
" border-style: inset;\n"
" border-width: 1;\n"
"}\n"
+ "\n"
+ ".menu,\n"
+ ".menubar,\n"
+ ".toolbar {\n"
+ " border-style: outset;\n"
+ " border-width: 1;\n"
+ "}\n"
+ "\n"
+ ".menu:hover,\n"
+ ".menubar:hover {\n"
+ " background-color: @selected_bg_color;\n"
+ " color: @selected_fg_color;\n"
+ "}\n"
+ "\n"
+ ".menu .check,\n"
+ ".menu .radio,\n"
+ ".menu .check:active,\n"
+ ".menu .radio:active {\n"
+ " border-style: none;\n"
+ "}\n"
+ "\n"
+ "GtkSpinButton.button {\n"
+ " border-width: 1;\n"
+ "}\n"
+ "\n"
+ ".scale.slider:hover,\n"
+ "GtkSpinButton.button:hover {\n"
+ " background-color: shade (@bg_color, 1.05);\n"
+ " border-color: shade (@bg_color, 0.8);\n"
+ "}\n"
+ "\n"
+ "GtkToggleButton.button:inconsistent {\n"
+ " border-style: outset;\n"
+ " border-width: 1px;\n"
+ " background-color: shade (@bg_color, 0.9);\n"
+ " border-color: shade (@bg_color, 0.7);\n"
+ "}\n"
+ "\n"
+ "GtkLabel:selected {\n"
+ " background-color: shade (@bg_color, 0.9);\n"
+ " color: @fg_color;\n"
+ "}\n"
+ "\n"
+ "GtkLabel:selected:focused {\n"
+ " background-color: @selected_bg_color;\n"
+ " color: @selected_fg_color;\n"
+ "}\n"
+ "\n"
+ ".spinner:active {\n"
+ " transition: 750ms linear loop;\n"
+ "}\n"
+ "\n"
+ ".info {\n"
+ " background-color: @info_bg_color;\n"
+ " color: @info_fg_color;\n"
+ "}\n"
+ "\n"
+ ".warning {\n"
+ " background-color: @warning_bg_color;\n"
+ " color: @warning_fg_color;\n"
+ "}\n"
+ "\n"
+ ".question {\n"
+ " background-color: @question_bg_color;\n"
+ " color: @question_fg_color;\n"
+ "}\n"
+ "\n"
+ ".error {\n"
+ " background-color: @error_bg_color;\n"
+ " color: @error_fg_color;\n"
+ "}\n"
+ "\n"
+ ".highlight {\n"
+ " background-color: @selected_bg_color;\n"
+ " color: @selected_fg_color;\n"
+ "}\n"
"\n";
provider = gtk_css_provider_new ();
- gtk_css_provider_load_from_data (provider, str, -1, NULL);
+ if (!gtk_css_provider_load_from_data (provider, str, -1, NULL))
+ {
+ g_error ("Failed to load the internal default CSS.");
+ }
}
return provider;
}
}
+ g_free (subpath);
+
if (path)
{
GError *error = NULL;