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