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