Sync with the latest tizen 2.x 28/47328/1 submit/tizen_mobile/20150903.042129
authorSung-jae Park <nicesj.park@samsung.com>
Wed, 2 Sep 2015 09:56:31 +0000 (18:56 +0900)
committerSung-jae Park <nicesj.park@samsung.com>
Wed, 2 Sep 2015 09:56:31 +0000 (18:56 +0900)
Change-Id: I768a1705ebd176b38212d39d19b98ee775c6e6af

16 files changed:
packaging/libwidget_viewer.spec
widget_viewer/include/debug.h
widget_viewer/include/util.h
widget_viewer/include/widget_viewer.h
widget_viewer/src/client.c
widget_viewer/src/util.c
widget_viewer/src/widget.c
widget_viewer/src/widget_internal.c
widget_viewer_evas/include/widget_viewer_evas.h
widget_viewer_evas/include/widget_viewer_evas_internal.h
widget_viewer_evas/src/widget_viewer_evas.c
widget_viewer_sdk/CMakeLists.txt
widget_viewer_sdk/data/widget_viewer_sdk.edc
widget_viewer_sdk/include/debug.h
widget_viewer_sdk/org.tizen.widget_viewer_sdk.xml
widget_viewer_sdk/src/main.c

index 5da01df..fb1358c 100644 (file)
@@ -2,7 +2,7 @@
 
 Name: libwidget_viewer
 Summary: Library for developing the application
-Version: 1.2.1
+Version: 1.2.2
 Release: 1
 Group: Applications/Core Applications
 License: Flora-1.1
index a6563ee..483309e 100644 (file)
@@ -19,9 +19,9 @@
 #define ErrPrint(format, arg...)    SECURE_LOGE(format, ##arg)
 #else
 extern FILE *__file_log_fp;
-#define DbgPrint(format, arg...) do { fprintf(__file_log_fp, "[LOG] [\e[32m%s/%s\e[0m:%d] " format, util_basename(__FILE__), __func__, __LINE__, ##arg); fflush(__file_log_fp); } while (0)
+#define DbgPrint(format, arg...) do { fprintf(__file_log_fp, "[LOG] [\e[32m%s/%s\e[0m:%d] " format, widget_util_basename(__FILE__), __func__, __LINE__, ##arg); fflush(__file_log_fp); } while (0)
 
-#define ErrPrint(format, arg...) do { fprintf(__file_log_fp, "[ERR] [\e[32m%s/%s\e[0m:%d] " format, util_basename(__FILE__), __func__, __LINE__, ##arg); fflush(__file_log_fp); } while (0)
+#define ErrPrint(format, arg...) do { fprintf(__file_log_fp, "[ERR] [\e[32m%s/%s\e[0m:%d] " format, widget_util_basename(__FILE__), __func__, __LINE__, ##arg); fflush(__file_log_fp); } while (0)
 #endif
 
 
index 498a249..b463568 100644 (file)
@@ -16,7 +16,6 @@
 
 extern int util_check_extension(const char *filename, const char *check_ptr);
 extern double util_timestamp(void);
-extern const char *util_basename(const char *name);
 extern const char *util_uri_to_path(const char *uri);
 extern int util_unlink(const char *filename);
 
index 4dce72a..be29dcd 100644 (file)
@@ -48,6 +48,10 @@ typedef struct widget *widget_h;
  */
 #define WIDGET_DEFAULT_PERIOD -1.0f
 
+#define WIDGET_VIEWER_CLICK_BUTTON_LEFT    "clicked"
+#define WIDGET_VIEWER_CLICK_BUTTON_RIGHT   "clicked,1"
+#define WIDGET_VIEWER_CLICK_BUTTON_CENTER  "clicked,2"
+
 /**
  * @internal
  * @brief Enumeration for Mouse & Key event for buffer type widget or Glance Bar.
@@ -284,6 +288,7 @@ typedef struct widget_mouse_event_info {
        double y;                                   /**< Y coordinates of Mouse Event */
        double ratio_w;
        double ratio_h;
+       int device;
 } *widget_mouse_event_info_s;
 
 /**
@@ -293,6 +298,7 @@ typedef struct widget_mouse_event_info {
  */
 typedef struct widget_key_event_info {
     unsigned int keycode;                       /**< Key code */
+       int device;
 } *widget_key_event_info_s;
 
 /**
@@ -652,7 +658,7 @@ extern int widget_viewer_resize_widget(widget_h handle, widget_size_type_e type,
  * @retval #WIDGET_STATUS_ERROR_FAULT Unrecoverable error occurred
  * @retval #WIDGET_STATUS_ERROR_NONE Successfully done
  */
-extern int widget_viewer_send_click_event(widget_h handle, double x, double y);
+extern int widget_viewer_send_click_event(widget_h handle, const char *event, double x, double y);
 
 /**
  * @internal
index 70e7eac..9609dff 100644 (file)
@@ -37,6 +37,7 @@
 #include <widget_cmd_list.h>
 #include <widget_buffer.h>
 #include <widget_conf.h>
+#include <widget_util.h>
 #include <secure_socket.h>
 
 #include "debug.h"
@@ -729,7 +730,7 @@ static struct packet *master_extra_updated(pid_t pid, int handle, const struct p
                        if (!conf_manual_sync()) {
                                ret = _widget_sync_widget_fb(common);
                                if (ret != (int)WIDGET_ERROR_NONE) {
-                                       ErrPrint("Failed to do sync FB (%s - %s) (%d)\n", pkgname, util_basename(util_uri_to_path(id)), ret);
+                                       ErrPrint("Failed to do sync FB (%s - %s) (%d)\n", pkgname, widget_util_basename(util_uri_to_path(id)), ret);
                                }
                        } else {
                                ret = WIDGET_ERROR_NONE;
@@ -822,7 +823,7 @@ static struct packet *master_widget_updated(pid_t pid, int handle, const struct
                        if (!conf_manual_sync()) {
                                ret = _widget_sync_widget_fb(common);
                                if (ret != (int)WIDGET_ERROR_NONE) {
-                                       ErrPrint("Failed to do sync FB (%s - %s) (%d)\n", pkgname, util_basename(util_uri_to_path(id)), ret);
+                                       ErrPrint("Failed to do sync FB (%s - %s) (%d)\n", pkgname, widget_util_basename(util_uri_to_path(id)), ret);
                                }
                        } else {
                                ret = WIDGET_ERROR_NONE;
@@ -915,7 +916,7 @@ static struct packet *master_gbar_created(pid_t pid, int handle, const struct pa
 
                        ret = _widget_sync_gbar_fb(common);
                        if (ret < 0) {
-                               ErrPrint("Failed to do sync FB (%s - %s)\n", pkgname, util_basename(util_uri_to_path(id)));
+                               ErrPrint("Failed to do sync FB (%s - %s)\n", pkgname, widget_util_basename(util_uri_to_path(id)));
                        }
                }
        }
@@ -1015,7 +1016,7 @@ static struct packet *master_gbar_destroyed(pid_t pid, int handle, const struct
                switch (fb_type(_widget_get_gbar_fb(common))) {
                case WIDGET_FB_TYPE_FILE:
                case WIDGET_FB_TYPE_SHM:
-                       widget_service_destroy_lock(common->gbar.lock);
+                       widget_service_destroy_lock(common->gbar.lock, 0);
                        common->gbar.lock = NULL;
                        break;
                case WIDGET_FB_TYPE_PIXMAP:
@@ -1089,7 +1090,7 @@ static struct packet *master_gbar_updated(pid_t pid, int handle, const struct pa
                        if (!conf_manual_sync()) {
                                ret = _widget_sync_gbar_fb(common);
                                if (ret < 0) {
-                                       ErrPrint("Failed to do sync FB (%s - %s), %d\n", pkgname, util_basename(util_uri_to_path(id)), ret);
+                                       ErrPrint("Failed to do sync FB (%s - %s), %d\n", pkgname, widget_util_basename(util_uri_to_path(id)), ret);
                                } else {
                                        dlist_foreach(common->widget_list, l, handler) {
                                                _widget_invoke_event_handler(handler, WIDGET_EVENT_GBAR_UPDATED);
@@ -1470,7 +1471,7 @@ static struct packet *master_size_changed(pid_t pid, int handle, const struct pa
 
                                ret = _widget_sync_widget_fb(common);
                                if (ret < 0) {
-                                       ErrPrint("Failed to do sync FB (%s - %s)\n", pkgname, util_basename(util_uri_to_path(id)));
+                                       ErrPrint("Failed to do sync FB (%s - %s)\n", pkgname, widget_util_basename(util_uri_to_path(id)));
                                }
 
                                /* Just update the size info only. */
