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