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