pui*: define PUI_MAGICs and add check logic of them
[platform/core/uifw/libpui.git] / src / PUI_ani.c
index 2ac1d0d..40b0a3e 100644 (file)
-#include "PUI.h"
+/*
+ * Copyright © 2019 Samsung Electronics co., Ltd. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
 #include "PUI_internal.h"
+#include "PUI_backend.h"
+#include "PUI.h"
 #include <Eina.h>
 
-static int KEY_WL_BUFFER = 0xabcdbeaf;
-static int KEY_CLIENT = 0xdcbabeaf;
-
-static Eina_Bool
-_cb_window_show(void *data, int type EINA_UNUSED, void *event)
+pui_int_error
+_pui_ani_error_to_int_error(pui_error e)
 {
-       pui_ani_h handle =  (pui_ani_h)data;
-       Ecore_Wl2_Event_Window_Show *ev = (Ecore_Wl2_Event_Window_Show *)event;
+       pui_int_error ei;
 
-       pui_info("...\n");
-
-       /* TODO */
-       (void) handle;
-       (void) ev;
+       switch (e)
+       {
+               case PUI_ERROR_NONE:
+                       ei = PUI_INT_ERROR_NONE;
+                       break;
 
-       return ECORE_CALLBACK_PASS_ON;
-}
+               case PUI_ERROR_INVALID_HANDLE:
+                       ei = PUI_INT_ERROR_INVALID_HANDLE;
+                       break;
 
-static Eina_Bool
-_cb_focus_in(void *data, int type EINA_UNUSED, void *event)
-{
-       pui_ani_h handle =  (pui_ani_h)data;
-       Ecore_Wl2_Event_Focus_In *ev = (Ecore_Wl2_Event_Focus_In *)event;
+               case PUI_ERROR_INVALID_SURFACE:
+                       ei = PUI_INT_ERROR_INVALID_SURFACE;
+                       break;
 
-       pui_info("...\n");
+               case PUI_ERROR_INVALID_BUFFER:
+                       ei = PUI_INT_ERROR_INVALID_BUFFER;
+                       break;
 
-       /* TODO */
-       (void) handle;
-       (void) ev;
+               default:
+                       ei = PUI_INT_ERROR_UNKNOWN;
+                       break;
+       }
 
-       return ECORE_CALLBACK_PASS_ON;
+       return ei;
 }
 
-static Eina_Bool
-_cb_focus_out(void *data, int type EINA_UNUSED, void *event)
+static void
+_pui_ani_cb_frame_done(Ecore_Wl2_Window *win, uint32_t timestamp EINA_UNUSED, void *data)
 {
-       pui_ani_h handle =  (pui_ani_h)data;
-       Ecore_Wl2_Event_Focus_Out *ev = (Ecore_Wl2_Event_Focus_Out *)event;
+       pui_h handle = (pui_h) data;
 
-       pui_info("...\n");
+       pui_info("Frame done ! (window=0x%x)\n", ecore_wl2_window_id_get(win));
 
-       /* TODO */
+       /* TODO : make use of handle */
        (void) handle;
-       (void) ev;
 
-       return ECORE_CALLBACK_PASS_ON;
+       return;
 }
 
-static Eina_Bool
-_cb_visibility_change(void *data, int type EINA_UNUSED, void *event)
+pui_ani_control_buffer *
+pui_ani_get_buffer(pui_ani_h ani_h)
 {
-       pui_ani_h handle =  (pui_ani_h)data;
-       pui_h ph = handle->pui_handle;
+       pui_h handle = NULL;
+       pui_ani_control_buffer *buffer = NULL;
 
-       Ecore_Wl2_Event_Window_Visibility_Change *ev;
-       PUI_Event_Animation_Status *e = NULL;
+       if (!PUI_MAGIC_CHECK(ani_h, PUI_MAGIC_ANI_H))
+       {
+               PUI_MAGIC_FAIL(ani_h, PUI_MAGIC_ANI_H, __FUNCTION__);
+               return NULL;
+       }
 
-       ev = event;
+       handle = ani_h->pui_handle;
+       buffer = pui_display_get_buffer(handle);
 
-       pui_info("Visibility change (window=0x%x, fully_obscured=%d)\n", ev->win, ev->fully_obscured);
+       return buffer;
+}
 
