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