--- /dev/null
+#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