-       ph->visiblity = !(ev->fully_obscured);
+pui_int_error
+pui_ani_set_buffer(pui_ani_h ani_h, pui_ani_control_buffer *buffer)
+{
+       pui_error e = PUI_ERROR_NONE;
+       pui_h handle = NULL;
 
-       if (ev->fully_obscured)
+       if (!PUI_MAGIC_CHECK(ani_h, PUI_MAGIC_ANI_H))
        {
-               //TODO : e
-               if (handle->status == PUI_ANI_STATUS_RUNNING)
-               {
-                       handle->status = PUI_ANI_STATUS_STOPPED;
+               PUI_MAGIC_FAIL(ani_h, PUI_MAGIC_ANI_H, __FUNCTION__);
+               return PUI_ERROR_INVALID_HANDLE;
+       }
 
-                       //PUI_Event_Animation_Status e;
-                       if (e = (PUI_Event_Animation_Status *)calloc(1, sizeof(PUI_Event_Animation_Status)))
-                       {
-                               e->win = ev->win;
-                               e->status = PUI_ANI_STATUS_FORCE_STOPPED;
+       handle = ani_h->pui_handle;
 
-                               ecore_event_add(PUI_EVENT_ANI_STOPPED, e, NULL, handle);
-                       }
-               }
-       }
-       else
+       if (!PUI_MAGIC_CHECK(handle, PUI_MAGIC_PUI_H))
        {
-               //TODO : e
-               if (e = (PUI_Event_Animation_Status *)calloc(1, sizeof(PUI_Event_Animation_Status)))
-               {
-                       e->win = ev->win;
-                       e->status = handle->status;
-
-                       if (handle->status == PUI_ANI_STATUS_STOPPED)
-                       {
-                               ecore_event_add(PUI_EVENT_ANI_READY_TO_START, e, NULL, handle);
-                       }
-                       else if(handle->status == PUI_ANI_STATUS_PAUSED)
-                       {
-                               ecore_event_add(PUI_EVENT_ANI_READY_TO_RESUME, e, NULL, handle);
-                       }
-               }
+               PUI_MAGIC_FAIL(handle, PUI_MAGIC_PUI_H, __FUNCTION__);
+               return PUI_ERROR_INVALID_HANDLE;
        }
 
-       return ECORE_CALLBACK_PASS_ON;
-}
-
-static void
-_buffer_release(void *data, struct wl_buffer *buffer)
-{
-       tbm_surface_h surface = (tbm_surface_h)data;
-       pui_h handle;
-
-       tbm_surface_internal_get_user_data(surface, (unsigned long)&KEY_CLIENT, (void **)&handle);
-       tbm_surface_queue_release(handle->tbm_queue, surface);
+       e = pui_display_set_buffer(handle, buffer);
 
-       pui_info("[UPDATE] release wl_buffer:%p, surface:%p\n", buffer, surface);
+       return _pui_ani_error_to_int_error(e);
 }
 
-static const struct wl_buffer_listener buffer_listener = {
-    _buffer_release
-};
-
-pui_ani_control_buffer *
-pui_ani_get_buffer(pui_ani_h ani_h)
+pui_int_error
+pui_ani_update(pui_ani_h ani_h)
 {
+       pui_error e = PUI_ERROR_NONE;
        pui_h handle = NULL;
-       tbm_surface_error_e ret;
-       tbm_surface_h surface;
-       pui_ani_control_buffer *buffer = NULL;
 
        if (!ani_h)
        {
-               pui_err(\r"Invalid pui ani handle !\n");
-               return NULL;
+               pui_err("Invalid ani handle !\n");
+               return PUI_INT_ERROR_INVALID_HANDLE;
        }
 
        handle = ani_h->pui_handle;
+       e = pui_display_update(handle);
+
+       return _pui_ani_error_to_int_error(e);
+}
 
-       if (!handle)
+static Eina_Bool
+_pui_ani_frame_cb(void *data)
+{
+       Eina_Bool ret;
+       Ecore_Timer *timer = NULL;
+
+       pui_ani_t *ani = (pui_ani_t *)data;
+
+       if (!PUI_MAGIC_CHECK(ani, PUI_MAGIC_ANI_T))
        {
-               pui_err("Error : PUI_INT_ERROR_INVALID_HANDLE\n");
-               return NULL;
+               PUI_MAGIC_FAIL(ani, PUI_MAGIC_ANI_T, __FUNCTION__);
+               return ECORE_CALLBACK_CANCEL;
        }
 
-       if (handle->current_surface)
+       if (!ani->backend_frame_cb)
        {
-               pui_warn("Current_surface is not used !\n");
+               pui_err("Invalid backend frame_cb !\n");
+               return ECORE_CALLBACK_CANCEL;
        }
 
-       if (!tbm_surface_queue_can_dequeue(handle->tbm_queue, 0))
+       if (!ani->frame_cb_timer)
        {
-               pui_err("[UPDATE] Cannot dequeue (error : PUI_ERROR_INTERNAL)\n");
-               return NULL;
+               pui_err("Invalid frame_cb timer !\n");
+               return ECORE_CALLBACK_CANCEL;
        }
 
-       ret = tbm_surface_queue_dequeue(handle->tbm_queue, &surface);
+       pui_info("...\n");
+
+       ret = (Eina_Bool)ani->backend_frame_cb(ani, ++ani->serial);
 
-       if (ret != TBM_SURFACE_ERROR_NONE)
+       if (!ret)
        {
-               pui_err("[UPDATE] dequeue err:%d\n", ret);
-               return NULL;
+               pui_err("Failed on backend's frame_cb !Frame_cb will be removed forcefuly !\n");
+
+               pui_ani_remove_frame_cb(ani);
+
+               return EINA_FALSE;
        }
 
-       tbm_surface_map(surface, TBM_SURF_OPTION_READ | TBM_SURF_OPTION_WRITE, &handle->sinfo);
+       if (ret && PUI_ANI_STATUS_STARTED == ani->status)
+               pui_ani_status_update(ani, PUI_ANI_STATUS_RUNNING);
 
-       handle->current_surface = surface;
-       buffer = (pui_ani_control_buffer *)&(handle->sinfo.planes[0]);
+       ecore_timer_del(ani->frame_cb_timer);
+       ani->frame_cb_timer = NULL;
 
-       return buffer;
+       timer = ecore_timer_add(ani->frame_interval, _pui_ani_frame_cb, ani);
+
+       if (!timer)
+       {
+               pui_err("Failed to add ecore timer !\n");
+               return 0;
+       }
+
+       ani->frame_cb_timer = timer;
+
+       return EINA_FALSE;
 }
 
