e_service_vttouch: supports virtual touch function 99/317799/1
authorjeon <jhyuni.kang@samsung.com>
Wed, 17 Jul 2024 07:32:19 +0000 (16:32 +0900)
committerJihoon Kim <jihoon48.kim@samsung.com>
Wed, 8 Jan 2025 05:39:49 +0000 (14:39 +0900)
Change-Id: Ie565d69ffdafea0283f176b97c261eeba8eb037b

13 files changed:
src/bin/Makefile.mk
src/bin/compmgr/e_comp_object.c
src/bin/core/e_client.c
src/bin/core/e_client_intern.h
src/bin/core/e_zone.c
src/bin/e_main.c
src/bin/inputmgr/services/e_service_virtual_touch.c [new file with mode: 0644]
src/bin/inputmgr/services/e_service_virtual_touch_intern.h [new file with mode: 0644]
src/bin/server/e_comp_wl.c
src/bin/windowmgr/e_magnifier.c
src/bin/windowmgr/services/e_service_gesture.c
src/bin/windowmgr/services/e_service_volume.c
src/include/e_service_virtual_touch.h [new file with mode: 0644]

index 6d5cc2a8b944946345db98abc041e1815fc23690..2d5cf1eb686d0dd5ce41166fc3c4f375b1acdf60 100644 (file)
@@ -6,6 +6,7 @@ E_CPPFLAGS = \
 -I$(top_builddir)/src/bin/server \
 -I$(top_builddir)/src/bin/windowmgr/services \
 -I$(top_builddir)/src/bin/windowmgr \
+-I$(top_builddir)/src/bin/inputmgr/services \
 -I$(top_builddir)/src/bin/inputmgr \
 -I$(top_builddir)/src/bin/compmgr \
 -I$(top_builddir)/src/bin/displaymgr \
@@ -20,6 +21,7 @@ E_CPPFLAGS = \
 -I$(top_srcdir)/src/bin/server \
 -I$(top_srcdir)/src/bin/windowmgr/services \
 -I$(top_srcdir)/src/bin/windowmgr \
+-I$(top_srcdir)/src/bin/inputmgr/services \
 -I$(top_srcdir)/src/bin/inputmgr \
 -I$(top_srcdir)/src/bin/compmgr \
 -I$(top_srcdir)/src/bin/displaymgr \
@@ -102,6 +104,7 @@ src/include/e_comp_wl_capture.h \
 src/include/e_service_gesture.h \
 src/include/e_service_quickpanel.h \
 src/include/e_service_softkey.h \
+src/include/e_service_virtual_touch.h \
 src/include/e_policy.h \
 src/include/e_policy_conformant.h \
 src/include/e_policy_visibility.h \
@@ -230,6 +233,7 @@ src/bin/windowmgr/e_magnifier.c \
 src/bin/windowmgr/e_layout.c \
 src/bin/windowmgr/e_place.c \
 src/bin/windowmgr/e_maximize.c \
+src/bin/inputmgr/services/e_service_virtual_touch.c \
 src/bin/inputmgr/e_comp_input.c \
 src/bin/inputmgr/e_mouse.c \
 src/bin/inputmgr/e_input.c \
index d65c5878c20de19cd490f1ce39d523888a3742f4..e0fee72f9f1dea3eccd1a47976235d6b5a8c94be 100644 (file)
@@ -735,6 +735,7 @@ _e_comp_object_cb_mouse_down(void *data, Evas *e EINA_UNUSED, Evas_Object *obj E
    E_Comp_Object *cw = data;
    E_Binding_Event_Mouse_Button ev2;
 
+   if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return;
    if (!cw->ec) return;
    if (e_client_action_get()) return;
    e_bindings_evas_event_mouse_down_button_convert(ev, &ev2);
@@ -749,6 +750,7 @@ _e_comp_object_cb_mouse_up(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EIN
    E_Comp_Object *cw = data;
    E_Binding_Event_Mouse_Button ev2;
 
+   if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return;
    if (!cw->ec) return;
    if (e_client_action_get() && (e_client_action_get() != cw->ec)) return;
    e_bindings_evas_event_mouse_up_button_convert(ev, &ev2);
@@ -762,6 +764,7 @@ _e_comp_object_cb_mouse_move(void *data, Evas *e EINA_UNUSED, Evas_Object *obj E
    Evas_Event_Mouse_Move *ev = event_info;
    E_Comp_Object *cw = data;
 
+   if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return;
    if (!cw->ec) return;
    if (e_client_action_get() && (e_client_action_get() != cw->ec)) return;
    e_client_mouse_move(cw->ec, &ev->cur.output);
@@ -4672,8 +4675,10 @@ _e_comp_object_autoclose_cleanup(Eina_Bool already_del)
 }
 
 static void
-_e_comp_object_autoclose_mouse_up_cb(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
+_e_comp_object_autoclose_mouse_up_cb(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info)
 {
+   Evas_Event_Mouse_Up *ev = event_info;
+   if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return;
    _e_comp_object_autoclose_cleanup(0);
 }
 
index 8d505e4ec08b021251c185b2aca28ae18d0cd8ba..c7e3b78769340be36baba2c9f6eae5d716f29f76 100644 (file)
@@ -117,6 +117,7 @@ struct _E_Client_Private
         struct wl_signal stay_within_margin;
         struct wl_signal mouse_move;
         struct wl_signal resize_end;
+        struct wl_signal virtual_touch;
      } events;
 
    Eina_Bool hide_by_request;
@@ -134,6 +135,13 @@ struct _E_Client_Private
       unsigned int w, h;
       Eina_Bool apply;
    } layout_info;
+
+   struct
+     {
+        Eina_Bool enable;
+        int       fingers;
+        int       threshold;
+     } virtual_touch;
 };
 
 static int _e_client_hooks_delete = 0;
@@ -1052,6 +1060,8 @@ _e_client_private_init(E_Client *ec)
    wl_signal_init(&priv->events.mouse_move);
    wl_signal_init(&priv->events.resize_end);
 
+   wl_signal_init(&priv->events.virtual_touch);
+
    e_object_data_set(E_OBJECT(ec), priv);
 
    return EINA_TRUE;
@@ -7308,6 +7318,13 @@ e_client_resize_end_listener_add(E_Client *ec, struct wl_listener *listener)
    wl_signal_add(&priv->events.resize_end, listener);
 }
 
+EINTERN void
+e_client_virtual_touch_listener_add(E_Client *ec, struct wl_listener *listener)
+{
+   API_ENTRY;
+   wl_signal_add(&priv->events.virtual_touch, listener);
+}
+
 EINTERN void
 e_client_shell_configure_send(E_Client *ec, uint32_t edges, int32_t width, int32_t height)
 {
@@ -8743,6 +8760,67 @@ e_client_vkbd_vkbd_get(E_Client *ec)
    return ec->vkbd.vkbd;
 }
 
+E_API void
+e_client_virtual_touch_enable_set(E_Client *ec, Eina_Bool set)
+{
+   API_ENTRY;
+
+   priv->virtual_touch.enable = set;
+
+   /* FIXME: This code set default values for virtual touch.
+    *        If an user set values using other functions,
+    *        these values are overwrited.
+    *        Plz consider how to get default values insteads of hard coding.
+    */
+   if (set)
+     {
+        if (priv->virtual_touch.fingers <= 0)
+          priv->virtual_touch.fingers = 1;
+        if (priv->virtual_touch.threshold <= 0)
+          priv->virtual_touch.threshold = 100;
+     }
+
+   wl_signal_emit(&priv->events.virtual_touch, ec);
+}
+
+E_API Eina_Bool
+e_client_virtual_touch_enable_get(E_Client *ec)
+{
+   API_ENTRY_VAL(EINA_FALSE);
+
+   return priv->virtual_touch.enable;
+}
+
+E_API void
+e_client_virtual_touch_finger_set(E_Client *ec, int fingers)
+{
+   API_ENTRY;
+   priv->virtual_touch.fingers = fingers;
+}
+
+E_API int
+e_client_virtual_touch_finger_get(E_Client *ec)
+{
+   API_ENTRY_VAL(-1);
+
+   return priv->virtual_touch.fingers;
+}
+
+E_API void
+e_client_virtual_touch_threshold_set(E_Client *ec, int threshold)
+{
+   API_ENTRY;
+   priv->virtual_touch.threshold = threshold;
+}
+
+E_API int
+e_client_virtual_touch_threshold_get(E_Client *ec)
+{
+   API_ENTRY_VAL(-1);
+
+   return priv->virtual_touch.threshold;
+}
+
 /////////////////////////////////////////////////////////
 EINTERN E_Comp_Wl_Subsurf_Data *
 e_client_subsurface_data_try_get(E_Client *ec)
