Revert "elm_gesture_layer: Fix potential NULL pointer dereference."
[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    ELM_GESTURE_LAYER_DATA_GET(data, sd);
964    sd->target = NULL;
965 }
966
967 /**
968  * @internal
969  *
970  * We register callbacks when gesture layer is attached to an object
971  * or when its enabled after disable.
972  *
973  * @param obj The gesture-layer object.
974  *
975  * @ingroup Elm_Gesture_Layer
976  */
977 static void
978 _callbacks_register(Evas_Object *obj)
979 {
980    ELM_GESTURE_LAYER_DATA_GET(obj, sd);
981
982    if (!sd->target) return;
983
984    evas_object_event_callback_add
985      (sd->target, EVAS_CALLBACK_MOUSE_DOWN, _mouse_down_cb, obj);
986    evas_object_event_callback_add
987      (sd->target, EVAS_CALLBACK_MOUSE_MOVE, _mouse_move_cb, obj);
988    evas_object_event_callback_add
989      (sd->target, EVAS_CALLBACK_MOUSE_UP, _mouse_up_cb, obj);
990
991    evas_object_event_callback_add
992      (sd->target, EVAS_CALLBACK_MOUSE_WHEEL, _mouse_wheel_cb, obj);
993
994    evas_object_event_callback_add
995      (sd->target, EVAS_CALLBACK_MULTI_DOWN, _multi_down_cb, obj);
996    evas_object_event_callback_add
997      (sd->target, EVAS_CALLBACK_MULTI_MOVE, _multi_move_cb, obj);
998    evas_object_event_callback_add
999      (sd->target, EVAS_CALLBACK_MULTI_UP, _multi_up_cb, obj);
1000
1001    evas_object_event_callback_add
1002      (sd->target, EVAS_CALLBACK_KEY_DOWN, _key_down_cb, obj);
1003    evas_object_event_callback_add
1004      (sd->target, EVAS_CALLBACK_KEY_UP, _key_up_cb, obj);
1005
1006    evas_object_event_callback_add
1007      (sd->target, EVAS_CALLBACK_DEL, _target_del_cb, obj);
1008 }
1009
1010 /**
1011  * @internal
1012  *
1013  * We unregister callbacks when gesture layer is disabled.
1014  *
1015  * @param obj The gesture-layer object.
1016  *
1017  * @ingroup Elm_Gesture_Layer
1018  */
1019 static void
1020 _callbacks_unregister(Evas_Object *obj)
1021 {
1022    ELM_GESTURE_LAYER_DATA_GET(obj, sd);
1023
1024    if (!sd->target) return;
1025
1026    evas_object_event_callback_del_full
1027      (sd->target, EVAS_CALLBACK_MOUSE_DOWN, _mouse_down_cb, obj);
1028    evas_object_event_callback_del_full
1029      (sd->target, EVAS_CALLBACK_MOUSE_MOVE, _mouse_move_cb, obj);
1030    evas_object_event_callback_del_full
1031      (sd->target, EVAS_CALLBACK_MOUSE_UP, _mouse_up_cb, obj);
1032
1033    evas_object_event_callback_del_full
1034      (sd->target, EVAS_CALLBACK_MOUSE_WHEEL, _mouse_wheel_cb, obj);
1035
1036    evas_object_event_callback_del_full
1037      (sd->target, EVAS_CALLBACK_MULTI_DOWN, _multi_down_cb, obj);
1038
1039    evas_object_event_callback_del_full
1040      (sd->target, EVAS_CALLBACK_MULTI_MOVE, _multi_move_cb, obj);
1041
1042    evas_object_event_callback_del_full
1043      (sd->target, EVAS_CALLBACK_MULTI_UP, _multi_up_cb, obj);
1044
1045    evas_object_event_callback_del_full
1046      (sd->target, EVAS_CALLBACK_KEY_DOWN, _key_down_cb, obj);
1047    evas_object_event_callback_del_full
1048      (sd->target, EVAS_CALLBACK_KEY_UP, _key_up_cb, obj);
1049
1050    evas_object_event_callback_del_full
1051      (sd->target, EVAS_CALLBACK_DEL, _target_del_cb, obj);
1052 }
1053
1054 /**
1055  * @internal
1056  * This function is used to find if device number
1057  * is found in a list of devices.
1058  * The list contains devices for refeeding *UP event
1059  *
1060  * @ingroup Elm_Gesture_Layer
1061  */
1062 static int
1063 _device_in_pending_cmp(const void *data1,
1064                        const void *data2)
1065 {
1066    /* Compare the two device numbers */
1067    return ((intptr_t)data1) - ((intptr_t)data2);
1068 }
1069
1070 /**
1071  * @internal
1072  *
1073  * This functions returns pending-device node
1074  * @ingroup Elm_Gesture_Layer
1075  */
1076 static Eina_List *
1077 _device_is_pending(Eina_List *list,
1078                    void *event,
1079                    Evas_Callback_Type event_type)
1080 {
1081    int device = ELM_MOUSE_DEVICE;
1082
1083    switch (event_type)
1084      {
1085       case EVAS_CALLBACK_MOUSE_UP:
1086         break;
1087
1088       case EVAS_CALLBACK_MULTI_UP:
1089         device = ((Evas_Event_Multi_Up *)event)->device;
1090         break;
1091
1092       default:
1093         return NULL;
1094      }
1095
1096    return eina_list_search_unsorted_list
1097             (list, _device_in_pending_cmp, (void *)(intptr_t)device);
1098 }
1099
1100 /**
1101  * @internal
1102  *
1103  * This functions adds device to refeed-pending device list
1104  * @ingroup Elm_Gesture_Layer
1105  */
1106 static Eina_List *
1107 _pending_device_add(Eina_List *list,
1108                     void *event,
1109                     Evas_Callback_Type event_type)
1110 {
1111    int device = ELM_MOUSE_DEVICE;
1112
1113    switch (event_type)
1114      {
1115       case EVAS_CALLBACK_MOUSE_DOWN:
1116         break;
1117
1118       case EVAS_CALLBACK_MULTI_DOWN:
1119         device = ((Evas_Event_Multi_Down *)event)->device;
1120         break;
1121
1122       default:
1123         return list;
1124      }
1125
1126    if (!eina_list_search_unsorted_list
1127          (list, _device_in_pending_cmp, (void *)(intptr_t)device))
1128      {
1129         return eina_list_append(list, (void *)(intptr_t)device);
1130      }
1131
1132    return list;
1133 }
1134
1135 /**
1136  * @internal
1137  *
1138  * This function reports ABORT to all none-detected gestures
1139  * Then resets test bits for all desired gesures
1140  * and clears input-events history.
1141  * note: if no gesture was detected, events from history list
1142  * are streamed to the widget because it's unused by layer.
1143  * user may cancel refeed of events by setting repeat events.
1144  *
1145  * @param obj The gesture-layer object.
1146  *
1147  * @ingroup Elm_Gesture_Layer
1148  */
1149 static Eina_Bool
1150 _event_history_clear(Evas_Object *obj)
1151 {
1152    int i;
1153    Gesture_Info *p;
1154    Evas *e = evas_object_evas_get(obj);
1155    Eina_Bool gesture_found = EINA_FALSE;
1156
1157    ELM_GESTURE_LAYER_DATA_GET(obj, sd);
1158
1159    for (i = ELM_GESTURE_FIRST; i < ELM_GESTURE_LAST; i++)
1160      {
1161         p = sd->gesture[i];
1162         if (p)
1163           {
1164              if (p->state == ELM_GESTURE_STATE_END)
1165                {
1166                   gesture_found = EINA_TRUE;
1167                }
1168              else
1169                {  /* Report ABORT to all gestures that still not finished */
1170                   if (sd->target)
1171                     _state_set(p, ELM_GESTURE_STATE_ABORT,
1172                           sd->gesture[i]->info, EINA_FALSE);
1173                }
1174           }
1175      }
1176
1177    _states_reset(sd); /* we are ready to start testing for gestures again */
1178
1179    /* Clear all gestures intermediate data */
1180    {
1181       /* FIXME: +1 because of the mistake in the enum. */
1182       Gesture_Info **gitr = sd->gesture + 1;
1183       Tests_Array_Funcs *fitr = _glayer_tests_array + 1;
1184       for (; fitr->reset; fitr++, gitr++)
1185         {
1186            if (IS_TESTED_GESTURE(*gitr))
1187              fitr->reset(*gitr);
1188         }
1189    }
1190
1191    /* Disable gesture layer so refeeded events won't be consumed by it */
1192    _callbacks_unregister(obj);
1193    while (sd->event_history_list)
1194      {
1195         Event_History *t;
1196         t = sd->event_history_list;
1197         Eina_List *pending = _device_is_pending
1198             (sd->pending, sd->event_history_list->event,
1199             sd->event_history_list->event_type);
1200
1201         /* Refeed events if no gesture matched input */
1202         if (pending || ((!gesture_found) && (!sd->repeat_events)))
1203           {
1204              evas_event_refeed_event(e, sd->event_history_list->event,
1205                                      sd->event_history_list->event_type);
1206
1207              if (pending)
1208                {
1209                   sd->pending = eina_list_remove_list(sd->pending, pending);
1210                }
1211              else
1212                {
1213                   sd->pending = _pending_device_add
1214                       (sd->pending, sd->event_history_list->event,
1215                       sd->event_history_list->event_type);
1216                }
1217           }
1218
1219         free(sd->event_history_list->event);
1220         sd->event_history_list = (Event_History *)eina_inlist_remove(
1221             EINA_INLIST_GET(sd->event_history_list),
1222             EINA_INLIST_GET(sd->event_history_list));
1223         free(t);
1224      }
1225    _callbacks_register(obj);
1226    return EINA_TRUE;
1227 }
1228
1229 /**
1230  * @internal
1231  *
1232  * if gesture was NOT detected AND we only have gestures in ABORT state
1233  * we clear history immediately to be ready for input.
1234  *
1235  * @param obj The gesture-layer object.
1236  * @return TRUE on event history_clear
1237  *
1238  * @ingroup Elm_Gesture_Layer
1239  */
1240 static Eina_Bool
1241 _clear_if_finished(Evas_Object *obj)
1242 {
1243    int i;
1244    Eina_Bool reset_s = EINA_TRUE, all_undefined = EINA_TRUE;
1245
1246    ELM_GESTURE_LAYER_DATA_GET(obj, sd);
1247
1248    /* Clear history if all we have aborted gestures */
1249    for (i = ELM_GESTURE_FIRST; i < ELM_GESTURE_LAST; i++)
1250      {  /* If no gesture started and all we have aborted gestures, reset all */
1251        Gesture_Info *p = sd->gesture[i];
1252
1253        if ((p) && (p->state != ELM_GESTURE_STATE_UNDEFINED))
1254          {
1255             if ((p->state == ELM_GESTURE_STATE_START) ||
1256                 (p->state == ELM_GESTURE_STATE_MOVE))
1257               reset_s = EINA_FALSE;
1258
1259             all_undefined = EINA_FALSE;
1260          }
1261      }
1262
1263    if (reset_s && (!all_undefined))
1264      return _event_history_clear(obj);
1265
1266    return EINA_FALSE;
1267 }
1268
1269 /**
1270  * @internal
1271  *
1272  * This function restartes line, flick, zoom and rotate gestures
1273  * when gesture-layer continues-gestures enabled.
1274  * Example of continues-gesture:
1275  * When doing a line, user stops moving finger but keeps fingers on touch.
1276  * This will cause line-end, then as user continues moving his finger
1277  * it re-starts line gesture.
1278  * When continue mode is disabled, user has to lift finger from touch
1279  * to end a gesture. Them touch-again to start a new one.
1280  *
1281  * @param data The gesture-layer object.
1282  * @param sd gesture layer widget data.
1283  * @param states_reset flag that marks gestures were reset in history clear.
1284  *
1285  * @ingroup Elm_Gesture_Layer
1286  */
1287 static void
1288 _continues_gestures_restart(void *data,
1289                             Eina_Bool states_reset)
1290 {
1291    ELM_GESTURE_LAYER_DATA_GET(data, sd);
1292
1293    /* Test all the gestures */
1294    {
1295       /* FIXME: +1 because of the mistake in the enum. */
1296       Gesture_Info **gitr = sd->gesture + 1;
1297       Tests_Array_Funcs *fitr = _glayer_tests_array + 1;
1298       for (; fitr->test; fitr++, gitr++)
1299         {
1300            Gesture_Info *g = *gitr;
1301            Eina_Bool tmp = (g) ?
1302              ((states_reset) || ((g->state != ELM_GESTURE_STATE_START)
1303                                  && (g->state != ELM_GESTURE_STATE_MOVE)))
1304              : EINA_FALSE;
1305            if (tmp && fitr->cont_reset)
1306              {
1307                 fitr->cont_reset(g);
1308                 _state_set(g, ELM_GESTURE_STATE_UNDEFINED, NULL, EINA_FALSE);
1309                 SET_TEST_BIT(g);
1310              }
1311         }
1312    }
1313 }
1314
1315 /**
1316  * @internal
1317  *
1318  * This function the core-function where input handling is done.
1319  * Here we get user input and stream it to gesture testing.
1320  * We notify user about any gestures with new state:
1321  * Valid states are:
1322  * START - gesture started.
1323  * MOVE - gesture is ongoing.
1324  * END - gesture was completed.
1325  * ABORT - gesture was aborted after START, MOVE (will NOT be completed)
1326  *
1327  * We also check if a gesture was detected, then reset event history
1328  * If no gestures were found we reset gesture test flag
1329  * after streaming event-history to widget.
1330  * (stream to the widget all events not consumed as a gesture)
1331  *
1332  * @param data The gesture-layer object.
1333  * @param event_info Pointer to recent input event.
1334  * @param event_type Recent input event type.
1335  *
1336  * @ingroup Elm_Gesture_Layer
1337  */
1338 static void
1339 _event_process(void *data,
1340                Evas_Object *obj __UNUSED__,
1341                void *event_info,
1342                Evas_Callback_Type event_type)
1343 {
1344    Pointer_Event _pe;
1345    Pointer_Event *pe = NULL;
1346
1347    ELM_GESTURE_LAYER_DATA_GET(data, sd);
1348
1349    /* Start testing candidate gesture from here */
1350    if (_pointer_event_make(data, event_info, event_type, &_pe))
1351      pe = &_pe;
1352
1353    /* Test all the gestures */
1354    {
1355       /* FIXME: +1 because of the mistake in the enum. */
1356       Gesture_Info **gitr = sd->gesture + 1;
1357       Tests_Array_Funcs *fitr = _glayer_tests_array + 1;
1358       for (; fitr->test; fitr++, gitr++)
1359         {
1360            if (IS_TESTED_GESTURE(*gitr))
1361              fitr->test(data, pe, event_info, event_type, (*gitr)->g_type);
1362         }
1363    }
1364
1365    if (_event_flag_get(event_info, event_type) & EVAS_EVENT_FLAG_ON_HOLD)
1366      _event_history_add(data, event_info, event_type);
1367
1368    /* we maintain list of touched devices              */
1369    /* We also use move to track current device x.y pos */
1370    if ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
1371        (event_type == EVAS_CALLBACK_MULTI_DOWN) ||
1372        (event_type == EVAS_CALLBACK_MOUSE_MOVE) ||
1373        (event_type == EVAS_CALLBACK_MULTI_MOVE))
1374      {
1375         sd->touched = _touched_device_add(sd->touched, pe);
1376      }
1377    else if ((event_type == EVAS_CALLBACK_MOUSE_UP) ||
1378             (event_type == EVAS_CALLBACK_MULTI_UP))
1379      {
1380         sd->touched = _touched_device_remove(sd->touched, pe);
1381      }
1382
1383    /* Report current states and clear history if needed */
1384    Eina_Bool states_reset = _clear_if_finished(data);
1385    if (sd->glayer_continues_enable)
1386      _continues_gestures_restart(data, states_reset);
1387 }
1388
1389 static Eina_Bool
1390 _inside(Evas_Coord xx1,
1391         Evas_Coord yy1,
1392         Evas_Coord xx2,
1393         Evas_Coord yy2,
1394         Evas_Coord w)
1395 {
1396    w >>= 1; /* Use half the distance, from center to all directions */
1397    if (!w)  /* use system default instead */
1398      w = elm_config_finger_size_get() >> 1; /* Finger size devided by 2 */
1399
1400    if (xx1 < (xx2 - w))
1401      return EINA_FALSE;
1402
1403    if (xx1 > (xx2 + w))
1404      return EINA_FALSE;
1405
1406    if (yy1 < (yy2 - w))
1407      return EINA_FALSE;
1408
1409    if (yy1 > (yy2 + w))
1410      return EINA_FALSE;
1411
1412    return EINA_TRUE;
1413 }
1414
1415 /* All *test_reset() funcs are called to clear
1416  * gesture intermediate data.
1417  * This happens when we need to reset our tests.
1418  * for example when gesture is detected or all ABORTed. */
1419 static void
1420 _tap_gestures_test_reset(Gesture_Info *gesture)
1421 {
1422    Eina_List *data;
1423    Pointer_Event *pe;
1424
1425    EINA_SAFETY_ON_NULL_RETURN(gesture);
1426    ELM_GESTURE_LAYER_DATA_GET(gesture->obj, sd);
1427
1428    ELM_SAFE_FREE(sd->gest_taps_timeout, ecore_timer_del);
1429
1430    if (!gesture->data)
1431      return;
1432
1433    EINA_LIST_FREE(((Taps_Type *)gesture->data)->l, data)
1434      EINA_LIST_FREE(data, pe)
1435        free(pe);
1436
1437    memset(gesture->data, 0, sizeof(Taps_Type));
1438 }
1439
1440 /* All *test_reset() funcs are called to clear
1441  * gesture intermediate data.
1442  * This happens when we need to reset our tests.
1443  * for example when gesture is detected or all ABORTed. */
1444 static void
1445 _n_long_tap_test_reset(Gesture_Info *gesture)
1446 {
1447    Pointer_Event *p;
1448    Long_Tap_Type *st;
1449
1450    EINA_SAFETY_ON_NULL_RETURN(gesture);
1451    if (!gesture->data) return;
1452
1453    st = gesture->data;
1454
1455    EINA_LIST_FREE(st->touched, p)
1456      free(p);
1457    st->touched = NULL;
1458
1459    ELM_SAFE_FREE(st->timeout, ecore_timer_del);
1460    memset(gesture->data, 0, sizeof(Long_Tap_Type));
1461 }
1462
1463 static void
1464 _momentum_test_reset(Gesture_Info *gesture)
1465 {
1466    EINA_SAFETY_ON_NULL_RETURN(gesture);
1467    if (!gesture->data) return;
1468
1469    memset(gesture->data, 0, sizeof(Momentum_Type));
1470 }
1471
1472 static void
1473 _line_data_reset(Line_Data *st)
1474 {
1475    if (!st)
1476      return;
1477
1478    memset(st, 0, sizeof(Line_Data));
1479    st->line_angle = ELM_GESTURE_NEGATIVE_ANGLE;
1480 }
1481
1482 static void
1483 _line_test_reset(Gesture_Info *gesture)
1484 {
1485    Line_Type *st;
1486    Line_Data *t_line;
1487
1488    EINA_SAFETY_ON_NULL_RETURN(gesture);
1489    if (!gesture->data) return;
1490
1491    st = gesture->data;
1492
1493    EINA_LIST_FREE(st->list, t_line)
1494      free(t_line);
1495    st->list = NULL;
1496 }
1497
1498 static void
1499 _zoom_test_reset(Gesture_Info *gesture)
1500 {
1501    Zoom_Type *st;
1502    Evas_Modifier_Mask mask;
1503
1504    EINA_SAFETY_ON_NULL_RETURN(gesture);
1505    if (!gesture->data) return;
1506    ELM_GESTURE_LAYER_DATA_GET(gesture->obj, sd);
1507
1508    st = gesture->data;
1509    mask = evas_key_modifier_mask_get(
1510        evas_object_evas_get(sd->target), "Control");
1511    evas_object_key_ungrab(sd->target, "Control_L", mask, 0);
1512    evas_object_key_ungrab(sd->target, "Control_R", mask, 0);
1513
1514    memset(st, 0, sizeof(Zoom_Type));
1515    st->zoom_distance_tolerance = sd->zoom_distance_tolerance;
1516    st->info.zoom = 1.0;
1517 }
1518
1519 static void
1520 _rotate_test_reset(Gesture_Info *gesture)
1521 {
1522    Rotate_Type *st;
1523
1524    EINA_SAFETY_ON_NULL_RETURN(gesture);
1525    if (!gesture->data) return;
1526
1527    ELM_GESTURE_LAYER_DATA_GET(gesture->obj, sd);
1528    st = gesture->data;
1529
1530    memset(st, 0, sizeof(Rotate_Type));
1531    st->info.base_angle = ELM_GESTURE_NEGATIVE_ANGLE;
1532    st->rotate_angular_tolerance = sd->rotate_angular_tolerance;
1533 }
1534
1535 static Eina_List *
1536 _match_fingers_compare(Eina_List *list,
1537                        Pointer_Event *pe1,
1538                        Evas_Coord w)
1539 {
1540     /* Compare coords of first item in list to cur coords */
1541    Eina_List *pe_list;
1542    Eina_List *l;
1543
1544    EINA_LIST_FOREACH(list, l, pe_list)
1545      {
1546         Pointer_Event *pe2 = eina_list_data_get(pe_list);
1547
1548         if (_inside(pe1->x, pe1->y, pe2->x, pe2->y, w))
1549           return pe_list;
1550      }
1551
1552   return NULL;
1553 }
1554
1555 static int
1556 _pe_device_compare(const void *data1,
1557                    const void *data2)
1558 {
1559    /* Compare device of first item in list to our pe device */
1560    const Pointer_Event *pe1 = eina_list_data_get(data1);
1561    const Pointer_Event *pe2 = data2;
1562
1563    if (pe1->device == pe2->device)
1564      return 0;
1565    else if (pe1->device < pe2->device)
1566      return -1;
1567    else
1568      return 1;
1569 }
1570
1571 static Eina_List *
1572 _pointer_event_record(Taps_Type *st,
1573                       Eina_List *pe_list,
1574                       Pointer_Event *pe,
1575                       Elm_Gesture_Layer_Smart_Data *sd,
1576                       void *event_info,
1577                       Evas_Callback_Type event_type)
1578 {
1579    /* Keep copy of pe and record it in list */
1580    Pointer_Event *p = malloc(sizeof(Pointer_Event));
1581
1582    memcpy(p, pe, sizeof(Pointer_Event));
1583    _event_consume(sd, event_info, event_type, EVAS_EVENT_FLAG_NONE);
1584
1585    st->sum_x += pe->x;
1586    st->sum_y += pe->y;
1587    st->n_taps++;
1588
1589    /* This will also update middle-point to report to user later */
1590    st->info.x = st->sum_x / st->n_taps;
1591    st->info.y = st->sum_y / st->n_taps;
1592    st->info.timestamp = pe->timestamp;
1593
1594    if (!pe_list)
1595      {
1596         pe_list = eina_list_append(pe_list, p);
1597         st->l = eina_list_append(st->l, pe_list);
1598      }
1599    else
1600      pe_list = eina_list_append(pe_list, p);
1601
1602    return pe_list;
1603 }
1604
1605 /**
1606  * @internal
1607  *
1608  * This function computes minimum rect to bound taps at idx index
1609  *
1610  * @param taps [in] List of lists containing taps info.
1611  * @param idx [in] index of events taken from lists.
1612  * @param r [out] rect object to save info
1613  * @return EINA_TRUE if managed to compute rect.
1614  *
1615  * @ingroup Elm_Gesture_Layer
1616  */
1617 static Eina_Bool
1618 _taps_rect_get(Eina_List *taps, int idx, Evas_Coord_Rectangle *r)
1619 {  /* Build a rect bounding all taps at index idx */
1620    Eina_List *l;
1621    Evas_Coord bx = 0, by = 0;
1622    Eina_List *pe_list;
1623    Eina_Bool was_init = EINA_FALSE;
1624
1625    EINA_LIST_FOREACH(taps, l, pe_list)
1626      {
1627         Pointer_Event *pe = eina_list_nth(pe_list, idx);
1628         if (!pe) continue;  /* Not suppose to happen */
1629
1630         if (was_init)
1631           {
1632              if (pe->x < r->x) r->x = pe->x;
1633              if (pe->y < r->y) r->y = pe->y;
1634              if (pe->x > bx) bx = pe->x;
1635              if (pe->y > by) by = pe->y;
1636           }
1637         else
1638           {
1639              r->x = bx = pe->x;
1640              r->y = by = pe->y;
1641              was_init = EINA_TRUE;
1642           }
1643      }
1644
1645    r->w = bx - r->x;
1646    r->h = by - r->y;
1647    return was_init;
1648 }
1649
1650 /**
1651  * @internal
1652  *
1653  * This function checks if the tap gesture is done.
1654  *
1655  * @param data gesture info pointer
1656  * @return EINA_TRUE if it is done.
1657  *
1658  * @ingroup Elm_Gesture_Layer
1659  */
1660 static Eina_Bool
1661 _tap_gesture_check_finish(Gesture_Info *gesture, Evas_Coord tap_finger_size)
1662 {
1663    /* Here we check if taps-gesture was completed successfuly */
1664    /* Count how many taps were recieved on each device then   */
1665    /* determine if it matches n_taps_needed defined on START  */
1666    unsigned int i;
1667    Taps_Type *st = gesture->data;
1668    Eina_List *l;
1669    Eina_List *pe_list;
1670    Evas_Coord_Rectangle base;
1671    Evas_Coord_Rectangle tmp;
1672    if (!tap_finger_size)  /* Use system default if not set by user */
1673      tap_finger_size = elm_config_finger_size_get();
1674
1675
1676    if (!st->l) return EINA_FALSE;
1677    EINA_LIST_FOREACH(st->l, l, pe_list)
1678      {
1679         /* No match taps number on device, ABORT */
1680         if (eina_list_count(pe_list) != st->n_taps_needed)
1681           {
1682              return EINA_FALSE;
1683           }
1684      }
1685
1686    /* Now bound each tap touches in a rect, compare diff within tolerance */
1687    /* Get rect based on first DOWN events for all devices */
1688    if (!_taps_rect_get(st->l, 0, &base))
1689      return EINA_FALSE;  /* Should not happen */
1690
1691    for(i = 1; i < st->n_taps_needed; i++)
1692      {  /* Compare all other rects to base, tolerance is finger size */
1693         if (_taps_rect_get(st->l, i, &tmp))
1694           {
1695              if (abs(tmp.x - base.x) > tap_finger_size)
1696                return EINA_FALSE;
1697
1698              if (abs(tmp.y - base.y) > tap_finger_size)
1699                return EINA_FALSE;
1700
1701              if (abs((tmp.x + tmp.w) - (base.x + base.w)) > tap_finger_size)
1702                return EINA_FALSE;
1703
1704              if (abs((tmp.y + tmp.h) - (base.y + base.h)) > tap_finger_size)
1705                return EINA_FALSE;
1706           }
1707      }
1708
1709    return EINA_TRUE;
1710 }
1711
1712 /**
1713  * @internal
1714  *
1715  * This function sets state a tap-gesture to END or ABORT
1716  *
1717  * @param data gesture info pointer
1718  *
1719  * @ingroup Elm_Gesture_Layer
1720  */
1721 static void
1722 _tap_gesture_finish(void *data, Evas_Coord tap_finger_size)
1723 {
1724    /* This function will test each tap gesture when timer expires */
1725    Elm_Gesture_State s = ELM_GESTURE_STATE_ABORT;
1726    Gesture_Info *gesture = data;
1727    Taps_Type *st = gesture->data;
1728
1729    if (_tap_gesture_check_finish(gesture, tap_finger_size))
1730      {
1731         s = ELM_GESTURE_STATE_END;
1732      }
1733
1734    st->info.n = eina_list_count(st->l);
1735    _state_set(gesture, s, gesture->info, EINA_FALSE);
1736    _tap_gestures_test_reset(gesture);
1737 }
1738
1739 /**
1740  * @internal
1741  *
1742  * when this timer expires we finish tap gestures.
1743  *
1744  * @param data The gesture-layer object.
1745  * @return cancles callback for this timer.
1746  *
1747  * @ingroup Elm_Gesture_Layer
1748  */
1749 static Eina_Bool
1750 _multi_tap_timeout(void *data)
1751 {
1752    ELM_GESTURE_LAYER_DATA_GET(data, sd);
1753
1754    if (IS_TESTED(ELM_GESTURE_N_TAPS))
1755      _tap_gesture_finish(sd->gesture[ELM_GESTURE_N_TAPS],
1756            sd->tap_finger_size);
1757
1758    if (IS_TESTED(ELM_GESTURE_N_DOUBLE_TAPS))
1759      _tap_gesture_finish(sd->gesture[ELM_GESTURE_N_DOUBLE_TAPS],
1760            sd->tap_finger_size);
1761
1762    if (IS_TESTED(ELM_GESTURE_N_TRIPLE_TAPS))
1763      _tap_gesture_finish(sd->gesture[ELM_GESTURE_N_TRIPLE_TAPS],
1764            sd->tap_finger_size);
1765
1766    _clear_if_finished(data);
1767    sd->gest_taps_timeout = NULL;
1768
1769    return ECORE_CALLBACK_CANCEL;
1770 }
1771
1772 /**
1773  * @internal
1774  *
1775  * when this timer expires we START long tap gesture
1776  *
1777  * @param data The gesture-layer object.
1778  * @return cancles callback for this timer.
1779  *
1780  * @ingroup Elm_Gesture_Layer
1781  */
1782 static Eina_Bool
1783 _long_tap_timeout(void *data)
1784 {
1785    Gesture_Info *gesture = data;
1786
1787    _state_set(gesture, ELM_GESTURE_STATE_MOVE,
1788               gesture->data, EINA_TRUE);
1789
1790    return ECORE_CALLBACK_RENEW;
1791 }
1792
1793 /**
1794  * @internal
1795  *
1796  * This function checks the state of a tap gesture.
1797  *
1798  * @param sd Gesture Layer Widget Data.
1799  * @param pe The recent input event as stored in pe struct.
1800  * @param event_info Original input event pointer.
1801  * @param event_type Type of original input event.
1802  * @param gesture what gesture is tested
1803  * @param how many taps for this gesture (1, 2 or 3)
1804  *
1805  * @ingroup Elm_Gesture_Layer
1806  */
1807 static void
1808 _tap_gesture_test(Evas_Object *obj,
1809                   Pointer_Event *pe,
1810                   void *event_info,
1811                   Evas_Callback_Type event_type,
1812                   Elm_Gesture_Type g_type)
1813 {
1814    int taps = 0;
1815    Taps_Type *st;
1816    Gesture_Info *gesture;
1817    Eina_List *pe_list = NULL;
1818    Pointer_Event *pe_last = NULL;
1819    Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
1820
1821    /* Here we fill Tap struct */
1822    ELM_GESTURE_LAYER_DATA_GET(obj, sd);
1823
1824    if (!pe)
1825      return;
1826
1827    gesture = sd->gesture[g_type];
1828    if (!gesture) return;
1829
1830    switch (g_type)
1831      {
1832       case ELM_GESTURE_N_TAPS:
1833          taps = 1;
1834          break;
1835
1836       case ELM_GESTURE_N_DOUBLE_TAPS:
1837          taps = 2;
1838          break;
1839
1840       case ELM_GESTURE_N_TRIPLE_TAPS:
1841          taps = 3;
1842          break;
1843
1844       default:
1845          taps = 0;
1846          break;
1847      }
1848
1849    st = gesture->data;
1850    if (!st) /* Allocated once on first time */
1851      {
1852         st = calloc(1, sizeof(Taps_Type));
1853         gesture->data = st;
1854         _tap_gestures_test_reset(gesture);
1855      }
1856
1857    switch (pe->event_type)
1858      {
1859       case EVAS_CALLBACK_MULTI_DOWN:
1860       case EVAS_CALLBACK_MOUSE_DOWN:
1861          /* Each device taps (DOWN, UP event) registered in same list    */
1862          /* Find list for this device or start a new list if not found   */
1863          pe_list = eina_list_search_unsorted(st->l, _pe_device_compare, pe);
1864          if (pe_list)
1865            {  /* This device touched before, verify that this tap is on  */
1866               /* top of a previous tap (including a tap of other device) */
1867               if (!_match_fingers_compare(st->l, pe, sd->tap_finger_size))
1868                 {  /* New DOWN event is not on top of any prev touch     */
1869                    ev_flag = _state_set(gesture, ELM_GESTURE_STATE_ABORT,
1870                          &st->info, EINA_FALSE);
1871                    _event_consume(sd, event_info, event_type, ev_flag);
1872
1873                    return;
1874                 }
1875            }
1876
1877          /* All tests are good, register this tap in device list */
1878          pe_list = _pointer_event_record
1879             (st, pe_list, pe, sd, event_info, event_type);
1880
1881          if (!sd->gest_taps_timeout)
1882            {
1883               if (sd->double_tap_timeout > 0.0)
1884                 {
1885                    sd->gest_taps_timeout =
1886                       ecore_timer_add(sd->double_tap_timeout,
1887                             _multi_tap_timeout, gesture->obj);
1888                 }
1889            }
1890          else  /* We re-allocate gest_taps_timeout between taps */
1891            ecore_timer_reset(sd->gest_taps_timeout);
1892
1893          if ((pe->device == 0) && (eina_list_count(pe_list) == 1))
1894            {  /* This is the first mouse down we got */
1895               ev_flag = _state_set(gesture, ELM_GESTURE_STATE_START,
1896                     &st->info, EINA_FALSE);
1897               _event_consume(sd, event_info, event_type, ev_flag);
1898
1899               st->n_taps_needed = taps * 2;  /* count DOWN and UP */
1900
1901               return;
1902            }
1903          else if (eina_list_count(pe_list) > st->n_taps_needed)
1904            {  /* If we arleady got too many touches for this gesture. */
1905               ev_flag = _state_set(gesture, ELM_GESTURE_STATE_ABORT,
1906                     &st->info, EINA_FALSE);
1907            }
1908
1909          if (gesture->state == ELM_GESTURE_STATE_MOVE)
1910            {  /* Report MOVE if all devices have same DOWN/UP count */
1911               /* Should be in MOVE state from last UP event */
1912               Eina_List *l;
1913               Eina_Bool move = EINA_TRUE;
1914               unsigned int n = 0;
1915
1916               EINA_LIST_FOREACH(st->l, l, pe_list)
1917                 {
1918                    if (n == 0)
1919                      {
1920                         n = eina_list_count(pe_list);
1921                      }
1922                    else if (n != eina_list_count(pe_list))
1923                      {
1924                         move = EINA_FALSE;
1925                      }
1926                 }
1927
1928               if (move && (n > 0))
1929                 {
1930                    ev_flag = _state_set(gesture, ELM_GESTURE_STATE_MOVE,
1931                          &st->info, EINA_TRUE);
1932                 }
1933            }
1934
1935          break;
1936
1937       case EVAS_CALLBACK_MULTI_UP:
1938       case EVAS_CALLBACK_MOUSE_UP:
1939          pe_list = eina_list_search_unsorted(st->l, _pe_device_compare, pe);
1940          if (!pe_list) return;
1941
1942          _pointer_event_record(st, pe_list, pe, sd, event_info, event_type);
1943
1944          if (((gesture->g_type == ELM_GESTURE_N_TAPS) &&
1945                   !IS_TESTED(ELM_GESTURE_N_DOUBLE_TAPS) &&
1946                   !IS_TESTED(ELM_GESTURE_N_TRIPLE_TAPS)) ||
1947                ((gesture->g_type == ELM_GESTURE_N_DOUBLE_TAPS) &&
1948                 !IS_TESTED(ELM_GESTURE_N_TRIPLE_TAPS)))
1949            {  /* Test for finish immidiatly, not waiting for timeout */
1950               if (_tap_gesture_check_finish(gesture, sd->tap_finger_size))
1951                 {
1952                    _tap_gesture_finish(gesture, sd->tap_finger_size);
1953                    return;
1954                 }
1955            }
1956
1957          if ((gesture->state == ELM_GESTURE_STATE_START) ||
1958                (gesture->state == ELM_GESTURE_STATE_MOVE))
1959            {  /* Tap gesture started, no finger on surface. Report MOVE */
1960               Eina_List *l;
1961               Eina_Bool move = EINA_TRUE;
1962               unsigned int n = 0;
1963
1964               /* Report move only if all devices have same DOWN/UP count */
1965               EINA_LIST_FOREACH(st->l, l, pe_list)
1966                 {
1967                    if (n == 0)
1968                      {
1969                         n = eina_list_count(pe_list);
1970                      }
1971                    else if (n != eina_list_count(pe_list))
1972                      {
1973                         move = EINA_FALSE;
1974                      }
1975                 }
1976
1977               if ((move && (n > 0)) && (n < st->n_taps_needed))
1978                 {  /* Set number of fingers and report MOVE */
1979                    /* We don't report MOVE when (n >= st->n_taps_needed)
1980                       because will be END or ABORT at this stage */
1981                    st->info.n = eina_list_count(st->l);
1982                    ev_flag = _state_set(gesture, ELM_GESTURE_STATE_MOVE,
1983                          &st->info, EINA_TRUE);
1984                 }
1985            }
1986
1987          break;
1988
1989       case EVAS_CALLBACK_MULTI_MOVE:
1990       case EVAS_CALLBACK_MOUSE_MOVE:
1991          /* Verify that user didn't move out of tap area before next tap */
1992          /* BUT: we need to skip some MOVE events coming before DOWN     */
1993          /* when user taps next tap. So fetch LAST recorded event for    */
1994          /* device (DOWN or UP event), ignore all MOVEs if last was UP   */
1995          pe_last = eina_list_data_get(eina_list_last(
1996                   eina_list_search_unsorted(st->l, _pe_device_compare, pe)));
1997
1998          if (pe_last)
1999            {  /* pe_last is the last event recorded for this device */
2000               if ((pe_last->event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
2001                     (pe_last->event_type == EVAS_CALLBACK_MULTI_DOWN))
2002                 {  /* Test only MOVE events that come after DOWN event */
2003                    if (!_inside(pe_last->x, pe_last->y, pe->x, pe->y,
2004                             sd->tap_finger_size))
2005                      {
2006                         ev_flag = _state_set(gesture, ELM_GESTURE_STATE_ABORT,
2007                               &st->info, EINA_FALSE);
2008                         _event_consume(sd, event_info, event_type, ev_flag);
2009                      }
2010                 }
2011            }
2012          break;
2013
2014       default:
2015          return;
2016      }
2017 }
2018
2019 /**
2020  * @internal
2021  *
2022  * This function computes center-point for  long-tap gesture
2023  *
2024  * @param st Long Tap gesture info pointer
2025  * @param pe The recent input event as stored in pe struct.
2026  *
2027  * @ingroup Elm_Gesture_Layer
2028  */
2029 static void
2030 _compute_taps_center(Long_Tap_Type *st,
2031                      Evas_Coord *x_out,
2032                      Evas_Coord *y_out,
2033                      Pointer_Event *pe)
2034 {
2035    Eina_List *l;
2036    Pointer_Event *p;
2037    Evas_Coord x = 0, y = 0;
2038
2039    if (!eina_list_count(st->touched))
2040      return;
2041
2042    EINA_LIST_FOREACH(st->touched, l, p)
2043      {  /* Accumulate all then take avarage */
2044        if (p->device == pe->device) /* This will take care of values
2045                                      * coming from MOVE event */
2046          {
2047             x += pe->x;
2048             y += pe->y;
2049          }
2050        else
2051          {
2052             x += p->x;
2053             y += p->y;
2054          }
2055      }
2056
2057    *x_out = x / eina_list_count(st->touched);
2058    *y_out = y / eina_list_count(st->touched);
2059 }
2060
2061 /**
2062  * @internal
2063  *
2064  * This function checks N long-tap gesture.
2065  *
2066  * @param obj The gesture-layer object.
2067  * @param pe The recent input event as stored in pe struct.
2068  * @param event_info Original input event pointer.
2069  * @param event_type Type of original input event.
2070  * @param g_type what Gesture we are testing.
2071  * @param taps How many click/taps we test for.
2072  *
2073  * @ingroup Elm_Gesture_Layer
2074  */
2075 static void
2076 _n_long_tap_test(Evas_Object *obj,
2077                  Pointer_Event *pe,
2078                  void *event_info,
2079                  Evas_Callback_Type event_type,
2080                  Elm_Gesture_Type g_type)
2081 {
2082    Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
2083    Gesture_Info *gesture;
2084    Long_Tap_Type *st;
2085
2086    /* Here we fill Recent_Taps struct and fire-up click/tap timers */
2087    ELM_GESTURE_LAYER_DATA_GET(obj, sd);
2088
2089    if (!pe) /* this happens when unhandled event arrived */
2090      return;  /* see _make_pointer_event function */
2091
2092    gesture = sd->gesture[g_type];
2093    if (!gesture) return;
2094
2095    st = gesture->data;
2096    if (!st) /* Allocated once on first time */
2097      {
2098         st = calloc(1, sizeof(Long_Tap_Type));
2099         gesture->data = st;
2100         _n_long_tap_test_reset(gesture);
2101      }
2102
2103    switch (pe->event_type)
2104      {
2105       case EVAS_CALLBACK_MULTI_DOWN:
2106       case EVAS_CALLBACK_MOUSE_DOWN:
2107         st->touched = _touched_device_add(st->touched, pe);
2108         st->info.n = eina_list_count(st->touched);
2109
2110         _event_consume(sd, event_info, event_type, ev_flag);
2111         _compute_taps_center(st, &st->info.x, &st->info.y, pe);
2112         st->center_x = st->info.x;  /* Update coords for */
2113         st->center_y = st->info.y;  /* reporting START  */
2114
2115         /* This is the first mouse down we got */
2116         if (eina_list_count(st->touched) == 1)
2117           {
2118              _state_set(gesture, ELM_GESTURE_STATE_START,
2119                    gesture->data, EINA_FALSE);
2120              st->info.timestamp = pe->timestamp;
2121
2122              /* To test long tap */
2123              /* When this timer expires, gesture STARTED */
2124              if ((!st->timeout) && (sd->long_tap_start_timeout > 0.0))
2125                st->timeout = ecore_timer_add(sd->long_tap_start_timeout,
2126                                              _long_tap_timeout, gesture);
2127           }
2128         else
2129           {
2130              if (st->timeout)
2131                 ecore_timer_reset(st->timeout);
2132           }
2133
2134         break;
2135
2136       case EVAS_CALLBACK_MULTI_UP:
2137       case EVAS_CALLBACK_MOUSE_UP:
2138         st->touched = _touched_device_remove(st->touched, pe);
2139         _compute_taps_center(st, &st->center_x, &st->center_y, pe);
2140         if (st->info.n)
2141           {
2142              if (gesture->state == ELM_GESTURE_STATE_MOVE)
2143                ev_flag = _state_set(gesture, ELM_GESTURE_STATE_END,
2144                                     &st->info, EINA_FALSE);
2145              else
2146                ev_flag = _state_set(gesture, ELM_GESTURE_STATE_ABORT,
2147                                     &st->info, EINA_FALSE);
2148
2149              ELM_SAFE_FREE(st->timeout, ecore_timer_del);
2150              _event_consume(sd, event_info, event_type, ev_flag);
2151           }
2152
2153         break;
2154
2155       case EVAS_CALLBACK_MULTI_MOVE:
2156       case EVAS_CALLBACK_MOUSE_MOVE:
2157         if (st->info.n &&
2158             ((gesture->state == ELM_GESTURE_STATE_START) ||
2159              /* Report MOVE only if STARTED */
2160              (gesture->state == ELM_GESTURE_STATE_MOVE)))
2161           {
2162              Evas_Coord x = 0;
2163              Evas_Coord y = 0;
2164
2165              _compute_taps_center(st, &x, &y, pe);
2166              /* ABORT if user moved fingers out of tap area */
2167              if (!_inside(x, y, st->center_x, st->center_y,
2168                       sd->tap_finger_size))
2169                {
2170                   ELM_SAFE_FREE(st->timeout, ecore_timer_del);
2171
2172                   /* Report MOVE if gesture started */
2173                   ev_flag = _state_set(gesture, ELM_GESTURE_STATE_ABORT,
2174                         &st->info, EINA_FALSE);
2175                }
2176
2177              _event_consume(sd, event_info, event_type, ev_flag);
2178           }
2179         break;
2180
2181       default:
2182         return;
2183      }
2184 }
2185
2186 /**
2187  * @internal
2188  *
2189  * This function computes momentum for MOMENTUM, LINE and FLICK gestures
2190  * This momentum value will be sent to widget when gesture is completed.
2191  *
2192  * @param momentum pointer to buffer where we record momentum value.
2193  * @param x1 x coord where user started gesture.
2194  * @param y1 y coord where user started gesture.
2195  * @param x2 x coord where user completed gesture.
2196  * @param y2 y coord where user completed gesture.
2197  * @param t1x timestamp for X, when user started gesture.
2198  * @param t1y timestamp for Y, when user started gesture.
2199  * @param t2  timestamp when user completed gesture.
2200  *
2201  * @ingroup Elm_Gesture_Layer
2202  */
2203 static void
2204 _momentum_set(Elm_Gesture_Momentum_Info *momentum,
2205               Evas_Coord xx1,
2206               Evas_Coord yy1,
2207               Evas_Coord xx2,
2208               Evas_Coord yy2,
2209               unsigned int t1x,
2210               unsigned int t1y,
2211               unsigned int t2)
2212 {
2213    Evas_Coord velx = 0, vely = 0, vel;
2214    Evas_Coord dx = xx2 - xx1;
2215    Evas_Coord dy = yy2 - yy1;
2216    int dtx = t2 - t1x;
2217    int dty = t2 - t1y;
2218
2219    if (dtx > 0)
2220      velx = (dx * 1000) / dtx;
2221
2222    if (dty > 0)
2223      vely = (dy * 1000) / dty;
2224
2225    vel = sqrt((velx * velx) + (vely * vely));
2226
2227    if ((_elm_config->thumbscroll_friction > 0.0) &&
2228        (vel > _elm_config->thumbscroll_momentum_threshold)) /* report
2229                                                              * momentum */
2230      {
2231         momentum->mx = velx;
2232         momentum->my = vely;
2233      }
2234    else
2235      {
2236         momentum->mx = 0;
2237         momentum->my = 0;
2238      }
2239 }
2240
2241 /**
2242  * @internal
2243  *
2244  * This function is used for computing rotation angle (DEG).
2245  *
2246  * @param x1 first finger x location.
2247  * @param y1 first finger y location.
2248  * @param x2 second finger x location.
2249  * @param y2 second finger y location.
2250  *
2251  * @return angle of the line between (x1,y1), (x2,y2) in Deg.
2252  * Angles now are given in DEG, not RAD.
2253  * ZERO angle at 12-oclock, growing clockwise.
2254  *
2255  * @ingroup Elm_Gesture_Layer
2256  */
2257 static double
2258 _angle_get(Evas_Coord xx1,
2259            Evas_Coord yy1,
2260            Evas_Coord xx2,
2261            Evas_Coord yy2)
2262 {
2263    double a, xx, yy, rt = (-1);
2264
2265    xx = fabs(xx2 - xx1);
2266    yy = fabs(yy2 - yy1);
2267
2268    if (((int)xx) && ((int)yy))
2269      {
2270         rt = a = RAD2DEG(atan(yy / xx));
2271         if (xx1 < xx2)
2272           {
2273              if (yy1 < yy2) rt = 360 - a;
2274              else rt = a;
2275           }
2276         else
2277           {
2278              if (yy1 < yy2) rt = 180 + a;
2279              else rt = 180 - a;
2280           }
2281      }
2282
2283    if (rt < 0) /* Do this only if rt is not set */
2284      {
2285         if (((int)xx)) /* Horizontal line */
2286           {
2287              if (xx2 < xx1) rt = 180;
2288              else rt = 0.0;
2289           }
2290         else
2291           {  /* Vertical line */
2292             if (yy2 < yy1) rt = 90;
2293             else rt = 270;
2294           }
2295      }
2296
2297    /* Now we want to change from:
2298     *                      90                   0
2299     * original circle   180   0   We want:  270   90
2300     *                     270                 180
2301     */
2302    rt = 450 - rt;
2303    if (rt >= 360) rt -= 360;
2304
2305    return rt;
2306 }
2307
2308 /**
2309  * @internal
2310  *
2311  * This function is used for computing the magnitude and direction
2312  * of vector between two points.
2313  *
2314  * @param x1 first finger x location.
2315  * @param y1 first finger y location.
2316  * @param x2 second finger x location.
2317  * @param y2 second finger y location.
2318  * @param l length computed (output)
2319  * @param a angle computed (output)
2320  *
2321  * @ingroup Elm_Gesture_Layer
2322  */
2323 static void
2324 _vector_get(Evas_Coord xx1,
2325             Evas_Coord yy1,
2326             Evas_Coord xx2,
2327             Evas_Coord yy2,
2328             Evas_Coord *l,
2329             double *a)
2330 {
2331    Evas_Coord xx, yy;
2332
2333    xx = xx2 - xx1;
2334    yy = yy2 - yy1;
2335    *l = (Evas_Coord)sqrt((xx * xx) + (yy * yy));
2336    *a = _angle_get(xx1, yy1, xx2, yy2);
2337 }
2338
2339 static int
2340 _direction_get(Evas_Coord xx1,
2341                Evas_Coord xx2)
2342 {
2343    if (xx2 < xx1) return -1;
2344    if (xx2 > xx1) return 1;
2345
2346    return 0;
2347 }
2348
2349 /**
2350  * @internal
2351  *
2352  * This function tests momentum gesture.
2353  * @param obj The gesture-layer object.
2354  * @param pe The recent input event as stored in pe struct.
2355  * @param event_info recent input event.
2356  * @param event_type recent event type.
2357  * @param g_type what Gesture we are testing.
2358  *
2359  * @ingroup Elm_Gesture_Layer
2360  */
2361 static void
2362 _momentum_test(Evas_Object *obj,
2363                Pointer_Event *pe,
2364                void *event_info,
2365                Evas_Callback_Type event_type,
2366                Elm_Gesture_Type g_type)
2367 {
2368    Eina_List *l;
2369    Pointer_Event *p;
2370    Momentum_Type *st;
2371    Gesture_Info *gesture;
2372    Pointer_Event pe_local;
2373    Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
2374    Elm_Gesture_State state_to_report = ELM_GESTURE_STATE_MOVE;
2375    unsigned int cnt = 1; /* We start counter counting current pe event */
2376
2377    ELM_GESTURE_LAYER_DATA_GET(obj, sd);
2378
2379    gesture = sd->gesture[g_type];
2380    if (!gesture) return;
2381
2382    /* When continues enable = TRUE a gesture may START on MOVE event */
2383    /* We don't allow this to happen with the if-statement below.     */
2384    /* When continues enable = FALSE a gesture may START on DOWN only */
2385    /* Therefor it would NOT start on MOVE event.                     */
2386    /* NOTE that touched list is updated AFTER this function returns  */
2387    /* so (count == 0) when we get here on first touch on surface.    */
2388    if ((sd->glayer_continues_enable) && (!eina_list_count(sd->touched)))
2389      return;  /* Got move on mouse-over move */
2390
2391    st = gesture->data;
2392    if (!st) /* Allocated once on first time */
2393      {
2394         st = calloc(1, sizeof(Momentum_Type));
2395         gesture->data = st;
2396         _momentum_test_reset(gesture);
2397      }
2398
2399    if (!pe)
2400      return;
2401
2402    /* First make avarage of all touched devices to determine center point */
2403    pe_local = *pe; /* Copy pe event info to local */
2404    EINA_LIST_FOREACH(sd->touched, l, p)
2405      if (p->device != pe_local.device)
2406        {
2407           pe_local.x += p->x;
2408           pe_local.y += p->y;
2409           cnt++;
2410        }
2411
2412    /* Compute avarage to get center point */
2413    pe_local.x /= cnt;
2414    pe_local.y /= cnt;
2415
2416    /* If user added finger - reset gesture */
2417    if ((st->info.n) && (st->info.n < cnt))
2418      state_to_report = ELM_GESTURE_STATE_ABORT;
2419
2420    if (st->info.n < cnt)
2421      st->info.n = cnt;
2422
2423    switch (event_type)
2424      {
2425       case EVAS_CALLBACK_MOUSE_DOWN:
2426       case EVAS_CALLBACK_MULTI_DOWN:
2427       case EVAS_CALLBACK_MOUSE_MOVE:
2428       case EVAS_CALLBACK_MULTI_MOVE:
2429         if (!st->t_st_x)
2430           {
2431              if ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
2432                  (event_type == EVAS_CALLBACK_MULTI_DOWN) ||
2433                  (sd->glayer_continues_enable))    /* start also on MOVE */
2434                {   /* We start on MOVE when cont-enabled only */
2435                  st->line_st.x = st->line_end.x = pe_local.x;
2436                  st->line_st.y = st->line_end.y = pe_local.y;
2437                  st->t_st_x = st->t_st_y = st->t_end = pe_local.timestamp;
2438                  st->xdir = st->ydir = 0;
2439                  st->info.x2 = st->info.x1 = pe_local.x;
2440                  st->info.y2 = st->info.y1 = pe_local.y;
2441                  st->info.tx = st->info.ty = pe_local.timestamp;
2442                  ev_flag = _state_set(gesture, ELM_GESTURE_STATE_START,
2443                                       &st->info, EINA_FALSE);
2444                  _event_consume(sd, event_info, event_type, ev_flag);
2445                }
2446
2447              return;
2448           }
2449
2450         if (st->t_up)
2451           {
2452              Eina_Bool force = EINA_TRUE;   /* for move state */
2453
2454              /* ABORT if got DOWN or MOVE event after UP+timeout */
2455              if ((st->t_up + ELM_GESTURE_MULTI_TIMEOUT) < pe_local.timestamp)
2456                {
2457                   state_to_report = ELM_GESTURE_STATE_ABORT;
2458                   force = EINA_FALSE;
2459                }
2460
2461              /* We report state but don't compute momentum now */
2462              ev_flag = _state_set(gesture, state_to_report, &st->info,
2463                                   force);
2464              _event_consume(sd, event_info, event_type, ev_flag);
2465              return;  /* Stop computing when user remove finger */
2466           }
2467
2468         /*  Too long of a wait, reset all values */
2469         if ((pe_local.timestamp - ELM_GESTURE_MOMENTUM_TIMEOUT) > st->t_end)
2470           {
2471              st->line_st.x = pe_local.x;
2472              st->line_st.y = pe_local.y;
2473              st->t_st_y = st->t_st_x = pe_local.timestamp;
2474              st->info.tx = st->t_st_x;
2475              st->info.ty = st->t_st_y;
2476              st->xdir = st->ydir = 0;
2477           }
2478         else
2479           {
2480              int xdir, ydir;
2481
2482              xdir = _direction_get(st->line_end.x, pe_local.x);
2483              ydir = _direction_get(st->line_end.y, pe_local.y);
2484              if (xdir && (xdir != st->xdir))
2485                {
2486                   st->line_st.x = st->line_end.x;
2487                   st->info.tx = st->t_st_x = st->t_end;
2488                   st->xdir = xdir;
2489                }
2490
2491              if (ydir && (ydir != st->ydir))
2492                {
2493                   st->line_st.y = st->line_end.y;
2494                   st->info.ty = st->t_st_y = st->t_end;
2495                   st->ydir = ydir;
2496                }
2497           }
2498
2499         st->info.x2 = st->line_end.x = pe_local.x;
2500         st->info.y2 = st->line_end.y = pe_local.y;
2501         st->t_end = pe_local.timestamp;
2502         _momentum_set(&st->info, st->line_st.x, st->line_st.y,
2503                       pe_local.x, pe_local.y, st->t_st_x, st->t_st_y,
2504                       pe_local.timestamp);
2505
2506         ev_flag = _state_set(gesture, state_to_report, &st->info,
2507                              EINA_TRUE);
2508         _event_consume(sd, event_info, event_type, ev_flag);
2509         break;
2510
2511       case EVAS_CALLBACK_MOUSE_UP:
2512       case EVAS_CALLBACK_MULTI_UP:
2513         st->t_up = pe_local.timestamp; /* Record recent up event time */
2514         if ((cnt > 1) || /* Ignore if more fingers touch surface        */
2515             (!st->t_st_x)) /* IGNORE if info was cleared, long press,move */
2516           return;
2517
2518         /* Too long of a wait, reset all values */
2519         if ((pe_local.timestamp - ELM_GESTURE_MOMENTUM_TIMEOUT) > st->t_end)
2520           {
2521              st->line_st.x = pe_local.x;
2522              st->line_st.y = pe_local.y;
2523              st->t_st_y = st->t_st_x = pe_local.timestamp;
2524              st->xdir = st->ydir = 0;
2525           }
2526
2527         st->info.x2 = pe_local.x;
2528         st->info.y2 = pe_local.y;
2529         st->line_end.x = pe_local.x;
2530         st->line_end.y = pe_local.y;
2531         st->t_end = pe_local.timestamp;
2532
2533         if ((fabs(st->info.mx) > ELM_GESTURE_MINIMUM_MOMENTUM) ||
2534             (fabs(st->info.my) > ELM_GESTURE_MINIMUM_MOMENTUM))
2535           state_to_report = ELM_GESTURE_STATE_END;
2536         else
2537           state_to_report = ELM_GESTURE_STATE_ABORT;
2538
2539         ev_flag = _state_set(gesture, state_to_report, &st->info,
2540                              EINA_FALSE);
2541         _event_consume(sd, event_info, event_type, ev_flag);
2542         return;
2543
2544       default:
2545         return;
2546      }
2547 }
2548
2549 static int
2550 _line_device_compare(const void *data1,
2551                      const void *data2)
2552 {
2553    /* Compare device component of line struct */
2554    const Line_Data *ln1 = data1;
2555    const int *device = data2;
2556
2557    if (ln1->t_st) /* Compare only with lines that started */
2558      return ln1->device - (*device);
2559
2560    return -1;
2561 }
2562
2563 /**
2564  * @internal
2565  *
2566  * This function construct line struct from input.
2567  * @param info pointer to store line momentum.
2568  * @param st line info to store input data.
2569  * @param pe The recent input event as stored in pe struct.
2570  *
2571  * @ingroup Elm_Gesture_Layer
2572  */
2573 static Eina_Bool
2574 _single_line_process(Elm_Gesture_Line_Info *info,
2575                      Line_Data *st,
2576                      Pointer_Event *pe,
2577                      Evas_Callback_Type event_type)
2578 {
2579    /* Record events and set momentum for line pointed by st */
2580    if (!pe)
2581      return EINA_FALSE;
2582
2583    switch (event_type)
2584      {
2585       case EVAS_CALLBACK_MOUSE_DOWN:
2586       case EVAS_CALLBACK_MOUSE_MOVE:
2587       case EVAS_CALLBACK_MULTI_DOWN:
2588       case EVAS_CALLBACK_MULTI_MOVE:
2589         if (!st->t_st) /* This happens only when line starts */
2590           {
2591              st->line_st.x = pe->x;
2592              st->line_st.y = pe->y;
2593              st->t_st = pe->timestamp;
2594              st->device = pe->device;
2595              info->momentum.x1 = pe->x;
2596              info->momentum.y1 = pe->y;
2597              info->momentum.tx = pe->timestamp;
2598              info->momentum.ty = pe->timestamp;
2599
2600              return EINA_TRUE;
2601           }
2602
2603         break;
2604
2605       case EVAS_CALLBACK_MOUSE_UP:
2606       case EVAS_CALLBACK_MULTI_UP:
2607         /* IGNORE if line info was cleared, like long press, move */
2608         if (!st->t_st)
2609           return EINA_FALSE;
2610
2611         st->line_end.x = pe->x;
2612         st->line_end.y = pe->y;
2613         st->t_end = pe->timestamp;
2614         break;
2615
2616       default:
2617         return EINA_FALSE;
2618      }
2619
2620    if (!st->t_st)
2621      {
2622         _line_data_reset(st);
2623         return EINA_FALSE;
2624      }
2625
2626    info->momentum.x2 = pe->x;
2627    info->momentum.y2 = pe->y;
2628    _momentum_set(&info->momentum, st->line_st.x, st->line_st.y, pe->x, pe->y,
2629                  st->t_st, st->t_st, pe->timestamp);
2630
2631    return EINA_TRUE;
2632 }
2633
2634 /**
2635  * @internal
2636  *
2637  * This function test for (n) line gesture.
2638  * @param obj The gesture-layer object.
2639  * @param pe The recent input event as stored in pe struct.
2640  * @param event_info Original input event pointer.
2641  * @param event_type Type of original input event.
2642  * @param g_type what Gesture we are testing.
2643  *
2644  * @ingroup Elm_Gesture_Layer
2645  */
2646 static void
2647 _n_line_test(Evas_Object *obj,
2648              Pointer_Event *pe,
2649              void *event_info,
2650              Evas_Callback_Type event_type,
2651              Elm_Gesture_Type g_type)
2652 {
2653    unsigned cnt;
2654    Line_Type *st;
2655    Eina_List *list;
2656    Gesture_Info *gesture;
2657    Line_Data *line = NULL;
2658
2659    if (!pe)
2660      return;
2661
2662    ELM_GESTURE_LAYER_DATA_GET(obj, sd);
2663
2664    gesture = sd->gesture[g_type];
2665    if (!gesture ) return;
2666
2667    /* When continues enable = TRUE a gesture may START on MOVE event */
2668    /* We don't allow this to happen with the if-statement below.     */
2669    /* When continues enable = FALSE a gesture may START on DOWN only */
2670    /* Therefor it would NOT start on MOVE event.                     */
2671    /* NOTE that touched list is updated AFTER this function returns  */
2672    /* so (count == 0) when we get here on first touch on surface.    */
2673    if ((sd->glayer_continues_enable) && (!eina_list_count(sd->touched)))
2674      return;  /* Got move on mouse-over move */
2675
2676    st = gesture->data;
2677    if (!st)
2678      {
2679         st = calloc(1, sizeof(Line_Type));
2680         gesture->data = st;
2681      }
2682
2683    list = st->list;
2684    cnt = eina_list_count(list);
2685
2686    if (cnt) /* list is not empty, locate this device on list */
2687      {
2688         line = (Line_Data *)eina_list_search_unsorted
2689             (st->list, _line_device_compare, &pe->device);
2690      }
2691
2692    if (!line) /* List is empty or device not found, new line-struct on
2693                * START only */
2694      {
2695         if ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
2696             (event_type == EVAS_CALLBACK_MULTI_DOWN) ||
2697             ((sd->glayer_continues_enable) &&   /* START on MOVE also */
2698              ((event_type == EVAS_CALLBACK_MOUSE_MOVE) ||
2699               /* Allocate new item on START only */
2700               (event_type == EVAS_CALLBACK_MULTI_MOVE))))
2701           {
2702              line = calloc(1, sizeof(Line_Data));
2703              _line_data_reset(line);
2704              list = eina_list_append(list, line);
2705              st->list = list;
2706           }
2707      }
2708
2709    if (!line) /* This may happen on MOVE that comes before DOWN      */
2710      return;  /* No line-struct to work with, can't continue testing */
2711
2712    /* update st with input */
2713    if (_single_line_process(&st->info, line, pe, event_type))
2714      _event_consume(sd, event_info, event_type, EVAS_EVENT_FLAG_NONE);
2715
2716    /* Get direction and magnitude of the line */
2717    double angle;
2718    _vector_get(line->line_st.x, line->line_st.y, pe->x, pe->y,
2719                &line->line_length, &angle);
2720
2721    /* These are used later to compare lines length */
2722    Evas_Coord shortest_line_len = line->line_length;
2723    Evas_Coord longest_line_len = line->line_length;
2724    Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
2725
2726    /* Now update line-state */
2727    if (line->t_st) /* Analyze line only if line started */
2728      {
2729         if (line->line_angle >= 0.0) /* if line direction was set, we
2730                                       * test if broke tolerance */
2731           {
2732              double a = fabs(angle - line->line_angle);
2733              /* Distance from line */
2734              double d = (tan(DEG2RAD(a))) * line->line_length;
2735              /* Broke tolerance: abort line and start a new one */
2736              if ((d > sd->line_distance_tolerance) ||
2737                  (a > sd->line_angular_tolerance))
2738                {
2739                   ev_flag = _state_set(gesture, ELM_GESTURE_STATE_ABORT,
2740                                        &st->info, EINA_FALSE);
2741                   _event_consume(sd, event_info, event_type, ev_flag);
2742                   return;
2743                }
2744
2745              /* We may finish line if momentum is zero */
2746              if (sd->glayer_continues_enable)
2747                {
2748                   /* This is for continues-gesture */
2749                   /* Finish line on zero momentum for continues gesture */
2750                   if ((!st->info.momentum.mx) && (!st->info.momentum.my))
2751                     {
2752                        line->line_end.x = pe->x;
2753                        line->line_end.y = pe->y;
2754                        line->t_end = pe->timestamp;
2755                     }
2756                }
2757           }
2758         else
2759           {  /* Record the line angle as it broke minimum length for line */
2760             if (line->line_length >= sd->line_min_length)
2761               st->info.angle = line->line_angle = angle;
2762           }
2763
2764         if (line->t_end)
2765           {
2766              if (line->line_angle < 0.0) /* it's not a line, too short
2767                                           * more close to a tap */
2768                {
2769                   ev_flag = _state_set(gesture, ELM_GESTURE_STATE_ABORT,
2770                                        &st->info, EINA_FALSE);
2771                   _event_consume(sd, event_info, event_type, ev_flag);
2772                   return;
2773                }
2774           }
2775      }
2776
2777    /* Count how many lines already started / ended */
2778    int started = 0;
2779    int ended = 0;
2780    unsigned int tm_start = pe->timestamp;
2781    unsigned int tm_end = pe->timestamp;
2782    Eina_List *l;
2783    Line_Data *t_line;
2784    double base_angle = ELM_GESTURE_NEGATIVE_ANGLE;
2785    Eina_Bool lines_parallel = EINA_TRUE;
2786    EINA_LIST_FOREACH(list, l, t_line)
2787      {
2788         if (base_angle < 0)
2789           base_angle = t_line->line_angle;
2790         else
2791           {
2792              if (t_line->line_angle >= 0) /* Compare angle only with
2793                                            * lines with direction
2794                                            * defined */
2795                {
2796                   if (fabs(base_angle - t_line->line_angle) >
2797                       sd->line_angular_tolerance)
2798                     lines_parallel = EINA_FALSE;
2799                }
2800           }
2801
2802         if (t_line->line_length) /* update only if this line is used */
2803           {
2804              if (shortest_line_len > t_line->line_length)
2805                shortest_line_len = t_line->line_length;
2806
2807              if (longest_line_len < t_line->line_length)
2808                longest_line_len = t_line->line_length;
2809           }
2810
2811         if (t_line->t_st)
2812           {
2813              started++;
2814              if (t_line->t_st < tm_start)
2815                tm_start = t_line->t_st;
2816           }
2817
2818         if (t_line->t_end)
2819           {
2820              ended++;
2821              if (t_line->t_end < tm_end)
2822                tm_end = t_line->t_end;
2823           }
2824      }
2825
2826    st->info.momentum.n = started;
2827
2828    if (ended &&
2829        ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
2830         /* user lift one finger then starts again without line-end - ABORT */
2831         (event_type == EVAS_CALLBACK_MULTI_DOWN)))
2832      {
2833         ev_flag = _state_set(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
2834                              EINA_FALSE);
2835         _event_consume(sd, event_info, event_type, ev_flag);
2836         return;
2837      }
2838
2839    if (!lines_parallel) /* Lines are NOT at same direction, abort this
2840                          * gesture */
2841      {
2842         ev_flag = _state_set(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
2843                              EINA_FALSE);
2844         _event_consume(sd, event_info, event_type, ev_flag);
2845         return;
2846      }
2847
2848    /* We report ABORT if lines length are NOT matching when fingers are up */
2849    if ((longest_line_len - shortest_line_len) >
2850        (elm_config_finger_size_get() * 2))
2851      {
2852         ev_flag = _state_set(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
2853                              EINA_FALSE);
2854         _event_consume(sd, event_info, event_type, ev_flag);
2855         return;
2856      }
2857
2858    /* We consider FLICK as a fast line.ABORT if take too long to finish */
2859    if ((g_type == ELM_GESTURE_N_FLICKS) && ((tm_end - tm_start) >
2860                                             sd->flick_time_limit_ms))
2861      {
2862         ev_flag = _state_set(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
2863                              EINA_FALSE);
2864         _event_consume(sd, event_info, event_type, ev_flag);
2865         return;
2866      }
2867
2868    switch (event_type)
2869      {
2870       case EVAS_CALLBACK_MOUSE_UP:
2871       case EVAS_CALLBACK_MULTI_UP:
2872         if ((started) && (started == ended))
2873           {
2874              ev_flag = _state_set(gesture, ELM_GESTURE_STATE_END,
2875                                   &st->info, EINA_FALSE);
2876              _event_consume(sd, event_info, event_type, ev_flag);
2877           }
2878
2879         return;
2880
2881       case EVAS_CALLBACK_MOUSE_DOWN:
2882       case EVAS_CALLBACK_MULTI_DOWN:
2883       case EVAS_CALLBACK_MOUSE_MOVE:
2884       case EVAS_CALLBACK_MULTI_MOVE:
2885         if (started)
2886           {
2887              /* For continues gesture */
2888              if (sd->glayer_continues_enable && (started == ended))
2889                {
2890                   ev_flag = _state_set(gesture, ELM_GESTURE_STATE_END,
2891                                        &st->info, EINA_FALSE);
2892                   _event_consume(sd, event_info, event_type, ev_flag);
2893                }
2894              else
2895                {   /* When continues, may START on MOVE event too */
2896                  Elm_Gesture_State s = ELM_GESTURE_STATE_MOVE;
2897
2898                  /* This happens when: on n > 1 lines then one finger up */
2899                  /* caused abort, then put finger down.                  */
2900                  /* This will stop line from starting again.             */
2901                  /* Number of lines, MUST match touched-device in list   */
2902                  if ((!sd->glayer_continues_enable) &&
2903                      (eina_list_count(st->list) <
2904                       eina_list_count(sd->touched)))
2905                    s = ELM_GESTURE_STATE_ABORT;
2906
2907                  if (gesture->state == ELM_GESTURE_STATE_UNDEFINED)
2908                    s = ELM_GESTURE_STATE_START;
2909
2910                  ev_flag = _state_set(gesture, s, &st->info, EINA_TRUE);
2911                  _event_consume(sd, event_info, event_type, ev_flag);
2912                }
2913           }
2914         break;
2915
2916       default:
2917         return;   /* Unhandeld event type */
2918      }
2919 }
2920
2921 /**
2922  * @internal
2923  *
2924  * This function is used to check if rotation gesture started.
2925  * @param st Contains current rotation values from user input.
2926  * @return TRUE/FALSE if we need to set rotation START.
2927  *
2928  * @ingroup Elm_Gesture_Layer
2929  */
2930 static Eina_Bool
2931 _on_rotation_broke_tolerance(Rotate_Type *st)
2932 {
2933    if (st->info.base_angle < 0)
2934      return EINA_FALSE;  /* Angle has to be computed first */
2935
2936    if (st->rotate_angular_tolerance < 0)
2937      return EINA_TRUE;
2938
2939    double low = st->info.base_angle - st->rotate_angular_tolerance;
2940    double high = st->info.base_angle + st->rotate_angular_tolerance;
2941    double t = st->info.angle;
2942
2943    if (low < 0)
2944      {
2945         low += 180;
2946         high += 180;
2947
2948         if (t < 180)
2949           t += 180;
2950         else
2951           t -= 180;
2952      }
2953
2954    if (high > 360)
2955      {
2956         low -= 180;
2957         high -= 180;
2958
2959         if (t < 180)
2960           t += 180;
2961         else
2962           t -= 180;
2963      }
2964
2965    if ((t < low) || (t > high)) /* This marks that roation action has
2966                                  * started */
2967      {
2968         st->rotate_angular_tolerance = ELM_GESTURE_NEGATIVE_ANGLE;
2969         st->info.base_angle = st->info.angle; /* Avoid jump in angle value */
2970         return EINA_TRUE;
2971      }
2972
2973    return EINA_FALSE;
2974 }
2975
2976 /**
2977  * @internal
2978  *
2979  * This function is used for computing the gap between fingers.
2980  * It returns the length and center point between fingers.
2981  *
2982  * @param x1 first finger x location.
2983  * @param y1 first finger y location.
2984  * @param x2 second finger x location.
2985  * @param y2 second finger y location.
2986  * @param x  Get center point x cord (output)
2987  * @param y  Get center point y cord (output)
2988  *
2989  * @return length of the line between (x1,y1), (x2,y2) in pixels.
2990  *
2991  * @ingroup Elm_Gesture_Layer
2992  */
2993 static Evas_Coord
2994 _finger_gap_length_get(Evas_Coord xx1,
2995                        Evas_Coord yy1,
2996                        Evas_Coord xx2,
2997                        Evas_Coord yy2,
2998                        Evas_Coord *x,
2999                        Evas_Coord *y)
3000 {
3001    double a, b, xx, yy, gap;
3002    xx = fabs(xx2 - xx1);
3003    yy = fabs(yy2 - yy1);
3004    gap = sqrt((xx * xx) + (yy * yy));
3005
3006    /* START - Compute zoom center point */
3007    /* The triangle defined as follows:
3008     *             B
3009     *           / |
3010     *          /  |
3011     *     gap /   | a
3012     *        /    |
3013     *       A-----C
3014     *          b
3015     * http://en.wikipedia.org/wiki/Trigonometric_functions
3016     *************************************/
3017    if (((int)xx) && ((int)yy))
3018      {
3019         double A = atan((yy / xx));
3020         a = (Evas_Coord)((gap / 2) * sin(A));
3021         b = (Evas_Coord)((gap / 2) * cos(A));
3022         *x = (Evas_Coord)((xx2 > xx1) ? (xx1 + b) : (xx2 + b));
3023         *y = (Evas_Coord)((yy2 > yy1) ? (yy1 + a) : (yy2 + a));
3024      }
3025    else
3026      {
3027         if ((int)xx) /* horiz line, take half width */
3028           {
3029              *x = (Evas_Coord)((xx1 + xx2) / 2);
3030              *y = (Evas_Coord)(yy1);
3031           }
3032
3033         if ((int)yy) /* vert line, take half width */
3034           {
3035              *x = (Evas_Coord)(xx1);
3036              *y = (Evas_Coord)((yy1 + yy2) / 2);
3037           }
3038      }
3039    /* END   - Compute zoom center point */
3040
3041    return (Evas_Coord)gap;
3042 }
3043
3044 /**
3045  * @internal
3046  *
3047  * This function is used for computing zoom value.
3048  *
3049  * @param st Pointer to zoom data based on user input.
3050  * @param tm_end Recent input event timestamp.
3051  * @param zoom_val Current computed zoom value.
3052  *
3053  * @return zoom momentum
3054  *
3055  * @ingroup Elm_Gesture_Layer
3056  */
3057 static double
3058 _zoom_momentum_get(Zoom_Type *st,
3059                    unsigned int tm_end,
3060                    double zoom_val)
3061 {
3062    unsigned int tm_total;
3063    if (!st->m_st_tm) /* Init, and we don't start computing momentum yet */
3064      {
3065         st->m_st_tm = st->m_prev_tm = tm_end;
3066         st->m_base = zoom_val;
3067         return 0.0;
3068      }
3069
3070    if ((tm_end - ELM_GESTURE_MOMENTUM_DELAY) < st->m_st_tm)
3071      return 0.0;  /* we don't start to compute momentum yet */
3072
3073    if (st->dir) /* if direction was already defined, check if changed */
3074      {
3075         if (((st->dir < 0) && (zoom_val > st->info.zoom)) ||
3076             /* Direction changed, reset momentum */
3077             ((st->dir > 0) && (zoom_val < st->info.zoom)))
3078           {
3079              st->m_st_tm = 0;
3080              st->dir = (-st->dir);
3081              return 0.0;
3082           }
3083      }
3084    else
3085      st->dir = (zoom_val > st->info.zoom) ? 1 : -1;  /* init */
3086
3087    if ((tm_end - ELM_GESTURE_MOMENTUM_TIMEOUT) > st->m_prev_tm)
3088      {
3089         st->m_st_tm = 0; /* Rest momentum when waiting too long */
3090         return 0.0;
3091      }
3092
3093    st->m_prev_tm = tm_end;
3094    tm_total = tm_end - st->m_st_tm;
3095
3096    if (tm_total)
3097      return ((zoom_val - st->m_base) * 1000) / tm_total;
3098    else
3099      return 0.0;
3100 }
3101
3102 /**
3103  * @internal
3104  *
3105  * This function is used for computing zoom value.
3106  *
3107  * @param st Pointer to zoom data based on user input.
3108  * @param x1 first finger x location.
3109  * @param y1 first finger y location.
3110  * @param x2 second finger x location.
3111  * @param y2 second finger y location.
3112  * @param factor zoom-factor, used to determine how fast zoom works.
3113  *
3114  * @return zoom value, when 1.0 means no zoom, 0.5 half size...
3115  *
3116  * @ingroup Elm_Gesture_Layer
3117  */
3118 static double
3119 _zoom_compute(Zoom_Type *st,
3120               Evas_Coord xx1,
3121               Evas_Coord yy1,
3122               Evas_Coord xx2,
3123               Evas_Coord yy2,
3124               double zoom_finger_factor)
3125 {
3126    double rt = 1.0;
3127    unsigned int tm_end = (st->zoom_mv.timestamp > st->zoom_mv1.timestamp) ?
3128      st->zoom_mv.timestamp : st->zoom_mv1.timestamp;
3129
3130    Evas_Coord diam = _finger_gap_length_get(xx1, yy1, xx2, yy2,
3131                                             &st->info.x, &st->info.y);
3132
3133    st->info.radius = diam / 2;
3134
3135    if (!st->zoom_base)
3136      {
3137         st->zoom_base = diam;
3138         return st->info.zoom;
3139      }
3140
3141    if (st->zoom_distance_tolerance) /* zoom tolerance <> ZERO, means
3142                                     * zoom action NOT started yet */
3143      {
3144         /* avoid jump with zoom value when break tolerance */
3145         if (diam < (st->zoom_base - st->zoom_distance_tolerance))
3146           {
3147              st->zoom_base -= st->zoom_distance_tolerance;
3148              st->zoom_distance_tolerance = 0;
3149           }
3150
3151         /* avoid jump with zoom value when break tolerance */
3152         if (diam > (st->zoom_base + st->zoom_distance_tolerance))
3153           {
3154              st->zoom_base += st->zoom_distance_tolerance;
3155              st->zoom_distance_tolerance = 0;
3156           }
3157
3158         return rt;
3159      }
3160
3161    /* We use factor only on the difference between gap-base   */
3162    /* if gap=120, base=100, we get ((120-100)/100)=0.2*factor */
3163    rt = ((1.0) + ((((float)diam - (float)st->zoom_base) /
3164                    (float)st->zoom_base) * zoom_finger_factor));
3165
3166    /* Momentum: zoom per second: */
3167    st->info.momentum = _zoom_momentum_get(st, tm_end, rt);
3168
3169    return rt;
3170 }
3171
3172 /**
3173  * @internal
3174  *
3175  * This function handles zoom with mouse wheel.
3176  * thats a combination of wheel + CTRL key.
3177  * @param obj The gesture-layer object.
3178  * @param event_info Original input event pointer.
3179  * @param event_type Type of original input event.
3180  * @param g_type what Gesture we are testing.
3181  *
3182  * @ingroup Elm_Gesture_Layer
3183  */
3184 static void
3185 _zoom_with_wheel_test(Evas_Object *obj,
3186                       void *event_info,
3187                       Evas_Callback_Type event_type,
3188                       Elm_Gesture_Type g_type)
3189 {
3190    ELM_GESTURE_LAYER_DATA_GET(obj, sd);
3191
3192    if (!sd->gesture[g_type]) return;
3193
3194    Gesture_Info *gesture_zoom = sd->gesture[g_type];
3195    Zoom_Type *st = gesture_zoom->data;
3196    Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
3197    if (!st) /* Allocated once on first time, used for zoom intermediate data */
3198      {
3199         st = calloc(1, sizeof(Zoom_Type));
3200         gesture_zoom->data = st;
3201         _zoom_test_reset(gesture_zoom);
3202      }
3203
3204    switch (event_type)
3205      {
3206       case EVAS_CALLBACK_KEY_UP:
3207       {
3208          Evas_Event_Key_Up *p = event_info;
3209          if ((!strcmp(p->key, "Control_L")) ||
3210              /* Test if we ended a zoom gesture when releasing CTRL */
3211              (!strcmp(p->key, "Control_R")))
3212            {
3213               if ((st->zoom_wheel) &&
3214                   ((gesture_zoom->state == ELM_GESTURE_STATE_START) ||
3215                    /* User released CTRL after zooming */
3216                    (gesture_zoom->state == ELM_GESTURE_STATE_MOVE)))
3217                 {
3218                    st->info.momentum = _zoom_momentum_get
3219                        (st, p->timestamp, st->info.zoom);
3220
3221                    ev_flag = _state_set
3222                        (gesture_zoom, ELM_GESTURE_STATE_END, &st->info,
3223                        EINA_FALSE);
3224                    _event_consume(sd, event_info, event_type, ev_flag);
3225
3226                    return;
3227                 }
3228            }
3229          break;
3230       }
3231
3232       case EVAS_CALLBACK_MOUSE_WHEEL:
3233       {
3234          Eina_Bool force;
3235          Elm_Gesture_State s;
3236          if (!evas_key_modifier_is_set(
3237                ((Evas_Event_Mouse_Wheel *)event_info)->modifiers,
3238                "Control")) /* if using wheel witout CTRL after starting zoom */
3239            {
3240               if ((st->zoom_wheel) &&
3241                   ((gesture_zoom->state == ELM_GESTURE_STATE_START) ||
3242                    (gesture_zoom->state == ELM_GESTURE_STATE_MOVE)))
3243                 {
3244                    ev_flag = _state_set
3245                        (gesture_zoom, ELM_GESTURE_STATE_END, &st->info,
3246                        EINA_FALSE);
3247                    _event_consume(sd, event_info, event_type, ev_flag);
3248
3249                    return;
3250                 }
3251               else
3252                 return;  /* Ignore mouse-wheel without control */
3253            }
3254
3255          /* Using mouse wheel with CTRL for zoom */
3256          /* (zoom_wheel == NULL) and (zoom_distance_tolerance == 0) we
3257           * continue a zoom gesture */
3258          if (st->zoom_wheel || (st->zoom_distance_tolerance == 0))
3259            {
3260               force = EINA_TRUE;
3261               s = ELM_GESTURE_STATE_MOVE;
3262            }
3263          else
3264            { /* On first wheel event, report START */
3265              Evas_Modifier_Mask mask = evas_key_modifier_mask_get(
3266                  evas_object_evas_get(sd->target), "Control");
3267              force = EINA_FALSE;
3268              s = ELM_GESTURE_STATE_START;
3269              if (!evas_object_key_grab
3270                    (sd->target, "Control_L", mask, 0, EINA_FALSE))
3271                ERR("Failed to Grabbed CTRL_L");
3272              if (!evas_object_key_grab
3273                    (sd->target, "Control_R", mask, 0, EINA_FALSE))
3274                ERR("Failed to Grabbed CTRL_R");
3275            }
3276
3277          st->zoom_distance_tolerance = 0; /* Cancel tolerance */
3278          st->zoom_wheel = (Evas_Event_Mouse_Wheel *)event_info;
3279          st->info.x = st->zoom_wheel->canvas.x;
3280          st->info.y = st->zoom_wheel->canvas.y;
3281
3282          if (st->zoom_wheel->z < 0) /* zoom in */
3283            st->info.zoom += (sd->zoom_finger_factor * sd->zoom_wheel_factor);
3284
3285          if (st->zoom_wheel->z > 0) /* zoom out */
3286            st->info.zoom -= (sd->zoom_finger_factor * sd->zoom_wheel_factor);
3287
3288          if (st->info.zoom < 0.0)
3289            st->info.zoom = 0.0;
3290
3291          st->info.momentum = _zoom_momentum_get
3292              (st, st->zoom_wheel->timestamp, st->info.zoom);
3293
3294          ev_flag = _state_set(gesture_zoom, s, &st->info, force);
3295          _event_consume(sd, event_info, event_type, ev_flag);
3296          break;
3297       }
3298
3299       default:
3300         return;
3301      }
3302 }
3303
3304 /**
3305  * @internal
3306  *
3307  * This function is used to test zoom gesture.
3308  * user may combine zoom, rotation together.
3309  * so its possible that both will be detected from input.
3310  * (both are two-finger movement-oriented gestures)
3311  *
3312  * @param obj The gesture-layer object.
3313  * @param event_info Pointer to recent input event.
3314  * @param event_type Recent input event type.
3315  * @param g_type what Gesture we are testing.
3316  *
3317  * @ingroup Elm_Gesture_Layer
3318  */
3319 static void
3320 _zoom_test(Evas_Object *obj,
3321            Pointer_Event *pe,
3322            void *event_info,
3323            Evas_Callback_Type event_type,
3324            Elm_Gesture_Type g_type)
3325 {
3326    /* Test for wheel zoom. */
3327    _zoom_with_wheel_test(obj, event_info, event_type, ELM_GESTURE_ZOOM);
3328
3329    if (!_elm_config->glayer_zoom_finger_enable)
3330      return;
3331
3332    if (!pe)
3333      return;
3334    ELM_GESTURE_LAYER_DATA_GET(obj, sd);
3335
3336    if (!sd->gesture[g_type]) return;
3337
3338    Gesture_Info *gesture_zoom = sd->gesture[g_type];
3339    Zoom_Type *st = gesture_zoom->data;
3340
3341    if (!st) /* Allocated once on first time, used for zoom data */
3342      {
3343         st = calloc(1, sizeof(Zoom_Type));
3344         gesture_zoom->data = st;
3345         _zoom_test_reset(gesture_zoom);
3346      }
3347
3348    /* Start - new zoom testing, letting all fingers start */
3349    Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
3350    switch (event_type)
3351      {
3352       case EVAS_CALLBACK_MOUSE_MOVE:
3353       case EVAS_CALLBACK_MULTI_MOVE:
3354         /* if non-continues mode and gesture NOT started, ignore MOVE */
3355         if ((!sd->glayer_continues_enable) &&
3356             (!st->zoom_st.timestamp))
3357           return;
3358
3359       case EVAS_CALLBACK_MOUSE_DOWN:
3360       case EVAS_CALLBACK_MULTI_DOWN:
3361       { /* Here we take care of zoom-start and zoom move */
3362         Eina_List *l;
3363         Pointer_Event *p;
3364
3365         if (eina_list_count(sd->touched) > 2) /* Process zoom only
3366                                                * when 2 fingers on
3367                                                * surface */
3368           {
3369              ev_flag = _state_set
3370                  (gesture_zoom, ELM_GESTURE_STATE_ABORT, &st->info,
3371                  EINA_FALSE);
3372              _event_consume(sd, event_info, event_type, ev_flag);
3373
3374              return;
3375           }
3376
3377         if (!st->zoom_st.timestamp) /* Now scan touched-devices list
3378                                      * and find other finger */
3379           {
3380              EINA_LIST_FOREACH(sd->touched, l, p)
3381                { /* Device of other finger <> pe device */
3382                  if (p->device != pe->device)
3383                    break;
3384                }
3385
3386              if (!p) /* Single finger on touch */
3387                return;
3388
3389              /* Record down fingers */
3390              _event_consume(sd, event_info, event_type, ev_flag);
3391              memcpy(&st->zoom_st, pe, sizeof(Pointer_Event));
3392              memcpy(&st->zoom_st1, p, sizeof(Pointer_Event));
3393
3394              /* Set mv field as well to be ready for MOVE events  */
3395              memcpy(&st->zoom_mv, pe, sizeof(Pointer_Event));
3396              memcpy(&st->zoom_mv1, p, sizeof(Pointer_Event));
3397
3398              /* Here we have zoom_st, zoom_st1 set, report START  */
3399              /* Set zoom-base after BOTH down events  recorded    */
3400              /* Compute length of line between fingers zoom start */
3401              st->info.zoom = 1.0;
3402              st->zoom_base = _finger_gap_length_get
3403                  (st->zoom_st1.x, st->zoom_st1.y, st->zoom_st.x, st->zoom_st.y,
3404                  &st->info.x, &st->info.y);
3405
3406              st->info.radius = st->zoom_base / 2;
3407
3408              if ((gesture_zoom->state != ELM_GESTURE_STATE_START) &&
3409                  /* zoom started with mouse-wheel, don't report twice */
3410                  (gesture_zoom->state != ELM_GESTURE_STATE_MOVE))
3411                {
3412                   ev_flag = _state_set
3413                       (gesture_zoom, ELM_GESTURE_STATE_START, &st->info,
3414                       EINA_FALSE);
3415                   _event_consume(sd, event_info, event_type, ev_flag);
3416                }
3417
3418              return; /* Zoom started */
3419           } /* End of ZOOM_START handling */
3420
3421         /* if we got here, we have (exacally) two fingers on surfce */
3422         /* we also after START, report MOVE */
3423         /* First detect which finger moved  */
3424         if (pe->device == st->zoom_mv.device)
3425           memcpy(&st->zoom_mv, pe, sizeof(Pointer_Event));
3426         else if (pe->device == st->zoom_mv1.device)
3427           memcpy(&st->zoom_mv1, pe, sizeof(Pointer_Event));
3428
3429         /* Compute change in zoom as fingers move */
3430         st->info.zoom = _zoom_compute(st,
3431                                       st->zoom_mv.x, st->zoom_mv.y,
3432                                       st->zoom_mv1.x, st->zoom_mv1.y,
3433                                       sd->zoom_finger_factor);
3434
3435         if (!st->zoom_distance_tolerance) /* Zoom broke tolerance,
3436                                            * report move */
3437           {
3438              double d = st->info.zoom - st->next_step;
3439              if (d < 0.0)
3440                d = (-d);
3441
3442              if (d >= sd->zoom_step) /* Report move in steps */
3443                {
3444                   st->next_step = st->info.zoom;
3445
3446                   ev_flag = _state_set(gesture_zoom,
3447                                        ELM_GESTURE_STATE_MOVE,
3448                                        &st->info, EINA_TRUE);
3449                   _event_consume(sd, event_info, event_type, ev_flag);
3450                }
3451           } /* End of ZOOM_MOVE handling */
3452
3453         return;
3454       }
3455
3456       case EVAS_CALLBACK_MOUSE_UP:
3457       case EVAS_CALLBACK_MULTI_UP:
3458         /* Reset timestamp of finger-up.This is used later
3459            by _zoom_test_reset() to retain finger-down data */
3460         _event_consume(sd, event_info, event_type, ev_flag);
3461         if (((st->zoom_wheel) || (st->zoom_base)) &&
3462             (st->zoom_distance_tolerance == 0))
3463           {
3464              ev_flag = _state_set(gesture_zoom, ELM_GESTURE_STATE_END,
3465                                   &st->info, EINA_FALSE);
3466              _event_consume(sd, event_info, event_type, ev_flag);
3467
3468              return;
3469           }
3470
3471         /* if we got here not a ZOOM */
3472         /* Must be != undefined, if gesture started */
3473         if (gesture_zoom->state != ELM_GESTURE_STATE_UNDEFINED)
3474           {
3475              ev_flag = _state_set
3476                  (gesture_zoom, ELM_GESTURE_STATE_ABORT, &st->info,
3477                  EINA_FALSE);
3478              _event_consume(sd, event_info, event_type, ev_flag);
3479           }
3480
3481         _zoom_test_reset(gesture_zoom);
3482
3483         return;
3484
3485       default:
3486         return;
3487      }
3488 }
3489
3490 static void
3491 _rotate_properties_get(Rotate_Type *st,
3492                        Evas_Coord xx1,
3493                        Evas_Coord yy1,
3494                        Evas_Coord xx2,
3495                        Evas_Coord yy2,
3496                        double *angle)
3497 {
3498    /* FIXME: Fix momentum computation, it's wrong */
3499    double prev_angle = *angle;
3500
3501    st->info.radius = _finger_gap_length_get(xx1, yy1, xx2, yy2,
3502                                             &st->info.x, &st->info.y) / 2;
3503
3504    *angle = _angle_get(xx1, yy1, xx2, yy2);
3505
3506    if (angle == &st->info.angle) /* Fingers are moving, compute momentum */
3507      {
3508         unsigned int tm_start =
3509           (st->rotate_st.timestamp > st->rotate_st1.timestamp)
3510           ?  st->rotate_st.timestamp : st->rotate_st1.timestamp;
3511         unsigned int tm_end =
3512           (st->rotate_mv.timestamp > st->rotate_mv1.timestamp)
3513           ? st->rotate_mv.timestamp : st->rotate_mv1.timestamp;
3514
3515         unsigned int tm_total = tm_end - tm_start;
3516         if (tm_total) /* Momentum computed as:
3517                          accumulated roation angle (deg) divided by time */
3518           {
3519              double m = 0;
3520              if (((prev_angle < 90) && ((*angle) > 270)) ||
3521                  /* We circle passing ZERO point */
3522                  ((prev_angle > 270) && ((*angle) < 90)))
3523                {
3524                   prev_angle = (*angle);
3525                }
3526              else m = prev_angle - (*angle);
3527
3528              st->accum_momentum += m;
3529
3530              if ((tm_end - st->prev_momentum_tm) < 100)
3531                st->prev_momentum += m;
3532              else
3533                {
3534                   if (fabs(st->prev_momentum) < 0.002)
3535                     st->accum_momentum = 0.0;  /* reset momentum */
3536
3537                   st->prev_momentum = 0.0; /* Start again    */
3538                }
3539
3540              st->prev_momentum_tm = tm_end;
3541              st->info.momentum = (st->accum_momentum * 1000) / tm_total;
3542           }
3543      }
3544    else
3545      st->info.momentum = 0;
3546 }
3547
3548 /**
3549  * @internal
3550  *
3551  * This function is used to test rotation gesture.
3552  * user may combine zoom, rotation together.
3553  * so its possible that both will be detected from input.
3554  * (both are two-finger movement-oriented gestures)
3555  *
3556  * @param obj The gesture-layer object.
3557  * @param event_info Pointer to recent input event.
3558  * @param event_type Recent input event type.
3559  * @param g_type what Gesture we are testing.
3560  *
3561  * @ingroup Elm_Gesture_Layer
3562  */
3563 static void
3564 _rotate_test(Evas_Object *obj,
3565              Pointer_Event *pe,
3566              void *event_info,
3567              Evas_Callback_Type event_type,
3568              Elm_Gesture_Type g_type)
3569 {
3570    Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
3571    Gesture_Info *gesture;
3572    Rotate_Type *st = NULL;
3573
3574    if (!_elm_config->glayer_rotate_finger_enable)
3575      return;
3576
3577    if (!pe)
3578      return;
3579
3580    ELM_GESTURE_LAYER_DATA_GET(obj, sd);
3581
3582    if (!sd->gesture[g_type]) return;
3583
3584    gesture = sd->gesture[g_type];
3585    if (!gesture) return ;
3586
3587    st = gesture->data;
3588    if (!st) /* Allocated once on first time */
3589      {
3590        st = calloc(1, sizeof(Rotate_Type));
3591        gesture->data = st;
3592        _rotate_test_reset(gesture);
3593      }
3594
3595    switch (event_type)
3596      {
3597       case EVAS_CALLBACK_MOUSE_MOVE:
3598       case EVAS_CALLBACK_MULTI_MOVE:
3599         /* if non-continues mode and gesture NOT started, ignore MOVE */
3600         if ((!sd->glayer_continues_enable) &&
3601             (!st->rotate_st.timestamp))
3602           return;
3603
3604       case EVAS_CALLBACK_MOUSE_DOWN:
3605       case EVAS_CALLBACK_MULTI_DOWN:
3606       { /* Here we take care of rotate-start and rotate move */
3607         Eina_List *l;
3608         Pointer_Event *p;
3609
3610         if (eina_list_count(sd->touched) > 2) /* Process rotate only
3611                                                * when 2 fingers on
3612                                                * surface */
3613           {
3614              ev_flag = _state_set
3615                  (gesture, ELM_GESTURE_STATE_ABORT, &st->info, EINA_FALSE);
3616              _event_consume(sd, event_info, event_type, ev_flag);
3617
3618              return;
3619           }
3620
3621         if (!st->rotate_st.timestamp) /* Now scan touched-devices list
3622                                        * and find other finger */
3623           {
3624              EINA_LIST_FOREACH(sd->touched, l, p)
3625                { /* Device of other finger <> pe device */
3626                  if (p->device != pe->device)
3627                    break;
3628                }
3629
3630              if (!p)
3631                return;  /* Single finger on touch */
3632
3633              /* Record down fingers */
3634              _event_consume(sd, event_info, event_type, ev_flag);
3635              memcpy(&st->rotate_st, pe, sizeof(Pointer_Event));
3636              memcpy(&st->rotate_st1, p, sizeof(Pointer_Event));
3637
3638              /* Set mv field as well to be ready for MOVE events  */
3639              memcpy(&st->rotate_mv, pe, sizeof(Pointer_Event));
3640              memcpy(&st->rotate_mv1, p, sizeof(Pointer_Event));
3641
3642              /* Here we have rotate_st, rotate_st1 set, report START  */
3643              /* Set rotate-base after BOTH down events  recorded    */
3644              /* Compute length of line between fingers rotate start */
3645              _rotate_properties_get(st,
3646                                     st->rotate_st.x, st->rotate_st.y,
3647                                     st->rotate_st1.x, st->rotate_st1.y,
3648                                     &st->info.base_angle);
3649
3650              ev_flag = _state_set(gesture, ELM_GESTURE_STATE_START,
3651                                   &st->info, EINA_FALSE);
3652              _event_consume(sd, event_info, event_type, ev_flag);
3653
3654              return; /* Rotate started */
3655           } /* End of ROTATE_START handling */
3656
3657         /* if we got here, we have (exacally) two fingers on surfce */
3658         /* we also after START, report MOVE */
3659         /* First detect which finger moved  */
3660         if (pe->device == st->rotate_mv.device)
3661           memcpy(&st->rotate_mv, pe, sizeof(Pointer_Event));
3662         else if (pe->device == st->rotate_mv1.device)
3663           memcpy(&st->rotate_mv1, pe, sizeof(Pointer_Event));
3664
3665         /* Compute change in rotate as fingers move */
3666         _rotate_properties_get(st,
3667                                st->rotate_mv.x, st->rotate_mv.y,
3668                                st->rotate_mv1.x, st->rotate_mv1.y,
3669                                &st->info.angle);
3670
3671         if (_on_rotation_broke_tolerance(st)) /* Rotation broke
3672                                                * tolerance, report
3673                                                * move */
3674           {
3675              double d = st->info.angle - st->next_step;
3676              if (d < 0)
3677                d = (-d);
3678
3679              if (d >= sd->rotate_step) /* Report move in steps */
3680                {
3681                   st->next_step = st->info.angle;
3682
3683                   ev_flag = _state_set
3684                       (gesture, ELM_GESTURE_STATE_MOVE, &st->info, EINA_TRUE);
3685                   _event_consume(sd, event_info, event_type, ev_flag);
3686                }
3687           } /* End of ROTATE_MOVE handling */
3688
3689         return;
3690       }
3691
3692       case EVAS_CALLBACK_MOUSE_UP:
3693       case EVAS_CALLBACK_MULTI_UP:
3694         _event_consume(sd, event_info, event_type, ev_flag);
3695         /* Reset timestamp of finger-up.This is used later
3696            by rotate_test_reset() to retain finger-down data */
3697         if (st->rotate_angular_tolerance < 0)
3698           {
3699              ev_flag = _state_set(gesture, ELM_GESTURE_STATE_END,
3700                                   &st->info, EINA_FALSE);
3701              _event_consume(sd, event_info, event_type, ev_flag);
3702
3703              return;
3704           }
3705
3706         /* Must be != undefined, if gesture started */
3707         if (gesture->state != ELM_GESTURE_STATE_UNDEFINED)
3708           {
3709              ev_flag = _state_set(gesture, ELM_GESTURE_STATE_ABORT,
3710                                   &st->info, EINA_FALSE);
3711              _event_consume(sd, event_info, event_type, ev_flag);
3712           }
3713
3714         _rotate_test_reset(gesture);
3715         return;
3716
3717       default:
3718         return;
3719      }
3720 }
3721
3722 static void
3723 _elm_gesture_layer_smart_disable(Eo *obj, void *_pd EINA_UNUSED, va_list *list)
3724 {
3725    Eina_Bool *ret = va_arg(*list, Eina_Bool *);
3726    if (elm_widget_disabled_get(obj))
3727      _callbacks_unregister(obj);
3728    else
3729      _callbacks_register(obj);
3730
3731    if (ret) *ret = EINA_TRUE;
3732 }
3733
3734 static void
3735 _elm_gesture_layer_smart_add(Eo *obj, void *_pd, va_list *list EINA_UNUSED)
3736 {
3737    eo_do_super(obj, MY_CLASS, evas_obj_smart_add());
3738
3739    elm_widget_sub_object_add(eo_parent_get(obj), obj);
3740
3741    Elm_Gesture_Layer_Smart_Data *priv = _pd;
3742
3743    priv->line_min_length =
3744      _elm_config->glayer_line_min_length * elm_config_finger_size_get();
3745    priv->zoom_distance_tolerance = _elm_config->glayer_zoom_distance_tolerance
3746      * elm_config_finger_size_get();
3747    priv->line_distance_tolerance = _elm_config->glayer_line_distance_tolerance
3748      * elm_config_finger_size_get();
3749    priv->zoom_finger_factor = _elm_config->glayer_zoom_finger_factor;
3750    /* mouse wheel zoom steps */
3751    priv->zoom_wheel_factor = _elm_config->glayer_zoom_wheel_factor;
3752    priv->rotate_angular_tolerance =
3753      _elm_config->glayer_rotate_angular_tolerance;
3754    priv->line_angular_tolerance = _elm_config->glayer_line_angular_tolerance;
3755    priv->flick_time_limit_ms = _elm_config->glayer_flick_time_limit_ms;
3756    priv->long_tap_start_timeout = _elm_config->glayer_long_tap_start_timeout;
3757    priv->repeat_events = EINA_TRUE;
3758    priv->glayer_continues_enable = _elm_config->glayer_continues_enable;
3759
3760    /* FIXME: Hack to get around old configs - if too small, enlarge. */
3761    if (_elm_config->glayer_double_tap_timeout < 0.00001)
3762      _elm_config->glayer_double_tap_timeout = 0.25;
3763    priv->double_tap_timeout = _elm_config->glayer_double_tap_timeout;
3764
3765    memset(priv->gesture, 0, sizeof(priv->gesture));
3766 }
3767
3768 static void _cbs_clean(Elm_Gesture_Layer_Smart_Data *sd, Elm_Gesture_Type idx, Elm_Gesture_State cb_type);
3769
3770 static void
3771 _elm_gesture_layer_smart_del(Eo *obj, void *_pd, va_list *list EINA_UNUSED)
3772 {
3773    Elm_Gesture_Layer_Smart_Data *sd = _pd;
3774    Pointer_Event *data;
3775    int i;
3776
3777    /* Clear all gestures intermediate data, stop any timers */
3778    {
3779       /* FIXME: +1 because of the mistake in the enum. */
3780       Gesture_Info **gitr = sd->gesture + 1;
3781       Tests_Array_Funcs *fitr = _glayer_tests_array + 1;
3782       for (; fitr->reset; fitr++, gitr++)
3783         {
3784            if (IS_TESTED_GESTURE(*gitr))
3785              fitr->reset(*gitr);
3786         }
3787    }
3788
3789    /* First Free all gestures internal data structures */
3790    for (i = 0; i < ELM_GESTURE_LAST; i++)
3791      if (sd->gesture[i])
3792        {
3793           if (sd->gesture[i]->data)
3794             free(sd->gesture[i]->data);
3795
3796           _cbs_clean(sd, i, ELM_GESTURE_STATE_START);
3797           _cbs_clean(sd, i, ELM_GESTURE_STATE_MOVE);
3798           _cbs_clean(sd, i, ELM_GESTURE_STATE_END);
3799           _cbs_clean(sd, i, ELM_GESTURE_STATE_ABORT);
3800           free(sd->gesture[i]);
3801           sd->gesture[i] = NULL; /* Referenced by _event_history_clear */
3802        }
3803    if (sd->gest_taps_timeout) ecore_timer_del(sd->gest_taps_timeout);
3804
3805    /* Then take care of clearing events */
3806    _event_history_clear(obj);
3807    sd->pending = eina_list_free(sd->pending);
3808
3809    EINA_LIST_FREE(sd->touched, data)
3810      free(data);
3811
3812    if (!elm_widget_disabled_get(obj))
3813      _callbacks_unregister(obj);
3814
3815
3816    eo_do_super(obj, MY_CLASS, evas_obj_smart_del());
3817 }
3818
3819 EAPI Evas_Object *
3820 elm_gesture_layer_add(Evas_Object *parent)
3821 {
3822    EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL);
3823    Evas_Object *obj = eo_add(MY_CLASS, parent);
3824    eo_unref(obj);
3825    return obj;
3826 }
3827
3828 static void
3829 _constructor(Eo *obj, void *_pd EINA_UNUSED, va_list *list EINA_UNUSED)
3830 {
3831    eo_do_super(obj, MY_CLASS, eo_constructor());
3832    eo_do(obj, evas_obj_type_set(MY_CLASS_NAME));
3833 }
3834
3835 EAPI Eina_Bool
3836 elm_gesture_layer_hold_events_get(const Evas_Object *obj)
3837 {
3838    ELM_GESTURE_LAYER_CHECK(obj) EINA_FALSE;
3839    Eina_Bool ret = EINA_FALSE;
3840    eo_do((Eo *) obj, elm_obj_gesture_layer_hold_events_get(&ret));
3841    return ret;
3842 }
3843
3844 static void
3845 _hold_events_get(Eo *obj EINA_UNUSED, void *_pd, va_list *list)
3846 {
3847    Eina_Bool *ret = va_arg(*list, Eina_Bool *);
3848    Elm_Gesture_Layer_Smart_Data *sd = _pd;
3849    *ret = !sd->repeat_events;
3850 }
3851
3852 EAPI void
3853 elm_gesture_layer_hold_events_set(Evas_Object *obj,
3854                                   Eina_Bool hold_events)
3855 {
3856    ELM_GESTURE_LAYER_CHECK(obj);
3857    eo_do(obj, elm_obj_gesture_layer_hold_events_set(hold_events));
3858 }
3859
3860 static void
3861 _hold_events_set(Eo *obj EINA_UNUSED, void *_pd, va_list *list)
3862 {
3863    Eina_Bool hold_events = va_arg(*list, int);
3864    Elm_Gesture_Layer_Smart_Data *sd = _pd;
3865
3866    sd->repeat_events = !(!!hold_events);
3867 }
3868
3869 EAPI double
3870 elm_gesture_layer_zoom_step_get(const Evas_Object *obj)
3871 {
3872    ELM_GESTURE_LAYER_CHECK(obj) 0;
3873    double ret = 0;
3874    eo_do((Eo *) obj, elm_obj_gesture_layer_zoom_step_get(&ret));
3875    return ret;
3876 }
3877
3878 static void
3879 _zoom_step_get(Eo *obj EINA_UNUSED, void *_pd, va_list *list)
3880 {
3881    double *ret = va_arg(*list, double *);
3882    Elm_Gesture_Layer_Smart_Data *sd = _pd;
3883    *ret = sd->zoom_step;
3884 }
3885
3886 EAPI void
3887 elm_gesture_layer_zoom_step_set(Evas_Object *obj,
3888                                 double step)
3889 {
3890    ELM_GESTURE_LAYER_CHECK(obj);
3891    eo_do(obj, elm_obj_gesture_layer_zoom_step_set(step));
3892 }
3893
3894 static void
3895 _zoom_step_set(Eo *obj EINA_UNUSED, void *_pd, va_list *list)
3896 {
3897    double step = va_arg(*list, double);
3898    Elm_Gesture_Layer_Smart_Data *sd = _pd;
3899
3900    if (step < 0) return;
3901
3902    sd->zoom_step = step;
3903 }
3904
3905 EAPI double
3906 elm_gesture_layer_rotate_step_get(const Evas_Object *obj)
3907 {
3908    ELM_GESTURE_LAYER_CHECK(obj) 0;
3909    double ret = 0;
3910    eo_do((Eo *) obj, elm_obj_gesture_layer_rotate_step_get(&ret));
3911    return ret;
3912 }
3913
3914 static void
3915 _rotate_step_get(Eo *obj EINA_UNUSED, void *_pd, va_list *list)
3916 {
3917    double *ret = va_arg(*list, double *);
3918    Elm_Gesture_Layer_Smart_Data *sd = _pd;
3919    *ret = sd->rotate_step;
3920 }
3921
3922 EAPI void
3923 elm_gesture_layer_rotate_step_set(Evas_Object *obj,
3924                                   double step)
3925 {
3926    ELM_GESTURE_LAYER_CHECK(obj);
3927    eo_do(obj, elm_obj_gesture_layer_rotate_step_set(step));
3928 }
3929
3930 static void
3931 _rotate_step_set(Eo *obj EINA_UNUSED, void *_pd, va_list *list)
3932 {
3933    double step = va_arg(*list, double);
3934    Elm_Gesture_Layer_Smart_Data *sd = _pd;
3935
3936    if (step < 0) return;
3937
3938    sd->rotate_step = step;
3939 }
3940
3941 EAPI Eina_Bool
3942 elm_gesture_layer_attach(Evas_Object *obj,
3943                          Evas_Object *target)
3944 {
3945    ELM_GESTURE_LAYER_CHECK(obj) EINA_FALSE;
3946    Eina_Bool ret = EINA_FALSE;
3947    eo_do(obj, elm_obj_gesture_layer_attach(target, &ret));
3948    return ret;
3949 }
3950
3951 static void
3952 _attach(Eo *obj, void *_pd, va_list *list)
3953 {
3954    Evas_Object *target = va_arg(*list, Evas_Object *);
3955    Eina_Bool *ret = va_arg(*list, Eina_Bool *);
3956    Elm_Gesture_Layer_Smart_Data *sd = _pd;
3957    if (ret) *ret = EINA_FALSE;
3958
3959    if (!target) return;
3960
3961    /* if was attached before, unregister callbacks first */
3962    if (sd->target)
3963      _callbacks_unregister(obj);
3964
3965    sd->target = target;
3966
3967    _callbacks_register(obj);
3968    if (ret) *ret = EINA_TRUE;
3969 }
3970
3971 static void
3972 _cbs_clean(Elm_Gesture_Layer_Smart_Data *sd,
3973           Elm_Gesture_Type idx,
3974           Elm_Gesture_State cb_type)
3975 {
3976    if (!sd->gesture[idx]) return;
3977
3978    Func_Data *cb_info;
3979    EINA_INLIST_FREE(sd->gesture[idx]->cbs[cb_type], cb_info)
3980      {
3981         sd->gesture[idx]->cbs[cb_type] = eina_inlist_remove(
3982               sd->gesture[idx]->cbs[cb_type], EINA_INLIST_GET(cb_info));
3983         free(cb_info);
3984      }
3985    SET_TEST_BIT(sd->gesture[idx]);
3986 }
3987
3988 EAPI void
3989 elm_gesture_layer_cb_set(Evas_Object *obj,
3990                          Elm_Gesture_Type idx,
3991                          Elm_Gesture_State cb_type,
3992                          Elm_Gesture_Event_Cb cb,
3993                          void *data)
3994 {
3995    ELM_GESTURE_LAYER_CHECK(obj);
3996    eo_do(obj, elm_obj_gesture_layer_cb_set(idx, cb_type, cb, data));
3997 }
3998
3999 static void
4000 _cb_set(Eo *obj, void *_pd, va_list *list)
4001 {
4002    Elm_Gesture_Type idx = va_arg(*list, Elm_Gesture_Type);
4003    Elm_Gesture_State cb_type = va_arg(*list, Elm_Gesture_State);
4004    Elm_Gesture_Event_Cb cb = va_arg(*list, Elm_Gesture_Event_Cb);
4005    void *data = va_arg(*list, void *);
4006
4007    Elm_Gesture_Layer_Smart_Data *sd = _pd;
4008
4009    /* Clear gesture intermediate data, stop any timers */
4010    if (IS_TESTED_GESTURE(sd->gesture[idx]))
4011      _glayer_tests_array[idx].reset(sd->gesture[idx]);
4012
4013    _cbs_clean(sd, idx, cb_type); // for ABI compat.
4014    eo_do(obj, elm_obj_gesture_layer_cb_add(idx, cb_type, cb, data));
4015 }
4016
4017 EAPI void
4018 elm_gesture_layer_cb_add(Evas_Object *obj,
4019                          Elm_Gesture_Type idx,
4020                          Elm_Gesture_State cb_type,
4021                          Elm_Gesture_Event_Cb cb,
4022                          void *data)
4023 {
4024    ELM_GESTURE_LAYER_CHECK(obj);
4025    eo_do(obj, elm_obj_gesture_layer_cb_add(idx, cb_type, cb, data));
4026 }
4027
4028 static void
4029 _cb_add(Eo *obj, void *_pd, va_list *list)
4030 {
4031    Elm_Gesture_Type idx = va_arg(*list, Elm_Gesture_Type);
4032    Elm_Gesture_State cb_type = va_arg(*list, Elm_Gesture_State);
4033    Elm_Gesture_Event_Cb cb = va_arg(*list, Elm_Gesture_Event_Cb);
4034    void *data = va_arg(*list, void *);
4035
4036    if (!cb) return;
4037
4038    Gesture_Info *p;
4039    Elm_Gesture_Layer_Smart_Data *sd = _pd;
4040
4041    if (!sd->gesture[idx])
4042      sd->gesture[idx] = calloc(1, sizeof(Gesture_Info));
4043    if (!sd->gesture[idx]) return;
4044
4045    Func_Data *cb_info = calloc(1, sizeof(*cb_info));
4046    if (!cb_info) return;
4047    cb_info->cb = cb;
4048    cb_info->user_data = data;
4049
4050    p = sd->gesture[idx];
4051    p->obj = obj;
4052    p->g_type = idx;
4053    p->cbs[cb_type] = eina_inlist_append(p->cbs[cb_type],
4054          EINA_INLIST_GET(cb_info));
4055    p->state = ELM_GESTURE_STATE_UNDEFINED;
4056    SET_TEST_BIT(p);
4057 }
4058
4059 EAPI void
4060 elm_gesture_layer_cb_del(Evas_Object *obj,
4061                          Elm_Gesture_Type idx,
4062                          Elm_Gesture_State cb_type,
4063                          Elm_Gesture_Event_Cb cb,
4064                          void *data)
4065 {
4066    ELM_GESTURE_LAYER_CHECK(obj);
4067    eo_do(obj, elm_obj_gesture_layer_cb_del(idx, cb_type, cb, data));
4068 }
4069
4070 static void
4071 _cb_del(Eo *obj EINA_UNUSED, void *_pd, va_list *list)
4072 {
4073    Elm_Gesture_Type idx = va_arg(*list, Elm_Gesture_Type);
4074    Elm_Gesture_State cb_type = va_arg(*list, Elm_Gesture_State);
4075    Elm_Gesture_Event_Cb cb = va_arg(*list, Elm_Gesture_Event_Cb);
4076    void *data = va_arg(*list, void *);
4077
4078    Elm_Gesture_Layer_Smart_Data *sd = _pd;
4079
4080    if (!sd->gesture[idx]) return;
4081
4082    Eina_Inlist *itr;
4083    Func_Data *cb_info;
4084    EINA_INLIST_FOREACH_SAFE(sd->gesture[idx]->cbs[cb_type], itr, cb_info)
4085      {
4086         if (cb_info->cb == cb && cb_info->user_data == data)
4087           {
4088              /* Clear gesture intermediate data, stop any timers */
4089              if (IS_TESTED_GESTURE(sd->gesture[idx]))
4090                 _glayer_tests_array[idx].reset(sd->gesture[idx]);
4091
4092              sd->gesture[idx]->cbs[cb_type] = eina_inlist_remove(
4093                    sd->gesture[idx]->cbs[cb_type], EINA_INLIST_GET(cb_info));
4094              free(cb_info);
4095              SET_TEST_BIT(sd->gesture[idx]);
4096              return;
4097           }
4098      }
4099 }
4100
4101 EAPI void
4102 elm_gesture_layer_line_min_length_set(Evas_Object *obj, int line_min_length)
4103 {
4104    ELM_GESTURE_LAYER_CHECK(obj);
4105    ELM_GESTURE_LAYER_DATA_GET(obj, sd);
4106    sd->line_min_length = line_min_length;
4107 }
4108
4109
4110 EAPI int
4111 elm_gesture_layer_line_min_length_get(const Evas_Object *obj)
4112 {
4113    ELM_GESTURE_LAYER_CHECK(obj) 0;
4114    ELM_GESTURE_LAYER_DATA_GET(obj, sd);
4115    return sd->line_min_length;
4116 }
4117
4118 EAPI void
4119 elm_gesture_layer_zoom_distance_tolerance_set(Evas_Object *obj, Evas_Coord zoom_distance_tolerance)
4120 {
4121    ELM_GESTURE_LAYER_CHECK(obj);
4122    ELM_GESTURE_LAYER_DATA_GET(obj, sd);
4123    sd->zoom_distance_tolerance = zoom_distance_tolerance;
4124 }
4125
4126 EAPI Evas_Coord
4127 elm_gesture_layer_zoom_distance_tolerance_get(const Evas_Object *obj)
4128 {
4129    ELM_GESTURE_LAYER_CHECK(obj) 0;
4130    ELM_GESTURE_LAYER_DATA_GET(obj, sd);
4131    return sd->zoom_distance_tolerance;
4132 }
4133
4134 EAPI void
4135 elm_gesture_layer_line_distance_tolerance_set(Evas_Object *obj, Evas_Coord line_distance_tolerance)
4136 {
4137    ELM_GESTURE_LAYER_CHECK(obj);
4138    ELM_GESTURE_LAYER_DATA_GET(obj, sd);
4139    sd->line_distance_tolerance = line_distance_tolerance;
4140 }
4141
4142 EAPI Evas_Coord
4143 elm_gesture_layer_line_distance_tolerance_get(const Evas_Object *obj)
4144 {
4145    ELM_GESTURE_LAYER_CHECK(obj) 0;
4146    ELM_GESTURE_LAYER_DATA_GET(obj, sd);
4147    return sd->line_distance_tolerance;
4148 }
4149
4150 EAPI void
4151 elm_gesture_layer_line_angular_tolerance_set(Evas_Object *obj, double line_angular_tolerance)
4152 {
4153    ELM_GESTURE_LAYER_CHECK(obj);
4154    ELM_GESTURE_LAYER_DATA_GET(obj, sd);
4155    sd->line_angular_tolerance = line_angular_tolerance;
4156 }
4157
4158 EAPI double
4159 elm_gesture_layer_line_angular_tolerance_get(const Evas_Object *obj)
4160 {
4161    ELM_GESTURE_LAYER_CHECK(obj) 0.0;
4162    ELM_GESTURE_LAYER_DATA_GET(obj, sd);
4163    return sd->line_angular_tolerance;
4164 }
4165
4166 EAPI void
4167 elm_gesture_layer_zoom_wheel_factor_set(Evas_Object *obj, double zoom_wheel_factor)
4168 {
4169    ELM_GESTURE_LAYER_CHECK(obj);
4170    ELM_GESTURE_LAYER_DATA_GET(obj, sd);
4171    sd->zoom_wheel_factor = zoom_wheel_factor;
4172 }
4173
4174 EAPI double
4175 elm_gesture_layer_zoom_wheel_factor_get(const Evas_Object *obj)
4176 {
4177    ELM_GESTURE_LAYER_CHECK(obj) 0.0;
4178    ELM_GESTURE_LAYER_DATA_GET(obj, sd);
4179    return sd->zoom_wheel_factor;
4180 }
4181
4182 EAPI void
4183 elm_gesture_layer_zoom_finger_factor_set(Evas_Object *obj, double zoom_finger_factor)
4184 {
4185    ELM_GESTURE_LAYER_CHECK(obj);
4186    ELM_GESTURE_LAYER_DATA_GET(obj, sd);
4187    sd->zoom_finger_factor = zoom_finger_factor;
4188 }
4189
4190 EAPI double
4191 elm_gesture_layer_zoom_finger_factor_get(const Evas_Object *obj)
4192 {
4193    ELM_GESTURE_LAYER_CHECK(obj) 0.0;
4194    ELM_GESTURE_LAYER_DATA_GET(obj, sd);
4195    return sd->zoom_finger_factor;
4196 }
4197
4198 EAPI void
4199 elm_gesture_layer_rotate_angular_tolerance_set(Evas_Object *obj, double rotate_angular_tolerance)
4200 {
4201    ELM_GESTURE_LAYER_CHECK(obj);
4202    ELM_GESTURE_LAYER_DATA_GET(obj, sd);
4203    sd->rotate_angular_tolerance = rotate_angular_tolerance;
4204 }
4205
4206 EAPI double
4207 elm_gesture_layer_rotate_angular_tolerance_get(const Evas_Object *obj)
4208 {
4209    ELM_GESTURE_LAYER_CHECK(obj) 0.0;
4210    ELM_GESTURE_LAYER_DATA_GET(obj, sd);
4211    return sd->rotate_angular_tolerance;
4212 }
4213
4214 EAPI void
4215 elm_gesture_layer_flick_time_limit_ms_set(Evas_Object *obj, unsigned int flick_time_limit_ms)
4216 {
4217    ELM_GESTURE_LAYER_CHECK(obj);
4218    ELM_GESTURE_LAYER_DATA_GET(obj, sd);
4219    sd->flick_time_limit_ms = flick_time_limit_ms;
4220 }
4221
4222 EAPI unsigned int
4223 elm_gesture_layer_flick_time_limit_ms_get(const Evas_Object *obj)
4224 {
4225    ELM_GESTURE_LAYER_CHECK(obj) 0;
4226    ELM_GESTURE_LAYER_DATA_GET(obj, sd);
4227    return sd->flick_time_limit_ms;
4228 }
4229
4230 EAPI void
4231 elm_gesture_layer_long_tap_start_timeout_set(Evas_Object *obj, double long_tap_start_timeout)
4232 {
4233    ELM_GESTURE_LAYER_CHECK(obj);
4234    ELM_GESTURE_LAYER_DATA_GET(obj, sd);
4235    sd->long_tap_start_timeout = long_tap_start_timeout;
4236 }
4237
4238 EAPI double
4239 elm_gesture_layer_long_tap_start_timeout_get(const Evas_Object *obj)
4240 {
4241    ELM_GESTURE_LAYER_CHECK(obj) 0.0;
4242    ELM_GESTURE_LAYER_DATA_GET(obj, sd);
4243    return sd->long_tap_start_timeout;
4244 }
4245
4246 EAPI void
4247 elm_gesture_layer_continues_enable_set(Evas_Object *obj, Eina_Bool continues_enable)
4248 {
4249    ELM_GESTURE_LAYER_CHECK(obj);
4250    ELM_GESTURE_LAYER_DATA_GET(obj, sd);
4251    sd->glayer_continues_enable = continues_enable;
4252 }
4253
4254 EAPI Eina_Bool
4255 elm_gesture_layer_continues_enable_get(const Evas_Object *obj)
4256 {
4257    ELM_GESTURE_LAYER_CHECK(obj) 0.0;
4258    ELM_GESTURE_LAYER_DATA_GET(obj, sd);
4259    return sd->glayer_continues_enable;
4260 }
4261
4262 EAPI void
4263 elm_gesture_layer_double_tap_timeout_set(Evas_Object *obj, double double_tap_timeout)
4264 {
4265    ELM_GESTURE_LAYER_CHECK(obj);
4266    ELM_GESTURE_LAYER_DATA_GET(obj, sd);
4267    sd->double_tap_timeout = double_tap_timeout;
4268 }
4269
4270 EAPI double
4271 elm_gesture_layer_double_tap_timeout_get(const Evas_Object *obj)
4272 {
4273    ELM_GESTURE_LAYER_CHECK(obj) 0.0;
4274    ELM_GESTURE_LAYER_DATA_GET(obj, sd);
4275    return sd->double_tap_timeout;
4276 }
4277
4278 EAPI void
4279 elm_gesture_layer_tap_finger_size_set(Evas_Object *obj,
4280       Evas_Coord sz)
4281 {
4282    ELM_GESTURE_LAYER_CHECK(obj);
4283    eo_do(obj, elm_obj_gesture_layer_tap_finger_size_set(sz));
4284 }
4285
4286 static void
4287 _tap_finger_size_set(Eo *obj EINA_UNUSED, void *_pd, va_list *list)
4288 {
4289    Evas_Coord sz = va_arg(*list, Evas_Coord);
4290    Elm_Gesture_Layer_Smart_Data *sd = _pd;
4291
4292    if (sz < 0)
4293       sz = 0;  /* Should not be negative, will reset to system value */
4294
4295    sd->tap_finger_size = sz;
4296 }
4297
4298 EAPI Evas_Coord
4299 elm_gesture_layer_tap_finger_size_get(const Evas_Object *obj)
4300 {
4301    ELM_GESTURE_LAYER_CHECK(obj) elm_config_finger_size_get();
4302    Evas_Coord ret = 0;
4303    eo_do((Eo *) obj, elm_obj_gesture_layer_tap_finger_size_get(&ret));
4304    return ret;
4305 }
4306
4307 static void
4308 _tap_finger_size_get(Eo *obj EINA_UNUSED, void *_pd, va_list *list)
4309 {
4310    Evas_Coord *ret = va_arg(*list, Evas_Coord *);
4311    Elm_Gesture_Layer_Smart_Data *sd = _pd;
4312    *ret = sd->tap_finger_size;
4313 }
4314
4315 static void
4316 _class_constructor(Eo_Class *klass)
4317 {
4318    const Eo_Op_Func_Description func_desc[] = {
4319         EO_OP_FUNC(EO_BASE_ID(EO_BASE_SUB_ID_CONSTRUCTOR), _constructor),
4320
4321         EO_OP_FUNC(EVAS_OBJ_SMART_ID(EVAS_OBJ_SMART_SUB_ID_ADD), _elm_gesture_layer_smart_add),
4322         EO_OP_FUNC(EVAS_OBJ_SMART_ID(EVAS_OBJ_SMART_SUB_ID_DEL), _elm_gesture_layer_smart_del),
4323
4324         EO_OP_FUNC(ELM_WIDGET_ID(ELM_WIDGET_SUB_ID_DISABLE), _elm_gesture_layer_smart_disable),
4325
4326         EO_OP_FUNC(ELM_OBJ_GESTURE_LAYER_ID(ELM_OBJ_GESTURE_LAYER_SUB_ID_HOLD_EVENTS_GET), _hold_events_get),
4327         EO_OP_FUNC(ELM_OBJ_GESTURE_LAYER_ID(ELM_OBJ_GESTURE_LAYER_SUB_ID_HOLD_EVENTS_SET), _hold_events_set),
4328         EO_OP_FUNC(ELM_OBJ_GESTURE_LAYER_ID(ELM_OBJ_GESTURE_LAYER_SUB_ID_ZOOM_STEP_GET), _zoom_step_get),
4329         EO_OP_FUNC(ELM_OBJ_GESTURE_LAYER_ID(ELM_OBJ_GESTURE_LAYER_SUB_ID_ZOOM_STEP_SET), _zoom_step_set),
4330         EO_OP_FUNC(ELM_OBJ_GESTURE_LAYER_ID(ELM_OBJ_GESTURE_LAYER_SUB_ID_ROTATE_STEP_GET), _rotate_step_get),
4331         EO_OP_FUNC(ELM_OBJ_GESTURE_LAYER_ID(ELM_OBJ_GESTURE_LAYER_SUB_ID_ROTATE_STEP_SET), _rotate_step_set),
4332         EO_OP_FUNC(ELM_OBJ_GESTURE_LAYER_ID(ELM_OBJ_GESTURE_LAYER_SUB_ID_ATTACH), _attach),
4333         EO_OP_FUNC(ELM_OBJ_GESTURE_LAYER_ID(ELM_OBJ_GESTURE_LAYER_SUB_ID_CB_SET), _cb_set),
4334         EO_OP_FUNC(ELM_OBJ_GESTURE_LAYER_ID(ELM_OBJ_GESTURE_LAYER_SUB_ID_TAP_FINGER_SIZE_SET), _tap_finger_size_set),
4335         EO_OP_FUNC(ELM_OBJ_GESTURE_LAYER_ID(ELM_OBJ_GESTURE_LAYER_SUB_ID_TAP_FINGER_SIZE_GET), _tap_finger_size_get),
4336         EO_OP_FUNC(ELM_OBJ_GESTURE_LAYER_ID(ELM_OBJ_GESTURE_LAYER_SUB_ID_CB_ADD), _cb_add),
4337         EO_OP_FUNC(ELM_OBJ_GESTURE_LAYER_ID(ELM_OBJ_GESTURE_LAYER_SUB_ID_CB_DEL), _cb_del),
4338         EO_OP_FUNC_SENTINEL
4339    };
4340    eo_class_funcs_set(klass, func_desc);
4341
4342    evas_smart_legacy_type_register(MY_CLASS_NAME, klass);
4343 }
4344
4345 static const Eo_Op_Description op_desc[] = {
4346      EO_OP_DESCRIPTION(ELM_OBJ_GESTURE_LAYER_SUB_ID_HOLD_EVENTS_GET, "Call this function to get repeat-events settings."),
4347      EO_OP_DESCRIPTION(ELM_OBJ_GESTURE_LAYER_SUB_ID_HOLD_EVENTS_SET, "This function is to make gesture-layer repeat events."),
4348      EO_OP_DESCRIPTION(ELM_OBJ_GESTURE_LAYER_SUB_ID_ZOOM_STEP_GET, "This function returns step-value for zoom action."),
4349      EO_OP_DESCRIPTION(ELM_OBJ_GESTURE_LAYER_SUB_ID_ZOOM_STEP_SET, "This function sets step-value for zoom action."),
4350      EO_OP_DESCRIPTION(ELM_OBJ_GESTURE_LAYER_SUB_ID_ROTATE_STEP_GET, "This function returns step-value for rotate action."),
4351      EO_OP_DESCRIPTION(ELM_OBJ_GESTURE_LAYER_SUB_ID_ROTATE_STEP_SET, "This function sets step-value for rotate action."),
4352      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."),
4353      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."),
4354      EO_OP_DESCRIPTION(ELM_OBJ_GESTURE_LAYER_SUB_ID_TAP_FINGER_SIZE_SET, "Use function to set valid touch-area size for finger."),
4355      EO_OP_DESCRIPTION(ELM_OBJ_GESTURE_LAYER_SUB_ID_TAP_FINGER_SIZE_GET, "This function returns the valid touch-area size for finger."),
4356      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."),
4357      EO_OP_DESCRIPTION(ELM_OBJ_GESTURE_LAYER_SUB_ID_CB_DEL, "Use function to remove added callbacks."),
4358      EO_OP_DESCRIPTION_SENTINEL
4359 };
4360
4361 static const Eo_Class_Description class_desc = {
4362      EO_VERSION,
4363      MY_CLASS_NAME,
4364      EO_CLASS_TYPE_REGULAR,
4365      EO_CLASS_DESCRIPTION_OPS(&ELM_OBJ_GESTURE_LAYER_BASE_ID, op_desc, ELM_OBJ_GESTURE_LAYER_SUB_ID_LAST),
4366      NULL,
4367      sizeof(Elm_Gesture_Layer_Smart_Data),
4368      _class_constructor,
4369      NULL
4370 };
4371
4372 EO_DEFINE_CLASS(elm_obj_gesture_layer_class_get, &class_desc, ELM_OBJ_WIDGET_CLASS, NULL);