1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 2010 Carlos Garnacho <carlosg@gnome.org>
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.
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.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
23 #include <gobject/gvaluecollector.h>
25 #include "gtkstylecontextprivate.h"
26 #include "gtkcssrgbavalueprivate.h"
27 #include "gtkstylepropertiesprivate.h"
28 #include "gtktypebuiltins.h"
29 #include "gtkthemingengineprivate.h"
31 #include "gtkwidget.h"
32 #include "gtkwindow.h"
33 #include "gtkprivate.h"
34 #include "gtksymboliccolorprivate.h"
35 #include "gtkanimationdescription.h"
36 #include "gtkcssnumbervalueprivate.h"
37 #include "gtktimeline.h"
38 #include "gtkiconfactory.h"
39 #include "gtkwidgetpath.h"
40 #include "gtkwidgetprivate.h"
41 #include "gtkstylecascadeprivate.h"
42 #include "gtkstyleproviderprivate.h"
43 #include "gtksettings.h"
46 * SECTION:gtkstylecontext
47 * @Short_description: Rendering UI elements
48 * @Title: GtkStyleContext
50 * #GtkStyleContext is an object that stores styling information affecting
51 * a widget defined by #GtkWidgetPath.
53 * In order to construct the final style information, #GtkStyleContext
54 * queries information from all attached #GtkStyleProviders. Style providers
55 * can be either attached explicitly to the context through
56 * gtk_style_context_add_provider(), or to the screen through
57 * gtk_style_context_add_provider_for_screen(). The resulting style is a
58 * combination of all providers' information in priority order.
60 * For GTK+ widgets, any #GtkStyleContext returned by
61 * gtk_widget_get_style_context() will already have a #GtkWidgetPath, a
62 * #GdkScreen and RTL/LTR information set. The style context will be also
63 * updated automatically if any of these settings change on the widget.
65 * If you are using the theming layer standalone, you will need to set a
66 * widget path and a screen yourself to the created style context through
67 * gtk_style_context_set_path() and gtk_style_context_set_screen(), as well
68 * as updating the context yourself using gtk_style_context_invalidate()
69 * whenever any of the conditions change, such as a change in the
70 * #GtkSettings:gtk-theme-name setting or a hierarchy change in the rendered
73 * <refsect2 id="gtkstylecontext-animations">
74 * <title>Transition animations</title>
76 * #GtkStyleContext has built-in support for state change transitions.
77 * Note that these animations respect the #GtkSettings:gtk-enable-animations
81 * For simple widgets where state changes affect the whole widget area,
82 * calling gtk_style_context_notify_state_change() with a %NULL region
83 * is sufficient to trigger the transition animation. And GTK+ already
84 * does that when gtk_widget_set_state() or gtk_widget_set_state_flags()
88 * If a widget needs to declare several animatable regions (i.e. not
89 * affecting the whole widget area), its #GtkWidget::draw signal handler
90 * needs to wrap the render operations for the different regions with
91 * calls to gtk_style_context_push_animatable_region() and
92 * gtk_style_context_pop_animatable_region(). These functions take an
93 * identifier for the region which must be unique within the style context.
94 * For simple widgets with a fixed set of animatable regions, using an
95 * enumeration works well:
98 * <title>Using an enumeration to identify animatable regions</title>
109 * spin_button_draw (GtkWidget *widget,
112 * GtkStyleContext *context;
114 * context = gtk_widget_get_style_context (widget);
116 * gtk_style_context_push_animatable_region (context,
117 * GUINT_TO_POINTER (REGION_ENTRY));
119 * gtk_render_background (cr, 0, 0, 100, 30);
120 * gtk_render_frame (cr, 0, 0, 100, 30);
122 * gtk_style_context_pop_animatable_region (context);
129 * For complex widgets with an arbitrary number of animatable regions, it
130 * is up to the implementation to come up with a way to uniquely identify
131 * each animatable region. Using pointers to internal structs is one way
135 * <title>Using struct pointers to identify animatable regions</title>
138 * notebook_draw_tab (GtkWidget *widget,
139 * NotebookPage *page,
142 * gtk_style_context_push_animatable_region (context, page);
143 * gtk_render_extension (cr, page->x, page->y, page->width, page->height);
144 * gtk_style_context_pop_animatable_region (context);
149 * The widget also needs to notify the style context about a state change
150 * for a given animatable region so the animation is triggered.
153 * <title>Triggering a state change animation on a region</title>
156 * notebook_motion_notify (GtkWidget *widget,
157 * GdkEventMotion *event)
159 * GtkStyleContext *context;
160 * NotebookPage *page;
162 * context = gtk_widget_get_style_context (widget);
163 * page = find_page_under_pointer (widget, event);
164 * gtk_style_context_notify_state_change (context,
165 * gtk_widget_get_window (widget),
167 * GTK_STATE_PRELIGHT,
174 * gtk_style_context_notify_state_change() accepts %NULL region IDs as a
175 * special value, in this case, the whole widget area will be updated
179 * <refsect2 id="gtkstylecontext-classes">
180 * <title>Style classes and regions</title>
182 * Widgets can add style classes to their context, which can be used
183 * to associate different styles by class (see <xref linkend="gtkcssprovider-selectors"/>). Theme engines can also use style classes to vary their
184 * rendering. GTK+ has a number of predefined style classes:
185 * #GTK_STYLE_CLASS_CELL,
186 * #GTK_STYLE_CLASS_ENTRY,
187 * #GTK_STYLE_CLASS_BUTTON,
188 * #GTK_STYLE_CLASS_COMBOBOX_ENTRY,
189 * #GTK_STYLE_CLASS_CALENDAR,
190 * #GTK_STYLE_CLASS_SLIDER,
191 * #GTK_STYLE_CLASS_BACKGROUND,
192 * #GTK_STYLE_CLASS_RUBBERBAND,
193 * #GTK_STYLE_CLASS_TOOLTIP,
194 * #GTK_STYLE_CLASS_MENU,
195 * #GTK_STYLE_CLASS_MENUBAR,
196 * #GTK_STYLE_CLASS_MENUITEM,
197 * #GTK_STYLE_CLASS_TOOLBAR,
198 * #GTK_STYLE_CLASS_PRIMARY_TOOLBAR,
199 * #GTK_STYLE_CLASS_INLINE_TOOLBAR,
200 * #GTK_STYLE_CLASS_RADIO,
201 * #GTK_STYLE_CLASS_CHECK,
202 * #GTK_STYLE_CLASS_TROUGH,
203 * #GTK_STYLE_CLASS_SCROLLBAR,
204 * #GTK_STYLE_CLASS_SCALE,
205 * #GTK_STYLE_CLASS_SCALE_HAS_MARKS_ABOVE,
206 * #GTK_STYLE_CLASS_SCALE_HAS_MARKS_BELOW,
207 * #GTK_STYLE_CLASS_HEADER,
208 * #GTK_STYLE_CLASS_ACCELERATOR,
209 * #GTK_STYLE_CLASS_GRIP,
210 * #GTK_STYLE_CLASS_DOCK,
211 * #GTK_STYLE_CLASS_PROGRESSBAR,
212 * #GTK_STYLE_CLASS_SPINNER,
213 * #GTK_STYLE_CLASS_EXPANDER,
214 * #GTK_STYLE_CLASS_SPINBUTTON,
215 * #GTK_STYLE_CLASS_NOTEBOOK,
216 * #GTK_STYLE_CLASS_VIEW,
217 * #GTK_STYLE_CLASS_SIDEBAR,
218 * #GTK_STYLE_CLASS_IMAGE,
219 * #GTK_STYLE_CLASS_HIGHLIGHT,
220 * #GTK_STYLE_CLASS_FRAME,
221 * #GTK_STYLE_CLASS_DND,
222 * #GTK_STYLE_CLASS_PANE_SEPARATOR,
223 * #GTK_STYLE_CLASS_SEPARATOR,
224 * #GTK_STYLE_CLASS_INFO,
225 * #GTK_STYLE_CLASS_WARNING,
226 * #GTK_STYLE_CLASS_QUESTION,
227 * #GTK_STYLE_CLASS_ERROR,
228 * #GTK_STYLE_CLASS_HORIZONTAL,
229 * #GTK_STYLE_CLASS_VERTICAL,
230 * #GTK_STYLE_CLASS_TOP,
231 * #GTK_STYLE_CLASS_BOTTOM,
232 * #GTK_STYLE_CLASS_LEFT,
233 * #GTK_STYLE_CLASS_RIGHT,
236 * Widgets can also add regions with flags to their context.
237 * The regions used by GTK+ widgets are:
242 * <entry>Region</entry>
243 * <entry>Flags</entry>
244 * <entry>Macro</entry>
245 * <entry>Used by</entry>
251 * <entry>even, odd</entry>
252 * <entry>GTK_STYLE_REGION_ROW</entry>
253 * <entry>#GtkTreeView</entry>
256 * <entry>column</entry>
257 * <entry>first, last, sorted</entry>
258 * <entry>GTK_STYLE_REGION_COLUMN</entry>
259 * <entry>#GtkTreeView</entry>
262 * <entry>column-header</entry>
264 * <entry>GTK_STYLE_REGION_COLUMN_HEADER</entry>
269 * <entry>even, odd, first, last</entry>
270 * <entry>GTK_STYLE_REGION_TAB</entry>
271 * <entry>#GtkNotebook</entry>
278 * <refsect2 id="gtkstylecontext-custom-styling">
279 * <title>Custom styling in UI libraries and applications</title>
281 * If you are developing a library with custom #GtkWidget<!-- -->s that
282 * render differently than standard components, you may need to add a
283 * #GtkStyleProvider yourself with the %GTK_STYLE_PROVIDER_PRIORITY_FALLBACK
284 * priority, either a #GtkCssProvider or a custom object implementing the
285 * #GtkStyleProvider interface. This way theming engines may still attempt
286 * to style your UI elements in a different way if needed so.
289 * If you are using custom styling on an applications, you probably want then
290 * to make your style information prevail to the theme's, so you must use
291 * a #GtkStyleProvider with the %GTK_STYLE_PROVIDER_PRIORITY_APPLICATION
292 * priority, keep in mind that the user settings in
293 * <filename><replaceable>XDG_CONFIG_HOME</replaceable>/gtk-3.0/gtk.css</filename> will
294 * still take precedence over your changes, as it uses the
295 * %GTK_STYLE_PROVIDER_PRIORITY_USER priority.
298 * If a custom theming engine is needed, you probably want to implement a
299 * #GtkStyleProvider yourself so it points to your #GtkThemingEngine
300 * implementation, as #GtkCssProvider uses gtk_theming_engine_load()
301 * which loads the theming engine module from the standard paths.
306 /* When these change we do a full restyling. Otherwise we try to figure out
307 * if we need to change things. */
308 #define GTK_STYLE_CONTEXT_RADICAL_CHANGE (GTK_CSS_CHANGE_NAME | GTK_CSS_CHANGE_CLASS)
309 /* When these change we don't clear the cache. This takes more memory but makes
310 * things go faster. */
311 #define GTK_STYLE_CONTEXT_CACHED_CHANGE (GTK_CSS_CHANGE_STATE)
313 typedef struct GtkStyleInfo GtkStyleInfo;
314 typedef struct GtkRegion GtkRegion;
315 typedef struct PropertyValue PropertyValue;
316 typedef struct AnimationInfo AnimationInfo;
317 typedef struct StyleData StyleData;
322 GtkRegionFlags flags;
335 GArray *style_classes;
337 GtkJunctionSides junction_sides;
338 GtkStateFlags state_flags;
343 GtkCssComputedValues *store;
344 GArray *property_cache;
349 GtkTimeline *timeline;
353 /* Region stack (until region_id) at the time of
354 * rendering, this is used for nested cancellation.
356 GSList *parent_regions;
360 gboolean target_value;
362 cairo_region_t *invalidation_region;
366 struct _GtkStyleContextPrivate
370 GtkStyleCascade *cascade;
372 GtkStyleContext *parent;
375 GtkWidgetPath *widget_path;
376 GHashTable *style_data;
378 StyleData *current_data;
379 GtkStateFlags current_state;
381 GSList *animation_regions;
384 GtkThemingEngine *theming_engine;
386 GtkTextDirection direction;
388 GtkCssChange relevant_changes;
389 GtkCssChange pending_changes;
391 guint animations_invalidated : 1;
392 guint invalidating_context : 1;
408 static guint signals[LAST_SIGNAL] = { 0 };
410 static void gtk_style_context_finalize (GObject *object);
412 static void gtk_style_context_impl_set_property (GObject *object,
416 static void gtk_style_context_impl_get_property (GObject *object,
420 static GtkSymbolicColor *
421 gtk_style_context_color_lookup_func (gpointer contextp,
425 G_DEFINE_TYPE (GtkStyleContext, gtk_style_context, G_TYPE_OBJECT)
428 gtk_style_context_real_changed (GtkStyleContext *context)
430 GtkStyleContextPrivate *priv = context->priv;
433 _gtk_widget_style_context_invalidated (priv->widget);
437 gtk_style_context_class_init (GtkStyleContextClass *klass)
439 GObjectClass *object_class = G_OBJECT_CLASS (klass);
441 object_class->finalize = gtk_style_context_finalize;
442 object_class->set_property = gtk_style_context_impl_set_property;
443 object_class->get_property = gtk_style_context_impl_get_property;
445 klass->changed = gtk_style_context_real_changed;
448 g_signal_new (I_("changed"),
449 G_TYPE_FROM_CLASS (object_class),
451 G_STRUCT_OFFSET (GtkStyleContextClass, changed),
453 g_cclosure_marshal_VOID__VOID,
456 g_object_class_install_property (object_class,
458 g_param_spec_object ("screen",
460 P_("The associated GdkScreen"),
462 GTK_PARAM_READWRITE));
463 g_object_class_install_property (object_class,
465 g_param_spec_enum ("direction",
467 P_("Text direction"),
468 GTK_TYPE_TEXT_DIRECTION,
470 GTK_PARAM_READWRITE));
472 * GtkStyleContext:parent:
474 * Sets or gets the style context's parent. See gtk_style_context_set_parent()
479 g_object_class_install_property (object_class,
481 g_param_spec_object ("parent",
483 P_("The parent style context"),
484 GTK_TYPE_STYLE_CONTEXT,
485 GTK_PARAM_READWRITE));
487 g_type_class_add_private (object_class, sizeof (GtkStyleContextPrivate));
490 static GtkStyleInfo *
491 style_info_new (void)
495 info = g_slice_new0 (GtkStyleInfo);
496 info->style_classes = g_array_new (FALSE, FALSE, sizeof (GQuark));
497 info->regions = g_array_new (FALSE, FALSE, sizeof (GtkRegion));
503 style_info_free (GtkStyleInfo *info)
505 g_array_free (info->style_classes, TRUE);
506 g_array_free (info->regions, TRUE);
507 g_slice_free (GtkStyleInfo, info);
510 static GtkStyleInfo *
511 style_info_copy (const GtkStyleInfo *info)
515 copy = style_info_new ();
516 g_array_insert_vals (copy->style_classes, 0,
517 info->style_classes->data,
518 info->style_classes->len);
520 g_array_insert_vals (copy->regions, 0,
524 copy->junction_sides = info->junction_sides;
525 copy->state_flags = info->state_flags;
531 style_info_hash (gconstpointer elem)
533 const GtkStyleInfo *info;
538 for (i = 0; i < info->style_classes->len; i++)
540 hash += g_array_index (info->style_classes, GQuark, i);
544 for (i = 0; i < info->regions->len; i++)
548 region = &g_array_index (info->regions, GtkRegion, i);
549 hash += region->class_quark;
550 hash += region->flags;
554 return hash ^ info->state_flags;
558 style_info_equal (gconstpointer elem1,
561 const GtkStyleInfo *info1, *info2;
566 if (info1->state_flags != info2->state_flags)
569 if (info1->junction_sides != info2->junction_sides)
572 if (info1->style_classes->len != info2->style_classes->len)
575 if (memcmp (info1->style_classes->data,
576 info2->style_classes->data,
577 info1->style_classes->len * sizeof (GQuark)) != 0)
580 if (info1->regions->len != info2->regions->len)
583 if (memcmp (info1->regions->data,
584 info2->regions->data,
585 info1->regions->len * sizeof (GtkRegion)) != 0)
592 style_data_new (void)
596 data = g_slice_new0 (StyleData);
602 clear_property_cache (StyleData *data)
606 if (!data->property_cache)
609 for (i = 0; i < data->property_cache->len; i++)
611 PropertyValue *node = &g_array_index (data->property_cache, PropertyValue, i);
613 g_param_spec_unref (node->pspec);
614 g_value_unset (&node->value);
617 g_array_free (data->property_cache, TRUE);
618 data->property_cache = NULL;
622 style_data_free (StyleData *data)
624 g_object_unref (data->store);
625 clear_property_cache (data);
627 g_slice_free (StyleData, data);
631 gtk_style_context_init (GtkStyleContext *style_context)
633 GtkStyleContextPrivate *priv;
636 priv = style_context->priv = G_TYPE_INSTANCE_GET_PRIVATE (style_context,
637 GTK_TYPE_STYLE_CONTEXT,
638 GtkStyleContextPrivate);
640 priv->style_data = g_hash_table_new_full (style_info_hash,
642 (GDestroyNotify) style_info_free,
643 (GDestroyNotify) style_data_free);
644 priv->theming_engine = g_object_ref ((gpointer) gtk_theming_engine_load (NULL));
646 priv->direction = GTK_TEXT_DIR_LTR;
648 priv->screen = gdk_screen_get_default ();
649 priv->cascade = _gtk_style_cascade_get_for_screen (priv->screen);
650 g_object_ref (priv->cascade);
651 priv->relevant_changes = GTK_CSS_CHANGE_ANY;
653 /* Create default info store */
654 info = style_info_new ();
655 priv->info_stack = g_slist_prepend (priv->info_stack, info);
659 animation_info_free (AnimationInfo *info)
661 g_object_unref (info->timeline);
662 g_object_unref (info->window);
664 if (info->invalidation_region)
665 cairo_region_destroy (info->invalidation_region);
667 g_array_free (info->rectangles, TRUE);
668 g_slist_free (info->parent_regions);
669 g_slice_free (AnimationInfo, info);
672 static AnimationInfo *
673 animation_info_lookup_by_timeline (GtkStyleContext *context,
674 GtkTimeline *timeline)
676 GtkStyleContextPrivate *priv;
680 priv = context->priv;
682 for (l = priv->animations; l; l = l->next)
686 if (info->timeline == timeline)
694 timeline_frame_cb (GtkTimeline *timeline,
698 GtkStyleContextPrivate *priv;
699 GtkStyleContext *context;
703 priv = context->priv;
704 info = animation_info_lookup_by_timeline (context, timeline);
706 g_assert (info != NULL);
708 /* Cancel transition if window is gone */
709 if (gdk_window_is_destroyed (info->window) ||
710 !gdk_window_is_visible (info->window))
712 priv->animations = g_slist_remove (priv->animations, info);
713 animation_info_free (info);
717 if (info->invalidation_region &&
718 !cairo_region_is_empty (info->invalidation_region))
719 gdk_window_invalidate_region (info->window, info->invalidation_region, TRUE);
721 gdk_window_invalidate_rect (info->window, NULL, TRUE);
725 timeline_finished_cb (GtkTimeline *timeline,
728 GtkStyleContextPrivate *priv;
729 GtkStyleContext *context;
733 priv = context->priv;
734 info = animation_info_lookup_by_timeline (context, timeline);
736 g_assert (info != NULL);
738 priv->animations = g_slist_remove (priv->animations, info);
740 /* Invalidate one last time the area, so the final content is painted */
741 if (info->invalidation_region &&
742 !cairo_region_is_empty (info->invalidation_region))
743 gdk_window_invalidate_region (info->window, info->invalidation_region, TRUE);
745 gdk_window_invalidate_rect (info->window, NULL, TRUE);
747 animation_info_free (info);
750 static AnimationInfo *
751 animation_info_new (GtkStyleContext *context,
754 GtkTimelineProgressType progress_type,
757 gboolean target_value,
762 info = g_slice_new0 (AnimationInfo);
764 info->rectangles = g_array_new (FALSE, FALSE, sizeof (cairo_rectangle_int_t));
765 info->timeline = _gtk_timeline_new (duration);
766 info->window = g_object_ref (window);
768 info->target_value = target_value;
769 info->region_id = region_id;
771 _gtk_timeline_set_progress_type (info->timeline, progress_type);
772 _gtk_timeline_set_loop (info->timeline, loop);
774 if (!loop && !target_value)
776 _gtk_timeline_set_direction (info->timeline, GTK_TIMELINE_DIRECTION_BACKWARD);
777 _gtk_timeline_rewind (info->timeline);
780 g_signal_connect (info->timeline, "frame",
781 G_CALLBACK (timeline_frame_cb), context);
782 g_signal_connect (info->timeline, "finished",
783 G_CALLBACK (timeline_finished_cb), context);
785 _gtk_timeline_start (info->timeline);
790 static AnimationInfo *
791 animation_info_lookup (GtkStyleContext *context,
795 GtkStyleContextPrivate *priv;
798 priv = context->priv;
800 for (l = priv->animations; l; l = l->next)
806 if (info->state == state &&
807 info->region_id == region_id)
815 gtk_style_context_finalize (GObject *object)
817 GtkStyleContextPrivate *priv;
818 GtkStyleContext *style_context;
821 style_context = GTK_STYLE_CONTEXT (object);
822 priv = style_context->priv;
824 /* children hold a reference to us */
825 g_assert (priv->children == NULL);
827 gtk_style_context_set_parent (style_context, NULL);
829 if (priv->widget_path)
830 gtk_widget_path_free (priv->widget_path);
832 g_hash_table_destroy (priv->style_data);
834 g_object_unref (priv->cascade);
836 g_slist_free_full (priv->info_stack, (GDestroyNotify) style_info_free);
838 g_slist_free (priv->animation_regions);
840 for (l = priv->animations; l; l = l->next)
841 animation_info_free ((AnimationInfo *) l->data);
843 g_slist_free (priv->animations);
845 if (priv->theming_engine)
846 g_object_unref (priv->theming_engine);
848 G_OBJECT_CLASS (gtk_style_context_parent_class)->finalize (object);
852 gtk_style_context_impl_set_property (GObject *object,
857 GtkStyleContext *style_context;
859 style_context = GTK_STYLE_CONTEXT (object);
864 gtk_style_context_set_screen (style_context,
865 g_value_get_object (value));
868 gtk_style_context_set_direction (style_context,
869 g_value_get_enum (value));
872 gtk_style_context_set_parent (style_context,
873 g_value_get_object (value));
876 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
882 gtk_style_context_impl_get_property (GObject *object,
887 GtkStyleContext *style_context;
888 GtkStyleContextPrivate *priv;
890 style_context = GTK_STYLE_CONTEXT (object);
891 priv = style_context->priv;
896 g_value_set_object (value, priv->screen);
899 g_value_set_enum (value, priv->direction);
902 g_value_set_object (value, priv->parent);
905 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
911 build_properties (GtkStyleContext *context,
912 StyleData *style_data,
916 GtkStyleContextPrivate *priv;
917 GtkCssMatcher matcher;
918 GtkCssLookup *lookup;
920 priv = context->priv;
922 _gtk_css_matcher_init (&matcher, path, state);
923 lookup = _gtk_css_lookup_new ();
925 _gtk_style_provider_private_lookup (GTK_STYLE_PROVIDER_PRIVATE (priv->cascade),
929 style_data->store = _gtk_css_computed_values_new ();
930 _gtk_css_lookup_resolve (lookup, context, style_data->store);
931 _gtk_css_lookup_free (lookup);
934 static GtkWidgetPath *
935 create_query_path (GtkStyleContext *context)
937 GtkStyleContextPrivate *priv;
942 priv = context->priv;
943 path = gtk_widget_path_copy (priv->widget ? gtk_widget_get_path (priv->widget) : priv->widget_path);
944 pos = gtk_widget_path_length (path) - 1;
946 info = priv->info_stack->data;
948 /* Set widget regions */
949 for (i = 0; i < info->regions->len; i++)
953 region = &g_array_index (info->regions, GtkRegion, i);
954 gtk_widget_path_iter_add_region (path, pos,
955 g_quark_to_string (region->class_quark),
959 /* Set widget classes */
960 for (i = 0; i < info->style_classes->len; i++)
964 quark = g_array_index (info->style_classes, GQuark, i);
965 gtk_widget_path_iter_add_class (path, pos,
966 g_quark_to_string (quark));
973 style_data_lookup (GtkStyleContext *context,
976 GtkStyleContextPrivate *priv;
978 gboolean state_mismatch;
981 priv = context->priv;
982 state_mismatch = ((GtkStyleInfo *) priv->info_stack->data)->state_flags != state;
984 /* Current data in use is cached, just return it */
985 if (priv->current_data && priv->current_state == state)
986 return priv->current_data;
988 g_assert (priv->widget != NULL || priv->widget_path != NULL);
990 if (G_UNLIKELY (state_mismatch))
992 gtk_style_context_save (context);
993 gtk_style_context_set_state (context, state);
996 priv->current_data = g_hash_table_lookup (priv->style_data, priv->info_stack->data);
997 priv->current_state = state;
999 if (!priv->current_data)
1001 GtkWidgetPath *path;
1003 path = create_query_path (context);
1005 priv->current_data = style_data_new ();
1006 g_hash_table_insert (priv->style_data,
1007 style_info_copy (priv->info_stack->data),
1008 priv->current_data);
1010 build_properties (context, priv->current_data, path, state);
1012 gtk_widget_path_free (path);
1015 data = priv->current_data;
1017 if (priv->theming_engine)
1018 g_object_unref (priv->theming_engine);
1020 v = _gtk_css_computed_values_get_value_by_name (priv->current_data->store, "engine");
1022 priv->theming_engine = _gtk_css_value_dup_object (v);
1024 priv->theming_engine = g_object_ref (gtk_theming_engine_load (NULL));
1026 if (G_UNLIKELY (state_mismatch))
1027 gtk_style_context_restore (context);
1033 gtk_style_context_set_invalid (GtkStyleContext *context,
1036 GtkStyleContextPrivate *priv;
1038 priv = context->priv;
1040 if (priv->invalid == invalid)
1043 priv->invalid = invalid;
1048 gtk_widget_queue_resize (priv->widget);
1050 gtk_style_context_set_invalid (priv->parent, TRUE);
1054 /* returns TRUE if someone called gtk_style_context_save() but hasn't
1055 * called gtk_style_context_restore() yet.
1056 * In those situations we don't invalidate the context when somebody
1057 * changes state/regions/classes.
1060 gtk_style_context_is_saved (GtkStyleContext *context)
1062 return context->priv->info_stack->next != NULL;
1066 gtk_style_context_queue_invalidate_internal (GtkStyleContext *context,
1067 GtkCssChange change)
1069 GtkStyleContextPrivate *priv = context->priv;
1071 priv->current_data = NULL;
1073 if (!gtk_style_context_is_saved (context))
1075 _gtk_style_context_queue_invalidate (context, GTK_CSS_CHANGE_STATE);
1076 /* XXX: We need to invalidate siblings here somehow */
1081 * gtk_style_context_new:
1083 * Creates a standalone #GtkStyleContext, this style context
1084 * won't be attached to any widget, so you may want
1085 * to call gtk_style_context_set_path() yourself.
1088 * This function is only useful when using the theming layer
1089 * separated from GTK+, if you are using #GtkStyleContext to
1090 * theme #GtkWidget<!-- -->s, use gtk_widget_get_style_context()
1091 * in order to get a style context ready to theme the widget.
1094 * Returns: A newly created #GtkStyleContext.
1097 gtk_style_context_new (void)
1099 return g_object_new (GTK_TYPE_STYLE_CONTEXT, NULL);
1103 _gtk_style_context_set_widget (GtkStyleContext *context,
1106 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
1107 g_return_if_fail (widget == NULL || GTK_IS_WIDGET (widget));
1109 context->priv->widget = widget;
1111 _gtk_style_context_queue_invalidate (context, GTK_CSS_CHANGE_ANY_SELF);
1115 * gtk_style_context_add_provider:
1116 * @context: a #GtkStyleContext
1117 * @provider: a #GtkStyleProvider
1118 * @priority: the priority of the style provider. The lower
1119 * it is, the earlier it will be used in the style
1120 * construction. Typically this will be in the range
1121 * between %GTK_STYLE_PROVIDER_PRIORITY_FALLBACK and
1122 * %GTK_STYLE_PROVIDER_PRIORITY_USER
1124 * Adds a style provider to @context, to be used in style construction.
1126 * <note><para>If both priorities are the same, A #GtkStyleProvider
1127 * added through this function takes precedence over another added
1128 * through gtk_style_context_add_provider_for_screen().</para></note>
1133 gtk_style_context_add_provider (GtkStyleContext *context,
1134 GtkStyleProvider *provider,
1137 GtkStyleContextPrivate *priv;
1139 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
1140 g_return_if_fail (GTK_IS_STYLE_PROVIDER (provider));
1142 priv = context->priv;
1144 if (priv->cascade == _gtk_style_cascade_get_for_screen (priv->screen))
1146 GtkStyleCascade *new_cascade;
1148 new_cascade = _gtk_style_cascade_new ();
1149 _gtk_style_cascade_set_parent (new_cascade, priv->cascade);
1150 g_object_unref (priv->cascade);
1151 priv->cascade = new_cascade;
1154 _gtk_style_cascade_add_provider (priv->cascade, provider, priority);
1156 gtk_style_context_invalidate (context);
1160 * gtk_style_context_remove_provider:
1161 * @context: a #GtkStyleContext
1162 * @provider: a #GtkStyleProvider
1164 * Removes @provider from the style providers list in @context.
1169 gtk_style_context_remove_provider (GtkStyleContext *context,
1170 GtkStyleProvider *provider)
1172 GtkStyleContextPrivate *priv;
1174 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
1175 g_return_if_fail (GTK_IS_STYLE_PROVIDER (provider));
1177 priv = context->priv;
1179 if (priv->cascade == _gtk_style_cascade_get_for_screen (priv->screen))
1182 _gtk_style_cascade_remove_provider (priv->cascade, provider);
1186 * gtk_style_context_reset_widgets:
1187 * @screen: a #GdkScreen
1189 * This function recomputes the styles for all widgets under a particular
1190 * #GdkScreen. This is useful when some global parameter has changed that
1191 * affects the appearance of all widgets, because when a widget gets a new
1192 * style, it will both redraw and recompute any cached information about
1193 * its appearance. As an example, it is used when the color scheme changes
1194 * in the related #GtkSettings object.
1199 gtk_style_context_reset_widgets (GdkScreen *screen)
1201 GList *list, *toplevels;
1203 _gtk_icon_set_invalidate_caches ();
1205 toplevels = gtk_window_list_toplevels ();
1206 g_list_foreach (toplevels, (GFunc) g_object_ref, NULL);
1208 for (list = toplevels; list; list = list->next)
1210 if (gtk_widget_get_screen (list->data) == screen)
1211 gtk_widget_reset_style (list->data);
1213 g_object_unref (list->data);
1216 g_list_free (toplevels);
1220 * gtk_style_context_add_provider_for_screen:
1221 * @screen: a #GdkScreen
1222 * @provider: a #GtkStyleProvider
1223 * @priority: the priority of the style provider. The lower
1224 * it is, the earlier it will be used in the style
1225 * construction. Typically this will be in the range
1226 * between %GTK_STYLE_PROVIDER_PRIORITY_FALLBACK and
1227 * %GTK_STYLE_PROVIDER_PRIORITY_USER
1229 * Adds a global style provider to @screen, which will be used
1230 * in style construction for all #GtkStyleContext<!-- -->s under
1233 * GTK+ uses this to make styling information from #GtkSettings
1236 * <note><para>If both priorities are the same, A #GtkStyleProvider
1237 * added through gtk_style_context_add_provider() takes precedence
1238 * over another added through this function.</para></note>
1243 gtk_style_context_add_provider_for_screen (GdkScreen *screen,
1244 GtkStyleProvider *provider,
1247 GtkStyleCascade *cascade;
1249 g_return_if_fail (GDK_IS_SCREEN (screen));
1250 g_return_if_fail (GTK_IS_STYLE_PROVIDER (provider));
1252 cascade = _gtk_style_cascade_get_for_screen (screen);
1253 _gtk_style_cascade_add_provider (cascade, provider, priority);
1257 * gtk_style_context_remove_provider_for_screen:
1258 * @screen: a #GdkScreen
1259 * @provider: a #GtkStyleProvider
1261 * Removes @provider from the global style providers list in @screen.
1266 gtk_style_context_remove_provider_for_screen (GdkScreen *screen,
1267 GtkStyleProvider *provider)
1269 GtkStyleCascade *cascade;
1271 g_return_if_fail (GDK_IS_SCREEN (screen));
1272 g_return_if_fail (GTK_IS_STYLE_PROVIDER (provider));
1274 cascade = _gtk_style_cascade_get_for_screen (screen);
1275 _gtk_style_cascade_remove_provider (cascade, provider);
1279 * gtk_style_context_get_section:
1280 * @context: a #GtkStyleContext
1281 * @property: style property name
1283 * Queries the location in the CSS where @property was defined for the
1284 * current @context. Note that the state to be queried is taken from
1285 * gtk_style_context_get_state().
1287 * If the location is not available, %NULL will be returned. The
1288 * location might not be available for various reasons, such as the
1289 * property being overridden, @property not naming a supported CSS
1290 * property or tracking of definitions being disabled for performance
1293 * Shorthand CSS properties cannot be queried for a location and will
1294 * always return %NULL.
1296 * Returns: %NULL or the section where value was defined
1299 gtk_style_context_get_section (GtkStyleContext *context,
1300 const gchar *property)
1302 GtkStyleContextPrivate *priv;
1303 GtkStyleProperty *prop;
1306 g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), NULL);
1307 g_return_val_if_fail (property != NULL, NULL);
1309 priv = context->priv;
1310 g_return_val_if_fail (priv->widget != NULL || priv->widget_path != NULL, NULL);
1312 prop = _gtk_style_property_lookup (property);
1313 if (!GTK_IS_CSS_STYLE_PROPERTY (prop))
1316 data = style_data_lookup (context, gtk_style_context_get_state (context));
1317 return _gtk_css_computed_values_get_section (data->store, _gtk_css_style_property_get_id (GTK_CSS_STYLE_PROPERTY (prop)));
1320 static GtkCssValue *
1321 gtk_style_context_query_func (guint id,
1324 return _gtk_css_computed_values_get_value (values, id);
1328 * gtk_style_context_get_property:
1329 * @context: a #GtkStyleContext
1330 * @property: style property name
1331 * @state: state to retrieve the property value for
1332 * @value: (out) (transfer full): return location for the style property value
1334 * Gets a style property from @context for the given state.
1336 * When @value is no longer needed, g_value_unset() must be called
1337 * to free any allocated memory.
1342 gtk_style_context_get_property (GtkStyleContext *context,
1343 const gchar *property,
1344 GtkStateFlags state,
1347 GtkStyleContextPrivate *priv;
1348 GtkStyleProperty *prop;
1351 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
1352 g_return_if_fail (property != NULL);
1353 g_return_if_fail (value != NULL);
1355 priv = context->priv;
1356 g_return_if_fail (priv->widget != NULL || priv->widget_path != NULL);
1358 prop = _gtk_style_property_lookup (property);
1361 g_warning ("Style property \"%s\" is not registered", property);
1364 if (_gtk_style_property_get_value_type (prop) == G_TYPE_NONE)
1366 g_warning ("Style property \"%s\" is not gettable", property);
1370 data = style_data_lookup (context, state);
1371 _gtk_style_property_query (prop, value, gtk_style_context_query_func, data->store);
1375 * gtk_style_context_get_valist:
1376 * @context: a #GtkStyleContext
1377 * @state: state to retrieve the property values for
1378 * @args: va_list of property name/return location pairs, followed by %NULL
1380 * Retrieves several style property values from @context for a given state.
1385 gtk_style_context_get_valist (GtkStyleContext *context,
1386 GtkStateFlags state,
1389 const gchar *property_name;
1391 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
1393 property_name = va_arg (args, const gchar *);
1395 while (property_name)
1397 gchar *error = NULL;
1398 GValue value = G_VALUE_INIT;
1400 gtk_style_context_get_property (context,
1405 G_VALUE_LCOPY (&value, args, 0, &error);
1406 g_value_unset (&value);
1410 g_warning ("Could not get style property \"%s\": %s", property_name, error);
1415 property_name = va_arg (args, const gchar *);
1420 * gtk_style_context_get:
1421 * @context: a #GtkStyleContext
1422 * @state: state to retrieve the property values for
1423 * @...: property name /return value pairs, followed by %NULL
1425 * Retrieves several style property values from @context for a
1431 gtk_style_context_get (GtkStyleContext *context,
1432 GtkStateFlags state,
1437 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
1439 va_start (args, state);
1440 gtk_style_context_get_valist (context, state, args);
1445 * gtk_style_context_set_state:
1446 * @context: a #GtkStyleContext
1447 * @flags: state to represent
1449 * Sets the state to be used when rendering with any
1450 * of the gtk_render_*() functions.
1455 gtk_style_context_set_state (GtkStyleContext *context,
1456 GtkStateFlags flags)
1458 GtkStyleContextPrivate *priv;
1461 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
1463 priv = context->priv;
1464 info = priv->info_stack->data;
1465 info->state_flags = flags;
1467 gtk_style_context_queue_invalidate_internal (context, GTK_CSS_CHANGE_STATE);
1471 * gtk_style_context_get_state:
1472 * @context: a #GtkStyleContext
1474 * Returns the state used when rendering.
1476 * Returns: the state flags
1481 gtk_style_context_get_state (GtkStyleContext *context)
1483 GtkStyleContextPrivate *priv;
1486 g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), 0);
1488 priv = context->priv;
1489 info = priv->info_stack->data;
1491 return info->state_flags;
1495 context_has_animatable_region (GtkStyleContext *context,
1498 GtkStyleContextPrivate *priv;
1500 /* NULL region_id means everything
1501 * rendered through the style context
1506 priv = context->priv;
1507 return g_slist_find (priv->animation_regions, region_id) != NULL;
1511 * gtk_style_context_state_is_running:
1512 * @context: a #GtkStyleContext
1513 * @state: a widget state
1514 * @progress: (out): return location for the transition progress
1516 * Returns %TRUE if there is a transition animation running for the
1517 * current region (see gtk_style_context_push_animatable_region()).
1519 * If @progress is not %NULL, the animation progress will be returned
1520 * there, 0.0 means the state is closest to being unset, while 1.0 means
1521 * it's closest to being set. This means transition animation will
1522 * run from 0 to 1 when @state is being set and from 1 to 0 when
1525 * Returns: %TRUE if there is a running transition animation for @state.
1530 gtk_style_context_state_is_running (GtkStyleContext *context,
1534 GtkStyleContextPrivate *priv;
1535 AnimationInfo *info;
1538 g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), FALSE);
1540 priv = context->priv;
1542 for (l = priv->animations; l; l = l->next)
1546 if (info->state == state &&
1547 context_has_animatable_region (context, info->region_id))
1550 *progress = _gtk_timeline_get_progress (info->timeline);
1560 * gtk_style_context_set_path:
1561 * @context: a #GtkStyleContext
1562 * @path: a #GtkWidgetPath
1564 * Sets the #GtkWidgetPath used for style matching. As a
1565 * consequence, the style will be regenerated to match
1566 * the new given path.
1568 * If you are using a #GtkStyleContext returned from
1569 * gtk_widget_get_style_context(), you do not need to call
1575 gtk_style_context_set_path (GtkStyleContext *context,
1576 GtkWidgetPath *path)
1578 GtkStyleContextPrivate *priv;
1580 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
1581 g_return_if_fail (path != NULL);
1583 priv = context->priv;
1584 g_return_if_fail (priv->widget == NULL);
1586 if (priv->widget_path)
1588 gtk_widget_path_free (priv->widget_path);
1589 priv->widget_path = NULL;
1593 priv->widget_path = gtk_widget_path_copy (path);
1595 _gtk_style_context_queue_invalidate (context, GTK_CSS_CHANGE_ANY);
1599 * gtk_style_context_get_path:
1600 * @context: a #GtkStyleContext
1602 * Returns the widget path used for style matching.
1604 * Returns: (transfer none): A #GtkWidgetPath
1608 const GtkWidgetPath *
1609 gtk_style_context_get_path (GtkStyleContext *context)
1611 GtkStyleContextPrivate *priv;
1613 priv = context->priv;
1615 return gtk_widget_get_path (priv->widget);
1617 return priv->widget_path;
1621 * gtk_style_context_set_parent:
1622 * @context: a #GtkStyleContext
1623 * @parent: (allow-none): the new parent or %NULL
1625 * Sets the parent style context for @context. The parent style
1626 * context is used to implement
1627 * <ulink url="http://www.w3.org/TR/css3-cascade/#inheritance">inheritance</ulink>
1630 * If you are using a #GtkStyleContext returned from
1631 * gtk_widget_get_style_context(), the parent will be set for you.
1636 gtk_style_context_set_parent (GtkStyleContext *context,
1637 GtkStyleContext *parent)
1639 GtkStyleContextPrivate *priv;
1641 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
1642 g_return_if_fail (parent == NULL || GTK_IS_STYLE_CONTEXT (parent));
1644 priv = context->priv;
1646 if (priv->parent == parent)
1651 parent->priv->children = g_slist_prepend (parent->priv->children, context);
1652 g_object_ref (parent);
1654 gtk_style_context_set_invalid (parent, TRUE);
1659 priv->parent->priv->children = g_slist_remove (priv->parent->priv->children, context);
1660 g_object_unref (priv->parent);
1663 priv->parent = parent;
1665 g_object_notify (G_OBJECT (context), "parent");
1666 _gtk_style_context_queue_invalidate (context, GTK_CSS_CHANGE_ANY_PARENT | GTK_CSS_CHANGE_ANY_SIBLING);
1670 * gtk_style_context_get_parent:
1671 * @context: a #GtkStyleContext
1673 * Gets the parent context set via gtk_style_context_set_parent().
1674 * See that function for details.
1676 * Returns: (transfer none): the parent context or %NULL
1681 gtk_style_context_get_parent (GtkStyleContext *context)
1683 g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), NULL);
1685 return context->priv->parent;
1689 * gtk_style_context_save:
1690 * @context: a #GtkStyleContext
1692 * Saves the @context state, so all modifications done through
1693 * gtk_style_context_add_class(), gtk_style_context_remove_class(),
1694 * gtk_style_context_add_region(), gtk_style_context_remove_region()
1695 * or gtk_style_context_set_junction_sides() can be reverted in one
1696 * go through gtk_style_context_restore().
1701 gtk_style_context_save (GtkStyleContext *context)
1703 GtkStyleContextPrivate *priv;
1706 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
1708 priv = context->priv;
1710 g_assert (priv->info_stack != NULL);
1712 info = style_info_copy (priv->info_stack->data);
1713 priv->info_stack = g_slist_prepend (priv->info_stack, info);
1717 * gtk_style_context_restore:
1718 * @context: a #GtkStyleContext
1720 * Restores @context state to a previous stage.
1721 * See gtk_style_context_save().
1726 gtk_style_context_restore (GtkStyleContext *context)
1728 GtkStyleContextPrivate *priv;
1731 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
1733 priv = context->priv;
1735 if (priv->info_stack)
1737 info = priv->info_stack->data;
1738 priv->info_stack = g_slist_remove (priv->info_stack, info);
1739 style_info_free (info);
1742 if (!priv->info_stack)
1744 g_warning ("Unpaired gtk_style_context_restore() call");
1746 /* Create default region */
1747 info = style_info_new ();
1748 priv->info_stack = g_slist_prepend (priv->info_stack, info);
1751 priv->current_data = NULL;
1755 style_class_find (GArray *array,
1760 gboolean found = FALSE;
1766 if (!array || array->len == 0)
1770 max = array->len - 1;
1776 mid = (min + max) / 2;
1777 item = g_array_index (array, GQuark, mid);
1779 if (class_quark == item)
1784 else if (class_quark > item)
1785 min = pos = mid + 1;
1792 while (!found && min <= max);
1801 region_find (GArray *array,
1806 gboolean found = FALSE;
1812 if (!array || array->len == 0)
1816 max = array->len - 1;
1822 mid = (min + max) / 2;
1823 region = &g_array_index (array, GtkRegion, mid);
1825 if (region->class_quark == class_quark)
1830 else if (region->class_quark > class_quark)
1831 min = pos = mid + 1;
1838 while (!found && min <= max);
1847 * gtk_style_context_add_class:
1848 * @context: a #GtkStyleContext
1849 * @class_name: class name to use in styling
1851 * Adds a style class to @context, so posterior calls to
1852 * gtk_style_context_get() or any of the gtk_render_*()
1853 * functions will make use of this new class for styling.
1855 * In the CSS file format, a #GtkEntry defining an "entry"
1856 * class, would be matched by:
1859 * GtkEntry.entry { ... }
1862 * While any widget defining an "entry" class would be
1871 gtk_style_context_add_class (GtkStyleContext *context,
1872 const gchar *class_name)
1874 GtkStyleContextPrivate *priv;
1879 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
1880 g_return_if_fail (class_name != NULL);
1882 priv = context->priv;
1883 class_quark = g_quark_from_string (class_name);
1885 g_assert (priv->info_stack != NULL);
1886 info = priv->info_stack->data;
1888 if (!style_class_find (info->style_classes, class_quark, &position))
1890 g_array_insert_val (info->style_classes, position, class_quark);
1892 gtk_style_context_queue_invalidate_internal (context, GTK_CSS_CHANGE_CLASS);
1897 * gtk_style_context_remove_class:
1898 * @context: a #GtkStyleContext
1899 * @class_name: class name to remove
1901 * Removes @class_name from @context.
1906 gtk_style_context_remove_class (GtkStyleContext *context,
1907 const gchar *class_name)
1909 GtkStyleContextPrivate *priv;
1914 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
1915 g_return_if_fail (class_name != NULL);
1917 class_quark = g_quark_try_string (class_name);
1922 priv = context->priv;
1924 g_assert (priv->info_stack != NULL);
1925 info = priv->info_stack->data;
1927 if (style_class_find (info->style_classes, class_quark, &position))
1929 g_array_remove_index (info->style_classes, position);
1931 gtk_style_context_queue_invalidate_internal (context, GTK_CSS_CHANGE_CLASS);
1936 * gtk_style_context_has_class:
1937 * @context: a #GtkStyleContext
1938 * @class_name: a class name
1940 * Returns %TRUE if @context currently has defined the
1943 * Returns: %TRUE if @context has @class_name defined
1948 gtk_style_context_has_class (GtkStyleContext *context,
1949 const gchar *class_name)
1951 GtkStyleContextPrivate *priv;
1955 g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), FALSE);
1956 g_return_val_if_fail (class_name != NULL, FALSE);
1958 class_quark = g_quark_try_string (class_name);
1963 priv = context->priv;
1965 g_assert (priv->info_stack != NULL);
1966 info = priv->info_stack->data;
1968 if (style_class_find (info->style_classes, class_quark, NULL))
1975 * gtk_style_context_list_classes:
1976 * @context: a #GtkStyleContext
1978 * Returns the list of classes currently defined in @context.
1980 * Returns: (transfer container) (element-type utf8): a #GList of
1981 * strings with the currently defined classes. The contents
1982 * of the list are owned by GTK+, but you must free the list
1983 * itself with g_list_free() when you are done with it.
1988 gtk_style_context_list_classes (GtkStyleContext *context)
1990 GtkStyleContextPrivate *priv;
1992 GList *classes = NULL;
1995 g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), NULL);
1997 priv = context->priv;
1999 g_assert (priv->info_stack != NULL);
2000 info = priv->info_stack->data;
2002 for (i = 0; i < info->style_classes->len; i++)
2006 quark = g_array_index (info->style_classes, GQuark, i);
2007 classes = g_list_prepend (classes, (gchar *) g_quark_to_string (quark));
2014 * gtk_style_context_list_regions:
2015 * @context: a #GtkStyleContext
2017 * Returns the list of regions currently defined in @context.
2019 * Returns: (transfer container) (element-type utf8): a #GList of
2020 * strings with the currently defined regions. The contents
2021 * of the list are owned by GTK+, but you must free the list
2022 * itself with g_list_free() when you are done with it.
2027 gtk_style_context_list_regions (GtkStyleContext *context)
2029 GtkStyleContextPrivate *priv;
2031 GList *classes = NULL;
2034 g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), NULL);
2036 priv = context->priv;
2038 g_assert (priv->info_stack != NULL);
2039 info = priv->info_stack->data;
2041 for (i = 0; i < info->regions->len; i++)
2044 const gchar *class_name;
2046 region = &g_array_index (info->regions, GtkRegion, i);
2048 class_name = g_quark_to_string (region->class_quark);
2049 classes = g_list_prepend (classes, (gchar *) class_name);
2056 _gtk_style_context_check_region_name (const gchar *str)
2058 g_return_val_if_fail (str != NULL, FALSE);
2060 if (!g_ascii_islower (str[0]))
2066 !g_ascii_islower (*str))
2076 * gtk_style_context_add_region:
2077 * @context: a #GtkStyleContext
2078 * @region_name: region name to use in styling
2079 * @flags: flags that apply to the region
2081 * Adds a region to @context, so posterior calls to
2082 * gtk_style_context_get() or any of the gtk_render_*()
2083 * functions will make use of this new region for styling.
2085 * In the CSS file format, a #GtkTreeView defining a "row"
2086 * region, would be matched by:
2089 * GtkTreeView row { ... }
2092 * Pseudo-classes are used for matching @flags, so the two
2095 * GtkTreeView row:nth-child(even) { ... }
2096 * GtkTreeView row:nth-child(odd) { ... }
2099 * would apply to even and odd rows, respectively.
2101 * <note><para>Region names must only contain lowercase letters
2102 * and '-', starting always with a lowercase letter.</para></note>
2107 gtk_style_context_add_region (GtkStyleContext *context,
2108 const gchar *region_name,
2109 GtkRegionFlags flags)
2111 GtkStyleContextPrivate *priv;
2113 GQuark region_quark;
2116 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2117 g_return_if_fail (region_name != NULL);
2118 g_return_if_fail (_gtk_style_context_check_region_name (region_name));
2120 priv = context->priv;
2121 region_quark = g_quark_from_string (region_name);
2123 g_assert (priv->info_stack != NULL);
2124 info = priv->info_stack->data;
2126 if (!region_find (info->regions, region_quark, &position))
2130 region.class_quark = region_quark;
2131 region.flags = flags;
2133 g_array_insert_val (info->regions, position, region);
2135 gtk_style_context_queue_invalidate_internal (context, GTK_CSS_CHANGE_REGION);
2140 * gtk_style_context_remove_region:
2141 * @context: a #GtkStyleContext
2142 * @region_name: region name to unset
2144 * Removes a region from @context.
2149 gtk_style_context_remove_region (GtkStyleContext *context,
2150 const gchar *region_name)
2152 GtkStyleContextPrivate *priv;
2154 GQuark region_quark;
2157 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2158 g_return_if_fail (region_name != NULL);
2160 region_quark = g_quark_try_string (region_name);
2165 priv = context->priv;
2167 g_assert (priv->info_stack != NULL);
2168 info = priv->info_stack->data;
2170 if (region_find (info->regions, region_quark, &position))
2172 g_array_remove_index (info->regions, position);
2174 gtk_style_context_queue_invalidate_internal (context, GTK_CSS_CHANGE_REGION);
2179 * gtk_style_context_has_region:
2180 * @context: a #GtkStyleContext
2181 * @region_name: a region name
2182 * @flags_return: (out) (allow-none): return location for region flags
2184 * Returns %TRUE if @context has the region defined.
2185 * If @flags_return is not %NULL, it is set to the flags
2186 * affecting the region.
2188 * Returns: %TRUE if region is defined
2193 gtk_style_context_has_region (GtkStyleContext *context,
2194 const gchar *region_name,
2195 GtkRegionFlags *flags_return)
2197 GtkStyleContextPrivate *priv;
2199 GQuark region_quark;
2202 g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), FALSE);
2203 g_return_val_if_fail (region_name != NULL, FALSE);
2208 region_quark = g_quark_try_string (region_name);
2213 priv = context->priv;
2215 g_assert (priv->info_stack != NULL);
2216 info = priv->info_stack->data;
2218 if (region_find (info->regions, region_quark, &position))
2224 region = &g_array_index (info->regions, GtkRegion, position);
2225 *flags_return = region->flags;
2234 style_property_values_cmp (gconstpointer bsearch_node1,
2235 gconstpointer bsearch_node2)
2237 const PropertyValue *val1 = bsearch_node1;
2238 const PropertyValue *val2 = bsearch_node2;
2240 if (val1->widget_type != val2->widget_type)
2241 return val1->widget_type < val2->widget_type ? -1 : 1;
2243 if (val1->pspec != val2->pspec)
2244 return val1->pspec < val2->pspec ? -1 : 1;
2246 if (val1->state != val2->state)
2247 return val1->state < val2->state ? -1 : 1;
2253 _gtk_style_context_peek_property (GtkStyleContext *context,
2254 const char *property_name)
2256 StyleData *data = style_data_lookup (context, gtk_style_context_get_state (context));
2258 return _gtk_css_computed_values_get_value_by_name (data->store, property_name);
2262 _gtk_style_context_get_number (GtkStyleContext *context,
2263 const char *property_name,
2264 double one_hundred_percent)
2268 value = _gtk_style_context_peek_property (context, property_name);
2269 return _gtk_css_number_value_get (value, one_hundred_percent);
2273 _gtk_style_context_peek_style_property (GtkStyleContext *context,
2275 GtkStateFlags state,
2278 GtkStyleContextPrivate *priv;
2279 PropertyValue *pcache, key = { 0 };
2283 priv = context->priv;
2284 data = style_data_lookup (context, state);
2286 key.widget_type = widget_type;
2290 /* need value cache array */
2291 if (!data->property_cache)
2292 data->property_cache = g_array_new (FALSE, FALSE, sizeof (PropertyValue));
2295 pcache = bsearch (&key,
2296 data->property_cache->data, data->property_cache->len,
2297 sizeof (PropertyValue), style_property_values_cmp);
2299 return &pcache->value;
2303 while (i < data->property_cache->len &&
2304 style_property_values_cmp (&key, &g_array_index (data->property_cache, PropertyValue, i)) >= 0)
2307 g_array_insert_val (data->property_cache, i, key);
2308 pcache = &g_array_index (data->property_cache, PropertyValue, i);
2310 /* cache miss, initialize value type, then set contents */
2311 g_param_spec_ref (pcache->pspec);
2312 g_value_init (&pcache->value, G_PARAM_SPEC_VALUE_TYPE (pspec));
2314 if (priv->widget || priv->widget_path)
2316 if (gtk_style_provider_get_style_property (GTK_STYLE_PROVIDER (priv->cascade),
2317 priv->widget ? gtk_widget_get_path (priv->widget)
2318 : priv->widget_path,
2319 state, pspec, &pcache->value))
2321 /* Resolve symbolic colors to GdkColor/GdkRGBA */
2322 if (G_VALUE_TYPE (&pcache->value) == GTK_TYPE_SYMBOLIC_COLOR)
2324 GtkSymbolicColor *color;
2327 color = g_value_dup_boxed (&pcache->value);
2329 g_value_unset (&pcache->value);
2331 if (G_PARAM_SPEC_VALUE_TYPE (pspec) == GDK_TYPE_RGBA)
2332 g_value_init (&pcache->value, GDK_TYPE_RGBA);
2334 g_value_init (&pcache->value, GDK_TYPE_COLOR);
2336 if (_gtk_style_context_resolve_color (context, color, &rgba))
2338 if (G_PARAM_SPEC_VALUE_TYPE (pspec) == GDK_TYPE_RGBA)
2339 g_value_set_boxed (&pcache->value, &rgba);
2344 rgb.red = rgba.red * 65535. + 0.5;
2345 rgb.green = rgba.green * 65535. + 0.5;
2346 rgb.blue = rgba.blue * 65535. + 0.5;
2348 g_value_set_boxed (&pcache->value, &rgb);
2352 g_param_value_set_default (pspec, &pcache->value);
2354 gtk_symbolic_color_unref (color);
2357 return &pcache->value;
2361 /* not supplied by any provider, revert to default */
2362 g_param_value_set_default (pspec, &pcache->value);
2364 return &pcache->value;
2368 * gtk_style_context_get_style_property:
2369 * @context: a #GtkStyleContext
2370 * @property_name: the name of the widget style property
2371 * @value: Return location for the property value
2373 * Gets the value for a widget style property.
2375 * When @value is no longer needed, g_value_unset() must be called
2376 * to free any allocated memory.
2379 gtk_style_context_get_style_property (GtkStyleContext *context,
2380 const gchar *property_name,
2383 GtkStyleContextPrivate *priv;
2384 GtkWidgetClass *widget_class;
2385 GtkStateFlags state;
2387 const GValue *peek_value;
2390 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2391 g_return_if_fail (property_name != NULL);
2392 g_return_if_fail (value != NULL);
2394 priv = context->priv;
2398 widget_type = G_OBJECT_TYPE (priv->widget);
2402 if (!priv->widget_path)
2405 widget_type = gtk_widget_path_get_object_type (priv->widget_path);
2407 if (!g_type_is_a (widget_type, GTK_TYPE_WIDGET))
2409 g_warning ("%s: can't get style properties for non-widget class `%s'",
2411 g_type_name (widget_type));
2416 widget_class = g_type_class_ref (widget_type);
2417 pspec = gtk_widget_class_find_style_property (widget_class, property_name);
2418 g_type_class_unref (widget_class);
2422 g_warning ("%s: widget class `%s' has no style property named `%s'",
2424 g_type_name (widget_type),
2429 state = gtk_style_context_get_state (context);
2430 peek_value = _gtk_style_context_peek_style_property (context, widget_type,
2433 if (G_VALUE_TYPE (value) == G_VALUE_TYPE (peek_value))
2434 g_value_copy (peek_value, value);
2435 else if (g_value_type_transformable (G_VALUE_TYPE (peek_value), G_VALUE_TYPE (value)))
2436 g_value_transform (peek_value, value);
2438 g_warning ("can't retrieve style property `%s' of type `%s' as value of type `%s'",
2440 G_VALUE_TYPE_NAME (peek_value),
2441 G_VALUE_TYPE_NAME (value));
2445 * gtk_style_context_get_style_valist:
2446 * @context: a #GtkStyleContext
2447 * @args: va_list of property name/return location pairs, followed by %NULL
2449 * Retrieves several widget style properties from @context according to the
2455 gtk_style_context_get_style_valist (GtkStyleContext *context,
2458 GtkStyleContextPrivate *priv;
2459 const gchar *prop_name;
2460 GtkStateFlags state;
2463 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2465 prop_name = va_arg (args, const gchar *);
2466 priv = context->priv;
2470 widget_type = G_OBJECT_TYPE (priv->widget);
2474 if (!priv->widget_path)
2477 widget_type = gtk_widget_path_get_object_type (priv->widget_path);
2479 if (!g_type_is_a (widget_type, GTK_TYPE_WIDGET))
2481 g_warning ("%s: can't get style properties for non-widget class `%s'",
2483 g_type_name (widget_type));
2488 state = gtk_style_context_get_state (context);
2492 GtkWidgetClass *widget_class;
2494 const GValue *peek_value;
2497 widget_class = g_type_class_ref (widget_type);
2498 pspec = gtk_widget_class_find_style_property (widget_class, prop_name);
2499 g_type_class_unref (widget_class);
2503 g_warning ("%s: widget class `%s' has no style property named `%s'",
2505 g_type_name (widget_type),
2510 peek_value = _gtk_style_context_peek_style_property (context, widget_type,
2513 G_VALUE_LCOPY (peek_value, args, 0, &error);
2517 g_warning ("can't retrieve style property `%s' of type `%s': %s",
2519 G_VALUE_TYPE_NAME (peek_value),
2525 prop_name = va_arg (args, const gchar *);
2530 * gtk_style_context_get_style:
2531 * @context: a #GtkStyleContext
2532 * @...: property name /return value pairs, followed by %NULL
2534 * Retrieves several widget style properties from @context according to the
2540 gtk_style_context_get_style (GtkStyleContext *context,
2545 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2547 va_start (args, context);
2548 gtk_style_context_get_style_valist (context, args);
2554 * gtk_style_context_lookup_icon_set:
2555 * @context: a #GtkStyleContext
2556 * @stock_id: an icon name
2558 * Looks up @stock_id in the icon factories associated to @context and
2559 * the default icon factory, returning an icon set if found, otherwise
2562 * Returns: (transfer none): The looked up %GtkIconSet, or %NULL
2565 gtk_style_context_lookup_icon_set (GtkStyleContext *context,
2566 const gchar *stock_id)
2568 GtkStyleContextPrivate *priv;
2570 g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), NULL);
2571 g_return_val_if_fail (stock_id != NULL, NULL);
2573 priv = context->priv;
2574 g_return_val_if_fail (priv->widget != NULL || priv->widget_path != NULL, NULL);
2576 return gtk_icon_factory_lookup_default (stock_id);
2580 * gtk_style_context_set_screen:
2581 * @context: a #GtkStyleContext
2582 * @screen: a #GdkScreen
2584 * Attaches @context to the given screen.
2586 * The screen is used to add style information from 'global' style
2587 * providers, such as the screens #GtkSettings instance.
2589 * If you are using a #GtkStyleContext returned from
2590 * gtk_widget_get_style_context(), you do not need to
2591 * call this yourself.
2596 gtk_style_context_set_screen (GtkStyleContext *context,
2599 GtkStyleContextPrivate *priv;
2601 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2602 g_return_if_fail (GDK_IS_SCREEN (screen));
2604 priv = context->priv;
2605 if (priv->screen == screen)
2608 if (priv->cascade == _gtk_style_cascade_get_for_screen (priv->screen))
2610 g_object_unref (priv->cascade);
2611 priv->cascade = _gtk_style_cascade_get_for_screen (screen);
2612 g_object_ref (priv->cascade);
2616 _gtk_style_cascade_set_parent (priv->cascade, _gtk_style_cascade_get_for_screen (screen));
2619 priv->screen = screen;
2621 g_object_notify (G_OBJECT (context), "screen");
2623 gtk_style_context_invalidate (context);
2627 * gtk_style_context_get_screen:
2628 * @context: a #GtkStyleContext
2630 * Returns the #GdkScreen to which @context is attached.
2632 * Returns: (transfer none): a #GdkScreen.
2635 gtk_style_context_get_screen (GtkStyleContext *context)
2637 GtkStyleContextPrivate *priv;
2639 g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), NULL);
2641 priv = context->priv;
2642 return priv->screen;
2646 * gtk_style_context_set_direction:
2647 * @context: a #GtkStyleContext
2648 * @direction: the new direction.
2650 * Sets the reading direction for rendering purposes.
2652 * If you are using a #GtkStyleContext returned from
2653 * gtk_widget_get_style_context(), you do not need to
2654 * call this yourself.
2659 gtk_style_context_set_direction (GtkStyleContext *context,
2660 GtkTextDirection direction)
2662 GtkStyleContextPrivate *priv;
2664 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2666 priv = context->priv;
2667 priv->direction = direction;
2669 g_object_notify (G_OBJECT (context), "direction");
2673 * gtk_style_context_get_direction:
2674 * @context: a #GtkStyleContext
2676 * Returns the widget direction used for rendering.
2678 * Returns: the widget direction
2683 gtk_style_context_get_direction (GtkStyleContext *context)
2685 GtkStyleContextPrivate *priv;
2687 g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), GTK_TEXT_DIR_LTR);
2689 priv = context->priv;
2690 return priv->direction;
2694 * gtk_style_context_set_junction_sides:
2695 * @context: a #GtkStyleContext
2696 * @sides: sides where rendered elements are visually connected to
2699 * Sets the sides where rendered elements (mostly through
2700 * gtk_render_frame()) will visually connect with other visual elements.
2702 * This is merely a hint that may or may not be honored
2703 * by theming engines.
2705 * Container widgets are expected to set junction hints as appropriate
2706 * for their children, so it should not normally be necessary to call
2707 * this function manually.
2712 gtk_style_context_set_junction_sides (GtkStyleContext *context,
2713 GtkJunctionSides sides)
2715 GtkStyleContextPrivate *priv;
2718 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2720 priv = context->priv;
2721 info = priv->info_stack->data;
2722 info->junction_sides = sides;
2726 * gtk_style_context_get_junction_sides:
2727 * @context: a #GtkStyleContext
2729 * Returns the sides where rendered elements connect visually with others.
2731 * Returns: the junction sides
2736 gtk_style_context_get_junction_sides (GtkStyleContext *context)
2738 GtkStyleContextPrivate *priv;
2741 g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), 0);
2743 priv = context->priv;
2744 info = priv->info_stack->data;
2745 return info->junction_sides;
2748 static GtkSymbolicColor *
2749 gtk_style_context_color_lookup_func (gpointer contextp,
2752 GtkStyleContext *context = contextp;
2754 return _gtk_style_provider_private_get_color (GTK_STYLE_PROVIDER_PRIVATE (context->priv->cascade), name);
2758 _gtk_style_context_resolve_color_value (GtkStyleContext *context,
2759 GtkSymbolicColor *color)
2761 g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), FALSE);
2762 g_return_val_if_fail (color != NULL, FALSE);
2764 return _gtk_symbolic_color_resolve_full (color,
2765 gtk_style_context_color_lookup_func,
2771 _gtk_style_context_resolve_color (GtkStyleContext *context,
2772 GtkSymbolicColor *color,
2777 g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), FALSE);
2778 g_return_val_if_fail (color != NULL, FALSE);
2779 g_return_val_if_fail (result != NULL, FALSE);
2781 val = _gtk_symbolic_color_resolve_full (color,
2782 gtk_style_context_color_lookup_func,
2787 *result = *_gtk_css_rgba_value_get_rgba (val);
2788 _gtk_css_value_unref (val);
2793 * gtk_style_context_lookup_color:
2794 * @context: a #GtkStyleContext
2795 * @color_name: color name to lookup
2796 * @color: (out): Return location for the looked up color
2798 * Looks up and resolves a color name in the @context color map.
2800 * Returns: %TRUE if @color_name was found and resolved, %FALSE otherwise
2803 gtk_style_context_lookup_color (GtkStyleContext *context,
2804 const gchar *color_name,
2807 GtkSymbolicColor *sym_color;
2809 g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), FALSE);
2810 g_return_val_if_fail (color_name != NULL, FALSE);
2811 g_return_val_if_fail (color != NULL, FALSE);
2813 sym_color = gtk_style_context_color_lookup_func (context, color_name);
2814 if (sym_color == NULL)
2817 return _gtk_style_context_resolve_color (context, sym_color, color);
2821 * gtk_style_context_notify_state_change:
2822 * @context: a #GtkStyleContext
2823 * @window: a #GdkWindow
2824 * @region_id: (allow-none): animatable region to notify on, or %NULL.
2825 * See gtk_style_context_push_animatable_region()
2826 * @state: state to trigger transition for
2827 * @state_value: %TRUE if @state is the state we are changing to,
2828 * %FALSE if we are changing away from it
2830 * Notifies a state change on @context, so if the current style makes use
2831 * of transition animations, one will be started so all rendered elements
2832 * under @region_id are animated for state @state being set to value
2835 * The @window parameter is used in order to invalidate the rendered area
2836 * as the animation runs, so make sure it is the same window that is being
2837 * rendered on by the gtk_render_*() functions.
2839 * If @region_id is %NULL, all rendered elements using @context will be
2840 * affected by this state transition.
2842 * As a practical example, a #GtkButton notifying a state transition on
2843 * the prelight state:
2845 * gtk_style_context_notify_state_change (context,
2846 * gtk_widget_get_window (widget),
2848 * GTK_STATE_PRELIGHT,
2849 * button->in_button);
2852 * Can be handled in the CSS file like this:
2855 * background-color: #f00
2859 * background-color: #fff;
2860 * transition: 200ms linear
2864 * This combination will animate the button background from red to white
2865 * if a pointer enters the button, and back to red if the pointer leaves
2868 * Note that @state is used when finding the transition parameters, which
2869 * is why the style places the transition under the :hover pseudo-class.
2874 gtk_style_context_notify_state_change (GtkStyleContext *context,
2878 gboolean state_value)
2880 GtkStyleContextPrivate *priv;
2881 GtkAnimationDescription *desc;
2882 AnimationInfo *info;
2883 GtkStateFlags flags;
2887 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2888 g_return_if_fail (GDK_IS_WINDOW (window));
2889 g_return_if_fail (state > GTK_STATE_NORMAL && state <= GTK_STATE_FOCUSED);
2891 priv = context->priv;
2892 g_return_if_fail (priv->widget != NULL || priv->widget_path != NULL);
2894 state_value = (state_value == TRUE);
2898 case GTK_STATE_ACTIVE:
2899 flags = GTK_STATE_FLAG_ACTIVE;
2901 case GTK_STATE_PRELIGHT:
2902 flags = GTK_STATE_FLAG_PRELIGHT;
2904 case GTK_STATE_SELECTED:
2905 flags = GTK_STATE_FLAG_SELECTED;
2907 case GTK_STATE_INSENSITIVE:
2908 flags = GTK_STATE_FLAG_INSENSITIVE;
2910 case GTK_STATE_INCONSISTENT:
2911 flags = GTK_STATE_FLAG_INCONSISTENT;
2913 case GTK_STATE_FOCUSED:
2914 flags = GTK_STATE_FLAG_FOCUSED;
2916 case GTK_STATE_NORMAL:
2922 /* Find out if there is any animation description for the given
2923 * state, it will fallback to the normal state as well if necessary.
2925 data = style_data_lookup (context, flags);
2926 v = _gtk_css_computed_values_get_value_by_name (data->store, "transition");
2929 desc = _gtk_css_value_get_boxed (v);
2933 if (_gtk_animation_description_get_duration (desc) == 0)
2936 info = animation_info_lookup (context, region_id, state);
2939 info->target_value != state_value)
2941 /* Target values are the opposite */
2942 if (!_gtk_timeline_get_loop (info->timeline))
2944 /* Reverse the animation */
2945 if (_gtk_timeline_get_direction (info->timeline) == GTK_TIMELINE_DIRECTION_FORWARD)
2946 _gtk_timeline_set_direction (info->timeline, GTK_TIMELINE_DIRECTION_BACKWARD);
2948 _gtk_timeline_set_direction (info->timeline, GTK_TIMELINE_DIRECTION_FORWARD);
2950 info->target_value = state_value;
2954 /* Take it out of its looping state */
2955 _gtk_timeline_set_loop (info->timeline, FALSE);
2959 (!_gtk_animation_description_get_loop (desc) ||
2962 info = animation_info_new (context, region_id,
2963 _gtk_animation_description_get_duration (desc),
2964 _gtk_animation_description_get_progress_type (desc),
2965 _gtk_animation_description_get_loop (desc),
2966 state, state_value, window);
2968 priv->animations = g_slist_prepend (priv->animations, info);
2969 priv->animations_invalidated = TRUE;
2974 * gtk_style_context_cancel_animations:
2975 * @context: a #GtkStyleContext
2976 * @region_id: (allow-none): animatable region to stop, or %NULL.
2977 * See gtk_style_context_push_animatable_region()
2979 * Stops all running animations for @region_id and all animatable
2980 * regions underneath.
2982 * A %NULL @region_id will stop all ongoing animations in @context,
2983 * when dealing with a #GtkStyleContext obtained through
2984 * gtk_widget_get_style_context(), this is normally done for you
2985 * in all circumstances you would expect all widget to be stopped,
2986 * so this should be only used in complex widgets with different
2987 * animatable regions.
2992 gtk_style_context_cancel_animations (GtkStyleContext *context,
2995 GtkStyleContextPrivate *priv;
2996 AnimationInfo *info;
2999 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3001 priv = context->priv;
3002 l = priv->animations;
3010 info->region_id == region_id ||
3011 g_slist_find (info->parent_regions, region_id))
3013 priv->animations = g_slist_remove (priv->animations, info);
3014 animation_info_free (info);
3020 is_parent_of (GdkWindow *parent,
3023 GtkWidget *child_widget, *parent_widget;
3026 gdk_window_get_user_data (child, (gpointer *) &child_widget);
3027 gdk_window_get_user_data (parent, (gpointer *) &parent_widget);
3029 if (child_widget != parent_widget &&
3030 !gtk_widget_is_ancestor (child_widget, parent_widget))
3037 if (window == parent)
3040 window = gdk_window_get_parent (window);
3047 * gtk_style_context_scroll_animations:
3048 * @context: a #GtkStyleContext
3049 * @window: a #GdkWindow used previously in
3050 * gtk_style_context_notify_state_change()
3051 * @dx: Amount to scroll in the X axis
3052 * @dy: Amount to scroll in the Y axis
3054 * This function is analogous to gdk_window_scroll(), and
3055 * should be called together with it so the invalidation
3056 * areas for any ongoing animation are scrolled together
3062 gtk_style_context_scroll_animations (GtkStyleContext *context,
3067 GtkStyleContextPrivate *priv;
3068 AnimationInfo *info;
3071 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3072 g_return_if_fail (GDK_IS_WINDOW (window));
3074 priv = context->priv;
3075 l = priv->animations;
3082 if (info->invalidation_region &&
3083 (window == info->window ||
3084 is_parent_of (window, info->window)))
3085 cairo_region_translate (info->invalidation_region, dx, dy);
3090 * gtk_style_context_push_animatable_region:
3091 * @context: a #GtkStyleContext
3092 * @region_id: unique identifier for the animatable region
3094 * Pushes an animatable region, so all further gtk_render_*() calls between
3095 * this call and the following gtk_style_context_pop_animatable_region()
3096 * will potentially show transition animations for this region if
3097 * gtk_style_context_notify_state_change() is called for a given state,
3098 * and the current theme/style defines transition animations for state
3101 * The @region_id used must be unique in @context so the theming engine
3102 * can uniquely identify rendered elements subject to a state transition.
3107 gtk_style_context_push_animatable_region (GtkStyleContext *context,
3110 GtkStyleContextPrivate *priv;
3112 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3113 g_return_if_fail (region_id != NULL);
3115 priv = context->priv;
3116 priv->animation_regions = g_slist_prepend (priv->animation_regions, region_id);
3120 * gtk_style_context_pop_animatable_region:
3121 * @context: a #GtkStyleContext
3123 * Pops an animatable region from @context.
3124 * See gtk_style_context_push_animatable_region().
3129 gtk_style_context_pop_animatable_region (GtkStyleContext *context)
3131 GtkStyleContextPrivate *priv;
3133 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3135 priv = context->priv;
3136 priv->animation_regions = g_slist_delete_link (priv->animation_regions,
3137 priv->animation_regions);
3141 _gtk_style_context_invalidate_animation_areas (GtkStyleContext *context)
3143 GtkStyleContextPrivate *priv;
3146 priv = context->priv;
3148 for (l = priv->animations; l; l = l->next)
3150 AnimationInfo *info;
3154 /* A NULL invalidation region means it has to be recreated on
3155 * the next expose event, this happens usually after a widget
3156 * allocation change, so the next expose after it will update
3157 * the invalidation region.
3159 if (info->invalidation_region)
3161 cairo_region_destroy (info->invalidation_region);
3162 info->invalidation_region = NULL;
3166 priv->animations_invalidated = TRUE;
3170 _gtk_style_context_coalesce_animation_areas (GtkStyleContext *context,
3173 GtkStyleContextPrivate *priv;
3176 priv = context->priv;
3178 if (!priv->animations_invalidated)
3181 l = priv->animations;
3185 AnimationInfo *info;
3194 if (info->invalidation_region)
3197 if (info->rectangles->len == 0)
3200 info->invalidation_region = cairo_region_create ();
3201 _gtk_widget_get_translation_to_window (widget, info->window, &rel_x, &rel_y);
3203 for (i = 0; i < info->rectangles->len; i++)
3205 cairo_rectangle_int_t *rect;
3207 rect = &g_array_index (info->rectangles, cairo_rectangle_int_t, i);
3209 /* These are widget relative coordinates,
3210 * so have them inverted to be window relative
3215 cairo_region_union_rectangle (info->invalidation_region, rect);
3218 g_array_remove_range (info->rectangles, 0, info->rectangles->len);
3221 priv->animations_invalidated = FALSE;
3225 store_animation_region (GtkStyleContext *context,
3231 GtkStyleContextPrivate *priv;
3234 priv = context->priv;
3236 if (!priv->animations_invalidated)
3239 for (l = priv->animations; l; l = l->next)
3241 AnimationInfo *info;
3245 /* The animation doesn't need updating
3246 * the invalidation area, bail out.
3248 if (info->invalidation_region)
3251 if (context_has_animatable_region (context, info->region_id))
3253 cairo_rectangle_int_t rect;
3257 rect.width = (gint) width;
3258 rect.height = (gint) height;
3260 g_array_append_val (info->rectangles, rect);
3262 if (!info->parent_regions)
3264 GSList *parent_regions;
3266 parent_regions = g_slist_find (priv->animation_regions, info->region_id);
3267 info->parent_regions = g_slist_copy (parent_regions);
3274 gtk_style_context_do_invalidate (GtkStyleContext *context,
3275 gboolean clear_caches)
3277 GtkStyleContextPrivate *priv;
3279 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3281 priv = context->priv;
3283 /* Avoid reentrancy */
3284 if (priv->invalidating_context)
3287 priv->invalidating_context = TRUE;
3290 g_hash_table_remove_all (priv->style_data);
3291 priv->current_data = NULL;
3293 g_signal_emit (context, signals[CHANGED], 0);
3295 priv->invalidating_context = FALSE;
3299 _gtk_style_context_validate (GtkStyleContext *context,
3300 GtkCssChange change)
3302 GtkStyleContextPrivate *priv;
3305 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3307 priv = context->priv;
3309 change |= priv->pending_changes;
3311 if (!priv->invalid && change == 0)
3314 priv->pending_changes = 0;
3315 gtk_style_context_set_invalid (context, FALSE);
3317 /* Try to avoid invalidating if we can */
3318 if (change & GTK_STYLE_CONTEXT_RADICAL_CHANGE)
3320 priv->relevant_changes = GTK_CSS_CHANGE_ANY;
3324 if (priv->relevant_changes == GTK_CSS_CHANGE_ANY)
3326 GtkWidgetPath *path;
3327 GtkCssMatcher matcher;
3329 path = create_query_path (context);
3330 _gtk_css_matcher_init (&matcher, path, priv->current_state);
3332 priv->relevant_changes = _gtk_style_provider_private_get_change (GTK_STYLE_PROVIDER_PRIVATE (priv->cascade),
3334 priv->relevant_changes &= ~GTK_STYLE_CONTEXT_RADICAL_CHANGE;
3336 gtk_widget_path_unref (path);
3340 if (priv->relevant_changes & change)
3342 gboolean clear_cache = ((priv->relevant_changes & change) & ~GTK_STYLE_CONTEXT_CACHED_CHANGE) != 0;
3344 gtk_style_context_do_invalidate (context, clear_cache);
3347 change = _gtk_css_change_for_child (change);
3348 for (list = priv->children; list; list = list->next)
3350 _gtk_style_context_validate (list->data, change);
3355 _gtk_style_context_queue_invalidate (GtkStyleContext *context,
3356 GtkCssChange change)
3358 GtkStyleContextPrivate *priv;
3360 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3361 g_return_if_fail (change != 0);
3363 priv = context->priv;
3365 if (priv->widget == NULL && priv->widget_path == NULL)
3368 priv->pending_changes |= change;
3369 gtk_style_context_set_invalid (context, TRUE);
3373 * gtk_style_context_invalidate:
3374 * @context: a #GtkStyleContext.
3376 * Invalidates @context style information, so it will be reconstructed
3379 * If you're using a #GtkStyleContext returned from
3380 * gtk_widget_get_style_context(), you do not need to
3381 * call this yourself.
3386 gtk_style_context_invalidate (GtkStyleContext *context)
3388 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3390 gtk_style_context_do_invalidate (context, TRUE);
3394 * gtk_style_context_set_background:
3395 * @context: a #GtkStyleContext
3396 * @window: a #GdkWindow
3398 * Sets the background of @window to the background pattern or
3399 * color specified in @context for its current state.
3404 gtk_style_context_set_background (GtkStyleContext *context,
3407 GtkStateFlags state;
3408 cairo_pattern_t *pattern;
3411 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3412 g_return_if_fail (GDK_IS_WINDOW (window));
3414 state = gtk_style_context_get_state (context);
3415 gtk_style_context_get (context, state,
3416 "background-image", &pattern,
3420 gdk_window_set_background_pattern (window, pattern);
3421 cairo_pattern_destroy (pattern);
3425 gtk_style_context_get (context, state,
3426 "background-color", &color,
3430 gdk_window_set_background_rgba (window, color);
3431 gdk_rgba_free (color);
3436 * gtk_style_context_get_color:
3437 * @context: a #GtkStyleContext
3438 * @state: state to retrieve the color for
3439 * @color: (out): return value for the foreground color
3441 * Gets the foreground color for a given state.
3446 gtk_style_context_get_color (GtkStyleContext *context,
3447 GtkStateFlags state,
3452 g_return_if_fail (color != NULL);
3453 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3455 gtk_style_context_get (context,
3465 * gtk_style_context_get_background_color:
3466 * @context: a #GtkStyleContext
3467 * @state: state to retrieve the color for
3468 * @color: (out): return value for the background color
3470 * Gets the background color for a given state.
3475 gtk_style_context_get_background_color (GtkStyleContext *context,
3476 GtkStateFlags state,
3481 g_return_if_fail (color != NULL);
3482 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3484 gtk_style_context_get (context,
3486 "background-color", &c,
3494 * gtk_style_context_get_border_color:
3495 * @context: a #GtkStyleContext
3496 * @state: state to retrieve the color for
3497 * @color: (out): return value for the border color
3499 * Gets the border color for a given state.
3504 gtk_style_context_get_border_color (GtkStyleContext *context,
3505 GtkStateFlags state,
3510 g_return_if_fail (color != NULL);
3511 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3513 gtk_style_context_get (context,
3523 * gtk_style_context_get_border:
3524 * @context: a #GtkStyleContext
3525 * @state: state to retrieve the border for
3526 * @border: (out): return value for the border settings
3528 * Gets the border for a given state as a #GtkBorder.
3529 * See %GTK_STYLE_PROPERTY_BORDER_WIDTH.
3534 gtk_style_context_get_border (GtkStyleContext *context,
3535 GtkStateFlags state,
3538 int top, left, bottom, right;
3540 g_return_if_fail (border != NULL);
3541 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3543 gtk_style_context_get (context,
3545 "border-top-width", &top,
3546 "border-left-width", &left,
3547 "border-bottom-width", &bottom,
3548 "border-right-width", &right,
3552 border->left = left;
3553 border->bottom = bottom;
3554 border->right = right;
3558 * gtk_style_context_get_padding:
3559 * @context: a #GtkStyleContext
3560 * @state: state to retrieve the padding for
3561 * @padding: (out): return value for the padding settings
3563 * Gets the padding for a given state as a #GtkBorder.
3564 * See %GTK_STYLE_PROPERTY_PADDING.
3569 gtk_style_context_get_padding (GtkStyleContext *context,
3570 GtkStateFlags state,
3573 int top, left, bottom, right;
3575 g_return_if_fail (padding != NULL);
3576 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3578 gtk_style_context_get (context,
3580 "padding-top", &top,
3581 "padding-left", &left,
3582 "padding-bottom", &bottom,
3583 "padding-right", &right,
3587 padding->left = left;
3588 padding->bottom = bottom;
3589 padding->right = right;
3593 * gtk_style_context_get_margin:
3594 * @context: a #GtkStyleContext
3595 * @state: state to retrieve the border for
3596 * @margin: (out): return value for the margin settings
3598 * Gets the margin for a given state as a #GtkBorder.
3599 * See %GTK_STYLE_PROPERTY_MARGIN.
3604 gtk_style_context_get_margin (GtkStyleContext *context,
3605 GtkStateFlags state,
3608 int top, left, bottom, right;
3610 g_return_if_fail (margin != NULL);
3611 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3613 gtk_style_context_get (context,
3616 "margin-left", &left,
3617 "margin-bottom", &bottom,
3618 "margin-right", &right,
3622 margin->left = left;
3623 margin->bottom = bottom;
3624 margin->right = right;
3628 * gtk_style_context_get_font:
3629 * @context: a #GtkStyleContext
3630 * @state: state to retrieve the font for
3632 * Returns the font description for a given state. The returned
3633 * object is const and will remain valid until the
3634 * #GtkStyleContext::changed signal happens.
3636 * Returns: (transfer none): the #PangoFontDescription for the given
3637 * state. This object is owned by GTK+ and should not be
3642 const PangoFontDescription *
3643 gtk_style_context_get_font (GtkStyleContext *context,
3644 GtkStateFlags state)
3646 GtkStyleContextPrivate *priv;
3648 PangoFontDescription *description;
3650 g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), NULL);
3652 priv = context->priv;
3653 g_return_val_if_fail (priv->widget != NULL || priv->widget_path != NULL, NULL);
3655 data = style_data_lookup (context, state);
3657 /* Yuck, fonts are created on-demand but we don't return a ref.
3658 * Do bad things to achieve this requirement */
3659 description = g_object_get_data (G_OBJECT (data->store), "font-cache-for-get_font");
3660 if (description == NULL)
3662 gtk_style_context_get (context, state, "font", &description, NULL);
3663 g_object_set_data_full (G_OBJECT (data->store),
3664 "font-cache-for-get_font",
3666 (GDestroyNotify) pango_font_description_free);
3672 get_cursor_color (GtkStyleContext *context,
3676 GdkColor *style_color;
3678 gtk_style_context_get_style (context,
3679 primary ? "cursor-color" : "secondary-cursor-color",
3685 color->red = style_color->red / 65535.0;
3686 color->green = style_color->green / 65535.0;
3687 color->blue = style_color->blue / 65535.0;
3690 gdk_color_free (style_color);
3694 gtk_style_context_get_color (context, GTK_STATE_FLAG_NORMAL, color);
3700 gtk_style_context_get_background_color (context, GTK_STATE_FLAG_NORMAL, &bg);
3702 color->red = (color->red + bg.red) * 0.5;
3703 color->green = (color->green + bg.green) * 0.5;
3704 color->blue = (color->blue + bg.blue) * 0.5;
3710 _gtk_style_context_get_cursor_color (GtkStyleContext *context,
3711 GdkRGBA *primary_color,
3712 GdkRGBA *secondary_color)
3715 get_cursor_color (context, TRUE, primary_color);
3717 if (secondary_color)
3718 get_cursor_color (context, FALSE, secondary_color);
3725 * @context: a #GtkStyleContext
3727 * @x: X origin of the rectangle
3728 * @y: Y origin of the rectangle
3729 * @width: rectangle width
3730 * @height: rectangle height
3732 * Renders a checkmark (as in a #GtkCheckButton).
3734 * The %GTK_STATE_FLAG_ACTIVE state determines whether the check is
3735 * on or off, and %GTK_STATE_FLAG_INCONSISTENT determines whether it
3736 * should be marked as undefined.
3739 * <title>Typical checkmark rendering</title>
3740 * <inlinegraphic fileref="checks.png" format="PNG"/>
3746 gtk_render_check (GtkStyleContext *context,
3753 GtkStyleContextPrivate *priv;
3754 GtkThemingEngineClass *engine_class;
3756 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3757 g_return_if_fail (cr != NULL);
3759 if (width <= 0 || height <= 0)
3762 priv = context->priv;
3763 engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
3767 store_animation_region (context, x, y, width, height);
3769 _gtk_theming_engine_set_context (priv->theming_engine, context);
3770 engine_class->render_check (priv->theming_engine, cr,
3771 x, y, width, height);
3777 * gtk_render_option:
3778 * @context: a #GtkStyleContext
3780 * @x: X origin of the rectangle
3781 * @y: Y origin of the rectangle
3782 * @width: rectangle width
3783 * @height: rectangle height
3785 * Renders an option mark (as in a #GtkRadioButton), the %GTK_STATE_FLAG_ACTIVE
3786 * state will determine whether the option is on or off, and
3787 * %GTK_STATE_FLAG_INCONSISTENT whether it should be marked as undefined.
3790 * <title>Typical option mark rendering</title>
3791 * <inlinegraphic fileref="options.png" format="PNG"/>
3797 gtk_render_option (GtkStyleContext *context,
3804 GtkStyleContextPrivate *priv;
3805 GtkThemingEngineClass *engine_class;
3807 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3808 g_return_if_fail (cr != NULL);
3810 if (width <= 0 || height <= 0)
3813 priv = context->priv;
3814 engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
3818 store_animation_region (context, x, y, width, height);
3820 _gtk_theming_engine_set_context (priv->theming_engine, context);
3821 engine_class->render_option (priv->theming_engine, cr,
3822 x, y, width, height);
3829 * @context: a #GtkStyleContext
3831 * @angle: arrow angle from 0 to 2 * %G_PI, being 0 the arrow pointing to the north
3832 * @x: X origin of the render area
3833 * @y: Y origin of the render area
3834 * @size: square side for render area
3836 * Renders an arrow pointing to @angle.
3839 * <title>Typical arrow rendering at 0, 1&solidus;2 π, π and 3&solidus;2 π</title>
3840 * <inlinegraphic fileref="arrows.png" format="PNG"/>
3846 gtk_render_arrow (GtkStyleContext *context,
3853 GtkStyleContextPrivate *priv;
3854 GtkThemingEngineClass *engine_class;
3856 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3857 g_return_if_fail (cr != NULL);
3862 priv = context->priv;
3863 engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
3867 gtk_style_context_save (context);
3868 gtk_style_context_add_class (context, GTK_STYLE_CLASS_ARROW);
3870 store_animation_region (context, x, y, size, size);
3872 _gtk_theming_engine_set_context (priv->theming_engine, context);
3873 engine_class->render_arrow (priv->theming_engine, cr,
3876 gtk_style_context_restore (context);
3881 * gtk_render_background:
3882 * @context: a #GtkStyleContext
3884 * @x: X origin of the rectangle
3885 * @y: Y origin of the rectangle
3886 * @width: rectangle width
3887 * @height: rectangle height
3889 * Renders the background of an element.
3892 * <title>Typical background rendering, showing the effect of
3893 * <parameter>background-image</parameter>,
3894 * <parameter>border-width</parameter> and
3895 * <parameter>border-radius</parameter></title>
3896 * <inlinegraphic fileref="background.png" format="PNG"/>
3902 gtk_render_background (GtkStyleContext *context,
3909 GtkStyleContextPrivate *priv;
3910 GtkThemingEngineClass *engine_class;
3912 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3913 g_return_if_fail (cr != NULL);
3915 if (width <= 0 || height <= 0)
3918 priv = context->priv;
3919 engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
3923 store_animation_region (context, x, y, width, height);
3925 _gtk_theming_engine_set_context (priv->theming_engine, context);
3926 engine_class->render_background (priv->theming_engine, cr, x, y, width, height);
3933 * @context: a #GtkStyleContext
3935 * @x: X origin of the rectangle
3936 * @y: Y origin of the rectangle
3937 * @width: rectangle width
3938 * @height: rectangle height
3940 * Renders a frame around the rectangle defined by @x, @y, @width, @height.
3943 * <title>Examples of frame rendering, showing the effect of
3944 * <parameter>border-image</parameter>,
3945 * <parameter>border-color</parameter>,
3946 * <parameter>border-width</parameter>,
3947 * <parameter>border-radius</parameter> and
3949 * <inlinegraphic fileref="frames.png" format="PNG"/>
3955 gtk_render_frame (GtkStyleContext *context,
3962 GtkStyleContextPrivate *priv;
3963 GtkThemingEngineClass *engine_class;
3965 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3966 g_return_if_fail (cr != NULL);
3968 if (width <= 0 || height <= 0)
3971 priv = context->priv;
3972 engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
3976 store_animation_region (context, x, y, width, height);
3978 _gtk_theming_engine_set_context (priv->theming_engine, context);
3979 engine_class->render_frame (priv->theming_engine, cr, x, y, width, height);
3985 * gtk_render_expander:
3986 * @context: a #GtkStyleContext
3988 * @x: X origin of the rectangle
3989 * @y: Y origin of the rectangle
3990 * @width: rectangle width
3991 * @height: rectangle height
3993 * Renders an expander (as used in #GtkTreeView and #GtkExpander) in the area
3994 * defined by @x, @y, @width, @height. The state %GTK_STATE_FLAG_ACTIVE
3995 * determines whether the expander is collapsed or expanded.
3998 * <title>Typical expander rendering</title>
3999 * <inlinegraphic fileref="expanders.png" format="PNG"/>
4005 gtk_render_expander (GtkStyleContext *context,
4012 GtkStyleContextPrivate *priv;
4013 GtkThemingEngineClass *engine_class;
4015 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
4016 g_return_if_fail (cr != NULL);
4018 if (width <= 0 || height <= 0)
4021 priv = context->priv;
4022 engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
4026 store_animation_region (context, x, y, width, height);
4028 _gtk_theming_engine_set_context (priv->theming_engine, context);
4029 engine_class->render_expander (priv->theming_engine, cr, x, y, width, height);
4036 * @context: a #GtkStyleContext
4038 * @x: X origin of the rectangle
4039 * @y: Y origin of the rectangle
4040 * @width: rectangle width
4041 * @height: rectangle height
4043 * Renders a focus indicator on the rectangle determined by @x, @y, @width, @height.
4045 * <title>Typical focus rendering</title>
4046 * <inlinegraphic fileref="focus.png" format="PNG"/>
4052 gtk_render_focus (GtkStyleContext *context,
4059 GtkStyleContextPrivate *priv;
4060 GtkThemingEngineClass *engine_class;
4062 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
4063 g_return_if_fail (cr != NULL);
4065 if (width <= 0 || height <= 0)
4068 priv = context->priv;
4069 engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
4073 store_animation_region (context, x, y, width, height);
4075 _gtk_theming_engine_set_context (priv->theming_engine, context);
4076 engine_class->render_focus (priv->theming_engine, cr, x, y, width, height);
4082 * gtk_render_layout:
4083 * @context: a #GtkStyleContext
4087 * @layout: the #PangoLayout to render
4089 * Renders @layout on the coordinates @x, @y
4094 gtk_render_layout (GtkStyleContext *context,
4098 PangoLayout *layout)
4100 GtkStyleContextPrivate *priv;
4101 GtkThemingEngineClass *engine_class;
4102 PangoRectangle extents;
4104 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
4105 g_return_if_fail (PANGO_IS_LAYOUT (layout));
4106 g_return_if_fail (cr != NULL);
4108 priv = context->priv;
4109 engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
4113 pango_layout_get_extents (layout, &extents, NULL);
4115 store_animation_region (context,
4121 _gtk_theming_engine_set_context (priv->theming_engine, context);
4122 engine_class->render_layout (priv->theming_engine, cr, x, y, layout);
4129 * @context: a #GtkStyleContext
4131 * @x0: X coordinate for the origin of the line
4132 * @y0: Y coordinate for the origin of the line
4133 * @x1: X coordinate for the end of the line
4134 * @y1: Y coordinate for the end of the line
4136 * Renders a line from (x0, y0) to (x1, y1).
4141 gtk_render_line (GtkStyleContext *context,
4148 GtkStyleContextPrivate *priv;
4149 GtkThemingEngineClass *engine_class;
4151 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
4152 g_return_if_fail (cr != NULL);
4154 priv = context->priv;
4155 engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
4159 _gtk_theming_engine_set_context (priv->theming_engine, context);
4160 engine_class->render_line (priv->theming_engine, cr, x0, y0, x1, y1);
4166 * gtk_render_slider:
4167 * @context: a #GtkStyleContext
4169 * @x: X origin of the rectangle
4170 * @y: Y origin of the rectangle
4171 * @width: rectangle width
4172 * @height: rectangle height
4173 * @orientation: orientation of the slider
4175 * Renders a slider (as in #GtkScale) in the rectangle defined by @x, @y,
4176 * @width, @height. @orientation defines whether the slider is vertical
4180 * <title>Typical slider rendering</title>
4181 * <inlinegraphic fileref="sliders.png" format="PNG"/>
4187 gtk_render_slider (GtkStyleContext *context,
4193 GtkOrientation orientation)
4195 GtkStyleContextPrivate *priv;
4196 GtkThemingEngineClass *engine_class;
4198 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
4199 g_return_if_fail (cr != NULL);
4201 if (width <= 0 || height <= 0)
4204 priv = context->priv;
4205 engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
4209 store_animation_region (context, x, y, width, height);
4211 _gtk_theming_engine_set_context (priv->theming_engine, context);
4212 engine_class->render_slider (priv->theming_engine, cr, x, y, width, height, orientation);
4218 * gtk_render_frame_gap:
4219 * @context: a #GtkStyleContext
4221 * @x: X origin of the rectangle
4222 * @y: Y origin of the rectangle
4223 * @width: rectangle width
4224 * @height: rectangle height
4225 * @gap_side: side where the gap is
4226 * @xy0_gap: initial coordinate (X or Y depending on @gap_side) for the gap
4227 * @xy1_gap: end coordinate (X or Y depending on @gap_side) for the gap
4229 * Renders a frame around the rectangle defined by (@x, @y, @width, @height),
4230 * leaving a gap on one side. @xy0_gap and @xy1_gap will mean X coordinates
4231 * for %GTK_POS_TOP and %GTK_POS_BOTTOM gap sides, and Y coordinates for
4232 * %GTK_POS_LEFT and %GTK_POS_RIGHT.
4235 * <title>Typical rendering of a frame with a gap</title>
4236 * <inlinegraphic fileref="frame-gap.png" format="PNG"/>
4242 gtk_render_frame_gap (GtkStyleContext *context,
4248 GtkPositionType gap_side,
4252 GtkStyleContextPrivate *priv;
4253 GtkThemingEngineClass *engine_class;
4255 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
4256 g_return_if_fail (cr != NULL);
4257 g_return_if_fail (xy0_gap <= xy1_gap);
4258 g_return_if_fail (xy0_gap >= 0);
4260 if (width <= 0 || height <= 0)
4263 if (gap_side == GTK_POS_LEFT ||
4264 gap_side == GTK_POS_RIGHT)
4265 g_return_if_fail (xy1_gap <= height);
4267 g_return_if_fail (xy1_gap <= width);
4269 priv = context->priv;
4270 engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
4274 store_animation_region (context, x, y, width, height);
4276 _gtk_theming_engine_set_context (priv->theming_engine, context);
4277 engine_class->render_frame_gap (priv->theming_engine, cr,
4278 x, y, width, height, gap_side,
4285 * gtk_render_extension:
4286 * @context: a #GtkStyleContext
4288 * @x: X origin of the rectangle
4289 * @y: Y origin of the rectangle
4290 * @width: rectangle width
4291 * @height: rectangle height
4292 * @gap_side: side where the gap is
4294 * Renders a extension (as in a #GtkNotebook tab) in the rectangle
4295 * defined by @x, @y, @width, @height. The side where the extension
4296 * connects to is defined by @gap_side.
4299 * <title>Typical extension rendering</title>
4300 * <inlinegraphic fileref="extensions.png" format="PNG"/>
4306 gtk_render_extension (GtkStyleContext *context,
4312 GtkPositionType gap_side)
4314 GtkStyleContextPrivate *priv;
4315 GtkThemingEngineClass *engine_class;
4317 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
4318 g_return_if_fail (cr != NULL);
4320 if (width <= 0 || height <= 0)
4323 priv = context->priv;
4324 engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
4328 store_animation_region (context, x, y, width, height);
4330 _gtk_theming_engine_set_context (priv->theming_engine, context);
4331 engine_class->render_extension (priv->theming_engine, cr, x, y, width, height, gap_side);
4337 * gtk_render_handle:
4338 * @context: a #GtkStyleContext
4340 * @x: X origin of the rectangle
4341 * @y: Y origin of the rectangle
4342 * @width: rectangle width
4343 * @height: rectangle height
4345 * Renders a handle (as in #GtkHandleBox, #GtkPaned and
4346 * #GtkWindow<!-- -->'s resize grip), in the rectangle
4347 * determined by @x, @y, @width, @height.
4350 * <title>Handles rendered for the paned and grip classes</title>
4351 * <inlinegraphic fileref="handles.png" format="PNG"/>
4357 gtk_render_handle (GtkStyleContext *context,
4364 GtkStyleContextPrivate *priv;
4365 GtkThemingEngineClass *engine_class;
4367 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
4368 g_return_if_fail (cr != NULL);
4370 if (width <= 0 || height <= 0)
4373 priv = context->priv;
4374 engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
4378 store_animation_region (context, x, y, width, height);
4380 _gtk_theming_engine_set_context (priv->theming_engine, context);
4381 engine_class->render_handle (priv->theming_engine, cr, x, y, width, height);
4387 * gtk_render_activity:
4388 * @context: a #GtkStyleContext
4390 * @x: X origin of the rectangle
4391 * @y: Y origin of the rectangle
4392 * @width: rectangle width
4393 * @height: rectangle height
4395 * Renders an activity area (Such as in #GtkSpinner or the
4396 * fill line in #GtkRange), the state %GTK_STATE_FLAG_ACTIVE
4397 * determines whether there is activity going on.
4402 gtk_render_activity (GtkStyleContext *context,
4409 GtkStyleContextPrivate *priv;
4410 GtkThemingEngineClass *engine_class;
4412 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
4413 g_return_if_fail (cr != NULL);
4415 if (width <= 0 || height <= 0)
4418 priv = context->priv;
4419 engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
4423 store_animation_region (context, x, y, width, height);
4425 _gtk_theming_engine_set_context (priv->theming_engine, context);
4426 engine_class->render_activity (priv->theming_engine, cr, x, y, width, height);
4432 * gtk_render_icon_pixbuf:
4433 * @context: a #GtkStyleContext
4434 * @source: the #GtkIconSource specifying the icon to render
4435 * @size: (type int): the size to render the icon at. A size of (GtkIconSize) -1
4436 * means render at the size of the source and don't scale.
4438 * Renders the icon specified by @source at the given @size, returning the result
4441 * Returns: (transfer full): a newly-created #GdkPixbuf containing the rendered icon
4446 gtk_render_icon_pixbuf (GtkStyleContext *context,
4447 const GtkIconSource *source,
4450 GtkStyleContextPrivate *priv;
4451 GtkThemingEngineClass *engine_class;
4453 g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), NULL);
4454 g_return_val_if_fail (size > GTK_ICON_SIZE_INVALID || size == -1, NULL);
4455 g_return_val_if_fail (source != NULL, NULL);
4457 priv = context->priv;
4458 engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
4460 _gtk_theming_engine_set_context (priv->theming_engine, context);
4461 return engine_class->render_icon_pixbuf (priv->theming_engine, source, size);
4466 * @context: a #GtkStyleContext
4468 * @pixbuf: a #GdkPixbuf containing the icon to draw
4469 * @x: X position for the @pixbuf
4470 * @y: Y position for the @pixbuf
4472 * Renders the icon in @pixbuf at the specified @x and @y coordinates.
4477 gtk_render_icon (GtkStyleContext *context,
4483 GtkStyleContextPrivate *priv;
4484 GtkThemingEngineClass *engine_class;
4486 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
4487 g_return_if_fail (cr != NULL);
4489 priv = context->priv;
4490 engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
4494 store_animation_region (context,
4496 gdk_pixbuf_get_width (pixbuf),
4497 gdk_pixbuf_get_height (pixbuf));
4499 _gtk_theming_engine_set_context (priv->theming_engine, context);
4500 engine_class->render_icon (priv->theming_engine, cr, pixbuf, x, y);
4506 draw_insertion_cursor (GtkStyleContext *context,
4511 gboolean is_primary,
4512 PangoDirection direction,
4513 gboolean draw_arrow)
4516 GdkRGBA primary_color;
4517 GdkRGBA secondary_color;
4518 gfloat cursor_aspect_ratio;
4524 _gtk_style_context_get_cursor_color (context, &primary_color, &secondary_color);
4525 gdk_cairo_set_source_rgba (cr, is_primary ? &primary_color : &secondary_color);
4527 /* When changing the shape or size of the cursor here,
4528 * propagate the changes to gtktextview.c:text_window_invalidate_cursors().
4531 gtk_style_context_get_style (context,
4532 "cursor-aspect-ratio", &cursor_aspect_ratio,
4535 stem_width = height * cursor_aspect_ratio + 1;
4537 /* put (stem_width % 2) on the proper side of the cursor */
4538 if (direction == PANGO_DIRECTION_LTR)
4539 offset = stem_width / 2;
4541 offset = stem_width - stem_width / 2;
4543 cairo_rectangle (cr, x - offset, y, stem_width, height);
4551 arrow_width = stem_width + 1;
4553 if (direction == PANGO_DIRECTION_RTL)
4555 ax = x - offset - 1;
4556 ay = y + height - arrow_width * 2 - arrow_width + 1;
4558 cairo_move_to (cr, ax, ay + 1);
4559 cairo_line_to (cr, ax - arrow_width, ay + arrow_width);
4560 cairo_line_to (cr, ax, ay + 2 * arrow_width);
4563 else if (direction == PANGO_DIRECTION_LTR)
4565 ax = x + stem_width - offset;
4566 ay = y + height - arrow_width * 2 - arrow_width + 1;
4568 cairo_move_to (cr, ax, ay + 1);
4569 cairo_line_to (cr, ax + arrow_width, ay + arrow_width);
4570 cairo_line_to (cr, ax, ay + 2 * arrow_width);
4574 g_assert_not_reached();
4581 * gtk_render_insertion_cursor:
4582 * @context: a #GtkStyleContext
4586 * @layout: the #PangoLayout of the text
4587 * @index: the index in the #PangoLayout
4588 * @direction: the #PangoDirection of the text
4590 * Draws a text caret on @cr at the specified index of @layout.
4595 gtk_render_insertion_cursor (GtkStyleContext *context,
4599 PangoLayout *layout,
4601 PangoDirection direction)
4603 GtkStyleContextPrivate *priv;
4604 gboolean split_cursor;
4605 PangoRectangle strong_pos, weak_pos;
4606 PangoRectangle *cursor1, *cursor2;
4607 PangoDirection keymap_direction;
4608 PangoDirection direction2;
4610 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
4611 g_return_if_fail (cr != NULL);
4612 g_return_if_fail (PANGO_IS_LAYOUT (layout));
4613 g_return_if_fail (index >= 0);
4615 priv = context->priv;
4617 g_object_get (gtk_settings_get_for_screen (priv->screen),
4618 "gtk-split-cursor", &split_cursor,
4621 keymap_direction = gdk_keymap_get_direction (gdk_keymap_get_for_display (gdk_screen_get_display (priv->screen)));
4623 pango_layout_get_cursor_pos (layout, index, &strong_pos, &weak_pos);
4625 direction2 = PANGO_DIRECTION_NEUTRAL;
4629 cursor1 = &strong_pos;
4631 if (strong_pos.x != weak_pos.x || strong_pos.y != weak_pos.y)
4633 direction2 = (direction == PANGO_DIRECTION_LTR) ? PANGO_DIRECTION_RTL : PANGO_DIRECTION_LTR;
4634 cursor2 = &weak_pos;
4639 if (keymap_direction == direction)
4640 cursor1 = &strong_pos;
4642 cursor1 = &weak_pos;
4645 draw_insertion_cursor (context,
4647 x + PANGO_PIXELS (cursor1->x),
4648 y + PANGO_PIXELS (cursor1->y),
4649 PANGO_PIXELS (cursor1->height),
4652 direction2 != PANGO_DIRECTION_NEUTRAL);
4654 if (direction2 != PANGO_DIRECTION_NEUTRAL)
4656 draw_insertion_cursor (context,
4658 x + PANGO_PIXELS (cursor2->x),
4659 y + PANGO_PIXELS (cursor2->y),
4660 PANGO_PIXELS (cursor2->height),
4668 * gtk_draw_insertion_cursor:
4669 * @widget: a #GtkWidget
4670 * @cr: cairo context to draw to
4671 * @location: location where to draw the cursor (@location->width is ignored)
4672 * @is_primary: if the cursor should be the primary cursor color.
4673 * @direction: whether the cursor is left-to-right or
4674 * right-to-left. Should never be #GTK_TEXT_DIR_NONE
4675 * @draw_arrow: %TRUE to draw a directional arrow on the
4676 * cursor. Should be %FALSE unless the cursor is split.
4678 * Draws a text caret on @cr at @location. This is not a style function
4679 * but merely a convenience function for drawing the standard cursor shape.
4682 * Deprecated: 3.4: Use gtk_render_insertion_cursor() instead.
4685 gtk_draw_insertion_cursor (GtkWidget *widget,
4687 const GdkRectangle *location,
4688 gboolean is_primary,
4689 GtkTextDirection direction,
4690 gboolean draw_arrow)
4692 GtkStyleContext *context;
4694 g_return_if_fail (GTK_IS_WIDGET (widget));
4695 g_return_if_fail (cr != NULL);
4696 g_return_if_fail (location != NULL);
4697 g_return_if_fail (direction != GTK_TEXT_DIR_NONE);
4699 context = gtk_widget_get_style_context (widget);
4701 draw_insertion_cursor (context, cr,
4702 location->x, location->y, location->height,
4704 (direction == GTK_TEXT_DIR_RTL) ? PANGO_DIRECTION_RTL : PANGO_DIRECTION_LTR,
4708 static AtkAttributeSet *
4709 add_attribute (AtkAttributeSet *attributes,
4710 AtkTextAttribute attr,
4715 at = g_new (AtkAttribute, 1);
4716 at->name = g_strdup (atk_text_attribute_get_name (attr));
4717 at->value = g_strdup (value);
4719 return g_slist_prepend (attributes, at);
4723 * _gtk_style_context_get_attributes:
4724 * @attributes: a #AtkAttributeSet to add attributes to
4725 * @context: the #GtkStyleContext to get attributes from
4726 * @flags: the state to use with @context
4728 * Adds the foreground and background color from @context to
4729 * @attributes, after translating them to ATK attributes.
4731 * This is a convenience function that can be used in
4732 * implementing the #AtkText interface in widgets.
4734 * Returns: the modified #AtkAttributeSet
4737 _gtk_style_context_get_attributes (AtkAttributeSet *attributes,
4738 GtkStyleContext *context,
4739 GtkStateFlags flags)
4744 gtk_style_context_get_background_color (context, flags, &color);
4745 value = g_strdup_printf ("%u,%u,%u",
4746 (guint) ceil (color.red * 65536 - color.red),
4747 (guint) ceil (color.green * 65536 - color.green),
4748 (guint) ceil (color.blue * 65536 - color.blue));
4749 attributes = add_attribute (attributes, ATK_TEXT_ATTR_BG_COLOR, value);
4752 gtk_style_context_get_color (context, flags, &color);
4753 value = g_strdup_printf ("%u,%u,%u",
4754 (guint) ceil (color.red * 65536 - color.red),
4755 (guint) ceil (color.green * 65536 - color.green),
4756 (guint) ceil (color.blue * 65536 - color.blue));
4757 attributes = add_attribute (attributes, ATK_TEXT_ATTR_FG_COLOR, value);