]> Pileus Git - ~andy/gtk/blob - gtk/tests/stylecontext.c
cd5f30b95dbfc603415b91c064ffebedb1da0a64
[~andy/gtk] / gtk / tests / stylecontext.c
1 #include <gtk/gtk.h>
2
3 static void
4 test_parse_empty (void)
5 {
6   GtkCssProvider *provider;
7   GError *error;
8   gboolean res;
9
10   provider = gtk_css_provider_new ();
11   error = NULL;
12   res = gtk_css_provider_load_from_data (provider, "", -1, &error);
13
14   g_assert (res);
15   g_assert_no_error (error);
16   g_clear_error (&error);
17
18   g_object_unref (provider);
19 }
20
21 static void
22 test_parse_selectors (void)
23 {
24   GtkCssProvider *provider;
25   GError *error;
26   gboolean res;
27   gint i;
28   const gchar *valid[] = {
29     "* {}",
30     "E {}",
31     "E F {}",
32     "E > F {}",
33     "E#id {}",
34     "#id {}",
35     "tab:first-child {}",
36     "tab:last-child {}",
37     "tab:nth-child(first) {}",
38     "tab:nth-child(last) {}",
39     "tab:nth-child(even) {}",
40     "tab:nth-child(odd) {}",
41     "tab:sorted {}",
42     ".some-class {}",
43     ".some-class.another-class {}",
44     ".some-class .another-class {}",
45     "E * {}",
46     "E .class {}",
47     "E > .foo {}",
48     "E > #id {}",
49     "E:active {}",
50     "E:prelight {}",
51     "E:hover {}",
52     "E:selected {}",
53     "E:insensitive {}",
54     "E:inconsistent {}",
55     "E:focused {}",
56     "E:active:prelight {}",
57     "* > .notebook tab:first-child .label:focused {}",
58     "E, F {}",
59     "E, F /* comment here */ {}",
60     "E,/* comment here */ F {}",
61     "E1.e1_2 #T3_4 {}",
62     NULL
63   };
64
65   const gchar *invalid[] = {
66     /* nth-child and similar pseudo classes can only
67      * be used with regions, not with types
68      */
69     "E:first-child {}",
70     "E:last-child {}",
71     "E:nth-child(first) {}",
72     "E:nth-child(last) {}",
73     "E:nth-child(even) {}",
74     "E:nth-child(odd) {}",
75     "E:sorted {}",
76     /* widget state pseudo-classes can only be used for
77      * the last element
78      */
79     "E:focused tab {}",
80      NULL
81   };
82
83   error = NULL;
84   for (i = 0; valid[i]; i++)
85     {
86       provider = gtk_css_provider_new ();
87       res = gtk_css_provider_load_from_data (provider, valid[i], -1, &error);
88       if (error)
89         g_print ("parsing '%s': got unexpected error: %s\n", valid[i], error->message);
90       g_assert_no_error (error);
91       g_assert (res);
92
93       g_object_unref (provider);
94    }
95
96   for (i = 0; invalid[i]; i++)
97     {
98       provider = gtk_css_provider_new ();
99       res = gtk_css_provider_load_from_data (provider, invalid[i], -1, &error);
100       g_assert_error (error, GTK_CSS_PROVIDER_ERROR, GTK_CSS_PROVIDER_ERROR_FAILED);
101       g_assert (!res);
102       g_object_unref (provider);
103       g_clear_error (&error);
104    }
105 }
106
107 static void
108 test_parse_declarations (void)
109 {
110   GtkCssProvider *provider;
111   GError *error;
112   gboolean res;
113   gint i;
114   const gchar *valid[] = {
115     "* {}",
116     "* { font: Sans 15 }",
117     "* { font: Sans 15; }",
118     "* { font: bold }",
119     "* { color: red }",
120     "* { /* just a comment */ }",
121     "* { /* multi\nline\ncomment */ }",
122     "* { font: /* comment here */ Sans 15 }",
123     "* { color: red; background-color: shade (@bg_color, 0.5) }",
124     "* { margin: 5 }",
125     "* { margin: 5 10 }",
126     "* { margin: 5 10 3 }",
127     "* { margin: 5 10 3 5 }",
128     "* { padding: 5 }",
129     "* { padding: 5 10 }",
130     "* { border-width: 5; border-radius: 10 }",
131     "* { border-color: #ff00ff }",
132     "* { engine: clearlooks }",
133     "* { background-image: -gtk-gradient (linear,               \n"
134     "                                    left top, right top,   \n"
135     "                                    from (#fff), to (#000)) }",
136     "* { background-image: -gtk-gradient (linear,               \n"
137     "                                    0.0 0.5, 0.5 1.0,      \n"
138     "                                    from (#fff),           \n"
139     "                                    color-stop (0.5, #f00),\n"
140     "                                    to (#000))              }",
141     "* { background-image: -gtk-gradient (radial,               \n"
142     "                                     center center, 0.2,   \n"
143     "                                     center center, 0.8,   \n"
144     "                                     color-stop (0.0,#fff),\n"
145     "                                     color-stop (1.0,#000))}\n",
146     "* { border-image: url (\"" SRCDIR "/test.png\") 3 4 3 4 stretch       }",
147     "* { border-image: url (\"" SRCDIR "/test.png\") 3 4 3 4 repeat stretch}",
148     "* { transition: 150ms ease-in-out                          }",
149     "* { transition: 1s linear loop                             }",
150     NULL
151   };
152
153   const gchar *invalid[] = {
154     "* { color }",
155     "* { color:green; color }",
156     "* { color:red; color; color:green }",
157     "* { color:green; color: }",
158     "* { color:red; color:; color:green }",
159     "* { color:green; color{;color:maroon} }",
160     "* { color:red; color{;color:maroon}; color:green }",
161     "* { content: 'Hello",
162     NULL
163   };
164
165   error = NULL;
166   for (i = 0; valid[i]; i++)
167     {
168       provider = gtk_css_provider_new ();
169       res = gtk_css_provider_load_from_data (provider, valid[i], -1, &error);
170       if (error)
171         g_print ("parsing '%s': got unexpected error: %s\n", valid[i], error->message);
172       g_assert_no_error (error);
173       g_assert (res);
174
175       g_object_unref (provider);
176    }
177
178   for (i = 0; invalid[i]; i++)
179     {
180       provider = gtk_css_provider_new ();
181       res = gtk_css_provider_load_from_data (provider, invalid[i], -1, &error);
182       g_assert_error (error, GTK_CSS_PROVIDER_ERROR, GTK_CSS_PROVIDER_ERROR_FAILED);
183       g_assert (!res);
184       g_object_unref (provider);
185       g_clear_error (&error);
186    }
187 }
188
189 static void
190 test_path (void)
191 {
192   GtkWidgetPath *path;
193   GtkWidgetPath *path2;
194   gint pos;
195   GtkRegionFlags flags;
196
197   path = gtk_widget_path_new ();
198   g_assert_cmpint (gtk_widget_path_length (path), ==, 0);
199
200   pos = gtk_widget_path_append_type (path, GTK_TYPE_WINDOW);
201   g_assert_cmpint (pos, ==, 0);
202   g_assert_cmpint (gtk_widget_path_length (path), ==, 1);
203   g_assert (gtk_widget_path_iter_get_object_type (path, 0) == GTK_TYPE_WINDOW);
204   g_assert (gtk_widget_path_is_type (path, GTK_TYPE_WIDGET));
205   g_assert (gtk_widget_path_iter_get_name (path, 0) == NULL);
206
207   pos = gtk_widget_path_append_type (path, GTK_TYPE_WIDGET);
208   g_assert_cmpint (pos, ==, 1);
209   g_assert_cmpint (gtk_widget_path_length (path), ==, 2);
210   gtk_widget_path_iter_set_object_type (path, pos, GTK_TYPE_BUTTON);
211   g_assert (gtk_widget_path_is_type (path, GTK_TYPE_BUTTON));
212   g_assert (gtk_widget_path_has_parent (path, GTK_TYPE_WIDGET));
213   g_assert (gtk_widget_path_has_parent (path, GTK_TYPE_WINDOW));
214   g_assert (!gtk_widget_path_has_parent (path, GTK_TYPE_DIALOG));
215   g_assert (gtk_widget_path_iter_get_name (path, 1) == NULL);
216
217   gtk_widget_path_iter_set_name (path, 1, "name");
218   g_assert (gtk_widget_path_iter_has_name (path, 1, "name"));
219
220   gtk_widget_path_iter_add_class (path, 1, "class1");
221   gtk_widget_path_iter_add_class (path, 1, "class2");
222   g_assert (gtk_widget_path_iter_has_class (path, 1, "class1"));
223   g_assert (gtk_widget_path_iter_has_class (path, 1, "class2"));
224   g_assert (!gtk_widget_path_iter_has_class (path, 1, "class3"));
225
226   path2 = gtk_widget_path_copy (path);
227   g_assert (gtk_widget_path_iter_has_class (path2, 1, "class1"));
228   g_assert (gtk_widget_path_iter_has_class (path2, 1, "class2"));
229   g_assert (!gtk_widget_path_iter_has_class (path2, 1, "class3"));
230   gtk_widget_path_free (path2);
231
232   gtk_widget_path_iter_remove_class (path, 1, "class2");
233   g_assert (gtk_widget_path_iter_has_class (path, 1, "class1"));
234   g_assert (!gtk_widget_path_iter_has_class (path, 1, "class2"));
235   gtk_widget_path_iter_clear_classes (path, 1);
236   g_assert (!gtk_widget_path_iter_has_class (path, 1, "class1"));
237
238   gtk_widget_path_iter_add_region (path, 1, "tab", 0);
239   gtk_widget_path_iter_add_region (path, 1, "title", GTK_REGION_EVEN | GTK_REGION_FIRST);
240
241   g_assert (gtk_widget_path_iter_has_region (path, 1, "tab", &flags) &&
242             flags == 0);
243   g_assert (gtk_widget_path_iter_has_region (path, 1, "title", &flags) &&
244             flags == (GTK_REGION_EVEN | GTK_REGION_FIRST));
245   g_assert (!gtk_widget_path_iter_has_region (path, 1, "extension", NULL));
246
247   path2 = gtk_widget_path_copy (path);
248   g_assert (gtk_widget_path_iter_has_region (path2, 1, "tab", &flags) &&
249             flags == 0);
250   g_assert (gtk_widget_path_iter_has_region (path2, 1, "title", &flags) &&
251             flags == (GTK_REGION_EVEN | GTK_REGION_FIRST));
252   g_assert (!gtk_widget_path_iter_has_region (path2, 1, "extension", NULL));
253   gtk_widget_path_free (path2);
254
255   gtk_widget_path_free (path);
256 }
257
258 static void
259 test_match (void)
260 {
261   GtkStyleContext *context;
262   GtkWidgetPath *path;
263   GtkCssProvider *provider;
264   GError *error;
265   const gchar *data;
266   GdkRGBA color;
267   GdkRGBA expected;
268
269   error = NULL;
270   provider = gtk_css_provider_new ();
271
272   gdk_rgba_parse (&expected, "#fff");
273
274   context = gtk_style_context_new ();
275
276   path = gtk_widget_path_new ();
277   gtk_widget_path_append_type (path, GTK_TYPE_WINDOW);
278   gtk_widget_path_append_type (path, GTK_TYPE_BOX);
279   gtk_widget_path_append_type (path, GTK_TYPE_BUTTON);
280   gtk_widget_path_iter_set_name (path, 0, "mywindow");
281   gtk_widget_path_iter_add_class (path, 2, "button");
282   gtk_style_context_set_path (context, path);
283   gtk_widget_path_free (path);
284
285   gtk_style_context_add_provider (context,
286                                   GTK_STYLE_PROVIDER (provider),
287                                   GTK_STYLE_PROVIDER_PRIORITY_USER);
288
289   data = "* { color: #fff }";
290   gtk_css_provider_load_from_data (provider, data, -1, &error);
291   g_assert_no_error (error);
292   gtk_style_context_invalidate (context);
293   gtk_style_context_get_color (context, GTK_STATE_FLAG_NORMAL, &color);
294   g_assert (gdk_rgba_equal (&color, &expected));
295
296   data = "* { color: #f00 }\n"
297          "GtkButton { color: #fff }";
298   gtk_css_provider_load_from_data (provider, data, -1, &error);
299   g_assert_no_error (error);
300   gtk_style_context_invalidate (context);
301   gtk_style_context_get_color (context, GTK_STATE_FLAG_NORMAL, &color);
302   g_assert (gdk_rgba_equal (&color, &expected));
303
304   data = "* { color: #f00 }\n"
305          "GtkButton { color: #fff }\n"
306          "GtkWindow > GtkButton { color: #000 }";
307   gtk_css_provider_load_from_data (provider, data, -1, &error);
308   g_assert_no_error (error);
309   gtk_style_context_invalidate (context);
310   gtk_style_context_get_color (context, GTK_STATE_FLAG_NORMAL, &color);
311   g_assert (gdk_rgba_equal (&color, &expected));
312
313   data = "* { color: #f00 }\n"
314          ".button { color: #fff }";
315   gtk_css_provider_load_from_data (provider, data, -1, &error);
316   g_assert_no_error (error);
317   gtk_style_context_invalidate (context);
318   gtk_style_context_get_color (context, GTK_STATE_FLAG_NORMAL, &color);
319   g_assert (gdk_rgba_equal (&color, &expected));
320
321   data = "* { color: #f00 }\n"
322          "GtkButton { color: #000 }\n"
323          ".button { color: #fff }";
324   gtk_css_provider_load_from_data (provider, data, -1, &error);
325   g_assert_no_error (error);
326   gtk_style_context_invalidate (context);
327   gtk_style_context_get_color (context, GTK_STATE_FLAG_NORMAL, &color);
328   g_assert (gdk_rgba_equal (&color, &expected));
329
330   data = "* { color: #f00 }\n"
331          "GtkButton { color: #000 }\n"
332          "GtkWindow GtkButton { color: #fff }";
333   gtk_css_provider_load_from_data (provider, data, -1, &error);
334   g_assert_no_error (error);
335   gtk_style_context_invalidate (context);
336   gtk_style_context_get_color (context, GTK_STATE_FLAG_NORMAL, &color);
337   g_assert (gdk_rgba_equal (&color, &expected));
338
339   data = "* { color: #f00 }\n"
340          ".button { color: #000 }\n"
341          "GtkWindow .button { color: #fff }";
342   gtk_css_provider_load_from_data (provider, data, -1, &error);
343   g_assert_no_error (error);
344   gtk_style_context_invalidate (context);
345   gtk_style_context_get_color (context, GTK_STATE_FLAG_NORMAL, &color);
346   g_assert (gdk_rgba_equal (&color, &expected));
347
348   data = "* { color: #f00 }\n"
349          "* .button { color: #000 }\n"
350          "#mywindow .button { color: #fff }";
351   gtk_css_provider_load_from_data (provider, data, -1, &error);
352   g_assert_no_error (error);
353   gtk_style_context_invalidate (context);
354   gtk_style_context_get_color (context, GTK_STATE_FLAG_NORMAL, &color);
355   g_assert (gdk_rgba_equal (&color, &expected));
356
357   data = "* { color: #f00 }\n"
358          "GtkWindow .button { color: #000 }\n"
359          "GtkWindow#mywindow .button { color: #fff }";
360   gtk_css_provider_load_from_data (provider, data, -1, &error);
361   g_assert_no_error (error);
362   gtk_style_context_invalidate (context);
363   gtk_style_context_get_color (context, GTK_STATE_FLAG_NORMAL, &color);
364   g_assert (gdk_rgba_equal (&color, &expected));
365
366   data = "* { color: #f00 }\n"
367          "GtkWindow .button { color: #fff }\n"
368          "GObject .button { color: #000 }";
369   gtk_css_provider_load_from_data (provider, data, -1, &error);
370   g_assert_no_error (error);
371   gtk_style_context_invalidate (context);
372   gtk_style_context_get_color (context, GTK_STATE_FLAG_NORMAL, &color);
373   g_assert (gdk_rgba_equal (&color, &expected));
374
375   g_object_unref (provider);
376   g_object_unref (context);
377 }
378
379 static void
380 test_style_property (void)
381 {
382   GtkStyleContext *context;
383   GtkWidgetPath *path;
384   GtkCssProvider *provider;
385   GError *error;
386   const gchar *data;
387   gint x;
388   GdkRGBA color;
389   GdkRGBA expected;
390
391   error = NULL;
392   provider = gtk_css_provider_new ();
393
394   context = gtk_style_context_new ();
395
396   path = gtk_widget_path_new ();
397   gtk_widget_path_append_type (path, GTK_TYPE_WINDOW);
398   gtk_widget_path_append_type (path, GTK_TYPE_BOX);
399   gtk_widget_path_append_type (path, GTK_TYPE_BUTTON);
400   gtk_style_context_set_path (context, path);
401   gtk_widget_path_free (path);
402   gtk_style_context_set_state (context, GTK_STATE_FLAG_PRELIGHT);
403
404   /* Since we set the prelight state on the context, we expect
405    * only the third selector to match, even though the second one
406    * has higher specificity, and the fourth one comes later.
407    *
408    * In particular, we want to verify that widget style properties and
409    * CSS properties follow the same matching rules, ie we expect
410    * color to be #003 and child-displacement-x to be 3.
411    */
412   data = "GtkButton:insensitive { color: #001; -GtkButton-child-displacement-x: 1 }\n"
413          "GtkBox GtkButton:selected { color: #002; -GtkButton-child-displacement-x: 2 }\n"
414          "GtkButton:prelight { color: #003; -GtkButton-child-displacement-x: 3 }\n"
415          "GtkButton:focused { color: #004; -GtkButton-child-displacement-x: 4 }\n";
416   gtk_css_provider_load_from_data (provider, data, -1, &error);
417   g_assert_no_error (error);
418   gtk_style_context_add_provider (context,
419                                   GTK_STYLE_PROVIDER (provider),
420                                   GTK_STYLE_PROVIDER_PRIORITY_USER);
421
422   gtk_style_context_invalidate (context);
423
424   gtk_style_context_get_color (context, GTK_STATE_FLAG_PRELIGHT, &color);
425   gdk_rgba_parse (&expected, "#003");
426   g_assert (gdk_rgba_equal (&color, &expected));
427
428   gtk_style_context_get_style (context, "child-displacement-x", &x, NULL);
429
430   g_assert_cmpint (x, ==, 3);
431
432   g_object_unref (provider);
433   g_object_unref (context);
434 }
435
436 void
437 test_basic_properties (void)
438 {
439   GtkStyleContext *context;
440   GtkWidgetPath *path;
441   GdkRGBA *color;
442   GdkRGBA *bg_color;
443   PangoFontDescription *font;
444
445   context = gtk_style_context_new ();
446   path = gtk_widget_path_new ();
447   gtk_style_context_set_path (context, path);
448   gtk_widget_path_free (path);
449
450   gtk_style_context_get (context, 0,
451                          "color", &color,
452                          "background-color", &bg_color,
453                          "font", &font,
454                          NULL);
455   g_assert (color != NULL);
456   g_assert (bg_color != NULL);
457   g_assert (font != NULL);
458
459   gdk_rgba_free (color);
460   gdk_rgba_free (bg_color);
461   pango_font_description_free (font);
462
463   g_object_unref (context);
464 }
465
466 int
467 main (int argc, char *argv[])
468 {
469   gtk_init (NULL, NULL);
470   g_test_init (&argc, &argv, NULL);
471
472   g_test_add_func ("/style/parse/empty", test_parse_empty);
473   g_test_add_func ("/style/parse/selectors", test_parse_selectors);
474   g_test_add_func ("/style/parse/declarations", test_parse_declarations);
475   g_test_add_func ("/style/path", test_path);
476   g_test_add_func ("/style/match", test_match);
477   g_test_add_func ("/style/style-property", test_style_property);
478   g_test_add_func ("/style/basic", test_basic_properties);
479
480   return g_test_run ();
481 }