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