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