325274e48fa320e31b5afadd12ab79549aee1987
[platform/core/uifw/libpui.git] / src / PUI_ani.c
1 /*
2  * Copyright © 2019 Samsung Electronics co., Ltd. All Rights Reserved.
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 "PUI_internal.h"
27 #include "PUI_backend.h"
28 #include "PUI.h"
29 #include <Eina.h>
30
31 pui_int_error
32 _pui_ani_error_to_int_error(pui_error e)
33 {
34         pui_int_error ei;
35
36         switch (e)
37         {
38                 case PUI_ERROR_NONE:
39                         ei = PUI_INT_ERROR_NONE;
40                         break;
41
42                 case PUI_ERROR_INVALID_HANDLE:
43                         ei = PUI_INT_ERROR_INVALID_HANDLE;
44                         break;
45
46                 case PUI_ERROR_INVALID_SURFACE:
47                         ei = PUI_INT_ERROR_INVALID_SURFACE;
48                         break;
49
50                 case PUI_ERROR_INVALID_BUFFER:
51                         ei = PUI_INT_ERROR_INVALID_BUFFER;
52                         break;
53
54                 default:
55                         ei = PUI_INT_ERROR_UNKNOWN;
56                         break;
57         }
58
59         return ei;
60 }
61
62 static void
63 _pui_ani_cb_frame_done(Ecore_Wl2_Window *win, uint32_t timestamp EINA_UNUSED, void *data)
64 {
65         pui_h handle = (pui_h) data;
66
67         pui_info("Frame done ! (window=0x%x)\n", ecore_wl2_window_id_get(win));
68
69         /* TODO : make use of handle */
70         (void) handle;
71
72         return;
73 }
74
75 pui_ani_control_buffer *
76 pui_ani_get_buffer(pui_ani_h ani_h)
77 {
78         pui_h handle = NULL;
79         pui_ani_control_buffer *buffer = NULL;
80
81         if (!ani_h)
82         {
83                 pui_err("Invalid pui ani handle !\n");
84                 return NULL;
85         }
86
87         handle = ani_h->pui_handle;
88         buffer = pui_display_get_buffer(handle);
89
90         return buffer;
91 }
92
93 pui_int_error
94 pui_ani_set_buffer(pui_ani_h ani_h, pui_ani_control_buffer *buffer)
95 {
96         pui_error e = PUI_ERROR_NONE;
97         pui_h handle = NULL;
98
99         handle = ani_h->pui_handle;
100         e = pui_display_set_buffer(handle, buffer);
101
102         return _pui_ani_error_to_int_error(e);
103 }
104
105 pui_int_error
106 pui_ani_update(pui_ani_h ani_h)
107 {
108         pui_error e = PUI_ERROR_NONE;
109         pui_h handle = NULL;
110
111         if (!ani_h)
112         {
113                 pui_err("Invalid ani handle !\n");
114                 return PUI_INT_ERROR_INVALID_HANDLE;
115         }
116
117         handle = ani_h->pui_handle;
118         e = pui_display_update(handle);
119
120         return _pui_ani_error_to_int_error(e);
121 }
122
123 static Eina_Bool
124 _pui_ani_frame_cb(void *data)
125 {
126         Eina_Bool ret;
127         Ecore_Timer *timer = NULL;
128
129         pui_ani_t *ani = (pui_ani_t *)data;
130
131         if (!ani)
132         {
133                 pui_err("Invalid pui ani !\n");
134                 return ECORE_CALLBACK_CANCEL;
135         }
136
137         if (!ani->backend_frame_cb)
138         {
139                 pui_err("Invalid backend frame_cb !\n");
140                 return ECORE_CALLBACK_CANCEL;
141         }
142
143         if (!ani->frame_cb_timer)
144         {
145                 pui_err("Invalid frame_cb timer !\n");
146                 return ECORE_CALLBACK_CANCEL;
147         }
148
149         pui_info("...\n");
150
151         ret = (Eina_Bool)ani->backend_frame_cb(ani, ++ani->serial);
152
153         if (!ret)
154         {
155                 pui_err("Failed on backend's frame_cb !Frame_cb will be removed forcefuly !\n");
156
157                 pui_ani_remove_frame_cb(ani);
158
159                 return EINA_FALSE;
160         }
161
162         if (ret && PUI_ANI_STATUS_STARTED == ani->status)
163                 pui_ani_status_update(ani, PUI_ANI_STATUS_RUNNING);
164
165         ecore_timer_del(ani->frame_cb_timer);
166         ani->frame_cb_timer = NULL;
167
168         timer = ecore_timer_add(ani->frame_interval, _pui_ani_frame_cb, ani);
169
170         if (!timer)
171         {
172                 pui_err("Failed to add ecore timer !\n");
173                 return 0;
174         }
175
176         ani->frame_cb_timer = timer;
177
178         return EINA_FALSE;
179 }
180
181 pui_bool
182 pui_ani_add_frame_cb(pui_ani_t *ani, pui_bool (*frame_cb)(void *data, int serial), double frame_interval)
183 {
184         Ecore_Timer *timer = NULL;
185
186         if (!ani)
187         {
188                 pui_err("Invalid put ani !\n");
189                 return 0;
190         }
191
192         if (frame_interval <= 0.0f)
193         {
194                 pui_err("Invalid frame interval (%.2f) ! frame interval must be larger than 0.\n", frame_interval);
195                 return 0;
196         }
197
198         ani->frame_cb = _pui_ani_frame_cb;
199         ani->backend_frame_cb = frame_cb;
200         ani->frame_interval = frame_interval;
201         ani->frame_cb_data = ani;
202         ani->serial = 0;
203
204         timer = ecore_timer_add(frame_interval, _pui_ani_frame_cb, ani);
205
206         if (!timer)
207         {
208                 pui_err("Failed to add ecore timer !\n");
209                 return 0;
210         }
211
212         ani->frame_cb_timer = timer;
213
214         pui_info("[Frame callback added][ani id=%s] frame_interval=%.2f\n", ani->id, frame_interval);
215
216         /* call frame_cb for starting the first frame */
217         _pui_ani_frame_cb(ani);
218
219         return 1;
220 }
221
222 void
223 pui_ani_remove_frame_cb(pui_ani_t *ani)
224 {
225         if (!ani)
226         {
227                 pui_err("Invalid put ani !\n");
228                 return;
229         }
230
231         if (ani->frame_cb_timer)
232         {
233                 ecore_timer_del(ani->frame_cb_timer);
234                 ani->frame_cb_timer = NULL;
235         }
236
237         ani->frame_cb = NULL;
238         ani->backend_frame_cb = NULL;
239         ani->frame_interval = 0;
240         ani->frame_cb_data = NULL;
241
242         pui_info("[Frame callback removed][ani id=%s]\n", ani->id);
243 }
244
245 pui_id
246 pui_ani_get_id(pui_ani_h ani_h)
247 {
248         if (!ani_h || !ani_h->ani)
249                 return NULL;
250
251         return ani_h->ani->id;
252 }
253
254 pui_ani_cmd
255 pui_ani_get_cmd(pui_ani_h ani_h)
256 {
257         if (!ani_h || !ani_h->ani)
258                 return PUI_ANI_CMD_NONE;
259
260         return ani_h->ani->cmd;
261 }
262
263 int
264 pui_ani_get_repeat(pui_ani_h ani_h)
265 {
266         if (!ani_h || !ani_h->ani)
267                 return 0;
268
269         return ani_h->ani->repeat;
270 }
271
272 pui_backend_ani_data *
273 pui_ani_get_ani_data(pui_ani_t *ani)
274 {
275         if (!ani)
276                 return NULL;
277
278         return ani->ani_data;
279 }
280
281 void
282 pui_ani_status_update(pui_ani_t *ani, pui_ani_status status)
283 {
284         int ev_type = -1;
285         pui_ani_h ani_h;
286         PUI_Event_Animation_Status *e = NULL;
287
288         if (!ani)
289         {
290                 pui_err("Invalid pui ani !\n");
291                 return;
292         }
293
294         if (ani->status == status)
295                 return;
296
297         ani_h = ani->ani_h;
298
299         ani->status = status;
300
301         switch (status)
302         {
303                 case PUI_ANI_STATUS_STARTED:
304                         ev_type = PUI_EVENT_ANI_STARTED;
305                         pui_info("[Status update][ani id:%s] PUI_EVENT_ANI_STARTED event has been added.\n", ani->id);
306                         break;
307
308                 case PUI_ANI_STATUS_RUNNING:
309                         pui_info("[Status update][ani id:%s] PUI_ANI_STATUS_RUNNING !\n", ani->id);
310                         break;
311
312                 case PUI_ANI_STATUS_PAUSED:
313                         ev_type = PUI_EVENT_ANI_PAUSED;
314                         pui_info("[Status update][ani id:%s] PUI_EVENT_ANI_PAUSED event has been added.\n", ani->id);
315                         break;
316
317                 case PUI_ANI_STATUS_STOPPED:
318                         ev_type = PUI_EVENT_ANI_STOPPED;
319                         pui_info("[Status update][ani id:%s] PUI_EVENT_ANI_STOPPED event has been added.\n", ani->id);
320                         break;
321
322                 default:
323                         pui_err("Unknown status !(ani status=%d, id=%s) !\n", status, ani->id);
324                         return;
325         }
326
327         if (ev_type > 0)
328         {
329                 e = (PUI_Event_Animation_Status *)calloc(1, sizeof(PUI_Event_Animation_Status));
330
331                 if (!e)
332                 {
333                         pui_err("Failed to allocate memory for PUI Event !\n");
334                         return;
335                 }
336
337                 e->ani_h = ani_h;
338                 e->win = ecore_wl2_window_id_get(ani_h->pui_handle->win);
339                 e->status = status;
340
341                 ecore_event_add(ev_type, e, NULL, ani_h);
342         }
343 }
344
345 pui_ani_status
346 pui_ani_status_get(pui_ani_t *ani)
347 {
348         pui_ani_status status = PUI_ANI_STATUS_UNKNOWN;
349
350         if (!ani)
351         {
352                 pui_err("Invalid pui ani !\n");
353                 return status;
354         }
355
356         return ani->status;
357 }
358
359 static pui_error
360 _pui_ani_control_with_force(pui_ani_h ani_h, pui_ani_cmd cmd, int repeat, pui_bool force)
361 {
362         pui_int_error ei = PUI_INT_ERROR_NONE;
363         pui_ani_t *ani = NULL;
364         pui_h handle = NULL;
365         pui_backend_ani_func *ani_func = NULL;
366
367         if (!ani_h)
368                 return PUI_ERROR_INVALID_ANI_HANDLE;
369
370         if (cmd < PUI_ANI_CMD_START || cmd >= PUI_ANI_CMD_LAST)
371         {
372                 pui_err("Invalid cmd ! (cmd=%d)\n", cmd);
373                 return PUI_ERROR_INVALID_ANI_CMD;
374         }
375
376         if (repeat < -1)
377         {
378                 pui_err("Invalid repeat count ! (repeat=%d)\n", repeat);
379                 return PUI_ERROR_INVALID_ANI_REPEAT;
380         }
381
382         handle = ani_h->pui_handle;
383         ani = ani_h->ani;
384
385         if (!ani || !ani->ani_data)
386         {
387                 pui_err("Invalid ani or ani_data !\n");
388                 return PUI_ERROR_INTERNAL;
389         }
390
391         ani_func = ani->ani_data->ani_func;
392
393         ani->cmd = cmd;
394         ani->repeat = repeat;
395
396         if (cmd == PUI_ANI_CMD_START)
397         {
398                 if (handle->manual_render)
399                 {
400                         pui_err("Manual render has been set ! Unable to start animation.\n");
401                         return PUI_ERROR_MANUAL_RENDER_ENABLED;
402                 }
403
404                 if (handle->current_ani_h && handle->current_ani_h != ani_h)
405                 {
406                         pui_ani_t *current_ani = handle->current_ani_h->ani;
407
408                         if (current_ani->status >= PUI_ANI_STATUS_STARTED &&
409                                 current_ani->status <= PUI_ANI_STATUS_RUNNING)
410                         {
411                                 pui_info("current_ani id=%s, status=%d\n", current_ani->id, current_ani->status);
412
413                                 ei = _pui_ani_control_with_force(handle->current_ani_h, PUI_ANI_CMD_STOP, 0, force);
414
415                                 if (ei != PUI_INT_ERROR_NONE)
416                                         pui_info("Failed to stop running previous animation ! (id:%s)\n", current_ani->id);
417
418                                 current_ani = NULL;
419                                 handle->current_ani_h = NULL;
420                         }
421                 }
422
423                 ei = ani_func->ani_start(ani, repeat);
424
425                 if (ei != PUI_INT_ERROR_NONE)
426                 {
427                         pui_err("Error on starting animation ! (id:%s, repeat:%d, status=%d))\n", ani->id, repeat, ani->status);
428
429                         if (ani->status != PUI_ANI_STATUS_RUNNING)
430                                 _pui_ani_control_with_force(ani_h, PUI_ANI_CMD_STOP, 0, 0);
431
432                         return PUI_ERROR_INTERNAL;
433                 }
434
435                 handle->current_ani_h = ani_h;
436         }
437         else//cmd == PUI_ANI_CMD_STOP
438         {
439                 ei = ani_func->ani_stop(ani, force);
440
441                 if (ani->frame_cb_timer)
442                         pui_ani_remove_frame_cb(ani);
443
444                 if (ei != PUI_INT_ERROR_NONE)
445                 {
446                         pui_err("Failied on stopping animation ! (id:%s)\n", ani->id);
447
448                         if (ani->status != PUI_ANI_STATUS_STOPPED)
449                                 pui_ani_status_update(ani, PUI_ANI_STATUS_STOPPED);
450
451                         return PUI_ERROR_INTERNAL;
452                 }
453
454                 return PUI_ERROR_NONE;
455         }
456
457         ani_h->frame_done_cb = ecore_wl2_window_frame_callback_add(handle->win, _pui_ani_cb_frame_done, handle);
458
459         if (!ani_h->frame_done_cb)
460         {
461                 pui_err("Failed to add frame callback !");
462                 goto err;
463         }
464
465         return PUI_ERROR_NONE;
466
467 err:
468         return PUI_ERROR_INTERNAL;
469 }
470
471 pui_error
472 pui_ani_control(pui_ani_h ani_h, pui_ani_cmd cmd, int repeat)
473 {
474         return _pui_ani_control_with_force(ani_h, cmd, repeat, 0);
475 }
476
477 static Eina_Bool
478 _cb_visibility_change(void *data, int type EINA_UNUSED, void *event)
479 {
480         pui_ani_h ani_h =  (pui_ani_h)data;
481         pui_ani_t *ani = ani_h->ani;
482         pui_h ph = ani_h->pui_handle;
483
484         Ecore_Wl2_Event_Window_Visibility_Change *ev;
485         PUI_Event_Animation_Status *e = NULL;
486
487         ev = event;
488
489         /* check if this is needed */
490         ph->visibility = !(ev->fully_obscured);
491
492         if (ev->fully_obscured)
493         {
494                 if (ani->status == PUI_ANI_STATUS_RUNNING)
495                 {
496                         pui_info("animation(%s) will be stopped as it lost its priority !\n", ani->id);
497
498                         _pui_ani_control_with_force(ani_h, PUI_ANI_CMD_STOP, 0, 1);
499                 }
500         }
501         else
502         {
503                 if (ani->status == PUI_ANI_STATUS_PAUSED)
504                 {
505                         e = (PUI_Event_Animation_Status *)calloc(1, sizeof(PUI_Event_Animation_Status));
506
507                         if (!e)
508                         {
509                                 pui_err("Failed to allocate memory for PUI Event !\n");
510                                 return ECORE_CALLBACK_PASS_ON;
511                         }
512
513                         e->ani_h = ani_h;
514                         e->win = ev->win;
515                         e->status = ani->status;
516
517                         if(ani->status == PUI_ANI_STATUS_PAUSED)
518                         {
519                                 pui_info("[Event added][ani id:%s] PUI_EVENT_ANI_READY_TO_RESUME event has been added.\n", ani_h->id);
520                                 ecore_event_add(PUI_EVENT_ANI_READY_TO_RESUME, e, NULL, ani_h);
521                         }
522                 }
523         }
524
525         return ECORE_CALLBACK_PASS_ON;
526 }
527
528 static void
529 _pui_ani_event_handlers_init(pui_ani_h ani_h)
530 {
531         Ecore_Event_Handler *h = NULL;
532
533         if (!ani_h)
534         {
535                 pui_err("Invalid handle !\n");
536                 return;
537         }
538
539         if (!ani_h->ecore_event_hdls)
540                 ani_h->ecore_event_hdls = eina_array_new(1);
541
542         h = ecore_event_handler_add(ECORE_WL2_EVENT_WINDOW_VISIBILITY_CHANGE, _cb_visibility_change, ani_h);
543         eina_array_push(ani_h->ecore_event_hdls, h);
544
545 }
546
547 static void
548 _pui_ani_event_handlers_shutdown(pui_ani_h ani_h)
549 {
550         if (!ani_h)
551         {
552                 pui_err("Invalid handle !\n");
553                 return;
554         }
555
556         if (ani_h->ecore_event_hdls)
557         {
558                 while (eina_array_count(ani_h->ecore_event_hdls))
559                         ecore_event_handler_del(eina_array_pop(ani_h->ecore_event_hdls));
560
561                 eina_array_free(ani_h->ecore_event_hdls);
562                 ani_h->ecore_event_hdls = NULL;
563         }
564 }
565
566 pui_ani_h
567 pui_ani_create(pui_h handle, pui_id id)
568 {
569         pui_ani_h ani_h = NULL;
570         pui_ani_t *ani = NULL;
571         pui_backend_ani_data *ani_data = NULL;
572
573         if (!handle || !handle->backend_module_data)
574         {
575                 pui_err("Invalid pui handle or backend module data !\n");
576                 return NULL;
577         }
578
579         ani_data = handle->backend_module_data->ani_create(id);
580
581         if (!ani_data)
582         {
583                 pui_err("Invalid ani data from backend module data !\n");
584                 return NULL;
585         }
586
587         ani_h = (pui_ani_h)calloc(1, sizeof(pui_ani));
588
589         if (!ani_h)
590         {
591                 pui_err("Failed to allocate memory for pui ani handle !\n");
592                 goto err;
593         }
594
595         ani_h->id = strdup(id);
596         ani_h->pui_handle = handle;
597         ani_h->ecore_event_hdls = NULL;
598
599         _pui_ani_event_handlers_init(ani_h);
600
601         ani = (pui_ani_t *)calloc(1, sizeof(pui_ani_t));
602
603         if (!ani)
604         {
605                 pui_err("Failed to allocate memory for pui ani mgr !\n");
606                 goto err;
607         }
608
609         ani->ani_h = ani_h;
610         ani->id = id;
611         ani->cmd = PUI_ANI_CMD_NONE;
612         ani->repeat = 0;
613         ani->status = PUI_ANI_STATUS_INITIAL;
614         ani->ani_data = ani_data;
615
616         ani_h->ani = ani;
617
618         handle->ani_handles = eina_list_append(handle->ani_handles, ani_h);
619
620         return ani_h;
621
622 err:
623         if (ani_data)
624         {
625                 handle->backend_module_data->ani_destroy(ani_data);
626         }
627
628         if (ani_h)
629                 free(ani_h);
630
631         return NULL;
632 }
633
634 void
635 pui_ani_destroy(pui_ani_h ani_h)
636 {
637         pui_h handle = NULL;
638         pui_ani_t *ani = NULL;
639         pui_backend_module_data *backend_module_data = NULL;
640
641         if (!ani_h || !ani_h->pui_handle)
642                 return;
643
644         handle = ani_h->pui_handle;
645         ani = ani_h->ani;
646
647         /* stop the animation being played already if any */
648         if (ani->status == PUI_ANI_STATUS_STARTED || ani->status == PUI_ANI_STATUS_RUNNING)
649                 pui_ani_control(ani_h, PUI_ANI_CMD_STOP, 0);
650
651         backend_module_data = handle->backend_module_data;
652         backend_module_data->ani_destroy(ani->ani_data);
653         ani->ani_data = NULL;
654
655         if (ani->frame_cb_timer)
656         {
657                 ecore_timer_del(ani->frame_cb_timer);
658                 ani->frame_cb_timer = NULL;
659         }
660
661         free(ani_h->ani);
662
663         _pui_ani_event_handlers_shutdown(ani_h);
664
665         if (ani_h->frame_done_cb)
666         {
667                 ecore_wl2_window_frame_callback_del(ani_h->frame_done_cb);
668                 ani_h->frame_done_cb = NULL;
669         }
670
671         handle->ani_handles = eina_list_remove(handle->ani_handles, ani_h);
672
673         free(ani_h->id);
674         free(ani_h);
675 }
676