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.
22 #include "gtkstylepropertiesprivate.h"
25 #include <gobject/gvaluecollector.h>
26 #include <cairo-gobject.h>
28 #include "gtkstyleprovider.h"
29 #include "gtksymboliccolor.h"
30 #include "gtkthemingengine.h"
31 #include "gtkanimationdescription.h"
32 #include "gtkgradient.h"
33 #include "gtkshadowprivate.h"
34 #include "gtkcsstypesprivate.h"
36 #include "gtkstylepropertyprivate.h"
40 * SECTION:gtkstyleproperties
41 * @Short_description: Store for style property information
42 * @Title: GtkStyleProperties
44 * GtkStyleProperties provides the storage for style information
45 * that is used by #GtkStyleContext and other #GtkStyleProvider
48 * Before style properties can be stored in GtkStyleProperties, they
49 * must be registered with gtk_style_properties_register_property().
51 * Unless you are writing a #GtkStyleProvider implementation, you
52 * are unlikely to use this API directly, as gtk_style_context_get()
53 * and its variants are the preferred way to access styling information
54 * from widget implementations and theming engine implementations
55 * should use the APIs provided by #GtkThemingEngine instead.
58 typedef struct GtkStylePropertiesPrivate GtkStylePropertiesPrivate;
59 typedef struct PropertyData PropertyData;
60 typedef struct ValueData ValueData;
73 struct GtkStylePropertiesPrivate
75 GHashTable *color_map;
76 GHashTable *properties;
79 static void gtk_style_properties_provider_init (GtkStyleProviderIface *iface);
80 static void gtk_style_properties_finalize (GObject *object);
83 G_DEFINE_TYPE_EXTENDED (GtkStyleProperties, gtk_style_properties, G_TYPE_OBJECT, 0,
84 G_IMPLEMENT_INTERFACE (GTK_TYPE_STYLE_PROVIDER,
85 gtk_style_properties_provider_init));
88 gtk_style_properties_class_init (GtkStylePropertiesClass *klass)
90 GObjectClass *object_class = G_OBJECT_CLASS (klass);
92 object_class->finalize = gtk_style_properties_finalize;
94 g_type_class_add_private (object_class, sizeof (GtkStylePropertiesPrivate));
98 property_data_new (void)
102 data = g_slice_new0 (PropertyData);
103 data->values = g_array_new (FALSE, FALSE, sizeof (ValueData));
109 property_data_remove_values (PropertyData *data)
113 for (i = 0; i < data->values->len; i++)
115 ValueData *value_data;
117 value_data = &g_array_index (data->values, ValueData, i);
119 if (G_IS_VALUE (&value_data->value))
120 g_value_unset (&value_data->value);
123 if (data->values->len > 0)
124 g_array_remove_range (data->values, 0, data->values->len);
128 property_data_free (PropertyData *data)
130 property_data_remove_values (data);
131 g_array_free (data->values, TRUE);
132 g_slice_free (PropertyData, data);
136 property_data_find_position (PropertyData *data,
141 gboolean found = FALSE;
147 if (data->values->len == 0)
150 /* Find position for the given state, or the position where
151 * it would be if not found, the array is ordered by the
155 max = data->values->len - 1;
159 ValueData *value_data;
161 mid = (min + max) / 2;
162 value_data = &g_array_index (data->values, ValueData, mid);
164 if (value_data->state == state)
169 else if (value_data->state < state)
170 position = min = mid + 1;
177 while (!found && min <= max);
186 property_data_get_value (PropertyData *data,
192 if (!property_data_find_position (data, state, &pos))
194 ValueData new = { 0 };
197 g_array_insert_val (data->values, pos, new);
200 val_data = &g_array_index (data->values, ValueData, pos);
202 return &val_data->value;
206 property_data_match_state (PropertyData *data,
212 if (property_data_find_position (data, state, &pos))
217 val_data = &g_array_index (data->values, ValueData, pos);
218 return &val_data->value;
221 if (pos >= data->values->len)
222 pos = data->values->len - 1;
224 /* No exact match, go downwards the list to find
225 * the closest match to the given state flags, as
226 * a side effect, there is an implicit precedence
227 * of higher flags over the smaller ones.
229 for (i = pos; i >= 0; i--)
233 val_data = &g_array_index (data->values, ValueData, i);
235 /* Check whether any of the requested
236 * flags are set, and no other flags are.
238 * Also, no flags acts as a wildcard, such
239 * value should be always in the first position
240 * in the array (if present) anyways.
242 if (val_data->state == 0 ||
243 ((val_data->state & state) != 0 &&
244 (val_data->state & ~state) == 0))
245 return &val_data->value;
252 gtk_style_properties_init (GtkStyleProperties *props)
254 GtkStylePropertiesPrivate *priv;
256 priv = props->priv = G_TYPE_INSTANCE_GET_PRIVATE (props,
257 GTK_TYPE_STYLE_PROPERTIES,
258 GtkStylePropertiesPrivate);
260 priv->properties = g_hash_table_new_full (NULL, NULL, NULL,
261 (GDestroyNotify) property_data_free);
265 gtk_style_properties_finalize (GObject *object)
267 GtkStylePropertiesPrivate *priv;
268 GtkStyleProperties *props;
270 props = GTK_STYLE_PROPERTIES (object);
272 g_hash_table_destroy (priv->properties);
275 g_hash_table_destroy (priv->color_map);
277 G_OBJECT_CLASS (gtk_style_properties_parent_class)->finalize (object);
281 gtk_style_properties_get_style (GtkStyleProvider *provider,
284 /* Return style set itself */
285 return g_object_ref (provider);
289 gtk_style_properties_provider_init (GtkStyleProviderIface *iface)
291 iface->get_style = gtk_style_properties_get_style;
294 /* Property registration functions */
297 * gtk_style_properties_register_property: (skip)
298 * @parse_func: parsing function to use, or %NULL
299 * @pspec: the #GParamSpec for the new property
301 * Registers a property so it can be used in the CSS file format.
302 * This function is the low-level equivalent of
303 * gtk_theming_engine_register_property(), if you are implementing
304 * a theming engine, you want to use that function instead.
309 gtk_style_properties_register_property (GtkStylePropertyParser parse_func,
312 g_return_if_fail (G_IS_PARAM_SPEC (pspec));
314 _gtk_style_property_register (pspec,
323 * gtk_style_properties_lookup_property: (skip)
324 * @property_name: property name to look up
325 * @parse_func: (out): return location for the parse function
326 * @pspec: (out) (transfer none): return location for the #GParamSpec
328 * Returns %TRUE if a property has been registered, if @pspec or
329 * @parse_func are not %NULL, the #GParamSpec and parsing function
330 * will be respectively returned.
332 * Returns: %TRUE if the property is registered, %FALSE otherwise
337 gtk_style_properties_lookup_property (const gchar *property_name,
338 GtkStylePropertyParser *parse_func,
341 const GtkStyleProperty *node;
342 gboolean found = FALSE;
344 g_return_val_if_fail (property_name != NULL, FALSE);
346 node = _gtk_style_property_lookup (property_name);
351 *pspec = node->pspec;
354 *parse_func = node->property_parse_func;
362 /* GParamSpec functionality */
365 GTK_STYLE_PROPERTY_INHERIT = 1 << G_PARAM_USER_SHIFT
369 * gtk_style_param_set_inherit:
370 * @pspec: A style param
371 * @inherit: whether the @pspec value should be inherited
373 * Sets whether a param spec installed with function such as
374 * gtk_style_properties_register_property() or
375 * gtk_widget_class_install_style_property() should inherit their
376 * value from the parent widget if it is not set instead of using
377 * the default value of @pspec. See the
378 * <ulink url="http://www.w3.org/TR/CSS21/cascade.html#inheritance">
379 * CSS specification's description of inheritance</ulink> for a
380 * longer description of this concept.
382 * By default, param specs do not inherit their value.
385 gtk_style_param_set_inherit (GParamSpec *pspec,
389 pspec->flags |= GTK_STYLE_PROPERTY_INHERIT;
391 pspec->flags &= ~GTK_STYLE_PROPERTY_INHERIT;
395 * gtk_style_param_get_inherit:
396 * @pspec: a style param
398 * Checks if the value of this param should be inherited from the parent
399 * #GtkWidget instead of using the default value when it has not been
400 * specified. See gtk_style_param_set_inherit() for more details.
402 * Returns: %TRUE if the param should inherit its value
405 gtk_style_param_get_inherit (GParamSpec *pspec)
407 return (pspec->flags & GTK_STYLE_PROPERTY_INHERIT) ? TRUE : FALSE;
410 /* GtkStyleProperties methods */
413 * gtk_style_properties_new:
415 * Returns a newly created #GtkStyleProperties
417 * Returns: a new #GtkStyleProperties
420 gtk_style_properties_new (void)
422 return g_object_new (GTK_TYPE_STYLE_PROPERTIES, NULL);
426 * gtk_style_properties_map_color:
427 * @props: a #GtkStyleProperties
429 * @color: #GtkSymbolicColor to map @name to
431 * Maps @color so it can be referenced by @name. See
432 * gtk_style_properties_lookup_color()
437 gtk_style_properties_map_color (GtkStyleProperties *props,
439 GtkSymbolicColor *color)
441 GtkStylePropertiesPrivate *priv;
443 g_return_if_fail (GTK_IS_STYLE_PROPERTIES (props));
444 g_return_if_fail (name != NULL);
445 g_return_if_fail (color != NULL);
449 if (G_UNLIKELY (!priv->color_map))
450 priv->color_map = g_hash_table_new_full (g_str_hash,
452 (GDestroyNotify) g_free,
453 (GDestroyNotify) gtk_symbolic_color_unref);
455 g_hash_table_replace (priv->color_map,
457 gtk_symbolic_color_ref (color));
461 * gtk_style_properties_lookup_color:
462 * @props: a #GtkStyleProperties
463 * @name: color name to lookup
465 * Returns the symbolic color that is mapped
468 * Returns: (transfer none): The mapped color
473 gtk_style_properties_lookup_color (GtkStyleProperties *props,
476 GtkStylePropertiesPrivate *priv;
478 g_return_val_if_fail (GTK_IS_STYLE_PROPERTIES (props), NULL);
479 g_return_val_if_fail (name != NULL, NULL);
483 if (!priv->color_map)
486 return g_hash_table_lookup (priv->color_map, name);
490 _gtk_style_properties_set_property_by_property (GtkStyleProperties *props,
491 const GtkStyleProperty *style_prop,
495 GtkStylePropertiesPrivate *priv;
500 value_type = G_VALUE_TYPE (value);
502 if (style_prop->pspec->value_type == GDK_TYPE_RGBA ||
503 style_prop->pspec->value_type == GDK_TYPE_COLOR)
505 /* Allow GtkSymbolicColor as well */
506 g_return_if_fail (value_type == GDK_TYPE_RGBA ||
507 value_type == GDK_TYPE_COLOR ||
508 value_type == GTK_TYPE_SYMBOLIC_COLOR);
510 else if (style_prop->pspec->value_type == CAIRO_GOBJECT_TYPE_PATTERN)
512 /* Allow GtkGradient as a substitute */
513 g_return_if_fail (value_type == CAIRO_GOBJECT_TYPE_PATTERN ||
514 value_type == GTK_TYPE_GRADIENT);
516 else if (style_prop->pspec->value_type == G_TYPE_INT)
518 g_return_if_fail (value_type == G_TYPE_INT ||
519 value_type == GTK_TYPE_CSS_BORDER_RADIUS);
522 g_return_if_fail (style_prop->pspec->value_type == value_type);
524 if (_gtk_style_property_is_shorthand (style_prop))
526 GParameter *parameters;
527 guint i, n_parameters;
529 parameters = _gtk_style_property_unpack (style_prop, value, &n_parameters);
531 for (i = 0; i < n_parameters; i++)
533 gtk_style_properties_set_property (props,
536 ¶meters[i].value);
537 g_value_unset (¶meters[i].value);
544 prop = g_hash_table_lookup (priv->properties, style_prop);
548 prop = property_data_new ();
549 g_hash_table_insert (priv->properties, (gpointer) style_prop, prop);
552 val = property_data_get_value (prop, state);
554 if (G_VALUE_TYPE (val) == value_type)
558 if (G_IS_VALUE (val))
561 g_value_init (val, value_type);
564 g_value_copy (value, val);
565 if (style_prop->pspec->value_type == value_type)
566 g_param_value_validate (style_prop->pspec, val);
570 * gtk_style_properties_set_property:
571 * @props: a #GtkStyleProperties
572 * @property: styling property to set
573 * @state: state to set the value for
574 * @value: new value for the property
576 * Sets a styling property in @props.
581 gtk_style_properties_set_property (GtkStyleProperties *props,
582 const gchar *property,
586 const GtkStyleProperty *node;
588 g_return_if_fail (GTK_IS_STYLE_PROPERTIES (props));
589 g_return_if_fail (property != NULL);
590 g_return_if_fail (value != NULL);
592 node = _gtk_style_property_lookup (property);
596 g_warning ("Style property \"%s\" is not registered", property);
600 _gtk_style_properties_set_property_by_property (props,
607 * gtk_style_properties_set_valist:
608 * @props: a #GtkStyleProperties
609 * @state: state to set the values for
610 * @args: va_list of property name/value pairs, followed by %NULL
612 * Sets several style properties on @props.
617 gtk_style_properties_set_valist (GtkStyleProperties *props,
621 const gchar *property_name;
623 g_return_if_fail (GTK_IS_STYLE_PROPERTIES (props));
625 property_name = va_arg (args, const gchar *);
627 while (property_name)
629 const GtkStyleProperty *node;
633 node = _gtk_style_property_lookup (property_name);
637 g_warning ("Style property \"%s\" is not registered", property_name);
641 G_VALUE_COLLECT_INIT (&val, node->pspec->value_type,
645 g_warning ("Could not set style property \"%s\": %s", property_name, error);
646 g_value_unset (&val);
651 _gtk_style_properties_set_property_by_property (props, node, state, &val);
652 g_value_unset (&val);
654 property_name = va_arg (args, const gchar *);
659 * gtk_style_properties_set:
660 * @props: a #GtkStyleProperties
661 * @state: state to set the values for
662 * @...: property name/value pairs, followed by %NULL
664 * Sets several style properties on @props.
669 gtk_style_properties_set (GtkStyleProperties *props,
675 g_return_if_fail (GTK_IS_STYLE_PROPERTIES (props));
677 va_start (args, state);
678 gtk_style_properties_set_valist (props, state, args);
683 resolve_color (GtkStyleProperties *props,
688 /* Resolve symbolic color to GdkRGBA */
689 if (!gtk_symbolic_color_resolve (g_value_get_boxed (value), props, &color))
692 /* Store it back, this is where GdkRGBA caching happens */
693 g_value_unset (value);
694 g_value_init (value, GDK_TYPE_RGBA);
695 g_value_set_boxed (value, &color);
701 resolve_color_rgb (GtkStyleProperties *props,
704 GdkColor color = { 0 };
707 if (!gtk_symbolic_color_resolve (g_value_get_boxed (value), props, &rgba))
710 color.red = rgba.red * 65535. + 0.5;
711 color.green = rgba.green * 65535. + 0.5;
712 color.blue = rgba.blue * 65535. + 0.5;
714 g_value_unset (value);
715 g_value_init (value, GDK_TYPE_COLOR);
716 g_value_set_boxed (value, &color);
722 resolve_gradient (GtkStyleProperties *props,
725 cairo_pattern_t *gradient;
727 if (!gtk_gradient_resolve (g_value_get_boxed (value), props, &gradient))
730 /* Store it back, this is where cairo_pattern_t caching happens */
731 g_value_unset (value);
732 g_value_init (value, CAIRO_GOBJECT_TYPE_PATTERN);
733 g_value_take_boxed (value, gradient);
739 resolve_shadow (GtkStyleProperties *props,
742 GtkShadow *resolved, *base;
744 base = g_value_get_boxed (value);
749 if (_gtk_shadow_get_resolved (base))
752 resolved = _gtk_shadow_resolve (base, props);
753 if (resolved == NULL)
756 g_value_take_boxed (value, resolved);
762 style_properties_resolve_type (GtkStyleProperties *props,
763 const GtkStyleProperty *node,
766 if (G_VALUE_TYPE (val) == GTK_TYPE_SYMBOLIC_COLOR)
768 if (node->pspec->value_type == GDK_TYPE_RGBA)
770 if (!resolve_color (props, val))
773 else if (node->pspec->value_type == GDK_TYPE_COLOR)
775 if (!resolve_color_rgb (props, val))
781 else if (G_VALUE_TYPE (val) == GTK_TYPE_GRADIENT)
783 g_return_val_if_fail (node->pspec->value_type == CAIRO_GOBJECT_TYPE_PATTERN, FALSE);
785 if (!resolve_gradient (props, val))
788 else if (G_VALUE_TYPE (val) == GTK_TYPE_SHADOW)
790 if (!resolve_shadow (props, val))
798 lookup_default_value (const GtkStyleProperty *node,
801 if (node->pspec->value_type == GTK_TYPE_THEMING_ENGINE)
802 g_value_set_object (value, gtk_theming_engine_load (NULL));
803 else if (node->pspec->value_type == PANGO_TYPE_FONT_DESCRIPTION)
804 g_value_take_boxed (value, pango_font_description_from_string ("Sans 10"));
805 else if (node->pspec->value_type == GDK_TYPE_RGBA)
808 gdk_rgba_parse (&color, "pink");
809 g_value_set_boxed (value, &color);
811 else if (node->pspec->value_type == GTK_TYPE_BORDER)
813 g_value_take_boxed (value, gtk_border_new ());
816 g_param_value_set_default (node->pspec, value);
819 /* NB: Will return NULL for shorthands */
821 _gtk_style_properties_peek_property (GtkStyleProperties *props,
822 const gchar *prop_name,
824 const GtkStyleProperty **property)
826 GtkStylePropertiesPrivate *priv;
827 const GtkStyleProperty *node;
831 g_return_val_if_fail (GTK_IS_STYLE_PROPERTIES (props), NULL);
832 g_return_val_if_fail (prop_name != NULL, NULL);
834 node = _gtk_style_property_lookup (prop_name);
840 g_warning ("Style property \"%s\" is not registered", prop_name);
845 prop = g_hash_table_lookup (priv->properties, node);
850 val = property_data_match_state (prop, state);
853 !style_properties_resolve_type (props, node, val))
860 * gtk_style_properties_get_property:
861 * @props: a #GtkStyleProperties
862 * @property: style property name
863 * @state: state to retrieve the property value for
864 * @value: (out) (transfer full): return location for the style property value.
866 * Gets a style property from @props for the given state. When done with @value,
867 * g_value_unset() needs to be called to free any allocated memory.
869 * Returns: %TRUE if the property exists in @props, %FALSE otherwise
874 gtk_style_properties_get_property (GtkStyleProperties *props,
875 const gchar *property,
879 const GtkStyleProperty *node;
882 g_return_val_if_fail (GTK_IS_STYLE_PROPERTIES (props), FALSE);
883 g_return_val_if_fail (property != NULL, FALSE);
884 g_return_val_if_fail (value != NULL, FALSE);
886 val = _gtk_style_properties_peek_property (props, property, state, &node);
891 g_value_init (value, node->pspec->value_type);
894 g_value_copy (val, value);
895 else if (_gtk_style_property_is_shorthand (node))
896 _gtk_style_property_pack (node, props, state, value);
898 lookup_default_value (node, value);
904 * gtk_style_properties_get_valist:
905 * @props: a #GtkStyleProperties
906 * @state: state to retrieve the property values for
907 * @args: va_list of property name/return location pairs, followed by %NULL
909 * Retrieves several style property values from @props for a given state.
914 gtk_style_properties_get_valist (GtkStyleProperties *props,
918 const gchar *property_name;
920 g_return_if_fail (GTK_IS_STYLE_PROPERTIES (props));
922 property_name = va_arg (args, const gchar *);
924 while (property_name)
926 const GtkStyleProperty *node;
930 val = _gtk_style_properties_peek_property (props, property_name, state, &node);
936 G_VALUE_LCOPY (val, args, 0, &error);
938 else if (_gtk_style_property_is_shorthand (node))
940 GValue packed = { 0 };
942 g_value_init (&packed, node->pspec->value_type);
943 _gtk_style_property_pack (node, props, state, &packed);
944 G_VALUE_LCOPY (&packed, args, 0, &error);
945 g_value_unset (&packed);
949 GValue default_value = { 0 };
951 g_value_init (&default_value, node->pspec->value_type);
952 lookup_default_value (node, &default_value);
953 G_VALUE_LCOPY (&default_value, args, 0, &error);
954 g_value_unset (&default_value);
959 g_warning ("Could not get style property \"%s\": %s", property_name, error);
964 property_name = va_arg (args, const gchar *);
969 * gtk_style_properties_get:
970 * @props: a #GtkStyleProperties
971 * @state: state to retrieve the property values for
972 * @...: property name /return value pairs, followed by %NULL
974 * Retrieves several style property values from @props for a
980 gtk_style_properties_get (GtkStyleProperties *props,
986 g_return_if_fail (GTK_IS_STYLE_PROPERTIES (props));
988 va_start (args, state);
989 gtk_style_properties_get_valist (props, state, args);
994 * gtk_style_properties_unset_property:
995 * @props: a #GtkStyleProperties
996 * @property: property to unset
997 * @state: state to unset
999 * Unsets a style property in @props.
1004 gtk_style_properties_unset_property (GtkStyleProperties *props,
1005 const gchar *property,
1006 GtkStateFlags state)
1008 GtkStylePropertiesPrivate *priv;
1009 const GtkStyleProperty *node;
1013 g_return_if_fail (GTK_IS_STYLE_PROPERTIES (props));
1014 g_return_if_fail (property != NULL);
1016 node = _gtk_style_property_lookup (property);
1020 g_warning ("Style property \"%s\" is not registered", property);
1025 prop = g_hash_table_lookup (priv->properties, node);
1030 if (property_data_find_position (prop, state, &pos))
1034 data = &g_array_index (prop->values, ValueData, pos);
1036 if (G_IS_VALUE (&data->value))
1037 g_value_unset (&data->value);
1039 g_array_remove_index (prop->values, pos);
1044 * gtk_style_properties_clear:
1045 * @props: a #GtkStyleProperties
1047 * Clears all style information from @props.
1050 gtk_style_properties_clear (GtkStyleProperties *props)
1052 GtkStylePropertiesPrivate *priv;
1054 g_return_if_fail (GTK_IS_STYLE_PROPERTIES (props));
1057 g_hash_table_remove_all (priv->properties);
1061 * gtk_style_properties_merge:
1062 * @props: a #GtkStyleProperties
1063 * @props_to_merge: a second #GtkStyleProperties
1064 * @replace: whether to replace values or not
1066 * Merges into @props all the style information contained
1067 * in @props_to_merge. If @replace is %TRUE, the values
1068 * will be overwritten, if it is %FALSE, the older values
1074 gtk_style_properties_merge (GtkStyleProperties *props,
1075 const GtkStyleProperties *props_to_merge,
1078 GtkStylePropertiesPrivate *priv, *priv_to_merge;
1079 GHashTableIter iter;
1080 gpointer key, value;
1082 g_return_if_fail (GTK_IS_STYLE_PROPERTIES (props));
1083 g_return_if_fail (GTK_IS_STYLE_PROPERTIES (props_to_merge));
1086 priv_to_merge = props_to_merge->priv;
1088 /* Merge symbolic color map */
1089 if (priv_to_merge->color_map)
1091 g_hash_table_iter_init (&iter, priv_to_merge->color_map);
1093 while (g_hash_table_iter_next (&iter, &key, &value))
1096 GtkSymbolicColor *color;
1102 g_hash_table_lookup (priv->color_map, name))
1105 gtk_style_properties_map_color (props, name, color);
1109 /* Merge symbolic style properties */
1110 g_hash_table_iter_init (&iter, priv_to_merge->properties);
1112 while (g_hash_table_iter_next (&iter, &key, &value))
1114 PropertyData *prop_to_merge = value;
1118 prop = g_hash_table_lookup (priv->properties, key);
1122 prop = property_data_new ();
1123 g_hash_table_insert (priv->properties, key, prop);
1126 for (i = 0; i < prop_to_merge->values->len; i++)
1131 data = &g_array_index (prop_to_merge->values, ValueData, i);
1133 if (replace && data->state == GTK_STATE_FLAG_NORMAL &&
1134 G_VALUE_TYPE (&data->value) != PANGO_TYPE_FONT_DESCRIPTION)
1136 /* Let normal state override all states
1137 * previously set in the original set
1139 property_data_remove_values (prop);
1142 value = property_data_get_value (prop, data->state);
1144 if (G_VALUE_TYPE (&data->value) == PANGO_TYPE_FONT_DESCRIPTION &&
1147 PangoFontDescription *font_desc;
1148 PangoFontDescription *font_desc_to_merge;
1150 /* Handle merging of font descriptions */
1151 font_desc = g_value_get_boxed (value);
1152 font_desc_to_merge = g_value_get_boxed (&data->value);
1154 pango_font_description_merge (font_desc, font_desc_to_merge, replace);
1156 else if (G_VALUE_TYPE (&data->value) == G_TYPE_PTR_ARRAY &&
1159 GPtrArray *array, *array_to_merge;
1162 /* Append the array, mainly thought
1163 * for the gtk-key-bindings property
1165 array = g_value_get_boxed (value);
1166 array_to_merge = g_value_get_boxed (&data->value);
1168 for (i = 0; i < array_to_merge->len; i++)
1169 g_ptr_array_add (array, g_ptr_array_index (array_to_merge, i));
1171 else if (replace || !G_IS_VALUE (value))
1173 if (!G_IS_VALUE (value))
1174 g_value_init (value, G_VALUE_TYPE (&data->value));
1175 else if (G_VALUE_TYPE (value) != G_VALUE_TYPE (&data->value))
1177 g_value_unset (value);
1178 g_value_init (value, G_VALUE_TYPE (&data->value));
1181 g_value_copy (&data->value, value);