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