]> Pileus Git - ~andy/gtk/blob - gtk/gtkstylecontext.c
stylecontext: Remove theming_engine cache variable
[~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 = gtk_widget_path_copy (priv->widget ? gtk_widget_get_path (priv->widget) : 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       if (gtk_style_provider_get_style_property (GTK_STYLE_PROVIDER (priv->cascade),
2072                                                  priv->widget ? gtk_widget_get_path (priv->widget)
2073                                                               : priv->widget_path,
2074                                                  state, pspec, &pcache->value))
2075         {
2076           /* Resolve symbolic colors to GdkColor/GdkRGBA */
2077           if (G_VALUE_TYPE (&pcache->value) == GTK_TYPE_SYMBOLIC_COLOR)
2078             {
2079               GtkSymbolicColor *color;
2080               GdkRGBA rgba;
2081
2082               color = g_value_dup_boxed (&pcache->value);
2083
2084               g_value_unset (&pcache->value);
2085
2086               if (G_PARAM_SPEC_VALUE_TYPE (pspec) == GDK_TYPE_RGBA)
2087                 g_value_init (&pcache->value, GDK_TYPE_RGBA);
2088               else
2089                 g_value_init (&pcache->value, GDK_TYPE_COLOR);
2090
2091               if (_gtk_style_context_resolve_color (context, color, &rgba))
2092                 {
2093                   if (G_PARAM_SPEC_VALUE_TYPE (pspec) == GDK_TYPE_RGBA)
2094                     g_value_set_boxed (&pcache->value, &rgba);
2095                   else
2096                     {
2097                       GdkColor rgb;
2098
2099                       rgb.red = rgba.red * 65535. + 0.5;
2100                       rgb.green = rgba.green * 65535. + 0.5;
2101                       rgb.blue = rgba.blue * 65535. + 0.5;
2102
2103                       g_value_set_boxed (&pcache->value, &rgb);
2104                     }
2105                 }
2106               else
2107                 g_param_value_set_default (pspec, &pcache->value);
2108
2109               gtk_symbolic_color_unref (color);
2110             }
2111
2112           return &pcache->value;
2113         }
2114     }
2115
2116   /* not supplied by any provider, revert to default */
2117   g_param_value_set_default (pspec, &pcache->value);
2118
2119   return &pcache->value;
2120 }
2121
2122 /**
2123  * gtk_style_context_get_style_property:
2124  * @context: a #GtkStyleContext
2125  * @property_name: the name of the widget style property
2126  * @value: Return location for the property value
2127  *
2128  * Gets the value for a widget style property.
2129  *
2130  * When @value is no longer needed, g_value_unset() must be called
2131  * to free any allocated memory.
2132  **/
2133 void
2134 gtk_style_context_get_style_property (GtkStyleContext *context,
2135                                       const gchar     *property_name,
2136                                       GValue          *value)
2137 {
2138   GtkStyleContextPrivate *priv;
2139   GtkWidgetClass *widget_class;
2140   GtkStateFlags state;
2141   GParamSpec *pspec;
2142   const GValue *peek_value;
2143   GType widget_type;
2144
2145   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2146   g_return_if_fail (property_name != NULL);
2147   g_return_if_fail (value != NULL);
2148
2149   priv = context->priv;
2150
2151   if (priv->widget)
2152     {
2153       widget_type = G_OBJECT_TYPE (priv->widget);
2154     }
2155   else
2156     {
2157       if (!priv->widget_path)
2158         return;
2159
2160       widget_type = gtk_widget_path_get_object_type (priv->widget_path);
2161
2162       if (!g_type_is_a (widget_type, GTK_TYPE_WIDGET))
2163         {
2164           g_warning ("%s: can't get style properties for non-widget class `%s'",
2165                      G_STRLOC,
2166                      g_type_name (widget_type));
2167           return;
2168         }
2169     }
2170
2171   widget_class = g_type_class_ref (widget_type);
2172   pspec = gtk_widget_class_find_style_property (widget_class, property_name);
2173   g_type_class_unref (widget_class);
2174
2175   if (!pspec)
2176     {
2177       g_warning ("%s: widget class `%s' has no style property named `%s'",
2178                  G_STRLOC,
2179                  g_type_name (widget_type),
2180                  property_name);
2181       return;
2182     }
2183
2184   state = gtk_style_context_get_state (context);
2185   peek_value = _gtk_style_context_peek_style_property (context, widget_type,
2186                                                        state, pspec);
2187
2188   if (G_VALUE_TYPE (value) == G_VALUE_TYPE (peek_value))
2189     g_value_copy (peek_value, value);
2190   else if (g_value_type_transformable (G_VALUE_TYPE (peek_value), G_VALUE_TYPE (value)))
2191     g_value_transform (peek_value, value);
2192   else
2193     g_warning ("can't retrieve style property `%s' of type `%s' as value of type `%s'",
2194                pspec->name,
2195                G_VALUE_TYPE_NAME (peek_value),
2196                G_VALUE_TYPE_NAME (value));
2197 }
2198
2199 /**
2200  * gtk_style_context_get_style_valist:
2201  * @context: a #GtkStyleContext
2202  * @args: va_list of property name/return location pairs, followed by %NULL
2203  *
2204  * Retrieves several widget style properties from @context according to the
2205  * current style.
2206  *
2207  * Since: 3.0
2208  **/
2209 void
2210 gtk_style_context_get_style_valist (GtkStyleContext *context,
2211                                     va_list          args)
2212 {
2213   GtkStyleContextPrivate *priv;
2214   const gchar *prop_name;
2215   GtkStateFlags state;
2216   GType widget_type;
2217
2218   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2219
2220   prop_name = va_arg (args, const gchar *);
2221   priv = context->priv;
2222
2223   if (priv->widget)
2224     {
2225       widget_type = G_OBJECT_TYPE (priv->widget);
2226     }
2227   else
2228     {
2229       if (!priv->widget_path)
2230         return;
2231
2232       widget_type = gtk_widget_path_get_object_type (priv->widget_path);
2233
2234       if (!g_type_is_a (widget_type, GTK_TYPE_WIDGET))
2235         {
2236           g_warning ("%s: can't get style properties for non-widget class `%s'",
2237                      G_STRLOC,
2238                      g_type_name (widget_type));
2239           return;
2240         }
2241     }
2242
2243   state = gtk_style_context_get_state (context);
2244
2245   while (prop_name)
2246     {
2247       GtkWidgetClass *widget_class;
2248       GParamSpec *pspec;
2249       const GValue *peek_value;
2250       gchar *error;
2251
2252       widget_class = g_type_class_ref (widget_type);
2253       pspec = gtk_widget_class_find_style_property (widget_class, prop_name);
2254       g_type_class_unref (widget_class);
2255
2256       if (!pspec)
2257         {
2258           g_warning ("%s: widget class `%s' has no style property named `%s'",
2259                      G_STRLOC,
2260                      g_type_name (widget_type),
2261                      prop_name);
2262           break;
2263         }
2264
2265       peek_value = _gtk_style_context_peek_style_property (context, widget_type,
2266                                                            state, pspec);
2267
2268       G_VALUE_LCOPY (peek_value, args, 0, &error);
2269
2270       if (error)
2271         {
2272           g_warning ("can't retrieve style property `%s' of type `%s': %s",
2273                      pspec->name,
2274                      G_VALUE_TYPE_NAME (peek_value),
2275                      error);
2276           g_free (error);
2277           break;
2278         }
2279
2280       prop_name = va_arg (args, const gchar *);
2281     }
2282 }
2283
2284 /**
2285  * gtk_style_context_get_style:
2286  * @context: a #GtkStyleContext
2287  * @...: property name /return value pairs, followed by %NULL
2288  *
2289  * Retrieves several widget style properties from @context according to the
2290  * current style.
2291  *
2292  * Since: 3.0
2293  **/
2294 void
2295 gtk_style_context_get_style (GtkStyleContext *context,
2296                              ...)
2297 {
2298   va_list args;
2299
2300   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2301
2302   va_start (args, context);
2303   gtk_style_context_get_style_valist (context, args);
2304   va_end (args);
2305 }
2306
2307
2308 /**
2309  * gtk_style_context_lookup_icon_set:
2310  * @context: a #GtkStyleContext
2311  * @stock_id: an icon name
2312  *
2313  * Looks up @stock_id in the icon factories associated to @context and
2314  * the default icon factory, returning an icon set if found, otherwise
2315  * %NULL.
2316  *
2317  * Returns: (transfer none): The looked  up %GtkIconSet, or %NULL
2318  **/
2319 GtkIconSet *
2320 gtk_style_context_lookup_icon_set (GtkStyleContext *context,
2321                                    const gchar     *stock_id)
2322 {
2323   GtkStyleContextPrivate *priv;
2324
2325   g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), NULL);
2326   g_return_val_if_fail (stock_id != NULL, NULL);
2327
2328   priv = context->priv;
2329   g_return_val_if_fail (priv->widget != NULL || priv->widget_path != NULL, NULL);
2330
2331   return gtk_icon_factory_lookup_default (stock_id);
2332 }
2333
2334 /**
2335  * gtk_style_context_set_screen:
2336  * @context: a #GtkStyleContext
2337  * @screen: a #GdkScreen
2338  *
2339  * Attaches @context to the given screen.
2340  *
2341  * The screen is used to add style information from 'global' style
2342  * providers, such as the screens #GtkSettings instance.
2343  *
2344  * If you are using a #GtkStyleContext returned from
2345  * gtk_widget_get_style_context(), you do not need to
2346  * call this yourself.
2347  *
2348  * Since: 3.0
2349  **/
2350 void
2351 gtk_style_context_set_screen (GtkStyleContext *context,
2352                               GdkScreen       *screen)
2353 {
2354   GtkStyleContextPrivate *priv;
2355
2356   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2357   g_return_if_fail (GDK_IS_SCREEN (screen));
2358
2359   priv = context->priv;
2360   if (priv->screen == screen)
2361     return;
2362
2363   if (priv->cascade == _gtk_style_cascade_get_for_screen (priv->screen))
2364     {
2365       g_object_unref (priv->cascade);
2366       priv->cascade = _gtk_style_cascade_get_for_screen (screen);
2367       g_object_ref (priv->cascade);
2368     }
2369   else
2370     {
2371       _gtk_style_cascade_set_parent (priv->cascade, _gtk_style_cascade_get_for_screen (screen));
2372     }
2373
2374   priv->screen = screen;
2375
2376   g_object_notify (G_OBJECT (context), "screen");
2377
2378   gtk_style_context_invalidate (context);
2379 }
2380
2381 /**
2382  * gtk_style_context_get_screen:
2383  * @context: a #GtkStyleContext
2384  *
2385  * Returns the #GdkScreen to which @context is attached.
2386  *
2387  * Returns: (transfer none): a #GdkScreen.
2388  **/
2389 GdkScreen *
2390 gtk_style_context_get_screen (GtkStyleContext *context)
2391 {
2392   GtkStyleContextPrivate *priv;
2393
2394   g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), NULL);
2395
2396   priv = context->priv;
2397   return priv->screen;
2398 }
2399
2400 /**
2401  * gtk_style_context_set_direction:
2402  * @context: a #GtkStyleContext
2403  * @direction: the new direction.
2404  *
2405  * Sets the reading direction for rendering purposes.
2406  *
2407  * If you are using a #GtkStyleContext returned from
2408  * gtk_widget_get_style_context(), you do not need to
2409  * call this yourself.
2410  *
2411  * Since: 3.0
2412  **/
2413 void
2414 gtk_style_context_set_direction (GtkStyleContext  *context,
2415                                  GtkTextDirection  direction)
2416 {
2417   GtkStyleContextPrivate *priv;
2418
2419   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2420
2421   priv = context->priv;
2422   priv->direction = direction;
2423
2424   g_object_notify (G_OBJECT (context), "direction");
2425 }
2426
2427 /**
2428  * gtk_style_context_get_direction:
2429  * @context: a #GtkStyleContext
2430  *
2431  * Returns the widget direction used for rendering.
2432  *
2433  * Returns: the widget direction
2434  *
2435  * Since: 3.0
2436  **/
2437 GtkTextDirection
2438 gtk_style_context_get_direction (GtkStyleContext *context)
2439 {
2440   GtkStyleContextPrivate *priv;
2441
2442   g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), GTK_TEXT_DIR_LTR);
2443
2444   priv = context->priv;
2445   return priv->direction;
2446 }
2447
2448 /**
2449  * gtk_style_context_set_junction_sides:
2450  * @context: a #GtkStyleContext
2451  * @sides: sides where rendered elements are visually connected to
2452  *     other elements
2453  *
2454  * Sets the sides where rendered elements (mostly through
2455  * gtk_render_frame()) will visually connect with other visual elements.
2456  *
2457  * This is merely a hint that may or may not be honored
2458  * by theming engines.
2459  *
2460  * Container widgets are expected to set junction hints as appropriate
2461  * for their children, so it should not normally be necessary to call
2462  * this function manually.
2463  *
2464  * Since: 3.0
2465  **/
2466 void
2467 gtk_style_context_set_junction_sides (GtkStyleContext  *context,
2468                                       GtkJunctionSides  sides)
2469 {
2470   GtkStyleContextPrivate *priv;
2471   GtkStyleInfo *info;
2472
2473   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2474
2475   priv = context->priv;
2476   info = priv->info_stack->data;
2477   info->junction_sides = sides;
2478 }
2479
2480 /**
2481  * gtk_style_context_get_junction_sides:
2482  * @context: a #GtkStyleContext
2483  *
2484  * Returns the sides where rendered elements connect visually with others.
2485  *
2486  * Returns: the junction sides
2487  *
2488  * Since: 3.0
2489  **/
2490 GtkJunctionSides
2491 gtk_style_context_get_junction_sides (GtkStyleContext *context)
2492 {
2493   GtkStyleContextPrivate *priv;
2494   GtkStyleInfo *info;
2495
2496   g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), 0);
2497
2498   priv = context->priv;
2499   info = priv->info_stack->data;
2500   return info->junction_sides;
2501 }
2502
2503 static GtkSymbolicColor *
2504 gtk_style_context_color_lookup_func (gpointer    contextp,
2505                                      const char *name)
2506 {
2507   GtkStyleContext *context = contextp;
2508
2509   return _gtk_style_provider_private_get_color (GTK_STYLE_PROVIDER_PRIVATE (context->priv->cascade), name);
2510 }
2511
2512 GtkCssValue *
2513 _gtk_style_context_resolve_color_value (GtkStyleContext  *context,
2514                                         GtkCssValue      *current,
2515                                         GtkCssValue      *color)
2516 {
2517   g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), FALSE);
2518   g_return_val_if_fail (current != NULL, FALSE);
2519   g_return_val_if_fail (color != NULL, FALSE);
2520
2521   return _gtk_symbolic_color_resolve_full ((GtkSymbolicColor *) color,
2522                                            current,
2523                                            gtk_style_context_color_lookup_func,
2524                                            context);
2525 }
2526
2527
2528 gboolean
2529 _gtk_style_context_resolve_color (GtkStyleContext  *context,
2530                                   GtkSymbolicColor *color,
2531                                   GdkRGBA          *result)
2532 {
2533   GtkCssValue *val;
2534
2535   g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), FALSE);
2536   g_return_val_if_fail (color != NULL, FALSE);
2537   g_return_val_if_fail (result != NULL, FALSE);
2538
2539   val = _gtk_symbolic_color_resolve_full (color,
2540                                           _gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_COLOR),
2541                                           gtk_style_context_color_lookup_func,
2542                                           context);
2543   if (val == NULL)
2544     return FALSE;
2545
2546   *result = *_gtk_css_rgba_value_get_rgba (val);
2547   _gtk_css_value_unref (val);
2548   return TRUE;
2549 }
2550
2551 /**
2552  * gtk_style_context_lookup_color:
2553  * @context: a #GtkStyleContext
2554  * @color_name: color name to lookup
2555  * @color: (out): Return location for the looked up color
2556  *
2557  * Looks up and resolves a color name in the @context color map.
2558  *
2559  * Returns: %TRUE if @color_name was found and resolved, %FALSE otherwise
2560  **/
2561 gboolean
2562 gtk_style_context_lookup_color (GtkStyleContext *context,
2563                                 const gchar     *color_name,
2564                                 GdkRGBA         *color)
2565 {
2566   GtkSymbolicColor *sym_color;
2567
2568   g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), FALSE);
2569   g_return_val_if_fail (color_name != NULL, FALSE);
2570   g_return_val_if_fail (color != NULL, FALSE);
2571
2572   sym_color = gtk_style_context_color_lookup_func (context, color_name);
2573   if (sym_color == NULL)
2574     return FALSE;
2575
2576   return _gtk_style_context_resolve_color (context, sym_color, color);
2577 }
2578
2579 /**
2580  * gtk_style_context_notify_state_change:
2581  * @context: a #GtkStyleContext
2582  * @window: a #GdkWindow
2583  * @region_id: (allow-none): animatable region to notify on, or %NULL.
2584  *     See gtk_style_context_push_animatable_region()
2585  * @state: state to trigger transition for
2586  * @state_value: %TRUE if @state is the state we are changing to,
2587  *     %FALSE if we are changing away from it
2588  *
2589  * Notifies a state change on @context, so if the current style makes use
2590  * of transition animations, one will be started so all rendered elements
2591  * under @region_id are animated for state @state being set to value
2592  * @state_value.
2593  *
2594  * The @window parameter is used in order to invalidate the rendered area
2595  * as the animation runs, so make sure it is the same window that is being
2596  * rendered on by the gtk_render_*() functions.
2597  *
2598  * If @region_id is %NULL, all rendered elements using @context will be
2599  * affected by this state transition.
2600  *
2601  * As a practical example, a #GtkButton notifying a state transition on
2602  * the prelight state:
2603  * <programlisting>
2604  * gtk_style_context_notify_state_change (context,
2605  *                                        gtk_widget_get_window (widget),
2606  *                                        NULL,
2607  *                                        GTK_STATE_PRELIGHT,
2608  *                                        button->in_button);
2609  * </programlisting>
2610  *
2611  * Can be handled in the CSS file like this:
2612  * <programlisting>
2613  * GtkButton {
2614  *     background-color: &num;f00
2615  * }
2616  *
2617  * GtkButton:hover {
2618  *     background-color: &num;fff;
2619  *     transition: 200ms linear
2620  * }
2621  * </programlisting>
2622  *
2623  * This combination will animate the button background from red to white
2624  * if a pointer enters the button, and back to red if the pointer leaves
2625  * the button.
2626  *
2627  * Note that @state is used when finding the transition parameters, which
2628  * is why the style places the transition under the :hover pseudo-class.
2629  *
2630  * Since: 3.0
2631  *
2632  * Deprecated: 3.6: This function does nothing.
2633  **/
2634 void
2635 gtk_style_context_notify_state_change (GtkStyleContext *context,
2636                                        GdkWindow       *window,
2637                                        gpointer         region_id,
2638                                        GtkStateType     state,
2639                                        gboolean         state_value)
2640 {
2641   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2642   g_return_if_fail (GDK_IS_WINDOW (window));
2643   g_return_if_fail (state > GTK_STATE_NORMAL && state <= GTK_STATE_FOCUSED);
2644   g_return_if_fail (context->priv->widget != NULL || context->priv->widget_path != NULL);
2645 }
2646
2647 /**
2648  * gtk_style_context_cancel_animations:
2649  * @context: a #GtkStyleContext
2650  * @region_id: (allow-none): animatable region to stop, or %NULL.
2651  *     See gtk_style_context_push_animatable_region()
2652  *
2653  * Stops all running animations for @region_id and all animatable
2654  * regions underneath.
2655  *
2656  * A %NULL @region_id will stop all ongoing animations in @context,
2657  * when dealing with a #GtkStyleContext obtained through
2658  * gtk_widget_get_style_context(), this is normally done for you
2659  * in all circumstances you would expect all widget to be stopped,
2660  * so this should be only used in complex widgets with different
2661  * animatable regions.
2662  *
2663  * Since: 3.0
2664  *
2665  * Deprecated: 3.6: This function does nothing.
2666  **/
2667 void
2668 gtk_style_context_cancel_animations (GtkStyleContext *context,
2669                                      gpointer         region_id)
2670 {
2671   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2672 }
2673
2674 /**
2675  * gtk_style_context_scroll_animations:
2676  * @context: a #GtkStyleContext
2677  * @window: a #GdkWindow used previously in
2678  *          gtk_style_context_notify_state_change()
2679  * @dx: Amount to scroll in the X axis
2680  * @dy: Amount to scroll in the Y axis
2681  *
2682  * This function is analogous to gdk_window_scroll(), and
2683  * should be called together with it so the invalidation
2684  * areas for any ongoing animation are scrolled together
2685  * with it.
2686  *
2687  * Since: 3.0
2688  *
2689  * Deprecated: 3.6: This function does nothing.
2690  **/
2691 void
2692 gtk_style_context_scroll_animations (GtkStyleContext *context,
2693                                      GdkWindow       *window,
2694                                      gint             dx,
2695                                      gint             dy)
2696 {
2697   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2698   g_return_if_fail (GDK_IS_WINDOW (window));
2699 }
2700
2701 /**
2702  * gtk_style_context_push_animatable_region:
2703  * @context: a #GtkStyleContext
2704  * @region_id: unique identifier for the animatable region
2705  *
2706  * Pushes an animatable region, so all further gtk_render_*() calls between
2707  * this call and the following gtk_style_context_pop_animatable_region()
2708  * will potentially show transition animations for this region if
2709  * gtk_style_context_notify_state_change() is called for a given state,
2710  * and the current theme/style defines transition animations for state
2711  * changes.
2712  *
2713  * The @region_id used must be unique in @context so the theming engine
2714  * can uniquely identify rendered elements subject to a state transition.
2715  *
2716  * Since: 3.0
2717  *
2718  * Deprecated: 3.6: This function does nothing.
2719  **/
2720 void
2721 gtk_style_context_push_animatable_region (GtkStyleContext *context,
2722                                           gpointer         region_id)
2723 {
2724   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2725   g_return_if_fail (region_id != NULL);
2726 }
2727
2728 /**
2729  * gtk_style_context_pop_animatable_region:
2730  * @context: a #GtkStyleContext
2731  *
2732  * Pops an animatable region from @context.
2733  * See gtk_style_context_push_animatable_region().
2734  *
2735  * Since: 3.0
2736  *
2737  * Deprecated: 3.6: This function does nothing.
2738  **/
2739 void
2740 gtk_style_context_pop_animatable_region (GtkStyleContext *context)
2741 {
2742   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2743 }
2744
2745 static void
2746 gtk_style_context_clear_cache (GtkStyleContext *context)
2747 {
2748   GtkStyleContextPrivate *priv;
2749   GSList *list;
2750
2751   priv = context->priv;
2752
2753   for (list = priv->info_stack; list; list = list->next)
2754     {
2755       GtkStyleInfo *info = list->data;
2756       info->data = NULL;
2757     }
2758   g_hash_table_remove_all (priv->style_data);
2759 }
2760
2761 static void
2762 gtk_style_context_do_invalidate (GtkStyleContext *context)
2763 {
2764   GtkStyleContextPrivate *priv;
2765
2766   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2767
2768   priv = context->priv;
2769
2770   /* Avoid reentrancy */
2771   if (priv->invalidating_context)
2772     return;
2773
2774   priv->invalidating_context = TRUE;
2775
2776   g_signal_emit (context, signals[CHANGED], 0);
2777
2778   priv->invalidating_context = FALSE;
2779 }
2780
2781 void
2782 _gtk_style_context_validate (GtkStyleContext *context,
2783                              GtkCssChange     change)
2784 {
2785   GtkStyleContextPrivate *priv;
2786   GSList *list;
2787
2788   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2789
2790   priv = context->priv;
2791
2792   change |= priv->pending_changes;
2793
2794   if (!priv->invalid && change == 0)
2795     return;
2796
2797   priv->pending_changes = 0;
2798   gtk_style_context_set_invalid (context, FALSE);
2799
2800   /* Try to avoid invalidating if we can */
2801   if (change & GTK_STYLE_CONTEXT_RADICAL_CHANGE)
2802     {
2803       priv->relevant_changes = GTK_CSS_CHANGE_ANY;
2804     }
2805   else
2806     {
2807       if (priv->relevant_changes == GTK_CSS_CHANGE_ANY)
2808         {
2809           GtkWidgetPath *path;
2810           GtkCssMatcher matcher;
2811
2812           path = create_query_path (context);
2813           _gtk_css_matcher_init (&matcher, path, ((GtkStyleInfo *) priv->info_stack->data)->state_flags);
2814
2815           priv->relevant_changes = _gtk_style_provider_private_get_change (GTK_STYLE_PROVIDER_PRIVATE (priv->cascade),
2816                                                                            &matcher);
2817           priv->relevant_changes &= ~GTK_STYLE_CONTEXT_RADICAL_CHANGE;
2818
2819           gtk_widget_path_unref (path);
2820         }
2821     }
2822
2823   if (priv->relevant_changes & change)
2824     {
2825       GtkStyleInfo *info = priv->info_stack->data;
2826
2827       if ((priv->relevant_changes & change) & ~GTK_STYLE_CONTEXT_CACHED_CHANGE)
2828         gtk_style_context_clear_cache (context);
2829
2830       info->data = NULL;
2831       gtk_style_context_do_invalidate (context);
2832     }
2833
2834   change = _gtk_css_change_for_child (change);
2835   for (list = priv->children; list; list = list->next)
2836     {
2837       _gtk_style_context_validate (list->data, change);
2838     }
2839 }
2840
2841 void
2842 _gtk_style_context_queue_invalidate (GtkStyleContext *context,
2843                                      GtkCssChange     change)
2844 {
2845   GtkStyleContextPrivate *priv;
2846
2847   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2848   g_return_if_fail (change != 0);
2849
2850   priv = context->priv;
2851
2852   if (priv->widget == NULL && priv->widget_path == NULL)
2853     return;
2854
2855   priv->pending_changes |= change;
2856   gtk_style_context_set_invalid (context, TRUE);
2857 }
2858
2859 /**
2860  * gtk_style_context_invalidate:
2861  * @context: a #GtkStyleContext.
2862  *
2863  * Invalidates @context style information, so it will be reconstructed
2864  * again.
2865  *
2866  * If you're using a #GtkStyleContext returned from
2867  * gtk_widget_get_style_context(), you do not need to
2868  * call this yourself.
2869  *
2870  * Since: 3.0
2871  **/
2872 void
2873 gtk_style_context_invalidate (GtkStyleContext *context)
2874 {
2875   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2876
2877   gtk_style_context_clear_cache (context);
2878   gtk_style_context_do_invalidate (context);
2879 }
2880
2881 /**
2882  * gtk_style_context_set_background:
2883  * @context: a #GtkStyleContext
2884  * @window: a #GdkWindow
2885  *
2886  * Sets the background of @window to the background pattern or
2887  * color specified in @context for its current state.
2888  *
2889  * Since: 3.0
2890  **/
2891 void
2892 gtk_style_context_set_background (GtkStyleContext *context,
2893                                   GdkWindow       *window)
2894 {
2895   GtkStateFlags state;
2896   cairo_pattern_t *pattern;
2897   GdkRGBA *color;
2898
2899   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2900   g_return_if_fail (GDK_IS_WINDOW (window));
2901
2902   state = gtk_style_context_get_state (context);
2903   gtk_style_context_get (context, state,
2904                          "background-image", &pattern,
2905                          NULL);
2906   if (pattern)
2907     {
2908       gdk_window_set_background_pattern (window, pattern);
2909       cairo_pattern_destroy (pattern);
2910       return;
2911     }
2912
2913   gtk_style_context_get (context, state,
2914                          "background-color", &color,
2915                          NULL);
2916   if (color)
2917     {
2918       gdk_window_set_background_rgba (window, color);
2919       gdk_rgba_free (color);
2920     }
2921 }
2922
2923 /**
2924  * gtk_style_context_get_color:
2925  * @context: a #GtkStyleContext
2926  * @state: state to retrieve the color for
2927  * @color: (out): return value for the foreground color
2928  *
2929  * Gets the foreground color for a given state.
2930  *
2931  * Since: 3.0
2932  **/
2933 void
2934 gtk_style_context_get_color (GtkStyleContext *context,
2935                              GtkStateFlags    state,
2936                              GdkRGBA         *color)
2937 {
2938   GdkRGBA *c;
2939
2940   g_return_if_fail (color != NULL);
2941   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2942
2943   gtk_style_context_get (context,
2944                          state,
2945                          "color", &c,
2946                          NULL);
2947
2948   *color = *c;
2949   gdk_rgba_free (c);
2950 }
2951
2952 /**
2953  * gtk_style_context_get_background_color:
2954  * @context: a #GtkStyleContext
2955  * @state: state to retrieve the color for
2956  * @color: (out): return value for the background color
2957  *
2958  * Gets the background color for a given state.
2959  *
2960  * Since: 3.0
2961  **/
2962 void
2963 gtk_style_context_get_background_color (GtkStyleContext *context,
2964                                         GtkStateFlags    state,
2965                                         GdkRGBA         *color)
2966 {
2967   GdkRGBA *c;
2968
2969   g_return_if_fail (color != NULL);
2970   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2971
2972   gtk_style_context_get (context,
2973                          state,
2974                          "background-color", &c,
2975                          NULL);
2976
2977   *color = *c;
2978   gdk_rgba_free (c);
2979 }
2980
2981 /**
2982  * gtk_style_context_get_border_color:
2983  * @context: a #GtkStyleContext
2984  * @state: state to retrieve the color for
2985  * @color: (out): return value for the border color
2986  *
2987  * Gets the border color for a given state.
2988  *
2989  * Since: 3.0
2990  **/
2991 void
2992 gtk_style_context_get_border_color (GtkStyleContext *context,
2993                                     GtkStateFlags    state,
2994                                     GdkRGBA         *color)
2995 {
2996   GdkRGBA *c;
2997
2998   g_return_if_fail (color != NULL);
2999   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3000
3001   gtk_style_context_get (context,
3002                          state,
3003                          "border-color", &c,
3004                          NULL);
3005
3006   *color = *c;
3007   gdk_rgba_free (c);
3008 }
3009
3010 /**
3011  * gtk_style_context_get_border:
3012  * @context: a #GtkStyleContext
3013  * @state: state to retrieve the border for
3014  * @border: (out): return value for the border settings
3015  *
3016  * Gets the border for a given state as a #GtkBorder.
3017  * See %GTK_STYLE_PROPERTY_BORDER_WIDTH.
3018  *
3019  * Since: 3.0
3020  **/
3021 void
3022 gtk_style_context_get_border (GtkStyleContext *context,
3023                               GtkStateFlags    state,
3024                               GtkBorder       *border)
3025 {
3026   int top, left, bottom, right;
3027
3028   g_return_if_fail (border != NULL);
3029   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3030
3031   gtk_style_context_get (context,
3032                          state,
3033                          "border-top-width", &top,
3034                          "border-left-width", &left,
3035                          "border-bottom-width", &bottom,
3036                          "border-right-width", &right,
3037                          NULL);
3038
3039   border->top = top;
3040   border->left = left;
3041   border->bottom = bottom;
3042   border->right = right;
3043 }
3044
3045 /**
3046  * gtk_style_context_get_padding:
3047  * @context: a #GtkStyleContext
3048  * @state: state to retrieve the padding for
3049  * @padding: (out): return value for the padding settings
3050  *
3051  * Gets the padding for a given state as a #GtkBorder.
3052  * See %GTK_STYLE_PROPERTY_PADDING.
3053  *
3054  * Since: 3.0
3055  **/
3056 void
3057 gtk_style_context_get_padding (GtkStyleContext *context,
3058                                GtkStateFlags    state,
3059                                GtkBorder       *padding)
3060 {
3061   int top, left, bottom, right;
3062
3063   g_return_if_fail (padding != NULL);
3064   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3065
3066   gtk_style_context_get (context,
3067                          state,
3068                          "padding-top", &top,
3069                          "padding-left", &left,
3070                          "padding-bottom", &bottom,
3071                          "padding-right", &right,
3072                          NULL);
3073
3074   padding->top = top;
3075   padding->left = left;
3076   padding->bottom = bottom;
3077   padding->right = right;
3078 }
3079
3080 /**
3081  * gtk_style_context_get_margin:
3082  * @context: a #GtkStyleContext
3083  * @state: state to retrieve the border for
3084  * @margin: (out): return value for the margin settings
3085  *
3086  * Gets the margin for a given state as a #GtkBorder.
3087  * See %GTK_STYLE_PROPERTY_MARGIN.
3088  *
3089  * Since: 3.0
3090  **/
3091 void
3092 gtk_style_context_get_margin (GtkStyleContext *context,
3093                               GtkStateFlags    state,
3094                               GtkBorder       *margin)
3095 {
3096   int top, left, bottom, right;
3097
3098   g_return_if_fail (margin != NULL);
3099   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3100
3101   gtk_style_context_get (context,
3102                          state,
3103                          "margin-top", &top,
3104                          "margin-left", &left,
3105                          "margin-bottom", &bottom,
3106                          "margin-right", &right,
3107                          NULL);
3108
3109   margin->top = top;
3110   margin->left = left;
3111   margin->bottom = bottom;
3112   margin->right = right;
3113 }
3114
3115 /**
3116  * gtk_style_context_get_font:
3117  * @context: a #GtkStyleContext
3118  * @state: state to retrieve the font for
3119  *
3120  * Returns the font description for a given state. The returned
3121  * object is const and will remain valid until the
3122  * #GtkStyleContext::changed signal happens.
3123  *
3124  * Returns: (transfer none): the #PangoFontDescription for the given
3125  *          state.  This object is owned by GTK+ and should not be
3126  *          freed.
3127  *
3128  * Since: 3.0
3129  **/
3130 const PangoFontDescription *
3131 gtk_style_context_get_font (GtkStyleContext *context,
3132                             GtkStateFlags    state)
3133 {
3134   GtkStyleContextPrivate *priv;
3135   StyleData *data;
3136   PangoFontDescription *description;
3137
3138   g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), NULL);
3139
3140   priv = context->priv;
3141   g_return_val_if_fail (priv->widget != NULL || priv->widget_path != NULL, NULL);
3142
3143   gtk_style_context_save (context);
3144   gtk_style_context_set_state (context, state);
3145   data = style_data_lookup (context);
3146   gtk_style_context_restore (context);
3147
3148   /* Yuck, fonts are created on-demand but we don't return a ref.
3149    * Do bad things to achieve this requirement */
3150   description = g_object_get_data (G_OBJECT (data->store), "font-cache-for-get_font");
3151   if (description == NULL)
3152     {
3153       gtk_style_context_get (context, state, "font", &description, NULL);
3154       g_object_set_data_full (G_OBJECT (data->store),
3155                               "font-cache-for-get_font",
3156                               description,
3157                               (GDestroyNotify) pango_font_description_free);
3158     }
3159   return description;
3160 }
3161
3162 static void
3163 get_cursor_color (GtkStyleContext *context,
3164                   gboolean         primary,
3165                   GdkRGBA         *color)
3166 {
3167   GdkColor *style_color;
3168
3169   gtk_style_context_get_style (context,
3170                                primary ? "cursor-color" : "secondary-cursor-color",
3171                                &style_color,
3172                                NULL);
3173
3174   if (style_color)
3175     {
3176       color->red = style_color->red / 65535.0;
3177       color->green = style_color->green / 65535.0;
3178       color->blue = style_color->blue / 65535.0;
3179       color->alpha = 1;
3180
3181       gdk_color_free (style_color);
3182     }
3183   else
3184     {
3185       gtk_style_context_get_color (context, GTK_STATE_FLAG_NORMAL, color);
3186
3187       if (!primary)
3188       {
3189         GdkRGBA bg;
3190
3191         gtk_style_context_get_background_color (context, GTK_STATE_FLAG_NORMAL, &bg);
3192
3193         color->red = (color->red + bg.red) * 0.5;
3194         color->green = (color->green + bg.green) * 0.5;
3195         color->blue = (color->blue + bg.blue) * 0.5;
3196       }
3197     }
3198 }
3199
3200 void
3201 _gtk_style_context_get_cursor_color (GtkStyleContext *context,
3202                                      GdkRGBA         *primary_color,
3203                                      GdkRGBA         *secondary_color)
3204 {
3205   if (primary_color)
3206     get_cursor_color (context, TRUE, primary_color);
3207
3208   if (secondary_color)
3209     get_cursor_color (context, FALSE, secondary_color);
3210 }
3211
3212 /* Paint methods */
3213
3214 /**
3215  * gtk_render_check:
3216  * @context: a #GtkStyleContext
3217  * @cr: a #cairo_t
3218  * @x: X origin of the rectangle
3219  * @y: Y origin of the rectangle
3220  * @width: rectangle width
3221  * @height: rectangle height
3222  *
3223  * Renders a checkmark (as in a #GtkCheckButton).
3224  *
3225  * The %GTK_STATE_FLAG_ACTIVE state determines whether the check is
3226  * on or off, and %GTK_STATE_FLAG_INCONSISTENT determines whether it
3227  * should be marked as undefined.
3228  *
3229  * <example>
3230  * <title>Typical checkmark rendering</title>
3231  * <inlinegraphic fileref="checks.png" format="PNG"/>
3232  * </example>
3233  *
3234  * Since: 3.0
3235  **/
3236 void
3237 gtk_render_check (GtkStyleContext *context,
3238                   cairo_t         *cr,
3239                   gdouble          x,
3240                   gdouble          y,
3241                   gdouble          width,
3242                   gdouble          height)
3243 {
3244   GtkThemingEngineClass *engine_class;
3245   GtkThemingEngine *engine;
3246
3247   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3248   g_return_if_fail (cr != NULL);
3249
3250   if (width <= 0 || height <= 0)
3251     return;
3252
3253   engine = _gtk_css_engine_value_get_engine (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_ENGINE));
3254   engine_class = GTK_THEMING_ENGINE_GET_CLASS (engine);
3255
3256   cairo_save (cr);
3257
3258
3259   _gtk_theming_engine_set_context (engine, context);
3260   engine_class->render_check (engine, cr,
3261                               x, y, width, height);
3262
3263   cairo_restore (cr);
3264 }
3265
3266 /**
3267  * gtk_render_option:
3268  * @context: a #GtkStyleContext
3269  * @cr: a #cairo_t
3270  * @x: X origin of the rectangle
3271  * @y: Y origin of the rectangle
3272  * @width: rectangle width
3273  * @height: rectangle height
3274  *
3275  * Renders an option mark (as in a #GtkRadioButton), the %GTK_STATE_FLAG_ACTIVE
3276  * state will determine whether the option is on or off, and
3277  * %GTK_STATE_FLAG_INCONSISTENT whether it should be marked as undefined.
3278  *
3279  * <example>
3280  * <title>Typical option mark rendering</title>
3281  * <inlinegraphic fileref="options.png" format="PNG"/>
3282  * </example>
3283  *
3284  * Since: 3.0
3285  **/
3286 void
3287 gtk_render_option (GtkStyleContext *context,
3288                    cairo_t         *cr,
3289                    gdouble          x,
3290                    gdouble          y,
3291                    gdouble          width,
3292                    gdouble          height)
3293 {
3294   GtkThemingEngineClass *engine_class;
3295   GtkThemingEngine *engine;
3296
3297   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3298   g_return_if_fail (cr != NULL);
3299
3300   if (width <= 0 || height <= 0)
3301     return;
3302
3303   engine = _gtk_css_engine_value_get_engine (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_ENGINE));
3304   engine_class = GTK_THEMING_ENGINE_GET_CLASS (engine);
3305
3306   cairo_save (cr);
3307
3308   _gtk_theming_engine_set_context (engine, context);
3309   engine_class->render_option (engine, cr,
3310                                x, y, width, height);
3311
3312   cairo_restore (cr);
3313 }
3314
3315 /**
3316  * gtk_render_arrow:
3317  * @context: a #GtkStyleContext
3318  * @cr: a #cairo_t
3319  * @angle: arrow angle from 0 to 2 * %G_PI, being 0 the arrow pointing to the north
3320  * @x: X origin of the render area
3321  * @y: Y origin of the render area
3322  * @size: square side for render area
3323  *
3324  * Renders an arrow pointing to @angle.
3325  *
3326  * <example>
3327  * <title>Typical arrow rendering at 0, 1&solidus;2 &pi;, &pi; and 3&solidus;2 &pi;</title>
3328  * <inlinegraphic fileref="arrows.png" format="PNG"/>
3329  * </example>
3330  *
3331  * Since: 3.0
3332  **/
3333 void
3334 gtk_render_arrow (GtkStyleContext *context,
3335                   cairo_t         *cr,
3336                   gdouble          angle,
3337                   gdouble          x,
3338                   gdouble          y,
3339                   gdouble          size)
3340 {
3341   GtkThemingEngineClass *engine_class;
3342   GtkThemingEngine *engine;
3343
3344   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3345   g_return_if_fail (cr != NULL);
3346
3347   if (size <= 0)
3348     return;
3349
3350   engine = _gtk_css_engine_value_get_engine (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_ENGINE));
3351   engine_class = GTK_THEMING_ENGINE_GET_CLASS (engine);
3352
3353   cairo_save (cr);
3354
3355   gtk_style_context_save (context);
3356   gtk_style_context_add_class (context, GTK_STYLE_CLASS_ARROW);
3357
3358   _gtk_theming_engine_set_context (engine, context);
3359   engine_class->render_arrow (engine, cr,
3360                               angle, x, y, size);
3361
3362   gtk_style_context_restore (context);
3363   cairo_restore (cr);
3364 }
3365
3366 /**
3367  * gtk_render_background:
3368  * @context: a #GtkStyleContext
3369  * @cr: a #cairo_t
3370  * @x: X origin of the rectangle
3371  * @y: Y origin of the rectangle
3372  * @width: rectangle width
3373  * @height: rectangle height
3374  *
3375  * Renders the background of an element.
3376  *
3377  * <example>
3378  * <title>Typical background rendering, showing the effect of
3379  * <parameter>background-image</parameter>,
3380  * <parameter>border-width</parameter> and
3381  * <parameter>border-radius</parameter></title>
3382  * <inlinegraphic fileref="background.png" format="PNG"/>
3383  * </example>
3384  *
3385  * Since: 3.0.
3386  **/
3387 void
3388 gtk_render_background (GtkStyleContext *context,
3389                        cairo_t         *cr,
3390                        gdouble          x,
3391                        gdouble          y,
3392                        gdouble          width,
3393                        gdouble          height)
3394 {
3395   GtkThemingEngineClass *engine_class;
3396   GtkThemingEngine *engine;
3397
3398   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3399   g_return_if_fail (cr != NULL);
3400
3401   if (width <= 0 || height <= 0)
3402     return;
3403
3404   engine = _gtk_css_engine_value_get_engine (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_ENGINE));
3405   engine_class = GTK_THEMING_ENGINE_GET_CLASS (engine);
3406
3407   cairo_save (cr);
3408
3409   _gtk_theming_engine_set_context (engine, context);
3410   engine_class->render_background (engine, cr, x, y, width, height);
3411
3412   cairo_restore (cr);
3413 }
3414
3415 /**
3416  * gtk_render_frame:
3417  * @context: a #GtkStyleContext
3418  * @cr: a #cairo_t
3419  * @x: X origin of the rectangle
3420  * @y: Y origin of the rectangle
3421  * @width: rectangle width
3422  * @height: rectangle height
3423  *
3424  * Renders a frame around the rectangle defined by @x, @y, @width, @height.
3425  *
3426  * <example>
3427  * <title>Examples of frame rendering, showing the effect of
3428  * <parameter>border-image</parameter>,
3429  * <parameter>border-color</parameter>,
3430  * <parameter>border-width</parameter>,
3431  * <parameter>border-radius</parameter> and
3432  * junctions</title>
3433  * <inlinegraphic fileref="frames.png" format="PNG"/>
3434  * </example>
3435  *
3436  * Since: 3.0
3437  **/
3438 void
3439 gtk_render_frame (GtkStyleContext *context,
3440                   cairo_t         *cr,
3441                   gdouble          x,
3442                   gdouble          y,
3443                   gdouble          width,
3444                   gdouble          height)
3445 {
3446   GtkThemingEngineClass *engine_class;
3447   GtkThemingEngine *engine;
3448
3449   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3450   g_return_if_fail (cr != NULL);
3451
3452   if (width <= 0 || height <= 0)
3453     return;
3454
3455   engine = _gtk_css_engine_value_get_engine (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_ENGINE));
3456   engine_class = GTK_THEMING_ENGINE_GET_CLASS (engine);
3457
3458   cairo_save (cr);
3459
3460   _gtk_theming_engine_set_context (engine, context);
3461   engine_class->render_frame (engine, cr, x, y, width, height);
3462
3463   cairo_restore (cr);
3464 }
3465
3466 /**
3467  * gtk_render_expander:
3468  * @context: a #GtkStyleContext
3469  * @cr: a #cairo_t
3470  * @x: X origin of the rectangle
3471  * @y: Y origin of the rectangle
3472  * @width: rectangle width
3473  * @height: rectangle height
3474  *
3475  * Renders an expander (as used in #GtkTreeView and #GtkExpander) in the area
3476  * defined by @x, @y, @width, @height. The state %GTK_STATE_FLAG_ACTIVE
3477  * determines whether the expander is collapsed or expanded.
3478  *
3479  * <example>
3480  * <title>Typical expander rendering</title>
3481  * <inlinegraphic fileref="expanders.png" format="PNG"/>
3482  * </example>
3483  *
3484  * Since: 3.0
3485  **/
3486 void
3487 gtk_render_expander (GtkStyleContext *context,
3488                      cairo_t         *cr,
3489                      gdouble          x,
3490                      gdouble          y,
3491                      gdouble          width,
3492                      gdouble          height)
3493 {
3494   GtkThemingEngineClass *engine_class;
3495   GtkThemingEngine *engine;
3496
3497   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3498   g_return_if_fail (cr != NULL);
3499
3500   if (width <= 0 || height <= 0)
3501     return;
3502
3503   engine = _gtk_css_engine_value_get_engine (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_ENGINE));
3504   engine_class = GTK_THEMING_ENGINE_GET_CLASS (engine);
3505
3506   cairo_save (cr);
3507
3508   _gtk_theming_engine_set_context (engine, context);
3509   engine_class->render_expander (engine, cr, x, y, width, height);
3510
3511   cairo_restore (cr);
3512 }
3513
3514 /**
3515  * gtk_render_focus:
3516  * @context: a #GtkStyleContext
3517  * @cr: a #cairo_t
3518  * @x: X origin of the rectangle
3519  * @y: Y origin of the rectangle
3520  * @width: rectangle width
3521  * @height: rectangle height
3522  *
3523  * Renders a focus indicator on the rectangle determined by @x, @y, @width, @height.
3524  * <example>
3525  * <title>Typical focus rendering</title>
3526  * <inlinegraphic fileref="focus.png" format="PNG"/>
3527  * </example>
3528  *
3529  * Since: 3.0
3530  **/
3531 void
3532 gtk_render_focus (GtkStyleContext *context,
3533                   cairo_t         *cr,
3534                   gdouble          x,
3535                   gdouble          y,
3536                   gdouble          width,
3537                   gdouble          height)
3538 {
3539   GtkThemingEngineClass *engine_class;
3540   GtkThemingEngine *engine;
3541
3542   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3543   g_return_if_fail (cr != NULL);
3544
3545   if (width <= 0 || height <= 0)
3546     return;
3547
3548   engine = _gtk_css_engine_value_get_engine (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_ENGINE));
3549   engine_class = GTK_THEMING_ENGINE_GET_CLASS (engine);
3550
3551   cairo_save (cr);
3552
3553   _gtk_theming_engine_set_context (engine, context);
3554   engine_class->render_focus (engine, cr, x, y, width, height);
3555
3556   cairo_restore (cr);
3557 }
3558
3559 /**
3560  * gtk_render_layout:
3561  * @context: a #GtkStyleContext
3562  * @cr: a #cairo_t
3563  * @x: X origin
3564  * @y: Y origin
3565  * @layout: the #PangoLayout to render
3566  *
3567  * Renders @layout on the coordinates @x, @y
3568  *
3569  * Since: 3.0
3570  **/
3571 void
3572 gtk_render_layout (GtkStyleContext *context,
3573                    cairo_t         *cr,
3574                    gdouble          x,
3575                    gdouble          y,
3576                    PangoLayout     *layout)
3577 {
3578   GtkThemingEngineClass *engine_class;
3579   GtkThemingEngine *engine;
3580   PangoRectangle extents;
3581
3582   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3583   g_return_if_fail (PANGO_IS_LAYOUT (layout));
3584   g_return_if_fail (cr != NULL);
3585
3586   engine = _gtk_css_engine_value_get_engine (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_ENGINE));
3587   engine_class = GTK_THEMING_ENGINE_GET_CLASS (engine);
3588
3589   cairo_save (cr);
3590
3591   pango_layout_get_extents (layout, &extents, NULL);
3592
3593   _gtk_theming_engine_set_context (engine, context);
3594   engine_class->render_layout (engine, cr, x, y, layout);
3595
3596   cairo_restore (cr);
3597 }
3598
3599 /**
3600  * gtk_render_line:
3601  * @context: a #GtkStyleContext
3602  * @cr: a #cairo_t
3603  * @x0: X coordinate for the origin of the line
3604  * @y0: Y coordinate for the origin of the line
3605  * @x1: X coordinate for the end of the line
3606  * @y1: Y coordinate for the end of the line
3607  *
3608  * Renders a line from (x0, y0) to (x1, y1).
3609  *
3610  * Since: 3.0
3611  **/
3612 void
3613 gtk_render_line (GtkStyleContext *context,
3614                  cairo_t         *cr,
3615                  gdouble          x0,
3616                  gdouble          y0,
3617                  gdouble          x1,
3618                  gdouble          y1)
3619 {
3620   GtkThemingEngineClass *engine_class;
3621   GtkThemingEngine *engine;
3622
3623   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3624   g_return_if_fail (cr != NULL);
3625
3626   engine = _gtk_css_engine_value_get_engine (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_ENGINE));
3627   engine_class = GTK_THEMING_ENGINE_GET_CLASS (engine);
3628
3629   cairo_save (cr);
3630
3631   _gtk_theming_engine_set_context (engine, context);
3632   engine_class->render_line (engine, cr, x0, y0, x1, y1);
3633
3634   cairo_restore (cr);
3635 }
3636
3637 /**
3638  * gtk_render_slider:
3639  * @context: a #GtkStyleContext
3640  * @cr: a #cairo_t
3641  * @x: X origin of the rectangle
3642  * @y: Y origin of the rectangle
3643  * @width: rectangle width
3644  * @height: rectangle height
3645  * @orientation: orientation of the slider
3646  *
3647  * Renders a slider (as in #GtkScale) in the rectangle defined by @x, @y,
3648  * @width, @height. @orientation defines whether the slider is vertical
3649  * or horizontal.
3650  *
3651  * <example>
3652  * <title>Typical slider rendering</title>
3653  * <inlinegraphic fileref="sliders.png" format="PNG"/>
3654  * </example>
3655  *
3656  * Since: 3.0
3657  **/
3658 void
3659 gtk_render_slider (GtkStyleContext *context,
3660                    cairo_t         *cr,
3661                    gdouble          x,
3662                    gdouble          y,
3663                    gdouble          width,
3664                    gdouble          height,
3665                    GtkOrientation   orientation)
3666 {
3667   GtkThemingEngineClass *engine_class;
3668   GtkThemingEngine *engine;
3669
3670   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3671   g_return_if_fail (cr != NULL);
3672
3673   if (width <= 0 || height <= 0)
3674     return;
3675
3676   engine = _gtk_css_engine_value_get_engine (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_ENGINE));
3677   engine_class = GTK_THEMING_ENGINE_GET_CLASS (engine);
3678
3679   cairo_save (cr);
3680
3681   _gtk_theming_engine_set_context (engine, context);
3682   engine_class->render_slider (engine, cr, x, y, width, height, orientation);
3683
3684   cairo_restore (cr);
3685 }
3686
3687 /**
3688  * gtk_render_frame_gap:
3689  * @context: a #GtkStyleContext
3690  * @cr: a #cairo_t
3691  * @x: X origin of the rectangle
3692  * @y: Y origin of the rectangle
3693  * @width: rectangle width
3694  * @height: rectangle height
3695  * @gap_side: side where the gap is
3696  * @xy0_gap: initial coordinate (X or Y depending on @gap_side) for the gap
3697  * @xy1_gap: end coordinate (X or Y depending on @gap_side) for the gap
3698  *
3699  * Renders a frame around the rectangle defined by (@x, @y, @width, @height),
3700  * leaving a gap on one side. @xy0_gap and @xy1_gap will mean X coordinates
3701  * for %GTK_POS_TOP and %GTK_POS_BOTTOM gap sides, and Y coordinates for
3702  * %GTK_POS_LEFT and %GTK_POS_RIGHT.
3703  *
3704  * <example>
3705  * <title>Typical rendering of a frame with a gap</title>
3706  * <inlinegraphic fileref="frame-gap.png" format="PNG"/>
3707  * </example>
3708  *
3709  * Since: 3.0
3710  **/
3711 void
3712 gtk_render_frame_gap (GtkStyleContext *context,
3713                       cairo_t         *cr,
3714                       gdouble          x,
3715                       gdouble          y,
3716                       gdouble          width,
3717                       gdouble          height,
3718                       GtkPositionType  gap_side,
3719                       gdouble          xy0_gap,
3720                       gdouble          xy1_gap)
3721 {
3722   GtkThemingEngineClass *engine_class;
3723   GtkThemingEngine *engine;
3724
3725   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3726   g_return_if_fail (cr != NULL);
3727   g_return_if_fail (xy0_gap <= xy1_gap);
3728   g_return_if_fail (xy0_gap >= 0);
3729
3730   if (width <= 0 || height <= 0)
3731     return;
3732
3733   if (gap_side == GTK_POS_LEFT ||
3734       gap_side == GTK_POS_RIGHT)
3735     g_return_if_fail (xy1_gap <= height);
3736   else
3737     g_return_if_fail (xy1_gap <= width);
3738
3739   engine = _gtk_css_engine_value_get_engine (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_ENGINE));
3740   engine_class = GTK_THEMING_ENGINE_GET_CLASS (engine);
3741
3742   cairo_save (cr);
3743
3744   _gtk_theming_engine_set_context (engine, context);
3745   engine_class->render_frame_gap (engine, cr,
3746                                   x, y, width, height, gap_side,
3747                                   xy0_gap, xy1_gap);
3748
3749   cairo_restore (cr);
3750 }
3751
3752 /**
3753  * gtk_render_extension:
3754  * @context: a #GtkStyleContext
3755  * @cr: a #cairo_t
3756  * @x: X origin of the rectangle
3757  * @y: Y origin of the rectangle
3758  * @width: rectangle width
3759  * @height: rectangle height
3760  * @gap_side: side where the gap is
3761  *
3762  * Renders a extension (as in a #GtkNotebook tab) in the rectangle
3763  * defined by @x, @y, @width, @height. The side where the extension
3764  * connects to is defined by @gap_side.
3765  *
3766  * <example>
3767  * <title>Typical extension rendering</title>
3768  * <inlinegraphic fileref="extensions.png" format="PNG"/>
3769  * </example>
3770  *
3771  * Since: 3.0
3772  **/
3773 void
3774 gtk_render_extension (GtkStyleContext *context,
3775                       cairo_t         *cr,
3776                       gdouble          x,
3777                       gdouble          y,
3778                       gdouble          width,
3779                       gdouble          height,
3780                       GtkPositionType  gap_side)
3781 {
3782   GtkThemingEngineClass *engine_class;
3783   GtkThemingEngine *engine;
3784
3785   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3786   g_return_if_fail (cr != NULL);
3787
3788   if (width <= 0 || height <= 0)
3789     return;
3790
3791   engine = _gtk_css_engine_value_get_engine (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_ENGINE));
3792   engine_class = GTK_THEMING_ENGINE_GET_CLASS (engine);
3793
3794   cairo_save (cr);
3795
3796   _gtk_theming_engine_set_context (engine, context);
3797   engine_class->render_extension (engine, cr, x, y, width, height, gap_side);
3798
3799   cairo_restore (cr);
3800 }
3801
3802 /**
3803  * gtk_render_handle:
3804  * @context: a #GtkStyleContext
3805  * @cr: a #cairo_t
3806  * @x: X origin of the rectangle
3807  * @y: Y origin of the rectangle
3808  * @width: rectangle width
3809  * @height: rectangle height
3810  *
3811  * Renders a handle (as in #GtkHandleBox, #GtkPaned and
3812  * #GtkWindow<!-- -->'s resize grip), in the rectangle
3813  * determined by @x, @y, @width, @height.
3814  *
3815  * <example>
3816  * <title>Handles rendered for the paned and grip classes</title>
3817  * <inlinegraphic fileref="handles.png" format="PNG"/>
3818  * </example>
3819  *
3820  * Since: 3.0
3821  **/
3822 void
3823 gtk_render_handle (GtkStyleContext *context,
3824                    cairo_t         *cr,
3825                    gdouble          x,
3826                    gdouble          y,
3827                    gdouble          width,
3828                    gdouble          height)
3829 {
3830   GtkThemingEngineClass *engine_class;
3831   GtkThemingEngine *engine;
3832
3833   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3834   g_return_if_fail (cr != NULL);
3835
3836   if (width <= 0 || height <= 0)
3837     return;
3838
3839   engine = _gtk_css_engine_value_get_engine (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_ENGINE));
3840   engine_class = GTK_THEMING_ENGINE_GET_CLASS (engine);
3841
3842   cairo_save (cr);
3843
3844   _gtk_theming_engine_set_context (engine, context);
3845   engine_class->render_handle (engine, cr, x, y, width, height);
3846
3847   cairo_restore (cr);
3848 }
3849
3850 /**
3851  * gtk_render_activity:
3852  * @context: a #GtkStyleContext
3853  * @cr: a #cairo_t
3854  * @x: X origin of the rectangle
3855  * @y: Y origin of the rectangle
3856  * @width: rectangle width
3857  * @height: rectangle height
3858  *
3859  * Renders an activity area (Such as in #GtkSpinner or the
3860  * fill line in #GtkRange), the state %GTK_STATE_FLAG_ACTIVE
3861  * determines whether there is activity going on.
3862  *
3863  * Since: 3.0
3864  **/
3865 void
3866 gtk_render_activity (GtkStyleContext *context,
3867                      cairo_t         *cr,
3868                      gdouble          x,
3869                      gdouble          y,
3870                      gdouble          width,
3871                      gdouble          height)
3872 {
3873   GtkThemingEngineClass *engine_class;
3874   GtkThemingEngine *engine;
3875
3876   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3877   g_return_if_fail (cr != NULL);
3878
3879   if (width <= 0 || height <= 0)
3880     return;
3881
3882   engine = _gtk_css_engine_value_get_engine (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_ENGINE));
3883   engine_class = GTK_THEMING_ENGINE_GET_CLASS (engine);
3884
3885   cairo_save (cr);
3886
3887   _gtk_theming_engine_set_context (engine, context);
3888   engine_class->render_activity (engine, cr, x, y, width, height);
3889
3890   cairo_restore (cr);
3891 }
3892
3893 /**
3894  * gtk_render_icon_pixbuf:
3895  * @context: a #GtkStyleContext
3896  * @source: the #GtkIconSource specifying the icon to render
3897  * @size: (type int): the size to render the icon at. A size of (GtkIconSize) -1
3898  *        means render at the size of the source and don't scale.
3899  *
3900  * Renders the icon specified by @source at the given @size, returning the result
3901  * in a pixbuf.
3902  *
3903  * Returns: (transfer full): a newly-created #GdkPixbuf containing the rendered icon
3904  *
3905  * Since: 3.0
3906  **/
3907 GdkPixbuf *
3908 gtk_render_icon_pixbuf (GtkStyleContext     *context,
3909                         const GtkIconSource *source,
3910                         GtkIconSize          size)
3911 {
3912   GtkThemingEngineClass *engine_class;
3913   GtkThemingEngine *engine;
3914
3915   g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), NULL);
3916   g_return_val_if_fail (size > GTK_ICON_SIZE_INVALID || size == -1, NULL);
3917   g_return_val_if_fail (source != NULL, NULL);
3918
3919   engine = _gtk_css_engine_value_get_engine (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_ENGINE));
3920   engine_class = GTK_THEMING_ENGINE_GET_CLASS (engine);
3921
3922   _gtk_theming_engine_set_context (engine, context);
3923   return engine_class->render_icon_pixbuf (engine, source, size);
3924 }
3925
3926 /**
3927  * gtk_render_icon:
3928  * @context: a #GtkStyleContext
3929  * @cr: a #cairo_t
3930  * @pixbuf: a #GdkPixbuf containing the icon to draw
3931  * @x: X position for the @pixbuf
3932  * @y: Y position for the @pixbuf
3933  *
3934  * Renders the icon in @pixbuf at the specified @x and @y coordinates.
3935  *
3936  * Since: 3.2
3937  **/
3938 void
3939 gtk_render_icon (GtkStyleContext *context,
3940                  cairo_t         *cr,
3941                  GdkPixbuf       *pixbuf,
3942                  gdouble          x,
3943                  gdouble          y)
3944 {
3945   GtkThemingEngineClass *engine_class;
3946   GtkThemingEngine *engine;
3947
3948   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3949   g_return_if_fail (cr != NULL);
3950
3951   engine = _gtk_css_engine_value_get_engine (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_ENGINE));
3952   engine_class = GTK_THEMING_ENGINE_GET_CLASS (engine);
3953
3954   cairo_save (cr);
3955
3956   _gtk_theming_engine_set_context (engine, context);
3957   engine_class->render_icon (engine, cr, pixbuf, x, y);
3958
3959   cairo_restore (cr);
3960 }
3961
3962 static void
3963 draw_insertion_cursor (GtkStyleContext *context,
3964                        cairo_t         *cr,
3965                        gdouble          x,
3966                        gdouble          y,
3967                        gdouble          height,
3968                        gboolean         is_primary,
3969                        PangoDirection   direction,
3970                        gboolean         draw_arrow)
3971
3972 {
3973   GdkRGBA primary_color;
3974   GdkRGBA secondary_color;
3975   gfloat cursor_aspect_ratio;
3976   gint stem_width;
3977   gint offset;
3978
3979   cairo_save (cr);
3980
3981   _gtk_style_context_get_cursor_color (context, &primary_color, &secondary_color);
3982   gdk_cairo_set_source_rgba (cr, is_primary ? &primary_color : &secondary_color);
3983
3984   /* When changing the shape or size of the cursor here,
3985    * propagate the changes to gtktextview.c:text_window_invalidate_cursors().
3986    */
3987
3988   gtk_style_context_get_style (context,
3989                                "cursor-aspect-ratio", &cursor_aspect_ratio,
3990                                NULL);
3991
3992   stem_width = height * cursor_aspect_ratio + 1;
3993
3994   /* put (stem_width % 2) on the proper side of the cursor */
3995   if (direction == PANGO_DIRECTION_LTR)
3996     offset = stem_width / 2;
3997   else
3998     offset = stem_width - stem_width / 2;
3999
4000   cairo_rectangle (cr, x - offset, y, stem_width, height);
4001   cairo_fill (cr);
4002
4003   if (draw_arrow)
4004     {
4005       gint arrow_width;
4006       gint ax, ay;
4007
4008       arrow_width = stem_width + 1;
4009
4010       if (direction == PANGO_DIRECTION_RTL)
4011         {
4012           ax = x - offset - 1;
4013           ay = y + height - arrow_width * 2 - arrow_width + 1;
4014
4015           cairo_move_to (cr, ax, ay + 1);
4016           cairo_line_to (cr, ax - arrow_width, ay + arrow_width);
4017           cairo_line_to (cr, ax, ay + 2 * arrow_width);
4018           cairo_fill (cr);
4019         }
4020       else if (direction == PANGO_DIRECTION_LTR)
4021         {
4022           ax = x + stem_width - offset;
4023           ay = y + height - arrow_width * 2 - arrow_width + 1;
4024
4025           cairo_move_to (cr, ax, ay + 1);
4026           cairo_line_to (cr, ax + arrow_width, ay + arrow_width);
4027           cairo_line_to (cr, ax, ay + 2 * arrow_width);
4028           cairo_fill (cr);
4029         }
4030       else
4031         g_assert_not_reached();
4032     }
4033
4034   cairo_restore (cr);
4035 }
4036
4037 /**
4038  * gtk_render_insertion_cursor:
4039  * @context: a #GtkStyleContext
4040  * @cr: a #cairo_t
4041  * @x: X origin
4042  * @y: Y origin
4043  * @layout: the #PangoLayout of the text
4044  * @index: the index in the #PangoLayout
4045  * @direction: the #PangoDirection of the text
4046  *
4047  * Draws a text caret on @cr at the specified index of @layout.
4048  *
4049  * Since: 3.4
4050  **/
4051 void
4052 gtk_render_insertion_cursor (GtkStyleContext *context,
4053                              cairo_t         *cr,
4054                              gdouble          x,
4055                              gdouble          y,
4056                              PangoLayout     *layout,
4057                              int              index,
4058                              PangoDirection   direction)
4059 {
4060   GtkStyleContextPrivate *priv;
4061   gboolean split_cursor;
4062   PangoRectangle strong_pos, weak_pos;
4063   PangoRectangle *cursor1, *cursor2;
4064   PangoDirection keymap_direction;
4065   PangoDirection direction2;
4066
4067   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
4068   g_return_if_fail (cr != NULL);
4069   g_return_if_fail (PANGO_IS_LAYOUT (layout));
4070   g_return_if_fail (index >= 0);
4071
4072   priv = context->priv;
4073
4074   g_object_get (gtk_settings_get_for_screen (priv->screen),
4075                 "gtk-split-cursor", &split_cursor,
4076                 NULL);
4077
4078   keymap_direction = gdk_keymap_get_direction (gdk_keymap_get_for_display (gdk_screen_get_display (priv->screen)));
4079
4080   pango_layout_get_cursor_pos (layout, index, &strong_pos, &weak_pos);
4081
4082   direction2 = PANGO_DIRECTION_NEUTRAL;
4083
4084   if (split_cursor)
4085     {
4086       cursor1 = &strong_pos;
4087
4088       if (strong_pos.x != weak_pos.x || strong_pos.y != weak_pos.y)
4089         {
4090           direction2 = (direction == PANGO_DIRECTION_LTR) ? PANGO_DIRECTION_RTL : PANGO_DIRECTION_LTR;
4091           cursor2 = &weak_pos;
4092         }
4093     }
4094   else
4095     {
4096       if (keymap_direction == direction)
4097         cursor1 = &strong_pos;
4098       else
4099         cursor1 = &weak_pos;
4100     }
4101
4102   draw_insertion_cursor (context,
4103                          cr,
4104                          x + PANGO_PIXELS (cursor1->x),
4105                          y + PANGO_PIXELS (cursor1->y),
4106                          PANGO_PIXELS (cursor1->height),
4107                          TRUE,
4108                          direction,
4109                          direction2 != PANGO_DIRECTION_NEUTRAL);
4110
4111   if (direction2 != PANGO_DIRECTION_NEUTRAL)
4112     {
4113       draw_insertion_cursor (context,
4114                              cr,
4115                              x + PANGO_PIXELS (cursor2->x),
4116                              y + PANGO_PIXELS (cursor2->y),
4117                              PANGO_PIXELS (cursor2->height),
4118                              FALSE,
4119                              direction2,
4120                              TRUE);
4121     }
4122 }
4123
4124 /**
4125  * gtk_draw_insertion_cursor:
4126  * @widget:  a #GtkWidget
4127  * @cr: cairo context to draw to
4128  * @location: location where to draw the cursor (@location->width is ignored)
4129  * @is_primary: if the cursor should be the primary cursor color.
4130  * @direction: whether the cursor is left-to-right or
4131  *             right-to-left. Should never be #GTK_TEXT_DIR_NONE
4132  * @draw_arrow: %TRUE to draw a directional arrow on the
4133  *        cursor. Should be %FALSE unless the cursor is split.
4134  *
4135  * Draws a text caret on @cr at @location. This is not a style function
4136  * but merely a convenience function for drawing the standard cursor shape.
4137  *
4138  * Since: 3.0
4139  * Deprecated: 3.4: Use gtk_render_insertion_cursor() instead.
4140  */
4141 void
4142 gtk_draw_insertion_cursor (GtkWidget          *widget,
4143                            cairo_t            *cr,
4144                            const GdkRectangle *location,
4145                            gboolean            is_primary,
4146                            GtkTextDirection    direction,
4147                            gboolean            draw_arrow)
4148 {
4149   GtkStyleContext *context;
4150
4151   g_return_if_fail (GTK_IS_WIDGET (widget));
4152   g_return_if_fail (cr != NULL);
4153   g_return_if_fail (location != NULL);
4154   g_return_if_fail (direction != GTK_TEXT_DIR_NONE);
4155
4156   context = gtk_widget_get_style_context (widget);
4157
4158   draw_insertion_cursor (context, cr,
4159                          location->x, location->y, location->height,
4160                          is_primary,
4161                          (direction == GTK_TEXT_DIR_RTL) ? PANGO_DIRECTION_RTL : PANGO_DIRECTION_LTR,
4162                          draw_arrow);
4163 }
4164
4165 static AtkAttributeSet *
4166 add_attribute (AtkAttributeSet  *attributes,
4167                AtkTextAttribute  attr,
4168                const gchar      *value)
4169 {
4170   AtkAttribute *at;
4171
4172   at = g_new (AtkAttribute, 1);
4173   at->name = g_strdup (atk_text_attribute_get_name (attr));
4174   at->value = g_strdup (value);
4175
4176   return g_slist_prepend (attributes, at);
4177 }
4178
4179 /*
4180  * _gtk_style_context_get_attributes:
4181  * @attributes: a #AtkAttributeSet to add attributes to
4182  * @context: the #GtkStyleContext to get attributes from
4183  * @flags: the state to use with @context
4184  *
4185  * Adds the foreground and background color from @context to
4186  * @attributes, after translating them to ATK attributes.
4187  *
4188  * This is a convenience function that can be used in
4189  * implementing the #AtkText interface in widgets.
4190  *
4191  * Returns: the modified #AtkAttributeSet
4192  */
4193 AtkAttributeSet *
4194 _gtk_style_context_get_attributes (AtkAttributeSet *attributes,
4195                                    GtkStyleContext *context,
4196                                    GtkStateFlags    flags)
4197 {
4198   GdkRGBA color;
4199   gchar *value;
4200
4201   gtk_style_context_get_background_color (context, flags, &color);
4202   value = g_strdup_printf ("%u,%u,%u",
4203                            (guint) ceil (color.red * 65536 - color.red),
4204                            (guint) ceil (color.green * 65536 - color.green),
4205                            (guint) ceil (color.blue * 65536 - color.blue));
4206   attributes = add_attribute (attributes, ATK_TEXT_ATTR_BG_COLOR, value);
4207   g_free (value);
4208
4209   gtk_style_context_get_color (context, flags, &color);
4210   value = g_strdup_printf ("%u,%u,%u",
4211                            (guint) ceil (color.red * 65536 - color.red),
4212                            (guint) ceil (color.green * 65536 - color.green),
4213                            (guint) ceil (color.blue * 65536 - color.blue));
4214   attributes = add_attribute (attributes, ATK_TEXT_ATTR_FG_COLOR, value);
4215   g_free (value);
4216
4217   return attributes;
4218 }