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