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