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