]> Pileus Git - ~andy/gtk/blob - gtk/gtkcssstyleproperty.c
cssstyleproperty: Make query func a vfunc
[~andy/gtk] / gtk / gtkcssstyleproperty.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 "gtkcssstylepropertyprivate.h"
23
24 #include "gtkcssinheritvalueprivate.h"
25 #include "gtkcssinitialvalueprivate.h"
26 #include "gtkcssstylefuncsprivate.h"
27 #include "gtkcsstypesprivate.h"
28 #include "gtkintl.h"
29 #include "gtkprivatetypebuiltins.h"
30 #include "gtkstylepropertiesprivate.h"
31
32 /* this is in case round() is not provided by the compiler, 
33  * such as in the case of C89 compilers, like MSVC
34  */
35 #include "fallback-c89.c"
36
37 enum {
38   PROP_0,
39   PROP_ID,
40   PROP_INHERIT,
41   PROP_INITIAL
42 };
43
44 G_DEFINE_TYPE (GtkCssStyleProperty, _gtk_css_style_property, GTK_TYPE_STYLE_PROPERTY)
45
46 static void
47 gtk_css_style_property_constructed (GObject *object)
48 {
49   GtkCssStyleProperty *property = GTK_CSS_STYLE_PROPERTY (object);
50   GtkCssStylePropertyClass *klass = GTK_CSS_STYLE_PROPERTY_GET_CLASS (property);
51
52   property->id = klass->style_properties->len;
53   g_ptr_array_add (klass->style_properties, property);
54
55   G_OBJECT_CLASS (_gtk_css_style_property_parent_class)->constructed (object);
56 }
57
58 static void
59 gtk_css_style_property_set_property (GObject      *object,
60                                      guint         prop_id,
61                                      const GValue *value,
62                                      GParamSpec   *pspec)
63 {
64   GtkCssStyleProperty *property = GTK_CSS_STYLE_PROPERTY (object);
65
66   switch (prop_id)
67     {
68     case PROP_INHERIT:
69       property->inherit = g_value_get_boolean (value);
70       break;
71     case PROP_INITIAL:
72       property->initial_value = g_value_dup_boxed (value);
73       g_assert (property->initial_value != NULL);
74       break;
75     default:
76       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
77       break;
78     }
79 }
80
81 static void
82 gtk_css_style_property_get_property (GObject    *object,
83                                      guint       prop_id,
84                                      GValue     *value,
85                                      GParamSpec *pspec)
86 {
87   GtkCssStyleProperty *property = GTK_CSS_STYLE_PROPERTY (object);
88
89   switch (prop_id)
90     {
91     case PROP_ID:
92       g_value_set_boolean (value, property->id);
93       break;
94     case PROP_INHERIT:
95       g_value_set_boolean (value, property->inherit);
96       break;
97     case PROP_INITIAL:
98       g_value_set_boxed (value, property->initial_value);
99       break;
100     default:
101       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
102       break;
103     }
104 }
105
106 static void
107 _gtk_css_style_property_assign (GtkStyleProperty   *property,
108                                 GtkStyleProperties *props,
109                                 GtkStateFlags       state,
110                                 const GValue       *value)
111 {
112   GtkCssValue *css_value = _gtk_css_value_new_from_gvalue (value);
113   _gtk_style_properties_set_property_by_property (props,
114                                                   GTK_CSS_STYLE_PROPERTY (property),
115                                                   state,
116                                                   css_value);
117   _gtk_css_value_unref (css_value);
118 }
119
120 static void
121 _gtk_css_style_property_query (GtkStyleProperty   *property,
122                                GValue             *value,
123                                GtkStyleQueryFunc   query_func,
124                                gpointer            query_data)
125 {
126   GtkCssStyleProperty *style_property = GTK_CSS_STYLE_PROPERTY (property);
127   GtkCssValue *css_value;
128   
129   css_value = (* query_func) (GTK_CSS_STYLE_PROPERTY (property)->id, query_data);
130   if (css_value == NULL)
131     css_value =_gtk_css_style_property_get_initial_value (style_property);
132
133   style_property->query_value (style_property, css_value, value);
134 }
135
136 static GtkCssValue *
137 gtk_css_style_property_parse_value (GtkStyleProperty *property,
138                                     GtkCssParser     *parser,
139                                     GFile            *base)
140 {
141   GtkCssStyleProperty *style_property = GTK_CSS_STYLE_PROPERTY (property);
142
143   if (_gtk_css_parser_try (parser, "initial", TRUE))
144     {
145       /* the initial value can be explicitly specified with the
146        * ‘initial’ keyword which all properties accept.
147        */
148       return _gtk_css_initial_value_new ();
149     }
150   else if (_gtk_css_parser_try (parser, "inherit", TRUE))
151     {
152       /* All properties accept the ‘inherit’ value which
153        * explicitly specifies that the value will be determined
154        * by inheritance. The ‘inherit’ value can be used to
155        * strengthen inherited values in the cascade, and it can
156        * also be used on properties that are not normally inherited.
157        */
158       return _gtk_css_inherit_value_new ();
159     }
160
161   return (* style_property->parse_value) (style_property, parser, base);
162 }
163
164 static void
165 _gtk_css_style_property_class_init (GtkCssStylePropertyClass *klass)
166 {
167   GObjectClass *object_class = G_OBJECT_CLASS (klass);
168   GtkStylePropertyClass *property_class = GTK_STYLE_PROPERTY_CLASS (klass);
169
170   object_class->constructed = gtk_css_style_property_constructed;
171   object_class->set_property = gtk_css_style_property_set_property;
172   object_class->get_property = gtk_css_style_property_get_property;
173
174   g_object_class_install_property (object_class,
175                                    PROP_ID,
176                                    g_param_spec_uint ("id",
177                                                       P_("ID"),
178                                                       P_("The numeric id for quick access"),
179                                                       0, G_MAXUINT, 0,
180                                                       G_PARAM_READABLE));
181   g_object_class_install_property (object_class,
182                                    PROP_INHERIT,
183                                    g_param_spec_boolean ("inherit",
184                                                          P_("Inherit"),
185                                                          P_("Set if the value is inherited by default"),
186                                                          FALSE,
187                                                          G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
188   g_object_class_install_property (object_class,
189                                    PROP_INITIAL,
190                                    g_param_spec_boxed ("initial-value",
191                                                        P_("Initial value"),
192                                                        P_("The initial specified value used for this property"),
193                                                        GTK_TYPE_CSS_VALUE,
194                                                        G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
195
196   property_class->assign = _gtk_css_style_property_assign;
197   property_class->query = _gtk_css_style_property_query;
198   property_class->parse_value = gtk_css_style_property_parse_value;
199
200   klass->style_properties = g_ptr_array_new ();
201 }
202
203 static GtkCssValue *
204 gtk_css_style_property_real_parse_value (GtkCssStyleProperty *property,
205                                          GtkCssParser        *parser,
206                                          GFile               *base)
207 {
208   g_assert_not_reached ();
209   return NULL;
210 }
211
212 static void
213 gtk_css_style_property_real_print_value (GtkCssStyleProperty *property,
214                                          const GtkCssValue   *value,
215                                          GString             *string)
216 {
217   _gtk_css_value_print (value, string);
218 }
219
220 static GtkCssValue *
221 gtk_css_style_property_real_compute_value (GtkCssStyleProperty *property,
222                                            GtkStyleContext     *context,
223                                            GtkCssValue         *specified)
224 {
225   return _gtk_css_value_ref (specified);
226 }
227
228 static gboolean
229 gtk_css_style_property_real_equal (GtkCssStyleProperty *property,
230                                    GtkCssValue         *value1,
231                                    GtkCssValue         *value2)
232 {
233   return _gtk_css_value_equal (value1, value2);
234 }
235
236 static void
237 _gtk_css_style_property_init (GtkCssStyleProperty *property)
238 {
239   property->parse_value = gtk_css_style_property_real_parse_value;
240   property->print_value = gtk_css_style_property_real_print_value;
241   property->compute_value = gtk_css_style_property_real_compute_value;
242   property->equal_func = gtk_css_style_property_real_equal;
243 }
244
245 /**
246  * _gtk_css_style_property_get_n_properties:
247  *
248  * Gets the number of style properties. This number can increase when new
249  * theme engines are loaded. Shorthand properties are not included here.
250  *
251  * Returns: The number of style properties.
252  **/
253 guint
254 _gtk_css_style_property_get_n_properties (void)
255 {
256   GtkCssStylePropertyClass *klass;
257
258   klass = g_type_class_peek (GTK_TYPE_CSS_STYLE_PROPERTY);
259   if (G_UNLIKELY (klass == NULL))
260     {
261       _gtk_style_property_init_properties ();
262       klass = g_type_class_peek (GTK_TYPE_CSS_STYLE_PROPERTY);
263       g_assert (klass);
264     }
265
266   return klass->style_properties->len;
267 }
268
269 /**
270  * _gtk_css_style_property_lookup_by_id:
271  * @id: the id of the property
272  *
273  * Gets the style property with the given id. All style properties (but not
274  * shorthand properties) are indexable by id so that it's easy to use arrays
275  * when doing style lookups.
276  *
277  * Returns: (transfer none): The style property with the given id
278  **/
279 GtkCssStyleProperty *
280 _gtk_css_style_property_lookup_by_id (guint id)
281 {
282   GtkCssStylePropertyClass *klass;
283
284   klass = g_type_class_peek (GTK_TYPE_CSS_STYLE_PROPERTY);
285   if (G_UNLIKELY (klass == NULL))
286     {
287       _gtk_style_property_init_properties ();
288       klass = g_type_class_peek (GTK_TYPE_CSS_STYLE_PROPERTY);
289       g_assert (klass);
290     }
291   g_return_val_if_fail (id < klass->style_properties->len, NULL);
292
293   return g_ptr_array_index (klass->style_properties, id);
294 }
295
296 /**
297  * _gtk_css_style_property_is_inherit:
298  * @property: the property
299  *
300  * Queries if the given @property is inherited. See
301  * <ulink url="http://www.w3.org/TR/css3-cascade/#inheritance>
302  * the CSS documentation</ulink> for an explanation of this concept.
303  *
304  * Returns: %TRUE if the property is inherited by default.
305  **/
306 gboolean
307 _gtk_css_style_property_is_inherit (GtkCssStyleProperty *property)
308 {
309   g_return_val_if_fail (GTK_IS_CSS_STYLE_PROPERTY (property), 0);
310
311   return property->inherit;
312 }
313
314 /**
315  * _gtk_css_style_property_get_id:
316  * @property: the property
317  *
318  * Gets the id for the given property. IDs are used to allow using arrays
319  * for style lookups.
320  *
321  * Returns: The id of the property
322  **/
323 guint
324 _gtk_css_style_property_get_id (GtkCssStyleProperty *property)
325 {
326   g_return_val_if_fail (GTK_IS_CSS_STYLE_PROPERTY (property), 0);
327
328   return property->id;
329 }
330
331 /**
332  * _gtk_css_style_property_get_initial_value:
333  * @property: the property
334  *
335  * Queries the initial value of the given @property. See
336  * <ulink url="http://www.w3.org/TR/css3-cascade/#intial>
337  * the CSS documentation</ulink> for an explanation of this concept.
338  *
339  * Returns: a reference to the initial value. The value will never change.
340  **/
341 GtkCssValue *
342 _gtk_css_style_property_get_initial_value (GtkCssStyleProperty *property)
343 {
344   g_return_val_if_fail (GTK_IS_CSS_STYLE_PROPERTY (property), NULL);
345
346   return property->initial_value;
347 }
348
349 /**
350  * _gtk_css_style_property_compute_value:
351  * @property: the property
352  * @computed: (out): an uninitialized value to be filled with the result
353  * @context: the context to use for resolving
354  * @specified: the value to compute from
355  *
356  * Converts the @specified value into the @computed value using the
357  * information in @context. This step is explained in detail in
358  * <ulink url="http://www.w3.org/TR/css3-cascade/#computed>
359  * the CSS documentation</ulink>.
360  **/
361 GtkCssValue *
362 _gtk_css_style_property_compute_value (GtkCssStyleProperty *property,
363                                        GtkStyleContext     *context,
364                                        GtkCssValue         *specified)
365 {
366   g_return_val_if_fail (GTK_IS_CSS_STYLE_PROPERTY (property), NULL);
367   g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), NULL);
368
369   return property->compute_value (property, context, specified);
370 }
371
372 /**
373  * _gtk_css_style_property_print_value:
374  * @property: the property
375  * @value: the value to print
376  * @string: the string to print to
377  *
378  * Prints @value to the given @string in CSS format. The @value must be a
379  * valid specified value as parsed using the parse functions or as assigned
380  * via _gtk_style_property_assign().
381  **/
382 void
383 _gtk_css_style_property_print_value (GtkCssStyleProperty    *property,
384                                      GtkCssValue            *value,
385                                      GString                *string)
386 {
387   g_return_if_fail (GTK_IS_CSS_STYLE_PROPERTY (property));
388   g_return_if_fail (value != NULL);
389   g_return_if_fail (string != NULL);
390
391   if (_gtk_css_value_is_inherit (value) ||
392       _gtk_css_value_is_initial (value))
393     _gtk_css_value_print (value, string);
394   else
395     property->print_value (property, value, string);
396 }
397
398 /**
399  * _gtk_css_style_property_is_equal:
400  * @property: the property
401  * @value1: the first value to compare
402  * @value2: the second value to compare
403  *
404  * Compares @value1 and @value2 for equality. Both values must be the
405  * result of a call _gtk_css_style_property_compute_value().
406  *
407  * Returns: %TRUE if @value1 and @value2 are equal
408  **/
409 gboolean
410 _gtk_css_style_property_is_equal (GtkCssStyleProperty *property,
411                                   GtkCssValue         *value1,
412                                   GtkCssValue         *value2)
413 {
414   g_return_val_if_fail (GTK_IS_CSS_STYLE_PROPERTY (property), FALSE);
415   g_return_val_if_fail (value1 != NULL, FALSE);
416   g_return_val_if_fail (value2 != NULL, FALSE);
417
418   return property->equal_func (property, value1, value2);
419 }