Merge branch 'tizen_2.2' of ssh://review.tizendev.org:29418/apps/livebox/data-provide...
[platform/framework/web/data-provider-slave.git] / src / lb.c
index 4d74b41..1d82a88 100644 (file)
--- a/src/lb.c
+++ b/src/lb.c
@@ -1,11 +1,11 @@
 /*
  * Copyright 2013  Samsung Electronics Co., Ltd
  *
- * Licensed under the Flora License, Version 1.0 (the "License");
+ * 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
+ * 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,
@@ -17,6 +17,7 @@
 #include <stdio.h>
 #include <stdlib.h> /* exit */
 #include <errno.h>
+#include <unistd.h> /* access */
 
 #include <Ecore.h>
 #include <Eina.h>
 #include "fault.h"
 #include "util.h"
 
+#define IS_LB_SHOWN(itm) (!(itm)->inst->item->has_livebox_script || ((itm)->inst->item->has_livebox_script && (itm)->is_lb_show))
+
 int errno;
 
+#define UPDATE_ITEM_DELETED    (-1)
+#define UPDATE_INVOKED         (-2)
+#define UPDATE_NOT_INVOKED     (0)
+
 struct item {
        Ecore_Timer *timer;
        struct instance *inst;
@@ -47,11 +54,17 @@ struct item {
        int heavy_updating; /* Only for debugging message */
        int is_paused; /* 1 is paused, 0 is resumed */
        double sleep_at;
+
+       unsigned int updated_in_pause;
+
+       int is_lb_show;
+       int is_pd_show;
+       int is_lb_updated;
 };
 
 static struct info {
        Eina_List *item_list;
-       struct item *update;
+       Eina_List *update_list;
        Eina_List *pending_list;
        Ecore_Timer *pending_timer;
        Eina_List *pd_open_pending_list;
@@ -62,7 +75,7 @@ static struct info {
        int pending_timer_freezed;
 } s_info  = {
        .item_list = NULL,
-       .update = NULL,
+       .update_list = NULL,
        .pending_list = NULL,
        .pending_timer = NULL,
        .pd_open_pending_list = NULL,
@@ -89,8 +102,9 @@ static void pending_timer_freeze(void)
 static void pending_timer_thaw(void)
 {
        DbgPrint("Freezed Count: %d\n", s_info.pending_timer_freezed);
-       if (!s_info.pending_timer_freezed)
+       if (!s_info.pending_timer_freezed) {
                return;
+       }
 
        s_info.pending_timer_freezed--;
        if (s_info.pending_timer && !s_info.pending_timer_freezed) {
@@ -113,7 +127,6 @@ static inline int pd_is_opened(const char *pkgname)
        i = 0;
        EINA_LIST_FOREACH(s_info.pd_list, l, tmp) {
                if (pkgname && !strcmp(pkgname, tmp)) {
-                       DbgPrint("PD(%s) is opened\n", pkgname);
                        return 1;
                }
 
@@ -128,25 +141,29 @@ static Eina_Bool pd_open_pended_cmd_consumer_cb(void *data)
        struct item *item;
 
        item = eina_list_nth(s_info.pd_open_pending_list, 0);
-       if (!item)
+       if (!item) {
                goto cleanout;
+       }
 
-       if (s_info.update)
+       if (eina_list_data_find(s_info.update_list, item)) {
                return ECORE_CALLBACK_RENEW;
+       }
 
        s_info.pd_open_pending_list = eina_list_remove(s_info.pd_open_pending_list, item);
-       DbgPrint("Consuming pended item: %s\n", item->inst->id);
        /*!
         * \note
         * To prevent from checking the is_updated function
         */
-       (void)updator_cb(item);
-       if (s_info.pd_open_pending_list)
+       if (updator_cb(item) == ECORE_CALLBACK_CANCEL) {
+               /* Item is destroyed */
+       }
+
+       if (s_info.pd_open_pending_list) {
                return ECORE_CALLBACK_RENEW;
+       }
 
 cleanout:
        s_info.pd_open_pending_timer = NULL;
-       DbgPrint("open pd pending list exhausted\n");
        return ECORE_CALLBACK_CANCEL;
 }
 
@@ -155,33 +172,38 @@ static Eina_Bool pended_cmd_consumer_cb(void *data)
        struct item *item;
 
        item = eina_list_nth(s_info.pending_list, 0);
-       if (!item)
+       if (!item) {
                goto cleanout;
+       }
 
-       if (s_info.update || pd_is_opened(item->inst->item->pkgname) < 0)
+       if (eina_list_data_find(s_info.update_list, item) || pd_is_opened(item->inst->item->pkgname) < 0) {
                return ECORE_CALLBACK_RENEW;
+       }
 
        s_info.pending_list = eina_list_remove(s_info.pending_list, item);
-       DbgPrint("Consuming pended item: %s\n", item->inst->id);
        /*!
         * \note
         * To prevent from checking the is_updated function
         */
-       (void)updator_cb(item);
-       if (s_info.pending_list)
+       if (updator_cb(item) == ECORE_CALLBACK_CANCEL) {
+               /* item is destroyed */
+       }
+
+       if (s_info.pending_list) {
                return ECORE_CALLBACK_RENEW;
+       }
 
 cleanout:
        s_info.pending_timer = NULL;
        s_info.pending_timer_freezed = 0;
-       DbgPrint("pending list exhausted\n");
        return ECORE_CALLBACK_CANCEL;
 }
 
 static inline __attribute__((always_inline)) int activate_pending_consumer(void)
 {
-       if (s_info.pending_timer)
+       if (s_info.pending_timer) {
                return 0;
+       }
 
        s_info.pending_timer = ecore_timer_add(0.000001f, pended_cmd_consumer_cb, NULL);
        if (!s_info.pending_timer) {
@@ -194,7 +216,6 @@ static inline __attribute__((always_inline)) int activate_pending_consumer(void)
         * Just freeze the timer.
         */
        if (s_info.pending_timer_freezed) {
-               DbgPrint("Pending timer created and freezed\n");
                ecore_timer_freeze(s_info.pending_timer);
        }
 
@@ -203,29 +224,30 @@ static inline __attribute__((always_inline)) int activate_pending_consumer(void)
 
 static inline void deactivate_pending_consumer(void)
 {
-       if (!s_info.pending_timer)
+       if (!s_info.pending_timer) {
                return;
+       }
 
        ecore_timer_del(s_info.pending_timer);
        s_info.pending_timer = NULL;
        s_info.pending_timer_freezed = 0;
-       DbgPrint("Clear the pending timer\n");
 }
 
 static inline void deactivate_pd_open_pending_consumer(void)
 {
-       if (!s_info.pd_open_pending_timer)
+       if (!s_info.pd_open_pending_timer) {
                return;
+       }
 
        ecore_timer_del(s_info.pd_open_pending_timer);
        s_info.pd_open_pending_timer = NULL;
-       DbgPrint("Clear the open_pd_pending timer\n");
 }
 
 static inline int __attribute__((always_inline)) activate_pd_open_pending_consumer(void)
 {
-       if (s_info.pd_open_pending_timer)
+       if (s_info.pd_open_pending_timer) {
                return 0;
+       }
 
        s_info.pd_open_pending_timer = ecore_timer_add(0.000001f, pd_open_pended_cmd_consumer_cb, NULL);
        if (!s_info.pd_open_pending_timer) {
@@ -244,8 +266,9 @@ static inline void migrate_to_pd_open_pending_list(const char *pkgname)
        int cnt = 0;
 
        EINA_LIST_FOREACH_SAFE(s_info.pending_list, l, n, item) {
-               if (strcmp(pkgname, item->inst->item->pkgname))
+               if (strcmp(pkgname, item->inst->item->pkgname)) {
                        continue;
+               }
 
                s_info.pending_list = eina_list_remove(s_info.pending_list, item);
                s_info.pd_open_pending_list = eina_list_append(s_info.pd_open_pending_list, item);
@@ -253,14 +276,12 @@ static inline void migrate_to_pd_open_pending_list(const char *pkgname)
        }
 
        if (s_info.pd_open_pending_list) {
-               DbgPrint("Activate PD open pending consumer (%s)\n", pkgname);
                activate_pd_open_pending_consumer();
        }
 
-       if (!s_info.pending_list)
+       if (!s_info.pending_list) {
                deactivate_pending_consumer();
-
-       DbgPrint("%d items are migrated\n", cnt);
+       }
 }
 
 static inline void migrate_to_pending_list(const char *pkgname)
@@ -271,24 +292,37 @@ static inline void migrate_to_pending_list(const char *pkgname)
        int cnt = 0;
 
        EINA_LIST_FOREACH_SAFE(s_info.pd_open_pending_list, l, n, item) {
-               if (strcmp(pkgname, item->inst->item->pkgname))
+               if (strcmp(pkgname, item->inst->item->pkgname)) {
                        continue;
+               }
 
                s_info.pd_open_pending_list = eina_list_remove(s_info.pd_open_pending_list, item);
                s_info.pending_list = eina_list_append(s_info.pending_list, item);
                cnt++;
        }
 
-       if (s_info.pending_list)
+       if (s_info.pending_list) {
                activate_pending_consumer();
+       }
 
-       if (!s_info.pd_open_pending_list)
+       if (!s_info.pd_open_pending_list) {
                deactivate_pd_open_pending_consumer();
+       }
+}
+
+static inline int is_pended_item(struct item *item)
+{
+       struct item *in_item;
+       if (pd_is_opened(item->inst->item->pkgname) == 1) {
+               in_item = eina_list_data_find(s_info.pd_open_pending_list, item);
+       } else {
+               in_item = eina_list_data_find(s_info.pending_list, item);
+       }
 
-       DbgPrint("%d items are migrated\n", cnt);
+       return (in_item == item);
 }
 
-static inline int append_pending_list(struct item *item)
+static int append_pending_list(struct item *item)
 {
        if (pd_is_opened(item->inst->item->pkgname) == 1) {
                if (eina_list_data_find(s_info.pd_open_pending_list, item) == item) {
@@ -296,7 +330,6 @@ static inline int append_pending_list(struct item *item)
                        return LB_STATUS_ERROR_EXIST;
                }
 
-               DbgPrint("Activate PD open pending consumer (%s)\n", item->inst->item->pkgname);
                if (activate_pd_open_pending_consumer() < 0) {
                        ErrPrint("Failed to activate PD open pending consumer\n");
                        return LB_STATUS_ERROR_FAULT;
@@ -309,50 +342,81 @@ static inline int append_pending_list(struct item *item)
                        return LB_STATUS_ERROR_EXIST;
                }
 
-               if (activate_pending_consumer() < 0)
+               if (activate_pending_consumer() < 0) {
                        return LB_STATUS_ERROR_FAULT;
+               }
 
                s_info.pending_list = eina_list_append(s_info.pending_list, item);
        }
        return 0;
 }
 
-static inline void timer_thaw(struct item *item)
+/*!
+ * \brief
+ *   This function can call the update callback
+ * return 0 if there is no changes
+ * return -1 the item is deleted
+ */
+static inline int timer_thaw(struct item *item)
 {
        double pending;
        double period;
        double delay;
        double sleep_time;
 
+       if (!item->timer) {
+               return 0;
+       }
+
        ecore_timer_thaw(item->timer);
        period = ecore_timer_interval_get(item->timer);
        pending = ecore_timer_pending_get(item->timer);
        delay = util_time_delay_for_compensation(period) - pending;
        ecore_timer_delay(item->timer, delay);
-       DbgPrint("Compensated: %lf\n", delay);
 
-       if (item->sleep_at == 0.0f)
-               return;
+       if (item->sleep_at == 0.0f) {
+               return 0;
+       }
 
        sleep_time = util_timestamp() - item->sleep_at;
+       item->sleep_at = 0.0f;
+
        if (sleep_time > pending) {
-               DbgPrint("Update time elapsed\n");
-               (void)updator_cb(item);
+               if (updator_cb(item) == ECORE_CALLBACK_CANCEL) {
+                       /* item is destroyed */
+                       return UPDATE_ITEM_DELETED;
+               } else {
+                       return UPDATE_INVOKED;
+               }
        }
 
-       item->sleep_at = 0.0f;
+       return UPDATE_NOT_INVOKED;
 }
 
-static inline void timer_freeze(struct item *item)
+static void timer_freeze(struct item *item)
 {
-       struct timeval tv;
+       if (!item->timer) {
+               return;
+       }
+
        ecore_timer_freeze(item->timer);
 
-       if (ecore_timer_interval_get(item->timer) <= 1.0f)
+       if (ecore_timer_interval_get(item->timer) <= 1.0f) {
                return;
+       }
+
+#if defined(_USE_ECORE_TIME_GET)
+       item->sleep_at = ecore_time_get();
+#else
+       struct timeval tv;
+       if (gettimeofday(&tv, NULL) < 0) {
+               ErrPrint("gettimeofday: %s\n", strerror(errno));
+               tv.tv_sec = 0;
+               tv.tv_usec = 0;
+       }
 
-       gettimeofday(&tv, NULL);
        item->sleep_at = (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0f;
+#endif
 }
 
 static inline void update_monitor_cnt(struct item *item)
@@ -371,10 +435,22 @@ static inline void update_monitor_cnt(struct item *item)
         * And handling this heavy updating from the
         * file update callback.
         */
-       if (interval >= MINIMUM_UPDATE_INTERVAL)
-               item->monitor_cnt++;
-       else
+       if (interval >= MINIMUM_UPDATE_INTERVAL) {
+               if (eina_list_data_find(s_info.update_list, item)) {
+                       /*!
+                        * \note
+                        * If already in updating mode,
+                        * reset the monitor_cnt to 1,
+                        * all updated event will be merged into A inotify event
+                        */
+                       DbgPrint("While waiting updated event, content is updated [%s]\n", item->inst->id);
+                       item->monitor_cnt = 1;
+               } else {
+                       item->monitor_cnt++;
+               }
+       } else {
                item->heavy_updating = 1;
+       }
 
        item->update_interval = now;
 }
@@ -385,8 +461,9 @@ static inline Eina_List *find_item(struct instance *inst)
        struct item *item;
        
        EINA_LIST_FOREACH(s_info.item_list, l, item) {
-               if (item->inst == inst)
+               if (item->inst == inst) {
                        return l;
+               }
        }
 
        return NULL;
@@ -409,16 +486,16 @@ static inline int output_handler(struct item *item)
        }
 
        if (item->monitor_cnt == 0) {
-               if (!invalid)
+               if (!invalid) {
                        fault_unmark_call(item->inst->item->pkgname, item->inst->id, "update,crashed", NO_ALARM);
+               }
 
                if (item->monitor) {
                        ecore_timer_del(item->monitor);
                        item->monitor = NULL;
                }
 
-               if (s_info.update == item)
-                       s_info.update = NULL;
+               s_info.update_list = eina_list_remove(s_info.update_list, item);
 
                if (item->deleteme) {
                        provider_send_deleted(item->inst->item->pkgname, item->inst->id);
@@ -435,13 +512,18 @@ static int desc_updated_cb(const char *filename, void *data, int over)
 {
        struct item *item;
 
-       if (over)
+       if (over) {
                WarnPrint("Event Q overflow\n");
+       }
 
        item = data;
 
        DbgPrint("DESC %s is updated\n", filename);
-       provider_send_desc_updated(item->inst->item->pkgname, item->inst->id, filename);
+       if (item->is_pd_show) {
+               provider_send_desc_updated(item->inst->item->pkgname, item->inst->id, filename);
+       } else {
+               ErrPrint("But PD is not opened, Ignore this update (%s)\n", item->inst->id);
+       }
        return EXIT_SUCCESS;
 }
 
@@ -455,8 +537,9 @@ static int file_updated_cb(const char *filename, void *data, int over)
        char *title = NULL;
        int ret;
 
-       if (over)
+       if (over) {
                WarnPrint("Event Q overflow\n");
+       }
 
        item = data;
 
@@ -472,24 +555,48 @@ static int file_updated_cb(const char *filename, void *data, int over)
                return EXIT_SUCCESS; /*!< To keep the callback */
        }
 
-       provider_send_updated(item->inst->item->pkgname, item->inst->id,
-                                       item->inst->w, item->inst->h, item->inst->priority, content, title);
+       if (IS_LB_SHOWN(item)) {
+               provider_send_updated(item->inst->item->pkgname, item->inst->id,
+                                       item->inst->w, item->inst->h, item->inst->priority,
+                                       content, title);
+       } else {
+               item->is_lb_updated++;
+       }
 
        return output_handler(item);
 }
 
+static void reset_lb_updated_flag(struct item *item)
+{
+       if (!item->is_lb_updated) {
+               return;
+       }
+
+       DbgPrint("[%s] Updated %d times, (content: %s), (title: %s)\n",
+                       item->inst->id, item->is_lb_updated,
+                       item->inst->content, item->inst->title);
+
+       provider_send_updated(item->inst->item->pkgname, item->inst->id,
+                       item->inst->w, item->inst->h, item->inst->priority,
+                       item->inst->content, item->inst->title);
+
+       item->is_lb_updated = 0;
+}
+
 static inline int clear_from_pd_open_pending_list(struct item *item)
 {
        Eina_List *l;
        struct item *tmp;
 
        EINA_LIST_FOREACH(s_info.pd_open_pending_list, l, tmp) {
-               if (tmp != item)
+               if (tmp != item) {
                        continue;
+               }
 
                s_info.pd_open_pending_list = eina_list_remove_list(s_info.pd_open_pending_list, l);
-               if (!s_info.pd_open_pending_list)
+               if (!s_info.pd_open_pending_list) {
                        deactivate_pd_open_pending_consumer();
+               }
                return LB_STATUS_SUCCESS;
        }
 
@@ -502,12 +609,14 @@ static inline int clear_from_pending_list(struct item *item)
        struct item *tmp;
 
        EINA_LIST_FOREACH(s_info.pending_list, l, tmp) {
-               if (tmp != item)
+               if (tmp != item) {
                        continue;
+               }
 
                s_info.pending_list = eina_list_remove_list(s_info.pending_list, l);
-               if (!s_info.pending_list)
+               if (!s_info.pending_list) {
                        deactivate_pending_consumer();
+               }
                return LB_STATUS_SUCCESS;
        }
 
@@ -520,19 +629,25 @@ static Eina_Bool update_timeout_cb(void *data)
 
        item = data;
 
-       DbgPrint("UPDATE TIMEOUT ========> %s - %s\n", item->inst->item->pkgname, item->inst->id);
+       ErrPrint("UPDATE TIMEOUT ========> %s - %s\n", item->inst->item->pkgname, item->inst->id);
 
-       if (s_info.update != item)
+       if (!eina_list_data_find(s_info.update_list, item)) {
                ErrPrint("Updating item is not matched\n");
+       }
 
        fault_unmark_call(item->inst->item->pkgname, item->inst->id, "update,crashed", NO_ALARM);
        fault_mark_call(item->inst->item->pkgname, item->inst->id, "update,timeout", NO_ALARM, DEFAULT_LIFE_TIMER);
-       s_info.update = NULL;
+       s_info.update_list = eina_list_remove(s_info.update_list, item);
 
        exit(ETIME);
        return ECORE_CALLBACK_CANCEL;
 }
 
+/*!
+ * \note
+ * This must has to return ECORE_CALLBACK_CANCEL, only if the item is deleted.
+ * So every caller, should manage the deleted item correctly.
+ */
 static Eina_Bool updator_cb(void *data)
 {
        struct item *item;
@@ -540,26 +655,46 @@ static Eina_Bool updator_cb(void *data)
 
        item = data;
 
-       if (item->monitor) {/*!< If this item is already in update process */
+       if (item->monitor) { /*!< If this item is already in update process */
+               return ECORE_CALLBACK_RENEW;
+       }
+
+       if (!IS_LB_SHOWN(item)) {
+               DbgPrint("%s is not shown yet. make delay for updates\n", item->inst->item->pkgname);
+               (void)append_pending_list(item);
+               return ECORE_CALLBACK_RENEW;
+       }
+
+       if (item->is_paused) {
+               item->updated_in_pause++;
+               DbgPrint("%s is paused[%d]. make delay for updating\n", item->inst->item->pkgname, item->updated_in_pause);
                return ECORE_CALLBACK_RENEW;
        }
 
+       item->updated_in_pause = 0;
+
        ret = so_is_updated(item->inst);
        if (ret <= 0) {
                if (so_need_to_destroy(item->inst) == NEED_TO_DESTROY) {
                        provider_send_deleted(item->inst->item->pkgname, item->inst->id);
                        lb_destroy(item->inst->item->pkgname, item->inst->id);
-
-                       ecore_timer_del(item->timer);
-                       item->timer = NULL;
+                       /*!
+                        * \CRITICAL
+                        * Every caller of this, must not access the item from now.
+                        */
                        return ECORE_CALLBACK_CANCEL;
                }
 
+               reset_lb_updated_flag(item);
                return ECORE_CALLBACK_RENEW;
        }
 
-       if (s_info.update || pd_is_opened(item->inst->item->pkgname) < 0) {
-               DbgPrint("%s is busy\n", s_info.update ? s_info.update->inst->id : item->inst->id);
+       /*!
+        * \note
+        * Check the update_list, if you want make serialized update
+        */
+       if (/*s_info.update_list || */pd_is_opened(item->inst->item->pkgname) < 0) {
+               DbgPrint("%s is busy\n", item->inst->id);
                (void)append_pending_list(item);
                return ECORE_CALLBACK_RENEW;
        }
@@ -571,6 +706,14 @@ static Eina_Bool updator_cb(void *data)
                return ECORE_CALLBACK_RENEW;
        }
 
+       ret = so_update(item->inst);
+       if (ret < 0) {
+               ecore_timer_del(item->monitor);
+               item->monitor = NULL;
+               reset_lb_updated_flag(item);
+               return ECORE_CALLBACK_RENEW;
+       }
+
        /*!
         * \note
         * Counter of the event monitor is only used for asynchronous content updating,
@@ -579,18 +722,6 @@ static Eina_Bool updator_cb(void *data)
         */
        item->monitor_cnt = 1;
 
-       s_info.update = item;
-
-       ret = so_update(item->inst);
-       if (ret < 0) {
-               item->monitor_cnt--;
-
-               ecore_timer_del(item->monitor);
-               item->monitor = NULL;
-               s_info.update = NULL;
-               return ECORE_CALLBACK_RENEW;
-       }
-
        /*!
         * \note
         * While waiting the Callback function call,
@@ -602,8 +733,24 @@ static Eina_Bool updator_cb(void *data)
                (void)append_pending_list(item);
        }
 
-       if (ret & OUTPUT_UPDATED)
+       if (ret & OUTPUT_UPDATED) {
+               /*!
+                * \NOTE 
+                * In this case, there is potential issue
+                * 1. User added update CALLBACK -> Inotify event (Only once)
+                *    > We have to detect this case. Is it possible to be a user callback called faster than inotify event handler?
+                * 2. Inotify event -> User added update CALLBACK -> Inotify event
+                *    > Okay. What we want is this.
+                */
                update_monitor_cnt(item);
+       }
+
+       /*
+        * \NOTE
+        * This should be updated after "update_monitor_cnt" function call,
+        * because the update_monitor_cnt function will see the s_info.update variable,
+        */
+       s_info.update_list = eina_list_append(s_info.update_list, item);
 
        return ECORE_CALLBACK_RENEW;
 }
@@ -631,6 +778,7 @@ static inline int add_desc_update_monitor(const char *id, struct item *item)
 {
        char *filename;
        int len;
+       int ret;
 
        len = strlen(util_uri_to_path(id)) + strlen(".desc") + 1;
        filename = malloc(len);
@@ -640,21 +788,14 @@ static inline int add_desc_update_monitor(const char *id, struct item *item)
        }
 
        snprintf(filename, len, "%s.desc", util_uri_to_path(id));
-       DbgPrint("Add DESC monitor: %s\n", filename);
-       return update_monitor_add_update_cb(filename, desc_updated_cb, item);
+       ret = update_monitor_add_update_cb(filename, desc_updated_cb, item);
+       free(filename);
+       return ret;
 }
 
 static inline int add_file_update_monitor(const char *id, struct item *item)
 {
-       char *filename;
-
-       filename = strdup(util_uri_to_path(id));
-       if (!filename) {
-               ErrPrint("Heap: %s (%s)\n", strerror(errno), id);
-               return LB_STATUS_ERROR_MEMORY;
-       }
-
-       return update_monitor_add_update_cb(filename, file_updated_cb, item);
+       return update_monitor_add_update_cb(util_uri_to_path(id), file_updated_cb, item);
 }
 
 static inline int update_monitor_add(const char *id, struct item *item)
@@ -703,8 +844,9 @@ const char *livebox_find_pkgname(const char *filename)
        struct item *item;
 
        EINA_LIST_FOREACH(s_info.item_list, l, item) {
-               if (!strcmp(item->inst->id, filename))
+               if (!strcmp(item->inst->id, filename)) {
                        return item->inst->item->pkgname;
+               }
        }
 
        return NULL;
@@ -715,6 +857,18 @@ int livebox_request_update_by_id(const char *filename)
        Eina_List *l;
        struct item *item;
 
+       if (so_current_op() != LIVEBOX_OP_UNKNOWN) {
+               ErrPrint("Current operation: %d\n", so_current_op());
+               /*!
+                * \note
+                * Some case requires to update the content of other box from livebox_XXX ABI.
+                * In that case this function can be used so we have not to filter it from here.
+                * ex) Setting accessibility.
+                * Press the assistive light, turned on, need to update other instances too.
+                * Then the box will use this function from livebox_clicked function.
+                */
+       }
+
        EINA_LIST_FOREACH(s_info.item_list, l, item) {
                if (!strcmp(item->inst->id, filename)) {
                        return append_pending_list(item);
@@ -724,14 +878,55 @@ int livebox_request_update_by_id(const char *filename)
        return LB_STATUS_ERROR_NOT_EXIST;
 }
 
+int livebox_trigger_update_monitor(const char *filename, int is_pd)
+{
+       char *fname;
+       int ret;
+
+       if (so_current_op() != LIVEBOX_OP_UNKNOWN) {
+               ErrPrint("Current operation: %d\n", so_current_op());
+               return LB_STATUS_ERROR_INVALID;
+       }
+
+       if (is_pd) {
+               int len;
+               len = strlen(filename) + strlen(".desc");
+
+               fname = malloc(len + 1);
+               if (!fname) {
+                       ErrPrint("Heap: %s\n", strerror(errno));
+                       return LB_STATUS_ERROR_MEMORY;
+               }
+
+               snprintf(fname, len, "%s.desc", filename);
+       } else {
+               fname = strdup(filename);
+               if (!fname) {
+                       ErrPrint("Heap: %s\n", strerror(errno));
+                       return LB_STATUS_ERROR_MEMORY;
+               }
+       }
+
+       if (access(fname, R_OK | W_OK) != 0) {
+               ErrPrint("access: %s (%s)\n", fname, strerror(errno));
+               ret = LB_STATUS_ERROR_IO;
+       } else {
+               ret = update_monitor_trigger_update_cb(fname, 0);
+       }
+
+       free(fname);
+       return ret;
+}
+
 HAPI int lb_open_pd(const char *pkgname)
 {
        Eina_List *l;
        char *tmp;
 
        EINA_LIST_FOREACH(s_info.pd_list, l, tmp) {
-               if (!strcmp(pkgname, tmp))
+               if (!strcmp(pkgname, tmp)) {
                        return 0;
+               }
        }
 
        tmp = strdup(pkgname);
@@ -740,8 +935,9 @@ HAPI int lb_open_pd(const char *pkgname)
                return LB_STATUS_ERROR_MEMORY;
        }
 
-       if (!s_info.pd_list)
+       if (!s_info.pd_list) {
                pending_timer_freeze();
+       }
 
        s_info.pd_list = eina_list_append(s_info.pd_list, tmp);
 
@@ -760,14 +956,16 @@ HAPI int lb_close_pd(const char *pkgname)
        char *tmp;
 
        EINA_LIST_FOREACH_SAFE(s_info.pd_list, l, n, tmp) {
-               if (strcmp(tmp, pkgname))
+               if (strcmp(tmp, pkgname)) {
                        continue;
+               }
 
                s_info.pd_list = eina_list_remove(s_info.pd_list, tmp);
                free(tmp);
 
-               if (!s_info.pd_list)
+               if (!s_info.pd_list) {
                        pending_timer_thaw();
+               }
 
                /*!
                 * Move all items in pd_open_pending_list
@@ -800,8 +998,9 @@ HAPI int lb_create(const char *pkgname, const char *id, const char *content_info
 
        if (!skip_need_to_create) {
                ret = so_create_needed(pkgname, cluster, category, abi);
-               if (ret != NEED_TO_CREATE)
+               if (ret != NEED_TO_CREATE) {
                        return LB_STATUS_ERROR_PERMISSION;
+               }
 
                need_to_create = 1;
        }
@@ -818,7 +1017,6 @@ HAPI int lb_create(const char *pkgname, const char *id, const char *content_info
                return ret;
        }
 
-       DbgPrint("Content: [%s]\n", content_info);
        create_ret = so_create(pkgname, id, content_info, timeout, has_livebox_script, cluster, category, abi, &inst);
        if (create_ret < 0) {
                update_monitor_del(id,  item);
@@ -837,13 +1035,14 @@ HAPI int lb_create(const char *pkgname, const char *id, const char *content_info
                if (!item->timer) {
                        ErrPrint("Failed to add timer (%s - %s, content[%s], cluster[%s], category[%s], abi[%s]\n", pkgname, id, content_info, cluster, category, abi);
                        update_monitor_del(id, item);
-                       so_destroy(inst);
+                       (void)so_destroy(inst);
                        free(item);
                        return LB_STATUS_ERROR_FAULT;
                }
 
-               if (s_info.paused)
+               if (s_info.paused) {
                        timer_freeze(item);
+               }
        } else {
                DbgPrint("Local update timer is disabled: %lf (%d)\n", period, s_info.secured);
                item->timer = NULL;
@@ -872,8 +1071,9 @@ HAPI int lb_create(const char *pkgname, const char *id, const char *content_info
                                char *tmp;
 
                                tmp = strdup(*out_content);
-                               if (!tmp)
+                               if (!tmp) {
                                        ErrPrint("Memory: %s\n", strerror(errno));
+                               }
 
                                *out_content = tmp;
                        }
@@ -882,8 +1082,9 @@ HAPI int lb_create(const char *pkgname, const char *id, const char *content_info
                                char *tmp;
 
                                tmp = strdup(*out_title);
-                               if (!tmp)
+                               if (!tmp) {
                                        ErrPrint("Memory: %s\n", strerror(errno));
+                               }
 
                                *out_title = tmp;
                        }
@@ -917,8 +1118,7 @@ HAPI int lb_destroy(const char *pkgname, const char *id)
        item = eina_list_data_get(l);
        s_info.item_list = eina_list_remove_list(s_info.item_list, l);
 
-       if (s_info.update == item)
-               s_info.update = NULL;
+       s_info.update_list = eina_list_remove(s_info.update_list, item);
 
        if (item->timer) {
                clear_from_pd_open_pending_list(item);
@@ -926,10 +1126,11 @@ HAPI int lb_destroy(const char *pkgname, const char *id)
                ecore_timer_del(item->timer);
                item->timer = NULL;
 
-               if (item->monitor)
+               if (item->monitor) {
                        item->deleteme = 1;
-               else
+               } else {
                        update_monitor_del(id, item);
+               }
        }
 
        if (!item->monitor) {
@@ -962,16 +1163,18 @@ HAPI int lb_resize(const char *pkgname, const char *id, int w, int h)
        item = eina_list_data_get(l);
 
        ret = so_resize(inst, w, h);
-       if (ret < 0)
+       if (ret < 0) {
                return ret;
+       }
 
        if (ret & NEED_TO_SCHEDULE) {
                DbgPrint("%s Returns NEED_TO_SCHEDULE\n", pkgname);
                (void)append_pending_list(item);
        }
 
-       if (ret & OUTPUT_UPDATED)
+       if (ret & OUTPUT_UPDATED) {
                update_monitor_cnt(item);
+       }
 
        return LB_STATUS_SUCCESS;
 }
@@ -1026,8 +1229,9 @@ HAPI int lb_set_period(const char *pkgname, const char *id, double period)
                                return LB_STATUS_ERROR_FAULT;
                        }
 
-                       if (s_info.paused)
+                       if (s_info.paused) {
                                timer_freeze(item);
+                       }
                }
        }
 
@@ -1056,16 +1260,18 @@ HAPI int lb_clicked(const char *pkgname, const char *id, const char *event, doub
        item = eina_list_data_get(l);
 
        ret = so_clicked(inst, event, timestamp, x, y);
-       if (ret < 0)
+       if (ret < 0) {
                return ret;
+       }
 
        if (ret & NEED_TO_SCHEDULE) {
                DbgPrint("%s Returns NEED_TO_SCHEDULE\n", pkgname);
                (void)append_pending_list(item);
        }
 
-       if (ret & OUTPUT_UPDATED)
+       if (ret & OUTPUT_UPDATED) {
                update_monitor_cnt(item);
+       }
 
        return LB_STATUS_SUCCESS;
 }
@@ -1091,17 +1297,46 @@ HAPI int lb_script_event(const char *pkgname, const char *id, const char *emissi
 
        item = eina_list_data_get(l);
 
+       if (emission && source && !strcmp(source, id)) {
+               if (item->inst->item->has_livebox_script) {
+                       if (!strcmp(emission, "lb,show")) {
+                               item->is_lb_show = 1;
+
+                               if (item->is_lb_updated && !is_pended_item(item)) {
+                                       reset_lb_updated_flag(item);
+                               }
+
+                               source = util_uri_to_path(source);
+                       } else if (!strcmp(emission, "lb,hide")) {
+                               DbgPrint("Livebox(%s) script is hide now\n", id);
+                               item->is_lb_show = 0;
+
+                               source = util_uri_to_path(source);
+                       }
+               }
+
+               if (!strcmp(emission, "pd,show")) {
+                       item->is_pd_show = 1;
+                       source = util_uri_to_path(source);
+               } else if (!strcmp(emission, "pd,hide")) {
+                       item->is_pd_show = 0;
+                       source = util_uri_to_path(source);
+               }
+       }
+
        ret = so_script_event(inst, emission, source, event_info);
-       if (ret < 0)
+       if (ret < 0) {
                return ret;
+       }
 
        if (ret & NEED_TO_SCHEDULE) {
                DbgPrint("%s Returns NEED_TO_SCHEDULE\n", pkgname);
                (void)append_pending_list(item);
        }
 
-       if (ret & OUTPUT_UPDATED)
+       if (ret & OUTPUT_UPDATED) {
                update_monitor_cnt(item);
+       }
 
        return LB_STATUS_SUCCESS;
 }
@@ -1159,33 +1394,38 @@ HAPI int lb_change_group(const char *pkgname, const char *id, const char *cluste
        item = eina_list_data_get(l);
 
        ret = so_change_group(inst, cluster, category);
-       if (ret < 0)
+       if (ret < 0) {
                return ret;
+       }
 
        if (ret & NEED_TO_SCHEDULE) {
                DbgPrint("%s Returns NEED_TO_SCHEDULE\n", pkgname);
                (void)append_pending_list(item);
        }
 
-       if (ret & OUTPUT_UPDATED)
+       if (ret & OUTPUT_UPDATED) {
                update_monitor_cnt(item);
+       }
 
        return LB_STATUS_SUCCESS;
 }
 
-static inline int lb_sys_event(struct instance *inst, struct item *item, int event)
+static int lb_sys_event(struct instance *inst, struct item *item, int event)
 {
        int ret;
 
        ret = so_sys_event(inst, event);
-       if (ret < 0)
+       if (ret < 0) {
                return ret;
+       }
 
-       if (ret & NEED_TO_SCHEDULE)
+       if (ret & NEED_TO_SCHEDULE) {
                (void)append_pending_list(item);
+       }
 
-       if (ret & OUTPUT_UPDATED)
+       if (ret & OUTPUT_UPDATED) {
                update_monitor_cnt(item);
+       }
 
        return LB_STATUS_SUCCESS;
 }
@@ -1243,14 +1483,17 @@ HAPI int lb_update_all(const char *pkgname, const char *cluster, const char *cat
 
        DbgPrint("Update content for %s\n", pkgname ? pkgname : "(all)");
        EINA_LIST_FOREACH_SAFE(s_info.item_list, l, n, item) {
-               if (item->deleteme)
+               if (item->deleteme) {
                        continue;
+               }
 
-               if (cluster && strcasecmp(item->inst->cluster, cluster))
+               if (cluster && strcasecmp(item->inst->cluster, cluster)) {
                        continue;
+               }
 
-               if (category && strcasecmp(item->inst->category, category))
+               if (category && strcasecmp(item->inst->category, category)) {
                        continue;
+               }
 
                if (pkgname && strlen(pkgname)) {
                        if (!strcmp(item->inst->item->pkgname, pkgname)) {
@@ -1264,6 +1507,28 @@ HAPI int lb_update_all(const char *pkgname, const char *cluster, const char *cat
        return LB_STATUS_SUCCESS;
 }
 
+HAPI int lb_delete_all_deleteme(void)
+{
+       Eina_List *l;
+       Eina_List *n;
+       struct item *item;
+       int cnt = 0;
+
+       EINA_LIST_FOREACH_SAFE(s_info.item_list, l, n, item) {
+               if (!item->deleteme) {
+                       continue;
+               }
+
+               update_monitor_del(item->inst->id, item);
+               (void)so_destroy(item->inst);
+               free(item);
+               cnt++;
+       }
+
+       DbgPrint("Delete all deleteme: %d\n", cnt);
+       return LB_STATUS_SUCCESS;
+}
+
 HAPI int lb_system_event_all(int event)
 {
        Eina_List *l;
@@ -1271,8 +1536,9 @@ HAPI int lb_system_event_all(int event)
        struct item *item;
 
        EINA_LIST_FOREACH_SAFE(s_info.item_list, l, n, item) {
-               if (item->deleteme)
+               if (item->deleteme) {
                        continue;
+               }
 
                DbgPrint("System event for %s (%d)\n", item->inst->id, event);
                lb_sys_event(item->inst, item, event);
@@ -1297,16 +1563,10 @@ HAPI void lb_pause_all(void)
                }
 
                if (item->is_paused) {
-                       DbgPrint("Instance %s is already paused\n", item->inst->id);
                        continue;
                }
 
-               if (item->timer) {
-                       DbgPrint("Instance %s freeze timer\n", item->inst->item->pkgname);
-                       timer_freeze(item);
-               } else {
-                       DbgPrint("Instance %s has no timer\n", item->inst->item->pkgname);
-               }
+               timer_freeze(item);
 
                lb_sys_event(item->inst, item, LB_SYS_EVENT_PAUSED);
        }
@@ -1315,29 +1575,40 @@ HAPI void lb_pause_all(void)
 HAPI void lb_resume_all(void)
 {
        Eina_List *l;
+       Eina_List *n;
        struct item *item;
 
        s_info.paused = 0;
 
        pending_timer_thaw();
 
-       EINA_LIST_FOREACH(s_info.item_list, l, item) {
+       EINA_LIST_FOREACH_SAFE(s_info.item_list, l, n, item) {
                if (item->deleteme) {
                        DbgPrint("Instance %s skip timer resume (deleteme)\n", item->inst->item->pkgname);
                        continue;
                }
 
                if (item->is_paused) {
-                       DbgPrint("Instance %s is still paused\n", item->inst->id);
                        continue;
                }
 
-               if (item->timer) {
-                       DbgPrint("Instance %s resume timer\n", item->inst->item->pkgname);
-                       timer_thaw(item);
+               lb_sys_event(item->inst, item, LB_SYS_EVENT_RESUMED);
+
+               if (item->updated_in_pause) {
+                       (void)append_pending_list(item);
+                       item->updated_in_pause = 0;
                }
 
-               lb_sys_event(item->inst, item, LB_SYS_EVENT_RESUMED);
+               /*!
+                * \note
+                * After send the resume callback, call this function.
+                * Because the timer_thaw can call the update function.
+                * Before resumed event is notified to the livebox,
+                * Do not call update function
+                */
+               if (timer_thaw(item) == UPDATE_ITEM_DELETED) {
+                       /* item is deleted */
+               }
        }
 }
 
@@ -1348,8 +1619,9 @@ HAPI int lb_pause(const char *pkgname, const char *id)
        struct item *item;
 
        inst = so_find_instance(pkgname, id);
-       if (!inst)
+       if (!inst) {
                return LB_STATUS_ERROR_INVALID;
+       }
 
        l = find_item(inst);
        if (!l) {
@@ -1358,8 +1630,9 @@ HAPI int lb_pause(const char *pkgname, const char *id)
        }
 
        item = eina_list_data_get(l);
-       if (!item)
+       if (!item) {
                return LB_STATUS_ERROR_FAULT;
+       }
 
        if (item->deleteme) {
                DbgPrint("Instance %s will be deleted (%s)\n", item->inst->item->pkgname, item->inst->id);
@@ -1369,12 +1642,10 @@ HAPI int lb_pause(const char *pkgname, const char *id)
        item->is_paused = 1;
 
        if (s_info.paused) {
-               DbgPrint("Already paused: %s\n", item->inst->id);
                return LB_STATUS_SUCCESS;
        }
 
-       if (item->timer)
-               timer_freeze(item);
+       timer_freeze(item);
 
        lb_sys_event(inst, item, LB_SYS_EVENT_PAUSED);
 
@@ -1386,10 +1657,12 @@ HAPI int lb_resume(const char *pkgname, const char *id)
        struct instance *inst;
        Eina_List *l;
        struct item *item;
+       int ret;
 
        inst = so_find_instance(pkgname, id);
-       if (!inst)
+       if (!inst) {
                return LB_STATUS_ERROR_INVALID;
+       }
 
        l = find_item(inst);
        if (!l) {
@@ -1398,8 +1671,9 @@ HAPI int lb_resume(const char *pkgname, const char *id)
        }
 
        item = eina_list_data_get(l);
-       if (!item)
+       if (!item) {
                return LB_STATUS_ERROR_FAULT;
+       }
 
        if (item->deleteme) {
                DbgPrint("Instance %s will be deleted (%s)\n", item->inst->item->pkgname, item->inst->id);
@@ -1409,14 +1683,31 @@ HAPI int lb_resume(const char *pkgname, const char *id)
        item->is_paused = 0;
 
        if (s_info.paused) {
-               DbgPrint("Instance %s is still paused\n", item->inst->id);
                return LB_STATUS_SUCCESS;
        }
 
-       if (item->timer)
-               timer_thaw(item);
-
        lb_sys_event(inst, item, LB_SYS_EVENT_RESUMED);
+
+       ret = timer_thaw(item);
+       if (ret == UPDATE_ITEM_DELETED) {
+               /*!
+                * \note
+                * ITEM is deleted
+                */
+               return LB_STATUS_SUCCESS;
+       } else if (ret == UPDATE_INVOKED) {
+               /*!
+                * \note
+                * if the update is successfully done, the updated_in_pause will be reset'd.
+                * or append it to the pending list
+                */
+       }
+
+       if (item->updated_in_pause) {
+               (void)append_pending_list(item);
+               item->updated_in_pause = 0;
+       }
+
        return LB_STATUS_SUCCESS;
 }
 
@@ -1425,4 +1716,9 @@ HAPI void lb_turn_secured_on(void)
        s_info.secured = 1;
 }
 
+HAPI int lb_is_all_paused(void)
+{
+       return s_info.paused;
+}
+
 /* End of a file */