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