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