]> Pileus Git - ~andy/gtk/blob - gtk/gtkstylecontext.c
css: Remove old animation code
[~andy/gtk] / gtk / gtkstylecontext.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 2010 Carlos Garnacho <carlosg@gnome.org>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library. If not, 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                                         GtkSymbolicColor *color)
2528 {
2529   g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), FALSE);
2530   g_return_val_if_fail (color != NULL, FALSE);
2531
2532   return _gtk_symbolic_color_resolve_full (color,
2533                                            gtk_style_context_color_lookup_func,
2534                                            context);
2535 }
2536
2537
2538 gboolean
2539 _gtk_style_context_resolve_color (GtkStyleContext  *context,
2540                                   GtkSymbolicColor *color,
2541                                   GdkRGBA          *result)
2542 {
2543   GtkCssValue *val;
2544
2545   g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), FALSE);
2546   g_return_val_if_fail (color != NULL, FALSE);
2547   g_return_val_if_fail (result != NULL, FALSE);
2548
2549   val = _gtk_symbolic_color_resolve_full (color,
2550                                           gtk_style_context_color_lookup_func,
2551                                           context);
2552   if (val == NULL)
2553     return FALSE;
2554
2555   *result = *_gtk_css_rgba_value_get_rgba (val);
2556   _gtk_css_value_unref (val);
2557   return TRUE;
2558 }
2559
2560 /**
2561  * gtk_style_context_lookup_color:
2562  * @context: a #GtkStyleContext
2563  * @color_name: color name to lookup
2564  * @color: (out): Return location for the looked up color
2565  *
2566  * Looks up and resolves a color name in the @context color map.
2567  *
2568  * Returns: %TRUE if @color_name was found and resolved, %FALSE otherwise
2569  **/
2570 gboolean
2571 gtk_style_context_lookup_color (GtkStyleContext *context,
2572                                 const gchar     *color_name,
2573                                 GdkRGBA         *color)
2574 {
2575   GtkSymbolicColor *sym_color;
2576
2577   g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), FALSE);
2578   g_return_val_if_fail (color_name != NULL, FALSE);
2579   g_return_val_if_fail (color != NULL, FALSE);
2580
2581   sym_color = gtk_style_context_color_lookup_func (context, color_name);
2582   if (sym_color == NULL)
2583     return FALSE;
2584
2585   return _gtk_style_context_resolve_color (context, sym_color, color);
2586 }
2587
2588 /**
2589  * gtk_style_context_notify_state_change:
2590  * @context: a #GtkStyleContext
2591  * @window: a #GdkWindow
2592  * @region_id: (allow-none): animatable region to notify on, or %NULL.
2593  *     See gtk_style_context_push_animatable_region()
2594  * @state: state to trigger transition for
2595  * @state_value: %TRUE if @state is the state we are changing to,
2596  *     %FALSE if we are changing away from it
2597  *
2598  * Notifies a state change on @context, so if the current style makes use
2599  * of transition animations, one will be started so all rendered elements
2600  * under @region_id are animated for state @state being set to value
2601  * @state_value.
2602  *
2603  * The @window parameter is used in order to invalidate the rendered area
2604  * as the animation runs, so make sure it is the same window that is being
2605  * rendered on by the gtk_render_*() functions.
2606  *
2607  * If @region_id is %NULL, all rendered elements using @context will be
2608  * affected by this state transition.
2609  *
2610  * As a practical example, a #GtkButton notifying a state transition on
2611  * the prelight state:
2612  * <programlisting>
2613  * gtk_style_context_notify_state_change (context,
2614  *                                        gtk_widget_get_window (widget),
2615  *                                        NULL,
2616  *                                        GTK_STATE_PRELIGHT,
2617  *                                        button->in_button);
2618  * </programlisting>
2619  *
2620  * Can be handled in the CSS file like this:
2621  * <programlisting>
2622  * GtkButton {
2623  *     background-color: &num;f00
2624  * }
2625  *
2626  * GtkButton:hover {
2627  *     background-color: &num;fff;
2628  *     transition: 200ms linear
2629  * }
2630  * </programlisting>
2631  *
2632  * This combination will animate the button background from red to white
2633  * if a pointer enters the button, and back to red if the pointer leaves
2634  * the button.
2635  *
2636  * Note that @state is used when finding the transition parameters, which
2637  * is why the style places the transition under the :hover pseudo-class.
2638  *
2639  * Since: 3.0
2640  *
2641  * Deprecated: 3.6: This function does nothing.
2642  **/
2643 void
2644 gtk_style_context_notify_state_change (GtkStyleContext *context,
2645                                        GdkWindow       *window,
2646                                        gpointer         region_id,
2647                                        GtkStateType     state,
2648                                        gboolean         state_value)
2649 {
2650   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2651   g_return_if_fail (GDK_IS_WINDOW (window));
2652   g_return_if_fail (state > GTK_STATE_NORMAL && state <= GTK_STATE_FOCUSED);
2653   g_return_if_fail (context->priv->widget != NULL || context->priv->widget_path != NULL);
2654 }
2655
2656 /**
2657  * gtk_style_context_cancel_animations:
2658  * @context: a #GtkStyleContext
2659  * @region_id: (allow-none): animatable region to stop, or %NULL.
2660  *     See gtk_style_context_push_animatable_region()
2661  *
2662  * Stops all running animations for @region_id and all animatable
2663  * regions underneath.
2664  *
2665  * A %NULL @region_id will stop all ongoing animations in @context,
2666  * when dealing with a #GtkStyleContext obtained through
2667  * gtk_widget_get_style_context(), this is normally done for you
2668  * in all circumstances you would expect all widget to be stopped,
2669  * so this should be only used in complex widgets with different
2670  * animatable regions.
2671  *
2672  * Since: 3.0
2673  *
2674  * Deprecated: 3.6: This function does nothing.
2675  **/
2676 void
2677 gtk_style_context_cancel_animations (GtkStyleContext *context,
2678                                      gpointer         region_id)
2679 {
2680   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2681 }
2682
2683 /**
2684  * gtk_style_context_scroll_animations:
2685  * @context: a #GtkStyleContext
2686  * @window: a #GdkWindow used previously in
2687  *          gtk_style_context_notify_state_change()
2688  * @dx: Amount to scroll in the X axis
2689  * @dy: Amount to scroll in the Y axis
2690  *
2691  * This function is analogous to gdk_window_scroll(), and
2692  * should be called together with it so the invalidation
2693  * areas for any ongoing animation are scrolled together
2694  * with it.
2695  *
2696  * Since: 3.0
2697  *
2698  * Deprecated: 3.6: This function does nothing.
2699  **/
2700 void
2701 gtk_style_context_scroll_animations (GtkStyleContext *context,
2702                                      GdkWindow       *window,
2703                                      gint             dx,
2704                                      gint             dy)
2705 {
2706   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2707   g_return_if_fail (GDK_IS_WINDOW (window));
2708 }
2709
2710 /**
2711  * gtk_style_context_push_animatable_region:
2712  * @context: a #GtkStyleContext
2713  * @region_id: unique identifier for the animatable region
2714  *
2715  * Pushes an animatable region, so all further gtk_render_*() calls between
2716  * this call and the following gtk_style_context_pop_animatable_region()
2717  * will potentially show transition animations for this region if
2718  * gtk_style_context_notify_state_change() is called for a given state,
2719  * and the current theme/style defines transition animations for state
2720  * changes.
2721  *
2722  * The @region_id used must be unique in @context so the theming engine
2723  * can uniquely identify rendered elements subject to a state transition.
2724  *
2725  * Since: 3.0
2726  *
2727  * Deprecated: 3.6: This function does nothing.
2728  **/
2729 void
2730 gtk_style_context_push_animatable_region (GtkStyleContext *context,
2731                                           gpointer         region_id)
2732 {
2733   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2734   g_return_if_fail (region_id != NULL);
2735 }
2736
2737 /**
2738  * gtk_style_context_pop_animatable_region:
2739  * @context: a #GtkStyleContext
2740  *
2741  * Pops an animatable region from @context.
2742  * See gtk_style_context_push_animatable_region().
2743  *
2744  * Since: 3.0
2745  *
2746  * Deprecated: 3.6: This function does nothing.
2747  **/
2748 void
2749 gtk_style_context_pop_animatable_region (GtkStyleContext *context)
2750 {
2751   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2752 }
2753
2754 static void
2755 gtk_style_context_do_invalidate (GtkStyleContext *context,
2756                                  gboolean         clear_caches)
2757 {
2758   GtkStyleContextPrivate *priv;
2759
2760   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2761
2762   priv = context->priv;
2763
2764   /* Avoid reentrancy */
2765   if (priv->invalidating_context)
2766     return;
2767
2768   priv->invalidating_context = TRUE;
2769
2770   if (clear_caches)
2771     {
2772       GSList *list;
2773
2774       for (list = priv->info_stack; list; list = list->next)
2775         {
2776           GtkStyleInfo *info = list->data;
2777           info->data = NULL;
2778         }
2779       g_hash_table_remove_all (priv->style_data);
2780     }
2781
2782   g_signal_emit (context, signals[CHANGED], 0);
2783
2784   priv->invalidating_context = FALSE;
2785 }
2786
2787 void
2788 _gtk_style_context_validate (GtkStyleContext *context,
2789                              GtkCssChange     change)
2790 {
2791   GtkStyleContextPrivate *priv;
2792   GSList *list;
2793
2794   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2795
2796   priv = context->priv;
2797
2798   change |= priv->pending_changes;
2799
2800   if (!priv->invalid && change == 0)
2801     return;
2802
2803   priv->pending_changes = 0;
2804   gtk_style_context_set_invalid (context, FALSE);
2805
2806   /* Try to avoid invalidating if we can */
2807   if (change & GTK_STYLE_CONTEXT_RADICAL_CHANGE)
2808     {
2809       priv->relevant_changes = GTK_CSS_CHANGE_ANY;
2810     }
2811   else
2812     {
2813       if (priv->relevant_changes == GTK_CSS_CHANGE_ANY)
2814         {
2815           GtkWidgetPath *path;
2816           GtkCssMatcher matcher;
2817
2818           path = create_query_path (context);
2819           _gtk_css_matcher_init (&matcher, path, ((GtkStyleInfo *) priv->info_stack->data)->state_flags);
2820
2821           priv->relevant_changes = _gtk_style_provider_private_get_change (GTK_STYLE_PROVIDER_PRIVATE (priv->cascade),
2822                                                                            &matcher);
2823           priv->relevant_changes &= ~GTK_STYLE_CONTEXT_RADICAL_CHANGE;
2824
2825           gtk_widget_path_unref (path);
2826         }
2827     }
2828
2829   if (priv->relevant_changes & change)
2830     {
2831       GtkStyleInfo *info = priv->info_stack->data;
2832       gboolean clear_cache = ((priv->relevant_changes & change) & ~GTK_STYLE_CONTEXT_CACHED_CHANGE) != 0;
2833
2834       info->data = NULL;
2835       gtk_style_context_do_invalidate (context, clear_cache);
2836     }
2837
2838   change = _gtk_css_change_for_child (change);
2839   for (list = priv->children; list; list = list->next)
2840     {
2841       _gtk_style_context_validate (list->data, change);
2842     }
2843 }
2844
2845 void
2846 _gtk_style_context_queue_invalidate (GtkStyleContext *context,
2847                                      GtkCssChange     change)
2848 {
2849   GtkStyleContextPrivate *priv;
2850
2851   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2852   g_return_if_fail (change != 0);
2853
2854   priv = context->priv;
2855
2856   if (priv->widget == NULL && priv->widget_path == NULL)
2857     return;
2858
2859   priv->pending_changes |= change;
2860   gtk_style_context_set_invalid (context, TRUE);
2861 }
2862
2863 /**
2864  * gtk_style_context_invalidate:
2865  * @context: a #GtkStyleContext.
2866  *
2867  * Invalidates @context style information, so it will be reconstructed
2868  * again.
2869  *
2870  * If you're using a #GtkStyleContext returned from
2871  * gtk_widget_get_style_context(), you do not need to
2872  * call this yourself.
2873  *
2874  * Since: 3.0
2875  **/
2876 void
2877 gtk_style_context_invalidate (GtkStyleContext *context)
2878 {
2879   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2880
2881   gtk_style_context_do_invalidate (context, TRUE);
2882 }
2883
2884 /**
2885  * gtk_style_context_set_background:
2886  * @context: a #GtkStyleContext
2887  * @window: a #GdkWindow
2888  *
2889  * Sets the background of @window to the background pattern or
2890  * color specified in @context for its current state.
2891  *
2892  * Since: 3.0
2893  **/
2894 void
2895 gtk_style_context_set_background (GtkStyleContext *context,
2896                                   GdkWindow       *window)
2897 {
2898   GtkStateFlags state;
2899   cairo_pattern_t *pattern;
2900   GdkRGBA *color;
2901
2902   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2903   g_return_if_fail (GDK_IS_WINDOW (window));
2904
2905   state = gtk_style_context_get_state (context);
2906   gtk_style_context_get (context, state,
2907                          "background-image", &pattern,
2908                          NULL);
2909   if (pattern)
2910     {
2911       gdk_window_set_background_pattern (window, pattern);
2912       cairo_pattern_destroy (pattern);
2913       return;
2914     }
2915
2916   gtk_style_context_get (context, state,
2917                          "background-color", &color,
2918                          NULL);
2919   if (color)
2920     {
2921       gdk_window_set_background_rgba (window, color);
2922       gdk_rgba_free (color);
2923     }
2924 }
2925
2926 /**
2927  * gtk_style_context_get_color:
2928  * @context: a #GtkStyleContext
2929  * @state: state to retrieve the color for
2930  * @color: (out): return value for the foreground color
2931  *
2932  * Gets the foreground color for a given state.
2933  *
2934  * Since: 3.0
2935  **/
2936 void
2937 gtk_style_context_get_color (GtkStyleContext *context,
2938                              GtkStateFlags    state,
2939                              GdkRGBA         *color)
2940 {
2941   GdkRGBA *c;
2942
2943   g_return_if_fail (color != NULL);
2944   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2945
2946   gtk_style_context_get (context,
2947                          state,
2948                          "color", &c,
2949                          NULL);
2950
2951   *color = *c;
2952   gdk_rgba_free (c);
2953 }
2954
2955 /**
2956  * gtk_style_context_get_background_color:
2957  * @context: a #GtkStyleContext
2958  * @state: state to retrieve the color for
2959  * @color: (out): return value for the background color
2960  *
2961  * Gets the background color for a given state.
2962  *
2963  * Since: 3.0
2964  **/
2965 void
2966 gtk_style_context_get_background_color (GtkStyleContext *context,
2967                                         GtkStateFlags    state,
2968                                         GdkRGBA         *color)
2969 {
2970   GdkRGBA *c;
2971
2972   g_return_if_fail (color != NULL);
2973   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2974
2975   gtk_style_context_get (context,
2976                          state,
2977                          "background-color", &c,
2978                          NULL);
2979
2980   *color = *c;
2981   gdk_rgba_free (c);
2982 }
2983
2984 /**
2985  * gtk_style_context_get_border_color:
2986  * @context: a #GtkStyleContext
2987  * @state: state to retrieve the color for
2988  * @color: (out): return value for the border color
2989  *
2990  * Gets the border color for a given state.
2991  *
2992  * Since: 3.0
2993  **/
2994 void
2995 gtk_style_context_get_border_color (GtkStyleContext *context,
2996                                     GtkStateFlags    state,
2997                                     GdkRGBA         *color)
2998 {
2999   GdkRGBA *c;
3000
3001   g_return_if_fail (color != NULL);
3002   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3003
3004   gtk_style_context_get (context,
3005                          state,
3006                          "border-color", &c,
3007                          NULL);
3008
3009   *color = *c;
3010   gdk_rgba_free (c);
3011 }
3012
3013 /**
3014  * gtk_style_context_get_border:
3015  * @context: a #GtkStyleContext
3016  * @state: state to retrieve the border for
3017  * @border: (out): return value for the border settings
3018  *
3019  * Gets the border for a given state as a #GtkBorder.
3020  * See %GTK_STYLE_PROPERTY_BORDER_WIDTH.
3021  *
3022  * Since: 3.0
3023  **/
3024 void
3025 gtk_style_context_get_border (GtkStyleContext *context,
3026                               GtkStateFlags    state,
3027                               GtkBorder       *border)
3028 {
3029   int top, left, bottom, right;
3030
3031   g_return_if_fail (border != NULL);
3032   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3033
3034   gtk_style_context_get (context,
3035                          state,
3036                          "border-top-width", &top,
3037                          "border-left-width", &left,
3038                          "border-bottom-width", &bottom,
3039                          "border-right-width", &right,
3040                          NULL);
3041
3042   border->top = top;
3043   border->left = left;
3044   border->bottom = bottom;
3045   border->right = right;
3046 }
3047
3048 /**
3049  * gtk_style_context_get_padding:
3050  * @context: a #GtkStyleContext
3051  * @state: state to retrieve the padding for
3052  * @padding: (out): return value for the padding settings
3053  *
3054  * Gets the padding for a given state as a #GtkBorder.
3055  * See %GTK_STYLE_PROPERTY_PADDING.
3056  *
3057  * Since: 3.0
3058  **/
3059 void
3060 gtk_style_context_get_padding (GtkStyleContext *context,
3061                                GtkStateFlags    state,
3062                                GtkBorder       *padding)
3063 {
3064   int top, left, bottom, right;
3065
3066   g_return_if_fail (padding != NULL);
3067   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3068
3069   gtk_style_context_get (context,
3070                          state,
3071                          "padding-top", &top,
3072                          "padding-left", &left,
3073                          "padding-bottom", &bottom,
3074                          "padding-right", &right,
3075                          NULL);
3076
3077   padding->top = top;
3078   padding->left = left;
3079   padding->bottom = bottom;
3080   padding->right = right;
3081 }
3082
3083 /**
3084  * gtk_style_context_get_margin:
3085  * @context: a #GtkStyleContext
3086  * @state: state to retrieve the border for
3087  * @margin: (out): return value for the margin settings
3088  *
3089  * Gets the margin for a given state as a #GtkBorder.
3090  * See %GTK_STYLE_PROPERTY_MARGIN.
3091  *
3092  * Since: 3.0
3093  **/
3094 void
3095 gtk_style_context_get_margin (GtkStyleContext *context,
3096                               GtkStateFlags    state,
3097                               GtkBorder       *margin)
3098 {
3099   int top, left, bottom, right;
3100
3101   g_return_if_fail (margin != NULL);
3102   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3103
3104   gtk_style_context_get (context,
3105                          state,
3106                          "margin-top", &top,
3107                          "margin-left", &left,
3108                          "margin-bottom", &bottom,
3109                          "margin-right", &right,
3110                          NULL);
3111
3112   margin->top = top;
3113   margin->left = left;
3114   margin->bottom = bottom;
3115   margin->right = right;
3116 }
3117
3118 /**
3119  * gtk_style_context_get_font:
3120  * @context: a #GtkStyleContext
3121  * @state: state to retrieve the font for
3122  *
3123  * Returns the font description for a given state. The returned
3124  * object is const and will remain valid until the
3125  * #GtkStyleContext::changed signal happens.
3126  *
3127  * Returns: (transfer none): the #PangoFontDescription for the given
3128  *          state.  This object is owned by GTK+ and should not be
3129  *          freed.
3130  *
3131  * Since: 3.0
3132  **/
3133 const PangoFontDescription *
3134 gtk_style_context_get_font (GtkStyleContext *context,
3135                             GtkStateFlags    state)
3136 {
3137   GtkStyleContextPrivate *priv;
3138   StyleData *data;
3139   PangoFontDescription *description;
3140
3141   g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), NULL);
3142
3143   priv = context->priv;
3144   g_return_val_if_fail (priv->widget != NULL || priv->widget_path != NULL, NULL);
3145
3146   gtk_style_context_save (context);
3147   gtk_style_context_set_state (context, state);
3148   data = style_data_lookup (context);
3149   gtk_style_context_restore (context);
3150
3151   /* Yuck, fonts are created on-demand but we don't return a ref.
3152    * Do bad things to achieve this requirement */
3153   description = g_object_get_data (G_OBJECT (data->store), "font-cache-for-get_font");
3154   if (description == NULL)
3155     {
3156       gtk_style_context_get (context, state, "font", &description, NULL);
3157       g_object_set_data_full (G_OBJECT (data->store),
3158                               "font-cache-for-get_font",
3159                               description,
3160                               (GDestroyNotify) pango_font_description_free);
3161     }
3162   return description;
3163 }
3164
3165 static void
3166 get_cursor_color (GtkStyleContext *context,
3167                   gboolean         primary,
3168                   GdkRGBA         *color)
3169 {
3170   GdkColor *style_color;
3171
3172   gtk_style_context_get_style (context,
3173                                primary ? "cursor-color" : "secondary-cursor-color",
3174                                &style_color,
3175                                NULL);
3176
3177   if (style_color)
3178     {
3179       color->red = style_color->red / 65535.0;
3180       color->green = style_color->green / 65535.0;
3181       color->blue = style_color->blue / 65535.0;
3182       color->alpha = 1;
3183
3184       gdk_color_free (style_color);
3185     }
3186   else
3187     {
3188       gtk_style_context_get_color (context, GTK_STATE_FLAG_NORMAL, color);
3189
3190       if (!primary)
3191       {
3192         GdkRGBA bg;
3193
3194         gtk_style_context_get_background_color (context, GTK_STATE_FLAG_NORMAL, &bg);
3195
3196         color->red = (color->red + bg.red) * 0.5;
3197         color->green = (color->green + bg.green) * 0.5;
3198         color->blue = (color->blue + bg.blue) * 0.5;
3199       }
3200     }
3201 }
3202
3203 void
3204 _gtk_style_context_get_cursor_color (GtkStyleContext *context,
3205                                      GdkRGBA         *primary_color,
3206                                      GdkRGBA         *secondary_color)
3207 {
3208   if (primary_color)
3209     get_cursor_color (context, TRUE, primary_color);
3210
3211   if (secondary_color)
3212     get_cursor_color (context, FALSE, secondary_color);
3213 }
3214
3215 /* Paint methods */
3216
3217 /**
3218  * gtk_render_check:
3219  * @context: a #GtkStyleContext
3220  * @cr: a #cairo_t
3221  * @x: X origin of the rectangle
3222  * @y: Y origin of the rectangle
3223  * @width: rectangle width
3224  * @height: rectangle height
3225  *
3226  * Renders a checkmark (as in a #GtkCheckButton).
3227  *
3228  * The %GTK_STATE_FLAG_ACTIVE state determines whether the check is
3229  * on or off, and %GTK_STATE_FLAG_INCONSISTENT determines whether it
3230  * should be marked as undefined.
3231  *
3232  * <example>
3233  * <title>Typical checkmark rendering</title>
3234  * <inlinegraphic fileref="checks.png" format="PNG"/>
3235  * </example>
3236  *
3237  * Since: 3.0
3238  **/
3239 void
3240 gtk_render_check (GtkStyleContext *context,
3241                   cairo_t         *cr,
3242                   gdouble          x,
3243                   gdouble          y,
3244                   gdouble          width,
3245                   gdouble          height)
3246 {
3247   GtkStyleContextPrivate *priv;
3248   GtkThemingEngineClass *engine_class;
3249
3250   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3251   g_return_if_fail (cr != NULL);
3252
3253   if (width <= 0 || height <= 0)
3254     return;
3255
3256   priv = context->priv;
3257   engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
3258
3259   cairo_save (cr);
3260
3261
3262   _gtk_theming_engine_set_context (priv->theming_engine, context);
3263   engine_class->render_check (priv->theming_engine, cr,
3264                               x, y, width, height);
3265
3266   cairo_restore (cr);
3267 }
3268
3269 /**
3270  * gtk_render_option:
3271  * @context: a #GtkStyleContext
3272  * @cr: a #cairo_t
3273  * @x: X origin of the rectangle
3274  * @y: Y origin of the rectangle
3275  * @width: rectangle width
3276  * @height: rectangle height
3277  *
3278  * Renders an option mark (as in a #GtkRadioButton), the %GTK_STATE_FLAG_ACTIVE
3279  * state will determine whether the option is on or off, and
3280  * %GTK_STATE_FLAG_INCONSISTENT whether it should be marked as undefined.
3281  *
3282  * <example>
3283  * <title>Typical option mark rendering</title>
3284  * <inlinegraphic fileref="options.png" format="PNG"/>
3285  * </example>
3286  *
3287  * Since: 3.0
3288  **/
3289 void
3290 gtk_render_option (GtkStyleContext *context,
3291                    cairo_t         *cr,
3292                    gdouble          x,
3293                    gdouble          y,
3294                    gdouble          width,
3295                    gdouble          height)
3296 {
3297   GtkStyleContextPrivate *priv;
3298   GtkThemingEngineClass *engine_class;
3299
3300   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3301   g_return_if_fail (cr != NULL);
3302
3303   if (width <= 0 || height <= 0)
3304     return;
3305
3306   priv = context->priv;
3307   engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
3308
3309   cairo_save (cr);
3310
3311   _gtk_theming_engine_set_context (priv->theming_engine, context);
3312   engine_class->render_option (priv->theming_engine, cr,
3313                                x, y, width, height);
3314
3315   cairo_restore (cr);
3316 }
3317
3318 /**
3319  * gtk_render_arrow:
3320  * @context: a #GtkStyleContext
3321  * @cr: a #cairo_t
3322  * @angle: arrow angle from 0 to 2 * %G_PI, being 0 the arrow pointing to the north
3323  * @x: X origin of the render area
3324  * @y: Y origin of the render area
3325  * @size: square side for render area
3326  *
3327  * Renders an arrow pointing to @angle.
3328  *
3329  * <example>
3330  * <title>Typical arrow rendering at 0, 1&solidus;2 &pi;, &pi; and 3&solidus;2 &pi;</title>
3331  * <inlinegraphic fileref="arrows.png" format="PNG"/>
3332  * </example>
3333  *
3334  * Since: 3.0
3335  **/
3336 void
3337 gtk_render_arrow (GtkStyleContext *context,
3338                   cairo_t         *cr,
3339                   gdouble          angle,
3340                   gdouble          x,
3341                   gdouble          y,
3342                   gdouble          size)
3343 {
3344   GtkStyleContextPrivate *priv;
3345   GtkThemingEngineClass *engine_class;
3346
3347   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3348   g_return_if_fail (cr != NULL);
3349
3350   if (size <= 0)
3351     return;
3352
3353   priv = context->priv;
3354   engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
3355
3356   cairo_save (cr);
3357
3358   gtk_style_context_save (context);
3359   gtk_style_context_add_class (context, GTK_STYLE_CLASS_ARROW);
3360
3361   _gtk_theming_engine_set_context (priv->theming_engine, context);
3362   engine_class->render_arrow (priv->theming_engine, cr,
3363                               angle, x, y, size);
3364
3365   gtk_style_context_restore (context);
3366   cairo_restore (cr);
3367 }
3368
3369 /**
3370  * gtk_render_background:
3371  * @context: a #GtkStyleContext
3372  * @cr: a #cairo_t
3373  * @x: X origin of the rectangle
3374  * @y: Y origin of the rectangle
3375  * @width: rectangle width
3376  * @height: rectangle height
3377  *
3378  * Renders the background of an element.
3379  *
3380  * <example>
3381  * <title>Typical background rendering, showing the effect of
3382  * <parameter>background-image</parameter>,
3383  * <parameter>border-width</parameter> and
3384  * <parameter>border-radius</parameter></title>
3385  * <inlinegraphic fileref="background.png" format="PNG"/>
3386  * </example>
3387  *
3388  * Since: 3.0.
3389  **/
3390 void
3391 gtk_render_background (GtkStyleContext *context,
3392                        cairo_t         *cr,
3393                        gdouble          x,
3394                        gdouble          y,
3395                        gdouble          width,
3396                        gdouble          height)
3397 {
3398   GtkStyleContextPrivate *priv;
3399   GtkThemingEngineClass *engine_class;
3400
3401   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3402   g_return_if_fail (cr != NULL);
3403
3404   if (width <= 0 || height <= 0)
3405     return;
3406
3407   priv = context->priv;
3408   engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
3409
3410   cairo_save (cr);
3411
3412   _gtk_theming_engine_set_context (priv->theming_engine, context);
3413   engine_class->render_background (priv->theming_engine, cr, x, y, width, height);
3414
3415   cairo_restore (cr);
3416 }
3417
3418 /**
3419  * gtk_render_frame:
3420  * @context: a #GtkStyleContext
3421  * @cr: a #cairo_t
3422  * @x: X origin of the rectangle
3423  * @y: Y origin of the rectangle
3424  * @width: rectangle width
3425  * @height: rectangle height
3426  *
3427  * Renders a frame around the rectangle defined by @x, @y, @width, @height.
3428  *
3429  * <example>
3430  * <title>Examples of frame rendering, showing the effect of
3431  * <parameter>border-image</parameter>,
3432  * <parameter>border-color</parameter>,
3433  * <parameter>border-width</parameter>,
3434  * <parameter>border-radius</parameter> and
3435  * junctions</title>
3436  * <inlinegraphic fileref="frames.png" format="PNG"/>
3437  * </example>
3438  *
3439  * Since: 3.0
3440  **/
3441 void
3442 gtk_render_frame (GtkStyleContext *context,
3443                   cairo_t         *cr,
3444                   gdouble          x,
3445                   gdouble          y,
3446                   gdouble          width,
3447                   gdouble          height)
3448 {
3449   GtkStyleContextPrivate *priv;
3450   GtkThemingEngineClass *engine_class;
3451
3452   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3453   g_return_if_fail (cr != NULL);
3454
3455   if (width <= 0 || height <= 0)
3456     return;
3457
3458   priv = context->priv;
3459   engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
3460
3461   cairo_save (cr);
3462
3463   _gtk_theming_engine_set_context (priv->theming_engine, context);
3464   engine_class->render_frame (priv->theming_engine, cr, x, y, width, height);
3465
3466   cairo_restore (cr);
3467 }
3468
3469 /**
3470  * gtk_render_expander:
3471  * @context: a #GtkStyleContext
3472  * @cr: a #cairo_t
3473  * @x: X origin of the rectangle
3474  * @y: Y origin of the rectangle
3475  * @width: rectangle width
3476  * @height: rectangle height
3477  *
3478  * Renders an expander (as used in #GtkTreeView and #GtkExpander) in the area
3479  * defined by @x, @y, @width, @height. The state %GTK_STATE_FLAG_ACTIVE
3480  * determines whether the expander is collapsed or expanded.
3481  *
3482  * <example>
3483  * <title>Typical expander rendering</title>
3484  * <inlinegraphic fileref="expanders.png" format="PNG"/>
3485  * </example>
3486  *
3487  * Since: 3.0
3488  **/
3489 void
3490 gtk_render_expander (GtkStyleContext *context,
3491                      cairo_t         *cr,
3492                      gdouble          x,
3493                      gdouble          y,
3494                      gdouble          width,
3495                      gdouble          height)
3496 {
3497   GtkStyleContextPrivate *priv;
3498   GtkThemingEngineClass *engine_class;
3499
3500   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3501   g_return_if_fail (cr != NULL);
3502
3503   if (width <= 0 || height <= 0)
3504     return;
3505
3506   priv = context->priv;
3507   engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
3508
3509   cairo_save (cr);
3510
3511   _gtk_theming_engine_set_context (priv->theming_engine, context);
3512   engine_class->render_expander (priv->theming_engine, cr, x, y, width, height);
3513
3514   cairo_restore (cr);
3515 }
3516
3517 /**
3518  * gtk_render_focus:
3519  * @context: a #GtkStyleContext
3520  * @cr: a #cairo_t
3521  * @x: X origin of the rectangle
3522  * @y: Y origin of the rectangle
3523  * @width: rectangle width
3524  * @height: rectangle height
3525  *
3526  * Renders a focus indicator on the rectangle determined by @x, @y, @width, @height.
3527  * <example>
3528  * <title>Typical focus rendering</title>
3529  * <inlinegraphic fileref="focus.png" format="PNG"/>
3530  * </example>
3531  *
3532  * Since: 3.0
3533  **/
3534 void
3535 gtk_render_focus (GtkStyleContext *context,
3536                   cairo_t         *cr,
3537                   gdouble          x,
3538                   gdouble          y,
3539                   gdouble          width,
3540                   gdouble          height)
3541 {
3542   GtkStyleContextPrivate *priv;
3543   GtkThemingEngineClass *engine_class;
3544
3545   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3546   g_return_if_fail (cr != NULL);
3547
3548   if (width <= 0 || height <= 0)
3549     return;
3550
3551   priv = context->priv;
3552   engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
3553
3554   cairo_save (cr);
3555
3556   _gtk_theming_engine_set_context (priv->theming_engine, context);
3557   engine_class->render_focus (priv->theming_engine, cr, x, y, width, height);
3558
3559   cairo_restore (cr);
3560 }
3561
3562 /**
3563  * gtk_render_layout:
3564  * @context: a #GtkStyleContext
3565  * @cr: a #cairo_t
3566  * @x: X origin
3567  * @y: Y origin
3568  * @layout: the #PangoLayout to render
3569  *
3570  * Renders @layout on the coordinates @x, @y
3571  *
3572  * Since: 3.0
3573  **/
3574 void
3575 gtk_render_layout (GtkStyleContext *context,
3576                    cairo_t         *cr,
3577                    gdouble          x,
3578                    gdouble          y,
3579                    PangoLayout     *layout)
3580 {
3581   GtkStyleContextPrivate *priv;
3582   GtkThemingEngineClass *engine_class;
3583   PangoRectangle extents;
3584
3585   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3586   g_return_if_fail (PANGO_IS_LAYOUT (layout));
3587   g_return_if_fail (cr != NULL);
3588
3589   priv = context->priv;
3590   engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
3591
3592   cairo_save (cr);
3593
3594   pango_layout_get_extents (layout, &extents, NULL);
3595
3596   _gtk_theming_engine_set_context (priv->theming_engine, context);
3597   engine_class->render_layout (priv->theming_engine, cr, x, y, layout);
3598
3599   cairo_restore (cr);
3600 }
3601
3602 /**
3603  * gtk_render_line:
3604  * @context: a #GtkStyleContext
3605  * @cr: a #cairo_t
3606  * @x0: X coordinate for the origin of the line
3607  * @y0: Y coordinate for the origin of the line
3608  * @x1: X coordinate for the end of the line
3609  * @y1: Y coordinate for the end of the line
3610  *
3611  * Renders a line from (x0, y0) to (x1, y1).
3612  *
3613  * Since: 3.0
3614  **/
3615 void
3616 gtk_render_line (GtkStyleContext *context,
3617                  cairo_t         *cr,
3618                  gdouble          x0,
3619                  gdouble          y0,
3620                  gdouble          x1,
3621                  gdouble          y1)
3622 {
3623   GtkStyleContextPrivate *priv;
3624   GtkThemingEngineClass *engine_class;
3625
3626   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3627   g_return_if_fail (cr != NULL);
3628
3629   priv = context->priv;
3630   engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
3631
3632   cairo_save (cr);
3633
3634   _gtk_theming_engine_set_context (priv->theming_engine, context);
3635   engine_class->render_line (priv->theming_engine, cr, x0, y0, x1, y1);
3636
3637   cairo_restore (cr);
3638 }
3639
3640 /**
3641  * gtk_render_slider:
3642  * @context: a #GtkStyleContext
3643  * @cr: a #cairo_t
3644  * @x: X origin of the rectangle
3645  * @y: Y origin of the rectangle
3646  * @width: rectangle width
3647  * @height: rectangle height
3648  * @orientation: orientation of the slider
3649  *
3650  * Renders a slider (as in #GtkScale) in the rectangle defined by @x, @y,
3651  * @width, @height. @orientation defines whether the slider is vertical
3652  * or horizontal.
3653  *
3654  * <example>
3655  * <title>Typical slider rendering</title>
3656  * <inlinegraphic fileref="sliders.png" format="PNG"/>
3657  * </example>
3658  *
3659  * Since: 3.0
3660  **/
3661 void
3662 gtk_render_slider (GtkStyleContext *context,
3663                    cairo_t         *cr,
3664                    gdouble          x,
3665                    gdouble          y,
3666                    gdouble          width,
3667                    gdouble          height,
3668                    GtkOrientation   orientation)
3669 {
3670   GtkStyleContextPrivate *priv;
3671   GtkThemingEngineClass *engine_class;
3672
3673   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3674   g_return_if_fail (cr != NULL);
3675
3676   if (width <= 0 || height <= 0)
3677     return;
3678
3679   priv = context->priv;
3680   engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
3681
3682   cairo_save (cr);
3683
3684   _gtk_theming_engine_set_context (priv->theming_engine, context);
3685   engine_class->render_slider (priv->theming_engine, cr, x, y, width, height, orientation);
3686
3687   cairo_restore (cr);
3688 }
3689
3690 /**
3691  * gtk_render_frame_gap:
3692  * @context: a #GtkStyleContext
3693  * @cr: a #cairo_t
3694  * @x: X origin of the rectangle
3695  * @y: Y origin of the rectangle
3696  * @width: rectangle width
3697  * @height: rectangle height
3698  * @gap_side: side where the gap is
3699  * @xy0_gap: initial coordinate (X or Y depending on @gap_side) for the gap
3700  * @xy1_gap: end coordinate (X or Y depending on @gap_side) for the gap
3701  *
3702  * Renders a frame around the rectangle defined by (@x, @y, @width, @height),
3703  * leaving a gap on one side. @xy0_gap and @xy1_gap will mean X coordinates
3704  * for %GTK_POS_TOP and %GTK_POS_BOTTOM gap sides, and Y coordinates for
3705  * %GTK_POS_LEFT and %GTK_POS_RIGHT.
3706  *
3707  * <example>
3708  * <title>Typical rendering of a frame with a gap</title>
3709  * <inlinegraphic fileref="frame-gap.png" format="PNG"/>
3710  * </example>
3711  *
3712  * Since: 3.0
3713  **/
3714 void
3715 gtk_render_frame_gap (GtkStyleContext *context,
3716                       cairo_t         *cr,
3717                       gdouble          x,
3718                       gdouble          y,
3719                       gdouble          width,
3720                       gdouble          height,
3721                       GtkPositionType  gap_side,
3722                       gdouble          xy0_gap,
3723                       gdouble          xy1_gap)
3724 {
3725   GtkStyleContextPrivate *priv;
3726   GtkThemingEngineClass *engine_class;
3727
3728   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3729   g_return_if_fail (cr != NULL);
3730   g_return_if_fail (xy0_gap <= xy1_gap);
3731   g_return_if_fail (xy0_gap >= 0);
3732
3733   if (width <= 0 || height <= 0)
3734     return;
3735
3736   if (gap_side == GTK_POS_LEFT ||
3737       gap_side == GTK_POS_RIGHT)
3738     g_return_if_fail (xy1_gap <= height);
3739   else
3740     g_return_if_fail (xy1_gap <= width);
3741
3742   priv = context->priv;
3743   engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
3744
3745   cairo_save (cr);
3746
3747   _gtk_theming_engine_set_context (priv->theming_engine, context);
3748   engine_class->render_frame_gap (priv->theming_engine, cr,
3749                                   x, y, width, height, gap_side,
3750                                   xy0_gap, xy1_gap);
3751
3752   cairo_restore (cr);
3753 }
3754
3755 /**
3756  * gtk_render_extension:
3757  * @context: a #GtkStyleContext
3758  * @cr: a #cairo_t
3759  * @x: X origin of the rectangle
3760  * @y: Y origin of the rectangle
3761  * @width: rectangle width
3762  * @height: rectangle height
3763  * @gap_side: side where the gap is
3764  *
3765  * Renders a extension (as in a #GtkNotebook tab) in the rectangle
3766  * defined by @x, @y, @width, @height. The side where the extension
3767  * connects to is defined by @gap_side.
3768  *
3769  * <example>
3770  * <title>Typical extension rendering</title>
3771  * <inlinegraphic fileref="extensions.png" format="PNG"/>
3772  * </example>
3773  *
3774  * Since: 3.0
3775  **/
3776 void
3777 gtk_render_extension (GtkStyleContext *context,
3778                       cairo_t         *cr,
3779                       gdouble          x,
3780                       gdouble          y,
3781                       gdouble          width,
3782                       gdouble          height,
3783                       GtkPositionType  gap_side)
3784 {
3785   GtkStyleContextPrivate *priv;
3786   GtkThemingEngineClass *engine_class;
3787
3788   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3789   g_return_if_fail (cr != NULL);
3790
3791   if (width <= 0 || height <= 0)
3792     return;
3793
3794   priv = context->priv;
3795   engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
3796
3797   cairo_save (cr);
3798
3799   _gtk_theming_engine_set_context (priv->theming_engine, context);
3800   engine_class->render_extension (priv->theming_engine, cr, x, y, width, height, gap_side);
3801
3802   cairo_restore (cr);
3803 }
3804
3805 /**
3806  * gtk_render_handle:
3807  * @context: a #GtkStyleContext
3808  * @cr: a #cairo_t
3809  * @x: X origin of the rectangle
3810  * @y: Y origin of the rectangle
3811  * @width: rectangle width
3812  * @height: rectangle height
3813  *
3814  * Renders a handle (as in #GtkHandleBox, #GtkPaned and
3815  * #GtkWindow<!-- -->'s resize grip), in the rectangle
3816  * determined by @x, @y, @width, @height.
3817  *
3818  * <example>
3819  * <title>Handles rendered for the paned and grip classes</title>
3820  * <inlinegraphic fileref="handles.png" format="PNG"/>
3821  * </example>
3822  *
3823  * Since: 3.0
3824  **/
3825 void
3826 gtk_render_handle (GtkStyleContext *context,
3827                    cairo_t         *cr,
3828                    gdouble          x,
3829                    gdouble          y,
3830                    gdouble          width,
3831                    gdouble          height)
3832 {
3833   GtkStyleContextPrivate *priv;
3834   GtkThemingEngineClass *engine_class;
3835
3836   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3837   g_return_if_fail (cr != NULL);
3838
3839   if (width <= 0 || height <= 0)
3840     return;
3841
3842   priv = context->priv;
3843   engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
3844
3845   cairo_save (cr);
3846
3847   _gtk_theming_engine_set_context (priv->theming_engine, context);
3848   engine_class->render_handle (priv->theming_engine, cr, x, y, width, height);
3849
3850   cairo_restore (cr);
3851 }
3852
3853 /**
3854  * gtk_render_activity:
3855  * @context: a #GtkStyleContext
3856  * @cr: a #cairo_t
3857  * @x: X origin of the rectangle
3858  * @y: Y origin of the rectangle
3859  * @width: rectangle width
3860  * @height: rectangle height
3861  *
3862  * Renders an activity area (Such as in #GtkSpinner or the
3863  * fill line in #GtkRange), the state %GTK_STATE_FLAG_ACTIVE
3864  * determines whether there is activity going on.
3865  *
3866  * Since: 3.0
3867  **/
3868 void
3869 gtk_render_activity (GtkStyleContext *context,
3870                      cairo_t         *cr,
3871                      gdouble          x,
3872                      gdouble          y,
3873                      gdouble          width,
3874                      gdouble          height)
3875 {
3876   GtkStyleContextPrivate *priv;
3877   GtkThemingEngineClass *engine_class;
3878
3879   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3880   g_return_if_fail (cr != NULL);
3881
3882   if (width <= 0 || height <= 0)
3883     return;
3884
3885   priv = context->priv;
3886   engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
3887
3888   cairo_save (cr);
3889
3890   _gtk_theming_engine_set_context (priv->theming_engine, context);
3891   engine_class->render_activity (priv->theming_engine, cr, x, y, width, height);
3892
3893   cairo_restore (cr);
3894 }
3895
3896 /**
3897  * gtk_render_icon_pixbuf:
3898  * @context: a #GtkStyleContext
3899  * @source: the #GtkIconSource specifying the icon to render
3900  * @size: (type int): the size to render the icon at. A size of (GtkIconSize) -1
3901  *        means render at the size of the source and don't scale.
3902  *
3903  * Renders the icon specified by @source at the given @size, returning the result
3904  * in a pixbuf.
3905  *
3906  * Returns: (transfer full): a newly-created #GdkPixbuf containing the rendered icon
3907  *
3908  * Since: 3.0
3909  **/
3910 GdkPixbuf *
3911 gtk_render_icon_pixbuf (GtkStyleContext     *context,
3912                         const GtkIconSource *source,
3913                         GtkIconSize          size)
3914 {
3915   GtkStyleContextPrivate *priv;
3916   GtkThemingEngineClass *engine_class;
3917
3918   g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), NULL);
3919   g_return_val_if_fail (size > GTK_ICON_SIZE_INVALID || size == -1, NULL);
3920   g_return_val_if_fail (source != NULL, NULL);
3921
3922   priv = context->priv;
3923   engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
3924
3925   _gtk_theming_engine_set_context (priv->theming_engine, context);
3926   return engine_class->render_icon_pixbuf (priv->theming_engine, source, size);
3927 }
3928
3929 /**
3930  * gtk_render_icon:
3931  * @context: a #GtkStyleContext
3932  * @cr: a #cairo_t
3933  * @pixbuf: a #GdkPixbuf containing the icon to draw
3934  * @x: X position for the @pixbuf
3935  * @y: Y position for the @pixbuf
3936  *
3937  * Renders the icon in @pixbuf at the specified @x and @y coordinates.
3938  *
3939  * Since: 3.2
3940  **/
3941 void
3942 gtk_render_icon (GtkStyleContext *context,
3943                  cairo_t         *cr,
3944                  GdkPixbuf       *pixbuf,
3945                  gdouble          x,
3946                  gdouble          y)
3947 {
3948   GtkStyleContextPrivate *priv;
3949   GtkThemingEngineClass *engine_class;
3950
3951   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3952   g_return_if_fail (cr != NULL);
3953
3954   priv = context->priv;
3955   engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
3956
3957   cairo_save (cr);
3958
3959   _gtk_theming_engine_set_context (priv->theming_engine, context);
3960   engine_class->render_icon (priv->theming_engine, cr, pixbuf, x, y);
3961
3962   cairo_restore (cr);
3963 }
3964
3965 static void
3966 draw_insertion_cursor (GtkStyleContext *context,
3967                        cairo_t         *cr,
3968                        gdouble          x,
3969                        gdouble          y,
3970                        gdouble          height,
3971                        gboolean         is_primary,
3972                        PangoDirection   direction,
3973                        gboolean         draw_arrow)
3974
3975 {
3976   GdkRGBA primary_color;
3977   GdkRGBA secondary_color;
3978   gfloat cursor_aspect_ratio;
3979   gint stem_width;
3980   gint offset;
3981
3982   cairo_save (cr);
3983
3984   _gtk_style_context_get_cursor_color (context, &primary_color, &secondary_color);
3985   gdk_cairo_set_source_rgba (cr, is_primary ? &primary_color : &secondary_color);
3986
3987   /* When changing the shape or size of the cursor here,
3988    * propagate the changes to gtktextview.c:text_window_invalidate_cursors().
3989    */
3990
3991   gtk_style_context_get_style (context,
3992                                "cursor-aspect-ratio", &cursor_aspect_ratio,
3993                                NULL);
3994
3995   stem_width = height * cursor_aspect_ratio + 1;
3996
3997   /* put (stem_width % 2) on the proper side of the cursor */
3998   if (direction == PANGO_DIRECTION_LTR)
3999     offset = stem_width / 2;
4000   else
4001     offset = stem_width - stem_width / 2;
4002
4003   cairo_rectangle (cr, x - offset, y, stem_width, height);
4004   cairo_fill (cr);
4005
4006   if (draw_arrow)
4007     {
4008       gint arrow_width;
4009       gint ax, ay;
4010
4011       arrow_width = stem_width + 1;
4012
4013       if (direction == PANGO_DIRECTION_RTL)
4014         {
4015           ax = x - offset - 1;
4016           ay = y + height - arrow_width * 2 - arrow_width + 1;
4017
4018           cairo_move_to (cr, ax, ay + 1);
4019           cairo_line_to (cr, ax - arrow_width, ay + arrow_width);
4020           cairo_line_to (cr, ax, ay + 2 * arrow_width);
4021           cairo_fill (cr);
4022         }
4023       else if (direction == PANGO_DIRECTION_LTR)
4024         {
4025           ax = x + stem_width - offset;
4026           ay = y + height - arrow_width * 2 - arrow_width + 1;
4027
4028           cairo_move_to (cr, ax, ay + 1);
4029           cairo_line_to (cr, ax + arrow_width, ay + arrow_width);
4030           cairo_line_to (cr, ax, ay + 2 * arrow_width);
4031           cairo_fill (cr);
4032         }
4033       else
4034         g_assert_not_reached();
4035     }
4036
4037   cairo_restore (cr);
4038 }
4039
4040 /**
4041  * gtk_render_insertion_cursor:
4042  * @context: a #GtkStyleContext
4043  * @cr: a #cairo_t
4044  * @x: X origin
4045  * @y: Y origin
4046  * @layout: the #PangoLayout of the text
4047  * @index: the index in the #PangoLayout
4048  * @direction: the #PangoDirection of the text
4049  *
4050  * Draws a text caret on @cr at the specified index of @layout.
4051  *
4052  * Since: 3.4
4053  **/
4054 void
4055 gtk_render_insertion_cursor (GtkStyleContext *context,
4056                              cairo_t         *cr,
4057                              gdouble          x,
4058                              gdouble          y,
4059                              PangoLayout     *layout,
4060                              int              index,
4061                              PangoDirection   direction)
4062 {
4063   GtkStyleContextPrivate *priv;
4064   gboolean split_cursor;
4065   PangoRectangle strong_pos, weak_pos;
4066   PangoRectangle *cursor1, *cursor2;
4067   PangoDirection keymap_direction;
4068   PangoDirection direction2;
4069
4070   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
4071   g_return_if_fail (cr != NULL);
4072   g_return_if_fail (PANGO_IS_LAYOUT (layout));
4073   g_return_if_fail (index >= 0);
4074
4075   priv = context->priv;
4076
4077   g_object_get (gtk_settings_get_for_screen (priv->screen),
4078                 "gtk-split-cursor", &split_cursor,
4079                 NULL);
4080
4081   keymap_direction = gdk_keymap_get_direction (gdk_keymap_get_for_display (gdk_screen_get_display (priv->screen)));
4082
4083   pango_layout_get_cursor_pos (layout, index, &strong_pos, &weak_pos);
4084
4085   direction2 = PANGO_DIRECTION_NEUTRAL;
4086
4087   if (split_cursor)
4088     {
4089       cursor1 = &strong_pos;
4090
4091       if (strong_pos.x != weak_pos.x || strong_pos.y != weak_pos.y)
4092         {
4093           direction2 = (direction == PANGO_DIRECTION_LTR) ? PANGO_DIRECTION_RTL : PANGO_DIRECTION_LTR;
4094           cursor2 = &weak_pos;
4095         }
4096     }
4097   else
4098     {
4099       if (keymap_direction == direction)
4100         cursor1 = &strong_pos;
4101       else
4102         cursor1 = &weak_pos;
4103     }
4104
4105   draw_insertion_cursor (context,
4106                          cr,
4107                          x + PANGO_PIXELS (cursor1->x),
4108                          y + PANGO_PIXELS (cursor1->y),
4109                          PANGO_PIXELS (cursor1->height),
4110                          TRUE,
4111                          direction,
4112                          direction2 != PANGO_DIRECTION_NEUTRAL);
4113
4114   if (direction2 != PANGO_DIRECTION_NEUTRAL)
4115     {
4116       draw_insertion_cursor (context,
4117                              cr,
4118                              x + PANGO_PIXELS (cursor2->x),
4119                              y + PANGO_PIXELS (cursor2->y),
4120                              PANGO_PIXELS (cursor2->height),
4121                              FALSE,
4122                              direction2,
4123                              TRUE);
4124     }
4125 }
4126
4127 /**
4128  * gtk_draw_insertion_cursor:
4129  * @widget:  a #GtkWidget
4130  * @cr: cairo context to draw to
4131  * @location: location where to draw the cursor (@location->width is ignored)
4132  * @is_primary: if the cursor should be the primary cursor color.
4133  * @direction: whether the cursor is left-to-right or
4134  *             right-to-left. Should never be #GTK_TEXT_DIR_NONE
4135  * @draw_arrow: %TRUE to draw a directional arrow on the
4136  *        cursor. Should be %FALSE unless the cursor is split.
4137  *
4138  * Draws a text caret on @cr at @location. This is not a style function
4139  * but merely a convenience function for drawing the standard cursor shape.
4140  *
4141  * Since: 3.0
4142  * Deprecated: 3.4: Use gtk_render_insertion_cursor() instead.
4143  */
4144 void
4145 gtk_draw_insertion_cursor (GtkWidget          *widget,
4146                            cairo_t            *cr,
4147                            const GdkRectangle *location,
4148                            gboolean            is_primary,
4149                            GtkTextDirection    direction,
4150                            gboolean            draw_arrow)
4151 {
4152   GtkStyleContext *context;
4153
4154   g_return_if_fail (GTK_IS_WIDGET (widget));
4155   g_return_if_fail (cr != NULL);
4156   g_return_if_fail (location != NULL);
4157   g_return_if_fail (direction != GTK_TEXT_DIR_NONE);
4158
4159   context = gtk_widget_get_style_context (widget);
4160
4161   draw_insertion_cursor (context, cr,
4162                          location->x, location->y, location->height,
4163                          is_primary,
4164                          (direction == GTK_TEXT_DIR_RTL) ? PANGO_DIRECTION_RTL : PANGO_DIRECTION_LTR,
4165                          draw_arrow);
4166 }
4167
4168 static AtkAttributeSet *
4169 add_attribute (AtkAttributeSet  *attributes,
4170                AtkTextAttribute  attr,
4171                const gchar      *value)
4172 {
4173   AtkAttribute *at;
4174
4175   at = g_new (AtkAttribute, 1);
4176   at->name = g_strdup (atk_text_attribute_get_name (attr));
4177   at->value = g_strdup (value);
4178
4179   return g_slist_prepend (attributes, at);
4180 }
4181
4182 /*
4183  * _gtk_style_context_get_attributes:
4184  * @attributes: a #AtkAttributeSet to add attributes to
4185  * @context: the #GtkStyleContext to get attributes from
4186  * @flags: the state to use with @context
4187  *
4188  * Adds the foreground and background color from @context to
4189  * @attributes, after translating them to ATK attributes.
4190  *
4191  * This is a convenience function that can be used in
4192  * implementing the #AtkText interface in widgets.
4193  *
4194  * Returns: the modified #AtkAttributeSet
4195  */
4196 AtkAttributeSet *
4197 _gtk_style_context_get_attributes (AtkAttributeSet *attributes,
4198                                    GtkStyleContext *context,
4199                                    GtkStateFlags    flags)
4200 {
4201   GdkRGBA color;
4202   gchar *value;
4203
4204   gtk_style_context_get_background_color (context, flags, &color);
4205   value = g_strdup_printf ("%u,%u,%u",
4206                            (guint) ceil (color.red * 65536 - color.red),
4207                            (guint) ceil (color.green * 65536 - color.green),
4208                            (guint) ceil (color.blue * 65536 - color.blue));
4209   attributes = add_attribute (attributes, ATK_TEXT_ATTR_BG_COLOR, value);
4210   g_free (value);
4211
4212   gtk_style_context_get_color (context, flags, &color);
4213   value = g_strdup_printf ("%u,%u,%u",
4214                            (guint) ceil (color.red * 65536 - color.red),
4215                            (guint) ceil (color.green * 65536 - color.green),
4216                            (guint) ceil (color.blue * 65536 - color.blue));
4217   attributes = add_attribute (attributes, ATK_TEXT_ATTR_FG_COLOR, value);
4218   g_free (value);
4219
4220   return attributes;
4221 }