2 <!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
3 "http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [
5 <chapter id="gtk-migrating-GtkStyleContext">
6 <title>Migrating from GtkStyle to GtkStyleContext</title>
9 In GTK+ 3.0, #GtkStyleContext was added to replace #GtkStyle and
10 the theming infrastructure available in 2.x. GtkStyleContext is an
11 object similar in spirit to GtkStyle, as it contains theming information,
12 although in a more complete and tokenized fashion. There are two aspects
13 to switching to GtkStyleContext: porting themes and theme engines, and
14 porting applications, libraries and widgets.
17 <refsect2 id="gtk-migrating-GtkStyleContext-themes">
18 <title>Migrating themes</title>
21 From GTK+ 3.0 on, theme engines must implement #GtkThemingEngine and be
22 installed in <filename>$libdir/gtk+-3.0/$GTK_VERSION/theming-engines</filename>,
23 and the files containing style information must be written in the CSS-like
24 format that is understood by #GtkCssProvider. For a theme named
25 "Clearlooks", the CSS file parsed by default is
26 <filename>$datadir/themes/Clearlooks/gtk-3.0/gtk.css</filename>,
27 with possible variants such as the dark theme being named
28 <filename>gtk-dark.css</filename> in the same directory.
32 <refsect2 id="gtk-migrating-theme-GtkStyleContext-engines">
33 <title>Migrating theme engines</title>
36 Migrating a #GtkStyle based engine to a #GtkThemingEngine based one
37 should be straightforward for most of the vfuncs. Besides a cleanup
38 in the available paint methods and a simplification in the passed
39 arguments (in favor of #GtkStyleContext containing all the information),
40 the available render methods resemble those of #GtkStyle quite
41 evidently. Notable differences include:
46 All variations of gtk_paint_box(), gtk_paint_flat_box(),
47 gtk_paint_shadow(), gtk_paint_box_gap() and gtk_paint_shadow_gap()
48 are replaced by gtk_render_background(), gtk_render_frame() and
49 gtk_render_frame_gap(). The first function renders frameless
50 backgrounds and the last two render frames in various forms.
53 gtk_paint_resize_grip() has been subsumed by gtk_render_handle()
54 with a #GTK_STYLE_CLASS_GRIP class set in the style context.
57 gtk_paint_spinner() disappears in favor of gtk_render_activity()
58 with a #GTK_STYLE_CLASS_SPINNER class set in the style context.
63 The list of available render methods is:
68 gtk_render_background(): Renders a widget/area background.
71 gtk_render_frame(): Renders a frame border around the given rectangle.
72 Usually the detail of the border depends on the theme information,
73 plus the current widget state.
76 gtk_render_frame_gap(): Renders a frame border with a gap on one side.
79 gtk_render_layout(): Renders a #PangoLayout.
82 gtk_render_handle(): Renders all kind of handles and resize grips,
83 depending on the style class.
86 gtk_render_check(): Render checkboxes.
89 gtk_render_option(): Render radiobuttons.
92 gtk_render_arrow(): Renders an arrow pointing to a direction.
95 gtk_render_expander(): Renders an expander indicator, such as in
99 gtk_render_focus(): Renders the indication that a widget has the
103 gtk_render_line(): Renders a line from one coordinate to another.
106 gtk_render_slider(): Renders a slider, such as in #GtkScale.
109 gtk_render_extension(): Renders an extension that protrudes from
110 a UI element, such as a notebook tab.
113 gtk_render_activity(): Renders an area displaying activity, be it
114 a progressbar or a spinner.
117 gtk_render_icon_pixbuf(): Renders an icon into a #GdkPixbuf.
122 One of the main differences to #GtkStyle-based engines is that the
123 rendered widget is totally isolated from the theme engine, all style
124 information is meant to be retrieved from the #GtkThemingEngine API,
125 or from the #GtkWidgetPath obtained from gtk_theming_engine_get_path(),
126 which fully represents the rendered widget's hierarchy from a styling
131 The detail string available in #GtkStyle-based engines has been
132 replaced by widget regions and style classes. Regions are a way for
133 complex widgets to associate different styles with different areas,
134 such as even and odd rows in a treeview. Style classes allow sharing
135 of style information between widgets, regardless of their type.
136 Regions and style classes can be used in style sheets to associate
137 styles, and them engines can also access them. There are several
138 predefined classes and regions such as %GTK_STYLE_CLASS_BUTTON or
139 %GTK_STYLE_REGION_TAB in <filename>gtkstylecontext.h</filename>,
140 although custom widgets may define their own, which themes may
146 <refsect2 id="gtk-migrating-GtkStyleContext-parser-extensions">
147 <title>Extending the CSS parser</title>
150 In #GtkStyle-based engines, #GtkRCStyle provided ways to extend the
151 gtkrc parser with engine-specific extensions. This has been replaced
152 by gtk_theming_engine_register_property(), which lets a theme engine
153 register new properties with an arbitrary type. While there is built-in
154 support for most basic types, it is possible to use a custom parser
159 The installed properties depend on the #GtkThemeEngine::name property,
160 so they should be added in the <literal>constructed()</literal> vfunc.
161 For example, if an engine with the name "Clearlooks" installs a
162 "focus-color" property with the type #GdkRGBA, the property
163 <literal>-Clearlooks-focus-color</literal> will be registered and
164 accepted in CSS like this:
165 <informalexample><programlisting>
167 -Clearlooks-focus-color: rgba(255, 0, 0, 1.0);
169 </programlisting></informalexample>
173 Widget style properties also follow a similar syntax, with the widget
174 type name used as a prefix. For example, the #GtkWidget:focus-line-width
175 style property can be modified in CSS as
176 <literal>-GtkWidget-focus-line-width</literal>.
180 <refsect2 id="gtk-migrating-GtkStyleContext-css">
181 <title>Using the CSS file format</title>
184 The syntax of RC and CSS files formats is obviously different.
185 The CSS-like syntax will hopefully be much more familiar to many
186 people, lowering the barrier for custom theming.
189 Instead of going through the syntax differences one-by-one, we
190 will present a more or less comprehensive example and discuss
191 how it can be translated into CSS:
195 <title>Sample RC code</title>
201 GtkButton::child-displacement-x = 1
202 GtkButton::child-displacement-y = 1
203 GtkCheckButton::indicator-size = 14
205 bg[NORMAL] = @bg_color
206 bg[PRELIGHT] = shade (1.02, @bg_color)
207 bg[SELECTED] = @selected_bg_color
208 bg[INSENSITIVE] = @bg_color
209 bg[ACTIVE] = shade (0.9, @bg_color)
211 fg[NORMAL] = @fg_color
212 fg[PRELIGHT] = @fg_color
213 fg[SELECTED] = @selected_fg_color
214 fg[INSENSITIVE] = darker (@bg_color)
215 fg[ACTIVE] = @fg_color
217 text[NORMAL] = @text_color
218 text[PRELIGHT] = @text_color
219 text[SELECTED] = @selected_fg_color
220 text[INSENSITIVE] = darker (@bg_color)
221 text[ACTIVE] = @selected_fg_color
223 base[NORMAL] = @base_color
224 base[PRELIGHT] = shade (0.95, @bg_color)
225 base[SELECTED] = @selected_bg_color
226 base[INSENSITIVE] = @bg_color
227 base[ACTIVE] = shade (0.9, @selected_bg_color)
229 engine "clearlooks" {
230 colorize_scrollbar = TRUE
239 bg[NORMAL] = @tooltip_bg_color
240 fg[NORMAL] = @tooltip_fg_color
247 bg[NORMAL] = shade (1.04, @bg_color)
248 bg[PRELIGHT] = shade (1.06, @bg_color)
249 bg[ACTIVE] = shade (0.85, @bg_color)
256 bg[SELECTED] = mix (0.4, @selected_bg_color, @base_color)
257 fg[SELECTED] = @text_color
259 engine "clearlooks" {
260 focus_color = shade (0.65, @selected_bg_color)
265 bg[NORMAL] = #fff;
268 class "GtkWidget" style "default"
269 class "GtkEntry" style "entry"
270 widget_class "*<GtkButton>" style "button"
271 widget "gtk-tooltip*" style "tooltips"
272 widget_class "window-name.*.GtkButton" style "other"
277 would roughly translate to this CSS:
281 <title>CSS translation</title>
285 -GtkButton-child-displacement-x: 1;
286 -GtkButton-child-displacement-y: 1;
287 -GtkCheckButton-indicator-size: 14;
289 background-color: @bg_color;
292 -Clearlooks-colorize-scrollbar: true;
293 -Clearlooks-style: classic;
297 background-color: shade (@bg_color, 1.02);
301 background-color: @selected_bg_color;
302 color: @selected_fg_color;
306 color: shade (@bg_color, 0.7);
310 background-color: shade (@bg_color, 0.9);
316 background-color: @tooltip_bg_color;
317 color: @tooltip_fg_color;
322 background-color: shade (@bg_color, 1.04);
326 background-color: shade (@bg_color, 1.06);
330 background-color: shade (@bg_color, 0.85);
336 background-color: @base_color;
341 background-color: mix (@selected_bg_color, @base_color, 0.4);
342 -Clearlooks-focus-color: shade (0.65, @selected_bg_color)
345 /* The latter selector is an specification of the first,
346 since any widget may use the same classes or names */
347 #window-name .button,
348 GtkWindow#window-name GtkButton.button {
349 background-color: #fff;
355 One notable difference is the reduction from fg/bg/text/base colors
356 to only foreground/background, in exchange the widget is able to render
357 its various elements with different CSS classes, which can be themed
362 Access to colors has also changed a bit. With #GtkStyle, the common
363 way to access colors is:
364 <informalexample><programlisting>
368 color1 = &style->bg[GTK_STATE_PRELIGHT];
369 gtk_style_lookup_color (style, "focus_color", &color2);
370 </programlisting></informalexample>
371 With #GtkStyleContext, you generally use #GdkRGBA instead of #GdkColor
372 and the code looks like this:
373 <informalexample><programlisting>
377 gtk_style_context_get (context, GTK_STATE_FLAG_PRELIGHT,
378 "background-color", &color1,
380 gtk_style_context_lookup_color (context, "focus_color", &color2);
384 gdk_rgba_free (color1);
385 </programlisting></informalexample>
386 Note that the memory handling here is different: gtk_style_context_get()
387 expects the address of a GdkRGBA* and returns a newly allocated struct,
388 gtk_style_context_lookup_color() expects the address of an existing
389 struct, and fills it.
393 It is worth mentioning that the new file format does not support
394 custom keybindings nor stock icon mappings as the RC format did.
398 <refsect2 id="gtk-migrating-GtkStyleContext-checklist">
399 <title>A checklist for widgets</title>
402 When porting your widgets to use #GtkStyleContext, this checklist
408 Replace <literal>style_set()</literal> calls with
409 <literal>style_updated()</literal>.
414 Try to identify the role of what you're rendering with any number
415 of classes. This will replace the detail string. There is a predefined
416 set of CSS classes which you can reuse where appropriate. Doing so
417 will give you theming 'for free', whereas custom classes will require
418 extra work in the theme. Note that complex widgets are likely to
419 need different styles when rendering different parts, and style
420 classes are one way to achieve this. This could result in code like
421 the following (simplified) examples:
425 <title>Setting a permanent CSS class</title>
428 gtk_button_init (GtkButton *button)
430 GtkStyleContext *context;
434 context = gtk_widget_get_style_context (GTK_WIDGET (button));
436 /* Set the "button" class */
437 gtk_style_context_add_class (context, GTK_STYLE_CLASS_BUTTON);
447 <title>Using dynamic CSS classes for different elements</title>
450 gtk_spin_button_draw (GtkSpinButton *spin,
453 GtkStyleContext *context;
457 context = gtk_widget_get_style_context (GTK_WIDGET (spin));
459 gtk_style_context_save (context);
460 gtk_style_context_add_class (context, GTK_STYLE_CLASS_ENTRY);
462 /* Call to entry draw impl with "entry" class */
463 parent_class->draw (spin, cr);
465 gtk_style_context_restore (context);
466 gtk_style_context_save (context);
468 /* Render up/down buttons with the "button" class */
469 gtk_style_context_add_class (context, GTK_STYLE_CLASS_BUTTON);
470 draw_up_button (spin, cr);
471 draw_down_button (spin, cr);
473 gtk_style_context_restore (context);
481 Note that #GtkStyleContext only provides fg/bg colors, so text/base
482 is done through distinctive theming of the different classes. For
483 example, an entry would usually be black on white while a button
484 would usually be black on light grey.
489 Replace all <literal>gtk_paint_*()</literal> calls with corresponding
490 <literal>gtk_render_*()</literal> calls. The most distinctive changes
491 are the use of #GtkStateFlags to represent the widget state and the
492 lack of #GtkShadowType. For gtk_render_check() and gtk_render_option(),
493 the @shadow_type parameter is replaced by the #GTK_STATE_FLAG_ACTIVE
494 and #GTK_STATE_FLAG_INCONSISTENT state flags. For things such as
495 pressed/unpressed button states, #GTK_STATE_FLAG_ACTIVE is used, and
496 the CSS may style normal/active states differently to render
497 outset/inset borders, respectively.
501 The various <literal>gtk_widget_modify_*()</literal> functions to
502 override colors or fonts for individual widgets have been replaced
503 by similar <literal>gtk_widget_override_*()</literal> functions.
507 It is no longer necessary to call gtk_widget_style_attach(),
508 gtk_style_attach(), gtk_style_detach() or gtk_widget_ensure_style().
512 Replace all uses of xthickness/ythickness. #GtkStyleContext uses the
513 CSS box model, and there are border-width/padding/margin properties to
514 replace the different applications of X and Y thickness. Note that all
515 of this is merely a guideline. Widgets may choose to follow it or not.
520 <refsect2 id="gtk-migrating-GtkStyleContext-parsing">
521 <title>Parsing of custom resources</title>
523 As a consequence of the RC format going away, calling gtk_rc_parse() or
524 gtk_rc_parse_string() won't have any effect on a widgets appearance.
525 The way to replace these calls is using a custom #GtkStyleProvider,
526 either for an individual widget through gtk_style_context_add_provider()
527 or for all widgets on a screen through gtk_style_context_add_provider_for_screen().
528 Typically, the provider will be a #GtkCssProvider, which parse CSS
529 information from a file or from a string.
533 Notice that you can also get style information from custom resources
534 by implementing the #GtkStyleProvider interface yourself. This is
535 an advanced feature that should be rarely used.
539 <refsect2 id="gtk-migrating-GtkStyleContext-bonus-points">
540 <title>Bonus points</title>
543 There are some features in #GtkStyleContext that were not available in
544 #GtkStyle, or were made available over time for certain widgets through
545 extending the detail string in obscure ways. There is a lot more
546 information available when rendering UI elements, and it is accessible
547 in more uniform, less hacky ways. By going through this list you'll
548 ensure your widget is a good citizen in a fully themable user interface.
553 If your widget renders a series of similar elements, such as tabs
554 in a #GtkNotebook or rows/column in a #GtkTreeView, consider adding
555 regions through gtk_style_context_add_region(). These regions can be
556 referenced in CSS and the :nth-child pseudo-class may be used to match
557 the elements depending on the flags passed.
560 <title>Theming widget regions</title>
563 background-color: #f3329d;
566 GtkTreeView row::nth-child (even) {
567 background-color: #dddddd;
575 If your container renders child widgets within different regions,
576 make it implement GtkContainer::get_path_for_child(). This function
577 lets containers assign a special #GtkWidgetPath to child widgets
578 depending on their role/region. This is necessary to extend the
579 concept above throughout the widget hierarchy.
583 For example, a #GtkNotebook modifies the tab labels' #GtkWidgetPath
584 so the "tab" region is added. This makes it possible to theme tab
589 <title>Theming a widget within a parent container region</title>
591 GtkNotebook tab GtkLabel {
600 If you intend several visual elements to look interconnected,
601 make sure you specify rendered elements' connection areas with
602 gtk_style_context_set_junction_sides(). It is of course up to the
603 theme to make use of this information or not.
608 #GtkStyleContext supports implicit animations on state changes for
609 the most simple case out-of-the-box: widgets with a single animatable
610 area, whose state is changed with gtk_widget_set_state_flags() or
611 gtk_widget_unset_state_flags(). These functions trigger animated
612 transitions for the affected state flags. Examples of widgets for
613 which this kind of animation may be sufficient are #GtkButton or
617 If your widget consists of more than a simple area, and these areas
618 may be rendered with different states, make sure to mark the rendered
619 areas with gtk_style_context_push_animatable_region() and
620 gtk_style_context_pop_animatable_region().
624 gtk_style_context_notify_state_change() may be used to trigger a
625 transition for a given state. The region ID will determine the
626 animatable region that is affected by this transition.