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