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