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