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