Sync with the latest one
[platform/framework/web/livebox-viewer.git] / src / livebox.c
index 897b0c6..c9d3635 100644 (file)
@@ -20,6 +20,9 @@
 #include <string.h> /* strdup */
 #include <math.h>
 #include <unistd.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
 
 #include <aul.h>
 #include <dlog.h>
@@ -37,7 +40,6 @@
 #include "util.h"
 #include "master_rpc.h"
 #include "client.h"
-#include "critical_log.h"
 #include "conf.h"
 
 #define EAPI __attribute__((visibility("default")))
@@ -128,13 +130,18 @@ static inline void default_access_event_cb(struct livebox *handler, int ret, voi
        DbgPrint("Default access event handler: %d\n", ret);
 }
 
+static inline void default_key_event_cb(struct livebox *handler, int ret, void *data)
+{
+       DbgPrint("Default key event handler: %d\n", ret);
+}
+
 static inline __attribute__((always_inline)) struct cb_info *create_cb_info(ret_cb_t cb, void *data)
 {
        struct cb_info *info;
 
        info = malloc(sizeof(*info));
        if (!info) {
-               CRITICAL_LOG("Heap: %s\n", strerror(errno));
+               ErrPrint("Heap: %s\n", strerror(errno));
                return NULL;
        }
 
@@ -148,6 +155,126 @@ static inline void destroy_cb_info(struct cb_info *info)
        free(info);
 }
 
+static int do_fb_lock(int fd)
+{
+        struct flock flock;
+       int ret;
+
+       flock.l_type = F_RDLCK;
+       flock.l_whence = SEEK_SET;
+       flock.l_start = 0;
+       flock.l_len = 0;
+       flock.l_pid = getpid();
+
+       do {
+               ret = fcntl(fd, F_SETLKW, &flock);
+               if (ret < 0) {
+                       ret = errno;
+                       ErrPrint("fcntl: %s\n", strerror(errno));
+               }
+       } while (ret == EINTR);
+
+       return ret;
+}
+
+static int do_fb_unlock(int fd)
+{
+       struct flock flock;
+       int ret;
+
+       flock.l_type = F_UNLCK;
+       flock.l_whence = SEEK_SET;
+       flock.l_start = 0;
+       flock.l_len = 0;
+       flock.l_pid = getpid();
+
+       do {
+               ret = fcntl(fd, F_SETLKW, &flock);
+               if (ret < 0) {
+                       ret = errno;
+                       ErrPrint("fcntl: %s\n", strerror(errno));
+               }
+       } while (ret == EINTR);
+
+       return ret;
+}
+
+int lb_destroy_lock_file(struct livebox *info, int is_pd)
+{
+       if (is_pd) {
+               if (!info->pd.lock) {
+                       return -EINVAL;
+               }
+
+               if (close(info->pd.lock_fd) < 0) {
+                       ErrPrint("close: %s\n", strerror(errno));
+               }
+               info->pd.lock_fd = -1;
+
+               if (unlink(info->pd.lock) < 0) {
+                       ErrPrint("unlink: %s\n", strerror(errno));
+               }
+
+               free(info->pd.lock);
+               info->pd.lock = NULL;
+       } else {
+               if (!info->lb.lock) {
+                       return -EINVAL;
+               }
+
+               if (close(info->lb.lock_fd) < 0) {
+                       ErrPrint("close: %s\n", strerror(errno));
+               }
+               info->lb.lock_fd = -1;
+
+               if (unlink(info->lb.lock) < 0) {
+                       ErrPrint("unlink: %s\n", strerror(errno));
+               }
+
+               free(info->lb.lock);
+               info->lb.lock = NULL;
+       }
+
+       return 0;
+}
+
+int lb_create_lock_file(struct livebox *info, int is_pd)
+{
+       int len;
+       char *file;
+
+       len = strlen(info->id);
+       file = malloc(len + 20);
+       if (!file) {
+               ErrPrint("Heap: %s\n", strerror(errno));
+               return -ENOMEM;
+       }
+
+       snprintf(file, len + 20, "%s.%s.lck", util_uri_to_path(info->id), is_pd ? "pd" : "lb");
+
+       if (is_pd) {
+               info->pd.lock_fd = open(file, O_RDONLY);
+               if (info->pd.lock_fd < 0) {
+                       ErrPrint("open: %s\n", strerror(errno));
+                       free(file);
+                       return -EIO;
+               }
+
+               info->pd.lock = file;
+       } else {
+               info->lb.lock_fd = open(file, O_RDONLY);
+               if (info->lb.lock_fd < 0) {
+                       ErrPrint("open: %s\n", strerror(errno));
+                       free(file);
+                       return -EIO;
+               }
+
+               info->lb.lock = file;
+       }
+
+       return 0;
+}
+
 static void update_mode_cb(struct livebox *handler, const struct packet *result, void *data)
 {
        int ret;
@@ -564,6 +691,32 @@ errout:
        handler->pinup_cbdata = NULL;
 }
 
