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