diff options
Diffstat (limited to 'src/script_handler.c')
-rw-r--r-- | src/script_handler.c | 1511 |
1 files changed, 1511 insertions, 0 deletions
diff --git a/src/script_handler.c b/src/script_handler.c new file mode 100644 index 0000000..0d973f8 --- /dev/null +++ b/src/script_handler.c @@ -0,0 +1,1511 @@ +/* + * Copyright 2013 Samsung Electronics Co., Ltd + * + * Licensed under the Flora License, Version 1.1 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://floralicense.org/license/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stdio.h> +#include <errno.h> +#include <stdlib.h> /* free */ +#include <ctype.h> +#include <dlfcn.h> +#include <sys/types.h> +#include <dirent.h> +#include <string.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> + +#include <Ecore.h> +#include <Eina.h> + +#include <dlog.h> +#include <packet.h> +#include <livebox-errno.h> + +#include "slave_life.h" +#include "slave_rpc.h" +#include "client_life.h" +#include "package.h" +#include "instance.h" +#include "buffer_handler.h" +#include "script_handler.h" +#include "debug.h" +#include "conf.h" +#include "util.h" + +#define INFO_SIZE "size" +#define INFO_CATEGORY "category" + +static const char *type_list[] = { + "access", + "access,operation", + "color", + "drag", + "image", + "info", + "script", + "signal", + "text", + NULL +}; + +static const char *field_list[] = { + "type", + "part", + "data", + "option", + "id", + "target", + "file", + NULL +}; + +int errno; + +static struct info { + Eina_List *script_port_list; + enum buffer_type env_buf_type; +} s_info = { + .script_port_list = NULL, + .env_buf_type = BUFFER_TYPE_FILE, +}; + +struct script_port { + void *handle; + + const char *(*magic_id)(void); + int (*update_color)(void *handle, const char *id, const char *part, const char *rgba); + int (*update_text)(void *handle, const char *id, const char *part, const char *text); + int (*update_image)(void *handle, const char *id, const char *part, const char *path, const char *option); + int (*update_access)(void *handle, const char *id, const char *part, const char *text, const char *option); + int (*operate_access)(void *handle, const char *id, const char *part, const char *operation, const char *option); + int (*update_script)(void *handle, const char *src_id, const char *target_id, const char *part, const char *path, const char *option); + int (*update_signal)(void *handle, const char *id, const char *part, const char *signal); + int (*update_drag)(void *handle, const char *id, const char *part, double x, double y); + int (*update_size)(void *handle, const char *id, int w, int h); + int (*update_category)(void *handle, const char *id, const char *category); + int (*feed_event)(void *handle, int event_type, int x, int y, int down, unsigned int keycode, double timestamp); + + void *(*create)(void *buffer_info, const char *file, const char *option); + int (*destroy)(void *handle); + + int (*load)(void *handle, int (*render_pre)(void *buffer_info, void *data), int (*render_post)(void *buffer_info, void *data), void *data); + int (*unload)(void *handle); + + int (*init)(double scale, int premultiplied); + int (*fini)(void); +}; + +enum block_type { + TYPE_ACCESS, + TYPE_ACCESS_OP, + TYPE_COLOR, + TYPE_DRAG, + TYPE_IMAGE, + TYPE_INFO, + TYPE_SCRIPT, + TYPE_SIGNAL, + TYPE_TEXT, + TYPE_MAX +}; + +enum field_type { + FIELD_TYPE, + FIELD_PART, + FIELD_DATA, + FIELD_OPTION, + FIELD_ID, + FIELD_TARGET, + FIELD_FILE +}; + +struct block { + enum block_type type; + char *part; + char *data; + char *option; + char *id; + char *target; + char *file; + + /* Should be released */ + char *filebuf; + const char *filename; +}; + +struct script_info { + struct buffer_info *buffer_handle; + int loaded; + + int w; + int h; + + int x; + int y; + int down; + + unsigned int keycode; + + struct script_port *port; + void *port_data; + + Eina_List *cached_blocks; +}; + +static inline void consuming_parsed_block(struct inst_info *inst, int is_pd, struct block *block); + +static int load_all_ports(void) +{ + struct script_port *item; + struct dirent *ent; + DIR *dir; + char *path; + int pathlen; + + dir = opendir(SCRIPT_PORT_PATH); + if (!dir) { + ErrPrint("Error: %s\n", strerror(errno)); + return LB_STATUS_ERROR_IO; + } + + while ((ent = readdir(dir))) { + if (ent->d_name[0] == '.') { + continue; + } + + pathlen = strlen(ent->d_name) + strlen(SCRIPT_PORT_PATH) + 1; + path = malloc(pathlen); + if (!path) { + ErrPrint("Heap: %s %d\n", strerror(errno), pathlen); + if (closedir(dir) < 0) { + ErrPrint("closedir: %s\n", strerror(errno)); + } + return LB_STATUS_ERROR_MEMORY; + } + + snprintf(path, pathlen, "%s%s", SCRIPT_PORT_PATH, ent->d_name); + + item = malloc(sizeof(*item)); + if (!item) { + ErrPrint("Heap: %s\n", strerror(errno)); + DbgFree(path); + if (closedir(dir) < 0) { + ErrPrint("closedir: %s\n", strerror(errno)); + } + return LB_STATUS_ERROR_MEMORY; + } + + DbgPrint("Open SCRIPT PORT: %s\n", path); + item->handle = dlopen(path, RTLD_GLOBAL | RTLD_NOW | RTLD_DEEPBIND); + DbgFree(path); + if (!item->handle) { + ErrPrint("Error: %s\n", dlerror()); + DbgFree(item); + if (closedir(dir) < 0) { + ErrPrint("closedir: %s\n", strerror(errno)); + } + return LB_STATUS_ERROR_FAULT; + } + + item->magic_id = dlsym(item->handle, "script_magic_id"); + if (!item->magic_id) { + goto errout; + } + + DbgPrint("SCRIPT PORT magic id: %s\n", item->magic_id()); + + item->update_color = dlsym(item->handle, "script_update_color"); + if (!item->update_color) { + goto errout; + } + + item->update_text = dlsym(item->handle, "script_update_text"); + if (!item->update_text) { + goto errout; + } + + item->update_image = dlsym(item->handle, "script_update_image"); + if (!item->update_image) { + goto errout; + } + + item->update_access = dlsym(item->handle, "script_update_access"); + if (!item->update_access) { + goto errout; + } + + item->operate_access = dlsym(item->handle, "script_operate_access"); + if (!item->operate_access) { + goto errout; + } + + item->update_script = dlsym(item->handle, "script_update_script"); + if (!item->update_script) { + goto errout; + } + + item->update_signal = dlsym(item->handle, "script_update_signal"); + if (!item->update_signal) { + goto errout; + } + + item->update_drag = dlsym(item->handle, "script_update_drag"); + if (!item->update_drag) { + goto errout; + } + + item->update_size = dlsym(item->handle, "script_update_size"); + if (!item->update_size) { + goto errout; + } + + item->update_category = dlsym(item->handle, "script_update_category"); + if (!item->update_category) { + goto errout; + } + + item->create = dlsym(item->handle, "script_create"); + if (!item->create) { + goto errout; + } + + item->destroy = dlsym(item->handle, "script_destroy"); + if (!item->destroy) { + goto errout; + } + + item->load = dlsym(item->handle, "script_load"); + if (!item->load) { + goto errout; + } + + item->unload = dlsym(item->handle, "script_unload"); + if (!item->unload) { + goto errout; + } + + item->init = dlsym(item->handle, "script_init"); + if (!item->init) { + goto errout; + } + + item->fini = dlsym(item->handle, "script_fini"); + if (!item->fini) { + goto errout; + } + + item->feed_event = dlsym(item->handle, "script_feed_event"); + if (!item->feed_event) { + goto errout; + } + + if (item->init(SCALE_WIDTH_FACTOR, PREMULTIPLIED_COLOR) < 0) { + ErrPrint("Failed to initialize script engine\n"); + goto errout; + } + + s_info.script_port_list = eina_list_append(s_info.script_port_list, item); + } + + if (closedir(dir) < 0) { + ErrPrint("closedir: %s\n", strerror(errno)); + } + + return LB_STATUS_SUCCESS; + +errout: + ErrPrint("Error: %s\n", dlerror()); + if (dlclose(item->handle) != 0) { + ErrPrint("dlclose: %s\n", strerror(errno)); + } + DbgFree(item); + if (closedir(dir) < 0) { + ErrPrint("closedir: %s\n", strerror(errno)); + } + return LB_STATUS_ERROR_FAULT; +} + +static inline struct script_port *find_port(const char *magic_id) +{ + Eina_List *l; + struct script_port *item; + + if (!s_info.script_port_list) { + int ret; + + ret = load_all_ports(); + if (ret < 0) { + ErrPrint("load_all_ports: %d\n", ret); + } + } + + EINA_LIST_FOREACH(s_info.script_port_list, l, item) { + if (!strcmp(item->magic_id(), magic_id)) { + return item; + } + } + + return NULL; +} + +static inline void delete_block(struct block *block) +{ + DbgFree(block->filebuf); + DbgFree(block); +} + +static int render_post_cb(void *_buffer_handle, void *data) +{ + PERF_INIT(); + PERF_BEGIN(); + struct inst_info *inst; + struct buffer_info *buffer_handle = _buffer_handle; + struct script_info *info; + + inst = buffer_handler_instance(buffer_handle); + if (!inst) { + goto out; + } + + if (instance_state(inst) != INST_ACTIVATED) { + ErrPrint("Render post invoked but instance is not activated\n"); + PERF_MARK(__func__); + return LB_STATUS_ERROR_INVALID; + } + + info = instance_lb_script(inst); + if (info && info == data) { + buffer_handler_flush(buffer_handle); + instance_lb_updated_by_instance(inst, NULL); + PERF_MARK("lb,update"); + return LB_STATUS_SUCCESS; + } + + info = instance_pd_script(inst); + if (info && info == data) { + buffer_handler_flush(buffer_handle); + instance_pd_updated_by_instance(inst, NULL); + PERF_MARK("pd,update"); + return LB_STATUS_SUCCESS; + } + +out: + ErrPrint("Failed to sync\n"); + PERF_MARK(__func__); + return LB_STATUS_ERROR_FAULT; +} + +/*! + * \NOTE + * Exported API + */ +EAPI int script_signal_emit(void *buffer_handle, const char *part, const char *signal, double sx, double sy, double ex, double ey) +{ + struct script_info *info; + struct inst_info *inst; + int w; + int h; + double fx; + double fy; + + if (!buffer_handle) { + ErrPrint("Invalid handle\n"); + return LB_STATUS_ERROR_INVALID; + } + + info = buffer_handler_data(buffer_handle); + if (!info) { + ErrPrint("Invalid handle\n"); + return LB_STATUS_ERROR_INVALID; + } + + inst = buffer_handler_instance(buffer_handle); + if (!inst) { + return LB_STATUS_ERROR_FAULT; + } + + if (!signal || strlen(signal) == 0) { + signal = ""; + } + + if (!part || strlen(part) == 0) { + part = ""; + } + + buffer_handler_get_size(buffer_handle, &w, &h); + + fx = (double)info->x / (double)w; + fy = (double)info->y / (double)h; + + return instance_signal_emit(inst, signal, part, sx, sy, ex, ey, fx, fy, info->down); +} + +static inline void flushing_cached_block(struct script_info *info) +{ + struct block *block; + struct inst_info *inst; + int is_pd; + + inst = buffer_handler_instance(info->buffer_handle); + if (!inst) { + ErrPrint("Instance is not valid\n"); + EINA_LIST_FREE(info->cached_blocks, block) { + delete_block(block); + } + return; + } + + is_pd = instance_pd_script(inst) == info; + + EINA_LIST_FREE(info->cached_blocks, block) { + consuming_parsed_block(inst, is_pd, block); + } +} + +HAPI int script_handler_load(struct script_info *info, int is_pd) +{ + struct inst_info *inst; + + if (!info || !info->port) { + ErrPrint("Script handler is not created\n"); + return LB_STATUS_ERROR_INVALID; + } + + if (info->loaded > 0) { + info->loaded++; + return LB_STATUS_SUCCESS; + } + + if (info->port->load(info->port_data, NULL, render_post_cb, info) < 0) { + ErrPrint("Unable to load the script\n"); + return LB_STATUS_ERROR_FAULT; + } + + info->loaded = 1; + flushing_cached_block(info); + + inst = buffer_handler_instance(info->buffer_handle); + if (inst) { + script_signal_emit(info->buffer_handle, instance_id(inst), + is_pd ? "pd,show" : "lb,show", 0.0f, 0.0f, 0.0f, 0.0f); + } + buffer_handler_flush(info->buffer_handle); + return LB_STATUS_SUCCESS; +} + +HAPI int script_handler_unload(struct script_info *info, int is_pd) +{ + struct inst_info *inst; + + if (!info || !info->port) { + return LB_STATUS_ERROR_INVALID; + } + + info->loaded--; + if (info->loaded > 0) { + return LB_STATUS_ERROR_BUSY; + } + + if (info->loaded < 0) { + info->loaded = 0; + return LB_STATUS_ERROR_ALREADY; + } + + inst = buffer_handler_instance(info->buffer_handle); + if (inst) { + script_signal_emit(info->buffer_handle, instance_id(inst), + is_pd ? "pd,hide" : "lb,hide", 0.0f, 0.0f, 0.0f, 0.0f); + } + + if (info->port->unload(info->port_data) < 0) { + ErrPrint("Failed to unload script object. but go ahead\n"); + } + + return LB_STATUS_SUCCESS; +} + +HAPI struct script_info *script_handler_create(struct inst_info *inst, const char *file, const char *option, int w, int h) +{ + struct script_info *info; + + DbgPrint("Create script: %s (%s) %dx%d\n", file, option, w, h); + + if (!file) { + return NULL; + } + + info = calloc(1, sizeof(*info)); + if (!info) { + ErrPrint("Heap: %s\n", strerror(errno)); + return NULL; + } + + info->buffer_handle = buffer_handler_create(inst, s_info.env_buf_type, w, h, DEFAULT_PIXELS); + if (!info->buffer_handle) { + /* buffer_handler_create will prints some log */ + DbgFree(info); + return NULL; + } + + (void)buffer_handler_set_data(info->buffer_handle, info); + + info->port = find_port(package_script(instance_package(inst))); + if (!info->port) { + ErrPrint("Failed to find a proper port for [%s]%s\n", + instance_package(inst), package_script(instance_package(inst))); + buffer_handler_destroy(info->buffer_handle); + DbgFree(info); + return NULL; + } + + info->port_data = info->port->create(info->buffer_handle, file, option); + if (!info->port_data) { + ErrPrint("Failed to create a port (%s - %s)\n", file, option); + buffer_handler_destroy(info->buffer_handle); + DbgFree(info); + return NULL; + } + + return info; +} + +HAPI int script_handler_destroy(struct script_info *info) +{ + struct block *block; + int ret; + + if (!info || !info->port) { + ErrPrint("port is not valid\n"); + return LB_STATUS_ERROR_INVALID; + } + + if (info->loaded != 0) { + ErrPrint("Script handler is not unloaded\n"); + return LB_STATUS_ERROR_BUSY; + } + + ret = info->port->destroy(info->port_data); + if (ret < 0) { + ErrPrint("Failed to destroy port, but go ahead: %d\n", ret); + } + + (void)buffer_handler_destroy(info->buffer_handle); + + EINA_LIST_FREE(info->cached_blocks, block) { + delete_block(block); + } + + DbgFree(info); + return LB_STATUS_SUCCESS; +} + +HAPI int script_handler_is_loaded(struct script_info *info) +{ + return info ? info->loaded > 0 : 0; +} + +HAPI struct buffer_info *script_handler_buffer_info(struct script_info *info) +{ + if (!info) { + return NULL; + } + + return info->buffer_handle; +} + +static int update_script_color(struct inst_info *inst, struct block *block, int is_pd) +{ + PERF_INIT(); + PERF_BEGIN(); + struct script_info *info; + int ret; + + if (!block || !block->part || !block->data) { + ErrPrint("Block or part or data is not valid\n"); + PERF_MARK("color"); + return LB_STATUS_ERROR_INVALID; + } + + info = is_pd ? instance_pd_script(inst) : instance_lb_script(inst); + if (!info) { + ErrPrint("info is NIL (%d, %s)\n", is_pd, instance_id(inst)); + PERF_MARK("color"); + return LB_STATUS_ERROR_FAULT; + } + + if (!info->port) { + ErrPrint("info->port is NIL (%d, %s)\n", is_pd, instance_id(inst)); + PERF_MARK("color"); + return LB_STATUS_ERROR_INVALID; + } + + ret = info->port->update_color(info->port_data, block->id, block->part, block->data); + PERF_MARK("color"); + return ret; +} + +static int update_script_text(struct inst_info *inst, struct block *block, int is_pd) +{ + PERF_INIT(); + PERF_BEGIN(); + struct script_info *info; + int ret; + + if (!block || !block->part || !block->data) { + ErrPrint("Block or part or data is not valid\n"); + PERF_MARK("text"); + return LB_STATUS_ERROR_INVALID; + } + + info = is_pd ? instance_pd_script(inst) : instance_lb_script(inst); + if (!info) { + ErrPrint("info is NIL (%d, %s)\n", is_pd, instance_id(inst)); + PERF_MARK("text"); + return LB_STATUS_ERROR_FAULT; + } + + if (!info->port) { + ErrPrint("info->port is NIL\n"); + PERF_MARK("text"); + return LB_STATUS_ERROR_INVALID; + } + + DbgPrint("[%s] %s (%s)\n", block->id, block->part, block->data); + ret = info->port->update_text(info->port_data, block->id, block->part, block->data); + + PERF_MARK("text"); + return ret; +} + +static int update_script_image(struct inst_info *inst, struct block *block, int is_pd) +{ + PERF_INIT(); + PERF_BEGIN(); + struct script_info *info; + int ret; + + if (!block || !block->part) { + ErrPrint("Block or part is not valid\n"); + PERF_MARK("image"); + return LB_STATUS_ERROR_INVALID; + } + + info = is_pd ? instance_pd_script(inst) : instance_lb_script(inst); + if (!info) { + ErrPrint("info is NIL (%d, %s)\n", is_pd, instance_id(inst)); + PERF_MARK("image"); + return LB_STATUS_ERROR_FAULT; + } + + if (!info->port) { + ErrPrint("info->port is NIL\n"); + PERF_MARK("image"); + return LB_STATUS_ERROR_INVALID; + } + + DbgPrint("[%s] %s (%s)\n", block->id, block->part, block->data); + ret = info->port->update_image(info->port_data, block->id, block->part, block->data, block->option); + PERF_MARK("image"); + return ret; +} + +static int update_access(struct inst_info *inst, struct block *block, int is_pd) +{ + PERF_INIT(); + PERF_BEGIN(); + struct script_info *info; + int ret; + + if (!block || !block->part) { + ErrPrint("Block or block->part is NIL\n"); + PERF_MARK("access"); + return LB_STATUS_ERROR_INVALID; + } + + info = is_pd ? instance_pd_script(inst) : instance_lb_script(inst); + if (!info) { + ErrPrint("info is NIL (%d, %s)\n", is_pd, instance_id(inst)); + PERF_MARK("access"); + return LB_STATUS_ERROR_FAULT; + } + + if (!info->port) { + ErrPrint("info->port is NIL\n"); + PERF_MARK("access"); + return LB_STATUS_ERROR_INVALID; + } + + ret = info->port->update_access(info->port_data, block->id, block->part, block->data, block->option); + PERF_MARK("access"); + return ret; +} + +static int operate_access(struct inst_info *inst, struct block *block, int is_pd) +{ + PERF_INIT(); + PERF_BEGIN(); + struct script_info *info; + int ret; + + if (!block || !block->part) { + ErrPrint("Block or block->part is NIL\n"); + PERF_MARK("operate_access"); + return LB_STATUS_ERROR_INVALID; + } + + info = is_pd ? instance_pd_script(inst) : instance_lb_script(inst); + if (!info) { + ErrPrint("info is NIL (%d, %s)\n", is_pd, instance_id(inst)); + PERF_MARK("operate_access"); + return LB_STATUS_ERROR_FAULT; + } + + if (!info->port) { + ErrPrint("info->port is NIL\n"); + PERF_MARK("operate_access"); + return LB_STATUS_ERROR_INVALID; + } + + ret = info->port->operate_access(info->port_data, block->id, block->part, block->data, block->option); + PERF_MARK("operate_access"); + return ret; +} + +static int update_script_script(struct inst_info *inst, struct block *block, int is_pd) +{ + PERF_INIT(); + PERF_BEGIN(); + struct script_info *info; + int ret; + + if (!block || !block->part) { + ErrPrint("Block or part is NIL\n"); + PERF_MARK("script"); + return LB_STATUS_ERROR_INVALID; + } + + info = is_pd ? instance_pd_script(inst) : instance_lb_script(inst); + if (!info) { + ErrPrint("info is NIL (%d, %s)\n", is_pd, instance_id(inst)); + PERF_MARK("script"); + return LB_STATUS_ERROR_FAULT; + } + + if (!info->port) { + ErrPrint("info->port is NIL\n"); + PERF_MARK("script"); + return LB_STATUS_ERROR_INVALID; + } + + ret = info->port->update_script(info->port_data, block->id, block->target, block->part, block->data, block->option); + PERF_MARK("script"); + return ret; +} + +static int update_script_signal(struct inst_info *inst, struct block *block, int is_pd) +{ + PERF_INIT(); + PERF_BEGIN(); + struct script_info *info; + int ret; + + if (!block) { + ErrPrint("block is NIL\n"); + PERF_MARK("signal"); + return LB_STATUS_ERROR_INVALID; + } + + info = is_pd ? instance_pd_script(inst) : instance_lb_script(inst); + if (!info) { + ErrPrint("info is NIL (%d, %s)\n", is_pd, instance_id(inst)); + PERF_MARK("signal"); + return LB_STATUS_ERROR_FAULT; + } + + if (!info->port) { + ErrPrint("info->port is NIL\n"); + PERF_MARK("signal"); + return LB_STATUS_ERROR_INVALID; + } + + ret = info->port->update_signal(info->port_data, block->id, block->part, block->data); + PERF_MARK("signal"); + return ret; +} + +static int update_script_drag(struct inst_info *inst, struct block *block, int is_pd) +{ + PERF_INIT(); + PERF_BEGIN(); + struct script_info *info; + double dx, dy; + int ret; + + if (!block || !block->data || !block->part) { + ErrPrint("block or block->data or block->part is NIL\n"); + PERF_MARK("drag"); + return LB_STATUS_ERROR_INVALID; + } + + info = is_pd ? instance_pd_script(inst) : instance_lb_script(inst); + if (!info) { + ErrPrint("info is NIL (%d, %s)\n", is_pd, instance_id(inst)); + PERF_MARK("drag"); + return LB_STATUS_ERROR_FAULT; + } + + if (sscanf(block->data, "%lfx%lf", &dx, &dy) != 2) { + ErrPrint("Invalid format of data (DRAG data [%s])\n", block->data); + PERF_MARK("drag"); + return LB_STATUS_ERROR_INVALID; + } + + if (!info->port) { + ErrPrint("info->port is NIL\n"); + PERF_MARK("drag"); + return LB_STATUS_ERROR_INVALID; + } + + ret = info->port->update_drag(info->port_data, block->id, block->part, dx, dy); + PERF_MARK("drag"); + return ret; +} + +static void update_size_for_script(struct script_info *info, struct inst_info *inst, int w, int h) +{ + /*! + * \note + * After update the buffer size, + * If it required to be unload and load. + * New size of buffer will be allocated + */ + buffer_handler_update_size(info->buffer_handle, w, h); + + if (info->port->update_size) { + (void)info->port->update_size(info->port_data, NULL, w, h); + } + + if (instance_lb_script(inst) == info) { + instance_set_lb_size(inst, w, h); + } else if (instance_pd_script(inst) == info) { + instance_set_pd_size(inst, w, h); + } else { + ErrPrint("Unknown script\n"); + } +} + +HAPI int script_handler_resize(struct script_info *info, int w, int h) +{ + PERF_INIT(); + PERF_BEGIN(); + struct inst_info *inst; + + if (!info) { + ErrPrint("info[%p] resize is ignored\n", info); + PERF_MARK("resize"); + return LB_STATUS_SUCCESS; + } + + inst = buffer_handler_instance(info->buffer_handle); + if (!inst) { + ErrPrint("Instance is not valid\n"); + PERF_MARK("resize"); + return LB_STATUS_ERROR_INVALID; + } + + update_size_for_script(info, inst, w, h); + + PERF_MARK("resize"); + return LB_STATUS_SUCCESS; +} + +HAPI const char *script_handler_buffer_id(struct script_info *info) +{ + if (!info || !info->buffer_handle) { + ErrPrint("Invalid info\n"); + return ""; + } + + return buffer_handler_id(info->buffer_handle); +} + +static int update_info(struct inst_info *inst, struct block *block, int is_pd) +{ + PERF_INIT(); + PERF_BEGIN(); + struct script_info *info; + + if (!block || !block->part || !block->data) { + ErrPrint("block or block->part or block->data is NIL\n"); + PERF_MARK("info"); + return LB_STATUS_ERROR_INVALID; + } + + info = is_pd ? instance_pd_script(inst) : instance_lb_script(inst); + if (!info) { + ErrPrint("info is NIL (%d, %s)\n", is_pd, instance_id(inst)); + PERF_MARK("info"); + return LB_STATUS_ERROR_FAULT; + } + + if (!info->port) { + ErrPrint("info->port is NIL\n"); + PERF_MARK("info"); + return LB_STATUS_ERROR_INVALID; + } + + if (!strcasecmp(block->part, INFO_SIZE)) { + int w, h; + + if (sscanf(block->data, "%dx%d", &w, &h) != 2) { + ErrPrint("Invalid format for SIZE(%s)\n", block->data); + PERF_MARK("info"); + return LB_STATUS_ERROR_INVALID; + } + + if (!block->id) { + update_size_for_script(info, inst, w, h); + } else { + (void)info->port->update_size(info->port_data, block->id, w, h); + } + } else if (!strcasecmp(block->part, INFO_CATEGORY)) { + (void)info->port->update_category(info->port_data, block->id, block->data); + } + PERF_MARK("info"); + + return LB_STATUS_SUCCESS; +} + +static inline void consuming_parsed_block(struct inst_info *inst, int is_pd, struct block *block) +{ + struct script_info *info; + typedef int (*update_function_t)(struct inst_info *inst, struct block *block, int is_pd); + update_function_t updators[] = { + update_access, + operate_access, + update_script_color, + update_script_drag, + update_script_image, + update_info, + update_script_script, + update_script_signal, + update_script_text, + NULL + }; + + info = is_pd ? instance_pd_script(inst) : instance_lb_script(inst); + if (!info) { + ErrPrint("info is NIL (%d, %s)\n", is_pd, instance_id(inst)); + goto free_out; + } + + if (script_handler_is_loaded(info)) { + if (block->type >= 0 || block->type < TYPE_MAX) { + (void)updators[block->type](inst, block, is_pd); + } else { + ErrPrint("Block type[%d] is not valid\n", block->type); + } + } else { + info->cached_blocks = eina_list_append(info->cached_blocks, block); + DbgPrint("Block is cached (%p), %d, %s\n", block, eina_list_count(info->cached_blocks), instance_id(inst)); + return; + } + +free_out: + delete_block(block); +} + +HAPI int script_init(void) +{ + if (!strcasecmp(PROVIDER_METHOD, "shm")) { + s_info.env_buf_type = BUFFER_TYPE_SHM; + } else if (!strcasecmp(PROVIDER_METHOD, "pixmap")) { + s_info.env_buf_type = BUFFER_TYPE_PIXMAP; + } + + return LB_STATUS_SUCCESS; +} + +HAPI int script_fini(void) +{ + struct script_port *item; + /*! + * \TODO: Release all handles + */ + EINA_LIST_FREE(s_info.script_port_list, item) { + item->fini(); + if (dlclose(item->handle) != 0) { + ErrPrint("dlclose: %s\n", strerror(errno)); + } + DbgFree(item); + } + + return 0; +} + +HAPI int script_handler_update_pointer(struct script_info *info, int x, int y, int down) +{ + if (!info) { + return LB_STATUS_SUCCESS; + } + + info->x = x; + info->y = y; + + if (down == 0) { + info->down = 0; + } else if (down == 1) { + info->down = 1; + } + + return LB_STATUS_SUCCESS; +} + +HAPI int script_handler_update_keycode(struct script_info *info, unsigned int keycode) +{ + if (!info) { + return LB_STATUS_SUCCESS; + } + + info->keycode = keycode; + + return LB_STATUS_SUCCESS; +} + +HAPI int script_handler_feed_event(struct script_info *info, int event, double timestamp) +{ + int ret; + + if (!info->port) { + ErrPrint("info->port is NIL\n"); + return LB_STATUS_ERROR_INVALID; + } + + ret = info->port->feed_event(info->port_data, event, info->x, info->y, info->down, info->keycode, timestamp); + return ret; +} + +static inline char *load_file(const char *filename) +{ + char *filebuf = NULL; + int fd; + off_t filesize; + int ret; + size_t readsize = 0; + + fd = open(filename, O_RDONLY); + if (fd < 0) { + ErrPrint("open: %s\n", strerror(errno)); + return NULL; + } + + filesize = lseek(fd, 0L, SEEK_END); + if (filesize == (off_t)-1) { + ErrPrint("lseek: %s\n", strerror(errno)); + goto errout; + } + + if (lseek(fd, 0L, SEEK_SET) < 0) { + ErrPrint("lseek: %s\n", strerror(errno)); + goto errout; + } + + filebuf = malloc(filesize + 1); + if (!filebuf) { + ErrPrint("malloc: %s\n", strerror(errno)); + goto errout; + } + + while (readsize < filesize) { + ret = read(fd, filebuf + readsize, (size_t)filesize - readsize); + if (ret < 0) { + if (errno == EINTR) { + DbgPrint("Read is interrupted\n"); + continue; + } + + ErrPrint("read: %s\n", strerror(errno)); + free(filebuf); + filebuf = NULL; + break; + } + + readsize += ret; + } + + if (filebuf) { + filebuf[readsize] = '\0'; + } + + /*! + * \note + * Now, we are ready to parse the filebuf. + */ + +errout: + if (close(fd) < 0) { + ErrPrint("close: %s\n", strerror(errno)); + } + + return filebuf; +} + +#if defined(_APPLY_SCRIPT_ASYNC_UPDATE) +struct apply_data { + struct inst_info *inst; + Eina_List *block_list; + int is_pd; +}; + +static Eina_Bool apply_changes_cb(void *_data) +{ + struct apply_data *data = _data; + struct block *block; + + block = eina_list_nth(data->block_list, 0); + data->block_list = eina_list_remove(data->block_list, block); + consuming_parsed_block(data->inst, data->is_pd, block); + + if (!data->block_list) { + free(data); + return ECORE_CALLBACK_CANCEL; + } + + return ECORE_CALLBACK_RENEW; +} +#endif + + +HAPI int script_handler_parse_desc(struct inst_info *inst, const char *filename, int is_pd) +{ + PERF_INIT(); + PERF_BEGIN(); + int type_idx = 0; + int type_len = 0; + int field_idx = 0; + int field_len = 0; + char *filebuf; + char *fileptr; + char *ptr = NULL; + struct block *block = NULL; + Eina_List *block_list = NULL; + enum state { + BEGIN, + FIELD, + DATA, + END, + DONE, + ERROR, + } state; + + filebuf = load_file(filename); + if (!filebuf) { + return LB_STATUS_ERROR_IO; + } + + fileptr = filebuf; + + state = BEGIN; + while (*fileptr && state != ERROR) { + switch (state) { + case BEGIN: + if (*fileptr == '{') { + block = calloc(1, sizeof(*block)); + if (!block) { + ErrPrint("calloc: %s\n", strerror(errno)); + state = ERROR; + continue; + } + state = FIELD; + ptr = NULL; + } + break; + case FIELD: + if (isspace(*fileptr)) { + if (ptr != NULL) { + *fileptr = '\0'; + } + } else if (*fileptr == '=') { + *fileptr = '\0'; + ptr = NULL; + state = DATA; + } else if (ptr == NULL) { + ptr = fileptr; + field_idx = 0; + field_len = 0; + + while (field_list[field_idx]) { + if (field_list[field_idx][field_len] == *fileptr) { + break; + } + field_idx++; + } + + if (!field_list[field_idx]) { + ErrPrint("Invalid field\n"); + state = ERROR; + continue; + } + + field_len++; + } else { + if (field_list[field_idx][field_len] != *fileptr) { + field_idx++; + while (field_list[field_idx]) { + if (!strncmp(field_list[field_idx], fileptr - field_len, field_len)) { + break; + } else { + field_idx++; + } + } + + if (!field_list[field_idx]) { + state = ERROR; + ErrPrint("field is not valid\n"); + continue; + } + } + + field_len++; + } + break; + case DATA: + switch (field_idx) { + case FIELD_TYPE: + if (ptr == NULL) { + if (isspace(*fileptr)) { + break; + } + + if (*fileptr == '\0') { + state = ERROR; + ErrPrint("Type is not valid\n"); + continue; + } + + ptr = fileptr; + type_idx = 0; + type_len = 0; + } + + if (*fileptr && (*fileptr == '\n' || *fileptr == '\r' || *fileptr == '\f')) { + *fileptr = '\0'; + } + + if (type_list[type_idx][type_len] != *fileptr) { + type_idx++; + while (type_list[type_idx]) { + if (!strncmp(type_list[type_idx], fileptr - type_len, type_len)) { + break; + } else { + type_idx++; + } + } + + if (!type_list[type_idx]) { + state = ERROR; + ErrPrint("type is not valid (%s)\n", fileptr - type_len); + continue; + } + } + + if (!*fileptr) { + block->type = type_idx; + state = DONE; + ptr = NULL; + } + + type_len++; + break; + case FIELD_PART: + if (ptr == NULL) { + ptr = fileptr; + } + + if (*fileptr && (*fileptr == '\n' || *fileptr == '\r' || *fileptr == '\f')) { + *fileptr = '\0'; + } + + if (!*fileptr) { + block->part = ptr; + state = DONE; + ptr = NULL; + } + break; + case FIELD_DATA: + if (ptr == NULL) { + ptr = fileptr; + } + + if (*fileptr && (*fileptr == '\n' || *fileptr == '\r' || *fileptr == '\f')) { + *fileptr = '\0'; + } + + if (!*fileptr) { + block->data = ptr; + state = DONE; + ptr = NULL; + } + break; + case FIELD_OPTION: + if (ptr == NULL) { + ptr = fileptr; + } + + if (*fileptr && (*fileptr == '\n' || *fileptr == '\r' || *fileptr == '\f')) { + *fileptr = '\0'; + } + + if (!*fileptr) { + block->option = ptr; + state = DONE; + ptr = NULL; + } + break; + case FIELD_ID: + if (ptr == NULL) { + ptr = fileptr; + } + + if (*fileptr && (*fileptr == '\n' || *fileptr == '\r' || *fileptr == '\f')) { + *fileptr = '\0'; + } + + if (!*fileptr) { + block->id = ptr; + state = DONE; + ptr = NULL; + } + break; + case FIELD_TARGET: + if (ptr == NULL) { + ptr = fileptr; + } + + if (*fileptr && (*fileptr == '\n' || *fileptr == '\r' || *fileptr == '\f')) { + *fileptr = '\0'; + } + + if (!*fileptr) { + block->target = ptr; + state = DONE; + ptr = NULL; + } + break; + case FIELD_FILE: + if (ptr == NULL) { + ptr = fileptr; + } + + if (*fileptr && (*fileptr == '\n' || *fileptr == '\r' || *fileptr == '\f')) { + *fileptr = '\0'; + } + + if (!*fileptr) { + block->target = ptr; + state = DONE; + ptr = NULL; + } + default: + break; + } + + break; + case DONE: + if (isspace(*fileptr)) { + } else if (*fileptr == '}') { + state = BEGIN; + block->filename = filename; + block_list = eina_list_append(block_list, block); + block = NULL; + } else { + state = FIELD; + continue; + } + break; + case END: + default: + break; + } + + fileptr++; + } + + if (state != BEGIN) { + ErrPrint("State %d\n", state); + + free(filebuf); + free(block); + + EINA_LIST_FREE(block_list, block) { + free(block); + } + + PERF_MARK("parser"); + return LB_STATUS_ERROR_FAULT; + } + + block = eina_list_data_get(eina_list_last(block_list)); + if (block) { + block->filebuf = filebuf; + } else { + ErrPrint("Last block is not exists (There is no parsed block)\n"); + free(filebuf); + } + + PERF_MARK("parser"); + +#if defined(_APPLY_SCRIPT_ASYNC_UPDATE) + struct apply_data *data; + + data = malloc(sizeof(*data)); + if (data) { + data->inst = inst; + data->is_pd = is_pd; + data->block_list = block_list; + if (!ecore_timer_add(0.001f, apply_changes_cb, data)) { + ErrPrint("Failed to add timer\n"); + free(data); + EINA_LIST_FREE(block_list, block) { + consuming_parsed_block(inst, is_pd, block); + } + } + } else { + ErrPrint("Heap: %s\n", strerror(errno)); + EINA_LIST_FREE(block_list, block) { + consuming_parsed_block(inst, is_pd, block); + } + } +#else + ErrPrint("Begin: Set content for EDJE object\n"); + EINA_LIST_FREE(block_list, block) { + consuming_parsed_block(inst, is_pd, block); + } + ErrPrint("End: Set content for EDJE object\n"); + + /*! + * Doesn't need to force to render the contents. + struct script_info *info; + info = is_pd ? instance_pd_script(inst) : instance_lb_script(inst); + if (info && info->ee) { + ecore_evas_manual_render(info->ee); + } + */ +#endif + + return LB_STATUS_SUCCESS; +} + +/* End of a file */ |