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, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
24 #include <gobject/gvaluecollector.h>
26 #include "gtkstylecontext.h"
27 #include "gtktypebuiltins.h"
28 #include "gtkthemingengine.h"
30 #include "gtkwidget.h"
31 #include "gtkwindow.h"
32 #include "gtkprivate.h"
33 #include "gtkanimationdescription.h"
34 #include "gtktimeline.h"
37 * SECTION:gtkstylecontext
38 * @Short_description: rendering UI elements
39 * @Title: GtkStyleContext
42 * #GtkStyleContext is an object that stores styling information affecting
43 * a widget defined by #GtkWidgetPath.
45 * In order to construct the final style information, #GtkStyleContext
46 * queries information to all attached #GtkStyleProvider<!-- -->s, either
47 * to the context specifically through gtk_style_context_add_provider(), or
48 * to the screen through gtk_style_context_add_provider_for_screen(). The
49 * resulting style is a combination of all provider's information in priority
52 * For GTK+ widgets, any #GtkStyleContext returned by
53 * gtk_widget_get_style_context() will already have a #GtkWidgetPath, a
54 * #GdkScreen and RTL/LTR information set, the style context will be also
55 * updated automatically if any of these settings change on the widget.
57 * If you using are the theming layer standalone, you will need to set a
58 * widget path and a screen yourself to the created style context through
59 * gtk_style_context_set_path() and gtk_style_context_set_screen(), as well
60 * as updating the context yourself using gtk_style_context_invalidate()
61 * whenever any of the conditions change, such as a change in the
62 * #GtkSettings:gtk-theme-name property or a hierarchy change in the rendered
65 * <refsect2 id="gtkstylecontext-animations">
66 * <title>Transition animations</title>
68 * #GtkStyleContext has built-in support for state change transitions.
71 * For simple widgets where state changes affect the whole widget area,
72 * calling gtk_style_context_notify_state_change() with a %NULL identifier
73 * would be sufficient.
76 * If a widget needs to declare several animatable regions (i.e. not
77 * affecting the whole widget area), its #GtkWidget::draw signal handler
78 * needs to wrap the render operations for the different regions around
79 * gtk_style_context_push_animatable_region() and
80 * gtk_style_context_pop_animatable_region(). These functions take an
81 * unique identifier within the style context, for simple widgets with
82 * little animatable regions, an enum may be used:
85 * <title>Using an enum as animatable region identifier</title>
96 * spin_button_draw (GtkWidget *widget,
99 * GtkStyleContext *context;
101 * context = gtk_widget_get_style_context (widget);
103 * gtk_style_context_push_animatable_region (context,
104 * GUINT_TO_POINTER (REGION_ENTRY));
106 * gtk_render_background (cr, 0, 0, 100, 30);
107 * gtk_render_frame (cr, 0, 0, 100, 30);
109 * gtk_style_context_pop_animatable_region (context);
116 * For complex widgets with an arbitrary number of animatable regions, it
117 * is up to the implementation to come up with a way to univocally identify
118 * an animatable region, pointers to internal structs would suffice.
121 * <title>Using an arbitrary pointer as animatable region identifier</title>
124 * notebook_draw_tab (GtkWidget *widget,
125 * NotebookPage *page,
128 * gtk_style_context_push_animatable_region (context, page);
129 * gtk_render_extension (cr, page->x, page->y, page->width, page->height);
130 * gtk_style_context_pop_animatable_region (context);
135 * The widget also needs to notify the style context about a state change
136 * for a given animatable region so the animation is triggered.
139 * <title>Triggering a state change animation on a region</title>
142 * notebook_motion_notify (GtkWidget *widget,
143 * GdkEventMotion *event)
145 * GtkStyleContext *context;
146 * NotebookPage *page;
148 * context = gtk_widget_get_style_context (widget);
149 * page = find_page_under_pointer (widget, event);
150 * gtk_style_context_notify_state_change (context,
151 * gtk_widget_get_window (widget),
153 * GTK_STATE_PRELIGHT,
160 * gtk_style_context_notify_state_change() accepts %NULL region IDs as a
161 * special value, in this case, the whole widget area will be updated
166 * <refsect2 id="gtkstylecontext-custom-styling">
167 * <title>Custom styling in UI libraries and applications</title>
169 * If you are developing a library with custom #GtkWidget<!-- -->s that
170 * render differently than standard components, you may need to add a
171 * #GtkStyleProvider yourself with the %GTK_STYLE_PROVIDER_PRIORITY_FALLBACK
172 * priority, either a #GtkCssProvider or a custom object implementing the
173 * #GtkStyleProvider interface. This way theming engines may still attempt
174 * to style your UI elements in a different way if needed so.
177 * If you are using custom styling on an applications, you probably want then
178 * to make your style information prevail to the theme's, so you must use
179 * a #GtkStyleProvider with the %GTK_STYLE_PROVIDER_PRIORITY_APPLICATION
180 * priority, keep in mind that the user settings in $HOME/.gtk-3.0.css will
181 * still take precedence over your changes, as it uses the
182 * %GTK_STYLE_PROVIDER_PRIORITY_USER priority.
185 * If a custom theming engine is needed, you probably want to implement a
186 * #GtkStyleProvider yourself so it points to your #GtkThemingEngine
187 * implementation, as #GtkCssProvider uses gtk_theming_engine_load()
188 * which loads the theming engine module from the standard paths.
193 typedef struct GtkStyleContextPrivate GtkStyleContextPrivate;
194 typedef struct GtkStyleProviderData GtkStyleProviderData;
195 typedef struct GtkStyleInfo GtkStyleInfo;
196 typedef struct GtkRegion GtkRegion;
197 typedef struct PropertyValue PropertyValue;
198 typedef struct AnimationInfo AnimationInfo;
199 typedef struct StyleData StyleData;
204 GtkRegionFlags flags;
207 struct GtkStyleProviderData
209 GtkStyleProvider *provider;
222 GArray *style_classes;
224 GtkJunctionSides junction_sides;
230 GSList *icon_factories;
231 GArray *property_cache;
236 GtkTimeline *timeline;
241 gboolean target_value;
243 cairo_region_t *invalidation_region;
247 struct GtkStyleContextPrivate
252 GList *providers_last;
254 GtkWidgetPath *widget_path;
255 GHashTable *style_data;
257 StyleData *current_data;
259 GtkStateFlags state_flags;
261 GSList *animation_regions;
264 guint animations_invalidated : 1;
265 guint invalidating_context : 1;
267 GtkThemingEngine *theming_engine;
269 GtkTextDirection direction;
283 guint signals[LAST_SIGNAL] = { 0 };
285 static GQuark provider_list_quark = 0;
287 static void gtk_style_context_finalize (GObject *object);
289 static void gtk_style_context_impl_set_property (GObject *object,
293 static void gtk_style_context_impl_get_property (GObject *object,
299 G_DEFINE_TYPE (GtkStyleContext, gtk_style_context, G_TYPE_OBJECT)
302 gtk_style_context_class_init (GtkStyleContextClass *klass)
304 GObjectClass *object_class = G_OBJECT_CLASS (klass);
306 object_class->finalize = gtk_style_context_finalize;
307 object_class->set_property = gtk_style_context_impl_set_property;
308 object_class->get_property = gtk_style_context_impl_get_property;
311 g_signal_new (I_("changed"),
312 G_TYPE_FROM_CLASS (object_class),
314 G_STRUCT_OFFSET (GtkStyleContextClass, changed),
316 g_cclosure_marshal_VOID__VOID,
319 g_object_class_install_property (object_class,
321 g_param_spec_object ("screen",
323 P_("The associated GdkScreen"),
325 GTK_PARAM_READWRITE));
326 g_object_class_install_property (object_class,
328 g_param_spec_enum ("direction",
330 P_("Text direction"),
331 GTK_TYPE_TEXT_DIRECTION,
333 GTK_PARAM_READWRITE));
335 g_type_class_add_private (object_class, sizeof (GtkStyleContextPrivate));
338 static GtkStyleInfo *
339 style_info_new (void)
343 info = g_slice_new0 (GtkStyleInfo);
344 info->style_classes = g_array_new (FALSE, FALSE, sizeof (GQuark));
345 info->regions = g_array_new (FALSE, FALSE, sizeof (GtkRegion));
351 style_info_free (GtkStyleInfo *info)
353 g_array_free (info->style_classes, TRUE);
354 g_array_free (info->regions, TRUE);
355 g_slice_free (GtkStyleInfo, info);
358 static GtkStyleInfo *
359 style_info_copy (const GtkStyleInfo *info)
363 copy = style_info_new ();
364 g_array_insert_vals (copy->style_classes, 0,
365 info->style_classes->data,
366 info->style_classes->len);
368 g_array_insert_vals (copy->regions, 0,
372 copy->junction_sides = info->junction_sides;
378 style_info_hash (gconstpointer elem)
380 const GtkStyleInfo *info;
385 for (i = 0; i < info->style_classes->len; i++)
387 hash += g_array_index (info->style_classes, GQuark, i);
391 for (i = 0; i < info->regions->len; i++)
395 region = &g_array_index (info->regions, GtkRegion, i);
396 hash += region->class_quark;
397 hash += region->flags;
405 style_info_equal (gconstpointer elem1,
408 const GtkStyleInfo *info1, *info2;
413 if (info1->junction_sides != info2->junction_sides)
416 if (info1->style_classes->len != info2->style_classes->len)
419 if (memcmp (info1->style_classes->data,
420 info2->style_classes->data,
421 info1->style_classes->len * sizeof (GQuark)) != 0)
424 if (info1->regions->len != info2->regions->len)
427 if (memcmp (info1->regions->data,
428 info2->regions->data,
429 info1->regions->len * sizeof (GtkRegion)) != 0)
436 style_data_new (void)
440 data = g_slice_new0 (StyleData);
441 data->store = gtk_style_set_new ();
447 clear_property_cache (StyleData *data)
451 if (!data->property_cache)
454 for (i = 0; i < data->property_cache->len; i++)
456 PropertyValue *node = &g_array_index (data->property_cache, PropertyValue, i);
458 g_param_spec_unref (node->pspec);
459 g_value_unset (&node->value);
462 g_array_free (data->property_cache, TRUE);
463 data->property_cache = NULL;
467 style_data_free (StyleData *data)
469 g_object_unref (data->store);
470 clear_property_cache (data);
472 g_slist_foreach (data->icon_factories, (GFunc) g_object_unref, NULL);
473 g_slist_free (data->icon_factories);
475 g_slice_free (StyleData, data);
479 gtk_style_context_init (GtkStyleContext *style_context)
481 GtkStyleContextPrivate *priv;
484 priv = style_context->priv = G_TYPE_INSTANCE_GET_PRIVATE (style_context,
485 GTK_TYPE_STYLE_CONTEXT,
486 GtkStyleContextPrivate);
488 priv->style_data = g_hash_table_new_full (style_info_hash,
490 (GDestroyNotify) style_info_free,
491 (GDestroyNotify) style_data_free);
492 priv->theming_engine = g_object_ref ((gpointer) gtk_theming_engine_load (NULL));
494 priv->direction = GTK_TEXT_DIR_RTL;
496 /* Create default info store */
497 info = style_info_new ();
498 priv->info_stack = g_slist_prepend (priv->info_stack, info);
501 static GtkStyleProviderData *
502 style_provider_data_new (GtkStyleProvider *provider,
505 GtkStyleProviderData *data;
507 data = g_slice_new (GtkStyleProviderData);
508 data->provider = g_object_ref (provider);
509 data->priority = priority;
515 style_provider_data_free (GtkStyleProviderData *data)
517 g_object_unref (data->provider);
518 g_slice_free (GtkStyleProviderData, data);
522 animation_info_free (AnimationInfo *info)
524 g_object_unref (info->timeline);
525 g_object_unref (info->window);
527 if (info->invalidation_region)
528 cairo_region_destroy (info->invalidation_region);
530 g_array_free (info->rectangles, TRUE);
531 g_slice_free (AnimationInfo, info);
535 timeline_frame_cb (GtkTimeline *timeline,
543 if (info->invalidation_region &&
544 !cairo_region_is_empty (info->invalidation_region))
545 gdk_window_invalidate_region (info->window, info->invalidation_region, TRUE);
547 gdk_window_invalidate_rect (info->window, NULL, TRUE);
551 timeline_finished_cb (GtkTimeline *timeline,
554 GtkStyleContextPrivate *priv;
555 GtkStyleContext *context;
560 priv = context->priv;
562 for (l = priv->animations; l; l = l->next)
566 if (info->timeline == timeline)
568 priv->animations = g_slist_delete_link (priv->animations, l);
570 /* Invalidate one last time the area, so the final content is painted */
571 if (info->invalidation_region &&
572 !cairo_region_is_empty (info->invalidation_region))
573 gdk_window_invalidate_region (info->window, info->invalidation_region, TRUE);
575 gdk_window_invalidate_rect (info->window, NULL, TRUE);
577 animation_info_free (info);
583 static AnimationInfo *
584 animation_info_new (GtkStyleContext *context,
587 GtkTimelineProgressType progress_type,
589 gboolean target_value,
594 info = g_slice_new0 (AnimationInfo);
596 info->rectangles = g_array_new (FALSE, FALSE, sizeof (cairo_rectangle_int_t));
597 info->timeline = gtk_timeline_new (duration);
598 info->window = g_object_ref (window);
600 info->target_value = target_value;
601 info->region_id = region_id;
603 gtk_timeline_set_progress_type (info->timeline, progress_type);
607 gtk_timeline_set_direction (info->timeline, GTK_TIMELINE_DIRECTION_BACKWARD);
608 gtk_timeline_rewind (info->timeline);
611 g_signal_connect (info->timeline, "frame",
612 G_CALLBACK (timeline_frame_cb), info);
613 g_signal_connect (info->timeline, "finished",
614 G_CALLBACK (timeline_finished_cb), context);
616 gtk_timeline_start (info->timeline);
621 static AnimationInfo *
622 animation_info_lookup (GtkStyleContext *context,
626 GtkStyleContextPrivate *priv;
629 priv = context->priv;
631 for (l = priv->animations; l; l = l->next)
637 if (info->state == state &&
638 info->region_id == region_id)
646 gtk_style_context_finalize (GObject *object)
648 GtkStyleContextPrivate *priv;
649 GtkStyleContext *style_context;
652 style_context = GTK_STYLE_CONTEXT (object);
653 priv = style_context->priv;
655 if (priv->widget_path)
656 gtk_widget_path_free (priv->widget_path);
658 g_hash_table_destroy (priv->style_data);
660 g_list_foreach (priv->providers, (GFunc) style_provider_data_free, NULL);
661 g_list_free (priv->providers);
663 g_slist_foreach (priv->info_stack, (GFunc) style_info_free, NULL);
664 g_slist_free (priv->info_stack);
666 g_slist_free (priv->animation_regions);
668 for (l = priv->animations; l; l = l->next)
669 animation_info_free ((AnimationInfo *) l->data);
671 g_slist_free (priv->animations);
673 if (priv->theming_engine)
674 g_object_unref (priv->theming_engine);
676 G_OBJECT_CLASS (gtk_style_context_parent_class)->finalize (object);
680 gtk_style_context_impl_set_property (GObject *object,
685 GtkStyleContextPrivate *priv;
686 GtkStyleContext *style_context;
688 style_context = GTK_STYLE_CONTEXT (object);
689 priv = style_context->priv;
694 gtk_style_context_set_screen (style_context,
695 g_value_get_object (value));
698 gtk_style_context_set_direction (style_context,
699 g_value_get_enum (value));
702 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
708 gtk_style_context_impl_get_property (GObject *object,
713 GtkStyleContextPrivate *priv;
714 GtkStyleContext *style_context;
716 style_context = GTK_STYLE_CONTEXT (object);
717 priv = style_context->priv;
722 g_value_set_object (value, priv->screen);
725 g_value_set_enum (value, priv->direction);
728 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
734 find_next_candidate (GList *local,
739 GtkStyleProviderData *local_data, *global_data;
741 local_data = local->data;
742 global_data = global->data;
744 if (local_data->priority >= global_data->priority)
758 build_properties (GtkStyleContext *context,
759 StyleData *style_data,
762 GtkStyleContextPrivate *priv;
763 GList *elem, *list, *global_list = NULL;
765 priv = context->priv;
766 list = priv->providers;
769 global_list = g_object_get_qdata (G_OBJECT (priv->screen), provider_list_quark);
771 while ((elem = find_next_candidate (list, global_list)) != NULL)
773 GtkStyleProviderData *data;
774 GtkStyleSet *provider_style;
781 global_list = global_list->next;
783 provider_style = gtk_style_provider_get_style (data->provider, path);
787 gtk_style_set_merge (style_data->store, provider_style, TRUE);
788 g_object_unref (provider_style);
794 build_icon_factories (GtkStyleContext *context,
795 StyleData *style_data,
798 GtkStyleContextPrivate *priv;
799 GList *elem, *list, *global_list = NULL;
801 priv = context->priv;
802 list = priv->providers_last;
806 global_list = g_object_get_qdata (G_OBJECT (priv->screen), provider_list_quark);
807 global_list = g_list_last (global_list);
810 while ((elem = find_next_candidate (list, global_list)) != NULL)
812 GtkIconFactory *factory;
813 GtkStyleProviderData *data;
820 global_list = global_list->prev;
822 factory = gtk_style_provider_get_icon_factory (data->provider, path);
825 style_data->icon_factories = g_slist_prepend (style_data->icon_factories, factory);
830 create_query_path (GtkStyleContext *context)
832 GtkStyleContextPrivate *priv;
837 priv = context->priv;
838 path = gtk_widget_path_copy (priv->widget_path);
839 pos = gtk_widget_path_length (path) - 1;
841 info = priv->info_stack->data;
843 /* Set widget regions */
844 for (i = 0; i < info->regions->len; i++)
848 region = &g_array_index (info->regions, GtkRegion, i);
849 gtk_widget_path_iter_add_region (path, pos,
850 g_quark_to_string (region->class_quark),
854 /* Set widget classes */
855 for (i = 0; i < info->style_classes->len; i++)
859 quark = g_array_index (info->style_classes, GQuark, i);
860 gtk_widget_path_iter_add_class (path, pos,
861 g_quark_to_string (quark));
868 style_data_lookup (GtkStyleContext *context)
870 GtkStyleContextPrivate *priv;
873 priv = context->priv;
875 /* Current data in use is cached, just return it */
876 if (priv->current_data)
877 return priv->current_data;
879 g_assert (priv->widget_path != NULL);
881 data = g_hash_table_lookup (priv->style_data, priv->info_stack->data);
887 data = style_data_new ();
888 path = create_query_path (context);
890 build_properties (context, data, path);
891 build_icon_factories (context, data, path);
893 g_hash_table_insert (priv->style_data,
894 style_info_copy (priv->info_stack->data),
897 gtk_widget_path_free (path);
900 priv->current_data = data;
902 if (priv->theming_engine)
903 g_object_unref (priv->theming_engine);
905 gtk_style_set_get (data->store, 0,
906 "engine", &priv->theming_engine,
912 style_provider_add (GList **list,
913 GtkStyleProvider *provider,
916 GtkStyleProviderData *new_data;
917 gboolean added = FALSE;
920 new_data = style_provider_data_new (provider, priority);
924 GtkStyleProviderData *data;
928 /* Provider was already attached to the style
929 * context, remove in order to add the new data
931 if (data->provider == provider)
938 /* Remove and free link */
939 *list = g_list_remove_link (*list, link);
940 style_provider_data_free (link->data);
941 g_list_free_1 (link);
947 data->priority > priority)
949 *list = g_list_insert_before (*list, l, new_data);
957 *list = g_list_append (*list, new_data);
961 style_provider_remove (GList **list,
962 GtkStyleProvider *provider)
968 GtkStyleProviderData *data;
972 if (data->provider == provider)
974 *list = g_list_remove_link (*list, l);
975 style_provider_data_free (l->data);
988 * gtk_style_context_add_provider:
989 * @context: a #GtkStyleContext
990 * @provider: a #GtkStyleProvider
991 * @priority: the priority of the style provider. The lower
992 * it is, the earlier it will be used in the style
993 * construction. Typically this will be in the range
994 * between %GTK_STYLE_PROVIDER_PRIORITY_FALLBACK and
995 * %GTK_STYLE_PROVIDER_PRIORITY_USER
997 * Adds a style provider to @context, to be used in style construction.
1002 gtk_style_context_add_provider (GtkStyleContext *context,
1003 GtkStyleProvider *provider,
1006 GtkStyleContextPrivate *priv;
1008 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
1009 g_return_if_fail (GTK_IS_STYLE_PROVIDER (provider));
1011 priv = context->priv;
1012 style_provider_add (&priv->providers, provider, priority);
1013 priv->providers_last = g_list_last (priv->providers);
1015 gtk_style_context_invalidate (context);
1019 * gtk_style_context_remove_provider:
1020 * @context: a #GtkStyleContext
1021 * @provider: a #GtkStyleProvider
1023 * Removes @provider from the style providers list in @context.
1028 gtk_style_context_remove_provider (GtkStyleContext *context,
1029 GtkStyleProvider *provider)
1031 GtkStyleContextPrivate *priv;
1033 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
1034 g_return_if_fail (GTK_IS_STYLE_PROVIDER (provider));
1036 priv = context->priv;
1038 if (style_provider_remove (&priv->providers, provider))
1040 priv->providers_last = g_list_last (priv->providers);
1042 gtk_style_context_invalidate (context);
1047 * gtk_style_context_reset_widgets:
1048 * @screen: a #GdkScreen
1050 * This function recomputes the styles for all widgets under a particular
1051 * #GdkScreen. This is useful when some global parameter has changed that
1052 * affects the appearance of all widgets, because when a widget gets a new
1053 * style, it will both redraw and recompute any cached information about
1054 * its appearance. As an example, it is used when the color scheme changes
1055 * in the related #GtkSettings object.
1060 gtk_style_context_reset_widgets (GdkScreen *screen)
1062 GList *list, *toplevels;
1064 toplevels = gtk_window_list_toplevels ();
1065 g_list_foreach (toplevels, (GFunc) g_object_ref, NULL);
1067 for (list = toplevels; list; list = list->next)
1069 if (gtk_widget_get_screen (list->data) == screen)
1070 gtk_widget_reset_style (list->data);
1072 g_object_unref (list->data);
1075 g_list_free (toplevels);
1079 * gtk_style_context_add_provider_for_screen:
1080 * @screen: a #GdkScreen
1081 * @provider: a #GtkStyleProvider
1082 * @priority: the priority of the style provider. The lower
1083 * it is, the earlier it will be used in the style
1084 * construction. Typically this will be in the range
1085 * between %GTK_STYLE_PROVIDER_PRIORITY_FALLBACK and
1086 * %GTK_STYLE_PROVIDER_PRIORITY_USER
1088 * Adds a global style provider to @screen, which will be used
1089 * in style construction for all #GtkStyleContext<!-- -->s under
1095 gtk_style_context_add_provider_for_screen (GdkScreen *screen,
1096 GtkStyleProvider *provider,
1099 GList *providers, *list;
1101 g_return_if_fail (GDK_IS_SCREEN (screen));
1102 g_return_if_fail (GTK_IS_STYLE_PROVIDER (provider));
1104 if (G_UNLIKELY (!provider_list_quark))
1105 provider_list_quark = g_quark_from_static_string ("gtk-provider-list-quark");
1107 list = providers = g_object_get_qdata (G_OBJECT (screen), provider_list_quark);
1108 style_provider_add (&list, provider, priority);
1110 if (list != providers)
1111 g_object_set_qdata (G_OBJECT (screen), provider_list_quark, list);
1113 gtk_style_context_reset_widgets (screen);
1117 * gtk_style_context_remove_provider_for_screen:
1118 * @screen: a #GdkScreen
1119 * @provider: a #GtkStyleProvider
1121 * Removes @provider from the global style providers list in @screen.
1126 gtk_style_context_remove_provider_for_screen (GdkScreen *screen,
1127 GtkStyleProvider *provider)
1129 GList *providers, *list;
1131 g_return_if_fail (GDK_IS_SCREEN (screen));
1132 g_return_if_fail (GTK_IS_STYLE_PROVIDER (provider));
1134 if (G_UNLIKELY (!provider_list_quark))
1137 list = providers = g_object_get_qdata (G_OBJECT (screen), provider_list_quark);
1139 if (style_provider_remove (&list, provider))
1141 if (list != providers)
1142 g_object_set_qdata (G_OBJECT (screen), provider_list_quark, list);
1144 gtk_style_context_reset_widgets (screen);
1149 * gtk_style_context_get_property:
1150 * @context: a #GtkStyleContext
1151 * @property: style property name
1152 * @state: state to retrieve the property value for
1153 * @value: (out) (transfer full): return location for the style property value.
1155 * Gets a style property from @context for the given state. When done with @value,
1156 * g_value_unset() needs to be called to free any allocated memory.
1161 gtk_style_context_get_property (GtkStyleContext *context,
1162 const gchar *property,
1163 GtkStateFlags state,
1166 GtkStyleContextPrivate *priv;
1169 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
1170 g_return_if_fail (property != NULL);
1171 g_return_if_fail (value != NULL);
1173 priv = context->priv;
1175 g_return_if_fail (priv->widget_path != NULL);
1177 data = style_data_lookup (context);
1178 gtk_style_set_get_property (data->store, property, state, value);
1182 * gtk_style_context_get_valist:
1183 * @context: a #GtkStyleContext
1184 * @state: state to retrieve the property values for
1185 * @args: va_list of property name/return location pairs, followed by %NULL
1187 * Retrieves several style property values from @context for a given state.
1192 gtk_style_context_get_valist (GtkStyleContext *context,
1193 GtkStateFlags state,
1196 GtkStyleContextPrivate *priv;
1199 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
1201 priv = context->priv;
1202 g_return_if_fail (priv->widget_path != NULL);
1204 data = style_data_lookup (context);
1205 gtk_style_set_get_valist (data->store, state, args);
1209 * gtk_style_context_get:
1210 * @context: a #GtkStyleContext
1211 * @state: state to retrieve the property values for
1212 * @...: property name /return value pairs, followed by %NULL
1214 * Retrieves several style property values from @context for a
1220 gtk_style_context_get (GtkStyleContext *context,
1221 GtkStateFlags state,
1224 GtkStyleContextPrivate *priv;
1228 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
1230 priv = context->priv;
1231 g_return_if_fail (priv->widget_path != NULL);
1233 data = style_data_lookup (context);
1235 va_start (args, state);
1236 gtk_style_set_get_valist (data->store, state, args);
1241 * gtk_style_context_set_state:
1242 * @context: a #GtkStyleContext
1243 * @flags: state to represent
1245 * Sets the style to be used when rendering with any
1246 * of the "gtk_render_" prefixed functions.
1251 gtk_style_context_set_state (GtkStyleContext *context,
1252 GtkStateFlags flags)
1254 GtkStyleContextPrivate *priv;
1256 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
1258 priv = context->priv;
1259 priv->state_flags = flags;
1263 * gtk_style_context_get_state:
1264 * @context: a #GtkStyleContext
1266 * returns the state used when rendering.
1268 * Returns: the state flags
1273 gtk_style_context_get_state (GtkStyleContext *context)
1275 GtkStyleContextPrivate *priv;
1277 g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), 0);
1279 priv = context->priv;
1280 return priv->state_flags;
1284 context_has_animatable_region (GtkStyleContext *context,
1287 GtkStyleContextPrivate *priv;
1290 /* NULL region_id means everything
1291 * rendered through the style context
1296 priv = context->priv;
1298 for (r = priv->animation_regions; r; r = r->next)
1300 if (r->data == region_id)
1308 * gtk_style_context_state_is_running:
1309 * @context: a #GtkStyleContext
1310 * @state: a widget state
1311 * @progress: (out): return location for the transition progress
1313 * Returns %TRUE if there is a transition animation running for the
1314 * current region (see gtk_style_context_push_animatable_region()).
1316 * If @progress is not %NULL, the animation progress will be returned
1317 * there, 0.0 means the state is closest to being %FALSE, while 1.0 means
1318 * it's closest to being %TRUE. This means transition animations will
1319 * run from 0 to 1 when @state is being set to %TRUE and from 1 to 0 when
1320 * it's being set to %FALSE.
1322 * Returns: %TRUE if there is a running transition animation for @state.
1327 gtk_style_context_state_is_running (GtkStyleContext *context,
1331 GtkStyleContextPrivate *priv;
1332 AnimationInfo *info;
1335 g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), FALSE);
1337 priv = context->priv;
1339 for (l = priv->animations; l; l = l->next)
1343 if (info->state == state &&
1344 context_has_animatable_region (context, info->region_id))
1347 *progress = gtk_timeline_get_progress (info->timeline);
1357 * gtk_style_context_set_path:
1358 * @context: a #GtkStyleContext
1359 * @path: a #GtkWidgetPath
1361 * Sets the #GtkWidgetPath used for style matching. As a
1362 * consequence, the style will be regenerated to match
1363 * the new given path. If you are using a #GtkStyleContext
1364 * returned from gtk_widget_get_style_context(), you do
1365 * not need to call this yourself.
1370 gtk_style_context_set_path (GtkStyleContext *context,
1371 GtkWidgetPath *path)
1373 GtkStyleContextPrivate *priv;
1375 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
1376 g_return_if_fail (path != NULL);
1378 priv = context->priv;
1380 if (priv->widget_path)
1382 gtk_widget_path_free (priv->widget_path);
1383 priv->widget_path = NULL;
1387 priv->widget_path = gtk_widget_path_copy (path);
1389 gtk_style_context_invalidate (context);
1393 * gtk_style_context_get_path:
1394 * @context: a #GtkStyleContext
1396 * Returns the widget path used for style matching.
1398 * Returns: (transfer none): A #GtkWidgetPath
1402 G_CONST_RETURN GtkWidgetPath *
1403 gtk_style_context_get_path (GtkStyleContext *context)
1405 GtkStyleContextPrivate *priv;
1407 priv = context->priv;
1408 return priv->widget_path;
1412 * gtk_style_context_save:
1413 * @context: a #GtkStyleContext
1415 * Saves the @context state, so all modifications done through
1416 * gtk_style_context_set_class(), gtk_style_context_unset_class(),
1417 * gtk_style_context_set_region(), gtk_style_context_unset_region()
1418 * or gtk_style_context_set_junction_sides() can be reverted in one
1419 * go through gtk_style_context_restore().
1424 gtk_style_context_save (GtkStyleContext *context)
1426 GtkStyleContextPrivate *priv;
1429 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
1431 priv = context->priv;
1433 g_assert (priv->info_stack != NULL);
1435 info = style_info_copy (priv->info_stack->data);
1436 priv->info_stack = g_slist_prepend (priv->info_stack, info);
1440 * gtk_style_context_restore:
1441 * @context: a #GtkStyleContext
1443 * Restores @context state to a previous stage. See
1444 * gtk_style_context_save().
1449 gtk_style_context_restore (GtkStyleContext *context)
1451 GtkStyleContextPrivate *priv;
1454 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
1456 priv = context->priv;
1458 if (priv->info_stack)
1460 info = priv->info_stack->data;
1461 priv->info_stack = g_slist_remove (priv->info_stack, info);
1462 style_info_free (info);
1465 if (!priv->info_stack)
1467 g_warning ("Unpaired gtk_style_context_restore() call");
1469 /* Create default region */
1470 info = style_info_new ();
1471 priv->info_stack = g_slist_prepend (priv->info_stack, info);
1474 priv->current_data = NULL;
1478 style_class_find (GArray *array,
1483 gboolean found = FALSE;
1489 if (!array || array->len == 0)
1493 max = array->len - 1;
1499 mid = (min + max) / 2;
1500 item = g_array_index (array, GQuark, mid);
1502 if (class_quark == item)
1507 else if (class_quark > item)
1508 min = pos = mid + 1;
1515 while (!found && min <= max);
1524 region_find (GArray *array,
1529 gboolean found = FALSE;
1535 if (!array || array->len == 0)
1539 max = array->len - 1;
1545 mid = (min + max) / 2;
1546 region = &g_array_index (array, GtkRegion, mid);
1548 if (region->class_quark == class_quark)
1553 else if (region->class_quark > class_quark)
1554 min = pos = mid + 1;
1561 while (!found && min <= max);
1570 * gtk_style_context_set_class:
1571 * @context: a #GtkStyleContext
1572 * @class_name: class name to use in styling
1574 * Sets a class name to @context, so posterior calls to
1575 * gtk_style_context_get() or any of the gtk_render_*
1576 * functions will make use of this new class for styling.
1578 * In the CSS file format, a #GtkEntry defining an "entry"
1579 * class, would be matched by:
1582 * GtkEntry.entry { ... }
1585 * While any widget defining an "entry" class would be
1594 gtk_style_context_set_class (GtkStyleContext *context,
1595 const gchar *class_name)
1597 GtkStyleContextPrivate *priv;
1602 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
1603 g_return_if_fail (class_name != NULL);
1605 priv = context->priv;
1606 class_quark = g_quark_from_string (class_name);
1608 g_assert (priv->info_stack != NULL);
1609 info = priv->info_stack->data;
1611 if (!style_class_find (info->style_classes, class_quark, &position))
1613 g_array_insert_val (info->style_classes, position, class_quark);
1615 /* Unset current data, as it likely changed due to the class change */
1616 priv->current_data = NULL;
1621 * gtk_style_context_unset_class:
1622 * @context: a #GtkStyleContext
1623 * @class_name: class name to remove
1625 * Removes @class_name from @context.
1630 gtk_style_context_unset_class (GtkStyleContext *context,
1631 const gchar *class_name)
1633 GtkStyleContextPrivate *priv;
1638 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
1639 g_return_if_fail (class_name != NULL);
1641 class_quark = g_quark_try_string (class_name);
1646 priv = context->priv;
1648 g_assert (priv->info_stack != NULL);
1649 info = priv->info_stack->data;
1651 if (style_class_find (info->style_classes, class_quark, &position))
1653 g_array_remove_index (info->style_classes, position);
1655 /* Unset current data, as it likely changed due to the class change */
1656 priv->current_data = NULL;
1661 * gtk_style_context_has_class:
1662 * @context: a #GtkStyleContext
1663 * @class_name: a class name
1665 * Returns %TRUE if @context currently has defined the
1668 * Returns: %TRUE if @context has @class_name defined
1673 gtk_style_context_has_class (GtkStyleContext *context,
1674 const gchar *class_name)
1676 GtkStyleContextPrivate *priv;
1680 g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), FALSE);
1681 g_return_val_if_fail (class_name != NULL, FALSE);
1683 class_quark = g_quark_try_string (class_name);
1688 priv = context->priv;
1690 g_assert (priv->info_stack != NULL);
1691 info = priv->info_stack->data;
1693 if (style_class_find (info->style_classes, class_quark, NULL))
1700 * gtk_style_context_list_classes:
1701 * @context: a #GtkStyleContext
1703 * Returns the list of classes currently defined in @context.
1705 * Returns: (transfer container) (element-type utf8): a #GList of
1706 * strings with the currently defined classes. The contents
1707 * of the list are owned by GTK+, but you must free the list
1708 * itself with g_list_free() when you are done with it.
1713 gtk_style_context_list_classes (GtkStyleContext *context)
1715 GtkStyleContextPrivate *priv;
1717 GList *classes = NULL;
1720 g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), NULL);
1722 priv = context->priv;
1724 g_assert (priv->info_stack != NULL);
1725 info = priv->info_stack->data;
1727 for (i = 0; i < info->style_classes->len; i++)
1731 quark = g_array_index (info->style_classes, GQuark, i);
1732 classes = g_list_prepend (classes, (gchar *) g_quark_to_string (quark));
1739 * gtk_style_context_list_regions:
1740 * @context: a #GtkStyleContext
1743 * Returns the list of regions currently defined in @context.
1745 * Returns: (transfer container) (element-type utf8): a #GList of
1746 * strings with the currently defined regions. The contents
1747 * of the list are owned by GTK+, but you must free the list
1748 * itself with g_list_free() when you are done with it.
1753 gtk_style_context_list_regions (GtkStyleContext *context)
1755 GtkStyleContextPrivate *priv;
1757 GList *classes = NULL;
1760 g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), NULL);
1762 priv = context->priv;
1764 g_assert (priv->info_stack != NULL);
1765 info = priv->info_stack->data;
1767 for (i = 0; i < info->regions->len; i++)
1770 const gchar *class_name;
1772 region = &g_array_index (info->regions, GtkRegion, i);
1774 class_name = g_quark_to_string (region->class_quark);
1775 classes = g_list_prepend (classes, (gchar *) class_name);
1782 * gtk_style_context_set_region:
1783 * @context: a #GtkStyleContext
1784 * @region_name: region name to use in styling
1785 * @flags: flags that apply to the region
1787 * Sets a region to @context, so posterior calls to
1788 * gtk_style_context_get() or any of the gtk_render_*
1789 * functions will make use of this new region for styling.
1791 * In the CSS file format, a #GtkTreeView defining a "row"
1792 * region, would be matched by:
1795 * GtkTreeView row { ... }
1798 * pseudo-classes are used for matching @flags, so the two
1801 * GtkTreeView row:nth-child (even) { ... }
1802 * GtkTreeView row:nth-child (odd) { ... }
1805 * would apply to even and odd rows, respectively.
1810 gtk_style_context_set_region (GtkStyleContext *context,
1811 const gchar *region_name,
1812 GtkRegionFlags flags)
1814 GtkStyleContextPrivate *priv;
1816 GQuark region_quark;
1819 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
1820 g_return_if_fail (region_name != NULL);
1822 priv = context->priv;
1823 region_quark = g_quark_from_string (region_name);
1825 g_assert (priv->info_stack != NULL);
1826 info = priv->info_stack->data;
1828 if (!region_find (info->regions, region_quark, &position))
1832 region.class_quark = region_quark;
1833 region.flags = flags;
1835 g_array_insert_val (info->regions, position, region);
1837 /* Unset current data, as it likely changed due to the region change */
1838 priv->current_data = NULL;
1843 * gtk_style_context_unset_region:
1844 * @context: a #GtkStyleContext
1845 * @region_name: region name to unset
1847 * Removes a region from @context
1852 gtk_style_context_unset_region (GtkStyleContext *context,
1853 const gchar *region_name)
1855 GtkStyleContextPrivate *priv;
1857 GQuark region_quark;
1860 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
1861 g_return_if_fail (region_name != NULL);
1863 region_quark = g_quark_try_string (region_name);
1868 priv = context->priv;
1870 g_assert (priv->info_stack != NULL);
1871 info = priv->info_stack->data;
1873 if (region_find (info->regions, region_quark, &position))
1875 g_array_remove_index (info->regions, position);
1877 /* Unset current data, as it likely changed due to the region change */
1878 priv->current_data = NULL;
1883 * gtk_style_context_has_region:
1884 * @context: a #GtkStyleContext
1885 * @region_name: a region name
1886 * @flags_return: (out) (allow-none): return location for region flags
1888 * Returns %TRUE if @context has the region defined. If @flags_return is
1889 * not %NULL, it is set to the flags affecting the region.
1891 * Returns: %TRUE if region is defined
1896 gtk_style_context_has_region (GtkStyleContext *context,
1897 const gchar *region_name,
1898 GtkRegionFlags *flags_return)
1900 GtkStyleContextPrivate *priv;
1902 GQuark region_quark;
1905 g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), FALSE);
1906 g_return_val_if_fail (region_name != NULL, FALSE);
1911 region_quark = g_quark_try_string (region_name);
1916 priv = context->priv;
1918 g_assert (priv->info_stack != NULL);
1919 info = priv->info_stack->data;
1921 if (region_find (info->regions, region_quark, &position))
1927 region = &g_array_index (info->regions, GtkRegion, position);
1928 *flags_return = region->flags;
1937 style_property_values_cmp (gconstpointer bsearch_node1,
1938 gconstpointer bsearch_node2)
1940 const PropertyValue *val1 = bsearch_node1;
1941 const PropertyValue *val2 = bsearch_node2;
1943 if (val1->widget_type == val2->widget_type)
1944 return val1->pspec < val2->pspec ? -1 : val1->pspec == val2->pspec ? 0 : 1;
1946 return val1->widget_type < val2->widget_type ? -1 : 1;
1950 _gtk_style_context_peek_style_property (GtkStyleContext *context,
1954 GtkStyleContextPrivate *priv;
1955 PropertyValue *pcache, key = { 0 };
1960 priv = context->priv;
1961 data = style_data_lookup (context);
1963 key.widget_type = widget_type;
1966 /* need value cache array */
1967 if (!data->property_cache)
1968 data->property_cache = g_array_new (FALSE, FALSE, sizeof (PropertyValue));
1971 pcache = bsearch (&key,
1972 data->property_cache->data, data->property_cache->len,
1973 sizeof (PropertyValue), style_property_values_cmp);
1975 return &pcache->value;
1979 while (i < data->property_cache->len &&
1980 style_property_values_cmp (&key, &g_array_index (data->property_cache, PropertyValue, i)) >= 0)
1983 g_array_insert_val (data->property_cache, i, key);
1984 pcache = &g_array_index (data->property_cache, PropertyValue, i);
1986 /* cache miss, initialize value type, then set contents */
1987 g_param_spec_ref (pcache->pspec);
1988 g_value_init (&pcache->value, G_PARAM_SPEC_VALUE_TYPE (pspec));
1990 if (priv->widget_path)
1992 for (list = priv->providers_last; list; list = list->prev)
1994 GtkStyleProviderData *data;
1998 if (gtk_style_provider_get_style_property (data->provider, priv->widget_path,
1999 pspec->name, &pcache->value))
2000 return &pcache->value;
2004 /* not supplied by any provider, revert to default */
2005 g_param_value_set_default (pspec, &pcache->value);
2007 return &pcache->value;
2011 * gtk_style_context_get_style_property:
2012 * @context: a #GtkStyleContext
2013 * @property_name: the name of the widget style property
2014 * @value: (out) (transfer full): Return location for the property value, free with
2015 * g_value_unset() after use.
2017 * Gets the value for a widget style property.
2020 gtk_style_context_get_style_property (GtkStyleContext *context,
2021 const gchar *property_name,
2024 GtkStyleContextPrivate *priv;
2025 GtkWidgetClass *widget_class;
2027 const GValue *peek_value;
2030 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2031 g_return_if_fail (property_name != NULL);
2032 g_return_if_fail (value != NULL);
2034 priv = context->priv;
2036 if (!priv->widget_path)
2039 widget_type = gtk_widget_path_get_widget_type (priv->widget_path);
2041 widget_class = g_type_class_ref (widget_type);
2042 pspec = gtk_widget_class_find_style_property (widget_class, property_name);
2043 g_type_class_unref (widget_class);
2047 g_warning ("%s: widget class `%s' has no style property named `%s'",
2049 g_type_name (widget_type),
2054 peek_value = _gtk_style_context_peek_style_property (context,
2058 if (G_VALUE_TYPE (value) == G_VALUE_TYPE (peek_value))
2059 g_value_copy (peek_value, value);
2060 else if (g_value_type_transformable (G_VALUE_TYPE (peek_value), G_VALUE_TYPE (value)))
2061 g_value_transform (peek_value, value);
2063 g_warning ("can't retrieve style property `%s' of type `%s' as value of type `%s'",
2065 G_VALUE_TYPE_NAME (peek_value),
2066 G_VALUE_TYPE_NAME (value));
2070 * gtk_style_context_get_style_valist:
2071 * @context: a #GtkStyleContext
2072 * @args: va_list of property name/return location pairs, followed by %NULL
2074 * Retrieves several widget style properties from @context according to the
2080 gtk_style_context_get_style_valist (GtkStyleContext *context,
2083 GtkStyleContextPrivate *priv;
2084 const gchar *prop_name;
2086 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2088 prop_name = va_arg (args, const gchar *);
2089 priv = context->priv;
2091 if (!priv->widget_path)
2096 GtkWidgetClass *widget_class;
2098 const GValue *peek_value;
2102 widget_type = gtk_widget_path_get_widget_type (priv->widget_path);
2104 widget_class = g_type_class_ref (widget_type);
2105 pspec = gtk_widget_class_find_style_property (widget_class, prop_name);
2106 g_type_class_unref (widget_class);
2110 g_warning ("%s: widget class `%s' has no style property named `%s'",
2112 g_type_name (widget_type),
2117 peek_value = _gtk_style_context_peek_style_property (context,
2121 G_VALUE_LCOPY (peek_value, args, 0, &error);
2125 g_warning ("can't retrieve style property `%s' of type `%s': %s",
2127 G_VALUE_TYPE_NAME (peek_value),
2132 prop_name = va_arg (args, const gchar *);
2137 * gtk_style_context_get_style:
2138 * @context: a #GtkStyleContext
2139 * @...: property name /return value pairs, followed by %NULL
2141 * Retrieves several widget style properties from @context according to the
2147 gtk_style_context_get_style (GtkStyleContext *context,
2152 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2154 va_start (args, context);
2155 gtk_style_context_get_style_valist (context, args);
2161 * gtk_style_context_lookup_icon_set:
2162 * @context: a #GtkStyleContext
2163 * @stock_id: an icon name
2165 * Looks up @stock_id in the icon factories associated to @context and
2166 * the default icon factory, returning an icon set if found, otherwise
2169 * Returns: (transfer none): The looked up %GtkIconSet, or %NULL
2172 gtk_style_context_lookup_icon_set (GtkStyleContext *context,
2173 const gchar *stock_id)
2175 GtkStyleContextPrivate *priv;
2179 g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), NULL);
2180 g_return_val_if_fail (stock_id != NULL, NULL);
2182 priv = context->priv;
2183 g_return_val_if_fail (priv->widget_path != NULL, NULL);
2185 data = style_data_lookup (context);
2187 for (list = data->icon_factories; list; list = list->next)
2189 GtkIconFactory *factory;
2190 GtkIconSet *icon_set;
2192 factory = list->data;
2193 icon_set = gtk_icon_factory_lookup (factory, stock_id);
2199 return gtk_icon_factory_lookup_default (stock_id);
2203 * gtk_style_context_set_screen:
2204 * @context: a #GtkStyleContext
2205 * @screen: a #GdkScreen
2207 * Sets the screen to which @context will be attached to, @screen
2208 * is used in order to reconstruct style based on the global providers
2209 * list. If you are using a #GtkStyleContext returned from
2210 * gtk_widget_get_style_context(), you do not need to call this yourself.
2215 gtk_style_context_set_screen (GtkStyleContext *context,
2218 GtkStyleContextPrivate *priv;
2220 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2222 priv = context->priv;
2223 priv->screen = screen;
2225 g_object_notify (G_OBJECT (context), "screen");
2227 gtk_style_context_invalidate (context);
2231 * gtk_style_context_get_screen:
2232 * @context: a #GtkStyleContext
2234 * Returns the #GdkScreen to which @context is attached to.
2236 * Returns: a #GdkScreen, or %NULL.
2239 gtk_style_context_get_screen (GtkStyleContext *context)
2241 GtkStyleContextPrivate *priv;
2243 g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), NULL);
2245 priv = context->priv;
2246 return priv->screen;
2250 * gtk_style_context_set_direction:
2251 * @context: a #GtkStyleContext
2252 * @direction: the new direction.
2254 * Sets the reading direction for rendering purposes. If you are
2255 * using a #GtkStyleContext returned from gtk_widget_get_style_context(),
2256 * you do not need to call this yourself.
2261 gtk_style_context_set_direction (GtkStyleContext *context,
2262 GtkTextDirection direction)
2264 GtkStyleContextPrivate *priv;
2266 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2268 priv = context->priv;
2269 priv->direction = direction;
2271 g_object_notify (G_OBJECT (context), "direction");
2275 * gtk_style_context_get_direction:
2276 * @context: a #GtkStyleContext
2278 * Returns the widget direction used for rendering.
2280 * Returns: the widget direction
2285 gtk_style_context_get_direction (GtkStyleContext *context)
2287 GtkStyleContextPrivate *priv;
2289 g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), GTK_TEXT_DIR_LTR);
2291 priv = context->priv;
2292 return priv->direction;
2296 * gtk_style_context_set_junction_sides:
2297 * @context: a #GtkStyleContext
2298 * @sides: sides where rendered elements are visually connected to other elements.
2300 * Sets the sides where rendered elements (mostly through gtk_render_frame()) will
2301 * visually connect with other visual elements. This is merely a guideline that may
2302 * be honored or not in theming engines.
2307 gtk_style_context_set_junction_sides (GtkStyleContext *context,
2308 GtkJunctionSides sides)
2310 GtkStyleContextPrivate *priv;
2313 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2315 priv = context->priv;
2316 info = priv->info_stack->data;
2317 info->junction_sides = sides;
2321 * gtk_style_context_get_junction_sides:
2322 * @context: a #GtkStyleContext
2324 * Returns the sides where rendered elements connect visually with others.
2326 * Returns: the junction sides
2331 gtk_style_context_get_junction_sides (GtkStyleContext *context)
2333 GtkStyleContextPrivate *priv;
2336 g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), 0);
2338 priv = context->priv;
2339 info = priv->info_stack->data;
2340 return info->junction_sides;
2344 * gtk_style_context_lookup_color:
2345 * @context: a #GtkStyleContext
2346 * @color_name: color name to lookup
2347 * @color: (out): Return location for the looked up color
2349 * Looks up and resolves a color name in the @context color map.
2351 * Returns: %TRUE if @color_name was found and resolved, %FALSE otherwise
2354 gtk_style_context_lookup_color (GtkStyleContext *context,
2355 const gchar *color_name,
2358 GtkStyleContextPrivate *priv;
2359 GtkSymbolicColor *sym_color;
2362 g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), FALSE);
2363 g_return_val_if_fail (color_name != NULL, FALSE);
2364 g_return_val_if_fail (color != NULL, FALSE);
2366 priv = context->priv;
2367 g_return_val_if_fail (priv->widget_path != NULL, FALSE);
2369 data = style_data_lookup (context);
2370 sym_color = gtk_style_set_lookup_color (data->store, color_name);
2375 return gtk_symbolic_color_resolve (sym_color, data->store, color);
2379 * gtk_style_context_notify_state_change:
2380 * @context: a #GtkStyleContext
2381 * @window: a #GdkWindow
2382 * @region_id: (allow-none): animatable region to notify on, or %NULL.
2383 * See gtk_style_context_push_animatable_region()
2384 * @state: state to trigger transition for
2385 * @state_value: target value of @state
2387 * Notifies a state change on @context, so if the current style makes use
2388 * of transition animations, one will be started so all rendered elements
2389 * under @region_id are animated for state @state being set to value @state_value.
2391 * The @window parameter is used in order to invalidate the rendered area
2392 * as the animation runs, so make sure it is the same window that is being
2393 * rendered on by the gtk_render_*() methods.
2395 * If @region_id is %NULL, all rendered elements using @context will be
2396 * affected by this state transition.
2398 * As a practical example, a #GtkButton notifying a state transition on
2399 * the prelight state:
2401 * gtk_style_context_notify_state_change (context,
2402 * gtk_widget_get_window (widget),
2403 * NULL, GTK_STATE_PRELIGHT,
2404 * button->in_button);
2407 * Could be handled in the CSS file like this:
2410 * background-color: #f00;
2414 * background-color: #fff;
2415 * transition: 200ms linear;
2419 * This combination would animate the button background from red to white
2420 * if a pointer enters the button, and back to red if the pointer leaves
2426 gtk_style_context_notify_state_change (GtkStyleContext *context,
2430 gboolean state_value)
2432 GtkStyleContextPrivate *priv;
2433 GtkAnimationDescription *desc;
2434 AnimationInfo *info;
2435 GtkStateFlags flags;
2438 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2439 g_return_if_fail (GDK_IS_WINDOW (window));
2440 g_return_if_fail (state < GTK_STATE_LAST);
2442 priv = context->priv;
2443 g_return_if_fail (priv->widget_path != NULL);
2445 state_value = (state_value == TRUE);
2449 case GTK_STATE_ACTIVE:
2450 flags = GTK_STATE_FLAG_ACTIVE;
2452 case GTK_STATE_PRELIGHT:
2453 flags = GTK_STATE_FLAG_PRELIGHT;
2455 case GTK_STATE_SELECTED:
2456 flags = GTK_STATE_FLAG_SELECTED;
2458 case GTK_STATE_INSENSITIVE:
2459 flags = GTK_STATE_FLAG_INSENSITIVE;
2461 case GTK_STATE_INCONSISTENT:
2462 flags = GTK_STATE_FLAG_INCONSISTENT;
2464 case GTK_STATE_FOCUSED:
2465 flags = GTK_STATE_FLAG_FOCUSED;
2467 case GTK_STATE_NORMAL:
2473 /* Find out if there is any animation description for the given
2474 * state, it will fallback to the normal state as well if necessary.
2476 data = style_data_lookup (context);
2477 gtk_style_set_get (data->store, flags,
2478 "transition", &desc,
2484 if (gtk_animation_description_get_duration (desc) == 0)
2486 gtk_animation_description_unref (desc);
2490 info = animation_info_lookup (context, region_id, state);
2494 /* Reverse the animation if target values are the opposite */
2495 if (info->target_value != state_value)
2497 if (gtk_timeline_get_direction (info->timeline) == GTK_TIMELINE_DIRECTION_FORWARD)
2498 gtk_timeline_set_direction (info->timeline, GTK_TIMELINE_DIRECTION_BACKWARD);
2500 gtk_timeline_set_direction (info->timeline, GTK_TIMELINE_DIRECTION_FORWARD);
2502 info->target_value = state_value;
2507 info = animation_info_new (context, region_id,
2508 gtk_animation_description_get_duration (desc),
2509 gtk_animation_description_get_progress_type (desc),
2510 state, state_value, window);
2512 priv->animations = g_slist_prepend (priv->animations, info);
2513 priv->animations_invalidated = TRUE;
2516 gtk_animation_description_unref (desc);
2520 * gtk_style_context_push_animatable_region:
2521 * @context: a #GtkStyleContext
2522 * @region_id: unique identifier for the animatable region
2524 * Pushes an animatable region, so all further gtk_render_*() calls between
2525 * this call and the following gtk_style_context_pop_animatable_region() will
2526 * potentially show transition animations for if gtk_style_context_notify_state_change()
2527 * is called for a given state, and the theme/style used contemplates the use of
2528 * transition animations for state changes.
2530 * The @region_id used must be unique in @context so the theming engine may
2531 * univocally identify rendered elements subject to a state transition.
2536 gtk_style_context_push_animatable_region (GtkStyleContext *context,
2539 GtkStyleContextPrivate *priv;
2541 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2542 g_return_if_fail (region_id != NULL);
2544 priv = context->priv;
2545 priv->animation_regions = g_slist_prepend (priv->animation_regions, region_id);
2549 * gtk_style_context_pop_animatable_region:
2550 * @context: a #GtkStyleContext
2552 * Pops an animatable region from @context. See gtk_style_context_push_animatable_region().
2557 gtk_style_context_pop_animatable_region (GtkStyleContext *context)
2559 GtkStyleContextPrivate *priv;
2561 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2563 priv = context->priv;
2564 priv->animation_regions = g_slist_delete_link (priv->animation_regions,
2565 priv->animation_regions);
2569 _gtk_style_context_invalidate_animation_areas (GtkStyleContext *context)
2571 GtkStyleContextPrivate *priv;
2574 priv = context->priv;
2576 for (l = priv->animations; l; l = l->next)
2578 AnimationInfo *info;
2582 /* A NULL invalidation region means it has to be recreated on
2583 * the next expose event, this happens usually after a widget
2584 * allocation change, so the next expose after it will update
2585 * the invalidation region.
2587 if (info->invalidation_region)
2589 cairo_region_destroy (info->invalidation_region);
2590 info->invalidation_region = NULL;
2594 priv->animations_invalidated = TRUE;
2598 _gtk_style_context_coalesce_animation_areas (GtkStyleContext *context,
2602 GtkStyleContextPrivate *priv;
2605 priv = context->priv;
2607 if (!priv->animations_invalidated)
2610 for (l = priv->animations; l; l = l->next)
2612 AnimationInfo *info;
2617 if (info->invalidation_region)
2620 /* FIXME: If this happens there's not much
2621 * point in keeping the animation running.
2623 if (info->rectangles->len == 0)
2626 info->invalidation_region = cairo_region_create ();
2628 for (i = 0; i <info->rectangles->len; i++)
2630 cairo_rectangle_int_t *rect;
2632 rect = &g_array_index (info->rectangles, cairo_rectangle_int_t, i);
2636 cairo_region_union_rectangle (info->invalidation_region, rect);
2639 g_array_remove_range (info->rectangles, 0, info->rectangles->len);
2642 priv->animations_invalidated = FALSE;
2646 store_animation_region (GtkStyleContext *context,
2652 GtkStyleContextPrivate *priv;
2655 priv = context->priv;
2657 if (!priv->animations_invalidated)
2660 for (l = priv->animations; l; l = l->next)
2662 AnimationInfo *info;
2666 /* The animation doesn't need updatring
2667 * the invalidation area, bail out.
2669 if (info->invalidation_region)
2672 if (context_has_animatable_region (context, info->region_id))
2674 cairo_rectangle_int_t rect;
2678 rect.width = (gint) width;
2679 rect.height = (gint) height;
2681 g_array_append_val (info->rectangles, rect);
2687 * gtk_style_context_invalidate:
2688 * @context: a #GtkStyleContext.
2690 * Invalidates @context style information, so it will be reconstructed
2691 * again. If you're using a #GtkStyleContext returned from
2692 * gtk_widget_get_style_context(), you do not need to call this yourself.
2697 gtk_style_context_invalidate (GtkStyleContext *context)
2699 GtkStyleContextPrivate *priv;
2701 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2703 priv = context->priv;
2705 /* Avoid reentrancy */
2706 if (priv->invalidating_context)
2709 priv->invalidating_context = TRUE;
2711 g_hash_table_remove_all (priv->style_data);
2712 priv->current_data = NULL;
2714 g_signal_emit (context, signals[CHANGED], 0);
2716 priv->invalidating_context = FALSE;
2721 gtk_render_check (GtkStyleContext *context,
2728 GtkStyleContextPrivate *priv;
2729 GtkThemingEngineClass *engine_class;
2731 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2732 g_return_if_fail (cr != NULL);
2734 priv = context->priv;
2735 engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
2737 store_animation_region (context, x, y, width, height);
2739 _gtk_theming_engine_set_context (priv->theming_engine, context);
2740 engine_class->render_check (priv->theming_engine, cr,
2741 x, y, width, height);
2745 gtk_render_option (GtkStyleContext *context,
2752 GtkStyleContextPrivate *priv;
2753 GtkThemingEngineClass *engine_class;
2755 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2756 g_return_if_fail (cr != NULL);
2758 priv = context->priv;
2759 engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
2761 store_animation_region (context, x, y, width, height);
2763 _gtk_theming_engine_set_context (priv->theming_engine, context);
2764 engine_class->render_option (priv->theming_engine, cr,
2765 x, y, width, height);
2769 gtk_render_arrow (GtkStyleContext *context,
2776 GtkStyleContextPrivate *priv;
2777 GtkThemingEngineClass *engine_class;
2779 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2780 g_return_if_fail (cr != NULL);
2782 priv = context->priv;
2783 engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
2785 store_animation_region (context, x, y, size, size);
2787 _gtk_theming_engine_set_context (priv->theming_engine, context);
2788 engine_class->render_arrow (priv->theming_engine, cr,
2793 gtk_render_background (GtkStyleContext *context,
2800 GtkStyleContextPrivate *priv;
2801 GtkThemingEngineClass *engine_class;
2803 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2804 g_return_if_fail (cr != NULL);
2806 priv = context->priv;
2807 engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
2809 store_animation_region (context, x, y, width, height);
2811 _gtk_theming_engine_set_context (priv->theming_engine, context);
2812 engine_class->render_background (priv->theming_engine, cr, x, y, width, height);
2816 gtk_render_frame (GtkStyleContext *context,
2823 GtkStyleContextPrivate *priv;
2824 GtkThemingEngineClass *engine_class;
2826 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2827 g_return_if_fail (cr != NULL);
2829 priv = context->priv;
2830 engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
2832 store_animation_region (context, x, y, width, height);
2834 _gtk_theming_engine_set_context (priv->theming_engine, context);
2835 engine_class->render_frame (priv->theming_engine, cr, x, y, width, height);
2839 gtk_render_expander (GtkStyleContext *context,
2846 GtkStyleContextPrivate *priv;
2847 GtkThemingEngineClass *engine_class;
2849 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2850 g_return_if_fail (cr != NULL);
2852 priv = context->priv;
2853 engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
2855 store_animation_region (context, x, y, width, height);
2857 _gtk_theming_engine_set_context (priv->theming_engine, context);
2858 engine_class->render_expander (priv->theming_engine, cr, x, y, width, height);
2862 gtk_render_focus (GtkStyleContext *context,
2869 GtkStyleContextPrivate *priv;
2870 GtkThemingEngineClass *engine_class;
2872 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2873 g_return_if_fail (cr != NULL);
2875 priv = context->priv;
2876 engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
2878 store_animation_region (context, x, y, width, height);
2880 _gtk_theming_engine_set_context (priv->theming_engine, context);
2881 engine_class->render_focus (priv->theming_engine, cr, x, y, width, height);
2885 gtk_render_layout (GtkStyleContext *context,
2889 PangoLayout *layout)
2891 GtkStyleContextPrivate *priv;
2892 GtkThemingEngineClass *engine_class;
2894 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2895 g_return_if_fail (cr != NULL);
2897 priv = context->priv;
2898 engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
2900 _gtk_theming_engine_set_context (priv->theming_engine, context);
2901 engine_class->render_layout (priv->theming_engine, cr, x, y, layout);
2905 gtk_render_line (GtkStyleContext *context,
2912 GtkStyleContextPrivate *priv;
2913 GtkThemingEngineClass *engine_class;
2915 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2916 g_return_if_fail (cr != NULL);
2918 priv = context->priv;
2919 engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
2921 _gtk_theming_engine_set_context (priv->theming_engine, context);
2922 engine_class->render_line (priv->theming_engine, cr, x0, y0, x1, y1);
2926 gtk_render_slider (GtkStyleContext *context,
2932 GtkOrientation orientation)
2934 GtkStyleContextPrivate *priv;
2935 GtkThemingEngineClass *engine_class;
2937 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2938 g_return_if_fail (cr != NULL);
2940 priv = context->priv;
2941 engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
2943 store_animation_region (context, x, y, width, height);
2945 _gtk_theming_engine_set_context (priv->theming_engine, context);
2946 engine_class->render_slider (priv->theming_engine, cr, x, y, width, height, orientation);
2950 gtk_render_frame_gap (GtkStyleContext *context,
2956 GtkPositionType gap_side,
2960 GtkStyleContextPrivate *priv;
2961 GtkThemingEngineClass *engine_class;
2963 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2964 g_return_if_fail (cr != NULL);
2966 priv = context->priv;
2967 engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
2969 store_animation_region (context, x, y, width, height);
2971 _gtk_theming_engine_set_context (priv->theming_engine, context);
2972 engine_class->render_frame_gap (priv->theming_engine, cr,
2973 x, y, width, height, gap_side,
2978 gtk_render_extension (GtkStyleContext *context,
2984 GtkPositionType gap_side)
2986 GtkStyleContextPrivate *priv;
2987 GtkThemingEngineClass *engine_class;
2989 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2990 g_return_if_fail (cr != NULL);
2992 priv = context->priv;
2993 engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
2995 store_animation_region (context, x, y, width, height);
2997 _gtk_theming_engine_set_context (priv->theming_engine, context);
2998 engine_class->render_extension (priv->theming_engine, cr, x, y, width, height, gap_side);
3002 gtk_render_handle (GtkStyleContext *context,
3009 GtkStyleContextPrivate *priv;
3010 GtkThemingEngineClass *engine_class;
3012 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3013 g_return_if_fail (cr != NULL);
3015 priv = context->priv;
3016 engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
3018 store_animation_region (context, x, y, width, height);
3020 _gtk_theming_engine_set_context (priv->theming_engine, context);
3021 engine_class->render_handle (priv->theming_engine, cr, x, y, width, height);