warn--
[framework/uifw/elementary.git] / src / lib / elm_gesture_layer.c
1 #include <Elementary.h>
2 #include "elm_priv.h"
3 /** @defgroup Elm_Gesture_Layer Gesture Layer */
4
5 /* Some defaults */
6 #define ELM_MOUSE_DEVICE 0
7 /* ELM_GESTURE_NEGATIVE_ANGLE - magic number says we didn't compute this yet */
8 #define ELM_GESTURE_NEGATIVE_ANGLE (-1.0) /* Magic number */
9 #define ELM_GESTURE_MOMENTUM_DELAY 25
10 #define ELM_GESTURE_MOMENTUM_TIMEOUT 50
11 #define ELM_GESTURE_MULTI_TIMEOUT 50
12 #define ELM_GESTURE_MINIMUM_MOMENTUM 0.001
13
14 /* Some Trigo values */
15 #define RAD_90DEG  M_PI_2
16 #define RAD_180DEG M_PI
17 #define RAD_270DEG (M_PI_2 * 3)
18 #define RAD_360DEG (M_PI * 2)
19 /* #define DEBUG_GESTURE_LAYER 1 */
20
21 #define RAD2DEG(x) ((x) * 57.295779513)
22 #define DEG2RAD(x) ((x) / 57.295779513)
23
24 static void *
25 _glayer_bufdup(void *buf, size_t size)
26 {
27    void *p;
28    p = malloc(size);
29    memcpy(p, buf, size);
30    return p;
31 }
32 #define COPY_EVENT_INFO(EV) _glayer_bufdup(EV, sizeof(*EV))
33
34
35 #define SET_TEST_BIT(P) do { \
36    P->test = P->fn[ELM_GESTURE_STATE_START].cb || P->fn[ELM_GESTURE_STATE_MOVE].cb || P->fn[ELM_GESTURE_STATE_END].cb || P->fn[ELM_GESTURE_STATE_ABORT].cb; \
37 } while (0)
38
39 #define IS_TESTED(T) ((wd->gesture[T]) ? wd->gesture[T]->test : EINA_FALSE)
40
41 /**
42  * @internal
43  *
44  * @struct _Func_Data
45  * Struct holds callback information.
46  *
47  * @ingroup Elm_Gesture_Layer
48  */
49 struct _Func_Data
50 {
51    void *user_data; /**< Holds user data to CB (like sd) */
52    Elm_Gesture_Event_Cb cb;
53 };
54
55 /**
56  * @internal
57  *
58  * @typedef Func_Data
59  * type for callback information
60  *
61  * @ingroup Elm_Gesture_Layer
62  */
63 typedef struct _Func_Data Func_Data;
64
65 /**
66  * @internal
67  *
68  * @struct _Gesture_Info
69  * Struct holds gesture info
70  *
71  * @ingroup Elm_Gesture_Layer
72  */
73 struct _Gesture_Info
74 {
75   Evas_Object *obj;
76   void *data; /**< Holds gesture intemidiate processing data */
77   Func_Data fn[ELM_GESTURE_STATE_ABORT + 1]; /**< Callback info for states */
78   Elm_Gesture_Type g_type;  /**< gesture type */
79   Elm_Gesture_State state;  /**< gesture state */
80   void *info;                        /**< Data for the state callback */
81   Eina_Bool test; /**< if true this gesture should be tested on input */
82 };
83
84 /**
85  * @internal
86  *
87  * @typedef Gesture_Info
88  * Type for _Gesture_Info
89  *
90  * @ingroup Elm_Gesture_Layer
91  */
92 typedef struct _Gesture_Info Gesture_Info;
93
94 /**
95  * @internal
96  *
97  * @struct _Event_History
98  * Struct holds event history.
99  * These events are repeated if no gesture found.
100  *
101  * @ingroup Elm_Gesture_Layer
102  */
103 struct _Event_History
104 {
105    EINA_INLIST;
106    void *event;
107    Evas_Callback_Type event_type;
108 };
109
110 /**
111  * @internal
112  *
113  * @typedef Event_History
114  * Type for _Event_History
115  *
116  * @ingroup Elm_Gesture_Layer
117  */
118 typedef struct _Event_History Event_History;
119
120 /**
121  * @internal
122  *
123  * @struct _Pointer_Event
124  * Struct holds pointer-event info
125  * This is a generic pointer event structure
126  *
127  * @ingroup Elm_Gesture_Layer
128  */
129 struct _Pointer_Event
130 {
131    Evas_Coord x, y;
132    unsigned int timestamp;
133    int device;
134    Evas_Callback_Type event_type;
135 };
136
137 /**
138  * @internal
139  *
140  * @typedef Pointer_Event
141  * Type for generic pointer event structure
142  *
143  * @ingroup Elm_Gesture_Layer
144  */
145 typedef struct _Pointer_Event Pointer_Event;
146
147 /* All *Type structs hold result for the user in 'info' field
148  * The rest is gesture processing intermediate data.
149  * NOTE: info field must be FIRST in the struct.
150  * This is used when reporting ABORT in event_history_clear() */
151 struct _Taps_Type
152 {
153    Elm_Gesture_Taps_Info info;
154    unsigned int sum_x;
155    unsigned int sum_y;
156    unsigned int n_taps_needed;
157    unsigned int n_taps;
158    Eina_List *l;
159 };
160 typedef struct _Taps_Type Taps_Type;
161
162 struct _Long_Tap_Type
163 {
164    Elm_Gesture_Taps_Info info;
165    Evas_Coord center_x;
166    Evas_Coord center_y;
167    unsigned int max_touched;
168    Ecore_Timer *timeout; /* When this expires, long tap STARTed */
169    Eina_List *touched;
170 };
171 typedef struct _Long_Tap_Type Long_Tap_Type;
172
173 struct _Momentum_Type
174 {  /* Fields used by _line_test() */
175    Elm_Gesture_Momentum_Info info;
176    Evas_Coord_Point line_st;
177    Evas_Coord_Point line_end;
178    unsigned int t_st_x;  /* Time start on X */
179    unsigned int t_st_y;  /* Time start on Y */
180    unsigned int t_end;   /* Time end        */
181    unsigned int t_up; /* Recent up event time */
182    int xdir, ydir;
183 };
184 typedef struct _Momentum_Type Momentum_Type;
185
186 struct _Line_Data
187 {
188    Evas_Coord_Point line_st;
189    Evas_Coord_Point line_end;
190    Evas_Coord line_length;
191    unsigned int t_st;  /* Time start */
192    unsigned int t_end; /* Time end   */
193    int device;
194    double line_angle;  /* Current angle of line */
195 };
196 typedef struct _Line_Data Line_Data;
197
198 struct _Line_Type
199 {  /* Fields used by _line_test() */
200    Elm_Gesture_Line_Info info;
201    Eina_List *list; /* List of Line_Data */
202 };
203 typedef struct _Line_Type Line_Type;
204
205 struct _Zoom_Type
206 {  /* Fields used by _zoom_test() */
207    Elm_Gesture_Zoom_Info info;
208    Pointer_Event zoom_st;
209    Pointer_Event zoom_mv;
210    Pointer_Event zoom_st1;
211    Pointer_Event zoom_mv1;
212    Evas_Event_Mouse_Wheel *zoom_wheel;
213    Evas_Coord zoom_base;  /* Holds gap between fingers on zoom-start  */
214    Evas_Coord zoom_distance_tolerance;
215    unsigned int m_st_tm;      /* momentum start time */
216    unsigned int m_prev_tm;    /* momentum prev time  */
217    int dir;   /* Direction: 1=zoom-in, (-1)=zoom-out */
218    double m_base; /* zoom value when momentum starts */
219    double next_step;
220 };
221 typedef struct _Zoom_Type Zoom_Type;
222
223 struct _Rotate_Type
224 {  /* Fields used by _rotation_test() */
225    Elm_Gesture_Rotate_Info info;
226    Pointer_Event rotate_st;
227    Pointer_Event rotate_mv;
228    Pointer_Event rotate_st1;
229    Pointer_Event rotate_mv1;
230    unsigned int prev_momentum_tm; /* timestamp of prev_momentum */
231    double prev_momentum;   /* Snapshot of momentum 0.01 sec ago */
232    double accum_momentum;
233    double rotate_angular_tolerance;
234    double next_step;
235 };
236 typedef struct _Rotate_Type Rotate_Type;
237
238 struct _Widget_Data
239 {
240    Evas_Object *target;  /* Target Widget */
241    Event_History *event_history_list;
242
243    int line_min_length;
244    Evas_Coord zoom_distance_tolerance;
245    Evas_Coord line_distance_tolerance;
246    double line_angular_tolerance;
247    double zoom_wheel_factor; /* mouse wheel zoom steps */
248    double zoom_finger_factor; /* used for zoom factor */
249    double rotate_angular_tolerance;
250    unsigned int flick_time_limit_ms;
251    double long_tap_start_timeout;
252    Eina_Bool glayer_continues_enable;
253
254    double zoom_step;
255    double rotate_step;
256
257    Gesture_Info *gesture[ELM_GESTURE_LAST];
258    Ecore_Timer *dbl_timeout; /* When this expires, dbl click/taps ABORTed  */
259    Eina_List *pending; /* List of devices need to refeed *UP event */
260    Eina_List *touched;  /* Information  of touched devices   */
261
262    Eina_Bool repeat_events : 1;
263 };
264 typedef struct _Widget_Data Widget_Data;
265
266 static const char *widtype = NULL;
267 static void _del_hook(Evas_Object *obj);
268
269 static Eina_Bool _event_history_clear(Evas_Object *obj);
270 static void _reset_states(Widget_Data *wd);
271 static void _key_down_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info);
272 static void _key_up_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info);
273 static void _zoom_with_wheel_test(Evas_Object *obj, void *event_info, Evas_Callback_Type event_type, Elm_Gesture_Type g_type);
274 static void _mouse_wheel(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info);
275 static void _mouse_down(void *data, Evas *e, Evas_Object *obj, void *event_info);
276 static void _mouse_move(void *data, Evas *e, Evas_Object *obj, void *event_info);
277 static void _mouse_up(void *data, Evas *e, Evas_Object *obj, void *event_info);
278
279 static void _multi_down(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info);
280 static void _multi_move(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info);
281 static void _multi_up(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info);
282
283 /* START - Functions to manage touched-device list */
284 /**
285  * @internal
286  * This function is used to find if device is touched
287  *
288  * @ingroup Elm_Gesture_Layer
289  */
290 static int
291 compare_device(const void *data1, const void *data2)
292 {  /* Compare the two device numbers */
293    return (((Pointer_Event *) data1)->device -((Pointer_Event *) data2)->device);
294 }
295
296 /**
297  * @internal
298  *
299  * Remove Pointer Event from touched device list
300  * @param list Pointer to touched device list.
301  * @param Pointer_Event Pointer to PE.
302  *
303  * @ingroup Elm_Gesture_Layer
304  */
305 static Eina_List *
306 _remove_touched_device(Eina_List *list, Pointer_Event *pe)
307 {
308    Eina_List *lst = NULL;
309    Pointer_Event *p = eina_list_search_unsorted(list, compare_device, pe);
310    if (p)
311      {
312         lst = eina_list_remove(list, p);
313         free(p);
314         return lst;
315      }
316
317    return list;
318 }
319
320 /**
321  * @internal
322  *
323  * Recoed Pointer Event in touched device list
324  * Note: This fuction allocates memory for PE event
325  * This memory is released in _remove_touched_device()
326  * @param list Pointer to touched device list.
327  * @param Pointer_Event Pointer to PE.
328  *
329  * @ingroup Elm_Gesture_Layer
330  */
331 static Eina_List *
332 _add_touched_device(Eina_List *list, Pointer_Event *pe)
333 {
334    Pointer_Event *p = eina_list_search_unsorted(list, compare_device, pe);
335    if (p)
336      {  /* We like to track device touch-position, overwrite info */
337         memcpy(p, pe, sizeof(Pointer_Event));
338         return list;
339      }
340
341    if ((pe->event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
342          (pe->event_type == EVAS_CALLBACK_MULTI_DOWN))
343      {  /* Add touched device on DOWN event only */
344         p = malloc(sizeof(Pointer_Event));
345         /* Freed in _remove_touched_device()    */
346         memcpy(p, pe, sizeof(Pointer_Event));
347         return eina_list_append(list, p);
348      }
349
350    return list;
351 }
352 /* END   - Functions to manage touched-device list */
353
354 /**
355  * @internal
356  *
357  * Get event flag
358  * @param event_info pointer to event.
359  *
360  * @ingroup Elm_Gesture_Layer
361  */
362 static Evas_Event_Flags
363 _get_event_flag(void *event_info, Evas_Callback_Type event_type)
364 {
365    switch(event_type)
366      {
367       case EVAS_CALLBACK_MOUSE_IN:
368          return ((Evas_Event_Mouse_In *) event_info)->event_flags;
369       case EVAS_CALLBACK_MOUSE_OUT:
370          return ((Evas_Event_Mouse_Out *) event_info)->event_flags;
371       case EVAS_CALLBACK_MOUSE_DOWN:
372          return ((Evas_Event_Mouse_Down *) event_info)->event_flags;
373       case EVAS_CALLBACK_MOUSE_MOVE:
374          return ((Evas_Event_Mouse_Move *) event_info)->event_flags;
375       case EVAS_CALLBACK_MOUSE_UP:
376          return ((Evas_Event_Mouse_Up *) event_info)->event_flags;
377       case EVAS_CALLBACK_MOUSE_WHEEL:
378          return ((Evas_Event_Mouse_Wheel *) event_info)->event_flags;
379       case EVAS_CALLBACK_MULTI_DOWN:
380          return ((Evas_Event_Multi_Down *) event_info)->event_flags;
381       case EVAS_CALLBACK_MULTI_MOVE:
382          return ((Evas_Event_Multi_Move *) event_info)->event_flags;
383       case EVAS_CALLBACK_MULTI_UP:
384          return ((Evas_Event_Multi_Up *) event_info)->event_flags;
385       case EVAS_CALLBACK_KEY_DOWN:
386          return ((Evas_Event_Key_Down *) event_info)->event_flags;
387       case EVAS_CALLBACK_KEY_UP:
388          return ((Evas_Event_Key_Up *) event_info)->event_flags;
389       default:
390          return EVAS_EVENT_FLAG_NONE;
391      }
392 }
393
394 /**
395  * @internal
396  *
397  * Sets event flag to value returned from user callback
398  * @param wd Widget Data
399  * @param event_info pointer to event.
400  * @param event_type what type was ev (mouse down, etc...)
401  * @param ev_flags event flags
402  *
403  * @ingroup Elm_Gesture_Layer
404  */
405 static void
406 consume_event(Widget_Data *wd, void *event_info,
407       Evas_Callback_Type event_type, Evas_Event_Flags ev_flags)
408 {  /* Mark EVAS_EVENT_FLAG_ON_HOLD on events that are used by gesture layer */
409    /* ev_flags != EVAS_EVENT_FLAG_NONE means target used event and g-layer  */
410    /* should not refeed this event.                                         */
411    if(!event_info)
412      return;  /* This happens when restarting gestures  */
413
414    if ((ev_flags) || (!wd->repeat_events))
415      {
416         switch(event_type)
417           {
418            case EVAS_CALLBACK_MOUSE_DOWN:
419               ((Evas_Event_Mouse_Down *) event_info)->event_flags |= ev_flags;
420               break;
421            case EVAS_CALLBACK_MOUSE_MOVE:
422               ((Evas_Event_Mouse_Move *) event_info)->event_flags |= ev_flags;
423               break;
424            case EVAS_CALLBACK_MOUSE_UP:
425               ((Evas_Event_Mouse_Up *) event_info)->event_flags |= ev_flags;
426               break;
427            case EVAS_CALLBACK_MOUSE_WHEEL:
428               ((Evas_Event_Mouse_Wheel *) event_info)->event_flags |= ev_flags;
429               break;
430            case EVAS_CALLBACK_MULTI_DOWN:
431               ((Evas_Event_Multi_Down *) event_info)->event_flags |= ev_flags;
432               break;
433            case EVAS_CALLBACK_MULTI_MOVE:
434               ((Evas_Event_Multi_Move *) event_info)->event_flags |= ev_flags;
435               break;
436            case EVAS_CALLBACK_MULTI_UP:
437               ((Evas_Event_Multi_Up *) event_info)->event_flags |= ev_flags;
438               break;
439            case EVAS_CALLBACK_KEY_DOWN:
440               ((Evas_Event_Key_Down *) event_info)->event_flags |= ev_flags;
441               break;
442            case EVAS_CALLBACK_KEY_UP:
443               ((Evas_Event_Key_Up *) event_info)->event_flags |= ev_flags;
444               break;
445            default:
446               return;
447           }
448      }
449 }
450
451 /**
452  * @internal
453  *
454  * Report current state of a gesture by calling user callback.
455  * @param gesture what gesture state we report.
456  * @param info inforamtion for user callback
457  *
458  * @ingroup Elm_Gesture_Layer
459  */
460 static Evas_Event_Flags
461 _report_state(Gesture_Info *gesture, void *info)
462 {  /* We report current state (START, MOVE, END, ABORT), once */
463 #if defined(DEBUG_GESTURE_LAYER)
464    printf("%s reporting gesture=<%d> state=<%d>\n" , __func__, gesture->g_type,
465          gesture->state);
466 #endif
467    if ((gesture->state != ELM_GESTURE_STATE_UNDEFINED) &&
468          (gesture->fn[gesture->state].cb))
469      {  /* Fill state-info struct and send ptr to user callback */
470         return gesture->fn[gesture->state].cb(
471               gesture->fn[gesture->state].user_data, info);
472      }
473
474    return EVAS_EVENT_FLAG_NONE;
475 }
476
477 /**
478  * @internal
479  *
480  * Update state for a given gesture.
481  * We may update gesture state to:
482  * UNDEFINED - current input did not start gesure yet.
483  * START - gesture started according to input.
484  * MOVE - gusture in progress.
485  * END - gesture completed according to input.
486  * ABORT - input does not matches gesure.
487  * note that we may move from UNDEFINED to ABORT
488  * because we may detect that gesture will not START
489  * with a given input.
490  *
491  * @param g given gesture to change state.
492  * @param s gesure new state.
493  * @param info buffer to be sent to user callback on report_state.
494  * @param force makes report_state to report the new-state even
495  * if its same as current state. Works for MOVE - gesture in progress.
496  *
497  * @ingroup Elm_Gesture_Layer
498  */
499 static Evas_Event_Flags
500 _set_state(Gesture_Info *g, Elm_Gesture_State s,
501       void *info, Eina_Bool force)
502 {
503    Elm_Gesture_State old_state;
504    if ((g->state == s) && (!force))
505      return EVAS_EVENT_FLAG_NONE;
506
507    old_state = g->state;
508
509    g->state = s;
510    g->info = info;  /* Information for user callback */
511    if ((g->state == ELM_GESTURE_STATE_ABORT) ||
512          (g->state == ELM_GESTURE_STATE_END))
513      g->test = EINA_FALSE;
514
515    if ((g->state != ELM_GESTURE_STATE_UNDEFINED) &&
516          (!((old_state == ELM_GESTURE_STATE_UNDEFINED) &&
517             (s == ELM_GESTURE_STATE_ABORT))))
518      return _report_state(g, g->info);
519
520    return EVAS_EVENT_FLAG_NONE;
521 }
522
523 /**
524  * @internal
525  *
526  * This resets all gesture states and sets test-bit.
527  * this is used for restarting gestures to listen to input.
528  * happens after we complete a gesture or no gesture was detected.
529  * @param wd Widget data of the gesture-layer object.
530  *
531  * @ingroup Elm_Gesture_Layer
532  */
533 static void
534 _reset_states(Widget_Data *wd)
535 {
536    int i;
537    Gesture_Info *p;
538    for (i = ELM_GESTURE_FIRST; i < ELM_GESTURE_LAST; i++)
539      {
540         p = wd->gesture[i];
541         if (p)
542           {
543              _set_state(p, ELM_GESTURE_STATE_UNDEFINED, NULL, EINA_FALSE);
544              SET_TEST_BIT(p);
545           }
546      }
547 }
548
549 /**
550  * @internal
551  *
552  * if gesture was NOT detected AND we only have gestures in ABORT state
553  * we clear history immediately to be ready for input.
554  *
555  * @param obj The gesture-layer object.
556  * @return TRUE on event history_clear
557  *
558  * @ingroup Elm_Gesture_Layer
559  */
560 static Eina_Bool
561 _clear_if_finished(Evas_Object *obj)
562 {
563    Widget_Data *wd = elm_widget_data_get(obj);
564    if (!wd) return EINA_FALSE;
565    int i;
566
567    /* Clear history if all we have aborted gestures */
568    Eina_Bool reset_s = EINA_TRUE, all_undefined = EINA_TRUE;
569    for (i = ELM_GESTURE_FIRST; i < ELM_GESTURE_LAST; i++)
570      {  /* If no gesture started and all we have aborted gestures, reset all */
571         Gesture_Info *p = wd->gesture[i];
572         if ((p) && (p->state != ELM_GESTURE_STATE_UNDEFINED))
573           {
574              if ((p->state == ELM_GESTURE_STATE_START) ||
575                    (p->state == ELM_GESTURE_STATE_MOVE))
576                reset_s = EINA_FALSE;
577
578              all_undefined = EINA_FALSE;
579           }
580      }
581
582    if (reset_s && (!all_undefined))
583      return _event_history_clear(obj);
584
585    return EINA_FALSE;
586 }
587
588 static Eina_Bool
589 _inside(Evas_Coord xx1, Evas_Coord yy1, Evas_Coord xx2, Evas_Coord yy2)
590 {
591    int w = _elm_config->finger_size >> 1; /* Finger size devided by 2 */
592    if (xx1 < (xx2 - w))
593      return EINA_FALSE;
594
595    if (xx1 > (xx2 + w))
596      return EINA_FALSE;
597
598    if (yy1 < (yy2 - w))
599      return EINA_FALSE;
600
601    if (yy1 > (yy2 + w))
602      return EINA_FALSE;
603
604    return EINA_TRUE;
605 }
606
607 /* All *test_reset() funcs are called to clear
608  * gesture intermediate data.
609  * This happens when we need to reset our tests.
610  * for example when gesture is detected or all ABORTed. */
611 static void
612 _tap_gestures_test_reset(Gesture_Info *gesture)
613 {
614    if (!gesture)
615      return;
616
617    Widget_Data *wd = elm_widget_data_get(gesture->obj);
618    wd->dbl_timeout = NULL;
619    Eina_List *data;
620    Pointer_Event *pe;
621
622    if (!gesture->data)
623      return;
624
625    EINA_LIST_FREE(((Taps_Type *) gesture->data)->l, data)
626       EINA_LIST_FREE(data, pe)
627          free(pe);
628
629   memset(gesture->data, 0, sizeof(Taps_Type));
630 }
631
632 /* All *test_reset() funcs are called to clear
633  * gesture intermediate data.
634  * This happens when we need to reset our tests.
635  * for example when gesture is detected or all ABORTed. */
636 static void
637 _n_long_tap_test_reset(Gesture_Info *gesture)
638 {
639    if (!gesture)
640      return;
641
642    if (!gesture->data)
643      return;
644
645    Long_Tap_Type *st = gesture->data;
646    Eina_List *l;
647    Pointer_Event *p;
648    EINA_LIST_FOREACH(st->touched, l, p)
649      free(p);
650
651    eina_list_free(st->touched);
652    if (st->timeout)
653      {
654         ecore_timer_del(st->timeout);
655         st->timeout = NULL;
656      }
657    memset(gesture->data, 0, sizeof(Long_Tap_Type));
658 }
659
660 static void
661 _momentum_test_reset(Gesture_Info *gesture)
662 {
663    if (!gesture)
664      return;
665
666    if (!gesture->data)
667      return;
668
669    memset(gesture->data, 0, sizeof(Momentum_Type));
670 }
671
672 static void
673 _line_data_reset(Line_Data *st)
674 {
675    if (!st)
676      return;
677
678    memset(st, 0, sizeof(Line_Data));
679    st->line_angle = ELM_GESTURE_NEGATIVE_ANGLE;
680 }
681
682 static void
683 _line_test_reset(Gesture_Info *gesture)
684 {
685    if (!gesture)
686      return;
687
688    if (!gesture->data)
689      return;
690
691    Line_Type *st = gesture->data;
692    Eina_List *list = st->list;
693    Eina_List *l;
694    Line_Data *t_line;
695    EINA_LIST_FOREACH(list, l, t_line)
696       free(t_line);
697
698    eina_list_free(list);
699    st->list = NULL;
700 }
701
702 static void
703 _zoom_test_reset(Gesture_Info *gesture)
704 {
705    if (!gesture)
706      return;
707
708    if (!gesture->data)
709      return;
710
711    Widget_Data *wd = elm_widget_data_get(gesture->obj);
712    Zoom_Type *st = gesture->data;
713    Evas_Modifier_Mask mask = evas_key_modifier_mask_get(
714          evas_object_evas_get(wd->target), "Control");
715    evas_object_key_ungrab(wd->target, "Control_L", mask, 0);
716    evas_object_key_ungrab(wd->target, "Control_R", mask, 0);
717
718    memset(st, 0, sizeof(Zoom_Type));
719    st->zoom_distance_tolerance = wd->zoom_distance_tolerance;
720    st->info.zoom = 1.0;
721 }
722
723 static void
724 _rotate_test_reset(Gesture_Info *gesture)
725 {
726    if (!gesture)
727      return;
728
729    if (!gesture->data)
730      return;
731
732    Widget_Data *wd = elm_widget_data_get(gesture->obj);
733    Rotate_Type *st = gesture->data;
734
735    memset(st, 0, sizeof(Rotate_Type));
736    st->info.base_angle = ELM_GESTURE_NEGATIVE_ANGLE;
737    st->rotate_angular_tolerance = wd->rotate_angular_tolerance;
738 }
739
740
741 /**
742  * @internal
743  *
744  * We register callbacks when gesture layer is attached to an object
745  * or when its enabled after disable.
746  *
747  * @param obj The gesture-layer object.
748  *
749  * @ingroup Elm_Gesture_Layer
750  */
751 static void
752 _register_callbacks(Evas_Object *obj)
753 {
754    Widget_Data *wd = elm_widget_data_get(obj);
755    if (!wd) return;
756
757    if (wd->target)
758      {
759         evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MOUSE_DOWN,
760               _mouse_down, obj);
761         evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MOUSE_MOVE,
762               _mouse_move, obj);
763         evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MOUSE_UP,
764               _mouse_up, obj);
765
766         evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MOUSE_WHEEL,
767               _mouse_wheel, obj);
768
769         evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MULTI_DOWN,
770               _multi_down, obj);
771         evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MULTI_MOVE,
772               _multi_move, obj);
773         evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MULTI_UP,
774               _multi_up, obj);
775
776         evas_object_event_callback_add(wd->target, EVAS_CALLBACK_KEY_DOWN,
777               _key_down_cb, obj);
778         evas_object_event_callback_add(wd->target, EVAS_CALLBACK_KEY_UP,
779               _key_up_cb, obj);
780      }
781 }
782
783 /**
784  * @internal
785  *
786  * We unregister callbacks when gesture layer is disabled.
787  *
788  * @param obj The gesture-layer object.
789  *
790  * @ingroup Elm_Gesture_Layer
791  */
792 static void
793 _unregister_callbacks(Evas_Object *obj)
794 {
795    Widget_Data *wd = elm_widget_data_get(obj);
796    if (!wd) return;
797
798    if (wd->target)
799      {
800         evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MOUSE_DOWN,
801               _mouse_down);
802         evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MOUSE_MOVE,
803               _mouse_move);
804         evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MOUSE_UP,
805               _mouse_up);
806
807         evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MOUSE_WHEEL,
808               _mouse_wheel);
809
810         evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MULTI_DOWN,
811               _multi_down);
812
813         evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MULTI_MOVE,
814               _multi_move);
815
816         evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MULTI_UP,
817               _multi_up);
818
819         evas_object_event_callback_del(wd->target, EVAS_CALLBACK_KEY_DOWN,
820               _key_down_cb);
821         evas_object_event_callback_del(wd->target, EVAS_CALLBACK_KEY_UP,
822               _key_up_cb);
823      }
824 }
825
826 /* START - Event history list handling functions */
827 /**
828  * @internal
829  * This function is used to find if device number
830  * is found in a list of devices.
831  * The list contains devices for refeeding *UP event
832  *
833  * @ingroup Elm_Gesture_Layer
834  */
835 static int
836 device_in_pending_list(const void *data1, const void *data2)
837 {  /* Compare the two device numbers */
838    return (((intptr_t) data1) - ((intptr_t) data2));
839 }
840
841 /**
842  * @internal
843  *
844  * This functions adds device to refeed-pending device list
845  * @ingroup Elm_Gesture_Layer
846  */
847 static Eina_List *
848 _add_device_pending(Eina_List *list, void *event, Evas_Callback_Type event_type)
849 {
850    int device = ELM_MOUSE_DEVICE;
851    switch(event_type)
852      {
853       case EVAS_CALLBACK_MOUSE_DOWN:
854          break;
855       case EVAS_CALLBACK_MULTI_DOWN:
856          device = ((Evas_Event_Multi_Down *) event)->device;
857          break;
858       default:
859          return list;
860      }
861
862    if (!eina_list_search_unsorted_list(list, device_in_pending_list,
863                                        (void *)(intptr_t)device))
864      {
865         return eina_list_append(list, (void *)(intptr_t)device);
866      }
867
868    return list;
869 }
870
871 /**
872  * @internal
873  *
874  * This functions returns pending-device node
875  * @ingroup Elm_Gesture_Layer
876  */
877 static Eina_List *
878 _device_is_pending(Eina_List *list, void *event, Evas_Callback_Type event_type)
879 {
880    int device = ELM_MOUSE_DEVICE;
881    switch(event_type)
882      {
883       case EVAS_CALLBACK_MOUSE_UP:
884          break;
885       case EVAS_CALLBACK_MULTI_UP:
886          device = ((Evas_Event_Multi_Up *) event)->device;
887          break;
888       default:
889         return NULL;
890      }
891
892    return eina_list_search_unsorted_list(list, device_in_pending_list,
893                                          (void *)(intptr_t)device);
894 }
895
896 /**
897  * @internal
898  *
899  * This function reports ABORT to all none-detected gestures
900  * Then resets test bits for all desired gesures
901  * and clears input-events history.
902  * note: if no gesture was detected, events from history list
903  * are streamed to the widget because it's unused by layer.
904  * user may cancel refeed of events by setting repeat events.
905  *
906  * @param obj The gesture-layer object.
907  *
908  * @ingroup Elm_Gesture_Layer
909  */
910 static Eina_Bool
911 _event_history_clear(Evas_Object *obj)
912 {
913    Widget_Data *wd = elm_widget_data_get(obj);
914    if (!wd) return EINA_FALSE;
915
916    int i;
917    Gesture_Info *p;
918    Evas *e = evas_object_evas_get(obj);
919    Eina_Bool gesture_found = EINA_FALSE;
920    for (i = ELM_GESTURE_FIRST; i < ELM_GESTURE_LAST; i++)
921      {
922         p = wd->gesture[i];
923         if (p)
924           {
925              if (p->state == ELM_GESTURE_STATE_END)
926                gesture_found = EINA_TRUE;
927              else
928                {  /* Report ABORT to all gestures that still not finished */
929                   _set_state(p, ELM_GESTURE_STATE_ABORT, wd->gesture[i]->info,
930                         EINA_FALSE);
931                }
932           }
933      }
934
935    _reset_states(wd); /* we are ready to start testing for gestures again */
936
937    /* Clear all gestures intermediate data */
938    if (IS_TESTED(ELM_GESTURE_N_LONG_TAPS))
939      {  /* We do not clear a long-tap gesture if fingers still on surface */
940         /* and gesture timer still pending to test gesture state          */
941         Long_Tap_Type *st = wd->gesture[ELM_GESTURE_N_LONG_TAPS]->data;
942         if ((st) &&  /* st not allocated if clear occurs before 1st input */
943               ((!eina_list_count(st->touched)) || (!st->timeout)))
944           _n_long_tap_test_reset(wd->gesture[ELM_GESTURE_N_LONG_TAPS]);
945      }
946
947    if (wd->dbl_timeout)
948      {
949         ecore_timer_del(wd->dbl_timeout);
950         wd->dbl_timeout = NULL;
951      }
952
953    _tap_gestures_test_reset(wd->gesture[ELM_GESTURE_N_TAPS]);
954    _tap_gestures_test_reset(wd->gesture[ELM_GESTURE_N_DOUBLE_TAPS]);
955    _tap_gestures_test_reset(wd->gesture[ELM_GESTURE_N_TRIPLE_TAPS]);
956    _momentum_test_reset(wd->gesture[ELM_GESTURE_MOMENTUM]);
957    _line_test_reset(wd->gesture[ELM_GESTURE_N_LINES]);
958    _line_test_reset(wd->gesture[ELM_GESTURE_N_FLICKS]);
959    _zoom_test_reset(wd->gesture[ELM_GESTURE_ZOOM]);
960    _rotate_test_reset(wd->gesture[ELM_GESTURE_ROTATE]);
961
962    /* Disable gesture layer so refeeded events won't be consumed by it */
963    _unregister_callbacks(obj);
964    while (wd->event_history_list)
965      {
966         Event_History *t;
967         t = wd->event_history_list;
968         Eina_List *pending = _device_is_pending(wd->pending,
969               wd->event_history_list->event,
970               wd->event_history_list->event_type);
971
972         /* Refeed events if no gesture matched input */
973         if (pending || ((!gesture_found) && (!wd->repeat_events)))
974           {
975              evas_event_refeed_event(e, wd->event_history_list->event,
976                    wd->event_history_list->event_type);
977
978              if (pending)
979                {
980                   wd->pending = eina_list_remove_list(wd->pending, pending);
981                }
982              else
983                {
984                   wd->pending = _add_device_pending(wd->pending,
985                         wd->event_history_list->event,
986                         wd->event_history_list->event_type);
987                }
988           }
989
990         free(wd->event_history_list->event);
991         wd->event_history_list = (Event_History *) eina_inlist_remove(
992               EINA_INLIST_GET(wd->event_history_list),
993               EINA_INLIST_GET(wd->event_history_list));
994         free(t);
995      }
996    _register_callbacks(obj);
997    return EINA_TRUE;
998 }
999
1000 /**
1001  * @internal
1002  *
1003  * This function copies input events.
1004  * We copy event info before adding it to history.
1005  * The memory is freed when we clear history.
1006  *
1007  * @param event the event to copy
1008  * @param event_type event type to copy
1009  *
1010  * @ingroup Elm_Gesture_Layer
1011  */
1012 static void *
1013 _copy_event_info(void *event, Evas_Callback_Type event_type)
1014 {
1015    switch(event_type)
1016      {
1017       case EVAS_CALLBACK_MOUSE_DOWN:
1018          return COPY_EVENT_INFO((Evas_Event_Mouse_Down *) event);
1019          break;
1020       case EVAS_CALLBACK_MOUSE_MOVE:
1021          return COPY_EVENT_INFO((Evas_Event_Mouse_Move *) event);
1022          break;
1023       case EVAS_CALLBACK_MOUSE_UP:
1024          return COPY_EVENT_INFO((Evas_Event_Mouse_Up *) event);
1025          break;
1026       case EVAS_CALLBACK_MOUSE_WHEEL:
1027          return COPY_EVENT_INFO((Evas_Event_Mouse_Wheel *) event);
1028          break;
1029       case EVAS_CALLBACK_MULTI_DOWN:
1030          return COPY_EVENT_INFO((Evas_Event_Multi_Down *) event);
1031          break;
1032       case EVAS_CALLBACK_MULTI_MOVE:
1033          return COPY_EVENT_INFO((Evas_Event_Multi_Move *) event);
1034          break;
1035       case EVAS_CALLBACK_MULTI_UP:
1036          return COPY_EVENT_INFO((Evas_Event_Multi_Up *) event);
1037          break;
1038       case EVAS_CALLBACK_KEY_DOWN:
1039          return COPY_EVENT_INFO((Evas_Event_Key_Down *) event);
1040          break;
1041       case EVAS_CALLBACK_KEY_UP:
1042          return COPY_EVENT_INFO((Evas_Event_Key_Up *) event);
1043          break;
1044       default:
1045          return NULL;
1046      }
1047 }
1048
1049 static Eina_Bool
1050 _event_history_add(Evas_Object *obj, void *event, Evas_Callback_Type event_type)
1051 {
1052    Widget_Data *wd = elm_widget_data_get(obj);
1053    Event_History *ev;
1054    if (!wd) return EINA_FALSE;
1055
1056    ev = malloc(sizeof(Event_History));
1057    ev->event = _copy_event_info(event, event_type);  /* Freed on event_history_clear */
1058    ev->event_type = event_type;
1059    wd->event_history_list = (Event_History *) eina_inlist_append(
1060          EINA_INLIST_GET(wd->event_history_list), EINA_INLIST_GET(ev));
1061
1062    return EINA_TRUE;
1063 }
1064 /* END - Event history list handling functions */
1065
1066 static void
1067 _del_hook(Evas_Object *obj)
1068 {
1069    Widget_Data *wd = elm_widget_data_get(obj);
1070    if (!wd) return;
1071
1072    _event_history_clear(obj);
1073    eina_list_free(wd->pending);
1074
1075    Pointer_Event *data;
1076    EINA_LIST_FREE(wd->touched, data)
1077      free(data);
1078
1079    if (!elm_widget_disabled_get(obj))
1080      _unregister_callbacks(obj);
1081
1082    /* Free all gestures internal data structures */
1083    int i;
1084    for (i = 0; i < ELM_GESTURE_LAST; i++)
1085      if (wd->gesture[i])
1086        {
1087           if (wd->gesture[i]->data)
1088             free(wd->gesture[i]->data);
1089
1090           free(wd->gesture[i]);
1091        }
1092
1093    free(wd);
1094 }
1095
1096 static int
1097 compare_match_fingers(const void *data1, const void *data2)
1098 {  /* Compare coords of first item in list to cur coords */
1099    const Pointer_Event *pe1 = eina_list_data_get(data1);
1100    const Pointer_Event *pe2 = data2;
1101
1102    if (_inside(pe1->x, pe1->y, pe2->x, pe2->y))
1103      return 0;
1104    else if (pe1->x < pe2->x)
1105      return -1;
1106    else
1107      {
1108         if (pe1->x == pe2->x)
1109           return pe1->y - pe2->y;
1110         else
1111           return 1;
1112      }
1113 }
1114
1115 static int
1116 compare_pe_device(const void *data1, const void *data2)
1117 {  /* Compare device of first item in list to our pe device */
1118    const Pointer_Event *pe1 = eina_list_data_get(data1);
1119    const Pointer_Event *pe2 = data2;
1120
1121    /* Only match if last was a down event */
1122    if ((pe1->event_type != EVAS_CALLBACK_MULTI_DOWN) &&
1123          (pe1->event_type != EVAS_CALLBACK_MOUSE_DOWN))
1124      return 1;
1125
1126    if (pe1->device == pe2->device)
1127      return 0;
1128    else if (pe1->device < pe2->device)
1129      return -1;
1130    else
1131      return 1;
1132 }
1133
1134 static Eina_List*
1135 _record_pointer_event(Taps_Type *st, Eina_List *pe_list, Pointer_Event *pe,
1136       Widget_Data *wd, void *event_info, Evas_Callback_Type event_type)
1137 {  /* Keep copy of pe and record it in list */
1138    Pointer_Event *p = malloc(sizeof(Pointer_Event));
1139    memcpy(p, pe, sizeof(Pointer_Event));
1140    consume_event(wd, event_info, event_type, EVAS_EVENT_FLAG_NONE);
1141
1142    st->sum_x += pe->x;
1143    st->sum_y += pe->y;
1144    st->n_taps++;
1145
1146    /* This will also update middle-point to report to user later */
1147    st->info.x = st->sum_x / st->n_taps;
1148    st->info.y = st->sum_y / st->n_taps;
1149    st->info.timestamp = pe->timestamp;
1150
1151    if (!pe_list)
1152      {
1153         pe_list = eina_list_append(pe_list, p);
1154         st->l = eina_list_append(st->l, pe_list);
1155      }
1156    else
1157      pe_list = eina_list_append(pe_list, p);
1158
1159    return pe_list;
1160 }
1161
1162 /**
1163  * @internal
1164  *
1165  * This function sets state a tap-gesture to END or ABORT
1166  *
1167  * @param data gesture info pointer
1168  *
1169  * @ingroup Elm_Gesture_Layer
1170  */
1171 static void
1172 _tap_gesture_finish(void *data)
1173 {  /* This function will test each tap gesture when timer expires */
1174    Gesture_Info *gesture = data;
1175    Elm_Gesture_State s = ELM_GESTURE_STATE_END;
1176    /* Here we check if taps-gesture was completed successfuly */
1177    /* Count how many taps were recieved on each device then   */
1178    /* determine if it matches n_taps_needed defined on START  */
1179    Taps_Type *st = gesture->data;
1180    Eina_List *l;
1181    Eina_List *pe_list;
1182    EINA_LIST_FOREACH(st->l, l, pe_list)
1183      {
1184         if (eina_list_count(pe_list) != st->n_taps_needed)
1185           {  /* No match taps number on device, ABORT */
1186              s = ELM_GESTURE_STATE_ABORT;
1187              break;
1188           }
1189      }
1190
1191    st->info.n = eina_list_count(st->l);
1192    _set_state(gesture, s, gesture->info, EINA_FALSE);
1193    _tap_gestures_test_reset(gesture);
1194 }
1195
1196 /**
1197  * @internal
1198  *
1199  * when this timer expires we finish tap gestures.
1200  *
1201  * @param data The gesture-layer object.
1202  * @return cancles callback for this timer.
1203  *
1204  * @ingroup Elm_Gesture_Layer
1205  */
1206 static Eina_Bool
1207 _multi_tap_timeout(void *data)
1208 {
1209    Widget_Data *wd = elm_widget_data_get(data);
1210    if (!wd) return EINA_FALSE;
1211
1212    if (IS_TESTED(ELM_GESTURE_N_TAPS))
1213      _tap_gesture_finish(wd->gesture[ELM_GESTURE_N_TAPS]);
1214
1215    if (IS_TESTED(ELM_GESTURE_N_DOUBLE_TAPS))
1216    _tap_gesture_finish(wd->gesture[ELM_GESTURE_N_DOUBLE_TAPS]);
1217
1218    if (IS_TESTED(ELM_GESTURE_N_TRIPLE_TAPS))
1219    _tap_gesture_finish(wd->gesture[ELM_GESTURE_N_TRIPLE_TAPS]);
1220
1221    _clear_if_finished(data);
1222    wd->dbl_timeout = NULL;
1223    return ECORE_CALLBACK_CANCEL;
1224 }
1225
1226 /**
1227  * @internal
1228  *
1229  * when this timer expires we START long tap gesture
1230  *
1231  * @param data The gesture-layer object.
1232  * @return cancles callback for this timer.
1233  *
1234  * @ingroup Elm_Gesture_Layer
1235  */
1236 static Eina_Bool
1237 _long_tap_timeout(void *data)
1238 {
1239    Gesture_Info *gesture = data;
1240    Long_Tap_Type *st = gesture->data;
1241    st->timeout = NULL;
1242
1243    _set_state(gesture, ELM_GESTURE_STATE_START,
1244          gesture->data, EINA_FALSE);
1245
1246    return ECORE_CALLBACK_CANCEL;
1247 }
1248
1249
1250 /**
1251  * @internal
1252  *
1253  * This function checks if a tap gesture should start
1254  *
1255  * @param wd Gesture Layer Widget Data.
1256  * @param pe The recent input event as stored in pe struct.
1257  * @param event_info Original input event pointer.
1258  * @param event_type Type of original input event.
1259  * @param gesture what gesture is tested
1260  * @param how many taps for this gesture (1, 2 or 3)
1261  *
1262  * @return Flag to determine if we need to set a timer for finish
1263  *
1264  * @ingroup Elm_Gesture_Layer
1265  */
1266 static Eina_Bool
1267 _tap_gesture_start(Widget_Data *wd, Pointer_Event *pe,
1268       void *event_info, Evas_Callback_Type event_type,
1269       Gesture_Info *gesture, int taps)
1270 {  /* Here we fill Tap struct */
1271    Taps_Type *st = gesture->data;
1272    if (!st)
1273      {  /* Allocated once on first time */
1274         st = calloc(1, sizeof(Taps_Type));
1275         gesture->data = st;
1276         _tap_gestures_test_reset(gesture);
1277      }
1278
1279    Eina_List *pe_list = NULL;
1280    Pointer_Event *pe_down = NULL;
1281    Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
1282    switch (pe->event_type)
1283      {
1284       case EVAS_CALLBACK_MULTI_DOWN:
1285       case EVAS_CALLBACK_MOUSE_DOWN:
1286          /* Check if got tap on same cord was tapped before */
1287          pe_list = eina_list_search_unsorted(st->l, compare_match_fingers, pe);
1288
1289          if ((!pe_list) &&
1290                eina_list_search_unsorted(st->l, compare_pe_device, pe))
1291            {  /* This device was touched in other cord before completion */
1292               ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
1293                     &st->info, EINA_FALSE);
1294               consume_event(wd, event_info, event_type, ev_flag);
1295
1296               return EINA_FALSE;
1297            }
1298
1299          pe_list = _record_pointer_event(st, pe_list, pe, wd, event_info, event_type);
1300          if ((pe->device == 0) && (eina_list_count(pe_list) == 1))
1301            {  /* This is the first mouse down we got */
1302               ev_flag = _set_state(gesture, ELM_GESTURE_STATE_START,
1303                     &st->info, EINA_FALSE);
1304               consume_event(wd, event_info, event_type, ev_flag);
1305
1306               st->n_taps_needed = taps * 2; /* count DOWN and UP */
1307
1308               return EINA_TRUE;
1309            }
1310
1311          break;
1312
1313       case EVAS_CALLBACK_MULTI_UP:
1314       case EVAS_CALLBACK_MOUSE_UP:
1315          pe_list = eina_list_search_unsorted(st->l, compare_pe_device, pe);
1316          if (!pe_list)
1317            return EINA_FALSE;
1318
1319          pe_list = _record_pointer_event(st, pe_list, pe, wd, event_info, event_type);
1320          break;
1321
1322       case EVAS_CALLBACK_MULTI_MOVE:
1323       case EVAS_CALLBACK_MOUSE_MOVE:
1324          /* Get first event in first list, this has to be a Mouse Down event  */
1325          /* and verify that user didn't move out of this area before next tap */
1326          pe_list = eina_list_search_unsorted(st->l, compare_pe_device, pe);
1327          if (pe_list)
1328            {
1329               pe_down = eina_list_data_get(pe_list);
1330               if (!_inside(pe_down->x, pe_down->y, pe->x, pe->y))
1331                 {
1332                    ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
1333                          &st->info, EINA_FALSE);
1334                    consume_event(wd, event_info, event_type, ev_flag);
1335                 }
1336            }
1337          break;
1338
1339       default:
1340          return EINA_FALSE;
1341      }
1342
1343    return EINA_FALSE;
1344 }
1345
1346
1347 /**
1348  * @internal
1349  *
1350  * This function checks all click/tap and double/triple taps
1351  *
1352  * @param obj The gesture-layer object.
1353  * @param pe The recent input event as stored in pe struct.
1354  * @param event_info Original input event pointer.
1355  * @param event_type Type of original input event.
1356  *
1357  * @ingroup Elm_Gesture_Layer
1358  */
1359 static void
1360 _tap_gestures_test(Evas_Object *obj, Pointer_Event *pe,
1361       void *event_info, Evas_Callback_Type event_type)
1362 {  /* Here we fill Recent_Taps struct and fire-up click/tap timers */
1363    Eina_Bool need_timer = EINA_FALSE;
1364    Widget_Data *wd = elm_widget_data_get(obj);
1365    if (!wd) return;
1366
1367    if (!pe)   /* this happens when unhandled event arrived */
1368      return;  /* see _make_pointer_event function */
1369
1370    if (IS_TESTED(ELM_GESTURE_N_TAPS))
1371      need_timer |= _tap_gesture_start(wd, pe, event_info, event_type,
1372            wd->gesture[ELM_GESTURE_N_TAPS], 1);
1373
1374    if (IS_TESTED(ELM_GESTURE_N_DOUBLE_TAPS))
1375      need_timer |= _tap_gesture_start(wd, pe, event_info, event_type,
1376            wd->gesture[ELM_GESTURE_N_DOUBLE_TAPS], 2);
1377
1378    if (IS_TESTED(ELM_GESTURE_N_TRIPLE_TAPS))
1379      need_timer |= _tap_gesture_start(wd, pe, event_info, event_type,
1380            wd->gesture[ELM_GESTURE_N_TRIPLE_TAPS], 3);
1381
1382    if ((need_timer) && (!wd->dbl_timeout))
1383      {  /* Set a timer to finish these gestures */
1384         wd->dbl_timeout = ecore_timer_add(0.4, _multi_tap_timeout,
1385               obj);
1386      }
1387 }
1388
1389 /**
1390  * @internal
1391  *
1392  * This function computes center-point for  long-tap gesture
1393  *
1394  * @param st Long Tap gesture info pointer
1395  * @param pe The recent input event as stored in pe struct.
1396  *
1397  * @ingroup Elm_Gesture_Layer
1398  */
1399 static void
1400 _compute_taps_center(Long_Tap_Type *st,
1401       Evas_Coord *x_out, Evas_Coord *y_out, Pointer_Event *pe)
1402 {
1403    if(!eina_list_count(st->touched))
1404      return;
1405
1406    Eina_List *l;
1407    Pointer_Event *p;
1408    Evas_Coord x = 0, y = 0;
1409    EINA_LIST_FOREACH(st->touched, l, p)
1410      {  /* Accumulate all then take avarage */
1411         if (p->device == pe->device)
1412           {  /* This will take care of values coming from MOVE event */
1413              x += pe->x;
1414              y += pe->y;
1415           }
1416         else
1417           {
1418              x += p->x;
1419              y += p->y;
1420           }
1421      }
1422
1423    *x_out = x / eina_list_count(st->touched);
1424    *y_out = y / eina_list_count(st->touched);
1425 }
1426
1427 /**
1428  * @internal
1429  *
1430  * This function checks N long-tap gesture.
1431  *
1432  * @param obj The gesture-layer object.
1433  * @param pe The recent input event as stored in pe struct.
1434  * @param event_info Original input event pointer.
1435  * @param event_type Type of original input event.
1436  * @param g_type what Gesture we are testing.
1437  * @param taps How many click/taps we test for.
1438  *
1439  * @ingroup Elm_Gesture_Layer
1440  */
1441 static void
1442 _n_long_tap_test(Evas_Object *obj, Pointer_Event *pe,
1443                  void *event_info, Evas_Callback_Type event_type,
1444                  Elm_Gesture_Type g_type)
1445 {  /* Here we fill Recent_Taps struct and fire-up click/tap timers */
1446    Widget_Data *wd = elm_widget_data_get(obj);
1447    if (!wd) return;
1448
1449    if (!pe)   /* this happens when unhandled event arrived */
1450      return;  /* see _make_pointer_event function */
1451    Gesture_Info *gesture = wd->gesture[g_type];
1452    if (!gesture) return;
1453
1454    Long_Tap_Type *st = gesture->data;
1455    if (!st)
1456      {  /* Allocated once on first time */
1457         st = calloc(1, sizeof(Long_Tap_Type));
1458         gesture->data = st;
1459         _n_long_tap_test_reset(gesture);
1460      }
1461
1462    Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
1463    switch (pe->event_type)
1464      {
1465       case EVAS_CALLBACK_MULTI_DOWN:
1466       case EVAS_CALLBACK_MOUSE_DOWN:
1467         st->touched = _add_touched_device(st->touched, pe);
1468         st->info.n = eina_list_count(st->touched);
1469         if (st->info.n > st->max_touched)
1470           st->max_touched = st->info.n;
1471         else
1472           {  /* User removed finger from touch, then put back - ABORT */
1473              if ((gesture->state == ELM_GESTURE_STATE_START) ||
1474                  (gesture->state == ELM_GESTURE_STATE_MOVE))
1475                {
1476                   ev_flag =_set_state(gesture, ELM_GESTURE_STATE_ABORT,
1477                                       &st->info, EINA_FALSE);
1478                   consume_event(wd, event_info, event_type, ev_flag);
1479                }
1480           }
1481
1482         if ((pe->device == 0) && (eina_list_count(st->touched) == 1))
1483           {  /* This is the first mouse down we got */
1484              st->info.timestamp = pe->timestamp;
1485
1486              /* To test long tap */
1487              /* When this timer expires, gesture STARTED */
1488              if (!st->timeout)
1489                st->timeout = ecore_timer_add(wd->long_tap_start_timeout,
1490                                              _long_tap_timeout, gesture);
1491           }
1492
1493         consume_event(wd, event_info, event_type, ev_flag);
1494         _compute_taps_center(st, &st->info.x, &st->info.y, pe);
1495         st->center_x = st->info.x;
1496         st->center_y = st->info.y;
1497         break;
1498
1499       case EVAS_CALLBACK_MULTI_UP:
1500       case EVAS_CALLBACK_MOUSE_UP:
1501         st->touched = _remove_touched_device(st->touched, pe);
1502         _compute_taps_center(st, &st->center_x, &st->center_y, pe);
1503         if (st->info.n &&
1504             ((gesture->state == ELM_GESTURE_STATE_START) ||
1505                 (gesture->state == ELM_GESTURE_STATE_MOVE)))
1506           {  /* Report END only for gesture that STARTed */
1507              if (eina_list_count(st->touched) == 0)
1508                {  /* Report END only at last release event */
1509                   ev_flag =_set_state(gesture, ELM_GESTURE_STATE_END,
1510                                       &st->info, EINA_FALSE);
1511                   consume_event(wd, event_info, event_type, ev_flag);
1512                }
1513           }
1514         else
1515           {  /* Stop test, user lifts finger before long-start */
1516              if (st->timeout) ecore_timer_del(st->timeout);
1517              st->timeout = NULL;
1518              ev_flag =_set_state(gesture, ELM_GESTURE_STATE_ABORT,
1519                                  &st->info, EINA_FALSE);
1520              consume_event(wd, event_info, event_type, ev_flag);
1521           }
1522
1523         break;
1524
1525       case EVAS_CALLBACK_MULTI_MOVE:
1526       case EVAS_CALLBACK_MOUSE_MOVE:
1527         if(st->info.n &&
1528            ((gesture->state == ELM_GESTURE_STATE_START) ||
1529                (gesture->state == ELM_GESTURE_STATE_MOVE)))
1530           {  /* Report MOVE only if STARTED */
1531              Evas_Coord x = 0;
1532              Evas_Coord y = 0;
1533              Elm_Gesture_State state_to_report = ELM_GESTURE_STATE_MOVE;
1534
1535              _compute_taps_center(st, &x, &y, pe);
1536              /* ABORT if user moved fingers out of tap area */
1537 #if defined(DEBUG_GESTURE_LAYER)
1538              printf("%s x,y=(%d,%d) st->info.x,st->info.y=(%d,%d)\n",__func__,x,y,st->info.x,st->info.y);
1539 #endif
1540              if (!_inside(x, y, st->center_x, st->center_y))
1541                state_to_report = ELM_GESTURE_STATE_ABORT;
1542
1543              /* Report MOVE if gesture started */
1544              ev_flag = _set_state(gesture, state_to_report,
1545                                   &st->info, EINA_TRUE);
1546              consume_event(wd, event_info, event_type, ev_flag);
1547           }
1548         break;
1549
1550       default:
1551         return;
1552      }
1553 }
1554
1555 /**
1556  * @internal
1557  *
1558  * This function computes momentum for MOMENTUM, LINE and FLICK gestures
1559  * This momentum value will be sent to widget when gesture is completed.
1560  *
1561  * @param momentum pointer to buffer where we record momentum value.
1562  * @param x1 x coord where user started gesture.
1563  * @param y1 y coord where user started gesture.
1564  * @param x2 x coord where user completed gesture.
1565  * @param y2 y coord where user completed gesture.
1566  * @param t1x timestamp for X, when user started gesture.
1567  * @param t1y timestamp for Y, when user started gesture.
1568  * @param t2  timestamp when user completed gesture.
1569  *
1570  * @ingroup Elm_Gesture_Layer
1571  */
1572 static void
1573 _set_momentum(Elm_Gesture_Momentum_Info *momentum, 
1574               Evas_Coord xx1, Evas_Coord yy1,
1575               Evas_Coord xx2, Evas_Coord yy2, 
1576               unsigned int t1x, unsigned int t1y, unsigned int t2)
1577 {
1578    Evas_Coord velx = 0, vely = 0, vel;
1579    Evas_Coord dx = xx2 - xx1;
1580    Evas_Coord dy = yy2 - yy1;
1581    int dtx = t2 - t1x;
1582    int dty = t2 - t1y;
1583    if (dtx > 0)
1584      velx = (dx * 1000) / dtx;
1585
1586    if (dty > 0)
1587      vely = (dy * 1000) / dty;
1588
1589    vel = sqrt((velx * velx) + (vely * vely));
1590
1591    if ((_elm_config->thumbscroll_friction > 0.0) &&
1592          (vel > _elm_config->thumbscroll_momentum_threshold))
1593      {  /* report momentum */
1594         momentum->mx = velx;
1595         momentum->my = vely;
1596      }
1597    else
1598      {
1599         momentum->mx = 0;
1600         momentum->my = 0;
1601      }
1602 }
1603
1604 /**
1605  * @internal
1606  *
1607  * This function is used for computing rotation angle (DEG).
1608  *
1609  * @param x1 first finger x location.
1610  * @param y1 first finger y location.
1611  * @param x2 second finger x location.
1612  * @param y2 second finger y location.
1613  *
1614  * @return angle of the line between (x1,y1), (x2,y2) in Deg.
1615  * Angles now are given in DEG, not RAD.
1616  * ZERO angle at 12-oclock, growing clockwise.
1617  *
1618  * @ingroup Elm_Gesture_Layer
1619  */
1620 static double
1621 get_angle(Evas_Coord x1, Evas_Coord y1, Evas_Coord x2, Evas_Coord y2)
1622 {
1623    double a, xx, yy, rt = (-1);
1624    xx = fabs(x2 - x1);
1625    yy = fabs(y2 - y1);
1626
1627    if (((int) xx) && ((int) yy))
1628      {
1629         rt = a = RAD2DEG(atan(yy / xx));
1630         if (x1 < x2)
1631           {
1632              if (y1 < y2)
1633                {
1634                   rt = 360 - a;
1635                }
1636              else
1637                {
1638                   rt = (a);
1639                }
1640           }
1641         else
1642           {
1643              if (y1 < y2)
1644                {
1645                   rt = 180 + a;
1646                }
1647              else
1648                {
1649                   rt = 180 - a;
1650                }
1651           }
1652      }
1653
1654    if (rt < 0)
1655      {  /* Do this only if rt is not set */
1656         if (((int) xx))
1657           {  /* Horizontal line */
1658              if (x2 < x1)
1659                {
1660                   rt = 180;
1661                }
1662              else
1663                {
1664                   rt = 0.0;
1665                }
1666           }
1667         else
1668           {  /* Vertical line */
1669              if (y2 < y1)
1670                {
1671                   rt = 90;
1672                }
1673              else
1674                {
1675                   rt = 270;
1676                }
1677           }
1678      }
1679
1680    /* Now we want to change from:
1681     *                      90                   0
1682     * original circle   180   0   We want:  270   90
1683     *                     270                 180
1684     */
1685
1686    rt = 450 - rt;
1687    if (rt >= 360)
1688      rt -= 360;
1689
1690    return rt;
1691 }
1692
1693 /**
1694  * @internal
1695  *
1696  * This function is used for computing the magnitude and direction
1697  * of vector between two points.
1698  *
1699  * @param x1 first finger x location.
1700  * @param y1 first finger y location.
1701  * @param x2 second finger x location.
1702  * @param y2 second finger y location.
1703  * @param l length computed (output)
1704  * @param a angle computed (output)
1705  *
1706  * @ingroup Elm_Gesture_Layer
1707  */
1708 static void
1709 get_vector(Evas_Coord x1, Evas_Coord y1, Evas_Coord x2, Evas_Coord y2,
1710       Evas_Coord *l, double *a)
1711 {
1712    Evas_Coord xx, yy;
1713    xx = x2 - x1;
1714    yy = y2 - y1;
1715    *l = (Evas_Coord) sqrt(xx*xx + yy*yy);
1716    *a = get_angle(x1, y1, x2, y2);
1717 }
1718
1719 static int
1720 _get_direction(Evas_Coord x1, Evas_Coord x2)
1721 {
1722    if (x2 < x1)
1723      return -1;
1724
1725    if (x2 > x1)
1726      return 1;
1727
1728    return 0;
1729 }
1730 /**
1731  * @internal
1732  *
1733  * This function tests momentum gesture.
1734  * @param obj The gesture-layer object.
1735  * @param pe The recent input event as stored in pe struct.
1736  * @param event_info recent input event.
1737  * @param event_type recent event type.
1738  * @param g_type what Gesture we are testing.
1739  *
1740  * @ingroup Elm_Gesture_Layer
1741  */
1742 static void
1743 _momentum_test(Evas_Object *obj, Pointer_Event *pe,
1744       void *event_info, Evas_Callback_Type event_type,
1745       Elm_Gesture_Type g_type)
1746 {
1747    Widget_Data *wd = elm_widget_data_get(obj);
1748    if (!wd) return;
1749    Gesture_Info *gesture = wd->gesture[g_type];
1750    if (!gesture ) return;
1751
1752    /* When continues enable = TRUE a gesture may START on MOVE event */
1753    /* We don't allow this to happen with the if-statement below.     */
1754    /* When continues enable = FALSE a gesture may START on DOWN only */
1755    /* Therefor it would NOT start on MOVE event.                     */
1756    /* NOTE that touched list is updated AFTER this function returns  */
1757    /* so (count == 0) when we get here on first touch on surface.    */
1758    if ((wd->glayer_continues_enable) && (!eina_list_count(wd->touched)))
1759      return; /* Got move on mouse-over move */
1760
1761    Momentum_Type *st = gesture->data;
1762    Elm_Gesture_State state_to_report = ELM_GESTURE_STATE_MOVE;
1763    if (!st)
1764      {  /* Allocated once on first time */
1765         st = calloc(1, sizeof(Momentum_Type));
1766         gesture->data = st;
1767         _momentum_test_reset(gesture);
1768      }
1769
1770    if (!pe)
1771      return;
1772
1773    /* First make avarage of all touched devices to determine center point */
1774    Eina_List *l;
1775    Pointer_Event *p;
1776    Pointer_Event pe_local = *pe;           /* Copy pe event info to local */
1777    unsigned int cnt = 1;    /* We start counter counting current pe event */
1778    EINA_LIST_FOREACH(wd->touched, l, p)
1779       if (p->device != pe_local.device)
1780         {
1781            pe_local.x += p->x;
1782            pe_local.y += p->y;
1783            cnt++;
1784         }
1785
1786
1787    /* Compute avarage to get center point */
1788    pe_local.x /= cnt;
1789    pe_local.y /= cnt;
1790
1791    /* If user added finger - reset gesture */
1792    if ((st->info.n) && (st->info.n < cnt))
1793      state_to_report = ELM_GESTURE_STATE_ABORT;
1794
1795
1796    if (st->info.n < cnt)
1797      st->info.n = cnt;
1798
1799    Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
1800    switch (event_type)
1801      {
1802       case EVAS_CALLBACK_MOUSE_DOWN:
1803       case EVAS_CALLBACK_MULTI_DOWN:
1804       case EVAS_CALLBACK_MOUSE_MOVE:
1805       case EVAS_CALLBACK_MULTI_MOVE:
1806          if (!st->t_st_x)
1807            {
1808               if ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
1809                     (event_type == EVAS_CALLBACK_MULTI_DOWN) ||
1810                     (wd->glayer_continues_enable)) /* start also on MOVE */
1811                 {  /* We start on MOVE when cont-enabled only */
1812                    st->line_st.x = st->line_end.x = pe_local.x;
1813                    st->line_st.y = st->line_end.y = pe_local.y;
1814                    st->t_st_x = st->t_st_y = st->t_end = pe_local.timestamp;
1815                    st->xdir = st->ydir = 0;
1816                    st->info.x2 = st->info.x1 = pe_local.x;
1817                    st->info.y2 = st->info.y1 = pe_local.y;
1818                    st->info.tx = st->info.ty = pe_local.timestamp;
1819                    ev_flag = _set_state(gesture, ELM_GESTURE_STATE_START,
1820                          &st->info, EINA_FALSE);
1821                    consume_event(wd, event_info, event_type, ev_flag);
1822                 }
1823
1824               return;
1825            }
1826
1827
1828          if (st->t_up)
1829            {
1830               Eina_Bool force = EINA_TRUE;  /* for move state */
1831               if ((st->t_up + ELM_GESTURE_MULTI_TIMEOUT) < pe_local.timestamp)
1832                 {  /* ABORT if got DOWN or MOVE event after UP+timeout */
1833                    state_to_report = ELM_GESTURE_STATE_ABORT;
1834                    force = EINA_FALSE;
1835                 }
1836
1837               /* We report state but don't compute momentum now */
1838               ev_flag = _set_state(gesture, state_to_report, &st->info,
1839                     force);
1840               consume_event(wd, event_info, event_type, ev_flag);
1841               return; /* Stop computing when user remove finger */
1842            }
1843
1844          if ((pe_local.timestamp - ELM_GESTURE_MOMENTUM_TIMEOUT) > st->t_end)
1845            {  /*  Too long of a wait, reset all values */
1846               st->line_st.x = pe_local.x;
1847               st->line_st.y = pe_local.y;
1848               st->t_st_y = st->t_st_x = pe_local.timestamp;
1849               st->info.tx = st->t_st_x;
1850               st->info.ty = st->t_st_y;
1851               st->xdir = st->ydir = 0;
1852            }
1853          else
1854            {
1855               int xdir, ydir;
1856               xdir = _get_direction(st->line_end.x, pe_local.x);
1857               ydir = _get_direction(st->line_end.y, pe_local.y);
1858               if (xdir && (xdir != st->xdir))
1859                 {
1860                    st->line_st.x = st->line_end.x;
1861                    st->info.tx = st->t_st_x = st->t_end;
1862                    st->xdir = xdir;
1863                 }
1864
1865               if (ydir && (ydir != st->ydir))
1866                 {
1867                    st->line_st.y = st->line_end.y;
1868                    st->info.ty = st->t_st_y = st->t_end;
1869                    st->ydir = ydir;
1870                 }
1871            }
1872
1873          st->info.x2 = st->line_end.x = pe_local.x;
1874          st->info.y2 = st->line_end.y = pe_local.y;
1875          st->t_end = pe_local.timestamp;
1876          _set_momentum(&st->info, st->line_st.x, st->line_st.y,
1877                pe_local.x, pe_local.y, st->t_st_x, st->t_st_y,
1878                pe_local.timestamp);
1879
1880          ev_flag = _set_state(gesture, state_to_report, &st->info,
1881                EINA_TRUE);
1882          consume_event(wd, event_info, event_type, ev_flag);
1883          break;
1884
1885
1886       case EVAS_CALLBACK_MOUSE_UP:
1887       case EVAS_CALLBACK_MULTI_UP:
1888          st->t_up = pe_local.timestamp;       /* Record recent up event time */
1889          if ((cnt > 1) ||     /* Ignore if more fingers touch surface        */
1890                (!st->t_st_x)) /* IGNORE if info was cleared, long press,move */
1891            return;
1892
1893          if ((pe_local.timestamp - ELM_GESTURE_MOMENTUM_TIMEOUT) > st->t_end)
1894            {  /* Too long of a wait, reset all values */
1895               st->line_st.x = pe_local.x;
1896               st->line_st.y = pe_local.y;
1897               st->t_st_y = st->t_st_x = pe_local.timestamp;
1898               st->xdir = st->ydir = 0;
1899            }
1900
1901          st->info.x2 = pe_local.x;
1902          st->info.y2 = pe_local.y;
1903          st->line_end.x = pe_local.x;
1904          st->line_end.y = pe_local.y;
1905          st->t_end = pe_local.timestamp;
1906
1907          if ((fabs(st->info.mx) > ELM_GESTURE_MINIMUM_MOMENTUM) ||
1908                (fabs(st->info.my) > ELM_GESTURE_MINIMUM_MOMENTUM))
1909            state_to_report = ELM_GESTURE_STATE_END;
1910          else
1911            state_to_report = ELM_GESTURE_STATE_ABORT;
1912
1913          ev_flag = _set_state(gesture, state_to_report, &st->info,
1914                EINA_FALSE);
1915          consume_event(wd, event_info, event_type, ev_flag);
1916          return;
1917
1918       default:
1919          return;
1920      }
1921 }
1922
1923 static int
1924 compare_line_device(const void *data1, const void *data2)
1925 {  /* Compare device component of line struct */
1926    const Line_Data *ln1 = data1;
1927    const int *device = data2;
1928
1929    if (ln1->t_st) /* Compare only with lines that started */
1930      return (ln1->device - (*device));
1931
1932    return (-1);
1933 }
1934
1935 /**
1936  * @internal
1937  *
1938  * This function construct line struct from input.
1939  * @param info pointer to store line momentum.
1940  * @param st line info to store input data.
1941  * @param pe The recent input event as stored in pe struct.
1942  *
1943  * @ingroup Elm_Gesture_Layer
1944  */
1945 static Eina_Bool
1946 _single_line_process(Elm_Gesture_Line_Info *info, Line_Data *st,
1947       Pointer_Event *pe, Evas_Callback_Type event_type)
1948 {  /* Record events and set momentum for line pointed by st */
1949    if (!pe)
1950      return EINA_FALSE;
1951
1952    switch (event_type)
1953      {
1954       case EVAS_CALLBACK_MOUSE_DOWN:
1955       case EVAS_CALLBACK_MOUSE_MOVE:
1956       case EVAS_CALLBACK_MULTI_DOWN:
1957       case EVAS_CALLBACK_MULTI_MOVE:
1958          if (!st->t_st)
1959            {  /* This happens only when line starts */
1960               st->line_st.x = pe->x;
1961               st->line_st.y = pe->y;
1962               st->t_st = pe->timestamp;
1963               st->device = pe->device;
1964               info->momentum.x1 = pe->x;
1965               info->momentum.y1 = pe->y;
1966               info->momentum.tx = pe->timestamp;
1967               info->momentum.ty = pe->timestamp;
1968
1969               return EINA_TRUE;
1970            }
1971
1972          break;
1973
1974       case EVAS_CALLBACK_MOUSE_UP:
1975       case EVAS_CALLBACK_MULTI_UP:
1976          /* IGNORE if line info was cleared, like long press, move */
1977          if (!st->t_st)
1978            return EINA_FALSE;
1979
1980          st->line_end.x = pe->x;
1981          st->line_end.y = pe->y;
1982          st->t_end = pe->timestamp;
1983          break;
1984
1985       default:
1986          return EINA_FALSE;
1987      }
1988
1989    if (!st->t_st)
1990      {
1991         _line_data_reset(st);
1992         return EINA_FALSE;
1993      }
1994
1995    info->momentum.x2 = pe->x;
1996    info->momentum.y2 = pe->y;
1997    _set_momentum(&info->momentum, st->line_st.x, st->line_st.y, pe->x, pe->y,
1998          st->t_st, st->t_st, pe->timestamp);
1999
2000    return EINA_TRUE;
2001 }
2002
2003 /**
2004  * @internal
2005  *
2006  * This function test for (n) line gesture.
2007  * @param obj The gesture-layer object.
2008  * @param pe The recent input event as stored in pe struct.
2009  * @param event_info Original input event pointer.
2010  * @param event_type Type of original input event.
2011  * @param g_type what Gesture we are testing.
2012  *
2013  * @ingroup Elm_Gesture_Layer
2014  */
2015 static void
2016 _n_line_test(Evas_Object *obj, Pointer_Event *pe, void *event_info,
2017       Evas_Callback_Type event_type, Elm_Gesture_Type g_type)
2018 {
2019    if (!pe)
2020      return;
2021    Widget_Data *wd = elm_widget_data_get(obj);
2022    if (!wd) return;
2023    Gesture_Info *gesture = wd->gesture[g_type];
2024    if (!gesture ) return;
2025
2026    /* When continues enable = TRUE a gesture may START on MOVE event */
2027    /* We don't allow this to happen with the if-statement below.     */
2028    /* When continues enable = FALSE a gesture may START on DOWN only */
2029    /* Therefor it would NOT start on MOVE event.                     */
2030    /* NOTE that touched list is updated AFTER this function returns  */
2031    /* so (count == 0) when we get here on first touch on surface.    */
2032    if ((wd->glayer_continues_enable) && (!eina_list_count(wd->touched)))
2033      return; /* Got move on mouse-over move */
2034
2035    Line_Type *st = gesture->data;
2036    if (!st)
2037      {
2038         st = calloc(1, sizeof(Line_Type));
2039         gesture->data = st;
2040      }
2041
2042    Line_Data *line = NULL;
2043    Eina_List *list = st->list;
2044    unsigned cnt = eina_list_count(list);
2045
2046    if (cnt)
2047      {  /* list is not empty, locate this device on list */
2048         line = (Line_Data *) eina_list_search_unsorted(st->list,
2049               compare_line_device, &pe->device);
2050      }
2051
2052    if (!line)
2053      {  /* List is empty or device not found, new line-struct on START only */
2054         if ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
2055               (event_type == EVAS_CALLBACK_MULTI_DOWN) ||
2056               ((wd->glayer_continues_enable) && /* START on MOVE also */
2057                ((event_type == EVAS_CALLBACK_MOUSE_MOVE) ||
2058                 (event_type == EVAS_CALLBACK_MULTI_MOVE))))
2059           {  /* Allocate new item on START only */
2060              line = calloc(1, sizeof(Line_Data));
2061              _line_data_reset(line);
2062              list = eina_list_append(list, line);
2063              st->list = list;
2064           }
2065      }
2066
2067    if (!line)  /* This may happen on MOVE that comes before DOWN      */
2068      return;   /* No line-struct to work with, can't continue testing */
2069
2070    if (_single_line_process(&st->info, line, pe, event_type)) /* update st with input */
2071      consume_event(wd, event_info, event_type, EVAS_EVENT_FLAG_NONE);
2072
2073    /* Get direction and magnitude of the line */
2074    double angle;
2075    get_vector(line->line_st.x, line->line_st.y, pe->x, pe->y,
2076          &line->line_length, &angle);
2077
2078    /* These are used later to compare lines length */
2079    Evas_Coord shortest_line_len = line->line_length;
2080    Evas_Coord longest_line_len = line->line_length;
2081    Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
2082
2083    /* Now update line-state */
2084    if (line->t_st)
2085      {  /* Analyze line only if line started */
2086         if (line->line_angle >= 0.0)
2087           {  /* if line direction was set, we test if broke tolerance */
2088              double a = fabs(angle - line->line_angle);
2089
2090              double d = (tan(DEG2RAD(a))) * line->line_length; /* Distance from line */
2091 #if defined(DEBUG_GESTURE_LAYER)
2092              printf("%s a=<%f> d=<%f>\n", __func__, a, d);
2093 #endif
2094              if ((d > wd->line_distance_tolerance) || (a > wd->line_angular_tolerance))
2095                {  /* Broke tolerance: abort line and start a new one */
2096                   ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
2097                         &st->info, EINA_FALSE);
2098                   consume_event(wd, event_info, event_type, ev_flag);
2099                   return;
2100                }
2101
2102              if (wd->glayer_continues_enable)
2103                {  /* We may finish line if momentum is zero */
2104                   /* This is for continues-gesture */
2105                   if ((!st->info.momentum.mx) && (!st->info.momentum.my))
2106                     {  /* Finish line on zero momentum for continues gesture */
2107                        line->line_end.x = pe->x;
2108                        line->line_end.y = pe->y;
2109                        line->t_end = pe->timestamp;
2110                     }
2111                }
2112           }
2113         else
2114           {  /* Record the line angle as it broke minimum length for line */
2115              if (line->line_length >= wd->line_min_length)
2116                st->info.angle = line->line_angle = angle;
2117           }
2118
2119
2120         if (line->t_end)
2121           {
2122              if (line->line_angle < 0.0)
2123                { /* it's not a line, too short more close to a tap */
2124                   ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
2125                         &st->info, EINA_FALSE);
2126                   consume_event(wd, event_info, event_type, ev_flag);
2127                   return;
2128                }
2129           }
2130      }
2131
2132    /* Count how many lines already started / ended */
2133    int started = 0;
2134    int ended = 0;
2135    unsigned int tm_start = pe->timestamp;
2136    unsigned int tm_end = pe->timestamp;
2137    Eina_List *l;
2138    Line_Data *t_line;
2139    double base_angle = ELM_GESTURE_NEGATIVE_ANGLE;
2140    Eina_Bool lines_parallel = EINA_TRUE;
2141    EINA_LIST_FOREACH(list, l, t_line)
2142      {
2143         if (base_angle < 0)
2144           base_angle = t_line->line_angle;
2145         else
2146           {
2147              if (t_line->line_angle >= 0)
2148                {  /* Compare angle only with lines with direction defined */
2149                   if (fabs(base_angle - t_line->line_angle) >
2150                         wd->line_angular_tolerance)
2151                     lines_parallel = EINA_FALSE;
2152                }
2153           }
2154
2155         if (t_line->line_length)
2156           {  /* update only if this line is used */
2157              if (shortest_line_len > t_line->line_length)
2158                shortest_line_len = t_line->line_length;
2159
2160              if (longest_line_len < t_line->line_length)
2161                longest_line_len = t_line->line_length;
2162           }
2163
2164         if (t_line->t_st)
2165           {
2166              started++;
2167              if (t_line->t_st < tm_start)
2168                tm_start = t_line->t_st;
2169           }
2170
2171         if (t_line->t_end)
2172           {
2173              ended++;
2174              if (t_line->t_end < tm_end)
2175                tm_end = t_line->t_end;
2176           }
2177      }
2178
2179    st->info.momentum.n = started;
2180
2181
2182    if (ended &&
2183          ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
2184           (event_type == EVAS_CALLBACK_MULTI_DOWN)))
2185      {  /* user lift one finger then starts again without line-end - ABORT */
2186         ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
2187               EINA_FALSE);
2188         consume_event(wd, event_info, event_type, ev_flag);
2189         return;
2190      }
2191
2192    if (!lines_parallel)
2193      { /* Lines are NOT at same direction, abort this gesture */
2194         ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
2195               EINA_FALSE);
2196         consume_event(wd, event_info, event_type, ev_flag);
2197         return;
2198      }
2199
2200
2201    /* We report ABORT if lines length are NOT matching when fingers are up */
2202    if ((longest_line_len - shortest_line_len) > (_elm_config->finger_size * 2))
2203      {
2204         ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
2205               EINA_FALSE);
2206         consume_event(wd, event_info, event_type, ev_flag);
2207         return;
2208      }
2209
2210    if ((g_type == ELM_GESTURE_N_FLICKS) && ((tm_end - tm_start) > wd->flick_time_limit_ms))
2211      {  /* We consider FLICK as a fast line.ABORT if take too long to finish */
2212         ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
2213               EINA_FALSE);
2214         consume_event(wd, event_info, event_type, ev_flag);
2215         return;
2216      }
2217
2218    switch (event_type)
2219      {
2220       case EVAS_CALLBACK_MOUSE_UP:
2221       case EVAS_CALLBACK_MULTI_UP:
2222          if ((started) && (started == ended))
2223            {
2224               ev_flag = _set_state(gesture, ELM_GESTURE_STATE_END,
2225                     &st->info, EINA_FALSE);
2226               consume_event(wd, event_info, event_type, ev_flag);
2227            }
2228
2229          return;
2230
2231       case EVAS_CALLBACK_MOUSE_DOWN:
2232       case EVAS_CALLBACK_MULTI_DOWN:
2233       case EVAS_CALLBACK_MOUSE_MOVE:
2234       case EVAS_CALLBACK_MULTI_MOVE:
2235          if (started)
2236            {
2237               if (wd->glayer_continues_enable && (started == ended))
2238                 {  /* For continues gesture */
2239                    ev_flag = _set_state(gesture, ELM_GESTURE_STATE_END,
2240                          &st->info, EINA_FALSE);
2241                    consume_event(wd, event_info, event_type, ev_flag);
2242                 }
2243               else
2244                 {  /* When continues, may START on MOVE event too */
2245                    Elm_Gesture_State s = ELM_GESTURE_STATE_MOVE;
2246
2247                    /* This happens when: on n > 1 lines then one finger up */
2248                    /* caused abort, then put finger down.                  */
2249                    /* This will stop line from starting again.             */
2250                    /* Number of lines, MUST match touched-device in list   */
2251                    if ((!wd->glayer_continues_enable) &&
2252                          (eina_list_count(st->list) < eina_list_count(wd->touched)))
2253                      s = ELM_GESTURE_STATE_ABORT;
2254
2255                    if (gesture->state == ELM_GESTURE_STATE_UNDEFINED)
2256                      s = ELM_GESTURE_STATE_START;
2257
2258                    ev_flag = _set_state(gesture, s, &st->info, EINA_TRUE);
2259                    consume_event(wd, event_info, event_type, ev_flag);
2260                 }
2261            }
2262          break;
2263
2264       default:
2265          return;  /* Unhandeld event type */
2266      }
2267 }
2268
2269 /**
2270  * @internal
2271  *
2272  * This function is used to check if rotation gesture started.
2273  * @param st Contains current rotation values from user input.
2274  * @return TRUE/FALSE if we need to set rotation START.
2275  *
2276  * @ingroup Elm_Gesture_Layer
2277  */
2278 static Eina_Bool
2279 rotation_broke_tolerance(Rotate_Type *st)
2280 {
2281    if (st->info.base_angle < 0)
2282      return EINA_FALSE; /* Angle has to be computed first */
2283
2284    if (st->rotate_angular_tolerance < 0)
2285      return EINA_TRUE;
2286
2287    double low  = st->info.base_angle - st->rotate_angular_tolerance;
2288    double high = st->info.base_angle + st->rotate_angular_tolerance;
2289    double t = st->info.angle;
2290
2291    if (low < 0)
2292      {
2293         low += 180;
2294         high += 180;
2295
2296         if (t < 180)
2297           t += 180;
2298         else
2299           t -= 180;
2300      }
2301
2302    if (high > 360)
2303      {
2304         low -= 180;
2305         high -= 180;
2306
2307         if (t < 180)
2308           t += 180;
2309         else
2310           t -= 180;
2311      }
2312
2313 #if defined(DEBUG_GESTURE_LAYER)
2314    printf("%s angle=<%f> low=<%f> high=<%f>\n", __func__, t, low, high);
2315 #endif
2316    if ((t < low) || (t > high))
2317      {  /* This marks that roation action has started */
2318         st->rotate_angular_tolerance = ELM_GESTURE_NEGATIVE_ANGLE;
2319         st->info.base_angle = st->info.angle; /* Avoid jump in angle value */
2320         return EINA_TRUE;
2321      }
2322
2323    return EINA_FALSE;
2324 }
2325
2326 /**
2327  * @internal
2328  *
2329  * This function is used for computing the gap between fingers.
2330  * It returns the length and center point between fingers.
2331  *
2332  * @param x1 first finger x location.
2333  * @param y1 first finger y location.
2334  * @param x2 second finger x location.
2335  * @param y2 second finger y location.
2336  * @param x  Gets center point x cord (output)
2337  * @param y  Gets center point y cord (output)
2338  *
2339  * @return length of the line between (x1,y1), (x2,y2) in pixels.
2340  *
2341  * @ingroup Elm_Gesture_Layer
2342  */
2343 static Evas_Coord
2344 get_finger_gap_length(Evas_Coord x1, Evas_Coord y1, Evas_Coord x2,
2345       Evas_Coord y2, Evas_Coord *x, Evas_Coord *y)
2346 {
2347    double a, b, xx, yy, gap;
2348    xx = fabs(x2 - x1);
2349    yy = fabs(y2 - y1);
2350    gap = sqrt(xx*xx + yy*yy);
2351
2352    /* START - Compute zoom center point */
2353    /* The triangle defined as follows:
2354     *             B
2355     *           / |
2356     *          /  |
2357     *     gap /   | a
2358     *        /    |
2359     *       A-----C
2360     *          b
2361     * http://en.wikipedia.org/wiki/Trigonometric_functions
2362     *************************************/
2363    if (((int) xx) && ((int) yy))
2364      {
2365         double A = atan((yy / xx));
2366 #if defined(DEBUG_GESTURE_LAYER)
2367         printf("xx=<%f> yy=<%f> A=<%f>\n", xx, yy, A);
2368 #endif
2369         a = (Evas_Coord) ((gap / 2) * sin(A));
2370         b = (Evas_Coord) ((gap / 2) * cos(A));
2371         *x = (Evas_Coord) ((x2 > x1) ? (x1 + b) : (x2 + b));
2372         *y = (Evas_Coord) ((y2 > y1) ? (y1 + a) : (y2 + a));
2373      }
2374    else
2375      {
2376         if ((int) xx)
2377           {  /* horiz line, take half width */
2378 #if defined(DEBUG_GESTURE_LAYER)
2379              printf("==== HORIZ ====\n");
2380 #endif
2381              *x = (Evas_Coord) ((x1 + x2) / 2);
2382              *y = (Evas_Coord) (y1);
2383           }
2384
2385         if ((int) yy)
2386           {  /* vert line, take half width */
2387 #if defined(DEBUG_GESTURE_LAYER)
2388              printf("==== VERT ====\n");
2389 #endif
2390              *x = (Evas_Coord) (x1);
2391              *y = (Evas_Coord) ((y1 + y2) / 2);
2392           }
2393      }
2394    /* END   - Compute zoom center point */
2395
2396    return (Evas_Coord) gap;
2397 }
2398
2399 /**
2400  * @internal
2401  *
2402  * This function is used for computing zoom value.
2403  *
2404  * @param st Pointer to zoom data based on user input.
2405  * @param tm_end Recent input event timestamp.
2406  * @param zoom_val Current computed zoom value.
2407  *
2408  * @return zoom momentum
2409  *
2410  * @ingroup Elm_Gesture_Layer
2411  */
2412 static double
2413 _zoom_momentum_get(Zoom_Type *st, unsigned int tm_end, double zoom_val)
2414 {
2415    unsigned int tm_total;
2416    if (!st->m_st_tm)
2417      {  /* Init, and we don't start computing momentum yet */
2418         st->m_st_tm = st->m_prev_tm = tm_end;
2419         st->m_base = zoom_val;
2420         return 0.0;
2421      }
2422
2423    if ((tm_end - ELM_GESTURE_MOMENTUM_DELAY) < st->m_st_tm)
2424      return 0.0; /* we don't start to compute momentum yet */
2425
2426    if (st->dir)
2427      {  /* if direction was already defined, check if changed */
2428         if (((st->dir < 0) && (zoom_val > st->info.zoom)) ||
2429               ((st->dir > 0) && (zoom_val < st->info.zoom)))
2430           {  /* Direction changed, reset momentum */
2431              st->m_st_tm = 0;
2432              st->dir = (-st->dir);
2433              return 0.0;
2434           }
2435      }
2436    else
2437      st->dir = (zoom_val > st->info.zoom) ? 1 : -1;  /* init */
2438
2439    if ((tm_end - ELM_GESTURE_MOMENTUM_TIMEOUT) > st->m_prev_tm)
2440      {
2441         st->m_st_tm = 0; /* Rest momentum when waiting too long */
2442         return 0.0;
2443      }
2444
2445    st->m_prev_tm = tm_end;
2446    tm_total = tm_end - st->m_st_tm;
2447
2448    if (tm_total)
2449      return ((zoom_val - st->m_base)  * 1000) / tm_total;
2450    else
2451      return 0.0;
2452 }
2453
2454 /**
2455  * @internal
2456  *
2457  * This function is used for computing zoom value.
2458  *
2459  * @param st Pointer to zoom data based on user input.
2460  * @param x1 first finger x location.
2461  * @param y1 first finger y location.
2462  * @param x2 second finger x location.
2463  * @param y2 second finger y location.
2464  * @param factor zoom-factor, used to determine how fast zoom works.
2465  *
2466  * @return zoom value, when 1.0 means no zoom, 0.5 half size...
2467  *
2468  * @ingroup Elm_Gesture_Layer
2469  */
2470 static double
2471 compute_zoom(Zoom_Type *st, Evas_Coord x1, Evas_Coord y1,
2472       Evas_Coord x2, Evas_Coord y2, double zoom_finger_factor)
2473 {
2474    double rt = 1.0;
2475    unsigned int tm_end = (st->zoom_mv.timestamp > st->zoom_mv1.timestamp) ?
2476       st->zoom_mv.timestamp : st->zoom_mv1.timestamp;
2477
2478    Evas_Coord diam = get_finger_gap_length(x1, y1, x2, y2,
2479          &st->info.x, &st->info.y);
2480
2481    st->info.radius = diam / 2;
2482
2483    if (!st->zoom_base)
2484      {
2485         st->zoom_base = diam;
2486         return st->info.zoom;
2487      }
2488
2489    if (st->zoom_distance_tolerance)
2490      {  /* zoom tolerance <> ZERO, means zoom action NOT started yet */
2491         if (diam < (st->zoom_base - st->zoom_distance_tolerance))
2492           {  /* avoid jump with zoom value when break tolerance */
2493              st->zoom_base -= st->zoom_distance_tolerance;
2494              st->zoom_distance_tolerance = 0;
2495           }
2496
2497         if (diam > (st->zoom_base + st->zoom_distance_tolerance))
2498           {  /* avoid jump with zoom value when break tolerance */
2499              st->zoom_base += st->zoom_distance_tolerance;
2500              st->zoom_distance_tolerance = 0;
2501           }
2502
2503         return rt;
2504      }
2505
2506    /* We use factor only on the difference between gap-base   */
2507    /* if gap=120, base=100, we get ((120-100)/100)=0.2*factor */
2508    rt = ((1.0) + ((((float) diam - (float) st->zoom_base) /
2509                (float) st->zoom_base) * zoom_finger_factor));
2510
2511    /* Momentum: zoom per second: */
2512    st->info.momentum = _zoom_momentum_get(st, tm_end, rt);
2513
2514    return rt;
2515 }
2516
2517 /**
2518  * @internal
2519  *
2520  * This function handles zoom with mouse wheel.
2521  * thats a combination of wheel + CTRL key.
2522  * @param obj The gesture-layer object.
2523  * @param event_info Original input event pointer.
2524  * @param event_type Type of original input event.
2525  * @param g_type what Gesture we are testing.
2526  *
2527  * @ingroup Elm_Gesture_Layer
2528  */
2529 static void
2530 _zoom_with_wheel_test(Evas_Object *obj, void *event_info,
2531       Evas_Callback_Type event_type, Elm_Gesture_Type g_type)
2532 {
2533    Widget_Data *wd = elm_widget_data_get(obj);
2534    if (!wd) return;
2535    if (!wd->gesture[g_type]) return;
2536
2537    Gesture_Info *gesture_zoom = wd->gesture[g_type];
2538    Zoom_Type *st = gesture_zoom->data;
2539    Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
2540    if (!st)
2541      {  /* Allocated once on first time, used for zoom intermediate data */
2542         st = calloc(1, sizeof(Zoom_Type));
2543         gesture_zoom->data = st;
2544         _zoom_test_reset(gesture_zoom);
2545      }
2546
2547    switch (event_type)
2548      {
2549       case EVAS_CALLBACK_KEY_UP:
2550            {
2551               Evas_Event_Key_Up *p = event_info;
2552               if ((!strcmp(p->keyname, "Control_L")) ||
2553                     (!strcmp(p->keyname, "Control_R")))
2554                 {  /* Test if we ended a zoom gesture when releasing CTRL */
2555                    if ((st->zoom_wheel) &&
2556                          ((gesture_zoom->state == ELM_GESTURE_STATE_START) ||
2557                           (gesture_zoom->state == ELM_GESTURE_STATE_MOVE)))
2558                      {  /* User released CTRL after zooming */
2559                         st->info.momentum = _zoom_momentum_get(st,
2560                               p->timestamp, st->info.zoom);
2561
2562                         ev_flag = _set_state(gesture_zoom,
2563                               ELM_GESTURE_STATE_END, &st->info, EINA_FALSE);
2564                         consume_event(wd, event_info, event_type, ev_flag);
2565
2566                         return;
2567                      }
2568                 }
2569               break;
2570            }
2571
2572       case EVAS_CALLBACK_MOUSE_WHEEL:
2573            {
2574               Eina_Bool force;
2575               Elm_Gesture_State s;
2576               if (!evas_key_modifier_is_set(
2577                        ((Evas_Event_Mouse_Wheel *) event_info)->modifiers,
2578                        "Control"))
2579                 {  /* if using wheel witout CTRL after starting zoom */
2580                    if ((st->zoom_wheel) &&
2581                          ((gesture_zoom->state == ELM_GESTURE_STATE_START) ||
2582                           (gesture_zoom->state == ELM_GESTURE_STATE_MOVE)))
2583                      {
2584                         ev_flag = _set_state(gesture_zoom,
2585                               ELM_GESTURE_STATE_END, &st->info, EINA_FALSE);
2586                         consume_event(wd, event_info, event_type, ev_flag);
2587
2588                         return;
2589                      }
2590                    else
2591                      return; /* Ignore mouse-wheel without control */
2592                 }
2593
2594               /* Using mouse wheel with CTRL for zoom */
2595               if (st->zoom_wheel || (st->zoom_distance_tolerance == 0))
2596                 {  /* (zoom_wheel == NULL) and (zoom_distance_tolerance == 0)
2597                       we continue a zoom gesture */
2598                    force = EINA_TRUE;
2599                    s = ELM_GESTURE_STATE_MOVE;
2600                 }
2601               else
2602                 {  /* On first wheel event, report START */
2603                    Evas_Modifier_Mask mask = evas_key_modifier_mask_get(
2604                             evas_object_evas_get(wd->target), "Control");
2605                    force = EINA_FALSE;
2606                    s = ELM_GESTURE_STATE_START;
2607                    if (!evas_object_key_grab(wd->target, "Control_L", mask, 0, EINA_FALSE))
2608                      ERR("Failed to Grabbed CTRL_L");
2609                    if (!evas_object_key_grab(wd->target, "Control_R", mask, 0, EINA_FALSE))
2610                      ERR("Failed to Grabbed CTRL_R");
2611                 }
2612
2613               st->zoom_distance_tolerance = 0; /* Cancel tolerance */
2614               st->zoom_wheel = (Evas_Event_Mouse_Wheel *) event_info;
2615               st->info.x  = st->zoom_wheel->canvas.x;
2616               st->info.y  = st->zoom_wheel->canvas.y;
2617
2618               if (st->zoom_wheel->z < 0) /* zoom in */
2619                 st->info.zoom += (wd->zoom_finger_factor * wd->zoom_wheel_factor);
2620
2621               if (st->zoom_wheel->z > 0) /* zoom out */
2622                 st->info.zoom -= (wd->zoom_finger_factor * wd->zoom_wheel_factor);
2623
2624               if (st->info.zoom < 0.0)
2625                 st->info.zoom = 0.0;
2626
2627               st->info.momentum = _zoom_momentum_get(st,
2628                     st->zoom_wheel->timestamp, st->info.zoom);
2629
2630               ev_flag = _set_state(gesture_zoom, s, &st->info, force);
2631               consume_event(wd, event_info, event_type, ev_flag);
2632               break;
2633            }
2634
2635       default:
2636            return;
2637      }
2638 }
2639
2640 /**
2641  * @internal
2642  *
2643  * This function is used to test zoom gesture.
2644  * user may combine zoom, rotation together.
2645  * so its possible that both will be detected from input.
2646  * (both are two-finger movement-oriented gestures)
2647  *
2648  * @param obj The gesture-layer object.
2649  * @param event_info Pointer to recent input event.
2650  * @param event_type Recent input event type.
2651  * @param g_type what Gesture we are testing.
2652  *
2653  * @ingroup Elm_Gesture_Layer
2654  */
2655 static void
2656 _zoom_test(Evas_Object *obj, Pointer_Event *pe, void *event_info,
2657       Evas_Callback_Type event_type, Elm_Gesture_Type g_type)
2658 {
2659    if (!pe)
2660      return;
2661    Widget_Data *wd = elm_widget_data_get(obj);
2662    if (!wd) return;
2663    if (!wd->gesture[g_type]) return;
2664
2665    Gesture_Info *gesture_zoom = wd->gesture[g_type];
2666    Zoom_Type *st = gesture_zoom->data;
2667
2668    if (!st)
2669      {  /* Allocated once on first time, used for zoom data */
2670         st = calloc(1, sizeof(Zoom_Type));
2671         gesture_zoom->data = st;
2672         _zoom_test_reset(gesture_zoom);
2673      }
2674
2675
2676    /* Start - new zoom testing, letting all fingers start */
2677    Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
2678    switch (event_type)
2679      {
2680       case EVAS_CALLBACK_MOUSE_MOVE:
2681       case EVAS_CALLBACK_MULTI_MOVE:
2682          /* if non-continues mode and gesture NOT started, ignore MOVE */
2683          if ((!wd->glayer_continues_enable) &&
2684                (!st->zoom_st.timestamp))
2685            return;
2686
2687       case EVAS_CALLBACK_MOUSE_DOWN:
2688       case EVAS_CALLBACK_MULTI_DOWN:
2689            {  /* Here we take care of zoom-start and zoom move */
2690               Eina_List *l;
2691               Pointer_Event *p;
2692
2693               if(eina_list_count(wd->touched) > 2)
2694                 {  /* Process zoom only when 2 fingers on surface */
2695                    ev_flag = _set_state(gesture_zoom,
2696                          ELM_GESTURE_STATE_ABORT, &st->info, EINA_FALSE);
2697                    consume_event(wd, event_info, event_type, ev_flag);
2698
2699                    return;
2700                 }
2701
2702               if (!st->zoom_st.timestamp)
2703                 {  /* Now scan touched-devices list and find other finger */
2704                    EINA_LIST_FOREACH(wd->touched, l, p)
2705                      {  /* Device of other finger <> pe device */
2706                         if (p->device != pe->device)
2707                           break;
2708                      }
2709
2710                    if (!p)  /* Single finger on touch */
2711                         return;
2712
2713                    /* Record down fingers */
2714                    consume_event(wd, event_info, event_type, ev_flag);
2715                    memcpy(&st->zoom_st, pe, sizeof(Pointer_Event));
2716                    memcpy(&st->zoom_st1, p, sizeof(Pointer_Event));
2717
2718                    /* Set mv field as well to be ready for MOVE events  */
2719                    memcpy(&st->zoom_mv, pe, sizeof(Pointer_Event));
2720                    memcpy(&st->zoom_mv1, p, sizeof(Pointer_Event));
2721
2722                    /* Here we have zoom_st, zoom_st1 set, report START  */
2723                    /* Set zoom-base after BOTH down events  recorded    */
2724                    /* Compute length of line between fingers zoom start */
2725                    st->info.zoom = 1.0;
2726                    st->zoom_base = get_finger_gap_length(st->zoom_st1.x,
2727                          st->zoom_st1.y, st->zoom_st.x,  st->zoom_st.y,
2728                          &st->info.x, &st->info.y);
2729
2730                    st->info.radius = st->zoom_base / 2;
2731
2732                    if ((gesture_zoom->state != ELM_GESTURE_STATE_START) &&
2733                          (gesture_zoom->state != ELM_GESTURE_STATE_MOVE))
2734                      {  /* zoom started with mouse-wheel, don't report twice */
2735                         ev_flag = _set_state(gesture_zoom,
2736                               ELM_GESTURE_STATE_START, &st->info, EINA_FALSE);
2737                         consume_event(wd, event_info, event_type, ev_flag);
2738                      }
2739
2740                    return;  /* Zoom started */
2741                 }  /* End of ZOOM_START handling */
2742
2743
2744               /* if we got here, we have (exacally) two fingers on surfce */
2745               /* we also after START, report MOVE */
2746               /* First detect which finger moved  */
2747               if (pe->device == st->zoom_mv.device)
2748                 memcpy(&st->zoom_mv, pe, sizeof(Pointer_Event));
2749               else if (pe->device == st->zoom_mv1.device)
2750                 memcpy(&st->zoom_mv1, pe, sizeof(Pointer_Event));
2751
2752               /* Compute change in zoom as fingers move */
2753               st->info.zoom = compute_zoom(st,
2754                     st->zoom_mv.x, st->zoom_mv.y,
2755                     st->zoom_mv1.x, st->zoom_mv1.y,
2756                     wd->zoom_finger_factor);
2757
2758               if (!st->zoom_distance_tolerance)
2759                 {  /* Zoom broke tolerance, report move */
2760                    double d = st->info.zoom - st->next_step;
2761                    if (d < 0.0)
2762                      d = (-d);
2763
2764                    if (d >= wd->zoom_step)
2765                      {  /* Report move in steps */
2766                         st->next_step = st->info.zoom;
2767
2768                         ev_flag = _set_state(gesture_zoom,
2769                               ELM_GESTURE_STATE_MOVE,
2770                               &st->info, EINA_TRUE);
2771                         consume_event(wd, event_info, event_type, ev_flag);
2772                      }
2773                 }  /* End of ZOOM_MOVE handling */
2774
2775               return;
2776            }
2777
2778       case EVAS_CALLBACK_MOUSE_UP:
2779       case EVAS_CALLBACK_MULTI_UP:
2780          /* Reset timestamp of finger-up.This is used later
2781             by _zoom_test_reset() to retain finger-down data */
2782          consume_event(wd, event_info, event_type, ev_flag);
2783          if (((st->zoom_wheel) || (st->zoom_base)) &&
2784                (st->zoom_distance_tolerance == 0))
2785            {
2786               ev_flag = _set_state(gesture_zoom, ELM_GESTURE_STATE_END,
2787                     &st->info, EINA_FALSE);
2788               consume_event(wd, event_info, event_type, ev_flag);
2789
2790               return;
2791            }
2792
2793          /* if we got here not a ZOOM */
2794          if (gesture_zoom->state != ELM_GESTURE_STATE_UNDEFINED)
2795            {  /* Must be != undefined, if gesture started */
2796               ev_flag = _set_state(gesture_zoom,
2797                     ELM_GESTURE_STATE_ABORT, &st->info, EINA_FALSE);
2798               consume_event(wd, event_info, event_type, ev_flag);
2799            }
2800
2801          _zoom_test_reset(gesture_zoom);
2802
2803          return;
2804
2805       default:
2806          return;
2807        }
2808 }
2809
2810 static void
2811 _get_rotate_properties(Rotate_Type *st,
2812       Evas_Coord x1, Evas_Coord y1,
2813       Evas_Coord x2, Evas_Coord y2,
2814       double *angle)
2815 {  /* FIXME: Fix momentum computation, it's wrong */
2816    double prev_angle = *angle;
2817    st->info.radius = get_finger_gap_length(x1, y1, x2, y2,
2818          &st->info.x, &st->info.y) / 2;
2819
2820    *angle = get_angle(x1, y1, x2, y2);
2821
2822    if (angle == &st->info.angle)
2823      {  /* Fingers are moving, compute momentum */
2824         unsigned int tm_start =
2825            (st->rotate_st.timestamp > st->rotate_st1.timestamp)
2826            ?  st->rotate_st.timestamp : st->rotate_st1.timestamp;
2827         unsigned int tm_end =
2828            (st->rotate_mv.timestamp > st->rotate_mv1.timestamp)
2829            ? st->rotate_mv.timestamp : st->rotate_mv1.timestamp;
2830
2831         unsigned int tm_total = tm_end - tm_start;
2832         if (tm_total)
2833           {  /* Momentum computed as:
2834                 accumulated roation angle (deg) divided by time */
2835              double m = 0;;
2836              if (((prev_angle < 90) && ((*angle) > 270)) ||
2837                    ((prev_angle > 270) && ((*angle) < 90)))
2838                {  /* We circle passing ZERO point */
2839                   prev_angle = (*angle);
2840                }
2841              else m = prev_angle - (*angle);
2842
2843              st->accum_momentum += m;
2844
2845              if ((tm_end - st->prev_momentum_tm) < 100)
2846                st->prev_momentum += m;
2847              else
2848                {
2849                   if (fabs(st->prev_momentum) < 0.002)
2850                     st->accum_momentum = 0.0;  /* reset momentum */
2851
2852                   st->prev_momentum = 0.0;     /* Start again    */
2853                }
2854
2855              st->prev_momentum_tm = tm_end;
2856              st->info.momentum = (st->accum_momentum * 1000) / tm_total;
2857           }
2858      }
2859    else
2860      st->info.momentum = 0;
2861 }
2862
2863 /**
2864  * @internal
2865  *
2866  * This function is used to test rotation gesture.
2867  * user may combine zoom, rotation together.
2868  * so its possible that both will be detected from input.
2869  * (both are two-finger movement-oriented gestures)
2870  *
2871  * @param obj The gesture-layer object.
2872  * @param event_info Pointer to recent input event.
2873  * @param event_type Recent input event type.
2874  * @param g_type what Gesture we are testing.
2875  *
2876  * @ingroup Elm_Gesture_Layer
2877  */
2878 static void
2879 _rotate_test(Evas_Object *obj, Pointer_Event *pe, void *event_info,
2880       Evas_Callback_Type event_type, Elm_Gesture_Type g_type)
2881 {
2882    if (!pe)
2883      return;
2884
2885    Widget_Data *wd = elm_widget_data_get(obj);
2886    if (!wd) return;
2887    if (!wd->gesture[g_type]) return;
2888
2889    Gesture_Info *gesture = wd->gesture[g_type];
2890    Rotate_Type *st;
2891    if (gesture)
2892    {
2893       st = gesture->data;
2894       if (!st)
2895         {  /* Allocated once on first time */
2896            st = calloc(1, sizeof(Rotate_Type));
2897            gesture->data = st;
2898            _rotate_test_reset(gesture);
2899         }
2900    }
2901
2902    Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
2903    switch (event_type)
2904      {
2905       case EVAS_CALLBACK_MOUSE_MOVE:
2906       case EVAS_CALLBACK_MULTI_MOVE:
2907          /* if non-continues mode and gesture NOT started, ignore MOVE */
2908          if ((!wd->glayer_continues_enable) &&
2909                (!st->rotate_st.timestamp))
2910            return;
2911
2912       case EVAS_CALLBACK_MOUSE_DOWN:
2913       case EVAS_CALLBACK_MULTI_DOWN:
2914            {  /* Here we take care of rotate-start and rotate move */
2915               Eina_List *l;
2916               Pointer_Event *p;
2917
2918               if(eina_list_count(wd->touched) > 2)
2919                 {  /* Process rotate only when 2 fingers on surface */
2920                    ev_flag = _set_state(gesture,
2921                          ELM_GESTURE_STATE_ABORT, &st->info, EINA_FALSE);
2922                    consume_event(wd, event_info, event_type, ev_flag);
2923
2924                    return;
2925                 }
2926
2927               if (!st->rotate_st.timestamp)
2928                 {  /* Now scan touched-devices list and find other finger */
2929                    EINA_LIST_FOREACH(wd->touched, l, p)
2930                      {  /* Device of other finger <> pe device */
2931                         if (p->device != pe->device)
2932                           break;
2933                      }
2934
2935                    if (!p)
2936                         return;  /* Single finger on touch */
2937
2938                    /* Record down fingers */
2939                    consume_event(wd, event_info, event_type, ev_flag);
2940                    memcpy(&st->rotate_st, pe, sizeof(Pointer_Event));
2941                    memcpy(&st->rotate_st1, p, sizeof(Pointer_Event));
2942
2943                    /* Set mv field as well to be ready for MOVE events  */
2944                    memcpy(&st->rotate_mv, pe, sizeof(Pointer_Event));
2945                    memcpy(&st->rotate_mv1, p, sizeof(Pointer_Event));
2946
2947                    /* Here we have rotate_st, rotate_st1 set, report START  */
2948                    /* Set rotate-base after BOTH down events  recorded    */
2949                    /* Compute length of line between fingers rotate start */
2950                    _get_rotate_properties(st,
2951                          st->rotate_st.x, st->rotate_st.y,
2952                          st->rotate_st1.x, st->rotate_st1.y,
2953                          &st->info.base_angle);
2954
2955                    ev_flag = _set_state(gesture, ELM_GESTURE_STATE_START,
2956                          &st->info, EINA_FALSE);
2957                    consume_event(wd, event_info, event_type, ev_flag);
2958
2959                    return;  /* Rotate started */
2960                 }  /* End of ROTATE_START handling */
2961
2962
2963               /* if we got here, we have (exacally) two fingers on surfce */
2964               /* we also after START, report MOVE */
2965               /* First detect which finger moved  */
2966               if (pe->device == st->rotate_mv.device)
2967                 memcpy(&st->rotate_mv, pe, sizeof(Pointer_Event));
2968               else if (pe->device == st->rotate_mv1.device)
2969                 memcpy(&st->rotate_mv1, pe, sizeof(Pointer_Event));
2970
2971               /* Compute change in rotate as fingers move */
2972               _get_rotate_properties(st,
2973                     st->rotate_mv.x, st->rotate_mv.y,
2974                     st->rotate_mv1.x, st->rotate_mv1.y,
2975                     &st->info.angle);
2976
2977               if (rotation_broke_tolerance(st))
2978                 {  /* Rotation broke tolerance, report move */
2979                    double d = st->info.angle - st->next_step;
2980                    if (d < 0)
2981                      d = (-d);
2982
2983                    if (d >= wd->rotate_step)
2984                      {  /* Report move in steps */
2985                         st->next_step = st->info.angle;
2986
2987                         ev_flag = _set_state(gesture,
2988                               ELM_GESTURE_STATE_MOVE, &st->info, EINA_TRUE);
2989                         consume_event(wd, event_info, event_type, ev_flag);
2990                      }
2991                 }  /* End of ROTATE_MOVE handling */
2992
2993               return;
2994            }
2995
2996       case EVAS_CALLBACK_MOUSE_UP:
2997       case EVAS_CALLBACK_MULTI_UP:
2998            consume_event(wd, event_info, event_type, ev_flag);
2999            /* Reset timestamp of finger-up.This is used later
3000               by rotate_test_reset() to retain finger-down data */
3001            if (st->rotate_angular_tolerance < 0)
3002              {
3003                 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_END,
3004                       &st->info, EINA_FALSE);
3005                 consume_event(wd, event_info, event_type, ev_flag);
3006
3007                 return;
3008              }
3009
3010            if (gesture->state != ELM_GESTURE_STATE_UNDEFINED)
3011              {  /* Must be != undefined, if gesture started */
3012                 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
3013                       &st->info, EINA_FALSE);
3014                 consume_event(wd, event_info, event_type, ev_flag);
3015              }
3016
3017            _rotate_test_reset(gesture);
3018            return;
3019
3020       default:
3021          return;
3022        }
3023 }
3024
3025 /**
3026  * @internal
3027  *
3028  * This function is used to save input events in an abstract struct
3029  * to be used later by getsure-testing functions.
3030  *
3031  * @param data The gesture-layer object.
3032  * @param event_info Pointer to recent input event.
3033  * @param event_type Recent input event type.
3034  * @param pe The abstract data-struct (output).
3035  *
3036  * @ingroup Elm_Gesture_Layer
3037  */
3038 static Eina_Bool
3039 _make_pointer_event(void *data, void *event_info,
3040       Evas_Callback_Type event_type, Pointer_Event *pe)
3041 {
3042    Widget_Data *wd = elm_widget_data_get(data);
3043    if (!wd) return EINA_FALSE;
3044
3045    memset(pe, '\0', sizeof(*pe));
3046    switch (event_type)
3047      {
3048       case EVAS_CALLBACK_MOUSE_DOWN:
3049            pe->x = ((Evas_Event_Mouse_Down *) event_info)->canvas.x;
3050            pe->y = ((Evas_Event_Mouse_Down *) event_info)->canvas.y;
3051            pe->timestamp = ((Evas_Event_Mouse_Down *) event_info)->timestamp;
3052            pe->device = ELM_MOUSE_DEVICE;
3053            break;
3054
3055       case EVAS_CALLBACK_MOUSE_UP:
3056            pe->x = ((Evas_Event_Mouse_Up *) event_info)->canvas.x;
3057            pe->y = ((Evas_Event_Mouse_Up *) event_info)->canvas.y;
3058            pe->timestamp = ((Evas_Event_Mouse_Up *) event_info)->timestamp;
3059            pe->device = ELM_MOUSE_DEVICE;
3060            break;
3061
3062       case EVAS_CALLBACK_MOUSE_MOVE:
3063            pe->x = ((Evas_Event_Mouse_Move *) event_info)->cur.canvas.x;
3064            pe->y = ((Evas_Event_Mouse_Move *) event_info)->cur.canvas.y;
3065            pe->timestamp = ((Evas_Event_Mouse_Move *) event_info)->timestamp;
3066            pe->device = ELM_MOUSE_DEVICE;
3067            break;
3068
3069       case EVAS_CALLBACK_MULTI_DOWN:
3070            pe->x = ((Evas_Event_Multi_Down *) event_info)->canvas.x;
3071            pe->y = ((Evas_Event_Multi_Down *) event_info)->canvas.y;
3072            pe->timestamp = ((Evas_Event_Multi_Down *) event_info)->timestamp;
3073            pe->device = ((Evas_Event_Multi_Down *) event_info)->device;
3074            break;
3075
3076       case EVAS_CALLBACK_MULTI_UP:
3077            pe->x = ((Evas_Event_Multi_Up *) event_info)->canvas.x;
3078            pe->y = ((Evas_Event_Multi_Up *) event_info)->canvas.y;
3079            pe->timestamp = ((Evas_Event_Multi_Up *) event_info)->timestamp;
3080            pe->device = ((Evas_Event_Multi_Up *) event_info)->device;
3081            break;
3082
3083       case EVAS_CALLBACK_MULTI_MOVE:
3084            pe->x = ((Evas_Event_Multi_Move *) event_info)->cur.canvas.x;
3085            pe->y = ((Evas_Event_Multi_Move *) event_info)->cur.canvas.y;
3086            pe->timestamp = ((Evas_Event_Multi_Move *) event_info)->timestamp;
3087            pe->device = ((Evas_Event_Multi_Move *) event_info)->device;
3088            break;
3089
3090       default:
3091            return EINA_FALSE;
3092      }
3093
3094    pe->event_type = event_type;
3095    return EINA_TRUE;
3096 }
3097
3098 /**
3099  * @internal
3100  *
3101  * This function restartes line, flick, zoom and rotate gestures
3102  * when gesture-layer continues-gestures enabled.
3103  * Example of continues-gesture:
3104  * When doing a line, user stops moving finger but keeps fingers on touch.
3105  * This will cause line-end, then as user continues moving his finger
3106  * it re-starts line gesture.
3107  * When continue mode is disabled, user has to lift finger from touch
3108  * to end a gesture. Them touch-again to start a new one.
3109  *
3110  * @param data The gesture-layer object.
3111  * @param wd gesture layer widget data.
3112  * @param states_reset flag that marks gestures were reset in history clear.
3113  *
3114  * @ingroup Elm_Gesture_Layer
3115  */
3116 static void
3117 continues_gestures_restart(void *data, Eina_Bool states_reset)
3118 {
3119    Widget_Data *wd = elm_widget_data_get(data);
3120    if (!wd) return;
3121
3122    /* Run through events to restart gestures */
3123    Gesture_Info *g;
3124    Eina_Bool n_momentum, n_lines, n_flicks, zoom, rotate;
3125    /* We turn-on flag for finished, aborted, not-started gestures */
3126    g = wd->gesture[ELM_GESTURE_MOMENTUM];
3127    n_momentum = (g) ? ((states_reset) | ((g->state != ELM_GESTURE_STATE_START)
3128          && (g->state != ELM_GESTURE_STATE_MOVE))) : EINA_FALSE;
3129    if (n_momentum)
3130      {
3131         _momentum_test_reset(wd->gesture[ELM_GESTURE_MOMENTUM]);
3132         _set_state(g, ELM_GESTURE_STATE_UNDEFINED, NULL, EINA_FALSE);
3133         SET_TEST_BIT(g);
3134      }
3135
3136    g = wd->gesture[ELM_GESTURE_N_LINES];
3137    n_lines = (g) ? ((states_reset) | ((g->state != ELM_GESTURE_STATE_START)
3138          && (g->state != ELM_GESTURE_STATE_MOVE))) : EINA_FALSE;
3139    if (n_lines)
3140      {
3141         _line_test_reset(wd->gesture[ELM_GESTURE_N_LINES]);
3142         _set_state(g, ELM_GESTURE_STATE_UNDEFINED, NULL, EINA_FALSE);
3143         SET_TEST_BIT(g);
3144      }
3145
3146    g = wd->gesture[ELM_GESTURE_N_FLICKS];
3147    n_flicks = (g) ? ((states_reset) | ((g->state != ELM_GESTURE_STATE_START)
3148          && (g->state != ELM_GESTURE_STATE_MOVE))) : EINA_FALSE;
3149    if (n_flicks)
3150      {
3151         _line_test_reset(wd->gesture[ELM_GESTURE_N_FLICKS]);
3152         _set_state(g, ELM_GESTURE_STATE_UNDEFINED, NULL, EINA_FALSE);
3153         SET_TEST_BIT(g);
3154      }
3155
3156    g = wd->gesture[ELM_GESTURE_ZOOM];
3157    zoom = (g) ? ((states_reset) | ((g->state != ELM_GESTURE_STATE_START)
3158          && (g->state != ELM_GESTURE_STATE_MOVE))) : EINA_FALSE;
3159    if (zoom)
3160      {
3161         _zoom_test_reset(wd->gesture[ELM_GESTURE_ZOOM]);
3162         _set_state(g, ELM_GESTURE_STATE_UNDEFINED, NULL, EINA_FALSE);
3163         SET_TEST_BIT(g);
3164      }
3165
3166    g = wd->gesture[ELM_GESTURE_ROTATE];
3167    rotate = (g) ? ((states_reset) | ((g->state != ELM_GESTURE_STATE_START)
3168          && (g->state != ELM_GESTURE_STATE_MOVE))) : EINA_FALSE;
3169    if (rotate)
3170      {
3171         _rotate_test_reset(wd->gesture[ELM_GESTURE_ROTATE]);
3172         _set_state(g, ELM_GESTURE_STATE_UNDEFINED, NULL, EINA_FALSE);
3173         SET_TEST_BIT(g);
3174      }
3175 }
3176
3177 /**
3178  * @internal
3179  *
3180  * This function the core-function where input handling is done.
3181  * Here we get user input and stream it to gesture testing.
3182  * We notify user about any gestures with new state:
3183  * Valid states are:
3184  * START - gesture started.
3185  * MOVE - gesture is ongoing.
3186  * END - gesture was completed.
3187  * ABORT - gesture was aborted after START, MOVE (will NOT be completed)
3188  *
3189  * We also check if a gesture was detected, then reset event history
3190  * If no gestures were found we reset gesture test flag
3191  * after streaming event-history to widget.
3192  * (stream to the widget all events not consumed as a gesture)
3193  *
3194  * @param data The gesture-layer object.
3195  * @param event_info Pointer to recent input event.
3196  * @param event_type Recent input event type.
3197  *
3198  * @ingroup Elm_Gesture_Layer
3199  */
3200 static void
3201 _event_process(void *data, Evas_Object *obj __UNUSED__,
3202       void *event_info, Evas_Callback_Type event_type)
3203 {
3204    Pointer_Event _pe;
3205    Pointer_Event *pe = NULL;
3206    Widget_Data *wd = elm_widget_data_get(data);
3207
3208 #if defined(DEBUG_GESTURE_LAYER)
3209    int i;
3210    Gesture_Info *g;
3211    printf("Gesture | State | is tested\n");
3212    for(i = ELM_GESTURE_N_TAPS; i < ELM_GESTURE_LAST; i++)
3213      {
3214         g = wd->gesture[i];
3215         if(g)
3216           printf("   %d       %d       %d\n", i, g->state, g->test);
3217      }
3218 #endif
3219
3220    /* Start testing candidate gesture from here */
3221    if (_make_pointer_event(data, event_info, event_type, &_pe))
3222      pe = &_pe;
3223
3224    if (IS_TESTED(ELM_GESTURE_N_LONG_TAPS))
3225      _n_long_tap_test(data, pe, event_info, event_type,
3226            ELM_GESTURE_N_LONG_TAPS);
3227
3228    /* This takes care of single, double and tripple tap */
3229    _tap_gestures_test(data, pe, event_info, event_type);
3230
3231    if (IS_TESTED(ELM_GESTURE_MOMENTUM))
3232      _momentum_test(data, pe, event_info, event_type,
3233            ELM_GESTURE_MOMENTUM);
3234
3235    if (IS_TESTED(ELM_GESTURE_N_LINES))
3236      _n_line_test(data, pe, event_info, event_type, ELM_GESTURE_N_LINES);
3237
3238    if (IS_TESTED(ELM_GESTURE_N_FLICKS))
3239      _n_line_test(data, pe, event_info, event_type, ELM_GESTURE_N_FLICKS);
3240
3241    if (_elm_config->glayer_zoom_finger_enable && IS_TESTED(ELM_GESTURE_ZOOM))
3242      _zoom_test(data, pe, event_info, event_type, ELM_GESTURE_ZOOM);
3243
3244    if (IS_TESTED(ELM_GESTURE_ZOOM))
3245      _zoom_with_wheel_test(data, event_info, event_type, ELM_GESTURE_ZOOM);
3246
3247    if (_elm_config->glayer_rotate_finger_enable && IS_TESTED(ELM_GESTURE_ROTATE))
3248      _rotate_test(data, pe, event_info, event_type, ELM_GESTURE_ROTATE);
3249
3250    if (_get_event_flag(event_info, event_type) & EVAS_EVENT_FLAG_ON_HOLD)
3251      _event_history_add(data, event_info, event_type);
3252    else if ((event_type == EVAS_CALLBACK_MOUSE_UP) ||
3253          (event_type == EVAS_CALLBACK_MULTI_UP))
3254      {
3255         Eina_List *pending = _device_is_pending(wd->pending, event_info, event_type);
3256         if (pending)
3257           {
3258              consume_event(wd, event_info, event_type, EVAS_EVENT_FLAG_ON_HOLD);
3259              _event_history_add(data, event_info, event_type);
3260           }
3261      }
3262
3263    /* we maintain list of touched devices              */
3264    /* We also use move to track current device x.y pos */
3265    if ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
3266          (event_type == EVAS_CALLBACK_MULTI_DOWN) ||
3267          (event_type == EVAS_CALLBACK_MOUSE_MOVE) ||
3268          (event_type == EVAS_CALLBACK_MULTI_MOVE))
3269      {
3270         wd->touched = _add_touched_device(wd->touched, pe);
3271      }
3272    else if ((event_type == EVAS_CALLBACK_MOUSE_UP) ||
3273          (event_type == EVAS_CALLBACK_MULTI_UP))
3274      {
3275         wd->touched = _remove_touched_device(wd->touched, pe);
3276      }
3277
3278    /* Report current states and clear history if needed */
3279    Eina_Bool states_reset = _clear_if_finished(data);
3280    if (wd->glayer_continues_enable)
3281      continues_gestures_restart(data, states_reset);
3282 }
3283
3284
3285 /**
3286  * For all _mouse_* / multi_* functions wethen send this event to
3287  * _event_process function.
3288  *
3289  * @param data The gesture-layer object.
3290  * @param event_info Pointer to recent input event.
3291  *
3292  * @ingroup Elm_Gesture_Layer
3293  */
3294 static void
3295 _mouse_down(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3296       void *event_info)
3297 {
3298    Widget_Data *wd = elm_widget_data_get(data);
3299    if (!wd) return;
3300    if (((Evas_Event_Mouse_Down *) event_info)->button != 1)
3301      return; /* We only process left-click at the moment */
3302
3303    _event_process(data, obj, event_info, EVAS_CALLBACK_MOUSE_DOWN);
3304 }
3305
3306 static void
3307 _mouse_move(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3308       void *event_info)
3309 {
3310    Widget_Data *wd = elm_widget_data_get(data);
3311    if (!wd) return;
3312
3313    _event_process(data, obj, event_info, EVAS_CALLBACK_MOUSE_MOVE);
3314 }
3315
3316 static void
3317 _key_down_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3318       void *event_info)
3319 {
3320    Widget_Data *wd = elm_widget_data_get(data);
3321    if (!wd) return;
3322
3323    _event_process(data, obj, event_info, EVAS_CALLBACK_KEY_DOWN);
3324 }
3325
3326 static void
3327 _key_up_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3328       void *event_info)
3329 {
3330    Widget_Data *wd = elm_widget_data_get(data);
3331    if (!wd) return;
3332
3333    _event_process(data, obj, event_info, EVAS_CALLBACK_KEY_UP);
3334 }
3335
3336 static void
3337 _mouse_up(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3338       void *event_info)
3339 {
3340    Widget_Data *wd = elm_widget_data_get(data);
3341    if (!wd) return;
3342
3343    if (((Evas_Event_Mouse_Up *) event_info)->button != 1)
3344      return; /* We only process left-click at the moment */
3345
3346    _event_process(data, obj, event_info, EVAS_CALLBACK_MOUSE_UP);
3347 }
3348
3349 static void
3350 _mouse_wheel(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3351       void *event_info)
3352 {
3353    Widget_Data *wd = elm_widget_data_get(data);
3354    if (!wd) return;
3355
3356    _event_process(data, obj, event_info, EVAS_CALLBACK_MOUSE_WHEEL);
3357 }
3358
3359 static void
3360 _multi_down(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3361       void *event_info)
3362 {
3363    Widget_Data *wd = elm_widget_data_get(data);
3364    if (!wd) return;
3365
3366    _event_process(data, obj, event_info, EVAS_CALLBACK_MULTI_DOWN);
3367 }
3368
3369 static void
3370 _multi_move(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3371       void *event_info)
3372 {
3373    Widget_Data *wd = elm_widget_data_get(data);
3374    if (!wd) return;
3375
3376    _event_process(data, obj, event_info, EVAS_CALLBACK_MULTI_MOVE);
3377 }
3378
3379 static void
3380 _multi_up(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3381       void *event_info)
3382 {
3383    Widget_Data *wd = elm_widget_data_get(data);
3384    if (!wd) return;
3385
3386    _event_process(data, obj, event_info, EVAS_CALLBACK_MULTI_UP);
3387 }
3388
3389 EAPI Eina_Bool
3390 elm_gesture_layer_hold_events_get(const Evas_Object *obj)
3391 {
3392    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
3393
3394    Widget_Data *wd = elm_widget_data_get(obj);
3395    if (!wd) return EINA_FALSE;
3396
3397    return !wd->repeat_events;
3398 }
3399
3400 EAPI void
3401 elm_gesture_layer_hold_events_set(Evas_Object *obj, Eina_Bool hold_events)
3402 {
3403    ELM_CHECK_WIDTYPE(obj, widtype);
3404
3405    Widget_Data *wd = elm_widget_data_get(obj);
3406    if (!wd) return;
3407
3408    wd->repeat_events = !(!!hold_events);
3409 }
3410
3411 EAPI double
3412 elm_gesture_layer_zoom_step_get(const Evas_Object *obj)
3413 {
3414    ELM_CHECK_WIDTYPE(obj, widtype) 0;
3415
3416    Widget_Data *wd = elm_widget_data_get(obj);
3417    if (!wd) return 0;
3418
3419    return wd->zoom_step;
3420 }
3421
3422 EAPI void
3423 elm_gesture_layer_zoom_step_set(Evas_Object *obj, double step)
3424 {
3425    ELM_CHECK_WIDTYPE(obj, widtype);
3426
3427    Widget_Data *wd = elm_widget_data_get(obj);
3428    if (!wd) return;
3429
3430    if (step < 0) return;
3431
3432    wd->zoom_step = step;
3433 }
3434
3435 EAPI double
3436 elm_gesture_layer_rotate_step_get(const Evas_Object *obj)
3437 {
3438    ELM_CHECK_WIDTYPE(obj, widtype) 0;
3439
3440    Widget_Data *wd = elm_widget_data_get(obj);
3441    if (!wd) return 0;
3442
3443    return wd->rotate_step;
3444 }
3445
3446 EAPI void
3447 elm_gesture_layer_rotate_step_set(Evas_Object *obj, double step)
3448 {
3449    ELM_CHECK_WIDTYPE(obj, widtype);
3450
3451    Widget_Data *wd = elm_widget_data_get(obj);
3452    if (!wd) return;
3453
3454    if (step < 0) return;
3455
3456    wd->rotate_step = step;
3457 }
3458
3459 EAPI Eina_Bool
3460 elm_gesture_layer_attach(Evas_Object *obj, Evas_Object *target)
3461 {
3462    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
3463
3464    Widget_Data *wd = elm_widget_data_get(obj);
3465    if (!wd) return EINA_FALSE;
3466
3467    if (!target) return EINA_FALSE;
3468
3469    /* if was attached before, unregister callbacks first */
3470    if (wd->target)
3471      _unregister_callbacks(obj);
3472
3473    wd->target = target;
3474
3475    _register_callbacks(obj);
3476    return EINA_TRUE;
3477 }
3478
3479 EAPI void
3480 elm_gesture_layer_cb_set(Evas_Object *obj, Elm_Gesture_Type idx,
3481       Elm_Gesture_State cb_type, Elm_Gesture_Event_Cb cb, void *data)
3482 {
3483    ELM_CHECK_WIDTYPE(obj, widtype);
3484
3485    Widget_Data *wd = elm_widget_data_get(obj);
3486    Gesture_Info *p;
3487    if (!wd) return;
3488
3489    if (!wd->gesture[idx])
3490      wd->gesture[idx] = calloc(1, sizeof(Gesture_Info));
3491    if (!wd->gesture[idx]) return;
3492
3493    p = wd->gesture[idx];
3494    p->obj = obj;
3495    p->g_type = idx;
3496    p->fn[cb_type].cb = cb;
3497    p->fn[cb_type].user_data = data;
3498    p->state = ELM_GESTURE_STATE_UNDEFINED;
3499    SET_TEST_BIT(p);
3500 }
3501
3502 static void
3503 _disable_hook(Evas_Object *obj)
3504 {
3505    if (elm_widget_disabled_get(obj))
3506      _unregister_callbacks(obj);
3507    else
3508      _register_callbacks(obj);
3509 }
3510
3511 EAPI Evas_Object *
3512 elm_gesture_layer_add(Evas_Object *parent)
3513 {
3514    Evas_Object *obj;
3515    Evas *e;
3516    Widget_Data *wd;
3517
3518    ELM_WIDGET_STANDARD_SETUP(wd, Widget_Data, parent, e, obj, NULL);
3519
3520    ELM_SET_WIDTYPE(widtype, "gesture_layer");
3521    elm_widget_type_set(obj, "gesture_layer");
3522    elm_widget_sub_object_add(parent, obj);
3523    elm_widget_data_set(obj, wd);
3524    elm_widget_del_hook_set(obj, _del_hook);
3525    elm_widget_disable_hook_set(obj, _disable_hook);
3526
3527    wd->target = NULL;
3528    wd->line_min_length =_elm_config->glayer_line_min_length * _elm_config->finger_size;
3529    wd->zoom_distance_tolerance = _elm_config->glayer_zoom_distance_tolerance * _elm_config->finger_size;
3530    wd->line_distance_tolerance = _elm_config->glayer_line_distance_tolerance * _elm_config->finger_size;
3531    wd->zoom_finger_factor = _elm_config->glayer_zoom_finger_factor;
3532    wd->zoom_wheel_factor = _elm_config->glayer_zoom_wheel_factor; /* mouse wheel zoom steps */
3533    wd->rotate_angular_tolerance = _elm_config->glayer_rotate_angular_tolerance;
3534    wd->line_angular_tolerance = _elm_config->glayer_line_angular_tolerance;
3535    wd->flick_time_limit_ms = _elm_config->glayer_flick_time_limit_ms;
3536    wd->long_tap_start_timeout = _elm_config->glayer_long_tap_start_timeout;
3537    wd->repeat_events = EINA_TRUE;
3538    wd->glayer_continues_enable = _elm_config->glayer_continues_enable;
3539
3540 #if defined(DEBUG_GESTURE_LAYER)
3541    printf("size of Gestures = <%d>\n", sizeof(wd->gesture));
3542    printf("initial values:\n\tzoom_finger_factor=<%f>\n\tzoom_distance_tolerance=<%d>\n\tline_min_length=<%d>\n\tline_distance_tolerance=<%d>\n\tzoom_wheel_factor=<%f>\n\trotate_angular_tolerance=<%f>\n\twd->line_angular_tolerance=<%f>\n\twd->flick_time_limit_ms=<%d>\n\twd->long_tap_start_timeout=<%f>\n\twd->zoom_step=<%f>\n\twd->rotate_step=<%f>\n\twd->glayer_continues_enable=<%d>\n ", wd->zoom_finger_factor, wd->zoom_distance_tolerance, wd->line_min_length, wd->line_distance_tolerance, wd->zoom_wheel_factor, wd->rotate_angular_tolerance, wd->line_angular_tolerance, wd->flick_time_limit_ms, wd->long_tap_start_timeout, wd->zoom_step, wd->rotate_step, wd->glayer_continues_enable);
3543 #endif
3544    memset(wd->gesture, 0, sizeof(wd->gesture));
3545
3546    return obj;
3547 }