]> Pileus Git - ~andy/gtk/blob - gtk/gtkcssprovider.c
cssprovider: Don't hardcode strings anymore
[~andy/gtk] / gtk / gtkcssprovider.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 2010 Carlos Garnacho <carlosg@gnome.org>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 #include "config.h"
21
22 #include <string.h>
23 #include <stdlib.h>
24
25 #include <gdk-pixbuf/gdk-pixbuf.h>
26 #include <cairo-gobject.h>
27
28 #include "gtkcssproviderprivate.h"
29
30 #include "gtkcssstringfuncsprivate.h"
31 #include "gtksymboliccolor.h"
32 #include "gtkstyleprovider.h"
33 #include "gtkstylecontextprivate.h"
34 #include "gtkbindings.h"
35 #include "gtkmarshalers.h"
36 #include "gtkprivate.h"
37 #include "gtkintl.h"
38
39 /**
40  * SECTION:gtkcssprovider
41  * @Short_description: CSS-like styling for widgets
42  * @Title: GtkCssProvider
43  * @See_also: #GtkStyleContext, #GtkStyleProvider
44  *
45  * GtkCssProvider is an object implementing the #GtkStyleProvider interface.
46  * It is able to parse <ulink url="http://www.w3.org/TR/CSS2">CSS</ulink>-like
47  * input in order to style widgets.
48  *
49  * <refsect2 id="gtkcssprovider-files">
50  * <title>Default files</title>
51  * <para>
52  * An application can cause GTK+ to parse a specific CSS style sheet by
53  * calling gtk_css_provider_load_from_file() and adding the provider with
54  * gtk_style_context_add_provider() or gtk_style_context_add_provider_for_screen().
55  * In addition, certain files will be read when GTK+ is initialized. First,
56  * the file <filename><envar>$XDG_CONFIG_HOME</envar>/gtk-3.0/gtk.css</filename>
57  * is loaded if it exists. Then, GTK+ tries to load
58  * <filename><envar>$HOME</envar>/.themes/<replaceable>theme-name</replaceable>/gtk-3.0/gtk.css</filename>,
59  * falling back to
60  * <filename><replaceable>datadir</replaceable>/share/themes/<replaceable>theme-name</replaceable>/gtk-3.0/gtk.css</filename>,
61  * where <replaceable>theme-name</replaceable> is the name of the current theme
62  * (see the #GtkSettings:gtk-theme-name setting) and <replaceable>datadir</replaceable>
63  * is the prefix configured when GTK+ was compiled, unless overridden by the
64  * <envar>GTK_DATA_PREFIX</envar> environment variable.
65  * </para>
66  * </refsect2>
67  * <refsect2 id="gtkcssprovider-stylesheets">
68  * <title>Style sheets</title>
69  * <para>
70  * The basic structure of the style sheets understood by this provider is
71  * a series of statements, which are either rule sets or '@-rules', separated
72  * by whitespace.
73  * </para>
74  * <para>
75  * A rule set consists of a selector and a declaration block, which is
76  * a series of declarations enclosed in curly braces ({ and }). The
77  * declarations are separated by semicolons (;). Multiple selectors can
78  * share the same declaration block, by putting all the separators in
79  * front of the block, separated by commas.
80  * </para>
81  * <example><title>A rule set with two selectors</title>
82  * <programlisting language="text">
83  * GtkButton, GtkEntry {
84  *     color: &num;ff00ea;
85  *     font: Comic Sans 12
86  * }
87  * </programlisting>
88  * </example>
89  * </refsect2>
90  * <refsect2 id="gtkcssprovider-selectors">
91  * <title>Selectors</title>
92  * <para>
93  * Selectors work very similar to the way they do in CSS, with widget class
94  * names taking the role of element names, and widget names taking the role
95  * of IDs. When used in a selector, widget names must be prefixed with a
96  * '&num;' character. The '*' character represents the so-called universal
97  * selector, which matches any widget.
98  * </para>
99  * <para>
100  * To express more complicated situations, selectors can be combined in
101  * various ways:
102  * <itemizedlist>
103  * <listitem><para>To require that a widget satisfies several conditions,
104  *   combine several selectors into one by concatenating them. E.g.
105  *   <literal>GtkButton&num;button1</literal> matches a GtkButton widget
106  *   with the name button1.</para></listitem>
107  * <listitem><para>To only match a widget when it occurs inside some other
108  *   widget, write the two selectors after each other, separated by whitespace.
109  *   E.g. <literal>GtkToolBar GtkButton</literal> matches GtkButton widgets
110  *   that occur inside a GtkToolBar.</para></listitem>
111  * <listitem><para>In the previous example, the GtkButton is matched even
112  *   if it occurs deeply nested inside the toolbar. To restrict the match
113  *   to direct children of the parent widget, insert a '>' character between
114  *   the two selectors. E.g. <literal>GtkNotebook > GtkLabel</literal> matches
115  *   GtkLabel widgets that are direct children of a GtkNotebook.</para></listitem>
116  * </itemizedlist>
117  * </para>
118  * <example>
119  * <title>Widget classes and names in selectors</title>
120  * <programlisting language="text">
121  * /&ast; Theme labels that are descendants of a window &ast;/
122  * GtkWindow GtkLabel {
123  *     background-color: &num;898989
124  * }
125  *
126  * /&ast; Theme notebooks, and anything that's within these &ast;/
127  * GtkNotebook {
128  *     background-color: &num;a939f0
129  * }
130  *
131  * /&ast; Theme combo boxes, and entries that
132  *  are direct children of a notebook &ast;/
133  * GtkComboBox,
134  * GtkNotebook > GtkEntry {
135  *     color: @fg_color;
136  *     background-color: &num;1209a2
137  * }
138  *
139  * /&ast; Theme any widget within a GtkBin &ast;/
140  * GtkBin * {
141  *     font-name: Sans 20
142  * }
143  *
144  * /&ast; Theme a label named title-label &ast;/
145  * GtkLabel&num;title-label {
146  *     font-name: Sans 15
147  * }
148  *
149  * /&ast; Theme any widget named main-entry &ast;/
150  * &num;main-entry {
151  *     background-color: &num;f0a810
152  * }
153  * </programlisting>
154  * </example>
155  * <para>
156  * Widgets may also define style classes, which can be used for matching.
157  * When used in a selector, style classes must be prefixed with a '.'
158  * character.
159  * </para>
160  * <para>
161  * Refer to the documentation of individual widgets to learn which
162  * style classes they define and see <xref linkend="gtkstylecontext-classes"/>
163  * for a list of all style classes used by GTK+ widgets.
164  * </para>
165  * <para>
166  * Note that there is some ambiguity in the selector syntax when it comes
167  * to differentiation widget class names from regions. GTK+ currently treats
168  * a string as a widget class name if it contains any uppercase characters
169  * (which should work for more widgets with names like GtkLabel).
170  * </para>
171  * <example>
172  * <title>Style classes in selectors</title>
173  * <programlisting language="text">
174  * /&ast; Theme all widgets defining the class entry &ast;/
175  * .entry {
176  *     color: &num;39f1f9;
177  * }
178  *
179  * /&ast; Theme spinbuttons' entry &ast;/
180  * GtkSpinButton.entry {
181  *     color: &num;900185
182  * }
183  * </programlisting>
184  * </example>
185  * <para>
186  * In complicated widgets like e.g. a GtkNotebook, it may be desirable
187  * to style different parts of the widget differently. To make this
188  * possible, container widgets may define regions, whose names
189  * may be used for matching in selectors.
190  * </para>
191  * <para>
192  * Some containers allow to further differentiate between regions by
193  * applying so-called pseudo-classes to the region. For example, the
194  * tab region in GtkNotebook allows to single out the first or last
195  * tab by using the :first-child or :last-child pseudo-class.
196  * When used in selectors, pseudo-classes must be prefixed with a
197  * ':' character.
198  * </para>
199  * <para>
200  * Refer to the documentation of individual widgets to learn which
201  * regions and pseudo-classes they define and see
202  * <xref linkend="gtkstylecontext-classes"/> for a list of all regions
203  * used by GTK+ widgets.
204  * </para>
205  * <example>
206  * <title>Regions in selectors</title>
207  * <programlisting language="text">
208  * /&ast; Theme any label within a notebook &ast;/
209  * GtkNotebook GtkLabel {
210  *     color: &num;f90192;
211  * }
212  *
213  * /&ast; Theme labels within notebook tabs &ast;/
214  * GtkNotebook tab GtkLabel {
215  *     color: &num;703910;
216  * }
217  *
218  * /&ast; Theme labels in the any first notebook
219  *  tab, both selectors are equivalent &ast;/
220  * GtkNotebook tab:nth-child(first) GtkLabel,
221  * GtkNotebook tab:first-child GtkLabel {
222  *     color: &num;89d012;
223  * }
224  * </programlisting>
225  * </example>
226  * <para>
227  * Another use of pseudo-classes is to match widgets depending on their
228  * state. This is conceptually similar to the :hover, :active or :focus
229  * pseudo-classes in CSS. The available pseudo-classes for widget states
230  * are :active, :prelight (or :hover), :insensitive, :selected, :focused
231  * and :inconsistent.
232  * </para>
233  * <example>
234  * <title>Styling specific widget states</title>
235  * <programlisting language="text">
236  * /&ast; Theme active (pressed) buttons &ast;/
237  * GtkButton:active {
238  *     background-color: &num;0274d9;
239  * }
240  *
241  * /&ast; Theme buttons with the mouse pointer on it,
242  *    both are equivalent &ast;/
243  * GtkButton:hover,
244  * GtkButton:prelight {
245  *     background-color: &num;3085a9;
246  * }
247  *
248  * /&ast; Theme insensitive widgets, both are equivalent &ast;/
249  * :insensitive,
250  * *:insensitive {
251  *     background-color: &num;320a91;
252  * }
253  *
254  * /&ast; Theme selection colors in entries &ast;/
255  * GtkEntry:selected {
256  *     background-color: &num;56f9a0;
257  * }
258  *
259  * /&ast; Theme focused labels &ast;/
260  * GtkLabel:focused {
261  *     background-color: &num;b4940f;
262  * }
263  *
264  * /&ast; Theme inconsistent checkbuttons &ast;/
265  * GtkCheckButton:inconsistent {
266  *     background-color: &num;20395a;
267  * }
268  * </programlisting>
269  * </example>
270  * <para>
271  * Widget state pseudoclasses may only apply to the last element
272  * in a selector.
273  * </para>
274  * <para>
275  * To determine the effective style for a widget, all the matching rule
276  * sets are merged. As in CSS, rules apply by specificity, so the rules
277  * whose selectors more closely match a widget path will take precedence
278  * over the others.
279  * </para>
280  * </refsect2>
281  * <refsect2 id="gtkcssprovider-rules">
282  * <title>&commat; Rules</title>
283  * <para>
284  * GTK+'s CSS supports the &commat;import rule, in order to load another
285  * CSS style sheet in addition to the currently parsed one.
286  * </para>
287  * <example>
288  * <title>Using the &commat;import rule</title>
289  * <programlisting language="text">
290  * &commat;import url ("path/to/common.css");
291  * </programlisting>
292  * </example>
293  * <para id="css-binding-set">
294  * In order to extend key bindings affecting different widgets, GTK+
295  * supports the &commat;binding-set rule to parse a set of bind/unbind
296  * directives, see #GtkBindingSet for the supported syntax. Note that
297  * the binding sets defined in this way must be associated with rule sets
298  * by setting the gtk-key-bindings style property.
299  * </para>
300  * <para>
301  * Customized key bindings are typically defined in a separate
302  * <filename>gtk-keys.css</filename> CSS file and GTK+ loads this file
303  * according to the current key theme, which is defined by the
304  * #GtkSettings:gtk-key-theme-name setting.
305  * </para>
306  * <example>
307  * <title>Using the &commat;binding rule</title>
308  * <programlisting language="text">
309  * &commat;binding-set binding-set1 {
310  *   bind "&lt;alt&gt;Left" { "move-cursor" (visual-positions, -3, 0) };
311  *   unbind "End";
312  * };
313  *
314  * &commat;binding-set binding-set2 {
315  *   bind "&lt;alt&gt;Right" { "move-cursor" (visual-positions, 3, 0) };
316  *   bind "&lt;alt&gt;KP_space" { "delete-from-cursor" (whitespace, 1)
317  *                          "insert-at-cursor" (" ") };
318  * };
319  *
320  * GtkEntry {
321  *   gtk-key-bindings: binding-set1, binding-set2;
322  * }
323  * </programlisting>
324  * </example>
325  * <para>
326  * GTK+ also supports an additional &commat;define-color rule, in order
327  * to define a color name which may be used instead of color numeric
328  * representations. Also see the #GtkSettings:gtk-color-scheme setting
329  * for a way to override the values of these named colors.
330  * </para>
331  * <example>
332  * <title>Defining colors</title>
333  * <programlisting language="text">
334  * &commat;define-color bg_color &num;f9a039;
335  *
336  * &ast; {
337  *     background-color: &commat;bg_color;
338  * }
339  * </programlisting>
340  * </example>
341  * </refsect2>
342  * <refsect2 id="gtkcssprovider-symbolic-colors">
343  * <title>Symbolic colors</title>
344  * <para>
345  * Besides being able to define color names, the CSS parser is also able
346  * to read different color expressions, which can also be nested, providing
347  * a rich language to define colors which are derived from a set of base
348  * colors.
349  * </para>
350  * <example>
351  * <title>Using symbolic colors</title>
352  * <programlisting language="text">
353  * &commat;define-color entry-color shade (&commat;bg_color, 0.7);
354  *
355  * GtkEntry {
356  *     background-color: @entry-color;
357  * }
358  *
359  * GtkEntry:focused {
360  *     background-color: mix (&commat;entry-color,
361  *                            shade (&num;fff, 0.5),
362  *                            0.8);
363  * }
364  * </programlisting>
365  * </example>
366  * <para>
367  *   The various ways to express colors in GTK+ CSS are:
368  * </para>
369  * <informaltable>
370  *   <tgroup cols="3">
371  *     <thead>
372  *       <row>
373  *         <entry>Syntax</entry>
374  *         <entry>Explanation</entry>
375  *         <entry>Examples</entry>
376  *       </row>
377  *     </thead>
378  *     <tbody>
379  *       <row>
380  *         <entry>rgb(@r, @g, @b)</entry>
381  *         <entry>An opaque color; @r, @g, @b can be either integers between
382  *                0 and 255 or percentages</entry>
383  *         <entry><literallayout>rgb(128, 10, 54)
384  * rgb(20%, 30%, 0%)</literallayout></entry>
385  *       </row>
386  *       <row>
387  *         <entry>rgba(@r, @g, @b, @a)</entry>
388  *         <entry>A translucent color; @r, @g, @b are as in the previous row,
389  *                @a is a floating point number between 0 and 1</entry>
390  *         <entry><literallayout>rgba(255, 255, 0, 0.5)</literallayout></entry>
391  *       </row>
392  *       <row>
393  *         <entry>&num;@xxyyzz</entry>
394  *         <entry>An opaque color; @xx, @yy, @zz are hexadecimal numbers
395  *                specifying @r, @g, @b variants with between 1 and 4
396  *                hexadecimal digits per component are allowed</entry>
397  *         <entry><literallayout>&num;ff12ab
398  * &num;f0c</literallayout></entry>
399  *       </row>
400  *       <row>
401  *         <entry>&commat;name</entry>
402  *         <entry>Reference to a color that has been defined with
403  *                &commat;define-color
404  *         </entry>
405  *         <entry>&commat;bg_color</entry>
406  *       </row>
407  *       <row>
408  *         <entry>mix(@color1, @color2, @f)</entry>
409  *         <entry>A linear combination of @color1 and @color2. @f is a
410  *                floating point number between 0 and 1.</entry>
411  *         <entry><literallayout>mix(&num;ff1e0a, &commat;bg_color, 0.8)</literallayout></entry>
412  *       </row>
413  *       <row>
414  *         <entry>shade(@color, @f)</entry>
415  *         <entry>A lighter or darker variant of @color. @f is a
416  *                floating point number.
417  *         </entry>
418  *         <entry>shade(&commat;fg_color, 0.5)</entry>
419  *       </row>
420  *       <row>
421  *         <entry>lighter(@color)</entry>
422  *         <entry>A lighter variant of @color</entry>
423  *       </row>
424  *       <row>
425  *         <entry>darker(@color)</entry>
426  *         <entry>A darker variant of @color</entry>
427  *       </row>
428  *     </tbody>
429  *   </tgroup>
430  * </informaltable>
431  * </refsect2>
432  * <refsect2 id="gtkcssprovider-gradients">
433  * <title>Gradients</title>
434  * <para>
435  * Linear or radial Gradients can be used as background images.
436  * </para>
437  * <para>
438  * A linear gradient along the line from (@start_x, @start_y) to
439  * (@end_x, @end_y) is specified using the syntax
440  * <literallayout>-gtk-gradient (linear,
441  *               @start_x @start_y, @end_x @end_y,
442  *               color-stop (@position, @color),
443  *               ...)</literallayout>
444  * where @start_x and @end_x can be either a floating point number between
445  * 0 and 1 or one of the special values 'left', 'right' or 'center', @start_y
446  * and @end_y can be either a floating point number between 0 and 1 or one
447  * of the special values 'top', 'bottom' or 'center', @position is a floating
448  * point number between 0 and 1 and @color is a color expression (see above).
449  * The color-stop can be repeated multiple times to add more than one color
450  * stop. 'from (@color)' and 'to (@color)' can be used as abbreviations for
451  * color stops with position 0 and 1, respectively.
452  * </para>
453  * <example>
454  * <title>A linear gradient</title>
455  * <inlinegraphic fileref="gradient1.png" format="PNG"/>
456  * <para>This gradient was specified with
457  * <literallayout>-gtk-gradient (linear,
458  *                left top, right bottom,
459  *                from(&commat;yellow), to(&commat;blue))</literallayout></para>
460  * </example>
461  * <example>
462  * <title>Another linear gradient</title>
463  * <inlinegraphic fileref="gradient2.png" format="PNG"/>
464  * <para>This gradient was specified with
465  * <literallayout>-gtk-gradient (linear,
466  *                0 0, 0 1,
467  *                color-stop(0, &commat;yellow),
468  *                color-stop(0.2, &commat;blue),
469  *                color-stop(1, &num;0f0))</literallayout></para>
470  * </example>
471  * <para>
472  * A radial gradient along the two circles defined by (@start_x, @start_y,
473  * @start_radius) and (@end_x, @end_y, @end_radius) is specified using the
474  * syntax
475  * <literallayout>-gtk-gradient (radial,
476  *                @start_x @start_y, @start_radius,
477  *                @end_x @end_y, @end_radius,
478  *                color-stop (@position, @color),
479  *                ...)</literallayout>
480  * where @start_radius and @end_radius are floating point numbers and
481  * the other parameters are as before.
482  * </para>
483  * <example>
484  * <title>A radial gradient</title>
485  * <inlinegraphic fileref="gradient3.png" format="PNG"/>
486  * <para>This gradient was specified with
487  * <literallayout>-gtk-gradient (radial,
488  *                center center, 0,
489  *                center center, 1,
490  *                from(&commat;yellow), to(&commat;green))</literallayout></para>
491  * </example>
492  * <example>
493  * <title>Another radial gradient</title>
494  * <inlinegraphic fileref="gradient4.png" format="PNG"/>
495  * <para>This gradient was specified with
496  * <literallayout>-gtk-gradient (radial,
497  *                0.4 0.4, 0.1,
498  *                0.6 0.6, 0.7,
499  *                color-stop (0, &num;f00),
500  *                color-stop (0.1, &num;a0f),
501  *                color-stop (0.2, &commat;yellow),
502  *                color-stop (1, &commat;green))</literallayout></para>
503  * </example>
504  * </refsect2>
505  * <refsect2 id="gtkcssprovider-slices">
506  * <title>Border images</title>
507  * <para>
508  * Images can be used in 'slices' for the purpose of creating scalable
509  * borders.
510  * </para>
511  * <inlinegraphic fileref="slices.png" format="PNG"/>
512  * <para>
513  * The syntax for specifying border images of this kind is:
514  * <literallayout>url(@path) @top @right @bottom @left [repeat|stretch]? [repeat|stretch]?</literallayout>
515  * The sizes of the 'cut off' portions are specified
516  * with the @top, @right, @bottom and @left parameters.
517  * The 'middle' sections can be repeated or stretched to create
518  * the desired effect, by adding the 'repeat' or 'stretch' options after
519  * the dimensions. If two options are specified, the first one affects
520  * the horizontal behaviour and the second one the vertical behaviour.
521  * If only one option is specified, it affects both.
522  * </para>
523  * <example>
524  * <title>A border image</title>
525  * <inlinegraphic fileref="border1.png" format="PNG"/>
526  * <para>This border image was specified with
527  * <literallayout>url("gradient1.png") 10 10 10 10</literallayout>
528  * </para>
529  * </example>
530  * <example>
531  * <title>A repeating border image</title>
532  * <inlinegraphic fileref="border2.png" format="PNG"/>
533  * <para>This border image was specified with
534  * <literallayout>url("gradient1.png") 10 10 10 10 repeat</literallayout>
535  * </para>
536  * </example>
537  * <example>
538  * <title>A stretched border image</title>
539  * <inlinegraphic fileref="border3.png" format="PNG"/>
540  * <para>This border image was specified with
541  * <literallayout>url("gradient1.png") 10 10 10 10 stretch</literallayout>
542  * </para>
543  * </example>
544  * </refsect2>
545  * <refsect2 id="gtkcssprovider-transitions">
546  * <para>Styles can specify transitions that will be used to create a gradual
547  * change in the appearance when a widget state changes. The following
548  * syntax is used to specify transitions:
549  * <literallayout>@duration [s|ms] [linear|ease|ease-in|ease-out|ease-in-out] [loop]?</literallayout>
550  * The @duration is the amount of time that the animation will take for
551  * a complete cycle from start to end. If the loop option is given, the
552  * animation will be repated until the state changes again.
553  * The option after the duration determines the transition function from a
554  * small set of predefined functions.
555  * <figure><title>Linear transition</title>
556  * <graphic fileref="linear.png" format="PNG"/>
557  * </figure>
558  * <figure><title>Ease transition</title>
559  * <graphic fileref="ease.png" format="PNG"/>
560  * </figure>
561  * <figure><title>Ease-in-out transition</title>
562  * <graphic fileref="ease-in-out.png" format="PNG"/>
563  * </figure>
564  * <figure><title>Ease-in transition</title>
565  * <graphic fileref="ease-in.png" format="PNG"/>
566  * </figure>
567  * <figure><title>Ease-out transition</title>
568  * <graphic fileref="ease-out.png" format="PNG"/>
569  * </figure>
570  * </para>
571  * </refsect2>
572  * <refsect2 id="gtkcssprovider-properties">
573  * <title>Supported properties</title>
574  * <para>
575  * Properties are the part that differ the most to common CSS,
576  * not all properties are supported (some are planned to be
577  * supported eventually, some others are meaningless or don't
578  * map intuitively in a widget based environment).
579  * </para>
580  * <para>
581  * There is also a difference in shorthand properties, for
582  * example in common CSS it is fine to define a font through
583  * the different @font-family, @font-style, @font-size
584  * properties, meanwhile in GTK+'s CSS only the canonical
585  * @font property is supported.
586  * </para>
587  * <para>
588  * The currently supported properties are:
589  * </para>
590  * <informaltable>
591  *   <tgroup cols="4">
592  *     <thead>
593  *       <row>
594  *         <entry>Property name</entry>
595  *         <entry>Syntax</entry>
596  *         <entry>Maps to</entry>
597  *         <entry>Examples</entry>
598  *       </row>
599  *     </thead>
600  *     <tbody>
601  *       <row>
602  *         <entry>engine</entry>
603  *         <entry>engine-name</entry>
604  *         <entry>#GtkThemingEngine</entry>
605  *         <entry>engine: clearlooks;
606  *  engine: none; /&ast; use the default (i.e. builtin) engine) &ast;/ </entry>
607  *       </row>
608  *       <row>
609  *         <entry>background-color</entry>
610  *         <entry morerows="2">color (see above)</entry>
611  *         <entry morerows="2">#GdkRGBA</entry>
612  *         <entry morerows="2"><literallayout>background-color: &num;fff;
613  * color: &amp;color1;
614  * background-color: shade (&amp;color1, 0.5);
615  * color: mix (&amp;color1, &num;f0f, 0.8);</literallayout>
616  *         </entry>
617  *       </row>
618  *       <row>
619  *         <entry>color</entry>
620  *       </row>
621  *       <row>
622  *         <entry>border-color</entry>
623  *       </row>
624  *       <row>
625  *         <entry>font</entry>
626  *         <entry>@family [@style] [@size]</entry>
627  *         <entry>#PangoFontDescription</entry>
628  *         <entry>font: Sans 15;</entry>
629  *       </row>
630  *       <row>
631  *         <entry>margin</entry>
632  *         <entry morerows="1"><literallayout>@width
633  * @vertical_width @horizontal_width
634  * @top_width @horizontal_width @bottom_width
635  * @top_width @right_width @bottom_width @left_width</literallayout>
636  *         </entry>
637  *         <entry morerows="1">#GtkBorder</entry>
638  *         <entry morerows="1"><literallayout>margin: 5;
639  * margin: 5 10;
640  * margin: 5 10 3;
641  * margin: 5 10 3 5;</literallayout>
642  *         </entry>
643  *       </row>
644  *       <row>
645  *         <entry>padding</entry>
646  *       </row>
647  *       <row>
648  *         <entry>background-image</entry>
649  *         <entry><literallayout>gradient (see above) or
650  * url(@path)</literallayout></entry>
651  *         <entry>#cairo_pattern_t</entry>
652  *         <entry><literallayout>-gtk-gradient (linear,
653  *                left top, right top,
654  *                from (&num;fff), to (&num;000));
655  * -gtk-gradient (linear, 0.0 0.5, 0.5 1.0,
656  *                from (&num;fff),
657  *                color-stop (0.5, &num;f00),
658  *                to (&num;000));
659  * -gtk-gradient (radial,
660  *                center center, 0.2,
661  *                center center, 0.8,
662  *                color-stop (0.0, &num;fff),
663  *                color-stop (1.0, &num;000));
664  * url ('background.png');</literallayout>
665  *         </entry>
666  *       </row>
667  *       <row>
668  *         <entry>border-width</entry>
669  *         <entry>integer</entry>
670  *         <entry>#gint</entry>
671  *         <entry>border-width: 5;</entry>
672  *       </row>
673  *       <row>
674  *         <entry>border-radius</entry>
675  *         <entry>integer</entry>
676  *         <entry>#gint</entry>
677  *         <entry>border-radius: 5;</entry>
678  *       </row>
679  *       <row>
680  *         <entry>border-style</entry>
681  *         <entry>[none|solid|inset|outset]</entry>
682  *         <entry>#GtkBorderStyle</entry>
683  *         <entry>border-style: solid;</entry>
684  *       </row>
685  *       <row>
686  *         <entry>border-image</entry>
687  *         <entry><literallayout>border image (see above)</literallayout></entry>
688  *         <entry>internal use only</entry>
689  *         <entry><literallayout>border-image: url("/path/to/image.png") 3 4 3 4 stretch;
690  * border-image: url("/path/to/image.png") 3 4 4 3 repeat stretch;</literallayout>
691  *         </entry>
692  *       </row>
693  *       <row>
694  *         <entry>transition</entry>
695  *         <entry>transition (see above)</entry>
696  *         <entry>internal use only</entry>
697  *         <entry><literallayout>transition: 150ms ease-in-out;
698  * transition: 1s linear loop;</literallayout>
699  *         </entry>
700  *       </row>
701  *       <row>
702  *         <entry>gtk-key-bindings</entry>
703  *         <entry>binding set name list</entry>
704  *         <entry>internal use only</entry>
705  *         <entry><literallayout>gtk-bindings: binding1, binding2, ...;</literallayout>
706  *         </entry>
707  *       </row>
708  *     </tbody>
709  *   </tgroup>
710  * </informaltable>
711  * <para>
712  * GtkThemingEngines can register their own, engine-specific style properties
713  * with the function gtk_theming_engine_register_property(). These properties
714  * can be set in CSS like other properties, using a name of the form
715  * <literallayout>-<replaceable>namespace</replaceable>-<replaceable>name</replaceable></literallayout>, where <replaceable>namespace</replaceable> is typically
716  * the name of the theming engine, and <replaceable>name</replaceable> is the
717  * name of the property. Style properties that have been registered by widgets
718  * using gtk_widget_class_install_style_property() can also be set in this
719  * way, using the widget class name for <replaceable>namespace</replaceable>.
720  * </para>
721  * <example>
722  * <title>Using engine-specific style properties</title>
723  * <programlisting>
724  * * {
725  *     engine: clearlooks;
726  *     border-radius: 4;
727  *     -GtkPaned-handle-size: 6;
728  *     -clearlooks-colorize-scrollbar: false;
729  * }
730  * </programlisting>
731  * </example>
732  * </refsect2>
733  */
734
735 typedef struct SelectorElement SelectorElement;
736 typedef struct SelectorPath SelectorPath;
737 typedef struct SelectorStyleInfo SelectorStyleInfo;
738 typedef struct _GtkCssScannerPrivate GtkCssScannerPrivate;
739 typedef enum SelectorElementType SelectorElementType;
740 typedef enum CombinatorType CombinatorType;
741 typedef enum ParserScope ParserScope;
742 typedef enum ParserSymbol ParserSymbol;
743
744 enum SelectorElementType {
745   SELECTOR_TYPE_NAME,
746   SELECTOR_NAME,
747   SELECTOR_GTYPE,
748   SELECTOR_REGION,
749   SELECTOR_CLASS,
750   SELECTOR_GLOB
751 };
752
753 enum CombinatorType {
754   COMBINATOR_DESCENDANT, /* No direct relation needed */
755   COMBINATOR_CHILD       /* Direct child */
756 };
757
758 struct SelectorElement
759 {
760   SelectorElementType elem_type;
761   CombinatorType combinator;
762
763   union
764   {
765     GQuark name;
766     GType type;
767
768     struct
769     {
770       GQuark name;
771       GtkRegionFlags flags;
772     } region;
773   };
774 };
775
776 struct SelectorPath
777 {
778   GSList *elements;
779   GtkStateFlags state;
780   guint ref_count;
781 };
782
783 struct SelectorStyleInfo
784 {
785   SelectorPath *path;
786   GHashTable *style;
787 };
788
789 struct _GtkCssScannerPrivate
790 {
791   GScanner *parent;
792   GFile *file;
793   GFile *base;
794   GSList *state;
795   GSList *cur_selectors;
796   GHashTable *cur_properties;
797 };
798
799 struct _GtkCssProviderPrivate
800 {
801   GScanner *scanner;
802
803   GHashTable *symbolic_colors;
804
805   GPtrArray *selectors_info;
806 };
807
808 enum ParserScope {
809   SCOPE_SELECTOR,
810   SCOPE_PSEUDO_CLASS,
811   SCOPE_NTH_CHILD,
812   SCOPE_DECLARATION,
813   SCOPE_VALUE,
814   SCOPE_BINDING_SET
815 };
816
817 /* Extend GtkStateType, since these
818  * values are also used as symbols
819  */
820 enum ParserSymbol {
821   /* Scope: pseudo-class */
822   SYMBOL_NTH_CHILD = GTK_STATE_FOCUSED + 1,
823   SYMBOL_FIRST_CHILD,
824   SYMBOL_LAST_CHILD,
825   SYMBOL_SORTED_CHILD,
826
827   /* Scope: nth-child */
828   SYMBOL_NTH_CHILD_EVEN,
829   SYMBOL_NTH_CHILD_ODD,
830   SYMBOL_NTH_CHILD_FIRST,
831   SYMBOL_NTH_CHILD_LAST
832 };
833
834 enum {
835   PARSING_ERROR,
836   LAST_SIGNAL
837 };
838
839 static guint css_provider_signals[LAST_SIGNAL] = { 0 };
840
841 static void gtk_css_provider_finalize (GObject *object);
842 static void gtk_css_style_provider_iface_init (GtkStyleProviderIface *iface);
843
844 static void scanner_apply_scope (GScanner    *scanner,
845                                  ParserScope  scope);
846 static gboolean
847 gtk_css_provider_load_internal (GtkCssProvider *css_provider,
848                                 GScanner       *scanner,
849                                 GFile          *file,
850                                 const char     *data,
851                                 gsize           length,
852                                 GError        **error);
853
854 GQuark
855 gtk_css_provider_error_quark (void)
856 {
857   return g_quark_from_static_string ("gtk-css-provider-error-quark");
858 }
859
860 G_DEFINE_TYPE_EXTENDED (GtkCssProvider, gtk_css_provider, G_TYPE_OBJECT, 0,
861                         G_IMPLEMENT_INTERFACE (GTK_TYPE_STYLE_PROVIDER,
862                                                gtk_css_style_provider_iface_init));
863
864 static void
865 gtk_css_provider_parsing_error (GtkCssProvider  *provider,
866                                 const gchar     *path,
867                                 guint            line,
868                                 guint            position,
869                                 const GError *   error)
870 {
871   /* Only emit a warning when we have no error handlers. This is our
872    * default handlers. And in this case erroneous CSS files are a bug
873    * and should be fixed.
874    * Note that these warnings can also be triggered by a broken theme
875    * that people installed from some weird location on the internets.
876    */
877   if (!g_signal_has_handler_pending (provider,
878                                      css_provider_signals[PARSING_ERROR],
879                                      0,
880                                      TRUE))
881     {
882       g_warning ("Theme parsing error: %s:%u:%u: %s", path ? path : "<unknown>", line, position, error->message);
883     }
884 }
885
886 static void
887 gtk_css_provider_class_init (GtkCssProviderClass *klass)
888 {
889   GObjectClass *object_class = G_OBJECT_CLASS (klass);
890
891   /**
892    * GtkCssProvider::parsing-error:
893    * @provider: the provider that had a parsing error
894    * @path: path to the parsed file or %NULL if the file cannot be
895    *   identified or the data was not loaded from a file
896    * @line: line in the file or data or 0 if unknown
897    * @position: offset into the current line or 0 if unknown or the
898    *   whole line is affected
899    * @error: The parsing error
900    *
901    * Signals that a parsing error occured. the @path, @line and @position
902    * describe the actual location of the error as accurately as possible.
903    *
904    * Parsing errors are never fatal, so the parsing will resume after
905    * the error. Errors may however cause parts of the given
906    * data or even all of it to not be parsed at all. So it is a useful idea
907    * to check that the parsing succeeds by connecting to this signal.
908    *
909    * Note that this signal may be emitted at any time as the css provider
910    * may opt to defer parsing parts or all of the input to a later time
911    * than when a loading function was called.
912    */
913   css_provider_signals[PARSING_ERROR] =
914     g_signal_new (I_("parsing-error"),
915                   G_TYPE_FROM_CLASS (object_class),
916                   G_SIGNAL_RUN_LAST,
917                   G_STRUCT_OFFSET (GtkCssProviderClass, parsing_error),
918                   NULL, NULL,
919                   _gtk_marshal_VOID__STRING_UINT_UINT_BOXED,
920                   G_TYPE_NONE, 4,
921                   G_TYPE_STRING, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_ERROR);
922
923   object_class->finalize = gtk_css_provider_finalize;
924
925   klass->parsing_error = gtk_css_provider_parsing_error;
926
927   g_type_class_add_private (object_class, sizeof (GtkCssProviderPrivate));
928 }
929
930 static void
931 gtk_css_provider_take_error_full (GtkCssProvider *provider,
932                                   GFile          *file,
933                                   guint           line,
934                                   guint           position,
935                                   GError         *error)
936 {
937   char *filename;
938
939   if (file)
940     filename = g_file_get_path (file);
941   else
942     filename = NULL;
943
944   g_signal_emit (provider, css_provider_signals[PARSING_ERROR], 0,
945                  filename, line, position, error);
946
947   g_free (filename);
948   g_error_free (error);
949 }
950
951 static SelectorPath *
952 selector_path_new (void)
953 {
954   SelectorPath *path;
955
956   path = g_slice_new0 (SelectorPath);
957   path->ref_count = 1;
958
959   return path;
960 }
961
962 static SelectorPath *
963 selector_path_ref (SelectorPath *path)
964 {
965   path->ref_count++;
966   return path;
967 }
968
969 static void
970 selector_path_unref (SelectorPath *path)
971 {
972   path->ref_count--;
973
974   if (path->ref_count > 0)
975     return;
976
977   while (path->elements)
978     {
979       g_slice_free (SelectorElement, path->elements->data);
980       path->elements = g_slist_delete_link (path->elements, path->elements);
981     }
982
983   g_slice_free (SelectorPath, path);
984 }
985
986 static void
987 selector_path_prepend_type (SelectorPath *path,
988                             const gchar  *type_name)
989 {
990   SelectorElement *elem;
991   GType type;
992
993   elem = g_slice_new (SelectorElement);
994   elem->combinator = COMBINATOR_DESCENDANT;
995   type = g_type_from_name (type_name);
996
997   if (type == G_TYPE_INVALID)
998     {
999       elem->elem_type = SELECTOR_TYPE_NAME;
1000       elem->name = g_quark_from_string (type_name);
1001     }
1002   else
1003     {
1004       elem->elem_type = SELECTOR_GTYPE;
1005       elem->type = type;
1006     }
1007
1008   path->elements = g_slist_prepend (path->elements, elem);
1009 }
1010
1011 static void
1012 selector_path_prepend_glob (SelectorPath *path)
1013 {
1014   SelectorElement *elem;
1015
1016   elem = g_slice_new (SelectorElement);
1017   elem->elem_type = SELECTOR_GLOB;
1018   elem->combinator = COMBINATOR_DESCENDANT;
1019
1020   path->elements = g_slist_prepend (path->elements, elem);
1021 }
1022
1023 static void
1024 selector_path_prepend_region (SelectorPath   *path,
1025                               const gchar    *name,
1026                               GtkRegionFlags  flags)
1027 {
1028   SelectorElement *elem;
1029
1030   elem = g_slice_new (SelectorElement);
1031   elem->combinator = COMBINATOR_DESCENDANT;
1032   elem->elem_type = SELECTOR_REGION;
1033
1034   elem->region.name = g_quark_from_string (name);
1035   elem->region.flags = flags;
1036
1037   path->elements = g_slist_prepend (path->elements, elem);
1038 }
1039
1040 static void
1041 selector_path_prepend_name (SelectorPath *path,
1042                             const gchar  *name)
1043 {
1044   SelectorElement *elem;
1045
1046   elem = g_slice_new (SelectorElement);
1047   elem->combinator = COMBINATOR_DESCENDANT;
1048   elem->elem_type = SELECTOR_NAME;
1049
1050   elem->name = g_quark_from_string (name);
1051
1052   path->elements = g_slist_prepend (path->elements, elem);
1053 }
1054
1055 static void
1056 selector_path_prepend_class (SelectorPath *path,
1057                              const gchar  *name)
1058 {
1059   SelectorElement *elem;
1060
1061   elem = g_slice_new (SelectorElement);
1062   elem->combinator = COMBINATOR_DESCENDANT;
1063   elem->elem_type = SELECTOR_CLASS;
1064
1065   elem->name = g_quark_from_string (name);
1066
1067   path->elements = g_slist_prepend (path->elements, elem);
1068 }
1069
1070 static void
1071 selector_path_prepend_combinator (SelectorPath   *path,
1072                                   CombinatorType  combinator)
1073 {
1074   SelectorElement *elem;
1075
1076   g_assert (path->elements != NULL);
1077
1078   /* It is actually stored in the last element */
1079   elem = path->elements->data;
1080   elem->combinator = combinator;
1081 }
1082
1083 static gint
1084 selector_path_depth (SelectorPath *path)
1085 {
1086   return g_slist_length (path->elements);
1087 }
1088
1089 static SelectorStyleInfo *
1090 selector_style_info_new (SelectorPath *path)
1091 {
1092   SelectorStyleInfo *info;
1093
1094   info = g_slice_new0 (SelectorStyleInfo);
1095   info->path = selector_path_ref (path);
1096
1097   return info;
1098 }
1099
1100 static void
1101 selector_style_info_free (SelectorStyleInfo *info)
1102 {
1103   if (info->style)
1104     g_hash_table_unref (info->style);
1105
1106   if (info->path)
1107     selector_path_unref (info->path);
1108
1109   g_slice_free (SelectorStyleInfo, info);
1110 }
1111
1112 static void
1113 selector_style_info_set_style (SelectorStyleInfo *info,
1114                                GHashTable        *style)
1115 {
1116   if (info->style)
1117     g_hash_table_unref (info->style);
1118
1119   if (style)
1120     info->style = g_hash_table_ref (style);
1121   else
1122     info->style = NULL;
1123 }
1124
1125 static void
1126 property_value_free (GValue *value)
1127 {
1128   if (G_IS_VALUE (value))
1129     g_value_unset (value);
1130
1131   g_slice_free (GValue, value);
1132 }
1133
1134 static void
1135 gtk_css_scanner_reset (GScanner *scanner)
1136 {
1137   GtkCssScannerPrivate *priv = scanner->user_data;
1138
1139   g_slist_free (priv->state);
1140   priv->state = NULL;
1141
1142   g_slist_foreach (priv->cur_selectors, (GFunc) selector_path_unref, NULL);
1143   g_slist_free (priv->cur_selectors);
1144   priv->cur_selectors = NULL;
1145
1146   if (priv->cur_properties)
1147     g_hash_table_unref (priv->cur_properties);
1148
1149   priv->cur_properties = g_hash_table_new_full (g_str_hash,
1150                                                 g_str_equal,
1151                                                 (GDestroyNotify) g_free,
1152                                                 (GDestroyNotify) property_value_free);
1153
1154   scanner_apply_scope (scanner, SCOPE_SELECTOR);
1155 }
1156
1157 static void
1158 gtk_css_scanner_destroy (GScanner *scanner)
1159 {
1160   GtkCssScannerPrivate *priv = scanner->user_data;
1161
1162   gtk_css_scanner_reset (scanner);
1163
1164   if (priv->file)
1165     g_object_unref (priv->file);
1166   g_hash_table_destroy (priv->cur_properties);
1167   g_slice_free (GtkCssScannerPrivate, priv);
1168   
1169   g_scanner_destroy (scanner);
1170 }
1171
1172 static GScanner *
1173 gtk_css_scanner_new (GScanner    *parent,
1174                      GFile       *file,
1175                      const gchar *data,
1176                      gsize        length)
1177 {
1178   GtkCssScannerPrivate *priv;
1179   GScanner *scanner;
1180
1181   scanner = g_scanner_new (NULL);
1182
1183   priv = scanner->user_data = g_slice_new0 (GtkCssScannerPrivate);
1184
1185   priv->parent = parent;
1186
1187   if (file)
1188     {
1189       priv->file = g_object_ref (file);
1190       priv->base = g_file_get_parent (file);
1191     }
1192   else
1193     {
1194       char *dir = g_get_current_dir ();
1195       priv->base = g_file_new_for_path (dir);
1196       g_free (dir);
1197     }
1198
1199   priv->cur_properties = g_hash_table_new_full (g_str_hash,
1200                                                 g_str_equal,
1201                                                 (GDestroyNotify) g_free,
1202                                                 (GDestroyNotify) property_value_free);
1203
1204   g_scanner_scope_add_symbol (scanner, SCOPE_PSEUDO_CLASS, "active", GUINT_TO_POINTER (GTK_STATE_ACTIVE));
1205   g_scanner_scope_add_symbol (scanner, SCOPE_PSEUDO_CLASS, "prelight", GUINT_TO_POINTER (GTK_STATE_PRELIGHT));
1206   g_scanner_scope_add_symbol (scanner, SCOPE_PSEUDO_CLASS, "hover", GUINT_TO_POINTER (GTK_STATE_PRELIGHT));
1207   g_scanner_scope_add_symbol (scanner, SCOPE_PSEUDO_CLASS, "selected", GUINT_TO_POINTER (GTK_STATE_SELECTED));
1208   g_scanner_scope_add_symbol (scanner, SCOPE_PSEUDO_CLASS, "insensitive", GUINT_TO_POINTER (GTK_STATE_INSENSITIVE));
1209   g_scanner_scope_add_symbol (scanner, SCOPE_PSEUDO_CLASS, "inconsistent", GUINT_TO_POINTER (GTK_STATE_INCONSISTENT));
1210   g_scanner_scope_add_symbol (scanner, SCOPE_PSEUDO_CLASS, "focused", GUINT_TO_POINTER (GTK_STATE_FOCUSED));
1211   g_scanner_scope_add_symbol (scanner, SCOPE_PSEUDO_CLASS, "focus", GUINT_TO_POINTER (GTK_STATE_FOCUSED));
1212
1213   g_scanner_scope_add_symbol (scanner, SCOPE_PSEUDO_CLASS, "nth-child", GUINT_TO_POINTER (SYMBOL_NTH_CHILD));
1214   g_scanner_scope_add_symbol (scanner, SCOPE_PSEUDO_CLASS, "first-child", GUINT_TO_POINTER (SYMBOL_FIRST_CHILD));
1215   g_scanner_scope_add_symbol (scanner, SCOPE_PSEUDO_CLASS, "last-child", GUINT_TO_POINTER (SYMBOL_LAST_CHILD));
1216   g_scanner_scope_add_symbol (scanner, SCOPE_PSEUDO_CLASS, "sorted", GUINT_TO_POINTER (SYMBOL_SORTED_CHILD));
1217
1218   g_scanner_scope_add_symbol (scanner, SCOPE_NTH_CHILD, "even", GUINT_TO_POINTER (SYMBOL_NTH_CHILD_EVEN));
1219   g_scanner_scope_add_symbol (scanner, SCOPE_NTH_CHILD, "odd", GUINT_TO_POINTER (SYMBOL_NTH_CHILD_ODD));
1220   g_scanner_scope_add_symbol (scanner, SCOPE_NTH_CHILD, "first", GUINT_TO_POINTER (SYMBOL_NTH_CHILD_FIRST));
1221   g_scanner_scope_add_symbol (scanner, SCOPE_NTH_CHILD, "last", GUINT_TO_POINTER (SYMBOL_NTH_CHILD_LAST));
1222
1223   scanner_apply_scope (scanner, SCOPE_SELECTOR);
1224
1225   if (length > G_MAXUINT32)
1226     g_warning ("CSS file too large, truncating");
1227
1228   g_scanner_input_text (scanner, data, length);
1229
1230   return scanner;
1231 }
1232
1233 static GFile *
1234 gtk_css_scanner_get_base_url (GScanner *scanner)
1235 {
1236   GtkCssScannerPrivate *priv = scanner->user_data;
1237
1238   return priv->base;
1239 }
1240
1241 static gboolean
1242 gtk_css_scanner_would_recurse (GScanner *scanner,
1243                                GFile    *file)
1244 {
1245   while (scanner)
1246     {
1247       GtkCssScannerPrivate *priv = scanner->user_data;
1248
1249       if (priv->file && g_file_equal (priv->file, file))
1250         return TRUE;
1251
1252       scanner = priv->parent;
1253     }
1254
1255   return FALSE;
1256 }
1257
1258 static void
1259 gtk_css_provider_init (GtkCssProvider *css_provider)
1260 {
1261   GtkCssProviderPrivate *priv;
1262
1263   priv = css_provider->priv = G_TYPE_INSTANCE_GET_PRIVATE (css_provider,
1264                                                            GTK_TYPE_CSS_PROVIDER,
1265                                                            GtkCssProviderPrivate);
1266
1267   priv->selectors_info = g_ptr_array_new_with_free_func ((GDestroyNotify) selector_style_info_free);
1268
1269   priv->symbolic_colors = g_hash_table_new_full (g_str_hash, g_str_equal,
1270                                                  (GDestroyNotify) g_free,
1271                                                  (GDestroyNotify) gtk_symbolic_color_unref);
1272 }
1273
1274 typedef struct ComparePathData ComparePathData;
1275
1276 struct ComparePathData
1277 {
1278   guint64 score;
1279   SelectorPath *path;
1280   GSList *iter;
1281 };
1282
1283 static gboolean
1284 compare_selector_element (GtkWidgetPath   *path,
1285                           guint            index,
1286                           SelectorElement *elem,
1287                           guint8          *score)
1288 {
1289   *score = 0;
1290
1291   if (elem->elem_type == SELECTOR_TYPE_NAME)
1292     {
1293       const gchar *type_name;
1294       GType resolved_type;
1295
1296       /* Resolve the type name */
1297       type_name = g_quark_to_string (elem->name);
1298       resolved_type = g_type_from_name (type_name);
1299
1300       if (resolved_type == G_TYPE_INVALID)
1301         {
1302           /* Type couldn't be resolved, so the selector
1303            * clearly doesn't affect the given widget path
1304            */
1305           return FALSE;
1306         }
1307
1308       elem->elem_type = SELECTOR_GTYPE;
1309       elem->type = resolved_type;
1310     }
1311
1312   if (elem->elem_type == SELECTOR_GTYPE)
1313     {
1314       GType type;
1315
1316       type = gtk_widget_path_iter_get_object_type (path, index);
1317
1318       if (!g_type_is_a (type, elem->type))
1319         return FALSE;
1320
1321       if (type == elem->type)
1322         *score |= 0xF;
1323       else
1324         {
1325           guint diff = g_type_depth (type) - g_type_depth (elem->type);
1326
1327           if (G_UNLIKELY (diff > 0xE))
1328             {
1329               g_warning ("Hierarchy is higher than expected.");
1330               diff = 0xE;
1331             }
1332           
1333           *score = 0XF - diff;
1334         }
1335
1336       return TRUE;
1337     }
1338   else if (elem->elem_type == SELECTOR_REGION)
1339     {
1340       GtkRegionFlags flags;
1341
1342       if (!gtk_widget_path_iter_has_qregion (path, index,
1343                                              elem->region.name,
1344                                              &flags))
1345         return FALSE;
1346
1347       if (elem->region.flags != 0 &&
1348           (flags & elem->region.flags) == 0)
1349         return FALSE;
1350
1351       *score = 0xF;
1352       return TRUE;
1353     }
1354   else if (elem->elem_type == SELECTOR_GLOB)
1355     {
1356       /* Treat as lowest matching type */
1357       *score = 1;
1358       return TRUE;
1359     }
1360   else if (elem->elem_type == SELECTOR_NAME)
1361     {
1362       if (!gtk_widget_path_iter_has_qname (path, index, elem->name))
1363         return FALSE;
1364
1365       *score = 0xF;
1366       return TRUE;
1367     }
1368   else if (elem->elem_type == SELECTOR_CLASS)
1369     {
1370       if (!gtk_widget_path_iter_has_qclass (path, index, elem->name))
1371         return FALSE;
1372
1373       *score = 0xF;
1374       return TRUE;
1375     }
1376
1377   return FALSE;
1378 }
1379
1380 static guint64
1381 compare_selector (GtkWidgetPath *path,
1382                   SelectorPath  *selector)
1383 {
1384   GSList *elements = selector->elements;
1385   gboolean match = TRUE, first = TRUE, first_match = FALSE;
1386   guint64 score = 0;
1387   gint i;
1388
1389   i = gtk_widget_path_length (path) - 1;
1390
1391   while (elements && match && i >= 0)
1392     {
1393       SelectorElement *elem;
1394       guint8 elem_score;
1395
1396       elem = elements->data;
1397
1398       match = compare_selector_element (path, i, elem, &elem_score);
1399
1400       if (match && first)
1401         first_match = TRUE;
1402
1403       /* Only move on to the next index if there is no match
1404        * with the current element (whether to continue or not
1405        * handled right after in the combinator check), or a
1406        * GType or glob has just been matched.
1407        *
1408        * Region and widget names do not trigger this because
1409        * the next element in the selector path could also be
1410        * related to the same index.
1411        */
1412       if (!match ||
1413           (elem->elem_type == SELECTOR_GTYPE ||
1414            elem->elem_type == SELECTOR_GLOB))
1415         i--;
1416
1417       if (!match &&
1418           elem->elem_type != SELECTOR_TYPE_NAME &&
1419           elem->combinator == COMBINATOR_DESCENDANT)
1420         {
1421           /* With descendant combinators there may
1422            * be intermediate chidren in the hierarchy
1423            */
1424           match = TRUE;
1425         }
1426       else if (match)
1427         elements = elements->next;
1428
1429       if (match)
1430         {
1431           /* Only 4 bits are actually used */
1432           score <<= 4;
1433           score |= elem_score;
1434         }
1435
1436       first = FALSE;
1437     }
1438
1439   /* If there are pending selector
1440    * elements to compare, it's not
1441    * a match.
1442    */
1443   if (elements)
1444     match = FALSE;
1445
1446   if (!match)
1447     score = 0;
1448   else if (first_match)
1449     {
1450       /* Assign more weight to these selectors
1451        * that matched right from the first element.
1452        */
1453       score <<= 4;
1454     }
1455
1456   return score;
1457 }
1458
1459 typedef struct StylePriorityInfo StylePriorityInfo;
1460
1461 struct StylePriorityInfo
1462 {
1463   guint64 score;
1464   GHashTable *style;
1465   GtkStateFlags state;
1466 };
1467
1468 static GArray *
1469 css_provider_get_selectors (GtkCssProvider *css_provider,
1470                             GtkWidgetPath  *path)
1471 {
1472   GtkCssProviderPrivate *priv;
1473   GArray *priority_info;
1474   guint i, j;
1475
1476   priv = css_provider->priv;
1477   priority_info = g_array_new (FALSE, FALSE, sizeof (StylePriorityInfo));
1478
1479   for (i = 0; i < priv->selectors_info->len; i++)
1480     {
1481       SelectorStyleInfo *info;
1482       StylePriorityInfo new;
1483       gboolean added = FALSE;
1484       guint64 score;
1485
1486       info = g_ptr_array_index (priv->selectors_info, i);
1487       score = compare_selector (path, info->path);
1488
1489       if (score <= 0)
1490         continue;
1491
1492       new.score = score;
1493       new.style = info->style;
1494       new.state = info->path->state;
1495
1496       for (j = 0; j < priority_info->len; j++)
1497         {
1498           StylePriorityInfo *cur;
1499
1500           cur = &g_array_index (priority_info, StylePriorityInfo, j);
1501
1502           if (cur->score > new.score)
1503             {
1504               g_array_insert_val (priority_info, j, new);
1505               added = TRUE;
1506               break;
1507             }
1508         }
1509
1510       if (!added)
1511         g_array_append_val (priority_info, new);
1512     }
1513
1514   return priority_info;
1515 }
1516
1517 static void
1518 css_provider_dump_symbolic_colors (GtkCssProvider     *css_provider,
1519                                    GtkStyleProperties *props)
1520 {
1521   GtkCssProviderPrivate *priv;
1522   GHashTableIter iter;
1523   gpointer key, value;
1524
1525   priv = css_provider->priv;
1526   g_hash_table_iter_init (&iter, priv->symbolic_colors);
1527
1528   while (g_hash_table_iter_next (&iter, &key, &value))
1529     {
1530       const gchar *name;
1531       GtkSymbolicColor *color;
1532
1533       name = key;
1534       color = value;
1535
1536       gtk_style_properties_map_color (props, name, color);
1537     }
1538 }
1539
1540 static GtkStyleProperties *
1541 gtk_css_provider_get_style (GtkStyleProvider *provider,
1542                             GtkWidgetPath    *path)
1543 {
1544   GtkCssProvider *css_provider;
1545   GtkStyleProperties *props;
1546   GArray *priority_info;
1547   guint i;
1548
1549   css_provider = GTK_CSS_PROVIDER (provider);
1550   props = gtk_style_properties_new ();
1551
1552   css_provider_dump_symbolic_colors (css_provider, props);
1553   priority_info = css_provider_get_selectors (css_provider, path);
1554
1555   for (i = 0; i < priority_info->len; i++)
1556     {
1557       StylePriorityInfo *info;
1558       GHashTableIter iter;
1559       gpointer key, value;
1560
1561       info = &g_array_index (priority_info, StylePriorityInfo, i);
1562       g_hash_table_iter_init (&iter, info->style);
1563
1564       while (g_hash_table_iter_next (&iter, &key, &value))
1565         {
1566           gchar *prop = key;
1567
1568           /* Properties starting with '-' may be both widget style properties
1569            * or custom properties from the theming engine, so check whether
1570            * the type is registered or not.
1571            */
1572           if (prop[0] == '-' &&
1573               !gtk_style_properties_lookup_property (prop, NULL, NULL))
1574             continue;
1575
1576           gtk_style_properties_set_property (props, key, info->state, value);
1577         }
1578     }
1579
1580   g_array_free (priority_info, TRUE);
1581
1582   return props;
1583 }
1584
1585 static gboolean
1586 gtk_css_provider_get_style_property (GtkStyleProvider *provider,
1587                                      GtkWidgetPath    *path,
1588                                      GtkStateFlags     state,
1589                                      GParamSpec       *pspec,
1590                                      GValue           *value)
1591 {
1592   GArray *priority_info;
1593   gboolean found = FALSE;
1594   gchar *prop_name;
1595   gint i;
1596
1597   prop_name = g_strdup_printf ("-%s-%s",
1598                                g_type_name (pspec->owner_type),
1599                                pspec->name);
1600
1601   priority_info = css_provider_get_selectors (GTK_CSS_PROVIDER (provider), path);
1602
1603   for (i = priority_info->len - 1; i >= 0; i--)
1604     {
1605       StylePriorityInfo *info;
1606       GValue *val;
1607
1608       info = &g_array_index (priority_info, StylePriorityInfo, i);
1609       val = g_hash_table_lookup (info->style, prop_name);
1610
1611       if (val &&
1612           (info->state == 0 ||
1613            info->state == state ||
1614            ((info->state & state) != 0 &&
1615             (info->state & ~(state)) == 0)))
1616         {
1617           GError *error = NULL;
1618
1619           found = _gtk_css_value_from_string (value,
1620                                               NULL,
1621                                               g_value_get_string (val),
1622                                               &error);
1623
1624           if (found)
1625             break;
1626           
1627           /* error location should be _way_ better */
1628           gtk_css_provider_take_error_full (GTK_CSS_PROVIDER (provider),
1629                                             NULL,
1630                                             0, 0,
1631                                             error);
1632         }
1633     }
1634
1635   g_array_free (priority_info, TRUE);
1636   g_free (prop_name);
1637
1638   return found;
1639 }
1640
1641 static void
1642 gtk_css_style_provider_iface_init (GtkStyleProviderIface *iface)
1643 {
1644   iface->get_style = gtk_css_provider_get_style;
1645   iface->get_style_property = gtk_css_provider_get_style_property;
1646 }
1647
1648 static void
1649 gtk_css_provider_finalize (GObject *object)
1650 {
1651   GtkCssProvider *css_provider;
1652   GtkCssProviderPrivate *priv;
1653
1654   css_provider = GTK_CSS_PROVIDER (object);
1655   priv = css_provider->priv;
1656
1657   g_ptr_array_free (priv->selectors_info, TRUE);
1658
1659   if (priv->symbolic_colors)
1660     g_hash_table_destroy (priv->symbolic_colors);
1661
1662   G_OBJECT_CLASS (gtk_css_provider_parent_class)->finalize (object);
1663 }
1664
1665 /**
1666  * gtk_css_provider_new:
1667  *
1668  * Returns a newly created #GtkCssProvider.
1669  *
1670  * Returns: A new #GtkCssProvider
1671  **/
1672 GtkCssProvider *
1673 gtk_css_provider_new (void)
1674 {
1675   return g_object_new (GTK_TYPE_CSS_PROVIDER, NULL);
1676 }
1677
1678 static void
1679 gtk_css_provider_take_error (GtkCssProvider *provider,
1680                              GScanner       *scanner,
1681                              GError         *error)
1682 {
1683   GtkCssScannerPrivate *priv = scanner->user_data;
1684
1685   gtk_css_provider_take_error_full (provider,
1686                                     priv->file,
1687                                     scanner->line,
1688                                     scanner->position,
1689                                     error);
1690 }
1691
1692 static void
1693 gtk_css_provider_error_literal (GtkCssProvider *provider,
1694                                 GScanner       *scanner,
1695                                 GQuark          domain,
1696                                 gint            code,
1697                                 const char     *message)
1698 {
1699   gtk_css_provider_take_error (provider,
1700                                scanner,
1701                                g_error_new_literal (domain, code, message));
1702 }
1703
1704 static void
1705 gtk_css_provider_error (GtkCssProvider *provider,
1706                         GScanner       *scanner,
1707                         GQuark          domain,
1708                         gint            code,
1709                         const char     *format,
1710                         ...)  G_GNUC_PRINTF (5, 6);
1711 static void
1712 gtk_css_provider_error (GtkCssProvider *provider,
1713                         GScanner       *scanner,
1714                         GQuark          domain,
1715                         gint            code,
1716                         const char     *format,
1717                         ...)
1718 {
1719   GError *error;
1720   va_list args;
1721
1722   va_start (args, format);
1723   error = g_error_new_valist (domain, code, format, args);
1724   va_end (args);
1725
1726   gtk_css_provider_take_error (provider, scanner, error);
1727 }
1728
1729 static void
1730 gtk_css_provider_invalid_token (GtkCssProvider *provider,
1731                                 GScanner       *scanner,
1732                                 const char     *expected)
1733 {
1734   gtk_css_provider_error (provider,
1735                           scanner,
1736                           GTK_CSS_PROVIDER_ERROR,
1737                           GTK_CSS_PROVIDER_ERROR_SYNTAX,
1738                           "expected a valid %s", expected);
1739 }
1740
1741 static void
1742 scanner_apply_scope (GScanner    *scanner,
1743                      ParserScope  scope)
1744 {
1745   g_scanner_set_scope (scanner, scope);
1746
1747   if (scope == SCOPE_VALUE)
1748     {
1749       scanner->config->cset_identifier_first = G_CSET_a_2_z G_CSET_A_2_Z G_CSET_DIGITS "@#-_\"'";
1750       scanner->config->cset_identifier_nth = G_CSET_a_2_z G_CSET_A_2_Z G_CSET_DIGITS "@#-_ +(),.%\t\n'/\"";
1751       scanner->config->scan_identifier_1char = TRUE;
1752       scanner->config->scan_string_sq = FALSE;
1753       scanner->config->scan_string_dq = FALSE;
1754     }
1755   else if (scope == SCOPE_BINDING_SET)
1756     {
1757       scanner->config->cset_identifier_first = G_CSET_a_2_z G_CSET_A_2_Z G_CSET_DIGITS "@#-_";
1758       scanner->config->cset_identifier_nth = G_CSET_a_2_z G_CSET_A_2_Z G_CSET_DIGITS "@#-_ +(){}<>,.%\t\n'/\"";
1759       scanner->config->scan_identifier_1char = TRUE;
1760       scanner->config->scan_string_sq = TRUE;
1761       scanner->config->scan_string_dq = TRUE;
1762     }
1763   else if (scope == SCOPE_SELECTOR)
1764     {
1765       scanner->config->cset_identifier_first = G_CSET_a_2_z G_CSET_A_2_Z "*@";
1766       scanner->config->cset_identifier_nth = G_CSET_a_2_z G_CSET_A_2_Z G_CSET_DIGITS "-_#.";
1767       scanner->config->scan_identifier_1char = TRUE;
1768       scanner->config->scan_string_sq = TRUE;
1769       scanner->config->scan_string_dq = TRUE;
1770     }
1771   else if (scope == SCOPE_PSEUDO_CLASS ||
1772            scope == SCOPE_NTH_CHILD ||
1773            scope == SCOPE_DECLARATION)
1774     {
1775       scanner->config->cset_identifier_first = G_CSET_a_2_z G_CSET_A_2_Z "-_";
1776       scanner->config->cset_identifier_nth = G_CSET_a_2_z G_CSET_A_2_Z G_CSET_DIGITS "-_";
1777       scanner->config->scan_identifier_1char = FALSE;
1778       scanner->config->scan_string_sq = TRUE;
1779       scanner->config->scan_string_dq = TRUE;
1780     }
1781   else
1782     g_assert_not_reached ();
1783
1784   scanner->config->scan_float = FALSE;
1785   scanner->config->cpair_comment_single = NULL;
1786 }
1787
1788 static void
1789 gtk_css_scanner_push_scope (GScanner    *scanner,
1790                             ParserScope  scope)
1791 {
1792   GtkCssScannerPrivate *priv;
1793
1794   priv = scanner->user_data;
1795   priv->state = g_slist_prepend (priv->state, GUINT_TO_POINTER (scope));
1796
1797   scanner_apply_scope (scanner, scope);
1798 }
1799
1800 static void
1801 gtk_css_scanner_pop_scope (GScanner *scanner)
1802 {
1803   GtkCssScannerPrivate *priv;
1804   ParserScope scope = SCOPE_SELECTOR;
1805
1806   priv = scanner->user_data;
1807
1808   if (!priv->state)
1809     {
1810       g_warning ("Push/pop calls to parser scope aren't paired");
1811       scanner_apply_scope (scanner, SCOPE_SELECTOR);
1812       return;
1813     }
1814
1815   priv->state = g_slist_delete_link (priv->state, priv->state);
1816
1817   /* Fetch new scope */
1818   if (priv->state)
1819     scope = GPOINTER_TO_INT (priv->state->data);
1820
1821   scanner_apply_scope (scanner, scope);
1822 }
1823
1824 static void
1825 css_provider_commit (GtkCssProvider *css_provider,
1826                      GScanner       *scanner)
1827 {
1828   GtkCssScannerPrivate *scanner_priv;
1829   GtkCssProviderPrivate *priv;
1830   GSList *l;
1831
1832   priv = css_provider->priv;
1833   scanner_priv = scanner->user_data;
1834
1835   l = scanner_priv->cur_selectors;
1836
1837   if (g_hash_table_size (scanner_priv->cur_properties) == 0)
1838     return;
1839
1840   while (l)
1841     {
1842       SelectorPath *path = l->data;
1843       SelectorStyleInfo *info;
1844
1845       info = selector_style_info_new (path);
1846       selector_style_info_set_style (info, scanner_priv->cur_properties);
1847
1848       g_ptr_array_add (priv->selectors_info, info);
1849       l = l->next;
1850     }
1851 }
1852
1853 static GTokenType
1854 parse_nth_child (GtkCssProvider *css_provider,
1855                  GScanner       *scanner,
1856                  GtkRegionFlags *flags)
1857 {
1858   ParserSymbol symbol;
1859
1860   g_scanner_get_next_token (scanner);
1861
1862   if (scanner->token != G_TOKEN_SYMBOL)
1863     return G_TOKEN_SYMBOL;
1864
1865   symbol = GPOINTER_TO_INT (scanner->value.v_symbol);
1866
1867   if (symbol == SYMBOL_NTH_CHILD)
1868     {
1869       g_scanner_get_next_token (scanner);
1870
1871       if (scanner->token != G_TOKEN_LEFT_PAREN)
1872         return G_TOKEN_LEFT_PAREN;
1873
1874       gtk_css_scanner_push_scope (scanner, SCOPE_NTH_CHILD);
1875       g_scanner_get_next_token (scanner);
1876
1877       if (scanner->token != G_TOKEN_SYMBOL)
1878         return G_TOKEN_SYMBOL;
1879
1880       symbol = GPOINTER_TO_INT (scanner->value.v_symbol);
1881
1882       switch (symbol)
1883         {
1884         case SYMBOL_NTH_CHILD_EVEN:
1885           *flags = GTK_REGION_EVEN;
1886           break;
1887         case SYMBOL_NTH_CHILD_ODD:
1888           *flags = GTK_REGION_ODD;
1889           break;
1890         case SYMBOL_NTH_CHILD_FIRST:
1891           *flags = GTK_REGION_FIRST;
1892           break;
1893         case SYMBOL_NTH_CHILD_LAST:
1894           *flags = GTK_REGION_LAST;
1895           break;
1896         default:
1897           break;
1898         }
1899
1900       g_scanner_get_next_token (scanner);
1901
1902       if (scanner->token != G_TOKEN_RIGHT_PAREN)
1903         return G_TOKEN_RIGHT_PAREN;
1904
1905       gtk_css_scanner_pop_scope (scanner);
1906     }
1907   else if (symbol == SYMBOL_FIRST_CHILD)
1908     *flags = GTK_REGION_FIRST;
1909   else if (symbol == SYMBOL_LAST_CHILD)
1910     *flags = GTK_REGION_LAST;
1911   else if (symbol == SYMBOL_SORTED_CHILD)
1912     *flags = GTK_REGION_SORTED;
1913   else
1914     {
1915       *flags = 0;
1916       return G_TOKEN_SYMBOL;
1917     }
1918
1919   return G_TOKEN_NONE;
1920 }
1921
1922 static GTokenType
1923 parse_pseudo_class (GtkCssProvider *css_provider,
1924                     GScanner       *scanner,
1925                     SelectorPath   *selector)
1926 {
1927   GtkStateType state;
1928
1929   g_scanner_get_next_token (scanner);
1930
1931   if (scanner->token != G_TOKEN_SYMBOL)
1932     return G_TOKEN_SYMBOL;
1933
1934   state = GPOINTER_TO_INT (scanner->value.v_symbol);
1935
1936   switch (state)
1937     {
1938     case GTK_STATE_ACTIVE:
1939       selector->state |= GTK_STATE_FLAG_ACTIVE;
1940       break;
1941     case GTK_STATE_PRELIGHT:
1942       selector->state |= GTK_STATE_FLAG_PRELIGHT;
1943       break;
1944     case GTK_STATE_SELECTED:
1945       selector->state |= GTK_STATE_FLAG_SELECTED;
1946       break;
1947     case GTK_STATE_INSENSITIVE:
1948       selector->state |= GTK_STATE_FLAG_INSENSITIVE;
1949       break;
1950     case GTK_STATE_INCONSISTENT:
1951       selector->state |= GTK_STATE_FLAG_INCONSISTENT;
1952       break;
1953     case GTK_STATE_FOCUSED:
1954       selector->state |= GTK_STATE_FLAG_FOCUSED;
1955       break;
1956     default:
1957       return G_TOKEN_SYMBOL;
1958     }
1959
1960   return G_TOKEN_NONE;
1961 }
1962
1963 /* Parses a number of concatenated classes */
1964 static void
1965 parse_classes (SelectorPath   *path,
1966                const gchar    *str)
1967 {
1968   gchar *pos;
1969
1970   if ((pos = strchr (str, '.')) != NULL)
1971     {
1972       /* Leave the last class to the call after the loop */
1973       while (pos)
1974         {
1975           *pos = '\0';
1976           selector_path_prepend_class (path, str);
1977
1978           str = pos + 1;
1979           pos = strchr (str, '.');
1980         }
1981     }
1982
1983   selector_path_prepend_class (path, str);
1984 }
1985
1986 static gboolean
1987 is_widget_class_name (const gchar *str)
1988 {
1989   /* Do a pretty lax check here, not all
1990    * widget class names contain only CamelCase
1991    * (gtkmm widgets don't), but at least part of
1992    * the name will be CamelCase, so check for
1993    * the first uppercase char
1994    */
1995   while (*str)
1996     {
1997       if (g_ascii_isupper (*str))
1998         return TRUE;
1999
2000       str++;
2001     }
2002
2003   return FALSE;
2004 }
2005
2006 static GTokenType
2007 parse_selector (GtkCssProvider  *css_provider,
2008                 GScanner        *scanner,
2009                 SelectorPath   **selector_out)
2010 {
2011   SelectorPath *path;
2012
2013   path = selector_path_new ();
2014   *selector_out = path;
2015
2016   if (scanner->token != ':' &&
2017       scanner->token != '#' &&
2018       scanner->token != '.' &&
2019       scanner->token != G_TOKEN_IDENTIFIER)
2020     return G_TOKEN_IDENTIFIER;
2021
2022   while (scanner->token == '#' ||
2023          scanner->token == '.' ||
2024          scanner->token == G_TOKEN_IDENTIFIER)
2025     {
2026       if (scanner->token == '#' ||
2027           scanner->token == '.')
2028         {
2029           gboolean is_class;
2030           gchar *pos;
2031
2032           is_class = (scanner->token == '.');
2033
2034           g_scanner_get_next_token (scanner);
2035
2036           if (scanner->token != G_TOKEN_IDENTIFIER)
2037             return G_TOKEN_IDENTIFIER;
2038
2039           selector_path_prepend_glob (path);
2040           selector_path_prepend_combinator (path, COMBINATOR_CHILD);
2041
2042           if (is_class)
2043             parse_classes (path, scanner->value.v_identifier);
2044           else
2045             {
2046               if ((pos = strchr (scanner->value.v_identifier, '.')) != NULL)
2047                 *pos = '\0';
2048
2049               selector_path_prepend_name (path, scanner->value.v_identifier);
2050
2051               /* Parse any remaining classes */
2052               if (pos)
2053                 parse_classes (path, pos + 1);
2054             }
2055         }
2056       else if (is_widget_class_name (scanner->value.v_identifier))
2057         {
2058           gchar *pos;
2059
2060           if ((pos = strchr (scanner->value.v_identifier, '#')) != NULL ||
2061               (pos = strchr (scanner->value.v_identifier, '.')) != NULL)
2062             {
2063               gchar *type_name, *name;
2064               gboolean is_class;
2065
2066               is_class = (*pos == '.');
2067
2068               /* Widget type and name/class put together */
2069               name = pos + 1;
2070               *pos = '\0';
2071               type_name = scanner->value.v_identifier;
2072
2073               selector_path_prepend_type (path, type_name);
2074
2075               /* This is only so there is a direct relationship
2076                * between widget type and its name.
2077                */
2078               selector_path_prepend_combinator (path, COMBINATOR_CHILD);
2079
2080               if (is_class)
2081                 parse_classes (path, name);
2082               else
2083                 {
2084                   if ((pos = strchr (name, '.')) != NULL)
2085                     *pos = '\0';
2086
2087                   selector_path_prepend_name (path, name);
2088
2089                   /* Parse any remaining classes */
2090                   if (pos)
2091                     parse_classes (path, pos + 1);
2092                 }
2093             }
2094           else
2095             selector_path_prepend_type (path, scanner->value.v_identifier);
2096         }
2097       else if (_gtk_style_context_check_region_name (scanner->value.v_identifier))
2098         {
2099           GtkRegionFlags flags = 0;
2100           gchar *region_name;
2101
2102           region_name = g_strdup (scanner->value.v_identifier);
2103
2104           if (g_scanner_peek_next_token (scanner) == ':')
2105             {
2106               ParserSymbol symbol;
2107
2108               g_scanner_get_next_token (scanner);
2109               gtk_css_scanner_push_scope (scanner, SCOPE_PSEUDO_CLASS);
2110
2111               /* Check for the next token being nth-child, parse in that
2112                * case, and fallback into common state parsing if not.
2113                */
2114               if (g_scanner_peek_next_token (scanner) != G_TOKEN_SYMBOL)
2115                 return G_TOKEN_SYMBOL;
2116
2117               symbol = GPOINTER_TO_INT (scanner->next_value.v_symbol);
2118
2119               if (symbol == SYMBOL_FIRST_CHILD ||
2120                   symbol == SYMBOL_LAST_CHILD ||
2121                   symbol == SYMBOL_NTH_CHILD ||
2122                   symbol == SYMBOL_SORTED_CHILD)
2123                 {
2124                   GTokenType token;
2125
2126                   if ((token = parse_nth_child (css_provider, scanner, &flags)) != G_TOKEN_NONE)
2127                     return token;
2128
2129                   gtk_css_scanner_pop_scope (scanner);
2130                 }
2131               else
2132                 {
2133                   gtk_css_scanner_pop_scope (scanner);
2134                   selector_path_prepend_region (path, region_name, 0);
2135                   g_free (region_name);
2136                   break;
2137                 }
2138             }
2139
2140           selector_path_prepend_region (path, region_name, flags);
2141           g_free (region_name);
2142         }
2143       else if (scanner->value.v_identifier[0] == '*')
2144         selector_path_prepend_glob (path);
2145       else
2146         return G_TOKEN_IDENTIFIER;
2147
2148       g_scanner_get_next_token (scanner);
2149
2150       if (scanner->token == '>')
2151         {
2152           selector_path_prepend_combinator (path, COMBINATOR_CHILD);
2153           g_scanner_get_next_token (scanner);
2154         }
2155     }
2156
2157   if (scanner->token == ':')
2158     {
2159       /* Add glob selector if path is empty */
2160       if (selector_path_depth (path) == 0)
2161         selector_path_prepend_glob (path);
2162
2163       gtk_css_scanner_push_scope (scanner, SCOPE_PSEUDO_CLASS);
2164
2165       while (scanner->token == ':')
2166         {
2167           GTokenType token;
2168
2169           if ((token = parse_pseudo_class (css_provider, scanner, path)) != G_TOKEN_NONE)
2170             return token;
2171
2172           g_scanner_get_next_token (scanner);
2173         }
2174
2175       gtk_css_scanner_pop_scope (scanner);
2176     }
2177
2178   return G_TOKEN_NONE;
2179 }
2180
2181 static void
2182 resolve_binding_sets (const gchar *value_str,
2183                       GValue      *value)
2184 {
2185   GPtrArray *array;
2186   gchar **bindings, **str;
2187
2188   bindings = g_strsplit (value_str, ",", -1);
2189   array = g_ptr_array_new ();
2190
2191   for (str = bindings; *str; str++)
2192     {
2193       GtkBindingSet *binding_set;
2194
2195       binding_set = gtk_binding_set_find (g_strstrip (*str));
2196
2197       if (!binding_set)
2198         continue;
2199
2200       g_ptr_array_add (array, binding_set);
2201     }
2202
2203   g_value_take_boxed (value, array);
2204   g_strfreev (bindings);
2205 }
2206
2207 static GTokenType
2208 parse_rule (GtkCssProvider  *css_provider,
2209             GScanner        *scanner)
2210 {
2211   GtkCssScannerPrivate *priv;
2212   GTokenType expected_token;
2213   SelectorPath *selector;
2214
2215   priv = scanner->user_data;
2216
2217   gtk_css_scanner_push_scope (scanner, SCOPE_SELECTOR);
2218
2219   /* Handle directives */
2220   if (scanner->token == G_TOKEN_IDENTIFIER &&
2221       scanner->value.v_identifier[0] == '@')
2222     {
2223       gchar *directive;
2224
2225       directive = &scanner->value.v_identifier[1];
2226
2227       if (strcmp (directive, "define-color") == 0)
2228         {
2229           GtkSymbolicColor *color;
2230           gchar *color_name, *color_str;
2231           GError *error = NULL;
2232
2233           /* Directive is a color mapping */
2234           g_scanner_get_next_token (scanner);
2235
2236           if (scanner->token != G_TOKEN_IDENTIFIER)
2237             {
2238               gtk_css_provider_invalid_token (css_provider, scanner, "Color name");
2239               return G_TOKEN_IDENTIFIER;
2240             }
2241
2242           color_name = g_strdup (scanner->value.v_identifier);
2243           gtk_css_scanner_push_scope (scanner, SCOPE_VALUE);
2244           g_scanner_get_next_token (scanner);
2245
2246           if (scanner->token != G_TOKEN_IDENTIFIER)
2247             {
2248               gtk_css_provider_invalid_token (css_provider, scanner, "Color definition");
2249               return G_TOKEN_IDENTIFIER;
2250             }
2251
2252           color_str = g_strstrip (scanner->value.v_identifier);
2253           color = _gtk_css_parse_symbolic_color (color_str, &error);
2254           if (!color)
2255             {
2256               gtk_css_provider_take_error (css_provider, scanner, error);
2257               return G_TOKEN_IDENTIFIER;
2258             }
2259
2260           g_hash_table_insert (css_provider->priv->symbolic_colors, color_name, color);
2261
2262           gtk_css_scanner_pop_scope (scanner);
2263           g_scanner_get_next_token (scanner);
2264
2265           if (scanner->token != ';')
2266             return ';';
2267
2268           return G_TOKEN_NONE;
2269         }
2270       else if (strcmp (directive, "import") == 0)
2271         {
2272           gchar *path = NULL;
2273           GFile *actual;
2274           GError *error = NULL;
2275
2276           gtk_css_scanner_push_scope (scanner, SCOPE_VALUE);
2277           g_scanner_get_next_token (scanner);
2278
2279           if (scanner->token == G_TOKEN_IDENTIFIER &&
2280               g_str_has_prefix (scanner->value.v_identifier, "url"))
2281             path = g_strstrip (scanner->value.v_identifier);
2282           else if (scanner->token == G_TOKEN_STRING)
2283             path = g_strstrip (scanner->value.v_string);
2284           else
2285             {
2286               gtk_css_provider_invalid_token (css_provider, scanner, "File URL");
2287               return G_TOKEN_IDENTIFIER;
2288             }
2289
2290           actual = _gtk_css_parse_url (gtk_css_scanner_get_base_url (scanner),
2291                                        path,
2292                                        NULL,
2293                                        &error);
2294
2295           if (actual == NULL)
2296             {
2297               gtk_css_provider_take_error (css_provider, scanner, error);
2298               return G_TOKEN_IDENTIFIER;
2299             }
2300
2301           gtk_css_scanner_pop_scope (scanner);
2302           g_scanner_get_next_token (scanner);
2303
2304           if (scanner->token != ';')
2305             {
2306               g_object_unref (actual);
2307               return ';';
2308             }
2309
2310           if (gtk_css_scanner_would_recurse (scanner, actual))
2311             {
2312               char *path = g_file_get_path (actual);
2313               gtk_css_provider_error (css_provider,
2314                                       scanner,
2315                                       GTK_CSS_PROVIDER_ERROR,
2316                                       GTK_CSS_PROVIDER_ERROR_IMPORT,
2317                                       "Loading '%s' would recurse",
2318                                       path);
2319               g_free (path);
2320             }
2321           else
2322             {
2323               gtk_css_provider_load_internal (css_provider,
2324                                               scanner,
2325                                               actual,
2326                                               NULL, 0,
2327                                               NULL);
2328             }
2329
2330           g_object_unref (actual);
2331
2332           return G_TOKEN_NONE;
2333         }
2334       else if (strcmp (directive, "binding-set") == 0)
2335         {
2336           GtkBindingSet *binding_set;
2337           gchar *binding_set_name;
2338
2339           g_scanner_get_next_token (scanner);
2340
2341           if (scanner->token != G_TOKEN_IDENTIFIER)
2342             {
2343               gtk_css_provider_invalid_token (css_provider, scanner, "Binding name");
2344               return G_TOKEN_IDENTIFIER;
2345             }
2346
2347           binding_set_name = scanner->value.v_identifier;
2348           binding_set = gtk_binding_set_find (binding_set_name);
2349
2350           if (!binding_set)
2351             {
2352               binding_set = gtk_binding_set_new (binding_set_name);
2353               binding_set->parsed = TRUE;
2354             }
2355
2356           g_scanner_get_next_token (scanner);
2357
2358           if (scanner->token != G_TOKEN_LEFT_CURLY)
2359             return G_TOKEN_LEFT_CURLY;
2360
2361           gtk_css_scanner_push_scope (scanner, SCOPE_BINDING_SET);
2362           g_scanner_get_next_token (scanner);
2363
2364           do
2365             {
2366               GTokenType ret;
2367
2368               if (scanner->token != G_TOKEN_IDENTIFIER)
2369                 {
2370                   gtk_css_provider_invalid_token (css_provider, scanner, "Binding definition");
2371                   return G_TOKEN_IDENTIFIER;
2372                 }
2373
2374               ret = gtk_binding_entry_add_signal_from_string (binding_set,
2375                                                               scanner->value.v_identifier);
2376               if (ret != G_TOKEN_NONE)
2377                 {
2378                   gtk_css_provider_invalid_token (css_provider, scanner, "Binding definition");
2379                   return ret;
2380                 }
2381
2382               g_scanner_get_next_token (scanner);
2383
2384               if (scanner->token != ';')
2385                 return ';';
2386
2387               g_scanner_get_next_token (scanner);
2388             }
2389           while (scanner->token != G_TOKEN_RIGHT_CURLY);
2390
2391           gtk_css_scanner_pop_scope (scanner);
2392           g_scanner_get_next_token (scanner);
2393
2394           return G_TOKEN_NONE;
2395         }
2396       else
2397         {
2398           gtk_css_provider_invalid_token (css_provider, scanner, "Directive");
2399           return G_TOKEN_IDENTIFIER;
2400         }
2401     }
2402
2403   expected_token = parse_selector (css_provider, scanner, &selector);
2404
2405   if (expected_token != G_TOKEN_NONE)
2406     {
2407       selector_path_unref (selector);
2408       gtk_css_provider_invalid_token (css_provider, scanner, "Selector");
2409       return expected_token;
2410     }
2411
2412   priv->cur_selectors = g_slist_prepend (priv->cur_selectors, selector);
2413
2414   while (scanner->token == ',')
2415     {
2416       g_scanner_get_next_token (scanner);
2417
2418       expected_token = parse_selector (css_provider, scanner, &selector);
2419
2420       if (expected_token != G_TOKEN_NONE)
2421         {
2422           selector_path_unref (selector);
2423           gtk_css_provider_invalid_token (css_provider, scanner, "Selector");
2424           return expected_token;
2425         }
2426
2427       priv->cur_selectors = g_slist_prepend (priv->cur_selectors, selector);
2428     }
2429
2430   gtk_css_scanner_pop_scope (scanner);
2431
2432   if (scanner->token != G_TOKEN_LEFT_CURLY)
2433     return G_TOKEN_LEFT_CURLY;
2434
2435   /* Declarations parsing */
2436   gtk_css_scanner_push_scope (scanner, SCOPE_DECLARATION);
2437
2438   g_scanner_get_next_token (scanner);
2439     
2440   while (scanner->token != G_TOKEN_RIGHT_CURLY &&
2441          !g_scanner_eof (scanner))
2442     {
2443       gchar *value_str = NULL;
2444       GtkStylePropertyParser parse_func = NULL;
2445       GParamSpec *pspec = NULL;;
2446       gchar *prop;
2447
2448       if (scanner->token == ';')
2449         {
2450           g_scanner_get_next_token (scanner);
2451           continue;
2452         }
2453
2454       if (scanner->token != G_TOKEN_IDENTIFIER)
2455         {
2456           gtk_css_provider_error_literal (css_provider,
2457                                           scanner,
2458                                           GTK_CSS_PROVIDER_ERROR,
2459                                           GTK_CSS_PROVIDER_ERROR_PROPERTY_NAME,
2460                                           "Expected a valid property name");
2461           goto find_end_of_declaration;
2462         }
2463
2464       prop = g_strdup (scanner->value.v_identifier);
2465
2466       if (!gtk_style_properties_lookup_property (prop, &parse_func, &pspec) &&
2467           prop[0] != '-')
2468         {
2469           gtk_css_provider_error (css_provider,
2470                                   scanner,
2471                                   GTK_CSS_PROVIDER_ERROR,
2472                                   GTK_CSS_PROVIDER_ERROR_PROPERTY_NAME,
2473                                   "'%s' is not a valid property name",
2474                                   prop);
2475           g_free (prop);
2476           goto find_end_of_declaration;
2477         }
2478
2479       g_scanner_get_next_token (scanner);
2480
2481       if (scanner->token != ':')
2482         {
2483           g_free (prop);
2484           gtk_css_provider_invalid_token (css_provider, scanner, "':'");
2485           goto find_end_of_declaration;
2486         }
2487
2488       gtk_css_scanner_push_scope (scanner, SCOPE_VALUE);
2489       g_scanner_get_next_token (scanner);
2490
2491       if (scanner->token != G_TOKEN_IDENTIFIER)
2492         {
2493           g_free (prop);
2494           /* the error value here is hacky. But strings should be used for
2495            * strings really, so a string is not a syntax error but a broken
2496            * value for everything that we support. */
2497           gtk_css_provider_error (css_provider,
2498                                   scanner,
2499                                   GTK_CSS_PROVIDER_ERROR,
2500                                   GTK_CSS_PROVIDER_ERROR_SYNTAX,
2501                                   "Not a property value");
2502           gtk_css_scanner_pop_scope (scanner);
2503           goto find_end_of_declaration;
2504         }
2505
2506       value_str = scanner->value.v_identifier;
2507       g_strchomp (value_str);
2508
2509       gtk_css_scanner_pop_scope (scanner);
2510       g_scanner_peek_next_token (scanner);
2511
2512       if (scanner->next_token != ';' &&
2513           scanner->next_token != G_TOKEN_RIGHT_CURLY &&
2514           scanner->next_token != G_TOKEN_EOF)
2515         {
2516           gtk_css_provider_invalid_token (css_provider, scanner, "';'");
2517           g_free (prop);
2518           goto find_end_of_declaration;
2519         }
2520
2521       if (pspec)
2522         {
2523           GValue *val;
2524
2525           val = g_slice_new0 (GValue);
2526           g_value_init (val, pspec->value_type);
2527
2528           if (strcmp (value_str, "none") == 0)
2529             {
2530               /* Insert the default value, so it has an opportunity
2531                * to override other style providers when merged
2532                */
2533               g_param_value_set_default (pspec, val);
2534               g_hash_table_insert (priv->cur_properties, prop, val);
2535             }
2536           else if (strcmp (prop, "gtk-key-bindings") == 0)
2537             {
2538               /* Private property holding the binding sets */
2539               resolve_binding_sets (value_str, val);
2540               g_hash_table_insert (priv->cur_properties, prop, val);
2541             }
2542           else if (parse_func)
2543             {
2544               GError *error = NULL;
2545               
2546               if ((*parse_func) (value_str, val, &error))
2547                 g_hash_table_insert (priv->cur_properties, prop, val);
2548               else
2549                 gtk_css_provider_take_error (css_provider, scanner, error);
2550             }
2551           else
2552             {
2553               GError *error = NULL;
2554               
2555               if (_gtk_css_value_from_string (val,
2556                                               gtk_css_scanner_get_base_url (scanner),
2557                                               value_str,
2558                                               &error))
2559                 {
2560                   g_hash_table_insert (priv->cur_properties, prop, val);
2561                 }
2562               else
2563                 {
2564                   g_value_unset (val);
2565                   g_slice_free (GValue, val);
2566                   g_free (prop);
2567
2568                   gtk_css_provider_take_error (css_provider, scanner, error);
2569                 }
2570             }
2571         }
2572       else if (prop[0] == '-')
2573         {
2574           GValue *val;
2575
2576           val = g_slice_new0 (GValue);
2577           g_value_init (val, G_TYPE_STRING);
2578           g_value_set_string (val, value_str);
2579
2580           g_hash_table_insert (priv->cur_properties, prop, val);
2581         }
2582       else
2583         g_free (prop);
2584
2585       g_scanner_get_next_token (scanner);
2586
2587       if (g_scanner_eof (scanner))
2588         {
2589           gtk_css_provider_invalid_token (css_provider, scanner, "}");
2590           break;
2591         }
2592
2593 find_end_of_declaration:
2594       while (scanner->token != ';' &&
2595              scanner->token != G_TOKEN_RIGHT_CURLY &&
2596              !g_scanner_eof (scanner))
2597         g_scanner_get_next_token (scanner);
2598     }
2599
2600   gtk_css_scanner_pop_scope (scanner);
2601
2602   return G_TOKEN_NONE;
2603 }
2604
2605 static void
2606 gtk_css_provider_reset (GtkCssProvider *css_provider)
2607 {
2608   GtkCssProviderPrivate *priv;
2609
2610   priv = css_provider->priv;
2611
2612   if (priv->selectors_info->len > 0)
2613     g_ptr_array_remove_range (priv->selectors_info, 0, priv->selectors_info->len);
2614 }
2615
2616 static void
2617 gtk_css_provider_propagate_error (GtkCssProvider  *provider,
2618                                   const gchar     *path,
2619                                   guint            line,
2620                                   guint            position,
2621                                   const GError    *error,
2622                                   GError         **propagate_to)
2623 {
2624   /* we already set an error. And we'd like to keep the first one */
2625   if (*propagate_to)
2626     return;
2627
2628   *propagate_to = g_error_copy (error);
2629   g_prefix_error (propagate_to, "%s:%u:%u: ", path ? path : "<unknown>", line, position);
2630 }
2631
2632 static void
2633 parse_stylesheet (GtkCssProvider  *css_provider,
2634                   GScanner        *scanner)
2635 {
2636   g_scanner_get_next_token (scanner);
2637
2638   while (!g_scanner_eof (scanner))
2639     {
2640       GTokenType expected_token;
2641
2642       expected_token = parse_rule (css_provider, scanner);
2643
2644       if (expected_token != G_TOKEN_NONE)
2645         {
2646           while (!g_scanner_eof (scanner) &&
2647                  scanner->token != G_TOKEN_RIGHT_CURLY)
2648             g_scanner_get_next_token (scanner);
2649         }
2650       else
2651         css_provider_commit (css_provider, scanner);
2652
2653       g_scanner_get_next_token (scanner);
2654       
2655       gtk_css_scanner_reset (scanner);
2656     }
2657 }
2658
2659 static gboolean
2660 gtk_css_provider_load_internal (GtkCssProvider *css_provider,
2661                                 GScanner       *parent,
2662                                 GFile          *file,
2663                                 const char     *data,
2664                                 gsize           length,
2665                                 GError        **error)
2666 {
2667   GScanner *scanner;
2668   gulong error_handler;
2669   char *free_data;
2670
2671   if (error)
2672     error_handler = g_signal_connect (css_provider,
2673                                       "parsing-error",
2674                                       G_CALLBACK (gtk_css_provider_propagate_error),
2675                                       error);
2676   else
2677     error_handler = 0; /* silence gcc */
2678
2679   if (data == NULL)
2680     {
2681       GError *load_error = NULL;
2682
2683       if (g_file_load_contents (file, NULL,
2684                                 &free_data, &length,
2685                                 NULL, &load_error))
2686         {
2687           data = free_data;
2688         }
2689       else
2690         {
2691           if (parent)
2692             {
2693               gtk_css_provider_error (css_provider,
2694                                       parent,
2695                                       GTK_CSS_PROVIDER_ERROR,
2696                                       GTK_CSS_PROVIDER_ERROR_IMPORT,
2697                                       "Failed to import: %s",
2698                                       load_error->message);
2699               g_error_free (load_error);
2700             }
2701           else
2702             {
2703               gtk_css_provider_take_error_full (css_provider,
2704                                                 file,
2705                                                 0, 0,
2706                                                 load_error);
2707             }
2708         }
2709     }
2710   else
2711     free_data = NULL;
2712
2713   if (data)
2714     {
2715       scanner = gtk_css_scanner_new (parent, file, data, length);
2716
2717       parse_stylesheet (css_provider, scanner);
2718
2719       gtk_css_scanner_destroy (scanner);
2720     }
2721
2722   if (error)
2723     {
2724       g_signal_handler_disconnect (css_provider, error_handler);
2725       
2726       if (*error)
2727         {
2728           /* We clear all contents from the provider for backwards compat reasons */
2729           gtk_css_provider_reset (css_provider);
2730           return FALSE;
2731         }
2732     }
2733
2734   return TRUE;
2735 }
2736
2737 /**
2738  * gtk_css_provider_load_from_data:
2739  * @css_provider: a #GtkCssProvider
2740  * @data: CSS data loaded in memory
2741  * @length: the length of @data in bytes, or -1 for NUL terminated strings
2742  * @error: (out) (allow-none): return location for a #GError, or %NULL
2743  *
2744  * Loads @data into @css_provider, making it clear any previously loaded
2745  * information.
2746  *
2747  * Returns: %TRUE if the data could be loaded.
2748  **/
2749 gboolean
2750 gtk_css_provider_load_from_data (GtkCssProvider  *css_provider,
2751                                  const gchar     *data,
2752                                  gssize           length,
2753                                  GError         **error)
2754 {
2755   g_return_val_if_fail (GTK_IS_CSS_PROVIDER (css_provider), FALSE);
2756   g_return_val_if_fail (data != NULL, FALSE);
2757
2758   if (length < 0)
2759     length = strlen (data);
2760
2761   gtk_css_provider_reset (css_provider);
2762
2763   return gtk_css_provider_load_internal (css_provider, NULL, NULL, data, length, error);
2764 }
2765
2766 /**
2767  * gtk_css_provider_load_from_file:
2768  * @css_provider: a #GtkCssProvider
2769  * @file: #GFile pointing to a file to load
2770  * @error: (out) (allow-none): return location for a #GError, or %NULL
2771  *
2772  * Loads the data contained in @file into @css_provider, making it
2773  * clear any previously loaded information.
2774  *
2775  * Returns: %TRUE if the data could be loaded.
2776  **/
2777 gboolean
2778 gtk_css_provider_load_from_file (GtkCssProvider  *css_provider,
2779                                  GFile           *file,
2780                                  GError         **error)
2781 {
2782   g_return_val_if_fail (GTK_IS_CSS_PROVIDER (css_provider), FALSE);
2783   g_return_val_if_fail (G_IS_FILE (file), FALSE);
2784
2785   gtk_css_provider_reset (css_provider);
2786
2787   return gtk_css_provider_load_internal (css_provider, NULL, file, NULL, 0, error);
2788 }
2789
2790 /**
2791  * gtk_css_provider_load_from_path:
2792  * @css_provider: a #GtkCssProvider
2793  * @path: the path of a filename to load, in the GLib filename encoding
2794  * @error: (out) (allow-none): return location for a #GError, or %NULL
2795  *
2796  * Loads the data contained in @path into @css_provider, making it clear
2797  * any previously loaded information.
2798  *
2799  * Returns: %TRUE if the data could be loaded.
2800  **/
2801 gboolean
2802 gtk_css_provider_load_from_path (GtkCssProvider  *css_provider,
2803                                  const gchar     *path,
2804                                  GError         **error)
2805 {
2806   GFile *file;
2807   gboolean result;
2808
2809   g_return_val_if_fail (GTK_IS_CSS_PROVIDER (css_provider), FALSE);
2810   g_return_val_if_fail (path != NULL, FALSE);
2811
2812   file = g_file_new_for_path (path);
2813   
2814   result = gtk_css_provider_load_from_file (css_provider, file, error);
2815
2816   g_object_unref (file);
2817
2818   return result;
2819 }
2820
2821 /**
2822  * gtk_css_provider_get_default:
2823  *
2824  * Returns the provider containing the style settings used as a
2825  * fallback for all widgets.
2826  *
2827  * Returns: (transfer none): The provider used for fallback styling.
2828  *          This memory is owned by GTK+, and you must not free it.
2829  **/
2830 GtkCssProvider *
2831 gtk_css_provider_get_default (void)
2832 {
2833   static GtkCssProvider *provider;
2834
2835   if (G_UNLIKELY (!provider))
2836     {
2837       const gchar *str =
2838         "@define-color fg_color #000; \n"
2839         "@define-color bg_color #dcdad5; \n"
2840         "@define-color text_color #000; \n"
2841         "@define-color base_color #fff; \n"
2842         "@define-color selected_bg_color #4b6983; \n"
2843         "@define-color selected_fg_color #fff; \n"
2844         "@define-color tooltip_bg_color #eee1b3; \n"
2845         "@define-color tooltip_fg_color #000; \n"
2846         "@define-color placeholder_text_color #808080; \n"
2847         "\n"
2848         "@define-color info_fg_color rgb (181, 171, 156);\n"
2849         "@define-color info_bg_color rgb (252, 252, 189);\n"
2850         "@define-color warning_fg_color rgb (173, 120, 41);\n"
2851         "@define-color warning_bg_color rgb (250, 173, 61);\n"
2852         "@define-color question_fg_color rgb (97, 122, 214);\n"
2853         "@define-color question_bg_color rgb (138, 173, 212);\n"
2854         "@define-color error_fg_color rgb (166, 38, 38);\n"
2855         "@define-color error_bg_color rgb (237, 54, 54);\n"
2856         "\n"
2857         "* {\n"
2858         "  background-color: @bg_color;\n"
2859         "  color: @fg_color;\n"
2860         "  border-color: shade (@bg_color, 0.6);\n"
2861         "  padding: 2;\n"
2862         "  border-width: 0;\n"
2863         "}\n"
2864         "\n"
2865         "*:prelight {\n"
2866         "  background-color: shade (@bg_color, 1.05);\n"
2867         "  color: shade (@fg_color, 1.3);\n"
2868         "}\n"
2869         "\n"
2870         "*:selected {\n"
2871         "  background-color: @selected_bg_color;\n"
2872         "  color: @selected_fg_color;\n"
2873         "}\n"
2874         "\n"
2875         ".expander, GtkTreeView.view.expander {\n"
2876         "  color: #fff;\n"
2877         "}\n"
2878         "\n"
2879         ".expander:prelight,\n"
2880         "GtkTreeView.view.expander:selected:prelight {\n"
2881         "  color: @text_color;\n"
2882         "}\n"
2883         "\n"
2884         ".expander:active {\n"
2885         "  transition: 200ms linear;\n"
2886         "}\n"
2887         "\n"
2888         "*:insensitive {\n"
2889         "  border-color: shade (@bg_color, 0.7);\n"
2890         "  background-color: shade (@bg_color, 0.9);\n"
2891         "  color: shade (@bg_color, 0.7);\n"
2892         "}\n"
2893         "\n"
2894         ".view {\n"
2895         "  border-width: 0;\n"
2896         "  border-radius: 0;\n"
2897         "  background-color: @base_color;\n"
2898         "  color: @text_color;\n"
2899         "}\n"
2900         ".view:selected {\n"
2901         "  background-color: shade (@bg_color, 0.9);\n"
2902         "  color: @fg_color;\n"
2903         "}\n"
2904         "\n"
2905         ".view:selected:focused {\n"
2906         "  background-color: @selected_bg_color;\n"
2907         "  color: @selected_fg_color;\n"
2908         "}\n"
2909         "\n"
2910         ".view column:sorted row,\n"
2911         ".view column:sorted row:prelight {\n"
2912         "  background-color: shade (@bg_color, 0.85);\n"
2913         "}\n"
2914         "\n"
2915         ".view column:sorted row:nth-child(odd),\n"
2916         ".view column:sorted row:nth-child(odd):prelight {\n"
2917         "  background-color: shade (@bg_color, 0.8);\n"
2918         "}\n"
2919         "\n"
2920         ".view row,\n"
2921         ".view row:prelight {\n"
2922         "  background-color: @base_color;\n"
2923         "  color: @text_color;\n"
2924         "}\n"
2925         "\n"
2926         ".view row:nth-child(odd),\n"
2927         ".view row:nth-child(odd):prelight {\n"
2928         "  background-color: shade (@base_color, 0.93); \n"
2929         "}\n"
2930         "\n"
2931         ".view row:selected:focused {\n"
2932         "  background-color: @selected_bg_color;\n"
2933         "}\n"
2934         "\n"
2935         ".view row:selected {\n"
2936         "  background-color: darker (@bg_color);\n"
2937         "  color: @selected_fg_color;\n"
2938         "}\n"
2939         "\n"
2940         ".view.cell.trough,\n"
2941         ".view.cell.trough:hover,\n"
2942         ".view.cell.trough:selected,\n"
2943         ".view.cell.trough:selected:focused {\n"
2944         "  background-color: @bg_color;\n"
2945         "  color: @fg_color;\n"
2946         "}\n"
2947         "\n"
2948         ".view.cell.progressbar,\n"
2949         ".view.cell.progressbar:hover,\n"
2950         ".view.cell.progressbar:selected,\n"
2951         ".view.cell.progressbar:selected:focused {\n"
2952         "  background-color: @selected_bg_color;\n"
2953         "  color: @selected_fg_color;\n"
2954         "}\n"
2955         "\n"
2956         ".rubberband {\n"
2957         "  background-color: alpha (@fg_color, 0.25);\n"
2958         "  border-color: @fg_color;\n"
2959         "  border-style: solid;\n"
2960         "  border-width: 1;\n"
2961         "}\n"
2962         "\n"
2963         ".tooltip {\n"
2964         "  background-color: @tooltip_bg_color; \n"
2965         "  color: @tooltip_fg_color; \n"
2966         "  border-color: @tooltip_fg_color; \n"
2967         "  border-width: 1;\n"
2968         "  border-style: solid;\n"
2969         "}\n"
2970         "\n"
2971         ".button,\n"
2972         ".slider {\n"
2973         "  border-style: outset; \n"
2974         "  border-width: 2; \n"
2975         "}\n"
2976         "\n"
2977         ".button:active {\n"
2978         "  background-color: shade (@bg_color, 0.7);\n"
2979         "  border-style: inset; \n"
2980         "}\n"
2981         "\n"
2982         ".button:prelight,\n"
2983         ".slider:prelight {\n"
2984         "  background-color: @selected_bg_color;\n"
2985         "  color: @selected_fg_color;\n"
2986         "  border-color: shade (@selected_bg_color, 0.7);\n"
2987         "}\n"
2988         "\n"
2989         ".trough {\n"
2990         "  background-color: darker (@bg_color);\n"
2991         "  border-style: inset;\n"
2992         "  border-width: 1;\n"
2993         "  padding: 0;\n"
2994         "}\n"
2995         "\n"
2996         ".entry {\n"
2997         "  border-style: inset;\n"
2998         "  border-width: 2;\n"
2999         "  background-color: @base_color;\n"
3000         "  color: @text_color;\n"
3001         "}\n"
3002         "\n"
3003         ".entry:insensitive {\n"
3004         "  background-color: shade (@base_color, 0.9);\n"
3005         "  color: shade (@base_color, 0.7);\n"
3006         "}\n"
3007         ".entry:active {\n"
3008         "  background-color: #c4c2bd;\n"
3009         "  color: #000;\n"
3010         "}\n"
3011         "\n"
3012         ".progressbar,\n"
3013         ".entry.progressbar, \n"
3014         ".cell.progressbar {\n"
3015         "  background-color: @selected_bg_color;\n"
3016         "  border-color: shade (@selected_bg_color, 0.7);\n"
3017         "  color: @selected_fg_color;\n"
3018         "  border-style: outset;\n"
3019         "  border-width: 1;\n"
3020         "}\n"
3021         "\n"
3022         "GtkCheckButton:hover,\n"
3023         "GtkCheckButton:selected,\n"
3024         "GtkRadioButton:hover,\n"
3025         "GtkRadioButton:selected {\n"
3026         "  background-color: shade (@bg_color, 1.05);\n"
3027         "}\n"
3028         "\n"
3029         ".check, .radio,"
3030         ".cell.check, .cell.radio,\n"
3031         ".cell.check:hover, .cell.radio:hover {\n"
3032         "  border-style: solid;\n"
3033         "  border-width: 1;\n"
3034         "  background-color: @base_color;\n"
3035         "  border-color: @fg_color;\n"
3036         "}\n"
3037         "\n"
3038         ".check:active, .radio:active,\n"
3039         ".check:hover, .radio:hover {\n"
3040         "  background-color: @base_color;\n"
3041         "  border-color: @fg_color;\n"
3042         "  color: @text_color;\n"
3043         "}\n"
3044         "\n"
3045         ".check:selected, .radio:selected {\n"
3046         "  background-color: darker (@bg_color);\n"
3047         "  color: @selected_fg_color;\n"
3048         "  border-color: @selected_fg_color;\n"
3049         "}\n"
3050         "\n"
3051         ".check:selected:focused, .radio:selected:focused {\n"
3052         "  background-color: @selected_bg_color;\n"
3053         "}\n"
3054         "\n"
3055         ".menu.check, .menu.radio {\n"
3056         "  color: @fg_color;\n"
3057         "  border-style: none;\n"
3058         "  border-width: 0;\n"
3059         "}\n"
3060         "\n"
3061         ".popup {\n"
3062         "  border-style: outset;\n"
3063         "  border-width: 1;\n"
3064         "}\n"
3065         "\n"
3066         ".viewport {\n"
3067         "  border-style: inset;\n"
3068         "  border-width: 2;\n"
3069         "}\n"
3070         "\n"
3071         ".notebook {\n"
3072         "  border-style: outset;\n"
3073         "  border-width: 1;\n"
3074         "}\n"
3075         "\n"
3076         ".frame {\n"
3077         "  border-style: inset;\n"
3078         "  border-width: 1;\n"
3079         "}\n"
3080         "\n"
3081         "GtkScrolledWindow.frame {\n"
3082         "  padding: 0;\n"
3083         "}\n"
3084         "\n"
3085         ".menu,\n"
3086         ".menubar,\n"
3087         ".toolbar {\n"
3088         "  border-style: outset;\n"
3089         "  border-width: 1;\n"
3090         "}\n"
3091         "\n"
3092         ".menu:hover,\n"
3093         ".menubar:hover,\n"
3094         ".menu.check:hover,\n"
3095         ".menu.radio:hover {\n"
3096         "  background-color: @selected_bg_color;\n"
3097         "  color: @selected_fg_color;\n"
3098         "}\n"
3099         "\n"
3100         "GtkSpinButton.button {\n"
3101         "  border-width: 1;\n"
3102         "}\n"
3103         "\n"
3104         ".scale.slider:hover,\n"
3105         "GtkSpinButton.button:hover {\n"
3106         "  background-color: shade (@bg_color, 1.05);\n"
3107         "  border-color: shade (@bg_color, 0.8);\n"
3108         "}\n"
3109         "\n"
3110         "GtkSwitch.trough:active {\n"
3111         "  background-color: @selected_bg_color;\n"
3112         "  color: @selected_fg_color;\n"
3113         "}\n"
3114         "\n"
3115         "GtkToggleButton.button:inconsistent {\n"
3116         "  border-style: outset;\n"
3117         "  border-width: 1px;\n"
3118         "  background-color: shade (@bg_color, 0.9);\n"
3119         "  border-color: shade (@bg_color, 0.7);\n"
3120         "}\n"
3121         "\n"
3122         "GtkLabel:selected {\n"
3123         "  background-color: shade (@bg_color, 0.9);\n"
3124         "}\n"
3125         "\n"
3126         "GtkLabel:selected:focused {\n"
3127         "  background-color: @selected_bg_color;\n"
3128         "}\n"
3129         "\n"
3130         ".spinner:active {\n"
3131         "  transition: 750ms linear loop;\n"
3132         "}\n"
3133         "\n"
3134         ".info {\n"
3135         "  background-color: @info_bg_color;\n"
3136         "  color: @info_fg_color;\n"
3137         "}\n"
3138         "\n"
3139         ".warning {\n"
3140         "  background-color: @warning_bg_color;\n"
3141         "  color: @warning_fg_color;\n"
3142         "}\n"
3143         "\n"
3144         ".question {\n"
3145         "  background-color: @question_bg_color;\n"
3146         "  color: @question_fg_color;\n"
3147         "}\n"
3148         "\n"
3149         ".error {\n"
3150         "  background-color: @error_bg_color;\n"
3151         "  color: @error_fg_color;\n"
3152         "}\n"
3153         "\n"
3154         ".highlight {\n"
3155         "  background-color: @selected_bg_color;\n"
3156         "  color: @selected_fg_color;\n"
3157         "}\n"
3158         "\n"
3159         ".light-area-focus {\n"
3160         "  color: #000;\n"
3161         "}\n"
3162         "\n"
3163         ".dark-area-focus {\n"
3164         "  color: #fff;\n"
3165         "}\n"
3166         "GtkCalendar.view {\n"
3167         "  border-width: 1;\n"
3168         "  border-style: inset;\n"
3169         "  padding: 1;\n"
3170         "}\n"
3171         "\n"
3172         "GtkCalendar.view:inconsistent {\n"
3173         "  color: darker (@bg_color);\n"
3174         "}\n"
3175         "\n"
3176         "GtkCalendar.header {\n"
3177         "  background-color: @bg_color;\n"
3178         "  border-style: outset;\n"
3179         "  border-width: 2;\n"
3180         "}\n"
3181         "\n"
3182         "GtkCalendar.highlight {\n"
3183         "  border-width: 0;\n"
3184         "}\n"
3185         "\n"
3186         "GtkCalendar.button {\n"
3187         "  background-color: @bg_color;\n"
3188         "}\n"
3189         "\n"
3190         "GtkCalendar.button:hover {\n"
3191         "  background-color: lighter (@bg_color);\n"
3192         "  color: @fg_color;\n"
3193         "}\n"
3194         "\n"
3195         ".menu * {\n"
3196         "  border-width: 0;\n"
3197         "  padding: 2;\n"
3198         "}\n"
3199         "\n";
3200
3201       provider = gtk_css_provider_new ();
3202       if (!gtk_css_provider_load_from_data (provider, str, -1, NULL))
3203         {
3204           g_error ("Failed to load the internal default CSS.");
3205         }
3206     }
3207
3208   return provider;
3209 }
3210
3211 gchar *
3212 _gtk_css_provider_get_theme_dir (void)
3213 {
3214   const gchar *var;
3215   gchar *path;
3216
3217   var = g_getenv ("GTK_DATA_PREFIX");
3218
3219   if (var)
3220     path = g_build_filename (var, "share", "themes", NULL);
3221   else
3222     path = g_build_filename (GTK_DATA_PREFIX, "share", "themes", NULL);
3223
3224   return path;
3225 }
3226
3227 /**
3228  * gtk_css_provider_get_named:
3229  * @name: A theme name
3230  * @variant: (allow-none): variant to load, for example, "dark", or
3231  *     %NULL for the default
3232  *
3233  * Loads a theme from the usual theme paths
3234  *
3235  * Returns: (transfer none): a #GtkCssProvider with the theme loaded.
3236  *     This memory is owned by GTK+, and you must not free it.
3237  */
3238 GtkCssProvider *
3239 gtk_css_provider_get_named (const gchar *name,
3240                             const gchar *variant)
3241 {
3242   static GHashTable *themes = NULL;
3243   GtkCssProvider *provider;
3244   gchar *key;
3245
3246   if (G_UNLIKELY (!themes))
3247     themes = g_hash_table_new (g_str_hash, g_str_equal);
3248
3249   if (variant == NULL)
3250     key = (gchar *)name;
3251   else
3252     key = g_strconcat (name, "-", variant, NULL);
3253
3254   provider = g_hash_table_lookup (themes, key);
3255
3256   if (!provider)
3257     {
3258       const gchar *home_dir;
3259       gchar *subpath, *path = NULL;
3260
3261       if (variant)
3262         subpath = g_strdup_printf ("gtk-3.0" G_DIR_SEPARATOR_S "gtk-%s.css", variant);
3263       else
3264         subpath = g_strdup ("gtk-3.0" G_DIR_SEPARATOR_S "gtk.css");
3265
3266       /* First look in the users home directory
3267        */
3268       home_dir = g_get_home_dir ();
3269       if (home_dir)
3270         {
3271           path = g_build_filename (home_dir, ".themes", name, subpath, NULL);
3272
3273           if (!g_file_test (path, G_FILE_TEST_EXISTS))
3274             {
3275               g_free (path);
3276               path = NULL;
3277             }
3278         }
3279
3280       if (!path)
3281         {
3282           gchar *theme_dir;
3283
3284           theme_dir = _gtk_css_provider_get_theme_dir ();
3285           path = g_build_filename (theme_dir, name, subpath, NULL);
3286           g_free (theme_dir);
3287
3288           if (!g_file_test (path, G_FILE_TEST_EXISTS))
3289             {
3290               g_free (path);
3291               path = NULL;
3292             }
3293         }
3294
3295       g_free (subpath);
3296
3297       if (path)
3298         {
3299           GError *error;
3300
3301           provider = gtk_css_provider_new ();
3302           error = NULL;
3303           if (!gtk_css_provider_load_from_path (provider, path, &error))
3304             {
3305               g_warning ("Could not load named theme \"%s\": %s", name, error->message);
3306               g_error_free (error);
3307
3308               g_object_unref (provider);
3309               provider = NULL;
3310             }
3311           else
3312             g_hash_table_insert (themes, g_strdup (key), provider);
3313
3314           g_free (path);
3315         }
3316     }
3317
3318   if (key != name)
3319     g_free (key);
3320
3321   return provider;
3322 }
3323
3324 static void
3325 selector_path_print (const SelectorPath *path,
3326                      GString *           str)
3327 {
3328   GSList *walk, *reverse;
3329
3330   reverse = g_slist_copy (path->elements);
3331   reverse = g_slist_reverse (reverse);
3332
3333   for (walk = reverse; walk; walk = walk->next)
3334     {
3335       SelectorElement *elem = walk->data;
3336
3337       switch (elem->elem_type)
3338         {
3339         case SELECTOR_TYPE_NAME:
3340         case SELECTOR_NAME:
3341           g_string_append (str, g_quark_to_string (elem->name));
3342           break;
3343         case SELECTOR_GTYPE:
3344           g_string_append (str, g_type_name (elem->type));
3345           break;
3346         case SELECTOR_REGION:
3347           g_string_append (str, g_quark_to_string (elem->region.name));
3348           if (elem->region.flags)
3349             {
3350               char * flag_names[] = {
3351                 "nth-child(even)",
3352                 "nth-child(odd)",
3353                 "first-child",
3354                 "last-child",
3355                 "sorted"
3356               };
3357               guint i;
3358
3359               for (i = 0; i < G_N_ELEMENTS (flag_names); i++)
3360                 {
3361                   if (elem->region.flags & (1 << i))
3362                     {
3363                       g_string_append_c (str, ':');
3364                       g_string_append (str, flag_names[i]);
3365                     }
3366                 }
3367             }
3368           break;
3369         case SELECTOR_CLASS:
3370           g_string_append_c (str, '.');
3371           g_string_append (str, g_quark_to_string (elem->name));
3372           break;
3373         case SELECTOR_GLOB:
3374           if (walk->next == NULL ||
3375               elem->combinator != COMBINATOR_CHILD ||
3376               ((SelectorElement *) walk->next->data)->elem_type != SELECTOR_CLASS)
3377             g_string_append (str, "*");
3378           break;
3379         default:
3380           g_assert_not_reached ();
3381         }
3382
3383       if (walk->next)
3384         {
3385           switch (elem->combinator)
3386             {
3387             case COMBINATOR_DESCENDANT:
3388               if (elem->elem_type != SELECTOR_CLASS ||
3389                   ((SelectorElement *) walk->next->data)->elem_type != SELECTOR_CLASS)
3390                 g_string_append_c (str, ' ');
3391               break;
3392             case COMBINATOR_CHILD:
3393               if (((SelectorElement *) walk->next->data)->elem_type != SELECTOR_CLASS)
3394                 g_string_append (str, " > ");
3395               break;
3396             default:
3397               g_assert_not_reached ();
3398             }
3399         }
3400         
3401     }
3402
3403   if (path->state)
3404     {
3405       char * state_names[] = {
3406         "active",
3407         "hover",
3408         "selected",
3409         "insensitive",
3410         "inconsistent",
3411         "focus"
3412       };
3413       guint i;
3414
3415       for (i = 0; i < G_N_ELEMENTS (state_names); i++)
3416         {
3417           if (path->state & (1 << i))
3418             {
3419               g_string_append_c (str, ':');
3420               g_string_append (str, state_names[i]);
3421             }
3422         }
3423     }
3424
3425   g_slist_free (reverse);
3426 }
3427
3428 static void
3429 selector_style_info_print (const SelectorStyleInfo *info,
3430                            GString                 *str)
3431 {
3432   GList *keys, *walk;
3433   char *s;
3434
3435   selector_path_print (info->path, str);
3436
3437   g_string_append (str, " {\n");
3438
3439   keys = g_hash_table_get_keys (info->style);
3440   /* so the output is identical for identical selector styles */
3441   keys = g_list_sort (keys, (GCompareFunc) strcmp);
3442
3443   for (walk = keys; walk; walk = walk->next)
3444     {
3445       const char *name = walk->data;
3446       const GValue *value = g_hash_table_lookup (info->style, (gpointer) name);
3447
3448       g_string_append (str, "  ");
3449       g_string_append (str, name);
3450       g_string_append (str, ": ");
3451       s = _gtk_css_value_to_string (value);
3452       g_string_append (str, s);
3453       g_free (s);
3454       g_string_append (str, ";\n");
3455     }
3456
3457   g_list_free (keys);
3458
3459   g_string_append (str, "}\n");
3460 }
3461
3462 static void
3463 gtk_css_provider_print_colors (GHashTable *colors,
3464                                GString    *str)
3465 {
3466   GList *keys, *walk;
3467   char *s;
3468
3469   keys = g_hash_table_get_keys (colors);
3470   /* so the output is identical for identical styles */
3471   keys = g_list_sort (keys, (GCompareFunc) strcmp);
3472
3473   for (walk = keys; walk; walk = walk->next)
3474     {
3475       const char *name = walk->data;
3476       GtkSymbolicColor *symbolic = g_hash_table_lookup (colors, (gpointer) name);
3477
3478       g_string_append (str, "@define-color ");
3479       g_string_append (str, name);
3480       g_string_append (str, " ");
3481       s = gtk_symbolic_color_to_string (symbolic);
3482       g_string_append (str, s);
3483       g_free (s);
3484       g_string_append (str, ";\n");
3485     }
3486
3487   g_list_free (keys);
3488 }
3489
3490 /**
3491  * gtk_css_provider_to_string:
3492  * @provider: the provider to write to a string
3493  *
3494  * Convertes the @provider into a string representation in CSS
3495  * format.
3496  * 
3497  * Using gtk_css_provider_load_from_data() with the return value
3498  * from this function on a new provider created with
3499  * gtk_css_provider_new() will basicallu create a duplicate of
3500  * this @provider.
3501  *
3502  * Returns: a new string representing the @provider.
3503  **/
3504 char *
3505 gtk_css_provider_to_string (GtkCssProvider *provider)
3506 {
3507   GtkCssProviderPrivate *priv;
3508   GString *str;
3509   guint i;
3510
3511   g_return_val_if_fail (GTK_IS_CSS_PROVIDER (provider), NULL);
3512
3513   priv = provider->priv;
3514
3515   str = g_string_new ("");
3516
3517   gtk_css_provider_print_colors (priv->symbolic_colors, str);
3518
3519   for (i = 0; i < priv->selectors_info->len; i++)
3520     {
3521       if (i > 0)
3522         g_string_append (str, "\n");
3523       selector_style_info_print (g_ptr_array_index (priv->selectors_info, i),
3524                                  str);
3525     }
3526
3527   return g_string_free (str, FALSE);
3528 }
3529