index ae41fb1208874f46dfe7cf456eeb198c0f931362..c5db9373d6971e1e89c23805cb61f2e8996c6140 100644 (file)
@@ -249,6 +249,7 @@ EINTERN void e_client_ping_listener_add(E_Client *ec, struct wl_listener *listen
 EINTERN void e_client_stay_within_margin_listener_add(E_Client *ec, struct wl_listener *listener);
 EINTERN void e_client_mouse_move_listener_add(E_Client *ec, struct wl_listener *listener);
 EINTERN void e_client_resize_end_listener_add(E_Client *ec, struct wl_listener *listener);
+EINTERN void e_client_virtual_touch_listener_add(E_Client *ec, struct wl_listener *listener);
 
 EINTERN struct wl_listener  *e_client_destroy_listener_get(E_Client *ec, wl_notify_func_t notify);
 
@@ -265,4 +266,12 @@ EINTERN void e_client_resize_handle(E_Client *ec);
 EINTERN int  e_client_resize_end(E_Client *ec);
 
 E_Comp_Wl_Subsurf_Data *e_client_subsurface_data_try_get(E_Client *ec);
+
+void      e_client_virtual_touch_enable_set(E_Client *ec, Eina_Bool set);
+Eina_Bool e_client_virtual_touch_enable_get(E_Client *ec);
+void      e_client_virtual_touch_finger_set(E_Client *ec, int fingers);
+int       e_client_virtual_touch_finger_get(E_Client *ec);
+void      e_client_virtual_touch_threshold_set(E_Client *ec, int threshold);
+int       e_client_virtual_touch_threshold_get(E_Client *ec);
+
 #endif
index 0152d39b85b68db145e09a369a01c4a2866872d2..0c3370622e7085f57670a80182fcbfb906bdce3a 100644 (file)
@@ -743,6 +743,9 @@ _e_zone_cb_bg_mouse_down(void *data,
                          void *event_info)
 {
    E_Zone *zone;
+   Evas_Event_Mouse_Down *ev = event_info;
+
+   if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return;
 
    zone = data;
    wl_signal_emit(&PRI(zone)->events.bg_mouse_down, event_info);
@@ -755,6 +758,9 @@ _e_zone_cb_bg_mouse_up(void *data,
                        void *event_info)
 {
    E_Zone *zone;
+   Evas_Event_Mouse_Up *ev = event_info;
+
+   if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return;
 
    zone = data;
 
index 761c20e00cb01f5dadbfdc869b451da0e8399a01..3d1587a6178b369bd9bc5177c1f131e5d2b5c540 100644 (file)
@@ -35,6 +35,7 @@
 #include "e_input_intern.h"
 #include "e_input_backend_intern.h"
 #include "e_comp_screen_intern.h"
+#include "e_service_virtual_touch_intern.h"
 
 #include <Eio.h>
 
@@ -760,6 +761,15 @@ main(int argc, char **argv)
    TSE("E_Process Init Done");
    _e_main_shutdown_push(e_process_shutdown);
 
+   TSB("E_Service_Virtual_Touch Init");
+   if (!e_service_virtual_touch_init())
+     {
+        e_error_message_show(_("Enlightenment cannot set up its virtual touch service.\n"));
+        goto failed;
+     }
+   TSE("E_Service_Virtual_Touch Init Done");
+   _e_main_shutdown_push(e_service_virtual_touch_deinit);
+
    TSB("Load Modules");
    e_module_all_load();
    TSE("Load Modules Done");
diff --git a/src/bin/inputmgr/services/e_service_virtual_touch.c b/src/bin/inputmgr/services/e_service_virtual_touch.c
new file mode 100644 (file)
index 0000000..9f2bb01
--- /dev/null
@@ -0,0 +1,828 @@
+#include "e_service_virtual_touch_intern.h"
+#include "e_client_intern.h"
+#include "e_comp_wl_intern.h"
+#include "e_utils_intern.h"
+
+#define MAX_FINGERS 10
+#define E_SERVICE_GESTURE_KEY "e_service_gesture_enabled"
+#define DEFAULT_START_TIME (0.3) // ms
+
+typedef struct _E_Service_Virtual_Touch E_Service_Virtual_Touch;
+typedef struct _E_Service_Virtual_Touch_Private_Client E_Service_Virtual_Touch_Private_Client;
+typedef struct _E_Service_Virtual_Touch_Event_Data E_Service_Virtual_Touch_Event_Data;
+typedef struct _E_Service_Virtual_Touch_Cb_Data E_Service_Virtual_Touch_Cb_Data;
+
+typedef enum _E_Service_Virtual_Touch_EventState
+{
+   E_SERVICE_VIRTUAL_TOUCH_EVENTSTATE_IGNORE, // Refeeding kept events, ignore all events during this state
+   E_SERVICE_VIRTUAL_TOUCH_EVENTSTATE_READY,
+   E_SERVICE_VIRTUAL_TOUCH_EVENTSTATE_UPDATE,
+   E_SERVICE_VIRTUAL_TOUCH_EVENTSTATE_END,
+   E_SERVICE_VIRTUAL_TOUCH_EVENTSTATE_CANCEL
+} E_Service_Virtual_Touch_EventState;
+
+struct _E_Service_Virtual_Touch_Event_Data
+{
+   void *event;
+   Evas_Callback_Type type;
+   Evas_Object *obj;
+};
+
+struct _E_Service_Virtual_Touch
+{
+   Evas_Object *obj;
+   Ecore_Event_Handler *handler_client_add;
+
+   E_Service_Virtual_Touch_State state;
+   E_Service_Virtual_Touch_EventState event_state;
+
+   Ecore_Timer *start_timer;
+
+   unsigned int pressed_fingers;
+
+   E_Client *ec_event;
+
+   struct
+     {
+        Eina_List *ec;
+        Eina_List *cb;
+        Eina_List *queued_event;
+     } list;
+
+   struct
+     {
+        Evas_Coord_Point prev;
+        Evas_Coord_Point cur;
+     } point;
+
+   struct
+     {
+        Eina_Bool pressed; /* to avoid processing that happened mouse move right after mouse up */
+        Evas_Coord_Point coord;
+     } touch_info[MAX_FINGERS];
+};
+
+struct _E_Service_Virtual_Touch_Cb_Data
+{
+   E_Service_Virtual_Touch_Cb func;
+   void *data;
+};
+
+struct _E_Service_Virtual_Touch_Private_Client
+{
+   E_Client *ec;
+
+   struct wl_listener client_destroy;
+   struct wl_listener client_virtual_touch;
+};
+
+/* TODO: Someday when you consider multi user's touch like multiseat in the future,
+ *       you need to consider to maintain E_Service_Virtual_Touch structure not globally.
+ *       Maybe each users are need to one of E_Service_Virtual_Touch structure,
+ *       to distinguish touch behavior.
+ */
+E_Service_Virtual_Touch *virtual_touch;
+
+static void
+_e_service_virtual_touch_util_center_point_get(int *cx, int *cy)
+{
+   int i;
+   int _x = 0, _y = 0;
+
+   if (virtual_touch->pressed_fingers <= 0) goto finish;
+
+   for (i = 0; i < virtual_touch->pressed_fingers; i++)
+     {
+        _x += virtual_touch->touch_info[i].coord.x;
+        _y += virtual_touch->touch_info[i].coord.y;
+     }
+
+   _x = (int)(_x / virtual_touch->pressed_fingers);
+   _y = (int)(_y / virtual_touch->pressed_fingers);
+
+finish:
+   *cx = _x;
+   *cy = _y;
+}
+
+static void
+_e_service_virtual_touch_event_keep(Evas_Object *obj, Evas_Callback_Type type, void *event)
+{
+   E_Service_Virtual_Touch_Event_Data *ev_data;
+   ev_data = E_NEW(E_Service_Virtual_Touch_Event_Data, 1);
+   EINA_SAFETY_ON_NULL_RETURN(ev_data);
+
+   ev_data->type = type;
+   /* NOTE: This is just pointer address copy for Evas_Object not using efl_ref().
+    *       Because during event keep, touch is not finished.
+    *       So this touched Evas_Object will be alive during touch.
+    */
+   ev_data->obj = obj;
+
+   if (type == EVAS_CALLBACK_MOUSE_DOWN)
+     {
+        ev_data->event = E_NEW(Evas_Event_Mouse_Down, 1);
+        EINA_SAFETY_ON_NULL_GOTO(ev_data->event, alloc_fail);
+        memcpy(ev_data->event, event, sizeof(Evas_Event_Mouse_Down));
+     }
+   else if (type == EVAS_CALLBACK_MOUSE_MOVE)
+     {
+        ev_data->event = E_NEW(Evas_Event_Mouse_Move, 1);
+        EINA_SAFETY_ON_NULL_GOTO(ev_data->event, alloc_fail);
+        memcpy(ev_data->event, event, sizeof(Evas_Event_Mouse_Move));
+     }
+   else if (type == EVAS_CALLBACK_MOUSE_UP)
+     {
+        ev_data->event = E_NEW(Evas_Event_Mouse_Up, 1);
+        EINA_SAFETY_ON_NULL_GOTO(ev_data->event, alloc_fail);
+        memcpy(ev_data->event, event, sizeof(Evas_Event_Mouse_Up));
+     }
+   else if (type == EVAS_CALLBACK_MULTI_DOWN)
+     {
+        ev_data->event = E_NEW(Evas_Event_Multi_Down, 1);
+        EINA_SAFETY_ON_NULL_GOTO(ev_data->event, alloc_fail);
+        memcpy(ev_data->event, event, sizeof(Evas_Event_Multi_Down));
+     }
+   else if (type == EVAS_CALLBACK_MULTI_MOVE)
+     {
+        ev_data->event = E_NEW(Evas_Event_Multi_Move, 1);
+        EINA_SAFETY_ON_NULL_GOTO(ev_data->event, alloc_fail);
+        memcpy(ev_data->event, event, sizeof(Evas_Event_Multi_Move));
+     }
+   else if (type == EVAS_CALLBACK_MULTI_UP)
+     {
+        ev_data->event = E_NEW(Evas_Event_Multi_Up, 1);
+        EINA_SAFETY_ON_NULL_GOTO(ev_data->event, alloc_fail);
+        memcpy(ev_data->event, event, sizeof(Evas_Event_Multi_Up));
+     }
+   else
+     {
+        WRN("[Virtualtouch] Invalid event type try to keep event.\n");
+        goto alloc_fail;
+     }
+
+   virtual_touch->list.queued_event = eina_list_append(virtual_touch->list.queued_event, ev_data);
+   return;
+
+alloc_fail:
+   E_FREE(ev_data);
+}
+
+static void
+_e_service_virtual_touch_event_flush(void)
+{
+   Eina_List *l, *ll;
+   E_Service_Virtual_Touch_Event_Data *ev_data;
+   E_Service_Virtual_Touch_EventState prev_state;
+
+   prev_state = virtual_touch->event_state;
+   virtual_touch->event_state = E_SERVICE_VIRTUAL_TOUCH_EVENTSTATE_IGNORE;
+
+   EINA_LIST_FOREACH_SAFE(virtual_touch->list.queued_event, l, ll, ev_data)
+     {
+        Evas *e = evas_object_evas_get(ev_data->obj);
+        evas_event_refeed_event(e, ev_data->event, ev_data->type);
+        virtual_touch->list.queued_event = eina_list_remove_list(virtual_touch->list.queued_event, l);
+        E_FREE(ev_data->event);
+        E_FREE(ev_data);
+     }
+   virtual_touch->list.queued_event = NULL;
+   virtual_touch->event_state = prev_state;
+}
+
+static void
+_e_service_virtual_touch_cancel()
+{
+   E_FREE_FUNC(virtual_touch->start_timer, ecore_timer_del);
+
+   if (virtual_touch->event_state == E_SERVICE_VIRTUAL_TOUCH_EVENTSTATE_READY)
+     {
+        if (virtual_touch->state == E_SERVICE_VIRTUAL_TOUCH_STATE_EVENTKEEP)
+          {
+             _e_service_virtual_touch_event_flush();
+          }
+     }
+   virtual_touch->event_state = E_SERVICE_VIRTUAL_TOUCH_EVENTSTATE_CANCEL;
+}
+
+static void
+_e_service_virtual_touch_drop(void)
+{
+   Eina_List *l, *ll;
+   E_Service_Virtual_Touch_Event_Data *ev_data;
+
+   EINA_LIST_FOREACH_SAFE(virtual_touch->list.queued_event, l, ll, ev_data)
+     {
+        virtual_touch->list.queued_event = eina_list_remove_list(virtual_touch->list.queued_event, l);
+        E_FREE(ev_data->event);
+        E_FREE(ev_data);
+     }
+   virtual_touch->list.queued_event = NULL;
+}
+
+static void
+_e_service_virtual_touch_cancel_send(void)
+{
+   EINA_SAFETY_ON_NULL_RETURN(virtual_touch->ec_event);
+
+   e_comp_wl_touch_cancel_send(virtual_touch->ec_event);
+}
+
+static void
+_e_service_virtual_touch_generate(E_Client *ec, E_Service_Virtual_Touch_Mode mode, int nfingers, int dx, int dy, unsigned int timestamp)
+{
+   Eina_List *l;
+   E_Service_Virtual_Touch_Cb_Data *cb_data;
+
+   if (mode == E_SERVICE_VIRTUAL_TOUCH_MODE_BEGIN)
+     {
+        E_FREE_FUNC(virtual_touch->start_timer, ecore_timer_del);
+        if (virtual_touch->state == E_SERVICE_VIRTUAL_TOUCH_STATE_EVENTKEEP)
+          {
+             _e_service_virtual_touch_drop();
+          }
+        else if (virtual_touch->state == E_SERVICE_VIRTUAL_TOUCH_STATE_CANCEL)
+          {
+             _e_service_virtual_touch_cancel_send();
+          }
+        virtual_touch->event_state = E_SERVICE_VIRTUAL_TOUCH_EVENTSTATE_UPDATE;
+     }
+   else if (mode == E_SERVICE_VIRTUAL_TOUCH_MODE_END)
+     {
+        virtual_touch->ec_event = NULL;
+        virtual_touch->event_state = E_SERVICE_VIRTUAL_TOUCH_EVENTSTATE_END;
+     }
+
+   EINA_LIST_FOREACH(virtual_touch->list.cb, l, cb_data)
+     {
+        cb_data->func(cb_data->data, ec, mode, nfingers, dx, dy, timestamp);
+     }
+}
+
+static Eina_Bool
+_e_service_virtual_touch_start_timer(void *data)
+{
+   _e_service_virtual_touch_cancel();
+
+   E_FREE_FUNC(virtual_touch->start_timer, ecore_timer_del);
+
+   return ECORE_CALLBACK_CANCEL;
+}
+
+static E_Service_Virtual_Touch_EventState
+_e_service_virtual_touch_touch_up(E_Client *ec, int idx, int x, int y, unsigned int timestamp)
+{
+   if (virtual_touch->event_state == E_SERVICE_VIRTUAL_TOUCH_EVENTSTATE_IGNORE)
+     {
+        return E_SERVICE_VIRTUAL_TOUCH_EVENTSTATE_IGNORE;
+     }
+
+   virtual_touch->pressed_fingers--;
+   virtual_touch->touch_info[idx].pressed = EINA_FALSE;
+   EINA_SAFETY_ON_NULL_RETURN_VAL(ec, E_SERVICE_VIRTUAL_TOUCH_EVENTSTATE_IGNORE);
+
+   virtual_touch->touch_info[idx].coord.x = x;
+   virtual_touch->touch_info[idx].coord.y = y;
+
+   if ((virtual_touch->event_state == E_SERVICE_VIRTUAL_TOUCH_EVENTSTATE_END) ||
+       (virtual_touch->event_state == E_SERVICE_VIRTUAL_TOUCH_EVENTSTATE_CANCEL))
+     {
+        return virtual_touch->event_state;
+     }
+
+   if (virtual_touch->event_state == E_SERVICE_VIRTUAL_TOUCH_EVENTSTATE_READY)
+     {
+        _e_service_virtual_touch_cancel();
+     }
+   else
+     {
+        _e_service_virtual_touch_generate(ec, E_SERVICE_VIRTUAL_TOUCH_MODE_END, virtual_touch->pressed_fingers, virtual_touch->point.cur.x, virtual_touch->point.cur.y, timestamp);
+     }
+
+   return virtual_touch->event_state;
+}
+
+static E_Service_Virtual_Touch_EventState
+_e_service_virtual_touch_touch_move(E_Client *ec, int idx, int x, int y, unsigned int timestamp)
+{
+   int cx = 0, cy = 0;
+   int dx = 0, dy = 0;
+
+   if (virtual_touch->event_state == E_SERVICE_VIRTUAL_TOUCH_EVENTSTATE_IGNORE)
+     {
+        return E_SERVICE_VIRTUAL_TOUCH_EVENTSTATE_IGNORE;
+     }
+
+   if (!virtual_touch->touch_info[idx].pressed)
+     return E_SERVICE_VIRTUAL_TOUCH_EVENTSTATE_IGNORE;
+
+   virtual_touch->touch_info[idx].coord.x = x;
+   virtual_touch->touch_info[idx].coord.y = y;
+
+   if ((virtual_touch->event_state == E_SERVICE_VIRTUAL_TOUCH_EVENTSTATE_END) ||
+       (virtual_touch->event_state == E_SERVICE_VIRTUAL_TOUCH_EVENTSTATE_CANCEL))
+     {
+        return virtual_touch->event_state;
+     }
+
+   _e_service_virtual_touch_util_center_point_get(&cx, &cy);
+   dx = ABS(virtual_touch->point.prev.x - cx);
+   dy = ABS(virtual_touch->point.prev.y - cy);
+   virtual_touch->point.cur.x = cx;
+   virtual_touch->point.cur.y = cy;
+
+   if ((dx >= e_client_virtual_touch_threshold_get(ec)) ||
+       (dy >= e_client_virtual_touch_threshold_get(ec)))
+     {
+        if (virtual_touch->event_state == E_SERVICE_VIRTUAL_TOUCH_EVENTSTATE_READY)
+          {
+             _e_service_virtual_touch_generate(ec, E_SERVICE_VIRTUAL_TOUCH_MODE_BEGIN, virtual_touch->pressed_fingers, cx, cy, timestamp);
+          }
+        else
+          {
+             _e_service_virtual_touch_generate(ec, E_SERVICE_VIRTUAL_TOUCH_MODE_UPDATE, virtual_touch->pressed_fingers, cx, cy, timestamp);
+          }
+        virtual_touch->point.prev.x = cx;
+        virtual_touch->point.prev.y = cy;
+     }
+
+   return virtual_touch->event_state;
+}
+
+static E_Service_Virtual_Touch_EventState
+_e_service_virtual_touch_touch_down(E_Client *ec, int idx, int x, int y, unsigned int timestamp)
+{
+   int cx = 0, cy = 0;
+
+   if (virtual_touch->event_state == E_SERVICE_VIRTUAL_TOUCH_EVENTSTATE_IGNORE)
+     {
+        return E_SERVICE_VIRTUAL_TOUCH_EVENTSTATE_IGNORE;
+     }
+
+   virtual_touch->pressed_fingers++;
+   virtual_touch->touch_info[idx].pressed = EINA_TRUE;
+   virtual_touch->touch_info[idx].coord.x = x;
+   virtual_touch->touch_info[idx].coord.y = y;
+   EINA_SAFETY_ON_NULL_RETURN_VAL(ec, E_SERVICE_VIRTUAL_TOUCH_EVENTSTATE_IGNORE);
+
+   // first finger pressed, check conditions.
+   if (virtual_touch->pressed_fingers == 1)
+     {
+        virtual_touch->ec_event = ec;
+        virtual_touch->start_timer = ecore_timer_add(DEFAULT_START_TIME, _e_service_virtual_touch_start_timer, (void *)virtual_touch);
+     }
+
+   if ((virtual_touch->event_state == E_SERVICE_VIRTUAL_TOUCH_EVENTSTATE_END) ||
+       (virtual_touch->event_state == E_SERVICE_VIRTUAL_TOUCH_EVENTSTATE_CANCEL))
+     {
+        return virtual_touch->event_state;
+     }
+
+   virtual_touch->touch_info[idx].coord.x = x;
+   virtual_touch->touch_info[idx].coord.y = y;
+
+   if (idx >= e_client_virtual_touch_finger_get(ec))
+     {
+        _e_service_virtual_touch_cancel();
+        return virtual_touch->event_state;
+     }
+
+   if (virtual_touch->pressed_fingers == e_client_virtual_touch_finger_get(ec))
+     {
+        _e_service_virtual_touch_util_center_point_get(&cx, &cy);
+        virtual_touch->point.prev.x = cx;
+        virtual_touch->point.prev.y = cy;
+     }
+
+   return virtual_touch->event_state;
+}
+
+static void
+_e_service_virtual_touch_state_ready(void)
+{
+   virtual_touch->event_state = E_SERVICE_VIRTUAL_TOUCH_EVENTSTATE_READY;
+   virtual_touch->ec_event = NULL;
+}
+
+static void
+_e_service_virtual_touch_cb_mouse_up(void *data, Evas *evas EINA_UNUSED, Evas_Object *obj, void *event)
+{
+   E_Client *ec = (E_Client *)data;
+   Evas_Event_Mouse_Up *ev = event;
+   E_Service_Virtual_Touch_EventState res = E_SERVICE_VIRTUAL_TOUCH_EVENTSTATE_READY;
+
+   res = _e_service_virtual_touch_touch_up(ec, 0, ev->canvas.x, ev->canvas.y, ev->timestamp);
+
+   switch (res)
+     {
+        case E_SERVICE_VIRTUAL_TOUCH_EVENTSTATE_END:
+           ev->event_flags = ev->event_flags | EVAS_EVENT_FLAG_ON_HOLD;
+           break;
+        case E_SERVICE_VIRTUAL_TOUCH_EVENTSTATE_CANCEL:
+           break;
+        case E_SERVICE_VIRTUAL_TOUCH_EVENTSTATE_IGNORE:
+           return;
+        default:
+           WRN("[Virtualtouch] Mouse Up: Invalid event_state(%d). virtual_touch->event_state: %d\n", res, virtual_touch->event_state);
+           break;
+     }
+
+   if (virtual_touch->pressed_fingers == 0)
+     {
+        _e_service_virtual_touch_state_ready();
+     }
+}
+
+static void
+_e_service_virtual_touch_cb_mouse_move(void *data, Evas *evas EINA_UNUSED, Evas_Object *obj, void *event)
+{
+   E_Client *ec = (E_Client *)data;
+   Evas_Event_Mouse_Move *ev = event;
+   E_Service_Virtual_Touch_EventState res = E_SERVICE_VIRTUAL_TOUCH_EVENTSTATE_READY;
+
+   res = _e_service_virtual_touch_touch_move(ec, 0, ev->cur.canvas.x, ev->cur.canvas.y, ev->timestamp);
+
+   switch (res)
+     {
+        case E_SERVICE_VIRTUAL_TOUCH_EVENTSTATE_READY:
+           if (virtual_touch->state == E_SERVICE_VIRTUAL_TOUCH_STATE_EVENTKEEP)
+             {
+                _e_service_virtual_touch_event_keep(ec->frame, EVAS_CALLBACK_MOUSE_MOVE, event);
+                ev->event_flags = ev->event_flags | EVAS_EVENT_FLAG_ON_HOLD;
+             }
+           else if (virtual_touch->state == E_SERVICE_VIRTUAL_TOUCH_STATE_CANCEL)
+             {
+                // cancel state: just send events
+                ;
+             }
+           break;
+        case E_SERVICE_VIRTUAL_TOUCH_EVENTSTATE_UPDATE:
+        case E_SERVICE_VIRTUAL_TOUCH_EVENTSTATE_END:
+           ev->event_flags = ev->event_flags | EVAS_EVENT_FLAG_ON_HOLD;
+           break;
+        case E_SERVICE_VIRTUAL_TOUCH_EVENTSTATE_CANCEL:
+           break;
+        case E_SERVICE_VIRTUAL_TOUCH_EVENTSTATE_IGNORE:
+           return;
+        default:
+           WRN("[Virtualtouch] Mouse Move: Invalid event_state(%d). virtual_touch->event_state: %d\n", res, virtual_touch->event_state);
+           break;
+     }
+}
+
+static void
+_e_service_virtual_touch_cb_mouse_down(void *data, Evas *evas EINA_UNUSED, Evas_Object *obj, void *event)
+{
+   E_Client *ec = (E_Client *)data;
+   Evas_Event_Mouse_Down *ev = event;
+   E_Service_Virtual_Touch_EventState res = E_SERVICE_VIRTUAL_TOUCH_EVENTSTATE_READY;
+
+   res = _e_service_virtual_touch_touch_down(ec, 0, ev->canvas.x, ev->canvas.y, ev->timestamp);
+
+   switch (res)
+     {
+        case E_SERVICE_VIRTUAL_TOUCH_EVENTSTATE_READY:
+           if (virtual_touch->state == E_SERVICE_VIRTUAL_TOUCH_STATE_EVENTKEEP)
+             {
+                _e_service_virtual_touch_event_keep(ec->frame, EVAS_CALLBACK_MOUSE_DOWN, event);
+                ev->event_flags = ev->event_flags | EVAS_EVENT_FLAG_ON_HOLD;
+             }
+           else if (virtual_touch->state == E_SERVICE_VIRTUAL_TOUCH_STATE_CANCEL)
+             {
+                // cancel state: just send events
+                ;
+             }
+           break;
+        case E_SERVICE_VIRTUAL_TOUCH_EVENTSTATE_END:
+           ev->event_flags = ev->event_flags | EVAS_EVENT_FLAG_ON_HOLD;
+           break;
+        case E_SERVICE_VIRTUAL_TOUCH_EVENTSTATE_CANCEL:
+           break;
+        case E_SERVICE_VIRTUAL_TOUCH_EVENTSTATE_IGNORE:
+           return;
+        default:
+           WRN("[Virtualtouch] Mouse Down: Invalid event_state(%d). virtual_touch->event_state: %d\n", res, virtual_touch->event_state);
+           break;
+     }
+}
+
+static void
+_e_service_virtual_touch_cb_multi_up(void *data, Evas *evas EINA_UNUSED, Evas_Object *obj, void *event)
+{
+   E_Client *ec = (E_Client *)data;
+   Evas_Event_Multi_Up *ev = event;
+   E_Service_Virtual_Touch_EventState res = E_SERVICE_VIRTUAL_TOUCH_EVENTSTATE_READY;
+
+   res = _e_service_virtual_touch_touch_up(ec, ev->device, ev->canvas.x, ev->canvas.y, ev->timestamp);
+
+   switch (res)
+     {
+        case E_SERVICE_VIRTUAL_TOUCH_EVENTSTATE_END:
+           ev->event_flags = ev->event_flags | EVAS_EVENT_FLAG_ON_HOLD;
+           break;
+        case E_SERVICE_VIRTUAL_TOUCH_EVENTSTATE_CANCEL:
+           break;
+        case E_SERVICE_VIRTUAL_TOUCH_EVENTSTATE_IGNORE:
+           return;
+        default:
+           WRN("[Virtualtouch] Nulti Up: Invalid event_state(%d). virtual_touch->event_state: %d\n", res, virtual_touch->event_state);
+           break;
+     }
+
+   if (virtual_touch->pressed_fingers == 0)
+     {
+        _e_service_virtual_touch_state_ready();
+     }
+}
+
+static void
+_e_service_virtual_touch_cb_multi_move(void *data, Evas *evas EINA_UNUSED, Evas_Object *obj, void *event)
+{
+   E_Client *ec = (E_Client *)data;
+   Evas_Event_Multi_Move *ev = event;
+   E_Service_Virtual_Touch_EventState res = E_SERVICE_VIRTUAL_TOUCH_EVENTSTATE_READY;
+
+   res = _e_service_virtual_touch_touch_move(ec, ev->device, ev->cur.canvas.x, ev->cur.canvas.y, ev->timestamp);
+
+   switch (res)
+     {
+        case E_SERVICE_VIRTUAL_TOUCH_EVENTSTATE_READY:
+           if (virtual_touch->state == E_SERVICE_VIRTUAL_TOUCH_STATE_EVENTKEEP)
+             {
+                _e_service_virtual_touch_event_keep(ec->frame, EVAS_CALLBACK_MULTI_MOVE, event);
+                ev->event_flags = ev->event_flags | EVAS_EVENT_FLAG_ON_HOLD;
+             }
+           else if (virtual_touch->state == E_SERVICE_VIRTUAL_TOUCH_STATE_CANCEL)
+             {
+                // cancel state: just send events
+                ;
+             }
+           break;
+        case E_SERVICE_VIRTUAL_TOUCH_EVENTSTATE_UPDATE:
+        case E_SERVICE_VIRTUAL_TOUCH_EVENTSTATE_END:
+           ev->event_flags = ev->event_flags | EVAS_EVENT_FLAG_ON_HOLD;
+           break;
+        case E_SERVICE_VIRTUAL_TOUCH_EVENTSTATE_CANCEL:
+           break;
+        case E_SERVICE_VIRTUAL_TOUCH_EVENTSTATE_IGNORE:
+           return;
+        default:
+           WRN("[Virtualtouch] Multi Move: Invalid event_state(%d). virtual_touch->event_state: %d\n", res, virtual_touch->event_state);
+           break;
+     }
+}
+
+static void
+_e_service_virtual_touch_cb_multi_down(void *data, Evas *evas EINA_UNUSED, Evas_Object *obj, void *event)
+{
+   E_Client *ec = (E_Client *)data;
+   Evas_Event_Multi_Down *ev = event;
+   E_Service_Virtual_Touch_EventState res = E_SERVICE_VIRTUAL_TOUCH_EVENTSTATE_READY;
+
+   res = _e_service_virtual_touch_touch_down(ec, ev->device, ev->canvas.x, ev->canvas.y, ev->timestamp);
+
+   switch (res)
+     {
+        case E_SERVICE_VIRTUAL_TOUCH_EVENTSTATE_READY:
+           if (virtual_touch->state == E_SERVICE_VIRTUAL_TOUCH_STATE_EVENTKEEP)
+             {
+                _e_service_virtual_touch_event_keep(ec->frame, EVAS_CALLBACK_MULTI_DOWN, event);
+                ev->event_flags = ev->event_flags | EVAS_EVENT_FLAG_ON_HOLD;
+             }
+           else if (virtual_touch->state == E_SERVICE_VIRTUAL_TOUCH_STATE_CANCEL)
+             {
+                // cancel state: just send events
+                ;
+             }
+           break;
+        case E_SERVICE_VIRTUAL_TOUCH_EVENTSTATE_END:
+           ev->event_flags = ev->event_flags | EVAS_EVENT_FLAG_ON_HOLD;
+           break;
+        case E_SERVICE_VIRTUAL_TOUCH_EVENTSTATE_CANCEL:
+           break;
+        case E_SERVICE_VIRTUAL_TOUCH_EVENTSTATE_IGNORE:
+           return;
+        default:
+           WRN("[Virtualtouch] Multi Down: Invalid event_state(%d). virtual_touch->event_state: %d\n", res, virtual_touch->event_state);
+           break;
+     }
+}
+
+E_API void
+e_service_virtual_touch_state_set(E_Service_Virtual_Touch_State state)
+{
+   EINA_SAFETY_ON_NULL_RETURN(virtual_touch);
+
+   INF("[Virtualtouch] state is changed %d to %d\n", virtual_touch->state, state);
+   virtual_touch->state = state;
+}
+
+E_API Eina_Bool
+e_service_virtual_touch_cb_set(E_Service_Virtual_Touch_Cb cb, void *data)
+{
+   Eina_List *l;
+   E_Service_Virtual_Touch_Cb_Data *cb_data;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(virtual_touch, EINA_FALSE);
+
+   EINA_LIST_FOREACH(virtual_touch->list.cb, l, cb_data)
+     {
+        if (cb_data->func == cb)
+          {
+             DBG("[VirtualTouch] Already set service_virtual_touch callback\n");
+             return EINA_FALSE;
+          }
+     }
+
+   cb_data = E_NEW(E_Service_Virtual_Touch_Cb_Data, 1);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(cb_data, EINA_FALSE);
+
+   cb_data->func = cb;
+   cb_data->data = data;
+
+   virtual_touch->list.cb = eina_list_append(virtual_touch->list.cb, cb_data);
+   return EINA_TRUE;
+}
+
+E_API void
+e_service_virtual_touch_cb_unset(E_Service_Virtual_Touch_Cb cb)
+{
+   Eina_List *l, *ll;
+   E_Service_Virtual_Touch_Cb_Data *cb_data;
+
+   EINA_SAFETY_ON_NULL_RETURN(virtual_touch);
+
+   EINA_LIST_FOREACH_SAFE(virtual_touch->list.cb, l, ll, cb_data)
+     {
+        if (cb_data->func == cb)
+          {
+             virtual_touch->list.cb = eina_list_remove_list(virtual_touch->list.cb, l);
+             E_FREE(cb_data);
+             break;
+          }
+     }
+}
+
+static void
+_e_service_virtual_touch_evas_callback_add(E_Client *ec)
+{
+   EINA_SAFETY_ON_NULL_RETURN(ec);
+   EINA_SAFETY_ON_NULL_RETURN(ec->frame);
+
+   evas_object_event_callback_priority_add(ec->frame, EVAS_CALLBACK_MOUSE_DOWN,
+      EVAS_CALLBACK_PRIORITY_BEFORE, _e_service_virtual_touch_cb_mouse_down, ec);
+
+   evas_object_event_callback_priority_add(ec->frame, EVAS_CALLBACK_MOUSE_MOVE,
+      EVAS_CALLBACK_PRIORITY_BEFORE, _e_service_virtual_touch_cb_mouse_move, ec);
+
+   evas_object_event_callback_priority_add(ec->frame, EVAS_CALLBACK_MOUSE_UP,
+      EVAS_CALLBACK_PRIORITY_BEFORE, _e_service_virtual_touch_cb_mouse_up, ec);
+
+   evas_object_event_callback_priority_add(ec->frame, EVAS_CALLBACK_MULTI_DOWN,
+      EVAS_CALLBACK_PRIORITY_BEFORE, _e_service_virtual_touch_cb_multi_down, ec);
+
+   evas_object_event_callback_priority_add(ec->frame, EVAS_CALLBACK_MULTI_MOVE,
+      EVAS_CALLBACK_PRIORITY_BEFORE, _e_service_virtual_touch_cb_multi_move, ec);
+
+   evas_object_event_callback_priority_add(ec->frame, EVAS_CALLBACK_MULTI_UP,
+      EVAS_CALLBACK_PRIORITY_BEFORE, _e_service_virtual_touch_cb_multi_up, ec);
+}
+
+static void
+_e_service_virtual_touch_evas_callback_del(E_Client *ec)
+{
+   EINA_SAFETY_ON_NULL_RETURN(ec);
+   EINA_SAFETY_ON_NULL_RETURN(ec->frame);
+
+   evas_object_event_callback_del(ec->frame, EVAS_CALLBACK_MOUSE_DOWN, _e_service_virtual_touch_cb_mouse_down);
+   evas_object_event_callback_del(ec->frame, EVAS_CALLBACK_MOUSE_MOVE, _e_service_virtual_touch_cb_mouse_move);
+   evas_object_event_callback_del(ec->frame, EVAS_CALLBACK_MOUSE_UP, _e_service_virtual_touch_cb_mouse_up);
+   evas_object_event_callback_del(ec->frame, EVAS_CALLBACK_MULTI_DOWN, _e_service_virtual_touch_cb_multi_down);
+   evas_object_event_callback_del(ec->frame, EVAS_CALLBACK_MULTI_MOVE, _e_service_virtual_touch_cb_multi_move);
+   evas_object_event_callback_del(ec->frame, EVAS_CALLBACK_MULTI_UP, _e_service_virtual_touch_cb_multi_up);
+}
+
+static void
+_e_service_virtual_touch_cb_client_destroy(struct wl_listener *listener, void *data)
+{
+   E_Client *ec = data, *ec_data;
+   E_Service_Virtual_Touch_Private_Client *vtp_client;
+   Eina_List *l, *ll;
+
+   EINA_SAFETY_ON_NULL_RETURN(ec);
+   
+   vtp_client = wl_container_of(listener, vtp_client, client_destroy);
+   E_FREE(vtp_client);
+
+   EINA_LIST_FOREACH_SAFE(virtual_touch->list.ec, l, ll, ec_data)
+     {
+        if (ec == ec_data)
+          {
+             virtual_touch->list.ec = eina_list_remove_list(virtual_touch->list.ec, l);
+             _e_service_virtual_touch_evas_callback_del(ec);
+             break;
+          }
+     }
+}
+
+static void
+_e_service_virtual_touch_cb_client_virtual_touch(struct wl_listener *listener, void *data)
+{
+   E_Service_Virtual_Touch_Private_Client *vtp_client;
+   E_Client *ec, *ec_data;
+   Eina_Bool enabled = EINA_FALSE;
+   Eina_List *l, *ll;
+
+   vtp_client = wl_container_of(listener, vtp_client, client_virtual_touch);
+   EINA_SAFETY_ON_NULL_RETURN(vtp_client);
+   ec = vtp_client->ec;
+   EINA_SAFETY_ON_NULL_RETURN(ec);
+
+   enabled = e_client_virtual_touch_enable_get(ec);
+
+   if (enabled)
+     {
+        if (eina_list_data_find(virtual_touch->list.ec, ec))
+          {
+             DBG("[VirtualTouch] client %p is already added\n", ec);
+             return;
+          }
+
+        INF("[VirtualTouch] Virtual Touch is enabled: ec: %p(%s), finger: %d, threshold: %d)\n",
+            ec, e_client_util_name_get(ec),
+            e_client_virtual_touch_finger_get(ec),
+            e_client_virtual_touch_threshold_get(ec));
+
+        virtual_touch->list.ec = eina_list_append(virtual_touch->list.ec, ec);
+
+        _e_service_virtual_touch_evas_callback_add(ec);
+     }
+   else
+     {
+        EINA_LIST_FOREACH_SAFE(virtual_touch->list.ec, l, ll, ec_data)
+          {
+             if (ec_data == ec)
+               {
+                  INF("[VirtualTouch] Virtual Touch is disabled: ec: %p(%s))\n", ec, e_client_util_name_get(ec));
+                  virtual_touch->list.ec = eina_list_remove_list(virtual_touch->list.ec, l);
+                  _e_service_virtual_touch_evas_callback_del(ec);
+               }
+          }
+     }
+}
+
+static Eina_Bool
+_e_service_virtual_touch_cb_ec_add(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
+{
+   E_Event_Client *ev;
+   E_Service_Virtual_Touch_Private_Client *vtp_client;
+
+   ev = event;
+   EINA_SAFETY_ON_NULL_RETURN_VAL(ev, ECORE_CALLBACK_PASS_ON);
+
+   vtp_client = E_NEW(E_Service_Virtual_Touch_Private_Client, 1);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(vtp_client, ECORE_CALLBACK_PASS_ON);
+
+   vtp_client->ec = ev->ec;
+
+   vtp_client->client_virtual_touch.notify = _e_service_virtual_touch_cb_client_virtual_touch;
+   e_client_virtual_touch_listener_add(vtp_client->ec, &vtp_client->client_virtual_touch);
+
+   vtp_client->client_destroy.notify = _e_service_virtual_touch_cb_client_destroy;
+   e_client_destroy_listener_add(vtp_client->ec, &vtp_client->client_destroy);
+
+   return ECORE_CALLBACK_PASS_ON;
+}
+
+EINTERN Eina_Bool
+e_service_virtual_touch_init(void)
+{
+   if (virtual_touch) return EINA_TRUE;
+
+   virtual_touch = E_NEW(E_Service_Virtual_Touch, 1);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(virtual_touch, EINA_FALSE);
+
+   virtual_touch->handler_client_add =
+      ecore_event_handler_add(E_EVENT_CLIENT_ADD,
+                              _e_service_virtual_touch_cb_ec_add, NULL);
+
+   /* FIXME: I set virtual_touch's state to event keep.
+    *        But we need to change this to configurable.
+    */
+   virtual_touch->state = E_SERVICE_VIRTUAL_TOUCH_STATE_EVENTKEEP;
+   virtual_touch->event_state = E_SERVICE_VIRTUAL_TOUCH_EVENTSTATE_READY;
+
+   return EINA_TRUE;
+}
+
+EINTERN int
+e_service_virtual_touch_deinit(void)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(virtual_touch, 0);
+
+   E_FREE_FUNC(virtual_touch->handler_client_add, ecore_event_handler_del);
+
+   E_FREE(virtual_touch);
+
+   return 0;
+}
\ No newline at end of file
diff --git a/src/bin/inputmgr/services/e_service_virtual_touch_intern.h b/src/bin/inputmgr/services/e_service_virtual_touch_intern.h
new file mode 100644 (file)
index 0000000..522ee2c
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef E_SERVICE_VIRTUAL_TOUCH_INTERN_H
+#define E_SERVICE_VIRTUAL_TOUCH_INTERN_H
+
+#include "e_intern.h"
+#include "e_service_virtual_touch.h"
+
+EINTERN Eina_Bool e_service_virtual_touch_init(void);
+EINTERN int e_service_virtual_touch_deinit(void);
+
+#endif /* E_SERVICE_VIRTUAL_TOUCH_INTERN_H */
index c5641608a8efd54741900d2cc58288e4ef5b4941..ca5b2b9189d98ea45d251dc38709d207c6df7b09 100644 (file)
@@ -1673,6 +1673,8 @@ _e_comp_wl_evas_cb_mouse_move(void *data, Evas *evas EINA_UNUSED, Evas_Object *o
    if (e_object_is_del(E_OBJECT(ec))) return;
    if ((ec->ignored) && (!ec->remote_surface.provider)) return;
    if (!(surface = e_comp_wl_client_surface_get(ec))) return;
+   if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return;
+
    if ((!need_send_motion) && (!need_send_released) && (e_client_visibility_get(ec) == E_VISIBILITY_FULLY_OBSCURED)) return;
 
    dev = ev->dev;
@@ -1770,6 +1772,8 @@ _e_comp_wl_evas_cb_mouse_down(void *data, Evas *evas EINA_UNUSED, Evas_Object *o
    if (_e_comp_wl_check_block_input(ec)) return;
 
    ev = event;
+   if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return;
+
    dev = ev->dev;
    dev_name = evas_device_description_get(dev);
 
@@ -1825,7 +1829,6 @@ _e_comp_wl_evas_cb_mouse_up(void *data, Evas *evas, Evas_Object *obj, void *even
    const Evas_Device *seat_dev;
    const char *dev_name, *seat_name;
    Evas_Device_Class dev_class;
-   Evas_Event_Flags flags;
    E_Comp_Wl_Data *comp_wl;
 
    if (!(ec = data)) return;
@@ -1843,11 +1846,10 @@ _e_comp_wl_evas_cb_mouse_up(void *data, Evas *evas, Evas_Object *obj, void *even
 
    seat_dev = evas_device_parent_get(dev);
    seat_name = evas_device_name_get(seat_dev);
-   flags = evas_event_default_flags_get(evas);
    dev_class = evas_device_class_get(dev);
 
    ELOGF("Mouse", "Up (obj: %p, button: %d, flag: 0x%x, time: %d, x:%d, y:%d, name:%20s) (dev:%s, seat:%s)",
-         ec, obj, ev->button, flags, ev->timestamp, ev->output.x, ev->output.y, e_client_util_name_get(ec),
+         ec, obj, ev->button, ev->event_flags, ev->timestamp, ev->output.x, ev->output.y, e_client_util_name_get(ec),
          dev_name, seat_name);
 
    comp_wl = e_comp_wl_get();
@@ -1859,7 +1861,7 @@ _e_comp_wl_evas_cb_mouse_up(void *data, Evas *evas, Evas_Object *obj, void *even
           comp_wl->touch.faked_ec = NULL;
      }
 
-   if (flags & EVAS_EVENT_FLAG_ON_HOLD) goto finish;
+   if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) goto finish;
 
    _e_comp_wl_device_send_event_device(comp_wl, ec, dev, ev->timestamp);
 
@@ -1985,6 +1987,7 @@ _e_comp_wl_evas_cb_multi_down(void *data, Evas *evas EINA_UNUSED, Evas_Object *o
    if (!ec) return;
    if (e_object_is_del(E_OBJECT(ec))) return;
    if (_e_comp_wl_check_block_input(ec)) return;
+   if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return;
 
    struct wl_resource *surface = e_comp_wl_client_surface_get(ec);
    if (!surface) return;
@@ -2025,12 +2028,12 @@ _e_comp_wl_evas_cb_multi_up(void *data, Evas *evas, Evas_Object *obj EINA_UNUSED
    const Evas_Device *seat_dev;
    const char *dev_name, *seat_name;
    Evas_Device_Class dev_class;
-   Evas_Event_Flags flags;
    E_Comp_Wl_Data *comp_wl;
 
    if (!ec) return;
    if (e_object_is_del(E_OBJECT(ec))) return;
    if (_e_comp_wl_check_block_input(ec)) return;
+   if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return;
 
    struct wl_resource *surface = e_comp_wl_client_surface_get(ec);
    if (!surface) return;
@@ -2038,15 +2041,11 @@ _e_comp_wl_evas_cb_multi_up(void *data, Evas *evas, Evas_Object *obj EINA_UNUSED
    /* Do not deliver emulated single touch events to client */
    if (ev->device == 0) return;
 
-   flags = evas_event_default_flags_get(evas);
-
    comp_wl = e_comp_wl_get();
    comp_wl->touch.pressed &= ~(1 << ev->device);
    if (!comp_wl->touch.pressed && comp_wl->touch.faked_ec)
      comp_wl->touch.faked_ec = NULL;
 
-   if (flags & EVAS_EVENT_FLAG_ON_HOLD) return;
-
    dev = ev->dev;
    dev_name = evas_device_description_get(dev);
 
@@ -2054,7 +2053,7 @@ _e_comp_wl_evas_cb_multi_up(void *data, Evas *evas, Evas_Object *obj EINA_UNUSED
    seat_name = evas_device_name_get(seat_dev);
 
    ELOGF("Touch", "Up (obj: %p, idx: %d, flag: 0x%x, time: %d, x:%d, y:%d, name:%20s) (dev:%s, seat:%s)",
-         ec, obj, ev->device, flags, ev->timestamp, ev->output.x, ev->output.y, e_client_util_name_get(ec),
+         ec, obj, ev->device, ev->event_flags, ev->timestamp, ev->output.x, ev->output.y, e_client_util_name_get(ec),
          dev_name, seat_name);
 
    if (dev && dev_name)
@@ -2081,6 +2080,7 @@ _e_comp_wl_evas_cb_multi_move(void *data, Evas *evas EINA_UNUSED, Evas_Object *o
    if (e_object_is_del(E_OBJECT(ec))) return;
    struct wl_resource *surface = e_comp_wl_client_surface_get(ec);
    if (!surface) return;
+   if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return;
 
    /* Do not deliver emulated single touch events to client */
    if (ev->device == 0) return;
index 1b94b3a188c730170b9dbc617d95806961fda875..c4ee0d832ad29dff637bfca9714e94bcca1040e0 100644 (file)
@@ -587,6 +587,8 @@ _e_magnifier_cb_mouse_move_proxy(void *data,
    int w, h;
    int nx, ny;
 
+   if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return;
+
    target_obj = _e_magnifier_mgr;
    if (!target_obj) return;
 
@@ -611,6 +613,9 @@ _e_magnifier_cb_mouse_down_proxy(void *data,
                                  void *event_info)
 {
    Evas_Object *target_obj;
+   Evas_Event_Mouse_Down *ev = event_info;
+
+   if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return;
 
    target_obj = _e_magnifier_mgr;
    if (!target_obj) return;
@@ -625,6 +630,9 @@ _e_magnifier_cb_mouse_up_proxy(void *data,
                                void *event_info)
 {
    Evas_Object *target_obj;
+   Evas_Event_Mouse_Up *ev = event_info;
+
+   if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return;
 
    target_obj = _e_magnifier_mgr;
    if (!target_obj) return;
index 48c4aafa7c5140fa282f9ecc01d91a3d8abd4a8c..1b22563f883044933fcb9fafc30712e0c01536f2 100644 (file)
@@ -469,6 +469,8 @@ _gesture_obj_cb_mouse_up(void *data, Evas *evas EINA_UNUSED, Evas_Object *obj, v
    E_Policy_Gesture *gesture = data;
    Evas_Event_Mouse_Up *ev = event;
 
+   if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return;
+
    gesture->pressed_fingers--;
    _gesture_touch_up(gesture, obj, 0, ev->canvas.x, ev->canvas.y, ev->timestamp);
 }
@@ -479,6 +481,8 @@ _gesture_obj_cb_mouse_move(void *data, Evas *evas EINA_UNUSED, Evas_Object *obj,
    E_Policy_Gesture *gesture = data;
    Evas_Event_Mouse_Move *ev = event;
 
+   if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return;
+
    if (!gesture->touch_info[0].pressed)
      return;
 
@@ -491,6 +495,8 @@ _gesture_obj_cb_mouse_down(void *data, Evas *evas EINA_UNUSED, Evas_Object *obj,
    E_Policy_Gesture *gesture = data;
    Evas_Event_Mouse_Down *ev = event;
 
+   if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return;
+
    gesture->pressed_fingers++;
 
    _gesture_touch_down(data, obj, 0, ev->canvas.x, ev->canvas.y, ev->timestamp);
@@ -502,6 +508,8 @@ _gesture_obj_cb_multi_up(void *data, Evas *evas EINA_UNUSED, Evas_Object *obj, v
    E_Policy_Gesture *gesture = data;
    Evas_Event_Multi_Up *ev = event;
 
+   if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return;
+
    if (gesture->gesture_fingers &&
        (gesture->gesture_fingers < (ev->device + 1)))
      {
@@ -524,6 +532,8 @@ _gesture_obj_cb_multi_move(void *data, Evas *evas EINA_UNUSED, Evas_Object *obj,
    E_Policy_Gesture *gesture = data;
    Evas_Event_Multi_Move *ev = event;
 
+   if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return;
+
    if (!gesture->touch_info[ev->device].pressed)
      return;
 
@@ -536,6 +546,8 @@ _gesture_obj_cb_multi_down(void *data, Evas *evas EINA_UNUSED, Evas_Object *obj,
    E_Policy_Gesture *gesture = data;
    Evas_Event_Multi_Down *ev = event;
 
+   if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return;
+
    if (gesture->gesture_fingers &&
        (gesture->gesture_fingers < (ev->device + 1)))
      {
index a71ba69d8a9b0af9bab8a7e5ede776e2c3d31704..6fd094bdcdadff68e4e9986424c29e5837b15f26 100644 (file)
@@ -58,6 +58,8 @@ _volume_region_obj_cb_mouse_move(void *data EINA_UNUSED, Evas *evas EINA_UNUSED,
 {
    Evas_Event_Mouse_Move *e = event;
 
+   if (e->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return;
+
    wl_touch_send_motion(_volume_wl_touch, e->timestamp, 0, // id 0 for the 1st figner
                         wl_fixed_from_int(e->cur.canvas.x - _volume_ec->client.x),
                         wl_fixed_from_int(e->cur.canvas.y - _volume_ec->client.y));
@@ -70,6 +72,8 @@ _volume_region_obj_cb_mouse_down(void *data EINA_UNUSED, Evas *evas EINA_UNUSED,
    uint32_t serial;
    E_Comp_Wl_Client_Data *volume_cdata = e_client_cdata_get(_volume_ec);
 
+   if (e->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return;
+
    serial = wl_display_next_serial(e_comp_wl_display_get());
    wl_touch_send_down(_volume_wl_touch, serial, e->timestamp,
                       volume_cdata->surface, 0,
@@ -83,6 +87,8 @@ _volume_region_obj_cb_mouse_up(void *data EINA_UNUSED, Evas *evas EINA_UNUSED, E
    Evas_Event_Mouse_Up *e = event;
    uint32_t serial;
 
+   if (e->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return;
+
    serial = wl_display_next_serial(e_comp_wl_display_get());
    wl_touch_send_up(_volume_wl_touch, serial, e->timestamp, 0);
 }
@@ -94,6 +100,8 @@ _volume_region_obj_cb_multi_down(void *data EINA_UNUSED, Evas *evas EINA_UNUSED,
    uint32_t serial;
    E_Comp_Wl_Client_Data *volume_cdata = e_client_cdata_get(_volume_ec);
 
+   if (e->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return;
+
    serial = wl_display_next_serial(e_comp_wl_display_get());
    wl_touch_send_down(_volume_wl_touch, serial, e->timestamp,
                       volume_cdata->surface, e->device,
@@ -107,6 +115,8 @@ _volume_region_obj_cb_multi_up(void *data EINA_UNUSED, Evas *evas EINA_UNUSED, E
    Evas_Event_Multi_Up *e = event;
    uint32_t serial;
 
+   if (e->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return;
+
    serial = wl_display_next_serial(e_comp_wl_display_get());
    wl_touch_send_up(_volume_wl_touch, serial, e->timestamp, e->device);
 }
@@ -116,6 +126,8 @@ _volume_region_obj_cb_multi_move(void *data EINA_UNUSED, Evas *evas EINA_UNUSED,
 {
    Evas_Event_Multi_Move *e = event;
 
+   if (e->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return;
+
    wl_touch_send_motion(_volume_wl_touch, e->timestamp, e->device,
                         wl_fixed_from_int(e->cur.canvas.x - _volume_ec->client.x),
                         wl_fixed_from_int(e->cur.canvas.y - _volume_ec->client.y));
diff --git a/src/include/e_service_virtual_touch.h b/src/include/e_service_virtual_touch.h
new file mode 100644 (file)
index 0000000..ee685f9
--- /dev/null
@@ -0,0 +1,30 @@
+#ifndef E_SERVICE_VIRTUAL_TOUCH_H
+#define E_SERVICE_VIRTUAL_TOUCH_H
+
+#include <e_types.h>
+#include <e_client.h>
+
+typedef enum _E_Service_Virtual_Touch_State E_Service_Virtual_Touch_State;
+typedef enum _E_Service_Virtual_Touch_Mode E_Service_Virtual_Touch_Mode;
+
+enum _E_Service_Virtual_Touch_State
+{
+   E_SERVICE_VIRTUAL_TOUCH_STATE_DISABLE = 0,
+   E_SERVICE_VIRTUAL_TOUCH_STATE_EVENTKEEP,
+   E_SERVICE_VIRTUAL_TOUCH_STATE_CANCEL
+};
+
+enum _E_Service_Virtual_Touch_Mode
+{
+   E_SERVICE_VIRTUAL_TOUCH_MODE_BEGIN,
+   E_SERVICE_VIRTUAL_TOUCH_MODE_UPDATE,
+   E_SERVICE_VIRTUAL_TOUCH_MODE_END
+};
+
+typedef void (*E_Service_Virtual_Touch_Cb)(void *data, E_Client *ec, E_Service_Virtual_Touch_Mode mode, int nfingers, int dx, int dy, unsigned int timestamp);
+
+E_API void      e_service_virtual_touch_state_set(E_Service_Virtual_Touch_State state);
+E_API Eina_Bool e_service_virtual_touch_cb_set(E_Service_Virtual_Touch_Cb cb, void *data);
+E_API void      e_service_virtual_touch_cb_unset(E_Service_Virtual_Touch_Cb cb);
+
+#endif /* E_SERVICE_VIRTUAL_TOUCH_H */