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