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