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