summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Blumenkrantz <zmike@osg.samsung.com>2015-10-22 13:46:48 -0400
committerMike Blumenkrantz <zmike@osg.samsung.com>2015-10-22 13:46:48 -0400
commitda8743aee7c8659682700434f15d7e9e2f21e99f (patch)
tree53040592667729c31a6a80b4a38d7d72b1f5080b
-rw-r--r--.gitignore50
-rw-r--r--AUTHORS1
-rw-r--r--COPYING25
-rw-r--r--ChangeLog0
-rw-r--r--Makefile.am25
-rw-r--r--NEWS0
-rw-r--r--README0
-rwxr-xr-xautogen.sh17
-rw-r--r--configure.ac50
-rw-r--r--m4/.gitignore39
-rw-r--r--module.desktop.in38
-rw-r--r--src/Makefile.am22
-rw-r--r--src/e_mod_config.c77
-rw-r--r--src/e_mod_main.c1027
-rw-r--r--src/e_mod_main.h13
15 files changed, 1384 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..255b55c
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,50 @@
1*~
2*.swo
3*.swp
4*.o
5*.lo
6*.la
7ABOUT-NLS
8INSTALL
9Makefile
10Makefile.in
11aclocal.m4
12autom4te.cache/
13config.guess
14config.h
15config.h.in
16config.log
17config.rpath
18config.status
19config.sub
20configure
21configure.ac.orig
22depcomp
23e_modules-contact.spec
24install-sh
25libtool
26ltmain.sh
27missing
28mkinstalldirs
29module.desktop
30po/Makefile
31po/Makefile.in
32po/Makefile.in.in
33po/Makevars.template
34po/POTFILES
35po/Rules-quot
36po/*.gmo
37po/boldquot.sed
38po/en@boldquot.header
39po/en@quot.header
40po/insert-header.sin
41po/quot.sed
42po/remove-potcdate.sed
43po/remove-potcdate.sin
44po/contact.pot
45po/stamp-po
46src/.deps/
47src/.libs/
48src/Makefile
49src/Makefile.in
50stamp-h1
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..73ebbe2
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1 @@
The Rasterman (Carsten Haitzler) <raster@rasterman.com>
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..dffd3a4
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,25 @@
1Copyright notice for Contact:
2
3Copyright (C) 2012-2015 Carsten Haitzler and various contributors (see AUTHORS)
4
5All rights reserved.
6
7Redistribution and use in source and binary forms, with or without
8modification, are permitted provided that the following conditions are met:
9
10 1. Redistributions of source code must retain the above copyright
11 notice, this list of conditions and the following disclaimer.
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions and the following disclaimer in the
14 documentation and/or other materials provided with the distribution.
15
16THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
17INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
18FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
22OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
23LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
25EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/ChangeLog b/ChangeLog
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/ChangeLog
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..b8bf065
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,25 @@
1ACLOCAL_AMFLAGS = -I m4
2MAINTAINERCLEANFILES = Makefile.in aclocal.m4 compile config.guess config.h.in \
3 config.sub configure depcomp install-sh ltmain.sh \
4 missing module.desktop config.rpath mkinstalldirs
5
6SUBDIRS = src
7
8#if HAVE_PO
9
10#SUBDIRS += po
11
12#endif
13
14filesdir = $(module_dir)/$(PACKAGE)
15files_DATA = module.desktop e-module-contact.edj
16
17EXTRA_DIST = module.desktop.in \
18 e_modules-contact.spec.in
19
20clean-local:
21 rm -rf *.edj module.desktop e_modules-contact.spec *~
22
23uninstall-local:
24 rm -rf $(DESTDIR)$(module_dir)/$(PACKAGE)
25
diff --git a/NEWS b/NEWS
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/NEWS
diff --git a/README b/README
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/README
diff --git a/autogen.sh b/autogen.sh
new file mode 100755
index 0000000..ae01364
--- /dev/null
+++ b/autogen.sh
@@ -0,0 +1,17 @@
1#!/bin/sh
2
3rm -rf autom4te.cache
4rm -f aclocal.m4 ltmain.sh
5
6touch README
7
8echo "Running autopoint..." ; autopoint -f || :
9echo "Running aclocal..." ; aclocal -I m4 $ACLOCAL_FLAGS || exit 1
10echo "Running autoheader..." ; autoheader || exit 1
11echo "Running autoconf..." ; autoconf || exit 1
12echo "Running libtoolize..." ; (libtoolize --copy --automake || glibtoolize --automake) || exit 1
13echo "Running automake..." ; automake --add-missing --copy --gnu || exit 1
14
15if [ -z "$NOCONFIGURE" ]; then
16 ./configure "$@"
17fi
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..8c98cb7
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,50 @@
1AC_INIT(access, 0.0.0, raster@rasterman.com)
2AC_CONFIG_MACRO_DIR([m4])
3AC_PREREQ(2.52)
4AC_CONFIG_SRCDIR(configure.ac)
5AC_CANONICAL_BUILD
6AC_CANONICAL_HOST
7AC_ISC_POSIX
8
9AM_INIT_AUTOMAKE([1.8 dist-bzip2])
10AM_CONFIG_HEADER(config.h)
11m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
12
13AC_PROG_CC
14AM_PROG_CC_STDC
15
16define([AC_LIBTOOL_LANG_CXX_CONFIG], [:])dnl
17define([AC_LIBTOOL_LANG_F77_CONFIG], [:])dnl
18AC_PROG_LIBTOOL
19
20#m4_ifdef([AM_GNU_GETTEXT_VERSION], [
21#AM_GNU_GETTEXT_VERSION([0.14])
22#])
23
24#m4_ifdef([AM_GNU_GETTEXT], [
25#AM_GNU_GETTEXT([external])
26#po_makefile_in=po/Makefile.in
27#AM_CONDITIONAL([HAVE_PO], [true])
28#],[
29#AM_CONDITIONAL([HAVE_PO], [false])
30#])
31#AC_SUBST(LTLIBINTL)
32
33PKG_CHECK_MODULES([E], [enlightenment >= 0.19.99])
34release=$(pkg-config --variable=release enlightenment)
35MODULE_ARCH="$host_os-$host_cpu-$release"
36AC_SUBST(MODULE_ARCH)
37AC_DEFINE_UNQUOTED(MODULE_ARCH, "$MODULE_ARCH", "Module architecture")
38
39module_dir="$(pkg-config --variable=modules enlightenment)"
40AC_SUBST(module_dir)
41
42AC_OUTPUT([
43Makefile
44src/Makefile
45module.desktop
46], [
47])
48
49#$po_makefile_in
50
diff --git a/m4/.gitignore b/m4/.gitignore
new file mode 100644
index 0000000..73b287f
--- /dev/null
+++ b/m4/.gitignore
@@ -0,0 +1,39 @@
1/codeset.m4
2/fcntl-o.m4
3/gettext.m4
4/glibc21.m4
5/iconv.m4
6/intdiv0.m4
7/inttypes-pri.m4
8/inttypes.m4
9/inttypes_h.m4
10/isc-posix.m4
11/lcmessage.m4
12/lib-ld.m4
13/lib-link.m4
14/lib-prefix.m4
15/libtool.m4
16/ltoptions.m4
17/ltsugar.m4
18/ltversion.m4
19/lt~obsolete.m4
20/nls.m4
21/po.m4
22/progtest.m4
23/stdint_h.m4
24/uintmax_t.m4
25/ulonglong.m4
26/glibc2.m4
27/intl.m4
28/intldir.m4
29/intlmacosx.m4
30/intmax.m4
31/lock.m4
32/longlong.m4
33/printf-posix.m4
34/size_max.m4
35/threadlib.m4
36/visibility.m4
37/wchar_t.m4
38/wint_t.m4
39/xsize.m4
diff --git a/module.desktop.in b/module.desktop.in
new file mode 100644
index 0000000..395357e
--- /dev/null
+++ b/module.desktop.in
@@ -0,0 +1,38 @@
1[Desktop Entry]
2Encoding=UTF-8
3Type=Link
4Name=Access
5Name[ca]=Accessibilitat
6Name[de]=Zugriff
7Name[el]=Πρόσβαση
8Name[eo]=Atingo
9Name[es]=Accesibilidad
10Name[fi]=Helppokäyttöisyys
11Name[fr]=Accès
12Name[gl]=Accesibilidade
13Name[ja]=アクセス
14Name[ko]=접근
15Name[lt]=Prieiga
16Name[ms]=Capaian
17Name[nl]=Toegang
18Name[pl]=Dostęp
19Name[pt]=Acessibilidade
20Name[ru]=Доступность
21Name[sr]=Приступачност
22Name[tr]=Access
23Comment=Accessibility module designed to improve ease of use for the vision impaired and the blind.
24Comment[ca]=Mòdul d'accessibilitat dissenyat per a facilitar l'ús a persones amb discapacitat visual.
25Comment[de]=Das Barrierefreiheitsmodul wurde entwickelt, um die Benutzerfreundlichkeit für Sehbehinderte und Blinde zu verbessern.
26Comment[eo]=Modulo por alirebleco elpensita por plifaciligi uzadon de vido ĉe misvidantoj kaj blinduloj.
27Comment[es]=Módulo de accesibilidad diseñado para facilitar el uso a ciegos y discapacitados visuales.
28Comment[fi]=Tämä moduuli on suunniteltu helpottamaan näkö- ja kuulovammaisten käyttäjien työskentelyä.
29Comment[fr]=Module d'accessibilité permettant d'améliorer l'expérience utilisateur des déficients visuels.
30Comment[gl]=Módulo de accesibilidade programado para facilitar o uso a cegos e discapacitados visuais.
31Comment[it]=Modulo per l'accessibilità, progettato per facilitare l'uso agli ipovedenti e ai ciechi.
32Comment[ms]=Modul kebolehcapaian direka untuk mempertingkatkan kemudahan untuk kegunaan cacat dan gangguan penglihatan.
33Comment[pt]=Módulo de acessibilidade para ajudar os deficientes visuais
34Comment[ru]=Модуль разработанный для упрощения работы за компьютером людей со слабым зрением.
35Comment[sr]=Јединица приступачности намењена олакшавању употребе слабовидим и слепим особама.
36Comment[tr]=Görme engelli ve körlerin kullanımını kolaylaştırmak için tasarlanmış erişilebilirlik modülü.
37Icon=preferences-desktop-accessibility
38X-Enlightenment-ModuleType=utils
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..0300079
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,22 @@
1MAINTAINERCLEANFILES = Makefile.in
2
3AM_CPPFLAGS = -I. \
4 -I$(top_srcdir) \
5 -I$(includedir) \
6 -DLOCALEDIR=\"$(datadir)/locale\" \
7 -DPACKAGE_DATA_DIR=\"$(module_dir)/$(PACKAGE)\" \
8 @E_CFLAGS@
9
10pkgdir = $(module_dir)/$(PACKAGE)/$(MODULE_ARCH)
11pkg_LTLIBRARIES = module.la
12module_la_SOURCES = \
13e_mod_main.c \
14e_mod_main.h \
15e_mod_config.c
16
17module_la_LIBADD = @E_LIBS@
18module_la_LDFLAGS = -module -avoid-version
19module_la_DEPENDENCIES = $(top_builddir)/config.h
20
21clean-local:
22 rm -rf *~
diff --git a/src/e_mod_config.c b/src/e_mod_config.c
new file mode 100644
index 0000000..51eb577
--- /dev/null
+++ b/src/e_mod_config.c
@@ -0,0 +1,77 @@
1#include "e.h"
2#include "e_mod_main.h"
3
4struct _E_Config_Dialog_Data
5{
6 int dummy;
7};
8
9/* local function prototypes */
10static void *_create_data (E_Config_Dialog *cfd);
11static void _fill_data (E_Config_Dialog_Data *cfdata);
12static void _free_data (E_Config_Dialog *cfd EINA_UNUSED, E_Config_Dialog_Data *cfdata);
13static Evas_Object *_basic_create(E_Config_Dialog *cfd EINA_UNUSED, Evas *evas, E_Config_Dialog_Data *cfdata);
14static int _basic_apply (E_Config_Dialog *cfd EINA_UNUSED, E_Config_Dialog_Data *cfdata);
15
16void
17_config_pager_module(void)
18{
19 E_Config_Dialog_View *v;
20
21 if (e_config_dialog_find("E", "_e_mod_access_config_dialog"))
22 return;
23 v = E_NEW(E_Config_Dialog_View, 1);
24 if (!v) return;
25
26 v->create_cfdata = _create_data;
27 v->free_cfdata = _free_data;
28 v->basic.create_widgets = _basic_create;
29 v->basic.apply_cfdata = _basic_apply;
30
31 e_config_dialog_new(NULL, _("Access Settings"), "E",
32 "_e_mod_access_config_dialog",
33 "preferences-desktop-access", 0, v, NULL);
34}
35
36/* local function prototypes */
37static void *
38_create_data(E_Config_Dialog *cfd EINA_UNUSED)
39{
40 E_Config_Dialog_Data *cfdata;
41
42 cfdata = E_NEW(E_Config_Dialog_Data, 1);
43 _fill_data(cfdata);
44 return cfdata;
45}
46
47static void
48_fill_data(E_Config_Dialog_Data *cfdata)
49{
50 cfdata->dummy = 1;
51}
52
53static void
54_free_data(E_Config_Dialog *cfd EINA_UNUSED, E_Config_Dialog_Data *cfdata)
55{
56 E_FREE(cfdata);
57}
58
59static Evas_Object *
60_basic_create(E_Config_Dialog *cfd EINA_UNUSED, Evas *evas, E_Config_Dialog_Data *cfdata EINA_UNUSED)
61{
62 Evas_Object *ol, *of;
63
64 ol = e_widget_list_add(evas, 0, 0);
65
66 of = e_widget_framelist_add(evas, _("General"), 0);
67 e_widget_list_object_append(ol, of, 1, 0, 0.5);
68
69 return ol;
70}
71
72static int
73_basic_apply(E_Config_Dialog *cfd EINA_UNUSED, E_Config_Dialog_Data *cfdata EINA_UNUSED)
74{
75 e_config_save_queue();
76 return 1;
77}
diff --git a/src/e_mod_main.c b/src/e_mod_main.c
new file mode 100644
index 0000000..d0cd055
--- /dev/null
+++ b/src/e_mod_main.c
@@ -0,0 +1,1027 @@
1#define E_COMP_X
2#include "e.h"
3#include "e_mod_main.h"
4#define HISTORY_MAX 8
5#define DEBUG_INFO 1
6
7static E_Config_DD *conf_edd = NULL;
8Config *access_config = NULL;
9
10typedef struct
11{
12 E_Zone *zone;
13 Ecore_X_Window win;
14 Ecore_Timer *timer;
15 Ecore_Timer *double_down_timer;
16 Ecore_Timer *tap_timer;
17 Evas_Object *info;
18 Evas_Object *text;
19 int x, y, dx, dy, mx, my;
20 int mouse_history[HISTORY_MAX];
21 unsigned int dt;
22 Eina_Inlist *history;
23 Eina_Bool longpressed : 1;
24 Eina_Bool two_finger_down : 1;
25 Eina_Bool double_down : 1;
26} Cover;
27
28#if DEBUG_INFO
29 static Ecore_Timer *dbg_timer = NULL;
30 static Eina_Bool
31 _reset_text(void *data)
32 {
33 Cover *cov = data;
34 if(!cov) return EINA_FALSE;
35
36 ecore_timer_del(dbg_timer);
37 dbg_timer = NULL;
38 evas_object_text_text_set(cov->text, "Screen Reader Mode");
39 return EINA_FALSE;
40 }
41 #define INFO(cov, txt) \
42 evas_object_text_text_set(cov->text, txt); \
43 EINA_LOG_INFO("%s", txt); \
44 if (dbg_timer) \
45 { \
46 ecore_timer_del(dbg_timer); \
47 dbg_timer = NULL; \
48 } \
49 dbg_timer = ecore_timer_add(1.0, _reset_text, cov);
50#else
51 #define INFO(cov, txt) EINA_LOG_INFO("%s", txt)
52#endif
53
54typedef struct
55{
56 EINA_INLIST;
57 int device;
58} Multi;
59
60static E_Client *_prev_bd;
61
62static Ecore_X_Atom _atom_access = 0;
63static Ecore_X_Window target_win = 0;
64
65static Eina_List *covers = NULL;
66static Eina_List *handlers = NULL;
67static Ecore_Event_Handler *client_message_handler = NULL;
68static Ecore_Event_Handler *property_handler = NULL;
69static int multi_device[3];
70
71static void
72_mouse_in_win_get(Cover *cov, int x, int y)
73{
74 Eina_List *l;
75 Ecore_X_Window *skip;
76 Cover *cov2;
77 int i;
78
79 skip = alloca(sizeof(Ecore_X_Window) * eina_list_count(covers));
80 i = 0;
81 EINA_LIST_FOREACH(covers, l, cov2)
82 {
83 skip[i] = cov2->win;
84 i++;
85 }
86
87 /* TODO: if target window is changed without highlight object,
88 then previous target window which has the highlight object
89 should get the message. how? */
90 target_win = ecore_x_window_shadow_tree_at_xy_with_skip_get
91 (cov->e_comp->root, x, y, skip, i);
92}
93
94static unsigned int
95_win_angle_get(Ecore_X_Window win)
96{
97 Ecore_X_Window root;
98
99 if (!win) return 0;
100
101 int ret;
102 int count;
103 int angle = 0;
104 unsigned char *prop_data = NULL;
105
106 root = ecore_x_window_root_get(win);
107 ret = ecore_x_window_prop_property_get(root,
108 ECORE_X_ATOM_E_ILLUME_ROTATE_ROOT_ANGLE,
109 ECORE_X_ATOM_CARDINAL,
110 32, &prop_data, &count);
111
112 if (ret && prop_data)
113 memcpy (&angle, prop_data, sizeof (int));
114
115 if (prop_data) free (prop_data);
116
117 return angle;
118}
119
120static void
121_coordinate_calibrate(Ecore_X_Window win, int *x, int *y)
122{
123 int tx, ty, w, h;
124 unsigned int angle;
125
126 if (!x) return;
127 if (!y) return;
128
129 angle = _win_angle_get(win);
130 ecore_x_window_geometry_get(win, NULL, NULL, &w, &h);
131
132 tx = *x;
133 ty = *y;
134
135 switch (angle)
136 {
137 case 90:
138 *x = h - ty;
139 *y = tx;
140 break;
141
142 case 180:
143 *x = w - tx;
144 *y = h - ty;
145 break;
146
147 case 270:
148 *x = ty;
149 *y = w - tx;
150 break;
151
152 default:
153 break;
154 }
155}
156
157static void
158_mouse_win_fake_tap(Cover *cov, Ecore_Event_Mouse_Button *ev)
159{
160 int x, y;
161
162 /* find target window to send message */
163 _mouse_in_win_get(cov, ev->root.x, ev->root.y);
164
165 ecore_x_pointer_xy_get(target_win, &x, &y);
166 ecore_x_mouse_in_send(target_win, x, y);
167 ecore_x_mouse_move_send(target_win, x, y);
168 ecore_x_mouse_down_send(target_win, x, y, 1);
169 ecore_x_mouse_up_send(target_win, x, y, 1);
170 ecore_x_mouse_out_send(target_win, x, y);
171}
172
173static void
174_messsage_read_send(Cover *cov)
175{
176 int x, y;
177
178 /* find target window to send message */
179 _mouse_in_win_get(cov, cov->x, cov->y);
180
181 ecore_x_pointer_xy_get(target_win, &x, &y);
182 _coordinate_calibrate(target_win, &x, &y);
183
184 ecore_x_client_message32_send(target_win, ECORE_X_ATOM_E_ILLUME_ACCESS_CONTROL,
185 ECORE_X_EVENT_MASK_WINDOW_CONFIGURE,
186 target_win,
187 ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_READ,
188 x, y, 0);
189
190#if DEBUG_INFO
191 Eina_List *l;
192 Cover *ecov;
193 Eina_Strbuf *buf;
194
195 buf = eina_strbuf_new();
196 eina_strbuf_append_printf(buf, "read x:%d, y:%d", x, y);
197
198 EINA_LIST_FOREACH(covers, l, ecov)
199 {
200 INFO(ecov, eina_strbuf_string_get(buf));
201 }
202 eina_strbuf_free(buf);
203#endif
204}
205
206static Eina_Bool
207_mouse_longpress(void *data)
208{
209 Cover *cov = data;
210 int distance = 40;
211 int dx, dy;
212
213 cov->timer = NULL;
214 dx = cov->x - cov->dx;
215 dy = cov->y - cov->dy;
216 if (((dx * dx) + (dy * dy)) < (distance * distance))
217 {
218 cov->longpressed = EINA_TRUE;
219 INFO(cov, "longpress");
220
221 if (!cov->double_down) _messsage_read_send(cov);
222 else
223 {
224 INFO(cov, "double down and longpress");
225 //TODO: send message to notify start longpress
226 }
227 }
228 return EINA_FALSE;
229}
230
231static Eina_Bool
232_mouse_double_down(void *data)
233{
234 Cover *cov = data;
235 ecore_timer_del(cov->double_down_timer);
236 cov->double_down_timer = NULL;
237 return EINA_FALSE;
238}
239
240static void
241_double_down_timeout(Cover *cov)
242{
243 double long_time = 0.5;
244 double short_time = 0.3;
245 int distance = 40;
246 int dx, dy;
247
248 dx = cov->x - cov->dx;
249 dy = cov->y - cov->dy;
250
251 if ((cov->double_down_timer) &&
252 (((dx * dx) + (dy * dy)) < (distance * distance)))
253 {
254 // start double tap and move from here
255 cov->double_down = EINA_TRUE;
256
257 if (cov->timer)
258 {
259 ecore_timer_del(cov->timer);
260 cov->timer = NULL;
261 }
262 /* check longpress after double down */
263 cov->timer = ecore_timer_add(long_time, _mouse_longpress, cov);
264 }
265
266 if (cov->double_down_timer)
267 {
268 ecore_timer_del(cov->double_down_timer);
269 cov->double_down_timer = NULL;
270 return;
271 }
272
273 cov->double_down_timer = ecore_timer_add(short_time, _mouse_double_down, cov);
274}
275
276static Eina_Bool
277_mouse_tap(void *data)
278{
279 Cover *cov = data;
280 cov->tap_timer = NULL;
281
282 _messsage_read_send(cov);
283
284 return EINA_FALSE;
285}
286
287static void
288_mouse_down(Cover *cov, Ecore_Event_Mouse_Button *ev)
289{
290 double long_time = 0.5;
291
292 cov->dx = ev->x;
293 cov->dy = ev->y;
294 cov->mx = ev->x;
295 cov->my = ev->y;
296 cov->x = ev->x;
297 cov->y = ev->y;
298 cov->dt = ev->timestamp;
299 cov->longpressed = EINA_FALSE;
300 cov->timer = ecore_timer_add(long_time, _mouse_longpress, cov);
301
302 if (cov->tap_timer)
303 {
304 ecore_timer_del(cov->tap_timer);
305 cov->tap_timer = NULL;
306 }
307
308 /* check mouse double down - not two fingers, refer to double click */
309 _double_down_timeout(cov);
310}
311
312static void
313_mouse_up(Cover *cov, Ecore_Event_Mouse_Button *ev)
314{
315 double timeout = 0.15;
316 double double_tap_timeout = 0.25;
317 int distance = 40;
318 int dx, dy;
319 int x, y;
320 int angle = 0;
321
322 // for two finger panning
323 if (cov->two_finger_down)
324 {
325 ecore_x_pointer_xy_get(target_win, &x, &y);
326 ecore_x_mouse_up_send(target_win, x, y, 1);
327 cov->two_finger_down = EINA_FALSE;
328 ecore_x_mouse_out_send(target_win, x, y);
329 }
330
331 // reset double down and moving
332 cov->double_down = EINA_FALSE;
333
334 if (cov->timer)
335 {
336 ecore_timer_del(cov->timer);
337 cov->timer = NULL;
338 }
339
340 if (cov->longpressed)
341 {
342 cov->longpressed = EINA_FALSE;
343 return;
344 }
345
346 dx = ev->x - cov->dx;
347 dy = ev->y - cov->dy;
348 if (((dx * dx) + (dy * dy)) < (distance * distance))
349 {
350 if (ev->double_click)
351 {
352 /* activate message would change focused window
353 FIXME: but it is possibe to create unfocused window
354 in this case, the message should go to unfocused window? */
355 _prev_bd = e_client_focused_get();
356
357 INFO(cov, "double_click");
358 ecore_x_e_illume_access_action_activate_send(target_win);
359 }
360 else if ((ev->timestamp - cov->dt) <= (timeout * 1000))
361 {
362 cov->tap_timer = ecore_timer_add(double_tap_timeout,
363 _mouse_tap, cov);
364 }
365 else if ((ev->timestamp - cov->dt) > (timeout * 1000) &&
366 (ev->timestamp - cov->dt) < (2 * timeout * 1000))
367 {
368 INFO(cov, "tap");
369 _mouse_win_fake_tap(cov, ev);
370 }
371 }
372 else if (((dx * dx) + (dy * dy)) > (4 * distance * distance)
373 && ((ev->timestamp - cov->dt) < (timeout * 1000)))
374 {
375 /* get root window rotation */
376 angle = _win_angle_get(target_win);
377
378 if (abs(dx) > abs(dy)) // left or right
379 {
380 if (dx > 0) // right
381 {
382 INFO(cov, "single flick right");
383 switch (angle)
384 {
385 case 180:
386 case 270:
387 ecore_x_e_illume_access_action_read_prev_send
388 (target_win);
389 break;
390
391 case 90:
392 default:
393 ecore_x_e_illume_access_action_read_next_send
394 (target_win);
395 break;
396 }
397
398 }
399 else // left
400 {
401 INFO(cov, "single flick left");
402 switch (angle)
403 {
404 case 180:
405 case 270:
406 ecore_x_e_illume_access_action_read_next_send
407 (target_win);
408 break;
409
410 case 90:
411 default:
412 ecore_x_e_illume_access_action_read_prev_send
413 (target_win);
414 break;
415 }
416 }
417 }
418 else // up or down
419 {
420 if (dy > 0) // down
421 {
422 INFO(cov, "single flick down");
423 switch (angle)
424 {
425 case 90:
426 case 180:
427 ecore_x_e_illume_access_action_read_prev_send
428 (target_win);
429 break;
430
431 case 270:
432 default:
433 ecore_x_e_illume_access_action_read_next_send
434 (target_win);
435 break;
436 }
437 }
438 else // up
439 {
440 INFO(cov, "single flick up");
441 switch (angle)
442 {
443 case 90:
444 case 180:
445 ecore_x_e_illume_access_action_read_next_send
446 (target_win);
447 break;
448
449 case 270:
450 default:
451 ecore_x_e_illume_access_action_read_prev_send
452 (target_win);
453 break;
454 }
455 }
456 }
457 }
458 cov->longpressed = EINA_FALSE;
459}
460
461static void
462_mouse_move(Cover *cov, Ecore_Event_Mouse_Move *ev)
463{
464 int x, y;
465
466 //FIXME: why here.. after long press you cannot go below..
467 //if (!cov->down) return;
468
469 //FIXME: one finger cannot come here
470 //_record_mouse_history(cov, ev);
471
472 ecore_x_pointer_xy_get(target_win, &x, &y);
473 ecore_x_mouse_move_send(target_win, x, y);
474}
475
476static void
477_mouse_wheel(Cover *cov EINA_UNUSED, Ecore_Event_Mouse_Wheel *ev EINA_UNUSED)
478{
479 if (ev->z == -1) // up
480 {
481 ecore_x_e_illume_access_action_up_send(target_win);
482 }
483 else if (ev->z == 1) // down
484 {
485 ecore_x_e_illume_access_action_down_send(target_win);
486 }
487}
488
489static Eina_Bool
490_cb_mouse_down(void *data EINA_UNUSED,
491 int type EINA_UNUSED,
492 void *event)
493{
494 Ecore_Event_Mouse_Button *ev = event;
495 Eina_List *l;
496 Cover *cov;
497 int i = 0;
498 int x, y;
499 E_Client *ec;
500
501 for (i = 0; i < 3; i++)
502 {
503 if (multi_device[i] == -1)
504 {
505 multi_device[i] = ev->multi.device;
506 break;
507 }
508 else if (multi_device[i] == ev->multi.device) break;
509 }
510
511 /* activate message would change focused window
512 FIXME: but it is possibe to create unfocused window
513 in this case, the message should go to focused window? */
514 ec = e_client_focused_get();
515 if (ec && (ec != _prev_bd)) target_win = e_client_util_win_get(ec);
516
517 EINA_LIST_FOREACH(covers, l, cov)
518 {
519 if (ev->window == cov->win)
520 {
521 // XXX change specific number
522 if (ev->multi.device == multi_device[0])
523 _mouse_down(cov, ev);
524
525 if (ev->multi.device == multi_device[1] && !(cov->two_finger_down))
526 {
527 // prevent longpress client message by two finger
528 if (cov->timer)
529 {
530 ecore_timer_del(cov->timer);
531 cov->timer = NULL;
532 }
533
534 ecore_x_pointer_xy_get(target_win, &x, &y);
535
536 ecore_x_mouse_in_send(target_win, x, y);
537 ecore_x_mouse_move_send(target_win, x, y);
538 ecore_x_mouse_down_send(target_win, x, y, 1);
539
540 cov->two_finger_down = EINA_TRUE;
541 }
542 return ECORE_CALLBACK_PASS_ON;
543 }
544 }
545 return ECORE_CALLBACK_PASS_ON;
546}
547
548static Eina_Bool
549_cb_mouse_up(void *data EINA_UNUSED,
550 int type EINA_UNUSED,
551 void *event)
552{
553 Ecore_Event_Mouse_Button *ev = event;
554 Eina_List *l;
555 Cover *cov;
556
557 EINA_LIST_FOREACH(covers, l, cov)
558 {
559 if (ev->window == cov->win)
560 {
561 if (ev->buttons == 1)
562 _mouse_up(cov, ev);
563 return ECORE_CALLBACK_PASS_ON;
564 }
565 }
566 return ECORE_CALLBACK_PASS_ON;
567}
568
569static Eina_Bool
570_cb_mouse_move(void *data EINA_UNUSED,
571 int type EINA_UNUSED,
572 void *event)
573{
574 Ecore_Event_Mouse_Move *ev = event;
575 Eina_List *l;
576 Cover *cov;
577 int angle = 0;
578
579 EINA_LIST_FOREACH(covers, l, cov)
580 {
581 cov->x = ev->x;
582 cov->y = ev->y;
583
584 if (ev->window == cov->win)
585 {
586 //if (ev->multi.device == multi_device[0] || ev->multi.device == multi_device[1])
587 if (cov->two_finger_down && ev->multi.device == multi_device[1])
588 _mouse_move(cov, ev);
589 else if (cov->longpressed && // client message for moving is available only after long press is detected
590 !(cov->double_down) && /* mouse move after double down should not send read message */
591 !(cov->two_finger_down) && ev->multi.device == multi_device[0])
592 {
593 INFO(cov, "read");
594 _messsage_read_send(cov);
595 }
596 else if (cov->double_down && // client message for moving is available only after long press is detected
597 !(cov->two_finger_down) && ev->multi.device == multi_device[0])
598 {
599 int distance = 5;
600 int dx, dy;
601
602 if (cov->longpressed)
603 {
604 //TODO: send message to notify move afte longpress
605 }
606 else
607 {
608 dx = ev->x - cov->mx;
609 dy = ev->y - cov->my;
610
611 /* get root window rotation */
612 angle = _win_angle_get(target_win);
613
614 if (((dx * dx) + (dy * dy)) > (distance * distance))
615 {
616
617 if (abs(dx) > abs(dy)) // left or right
618 {
619 if (dx > 0) // right
620 {
621 INFO(cov, "mouse double down and move - right");
622 switch (angle)
623 {
624 case 180:
625 case 270:
626 ecore_x_e_illume_access_action_down_send(target_win);
627 break;
628
629 case 90:
630 default:
631 ecore_x_e_illume_access_action_up_send(target_win);
632 break;
633 }
634 }
635 else // left
636 {
637 INFO(cov, "mouse double down and move - left");
638 switch (angle)
639 {
640 case 180:
641 case 270:
642 ecore_x_e_illume_access_action_up_send(target_win);
643 break;
644
645 case 90:
646 default:
647 ecore_x_e_illume_access_action_down_send(target_win);
648 break;
649 }
650 }
651 }
652 else // up or down
653 {
654 if (dy > 0) // down
655 {
656 INFO(cov, "mouse double down and move - down");
657 switch (angle)
658 {
659 case 90:
660 case 180:
661 ecore_x_e_illume_access_action_up_send(target_win);
662 break;
663
664 case 270:
665 default:
666 ecore_x_e_illume_access_action_down_send(target_win);
667 break;
668 }
669 }
670 else // up
671 {
672 INFO(cov, "mouse double down and move - up");
673 switch (angle)
674 {
675 case 90:
676 case 180:
677 ecore_x_e_illume_access_action_down_send(target_win);
678 break;
679
680 case 270:
681 default:
682 ecore_x_e_illume_access_action_up_send(target_win);
683 break;
684 }
685 }
686 }
687
688 cov->mx = ev->x;
689 cov->my = ev->y;
690 }
691 }
692 }
693
694 return ECORE_CALLBACK_PASS_ON;
695 }
696 }
697 return ECORE_CALLBACK_PASS_ON;
698}
699
700static Eina_Bool
701_cb_mouse_wheel(void *data EINA_UNUSED,
702 int type EINA_UNUSED,
703 void *event)
704{
705 Ecore_Event_Mouse_Wheel *ev = event;
706 Eina_List *l;
707 Cover *cov;
708
709 EINA_LIST_FOREACH(covers, l, cov)
710 {
711 if (ev->window == cov->win)
712 {
713 _mouse_wheel(cov, ev);
714 return ECORE_CALLBACK_PASS_ON;
715 }
716 }
717 return ECORE_CALLBACK_PASS_ON;
718}
719
720static Cover *
721_cover_new(E_Zone *zone)
722{
723 Cover *cov;
724
725 cov = E_NEW(Cover, 1);
726 if (!cov) return NULL;
727 cov->zone = zone;
728
729#if DEBUG_INFO
730 Ecore_Evas *ee;
731 ee = ecore_evas_new(NULL,
732 zone->x,
733 zone->y,
734 zone->w, zone->h,
735 NULL);
736 ecore_evas_alpha_set(ee, EINA_TRUE);
737 cov->win = (Ecore_X_Window)ecore_evas_window_get(ee);
738
739 /* create infomation */
740 Evas *e;
741 e = ecore_evas_get(ee);
742 cov->info = evas_object_rectangle_add(e);
743 evas_object_color_set(cov->info, 255, 255, 255, 100);
744 evas_object_move(cov->info, zone->x, zone->y);
745 evas_object_resize(cov->info, zone->w, 30);
746 evas_object_show(cov->info);
747
748 cov->text = evas_object_text_add(e);
749 evas_object_text_style_set(cov->text, EVAS_TEXT_STYLE_PLAIN);
750 evas_object_text_font_set(cov->text, "DejaVu", 14);
751 INFO(cov, "Screen Reader Mode");
752
753 evas_object_color_set(cov->text, 0, 0, 0, 255);
754 evas_object_resize(cov->text, (zone->w / 8), 20);
755 evas_object_move(cov->text, zone->x + 5, zone->y + 5);
756 evas_object_show(cov->text);
757
758#else
759 cov->win = ecore_x_window_input_new(e_comp->root,
760 zone->x, zone->y,
761 zone->w, zone->h);
762#endif
763
764 ecore_x_input_multi_select(cov->win);
765
766 ecore_x_icccm_title_set(cov->win, "access-screen-reader");
767 ecore_x_netwm_name_set(cov->win, "access-screen-reader");
768
769 ecore_x_window_ignore_set(cov->win, 1);
770 ecore_x_window_configure(cov->win,
771 ECORE_X_WINDOW_CONFIGURE_MASK_SIBLING |
772 ECORE_X_WINDOW_CONFIGURE_MASK_STACK_MODE,
773 0, 0, 0, 0, 0,
774 e_comp->layers[8].win,
775 ECORE_X_WINDOW_STACK_ABOVE);
776 ecore_x_window_show(cov->win);
777 ecore_x_window_raise(cov->win);
778
779 return cov;
780}
781
782static void
783_covers_init(void)
784{
785 const Eina_List *l;
786 int i = 0;
787 E_Zone *zone;
788
789 EINA_LIST_FOREACH(e_comp->zones, l, zone)
790 {
791 Cover *cov = _cover_new(zone);
792 if (!cov) continue;
793 covers = eina_list_append(covers, cov);
794 for (i = 0; i < HISTORY_MAX; i++) cov->mouse_history[i] = -1;
795 }
796}
797
798static void
799_covers_shutdown(void)
800{
801 Cover *cov;
802
803 EINA_LIST_FREE(covers, cov)
804 {
805 ecore_x_window_ignore_set(cov->win, 0);
806 ecore_x_window_free(cov->win);
807 evas_object_del(cov->info);
808 evas_object_del(cov->text);
809
810 if (cov->timer)
811 {
812 ecore_timer_del(cov->timer);
813 cov->timer = NULL;
814 }
815
816 if (cov->double_down_timer)
817 {
818 ecore_timer_del(cov->double_down_timer);
819 cov->double_down_timer = NULL;
820 }
821
822 if (cov->tap_timer)
823 {
824 ecore_timer_del(cov->tap_timer);
825 cov->tap_timer = NULL;
826 }
827
828#if DEBUG_INFO
829 if (dbg_timer)
830 {
831 ecore_timer_del(dbg_timer);
832 dbg_timer = NULL;
833 }
834#endif
835
836 free(cov);
837 }
838}
839
840static Eina_Bool
841_cb_zone_add(void *data EINA_UNUSED,
842 int type EINA_UNUSED,
843 void *event EINA_UNUSED)
844{
845 _covers_shutdown();
846 _covers_init();
847 return ECORE_CALLBACK_PASS_ON;
848}
849
850static Eina_Bool
851_cb_zone_del(void *data EINA_UNUSED,
852 int type EINA_UNUSED,
853 void *event EINA_UNUSED)
854{
855 _covers_shutdown();
856 _covers_init();
857 return ECORE_CALLBACK_PASS_ON;
858}
859
860static Eina_Bool
861_cb_zone_move_resize(void *data EINA_UNUSED,
862 int type EINA_UNUSED,
863 void *event EINA_UNUSED)
864{
865 _covers_shutdown();
866 _covers_init();
867 return ECORE_CALLBACK_PASS_ON;
868}
869
870static void
871_events_init(void)
872{
873 int i = 0;
874
875 handlers = eina_list_append
876 (handlers, ecore_event_handler_add(ECORE_EVENT_MOUSE_BUTTON_DOWN,
877 _cb_mouse_down, NULL));
878 handlers = eina_list_append
879 (handlers, ecore_event_handler_add(ECORE_EVENT_MOUSE_BUTTON_UP,
880 _cb_mouse_up, NULL));
881 handlers = eina_list_append
882 (handlers, ecore_event_handler_add(ECORE_EVENT_MOUSE_MOVE,
883 _cb_mouse_move, NULL));
884 handlers = eina_list_append
885 (handlers, ecore_event_handler_add(ECORE_EVENT_MOUSE_WHEEL,
886 _cb_mouse_wheel, NULL));
887 handlers = eina_list_append
888 (handlers, ecore_event_handler_add(E_EVENT_ZONE_ADD,
889 _cb_zone_add, NULL));
890 handlers = eina_list_append
891 (handlers, ecore_event_handler_add(E_EVENT_ZONE_DEL,
892 _cb_zone_del, NULL));
893 handlers = eina_list_append
894 (handlers, ecore_event_handler_add(E_EVENT_ZONE_MOVE_RESIZE,
895 _cb_zone_move_resize, NULL));
896
897 for (i = 0; i < 3; i++) multi_device[i] = -1;
898}
899
900static void
901_events_shutdown(void)
902{
903 E_FREE_LIST(handlers, ecore_event_handler_del);
904}
905
906static Eina_Bool
907_cb_property_change(void *data EINA_UNUSED,
908 int type EINA_UNUSED,
909 void *ev)
910{
911 E_Client *ec;
912 Ecore_X_Event_Window_Property *event = ev;
913
914 if (event->atom == ECORE_X_ATOM_NET_ACTIVE_WINDOW)
915 {
916 ec = e_client_focused_get();
917 if (ec) target_win = e_client_util_win_get(ec);
918 }
919
920 return ECORE_CALLBACK_PASS_ON;
921}
922
923static Eina_Bool
924_cb_client_message(void *data EINA_UNUSED,
925 int type EINA_UNUSED,
926 void *ev)
927{
928 int block;
929 Ecore_X_Event_Client_Message *event = ev;
930
931 if (event->message_type != _atom_access)
932 return ECORE_CALLBACK_PASS_ON;
933
934 block = e_config_save_block_get();
935 if (block) e_config_save_block_set(!block);
936
937 if ((Eina_Bool)event->data.l[0])
938 {
939 EINA_LOG_INFO("[access module] module enable");
940 _covers_init();
941 _events_init();
942 access_config->window = EINA_TRUE;
943 }
944 else
945 {
946 EINA_LOG_INFO("[access module] module disable");
947 _covers_shutdown();
948 _events_shutdown();
949 access_config->window = EINA_FALSE;
950 }
951
952 /* save config value */
953 e_config_domain_save("module.access", conf_edd, access_config);
954 e_config_save_block_set(block);
955
956 return ECORE_CALLBACK_PASS_ON;
957}
958
959/***************************************************************************/
960/* module setup */
961E_API E_Module_Api e_modapi =
962{
963 E_MODULE_API_VERSION, "Access"
964};
965
966E_API void *
967e_modapi_init(E_Module *m)
968{
969 if (!_atom_access)
970 _atom_access = ecore_x_atom_get("_E_MOD_ACC_SCR_READER_");
971
972 ecore_x_event_mask_set(ecore_x_window_root_first_get(),
973 ECORE_X_EVENT_MASK_WINDOW_CONFIGURE);
974 client_message_handler = ecore_event_handler_add
975 (ECORE_X_EVENT_CLIENT_MESSAGE, _cb_client_message, NULL);
976 ecore_x_event_mask_set(ecore_x_window_root_first_get(),
977 ECORE_X_EVENT_MASK_WINDOW_PROPERTY);
978 property_handler = ecore_event_handler_add
979 (ECORE_X_EVENT_WINDOW_PROPERTY, _cb_property_change, NULL);
980
981 /* load config value */
982 conf_edd = E_CONFIG_DD_NEW("Access_Config", Config);
983 E_CONFIG_VAL(conf_edd, Config, window, UCHAR);
984
985 access_config = e_config_domain_load("module.access", conf_edd);
986
987 if (!access_config)
988 {
989 access_config = E_NEW(Config, 1);
990 access_config->window = EINA_FALSE;
991 return m;
992 }
993
994 if (access_config->window)
995 {
996 _covers_shutdown();
997 _covers_init();
998 _events_init();
999 }
1000 else
1001 {
1002 _covers_shutdown();
1003 _events_shutdown();
1004 }
1005
1006 return m;
1007}
1008
1009E_API int
1010e_modapi_shutdown(E_Module *m EINA_UNUSED)
1011{
1012 EINA_LOG_INFO("[access module] module shutdown");
1013 if (client_message_handler) ecore_event_handler_del(client_message_handler);
1014 if (property_handler) ecore_event_handler_del(property_handler);
1015
1016 _covers_shutdown();
1017 _events_shutdown();
1018
1019 return 1;
1020}
1021
1022E_API int
1023e_modapi_save(E_Module *m EINA_UNUSED)
1024{
1025 e_config_domain_save("module.access", conf_edd, access_config);
1026 return 1;
1027}
diff --git a/src/e_mod_main.h b/src/e_mod_main.h
new file mode 100644
index 0000000..ed744db
--- /dev/null
+++ b/src/e_mod_main.h
@@ -0,0 +1,13 @@
1#ifndef E_MOD_MAIN_H
2#define E_MOD_MAIN_H
3
4#define _(A) A
5typedef struct _Config Config;
6
7struct _Config
8{
9 /* saved * loaded config values */
10 Eina_Bool window;
11};
12
13#endif