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