]> Pileus Git - ~andy/gtk/blob - gtk/gtkstylecontext.c
Add an outline around menu popups
[~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 are 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,
2044                                                      priv->widget_path, pspec,
2045                                                      &pcache->value))
2046             {
2047               /* Resolve symbolic colors to GdkColor/GdkRGBA */
2048               if (G_VALUE_TYPE (&pcache->value) == GTK_TYPE_SYMBOLIC_COLOR)
2049                 {
2050                   GtkSymbolicColor *color;
2051                   GdkRGBA rgba;
2052
2053                   color = g_value_get_boxed (&pcache->value);
2054
2055                   if (gtk_symbolic_color_resolve (color, data->store, &rgba))
2056                     {
2057                       g_value_unset (&pcache->value);
2058
2059                       if (G_PARAM_SPEC_VALUE_TYPE (pspec) == GDK_TYPE_RGBA)
2060                         {
2061                           g_value_init (&pcache->value, GDK_TYPE_RGBA);
2062                           g_value_set_boxed (&pcache->value, &rgba);
2063                         }
2064                       else
2065                         {
2066                           GdkColor rgb;
2067
2068                           rgb.red = rgba.red * 65535. + 0.5;
2069                           rgb.green = rgba.green * 65535. + 0.5;
2070                           rgb.blue = rgba.blue * 65535. + 0.5;
2071
2072                           g_value_init (&pcache->value, GDK_TYPE_COLOR);
2073                           g_value_set_boxed (&pcache->value, &rgb);
2074                         }
2075                     }
2076                   else
2077                     g_param_value_set_default (pspec, &pcache->value);
2078                 }
2079
2080               return &pcache->value;
2081             }
2082         }
2083     }
2084
2085   /* not supplied by any provider, revert to default */
2086   g_param_value_set_default (pspec, &pcache->value);
2087
2088   return &pcache->value;
2089 }
2090
2091 /**
2092  * gtk_style_context_get_style_property:
2093  * @context: a #GtkStyleContext
2094  * @property_name: the name of the widget style property
2095  * @value: (out) (transfer full): Return location for the property value, free with
2096  *         g_value_unset() after use.
2097  *
2098  * Gets the value for a widget style property.
2099  **/
2100 void
2101 gtk_style_context_get_style_property (GtkStyleContext *context,
2102                                       const gchar     *property_name,
2103                                       GValue          *value)
2104 {
2105   GtkStyleContextPrivate *priv;
2106   GtkWidgetClass *widget_class;
2107   GParamSpec *pspec;
2108   const GValue *peek_value;
2109   GType widget_type;
2110
2111   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2112   g_return_if_fail (property_name != NULL);
2113   g_return_if_fail (value != NULL);
2114
2115   priv = context->priv;
2116
2117   if (!priv->widget_path)
2118     return;
2119
2120   widget_type = gtk_widget_path_get_widget_type (priv->widget_path);
2121
2122   widget_class = g_type_class_ref (widget_type);
2123   pspec = gtk_widget_class_find_style_property (widget_class, property_name);
2124   g_type_class_unref (widget_class);
2125
2126   if (!pspec)
2127     {
2128       g_warning ("%s: widget class `%s' has no style property named `%s'",
2129                  G_STRLOC,
2130                  g_type_name (widget_type),
2131                  property_name);
2132       return;
2133     }
2134
2135   peek_value = _gtk_style_context_peek_style_property (context,
2136                                                        widget_type,
2137                                                        pspec);
2138
2139   if (G_VALUE_TYPE (value) == G_VALUE_TYPE (peek_value))
2140     g_value_copy (peek_value, value);
2141   else if (g_value_type_transformable (G_VALUE_TYPE (peek_value), G_VALUE_TYPE (value)))
2142     g_value_transform (peek_value, value);
2143   else
2144     g_warning ("can't retrieve style property `%s' of type `%s' as value of type `%s'",
2145                pspec->name,
2146                G_VALUE_TYPE_NAME (peek_value),
2147                G_VALUE_TYPE_NAME (value));
2148 }
2149
2150 /**
2151  * gtk_style_context_get_style_valist:
2152  * @context: a #GtkStyleContext
2153  * @args: va_list of property name/return location pairs, followed by %NULL
2154  *
2155  * Retrieves several widget style properties from @context according to the
2156  * current style.
2157  *
2158  * Since: 3.0
2159  **/
2160 void
2161 gtk_style_context_get_style_valist (GtkStyleContext *context,
2162                                     va_list          args)
2163 {
2164   GtkStyleContextPrivate *priv;
2165   const gchar *prop_name;
2166
2167   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2168
2169   prop_name = va_arg (args, const gchar *);
2170   priv = context->priv;
2171
2172   if (!priv->widget_path)
2173     return;
2174
2175   while (prop_name)
2176     {
2177       GtkWidgetClass *widget_class;
2178       GParamSpec *pspec;
2179       const GValue *peek_value;
2180       GType widget_type;
2181       gchar *error;
2182
2183       widget_type = gtk_widget_path_get_widget_type (priv->widget_path);
2184
2185       widget_class = g_type_class_ref (widget_type);
2186       pspec = gtk_widget_class_find_style_property (widget_class, prop_name);
2187       g_type_class_unref (widget_class);
2188
2189       if (!pspec)
2190         {
2191           g_warning ("%s: widget class `%s' has no style property named `%s'",
2192                      G_STRLOC,
2193                      g_type_name (widget_type),
2194                      prop_name);
2195           continue;
2196         }
2197
2198       peek_value = _gtk_style_context_peek_style_property (context,
2199                                                            widget_type,
2200                                                            pspec);
2201
2202       G_VALUE_LCOPY (peek_value, args, 0, &error);
2203
2204       if (error)
2205         {
2206           g_warning ("can't retrieve style property `%s' of type `%s': %s",
2207                      pspec->name,
2208                      G_VALUE_TYPE_NAME (peek_value),
2209                      error);
2210           g_free (error);
2211         }
2212
2213       prop_name = va_arg (args, const gchar *);
2214     }
2215 }
2216
2217 /**
2218  * gtk_style_context_get_style:
2219  * @context: a #GtkStyleContext
2220  * @...: property name /return value pairs, followed by %NULL
2221  *
2222  * Retrieves several widget style properties from @context according to the
2223  * current style.
2224  *
2225  * Since: 3.0
2226  **/
2227 void
2228 gtk_style_context_get_style (GtkStyleContext *context,
2229                              ...)
2230 {
2231   va_list args;
2232
2233   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2234
2235   va_start (args, context);
2236   gtk_style_context_get_style_valist (context, args);
2237   va_end (args);
2238 }
2239
2240
2241 /**
2242  * gtk_style_context_lookup_icon_set:
2243  * @context: a #GtkStyleContext
2244  * @stock_id: an icon name
2245  *
2246  * Looks up @stock_id in the icon factories associated to @context and
2247  * the default icon factory, returning an icon set if found, otherwise
2248  * %NULL.
2249  *
2250  * Returns: (transfer none): The looked  up %GtkIconSet, or %NULL
2251  **/
2252 GtkIconSet *
2253 gtk_style_context_lookup_icon_set (GtkStyleContext *context,
2254                                    const gchar     *stock_id)
2255 {
2256   GtkStyleContextPrivate *priv;
2257   StyleData *data;
2258   GSList *list;
2259
2260   g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), NULL);
2261   g_return_val_if_fail (stock_id != NULL, NULL);
2262
2263   priv = context->priv;
2264   g_return_val_if_fail (priv->widget_path != NULL, NULL);
2265
2266   data = style_data_lookup (context);
2267
2268   for (list = data->icon_factories; list; list = list->next)
2269     {
2270       GtkIconFactory *factory;
2271       GtkIconSet *icon_set;
2272
2273       factory = list->data;
2274       icon_set = gtk_icon_factory_lookup (factory, stock_id);
2275
2276       if (icon_set)
2277         return icon_set;
2278     }
2279
2280   return gtk_icon_factory_lookup_default (stock_id);
2281 }
2282
2283 /**
2284  * gtk_style_context_set_screen:
2285  * @context: a #GtkStyleContext
2286  * @screen: a #GdkScreen
2287  *
2288  * Sets the screen to which @context will be attached to, @screen
2289  * is used in order to reconstruct style based on the global providers
2290  * list. If you are using a #GtkStyleContext returned from
2291  * gtk_widget_get_style_context(), you do not need to call this yourself.
2292  *
2293  * Since: 3.0
2294  **/
2295 void
2296 gtk_style_context_set_screen (GtkStyleContext *context,
2297                               GdkScreen       *screen)
2298 {
2299   GtkStyleContextPrivate *priv;
2300
2301   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2302
2303   priv = context->priv;
2304   priv->screen = screen;
2305
2306   g_object_notify (G_OBJECT (context), "screen");
2307
2308   gtk_style_context_invalidate (context);
2309 }
2310
2311 /**
2312  * gtk_style_context_get_screen:
2313  * @context: a #GtkStyleContext
2314  *
2315  * Returns the #GdkScreen to which @context is attached to.
2316  *
2317  * Returns: a #GdkScreen, or %NULL.
2318  **/
2319 GdkScreen *
2320 gtk_style_context_get_screen (GtkStyleContext *context)
2321 {
2322   GtkStyleContextPrivate *priv;
2323
2324   g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), NULL);
2325
2326   priv = context->priv;
2327   return priv->screen;
2328 }
2329
2330 /**
2331  * gtk_style_context_set_direction:
2332  * @context: a #GtkStyleContext
2333  * @direction: the new direction.
2334  *
2335  * Sets the reading direction for rendering purposes. If you are
2336  * using a #GtkStyleContext returned from gtk_widget_get_style_context(),
2337  * you do not need to call this yourself.
2338  *
2339  * Since: 3.0
2340  **/
2341 void
2342 gtk_style_context_set_direction (GtkStyleContext  *context,
2343                                  GtkTextDirection  direction)
2344 {
2345   GtkStyleContextPrivate *priv;
2346
2347   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2348
2349   priv = context->priv;
2350   priv->direction = direction;
2351
2352   g_object_notify (G_OBJECT (context), "direction");
2353 }
2354
2355 /**
2356  * gtk_style_context_get_direction:
2357  * @context: a #GtkStyleContext
2358  *
2359  * Returns the widget direction used for rendering.
2360  *
2361  * Returns: the widget direction
2362  *
2363  * Since: 3.0
2364  **/
2365 GtkTextDirection
2366 gtk_style_context_get_direction (GtkStyleContext *context)
2367 {
2368   GtkStyleContextPrivate *priv;
2369
2370   g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), GTK_TEXT_DIR_LTR);
2371
2372   priv = context->priv;
2373   return priv->direction;
2374 }
2375
2376 /**
2377  * gtk_style_context_set_junction_sides:
2378  * @context: a #GtkStyleContext
2379  * @sides: sides where rendered elements are visually connected to other elements.
2380  *
2381  * Sets the sides where rendered elements (mostly through gtk_render_frame()) will
2382  * visually connect with other visual elements. This is merely a guideline that may
2383  * be honored or not in theming engines.
2384  *
2385  * Since: 3.0
2386  **/
2387 void
2388 gtk_style_context_set_junction_sides (GtkStyleContext  *context,
2389                                       GtkJunctionSides  sides)
2390 {
2391   GtkStyleContextPrivate *priv;
2392   GtkStyleInfo *info;
2393
2394   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2395
2396   priv = context->priv;
2397   info = priv->info_stack->data;
2398   info->junction_sides = sides;
2399 }
2400
2401 /**
2402  * gtk_style_context_get_junction_sides:
2403  * @context: a #GtkStyleContext
2404  *
2405  * Returns the sides where rendered elements connect visually with others.
2406  *
2407  * Returns: the junction sides
2408  *
2409  * Since: 3.0
2410  **/
2411 GtkJunctionSides
2412 gtk_style_context_get_junction_sides (GtkStyleContext *context)
2413 {
2414   GtkStyleContextPrivate *priv;
2415   GtkStyleInfo *info;
2416
2417   g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), 0);
2418
2419   priv = context->priv;
2420   info = priv->info_stack->data;
2421   return info->junction_sides;
2422 }
2423
2424 /**
2425  * gtk_style_context_lookup_color:
2426  * @context: a #GtkStyleContext
2427  * @color_name: color name to lookup
2428  * @color: (out): Return location for the looked up color
2429  *
2430  * Looks up and resolves a color name in the @context color map.
2431  *
2432  * Returns: %TRUE if @color_name was found and resolved, %FALSE otherwise
2433  **/
2434 gboolean
2435 gtk_style_context_lookup_color (GtkStyleContext *context,
2436                                 const gchar     *color_name,
2437                                 GdkRGBA         *color)
2438 {
2439   GtkStyleContextPrivate *priv;
2440   GtkSymbolicColor *sym_color;
2441   StyleData *data;
2442
2443   g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), FALSE);
2444   g_return_val_if_fail (color_name != NULL, FALSE);
2445   g_return_val_if_fail (color != NULL, FALSE);
2446
2447   priv = context->priv;
2448   g_return_val_if_fail (priv->widget_path != NULL, FALSE);
2449
2450   data = style_data_lookup (context);
2451   sym_color = gtk_style_properties_lookup_color (data->store, color_name);
2452
2453   if (!sym_color)
2454     return FALSE;
2455
2456   return gtk_symbolic_color_resolve (sym_color, data->store, color);
2457 }
2458
2459 /**
2460  * gtk_style_context_notify_state_change:
2461  * @context: a #GtkStyleContext
2462  * @window: a #GdkWindow
2463  * @region_id: (allow-none): animatable region to notify on, or %NULL.
2464  *             See gtk_style_context_push_animatable_region()
2465  * @state: state to trigger transition for
2466  * @state_value: target value of @state
2467  *
2468  * Notifies a state change on @context, so if the current style makes use
2469  * of transition animations, one will be started so all rendered elements
2470  * under @region_id are animated for state @state being set to value @state_value.
2471  *
2472  * The @window parameter is used in order to invalidate the rendered area
2473  * as the animation runs, so make sure it is the same window that is being
2474  * rendered on by the gtk_render_*() methods.
2475  *
2476  * If @region_id is %NULL, all rendered elements using @context will be
2477  * affected by this state transition.
2478  *
2479  * As a practical example, a #GtkButton notifying a state transition on
2480  * the prelight state:
2481  * <programlisting>
2482  * gtk_style_context_notify_state_change (context,
2483  *                                        gtk_widget_get_window (widget),
2484  *                                        NULL, GTK_STATE_PRELIGHT,
2485  *                                        button->in_button);
2486  * </programlisting>
2487  *
2488  * Could be handled in the CSS file like this:
2489  * <programlisting>
2490  * GtkButton {
2491  *     background-color: #f00;
2492  * }
2493  *
2494  * GtkButton:hover {
2495  *     background-color: #fff;
2496  *     transition: 200ms linear;
2497  * }
2498  * </programlisting>
2499  *
2500  * This combination would animate the button background from red to white
2501  * if a pointer enters the button, and back to red if the pointer leaves
2502  * the button.
2503  *
2504  * Since: 3.0
2505  **/
2506 void
2507 gtk_style_context_notify_state_change (GtkStyleContext *context,
2508                                        GdkWindow       *window,
2509                                        gpointer         region_id,
2510                                        GtkStateType     state,
2511                                        gboolean         state_value)
2512 {
2513   GtkStyleContextPrivate *priv;
2514   GtkAnimationDescription *desc;
2515   AnimationInfo *info;
2516   GtkStateFlags flags;
2517   StyleData *data;
2518
2519   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2520   g_return_if_fail (GDK_IS_WINDOW (window));
2521   g_return_if_fail (state > GTK_STATE_NORMAL && state <= GTK_STATE_FOCUSED);
2522
2523   priv = context->priv;
2524   g_return_if_fail (priv->widget_path != NULL);
2525
2526   state_value = (state_value == TRUE);
2527
2528   switch (state)
2529     {
2530     case GTK_STATE_ACTIVE:
2531       flags = GTK_STATE_FLAG_ACTIVE;
2532       break;
2533     case GTK_STATE_PRELIGHT:
2534       flags = GTK_STATE_FLAG_PRELIGHT;
2535       break;
2536     case GTK_STATE_SELECTED:
2537       flags = GTK_STATE_FLAG_SELECTED;
2538       break;
2539     case GTK_STATE_INSENSITIVE:
2540       flags = GTK_STATE_FLAG_INSENSITIVE;
2541       break;
2542     case GTK_STATE_INCONSISTENT:
2543       flags = GTK_STATE_FLAG_INCONSISTENT;
2544       break;
2545     case GTK_STATE_FOCUSED:
2546       flags = GTK_STATE_FLAG_FOCUSED;
2547       break;
2548     case GTK_STATE_NORMAL:
2549     default:
2550       flags = 0;
2551       break;
2552     }
2553
2554   /* Find out if there is any animation description for the given
2555    * state, it will fallback to the normal state as well if necessary.
2556    */
2557   data = style_data_lookup (context);
2558   gtk_style_properties_get (data->store, flags,
2559                             "transition", &desc,
2560                             NULL);
2561
2562   if (!desc)
2563     return;
2564
2565   if (gtk_animation_description_get_duration (desc) == 0)
2566     {
2567       gtk_animation_description_unref (desc);
2568       return;
2569     }
2570
2571   info = animation_info_lookup (context, region_id, state);
2572
2573   if (info &&
2574       info->target_value != state_value)
2575     {
2576       /* Target values are the opposite */
2577       if (!gtk_timeline_get_loop (info->timeline))
2578         {
2579           /* Reverse the animation */
2580           if (gtk_timeline_get_direction (info->timeline) == GTK_TIMELINE_DIRECTION_FORWARD)
2581             gtk_timeline_set_direction (info->timeline, GTK_TIMELINE_DIRECTION_BACKWARD);
2582           else
2583             gtk_timeline_set_direction (info->timeline, GTK_TIMELINE_DIRECTION_FORWARD);
2584
2585           info->target_value = state_value;
2586         }
2587       else
2588         {
2589           /* Take it out of its looping state */
2590           gtk_timeline_set_loop (info->timeline, FALSE);
2591         }
2592     }
2593   else if (!info)
2594     {
2595       info = animation_info_new (context, region_id,
2596                                  gtk_animation_description_get_duration (desc),
2597                                  gtk_animation_description_get_progress_type (desc),
2598                                  gtk_animation_description_get_loop (desc),
2599                                  state, state_value, window);
2600
2601       priv->animations = g_slist_prepend (priv->animations, info);
2602       priv->animations_invalidated = TRUE;
2603     }
2604
2605   gtk_animation_description_unref (desc);
2606 }
2607
2608 /**
2609  * gtk_style_context_push_animatable_region:
2610  * @context: a #GtkStyleContext
2611  * @region_id: unique identifier for the animatable region
2612  *
2613  * Pushes an animatable region, so all further gtk_render_*() calls between
2614  * this call and the following gtk_style_context_pop_animatable_region() will
2615  * potentially show transition animations for if gtk_style_context_notify_state_change()
2616  * is called for a given state, and the theme/style used contemplates the use of
2617  * transition animations for state changes.
2618  *
2619  * The @region_id used must be unique in @context so the theming engine may
2620  * univocally identify rendered elements subject to a state transition.
2621  *
2622  * Since: 3.0
2623  **/
2624 void
2625 gtk_style_context_push_animatable_region (GtkStyleContext *context,
2626                                           gpointer         region_id)
2627 {
2628   GtkStyleContextPrivate *priv;
2629
2630   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2631   g_return_if_fail (region_id != NULL);
2632
2633   priv = context->priv;
2634   priv->animation_regions = g_slist_prepend (priv->animation_regions, region_id);
2635 }
2636
2637 /**
2638  * gtk_style_context_pop_animatable_region:
2639  * @context: a #GtkStyleContext
2640  *
2641  * Pops an animatable region from @context. See gtk_style_context_push_animatable_region().
2642  *
2643  * Since: 3.0
2644  **/
2645 void
2646 gtk_style_context_pop_animatable_region (GtkStyleContext *context)
2647 {
2648   GtkStyleContextPrivate *priv;
2649
2650   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2651
2652   priv = context->priv;
2653   priv->animation_regions = g_slist_delete_link (priv->animation_regions,
2654                                                  priv->animation_regions);
2655 }
2656
2657 void
2658 _gtk_style_context_invalidate_animation_areas (GtkStyleContext *context)
2659 {
2660   GtkStyleContextPrivate *priv;
2661   GSList *l;
2662
2663   priv = context->priv;
2664
2665   for (l = priv->animations; l; l = l->next)
2666     {
2667       AnimationInfo *info;
2668
2669       info = l->data;
2670
2671       /* A NULL invalidation region means it has to be recreated on
2672        * the next expose event, this happens usually after a widget
2673        * allocation change, so the next expose after it will update
2674        * the invalidation region.
2675        */
2676       if (info->invalidation_region)
2677         {
2678           cairo_region_destroy (info->invalidation_region);
2679           info->invalidation_region = NULL;
2680         }
2681     }
2682
2683   priv->animations_invalidated = TRUE;
2684 }
2685
2686 void
2687 _gtk_style_context_coalesce_animation_areas (GtkStyleContext *context,
2688                                              gint             rel_x,
2689                                              gint             rel_y)
2690 {
2691   GtkStyleContextPrivate *priv;
2692   GSList *l;
2693
2694   priv = context->priv;
2695
2696   if (!priv->animations_invalidated)
2697     return;
2698
2699   for (l = priv->animations; l; l = l->next)
2700     {
2701       AnimationInfo *info;
2702       guint i;
2703
2704       info = l->data;
2705
2706       if (info->invalidation_region)
2707         continue;
2708
2709       /* FIXME: If this happens there's not much
2710        * point in keeping the animation running.
2711        */
2712       if (info->rectangles->len == 0)
2713         continue;
2714
2715       info->invalidation_region = cairo_region_create ();
2716
2717       for (i = 0; i <info->rectangles->len; i++)
2718         {
2719           cairo_rectangle_int_t *rect;
2720
2721           rect = &g_array_index (info->rectangles, cairo_rectangle_int_t, i);
2722           rect->x += rel_x;
2723           rect->y += rel_y;
2724
2725           cairo_region_union_rectangle (info->invalidation_region, rect);
2726         }
2727
2728       g_array_remove_range (info->rectangles, 0, info->rectangles->len);
2729     }
2730
2731   priv->animations_invalidated = FALSE;
2732 }
2733
2734 static void
2735 store_animation_region (GtkStyleContext *context,
2736                         gdouble          x,
2737                         gdouble          y,
2738                         gdouble          width,
2739                         gdouble          height)
2740 {
2741   GtkStyleContextPrivate *priv;
2742   GSList *l;
2743
2744   priv = context->priv;
2745
2746   if (!priv->animations_invalidated)
2747     return;
2748
2749   for (l = priv->animations; l; l = l->next)
2750     {
2751       AnimationInfo *info;
2752
2753       info = l->data;
2754
2755       /* The animation doesn't need updatring
2756        * the invalidation area, bail out.
2757        */
2758       if (info->invalidation_region)
2759         continue;
2760
2761       if (context_has_animatable_region (context, info->region_id))
2762         {
2763           cairo_rectangle_int_t rect;
2764
2765           rect.x = (gint) x;
2766           rect.y = (gint) y;
2767           rect.width = (gint) width;
2768           rect.height = (gint) height;
2769
2770           g_array_append_val (info->rectangles, rect);
2771         }
2772     }
2773 }
2774
2775 /**
2776  * gtk_style_context_invalidate:
2777  * @context: a #GtkStyleContext.
2778  *
2779  * Invalidates @context style information, so it will be reconstructed
2780  * again. If you're using a #GtkStyleContext returned from
2781  * gtk_widget_get_style_context(), you do not need to call this yourself.
2782  *
2783  * Since: 3.0
2784  **/
2785 void
2786 gtk_style_context_invalidate (GtkStyleContext *context)
2787 {
2788   GtkStyleContextPrivate *priv;
2789
2790   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2791
2792   priv = context->priv;
2793
2794   /* Avoid reentrancy */
2795   if (priv->invalidating_context)
2796     return;
2797
2798   priv->invalidating_context = TRUE;
2799
2800   g_hash_table_remove_all (priv->style_data);
2801   priv->current_data = NULL;
2802
2803   g_signal_emit (context, signals[CHANGED], 0);
2804
2805   priv->invalidating_context = FALSE;
2806 }
2807
2808 /**
2809  * gtk_style_context_set_background:
2810  * @context: a #GtkStyleContext
2811  * @window: a #GdkWindow
2812  *
2813  * Sets the background of @window to the background pattern or
2814  * color specified in @context for its current state.
2815  *
2816  * Since: 3.0
2817  **/
2818 void
2819 gtk_style_context_set_background (GtkStyleContext *context,
2820                                   GdkWindow       *window)
2821 {
2822   GtkStateFlags state;
2823   cairo_pattern_t *pattern;
2824   GdkRGBA *color;
2825
2826   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2827   g_return_if_fail (GDK_IS_WINDOW (window));
2828
2829   state = gtk_style_context_get_state (context);
2830   gtk_style_context_get (context, state,
2831                          "background-image", &pattern,
2832                          NULL);
2833   if (pattern)
2834     {
2835       gdk_window_set_background_pattern (window, pattern);
2836       cairo_pattern_destroy (pattern);
2837       return;
2838     }
2839
2840   gtk_style_context_get (context, state,
2841                          "background-color", &color,
2842                          NULL);
2843   if (color)
2844     {
2845       gdk_window_set_background_rgba (window, color);
2846       gdk_rgba_free (color);
2847     }
2848 }
2849
2850 /* Paint methods */
2851
2852 /**
2853  * gtk_render_check:
2854  * @context: a #GtkStyleContext
2855  * @cr: a #cairo_t
2856  * @x: X origin of the rectangle
2857  * @y: Y origin of the rectangle
2858  * @width: rectangle width
2859  * @height: rectangle height
2860  *
2861  * Renders a checkmark (as in a #GtkCheckButton), the %GTK_STATE_FLAG_ACTIVE
2862  * state will determine whether the check is on or off, and
2863  * %GTK_STATE_FLAG_INCONSISTENT whether it should be marked as undefined.
2864  *
2865  * Since: 3.0
2866  **/
2867 void
2868 gtk_render_check (GtkStyleContext *context,
2869                   cairo_t         *cr,
2870                   gdouble          x,
2871                   gdouble          y,
2872                   gdouble          width,
2873                   gdouble          height)
2874 {
2875   GtkStyleContextPrivate *priv;
2876   GtkThemingEngineClass *engine_class;
2877
2878   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2879   g_return_if_fail (cr != NULL);
2880
2881   priv = context->priv;
2882   engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
2883
2884   store_animation_region (context, x, y, width, height);
2885
2886   _gtk_theming_engine_set_context (priv->theming_engine, context);
2887   engine_class->render_check (priv->theming_engine, cr,
2888                               x, y, width, height);
2889 }
2890
2891 /**
2892  * gtk_render_option:
2893  * @context: a #GtkStyleContext
2894  * @cr: a #cairo_t
2895  * @x: X origin of the rectangle
2896  * @y: Y origin of the rectangle
2897  * @width: rectangle width
2898  * @height: rectangle height
2899  *
2900  * Renders an option mark (as in a #GtkRadioButton), the %GTK_STATE_FLAG_ACTIVE
2901  * state will determine whether the option is on or off, and
2902  * %GTK_STATE_FLAG_INCONSISTENT whether it should be marked as undefined.
2903  *
2904  * Since: 3.0
2905  **/
2906 void
2907 gtk_render_option (GtkStyleContext *context,
2908                    cairo_t         *cr,
2909                    gdouble          x,
2910                    gdouble          y,
2911                    gdouble          width,
2912                    gdouble          height)
2913 {
2914   GtkStyleContextPrivate *priv;
2915   GtkThemingEngineClass *engine_class;
2916
2917   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2918   g_return_if_fail (cr != NULL);
2919
2920   priv = context->priv;
2921   engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
2922
2923   store_animation_region (context, x, y, width, height);
2924
2925   _gtk_theming_engine_set_context (priv->theming_engine, context);
2926   engine_class->render_option (priv->theming_engine, cr,
2927                                x, y, width, height);
2928 }
2929
2930 /**
2931  * gtk_render_arrow:
2932  * @context: a #GtkStyleContext
2933  * @cr: a #cairo_t
2934  * @angle: arrow angle from 0 to 2 * %G_PI, being 0 the arrow pointing to the north
2935  * @x: Center X for the render area
2936  * @y: Center Y for the render area
2937  * @size: square side for render area
2938  *
2939  * Renders an arrow pointing to @angle.
2940  *
2941  * Since: 3.0
2942  **/
2943 void
2944 gtk_render_arrow (GtkStyleContext *context,
2945                   cairo_t         *cr,
2946                   gdouble          angle,
2947                   gdouble          x,
2948                   gdouble          y,
2949                   gdouble          size)
2950 {
2951   GtkStyleContextPrivate *priv;
2952   GtkThemingEngineClass *engine_class;
2953
2954   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2955   g_return_if_fail (cr != NULL);
2956
2957   priv = context->priv;
2958   engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
2959
2960   store_animation_region (context, x, y, size, size);
2961
2962   _gtk_theming_engine_set_context (priv->theming_engine, context);
2963   engine_class->render_arrow (priv->theming_engine, cr,
2964                               angle, x, y, size);
2965 }
2966
2967 /**
2968  * gtk_render_background:
2969  * @context: a #GtkStyleContext
2970  * @cr: a #cairo_t
2971  * @x: X origin of the rectangle
2972  * @y: Y origin of the rectangle
2973  * @width: rectangle width
2974  * @height: rectangle height
2975  *
2976  * Renders the background of an element.
2977  *
2978  * Since: 3.0.
2979  **/
2980 void
2981 gtk_render_background (GtkStyleContext *context,
2982                        cairo_t         *cr,
2983                        gdouble          x,
2984                        gdouble          y,
2985                        gdouble          width,
2986                        gdouble          height)
2987 {
2988   GtkStyleContextPrivate *priv;
2989   GtkThemingEngineClass *engine_class;
2990
2991   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2992   g_return_if_fail (cr != NULL);
2993
2994   priv = context->priv;
2995   engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
2996
2997   store_animation_region (context, x, y, width, height);
2998
2999   _gtk_theming_engine_set_context (priv->theming_engine, context);
3000   engine_class->render_background (priv->theming_engine, cr, x, y, width, height);
3001 }
3002
3003 /**
3004  * gtk_render_frame:
3005  * @context: a #GtkStyleContext
3006  * @cr: a #cairo_t
3007  * @x: X origin of the rectangle
3008  * @y: Y origin of the rectangle
3009  * @width: rectangle width
3010  * @height: rectangle height
3011  *
3012  * Renders a frame around the rectangle defined by @x, @y, @width, @height.
3013  *
3014  * Since: 3.0
3015  **/
3016 void
3017 gtk_render_frame (GtkStyleContext *context,
3018                   cairo_t         *cr,
3019                   gdouble          x,
3020                   gdouble          y,
3021                   gdouble          width,
3022                   gdouble          height)
3023 {
3024   GtkStyleContextPrivate *priv;
3025   GtkThemingEngineClass *engine_class;
3026
3027   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3028   g_return_if_fail (cr != NULL);
3029
3030   priv = context->priv;
3031   engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
3032
3033   store_animation_region (context, x, y, width, height);
3034
3035   _gtk_theming_engine_set_context (priv->theming_engine, context);
3036   engine_class->render_frame (priv->theming_engine, cr, x, y, width, height);
3037 }
3038
3039 /**
3040  * gtk_render_expander:
3041  * @context: a #GtkStyleContext
3042  * @cr: a #cairo_t
3043  * @x: X origin of the rectangle
3044  * @y: Y origin of the rectangle
3045  * @width: rectangle width
3046  * @height: rectangle height
3047  *
3048  * Renders an expander (as used in #GtkTreeView and #GtkExpander) in the area
3049  * defined by @x, @y, @width, @height. The state %GTK_STATE_FLAG_ACTIVE determines
3050  * whether the expander is collapsed or expanded.
3051  *
3052  * Since: 3.0
3053  **/
3054 void
3055 gtk_render_expander (GtkStyleContext *context,
3056                      cairo_t         *cr,
3057                      gdouble          x,
3058                      gdouble          y,
3059                      gdouble          width,
3060                      gdouble          height)
3061 {
3062   GtkStyleContextPrivate *priv;
3063   GtkThemingEngineClass *engine_class;
3064
3065   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3066   g_return_if_fail (cr != NULL);
3067
3068   priv = context->priv;
3069   engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
3070
3071   store_animation_region (context, x, y, width, height);
3072
3073   _gtk_theming_engine_set_context (priv->theming_engine, context);
3074   engine_class->render_expander (priv->theming_engine, cr, x, y, width, height);
3075 }
3076
3077 /**
3078  * gtk_render_focus:
3079  * @context: a #GtkStyleContext
3080  * @cr: a #cairo_t
3081  * @x: X origin of the rectangle
3082  * @y: Y origin of the rectangle
3083  * @width: rectangle width
3084  * @height: rectangle height
3085  *
3086  * Renders a focus indicator on the rectangle determined by @x, @y, @width, @height.
3087  *
3088  * Since: 3.0
3089  **/
3090 void
3091 gtk_render_focus (GtkStyleContext *context,
3092                   cairo_t         *cr,
3093                   gdouble          x,
3094                   gdouble          y,
3095                   gdouble          width,
3096                   gdouble          height)
3097 {
3098   GtkStyleContextPrivate *priv;
3099   GtkThemingEngineClass *engine_class;
3100
3101   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3102   g_return_if_fail (cr != NULL);
3103
3104   priv = context->priv;
3105   engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
3106
3107   store_animation_region (context, x, y, width, height);
3108
3109   _gtk_theming_engine_set_context (priv->theming_engine, context);
3110   engine_class->render_focus (priv->theming_engine, cr, x, y, width, height);
3111 }
3112
3113 /**
3114  * gtk_render_layout:
3115  * @context: a #GtkStyleContext
3116  * @cr: a #cairo_t
3117  * @x: X origin
3118  * @y: Y origin
3119  * @layout: the #PangoLayout to render
3120  *
3121  * Renders @layout on the coordinates @x, @y
3122  *
3123  * Since: 3.0
3124  **/
3125 void
3126 gtk_render_layout (GtkStyleContext *context,
3127                    cairo_t         *cr,
3128                    gdouble          x,
3129                    gdouble          y,
3130                    PangoLayout     *layout)
3131 {
3132   GtkStyleContextPrivate *priv;
3133   GtkThemingEngineClass *engine_class;
3134
3135   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3136   g_return_if_fail (cr != NULL);
3137
3138   priv = context->priv;
3139   engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
3140
3141   _gtk_theming_engine_set_context (priv->theming_engine, context);
3142   engine_class->render_layout (priv->theming_engine, cr, x, y, layout);
3143 }
3144
3145 /**
3146  * gtk_render_line:
3147  * @context: a #GtkStyleContext
3148  * @cr: a #cairo_t
3149  * @x0: X coordinate for the origin of the line
3150  * @y0: Y coordinate for the origin of the line
3151  * @x1: X coordinate for the end of the line
3152  * @y1: Y coordinate for the end of the line
3153  *
3154  * Renders a line from (x0, y0) to (x1, y1).
3155  *
3156  * Since: 3.0
3157  **/
3158 void
3159 gtk_render_line (GtkStyleContext *context,
3160                  cairo_t         *cr,
3161                  gdouble          x0,
3162                  gdouble          y0,
3163                  gdouble          x1,
3164                  gdouble          y1)
3165 {
3166   GtkStyleContextPrivate *priv;
3167   GtkThemingEngineClass *engine_class;
3168
3169   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3170   g_return_if_fail (cr != NULL);
3171
3172   priv = context->priv;
3173   engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
3174
3175   _gtk_theming_engine_set_context (priv->theming_engine, context);
3176   engine_class->render_line (priv->theming_engine, cr, x0, y0, x1, y1);
3177 }
3178
3179 /**
3180  * gtk_render_slider:
3181  * @context: a #GtkStyleContext
3182  * @cr: a #cairo_t
3183  * @x: X origin of the rectangle
3184  * @y: Y origin of the rectangle
3185  * @width: rectangle width
3186  * @height: rectangle height
3187  * @orientation: orientation of the slider
3188  *
3189  * Renders a slider (as in #GtkScale) in the rectangle defined by @x, @y,
3190  * @width, @height. @orientation defines whether the slider is vertical
3191  * or horizontal.
3192  *
3193  * Since: 3.0
3194  **/
3195 void
3196 gtk_render_slider (GtkStyleContext *context,
3197                    cairo_t         *cr,
3198                    gdouble          x,
3199                    gdouble          y,
3200                    gdouble          width,
3201                    gdouble          height,
3202                    GtkOrientation   orientation)
3203 {
3204   GtkStyleContextPrivate *priv;
3205   GtkThemingEngineClass *engine_class;
3206
3207   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3208   g_return_if_fail (cr != NULL);
3209
3210   priv = context->priv;
3211   engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
3212
3213   store_animation_region (context, x, y, width, height);
3214
3215   _gtk_theming_engine_set_context (priv->theming_engine, context);
3216   engine_class->render_slider (priv->theming_engine, cr, x, y, width, height, orientation);
3217 }
3218
3219 /**
3220  * gtk_render_frame_gap:
3221  * @context: a #GtkStyleContext
3222  * @cr: a #cairo_t
3223  * @x: X origin of the rectangle
3224  * @y: Y origin of the rectangle
3225  * @width: rectangle width
3226  * @height: rectangle height
3227  * @gap_side: side where the gap is
3228  * @xy0_gap: initial coordinate (X or Y depending on @gap_side) for the gap
3229  * @xy1_gap: end coordinate (X or Y depending on @gap_side) for the gap
3230  *
3231  * Renders a frame around the rectangle defined by (@x, @y, @width, @height),
3232  * leaving a gap on one side. @xy0_gap and @xy1_gap will mean X coordinates for
3233  * %GTK_POS_TOP and %GTK_POS_BOTTOM gap sides, and Y coordinates for %GTK_POS_LEFT
3234  * and %GTK_POS_RIGHT.
3235  *
3236  * Since: 3.0
3237  **/
3238 void
3239 gtk_render_frame_gap (GtkStyleContext *context,
3240                       cairo_t         *cr,
3241                       gdouble          x,
3242                       gdouble          y,
3243                       gdouble          width,
3244                       gdouble          height,
3245                       GtkPositionType  gap_side,
3246                       gdouble          xy0_gap,
3247                       gdouble          xy1_gap)
3248 {
3249   GtkStyleContextPrivate *priv;
3250   GtkThemingEngineClass *engine_class;
3251
3252   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3253   g_return_if_fail (cr != NULL);
3254
3255   priv = context->priv;
3256   engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
3257
3258   store_animation_region (context, x, y, width, height);
3259
3260   _gtk_theming_engine_set_context (priv->theming_engine, context);
3261   engine_class->render_frame_gap (priv->theming_engine, cr,
3262                                   x, y, width, height, gap_side,
3263                                   xy0_gap, xy1_gap);
3264 }
3265
3266 /**
3267  * gtk_render_extension:
3268  * @context: a #GtkStyleContext
3269  * @cr: a #cairo_t
3270  * @x: X origin of the rectangle
3271  * @y: Y origin of the rectangle
3272  * @width: rectangle width
3273  * @height: rectangle height
3274  * @gap_side: side where the gap is
3275  *
3276  * Renders a extension (as in a #GtkNotebook tab) in the rectangle
3277  * defined by @x, @y, @width, @height. The side where the extension
3278  * connects to is defined by @gap_side.
3279  *
3280  * Since: 3.0
3281  **/
3282 void
3283 gtk_render_extension (GtkStyleContext *context,
3284                       cairo_t         *cr,
3285                       gdouble          x,
3286                       gdouble          y,
3287                       gdouble          width,
3288                       gdouble          height,
3289                       GtkPositionType  gap_side)
3290 {
3291   GtkStyleContextPrivate *priv;
3292   GtkThemingEngineClass *engine_class;
3293
3294   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3295   g_return_if_fail (cr != NULL);
3296
3297   priv = context->priv;
3298   engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
3299
3300   store_animation_region (context, x, y, width, height);
3301
3302   _gtk_theming_engine_set_context (priv->theming_engine, context);
3303   engine_class->render_extension (priv->theming_engine, cr, x, y, width, height, gap_side);
3304 }
3305
3306 /**
3307  * gtk_render_handle:
3308  * @context: a #GtkStyleContext
3309  * @cr: a #cairo_t
3310  * @x: X origin of the rectangle
3311  * @y: Y origin of the rectangle
3312  * @width: rectangle width
3313  * @height: rectangle height
3314  *
3315  * Renders a handle (as in #GtkHandleBox, #GtkPaned and
3316  * #GtkWindow<!-- -->'s resize grip), in the rectangle
3317  * determined by @x, @y, @width, @height.
3318  *
3319  * Since: 3.0
3320  **/
3321 void
3322 gtk_render_handle (GtkStyleContext *context,
3323                    cairo_t         *cr,
3324                    gdouble          x,
3325                    gdouble          y,
3326                    gdouble          width,
3327                    gdouble          height)
3328 {
3329   GtkStyleContextPrivate *priv;
3330   GtkThemingEngineClass *engine_class;
3331
3332   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3333   g_return_if_fail (cr != NULL);
3334
3335   priv = context->priv;
3336   engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
3337
3338   store_animation_region (context, x, y, width, height);
3339
3340   _gtk_theming_engine_set_context (priv->theming_engine, context);
3341   engine_class->render_handle (priv->theming_engine, cr, x, y, width, height);
3342 }
3343
3344 /**
3345  * gtk_render_activity:
3346  * @context: a #GtkStyleContext
3347  * @cr: a #cairo_t
3348  * @x: X origin of the rectangle
3349  * @y: Y origin of the rectangle
3350  * @width: rectangle width
3351  * @height: rectangle height
3352  *
3353  * Renders an activity area (Such as in #GtkSpinner or the
3354  * fill line in #GtkRange), the state %GTK_STATE_FLAG_ACTIVE
3355  * determines whether there is activity going on.
3356  *
3357  * Since: 3.0
3358  **/
3359 void
3360 gtk_render_activity (GtkStyleContext *context,
3361                      cairo_t         *cr,
3362                      gdouble          x,
3363                      gdouble          y,
3364                      gdouble          width,
3365                      gdouble          height)
3366 {
3367   GtkStyleContextPrivate *priv;
3368   GtkThemingEngineClass *engine_class;
3369
3370   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3371   g_return_if_fail (cr != NULL);
3372
3373   priv = context->priv;
3374   engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
3375
3376   store_animation_region (context, x, y, width, height);
3377
3378   _gtk_theming_engine_set_context (priv->theming_engine, context);
3379   engine_class->render_activity (priv->theming_engine, cr, x, y, width, height);
3380 }
3381
3382 /**
3383  * gtk_render_icon_pixbuf:
3384  * @context: a #GtkStyleContext
3385  * @source: the #GtkIconSource specifying the icon to render
3386  * @size: (type int): the size to render the icon at. A size of (GtkIconSize) -1
3387  *        means render at the size of the source and don't scale.
3388  *
3389  * Renders the icon specified by @source at the given @size, returning the result
3390  * in a pixbuf.
3391  *
3392  * Returns: (transfer full): a newly-created #GdkPixbuf containing the rendered icon
3393  *
3394  * Since: 3.0
3395  **/
3396 GdkPixbuf *
3397 gtk_render_icon_pixbuf (GtkStyleContext     *context,
3398                         const GtkIconSource *source,
3399                         GtkIconSize          size)
3400 {
3401   GtkStyleContextPrivate *priv;
3402   GtkThemingEngineClass *engine_class;
3403
3404   g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), NULL);
3405   g_return_val_if_fail (size == -1 || size <= GTK_ICON_SIZE_DIALOG, NULL);
3406   g_return_val_if_fail (source != NULL, NULL);
3407
3408   priv = context->priv;
3409   engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
3410
3411   _gtk_theming_engine_set_context (priv->theming_engine, context);
3412   return engine_class->render_icon_pixbuf (priv->theming_engine, source, size);
3413 }