Sync with the latest tizen 2.x
[apps/native/widget/widget.git] / src / virtual_window.c
index 288ef65..1d91878 100644 (file)
 #include <dlfcn.h>
 #include <Eina.h>
 #include <math.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
 
 #include <X11/Xlib.h>
 
@@ -34,7 +38,9 @@
 #include <widget_conf.h>
 #include <widget_buffer.h>
 #include <widget_provider.h>
+#include <widget_provider_buffer.h>
 #include <widget_util.h>
+#include <libgen.h>
 
 #include "widget.h"
 #include "widget_internal.h"
 
 #define PUBLIC __attribute__((visibility("default")))
 #define WIDGET_WIN_TAG "dynamic,box,win"
+#define WIN_INFO_TAG "dynamic,box,info"
 
 #define WIDGET_DEFAULT_WIDTH 1
 #define WIDGET_DEFAULT_HEIGHT 1
 
+#define MOUSE_BUTTON_LEFT 1
+
+/**
+ * @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)))))))
+
 static inline Evas_Object *get_highlighted_object(Evas_Object *obj)
 {
        Evas_Object *o, *ho;
@@ -60,41 +85,42 @@ static inline Evas_Object *get_highlighted_object(Evas_Object *obj)
        return ho;
 }
 
-static inline void apply_orientation(int degree, int *x, int *y)
+static inline void apply_orientation(int degree, int *x, int *y, int width, int height, input_event_source_e source)
 {
        int _x;
        int _y;
        int _angle;
 
+       if (source == INPUT_EVENT_SOURCE_VIEWER) {
+               /* Already rotated */
+               return;
+       }
+
+       _x = *x;
+       _y = *y;
+
        switch (degree) {
        case 0:
                return;
        case 90:
-               _x = *x;
-               _y = *y;
-
-               *x = -_y;
-               *y = _x;
+               *x = _y;
+               *y = width - _x;
                return;
        case 180:
-               _x = *x;
-               _y = *y;
-               _angle = degree;
-
-               *x = -_x;
-               *y = -_y;
+               *x = width - _x;
+               *y = height - _y;
                return;
        case 270:
-               _x = *x;
-               _y = *y;
-               _angle = degree;
-
-               *x = _y;
-               *y = -_x;
+               *x = height - _y;
+               *y = _x;
                return;
        default:
-               _x = *x;
-               _y = *y;
+               /**
+                * @FIXME
+                * This rotation formular is not work correctly.
+                * The pointer should be rotated by other way.
+                * This is not what we want.
+                */
                _angle = degree;
 
                *x = (double)_x * cos((double)_angle) - (double)_y * sin((double)_angle);
@@ -103,62 +129,14 @@ static inline void apply_orientation(int degree, int *x, int *y)
        }
 }
 
