]> Pileus Git - ~andy/gtk/blob - gtk/gtkstylecontext.c
58faf5d7779218162e483016f99d6c644e2fc530
[~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   GtkStateFlags state_flags;
226 };
227
228 struct StyleData
229 {
230   GtkStyleProperties *store;
231   GSList *icon_factories;
232   GArray *property_cache;
233 };
234
235 struct AnimationInfo
236 {
237   GtkTimeline *timeline;
238
239   gpointer region_id;
240   GdkWindow *window;
241   GtkStateType state;
242   gboolean target_value;
243
244   cairo_region_t *invalidation_region;
245   GArray *rectangles;
246 };
247
248 struct GtkStyleContextPrivate
249 {
250   GdkScreen *screen;
251
252   GList *providers;
253   GList *providers_last;
254
255   GtkWidgetPath *widget_path;
256   GHashTable *style_data;
257   GSList *info_stack;
258   StyleData *current_data;
259
260   GSList *animation_regions;
261   GSList *animations;
262
263   guint animations_invalidated : 1;
264   guint invalidating_context : 1;
265
266   GtkThemingEngine *theming_engine;
267
268   GtkTextDirection direction;
269 };
270
271 enum {
272   PROP_0,
273   PROP_SCREEN,
274   PROP_DIRECTION
275 };
276
277 enum {
278   CHANGED,
279   LAST_SIGNAL
280 };
281
282 guint signals[LAST_SIGNAL] = { 0 };
283
284 static GQuark provider_list_quark = 0;
285
286 static void gtk_style_context_finalize (GObject *object);
287
288 static void gtk_style_context_impl_set_property (GObject      *object,
289                                                  guint         prop_id,
290                                                  const GValue *value,
291                                                  GParamSpec   *pspec);
292 static void gtk_style_context_impl_get_property (GObject      *object,
293                                                  guint         prop_id,
294                                                  GValue       *value,
295                                                  GParamSpec   *pspec);
296
297
298 G_DEFINE_TYPE (GtkStyleContext, gtk_style_context, G_TYPE_OBJECT)
299
300 static void
301 gtk_style_context_class_init (GtkStyleContextClass *klass)
302 {
303   GObjectClass *object_class = G_OBJECT_CLASS (klass);
304
305   object_class->finalize = gtk_style_context_finalize;
306   object_class->set_property = gtk_style_context_impl_set_property;
307   object_class->get_property = gtk_style_context_impl_get_property;
308
309   signals[CHANGED] =
310     g_signal_new (I_("changed"),
311                   G_TYPE_FROM_CLASS (object_class),
312                   G_SIGNAL_RUN_FIRST,
313                   G_STRUCT_OFFSET (GtkStyleContextClass, changed),
314                   NULL, NULL,
315                   g_cclosure_marshal_VOID__VOID,
316                   G_TYPE_NONE, 0);
317
318   g_object_class_install_property (object_class,
319                                    PROP_SCREEN,
320                                    g_param_spec_object ("screen",
321                                                         P_("Screen"),
322                                                         P_("The associated GdkScreen"),
323                                                         GDK_TYPE_SCREEN,
324                                                         GTK_PARAM_READWRITE));
325   g_object_class_install_property (object_class,
326                                    PROP_DIRECTION,
327                                    g_param_spec_enum ("direction",
328                                                       P_("Direction"),
329                                                       P_("Text direction"),
330                                                       GTK_TYPE_TEXT_DIRECTION,
331                                                       GTK_TEXT_DIR_LTR,
332                                                       GTK_PARAM_READWRITE));
333
334   g_type_class_add_private (object_class, sizeof (GtkStyleContextPrivate));
335 }
336
337 static GtkStyleInfo *
338 style_info_new (void)
339 {
340   GtkStyleInfo *info;
341
342   info = g_slice_new0 (GtkStyleInfo);
343   info->style_classes = g_array_new (FALSE, FALSE, sizeof (GQuark));
344   info->regions = g_array_new (FALSE, FALSE, sizeof (GtkRegion));
345
346   return info;
347 }
348
349 static void
350 style_info_free (GtkStyleInfo *info)
351 {
352   g_array_free (info->style_classes, TRUE);
353   g_array_free (info->regions, TRUE);
354   g_slice_free (GtkStyleInfo, info);
355 }
356
357 static GtkStyleInfo *
358 style_info_copy (const GtkStyleInfo *info)
359 {
360   GtkStyleInfo *copy;
361
362   copy = style_info_new ();
363   g_array_insert_vals (copy->style_classes, 0,
364                        info->style_classes->data,
365                        info->style_classes->len);
366
367   g_array_insert_vals (copy->regions, 0,
368                        info->regions->data,
369                        info->regions->len);
370
371   copy->junction_sides = info->junction_sides;
372
373   return copy;
374 }
375
376 static guint
377 style_info_hash (gconstpointer elem)
378 {
379   const GtkStyleInfo *info;
380   guint i, hash = 0;
381
382   info = elem;
383
384   for (i = 0; i < info->style_classes->len; i++)
385     {
386       hash += g_array_index (info->style_classes, GQuark, i);
387       hash <<= 5;
388     }
389
390   for (i = 0; i < info->regions->len; i++)
391     {
392       GtkRegion *region;
393
394       region = &g_array_index (info->regions, GtkRegion, i);
395       hash += region->class_quark;
396       hash += region->flags;
397       hash <<= 5;
398     }
399
400   return hash;
401 }
402
403 static gboolean
404 style_info_equal (gconstpointer elem1,
405                   gconstpointer elem2)
406 {
407   const GtkStyleInfo *info1, *info2;
408
409   info1 = elem1;
410   info2 = elem2;
411
412   if (info1->junction_sides != info2->junction_sides)
413     return FALSE;
414
415   if (info1->style_classes->len != info2->style_classes->len)
416     return FALSE;
417
418   if (memcmp (info1->style_classes->data,
419               info2->style_classes->data,
420               info1->style_classes->len * sizeof (GQuark)) != 0)
421     return FALSE;
422
423   if (info1->regions->len != info2->regions->len)
424     return FALSE;
425
426   if (memcmp (info1->regions->data,
427               info2->regions->data,
428               info1->regions->len * sizeof (GtkRegion)) != 0)
429     return FALSE;
430
431   return TRUE;
432 }
433
434 static StyleData *
435 style_data_new (void)
436 {
437   StyleData *data;
438
439   data = g_slice_new0 (StyleData);
440   data->store = gtk_style_properties_new ();
441
442   return data;
443 }
444
445 static void
446 clear_property_cache (StyleData *data)
447 {
448   guint i;
449
450   if (!data->property_cache)
451     return;
452
453   for (i = 0; i < data->property_cache->len; i++)
454     {
455       PropertyValue *node = &g_array_index (data->property_cache, PropertyValue, i);
456
457       g_param_spec_unref (node->pspec);
458       g_value_unset (&node->value);
459     }
460
461   g_array_free (data->property_cache, TRUE);
462   data->property_cache = NULL;
463 }
464
465 static void
466 style_data_free (StyleData *data)
467 {
468   g_object_unref (data->store);
469   clear_property_cache (data);
470
471   g_slist_foreach (data->icon_factories, (GFunc) g_object_unref, NULL);
472   g_slist_free (data->icon_factories);
473
474   g_slice_free (StyleData, data);
475 }
476
477 static void
478 gtk_style_context_init (GtkStyleContext *style_context)
479 {
480   GtkStyleContextPrivate *priv;
481   GtkStyleInfo *info;
482
483   priv = style_context->priv = G_TYPE_INSTANCE_GET_PRIVATE (style_context,
484                                                             GTK_TYPE_STYLE_CONTEXT,
485                                                             GtkStyleContextPrivate);
486
487   priv->style_data = g_hash_table_new_full (style_info_hash,
488                                             style_info_equal,
489                                             (GDestroyNotify) style_info_free,
490                                             (GDestroyNotify) style_data_free);
491   priv->theming_engine = g_object_ref ((gpointer) gtk_theming_engine_load (NULL));
492
493   priv->direction = GTK_TEXT_DIR_RTL;
494
495   /* Create default info store */
496   info = style_info_new ();
497   priv->info_stack = g_slist_prepend (priv->info_stack, info);
498 }
499
500 static GtkStyleProviderData *
501 style_provider_data_new (GtkStyleProvider *provider,
502                          guint             priority)
503 {
504   GtkStyleProviderData *data;
505
506   data = g_slice_new (GtkStyleProviderData);
507   data->provider = g_object_ref (provider);
508   data->priority = priority;
509
510   return data;
511 }
512
513 static void
514 style_provider_data_free (GtkStyleProviderData *data)
515 {
516   g_object_unref (data->provider);
517   g_slice_free (GtkStyleProviderData, data);
518 }
519
520 static void
521 animation_info_free (AnimationInfo *info)
522 {
523   g_object_unref (info->timeline);
524   g_object_unref (info->window);
525
526   if (info->invalidation_region)
527     cairo_region_destroy (info->invalidation_region);
528
529   g_array_free (info->rectangles, TRUE);
530   g_slice_free (AnimationInfo, info);
531 }
532
533 static void
534 timeline_frame_cb (GtkTimeline *timeline,
535                    gdouble      progress,
536                    gpointer     user_data)
537 {
538   AnimationInfo *info;
539
540   info = user_data;
541
542   if (info->invalidation_region &&
543       !cairo_region_is_empty (info->invalidation_region))
544     gdk_window_invalidate_region (info->window, info->invalidation_region, TRUE);
545   else
546     gdk_window_invalidate_rect (info->window, NULL, TRUE);
547 }
548
549 static void
550 timeline_finished_cb (GtkTimeline *timeline,
551                       gpointer     user_data)
552 {
553   GtkStyleContextPrivate *priv;
554   GtkStyleContext *context;
555   AnimationInfo *info;
556   GSList *l;
557
558   context = user_data;
559   priv = context->priv;
560
561   for (l = priv->animations; l; l = l->next)
562     {
563       info = l->data;
564
565       if (info->timeline == timeline)
566         {
567           priv->animations = g_slist_delete_link (priv->animations, l);
568
569           /* Invalidate one last time the area, so the final content is painted */
570           if (info->invalidation_region &&
571               !cairo_region_is_empty (info->invalidation_region))
572             gdk_window_invalidate_region (info->window, info->invalidation_region, TRUE);
573           else
574             gdk_window_invalidate_rect (info->window, NULL, TRUE);
575
576           animation_info_free (info);
577           break;
578         }
579     }
580 }
581
582 static AnimationInfo *
583 animation_info_new (GtkStyleContext         *context,
584                     gpointer                 region_id,
585                     gdouble                  duration,
586                     GtkTimelineProgressType  progress_type,
587                     gboolean                 loop,
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   gtk_timeline_set_loop (info->timeline, loop);
605
606   if (!loop && !target_value)
607     {
608       gtk_timeline_set_direction (info->timeline, GTK_TIMELINE_DIRECTION_BACKWARD);
609       gtk_timeline_rewind (info->timeline);
610     }
611
612   g_signal_connect (info->timeline, "frame",
613                     G_CALLBACK (timeline_frame_cb), info);
614   g_signal_connect (info->timeline, "finished",
615                     G_CALLBACK (timeline_finished_cb), context);
616
617   gtk_timeline_start (info->timeline);
618
619   return info;
620 }
621
622 static AnimationInfo *
623 animation_info_lookup (GtkStyleContext *context,
624                        gpointer         region_id,
625                        GtkStateType     state)
626 {
627   GtkStyleContextPrivate *priv;
628   GSList *l;
629
630   priv = context->priv;
631
632   for (l = priv->animations; l; l = l->next)
633     {
634       AnimationInfo *info;
635
636       info = l->data;
637
638       if (info->state == state &&
639           info->region_id == region_id)
640         return info;
641     }
642
643   return NULL;
644 }
645
646 static void
647 gtk_style_context_finalize (GObject *object)
648 {
649   GtkStyleContextPrivate *priv;
650   GtkStyleContext *style_context;
651   GSList *l;
652
653   style_context = GTK_STYLE_CONTEXT (object);
654   priv = style_context->priv;
655
656   if (priv->widget_path)
657     gtk_widget_path_free (priv->widget_path);
658
659   g_hash_table_destroy (priv->style_data);
660
661   g_list_foreach (priv->providers, (GFunc) style_provider_data_free, NULL);
662   g_list_free (priv->providers);
663
664   g_slist_foreach (priv->info_stack, (GFunc) style_info_free, NULL);
665   g_slist_free (priv->info_stack);
666
667   g_slist_free (priv->animation_regions);
668
669   for (l = priv->animations; l; l = l->next)
670     animation_info_free ((AnimationInfo *) l->data);
671
672   g_slist_free (priv->animations);
673
674   if (priv->theming_engine)
675     g_object_unref (priv->theming_engine);
676
677   G_OBJECT_CLASS (gtk_style_context_parent_class)->finalize (object);
678 }
679
680 static void
681 gtk_style_context_impl_set_property (GObject      *object,
682                                      guint         prop_id,
683                                      const GValue *value,
684                                      GParamSpec   *pspec)
685 {
686   GtkStyleContextPrivate *priv;
687   GtkStyleContext *style_context;
688
689   style_context = GTK_STYLE_CONTEXT (object);
690   priv = style_context->priv;
691
692   switch (prop_id)
693     {
694     case PROP_SCREEN:
695       gtk_style_context_set_screen (style_context,
696                                     g_value_get_object (value));
697       break;
698     case PROP_DIRECTION:
699       gtk_style_context_set_direction (style_context,
700                                        g_value_get_enum (value));
701       break;
702     default:
703       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
704       break;
705     }
706 }
707
708 static void
709 gtk_style_context_impl_get_property (GObject    *object,
710                                      guint       prop_id,
711                                      GValue     *value,
712                                      GParamSpec *pspec)
713 {
714   GtkStyleContextPrivate *priv;
715   GtkStyleContext *style_context;
716
717   style_context = GTK_STYLE_CONTEXT (object);
718   priv = style_context->priv;
719
720   switch (prop_id)
721     {
722     case PROP_SCREEN:
723       g_value_set_object (value, priv->screen);
724       break;
725     case PROP_DIRECTION:
726       g_value_set_enum (value, priv->direction);
727       break;
728     default:
729       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
730       break;
731     }
732 }
733
734 static GList *
735 find_next_candidate (GList *local,
736                      GList *global)
737 {
738   if (local && global)
739     {
740       GtkStyleProviderData *local_data, *global_data;
741
742       local_data = local->data;
743       global_data = global->data;
744
745       if (local_data->priority < global_data->priority)
746         return local;
747       else
748         return global;
749     }
750   else if (local)
751     return local;
752   else if (global)
753     return global;
754
755   return NULL;
756 }
757
758 static void
759 build_properties (GtkStyleContext *context,
760                   StyleData       *style_data,
761                   GtkWidgetPath   *path)
762 {
763   GtkStyleContextPrivate *priv;
764   GList *elem, *list, *global_list = NULL;
765
766   priv = context->priv;
767   list = priv->providers;
768
769   if (priv->screen)
770     global_list = g_object_get_qdata (G_OBJECT (priv->screen), provider_list_quark);
771
772   while ((elem = find_next_candidate (list, global_list)) != NULL)
773     {
774       GtkStyleProviderData *data;
775       GtkStyleProperties *provider_style;
776
777       data = elem->data;
778
779       if (elem == list)
780         list = list->next;
781       else
782         global_list = global_list->next;
783
784       provider_style = gtk_style_provider_get_style (data->provider, path);
785
786       if (provider_style)
787         {
788           gtk_style_properties_merge (style_data->store, provider_style, TRUE);
789           g_object_unref (provider_style);
790         }
791     }
792 }
793
794 static void
795 build_icon_factories (GtkStyleContext *context,
796                       StyleData       *style_data,
797                       GtkWidgetPath   *path)
798 {
799   GtkStyleContextPrivate *priv;
800   GList *elem, *list, *global_list = NULL;
801
802   priv = context->priv;
803   list = priv->providers_last;
804
805   if (priv->screen)
806     {
807       global_list = g_object_get_qdata (G_OBJECT (priv->screen), provider_list_quark);
808       global_list = g_list_last (global_list);
809     }
810
811   while ((elem = find_next_candidate (list, global_list)) != NULL)
812     {
813       GtkIconFactory *factory;
814       GtkStyleProviderData *data;
815
816       data = elem->data;
817
818       if (elem == list)
819         list = list->prev;
820       else
821         global_list = global_list->prev;
822
823       factory = gtk_style_provider_get_icon_factory (data->provider, path);
824
825       if (factory)
826         style_data->icon_factories = g_slist_prepend (style_data->icon_factories, factory);
827     }
828 }
829
830 GtkWidgetPath *
831 create_query_path (GtkStyleContext *context)
832 {
833   GtkStyleContextPrivate *priv;
834   GtkWidgetPath *path;
835   GtkStyleInfo *info;
836   guint i, pos;
837
838   priv = context->priv;
839   path = gtk_widget_path_copy (priv->widget_path);
840   pos = gtk_widget_path_length (path) - 1;
841
842   info = priv->info_stack->data;
843
844   /* Set widget regions */
845   for (i = 0; i < info->regions->len; i++)
846     {
847       GtkRegion *region;
848
849       region = &g_array_index (info->regions, GtkRegion, i);
850       gtk_widget_path_iter_add_region (path, pos,
851                                        g_quark_to_string (region->class_quark),
852                                        region->flags);
853     }
854
855   /* Set widget classes */
856   for (i = 0; i < info->style_classes->len; i++)
857     {
858       GQuark quark;
859
860       quark = g_array_index (info->style_classes, GQuark, i);
861       gtk_widget_path_iter_add_class (path, pos,
862                                       g_quark_to_string (quark));
863     }
864
865   return path;
866 }
867
868 static StyleData *
869 style_data_lookup (GtkStyleContext *context)
870 {
871   GtkStyleContextPrivate *priv;
872   StyleData *data;
873
874   priv = context->priv;
875
876   /* Current data in use is cached, just return it */
877   if (priv->current_data)
878     return priv->current_data;
879
880   g_assert (priv->widget_path != NULL);
881
882   data = g_hash_table_lookup (priv->style_data, priv->info_stack->data);
883
884   if (!data)
885     {
886       GtkWidgetPath *path;
887
888       data = style_data_new ();
889       path = create_query_path (context);
890
891       build_properties (context, data, path);
892       build_icon_factories (context, data, path);
893
894       g_hash_table_insert (priv->style_data,
895                            style_info_copy (priv->info_stack->data),
896                            data);
897
898       gtk_widget_path_free (path);
899     }
900
901   priv->current_data = data;
902
903   if (priv->theming_engine)
904     g_object_unref (priv->theming_engine);
905
906   gtk_style_properties_get (data->store, 0,
907                             "engine", &priv->theming_engine,
908                             NULL);
909   return data;
910 }
911
912 static void
913 style_provider_add (GList            **list,
914                     GtkStyleProvider  *provider,
915                     guint              priority)
916 {
917   GtkStyleProviderData *new_data;
918   gboolean added = FALSE;
919   GList *l = *list;
920
921   new_data = style_provider_data_new (provider, priority);
922
923   while (l)
924     {
925       GtkStyleProviderData *data;
926
927       data = l->data;
928
929       /* Provider was already attached to the style
930        * context, remove in order to add the new data
931        */
932       if (data->provider == provider)
933         {
934           GList *link;
935
936           link = l;
937           l = l->next;
938
939           /* Remove and free link */
940           *list = g_list_remove_link (*list, link);
941           style_provider_data_free (link->data);
942           g_list_free_1 (link);
943
944           continue;
945         }
946
947       if (!added &&
948           data->priority > priority)
949         {
950           *list = g_list_insert_before (*list, l, new_data);
951           added = TRUE;
952         }
953
954       l = l->next;
955     }
956
957   if (!added)
958     *list = g_list_append (*list, new_data);
959 }
960
961 static gboolean
962 style_provider_remove (GList            **list,
963                        GtkStyleProvider  *provider)
964 {
965   GList *l = *list;
966
967   while (l)
968     {
969       GtkStyleProviderData *data;
970
971       data = l->data;
972
973       if (data->provider == provider)
974         {
975           *list = g_list_remove_link (*list, l);
976           style_provider_data_free (l->data);
977           g_list_free_1 (l);
978
979           return TRUE;
980         }
981
982       l = l->next;
983     }
984
985   return FALSE;
986 }
987
988 /**
989  * gtk_style_context_new:
990  *
991  * Creates a standalone #GtkStyleContext, this style context
992  * won't be attached to any widget nor screen, so you may want
993  * to call gtk_style_context_set_path() and
994  * gtk_style_context_set_screen() yourself.
995  *
996  * <note>
997  * This function is only useful when using the theming layer
998  * separated from GTK+, if you are using #GtkStyleContext to
999  * theme #GtkWidget<!-- -->s, use gtk_widget_get_style_context()
1000  * in order to get a style context ready to theme the widget.
1001  * </note>
1002  *
1003  * Returns: A newly created #GtkStyleContext.
1004  **/
1005 GtkStyleContext *
1006 gtk_style_context_new (void)
1007 {
1008   return g_object_new (GTK_TYPE_STYLE_CONTEXT, NULL);
1009 }
1010
1011 /**
1012  * gtk_style_context_add_provider:
1013  * @context: a #GtkStyleContext
1014  * @provider: a #GtkStyleProvider
1015  * @priority: the priority of the style provider. The lower
1016  *            it is, the earlier it will be used in the style
1017  *            construction. Typically this will be in the range
1018  *            between %GTK_STYLE_PROVIDER_PRIORITY_FALLBACK and
1019  *            %GTK_STYLE_PROVIDER_PRIORITY_USER
1020  *
1021  * Adds a style provider to @context, to be used in style construction.
1022  *
1023  * Since: 3.0
1024  **/
1025 void
1026 gtk_style_context_add_provider (GtkStyleContext  *context,
1027                                 GtkStyleProvider *provider,
1028                                 guint             priority)
1029 {
1030   GtkStyleContextPrivate *priv;
1031
1032   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
1033   g_return_if_fail (GTK_IS_STYLE_PROVIDER (provider));
1034
1035   priv = context->priv;
1036   style_provider_add (&priv->providers, provider, priority);
1037   priv->providers_last = g_list_last (priv->providers);
1038
1039   gtk_style_context_invalidate (context);
1040 }
1041
1042 /**
1043  * gtk_style_context_remove_provider:
1044  * @context: a #GtkStyleContext
1045  * @provider: a #GtkStyleProvider
1046  *
1047  * Removes @provider from the style providers list in @context.
1048  *
1049  * Since: 3.0
1050  **/
1051 void
1052 gtk_style_context_remove_provider (GtkStyleContext  *context,
1053                                    GtkStyleProvider *provider)
1054 {
1055   GtkStyleContextPrivate *priv;
1056
1057   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
1058   g_return_if_fail (GTK_IS_STYLE_PROVIDER (provider));
1059
1060   priv = context->priv;
1061
1062   if (style_provider_remove (&priv->providers, provider))
1063     {
1064       priv->providers_last = g_list_last (priv->providers);
1065
1066       gtk_style_context_invalidate (context);
1067     }
1068 }
1069
1070 /**
1071  * gtk_style_context_reset_widgets:
1072  * @screen: a #GdkScreen
1073  *
1074  * This function recomputes the styles for all widgets under a particular
1075  * #GdkScreen. This is useful when some global parameter has changed that
1076  * affects the appearance of all widgets, because when a widget gets a new
1077  * style, it will both redraw and recompute any cached information about
1078  * its appearance. As an example, it is used when the color scheme changes
1079  * in the related #GtkSettings object.
1080  *
1081  * Since: 3.0
1082  **/
1083 void
1084 gtk_style_context_reset_widgets (GdkScreen *screen)
1085 {
1086   GList *list, *toplevels;
1087
1088   toplevels = gtk_window_list_toplevels ();
1089   g_list_foreach (toplevels, (GFunc) g_object_ref, NULL);
1090
1091   for (list = toplevels; list; list = list->next)
1092     {
1093       if (gtk_widget_get_screen (list->data) == screen)
1094         gtk_widget_reset_style (list->data);
1095
1096       g_object_unref (list->data);
1097     }
1098
1099   g_list_free (toplevels);
1100 }
1101
1102 /**
1103  * gtk_style_context_add_provider_for_screen:
1104  * @screen: a #GdkScreen
1105  * @provider: a #GtkStyleProvider
1106  * @priority: the priority of the style provider. The lower
1107  *            it is, the earlier it will be used in the style
1108  *            construction. Typically this will be in the range
1109  *            between %GTK_STYLE_PROVIDER_PRIORITY_FALLBACK and
1110  *            %GTK_STYLE_PROVIDER_PRIORITY_USER
1111  *
1112  * Adds a global style provider to @screen, which will be used
1113  * in style construction for all #GtkStyleContext<!-- -->s under
1114  * @screen.
1115  *
1116  * Since: 3.0
1117  **/
1118 void
1119 gtk_style_context_add_provider_for_screen (GdkScreen        *screen,
1120                                            GtkStyleProvider *provider,
1121                                            guint             priority)
1122 {
1123   GList *providers, *list;
1124
1125   g_return_if_fail (GDK_IS_SCREEN (screen));
1126   g_return_if_fail (GTK_IS_STYLE_PROVIDER (provider));
1127
1128   if (G_UNLIKELY (!provider_list_quark))
1129     provider_list_quark = g_quark_from_static_string ("gtk-provider-list-quark");
1130
1131   list = providers = g_object_get_qdata (G_OBJECT (screen), provider_list_quark);
1132   style_provider_add (&list, provider, priority);
1133
1134   if (list != providers)
1135     g_object_set_qdata (G_OBJECT (screen), provider_list_quark, list);
1136
1137   gtk_style_context_reset_widgets (screen);
1138 }
1139
1140 /**
1141  * gtk_style_context_remove_provider_for_screen:
1142  * @screen: a #GdkScreen
1143  * @provider: a #GtkStyleProvider
1144  *
1145  * Removes @provider from the global style providers list in @screen.
1146  *
1147  * Since: 3.0
1148  **/
1149 void
1150 gtk_style_context_remove_provider_for_screen (GdkScreen        *screen,
1151                                               GtkStyleProvider *provider)
1152 {
1153   GList *providers, *list;
1154
1155   g_return_if_fail (GDK_IS_SCREEN (screen));
1156   g_return_if_fail (GTK_IS_STYLE_PROVIDER (provider));
1157
1158   if (G_UNLIKELY (!provider_list_quark))
1159     return;
1160
1161   list = providers = g_object_get_qdata (G_OBJECT (screen), provider_list_quark);
1162
1163   if (style_provider_remove (&list, provider))
1164     {
1165       if (list != providers)
1166         g_object_set_qdata (G_OBJECT (screen), provider_list_quark, list);
1167
1168       gtk_style_context_reset_widgets (screen);
1169     }
1170 }
1171
1172 /**
1173  * gtk_style_context_get_property:
1174  * @context: a #GtkStyleContext
1175  * @property: style property name
1176  * @state: state to retrieve the property value for
1177  * @value: (out) (transfer full):  return location for the style property value.
1178  *
1179  * Gets a style property from @context for the given state. When done with @value,
1180  * g_value_unset() needs to be called to free any allocated memory.
1181  *
1182  * Since: 3.0
1183  **/
1184 void
1185 gtk_style_context_get_property (GtkStyleContext *context,
1186                                 const gchar     *property,
1187                                 GtkStateFlags    state,
1188                                 GValue          *value)
1189 {
1190   GtkStyleContextPrivate *priv;
1191   StyleData *data;
1192
1193   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
1194   g_return_if_fail (property != NULL);
1195   g_return_if_fail (value != NULL);
1196
1197   priv = context->priv;
1198
1199   g_return_if_fail (priv->widget_path != NULL);
1200
1201   data = style_data_lookup (context);
1202   gtk_style_properties_get_property (data->store, property, state, value);
1203 }
1204
1205 /**
1206  * gtk_style_context_get_valist:
1207  * @context: a #GtkStyleContext
1208  * @state: state to retrieve the property values for
1209  * @args: va_list of property name/return location pairs, followed by %NULL
1210  *
1211  * Retrieves several style property values from @context for a given state.
1212  *
1213  * Since: 3.0
1214  **/
1215 void
1216 gtk_style_context_get_valist (GtkStyleContext *context,
1217                               GtkStateFlags    state,
1218                               va_list          args)
1219 {
1220   GtkStyleContextPrivate *priv;
1221   StyleData *data;
1222
1223   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
1224
1225   priv = context->priv;
1226   g_return_if_fail (priv->widget_path != NULL);
1227
1228   data = style_data_lookup (context);
1229   gtk_style_properties_get_valist (data->store, state, args);
1230 }
1231
1232 /**
1233  * gtk_style_context_get:
1234  * @context: a #GtkStyleContext
1235  * @state: state to retrieve the property values for
1236  * @...: property name /return value pairs, followed by %NULL
1237  *
1238  * Retrieves several style property values from @context for a
1239  * given state.
1240  *
1241  * Since: 3.0
1242  **/
1243 void
1244 gtk_style_context_get (GtkStyleContext *context,
1245                        GtkStateFlags    state,
1246                        ...)
1247 {
1248   GtkStyleContextPrivate *priv;
1249   StyleData *data;
1250   va_list args;
1251
1252   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
1253
1254   priv = context->priv;
1255   g_return_if_fail (priv->widget_path != NULL);
1256
1257   data = style_data_lookup (context);
1258
1259   va_start (args, state);
1260   gtk_style_properties_get_valist (data->store, state, args);
1261   va_end (args);
1262 }
1263
1264 /**
1265  * gtk_style_context_set_state:
1266  * @context: a #GtkStyleContext
1267  * @flags: state to represent
1268  *
1269  * Sets the style to be used when rendering with any
1270  * of the "gtk_render_" prefixed functions.
1271  *
1272  * Since: 3.0
1273  **/
1274 void
1275 gtk_style_context_set_state (GtkStyleContext *context,
1276                              GtkStateFlags    flags)
1277 {
1278   GtkStyleContextPrivate *priv;
1279   GtkStyleInfo *info;
1280
1281   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
1282
1283   priv = context->priv;
1284   info = priv->info_stack->data;
1285   info->state_flags = flags;
1286 }
1287
1288 /**
1289  * gtk_style_context_get_state:
1290  * @context: a #GtkStyleContext
1291  *
1292  * returns the state used when rendering.
1293  *
1294  * Returns: the state flags
1295  *
1296  * Since: 3.0
1297  **/
1298 GtkStateFlags
1299 gtk_style_context_get_state (GtkStyleContext *context)
1300 {
1301   GtkStyleContextPrivate *priv;
1302   GtkStyleInfo *info;
1303
1304   g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), 0);
1305
1306   priv = context->priv;
1307   info = priv->info_stack->data;
1308
1309   return info->state_flags;
1310 }
1311
1312 static gboolean
1313 context_has_animatable_region (GtkStyleContext *context,
1314                                gpointer         region_id)
1315 {
1316   GtkStyleContextPrivate *priv;
1317   GSList *r;
1318
1319   /* NULL region_id means everything
1320    * rendered through the style context
1321    */
1322   if (!region_id)
1323     return TRUE;
1324
1325   priv = context->priv;
1326
1327   for (r = priv->animation_regions; r; r = r->next)
1328     {
1329       if (r->data == region_id)
1330         return TRUE;
1331     }
1332
1333   return FALSE;
1334 }
1335
1336 /**
1337  * gtk_style_context_state_is_running:
1338  * @context: a #GtkStyleContext
1339  * @state: a widget state
1340  * @progress: (out): return location for the transition progress
1341  *
1342  * Returns %TRUE if there is a transition animation running for the
1343  * current region (see gtk_style_context_push_animatable_region()).
1344  *
1345  * If @progress is not %NULL, the animation progress will be returned
1346  * there, 0.0 means the state is closest to being %FALSE, while 1.0 means
1347  * it's closest to being %TRUE. This means transition animations will
1348  * run from 0 to 1 when @state is being set to %TRUE and from 1 to 0 when
1349  * it's being set to %FALSE.
1350  *
1351  * Returns: %TRUE if there is a running transition animation for @state.
1352  *
1353  * Since: 3.0
1354  **/
1355 gboolean
1356 gtk_style_context_state_is_running (GtkStyleContext *context,
1357                                     GtkStateType     state,
1358                                     gdouble         *progress)
1359 {
1360   GtkStyleContextPrivate *priv;
1361   AnimationInfo *info;
1362   GSList *l;
1363
1364   g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), FALSE);
1365
1366   priv = context->priv;
1367
1368   for (l = priv->animations; l; l = l->next)
1369     {
1370       info = l->data;
1371
1372       if (info->state == state &&
1373           context_has_animatable_region (context, info->region_id))
1374         {
1375           if (progress)
1376             *progress = gtk_timeline_get_progress (info->timeline);
1377
1378           return TRUE;
1379         }
1380     }
1381
1382   return FALSE;
1383 }
1384
1385 /**
1386  * gtk_style_context_set_path:
1387  * @context: a #GtkStyleContext
1388  * @path: a #GtkWidgetPath
1389  *
1390  * Sets the #GtkWidgetPath used for style matching. As a
1391  * consequence, the style will be regenerated to match
1392  * the new given path. If you are using a #GtkStyleContext
1393  * returned from gtk_widget_get_style_context(), you do
1394  * not need to call this yourself.
1395  *
1396  * Since: 3.0
1397  **/
1398 void
1399 gtk_style_context_set_path (GtkStyleContext *context,
1400                             GtkWidgetPath   *path)
1401 {
1402   GtkStyleContextPrivate *priv;
1403
1404   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
1405   g_return_if_fail (path != NULL);
1406
1407   priv = context->priv;
1408
1409   if (priv->widget_path)
1410     {
1411       gtk_widget_path_free (priv->widget_path);
1412       priv->widget_path = NULL;
1413     }
1414
1415   if (path)
1416     priv->widget_path = gtk_widget_path_copy (path);
1417
1418   gtk_style_context_invalidate (context);
1419 }
1420
1421 /**
1422  * gtk_style_context_get_path:
1423  * @context: a #GtkStyleContext
1424  *
1425  * Returns the widget path used for style matching.
1426  *
1427  * Returns: (transfer none): A #GtkWidgetPath
1428  *
1429  * Since: 3.0
1430  **/
1431 G_CONST_RETURN GtkWidgetPath *
1432 gtk_style_context_get_path (GtkStyleContext *context)
1433 {
1434   GtkStyleContextPrivate *priv;
1435
1436   priv = context->priv;
1437   return priv->widget_path;
1438 }
1439
1440 /**
1441  * gtk_style_context_save:
1442  * @context: a #GtkStyleContext
1443  *
1444  * Saves the @context state, so all modifications done through
1445  * gtk_style_context_add_class(), gtk_style_context_remove_class(),
1446  * gtk_style_context_add_region(), gtk_style_context_remove_region()
1447  * or gtk_style_context_set_junction_sides() can be reverted in one
1448  * go through gtk_style_context_restore().
1449  *
1450  * Since: 3.0
1451  **/
1452 void
1453 gtk_style_context_save (GtkStyleContext *context)
1454 {
1455   GtkStyleContextPrivate *priv;
1456   GtkStyleInfo *info;
1457
1458   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
1459
1460   priv = context->priv;
1461
1462   g_assert (priv->info_stack != NULL);
1463
1464   info = style_info_copy (priv->info_stack->data);
1465   priv->info_stack = g_slist_prepend (priv->info_stack, info);
1466 }
1467
1468 /**
1469  * gtk_style_context_restore:
1470  * @context: a #GtkStyleContext
1471  *
1472  * Restores @context state to a previous stage. See
1473  * gtk_style_context_save().
1474  *
1475  * Since: 3.0
1476  **/
1477 void
1478 gtk_style_context_restore (GtkStyleContext *context)
1479 {
1480   GtkStyleContextPrivate *priv;
1481   GtkStyleInfo *info;
1482
1483   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
1484
1485   priv = context->priv;
1486
1487   if (priv->info_stack)
1488     {
1489       info = priv->info_stack->data;
1490       priv->info_stack = g_slist_remove (priv->info_stack, info);
1491       style_info_free (info);
1492     }
1493
1494   if (!priv->info_stack)
1495     {
1496       g_warning ("Unpaired gtk_style_context_restore() call");
1497
1498       /* Create default region */
1499       info = style_info_new ();
1500       priv->info_stack = g_slist_prepend (priv->info_stack, info);
1501     }
1502
1503   priv->current_data = NULL;
1504 }
1505
1506 static gboolean
1507 style_class_find (GArray *array,
1508                   GQuark  class_quark,
1509                   guint  *position)
1510 {
1511   gint min, max, mid;
1512   gboolean found = FALSE;
1513   guint pos;
1514
1515   if (position)
1516     *position = 0;
1517
1518   if (!array || array->len == 0)
1519     return FALSE;
1520
1521   min = 0;
1522   max = array->len - 1;
1523
1524   do
1525     {
1526       GQuark item;
1527
1528       mid = (min + max) / 2;
1529       item = g_array_index (array, GQuark, mid);
1530
1531       if (class_quark == item)
1532         {
1533           found = TRUE;
1534           pos = mid;
1535         }
1536       else if (class_quark > item)
1537         min = pos = mid + 1;
1538       else
1539         {
1540           max = mid - 1;
1541           pos = mid;
1542         }
1543     }
1544   while (!found && min <= max);
1545
1546   if (position)
1547     *position = pos;
1548
1549   return found;
1550 }
1551
1552 static gboolean
1553 region_find (GArray *array,
1554              GQuark  class_quark,
1555              guint  *position)
1556 {
1557   gint min, max, mid;
1558   gboolean found = FALSE;
1559   guint pos;
1560
1561   if (position)
1562     *position = 0;
1563
1564   if (!array || array->len == 0)
1565     return FALSE;
1566
1567   min = 0;
1568   max = array->len - 1;
1569
1570   do
1571     {
1572       GtkRegion *region;
1573
1574       mid = (min + max) / 2;
1575       region = &g_array_index (array, GtkRegion, mid);
1576
1577       if (region->class_quark == class_quark)
1578         {
1579           found = TRUE;
1580           pos = mid;
1581         }
1582       else if (region->class_quark > class_quark)
1583         min = pos = mid + 1;
1584       else
1585         {
1586           max = mid - 1;
1587           pos = mid;
1588         }
1589     }
1590   while (!found && min <= max);
1591
1592   if (position)
1593     *position = pos;
1594
1595   return found;
1596 }
1597
1598 /**
1599  * gtk_style_context_add_class:
1600  * @context: a #GtkStyleContext
1601  * @class_name: class name to use in styling
1602  *
1603  * Sets a class name to @context, so posterior calls to
1604  * gtk_style_context_get() or any of the gtk_render_*
1605  * functions will make use of this new class for styling.
1606  *
1607  * In the CSS file format, a #GtkEntry defining an "entry"
1608  * class, would be matched by:
1609  *
1610  * <programlisting>
1611  * GtkEntry.entry { ... }
1612  * </programlisting>
1613  *
1614  * While any widget defining an "entry" class would be
1615  * matched by:
1616  * <programlisting>
1617  * .entry { ... }
1618  * </programlisting>
1619  *
1620  * Since: 3.0
1621  **/
1622 void
1623 gtk_style_context_add_class (GtkStyleContext *context,
1624                              const gchar     *class_name)
1625 {
1626   GtkStyleContextPrivate *priv;
1627   GtkStyleInfo *info;
1628   GQuark class_quark;
1629   guint position;
1630
1631   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
1632   g_return_if_fail (class_name != NULL);
1633
1634   priv = context->priv;
1635   class_quark = g_quark_from_string (class_name);
1636
1637   g_assert (priv->info_stack != NULL);
1638   info = priv->info_stack->data;
1639
1640   if (!style_class_find (info->style_classes, class_quark, &position))
1641     {
1642       g_array_insert_val (info->style_classes, position, class_quark);
1643
1644       /* Unset current data, as it likely changed due to the class change */
1645       priv->current_data = NULL;
1646     }
1647 }
1648
1649 /**
1650  * gtk_style_context_remove_class:
1651  * @context: a #GtkStyleContext
1652  * @class_name: class name to remove
1653  *
1654  * Removes @class_name from @context.
1655  *
1656  * Since: 3.0
1657  **/
1658 void
1659 gtk_style_context_remove_class (GtkStyleContext *context,
1660                                 const gchar     *class_name)
1661 {
1662   GtkStyleContextPrivate *priv;
1663   GtkStyleInfo *info;
1664   GQuark class_quark;
1665   guint position;
1666
1667   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
1668   g_return_if_fail (class_name != NULL);
1669
1670   class_quark = g_quark_try_string (class_name);
1671
1672   if (!class_quark)
1673     return;
1674
1675   priv = context->priv;
1676
1677   g_assert (priv->info_stack != NULL);
1678   info = priv->info_stack->data;
1679
1680   if (style_class_find (info->style_classes, class_quark, &position))
1681     {
1682       g_array_remove_index (info->style_classes, position);
1683
1684       /* Unset current data, as it likely changed due to the class change */
1685       priv->current_data = NULL;
1686     }
1687 }
1688
1689 /**
1690  * gtk_style_context_has_class:
1691  * @context: a #GtkStyleContext
1692  * @class_name: a class name
1693  *
1694  * Returns %TRUE if @context currently has defined the
1695  * given class name
1696  *
1697  * Returns: %TRUE if @context has @class_name defined
1698  *
1699  * Since: 3.0
1700  **/
1701 gboolean
1702 gtk_style_context_has_class (GtkStyleContext *context,
1703                              const gchar     *class_name)
1704 {
1705   GtkStyleContextPrivate *priv;
1706   GtkStyleInfo *info;
1707   GQuark class_quark;
1708
1709   g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), FALSE);
1710   g_return_val_if_fail (class_name != NULL, FALSE);
1711
1712   class_quark = g_quark_try_string (class_name);
1713
1714   if (!class_quark)
1715     return FALSE;
1716
1717   priv = context->priv;
1718
1719   g_assert (priv->info_stack != NULL);
1720   info = priv->info_stack->data;
1721
1722   if (style_class_find (info->style_classes, class_quark, NULL))
1723     return TRUE;
1724
1725   return FALSE;
1726 }
1727
1728 /**
1729  * gtk_style_context_list_classes:
1730  * @context: a #GtkStyleContext
1731  *
1732  * Returns the list of classes currently defined in @context.
1733  *
1734  * Returns: (transfer container) (element-type utf8): a #GList of
1735  *          strings with the currently defined classes. The contents
1736  *          of the list are owned by GTK+, but you must free the list
1737  *          itself with g_list_free() when you are done with it.
1738  *
1739  * Since: 3.0
1740  **/
1741 GList *
1742 gtk_style_context_list_classes (GtkStyleContext *context)
1743 {
1744   GtkStyleContextPrivate *priv;
1745   GtkStyleInfo *info;
1746   GList *classes = NULL;
1747   guint i;
1748
1749   g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), NULL);
1750
1751   priv = context->priv;
1752
1753   g_assert (priv->info_stack != NULL);
1754   info = priv->info_stack->data;
1755
1756   for (i = 0; i < info->style_classes->len; i++)
1757     {
1758       GQuark quark;
1759
1760       quark = g_array_index (info->style_classes, GQuark, i);
1761       classes = g_list_prepend (classes, (gchar *) g_quark_to_string (quark));
1762     }
1763
1764   return classes;
1765 }
1766
1767 /**
1768  * gtk_style_context_list_regions:
1769  * @context: a #GtkStyleContext
1770  *
1771  *
1772  * Returns the list of regions currently defined in @context.
1773  *
1774  * Returns: (transfer container) (element-type utf8): a #GList of
1775  *          strings with the currently defined regions. The contents
1776  *          of the list are owned by GTK+, but you must free the list
1777  *          itself with g_list_free() when you are done with it.
1778  *
1779  * Since: 3.0
1780  **/
1781 GList *
1782 gtk_style_context_list_regions (GtkStyleContext *context)
1783 {
1784   GtkStyleContextPrivate *priv;
1785   GtkStyleInfo *info;
1786   GList *classes = NULL;
1787   guint i;
1788
1789   g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), NULL);
1790
1791   priv = context->priv;
1792
1793   g_assert (priv->info_stack != NULL);
1794   info = priv->info_stack->data;
1795
1796   for (i = 0; i < info->regions->len; i++)
1797     {
1798       GtkRegion *region;
1799       const gchar *class_name;
1800
1801       region = &g_array_index (info->regions, GtkRegion, i);
1802
1803       class_name = g_quark_to_string (region->class_quark);
1804       classes = g_list_prepend (classes, (gchar *) class_name);
1805     }
1806
1807   return classes;
1808 }
1809
1810 /**
1811  * gtk_style_context_add_region:
1812  * @context: a #GtkStyleContext
1813  * @region_name: region name to use in styling
1814  * @flags: flags that apply to the region
1815  *
1816  * Sets a region to @context, so posterior calls to
1817  * gtk_style_context_get() or any of the gtk_render_*
1818  * functions will make use of this new region for styling.
1819  *
1820  * In the CSS file format, a #GtkTreeView defining a "row"
1821  * region, would be matched by:
1822  *
1823  * <programlisting>
1824  * GtkTreeView row { ... }
1825  * </programlisting>
1826  *
1827  * pseudo-classes are used for matching @flags, so the two
1828  * following rules:
1829  * <programlisting>
1830  * GtkTreeView row:nth-child (even) { ... }
1831  * GtkTreeView row:nth-child (odd) { ... }
1832  * </programlisting>
1833  *
1834  * would apply to even and odd rows, respectively.
1835  *
1836  * Since: 3.0
1837  **/
1838 void
1839 gtk_style_context_add_region (GtkStyleContext *context,
1840                               const gchar     *region_name,
1841                               GtkRegionFlags   flags)
1842 {
1843   GtkStyleContextPrivate *priv;
1844   GtkStyleInfo *info;
1845   GQuark region_quark;
1846   guint position;
1847
1848   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
1849   g_return_if_fail (region_name != NULL);
1850
1851   priv = context->priv;
1852   region_quark = g_quark_from_string (region_name);
1853
1854   g_assert (priv->info_stack != NULL);
1855   info = priv->info_stack->data;
1856
1857   if (!region_find (info->regions, region_quark, &position))
1858     {
1859       GtkRegion region;
1860
1861       region.class_quark = region_quark;
1862       region.flags = flags;
1863
1864       g_array_insert_val (info->regions, position, region);
1865
1866       /* Unset current data, as it likely changed due to the region change */
1867       priv->current_data = NULL;
1868     }
1869 }
1870
1871 /**
1872  * gtk_style_context_remove_region:
1873  * @context: a #GtkStyleContext
1874  * @region_name: region name to unset
1875  *
1876  * Removes a region from @context
1877  *
1878  * Since: 3.0
1879  **/
1880 void
1881 gtk_style_context_remove_region (GtkStyleContext *context,
1882                                  const gchar     *region_name)
1883 {
1884   GtkStyleContextPrivate *priv;
1885   GtkStyleInfo *info;
1886   GQuark region_quark;
1887   guint position;
1888
1889   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
1890   g_return_if_fail (region_name != NULL);
1891
1892   region_quark = g_quark_try_string (region_name);
1893
1894   if (!region_quark)
1895     return;
1896
1897   priv = context->priv;
1898
1899   g_assert (priv->info_stack != NULL);
1900   info = priv->info_stack->data;
1901
1902   if (region_find (info->regions, region_quark, &position))
1903     {
1904       g_array_remove_index (info->regions, position);
1905
1906       /* Unset current data, as it likely changed due to the region change */
1907       priv->current_data = NULL;
1908     }
1909 }
1910
1911 /**
1912  * gtk_style_context_has_region:
1913  * @context: a #GtkStyleContext
1914  * @region_name: a region name
1915  * @flags_return: (out) (allow-none): return location for region flags
1916  *
1917  * Returns %TRUE if @context has the region defined. If @flags_return is
1918  * not %NULL, it is set to the flags affecting the region.
1919  *
1920  * Returns: %TRUE if region is defined
1921  *
1922  * Since: 3.0
1923  **/
1924 gboolean
1925 gtk_style_context_has_region (GtkStyleContext *context,
1926                               const gchar     *region_name,
1927                               GtkRegionFlags  *flags_return)
1928 {
1929   GtkStyleContextPrivate *priv;
1930   GtkStyleInfo *info;
1931   GQuark region_quark;
1932   guint position;
1933
1934   g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), FALSE);
1935   g_return_val_if_fail (region_name != NULL, FALSE);
1936
1937   if (flags_return)
1938     *flags_return = 0;
1939
1940   region_quark = g_quark_try_string (region_name);
1941
1942   if (!region_quark)
1943     return FALSE;
1944
1945   priv = context->priv;
1946
1947   g_assert (priv->info_stack != NULL);
1948   info = priv->info_stack->data;
1949
1950   if (region_find (info->regions, region_quark, &position))
1951     {
1952       if (flags_return)
1953         {
1954           GtkRegion *region;
1955
1956           region = &g_array_index (info->regions, GtkRegion, position);
1957           *flags_return = region->flags;
1958         }
1959       return TRUE;
1960     }
1961
1962   return FALSE;
1963 }
1964
1965 static gint
1966 style_property_values_cmp (gconstpointer bsearch_node1,
1967                            gconstpointer bsearch_node2)
1968 {
1969   const PropertyValue *val1 = bsearch_node1;
1970   const PropertyValue *val2 = bsearch_node2;
1971
1972   if (val1->widget_type == val2->widget_type)
1973     return val1->pspec < val2->pspec ? -1 : val1->pspec == val2->pspec ? 0 : 1;
1974   else
1975     return val1->widget_type < val2->widget_type ? -1 : 1;
1976 }
1977
1978 const GValue *
1979 _gtk_style_context_peek_style_property (GtkStyleContext *context,
1980                                         GType            widget_type,
1981                                         GParamSpec      *pspec)
1982 {
1983   GtkStyleContextPrivate *priv;
1984   PropertyValue *pcache, key = { 0 };
1985   GList *global_list = NULL;
1986   StyleData *data;
1987   guint i;
1988
1989   priv = context->priv;
1990   data = style_data_lookup (context);
1991
1992   key.widget_type = widget_type;
1993   key.pspec = pspec;
1994
1995   /* need value cache array */
1996   if (!data->property_cache)
1997     data->property_cache = g_array_new (FALSE, FALSE, sizeof (PropertyValue));
1998   else
1999     {
2000       pcache = bsearch (&key,
2001                         data->property_cache->data, data->property_cache->len,
2002                         sizeof (PropertyValue), style_property_values_cmp);
2003       if (pcache)
2004         return &pcache->value;
2005     }
2006
2007   i = 0;
2008   while (i < data->property_cache->len &&
2009          style_property_values_cmp (&key, &g_array_index (data->property_cache, PropertyValue, i)) >= 0)
2010     i++;
2011
2012   g_array_insert_val (data->property_cache, i, key);
2013   pcache = &g_array_index (data->property_cache, PropertyValue, i);
2014
2015   /* cache miss, initialize value type, then set contents */
2016   g_param_spec_ref (pcache->pspec);
2017   g_value_init (&pcache->value, G_PARAM_SPEC_VALUE_TYPE (pspec));
2018
2019   if (priv->screen)
2020     {
2021       global_list = g_object_get_qdata (G_OBJECT (priv->screen), provider_list_quark);
2022       global_list = g_list_last (global_list);
2023     }
2024
2025   if (priv->widget_path)
2026     {
2027       GList *list, *global, *elem;
2028
2029       list = priv->providers_last;
2030       global = global_list;
2031
2032       while ((elem = find_next_candidate (list, global)) != NULL)
2033         {
2034           GtkStyleProviderData *provider_data;
2035
2036           provider_data = elem->data;
2037
2038           if (elem == list)
2039             list = list->prev;
2040           else
2041             global = global->prev;
2042
2043           if (gtk_style_provider_get_style_property (provider_data->provider, priv->widget_path,
2044                                                      pspec->name, &pcache->value))
2045             {
2046               /* Resolve symbolic colors to GdkColor/GdkRGBA */
2047               if (G_VALUE_TYPE (&pcache->value) == GTK_TYPE_SYMBOLIC_COLOR)
2048                 {
2049                   GtkSymbolicColor *color;
2050                   GdkRGBA rgba;
2051
2052                   color = g_value_get_boxed (&pcache->value);
2053
2054                   if (gtk_symbolic_color_resolve (color, data->store, &rgba))
2055                     {
2056                       g_value_unset (&pcache->value);
2057
2058                       if (G_PARAM_SPEC_VALUE_TYPE (pspec) == GDK_TYPE_RGBA)
2059                         {
2060                           g_value_init (&pcache->value, GDK_TYPE_RGBA);
2061                           g_value_set_boxed (&pcache->value, &rgba);
2062                         }
2063                       else
2064                         {
2065                           GdkColor rgb;
2066
2067                           rgb.red = rgba.red * 65535. + 0.5;
2068                           rgb.green = rgba.green * 65535. + 0.5;
2069                           rgb.blue = rgba.blue * 65535. + 0.5;
2070
2071                           g_value_init (&pcache->value, GDK_TYPE_COLOR);
2072                           g_value_set_boxed (&pcache->value, &rgb);
2073                         }
2074                     }
2075                   else
2076                     g_param_value_set_default (pspec, &pcache->value);
2077                 }
2078
2079               return &pcache->value;
2080             }
2081         }
2082     }
2083
2084   /* not supplied by any provider, revert to default */
2085   g_param_value_set_default (pspec, &pcache->value);
2086
2087   return &pcache->value;
2088 }
2089
2090 /**
2091  * gtk_style_context_get_style_property:
2092  * @context: a #GtkStyleContext
2093  * @property_name: the name of the widget style property
2094  * @value: (out) (transfer full): Return location for the property value, free with
2095  *         g_value_unset() after use.
2096  *
2097  * Gets the value for a widget style property.
2098  **/
2099 void
2100 gtk_style_context_get_style_property (GtkStyleContext *context,
2101                                       const gchar     *property_name,
2102                                       GValue          *value)
2103 {
2104   GtkStyleContextPrivate *priv;
2105   GtkWidgetClass *widget_class;
2106   GParamSpec *pspec;
2107   const GValue *peek_value;
2108   GType widget_type;
2109
2110   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2111   g_return_if_fail (property_name != NULL);
2112   g_return_if_fail (value != NULL);
2113
2114   priv = context->priv;
2115
2116   if (!priv->widget_path)
2117     return;
2118
2119   widget_type = gtk_widget_path_get_widget_type (priv->widget_path);
2120
2121   widget_class = g_type_class_ref (widget_type);
2122   pspec = gtk_widget_class_find_style_property (widget_class, property_name);
2123   g_type_class_unref (widget_class);
2124
2125   if (!pspec)
2126     {
2127       g_warning ("%s: widget class `%s' has no style property named `%s'",
2128                  G_STRLOC,
2129                  g_type_name (widget_type),
2130                  property_name);
2131       return;
2132     }
2133
2134   peek_value = _gtk_style_context_peek_style_property (context,
2135                                                        widget_type,
2136                                                        pspec);
2137
2138   if (G_VALUE_TYPE (value) == G_VALUE_TYPE (peek_value))
2139     g_value_copy (peek_value, value);
2140   else if (g_value_type_transformable (G_VALUE_TYPE (peek_value), G_VALUE_TYPE (value)))
2141     g_value_transform (peek_value, value);
2142   else
2143     g_warning ("can't retrieve style property `%s' of type `%s' as value of type `%s'",
2144                pspec->name,
2145                G_VALUE_TYPE_NAME (peek_value),
2146                G_VALUE_TYPE_NAME (value));
2147 }
2148
2149 /**
2150  * gtk_style_context_get_style_valist:
2151  * @context: a #GtkStyleContext
2152  * @args: va_list of property name/return location pairs, followed by %NULL
2153  *
2154  * Retrieves several widget style properties from @context according to the
2155  * current style.
2156  *
2157  * Since: 3.0
2158  **/
2159 void
2160 gtk_style_context_get_style_valist (GtkStyleContext *context,
2161                                     va_list          args)
2162 {
2163   GtkStyleContextPrivate *priv;
2164   const gchar *prop_name;
2165
2166   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2167
2168   prop_name = va_arg (args, const gchar *);
2169   priv = context->priv;
2170
2171   if (!priv->widget_path)
2172     return;
2173
2174   while (prop_name)
2175     {
2176       GtkWidgetClass *widget_class;
2177       GParamSpec *pspec;
2178       const GValue *peek_value;
2179       GType widget_type;
2180       gchar *error;
2181
2182       widget_type = gtk_widget_path_get_widget_type (priv->widget_path);
2183
2184       widget_class = g_type_class_ref (widget_type);
2185       pspec = gtk_widget_class_find_style_property (widget_class, prop_name);
2186       g_type_class_unref (widget_class);
2187
2188       if (!pspec)
2189         {
2190           g_warning ("%s: widget class `%s' has no style property named `%s'",
2191                      G_STRLOC,
2192                      g_type_name (widget_type),
2193                      prop_name);
2194           continue;
2195         }
2196
2197       peek_value = _gtk_style_context_peek_style_property (context,
2198                                                            widget_type,
2199                                                            pspec);
2200
2201       G_VALUE_LCOPY (peek_value, args, 0, &error);
2202
2203       if (error)
2204         {
2205           g_warning ("can't retrieve style property `%s' of type `%s': %s",
2206                      pspec->name,
2207                      G_VALUE_TYPE_NAME (peek_value),
2208                      error);
2209           g_free (error);
2210         }
2211
2212       prop_name = va_arg (args, const gchar *);
2213     }
2214 }
2215
2216 /**
2217  * gtk_style_context_get_style:
2218  * @context: a #GtkStyleContext
2219  * @...: property name /return value pairs, followed by %NULL
2220  *
2221  * Retrieves several widget style properties from @context according to the
2222  * current style.
2223  *
2224  * Since: 3.0
2225  **/
2226 void
2227 gtk_style_context_get_style (GtkStyleContext *context,
2228                              ...)
2229 {
2230   va_list args;
2231
2232   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2233
2234   va_start (args, context);
2235   gtk_style_context_get_style_valist (context, args);
2236   va_end (args);
2237 }
2238
2239
2240 /**
2241  * gtk_style_context_lookup_icon_set:
2242  * @context: a #GtkStyleContext
2243  * @stock_id: an icon name
2244  *
2245  * Looks up @stock_id in the icon factories associated to @context and
2246  * the default icon factory, returning an icon set if found, otherwise
2247  * %NULL.
2248  *
2249  * Returns: (transfer none): The looked  up %GtkIconSet, or %NULL
2250  **/
2251 GtkIconSet *
2252 gtk_style_context_lookup_icon_set (GtkStyleContext *context,
2253                                    const gchar     *stock_id)
2254 {
2255   GtkStyleContextPrivate *priv;
2256   StyleData *data;
2257   GSList *list;
2258
2259   g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), NULL);
2260   g_return_val_if_fail (stock_id != NULL, NULL);
2261
2262   priv = context->priv;
2263   g_return_val_if_fail (priv->widget_path != NULL, NULL);
2264
2265   data = style_data_lookup (context);
2266
2267   for (list = data->icon_factories; list; list = list->next)
2268     {
2269       GtkIconFactory *factory;
2270       GtkIconSet *icon_set;
2271
2272       factory = list->data;
2273       icon_set = gtk_icon_factory_lookup (factory, stock_id);
2274
2275       if (icon_set)
2276         return icon_set;
2277     }
2278
2279   return gtk_icon_factory_lookup_default (stock_id);
2280 }
2281
2282 /**
2283  * gtk_style_context_set_screen:
2284  * @context: a #GtkStyleContext
2285  * @screen: a #GdkScreen
2286  *
2287  * Sets the screen to which @context will be attached to, @screen
2288  * is used in order to reconstruct style based on the global providers
2289  * list. If you are using a #GtkStyleContext returned from
2290  * gtk_widget_get_style_context(), you do not need to call this yourself.
2291  *
2292  * Since: 3.0
2293  **/
2294 void
2295 gtk_style_context_set_screen (GtkStyleContext *context,
2296                               GdkScreen       *screen)
2297 {
2298   GtkStyleContextPrivate *priv;
2299
2300   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2301
2302   priv = context->priv;
2303   priv->screen = screen;
2304
2305   g_object_notify (G_OBJECT (context), "screen");
2306
2307   gtk_style_context_invalidate (context);
2308 }
2309
2310 /**
2311  * gtk_style_context_get_screen:
2312  * @context: a #GtkStyleContext
2313  *
2314  * Returns the #GdkScreen to which @context is attached to.
2315  *
2316  * Returns: a #GdkScreen, or %NULL.
2317  **/
2318 GdkScreen *
2319 gtk_style_context_get_screen (GtkStyleContext *context)
2320 {
2321   GtkStyleContextPrivate *priv;
2322
2323   g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), NULL);
2324
2325   priv = context->priv;
2326   return priv->screen;
2327 }
2328
2329 /**
2330  * gtk_style_context_set_direction:
2331  * @context: a #GtkStyleContext
2332  * @direction: the new direction.
2333  *
2334  * Sets the reading direction for rendering purposes. If you are
2335  * using a #GtkStyleContext returned from gtk_widget_get_style_context(),
2336  * you do not need to call this yourself.
2337  *
2338  * Since: 3.0
2339  **/
2340 void
2341 gtk_style_context_set_direction (GtkStyleContext  *context,
2342                                  GtkTextDirection  direction)
2343 {
2344   GtkStyleContextPrivate *priv;
2345
2346   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2347
2348   priv = context->priv;
2349   priv->direction = direction;
2350
2351   g_object_notify (G_OBJECT (context), "direction");
2352 }
2353
2354 /**
2355  * gtk_style_context_get_direction:
2356  * @context: a #GtkStyleContext
2357  *
2358  * Returns the widget direction used for rendering.
2359  *
2360  * Returns: the widget direction
2361  *
2362  * Since: 3.0
2363  **/
2364 GtkTextDirection
2365 gtk_style_context_get_direction (GtkStyleContext *context)
2366 {
2367   GtkStyleContextPrivate *priv;
2368
2369   g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), GTK_TEXT_DIR_LTR);
2370
2371   priv = context->priv;
2372   return priv->direction;
2373 }
2374
2375 /**
2376  * gtk_style_context_set_junction_sides:
2377  * @context: a #GtkStyleContext
2378  * @sides: sides where rendered elements are visually connected to other elements.
2379  *
2380  * Sets the sides where rendered elements (mostly through gtk_render_frame()) will
2381  * visually connect with other visual elements. This is merely a guideline that may
2382  * be honored or not in theming engines.
2383  *
2384  * Since: 3.0
2385  **/
2386 void
2387 gtk_style_context_set_junction_sides (GtkStyleContext  *context,
2388                                       GtkJunctionSides  sides)
2389 {
2390   GtkStyleContextPrivate *priv;
2391   GtkStyleInfo *info;
2392
2393   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2394
2395   priv = context->priv;
2396   info = priv->info_stack->data;
2397   info->junction_sides = sides;
2398 }
2399
2400 /**
2401  * gtk_style_context_get_junction_sides:
2402  * @context: a #GtkStyleContext
2403  *
2404  * Returns the sides where rendered elements connect visually with others.
2405  *
2406  * Returns: the junction sides
2407  *
2408  * Since: 3.0
2409  **/
2410 GtkJunctionSides
2411 gtk_style_context_get_junction_sides (GtkStyleContext *context)
2412 {
2413   GtkStyleContextPrivate *priv;
2414   GtkStyleInfo *info;
2415
2416   g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), 0);
2417
2418   priv = context->priv;
2419   info = priv->info_stack->data;
2420   return info->junction_sides;
2421 }
2422
2423 /**
2424  * gtk_style_context_lookup_color:
2425  * @context: a #GtkStyleContext
2426  * @color_name: color name to lookup
2427  * @color: (out): Return location for the looked up color
2428  *
2429  * Looks up and resolves a color name in the @context color map.
2430  *
2431  * Returns: %TRUE if @color_name was found and resolved, %FALSE otherwise
2432  **/
2433 gboolean
2434 gtk_style_context_lookup_color (GtkStyleContext *context,
2435                                 const gchar     *color_name,
2436                                 GdkRGBA         *color)
2437 {
2438   GtkStyleContextPrivate *priv;
2439   GtkSymbolicColor *sym_color;
2440   StyleData *data;
2441
2442   g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), FALSE);
2443   g_return_val_if_fail (color_name != NULL, FALSE);
2444   g_return_val_if_fail (color != NULL, FALSE);
2445
2446   priv = context->priv;
2447   g_return_val_if_fail (priv->widget_path != NULL, FALSE);
2448
2449   data = style_data_lookup (context);
2450   sym_color = gtk_style_properties_lookup_color (data->store, color_name);
2451
2452   if (!sym_color)
2453     return FALSE;
2454
2455   return gtk_symbolic_color_resolve (sym_color, data->store, color);
2456 }
2457
2458 /**
2459  * gtk_style_context_notify_state_change:
2460  * @context: a #GtkStyleContext
2461  * @window: a #GdkWindow
2462  * @region_id: (allow-none): animatable region to notify on, or %NULL.
2463  *             See gtk_style_context_push_animatable_region()
2464  * @state: state to trigger transition for
2465  * @state_value: target value of @state
2466  *
2467  * Notifies a state change on @context, so if the current style makes use
2468  * of transition animations, one will be started so all rendered elements
2469  * under @region_id are animated for state @state being set to value @state_value.
2470  *
2471  * The @window parameter is used in order to invalidate the rendered area
2472  * as the animation runs, so make sure it is the same window that is being
2473  * rendered on by the gtk_render_*() methods.
2474  *
2475  * If @region_id is %NULL, all rendered elements using @context will be
2476  * affected by this state transition.
2477  *
2478  * As a practical example, a #GtkButton notifying a state transition on
2479  * the prelight state:
2480  * <programlisting>
2481  * gtk_style_context_notify_state_change (context,
2482  *                                        gtk_widget_get_window (widget),
2483  *                                        NULL, GTK_STATE_PRELIGHT,
2484  *                                        button->in_button);
2485  * </programlisting>
2486  *
2487  * Could be handled in the CSS file like this:
2488  * <programlisting>
2489  * GtkButton {
2490  *     background-color: #f00;
2491  * }
2492  *
2493  * GtkButton:hover {
2494  *     background-color: #fff;
2495  *     transition: 200ms linear;
2496  * }
2497  * </programlisting>
2498  *
2499  * This combination would animate the button background from red to white
2500  * if a pointer enters the button, and back to red if the pointer leaves
2501  * the button.
2502  *
2503  * Since: 3.0
2504  **/
2505 void
2506 gtk_style_context_notify_state_change (GtkStyleContext *context,
2507                                        GdkWindow       *window,
2508                                        gpointer         region_id,
2509                                        GtkStateType     state,
2510                                        gboolean         state_value)
2511 {
2512   GtkStyleContextPrivate *priv;
2513   GtkAnimationDescription *desc;
2514   AnimationInfo *info;
2515   GtkStateFlags flags;
2516   StyleData *data;
2517
2518   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2519   g_return_if_fail (GDK_IS_WINDOW (window));
2520   g_return_if_fail (state > GTK_STATE_NORMAL && state <= GTK_STATE_FOCUSED);
2521
2522   priv = context->priv;
2523   g_return_if_fail (priv->widget_path != NULL);
2524
2525   state_value = (state_value == TRUE);
2526
2527   switch (state)
2528     {
2529     case GTK_STATE_ACTIVE:
2530       flags = GTK_STATE_FLAG_ACTIVE;
2531       break;
2532     case GTK_STATE_PRELIGHT:
2533       flags = GTK_STATE_FLAG_PRELIGHT;
2534       break;
2535     case GTK_STATE_SELECTED:
2536       flags = GTK_STATE_FLAG_SELECTED;
2537       break;
2538     case GTK_STATE_INSENSITIVE:
2539       flags = GTK_STATE_FLAG_INSENSITIVE;
2540       break;
2541     case GTK_STATE_INCONSISTENT:
2542       flags = GTK_STATE_FLAG_INCONSISTENT;
2543       break;
2544     case GTK_STATE_FOCUSED:
2545       flags = GTK_STATE_FLAG_FOCUSED;
2546       break;
2547     case GTK_STATE_NORMAL:
2548     default:
2549       flags = 0;
2550       break;
2551     }
2552
2553   /* Find out if there is any animation description for the given
2554    * state, it will fallback to the normal state as well if necessary.
2555    */
2556   data = style_data_lookup (context);
2557   gtk_style_properties_get (data->store, flags,
2558                             "transition", &desc,
2559                             NULL);
2560
2561   if (!desc)
2562     return;
2563
2564   if (gtk_animation_description_get_duration (desc) == 0)
2565     {
2566       gtk_animation_description_unref (desc);
2567       return;
2568     }
2569
2570   info = animation_info_lookup (context, region_id, state);
2571
2572   if (info &&
2573       info->target_value != state_value)
2574     {
2575       /* Target values are the opposite */
2576       if (!gtk_timeline_get_loop (info->timeline))
2577         {
2578           /* Reverse the animation */
2579           if (gtk_timeline_get_direction (info->timeline) == GTK_TIMELINE_DIRECTION_FORWARD)
2580             gtk_timeline_set_direction (info->timeline, GTK_TIMELINE_DIRECTION_BACKWARD);
2581           else
2582             gtk_timeline_set_direction (info->timeline, GTK_TIMELINE_DIRECTION_FORWARD);
2583
2584           info->target_value = state_value;
2585         }
2586       else
2587         {
2588           /* Take it out of its looping state */
2589           gtk_timeline_set_loop (info->timeline, FALSE);
2590         }
2591     }
2592   else if (!info)
2593     {
2594       info = animation_info_new (context, region_id,
2595                                  gtk_animation_description_get_duration (desc),
2596                                  gtk_animation_description_get_progress_type (desc),
2597                                  gtk_animation_description_get_loop (desc),
2598                                  state, state_value, window);
2599
2600       priv->animations = g_slist_prepend (priv->animations, info);
2601       priv->animations_invalidated = TRUE;
2602     }
2603
2604   gtk_animation_description_unref (desc);
2605 }
2606
2607 /**
2608  * gtk_style_context_push_animatable_region:
2609  * @context: a #GtkStyleContext
2610  * @region_id: unique identifier for the animatable region
2611  *
2612  * Pushes an animatable region, so all further gtk_render_*() calls between
2613  * this call and the following gtk_style_context_pop_animatable_region() will
2614  * potentially show transition animations for if gtk_style_context_notify_state_change()
2615  * is called for a given state, and the theme/style used contemplates the use of
2616  * transition animations for state changes.
2617  *
2618  * The @region_id used must be unique in @context so the theming engine may
2619  * univocally identify rendered elements subject to a state transition.
2620  *
2621  * Since: 3.0
2622  **/
2623 void
2624 gtk_style_context_push_animatable_region (GtkStyleContext *context,
2625                                           gpointer         region_id)
2626 {
2627   GtkStyleContextPrivate *priv;
2628
2629   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2630   g_return_if_fail (region_id != NULL);
2631
2632   priv = context->priv;
2633   priv->animation_regions = g_slist_prepend (priv->animation_regions, region_id);
2634 }
2635
2636 /**
2637  * gtk_style_context_pop_animatable_region:
2638  * @context: a #GtkStyleContext
2639  *
2640  * Pops an animatable region from @context. See gtk_style_context_push_animatable_region().
2641  *
2642  * Since: 3.0
2643  **/
2644 void
2645 gtk_style_context_pop_animatable_region (GtkStyleContext *context)
2646 {
2647   GtkStyleContextPrivate *priv;
2648
2649   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2650
2651   priv = context->priv;
2652   priv->animation_regions = g_slist_delete_link (priv->animation_regions,
2653                                                  priv->animation_regions);
2654 }
2655
2656 void
2657 _gtk_style_context_invalidate_animation_areas (GtkStyleContext *context)
2658 {
2659   GtkStyleContextPrivate *priv;
2660   GSList *l;
2661
2662   priv = context->priv;
2663
2664   for (l = priv->animations; l; l = l->next)
2665     {
2666       AnimationInfo *info;
2667
2668       info = l->data;
2669
2670       /* A NULL invalidation region means it has to be recreated on
2671        * the next expose event, this happens usually after a widget
2672        * allocation change, so the next expose after it will update
2673        * the invalidation region.
2674        */
2675       if (info->invalidation_region)
2676         {
2677           cairo_region_destroy (info->invalidation_region);
2678           info->invalidation_region = NULL;
2679         }
2680     }
2681
2682   priv->animations_invalidated = TRUE;
2683 }
2684
2685 void
2686 _gtk_style_context_coalesce_animation_areas (GtkStyleContext *context,
2687                                              gint             rel_x,
2688                                              gint             rel_y)
2689 {
2690   GtkStyleContextPrivate *priv;
2691   GSList *l;
2692
2693   priv = context->priv;
2694
2695   if (!priv->animations_invalidated)
2696     return;
2697
2698   for (l = priv->animations; l; l = l->next)
2699     {
2700       AnimationInfo *info;
2701       guint i;
2702
2703       info = l->data;
2704
2705       if (info->invalidation_region)
2706         continue;
2707
2708       /* FIXME: If this happens there's not much
2709        * point in keeping the animation running.
2710        */
2711       if (info->rectangles->len == 0)
2712         continue;
2713
2714       info->invalidation_region = cairo_region_create ();
2715
2716       for (i = 0; i <info->rectangles->len; i++)
2717         {
2718           cairo_rectangle_int_t *rect;
2719
2720           rect = &g_array_index (info->rectangles, cairo_rectangle_int_t, i);
2721           rect->x += rel_x;
2722           rect->y += rel_y;
2723
2724           cairo_region_union_rectangle (info->invalidation_region, rect);
2725         }
2726
2727       g_array_remove_range (info->rectangles, 0, info->rectangles->len);
2728     }
2729
2730   priv->animations_invalidated = FALSE;
2731 }
2732
2733 static void
2734 store_animation_region (GtkStyleContext *context,
2735                         gdouble          x,
2736                         gdouble          y,
2737                         gdouble          width,
2738                         gdouble          height)
2739 {
2740   GtkStyleContextPrivate *priv;
2741   GSList *l;
2742
2743   priv = context->priv;
2744
2745   if (!priv->animations_invalidated)
2746     return;
2747
2748   for (l = priv->animations; l; l = l->next)
2749     {
2750       AnimationInfo *info;
2751
2752       info = l->data;
2753
2754       /* The animation doesn't need updatring
2755        * the invalidation area, bail out.
2756        */
2757       if (info->invalidation_region)
2758         continue;
2759
2760       if (context_has_animatable_region (context, info->region_id))
2761         {
2762           cairo_rectangle_int_t rect;
2763
2764           rect.x = (gint) x;
2765           rect.y = (gint) y;
2766           rect.width = (gint) width;
2767           rect.height = (gint) height;
2768
2769           g_array_append_val (info->rectangles, rect);
2770         }
2771     }
2772 }
2773
2774 /**
2775  * gtk_style_context_invalidate:
2776  * @context: a #GtkStyleContext.
2777  *
2778  * Invalidates @context style information, so it will be reconstructed
2779  * again. If you're using a #GtkStyleContext returned from
2780  * gtk_widget_get_style_context(), you do not need to call this yourself.
2781  *
2782  * Since: 3.0
2783  **/
2784 void
2785 gtk_style_context_invalidate (GtkStyleContext *context)
2786 {
2787   GtkStyleContextPrivate *priv;
2788
2789   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2790
2791   priv = context->priv;
2792
2793   /* Avoid reentrancy */
2794   if (priv->invalidating_context)
2795     return;
2796
2797   priv->invalidating_context = TRUE;
2798
2799   g_hash_table_remove_all (priv->style_data);
2800   priv->current_data = NULL;
2801
2802   g_signal_emit (context, signals[CHANGED], 0);
2803
2804   priv->invalidating_context = FALSE;
2805 }
2806
2807 /**
2808  * gtk_style_context_set_background:
2809  * @context: a #GtkStyleContext
2810  * @window: a #GdkWindow
2811  *
2812  * Sets the background of @window to the background pattern or
2813  * color specified in @context for its current state.
2814  *
2815  * Since: 3.0
2816  **/
2817 void
2818 gtk_style_context_set_background (GtkStyleContext *context,
2819                                   GdkWindow       *window)
2820 {
2821   GtkStateFlags state;
2822   cairo_pattern_t *pattern;
2823   GdkRGBA *color;
2824
2825   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2826   g_return_if_fail (GDK_IS_WINDOW (window));
2827
2828   state = gtk_style_context_get_state (context);
2829   gtk_style_context_get (context, state,
2830                          "background-image", &pattern,
2831                          NULL);
2832   if (pattern)
2833     {
2834       gdk_window_set_background_pattern (window, pattern);
2835       cairo_pattern_destroy (pattern);
2836       return;
2837     }
2838
2839   gtk_style_context_get (context, state,
2840                          "background-color", &color,
2841                          NULL);
2842   if (color)
2843     {
2844       gdk_window_set_background_rgba (window, color);
2845       gdk_rgba_free (color);
2846     }
2847 }
2848
2849 /* Paint methods */
2850
2851 /**
2852  * gtk_render_check:
2853  * @context: a #GtkStyleContext
2854  * @cr: a #cairo_t
2855  * @x: X origin of the rectangle
2856  * @y: Y origin of the rectangle
2857  * @width: rectangle width
2858  * @height: rectangle height
2859  *
2860  * Renders a checkmark (as in a #GtkCheckButton), the %GTK_STATE_FLAG_ACTIVE
2861  * state will determine whether the check is on or off, and
2862  * %GTK_STATE_FLAG_INCONSISTENT whether it should be marked as undefined.
2863  *
2864  * Since: 3.0
2865  **/
2866 void
2867 gtk_render_check (GtkStyleContext *context,
2868                   cairo_t         *cr,
2869                   gdouble          x,
2870                   gdouble          y,
2871                   gdouble          width,
2872                   gdouble          height)
2873 {
2874   GtkStyleContextPrivate *priv;
2875   GtkThemingEngineClass *engine_class;
2876
2877   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2878   g_return_if_fail (cr != NULL);
2879
2880   priv = context->priv;
2881   engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
2882
2883   store_animation_region (context, x, y, width, height);
2884
2885   _gtk_theming_engine_set_context (priv->theming_engine, context);
2886   engine_class->render_check (priv->theming_engine, cr,
2887                               x, y, width, height);
2888 }
2889
2890 /**
2891  * gtk_render_option:
2892  * @context: a #GtkStyleContext
2893  * @cr: a #cairo_t
2894  * @x: X origin of the rectangle
2895  * @y: Y origin of the rectangle
2896  * @width: rectangle width
2897  * @height: rectangle height
2898  *
2899  * Renders an option mark (as in a #GtkRadioButton), the %GTK_STATE_FLAG_ACTIVE
2900  * state will determine whether the option is on or off, and
2901  * %GTK_STATE_FLAG_INCONSISTENT whether it should be marked as undefined.
2902  *
2903  * Since: 3.0
2904  **/
2905 void
2906 gtk_render_option (GtkStyleContext *context,
2907                    cairo_t         *cr,
2908                    gdouble          x,
2909                    gdouble          y,
2910                    gdouble          width,
2911                    gdouble          height)
2912 {
2913   GtkStyleContextPrivate *priv;
2914   GtkThemingEngineClass *engine_class;
2915
2916   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2917   g_return_if_fail (cr != NULL);
2918
2919   priv = context->priv;
2920   engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
2921
2922   store_animation_region (context, x, y, width, height);
2923
2924   _gtk_theming_engine_set_context (priv->theming_engine, context);
2925   engine_class->render_option (priv->theming_engine, cr,
2926                                x, y, width, height);
2927 }
2928
2929 /**
2930  * gtk_render_arrow:
2931  * @context: a #GtkStyleContext
2932  * @cr: a #cairo_t
2933  * @angle: arrow angle from 0 to 2 * %G_PI, being 0 the arrow pointing to the north
2934  * @x: Center X for the render area
2935  * @y: Center Y for the render area
2936  * @size: square side for render area
2937  *
2938  * Renders an arrow pointing to @angle.
2939  *
2940  * Since: 3.0
2941  **/
2942 void
2943 gtk_render_arrow (GtkStyleContext *context,
2944                   cairo_t         *cr,
2945                   gdouble          angle,
2946                   gdouble          x,
2947                   gdouble          y,
2948                   gdouble          size)
2949 {
2950   GtkStyleContextPrivate *priv;
2951   GtkThemingEngineClass *engine_class;
2952
2953   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2954   g_return_if_fail (cr != NULL);
2955
2956   priv = context->priv;
2957   engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
2958
2959   store_animation_region (context, x, y, size, size);
2960
2961   _gtk_theming_engine_set_context (priv->theming_engine, context);
2962   engine_class->render_arrow (priv->theming_engine, cr,
2963                               angle, x, y, size);
2964 }
2965
2966 /**
2967  * gtk_render_background:
2968  * @context: a #GtkStyleContext
2969  * @cr: a #cairo_t
2970  * @x: X origin of the rectangle
2971  * @y: Y origin of the rectangle
2972  * @width: rectangle width
2973  * @height: rectangle height
2974  *
2975  * Renders the background of an element.
2976  *
2977  * Since: 3.0.
2978  **/
2979 void
2980 gtk_render_background (GtkStyleContext *context,
2981                        cairo_t         *cr,
2982                        gdouble          x,
2983                        gdouble          y,
2984                        gdouble          width,
2985                        gdouble          height)
2986 {
2987   GtkStyleContextPrivate *priv;
2988   GtkThemingEngineClass *engine_class;
2989
2990   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2991   g_return_if_fail (cr != NULL);
2992
2993   priv = context->priv;
2994   engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
2995
2996   store_animation_region (context, x, y, width, height);
2997
2998   _gtk_theming_engine_set_context (priv->theming_engine, context);
2999   engine_class->render_background (priv->theming_engine, cr, x, y, width, height);
3000 }
3001
3002 /**
3003  * gtk_render_frame:
3004  * @context: a #GtkStyleContext
3005  * @cr: a #cairo_t
3006  * @x: X origin of the rectangle
3007  * @y: Y origin of the rectangle
3008  * @width: rectangle width
3009  * @height: rectangle height
3010  *
3011  * Renders a frame around the rectangle defined by @x, @y, @width, @height.
3012  *
3013  * Since: 3.0
3014  **/
3015 void
3016 gtk_render_frame (GtkStyleContext *context,
3017                   cairo_t         *cr,
3018                   gdouble          x,
3019                   gdouble          y,
3020                   gdouble          width,
3021                   gdouble          height)
3022 {
3023   GtkStyleContextPrivate *priv;
3024   GtkThemingEngineClass *engine_class;
3025
3026   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3027   g_return_if_fail (cr != NULL);
3028
3029   priv = context->priv;
3030   engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
3031
3032   store_animation_region (context, x, y, width, height);
3033
3034   _gtk_theming_engine_set_context (priv->theming_engine, context);
3035   engine_class->render_frame (priv->theming_engine, cr, x, y, width, height);
3036 }
3037
3038 /**
3039  * gtk_render_expander:
3040  * @context: a #GtkStyleContext
3041  * @cr: a #cairo_t
3042  * @x: X origin of the rectangle
3043  * @y: Y origin of the rectangle
3044  * @width: rectangle width
3045  * @height: rectangle height
3046  *
3047  * Renders an expander (as used in #GtkTreeView and #GtkExpander) in the area
3048  * defined by @x, @y, @width, @height. The state %GTK_STATE_FLAG_ACTIVE determines
3049  * whether the expander is collapsed or expanded.
3050  *
3051  * Since: 3.0
3052  **/
3053 void
3054 gtk_render_expander (GtkStyleContext *context,
3055                      cairo_t         *cr,
3056                      gdouble          x,
3057                      gdouble          y,
3058                      gdouble          width,
3059                      gdouble          height)
3060 {
3061   GtkStyleContextPrivate *priv;
3062   GtkThemingEngineClass *engine_class;
3063
3064   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3065   g_return_if_fail (cr != NULL);
3066
3067   priv = context->priv;
3068   engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
3069
3070   store_animation_region (context, x, y, width, height);
3071
3072   _gtk_theming_engine_set_context (priv->theming_engine, context);
3073   engine_class->render_expander (priv->theming_engine, cr, x, y, width, height);
3074 }
3075
3076 /**
3077  * gtk_render_focus:
3078  * @context: a #GtkStyleContext
3079  * @cr: a #cairo_t
3080  * @x: X origin of the rectangle
3081  * @y: Y origin of the rectangle
3082  * @width: rectangle width
3083  * @height: rectangle height
3084  *
3085  * Renders a focus indicator on the rectangle determined by @x, @y, @width, @height.
3086  *
3087  * Since: 3.0
3088  **/
3089 void
3090 gtk_render_focus (GtkStyleContext *context,
3091                   cairo_t         *cr,
3092                   gdouble          x,
3093                   gdouble          y,
3094                   gdouble          width,
3095                   gdouble          height)
3096 {
3097   GtkStyleContextPrivate *priv;
3098   GtkThemingEngineClass *engine_class;
3099
3100   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3101   g_return_if_fail (cr != NULL);
3102
3103   priv = context->priv;
3104   engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
3105
3106   store_animation_region (context, x, y, width, height);
3107
3108   _gtk_theming_engine_set_context (priv->theming_engine, context);
3109   engine_class->render_focus (priv->theming_engine, cr, x, y, width, height);
3110 }
3111
3112 /**
3113  * gtk_render_layout:
3114  * @context: a #GtkStyleContext
3115  * @cr: a #cairo_t
3116  * @x: X origin
3117  * @y: Y origin
3118  * @layout: the #PangoLayout to render
3119  *
3120  * Renders @layout on the coordinates @x, @y
3121  *
3122  * Since: 3.0
3123  **/
3124 void
3125 gtk_render_layout (GtkStyleContext *context,
3126                    cairo_t         *cr,
3127                    gdouble          x,
3128                    gdouble          y,
3129                    PangoLayout     *layout)
3130 {
3131   GtkStyleContextPrivate *priv;
3132   GtkThemingEngineClass *engine_class;
3133
3134   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3135   g_return_if_fail (cr != NULL);
3136
3137   priv = context->priv;
3138   engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
3139
3140   _gtk_theming_engine_set_context (priv->theming_engine, context);
3141   engine_class->render_layout (priv->theming_engine, cr, x, y, layout);
3142 }
3143
3144 /**
3145  * gtk_render_line:
3146  * @context: a #GtkStyleContext
3147  * @cr: a #cairo_t
3148  * @x0: X coordinate for the origin of the line
3149  * @y0: Y coordinate for the origin of the line
3150  * @x1: X coordinate for the end of the line
3151  * @y1: Y coordinate for the end of the line
3152  *
3153  * Renders a line from (x0, y0) to (x1, y1).
3154  *
3155  * Since: 3.0
3156  **/
3157 void
3158 gtk_render_line (GtkStyleContext *context,
3159                  cairo_t         *cr,
3160                  gdouble          x0,
3161                  gdouble          y0,
3162                  gdouble          x1,
3163                  gdouble          y1)
3164 {
3165   GtkStyleContextPrivate *priv;
3166   GtkThemingEngineClass *engine_class;
3167
3168   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3169   g_return_if_fail (cr != NULL);
3170
3171   priv = context->priv;
3172   engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
3173
3174   _gtk_theming_engine_set_context (priv->theming_engine, context);
3175   engine_class->render_line (priv->theming_engine, cr, x0, y0, x1, y1);
3176 }
3177
3178 /**
3179  * gtk_render_slider:
3180  * @context: a #GtkStyleContext
3181  * @cr: a #cairo_t
3182  * @x: X origin of the rectangle
3183  * @y: Y origin of the rectangle
3184  * @width: rectangle width
3185  * @height: rectangle height
3186  * @orientation: orientation of the slider
3187  *
3188  * Renders a slider (as in #GtkScale) in the rectangle defined by @x, @y,
3189  * @width, @height. @orientation defines whether the slider is vertical
3190  * or horizontal.
3191  *
3192  * Since: 3.0
3193  **/
3194 void
3195 gtk_render_slider (GtkStyleContext *context,
3196                    cairo_t         *cr,
3197                    gdouble          x,
3198                    gdouble          y,
3199                    gdouble          width,
3200                    gdouble          height,
3201                    GtkOrientation   orientation)
3202 {
3203   GtkStyleContextPrivate *priv;
3204   GtkThemingEngineClass *engine_class;
3205
3206   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3207   g_return_if_fail (cr != NULL);
3208
3209   priv = context->priv;
3210   engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
3211
3212   store_animation_region (context, x, y, width, height);
3213
3214   _gtk_theming_engine_set_context (priv->theming_engine, context);
3215   engine_class->render_slider (priv->theming_engine, cr, x, y, width, height, orientation);
3216 }
3217
3218 /**
3219  * gtk_render_frame_gap:
3220  * @context: a #GtkStyleContext
3221  * @cr: a #cairo_t
3222  * @x: X origin of the rectangle
3223  * @y: Y origin of the rectangle
3224  * @width: rectangle width
3225  * @height: rectangle height
3226  * @gap_side: side where the gap is
3227  * @xy0_gap: initial coordinate (X or Y depending on @gap_side) for the gap
3228  * @xy1_gap: end coordinate (X or Y depending on @gap_side) for the gap
3229  *
3230  * Renders a frame around the rectangle defined by (@x, @y, @width, @height),
3231  * leaving a gap on one side. @xy0_gap and @xy1_gap will mean X coordinates for
3232  * %GTK_POS_TOP and %GTK_POS_BOTTOM gap sides, and Y coordinates for %GTK_POS_LEFT
3233  * and %GTK_POS_RIGHT.
3234  *
3235  * Since: 3.0
3236  **/
3237 void
3238 gtk_render_frame_gap (GtkStyleContext *context,
3239                       cairo_t         *cr,
3240                       gdouble          x,
3241                       gdouble          y,
3242                       gdouble          width,
3243                       gdouble          height,
3244                       GtkPositionType  gap_side,
3245                       gdouble          xy0_gap,
3246                       gdouble          xy1_gap)
3247 {
3248   GtkStyleContextPrivate *priv;
3249   GtkThemingEngineClass *engine_class;
3250
3251   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3252   g_return_if_fail (cr != NULL);
3253
3254   priv = context->priv;
3255   engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
3256
3257   store_animation_region (context, x, y, width, height);
3258
3259   _gtk_theming_engine_set_context (priv->theming_engine, context);
3260   engine_class->render_frame_gap (priv->theming_engine, cr,
3261                                   x, y, width, height, gap_side,
3262                                   xy0_gap, xy1_gap);
3263 }
3264
3265 /**
3266  * gtk_render_extension:
3267  * @context: a #GtkStyleContext
3268  * @cr: a #cairo_t
3269  * @x: X origin of the rectangle
3270  * @y: Y origin of the rectangle
3271  * @width: rectangle width
3272  * @height: rectangle height
3273  * @gap_side: side where the gap is
3274  *
3275  * Renders a extension (as in a #GtkNotebook tab) in the rectangle
3276  * defined by @x, @y, @width, @height. The side where the extension
3277  * connects to is defined by @gap_side.
3278  *
3279  * Since: 3.0
3280  **/
3281 void
3282 gtk_render_extension (GtkStyleContext *context,
3283                       cairo_t         *cr,
3284                       gdouble          x,
3285                       gdouble          y,
3286                       gdouble          width,
3287                       gdouble          height,
3288                       GtkPositionType  gap_side)
3289 {
3290   GtkStyleContextPrivate *priv;
3291   GtkThemingEngineClass *engine_class;
3292
3293   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3294   g_return_if_fail (cr != NULL);
3295
3296   priv = context->priv;
3297   engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
3298
3299   store_animation_region (context, x, y, width, height);
3300
3301   _gtk_theming_engine_set_context (priv->theming_engine, context);
3302   engine_class->render_extension (priv->theming_engine, cr, x, y, width, height, gap_side);
3303 }
3304
3305 /**
3306  * gtk_render_handle:
3307  * @context: a #GtkStyleContext
3308  * @cr: a #cairo_t
3309  * @x: X origin of the rectangle
3310  * @y: Y origin of the rectangle
3311  * @width: rectangle width
3312  * @height: rectangle height
3313  *
3314  * Renders a handle (as in #GtkHandleBox, #GtkPaned and
3315  * #GtkWindow<!-- -->'s resize grip), in the rectangle
3316  * determined by @x, @y, @width, @height.
3317  *
3318  * Since: 3.0
3319  **/
3320 void
3321 gtk_render_handle (GtkStyleContext *context,
3322                    cairo_t         *cr,
3323                    gdouble          x,
3324                    gdouble          y,
3325                    gdouble          width,
3326                    gdouble          height)
3327 {
3328   GtkStyleContextPrivate *priv;
3329   GtkThemingEngineClass *engine_class;
3330
3331   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3332   g_return_if_fail (cr != NULL);
3333
3334   priv = context->priv;
3335   engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
3336
3337   store_animation_region (context, x, y, width, height);
3338
3339   _gtk_theming_engine_set_context (priv->theming_engine, context);
3340   engine_class->render_handle (priv->theming_engine, cr, x, y, width, height);
3341 }
3342
3343 /**
3344  * gtk_render_activity:
3345  * @context: a #GtkStyleContext
3346  * @cr: a #cairo_t
3347  * @x: X origin of the rectangle
3348  * @y: Y origin of the rectangle
3349  * @width: rectangle width
3350  * @height: rectangle height
3351  *
3352  * Renders an activity area (Such as in #GtkSpinner or the
3353  * fill line in #GtkRange), the state %GTK_STATE_FLAG_ACTIVE
3354  * determines whether there is activity going on.
3355  *
3356  * Since: 3.0
3357  **/
3358 void
3359 gtk_render_activity (GtkStyleContext *context,
3360                      cairo_t         *cr,
3361                      gdouble          x,
3362                      gdouble          y,
3363                      gdouble          width,
3364                      gdouble          height)
3365 {
3366   GtkStyleContextPrivate *priv;
3367   GtkThemingEngineClass *engine_class;
3368
3369   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3370   g_return_if_fail (cr != NULL);
3371
3372   priv = context->priv;
3373   engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
3374
3375   store_animation_region (context, x, y, width, height);
3376
3377   _gtk_theming_engine_set_context (priv->theming_engine, context);
3378   engine_class->render_activity (priv->theming_engine, cr, x, y, width, height);
3379 }
3380
3381 /**
3382  * gtk_render_icon_pixbuf:
3383  * @context: a #GtkStyleContext
3384  * @source: the #GtkIconSource specifying the icon to render
3385  * @size: (type int): the size to render the icon at. A size of (GtkIconSize) -1
3386  *        means render at the size of the source and don't scale.
3387  *
3388  * Renders the icon specified by @source at the given @size, returning the result
3389  * in a pixbuf.
3390  *
3391  * Returns: (transfer full): a newly-created #GdkPixbuf containing the rendered icon
3392  *
3393  * Since: 3.0
3394  **/
3395 GdkPixbuf *
3396 gtk_render_icon_pixbuf (GtkStyleContext     *context,
3397                         const GtkIconSource *source,
3398                         GtkIconSize          size)
3399 {
3400   GtkStyleContextPrivate *priv;
3401   GtkThemingEngineClass *engine_class;
3402
3403   g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), NULL);
3404   g_return_val_if_fail (size == -1 || size <= GTK_ICON_SIZE_DIALOG, NULL);
3405   g_return_val_if_fail (source != NULL, NULL);
3406
3407   priv = context->priv;
3408   engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
3409
3410   _gtk_theming_engine_set_context (priv->theming_engine, context);
3411   return engine_class->render_icon_pixbuf (priv->theming_engine, source, size);
3412 }