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