-/**
- * @note
- * Every user event (mouse) on the buffer will be passed via this event callback
- */
-static int event_handler_cb(widget_buffer_h handler, struct widget_buffer_event_data *event_info, void *data)
+static inline int processing_events(vwin_info_t info, widget_buffer_event_data_t event_info, double timestamp)
 {
-       vwin_info_t info = data;
        Elm_Access_Action_Info action_info;
        Elm_Access_Action_Type action_type;
-       int ret = 0;
        Evas_Object *parent_elm;
        KeySym *key_symbol;
        unsigned int flags = 0;
-       double timestamp;
-
-       if (!info->handle) {
-               /* Just ignore this event */
-               return 0;
-       }
-
-       if (WIDGET_CONF_USE_GETTIMEOFDAY) {
-               if (WIDGET_CONF_EVENT_FILTER > 0.0f && (info->pressed == 0 || event_info->type == WIDGET_BUFFER_EVENT_MOVE)) {
-                       struct timeval tv;
-
-                       if (gettimeofday(&tv, NULL) < 0) {
-                               ErrPrint("gettimeofday: %d\n", errno);
-                       } else {
-                               timestamp = (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0f;
-                               timestamp -= event_info->timestamp;
-
-                               if (timestamp > WIDGET_CONF_EVENT_FILTER) {
-                                       DbgPrint("Dropped %lf\n", timestamp);
-                                       return 0;
-                               }
-                       }
-               }
-
-               /**
-                * If the device doesn't use the clock monotic time, we have to emulate it for EVAS
-                * Evas only use the monotic time for animating objects
-                */
-               timestamp = ecore_time_get() * 1000.0f;
-       } else {
-               if (WIDGET_CONF_EVENT_FILTER > 0.0f && (info->pressed == 0 || event_info->type == WIDGET_BUFFER_EVENT_MOVE)) {
-                       timestamp = ecore_time_get();
-
-                       timestamp -= event_info->timestamp;
-                       if (timestamp > WIDGET_CONF_EVENT_FILTER) {
-                               DbgPrint("Dropped %lf\n", timestamp);
-                               return 0;
-                       }
-               }
-
-               timestamp = event_info->timestamp * 1000.0f;
-       }
-
+       int ret = 0;
        /**
         * @note
         * Feed up events
@@ -169,6 +147,9 @@ static int event_handler_cb(widget_buffer_h handler, struct widget_buffer_event_
                flags |= EVAS_EVENT_FLAG_ON_HOLD;
                evas_event_default_flags_set(info->e, flags);
                ErrPrint("ON_HOLD[%s] %dx%d - %lf\n", info->id, event_info->info.pointer.x, event_info->info.pointer.y, timestamp);
+               if (info->pressed == 0) {
+                       info->flags.field.on_hold_before_down = 1;
+               }
                break;
        case WIDGET_BUFFER_EVENT_OFF_HOLD:
                flags = evas_event_default_flags_get(info->e);
@@ -179,6 +160,9 @@ static int event_handler_cb(widget_buffer_h handler, struct widget_buffer_event_
                flags = evas_event_default_flags_get(info->e);
                flags |= EVAS_EVENT_FLAG_ON_SCROLL;
                evas_event_default_flags_set(info->e, flags);
+               if (info->pressed == 0) {
+                       info->flags.field.on_scroll_before_down = 1;
+               }
                break;
        case WIDGET_BUFFER_EVENT_OFF_SCROLL:
                flags = evas_event_default_flags_get(info->e);
@@ -192,13 +176,23 @@ static int event_handler_cb(widget_buffer_h handler, struct widget_buffer_event_
                evas_event_feed_mouse_out(info->e, timestamp, NULL);
                break;
        case WIDGET_BUFFER_EVENT_DOWN:
-               apply_orientation(info->orientation, &event_info->info.pointer.x, &event_info->info.pointer.y);
+               apply_orientation(info->orientation, &event_info->info.pointer.x, &event_info->info.pointer.y, info->w, info->h, event_info->info.pointer.source);
 
-               if (info->pressed) {
+               if (IS_PRESSED(info, event_info->info.pointer.device)) {
                        ErrPrint("MOUSE UP is not called\n");
-                       ErrPrint("UP[%s] %dx%d - %lf\n", info->id, event_info->info.pointer.x, event_info->info.pointer.y, timestamp);
-                       evas_event_feed_mouse_move(info->e, event_info->info.pointer.x, event_info->info.pointer.y, timestamp, NULL);
-                       evas_event_feed_mouse_up(info->e, 1, EVAS_BUTTON_NONE, timestamp, NULL);
+                       ErrPrint("UP[%s] %dx%d - %lf (%d)\n", info->id, event_info->info.pointer.x, event_info->info.pointer.y, timestamp, event_info->info.pointer.device);
+                       if (event_info->info.pointer.device > 0) {
+                               /**
+                                * @multi touch up
+                                */
+                               evas_event_feed_multi_up(info->e, event_info->info.pointer.device, event_info->info.pointer.x, event_info->info.pointer.y,
+                                                                                       0.0f, 0.0f, 0.0f, /* radius, radius_x, radius_y */
+                                                                                       0.0f, 0.0f, 0.0f, 0.0f, /* pressure, angle, fx, fy */
+                                                                                       EVAS_BUTTON_NONE, timestamp, NULL); /* button_flags, timestamp, ... */
+                       } else {
+                               evas_event_feed_mouse_move(info->e, event_info->info.pointer.x, event_info->info.pointer.y, timestamp, NULL);
+                               evas_event_feed_mouse_up(info->e, MOUSE_BUTTON_LEFT, EVAS_BUTTON_NONE, timestamp, NULL);
+                       }
                }
 
                /**
@@ -206,40 +200,78 @@ static int event_handler_cb(widget_buffer_h handler, struct widget_buffer_event_
                 * Before processing the DOWN event,
                 * Reset the evas event flags regarding ON_HOLD option.
                 * It can be re-enabled while processing down-move-up events.
+                * However if those events are occurred right before DOWN,
+                * Do not clear it.
+                * Some speicific cases, the ON_HOLD(ON_SCROLL) event can be delievered
+                * before MOUSE_DOWN event.
                 */
                flags = evas_event_default_flags_get(info->e);
-               flags &= ~EVAS_EVENT_FLAG_ON_SCROLL;
-               flags &= ~EVAS_EVENT_FLAG_ON_HOLD;
+               if (!info->flags.field.on_hold_before_down) {
+                       flags &= ~EVAS_EVENT_FLAG_ON_HOLD;
+               }
+               if (!info->flags.field.on_scroll_before_down) {
+                       flags &= ~EVAS_EVENT_FLAG_ON_SCROLL;
+               }
                evas_event_default_flags_set(info->e, flags);
+
+               /**
+                * @note
+                * Reset flags after dealing with the ON_HOLD/ON_SCROLL event
+                */
+               info->flags.field.on_scroll_before_down = 0;
+               info->flags.field.on_hold_before_down = 0;
                /**
                 * @note
                 * Calculate the event occurred X & Y on the buffer
                 */
