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