Using the CSS file format

The syntax of RC and CSS files formats is obviously different. The CSS-like syntax will hopefully be much more familiar to many people, lowering the barrier for custom theming.

Instead of going through the syntax differences one-by-one, we will present a more or less comprehensive example and discuss how it can be translated into CSS:

Example 44. Sample RC code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
style "default" {
        xthickness = 1
        ythickness = 1

        GtkButton::child-displacement-x = 1
        GtkButton::child-displacement-y = 1
        GtkCheckButton::indicator-size = 14

        bg[NORMAL]        = @bg_color
        bg[PRELIGHT]      = shade (1.02, @bg_color)
        bg[SELECTED]      = @selected_bg_color
        bg[INSENSITIVE]   = @bg_color
        bg[ACTIVE]        = shade (0.9, @bg_color)

        fg[NORMAL]        = @fg_color
        fg[PRELIGHT]      = @fg_color
        fg[SELECTED]      = @selected_fg_color
        fg[INSENSITIVE]   = darker (@bg_color)
        fg[ACTIVE]        = @fg_color

        text[NORMAL]      = @text_color
        text[PRELIGHT]    = @text_color
        text[SELECTED]    = @selected_fg_color
        text[INSENSITIVE] = darker (@bg_color)
        text[ACTIVE]      = @selected_fg_color

        base[NORMAL]      = @base_color
        base[PRELIGHT]    = shade (0.95, @bg_color)
        base[SELECTED]    = @selected_bg_color
        base[INSENSITIVE] = @bg_color
        base[ACTIVE]      = shade (0.9, @selected_bg_color)

        engine "clearlooks" {
                colorize_scrollbar = TRUE
                style = CLASSIC
        }
}

style "tooltips" {
        xthickness = 4
        ythickness = 4

        bg[NORMAL]        = @tooltip_bg_color
        fg[NORMAL]        = @tooltip_fg_color
}

style "button" {
        xthickness = 3
        ythickness = 3

        bg[NORMAL]        = shade (1.04, @bg_color)
        bg[PRELIGHT]      = shade (1.06, @bg_color)
        bg[ACTIVE]        = shade (0.85, @bg_color)
}

style "entry" {
        xthickness = 3
        ythickness = 3

        bg[SELECTED] = mix (0.4, @selected_bg_color, @base_color)
        fg[SELECTED] = @text_color

        engine "clearlooks" {
                focus_color = shade (0.65, @selected_bg_color)
        }
}

style "other" {
        bg[NORMAL] = #fff;
}

class "GtkWidget" style "default"
class "GtkEntry" style "entry"
widget_class "*<GtkButton>" style "button"
widget "gtk-tooltip*" style "tooltips"
widget_class "window-name.*.GtkButton" style "other"

would roughly translate to this CSS:

Example 45. CSS translation

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
* {
  padding: 1;
  -GtkButton-child-displacement-x: 1;
  -GtkButton-child-displacement-y: 1;
  -GtkCheckButton-indicator-size: 14;

  background-color: @bg_color;
  color: @fg_color;

  -Clearlooks-colorize-scrollbar: true;
  -Clearlooks-style: classic;
}

*:hover {
  background-color: shade (@bg_color, 1.02);
}

*:selected {
  background-color: @selected_bg_color;
  color: @selected_fg_color;
}

*:insensitive {
  color: shade (@bg_color, 0.7);
}

*:active {
  background-color: shade (@bg_color, 0.9);
}

.tooltip {
  padding: 4;

  background-color: @tooltip_bg_color;
  color: @tooltip_fg_color;
}

.button {
  padding: 3;
  background-color: shade (@bg_color, 1.04);
}

.button:hover {
  background-color: shade (@bg_color, 1.06);
}

.button:active {
  background-color: shade (@bg_color, 0.85);
}

.entry {
  padding: 3;

  background-color: @base_color;
  color: @text_color;
}

.entry:selected {
  background-color: mix (@selected_bg_color, @base_color, 0.4);
  -Clearlooks-focus-color: shade (0.65, @selected_bg_color)
}

/* The latter selector is an specification of the first,
   since any widget may use the same classes or names */
#window-name .button,
GtkWindow#window-name GtkButton.button {
  background-color: #fff;
}

One notable difference is the reduction from fg/bg/text/base colors to only foreground/background, in exchange the widget is able to render its various elements with different CSS classes, which can be themed independently.

In the same vein, the light, dark and mid color variants that were available in GtkStyle should be replaced by a combination of symbolic colors and custom CSS, where necessary. text_aa should really not be used anywhere, anyway, and the white and black colors that were available in GtkStyle can just be replaced by literal GdkRGBA structs.

Access to colors has also changed a bit. With GtkStyle, the common way to access colors is:

1
2
3
4
5
GdkColor *color1;
GdkColor color2;

color1 = &style->bg[GTK_STATE_PRELIGHT];
gtk_style_lookup_color (style, "focus_color", &color2);

With GtkStyleContext, you generally use GdkRGBA instead of GdkColor and the code looks like this:

1
2
3
4
5
6
7
8
9
10
11
GdkRGBA *color1;
GdkRGBA  color2;

gtk_style_context_get (context, GTK_STATE_FLAG_PRELIGHT,
                       "background-color", &color1,
                       NULL);
gtk_style_context_lookup_color (context, "focus_color", &color2);

...

gdk_rgba_free (color1);

Note that the memory handling here is different: gtk_style_context_get() expects the address of a GdkRGBA* and returns a newly allocated struct, gtk_style_context_lookup_color() expects the address of an existing struct, and fills it.

It is worth mentioning that the new file format does not support stock icon mappings as the RC format did.