]> Pileus Git - ~andy/gtk/blob - gtk/gtkcssstylepropertyimpl.c
styleproperty: Change order for property registration
[~andy/gtk] / gtk / gtkcssstylepropertyimpl.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 2010 Carlos Garnacho <carlosg@gnome.org>
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 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
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 #include "config.h"
21
22 #include "gtkstylepropertyprivate.h"
23
24 #include <gobject/gvaluecollector.h>
25 #include <gdk-pixbuf/gdk-pixbuf.h>
26 #include <cairo-gobject.h>
27
28 #include "gtkcssparserprivate.h"
29 #include "gtkcssstylefuncsprivate.h"
30 #include "gtkcssstylepropertyprivate.h"
31 #include "gtkcsstypesprivate.h"
32 #include "gtkintl.h"
33 #include "gtkprivatetypebuiltins.h"
34 #include "gtkstylepropertiesprivate.h"
35
36 /* the actual parsers we have */
37 #include "gtkanimationdescription.h"
38 #include "gtkbindings.h"
39 #include "gtkcssimageprivate.h"
40 #include "gtkgradient.h"
41 #include "gtkshadowprivate.h"
42 #include "gtkthemingengine.h"
43 #include "gtktypebuiltins.h"
44 #include "gtkwin32themeprivate.h"
45
46 /*** REGISTRATION ***/
47
48 static void
49 _gtk_style_property_register (const char *                   name,
50                               GType                          value_type,
51                               GtkStylePropertyFlags          flags,
52                               GtkCssStylePropertyParseFunc   parse_value,
53                               GtkCssStylePropertyPrintFunc   print_value,
54                               GtkCssStylePropertyComputeFunc compute_value,
55                               const GValue *                 initial_value)
56 {
57   GtkCssStyleProperty *node;
58
59   node = g_object_new (GTK_TYPE_CSS_STYLE_PROPERTY,
60                        "inherit", (flags & GTK_STYLE_PROPERTY_INHERIT) ? TRUE : FALSE,
61                        "initial-value", initial_value,
62                        "name", name,
63                        "value-type", value_type,
64                        NULL);
65
66   if (parse_value)
67     node->parse_value = parse_value;
68   if (print_value)
69     node->print_value = print_value;
70   if (compute_value)
71     node->compute_value = compute_value;
72 }
73
74 static void
75 gtk_style_property_register (const char *                   name,
76                              GType                          value_type,
77                              GtkStylePropertyFlags          flags,
78                              GtkCssStylePropertyParseFunc   parse_value,
79                              GtkCssStylePropertyPrintFunc   print_value,
80                              GtkCssStylePropertyComputeFunc compute_value,
81                              ...)
82 {
83   GValue initial_value = G_VALUE_INIT;
84   char *error = NULL;
85   va_list args;
86
87   va_start (args, compute_value);
88   G_VALUE_COLLECT_INIT (&initial_value, value_type,
89                         args, 0, &error);
90   if (error)
91     {
92       g_error ("property `%s' initial value is broken: %s", name, error);
93       g_value_unset (&initial_value);
94       return;
95     }
96
97   va_end (args);
98
99   _gtk_style_property_register (name,
100                                 value_type,
101                                 flags,
102                                 parse_value,
103                                 print_value,
104                                 compute_value,
105                                 &initial_value);
106
107   g_value_unset (&initial_value);
108 }
109
110 /*** HELPERS ***/
111
112 static void
113 string_append_double (GString *string,
114                       double   d)
115 {
116   char buf[G_ASCII_DTOSTR_BUF_SIZE];
117
118   g_ascii_dtostr (buf, sizeof (buf), d);
119   g_string_append (string, buf);
120 }
121
122 static void
123 string_append_string (GString    *str,
124                       const char *string)
125 {
126   gsize len;
127
128   g_string_append_c (str, '"');
129
130   do {
131     len = strcspn (string, "\"\n\r\f");
132     g_string_append (str, string);
133     string += len;
134     switch (*string)
135       {
136       case '\0':
137         break;
138       case '\n':
139         g_string_append (str, "\\A ");
140         break;
141       case '\r':
142         g_string_append (str, "\\D ");
143         break;
144       case '\f':
145         g_string_append (str, "\\C ");
146         break;
147       case '\"':
148         g_string_append (str, "\\\"");
149         break;
150       default:
151         g_assert_not_reached ();
152         break;
153       }
154   } while (*string);
155
156   g_string_append_c (str, '"');
157 }
158
159 /*** IMPLEMENTATIONS ***/
160
161 static gboolean
162 font_family_parse (GtkCssStyleProperty *property,
163                    GValue              *value,
164                    GtkCssParser        *parser,
165                    GFile               *base)
166 {
167   GPtrArray *names;
168   char *name;
169
170   /* We don't special case generic families. Pango should do
171    * that for us */
172
173   names = g_ptr_array_new ();
174
175   do {
176     name = _gtk_css_parser_try_ident (parser, TRUE);
177     if (name)
178       {
179         GString *string = g_string_new (name);
180         g_free (name);
181         while ((name = _gtk_css_parser_try_ident (parser, TRUE)))
182           {
183             g_string_append_c (string, ' ');
184             g_string_append (string, name);
185             g_free (name);
186           }
187         name = g_string_free (string, FALSE);
188       }
189     else 
190       {
191         name = _gtk_css_parser_read_string (parser);
192         if (name == NULL)
193           {
194             g_ptr_array_free (names, TRUE);
195             return FALSE;
196           }
197       }
198
199     g_ptr_array_add (names, name);
200   } while (_gtk_css_parser_try (parser, ",", TRUE));
201
202   /* NULL-terminate array */
203   g_ptr_array_add (names, NULL);
204   g_value_set_boxed (value, g_ptr_array_free (names, FALSE));
205   return TRUE;
206 }
207
208 static void
209 font_family_value_print (GtkCssStyleProperty *property,
210                          const GValue        *value,
211                          GString             *string)
212 {
213   const char **names = g_value_get_boxed (value);
214
215   if (names == NULL || *names == NULL)
216     {
217       g_string_append (string, "none");
218       return;
219     }
220
221   string_append_string (string, *names);
222   names++;
223   while (*names)
224     {
225       g_string_append (string, ", ");
226       string_append_string (string, *names);
227       names++;
228     }
229 }
230
231 static gboolean 
232 bindings_value_parse (GtkCssStyleProperty *property,
233                       GValue              *value,
234                       GtkCssParser        *parser,
235                       GFile               *base)
236 {
237   GPtrArray *array;
238   GtkBindingSet *binding_set;
239   char *name;
240
241   array = g_ptr_array_new ();
242
243   do {
244       name = _gtk_css_parser_try_ident (parser, TRUE);
245       if (name == NULL)
246         {
247           _gtk_css_parser_error (parser, "Not a valid binding name");
248           g_ptr_array_free (array, TRUE);
249           return FALSE;
250         }
251
252       binding_set = gtk_binding_set_find (name);
253
254       if (!binding_set)
255         {
256           _gtk_css_parser_error (parser, "No binding set named '%s'", name);
257           g_free (name);
258           continue;
259         }
260
261       g_ptr_array_add (array, binding_set);
262       g_free (name);
263     }
264   while (_gtk_css_parser_try (parser, ",", TRUE));
265
266   g_value_take_boxed (value, array);
267
268   return TRUE;
269 }
270
271 static void
272 bindings_value_print (GtkCssStyleProperty *property,
273                       const GValue        *value,
274                       GString             *string)
275 {
276   GPtrArray *array;
277   guint i;
278
279   array = g_value_get_boxed (value);
280
281   for (i = 0; i < array->len; i++)
282     {
283       GtkBindingSet *binding_set = g_ptr_array_index (array, i);
284
285       if (i > 0)
286         g_string_append (string, ", ");
287       g_string_append (string, binding_set->set_name);
288     }
289 }
290
291 static gboolean 
292 border_corner_radius_value_parse (GtkCssStyleProperty *property,
293                                   GValue              *value,
294                                   GtkCssParser        *parser,
295                                   GFile               *base)
296 {
297   GtkCssBorderCornerRadius corner;
298
299   if (!_gtk_css_parser_try_double (parser, &corner.horizontal))
300     {
301       _gtk_css_parser_error (parser, "Expected a number");
302       return FALSE;
303     }
304   else if (corner.horizontal < 0)
305     goto negative;
306
307   if (!_gtk_css_parser_try_double (parser, &corner.vertical))
308     corner.vertical = corner.horizontal;
309   else if (corner.vertical < 0)
310     goto negative;
311
312   g_value_set_boxed (value, &corner);
313   return TRUE;
314
315 negative:
316   _gtk_css_parser_error (parser, "Border radius values cannot be negative");
317   return FALSE;
318 }
319
320 static void
321 border_corner_radius_value_print (GtkCssStyleProperty *property,
322                                   const GValue        *value,
323                                   GString             *string)
324 {
325   GtkCssBorderCornerRadius *corner;
326
327   corner = g_value_get_boxed (value);
328
329   if (corner == NULL)
330     {
331       g_string_append (string, "none");
332       return;
333     }
334
335   string_append_double (string, corner->horizontal);
336   if (corner->horizontal != corner->vertical)
337     {
338       g_string_append_c (string, ' ');
339       string_append_double (string, corner->vertical);
340     }
341 }
342
343 static gboolean 
344 css_image_value_parse (GtkCssStyleProperty *property,
345                        GValue              *value,
346                        GtkCssParser        *parser,
347                        GFile               *base)
348 {
349   GtkCssImage *image;
350
351   if (_gtk_css_parser_try (parser, "none", TRUE))
352     image = NULL;
353   else
354     {
355       image = _gtk_css_image_new_parse (parser, base);
356       if (image == NULL)
357         return FALSE;
358     }
359
360   g_value_unset (value);
361   g_value_init (value, GTK_TYPE_CSS_IMAGE);
362   g_value_take_object (value, image);
363   return TRUE;
364 }
365
366 static void
367 css_image_value_print (GtkCssStyleProperty *property,
368                        const GValue        *value,
369                        GString             *string)
370 {
371   GtkCssImage *image = g_value_get_object (value);
372
373   if (image)
374     _gtk_css_image_print (image, string);
375   else
376     g_string_append (string, "none");
377 }
378
379 static void
380 css_image_value_compute (GtkCssStyleProperty    *property,
381                          GValue                 *computed,
382                          GtkStyleContext        *context,
383                          const GValue           *specified)
384 {
385   GtkCssImage *image = g_value_get_object (specified);
386
387   if (image)
388     image = _gtk_css_image_compute (image, context);
389
390   g_value_init (computed, GTK_TYPE_CSS_IMAGE);
391   g_value_take_object (computed, image);
392 }
393
394 /*** REGISTRATION ***/
395
396 #define rgba_init(rgba, r, g, b, a) G_STMT_START{ \
397   (rgba)->red = (r); \
398   (rgba)->green = (g); \
399   (rgba)->blue = (b); \
400   (rgba)->alpha = (a); \
401 }G_STMT_END
402 void
403 _gtk_css_style_property_init_properties (void)
404 {
405   GValue value = { 0, };
406   char *default_font_family[] = { "Sans", NULL };
407   GdkRGBA rgba;
408   GtkCssBorderCornerRadius no_corner_radius = { 0, };
409   GtkBorder border_of_ones = { 1, 1, 1, 1 };
410   GtkCssBackgroundRepeat background_repeat = { GTK_CSS_BACKGROUND_REPEAT_STYLE_REPEAT };
411   GtkCssBorderImageRepeat border_image_repeat = { GTK_CSS_REPEAT_STYLE_STRETCH, GTK_CSS_REPEAT_STYLE_STRETCH };
412
413   /* Initialize "color" and "font-size" first,
414    * so that when computing values later they are
415    * done first. That way, 'currentColor' and font
416    * sizes in em can be looked up properly */
417   rgba_init (&rgba, 1, 1, 1, 1);
418   gtk_style_property_register            ("color",
419                                           GDK_TYPE_RGBA,
420                                           GTK_STYLE_PROPERTY_INHERIT,
421                                           NULL,
422                                           NULL,
423                                           NULL,
424                                           &rgba);
425   gtk_style_property_register            ("font-size",
426                                           G_TYPE_DOUBLE,
427                                           GTK_STYLE_PROPERTY_INHERIT,
428                                           NULL,
429                                           NULL,
430                                           NULL,
431                                           10.0);
432
433   /* properties that aren't referenced when computing values
434    * start here */
435   rgba_init (&rgba, 0, 0, 0, 0);
436   gtk_style_property_register            ("background-color",
437                                           GDK_TYPE_RGBA,
438                                           0,
439                                           NULL,
440                                           NULL,
441                                           NULL,
442                                           &rgba);
443
444   gtk_style_property_register            ("font-family",
445                                           G_TYPE_STRV,
446                                           GTK_STYLE_PROPERTY_INHERIT,
447                                           font_family_parse,
448                                           font_family_value_print,
449                                           NULL,
450                                           default_font_family);
451   gtk_style_property_register            ("font-style",
452                                           PANGO_TYPE_STYLE,
453                                           GTK_STYLE_PROPERTY_INHERIT,
454                                           NULL,
455                                           NULL,
456                                           NULL,
457                                           PANGO_STYLE_NORMAL);
458   gtk_style_property_register            ("font-variant",
459                                           PANGO_TYPE_VARIANT,
460                                           GTK_STYLE_PROPERTY_INHERIT,
461                                           NULL,
462                                           NULL,
463                                           NULL,
464                                           PANGO_VARIANT_NORMAL);
465   /* xxx: need to parse this properly, ie parse the numbers */
466   gtk_style_property_register            ("font-weight",
467                                           PANGO_TYPE_WEIGHT,
468                                           GTK_STYLE_PROPERTY_INHERIT,
469                                           NULL,
470                                           NULL,
471                                           NULL,
472                                           PANGO_WEIGHT_NORMAL);
473
474   gtk_style_property_register            ("text-shadow",
475                                           GTK_TYPE_SHADOW,
476                                           GTK_STYLE_PROPERTY_INHERIT,
477                                           NULL,
478                                           NULL,
479                                           NULL,
480                                           NULL);
481
482   gtk_style_property_register            ("icon-shadow",
483                                           GTK_TYPE_SHADOW,
484                                           GTK_STYLE_PROPERTY_INHERIT,
485                                           NULL,
486                                           NULL,
487                                           NULL,
488                                           NULL);
489
490   gtk_style_property_register            ("box-shadow",
491                                           GTK_TYPE_SHADOW,
492                                           0,
493                                           NULL,
494                                           NULL,
495                                           NULL,
496                                           NULL);
497
498   gtk_style_property_register            ("margin-top",
499                                           G_TYPE_INT,
500                                           0,
501                                           NULL,
502                                           NULL,
503                                           NULL,
504                                           0);
505   gtk_style_property_register            ("margin-left",
506                                           G_TYPE_INT,
507                                           0,
508                                           NULL,
509                                           NULL,
510                                           NULL,
511                                           0);
512   gtk_style_property_register            ("margin-bottom",
513                                           G_TYPE_INT,
514                                           0,
515                                           NULL,
516                                           NULL,
517                                           NULL,
518                                           0);
519   gtk_style_property_register            ("margin-right",
520                                           G_TYPE_INT,
521                                           0,
522                                           NULL,
523                                           NULL,
524                                           NULL,
525                                           0);
526   gtk_style_property_register            ("padding-top",
527                                           G_TYPE_INT,
528                                           0,
529                                           NULL,
530                                           NULL,
531                                           NULL,
532                                           0);
533   gtk_style_property_register            ("padding-left",
534                                           G_TYPE_INT,
535                                           0,
536                                           NULL,
537                                           NULL,
538                                           NULL,
539                                           0);
540   gtk_style_property_register            ("padding-bottom",
541                                           G_TYPE_INT,
542                                           0,
543                                           NULL,
544                                           NULL,
545                                           NULL,
546                                           0);
547   gtk_style_property_register            ("padding-right",
548                                           G_TYPE_INT,
549                                           0,
550                                           NULL,
551                                           NULL,
552                                           NULL,
553                                           0);
554   gtk_style_property_register            ("border-top-width",
555                                           G_TYPE_INT,
556                                           0,
557                                           NULL,
558                                           NULL,
559                                           NULL,
560                                           0);
561   gtk_style_property_register            ("border-left-width",
562                                           G_TYPE_INT,
563                                           0,
564                                           NULL,
565                                           NULL,
566                                           NULL,
567                                           0);
568   gtk_style_property_register            ("border-bottom-width",
569                                           G_TYPE_INT,
570                                           0,
571                                           NULL,
572                                           NULL,
573                                           NULL,
574                                           0);
575   gtk_style_property_register            ("border-right-width",
576                                           G_TYPE_INT,
577                                           0,
578                                           NULL,
579                                           NULL,
580                                           NULL,
581                                           0);
582
583   gtk_style_property_register            ("border-top-left-radius",
584                                           GTK_TYPE_CSS_BORDER_CORNER_RADIUS,
585                                           0,
586                                           border_corner_radius_value_parse,
587                                           border_corner_radius_value_print,
588                                           NULL,
589                                           &no_corner_radius);
590   gtk_style_property_register            ("border-top-right-radius",
591                                           GTK_TYPE_CSS_BORDER_CORNER_RADIUS,
592                                           0,
593                                           border_corner_radius_value_parse,
594                                           border_corner_radius_value_print,
595                                           NULL,
596                                           &no_corner_radius);
597   gtk_style_property_register            ("border-bottom-right-radius",
598                                           GTK_TYPE_CSS_BORDER_CORNER_RADIUS,
599                                           0,
600                                           border_corner_radius_value_parse,
601                                           border_corner_radius_value_print,
602                                           NULL,
603                                           &no_corner_radius);
604   gtk_style_property_register            ("border-bottom-left-radius",
605                                           GTK_TYPE_CSS_BORDER_CORNER_RADIUS,
606                                           0,
607                                           border_corner_radius_value_parse,
608                                           border_corner_radius_value_print,
609                                           NULL,
610                                           &no_corner_radius);
611
612   gtk_style_property_register            ("border-style",
613                                           GTK_TYPE_BORDER_STYLE,
614                                           0,
615                                           NULL,
616                                           NULL,
617                                           NULL,
618                                           GTK_BORDER_STYLE_NONE);
619   gtk_style_property_register            ("background-clip",
620                                           GTK_TYPE_CSS_AREA,
621                                           0,
622                                           NULL,
623                                           NULL,
624                                           NULL,
625                                           GTK_CSS_AREA_BORDER_BOX);
626                                         
627   gtk_style_property_register            ("background-origin",
628                                           GTK_TYPE_CSS_AREA,
629                                           0,
630                                           NULL,
631                                           NULL,
632                                           NULL,
633                                           GTK_CSS_AREA_PADDING_BOX);
634
635   g_value_init (&value, GTK_TYPE_CSS_SPECIAL_VALUE);
636   g_value_set_enum (&value, GTK_CSS_CURRENT_COLOR);
637   _gtk_style_property_register           ("border-top-color",
638                                           GDK_TYPE_RGBA,
639                                           0,
640                                           NULL,
641                                           NULL,
642                                           NULL,
643                                           &value);
644   _gtk_style_property_register           ("border-right-color",
645                                           GDK_TYPE_RGBA,
646                                           0,
647                                           NULL,
648                                           NULL,
649                                           NULL,
650                                           &value);
651   _gtk_style_property_register           ("border-bottom-color",
652                                           GDK_TYPE_RGBA,
653                                           0,
654                                           NULL,
655                                           NULL,
656                                           NULL,
657                                           &value);
658   _gtk_style_property_register           ("border-left-color",
659                                           GDK_TYPE_RGBA,
660                                           0,
661                                           NULL,
662                                           NULL,
663                                           NULL,
664                                           &value);
665   g_value_unset (&value);
666
667   gtk_style_property_register            ("background-repeat",
668                                           GTK_TYPE_CSS_BACKGROUND_REPEAT,
669                                           0,
670                                           NULL,
671                                           NULL,
672                                           NULL,
673                                           &background_repeat);
674   g_value_init (&value, GTK_TYPE_CSS_IMAGE);
675   _gtk_style_property_register           ("background-image",
676                                           CAIRO_GOBJECT_TYPE_PATTERN,
677                                           0,
678                                           css_image_value_parse,
679                                           css_image_value_print,
680                                           css_image_value_compute,
681                                           &value);
682
683   _gtk_style_property_register           ("border-image-source",
684                                           CAIRO_GOBJECT_TYPE_PATTERN,
685                                           0,
686                                           css_image_value_parse,
687                                           css_image_value_print,
688                                           css_image_value_compute,
689                                           &value);
690   g_value_unset (&value);
691   gtk_style_property_register            ("border-image-repeat",
692                                           GTK_TYPE_CSS_BORDER_IMAGE_REPEAT,
693                                           0,
694                                           NULL,
695                                           NULL,
696                                           NULL,
697                                           &border_image_repeat);
698
699   /* XXX: The initial vaue is wrong, it should be 100% */
700   gtk_style_property_register            ("border-image-slice",
701                                           GTK_TYPE_BORDER,
702                                           0,
703                                           NULL,
704                                           NULL,
705                                           NULL,
706                                           &border_of_ones);
707   gtk_style_property_register            ("border-image-width",
708                                           GTK_TYPE_BORDER,
709                                           0,
710                                           NULL,
711                                           NULL,
712                                           NULL,
713                                           NULL);
714   gtk_style_property_register            ("engine",
715                                           GTK_TYPE_THEMING_ENGINE,
716                                           0,
717                                           NULL,
718                                           NULL,
719                                           NULL,
720                                           gtk_theming_engine_load (NULL));
721   gtk_style_property_register            ("transition",
722                                           GTK_TYPE_ANIMATION_DESCRIPTION,
723                                           0,
724                                           NULL,
725                                           NULL,
726                                           NULL,
727                                           NULL);
728
729   /* Private property holding the binding sets */
730   gtk_style_property_register            ("gtk-key-bindings",
731                                           G_TYPE_PTR_ARRAY,
732                                           0,
733                                           bindings_value_parse,
734                                           bindings_value_print,
735                                           NULL,
736                                           NULL);
737 }
738