-pui_int_error
-pui_ani_set_buffer(pui_ani_h ani_h, pui_ani_control_buffer *buffer)
+pui_bool
+pui_ani_add_frame_cb(pui_ani_t *ani, pui_bool (*frame_cb)(void *data, int serial), double frame_interval)
 {
-       pui_h handle = NULL;
+       Ecore_Timer *timer = NULL;
 
-       if (!ani_h)
+       if (!PUI_MAGIC_CHECK(ani, PUI_MAGIC_ANI_T))
        {
-               pui_err("Invalid ani handle !\n");
-               return PUI_INT_ERROR_INVALID_HANDLE;
+               PUI_MAGIC_FAIL(ani, PUI_MAGIC_ANI_T, __FUNCTION__);
+               return 0;
        }
 
-       handle = ani_h->pui_handle;
-
-       if (!handle)
+       if (frame_interval <= 0.0f)
        {
-               pui_err("Error : PUI_INT_ERROR_INVALID_HANDLE\n");
-               return PUI_INT_ERROR_INVALID_HANDLE;
+               pui_err("Invalid frame interval (%.2f) ! frame interval must be larger than 0.\n", frame_interval);
+               return 0;
        }
 
-       if (!handle->current_surface)
+       ani->frame_cb = _pui_ani_frame_cb;
+       ani->backend_frame_cb = frame_cb;
+       ani->frame_interval = frame_interval;
+       ani->frame_cb_data = ani;
+       ani->serial = 0;
+
+       timer = ecore_timer_add(frame_interval, _pui_ani_frame_cb, ani);
+
+       if (!timer)
        {
-               pui_err("Current_surface is not valid !\n");
-               return PUI_INT_ERROR_INVALID_SURFACE;
+               pui_err("Failed to add ecore timer !\n");
+               return 0;
        }
 
-       if (!buffer || !buffer->ptr || !buffer->size)
-               return PUI_INT_ERROR_INVALID_BUFFER;
+       ani->frame_cb_timer = timer;
+
+       pui_info("[Frame callback added][ani id=%s] frame_interval=%.2f\n", ani->id, frame_interval);
 
-       handle->is_buffer_set = 1;
+       /* call frame_cb for starting the first frame */
+       _pui_ani_frame_cb(ani);
 
-       return PUI_INT_ERROR_NONE;
+       return 1;
 }
 
-pui_int_error
-pui_ani_update(pui_ani_h ani_h)
+void
+pui_ani_remove_frame_cb(pui_ani_t *ani)
 {
-       tbm_surface_h surface;
-       tbm_surface_error_e ret;
+       if (!PUI_MAGIC_CHECK(ani, PUI_MAGIC_ANI_T))
+       {
+               PUI_MAGIC_FAIL(ani, PUI_MAGIC_ANI_T, __FUNCTION__);
+               return;
+       }
 
-       pui_h handle = NULL;
+       if (ani->frame_cb_timer)
+       {
+               ecore_timer_del(ani->frame_cb_timer);
+               ani->frame_cb_timer = NULL;
+       }
 
-       if (!ani_h)
+       ani->frame_cb = NULL;
+       ani->backend_frame_cb = NULL;
+       ani->frame_interval = 0;
+       ani->frame_cb_data = NULL;
+
+       pui_info("[Frame callback removed][ani id=%s]\n", ani->id);
+}
+
+pui_id
+pui_ani_get_id(pui_ani_h ani_h)
+{
+       if (!PUI_MAGIC_CHECK(ani_h, PUI_MAGIC_ANI_H))
        {
-               pui_err("Invalid ani handle !\n");
-               return PUI_INT_ERROR_INVALID_HANDLE;
+               PUI_MAGIC_FAIL(ani_h, PUI_MAGIC_ANI_H, __FUNCTION__);
+               return NULL;
        }
 
-       handle = ani_h->pui_handle;
+       if (!PUI_MAGIC_CHECK(ani_h->ani, PUI_MAGIC_ANI_T))
+       {
+               PUI_MAGIC_FAIL(ani_h->ani, PUI_MAGIC_ANI_T, __FUNCTION__);
+               return NULL;
+       }
 
-       if (!handle)
+       return ani_h->ani->id;
+}
+
+pui_ani_cmd
+pui_ani_get_cmd(pui_ani_h ani_h)
+{
+       if (!PUI_MAGIC_CHECK(ani_h, PUI_MAGIC_ANI_H))
        {
-               pui_err("Error : PUI_INT_ERROR_INVALID_HANDLE\n");
-               return PUI_INT_ERROR_INVALID_HANDLE;
+               PUI_MAGIC_FAIL(ani_h, PUI_MAGIC_ANI_H, __FUNCTION__);
+               return PUI_ANI_CMD_NONE;
        }
 
-       if (!handle->current_surface)
-               return PUI_INT_ERROR_INVALID_SURFACE;
+       if (!PUI_MAGIC_CHECK(ani_h->ani, PUI_MAGIC_ANI_T))
+       {
+               PUI_MAGIC_FAIL(ani_h->ani, PUI_MAGIC_ANI_T, __FUNCTION__);
+               return PUI_ANI_CMD_NONE;
+       }
+
+       return ani_h->ani->cmd;
+}
 
