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