]> Pileus Git - ~andy/gtk/blob - gtk/gtkstylecontext.c
Fix commit 5f55c420471db9a05d145e140b3a7cdfc5bdba9f
[~andy/gtk] / gtk / gtkstylecontext.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 <gdk/gdk.h>
23 #include <stdlib.h>
24 #include <gobject/gvaluecollector.h>
25
26 #include "gtkstylecontextprivate.h"
27 #include "gtkstylepropertiesprivate.h"
28 #include "gtktypebuiltins.h"
29 #include "gtkthemingengine.h"
30 #include "gtkintl.h"
31 #include "gtkwidget.h"
32 #include "gtkwindow.h"
33 #include "gtkprivate.h"
34 #include "gtksymboliccolor.h"
35 #include "gtkanimationdescription.h"
36 #include "gtktimeline.h"
37 #include "gtkiconfactory.h"
38 #include "gtkwidgetprivate.h"
39
40 /**
41  * SECTION:gtkstylecontext
42  * @Short_description: Rendering UI elements
43  * @Title: GtkStyleContext
44  *
45  * #GtkStyleContext is an object that stores styling information affecting
46  * a widget defined by #GtkWidgetPath.
47  *
48  * In order to construct the final style information, #GtkStyleContext
49  * queries information from all attached #GtkStyleProviders. Style providers
50  * can be either attached explicitly to the context through
51  * gtk_style_context_add_provider(), or to the screen through
52  * gtk_style_context_add_provider_for_screen(). The resulting style is a
53  * combination of all providers' information in priority order.
54  *
55  * For GTK+ widgets, any #GtkStyleContext returned by
56  * gtk_widget_get_style_context() will already have a #GtkWidgetPath, a
57  * #GdkScreen and RTL/LTR information set. The style context will be also
58  * updated automatically if any of these settings change on the widget.
59  *
60  * If you are using the theming layer standalone, you will need to set a
61  * widget path and a screen yourself to the created style context through
62  * gtk_style_context_set_path() and gtk_style_context_set_screen(), as well
63  * as updating the context yourself using gtk_style_context_invalidate()
64  * whenever any of the conditions change, such as a change in the
65  * #GtkSettings:gtk-theme-name setting or a hierarchy change in the rendered
66  * widget.
67  *
68  * <refsect2 id="gtkstylecontext-animations">
69  * <title>Transition animations</title>
70  * <para>
71  * #GtkStyleContext has built-in support for state change transitions.
72  * Note that these animations respect the #GtkSettings:gtk-enable-animations
73  * setting.
74  * </para>
75  * <para>
76  * For simple widgets where state changes affect the whole widget area,
77  * calling gtk_style_context_notify_state_change() with a %NULL region
78  * is sufficient to trigger the transition animation. And GTK+ already
79  * does that when gtk_widget_set_state() or gtk_widget_set_state_flags()
80  * are called.
81  * </para>
82  * <para>
83  * If a widget needs to declare several animatable regions (i.e. not
84  * affecting the whole widget area), its #GtkWidget::draw signal handler
85  * needs to wrap the render operations for the different regions with
86  * calls to gtk_style_context_push_animatable_region() and
87  * gtk_style_context_pop_animatable_region(). These functions take an
88  * identifier for the region which must be unique within the style context.
89  * For simple widgets with a fixed set of animatable regions, using an
90  * enumeration works well:
91  * </para>
92  * <example>
93  * <title>Using an enumeration to identify  animatable regions</title>
94  * <programlisting>
95  * enum {
96  *   REGION_ENTRY,
97  *   REGION_BUTTON_UP,
98  *   REGION_BUTTON_DOWN
99  * };
100  *
101  * ...
102  *
103  * gboolean
104  * spin_button_draw (GtkWidget *widget,
105  *                   cairo_t   *cr)
106  * {
107  *   GtkStyleContext *context;
108  *
109  *   context = gtk_widget_get_style_context (widget);
110  *
111  *   gtk_style_context_push_animatable_region (context,
112  *                                             GUINT_TO_POINTER (REGION_ENTRY));
113  *
114  *   gtk_render_background (cr, 0, 0, 100, 30);
115  *   gtk_render_frame (cr, 0, 0, 100, 30);
116  *
117  *   gtk_style_context_pop_animatable_region (context);
118  *
119  *   ...
120  * }
121  * </programlisting>
122  * </example>
123  * <para>
124  * For complex widgets with an arbitrary number of animatable regions, it
125  * is up to the implementation to come up with a way to uniquely identify
126  * each animatable region. Using pointers to internal structs is one way
127  * to achieve this:
128  * </para>
129  * <example>
130  * <title>Using struct pointers to identify animatable regions</title>
131  * <programlisting>
132  * void
133  * notebook_draw_tab (GtkWidget    *widget,
134  *                    NotebookPage *page,
135  *                    cairo_t      *cr)
136  * {
137  *   gtk_style_context_push_animatable_region (context, page);
138  *   gtk_render_extension (cr, page->x, page->y, page->width, page->height);
139  *   gtk_style_context_pop_animatable_region (context);
140  * }
141  * </programlisting>
142  * </example>
143  * <para>
144  * The widget also needs to notify the style context about a state change
145  * for a given animatable region so the animation is triggered.
146  * </para>
147  * <example>
148  * <title>Triggering a state change animation on a region</title>
149  * <programlisting>
150  * gboolean
151  * notebook_motion_notify (GtkWidget      *widget,
152  *                         GdkEventMotion *event)
153  * {
154  *   GtkStyleContext *context;
155  *   NotebookPage *page;
156  *
157  *   context = gtk_widget_get_style_context (widget);
158  *   page = find_page_under_pointer (widget, event);
159  *   gtk_style_context_notify_state_change (context,
160  *                                          gtk_widget_get_window (widget),
161  *                                          page,
162  *                                          GTK_STATE_PRELIGHT,
163  *                                          TRUE);
164  *   ...
165  * }
166  * </programlisting>
167  * </example>
168  * <para>
169  * gtk_style_context_notify_state_change() accepts %NULL region IDs as a
170  * special value, in this case, the whole widget area will be updated
171  * by the animation.
172  * </para>
173  * </refsect2>
174  * <refsect2 id="gtkstylecontext-classes">
175  * <title>Style classes and regions</title>
176  * <para>
177  * Widgets can add style classes to their context, which can be used
178  * to associate different styles by class (see <xref linkend="gtkcssprovider-selectors"/>). Theme engines can also use style classes to vary their
179  * rendering. GTK+ has a number of predefined style classes:
180  * <informaltable>
181  *   <tgroup cols="3">
182  *     <thead>
183  *       <row>
184  *         <entry>Style class</entry>
185  *         <entry>Macro</entry>
186  *         <entry>Used by</entry>
187  *       </row>
188  *     </thead>
189  *     <tbody>
190  *       <row>
191  *         <entry>button</entry>
192  *         <entry>GTK_STYLE_CLASS_BUTTON</entry>
193  *         <entry>#GtkButton, #GtkToggleButton, #GtkRadioButton, #GtkCheckButton</entry>
194  *       </row>
195  *       <row>
196  *         <entry>default</entry>
197  *         <entry>GTK_STYLE_CLASS_DEFAULT</entry>
198  *         <entry>#GtkButton</entry>
199  *       </row>
200  *       <row>
201  *         <entry>check</entry>
202  *         <entry>GTK_STYLE_CLASS_CHECK</entry>
203  *         <entry>#GtkCheckButton, #GtkCheckMenuItem, #GtkCellRendererToggle</entry>
204  *       </row>
205  *       <row>
206  *         <entry>radio</entry>
207  *         <entry>GTK_STYLE_CLASS_RADIO</entry>
208  *         <entry>#GtkRadioButton, #GtkRadioMenuItem, #GtkCellRendererToggle</entry>
209  *       </row>
210  *       <row>
211  *         <entry>arrow</entry>
212  *         <entry>GTK_STYLE_CLASS_ARROW</entry>
213  *         <entry>#GtkArrow</entry>
214  *       </row>
215  *       <row>
216  *         <entry>calendar</entry>
217  *         <entry>GTK_STYLE_CLASS_CALENDAR</entry>
218  *         <entry>#GtkCalendar</entry>
219  *       </row>
220  *       <row>
221  *         <entry>entry</entry>
222  *         <entry>GTK_STYLE_CLASS_ENTRY</entry>
223  *         <entry>#GtkEntry</entry>
224  *       </row>
225  *       <row>
226  *         <entry>cell</entry>
227  *         <entry>GTK_STYLE_CLASS_CELL</entry>
228  *         <entry>#GtkCellRendererToggle</entry>
229  *       </row>
230  *       <row>
231  *         <entry>menu</entry>
232  *         <entry>GTK_STYLE_CLASS_MENU</entry>
233  *         <entry>#GtkMenu, #GtkMenuItem, #GtkCheckMenuItem, #GtkRadioMenuItem</entry>
234  *       </row>
235  *       <row>
236  *         <entry>expander</entry>
237  *         <entry>GTK_STYLE_CLASS_EXPANDER</entry>
238  *         <entry>#GtkExpander</entry>
239  *       </row>
240  *       <row>
241  *         <entry>tooltip</entry>
242  *         <entry>GTK_STYLE_CLASS_TOOLTIP</entry>
243  *         <entry>#GtkTooltip</entry>
244  *       </row>
245  *       <row>
246  *         <entry>frame</entry>
247  *         <entry>GTK_STYLE_CLASS_FRAME</entry>
248  *         <entry>#GtkFrame</entry>
249  *       </row>
250  *       <row>
251  *         <entry>scrolled-window</entry>
252  *         <entry></entry>
253  *         <entry>#GtkScrolledWindow</entry>
254  *       </row>
255  *       <row>
256  *         <entry>viewport</entry>
257  *         <entry></entry>
258  *         <entry>#GtkViewport</entry>
259  *       </row>
260  *       <row>
261  *         <entry>trough</entry>
262  *         <entry>GTK_STYLE_CLASS_TROUGH</entry>
263  *         <entry>#GtkScrollbar, #GtkProgressBar, #GtkScale</entry>
264  *       </row>
265  *       <row>
266  *         <entry>progressbar</entry>
267  *         <entry>GTK_STYLE_CLASS_PROGRESSBAR</entry>
268  *         <entry>#GtkProgressBar, #GtkCellRendererProgress</entry>
269  *       </row>
270  *       <row>
271  *         <entry>slider</entry>
272  *         <entry>GTK_STYLE_CLASS_SLIDER</entry>
273  *         <entry>#GtkScrollbar, #GtkScale</entry>
274  *       </row>
275  *       <row>
276  *         <entry>menuitem</entry>
277  *         <entry>GTK_STYLE_CLASS_MENUITEM</entry>
278  *         <entry>#GtkMenuItem</entry>
279  *       </row>
280  *       <row>
281  *         <entry>popup</entry>
282  *         <entry></entry>
283  *         <entry>#GtkMenu</entry>
284  *       </row>
285  *       <row>
286  *         <entry>accelerator</entry>
287  *         <entry>GTK_STYLE_CLASS_ACCELERATOR</entry>
288  *         <entry>#GtkAccelLabel</entry>
289  *       </row>
290  *       <row>
291  *         <entry>menubar</entry>
292  *         <entry>GTK_STYLE_CLASS_MENUBAR</entry>
293  *         <entry>#GtkMenuBar</entry>
294  *       </row>
295  *       <row>
296  *         <entry>toolbar</entry>
297  *         <entry>GTK_STYLE_CLASS_TOOLBAR</entry>
298  *         <entry>#GtkToolbar</entry>
299  *       </row>
300  *       <row>
301  *         <entry>dock</entry>
302  *         <entry>GTK_STYLE_CLASS_DOCK</entry>
303  *         <entry>#GtkHandleBox</entry>
304  *       </row>
305  *       <row>
306  *         <entry>notebook</entry>
307  *         <entry></entry>
308  *         <entry>#GtkNotebook</entry>
309  *       </row>
310  *       <row>
311  *         <entry>background</entry>
312  *         <entry>GTK_STYLE_CLASS_BACKGROUND</entry>
313  *         <entry>#GtkWindow</entry>
314  *       </row>
315  *       <row>
316  *         <entry>rubberband</entry>
317  *         <entry>GTK_STYLE_CLASS_RUBBERBAND</entry>
318  *         <entry></entry>
319  *       </row>
320  *       <row>
321  *         <entry>header</entry>
322  *         <entry>GTK_STYLE_CLASS_HEADER</entry>
323  *         <entry></entry>
324  *       </row>
325  *       <row>
326  *         <entry>grip</entry>
327  *         <entry>GTK_STYLE_CLASS_GRIP</entry>
328  *         <entry>#GtkWindow</entry>
329  *       </row>
330  *       <row>
331  *         <entry>spinner</entry>
332  *         <entry>GTK_STYLE_CLASS_SPINNER</entry>
333  *         <entry>#GtkSpinner</entry>
334  *       </row>
335  *     </tbody>
336  *   </tgroup>
337  * </informaltable>
338  * </para>
339  * <para>
340  * Widgets can also add regions with flags to their context.
341  * The regions used by GTK+ widgets are:
342  * <informaltable>
343  *   <tgroup cols="4">
344  *     <thead>
345  *       <row>
346  *         <entry>Region</entry>
347  *         <entry>Flags</entry>
348  *         <entry>Macro</entry>
349  *         <entry>Used by</entry>
350  *       </row>
351  *     </thead>
352  *     <tbody>
353  *       <row>
354  *         <entry>row</entry>
355  *         <entry>even, odd</entry>
356  *         <entry>GTK_STYLE_REGION_ROW</entry>
357  *         <entry>#GtkTreeView</entry>
358  *       </row>
359  *       <row>
360  *         <entry>column</entry>
361  *         <entry>first, last, sorted</entry>
362  *         <entry>GTK_STYLE_REGION_COLUMN</entry>
363  *         <entry>#GtkTreeView</entry>
364  *       </row>
365  *       <row>
366  *         <entry>column-header</entry>
367  *         <entry></entry>
368  *         <entry>GTK_STYLE_REGION_COLUMN_HEADER</entry>
369  *         <entry></entry>
370  *       </row>
371  *       <row>
372  *         <entry>tab</entry>
373  *         <entry>even, odd, first, last</entry>
374  *         <entry>GTK_STYLE_REGION_TAB</entry>
375  *         <entry>#GtkNotebook</entry>
376  *       </row>
377  *     </tbody>
378  *   </tgroup>
379  * </informaltable>
380  * </para>
381  * </refsect2>
382  * <refsect2 id="gtkstylecontext-custom-styling">
383  * <title>Custom styling in UI libraries and applications</title>
384  * <para>
385  * If you are developing a library with custom #GtkWidget<!-- -->s that
386  * render differently than standard components, you may need to add a
387  * #GtkStyleProvider yourself with the %GTK_STYLE_PROVIDER_PRIORITY_FALLBACK
388  * priority, either a #GtkCssProvider or a custom object implementing the
389  * #GtkStyleProvider interface. This way theming engines may still attempt
390  * to style your UI elements in a different way if needed so.
391  * </para>
392  * <para>
393  * If you are using custom styling on an applications, you probably want then
394  * to make your style information prevail to the theme's, so you must use
395  * a #GtkStyleProvider with the %GTK_STYLE_PROVIDER_PRIORITY_APPLICATION
396  * priority, keep in mind that the user settings in
397  * <filename><replaceable>XDG_CONFIG_HOME</replaceable>/gtk-3.0/gtk.css</filename> will
398  * still take precedence over your changes, as it uses the
399  * %GTK_STYLE_PROVIDER_PRIORITY_USER priority.
400  * </para>
401  * <para>
402  * If a custom theming engine is needed, you probably want to implement a
403  * #GtkStyleProvider yourself so it points to your #GtkThemingEngine
404  * implementation, as #GtkCssProvider uses gtk_theming_engine_load()
405  * which loads the theming engine module from the standard paths.
406  * </para>
407  * </refsect2>
408  */
409
410 typedef struct GtkStyleProviderData GtkStyleProviderData;
411 typedef struct GtkStyleInfo GtkStyleInfo;
412 typedef struct GtkRegion GtkRegion;
413 typedef struct PropertyValue PropertyValue;
414 typedef struct AnimationInfo AnimationInfo;
415 typedef struct StyleData StyleData;
416
417 struct GtkRegion
418 {
419   GQuark class_quark;
420   GtkRegionFlags flags;
421 };
422
423 struct GtkStyleProviderData
424 {
425   GtkStyleProvider *provider;
426   guint priority;
427 };
428
429 struct PropertyValue
430 {
431   GType       widget_type;
432   GParamSpec *pspec;
433   GtkStateFlags state;
434   GValue      value;
435 };
436
437 struct GtkStyleInfo
438 {
439   GArray *style_classes;
440   GArray *regions;
441   GtkJunctionSides junction_sides;
442   GtkStateFlags state_flags;
443 };
444
445 struct StyleData
446 {
447   GtkStyleProperties *store;
448   GSList *icon_factories;
449   GArray *property_cache;
450 };
451
452 struct AnimationInfo
453 {
454   GtkTimeline *timeline;
455
456   gpointer region_id;
457
458   /* Region stack (until region_id) at the time of
459    * rendering, this is used for nested cancellation.
460    */
461   GSList *parent_regions;
462
463   GdkWindow *window;
464   GtkStateType state;
465   gboolean target_value;
466
467   cairo_region_t *invalidation_region;
468   GArray *rectangles;
469 };
470
471 struct _GtkStyleContextPrivate
472 {
473   GdkScreen *screen;
474
475   GList *providers;
476   GList *providers_last;
477
478   GtkWidgetPath *widget_path;
479   GHashTable *style_data;
480   GSList *info_stack;
481   StyleData *current_data;
482
483   GSList *animation_regions;
484   GSList *animations;
485
486   GtkThemingEngine *theming_engine;
487
488   GtkTextDirection direction;
489
490   guint animations_invalidated : 1;
491   guint invalidating_context : 1;
492 };
493
494 enum {
495   PROP_0,
496   PROP_SCREEN,
497   PROP_DIRECTION
498 };
499
500 enum {
501   CHANGED,
502   LAST_SIGNAL
503 };
504
505 static guint signals[LAST_SIGNAL] = { 0 };
506
507 static GQuark provider_list_quark = 0;
508 static GdkRGBA fallback_color = { 1.0, 0.75, 0.75, 1.0 };
509 static GtkBorder fallback_border = { 0 };
510
511 static void gtk_style_context_finalize (GObject *object);
512
513 static void gtk_style_context_impl_set_property (GObject      *object,
514                                                  guint         prop_id,
515                                                  const GValue *value,
516                                                  GParamSpec   *pspec);
517 static void gtk_style_context_impl_get_property (GObject      *object,
518                                                  guint         prop_id,
519                                                  GValue       *value,
520                                                  GParamSpec   *pspec);
521
522
523 G_DEFINE_TYPE (GtkStyleContext, gtk_style_context, G_TYPE_OBJECT)
524
525 static void
526 gtk_style_context_class_init (GtkStyleContextClass *klass)
527 {
528   GObjectClass *object_class = G_OBJECT_CLASS (klass);
529
530   object_class->finalize = gtk_style_context_finalize;
531   object_class->set_property = gtk_style_context_impl_set_property;
532   object_class->get_property = gtk_style_context_impl_get_property;
533
534   signals[CHANGED] =
535     g_signal_new (I_("changed"),
536                   G_TYPE_FROM_CLASS (object_class),
537                   G_SIGNAL_RUN_FIRST,
538                   G_STRUCT_OFFSET (GtkStyleContextClass, changed),
539                   NULL, NULL,
540                   g_cclosure_marshal_VOID__VOID,
541                   G_TYPE_NONE, 0);
542
543   g_object_class_install_property (object_class,
544                                    PROP_SCREEN,
545                                    g_param_spec_object ("screen",
546                                                         P_("Screen"),
547                                                         P_("The associated GdkScreen"),
548                                                         GDK_TYPE_SCREEN,
549                                                         GTK_PARAM_READWRITE));
550   g_object_class_install_property (object_class,
551                                    PROP_DIRECTION,
552                                    g_param_spec_enum ("direction",
553                                                       P_("Direction"),
554                                                       P_("Text direction"),
555                                                       GTK_TYPE_TEXT_DIRECTION,
556                                                       GTK_TEXT_DIR_LTR,
557                                                       GTK_PARAM_READWRITE));
558
559   g_type_class_add_private (object_class, sizeof (GtkStyleContextPrivate));
560 }
561
562 static GtkStyleInfo *
563 style_info_new (void)
564 {
565   GtkStyleInfo *info;
566
567   info = g_slice_new0 (GtkStyleInfo);
568   info->style_classes = g_array_new (FALSE, FALSE, sizeof (GQuark));
569   info->regions = g_array_new (FALSE, FALSE, sizeof (GtkRegion));
570
571   return info;
572 }
573
574 static void
575 style_info_free (GtkStyleInfo *info)
576 {
577   g_array_free (info->style_classes, TRUE);
578   g_array_free (info->regions, TRUE);
579   g_slice_free (GtkStyleInfo, info);
580 }
581
582 static GtkStyleInfo *
583 style_info_copy (const GtkStyleInfo *info)
584 {
585   GtkStyleInfo *copy;
586
587   copy = style_info_new ();
588   g_array_insert_vals (copy->style_classes, 0,
589                        info->style_classes->data,
590                        info->style_classes->len);
591
592   g_array_insert_vals (copy->regions, 0,
593                        info->regions->data,
594                        info->regions->len);
595
596   copy->junction_sides = info->junction_sides;
597   copy->state_flags = info->state_flags;
598
599   return copy;
600 }
601
602 static guint
603 style_info_hash (gconstpointer elem)
604 {
605   const GtkStyleInfo *info;
606   guint i, hash = 0;
607
608   info = elem;
609
610   for (i = 0; i < info->style_classes->len; i++)
611     {
612       hash += g_array_index (info->style_classes, GQuark, i);
613       hash <<= 5;
614     }
615
616   for (i = 0; i < info->regions->len; i++)
617     {
618       GtkRegion *region;
619
620       region = &g_array_index (info->regions, GtkRegion, i);
621       hash += region->class_quark;
622       hash += region->flags;
623       hash <<= 5;
624     }
625
626   return hash;
627 }
628
629 static gboolean
630 style_info_equal (gconstpointer elem1,
631                   gconstpointer elem2)
632 {
633   const GtkStyleInfo *info1, *info2;
634
635   info1 = elem1;
636   info2 = elem2;
637
638   if (info1->junction_sides != info2->junction_sides)
639     return FALSE;
640
641   if (info1->style_classes->len != info2->style_classes->len)
642     return FALSE;
643
644   if (memcmp (info1->style_classes->data,
645               info2->style_classes->data,
646               info1->style_classes->len * sizeof (GQuark)) != 0)
647     return FALSE;
648
649   if (info1->regions->len != info2->regions->len)
650     return FALSE;
651
652   if (memcmp (info1->regions->data,
653               info2->regions->data,
654               info1->regions->len * sizeof (GtkRegion)) != 0)
655     return FALSE;
656
657   return TRUE;
658 }
659
660 static StyleData *
661 style_data_new (void)
662 {
663   StyleData *data;
664
665   data = g_slice_new0 (StyleData);
666   data->store = gtk_style_properties_new ();
667
668   return data;
669 }
670
671 static void
672 clear_property_cache (StyleData *data)
673 {
674   guint i;
675
676   if (!data->property_cache)
677     return;
678
679   for (i = 0; i < data->property_cache->len; i++)
680     {
681       PropertyValue *node = &g_array_index (data->property_cache, PropertyValue, i);
682
683       g_param_spec_unref (node->pspec);
684       g_value_unset (&node->value);
685     }
686
687   g_array_free (data->property_cache, TRUE);
688   data->property_cache = NULL;
689 }
690
691 static void
692 style_data_free (StyleData *data)
693 {
694   g_object_unref (data->store);
695   clear_property_cache (data);
696
697   g_slist_foreach (data->icon_factories, (GFunc) g_object_unref, NULL);
698   g_slist_free (data->icon_factories);
699
700   g_slice_free (StyleData, data);
701 }
702
703 static void
704 gtk_style_context_init (GtkStyleContext *style_context)
705 {
706   GtkStyleContextPrivate *priv;
707   GtkStyleInfo *info;
708
709   priv = style_context->priv = G_TYPE_INSTANCE_GET_PRIVATE (style_context,
710                                                             GTK_TYPE_STYLE_CONTEXT,
711                                                             GtkStyleContextPrivate);
712
713   priv->style_data = g_hash_table_new_full (style_info_hash,
714                                             style_info_equal,
715                                             (GDestroyNotify) style_info_free,
716                                             (GDestroyNotify) style_data_free);
717   priv->theming_engine = g_object_ref ((gpointer) gtk_theming_engine_load (NULL));
718
719   priv->direction = GTK_TEXT_DIR_LTR;
720
721   priv->screen = gdk_screen_get_default ();
722
723   /* Create default info store */
724   info = style_info_new ();
725   priv->info_stack = g_slist_prepend (priv->info_stack, info);
726 }
727
728 static GtkStyleProviderData *
729 style_provider_data_new (GtkStyleProvider *provider,
730                          guint             priority)
731 {
732   GtkStyleProviderData *data;
733
734   data = g_slice_new (GtkStyleProviderData);
735   data->provider = g_object_ref (provider);
736   data->priority = priority;
737
738   return data;
739 }
740
741 static void
742 style_provider_data_free (GtkStyleProviderData *data)
743 {
744   g_object_unref (data->provider);
745   g_slice_free (GtkStyleProviderData, data);
746 }
747
748 static void
749 animation_info_free (AnimationInfo *info)
750 {
751   g_object_unref (info->timeline);
752   g_object_unref (info->window);
753
754   if (info->invalidation_region)
755     cairo_region_destroy (info->invalidation_region);
756
757   g_array_free (info->rectangles, TRUE);
758   g_slist_free (info->parent_regions);
759   g_slice_free (AnimationInfo, info);
760 }
761
762 static AnimationInfo *
763 animation_info_lookup_by_timeline (GtkStyleContext *context,
764                                    GtkTimeline     *timeline)
765 {
766   GtkStyleContextPrivate *priv;
767   AnimationInfo *info;
768   GSList *l;
769
770   priv = context->priv;
771
772   for (l = priv->animations; l; l = l->next)
773     {
774       info = l->data;
775
776       if (info->timeline == timeline)
777         return info;
778     }
779
780   return NULL;
781 }
782
783 static void
784 timeline_frame_cb (GtkTimeline *timeline,
785                    gdouble      progress,
786                    gpointer     user_data)
787 {
788   GtkStyleContextPrivate *priv;
789   GtkStyleContext *context;
790   AnimationInfo *info;
791
792   context = user_data;
793   priv = context->priv;
794   info = animation_info_lookup_by_timeline (context, timeline);
795
796   g_assert (info != NULL);
797
798   /* Cancel transition if window is gone */
799   if (gdk_window_is_destroyed (info->window) ||
800       !gdk_window_is_visible (info->window))
801     {
802       priv->animations = g_slist_remove (priv->animations, info);
803       animation_info_free (info);
804       return;
805     }
806
807   if (info->invalidation_region &&
808       !cairo_region_is_empty (info->invalidation_region))
809     gdk_window_invalidate_region (info->window, info->invalidation_region, TRUE);
810   else
811     gdk_window_invalidate_rect (info->window, NULL, TRUE);
812 }
813
814 static void
815 timeline_finished_cb (GtkTimeline *timeline,
816                       gpointer     user_data)
817 {
818   GtkStyleContextPrivate *priv;
819   GtkStyleContext *context;
820   AnimationInfo *info;
821
822   context = user_data;
823   priv = context->priv;
824   info = animation_info_lookup_by_timeline (context, timeline);
825
826   g_assert (info != NULL);
827
828   priv->animations = g_slist_remove (priv->animations, info);
829
830   /* Invalidate one last time the area, so the final content is painted */
831   if (info->invalidation_region &&
832       !cairo_region_is_empty (info->invalidation_region))
833     gdk_window_invalidate_region (info->window, info->invalidation_region, TRUE);
834   else
835     gdk_window_invalidate_rect (info->window, NULL, TRUE);
836
837   animation_info_free (info);
838 }
839
840 static AnimationInfo *
841 animation_info_new (GtkStyleContext         *context,
842                     gpointer                 region_id,
843                     guint                    duration,
844                     GtkTimelineProgressType  progress_type,
845                     gboolean                 loop,
846                     GtkStateType             state,
847                     gboolean                 target_value,
848                     GdkWindow               *window)
849 {
850   AnimationInfo *info;
851
852   info = g_slice_new0 (AnimationInfo);
853
854   info->rectangles = g_array_new (FALSE, FALSE, sizeof (cairo_rectangle_int_t));
855   info->timeline = _gtk_timeline_new (duration);
856   info->window = g_object_ref (window);
857   info->state = state;
858   info->target_value = target_value;
859   info->region_id = region_id;
860
861   _gtk_timeline_set_progress_type (info->timeline, progress_type);
862   _gtk_timeline_set_loop (info->timeline, loop);
863
864   if (!loop && !target_value)
865     {
866       _gtk_timeline_set_direction (info->timeline, GTK_TIMELINE_DIRECTION_BACKWARD);
867       _gtk_timeline_rewind (info->timeline);
868     }
869
870   g_signal_connect (info->timeline, "frame",
871                     G_CALLBACK (timeline_frame_cb), context);
872   g_signal_connect (info->timeline, "finished",
873                     G_CALLBACK (timeline_finished_cb), context);
874
875   _gtk_timeline_start (info->timeline);
876
877   return info;
878 }
879
880 static AnimationInfo *
881 animation_info_lookup (GtkStyleContext *context,
882                        gpointer         region_id,
883                        GtkStateType     state)
884 {
885   GtkStyleContextPrivate *priv;
886   GSList *l;
887
888   priv = context->priv;
889
890   for (l = priv->animations; l; l = l->next)
891     {
892       AnimationInfo *info;
893
894       info = l->data;
895
896       if (info->state == state &&
897           info->region_id == region_id)
898         return info;
899     }
900
901   return NULL;
902 }
903
904 static void
905 gtk_style_context_finalize (GObject *object)
906 {
907   GtkStyleContextPrivate *priv;
908   GtkStyleContext *style_context;
909   GSList *l;
910
911   style_context = GTK_STYLE_CONTEXT (object);
912   priv = style_context->priv;
913
914   if (priv->widget_path)
915     gtk_widget_path_free (priv->widget_path);
916
917   g_hash_table_destroy (priv->style_data);
918
919   g_list_foreach (priv->providers, (GFunc) style_provider_data_free, NULL);
920   g_list_free (priv->providers);
921
922   g_slist_foreach (priv->info_stack, (GFunc) style_info_free, NULL);
923   g_slist_free (priv->info_stack);
924
925   g_slist_free (priv->animation_regions);
926
927   for (l = priv->animations; l; l = l->next)
928     animation_info_free ((AnimationInfo *) l->data);
929
930   g_slist_free (priv->animations);
931
932   if (priv->theming_engine)
933     g_object_unref (priv->theming_engine);
934
935   G_OBJECT_CLASS (gtk_style_context_parent_class)->finalize (object);
936 }
937
938 static void
939 gtk_style_context_impl_set_property (GObject      *object,
940                                      guint         prop_id,
941                                      const GValue *value,
942                                      GParamSpec   *pspec)
943 {
944   GtkStyleContext *style_context;
945
946   style_context = GTK_STYLE_CONTEXT (object);
947
948   switch (prop_id)
949     {
950     case PROP_SCREEN:
951       gtk_style_context_set_screen (style_context,
952                                     g_value_get_object (value));
953       break;
954     case PROP_DIRECTION:
955       gtk_style_context_set_direction (style_context,
956                                        g_value_get_enum (value));
957       break;
958     default:
959       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
960       break;
961     }
962 }
963
964 static void
965 gtk_style_context_impl_get_property (GObject    *object,
966                                      guint       prop_id,
967                                      GValue     *value,
968                                      GParamSpec *pspec)
969 {
970   GtkStyleContext *style_context;
971   GtkStyleContextPrivate *priv;
972
973   style_context = GTK_STYLE_CONTEXT (object);
974   priv = style_context->priv;
975
976   switch (prop_id)
977     {
978     case PROP_SCREEN:
979       g_value_set_object (value, priv->screen);
980       break;
981     case PROP_DIRECTION:
982       g_value_set_enum (value, priv->direction);
983       break;
984     default:
985       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
986       break;
987     }
988 }
989
990 static GList *
991 find_next_candidate (GList    *local,
992                      GList    *global,
993                      gboolean  ascending)
994 {
995   if (local && global)
996     {
997       GtkStyleProviderData *local_data, *global_data;
998
999       local_data = local->data;
1000       global_data = global->data;
1001
1002       if (local_data->priority < global_data->priority)
1003         return (ascending) ? local : global;
1004       else
1005         return (ascending) ? global : local;
1006     }
1007   else if (local)
1008     return local;
1009   else if (global)
1010     return global;
1011
1012   return NULL;
1013 }
1014
1015 static void
1016 build_properties (GtkStyleContext *context,
1017                   StyleData       *style_data,
1018                   GtkWidgetPath   *path)
1019 {
1020   GtkStyleContextPrivate *priv;
1021   GList *elem, *list, *global_list = NULL;
1022
1023   priv = context->priv;
1024   list = priv->providers;
1025
1026   if (priv->screen)
1027     global_list = g_object_get_qdata (G_OBJECT (priv->screen), provider_list_quark);
1028
1029   while ((elem = find_next_candidate (list, global_list, TRUE)) != NULL)
1030     {
1031       GtkStyleProviderData *data;
1032       GtkStyleProperties *provider_style;
1033
1034       data = elem->data;
1035
1036       if (elem == list)
1037         list = list->next;
1038       else
1039         global_list = global_list->next;
1040
1041       provider_style = gtk_style_provider_get_style (data->provider, path);
1042
1043       if (provider_style)
1044         {
1045           gtk_style_properties_merge (style_data->store, provider_style, TRUE);
1046           g_object_unref (provider_style);
1047         }
1048     }
1049 }
1050
1051 static void
1052 build_icon_factories (GtkStyleContext *context,
1053                       StyleData       *style_data,
1054                       GtkWidgetPath   *path)
1055 {
1056   GtkStyleContextPrivate *priv;
1057   GList *elem, *list, *global_list = NULL;
1058
1059   priv = context->priv;
1060   list = priv->providers_last;
1061
1062   if (priv->screen)
1063     {
1064       global_list = g_object_get_qdata (G_OBJECT (priv->screen), provider_list_quark);
1065       global_list = g_list_last (global_list);
1066     }
1067
1068   while ((elem = find_next_candidate (list, global_list, FALSE)) != NULL)
1069     {
1070       GtkIconFactory *factory;
1071       GtkStyleProviderData *data;
1072
1073       data = elem->data;
1074
1075       if (elem == list)
1076         list = list->prev;
1077       else
1078         global_list = global_list->prev;
1079
1080       factory = gtk_style_provider_get_icon_factory (data->provider, path);
1081
1082       if (factory)
1083         style_data->icon_factories = g_slist_prepend (style_data->icon_factories, factory);
1084     }
1085 }
1086
1087 static GtkWidgetPath *
1088 create_query_path (GtkStyleContext *context)
1089 {
1090   GtkStyleContextPrivate *priv;
1091   GtkWidgetPath *path;
1092   GtkStyleInfo *info;
1093   guint i, pos;
1094
1095   priv = context->priv;
1096   path = gtk_widget_path_copy (priv->widget_path);
1097   pos = gtk_widget_path_length (path) - 1;
1098
1099   info = priv->info_stack->data;
1100
1101   /* Set widget regions */
1102   for (i = 0; i < info->regions->len; i++)
1103     {
1104       GtkRegion *region;
1105
1106       region = &g_array_index (info->regions, GtkRegion, i);
1107       gtk_widget_path_iter_add_region (path, pos,
1108                                        g_quark_to_string (region->class_quark),
1109                                        region->flags);
1110     }
1111
1112   /* Set widget classes */
1113   for (i = 0; i < info->style_classes->len; i++)
1114     {
1115       GQuark quark;
1116
1117       quark = g_array_index (info->style_classes, GQuark, i);
1118       gtk_widget_path_iter_add_class (path, pos,
1119                                       g_quark_to_string (quark));
1120     }
1121
1122   return path;
1123 }
1124
1125 static StyleData *
1126 style_data_lookup (GtkStyleContext *context)
1127 {
1128   GtkStyleContextPrivate *priv;
1129   StyleData *data;
1130
1131   priv = context->priv;
1132
1133   /* Current data in use is cached, just return it */
1134   if (priv->current_data)
1135     return priv->current_data;
1136
1137   g_assert (priv->widget_path != NULL);
1138
1139   data = g_hash_table_lookup (priv->style_data, priv->info_stack->data);
1140
1141   if (!data)
1142     {
1143       GtkWidgetPath *path;
1144
1145       data = style_data_new ();
1146       path = create_query_path (context);
1147
1148       build_properties (context, data, path);
1149       build_icon_factories (context, data, path);
1150
1151       g_hash_table_insert (priv->style_data,
1152                            style_info_copy (priv->info_stack->data),
1153                            data);
1154
1155       gtk_widget_path_free (path);
1156     }
1157
1158   priv->current_data = data;
1159
1160   if (priv->theming_engine)
1161     g_object_unref (priv->theming_engine);
1162
1163   gtk_style_properties_get (data->store, 0,
1164                             "engine", &priv->theming_engine,
1165                             NULL);
1166
1167   if (!priv->theming_engine)
1168     priv->theming_engine = g_object_ref (gtk_theming_engine_load (NULL));
1169
1170   return data;
1171 }
1172
1173 static void
1174 style_provider_add (GList            **list,
1175                     GtkStyleProvider  *provider,
1176                     guint              priority)
1177 {
1178   GtkStyleProviderData *new_data;
1179   gboolean added = FALSE;
1180   GList *l = *list;
1181
1182   new_data = style_provider_data_new (provider, priority);
1183
1184   while (l)
1185     {
1186       GtkStyleProviderData *data;
1187
1188       data = l->data;
1189
1190       /* Provider was already attached to the style
1191        * context, remove in order to add the new data
1192        */
1193       if (data->provider == provider)
1194         {
1195           GList *link;
1196
1197           link = l;
1198           l = l->next;
1199
1200           /* Remove and free link */
1201           *list = g_list_remove_link (*list, link);
1202           style_provider_data_free (link->data);
1203           g_list_free_1 (link);
1204
1205           continue;
1206         }
1207
1208       if (!added &&
1209           data->priority > priority)
1210         {
1211           *list = g_list_insert_before (*list, l, new_data);
1212           added = TRUE;
1213         }
1214
1215       l = l->next;
1216     }
1217
1218   if (!added)
1219     *list = g_list_append (*list, new_data);
1220 }
1221
1222 static gboolean
1223 style_provider_remove (GList            **list,
1224                        GtkStyleProvider  *provider)
1225 {
1226   GList *l = *list;
1227
1228   while (l)
1229     {
1230       GtkStyleProviderData *data;
1231
1232       data = l->data;
1233
1234       if (data->provider == provider)
1235         {
1236           *list = g_list_remove_link (*list, l);
1237           style_provider_data_free (l->data);
1238           g_list_free_1 (l);
1239
1240           return TRUE;
1241         }
1242
1243       l = l->next;
1244     }
1245
1246   return FALSE;
1247 }
1248
1249 /**
1250  * gtk_style_context_new:
1251  *
1252  * Creates a standalone #GtkStyleContext, this style context
1253  * won't be attached to any widget, so you may want
1254  * to call gtk_style_context_set_path() yourself.
1255  *
1256  * <note>
1257  * This function is only useful when using the theming layer
1258  * separated from GTK+, if you are using #GtkStyleContext to
1259  * theme #GtkWidget<!-- -->s, use gtk_widget_get_style_context()
1260  * in order to get a style context ready to theme the widget.
1261  * </note>
1262  *
1263  * Returns: A newly created #GtkStyleContext.
1264  **/
1265 GtkStyleContext *
1266 gtk_style_context_new (void)
1267 {
1268   return g_object_new (GTK_TYPE_STYLE_CONTEXT, NULL);
1269 }
1270
1271 /**
1272  * gtk_style_context_add_provider:
1273  * @context: a #GtkStyleContext
1274  * @provider: a #GtkStyleProvider
1275  * @priority: the priority of the style provider. The lower
1276  *            it is, the earlier it will be used in the style
1277  *            construction. Typically this will be in the range
1278  *            between %GTK_STYLE_PROVIDER_PRIORITY_FALLBACK and
1279  *            %GTK_STYLE_PROVIDER_PRIORITY_USER
1280  *
1281  * Adds a style provider to @context, to be used in style construction.
1282  *
1283  * <note><para>If both priorities are the same, A #GtkStyleProvider
1284  * added through this function takes precedence over another added
1285  * through gtk_style_context_add_provider_for_screen().</para></note>
1286  *
1287  * Since: 3.0
1288  **/
1289 void
1290 gtk_style_context_add_provider (GtkStyleContext  *context,
1291                                 GtkStyleProvider *provider,
1292                                 guint             priority)
1293 {
1294   GtkStyleContextPrivate *priv;
1295
1296   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
1297   g_return_if_fail (GTK_IS_STYLE_PROVIDER (provider));
1298
1299   priv = context->priv;
1300   style_provider_add (&priv->providers, provider, priority);
1301   priv->providers_last = g_list_last (priv->providers);
1302
1303   gtk_style_context_invalidate (context);
1304 }
1305
1306 /**
1307  * gtk_style_context_remove_provider:
1308  * @context: a #GtkStyleContext
1309  * @provider: a #GtkStyleProvider
1310  *
1311  * Removes @provider from the style providers list in @context.
1312  *
1313  * Since: 3.0
1314  **/
1315 void
1316 gtk_style_context_remove_provider (GtkStyleContext  *context,
1317                                    GtkStyleProvider *provider)
1318 {
1319   GtkStyleContextPrivate *priv;
1320
1321   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
1322   g_return_if_fail (GTK_IS_STYLE_PROVIDER (provider));
1323
1324   priv = context->priv;
1325
1326   if (style_provider_remove (&priv->providers, provider))
1327     {
1328       priv->providers_last = g_list_last (priv->providers);
1329
1330       gtk_style_context_invalidate (context);
1331     }
1332 }
1333
1334 /**
1335  * gtk_style_context_reset_widgets:
1336  * @screen: a #GdkScreen
1337  *
1338  * This function recomputes the styles for all widgets under a particular
1339  * #GdkScreen. This is useful when some global parameter has changed that
1340  * affects the appearance of all widgets, because when a widget gets a new
1341  * style, it will both redraw and recompute any cached information about
1342  * its appearance. As an example, it is used when the color scheme changes
1343  * in the related #GtkSettings object.
1344  *
1345  * Since: 3.0
1346  **/
1347 void
1348 gtk_style_context_reset_widgets (GdkScreen *screen)
1349 {
1350   GList *list, *toplevels;
1351
1352   _gtk_icon_set_invalidate_caches ();
1353
1354   toplevels = gtk_window_list_toplevels ();
1355   g_list_foreach (toplevels, (GFunc) g_object_ref, NULL);
1356
1357   for (list = toplevels; list; list = list->next)
1358     {
1359       if (gtk_widget_get_screen (list->data) == screen)
1360         gtk_widget_reset_style (list->data);
1361
1362       g_object_unref (list->data);
1363     }
1364
1365   g_list_free (toplevels);
1366 }
1367
1368 /**
1369  * gtk_style_context_add_provider_for_screen:
1370  * @screen: a #GdkScreen
1371  * @provider: a #GtkStyleProvider
1372  * @priority: the priority of the style provider. The lower
1373  *            it is, the earlier it will be used in the style
1374  *            construction. Typically this will be in the range
1375  *            between %GTK_STYLE_PROVIDER_PRIORITY_FALLBACK and
1376  *            %GTK_STYLE_PROVIDER_PRIORITY_USER
1377  *
1378  * Adds a global style provider to @screen, which will be used
1379  * in style construction for all #GtkStyleContext<!-- -->s under
1380  * @screen.
1381  *
1382  * GTK+ uses this to make styling information from #GtkSettings
1383  * available.
1384  *
1385  * <note><para>If both priorities are the same, A #GtkStyleProvider
1386  * added through gtk_style_context_add_provider() takes precedence
1387  * over another added through this function.</para></note>
1388  *
1389  * Since: 3.0
1390  **/
1391 void
1392 gtk_style_context_add_provider_for_screen (GdkScreen        *screen,
1393                                            GtkStyleProvider *provider,
1394                                            guint             priority)
1395 {
1396   GList *providers, *list;
1397
1398   g_return_if_fail (GDK_IS_SCREEN (screen));
1399   g_return_if_fail (GTK_IS_STYLE_PROVIDER (provider));
1400
1401   if (G_UNLIKELY (!provider_list_quark))
1402     provider_list_quark = g_quark_from_static_string ("gtk-provider-list-quark");
1403
1404   list = providers = g_object_get_qdata (G_OBJECT (screen), provider_list_quark);
1405   style_provider_add (&list, provider, priority);
1406
1407   if (list != providers)
1408     g_object_set_qdata (G_OBJECT (screen), provider_list_quark, list);
1409
1410   gtk_style_context_reset_widgets (screen);
1411 }
1412
1413 /**
1414  * gtk_style_context_remove_provider_for_screen:
1415  * @screen: a #GdkScreen
1416  * @provider: a #GtkStyleProvider
1417  *
1418  * Removes @provider from the global style providers list in @screen.
1419  *
1420  * Since: 3.0
1421  **/
1422 void
1423 gtk_style_context_remove_provider_for_screen (GdkScreen        *screen,
1424                                               GtkStyleProvider *provider)
1425 {
1426   GList *providers, *list;
1427
1428   g_return_if_fail (GDK_IS_SCREEN (screen));
1429   g_return_if_fail (GTK_IS_STYLE_PROVIDER (provider));
1430
1431   if (G_UNLIKELY (!provider_list_quark))
1432     return;
1433
1434   list = providers = g_object_get_qdata (G_OBJECT (screen), provider_list_quark);
1435
1436   if (style_provider_remove (&list, provider))
1437     {
1438       if (list != providers)
1439         g_object_set_qdata (G_OBJECT (screen), provider_list_quark, list);
1440
1441       gtk_style_context_reset_widgets (screen);
1442     }
1443 }
1444
1445 /**
1446  * gtk_style_context_get_property:
1447  * @context: a #GtkStyleContext
1448  * @property: style property name
1449  * @state: state to retrieve the property value for
1450  * @value: (out) (transfer full):  return location for the style property value
1451  *
1452  * Gets a style property from @context for the given state.
1453  *
1454  * When @value is no longer needed, g_value_unset() must be called
1455  * to free any allocated memory.
1456  *
1457  * Since: 3.0
1458  **/
1459 void
1460 gtk_style_context_get_property (GtkStyleContext *context,
1461                                 const gchar     *property,
1462                                 GtkStateFlags    state,
1463                                 GValue          *value)
1464 {
1465   GtkStyleContextPrivate *priv;
1466   StyleData *data;
1467
1468   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
1469   g_return_if_fail (property != NULL);
1470   g_return_if_fail (value != NULL);
1471
1472   priv = context->priv;
1473
1474   g_return_if_fail (priv->widget_path != NULL);
1475
1476   data = style_data_lookup (context);
1477   gtk_style_properties_get_property (data->store, property, state, value);
1478 }
1479
1480 /**
1481  * gtk_style_context_get_valist:
1482  * @context: a #GtkStyleContext
1483  * @state: state to retrieve the property values for
1484  * @args: va_list of property name/return location pairs, followed by %NULL
1485  *
1486  * Retrieves several style property values from @context for a given state.
1487  *
1488  * Since: 3.0
1489  **/
1490 void
1491 gtk_style_context_get_valist (GtkStyleContext *context,
1492                               GtkStateFlags    state,
1493                               va_list          args)
1494 {
1495   GtkStyleContextPrivate *priv;
1496   StyleData *data;
1497
1498   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
1499
1500   priv = context->priv;
1501   g_return_if_fail (priv->widget_path != NULL);
1502
1503   data = style_data_lookup (context);
1504   gtk_style_properties_get_valist (data->store, state, args);
1505 }
1506
1507 /**
1508  * gtk_style_context_get:
1509  * @context: a #GtkStyleContext
1510  * @state: state to retrieve the property values for
1511  * @...: property name /return value pairs, followed by %NULL
1512  *
1513  * Retrieves several style property values from @context for a
1514  * given state.
1515  *
1516  * Since: 3.0
1517  **/
1518 void
1519 gtk_style_context_get (GtkStyleContext *context,
1520                        GtkStateFlags    state,
1521                        ...)
1522 {
1523   GtkStyleContextPrivate *priv;
1524   StyleData *data;
1525   va_list args;
1526
1527   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
1528
1529   priv = context->priv;
1530   g_return_if_fail (priv->widget_path != NULL);
1531
1532   data = style_data_lookup (context);
1533
1534   va_start (args, state);
1535   gtk_style_properties_get_valist (data->store, state, args);
1536   va_end (args);
1537 }
1538
1539 /**
1540  * gtk_style_context_set_state:
1541  * @context: a #GtkStyleContext
1542  * @flags: state to represent
1543  *
1544  * Sets the state to be used when rendering with any
1545  * of the gtk_render_*() functions.
1546  *
1547  * Since: 3.0
1548  **/
1549 void
1550 gtk_style_context_set_state (GtkStyleContext *context,
1551                              GtkStateFlags    flags)
1552 {
1553   GtkStyleContextPrivate *priv;
1554   GtkStyleInfo *info;
1555
1556   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
1557
1558   priv = context->priv;
1559   info = priv->info_stack->data;
1560   info->state_flags = flags;
1561 }
1562
1563 /**
1564  * gtk_style_context_get_state:
1565  * @context: a #GtkStyleContext
1566  *
1567  * Returns the state used when rendering.
1568  *
1569  * Returns: the state flags
1570  *
1571  * Since: 3.0
1572  **/
1573 GtkStateFlags
1574 gtk_style_context_get_state (GtkStyleContext *context)
1575 {
1576   GtkStyleContextPrivate *priv;
1577   GtkStyleInfo *info;
1578
1579   g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), 0);
1580
1581   priv = context->priv;
1582   info = priv->info_stack->data;
1583
1584   return info->state_flags;
1585 }
1586
1587 static gboolean
1588 context_has_animatable_region (GtkStyleContext *context,
1589                                gpointer         region_id)
1590 {
1591   GtkStyleContextPrivate *priv;
1592
1593   /* NULL region_id means everything
1594    * rendered through the style context
1595    */
1596   if (!region_id)
1597     return TRUE;
1598
1599   priv = context->priv;
1600   return g_slist_find (priv->animation_regions, region_id) != NULL;
1601 }
1602
1603 /**
1604  * gtk_style_context_state_is_running:
1605  * @context: a #GtkStyleContext
1606  * @state: a widget state
1607  * @progress: (out): return location for the transition progress
1608  *
1609  * Returns %TRUE if there is a transition animation running for the
1610  * current region (see gtk_style_context_push_animatable_region()).
1611  *
1612  * If @progress is not %NULL, the animation progress will be returned
1613  * there, 0.0 means the state is closest to being unset, while 1.0 means
1614  * it's closest to being set. This means transition animation will
1615  * run from 0 to 1 when @state is being set and from 1 to 0 when
1616  * it's being unset.
1617  *
1618  * Returns: %TRUE if there is a running transition animation for @state.
1619  *
1620  * Since: 3.0
1621  **/
1622 gboolean
1623 gtk_style_context_state_is_running (GtkStyleContext *context,
1624                                     GtkStateType     state,
1625                                     gdouble         *progress)
1626 {
1627   GtkStyleContextPrivate *priv;
1628   AnimationInfo *info;
1629   GSList *l;
1630
1631   g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), FALSE);
1632
1633   priv = context->priv;
1634
1635   for (l = priv->animations; l; l = l->next)
1636     {
1637       info = l->data;
1638
1639       if (info->state == state &&
1640           context_has_animatable_region (context, info->region_id))
1641         {
1642           if (progress)
1643             *progress = _gtk_timeline_get_progress (info->timeline);
1644
1645           return TRUE;
1646         }
1647     }
1648
1649   return FALSE;
1650 }
1651
1652 /**
1653  * gtk_style_context_set_path:
1654  * @context: a #GtkStyleContext
1655  * @path: a #GtkWidgetPath
1656  *
1657  * Sets the #GtkWidgetPath used for style matching. As a
1658  * consequence, the style will be regenerated to match
1659  * the new given path.
1660  *
1661  * If you are using a #GtkStyleContext returned from
1662  * gtk_widget_get_style_context(), you do not need to call
1663  * this yourself.
1664  *
1665  * Since: 3.0
1666  **/
1667 void
1668 gtk_style_context_set_path (GtkStyleContext *context,
1669                             GtkWidgetPath   *path)
1670 {
1671   GtkStyleContextPrivate *priv;
1672
1673   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
1674   g_return_if_fail (path != NULL);
1675
1676   priv = context->priv;
1677
1678   if (priv->widget_path)
1679     {
1680       gtk_widget_path_free (priv->widget_path);
1681       priv->widget_path = NULL;
1682     }
1683
1684   if (path)
1685     priv->widget_path = gtk_widget_path_copy (path);
1686
1687   gtk_style_context_invalidate (context);
1688 }
1689
1690 /**
1691  * gtk_style_context_get_path:
1692  * @context: a #GtkStyleContext
1693  *
1694  * Returns the widget path used for style matching.
1695  *
1696  * Returns: (transfer none): A #GtkWidgetPath
1697  *
1698  * Since: 3.0
1699  **/
1700 G_CONST_RETURN GtkWidgetPath *
1701 gtk_style_context_get_path (GtkStyleContext *context)
1702 {
1703   GtkStyleContextPrivate *priv;
1704
1705   priv = context->priv;
1706   return priv->widget_path;
1707 }
1708
1709 /**
1710  * gtk_style_context_save:
1711  * @context: a #GtkStyleContext
1712  *
1713  * Saves the @context state, so all modifications done through
1714  * gtk_style_context_add_class(), gtk_style_context_remove_class(),
1715  * gtk_style_context_add_region(), gtk_style_context_remove_region()
1716  * or gtk_style_context_set_junction_sides() can be reverted in one
1717  * go through gtk_style_context_restore().
1718  *
1719  * Since: 3.0
1720  **/
1721 void
1722 gtk_style_context_save (GtkStyleContext *context)
1723 {
1724   GtkStyleContextPrivate *priv;
1725   GtkStyleInfo *info;
1726
1727   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
1728
1729   priv = context->priv;
1730
1731   g_assert (priv->info_stack != NULL);
1732
1733   info = style_info_copy (priv->info_stack->data);
1734   priv->info_stack = g_slist_prepend (priv->info_stack, info);
1735 }
1736
1737 /**
1738  * gtk_style_context_restore:
1739  * @context: a #GtkStyleContext
1740  *
1741  * Restores @context state to a previous stage.
1742  * See gtk_style_context_save().
1743  *
1744  * Since: 3.0
1745  **/
1746 void
1747 gtk_style_context_restore (GtkStyleContext *context)
1748 {
1749   GtkStyleContextPrivate *priv;
1750   GtkStyleInfo *info;
1751
1752   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
1753
1754   priv = context->priv;
1755
1756   if (priv->info_stack)
1757     {
1758       info = priv->info_stack->data;
1759       priv->info_stack = g_slist_remove (priv->info_stack, info);
1760       style_info_free (info);
1761     }
1762
1763   if (!priv->info_stack)
1764     {
1765       g_warning ("Unpaired gtk_style_context_restore() call");
1766
1767       /* Create default region */
1768       info = style_info_new ();
1769       priv->info_stack = g_slist_prepend (priv->info_stack, info);
1770     }
1771
1772   priv->current_data = NULL;
1773 }
1774
1775 static gboolean
1776 style_class_find (GArray *array,
1777                   GQuark  class_quark,
1778                   guint  *position)
1779 {
1780   gint min, max, mid;
1781   gboolean found = FALSE;
1782   guint pos;
1783
1784   if (position)
1785     *position = 0;
1786
1787   if (!array || array->len == 0)
1788     return FALSE;
1789
1790   min = 0;
1791   max = array->len - 1;
1792
1793   do
1794     {
1795       GQuark item;
1796
1797       mid = (min + max) / 2;
1798       item = g_array_index (array, GQuark, mid);
1799
1800       if (class_quark == item)
1801         {
1802           found = TRUE;
1803           pos = mid;
1804         }
1805       else if (class_quark > item)
1806         min = pos = mid + 1;
1807       else
1808         {
1809           max = mid - 1;
1810           pos = mid;
1811         }
1812     }
1813   while (!found && min <= max);
1814
1815   if (position)
1816     *position = pos;
1817
1818   return found;
1819 }
1820
1821 static gboolean
1822 region_find (GArray *array,
1823              GQuark  class_quark,
1824              guint  *position)
1825 {
1826   gint min, max, mid;
1827   gboolean found = FALSE;
1828   guint pos;
1829
1830   if (position)
1831     *position = 0;
1832
1833   if (!array || array->len == 0)
1834     return FALSE;
1835
1836   min = 0;
1837   max = array->len - 1;
1838
1839   do
1840     {
1841       GtkRegion *region;
1842
1843       mid = (min + max) / 2;
1844       region = &g_array_index (array, GtkRegion, mid);
1845
1846       if (region->class_quark == class_quark)
1847         {
1848           found = TRUE;
1849           pos = mid;
1850         }
1851       else if (region->class_quark > class_quark)
1852         min = pos = mid + 1;
1853       else
1854         {
1855           max = mid - 1;
1856           pos = mid;
1857         }
1858     }
1859   while (!found && min <= max);
1860
1861   if (position)
1862     *position = pos;
1863
1864   return found;
1865 }
1866
1867 /**
1868  * gtk_style_context_add_class:
1869  * @context: a #GtkStyleContext
1870  * @class_name: class name to use in styling
1871  *
1872  * Adds a style class to @context, so posterior calls to
1873  * gtk_style_context_get() or any of the gtk_render_*()
1874  * functions will make use of this new class for styling.
1875  *
1876  * In the CSS file format, a #GtkEntry defining an "entry"
1877  * class, would be matched by:
1878  *
1879  * <programlisting>
1880  * GtkEntry.entry { ... }
1881  * </programlisting>
1882  *
1883  * While any widget defining an "entry" class would be
1884  * matched by:
1885  * <programlisting>
1886  * .entry { ... }
1887  * </programlisting>
1888  *
1889  * Since: 3.0
1890  **/
1891 void
1892 gtk_style_context_add_class (GtkStyleContext *context,
1893                              const gchar     *class_name)
1894 {
1895   GtkStyleContextPrivate *priv;
1896   GtkStyleInfo *info;
1897   GQuark class_quark;
1898   guint position;
1899
1900   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
1901   g_return_if_fail (class_name != NULL);
1902
1903   priv = context->priv;
1904   class_quark = g_quark_from_string (class_name);
1905
1906   g_assert (priv->info_stack != NULL);
1907   info = priv->info_stack->data;
1908
1909   if (!style_class_find (info->style_classes, class_quark, &position))
1910     {
1911       g_array_insert_val (info->style_classes, position, class_quark);
1912
1913       /* Unset current data, as it likely changed due to the class change */
1914       priv->current_data = NULL;
1915     }
1916 }
1917
1918 /**
1919  * gtk_style_context_remove_class:
1920  * @context: a #GtkStyleContext
1921  * @class_name: class name to remove
1922  *
1923  * Removes @class_name from @context.
1924  *
1925  * Since: 3.0
1926  **/
1927 void
1928 gtk_style_context_remove_class (GtkStyleContext *context,
1929                                 const gchar     *class_name)
1930 {
1931   GtkStyleContextPrivate *priv;
1932   GtkStyleInfo *info;
1933   GQuark class_quark;
1934   guint position;
1935
1936   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
1937   g_return_if_fail (class_name != NULL);
1938
1939   class_quark = g_quark_try_string (class_name);
1940
1941   if (!class_quark)
1942     return;
1943
1944   priv = context->priv;
1945
1946   g_assert (priv->info_stack != NULL);
1947   info = priv->info_stack->data;
1948
1949   if (style_class_find (info->style_classes, class_quark, &position))
1950     {
1951       g_array_remove_index (info->style_classes, position);
1952
1953       /* Unset current data, as it likely changed due to the class change */
1954       priv->current_data = NULL;
1955     }
1956 }
1957
1958 /**
1959  * gtk_style_context_has_class:
1960  * @context: a #GtkStyleContext
1961  * @class_name: a class name
1962  *
1963  * Returns %TRUE if @context currently has defined the
1964  * given class name
1965  *
1966  * Returns: %TRUE if @context has @class_name defined
1967  *
1968  * Since: 3.0
1969  **/
1970 gboolean
1971 gtk_style_context_has_class (GtkStyleContext *context,
1972                              const gchar     *class_name)
1973 {
1974   GtkStyleContextPrivate *priv;
1975   GtkStyleInfo *info;
1976   GQuark class_quark;
1977
1978   g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), FALSE);
1979   g_return_val_if_fail (class_name != NULL, FALSE);
1980
1981   class_quark = g_quark_try_string (class_name);
1982
1983   if (!class_quark)
1984     return FALSE;
1985
1986   priv = context->priv;
1987
1988   g_assert (priv->info_stack != NULL);
1989   info = priv->info_stack->data;
1990
1991   if (style_class_find (info->style_classes, class_quark, NULL))
1992     return TRUE;
1993
1994   return FALSE;
1995 }
1996
1997 /**
1998  * gtk_style_context_list_classes:
1999  * @context: a #GtkStyleContext
2000  *
2001  * Returns the list of classes currently defined in @context.
2002  *
2003  * Returns: (transfer container) (element-type utf8): a #GList of
2004  *          strings with the currently defined classes. The contents
2005  *          of the list are owned by GTK+, but you must free the list
2006  *          itself with g_list_free() when you are done with it.
2007  *
2008  * Since: 3.0
2009  **/
2010 GList *
2011 gtk_style_context_list_classes (GtkStyleContext *context)
2012 {
2013   GtkStyleContextPrivate *priv;
2014   GtkStyleInfo *info;
2015   GList *classes = NULL;
2016   guint i;
2017
2018   g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), NULL);
2019
2020   priv = context->priv;
2021
2022   g_assert (priv->info_stack != NULL);
2023   info = priv->info_stack->data;
2024
2025   for (i = 0; i < info->style_classes->len; i++)
2026     {
2027       GQuark quark;
2028
2029       quark = g_array_index (info->style_classes, GQuark, i);
2030       classes = g_list_prepend (classes, (gchar *) g_quark_to_string (quark));
2031     }
2032
2033   return classes;
2034 }
2035
2036 /**
2037  * gtk_style_context_list_regions:
2038  * @context: a #GtkStyleContext
2039  *
2040  * Returns the list of regions currently defined in @context.
2041  *
2042  * Returns: (transfer container) (element-type utf8): a #GList of
2043  *          strings with the currently defined regions. The contents
2044  *          of the list are owned by GTK+, but you must free the list
2045  *          itself with g_list_free() when you are done with it.
2046  *
2047  * Since: 3.0
2048  **/
2049 GList *
2050 gtk_style_context_list_regions (GtkStyleContext *context)
2051 {
2052   GtkStyleContextPrivate *priv;
2053   GtkStyleInfo *info;
2054   GList *classes = NULL;
2055   guint i;
2056
2057   g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), NULL);
2058
2059   priv = context->priv;
2060
2061   g_assert (priv->info_stack != NULL);
2062   info = priv->info_stack->data;
2063
2064   for (i = 0; i < info->regions->len; i++)
2065     {
2066       GtkRegion *region;
2067       const gchar *class_name;
2068
2069       region = &g_array_index (info->regions, GtkRegion, i);
2070
2071       class_name = g_quark_to_string (region->class_quark);
2072       classes = g_list_prepend (classes, (gchar *) class_name);
2073     }
2074
2075   return classes;
2076 }
2077
2078 gboolean
2079 _gtk_style_context_check_region_name (const gchar *str)
2080 {
2081   g_return_val_if_fail (str != NULL, FALSE);
2082
2083   if (!g_ascii_islower (str[0]))
2084     return FALSE;
2085
2086   while (*str)
2087     {
2088       if (*str != '-' &&
2089           !g_ascii_islower (*str))
2090         return FALSE;
2091
2092       str++;
2093     }
2094
2095   return TRUE;
2096 }
2097
2098 /**
2099  * gtk_style_context_add_region:
2100  * @context: a #GtkStyleContext
2101  * @region_name: region name to use in styling
2102  * @flags: flags that apply to the region
2103  *
2104  * Adds a region to @context, so posterior calls to
2105  * gtk_style_context_get() or any of the gtk_render_*()
2106  * functions will make use of this new region for styling.
2107  *
2108  * In the CSS file format, a #GtkTreeView defining a "row"
2109  * region, would be matched by:
2110  *
2111  * <programlisting>
2112  * GtkTreeView row { ... }
2113  * </programlisting>
2114  *
2115  * Pseudo-classes are used for matching @flags, so the two
2116  * following rules:
2117  * <programlisting>
2118  * GtkTreeView row:nth-child (even) { ... }
2119  * GtkTreeView row:nth-child (odd) { ... }
2120  * </programlisting>
2121  *
2122  * would apply to even and odd rows, respectively.
2123  *
2124  * <note><para>Region names must only contain lowercase letters
2125  * and '-', starting always with a lowercase letter.</para></note>
2126  *
2127  * Since: 3.0
2128  **/
2129 void
2130 gtk_style_context_add_region (GtkStyleContext *context,
2131                               const gchar     *region_name,
2132                               GtkRegionFlags   flags)
2133 {
2134   GtkStyleContextPrivate *priv;
2135   GtkStyleInfo *info;
2136   GQuark region_quark;
2137   guint position;
2138
2139   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2140   g_return_if_fail (region_name != NULL);
2141   g_return_if_fail (_gtk_style_context_check_region_name (region_name));
2142
2143   priv = context->priv;
2144   region_quark = g_quark_from_string (region_name);
2145
2146   g_assert (priv->info_stack != NULL);
2147   info = priv->info_stack->data;
2148
2149   if (!region_find (info->regions, region_quark, &position))
2150     {
2151       GtkRegion region;
2152
2153       region.class_quark = region_quark;
2154       region.flags = flags;
2155
2156       g_array_insert_val (info->regions, position, region);
2157
2158       /* Unset current data, as it likely changed due to the region change */
2159       priv->current_data = NULL;
2160     }
2161 }
2162
2163 /**
2164  * gtk_style_context_remove_region:
2165  * @context: a #GtkStyleContext
2166  * @region_name: region name to unset
2167  *
2168  * Removes a region from @context.
2169  *
2170  * Since: 3.0
2171  **/
2172 void
2173 gtk_style_context_remove_region (GtkStyleContext *context,
2174                                  const gchar     *region_name)
2175 {
2176   GtkStyleContextPrivate *priv;
2177   GtkStyleInfo *info;
2178   GQuark region_quark;
2179   guint position;
2180
2181   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2182   g_return_if_fail (region_name != NULL);
2183
2184   region_quark = g_quark_try_string (region_name);
2185
2186   if (!region_quark)
2187     return;
2188
2189   priv = context->priv;
2190
2191   g_assert (priv->info_stack != NULL);
2192   info = priv->info_stack->data;
2193
2194   if (region_find (info->regions, region_quark, &position))
2195     {
2196       g_array_remove_index (info->regions, position);
2197
2198       /* Unset current data, as it likely changed due to the region change */
2199       priv->current_data = NULL;
2200     }
2201 }
2202
2203 /**
2204  * gtk_style_context_has_region:
2205  * @context: a #GtkStyleContext
2206  * @region_name: a region name
2207  * @flags_return: (out) (allow-none): return location for region flags
2208  *
2209  * Returns %TRUE if @context has the region defined.
2210  * If @flags_return is not %NULL, it is set to the flags
2211  * affecting the region.
2212  *
2213  * Returns: %TRUE if region is defined
2214  *
2215  * Since: 3.0
2216  **/
2217 gboolean
2218 gtk_style_context_has_region (GtkStyleContext *context,
2219                               const gchar     *region_name,
2220                               GtkRegionFlags  *flags_return)
2221 {
2222   GtkStyleContextPrivate *priv;
2223   GtkStyleInfo *info;
2224   GQuark region_quark;
2225   guint position;
2226
2227   g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), FALSE);
2228   g_return_val_if_fail (region_name != NULL, FALSE);
2229
2230   if (flags_return)
2231     *flags_return = 0;
2232
2233   region_quark = g_quark_try_string (region_name);
2234
2235   if (!region_quark)
2236     return FALSE;
2237
2238   priv = context->priv;
2239
2240   g_assert (priv->info_stack != NULL);
2241   info = priv->info_stack->data;
2242
2243   if (region_find (info->regions, region_quark, &position))
2244     {
2245       if (flags_return)
2246         {
2247           GtkRegion *region;
2248
2249           region = &g_array_index (info->regions, GtkRegion, position);
2250           *flags_return = region->flags;
2251         }
2252       return TRUE;
2253     }
2254
2255   return FALSE;
2256 }
2257
2258 static gint
2259 style_property_values_cmp (gconstpointer bsearch_node1,
2260                            gconstpointer bsearch_node2)
2261 {
2262   const PropertyValue *val1 = bsearch_node1;
2263   const PropertyValue *val2 = bsearch_node2;
2264
2265   if (val1->widget_type != val2->widget_type)
2266     return val1->widget_type < val2->widget_type ? -1 : 1;
2267
2268   if (val1->pspec != val2->pspec)
2269     return val1->pspec < val2->pspec ? -1 : 1;
2270
2271   if (val1->state != val2->state)
2272     return val1->state < val2->state ? -1 : 1;
2273
2274   return 0;
2275 }
2276
2277 const GValue *
2278 _gtk_style_context_peek_style_property (GtkStyleContext *context,
2279                                         GType            widget_type,
2280                                         GtkStateFlags    state,
2281                                         GParamSpec      *pspec)
2282 {
2283   GtkStyleContextPrivate *priv;
2284   PropertyValue *pcache, key = { 0 };
2285   GList *global_list = NULL;
2286   StyleData *data;
2287   guint i;
2288
2289   priv = context->priv;
2290   data = style_data_lookup (context);
2291
2292   key.widget_type = widget_type;
2293   key.state = state;
2294   key.pspec = pspec;
2295
2296   /* need value cache array */
2297   if (!data->property_cache)
2298     data->property_cache = g_array_new (FALSE, FALSE, sizeof (PropertyValue));
2299   else
2300     {
2301       pcache = bsearch (&key,
2302                         data->property_cache->data, data->property_cache->len,
2303                         sizeof (PropertyValue), style_property_values_cmp);
2304       if (pcache)
2305         return &pcache->value;
2306     }
2307
2308   i = 0;
2309   while (i < data->property_cache->len &&
2310          style_property_values_cmp (&key, &g_array_index (data->property_cache, PropertyValue, i)) >= 0)
2311     i++;
2312
2313   g_array_insert_val (data->property_cache, i, key);
2314   pcache = &g_array_index (data->property_cache, PropertyValue, i);
2315
2316   /* cache miss, initialize value type, then set contents */
2317   g_param_spec_ref (pcache->pspec);
2318   g_value_init (&pcache->value, G_PARAM_SPEC_VALUE_TYPE (pspec));
2319
2320   if (priv->screen)
2321     {
2322       global_list = g_object_get_qdata (G_OBJECT (priv->screen), provider_list_quark);
2323       global_list = g_list_last (global_list);
2324     }
2325
2326   if (priv->widget_path)
2327     {
2328       GList *list, *global, *elem;
2329
2330       list = priv->providers_last;
2331       global = global_list;
2332
2333       while ((elem = find_next_candidate (list, global, FALSE)) != NULL)
2334         {
2335           GtkStyleProviderData *provider_data;
2336
2337           provider_data = elem->data;
2338
2339           if (elem == list)
2340             list = list->prev;
2341           else
2342             global = global->prev;
2343
2344           if (gtk_style_provider_get_style_property (provider_data->provider,
2345                                                      priv->widget_path, state,
2346                                                      pspec, &pcache->value))
2347             {
2348               /* Resolve symbolic colors to GdkColor/GdkRGBA */
2349               if (G_VALUE_TYPE (&pcache->value) == GTK_TYPE_SYMBOLIC_COLOR)
2350                 {
2351                   GtkSymbolicColor *color;
2352                   GdkRGBA rgba;
2353
2354                   color = g_value_dup_boxed (&pcache->value);
2355
2356                   g_value_unset (&pcache->value);
2357
2358                   if (G_PARAM_SPEC_VALUE_TYPE (pspec) == GDK_TYPE_RGBA)
2359                     g_value_init (&pcache->value, GDK_TYPE_RGBA);
2360                   else
2361                     g_value_init (&pcache->value, GDK_TYPE_COLOR);
2362
2363                   if (gtk_symbolic_color_resolve (color, data->store, &rgba))
2364                     {
2365                       if (G_PARAM_SPEC_VALUE_TYPE (pspec) == GDK_TYPE_RGBA)
2366                         g_value_set_boxed (&pcache->value, &rgba);
2367                       else
2368                         {
2369                           GdkColor rgb;
2370
2371                           rgb.red = rgba.red * 65535. + 0.5;
2372                           rgb.green = rgba.green * 65535. + 0.5;
2373                           rgb.blue = rgba.blue * 65535. + 0.5;
2374
2375                           g_value_set_boxed (&pcache->value, &rgb);
2376                         }
2377                     }
2378                   else
2379                     g_param_value_set_default (pspec, &pcache->value);
2380
2381                   gtk_symbolic_color_unref (color);
2382                 }
2383
2384               return &pcache->value;
2385             }
2386         }
2387     }
2388
2389   /* not supplied by any provider, revert to default */
2390   g_param_value_set_default (pspec, &pcache->value);
2391
2392   return &pcache->value;
2393 }
2394
2395 /**
2396  * gtk_style_context_get_style_property:
2397  * @context: a #GtkStyleContext
2398  * @property_name: the name of the widget style property
2399  * @value: Return location for the property value
2400  *
2401  * Gets the value for a widget style property.
2402  *
2403  * When @value is no longer needed, g_value_unset() must be called
2404  * to free any allocated memory.
2405  **/
2406 void
2407 gtk_style_context_get_style_property (GtkStyleContext *context,
2408                                       const gchar     *property_name,
2409                                       GValue          *value)
2410 {
2411   GtkStyleContextPrivate *priv;
2412   GtkWidgetClass *widget_class;
2413   GtkStateFlags state;
2414   GParamSpec *pspec;
2415   const GValue *peek_value;
2416   GType widget_type;
2417
2418   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2419   g_return_if_fail (property_name != NULL);
2420   g_return_if_fail (value != NULL);
2421
2422   priv = context->priv;
2423
2424   if (!priv->widget_path)
2425     return;
2426
2427   widget_type = gtk_widget_path_get_object_type (priv->widget_path);
2428
2429   if (!g_type_is_a (widget_type, GTK_TYPE_WIDGET))
2430     {
2431       g_warning ("%s: can't get style properties for non-widget class `%s'",
2432                  G_STRLOC,
2433                  g_type_name (widget_type));
2434       return;
2435     }
2436
2437   widget_class = g_type_class_ref (widget_type);
2438   pspec = gtk_widget_class_find_style_property (widget_class, property_name);
2439   g_type_class_unref (widget_class);
2440
2441   if (!pspec)
2442     {
2443       g_warning ("%s: widget class `%s' has no style property named `%s'",
2444                  G_STRLOC,
2445                  g_type_name (widget_type),
2446                  property_name);
2447       return;
2448     }
2449
2450   state = gtk_style_context_get_state (context);
2451   peek_value = _gtk_style_context_peek_style_property (context, widget_type,
2452                                                        state, pspec);
2453
2454   if (G_VALUE_TYPE (value) == G_VALUE_TYPE (peek_value))
2455     g_value_copy (peek_value, value);
2456   else if (g_value_type_transformable (G_VALUE_TYPE (peek_value), G_VALUE_TYPE (value)))
2457     g_value_transform (peek_value, value);
2458   else
2459     g_warning ("can't retrieve style property `%s' of type `%s' as value of type `%s'",
2460                pspec->name,
2461                G_VALUE_TYPE_NAME (peek_value),
2462                G_VALUE_TYPE_NAME (value));
2463 }
2464
2465 /**
2466  * gtk_style_context_get_style_valist:
2467  * @context: a #GtkStyleContext
2468  * @args: va_list of property name/return location pairs, followed by %NULL
2469  *
2470  * Retrieves several widget style properties from @context according to the
2471  * current style.
2472  *
2473  * Since: 3.0
2474  **/
2475 void
2476 gtk_style_context_get_style_valist (GtkStyleContext *context,
2477                                     va_list          args)
2478 {
2479   GtkStyleContextPrivate *priv;
2480   const gchar *prop_name;
2481   GtkStateFlags state;
2482   GType widget_type;
2483
2484   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2485
2486   prop_name = va_arg (args, const gchar *);
2487   priv = context->priv;
2488
2489   if (!priv->widget_path)
2490     return;
2491
2492   widget_type = gtk_widget_path_get_object_type (priv->widget_path);
2493
2494   if (!g_type_is_a (widget_type, GTK_TYPE_WIDGET))
2495     {
2496       g_warning ("%s: can't get style properties for non-widget class `%s'",
2497                  G_STRLOC,
2498                  g_type_name (widget_type));
2499       return;
2500     }
2501
2502   state = gtk_style_context_get_state (context);
2503
2504   while (prop_name)
2505     {
2506       GtkWidgetClass *widget_class;
2507       GParamSpec *pspec;
2508       const GValue *peek_value;
2509       gchar *error;
2510
2511       widget_class = g_type_class_ref (widget_type);
2512       pspec = gtk_widget_class_find_style_property (widget_class, prop_name);
2513       g_type_class_unref (widget_class);
2514
2515       if (!pspec)
2516         {
2517           g_warning ("%s: widget class `%s' has no style property named `%s'",
2518                      G_STRLOC,
2519                      g_type_name (widget_type),
2520                      prop_name);
2521           continue;
2522         }
2523
2524       peek_value = _gtk_style_context_peek_style_property (context, widget_type,
2525                                                            state, pspec);
2526
2527       G_VALUE_LCOPY (peek_value, args, 0, &error);
2528
2529       if (error)
2530         {
2531           g_warning ("can't retrieve style property `%s' of type `%s': %s",
2532                      pspec->name,
2533                      G_VALUE_TYPE_NAME (peek_value),
2534                      error);
2535           g_free (error);
2536         }
2537
2538       prop_name = va_arg (args, const gchar *);
2539     }
2540 }
2541
2542 /**
2543  * gtk_style_context_get_style:
2544  * @context: a #GtkStyleContext
2545  * @...: property name /return value pairs, followed by %NULL
2546  *
2547  * Retrieves several widget style properties from @context according to the
2548  * current style.
2549  *
2550  * Since: 3.0
2551  **/
2552 void
2553 gtk_style_context_get_style (GtkStyleContext *context,
2554                              ...)
2555 {
2556   va_list args;
2557
2558   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2559
2560   va_start (args, context);
2561   gtk_style_context_get_style_valist (context, args);
2562   va_end (args);
2563 }
2564
2565
2566 /**
2567  * gtk_style_context_lookup_icon_set:
2568  * @context: a #GtkStyleContext
2569  * @stock_id: an icon name
2570  *
2571  * Looks up @stock_id in the icon factories associated to @context and
2572  * the default icon factory, returning an icon set if found, otherwise
2573  * %NULL.
2574  *
2575  * Returns: (transfer none): The looked  up %GtkIconSet, or %NULL
2576  **/
2577 GtkIconSet *
2578 gtk_style_context_lookup_icon_set (GtkStyleContext *context,
2579                                    const gchar     *stock_id)
2580 {
2581   GtkStyleContextPrivate *priv;
2582   StyleData *data;
2583   GSList *list;
2584
2585   g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), NULL);
2586   g_return_val_if_fail (stock_id != NULL, NULL);
2587
2588   priv = context->priv;
2589   g_return_val_if_fail (priv->widget_path != NULL, NULL);
2590
2591   data = style_data_lookup (context);
2592
2593   for (list = data->icon_factories; list; list = list->next)
2594     {
2595       GtkIconFactory *factory;
2596       GtkIconSet *icon_set;
2597
2598       factory = list->data;
2599       icon_set = gtk_icon_factory_lookup (factory, stock_id);
2600
2601       if (icon_set)
2602         return icon_set;
2603     }
2604
2605   return gtk_icon_factory_lookup_default (stock_id);
2606 }
2607
2608 /**
2609  * gtk_style_context_set_screen:
2610  * @context: a #GtkStyleContext
2611  * @screen: a #GdkScreen
2612  *
2613  * Attaches @context to the given screen.
2614  *
2615  * The screen is used to add style information from 'global' style
2616  * providers, such as the screens #GtkSettings instance.
2617  *
2618  * If you are using a #GtkStyleContext returned from
2619  * gtk_widget_get_style_context(), you do not need to
2620  * call this yourself.
2621  *
2622  * Since: 3.0
2623  **/
2624 void
2625 gtk_style_context_set_screen (GtkStyleContext *context,
2626                               GdkScreen       *screen)
2627 {
2628   GtkStyleContextPrivate *priv;
2629
2630   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2631   g_return_if_fail (GDK_IS_SCREEN (screen));
2632
2633   priv = context->priv;
2634   if (priv->screen == screen)
2635     return;
2636
2637   priv->screen = screen;
2638
2639   g_object_notify (G_OBJECT (context), "screen");
2640
2641   gtk_style_context_invalidate (context);
2642 }
2643
2644 /**
2645  * gtk_style_context_get_screen:
2646  * @context: a #GtkStyleContext
2647  *
2648  * Returns the #GdkScreen to which @context is attached.
2649  *
2650  * Returns: (transfer none): a #GdkScreen.
2651  **/
2652 GdkScreen *
2653 gtk_style_context_get_screen (GtkStyleContext *context)
2654 {
2655   GtkStyleContextPrivate *priv;
2656
2657   g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), NULL);
2658
2659   priv = context->priv;
2660   return priv->screen;
2661 }
2662
2663 /**
2664  * gtk_style_context_set_direction:
2665  * @context: a #GtkStyleContext
2666  * @direction: the new direction.
2667  *
2668  * Sets the reading direction for rendering purposes.
2669  *
2670  * If you are using a #GtkStyleContext returned from
2671  * gtk_widget_get_style_context(), you do not need to
2672  * call this yourself.
2673  *
2674  * Since: 3.0
2675  **/
2676 void
2677 gtk_style_context_set_direction (GtkStyleContext  *context,
2678                                  GtkTextDirection  direction)
2679 {
2680   GtkStyleContextPrivate *priv;
2681
2682   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2683
2684   priv = context->priv;
2685   priv->direction = direction;
2686
2687   g_object_notify (G_OBJECT (context), "direction");
2688 }
2689
2690 /**
2691  * gtk_style_context_get_direction:
2692  * @context: a #GtkStyleContext
2693  *
2694  * Returns the widget direction used for rendering.
2695  *
2696  * Returns: the widget direction
2697  *
2698  * Since: 3.0
2699  **/
2700 GtkTextDirection
2701 gtk_style_context_get_direction (GtkStyleContext *context)
2702 {
2703   GtkStyleContextPrivate *priv;
2704
2705   g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), GTK_TEXT_DIR_LTR);
2706
2707   priv = context->priv;
2708   return priv->direction;
2709 }
2710
2711 /**
2712  * gtk_style_context_set_junction_sides:
2713  * @context: a #GtkStyleContext
2714  * @sides: sides where rendered elements are visually connected to
2715  *     other elements
2716  *
2717  * Sets the sides where rendered elements (mostly through
2718  * gtk_render_frame()) will visually connect with other visual elements.
2719  *
2720  * This is merely a hint that may or may not be honored
2721  * by theming engines.
2722  *
2723  * Container widgets are expected to set junction hints as appropriate
2724  * for their children, so it should not normally be necessary to call
2725  * this function manually.
2726  *
2727  * Since: 3.0
2728  **/
2729 void
2730 gtk_style_context_set_junction_sides (GtkStyleContext  *context,
2731                                       GtkJunctionSides  sides)
2732 {
2733   GtkStyleContextPrivate *priv;
2734   GtkStyleInfo *info;
2735
2736   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2737
2738   priv = context->priv;
2739   info = priv->info_stack->data;
2740   info->junction_sides = sides;
2741 }
2742
2743 /**
2744  * gtk_style_context_get_junction_sides:
2745  * @context: a #GtkStyleContext
2746  *
2747  * Returns the sides where rendered elements connect visually with others.
2748  *
2749  * Returns: the junction sides
2750  *
2751  * Since: 3.0
2752  **/
2753 GtkJunctionSides
2754 gtk_style_context_get_junction_sides (GtkStyleContext *context)
2755 {
2756   GtkStyleContextPrivate *priv;
2757   GtkStyleInfo *info;
2758
2759   g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), 0);
2760
2761   priv = context->priv;
2762   info = priv->info_stack->data;
2763   return info->junction_sides;
2764 }
2765
2766 /**
2767  * gtk_style_context_lookup_color:
2768  * @context: a #GtkStyleContext
2769  * @color_name: color name to lookup
2770  * @color: (out): Return location for the looked up color
2771  *
2772  * Looks up and resolves a color name in the @context color map.
2773  *
2774  * Returns: %TRUE if @color_name was found and resolved, %FALSE otherwise
2775  **/
2776 gboolean
2777 gtk_style_context_lookup_color (GtkStyleContext *context,
2778                                 const gchar     *color_name,
2779                                 GdkRGBA         *color)
2780 {
2781   GtkStyleContextPrivate *priv;
2782   GtkSymbolicColor *sym_color;
2783   StyleData *data;
2784
2785   g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), FALSE);
2786   g_return_val_if_fail (color_name != NULL, FALSE);
2787   g_return_val_if_fail (color != NULL, FALSE);
2788
2789   priv = context->priv;
2790   g_return_val_if_fail (priv->widget_path != NULL, FALSE);
2791
2792   data = style_data_lookup (context);
2793   sym_color = gtk_style_properties_lookup_color (data->store, color_name);
2794
2795   if (!sym_color)
2796     return FALSE;
2797
2798   return gtk_symbolic_color_resolve (sym_color, data->store, color);
2799 }
2800
2801 /**
2802  * gtk_style_context_notify_state_change:
2803  * @context: a #GtkStyleContext
2804  * @window: a #GdkWindow
2805  * @region_id: (allow-none): animatable region to notify on, or %NULL.
2806  *     See gtk_style_context_push_animatable_region()
2807  * @state: state to trigger transition for
2808  * @state_value: %TRUE if @state is the state we are changing to,
2809  *     %FALSE if we are changing away from it
2810  *
2811  * Notifies a state change on @context, so if the current style makes use
2812  * of transition animations, one will be started so all rendered elements
2813  * under @region_id are animated for state @state being set to value
2814  * @state_value.
2815  *
2816  * The @window parameter is used in order to invalidate the rendered area
2817  * as the animation runs, so make sure it is the same window that is being
2818  * rendered on by the gtk_render_*() functions.
2819  *
2820  * If @region_id is %NULL, all rendered elements using @context will be
2821  * affected by this state transition.
2822  *
2823  * As a practical example, a #GtkButton notifying a state transition on
2824  * the prelight state:
2825  * <programlisting>
2826  * gtk_style_context_notify_state_change (context,
2827  *                                        gtk_widget_get_window (widget),
2828  *                                        NULL,
2829  *                                        GTK_STATE_PRELIGHT,
2830  *                                        button->in_button);
2831  * </programlisting>
2832  *
2833  * Can be handled in the CSS file like this:
2834  * <programlisting>
2835  * GtkButton {
2836  *     background-color: &num;f00
2837  * }
2838  *
2839  * GtkButton:hover {
2840  *     background-color: &num;fff;
2841  *     transition: 200ms linear
2842  * }
2843  * </programlisting>
2844  *
2845  * This combination will animate the button background from red to white
2846  * if a pointer enters the button, and back to red if the pointer leaves
2847  * the button.
2848  *
2849  * Note that @state is used when finding the transition parameters, which
2850  * is why the style places the transition under the :hover pseudo-class.
2851  *
2852  * Since: 3.0
2853  **/
2854 void
2855 gtk_style_context_notify_state_change (GtkStyleContext *context,
2856                                        GdkWindow       *window,
2857                                        gpointer         region_id,
2858                                        GtkStateType     state,
2859                                        gboolean         state_value)
2860 {
2861   GtkStyleContextPrivate *priv;
2862   GtkAnimationDescription *desc;
2863   AnimationInfo *info;
2864   GtkStateFlags flags;
2865   StyleData *data;
2866
2867   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2868   g_return_if_fail (GDK_IS_WINDOW (window));
2869   g_return_if_fail (state > GTK_STATE_NORMAL && state <= GTK_STATE_FOCUSED);
2870
2871   priv = context->priv;
2872   g_return_if_fail (priv->widget_path != NULL);
2873
2874   state_value = (state_value == TRUE);
2875
2876   switch (state)
2877     {
2878     case GTK_STATE_ACTIVE:
2879       flags = GTK_STATE_FLAG_ACTIVE;
2880       break;
2881     case GTK_STATE_PRELIGHT:
2882       flags = GTK_STATE_FLAG_PRELIGHT;
2883       break;
2884     case GTK_STATE_SELECTED:
2885       flags = GTK_STATE_FLAG_SELECTED;
2886       break;
2887     case GTK_STATE_INSENSITIVE:
2888       flags = GTK_STATE_FLAG_INSENSITIVE;
2889       break;
2890     case GTK_STATE_INCONSISTENT:
2891       flags = GTK_STATE_FLAG_INCONSISTENT;
2892       break;
2893     case GTK_STATE_FOCUSED:
2894       flags = GTK_STATE_FLAG_FOCUSED;
2895       break;
2896     case GTK_STATE_NORMAL:
2897     default:
2898       flags = 0;
2899       break;
2900     }
2901
2902   /* Find out if there is any animation description for the given
2903    * state, it will fallback to the normal state as well if necessary.
2904    */
2905   data = style_data_lookup (context);
2906   gtk_style_properties_get (data->store, flags,
2907                             "transition", &desc,
2908                             NULL);
2909
2910   if (!desc)
2911     return;
2912
2913   if (_gtk_animation_description_get_duration (desc) == 0)
2914     {
2915       _gtk_animation_description_unref (desc);
2916       return;
2917     }
2918
2919   info = animation_info_lookup (context, region_id, state);
2920
2921   if (info &&
2922       info->target_value != state_value)
2923     {
2924       /* Target values are the opposite */
2925       if (!_gtk_timeline_get_loop (info->timeline))
2926         {
2927           /* Reverse the animation */
2928           if (_gtk_timeline_get_direction (info->timeline) == GTK_TIMELINE_DIRECTION_FORWARD)
2929             _gtk_timeline_set_direction (info->timeline, GTK_TIMELINE_DIRECTION_BACKWARD);
2930           else
2931             _gtk_timeline_set_direction (info->timeline, GTK_TIMELINE_DIRECTION_FORWARD);
2932
2933           info->target_value = state_value;
2934         }
2935       else
2936         {
2937           /* Take it out of its looping state */
2938           _gtk_timeline_set_loop (info->timeline, FALSE);
2939         }
2940     }
2941   else if (!info &&
2942            (!_gtk_animation_description_get_loop (desc) ||
2943             state_value))
2944     {
2945       info = animation_info_new (context, region_id,
2946                                  _gtk_animation_description_get_duration (desc),
2947                                  _gtk_animation_description_get_progress_type (desc),
2948                                  _gtk_animation_description_get_loop (desc),
2949                                  state, state_value, window);
2950
2951       priv->animations = g_slist_prepend (priv->animations, info);
2952       priv->animations_invalidated = TRUE;
2953     }
2954
2955   _gtk_animation_description_unref (desc);
2956 }
2957
2958 /**
2959  * gtk_style_context_cancel_animations:
2960  * @context: a #GtkStyleContext
2961  * @region_id: (allow-none): animatable region to stop, or %NULL.
2962  *     See gtk_style_context_push_animatable_region()
2963  *
2964  * Stops all running animations for @region_id and all animatable
2965  * regions underneath.
2966  *
2967  * A %NULL @region_id will stop all ongoing animations in @context,
2968  * when dealing with a #GtkStyleContext obtained through
2969  * gtk_widget_get_style_context(), this is normally done for you
2970  * in all circumstances you would expect all widget to be stopped,
2971  * so this should be only used in complex widgets with different
2972  * animatable regions.
2973  *
2974  * Since: 3.0
2975  **/
2976 void
2977 gtk_style_context_cancel_animations (GtkStyleContext *context,
2978                                      gpointer         region_id)
2979 {
2980   GtkStyleContextPrivate *priv;
2981   AnimationInfo *info;
2982   GSList *l;
2983
2984   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2985
2986   priv = context->priv;
2987   l = priv->animations;
2988
2989   while (l)
2990     {
2991       info = l->data;
2992       l = l->next;
2993
2994       if (!region_id ||
2995           info->region_id == region_id ||
2996           g_slist_find (info->parent_regions, region_id))
2997         {
2998           priv->animations = g_slist_remove (priv->animations, info);
2999           animation_info_free (info);
3000         }
3001     }
3002 }
3003
3004 static gboolean
3005 is_parent_of (GdkWindow *parent,
3006               GdkWindow *child)
3007 {
3008   GtkWidget *child_widget, *parent_widget;
3009   GdkWindow *window;
3010
3011   gdk_window_get_user_data (child, (gpointer *) &child_widget);
3012   gdk_window_get_user_data (parent, (gpointer *) &parent_widget);
3013
3014   if (child_widget != parent_widget &&
3015       !gtk_widget_is_ancestor (child_widget, parent_widget))
3016     return FALSE;
3017
3018   window = child;
3019
3020   while (window)
3021     {
3022       if (window == parent)
3023         return TRUE;
3024
3025       window = gdk_window_get_parent (window);
3026     }
3027
3028   return FALSE;
3029 }
3030
3031 /**
3032  * gtk_style_context_scroll_animations:
3033  * @context: a #GtkStyleContext
3034  * @window: a #GdkWindow used previously in
3035  *          gtk_style_context_notify_state_change()
3036  * @dx: Amount to scroll in the X axis
3037  * @dy: Amount to scroll in the Y axis
3038  *
3039  * This function is analogous to gdk_window_scroll(), and
3040  * should be called together with it so the invalidation
3041  * areas for any ongoing animation are scrolled together
3042  * with it.
3043  *
3044  * Since: 3.0
3045  **/
3046 void
3047 gtk_style_context_scroll_animations (GtkStyleContext *context,
3048                                      GdkWindow       *window,
3049                                      gint             dx,
3050                                      gint             dy)
3051 {
3052   GtkStyleContextPrivate *priv;
3053   AnimationInfo *info;
3054   GSList *l;
3055
3056   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3057   g_return_if_fail (GDK_IS_WINDOW (window));
3058
3059   priv = context->priv;
3060   l = priv->animations;
3061
3062   while (l)
3063     {
3064       info = l->data;
3065       l = l->next;
3066
3067       if (info->invalidation_region &&
3068           (window == info->window ||
3069            is_parent_of (window, info->window)))
3070         cairo_region_translate (info->invalidation_region, dx, dy);
3071     }
3072 }
3073
3074 /**
3075  * gtk_style_context_push_animatable_region:
3076  * @context: a #GtkStyleContext
3077  * @region_id: unique identifier for the animatable region
3078  *
3079  * Pushes an animatable region, so all further gtk_render_*() calls between
3080  * this call and the following gtk_style_context_pop_animatable_region()
3081  * will potentially show transition animations for this region if
3082  * gtk_style_context_notify_state_change() is called for a given state,
3083  * and the current theme/style defines transition animations for state
3084  * changes.
3085  *
3086  * The @region_id used must be unique in @context so the theming engine
3087  * can uniquely identify rendered elements subject to a state transition.
3088  *
3089  * Since: 3.0
3090  **/
3091 void
3092 gtk_style_context_push_animatable_region (GtkStyleContext *context,
3093                                           gpointer         region_id)
3094 {
3095   GtkStyleContextPrivate *priv;
3096
3097   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3098   g_return_if_fail (region_id != NULL);
3099
3100   priv = context->priv;
3101   priv->animation_regions = g_slist_prepend (priv->animation_regions, region_id);
3102 }
3103
3104 /**
3105  * gtk_style_context_pop_animatable_region:
3106  * @context: a #GtkStyleContext
3107  *
3108  * Pops an animatable region from @context.
3109  * See gtk_style_context_push_animatable_region().
3110  *
3111  * Since: 3.0
3112  **/
3113 void
3114 gtk_style_context_pop_animatable_region (GtkStyleContext *context)
3115 {
3116   GtkStyleContextPrivate *priv;
3117
3118   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3119
3120   priv = context->priv;
3121   priv->animation_regions = g_slist_delete_link (priv->animation_regions,
3122                                                  priv->animation_regions);
3123 }
3124
3125 void
3126 _gtk_style_context_invalidate_animation_areas (GtkStyleContext *context)
3127 {
3128   GtkStyleContextPrivate *priv;
3129   GSList *l;
3130
3131   priv = context->priv;
3132
3133   for (l = priv->animations; l; l = l->next)
3134     {
3135       AnimationInfo *info;
3136
3137       info = l->data;
3138
3139       /* A NULL invalidation region means it has to be recreated on
3140        * the next expose event, this happens usually after a widget
3141        * allocation change, so the next expose after it will update
3142        * the invalidation region.
3143        */
3144       if (info->invalidation_region)
3145         {
3146           cairo_region_destroy (info->invalidation_region);
3147           info->invalidation_region = NULL;
3148         }
3149     }
3150
3151   priv->animations_invalidated = TRUE;
3152 }
3153
3154 void
3155 _gtk_style_context_coalesce_animation_areas (GtkStyleContext *context,
3156                                              GtkWidget       *widget)
3157 {
3158   GtkStyleContextPrivate *priv;
3159   GSList *l;
3160
3161   priv = context->priv;
3162
3163   if (!priv->animations_invalidated)
3164     return;
3165
3166   l = priv->animations;
3167
3168   while (l)
3169     {
3170       AnimationInfo *info;
3171       gint rel_x, rel_y;
3172       GSList *cur;
3173       guint i;
3174
3175       cur = l;
3176       info = cur->data;
3177       l = l->next;
3178
3179       if (info->invalidation_region)
3180         continue;
3181
3182       if (info->rectangles->len == 0)
3183         continue;
3184
3185       info->invalidation_region = cairo_region_create ();
3186       _gtk_widget_get_translation_to_window (widget, info->window, &rel_x, &rel_y);
3187
3188       for (i = 0; i < info->rectangles->len; i++)
3189         {
3190           cairo_rectangle_int_t *rect;
3191
3192           rect = &g_array_index (info->rectangles, cairo_rectangle_int_t, i);
3193
3194           /* These are widget relative coordinates,
3195            * so have them inverted to be window relative
3196            */
3197           rect->x -= rel_x;
3198           rect->y -= rel_y;
3199
3200           cairo_region_union_rectangle (info->invalidation_region, rect);
3201         }
3202
3203       g_array_remove_range (info->rectangles, 0, info->rectangles->len);
3204     }
3205
3206   priv->animations_invalidated = FALSE;
3207 }
3208
3209 static void
3210 store_animation_region (GtkStyleContext *context,
3211                         gdouble          x,
3212                         gdouble          y,
3213                         gdouble          width,
3214                         gdouble          height)
3215 {
3216   GtkStyleContextPrivate *priv;
3217   GSList *l;
3218
3219   priv = context->priv;
3220
3221   if (!priv->animations_invalidated)
3222     return;
3223
3224   for (l = priv->animations; l; l = l->next)
3225     {
3226       AnimationInfo *info;
3227
3228       info = l->data;
3229
3230       /* The animation doesn't need updating
3231        * the invalidation area, bail out.
3232        */
3233       if (info->invalidation_region)
3234         continue;
3235
3236       if (context_has_animatable_region (context, info->region_id))
3237         {
3238           cairo_rectangle_int_t rect;
3239
3240           rect.x = (gint) x;
3241           rect.y = (gint) y;
3242           rect.width = (gint) width;
3243           rect.height = (gint) height;
3244
3245           g_array_append_val (info->rectangles, rect);
3246
3247           if (!info->parent_regions)
3248             {
3249               GSList *parent_regions;
3250
3251               parent_regions = g_slist_find (priv->animation_regions, info->region_id);
3252               info->parent_regions = g_slist_copy (parent_regions);
3253             }
3254         }
3255     }
3256 }
3257
3258 /**
3259  * gtk_style_context_invalidate:
3260  * @context: a #GtkStyleContext.
3261  *
3262  * Invalidates @context style information, so it will be reconstructed
3263  * again.
3264  *
3265  * If you're using a #GtkStyleContext returned from
3266  * gtk_widget_get_style_context(), you do not need to
3267  * call this yourself.
3268  *
3269  * Since: 3.0
3270  **/
3271 void
3272 gtk_style_context_invalidate (GtkStyleContext *context)
3273 {
3274   GtkStyleContextPrivate *priv;
3275
3276   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3277
3278   priv = context->priv;
3279
3280   /* Avoid reentrancy */
3281   if (priv->invalidating_context)
3282     return;
3283
3284   priv->invalidating_context = TRUE;
3285
3286   g_hash_table_remove_all (priv->style_data);
3287   priv->current_data = NULL;
3288
3289   g_signal_emit (context, signals[CHANGED], 0);
3290
3291   priv->invalidating_context = FALSE;
3292 }
3293
3294 /**
3295  * gtk_style_context_set_background:
3296  * @context: a #GtkStyleContext
3297  * @window: a #GdkWindow
3298  *
3299  * Sets the background of @window to the background pattern or
3300  * color specified in @context for its current state.
3301  *
3302  * Since: 3.0
3303  **/
3304 void
3305 gtk_style_context_set_background (GtkStyleContext *context,
3306                                   GdkWindow       *window)
3307 {
3308   GtkStateFlags state;
3309   cairo_pattern_t *pattern;
3310   GdkRGBA *color;
3311
3312   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3313   g_return_if_fail (GDK_IS_WINDOW (window));
3314
3315   state = gtk_style_context_get_state (context);
3316   gtk_style_context_get (context, state,
3317                          "background-image", &pattern,
3318                          NULL);
3319   if (pattern)
3320     {
3321       gdk_window_set_background_pattern (window, pattern);
3322       cairo_pattern_destroy (pattern);
3323       return;
3324     }
3325
3326   gtk_style_context_get (context, state,
3327                          "background-color", &color,
3328                          NULL);
3329   if (color)
3330     {
3331       gdk_window_set_background_rgba (window, color);
3332       gdk_rgba_free (color);
3333     }
3334 }
3335
3336 /**
3337  * gtk_style_context_get_color:
3338  * @context: a #GtkStyleContext
3339  * @state: state to retrieve the color for
3340  * @color: (out): return value for the foreground color
3341  *
3342  * Gets the foreground color for a given state.
3343  *
3344  * Since: 3.0
3345  **/
3346 void
3347 gtk_style_context_get_color (GtkStyleContext *context,
3348                              GtkStateFlags    state,
3349                              GdkRGBA         *color)
3350 {
3351   GtkStyleContextPrivate *priv;
3352   StyleData *data;
3353   const GValue *value;
3354   GdkRGBA *c;
3355
3356   g_return_if_fail (color != NULL);
3357   *color = fallback_color;
3358
3359   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3360
3361   priv = context->priv;
3362   g_return_if_fail (priv->widget_path != NULL);
3363
3364   data = style_data_lookup (context);
3365   value = _gtk_style_properties_peek_property (data->store,
3366                                                "color", state);
3367
3368   if (value)
3369     {
3370       c = g_value_get_boxed (value);
3371       *color = *c;
3372     }
3373 }
3374
3375 /**
3376  * gtk_style_context_get_background_color:
3377  * @context: a #GtkStyleContext
3378  * @state: state to retrieve the color for
3379  * @color: (out): return value for the background color
3380  *
3381  * Gets the background color for a given state.
3382  *
3383  * Since: 3.0
3384  **/
3385 void
3386 gtk_style_context_get_background_color (GtkStyleContext *context,
3387                                         GtkStateFlags    state,
3388                                         GdkRGBA         *color)
3389 {
3390   GtkStyleContextPrivate *priv;
3391   StyleData *data;
3392   const GValue *value;
3393   GdkRGBA *c;
3394
3395   g_return_if_fail (color != NULL);
3396   *color = fallback_color;
3397
3398   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3399
3400   priv = context->priv;
3401   g_return_if_fail (priv->widget_path != NULL);
3402
3403   data = style_data_lookup (context);
3404   value = _gtk_style_properties_peek_property (data->store,
3405                                                "background-color", state);
3406
3407   if (value)
3408     {
3409       c = g_value_get_boxed (value);
3410       *color = *c;
3411     }
3412 }
3413
3414 /**
3415  * gtk_style_context_get_border_color:
3416  * @context: a #GtkStyleContext
3417  * @state: state to retrieve the color for
3418  * @color: (out): return value for the border color
3419  *
3420  * Gets the border color for a given state.
3421  *
3422  * Since: 3.0
3423  **/
3424 void
3425 gtk_style_context_get_border_color (GtkStyleContext *context,
3426                                     GtkStateFlags    state,
3427                                     GdkRGBA         *color)
3428 {
3429   GtkStyleContextPrivate *priv;
3430   StyleData *data;
3431   const GValue *value;
3432   GdkRGBA *c;
3433
3434   g_return_if_fail (color != NULL);
3435   *color = fallback_color;
3436
3437   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3438
3439   priv = context->priv;
3440   g_return_if_fail (priv->widget_path != NULL);
3441
3442   data = style_data_lookup (context);
3443   value = _gtk_style_properties_peek_property (data->store,
3444                                                "border-color", state);
3445
3446   if (value)
3447     {
3448       c = g_value_get_boxed (value);
3449       *color = *c;
3450     }
3451 }
3452
3453 /**
3454  * gtk_style_context_get_border:
3455  * @context: a #GtkStyleContext
3456  * @state: state to retrieve the border for
3457  * @border: (out): return value for the border settings
3458  *
3459  * Gets the border for a given state as a #GtkBorder.
3460  * See %GTK_STYLE_PROPERTY_BORDER_WIDTH.
3461  *
3462  * Since: 3.0
3463  **/
3464 void
3465 gtk_style_context_get_border (GtkStyleContext *context,
3466                               GtkStateFlags    state,
3467                               GtkBorder       *border)
3468 {
3469   GtkStyleContextPrivate *priv;
3470   StyleData *data;
3471   const GValue *value;
3472   GtkBorder *b;
3473
3474   g_return_if_fail (border != NULL);
3475   *border = fallback_border;
3476
3477   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3478
3479   priv = context->priv;
3480   g_return_if_fail (priv->widget_path != NULL);
3481
3482   data = style_data_lookup (context);
3483   value = _gtk_style_properties_peek_property (data->store,
3484                                                "border-width", state);
3485
3486   if (value)
3487     {
3488       b = g_value_get_boxed (value);
3489       *border = *b;
3490     }
3491 }
3492
3493 /**
3494  * gtk_style_context_get_padding:
3495  * @context: a #GtkStyleContext
3496  * @state: state to retrieve the padding for
3497  * @padding: (out): return value for the padding settings
3498  *
3499  * Gets the padding for a given state as a #GtkBorder.
3500  * See %GTK_STYLE_PROPERTY_PADDING.
3501  *
3502  * Since: 3.0
3503  **/
3504 void
3505 gtk_style_context_get_padding (GtkStyleContext *context,
3506                                GtkStateFlags    state,
3507                                GtkBorder       *padding)
3508 {
3509   GtkStyleContextPrivate *priv;
3510   StyleData *data;
3511   const GValue *value;
3512   GtkBorder *b;
3513
3514   g_return_if_fail (padding != NULL);
3515   *padding = fallback_border;
3516
3517   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3518
3519   priv = context->priv;
3520   g_return_if_fail (priv->widget_path != NULL);
3521
3522   data = style_data_lookup (context);
3523   value = _gtk_style_properties_peek_property (data->store,
3524                                                "padding", state);
3525
3526   if (value)
3527     {
3528       b = g_value_get_boxed (value);
3529       *padding = *b;
3530     }
3531 }
3532
3533 /**
3534  * gtk_style_context_get_margin:
3535  * @context: a #GtkStyleContext
3536  * @state: state to retrieve the border for
3537  * @margin: (out): return value for the margin settings
3538  *
3539  * Gets the margin for a given state as a #GtkBorder.
3540  * See %GTK_STYLE_PROPERTY_MARGIN.
3541  *
3542  * Since: 3.0
3543  **/
3544 void
3545 gtk_style_context_get_margin (GtkStyleContext *context,
3546                               GtkStateFlags    state,
3547                               GtkBorder       *margin)
3548 {
3549   GtkStyleContextPrivate *priv;
3550   StyleData *data;
3551   const GValue *value;
3552   GtkBorder *b;
3553
3554   g_return_if_fail (margin != NULL);
3555   *margin = fallback_border;
3556
3557   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3558
3559   priv = context->priv;
3560   g_return_if_fail (priv->widget_path != NULL);
3561
3562   data = style_data_lookup (context);
3563   value = _gtk_style_properties_peek_property (data->store,
3564                                                "margin", state);
3565
3566   if (value)
3567     {
3568       b = g_value_get_boxed (value);
3569       *margin = *b;
3570     }
3571 }
3572
3573 /**
3574  * gtk_style_context_get_font:
3575  * @context: a #GtkStyleContext
3576  * @state: state to retrieve the font for
3577  *
3578  * Returns the font description for a given state. The returned
3579  * object is const and will remain valid until the
3580  * #GtkStyleContext::changed signal happens.
3581  *
3582  * Returns: (transfer none): the #PangoFontDescription for the given
3583  *          state.  This object is owned by GTK+ and should not be
3584  *          freed.
3585  *
3586  * Since: 3.0
3587  **/
3588 const PangoFontDescription *
3589 gtk_style_context_get_font (GtkStyleContext *context,
3590                             GtkStateFlags    state)
3591 {
3592   GtkStyleContextPrivate *priv;
3593   StyleData *data;
3594   const GValue *value;
3595
3596   g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), NULL);
3597
3598   priv = context->priv;
3599   g_return_val_if_fail (priv->widget_path != NULL, NULL);
3600
3601   data = style_data_lookup (context);
3602   value = _gtk_style_properties_peek_property (data->store, "font", state);
3603
3604   if (value)
3605     return g_value_get_boxed (value);
3606
3607   return NULL;
3608 }
3609
3610 static void
3611 get_cursor_color (GtkStyleContext *context,
3612                   gboolean         primary,
3613                   GdkRGBA         *color)
3614 {
3615   GdkColor *style_color;
3616
3617   gtk_style_context_get_style (context,
3618                                primary ? "cursor-color" : "secondary-cursor-color",
3619                                &style_color,
3620                                NULL);
3621
3622   if (style_color)
3623     {
3624       color->red = style_color->red / 65535.0;
3625       color->green = style_color->green / 65535.0;
3626       color->blue = style_color->blue / 65535.0;
3627       color->alpha = 1;
3628
3629       gdk_color_free (style_color);
3630     }
3631   else
3632     {
3633       gtk_style_context_get_color (context, GTK_STATE_FLAG_NORMAL, color);
3634
3635       if (!primary)
3636       {
3637         GdkRGBA bg;
3638
3639         gtk_style_context_get_background_color (context, GTK_STATE_FLAG_NORMAL, &bg);
3640
3641         color->red = (color->red + bg.red) * 0.5;
3642         color->green = (color->green + bg.green) * 0.5;
3643         color->blue = (color->blue + bg.blue) * 0.5;
3644       }
3645     }
3646 }
3647
3648 void
3649 _gtk_style_context_get_cursor_color (GtkStyleContext *context,
3650                                      GdkRGBA         *primary_color,
3651                                      GdkRGBA         *secondary_color)
3652 {
3653   if (primary_color)
3654     get_cursor_color (context, TRUE, primary_color);
3655
3656   if (secondary_color)
3657     get_cursor_color (context, FALSE, secondary_color);
3658 }
3659
3660 /* Paint methods */
3661
3662 /**
3663  * gtk_render_check:
3664  * @context: a #GtkStyleContext
3665  * @cr: a #cairo_t
3666  * @x: X origin of the rectangle
3667  * @y: Y origin of the rectangle
3668  * @width: rectangle width
3669  * @height: rectangle height
3670  *
3671  * Renders a checkmark (as in a #GtkCheckButton).
3672  *
3673  * The %GTK_STATE_FLAG_ACTIVE state determines whether the check is
3674  * on or off, and %GTK_STATE_FLAG_INCONSISTENT determines whether it
3675  * should be marked as undefined.
3676  *
3677  * <example>
3678  * <title>Typical checkmark rendering</title>
3679  * <inlinegraphic fileref="checks.png" format="PNG"/>
3680  * </example>
3681  *
3682  * Since: 3.0
3683  **/
3684 void
3685 gtk_render_check (GtkStyleContext *context,
3686                   cairo_t         *cr,
3687                   gdouble          x,
3688                   gdouble          y,
3689                   gdouble          width,
3690                   gdouble          height)
3691 {
3692   GtkStyleContextPrivate *priv;
3693   GtkThemingEngineClass *engine_class;
3694
3695   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3696   g_return_if_fail (cr != NULL);
3697
3698   if (width <= 0 || height <= 0)
3699     return;
3700
3701   priv = context->priv;
3702   engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
3703
3704   cairo_save (cr);
3705
3706   store_animation_region (context, x, y, width, height);
3707
3708   _gtk_theming_engine_set_context (priv->theming_engine, context);
3709   engine_class->render_check (priv->theming_engine, cr,
3710                               x, y, width, height);
3711
3712   cairo_restore (cr);
3713 }
3714
3715 /**
3716  * gtk_render_option:
3717  * @context: a #GtkStyleContext
3718  * @cr: a #cairo_t
3719  * @x: X origin of the rectangle
3720  * @y: Y origin of the rectangle
3721  * @width: rectangle width
3722  * @height: rectangle height
3723  *
3724  * Renders an option mark (as in a #GtkRadioButton), the %GTK_STATE_FLAG_ACTIVE
3725  * state will determine whether the option is on or off, and
3726  * %GTK_STATE_FLAG_INCONSISTENT whether it should be marked as undefined.
3727  *
3728  * <example>
3729  * <title>Typical option mark rendering</title>
3730  * <inlinegraphic fileref="options.png" format="PNG"/>
3731  * </example>
3732  *
3733  * Since: 3.0
3734  **/
3735 void
3736 gtk_render_option (GtkStyleContext *context,
3737                    cairo_t         *cr,
3738                    gdouble          x,
3739                    gdouble          y,
3740                    gdouble          width,
3741                    gdouble          height)
3742 {
3743   GtkStyleContextPrivate *priv;
3744   GtkThemingEngineClass *engine_class;
3745
3746   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3747   g_return_if_fail (cr != NULL);
3748
3749   if (width <= 0 || height <= 0)
3750     return;
3751
3752   priv = context->priv;
3753   engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
3754
3755   cairo_save (cr);
3756
3757   store_animation_region (context, x, y, width, height);
3758
3759   _gtk_theming_engine_set_context (priv->theming_engine, context);
3760   engine_class->render_option (priv->theming_engine, cr,
3761                                x, y, width, height);
3762
3763   cairo_restore (cr);
3764 }
3765
3766 /**
3767  * gtk_render_arrow:
3768  * @context: a #GtkStyleContext
3769  * @cr: a #cairo_t
3770  * @angle: arrow angle from 0 to 2 * %G_PI, being 0 the arrow pointing to the north
3771  * @x: Center X for the render area
3772  * @y: Center Y for the render area
3773  * @size: square side for render area
3774  *
3775  * Renders an arrow pointing to @angle.
3776  *
3777  * <example>
3778  * <title>Typical arrow rendering at 0, 1&solidus;2 &pi;, &pi; and 3&solidus;2 &pi;</title>
3779  * <inlinegraphic fileref="arrows.png" format="PNG"/>
3780  * </example>
3781  *
3782  * Since: 3.0
3783  **/
3784 void
3785 gtk_render_arrow (GtkStyleContext *context,
3786                   cairo_t         *cr,
3787                   gdouble          angle,
3788                   gdouble          x,
3789                   gdouble          y,
3790                   gdouble          size)
3791 {
3792   GtkStyleContextPrivate *priv;
3793   GtkThemingEngineClass *engine_class;
3794
3795   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3796   g_return_if_fail (cr != NULL);
3797
3798   if (size <= 0)
3799     return;
3800
3801   priv = context->priv;
3802   engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
3803
3804   cairo_save (cr);
3805
3806   store_animation_region (context, x, y, size, size);
3807
3808   _gtk_theming_engine_set_context (priv->theming_engine, context);
3809   engine_class->render_arrow (priv->theming_engine, cr,
3810                               angle, x, y, size);
3811
3812   cairo_restore (cr);
3813 }
3814
3815 /**
3816  * gtk_render_background:
3817  * @context: a #GtkStyleContext
3818  * @cr: a #cairo_t
3819  * @x: X origin of the rectangle
3820  * @y: Y origin of the rectangle
3821  * @width: rectangle width
3822  * @height: rectangle height
3823  *
3824  * Renders the background of an element.
3825  *
3826  * <example>
3827  * <title>Typical background rendering, showing the effect of
3828  * <parameter>background-image</parameter>,
3829  * <parameter>border-width</parameter> and
3830  * <parameter>border-radius</parameter></title>
3831  * <inlinegraphic fileref="background.png" format="PNG"/>
3832  * </example>
3833  *
3834  * Since: 3.0.
3835  **/
3836 void
3837 gtk_render_background (GtkStyleContext *context,
3838                        cairo_t         *cr,
3839                        gdouble          x,
3840                        gdouble          y,
3841                        gdouble          width,
3842                        gdouble          height)
3843 {
3844   GtkStyleContextPrivate *priv;
3845   GtkThemingEngineClass *engine_class;
3846
3847   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3848   g_return_if_fail (cr != NULL);
3849
3850   if (width <= 0 || height <= 0)
3851     return;
3852
3853   priv = context->priv;
3854   engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
3855
3856   cairo_save (cr);
3857
3858   store_animation_region (context, x, y, width, height);
3859
3860   _gtk_theming_engine_set_context (priv->theming_engine, context);
3861   engine_class->render_background (priv->theming_engine, cr, x, y, width, height);
3862
3863   cairo_restore (cr);
3864 }
3865
3866 /**
3867  * gtk_render_frame:
3868  * @context: a #GtkStyleContext
3869  * @cr: a #cairo_t
3870  * @x: X origin of the rectangle
3871  * @y: Y origin of the rectangle
3872  * @width: rectangle width
3873  * @height: rectangle height
3874  *
3875  * Renders a frame around the rectangle defined by @x, @y, @width, @height.
3876  *
3877  * <example>
3878  * <title>Examples of frame rendering, showing the effect of
3879  * <parameter>border-image</parameter>,
3880  * <parameter>border-color</parameter>,
3881  * <parameter>border-width</parameter>,
3882  * <parameter>border-radius</parameter> and
3883  * junctions</title>
3884  * <inlinegraphic fileref="frames.png" format="PNG"/>
3885  * </example>
3886  *
3887  * Since: 3.0
3888  **/
3889 void
3890 gtk_render_frame (GtkStyleContext *context,
3891                   cairo_t         *cr,
3892                   gdouble          x,
3893                   gdouble          y,
3894                   gdouble          width,
3895                   gdouble          height)
3896 {
3897   GtkStyleContextPrivate *priv;
3898   GtkThemingEngineClass *engine_class;
3899
3900   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3901   g_return_if_fail (cr != NULL);
3902
3903   if (width <= 0 || height <= 0)
3904     return;
3905
3906   priv = context->priv;
3907   engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
3908
3909   cairo_save (cr);
3910
3911   store_animation_region (context, x, y, width, height);
3912
3913   _gtk_theming_engine_set_context (priv->theming_engine, context);
3914   engine_class->render_frame (priv->theming_engine, cr, x, y, width, height);
3915
3916   cairo_restore (cr);
3917 }
3918
3919 /**
3920  * gtk_render_expander:
3921  * @context: a #GtkStyleContext
3922  * @cr: a #cairo_t
3923  * @x: X origin of the rectangle
3924  * @y: Y origin of the rectangle
3925  * @width: rectangle width
3926  * @height: rectangle height
3927  *
3928  * Renders an expander (as used in #GtkTreeView and #GtkExpander) in the area
3929  * defined by @x, @y, @width, @height. The state %GTK_STATE_FLAG_ACTIVE
3930  * determines whether the expander is collapsed or expanded.
3931  *
3932  * <example>
3933  * <title>Typical expander rendering</title>
3934  * <inlinegraphic fileref="expanders.png" format="PNG"/>
3935  * </example>
3936  *
3937  * Since: 3.0
3938  **/
3939 void
3940 gtk_render_expander (GtkStyleContext *context,
3941                      cairo_t         *cr,
3942                      gdouble          x,
3943                      gdouble          y,
3944                      gdouble          width,
3945                      gdouble          height)
3946 {
3947   GtkStyleContextPrivate *priv;
3948   GtkThemingEngineClass *engine_class;
3949
3950   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3951   g_return_if_fail (cr != NULL);
3952
3953   if (width <= 0 || height <= 0)
3954     return;
3955
3956   priv = context->priv;
3957   engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
3958
3959   cairo_save (cr);
3960
3961   store_animation_region (context, x, y, width, height);
3962
3963   _gtk_theming_engine_set_context (priv->theming_engine, context);
3964   engine_class->render_expander (priv->theming_engine, cr, x, y, width, height);
3965
3966   cairo_restore (cr);
3967 }
3968
3969 /**
3970  * gtk_render_focus:
3971  * @context: a #GtkStyleContext
3972  * @cr: a #cairo_t
3973  * @x: X origin of the rectangle
3974  * @y: Y origin of the rectangle
3975  * @width: rectangle width
3976  * @height: rectangle height
3977  *
3978  * Renders a focus indicator on the rectangle determined by @x, @y, @width, @height.
3979  * <example>
3980  * <title>Typical focus rendering</title>
3981  * <inlinegraphic fileref="focus.png" format="PNG"/>
3982  * </example>
3983  *
3984  * Since: 3.0
3985  **/
3986 void
3987 gtk_render_focus (GtkStyleContext *context,
3988                   cairo_t         *cr,
3989                   gdouble          x,
3990                   gdouble          y,
3991                   gdouble          width,
3992                   gdouble          height)
3993 {
3994   GtkStyleContextPrivate *priv;
3995   GtkThemingEngineClass *engine_class;
3996
3997   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3998   g_return_if_fail (cr != NULL);
3999
4000   if (width <= 0 || height <= 0)
4001     return;
4002
4003   priv = context->priv;
4004   engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
4005
4006   cairo_save (cr);
4007
4008   store_animation_region (context, x, y, width, height);
4009
4010   _gtk_theming_engine_set_context (priv->theming_engine, context);
4011   engine_class->render_focus (priv->theming_engine, cr, x, y, width, height);
4012
4013   cairo_restore (cr);
4014 }
4015
4016 /**
4017  * gtk_render_layout:
4018  * @context: a #GtkStyleContext
4019  * @cr: a #cairo_t
4020  * @x: X origin
4021  * @y: Y origin
4022  * @layout: the #PangoLayout to render
4023  *
4024  * Renders @layout on the coordinates @x, @y
4025  *
4026  * Since: 3.0
4027  **/
4028 void
4029 gtk_render_layout (GtkStyleContext *context,
4030                    cairo_t         *cr,
4031                    gdouble          x,
4032                    gdouble          y,
4033                    PangoLayout     *layout)
4034 {
4035   GtkStyleContextPrivate *priv;
4036   GtkThemingEngineClass *engine_class;
4037   PangoRectangle extents;
4038
4039   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
4040   g_return_if_fail (PANGO_IS_LAYOUT (layout));
4041   g_return_if_fail (cr != NULL);
4042
4043   priv = context->priv;
4044   engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
4045
4046   cairo_save (cr);
4047
4048   pango_layout_get_extents (layout, &extents, NULL);
4049
4050   store_animation_region (context,
4051                           x + extents.x,
4052                           y + extents.y,
4053                           extents.width,
4054                           extents.height);
4055
4056   _gtk_theming_engine_set_context (priv->theming_engine, context);
4057   engine_class->render_layout (priv->theming_engine, cr, x, y, layout);
4058
4059   cairo_restore (cr);
4060 }
4061
4062 /**
4063  * gtk_render_line:
4064  * @context: a #GtkStyleContext
4065  * @cr: a #cairo_t
4066  * @x0: X coordinate for the origin of the line
4067  * @y0: Y coordinate for the origin of the line
4068  * @x1: X coordinate for the end of the line
4069  * @y1: Y coordinate for the end of the line
4070  *
4071  * Renders a line from (x0, y0) to (x1, y1).
4072  *
4073  * Since: 3.0
4074  **/
4075 void
4076 gtk_render_line (GtkStyleContext *context,
4077                  cairo_t         *cr,
4078                  gdouble          x0,
4079                  gdouble          y0,
4080                  gdouble          x1,
4081                  gdouble          y1)
4082 {
4083   GtkStyleContextPrivate *priv;
4084   GtkThemingEngineClass *engine_class;
4085
4086   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
4087   g_return_if_fail (cr != NULL);
4088
4089   priv = context->priv;
4090   engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
4091
4092   cairo_save (cr);
4093
4094   _gtk_theming_engine_set_context (priv->theming_engine, context);
4095   engine_class->render_line (priv->theming_engine, cr, x0, y0, x1, y1);
4096
4097   cairo_restore (cr);
4098 }
4099
4100 /**
4101  * gtk_render_slider:
4102  * @context: a #GtkStyleContext
4103  * @cr: a #cairo_t
4104  * @x: X origin of the rectangle
4105  * @y: Y origin of the rectangle
4106  * @width: rectangle width
4107  * @height: rectangle height
4108  * @orientation: orientation of the slider
4109  *
4110  * Renders a slider (as in #GtkScale) in the rectangle defined by @x, @y,
4111  * @width, @height. @orientation defines whether the slider is vertical
4112  * or horizontal.
4113  *
4114  * <example>
4115  * <title>Typical slider rendering</title>
4116  * <inlinegraphic fileref="sliders.png" format="PNG"/>
4117  * </example>
4118  *
4119  * Since: 3.0
4120  **/
4121 void
4122 gtk_render_slider (GtkStyleContext *context,
4123                    cairo_t         *cr,
4124                    gdouble          x,
4125                    gdouble          y,
4126                    gdouble          width,
4127                    gdouble          height,
4128                    GtkOrientation   orientation)
4129 {
4130   GtkStyleContextPrivate *priv;
4131   GtkThemingEngineClass *engine_class;
4132
4133   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
4134   g_return_if_fail (cr != NULL);
4135
4136   if (width <= 0 || height <= 0)
4137     return;
4138
4139   priv = context->priv;
4140   engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
4141
4142   cairo_save (cr);
4143
4144   store_animation_region (context, x, y, width, height);
4145
4146   _gtk_theming_engine_set_context (priv->theming_engine, context);
4147   engine_class->render_slider (priv->theming_engine, cr, x, y, width, height, orientation);
4148
4149   cairo_restore (cr);
4150 }
4151
4152 /**
4153  * gtk_render_frame_gap:
4154  * @context: a #GtkStyleContext
4155  * @cr: a #cairo_t
4156  * @x: X origin of the rectangle
4157  * @y: Y origin of the rectangle
4158  * @width: rectangle width
4159  * @height: rectangle height
4160  * @gap_side: side where the gap is
4161  * @xy0_gap: initial coordinate (X or Y depending on @gap_side) for the gap
4162  * @xy1_gap: end coordinate (X or Y depending on @gap_side) for the gap
4163  *
4164  * Renders a frame around the rectangle defined by (@x, @y, @width, @height),
4165  * leaving a gap on one side. @xy0_gap and @xy1_gap will mean X coordinates
4166  * for %GTK_POS_TOP and %GTK_POS_BOTTOM gap sides, and Y coordinates for
4167  * %GTK_POS_LEFT and %GTK_POS_RIGHT.
4168  *
4169  * <example>
4170  * <title>Typical rendering of a frame with a gap</title>
4171  * <inlinegraphic fileref="frame-gap.png" format="PNG"/>
4172  * </example>
4173  *
4174  * Since: 3.0
4175  **/
4176 void
4177 gtk_render_frame_gap (GtkStyleContext *context,
4178                       cairo_t         *cr,
4179                       gdouble          x,
4180                       gdouble          y,
4181                       gdouble          width,
4182                       gdouble          height,
4183                       GtkPositionType  gap_side,
4184                       gdouble          xy0_gap,
4185                       gdouble          xy1_gap)
4186 {
4187   GtkStyleContextPrivate *priv;
4188   GtkThemingEngineClass *engine_class;
4189
4190   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
4191   g_return_if_fail (cr != NULL);
4192   g_return_if_fail (xy0_gap <= xy1_gap);
4193   g_return_if_fail (xy0_gap >= 0);
4194
4195   if (width <= 0 || height <= 0)
4196     return;
4197
4198   if (gap_side == GTK_POS_LEFT ||
4199       gap_side == GTK_POS_RIGHT)
4200     g_return_if_fail (xy1_gap <= height);
4201   else
4202     g_return_if_fail (xy1_gap <= width);
4203
4204   priv = context->priv;
4205   engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
4206
4207   cairo_save (cr);
4208
4209   store_animation_region (context, x, y, width, height);
4210
4211   _gtk_theming_engine_set_context (priv->theming_engine, context);
4212   engine_class->render_frame_gap (priv->theming_engine, cr,
4213                                   x, y, width, height, gap_side,
4214                                   xy0_gap, xy1_gap);
4215
4216   cairo_restore (cr);
4217 }
4218
4219 /**
4220  * gtk_render_extension:
4221  * @context: a #GtkStyleContext
4222  * @cr: a #cairo_t
4223  * @x: X origin of the rectangle
4224  * @y: Y origin of the rectangle
4225  * @width: rectangle width
4226  * @height: rectangle height
4227  * @gap_side: side where the gap is
4228  *
4229  * Renders a extension (as in a #GtkNotebook tab) in the rectangle
4230  * defined by @x, @y, @width, @height. The side where the extension
4231  * connects to is defined by @gap_side.
4232  *
4233  * <example>
4234  * <title>Typical extension rendering</title>
4235  * <inlinegraphic fileref="extensions.png" format="PNG"/>
4236  * </example>
4237  *
4238  * Since: 3.0
4239  **/
4240 void
4241 gtk_render_extension (GtkStyleContext *context,
4242                       cairo_t         *cr,
4243                       gdouble          x,
4244                       gdouble          y,
4245                       gdouble          width,
4246                       gdouble          height,
4247                       GtkPositionType  gap_side)
4248 {
4249   GtkStyleContextPrivate *priv;
4250   GtkThemingEngineClass *engine_class;
4251
4252   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
4253   g_return_if_fail (cr != NULL);
4254
4255   if (width <= 0 || height <= 0)
4256     return;
4257
4258   priv = context->priv;
4259   engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
4260
4261   cairo_save (cr);
4262
4263   store_animation_region (context, x, y, width, height);
4264
4265   _gtk_theming_engine_set_context (priv->theming_engine, context);
4266   engine_class->render_extension (priv->theming_engine, cr, x, y, width, height, gap_side);
4267
4268   cairo_restore (cr);
4269 }
4270
4271 /**
4272  * gtk_render_handle:
4273  * @context: a #GtkStyleContext
4274  * @cr: a #cairo_t
4275  * @x: X origin of the rectangle
4276  * @y: Y origin of the rectangle
4277  * @width: rectangle width
4278  * @height: rectangle height
4279  *
4280  * Renders a handle (as in #GtkHandleBox, #GtkPaned and
4281  * #GtkWindow<!-- -->'s resize grip), in the rectangle
4282  * determined by @x, @y, @width, @height.
4283  *
4284  * <example>
4285  * <title>Handles rendered for the paned and grip classes</title>
4286  * <inlinegraphic fileref="handles.png" format="PNG"/>
4287  * </example>
4288  *
4289  * Since: 3.0
4290  **/
4291 void
4292 gtk_render_handle (GtkStyleContext *context,
4293                    cairo_t         *cr,
4294                    gdouble          x,
4295                    gdouble          y,
4296                    gdouble          width,
4297                    gdouble          height)
4298 {
4299   GtkStyleContextPrivate *priv;
4300   GtkThemingEngineClass *engine_class;
4301
4302   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
4303   g_return_if_fail (cr != NULL);
4304
4305   if (width <= 0 || height <= 0)
4306     return;
4307
4308   priv = context->priv;
4309   engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
4310
4311   cairo_save (cr);
4312
4313   store_animation_region (context, x, y, width, height);
4314
4315   _gtk_theming_engine_set_context (priv->theming_engine, context);
4316   engine_class->render_handle (priv->theming_engine, cr, x, y, width, height);
4317
4318   cairo_restore (cr);
4319 }
4320
4321 /**
4322  * gtk_render_activity:
4323  * @context: a #GtkStyleContext
4324  * @cr: a #cairo_t
4325  * @x: X origin of the rectangle
4326  * @y: Y origin of the rectangle
4327  * @width: rectangle width
4328  * @height: rectangle height
4329  *
4330  * Renders an activity area (Such as in #GtkSpinner or the
4331  * fill line in #GtkRange), the state %GTK_STATE_FLAG_ACTIVE
4332  * determines whether there is activity going on.
4333  *
4334  * Since: 3.0
4335  **/
4336 void
4337 gtk_render_activity (GtkStyleContext *context,
4338                      cairo_t         *cr,
4339                      gdouble          x,
4340                      gdouble          y,
4341                      gdouble          width,
4342                      gdouble          height)
4343 {
4344   GtkStyleContextPrivate *priv;
4345   GtkThemingEngineClass *engine_class;
4346
4347   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
4348   g_return_if_fail (cr != NULL);
4349
4350   if (width <= 0 || height <= 0)
4351     return;
4352
4353   priv = context->priv;
4354   engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
4355
4356   cairo_save (cr);
4357
4358   store_animation_region (context, x, y, width, height);
4359
4360   _gtk_theming_engine_set_context (priv->theming_engine, context);
4361   engine_class->render_activity (priv->theming_engine, cr, x, y, width, height);
4362
4363   cairo_restore (cr);
4364 }
4365
4366 /**
4367  * gtk_render_icon_pixbuf:
4368  * @context: a #GtkStyleContext
4369  * @source: the #GtkIconSource specifying the icon to render
4370  * @size: (type int): the size to render the icon at. A size of (GtkIconSize) -1
4371  *        means render at the size of the source and don't scale.
4372  *
4373  * Renders the icon specified by @source at the given @size, returning the result
4374  * in a pixbuf.
4375  *
4376  * Returns: (transfer full): a newly-created #GdkPixbuf containing the rendered icon
4377  *
4378  * Since: 3.0
4379  **/
4380 GdkPixbuf *
4381 gtk_render_icon_pixbuf (GtkStyleContext     *context,
4382                         const GtkIconSource *source,
4383                         GtkIconSize          size)
4384 {
4385   GtkStyleContextPrivate *priv;
4386   GtkThemingEngineClass *engine_class;
4387
4388   g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), NULL);
4389   g_return_val_if_fail (size > GTK_ICON_SIZE_INVALID || size == -1, NULL);
4390   g_return_val_if_fail (source != NULL, NULL);
4391
4392   priv = context->priv;
4393   engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
4394
4395   _gtk_theming_engine_set_context (priv->theming_engine, context);
4396   return engine_class->render_icon_pixbuf (priv->theming_engine, source, size);
4397 }