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