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