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