1 /*
2 * Copyright © 2011 Intel Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files (the
6 * "Software"), to deal in the Software without restriction, including
7 * without limitation the rights to use, copy, modify, merge, publish,
8 * distribute, sublicense, and/or sell copies of the Software, and to
9 * permit persons to whom the Software is furnished to do so, subject to
10 * the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the
13 * next paragraph) shall be included in all copies or substantial
14 * portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
20 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
21 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 * SOFTWARE.
24 */
25
26 #include "config.h"
27
28 #include <stdlib.h>
29 #include <string.h>
30 #include <stdint.h>
31 #include <stdio.h>
32 #include <math.h>
33 #include <inttypes.h>
34
35 #include <unistd.h>
36 #include <fcntl.h>
37
38 #include <libweston/libweston.h>
39 #include "shared/helpers.h"
40 #include "shared/timespec-util.h"
41
42 WL_EXPORT void
weston_spring_init(struct weston_spring * spring,double k,double current,double target)43 weston_spring_init(struct weston_spring *spring,
44 double k, double current, double target)
45 {
46 spring->k = k;
47 spring->friction = 400.0;
48 spring->current = current;
49 spring->previous = current;
50 spring->target = target;
51 spring->clip = WESTON_SPRING_OVERSHOOT;
52 spring->min = 0.0;
53 spring->max = 1.0;
54 }
55
56 WL_EXPORT void
weston_spring_update(struct weston_spring * spring,const struct timespec * time)57 weston_spring_update(struct weston_spring *spring, const struct timespec *time)
58 {
59 double force, v, current, step;
60
61 /* Limit the number of executions of the loop below by ensuring that
62 * the timestamp for last update of the spring is no more than 1s ago.
63 * This handles the case where time moves backwards or forwards in
64 * large jumps.
65 */
66 if (timespec_sub_to_msec(time, &spring->timestamp) > 1000) {
67 weston_log("unexpectedly large timestamp jump "
68 "(from %" PRId64 " to %" PRId64 ")\n",
69 timespec_to_msec(&spring->timestamp),
70 timespec_to_msec(time));
71 timespec_add_msec(&spring->timestamp, time, -1000);
72 }
73
74 step = 0.01;
75 while (4 < timespec_sub_to_msec(time, &spring->timestamp)) {
76 current = spring->current;
77 v = current - spring->previous;
78 force = spring->k * (spring->target - current) / 10.0 +
79 (spring->previous - current) - v * spring->friction;
80
81 spring->current =
82 current + (current - spring->previous) +
83 force * step * step;
84 spring->previous = current;
85
86 switch (spring->clip) {
87 case WESTON_SPRING_OVERSHOOT:
88 break;
89
90 case WESTON_SPRING_CLAMP:
91 if (spring->current > spring->max) {
92 spring->current = spring->max;
93 spring->previous = spring->max;
94 } else if (spring->current < 0.0) {
95 spring->current = spring->min;
96 spring->previous = spring->min;
97 }
98 break;
99
100 case WESTON_SPRING_BOUNCE:
101 if (spring->current > spring->max) {
102 spring->current =
103 2 * spring->max - spring->current;
104 spring->previous =
105 2 * spring->max - spring->previous;
106 } else if (spring->current < spring->min) {
107 spring->current =
108 2 * spring->min - spring->current;
109 spring->previous =
110 2 * spring->min - spring->previous;
111 }
112 break;
113 }
114
115 timespec_add_msec(&spring->timestamp, &spring->timestamp, 4);
116 }
117 }
118
119 WL_EXPORT int
weston_spring_done(struct weston_spring * spring)120 weston_spring_done(struct weston_spring *spring)
121 {
122 return fabs(spring->previous - spring->target) < 0.002 &&
123 fabs(spring->current - spring->target) < 0.002;
124 }
125
126 typedef void (*weston_view_animation_frame_func_t)(struct weston_view_animation *animation);
127
128 struct weston_view_animation {
129 struct weston_view *view;
130 struct weston_animation animation;
131 struct weston_spring spring;
132 struct weston_transform transform;
133 struct wl_listener listener;
134 float start, stop;
135 weston_view_animation_frame_func_t frame;
136 weston_view_animation_frame_func_t reset;
137 weston_view_animation_done_func_t done;
138 void *data;
139 void *private;
140 };
141
142 WL_EXPORT void
weston_view_animation_destroy(struct weston_view_animation * animation)143 weston_view_animation_destroy(struct weston_view_animation *animation)
144 {
145 wl_list_remove(&animation->animation.link);
146 wl_list_remove(&animation->listener.link);
147 wl_list_remove(&animation->transform.link);
148 if (animation->reset)
149 animation->reset(animation);
150 weston_view_geometry_dirty(animation->view);
151 if (animation->done)
152 animation->done(animation, animation->data);
153 free(animation);
154 }
155
156 static void
handle_animation_view_destroy(struct wl_listener * listener,void * data)157 handle_animation_view_destroy(struct wl_listener *listener, void *data)
158 {
159 struct weston_view_animation *animation =
160 container_of(listener,
161 struct weston_view_animation, listener);
162
163 weston_view_animation_destroy(animation);
164 }
165
166 static void
weston_view_animation_frame(struct weston_animation * base,struct weston_output * output,const struct timespec * time)167 weston_view_animation_frame(struct weston_animation *base,
168 struct weston_output *output,
169 const struct timespec *time)
170 {
171 struct weston_view_animation *animation =
172 container_of(base,
173 struct weston_view_animation, animation);
174 struct weston_compositor *compositor =
175 animation->view->surface->compositor;
176
177 if (base->frame_counter <= 1)
178 animation->spring.timestamp = *time;
179
180 weston_spring_update(&animation->spring, time);
181
182 if (weston_spring_done(&animation->spring)) {
183 weston_view_schedule_repaint(animation->view);
184 weston_view_animation_destroy(animation);
185 return;
186 }
187
188 if (animation->frame)
189 animation->frame(animation);
190
191 weston_view_geometry_dirty(animation->view);
192 weston_view_schedule_repaint(animation->view);
193
194 /* The view's output_mask will be zero if its position is
195 * offscreen. Animations should always run but as they are also
196 * run off the repaint cycle, if there's nothing to repaint
197 * the animation stops running. Therefore if we catch this situation
198 * and schedule a repaint on all outputs it will be avoided.
199 */
200 if (animation->view->output_mask == 0)
201 weston_compositor_schedule_repaint(compositor);
202 }
203
204 static void
idle_animation_destroy(void * data)205 idle_animation_destroy(void *data)
206 {
207 struct weston_view_animation *animation = data;
208
209 weston_view_animation_destroy(animation);
210 }
211
212 static struct weston_view_animation *
weston_view_animation_create(struct weston_view * view,float start,float stop,weston_view_animation_frame_func_t frame,weston_view_animation_frame_func_t reset,weston_view_animation_done_func_t done,void * data,void * private)213 weston_view_animation_create(struct weston_view *view,
214 float start, float stop,
215 weston_view_animation_frame_func_t frame,
216 weston_view_animation_frame_func_t reset,
217 weston_view_animation_done_func_t done,
218 void *data,
219 void *private)
220 {
221 struct weston_view_animation *animation;
222 struct weston_compositor *ec = view->surface->compositor;
223 struct wl_event_loop *loop;
224
225 animation = malloc(sizeof *animation);
226 if (!animation)
227 return NULL;
228
229 animation->view = view;
230 animation->frame = frame;
231 animation->reset = reset;
232 animation->done = done;
233 animation->data = data;
234 animation->start = start;
235 animation->stop = stop;
236 animation->private = private;
237
238 weston_matrix_init(&animation->transform.matrix);
239 wl_list_insert(&view->geometry.transformation_list,
240 &animation->transform.link);
241
242 animation->animation.frame = weston_view_animation_frame;
243
244 animation->listener.notify = handle_animation_view_destroy;
245 wl_signal_add(&view->destroy_signal, &animation->listener);
246
247 if (view->output) {
248 wl_list_insert(&view->output->animation_list,
249 &animation->animation.link);
250 } else {
251 wl_list_init(&animation->animation.link);
252 loop = wl_display_get_event_loop(ec->wl_display);
253 wl_event_loop_add_idle(loop, idle_animation_destroy, animation);
254 }
255
256 return animation;
257 }
258
259 static void
weston_view_animation_run(struct weston_view_animation * animation)260 weston_view_animation_run(struct weston_view_animation *animation)
261 {
262 struct timespec zero_time = { 0 };
263
264 animation->animation.frame_counter = 0;
265 weston_view_animation_frame(&animation->animation, NULL, &zero_time);
266 }
267
268 static void
reset_alpha(struct weston_view_animation * animation)269 reset_alpha(struct weston_view_animation *animation)
270 {
271 struct weston_view *view = animation->view;
272
273 view->alpha = animation->stop;
274 }
275
276 static void
zoom_frame(struct weston_view_animation * animation)277 zoom_frame(struct weston_view_animation *animation)
278 {
279 struct weston_view *es = animation->view;
280 float scale;
281
282 scale = animation->start +
283 (animation->stop - animation->start) *
284 animation->spring.current;
285 weston_matrix_init(&animation->transform.matrix);
286 weston_matrix_translate(&animation->transform.matrix,
287 -0.5f * es->surface->width,
288 -0.5f * es->surface->height, 0);
289 weston_matrix_scale(&animation->transform.matrix, scale, scale, scale);
290 weston_matrix_translate(&animation->transform.matrix,
291 0.5f * es->surface->width,
292 0.5f * es->surface->height, 0);
293
294 es->alpha = animation->spring.current;
295 if (es->alpha > 1.0)
296 es->alpha = 1.0;
297 }
298
299 WL_EXPORT struct weston_view_animation *
weston_zoom_run(struct weston_view * view,float start,float stop,weston_view_animation_done_func_t done,void * data)300 weston_zoom_run(struct weston_view *view, float start, float stop,
301 weston_view_animation_done_func_t done, void *data)
302 {
303 struct weston_view_animation *zoom;
304
305 zoom = weston_view_animation_create(view, start, stop,
306 zoom_frame, reset_alpha,
307 done, data, NULL);
308
309 if (zoom == NULL)
310 return NULL;
311
312 weston_spring_init(&zoom->spring, 300.0, start, stop);
313 zoom->spring.friction = 1400;
314 zoom->spring.previous = start - (stop - start) * 0.03;
315
316 weston_view_animation_run(zoom);
317
318 return zoom;
319 }
320
321 static void
fade_frame(struct weston_view_animation * animation)322 fade_frame(struct weston_view_animation *animation)
323 {
324 if (animation->spring.current > 0.999)
325 animation->view->alpha = 1;
326 else if (animation->spring.current < 0.001 )
327 animation->view->alpha = 0;
328 else
329 animation->view->alpha = animation->spring.current;
330 }
331
332 WL_EXPORT struct weston_view_animation *
weston_fade_run(struct weston_view * view,float start,float end,float k,weston_view_animation_done_func_t done,void * data)333 weston_fade_run(struct weston_view *view,
334 float start, float end, float k,
335 weston_view_animation_done_func_t done, void *data)
336 {
337 struct weston_view_animation *fade;
338
339 fade = weston_view_animation_create(view, start, end,
340 fade_frame, reset_alpha,
341 done, data, NULL);
342
343 if (fade == NULL)
344 return NULL;
345
346 weston_spring_init(&fade->spring, 1000.0, start, end);
347 fade->spring.friction = 4000;
348 fade->spring.previous = start - (end - start) * 0.1;
349
350 view->alpha = start;
351
352 weston_view_animation_run(fade);
353
354 return fade;
355 }
356
357 WL_EXPORT void
weston_fade_update(struct weston_view_animation * fade,float target)358 weston_fade_update(struct weston_view_animation *fade, float target)
359 {
360 fade->spring.target = target;
361 fade->stop = target;
362 }
363
364 static void
stable_fade_frame(struct weston_view_animation * animation)365 stable_fade_frame(struct weston_view_animation *animation)
366 {
367 struct weston_view *back_view;
368
369 if (animation->spring.current > 0.999)
370 animation->view->alpha = 1;
371 else if (animation->spring.current < 0.001 )
372 animation->view->alpha = 0;
373 else
374 animation->view->alpha = animation->spring.current;
375
376 back_view = (struct weston_view *) animation->private;
377 back_view->alpha =
378 (animation->spring.target - animation->view->alpha) /
379 (1.0 - animation->view->alpha);
380 weston_view_geometry_dirty(back_view);
381 }
382
383 WL_EXPORT struct weston_view_animation *
weston_stable_fade_run(struct weston_view * front_view,float start,struct weston_view * back_view,float end,weston_view_animation_done_func_t done,void * data)384 weston_stable_fade_run(struct weston_view *front_view, float start,
385 struct weston_view *back_view, float end,
386 weston_view_animation_done_func_t done, void *data)
387 {
388 struct weston_view_animation *fade;
389
390 fade = weston_view_animation_create(front_view, 0, 0,
391 stable_fade_frame, NULL,
392 done, data, back_view);
393
394 if (fade == NULL)
395 return NULL;
396
397 weston_spring_init(&fade->spring, 400, start, end);
398 fade->spring.friction = 1150;
399
400 front_view->alpha = start;
401 back_view->alpha = end;
402
403 weston_view_animation_run(fade);
404
405 return fade;
406 }
407
408 static void
slide_frame(struct weston_view_animation * animation)409 slide_frame(struct weston_view_animation *animation)
410 {
411 float scale;
412
413 scale = animation->start +
414 (animation->stop - animation->start) *
415 animation->spring.current;
416 weston_matrix_init(&animation->transform.matrix);
417 weston_matrix_translate(&animation->transform.matrix, 0, scale, 0);
418 }
419
420 WL_EXPORT struct weston_view_animation *
weston_slide_run(struct weston_view * view,float start,float stop,weston_view_animation_done_func_t done,void * data)421 weston_slide_run(struct weston_view *view, float start, float stop,
422 weston_view_animation_done_func_t done, void *data)
423 {
424 struct weston_view_animation *animation;
425
426 animation = weston_view_animation_create(view, start, stop,
427 slide_frame, NULL, done,
428 data, NULL);
429 if (!animation)
430 return NULL;
431
432 weston_spring_init(&animation->spring, 400.0, 0.0, 1.0);
433 animation->spring.friction = 600;
434 animation->spring.clip = WESTON_SPRING_BOUNCE;
435
436 weston_view_animation_run(animation);
437
438 return animation;
439 }
440
441 struct weston_move_animation {
442 int dx;
443 int dy;
444 bool reverse;
445 bool scale;
446 weston_view_animation_done_func_t done;
447 };
448
449 static void
move_frame(struct weston_view_animation * animation)450 move_frame(struct weston_view_animation *animation)
451 {
452 struct weston_move_animation *move = animation->private;
453 float scale;
454 float progress = animation->spring.current;
455
456 if (move->reverse)
457 progress = 1.0 - progress;
458
459 scale = animation->start +
460 (animation->stop - animation->start) *
461 progress;
462 weston_matrix_init(&animation->transform.matrix);
463 if (move->scale)
464 weston_matrix_scale(&animation->transform.matrix, scale, scale,
465 1.0f);
466 weston_matrix_translate(&animation->transform.matrix,
467 move->dx * progress, move->dy * progress,
468 0);
469 }
470
471 static void
move_done(struct weston_view_animation * animation,void * data)472 move_done(struct weston_view_animation *animation, void *data)
473 {
474 struct weston_move_animation *move = animation->private;
475
476 if (move->done)
477 move->done(animation, data);
478
479 free(move);
480 }
481
482 static struct weston_view_animation *
weston_move_scale_run_internal(struct weston_view * view,int dx,int dy,float start,float end,bool reverse,bool scale,weston_view_animation_done_func_t done,void * data)483 weston_move_scale_run_internal(struct weston_view *view, int dx, int dy,
484 float start, float end, bool reverse, bool scale,
485 weston_view_animation_done_func_t done,
486 void *data)
487 {
488 struct weston_move_animation *move;
489 struct weston_view_animation *animation;
490
491 move = malloc(sizeof(*move));
492 if (!move)
493 return NULL;
494 move->dx = dx;
495 move->dy = dy;
496 move->reverse = reverse;
497 move->scale = scale;
498 move->done = done;
499
500 animation = weston_view_animation_create(view, start, end, move_frame,
501 NULL, move_done, data, move);
502
503 if (animation == NULL){
504 free(move);
505 return NULL;
506 }
507
508 weston_spring_init(&animation->spring, 400.0, 0.0, 1.0);
509 animation->spring.friction = 1150;
510
511 weston_view_animation_run(animation);
512
513 return animation;
514 }
515
516 WL_EXPORT struct weston_view_animation *
weston_move_scale_run(struct weston_view * view,int dx,int dy,float start,float end,bool reverse,weston_view_animation_done_func_t done,void * data)517 weston_move_scale_run(struct weston_view *view, int dx, int dy,
518 float start, float end, bool reverse,
519 weston_view_animation_done_func_t done, void *data)
520 {
521 return weston_move_scale_run_internal(view, dx, dy, start, end, reverse,
522 true, done, data);
523 }
524
525 WL_EXPORT struct weston_view_animation *
weston_move_run(struct weston_view * view,int dx,int dy,float start,float end,bool reverse,weston_view_animation_done_func_t done,void * data)526 weston_move_run(struct weston_view *view, int dx, int dy,
527 float start, float end, bool reverse,
528 weston_view_animation_done_func_t done, void *data)
529 {
530 return weston_move_scale_run_internal(view, dx, dy, start, end, reverse,
531 false, done, data);
532 }
533