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