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