-               evas_event_feed_mouse_move(info->e, event_info->info.pointer.x, event_info->info.pointer.y, timestamp, NULL);
-               evas_event_feed_mouse_down(info->e, 1, EVAS_BUTTON_NONE, timestamp, NULL); /* + 0.2f just for fake event */
-               info->pressed = 1;
-               ErrPrint("DOWN[%s] %dx%d - %lf\n", info->id, event_info->info.pointer.x, event_info->info.pointer.y, timestamp);
+               if (event_info->info.pointer.device > 0) {
+                       evas_event_feed_multi_down(info->e, event_info->info.pointer.device, event_info->info.pointer.x, event_info->info.pointer.y,
+                                                                                       0.0f, 0.0f, 0.0f, /* radius, radius_x, radius_y */
+                                                                                       0.0f, 0.0f, 0.0f, 0.0f, /* pressure, angle, fx, fy */
+                                                                                       EVAS_BUTTON_NONE, timestamp, NULL); /* button_flags, timestamp, ... */
+               } else {
+                       evas_event_feed_mouse_move(info->e, event_info->info.pointer.x, event_info->info.pointer.y, timestamp, NULL);
+                       evas_event_feed_mouse_down(info->e, MOUSE_BUTTON_LEFT, EVAS_BUTTON_NONE, timestamp, NULL); /* + 0.2f just for fake event */
+               }
+
+               SET_PRESSED(info, event_info->info.pointer.device);
+               ErrPrint("DOWN[%s] %dx%d - %lf (%d)\n", info->id, event_info->info.pointer.x, event_info->info.pointer.y, timestamp, event_info->info.pointer.device);
                break;
        case WIDGET_BUFFER_EVENT_MOVE:
-               apply_orientation(info->orientation, &event_info->info.pointer.x, &event_info->info.pointer.y);
+               apply_orientation(info->orientation, &event_info->info.pointer.x, &event_info->info.pointer.y, info->w, info->h, event_info->info.pointer.source);
                /**
                 * @note
                 * Calculate the event occurred X & Y on the buffer
                 */
-               evas_event_feed_mouse_move(info->e, event_info->info.pointer.x, event_info->info.pointer.y, timestamp, NULL);
+               if (event_info->info.pointer.device > 0) {
+                       evas_event_feed_multi_move(info->e, event_info->info.pointer.device, event_info->info.pointer.x, event_info->info.pointer.y,
+                                                                                       0.0f, 0.0f, 0.0f, /* radius, radius_x, radius_y */
+                                                                                       0.0f, 0.0f, 0.0f, 0.0f, /* pressure, angle, fx, fy */
+                                                                                       timestamp, NULL); /* timestamp, ... */
+               } else {
+                       evas_event_feed_mouse_move(info->e, event_info->info.pointer.x, event_info->info.pointer.y, timestamp, NULL);
+               }
                break;
        case WIDGET_BUFFER_EVENT_UP:
-               apply_orientation(info->orientation, &event_info->info.pointer.x, &event_info->info.pointer.y);
-               evas_event_feed_mouse_move(info->e, event_info->info.pointer.x, event_info->info.pointer.y, timestamp, NULL);
-               evas_event_feed_mouse_up(info->e, 1, EVAS_BUTTON_NONE, timestamp, NULL);
-               info->pressed = 0;
+               apply_orientation(info->orientation, &event_info->info.pointer.x, &event_info->info.pointer.y, info->w, info->h, event_info->info.pointer.source);
+
+               if (event_info->info.pointer.device > 0) {
+                       evas_event_feed_multi_up(info->e, event_info->info.pointer.device, event_info->info.pointer.x, event_info->info.pointer.y,
+                                                                                       0.0f, 0.0f, 0.0f, /* radius, radius_x, radius_y */
+                                                                                       0.0f, 0.0f, 0.0f, 0.0f, /* pressure, angle, fx, fy */
+                                                                                       EVAS_BUTTON_NONE, timestamp, NULL); /* button_flags, timestamp, ... */
+               } else {
+                       evas_event_feed_mouse_move(info->e, event_info->info.pointer.x, event_info->info.pointer.y, timestamp, NULL);
+                       evas_event_feed_mouse_up(info->e, MOUSE_BUTTON_LEFT, EVAS_BUTTON_NONE, timestamp, NULL);
+               }
+               SET_RELEASED(info, event_info->info.pointer.device);
                /**
                 * @note
                 * We have to keep the event flags, so we should not clear them from here.
                 * Sometimes, asynchronously callable Callbacks can refer the evas event flags after up event.
                 * so if we reset them from here, those kind of callbacks will fails to do their job properly.
                 */
-               ErrPrint("UP[%s] %dx%d - %lf\n", info->id, event_info->info.pointer.x, event_info->info.pointer.y, timestamp);
+               ErrPrint("UP[%s] %dx%d - %lf (%d)\n", info->id, event_info->info.pointer.x, event_info->info.pointer.y, timestamp, event_info->info.pointer.device);
                break;
        case WIDGET_BUFFER_EVENT_ACCESS_HIGHLIGHT:
                parent_elm = ecore_evas_data_get(info->ee, WIDGET_WIN_TAG);
@@ -248,7 +280,7 @@ static int event_handler_cb(widget_buffer_h handler, struct widget_buffer_event_
                        break;
                }
                memset(&action_info, 0, sizeof(action_info));
