From 59f1886db53db5ac487f65896d2375ac4c0fa6f1 Mon Sep 17 00:00:00 2001 From: Sung-Jin Park Date: Thu, 11 Jul 2019 15:27:47 +0900 Subject: [PATCH] renew pui prototype Change-Id: Iaeb10104cd31f5245393eff9d0069fdf85d827f1 Signed-off-by: Sung-Jin Park --- README.md | 2 +- backends/default_backend.c | 245 ++++++++++++++++++++++++ include/PUI.h | 99 ++++++++++ include/PUI_backend.h | 93 +++++++++ include/PUI_internal.h | 108 +++++++++++ samples/PUI_sample.c | 298 +++++++++++++++++++++++++++++ src/PUI.c | 365 +++++++++++++++++++++++++++++++++++ src/PUI_ani.c | 464 +++++++++++++++++++++++++++++++++++++++++++++ src/PUI_backend.c | 109 +++++++++++ 9 files changed, 1782 insertions(+), 1 deletion(-) create mode 100644 backends/default_backend.c create mode 100644 include/PUI.h create mode 100644 include/PUI_backend.h create mode 100644 include/PUI_internal.h create mode 100644 samples/PUI_sample.c create mode 100644 src/PUI.c create mode 100644 src/PUI_ani.c create mode 100644 src/PUI_backend.c diff --git a/README.md b/README.md index 727127a..82f7d56 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,2 @@ # libPUI -libPUI provides the interfaces to request UI actions defined in a PUI(Product User Interface) via it's backend interface. +libPUI provides the interfaces to request to do UI actions defined in a PUI(Product User Interface) via it's backend interface. diff --git a/backends/default_backend.c b/backends/default_backend.c new file mode 100644 index 0000000..f0ca99d --- /dev/null +++ b/backends/default_backend.c @@ -0,0 +1,245 @@ +#include +#include + +pui_backend_ani_func *ani_func = NULL; + +enum +{ + None, + Linear, + EaseInSine, + EaseOutSine, + EaseInQuart, + EaseOutQuart +} pui_effect_func; + +typedef struct _default_ani_data default_ani_data; +struct _default_ani_data +{ + pui_id id; + pui_ani_status status; + pui_ani_control_buffer *buffer; + unsigned int repeat; + + unsigned int key_frame_idx; + unsigned int num_key_frames; + double interval; + pui_effect_func effect_func; + + Eina_Bool (*frame_cb)(void *data); + +/* + void *frame_cb_data; + double expire; + Ecore_Timer *frame_cb_timer; +*/ +}; + +static void +_start_frame(pui_ani_mgr *ani_mgr) +{ + //TODO +} + +static Eina_Bool +_frame_cb(void *data) +{ + //TODO + //_get_next_frame(); + //pui_backend_ani_get_buffer(); + //pui_backend_ani_update(); +} + +pui_int_error +get_ani_data_from_collection(default_ani_data *data, pui_id id) +{ + pui_int_error e = PUI_INT_ERROR_NONE; + + //TODO + //ex> data->id = id; + //ex> data->interval = 30; + + return e; +} + +pui_backend_ani_data * +_ani_create(pui_ani_mgr *ani_mgr, pui_id id) +{ + pui_int_error e = PUI_INT_ERROR_NONE; + default_ani_data *data = (default_ani_data *)calloc(1, sizeof(default_ani_data)); + + if (!data) + { + pui_err("Failed to allocate memory !\n"); + return NULL; + } + + e = get_ani_data_from_collection(data, id); + + if (PUI_INT_ERROR_NONE != e) + { + pui_err("Failed to get ani data from collection !\n"); + goto err; + } + + return (pui_backend_ani_data *)default_ani_data; + +err: + if (data) + free(data); + + return NULL; +} + +pui_error +_ani_start(pui_ani_mgr *ani_mgr, int repeat) +{ + pui_int_error e = PUI_INT_ERROR_NONE; + + default_ani_data *data = (default_ani_data *)ani_mgr->ani_data; + + //TODO + //start_frame(ani_mgr); + //pui_backend_ani_add_frame_cb(data->frame_cb); + + return e; +} + +pui_error +_ani_stop(pui_ani_mgr *ani_mgr) +{ + pui_int_error e = PUI_INT_ERROR_NONE; + + default_ani_data *data = (default_ani_data *)ani_mgr->ani_data; + + //TODO + //pui_backend_ani_remove_frame_cb(data->frame_cb); + + return e; +} + +pui_int_error +_create_ani_collection(void) +{ + pui_int_error e = PUI_INT_ERROR_NONE; + + //TODO + + return e; +} + +pui_int_error +_is_ani_supported(pui_id id) +{ + pui_int_error e = PUI_INT_ERROR_NONE; + + //TODO + /* if the given id is not supported, return PUI_INT_ERROR_ID_NOT_SUPPORTED. */ + + return e; +} + +pui_backend_ani_func * +_get_ani_func(pui_id id) +{ + if (ani_func) + return ani_func; + + ani_func = pui_backend_ani_alloc_ani_func(); + + if (!ani_func) + { + pui_err("Failed to allocate memory !\n"); + return NULL; + } + + /* Assign each function pointer that corresponds to the given id */ + ani_func->ani_create = _ani_create; + ani_func->ani_start = _ani_start; + ani_func->ani_stop = _ani_stop; + + ani_func->reserved1 = NULL; + ani_func->reserved2 = NULL; + ani_func->reserved3 = NULL; + ani_func->reserved4 = NULL; + ani_func->reserved5 = NULL; + ani_func->reserved6 = NULL; + ani_func->reserved7 = NULL; + ani_func->reserved8 = NULL; + ani_func->reserved9 = NULL; + ani_func->reserved10 = NULL; + + return ani_func; +} + +static pui_backend_module_data * +pui_default_backend_init(void) +{ + pui_backend_module_data *backend_data = NULL; + + backend_data = (pui_backend_module_data *)calloc(1, sizeof(pui_backend_module_data)); + + if (!backend_data) + { + pui_err("Failed to allocate memory for pui backend module data !\n"); + return NULL; + } + + /* Allocate backend specific data if needed. Now it will be empty. */ + backend_data->data = NULL; + + backend_data->create_ani_collection = _create_ani_collection; + backend_data->is_ani_supported = _is_ani_supported; + backend_data->get_ani_func = _get_ani_func; + + return backend_data; + +err: + if (backend_data) + { + if (backend_data->data) + { + free(backend_data->data); + } + + free(backend_data); + } + + return NULL; +} + +static void +pui_default_backend_deinit(pui_backend_module_data *backend_data) +{ + if (!backend_data) + return; + + if (backend_data->data) + { + //TODO : free variables of backend_data + + free(backend_data->data); + } + + if (backend_data->get_ani_func && ani_func) + { + pui_backend_ani_free_ani_func(ani_func); + ani_func = NULL; + } + + backend_data->get_ani_func = NULL; + backend_data->create_ani_collection = NULL; + backend_data->is_ani_supported = NULL; + + free(backend_data); + backend_data = NULL; +} + +pui_backend_module pui_backend_module_info = { + "tizen_ref_speaker", + "Samsung", + PUI_BACKEND_SET_ABI_VERSION(1, 0), + pui_default_backend_init, + pui_default_backend_deinit +}; + diff --git a/include/PUI.h b/include/PUI.h new file mode 100644 index 0000000..42cafab --- /dev/null +++ b/include/PUI.h @@ -0,0 +1,99 @@ +#ifndef _LIBPUI_H_ +#define _LIBPUI_H_ + +#include "PUI_internal.h" +#include +#include +#include + +#define EFL_BETA_API_SUPPORT +#define PUI_API __attribute__ ((visibility("default")) + +EAPI extern int PUI_EVENT_ANI_STARTED = 0; +EAPI extern int PUI_EVENT_ANI_STOPPED = 0; +EAPI extern int PUI_EVENT_ANI_PAUSED = 0; +EAPI extern int PUI_EVENT_ANI_READY_TO_START = 0; +EAPI extern int PUI_EVENT_ANI_READY_TO_RESUME = 0; +EAPI extern int PUI_EVENT_ANI_FRAME_DONE = 0; +EAPI extern int PUI_EVENT_ANI_BUFFER_RELEASED = 0; + +enum { + PUI_ERROR_NONE, + PUI_ERROR_INVALID_ANI_HANDLE, + PUI_ERROR_INVALID_ANI_CMD, + PUI_ERROR_INVALID_ANI_OPT, + PUI_ERROR_INTERNAL, +} pui_error; + +enum { + PUI_ANI_STATUS_INITIAL, + PUI_ANI_STATUS_RUNNING, + PUI_ANI_STATUS_PAUSED, + PUI_ANI_STATUS_STOPPED, + PUI_ANI_STATUS_FORCE_STOPPED, +} pui_ani_status; + +enum { + PUI_ANI_CMD_NONE, + PUI_ANI_CMD_START, + PUI_ANI_CMD_STOP, + PUI_ANI_CMD_LAST +} pui_ani_cmd; + +enum { + PUI_ANI_OPT_NONE, + PUI_ANI_OPT_ONCE, + PUI_ANI_OPT_REPEAT, + PUI_ANI_OPT_LAST +} pui_ani_opt; + +typedef char* pui_id; +typedef char* pui_error_string; +typedef struct _pui * pui_h; +typedef struct _pui_ani * pui_ani_h; +typedef struct _pui_module_data pui_module_data; + +typedef struct _PUI_Event_Animation_Status PUI_Event_Animation_Status; + +#ifdef __cplusplus +extern "C" { +#endif + +PUI_API int +pui_init(void); + +PUI_API int +pui_shutdown(void); + +PUI_API pui_h +pui_create(Ecore_Wl2_Window *win); + +PUI_API void +pui_destroy(pui_h handle); + +PUI_API const pui_error_string +pui_error_to_string(pui_error e); + +PUI_API pui_ani_h +pui_ani_create(pui_h handle, pui_id id); + +PUI_API pui_error +pui_ani_control(pui_ani_h handle, pui_ani_cmd cmd, pui_ani_opt opt); + +PUI_API void +pui_ani_destroy(pui_ani_h handle); + +PUI_API pui_id +pui_ani_get_id(pui_ani_h handle); + +PUI_API pui_ani_cmd +pui_ani_get_cmd(pui_ani_h handle); + +PUI_API pui_ani_opt +pui_ani_get_opt(pui_ani_h handle); + +#ifdef __cplusplus +} +#endif + +#endif//_LIBPUI_H_ diff --git a/include/PUI_backend.h b/include/PUI_backend.h new file mode 100644 index 0000000..147066a --- /dev/null +++ b/include/PUI_backend.h @@ -0,0 +1,93 @@ +#ifndef _LIBPUI_BACKEND_H_ +#define _LIBPUI_BACKEND_H_ + +#include "PUI.h" +#include "PUI_internal.h" + +#define PUI_BACKEND_ABI_MAJOR_MASK 0xFFFF0000 +#define PUI_BACKEND_ABI_MINOR_MASK 0x0000FFFF + +#define PUI_BACKEND_GET_ABI_MAJOR(m) ((m) & PUI_BACKEND_ABI_MAJOR_MASK) >> 16) +#define PUI_BACKEND_GET_ABI_MINOR(m) ((m) & PUI_BACKEND_ABI_MINOR_MASK) + +#define PUI_BACKEND_SET_ABI_VERSION(major, minor) \ + ((((major) << 16) & PUI_BACKEND_ABI_MAJOR_MASK) | ((minor) & PUI_BACKEND_ABI_MINOR_MASK)) + +#define PUI_BACKEND_ABI_VERSION_1_0 PUI_BACKEND_SET_ABI_VERSION(1, 0) +#define PUI_BACKEND_AB_VERSION_LAST PUI_BACKEND_ABI_VERSION_1_0 + +typedef struct _pui_ani_control_buffer pui_ani_control_buffer; +typedef struct _pui_ani_mgr pui_ani_mgr; + +typedef struct _pui_backend_ani_func pui_backend_ani_func; +struct _pui_backend_ani_func +{ + pui_error (*ani_create)(pui_ani_mgr *ani_mgr, pui_id id); + pui_error (*ani_start)(pui_ani_mgr *ani_mgr, int repeat); + pui_error (*ani_stop)(pui_ani_mgr *ani_mgr); + + void (*reserved1)(void); + void (*reserved2)(void); + void (*reserved3)(void); + void (*reserved4)(void); + void (*reserved5)(void); + void (*reserved6)(void); + void (*reserved7)(void); + void (*reserved8)(void); + void (*reserved9)(void); + void (*reserved10)(void); +}; + +typedef struct _pui_backend_module_data pui_backend_module_data; +struct _pui_backend_module_data +{ + void *data; + + pui_int_error (*create_ani_collection)(void); + pui_int_error (*is_ani_supported)(pui_id id); + pui_backend_ani_func *(*get_ani_func)(pui_id id); +}; + +typedef struct _pui_backend_module pui_backend_module; +typedef struct _pui_backend_module +{ + const char *name; /**< The name of a backend module */ + const char *vendor; /**< The vendor name of a backend module */ + unsigned long abi_version; /**< The API version of a backend module */ + + pui_backend_module_data *(*backend_init)(void); + void (*backend_deinit)(pui_backend_module_data *backend_data); +}; + +typedef void pui_backend_ani_data; + +#ifdef __cplusplus +extern "C" { +#endif + +pui_ani_control_buffer * +pui_backend_ani_get_buffer(pui_ani_mgr *ani_mgr); + +pui_int_error +pui_backend_ani_set_buffer(pui_ani_mgr *ani_mgr, pui_ani_control_buffer *buffer); + +pui_int_error +pui_backend_ani_update(pui_ani_mgr *ani_mgr); + +void +pui_backend_ani_add_frame_cb(pui_ani_mgr *ani_mgr, Eina_Bool (*frame_cb)(void *data), double expire, void *data) ; + +void +pui_backend_ani_remove_frame_cb(pui_ani_mgr *ani_mgr, void *data); + +pui_backend_ani_func * +pui_backend_ani_alloc_ani_func(void); + +void +pui_backend_ani_free_ani_func(pui_backend_ani_func *func); + +#ifdef __cplusplus +} +#endif + +#endif//_LIBPUI_BACKEND_H_ diff --git a/include/PUI_internal.h b/include/PUI_internal.h new file mode 100644 index 0000000..098d7a5 --- /dev/null +++ b/include/PUI_internal.h @@ -0,0 +1,108 @@ +#ifndef _LIBPUI_INTERNAL_H_ +#define _LIBPUI_INTERNAL_H_ + +#include "PUI.h" +#include "PUI_backend.h" + +#ifndef PATH_MAX +#define PATH_MAX 4096 +#endif + +enum { + PUI_INT_ERROR_NONE, + PUI_INT_ERROR_INVALID_HANDLE, + PUI_INT_ERROR_INVALID_SURFACE, + PUI_INT_ERROR_INVALID_BUFFER, + PUI_INT_ERROR_ID_NOT_SUPPORTED, + PUI_INT_ERROR_INVALID_BACKEND_MGR, + PUI_NIT_ERROR_NO__ANI_AVAILABLE, + PUI_INT_ERROR_BACKEND_FUNC_ERROR, +} pui_int_error; + +typedef struct _PUI_Event_Animation_Status +{ + unsigned int win; + pui_ani_status status; +}; + +struct _pui_ani_control_buffer +{ + unsigned char *ptr; + uint32_t size; +}; + +struct _pui_ani +{ + pui_h pui_handle; + pui_ani_mgr *ani_mgr; + + Eina_Array *ecore_event_hdls; + Ecore_Wl2_Frame_Cb_Handle *frame_cb; + + pui_id id; + pui_ani_cmd cmd; + pui_ani_opt opt; + pui_ani_status status; +}; + +struct _pui_ani_mgr +{ + pui_ani_h ani_h; + + pui_id id; + pui_ani_status status; + + pui_ani_control_buffer *buffer + + Eina_Bool (*frame_cb)(void *data); + void *frame_cb_data; + double expire; + Ecore_Timer *frame_cb_timer; + + pui_backend_ani_func *ani_func; + pui_backend_ani_data *ani_data; +}; + +struct _pui +{ + Ecore_Wl2_Window *win; + Ecore_Wl2_Display *ewd; + int visibility; + + struct wayland_tbm_client *wl_tbm_client; + tbm_surface_queue_h tbm_queue; + + tbm_surface_info_s current_sinfo; + tbm_surface_h current_surface; + int is_buffer_set; + + Eina_List *ani_handles; + + pui_backend_module_data *backend_module_data; +}; + +struct _pui_module_data +{ + void *module_info; + pui_backend_module *backend_module_info; + pui_backend_module_data *backend_module_data; +}; + +#ifdef __cplusplus +extern "C" { +#endif + +pui_ani_control_buffer * +get_buffer(pui_ani_h handle); + +pui_int_error +set_buffer(pui_ani_h handle, pui_ani_control_buffer *buffer); + +pui_int_error +pui_ani_update(pui_ani_h handle); + +#ifdef __cplusplus +} +#endif + +#endif//_LIBPUI_INTERNAL_H_ \ No newline at end of file diff --git a/samples/PUI_sample.c b/samples/PUI_sample.c new file mode 100644 index 0000000..cc4744d --- /dev/null +++ b/samples/PUI_sample.c @@ -0,0 +1,298 @@ +#include +#include + +#define NUM_ECORE_EVENT_HANDLERS 4 + +#define debug_error(msg, ...) \ + do { \ + fprintf(stderr, "[ERROR][%s] " msg, __FUNCTION__, ##__VA_ARGS__); \ + } while(0) + +#define debug_info(msg, ...) \ + do { \ + fprintf(stdout, "[INFO][%s] " msg, __FUNCTION__, ##__VA_ARGS__); \ + } while(0) + +typedef struct _animation animation_t; +struct _animation +{ + pui_id id; + pui_ani_cmd cmd; + pui_ani_opt opt; +}; + +typedef struct app_data app_data_t; +struct app_data +{ + pui_h ph; + pui_ani_h ani_h; + + Ecore_Wl2_Display *ewd; + Ecore_Wl2_Window *win; +}; + +static Eina_Array *_ecore_event_hdls = NULL; +static animation_t ani_collection[] = { + { "bixby_listening", PUI_ANI_CMD_START, PUI_ANI_OPT_ONCE }, + { "bixby_processing", PUI_ANI_CMD_START, PUI_ANI_OPT_REPEAT }, + { "bixby_speaking", PUI_ANI_CMD_START, PUI_ANI_OPT_REPEAT }, + { "bixby_error", PUI_ANI_CMD_START, PUI_ANI_OPT_ONCE }, + { "alarm", PUI_ANI_CMD_START, PUI_ANI_OPT_REPEAT }, + { "notification", PUI_ANI_CMD_START, PUI_ANI_OPT_REPEAT }, +}; + +static void +ani_play(app_data_t *app, pui_ani_opt opt) +{ + pui_error e; + + if (!app || !app->ani_h) + { + debug_error("Invalid app data or pui animation handle !\n"); + return; + } + + e = pui_ani_control(app->ani_h, PUI_ANI_CMD_START, opt); + + if (PUI_ERROR_NONE != e) + { + debug_error("Failed on playing an animation ! (cmd:%d, opt:%d)\n", PUI_ANI_CMD_START, opt); + return; + } + + debug_info("Animation(%s) will be started !\n", pui_ani_get_id(ani_h)); +} + +static void +ani_stop(app_data_t *app) +{ + pui_error e; + + if (!app || !app->ani_h) + { + debug_error("Invalid app data or pui animation handle !\n"); + return; + } + + e = pui_ani_control(app->ani_h, PUI_ANI_CMD_STOP, PUI_ANI_OPT_ONCE); + + if (PUI_ERROR_NONE != e) + { + debug_error("Failed on stopping an animation !(cmd:%d, opt:%d)\n", PUI_ANI_CMD_STOP, PUI_ANI_OPT_ONCE); + return; + } + + debug_info("Animation(%s) will be stopped !\n", pui_ani_get_id(ani_h)); +} + +static void +ani_collection_play(app_data_t *app) +{ + static int ani_idx = 0; + int n_animation = 0; + pui_ani_h ani_h = NULL; + pui_error e = PUI_ERROR_NONE; + + n_animation = ani_collection / sizeof(animation_t); + + if (n_animation < 0) + { + debug_error("No animation is available ! (n_animation=%d)\n", n_animation); + return; + } + + if (!app->ph) + { + debug_error("Invalid pui_h handle !\n"); + return; + } + + ani_h = pui_ani_create(app->ph, ani_collection[ani_idx].id); + + if (!ani_h) + { + debug_error("Failed to create new PUI animation handle !\n"); + return; + } + + if (app->ani_h) + { + ani_stop(app); + app->ani_h = NULL; + } + + app->ani_h = ani_h; + ani_play(app, ani_collection[ani_idx].opt); + + if (++ani_idx >= n_animation) + ani_idx = 0; + + return; + +err: + if (ani_h) + { + pui_ani_control(ani_h, PUI_ANI_CMD_STOP, PUI_ANI_OPT_NONE); + pui_ani_destroy(ani_h); + } +} + +static Eina_Bool +_cb_key_up(void *data EINA_UNUSED, int type EINA_UNUSED, void *event) +{ + app_data_t *app = (app_data_t *)data; + Ecore_Event_Key *ev = event; + + debug_info("KEY: name:%s, sym:%s, code:%d\n", ev->keyname, ev->key, ev->keycode); + + ani_collection_play(app); + + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_cb_focus_in(void *data, int type EINA_UNUSED, void *event) +{ + app_data_t *app = (app_data_t *)data; + Ecore_Wl2_Event_Focus_In *ev = (Ecore_Wl2_Event_Focus_In *)event; + + debug_info("\n"); + + /* TODO */ + (void) app; + (void) ev; + + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_cb_focus_out(void *data, int type EINA_UNUSED, void *event) +{ + app_data_t *app = (app_data_t *)data; + Ecore_Wl2_Event_Focus_Out *ev = (Ecore_Wl2_Event_Focus_Out *)event; + + debug_info("\n"); + + /* TODO */ + (void) app; + (void) ev; + + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_cb_visibility_change(void *data, int type EINA_UNUSED, void *event) +{ + app_data_t *app = (app_data_t *)data; + Ecore_Wl2_Event_Window_Visibility_Change *ev; + + ev = event; + + debug_info("Visibility change (window=0x%x, fully_obscured=%d)\n", ev->win, ev->fully_obscured); + + if (ev->fully_obscured) + { + debug_info("Loose LED control !\n"); + ani_stop(app); + } + else + { + debug_info("Gain LED control !\n"); + ani_collection_play(app); + } + + return ECORE_CALLBACK_PASS_ON; +} + +static void +event_handlers_init(app_data_t *app) +{ + Ecore_Event_Handler *h = NULL; + _ecore_event_hdls = eina_array_new(NUM_ECORE_EVENT_HANDLERS); + + h = ecore_event_handler_add(ECORE_EVENT_KEY_UP, _cb_key_up, app); + eina_array_push(_ecore_event_hdls, h); + + h = ecore_event_handler_add(ECORE_WL2_EVENT_FOCUS_IN, _cb_focus_in, app); + eina_array_push(_ecore_event_hdls, h); + + h = ecore_event_handler_add(ECORE_WL2_EVENT_FOCUS_OUT, _cb_focus_out, app); + eina_array_push(_ecore_event_hdls, h); + + h = ecore_event_handler_add(ECORE_WL2_EVENT_WINDOW_VISIBILITY_CHANGE, _cb_visibility_change, app); + eina_array_push(_ecore_event_hdls, h); +} + +int main() +{ + app_data_t *app = NULL; + const char *socket_name = NULL; + + if (!ecore_wl2_init()) + { + fprintf(stderr, "Failed to init ecore wl2 !\n"); + return EXIT_SUCCESS; + } + + socket_name = getenv("WAYLAND_DISPLAY"); + + if (!socket_name) + socket_name = "wayland-0"; + + app = (app_data_t *)calloc(1, sizeof(app_data_t)); + + if (!app) + { + debug_error("Failed to allocate app data !\n"); + goto err; + } + + app->ewd = ecore_wl2_display_connect(socket_name); + + if (!app->ewd) + { + debug_error("Failed to connect to display !\n"); + goto err; + } + + app->win = ecore_wl2_window_new(app->ewd, NULL, 0, 0, 1, 1); + + if (!app->win) + { + debug_error("Failed to create a window !\n"); + goto err; + } + + ecore_wl2_window_alpha_set(app->win, EINA_FALSE); + ecore_wl2_window_show(app->win); + ecore_wl2_window_commit(app->win, EINA_TRUE); + ecore_wl2_window_activate(app->win); + + if (!pui_init()) + { + debug_error("Failed to init pui !\n"); + goto err; + } + + app->ph = pui_create(app->win); + + if (!app->ph) + { + debug_error("Failed to create PUI handle !\n"); + goto err; + } + + event_handlers_init(app); + + ecore_main_loop_begin(); +err: + if (app->ani_h) + pui_ani_destroy(app->ani_h) + if (app->ph) + pui_destroy(app->ph); + + pui_shutdown(); + ecore_wl2_shutdown(); + + return EXIT_SUCCESS; +} diff --git a/src/PUI.c b/src/PUI.c new file mode 100644 index 0000000..c5e8a94 --- /dev/null +++ b/src/PUI.c @@ -0,0 +1,365 @@ +#include "PUI.h" +#include "PUI_internal.h" +#include "PUI_backend.h" + +#ifndef PUI_MODULE_DIR +#define PUI_MODULE_DIR "/usr/lib" +#endif + +#define pui_err(msg, ...) \ + do { \ + fprintf(stderr, "[ERROR][%s] " msg, __FUNCTION__, ##__VA_ARGS__); \ + } while(0) + +#define pui_warn(msg, ...) \ + do { \ + fprintf(stderr, "[WARNING][%s] " msg, __FUNCTION__, ##__VA_ARGS__); \ + } while(0) + +#define pui_info(msg, ...) \ + do { \ + fprintf(stdout, "[INFO][%s] " msg, __FUNCTION__, ##__VA_ARGS__); \ + } while(0) + +static int _pui_init_count = 0; +static pui_module_data *pui_module = NUJLL; + +EAPI int PUI_EVENT_ANI_STARTED = 0; +EAPI int PUI_EVENT_ANI_STOPPED = 0; +EAPI int PUI_EVENT_ANI_PAUSED = 0; +EAPI int PUI_EVENT_ANI_READY_TO_START = 0; +EAPI int PUI_EVENT_ANI_READY_TO_RESUME = 0; +EAPI int PUI_EVENT_ANI_FRAME_DONE = 0; +EAPI int PUI_EVENT_ANI_BUFFER_RELEASED = 0; + +const pui_error_string +pui_error_to_string(pui_error e) +{ + const pui_error_string str = NULL; + + switch (e) + { + case PUI_ERROR_NONE: + str = "PUI_No_Error"; + break; + + case PUI_ERROR_INVALID_ANI_HANDLE: + str = "PUI_Invalid_Animation_Handle"; + break; + + case PUI_ERROR_INVALID_ANI_CMD: + str = "PUI_Invalid_Animation_Command"; + break; + + case PUI_ERROR_INVALID_ANI_OPT: + str = "PUI_Invalid_Animation_Option"; + break; + + case PUI_ERROR_INTERNAL: + str = "PUI_Internal_Error"; + break; + + default: + str = "PUI_Unknown_Error"; + } + + return str; +} + +static void +_pui_cb_frame(Ecore_Wl2_Window *win, uint32_t timestamp EINA_UNUSED, void *data) +{ + pui_h handle = (pui_h) data; + + TRACE("Frame done ! (window=%p)\n", win); + + // TODO + + return; +} + +pui_h +pui_create(Ecore_Wl2_Window *win) +{ + pui_h handle = NULL; + Ecore_Wl2_display *ewd = ecore_wl2_window_display_get(win); + struct wayland_tbm_client *wl_tbm_client = NULL; + Ecore_Wl2_Frame_Cb_Handle *frame_cb = NULL; + + if (!win || !ewd) + { + pui_err("Invalid window or display !"); + return NULL; + } + + wl_tbm_client = wayland_tbm_client_init(ecore_wl2_display_get(ewd)); + + if (!wl_tbm_client) + { + pui_err("Failed to init wayland_tbm_client !"); + return NULL; + } + + handle = (pui_h)calloc(1, sizeof(pui_h)); + + if (!handle) + return NULL; + + handle->win = win; + handle->ewd = ewd; + handle->visibility = 0; + handle->wl_tbm_client = wl_tbm_client; + handle->ani_handles = NULL; + handle->backend_module_data = pui_module->backend_module_data; + + handle->tbm_queue = wayland_tbm_client_create_surface_queue(handle->wl_tbm_client, + ecore_wl2_window_surface_get(handle->win), + 2, 100, 100, TBM_FORMAT_ABGR8888); + + if (!handle->tbm_queue) + { + pui_err("Failed to create a surface queue !"); + goto err; + } + + return handle; + +err: + pui_destroy(handle); + + return NULL; +} + +void +pui_destroy(pui_h handle) +{ + pui_ani_h *ani_h = NULL; + + if (!handle) + return; + + EINA_LIST_FREE(handle->ani_handles, ani_h) + { + pui_ani_destroy(ani_h); + free(ani_h); + } + + if (handle->tbm_queue) + { + tbm_surface_queue_destroy(handle->tbm_queue); + handle->tbm_queue = NULL; + } + + if (handle->wl_tbm_client) + { + wayland_tbm_client_deinit(handle->wl_tbm_client); + handle->wl_tbm_client = NULL; + } + + free(handle); +} + +#define PREFIX_LIB "libpui_" +#define SUFFIX_LIB ".so" +#define DEFAULT_LIB PREFIX_LIB"default"SUFFIX_LIB + +static void +_pui_load_backend_module(void) +{ + //char path[PATH_MAX] = {0, }; + void *module_info = NULL; + pui_backend_module *backend_module_info = NULL; + int backend_module_major, backend_module_minor; + int pui_backend_major, pui_backend_minor; + + pui_backend_module_data *backend_module_data = NULL; + + + module_info = dlopen(DEFAULT_LIB, RTLD_LAZY); + + if (!module_info) + { + pui_err("Failed to dlopen(error:%s, path:%s) !\n", dlerror(), DEFAULT_LIB); + return; + } + + backend_module_info = dlsym(module_info, "pui_backend_module_info"); + + if (!backend_module_info) { + pui_err("Backend module(%s) doesn't have pui_backend_module_info !\n", DEFAULT_LIB); + goto err; + } + + pui_backend_major = PUI_BACKEND_GET_ABI_MAJOR(PUI_BACKEND_AB_VERSION_LAST); + pui_backend_minor = PUI_BACKEND_GET_ABI_MINOR(PUI_BACKEND_AB_VERSION_LAST); + + backend_module_major = PUI_BACKEND_GET_ABI_MAJOR(backend_module_info->abi_version); + backend_module_minor = PUI_BACKEND_GET_ABI_MINOR(backend_module_info->abi_version); + + if (backend_module_major > pui_backend_major) { + TBM_ERR("PUI backend module ABI major ver(%d) is newer than the PUI's ver(%d)\n", + backend_module_major, pui_backend_major); + goto err; + } else if (backend_module_minor > pui_backend_minor) { + TBM_ERR("PUI backend module ABI minor ver(%d) is newer than the PUI's ver(%d)\n", + backend_module_minor, pui_backend_minor); + goto err; + } + + if (!backend_module_info->backend_init || !backend_module_info->backend_deinit) + { + pui_err("Backend module doesn't have backend_init/backend_deinit function !\n"); + goto err; + } + + backend_module_data = backend_module_info->backend_init(); + + if (!backend_module_data) + { + pui_err("Failed to init module (%s) !\n", DEFAULT_LIB); + goto err; + } + + pui_module->module_info = module_info; + pui_module->backend_module_info = backend_module_info; + pui_module->backend_module_data = backend_module_data; + + return; + +err: + if (backend_module_info) + backend_module_info->backend_deinit + + if (module_info) + dlclose(module_info); + + return; +} + +static void +_pui_unload_backend_module(void) +{ + if (!pui_module) + { + pui_err("Invalid pui module !\n"); + return; + } + + if (pui_module->backend_module_info) + { + pui_module->backend_module_info->backend_deinit(pui_module->backend_module_data); + pui_module->backend_module_data = NULL; + pui_module->backend_module_info = NULL; + } + + if (pui_module->module_info) + dlclose(pui_module->module_info); +} + +static void +_pui_load(void) +{ + _pui_load_backend_module(); +} + +static void +_pui_unload(void) +{ + _pui_unload_backend_module(); +} + +static void +_pui_event_init(void) +{ + PUI_EVENT_ANI_STARTED = ecore_event_type_new(); + PUI_EVENT_ANI_STOPPED = ecore_event_type_new(); + PUI_EVENT_ANI_PAUSED = ecore_event_type_new(); + PUI_EVENT_ANI_READY_TO_START = ecore_event_type_new(); + PUI_EVENT_ANI_READY_TO_RESUME = ecore_event_type_new(); + PUI_EVENT_ANI_FRAME_DONE = ecore_event_type_new(); + PUI_EVENT_ANI_BUFFER_RELEASED = ecore_event_type_new(); +} + +static void +_pui_event_shutdown(void) +{ + ecore_event_type_flush(PUI_EVENT_ANI_STARTED, + PUI_EVENT_ANI_STOPPED, + PUI_EVENT_ANI_PAUSED, + PUI_EVENT_ANI_READY_TO_START, + PUI_EVENT_ANI_READY_TO_RESUME, + PUI_EVENT_ANI_FRAME_DONE, + PUI_EVENT_ANI_BUFFER_RELEASED); + + PUI_EVENT_ANI_STARTED = -1; + PUI_EVENT_ANI_STOPPED = -1; + PUI_EVENT_ANI_PAUSED = -1; + PUI_EVENT_ANI_READY_TO_START = -1; + PUI_EVENT_ANI_READY_TO_RESUME = -1; + PUI_EVENT_ANI_FRAME_DONE = -1; + PUI_EVENT_ANI_BUFFER_RELEASED = -1; +} + +int +pui_init(void) +{ + if (++_pui_init_count != 1) + return _pui_init_count; + + if (pui_module) + { + pui_err("Invalid calling of pui_init() !\n"); + goto error; + } + + pui_module = (pui_module_data *)calloc(1, sizeof(pui_module_data)); + + if (!pui_module) + { + pui_err("Failed to allocate memory for pui module data !\n"); + goto error; + } + + //TODO + ecore_wl2_init(); + + _pui_event_init(); + + _pui_load(); + + return _pui_init_count; + +error: + return --_pui_init_count; +} + +int +pui_shutdown(void) +{ + if (_pui_init_count <= 0) + { + pui_err("Invalid pui init count : %d\n", _pui_init_count); + _pui_init_count = 0; + return 0; + } + + if (!pui_module) + { + pui_err("Invalid pui module data !\n"); + return _pui_init_count; + } + + _pui_init_count--; + + //TODO + _pui_unload(); + + _pui_event_shutdown(); + + ecore_wl2_shutdown(); + + free(pui_module); + + return _pui_init_count; +} + diff --git a/src/PUI_ani.c b/src/PUI_ani.c new file mode 100644 index 0000000..2ac1d0d --- /dev/null +++ b/src/PUI_ani.c @@ -0,0 +1,464 @@ +#include "PUI.h" +#include "PUI_internal.h" +#include + +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_ani_h handle = (pui_ani_h)data; + Ecore_Wl2_Event_Window_Show *ev = (Ecore_Wl2_Event_Window_Show *)event; + + pui_info("...\n"); + + /* TODO */ + (void) handle; + (void) ev; + + return ECORE_CALLBACK_PASS_ON; +} + +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; + + pui_info("...\n"); + + /* TODO */ + (void) handle; + (void) ev; + + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_cb_focus_out(void *data, int type EINA_UNUSED, void *event) +{ + pui_ani_h handle = (pui_ani_h)data; + Ecore_Wl2_Event_Focus_Out *ev = (Ecore_Wl2_Event_Focus_Out *)event; + + pui_info("...\n"); + + /* TODO */ + (void) handle; + (void) ev; + + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_cb_visibility_change(void *data, int type EINA_UNUSED, void *event) +{ + pui_ani_h handle = (pui_ani_h)data; + pui_h ph = handle->pui_handle; + + Ecore_Wl2_Event_Window_Visibility_Change *ev; + PUI_Event_Animation_Status *e = NULL; + + ev = event; + + pui_info("Visibility change (window=0x%x, fully_obscured=%d)\n", ev->win, ev->fully_obscured); + + ph->visiblity = !(ev->fully_obscured); + + if (ev->fully_obscured) + { + //TODO : e + if (handle->status == PUI_ANI_STATUS_RUNNING) + { + handle->status = PUI_ANI_STATUS_STOPPED; + + //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; + + ecore_event_add(PUI_EVENT_ANI_STOPPED, e, NULL, handle); + } + } + } + else + { + //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); + } + } + } + + 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); + + pui_info("[UPDATE] release wl_buffer:%p, surface:%p\n", buffer, surface); +} + +static const struct wl_buffer_listener buffer_listener = { + _buffer_release +}; + +pui_ani_control_buffer * +pui_ani_get_buffer(pui_ani_h ani_h) +{ + pui_h handle = NULL; + tbm_surface_error_e ret; + tbm_surface_h surface; + pui_ani_control_buffer *buffer = NULL; + + if (!ani_h) + { + pui_err( "Invalid pui ani handle !\n"); + return NULL; + } + + handle = ani_h->pui_handle; + + if (!handle) + { + pui_err("Error : PUI_INT_ERROR_INVALID_HANDLE\n"); + return NULL; + } + + if (handle->current_surface) + { + pui_warn("Current_surface is not used !\n"); + } + + if (!tbm_surface_queue_can_dequeue(handle->tbm_queue, 0)) + { + pui_err("[UPDATE] Cannot dequeue (error : PUI_ERROR_INTERNAL)\n"); + return NULL; + } + + ret = tbm_surface_queue_dequeue(handle->tbm_queue, &surface); + + if (ret != TBM_SURFACE_ERROR_NONE) + { + pui_err("[UPDATE] dequeue err:%d\n", ret); + return NULL; + } + + tbm_surface_map(surface, TBM_SURF_OPTION_READ | TBM_SURF_OPTION_WRITE, &handle->sinfo); + + handle->current_surface = surface; + buffer = (pui_ani_control_buffer *)&(handle->sinfo.planes[0]); + + return buffer; +} + +pui_int_error +pui_ani_set_buffer(pui_ani_h ani_h, pui_ani_control_buffer *buffer) +{ + pui_h handle = NULL; + + if (!ani_h) + { + pui_err("Invalid ani handle !\n"); + return PUI_INT_ERROR_INVALID_HANDLE; + } + + handle = ani_h->pui_handle; + + if (!handle) + { + pui_err("Error : PUI_INT_ERROR_INVALID_HANDLE\n"); + return PUI_INT_ERROR_INVALID_HANDLE; + } + + if (!handle->current_surface) + { + pui_err("Current_surface is not valid !\n"); + return PUI_INT_ERROR_INVALID_SURFACE; + } + + if (!buffer || !buffer->ptr || !buffer->size) + return PUI_INT_ERROR_INVALID_BUFFER; + + handle->is_buffer_set = 1; + + return PUI_INT_ERROR_NONE; +} + +pui_int_error +pui_ani_update(pui_ani_h ani_h) +{ + tbm_surface_h surface; + tbm_surface_error_e ret; + + pui_h handle = NULL; + + if (!ani_h) + { + pui_err("Invalid ani handle !\n"); + return PUI_INT_ERROR_INVALID_HANDLE; + } + + handle = ani_h->pui_handle; + + if (!handle) + { + pui_err("Error : PUI_INT_ERROR_INVALID_HANDLE\n"); + return PUI_INT_ERROR_INVALID_HANDLE; + } + + if (!handle->current_surface) + return PUI_INT_ERROR_INVALID_SURFACE; + + if (!handle->is_buffer_set) + { + pui_err("Buffer is not set !\n"); + return PUI_INT_ERROR_INVALID_BUFFER; + } + + surface = handle->current_surface; + handle->current_surface = NULL; + + tbm_surface_unmap(surface); + + ret = tbm_surface_queue_enqueue(handle->tbm_queue, surface); + + if (ret != TBM_SURFACE_ERROR_NONE) + { + pui_err("[UPDATE] enqueue err:%d\n", ret); + return; + } + + ret = tbm_surface_queue_acquire(handle->tbm_queue, &surface); + + if (ret != TBM_SURFACE_ERROR_NONE) + { + pui_err("[UPDATE] acquire err:%d\n", ret); + 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 (!wl_buffer) + { + pui_err("[UPDATE] failed to create wl_buffer tbm_surface:%p\n", surface); + return; + } + + wl_buffer_add_listener(wl_buffer, &buffer_listener, surface); + + 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); + } + + if (!wl_buffer) + { + pui_err("[UPDATE] dequeue err:%d\n", ret); + return; + } + + 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); + + pui_info("[UPDATE] commit wl_buffer:%p, surface:%p\n", wl_buffer, surface); + + handle->is_buffer_set = 0; + + return PUI_INT_ERROR_NONE; +} + +static void +_pui_ani_event_handlers_init(pui_ani_h ani_h) +{ + Ecore_Event_Handler *h = NULL; + + if (!ani_h) + { + pui_err("Invalid handle !\n"); + return; + } + + if (!ani_h->ecore_event_hdls) + ani_h->ecore_event_hdls = eina_array_new(5); + + h = ecore_event_handler_add(ECORE_WL2_EVENT_WINDOW_SHOW, _cb_window_show, handle); + eina_array_push(ani_h->_ecore_event_hdls, h); + + h = ecore_event_handler_add(ECORE_WL2_EVENT_FOCUS_IN, _cb_focus_in, handle); + eina_array_push(ani_h->_ecore_event_hdls, h); + + h = ecore_event_handler_add(ECORE_WL2_EVENT_FOCUS_OUT, _cb_focus_out, handle); + eina_array_push(ani_h->_ecore_event_hdls, h); + + h = ecore_event_handler_add(ECORE_WL2_EVENT_WINDOW_VISIBILITY_CHANGE, _cb_visibility_change, handle); + eina_array_push(ani_h->_ecore_event_hdls, h); + +} + +static void +_pui_ani_event_handlers_shutdown(pui_ani_h ani_h) +{ + if (!ani_h) + { + pui_err("Invalid handle !\n"); + return; + } + + 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_id +pui_ani_get_id(pui_ani_h ani_h) +{ + if (ani_h && ani_h->id) + return ani_h->id; +} + +pui_ani_cmd +pui_ani_get_cmd(pui_ani_h ani_h) +{ + if (ani_h && ani_h->cmd) + return ani_h->cmd; +} + +pui_ani_opt +pui_ani_get_opt(pui_ani_h ani_h) +{ + if (ani_h && ani_h->opt) + return ani_h->opt; +} + +pui_error +pui_ani_control(pui_ani_h ani_h, pui_ani_cmd cmd, pui_ani_opt opt) +{ + if (!ani_h) + return PUI_ERROR_INVALID_ANI_HANDLE; + + if (cmd < PUI_ANI_CMD_START || cmd >= PUI_ANI_CMD_LAST) + return PUI_ERROR_INVALID_ANI_CMD; + + if (opt < PUI_ANI_OPT_NONE || opt >= PUI_ANI_OPT_LAST) + return PUI_ERROR_INVALID_ANI_OPT; + + if (ani_h->id && ani_h->status == PUI_ANI_STATUS_RUNNING) + { + + } + + ani_h->cmd = cmd; + ani_h->opt = opt; + ani_h->status = PUI_ANI_STATUS_STOPPED; + + ani_h->frame_cb = ecore_wl2_window_frame_callback_add(win, _pui_cb_frame, handle); + + if (!ani_h->frame_cb) + { + pui_err("Failed to add frame callback !"); + goto err; + } + + //TODO + + return PUI_ERROR_NONE; + +err: + return PUI_ERROR_INTERNAL; +} + +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; + + if (!handle || !handle->backend_module_data)) + { + pui_err("Invalid pui handle or backend module data !\n"); + return NULL; + } + + ani_func = handle->backend_module_data->get_ani_func(id); + + if (!ani_func) + { + pui_err("Invalid ani func from backend module data !\n"); + return NULL; + } + + ani_h = (pui_ani_h)calloc(1, sizeof(pui_ani_h)); + + if (!ani_h) + { + pui_err("Failed to allocate memory for pui ani handle !\n"); + return NULL; + } + + ani_h->ecore_event_hdls = NULL; + _pui_ani_event_handlers_init(ani_h); + + ani_mgr = (pui_ani_mgr *)calloc(1, sizeof(pui_ani_mgr)); + + if (!ani_mgr) + { + 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; + + return ani_h; + +err: + if (ani_h) + free(ani_h); + return NULL; +} + +void +pui_ani_destroy(pui_ani_h ani_h) +{ + if (!ani_h) + return; + + 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); + + _pui_ani_event_handlers_shutdown(ani_h); + + if (ani_h->frame_cb) + { + ecore_wl2_window_frame_callback_del(ani_h->frame_cb); + ani_h->frame_cb = NULL; + } +} + diff --git a/src/PUI_backend.c b/src/PUI_backend.c new file mode 100644 index 0000000..d985624 --- /dev/null +++ b/src/PUI_backend.c @@ -0,0 +1,109 @@ +#include +#include "PUI_backend.h" +#include "PUI_internal.h" + +pui_ani_control_buffer * +pui_backend_ani_get_buffer(pui_ani_mgr *ani_mgr) +{ + pui_ani_control_buffer *buffer = NULL; + + buffer = pui_ani_get_buffer(ani_mgr->ani_h); + + if (!buffer) + return NULL; + + return buffer; +} + +pui_int_error +pui_backend_ani_set_buffer(pui_ani_mgr *ani_mgr, pui_ani_control_buffer *buffer) +{ + pui_int_error err = PUI_INT_ERROR_NONE; + + if (!buffer) + return PUI_INT_ERROR_INVALID_BUFFER; + + err = pui_ani_set_buffer(ani_mgr->ani_h, buffer); + + return err; +} + +pui_int_error +pui_backend_ani_update(pui_ani_mgr *ani_mgr) +{ + pui_int_error err = PUI_INT_ERROR_NONE; + + err = pui_ani_update(ani_mgr->ani_h); + + return err; +} + +void +pui_backend_ani_add_frame_cb(pui_ani_mgr *ani_mgr, Eina_Bool (*frame_cb)(void *data), double expire, void *data) +{ + Ecore_Timer *timer = NULL; + + if (!ani_mgr) + return; + + ani_mgr->frame_cb = frame_cb; + ani_mgr->expire = expire; + ani_mgr->frame_cb_data = data; + + timer = ecore_timer_add(expire, (Ecore_Task_Cb)frame_cb, data); + + if (ani_mgr->frame_cb_timer) + { + ecore_timer_del(ani_mgr->frame_cb_timer); + ani_mgr->frame_cb_timer = NULL; + } + + ani_mgr->frame_cb_timer = timer; +} + +void +pui_backend_ani_remove_frame_cb(pui_ani_mgr *ani_mgr, void *data) +{ + if (!ani_mgr) + return; + + if (ani_mgr->frame_cb_timer) + { + ecore_timer_del(ani_mgr->frame_cb_timer); + ani_mgr->frame_cb_timer = NULL; + } + + ani_mgr->frame_cb = NULL; + ani_mgr->expire = 0; + ani_mgr->frame_cb_data = NULL; +} + +pui_backend_ani_func * +pui_backend_ani_alloc_ani_func(void) +{ + pui_backend_ani_func *ani_func = NULL; + + ani_func = (pui_backend_ani_func *)calloc(1, sizeof(pui_backend_ani_func)); + if (!ani_func) + { + pui_err("Failed to allocate memory !\n"); + return NULL; + } + + pui_info("Succeed to allocate memory !\n"); + return ani_func; +} + +void +pui_backend_ani_free_ani_func(pui_backend_ani_func *ani_func) +{ + if (!ani_func) + { + pui_err("Invalid ani backend_func pointer !\n"); + return; + } + + free(ani_func); + pui_info("Succeed to free memory !\n"); +} + -- 2.7.4