]> Pileus Git - ~andy/gtk/blob - gtk/gtkcssstyleproperty.c
css: Add _gtk_css_style_property_affects_font
[~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 "gtkcssenumvalueprivate.h"
25 #include "gtkcssinheritvalueprivate.h"
26 #include "gtkcssinitialvalueprivate.h"
27 #include "gtkcssstylefuncsprivate.h"
28 #include "gtkcsstypesprivate.h"
29 #include "gtkintl.h"
30 #include "gtkprivatetypebuiltins.h"
31 #include "gtkstylepropertiesprivate.h"
32
33 /* this is in case round() is not provided by the compiler, 
34  * such as in the case of C89 compilers, like MSVC
35  */
36 #include "fallback-c89.c"
37
38 enum {
39   PROP_0,
40   PROP_ANIMATED,
41   PROP_AFFECTS_SIZE,
42   PROP_AFFECTS_FONT,
43   PROP_ID,
44   PROP_INHERIT,
45   PROP_INITIAL
46 };
47
48 G_DEFINE_TYPE (GtkCssStyleProperty, _gtk_css_style_property, GTK_TYPE_STYLE_PROPERTY)
49
50 static GtkBitmask *_properties_affecting_size = NULL;
51 static GtkBitmask *_properties_affecting_font = NULL;
52
53 static void
54 gtk_css_style_property_constructed (GObject *object)
55 {
56   GtkCssStyleProperty *property = GTK_CSS_STYLE_PROPERTY (object);
57   GtkCssStylePropertyClass *klass = GTK_CSS_STYLE_PROPERTY_GET_CLASS (property);
58
59   property->id = klass->style_properties->len;
60   g_ptr_array_add (klass->style_properties, property);
61
62   if (property->affects_size)
63     _properties_affecting_size = _gtk_bitmask_set (_properties_affecting_size, property->id, TRUE);
64
65   if (property->affects_font)
66     _properties_affecting_font = _gtk_bitmask_set (_properties_affecting_font, property->id, TRUE);
67
68   G_OBJECT_CLASS (_gtk_css_style_property_parent_class)->constructed (object);
69 }
70
71 static void
72 gtk_css_style_property_set_property (GObject      *object,
73                                      guint         prop_id,
74                                      const GValue *value,
75                                      GParamSpec   *pspec)
76 {
77   GtkCssStyleProperty *property = GTK_CSS_STYLE_PROPERTY (object);
78
79   switch (prop_id)
80     {
81     case PROP_ANIMATED:
82       property->animated = g_value_get_boolean (value);
83       break;
84     case PROP_AFFECTS_SIZE:
85       property->affects_size = g_value_get_boolean (value);
86       break;
87     case PROP_AFFECTS_FONT:
88       property->affects_font = g_value_get_boolean (value);
89       break;
90     case PROP_INHERIT:
91       property->inherit = g_value_get_boolean (value);
92       break;
93     case PROP_INITIAL:
94       property->initial_value = g_value_dup_boxed (value);
95       g_assert (property->initial_value != NULL);
96       break;
97     default:
98       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
99       break;
100     }
101 }
102
103 static void
104 gtk_css_style_property_get_property (GObject    *object,
105                                      guint       prop_id,
106                                      GValue     *value,
107                                      GParamSpec *pspec)
108 {
109   GtkCssStyleProperty *property = GTK_CSS_STYLE_PROPERTY (object);
110
111   switch (prop_id)
112     {
113     case PROP_ANIMATED:
114       g_value_set_boolean (value, property->animated);
115       break;
116     case PROP_AFFECTS_SIZE:
117       g_value_set_boolean (value, property->affects_size);
118       break;
119     case PROP_AFFECTS_FONT:
120       g_value_set_boolean (value, property->affects_font);
121       break;
122     case PROP_ID:
123       g_value_set_boolean (value, property->id);
124       break;
125     case PROP_INHERIT:
126       g_value_set_boolean (value, property->inherit);
127       break;
128     case PROP_INITIAL:
129       g_value_set_boxed (value, property->initial_value);
130       break;
131     default:
132       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
133       break;
134     }
135 }
136
137 static void
138 _gtk_css_style_property_assign (GtkStyleProperty   *property,
139                                 GtkStyleProperties *props,
140                                 GtkStateFlags       state,
141                                 const GValue       *value)
142 {
143   GtkCssStyleProperty *style;
144   GtkCssValue *css_value;
145   
146   style = GTK_CSS_STYLE_PROPERTY (property);
147   css_value = style->assign_value (style, value);
148
149   _gtk_style_properties_set_property_by_property (props,
150                                                   style,
151                                                   state,
152                                                   css_value);
153   _gtk_css_value_unref (css_value);
154 }
155
156 static gboolean
157 _gtk_css_style_property_query_special_case (GtkCssStyleProperty *property,
158                                             GValue              *value,
159                                             GtkStyleQueryFunc    query_func,
160                                             gpointer             query_data)
161 {
162   GtkBorderStyle border_style;
163
164   switch (property->id)
165     {
166       case GTK_CSS_PROPERTY_BORDER_TOP_WIDTH:
167         border_style = _gtk_css_border_style_value_get (query_func (GTK_CSS_PROPERTY_BORDER_TOP_STYLE, query_data));
168         if (border_style == GTK_BORDER_STYLE_NONE || border_style == GTK_BORDER_STYLE_HIDDEN)
169           {
170             g_value_init (value, G_TYPE_INT);
171             return TRUE;
172           }
173         break;
174       case GTK_CSS_PROPERTY_BORDER_RIGHT_WIDTH:
175         border_style = _gtk_css_border_style_value_get (query_func (GTK_CSS_PROPERTY_BORDER_RIGHT_STYLE, query_data));
176         if (border_style == GTK_BORDER_STYLE_NONE || border_style == GTK_BORDER_STYLE_HIDDEN)
177           {
178             g_value_init (value, G_TYPE_INT);
179             return TRUE;
180           }
181         break;
182       case GTK_CSS_PROPERTY_BORDER_BOTTOM_WIDTH:
183         border_style = _gtk_css_border_style_value_get (query_func (GTK_CSS_PROPERTY_BORDER_BOTTOM_STYLE, query_data));
184         if (border_style == GTK_BORDER_STYLE_NONE || border_style == GTK_BORDER_STYLE_HIDDEN)
185           {
186             g_value_init (value, G_TYPE_INT);
187             return TRUE;
188           }
189         break;
190       case GTK_CSS_PROPERTY_BORDER_LEFT_WIDTH:
191         border_style = _gtk_css_border_style_value_get (query_func (GTK_CSS_PROPERTY_BORDER_LEFT_STYLE, query_data));
192         if (border_style == GTK_BORDER_STYLE_NONE || border_style == GTK_BORDER_STYLE_HIDDEN)
193           {
194             g_value_init (value, G_TYPE_INT);
195             return TRUE;
196           }
197         break;
198       case GTK_CSS_PROPERTY_OUTLINE_WIDTH:
199         border_style = _gtk_css_border_style_value_get (query_func (GTK_CSS_PROPERTY_OUTLINE_STYLE, query_data));
200         if (border_style == GTK_BORDER_STYLE_NONE || border_style == GTK_BORDER_STYLE_HIDDEN)
201           {
202             g_value_init (value, G_TYPE_INT);
203             return TRUE;
204           }
205         break;
206       default:
207         break;
208     }
209
210   return FALSE;
211 }
212
213 static void
214 _gtk_css_style_property_query (GtkStyleProperty   *property,
215                                GValue             *value,
216                                GtkStyleQueryFunc   query_func,
217                                gpointer            query_data)
218 {
219   GtkCssStyleProperty *style_property = GTK_CSS_STYLE_PROPERTY (property);
220   GtkCssValue *css_value;
221   
222   /* I don't like this special case being here in this generic code path, but no idea where else to put it. */
223   if (_gtk_css_style_property_query_special_case (style_property, value, query_func, query_data))
224     return;
225
226   css_value = (* query_func) (GTK_CSS_STYLE_PROPERTY (property)->id, query_data);
227   if (css_value == NULL)
228     css_value =_gtk_css_style_property_get_initial_value (style_property);
229
230   style_property->query_value (style_property, css_value, value);
231 }
232
233 static GtkCssValue *
234 gtk_css_style_property_parse_value (GtkStyleProperty *property,
235                                     GtkCssParser     *parser)
236 {
237   GtkCssStyleProperty *style_property = GTK_CSS_STYLE_PROPERTY (property);
238
239   if (_gtk_css_parser_try (parser, "initial", TRUE))
240     {
241       /* the initial value can be explicitly specified with the
242        * ‘initial’ keyword which all properties accept.
243        */
244       return _gtk_css_initial_value_new ();
245     }
246   else if (_gtk_css_parser_try (parser, "inherit", TRUE))
247     {
248       /* All properties accept the ‘inherit’ value which
249        * explicitly specifies that the value will be determined
250        * by inheritance. The ‘inherit’ value can be used to
251        * strengthen inherited values in the cascade, and it can
252        * also be used on properties that are not normally inherited.
253        */
254       return _gtk_css_inherit_value_new ();
255     }
256
257   return (* style_property->parse_value) (style_property, parser);
258 }
259
260 static void
261 _gtk_css_style_property_class_init (GtkCssStylePropertyClass *klass)
262 {
263   GObjectClass *object_class = G_OBJECT_CLASS (klass);
264   GtkStylePropertyClass *property_class = GTK_STYLE_PROPERTY_CLASS (klass);
265
266   object_class->constructed = gtk_css_style_property_constructed;
267   object_class->set_property = gtk_css_style_property_set_property;
268   object_class->get_property = gtk_css_style_property_get_property;
269
270   g_object_class_install_property (object_class,
271                                    PROP_ANIMATED,
272                                    g_param_spec_boolean ("animated",
273                                                          P_("Animated"),
274                                                          P_("Set if the value can be animated"),
275                                                          FALSE,
276                                                          G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
277   g_object_class_install_property (object_class,
278                                    PROP_AFFECTS_SIZE,
279                                    g_param_spec_boolean ("affects-size",
280                                                          P_("Affects size"),
281                                                          P_("Set if the value affects the sizing of elements"),
282                                                          TRUE,
283                                                          G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
284   g_object_class_install_property (object_class,
285                                    PROP_AFFECTS_FONT,
286                                    g_param_spec_boolean ("affects-font",
287                                                          P_("Affects font"),
288                                                          P_("Set if the value affects the font"),
289                                                          FALSE,
290                                                          G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
291   g_object_class_install_property (object_class,
292                                    PROP_ID,
293                                    g_param_spec_uint ("id",
294                                                       P_("ID"),
295                                                       P_("The numeric id for quick access"),
296                                                       0, G_MAXUINT, 0,
297                                                       G_PARAM_READABLE));
298   g_object_class_install_property (object_class,
299                                    PROP_INHERIT,
300                                    g_param_spec_boolean ("inherit",
301                                                          P_("Inherit"),
302                                                          P_("Set if the value is inherited by default"),
303                                                          FALSE,
304                                                          G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
305   g_object_class_install_property (object_class,
306                                    PROP_INITIAL,
307                                    g_param_spec_boxed ("initial-value",
308                                                        P_("Initial value"),
309                                                        P_("The initial specified value used for this property"),
310                                                        GTK_TYPE_CSS_VALUE,
311                                                        G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
312
313   property_class->assign = _gtk_css_style_property_assign;
314   property_class->query = _gtk_css_style_property_query;
315   property_class->parse_value = gtk_css_style_property_parse_value;
316
317   klass->style_properties = g_ptr_array_new ();
318
319   _properties_affecting_size = _gtk_bitmask_new ();
320   _properties_affecting_font = _gtk_bitmask_new ();
321 }
322
323 static GtkCssValue *
324 gtk_css_style_property_real_parse_value (GtkCssStyleProperty *property,
325                                          GtkCssParser        *parser)
326 {
327   g_assert_not_reached ();
328   return NULL;
329 }
330
331 static void
332 _gtk_css_style_property_init (GtkCssStyleProperty *property)
333 {
334   property->parse_value = gtk_css_style_property_real_parse_value;
335 }
336
337 /**
338  * _gtk_css_style_property_get_n_properties:
339  *
340  * Gets the number of style properties. This number can increase when new
341  * theme engines are loaded. Shorthand properties are not included here.
342  *
343  * Returns: The number of style properties.
344  **/
345 guint
346 _gtk_css_style_property_get_n_properties (void)
347 {
348   GtkCssStylePropertyClass *klass;
349
350   klass = g_type_class_peek (GTK_TYPE_CSS_STYLE_PROPERTY);
351   if (G_UNLIKELY (klass == NULL))
352     {
353       _gtk_style_property_init_properties ();
354       klass = g_type_class_peek (GTK_TYPE_CSS_STYLE_PROPERTY);
355       g_assert (klass);
356     }
357
358   return klass->style_properties->len;
359 }
360
361 /**
362  * _gtk_css_style_property_lookup_by_id:
363  * @id: the id of the property
364  *
365  * Gets the style property with the given id. All style properties (but not
366  * shorthand properties) are indexable by id so that it's easy to use arrays
367  * when doing style lookups.
368  *
369  * Returns: (transfer none): The style property with the given id
370  **/
371 GtkCssStyleProperty *
372 _gtk_css_style_property_lookup_by_id (guint id)
373 {
374   GtkCssStylePropertyClass *klass;
375
376   klass = g_type_class_peek (GTK_TYPE_CSS_STYLE_PROPERTY);
377   if (G_UNLIKELY (klass == NULL))
378     {
379       _gtk_style_property_init_properties ();
380       klass = g_type_class_peek (GTK_TYPE_CSS_STYLE_PROPERTY);
381       g_assert (klass);
382     }
383   g_return_val_if_fail (id < klass->style_properties->len, NULL);
384
385   return g_ptr_array_index (klass->style_properties, id);
386 }
387
388 /**
389  * _gtk_css_style_property_is_inherit:
390  * @property: the property
391  *
392  * Queries if the given @property is inherited. See
393  * <ulink url="http://www.w3.org/TR/css3-cascade/#inheritance>
394  * the CSS documentation</ulink> for an explanation of this concept.
395  *
396  * Returns: %TRUE if the property is inherited by default.
397  **/
398 gboolean
399 _gtk_css_style_property_is_inherit (GtkCssStyleProperty *property)
400 {
401   g_return_val_if_fail (GTK_IS_CSS_STYLE_PROPERTY (property), FALSE);
402
403   return property->inherit;
404 }
405
406 /**
407  * _gtk_css_style_property_is_animated:
408  * @property: the property
409  *
410  * Queries if the given @property can be is animated. See
411  * <ulink url="http://www.w3.org/TR/css3-transitions/#animatable-css>
412  * the CSS documentation</ulink> for animatable properties.
413  *
414  * Returns: %TRUE if the property can be animated.
415  **/
416 gboolean
417 _gtk_css_style_property_is_animated (GtkCssStyleProperty *property)
418 {
419   g_return_val_if_fail (GTK_IS_CSS_STYLE_PROPERTY (property), FALSE);
420
421   return property->animated;
422 }
423
424 /**
425  * _gtk_css_style_property_affects_size:
426  * @property: the property
427  *
428  * Queries if the given @property affects the size of elements. This is
429  * used for optimizations inside GTK, where a gtk_widget_queue_resize()
430  * can be avoided if the property does not affect size.
431  *
432  * Returns: %TRUE if the property affects sizing of elements.
433  **/
434 gboolean
435 _gtk_css_style_property_affects_size (GtkCssStyleProperty *property)
436 {
437   g_return_val_if_fail (GTK_IS_CSS_STYLE_PROPERTY (property), FALSE);
438
439   return property->affects_size;
440 }
441
442 /**
443  * _gtk_css_style_property_affects_font:
444  * @property: the property
445  *
446  * Queries if the given @property affects the default font. This is
447  * used for optimizations inside GTK, where clearing pango
448  * layouts can be avoided if the font doesn't change.
449  *
450  * Returns: %TRUE if the property affects the font.
451  **/
452 gboolean
453 _gtk_css_style_property_affects_font (GtkCssStyleProperty *property)
454 {
455   g_return_val_if_fail (GTK_IS_CSS_STYLE_PROPERTY (property), FALSE);
456
457   return property->affects_font;
458 }
459
460 /**
461  * _gtk_css_style_property_get_id:
462  * @property: the property
463  *
464  * Gets the id for the given property. IDs are used to allow using arrays
465  * for style lookups.
466  *
467  * Returns: The id of the property
468  **/
469 guint
470 _gtk_css_style_property_get_id (GtkCssStyleProperty *property)
471 {
472   g_return_val_if_fail (GTK_IS_CSS_STYLE_PROPERTY (property), 0);
473
474   return property->id;
475 }
476
477 /**
478  * _gtk_css_style_property_get_initial_value:
479  * @property: the property
480  *
481  * Queries the initial value of the given @property. See
482  * <ulink url="http://www.w3.org/TR/css3-cascade/#intial>
483  * the CSS documentation</ulink> for an explanation of this concept.
484  *
485  * Returns: a reference to the initial value. The value will never change.
486  **/
487 GtkCssValue *
488 _gtk_css_style_property_get_initial_value (GtkCssStyleProperty *property)
489 {
490   g_return_val_if_fail (GTK_IS_CSS_STYLE_PROPERTY (property), NULL);
491
492   return property->initial_value;
493 }
494
495 gboolean
496 _gtk_css_style_property_changes_affect_size (const GtkBitmask *changes)
497 {
498   return _gtk_bitmask_intersects (changes, _properties_affecting_size);
499 }
500
501 gboolean
502 _gtk_css_style_property_changes_affect_font (const GtkBitmask *changes)
503 {
504   return _gtk_bitmask_intersects (changes, _properties_affecting_font);
505 }