]> Pileus Git - ~andy/gtk/blob - gtk/gtkcsscustomproperty.c
9da425fe7ae7f4a9199e13b1706f9be7a8360071
[~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_query (GtkStyleProperty   *property,
88                                GValue             *value,
89                                GtkStyleQueryFunc   query_func,
90                                gpointer            query_data)
91 {
92   GtkCssStyleProperty *style = GTK_CSS_STYLE_PROPERTY (property);
93   GtkCssValue *css_value;
94   
95   css_value = (* query_func) (_gtk_css_style_property_get_id (style), query_data);
96   if (css_value == NULL)
97     css_value =_gtk_css_style_property_get_initial_value (style);
98
99   _gtk_css_value_init_gvalue (css_value, value);
100   g_assert (GTK_CSS_CUSTOM_PROPERTY (property)->pspec->value_type == G_VALUE_TYPE (value));
101 }
102
103 static void
104 _gtk_css_custom_property_class_init (GtkCssCustomPropertyClass *klass)
105 {
106   GtkStylePropertyClass *property_class = GTK_STYLE_PROPERTY_CLASS (klass);
107
108   property_class->parse_value = gtk_css_custom_property_parse_value;
109   property_class->query = gtk_css_custom_property_query;
110 }
111
112 static GtkCssValue *
113 gtk_css_custom_property_compute_value (GtkCssStyleProperty *property,
114                                        GtkStyleContext     *context,
115                                        GtkCssValue         *specified)
116 {
117   GtkCssCustomProperty *custom = GTK_CSS_CUSTOM_PROPERTY (property);
118
119   return _gtk_css_style_compute_value (context, custom->pspec->value_type, specified);
120 }
121
122 static void
123 _gtk_css_custom_property_init (GtkCssCustomProperty *custom)
124 {
125   GtkCssStyleProperty *style = GTK_CSS_STYLE_PROPERTY (custom);
126
127   style->compute_value = gtk_css_custom_property_compute_value;
128 }
129
130 static GtkCssValue *
131 gtk_css_custom_property_create_initial_value (GParamSpec *pspec)
132 {
133   GValue value = G_VALUE_INIT;
134   GtkCssValue *result;
135
136   g_value_init (&value, pspec->value_type);
137
138   if (pspec->value_type == GTK_TYPE_THEMING_ENGINE)
139     g_value_set_object (&value, gtk_theming_engine_load (NULL));
140   else if (pspec->value_type == PANGO_TYPE_FONT_DESCRIPTION)
141     g_value_take_boxed (&value, pango_font_description_from_string ("Sans 10"));
142   else if (pspec->value_type == GDK_TYPE_RGBA)
143     {
144       GdkRGBA color;
145       gdk_rgba_parse (&color, "pink");
146       g_value_set_boxed (&value, &color);
147     }
148   else if (pspec->value_type == GDK_TYPE_COLOR)
149     {
150       GdkColor color;
151       gdk_color_parse ("pink", &color);
152       g_value_set_boxed (&value, &color);
153     }
154   else if (pspec->value_type == GTK_TYPE_BORDER)
155     {
156       g_value_take_boxed (&value, gtk_border_new ());
157     }
158   else
159     g_param_value_set_default (pspec, &value);
160
161   result = _gtk_css_value_new_from_gvalue (&value);
162   g_value_unset (&value);
163
164   return result;
165 }
166
167 /* Property registration functions */
168
169 /**
170  * gtk_theming_engine_register_property: (skip)
171  * @name_space: namespace for the property name
172  * @parse_func: parsing function to use, or %NULL
173  * @pspec: the #GParamSpec for the new property
174  *
175  * Registers a property so it can be used in the CSS file format,
176  * on the CSS file the property will look like
177  * "-${@name_space}-${property_name}". being
178  * ${property_name} the given to @pspec. @name_space will usually
179  * be the theme engine name.
180  *
181  * For any type a @parse_func may be provided, being this function
182  * used for turning any property value (between ':' and ';') in
183  * CSS to the #GValue needed. For basic types there is already
184  * builtin parsing support, so %NULL may be provided for these
185  * cases.
186  *
187  * <note>
188  * Engines must ensure property registration happens exactly once,
189  * usually GTK+ deals with theming engines as singletons, so this
190  * should be guaranteed to happen once, but bear this in mind
191  * when creating #GtkThemeEngine<!-- -->s yourself.
192  * </note>
193  *
194  * <note>
195  * In order to make use of the custom registered properties in
196  * the CSS file, make sure the engine is loaded first by specifying
197  * the engine property, either in a previous rule or within the same
198  * one.
199  * <programlisting>
200  * &ast; {
201  *     engine: someengine;
202  *     -SomeEngine-custom-property: 2;
203  * }
204  * </programlisting>
205  * </note>
206  *
207  * Since: 3.0
208  **/
209 void
210 gtk_theming_engine_register_property (const gchar            *name_space,
211                                       GtkStylePropertyParser  parse_func,
212                                       GParamSpec             *pspec)
213 {
214   GtkCssCustomProperty *node;
215   GtkCssValue *initial;
216   gchar *name;
217
218   g_return_if_fail (name_space != NULL);
219   g_return_if_fail (strchr (name_space, ' ') == NULL);
220   g_return_if_fail (G_IS_PARAM_SPEC (pspec));
221
222   name = g_strdup_printf ("-%s-%s", name_space, pspec->name);
223
224   /* This also initializes the default properties */
225   if (_gtk_style_property_lookup (pspec->name))
226     {
227       g_warning ("a property with name '%s' already exists", name);
228       g_free (name);
229       return;
230     }
231   
232   initial = gtk_css_custom_property_create_initial_value (pspec);
233
234   node = g_object_new (GTK_TYPE_CSS_CUSTOM_PROPERTY,
235                        "initial-value", initial,
236                        "name", name,
237                        "value-type", pspec->value_type,
238                        NULL);
239   node->pspec = pspec;
240   node->property_parse_func = parse_func;
241
242   _gtk_css_value_unref (initial);
243   g_free (name);
244 }
245
246 /**
247  * gtk_style_properties_register_property: (skip)
248  * @parse_func: parsing function to use, or %NULL
249  * @pspec: the #GParamSpec for the new property
250  *
251  * Registers a property so it can be used in the CSS file format.
252  * This function is the low-level equivalent of
253  * gtk_theming_engine_register_property(), if you are implementing
254  * a theming engine, you want to use that function instead.
255  *
256  * Since: 3.0
257  **/
258 void
259 gtk_style_properties_register_property (GtkStylePropertyParser  parse_func,
260                                         GParamSpec             *pspec)
261 {
262   GtkCssCustomProperty *node;
263   GtkCssValue *initial;
264
265   g_return_if_fail (G_IS_PARAM_SPEC (pspec));
266
267   /* This also initializes the default properties */
268   if (_gtk_style_property_lookup (pspec->name))
269     {
270       g_warning ("a property with name '%s' already exists", pspec->name);
271       return;
272     }
273   
274   initial = gtk_css_custom_property_create_initial_value (pspec);
275
276   node = g_object_new (GTK_TYPE_CSS_CUSTOM_PROPERTY,
277                        "initial-value", initial,
278                        "name", pspec->name,
279                        "value-type", pspec->value_type,
280                        NULL);
281   node->pspec = pspec;
282   node->property_parse_func = parse_func;
283
284   _gtk_css_value_unref (initial);
285 }
286
287 /**
288  * gtk_style_properties_lookup_property: (skip)
289  * @property_name: property name to look up
290  * @parse_func: (out): return location for the parse function
291  * @pspec: (out) (transfer none): return location for the #GParamSpec
292  *
293  * Returns %TRUE if a property has been registered, if @pspec or
294  * @parse_func are not %NULL, the #GParamSpec and parsing function
295  * will be respectively returned.
296  *
297  * Returns: %TRUE if the property is registered, %FALSE otherwise
298  *
299  * Since: 3.0
300  **/
301 gboolean
302 gtk_style_properties_lookup_property (const gchar             *property_name,
303                                       GtkStylePropertyParser  *parse_func,
304                                       GParamSpec             **pspec)
305 {
306   GtkStyleProperty *node;
307   gboolean found = FALSE;
308
309   g_return_val_if_fail (property_name != NULL, FALSE);
310
311   node = _gtk_style_property_lookup (property_name);
312
313   if (GTK_IS_CSS_CUSTOM_PROPERTY (node))
314     {
315       GtkCssCustomProperty *custom = GTK_CSS_CUSTOM_PROPERTY (node);
316
317       if (pspec)
318         *pspec = custom->pspec;
319
320       if (parse_func)
321         *parse_func = custom->property_parse_func;
322
323       found = TRUE;
324     }
325
326   return found;
327 }
328