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