@@ -1791,7 +1792,7 @@ static struct packet *master_created(pid_t pid, int handle, const struct packet
 
                ret = _widget_sync_widget_fb(common);
                if (ret < 0) {
-                       ErrPrint("Failed to do sync FB (%s - %s)\n", pkgname, util_basename(util_uri_to_path(id)));
+                       ErrPrint("Failed to do sync FB (%s - %s)\n", pkgname, widget_util_basename(util_uri_to_path(id)));
                }
                break;
        case WIDGET_TYPE_TEXT:
@@ -1815,7 +1816,7 @@ static struct packet *master_created(pid_t pid, int handle, const struct packet
 
                ret = _widget_sync_gbar_fb(common);
                if (ret < 0) {
-                       ErrPrint("Failed to do sync FB (%s - %s)\n", pkgname, util_basename(util_uri_to_path(id)));
+                       ErrPrint("Failed to do sync FB (%s - %s)\n", pkgname, widget_util_basename(util_uri_to_path(id)));
                }
 
                /*!
index c9cc01d..eac5a75 100644 (file)
@@ -91,19 +91,6 @@ double util_timestamp(void)
 #endif
 }
 
-const char *util_basename(const char *name)
-{
-       int length;
-       length = name ? strlen(name) : 0;
-       if (!length) {
-               return ".";
-       }
-
-       while (--length > 0 && name[length] != '/');
-
-       return length <= 0 ? name : name + length + (name[length] == '/');
-}
-
 const char *util_uri_to_path(const char *uri)
 {
        int len;
index 84138ac..a2131a3 100644 (file)
@@ -847,13 +847,13 @@ static int send_access_event(widget_h handle, const char *event, int x, int y, i
        return master_rpc_async_request(handle, packet, 0, access_ret_cb, NULL);
 }
 
-static int send_key_event(widget_h handle, const char *event, unsigned int keycode)
+static int send_key_event(widget_h handle, const char *event, unsigned int keycode, int device)
 {
        struct packet *packet;
        double timestamp;
 
        timestamp = util_timestamp();
-       packet = packet_create(event, "ssdi", handle->common->pkgname, handle->common->id, timestamp, keycode);
+       packet = packet_create(event, "ssdii", handle->common->pkgname, handle->common->id, timestamp, keycode, device);
        if (!packet) {
                ErrPrint("Failed to build packet\n");
                return WIDGET_ERROR_FAULT;
@@ -862,13 +862,13 @@ static int send_key_event(widget_h handle, const char *event, unsigned int keyco
        return master_rpc_async_request(handle, packet, 0, key_ret_cb, NULL);
 }
 
-static int send_mouse_event(widget_h handle, const char *event, int x, int y, double ratio_w, double ratio_h)
+static int send_mouse_event(widget_h handle, const char *event, int x, int y, double ratio_w, double ratio_h, int device)
 {
        struct packet *packet;
        double timestamp;
 
        timestamp = util_timestamp();
-       packet = packet_create_noack(event, "ssdiiidd", handle->common->pkgname, handle->common->id, timestamp, x, y, INPUT_EVENT_SOURCE_VIEWER, ratio_w, ratio_h);
+       packet = packet_create_noack(event, "ssdiiiddi", handle->common->pkgname, handle->common->id, timestamp, x, y, INPUT_EVENT_SOURCE_VIEWER, ratio_w, ratio_h, device);
        if (!packet) {
                ErrPrint("Failed to build param\n");
                return WIDGET_ERROR_FAULT;
@@ -1841,7 +1841,7 @@ EAPI int widget_viewer_resize_widget(widget_h handle, widget_size_type_e type, w
        return ret;
 }
 
-EAPI int widget_viewer_send_click_event(widget_h handle, double x, double y)
+EAPI int widget_viewer_send_click_event(widget_h handle, const char *event, double x, double y)
 {
        struct packet *packet;
        double timestamp;
@@ -1858,6 +1858,11 @@ EAPI int widget_viewer_send_click_event(widget_h handle, double x, double y)
                return WIDGET_ERROR_INVALID_PARAMETER;
        }
 
+       if (!event || (strcmp(event, WIDGET_VIEWER_CLICK_BUTTON_LEFT) && strcmp(event, WIDGET_VIEWER_CLICK_BUTTON_RIGHT) && strcmp(event, WIDGET_VIEWER_CLICK_BUTTON_CENTER))) {
+               ErrPrint("Unknown event: (%s)\n", event);
+               return WIDGET_ERROR_INVALID_PARAMETER;
+       }
+
        if (!handle->common->id) {
                ErrPrint("Handler is not valid\n");
                return WIDGET_ERROR_INVALID_PARAMETER;
@@ -1875,7 +1880,7 @@ EAPI int widget_viewer_send_click_event(widget_h handle, double x, double y)
        timestamp = util_timestamp();
        DbgPrint("CLICKED: %lf\n", timestamp);
 
-       packet = packet_create_noack((const char *)&cmd, "sssddd", handle->common->pkgname, handle->common->id, "clicked", timestamp, x, y);
+       packet = packet_create_noack((const char *)&cmd, "sssddd", handle->common->pkgname, handle->common->id, event, timestamp, x, y);
        if (!packet) {
                ErrPrint("Failed to build param\n");
                return WIDGET_ERROR_FAULT;
@@ -2438,7 +2443,7 @@ EAPI int widget_viewer_feed_mouse_event(widget_h handle, widget_mouse_event_type
                return WIDGET_ERROR_INVALID_PARAMETER;
        }
 
-       return send_mouse_event(handle, (const char *)&cmd, info->x, info->y, info->ratio_w, info->ratio_h);
+       return send_mouse_event(handle, (const char *)&cmd, info->x, info->y, info->ratio_w, info->ratio_h, info->device);
 }
 
 EAPI int widget_viewer_feed_key_event(widget_h handle, widget_key_event_type_e type, widget_key_event_info_s info, widget_ret_cb cb, void *data)
@@ -2570,7 +2575,7 @@ EAPI int widget_viewer_feed_key_event(widget_h handle, widget_key_event_type_e t
                cb = default_key_event_cb;
        }
 
-       ret = send_key_event(handle, (const char *)&cmd, info->keycode);
+       ret = send_key_event(handle, (const char *)&cmd, info->keycode, info->device);
        if (ret == (int)WIDGET_ERROR_NONE) {
                handle->cbs.key_event.cb = cb;
                handle->cbs.key_event.data = data;
index a767b12..acd4db6 100644 (file)
@@ -754,7 +754,7 @@ widget_h _widget_unref(widget_h handler, int destroy_common)
                         * \note
                         * Lock file should be deleted after all callbacks are processed.
                         */
-                       (void)widget_service_destroy_lock(handler->common->widget.lock);
+                       (void)widget_service_destroy_lock(handler->common->widget.lock, 0);
                        handler->common->widget.lock = NULL;
                        _widget_destroy_common_handle(handler->common);
                }
index 48540bd..849ea40 100644 (file)
@@ -285,7 +285,7 @@ extern double widget_viewer_evas_get_period(Evas_Object *widget);
  */
 extern void widget_viewer_evas_cancel_click_event(Evas_Object *widget);
 
-/*
+/**
  * @brief Hides the preview of the widget
  * @remarks This function should be called right after create the widget object before resizing it
  * @since_tizen 2.3.1
index 2e12237..5faae3b 100644 (file)
@@ -34,6 +34,8 @@ extern "C" {
 #define WIDGET_VIEWER_EVAS_SHARED_CONTENT  0x0002          /**< Multiple instances will share the content of one real instance */
 #define WIDGET_VIEWER_EVAS_SUPPORT_GBAR    0x0004          /**< GBAR will be used */
 
+#define WIDGET_VIEWER_EVAS_DISABLE_SCROLLER 0x4000
+
 typedef enum widget_access_result {
     WIDGET_ACCESS_RESULT_DONE = 0x00,
     WIDGET_ACCESS_RESULT_FIRST = 0x01,
@@ -269,6 +271,7 @@ extern int widget_viewer_evas_set_preview_image(Evas_Object *widget, widget_size
  */
 extern int widget_viewer_evas_hide_overlay(Evas_Object *widget);
 
+extern int widget_viewer_evas_hide_faulted_overlay_once(Evas_Object *widget);
 #ifdef __cplusplus
 }
 #endif
index 1bb49b1..37de833 100644 (file)
 #define DEFAULT_CLUSTER "user,created"
 #define DEFAULT_CATEGORY "default"
 
+/**
+ * @note
+ * Supported touch devices are limited to 32.
+ * Because of count of bits of integer type. (32 bits)
+ */
+#define MAX_DEVICE 32
+
+#define IS_PRESSED(info, device)       (((device) < MAX_DEVICE) ? (((info)->pressed & (0x01 << (device))) == (0x01 << (device))) : 0)
+
+/**
+ * @note
+ * Short-Circuit
+ */
+#define SET_PRESSED(info, device)      ((void)(((device) < MAX_DEVICE) && (((info)->pressed |= (0x01 << (device))))))
+#define SET_RELEASED(info, device)     ((void)(((device) < MAX_DEVICE) && (((info)->pressed &= (~(0x01 << (device)))))))
+
 /*!
  * \note
  * Enable this to apply shadow effect to image object (for text widget)
@@ -167,8 +183,9 @@ static struct {
                        unsigned int render_animator:1;
                        unsigned int auto_render_selector:1;
                        unsigned int skip_acquire:1;
+                       unsigned int disable_internal_scroller: 1;
 
-                       unsigned int reserved:18;
+                       unsigned int reserved:17;
                } field;
                unsigned int mask;
        } conf;
@@ -179,6 +196,8 @@ static struct {
        Eina_List *gbar_dirty_objects;
        Eina_List *subscribed_category_list;
        Eina_List *subscribed_group_list;
+       Eina_List *updated_pixmap_list;
+       Eina_List *updated_pixmap_lock_list;
 
        int initialized;
 } s_info = {
@@ -200,6 +219,8 @@ static struct {
        .gbar_dirty_objects = NULL,
        .subscribed_category_list = NULL,
        .subscribed_group_list = NULL,
+       .updated_pixmap_list = NULL,
+       .updated_pixmap_lock_list = NULL,
        .initialized = 0,
 };
 
@@ -278,30 +299,30 @@ struct widget_data {
        int widget_latest_idx; /* -1 = primary buffer, 0 ~ = extra buffer */
        int gbar_latest_idx; /* -1 = primary buffer, 0 ~ = extra buffer */
 
-       struct down {
+       struct _down {
                int x;
                int y;
 
-               struct {
+               struct _geo {
                        int x;
                        int y;
-                       int w;
-                       int h;
                } geo;
+
+               int is_gbar;
        } down;
 
-       int x;
-       int y;
+       int x[MAX_DEVICE];
+       int y[MAX_DEVICE];
 
        int widget_width;
        int widget_height;
        int fixed_width;
        int fixed_height;
        widget_size_type_e size_type;
+       unsigned int pressed;                     /**< Mouse is pressed */
 
        union {
                struct {
-                       unsigned int pressed:1;                     /**< Mouse is pressed */
                        unsigned int touch_effect:1;                /**< Requires to play touch effect */
                        unsigned int mouse_event:1;                 /**< Requires to feed mouse event */
                        unsigned int scroll_x:1;                    /**< */
@@ -338,6 +359,12 @@ struct widget_data {
                        unsigned int extra_info_updated:1;
 
                        unsigned int hide_overlay_manually:1;
+
+                       /**
+                        * @note
+                        * Do not raise up the overlay for faulted.
+                        */
+                       unsigned int hide_faulted_overlay: 1;
                } field;        /* Do we really have the performance loss because of bit fields? */
 
                unsigned int flags;
@@ -1020,86 +1047,173 @@ struct widget_data *widget_unref(struct widget_data *data)
        return NULL;
 }
 
+static void gbar_multi_down_cb(void *cbdata, Evas *e, Evas_Object *obj, void *event_info)
+{
+       Evas_Event_Multi_Down *down = event_info;
+       struct widget_data *data = cbdata;
+       struct widget_mouse_event_info minfo;
+       Evas_Coord x, y, w, h;
+
+       if (data->state != WIDGET_DATA_CREATED) {
+               ErrPrint("Invalid widget data: %p\n", data);
+               return;
+       }
+
+       SET_PRESSED(data, down->device);
+
+       evas_object_geometry_get(obj, &x, &y, &w, &h);
+
+       if (data->size_type != WIDGET_SIZE_TYPE_UNKNOWN && !s_info.conf.field.use_fixed_size) {
+               minfo.ratio_w = (double)data->fixed_width / (double)w;
+               minfo.ratio_h = (double)data->fixed_height / (double)h;
+       } else {
+               minfo.ratio_w = 1.0f;
+               minfo.ratio_h = 1.0f;
+       }
+       minfo.device = down->device;
+
+       if (s_info.conf.field.auto_feed) {
+               minfo.x = (double)x;
+               minfo.y = (double)y;
+               widget_viewer_feed_mouse_event(data->handle, WIDGET_GBAR_MOUSE_SET, &minfo);
+       } else {
+               minfo.x = (double)(down->canvas.x - x);
+               minfo.y = (double)(down->canvas.y - y);
+
+               widget_viewer_feed_mouse_event(data->handle, WIDGET_GBAR_MOUSE_ENTER, &minfo);
+               widget_viewer_feed_mouse_event(data->handle, WIDGET_GBAR_MOUSE_DOWN, &minfo);
+       }
+
+       if (data->is.field.cancel_click == CANCEL_USER) {
+               minfo.x = (double)(down->canvas.x - x);
+               minfo.y = (double)(down->canvas.y - y);
+
+               minfo.device = 0;
+               widget_viewer_feed_mouse_event(data->handle, WIDGET_GBAR_MOUSE_ON_HOLD, &minfo);
+               data->is.field.cancel_click = CANCEL_PROCESSED;
+       }
+}
+
 static void gbar_down_cb(void *cbdata, Evas *e, Evas_Object *obj, void *event_info)
 {
        Evas_Event_Mouse_Down *down = event_info;
        struct widget_data *data = cbdata;
        struct widget_mouse_event_info minfo;
+       Evas_Coord x, y, w, h;
 
        if (data->state != WIDGET_DATA_CREATED) {
                ErrPrint("Invalid widget data: %p\n", data);
                return;
        }
 
-       evas_object_geometry_get(obj, &data->down.geo.x, &data->down.geo.y, &data->down.geo.w, &data->down.geo.h);
+       evas_object_geometry_get(obj, &data->down.geo.x, &data->down.geo.y, &w, &h);
+       x = data->down.geo.x;
+       y = data->down.geo.y;
+       data->down.is_gbar = 1;
 
-       data->x = data->down.x = down->canvas.x;
-       data->y = data->down.y = down->canvas.y;
-       data->is.field.pressed = 1;
+       data->x[0] = data->down.x = down->canvas.x;
+       data->y[0] = data->down.y = down->canvas.y;
+       SET_PRESSED(data, 0);
        if (s_info.conf.field.auto_render_selector) {
                DbgPrint("Change to direct render\n");
                s_info.conf.field.render_animator = 0;
        }
 
+       /**
+        * In case of the GBar,
+        * There is no pre-defined size set.
+        * Every time its size will be notified to the provider app.
+        * So we don't need to handling the scale info of it.
+        */
+       minfo.ratio_w = 1.0f;
+       minfo.ratio_h = 1.0f;
+       minfo.device = 0;
+
        if (s_info.conf.field.auto_feed) {
-               minfo.x = (double)data->down.geo.x;
-               minfo.y = (double)data->down.geo.y;
-               if (s_info.conf.field.use_fixed_size) {
-                       minfo.ratio_w = 1.0f;
-                       minfo.ratio_h = 1.0f;
-               } else {
-                       minfo.ratio_w = (double)data->fixed_width / (double)data->down.geo.w;
-                       minfo.ratio_h = (double)data->fixed_height / (double)data->down.geo.h;
-               }
+               minfo.x = (double)x;
+               minfo.y = (double)y;
                widget_viewer_feed_mouse_event(data->handle, WIDGET_GBAR_MOUSE_SET, &minfo);
        } else {
-               minfo.x = (double)(down->canvas.x - data->down.geo.x);
-               minfo.y = (double)(down->canvas.y - data->down.geo.y);
-
-               if (data->size_type != WIDGET_SIZE_TYPE_UNKNOWN && !s_info.conf.field.use_fixed_size) {
-                       minfo.ratio_w = (double)data->fixed_width / (double)data->down.geo.w;
-                       minfo.ratio_h = (double)data->fixed_height / (double)data->down.geo.h;
-               } else {
-                       minfo.ratio_w = 1.0f;
-                       minfo.ratio_h = 1.0f;
-               }
-
+               minfo.x = (double)(down->canvas.x - x);
+               minfo.y = (double)(down->canvas.y - y);
                widget_viewer_feed_mouse_event(data->handle, WIDGET_GBAR_MOUSE_ENTER, &minfo);
                widget_viewer_feed_mouse_event(data->handle, WIDGET_GBAR_MOUSE_DOWN, &minfo);
        }
 }
 
+static void gbar_multi_move_cb(void *cbdata, Evas *e, Evas_Object *obj, void *event_info)
+{
+       Evas_Event_Multi_Move *move = event_info;
+       struct widget_data *data = cbdata;
+       Evas_Coord x, y, w, h;
+
+       if (data->state != WIDGET_DATA_CREATED) {
+               ErrPrint("Invalid widget data: %p\n", data);
+               return;
+       }
+
+       if (!IS_PRESSED(data, move->device)) {
+               return;
+       }
+
+       evas_object_geometry_get(obj, &x, &y, &w, &h);
+
+       /**
+        * @note
+        * In this case, the ON_HOLD event is already sent.
+        * We don't need to check the cancel_state.
+        */
+       if (!s_info.conf.field.auto_feed) {
+               struct widget_mouse_event_info minfo;
+
+               minfo.x = (double)(move->cur.canvas.x - x);
+               minfo.y = (double)(move->cur.canvas.y - y);
+
+               minfo.ratio_w = 1.0f;
+               minfo.ratio_h = 1.0f;
+               minfo.device = move->device;
+
+               widget_viewer_feed_mouse_event(data->handle, WIDGET_GBAR_MOUSE_MOVE, &minfo);
+
+               if (s_info.conf.field.auto_render_selector) {
+                       DbgPrint("Change to direct render\n");
+                       s_info.conf.field.render_animator = 0;
+               }
+       }
+}
+
 static void gbar_move_cb(void *cbdata, Evas *e, Evas_Object *obj, void *event_info)
 {
        Evas_Event_Mouse_Move *move = event_info;
        struct widget_data *data = cbdata;
        Evas_Coord x, y, w, h;
-       struct widget_mouse_event_info minfo;
 
        if (data->state != WIDGET_DATA_CREATED) {
                ErrPrint("Invalid widget data: %p\n", data);
                return;
        }
 
-       if (!data->is.field.pressed) {
+       if (!IS_PRESSED(data,0)) {
                return;
        }
 
        evas_object_geometry_get(obj, &x, &y, &w, &h);
 
-       data->x = move->cur.canvas.x;
-       data->y = move->cur.canvas.y;
+       data->x[0] = move->cur.canvas.x;
+       data->y[0] = move->cur.canvas.y;
+
+       if (data->is.field.cancel_click == CANCEL_USER || !s_info.conf.field.auto_feed) {
+               struct widget_mouse_event_info minfo;
 
-       if (data->is.field.cancel_click != CANCEL_DISABLED || !s_info.conf.field.auto_feed) {
                minfo.x = (double)(move->cur.canvas.x - x);
                minfo.y = (double)(move->cur.canvas.y - y);
 
-               if (data->size_type != WIDGET_SIZE_TYPE_UNKNOWN && !s_info.conf.field.use_fixed_size) {
-                       minfo.ratio_w = (double)data->fixed_width / (double)w;
-                       minfo.ratio_h = (double)data->fixed_height / (double)h;
-               } else {
-                       minfo.ratio_w = 1.0f;
-                       minfo.ratio_h = 1.0f;
+               minfo.ratio_w = 1.0f;
+               minfo.ratio_h = 1.0f;
+               minfo.device = 0;
+
+               if (!s_info.conf.field.auto_feed) {
+                       widget_viewer_feed_mouse_event(data->handle, WIDGET_GBAR_MOUSE_MOVE, &minfo);
                }
 
                if (data->is.field.cancel_click == CANCEL_USER) {
@@ -1107,10 +1221,6 @@ static void gbar_move_cb(void *cbdata, Evas *e, Evas_Object *obj, void *event_in
                        data->is.field.cancel_click = CANCEL_PROCESSED;
                }
 
-               if (!s_info.conf.field.auto_feed) {
-                       widget_viewer_feed_mouse_event(data->handle, WIDGET_GBAR_MOUSE_MOVE, &minfo);
-               }
-
                if (s_info.conf.field.auto_render_selector) {
                        DbgPrint("Change to direct render\n");
                        s_info.conf.field.render_animator = 0;
@@ -1178,9 +1288,9 @@ static void gbar_pixmap_del_cb(void *cbdata, Evas *e, Evas_Object *obj, void *ev
        }
 }
 
-static void gbar_up_cb(void *cbdata, Evas *e, Evas_Object *obj, void *event_info)
+static void gbar_multi_up_cb(void *cbdata, Evas *e, Evas_Object *obj, void *event_info)
 {
-       Evas_Event_Mouse_Up *up = event_info;
+       Evas_Event_Multi_Up *up = event_info;
        struct widget_data *data = cbdata;
        Evas_Coord x, y, w, h;
        struct widget_mouse_event_info minfo;
@@ -1190,12 +1300,18 @@ static void gbar_up_cb(void *cbdata, Evas *e, Evas_Object *obj, void *event_info
                return;
        }
 
-       if (!data->is.field.pressed) {
+       if (!IS_PRESSED(data, up->device)) {
                return;
        }
 
+       SET_RELEASED(data, up->device);
+
        evas_object_geometry_get(obj, &x, &y, &w, &h);
 
+       minfo.ratio_w = 1.0f;
+       minfo.ratio_h = 1.0f;
+       minfo.device = up->device;
+
        if (s_info.conf.field.auto_feed) {
                /**
                 * @note
@@ -1205,43 +1321,172 @@ static void gbar_up_cb(void *cbdata, Evas *e, Evas_Object *obj, void *event_info
                minfo.x = (double)up->canvas.x;
                minfo.y = (double)up->canvas.y;
 
-               if (data->size_type != WIDGET_SIZE_TYPE_UNKNOWN && !s_info.conf.field.use_fixed_size) {
-                       minfo.ratio_w = (double)data->fixed_width / (double)w;
-                       minfo.ratio_h = (double)data->fixed_height / (double)h;
-               } else {
-                       minfo.ratio_w = 1.0f;
-                       minfo.ratio_h = 1.0f;
+               widget_viewer_feed_mouse_event(data->handle, WIDGET_GBAR_MOUSE_UNSET, &minfo);
+       } else {
+               minfo.x = (double)(up->canvas.x - x);
+               minfo.y = (double)(up->canvas.y - y);
+
+               widget_viewer_feed_mouse_event(data->handle, WIDGET_GBAR_MOUSE_UP, &minfo);
+               widget_viewer_feed_mouse_event(data->handle, WIDGET_GBAR_MOUSE_LEAVE, &minfo);
+       }
+}
+
+static void gbar_up_cb(void *cbdata, Evas *e, Evas_Object *obj, void *event_info)
+{
+       Evas_Event_Mouse_Up *up = event_info;
+       struct widget_data *data = cbdata;
+       Evas_Coord x, y, w, h;
+       struct widget_mouse_event_info minfo;
+
+       if (data->state != WIDGET_DATA_CREATED) {
+               ErrPrint("Invalid widget data: %p\n", data);
+               return;
+       }
+
+       if (!IS_PRESSED(data, 0)) {
+               return;
+       }
+
+       SET_RELEASED(data, 0);
+
+       evas_object_geometry_get(obj, &x, &y, &w, &h);
+
+       minfo.ratio_w = 1.0f;
+       minfo.ratio_h = 1.0f;
+       minfo.device = 0;
+
+       /**
+        * @note
+        * If the object is moved, we should send ON_HOLD event.
+        */
+       if (data->down.geo.x != x || data->down.geo.y != y || data->is.field.cancel_click == CANCEL_USER) {
+               if (data->is.field.cancel_click != CANCEL_PROCESSED) {
+                       minfo.x = (double)(up->canvas.x - x);
+                       minfo.y = (double)(up->canvas.y - y);
+                       widget_viewer_feed_mouse_event(data->handle, WIDGET_GBAR_MOUSE_ON_HOLD, &minfo);
+                       data->is.field.cancel_click = CANCEL_PROCESSED;
                }
+       }
+
+       if (s_info.conf.field.auto_feed) {
+               /**
+                * @note
+                * UNSET will subtract object.x and object.y by master
+                * so we just send original touch position based on screen
+                */
+               minfo.x = (double)up->canvas.x;
+               minfo.y = (double)up->canvas.y;
 
                widget_viewer_feed_mouse_event(data->handle, WIDGET_GBAR_MOUSE_UNSET, &minfo);
        } else {
                minfo.x = (double)(up->canvas.x - x);
                minfo.y = (double)(up->canvas.y - y);
 
-               if (data->size_type != WIDGET_SIZE_TYPE_UNKNOWN && !s_info.conf.field.use_fixed_size) {
+               widget_viewer_feed_mouse_event(data->handle, WIDGET_GBAR_MOUSE_UP, &minfo);
+               widget_viewer_feed_mouse_event(data->handle, WIDGET_GBAR_MOUSE_LEAVE, &minfo);
+       }
+
+       data->is.field.cancel_click = CANCEL_DISABLED;
+}
+
+static void smart_callback_call(struct widget_data *data, const char *signal, void *cbdata)
+{
+       if (data->is.field.deleted || !data->widget) {
+               DbgPrint("widget is deleted, ignore smart callback call\n");
+               return;
+       }
+
+       evas_object_smart_callback_call(data->widget, signal, cbdata);
+}
+
+static void __widget_multi_down_cb(void *cbdata, Evas *e, Evas_Object *obj, void *event_info)
+{
+       Evas_Event_Multi_Down *down = event_info;
+       struct widget_data *data = cbdata;
+       Evas_Coord x, y, w, h;
+
+       if (data->state != WIDGET_DATA_CREATED) {
+               ErrPrint("Invalid widget data: %p\n", data);
+               return;
+       }
+
+       data->x[down->device] = down->canvas.x;
+       data->y[down->device] = down->canvas.y;
+
+       evas_object_geometry_get(obj, &x, &y, &w, &h);
+
+       /**
+        * @note
+        * If the multi-touch started,
+        * GBar will not be created.
+        */
+       if (s_info.conf.field.support_gbar && data->is.field.flick_down) {
+               struct widget_evas_event_info info;
+
+               DbgPrint("Flick down is canceled\n");
+               data->is.field.flick_down = 0;
+               info.widget_app_id = data->widget_id;
+               info.event = WIDGET_EVENT_GBAR_CREATED;
+               info.error = WIDGET_ERROR_CANCELED;
+
+               smart_callback_call(data, WIDGET_SMART_SIGNAL_FLICKDOWN_CANCELLED, &info);
+       }
+
+       if (s_info.conf.field.auto_render_selector) {
+               DbgPrint("Change to direct render\n");
+               s_info.conf.field.render_animator = 0;
+       }
+
+       SET_PRESSED(data, down->device);
+
+       if (data->handle && !data->is.field.faulted) {
+               struct widget_mouse_event_info minfo;
+
+               if (!s_info.conf.field.use_fixed_size) {
                        minfo.ratio_w = (double)data->fixed_width / (double)w;
                        minfo.ratio_h = (double)data->fixed_height / (double)h;
                } else {
                        minfo.ratio_w = 1.0f;
                        minfo.ratio_h = 1.0f;
                }
+               minfo.device = down->device;
 
-               if (data->down.geo.x != x || data->down.geo.y != y || data->is.field.cancel_click == CANCEL_USER) {
-                       widget_viewer_feed_mouse_event(data->handle, WIDGET_GBAR_MOUSE_ON_HOLD, &minfo);
-                       data->is.field.cancel_click = CANCEL_PROCESSED;
+               if (s_info.conf.field.auto_feed && data->is.field.mouse_event) {
+                       minfo.x = (double)data->down.geo.x;
+                       minfo.y = (double)data->down.geo.y;
+                       DbgPrint("[%d] %lfx%lf (%lfx%lf), %dx%d %dx%d\n", minfo.device, minfo.x, minfo.y, minfo.ratio_w, minfo.ratio_h, data->fixed_width, data->fixed_height, w, h);
+                       widget_viewer_feed_mouse_event(data->handle, WIDGET_MOUSE_SET, &minfo);
+               } else {
+                       minfo.x = (double)(data->x[down->device] - x);
+                       minfo.y = (double)(data->y[down->device] - y);
+
+                       DbgPrint("[%d] %lfx%lf (%lfx%lf)\n", minfo.device, minfo.x, minfo.y, minfo.ratio_w, minfo.ratio_h);
+
+                       widget_viewer_feed_mouse_event(data->handle, WIDGET_MOUSE_ENTER, &minfo);
+                       widget_viewer_feed_mouse_event(data->handle, WIDGET_MOUSE_DOWN, &minfo);
+                       widget_viewer_feed_mouse_event(data->handle, WIDGET_MOUSE_MOVE, &minfo);
                }
 
-               widget_viewer_feed_mouse_event(data->handle, WIDGET_GBAR_MOUSE_UP, &minfo);
-               widget_viewer_feed_mouse_event(data->handle, WIDGET_GBAR_MOUSE_LEAVE, &minfo);
+               /**
+                * @note
+                * Send the ON_HOLD event if the multi-touch events are triggered.
+                */
+               if (data->is.field.cancel_click != CANCEL_PROCESSED) {
+                       DbgPrint("ON_HOLD send\n");
+                       minfo.x = (double)(data->x[0] - x);
+                       minfo.y = (double)(data->y[0] - y);
+                       minfo.device = 0;
+                       widget_viewer_feed_mouse_event(data->handle, WIDGET_MOUSE_ON_HOLD, &minfo);
+                       data->is.field.cancel_click = CANCEL_PROCESSED;
+               }
        }
-
-       data->is.field.cancel_click = CANCEL_DISABLED;
 }
 
 static void __widget_down_cb(void *cbdata, Evas *e, Evas_Object *obj, void *event_info)
 {
        Evas_Event_Mouse_Down *down = event_info;
        struct widget_data *data = cbdata;
+       Evas_Coord x, y, w, h;
 
        if (data->state != WIDGET_DATA_CREATED) {
                ErrPrint("Invalid widget data: %p\n", data);
@@ -1252,9 +1497,9 @@ static void __widget_down_cb(void *cbdata, Evas *e, Evas_Object *obj, void *even
                data->is.field.flick_down = 1;
        }
 
-       data->down.x = data->x = down->canvas.x;
-       data->down.y = data->y = down->canvas.y;
-       data->is.field.pressed = 1;
+       data->down.x = data->x[0] = down->canvas.x;
+       data->down.y = data->y[0] = down->canvas.y;
+       data->down.is_gbar = 0;
        data->is.field.scroll_x = 0;
        data->is.field.scroll_y = 0;
        data->is.field.cancel_scroll_x = 0;
@@ -1265,10 +1510,12 @@ static void __widget_down_cb(void *cbdata, Evas *e, Evas_Object *obj, void *even
                s_info.conf.field.render_animator = 0;
        }
 
-       evas_object_geometry_get(obj, &data->down.geo.x, &data->down.geo.y, &data->down.geo.w, &data->down.geo.h);
+       evas_object_geometry_get(obj, &data->down.geo.x, &data->down.geo.y, &w, &h);
+       x = data->down.geo.x;
+       y = data->down.geo.y;
 
        if (s_info.conf.field.sensitive_move && (data->down.geo.x != data->view_port.x || data->down.geo.y != data->view_port.y)) {
-               data->is.field.pressed = 0;
+               SET_RELEASED(data, 0);
                if (s_info.conf.field.auto_render_selector) {
                        DbgPrint("Change to render animator\n");
                        s_info.conf.field.render_animator = 1;
@@ -1276,32 +1523,29 @@ static void __widget_down_cb(void *cbdata, Evas *e, Evas_Object *obj, void *even
                return;
        }
 
+       SET_PRESSED(data, 0);
+
        if (data->handle && !data->is.field.faulted) {
                struct widget_mouse_event_info minfo;
 
+               if (!s_info.conf.field.use_fixed_size) {
+                       minfo.ratio_w = (double)data->fixed_width / (double)w;
+                       minfo.ratio_h = (double)data->fixed_height / (double)h;
+               } else {
+                       minfo.ratio_w = 1.0f;
+                       minfo.ratio_h = 1.0f;
+               }
+               minfo.device = 0;
+
                if (s_info.conf.field.auto_feed && data->is.field.mouse_event) {
-                       minfo.x = (double)data->down.geo.x;
-                       minfo.y = (double)data->down.geo.y;
-                       if (!s_info.conf.field.use_fixed_size) {
-                               minfo.ratio_w = (double)data->fixed_width / (double)data->down.geo.w;
-                               minfo.ratio_h = (double)data->fixed_height / (double)data->down.geo.h;
-                       } else {
-                               minfo.ratio_w = 1.0f;
-                               minfo.ratio_h = 1.0f;
-                       }
-                       DbgPrint("%lfx%lf (%lfx%lf), %dx%d %dx%d\n", minfo.x, minfo.y, minfo.ratio_w, minfo.ratio_h, data->fixed_width, data->fixed_height, data->down.geo.w, data->down.geo.h);
+                       minfo.x = (double)x;
+                       minfo.y = (double)y;
+                       DbgPrint("%lfx%lf (%lfx%lf), %dx%d %dx%d\n", minfo.x, minfo.y, minfo.ratio_w, minfo.ratio_h, data->fixed_width, data->fixed_height, w, h);
                        widget_viewer_feed_mouse_event(data->handle, WIDGET_MOUSE_SET, &minfo);
                } else {
-                       minfo.x = (double)(data->x - data->down.geo.x);
-                       minfo.y = (double)(data->y - data->down.geo.y);
+                       minfo.x = (double)(data->x[0] - x);
+                       minfo.y = (double)(data->y[0] - y);
 
-                       if (data->size_type != WIDGET_SIZE_TYPE_UNKNOWN && !s_info.conf.field.use_fixed_size) {
-                               minfo.ratio_w = (double)data->fixed_width / (double)data->down.geo.w;
-                               minfo.ratio_h = (double)data->fixed_height / (double)data->down.geo.h;
-                       } else {
-                               minfo.ratio_w = 1.0f;
-                               minfo.ratio_h = 1.0f;
-                       }
                        DbgPrint("%lfx%lf (%lfx%lf)\n", minfo.x, minfo.y, minfo.ratio_w, minfo.ratio_h);
 
                        widget_viewer_feed_mouse_event(data->handle, WIDGET_MOUSE_ENTER, &minfo);
@@ -1311,16 +1555,6 @@ static void __widget_down_cb(void *cbdata, Evas *e, Evas_Object *obj, void *even
        }
 }
 
-static void smart_callback_call(struct widget_data *data, const char *signal, void *cbdata)
-{
-       if (data->is.field.deleted || !data->widget) {
-               DbgPrint("widget is deleted, ignore smart callback call\n");
-               return;
-       }
-
-       evas_object_smart_callback_call(data->widget, signal, cbdata);
-}
-
 static void __widget_destroy_gbar_cb(struct widget *handle, int ret, void *cbdata)
 {
        struct widget_data *data = cbdata;
@@ -2559,6 +2793,11 @@ static void gbar_create_pixmap_object(struct widget_data *data)
                evas_object_event_callback_add(gbar_content, EVAS_CALLBACK_MOUSE_DOWN, gbar_down_cb, data);
                evas_object_event_callback_add(gbar_content, EVAS_CALLBACK_MOUSE_MOVE, gbar_move_cb, data);
                evas_object_event_callback_add(gbar_content, EVAS_CALLBACK_MOUSE_UP, gbar_up_cb, data);
+
+               evas_object_event_callback_add(gbar_content, EVAS_CALLBACK_MULTI_DOWN, gbar_multi_down_cb, data);
+               evas_object_event_callback_add(gbar_content, EVAS_CALLBACK_MULTI_MOVE, gbar_multi_move_cb, data);
+               evas_object_event_callback_add(gbar_content, EVAS_CALLBACK_MULTI_UP, gbar_multi_up_cb, data);
+
                evas_object_event_callback_add(gbar_content, EVAS_CALLBACK_DEL, gbar_pixmap_del_cb, data);
        }
 }
@@ -2725,6 +2964,70 @@ static void update_scroll_flag(struct widget_data *data, int x, int y)
        data->is.field.scroll_y = !data->is.field.cancel_scroll_y && data->is.field.scroll_y;
 }
 
+static void __widget_multi_up_cb(void *cbdata, Evas *e, Evas_Object *obj, void *event_info)
+{
+       Evas_Event_Multi_Up *up = event_info;
+       struct widget_data *data = cbdata;
+       Evas_Coord x, y, w, h;
+
+       if (data->state != WIDGET_DATA_CREATED) {
+               ErrPrint("Invalid widget data: %p\n", data);
+               return;
+       }
+
+       if (s_info.conf.field.auto_render_selector) {
+               DbgPrint("Change to render animator\n");
+               s_info.conf.field.render_animator = 1;
+       }
+
+       if (!IS_PRESSED(data, up->device)) {
+               return;
+       }
+
+       SET_RELEASED(data, up->device);
+
+       if (data->handle && !data->is.field.faulted) {
+               struct widget_mouse_event_info minfo;
+
+               data->x[up->device] = up->canvas.x;
+               data->y[up->device] = up->canvas.y;
+
+               evas_object_geometry_get(data->widget, &x, &y, &w, &h);
+
+               if (data->size_type != WIDGET_SIZE_TYPE_UNKNOWN && !s_info.conf.field.use_fixed_size) {
+                       minfo.ratio_w = (double)data->fixed_width / (double)w;
+                       minfo.ratio_h = (double)data->fixed_height / (double)h;
+                       DbgPrint("Width: %d/%d - Height: %d/%d\n", data->fixed_width, w, data->fixed_height, h);
+               } else {
+                       minfo.ratio_w = 1.0f;
+                       minfo.ratio_h = 1.0f;
+               }
+               DbgPrint("Ratio: %lfx%lf\n", minfo.ratio_w, minfo.ratio_h);
+               minfo.device = up->device;
+
+               if (s_info.conf.field.auto_feed && data->is.field.mouse_event) {
+                       /**
+                        * @note
+                        * UNSET will subtract object.x and object.y by master
+                        * so we just send original touch position based on screen
+                        */
+                       minfo.x = (double)data->x[up->device];
+                       minfo.y = (double)data->y[up->device];
+                       DbgPrint("X,Y = %lfx%lf\n", minfo.x, minfo.y);
+
+                       widget_viewer_feed_mouse_event(data->handle, WIDGET_MOUSE_UNSET, &minfo);
+               } else {
+                       /* We have to keep the first position of touch down */
+                       minfo.x = (double)(data->x[up->device] - x);
+                       minfo.y = (double)(data->y[up->device] - y);
+
+                       DbgPrint("%lfx%lf (%lfx%lf)\n", minfo.x, minfo.y, minfo.ratio_w, minfo.ratio_h);
+                       widget_viewer_feed_mouse_event(data->handle, WIDGET_MOUSE_UP, &minfo);
+                       widget_viewer_feed_mouse_event(data->handle, WIDGET_MOUSE_LEAVE, &minfo);
+               }
+       }
+}
+
 static void __widget_up_cb(void *cbdata, Evas *e, Evas_Object *obj, void *event_info)
 {
        Evas_Event_Mouse_Up *up = event_info;
@@ -2739,15 +3042,15 @@ static void __widget_up_cb(void *cbdata, Evas *e, Evas_Object *obj, void *event_
                return;
        }
 
-       if (!data->is.field.pressed) {
+       if (!IS_PRESSED(data, 0)) {
                return;
        }
 
        update_scroll_flag(data, up->canvas.x, up->canvas.y);
 
-       data->x = up->canvas.x;
-       data->y = up->canvas.y;
-       data->is.field.pressed = 0;
+       data->x[0] = up->canvas.x;
+       data->y[0] = up->canvas.y;
+       SET_RELEASED(data, 0);
 
        if (s_info.conf.field.auto_render_selector) {
                DbgPrint("Change to render animator\n");
@@ -2757,14 +3060,14 @@ static void __widget_up_cb(void *cbdata, Evas *e, Evas_Object *obj, void *event_
        info.widget_app_id = data->widget_id;
        info.event = WIDGET_EVENT_GBAR_CREATED;
 
-       if (s_info.conf.field.support_gbar && data->is.field.flick_down && data->y - data->down.y < CLICK_REGION) {
+       if (s_info.conf.field.support_gbar && data->is.field.flick_down && (data->y[0] - data->down.y) < CLICK_REGION) {
                DbgPrint("Flick down is canceled\n");
                data->is.field.flick_down = 0;
                info.error = WIDGET_ERROR_CANCELED;
                smart_callback_call(data, WIDGET_SMART_SIGNAL_FLICKDOWN_CANCELLED, &info);
        }
 
-       evas_object_geometry_get(data->widget, &x, &y, &w, &h);
+       evas_object_geometry_get(obj, &x, &y, &w, &h);
 
        if (data->is.field.flick_down) {
                data->is.field.flick_down = 0;
@@ -2841,9 +3144,6 @@ static void __widget_up_cb(void *cbdata, Evas *e, Evas_Object *obj, void *event_
        if (data->handle && !data->is.field.faulted) {
                struct widget_mouse_event_info minfo;
 
-               minfo.x = (double)(data->x - x);
-               minfo.y = (double)(data->y - y);
-
                if (data->size_type != WIDGET_SIZE_TYPE_UNKNOWN && !s_info.conf.field.use_fixed_size) {
                        minfo.ratio_w = (double)data->fixed_width / (double)w;
                        minfo.ratio_h = (double)data->fixed_height / (double)h;
@@ -2851,97 +3151,107 @@ static void __widget_up_cb(void *cbdata, Evas *e, Evas_Object *obj, void *event_
                        minfo.ratio_w = 1.0f;
                        minfo.ratio_h = 1.0f;
                }
-
-               evas_object_geometry_get(obj, &x, &y, NULL, NULL);
+               minfo.device = 0;
 
                reset_scroller(data);
 
-               if (s_info.conf.field.auto_feed && data->is.field.mouse_event) {
-                       struct widget_mouse_event_info _minfo;
-
-                       if (data->down.geo.x != x || data->down.geo.y != y || data->is.field.scroll_x || data->is.field.scroll_y || data->is.field.cancel_click == CANCEL_USER) {
-                               widget_viewer_feed_mouse_event(data->handle, WIDGET_MOUSE_ON_HOLD, &minfo);
-                               data->is.field.cancel_click = CANCEL_PROCESSED;
-                       } else if ((up->event_flags & EVAS_EVENT_FLAG_ON_HOLD) == EVAS_EVENT_FLAG_ON_HOLD) {
+               if (data->is.field.cancel_click != CANCEL_PROCESSED) {
+                       if (data->down.geo.x != x || data->down.geo.y != y ||
+                               data->is.field.scroll_x || data->is.field.scroll_y ||
+                               data->is.field.cancel_click == CANCEL_USER ||
+                               (!data->is.field.mouse_event && (abs(data->x[0] - data->down.x) > CLICK_REGION || abs(data->y[0] - data->down.y) > CLICK_REGION)) ||
+                               (up->event_flags & EVAS_EVENT_FLAG_ON_HOLD) == EVAS_EVENT_FLAG_ON_HOLD)
+                       {
+                               minfo.x = (double)(data->x[0] - x);
+                               minfo.y = (double)(data->y[0] - y);
                                widget_viewer_feed_mouse_event(data->handle, WIDGET_MOUSE_ON_HOLD, &minfo);
                                data->is.field.cancel_click = CANCEL_PROCESSED;
                        }
+               }
 
+               if (s_info.conf.field.auto_feed && data->is.field.mouse_event) {
                        /**
                         * @note
                         * UNSET will subtract object.x and object.y by master
                         * so we just send original touch position based on screen
                         */
-                       _minfo.x = (double)up->canvas.x;
-                       _minfo.y = (double)up->canvas.y;
-                       DbgPrint("X,Y = %lfx%lf\n", _minfo.x, _minfo.y);
-
-                       if (data->size_type != WIDGET_SIZE_TYPE_UNKNOWN && !s_info.conf.field.use_fixed_size) {
-                               _minfo.ratio_w = (double)data->fixed_width / (double)data->down.geo.w;
-                               _minfo.ratio_h = (double)data->fixed_height / (double)data->down.geo.h;
-                               DbgPrint("Width: %d/%d - Height: %d/%d\n", data->fixed_width, data->down.geo.w, data->fixed_height, data->down.geo.h);
-                               DbgPrint("Ratio: %lfx%lf\n", _minfo.ratio_w, _minfo.ratio_h);
-                       } else {
-                               _minfo.ratio_w = 1.0f;
-                               _minfo.ratio_h = 1.0f;
-                               DbgPrint("UNKNOWN Ratio: %lfx%lf\n", minfo.ratio_w, minfo.ratio_h);
-                       }
-
-                       widget_viewer_feed_mouse_event(data->handle, WIDGET_MOUSE_UNSET, &_minfo);
+                       minfo.x = (double)data->x[0];
+                       minfo.y = (double)data->y[0];
+                       DbgPrint("X,Y = %lfx%lf\n", minfo.x, minfo.y);
+                       widget_viewer_feed_mouse_event(data->handle, WIDGET_MOUSE_UNSET, &minfo);
                } else {
-                       if (!data->is.field.mouse_event) {
-                               /* We have to keep the first position of touch down */
-                               minfo.x = (double)(data->down.x - x);
-                               minfo.y = (double)(data->down.y - y);
-
-                               if (data->size_type != WIDGET_SIZE_TYPE_UNKNOWN && !s_info.conf.field.use_fixed_size) {
-                                       minfo.ratio_w = (double)data->fixed_width / (double)w;
-                                       minfo.ratio_h = (double)data->fixed_height / (double)h;
-                               } else {
-                                       minfo.ratio_w = 1.0f;
-                                       minfo.ratio_h = 1.0f;
-                               }
+                       minfo.x = (double)(data->x[0] - x);
+                       minfo.y = (double)(data->y[0] - y);
 
-                               if (data->down.geo.x != x || data->down.geo.y != y || data->is.field.scroll_x || data->is.field.scroll_y || data->is.field.cancel_click == CANCEL_USER || abs(data->x - data->down.x) > CLICK_REGION || abs(data->y - data->down.y) > CLICK_REGION) {
-                                       widget_viewer_feed_mouse_event(data->handle, WIDGET_MOUSE_ON_HOLD, &minfo);
-                                       data->is.field.cancel_click = CANCEL_PROCESSED;
-                               } else if ((up->event_flags & EVAS_EVENT_FLAG_ON_HOLD) == EVAS_EVENT_FLAG_ON_HOLD) {
-                                       widget_viewer_feed_mouse_event(data->handle, WIDGET_MOUSE_ON_HOLD, &minfo);
-                                       data->is.field.cancel_click = CANCEL_PROCESSED;
-                               }
-                       } else {
-                               if (data->down.geo.x != x || data->down.geo.y != y || data->is.field.scroll_x || data->is.field.scroll_y || data->is.field.cancel_click == CANCEL_USER) {
-                                       widget_viewer_feed_mouse_event(data->handle, WIDGET_MOUSE_ON_HOLD, &minfo);
-                                       data->is.field.cancel_click = CANCEL_PROCESSED;
-                               } else if ((up->event_flags & EVAS_EVENT_FLAG_ON_HOLD) == EVAS_EVENT_FLAG_ON_HOLD) {
-                                       widget_viewer_feed_mouse_event(data->handle, WIDGET_MOUSE_ON_HOLD, &minfo);
-                                       data->is.field.cancel_click = CANCEL_PROCESSED;
+                       DbgPrint("%lfx%lf (%lfx%lf)\n", minfo.x, minfo.y, minfo.ratio_w, minfo.ratio_h);
+                       widget_viewer_feed_mouse_event(data->handle, WIDGET_MOUSE_UP, &minfo);
+                       widget_viewer_feed_mouse_event(data->handle, WIDGET_MOUSE_LEAVE, &minfo);
+               }
+
+               if (!data->is.field.flick_down) {
+                       ret = WIDGET_ERROR_INVALID_PARAMETER;
+                       if (data->is.field.gbar_created) {
+                               ret = widget_viewer_destroy_glance_bar(data->handle, __widget_destroy_gbar_cb, widget_ref(data));
+                               if (ret < 0) {
+                                       data = widget_unref(data);
                                }
+                       } else if (data->is.field.cancel_click == CANCEL_DISABLED) {
+                               ret = widget_viewer_send_click_event(data->handle, WIDGET_VIEWER_CLICK_BUTTON_LEFT, minfo.x, minfo.y);
                        }
+               }
+
+               if (data) {
+                       DbgPrint("Up: %lfx%lf [x:%d/%d/%d] [y:%d/%d/%d], ret: 0x%X, cancel: 0x%x\n",
+                                       minfo.x, minfo.y,
+                                       data->is.field.scroll_x, s_info.conf.field.is_scroll_x, data->is.field.cancel_scroll_x,
+                                       data->is.field.scroll_y, s_info.conf.field.is_scroll_y, data->is.field.cancel_scroll_y,
+                                       ret, data->is.field.cancel_click);
+                       data->is.field.cancel_click = CANCEL_DISABLED;
+               }
+       }
+}
+
+static void __widget_multi_move_cb(void *cbdata, Evas *e, Evas_Object *obj, void *event_info)
+{
+       Evas_Event_Multi_Move *move = event_info;
+       struct widget_data *data = cbdata;
+
+       if (data->state != WIDGET_DATA_CREATED) {
+               ErrPrint("Invalid widget data: %p\n", data);
+               return;
+       }
+
+       if (!IS_PRESSED(data, move->device)) {
+               return;
+       }
+
+       data->x[move->device] = move->cur.canvas.x;
+       data->y[move->device] = move->cur.canvas.y;
+
+       if (data->handle && !data->is.field.faulted) {
+               if (!s_info.conf.field.auto_feed && data->is.field.mouse_event) {
+                       struct widget_mouse_event_info minfo;
+                       Evas_Coord x, y, w, h;
+
+                       evas_object_geometry_get(obj, &x, &y, &w, &h);
 
-                       DbgPrint("%lfx%lf (%lfx%lf)\n", minfo.x, minfo.y, minfo.ratio_w, minfo.ratio_h);
-                       widget_viewer_feed_mouse_event(data->handle, WIDGET_MOUSE_UP, &minfo);
-                       widget_viewer_feed_mouse_event(data->handle, WIDGET_MOUSE_LEAVE, &minfo);
-               }
+                       minfo.x = (double)(data->x[move->device] - x);
+                       minfo.y = (double)(data->y[move->device] - y);
 
-               if (!data->is.field.flick_down) {
-                       ret = WIDGET_ERROR_INVALID_PARAMETER;
-                       if (data->is.field.gbar_created) {
-                               ret = widget_viewer_destroy_glance_bar(data->handle, __widget_destroy_gbar_cb, widget_ref(data));
-                               if (ret < 0)
-                                       data = widget_unref(data);
-                       } else if (data->is.field.cancel_click == CANCEL_DISABLED) {
-                               ret = widget_viewer_send_click_event(data->handle, minfo.x, minfo.y);
+                       if (data->size_type != WIDGET_SIZE_TYPE_UNKNOWN && !s_info.conf.field.use_fixed_size) {
+                               minfo.ratio_w = (double)data->fixed_width / (double)w;
+                               minfo.ratio_h = (double)data->fixed_height / (double)h;
+                       } else {
+                               minfo.ratio_w = 1.0f;
+                               minfo.ratio_h = 1.0f;
                        }
-               }
+                       minfo.device = move->device;
 
-               if (data) {
-                       DbgPrint("Up: %lfx%lf [x:%d/%d/%d] [y:%d/%d/%d], ret: 0x%X, cancel: 0x%x\n",
-                                       minfo.x, minfo.y,
-                                       data->is.field.scroll_x, s_info.conf.field.is_scroll_x, data->is.field.cancel_scroll_x,
-                                       data->is.field.scroll_y, s_info.conf.field.is_scroll_y, data->is.field.cancel_scroll_y,
-                                       ret, data->is.field.cancel_click);
-                       data->is.field.cancel_click = CANCEL_DISABLED;
+                       widget_viewer_feed_mouse_event(data->handle, WIDGET_MOUSE_MOVE, &minfo);
+               }
+       } else {
+               if (s_info.conf.field.auto_render_selector) {
+                       s_info.conf.field.render_animator = 1;
                }
        }
 }
@@ -2956,11 +3266,11 @@ static void __widget_move_cb(void *cbdata, Evas *e, Evas_Object *obj, void *even
                return;
        }
 
-       if (!data->is.field.pressed) {
+       if (!IS_PRESSED(data, 0)) {
                return;
        }
 
-       if (s_info.conf.field.support_gbar && data->is.field.flick_down && data->y - move->cur.canvas.y > 0) {
+       if (s_info.conf.field.support_gbar && data->is.field.flick_down && data->y[0] - move->cur.canvas.y > 0) {
                struct widget_evas_event_info info;
 
                DbgPrint("Flick down is canceled\n");
@@ -2974,27 +3284,29 @@ static void __widget_move_cb(void *cbdata, Evas *e, Evas_Object *obj, void *even
 
        update_scroll_flag(data, move->cur.canvas.x, move->cur.canvas.y);
 
-       data->x = move->cur.canvas.x;
-       data->y = move->cur.canvas.y;
+       data->x[0] = move->cur.canvas.x;
+       data->y[0] = move->cur.canvas.y;
 
        if (data->handle && !data->is.field.faulted) {
-               if (data->is.field.cancel_click == CANCEL_USER) {
-                       struct widget_mouse_event_info minfo;
-                       Evas_Coord x, y, w, h;
+               Evas_Coord x, y, w, h;
+               struct widget_mouse_event_info minfo;
+               int need_move_event = 0;
 
-                       evas_object_geometry_get(obj, &x, &y, &w, &h);
+               evas_object_geometry_get(obj, &x, &y, &w, &h);
 
-                       minfo.x = (double)(data->x - x);
-                       minfo.y = (double)(data->y - y);
+               if (data->size_type != WIDGET_SIZE_TYPE_UNKNOWN && !s_info.conf.field.use_fixed_size) {
+                       minfo.ratio_w = (double)data->fixed_width / (double)w;
+                       minfo.ratio_h = (double)data->fixed_height / (double)h;
+               } else {
+                       minfo.ratio_w = 1.0f;
+                       minfo.ratio_h = 1.0f;
+               }
+               minfo.device = 0;
 
-                       if (data->size_type != WIDGET_SIZE_TYPE_UNKNOWN && !s_info.conf.field.use_fixed_size) {
-                               minfo.ratio_w = (double)data->fixed_width / (double)w;
-                               minfo.ratio_h = (double)data->fixed_height / (double)h;
-                       } else {
-                               minfo.ratio_w = 1.0f;
-                               minfo.ratio_h = 1.0f;
-                       }
+               if (data->is.field.cancel_click == CANCEL_USER) {
 
+                       minfo.x = (double)(data->x[0] - x);
+                       minfo.y = (double)(data->y[0] - y);
                        widget_viewer_feed_mouse_event(data->handle, WIDGET_MOUSE_ON_HOLD, &minfo);
 
                        /*
@@ -3006,29 +3318,22 @@ static void __widget_move_cb(void *cbdata, Evas *e, Evas_Object *obj, void *even
                                DbgPrint("Change to render animator\n");
                                s_info.conf.field.render_animator = 1;
                        }
-               }
-
-               if (!s_info.conf.field.auto_feed) {
-                       struct widget_mouse_event_info minfo;
-                       Evas_Coord x, y, w, h;
-
-                       evas_object_geometry_get(obj, &x, &y, &w, &h);
 
-                       minfo.x = (double)(data->x - x);
-                       minfo.y = (double)(data->y - y);
+                       /**
+                        * @note
+                        * After ON_HOLD, we should send one MOVE event.
+                        */
+                       need_move_event = 1;
+               }
 
-                       if (data->size_type != WIDGET_SIZE_TYPE_UNKNOWN && !s_info.conf.field.use_fixed_size) {
-                               minfo.ratio_w = (double)data->fixed_width / (double)w;
-                               minfo.ratio_h = (double)data->fixed_height / (double)h;
-                       } else {
-                               minfo.ratio_w = 1.0f;
-                               minfo.ratio_h = 1.0f;
-                       }
+               if (!s_info.conf.field.auto_feed && (need_move_event || data->is.field.mouse_event)) {
+                       minfo.x = (double)(data->x[0] - x);
+                       minfo.y = (double)(data->y[0] - y);
 
                        widget_viewer_feed_mouse_event(data->handle, WIDGET_MOUSE_MOVE, &minfo);
                }
 
-               if (s_info.conf.field.support_gbar && data->is.field.flick_down && abs(data->y - data->down.y) > CLICK_REGION) {
+               if (s_info.conf.field.support_gbar && data->is.field.flick_down && abs(data->y[0] - data->down.y) > CLICK_REGION) {
                        struct widget_evas_event_info info;
                        data->is.field.flick_down = 0;
                        info.widget_app_id = data->widget_id;
@@ -3255,7 +3560,7 @@ static void __widget_data_setup(struct widget_data *data)
                return;
        }
 
-       if (s_info.conf.field.is_scroll_x || s_info.conf.field.is_scroll_y) {
+       if (!s_info.conf.field.disable_internal_scroller && (s_info.conf.field.is_scroll_x || s_info.conf.field.is_scroll_y)) {
                Evas_Object *scroller;
                scroller = elm_scroller_add(data->parent);
                if (scroller) {
@@ -3302,6 +3607,10 @@ static void __widget_data_setup(struct widget_data *data)
        evas_object_event_callback_add(data->widget_layout, EVAS_CALLBACK_MOUSE_MOVE, __widget_move_cb, data);
        evas_object_event_callback_add(data->widget_layout, EVAS_CALLBACK_MOUSE_UP, __widget_up_cb, data);
 
+       evas_object_event_callback_add(data->widget_layout, EVAS_CALLBACK_MULTI_DOWN, __widget_multi_down_cb, data);
+       evas_object_event_callback_add(data->widget_layout, EVAS_CALLBACK_MULTI_MOVE, __widget_multi_move_cb, data);
+       evas_object_event_callback_add(data->widget_layout, EVAS_CALLBACK_MULTI_UP, __widget_multi_up_cb, data);
+
        evas_object_smart_member_add(data->stage, data->widget);
        evas_object_smart_member_add(data->widget_layout, data->widget);
        evas_object_clip_set(data->widget_layout, data->stage);
@@ -3338,7 +3647,7 @@ static void append_widget_dirty_object_list(struct widget_data *data, int idx)
        }
 
        if (widget_viewer_get_visibility(data->handle) != WIDGET_SHOW) {
-               DbgPrint("Box is not visible\n");
+               DbgPrint("Box[%s] is not visible\n", data->widget_id);
                return;
        }
 
@@ -3778,95 +4087,96 @@ static int do_force_mouse_up(struct widget_data *data)
        struct widget_mouse_event_info minfo;
        Evas_Coord x, y, w, h;
        struct widget_evas_event_info info;
+       int i;
 
        if (s_info.conf.field.auto_render_selector && s_info.conf.field.render_animator == 0) {
                DbgPrint("Change to render animator\n");
                s_info.conf.field.render_animator = 1;
        }
 
-       if (!data->is.field.pressed) {
+       if (!data->pressed) {
+               /**
+                * @note
+                * No buttons are pressed or there is no touch.
+                */
                return WIDGET_ERROR_INVALID_PARAMETER;
        }
 
+       /**
+        * @todo
+        * What happens if this is called for GBar?
+        */
        evas_object_geometry_get(data->widget, &x, &y, &w, &h);
 
-       minfo.x = (double)(data->x - x);
-       minfo.y = (double)(data->y - y);
-
-       if (data->size_type != WIDGET_SIZE_TYPE_UNKNOWN && !s_info.conf.field.use_fixed_size) {
+       /**
+        * @note
+        * If the GBar is pressed, we don't need to calculate the ratio.
+        */
+       if (!data->down.is_gbar && (data->size_type != WIDGET_SIZE_TYPE_UNKNOWN && !s_info.conf.field.use_fixed_size)) {
                minfo.ratio_w = (double)data->fixed_width / (double)w;
                minfo.ratio_h = (double)data->fixed_height / (double)h;
+               DbgPrint("Width: %d/%d - Height: %d/%d\n", data->fixed_width, w, data->fixed_height, h);
        } else {
                minfo.ratio_w = 1.0f;
                minfo.ratio_h = 1.0f;
        }
+       DbgPrint("Ratio: %lfx%lf\n", minfo.ratio_w, minfo.ratio_h);
 
-       data->is.field.pressed = 0;
+       DbgPrint("%x\n", data->is.field.cancel_click);
+       if (data->is.field.cancel_click != CANCEL_PROCESSED) {
+               DbgPrint("ON_HOLD send\n");
+               minfo.device = 0;
+               minfo.x = (double)(data->x[0] - x);
+               minfo.y = (double)(data->y[0] - y);
+
+               widget_viewer_feed_mouse_event(data->handle, WIDGET_MOUSE_ON_HOLD, &minfo);
+               data->is.field.cancel_click = CANCEL_PROCESSED;
+       }
 
        reset_scroller(data);
 
        if (s_info.conf.field.auto_feed && data->is.field.mouse_event) {
-               DbgPrint("%x\n", data->is.field.cancel_click);
-               if (data->is.field.cancel_click != CANCEL_PROCESSED) {
-                       DbgPrint("ON_HOLD send\n");
-                       widget_viewer_feed_mouse_event(data->handle, WIDGET_MOUSE_ON_HOLD, &minfo);
-                       data->is.field.cancel_click = CANCEL_PROCESSED;
-               }
-
-               /**
-                * @note
-                * UNSET will subtract object.x and object.y by master
-                * so we just send original touch position based on screen
-                */
-               minfo.x = (double)data->x;
-               minfo.y = (double)data->y;
-               DbgPrint("X,Y = %lfx%lf\n", minfo.x, minfo.y);
+               for (i = 0; i < MAX_DEVICE; i++) {
+                       if (IS_PRESSED(data, i)) {
+                               /**
+                                * @note
+                                * UNSET will subtract object.x and object.y by master
+                                * so we just send original touch position based on screen
+                                */
+                               minfo.x = (double)data->x[i];
+                               minfo.y = (double)data->y[i];
+                               DbgPrint("X,Y = %lfx%lf\n", minfo.x, minfo.y);
+                               minfo.device = i;
 
-               if (data->size_type != WIDGET_SIZE_TYPE_UNKNOWN && !s_info.conf.field.use_fixed_size) {
-                       minfo.ratio_w = (double)data->fixed_width / (double)data->down.geo.w;
-                       minfo.ratio_h = (double)data->fixed_height / (double)data->down.geo.h;
-                       DbgPrint("Width: %d/%d - Height: %d/%d\n", data->fixed_width, data->down.geo.w, data->fixed_height, data->down.geo.h);
-                       DbgPrint("Ratio: %lfx%lf\n", minfo.ratio_w, minfo.ratio_h);
-               } else {
-                       minfo.ratio_w = 1.0f;
-                       minfo.ratio_h = 1.0f;
-                       DbgPrint("UNKNOWN Ratio: %lfx%lf\n", minfo.ratio_w, minfo.ratio_h);
+                               widget_viewer_feed_mouse_event(data->handle, WIDGET_MOUSE_UNSET, &minfo);
+                       }
                }
-
-               widget_viewer_feed_mouse_event(data->handle, WIDGET_MOUSE_UNSET, &minfo);
        } else {
-               if (!data->is.field.mouse_event) {
-                       /* We have to keep the first position of touch down */
-                       minfo.x = (double)(data->down.x - x);
-                       minfo.y = (double)(data->down.y - y);
-                       if (data->size_type != WIDGET_SIZE_TYPE_UNKNOWN && !s_info.conf.field.use_fixed_size) {
-                               minfo.ratio_w = (double)data->fixed_width / (double)w;
-                               minfo.ratio_h = (double)data->fixed_height / (double)h;
-                       } else {
-                               minfo.ratio_w = 1.0f;
-                               minfo.ratio_h = 1.0f;
+               DbgPrint("%lfx%lf (%lfx%lf)\n", minfo.x, minfo.y, minfo.ratio_w, minfo.ratio_h);
+               for (i = 0; i < MAX_DEVICE; i++) {
+                       if (IS_PRESSED(data, i)) {
+                               minfo.x = (double)(data->x[i] - x);
+                               minfo.y = (double)(data->y[i] - y);
+                               minfo.device = i;
+
+                               widget_viewer_feed_mouse_event(data->handle, WIDGET_MOUSE_UP, &minfo);
+                               widget_viewer_feed_mouse_event(data->handle, WIDGET_MOUSE_LEAVE, &minfo);
                        }
                }
+       }
 
-               DbgPrint("%x\n", data->is.field.cancel_click);
-               if (data->is.field.cancel_click != CANCEL_PROCESSED) {
-                       DbgPrint("ON_HOLD send\n");
-                       widget_viewer_feed_mouse_event(data->handle, WIDGET_MOUSE_ON_HOLD, &minfo);
-                       data->is.field.cancel_click = CANCEL_PROCESSED;
-               }
+       data->pressed = 0;
+       data->is.field.cancel_click = CANCEL_DISABLED;
 
-               DbgPrint("%lfx%lf (%lfx%lf)\n", minfo.x, minfo.y, minfo.ratio_w, minfo.ratio_h);
-               widget_viewer_feed_mouse_event(data->handle, WIDGET_MOUSE_UP, &minfo);
-               widget_viewer_feed_mouse_event(data->handle, WIDGET_MOUSE_LEAVE, &minfo);
+       if (s_info.conf.field.support_gbar && data->is.field.flick_down) {
+               data->is.field.flick_down = 0;
+               info.widget_app_id = data->widget_id;
+               info.event = WIDGET_EVENT_GBAR_CREATED;
+               info.error = WIDGET_ERROR_CANCELED;
+               smart_callback_call(data, WIDGET_SMART_SIGNAL_FLICKDOWN_CANCELLED, &info);
+               DbgPrint("Flick down is canceled\n");
        }
 
-       data->is.field.cancel_click = CANCEL_DISABLED;
-       data->is.field.flick_down = 0;
-       info.widget_app_id = data->widget_id;
-       info.event = WIDGET_EVENT_GBAR_CREATED;
-       info.error = WIDGET_ERROR_CANCELED;
-       smart_callback_call(data, WIDGET_SMART_SIGNAL_FLICKDOWN_CANCELLED, &info);
-       DbgPrint("Flick down is canceled\n");
        return WIDGET_ERROR_NONE;
 }
 
@@ -4460,6 +4770,12 @@ static void acquire_widget_pixmap_cb(struct widget *handle, int pixmap, void *cb
        if (!s_info.conf.field.skip_acquire) {
                free(acquire_data);
        }
+
+       if (WIDGET_CONF_ENABLE_RESOURCE_LOCK) {
+               if (!eina_list_data_find(s_info.updated_pixmap_list, (void *)((unsigned long long)pixmap))) {
+                       s_info.updated_pixmap_list = eina_list_append(s_info.updated_pixmap_list, (void *)((unsigned long long)pixmap));
+               }
+       }
 }
 
 static void __widget_update_pixmap_object(struct widget_data *data, Evas_Object *widget_content, int w, int h)
@@ -4468,53 +4784,71 @@ static void __widget_update_pixmap_object(struct widget_data *data, Evas_Object
        struct acquire_data *acquire_data;
 
        if (data->widget_latest_idx == WIDGET_PRIMARY_BUFFER) {
-               unsigned int resource_id;
+               unsigned int resource_id = 0u;
+
+               if (widget_viewer_get_resource_id(data->handle, 0, &resource_id) < 0) {
+                       ErrPrint("Failed to get resource_id\n");
+               } else if (resource_id > 0) {
+                       if (data->widget_pixmap == resource_id) {
+                               if (data->widget_extra) {
+                                       /* Just replace the pixmap in this case, do not release old pixmap */
+                                       replace_pixmap(NULL, 0, widget_content, data->widget_pixmap);
+                               }
+
+                               update_widget_pixmap(widget_content, w, h);
 
-               widget_viewer_get_resource_id(data->handle, 0, &resource_id);
-               if (data->widget_pixmap == resource_id) {
-                       if (data->widget_extra) {
-                               /* Just replace the pixmap in this case, do not release old pixmap */
-                               replace_pixmap(NULL, 0, widget_content, data->widget_pixmap);
+                               if (WIDGET_CONF_ENABLE_RESOURCE_LOCK) {
+                                       if (!eina_list_data_find(s_info.updated_pixmap_list, (void *)((unsigned long long)resource_id))) {
+                                               s_info.updated_pixmap_list = eina_list_append(s_info.updated_pixmap_list, (void *)((unsigned long long)resource_id));
+                                       }
+                               }
+                               return;
                        }
 
-                       update_widget_pixmap(widget_content, w, h);
-                       return;
-               }
+                       if (s_info.conf.field.skip_acquire && resource_id != 0) {
+                               struct acquire_data local_acquire_data = {
+                                       .data = widget_ref(data),
+                                       .content = widget_content,
+                                       .w = w,
+                                       .h = h,
+                               };
 
-               if (s_info.conf.field.skip_acquire && resource_id != 0) {
-                       struct acquire_data local_acquire_data = {
-                               .data = widget_ref(data),
-                               .content = widget_content,
-                               .w = w,
-                               .h = h,
-                       };
+                               /**
+                                * @note
+                                * Resource lock will be acquired from below callback.
+                                */
+                               acquire_widget_pixmap_cb(data->handle, resource_id, &local_acquire_data);
+                               return;
+                       }
 
-                       acquire_widget_pixmap_cb(data->handle, resource_id, &local_acquire_data);
-                       return;
-               }
+                       if (data->is.field.widget_pixmap_acquire_requested) {
+                               DbgPrint("Pixmap is not acquired (in-process)\n");
+                               return;
+                       }
 
-               if (data->is.field.widget_pixmap_acquire_requested) {
-                       DbgPrint("Pixmap is not acquired\n");
-                       return;
-               }
+                       acquire_data = malloc(sizeof(*acquire_data));
+                       if (!acquire_data) {
+                               ErrPrint("malloc: %d\n", errno);
+                               return;
+                       }
 
-               acquire_data = malloc(sizeof(*acquire_data));
-               if (!acquire_data) {
-                       ErrPrint("malloc: %d\n", errno);
-                       return;
-               }
+                       acquire_data->data = widget_ref(data);
+                       acquire_data->content = widget_content;
+                       acquire_data->w = w;
+                       acquire_data->h = h;
 
-               acquire_data->data = widget_ref(data);
-               acquire_data->content = widget_content;
-               acquire_data->w = w;
-               acquire_data->h = h;
+                       ret = widget_viewer_acquire_resource_id(data->handle, 0, acquire_widget_pixmap_cb, acquire_data);
+                       if (ret != WIDGET_ERROR_NONE) {
+                               widget_unref(data);
+                               free(acquire_data);
+                       } else {
+                               data->is.field.widget_pixmap_acquire_requested = 1;
+                       }
 
-               ret = widget_viewer_acquire_resource_id(data->handle, 0, acquire_widget_pixmap_cb, acquire_data);
-               if (ret != WIDGET_ERROR_NONE) {
-                       widget_unref(data);
-                       free(acquire_data);
-               } else {
-                       data->is.field.widget_pixmap_acquire_requested = 1;
+                       /**
+                        * @note
+                        * Resource lock should be acquired from acquire_widget_pixmap_cb
+                        */
                }
        } else {
                if (!data->widget_extra) {
@@ -4524,7 +4858,13 @@ static void __widget_update_pixmap_object(struct widget_data *data, Evas_Object
 
                replace_pixmap(NULL, 0, widget_content, data->widget_extra[data->widget_latest_idx]);
                update_widget_pixmap(widget_content, w, h);
+               if (WIDGET_CONF_ENABLE_RESOURCE_LOCK) {
+                       if (!eina_list_data_find(s_info.updated_pixmap_list, (void *)((unsigned long long)data->widget_extra[data->widget_latest_idx]))) {
+                               s_info.updated_pixmap_list = eina_list_append(s_info.updated_pixmap_list, (void *)((unsigned long long)data->widget_extra[data->widget_latest_idx]));
+                       }
+               }
        }
+
 }
 
 static int widget_system_created(struct widget *handle, struct widget_data *data)
@@ -4620,11 +4960,21 @@ static void __widget_created_cb(struct widget *handle, int ret, void *cbdata)
 
                        if (!data->is.field.faulted) {
                                data->is.field.faulted = 1;
+
+                               DbgPrint("Display tap to load (%p) [%s]\n", data, data->widget_id);
+                               smart_callback_call(data, WIDGET_SMART_SIGNAL_WIDGET_CREATE_ABORTED, &fault_event);
+
                                __widget_overlay_faulted(data);
-                       }
+                       } else {
+                               smart_callback_call(data, WIDGET_SMART_SIGNAL_WIDGET_CREATE_ABORTED, &fault_event);
 
-                       DbgPrint("Display tap to load (%p) [%s]\n", data, data->widget_id);
-                       smart_callback_call(data, WIDGET_SMART_SIGNAL_WIDGET_CREATE_ABORTED, &fault_event);
+                               /**
+                                * @note
+                                * While processing the faulted smart callback, the user can request hide_faulted_overlay
+                                * So we should reset it from here. in other cases, the widget_overlay_faulted function deals with this.
+                                */
+                               data->is.field.hide_faulted_overlay = 0;
+                       }
 
                        ret = WIDGET_ERROR_FAULT;
                } else {
@@ -5017,6 +5367,12 @@ static void __widget_overlay_faulted(struct widget_data *data)
        Evas_Object *overlay;
        widget_type_e widget_type;
 
+       if (data->is.field.hide_faulted_overlay == 1) {
+               DbgPrint("Faulted overlay is hidden by request (%s)\n", data->widget_id);
+               data->is.field.hide_faulted_overlay = 0;
+               return;
+       }
+
        if (data->is.field.widget_overlay_loaded) {
                __widget_overlay_disable(data, 1, 1);
        }
@@ -6367,11 +6723,14 @@ static int widget_fault_handler(enum widget_fault_type fault, const char *pkgnam
                        if (!strcmp(data->widget_id, pkgname)) {
                                DbgPrint("Faulted: %s (%p)\n", pkgname, data);
                                data->is.field.faulted = 1;
-                               __widget_overlay_faulted(data);
+
                                info.error = WIDGET_ERROR_FAULT;
                                info.widget_app_id = data->widget_id;
                                info.event = WIDGET_FAULT_DEACTIVATED;
+
                                smart_callback_call(data, WIDGET_SMART_SIGNAL_WIDGET_FAULTED, &info);
+
+                               __widget_overlay_faulted(data);
                        }
                }
                break;
@@ -6385,11 +6744,14 @@ static int widget_fault_handler(enum widget_fault_type fault, const char *pkgnam
                        if (!strcmp(data->widget_id, pkgname)) {
                                DbgPrint("Disconnected: %s (%p)\n", pkgname, data);
                                data->is.field.faulted = 1;
-                               __widget_overlay_faulted(data);
+
                                info.error = WIDGET_ERROR_FAULT;
                                info.widget_app_id = data->widget_id;
                                info.event = WIDGET_FAULT_PROVIDER_DISCONNECTED;
+
                                smart_callback_call(data, WIDGET_SMART_SIGNAL_PROVIDER_DISCONNECTED, &info);
+
+                               __widget_overlay_faulted(data);
                        }
                }
                break;
@@ -6399,6 +6761,32 @@ static int widget_fault_handler(enum widget_fault_type fault, const char *pkgnam
        return 0;
 }
 
+static void evas_render_post_cb(void *data, Evas *e, void *event_info)
+{
+       widget_resource_lock_t handle;
+
+       EINA_LIST_FREE(s_info.updated_pixmap_lock_list, handle) {
+               widget_service_release_resource_lock(handle);
+               widget_service_destroy_resource_lock(handle, 0);
+       }
+}
+
+static void evas_render_pre_cb(void *data, Evas *e, void *event_info)
+{
+       widget_resource_lock_t handle;
+       void *pixmap;
+
+       EINA_LIST_FREE(s_info.updated_pixmap_list, pixmap) {
+               handle = widget_service_create_resource_lock((unsigned int)((unsigned long long)pixmap), WIDGET_LOCK_READ);
+               if (handle) {
+                       widget_service_acquire_resource_lock(handle);
+                       s_info.updated_pixmap_lock_list = eina_list_append(s_info.updated_pixmap_lock_list, handle);
+               } else {
+                       ErrPrint("Failed to create a resource lock\n");
+               }
+       }
+}
+
 EAPI int widget_viewer_evas_init(Evas_Object *win)
 {
        int ret;
@@ -6454,6 +6842,15 @@ EAPI int widget_viewer_evas_init(Evas_Object *win)
        s_info.conf.field.force_to_buffer = 0;
        s_info.win = win;
 
+       if (WIDGET_CONF_ENABLE_RESOURCE_LOCK) {
+               Evas *e;
+               e = evas_object_evas_get(win);
+               if (e) {
+                       evas_event_callback_add(e, EVAS_CALLBACK_RENDER_PRE, evas_render_pre_cb, NULL);
+                       evas_event_callback_add(e, EVAS_CALLBACK_RENDER_POST, evas_render_post_cb, NULL);
+               }
+       }
+
        return ret;
 }
 
@@ -6466,6 +6863,15 @@ EAPI int widget_viewer_evas_fini(void)
        }
 
        if (s_info.initialized) {
+               if (WIDGET_CONF_ENABLE_RESOURCE_LOCK && s_info.win) {
+                       Evas *e;
+                       e = evas_object_evas_get(s_info.win);
+                       if (e) {
+                               evas_event_callback_del(e, EVAS_CALLBACK_RENDER_PRE, evas_render_pre_cb);
+                               evas_event_callback_del(e, EVAS_CALLBACK_RENDER_POST, evas_render_post_cb);
+                       }
+               }
+
                widget_viewer_remove_event_handler(widget_event_handler);
                widget_viewer_remove_fault_handler(widget_fault_handler);
                widget_viewer_fini();
@@ -6733,6 +7139,10 @@ EAPI int widget_viewer_evas_set_option(widget_evas_conf_e type, int value)
                s_info.conf.field.skip_acquire = !!value;
                DbgPrint("Turn %s skip-acquire option\n", s_info.conf.field.skip_acquire ? "on" : "off");
                break;
+       case WIDGET_VIEWER_EVAS_DISABLE_SCROLLER:
+               s_info.conf.field.disable_internal_scroller = !!value;
+               DbgPrint("Turn %s internal_scroller option\n", s_info.conf.field.disable_internal_scroller ? "off" : "on");
+               break;
        default:
                ret = WIDGET_ERROR_INVALID_PARAMETER;
                break;
@@ -6915,7 +7325,7 @@ EAPI void widget_viewer_evas_cancel_click_event(Evas_Object *widget)
                return;
        }
 
-       if (!data->is.field.pressed) {
+       if (!data->pressed) {
                DbgPrint("Cancel ignored\n");
                return;
        }
@@ -7976,4 +8386,54 @@ EAPI int widget_viewer_evas_hide_overlay(Evas_Object *widget)
        return WIDGET_ERROR_NONE;
 }
 
+/**
+ * @note
+ * This function must has to be called after the object is faulted.
+ * And this will not reset the faulted flag. it just dislable the faulted overlay if it is exists.
+ *
+ * The best usage of this function is called from smart-callback.
+ * Any faulted smart callback can call this.
+ * Then the widget_viewer_evas will check the flag to decide whether enable the faulted overlay or not.
+ */
+EAPI int widget_viewer_evas_hide_faulted_overlay_once(Evas_Object *widget)
+{
+       struct widget_data *data;
+
+       if (!is_widget_feature_enabled()) {
+               return WIDGET_ERROR_NOT_SUPPORTED;
+       }
+
+       if (!s_info.initialized) {
+               return WIDGET_ERROR_FAULT;
+       }
+
+       data = get_smart_data(widget);
+       if (!data) {
+               ErrPrint("Invalid object\n");
+               return WIDGET_ERROR_INVALID_PARAMETER;
+       }
+
+       if (data->is.field.faulted == 0) {
+               ErrPrint("Object is not faulted\n");
+               return WIDGET_ERROR_INVALID_PARAMETER;
+       }
+
+       /**
+        * @note
+        * If the overlay (faulted) is already enabled,
+        * Turn it off first.
+        */
+       if (data->is.field.widget_overlay_loaded) {
+               DbgPrint("Faulted overlay is disabled\n");
+               __widget_overlay_disable(data, 1, 1);
+       }
+
+       /**
+        * This flag will be checked before enable the faulted overlay.
+        * And this will be reset'd right after ignore the faulted overlay.
+        */
+       data->is.field.hide_faulted_overlay = 1;
+       return WIDGET_ERROR_NONE;
+}
+
 /* End of a file */
index b8d8342..880bf81 100644 (file)
@@ -60,6 +60,7 @@ TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${sdk_pkgs_LDFLAGS} "-lm -pie -fPIC" widge
 
 INSTALL(TARGETS ${PROJECT_NAME} DESTINATION ${BINDIR})
 INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/${PKGNAME}.xml DESTINATION /usr/share/packages)
+#INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/${PKGNAME}.efl DESTINATION /etc/smack/accesses.d RENAME ${PKGNAME})
 INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/LICENSE DESTINATION /usr/share/license RENAME ${PKGNAME})
 INSTALL(DIRECTORY DESTINATION ${DATADIR})
 
index 109aec7..ac60555 100644 (file)
@@ -103,7 +103,7 @@ collections {
                                        color3: 0 0 0 255;
                                        text {
                                                style: "info,text";
-                                               text: "Hello";
+                                               text: "widget id";
                                                fit: 1 1;
                                        }
                                }
@@ -140,7 +140,7 @@ collections {
                                        color3: 0 0 0 255;
                                        text {
                                                style: "info,text";
-                                               text: "Hello";
+                                               text: "content info";
                                                fit: 1 1;
                                        }
                                }
@@ -177,7 +177,7 @@ collections {
                                        color3: 0 0 0 255;
                                        text {
                                                style: "info,text";
-                                               text: "Hello";
+                                               text: "Title";
                                                fit: 1 1;
                                        }
                                }
@@ -214,7 +214,7 @@ collections {
                                        color3: 0 0 0 255;
                                        text {
                                                style: "info,text";
-                                               text: "Hello";
+                                               text: "Update period";
                                                fit: 1 1;
                                        }
                                }
@@ -242,6 +242,7 @@ collections {
                                name: "message";
                                mouse_events: 0;
                                type: TEXTBLOCK;
+                               scale: 1;
                                description {
                                        state: "default" 0.0;
                                        rel1 { relative: 0.5 0.3; }
@@ -251,7 +252,7 @@ collections {
                                        color3: 0 0 0 255;
                                        fixed: 1 0;
                                        align: 0.5 0.0;
-                                       min: 400 0;
+                                       min: 200 0;
                                        text {
                                                style: "info,text";
                                                text: "Information";
index a6563ee..483309e 100644 (file)
@@ -19,9 +19,9 @@
 #define ErrPrint(format, arg...)    SECURE_LOGE(format, ##arg)
 #else
 extern FILE *__file_log_fp;
-#define DbgPrint(format, arg...) do { fprintf(__file_log_fp, "[LOG] [\e[32m%s/%s\e[0m:%d] " format, util_basename(__FILE__), __func__, __LINE__, ##arg); fflush(__file_log_fp); } while (0)
+#define DbgPrint(format, arg...) do { fprintf(__file_log_fp, "[LOG] [\e[32m%s/%s\e[0m:%d] " format, widget_util_basename(__FILE__), __func__, __LINE__, ##arg); fflush(__file_log_fp); } while (0)
 
-#define ErrPrint(format, arg...) do { fprintf(__file_log_fp, "[ERR] [\e[32m%s/%s\e[0m:%d] " format, util_basename(__FILE__), __func__, __LINE__, ##arg); fflush(__file_log_fp); } while (0)
+#define ErrPrint(format, arg...) do { fprintf(__file_log_fp, "[ERR] [\e[32m%s/%s\e[0m:%d] " format, widget_util_basename(__FILE__), __func__, __LINE__, ##arg); fflush(__file_log_fp); } while (0)
 #endif
 
 
index 60eabff..ffd0622 100644 (file)
@@ -10,7 +10,7 @@
        </privileges>
 
        <!-- Main application -->
-       <ui-application appid="org.tizen.widget_viewer_sdk" exec="/usr/apps/org.tizen.widget_viewer_sdk/bin/widget_viewer_sdk" nodisplay="true" multiple="false" type="capp" taskmanage="true">
+       <ui-application appid="org.tizen.widget_viewer_sdk" exec="/usr/apps/org.tizen.widget_viewer_sdk/bin/widget_viewer_sdk" nodisplay="true" multiple="false" type="capp" taskmanage="false">
                <label>Widget Viewer for SDK</label>
                <label xml:lang="ko-kr">위젯 뷰어 for SDK</label>
                <icon>org.tizen.widget_viewer_sdk</icon>
index aa8b260..f4eb75f 100644 (file)
@@ -20,6 +20,9 @@
 #include <errno.h>
 #include <widget_errno.h>
 #include <widget_service.h>
+#include <widget_service_internal.h>
+#include <widget_conf.h>
+#include <widget_util.h>
 #include <widget_viewer_evas.h>
 #include <vconf.h>
 #include <bundle.h>
@@ -34,6 +37,12 @@ int errno;
 #include "main.h"
 #include "debug.h"
 
+#define WATCH_CATEGORY "http://tizen.org/category/wearable_clock"
+#define DEFAULT_WATCH "org.tizen.digitalclock"
+#define LAZY_WATCH_TIME 3.0f
+#define CR 13
+#define LF 10
+
 static struct info {
        int w;
        int h;
@@ -51,6 +60,11 @@ static struct info {
                int *size_types;
                int count_of_size_type;
        } ctx;
+
+       Ecore_Timer *lazy_widget_loader;
+       double lazy_watch_time;
+       char *default_watch;
+       char *watch_category;
 } s_info = {
        .w = 0,
        .h = 0,
@@ -66,9 +80,90 @@ static struct info {
                .size_types = NULL,
                .count_of_size_type = 20,
        },
+
+       .lazy_widget_loader = NULL,
+       .lazy_watch_time = LAZY_WATCH_TIME,
+       .default_watch = DEFAULT_WATCH,
+       .watch_category = WATCH_CATEGORY,
 };
 
 #define LONG_PRESS 1.0f
+#define CONF_FNAME "/etc/widget_viewer_sdk.conf"
+
+static void watch_category_handler(char *buffer)
+{
+       char *old_category;
+
+       old_category = s_info.watch_category;
+
+       s_info.watch_category = strdup(buffer);
+       if (!s_info.watch_category) {
+               ErrPrint("strdup: %d\n", errno);
+               s_info.watch_category = old_category;
+       } else if ((long)old_category != (long)WATCH_CATEGORY) { /** Forcely compare the address */
+               free(old_category);
+       }
+
+       DbgPrint("Watch category: [%s]\n", s_info.watch_category);
+}
+
+static void default_watch_handler(char *buffer)
+{
+       char *old_watch;
+
+       old_watch = s_info.default_watch;
+
+       s_info.default_watch = strdup(buffer);
+       if (!s_info.default_watch) {
+               ErrPrint("strdup: %d\n", errno);
+               s_info.default_watch = old_watch;
+       } else if ((long)old_watch != (long)DEFAULT_WATCH) { /** Forcely compare the address */
+               free(old_watch);
+       }
+
+       DbgPrint("Default watch: [%s]\n", s_info.default_watch);
+}
+
+static void lazy_load_time_handler(char *buffer)
+{
+       double val;
+       if (sscanf(buffer, "%lf", &val) != 1) {
+               ErrPrint("Unable to parse data: [%s]\n", buffer);
+               return;
+       }
+
+       if (val < 0.0f) {
+               ErrPrint("Invalid value: %lf\n", val);
+               val = LAZY_WATCH_TIME;
+       }
+
+       s_info.lazy_watch_time = val;
+       DbgPrint("Lazy watch time: %lf\n", s_info.lazy_watch_time);
+}
+
+static void load_configuration(void)
+{
+       static const widget_conf_parser_table_t token_handler[] = {
+               {
+                       .name = "watch_category",
+                       .handler = watch_category_handler,
+               },
+               {
+                       .name = "default_watch",
+                       .handler = default_watch_handler,
+               },
+               {
+                       .name = "lazy_load_time",
+                       .handler = lazy_load_time_handler,
+               },
+               {
+                       .name = NULL,
+                       .handler = NULL,
+               },
+       };
+
+       (void)widget_conf_parser(CONF_FNAME, token_handler);
+}
 
 static void back_key_cb(void *data, Evas_Object *obj, void *event_info)
 {
@@ -113,6 +208,8 @@ static void layout_up_cb(void *data, Evas *e, Evas_Object *obj, void *event_info
 
 static bool app_create(void *data)
 {
+       load_configuration();
+
        s_info.win = elm_win_add(NULL, "Widget Viewer (SDK)", ELM_WIN_BASIC);
        if (!s_info.win) {
                LOGD("Failed to create a window\n");
@@ -527,6 +624,16 @@ static int prepare_widget(const char *widget_id, app_control_h control)
        return ret;
 }
 
+static Eina_Bool lazy_widget_loader_cb(void *widget_id)
+{
+       DbgPrint("Lazy loader expired. load widget [%s]\n", widget_id);
+
+       (void)load_widget(widget_id);
+       free(widget_id);
+       s_info.lazy_widget_loader = NULL;
+       return ECORE_CALLBACK_CANCEL;
+}
+
 static void _app_control(app_control_h service, void *data)
 {
        char *widget_id = NULL;
@@ -534,15 +641,70 @@ static void _app_control(app_control_h service, void *data)
 
        ret = app_control_get_extra_data(service, WIDGET_APPID, &widget_id);
        if (ret == APP_CONTROL_ERROR_NONE) {
+               char *category;
+               int lazy_loader = 0;
+
                DbgPrint("Loading a widget: [%s]\n", widget_id);
                if (!widget_id) {
                        return;
                }
 
+               category = widget_service_get_category(widget_id);
+               if (category) {
+                       if (!strcmp(category, WATCH_CATEGORY)) {
+                               /**
+                                * Trying to unload the WATCH from W-HOME
+                                */
+                               char *watch_id;
+                               int need_to_unload = 0;
+
+                               watch_id = vconf_get_str(VCONFKEY_WMS_CLOCKS_SET_IDLE);
+                               if (watch_id) {
+                                       need_to_unload = !!strcmp(watch_id, s_info.default_watch);
+                                       free(watch_id);
+                               }
+
+                               if (need_to_unload) {
+                                       DbgPrint("Watch: [%s] - unload first, SET(%s)\n", widget_id, s_info.default_watch);
+                                       ret = vconf_set_str(VCONFKEY_WMS_CLOCKS_SET_IDLE, s_info.default_watch);
+                                       if (ret != 0) {
+                                               ErrPrint("If this is not wearable, there is no such CLOCKS_SET_IDLE key (%d)\n", ret);
+                                       }
+
+                                       /**
+                                        * @note
+                                        * In this case, we should waiting some time to unload watch first.
+                                        */
+                                       lazy_loader = 1;
+                               }
+                       }
+                       free(category);
+               }
+
                ret = unload_widget();
                ret = prepare_widget(widget_id, service);
-               ret = load_widget(widget_id);
-               free(widget_id);
+
+               if (s_info.lazy_widget_loader) {
+                       char *tmp;
+                       tmp = ecore_timer_del(s_info.lazy_widget_loader);
+                       free(tmp);
+               }
+
+               if (lazy_loader) {
+                       DbgPrint("Load a watch after some time later (%lf)\n", s_info.lazy_watch_time);
+                       s_info.lazy_widget_loader = ecore_timer_add(s_info.lazy_watch_time, lazy_widget_loader_cb, widget_id);
+                       if (!s_info.lazy_widget_loader) {
+                               ErrPrint("Unable to fire the timer\n");
+                               lazy_widget_loader_cb(widget_id);
+                       }
+                       /**
+                        * @note
+                        * widget_id will be deleted from lazy_widget_loader_cb. or return value of ecore_timer_del().
+                        */
+               } else {
+                       DbgPrint("Immediately loads the watch[%s]\n", widget_id);
+                       lazy_widget_loader_cb(widget_id);
+               }
        } else {
                /**
                 * @note