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