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