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