-               action_type = ELM_ACCESS_ACTION_HIGHLIGHT;
+               action_type = 0; //ELM_ACCESS_ACTION_HIGHLIGHT;
                /**
                 * @note
                 * Calculate the event occurred X & Y on the buffer
@@ -276,7 +308,7 @@ static int event_handler_cb(widget_buffer_h handler, struct widget_buffer_event_
                        break;
                }
                memset(&action_info, 0, sizeof(action_info));
-               action_type = ELM_ACCESS_ACTION_HIGHLIGHT_NEXT;
+               action_type = 0; //ELM_ACCESS_ACTION_HIGHLIGHT_NEXT;
                action_info.highlight_cycle = EINA_FALSE;
                ret = elm_access_action(parent_elm, action_type, &action_info);
                ret = (ret == EINA_FALSE) ? WIDGET_ACCESS_STATUS_LAST : WIDGET_ACCESS_STATUS_DONE;
@@ -288,7 +320,7 @@ static int event_handler_cb(widget_buffer_h handler, struct widget_buffer_event_
                        break;
                }
                memset(&action_info, 0, sizeof(action_info));
-               action_type = ELM_ACCESS_ACTION_HIGHLIGHT_PREV;
+               action_type = 0; //ELM_ACCESS_ACTION_HIGHLIGHT_PREV;
                action_info.highlight_cycle = EINA_FALSE;
                ret = elm_access_action(parent_elm, action_type, &action_info);
                ret = (ret == EINA_FALSE) ? WIDGET_ACCESS_STATUS_FIRST : WIDGET_ACCESS_STATUS_DONE;
@@ -300,7 +332,7 @@ static int event_handler_cb(widget_buffer_h handler, struct widget_buffer_event_
                        break;
                }
                memset(&action_info, 0, sizeof(action_info));
-               action_type = ELM_ACCESS_ACTION_ACTIVATE;
+               action_type = 0; //ELM_ACCESS_ACTION_ACTIVATE;
                ret = elm_access_action(parent_elm, action_type, &action_info);
                ret = (ret == EINA_FALSE) ? WIDGET_ACCESS_STATUS_ERROR : WIDGET_ACCESS_STATUS_DONE;
                break;
@@ -311,7 +343,7 @@ static int event_handler_cb(widget_buffer_h handler, struct widget_buffer_event_
                        break;
                }
                memset(&action_info, 0, sizeof(action_info));
-               action_type = ELM_ACCESS_ACTION_UP;
+               action_type = 0; //ELM_ACCESS_ACTION_UP;
                ret = elm_access_action(parent_elm, action_type, &action_info);
                ret = (ret == EINA_FALSE) ? WIDGET_ACCESS_STATUS_ERROR : WIDGET_ACCESS_STATUS_DONE;
                break;
@@ -322,7 +354,7 @@ static int event_handler_cb(widget_buffer_h handler, struct widget_buffer_event_
                        break;
                }
                memset(&action_info, 0, sizeof(action_info));
-               action_type = ELM_ACCESS_ACTION_DOWN;
+               action_type = 0; //ELM_ACCESS_ACTION_DOWN;
                ret = elm_access_action(parent_elm, action_type, &action_info);
                ret = (ret == EINA_FALSE) ? WIDGET_ACCESS_STATUS_ERROR : WIDGET_ACCESS_STATUS_DONE;
                break;
@@ -333,7 +365,7 @@ static int event_handler_cb(widget_buffer_h handler, struct widget_buffer_event_
                        break;
                }
                memset(&action_info, 0, sizeof(action_info));
-               action_type = ELM_ACCESS_ACTION_SCROLL;
+               action_type = 0; //ELM_ACCESS_ACTION_SCROLL;
                action_info.x = event_info->info.access.x;
                action_info.y = event_info->info.access.y;
                action_info.mouse_type = event_info->info.access.mouse_type;
@@ -347,7 +379,7 @@ static int event_handler_cb(widget_buffer_h handler, struct widget_buffer_event_
                        break;
                }
                memset(&action_info, 0, sizeof(action_info));
-               action_type = ELM_ACCESS_ACTION_SCROLL;
+               action_type = 0; //ELM_ACCESS_ACTION_SCROLL;
                action_info.x = event_info->info.access.x;
                action_info.y = event_info->info.access.y;
                action_info.mouse_type = event_info->info.access.mouse_type;
@@ -361,7 +393,7 @@ static int event_handler_cb(widget_buffer_h handler, struct widget_buffer_event_
                        break;
                }
                memset(&action_info, 0, sizeof(action_info));
-               action_type = ELM_ACCESS_ACTION_SCROLL;
+               action_type = 0; //ELM_ACCESS_ACTION_SCROLL;
                action_info.x = event_info->info.access.x;
                action_info.y = event_info->info.access.y;
                action_info.mouse_type = event_info->info.access.mouse_type;
@@ -375,7 +407,7 @@ static int event_handler_cb(widget_buffer_h handler, struct widget_buffer_event_
                        break;
                }
                memset(&action_info, 0, sizeof(action_info));
-               action_type = ELM_ACCESS_ACTION_UNHIGHLIGHT;
+               action_type = 0; //ELM_ACCESS_ACTION_UNHIGHLIGHT;
                ret = elm_access_action(parent_elm, action_type, &action_info);
                ret = (ret == EINA_FALSE) ? WIDGET_ACCESS_STATUS_ERROR : WIDGET_ACCESS_STATUS_DONE;
                break;
@@ -386,7 +418,7 @@ static int event_handler_cb(widget_buffer_h handler, struct widget_buffer_event_
                        break;
                }
                memset(&action_info, 0, sizeof(action_info));
-               action_type = ELM_ACCESS_ACTION_VALUE_CHANGE;
+               action_type = 0; //ELM_ACCESS_ACTION_VALUE_CHANGE;
                action_info.x = event_info->info.access.x;
                action_info.y = event_info->info.access.y;
                action_info.mouse_type = event_info->info.access.mouse_type;
@@ -400,7 +432,7 @@ static int event_handler_cb(widget_buffer_h handler, struct widget_buffer_event_
                        break;
                }
                memset(&action_info, 0, sizeof(action_info));
-               action_type = ELM_ACCESS_ACTION_MOUSE;
+               action_type = 0; //ELM_ACCESS_ACTION_MOUSE;
                action_info.x = event_info->info.access.x;
                action_info.y = event_info->info.access.y;
                action_info.mouse_type = event_info->info.access.mouse_type;
@@ -414,7 +446,7 @@ static int event_handler_cb(widget_buffer_h handler, struct widget_buffer_event_
                        break;
                }
                memset(&action_info, 0, sizeof(action_info));
-               action_type = ELM_ACCESS_ACTION_BACK;
+               action_type = 0; //ELM_ACCESS_ACTION_BACK;
                action_info.x = event_info->info.access.x;
                action_info.y = event_info->info.access.y;
                action_info.mouse_type = event_info->info.access.mouse_type;
@@ -428,7 +460,7 @@ static int event_handler_cb(widget_buffer_h handler, struct widget_buffer_event_
                        break;
                }
                memset(&action_info, 0, sizeof(action_info));
-               action_type = ELM_ACCESS_ACTION_OVER;
+               action_type = 0; //ELM_ACCESS_ACTION_OVER;
                action_info.x = event_info->info.access.x;
                action_info.y = event_info->info.access.y;
                action_info.mouse_type = event_info->info.access.mouse_type;
@@ -442,7 +474,7 @@ static int event_handler_cb(widget_buffer_h handler, struct widget_buffer_event_
                        break;
                }
                memset(&action_info, 0, sizeof(action_info));
-               action_type = ELM_ACCESS_ACTION_READ;
+               action_type = 0; //ELM_ACCESS_ACTION_READ;
                action_info.x = event_info->info.access.x;
                action_info.y = event_info->info.access.y;
                action_info.mouse_type = event_info->info.access.mouse_type;
@@ -456,7 +488,7 @@ static int event_handler_cb(widget_buffer_h handler, struct widget_buffer_event_
                        break;
                }
                memset(&action_info, 0, sizeof(action_info));
-               action_type = ELM_ACCESS_ACTION_ENABLE;
+               action_type = 0; //ELM_ACCESS_ACTION_ENABLE;
                action_info.x = event_info->info.access.x;
                action_info.y = event_info->info.access.y;
                action_info.mouse_type = event_info->info.access.mouse_type;
@@ -470,7 +502,7 @@ static int event_handler_cb(widget_buffer_h handler, struct widget_buffer_event_
                        break;
                }
                memset(&action_info, 0, sizeof(action_info));
-               action_type = ELM_ACCESS_ACTION_DISABLE;
+               action_type = 0; //ELM_ACCESS_ACTION_DISABLE;
                action_info.x = event_info->info.access.x;
                action_info.y = event_info->info.access.y;
                action_info.mouse_type = event_info->info.access.mouse_type;
@@ -569,15 +601,130 @@ static int event_handler_cb(widget_buffer_h handler, struct widget_buffer_event_
        return ret;
 }
 
+static Eina_Bool pended_event_consumer_cb(void *data)
+{
+       vwin_info_t info = data;
+       widget_buffer_event_data_t event_info;
+
+       event_info = eina_list_nth(info->pended_events_list, 0);
+       if (!event_info) {
+               info->pended_events_consumer = NULL;
+               return ECORE_CALLBACK_CANCEL;
+       }
+
+       DbgPrint("Consuming delayed events\n");
+       (void)processing_events(info, event_info, event_info->timestamp);
+
+       info->pended_events_list = eina_list_remove(info->pended_events_list, event_info);
+       free(event_info);
+       return ECORE_CALLBACK_RENEW;
+}
+
+/**
+ * @note
+ * Every user event (mouse) on the buffer will be passed via this event callback
+ */
+static int event_handler_cb(widget_buffer_h handler, widget_buffer_event_data_t event_info, void *data)
+{
+       vwin_info_t info = data;
+       double timestamp;
+
+       /**
+        * @note
+        * If the feeds event is accessibility or key event,
+        * "return 0" will confusing the viewer,
+        * because it will waiting result of event processing to do handles state properly.
+        */
+
+       if (!info || info->state != VWIN_INFO_CREATED || !info->handle || info->flags.field.deleted) {
+               /* Just ignore this event */
+               return 0;
+       }
+
+       if (event_info->type == WIDGET_BUFFER_EVENT_FRAME_SKIP_CLEARED) {
+               /**
+                * Increase the count_of_rendering only if it meets conditions.
+                * Or do not increase it to prevent from overflow problem.
+                * If we trying to increase the count_of_rendering variable, it could be overflowed.
+                * These conditions will prevents count_of_rendering from overflow issue.
+                */
+               if (info->pended_events_list && !info->pended_events_consumer) {
+                       info->pended_events_consumer = ecore_timer_add(0.0001f, pended_event_consumer_cb, info);
+                       if (info->pended_events_consumer) {
+                               ErrPrint("Failed to create a pended event consumer\n");
+                       }
+               }
+
+               return 0;
+       }
+
+       if (WIDGET_CONF_USE_GETTIMEOFDAY) {
+               if (WIDGET_CONF_EVENT_FILTER > 0.0f && (info->pressed == 0 || event_info->type == WIDGET_BUFFER_EVENT_MOVE)) {
+                       struct timeval tv;
+
+                       if (gettimeofday(&tv, NULL) < 0) {
+                               ErrPrint("gettimeofday: %d\n", errno);
+                       } else {
+                               timestamp = (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0f;
+                               timestamp -= event_info->timestamp;
+
+                               if (timestamp > WIDGET_CONF_EVENT_FILTER) {
+                                       DbgPrint("Dropped %lf\n", timestamp);
+                                       return 0;
+                               }
+                       }
+               }
+
+               /**
+                * If the device doesn't use the clock monotic time, we have to emulate it for EVAS
+                * Evas only use the monotic time for animating objects
+                */
+               timestamp = ecore_time_get() * 1000.0f;
+       } else {
+               if (WIDGET_CONF_EVENT_FILTER > 0.0f && (info->pressed == 0 || event_info->type == WIDGET_BUFFER_EVENT_MOVE)) {
+                       timestamp = ecore_time_get();
+
+                       timestamp -= event_info->timestamp;
+                       if (timestamp > WIDGET_CONF_EVENT_FILTER) {
+                               DbgPrint("Dropped %lf\n", timestamp);
+                               return 0;
+                       }
+               }
+
+               timestamp = event_info->timestamp * 1000.0f;
+       }
+
+       if ((info->w <= 1 && info->h <= 1) || widget_provider_buffer_frame_skip(info->handle) > 0 || info->pended_events_list) {
+               widget_buffer_event_data_t _ev_info;
+               _ev_info = malloc(sizeof(*_ev_info));
+               if (_ev_info) {
+                       memcpy(_ev_info, event_info, sizeof(*_ev_info));
+                       info->pended_events_list = eina_list_append(info->pended_events_list, _ev_info);
+                       _ev_info->timestamp = timestamp;
+                       /**
+                        * @note
+                        * Push events to pending list,.
+                        * Consuming it first.
+                        */
+                       DbgPrint("Canvas is not prepared. pending the events (%dx%d)\n", info->w, info->h);
+                       return 0;
+               } else {
+                       ErrPrint("malloc: %d\n", errno);
+               }
+       }
+
+       return processing_events(info, event_info, timestamp);
+}
+
 static void pre_render_cb(void *data, Evas *e, void *event_info)
 {
        vwin_info_t info = data;
 
-       if (!info->handle) {
+       if (!info || info->state != VWIN_INFO_CREATED || !info->handle) {
                return;
        }
 
-       if (widget_conf_premultiplied_alpha()) {
+       if (WIDGET_CONF_PREMULTIPLIED_COLOR) {
                Evas_Coord w;
                Evas_Coord h;
 
@@ -596,32 +743,43 @@ static void pre_render_cb(void *data, Evas *e, void *event_info)
        }
 }
 
+static inline void dump_to_file(void *buffer, int size, const char *fname)
+{
+       int fd;
+
+       fd = open(fname, O_WRONLY | O_CREAT, 0644);
+       if (fd >= 0) {
+               if (write(fd, buffer, size) != size) {
+                       ErrPrint("write: %d\n", errno);
+               }
+
+               if (close(fd) < 0) {
+                       ErrPrint("close: %d\n", errno);
+               }
+       }
+}
+
 static void post_render_cb(void *data, Evas *e, void *event_info)
 {
        vwin_info_t info = data;
+       const char *ee_key;
 
-       if (!info->handle) {
+       if (!info || info->state != VWIN_INFO_CREATED || !info->handle) {
                return;
        }
 
-       if (widget_conf_premultiplied_alpha()) {
-               void *canvas;
-               int x, y, w, h;
-
-               // Get a pointer of a buffer of the virtual canvas
-               canvas = (void *)ecore_evas_buffer_pixels_get(info->ee);
-               if (!canvas) {
-                       ErrPrint("Failed to get pixel canvas\n");
+       ee_key = WIDGET_CONF_EE_KEY_FOR_UPDATE;
+       if (ee_key) {
+               const char *value;
+               value = ecore_evas_data_get(info->ee, ee_key);
+               if (value && strcmp(value, "true")) {
+                       DbgPrint("Frame skipped[%s]\n", value);
                        return;
                }
-
-               ecore_evas_geometry_get(info->ee, &x, &y, &w, &h);
-               evas_data_argb_unpremul(canvas, w * h);
+               ecore_evas_data_set(info->ee, ee_key, "false");
        }
 
-       if (info->type == VWIN_GEM) {
-               widget_buffer_post_render(info->handle);
-       } else if (info->type == VWIN_PIXMAP) {
+       if (info->type == VWIN_PIXMAP) {
                int idx;
                unsigned int front_resource_id;
 
@@ -629,24 +787,111 @@ static void post_render_cb(void *data, Evas *e, void *event_info)
 
                for (idx = 0; idx < WIDGET_CONF_EXTRA_BUFFER_COUNT; idx++) {
                        if (front_resource_id == info->resource_array[idx]) {
-                               /**
-                                */
-                               widget_send_updated_by_idx(info->handle, idx);
                                break;
                        }
                }
 
                if (idx == WIDGET_CONF_EXTRA_BUFFER_COUNT) {
-                       /* Send updated event for PRIMARY BUFFER */
-                       if (front_resource_id == widget_viewer_get_resource_id(info->handle, WIDGET_PRIMARY_BUFFER)) {
-                               widget_send_updated_by_idx(info->handle, WIDGET_PRIMARY_BUFFER);
-                       } else {
-                               DbgPrint("Unable to send updated: %u (%u)\n", front_resource_id, widget_viewer_get_resource_id(info->handle, WIDGET_PRIMARY_BUFFER));
+                       idx = WIDGET_PRIMARY_BUFFER;
+               }
+
+               /* Send updated event for PRIMARY BUFFER */
+               if (front_resource_id == widget_viewer_get_resource_id(info->handle, idx)) {
+                       if (info->ctrl_mode.dump_to_file) {
+                               char fname[512];
+                               void *canvas;
+
+                               snprintf(fname, sizeof(fname) - 1, "/tmp/%s.%u.%lf.raw", widget_util_basename(info->id), front_resource_id, ecore_time_get());
+                               canvas = widget_provider_buffer_dump_frame(info->handle, idx);
+                               if (canvas) {
+                                       int w, h;
+                                       int size;
+
+                                       ecore_evas_geometry_get(info->ee, NULL, NULL, &w, &h);
+                                       size = w * h * sizeof(int);
+
+                                       dump_to_file(canvas, size, fname);
+                                       free(canvas);
+                               }
                        }
+                       widget_send_updated_by_idx(info->handle, idx);
+               } else {
+                       DbgPrint("Unable to send updated: %u (%u)\n", front_resource_id, widget_viewer_get_resource_id(info->handle, idx));
                }
-       } else if (info->type == VWIN_SW_BUF) {
-               widget_viewer_sync_buffer(info->handle);
+       } else {
+               if (WIDGET_CONF_PREMULTIPLIED_COLOR) {
+                       void *canvas;
+                       int w, h;
+
+                       // Get a pointer of a buffer of the virtual canvas
+                       canvas = (void *)ecore_evas_buffer_pixels_get(info->ee);
+                       if (!canvas) {
+                               ErrPrint("Failed to get pixel canvas\n");
+                               return;
+                       }
+
+                       ecore_evas_geometry_get(info->ee, NULL, NULL, &w, &h);
+                       evas_data_argb_unpremul(canvas, w * h);
+               }
+
+               if (info->ctrl_mode.dump_to_file) {
+                       void *canvas;
+                       char fname[512];
+                       int size;
+                       int w, h;
+
+                       canvas = (void *)ecore_evas_buffer_pixels_get(info->ee);
+                       if (!canvas) {
+                               ErrPrint("Failed to get pixel canvas\n");
+                               return;
+                       }
+
+                       /**
+                        * TODO
+                        * Save to a file
+                        */
+                       ecore_evas_geometry_get(info->ee, NULL, NULL, &w, &h);
+                       size = w * h * sizeof(int);
+
+                       snprintf(fname, sizeof(fname) - 1, "/tmp/%s.%lf.raw", widget_util_basename(info->id), ecore_time_get());
+                       dump_to_file(canvas, size, fname);
+               }
+
+               if (info->type == VWIN_GEM) {
+                       widget_buffer_post_render(info->handle);
+               } else if (info->type == VWIN_SW_BUF) {
+                       widget_viewer_sync_buffer(info->handle);
+               }
+       }
+}
+
+static int pre_ctrl_mode_cb(const char *id, void *data)
+{
+       vwin_info_t info = data;
+       const char *path;
+       int cmd;
+       int value;
+
+       /* Try provider_app first */
+       if (!info || info->state != VWIN_INFO_CREATED || !id || !info->id) {
+               return WIDGET_ERROR_INVALID_PARAMETER;
+       }
+
+       path = widget_util_uri_to_path(id);
+       if (path && strcmp(info->id, path)) {
+               /* Skip */
+               DbgPrint("SKIP: Pre orientation event callback is called [%s], %s\n", id, info->id);
+               return WIDGET_ERROR_INVALID_PARAMETER;
        }
+
+       widget_get_last_ctrl_mode(path, &cmd, &value);
+
+       if (cmd == WIDGET_CTRL_MODE_DUMP_FRAME) {
+               info->ctrl_mode.dump_to_file = !!value;
+               DbgPrint("CtrlMode: DumpToFile: %d\n", info->ctrl_mode.dump_to_file);
+       }
+
+       return WIDGET_ERROR_NONE;
 }
 
 static int pre_orientation_cb(const char *id, void *data)
@@ -656,7 +901,7 @@ static int pre_orientation_cb(const char *id, void *data)
        int orientation;
 
        /* Try provider_app first */
-       if (!id) {
+       if (!info || info->state != VWIN_INFO_CREATED || !id || !info->id) {
                return WIDGET_ERROR_INVALID_PARAMETER;
        }
 
@@ -683,6 +928,10 @@ static int pre_destroy_cb(const char *id, void *data)
        vwin_info_t info = data;
        const char *path = NULL;
 
+       if (!info || info->state != VWIN_INFO_CREATED) {
+               return WIDGET_ERROR_INVALID_PARAMETER;
+       }
+
        if (id) {
                path = widget_util_uri_to_path(id);
 
@@ -707,20 +956,33 @@ static void ecore_evas_free_cb(Ecore_Evas *ee)
 {
        vwin_info_t info;
 
-       info = ecore_evas_data_get(ee, "dynamic,box,info");
+       info = ecore_evas_data_get(ee, WIN_INFO_TAG);
        if (!info) {
                DbgPrint("Info is not valid\n");
                return;
        }
 
+       if (info->pended_events_consumer) {
+               widget_buffer_event_data_t event_info;
+
+               DbgPrint("Clearing pended event consumer\n");
+               ecore_timer_del(info->pended_events_consumer);
+               info->pended_events_consumer = NULL;
+
+               EINA_LIST_FREE(info->pended_events_list, event_info) {
+                       free(event_info);
+               }
+       }
+
        widget_del_pre_callback(WIDGET_PRE_DESTROY_CALLBACK, pre_destroy_cb, info);
+       widget_del_pre_callback(WIDGET_PRE_CTRL_MODE_CALLBACK, pre_ctrl_mode_cb, info);
 
        if (info->e) {
                evas_event_callback_del(info->e, EVAS_CALLBACK_RENDER_POST, post_render_cb);
                evas_event_callback_del(info->e, EVAS_CALLBACK_RENDER_PRE, pre_render_cb);
        }
 
-       info->deleted = 1;
+       info->flags.field.deleted = 1;
        info->ee = NULL;
 }
 
@@ -750,28 +1012,32 @@ PUBLIC Evas *widget_get_evas(const char *id)
                return NULL;
        }
 
+       info->state = VWIN_INFO_CREATED;
+
        info->id = strdup(id);
        if (!info->id) {
                ErrPrint("Heap: %d\n", errno);
+               info->state = VWIN_INFO_DESTROYED;
                free(info);
                return NULL;
        }
 
 #ifdef WIDGET_FEATURE_GBAR_SUPPORTED
-       info->is_gbar = is_gbar;
+       info->flags.field.is_gbar = is_gbar;
 #else
-       info->is_gbar = 0;
+       info->flags.field.is_gbar = 0;
 #endif /* WIDGET_FEATURE_GBAR_SUPPORTED */
 
        /**
         * Acquire a buffer for canvas.
         */
-       info->handle = widget_create_buffer(info->id, info->is_gbar,
+       info->handle = widget_create_buffer(info->id, info->flags.field.is_gbar,
                        binder_widget_auto_align(),
                        event_handler_cb, info);
 
        if (!info->handle) {
                ErrPrint("Failed to create a widget buffer\n");
+               info->state = VWIN_INFO_DESTROYED;
                free(info->id);
                free(info);
                return NULL;
@@ -787,12 +1053,13 @@ PUBLIC Evas *widget_get_evas(const char *id)
        if (!info->ee) {
                ErrPrint("Failed to create ecore_evas (%dx%d)\n", info->w, info->h);
                widget_destroy_buffer(info->handle);
+               info->state = VWIN_INFO_DESTROYED;
                free(info->id);
                free(info);
                return NULL;
        }
 
-       ecore_evas_data_set(info->ee, "dynamic,box,info", info);
+       ecore_evas_data_set(info->ee, WIN_INFO_TAG, info);
 
        /**
         * @note
@@ -819,6 +1086,7 @@ PUBLIC Evas *widget_get_evas(const char *id)
 
        widget_add_pre_callback(WIDGET_PRE_DESTROY_CALLBACK, pre_destroy_cb, info);
        widget_add_pre_callback(WIDGET_PRE_ORIENTATION_CALLBACK, pre_orientation_cb, info);
+       widget_add_pre_callback(WIDGET_PRE_CTRL_MODE_CALLBACK, pre_ctrl_mode_cb, info);
 
        orientation = widget_get_orientation(info->id);
        if (orientation < 0) {