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