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