1522359dab2aad6b3a63858469661b670dc2bfde
[platform/core/uifw/e17-extra-modules.git] / screen-reader / src / e_mod_main.c
1 #include <Elementary.h>
2 #include <vconf.h>
3 #include "e.h"
4 #include "e_mod_main.h"
5 #define HISTORY_MAX 8
6 #define DEBUG_INFO 0
7
8 #if DEBUG_INFO
9   #define INFO(cov, txt) \
10     evas_object_text_text_set(cov->text, txt); \
11     INF("%s", txt)
12 #else
13   #define INFO(cov, txt) INF("%s -> %x", txt, target_win)
14 #endif
15
16 #define MOUSE_BUTTON_DOWN 0
17 #define MOUSE_MOVE 1
18 #define MOUSE_BUTTON_UP 2
19
20 typedef struct
21 {
22    E_Zone         *zone;
23    Ecore_X_Window  win;
24    Ecore_X_Window  down_win;
25    Ecore_Timer    *timer;
26    Ecore_Timer    *double_down_timer;
27    Ecore_Timer    *tap_timer;
28    Evas_Object    *info;
29    Evas_Object    *text;
30    int             x, y, dx, dy, mx, my;
31    int             mouse_history[HISTORY_MAX];
32    unsigned int    dt;
33    unsigned int    n_taps;
34    Eina_Inarray   *two_finger_move;
35    Eina_Inlist    *history;
36
37    Ecore_X_Atom    atom_control_panel_open;
38    Ecore_X_Atom    atom_app_tray_open;
39
40    Eina_Bool       longpressed : 1;
41    Eina_Bool       two_finger_down : 1;
42    Eina_Bool       three_finger_down : 1;
43    Eina_Bool       mouse_double_down : 1;
44    Eina_Bool       lock_screen : 1;
45 } Cover;
46
47 typedef struct
48 {
49    EINA_INLIST;
50    int             device;
51 } Multi;
52
53 static int g_enable = 0;
54 static Ecore_X_Window target_win = 0;
55 static Ecore_X_Window unfocused_win = 0;
56
57 static Eina_List *covers = NULL;
58 static Eina_List *handlers = NULL;
59 static Ecore_Event_Handler *property_handler = NULL;
60
61 static void _move_module_enable_set(int enable);
62
63 static void
64 _mouse_in_win_get(Cover *cov, int x, int y)
65 {
66    E_Border *bd;
67    Eina_List *l;
68    Ecore_X_Window *skip;
69    Ecore_X_Window win = 0;
70    Cover *cov2;
71    int i;
72
73    skip = alloca(sizeof(Ecore_X_Window) * eina_list_count(covers));
74    i = 0;
75    EINA_LIST_FOREACH(covers, l, cov2)
76      {
77         skip[i] = cov2->win;
78         i++;
79      }
80    win = ecore_x_window_shadow_tree_at_xy_with_skip_get
81      (cov->zone->container->manager->root, x, y, skip, i);
82
83    if (win != target_win)
84      {
85         target_win = win;
86
87         bd = e_border_focused_get();
88         if (bd && (bd->client.win != target_win))
89           unfocused_win = target_win;
90         else
91           unfocused_win = 0;
92      }
93 }
94
95 static unsigned int
96 _win_angle_get(Ecore_X_Window win)
97 {
98    Ecore_X_Window root;
99
100    if (!win) return 0;
101
102    int ret;
103    int count;
104    int angle = 0;
105    unsigned char *prop_data = NULL;
106
107    root = ecore_x_window_root_get(win);
108    ret = ecore_x_window_prop_property_get(root,
109        ECORE_X_ATOM_E_ILLUME_ROTATE_ROOT_ANGLE,
110                          ECORE_X_ATOM_CARDINAL,
111                         32, &prop_data, &count);
112
113    if (ret && prop_data)
114       memcpy (&angle, prop_data, sizeof (int));
115
116    if (prop_data) free (prop_data);
117
118    return angle;
119 }
120
121 static void
122 _cov_data_reset(Cover *cov)
123 {
124    cov->n_taps = 0;
125    cov->longpressed = EINA_FALSE;
126    cov->two_finger_down = EINA_FALSE;
127    cov->two_finger_move = EINA_FALSE;
128    cov->mouse_double_down = EINA_FALSE;
129    cov->three_finger_down = EINA_FALSE;
130    cov->lock_screen = EINA_FALSE;
131
132    if (cov->timer)
133      {
134         ecore_timer_del(cov->timer);
135         cov->timer = NULL;
136      }
137
138    if (cov->double_down_timer)
139      {
140         ecore_timer_del(cov->double_down_timer);
141         cov->double_down_timer = NULL;
142      }
143
144    if (cov->tap_timer)
145      {
146         ecore_timer_del(cov->tap_timer);
147         cov->tap_timer = NULL;
148      }
149 }
150
151 static void
152 _screen_reader_support_check()
153 {
154    int ret;
155    unsigned int val;
156    Eina_List *l;
157    Cover *cov;
158
159    ret = ecore_x_window_prop_card32_get
160       (target_win, ECORE_X_ATOM_E_ILLUME_ACCESS_CONTROL, &val, 1);
161
162    if ((ret >= 0) && (val == 2))
163      {
164         /* hide input window */
165         EINA_LIST_FOREACH(covers, l, cov)
166           {
167              ecore_x_window_hide(cov->win);
168              _cov_data_reset(cov);
169           }
170
171         _move_module_enable_set(EINA_FALSE);
172      }
173    else
174      {
175         /* show input window */
176         EINA_LIST_FOREACH(covers, l, cov)
177           {
178              ecore_x_window_show(cov->win);
179           }
180
181         _move_module_enable_set(EINA_TRUE);
182      }
183 }
184
185 static void
186 _target_window_find()
187 {
188    Ecore_X_Window win;
189    E_Border *bd;
190    unsigned int val;
191    int ret;
192
193    /* find proper target window to send a meesage */
194    Eina_List *borders, *l;
195
196    win = 0;
197    borders = e_border_client_list();
198    EINA_LIST_REVERSE_FOREACH(borders, l, bd)
199      {
200         if (!bd->visible) continue;
201         if (bd->client.netwm.type == ECORE_X_WINDOW_TYPE_NORMAL) break;
202
203         ret = ecore_x_window_prop_card32_get
204            (bd->client.win, ECORE_X_ATOM_E_ILLUME_ACCESS_CONTROL, &val, 1);
205
206        if ((ret >= 0) && (val == 1))
207          {
208             win = bd->client.win;
209             break;
210          }
211      }
212
213    /* there would be an unfocused window which does not have 'val == 1'
214       such as an window of virtual keyboard. if the window is selected by
215       _mouse_in_win_get(); previously with the unfocused window, the target
216       window should be the unfocused window */
217    if (win) target_win = win;
218    else
219      {
220         if (unfocused_win) target_win = unfocused_win;
221         else
222           {
223              bd = e_border_focused_get();
224              if (bd) target_win = bd->client.win;
225           }
226      }
227 }
228
229 static void
230 _lock_screen_check(Cover *cov)
231 {
232    Ecore_X_Window win;
233    E_Border *bd;
234    const char *name = NULL;
235    const char *clas = NULL;
236
237    Eina_List *borders, *l;
238
239    cov->lock_screen = EINA_FALSE;
240    win = 0;
241    borders = e_border_client_list();
242    EINA_LIST_REVERSE_FOREACH(borders, l, bd)
243      {
244         if (!bd) continue;
245         if (!bd->visible) continue;
246
247         name = bd->client.icccm.name;
248         clas = bd->client.icccm.class;
249
250         if (clas == NULL || name == NULL) continue;
251         if (strncmp(clas,"LOCK_SCREEN",strlen("LOCK_SCREEN"))!= 0) continue;
252         if (strncmp(name,"LOCK_SCREEN",strlen("LOCK_SCREEN"))!= 0) continue;
253
254         INF("lock screen is detected");
255         cov->lock_screen = EINA_TRUE;
256
257         break;
258      }
259 }
260
261 static void
262 _app_tray_open(Cover *cov)
263 {
264    Ecore_X_Window win;
265    E_Border *bd;
266    const char *name = NULL;
267    const char *clas = NULL;
268
269    Eina_List *borders, *l;
270
271    win = 0;
272    borders = e_border_client_list();
273    EINA_LIST_REVERSE_FOREACH(borders, l, bd)
274      {
275         if (!bd) continue;
276         if (!bd->visible) continue;
277         if (bd->client.netwm.type != ECORE_X_WINDOW_TYPE_NORMAL) break;
278
279         name = bd->client.icccm.name;
280         clas = bd->client.icccm.class;
281
282         if (clas == NULL || name == NULL) continue;
283         if (strncmp(clas,"MINIAPP_TRAY",strlen("MINIAPP_TRAY"))!= 0) continue;
284         if (strncmp(name,"MINIAPP_TRAY",strlen("MINIAPP_TRAY"))!= 0) continue;
285
286         /* open mini app tray */
287         INF("open app tray");
288         ecore_x_client_message32_send(bd->client.win, ECORE_X_ATOM_E_ILLUME_ACCESS_CONTROL,
289                                       ECORE_X_EVENT_MASK_WINDOW_CONFIGURE,
290                                       bd->client.win,
291                                       cov->atom_app_tray_open,
292                                       0, 0, 0);
293         break;
294      }
295 }
296
297 static void
298 _quickpanel_open(void)
299 {
300    Ecore_X_Window win;
301    E_Border *bd;
302    const char *name = NULL;
303    const char *clas = NULL;
304
305    Eina_List *borders, *l;
306
307    win = 0;
308    borders = e_border_client_list();
309    EINA_LIST_REVERSE_FOREACH(borders, l, bd)
310      {
311         if (!bd) continue;
312         if (!bd->visible) continue;
313         if (bd->client.netwm.type != ECORE_X_WINDOW_TYPE_NORMAL) break;
314
315         name = bd->client.icccm.name;
316         clas = bd->client.icccm.class;
317
318         if (clas == NULL || name == NULL) continue;
319         if (strncmp(clas,"QUICKPANEL",strlen("QUICKPANEL"))!= 0) continue;
320         if (strncmp(name,"QUICKPANEL",strlen("QUICKPANEL"))!= 0) continue;
321
322         /* open quickpanel */
323         INF("open quickpanel");
324         ecore_x_e_illume_quickpanel_state_send
325           (ecore_x_e_illume_zone_get(bd->client.win),
326            ECORE_X_ILLUME_QUICKPANEL_STATE_ON);
327         break;
328      }
329 }
330
331 static void
332 _coordinate_calibrate(Ecore_X_Window win, int *x, int *y)
333 {
334    int tx, ty, w, h;
335    unsigned int angle;
336
337    if (!x) return;
338    if (!y) return;
339
340    angle = _win_angle_get(win);
341    ecore_x_window_geometry_get(win, NULL, NULL, &w, &h);
342
343    tx = *x;
344    ty = *y;
345
346    switch (angle)
347      {
348       case 90:
349         *x = h - ty;
350         *y = tx;
351         break;
352
353       case 180:
354         *x = w - tx;
355         *y = h - ty;
356         break;
357
358       case 270:
359         *x = ty;
360         *y = w - tx;
361         break;
362
363       default:
364         break;
365      }
366 }
367
368 static void
369 _mouse_win_fake_tap(Cover *cov, Ecore_Event_Mouse_Button *ev)
370 {
371    int x, y;
372
373    /* find target window to send message */
374    _mouse_in_win_get(cov, ev->root.x, ev->root.y);
375
376    ecore_x_pointer_xy_get(target_win, &x, &y);
377    ecore_x_mouse_in_send(target_win, x, y);
378    ecore_x_mouse_move_send(target_win, x, y);
379    ecore_x_mouse_down_send(target_win, x, y, 1);
380    ecore_x_mouse_up_send(target_win, x, y, 1);
381    ecore_x_mouse_out_send(target_win, x, y);
382 }
383
384 static void
385 _message_control_panel_open_send(Cover *cov)
386 {
387    ecore_x_client_message32_send(target_win, ECORE_X_ATOM_E_ILLUME_ACCESS_CONTROL,
388                                  ECORE_X_EVENT_MASK_WINDOW_CONFIGURE,
389                                  target_win,
390                                  cov->atom_control_panel_open,
391                                  0, 0, 0);
392 }
393
394 static void
395 _message_back_send(Cover *cov)
396 {
397    ecore_x_client_message32_send(target_win, ECORE_X_ATOM_E_ILLUME_ACCESS_CONTROL,
398                                  ECORE_X_EVENT_MASK_WINDOW_CONFIGURE,
399                                  target_win,
400                                  ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_BACK,
401                                  0, 0, 0);
402 }
403
404 static void
405 _message_scroll_send(Cover *cov, int type)
406 {
407    int x, y;
408    Ecore_X_Atom atom;
409
410    atom = ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_SCROLL;
411    if (cov->lock_screen) atom = ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_MOUSE;
412
413    ecore_x_pointer_xy_get(target_win, &x, &y);
414    _coordinate_calibrate(target_win, &x, &y);
415
416    ecore_x_client_message32_send(target_win, ECORE_X_ATOM_E_ILLUME_ACCESS_CONTROL,
417                                  ECORE_X_EVENT_MASK_WINDOW_CONFIGURE,
418                                  target_win,
419                                  atom,
420                                  type, x, y);
421 }
422
423 static void
424 _message_mouse_send(Cover *cov, int type)
425 {
426    int x, y;
427
428    ecore_x_pointer_xy_get(cov->down_win, &x, &y);
429    _coordinate_calibrate(cov->down_win, &x, &y);
430
431    ecore_x_client_message32_send(cov->down_win, ECORE_X_ATOM_E_ILLUME_ACCESS_CONTROL,
432                                  ECORE_X_EVENT_MASK_WINDOW_CONFIGURE,
433                                  cov->down_win,
434                                  ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_MOUSE,
435                                  type, x, y);
436 }
437
438 static void
439 _message_read_send(Cover *cov)
440 {
441    int x, y;
442
443    /* find target window to send message */
444    _mouse_in_win_get(cov, cov->x, cov->y);
445
446    ecore_x_pointer_xy_get(target_win, &x, &y);
447    _coordinate_calibrate(target_win, &x, &y);
448
449    ecore_x_client_message32_send(target_win, ECORE_X_ATOM_E_ILLUME_ACCESS_CONTROL,
450                                  ECORE_X_EVENT_MASK_WINDOW_CONFIGURE,
451                                  target_win,
452                                  ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_READ,
453                                  x, y, 0);
454 }
455
456 static Eina_Bool
457 _mouse_longpress(void *data)
458 {
459    Cover *cov = data;
460    int distance = 40;
461    int dx, dy;
462
463    cov->timer = NULL;
464    dx = cov->x - cov->dx;
465    dy = cov->y - cov->dy;
466    if (((dx * dx) + (dy * dy)) < (distance * distance))
467      {
468         cov->longpressed = EINA_TRUE;
469         INFO(cov, "longpress");
470
471         if (!cov->mouse_double_down) _message_read_send(cov);
472         else
473           {
474              /* send message to start longpress,
475                 keep previous target window to send mouse-up event */
476              cov->down_win = target_win;
477
478              _message_mouse_send(cov, MOUSE_BUTTON_DOWN);
479           }
480      }
481    return EINA_FALSE;
482 }
483
484 static Eina_Bool
485 _mouse_double_down(void *data)
486 {
487    Cover *cov = data;
488    ecore_timer_del(cov->double_down_timer);
489    cov->double_down_timer = NULL;
490    return EINA_FALSE;
491 }
492
493 static void
494 _mouse_double_down_timeout(Cover *cov)
495 {
496    double long_time = 0.5;
497    double short_time = 0.3;
498    int distance = 40;
499    int dx, dy;
500
501    dx = cov->x - cov->dx;
502    dy = cov->y - cov->dy;
503
504    if ((cov->double_down_timer) &&
505        (((dx * dx) + (dy * dy)) < (distance * distance)))
506      {
507         /* start double tap and move from here */
508         cov->mouse_double_down = EINA_TRUE;
509
510         if (cov->timer)
511           {
512              ecore_timer_del(cov->timer);
513              cov->timer = NULL;
514           }
515         /* check longpress after double down */
516         cov->timer = ecore_timer_add(long_time, _mouse_longpress, cov);
517      }
518
519    if (cov->double_down_timer)
520      {
521         ecore_timer_del(cov->double_down_timer);
522         cov->double_down_timer = NULL;
523         return;
524      }
525
526    cov->double_down_timer = ecore_timer_add(short_time, _mouse_double_down, cov);
527 }
528
529 static Eina_Bool
530 _mouse_tap(void *data)
531 {
532    Cover *cov = data;
533    cov->tap_timer = NULL;
534
535    _message_read_send(cov);
536
537    return EINA_FALSE;
538 }
539
540 static void
541 _mouse_down(Cover *cov, Ecore_Event_Mouse_Button *ev)
542 {
543    double longtime = 0.5;
544
545    cov->dx = ev->x;
546    cov->dy = ev->y;
547    cov->mx = ev->x;
548    cov->my = ev->y;
549    cov->x = ev->x;
550    cov->y = ev->y;
551    cov->dt = ev->timestamp;
552    cov->longpressed = EINA_FALSE;
553    cov->timer = ecore_timer_add(longtime, _mouse_longpress, cov);
554    cov->down_win = 0;
555
556    if (cov->tap_timer)
557      {
558         ecore_timer_del(cov->tap_timer);
559         cov->tap_timer = NULL;
560      }
561
562    /* check mouse double down - not two fingers, refer to double click */
563    _mouse_double_down_timeout(cov);
564 }
565
566 static void
567 _circle_draw_check(Cover *cov)
568 {
569    Ecore_Event_Mouse_Move *ev, *t_ev, *b_ev, *l_ev, *r_ev;
570    Evas_Coord_Point m_tb, m_lr;
571    int count = 0;
572    int offset, i;
573    int min_x, min_y, max_x, max_y;
574    int left = 0, right = 0, top = 0, bottom = 0;
575    int distance;
576
577    count = eina_inarray_count(cov->two_finger_move);
578    if (count < 10 || count > 60) goto inarray_free;
579
580    offset = count / 8;
581
582    i = 0;
583    EINA_INARRAY_FOREACH(cov->two_finger_move, ev)
584      {
585         if (i == 0)
586           {
587              min_x = ev->x;
588              max_x = ev->x;
589              min_y = ev->y;
590              max_y = ev->y;
591           }
592
593         if (ev->x < min_x)
594           {
595              min_x = ev->x;
596              left = i;
597           }
598
599         if (ev->y < min_y)
600           {
601              min_y = ev->y;
602              bottom = i;
603           }
604
605         if (ev->x > max_x)
606           {
607              max_x = ev->x;
608              right = i;
609           }
610
611         if (ev->y > max_y)
612           {
613              max_y = ev->y;
614              top = i;
615           }
616
617         i++;
618      }
619
620    t_ev = eina_inarray_nth(cov->two_finger_move, top);
621    b_ev = eina_inarray_nth(cov->two_finger_move, bottom);
622    m_tb.x = (t_ev->x + b_ev->x) / 2;
623    m_tb.y = (t_ev->y + b_ev->y) / 2;
624
625
626    l_ev = eina_inarray_nth(cov->two_finger_move, left);
627    r_ev = eina_inarray_nth(cov->two_finger_move, right);
628    m_lr.x = (l_ev->x + r_ev->x) / 2;
629    m_lr.y = (l_ev->y + r_ev->y) / 2;
630
631    distance = (int) sqrt(((m_tb.x - m_lr.x) * (m_tb.x - m_lr.x)) + ((m_tb.y - m_lr.y) * (m_tb.y - m_lr.y)));
632
633    i = 0;
634    if (top > left) i++;
635    if (left > bottom) i++;
636    if (bottom > right) i++;
637    if (right > top) i++;
638
639    if ((i >= 3) && (distance < 60))
640      {
641         INFO(cov, "two finger circle draw");
642         _message_back_send(cov);
643      }
644
645 inarray_free:
646    eina_inarray_free(cov->two_finger_move);
647 }
648
649 static void
650 _mouse_up(Cover *cov, Ecore_Event_Mouse_Button *ev)
651 {
652    double timeout = 0.15;
653    double double_tap_timeout = 0.25;
654    int distance = 40;
655    int dx, dy;
656    int angle = 0;
657
658    if (cov->three_finger_down)
659      {
660         cov->three_finger_down = EINA_FALSE;
661
662         dx = ev->x - cov->dx;
663         dy = ev->y - cov->dy;
664
665         if (((dx * dx) + (dy * dy)) > (4 * distance * distance)
666             && ((ev->timestamp - cov->dt) < (timeout * 3000)))
667           {
668              /* get root window rotation */
669              angle = _win_angle_get(target_win);
670
671              if (abs(dx) > abs(dy)) /* left or right */
672                {
673                   if (dx > 0) /* right */
674                     {
675                        INFO(cov, "three finger swipe right");
676                        switch (angle)
677                          {
678                           case 270:
679                             _app_tray_open(cov);
680                           break;
681
682                           case 90:
683                             _quickpanel_open();
684                           break;
685                          }
686
687                     }
688                   else /* left */
689                     {
690                        INFO(cov, "three finger swipe left");
691                        switch (angle)
692                          {
693                           case 270:
694                             _quickpanel_open();
695                           break;
696
697                           case 90:
698                             _app_tray_open(cov);
699                           break;
700
701                          }
702                     }
703                }
704              else /* up or down */
705                {
706                   if (dy > 0) /* down */
707                     {
708                        INFO(cov, "three finger swipe down");
709                        switch (angle)
710                          {
711                           case 180:
712                           default:
713                             _quickpanel_open();
714                           break;
715                          }
716                     }
717                   else /* up */
718                     {
719                        INFO(cov, "three finger swipe up");
720                        switch (angle)
721                          {
722                           case 180:
723                           default:
724                             _app_tray_open(cov);
725                           break;
726                          }
727                     }
728                }
729           }
730         goto end;
731      }
732
733    /* for two finger panning */
734    if (cov->two_finger_down)
735      {
736         cov->two_finger_down = EINA_FALSE;
737
738         _message_scroll_send(cov, MOUSE_BUTTON_UP);
739         cov->lock_screen = EINA_FALSE;
740
741         /* to check 2 finger mouse move */
742         if (cov->two_finger_move) _circle_draw_check(cov);
743
744         dx = ev->x - cov->dx;
745         dy = ev->y - cov->dy;
746
747         if (((dx * dx) + (dy * dy)) < (distance * distance))
748           {
749              if (ev->double_click)
750                {
751                   INFO(cov, "two finger double click");
752                   _message_control_panel_open_send(cov);
753                }
754           }
755         goto end;
756      }
757
758    if (cov->mouse_double_down)
759      {
760         /* reset double down and moving: action up/down */
761         cov->mouse_double_down = EINA_FALSE;
762
763         if (cov->longpressed)
764           {
765              /* mouse up after longpress */
766              _message_mouse_send(cov, MOUSE_BUTTON_UP);
767           }
768      }
769
770    /* delete timer which is used for checking longpress */
771    if (cov->timer)
772      {
773         ecore_timer_del(cov->timer);
774         cov->timer = NULL;
775      }
776
777    if (cov->longpressed)
778      {
779         cov->longpressed = EINA_FALSE;
780         return;
781      }
782
783    dx = ev->x - cov->dx;
784    dy = ev->y - cov->dy;
785    if (((dx * dx) + (dy * dy)) < (distance * distance))
786      {
787         if (ev->double_click)
788           {
789              INFO(cov, "double_click");
790              ecore_x_e_illume_access_action_activate_send(target_win);
791           }
792         else
793           {
794              cov->tap_timer = ecore_timer_add(double_tap_timeout,
795                                          _mouse_tap, cov);
796           }
797      }
798    else if (((dx * dx) + (dy * dy)) > (4 * distance * distance)
799             && ((ev->timestamp - cov->dt) < (timeout * 2000)))
800      {
801         /* get root window rotation */
802         angle = _win_angle_get(target_win);
803
804         if (abs(dx) > abs(dy)) /* left or right */
805           {
806              if (dx > 0) /* right */
807                {
808                   INFO(cov, "single flick right");
809                   switch (angle)
810                     {
811                      case 270:
812                        ecore_x_e_illume_access_action_up_send(target_win);
813                      break;
814
815                      case 90:
816                        ecore_x_e_illume_access_action_down_send(target_win);
817                      break;
818
819                      case 180:
820                      default:
821                        ecore_x_e_illume_access_action_read_next_send
822                                                         (target_win);
823                      break;
824                     }
825
826                }
827              else /* left */
828                {
829                   INFO(cov, "single flick left");
830                   switch (angle)
831                     {
832                      case 270:
833                        ecore_x_e_illume_access_action_down_send(target_win);
834                      break;
835
836                      case 90:
837                        ecore_x_e_illume_access_action_up_send(target_win);
838                      break;
839
840                      case 180:
841                      default:
842                        ecore_x_e_illume_access_action_read_prev_send
843                                                         (target_win);
844                      break;
845                     }
846                }
847           }
848         else /* up or down */
849           {
850              if (dy > 0) /* down */
851                {
852                   INFO(cov, "single flick down");
853                   switch (angle)
854                     {
855                      case 90:
856                        ecore_x_e_illume_access_action_read_prev_send
857                                                         (target_win);
858                      break;
859
860                      case 270:
861                        ecore_x_e_illume_access_action_read_next_send
862                                                         (target_win);
863                      break;
864
865                      case 180:
866                      default:
867                        ecore_x_e_illume_access_action_down_send(target_win);
868                      break;
869                     }
870                }
871              else /* up */
872                {
873                   INFO(cov, "single flick up");
874                   switch (angle)
875                     {
876                      case 90:
877                        ecore_x_e_illume_access_action_read_next_send
878                                                         (target_win);
879                      break;
880
881                      case 270:
882                        ecore_x_e_illume_access_action_read_prev_send
883                                                         (target_win);
884                      break;
885
886                      case 180:
887                      default:
888                        ecore_x_e_illume_access_action_up_send(target_win);
889                      break;
890                     }
891                }
892           }
893      }
894
895 end:
896    cov->longpressed = EINA_FALSE;
897 }
898
899 static void
900 _mouse_move(Cover *cov __UNUSED__, Ecore_Event_Mouse_Move *ev __UNUSED__)
901 {
902    //FIXME: why here, after long press you cannot go below..
903    //if (!cov->down) return;
904
905    //FIXME: one finger cannot come here
906    //_record_mouse_history(cov, ev);
907    if (cov->two_finger_move) eina_inarray_push(cov->two_finger_move, ev);
908
909    _message_scroll_send(cov, MOUSE_MOVE);
910 }
911
912 static void
913 _mouse_wheel(Cover *cov __UNUSED__, Ecore_Event_Mouse_Wheel *ev __UNUSED__)
914 {
915    if (ev->z == -1) /* up */
916      {
917 #if ECORE_VERSION_MAJOR >= 1
918 # if ECORE_VERSION_MINOR >= 8
919         ecore_x_e_illume_access_action_up_send(target_win);
920 # endif
921 #endif
922      }
923    else if (ev->z == 1) /* down */
924      {
925 #if ECORE_VERSION_MAJOR >= 1
926 # if ECORE_VERSION_MINOR >= 8
927         ecore_x_e_illume_access_action_down_send(target_win);
928 # endif
929 #endif
930      }
931 }
932
933 static Eina_Bool
934 _cb_mouse_down(void    *data __UNUSED__,
935                int      type __UNUSED__,
936                void    *event)
937 {
938    Ecore_Event_Mouse_Button *ev = event;
939    Eina_List *l;
940    Cover *cov;
941
942    EINA_LIST_FOREACH(covers, l, cov)
943      {
944         /* sometimes the mouse down event has improper multi.device value */
945         cov->n_taps++;
946
947         if (ev->window == cov->win)
948           {
949              //XXX change specific number
950              if (ev->multi.device == 0)
951                {
952                   _target_window_find();
953                   _mouse_down(cov, ev);
954                }
955
956              else if (cov->n_taps == 2 &&
957                       !(cov->two_finger_down) &&
958                       !(cov->longpressed))
959                {
960                   /* prevent longpress client message by two finger */
961                   if (cov->timer)
962                     {
963                        ecore_timer_del(cov->timer);
964                        cov->timer = NULL;
965                     }
966
967                   cov->two_finger_down = EINA_TRUE;
968
969                   _lock_screen_check(cov);
970                   _message_scroll_send(cov, MOUSE_BUTTON_DOWN);
971
972                   /* to check 2 finger mouse move */
973                   cov->two_finger_move = eina_inarray_new(sizeof(Ecore_Event_Mouse_Move), 0);
974                }
975
976              else if (cov->n_taps == 3 &&
977                       !(cov->three_finger_down) &&
978                       !(cov->longpressed))
979                {
980                   cov->three_finger_down = EINA_TRUE;
981
982                   if (cov->two_finger_down)
983                     {
984                        cov->two_finger_down = EINA_FALSE;
985
986                        _message_scroll_send(cov, MOUSE_BUTTON_UP);
987                        cov->lock_screen = EINA_FALSE;
988
989                        eina_inarray_free(cov->two_finger_move);
990                     }
991                }
992              return ECORE_CALLBACK_PASS_ON;
993           }
994      }
995    return ECORE_CALLBACK_PASS_ON;
996 }
997
998 static Eina_Bool
999 _cb_mouse_up(void    *data __UNUSED__,
1000              int      type __UNUSED__,
1001              void    *event)
1002 {
1003    Ecore_Event_Mouse_Button *ev = event;
1004    Eina_List *l;
1005    Cover *cov;
1006
1007    EINA_LIST_FOREACH(covers, l, cov)
1008      {
1009         cov->n_taps--;
1010
1011         if (ev->window == cov->win)
1012           {
1013              /* the first finger: 1, from the second finger: 0 */
1014              if (ev->buttons == 1) _mouse_up(cov, ev);
1015
1016              return ECORE_CALLBACK_PASS_ON;
1017           }
1018      }
1019    return ECORE_CALLBACK_PASS_ON;
1020 }
1021
1022 static Eina_Bool
1023 _cb_mouse_move(void    *data __UNUSED__,
1024                int      type __UNUSED__,
1025                void    *event)
1026 {
1027    Ecore_Event_Mouse_Move *ev = event;
1028    Eina_List *l;
1029    Cover *cov;
1030
1031    EINA_LIST_FOREACH(covers, l, cov)
1032      {
1033         cov->x = ev->x;
1034         cov->y = ev->y;
1035
1036         if (ev->window == cov->win)
1037           {
1038              //if (ev->multi.device == multi_device[0] || ev->multi.device == multi_device[1])
1039              if (cov->two_finger_down && cov->n_taps == 2)
1040                _mouse_move(cov, ev);
1041              else if (cov->longpressed && /* client message for moving is available only after long press is detected */
1042                       !(cov->mouse_double_down) && /* mouse move after double down should not send read message */
1043                       !(cov->two_finger_down) && ev->multi.device == 0)
1044                {
1045                   INFO(cov, "read");
1046                   _message_read_send(cov);
1047                }
1048              else if (cov->mouse_double_down && /* client message for moving is available only after long press is detected */
1049                       !(cov->two_finger_down) && ev->multi.device == 0)
1050                {
1051                   if (cov->longpressed)
1052                     {
1053                        /* send message to notify move after longpress */
1054                         _message_mouse_send(cov, MOUSE_MOVE);
1055                     }
1056                }
1057
1058              return ECORE_CALLBACK_PASS_ON;
1059           }
1060      }
1061    return ECORE_CALLBACK_PASS_ON;
1062 }
1063
1064 static Eina_Bool
1065 _cb_mouse_wheel(void    *data __UNUSED__,
1066                 int      type __UNUSED__,
1067                 void    *event)
1068 {
1069    Ecore_Event_Mouse_Wheel *ev = event;
1070    Eina_List *l;
1071    Cover *cov;
1072
1073    EINA_LIST_FOREACH(covers, l, cov)
1074      {
1075         if (ev->window == cov->win)
1076           {
1077              _mouse_wheel(cov, ev);
1078              return ECORE_CALLBACK_PASS_ON;
1079           }
1080      }
1081    return ECORE_CALLBACK_PASS_ON;
1082 }
1083
1084 static Cover *
1085 _cover_new(E_Zone *zone)
1086 {
1087    Cover *cov;
1088
1089    cov = E_NEW(Cover, 1);
1090    if (!cov) return NULL;
1091    cov->zone = zone;
1092
1093 #if DEBUG_INFO
1094    Ecore_Evas *ee;
1095    ee = ecore_evas_new(NULL,
1096                        zone->container->x + zone->x,
1097                        zone->container->y + zone->y,
1098                        zone->w, zone->h,
1099                        NULL);
1100    ecore_evas_alpha_set(ee, EINA_TRUE);
1101    cov->win = (Ecore_X_Window)ecore_evas_window_get(ee);
1102
1103    /* create infomation */
1104    Evas *e;
1105    e = ecore_evas_get(ee);
1106    cov->info = evas_object_rectangle_add(e);
1107    evas_object_color_set(cov->info, 255, 255, 255, 100);
1108    evas_object_move(cov->info, zone->container->x + zone->x, zone->container->y + zone->y);
1109    evas_object_resize(cov->info, zone->w, 30);
1110    evas_object_show(cov->info);
1111
1112    cov->text = evas_object_text_add(e);
1113    evas_object_text_style_set(cov->text, EVAS_TEXT_STYLE_PLAIN);
1114    evas_object_text_font_set(cov->text, "DejaVu", 14);
1115    evas_object_text_text_set(cov->text, "screen-reader module");
1116
1117    evas_object_color_set(cov->text, 0, 0, 0, 255);
1118    evas_object_resize(cov->text, (zone->w / 8), 20);
1119    evas_object_move(cov->text, zone->container->x + zone->x + 5, zone->container->y + zone->y + 5);
1120    evas_object_show(cov->text);
1121
1122 #else
1123    cov->win = ecore_x_window_input_new(zone->container->manager->root,
1124                                        zone->container->x + zone->x,
1125                                        zone->container->y + zone->y,
1126                                        zone->w, zone->h);
1127 #endif
1128
1129    ecore_x_input_multi_select(cov->win);
1130
1131    ecore_x_icccm_title_set(cov->win, "screen-reader-input");
1132    ecore_x_netwm_name_set(cov->win, "screen-reader-input");
1133
1134    ecore_x_window_ignore_set(cov->win, 1);
1135    ecore_x_window_configure(cov->win,
1136                             ECORE_X_WINDOW_CONFIGURE_MASK_SIBLING |
1137                             ECORE_X_WINDOW_CONFIGURE_MASK_STACK_MODE,
1138                             0, 0, 0, 0, 0,
1139                             zone->container->layers[8].win,
1140                             ECORE_X_WINDOW_STACK_ABOVE);
1141    ecore_x_window_show(cov->win);
1142    ecore_x_window_raise(cov->win);
1143
1144    return cov;
1145 }
1146
1147 static void
1148 _covers_init(void)
1149 {
1150    Eina_List *l, *l2, *l3;
1151    E_Manager *man;
1152
1153    EINA_LIST_FOREACH(e_manager_list(), l, man)
1154      {
1155         E_Container *con;
1156         EINA_LIST_FOREACH(man->containers, l2, con)
1157           {
1158              E_Zone *zone;
1159              EINA_LIST_FOREACH(con->zones, l3, zone)
1160                {
1161                   Cover *cov = _cover_new(zone);
1162                   if (cov)
1163                     {
1164                        covers = eina_list_append(covers, cov);
1165                        cov->n_taps = 0;
1166
1167                        cov->atom_control_panel_open = ecore_x_atom_get("_E_MOD_SCREEN_READER_ACTION_CONTROL_PANEL_OPEN_");
1168                        cov->atom_app_tray_open = ecore_x_atom_get("_E_MOD_SCREEN_READER_ACTION_APP_TRAY_OPEN_");
1169                     }
1170                }
1171           }
1172      }
1173 }
1174
1175 static void
1176 _covers_shutdown(void)
1177 {
1178    Cover *cov;
1179
1180    EINA_LIST_FREE(covers, cov)
1181      {
1182         ecore_x_window_ignore_set(cov->win, 0);
1183         ecore_x_window_free(cov->win);
1184         evas_object_del(cov->info);
1185         evas_object_del(cov->text);
1186
1187         if (cov->timer)
1188           {
1189              ecore_timer_del(cov->timer);
1190              cov->timer = NULL;
1191           }
1192
1193         if (cov->double_down_timer)
1194           {
1195              ecore_timer_del(cov->double_down_timer);
1196              cov->double_down_timer = NULL;
1197           }
1198
1199         if (cov->tap_timer)
1200           {
1201              ecore_timer_del(cov->tap_timer);
1202              cov->tap_timer = NULL;
1203           }
1204
1205         free(cov);
1206      }
1207 }
1208
1209 static Eina_Bool
1210 _cb_zone_add(void    *data __UNUSED__,
1211              int      type __UNUSED__,
1212              void    *event __UNUSED__)
1213 {
1214    _covers_shutdown();
1215    _covers_init();
1216    return ECORE_CALLBACK_PASS_ON;
1217 }
1218
1219 static Eina_Bool
1220 _cb_zone_del(void    *data __UNUSED__,
1221              int      type __UNUSED__,
1222              void    *event __UNUSED__)
1223 {
1224    _covers_shutdown();
1225    _covers_init();
1226    return ECORE_CALLBACK_PASS_ON;
1227 }
1228
1229 static Eina_Bool
1230 _cb_zone_move_resize(void    *data __UNUSED__,
1231                      int      type __UNUSED__,
1232                      void    *event __UNUSED__)
1233 {
1234    _covers_shutdown();
1235    _covers_init();
1236    return ECORE_CALLBACK_PASS_ON;
1237 }
1238
1239 static void
1240 _events_init(void)
1241 {
1242    handlers = eina_list_append
1243      (handlers, ecore_event_handler_add(ECORE_EVENT_MOUSE_BUTTON_DOWN,
1244                                         _cb_mouse_down, NULL));
1245    handlers = eina_list_append
1246      (handlers, ecore_event_handler_add(ECORE_EVENT_MOUSE_BUTTON_UP,
1247                                         _cb_mouse_up, NULL));
1248    handlers = eina_list_append
1249      (handlers, ecore_event_handler_add(ECORE_EVENT_MOUSE_MOVE,
1250                                         _cb_mouse_move, NULL));
1251    handlers = eina_list_append
1252      (handlers, ecore_event_handler_add(ECORE_EVENT_MOUSE_WHEEL,
1253                                         _cb_mouse_wheel, NULL));
1254    handlers = eina_list_append
1255      (handlers, ecore_event_handler_add(E_EVENT_ZONE_ADD,
1256                                         _cb_zone_add, NULL));
1257    handlers = eina_list_append
1258      (handlers, ecore_event_handler_add(E_EVENT_ZONE_DEL,
1259                                         _cb_zone_del, NULL));
1260    handlers = eina_list_append
1261      (handlers, ecore_event_handler_add(E_EVENT_ZONE_MOVE_RESIZE,
1262                                         _cb_zone_move_resize, NULL));
1263 }
1264
1265 static void
1266 _events_shutdown(void)
1267 {
1268    E_FREE_LIST(handlers, ecore_event_handler_del);
1269 }
1270
1271 static Eina_Bool
1272 _cb_property_change(void *data __UNUSED__,
1273                    int   type __UNUSED__,
1274                    void *ev)
1275 {
1276    E_Border *bd;
1277    Ecore_X_Event_Window_Property *event = ev;
1278
1279    if (!g_enable) return ECORE_CALLBACK_PASS_ON;
1280
1281    if (event->atom == ECORE_X_ATOM_NET_ACTIVE_WINDOW)
1282      {
1283         bd = e_border_focused_get();
1284         if (bd)
1285           {
1286              target_win = bd->client.win;
1287              _screen_reader_support_check();
1288           }
1289      }
1290
1291    if (event->atom == ECORE_X_ATOM_E_ILLUME_ACCESS_CONTROL &&
1292        event->win == target_win)
1293      {
1294         _screen_reader_support_check();
1295      }
1296
1297    return ECORE_CALLBACK_PASS_ON;
1298 }
1299
1300 static void
1301 _move_module_enable_set(int enable)
1302 {
1303    E_Manager *man = e_manager_current_get();
1304
1305    if (!man) ERR("cannot get current manager");
1306
1307    if (enable)
1308      {
1309         INF("send enaable message");
1310         e_msg_send("screen-reader", "enable", 0, E_OBJECT(man), NULL, NULL, NULL);
1311      }
1312    else
1313      {
1314         INF("send disaable message");
1315         e_msg_send("screen-reader", "disable", 0, E_OBJECT(man), NULL, NULL, NULL);
1316      }
1317 }
1318
1319 static void
1320 _vconf_cb_accessibility_tts_change(keynode_t *node,
1321                                    void      *data)
1322 {
1323    int enable = 0;
1324
1325    if (!node) return;
1326
1327    enable = vconf_keynode_get_bool(node);
1328    if (g_enable == enable) return;
1329
1330    g_enable = enable;
1331    if (enable)
1332      {
1333         INF("[screen reader module] module enable");
1334         _covers_shutdown();
1335         _covers_init();
1336         _events_shutdown();
1337         _events_init();
1338
1339         /* send a message to the move module */
1340         _move_module_enable_set(enable);
1341      }
1342    else
1343      {
1344         INF("[screen reader module] module disable");
1345         _covers_shutdown();
1346         _events_shutdown();
1347
1348         /* send a message to the move module */
1349         _move_module_enable_set(enable);
1350      }
1351
1352    elm_config_access_set(enable);
1353    elm_config_all_flush();
1354    elm_config_save();
1355 }
1356 /***************************************************************************/
1357 /* module setup */
1358 EAPI E_Module_Api e_modapi =
1359 {
1360    E_MODULE_API_VERSION, "Screen Reader"
1361 };
1362
1363 EAPI void *
1364 e_modapi_init(E_Module *m)
1365 {
1366    vconf_notify_key_changed(VCONFKEY_SETAPPL_ACCESSIBILITY_TTS,
1367                             _vconf_cb_accessibility_tts_change,
1368                             NULL);
1369
1370    ecore_x_event_mask_set(ecore_x_window_root_first_get(),
1371                           ECORE_X_EVENT_MASK_WINDOW_CONFIGURE);
1372    ecore_x_event_mask_set(ecore_x_window_root_first_get(),
1373                           ECORE_X_EVENT_MASK_WINDOW_PROPERTY);
1374    property_handler = ecore_event_handler_add
1375                        (ECORE_X_EVENT_WINDOW_PROPERTY, _cb_property_change, NULL);
1376
1377    if (vconf_get_bool(VCONFKEY_SETAPPL_ACCESSIBILITY_TTS, &g_enable) != 0)
1378      INF("vconf get failed\n");
1379
1380    if (g_enable)
1381      {
1382         _covers_shutdown();
1383         _covers_init();
1384         _events_shutdown();
1385         _events_init();
1386
1387         /* send a message to the move module */
1388         _move_module_enable_set(g_enable);
1389      }
1390    else
1391      {
1392         _covers_shutdown();
1393         _events_shutdown();
1394
1395         /* send a message to the move module */
1396         _move_module_enable_set(g_enable);
1397      }
1398
1399    elm_config_access_set(g_enable);
1400    elm_config_all_flush();
1401    elm_config_save();
1402
1403    return m;
1404 }
1405
1406 EAPI int
1407 e_modapi_shutdown(E_Module *m __UNUSED__)
1408 {
1409    INF("[screen-reader module] module shutdown");
1410    if (property_handler) ecore_event_handler_del(property_handler);
1411
1412    _covers_shutdown();
1413    _events_shutdown();
1414
1415    return 1;
1416 }
1417
1418 EAPI int
1419 e_modapi_save(E_Module *m __UNUSED__)
1420 {
1421    return 1;
1422 }