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