backend: add default clear animations
[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_last_buffer(pui_ani_h ani_h)
77 {
78         pui_h handle = NULL;
79         pui_ani_control_buffer *buffer = NULL;
80
81         if (!PUI_MAGIC_CHECK(ani_h, PUI_MAGIC_ANI_H))
82         {
83                 PUI_MAGIC_FAIL(ani_h, PUI_MAGIC_ANI_H, __FUNCTION__);
84                 return NULL;
85         }
86
87         handle = ani_h->pui_handle;
88         buffer = pui_display_get_last_buffer(handle);
89
90         return buffer;
91 }
92
93 pui_ani_control_buffer *
94 pui_ani_get_buffer(pui_ani_h ani_h)
95 {
96         pui_h handle = NULL;
97         pui_ani_control_buffer *buffer = NULL;
98
99         if (!PUI_MAGIC_CHECK(ani_h, PUI_MAGIC_ANI_H))
100         {
101                 PUI_MAGIC_FAIL(ani_h, PUI_MAGIC_ANI_H, __FUNCTION__);
102                 return NULL;
103         }
104
105         handle = ani_h->pui_handle;
106         buffer = pui_display_get_buffer(handle);
107
108         return buffer;
109 }
110
111 pui_int_error
112 pui_ani_set_buffer(pui_ani_h ani_h, pui_ani_control_buffer *buffer)
113 {
114         pui_error e = PUI_ERROR_NONE;
115         pui_h handle = NULL;
116
117         if (!PUI_MAGIC_CHECK(ani_h, PUI_MAGIC_ANI_H))
118         {
119                 PUI_MAGIC_FAIL(ani_h, PUI_MAGIC_ANI_H, __FUNCTION__);
120                 return PUI_ERROR_INVALID_HANDLE;
121         }
122
123         handle = ani_h->pui_handle;
124
125         if (!PUI_MAGIC_CHECK(handle, PUI_MAGIC_PUI_H))
126         {
127                 PUI_MAGIC_FAIL(handle, PUI_MAGIC_PUI_H, __FUNCTION__);
128                 return PUI_ERROR_INVALID_HANDLE;
129         }
130
131         e = pui_display_set_buffer(handle, buffer);
132
133         return _pui_ani_error_to_int_error(e);
134 }
135
136 pui_int_error
137 pui_ani_update(pui_ani_h ani_h)
138 {
139         pui_error e = PUI_ERROR_NONE;
140         pui_h handle = NULL;
141
142         if (!ani_h)
143         {
144                 pui_err("Invalid ani handle !\n");
145                 return PUI_INT_ERROR_INVALID_HANDLE;
146         }
147
148         handle = ani_h->pui_handle;
149         e = pui_display_update(handle);
150
151         return _pui_ani_error_to_int_error(e);
152 }
153
154 static Eina_Bool
155 _pui_ani_frame_cb(void *data)
156 {
157         Eina_Bool ret;
158         Ecore_Timer *timer = NULL;
159
160         pui_ani_t *ani = (pui_ani_t *)data;
161
162         if (!PUI_MAGIC_CHECK(ani, PUI_MAGIC_ANI_T))
163         {
164                 PUI_MAGIC_FAIL(ani, PUI_MAGIC_ANI_T, __FUNCTION__);
165                 return ECORE_CALLBACK_CANCEL;
166         }
167
168         if (!ani->backend_frame_cb)
169         {
170                 pui_err("Invalid backend frame_cb !\n");
171                 return ECORE_CALLBACK_CANCEL;
172         }
173
174         if (!ani->frame_cb_timer)
175         {
176                 pui_err("Invalid frame_cb timer !\n");
177                 return ECORE_CALLBACK_CANCEL;
178         }
179
180         pui_info("...\n");
181
182         ret = (Eina_Bool)ani->backend_frame_cb(ani, ++ani->serial);
183
184         if (!ret)
185         {
186                 pui_err("Failed on backend's frame_cb !Frame_cb will be removed forcefuly !\n");
187
188                 pui_ani_remove_frame_cb(ani);
189
190                 return EINA_FALSE;
191         }
192
193         if (ret && PUI_ANI_STATUS_STARTED == ani->status)
194                 pui_ani_status_update(ani, PUI_ANI_STATUS_RUNNING);
195
196         ecore_timer_del(ani->frame_cb_timer);
197         ani->frame_cb_timer = NULL;
198
199         timer = ecore_timer_add(ani->frame_interval, _pui_ani_frame_cb, ani);
200
201         if (!timer)
202         {
203                 pui_err("Failed to add ecore timer !\n");
204                 return 0;
205         }
206
207         ani->frame_cb_timer = timer;
208
209         return EINA_FALSE;
210 }
211
212 pui_bool
213 pui_ani_add_frame_cb(pui_ani_t *ani, pui_bool (*frame_cb)(void *data, int serial), double frame_interval)
214 {
215         Ecore_Timer *timer = NULL;
216
217         if (!PUI_MAGIC_CHECK(ani, PUI_MAGIC_ANI_T))
218         {
219                 PUI_MAGIC_FAIL(ani, PUI_MAGIC_ANI_T, __FUNCTION__);
220                 return 0;
221         }
222
223         if (frame_interval <= 0.0f)
224         {
225                 pui_err("Invalid frame interval (%.2f) ! frame interval must be larger than 0.\n", frame_interval);
226                 return 0;
227         }
228
229         ani->frame_cb = _pui_ani_frame_cb;
230         ani->backend_frame_cb = frame_cb;
231         ani->frame_interval = frame_interval;
232         ani->frame_cb_data = ani;
233         ani->serial = 0;
234
235         timer = ecore_timer_add(frame_interval, _pui_ani_frame_cb, ani);
236
237         if (!timer)
238         {
239                 pui_err("Failed to add ecore timer !\n");
240                 return 0;
241         }
242
243         ani->frame_cb_timer = timer;
244
245         pui_info("[Frame callback added][ani id=%s] frame_interval=%.2f\n", ani->id, frame_interval);
246
247         /* call frame_cb for starting the first frame */
248         _pui_ani_frame_cb(ani);
249
250         return 1;
251 }
252
253 void
254 pui_ani_remove_frame_cb(pui_ani_t *ani)
255 {
256         if (!PUI_MAGIC_CHECK(ani, PUI_MAGIC_ANI_T))
257         {
258                 PUI_MAGIC_FAIL(ani, PUI_MAGIC_ANI_T, __FUNCTION__);
259                 return;
260         }
261
262         if (ani->frame_cb_timer)
263         {
264                 ecore_timer_del(ani->frame_cb_timer);
265                 ani->frame_cb_timer = NULL;
266         }
267
268         ani->frame_cb = NULL;
269         ani->backend_frame_cb = NULL;
270         ani->frame_interval = 0;
271         ani->frame_cb_data = NULL;
272
273         pui_info("[Frame callback removed][ani id=%s]\n", ani->id);
274 }
275
276 pui_id
277 pui_ani_get_id(pui_ani_h ani_h)
278 {
279         if (!PUI_MAGIC_CHECK(ani_h, PUI_MAGIC_ANI_H))
280         {
281                 PUI_MAGIC_FAIL(ani_h, PUI_MAGIC_ANI_H, __FUNCTION__);
282                 return NULL;
283         }
284
285         if (!PUI_MAGIC_CHECK(ani_h->ani, PUI_MAGIC_ANI_T))
286         {
287                 PUI_MAGIC_FAIL(ani_h->ani, PUI_MAGIC_ANI_T, __FUNCTION__);
288                 return NULL;
289         }
290
291         return ani_h->ani->id;
292 }
293
294 pui_ani_cmd
295 pui_ani_get_cmd(pui_ani_h ani_h)
296 {
297         if (!PUI_MAGIC_CHECK(ani_h, PUI_MAGIC_ANI_H))
298         {
299                 PUI_MAGIC_FAIL(ani_h, PUI_MAGIC_ANI_H, __FUNCTION__);
300                 return PUI_ANI_CMD_NONE;
301         }
302
303         if (!PUI_MAGIC_CHECK(ani_h->ani, PUI_MAGIC_ANI_T))
304         {
305                 PUI_MAGIC_FAIL(ani_h->ani, PUI_MAGIC_ANI_T, __FUNCTION__);
306                 return PUI_ANI_CMD_NONE;
307         }
308
309         return ani_h->ani->cmd;
310 }
311
312 int
313 pui_ani_get_repeat(pui_ani_h ani_h)
314 {
315         if (!PUI_MAGIC_CHECK(ani_h, PUI_MAGIC_ANI_H))
316         {
317                 PUI_MAGIC_FAIL(ani_h, PUI_MAGIC_ANI_H, __FUNCTION__);
318                 return 0;
319         }
320
321         if (!PUI_MAGIC_CHECK(ani_h->ani, PUI_MAGIC_ANI_T))
322         {
323                 PUI_MAGIC_FAIL(ani_h->ani, PUI_MAGIC_ANI_T, __FUNCTION__);
324                 return 0;
325         }
326
327         return ani_h->ani->repeat;
328 }
329
330 pui_backend_ani_data *
331 pui_ani_get_ani_data(pui_ani_t *ani)
332 {
333         if (!PUI_MAGIC_CHECK(ani, PUI_MAGIC_ANI_T))
334         {
335                 PUI_MAGIC_FAIL(ani, PUI_MAGIC_ANI_T, __FUNCTION__);
336                 return NULL;
337         }
338
339         return ani->ani_data;
340 }
341
342 void
343 pui_ani_status_update(pui_ani_t *ani, pui_ani_status status)
344 {
345         int ev_type = -1;
346         pui_ani_h ani_h;
347         PUI_Event_Animation_Status *e = NULL;
348
349         if (!PUI_MAGIC_CHECK(ani, PUI_MAGIC_ANI_T))
350         {
351                 PUI_MAGIC_FAIL(ani, PUI_MAGIC_ANI_T, __FUNCTION__);
352                 return;
353         }
354
355         if (ani->status == status)
356                 return;
357
358         ani_h = ani->ani_h;
359
360         ani->status = status;
361
362         switch (status)
363         {
364                 case PUI_ANI_STATUS_STARTED:
365                         ev_type = PUI_EVENT_ANI_STARTED;
366                         pui_info("[Status update][ani id:%s] PUI_EVENT_ANI_STARTED event has been added.\n", ani->id);
367                         break;
368
369                 case PUI_ANI_STATUS_RUNNING:
370                         pui_info("[Status update][ani id:%s] PUI_ANI_STATUS_RUNNING !\n", ani->id);
371                         break;
372
373                 case PUI_ANI_STATUS_PAUSED:
374                         ev_type = PUI_EVENT_ANI_PAUSED;
375                         pui_info("[Status update][ani id:%s] PUI_EVENT_ANI_PAUSED event has been added.\n", ani->id);
376                         break;
377
378                 case PUI_ANI_STATUS_STOPPED:
379                         ev_type = PUI_EVENT_ANI_STOPPED;
380                         pui_info("[Status update][ani id:%s] PUI_EVENT_ANI_STOPPED event has been added.\n", ani->id);
381                         break;
382
383                 default:
384                         pui_err("Unknown status !(ani status=%d, id=%s) !\n", status, ani->id);
385                         return;
386         }
387
388         if (ev_type > 0)
389         {
390                 e = (PUI_Event_Animation_Status *)calloc(1, sizeof(PUI_Event_Animation_Status));
391
392                 if (!e)
393                 {
394                         pui_err("Failed to allocate memory for PUI Event !\n");
395                         return;
396                 }
397
398                 e->ani_h = ani_h;
399                 e->win = ecore_wl2_window_id_get(ani_h->pui_handle->win);
400                 e->status = status;
401
402                 ecore_event_add(ev_type, e, NULL, ani_h);
403         }
404 }
405
406 pui_ani_status
407 pui_ani_status_get(pui_ani_t *ani)
408 {
409         pui_ani_status status = PUI_ANI_STATUS_UNKNOWN;
410
411         if (!PUI_MAGIC_CHECK(ani, PUI_MAGIC_ANI_T))
412         {
413                 PUI_MAGIC_FAIL(ani, PUI_MAGIC_ANI_T, __FUNCTION__);
414                 return status;
415         }
416
417         return ani->status;
418 }
419
420 static pui_error
421 _pui_ani_control_with_force(pui_ani_h ani_h, pui_ani_cmd cmd, int repeat, pui_bool force)
422 {
423         pui_int_error ei = PUI_INT_ERROR_NONE;
424         pui_ani_t *ani = NULL;
425         pui_h handle = NULL;
426         pui_backend_ani_func *ani_func = NULL;
427
428         if (!PUI_MAGIC_CHECK(ani_h, PUI_MAGIC_ANI_H))
429         {
430                 PUI_MAGIC_FAIL(ani_h, PUI_MAGIC_ANI_H, __FUNCTION__);
431                 return PUI_ERROR_INVALID_ANI_HANDLE;
432         }
433
434         if (cmd < PUI_ANI_CMD_START || cmd >= PUI_ANI_CMD_LAST)
435         {
436                 pui_err("Invalid cmd ! (cmd=%d)\n", cmd);
437                 return PUI_ERROR_INVALID_ANI_CMD;
438         }
439
440         if (repeat < -1)
441         {
442                 pui_err("Invalid repeat count ! (repeat=%d)\n", repeat);
443                 return PUI_ERROR_INVALID_ANI_REPEAT;
444         }
445
446         handle = ani_h->pui_handle;
447         ani = ani_h->ani;
448
449         if (!PUI_MAGIC_CHECK(handle, PUI_MAGIC_PUI_H))
450         {
451                 PUI_MAGIC_FAIL(handle, PUI_MAGIC_PUI_H, __FUNCTION__);
452                 return PUI_ERROR_INTERNAL;
453         }
454
455         if (!PUI_MAGIC_CHECK(ani, PUI_MAGIC_ANI_T))
456         {
457                 PUI_MAGIC_FAIL(ani, PUI_MAGIC_ANI_T, __FUNCTION__);
458                 return PUI_ERROR_INTERNAL;
459         }
460
461         if (!ani->ani_data)
462         {
463                 pui_err("Invalid ani_data !\n");
464                 return PUI_ERROR_INTERNAL;
465         }
466
467         ani_func = ani->ani_data->ani_func;
468
469         ani->cmd = cmd;
470         ani->repeat = repeat;
471
472         if (cmd == PUI_ANI_CMD_START)
473         {
474                 if (handle->manual_render)
475                 {
476                         pui_err("Manual render has been set ! Unable to start animation.\n");
477                         return PUI_ERROR_MANUAL_RENDER_ENABLED;
478                 }
479
480                 if (handle->current_ani_h && handle->current_ani_h != ani_h)
481                 {
482                         pui_ani_t *current_ani = handle->current_ani_h->ani;
483
484                         if (current_ani->status >= PUI_ANI_STATUS_STARTED &&
485                                 current_ani->status <= PUI_ANI_STATUS_RUNNING)
486                         {
487                                 pui_info("current_ani id=%s, status=%d\n", current_ani->id, current_ani->status);
488
489                                 ei = _pui_ani_control_with_force(handle->current_ani_h, PUI_ANI_CMD_STOP, 0, force);
490
491                                 if (ei != PUI_INT_ERROR_NONE)
492                                         pui_info("Failed to stop running previous animation ! (id:%s)\n", current_ani->id);
493
494                                 current_ani = NULL;
495                                 handle->current_ani_h = NULL;
496                         }
497                 }
498
499                 ei = ani_func->ani_start(ani, repeat);
500
501                 if (ei != PUI_INT_ERROR_NONE)
502                 {
503                         pui_err("Error on starting animation ! (id:%s, repeat:%d, status=%d))\n", ani->id, repeat, ani->status);
504
505                         if (ani->status != PUI_ANI_STATUS_RUNNING)
506                                 _pui_ani_control_with_force(ani_h, PUI_ANI_CMD_STOP, 0, 0);
507
508                         return PUI_ERROR_INTERNAL;
509                 }
510
511                 handle->current_ani_h = ani_h;
512         }
513         else//cmd == PUI_ANI_CMD_STOP
514         {
515                 ei = ani_func->ani_stop(ani, force);
516
517                 if (ani->frame_cb_timer)
518                         pui_ani_remove_frame_cb(ani);
519
520                 if (ei != PUI_INT_ERROR_NONE)
521                 {
522                         pui_err("Failied on stopping animation ! (id:%s)\n", ani->id);
523
524                         if (ani->status != PUI_ANI_STATUS_STOPPED)
525                                 pui_ani_status_update(ani, PUI_ANI_STATUS_STOPPED);
526
527                         return PUI_ERROR_INTERNAL;
528                 }
529
530                 return PUI_ERROR_NONE;
531         }
532
533         ani_h->frame_done_cb = ecore_wl2_window_frame_callback_add(handle->win, _pui_ani_cb_frame_done, handle);
534
535         if (!ani_h->frame_done_cb)
536         {
537                 pui_err("Failed to add frame callback !");
538                 goto err;
539         }
540
541         return PUI_ERROR_NONE;
542
543 err:
544         return PUI_ERROR_INTERNAL;
545 }
546
547 pui_error
548 pui_ani_control(pui_ani_h ani_h, pui_ani_cmd cmd, int repeat)
549 {
550         return _pui_ani_control_with_force(ani_h, cmd, repeat, 0);
551 }
552
553 static Eina_Bool
554 _cb_visibility_change(void *data, int type EINA_UNUSED, void *event)
555 {
556         pui_ani_h ani_h =  (pui_ani_h)data;
557         pui_ani_t *ani = ani_h->ani;
558         pui_h ph = ani_h->pui_handle;
559
560         Ecore_Wl2_Event_Window_Visibility_Change *ev;
561         PUI_Event_Animation_Status *e = NULL;
562
563         if (!PUI_MAGIC_CHECK(ani_h, PUI_MAGIC_ANI_H))
564         {
565                 PUI_MAGIC_FAIL(ani_h, PUI_MAGIC_ANI_H, __FUNCTION__);
566                 return ECORE_CALLBACK_PASS_ON;
567         }
568
569         if (!PUI_MAGIC_CHECK(ani, PUI_MAGIC_ANI_T))
570         {
571                 PUI_MAGIC_FAIL(ani, PUI_MAGIC_ANI_T, __FUNCTION__);
572                 return ECORE_CALLBACK_PASS_ON;
573         }
574
575         if (!PUI_MAGIC_CHECK(ph, PUI_MAGIC_PUI_H))
576         {
577                 PUI_MAGIC_FAIL(ph, PUI_MAGIC_PUI_H, __FUNCTION__);
578                 return ECORE_CALLBACK_PASS_ON;
579         }
580
581         ev = event;
582
583         /* check if this is needed */
584         ph->visibility = !(ev->fully_obscured);
585
586         if (ev->fully_obscured)
587         {
588                 if (ani->status == PUI_ANI_STATUS_RUNNING)
589                 {
590                         pui_info("animation(%s) will be stopped as it lost its priority !\n", ani->id);
591
592                         _pui_ani_control_with_force(ani_h, PUI_ANI_CMD_STOP, 0, 1);
593                 }
594         }
595         else
596         {
597                 if (ani->status == PUI_ANI_STATUS_PAUSED)
598                 {
599                         e = (PUI_Event_Animation_Status *)calloc(1, sizeof(PUI_Event_Animation_Status));
600
601                         if (!e)
602                         {
603                                 pui_err("Failed to allocate memory for PUI Event !\n");
604                                 return ECORE_CALLBACK_PASS_ON;
605                         }
606
607                         e->ani_h = ani_h;
608                         e->win = ev->win;
609                         e->status = ani->status;
610
611                         if(ani->status == PUI_ANI_STATUS_PAUSED)
612                         {
613                                 pui_info("[Event added][ani id:%s] PUI_EVENT_ANI_READY_TO_RESUME event has been added.\n", ani_h->id);
614                                 ecore_event_add(PUI_EVENT_ANI_READY_TO_RESUME, e, NULL, ani_h);
615                         }
616                 }
617         }
618
619         return ECORE_CALLBACK_PASS_ON;
620 }
621
622 static void
623 _pui_ani_event_handlers_init(pui_ani_h ani_h)
624 {
625         Ecore_Event_Handler *h = NULL;
626
627         if (!PUI_MAGIC_CHECK(ani_h, PUI_MAGIC_ANI_H))
628         {
629                 PUI_MAGIC_FAIL(ani_h, PUI_MAGIC_ANI_H, __FUNCTION__);
630                 return;
631         }
632
633         if (!ani_h->ecore_event_hdls)
634                 ani_h->ecore_event_hdls = eina_array_new(1);
635
636         h = ecore_event_handler_add(ECORE_WL2_EVENT_WINDOW_VISIBILITY_CHANGE, _cb_visibility_change, ani_h);
637         eina_array_push(ani_h->ecore_event_hdls, h);
638
639 }
640
641 static void
642 _pui_ani_event_handlers_shutdown(pui_ani_h ani_h)
643 {
644         if (!PUI_MAGIC_CHECK(ani_h, PUI_MAGIC_ANI_H))
645         {
646                 PUI_MAGIC_FAIL(ani_h, PUI_MAGIC_ANI_H, __FUNCTION__);
647                 return;
648         }
649
650         if (ani_h->ecore_event_hdls)
651         {
652                 while (eina_array_count(ani_h->ecore_event_hdls))
653                         ecore_event_handler_del(eina_array_pop(ani_h->ecore_event_hdls));
654
655                 eina_array_free(ani_h->ecore_event_hdls);
656                 ani_h->ecore_event_hdls = NULL;
657         }
658 }
659
660 pui_ani_h
661 pui_ani_create(pui_h handle, pui_id id)
662 {
663         pui_ani_h ani_h = NULL;
664         pui_ani_t *ani = NULL;
665         pui_backend_ani_data *ani_data = NULL;
666
667         if (!PUI_MAGIC_CHECK(handle, PUI_MAGIC_PUI_H))
668         {
669                 PUI_MAGIC_FAIL(handle, PUI_MAGIC_PUI_H, __FUNCTION__);
670                 return NULL;
671         }
672
673         if (!handle->backend_module_data)
674         {
675                 pui_err("Invalid backend module data !\n");
676                 return NULL;
677         }
678
679         ani_data = handle->backend_module_data->ani_create(id);
680
681         if (!ani_data)
682         {
683                 pui_err("Invalid ani data from backend module data !\n");
684                 return NULL;
685         }
686
687         ani_h = (pui_ani_h)calloc(1, sizeof(pui_ani));
688
689         if (!ani_h)
690         {
691                 pui_err("Failed to allocate memory for pui ani handle !\n");
692                 goto err;
693         }
694
695         ani_h->id = strdup(id);
696         ani_h->pui_handle = handle;
697         ani_h->ecore_event_hdls = NULL;
698
699         PUI_MAGIC_SET(ani_h, PUI_MAGIC_ANI_H);
700
701         _pui_ani_event_handlers_init(ani_h);
702
703         ani = (pui_ani_t *)calloc(1, sizeof(pui_ani_t));
704
705         if (!ani)
706         {
707                 pui_err("Failed to allocate memory for pui ani mgr !\n");
708                 goto err;
709         }
710
711         ani->ani_h = ani_h;
712         ani->id = id;
713         ani->cmd = PUI_ANI_CMD_NONE;
714         ani->repeat = 0;
715         ani->status = PUI_ANI_STATUS_INITIAL;
716         ani->ani_data = ani_data;
717
718         ani_h->ani = ani;
719
720         handle->ani_handles = eina_list_append(handle->ani_handles, ani_h);
721
722         PUI_MAGIC_SET(ani, PUI_MAGIC_ANI_T);
723
724         return ani_h;
725
726 err:
727         if (ani_data)
728         {
729                 handle->backend_module_data->ani_destroy(ani_data);
730         }
731
732         if (ani_h)
733         {
734                 PUI_MAGIC_SET(ani_h, PUI_MAGIC_NONE);
735                 free(ani_h);
736         }
737
738         return NULL;
739 }
740
741 void
742 pui_ani_destroy(pui_ani_h ani_h)
743 {
744         pui_h handle = NULL;
745         pui_ani_t *ani = NULL;
746         pui_backend_module_data *backend_module_data = NULL;
747
748         if (!PUI_MAGIC_CHECK(ani_h, PUI_MAGIC_ANI_H))
749         {
750                 PUI_MAGIC_FAIL(ani_h, PUI_MAGIC_ANI_H, __FUNCTION__);
751                 return;
752         }
753
754         handle = ani_h->pui_handle;
755         ani = ani_h->ani;
756
757         if (!PUI_MAGIC_CHECK(handle, PUI_MAGIC_PUI_H))
758         {
759                 PUI_MAGIC_FAIL(handle, PUI_MAGIC_PUI_H, __FUNCTION__);
760                 return;
761         }
762
763         if (!PUI_MAGIC_CHECK(ani, PUI_MAGIC_ANI_T))
764         {
765                 PUI_MAGIC_FAIL(ani, PUI_MAGIC_ANI_T, __FUNCTION__);
766                 return;
767         }
768
769         /* stop the animation being played already if any */
770         if (ani->status == PUI_ANI_STATUS_STARTED || ani->status == PUI_ANI_STATUS_RUNNING)
771                 pui_ani_control(ani_h, PUI_ANI_CMD_STOP, 0);
772
773         backend_module_data = handle->backend_module_data;
774         backend_module_data->ani_destroy(ani->ani_data);
775         ani->ani_data = NULL;
776
777         if (ani->frame_cb_timer)
778         {
779                 ecore_timer_del(ani->frame_cb_timer);
780                 ani->frame_cb_timer = NULL;
781         }
782
783         PUI_MAGIC_SET(ani_h->ani, PUI_MAGIC_NONE);
784         free(ani_h->ani);
785
786         _pui_ani_event_handlers_shutdown(ani_h);
787
788         if (ani_h->frame_done_cb)
789         {
790                 ecore_wl2_window_frame_callback_del(ani_h->frame_done_cb);
791                 ani_h->frame_done_cb = NULL;
792         }
793
794         handle->ani_handles = eina_list_remove(handle->ani_handles, ani_h);
795
796         PUI_MAGIC_SET(ani_h, PUI_MAGIC_NONE);
797
798         free(ani_h->id);
799         free(ani_h);
800 }
801