]> Pileus Git - ~andy/gtk/blob - gtk/gtkcsscustomproperty.c
styleproperty: Simplify compute_value function
[~andy/gtk] / gtk / gtkcsscustomproperty.c
1 /*
2  * Copyright © 2011 Red Hat Inc.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
16  *
17  * Authors: Benjamin Otte <otte@gnome.org>
18  */
19
20 #include "config.h"
21
22 #include "gtkcsscustompropertyprivate.h"
23
24 #include <string.h>
25
26 #include "gtkcssstylefuncsprivate.h"
27 #include "gtkthemingengine.h"
28
29 G_DEFINE_TYPE (GtkCssCustomProperty, _gtk_css_custom_property, GTK_TYPE_CSS_STYLE_PROPERTY)
30
31 static GType
32 gtk_css_custom_property_get_specified_type (GParamSpec *pspec)
33 {
34   if (pspec->value_type == GDK_TYPE_RGBA ||
35       pspec->value_type == GDK_TYPE_COLOR)
36     return GTK_TYPE_SYMBOLIC_COLOR;
37   else
38     return pspec->value_type;
39 }
40
41 static GtkCssValue *
42 gtk_css_custom_property_parse_value (GtkStyleProperty *property,
43                                      GtkCssParser     *parser,
44                                      GFile            *base)
45 {
46   GtkCssCustomProperty *custom = GTK_CSS_CUSTOM_PROPERTY (property);
47   GValue value = G_VALUE_INIT;
48   GtkCssValue *result;
49   gboolean success;
50
51   if (custom->property_parse_func)
52     {
53       GError *error = NULL;
54       char *value_str;
55       
56       g_value_init (&value, _gtk_style_property_get_value_type (property));
57
58       value_str = _gtk_css_parser_read_value (parser);
59       if (value_str != NULL)
60         {
61           success = (* custom->property_parse_func) (value_str, &value, &error);
62           g_free (value_str);
63         }
64       else
65         success = FALSE;
66     }
67   else
68     {
69       g_value_init (&value, gtk_css_custom_property_get_specified_type (custom->pspec));
70
71       success = _gtk_css_style_parse_value (&value, parser, base);
72     }
73
74   if (!success)
75     {
76       g_value_unset (&value);
77       return NULL;
78     }
79
80   result = _gtk_css_value_new_from_gvalue (&value);
81   g_value_unset (&value);
82
83   return result;
84 }
85
86 static void
87 _gtk_css_custom_property_class_init (GtkCssCustomPropertyClass *klass)
88 {
89   GtkStylePropertyClass *property_class = GTK_STYLE_PROPERTY_CLASS (klass);
90
91   property_class->parse_value = gtk_css_custom_property_parse_value;
92 }
93
94 static GtkCssValue *
95 gtk_css_custom_property_compute_value (GtkCssStyleProperty *property,
96                                        GtkStyleContext     *context,
97                                        GtkCssValue         *specified)
98 {
99   GtkCssCustomProperty *custom = GTK_CSS_CUSTOM_PROPERTY (property);
100
101   return _gtk_css_style_compute_value (context, custom->pspec->value_type, specified);
102 }
103
104 static void
105 _gtk_css_custom_property_init (GtkCssCustomProperty *custom)
106 {
107   GtkCssStyleProperty *style = GTK_CSS_STYLE_PROPERTY (custom);
108
109   style->compute_value = gtk_css_custom_property_compute_value;
110 }
111
112 static GtkCssValue *
113 gtk_css_custom_property_create_initial_value (GParamSpec *pspec)
114 {
115   GValue value = G_VALUE_INIT;
116   GtkCssValue *result;
117
118   g_value_init (&value, pspec->value_type);
119
120   if (pspec->value_type == GTK_TYPE_THEMING_ENGINE)
121     g_value_set_object (&value, gtk_theming_engine_load (NULL));
122   else if (pspec->value_type == PANGO_TYPE_FONT_DESCRIPTION)
123     g_value_take_boxed (&value, pango_font_description_from_string ("Sans 10"));
124   else if (pspec->value_type == GDK_TYPE_RGBA)
125     {
126       GdkRGBA color;
127       gdk_rgba_parse (&color, "pink");
128       g_value_set_boxed (&value, &color);
129     }
130   else if (pspec->value_type == GDK_TYPE_COLOR)
131     {
132       GdkColor color;
133       gdk_color_parse ("pink", &color);
134       g_value_set_boxed (&value, &color);
135     }
136   else if (pspec->value_type == GTK_TYPE_BORDER)
137     {
138       g_value_take_boxed (&value, gtk_border_new ());
139     }
140   else
141     g_param_value_set_default (pspec, &value);
142
143   result = _gtk_css_value_new_from_gvalue (&value);
144   g_value_unset (&value);
145
146   return result;
147 }
148
149 /* Property registration functions */
150
151 /**
152  * gtk_theming_engine_register_property: (skip)
153  * @name_space: namespace for the property name
154  * @parse_func: parsing function to use, or %NULL
155  * @pspec: the #GParamSpec for the new property
156  *
157  * Registers a property so it can be used in the CSS file format,
158  * on the CSS file the property will look like
159  * "-${@name_space}-${property_name}". being
160  * ${property_name} the given to @pspec. @name_space will usually
161  * be the theme engine name.
162  *
163  * For any type a @parse_func may be provided, being this function
164  * used for turning any property value (between ':' and ';') in
165  * CSS to the #GValue needed. For basic types there is already
166  * builtin parsing support, so %NULL may be provided for these
167  * cases.
168  *
169  * <note>
170  * Engines must ensure property registration happens exactly once,
171  * usually GTK+ deals with theming engines as singletons, so this
172  * should be guaranteed to happen once, but bear this in mind
173  * when creating #GtkThemeEngine<!-- -->s yourself.
174  * </note>
175  *
176  * <note>
177  * In order to make use of the custom registered properties in
178  * the CSS file, make sure the engine is loaded first by specifying
179  * the engine property, either in a previous rule or within the same
180  * one.
181  * <programlisting>
182  * &ast; {
183  *     engine: someengine;
184  *     -SomeEngine-custom-property: 2;
185  * }
186  * </programlisting>
187  * </note>
188  *
189  * Since: 3.0
190  **/
191 void
192 gtk_theming_engine_register_property (const gchar            *name_space,
193                                       GtkStylePropertyParser  parse_func,
194                                       GParamSpec             *pspec)
195 {
196   GtkCssCustomProperty *node;
197   GtkCssValue *initial;
198   gchar *name;
199
200   g_return_if_fail (name_space != NULL);
201   g_return_if_fail (strchr (name_space, ' ') == NULL);
202   g_return_if_fail (G_IS_PARAM_SPEC (pspec));
203
204   name = g_strdup_printf ("-%s-%s", name_space, pspec->name);
205
206   /* This also initializes the default properties */
207   if (_gtk_style_property_lookup (pspec->name))
208     {
209       g_warning ("a property with name '%s' already exists", name);
210       g_free (name);
211       return;
212     }
213   
214   initial = gtk_css_custom_property_create_initial_value (pspec);
215
216   node = g_object_new (GTK_TYPE_CSS_CUSTOM_PROPERTY,
217                        "initial-value", initial,
218                        "name", name,
219                        "computed-type", pspec->value_type,
220                        "value-type", pspec->value_type,
221                        NULL);
222   node->pspec = pspec;
223   node->property_parse_func = parse_func;
224
225   _gtk_css_value_unref (initial);
226   g_free (name);
227 }
228
229 /**
230  * gtk_style_properties_register_property: (skip)
231  * @parse_func: parsing function to use, or %NULL
232  * @pspec: the #GParamSpec for the new property
233  *
234  * Registers a property so it can be used in the CSS file format.
235  * This function is the low-level equivalent of
236  * gtk_theming_engine_register_property(), if you are implementing
237  * a theming engine, you want to use that function instead.
238  *
239  * Since: 3.0
240  **/
241 void
242 gtk_style_properties_register_property (GtkStylePropertyParser  parse_func,
243                                         GParamSpec             *pspec)
244 {
245   GtkCssCustomProperty *node;
246   GtkCssValue *initial;
247
248   g_return_if_fail (G_IS_PARAM_SPEC (pspec));
249
250   /* This also initializes the default properties */
251   if (_gtk_style_property_lookup (pspec->name))
252     {
253       g_warning ("a property with name '%s' already exists", pspec->name);
254       return;
255     }
256   
257   initial = gtk_css_custom_property_create_initial_value (pspec);
258
259   node = g_object_new (GTK_TYPE_CSS_CUSTOM_PROPERTY,
260                        "initial-value", initial,
261                        "name", pspec->name,
262                        "computed-type", pspec->value_type,
263                        "value-type", pspec->value_type,
264                        NULL);
265   node->pspec = pspec;
266   node->property_parse_func = parse_func;
267
268   _gtk_css_value_unref (initial);
269 }
270
271 /**
272  * gtk_style_properties_lookup_property: (skip)
273  * @property_name: property name to look up
274  * @parse_func: (out): return location for the parse function
275  * @pspec: (out) (transfer none): return location for the #GParamSpec
276  *
277  * Returns %TRUE if a property has been registered, if @pspec or
278  * @parse_func are not %NULL, the #GParamSpec and parsing function
279  * will be respectively returned.
280  *
281  * Returns: %TRUE if the property is registered, %FALSE otherwise
282  *
283  * Since: 3.0
284  **/
285 gboolean
286 gtk_style_properties_lookup_property (const gchar             *property_name,
287                                       GtkStylePropertyParser  *parse_func,
288                                       GParamSpec             **pspec)
289 {
290   GtkStyleProperty *node;
291   gboolean found = FALSE;
292
293   g_return_val_if_fail (property_name != NULL, FALSE);
294
295   node = _gtk_style_property_lookup (property_name);
296
297   if (GTK_IS_CSS_CUSTOM_PROPERTY (node))
298     {
299       GtkCssCustomProperty *custom = GTK_CSS_CUSTOM_PROPERTY (node);
300
301       if (pspec)
302         *pspec = custom->pspec;
303
304       if (parse_func)
305         *parse_func = custom->property_parse_func;
306
307       found = TRUE;
308     }
309
310   return found;
311 }
312