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