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