Gesture Layer: support multiple callbacks per type/state.
[platform/upstream/elementary.git] / src / lib / elm_gesture_layer.c
1 #ifdef HAVE_CONFIG_H
2 # include "elementary_config.h"
3 #endif
4
5 #include <Elementary.h>
6 #include "elm_priv.h"
7
8 EAPI Eo_Op ELM_OBJ_GESTURE_LAYER_BASE_ID = EO_NOOP;
9
10 #define MY_CLASS ELM_OBJ_GESTURE_LAYER_CLASS
11
12 #define MY_CLASS_NAME "elm_gesture_layer"
13
14 /* Some defaults */
15 #define ELM_MOUSE_DEVICE             0
16 /* ELM_GESTURE_NEGATIVE_ANGLE - magic number says we didn't compute this yet */
17 #define ELM_GESTURE_NEGATIVE_ANGLE   (-1.0) /* Magic number */
18 #define ELM_GESTURE_MOMENTUM_DELAY   25
19 #define ELM_GESTURE_MOMENTUM_TIMEOUT 50
20 #define ELM_GESTURE_MULTI_TIMEOUT    50
21 #define ELM_GESTURE_MINIMUM_MOMENTUM 0.001
22
23 /* Some Trigo values */
24 #define RAD_90DEG                    M_PI_2
25 #define RAD_180DEG                   M_PI
26 #define RAD_270DEG                   (M_PI_2 * 3)
27 #define RAD_360DEG                   (M_PI * 2)
28
29 #define RAD2DEG(x) ((x) * 57.295779513)
30 #define DEG2RAD(x) ((x) / 57.295779513)
31
32 static void *
33 _glayer_buf_dup(void *buf, size_t size)
34 {
35    void *p;
36
37    p = malloc(size);
38    memcpy(p, buf, size);
39
40    return p;
41 }
42
43 #define COPY_EVENT_INFO(EV) _glayer_buf_dup(EV, sizeof(*EV))
44
45 #define SET_TEST_BIT(P)                               \
46   do {                                                \
47        P->test = P->cbs[ELM_GESTURE_STATE_START] || \
48          P->cbs[ELM_GESTURE_STATE_MOVE] ||          \
49          P->cbs[ELM_GESTURE_STATE_END] ||           \
50          P->cbs[ELM_GESTURE_STATE_ABORT];           \
51     } while (0)
52
53 #define IS_TESTED_GESTURE(gesture) \
54   ((gesture) ? (gesture)->test : EINA_FALSE)
55
56 #define IS_TESTED(T) \
57   ((sd->gesture[T]) ? sd->gesture[T]->test : EINA_FALSE)
58
59 #define ELM_GESTURE_LAYER_DATA_GET(o, sd) \
60   Elm_Gesture_Layer_Smart_Data * sd = eo_data_scope_get(o, MY_CLASS)
61
62 #define ELM_GESTURE_LAYER_DATA_GET_OR_RETURN(o, ptr) \
63   ELM_GESTURE_LAYER_DATA_GET(o, ptr);                \
64   if (!ptr)                                          \
65     {                                                \
66        CRITICAL("No widget data for object %p (%s)", \
67                 o, evas_object_type_get(o));         \
68        return;                                       \
69     }
70
71 #define ELM_GESTURE_LAYER_DATA_GET_OR_RETURN_VAL(o, ptr, val) \
72   ELM_GESTURE_LAYER_DATA_GET(o, ptr);                         \
73   if (!ptr)                                                   \
74     {                                                         \
75        CRITICAL("No widget data for object %p (%s)",          \
76                 o, evas_object_type_get(o));                  \
77        return val;                                            \
78     }
79
80 #define ELM_GESTURE_LAYER_CHECK(obj)                                      \
81   if (!obj || !eo_isa(obj, MY_CLASS)) \
82     return
83
84 /**
85  * @internal
86  *
87  * @struct _Pointer_Event
88  * Struct holds pointer-event info
89  * This is a generic pointer event structure
90  *
91  * @ingroup Elm_Gesture_Layer
92  */
93 struct _Pointer_Event
94 {
95    Evas_Coord         x, y;
96    unsigned int       timestamp;
97    int                device;
98    Evas_Callback_Type event_type;
99 };
100
101 /**
102  * @internal
103  *
104  * @typedef Pointer_Event
105  * Type for generic pointer event structure
106  *
107  * @ingroup Elm_Gesture_Layer
108  */
109 typedef struct _Pointer_Event Pointer_Event;
110
111 /**
112  * @internal
113  *
114  * @struct _Func_Data
115  * Struct holds callback information.
116  *
117  * @ingroup Elm_Gesture_Layer
118  */
119 struct _Func_Data
120 {
121    EINA_INLIST;
122    void                *user_data; /**< Holds user data to CB (like sd) */
123    Elm_Gesture_Event_Cb cb;
124 };
125
126 /**
127  * @internal
128  *
129  * @typedef Func_Data
130  * type for callback information
131  *
132  * @ingroup Elm_Gesture_Layer
133  */
134 typedef struct _Func_Data Func_Data;
135
136 /**
137  * @internal
138  *
139  * @struct _Gesture_Info
140  * Struct holds gesture info
141  *
142  * @ingroup Elm_Gesture_Layer
143  */
144 struct _Gesture_Info
145 {
146    Evas_Object      *obj;
147    void             *data; /**< Holds gesture intemidiate processing data */
148    Eina_Inlist      *cbs[ELM_GESTURE_STATE_ABORT + 1]; /**< Callback info (Func_Data) for states */
149    Elm_Gesture_Type  g_type; /**< gesture type */
150    Elm_Gesture_State state; /**< gesture state */
151    void             *info; /**< Data for the state callback */
152    Eina_Bool         test; /**< if true this gesture should be tested on input */
153 };
154
155 /**
156  * @internal
157  *
158  * @typedef Gesture_Info
159  * Type for _Gesture_Info
160  *
161  * @ingroup Elm_Gesture_Layer
162  */
163 typedef struct _Gesture_Info Gesture_Info;
164
165 typedef struct
166 {
167    void (*test)(Evas_Object *obj, Pointer_Event *pe,
168                 void *event_info, Evas_Callback_Type event_type,
169                 Elm_Gesture_Type g_type);
170    void (*reset)(Gesture_Info *gesture);
171    void (*cont_reset)(Gesture_Info *gesture); /* Can be NULL. */
172 } Tests_Array_Funcs;
173
174 /* functions referred by _glayer_tests_array */
175 static void _tap_gesture_test(Evas_Object *obj,
176                               Pointer_Event *pe,
177                               void *event_info,
178                               Evas_Callback_Type event_type,
179                               Elm_Gesture_Type g_type);
180 static void _tap_gestures_test_reset(Gesture_Info *gesture);
181 static void _n_long_tap_test(Evas_Object *obj,
182                              Pointer_Event *pe,
183                              void *event_info,
184                              Evas_Callback_Type event_type,
185                              Elm_Gesture_Type g_type);
186 static void _n_long_tap_test_reset(Gesture_Info *gesture);
187 static void _momentum_test(Evas_Object *obj,
188                            Pointer_Event *pe,
189                            void *event_info,
190                            Evas_Callback_Type event_type,
191                            Elm_Gesture_Type g_type);
192 static void _momentum_test_reset(Gesture_Info *gesture);
193 static void _n_line_test(Evas_Object *obj,
194                          Pointer_Event *pe,
195                          void *event_info,
196                          Evas_Callback_Type event_type,
197                          Elm_Gesture_Type g_type);
198 static void _line_test_reset(Gesture_Info *gesture);
199 static void _zoom_test(Evas_Object *obj,
200                        Pointer_Event *pe,
201                        void *event_info,
202                        Evas_Callback_Type event_type,
203                        Elm_Gesture_Type g_type);
204 static void _zoom_test_reset(Gesture_Info *gesture);
205 static void _rotate_test(Evas_Object *obj,
206                          Pointer_Event *pe,
207                          void *event_info,
208                          Evas_Callback_Type event_type,
209                          Elm_Gesture_Type g_type);
210 static void _rotate_test_reset(Gesture_Info *gesture);
211
212 static void _event_process(void *data,
213                            Evas_Object *obj,
214                            void *event_info,
215                            Evas_Callback_Type event_type);
216
217 static void _callbacks_unregister(Evas_Object *obj);
218
219 /* Should be the same order as _Elm_Gesture_Type */
220 static Tests_Array_Funcs _glayer_tests_array[] = {
221    { NULL, NULL, NULL },     /** Because someone made an awful mistake. */
222    { _tap_gesture_test, _tap_gestures_test_reset, NULL },
223    /* ELM_GESTURE_N_TAPS */
224    { _n_long_tap_test, _n_long_tap_test_reset, NULL },
225    /* ELM_GESTURE_N_LONG_TAPS */
226    { _tap_gesture_test, _tap_gestures_test_reset, NULL },
227    /* ELM_GESTURE_N_DOUBLE_TAPS */
228    { _tap_gesture_test, _tap_gestures_test_reset, NULL },
229    /* ELM_GESTURE_N_TRIPLE_TAPS */
230    { _momentum_test, _momentum_test_reset, _momentum_test_reset },
231    /* ELM_GESTURE_MOMENTUM */
232    { _n_line_test, _line_test_reset, _line_test_reset },
233    /* ELM_GESTURE_N_LINES */
234    { _n_line_test, _line_test_reset, _line_test_reset },
235    /* ELM_GESTURE_N_FLICKS */
236    { _zoom_test, _zoom_test_reset, _zoom_test_reset },
237    /* ELM_GESTURE_ZOOM */
238    { _rotate_test, _rotate_test_reset, _rotate_test_reset },
239    /* ELM_GESTURE_ROTATE */
240    { NULL, NULL, NULL }
241 };
242
243 /**
244  * @internal
245  *
246  * @struct _Event_History
247  * Struct holds event history.
248  * These events are repeated if no gesture found.
249  *
250  * @ingroup Elm_Gesture_Layer
251  */
252 struct _Event_History
253 {
254    EINA_INLIST;
255    void              *event;
256    Evas_Callback_Type event_type;
257 };
258
259 /**
260  * @internal
261  *
262  * @typedef Event_History
263  * Type for _Event_History
264  *
265  * @ingroup Elm_Gesture_Layer
266  */
267 typedef struct _Event_History Event_History;
268
269 /* All *Type structs hold result for the user in 'info' field
270  * The rest is gesture processing intermediate data.
271  * NOTE: info field must be FIRST in the struct.
272  * This is used when reporting ABORT in _event_history_clear() */
273 struct _Taps_Type
274 {
275    Elm_Gesture_Taps_Info info;
276    unsigned int          sum_x;
277    unsigned int          sum_y;
278    unsigned int          n_taps_needed;
279    unsigned int          n_taps;
280    Eina_List            *l;
281 };
282 typedef struct _Taps_Type Taps_Type;
283
284 struct _Long_Tap_Type
285 {
286    Elm_Gesture_Taps_Info info;
287    Evas_Coord            center_x;
288    Evas_Coord            center_y;
289    Ecore_Timer          *timeout; /* When this expires, long tap STARTed */
290    Eina_List            *touched;
291 };
292 typedef struct _Long_Tap_Type Long_Tap_Type;
293
294 struct _Momentum_Type /* Fields used by _line_test() */
295 {
296    Elm_Gesture_Momentum_Info info;
297    Evas_Coord_Point          line_st;
298    Evas_Coord_Point          line_end;
299    unsigned int              t_st_x; /* Time start on X */
300    unsigned int              t_st_y; /* Time start on Y */
301    unsigned int              t_end; /* Time end        */
302    unsigned int              t_up; /* Recent up event time */
303    int                       xdir, ydir;
304 };
305 typedef struct _Momentum_Type Momentum_Type;
306
307 struct _Line_Data
308 {
309    Evas_Coord_Point line_st;
310    Evas_Coord_Point line_end;
311    Evas_Coord       line_length;
312    unsigned int     t_st; /* Time start */
313    unsigned int     t_end; /* Time end   */
314    int              device;
315    double           line_angle; /* Current angle of line */
316 };
317 typedef struct _Line_Data Line_Data;
318
319 struct _Line_Type /* Fields used by _line_test() */
320 {
321    Elm_Gesture_Line_Info info;
322    Eina_List            *list; /* List of Line_Data */
323 };
324 typedef struct _Line_Type Line_Type;
325
326 struct _Zoom_Type /* Fields used by _zoom_test() */
327 {
328    Elm_Gesture_Zoom_Info   info;
329    Pointer_Event           zoom_st;
330    Pointer_Event           zoom_mv;
331    Pointer_Event           zoom_st1;
332    Pointer_Event           zoom_mv1;
333    Evas_Event_Mouse_Wheel *zoom_wheel;
334    Evas_Coord              zoom_base; /* Holds gap between fingers on
335                                        * zoom-start  */
336    Evas_Coord              zoom_distance_tolerance;
337    unsigned int            m_st_tm; /* momentum start time */
338    unsigned int            m_prev_tm; /* momentum prev time  */
339    int                     dir; /* Direction: 1=zoom-in, (-1)=zoom-out */
340    double                  m_base; /* zoom value when momentum starts */
341    double                  next_step;
342 };
343 typedef struct _Zoom_Type Zoom_Type;
344
345 struct _Rotate_Type /* Fields used by _rotation_test() */
346 {
347    Elm_Gesture_Rotate_Info info;
348    Pointer_Event           rotate_st;
349    Pointer_Event           rotate_mv;
350    Pointer_Event           rotate_st1;
351    Pointer_Event           rotate_mv1;
352    unsigned int            prev_momentum_tm; /* timestamp of prev_momentum */
353    double                  prev_momentum; /* Snapshot of momentum 0.01
354                                            * sec ago */
355    double                  accum_momentum;
356    double                  rotate_angular_tolerance;
357    double                  next_step;
358 };
359 typedef struct _Rotate_Type                  Rotate_Type;
360
361 typedef struct _Elm_Gesture_Layer_Smart_Data Elm_Gesture_Layer_Smart_Data;
362 struct _Elm_Gesture_Layer_Smart_Data
363 {
364    Evas_Object          *target; /* Target Widget */
365    Event_History        *event_history_list;
366
367    int                   line_min_length;
368    Evas_Coord            zoom_distance_tolerance;
369    Evas_Coord            line_distance_tolerance;
370    double                line_angular_tolerance;
371    double                zoom_wheel_factor; /* mouse wheel zoom steps */
372    double                zoom_finger_factor; /* used for zoom factor */
373    double                rotate_angular_tolerance;
374    unsigned int          flick_time_limit_ms;
375    double                long_tap_start_timeout;
376    Eina_Bool             glayer_continues_enable;
377    double                double_tap_timeout;
378
379    double                zoom_step;
380    double                rotate_step;
381
382    Gesture_Info         *gesture[ELM_GESTURE_LAST];
383    Eina_List            *pending; /* List of devices need to refeed
384                                    * *UP event */
385    Eina_List            *touched; /* Information  of touched devices */
386
387    /* Taps Gestures */
388    Evas_Coord           tap_finger_size;    /* Default from Config */
389    Ecore_Timer          *gest_taps_timeout; /* When this expires, dbl
390                                              * click/taps ABORTed  */
391
392    Eina_Bool             repeat_events : 1;
393 };
394
395 /* START - Functions to manage touched-device list */
396 /**
397  * @internal
398  * This function is used to find if device is touched
399  *
400  * @ingroup Elm_Gesture_Layer
401  */
402 static int
403 _device_compare(const void *data1,
404                 const void *data2)
405 {
406    /* Compare the two device numbers */
407    return ((Pointer_Event *)data1)->device - ((Pointer_Event *)data2)->device;
408 }
409
410 /**
411  * @internal
412  *
413  * Remove Pointer Event from touched device list
414  * @param list Pointer to touched device list.
415  * @param Pointer_Event Pointer to PE.
416  *
417  * @ingroup Elm_Gesture_Layer
418  */
419 static Eina_List *
420 _touched_device_remove(Eina_List *list,
421                        Pointer_Event *pe)
422 {
423    Eina_List *lst = NULL;
424    Pointer_Event *p = eina_list_search_unsorted(list, _device_compare, pe);
425    if (p)
426      {
427         lst = eina_list_remove(list, p);
428         free(p);
429         return lst;
430      }
431
432    return list;
433 }
434
435 /**
436  * @internal
437  *
438  * Recoed Pointer Event in touched device list
439  * Note: This fuction allocates memory for PE event
440  * This memory is released in _touched_device_remove()
441  * @param list Pointer to touched device list.
442  * @param Pointer_Event Pointer to PE.
443  *
444  * @ingroup Elm_Gesture_Layer
445  */
446 static Eina_List *
447 _touched_device_add(Eina_List *list,
448                     Pointer_Event *pe)
449 {
450    Pointer_Event *p = eina_list_search_unsorted(list, _device_compare, pe);
451
452    if (p) /* We like to track device touch-position, overwrite info */
453      {
454         memcpy(p, pe, sizeof(Pointer_Event));
455         return list;
456      }
457
458    if ((pe->event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
459        (pe->event_type == EVAS_CALLBACK_MULTI_DOWN)) /* Add touched
460                                                       * device on DOWN
461                                                       * event only */
462      {
463         p = malloc(sizeof(Pointer_Event));
464         /* Freed in _touched_device_remove()    */
465         memcpy(p, pe, sizeof(Pointer_Event));
466         return eina_list_append(list, p);
467      }
468
469    return list;
470 }
471
472 /* END   - Functions to manage touched-device list */
473
474 /**
475  * @internal
476  *
477  * Get event flag
478  * @param event_info pointer to event.
479  *
480  * @ingroup Elm_Gesture_Layer
481  */
482 static Evas_Event_Flags
483 _event_flag_get(void *event_info,
484                 Evas_Callback_Type event_type)
485 {
486    switch (event_type)
487      {
488       case EVAS_CALLBACK_MOUSE_IN:
489         return ((Evas_Event_Mouse_In *)event_info)->event_flags;
490
491       case EVAS_CALLBACK_MOUSE_OUT:
492         return ((Evas_Event_Mouse_Out *)event_info)->event_flags;
493
494       case EVAS_CALLBACK_MOUSE_DOWN:
495         return ((Evas_Event_Mouse_Down *)event_info)->event_flags;
496
497       case EVAS_CALLBACK_MOUSE_MOVE:
498         return ((Evas_Event_Mouse_Move *)event_info)->event_flags;
499
500       case EVAS_CALLBACK_MOUSE_UP:
501         return ((Evas_Event_Mouse_Up *)event_info)->event_flags;
502
503       case EVAS_CALLBACK_MOUSE_WHEEL:
504         return ((Evas_Event_Mouse_Wheel *)event_info)->event_flags;
505
506       case EVAS_CALLBACK_MULTI_DOWN:
507         return ((Evas_Event_Multi_Down *)event_info)->event_flags;
508
509       case EVAS_CALLBACK_MULTI_MOVE:
510         return ((Evas_Event_Multi_Move *)event_info)->event_flags;
511
512       case EVAS_CALLBACK_MULTI_UP:
513         return ((Evas_Event_Multi_Up *)event_info)->event_flags;
514
515       case EVAS_CALLBACK_KEY_DOWN:
516         return ((Evas_Event_Key_Down *)event_info)->event_flags;
517
518       case EVAS_CALLBACK_KEY_UP:
519         return ((Evas_Event_Key_Up *)event_info)->event_flags;
520
521       default:
522         return EVAS_EVENT_FLAG_NONE;
523      }
524 }
525
526 /**
527  * @internal
528  *
529  * Sets event flag to value returned from user callback
530  * @param sd Widget Data
531  * @param event_info pointer to event.
532  * @param event_type what type was ev (mouse down, etc...)
533  * @param ev_flags event flags
534  *
535  * @ingroup Elm_Gesture_Layer
536  */
537 static void
538 _event_consume(Elm_Gesture_Layer_Smart_Data *sd,
539                void *event_info,
540                Evas_Callback_Type event_type,
541                Evas_Event_Flags ev_flags)
542 {
543    /* Mark EVAS_EVENT_FLAG_ON_HOLD on events that are used by gesture layer */
544    /* ev_flags != EVAS_EVENT_FLAG_NONE means target used event and g-layer  */
545    /* should not refeed this event.  */
546    if (!event_info)
547      return;  /* This happens when restarting gestures  */
548
549    if (!sd->repeat_events) ev_flags |= EVAS_EVENT_FLAG_ON_HOLD;
550
551    if (ev_flags)
552      {
553         switch (event_type)
554           {
555            case EVAS_CALLBACK_MOUSE_DOWN:
556              ((Evas_Event_Mouse_Down *)event_info)->event_flags |= ev_flags;
557              break;
558
559            case EVAS_CALLBACK_MOUSE_MOVE:
560              ((Evas_Event_Mouse_Move *)event_info)->event_flags |= ev_flags;
561              break;
562
563            case EVAS_CALLBACK_MOUSE_UP:
564              ((Evas_Event_Mouse_Up *)event_info)->event_flags |= ev_flags;
565              break;
566
567            case EVAS_CALLBACK_MOUSE_WHEEL:
568              ((Evas_Event_Mouse_Wheel *)event_info)->event_flags |= ev_flags;
569              break;
570
571            case EVAS_CALLBACK_MULTI_DOWN:
572              ((Evas_Event_Multi_Down *)event_info)->event_flags |= ev_flags;
573              break;
574
575            case EVAS_CALLBACK_MULTI_MOVE:
576              ((Evas_Event_Multi_Move *)event_info)->event_flags |= ev_flags;
577              break;
578
579            case EVAS_CALLBACK_MULTI_UP:
580              ((Evas_Event_Multi_Up *)event_info)->event_flags |= ev_flags;
581              break;
582
583            case EVAS_CALLBACK_KEY_DOWN:
584              ((Evas_Event_Key_Down *)event_info)->event_flags |= ev_flags;
585              break;
586
587            case EVAS_CALLBACK_KEY_UP:
588              ((Evas_Event_Key_Up *)event_info)->event_flags |= ev_flags;
589              break;
590
591            default:
592              return;
593           }
594      }
595 }
596
597 /**
598  * @internal
599  *
600  * Report current state of a gesture by calling user callback.
601  * @param gesture what gesture state we report.
602  * @param info inforamtion for user callback
603  *
604  * @ingroup Elm_Gesture_Layer
605  */
606 static Evas_Event_Flags
607 _state_report(Gesture_Info *gesture,
608               void *info)
609 {
610    Evas_Event_Flags flags = EVAS_EVENT_FLAG_NONE;
611    /* We report current state (START, MOVE, END, ABORT), once */
612    if ((gesture->state != ELM_GESTURE_STATE_UNDEFINED) &&
613        (gesture->cbs[gesture->state])) /* Fill state-info struct and
614                                         * send ptr to user
615                                         * callback */
616      {
617         Func_Data *cb_info;
618         EINA_INLIST_FOREACH(gesture->cbs[gesture->state], cb_info)
619            flags |= cb_info->cb(cb_info->user_data, info);
620      }
621
622    return EVAS_EVENT_FLAG_NONE;
623 }
624
625 /**
626  * @internal
627  *
628  * Update state for a given gesture.
629  * We may update gesture state to:
630  * - @c UNDEFINED - current input did not start gesure yet.
631  * - @c START - gesture started according to input.
632  * - @c MOVE - gusture in progress.
633  * - @c END - gesture completed according to input.
634  * - @c ABORT - input does not matches gesure.
635  * note that we may move from UNDEFINED to ABORT
636  * because we may detect that gesture will not START
637  * with a given input.
638  *
639  * @param g given gesture to change state.
640  * @param s gesure new state.
641  * @param info buffer to be sent to user callback on report_state.
642  * @param force makes report_state to report the new-state even
643  * if its same as current state. Works for MOVE - gesture in progress.
644  *
645  * @ingroup Elm_Gesture_Layer
646  */
647 static Evas_Event_Flags
648 _state_set(Gesture_Info *g,
649            Elm_Gesture_State s,
650            void *info,
651            Eina_Bool force)
652 {
653    Elm_Gesture_State old_state;
654
655    if ((g->state == s) && (!force))
656      return EVAS_EVENT_FLAG_NONE;
657
658    old_state = g->state;
659
660    g->state = s;
661    g->info = info;  /* Information for user callback */
662    if ((g->state == ELM_GESTURE_STATE_ABORT) ||
663        (g->state == ELM_GESTURE_STATE_END))
664      g->test = EINA_FALSE;
665
666    if ((g->state != ELM_GESTURE_STATE_UNDEFINED) &&
667        (!((old_state == ELM_GESTURE_STATE_UNDEFINED) &&
668           (s == ELM_GESTURE_STATE_ABORT))))
669      return _state_report(g, g->info);
670
671    return EVAS_EVENT_FLAG_NONE;
672 }
673
674 /**
675  * @internal
676  *
677  * This resets all gesture states and sets test-bit.
678  * this is used for restarting gestures to listen to input.
679  * happens after we complete a gesture or no gesture was detected.
680  * @param sd Widget data of the gesture-layer object.
681  *
682  * @ingroup Elm_Gesture_Layer
683  */
684 static void
685 _states_reset(Elm_Gesture_Layer_Smart_Data *sd)
686 {
687    int i;
688    Gesture_Info *p;
689
690    for (i = ELM_GESTURE_FIRST; i < ELM_GESTURE_LAST; i++)
691      {
692         p = sd->gesture[i];
693         if (p)
694           {
695              _state_set(p, ELM_GESTURE_STATE_UNDEFINED, NULL, EINA_FALSE);
696              SET_TEST_BIT(p);
697           }
698      }
699 }
700
701 /**
702  * @internal
703  *
704  * This function is used to save input events in an abstract struct
705  * to be used later by getsure-testing functions.
706  *
707  * @param data The gesture-layer object.
708  * @param event_info Pointer to recent input event.
709  * @param event_type Recent input event type.
710  * @param pe The abstract data-struct (output).
711  *
712  * @ingroup Elm_Gesture_Layer
713  */
714 static Eina_Bool
715 _pointer_event_make(void *data __UNUSED__,
716                     void *event_info,
717                     Evas_Callback_Type event_type,
718                     Pointer_Event *pe)
719 {
720    memset(pe, '\0', sizeof(*pe));
721    switch (event_type)
722      {
723       case EVAS_CALLBACK_MOUSE_DOWN:
724         pe->x = ((Evas_Event_Mouse_Down *)event_info)->canvas.x;
725         pe->y = ((Evas_Event_Mouse_Down *)event_info)->canvas.y;
726         pe->timestamp = ((Evas_Event_Mouse_Down *)event_info)->timestamp;
727         pe->device = ELM_MOUSE_DEVICE;
728         break;
729
730       case EVAS_CALLBACK_MOUSE_UP:
731         pe->x = ((Evas_Event_Mouse_Up *)event_info)->canvas.x;
732         pe->y = ((Evas_Event_Mouse_Up *)event_info)->canvas.y;
733         pe->timestamp = ((Evas_Event_Mouse_Up *)event_info)->timestamp;
734         pe->device = ELM_MOUSE_DEVICE;
735         break;
736
737       case EVAS_CALLBACK_MOUSE_MOVE:
738         pe->x = ((Evas_Event_Mouse_Move *)event_info)->cur.canvas.x;
739         pe->y = ((Evas_Event_Mouse_Move *)event_info)->cur.canvas.y;
740         pe->timestamp = ((Evas_Event_Mouse_Move *)event_info)->timestamp;
741         pe->device = ELM_MOUSE_DEVICE;
742         break;
743
744       case EVAS_CALLBACK_MULTI_DOWN:
745         pe->x = ((Evas_Event_Multi_Down *)event_info)->canvas.x;
746         pe->y = ((Evas_Event_Multi_Down *)event_info)->canvas.y;
747         pe->timestamp = ((Evas_Event_Multi_Down *)event_info)->timestamp;
748         pe->device = ((Evas_Event_Multi_Down *)event_info)->device;
749         break;
750
751       case EVAS_CALLBACK_MULTI_UP:
752         pe->x = ((Evas_Event_Multi_Up *)event_info)->canvas.x;
753         pe->y = ((Evas_Event_Multi_Up *)event_info)->canvas.y;
754         pe->timestamp = ((Evas_Event_Multi_Up *)event_info)->timestamp;
755         pe->device = ((Evas_Event_Multi_Up *)event_info)->device;
756         break;
757
758       case EVAS_CALLBACK_MULTI_MOVE:
759         pe->x = ((Evas_Event_Multi_Move *)event_info)->cur.canvas.x;
760         pe->y = ((Evas_Event_Multi_Move *)event_info)->cur.canvas.y;
761         pe->timestamp = ((Evas_Event_Multi_Move *)event_info)->timestamp;
762         pe->device = ((Evas_Event_Multi_Move *)event_info)->device;
763         break;
764
765       default:
766         return EINA_FALSE;
767      }
768
769    pe->event_type = event_type;
770    return EINA_TRUE;
771 }
772
773 /**
774  * @internal
775  *
776  * This function copies input events.
777  * We copy event info before adding it to history.
778  * The memory is freed when we clear history.
779  *
780  * @param event the event to copy
781  * @param event_type event type to copy
782  *
783  * @ingroup Elm_Gesture_Layer
784  */
785 static void *
786 _event_info_copy(void *event,
787                  Evas_Callback_Type event_type)
788 {
789    switch (event_type)
790      {
791       case EVAS_CALLBACK_MOUSE_DOWN:
792         return COPY_EVENT_INFO((Evas_Event_Mouse_Down *)event);
793         break;
794
795       case EVAS_CALLBACK_MOUSE_MOVE:
796         return COPY_EVENT_INFO((Evas_Event_Mouse_Move *)event);
797         break;
798
799       case EVAS_CALLBACK_MOUSE_UP:
800         return COPY_EVENT_INFO((Evas_Event_Mouse_Up *)event);
801         break;
802
803       case EVAS_CALLBACK_MOUSE_WHEEL:
804         return COPY_EVENT_INFO((Evas_Event_Mouse_Wheel *)event);
805         break;
806
807       case EVAS_CALLBACK_MULTI_DOWN:
808         return COPY_EVENT_INFO((Evas_Event_Multi_Down *)event);
809         break;
810
811       case EVAS_CALLBACK_MULTI_MOVE:
812         return COPY_EVENT_INFO((Evas_Event_Multi_Move *)event);
813         break;
814
815       case EVAS_CALLBACK_MULTI_UP:
816         return COPY_EVENT_INFO((Evas_Event_Multi_Up *)event);
817         break;
818
819       case EVAS_CALLBACK_KEY_DOWN:
820         return COPY_EVENT_INFO((Evas_Event_Key_Down *)event);
821         break;
822
823       case EVAS_CALLBACK_KEY_UP:
824         return COPY_EVENT_INFO((Evas_Event_Key_Up *)event);
825         break;
826
827       default:
828         return NULL;
829      }
830 }
831
832 static Eina_Bool
833 _event_history_add(Evas_Object *obj,
834                    void *event,
835                    Evas_Callback_Type event_type)
836 {
837    Event_History *ev;
838
839    ELM_GESTURE_LAYER_DATA_GET(obj, sd);
840
841    ev = malloc(sizeof(Event_History));
842    ev->event = _event_info_copy(event, event_type);  /* Freed on
843                                                       * _event_history_clear */
844    ev->event_type = event_type;
845    sd->event_history_list = (Event_History *)eina_inlist_append(
846        EINA_INLIST_GET(sd->event_history_list), EINA_INLIST_GET(ev));
847
848    return EINA_TRUE;
849 }
850
851 /**
852  * For all _mouse_* / multi_* functions wethen send this event to
853  * _event_process function.
854  *
855  * @param data The gesture-layer object.
856  * @param event_info Pointer to recent input event.
857  *
858  * @ingroup Elm_Gesture_Layer
859  */
860 static void
861 _mouse_down_cb(void *data,
862                Evas *e __UNUSED__,
863                Evas_Object *obj __UNUSED__,
864                void *event_info)
865 {
866    if (((Evas_Event_Mouse_Down *)event_info)->button != 1)
867      return;  /* We only process left-click at the moment */
868
869    _event_process(data, obj, event_info, EVAS_CALLBACK_MOUSE_DOWN);
870 }
871
872 static void
873 _mouse_move_cb(void *data,
874                Evas *e __UNUSED__,
875                Evas_Object *obj __UNUSED__,
876                void *event_info)
877 {
878    _event_process(data, obj, event_info, EVAS_CALLBACK_MOUSE_MOVE);
879 }
880
881 static void
882 _key_down_cb(void *data,
883              Evas *e __UNUSED__,
884              Evas_Object *obj __UNUSED__,
885              void *event_info)
886 {
887    _event_process(data, obj, event_info, EVAS_CALLBACK_KEY_DOWN);
888 }
889
890 static void
891 _key_up_cb(void *data,
892            Evas *e __UNUSED__,
893            Evas_Object *obj __UNUSED__,
894            void *event_info)
895 {
896    _event_process(data, obj, event_info, EVAS_CALLBACK_KEY_UP);
897 }
898
899 static void
900 _mouse_up_cb(void *data,
901              Evas *e __UNUSED__,
902              Evas_Object *obj __UNUSED__,
903              void *event_info)
904 {
905    if (((Evas_Event_Mouse_Up *)event_info)->button != 1)
906      return;  /* We only process left-click at the moment */
907
908    _event_process(data, obj, event_info, EVAS_CALLBACK_MOUSE_UP);
909 }
910
911 static void
912 _mouse_wheel_cb(void *data,
913                 Evas *e __UNUSED__,
914                 Evas_Object *obj __UNUSED__,
915                 void *event_info)
916 {
917    _event_process(data, obj, event_info, EVAS_CALLBACK_MOUSE_WHEEL);
918 }
919
920 static void
921 _multi_down_cb(void *data,
922                Evas *e __UNUSED__,
923                Evas_Object *obj __UNUSED__,
924                void *event_info)
925 {
926    /* Skip the mouse duplicates. */
927    if (((Evas_Event_Multi_Down *) event_info)->device == 0) return;
928
929    _event_process(data, obj, event_info, EVAS_CALLBACK_MULTI_DOWN);
930 }
931
932 static void
933 _multi_move_cb(void *data,
934                Evas *e __UNUSED__,
935                Evas_Object *obj __UNUSED__,
936                void *event_info)
937 {
938    /* Skip the mouse duplicates. */
939    if (((Evas_Event_Multi_Move *) event_info)->device == 0) return;
940
941    _event_process(data, obj, event_info, EVAS_CALLBACK_MULTI_MOVE);
942 }
943
944 static void
945 _multi_up_cb(void *data,
946              Evas *e __UNUSED__,
947              Evas_Object *obj __UNUSED__,
948              void *event_info)
949 {
950    /* Skip the mouse duplicates. */
951    if (((Evas_Event_Multi_Up *) event_info)->device == 0) return;
952
953    _event_process(data, obj, event_info, EVAS_CALLBACK_MULTI_UP);
954 }
955
956 static void
957 _target_del_cb(void *data,
958                Evas *e __UNUSED__,
959                Evas_Object *obj __UNUSED__,
960                void *event_info __UNUSED__)
961 {
962    _callbacks_unregister(data);
963 }
964
965 /**
966  * @internal
967  *
968  * We register callbacks when gesture layer is attached to an object
969  * or when its enabled after disable.
970  *
971  * @param obj The gesture-layer object.
972  *
973  * @ingroup Elm_Gesture_Layer
974  */
975 static void
976 _callbacks_register(Evas_Object *obj)
977 {
978    ELM_GESTURE_LAYER_DATA_GET(obj, sd);
979
980    if (!sd->target) return;
981
982    evas_object_event_callback_add
983      (sd->target, EVAS_CALLBACK_MOUSE_DOWN, _mouse_down_cb, obj);
984    evas_object_event_callback_add
985      (sd->target, EVAS_CALLBACK_MOUSE_MOVE, _mouse_move_cb, obj);
986    evas_object_event_callback_add
987      (sd->target, EVAS_CALLBACK_MOUSE_UP, _mouse_up_cb, obj);
988
989    evas_object_event_callback_add
990      (sd->target, EVAS_CALLBACK_MOUSE_WHEEL, _mouse_wheel_cb, obj);
991
992    evas_object_event_callback_add
993      (sd->target, EVAS_CALLBACK_MULTI_DOWN, _multi_down_cb, obj);
994    evas_object_event_callback_add
995      (sd->target, EVAS_CALLBACK_MULTI_MOVE, _multi_move_cb, obj);
996    evas_object_event_callback_add
997      (sd->target, EVAS_CALLBACK_MULTI_UP, _multi_up_cb, obj);
998
999    evas_object_event_callback_add
1000      (sd->target, EVAS_CALLBACK_KEY_DOWN, _key_down_cb, obj);
1001    evas_object_event_callback_add
1002      (sd->target, EVAS_CALLBACK_KEY_UP, _key_up_cb, obj);
1003
1004    evas_object_event_callback_add
1005      (sd->target, EVAS_CALLBACK_DEL, _target_del_cb, obj);
1006 }
1007
1008 /**
1009  * @internal
1010  *
1011  * We unregister callbacks when gesture layer is disabled.
1012  *
1013  * @param obj The gesture-layer object.
1014  *
1015  * @ingroup Elm_Gesture_Layer
1016  */
1017 static void
1018 _callbacks_unregister(Evas_Object *obj)
1019 {
1020    ELM_GESTURE_LAYER_DATA_GET(obj, sd);
1021
1022    if (!sd->target) return;
1023
1024    evas_object_event_callback_del_full
1025      (sd->target, EVAS_CALLBACK_MOUSE_DOWN, _mouse_down_cb, obj);
1026    evas_object_event_callback_del_full
1027      (sd->target, EVAS_CALLBACK_MOUSE_MOVE, _mouse_move_cb, obj);
1028    evas_object_event_callback_del_full
1029      (sd->target, EVAS_CALLBACK_MOUSE_UP, _mouse_up_cb, obj);
1030
1031    evas_object_event_callback_del_full
1032      (sd->target, EVAS_CALLBACK_MOUSE_WHEEL, _mouse_wheel_cb, obj);
1033
1034    evas_object_event_callback_del_full
1035      (sd->target, EVAS_CALLBACK_MULTI_DOWN, _multi_down_cb, obj);
1036
1037    evas_object_event_callback_del_full
1038      (sd->target, EVAS_CALLBACK_MULTI_MOVE, _multi_move_cb, obj);
1039
1040    evas_object_event_callback_del_full
1041      (sd->target, EVAS_CALLBACK_MULTI_UP, _multi_up_cb, obj);
1042
1043    evas_object_event_callback_del_full
1044      (sd->target, EVAS_CALLBACK_KEY_DOWN, _key_down_cb, obj);
1045    evas_object_event_callback_del_full
1046      (sd->target, EVAS_CALLBACK_KEY_UP, _key_up_cb, obj);
1047
1048    evas_object_event_callback_del_full
1049      (sd->target, EVAS_CALLBACK_DEL, _target_del_cb, obj);
1050 }
1051
1052 /**
1053  * @internal
1054  * This function is used to find if device number
1055  * is found in a list of devices.
1056  * The list contains devices for refeeding *UP event
1057  *
1058  * @ingroup Elm_Gesture_Layer
1059  */
1060 static int
1061 _device_in_pending_cmp(const void *data1,
1062                        const void *data2)
1063 {
1064    /* Compare the two device numbers */
1065    return ((intptr_t)data1) - ((intptr_t)data2);
1066 }
1067
1068 /**
1069  * @internal
1070  *
1071  * This functions returns pending-device node
1072  * @ingroup Elm_Gesture_Layer
1073  */
1074 static Eina_List *
1075 _device_is_pending(Eina_List *list,
1076                    void *event,
1077                    Evas_Callback_Type event_type)
1078 {
1079    int device = ELM_MOUSE_DEVICE;
1080
1081    switch (event_type)
1082      {
1083       case EVAS_CALLBACK_MOUSE_UP:
1084         break;
1085
1086       case EVAS_CALLBACK_MULTI_UP:
1087         device = ((Evas_Event_Multi_Up *)event)->device;
1088         break;
1089
1090       default:
1091         return NULL;
1092      }
1093
1094    return eina_list_search_unsorted_list
1095             (list, _device_in_pending_cmp, (void *)(intptr_t)device);
1096 }
1097
1098 /**
1099  * @internal
1100  *
1101  * This functions adds device to refeed-pending device list
1102  * @ingroup Elm_Gesture_Layer
1103  */
1104 static Eina_List *
1105 _pending_device_add(Eina_List *list,
1106                     void *event,
1107                     Evas_Callback_Type event_type)
1108 {
1109    int device = ELM_MOUSE_DEVICE;
1110
1111    switch (event_type)
1112      {
1113       case EVAS_CALLBACK_MOUSE_DOWN:
1114         break;
1115
1116       case EVAS_CALLBACK_MULTI_DOWN:
1117         device = ((Evas_Event_Multi_Down *)event)->device;
1118         break;
1119
1120       default:
1121         return list;
1122      }
1123
1124    if (!eina_list_search_unsorted_list
1125          (list, _device_in_pending_cmp, (void *)(intptr_t)device))
1126      {
1127         return eina_list_append(list, (void *)(intptr_t)device);
1128      }
1129
1130    return list;
1131 }
1132
1133 /**
1134  * @internal
1135  *
1136  * This function reports ABORT to all none-detected gestures
1137  * Then resets test bits for all desired gesures
1138  * and clears input-events history.
1139  * note: if no gesture was detected, events from history list
1140  * are streamed to the widget because it's unused by layer.
1141  * user may cancel refeed of events by setting repeat events.
1142  *
1143  * @param obj The gesture-layer object.
1144  *
1145  * @ingroup Elm_Gesture_Layer
1146  */
1147 static Eina_Bool
1148 _event_history_clear(Evas_Object *obj)
1149 {
1150    int i;
1151    Gesture_Info *p;
1152    Evas *e = evas_object_evas_get(obj);
1153    Eina_Bool gesture_found = EINA_FALSE;
1154
1155    ELM_GESTURE_LAYER_DATA_GET(obj, sd);
1156
1157    for (i = ELM_GESTURE_FIRST; i < ELM_GESTURE_LAST; i++)
1158      {
1159         p = sd->gesture[i];
1160         if (p)
1161           {
1162              if (p->state == ELM_GESTURE_STATE_END)
1163                {
1164                   gesture_found = EINA_TRUE;
1165                }
1166              else
1167                {  /* Report ABORT to all gestures that still not finished */
1168                  _state_set(p, ELM_GESTURE_STATE_ABORT, sd->gesture[i]->info,
1169                             EINA_FALSE);
1170                }
1171           }
1172      }
1173
1174    _states_reset(sd); /* we are ready to start testing for gestures again */
1175
1176    /* Clear all gestures intermediate data */
1177    {
1178       /* FIXME: +1 because of the mistake in the enum. */
1179       Gesture_Info **gitr = sd->gesture + 1;
1180       Tests_Array_Funcs *fitr = _glayer_tests_array + 1;
1181       for (; fitr->reset; fitr++, gitr++)
1182         {
1183            if (IS_TESTED_GESTURE(*gitr))
1184              fitr->reset(*gitr);
1185         }
1186    }
1187
1188    /* Disable gesture layer so refeeded events won't be consumed by it */
1189    _callbacks_unregister(obj);
1190    while (sd->event_history_list)
1191      {
1192         Event_History *t;
1193         t = sd->event_history_list;
1194         Eina_List *pending = _device_is_pending
1195             (sd->pending, sd->event_history_list->event,
1196             sd->event_history_list->event_type);
1197
1198         /* Refeed events if no gesture matched input */
1199         if (pending || ((!gesture_found) && (!sd->repeat_events)))
1200           {
1201              evas_event_refeed_event(e, sd->event_history_list->event,
1202                                      sd->event_history_list->event_type);
1203
1204              if (pending)
1205                {
1206                   sd->pending = eina_list_remove_list(sd->pending, pending);
1207                }
1208              else
1209                {
1210                   sd->pending = _pending_device_add
1211                       (sd->pending, sd->event_history_list->event,
1212                       sd->event_history_list->event_type);
1213                }
1214           }
1215
1216         free(sd->event_history_list->event);
1217         sd->event_history_list = (Event_History *)eina_inlist_remove(
1218             EINA_INLIST_GET(sd->event_history_list),
1219             EINA_INLIST_GET(sd->event_history_list));
1220         free(t);
1221      }
1222    _callbacks_register(obj);
1223    return EINA_TRUE;
1224 }
1225
1226 /**
1227  * @internal
1228  *
1229  * if gesture was NOT detected AND we only have gestures in ABORT state
1230  * we clear history immediately to be ready for input.
1231  *
1232  * @param obj The gesture-layer object.
1233  * @return TRUE on event history_clear
1234  *
1235  * @ingroup Elm_Gesture_Layer
1236  */
1237 static Eina_Bool
1238 _clear_if_finished(Evas_Object *obj)
1239 {
1240    int i;
1241    Eina_Bool reset_s = EINA_TRUE, all_undefined = EINA_TRUE;
1242
1243    ELM_GESTURE_LAYER_DATA_GET(obj, sd);
1244
1245    /* Clear history if all we have aborted gestures */
1246    for (i = ELM_GESTURE_FIRST; i < ELM_GESTURE_LAST; i++)
1247      {  /* If no gesture started and all we have aborted gestures, reset all */
1248        Gesture_Info *p = sd->gesture[i];
1249
1250        if ((p) && (p->state != ELM_GESTURE_STATE_UNDEFINED))
1251          {
1252             if ((p->state == ELM_GESTURE_STATE_START) ||
1253                 (p->state == ELM_GESTURE_STATE_MOVE))
1254               reset_s = EINA_FALSE;
1255
1256             all_undefined = EINA_FALSE;
1257          }
1258      }
1259
1260    if (reset_s && (!all_undefined))
1261      return _event_history_clear(obj);
1262
1263    return EINA_FALSE;
1264 }
1265
1266 /**
1267  * @internal
1268  *
1269  * This function restartes line, flick, zoom and rotate gestures
1270  * when gesture-layer continues-gestures enabled.
1271  * Example of continues-gesture:
1272  * When doing a line, user stops moving finger but keeps fingers on touch.
1273  * This will cause line-end, then as user continues moving his finger
1274  * it re-starts line gesture.
1275  * When continue mode is disabled, user has to lift finger from touch
1276  * to end a gesture. Them touch-again to start a new one.
1277  *
1278  * @param data The gesture-layer object.
1279  * @param sd gesture layer widget data.
1280  * @param states_reset flag that marks gestures were reset in history clear.
1281  *
1282  * @ingroup Elm_Gesture_Layer
1283  */
1284 static void
1285 _continues_gestures_restart(void *data,
1286                             Eina_Bool states_reset)
1287 {
1288    ELM_GESTURE_LAYER_DATA_GET(data, sd);
1289
1290    /* Test all the gestures */
1291    {
1292       /* FIXME: +1 because of the mistake in the enum. */
1293       Gesture_Info **gitr = sd->gesture + 1;
1294       Tests_Array_Funcs *fitr = _glayer_tests_array + 1;
1295       for (; fitr->test; fitr++, gitr++)
1296         {
1297            Gesture_Info *g = *gitr;
1298            Eina_Bool tmp = (g) ?
1299              ((states_reset) || ((g->state != ELM_GESTURE_STATE_START)
1300                                  && (g->state != ELM_GESTURE_STATE_MOVE)))
1301              : EINA_FALSE;
1302            if (tmp && fitr->cont_reset)
1303              {
1304                 fitr->cont_reset(g);
1305                 _state_set(g, ELM_GESTURE_STATE_UNDEFINED, NULL, EINA_FALSE);
1306                 SET_TEST_BIT(g);
1307              }
1308         }
1309    }
1310 }
1311
1312 /**
1313  * @internal
1314  *
1315  * This function the core-function where input handling is done.
1316  * Here we get user input and stream it to gesture testing.
1317  * We notify user about any gestures with new state:
1318  * Valid states are:
1319  * START - gesture started.
1320  * MOVE - gesture is ongoing.
1321  * END - gesture was completed.
1322  * ABORT - gesture was aborted after START, MOVE (will NOT be completed)
1323  *
1324  * We also check if a gesture was detected, then reset event history
1325  * If no gestures were found we reset gesture test flag
1326  * after streaming event-history to widget.
1327  * (stream to the widget all events not consumed as a gesture)
1328  *
1329  * @param data The gesture-layer object.
1330  * @param event_info Pointer to recent input event.
1331  * @param event_type Recent input event type.
1332  *
1333  * @ingroup Elm_Gesture_Layer
1334  */
1335 static void
1336 _event_process(void *data,
1337                Evas_Object *obj __UNUSED__,
1338                void *event_info,
1339                Evas_Callback_Type event_type)
1340 {
1341    Pointer_Event _pe;
1342    Pointer_Event *pe = NULL;
1343
1344    ELM_GESTURE_LAYER_DATA_GET(data, sd);
1345
1346    /* Start testing candidate gesture from here */
1347    if (!_pointer_event_make(data, event_info, event_type, &_pe))
1348      return;
1349
1350    pe = &_pe;
1351
1352    /* Test all the gestures */
1353    {
1354       /* FIXME: +1 because of the mistake in the enum. */
1355       Gesture_Info **gitr = sd->gesture + 1;
1356       Tests_Array_Funcs *fitr = _glayer_tests_array + 1;
1357       for (; fitr->test; fitr++, gitr++)
1358         {
1359            if (IS_TESTED_GESTURE(*gitr))
1360              fitr->test(data, pe, event_info, event_type, (*gitr)->g_type);
1361         }
1362    }
1363
1364    if (_event_flag_get(event_info, event_type) & EVAS_EVENT_FLAG_ON_HOLD)
1365      _event_history_add(data, event_info, event_type);
1366
1367    /* we maintain list of touched devices              */
1368    /* We also use move to track current device x.y pos */
1369    if ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
1370        (event_type == EVAS_CALLBACK_MULTI_DOWN) ||
1371        (event_type == EVAS_CALLBACK_MOUSE_MOVE) ||
1372        (event_type == EVAS_CALLBACK_MULTI_MOVE))
1373      {
1374         sd->touched = _touched_device_add(sd->touched, pe);
1375      }
1376    else if ((event_type == EVAS_CALLBACK_MOUSE_UP) ||
1377             (event_type == EVAS_CALLBACK_MULTI_UP))
1378      {
1379         sd->touched = _touched_device_remove(sd->touched, pe);
1380      }
1381
1382    /* Report current states and clear history if needed */
1383    Eina_Bool states_reset = _clear_if_finished(data);
1384    if (sd->glayer_continues_enable)
1385      _continues_gestures_restart(data, states_reset);
1386 }
1387
1388 static Eina_Bool
1389 _inside(Evas_Coord xx1,
1390         Evas_Coord yy1,
1391         Evas_Coord xx2,
1392         Evas_Coord yy2,
1393         Evas_Coord w)
1394 {
1395    w >>= 1; /* Use half the distance, from center to all directions */
1396    if (!w)  /* use system default instead */
1397      w = elm_config_finger_size_get() >> 1; /* Finger size devided by 2 */
1398
1399    if (xx1 < (xx2 - w))
1400      return EINA_FALSE;
1401
1402    if (xx1 > (xx2 + w))
1403      return EINA_FALSE;
1404
1405    if (yy1 < (yy2 - w))
1406      return EINA_FALSE;
1407
1408    if (yy1 > (yy2 + w))
1409      return EINA_FALSE;
1410
1411    return EINA_TRUE;
1412 }
1413
1414 /* All *test_reset() funcs are called to clear
1415  * gesture intermediate data.
1416  * This happens when we need to reset our tests.
1417  * for example when gesture is detected or all ABORTed. */
1418 static void
1419 _tap_gestures_test_reset(Gesture_Info *gesture)
1420 {
1421    Eina_List *data;
1422    Pointer_Event *pe;
1423
1424    EINA_SAFETY_ON_NULL_RETURN(gesture);
1425    ELM_GESTURE_LAYER_DATA_GET(gesture->obj, sd);
1426
1427    ELM_SAFE_FREE(sd->gest_taps_timeout, ecore_timer_del);
1428
1429    if (!gesture->data)
1430      return;
1431
1432    EINA_LIST_FREE(((Taps_Type *)gesture->data)->l, data)
1433      EINA_LIST_FREE(data, pe)
1434        free(pe);
1435
1436    memset(gesture->data, 0, sizeof(Taps_Type));
1437 }
1438
1439 /* All *test_reset() funcs are called to clear
1440  * gesture intermediate data.
1441  * This happens when we need to reset our tests.
1442  * for example when gesture is detected or all ABORTed. */
1443 static void
1444 _n_long_tap_test_reset(Gesture_Info *gesture)
1445 {
1446    Pointer_Event *p;
1447    Long_Tap_Type *st;
1448
1449    EINA_SAFETY_ON_NULL_RETURN(gesture);
1450    if (!gesture->data) return;
1451
1452    st = gesture->data;
1453
1454    EINA_LIST_FREE(st->touched, p)
1455      free(p);
1456    st->touched = NULL;
1457
1458    ELM_SAFE_FREE(st->timeout, ecore_timer_del);
1459    memset(gesture->data, 0, sizeof(Long_Tap_Type));
1460 }
1461
1462 static void
1463 _momentum_test_reset(Gesture_Info *gesture)
1464 {
1465    EINA_SAFETY_ON_NULL_RETURN(gesture);
1466    if (!gesture->data) return;
1467
1468    memset(gesture->data, 0, sizeof(Momentum_Type));
1469 }
1470
1471 static void
1472 _line_data_reset(Line_Data *st)
1473 {
1474    if (!st)
1475      return;
1476
1477    memset(st, 0, sizeof(Line_Data));
1478    st->line_angle = ELM_GESTURE_NEGATIVE_ANGLE;
1479 }
1480
1481 static void
1482 _line_test_reset(Gesture_Info *gesture)
1483 {
1484    Line_Type *st;
1485    Line_Data *t_line;
1486
1487    EINA_SAFETY_ON_NULL_RETURN(gesture);
1488    if (!gesture->data) return;
1489
1490    st = gesture->data;
1491
1492    EINA_LIST_FREE(st->list, t_line)
1493      free(t_line);
1494    st->list = NULL;
1495 }
1496
1497 static void
1498 _zoom_test_reset(Gesture_Info *gesture)
1499 {
1500    Zoom_Type *st;
1501    Evas_Modifier_Mask mask;
1502
1503    EINA_SAFETY_ON_NULL_RETURN(gesture);
1504    if (!gesture->data) return;
1505    ELM_GESTURE_LAYER_DATA_GET(gesture->obj, sd);
1506
1507    st = gesture->data;
1508    mask = evas_key_modifier_mask_get(
1509        evas_object_evas_get(sd->target), "Control");
1510    evas_object_key_ungrab(sd->target, "Control_L", mask, 0);
1511    evas_object_key_ungrab(sd->target, "Control_R", mask, 0);
1512
1513    memset(st, 0, sizeof(Zoom_Type));
1514    st->zoom_distance_tolerance = sd->zoom_distance_tolerance;
1515    st->info.zoom = 1.0;
1516 }
1517
1518 static void
1519 _rotate_test_reset(Gesture_Info *gesture)
1520 {
1521    Rotate_Type *st;
1522
1523    EINA_SAFETY_ON_NULL_RETURN(gesture);
1524    if (!gesture->data) return;
1525
1526    ELM_GESTURE_LAYER_DATA_GET(gesture->obj, sd);
1527    st = gesture->data;
1528
1529    memset(st, 0, sizeof(Rotate_Type));
1530    st->info.base_angle = ELM_GESTURE_NEGATIVE_ANGLE;
1531    st->rotate_angular_tolerance = sd->rotate_angular_tolerance;
1532 }
1533
1534 static Eina_List *
1535 _match_fingers_compare(Eina_List *list,
1536                        Pointer_Event *pe1,
1537                        Evas_Coord w)
1538 {
1539     /* Compare coords of first item in list to cur coords */
1540    Eina_List *pe_list;
1541    Eina_List *l;
1542
1543    EINA_LIST_FOREACH(list, l, pe_list)
1544      {
1545         Pointer_Event *pe2 = eina_list_data_get(pe_list);
1546
1547         if (_inside(pe1->x, pe1->y, pe2->x, pe2->y, w))
1548           return pe_list;
1549      }
1550
1551   return NULL;
1552 }
1553
1554 static int
1555 _pe_device_compare(const void *data1,
1556                    const void *data2)
1557 {
1558    /* Compare device of first item in list to our pe device */
1559    const Pointer_Event *pe1 = eina_list_data_get(data1);
1560    const Pointer_Event *pe2 = data2;
1561
1562    if (pe1->device == pe2->device)
1563      return 0;
1564    else if (pe1->device < pe2->device)
1565      return -1;
1566    else
1567      return 1;
1568 }
1569
1570 static Eina_List *
1571 _pointer_event_record(Taps_Type *st,
1572                       Eina_List *pe_list,
1573                       Pointer_Event *pe,
1574                       Elm_Gesture_Layer_Smart_Data *sd,
1575                       void *event_info,
1576                       Evas_Callback_Type event_type)
1577 {
1578    /* Keep copy of pe and record it in list */
1579    Pointer_Event *p = malloc(sizeof(Pointer_Event));
1580
1581    memcpy(p, pe, sizeof(Pointer_Event));
1582    _event_consume(sd, event_info, event_type, EVAS_EVENT_FLAG_NONE);
1583
1584    st->sum_x += pe->x;
1585    st->sum_y += pe->y;
1586    st->n_taps++;
1587
1588    /* This will also update middle-point to report to user later */
1589    st->info.x = st->sum_x / st->n_taps;
1590    st->info.y = st->sum_y / st->n_taps;
1591    st->info.timestamp = pe->timestamp;
1592
1593    if (!pe_list)
1594      {
1595         pe_list = eina_list_append(pe_list, p);
1596         st->l = eina_list_append(st->l, pe_list);
1597      }
1598    else
1599      pe_list = eina_list_append(pe_list, p);
1600
1601    return pe_list;
1602 }
1603
1604 /**
1605  * @internal
1606  *
1607  * This function computes minimum rect to bound taps at idx index
1608  *
1609  * @param taps [in] List of lists containing taps info.
1610  * @param idx [in] index of events taken from lists.
1611  * @param r [out] rect object to save info
1612  * @return EINA_TRUE if managed to compute rect.
1613  *
1614  * @ingroup Elm_Gesture_Layer
1615  */
1616 static Eina_Bool
1617 _taps_rect_get(Eina_List *taps, int idx, Evas_Coord_Rectangle *r)
1618 {  /* Build a rect bounding all taps at index idx */
1619    Eina_List *l;
1620    Evas_Coord bx, by;
1621    Eina_List *pe_list;
1622    Eina_Bool was_init = EINA_FALSE;
1623
1624    EINA_LIST_FOREACH(taps, l, pe_list)
1625      {
1626         Pointer_Event *pe = eina_list_nth(pe_list, idx);
1627         if (!pe) continue;  /* Not suppose to happen */
1628
1629         if (was_init)
1630           {
1631              if (pe->x < r->x) r->x = pe->x;
1632              if (pe->y < r->y) r->y = pe->y;
1633              if (pe->x > bx) bx = pe->x;
1634              if (pe->y > by) by = pe->y;
1635           }
1636         else
1637           {
1638              r->x = bx = pe->x;
1639              r->y = by = pe->y;
1640              was_init = EINA_TRUE;
1641           }
1642      }
1643
1644    r->w = bx - r->x;
1645    r->h = by - r->y;
1646    return was_init;
1647 }
1648
1649 /**
1650  * @internal
1651  *
1652  * This function checks if the tap gesture is done.
1653  *
1654  * @param data gesture info pointer
1655  * @return EINA_TRUE if it is done.
1656  *
1657  * @ingroup Elm_Gesture_Layer
1658  */
1659 static Eina_Bool
1660 _tap_gesture_check_finish(Gesture_Info *gesture, Evas_Coord tap_finger_size)
1661 {
1662    /* Here we check if taps-gesture was completed successfuly */
1663    /* Count how many taps were recieved on each device then   */
1664    /* determine if it matches n_taps_needed defined on START  */
1665    unsigned int i;
1666    Taps_Type *st = gesture->data;
1667    Eina_List *l;
1668    Eina_List *pe_list;
1669    Evas_Coord_Rectangle base;
1670    Evas_Coord_Rectangle tmp;
1671    if (!tap_finger_size)  /* Use system default if not set by user */
1672      tap_finger_size = elm_config_finger_size_get();
1673
1674
1675    if (!st->l) return EINA_FALSE;
1676    EINA_LIST_FOREACH(st->l, l, pe_list)
1677      {
1678         /* No match taps number on device, ABORT */
1679         if (eina_list_count(pe_list) != st->n_taps_needed)
1680           {
1681              return EINA_FALSE;
1682           }
1683      }
1684
1685    /* Now bound each tap touches in a rect, compare diff within tolerance */
1686    /* Get rect based on first DOWN events for all devices */
1687    if (!_taps_rect_get(st->l, 0, &base))
1688      return EINA_FALSE;  /* Should not happen */
1689
1690    for(i = 1; i < st->n_taps_needed; i++)
1691      {  /* Compare all other rects to base, tolerance is finger size */
1692         if (_taps_rect_get(st->l, i, &tmp))
1693           {
1694              if (abs(tmp.x - base.x) > tap_finger_size)
1695                return EINA_FALSE;
1696
1697              if (abs(tmp.y - base.y) > tap_finger_size)
1698                return EINA_FALSE;
1699
1700              if (abs((tmp.x + tmp.w) - (base.x + base.w)) > tap_finger_size)
1701                return EINA_FALSE;
1702
1703              if (abs((tmp.y + tmp.h) - (base.y + base.h)) > tap_finger_size)
1704                return EINA_FALSE;
1705           }
1706      }
1707
1708    return EINA_TRUE;
1709 }
1710
1711 /**
1712  * @internal
1713  *
1714  * This function sets state a tap-gesture to END or ABORT
1715  *
1716  * @param data gesture info pointer
1717  *
1718  * @ingroup Elm_Gesture_Layer
1719  */
1720 static void
1721 _tap_gesture_finish(void *data, Evas_Coord tap_finger_size)
1722 {
1723    /* This function will test each tap gesture when timer expires */
1724    Elm_Gesture_State s = ELM_GESTURE_STATE_ABORT;
1725    Gesture_Info *gesture = data;
1726    Taps_Type *st = gesture->data;
1727
1728    if (_tap_gesture_check_finish(gesture, tap_finger_size))
1729      {
1730         s = ELM_GESTURE_STATE_END;
1731      }
1732
1733    st->info.n = eina_list_count(st->l);
1734    _state_set(gesture, s, gesture->info, EINA_FALSE);
1735    _tap_gestures_test_reset(gesture);
1736 }
1737
1738 /**
1739  * @internal
1740  *
1741  * when this timer expires we finish tap gestures.
1742  *
1743  * @param data The gesture-layer object.
1744  * @return cancles callback for this timer.
1745  *
1746  * @ingroup Elm_Gesture_Layer
1747  */
1748 static Eina_Bool
1749 _multi_tap_timeout(void *data)
1750 {
1751    ELM_GESTURE_LAYER_DATA_GET(data, sd);
1752
1753    if (IS_TESTED(ELM_GESTURE_N_TAPS))
1754      _tap_gesture_finish(sd->gesture[ELM_GESTURE_N_TAPS],
1755            sd->tap_finger_size);
1756
1757    if (IS_TESTED(ELM_GESTURE_N_DOUBLE_TAPS))
1758      _tap_gesture_finish(sd->gesture[ELM_GESTURE_N_DOUBLE_TAPS],
1759            sd->tap_finger_size);
1760
1761    if (IS_TESTED(ELM_GESTURE_N_TRIPLE_TAPS))
1762      _tap_gesture_finish(sd->gesture[ELM_GESTURE_N_TRIPLE_TAPS],
1763            sd->tap_finger_size);
1764
1765    _clear_if_finished(data);
1766    sd->gest_taps_timeout = NULL;
1767
1768    return ECORE_CALLBACK_CANCEL;
1769 }
1770
1771 /**
1772  * @internal
1773  *
1774  * when this timer expires we START long tap gesture
1775  *
1776  * @param data The gesture-layer object.
1777  * @return cancles callback for this timer.
1778  *
1779  * @ingroup Elm_Gesture_Layer
1780  */
1781 static Eina_Bool
1782 _long_tap_timeout(void *data)
1783 {
1784    Gesture_Info *gesture = data;
1785
1786    _state_set(gesture, ELM_GESTURE_STATE_MOVE,
1787               gesture->data, EINA_TRUE);
1788
1789    return ECORE_CALLBACK_RENEW;
1790 }
1791
1792 /**
1793  * @internal
1794  *
1795  * This function checks the state of a tap gesture.
1796  *
1797  * @param sd Gesture Layer Widget Data.
1798  * @param pe The recent input event as stored in pe struct.
1799  * @param event_info Original input event pointer.
1800  * @param event_type Type of original input event.
1801  * @param gesture what gesture is tested
1802  * @param how many taps for this gesture (1, 2 or 3)
1803  *
1804  * @ingroup Elm_Gesture_Layer
1805  */
1806 static void
1807 _tap_gesture_test(Evas_Object *obj,
1808                   Pointer_Event *pe,
1809                   void *event_info,
1810                   Evas_Callback_Type event_type,
1811                   Elm_Gesture_Type g_type)
1812 {
1813    int taps = 0;
1814    Taps_Type *st;
1815    Gesture_Info *gesture;
1816    Eina_List *pe_list = NULL;
1817    Pointer_Event *pe_last = NULL;
1818    Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
1819
1820    /* Here we fill Tap struct */
1821    ELM_GESTURE_LAYER_DATA_GET(obj, sd);
1822
1823    if (!pe)
1824      return;
1825
1826    gesture = sd->gesture[g_type];
1827    if (!gesture) return;
1828
1829    switch (g_type)
1830      {
1831       case ELM_GESTURE_N_TAPS:
1832          taps = 1;
1833          break;
1834
1835       case ELM_GESTURE_N_DOUBLE_TAPS:
1836          taps = 2;
1837          break;
1838
1839       case ELM_GESTURE_N_TRIPLE_TAPS:
1840          taps = 3;
1841          break;
1842
1843       default:
1844          taps = 0;
1845          break;
1846      }
1847
1848    st = gesture->data;
1849    if (!st) /* Allocated once on first time */
1850      {
1851         st = calloc(1, sizeof(Taps_Type));
1852         gesture->data = st;
1853         _tap_gestures_test_reset(gesture);
1854      }
1855
1856    switch (pe->event_type)
1857      {
1858       case EVAS_CALLBACK_MULTI_DOWN:
1859       case EVAS_CALLBACK_MOUSE_DOWN:
1860          /* Each device taps (DOWN, UP event) registered in same list    */
1861          /* Find list for this device or start a new list if not found   */
1862          pe_list = eina_list_search_unsorted(st->l, _pe_device_compare, pe);
1863          if (pe_list)
1864            {  /* This device touched before, verify that this tap is on  */
1865               /* top of a previous tap (including a tap of other device) */
1866               if (!_match_fingers_compare(st->l, pe, sd->tap_finger_size))
1867                 {  /* New DOWN event is not on top of any prev touch     */
1868                    ev_flag = _state_set(gesture, ELM_GESTURE_STATE_ABORT,
1869                          &st->info, EINA_FALSE);
1870                    _event_consume(sd, event_info, event_type, ev_flag);
1871
1872                    return;
1873                 }
1874            }
1875
1876          /* All tests are good, register this tap in device list */
1877          pe_list = _pointer_event_record
1878             (st, pe_list, pe, sd, event_info, event_type);
1879
1880          if (!sd->gest_taps_timeout)
1881            {
1882               if (sd->double_tap_timeout > 0.0)
1883                 {
1884                    sd->gest_taps_timeout =
1885                       ecore_timer_add(sd->double_tap_timeout,
1886                             _multi_tap_timeout, gesture->obj);
1887                 }
1888            }
1889          else  /* We re-allocate gest_taps_timeout between taps */
1890            ecore_timer_reset(sd->gest_taps_timeout);
1891
1892          if ((pe->device == 0) && (eina_list_count(pe_list) == 1))
1893            {  /* This is the first mouse down we got */
1894               ev_flag = _state_set(gesture, ELM_GESTURE_STATE_START,
1895                     &st->info, EINA_FALSE);
1896               _event_consume(sd, event_info, event_type, ev_flag);
1897
1898               st->n_taps_needed = taps * 2;  /* count DOWN and UP */
1899
1900               return;
1901            }
1902          else if (eina_list_count(pe_list) > st->n_taps_needed)
1903            {  /* If we arleady got too many touches for this gesture. */
1904               ev_flag = _state_set(gesture, ELM_GESTURE_STATE_ABORT,
1905                     &st->info, EINA_FALSE);
1906            }
1907
1908          break;
1909
1910       case EVAS_CALLBACK_MULTI_UP:
1911       case EVAS_CALLBACK_MOUSE_UP:
1912          pe_list = eina_list_search_unsorted(st->l, _pe_device_compare, pe);
1913          if (!pe_list) return;
1914
1915          pe_list = _pointer_event_record
1916             (st, pe_list, pe, sd, event_info, event_type);
1917
1918          if (((gesture->g_type == ELM_GESTURE_N_TAPS) &&
1919                   !IS_TESTED(ELM_GESTURE_N_DOUBLE_TAPS) &&
1920                   !IS_TESTED(ELM_GESTURE_N_TRIPLE_TAPS)) ||
1921                ((gesture->g_type == ELM_GESTURE_N_DOUBLE_TAPS) &&
1922                 !IS_TESTED(ELM_GESTURE_N_TRIPLE_TAPS)))
1923            {  /* Test for finish immidiatly, not waiting for timeout */
1924               if (_tap_gesture_check_finish(gesture, sd->tap_finger_size))
1925                 {
1926                    _tap_gesture_finish(gesture, sd->tap_finger_size);
1927                    return;
1928                 }
1929            }
1930
1931          break;
1932
1933       case EVAS_CALLBACK_MULTI_MOVE:
1934       case EVAS_CALLBACK_MOUSE_MOVE:
1935          /* Verify that user didn't move out of tap area before next tap */
1936          /* BUT: we need to skip some MOVE events coming before DOWN     */
1937          /* when user taps next tap. So fetch LAST recorded event for    */
1938          /* device (DOWN or UP event), ignore all MOVEs if last was UP   */
1939          pe_last = eina_list_data_get(eina_list_last(
1940                   eina_list_search_unsorted(st->l, _pe_device_compare, pe)));
1941
1942          if (pe_last)
1943            {  /* pe_last is the last event recorded for this device */
1944               if ((pe_last->event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
1945                     (pe_last->event_type == EVAS_CALLBACK_MULTI_DOWN))
1946                 {  /* Test only MOVE events that come after DOWN event */
1947                    if (!_inside(pe_last->x, pe_last->y, pe->x, pe->y,
1948                             sd->tap_finger_size))
1949                      {
1950                         ev_flag = _state_set(gesture, ELM_GESTURE_STATE_ABORT,
1951                               &st->info, EINA_FALSE);
1952                         _event_consume(sd, event_info, event_type, ev_flag);
1953                      }
1954                 }
1955            }
1956          break;
1957
1958       default:
1959          return;
1960      }
1961 }
1962
1963 /**
1964  * @internal
1965  *
1966  * This function computes center-point for  long-tap gesture
1967  *
1968  * @param st Long Tap gesture info pointer
1969  * @param pe The recent input event as stored in pe struct.
1970  *
1971  * @ingroup Elm_Gesture_Layer
1972  */
1973 static void
1974 _compute_taps_center(Long_Tap_Type *st,
1975                      Evas_Coord *x_out,
1976                      Evas_Coord *y_out,
1977                      Pointer_Event *pe)
1978 {
1979    Eina_List *l;
1980    Pointer_Event *p;
1981    Evas_Coord x = 0, y = 0;
1982
1983    if (!eina_list_count(st->touched))
1984      return;
1985
1986    EINA_LIST_FOREACH(st->touched, l, p)
1987      {  /* Accumulate all then take avarage */
1988        if (p->device == pe->device) /* This will take care of values
1989                                      * coming from MOVE event */
1990          {
1991             x += pe->x;
1992             y += pe->y;
1993          }
1994        else
1995          {
1996             x += p->x;
1997             y += p->y;
1998          }
1999      }
2000
2001    *x_out = x / eina_list_count(st->touched);
2002    *y_out = y / eina_list_count(st->touched);
2003 }
2004
2005 /**
2006  * @internal
2007  *
2008  * This function checks N long-tap gesture.
2009  *
2010  * @param obj The gesture-layer object.
2011  * @param pe The recent input event as stored in pe struct.
2012  * @param event_info Original input event pointer.
2013  * @param event_type Type of original input event.
2014  * @param g_type what Gesture we are testing.
2015  * @param taps How many click/taps we test for.
2016  *
2017  * @ingroup Elm_Gesture_Layer
2018  */
2019 static void
2020 _n_long_tap_test(Evas_Object *obj,
2021                  Pointer_Event *pe,
2022                  void *event_info,
2023                  Evas_Callback_Type event_type,
2024                  Elm_Gesture_Type g_type)
2025 {
2026    Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
2027    Gesture_Info *gesture;
2028    Long_Tap_Type *st;
2029
2030    /* Here we fill Recent_Taps struct and fire-up click/tap timers */
2031    ELM_GESTURE_LAYER_DATA_GET(obj, sd);
2032
2033    if (!pe) /* this happens when unhandled event arrived */
2034      return;  /* see _make_pointer_event function */
2035
2036    gesture = sd->gesture[g_type];
2037    if (!gesture) return;
2038
2039    st = gesture->data;
2040    if (!st) /* Allocated once on first time */
2041      {
2042         st = calloc(1, sizeof(Long_Tap_Type));
2043         gesture->data = st;
2044         _n_long_tap_test_reset(gesture);
2045      }
2046
2047    switch (pe->event_type)
2048      {
2049       case EVAS_CALLBACK_MULTI_DOWN:
2050       case EVAS_CALLBACK_MOUSE_DOWN:
2051         st->touched = _touched_device_add(st->touched, pe);
2052         st->info.n = eina_list_count(st->touched);
2053
2054         _event_consume(sd, event_info, event_type, ev_flag);
2055         _compute_taps_center(st, &st->info.x, &st->info.y, pe);
2056         st->center_x = st->info.x;  /* Update coords for */
2057         st->center_y = st->info.y;  /* reporting START  */
2058
2059         /* This is the first mouse down we got */
2060         if (eina_list_count(st->touched) == 1)
2061           {
2062              _state_set(gesture, ELM_GESTURE_STATE_START,
2063                    gesture->data, EINA_FALSE);
2064              st->info.timestamp = pe->timestamp;
2065
2066              /* To test long tap */
2067              /* When this timer expires, gesture STARTED */
2068              if ((!st->timeout) && (sd->long_tap_start_timeout > 0.0))
2069                st->timeout = ecore_timer_add(sd->long_tap_start_timeout,
2070                                              _long_tap_timeout, gesture);
2071           }
2072         else
2073           {
2074              if (st->timeout)
2075                 ecore_timer_reset(st->timeout);
2076           }
2077
2078         break;
2079
2080       case EVAS_CALLBACK_MULTI_UP:
2081       case EVAS_CALLBACK_MOUSE_UP:
2082         st->touched = _touched_device_remove(st->touched, pe);
2083         _compute_taps_center(st, &st->center_x, &st->center_y, pe);
2084         if (st->info.n)
2085           {
2086              if (gesture->state == ELM_GESTURE_STATE_MOVE)
2087                ev_flag = _state_set(gesture, ELM_GESTURE_STATE_END,
2088                                     &st->info, EINA_FALSE);
2089              else
2090                ev_flag = _state_set(gesture, ELM_GESTURE_STATE_ABORT,
2091                                     &st->info, EINA_FALSE);
2092
2093              ELM_SAFE_FREE(st->timeout, ecore_timer_del);
2094              _event_consume(sd, event_info, event_type, ev_flag);
2095           }
2096
2097         break;
2098
2099       case EVAS_CALLBACK_MULTI_MOVE:
2100       case EVAS_CALLBACK_MOUSE_MOVE:
2101         if (st->info.n &&
2102             ((gesture->state == ELM_GESTURE_STATE_START) ||
2103              /* Report MOVE only if STARTED */
2104              (gesture->state == ELM_GESTURE_STATE_MOVE)))
2105           {
2106              Evas_Coord x = 0;
2107              Evas_Coord y = 0;
2108
2109              _compute_taps_center(st, &x, &y, pe);
2110              /* ABORT if user moved fingers out of tap area */
2111              if (!_inside(x, y, st->center_x, st->center_y,
2112                       sd->tap_finger_size))
2113                {
2114                   ELM_SAFE_FREE(st->timeout, ecore_timer_del);
2115
2116                   /* Report MOVE if gesture started */
2117                   ev_flag = _state_set(gesture, ELM_GESTURE_STATE_ABORT,
2118                         &st->info, EINA_FALSE);
2119                }
2120
2121              _event_consume(sd, event_info, event_type, ev_flag);
2122           }
2123         break;
2124
2125       default:
2126         return;
2127      }
2128 }
2129
2130 /**
2131  * @internal
2132  *
2133  * This function computes momentum for MOMENTUM, LINE and FLICK gestures
2134  * This momentum value will be sent to widget when gesture is completed.
2135  *
2136  * @param momentum pointer to buffer where we record momentum value.
2137  * @param x1 x coord where user started gesture.
2138  * @param y1 y coord where user started gesture.
2139  * @param x2 x coord where user completed gesture.
2140  * @param y2 y coord where user completed gesture.
2141  * @param t1x timestamp for X, when user started gesture.
2142  * @param t1y timestamp for Y, when user started gesture.
2143  * @param t2  timestamp when user completed gesture.
2144  *
2145  * @ingroup Elm_Gesture_Layer
2146  */
2147 static void
2148 _momentum_set(Elm_Gesture_Momentum_Info *momentum,
2149               Evas_Coord xx1,
2150               Evas_Coord yy1,
2151               Evas_Coord xx2,
2152               Evas_Coord yy2,
2153               unsigned int t1x,
2154               unsigned int t1y,
2155               unsigned int t2)
2156 {
2157    Evas_Coord velx = 0, vely = 0, vel;
2158    Evas_Coord dx = xx2 - xx1;
2159    Evas_Coord dy = yy2 - yy1;
2160    int dtx = t2 - t1x;
2161    int dty = t2 - t1y;
2162
2163    if (dtx > 0)
2164      velx = (dx * 1000) / dtx;
2165
2166    if (dty > 0)
2167      vely = (dy * 1000) / dty;
2168
2169    vel = sqrt((velx * velx) + (vely * vely));
2170
2171    if ((_elm_config->thumbscroll_friction > 0.0) &&
2172        (vel > _elm_config->thumbscroll_momentum_threshold)) /* report
2173                                                              * momentum */
2174      {
2175         momentum->mx = velx;
2176         momentum->my = vely;
2177      }
2178    else
2179      {
2180         momentum->mx = 0;
2181         momentum->my = 0;
2182      }
2183 }
2184
2185 /**
2186  * @internal
2187  *
2188  * This function is used for computing rotation angle (DEG).
2189  *
2190  * @param x1 first finger x location.
2191  * @param y1 first finger y location.
2192  * @param x2 second finger x location.
2193  * @param y2 second finger y location.
2194  *
2195  * @return angle of the line between (x1,y1), (x2,y2) in Deg.
2196  * Angles now are given in DEG, not RAD.
2197  * ZERO angle at 12-oclock, growing clockwise.
2198  *
2199  * @ingroup Elm_Gesture_Layer
2200  */
2201 static double
2202 _angle_get(Evas_Coord xx1,
2203            Evas_Coord yy1,
2204            Evas_Coord xx2,
2205            Evas_Coord yy2)
2206 {
2207    double a, xx, yy, rt = (-1);
2208
2209    xx = fabs(xx2 - xx1);
2210    yy = fabs(yy2 - yy1);
2211
2212    if (((int)xx) && ((int)yy))
2213      {
2214         rt = a = RAD2DEG(atan(yy / xx));
2215         if (xx1 < xx2)
2216           {
2217              if (yy1 < yy2) rt = 360 - a;
2218              else rt = a;
2219           }
2220         else
2221           {
2222              if (yy1 < yy2) rt = 180 + a;
2223              else rt = 180 - a;
2224           }
2225      }
2226
2227    if (rt < 0) /* Do this only if rt is not set */
2228      {
2229         if (((int)xx)) /* Horizontal line */
2230           {
2231              if (xx2 < xx1) rt = 180;
2232              else rt = 0.0;
2233           }
2234         else
2235           {  /* Vertical line */
2236             if (yy2 < yy1) rt = 90;
2237             else rt = 270;
2238           }
2239      }
2240
2241    /* Now we want to change from:
2242     *                      90                   0
2243     * original circle   180   0   We want:  270   90
2244     *                     270                 180
2245     */
2246    rt = 450 - rt;
2247    if (rt >= 360) rt -= 360;
2248
2249    return rt;
2250 }
2251
2252 /**
2253  * @internal
2254  *
2255  * This function is used for computing the magnitude and direction
2256  * of vector between two points.
2257  *
2258  * @param x1 first finger x location.
2259  * @param y1 first finger y location.
2260  * @param x2 second finger x location.
2261  * @param y2 second finger y location.
2262  * @param l length computed (output)
2263  * @param a angle computed (output)
2264  *
2265  * @ingroup Elm_Gesture_Layer
2266  */
2267 static void
2268 _vector_get(Evas_Coord xx1,
2269             Evas_Coord yy1,
2270             Evas_Coord xx2,
2271             Evas_Coord yy2,
2272             Evas_Coord *l,
2273             double *a)
2274 {
2275    Evas_Coord xx, yy;
2276
2277    xx = xx2 - xx1;
2278    yy = yy2 - yy1;
2279    *l = (Evas_Coord)sqrt((xx * xx) + (yy * yy));
2280    *a = _angle_get(xx1, yy1, xx2, yy2);
2281 }
2282
2283 static int
2284 _direction_get(Evas_Coord xx1,
2285                Evas_Coord xx2)
2286 {
2287    if (xx2 < xx1) return -1;
2288    if (xx2 > xx1) return 1;
2289
2290    return 0;
2291 }
2292
2293 /**
2294  * @internal
2295  *
2296  * This function tests momentum gesture.
2297  * @param obj The gesture-layer object.
2298  * @param pe The recent input event as stored in pe struct.
2299  * @param event_info recent input event.
2300  * @param event_type recent event type.
2301  * @param g_type what Gesture we are testing.
2302  *
2303  * @ingroup Elm_Gesture_Layer
2304  */
2305 static void
2306 _momentum_test(Evas_Object *obj,
2307                Pointer_Event *pe,
2308                void *event_info,
2309                Evas_Callback_Type event_type,
2310                Elm_Gesture_Type g_type)
2311 {
2312    Eina_List *l;
2313    Pointer_Event *p;
2314    Momentum_Type *st;
2315    Gesture_Info *gesture;
2316    Pointer_Event pe_local;
2317    Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
2318    Elm_Gesture_State state_to_report = ELM_GESTURE_STATE_MOVE;
2319    unsigned int cnt = 1; /* We start counter counting current pe event */
2320
2321    ELM_GESTURE_LAYER_DATA_GET(obj, sd);
2322
2323    gesture = sd->gesture[g_type];
2324    if (!gesture) return;
2325
2326    /* When continues enable = TRUE a gesture may START on MOVE event */
2327    /* We don't allow this to happen with the if-statement below.     */
2328    /* When continues enable = FALSE a gesture may START on DOWN only */
2329    /* Therefor it would NOT start on MOVE event.                     */
2330    /* NOTE that touched list is updated AFTER this function returns  */
2331    /* so (count == 0) when we get here on first touch on surface.    */
2332    if ((sd->glayer_continues_enable) && (!eina_list_count(sd->touched)))
2333      return;  /* Got move on mouse-over move */
2334
2335    st = gesture->data;
2336    if (!st) /* Allocated once on first time */
2337      {
2338         st = calloc(1, sizeof(Momentum_Type));
2339         gesture->data = st;
2340         _momentum_test_reset(gesture);
2341      }
2342
2343    if (!pe)
2344      return;
2345
2346    /* First make avarage of all touched devices to determine center point */
2347    pe_local = *pe; /* Copy pe event info to local */
2348    EINA_LIST_FOREACH(sd->touched, l, p)
2349      if (p->device != pe_local.device)
2350        {
2351           pe_local.x += p->x;
2352           pe_local.y += p->y;
2353           cnt++;
2354        }
2355
2356    /* Compute avarage to get center point */
2357    pe_local.x /= cnt;
2358    pe_local.y /= cnt;
2359
2360    /* If user added finger - reset gesture */
2361    if ((st->info.n) && (st->info.n < cnt))
2362      state_to_report = ELM_GESTURE_STATE_ABORT;
2363
2364    if (st->info.n < cnt)
2365      st->info.n = cnt;
2366
2367    switch (event_type)
2368      {
2369       case EVAS_CALLBACK_MOUSE_DOWN:
2370       case EVAS_CALLBACK_MULTI_DOWN:
2371       case EVAS_CALLBACK_MOUSE_MOVE:
2372       case EVAS_CALLBACK_MULTI_MOVE:
2373         if (!st->t_st_x)
2374           {
2375              if ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
2376                  (event_type == EVAS_CALLBACK_MULTI_DOWN) ||
2377                  (sd->glayer_continues_enable))    /* start also on MOVE */
2378                {   /* We start on MOVE when cont-enabled only */
2379                  st->line_st.x = st->line_end.x = pe_local.x;
2380                  st->line_st.y = st->line_end.y = pe_local.y;
2381                  st->t_st_x = st->t_st_y = st->t_end = pe_local.timestamp;
2382                  st->xdir = st->ydir = 0;
2383                  st->info.x2 = st->info.x1 = pe_local.x;
2384                  st->info.y2 = st->info.y1 = pe_local.y;
2385                  st->info.tx = st->info.ty = pe_local.timestamp;
2386                  ev_flag = _state_set(gesture, ELM_GESTURE_STATE_START,
2387                                       &st->info, EINA_FALSE);
2388                  _event_consume(sd, event_info, event_type, ev_flag);
2389                }
2390
2391              return;
2392           }
2393
2394         if (st->t_up)
2395           {
2396              Eina_Bool force = EINA_TRUE;   /* for move state */
2397
2398              /* ABORT if got DOWN or MOVE event after UP+timeout */
2399              if ((st->t_up + ELM_GESTURE_MULTI_TIMEOUT) < pe_local.timestamp)
2400                {
2401                   state_to_report = ELM_GESTURE_STATE_ABORT;
2402                   force = EINA_FALSE;
2403                }
2404
2405              /* We report state but don't compute momentum now */
2406              ev_flag = _state_set(gesture, state_to_report, &st->info,
2407                                   force);
2408              _event_consume(sd, event_info, event_type, ev_flag);
2409              return;  /* Stop computing when user remove finger */
2410           }
2411
2412         /*  Too long of a wait, reset all values */
2413         if ((pe_local.timestamp - ELM_GESTURE_MOMENTUM_TIMEOUT) > st->t_end)
2414           {
2415              st->line_st.x = pe_local.x;
2416              st->line_st.y = pe_local.y;
2417              st->t_st_y = st->t_st_x = pe_local.timestamp;
2418              st->info.tx = st->t_st_x;
2419              st->info.ty = st->t_st_y;
2420              st->xdir = st->ydir = 0;
2421           }
2422         else
2423           {
2424              int xdir, ydir;
2425
2426              xdir = _direction_get(st->line_end.x, pe_local.x);
2427              ydir = _direction_get(st->line_end.y, pe_local.y);
2428              if (xdir && (xdir != st->xdir))
2429                {
2430                   st->line_st.x = st->line_end.x;
2431                   st->info.tx = st->t_st_x = st->t_end;
2432                   st->xdir = xdir;
2433                }
2434
2435              if (ydir && (ydir != st->ydir))
2436                {
2437                   st->line_st.y = st->line_end.y;
2438                   st->info.ty = st->t_st_y = st->t_end;
2439                   st->ydir = ydir;
2440                }
2441           }
2442
2443         st->info.x2 = st->line_end.x = pe_local.x;
2444         st->info.y2 = st->line_end.y = pe_local.y;
2445         st->t_end = pe_local.timestamp;
2446         _momentum_set(&st->info, st->line_st.x, st->line_st.y,
2447                       pe_local.x, pe_local.y, st->t_st_x, st->t_st_y,
2448                       pe_local.timestamp);
2449
2450         ev_flag = _state_set(gesture, state_to_report, &st->info,
2451                              EINA_TRUE);
2452         _event_consume(sd, event_info, event_type, ev_flag);
2453         break;
2454
2455       case EVAS_CALLBACK_MOUSE_UP:
2456       case EVAS_CALLBACK_MULTI_UP:
2457         st->t_up = pe_local.timestamp; /* Record recent up event time */
2458         if ((cnt > 1) || /* Ignore if more fingers touch surface        */
2459             (!st->t_st_x)) /* IGNORE if info was cleared, long press,move */
2460           return;
2461
2462         /* Too long of a wait, reset all values */
2463         if ((pe_local.timestamp - ELM_GESTURE_MOMENTUM_TIMEOUT) > st->t_end)
2464           {
2465              st->line_st.x = pe_local.x;
2466              st->line_st.y = pe_local.y;
2467              st->t_st_y = st->t_st_x = pe_local.timestamp;
2468              st->xdir = st->ydir = 0;
2469           }
2470
2471         st->info.x2 = pe_local.x;
2472         st->info.y2 = pe_local.y;
2473         st->line_end.x = pe_local.x;
2474         st->line_end.y = pe_local.y;
2475         st->t_end = pe_local.timestamp;
2476
2477         if ((fabs(st->info.mx) > ELM_GESTURE_MINIMUM_MOMENTUM) ||
2478             (fabs(st->info.my) > ELM_GESTURE_MINIMUM_MOMENTUM))
2479           state_to_report = ELM_GESTURE_STATE_END;
2480         else
2481           state_to_report = ELM_GESTURE_STATE_ABORT;
2482
2483         ev_flag = _state_set(gesture, state_to_report, &st->info,
2484                              EINA_FALSE);
2485         _event_consume(sd, event_info, event_type, ev_flag);
2486         return;
2487
2488       default:
2489         return;
2490      }
2491 }
2492
2493 static int
2494 _line_device_compare(const void *data1,
2495                      const void *data2)
2496 {
2497    /* Compare device component of line struct */
2498    const Line_Data *ln1 = data1;
2499    const int *device = data2;
2500
2501    if (ln1->t_st) /* Compare only with lines that started */
2502      return ln1->device - (*device);
2503
2504    return -1;
2505 }
2506
2507 /**
2508  * @internal
2509  *
2510  * This function construct line struct from input.
2511  * @param info pointer to store line momentum.
2512  * @param st line info to store input data.
2513  * @param pe The recent input event as stored in pe struct.
2514  *
2515  * @ingroup Elm_Gesture_Layer
2516  */
2517 static Eina_Bool
2518 _single_line_process(Elm_Gesture_Line_Info *info,
2519                      Line_Data *st,
2520                      Pointer_Event *pe,
2521                      Evas_Callback_Type event_type)
2522 {
2523    /* Record events and set momentum for line pointed by st */
2524    if (!pe)
2525      return EINA_FALSE;
2526
2527    switch (event_type)
2528      {
2529       case EVAS_CALLBACK_MOUSE_DOWN:
2530       case EVAS_CALLBACK_MOUSE_MOVE:
2531       case EVAS_CALLBACK_MULTI_DOWN:
2532       case EVAS_CALLBACK_MULTI_MOVE:
2533         if (!st->t_st) /* This happens only when line starts */
2534           {
2535              st->line_st.x = pe->x;
2536              st->line_st.y = pe->y;
2537              st->t_st = pe->timestamp;
2538              st->device = pe->device;
2539              info->momentum.x1 = pe->x;
2540              info->momentum.y1 = pe->y;
2541              info->momentum.tx = pe->timestamp;
2542              info->momentum.ty = pe->timestamp;
2543
2544              return EINA_TRUE;
2545           }
2546
2547         break;
2548
2549       case EVAS_CALLBACK_MOUSE_UP:
2550       case EVAS_CALLBACK_MULTI_UP:
2551         /* IGNORE if line info was cleared, like long press, move */
2552         if (!st->t_st)
2553           return EINA_FALSE;
2554
2555         st->line_end.x = pe->x;
2556         st->line_end.y = pe->y;
2557         st->t_end = pe->timestamp;
2558         break;
2559
2560       default:
2561         return EINA_FALSE;
2562      }
2563
2564    if (!st->t_st)
2565      {
2566         _line_data_reset(st);
2567         return EINA_FALSE;
2568      }
2569
2570    info->momentum.x2 = pe->x;
2571    info->momentum.y2 = pe->y;
2572    _momentum_set(&info->momentum, st->line_st.x, st->line_st.y, pe->x, pe->y,
2573                  st->t_st, st->t_st, pe->timestamp);
2574
2575    return EINA_TRUE;
2576 }
2577
2578 /**
2579  * @internal
2580  *
2581  * This function test for (n) line gesture.
2582  * @param obj The gesture-layer object.
2583  * @param pe The recent input event as stored in pe struct.
2584  * @param event_info Original input event pointer.
2585  * @param event_type Type of original input event.
2586  * @param g_type what Gesture we are testing.
2587  *
2588  * @ingroup Elm_Gesture_Layer
2589  */
2590 static void
2591 _n_line_test(Evas_Object *obj,
2592              Pointer_Event *pe,
2593              void *event_info,
2594              Evas_Callback_Type event_type,
2595              Elm_Gesture_Type g_type)
2596 {
2597    unsigned cnt;
2598    Line_Type *st;
2599    Eina_List *list;
2600    Gesture_Info *gesture;
2601    Line_Data *line = NULL;
2602
2603    if (!pe)
2604      return;
2605
2606    ELM_GESTURE_LAYER_DATA_GET(obj, sd);
2607
2608    gesture = sd->gesture[g_type];
2609    if (!gesture ) return;
2610
2611    /* When continues enable = TRUE a gesture may START on MOVE event */
2612    /* We don't allow this to happen with the if-statement below.     */
2613    /* When continues enable = FALSE a gesture may START on DOWN only */
2614    /* Therefor it would NOT start on MOVE event.                     */
2615    /* NOTE that touched list is updated AFTER this function returns  */
2616    /* so (count == 0) when we get here on first touch on surface.    */
2617    if ((sd->glayer_continues_enable) && (!eina_list_count(sd->touched)))
2618      return;  /* Got move on mouse-over move */
2619
2620    st = gesture->data;
2621    if (!st)
2622      {
2623         st = calloc(1, sizeof(Line_Type));
2624         gesture->data = st;
2625      }
2626
2627    list = st->list;
2628    cnt = eina_list_count(list);
2629
2630    if (cnt) /* list is not empty, locate this device on list */
2631      {
2632         line = (Line_Data *)eina_list_search_unsorted
2633             (st->list, _line_device_compare, &pe->device);
2634      }
2635
2636    if (!line) /* List is empty or device not found, new line-struct on
2637                * START only */
2638      {
2639         if ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
2640             (event_type == EVAS_CALLBACK_MULTI_DOWN) ||
2641             ((sd->glayer_continues_enable) &&   /* START on MOVE also */
2642              ((event_type == EVAS_CALLBACK_MOUSE_MOVE) ||
2643               /* Allocate new item on START only */
2644               (event_type == EVAS_CALLBACK_MULTI_MOVE))))
2645           {
2646              line = calloc(1, sizeof(Line_Data));
2647              _line_data_reset(line);
2648              list = eina_list_append(list, line);
2649              st->list = list;
2650           }
2651      }
2652
2653    if (!line) /* This may happen on MOVE that comes before DOWN      */
2654      return;  /* No line-struct to work with, can't continue testing */
2655
2656    /* update st with input */
2657    if (_single_line_process(&st->info, line, pe, event_type))
2658      _event_consume(sd, event_info, event_type, EVAS_EVENT_FLAG_NONE);
2659
2660    /* Get direction and magnitude of the line */
2661    double angle;
2662    _vector_get(line->line_st.x, line->line_st.y, pe->x, pe->y,
2663                &line->line_length, &angle);
2664
2665    /* These are used later to compare lines length */
2666    Evas_Coord shortest_line_len = line->line_length;
2667    Evas_Coord longest_line_len = line->line_length;
2668    Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
2669
2670    /* Now update line-state */
2671    if (line->t_st) /* Analyze line only if line started */
2672      {
2673         if (line->line_angle >= 0.0) /* if line direction was set, we
2674                                       * test if broke tolerance */
2675           {
2676              double a = fabs(angle - line->line_angle);
2677              /* Distance from line */
2678              double d = (tan(DEG2RAD(a))) * line->line_length;
2679              /* Broke tolerance: abort line and start a new one */
2680              if ((d > sd->line_distance_tolerance) ||
2681                  (a > sd->line_angular_tolerance))
2682                {
2683                   ev_flag = _state_set(gesture, ELM_GESTURE_STATE_ABORT,
2684                                        &st->info, EINA_FALSE);
2685                   _event_consume(sd, event_info, event_type, ev_flag);
2686                   return;
2687                }
2688
2689              /* We may finish line if momentum is zero */
2690              if (sd->glayer_continues_enable)
2691                {
2692                   /* This is for continues-gesture */
2693                   /* Finish line on zero momentum for continues gesture */
2694                   if ((!st->info.momentum.mx) && (!st->info.momentum.my))
2695                     {
2696                        line->line_end.x = pe->x;
2697                        line->line_end.y = pe->y;
2698                        line->t_end = pe->timestamp;
2699                     }
2700                }
2701           }
2702         else
2703           {  /* Record the line angle as it broke minimum length for line */
2704             if (line->line_length >= sd->line_min_length)
2705               st->info.angle = line->line_angle = angle;
2706           }
2707
2708         if (line->t_end)
2709           {
2710              if (line->line_angle < 0.0) /* it's not a line, too short
2711                                           * more close to a tap */
2712                {
2713                   ev_flag = _state_set(gesture, ELM_GESTURE_STATE_ABORT,
2714                                        &st->info, EINA_FALSE);
2715                   _event_consume(sd, event_info, event_type, ev_flag);
2716                   return;
2717                }
2718           }
2719      }
2720
2721    /* Count how many lines already started / ended */
2722    int started = 0;
2723    int ended = 0;
2724    unsigned int tm_start = pe->timestamp;
2725    unsigned int tm_end = pe->timestamp;
2726    Eina_List *l;
2727    Line_Data *t_line;
2728    double base_angle = ELM_GESTURE_NEGATIVE_ANGLE;
2729    Eina_Bool lines_parallel = EINA_TRUE;
2730    EINA_LIST_FOREACH(list, l, t_line)
2731      {
2732         if (base_angle < 0)
2733           base_angle = t_line->line_angle;
2734         else
2735           {
2736              if (t_line->line_angle >= 0) /* Compare angle only with
2737                                            * lines with direction
2738                                            * defined */
2739                {
2740                   if (fabs(base_angle - t_line->line_angle) >
2741                       sd->line_angular_tolerance)
2742                     lines_parallel = EINA_FALSE;
2743                }
2744           }
2745
2746         if (t_line->line_length) /* update only if this line is used */
2747           {
2748              if (shortest_line_len > t_line->line_length)
2749                shortest_line_len = t_line->line_length;
2750
2751              if (longest_line_len < t_line->line_length)
2752                longest_line_len = t_line->line_length;
2753           }
2754
2755         if (t_line->t_st)
2756           {
2757              started++;
2758              if (t_line->t_st < tm_start)
2759                tm_start = t_line->t_st;
2760           }
2761
2762         if (t_line->t_end)
2763           {
2764              ended++;
2765              if (t_line->t_end < tm_end)
2766                tm_end = t_line->t_end;
2767           }
2768      }
2769
2770    st->info.momentum.n = started;
2771
2772    if (ended &&
2773        ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
2774         /* user lift one finger then starts again without line-end - ABORT */
2775         (event_type == EVAS_CALLBACK_MULTI_DOWN)))
2776      {
2777         ev_flag = _state_set(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
2778                              EINA_FALSE);
2779         _event_consume(sd, event_info, event_type, ev_flag);
2780         return;
2781      }
2782
2783    if (!lines_parallel) /* Lines are NOT at same direction, abort this
2784                          * gesture */
2785      {
2786         ev_flag = _state_set(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
2787                              EINA_FALSE);
2788         _event_consume(sd, event_info, event_type, ev_flag);
2789         return;
2790      }
2791
2792    /* We report ABORT if lines length are NOT matching when fingers are up */
2793    if ((longest_line_len - shortest_line_len) >
2794        (elm_config_finger_size_get() * 2))
2795      {
2796         ev_flag = _state_set(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
2797                              EINA_FALSE);
2798         _event_consume(sd, event_info, event_type, ev_flag);
2799         return;
2800      }
2801
2802    /* We consider FLICK as a fast line.ABORT if take too long to finish */
2803    if ((g_type == ELM_GESTURE_N_FLICKS) && ((tm_end - tm_start) >
2804                                             sd->flick_time_limit_ms))
2805      {
2806         ev_flag = _state_set(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
2807                              EINA_FALSE);
2808         _event_consume(sd, event_info, event_type, ev_flag);
2809         return;
2810      }
2811
2812    switch (event_type)
2813      {
2814       case EVAS_CALLBACK_MOUSE_UP:
2815       case EVAS_CALLBACK_MULTI_UP:
2816         if ((started) && (started == ended))
2817           {
2818              ev_flag = _state_set(gesture, ELM_GESTURE_STATE_END,
2819                                   &st->info, EINA_FALSE);
2820              _event_consume(sd, event_info, event_type, ev_flag);
2821           }
2822
2823         return;
2824
2825       case EVAS_CALLBACK_MOUSE_DOWN:
2826       case EVAS_CALLBACK_MULTI_DOWN:
2827       case EVAS_CALLBACK_MOUSE_MOVE:
2828       case EVAS_CALLBACK_MULTI_MOVE:
2829         if (started)
2830           {
2831              /* For continues gesture */
2832              if (sd->glayer_continues_enable && (started == ended))
2833                {
2834                   ev_flag = _state_set(gesture, ELM_GESTURE_STATE_END,
2835                                        &st->info, EINA_FALSE);
2836                   _event_consume(sd, event_info, event_type, ev_flag);
2837                }
2838              else
2839                {   /* When continues, may START on MOVE event too */
2840                  Elm_Gesture_State s = ELM_GESTURE_STATE_MOVE;
2841
2842                  /* This happens when: on n > 1 lines then one finger up */
2843                  /* caused abort, then put finger down.                  */
2844                  /* This will stop line from starting again.             */
2845                  /* Number of lines, MUST match touched-device in list   */
2846                  if ((!sd->glayer_continues_enable) &&
2847                      (eina_list_count(st->list) <
2848                       eina_list_count(sd->touched)))
2849                    s = ELM_GESTURE_STATE_ABORT;
2850
2851                  if (gesture->state == ELM_GESTURE_STATE_UNDEFINED)
2852                    s = ELM_GESTURE_STATE_START;
2853
2854                  ev_flag = _state_set(gesture, s, &st->info, EINA_TRUE);
2855                  _event_consume(sd, event_info, event_type, ev_flag);
2856                }
2857           }
2858         break;
2859
2860       default:
2861         return;   /* Unhandeld event type */
2862      }
2863 }
2864
2865 /**
2866  * @internal
2867  *
2868  * This function is used to check if rotation gesture started.
2869  * @param st Contains current rotation values from user input.
2870  * @return TRUE/FALSE if we need to set rotation START.
2871  *
2872  * @ingroup Elm_Gesture_Layer
2873  */
2874 static Eina_Bool
2875 _on_rotation_broke_tolerance(Rotate_Type *st)
2876 {
2877    if (st->info.base_angle < 0)
2878      return EINA_FALSE;  /* Angle has to be computed first */
2879
2880    if (st->rotate_angular_tolerance < 0)
2881      return EINA_TRUE;
2882
2883    double low = st->info.base_angle - st->rotate_angular_tolerance;
2884    double high = st->info.base_angle + st->rotate_angular_tolerance;
2885    double t = st->info.angle;
2886
2887    if (low < 0)
2888      {
2889         low += 180;
2890         high += 180;
2891
2892         if (t < 180)
2893           t += 180;
2894         else
2895           t -= 180;
2896      }
2897
2898    if (high > 360)
2899      {
2900         low -= 180;
2901         high -= 180;
2902
2903         if (t < 180)
2904           t += 180;
2905         else
2906           t -= 180;
2907      }
2908
2909    if ((t < low) || (t > high)) /* This marks that roation action has
2910                                  * started */
2911      {
2912         st->rotate_angular_tolerance = ELM_GESTURE_NEGATIVE_ANGLE;
2913         st->info.base_angle = st->info.angle; /* Avoid jump in angle value */
2914         return EINA_TRUE;
2915      }
2916
2917    return EINA_FALSE;
2918 }
2919
2920 /**
2921  * @internal
2922  *
2923  * This function is used for computing the gap between fingers.
2924  * It returns the length and center point between fingers.
2925  *
2926  * @param x1 first finger x location.
2927  * @param y1 first finger y location.
2928  * @param x2 second finger x location.
2929  * @param y2 second finger y location.
2930  * @param x  Gets center point x cord (output)
2931  * @param y  Gets center point y cord (output)
2932  *
2933  * @return length of the line between (x1,y1), (x2,y2) in pixels.
2934  *
2935  * @ingroup Elm_Gesture_Layer
2936  */
2937 static Evas_Coord
2938 _finger_gap_length_get(Evas_Coord xx1,
2939                        Evas_Coord yy1,
2940                        Evas_Coord xx2,
2941                        Evas_Coord yy2,
2942                        Evas_Coord *x,
2943                        Evas_Coord *y)
2944 {
2945    double a, b, xx, yy, gap;
2946    xx = fabs(xx2 - xx1);
2947    yy = fabs(yy2 - yy1);
2948    gap = sqrt((xx * xx) + (yy * yy));
2949
2950    /* START - Compute zoom center point */
2951    /* The triangle defined as follows:
2952     *             B
2953     *           / |
2954     *          /  |
2955     *     gap /   | a
2956     *        /    |
2957     *       A-----C
2958     *          b
2959     * http://en.wikipedia.org/wiki/Trigonometric_functions
2960     *************************************/
2961    if (((int)xx) && ((int)yy))
2962      {
2963         double A = atan((yy / xx));
2964         a = (Evas_Coord)((gap / 2) * sin(A));
2965         b = (Evas_Coord)((gap / 2) * cos(A));
2966         *x = (Evas_Coord)((xx2 > xx1) ? (xx1 + b) : (xx2 + b));
2967         *y = (Evas_Coord)((yy2 > yy1) ? (yy1 + a) : (yy2 + a));
2968      }
2969    else
2970      {
2971         if ((int)xx) /* horiz line, take half width */
2972           {
2973              *x = (Evas_Coord)((xx1 + xx2) / 2);
2974              *y = (Evas_Coord)(yy1);
2975           }
2976
2977         if ((int)yy) /* vert line, take half width */
2978           {
2979              *x = (Evas_Coord)(xx1);
2980              *y = (Evas_Coord)((yy1 + yy2) / 2);
2981           }
2982      }
2983    /* END   - Compute zoom center point */
2984
2985    return (Evas_Coord)gap;
2986 }
2987
2988 /**
2989  * @internal
2990  *
2991  * This function is used for computing zoom value.
2992  *
2993  * @param st Pointer to zoom data based on user input.
2994  * @param tm_end Recent input event timestamp.
2995  * @param zoom_val Current computed zoom value.
2996  *
2997  * @return zoom momentum
2998  *
2999  * @ingroup Elm_Gesture_Layer
3000  */
3001 static double
3002 _zoom_momentum_get(Zoom_Type *st,
3003                    unsigned int tm_end,
3004                    double zoom_val)
3005 {
3006    unsigned int tm_total;
3007    if (!st->m_st_tm) /* Init, and we don't start computing momentum yet */
3008      {
3009         st->m_st_tm = st->m_prev_tm = tm_end;
3010         st->m_base = zoom_val;
3011         return 0.0;
3012      }
3013
3014    if ((tm_end - ELM_GESTURE_MOMENTUM_DELAY) < st->m_st_tm)
3015      return 0.0;  /* we don't start to compute momentum yet */
3016
3017    if (st->dir) /* if direction was already defined, check if changed */
3018      {
3019         if (((st->dir < 0) && (zoom_val > st->info.zoom)) ||
3020             /* Direction changed, reset momentum */
3021             ((st->dir > 0) && (zoom_val < st->info.zoom)))
3022           {
3023              st->m_st_tm = 0;
3024              st->dir = (-st->dir);
3025              return 0.0;
3026           }
3027      }
3028    else
3029      st->dir = (zoom_val > st->info.zoom) ? 1 : -1;  /* init */
3030
3031    if ((tm_end - ELM_GESTURE_MOMENTUM_TIMEOUT) > st->m_prev_tm)
3032      {
3033         st->m_st_tm = 0; /* Rest momentum when waiting too long */
3034         return 0.0;
3035      }
3036
3037    st->m_prev_tm = tm_end;
3038    tm_total = tm_end - st->m_st_tm;
3039
3040    if (tm_total)
3041      return ((zoom_val - st->m_base) * 1000) / tm_total;
3042    else
3043      return 0.0;
3044 }
3045
3046 /**
3047  * @internal
3048  *
3049  * This function is used for computing zoom value.
3050  *
3051  * @param st Pointer to zoom data based on user input.
3052  * @param x1 first finger x location.
3053  * @param y1 first finger y location.
3054  * @param x2 second finger x location.
3055  * @param y2 second finger y location.
3056  * @param factor zoom-factor, used to determine how fast zoom works.
3057  *
3058  * @return zoom value, when 1.0 means no zoom, 0.5 half size...
3059  *
3060  * @ingroup Elm_Gesture_Layer
3061  */
3062 static double
3063 _zoom_compute(Zoom_Type *st,
3064               Evas_Coord xx1,
3065               Evas_Coord yy1,
3066               Evas_Coord xx2,
3067               Evas_Coord yy2,
3068               double zoom_finger_factor)
3069 {
3070    double rt = 1.0;
3071    unsigned int tm_end = (st->zoom_mv.timestamp > st->zoom_mv1.timestamp) ?
3072      st->zoom_mv.timestamp : st->zoom_mv1.timestamp;
3073
3074    Evas_Coord diam = _finger_gap_length_get(xx1, yy1, xx2, yy2,
3075                                             &st->info.x, &st->info.y);
3076
3077    st->info.radius = diam / 2;
3078
3079    if (!st->zoom_base)
3080      {
3081         st->zoom_base = diam;
3082         return st->info.zoom;
3083      }
3084
3085    if (st->zoom_distance_tolerance) /* zoom tolerance <> ZERO, means
3086                                     * zoom action NOT started yet */
3087      {
3088         /* avoid jump with zoom value when break tolerance */
3089         if (diam < (st->zoom_base - st->zoom_distance_tolerance))
3090           {
3091              st->zoom_base -= st->zoom_distance_tolerance;
3092              st->zoom_distance_tolerance = 0;
3093           }
3094
3095         /* avoid jump with zoom value when break tolerance */
3096         if (diam > (st->zoom_base + st->zoom_distance_tolerance))
3097           {
3098              st->zoom_base += st->zoom_distance_tolerance;
3099              st->zoom_distance_tolerance = 0;
3100           }
3101
3102         return rt;
3103      }
3104
3105    /* We use factor only on the difference between gap-base   */
3106    /* if gap=120, base=100, we get ((120-100)/100)=0.2*factor */
3107    rt = ((1.0) + ((((float)diam - (float)st->zoom_base) /
3108                    (float)st->zoom_base) * zoom_finger_factor));
3109
3110    /* Momentum: zoom per second: */
3111    st->info.momentum = _zoom_momentum_get(st, tm_end, rt);
3112
3113    return rt;
3114 }
3115
3116 /**
3117  * @internal
3118  *
3119  * This function handles zoom with mouse wheel.
3120  * thats a combination of wheel + CTRL key.
3121  * @param obj The gesture-layer object.
3122  * @param event_info Original input event pointer.
3123  * @param event_type Type of original input event.
3124  * @param g_type what Gesture we are testing.
3125  *
3126  * @ingroup Elm_Gesture_Layer
3127  */
3128 static void
3129 _zoom_with_wheel_test(Evas_Object *obj,
3130                       void *event_info,
3131                       Evas_Callback_Type event_type,
3132                       Elm_Gesture_Type g_type)
3133 {
3134    ELM_GESTURE_LAYER_DATA_GET(obj, sd);
3135
3136    if (!sd->gesture[g_type]) return;
3137
3138    Gesture_Info *gesture_zoom = sd->gesture[g_type];
3139    Zoom_Type *st = gesture_zoom->data;
3140    Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
3141    if (!st) /* Allocated once on first time, used for zoom intermediate data */
3142      {
3143         st = calloc(1, sizeof(Zoom_Type));
3144         gesture_zoom->data = st;
3145         _zoom_test_reset(gesture_zoom);
3146      }
3147
3148    switch (event_type)
3149      {
3150       case EVAS_CALLBACK_KEY_UP:
3151       {
3152          Evas_Event_Key_Up *p = event_info;
3153          if ((!strcmp(p->keyname, "Control_L")) ||
3154              /* Test if we ended a zoom gesture when releasing CTRL */
3155              (!strcmp(p->keyname, "Control_R")))
3156            {
3157               if ((st->zoom_wheel) &&
3158                   ((gesture_zoom->state == ELM_GESTURE_STATE_START) ||
3159                    /* User released CTRL after zooming */
3160                    (gesture_zoom->state == ELM_GESTURE_STATE_MOVE)))
3161                 {
3162                    st->info.momentum = _zoom_momentum_get
3163                        (st, p->timestamp, st->info.zoom);
3164
3165                    ev_flag = _state_set
3166                        (gesture_zoom, ELM_GESTURE_STATE_END, &st->info,
3167                        EINA_FALSE);
3168                    _event_consume(sd, event_info, event_type, ev_flag);
3169
3170                    return;
3171                 }
3172            }
3173          break;
3174       }
3175
3176       case EVAS_CALLBACK_MOUSE_WHEEL:
3177       {
3178          Eina_Bool force;
3179          Elm_Gesture_State s;
3180          if (!evas_key_modifier_is_set(
3181                ((Evas_Event_Mouse_Wheel *)event_info)->modifiers,
3182                "Control")) /* if using wheel witout CTRL after starting zoom */
3183            {
3184               if ((st->zoom_wheel) &&
3185                   ((gesture_zoom->state == ELM_GESTURE_STATE_START) ||
3186                    (gesture_zoom->state == ELM_GESTURE_STATE_MOVE)))
3187                 {
3188                    ev_flag = _state_set
3189                        (gesture_zoom, ELM_GESTURE_STATE_END, &st->info,
3190                        EINA_FALSE);
3191                    _event_consume(sd, event_info, event_type, ev_flag);
3192
3193                    return;
3194                 }
3195               else
3196                 return;  /* Ignore mouse-wheel without control */
3197            }
3198
3199          /* Using mouse wheel with CTRL for zoom */
3200          /* (zoom_wheel == NULL) and (zoom_distance_tolerance == 0) we
3201           * continue a zoom gesture */
3202          if (st->zoom_wheel || (st->zoom_distance_tolerance == 0))
3203            {
3204               force = EINA_TRUE;
3205               s = ELM_GESTURE_STATE_MOVE;
3206            }
3207          else
3208            { /* On first wheel event, report START */
3209              Evas_Modifier_Mask mask = evas_key_modifier_mask_get(
3210                  evas_object_evas_get(sd->target), "Control");
3211              force = EINA_FALSE;
3212              s = ELM_GESTURE_STATE_START;
3213              if (!evas_object_key_grab
3214                    (sd->target, "Control_L", mask, 0, EINA_FALSE))
3215                ERR("Failed to Grabbed CTRL_L");
3216              if (!evas_object_key_grab
3217                    (sd->target, "Control_R", mask, 0, EINA_FALSE))
3218                ERR("Failed to Grabbed CTRL_R");
3219            }
3220
3221          st->zoom_distance_tolerance = 0; /* Cancel tolerance */
3222          st->zoom_wheel = (Evas_Event_Mouse_Wheel *)event_info;
3223          st->info.x = st->zoom_wheel->canvas.x;
3224          st->info.y = st->zoom_wheel->canvas.y;
3225
3226          if (st->zoom_wheel->z < 0) /* zoom in */
3227            st->info.zoom += (sd->zoom_finger_factor * sd->zoom_wheel_factor);
3228
3229          if (st->zoom_wheel->z > 0) /* zoom out */
3230            st->info.zoom -= (sd->zoom_finger_factor * sd->zoom_wheel_factor);
3231
3232          if (st->info.zoom < 0.0)
3233            st->info.zoom = 0.0;
3234
3235          st->info.momentum = _zoom_momentum_get
3236              (st, st->zoom_wheel->timestamp, st->info.zoom);
3237
3238          ev_flag = _state_set(gesture_zoom, s, &st->info, force);
3239          _event_consume(sd, event_info, event_type, ev_flag);
3240          break;
3241       }
3242
3243       default:
3244         return;
3245      }
3246 }
3247
3248 /**
3249  * @internal
3250  *
3251  * This function is used to test zoom gesture.
3252  * user may combine zoom, rotation together.
3253  * so its possible that both will be detected from input.
3254  * (both are two-finger movement-oriented gestures)
3255  *
3256  * @param obj The gesture-layer object.
3257  * @param event_info Pointer to recent input event.
3258  * @param event_type Recent input event type.
3259  * @param g_type what Gesture we are testing.
3260  *
3261  * @ingroup Elm_Gesture_Layer
3262  */
3263 static void
3264 _zoom_test(Evas_Object *obj,
3265            Pointer_Event *pe,
3266            void *event_info,
3267            Evas_Callback_Type event_type,
3268            Elm_Gesture_Type g_type)
3269 {
3270    /* Test for wheel zoom. */
3271    _zoom_with_wheel_test(obj, event_info, event_type, ELM_GESTURE_ZOOM);
3272
3273    if (!_elm_config->glayer_zoom_finger_enable)
3274      return;
3275
3276    if (!pe)
3277      return;
3278    ELM_GESTURE_LAYER_DATA_GET(obj, sd);
3279
3280    if (!sd->gesture[g_type]) return;
3281
3282    Gesture_Info *gesture_zoom = sd->gesture[g_type];
3283    Zoom_Type *st = gesture_zoom->data;
3284
3285    if (!st) /* Allocated once on first time, used for zoom data */
3286      {
3287         st = calloc(1, sizeof(Zoom_Type));
3288         gesture_zoom->data = st;
3289         _zoom_test_reset(gesture_zoom);
3290      }
3291
3292    /* Start - new zoom testing, letting all fingers start */
3293    Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
3294    switch (event_type)
3295      {
3296       case EVAS_CALLBACK_MOUSE_MOVE:
3297       case EVAS_CALLBACK_MULTI_MOVE:
3298         /* if non-continues mode and gesture NOT started, ignore MOVE */
3299         if ((!sd->glayer_continues_enable) &&
3300             (!st->zoom_st.timestamp))
3301           return;
3302
3303       case EVAS_CALLBACK_MOUSE_DOWN:
3304       case EVAS_CALLBACK_MULTI_DOWN:
3305       { /* Here we take care of zoom-start and zoom move */
3306         Eina_List *l;
3307         Pointer_Event *p;
3308
3309         if (eina_list_count(sd->touched) > 2) /* Process zoom only
3310                                                * when 2 fingers on
3311                                                * surface */
3312           {
3313              ev_flag = _state_set
3314                  (gesture_zoom, ELM_GESTURE_STATE_ABORT, &st->info,
3315                  EINA_FALSE);
3316              _event_consume(sd, event_info, event_type, ev_flag);
3317
3318              return;
3319           }
3320
3321         if (!st->zoom_st.timestamp) /* Now scan touched-devices list
3322                                      * and find other finger */
3323           {
3324              EINA_LIST_FOREACH(sd->touched, l, p)
3325                { /* Device of other finger <> pe device */
3326                  if (p->device != pe->device)
3327                    break;
3328                }
3329
3330              if (!p) /* Single finger on touch */
3331                return;
3332
3333              /* Record down fingers */
3334              _event_consume(sd, event_info, event_type, ev_flag);
3335              memcpy(&st->zoom_st, pe, sizeof(Pointer_Event));
3336              memcpy(&st->zoom_st1, p, sizeof(Pointer_Event));
3337
3338              /* Set mv field as well to be ready for MOVE events  */
3339              memcpy(&st->zoom_mv, pe, sizeof(Pointer_Event));
3340              memcpy(&st->zoom_mv1, p, sizeof(Pointer_Event));
3341
3342              /* Here we have zoom_st, zoom_st1 set, report START  */
3343              /* Set zoom-base after BOTH down events  recorded    */
3344              /* Compute length of line between fingers zoom start */
3345              st->info.zoom = 1.0;
3346              st->zoom_base = _finger_gap_length_get
3347                  (st->zoom_st1.x, st->zoom_st1.y, st->zoom_st.x, st->zoom_st.y,
3348                  &st->info.x, &st->info.y);
3349
3350              st->info.radius = st->zoom_base / 2;
3351
3352              if ((gesture_zoom->state != ELM_GESTURE_STATE_START) &&
3353                  /* zoom started with mouse-wheel, don't report twice */
3354                  (gesture_zoom->state != ELM_GESTURE_STATE_MOVE))
3355                {
3356                   ev_flag = _state_set
3357                       (gesture_zoom, ELM_GESTURE_STATE_START, &st->info,
3358                       EINA_FALSE);
3359                   _event_consume(sd, event_info, event_type, ev_flag);
3360                }
3361
3362              return; /* Zoom started */
3363           } /* End of ZOOM_START handling */
3364
3365         /* if we got here, we have (exacally) two fingers on surfce */
3366         /* we also after START, report MOVE */
3367         /* First detect which finger moved  */
3368         if (pe->device == st->zoom_mv.device)
3369           memcpy(&st->zoom_mv, pe, sizeof(Pointer_Event));
3370         else if (pe->device == st->zoom_mv1.device)
3371           memcpy(&st->zoom_mv1, pe, sizeof(Pointer_Event));
3372
3373         /* Compute change in zoom as fingers move */
3374         st->info.zoom = _zoom_compute(st,
3375                                       st->zoom_mv.x, st->zoom_mv.y,
3376                                       st->zoom_mv1.x, st->zoom_mv1.y,
3377                                       sd->zoom_finger_factor);
3378
3379         if (!st->zoom_distance_tolerance) /* Zoom broke tolerance,
3380                                            * report move */
3381           {
3382              double d = st->info.zoom - st->next_step;
3383              if (d < 0.0)
3384                d = (-d);
3385
3386              if (d >= sd->zoom_step) /* Report move in steps */
3387                {
3388                   st->next_step = st->info.zoom;
3389
3390                   ev_flag = _state_set(gesture_zoom,
3391                                        ELM_GESTURE_STATE_MOVE,
3392                                        &st->info, EINA_TRUE);
3393                   _event_consume(sd, event_info, event_type, ev_flag);
3394                }
3395           } /* End of ZOOM_MOVE handling */
3396
3397         return;
3398       }
3399
3400       case EVAS_CALLBACK_MOUSE_UP:
3401       case EVAS_CALLBACK_MULTI_UP:
3402         /* Reset timestamp of finger-up.This is used later
3403            by _zoom_test_reset() to retain finger-down data */
3404         _event_consume(sd, event_info, event_type, ev_flag);
3405         if (((st->zoom_wheel) || (st->zoom_base)) &&
3406             (st->zoom_distance_tolerance == 0))
3407           {
3408              ev_flag = _state_set(gesture_zoom, ELM_GESTURE_STATE_END,
3409                                   &st->info, EINA_FALSE);
3410              _event_consume(sd, event_info, event_type, ev_flag);
3411
3412              return;
3413           }
3414
3415         /* if we got here not a ZOOM */
3416         /* Must be != undefined, if gesture started */
3417         if (gesture_zoom->state != ELM_GESTURE_STATE_UNDEFINED)
3418           {
3419              ev_flag = _state_set
3420                  (gesture_zoom, ELM_GESTURE_STATE_ABORT, &st->info,
3421                  EINA_FALSE);
3422              _event_consume(sd, event_info, event_type, ev_flag);
3423           }
3424
3425         _zoom_test_reset(gesture_zoom);
3426
3427         return;
3428
3429       default:
3430         return;
3431      }
3432 }
3433
3434 static void
3435 _rotate_properties_get(Rotate_Type *st,
3436                        Evas_Coord xx1,
3437                        Evas_Coord yy1,
3438                        Evas_Coord xx2,
3439                        Evas_Coord yy2,
3440                        double *angle)
3441 {
3442    /* FIXME: Fix momentum computation, it's wrong */
3443    double prev_angle = *angle;
3444
3445    st->info.radius = _finger_gap_length_get(xx1, yy1, xx2, yy2,
3446                                             &st->info.x, &st->info.y) / 2;
3447
3448    *angle = _angle_get(xx1, yy1, xx2, yy2);
3449
3450    if (angle == &st->info.angle) /* Fingers are moving, compute momentum */
3451      {
3452         unsigned int tm_start =
3453           (st->rotate_st.timestamp > st->rotate_st1.timestamp)
3454           ?  st->rotate_st.timestamp : st->rotate_st1.timestamp;
3455         unsigned int tm_end =
3456           (st->rotate_mv.timestamp > st->rotate_mv1.timestamp)
3457           ? st->rotate_mv.timestamp : st->rotate_mv1.timestamp;
3458
3459         unsigned int tm_total = tm_end - tm_start;
3460         if (tm_total) /* Momentum computed as:
3461                          accumulated roation angle (deg) divided by time */
3462           {
3463              double m = 0;
3464              if (((prev_angle < 90) && ((*angle) > 270)) ||
3465                  /* We circle passing ZERO point */
3466                  ((prev_angle > 270) && ((*angle) < 90)))
3467                {
3468                   prev_angle = (*angle);
3469                }
3470              else m = prev_angle - (*angle);
3471
3472              st->accum_momentum += m;
3473
3474              if ((tm_end - st->prev_momentum_tm) < 100)
3475                st->prev_momentum += m;
3476              else
3477                {
3478                   if (fabs(st->prev_momentum) < 0.002)
3479                     st->accum_momentum = 0.0;  /* reset momentum */
3480
3481                   st->prev_momentum = 0.0; /* Start again    */
3482                }
3483
3484              st->prev_momentum_tm = tm_end;
3485              st->info.momentum = (st->accum_momentum * 1000) / tm_total;
3486           }
3487      }
3488    else
3489      st->info.momentum = 0;
3490 }
3491
3492 /**
3493  * @internal
3494  *
3495  * This function is used to test rotation gesture.
3496  * user may combine zoom, rotation together.
3497  * so its possible that both will be detected from input.
3498  * (both are two-finger movement-oriented gestures)
3499  *
3500  * @param obj The gesture-layer object.
3501  * @param event_info Pointer to recent input event.
3502  * @param event_type Recent input event type.
3503  * @param g_type what Gesture we are testing.
3504  *
3505  * @ingroup Elm_Gesture_Layer
3506  */
3507 static void
3508 _rotate_test(Evas_Object *obj,
3509              Pointer_Event *pe,
3510              void *event_info,
3511              Evas_Callback_Type event_type,
3512              Elm_Gesture_Type g_type)
3513 {
3514    Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
3515    Gesture_Info *gesture;
3516    Rotate_Type *st = NULL;
3517
3518    if (!_elm_config->glayer_rotate_finger_enable)
3519      return;
3520
3521    if (!pe)
3522      return;
3523
3524    ELM_GESTURE_LAYER_DATA_GET(obj, sd);
3525
3526    if (!sd->gesture[g_type]) return;
3527
3528    gesture = sd->gesture[g_type];
3529    if (!gesture) return ;
3530
3531    st = gesture->data;
3532    if (!st) /* Allocated once on first time */
3533      {
3534        st = calloc(1, sizeof(Rotate_Type));
3535        gesture->data = st;
3536        _rotate_test_reset(gesture);
3537      }
3538
3539    switch (event_type)
3540      {
3541       case EVAS_CALLBACK_MOUSE_MOVE:
3542       case EVAS_CALLBACK_MULTI_MOVE:
3543         /* if non-continues mode and gesture NOT started, ignore MOVE */
3544         if ((!sd->glayer_continues_enable) &&
3545             (!st->rotate_st.timestamp))
3546           return;
3547
3548       case EVAS_CALLBACK_MOUSE_DOWN:
3549       case EVAS_CALLBACK_MULTI_DOWN:
3550       { /* Here we take care of rotate-start and rotate move */
3551         Eina_List *l;
3552         Pointer_Event *p;
3553
3554         if (eina_list_count(sd->touched) > 2) /* Process rotate only
3555                                                * when 2 fingers on
3556                                                * surface */
3557           {
3558              ev_flag = _state_set
3559                  (gesture, ELM_GESTURE_STATE_ABORT, &st->info, EINA_FALSE);
3560              _event_consume(sd, event_info, event_type, ev_flag);
3561
3562              return;
3563           }
3564
3565         if (!st->rotate_st.timestamp) /* Now scan touched-devices list
3566                                        * and find other finger */
3567           {
3568              EINA_LIST_FOREACH(sd->touched, l, p)
3569                { /* Device of other finger <> pe device */
3570                  if (p->device != pe->device)
3571                    break;
3572                }
3573
3574              if (!p)
3575                return;  /* Single finger on touch */
3576
3577              /* Record down fingers */
3578              _event_consume(sd, event_info, event_type, ev_flag);
3579              memcpy(&st->rotate_st, pe, sizeof(Pointer_Event));
3580              memcpy(&st->rotate_st1, p, sizeof(Pointer_Event));
3581
3582              /* Set mv field as well to be ready for MOVE events  */
3583              memcpy(&st->rotate_mv, pe, sizeof(Pointer_Event));
3584              memcpy(&st->rotate_mv1, p, sizeof(Pointer_Event));
3585
3586              /* Here we have rotate_st, rotate_st1 set, report START  */
3587              /* Set rotate-base after BOTH down events  recorded    */
3588              /* Compute length of line between fingers rotate start */
3589              _rotate_properties_get(st,
3590                                     st->rotate_st.x, st->rotate_st.y,
3591                                     st->rotate_st1.x, st->rotate_st1.y,
3592                                     &st->info.base_angle);
3593
3594              ev_flag = _state_set(gesture, ELM_GESTURE_STATE_START,
3595                                   &st->info, EINA_FALSE);
3596              _event_consume(sd, event_info, event_type, ev_flag);
3597
3598              return; /* Rotate started */
3599           } /* End of ROTATE_START handling */
3600
3601         /* if we got here, we have (exacally) two fingers on surfce */
3602         /* we also after START, report MOVE */
3603         /* First detect which finger moved  */
3604         if (pe->device == st->rotate_mv.device)
3605           memcpy(&st->rotate_mv, pe, sizeof(Pointer_Event));
3606         else if (pe->device == st->rotate_mv1.device)
3607           memcpy(&st->rotate_mv1, pe, sizeof(Pointer_Event));
3608
3609         /* Compute change in rotate as fingers move */
3610         _rotate_properties_get(st,
3611                                st->rotate_mv.x, st->rotate_mv.y,
3612                                st->rotate_mv1.x, st->rotate_mv1.y,
3613                                &st->info.angle);
3614
3615         if (_on_rotation_broke_tolerance(st)) /* Rotation broke
3616                                                * tolerance, report
3617                                                * move */
3618           {
3619              double d = st->info.angle - st->next_step;
3620              if (d < 0)
3621                d = (-d);
3622
3623              if (d >= sd->rotate_step) /* Report move in steps */
3624                {
3625                   st->next_step = st->info.angle;
3626
3627                   ev_flag = _state_set
3628                       (gesture, ELM_GESTURE_STATE_MOVE, &st->info, EINA_TRUE);
3629                   _event_consume(sd, event_info, event_type, ev_flag);
3630                }
3631           } /* End of ROTATE_MOVE handling */
3632
3633         return;
3634       }
3635
3636       case EVAS_CALLBACK_MOUSE_UP:
3637       case EVAS_CALLBACK_MULTI_UP:
3638         _event_consume(sd, event_info, event_type, ev_flag);
3639         /* Reset timestamp of finger-up.This is used later
3640            by rotate_test_reset() to retain finger-down data */
3641         if (st->rotate_angular_tolerance < 0)
3642           {
3643              ev_flag = _state_set(gesture, ELM_GESTURE_STATE_END,
3644                                   &st->info, EINA_FALSE);
3645              _event_consume(sd, event_info, event_type, ev_flag);
3646
3647              return;
3648           }
3649
3650         /* Must be != undefined, if gesture started */
3651         if (gesture->state != ELM_GESTURE_STATE_UNDEFINED)
3652           {
3653              ev_flag = _state_set(gesture, ELM_GESTURE_STATE_ABORT,
3654                                   &st->info, EINA_FALSE);
3655              _event_consume(sd, event_info, event_type, ev_flag);
3656           }
3657
3658         _rotate_test_reset(gesture);
3659         return;
3660
3661       default:
3662         return;
3663      }
3664 }
3665
3666 static void
3667 _elm_gesture_layer_smart_disable(Eo *obj, void *_pd EINA_UNUSED, va_list *list)
3668 {
3669    Eina_Bool *ret = va_arg(*list, Eina_Bool *);
3670    if (elm_widget_disabled_get(obj))
3671      _callbacks_unregister(obj);
3672    else
3673      _callbacks_register(obj);
3674
3675    if (ret) *ret = EINA_TRUE;
3676 }
3677
3678 static void
3679 _elm_gesture_layer_smart_add(Eo *obj, void *_pd, va_list *list EINA_UNUSED)
3680 {
3681    eo_do_super(obj, MY_CLASS, evas_obj_smart_add());
3682
3683    Elm_Gesture_Layer_Smart_Data *priv = _pd;
3684
3685    priv->line_min_length =
3686      _elm_config->glayer_line_min_length * elm_config_finger_size_get();
3687    priv->zoom_distance_tolerance = _elm_config->glayer_zoom_distance_tolerance
3688      * elm_config_finger_size_get();
3689    priv->line_distance_tolerance = _elm_config->glayer_line_distance_tolerance
3690      * elm_config_finger_size_get();
3691    priv->zoom_finger_factor = _elm_config->glayer_zoom_finger_factor;
3692    /* mouse wheel zoom steps */
3693    priv->zoom_wheel_factor = _elm_config->glayer_zoom_wheel_factor;
3694    priv->rotate_angular_tolerance =
3695      _elm_config->glayer_rotate_angular_tolerance;
3696    priv->line_angular_tolerance = _elm_config->glayer_line_angular_tolerance;
3697    priv->flick_time_limit_ms = _elm_config->glayer_flick_time_limit_ms;
3698    priv->long_tap_start_timeout = _elm_config->glayer_long_tap_start_timeout;
3699    priv->repeat_events = EINA_TRUE;
3700    priv->glayer_continues_enable = _elm_config->glayer_continues_enable;
3701
3702    /* FIXME: Hack to get around old configs - if too small, enlarge. */
3703    if (_elm_config->glayer_double_tap_timeout < 0.00001)
3704      _elm_config->glayer_double_tap_timeout = 0.25;
3705    priv->double_tap_timeout = _elm_config->glayer_double_tap_timeout;
3706
3707    memset(priv->gesture, 0, sizeof(priv->gesture));
3708 }
3709
3710 static void _cbs_clean(Elm_Gesture_Layer_Smart_Data *sd, Elm_Gesture_Type idx, Elm_Gesture_State cb_type);
3711
3712 static void
3713 _elm_gesture_layer_smart_del(Eo *obj, void *_pd, va_list *list EINA_UNUSED)
3714 {
3715    Elm_Gesture_Layer_Smart_Data *sd = _pd;
3716    Pointer_Event *data;
3717    int i;
3718
3719    _event_history_clear(obj);
3720    sd->pending = eina_list_free(sd->pending);
3721
3722    EINA_LIST_FREE(sd->touched, data)
3723      free(data);
3724
3725    if (!elm_widget_disabled_get(obj))
3726      _callbacks_unregister(obj);
3727
3728    /* Free all gestures internal data structures */
3729    for (i = 0; i < ELM_GESTURE_LAST; i++)
3730      if (sd->gesture[i])
3731        {
3732           if (sd->gesture[i]->data)
3733             free(sd->gesture[i]->data);
3734
3735           _cbs_clean(sd, i, ELM_GESTURE_STATE_START);
3736           _cbs_clean(sd, i, ELM_GESTURE_STATE_MOVE);
3737           _cbs_clean(sd, i, ELM_GESTURE_STATE_END);
3738           _cbs_clean(sd, i, ELM_GESTURE_STATE_ABORT);
3739           free(sd->gesture[i]);
3740        }
3741    if (sd->gest_taps_timeout) ecore_timer_del(sd->gest_taps_timeout);
3742
3743    eo_do_super(obj, MY_CLASS, evas_obj_smart_del());
3744 }
3745
3746 EAPI Evas_Object *
3747 elm_gesture_layer_add(Evas_Object *parent)
3748 {
3749    EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL);
3750    Evas_Object *obj = eo_add(MY_CLASS, parent);
3751    eo_unref(obj);
3752    return obj;
3753 }
3754
3755 static void
3756 _constructor(Eo *obj, void *_pd EINA_UNUSED, va_list *list EINA_UNUSED)
3757 {
3758    eo_do_super(obj, MY_CLASS, eo_constructor());
3759    eo_do(obj, evas_obj_type_set(MY_CLASS_NAME));
3760
3761    elm_widget_sub_object_add(eo_parent_get(obj), obj);
3762 }
3763
3764 EAPI Eina_Bool
3765 elm_gesture_layer_hold_events_get(const Evas_Object *obj)
3766 {
3767    ELM_GESTURE_LAYER_CHECK(obj) EINA_FALSE;
3768    Eina_Bool ret = EINA_FALSE;
3769    eo_do((Eo *) obj, elm_obj_gesture_layer_hold_events_get(&ret));
3770    return ret;
3771 }
3772
3773 static void
3774 _hold_events_get(Eo *obj EINA_UNUSED, void *_pd, va_list *list)
3775 {
3776    Eina_Bool *ret = va_arg(*list, Eina_Bool *);
3777    Elm_Gesture_Layer_Smart_Data *sd = _pd;
3778    *ret = !sd->repeat_events;
3779 }
3780
3781 EAPI void
3782 elm_gesture_layer_hold_events_set(Evas_Object *obj,
3783                                   Eina_Bool hold_events)
3784 {
3785    ELM_GESTURE_LAYER_CHECK(obj);
3786    eo_do(obj, elm_obj_gesture_layer_hold_events_set(hold_events));
3787 }
3788
3789 static void
3790 _hold_events_set(Eo *obj EINA_UNUSED, void *_pd, va_list *list)
3791 {
3792    Eina_Bool hold_events = va_arg(*list, int);
3793    Elm_Gesture_Layer_Smart_Data *sd = _pd;
3794
3795    sd->repeat_events = !(!!hold_events);
3796 }
3797
3798 EAPI double
3799 elm_gesture_layer_zoom_step_get(const Evas_Object *obj)
3800 {
3801    ELM_GESTURE_LAYER_CHECK(obj) 0;
3802    double ret = 0;
3803    eo_do((Eo *) obj, elm_obj_gesture_layer_zoom_step_get(&ret));
3804    return ret;
3805 }
3806
3807 static void
3808 _zoom_step_get(Eo *obj EINA_UNUSED, void *_pd, va_list *list)
3809 {
3810    double *ret = va_arg(*list, double *);
3811    Elm_Gesture_Layer_Smart_Data *sd = _pd;
3812    *ret = sd->zoom_step;
3813 }
3814
3815 EAPI void
3816 elm_gesture_layer_zoom_step_set(Evas_Object *obj,
3817                                 double step)
3818 {
3819    ELM_GESTURE_LAYER_CHECK(obj);
3820    eo_do(obj, elm_obj_gesture_layer_zoom_step_set(step));
3821 }
3822
3823 static void
3824 _zoom_step_set(Eo *obj EINA_UNUSED, void *_pd, va_list *list)
3825 {
3826    double step = va_arg(*list, double);
3827    Elm_Gesture_Layer_Smart_Data *sd = _pd;
3828
3829    if (step < 0) return;
3830
3831    sd->zoom_step = step;
3832 }
3833
3834 EAPI double
3835 elm_gesture_layer_rotate_step_get(const Evas_Object *obj)
3836 {
3837    ELM_GESTURE_LAYER_CHECK(obj) 0;
3838    double ret = 0;
3839    eo_do((Eo *) obj, elm_obj_gesture_layer_rotate_step_get(&ret));
3840    return ret;
3841 }
3842
3843 static void
3844 _rotate_step_get(Eo *obj EINA_UNUSED, void *_pd, va_list *list)
3845 {
3846    double *ret = va_arg(*list, double *);
3847    Elm_Gesture_Layer_Smart_Data *sd = _pd;
3848    *ret = sd->rotate_step;
3849 }
3850
3851 EAPI void
3852 elm_gesture_layer_rotate_step_set(Evas_Object *obj,
3853                                   double step)
3854 {
3855    ELM_GESTURE_LAYER_CHECK(obj);
3856    eo_do(obj, elm_obj_gesture_layer_rotate_step_set(step));
3857 }
3858
3859 static void
3860 _rotate_step_set(Eo *obj EINA_UNUSED, void *_pd, va_list *list)
3861 {
3862    double step = va_arg(*list, double);
3863    Elm_Gesture_Layer_Smart_Data *sd = _pd;
3864
3865    if (step < 0) return;
3866
3867    sd->rotate_step = step;
3868 }
3869
3870 EAPI Eina_Bool
3871 elm_gesture_layer_attach(Evas_Object *obj,
3872                          Evas_Object *target)
3873 {
3874    ELM_GESTURE_LAYER_CHECK(obj) EINA_FALSE;
3875    Eina_Bool ret = EINA_FALSE;
3876    eo_do(obj, elm_obj_gesture_layer_attach(target, &ret));
3877    return ret;
3878 }
3879
3880 static void
3881 _attach(Eo *obj, void *_pd, va_list *list)
3882 {
3883    Evas_Object *target = va_arg(*list, Evas_Object *);
3884    Eina_Bool *ret = va_arg(*list, Eina_Bool *);
3885    Elm_Gesture_Layer_Smart_Data *sd = _pd;
3886    if (ret) *ret = EINA_FALSE;
3887
3888    if (!target) return;
3889
3890    /* if was attached before, unregister callbacks first */
3891    if (sd->target)
3892      _callbacks_unregister(obj);
3893
3894    sd->target = target;
3895
3896    _callbacks_register(obj);
3897    if (ret) *ret = EINA_TRUE;
3898 }
3899
3900 static void
3901 _cbs_clean(Elm_Gesture_Layer_Smart_Data *sd,
3902           Elm_Gesture_Type idx,
3903           Elm_Gesture_State cb_type)
3904 {
3905    if (!sd->gesture[idx]) return;
3906
3907    Func_Data *cb_info;
3908    EINA_INLIST_FREE(sd->gesture[idx]->cbs[cb_type], cb_info)
3909      {
3910         sd->gesture[idx]->cbs[cb_type] = eina_inlist_remove(
3911               sd->gesture[idx]->cbs[cb_type], EINA_INLIST_GET(cb_info));
3912         free(cb_info);
3913      }
3914    SET_TEST_BIT(sd->gesture[idx]);
3915 }
3916
3917 EAPI void
3918 elm_gesture_layer_cb_set(Evas_Object *obj,
3919                          Elm_Gesture_Type idx,
3920                          Elm_Gesture_State cb_type,
3921                          Elm_Gesture_Event_Cb cb,
3922                          void *data)
3923 {
3924    ELM_GESTURE_LAYER_CHECK(obj);
3925    eo_do(obj, elm_obj_gesture_layer_cb_set(idx, cb_type, cb, data));
3926 }
3927
3928 static void
3929 _cb_set(Eo *obj, void *_pd, va_list *list)
3930 {
3931    Elm_Gesture_Type idx = va_arg(*list, Elm_Gesture_Type);
3932    Elm_Gesture_State cb_type = va_arg(*list, Elm_Gesture_State);
3933    Elm_Gesture_Event_Cb cb = va_arg(*list, Elm_Gesture_Event_Cb);
3934    void *data = va_arg(*list, void *);
3935
3936    Elm_Gesture_Layer_Smart_Data *sd = _pd;
3937
3938    _cbs_clean(sd, idx, cb_type); // for ABI compat.
3939    eo_do(obj, elm_obj_gesture_layer_cb_add(idx, cb_type, cb, data));
3940 }
3941
3942 EAPI void
3943 elm_gesture_layer_cb_add(Evas_Object *obj,
3944                          Elm_Gesture_Type idx,
3945                          Elm_Gesture_State cb_type,
3946                          Elm_Gesture_Event_Cb cb,
3947                          void *data)
3948 {
3949    ELM_GESTURE_LAYER_CHECK(obj);
3950    eo_do(obj, elm_obj_gesture_layer_cb_add(idx, cb_type, cb, data));
3951 }
3952
3953 static void
3954 _cb_add(Eo *obj, void *_pd, va_list *list)
3955 {
3956    Elm_Gesture_Type idx = va_arg(*list, Elm_Gesture_Type);
3957    Elm_Gesture_State cb_type = va_arg(*list, Elm_Gesture_State);
3958    Elm_Gesture_Event_Cb cb = va_arg(*list, Elm_Gesture_Event_Cb);
3959    void *data = va_arg(*list, void *);
3960
3961    if (!cb) return;
3962
3963    Gesture_Info *p;
3964    Elm_Gesture_Layer_Smart_Data *sd = _pd;
3965
3966    if (!sd->gesture[idx])
3967      sd->gesture[idx] = calloc(1, sizeof(Gesture_Info));
3968    if (!sd->gesture[idx]) return;
3969
3970    Func_Data *cb_info = calloc(1, sizeof(*cb_info));
3971    if (!cb_info) return;
3972    cb_info->cb = cb;
3973    cb_info->user_data = data;
3974
3975    p = sd->gesture[idx];
3976    p->obj = obj;
3977    p->g_type = idx;
3978    p->cbs[cb_type] = eina_inlist_append(p->cbs[cb_type],
3979          EINA_INLIST_GET(cb_info));
3980    p->state = ELM_GESTURE_STATE_UNDEFINED;
3981    SET_TEST_BIT(p);
3982 }
3983
3984 EAPI void
3985 elm_gesture_layer_cb_del(Evas_Object *obj,
3986                          Elm_Gesture_Type idx,
3987                          Elm_Gesture_State cb_type,
3988                          Elm_Gesture_Event_Cb cb,
3989                          void *data)
3990 {
3991    ELM_GESTURE_LAYER_CHECK(obj);
3992    eo_do(obj, elm_obj_gesture_layer_cb_del(idx, cb_type, cb, data));
3993 }
3994
3995 static void
3996 _cb_del(Eo *obj EINA_UNUSED, void *_pd, va_list *list)
3997 {
3998    Elm_Gesture_Type idx = va_arg(*list, Elm_Gesture_Type);
3999    Elm_Gesture_State cb_type = va_arg(*list, Elm_Gesture_State);
4000    Elm_Gesture_Event_Cb cb = va_arg(*list, Elm_Gesture_Event_Cb);
4001    void *data = va_arg(*list, void *);
4002
4003    Elm_Gesture_Layer_Smart_Data *sd = _pd;
4004
4005    if (!sd->gesture[idx]) return;
4006
4007    Eina_Inlist *itr;
4008    Func_Data *cb_info;
4009    EINA_INLIST_FOREACH_SAFE(sd->gesture[idx]->cbs[cb_type], itr, cb_info)
4010      {
4011         if (cb_info->cb == cb && cb_info->user_data == data)
4012           {
4013              sd->gesture[idx]->cbs[cb_type] = eina_inlist_remove(
4014                    sd->gesture[idx]->cbs[cb_type], EINA_INLIST_GET(cb_info));
4015              free(cb_info);
4016              SET_TEST_BIT(sd->gesture[idx]);
4017              return;
4018           }
4019      }
4020 }
4021
4022 EAPI void
4023 elm_gesture_layer_line_min_length_set(Evas_Object *obj, int line_min_length)
4024 {
4025    ELM_GESTURE_LAYER_CHECK(obj);
4026    ELM_GESTURE_LAYER_DATA_GET(obj, sd);
4027    sd->line_min_length = line_min_length;
4028 }
4029
4030
4031 EAPI int
4032 elm_gesture_layer_line_min_length_get(const Evas_Object *obj)
4033 {
4034    ELM_GESTURE_LAYER_CHECK(obj) 0;
4035    ELM_GESTURE_LAYER_DATA_GET(obj, sd);
4036    return sd->line_min_length;
4037 }
4038
4039 EAPI void
4040 elm_gesture_layer_zoom_distance_tolerance_set(Evas_Object *obj, Evas_Coord zoom_distance_tolerance)
4041 {
4042    ELM_GESTURE_LAYER_CHECK(obj);
4043    ELM_GESTURE_LAYER_DATA_GET(obj, sd);
4044    sd->zoom_distance_tolerance = zoom_distance_tolerance;
4045 }
4046
4047 EAPI Evas_Coord
4048 elm_gesture_layer_zoom_distance_tolerance_get(const Evas_Object *obj)
4049 {
4050    ELM_GESTURE_LAYER_CHECK(obj) 0;
4051    ELM_GESTURE_LAYER_DATA_GET(obj, sd);
4052    return sd->zoom_distance_tolerance;
4053 }
4054
4055 EAPI void
4056 elm_gesture_layer_line_distance_tolerance_set(Evas_Object *obj, Evas_Coord line_distance_tolerance)
4057 {
4058    ELM_GESTURE_LAYER_CHECK(obj);
4059    ELM_GESTURE_LAYER_DATA_GET(obj, sd);
4060    sd->line_distance_tolerance = line_distance_tolerance;
4061 }
4062
4063 EAPI Evas_Coord
4064 elm_gesture_layer_line_distance_tolerance_get(const Evas_Object *obj)
4065 {
4066    ELM_GESTURE_LAYER_CHECK(obj) 0;
4067    ELM_GESTURE_LAYER_DATA_GET(obj, sd);
4068    return sd->line_distance_tolerance;
4069 }
4070
4071 EAPI void
4072 elm_gesture_layer_line_angular_tolerance_set(Evas_Object *obj, double line_angular_tolerance)
4073 {
4074    ELM_GESTURE_LAYER_CHECK(obj);
4075    ELM_GESTURE_LAYER_DATA_GET(obj, sd);
4076    sd->line_angular_tolerance = line_angular_tolerance;
4077 }
4078
4079 EAPI double
4080 elm_gesture_layer_line_angular_tolerance_get(const Evas_Object *obj)
4081 {
4082    ELM_GESTURE_LAYER_CHECK(obj) 0.0;
4083    ELM_GESTURE_LAYER_DATA_GET(obj, sd);
4084    return sd->line_angular_tolerance;
4085 }
4086
4087 EAPI void
4088 elm_gesture_layer_zoom_wheel_factor_set(Evas_Object *obj, double zoom_wheel_factor)
4089 {
4090    ELM_GESTURE_LAYER_CHECK(obj);
4091    ELM_GESTURE_LAYER_DATA_GET(obj, sd);
4092    sd->zoom_wheel_factor = zoom_wheel_factor;
4093 }
4094
4095 EAPI double
4096 elm_gesture_layer_zoom_wheel_factor_get(const Evas_Object *obj)
4097 {
4098    ELM_GESTURE_LAYER_CHECK(obj) 0.0;
4099    ELM_GESTURE_LAYER_DATA_GET(obj, sd);
4100    return sd->zoom_wheel_factor;
4101 }
4102
4103 EAPI void
4104 elm_gesture_layer_zoom_finger_factor_set(Evas_Object *obj, double zoom_finger_factor)
4105 {
4106    ELM_GESTURE_LAYER_CHECK(obj);
4107    ELM_GESTURE_LAYER_DATA_GET(obj, sd);
4108    sd->zoom_finger_factor = zoom_finger_factor;
4109 }
4110
4111 EAPI double
4112 elm_gesture_layer_zoom_finger_factor_get(const Evas_Object *obj)
4113 {
4114    ELM_GESTURE_LAYER_CHECK(obj) 0.0;
4115    ELM_GESTURE_LAYER_DATA_GET(obj, sd);
4116    return sd->zoom_finger_factor;
4117 }
4118
4119 EAPI void
4120 elm_gesture_layer_rotate_angular_tolerance_set(Evas_Object *obj, double rotate_angular_tolerance)
4121 {
4122    ELM_GESTURE_LAYER_CHECK(obj);
4123    ELM_GESTURE_LAYER_DATA_GET(obj, sd);
4124    sd->rotate_angular_tolerance = rotate_angular_tolerance;
4125 }
4126
4127 EAPI double
4128 elm_gesture_layer_rotate_angular_tolerance_get(const Evas_Object *obj)
4129 {
4130    ELM_GESTURE_LAYER_CHECK(obj) 0.0;
4131    ELM_GESTURE_LAYER_DATA_GET(obj, sd);
4132    return sd->rotate_angular_tolerance;
4133 }
4134
4135 EAPI void
4136 elm_gesture_layer_flick_time_limit_ms_set(Evas_Object *obj, unsigned int flick_time_limit_ms)
4137 {
4138    ELM_GESTURE_LAYER_CHECK(obj);
4139    ELM_GESTURE_LAYER_DATA_GET(obj, sd);
4140    sd->flick_time_limit_ms = flick_time_limit_ms;
4141 }
4142
4143 EAPI unsigned int
4144 elm_gesture_layer_flick_time_limit_ms_get(const Evas_Object *obj)
4145 {
4146    ELM_GESTURE_LAYER_CHECK(obj) 0;
4147    ELM_GESTURE_LAYER_DATA_GET(obj, sd);
4148    return sd->flick_time_limit_ms;
4149 }
4150
4151 EAPI void
4152 elm_gesture_layer_long_tap_start_timeout_set(Evas_Object *obj, double long_tap_start_timeout)
4153 {
4154    ELM_GESTURE_LAYER_CHECK(obj);
4155    ELM_GESTURE_LAYER_DATA_GET(obj, sd);
4156    sd->long_tap_start_timeout = long_tap_start_timeout;
4157 }
4158
4159 EAPI double
4160 elm_gesture_layer_long_tap_start_timeout_get(const Evas_Object *obj)
4161 {
4162    ELM_GESTURE_LAYER_CHECK(obj) 0.0;
4163    ELM_GESTURE_LAYER_DATA_GET(obj, sd);
4164    return sd->long_tap_start_timeout;
4165 }
4166
4167 EAPI void
4168 elm_gesture_layer_continues_enable_set(Evas_Object *obj, Eina_Bool continues_enable)
4169 {
4170    ELM_GESTURE_LAYER_CHECK(obj);
4171    ELM_GESTURE_LAYER_DATA_GET(obj, sd);
4172    sd->glayer_continues_enable = continues_enable;
4173 }
4174
4175 EAPI Eina_Bool
4176 elm_gesture_layer_continues_enable_get(const Evas_Object *obj)
4177 {
4178    ELM_GESTURE_LAYER_CHECK(obj) 0.0;
4179    ELM_GESTURE_LAYER_DATA_GET(obj, sd);
4180    return sd->glayer_continues_enable;
4181 }
4182
4183 EAPI void
4184 elm_gesture_layer_double_tap_timeout_set(Evas_Object *obj, double double_tap_timeout)
4185 {
4186    ELM_GESTURE_LAYER_CHECK(obj);
4187    ELM_GESTURE_LAYER_DATA_GET(obj, sd);
4188    sd->double_tap_timeout = double_tap_timeout;
4189 }
4190
4191 EAPI double
4192 elm_gesture_layer_double_tap_timeout_get(const Evas_Object *obj)
4193 {
4194    ELM_GESTURE_LAYER_CHECK(obj) 0.0;
4195    ELM_GESTURE_LAYER_DATA_GET(obj, sd);
4196    return sd->double_tap_timeout;
4197 }
4198
4199 EAPI void
4200 elm_gesture_layer_tap_finger_size_set(Evas_Object *obj,
4201       Evas_Coord sz)
4202 {
4203    ELM_GESTURE_LAYER_CHECK(obj);
4204    eo_do(obj, elm_obj_gesture_layer_tap_finger_size_set(sz));
4205 }
4206
4207 static void
4208 _tap_finger_size_set(Eo *obj EINA_UNUSED, void *_pd, va_list *list)
4209 {
4210    Evas_Coord sz = va_arg(*list, Evas_Coord);
4211    Elm_Gesture_Layer_Smart_Data *sd = _pd;
4212
4213    if (sz < 0)
4214       sz = 0;  /* Should not be negative, will reset to system value */
4215
4216    sd->tap_finger_size = sz;
4217 }
4218
4219 EAPI Evas_Coord
4220 elm_gesture_layer_tap_finger_size_get(const Evas_Object *obj)
4221 {
4222    ELM_GESTURE_LAYER_CHECK(obj) elm_config_finger_size_get();
4223    Evas_Coord ret = 0;
4224    eo_do((Eo *) obj, elm_obj_gesture_layer_tap_finger_size_get(&ret));
4225    return ret;
4226 }
4227
4228 static void
4229 _tap_finger_size_get(Eo *obj EINA_UNUSED, void *_pd, va_list *list)
4230 {
4231    Evas_Coord *ret = va_arg(*list, Evas_Coord *);
4232    Elm_Gesture_Layer_Smart_Data *sd = _pd;
4233    *ret = sd->tap_finger_size;
4234 }
4235
4236 static void
4237 _class_constructor(Eo_Class *klass)
4238 {
4239    const Eo_Op_Func_Description func_desc[] = {
4240         EO_OP_FUNC(EO_BASE_ID(EO_BASE_SUB_ID_CONSTRUCTOR), _constructor),
4241
4242         EO_OP_FUNC(EVAS_OBJ_SMART_ID(EVAS_OBJ_SMART_SUB_ID_ADD), _elm_gesture_layer_smart_add),
4243         EO_OP_FUNC(EVAS_OBJ_SMART_ID(EVAS_OBJ_SMART_SUB_ID_DEL), _elm_gesture_layer_smart_del),
4244
4245         EO_OP_FUNC(ELM_WIDGET_ID(ELM_WIDGET_SUB_ID_DISABLE), _elm_gesture_layer_smart_disable),
4246
4247         EO_OP_FUNC(ELM_OBJ_GESTURE_LAYER_ID(ELM_OBJ_GESTURE_LAYER_SUB_ID_HOLD_EVENTS_GET), _hold_events_get),
4248         EO_OP_FUNC(ELM_OBJ_GESTURE_LAYER_ID(ELM_OBJ_GESTURE_LAYER_SUB_ID_HOLD_EVENTS_SET), _hold_events_set),
4249         EO_OP_FUNC(ELM_OBJ_GESTURE_LAYER_ID(ELM_OBJ_GESTURE_LAYER_SUB_ID_ZOOM_STEP_GET), _zoom_step_get),
4250         EO_OP_FUNC(ELM_OBJ_GESTURE_LAYER_ID(ELM_OBJ_GESTURE_LAYER_SUB_ID_ZOOM_STEP_SET), _zoom_step_set),
4251         EO_OP_FUNC(ELM_OBJ_GESTURE_LAYER_ID(ELM_OBJ_GESTURE_LAYER_SUB_ID_ROTATE_STEP_GET), _rotate_step_get),
4252         EO_OP_FUNC(ELM_OBJ_GESTURE_LAYER_ID(ELM_OBJ_GESTURE_LAYER_SUB_ID_ROTATE_STEP_SET), _rotate_step_set),
4253         EO_OP_FUNC(ELM_OBJ_GESTURE_LAYER_ID(ELM_OBJ_GESTURE_LAYER_SUB_ID_ATTACH), _attach),
4254         EO_OP_FUNC(ELM_OBJ_GESTURE_LAYER_ID(ELM_OBJ_GESTURE_LAYER_SUB_ID_CB_SET), _cb_set),
4255         EO_OP_FUNC(ELM_OBJ_GESTURE_LAYER_ID(ELM_OBJ_GESTURE_LAYER_TAP_FINGER_SIZE_SET), _tap_finger_size_set),
4256         EO_OP_FUNC(ELM_OBJ_GESTURE_LAYER_ID(ELM_OBJ_GESTURE_LAYER_TAP_FINGER_SIZE_GET), _tap_finger_size_get),
4257         EO_OP_FUNC(ELM_OBJ_GESTURE_LAYER_ID(ELM_OBJ_GESTURE_LAYER_SUB_ID_CB_ADD), _cb_add),
4258         EO_OP_FUNC(ELM_OBJ_GESTURE_LAYER_ID(ELM_OBJ_GESTURE_LAYER_SUB_ID_CB_DEL), _cb_del),
4259         EO_OP_FUNC_SENTINEL
4260    };
4261    eo_class_funcs_set(klass, func_desc);
4262
4263    evas_smart_legacy_type_register(MY_CLASS_NAME, klass);
4264 }
4265
4266 static const Eo_Op_Description op_desc[] = {
4267      EO_OP_DESCRIPTION(ELM_OBJ_GESTURE_LAYER_SUB_ID_HOLD_EVENTS_GET, "Call this function to get repeat-events settings."),
4268      EO_OP_DESCRIPTION(ELM_OBJ_GESTURE_LAYER_SUB_ID_HOLD_EVENTS_SET, "This function is to make gesture-layer repeat events."),
4269      EO_OP_DESCRIPTION(ELM_OBJ_GESTURE_LAYER_SUB_ID_ZOOM_STEP_GET, "This function returns step-value for zoom action."),
4270      EO_OP_DESCRIPTION(ELM_OBJ_GESTURE_LAYER_SUB_ID_ZOOM_STEP_SET, "This function sets step-value for zoom action."),
4271      EO_OP_DESCRIPTION(ELM_OBJ_GESTURE_LAYER_SUB_ID_ROTATE_STEP_GET, "This function returns step-value for rotate action."),
4272      EO_OP_DESCRIPTION(ELM_OBJ_GESTURE_LAYER_SUB_ID_ROTATE_STEP_SET, "This function sets step-value for rotate action."),
4273      EO_OP_DESCRIPTION(ELM_OBJ_GESTURE_LAYER_SUB_ID_ATTACH, "Attach a given gesture layer widget to an Evas object, thus setting the widget's target."),
4274      EO_OP_DESCRIPTION(ELM_OBJ_GESTURE_LAYER_SUB_ID_CB_SET, "Use function to set callbacks to be notified about change of state of gesture."),
4275      EO_OP_DESCRIPTION(ELM_OBJ_GESTURE_LAYER_TAP_FINGER_SIZE_SET, "Use function to set valid touch-area size for finger."),
4276      EO_OP_DESCRIPTION(ELM_OBJ_GESTURE_LAYER_TAP_FINGER_SIZE_GET, "This function returns the valid touch-area size for finger."),
4277      EO_OP_DESCRIPTION(ELM_OBJ_GESTURE_LAYER_SUB_ID_CB_ADD, "Use function to add callbacks to be notified about change of state of gesture."),
4278      EO_OP_DESCRIPTION(ELM_OBJ_GESTURE_LAYER_SUB_ID_CB_DEL, "Use function to remove added callbacks."),
4279      EO_OP_DESCRIPTION_SENTINEL
4280 };
4281
4282 static const Eo_Class_Description class_desc = {
4283      EO_VERSION,
4284      MY_CLASS_NAME,
4285      EO_CLASS_TYPE_REGULAR,
4286      EO_CLASS_DESCRIPTION_OPS(&ELM_OBJ_GESTURE_LAYER_BASE_ID, op_desc, ELM_OBJ_GESTURE_LAYER_SUB_ID_LAST),
4287      NULL,
4288      sizeof(Elm_Gesture_Layer_Smart_Data),
4289      _class_constructor,
4290      NULL
4291 };
4292
4293 EO_DEFINE_CLASS(elm_obj_gesture_layer_class_get, &class_desc, ELM_OBJ_WIDGET_CLASS, NULL);