e_service_gesture: do not raise a gesture without 1st finger event
[platform/upstream/enlightenment.git] / src / bin / services / e_service_gesture.c
1 #include "e.h"
2 #include "services/e_service_gesture.h"
3
4 #define MAX_FINGERS 10
5 #define E_SERVICE_GESTURE_KEY "e_service_gesture_enabled"
6
7 typedef enum
8 {
9    POL_GESTURE_STATUS_NONE,
10    POL_GESTURE_STATUS_READY,
11    POL_GESTURE_STATUS_ACTIVE,
12    POL_GESTURE_STATUS_CANCEL
13 } E_Policy_Gesture_Status;
14
15 struct _E_Policy_Gesture
16 {
17    Evas_Object *obj;
18    E_Policy_Gesture_Type type;
19
20    E_Policy_Gesture_Status status;
21
22    unsigned int set_fingers;
23    int pressed_fingers;
24    int gesture_fingers;
25
26    int angle;
27    Ecore_Timer *waiting_timer;
28
29    double wait_time;
30    int wait_dist;
31
32    unsigned int timestamp;
33    Evas_Coord_Point c_start;
34
35    struct
36      {
37         Eina_Bool pressed; /* to avoid processing that happened mouse move right after mouse up */
38
39         Evas_Coord_Point start;
40         Evas_Coord_Point cur;
41      } touch_info[MAX_FINGERS];
42
43    struct
44      {
45         E_Policy_Gesture_Start_Cb start;
46         E_Policy_Gesture_Move_Cb move;
47         E_Policy_Gesture_End_Cb end;
48         void *data;
49      } cb;
50 };
51
52 static void
53 _gesture_util_center_start_point_get(E_Policy_Gesture *gesture, int *cx, int *cy)
54 {
55    int i;
56    Evas_Coord_Point total_point = {0, };
57
58    if (!gesture->pressed_fingers) return;
59
60    for (i = 0; i < gesture->pressed_fingers; i++)
61      {
62         total_point.x += gesture->touch_info[i].start.x;
63         total_point.y += gesture->touch_info[i].start.y;
64      }
65
66    total_point.x = (int)(total_point.x / gesture->pressed_fingers);
67    total_point.y = (int)(total_point.y / gesture->pressed_fingers);
68
69    *cx = total_point.x;
70    *cy = total_point.y;
71 }
72
73 static void
74 _gesture_util_center_cur_point_get(E_Policy_Gesture *gesture, int *cx, int *cy)
75 {
76    int i, touch_num;
77    Evas_Coord_Point total_point = {0, };
78
79    if (!gesture->pressed_fingers) return;
80
81    touch_num = gesture->pressed_fingers;
82
83    for (i = 0; i < touch_num; i++)
84      {
85         if (!gesture->touch_info[i].pressed)
86           {
87              touch_num++;
88              continue;
89           }
90         total_point.x += gesture->touch_info[i].cur.x;
91         total_point.y += gesture->touch_info[i].cur.y;
92      }
93
94    total_point.x = (int)(total_point.x / gesture->pressed_fingers);
95    total_point.y = (int)(total_point.y / gesture->pressed_fingers);
96
97    *cx = total_point.x;
98    *cy = total_point.y;
99 }
100
101 static E_Policy_Gesture_Status
102 _gesture_line_check(E_Policy_Gesture *gesture, int x, int y, int sensitivity)
103 {
104    int dx, dy;
105
106    dx = x - gesture->c_start.x;
107    dy = y - gesture->c_start.y;
108
109    if (gesture->angle == 0 || gesture->angle == 180)
110      {
111         if (abs(dy) < sensitivity)
112           return POL_GESTURE_STATUS_READY;
113      }
114    else if (gesture->angle == 90 || gesture->angle == 270)
115      {
116         if (abs(dx) < sensitivity)
117           return POL_GESTURE_STATUS_READY;
118      }
119    else
120      {
121         if ((abs(dy) < sensitivity) &&
122             (abs(dx) < sensitivity))
123           return POL_GESTURE_STATUS_READY;
124      }
125
126    return POL_GESTURE_STATUS_ACTIVE;
127 }
128
129 static E_Policy_Gesture_Status
130 _gesture_flick_check(E_Policy_Gesture *gesture, Evas_Object *obj, int x, int y, unsigned int timestamp)
131 {
132    int dy;
133    int ox, oy, ow, oh;
134    unsigned int dt;
135    float vel = 0.0;
136    const float sensitivity = 0.25; /* FIXME: hard coded, it sould be configurable. */
137
138    evas_object_geometry_get(obj, &ox, &oy, &ow, &oh);
139    if (!E_INSIDE(x, y, ox, oy, ow, oh))
140      return POL_GESTURE_STATUS_READY;
141
142    dy = y - gesture->c_start.y;
143    dt = timestamp - gesture->timestamp;
144    if (dt == 0)
145      return POL_GESTURE_STATUS_READY;
146
147    vel = (float)dy / (float)dt;
148    if (fabs(vel) < sensitivity)
149      return POL_GESTURE_STATUS_READY;
150
151    return POL_GESTURE_STATUS_ACTIVE;
152 }
153
154 static E_Policy_Gesture_Status
155 _gesture_check(E_Policy_Gesture *gesture, Evas_Object *obj, int x, int y, unsigned int timestamp)
156 {
157    E_Policy_Gesture_Status ret = POL_GESTURE_STATUS_READY;
158
159    if (gesture->waiting_timer)
160      {
161         // All waiting fingers are not pressed. So waiting other fingers
162         return ret;
163      }
164
165    switch (gesture->type)
166      {
167       case POL_GESTURE_TYPE_NONE:
168          ret = POL_GESTURE_STATUS_ACTIVE;
169          break;
170       case POL_GESTURE_TYPE_LINE:
171          /* FIXME: sensitivity is hard coded, it sould be configurable. */
172          ret = _gesture_line_check(gesture, x, y, 50);
173          break;
174       case POL_GESTURE_TYPE_FLICK:
175          ret = _gesture_flick_check(gesture, obj, x, y, timestamp);
176          break;
177       default:
178          WRN("Unknown gesture type %d", gesture->type);
179          break;
180      }
181
182    if ((ret == POL_GESTURE_STATUS_ACTIVE) &&
183        !gesture->gesture_fingers)
184      {
185         gesture->gesture_fingers = gesture->pressed_fingers;
186      }
187
188    return ret;
189 }
190
191 static void
192 _gesture_cleanup(E_Policy_Gesture *gesture)
193 {
194    gesture->pressed_fingers = 0;
195    gesture->gesture_fingers = 0;
196    gesture->status = POL_GESTURE_STATUS_READY;
197    if (gesture->waiting_timer)
198      {
199         ecore_timer_del(gesture->waiting_timer);
200         gesture->waiting_timer = NULL;
201      }
202 }
203
204 static void
205 _gesture_cancel(E_Policy_Gesture *gesture)
206 {
207    gesture->status = POL_GESTURE_STATUS_CANCEL;
208 }
209
210 static void
211 _gesture_start(E_Policy_Gesture *gesture)
212 {
213    if (gesture->set_fingers & (1 << gesture->pressed_fingers))
214      {
215         if (gesture->set_fingers < (1 << (gesture->pressed_fingers + 1)))
216           {
217              // All of waiting fingers are come. Stop waiting other fingers
218              if (gesture->waiting_timer)
219                {
220                   ecore_timer_del(gesture->waiting_timer);
221                   gesture->waiting_timer = NULL;
222                }
223           }
224      }
225 }
226
227 static Eina_Bool
228 _gesture_waiting_timer(void *data)
229 {
230    E_Policy_Gesture *gesture = data;
231    unsigned int timestamp;
232
233    ecore_timer_del(gesture->waiting_timer);
234    gesture->waiting_timer = NULL;
235
236    if (gesture->set_fingers & (1 << gesture->pressed_fingers))
237      {
238         timestamp = e_util_timestamp_get();
239         gesture->status = _gesture_check(gesture, gesture->obj, gesture->c_start.x, gesture->c_start.y, timestamp);
240         if (gesture->status == POL_GESTURE_STATUS_ACTIVE)
241           {
242              if (gesture->cb.start)
243                {
244                   gesture->cb.start(gesture->cb.data, gesture->obj, gesture->gesture_fingers, gesture->c_start.x, gesture->c_start.y, timestamp);
245                }
246           }
247         gesture->gesture_fingers = gesture->pressed_fingers;
248      }
249    else
250      {
251         _gesture_cancel(gesture);
252      }
253
254    return ECORE_CALLBACK_CANCEL;
255 }
256
257 static void
258 _gesture_touch_up(E_Policy_Gesture *gesture, Evas_Object *obj, int idx, int x, int y, int timestamp)
259 {
260    int cx = 0, cy = 0;
261
262    switch (gesture->status)
263      {
264         case POL_GESTURE_STATUS_READY:
265           gesture->touch_info[idx].pressed = EINA_FALSE;
266           _gesture_cancel(gesture);
267           break;
268
269         case POL_GESTURE_STATUS_ACTIVE:
270           gesture->touch_info[idx].pressed = EINA_FALSE;
271           gesture->touch_info[idx].cur.x = x;
272           gesture->touch_info[idx].cur.y = y;
273           _gesture_util_center_cur_point_get(gesture, &cx, &cy);
274
275           if (gesture->pressed_fingers <= 0)
276             {
277                if (gesture->cb.end)
278                  {
279                     gesture->cb.end(gesture->cb.data, obj, gesture->gesture_fingers, cx, cy, timestamp);
280                  }
281             }
282           break;
283
284         case POL_GESTURE_STATUS_CANCEL:
285           break;
286
287         default:
288           break;
289      }
290
291    if (gesture->pressed_fingers <= 0)
292      {
293         _gesture_cleanup(gesture);
294      }
295 }
296
297 static void
298 _gesture_touch_move(E_Policy_Gesture *gesture, Evas_Object *obj, int idx, int x, int y, int timestamp)
299 {
300    int cx = 0, cy = 0;
301
302    switch (gesture->status)
303      {
304         case POL_GESTURE_STATUS_READY:
305           gesture->touch_info[idx].cur.x = x;
306           gesture->touch_info[idx].cur.y = y;
307
308           _gesture_util_center_cur_point_get(gesture, &cx, &cy);
309           if (gesture->waiting_timer)
310             {
311                if (_gesture_line_check(gesture, cx, cy, gesture->wait_dist) == POL_GESTURE_STATUS_ACTIVE)
312                  {
313                     ecore_timer_del(gesture->waiting_timer);
314                     gesture->waiting_timer = NULL;
315                     if (!(gesture->set_fingers & (1 << gesture->pressed_fingers)))
316                       {
317                          _gesture_cancel(gesture);
318                          return;
319                       }
320                  }
321             }
322
323           gesture->status = _gesture_check(gesture, obj, cx, cy, timestamp);
324           if (gesture->status == POL_GESTURE_STATUS_ACTIVE)
325             {
326                if (gesture->cb.start)
327                  {
328                     gesture->cb.start(gesture->cb.data, obj, gesture->gesture_fingers, gesture->c_start.x, gesture->c_start.y, timestamp);
329                  }
330             }
331           else
332             return;
333           break;
334
335         case POL_GESTURE_STATUS_ACTIVE:
336           gesture->touch_info[idx].cur.x = x;
337           gesture->touch_info[idx].cur.y = y;
338
339           _gesture_util_center_cur_point_get(gesture, &cx, &cy);
340           break;
341
342         case POL_GESTURE_STATUS_CANCEL:
343           return;
344
345         default:
346           return;
347      }
348
349    if (gesture->cb.move)
350      gesture->cb.move(gesture->cb.data, obj, gesture->gesture_fingers, cx, cy, timestamp);
351 }
352
353 static void
354 _gesture_touch_down(E_Policy_Gesture *gesture, Evas_Object *obj, int idx, Evas_Coord x, Evas_Coord y, unsigned int timestamp)
355 {
356    int cx = 0, cy = 0;
357
358    switch (gesture->status)
359      {
360         case POL_GESTURE_STATUS_READY:
361           gesture->touch_info[idx].pressed = EINA_TRUE;
362           gesture->touch_info[idx].cur.x = gesture->touch_info[idx].start.x = x;
363           gesture->touch_info[idx].cur.y = gesture->touch_info[idx].start.y = y;
364
365           if (gesture->set_fingers < (1 << (idx + 1)))
366             {
367                // too many fingers are touched
368                _gesture_cancel(gesture);
369                break;
370             }
371
372           if (gesture->gesture_fingers)
373             {
374                // already gesture is begin(or definited), so ignore meaningless touch.
375                break;
376             }
377
378           gesture->timestamp = timestamp;
379
380           if (gesture->pressed_fingers == 1)
381             {
382                gesture->c_start.x = x;
383                gesture->c_start.y = y;
384                if (gesture->set_fingers > 2)
385                  gesture->waiting_timer = ecore_timer_add(gesture->wait_time, _gesture_waiting_timer, (void *)gesture);
386             }
387           else
388             {
389                _gesture_util_center_start_point_get(gesture, &cx, &cy);
390                gesture->c_start.x = cx;
391                gesture->c_start.y = cy;
392             }
393
394           _gesture_start(gesture);
395
396           gesture->status = _gesture_check(gesture, obj, x, y, timestamp);
397           if (gesture->status == POL_GESTURE_STATUS_ACTIVE)
398             {
399                if (gesture->cb.start)
400                  gesture->cb.start(gesture->cb.data, obj, gesture->gesture_fingers, gesture->c_start.x, gesture->c_start.y, timestamp);
401             }
402           break;
403
404         case POL_GESTURE_STATUS_ACTIVE:
405           gesture->touch_info[idx].pressed = EINA_TRUE;
406           break;
407
408         case POL_GESTURE_STATUS_CANCEL:
409           break;
410
411         default:
412           break;
413      }
414 }
415
416 static void
417 _gesture_obj_cb_mouse_up(void *data, Evas *evas EINA_UNUSED, Evas_Object *obj, void *event)
418 {
419    E_Policy_Gesture *gesture = data;
420    Evas_Event_Mouse_Up *ev = event;
421
422    gesture->pressed_fingers--;
423    _gesture_touch_up(gesture, obj, 0, ev->canvas.x, ev->canvas.y, ev->timestamp);
424 }
425
426 static void
427 _gesture_obj_cb_mouse_move(void *data, Evas *evas EINA_UNUSED, Evas_Object *obj, void *event)
428 {
429    E_Policy_Gesture *gesture = data;
430    Evas_Event_Mouse_Move *ev = event;
431
432    if (!gesture->touch_info[0].pressed)
433      return;
434
435    _gesture_touch_move(gesture, obj, 0, ev->cur.canvas.x, ev->cur.canvas.y, ev->timestamp);
436 }
437
438 static void
439 _gesture_obj_cb_mouse_down(void *data, Evas *evas EINA_UNUSED, Evas_Object *obj, void *event)
440 {
441    E_Policy_Gesture *gesture = data;
442    Evas_Event_Mouse_Down *ev = event;
443
444    gesture->pressed_fingers++;
445    _gesture_touch_down(data, obj, 0, ev->canvas.x, ev->canvas.y, ev->timestamp);
446 }
447
448 static void
449 _gesture_obj_cb_multi_up(void *data, Evas *evas EINA_UNUSED, Evas_Object *obj, void *event)
450 {
451    E_Policy_Gesture *gesture = data;
452    Evas_Event_Multi_Up *ev = event;
453
454    if (gesture->gesture_fingers &&
455        (gesture->gesture_fingers < (ev->device + 1)))
456      {
457         // already gesture is begin(or definited), so ignore meaningless touch
458         return;
459      }
460
461    if (!gesture->touch_info[ev->device].pressed)
462      {
463         return;
464      }
465
466    gesture->pressed_fingers--;
467    _gesture_touch_up(gesture, obj, ev->device, ev->canvas.x, ev->canvas.y, ev->timestamp);
468 }
469
470 static void
471 _gesture_obj_cb_multi_move(void *data, Evas *evas EINA_UNUSED, Evas_Object *obj, void *event)
472 {
473    E_Policy_Gesture *gesture = data;
474    Evas_Event_Multi_Move *ev = event;
475
476    if (!gesture->touch_info[ev->device].pressed)
477      return;
478
479    _gesture_touch_move(gesture, obj, ev->device, ev->cur.canvas.x, ev->cur.canvas.y, ev->timestamp);
480 }
481
482 static void
483 _gesture_obj_cb_multi_down(void *data, Evas *evas EINA_UNUSED, Evas_Object *obj, void *event)
484 {
485    E_Policy_Gesture *gesture = data;
486    Evas_Event_Multi_Down *ev = event;
487
488    if (gesture->gesture_fingers &&
489        (gesture->gesture_fingers < (ev->device + 1)))
490      {
491         // already gesture is begin(or definited), so ignore meaningless touch
492         return;
493      }
494
495    if (gesture->pressed_fingers <= 0)
496      {
497        // 1st finger's event didn't come, so ignore meaningless touch
498        return;
499      }
500
501    gesture->pressed_fingers++;
502
503    _gesture_touch_down(data, obj, ev->device, ev->canvas.x, ev->canvas.y, ev->timestamp);
504 }
505
506 E_API E_Policy_Gesture *
507 e_service_gesture_add(Evas_Object *obj, E_Policy_Gesture_Type type, int nfingers)
508 {
509    E_Policy_Gesture *gesture;
510
511    EINA_SAFETY_ON_NULL_RETURN_VAL(obj, NULL);
512
513    if (evas_object_data_get(obj, E_SERVICE_GESTURE_KEY))
514      {
515         WRN("obj(%p) is already added gesture.\n", obj);
516         return NULL;
517      }
518
519    gesture = E_NEW(E_Policy_Gesture, 1);
520    if (EINA_UNLIKELY(gesture == NULL))
521      return NULL;
522
523    gesture->obj = obj;
524    gesture->type = type;
525    gesture->set_fingers |= 1 << nfingers;
526
527    // attempt to get wait_time and wait_dist to config file.
528    // but if failed, set default VALUE
529    if (e_config)
530      {
531         if (e_config->gesture_service.wait_time)
532           gesture->wait_time = e_config->gesture_service.wait_time;
533         if (e_config->gesture_service.wait_dist)
534           gesture->wait_dist = e_config->gesture_service.wait_dist;
535      }
536    if (!gesture->wait_time)
537      gesture->wait_time = 0.1;
538    if (!gesture->wait_dist)
539      gesture->wait_dist = 50;
540    gesture->status = POL_GESTURE_STATUS_READY;
541
542    /* we should to repeat mouse event to below object
543     * until we can make sure gesture */
544    if (type != POL_GESTURE_TYPE_NONE)
545      evas_object_repeat_events_set(obj, EINA_TRUE);
546
547    evas_object_event_callback_add(obj, EVAS_CALLBACK_MOUSE_DOWN,
548                                   _gesture_obj_cb_mouse_down, gesture);
549    evas_object_event_callback_add(obj, EVAS_CALLBACK_MOUSE_MOVE,
550                                   _gesture_obj_cb_mouse_move, gesture);
551    evas_object_event_callback_add(obj, EVAS_CALLBACK_MOUSE_UP,
552                                   _gesture_obj_cb_mouse_up, gesture);
553    evas_object_event_callback_add(obj, EVAS_CALLBACK_MULTI_DOWN,
554                                   _gesture_obj_cb_multi_down, gesture);
555    evas_object_event_callback_add(obj, EVAS_CALLBACK_MULTI_MOVE,
556                                   _gesture_obj_cb_multi_move, gesture);
557    evas_object_event_callback_add(obj, EVAS_CALLBACK_MULTI_UP,
558                                   _gesture_obj_cb_multi_up, gesture);
559
560    evas_object_data_set(obj, E_SERVICE_GESTURE_KEY, (void *)1);
561
562    return gesture;
563 }
564
565 E_API void
566 e_service_gesture_del(E_Policy_Gesture *gesture)
567 {
568    EINA_SAFETY_ON_NULL_RETURN(gesture);
569
570    evas_object_event_callback_del(gesture->obj, EVAS_CALLBACK_MOUSE_DOWN,
571                                   _gesture_obj_cb_mouse_down);
572    evas_object_event_callback_del(gesture->obj, EVAS_CALLBACK_MOUSE_MOVE,
573                                   _gesture_obj_cb_mouse_move);
574    evas_object_event_callback_del(gesture->obj, EVAS_CALLBACK_MOUSE_UP,
575                                   _gesture_obj_cb_mouse_up);
576    evas_object_event_callback_del(gesture->obj, EVAS_CALLBACK_MULTI_DOWN,
577                                   _gesture_obj_cb_multi_down);
578    evas_object_event_callback_del(gesture->obj, EVAS_CALLBACK_MULTI_MOVE,
579                                   _gesture_obj_cb_multi_move);
580    evas_object_event_callback_del(gesture->obj, EVAS_CALLBACK_MULTI_UP,
581                                   _gesture_obj_cb_multi_up);
582
583    evas_object_data_del(gesture->obj, E_SERVICE_GESTURE_KEY);
584
585    E_FREE_FUNC(gesture->waiting_timer, ecore_timer_del);
586
587    free(gesture);
588 }
589
590 E_API void
591 e_service_gesture_type_set(E_Policy_Gesture *gesture, E_Policy_Gesture_Type type)
592 {
593    EINA_SAFETY_ON_NULL_RETURN(gesture);
594
595    if (gesture->type == type)
596      return;
597
598    gesture->type = type;
599    if (type == POL_GESTURE_TYPE_NONE)
600      evas_object_repeat_events_set(gesture->obj, EINA_FALSE);
601    else
602      evas_object_repeat_events_set(gesture->obj, EINA_TRUE);
603 }
604
605 E_API void
606 e_service_gesture_cb_set(E_Policy_Gesture *gesture, E_Policy_Gesture_Start_Cb cb_start, E_Policy_Gesture_Move_Cb cb_move, E_Policy_Gesture_End_Cb cb_end, void *data)
607 {
608    EINA_SAFETY_ON_NULL_RETURN(gesture);
609
610    gesture->cb.start = cb_start;
611    gesture->cb.move = cb_move;
612    gesture->cb.end = cb_end;
613    gesture->cb.data = data;
614 }
615
616 E_API void
617 e_service_gesture_angle_set(E_Policy_Gesture *gesture, int angle)
618 {
619    EINA_SAFETY_ON_NULL_RETURN(gesture);
620    gesture->angle = angle;
621 }
622
623 E_API void
624 e_service_gesture_fingers_set(E_Policy_Gesture *gesture, int nfingers)
625 {
626    EINA_SAFETY_ON_NULL_RETURN(gesture);
627
628    if (gesture->set_fingers & (1 << nfingers))
629      return;
630    gesture->set_fingers |= 1 << nfingers;
631 }
632
633 E_API void
634 e_service_gesture_wait_time_set(E_Policy_Gesture *gesture, double wait_time)
635 {
636    EINA_SAFETY_ON_NULL_RETURN(gesture);
637    gesture->wait_time = wait_time;
638 }
639
640 E_API void
641 e_service_gesture_wait_dist_set(E_Policy_Gesture *gesture, int wait_dist)
642 {
643    EINA_SAFETY_ON_NULL_RETURN(gesture);
644    gesture->wait_dist = wait_dist;
645 }
646