1 | /* |
2 | * Copyright © 2012 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 "gtkcssanimatedstyleprivate.h" |
23 | |
24 | #include "gtkcssanimationprivate.h" |
25 | #include "gtkcssarrayvalueprivate.h" |
26 | #include "gtkcssdynamicprivate.h" |
27 | #include "gtkcssenumvalueprivate.h" |
28 | #include "gtkcssinheritvalueprivate.h" |
29 | #include "gtkcssinitialvalueprivate.h" |
30 | #include "gtkcssnumbervalueprivate.h" |
31 | #include "gtkcssshorthandpropertyprivate.h" |
32 | #include "gtkcssstaticstyleprivate.h" |
33 | #include "gtkcssstringvalueprivate.h" |
34 | #include "gtkcssstylepropertyprivate.h" |
35 | #include "gtkcsstransitionprivate.h" |
36 | #include "gtkprivate.h" |
37 | #include "gtkstyleanimationprivate.h" |
38 | #include "gtkstylepropertyprivate.h" |
39 | #include "gtkstyleproviderprivate.h" |
40 | |
41 | G_DEFINE_TYPE (GtkCssAnimatedStyle, gtk_css_animated_style, GTK_TYPE_CSS_STYLE) |
42 | |
43 | |
44 | static GtkCssSection * |
45 | gtk_css_animated_style_get_section (GtkCssStyle *style, |
46 | guint id) |
47 | { |
48 | GtkCssAnimatedStyle *animated = GTK_CSS_ANIMATED_STYLE (style); |
49 | |
50 | return gtk_css_style_get_section (style: animated->style, id); |
51 | } |
52 | |
53 | static gboolean |
54 | gtk_css_animated_style_is_static (GtkCssStyle *style) |
55 | { |
56 | GtkCssAnimatedStyle *animated = (GtkCssAnimatedStyle *)style; |
57 | guint i; |
58 | |
59 | for (i = 0; i < animated->n_animations; i ++) |
60 | { |
61 | if (!_gtk_style_animation_is_static (animation: animated->animations[i])) |
62 | return FALSE; |
63 | } |
64 | |
65 | return TRUE; |
66 | } |
67 | |
68 | static GtkCssStaticStyle * |
69 | gtk_css_animated_style_get_static_style (GtkCssStyle *style) |
70 | { |
71 | /* This is called a lot, so we avoid a dynamic type check here */ |
72 | GtkCssAnimatedStyle *animated = (GtkCssAnimatedStyle *) style; |
73 | |
74 | return (GtkCssStaticStyle *)animated->style; |
75 | } |
76 | |
77 | static void |
78 | gtk_css_animated_style_dispose (GObject *object) |
79 | { |
80 | GtkCssAnimatedStyle *style = GTK_CSS_ANIMATED_STYLE (object); |
81 | guint i; |
82 | |
83 | for (i = 0; i < style->n_animations; i ++) |
84 | gtk_style_animation_unref (animation: style->animations[i]); |
85 | |
86 | style->n_animations = 0; |
87 | g_free (mem: style->animations); |
88 | style->animations = NULL; |
89 | |
90 | G_OBJECT_CLASS (gtk_css_animated_style_parent_class)->dispose (object); |
91 | } |
92 | |
93 | static void |
94 | gtk_css_animated_style_finalize (GObject *object) |
95 | { |
96 | GtkCssAnimatedStyle *style = GTK_CSS_ANIMATED_STYLE (object); |
97 | |
98 | g_object_unref (object: style->style); |
99 | |
100 | G_OBJECT_CLASS (gtk_css_animated_style_parent_class)->finalize (object); |
101 | } |
102 | |
103 | static void |
104 | gtk_css_animated_style_class_init (GtkCssAnimatedStyleClass *klass) |
105 | { |
106 | GObjectClass *object_class = G_OBJECT_CLASS (klass); |
107 | GtkCssStyleClass *style_class = GTK_CSS_STYLE_CLASS (klass); |
108 | |
109 | object_class->dispose = gtk_css_animated_style_dispose; |
110 | object_class->finalize = gtk_css_animated_style_finalize; |
111 | |
112 | style_class->get_section = gtk_css_animated_style_get_section; |
113 | style_class->is_static = gtk_css_animated_style_is_static; |
114 | style_class->get_static_style = gtk_css_animated_style_get_static_style; |
115 | } |
116 | |
117 | static void |
118 | gtk_css_animated_style_init (GtkCssAnimatedStyle *style) |
119 | { |
120 | } |
121 | |
122 | #define DEFINE_UNSHARE(TYPE, NAME) \ |
123 | static inline void \ |
124 | unshare_ ## NAME (GtkCssAnimatedStyle *animated) \ |
125 | { \ |
126 | GtkCssStyle *style = (GtkCssStyle *)animated; \ |
127 | if (style->NAME == animated->style->NAME) \ |
128 | { \ |
129 | gtk_css_values_unref ((GtkCssValues *)style->NAME); \ |
130 | style->NAME = (TYPE *)gtk_css_values_copy ((GtkCssValues *)animated->style->NAME); \ |
131 | } \ |
132 | } |
133 | |
134 | DEFINE_UNSHARE (GtkCssCoreValues, core) |
135 | DEFINE_UNSHARE (GtkCssBackgroundValues, background) |
136 | DEFINE_UNSHARE (GtkCssBorderValues, border) |
137 | DEFINE_UNSHARE (GtkCssIconValues, icon) |
138 | DEFINE_UNSHARE (GtkCssOutlineValues, outline) |
139 | DEFINE_UNSHARE (GtkCssFontValues, font) |
140 | DEFINE_UNSHARE (GtkCssFontVariantValues, font_variant) |
141 | DEFINE_UNSHARE (GtkCssAnimationValues, animation) |
142 | DEFINE_UNSHARE (GtkCssTransitionValues, transition) |
143 | DEFINE_UNSHARE (GtkCssSizeValues, size) |
144 | DEFINE_UNSHARE (GtkCssOtherValues, other) |
145 | |
146 | static inline void |
147 | gtk_css_take_value (GtkCssValue **variable, |
148 | GtkCssValue *value) |
149 | { |
150 | if (*variable) |
151 | gtk_css_value_unref (value: *variable); |
152 | *variable = value; |
153 | } |
154 | |
155 | void |
156 | gtk_css_animated_style_set_animated_value (GtkCssAnimatedStyle *animated, |
157 | guint id, |
158 | GtkCssValue *value) |
159 | { |
160 | GtkCssStyle *style = (GtkCssStyle *)animated; |
161 | |
162 | gtk_internal_return_if_fail (GTK_IS_CSS_ANIMATED_STYLE (style)); |
163 | gtk_internal_return_if_fail (value != NULL); |
164 | |
165 | switch (id) |
166 | { |
167 | case GTK_CSS_PROPERTY_COLOR: |
168 | unshare_core (animated); |
169 | gtk_css_take_value (variable: &style->core->color, value); |
170 | break; |
171 | case GTK_CSS_PROPERTY_DPI: |
172 | unshare_core (animated); |
173 | gtk_css_take_value (variable: &style->core->dpi, value); |
174 | break; |
175 | case GTK_CSS_PROPERTY_FONT_SIZE: |
176 | unshare_core (animated); |
177 | gtk_css_take_value (variable: &style->core->font_size, value); |
178 | break; |
179 | case GTK_CSS_PROPERTY_ICON_PALETTE: |
180 | unshare_core (animated); |
181 | gtk_css_take_value (variable: &style->core->icon_palette, value); |
182 | break; |
183 | case GTK_CSS_PROPERTY_BACKGROUND_COLOR: |
184 | unshare_background (animated); |
185 | gtk_css_take_value (variable: &style->background->background_color, value); |
186 | break; |
187 | case GTK_CSS_PROPERTY_FONT_FAMILY: |
188 | unshare_font (animated); |
189 | gtk_css_take_value (variable: &style->font->font_family, value); |
190 | break; |
191 | case GTK_CSS_PROPERTY_FONT_STYLE: |
192 | unshare_font (animated); |
193 | gtk_css_take_value (variable: &style->font->font_style, value); |
194 | break; |
195 | case GTK_CSS_PROPERTY_FONT_WEIGHT: |
196 | unshare_font (animated); |
197 | gtk_css_take_value (variable: &style->font->font_weight, value); |
198 | break; |
199 | case GTK_CSS_PROPERTY_FONT_STRETCH: |
200 | unshare_font (animated); |
201 | gtk_css_take_value (variable: &style->font->font_stretch, value); |
202 | break; |
203 | case GTK_CSS_PROPERTY_LETTER_SPACING: |
204 | unshare_font (animated); |
205 | gtk_css_take_value (variable: &style->font->letter_spacing, value); |
206 | break; |
207 | case GTK_CSS_PROPERTY_LINE_HEIGHT: |
208 | unshare_font (animated); |
209 | gtk_css_take_value (variable: &style->font->line_height, value); |
210 | break; |
211 | case GTK_CSS_PROPERTY_TEXT_DECORATION_LINE: |
212 | unshare_font_variant (animated); |
213 | gtk_css_take_value (variable: &style->font_variant->text_decoration_line, value); |
214 | break; |
215 | case GTK_CSS_PROPERTY_TEXT_DECORATION_COLOR: |
216 | unshare_font_variant (animated); |
217 | gtk_css_take_value (variable: &style->font_variant->text_decoration_color, value); |
218 | break; |
219 | case GTK_CSS_PROPERTY_TEXT_DECORATION_STYLE: |
220 | unshare_font_variant (animated); |
221 | gtk_css_take_value (variable: &style->font_variant->text_decoration_style, value); |
222 | break; |
223 | case GTK_CSS_PROPERTY_TEXT_TRANSFORM: |
224 | unshare_font_variant (animated); |
225 | gtk_css_take_value (variable: &style->font_variant->text_transform, value); |
226 | break; |
227 | case GTK_CSS_PROPERTY_FONT_KERNING: |
228 | unshare_font_variant (animated); |
229 | gtk_css_take_value (variable: &style->font_variant->font_kerning, value); |
230 | break; |
231 | case GTK_CSS_PROPERTY_FONT_VARIANT_LIGATURES: |
232 | unshare_font_variant (animated); |
233 | gtk_css_take_value (variable: &style->font_variant->font_variant_ligatures, value); |
234 | break; |
235 | case GTK_CSS_PROPERTY_FONT_VARIANT_POSITION: |
236 | unshare_font_variant (animated); |
237 | gtk_css_take_value (variable: &style->font_variant->font_variant_position, value); |
238 | break; |
239 | case GTK_CSS_PROPERTY_FONT_VARIANT_CAPS: |
240 | unshare_font_variant (animated); |
241 | gtk_css_take_value (variable: &style->font_variant->font_variant_caps, value); |
242 | break; |
243 | case GTK_CSS_PROPERTY_FONT_VARIANT_NUMERIC: |
244 | unshare_font_variant (animated); |
245 | gtk_css_take_value (variable: &style->font_variant->font_variant_numeric, value); |
246 | break; |
247 | case GTK_CSS_PROPERTY_FONT_VARIANT_ALTERNATES: |
248 | unshare_font_variant (animated); |
249 | gtk_css_take_value (variable: &style->font_variant->font_variant_alternates, value); |
250 | break; |
251 | case GTK_CSS_PROPERTY_FONT_VARIANT_EAST_ASIAN: |
252 | unshare_font_variant (animated); |
253 | gtk_css_take_value (variable: &style->font_variant->font_variant_east_asian, value); |
254 | break; |
255 | case GTK_CSS_PROPERTY_TEXT_SHADOW: |
256 | unshare_font (animated); |
257 | gtk_css_take_value (variable: &style->font->text_shadow, value); |
258 | break; |
259 | case GTK_CSS_PROPERTY_BOX_SHADOW: |
260 | unshare_background (animated); |
261 | gtk_css_take_value (variable: &style->background->box_shadow, value); |
262 | break; |
263 | case GTK_CSS_PROPERTY_MARGIN_TOP: |
264 | unshare_size (animated); |
265 | gtk_css_take_value (variable: &style->size->margin_top, value); |
266 | break; |
267 | case GTK_CSS_PROPERTY_MARGIN_LEFT: |
268 | unshare_size (animated); |
269 | gtk_css_take_value (variable: &style->size->margin_left, value); |
270 | break; |
271 | case GTK_CSS_PROPERTY_MARGIN_BOTTOM: |
272 | unshare_size (animated); |
273 | gtk_css_take_value (variable: &style->size->margin_bottom, value); |
274 | break; |
275 | case GTK_CSS_PROPERTY_MARGIN_RIGHT: |
276 | unshare_size (animated); |
277 | gtk_css_take_value (variable: &style->size->margin_right, value); |
278 | break; |
279 | case GTK_CSS_PROPERTY_PADDING_TOP: |
280 | unshare_size (animated); |
281 | gtk_css_take_value (variable: &style->size->padding_top, value); |
282 | break; |
283 | case GTK_CSS_PROPERTY_PADDING_LEFT: |
284 | unshare_size (animated); |
285 | gtk_css_take_value (variable: &style->size->padding_left, value); |
286 | break; |
287 | case GTK_CSS_PROPERTY_PADDING_BOTTOM: |
288 | unshare_size (animated); |
289 | gtk_css_take_value (variable: &style->size->padding_bottom, value); |
290 | break; |
291 | case GTK_CSS_PROPERTY_PADDING_RIGHT: |
292 | unshare_size (animated); |
293 | gtk_css_take_value (variable: &style->size->padding_right, value); |
294 | break; |
295 | case GTK_CSS_PROPERTY_BORDER_TOP_STYLE: |
296 | unshare_border (animated); |
297 | gtk_css_take_value (variable: &style->border->border_top_style, value); |
298 | break; |
299 | case GTK_CSS_PROPERTY_BORDER_TOP_WIDTH: |
300 | unshare_border (animated); |
301 | gtk_css_take_value (variable: &style->border->border_top_width, value); |
302 | break; |
303 | case GTK_CSS_PROPERTY_BORDER_LEFT_STYLE: |
304 | unshare_border (animated); |
305 | gtk_css_take_value (variable: &style->border->border_left_style, value); |
306 | break; |
307 | case GTK_CSS_PROPERTY_BORDER_LEFT_WIDTH: |
308 | unshare_border (animated); |
309 | gtk_css_take_value (variable: &style->border->border_left_width, value); |
310 | break; |
311 | case GTK_CSS_PROPERTY_BORDER_BOTTOM_STYLE: |
312 | unshare_border (animated); |
313 | gtk_css_take_value (variable: &style->border->border_bottom_style, value); |
314 | break; |
315 | case GTK_CSS_PROPERTY_BORDER_BOTTOM_WIDTH: |
316 | unshare_border (animated); |
317 | gtk_css_take_value (variable: &style->border->border_bottom_width, value); |
318 | break; |
319 | case GTK_CSS_PROPERTY_BORDER_RIGHT_STYLE: |
320 | unshare_border (animated); |
321 | gtk_css_take_value (variable: &style->border->border_right_style, value); |
322 | break; |
323 | case GTK_CSS_PROPERTY_BORDER_RIGHT_WIDTH: |
324 | unshare_border (animated); |
325 | gtk_css_take_value (variable: &style->border->border_right_width, value); |
326 | break; |
327 | case GTK_CSS_PROPERTY_BORDER_TOP_LEFT_RADIUS: |
328 | unshare_border (animated); |
329 | gtk_css_take_value (variable: &style->border->border_top_left_radius, value); |
330 | break; |
331 | case GTK_CSS_PROPERTY_BORDER_TOP_RIGHT_RADIUS: |
332 | unshare_border (animated); |
333 | gtk_css_take_value (variable: &style->border->border_top_right_radius, value); |
334 | break; |
335 | case GTK_CSS_PROPERTY_BORDER_BOTTOM_RIGHT_RADIUS: |
336 | unshare_border (animated); |
337 | gtk_css_take_value (variable: &style->border->border_bottom_right_radius, value); |
338 | break; |
339 | case GTK_CSS_PROPERTY_BORDER_BOTTOM_LEFT_RADIUS: |
340 | unshare_border (animated); |
341 | gtk_css_take_value (variable: &style->border->border_bottom_left_radius, value); |
342 | break; |
343 | case GTK_CSS_PROPERTY_OUTLINE_STYLE: |
344 | unshare_outline (animated); |
345 | gtk_css_take_value (variable: &style->outline->outline_style, value); |
346 | break; |
347 | case GTK_CSS_PROPERTY_OUTLINE_WIDTH: |
348 | unshare_outline (animated); |
349 | gtk_css_take_value (variable: &style->outline->outline_width, value); |
350 | break; |
351 | case GTK_CSS_PROPERTY_OUTLINE_OFFSET: |
352 | unshare_outline (animated); |
353 | gtk_css_take_value (variable: &style->outline->outline_offset, value); |
354 | break; |
355 | case GTK_CSS_PROPERTY_BACKGROUND_CLIP: |
356 | unshare_background (animated); |
357 | gtk_css_take_value (variable: &style->background->background_clip, value); |
358 | break; |
359 | case GTK_CSS_PROPERTY_BACKGROUND_ORIGIN: |
360 | unshare_background (animated); |
361 | gtk_css_take_value (variable: &style->background->background_origin, value); |
362 | break; |
363 | case GTK_CSS_PROPERTY_BACKGROUND_SIZE: |
364 | unshare_background (animated); |
365 | gtk_css_take_value (variable: &style->background->background_size, value); |
366 | break; |
367 | case GTK_CSS_PROPERTY_BACKGROUND_POSITION: |
368 | unshare_background (animated); |
369 | gtk_css_take_value (variable: &style->background->background_position, value); |
370 | break; |
371 | case GTK_CSS_PROPERTY_BORDER_TOP_COLOR: |
372 | unshare_border (animated); |
373 | gtk_css_take_value (variable: &style->border->border_top_color, value); |
374 | break; |
375 | case GTK_CSS_PROPERTY_BORDER_RIGHT_COLOR: |
376 | unshare_border (animated); |
377 | gtk_css_take_value (variable: &style->border->border_right_color, value); |
378 | break; |
379 | case GTK_CSS_PROPERTY_BORDER_BOTTOM_COLOR: |
380 | unshare_border (animated); |
381 | gtk_css_take_value (variable: &style->border->border_bottom_color, value); |
382 | break; |
383 | case GTK_CSS_PROPERTY_BORDER_LEFT_COLOR: |
384 | unshare_border (animated); |
385 | gtk_css_take_value (variable: &style->border->border_left_color, value); |
386 | break; |
387 | case GTK_CSS_PROPERTY_OUTLINE_COLOR: |
388 | unshare_outline (animated); |
389 | gtk_css_take_value (variable: &style->outline->outline_color, value); |
390 | break; |
391 | case GTK_CSS_PROPERTY_BACKGROUND_REPEAT: |
392 | unshare_background (animated); |
393 | gtk_css_take_value (variable: &style->background->background_repeat, value); |
394 | break; |
395 | case GTK_CSS_PROPERTY_BACKGROUND_IMAGE: |
396 | unshare_background (animated); |
397 | gtk_css_take_value (variable: &style->background->background_image, value); |
398 | break; |
399 | case GTK_CSS_PROPERTY_BACKGROUND_BLEND_MODE: |
400 | unshare_background (animated); |
401 | gtk_css_take_value (variable: &style->background->background_blend_mode, value); |
402 | break; |
403 | case GTK_CSS_PROPERTY_BORDER_IMAGE_SOURCE: |
404 | unshare_border (animated); |
405 | gtk_css_take_value (variable: &style->border->border_image_source, value); |
406 | break; |
407 | case GTK_CSS_PROPERTY_BORDER_IMAGE_REPEAT: |
408 | unshare_border (animated); |
409 | gtk_css_take_value (variable: &style->border->border_image_repeat, value); |
410 | break; |
411 | case GTK_CSS_PROPERTY_BORDER_IMAGE_SLICE: |
412 | unshare_border (animated); |
413 | gtk_css_take_value (variable: &style->border->border_image_slice, value); |
414 | break; |
415 | case GTK_CSS_PROPERTY_BORDER_IMAGE_WIDTH: |
416 | unshare_border (animated); |
417 | gtk_css_take_value (variable: &style->border->border_image_width, value); |
418 | break; |
419 | case GTK_CSS_PROPERTY_ICON_SOURCE: |
420 | unshare_other (animated); |
421 | gtk_css_take_value (variable: &style->other->icon_source, value); |
422 | break; |
423 | case GTK_CSS_PROPERTY_ICON_SIZE: |
424 | unshare_icon (animated); |
425 | gtk_css_take_value (variable: &style->icon->icon_size, value); |
426 | break; |
427 | case GTK_CSS_PROPERTY_ICON_SHADOW: |
428 | unshare_icon (animated); |
429 | gtk_css_take_value (variable: &style->icon->icon_shadow, value); |
430 | break; |
431 | case GTK_CSS_PROPERTY_ICON_STYLE: |
432 | unshare_icon (animated); |
433 | gtk_css_take_value (variable: &style->icon->icon_style, value); |
434 | break; |
435 | case GTK_CSS_PROPERTY_ICON_TRANSFORM: |
436 | unshare_other (animated); |
437 | gtk_css_take_value (variable: &style->other->icon_transform, value); |
438 | break; |
439 | case GTK_CSS_PROPERTY_ICON_FILTER: |
440 | unshare_other (animated); |
441 | gtk_css_take_value (variable: &style->other->icon_filter, value); |
442 | break; |
443 | case GTK_CSS_PROPERTY_BORDER_SPACING: |
444 | unshare_size (animated); |
445 | gtk_css_take_value (variable: &style->size->border_spacing, value); |
446 | break; |
447 | case GTK_CSS_PROPERTY_TRANSFORM: |
448 | unshare_other (animated); |
449 | gtk_css_take_value (variable: &style->other->transform, value); |
450 | break; |
451 | case GTK_CSS_PROPERTY_TRANSFORM_ORIGIN: |
452 | unshare_other (animated); |
453 | gtk_css_take_value (variable: &style->other->transform_origin, value); |
454 | break; |
455 | case GTK_CSS_PROPERTY_MIN_WIDTH: |
456 | unshare_size (animated); |
457 | gtk_css_take_value (variable: &style->size->min_width, value); |
458 | break; |
459 | case GTK_CSS_PROPERTY_MIN_HEIGHT: |
460 | unshare_size (animated); |
461 | gtk_css_take_value (variable: &style->size->min_height, value); |
462 | break; |
463 | case GTK_CSS_PROPERTY_TRANSITION_PROPERTY: |
464 | unshare_transition (animated); |
465 | gtk_css_take_value (variable: &style->transition->transition_property, value); |
466 | break; |
467 | case GTK_CSS_PROPERTY_TRANSITION_DURATION: |
468 | unshare_transition (animated); |
469 | gtk_css_take_value (variable: &style->transition->transition_duration, value); |
470 | break; |
471 | case GTK_CSS_PROPERTY_TRANSITION_TIMING_FUNCTION: |
472 | unshare_transition (animated); |
473 | gtk_css_take_value (variable: &style->transition->transition_timing_function, value); |
474 | break; |
475 | case GTK_CSS_PROPERTY_TRANSITION_DELAY: |
476 | unshare_transition (animated); |
477 | gtk_css_take_value (variable: &style->transition->transition_delay, value); |
478 | break; |
479 | case GTK_CSS_PROPERTY_ANIMATION_NAME: |
480 | unshare_animation (animated); |
481 | gtk_css_take_value (variable: &style->animation->animation_name, value); |
482 | break; |
483 | case GTK_CSS_PROPERTY_ANIMATION_DURATION: |
484 | unshare_animation (animated); |
485 | gtk_css_take_value (variable: &style->animation->animation_duration, value); |
486 | break; |
487 | case GTK_CSS_PROPERTY_ANIMATION_TIMING_FUNCTION: |
488 | unshare_animation (animated); |
489 | gtk_css_take_value (variable: &style->animation->animation_timing_function, value); |
490 | break; |
491 | case GTK_CSS_PROPERTY_ANIMATION_ITERATION_COUNT: |
492 | unshare_animation (animated); |
493 | gtk_css_take_value (variable: &style->animation->animation_iteration_count, value); |
494 | break; |
495 | case GTK_CSS_PROPERTY_ANIMATION_DIRECTION: |
496 | unshare_animation (animated); |
497 | gtk_css_take_value (variable: &style->animation->animation_direction, value); |
498 | break; |
499 | case GTK_CSS_PROPERTY_ANIMATION_PLAY_STATE: |
500 | unshare_animation (animated); |
501 | gtk_css_take_value (variable: &style->animation->animation_play_state, value); |
502 | break; |
503 | case GTK_CSS_PROPERTY_ANIMATION_DELAY: |
504 | unshare_animation (animated); |
505 | gtk_css_take_value (variable: &style->animation->animation_delay, value); |
506 | break; |
507 | case GTK_CSS_PROPERTY_ANIMATION_FILL_MODE: |
508 | unshare_animation (animated); |
509 | gtk_css_take_value (variable: &style->animation->animation_fill_mode, value); |
510 | break; |
511 | case GTK_CSS_PROPERTY_OPACITY: |
512 | unshare_other (animated); |
513 | gtk_css_take_value (variable: &style->other->opacity, value); |
514 | break; |
515 | case GTK_CSS_PROPERTY_FILTER: |
516 | unshare_other (animated); |
517 | gtk_css_take_value (variable: &style->other->filter, value); |
518 | break; |
519 | case GTK_CSS_PROPERTY_CARET_COLOR: |
520 | unshare_font (animated); |
521 | gtk_css_take_value (variable: &style->font->caret_color, value); |
522 | break; |
523 | case GTK_CSS_PROPERTY_SECONDARY_CARET_COLOR: |
524 | unshare_font (animated); |
525 | gtk_css_take_value (variable: &style->font->secondary_caret_color, value); |
526 | break; |
527 | case GTK_CSS_PROPERTY_FONT_FEATURE_SETTINGS: |
528 | unshare_font (animated); |
529 | gtk_css_take_value (variable: &style->font->font_feature_settings, value); |
530 | break; |
531 | case GTK_CSS_PROPERTY_FONT_VARIATION_SETTINGS: |
532 | unshare_font (animated); |
533 | gtk_css_take_value (variable: &style->font->font_variation_settings, value); |
534 | break; |
535 | |
536 | default: |
537 | g_assert_not_reached (); |
538 | break; |
539 | } |
540 | } |
541 | |
542 | GtkCssValue * |
543 | gtk_css_animated_style_get_intrinsic_value (GtkCssAnimatedStyle *style, |
544 | guint id) |
545 | { |
546 | return gtk_css_style_get_value (style: style->style, id); |
547 | } |
548 | |
549 | static GPtrArray * |
550 | gtk_css_animated_style_create_dynamic (GPtrArray *animations, |
551 | GtkCssStyle *style, |
552 | gint64 timestamp) |
553 | { |
554 | guint i; |
555 | |
556 | /* XXX: Check animations if they have dynamic values */ |
557 | |
558 | for (i = 0; i < GTK_CSS_PROPERTY_N_PROPERTIES; i++) |
559 | { |
560 | if (gtk_css_value_is_dynamic (value: gtk_css_style_get_value (style, id: i))) |
561 | { |
562 | if (!animations) |
563 | animations = g_ptr_array_new (); |
564 | |
565 | g_ptr_array_insert (array: animations, index_: 0, data: gtk_css_dynamic_new (timestamp)); |
566 | break; |
567 | } |
568 | } |
569 | |
570 | return animations; |
571 | } |
572 | |
573 | /* TRANSITIONS */ |
574 | |
575 | typedef struct _TransitionInfo TransitionInfo; |
576 | struct _TransitionInfo { |
577 | guint index; /* index into value arrays */ |
578 | gboolean pending; /* TRUE if we still need to handle it */ |
579 | }; |
580 | |
581 | static void |
582 | transition_info_add (TransitionInfo infos[GTK_CSS_PROPERTY_N_PROPERTIES], |
583 | GtkStyleProperty *property, |
584 | guint index) |
585 | { |
586 | if (GTK_IS_CSS_SHORTHAND_PROPERTY (property)) |
587 | { |
588 | GtkCssShorthandProperty *shorthand = (GtkCssShorthandProperty *) property; |
589 | guint len = _gtk_css_shorthand_property_get_n_subproperties (shorthand); |
590 | guint i; |
591 | |
592 | for (i = 0; i < len; i++) |
593 | { |
594 | GtkCssStyleProperty *prop = _gtk_css_shorthand_property_get_subproperty (shorthand, property: i); |
595 | guint id; |
596 | |
597 | if (!_gtk_css_style_property_is_animated (property: (GtkCssStyleProperty *) prop)) |
598 | continue; |
599 | |
600 | id = _gtk_css_style_property_get_id (property: (GtkCssStyleProperty *) prop); |
601 | infos[id].index = index; |
602 | infos[id].pending = TRUE; |
603 | } |
604 | } |
605 | else |
606 | { |
607 | guint id; |
608 | |
609 | if (!_gtk_css_style_property_is_animated (property: (GtkCssStyleProperty *) property)) |
610 | return; |
611 | |
612 | id = _gtk_css_style_property_get_id (property: (GtkCssStyleProperty *) property); |
613 | g_assert (id < GTK_CSS_PROPERTY_N_PROPERTIES); |
614 | infos[id].index = index; |
615 | infos[id].pending = TRUE; |
616 | } |
617 | } |
618 | |
619 | static void |
620 | transition_infos_set (TransitionInfo infos[GTK_CSS_PROPERTY_N_PROPERTIES], |
621 | GtkCssValue *transitions) |
622 | { |
623 | guint i; |
624 | |
625 | for (i = 0; i < _gtk_css_array_value_get_n_values (value: transitions); i++) |
626 | { |
627 | GtkStyleProperty *property; |
628 | GtkCssValue *prop_value; |
629 | |
630 | prop_value = _gtk_css_array_value_get_nth (value: transitions, i); |
631 | if (g_ascii_strcasecmp (s1: _gtk_css_ident_value_get (ident: prop_value), s2: "all" ) == 0) |
632 | { |
633 | const guint len = _gtk_css_style_property_get_n_properties (); |
634 | guint j; |
635 | |
636 | for (j = 0; j < len; j++) |
637 | { |
638 | property = (GtkStyleProperty *)_gtk_css_style_property_lookup_by_id (id: j); |
639 | transition_info_add (infos, property, index: i); |
640 | } |
641 | } |
642 | else |
643 | { |
644 | property = _gtk_style_property_lookup (name: _gtk_css_ident_value_get (ident: prop_value)); |
645 | if (property) |
646 | transition_info_add (infos, property, index: i); |
647 | } |
648 | } |
649 | } |
650 | |
651 | static GtkStyleAnimation * |
652 | gtk_css_animated_style_find_transition (GtkCssAnimatedStyle *style, |
653 | guint property_id) |
654 | { |
655 | guint i; |
656 | |
657 | for (i = 0; i < style->n_animations; i ++) |
658 | { |
659 | GtkStyleAnimation *animation = style->animations[i]; |
660 | |
661 | if (!_gtk_css_transition_is_transition (animation)) |
662 | continue; |
663 | |
664 | if (_gtk_css_transition_get_property (transition: (GtkCssTransition *)animation) == property_id) |
665 | return animation; |
666 | } |
667 | |
668 | return NULL; |
669 | } |
670 | |
671 | static GPtrArray * |
672 | gtk_css_animated_style_create_css_transitions (GPtrArray *animations, |
673 | GtkCssStyle *base_style, |
674 | gint64 timestamp, |
675 | GtkCssStyle *source) |
676 | { |
677 | TransitionInfo transitions[GTK_CSS_PROPERTY_N_PROPERTIES] = { { 0, } }; |
678 | GtkCssValue *durations, *delays, *timing_functions; |
679 | gboolean source_is_animated; |
680 | guint i; |
681 | |
682 | durations = base_style->transition->transition_duration; |
683 | delays = base_style->transition->transition_delay; |
684 | timing_functions = base_style->transition->transition_timing_function; |
685 | |
686 | if (_gtk_css_array_value_get_n_values (value: durations) == 1 && |
687 | _gtk_css_array_value_get_n_values (value: delays) == 1 && |
688 | _gtk_css_number_value_get (number: _gtk_css_array_value_get_nth (value: durations, i: 0), one_hundred_percent: 100) + |
689 | _gtk_css_number_value_get (number: _gtk_css_array_value_get_nth (value: delays, i: 0), one_hundred_percent: 100) == 0) |
690 | return animations; |
691 | |
692 | transition_infos_set (infos: transitions, transitions: base_style->transition->transition_property); |
693 | |
694 | source_is_animated = GTK_IS_CSS_ANIMATED_STYLE (source); |
695 | for (i = 0; i < GTK_CSS_PROPERTY_N_PROPERTIES; i++) |
696 | { |
697 | GtkStyleAnimation *animation; |
698 | GtkCssValue *start, *end; |
699 | double duration, delay; |
700 | |
701 | if (!transitions[i].pending) |
702 | continue; |
703 | |
704 | duration = _gtk_css_number_value_get (number: _gtk_css_array_value_get_nth (value: durations, i: transitions[i].index), one_hundred_percent: 100); |
705 | delay = _gtk_css_number_value_get (number: _gtk_css_array_value_get_nth (value: delays, i: transitions[i].index), one_hundred_percent: 100); |
706 | if (duration + delay == 0.0) |
707 | continue; |
708 | |
709 | if (source_is_animated) |
710 | { |
711 | start = gtk_css_animated_style_get_intrinsic_value (style: (GtkCssAnimatedStyle *)source, id: i); |
712 | end = gtk_css_style_get_value (style: base_style, id: i); |
713 | |
714 | if (_gtk_css_value_equal (value1: start, value2: end)) |
715 | { |
716 | animation = gtk_css_animated_style_find_transition (style: (GtkCssAnimatedStyle *)source, property_id: i); |
717 | if (animation) |
718 | { |
719 | animation = _gtk_style_animation_advance (animation, timestamp); |
720 | if (!animations) |
721 | animations = g_ptr_array_new (); |
722 | |
723 | g_ptr_array_add (array: animations, data: animation); |
724 | } |
725 | |
726 | continue; |
727 | } |
728 | } |
729 | |
730 | if (_gtk_css_value_equal (value1: gtk_css_style_get_value (style: source, id: i), |
731 | value2: gtk_css_style_get_value (style: base_style, id: i))) |
732 | continue; |
733 | |
734 | animation = _gtk_css_transition_new (property: i, |
735 | start: gtk_css_style_get_value (style: source, id: i), |
736 | ease: _gtk_css_array_value_get_nth (value: timing_functions, i), |
737 | timestamp, |
738 | duration_us: duration * G_USEC_PER_SEC, |
739 | delay_us: delay * G_USEC_PER_SEC); |
740 | if (!animations) |
741 | animations = g_ptr_array_new (); |
742 | |
743 | g_ptr_array_add (array: animations, data: animation); |
744 | } |
745 | |
746 | return animations; |
747 | } |
748 | |
749 | static GtkStyleAnimation * |
750 | gtk_css_animated_style_find_animation (GtkStyleAnimation **animations, |
751 | guint n_animations, |
752 | const char *name) |
753 | { |
754 | guint i; |
755 | |
756 | for (i = 0; i < n_animations; i ++) |
757 | { |
758 | GtkStyleAnimation *animation = animations[i]; |
759 | |
760 | if (!_gtk_css_animation_is_animation (animation)) |
761 | continue; |
762 | |
763 | if (g_str_equal (v1: _gtk_css_animation_get_name (animation: (GtkCssAnimation *)animation), v2: name)) |
764 | return animation; |
765 | } |
766 | |
767 | return NULL; |
768 | } |
769 | |
770 | static GPtrArray * |
771 | gtk_css_animated_style_create_css_animations (GPtrArray *animations, |
772 | GtkCssStyle *base_style, |
773 | GtkCssStyle *parent_style, |
774 | gint64 timestamp, |
775 | GtkStyleProvider *provider, |
776 | GtkCssStyle *source) |
777 | { |
778 | GtkCssValue *durations, *delays, *timing_functions, *animation_names; |
779 | GtkCssValue *iteration_counts, *directions, *play_states, *fill_modes; |
780 | gboolean source_is_animated; |
781 | guint i; |
782 | |
783 | animation_names = base_style->animation->animation_name; |
784 | |
785 | if (_gtk_css_array_value_get_n_values (value: animation_names) == 1) |
786 | { |
787 | const char *name = _gtk_css_ident_value_get (ident: _gtk_css_array_value_get_nth (value: animation_names, i: 0)); |
788 | |
789 | if (g_ascii_strcasecmp (s1: name, s2: "none" ) == 0) |
790 | return animations; |
791 | } |
792 | |
793 | durations = base_style->animation->animation_duration; |
794 | delays = base_style->animation->animation_delay; |
795 | timing_functions = base_style->animation->animation_timing_function; |
796 | iteration_counts = base_style->animation->animation_iteration_count; |
797 | directions = base_style->animation->animation_direction; |
798 | play_states = base_style->animation->animation_play_state; |
799 | fill_modes = base_style->animation->animation_fill_mode; |
800 | source_is_animated = GTK_IS_CSS_ANIMATED_STYLE (source); |
801 | |
802 | for (i = 0; i < _gtk_css_array_value_get_n_values (value: animation_names); i++) |
803 | { |
804 | GtkStyleAnimation *animation = NULL; |
805 | GtkCssKeyframes *keyframes; |
806 | const char *name; |
807 | |
808 | name = _gtk_css_ident_value_get (ident: _gtk_css_array_value_get_nth (value: animation_names, i)); |
809 | if (g_ascii_strcasecmp (s1: name, s2: "none" ) == 0) |
810 | continue; |
811 | |
812 | if (animations) |
813 | animation = gtk_css_animated_style_find_animation (animations: (GtkStyleAnimation **)animations->pdata, n_animations: animations->len, name); |
814 | |
815 | if (animation) |
816 | continue; |
817 | |
818 | if (source_is_animated) |
819 | animation = gtk_css_animated_style_find_animation (animations: (GtkStyleAnimation **)GTK_CSS_ANIMATED_STYLE (source)->animations, |
820 | GTK_CSS_ANIMATED_STYLE (source)->n_animations, |
821 | name); |
822 | |
823 | if (animation) |
824 | { |
825 | animation = _gtk_css_animation_advance_with_play_state (animation: (GtkCssAnimation *)animation, |
826 | timestamp, |
827 | play_state: _gtk_css_play_state_value_get (value: _gtk_css_array_value_get_nth (value: play_states, i))); |
828 | } |
829 | else |
830 | { |
831 | keyframes = gtk_style_provider_get_keyframes (provider, name); |
832 | if (keyframes == NULL) |
833 | continue; |
834 | |
835 | keyframes = _gtk_css_keyframes_compute (keyframes, provider, style: base_style, parent_style); |
836 | |
837 | animation = _gtk_css_animation_new (name, |
838 | keyframes, |
839 | timestamp, |
840 | delay_us: _gtk_css_number_value_get (number: _gtk_css_array_value_get_nth (value: delays, i), one_hundred_percent: 100) * G_USEC_PER_SEC, |
841 | duration_us: _gtk_css_number_value_get (number: _gtk_css_array_value_get_nth (value: durations, i), one_hundred_percent: 100) * G_USEC_PER_SEC, |
842 | ease: _gtk_css_array_value_get_nth (value: timing_functions, i), |
843 | direction: _gtk_css_direction_value_get (value: _gtk_css_array_value_get_nth (value: directions, i)), |
844 | play_state: _gtk_css_play_state_value_get (value: _gtk_css_array_value_get_nth (value: play_states, i)), |
845 | fill_mode: _gtk_css_fill_mode_value_get (value: _gtk_css_array_value_get_nth (value: fill_modes, i)), |
846 | iteration_count: _gtk_css_number_value_get (number: _gtk_css_array_value_get_nth (value: iteration_counts, i), one_hundred_percent: 100)); |
847 | _gtk_css_keyframes_unref (keyframes); |
848 | } |
849 | |
850 | if (!animations) |
851 | animations = g_ptr_array_sized_new (reserved_size: 16); |
852 | |
853 | g_ptr_array_add (array: animations, data: animation); |
854 | } |
855 | |
856 | return animations; |
857 | } |
858 | |
859 | /* PUBLIC API */ |
860 | |
861 | static void |
862 | gtk_css_animated_style_apply_animations (GtkCssAnimatedStyle *style) |
863 | { |
864 | guint i; |
865 | |
866 | for (i = 0; i < style->n_animations; i ++) |
867 | { |
868 | GtkStyleAnimation *animation = style->animations[i]; |
869 | |
870 | _gtk_style_animation_apply_values (animation, style); |
871 | } |
872 | } |
873 | |
874 | GtkCssStyle * |
875 | gtk_css_animated_style_new (GtkCssStyle *base_style, |
876 | GtkCssStyle *parent_style, |
877 | gint64 timestamp, |
878 | GtkStyleProvider *provider, |
879 | GtkCssStyle *previous_style) |
880 | { |
881 | GtkCssAnimatedStyle *result; |
882 | GtkCssStyle *style; |
883 | GPtrArray *animations = NULL; |
884 | |
885 | gtk_internal_return_val_if_fail (GTK_IS_CSS_STYLE (base_style), NULL); |
886 | gtk_internal_return_val_if_fail (parent_style == NULL || GTK_IS_CSS_STYLE (parent_style), NULL); |
887 | gtk_internal_return_val_if_fail (GTK_IS_STYLE_PROVIDER (provider), NULL); |
888 | gtk_internal_return_val_if_fail (previous_style == NULL || GTK_IS_CSS_STYLE (previous_style), NULL); |
889 | |
890 | if (timestamp == 0) |
891 | return g_object_ref (base_style); |
892 | |
893 | if (previous_style != NULL) |
894 | animations = gtk_css_animated_style_create_css_transitions (animations, base_style, timestamp, source: previous_style); |
895 | |
896 | animations = gtk_css_animated_style_create_css_animations (animations, base_style, parent_style, timestamp, provider, source: previous_style); |
897 | animations = gtk_css_animated_style_create_dynamic (animations, style: base_style, timestamp); |
898 | |
899 | if (animations == NULL) |
900 | return g_object_ref (base_style); |
901 | |
902 | result = g_object_new (GTK_TYPE_CSS_ANIMATED_STYLE, NULL); |
903 | |
904 | result->style = g_object_ref (base_style); |
905 | result->current_time = timestamp; |
906 | result->n_animations = animations->len; |
907 | result->animations = g_ptr_array_free (array: animations, FALSE); |
908 | |
909 | style = (GtkCssStyle *)result; |
910 | style->core = (GtkCssCoreValues *)gtk_css_values_ref (values: (GtkCssValues *)base_style->core); |
911 | style->background = (GtkCssBackgroundValues *)gtk_css_values_ref (values: (GtkCssValues *)base_style->background); |
912 | style->border = (GtkCssBorderValues *)gtk_css_values_ref (values: (GtkCssValues *)base_style->border); |
913 | style->icon = (GtkCssIconValues *)gtk_css_values_ref (values: (GtkCssValues *)base_style->icon); |
914 | style->outline = (GtkCssOutlineValues *)gtk_css_values_ref (values: (GtkCssValues *)base_style->outline); |
915 | style->font = (GtkCssFontValues *)gtk_css_values_ref (values: (GtkCssValues *)base_style->font); |
916 | style->font_variant = (GtkCssFontVariantValues *)gtk_css_values_ref (values: (GtkCssValues *)base_style->font_variant); |
917 | style->animation = (GtkCssAnimationValues *)gtk_css_values_ref (values: (GtkCssValues *)base_style->animation); |
918 | style->transition = (GtkCssTransitionValues *)gtk_css_values_ref (values: (GtkCssValues *)base_style->transition); |
919 | style->size = (GtkCssSizeValues *)gtk_css_values_ref (values: (GtkCssValues *)base_style->size); |
920 | style->other = (GtkCssOtherValues *)gtk_css_values_ref (values: (GtkCssValues *)base_style->other); |
921 | |
922 | gtk_css_animated_style_apply_animations (style: result); |
923 | |
924 | return GTK_CSS_STYLE (result); |
925 | } |
926 | |
927 | GtkCssStyle * |
928 | gtk_css_animated_style_new_advance (GtkCssAnimatedStyle *source, |
929 | GtkCssStyle *base_style, |
930 | gint64 timestamp) |
931 | { |
932 | GtkCssAnimatedStyle *result; |
933 | GtkCssStyle *style; |
934 | GPtrArray *animations; |
935 | guint i; |
936 | |
937 | gtk_internal_return_val_if_fail (GTK_IS_CSS_ANIMATED_STYLE (source), NULL); |
938 | gtk_internal_return_val_if_fail (GTK_IS_CSS_STYLE (base_style), NULL); |
939 | |
940 | if (timestamp == 0 || timestamp == source->current_time) |
941 | return g_object_ref (source->style); |
942 | |
943 | gtk_internal_return_val_if_fail (timestamp > source->current_time, NULL); |
944 | |
945 | animations = NULL; |
946 | for (i = 0; i < source->n_animations; i ++) |
947 | { |
948 | GtkStyleAnimation *animation = source->animations[i]; |
949 | |
950 | if (_gtk_style_animation_is_finished (animation)) |
951 | continue; |
952 | |
953 | if (!animations) |
954 | animations = g_ptr_array_sized_new (reserved_size: 16); |
955 | |
956 | animation = _gtk_style_animation_advance (animation, timestamp); |
957 | g_ptr_array_add (array: animations, data: animation); |
958 | } |
959 | |
960 | if (animations == NULL) |
961 | return g_object_ref (source->style); |
962 | |
963 | result = g_object_new (GTK_TYPE_CSS_ANIMATED_STYLE, NULL); |
964 | |
965 | result->style = g_object_ref (base_style); |
966 | result->current_time = timestamp; |
967 | result->n_animations = animations->len; |
968 | result->animations = g_ptr_array_free (array: animations, FALSE); |
969 | |
970 | style = (GtkCssStyle *)result; |
971 | style->core = (GtkCssCoreValues *)gtk_css_values_ref (values: (GtkCssValues *)base_style->core); |
972 | style->background = (GtkCssBackgroundValues *)gtk_css_values_ref (values: (GtkCssValues *)base_style->background); |
973 | style->border = (GtkCssBorderValues *)gtk_css_values_ref (values: (GtkCssValues *)base_style->border); |
974 | style->icon = (GtkCssIconValues *)gtk_css_values_ref (values: (GtkCssValues *)base_style->icon); |
975 | style->outline = (GtkCssOutlineValues *)gtk_css_values_ref (values: (GtkCssValues *)base_style->outline); |
976 | style->font = (GtkCssFontValues *)gtk_css_values_ref (values: (GtkCssValues *)base_style->font); |
977 | style->font_variant = (GtkCssFontVariantValues *)gtk_css_values_ref (values: (GtkCssValues *)base_style->font_variant); |
978 | style->animation = (GtkCssAnimationValues *)gtk_css_values_ref (values: (GtkCssValues *)base_style->animation); |
979 | style->transition = (GtkCssTransitionValues *)gtk_css_values_ref (values: (GtkCssValues *)base_style->transition); |
980 | style->size = (GtkCssSizeValues *)gtk_css_values_ref (values: (GtkCssValues *)base_style->size); |
981 | style->other = (GtkCssOtherValues *)gtk_css_values_ref (values: (GtkCssValues *)base_style->other); |
982 | |
983 | gtk_css_animated_style_apply_animations (style: result); |
984 | |
985 | return GTK_CSS_STYLE (result); |
986 | } |
987 | |