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