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