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