+static void key_ret_cb(struct livebox *handler, const struct packet *result, void *data)
+{
+       int ret;
+
+       if (!result) {
+               ret = LB_STATUS_ERROR_FAULT;
+               return;
+       }
+
+       if (packet_get(result, "i", &ret) != 1) {
+               ret = LB_STATUS_ERROR_INVALID;
+               return;
+       }
+
+       if (ret != LB_STATUS_SUCCESS) {
+               goto errout;
+       }
+
+       return;
+errout:
+       handler->key_event_cb(handler, ret, handler->key_event_cbdata);
+       handler->key_event_cb = NULL;
+       handler->key_event_cbdata = NULL;
+       return;
+}
+
 static void access_ret_cb(struct livebox *handler, const struct packet *result, void *data)
 {
        int ret;
@@ -607,6 +760,21 @@ static int send_access_event(struct livebox *handler, const char *event, int x,
        return master_rpc_async_request(handler, packet, 0, access_ret_cb, NULL);
 }
 
+static int send_key_event(struct livebox *handler, const char *event, unsigned int keycode)
+{
+       struct packet *packet;
+       double timestamp;
+
+       timestamp = util_timestamp();
+       packet = packet_create(event, "ssdi", handler->pkgname, handler->id, timestamp, keycode);
+       if (!packet) {
+               ErrPrint("Failed to build packet\n");
+               return LB_STATUS_ERROR_FAULT;
+       }
+
+       return master_rpc_async_request(handler, packet, 0, key_ret_cb, NULL);
+}
+
 static int send_mouse_event(struct livebox *handler, const char *event, int x, int y)
 {
        struct packet *packet;
@@ -622,7 +790,7 @@ static int send_mouse_event(struct livebox *handler, const char *event, int x, i
        return master_rpc_request_only(handler, packet);
 }
 
-static void initialize_livebox(void *disp)
+static void initialize_livebox(void *disp, int use_thread)
 {
 #if defined(FLOG)
        char filename[BUFSIZ];
@@ -632,16 +800,15 @@ static void initialize_livebox(void *disp)
                __file_log_fp = fdopen(1, "w+t");
        }
 #endif
-       critical_log_init("viewer");
        livebox_service_init();
        fb_init(disp);
 
-       client_init();
+       client_init(use_thread);
 
        s_info.init_count++;
 }
 
-EAPI int livebox_init_with_options(void *disp, int prevent_overwrite, double event_filter)
+EAPI int livebox_init_with_options(void *disp, int prevent_overwrite, double event_filter, int use_thread)
 {
        if (s_info.init_count > 0) {
                s_info.init_count++;
@@ -656,7 +823,7 @@ EAPI int livebox_init_with_options(void *disp, int prevent_overwrite, double eve
        s_info.prevent_overwrite = prevent_overwrite;
        MINIMUM_EVENT = event_filter;
 
-       initialize_livebox(disp);
+       initialize_livebox(disp, use_thread);
        return LB_STATUS_SUCCESS;
 }
 
@@ -679,7 +846,7 @@ EAPI int livebox_init(void *disp)
                sscanf(env, "%lf", &MINIMUM_EVENT);
        }
 
-       initialize_livebox(disp);
+       initialize_livebox(disp, 0);
        return LB_STATUS_SUCCESS;
 }
 
@@ -699,7 +866,6 @@ EAPI int livebox_fini(void)
        client_fini();
        fb_fini();
        livebox_service_fini();
-       critical_log_fini();
        return LB_STATUS_SUCCESS;
 }
 
@@ -741,7 +907,7 @@ EAPI struct livebox *livebox_add_with_size(const char *pkgname, const char *cont
        }
 
        if (type != LB_SIZE_TYPE_UNKNOWN) {
-               livebox_service_get_size(type, &width, &height);
+               (void)livebox_service_get_size(type, &width, &height);
        }
 
        handler = calloc(1, sizeof(*handler));
