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