]> Pileus Git - ~andy/gtk/blob - gtk/gtkcsscustomproperty.c
css: Ensure proper type for parsing custom properties
[~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, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17  *
18  * Authors: Benjamin Otte <otte@gnome.org>
19  */
20
21 #include "config.h"
22
23 #include "gtkcsscustompropertyprivate.h"
24
25 #include <string.h>
26
27 #include "gtkcssstylefuncsprivate.h"
28 #include "gtkthemingengine.h"
29
30 G_DEFINE_TYPE (GtkCssCustomProperty, _gtk_css_custom_property, GTK_TYPE_CSS_STYLE_PROPERTY)
31
32 static gboolean
33 gtk_css_custom_property_parse_value (GtkStyleProperty *property,
34                                      GValue           *value,
35                                      GtkCssParser     *parser,
36                                      GFile            *base)
37 {
38   GtkCssCustomProperty *custom = GTK_CSS_CUSTOM_PROPERTY (property);
39   gboolean success;
40
41   if (custom->property_parse_func)
42     {
43       GError *error = NULL;
44       char *value_str;
45       
46       g_value_init (value, _gtk_style_property_get_value_type (property));
47
48       value_str = _gtk_css_parser_read_value (parser);
49       if (value_str != NULL)
50         {
51           success = (* custom->property_parse_func) (value_str, value, &error);
52           g_free (value_str);
53         }
54       else
55         success = FALSE;
56     }
57   else
58     {
59       GtkCssStyleProperty *style = GTK_CSS_STYLE_PROPERTY (property);
60       g_value_init (value, _gtk_css_style_property_get_specified_type (style));
61
62       success = _gtk_css_style_parse_value (value, parser, base);
63     }
64
65   if (!success)
66     g_value_unset (value);
67
68   return success;
69 }
70
71 static void
72 _gtk_css_custom_property_class_init (GtkCssCustomPropertyClass *klass)
73 {
74   GtkStylePropertyClass *property_class = GTK_STYLE_PROPERTY_CLASS (klass);
75
76   property_class->parse_value = gtk_css_custom_property_parse_value;
77 }
78
79
80 static void
81 _gtk_css_custom_property_init (GtkCssCustomProperty *custom_property)
82 {
83 }
84
85 static GType
86 gtk_css_custom_property_get_specified_type (GParamSpec *pspec)
87 {
88   if (pspec->value_type == GDK_TYPE_RGBA ||
89       pspec->value_type == GDK_TYPE_COLOR)
90     return GTK_TYPE_SYMBOLIC_COLOR;
91   else
92     return pspec->value_type;
93 }
94
95 static void
96 gtk_css_custom_property_create_initial_value (GParamSpec *pspec,
97                                               GValue     *value)
98 {
99   g_value_init (value, gtk_css_custom_property_get_specified_type (pspec));
100
101   if (pspec->value_type == GTK_TYPE_THEMING_ENGINE)
102     g_value_set_object (value, gtk_theming_engine_load (NULL));
103   else if (pspec->value_type == PANGO_TYPE_FONT_DESCRIPTION)
104     g_value_take_boxed (value, pango_font_description_from_string ("Sans 10"));
105   else if (pspec->value_type == GDK_TYPE_RGBA ||
106            pspec->value_type == GDK_TYPE_COLOR)
107     {
108       GdkRGBA color;
109       gdk_rgba_parse (&color, "pink");
110       g_value_take_boxed (value, gtk_symbolic_color_new_literal (&color));
111     }
112   else if (pspec->value_type == GTK_TYPE_BORDER)
113     {
114       g_value_take_boxed (value, gtk_border_new ());
115     }
116   else
117     g_param_value_set_default (pspec, value);
118 }
119
120 /* Property registration functions */
121
122 /**
123  * gtk_theming_engine_register_property: (skip)
124  * @name_space: namespace for the property name
125  * @parse_func: parsing function to use, or %NULL
126  * @pspec: the #GParamSpec for the new property
127  *
128  * Registers a property so it can be used in the CSS file format,
129  * on the CSS file the property will look like
130  * "-${@name_space}-${property_name}". being
131  * ${property_name} the given to @pspec. @name_space will usually
132  * be the theme engine name.
133  *
134  * For any type a @parse_func may be provided, being this function
135  * used for turning any property value (between ':' and ';') in
136  * CSS to the #GValue needed. For basic types there is already
137  * builtin parsing support, so %NULL may be provided for these
138  * cases.
139  *
140  * <note>
141  * Engines must ensure property registration happens exactly once,
142  * usually GTK+ deals with theming engines as singletons, so this
143  * should be guaranteed to happen once, but bear this in mind
144  * when creating #GtkThemeEngine<!-- -->s yourself.
145  * </note>
146  *
147  * <note>
148  * In order to make use of the custom registered properties in
149  * the CSS file, make sure the engine is loaded first by specifying
150  * the engine property, either in a previous rule or within the same
151  * one.
152  * <programlisting>
153  * &ast; {
154  *     engine: someengine;
155  *     -SomeEngine-custom-property: 2;
156  * }
157  * </programlisting>
158  * </note>
159  *
160  * Since: 3.0
161  **/
162 void
163 gtk_theming_engine_register_property (const gchar            *name_space,
164                                       GtkStylePropertyParser  parse_func,
165                                       GParamSpec             *pspec)
166 {
167   GtkCssCustomProperty *node;
168   GValue initial = { 0, };
169   gchar *name;
170
171   g_return_if_fail (name_space != NULL);
172   g_return_if_fail (strchr (name_space, ' ') == NULL);
173   g_return_if_fail (G_IS_PARAM_SPEC (pspec));
174
175   name = g_strdup_printf ("-%s-%s", name_space, pspec->name);
176   gtk_css_custom_property_create_initial_value (pspec, &initial);
177
178   node = g_object_new (GTK_TYPE_CSS_CUSTOM_PROPERTY,
179                        "initial-value", &initial,
180                        "name", name,
181                        "computed-type", pspec->value_type,
182                        "value-type", pspec->value_type,
183                        NULL);
184   node->pspec = pspec;
185   node->property_parse_func = parse_func;
186
187   g_value_unset (&initial);
188   g_free (name);
189 }
190
191 /**
192  * gtk_style_properties_register_property: (skip)
193  * @parse_func: parsing function to use, or %NULL
194  * @pspec: the #GParamSpec for the new property
195  *
196  * Registers a property so it can be used in the CSS file format.
197  * This function is the low-level equivalent of
198  * gtk_theming_engine_register_property(), if you are implementing
199  * a theming engine, you want to use that function instead.
200  *
201  * Since: 3.0
202  **/
203 void
204 gtk_style_properties_register_property (GtkStylePropertyParser  parse_func,
205                                         GParamSpec             *pspec)
206 {
207   GtkCssCustomProperty *node;
208   GValue initial = { 0, };
209
210   g_return_if_fail (G_IS_PARAM_SPEC (pspec));
211
212   gtk_css_custom_property_create_initial_value (pspec, &initial);
213
214   node = g_object_new (GTK_TYPE_CSS_CUSTOM_PROPERTY,
215                        "initial-value", &initial,
216                        "name", pspec->name,
217                        "computed-type", pspec->value_type,
218                        "value-type", pspec->value_type,
219                        NULL);
220   node->pspec = pspec;
221   node->property_parse_func = parse_func;
222
223   g_value_unset (&initial);
224 }
225
226 /**
227  * gtk_style_properties_lookup_property: (skip)
228  * @property_name: property name to look up
229  * @parse_func: (out): return location for the parse function
230  * @pspec: (out) (transfer none): return location for the #GParamSpec
231  *
232  * Returns %TRUE if a property has been registered, if @pspec or
233  * @parse_func are not %NULL, the #GParamSpec and parsing function
234  * will be respectively returned.
235  *
236  * Returns: %TRUE if the property is registered, %FALSE otherwise
237  *
238  * Since: 3.0
239  **/
240 gboolean
241 gtk_style_properties_lookup_property (const gchar             *property_name,
242                                       GtkStylePropertyParser  *parse_func,
243                                       GParamSpec             **pspec)
244 {
245   GtkStyleProperty *node;
246   gboolean found = FALSE;
247
248   g_return_val_if_fail (property_name != NULL, FALSE);
249
250   node = _gtk_style_property_lookup (property_name);
251
252   if (GTK_IS_CSS_CUSTOM_PROPERTY (node))
253     {
254       GtkCssCustomProperty *custom = GTK_CSS_CUSTOM_PROPERTY (node);
255
256       if (pspec)
257         *pspec = custom->pspec;
258
259       if (parse_func)
260         *parse_func = custom->property_parse_func;
261
262       found = TRUE;
263     }
264
265   return found;
266 }
267