@@ -812,6 +978,11 @@ EAPI struct livebox *livebox_add_with_size(const char *pkgname, const char *cont
        handler->timestamp = util_timestamp();
        handler->is_user = 1;
        handler->visible = LB_SHOW;
+       handler->delete_type = LB_DELETE_PERMANENTLY;
+       handler->pd.lock = NULL;
+       handler->pd.lock_fd = -1;
+       handler->lb.lock = NULL;
+       handler->lb.lock_fd = -1;
 
        s_info.livebox_list = dlist_append(s_info.livebox_list, handler);
 
@@ -908,6 +1079,44 @@ EAPI int livebox_set_period(struct livebox *handler, double period, ret_cb_t cb,
        return ret;
 }
 
+EAPI int livebox_del_NEW(struct livebox *handler, int type, ret_cb_t cb, void *data)
+{
+       if (!handler) {
+               ErrPrint("Handler is NIL\n");
+               return LB_STATUS_ERROR_INVALID;
+       }
+
+       if (handler->state != CREATE) {
+               ErrPrint("Handler is already deleted\n");
+               return LB_STATUS_ERROR_INVALID;
+       }
+
+       handler->state = DELETE;
+       handler->delete_type = type;
+
+       if (!handler->id) {
+               /*!
+                * \note
+                * The id is not determined yet.
+                * It means a user didn't receive created event yet.
+                * Then just stop to delete procedure from here.
+                * Because the "created" event handler will release this.
+                * By the way, if the user adds any callback for getting return status of this,
+                * call it at here.
+                */
+               if (cb) {
+                       cb(handler, 0, data);
+               }
+               return LB_STATUS_SUCCESS;
+       }
+
+       if (!cb) {
+               cb = default_delete_cb;
+       }
+
+       return lb_send_delete(handler, type, cb, data);
+}
+
 EAPI int livebox_del(struct livebox *handler, ret_cb_t cb, void *data)
 {
        if (!handler) {
@@ -921,6 +1130,7 @@ EAPI int livebox_del(struct livebox *handler, ret_cb_t cb, void *data)
        }
 
        handler->state = DELETE;
+       handler->delete_type = LB_DELETE_PERMANENTLY;
 
        if (!handler->id) {
                /*!
@@ -942,7 +1152,7 @@ EAPI int livebox_del(struct livebox *handler, ret_cb_t cb, void *data)
                cb = default_delete_cb;
        }
 
-       return lb_send_delete(handler, cb, data);
+       return lb_send_delete(handler, LB_DELETE_PERMANENTLY, cb, data);
 }
 
 EAPI int livebox_set_fault_handler(int (*cb)(enum livebox_fault_type, const char *, const char *, const char *, void *), void *data)
@@ -955,7 +1165,7 @@ EAPI int livebox_set_fault_handler(int (*cb)(enum livebox_fault_type, const char
 
        info = malloc(sizeof(*info));
        if (!info) {
-               CRITICAL_LOG("Heap: %s\n", strerror(errno));
+               ErrPrint("Heap: %s\n", strerror(errno));
                return LB_STATUS_ERROR_MEMORY;
        }
 
@@ -997,7 +1207,7 @@ EAPI int livebox_set_event_handler(int (*cb)(struct livebox *, enum livebox_even
 
        info = malloc(sizeof(*info));
        if (!info) {
-               CRITICAL_LOG("Heap: %s\n", strerror(errno));
+               ErrPrint("Heap: %s\n", strerror(errno));
                return LB_STATUS_ERROR_MEMORY;
        }
 
@@ -1220,7 +1430,7 @@ EAPI int livebox_pd_is_created(struct livebox *handler)
                return LB_STATUS_ERROR_INVALID;
        }
 
-       if (!handler->pd.data.fb || handler->state != CREATE || !handler->id) {
+       if (handler->state != CREATE || !handler->pd.data.fb || !handler->id) {
                ErrPrint("Handler is not valid\n");
                return LB_STATUS_ERROR_INVALID;
        }
@@ -1243,7 +1453,7 @@ EAPI int livebox_create_pd_with_position(struct livebox *handler, double x, doub
                return LB_STATUS_ERROR_INVALID;
        }
 
-       if (!handler->pd.data.fb || handler->state != CREATE || !handler->id) {
+       if (handler->state != CREATE || !handler->pd.data.fb || !handler->id) {
                ErrPrint("Handler is not valid\n");
                return LB_STATUS_ERROR_INVALID;
        }
@@ -1287,7 +1497,7 @@ EAPI int livebox_move_pd(struct livebox *handler, double x, double y)
                return LB_STATUS_ERROR_INVALID;
        }
 
-       if (!handler->pd.data.fb || handler->state != CREATE || !handler->id) {
+       if (handler->state != CREATE || !handler->pd.data.fb || !handler->id) {
                ErrPrint("Handler is not valid\n");
                return LB_STATUS_ERROR_INVALID;
        }
@@ -1348,7 +1558,7 @@ EAPI int livebox_destroy_pd(struct livebox *handler, ret_cb_t cb, void *data)
                return LB_STATUS_ERROR_INVALID;
        }
 
-       if (!handler->pd.data.fb || handler->state != CREATE || !handler->id) {
+       if (handler->state != CREATE || !handler->pd.data.fb || !handler->id) {
                ErrPrint("Handler is not valid\n");
                return LB_STATUS_ERROR_INVALID;
        }
@@ -1474,6 +1684,11 @@ EAPI int livebox_access_event(struct livebox *handler, enum access_event_type ty
 
 EAPI int livebox_content_event(struct livebox *handler, enum content_event_type type, double x, double y)
 {
+       return livebox_mouse_event(handler, type, x, y);
+}
+
+EAPI int livebox_mouse_event(struct livebox *handler, enum content_event_type type, double x, double y)
+{
        int w = 1;
        int h = 1;
        char cmd[32] = { '\0', };
@@ -1489,6 +1704,11 @@ EAPI int livebox_content_event(struct livebox *handler, enum content_event_type
                return LB_STATUS_ERROR_INVALID;
        }
 
+       if (!(type & CONTENT_EVENT_MOUSE_MASK)) {
+               ErrPrint("Invalid content event is used\n");
+               return LB_STATUS_ERROR_INVALID;
+       }
+
        if (type & CONTENT_EVENT_PD_MASK) {
                int flag = 1;
 
@@ -1497,19 +1717,17 @@ EAPI int livebox_content_event(struct livebox *handler, enum content_event_type
                        return LB_STATUS_ERROR_INVALID;
                }
 
-               if (type & CONTENT_EVENT_MOUSE_MASK) {
-                       if (!handler->pd.data.fb) {
-                               ErrPrint("Handler is not valid\n");
-                               return LB_STATUS_ERROR_INVALID;
-                       }
+               if (!handler->pd.data.fb) {
+                       ErrPrint("Handler is not valid\n");
+                       return LB_STATUS_ERROR_INVALID;
+               }
 
-                       if (type & CONTENT_EVENT_MOUSE_MOVE) {
-                               if (fabs(x - handler->pd.x) < MINIMUM_EVENT && fabs(y - handler->pd.y) < MINIMUM_EVENT) {
-                                       return LB_STATUS_ERROR_BUSY;
-                               }
-                       } else if (type & CONTENT_EVENT_MOUSE_SET) {
-                               flag = 0;
+               if (type & CONTENT_EVENT_MOUSE_MOVE) {
+                       if (fabs(x - handler->pd.x) < MINIMUM_EVENT && fabs(y - handler->pd.y) < MINIMUM_EVENT) {
+                               return LB_STATUS_ERROR_BUSY;
                        }
+               } else if (type & CONTENT_EVENT_MOUSE_SET) {
+                       flag = 0;
                }
 
                if (flag) {
@@ -1523,23 +1741,21 @@ EAPI int livebox_content_event(struct livebox *handler, enum content_event_type
        } else if (type & CONTENT_EVENT_LB_MASK) {
                int flag = 1;
 
-               if (type & CONTENT_EVENT_MOUSE_MASK) {
-                       if (!handler->lb.mouse_event) {
-                               return LB_STATUS_ERROR_INVALID;
-                       }
+               if (!handler->lb.mouse_event) {
+                       return LB_STATUS_ERROR_INVALID;
+               }
 
-                       if (!handler->lb.data.fb) {
-                               ErrPrint("Handler is not valid\n");
-                               return LB_STATUS_ERROR_INVALID;
-                       }
+               if (!handler->lb.data.fb) {
+                       ErrPrint("Handler is not valid\n");
+                       return LB_STATUS_ERROR_INVALID;
+               }
 
-                       if (type & CONTENT_EVENT_MOUSE_MOVE) {
-                               if (fabs(x - handler->lb.x) < MINIMUM_EVENT && fabs(y - handler->lb.y) < MINIMUM_EVENT) {
-                                       return LB_STATUS_ERROR_BUSY;
-                               }
-                       } else if (type & CONTENT_EVENT_MOUSE_SET) {
-                               flag = 0;
+               if (type & CONTENT_EVENT_MOUSE_MOVE) {
+                       if (fabs(x - handler->lb.x) < MINIMUM_EVENT && fabs(y - handler->lb.y) < MINIMUM_EVENT) {
+                               return LB_STATUS_ERROR_BUSY;
                        }
+               } else if (type & CONTENT_EVENT_MOUSE_SET) {
+                       flag = 0;
                }
 
                if (flag) {
@@ -1580,18 +1796,126 @@ EAPI int livebox_content_event(struct livebox *handler, enum content_event_type
        case CONTENT_EVENT_MOUSE_UNSET | CONTENT_EVENT_MOUSE_MASK:
                strcpy(ptr, "_mouse_unset");
                break;
-       case CONTENT_EVENT_KEY_DOWN | CONTENT_EVENT_KEY_MASK:
-               strcpy(ptr, "_key_down");
+       default:
+               ErrPrint("Invalid event type\n");
+               return LB_STATUS_ERROR_INVALID;
+       }
+
+       return send_mouse_event(handler, cmd, x * w, y * h);
+}
+
+EAPI int livebox_key_event(struct livebox *handler, enum content_event_type type, unsigned int keycode, ret_cb_t cb, void *data)
+{
+       char cmd[32] = { '\0', };
+       char *ptr = cmd;
+       int ret;
+
+       if (!handler) {
+               ErrPrint("Handler is NIL\n");
+               return LB_STATUS_ERROR_INVALID;
+       }
+
+       if (handler->state != CREATE || !handler->id) {
+               ErrPrint("Handler is not valid\n");
+               return LB_STATUS_ERROR_INVALID;
+       }
+
+       if (!(type & CONTENT_EVENT_KEY_MASK)) {
+               ErrPrint("Invalid key event is used\n");
+               return LB_STATUS_ERROR_INVALID;
+       }
+
+       if (type & CONTENT_EVENT_PD_MASK) {
+               if (!handler->is_pd_created) {
+                       ErrPrint("PD is not created\n");
+                       return LB_STATUS_ERROR_INVALID;
+               }
+
+               if (!handler->pd.data.fb) {
+                       ErrPrint("Handler is not valid\n");
+                       return LB_STATUS_ERROR_INVALID;
+               }
+
+               if (type & CONTENT_EVENT_KEY_DOWN) {
+                       /*!
+                        * \TODO
+                        * filtering the reproduced events if it is too fast
+                        */
+               } else if (type & CONTENT_EVENT_KEY_SET) {
+                       /*!
+                        * \TODO
+                        * What can I do for this case?
+                        */
+               }
+
+               *ptr++ = 'p';
+               *ptr++ = 'd';
+       } else if (type & CONTENT_EVENT_LB_MASK) {
+               if (!handler->lb.mouse_event) {
+                       return LB_STATUS_ERROR_INVALID;
+               }
+
+               if (!handler->lb.data.fb) {
+                       ErrPrint("Handler is not valid\n");
+                       return LB_STATUS_ERROR_INVALID;
+               }
+
+               if (type & CONTENT_EVENT_KEY_DOWN) {
+                       /*!
+                        * \TODO
+                        * filtering the reproduced events if it is too fast
+                        */
+               } else if (type & CONTENT_EVENT_KEY_SET) {
+                       /*!
+                        * What can I do for this case?
+                        */
+               }
+
+               *ptr++ = 'l';
+               *ptr++ = 'b';
+       } else {
+               ErrPrint("Invalid event type\n");
+               return LB_STATUS_ERROR_INVALID;
+       }
+
+       /*!
+        * Must be short than 29 bytes.
+        */
+       switch ((type & ~(CONTENT_EVENT_PD_MASK | CONTENT_EVENT_LB_MASK))) {
+       case CONTENT_EVENT_KEY_FOCUS_IN | CONTENT_EVENT_KEY_MASK:
+               strcpy(ptr, "_key_focus_in");
+               break;
+       case CONTENT_EVENT_KEY_FOCUS_OUT | CONTENT_EVENT_KEY_MASK:
+               strcpy(ptr, "_key_focus_out");
                break;
        case CONTENT_EVENT_KEY_UP | CONTENT_EVENT_KEY_MASK:
                strcpy(ptr, "_key_up");
                break;
+       case CONTENT_EVENT_KEY_DOWN | CONTENT_EVENT_KEY_MASK:
+               strcpy(ptr, "_key_down");
+               break;
+       case CONTENT_EVENT_KEY_SET | CONTENT_EVENT_KEY_MASK:
+               strcpy(ptr, "_key_set");
+               break;
+       case CONTENT_EVENT_KEY_UNSET | CONTENT_EVENT_KEY_MASK:
+               strcpy(ptr, "_key_unset");
+               break;
        default:
                ErrPrint("Invalid event type\n");
                return LB_STATUS_ERROR_INVALID;
        }
 
-       return send_mouse_event(handler, cmd, x * w, y * h);
+       if (!cb) {
+               cb = default_key_event_cb;
+       }
+
+       ret = send_key_event(handler, cmd, keycode);
+       if (ret == LB_STATUS_SUCCESS) {
+               handler->key_event_cb = cb;
+               handler->key_event_cbdata = data;
+       }
+
+       return ret;
 }
 
 EAPI const char *livebox_filename(struct livebox *handler)
