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