-       if (!handle->is_buffer_set)
+int
+pui_ani_get_repeat(pui_ani_h ani_h)
+{
+       if (!PUI_MAGIC_CHECK(ani_h, PUI_MAGIC_ANI_H))
        {
-               pui_err("Buffer is not set !\n");
-               return PUI_INT_ERROR_INVALID_BUFFER;
+               PUI_MAGIC_FAIL(ani_h, PUI_MAGIC_ANI_H, __FUNCTION__);
+               return 0;
        }
 
-       surface = handle->current_surface;
-       handle->current_surface = NULL;
+       if (!PUI_MAGIC_CHECK(ani_h->ani, PUI_MAGIC_ANI_T))
+       {
+               PUI_MAGIC_FAIL(ani_h->ani, PUI_MAGIC_ANI_T, __FUNCTION__);
+               return 0;
+       }
+
+       return ani_h->ani->repeat;
+}
+
+pui_backend_ani_data *
+pui_ani_get_ani_data(pui_ani_t *ani)
+{
+       if (!PUI_MAGIC_CHECK(ani, PUI_MAGIC_ANI_T))
+       {
+               PUI_MAGIC_FAIL(ani, PUI_MAGIC_ANI_T, __FUNCTION__);
+               return NULL;
+       }
 
-       tbm_surface_unmap(surface);
+       return ani->ani_data;
+}
 
