]> Pileus Git - ~andy/gtk/blob - gtk/gtkstylecontext.c
Change semantics of the methods to check whether an animation is running.
[~andy/gtk] / gtk / gtkstylecontext.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 2010 Carlos Garnacho <carlosg@gnome.org>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 #include "config.h"
21
22 #include <gdk/gdk.h>
23 #include <stdlib.h>
24 #include <gobject/gvaluecollector.h>
25
26 #include "gtkstylecontext.h"
27 #include "gtktypebuiltins.h"
28 #include "gtkthemingengine.h"
29 #include "gtkintl.h"
30 #include "gtkwidget.h"
31 #include "gtkwindow.h"
32 #include "gtkprivate.h"
33 #include "gtkanimationdescription.h"
34 #include "gtktimeline.h"
35
36 /**
37  * SECTION:gtkstylecontext
38  * @Short_description: rendering UI elements
39  * @Title: GtkStyleContext
40  * @See_also:
41  *
42  * #GtkStyleContext is an object that stores styling information affecting
43  * a widget defined by #GtkWidgetPath.
44  *
45  * In order to construct the final style information, #GtkStyleContext
46  * queries information to all attached #GtkStyleProvider<!-- -->s, either
47  * to the context specifically through gtk_style_context_add_provider(), or
48  * to the screen through gtk_style_context_add_provider_for_screen(). The
49  * resulting style is a combination of all provider's information in priority
50  * order.
51  *
52  * For GTK+ widgets, any #GtkStyleContext returned by
53  * gtk_widget_get_style_context() will already have a #GtkWidgetPath, a
54  * #GdkScreen and RTL/LTR information set, the style context will be also
55  * updated automatically if any of these settings change on the widget.
56  *
57  * If you using are the theming layer standalone, you will need to set a
58  * widget path and a screen yourself to the created style context through
59  * gtk_style_context_set_path() and gtk_style_context_set_screen(), as well
60  * as updating the context yourself using gtk_style_context_invalidate()
61  * whenever any of the conditions change, such as a change in the
62  * #GtkSettings:gtk-theme-name property or a hierarchy change in the rendered
63  * widget.
64  *
65  * <refsect2 id="gtkstylecontext-animations">
66  * <title>Transition animations</title>
67  * <para>
68  * #GtkStyleContext has built-in support for state change transitions.
69  * </para>
70  * <note>
71  * For simple widgets where state changes affect the whole widget area,
72  * calling gtk_style_context_notify_state_change() with a %NULL identifier
73  * would be sufficient.
74  * </note>
75  * <para>
76  * If a widget needs to declare several animatable regions (i.e. not
77  * affecting the whole widget area), its #GtkWidget::draw signal handler
78  * needs to wrap the render operations for the different regions around
79  * gtk_style_context_push_animatable_region() and
80  * gtk_style_context_pop_animatable_region(). These functions take an
81  * unique identifier within the style context, for simple widgets with
82  * little animatable regions, an enum may be used:
83  * </para>
84  * <example>
85  * <title>Using an enum as animatable region identifier</title>
86  * <programlisting>
87  * enum {
88  *   REGION_ENTRY,
89  *   REGION_BUTTON_UP,
90  *   REGION_BUTTON_DOWN
91  * };
92  *
93  * ...
94  *
95  * gboolean
96  * spin_button_draw (GtkWidget *widget,
97  *                   cairo_t   *cr)
98  * {
99  *   GtkStyleContext *context;
100  *
101  *   context = gtk_widget_get_style_context (widget);
102  *
103  *   gtk_style_context_push_animatable_region (context,
104  *                                             GUINT_TO_POINTER (REGION_ENTRY));
105  *
106  *   gtk_render_background (cr, 0, 0, 100, 30);
107  *   gtk_render_frame (cr, 0, 0, 100, 30);
108  *
109  *   gtk_style_context_pop_animatable_region (context);
110  *
111  *   ...
112  * }
113  * </programlisting>
114  * </example>
115  * <para>
116  * For complex widgets with an arbitrary number of animatable regions, it
117  * is up to the implementation to come up with a way to univocally identify
118  * an animatable region, pointers to internal structs would suffice.
119  * </para>
120  * <example>
121  * <title>Using an arbitrary pointer as animatable region identifier</title>
122  * <programlisting>
123  * void
124  * notebook_draw_tab (GtkWidget    *widget,
125  *                    NotebookPage *page,
126  *                    cairo_t      *cr)
127  * {
128  *   gtk_style_context_push_animatable_region (context, page);
129  *   gtk_render_extension (cr, page->x, page->y, page->width, page->height);
130  *   gtk_style_context_pop_animatable_region (context);
131  * }
132  * </programlisting>
133  * </example>
134  * <para>
135  * The widget also needs to notify the style context about a state change
136  * for a given animatable region so the animation is triggered.
137  * </para>
138  * <example>
139  * <title>Triggering a state change animation on a region</title>
140  * <programlisting>
141  * gboolean
142  * notebook_motion_notify (GtkWidget      *widget,
143  *                         GdkEventMotion *event)
144  * {
145  *   GtkStyleContext *context;
146  *   NotebookPage *page;
147  *
148  *   context = gtk_widget_get_style_context (widget);
149  *   page = find_page_under_pointer (widget, event);
150  *   gtk_style_context_notify_state_change (context,
151  *                                          gtk_widget_get_window (widget),
152  *                                          page,
153  *                                          GTK_STATE_PRELIGHT,
154  *                                          TRUE);
155  *   ...
156  * }
157  * </programlisting>
158  * </example>
159  * <para>
160  * gtk_style_context_notify_state_change() accepts %NULL region IDs as a
161  * special value, in this case, the whole widget area will be updated
162  * by the animation.
163  * </para>
164  * </refsect2>
165  *
166  * <refsect2 id="gtkstylecontext-custom-styling">
167  * <title>Custom styling in UI libraries and applications</title>
168  * <para>
169  * If you are developing a library with custom #GtkWidget<!-- -->s that
170  * render differently than standard components, you may need to add a
171  * #GtkStyleProvider yourself with the %GTK_STYLE_PROVIDER_PRIORITY_FALLBACK
172  * priority, either a #GtkCssProvider or a custom object implementing the
173  * #GtkStyleProvider interface. This way theming engines may still attempt
174  * to style your UI elements in a different way if needed so.
175  * </para>
176  * <para>
177  * If you are using custom styling on an applications, you probably want then
178  * to make your style information prevail to the theme's, so you must use
179  * a #GtkStyleProvider with the %GTK_STYLE_PROVIDER_PRIORITY_APPLICATION
180  * priority, keep in mind that the user settings in $HOME/.gtk-3.0.css will
181  * still take precedence over your changes, as it uses the
182  * %GTK_STYLE_PROVIDER_PRIORITY_USER priority.
183  * </para>
184  * <para>
185  * If a custom theming engine is needed, you probably want to implement a
186  * #GtkStyleProvider yourself so it points to your #GtkThemingEngine
187  * implementation, as #GtkCssProvider uses gtk_theming_engine_load()
188  * which loads the theming engine module from the standard paths.
189  * </para>
190  * </refsect2>
191  */
192
193 typedef struct GtkStyleContextPrivate GtkStyleContextPrivate;
194 typedef struct GtkStyleProviderData GtkStyleProviderData;
195 typedef struct GtkStyleInfo GtkStyleInfo;
196 typedef struct GtkRegion GtkRegion;
197 typedef struct PropertyValue PropertyValue;
198 typedef struct AnimationInfo AnimationInfo;
199 typedef struct StyleData StyleData;
200
201 struct GtkRegion
202 {
203   GQuark class_quark;
204   GtkRegionFlags flags;
205 };
206
207 struct GtkStyleProviderData
208 {
209   GtkStyleProvider *provider;
210   guint priority;
211 };
212
213 struct PropertyValue
214 {
215   GType       widget_type;
216   GParamSpec *pspec;
217   GValue      value;
218 };
219
220 struct GtkStyleInfo
221 {
222   GArray *style_classes;
223   GArray *regions;
224   GtkJunctionSides junction_sides;
225 };
226
227 struct StyleData
228 {
229   GtkStyleSet *store;
230   GSList *icon_factories;
231   GArray *property_cache;
232 };
233
234 struct AnimationInfo
235 {
236   GtkTimeline *timeline;
237
238   gpointer region_id;
239   GdkWindow *window;
240   GtkStateType state;
241   gboolean target_value;
242
243   cairo_region_t *invalidation_region;
244   GArray *rectangles;
245 };
246
247 struct GtkStyleContextPrivate
248 {
249   GdkScreen *screen;
250
251   GList *providers;
252   GList *providers_last;
253
254   GtkWidgetPath *widget_path;
255   GHashTable *style_data;
256   GSList *info_stack;
257   StyleData *current_data;
258
259   GtkStateFlags state_flags;
260
261   GSList *animation_regions;
262   GSList *animations;
263
264   guint animations_invalidated : 1;
265   guint invalidating_context : 1;
266
267   GtkThemingEngine *theming_engine;
268
269   GtkTextDirection direction;
270 };
271
272 enum {
273   PROP_0,
274   PROP_SCREEN,
275   PROP_DIRECTION
276 };
277
278 enum {
279   CHANGED,
280   LAST_SIGNAL
281 };
282
283 guint signals[LAST_SIGNAL] = { 0 };
284
285 static GQuark provider_list_quark = 0;
286
287 static void gtk_style_context_finalize (GObject *object);
288
289 static void gtk_style_context_impl_set_property (GObject      *object,
290                                                  guint         prop_id,
291                                                  const GValue *value,
292                                                  GParamSpec   *pspec);
293 static void gtk_style_context_impl_get_property (GObject      *object,
294                                                  guint         prop_id,
295                                                  GValue       *value,
296                                                  GParamSpec   *pspec);
297
298
299 G_DEFINE_TYPE (GtkStyleContext, gtk_style_context, G_TYPE_OBJECT)
300
301 static void
302 gtk_style_context_class_init (GtkStyleContextClass *klass)
303 {
304   GObjectClass *object_class = G_OBJECT_CLASS (klass);
305
306   object_class->finalize = gtk_style_context_finalize;
307   object_class->set_property = gtk_style_context_impl_set_property;
308   object_class->get_property = gtk_style_context_impl_get_property;
309
310   signals[CHANGED] =
311     g_signal_new (I_("changed"),
312                   G_TYPE_FROM_CLASS (object_class),
313                   G_SIGNAL_RUN_FIRST,
314                   G_STRUCT_OFFSET (GtkStyleContextClass, changed),
315                   NULL, NULL,
316                   g_cclosure_marshal_VOID__VOID,
317                   G_TYPE_NONE, 0);
318
319   g_object_class_install_property (object_class,
320                                    PROP_SCREEN,
321                                    g_param_spec_object ("screen",
322                                                         P_("Screen"),
323                                                         P_("The associated GdkScreen"),
324                                                         GDK_TYPE_SCREEN,
325                                                         GTK_PARAM_READWRITE));
326   g_object_class_install_property (object_class,
327                                    PROP_DIRECTION,
328                                    g_param_spec_enum ("direction",
329                                                       P_("Direction"),
330                                                       P_("Text direction"),
331                                                       GTK_TYPE_TEXT_DIRECTION,
332                                                       GTK_TEXT_DIR_LTR,
333                                                       GTK_PARAM_READWRITE));
334
335   g_type_class_add_private (object_class, sizeof (GtkStyleContextPrivate));
336 }
337
338 static GtkStyleInfo *
339 style_info_new (void)
340 {
341   GtkStyleInfo *info;
342
343   info = g_slice_new0 (GtkStyleInfo);
344   info->style_classes = g_array_new (FALSE, FALSE, sizeof (GQuark));
345   info->regions = g_array_new (FALSE, FALSE, sizeof (GtkRegion));
346
347   return info;
348 }
349
350 static void
351 style_info_free (GtkStyleInfo *info)
352 {
353   g_array_free (info->style_classes, TRUE);
354   g_array_free (info->regions, TRUE);
355   g_slice_free (GtkStyleInfo, info);
356 }
357
358 static GtkStyleInfo *
359 style_info_copy (const GtkStyleInfo *info)
360 {
361   GtkStyleInfo *copy;
362
363   copy = style_info_new ();
364   g_array_insert_vals (copy->style_classes, 0,
365                        info->style_classes->data,
366                        info->style_classes->len);
367
368   g_array_insert_vals (copy->regions, 0,
369                        info->regions->data,
370                        info->regions->len);
371
372   copy->junction_sides = info->junction_sides;
373
374   return copy;
375 }
376
377 static guint
378 style_info_hash (gconstpointer elem)
379 {
380   const GtkStyleInfo *info;
381   guint i, hash = 0;
382
383   info = elem;
384
385   for (i = 0; i < info->style_classes->len; i++)
386     {
387       hash += g_array_index (info->style_classes, GQuark, i);
388       hash <<= 5;
389     }
390
391   for (i = 0; i < info->regions->len; i++)
392     {
393       GtkRegion *region;
394
395       region = &g_array_index (info->regions, GtkRegion, i);
396       hash += region->class_quark;
397       hash += region->flags;
398       hash <<= 5;
399     }
400
401   return hash;
402 }
403
404 static gboolean
405 style_info_equal (gconstpointer elem1,
406                   gconstpointer elem2)
407 {
408   const GtkStyleInfo *info1, *info2;
409
410   info1 = elem1;
411   info2 = elem2;
412
413   if (info1->junction_sides != info2->junction_sides)
414     return FALSE;
415
416   if (info1->style_classes->len != info2->style_classes->len)
417     return FALSE;
418
419   if (memcmp (info1->style_classes->data,
420               info2->style_classes->data,
421               info1->style_classes->len * sizeof (GQuark)) != 0)
422     return FALSE;
423
424   if (info1->regions->len != info2->regions->len)
425     return FALSE;
426
427   if (memcmp (info1->regions->data,
428               info2->regions->data,
429               info1->regions->len * sizeof (GtkRegion)) != 0)
430     return FALSE;
431
432   return TRUE;
433 }
434
435 static StyleData *
436 style_data_new (void)
437 {
438   StyleData *data;
439
440   data = g_slice_new0 (StyleData);
441   data->store = gtk_style_set_new ();
442
443   return data;
444 }
445
446 static void
447 clear_property_cache (StyleData *data)
448 {
449   guint i;
450
451   if (!data->property_cache)
452     return;
453
454   for (i = 0; i < data->property_cache->len; i++)
455     {
456       PropertyValue *node = &g_array_index (data->property_cache, PropertyValue, i);
457
458       g_param_spec_unref (node->pspec);
459       g_value_unset (&node->value);
460     }
461
462   g_array_free (data->property_cache, TRUE);
463   data->property_cache = NULL;
464 }
465
466 static void
467 style_data_free (StyleData *data)
468 {
469   g_object_unref (data->store);
470   clear_property_cache (data);
471
472   g_slist_foreach (data->icon_factories, (GFunc) g_object_unref, NULL);
473   g_slist_free (data->icon_factories);
474
475   g_slice_free (StyleData, data);
476 }
477
478 static void
479 gtk_style_context_init (GtkStyleContext *style_context)
480 {
481   GtkStyleContextPrivate *priv;
482   GtkStyleInfo *info;
483
484   priv = style_context->priv = G_TYPE_INSTANCE_GET_PRIVATE (style_context,
485                                                             GTK_TYPE_STYLE_CONTEXT,
486                                                             GtkStyleContextPrivate);
487
488   priv->style_data = g_hash_table_new_full (style_info_hash,
489                                             style_info_equal,
490                                             (GDestroyNotify) style_info_free,
491                                             (GDestroyNotify) style_data_free);
492   priv->theming_engine = g_object_ref ((gpointer) gtk_theming_engine_load (NULL));
493
494   priv->direction = GTK_TEXT_DIR_RTL;
495
496   /* Create default info store */
497   info = style_info_new ();
498   priv->info_stack = g_slist_prepend (priv->info_stack, info);
499 }
500
501 static GtkStyleProviderData *
502 style_provider_data_new (GtkStyleProvider *provider,
503                          guint             priority)
504 {
505   GtkStyleProviderData *data;
506
507   data = g_slice_new (GtkStyleProviderData);
508   data->provider = g_object_ref (provider);
509   data->priority = priority;
510
511   return data;
512 }
513
514 static void
515 style_provider_data_free (GtkStyleProviderData *data)
516 {
517   g_object_unref (data->provider);
518   g_slice_free (GtkStyleProviderData, data);
519 }
520
521 static void
522 animation_info_free (AnimationInfo *info)
523 {
524   g_object_unref (info->timeline);
525   g_object_unref (info->window);
526
527   if (info->invalidation_region)
528     cairo_region_destroy (info->invalidation_region);
529
530   g_array_free (info->rectangles, TRUE);
531   g_slice_free (AnimationInfo, info);
532 }
533
534 static void
535 timeline_frame_cb (GtkTimeline *timeline,
536                    gdouble      progress,
537                    gpointer     user_data)
538 {
539   AnimationInfo *info;
540
541   info = user_data;
542
543   if (info->invalidation_region &&
544       !cairo_region_is_empty (info->invalidation_region))
545     gdk_window_invalidate_region (info->window, info->invalidation_region, TRUE);
546   else
547     gdk_window_invalidate_rect (info->window, NULL, TRUE);
548 }
549
550 static void
551 timeline_finished_cb (GtkTimeline *timeline,
552                       gpointer     user_data)
553 {
554   GtkStyleContextPrivate *priv;
555   GtkStyleContext *context;
556   AnimationInfo *info;
557   GSList *l;
558
559   context = user_data;
560   priv = context->priv;
561
562   for (l = priv->animations; l; l = l->next)
563     {
564       info = l->data;
565
566       if (info->timeline == timeline)
567         {
568           priv->animations = g_slist_delete_link (priv->animations, l);
569
570           /* Invalidate one last time the area, so the final content is painted */
571           if (info->invalidation_region &&
572               !cairo_region_is_empty (info->invalidation_region))
573             gdk_window_invalidate_region (info->window, info->invalidation_region, TRUE);
574           else
575             gdk_window_invalidate_rect (info->window, NULL, TRUE);
576
577           animation_info_free (info);
578           break;
579         }
580     }
581 }
582
583 static AnimationInfo *
584 animation_info_new (GtkStyleContext         *context,
585                     gpointer                 region_id,
586                     gdouble                  duration,
587                     GtkTimelineProgressType  progress_type,
588                     GtkStateType             state,
589                     gboolean                 target_value,
590                     GdkWindow               *window)
591 {
592   AnimationInfo *info;
593
594   info = g_slice_new0 (AnimationInfo);
595
596   info->rectangles = g_array_new (FALSE, FALSE, sizeof (cairo_rectangle_int_t));
597   info->timeline = gtk_timeline_new (duration);
598   info->window = g_object_ref (window);
599   info->state = state;
600   info->target_value = target_value;
601   info->region_id = region_id;
602
603   gtk_timeline_set_progress_type (info->timeline, progress_type);
604
605   if (!target_value)
606     {
607       gtk_timeline_set_direction (info->timeline, GTK_TIMELINE_DIRECTION_BACKWARD);
608       gtk_timeline_rewind (info->timeline);
609     }
610
611   g_signal_connect (info->timeline, "frame",
612                     G_CALLBACK (timeline_frame_cb), info);
613   g_signal_connect (info->timeline, "finished",
614                     G_CALLBACK (timeline_finished_cb), context);
615
616   gtk_timeline_start (info->timeline);
617
618   return info;
619 }
620
621 static AnimationInfo *
622 animation_info_lookup (GtkStyleContext *context,
623                        gpointer         region_id,
624                        GtkStateType     state)
625 {
626   GtkStyleContextPrivate *priv;
627   GSList *l;
628
629   priv = context->priv;
630
631   for (l = priv->animations; l; l = l->next)
632     {
633       AnimationInfo *info;
634
635       info = l->data;
636
637       if (info->state == state &&
638           info->region_id == region_id)
639         return info;
640     }
641
642   return NULL;
643 }
644
645 static void
646 gtk_style_context_finalize (GObject *object)
647 {
648   GtkStyleContextPrivate *priv;
649   GtkStyleContext *style_context;
650   GSList *l;
651
652   style_context = GTK_STYLE_CONTEXT (object);
653   priv = style_context->priv;
654
655   if (priv->widget_path)
656     gtk_widget_path_free (priv->widget_path);
657
658   g_hash_table_destroy (priv->style_data);
659
660   g_list_foreach (priv->providers, (GFunc) style_provider_data_free, NULL);
661   g_list_free (priv->providers);
662
663   g_slist_foreach (priv->info_stack, (GFunc) style_info_free, NULL);
664   g_slist_free (priv->info_stack);
665
666   g_slist_free (priv->animation_regions);
667
668   for (l = priv->animations; l; l = l->next)
669     animation_info_free ((AnimationInfo *) l->data);
670
671   g_slist_free (priv->animations);
672
673   if (priv->theming_engine)
674     g_object_unref (priv->theming_engine);
675
676   G_OBJECT_CLASS (gtk_style_context_parent_class)->finalize (object);
677 }
678
679 static void
680 gtk_style_context_impl_set_property (GObject      *object,
681                                      guint         prop_id,
682                                      const GValue *value,
683                                      GParamSpec   *pspec)
684 {
685   GtkStyleContextPrivate *priv;
686   GtkStyleContext *style_context;
687
688   style_context = GTK_STYLE_CONTEXT (object);
689   priv = style_context->priv;
690
691   switch (prop_id)
692     {
693     case PROP_SCREEN:
694       gtk_style_context_set_screen (style_context,
695                                     g_value_get_object (value));
696       break;
697     case PROP_DIRECTION:
698       gtk_style_context_set_direction (style_context,
699                                        g_value_get_enum (value));
700       break;
701     default:
702       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
703       break;
704     }
705 }
706
707 static void
708 gtk_style_context_impl_get_property (GObject    *object,
709                                      guint       prop_id,
710                                      GValue     *value,
711                                      GParamSpec *pspec)
712 {
713   GtkStyleContextPrivate *priv;
714   GtkStyleContext *style_context;
715
716   style_context = GTK_STYLE_CONTEXT (object);
717   priv = style_context->priv;
718
719   switch (prop_id)
720     {
721     case PROP_SCREEN:
722       g_value_set_object (value, priv->screen);
723       break;
724     case PROP_DIRECTION:
725       g_value_set_enum (value, priv->direction);
726       break;
727     default:
728       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
729       break;
730     }
731 }
732
733 static GList *
734 find_next_candidate (GList *local,
735                      GList *global)
736 {
737   if (local && global)
738     {
739       GtkStyleProviderData *local_data, *global_data;
740
741       local_data = local->data;
742       global_data = global->data;
743
744       if (local_data->priority >= global_data->priority)
745         return local;
746       else
747         return global;
748     }
749   else if (local)
750     return local;
751   else if (global)
752     return global;
753
754   return NULL;
755 }
756
757 static void
758 build_properties (GtkStyleContext *context,
759                   StyleData       *style_data,
760                   GtkWidgetPath   *path)
761 {
762   GtkStyleContextPrivate *priv;
763   GList *elem, *list, *global_list = NULL;
764
765   priv = context->priv;
766   list = priv->providers;
767
768   if (priv->screen)
769     global_list = g_object_get_qdata (G_OBJECT (priv->screen), provider_list_quark);
770
771   while ((elem = find_next_candidate (list, global_list)) != NULL)
772     {
773       GtkStyleProviderData *data;
774       GtkStyleSet *provider_style;
775
776       data = elem->data;
777
778       if (elem == list)
779         list = list->next;
780       else
781         global_list = global_list->next;
782
783       provider_style = gtk_style_provider_get_style (data->provider, path);
784
785       if (provider_style)
786         {
787           gtk_style_set_merge (style_data->store, provider_style, TRUE);
788           g_object_unref (provider_style);
789         }
790     }
791 }
792
793 static void
794 build_icon_factories (GtkStyleContext *context,
795                       StyleData       *style_data,
796                       GtkWidgetPath   *path)
797 {
798   GtkStyleContextPrivate *priv;
799   GList *elem, *list, *global_list = NULL;
800
801   priv = context->priv;
802   list = priv->providers_last;
803
804   if (priv->screen)
805     {
806       global_list = g_object_get_qdata (G_OBJECT (priv->screen), provider_list_quark);
807       global_list = g_list_last (global_list);
808     }
809
810   while ((elem = find_next_candidate (list, global_list)) != NULL)
811     {
812       GtkIconFactory *factory;
813       GtkStyleProviderData *data;
814
815       data = elem->data;
816
817       if (elem == list)
818         list = list->prev;
819       else
820         global_list = global_list->prev;
821
822       factory = gtk_style_provider_get_icon_factory (data->provider, path);
823
824       if (factory)
825         style_data->icon_factories = g_slist_prepend (style_data->icon_factories, factory);
826     }
827 }
828
829 GtkWidgetPath *
830 create_query_path (GtkStyleContext *context)
831 {
832   GtkStyleContextPrivate *priv;
833   GtkWidgetPath *path;
834   GtkStyleInfo *info;
835   guint i, pos;
836
837   priv = context->priv;
838   path = gtk_widget_path_copy (priv->widget_path);
839   pos = gtk_widget_path_length (path) - 1;
840
841   info = priv->info_stack->data;
842
843   /* Set widget regions */
844   for (i = 0; i < info->regions->len; i++)
845     {
846       GtkRegion *region;
847
848       region = &g_array_index (info->regions, GtkRegion, i);
849       gtk_widget_path_iter_add_region (path, pos,
850                                        g_quark_to_string (region->class_quark),
851                                        region->flags);
852     }
853
854   /* Set widget classes */
855   for (i = 0; i < info->style_classes->len; i++)
856     {
857       GQuark quark;
858
859       quark = g_array_index (info->style_classes, GQuark, i);
860       gtk_widget_path_iter_add_class (path, pos,
861                                       g_quark_to_string (quark));
862     }
863
864   return path;
865 }
866
867 static StyleData *
868 style_data_lookup (GtkStyleContext *context)
869 {
870   GtkStyleContextPrivate *priv;
871   StyleData *data;
872
873   priv = context->priv;
874
875   /* Current data in use is cached, just return it */
876   if (priv->current_data)
877     return priv->current_data;
878
879   g_assert (priv->widget_path != NULL);
880
881   data = g_hash_table_lookup (priv->style_data, priv->info_stack->data);
882
883   if (!data)
884     {
885       GtkWidgetPath *path;
886
887       data = style_data_new ();
888       path = create_query_path (context);
889
890       build_properties (context, data, path);
891       build_icon_factories (context, data, path);
892
893       g_hash_table_insert (priv->style_data,
894                            style_info_copy (priv->info_stack->data),
895                            data);
896
897       gtk_widget_path_free (path);
898     }
899
900   priv->current_data = data;
901
902   if (priv->theming_engine)
903     g_object_unref (priv->theming_engine);
904
905   gtk_style_set_get (data->store, 0,
906                      "engine", &priv->theming_engine,
907                      NULL);
908   return data;
909 }
910
911 static void
912 style_provider_add (GList            **list,
913                     GtkStyleProvider  *provider,
914                     guint              priority)
915 {
916   GtkStyleProviderData *new_data;
917   gboolean added = FALSE;
918   GList *l = *list;
919
920   new_data = style_provider_data_new (provider, priority);
921
922   while (l)
923     {
924       GtkStyleProviderData *data;
925
926       data = l->data;
927
928       /* Provider was already attached to the style
929        * context, remove in order to add the new data
930        */
931       if (data->provider == provider)
932         {
933           GList *link;
934
935           link = l;
936           l = l->next;
937
938           /* Remove and free link */
939           *list = g_list_remove_link (*list, link);
940           style_provider_data_free (link->data);
941           g_list_free_1 (link);
942
943           continue;
944         }
945
946       if (!added &&
947           data->priority > priority)
948         {
949           *list = g_list_insert_before (*list, l, new_data);
950           added = TRUE;
951         }
952
953       l = l->next;
954     }
955
956   if (!added)
957     *list = g_list_append (*list, new_data);
958 }
959
960 static gboolean
961 style_provider_remove (GList            **list,
962                        GtkStyleProvider  *provider)
963 {
964   GList *l = *list;
965
966   while (l)
967     {
968       GtkStyleProviderData *data;
969
970       data = l->data;
971
972       if (data->provider == provider)
973         {
974           *list = g_list_remove_link (*list, l);
975           style_provider_data_free (l->data);
976           g_list_free_1 (l);
977
978           return TRUE;
979         }
980
981       l = l->next;
982     }
983
984   return FALSE;
985 }
986
987 /**
988  * gtk_style_context_add_provider:
989  * @context: a #GtkStyleContext
990  * @provider: a #GtkStyleProvider
991  * @priority: the priority of the style provider. The lower
992  *            it is, the earlier it will be used in the style
993  *            construction. Typically this will be in the range
994  *            between %GTK_STYLE_PROVIDER_PRIORITY_FALLBACK and
995  *            %GTK_STYLE_PROVIDER_PRIORITY_USER
996  *
997  * Adds a style provider to @context, to be used in style construction.
998  *
999  * Since: 3.0
1000  **/
1001 void
1002 gtk_style_context_add_provider (GtkStyleContext  *context,
1003                                 GtkStyleProvider *provider,
1004                                 guint             priority)
1005 {
1006   GtkStyleContextPrivate *priv;
1007
1008   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
1009   g_return_if_fail (GTK_IS_STYLE_PROVIDER (provider));
1010
1011   priv = context->priv;
1012   style_provider_add (&priv->providers, provider, priority);
1013   priv->providers_last = g_list_last (priv->providers);
1014
1015   gtk_style_context_invalidate (context);
1016 }
1017
1018 /**
1019  * gtk_style_context_remove_provider:
1020  * @context: a #GtkStyleContext
1021  * @provider: a #GtkStyleProvider
1022  *
1023  * Removes @provider from the style providers list in @context.
1024  *
1025  * Since: 3.0
1026  **/
1027 void
1028 gtk_style_context_remove_provider (GtkStyleContext  *context,
1029                                    GtkStyleProvider *provider)
1030 {
1031   GtkStyleContextPrivate *priv;
1032
1033   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
1034   g_return_if_fail (GTK_IS_STYLE_PROVIDER (provider));
1035
1036   priv = context->priv;
1037
1038   if (style_provider_remove (&priv->providers, provider))
1039     {
1040       priv->providers_last = g_list_last (priv->providers);
1041
1042       gtk_style_context_invalidate (context);
1043     }
1044 }
1045
1046 /**
1047  * gtk_style_context_reset_widgets:
1048  * @screen: a #GdkScreen
1049  *
1050  * This function recomputes the styles for all widgets under a particular
1051  * #GdkScreen. This is useful when some global parameter has changed that
1052  * affects the appearance of all widgets, because when a widget gets a new
1053  * style, it will both redraw and recompute any cached information about
1054  * its appearance. As an example, it is used when the color scheme changes
1055  * in the related #GtkSettings object.
1056  *
1057  * Since: 3.0
1058  **/
1059 void
1060 gtk_style_context_reset_widgets (GdkScreen *screen)
1061 {
1062   GList *list, *toplevels;
1063
1064   toplevels = gtk_window_list_toplevels ();
1065   g_list_foreach (toplevels, (GFunc) g_object_ref, NULL);
1066
1067   for (list = toplevels; list; list = list->next)
1068     {
1069       if (gtk_widget_get_screen (list->data) == screen)
1070         gtk_widget_reset_style (list->data);
1071
1072       g_object_unref (list->data);
1073     }
1074
1075   g_list_free (toplevels);
1076 }
1077
1078 /**
1079  * gtk_style_context_add_provider_for_screen:
1080  * @screen: a #GdkScreen
1081  * @provider: a #GtkStyleProvider
1082  * @priority: the priority of the style provider. The lower
1083  *            it is, the earlier it will be used in the style
1084  *            construction. Typically this will be in the range
1085  *            between %GTK_STYLE_PROVIDER_PRIORITY_FALLBACK and
1086  *            %GTK_STYLE_PROVIDER_PRIORITY_USER
1087  *
1088  * Adds a global style provider to @screen, which will be used
1089  * in style construction for all #GtkStyleContext<!-- -->s under
1090  * @screen.
1091  *
1092  * Since: 3.0
1093  **/
1094 void
1095 gtk_style_context_add_provider_for_screen (GdkScreen        *screen,
1096                                            GtkStyleProvider *provider,
1097                                            guint             priority)
1098 {
1099   GList *providers, *list;
1100
1101   g_return_if_fail (GDK_IS_SCREEN (screen));
1102   g_return_if_fail (GTK_IS_STYLE_PROVIDER (provider));
1103
1104   if (G_UNLIKELY (!provider_list_quark))
1105     provider_list_quark = g_quark_from_static_string ("gtk-provider-list-quark");
1106
1107   list = providers = g_object_get_qdata (G_OBJECT (screen), provider_list_quark);
1108   style_provider_add (&list, provider, priority);
1109
1110   if (list != providers)
1111     g_object_set_qdata (G_OBJECT (screen), provider_list_quark, list);
1112
1113   gtk_style_context_reset_widgets (screen);
1114 }
1115
1116 /**
1117  * gtk_style_context_remove_provider_for_screen:
1118  * @screen: a #GdkScreen
1119  * @provider: a #GtkStyleProvider
1120  *
1121  * Removes @provider from the global style providers list in @screen.
1122  *
1123  * Since: 3.0
1124  **/
1125 void
1126 gtk_style_context_remove_provider_for_screen (GdkScreen        *screen,
1127                                               GtkStyleProvider *provider)
1128 {
1129   GList *providers, *list;
1130
1131   g_return_if_fail (GDK_IS_SCREEN (screen));
1132   g_return_if_fail (GTK_IS_STYLE_PROVIDER (provider));
1133
1134   if (G_UNLIKELY (!provider_list_quark))
1135     return;
1136
1137   list = providers = g_object_get_qdata (G_OBJECT (screen), provider_list_quark);
1138
1139   if (style_provider_remove (&list, provider))
1140     {
1141       if (list != providers)
1142         g_object_set_qdata (G_OBJECT (screen), provider_list_quark, list);
1143
1144       gtk_style_context_reset_widgets (screen);
1145     }
1146 }
1147
1148 /**
1149  * gtk_style_context_get_property:
1150  * @context: a #GtkStyleContext
1151  * @property: style property name
1152  * @state: state to retrieve the property value for
1153  * @value: (out) (transfer full):  return location for the style property value.
1154  *
1155  * Gets a style property from @context for the given state. When done with @value,
1156  * g_value_unset() needs to be called to free any allocated memory.
1157  *
1158  * Since: 3.0
1159  **/
1160 void
1161 gtk_style_context_get_property (GtkStyleContext *context,
1162                                 const gchar     *property,
1163                                 GtkStateFlags    state,
1164                                 GValue          *value)
1165 {
1166   GtkStyleContextPrivate *priv;
1167   StyleData *data;
1168
1169   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
1170   g_return_if_fail (property != NULL);
1171   g_return_if_fail (value != NULL);
1172
1173   priv = context->priv;
1174
1175   g_return_if_fail (priv->widget_path != NULL);
1176
1177   data = style_data_lookup (context);
1178   gtk_style_set_get_property (data->store, property, state, value);
1179 }
1180
1181 /**
1182  * gtk_style_context_get_valist:
1183  * @context: a #GtkStyleContext
1184  * @state: state to retrieve the property values for
1185  * @args: va_list of property name/return location pairs, followed by %NULL
1186  *
1187  * Retrieves several style property values from @context for a given state.
1188  *
1189  * Since: 3.0
1190  **/
1191 void
1192 gtk_style_context_get_valist (GtkStyleContext *context,
1193                               GtkStateFlags    state,
1194                               va_list          args)
1195 {
1196   GtkStyleContextPrivate *priv;
1197   StyleData *data;
1198
1199   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
1200
1201   priv = context->priv;
1202   g_return_if_fail (priv->widget_path != NULL);
1203
1204   data = style_data_lookup (context);
1205   gtk_style_set_get_valist (data->store, state, args);
1206 }
1207
1208 /**
1209  * gtk_style_context_get:
1210  * @context: a #GtkStyleContext
1211  * @state: state to retrieve the property values for
1212  * @...: property name /return value pairs, followed by %NULL
1213  *
1214  * Retrieves several style property values from @context for a
1215  * given state.
1216  *
1217  * Since: 3.0
1218  **/
1219 void
1220 gtk_style_context_get (GtkStyleContext *context,
1221                        GtkStateFlags    state,
1222                        ...)
1223 {
1224   GtkStyleContextPrivate *priv;
1225   StyleData *data;
1226   va_list args;
1227
1228   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
1229
1230   priv = context->priv;
1231   g_return_if_fail (priv->widget_path != NULL);
1232
1233   data = style_data_lookup (context);
1234
1235   va_start (args, state);
1236   gtk_style_set_get_valist (data->store, state, args);
1237   va_end (args);
1238 }
1239
1240 /**
1241  * gtk_style_context_set_state:
1242  * @context: a #GtkStyleContext
1243  * @flags: state to represent
1244  *
1245  * Sets the style to be used when rendering with any
1246  * of the "gtk_render_" prefixed functions.
1247  *
1248  * Since: 3.0
1249  **/
1250 void
1251 gtk_style_context_set_state (GtkStyleContext *context,
1252                              GtkStateFlags    flags)
1253 {
1254   GtkStyleContextPrivate *priv;
1255
1256   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
1257
1258   priv = context->priv;
1259   priv->state_flags = flags;
1260 }
1261
1262 /**
1263  * gtk_style_context_get_state:
1264  * @context: a #GtkStyleContext
1265  *
1266  * returns the state used when rendering.
1267  *
1268  * Returns: the state flags
1269  *
1270  * Since: 3.0
1271  **/
1272 GtkStateFlags
1273 gtk_style_context_get_state (GtkStyleContext *context)
1274 {
1275   GtkStyleContextPrivate *priv;
1276
1277   g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), 0);
1278
1279   priv = context->priv;
1280   return priv->state_flags;
1281 }
1282
1283 static gboolean
1284 context_has_animatable_region (GtkStyleContext *context,
1285                                gpointer         region_id)
1286 {
1287   GtkStyleContextPrivate *priv;
1288   GSList *r;
1289
1290   /* NULL region_id means everything
1291    * rendered through the style context
1292    */
1293   if (!region_id)
1294     return TRUE;
1295
1296   priv = context->priv;
1297
1298   for (r = priv->animation_regions; r; r = r->next)
1299     {
1300       if (r->data == region_id)
1301         return TRUE;
1302     }
1303
1304   return FALSE;
1305 }
1306
1307 /**
1308  * gtk_style_context_state_is_running:
1309  * @context: a #GtkStyleContext
1310  * @state: a widget state
1311  * @progress: (out): return location for the transition progress
1312  *
1313  * Returns %TRUE if there is a transition animation running for the
1314  * current region (see gtk_style_context_push_animatable_region()).
1315  *
1316  * If @progress is not %NULL, the animation progress will be returned
1317  * there, 0.0 means the state is closest to being %FALSE, while 1.0 means
1318  * it's closest to being %TRUE. This means transition animations will
1319  * run from 0 to 1 when @state is being set to %TRUE and from 1 to 0 when
1320  * it's being set to %FALSE.
1321  *
1322  * Returns: %TRUE if there is a running transition animation for @state.
1323  *
1324  * Since: 3.0
1325  **/
1326 gboolean
1327 gtk_style_context_state_is_running (GtkStyleContext *context,
1328                                     GtkStateType     state,
1329                                     gdouble         *progress)
1330 {
1331   GtkStyleContextPrivate *priv;
1332   AnimationInfo *info;
1333   GSList *l;
1334
1335   g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), FALSE);
1336
1337   priv = context->priv;
1338
1339   for (l = priv->animations; l; l = l->next)
1340     {
1341       info = l->data;
1342
1343       if (info->state == state &&
1344           context_has_animatable_region (context, info->region_id))
1345         {
1346           if (progress)
1347             *progress = gtk_timeline_get_progress (info->timeline);
1348
1349           return TRUE;
1350         }
1351     }
1352
1353   return FALSE;
1354 }
1355
1356 /**
1357  * gtk_style_context_set_path:
1358  * @context: a #GtkStyleContext
1359  * @path: a #GtkWidgetPath
1360  *
1361  * Sets the #GtkWidgetPath used for style matching. As a
1362  * consequence, the style will be regenerated to match
1363  * the new given path. If you are using a #GtkStyleContext
1364  * returned from gtk_widget_get_style_context(), you do
1365  * not need to call this yourself.
1366  *
1367  * Since: 3.0
1368  **/
1369 void
1370 gtk_style_context_set_path (GtkStyleContext *context,
1371                             GtkWidgetPath   *path)
1372 {
1373   GtkStyleContextPrivate *priv;
1374
1375   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
1376   g_return_if_fail (path != NULL);
1377
1378   priv = context->priv;
1379
1380   if (priv->widget_path)
1381     {
1382       gtk_widget_path_free (priv->widget_path);
1383       priv->widget_path = NULL;
1384     }
1385
1386   if (path)
1387     priv->widget_path = gtk_widget_path_copy (path);
1388
1389   gtk_style_context_invalidate (context);
1390 }
1391
1392 /**
1393  * gtk_style_context_get_path:
1394  * @context: a #GtkStyleContext
1395  *
1396  * Returns the widget path used for style matching.
1397  *
1398  * Returns: (transfer none): A #GtkWidgetPath
1399  *
1400  * Since: 3.0
1401  **/
1402 G_CONST_RETURN GtkWidgetPath *
1403 gtk_style_context_get_path (GtkStyleContext *context)
1404 {
1405   GtkStyleContextPrivate *priv;
1406
1407   priv = context->priv;
1408   return priv->widget_path;
1409 }
1410
1411 /**
1412  * gtk_style_context_save:
1413  * @context: a #GtkStyleContext
1414  *
1415  * Saves the @context state, so all modifications done through
1416  * gtk_style_context_set_class(), gtk_style_context_unset_class(),
1417  * gtk_style_context_set_region(), gtk_style_context_unset_region()
1418  * or gtk_style_context_set_junction_sides() can be reverted in one
1419  * go through gtk_style_context_restore().
1420  *
1421  * Since: 3.0
1422  **/
1423 void
1424 gtk_style_context_save (GtkStyleContext *context)
1425 {
1426   GtkStyleContextPrivate *priv;
1427   GtkStyleInfo *info;
1428
1429   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
1430
1431   priv = context->priv;
1432
1433   g_assert (priv->info_stack != NULL);
1434
1435   info = style_info_copy (priv->info_stack->data);
1436   priv->info_stack = g_slist_prepend (priv->info_stack, info);
1437 }
1438
1439 /**
1440  * gtk_style_context_restore:
1441  * @context: a #GtkStyleContext
1442  *
1443  * Restores @context state to a previous stage. See
1444  * gtk_style_context_save().
1445  *
1446  * Since: 3.0
1447  **/
1448 void
1449 gtk_style_context_restore (GtkStyleContext *context)
1450 {
1451   GtkStyleContextPrivate *priv;
1452   GtkStyleInfo *info;
1453
1454   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
1455
1456   priv = context->priv;
1457
1458   if (priv->info_stack)
1459     {
1460       info = priv->info_stack->data;
1461       priv->info_stack = g_slist_remove (priv->info_stack, info);
1462       style_info_free (info);
1463     }
1464
1465   if (!priv->info_stack)
1466     {
1467       g_warning ("Unpaired gtk_style_context_restore() call");
1468
1469       /* Create default region */
1470       info = style_info_new ();
1471       priv->info_stack = g_slist_prepend (priv->info_stack, info);
1472     }
1473
1474   priv->current_data = NULL;
1475 }
1476
1477 static gboolean
1478 style_class_find (GArray *array,
1479                   GQuark  class_quark,
1480                   guint  *position)
1481 {
1482   gint min, max, mid;
1483   gboolean found = FALSE;
1484   guint pos;
1485
1486   if (position)
1487     *position = 0;
1488
1489   if (!array || array->len == 0)
1490     return FALSE;
1491
1492   min = 0;
1493   max = array->len - 1;
1494
1495   do
1496     {
1497       GQuark item;
1498
1499       mid = (min + max) / 2;
1500       item = g_array_index (array, GQuark, mid);
1501
1502       if (class_quark == item)
1503         {
1504           found = TRUE;
1505           pos = mid;
1506         }
1507       else if (class_quark > item)
1508         min = pos = mid + 1;
1509       else
1510         {
1511           max = mid - 1;
1512           pos = mid;
1513         }
1514     }
1515   while (!found && min <= max);
1516
1517   if (position)
1518     *position = pos;
1519
1520   return found;
1521 }
1522
1523 static gboolean
1524 region_find (GArray *array,
1525              GQuark  class_quark,
1526              guint  *position)
1527 {
1528   gint min, max, mid;
1529   gboolean found = FALSE;
1530   guint pos;
1531
1532   if (position)
1533     *position = 0;
1534
1535   if (!array || array->len == 0)
1536     return FALSE;
1537
1538   min = 0;
1539   max = array->len - 1;
1540
1541   do
1542     {
1543       GtkRegion *region;
1544
1545       mid = (min + max) / 2;
1546       region = &g_array_index (array, GtkRegion, mid);
1547
1548       if (region->class_quark == class_quark)
1549         {
1550           found = TRUE;
1551           pos = mid;
1552         }
1553       else if (region->class_quark > class_quark)
1554         min = pos = mid + 1;
1555       else
1556         {
1557           max = mid - 1;
1558           pos = mid;
1559         }
1560     }
1561   while (!found && min <= max);
1562
1563   if (position)
1564     *position = pos;
1565
1566   return found;
1567 }
1568
1569 /**
1570  * gtk_style_context_set_class:
1571  * @context: a #GtkStyleContext
1572  * @class_name: class name to use in styling
1573  *
1574  * Sets a class name to @context, so posterior calls to
1575  * gtk_style_context_get() or any of the gtk_render_*
1576  * functions will make use of this new class for styling.
1577  *
1578  * In the CSS file format, a #GtkEntry defining an "entry"
1579  * class, would be matched by:
1580  *
1581  * <programlisting>
1582  * GtkEntry.entry { ... }
1583  * </programlisting>
1584  *
1585  * While any widget defining an "entry" class would be
1586  * matched by:
1587  * <programlisting>
1588  * .entry { ... }
1589  * </programlisting>
1590  *
1591  * Since: 3.0
1592  **/
1593 void
1594 gtk_style_context_set_class (GtkStyleContext *context,
1595                              const gchar     *class_name)
1596 {
1597   GtkStyleContextPrivate *priv;
1598   GtkStyleInfo *info;
1599   GQuark class_quark;
1600   guint position;
1601
1602   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
1603   g_return_if_fail (class_name != NULL);
1604
1605   priv = context->priv;
1606   class_quark = g_quark_from_string (class_name);
1607
1608   g_assert (priv->info_stack != NULL);
1609   info = priv->info_stack->data;
1610
1611   if (!style_class_find (info->style_classes, class_quark, &position))
1612     {
1613       g_array_insert_val (info->style_classes, position, class_quark);
1614
1615       /* Unset current data, as it likely changed due to the class change */
1616       priv->current_data = NULL;
1617     }
1618 }
1619
1620 /**
1621  * gtk_style_context_unset_class:
1622  * @context: a #GtkStyleContext
1623  * @class_name: class name to remove
1624  *
1625  * Removes @class_name from @context.
1626  *
1627  * Since: 3.0
1628  **/
1629 void
1630 gtk_style_context_unset_class (GtkStyleContext *context,
1631                                const gchar     *class_name)
1632 {
1633   GtkStyleContextPrivate *priv;
1634   GtkStyleInfo *info;
1635   GQuark class_quark;
1636   guint position;
1637
1638   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
1639   g_return_if_fail (class_name != NULL);
1640
1641   class_quark = g_quark_try_string (class_name);
1642
1643   if (!class_quark)
1644     return;
1645
1646   priv = context->priv;
1647
1648   g_assert (priv->info_stack != NULL);
1649   info = priv->info_stack->data;
1650
1651   if (style_class_find (info->style_classes, class_quark, &position))
1652     {
1653       g_array_remove_index (info->style_classes, position);
1654
1655       /* Unset current data, as it likely changed due to the class change */
1656       priv->current_data = NULL;
1657     }
1658 }
1659
1660 /**
1661  * gtk_style_context_has_class:
1662  * @context: a #GtkStyleContext
1663  * @class_name: a class name
1664  *
1665  * Returns %TRUE if @context currently has defined the
1666  * given class name
1667  *
1668  * Returns: %TRUE if @context has @class_name defined
1669  *
1670  * Since: 3.0
1671  **/
1672 gboolean
1673 gtk_style_context_has_class (GtkStyleContext *context,
1674                              const gchar     *class_name)
1675 {
1676   GtkStyleContextPrivate *priv;
1677   GtkStyleInfo *info;
1678   GQuark class_quark;
1679
1680   g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), FALSE);
1681   g_return_val_if_fail (class_name != NULL, FALSE);
1682
1683   class_quark = g_quark_try_string (class_name);
1684
1685   if (!class_quark)
1686     return FALSE;
1687
1688   priv = context->priv;
1689
1690   g_assert (priv->info_stack != NULL);
1691   info = priv->info_stack->data;
1692
1693   if (style_class_find (info->style_classes, class_quark, NULL))
1694     return TRUE;
1695
1696   return FALSE;
1697 }
1698
1699 /**
1700  * gtk_style_context_list_classes:
1701  * @context: a #GtkStyleContext
1702  *
1703  * Returns the list of classes currently defined in @context.
1704  *
1705  * Returns: (transfer container) (element-type utf8): a #GList of
1706  *          strings with the currently defined classes. The contents
1707  *          of the list are owned by GTK+, but you must free the list
1708  *          itself with g_list_free() when you are done with it.
1709  *
1710  * Since: 3.0
1711  **/
1712 GList *
1713 gtk_style_context_list_classes (GtkStyleContext *context)
1714 {
1715   GtkStyleContextPrivate *priv;
1716   GtkStyleInfo *info;
1717   GList *classes = NULL;
1718   guint i;
1719
1720   g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), NULL);
1721
1722   priv = context->priv;
1723
1724   g_assert (priv->info_stack != NULL);
1725   info = priv->info_stack->data;
1726
1727   for (i = 0; i < info->style_classes->len; i++)
1728     {
1729       GQuark quark;
1730
1731       quark = g_array_index (info->style_classes, GQuark, i);
1732       classes = g_list_prepend (classes, (gchar *) g_quark_to_string (quark));
1733     }
1734
1735   return classes;
1736 }
1737
1738 /**
1739  * gtk_style_context_list_regions:
1740  * @context: a #GtkStyleContext
1741  *
1742  *
1743  * Returns the list of regions currently defined in @context.
1744  *
1745  * Returns: (transfer container) (element-type utf8): a #GList of
1746  *          strings with the currently defined regions. The contents
1747  *          of the list are owned by GTK+, but you must free the list
1748  *          itself with g_list_free() when you are done with it.
1749  *
1750  * Since: 3.0
1751  **/
1752 GList *
1753 gtk_style_context_list_regions (GtkStyleContext *context)
1754 {
1755   GtkStyleContextPrivate *priv;
1756   GtkStyleInfo *info;
1757   GList *classes = NULL;
1758   guint i;
1759
1760   g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), NULL);
1761
1762   priv = context->priv;
1763
1764   g_assert (priv->info_stack != NULL);
1765   info = priv->info_stack->data;
1766
1767   for (i = 0; i < info->regions->len; i++)
1768     {
1769       GtkRegion *region;
1770       const gchar *class_name;
1771
1772       region = &g_array_index (info->regions, GtkRegion, i);
1773
1774       class_name = g_quark_to_string (region->class_quark);
1775       classes = g_list_prepend (classes, (gchar *) class_name);
1776     }
1777
1778   return classes;
1779 }
1780
1781 /**
1782  * gtk_style_context_set_region:
1783  * @context: a #GtkStyleContext
1784  * @region_name: region name to use in styling
1785  * @flags: flags that apply to the region
1786  *
1787  * Sets a region to @context, so posterior calls to
1788  * gtk_style_context_get() or any of the gtk_render_*
1789  * functions will make use of this new region for styling.
1790  *
1791  * In the CSS file format, a #GtkTreeView defining a "row"
1792  * region, would be matched by:
1793  *
1794  * <programlisting>
1795  * GtkTreeView row { ... }
1796  * </programlisting>
1797  *
1798  * pseudo-classes are used for matching @flags, so the two
1799  * following rules:
1800  * <programlisting>
1801  * GtkTreeView row:nth-child (even) { ... }
1802  * GtkTreeView row:nth-child (odd) { ... }
1803  * </programlisting>
1804  *
1805  * would apply to even and odd rows, respectively.
1806  *
1807  * Since: 3.0
1808  **/
1809 void
1810 gtk_style_context_set_region (GtkStyleContext *context,
1811                               const gchar     *region_name,
1812                               GtkRegionFlags   flags)
1813 {
1814   GtkStyleContextPrivate *priv;
1815   GtkStyleInfo *info;
1816   GQuark region_quark;
1817   guint position;
1818
1819   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
1820   g_return_if_fail (region_name != NULL);
1821
1822   priv = context->priv;
1823   region_quark = g_quark_from_string (region_name);
1824
1825   g_assert (priv->info_stack != NULL);
1826   info = priv->info_stack->data;
1827
1828   if (!region_find (info->regions, region_quark, &position))
1829     {
1830       GtkRegion region;
1831
1832       region.class_quark = region_quark;
1833       region.flags = flags;
1834
1835       g_array_insert_val (info->regions, position, region);
1836
1837       /* Unset current data, as it likely changed due to the region change */
1838       priv->current_data = NULL;
1839     }
1840 }
1841
1842 /**
1843  * gtk_style_context_unset_region:
1844  * @context: a #GtkStyleContext
1845  * @region_name: region name to unset
1846  *
1847  * Removes a region from @context
1848  *
1849  * Since: 3.0
1850  **/
1851 void
1852 gtk_style_context_unset_region (GtkStyleContext *context,
1853                                 const gchar     *region_name)
1854 {
1855   GtkStyleContextPrivate *priv;
1856   GtkStyleInfo *info;
1857   GQuark region_quark;
1858   guint position;
1859
1860   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
1861   g_return_if_fail (region_name != NULL);
1862
1863   region_quark = g_quark_try_string (region_name);
1864
1865   if (!region_quark)
1866     return;
1867
1868   priv = context->priv;
1869
1870   g_assert (priv->info_stack != NULL);
1871   info = priv->info_stack->data;
1872
1873   if (region_find (info->regions, region_quark, &position))
1874     {
1875       g_array_remove_index (info->regions, position);
1876
1877       /* Unset current data, as it likely changed due to the region change */
1878       priv->current_data = NULL;
1879     }
1880 }
1881
1882 /**
1883  * gtk_style_context_has_region:
1884  * @context: a #GtkStyleContext
1885  * @region_name: a region name
1886  * @flags_return: (out) (allow-none): return location for region flags
1887  *
1888  * Returns %TRUE if @context has the region defined. If @flags_return is
1889  * not %NULL, it is set to the flags affecting the region.
1890  *
1891  * Returns: %TRUE if region is defined
1892  *
1893  * Since: 3.0
1894  **/
1895 gboolean
1896 gtk_style_context_has_region (GtkStyleContext *context,
1897                               const gchar     *region_name,
1898                               GtkRegionFlags  *flags_return)
1899 {
1900   GtkStyleContextPrivate *priv;
1901   GtkStyleInfo *info;
1902   GQuark region_quark;
1903   guint position;
1904
1905   g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), FALSE);
1906   g_return_val_if_fail (region_name != NULL, FALSE);
1907
1908   if (flags_return)
1909     *flags_return = 0;
1910
1911   region_quark = g_quark_try_string (region_name);
1912
1913   if (!region_quark)
1914     return FALSE;
1915
1916   priv = context->priv;
1917
1918   g_assert (priv->info_stack != NULL);
1919   info = priv->info_stack->data;
1920
1921   if (region_find (info->regions, region_quark, &position))
1922     {
1923       if (flags_return)
1924         {
1925           GtkRegion *region;
1926
1927           region = &g_array_index (info->regions, GtkRegion, position);
1928           *flags_return = region->flags;
1929         }
1930       return TRUE;
1931     }
1932
1933   return FALSE;
1934 }
1935
1936 static gint
1937 style_property_values_cmp (gconstpointer bsearch_node1,
1938                            gconstpointer bsearch_node2)
1939 {
1940   const PropertyValue *val1 = bsearch_node1;
1941   const PropertyValue *val2 = bsearch_node2;
1942
1943   if (val1->widget_type == val2->widget_type)
1944     return val1->pspec < val2->pspec ? -1 : val1->pspec == val2->pspec ? 0 : 1;
1945   else
1946     return val1->widget_type < val2->widget_type ? -1 : 1;
1947 }
1948
1949 const GValue *
1950 _gtk_style_context_peek_style_property (GtkStyleContext *context,
1951                                         GType            widget_type,
1952                                         GParamSpec      *pspec)
1953 {
1954   GtkStyleContextPrivate *priv;
1955   PropertyValue *pcache, key = { 0 };
1956   StyleData *data;
1957   GList *list;
1958   guint i;
1959
1960   priv = context->priv;
1961   data = style_data_lookup (context);
1962
1963   key.widget_type = widget_type;
1964   key.pspec = pspec;
1965
1966   /* need value cache array */
1967   if (!data->property_cache)
1968     data->property_cache = g_array_new (FALSE, FALSE, sizeof (PropertyValue));
1969   else
1970     {
1971       pcache = bsearch (&key,
1972                         data->property_cache->data, data->property_cache->len,
1973                         sizeof (PropertyValue), style_property_values_cmp);
1974       if (pcache)
1975         return &pcache->value;
1976     }
1977
1978   i = 0;
1979   while (i < data->property_cache->len &&
1980          style_property_values_cmp (&key, &g_array_index (data->property_cache, PropertyValue, i)) >= 0)
1981     i++;
1982
1983   g_array_insert_val (data->property_cache, i, key);
1984   pcache = &g_array_index (data->property_cache, PropertyValue, i);
1985
1986   /* cache miss, initialize value type, then set contents */
1987   g_param_spec_ref (pcache->pspec);
1988   g_value_init (&pcache->value, G_PARAM_SPEC_VALUE_TYPE (pspec));
1989
1990   if (priv->widget_path)
1991     {
1992       for (list = priv->providers_last; list; list = list->prev)
1993         {
1994           GtkStyleProviderData *data;
1995
1996           data = list->data;
1997
1998           if (gtk_style_provider_get_style_property (data->provider, priv->widget_path,
1999                                                      pspec->name, &pcache->value))
2000             return &pcache->value;
2001         }
2002     }
2003
2004   /* not supplied by any provider, revert to default */
2005   g_param_value_set_default (pspec, &pcache->value);
2006
2007   return &pcache->value;
2008 }
2009
2010 /**
2011  * gtk_style_context_get_style_property:
2012  * @context: a #GtkStyleContext
2013  * @property_name: the name of the widget style property
2014  * @value: (out) (transfer full): Return location for the property value, free with
2015  *         g_value_unset() after use.
2016  *
2017  * Gets the value for a widget style property.
2018  **/
2019 void
2020 gtk_style_context_get_style_property (GtkStyleContext *context,
2021                                       const gchar     *property_name,
2022                                       GValue          *value)
2023 {
2024   GtkStyleContextPrivate *priv;
2025   GtkWidgetClass *widget_class;
2026   GParamSpec *pspec;
2027   const GValue *peek_value;
2028   GType widget_type;
2029
2030   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2031   g_return_if_fail (property_name != NULL);
2032   g_return_if_fail (value != NULL);
2033
2034   priv = context->priv;
2035
2036   if (!priv->widget_path)
2037     return;
2038
2039   widget_type = gtk_widget_path_get_widget_type (priv->widget_path);
2040
2041   widget_class = g_type_class_ref (widget_type);
2042   pspec = gtk_widget_class_find_style_property (widget_class, property_name);
2043   g_type_class_unref (widget_class);
2044
2045   if (!pspec)
2046     {
2047       g_warning ("%s: widget class `%s' has no style property named `%s'",
2048                  G_STRLOC,
2049                  g_type_name (widget_type),
2050                  property_name);
2051       return;
2052     }
2053
2054   peek_value = _gtk_style_context_peek_style_property (context,
2055                                                        widget_type,
2056                                                        pspec);
2057
2058   if (G_VALUE_TYPE (value) == G_VALUE_TYPE (peek_value))
2059     g_value_copy (peek_value, value);
2060   else if (g_value_type_transformable (G_VALUE_TYPE (peek_value), G_VALUE_TYPE (value)))
2061     g_value_transform (peek_value, value);
2062   else
2063     g_warning ("can't retrieve style property `%s' of type `%s' as value of type `%s'",
2064                pspec->name,
2065                G_VALUE_TYPE_NAME (peek_value),
2066                G_VALUE_TYPE_NAME (value));
2067 }
2068
2069 /**
2070  * gtk_style_context_get_style_valist:
2071  * @context: a #GtkStyleContext
2072  * @args: va_list of property name/return location pairs, followed by %NULL
2073  *
2074  * Retrieves several widget style properties from @context according to the
2075  * current style.
2076  *
2077  * Since: 3.0
2078  **/
2079 void
2080 gtk_style_context_get_style_valist (GtkStyleContext *context,
2081                                     va_list          args)
2082 {
2083   GtkStyleContextPrivate *priv;
2084   const gchar *prop_name;
2085
2086   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2087
2088   prop_name = va_arg (args, const gchar *);
2089   priv = context->priv;
2090
2091   if (!priv->widget_path)
2092     return;
2093
2094   while (prop_name)
2095     {
2096       GtkWidgetClass *widget_class;
2097       GParamSpec *pspec;
2098       const GValue *peek_value;
2099       GType widget_type;
2100       gchar *error;
2101
2102       widget_type = gtk_widget_path_get_widget_type (priv->widget_path);
2103
2104       widget_class = g_type_class_ref (widget_type);
2105       pspec = gtk_widget_class_find_style_property (widget_class, prop_name);
2106       g_type_class_unref (widget_class);
2107
2108       if (!pspec)
2109         {
2110           g_warning ("%s: widget class `%s' has no style property named `%s'",
2111                      G_STRLOC,
2112                      g_type_name (widget_type),
2113                      prop_name);
2114           continue;
2115         }
2116
2117       peek_value = _gtk_style_context_peek_style_property (context,
2118                                                            widget_type,
2119                                                            pspec);
2120
2121       G_VALUE_LCOPY (peek_value, args, 0, &error);
2122
2123       if (error)
2124         {
2125           g_warning ("can't retrieve style property `%s' of type `%s': %s",
2126                      pspec->name,
2127                      G_VALUE_TYPE_NAME (peek_value),
2128                      error);
2129           g_free (error);
2130         }
2131
2132       prop_name = va_arg (args, const gchar *);
2133     }
2134 }
2135
2136 /**
2137  * gtk_style_context_get_style:
2138  * @context: a #GtkStyleContext
2139  * @...: property name /return value pairs, followed by %NULL
2140  *
2141  * Retrieves several widget style properties from @context according to the
2142  * current style.
2143  *
2144  * Since: 3.0
2145  **/
2146 void
2147 gtk_style_context_get_style (GtkStyleContext *context,
2148                              ...)
2149 {
2150   va_list args;
2151
2152   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2153
2154   va_start (args, context);
2155   gtk_style_context_get_style_valist (context, args);
2156   va_end (args);
2157 }
2158
2159
2160 /**
2161  * gtk_style_context_lookup_icon_set:
2162  * @context: a #GtkStyleContext
2163  * @stock_id: an icon name
2164  *
2165  * Looks up @stock_id in the icon factories associated to @context and
2166  * the default icon factory, returning an icon set if found, otherwise
2167  * %NULL.
2168  *
2169  * Returns: (transfer none): The looked  up %GtkIconSet, or %NULL
2170  **/
2171 GtkIconSet *
2172 gtk_style_context_lookup_icon_set (GtkStyleContext *context,
2173                                    const gchar     *stock_id)
2174 {
2175   GtkStyleContextPrivate *priv;
2176   StyleData *data;
2177   GSList *list;
2178
2179   g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), NULL);
2180   g_return_val_if_fail (stock_id != NULL, NULL);
2181
2182   priv = context->priv;
2183   g_return_val_if_fail (priv->widget_path != NULL, NULL);
2184
2185   data = style_data_lookup (context);
2186
2187   for (list = data->icon_factories; list; list = list->next)
2188     {
2189       GtkIconFactory *factory;
2190       GtkIconSet *icon_set;
2191
2192       factory = list->data;
2193       icon_set = gtk_icon_factory_lookup (factory, stock_id);
2194
2195       if (icon_set)
2196         return icon_set;
2197     }
2198
2199   return gtk_icon_factory_lookup_default (stock_id);
2200 }
2201
2202 /**
2203  * gtk_style_context_set_screen:
2204  * @context: a #GtkStyleContext
2205  * @screen: a #GdkScreen
2206  *
2207  * Sets the screen to which @context will be attached to, @screen
2208  * is used in order to reconstruct style based on the global providers
2209  * list. If you are using a #GtkStyleContext returned from
2210  * gtk_widget_get_style_context(), you do not need to call this yourself.
2211  *
2212  * Since: 3.0
2213  **/
2214 void
2215 gtk_style_context_set_screen (GtkStyleContext *context,
2216                               GdkScreen       *screen)
2217 {
2218   GtkStyleContextPrivate *priv;
2219
2220   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2221
2222   priv = context->priv;
2223   priv->screen = screen;
2224
2225   g_object_notify (G_OBJECT (context), "screen");
2226
2227   gtk_style_context_invalidate (context);
2228 }
2229
2230 /**
2231  * gtk_style_context_get_screen:
2232  * @context: a #GtkStyleContext
2233  *
2234  * Returns the #GdkScreen to which @context is attached to.
2235  *
2236  * Returns: a #GdkScreen, or %NULL.
2237  **/
2238 GdkScreen *
2239 gtk_style_context_get_screen (GtkStyleContext *context)
2240 {
2241   GtkStyleContextPrivate *priv;
2242
2243   g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), NULL);
2244
2245   priv = context->priv;
2246   return priv->screen;
2247 }
2248
2249 /**
2250  * gtk_style_context_set_direction:
2251  * @context: a #GtkStyleContext
2252  * @direction: the new direction.
2253  *
2254  * Sets the reading direction for rendering purposes. If you are
2255  * using a #GtkStyleContext returned from gtk_widget_get_style_context(),
2256  * you do not need to call this yourself.
2257  *
2258  * Since: 3.0
2259  **/
2260 void
2261 gtk_style_context_set_direction (GtkStyleContext  *context,
2262                                  GtkTextDirection  direction)
2263 {
2264   GtkStyleContextPrivate *priv;
2265
2266   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2267
2268   priv = context->priv;
2269   priv->direction = direction;
2270
2271   g_object_notify (G_OBJECT (context), "direction");
2272 }
2273
2274 /**
2275  * gtk_style_context_get_direction:
2276  * @context: a #GtkStyleContext
2277  *
2278  * Returns the widget direction used for rendering.
2279  *
2280  * Returns: the widget direction
2281  *
2282  * Since: 3.0
2283  **/
2284 GtkTextDirection
2285 gtk_style_context_get_direction (GtkStyleContext *context)
2286 {
2287   GtkStyleContextPrivate *priv;
2288
2289   g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), GTK_TEXT_DIR_LTR);
2290
2291   priv = context->priv;
2292   return priv->direction;
2293 }
2294
2295 /**
2296  * gtk_style_context_set_junction_sides:
2297  * @context: a #GtkStyleContext
2298  * @sides: sides where rendered elements are visually connected to other elements.
2299  *
2300  * Sets the sides where rendered elements (mostly through gtk_render_frame()) will
2301  * visually connect with other visual elements. This is merely a guideline that may
2302  * be honored or not in theming engines.
2303  *
2304  * Since: 3.0
2305  **/
2306 void
2307 gtk_style_context_set_junction_sides (GtkStyleContext  *context,
2308                                       GtkJunctionSides  sides)
2309 {
2310   GtkStyleContextPrivate *priv;
2311   GtkStyleInfo *info;
2312
2313   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2314
2315   priv = context->priv;
2316   info = priv->info_stack->data;
2317   info->junction_sides = sides;
2318 }
2319
2320 /**
2321  * gtk_style_context_get_junction_sides:
2322  * @context: a #GtkStyleContext
2323  *
2324  * Returns the sides where rendered elements connect visually with others.
2325  *
2326  * Returns: the junction sides
2327  *
2328  * Since: 3.0
2329  **/
2330 GtkJunctionSides
2331 gtk_style_context_get_junction_sides (GtkStyleContext *context)
2332 {
2333   GtkStyleContextPrivate *priv;
2334   GtkStyleInfo *info;
2335
2336   g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), 0);
2337
2338   priv = context->priv;
2339   info = priv->info_stack->data;
2340   return info->junction_sides;
2341 }
2342
2343 /**
2344  * gtk_style_context_lookup_color:
2345  * @context: a #GtkStyleContext
2346  * @color_name: color name to lookup
2347  * @color: (out): Return location for the looked up color
2348  *
2349  * Looks up and resolves a color name in the @context color map.
2350  *
2351  * Returns: %TRUE if @color_name was found and resolved, %FALSE otherwise
2352  **/
2353 gboolean
2354 gtk_style_context_lookup_color (GtkStyleContext *context,
2355                                 const gchar     *color_name,
2356                                 GdkColor        *color)
2357 {
2358   GtkStyleContextPrivate *priv;
2359   GtkSymbolicColor *sym_color;
2360   StyleData *data;
2361
2362   g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), FALSE);
2363   g_return_val_if_fail (color_name != NULL, FALSE);
2364   g_return_val_if_fail (color != NULL, FALSE);
2365
2366   priv = context->priv;
2367   g_return_val_if_fail (priv->widget_path != NULL, FALSE);
2368
2369   data = style_data_lookup (context);
2370   sym_color = gtk_style_set_lookup_color (data->store, color_name);
2371
2372   if (!sym_color)
2373     return FALSE;
2374
2375   return gtk_symbolic_color_resolve (sym_color, data->store, color);
2376 }
2377
2378 /**
2379  * gtk_style_context_notify_state_change:
2380  * @context: a #GtkStyleContext
2381  * @window: a #GdkWindow
2382  * @region_id: (allow-none): animatable region to notify on, or %NULL.
2383  *             See gtk_style_context_push_animatable_region()
2384  * @state: state to trigger transition for
2385  * @state_value: target value of @state
2386  *
2387  * Notifies a state change on @context, so if the current style makes use
2388  * of transition animations, one will be started so all rendered elements
2389  * under @region_id are animated for state @state being set to value @state_value.
2390  *
2391  * The @window parameter is used in order to invalidate the rendered area
2392  * as the animation runs, so make sure it is the same window that is being
2393  * rendered on by the gtk_render_*() methods.
2394  *
2395  * If @region_id is %NULL, all rendered elements using @context will be
2396  * affected by this state transition.
2397  *
2398  * As a practical example, a #GtkButton notifying a state transition on
2399  * the prelight state:
2400  * <programlisting>
2401  * gtk_style_context_notify_state_change (context,
2402  *                                        gtk_widget_get_window (widget),
2403  *                                        NULL, GTK_STATE_PRELIGHT,
2404  *                                        button->in_button);
2405  * </programlisting>
2406  *
2407  * Could be handled in the CSS file like this:
2408  * <programlisting>
2409  * GtkButton {
2410  *     background-color: #f00;
2411  * }
2412  *
2413  * GtkButton:hover {
2414  *     background-color: #fff;
2415  *     transition: 200ms linear;
2416  * }
2417  * </programlisting>
2418  *
2419  * This combination would animate the button background from red to white
2420  * if a pointer enters the button, and back to red if the pointer leaves
2421  * the button.
2422  *
2423  * Since: 3.0
2424  **/
2425 void
2426 gtk_style_context_notify_state_change (GtkStyleContext *context,
2427                                        GdkWindow       *window,
2428                                        gpointer         region_id,
2429                                        GtkStateType     state,
2430                                        gboolean         state_value)
2431 {
2432   GtkStyleContextPrivate *priv;
2433   GtkAnimationDescription *desc;
2434   AnimationInfo *info;
2435   GtkStateFlags flags;
2436   StyleData *data;
2437
2438   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2439   g_return_if_fail (GDK_IS_WINDOW (window));
2440   g_return_if_fail (state < GTK_STATE_LAST);
2441
2442   priv = context->priv;
2443   g_return_if_fail (priv->widget_path != NULL);
2444
2445   state_value = (state_value == TRUE);
2446
2447   switch (state)
2448     {
2449     case GTK_STATE_ACTIVE:
2450       flags = GTK_STATE_FLAG_ACTIVE;
2451       break;
2452     case GTK_STATE_PRELIGHT:
2453       flags = GTK_STATE_FLAG_PRELIGHT;
2454       break;
2455     case GTK_STATE_SELECTED:
2456       flags = GTK_STATE_FLAG_SELECTED;
2457       break;
2458     case GTK_STATE_INSENSITIVE:
2459       flags = GTK_STATE_FLAG_INSENSITIVE;
2460       break;
2461     case GTK_STATE_INCONSISTENT:
2462       flags = GTK_STATE_FLAG_INCONSISTENT;
2463       break;
2464     case GTK_STATE_FOCUSED:
2465       flags = GTK_STATE_FLAG_FOCUSED;
2466       break;
2467     case GTK_STATE_NORMAL:
2468     default:
2469       flags = 0;
2470       break;
2471     }
2472
2473   /* Find out if there is any animation description for the given
2474    * state, it will fallback to the normal state as well if necessary.
2475    */
2476   data = style_data_lookup (context);
2477   gtk_style_set_get (data->store, flags,
2478                      "transition", &desc,
2479                      NULL);
2480
2481   if (!desc)
2482     return;
2483
2484   if (gtk_animation_description_get_duration (desc) == 0)
2485     {
2486       gtk_animation_description_unref (desc);
2487       return;
2488     }
2489
2490   info = animation_info_lookup (context, region_id, state);
2491
2492   if (info)
2493     {
2494       /* Reverse the animation if target values are the opposite */
2495       if (info->target_value != state_value)
2496         {
2497           if (gtk_timeline_get_direction (info->timeline) == GTK_TIMELINE_DIRECTION_FORWARD)
2498             gtk_timeline_set_direction (info->timeline, GTK_TIMELINE_DIRECTION_BACKWARD);
2499           else
2500             gtk_timeline_set_direction (info->timeline, GTK_TIMELINE_DIRECTION_FORWARD);
2501
2502           info->target_value = state_value;
2503         }
2504     }
2505   else
2506     {
2507       info = animation_info_new (context, region_id,
2508                                  gtk_animation_description_get_duration (desc),
2509                                  gtk_animation_description_get_progress_type (desc),
2510                                  state, state_value, window);
2511
2512       priv->animations = g_slist_prepend (priv->animations, info);
2513       priv->animations_invalidated = TRUE;
2514     }
2515
2516   gtk_animation_description_unref (desc);
2517 }
2518
2519 /**
2520  * gtk_style_context_push_animatable_region:
2521  * @context: a #GtkStyleContext
2522  * @region_id: unique identifier for the animatable region
2523  *
2524  * Pushes an animatable region, so all further gtk_render_*() calls between
2525  * this call and the following gtk_style_context_pop_animatable_region() will
2526  * potentially show transition animations for if gtk_style_context_notify_state_change()
2527  * is called for a given state, and the theme/style used contemplates the use of
2528  * transition animations for state changes.
2529  *
2530  * The @region_id used must be unique in @context so the theming engine may
2531  * univocally identify rendered elements subject to a state transition.
2532  *
2533  * Since: 3.0
2534  **/
2535 void
2536 gtk_style_context_push_animatable_region (GtkStyleContext *context,
2537                                           gpointer         region_id)
2538 {
2539   GtkStyleContextPrivate *priv;
2540
2541   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2542   g_return_if_fail (region_id != NULL);
2543
2544   priv = context->priv;
2545   priv->animation_regions = g_slist_prepend (priv->animation_regions, region_id);
2546 }
2547
2548 /**
2549  * gtk_style_context_pop_animatable_region:
2550  * @context: a #GtkStyleContext
2551  *
2552  * Pops an animatable region from @context. See gtk_style_context_push_animatable_region().
2553  *
2554  * Since: 3.0
2555  **/
2556 void
2557 gtk_style_context_pop_animatable_region (GtkStyleContext *context)
2558 {
2559   GtkStyleContextPrivate *priv;
2560
2561   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2562
2563   priv = context->priv;
2564   priv->animation_regions = g_slist_delete_link (priv->animation_regions,
2565                                                  priv->animation_regions);
2566 }
2567
2568 void
2569 _gtk_style_context_invalidate_animation_areas (GtkStyleContext *context)
2570 {
2571   GtkStyleContextPrivate *priv;
2572   GSList *l;
2573
2574   priv = context->priv;
2575
2576   for (l = priv->animations; l; l = l->next)
2577     {
2578       AnimationInfo *info;
2579
2580       info = l->data;
2581
2582       /* A NULL invalidation region means it has to be recreated on
2583        * the next expose event, this happens usually after a widget
2584        * allocation change, so the next expose after it will update
2585        * the invalidation region.
2586        */
2587       if (info->invalidation_region)
2588         {
2589           cairo_region_destroy (info->invalidation_region);
2590           info->invalidation_region = NULL;
2591         }
2592     }
2593
2594   priv->animations_invalidated = TRUE;
2595 }
2596
2597 void
2598 _gtk_style_context_coalesce_animation_areas (GtkStyleContext *context,
2599                                              gint             rel_x,
2600                                              gint             rel_y)
2601 {
2602   GtkStyleContextPrivate *priv;
2603   GSList *l;
2604
2605   priv = context->priv;
2606
2607   if (!priv->animations_invalidated)
2608     return;
2609
2610   for (l = priv->animations; l; l = l->next)
2611     {
2612       AnimationInfo *info;
2613       guint i;
2614
2615       info = l->data;
2616
2617       if (info->invalidation_region)
2618         continue;
2619
2620       /* FIXME: If this happens there's not much
2621        * point in keeping the animation running.
2622        */
2623       if (info->rectangles->len == 0)
2624         continue;
2625
2626       info->invalidation_region = cairo_region_create ();
2627
2628       for (i = 0; i <info->rectangles->len; i++)
2629         {
2630           cairo_rectangle_int_t *rect;
2631
2632           rect = &g_array_index (info->rectangles, cairo_rectangle_int_t, i);
2633           rect->x += rel_x;
2634           rect->y += rel_y;
2635
2636           cairo_region_union_rectangle (info->invalidation_region, rect);
2637         }
2638
2639       g_array_remove_range (info->rectangles, 0, info->rectangles->len);
2640     }
2641
2642   priv->animations_invalidated = FALSE;
2643 }
2644
2645 static void
2646 store_animation_region (GtkStyleContext *context,
2647                         gdouble          x,
2648                         gdouble          y,
2649                         gdouble          width,
2650                         gdouble          height)
2651 {
2652   GtkStyleContextPrivate *priv;
2653   GSList *l;
2654
2655   priv = context->priv;
2656
2657   if (!priv->animations_invalidated)
2658     return;
2659
2660   for (l = priv->animations; l; l = l->next)
2661     {
2662       AnimationInfo *info;
2663
2664       info = l->data;
2665
2666       /* The animation doesn't need updatring
2667        * the invalidation area, bail out.
2668        */
2669       if (info->invalidation_region)
2670         continue;
2671
2672       if (context_has_animatable_region (context, info->region_id))
2673         {
2674           cairo_rectangle_int_t rect;
2675
2676           rect.x = (gint) x;
2677           rect.y = (gint) y;
2678           rect.width = (gint) width;
2679           rect.height = (gint) height;
2680
2681           g_array_append_val (info->rectangles, rect);
2682         }
2683     }
2684 }
2685
2686 /**
2687  * gtk_style_context_invalidate:
2688  * @context: a #GtkStyleContext.
2689  *
2690  * Invalidates @context style information, so it will be reconstructed
2691  * again. If you're using a #GtkStyleContext returned from
2692  * gtk_widget_get_style_context(), you do not need to call this yourself.
2693  *
2694  * Since: 3.0
2695  **/
2696 void
2697 gtk_style_context_invalidate (GtkStyleContext *context)
2698 {
2699   GtkStyleContextPrivate *priv;
2700
2701   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2702
2703   priv = context->priv;
2704
2705   /* Avoid reentrancy */
2706   if (priv->invalidating_context)
2707     return;
2708
2709   priv->invalidating_context = TRUE;
2710
2711   g_hash_table_remove_all (priv->style_data);
2712   priv->current_data = NULL;
2713
2714   g_signal_emit (context, signals[CHANGED], 0);
2715
2716   priv->invalidating_context = FALSE;
2717 }
2718
2719 /* Paint methods */
2720 void
2721 gtk_render_check (GtkStyleContext *context,
2722                   cairo_t         *cr,
2723                   gdouble          x,
2724                   gdouble          y,
2725                   gdouble          width,
2726                   gdouble          height)
2727 {
2728   GtkStyleContextPrivate *priv;
2729   GtkThemingEngineClass *engine_class;
2730
2731   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2732   g_return_if_fail (cr != NULL);
2733
2734   priv = context->priv;
2735   engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
2736
2737   store_animation_region (context, x, y, width, height);
2738
2739   _gtk_theming_engine_set_context (priv->theming_engine, context);
2740   engine_class->render_check (priv->theming_engine, cr,
2741                               x, y, width, height);
2742 }
2743
2744 void
2745 gtk_render_option (GtkStyleContext *context,
2746                    cairo_t         *cr,
2747                    gdouble          x,
2748                    gdouble          y,
2749                    gdouble          width,
2750                    gdouble          height)
2751 {
2752   GtkStyleContextPrivate *priv;
2753   GtkThemingEngineClass *engine_class;
2754
2755   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2756   g_return_if_fail (cr != NULL);
2757
2758   priv = context->priv;
2759   engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
2760
2761   store_animation_region (context, x, y, width, height);
2762
2763   _gtk_theming_engine_set_context (priv->theming_engine, context);
2764   engine_class->render_option (priv->theming_engine, cr,
2765                                x, y, width, height);
2766 }
2767
2768 void
2769 gtk_render_arrow (GtkStyleContext *context,
2770                   cairo_t         *cr,
2771                   gdouble          angle,
2772                   gdouble          x,
2773                   gdouble          y,
2774                   gdouble          size)
2775 {
2776   GtkStyleContextPrivate *priv;
2777   GtkThemingEngineClass *engine_class;
2778
2779   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2780   g_return_if_fail (cr != NULL);
2781
2782   priv = context->priv;
2783   engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
2784
2785   store_animation_region (context, x, y, size, size);
2786
2787   _gtk_theming_engine_set_context (priv->theming_engine, context);
2788   engine_class->render_arrow (priv->theming_engine, cr,
2789                               angle, x, y, size);
2790 }
2791
2792 void
2793 gtk_render_background (GtkStyleContext *context,
2794                        cairo_t         *cr,
2795                        gdouble          x,
2796                        gdouble          y,
2797                        gdouble          width,
2798                        gdouble          height)
2799 {
2800   GtkStyleContextPrivate *priv;
2801   GtkThemingEngineClass *engine_class;
2802
2803   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2804   g_return_if_fail (cr != NULL);
2805
2806   priv = context->priv;
2807   engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
2808
2809   store_animation_region (context, x, y, width, height);
2810
2811   _gtk_theming_engine_set_context (priv->theming_engine, context);
2812   engine_class->render_background (priv->theming_engine, cr, x, y, width, height);
2813 }
2814
2815 void
2816 gtk_render_frame (GtkStyleContext *context,
2817                   cairo_t         *cr,
2818                   gdouble          x,
2819                   gdouble          y,
2820                   gdouble          width,
2821                   gdouble          height)
2822 {
2823   GtkStyleContextPrivate *priv;
2824   GtkThemingEngineClass *engine_class;
2825
2826   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2827   g_return_if_fail (cr != NULL);
2828
2829   priv = context->priv;
2830   engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
2831
2832   store_animation_region (context, x, y, width, height);
2833
2834   _gtk_theming_engine_set_context (priv->theming_engine, context);
2835   engine_class->render_frame (priv->theming_engine, cr, x, y, width, height);
2836 }
2837
2838 void
2839 gtk_render_expander (GtkStyleContext *context,
2840                      cairo_t         *cr,
2841                      gdouble          x,
2842                      gdouble          y,
2843                      gdouble          width,
2844                      gdouble          height)
2845 {
2846   GtkStyleContextPrivate *priv;
2847   GtkThemingEngineClass *engine_class;
2848
2849   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2850   g_return_if_fail (cr != NULL);
2851
2852   priv = context->priv;
2853   engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
2854
2855   store_animation_region (context, x, y, width, height);
2856
2857   _gtk_theming_engine_set_context (priv->theming_engine, context);
2858   engine_class->render_expander (priv->theming_engine, cr, x, y, width, height);
2859 }
2860
2861 void
2862 gtk_render_focus (GtkStyleContext *context,
2863                   cairo_t         *cr,
2864                   gdouble          x,
2865                   gdouble          y,
2866                   gdouble          width,
2867                   gdouble          height)
2868 {
2869   GtkStyleContextPrivate *priv;
2870   GtkThemingEngineClass *engine_class;
2871
2872   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2873   g_return_if_fail (cr != NULL);
2874
2875   priv = context->priv;
2876   engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
2877
2878   store_animation_region (context, x, y, width, height);
2879
2880   _gtk_theming_engine_set_context (priv->theming_engine, context);
2881   engine_class->render_focus (priv->theming_engine, cr, x, y, width, height);
2882 }
2883
2884 void
2885 gtk_render_layout (GtkStyleContext *context,
2886                    cairo_t         *cr,
2887                    gdouble          x,
2888                    gdouble          y,
2889                    PangoLayout     *layout)
2890 {
2891   GtkStyleContextPrivate *priv;
2892   GtkThemingEngineClass *engine_class;
2893
2894   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2895   g_return_if_fail (cr != NULL);
2896
2897   priv = context->priv;
2898   engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
2899
2900   _gtk_theming_engine_set_context (priv->theming_engine, context);
2901   engine_class->render_layout (priv->theming_engine, cr, x, y, layout);
2902 }
2903
2904 void
2905 gtk_render_line (GtkStyleContext *context,
2906                  cairo_t         *cr,
2907                  gdouble          x0,
2908                  gdouble          y0,
2909                  gdouble          x1,
2910                  gdouble          y1)
2911 {
2912   GtkStyleContextPrivate *priv;
2913   GtkThemingEngineClass *engine_class;
2914
2915   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2916   g_return_if_fail (cr != NULL);
2917
2918   priv = context->priv;
2919   engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
2920
2921   _gtk_theming_engine_set_context (priv->theming_engine, context);
2922   engine_class->render_line (priv->theming_engine, cr, x0, y0, x1, y1);
2923 }
2924
2925 void
2926 gtk_render_slider (GtkStyleContext *context,
2927                    cairo_t         *cr,
2928                    gdouble          x,
2929                    gdouble          y,
2930                    gdouble          width,
2931                    gdouble          height,
2932                    GtkOrientation   orientation)
2933 {
2934   GtkStyleContextPrivate *priv;
2935   GtkThemingEngineClass *engine_class;
2936
2937   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2938   g_return_if_fail (cr != NULL);
2939
2940   priv = context->priv;
2941   engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
2942
2943   store_animation_region (context, x, y, width, height);
2944
2945   _gtk_theming_engine_set_context (priv->theming_engine, context);
2946   engine_class->render_slider (priv->theming_engine, cr, x, y, width, height, orientation);
2947 }
2948
2949 void
2950 gtk_render_frame_gap (GtkStyleContext *context,
2951                       cairo_t         *cr,
2952                       gdouble          x,
2953                       gdouble          y,
2954                       gdouble          width,
2955                       gdouble          height,
2956                       GtkPositionType  gap_side,
2957                       gdouble          xy0_gap,
2958                       gdouble          xy1_gap)
2959 {
2960   GtkStyleContextPrivate *priv;
2961   GtkThemingEngineClass *engine_class;
2962
2963   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2964   g_return_if_fail (cr != NULL);
2965
2966   priv = context->priv;
2967   engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
2968
2969   store_animation_region (context, x, y, width, height);
2970
2971   _gtk_theming_engine_set_context (priv->theming_engine, context);
2972   engine_class->render_frame_gap (priv->theming_engine, cr,
2973                                   x, y, width, height, gap_side,
2974                                   xy0_gap, xy1_gap);
2975 }
2976
2977 void
2978 gtk_render_extension (GtkStyleContext *context,
2979                       cairo_t         *cr,
2980                       gdouble          x,
2981                       gdouble          y,
2982                       gdouble          width,
2983                       gdouble          height,
2984                       GtkPositionType  gap_side)
2985 {
2986   GtkStyleContextPrivate *priv;
2987   GtkThemingEngineClass *engine_class;
2988
2989   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2990   g_return_if_fail (cr != NULL);
2991
2992   priv = context->priv;
2993   engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
2994
2995   store_animation_region (context, x, y, width, height);
2996
2997   _gtk_theming_engine_set_context (priv->theming_engine, context);
2998   engine_class->render_extension (priv->theming_engine, cr, x, y, width, height, gap_side);
2999 }
3000
3001 void
3002 gtk_render_handle (GtkStyleContext *context,
3003                    cairo_t         *cr,
3004                    gdouble          x,
3005                    gdouble          y,
3006                    gdouble          width,
3007                    gdouble          height)
3008 {
3009   GtkStyleContextPrivate *priv;
3010   GtkThemingEngineClass *engine_class;
3011
3012   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3013   g_return_if_fail (cr != NULL);
3014
3015   priv = context->priv;
3016   engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
3017
3018   store_animation_region (context, x, y, width, height);
3019
3020   _gtk_theming_engine_set_context (priv->theming_engine, context);
3021   engine_class->render_handle (priv->theming_engine, cr, x, y, width, height);
3022 }