@@ -1729,7 +2053,7 @@ EAPI int livebox_set_group(struct livebox *handler, const char *cluster, const c
        return ret;
 }
 
-EAPI int livebox_get_group(struct livebox *handler, char ** const cluster, char ** const category)
+EAPI int livebox_get_group(struct livebox *handler, const char **cluster, const char **category)
 {
        if (!handler) {
                ErrPrint("Handler is NIL\n");
@@ -2421,7 +2745,7 @@ EAPI int livebox_emit_text_signal(struct livebox *handler, const char *emission,
                return LB_STATUS_ERROR_INVALID;
        }
 
-       if ((handler->lb.type != _LB_TYPE_TEXT && handler->pd.type != _PD_TYPE_TEXT) || handler->state != CREATE || !handler->id) {
+       if (handler->state != CREATE || (handler->lb.type != _LB_TYPE_TEXT && handler->pd.type != _PD_TYPE_TEXT) || !handler->id) {
                ErrPrint("Handler is not valid\n");
                return LB_STATUS_ERROR_INVALID;
        }
@@ -2596,7 +2920,7 @@ int lb_set_group(struct livebox *handler, const char *cluster, const char *categ
        if (cluster) {
                pc = strdup(cluster);
                if (!pc) {
-                       CRITICAL_LOG("Heap: %s (cluster: %s)\n", strerror(errno), cluster);
+                       ErrPrint("Heap: %s (cluster: %s)\n", strerror(errno), cluster);
                        return LB_STATUS_ERROR_MEMORY;
                }
        }
@@ -2604,7 +2928,7 @@ int lb_set_group(struct livebox *handler, const char *cluster, const char *categ
        if (category) {
                ps = strdup(category);
                if (!ps) {
-                       CRITICAL_LOG("Heap: %s (category: %s)\n", strerror(errno), category);
+                       ErrPrint("Heap: %s (category: %s)\n", strerror(errno), category);
                        free(pc);
                        return LB_STATUS_ERROR_MEMORY;
                }
@@ -2735,6 +3059,11 @@ struct livebox *lb_new_livebox(const char *pkgname, const char *id, double times
        handler->pd.type = _PD_TYPE_SCRIPT;
        handler->state = CREATE;
        handler->visible = LB_SHOW;
+       handler->delete_type = LB_DELETE_PERMANENTLY;
+       handler->pd.lock = NULL;
+       handler->pd.lock_fd = -1;
+       handler->lb.lock = NULL;
+       handler->lb.lock_fd = -1;
 
        s_info.livebox_list = dlist_append(s_info.livebox_list, handler);
        lb_ref(handler);
@@ -2765,7 +3094,7 @@ int lb_set_content(struct livebox *handler, const char *content)
        if (content) {
                handler->content = strdup(content);
                if (!handler->content) {
-                       CRITICAL_LOG("Heap: %s (content: %s)\n", strerror(errno), content);
+                       ErrPrint("Heap: %s (content: %s)\n", strerror(errno), content);
                        return LB_STATUS_ERROR_MEMORY;
                }
        }
@@ -2783,7 +3112,7 @@ int lb_set_title(struct livebox *handler, const char *title)
        if (title) {
                handler->title = strdup(title);
                if (!handler->title) {
-                       CRITICAL_LOG("Heap: %s (title: %s)\n", strerror(errno), title);
+                       ErrPrint("Heap: %s (title: %s)\n", strerror(errno), title);
                        return LB_STATUS_ERROR_MEMORY;
                }
        }
@@ -2828,8 +3157,10 @@ void lb_set_id(struct livebox *handler, const char *id)
 void lb_set_filename(struct livebox *handler, const char *filename)
 {
        if (handler->filename) {
-               if (handler->filename[0] && unlink(handler->filename) < 0) {
-                       ErrPrint("unlink: %s (%s)\n", strerror(errno), handler->filename);
+               if (handler->lb.type == _LB_TYPE_FILE || handler->lb.type == _LB_TYPE_TEXT) {
+                       if (handler->filename[0] && unlink(handler->filename) < 0) {
+                               ErrPrint("unlink: %s (%s)\n", strerror(errno), handler->filename);
+                       }
                }
 
                free(handler->filename);
@@ -2837,11 +3168,42 @@ void lb_set_filename(struct livebox *handler, const char *filename)
 
        handler->filename = strdup(filename);
        if (!handler->filename) {
-               ErrPrint("Heap: %s (%s)\n", strerror(errno), handler->filename);
-               return;
+               ErrPrint("Heap: %s\n", strerror(errno));
        }
 }
 
+void lb_set_alt_info(struct livebox *handler, const char *icon, const char *name)
+{
+       char *_icon = NULL;
+       char *_name = NULL;
+
+       if (icon && strlen(icon)) {
+               _icon = strdup(icon);
+               if (!_icon) {
+                       ErrPrint("Heap: %s\n", strerror(errno));
+               }
+       }
+
+       if (name && strlen(name)) {
+               _name = strdup(name);
+               if (!_name) {
+                       ErrPrint("Heap: %s\n", strerror(errno));
+               }
+       }
+
+       if (handler->icon) {
+               free(handler->icon);
+       }
+
+       handler->icon = _icon;
+
+       if (handler->name) {
+               free(handler->name);
+       }
+
+       handler->name = _name;
+}
+
 int lb_set_lb_fb(struct livebox *handler, const char *filename)
 {
        struct fb_info *fb;
@@ -3043,6 +3405,12 @@ struct livebox *lb_unref(struct livebox *handler)
                handler->access_event_cbdata = NULL;
        }
 
+       if (handler->key_event_cb) {
+               handler->key_event_cb(handler, LB_KEY_STATUS_ERROR, handler->key_event_cbdata);
+               handler->key_event_cb = NULL;
+               handler->key_event_cbdata = NULL;
+       }
+
        if (handler->filename) {
                (void)util_unlink(handler->filename);
        }
@@ -3056,6 +3424,8 @@ struct livebox *lb_unref(struct livebox *handler)
        free(handler->pkgname);
        free(handler->filename);
        free(handler->lb.auto_launch);
+       free(handler->icon);
+       free(handler->name);
 
        if (handler->lb.data.fb) {
                fb_destroy(handler->lb.data.fb);
@@ -3071,7 +3441,7 @@ struct livebox *lb_unref(struct livebox *handler)
        return NULL;
 }
 
-int lb_send_delete(struct livebox *handler, ret_cb_t cb, void *data)
+int lb_send_delete(struct livebox *handler, int type, ret_cb_t cb, void *data)
 {
        struct packet *packet;
        struct cb_info *cbinfo;
@@ -3087,7 +3457,7 @@ int lb_send_delete(struct livebox *handler, ret_cb_t cb, void *data)
                return LB_STATUS_ERROR_BUSY;
        }
 
-       packet = packet_create("delete", "ss", handler->pkgname, handler->id);
+       packet = packet_create("delete", "ssi", handler->pkgname, handler->id, type);
        if (!packet) {
                ErrPrint("Failed to build a param\n");
                if (cb) {
@@ -3163,12 +3533,119 @@ EAPI int livebox_frame_drop_for_resizing(void)
 
 EAPI int livebox_sync_lb_fb(struct livebox *handler)
 {
-       return fb_sync(lb_get_lb_fb(handler));
+       int ret;
+
+       if (fb_type(lb_get_lb_fb(handler)) == BUFFER_TYPE_FILE && handler->lb.lock_fd >= 0) {
+               (void)do_fb_lock(handler->lb.lock_fd);
+               ret = fb_sync(lb_get_lb_fb(handler));
+               (void)do_fb_unlock(handler->lb.lock_fd);
+       } else {
+               ret = fb_sync(lb_get_lb_fb(handler));
+       }
+
+       return ret;
 }
 
 EAPI int livebox_sync_pd_fb(struct livebox *handler)
 {
-       return fb_sync(lb_get_pd_fb(handler));
+       int ret;
+
+       if (fb_type(lb_get_pd_fb(handler)) == BUFFER_TYPE_FILE && handler->pd.lock_fd >= 0) {
+               (void)do_fb_lock(handler->pd.lock_fd);
+               ret = fb_sync(lb_get_pd_fb(handler));
+               (void)do_fb_unlock(handler->pd.lock_fd);
+       } else {
+               ret = fb_sync(lb_get_pd_fb(handler));
+       }
+
+       return ret;
+}
+
+EAPI const char *livebox_alt_icon(struct livebox *handler)
+{
+       if (!handler || handler->state != CREATE) {
+               ErrPrint("Handler is not valid[%p]\n", handler);
+               return NULL;
+       }
+       return handler->icon;
+}
+
+EAPI const char *livebox_alt_name(struct livebox *handler)
+{
+       if (!handler || handler->state != CREATE) {
+               ErrPrint("Handler is not valid[%p]\n", handler);
+               return NULL;
+       }
+
+       return handler->name;
+}
+
+EAPI int livebox_acquire_fb_lock(struct livebox *handler, int is_pd)
+{
+       int ret = LB_STATUS_SUCCESS;
+       int fd;
+
+       if (is_pd) {
+               if (!handler->pd.lock || handler->pd.lock_fd < 0) {
+                       DbgPrint("Lock: %s (%d)\n", handler->pd.lock, handler->pd.lock_fd);
+                       return LB_STATUS_ERROR_INVALID;
+               }
+
+               if (fb_type(lb_get_pd_fb(handler)) == BUFFER_TYPE_FILE) {
+                       return LB_STATUS_SUCCESS;
+               }
+
+               fd = handler->pd.lock_fd;
+       } else {
+               if (!handler->lb.lock || handler->lb.lock_fd < 0) {
+                       DbgPrint("Lock: %s (%d)\n", handler->lb.lock, handler->lb.lock_fd);
+                       return LB_STATUS_ERROR_INVALID;
+               }
+
+               if (fb_type(lb_get_lb_fb(handler)) == BUFFER_TYPE_FILE) {
+                       return LB_STATUS_SUCCESS;
+               }
+
+               fd = handler->lb.lock_fd;
+       }
+
+       ret = do_fb_lock(fd);
+
+       return ret == 0 ? LB_STATUS_SUCCESS : LB_STATUS_ERROR_FAULT;
+}
+
+EAPI int livebox_release_fb_lock(struct livebox *handler, int is_pd)
+{
+       int ret = LB_STATUS_SUCCESS;
+       int fd;
+
+       if (is_pd) {
+               if (!handler->pd.lock || handler->pd.lock_fd < 0) {
+                       DbgPrint("Unlock: %s (%d)\n", handler->pd.lock, handler->pd.lock_fd);
+                       return LB_STATUS_ERROR_INVALID;
+               }
+
+               if (fb_type(lb_get_pd_fb(handler)) == BUFFER_TYPE_FILE) {
+                       return LB_STATUS_SUCCESS;
+               }
+
+               fd = handler->pd.lock_fd;
+       } else {
+               if (!handler->lb.lock || handler->lb.lock_fd < 0) {
+                       DbgPrint("Unlock: %s (%d)\n", handler->lb.lock, handler->lb.lock_fd);
+                       return LB_STATUS_ERROR_INVALID;
+               }
+
+               if (fb_type(lb_get_lb_fb(handler)) == BUFFER_TYPE_FILE) {
+                       return LB_STATUS_SUCCESS;
+               }
+
+               fd = handler->lb.lock_fd;
+       }
+
+       ret = do_fb_unlock(fd);
+
+       return ret == 0 ? LB_STATUS_SUCCESS : LB_STATUS_ERROR_FAULT;
 }
 
 /* End of a file */