-       ret = tbm_surface_queue_enqueue(handle->tbm_queue, surface);
+void
+pui_ani_status_update(pui_ani_t *ani, pui_ani_status status)
+{
+       int ev_type = -1;
+       pui_ani_h ani_h;
+       PUI_Event_Animation_Status *e = NULL;
 
-       if (ret != TBM_SURFACE_ERROR_NONE)
+       if (!PUI_MAGIC_CHECK(ani, PUI_MAGIC_ANI_T))
        {
-               pui_err("[UPDATE] enqueue err:%d\n", ret);
+               PUI_MAGIC_FAIL(ani, PUI_MAGIC_ANI_T, __FUNCTION__);
                return;
        }
 
-       ret = tbm_surface_queue_acquire(handle->tbm_queue, &surface);
+       if (ani->status == status)
+               return;
+
+       ani_h = ani->ani_h;
+
+       ani->status = status;
 
-       if (ret != TBM_SURFACE_ERROR_NONE)
+       switch (status)
        {
-               pui_err("[UPDATE] acquire err:%d\n", ret);
-               return;
+               case PUI_ANI_STATUS_STARTED:
+                       ev_type = PUI_EVENT_ANI_STARTED;
+                       pui_info("[Status update][ani id:%s] PUI_EVENT_ANI_STARTED event has been added.\n", ani->id);
+                       break;
+
+               case PUI_ANI_STATUS_RUNNING:
+                       pui_info("[Status update][ani id:%s] PUI_ANI_STATUS_RUNNING !\n", ani->id);
+                       break;
+
+               case PUI_ANI_STATUS_PAUSED:
+                       ev_type = PUI_EVENT_ANI_PAUSED;
+                       pui_info("[Status update][ani id:%s] PUI_EVENT_ANI_PAUSED event has been added.\n", ani->id);
+                       break;
+
+               case PUI_ANI_STATUS_STOPPED:
+                       ev_type = PUI_EVENT_ANI_STOPPED;
+                       pui_info("[Status update][ani id:%s] PUI_EVENT_ANI_STOPPED event has been added.\n", ani->id);
+                       break;
+
+               default:
+                       pui_err("Unknown status !(ani status=%d, id=%s) !\n", status, ani->id);
+                       return;
        }
 
-       if (!tbm_surface_internal_get_user_data(surface, (unsigned long)&KEY_WL_BUFFER, (void **)&wl_buffer)) {
-               wl_buffer = wayland_tbm_client_create_buffer(handle->wl_tbm_client, surface);
+       if (ev_type > 0)
+       {
+               e = (PUI_Event_Animation_Status *)calloc(1, sizeof(PUI_Event_Animation_Status));
 
-               if (!wl_buffer)
+               if (!e)
                {
-                       pui_err("[UPDATE] failed to create wl_buffer tbm_surface:%p\n", surface);
+                       pui_err("Failed to allocate memory for PUI Event !\n");
                        return;
                }
 
-               wl_buffer_add_listener(wl_buffer, &buffer_listener, surface);
+               e->ani_h = ani_h;
+               e->win = ecore_wl2_window_id_get(ani_h->pui_handle->win);
+               e->status = status;
 
-               tbm_surface_internal_add_user_data(surface, (unsigned long)&KEY_WL_BUFFER, NULL);
-               tbm_surface_internal_set_user_data(surface, (unsigned long)&KEY_WL_BUFFER, wl_buffer);
-               tbm_surface_internal_add_user_data(surface, (unsigned long)&KEY_CLIENT, NULL);
-               tbm_surface_internal_set_user_data(surface, (unsigned long)&KEY_CLIENT, handle);
+               ecore_event_add(ev_type, e, NULL, ani_h);
        }
+}
+
+pui_ani_status
+pui_ani_status_get(pui_ani_t *ani)
+{
+       pui_ani_status status = PUI_ANI_STATUS_UNKNOWN;
 
-       if (!wl_buffer)
+       if (!PUI_MAGIC_CHECK(ani, PUI_MAGIC_ANI_T))
        {
-               pui_err("[UPDATE] dequeue err:%d\n", ret);
-               return;
+               PUI_MAGIC_FAIL(ani, PUI_MAGIC_ANI_T, __FUNCTION__);
+               return status;
        }
 
-       ecore_wl2_window_buffer_attach(handle->win, wl_buffer, 0, 0, 0);
-       ecore_wl2_window_damage(handle->win, NULL, 0);
-       ecore_wl2_window_commit(handle->win, EINA_TRUE);
+       return ani->status;
+}
 
-       pui_info("[UPDATE] commit wl_buffer:%p, surface:%p\n", wl_buffer, surface);
+static pui_error
+_pui_ani_control_with_force(pui_ani_h ani_h, pui_ani_cmd cmd, int repeat, pui_bool force)
+{
+       pui_int_error ei = PUI_INT_ERROR_NONE;
+       pui_ani_t *ani = NULL;
+       pui_h handle = NULL;
+       pui_backend_ani_func *ani_func = NULL;
 
-       handle->is_buffer_set = 0;
+       if (!PUI_MAGIC_CHECK(ani_h, PUI_MAGIC_ANI_H))
+       {
+               PUI_MAGIC_FAIL(ani_h, PUI_MAGIC_ANI_H, __FUNCTION__);
+               return PUI_ERROR_INVALID_ANI_HANDLE;
+       }
 
-       return PUI_INT_ERROR_NONE;
-}
+       if (cmd < PUI_ANI_CMD_START || cmd >= PUI_ANI_CMD_LAST)
+       {
+               pui_err("Invalid cmd ! (cmd=%d)\n", cmd);
+               return PUI_ERROR_INVALID_ANI_CMD;
+       }
 
-static void
-_pui_ani_event_handlers_init(pui_ani_h ani_h)
-{
-       Ecore_Event_Handler *h = NULL;
+       if (repeat < -1)
+       {
+               pui_err("Invalid repeat count ! (repeat=%d)\n", repeat);
+               return PUI_ERROR_INVALID_ANI_REPEAT;
+       }
 
-       if (!ani_h)
+       handle = ani_h->pui_handle;
+       ani = ani_h->ani;
+
+       if (!PUI_MAGIC_CHECK(handle, PUI_MAGIC_PUI_H))
        {
-               pui_err("Invalid handle !\n");
-               return;
+               PUI_MAGIC_FAIL(handle, PUI_MAGIC_PUI_H, __FUNCTION__);
+               return PUI_ERROR_INTERNAL;
        }
 
-       if (!ani_h->ecore_event_hdls)
-               ani_h->ecore_event_hdls = eina_array_new(5);
+       if (!PUI_MAGIC_CHECK(ani, PUI_MAGIC_ANI_T))
+       {
+               PUI_MAGIC_FAIL(ani, PUI_MAGIC_ANI_T, __FUNCTION__);
+               return PUI_ERROR_INTERNAL;
+       }
 
-       h = ecore_event_handler_add(ECORE_WL2_EVENT_WINDOW_SHOW, _cb_window_show, handle);
-       eina_array_push(ani_h->_ecore_event_hdls, h);
+       if (!ani->ani_data)
+       {
+               pui_err("Invalid ani_data !\n");
+               return PUI_ERROR_INTERNAL;
+       }
 
-       h = ecore_event_handler_add(ECORE_WL2_EVENT_FOCUS_IN, _cb_focus_in, handle);
-       eina_array_push(ani_h->_ecore_event_hdls, h);
+       ani_func = ani->ani_data->ani_func;
 
-       h = ecore_event_handler_add(ECORE_WL2_EVENT_FOCUS_OUT, _cb_focus_out, handle);
-       eina_array_push(ani_h->_ecore_event_hdls, h);
+       ani->cmd = cmd;
+       ani->repeat = repeat;
 
-       h = ecore_event_handler_add(ECORE_WL2_EVENT_WINDOW_VISIBILITY_CHANGE, _cb_visibility_change, handle);
-       eina_array_push(ani_h->_ecore_event_hdls, h);
+       if (cmd == PUI_ANI_CMD_START)
+       {
+               if (handle->manual_render)
+               {
+                       pui_err("Manual render has been set ! Unable to start animation.\n");
+                       return PUI_ERROR_MANUAL_RENDER_ENABLED;
+               }
 
-}
+               if (handle->current_ani_h && handle->current_ani_h != ani_h)
+               {
+                       pui_ani_t *current_ani = handle->current_ani_h->ani;
 
-static void
-_pui_ani_event_handlers_shutdown(pui_ani_h ani_h)
-{
-       if (!ani_h)
+                       if (current_ani->status >= PUI_ANI_STATUS_STARTED &&
+                               current_ani->status <= PUI_ANI_STATUS_RUNNING)
+                       {
+                               pui_info("current_ani id=%s, status=%d\n", current_ani->id, current_ani->status);
+
+                               ei = _pui_ani_control_with_force(handle->current_ani_h, PUI_ANI_CMD_STOP, 0, force);
+
+                               if (ei != PUI_INT_ERROR_NONE)
+                                       pui_info("Failed to stop running previous animation ! (id:%s)\n", current_ani->id);
+
+                               current_ani = NULL;
+                               handle->current_ani_h = NULL;
+                       }
+               }
+
+               ei = ani_func->ani_start(ani, repeat);
+
+               if (ei != PUI_INT_ERROR_NONE)
+               {
+                       pui_err("Error on starting animation ! (id:%s, repeat:%d, status=%d))\n", ani->id, repeat, ani->status);
+
+                       if (ani->status != PUI_ANI_STATUS_RUNNING)
+                               _pui_ani_control_with_force(ani_h, PUI_ANI_CMD_STOP, 0, 0);
+
+                       return PUI_ERROR_INTERNAL;
+               }
+
+               handle->current_ani_h = ani_h;
+       }
+       else//cmd == PUI_ANI_CMD_STOP
        {
-               pui_err("Invalid handle !\n");
-               return;
+               ei = ani_func->ani_stop(ani, force);
+
+               if (ani->frame_cb_timer)
+                       pui_ani_remove_frame_cb(ani);
+
+               if (ei != PUI_INT_ERROR_NONE)
+               {
+                       pui_err("Failied on stopping animation ! (id:%s)\n", ani->id);
+
+                       if (ani->status != PUI_ANI_STATUS_STOPPED)
+                               pui_ani_status_update(ani, PUI_ANI_STATUS_STOPPED);
+
+                       return PUI_ERROR_INTERNAL;
+               }
+
+               return PUI_ERROR_NONE;
        }
 
-       while (eina_array_count(ani_h->_ecore_event_hdls))
-               ecore_event_handler_del(eina_array_pop(ani_h->_ecore_event_hdls));
-       eina_array_free(ani_h->_ecore_event_hdls);
+       ani_h->frame_done_cb = ecore_wl2_window_frame_callback_add(handle->win, _pui_ani_cb_frame_done, handle);
 
-       ani_h->_ecore_event_hdls = NULL;
-}
+       if (!ani_h->frame_done_cb)
+       {
+               pui_err("Failed to add frame callback !");
+               goto err;
+       }
 
-pui_id
-pui_ani_get_id(pui_ani_h ani_h)
-{
-       if (ani_h && ani_h->id)
-               return ani_h->id;
-}
+       return PUI_ERROR_NONE;
 
-pui_ani_cmd
-pui_ani_get_cmd(pui_ani_h ani_h)
-{
-       if (ani_h && ani_h->cmd)
-               return ani_h->cmd;
+err:
+       return PUI_ERROR_INTERNAL;
 }
 
-pui_ani_opt
-pui_ani_get_opt(pui_ani_h ani_h)
+pui_error
+pui_ani_control(pui_ani_h ani_h, pui_ani_cmd cmd, int repeat)
 {
-       if (ani_h && ani_h->opt)
-               return ani_h->opt;
+       return _pui_ani_control_with_force(ani_h, cmd, repeat, 0);
 }
 
-pui_error
-pui_ani_control(pui_ani_h ani_h, pui_ani_cmd cmd, pui_ani_opt opt)
+static Eina_Bool
+_cb_visibility_change(void *data, int type EINA_UNUSED, void *event)
 {
-       if (!ani_h)
-               return PUI_ERROR_INVALID_ANI_HANDLE;
+       pui_ani_h ani_h =  (pui_ani_h)data;
+       pui_ani_t *ani = ani_h->ani;
+       pui_h ph = ani_h->pui_handle;
 
-       if (cmd < PUI_ANI_CMD_START || cmd >= PUI_ANI_CMD_LAST)
-               return PUI_ERROR_INVALID_ANI_CMD;
+       Ecore_Wl2_Event_Window_Visibility_Change *ev;
+       PUI_Event_Animation_Status *e = NULL;
 
-       if (opt < PUI_ANI_OPT_NONE || opt >= PUI_ANI_OPT_LAST)
-               return PUI_ERROR_INVALID_ANI_OPT;
+       if (!PUI_MAGIC_CHECK(ani_h, PUI_MAGIC_ANI_H))
+       {
+               PUI_MAGIC_FAIL(ani_h, PUI_MAGIC_ANI_H, __FUNCTION__);
+               return ECORE_CALLBACK_PASS_ON;
+       }
 
-       if (ani_h->id && ani_h->status == PUI_ANI_STATUS_RUNNING)
+       if (!PUI_MAGIC_CHECK(ani, PUI_MAGIC_ANI_T))
        {
-               
+               PUI_MAGIC_FAIL(ani, PUI_MAGIC_ANI_T, __FUNCTION__);
+               return ECORE_CALLBACK_PASS_ON;
        }
 
-       ani_h->cmd = cmd;
-       ani_h->opt = opt;
-       ani_h->status = PUI_ANI_STATUS_STOPPED;
+       if (!PUI_MAGIC_CHECK(ph, PUI_MAGIC_PUI_H))
+       {
+               PUI_MAGIC_FAIL(ph, PUI_MAGIC_PUI_H, __FUNCTION__);
+               return ECORE_CALLBACK_PASS_ON;
+       }
+
+       ev = event;
 
-       ani_h->frame_cb = ecore_wl2_window_frame_callback_add(win, _pui_cb_frame, handle);
+       /* check if this is needed */
+       ph->visibility = !(ev->fully_obscured);
 
-       if (!ani_h->frame_cb)
+       if (ev->fully_obscured)
        {
-               pui_err("Failed to add frame callback !");
-               goto err;
+               if (ani->status == PUI_ANI_STATUS_RUNNING)
+               {
+                       pui_info("animation(%s) will be stopped as it lost its priority !\n", ani->id);
+
+                       _pui_ani_control_with_force(ani_h, PUI_ANI_CMD_STOP, 0, 1);
+               }
        }
+       else
+       {
+               if (ani->status == PUI_ANI_STATUS_PAUSED)
+               {
+                       e = (PUI_Event_Animation_Status *)calloc(1, sizeof(PUI_Event_Animation_Status));
 
-       //TODO
+                       if (!e)
+                       {
+                               pui_err("Failed to allocate memory for PUI Event !\n");
+                               return ECORE_CALLBACK_PASS_ON;
+                       }
 
-       return PUI_ERROR_NONE;
+                       e->ani_h = ani_h;
+                       e->win = ev->win;
+                       e->status = ani->status;
 
-err:
-       return PUI_ERROR_INTERNAL;
+                       if(ani->status == PUI_ANI_STATUS_PAUSED)
+                       {
+                               pui_info("[Event added][ani id:%s] PUI_EVENT_ANI_READY_TO_RESUME event has been added.\n", ani_h->id);
+                               ecore_event_add(PUI_EVENT_ANI_READY_TO_RESUME, e, NULL, ani_h);
+                       }
+               }
+       }
+
+       return ECORE_CALLBACK_PASS_ON;
+}
+
+static void
+_pui_ani_event_handlers_init(pui_ani_h ani_h)
+{
+       Ecore_Event_Handler *h = NULL;
+
+       if (!PUI_MAGIC_CHECK(ani_h, PUI_MAGIC_ANI_H))
+       {
+               PUI_MAGIC_FAIL(ani_h, PUI_MAGIC_ANI_H, __FUNCTION__);
+               return;
+       }
+
+       if (!ani_h->ecore_event_hdls)
+               ani_h->ecore_event_hdls = eina_array_new(1);
+
+       h = ecore_event_handler_add(ECORE_WL2_EVENT_WINDOW_VISIBILITY_CHANGE, _cb_visibility_change, ani_h);
+       eina_array_push(ani_h->ecore_event_hdls, h);
+
+}
+
+static void
+_pui_ani_event_handlers_shutdown(pui_ani_h ani_h)
+{
+       if (!PUI_MAGIC_CHECK(ani_h, PUI_MAGIC_ANI_H))
+       {
+               PUI_MAGIC_FAIL(ani_h, PUI_MAGIC_ANI_H, __FUNCTION__);
+               return;
+       }
+
+       if (ani_h->ecore_event_hdls)
+       {
+               while (eina_array_count(ani_h->ecore_event_hdls))
+                       ecore_event_handler_del(eina_array_pop(ani_h->ecore_event_hdls));
+
+               eina_array_free(ani_h->ecore_event_hdls);
+               ani_h->ecore_event_hdls = NULL;
+       }
 }
 
 pui_ani_h
 pui_ani_create(pui_h handle, pui_id id)
 {
        pui_ani_h ani_h = NULL;
-       pui_ani_mgr *ani_mgr = NULL;
-       pui_backend_ani_func *ani_func = NULL;
+       pui_ani_t *ani = NULL;
+       pui_backend_ani_data *ani_data = NULL;
+
+       if (!PUI_MAGIC_CHECK(handle, PUI_MAGIC_PUI_H))
+       {
+               PUI_MAGIC_FAIL(handle, PUI_MAGIC_PUI_H, __FUNCTION__);
+               return NULL;
+       }
 
-       if (!handle || !handle->backend_module_data))
+       if (!handle->backend_module_data)
        {
-               pui_err("Invalid pui handle or backend module data !\n");
+               pui_err("Invalid backend module data !\n");
                return NULL;
        }
 
-       ani_func = handle->backend_module_data->get_ani_func(id);
+       ani_data = handle->backend_module_data->ani_create(id);
 
-       if (!ani_func)
+       if (!ani_data)
        {
-               pui_err("Invalid ani func from backend module data !\n");
+               pui_err("Invalid ani data from backend module data !\n");
                return NULL;
        }
 
-       ani_h = (pui_ani_h)calloc(1, sizeof(pui_ani_h));
+       ani_h = (pui_ani_h)calloc(1, sizeof(pui_ani));
 
        if (!ani_h)
        {
                pui_err("Failed to allocate memory for pui ani handle !\n");
-               return NULL;
+               goto err;
        }
 
+       ani_h->id = strdup(id);
+       ani_h->pui_handle = handle;
        ani_h->ecore_event_hdls = NULL;
+
+       PUI_MAGIC_SET(ani_h, PUI_MAGIC_ANI_H);
+
        _pui_ani_event_handlers_init(ani_h);
 
-       ani_mgr = (pui_ani_mgr *)calloc(1, sizeof(pui_ani_mgr));
+       ani = (pui_ani_t *)calloc(1, sizeof(pui_ani_t));
 
-       if (!ani_mgr)
+       if (!ani)
        {
                pui_err("Failed to allocate memory for pui ani mgr !\n");
                goto err;
        }
 
-       ani_mgr->ani_h = ani_h;
-       ani_mgr->id = id;
-       ani_mgr->status = PUI_ANI_STATUS_INITIAL;
-       ani_mgr->ani_func = ani_func;
+       ani->ani_h = ani_h;
+       ani->id = id;
+       ani->cmd = PUI_ANI_CMD_NONE;
+       ani->repeat = 0;
+       ani->status = PUI_ANI_STATUS_INITIAL;
+       ani->ani_data = ani_data;
+
+       ani_h->ani = ani;
+
+       handle->ani_handles = eina_list_append(handle->ani_handles, ani_h);
+
+       PUI_MAGIC_SET(ani, PUI_MAGIC_ANI_T);
 
        return ani_h;
 
 err:
+       if (ani_data)
+       {
+               handle->backend_module_data->ani_destroy(ani_data);
+       }
+
        if (ani_h)
+       {
+               PUI_MAGIC_SET(ani_h, PUI_MAGIC_NONE);
                free(ani_h);
+       }
+
        return NULL;
 }
 
 void
 pui_ani_destroy(pui_ani_h ani_h)
 {
-       if (!ani_h)
+       pui_h handle = NULL;
+       pui_ani_t *ani = NULL;
+       pui_backend_module_data *backend_module_data = NULL;
+
+       if (!PUI_MAGIC_CHECK(ani_h, PUI_MAGIC_ANI_H))
+       {
+               PUI_MAGIC_FAIL(ani_h, PUI_MAGIC_ANI_H, __FUNCTION__);
                return;
+       }
+
+       handle = ani_h->pui_handle;
+       ani = ani_h->ani;
 
-       if (ani_h->ani_mgr->status != PUI_ANI_STATUS_STOPPED)
-               pui_ani_control(ani_h, PUI_ANI_CMD_STOP, PUI_ANI_OPT_NONE);
-       free(ani_h->ani_mgr);
+       if (!PUI_MAGIC_CHECK(handle, PUI_MAGIC_PUI_H))
+       {
+               PUI_MAGIC_FAIL(handle, PUI_MAGIC_PUI_H, __FUNCTION__);
+               return;
+       }
+
+       if (!PUI_MAGIC_CHECK(ani, PUI_MAGIC_ANI_T))
+       {
+               PUI_MAGIC_FAIL(ani, PUI_MAGIC_ANI_T, __FUNCTION__);
+               return;
+       }
+
+       /* stop the animation being played already if any */
+       if (ani->status == PUI_ANI_STATUS_STARTED || ani->status == PUI_ANI_STATUS_RUNNING)
+               pui_ani_control(ani_h, PUI_ANI_CMD_STOP, 0);
+
+       backend_module_data = handle->backend_module_data;
+       backend_module_data->ani_destroy(ani->ani_data);
+       ani->ani_data = NULL;
+
+       if (ani->frame_cb_timer)
+       {
+               ecore_timer_del(ani->frame_cb_timer);
+               ani->frame_cb_timer = NULL;
+       }
+
+       PUI_MAGIC_SET(ani_h->ani, PUI_MAGIC_NONE);
+       free(ani_h->ani);
 
        _pui_ani_event_handlers_shutdown(ani_h);
-       
-       if (ani_h->frame_cb)
+
+       if (ani_h->frame_done_cb)
        {
-               ecore_wl2_window_frame_callback_del(ani_h->frame_cb);
-               ani_h->frame_cb = NULL;
+               ecore_wl2_window_frame_callback_del(ani_h->frame_done_cb);
+               ani_h->frame_done_cb = NULL;
        }
+
+       handle->ani_handles = eina_list_remove(handle->ani_handles, ani_h);
+
+       PUI_MAGIC_SET(ani_h, PUI_MAGIC_NONE);
+
+       free(ani_h->id);
+       free(ani_h);
 }