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