summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarsten Haitzler <raster@rasterman.com>2011-08-19 11:07:42 +0000
committerCarsten Haitzler <raster@rasterman.com>2011-08-19 11:07:42 +0000
commitc264466f3bd6f352d9aba93ea998e9edf9b59a08 (patch)
tree13bd5c37b274c4b125bde08beccf74d8c57f4dad
parent20236447bb926f0c1503a6ed8a50ad335ab7565d (diff)
this is... the beginning of accessibility supportin elm. it's direct
as in elm manages it itself - all it needs is a module to send text to. one is provided here that just execs espeak and handles a stream of things for it to say. this is only a start and is still being fleshed out. SVN revision: 62585
-rw-r--r--configure.ac1
-rw-r--r--data/themes/widgets/label.edc5
-rw-r--r--src/lib/Makefile.am1
-rw-r--r--src/lib/elm_access.c245
-rw-r--r--src/lib/elm_button.c14
-rw-r--r--src/lib/elm_widget.h44
-rw-r--r--src/modules/Makefile.am3
-rw-r--r--src/modules/access_output/Makefile.am33
-rw-r--r--src/modules/access_output/mod.c116
9 files changed, 451 insertions, 11 deletions
diff --git a/configure.ac b/configure.ac
index a768c0f90..dae927a1f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -582,6 +582,7 @@ src/lib/Makefile
582src/lib/Elementary.h 582src/lib/Elementary.h
583src/bin/Makefile 583src/bin/Makefile
584src/modules/Makefile 584src/modules/Makefile
585src/modules/access_output/Makefile
585src/modules/test_entry/Makefile 586src/modules/test_entry/Makefile
586src/modules/test_map/Makefile 587src/modules/test_map/Makefile
587src/edje_externals/Makefile 588src/edje_externals/Makefile
diff --git a/data/themes/widgets/label.edc b/data/themes/widgets/label.edc
index 681d2d2a9..cc190a8a5 100644
--- a/data/themes/widgets/label.edc
+++ b/data/themes/widgets/label.edc
@@ -30,7 +30,6 @@ group { name: "elm/label/base/default";
30 } 30 }
31 part { name: "elm.text"; 31 part { name: "elm.text";
32 type: TEXTBLOCK; 32 type: TEXTBLOCK;
33 mouse_events: 0;
34 scale: 1; 33 scale: 1;
35 clip_to: "label.text.clip"; 34 clip_to: "label.text.clip";
36 description { state: "default" 0.0; 35 description { state: "default" 0.0;
@@ -70,7 +69,6 @@ group { name: "elm/label/base/marker";
70 } 69 }
71 part { name: "elm.text"; 70 part { name: "elm.text";
72 type: TEXTBLOCK; 71 type: TEXTBLOCK;
73 mouse_events: 0;
74 scale: 1; 72 scale: 1;
75 description { state: "default" 0.0; 73 description { state: "default" 0.0;
76 text { 74 text {
@@ -161,7 +159,6 @@ group { name: "elm/label/base/slide_long";
161 } 159 }
162 part { name: "elm.text"; 160 part { name: "elm.text";
163 type: TEXTBLOCK; 161 type: TEXTBLOCK;
164 mouse_events: 0;
165 scale: 1; 162 scale: 1;
166 clip_to: "label.text.clip"; 163 clip_to: "label.text.clip";
167 description { state: "default" 0.0; 164 description { state: "default" 0.0;
@@ -287,7 +284,6 @@ group { name: "elm/label/base/slide_short";
287 } 284 }
288 part { name: "elm.text"; 285 part { name: "elm.text";
289 type: TEXTBLOCK; 286 type: TEXTBLOCK;
290 mouse_events: 0;
291 scale: 1; 287 scale: 1;
292 clip_to: "label.text.clip"; 288 clip_to: "label.text.clip";
293 description { state: "default" 0.0; 289 description { state: "default" 0.0;
@@ -424,7 +420,6 @@ group { name: "elm/label/base/slide_bounce";
424 } 420 }
425 part { name: "elm.text"; 421 part { name: "elm.text";
426 type: TEXTBLOCK; 422 type: TEXTBLOCK;
427 mouse_events: 0;
428 scale: 1; 423 scale: 1;
429 clip_to: "label.text.clip"; 424 clip_to: "label.text.clip";
430 description { state: "default" 0.0; 425 description { state: "default" 0.0;
diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am
index 9b6fb2ed7..5a52be5e7 100644
--- a/src/lib/Makefile.am
+++ b/src/lib/Makefile.am
@@ -51,6 +51,7 @@ elc_hoversel.c \
51elc_naviframe.c \ 51elc_naviframe.c \
52elc_player.c \ 52elc_player.c \
53elc_scrolled_entry.c \ 53elc_scrolled_entry.c \
54elm_access.c \
54elm_actionslider.c \ 55elm_actionslider.c \
55elm_bg.c \ 56elm_bg.c \
56elm_box.c \ 57elm_box.c \
diff --git a/src/lib/elm_access.c b/src/lib/elm_access.c
new file mode 100644
index 000000000..d441d63d9
--- /dev/null
+++ b/src/lib/elm_access.c
@@ -0,0 +1,245 @@
1#include <Elementary.h>
2#include "elm_priv.h"
3
4typedef struct _Mod_Api Mod_Api;
5
6struct _Mod_Api
7{
8 void (*out_read) (const char *txt);
9 void (*out_read_done) (void);
10 void (*out_cancel) (void);
11 void (*out_done_callback_set) (void (*func) (void *data), const void *data);
12};
13
14static int initted = 0;
15static Elm_Module *mod = NULL;
16static Mod_Api *mapi = NULL;
17
18static void
19_access_init(void)
20{
21 Elm_Module *m;
22 initted++;
23 if (initted > 1) return;
24 if (!(m = _elm_module_find_as("access/api"))) return;
25 mod = m;
26 m->api = malloc(sizeof(Mod_Api));
27 if (!m->api) return;
28 m->init_func(m);
29 ((Mod_Api *)(m->api) )->out_read = // called to read out some text
30 _elm_module_symbol_get(m, "out_read");
31 ((Mod_Api *)(m->api) )->out_read_done = // called to set a done marker so when it is reached the done callback is called
32 _elm_module_symbol_get(m, "out_read_done");
33 ((Mod_Api *)(m->api) )->out_cancel = // called to read out some text
34 _elm_module_symbol_get(m, "out_cancel");
35 ((Mod_Api *)(m->api) )->out_done_callback_set = // called when last read done
36 _elm_module_symbol_get(m, "out_done_callback_set");
37 mapi = m->api;
38}
39
40static Elm_Access_Item *
41_access_add_set(Elm_Access_Info *ac, int type)
42{
43 Elm_Access_Item *ai;
44 Eina_List *l;
45
46 if (!ac) return NULL;
47 EINA_LIST_FOREACH(ac->items, l, ai)
48 {
49 if (ai->type == type)
50 {
51 if (!ai->func)
52 {
53 if (ai->data) eina_stringshare_del(ai->data);
54 }
55 ai->func = NULL;
56 ai->data = NULL;
57 return ai;
58 }
59 }
60 ai = calloc(1, sizeof(Elm_Access_Item));
61 ai->type = type;
62 ac->items = eina_list_prepend(ac->items, ai);
63 return ai;
64}
65static Eina_Bool
66_access_obj_over_timeout_cb(void *data)
67{
68 Elm_Access_Info *ac = evas_object_data_get(data, "_elm_access");
69 if (!ac) return EINA_FALSE;
70 _elm_access_read(ac, ELM_ACCESS_CANCEL, data, NULL);
71 _elm_access_read(ac, ELM_ACCESS_TYPE, data, NULL);
72 _elm_access_read(ac, ELM_ACCESS_INFO, data, NULL);
73 _elm_access_read(ac, ELM_ACCESS_STATE, data, NULL);
74 _elm_access_read(ac, ELM_ACCESS_DONE, data, NULL);
75 ac->delay_timer = NULL;
76 return EINA_FALSE;
77}
78
79static void
80_access_obj_mouse_in_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
81{
82 Elm_Access_Info *ac = evas_object_data_get(data, "_elm_access");
83 if (!ac) return;
84
85 if (ac->delay_timer)
86 {
87 ecore_timer_del(ac->delay_timer);
88 ac->delay_timer = NULL;
89 }
90 ac->delay_timer = ecore_timer_add(0.2, _access_obj_over_timeout_cb, data);
91}
92
93static void
94_access_obj_mouse_out_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
95{
96 Elm_Access_Info *ac = evas_object_data_get(data, "_elm_access");
97 if (!ac) return;
98 if (ac->delay_timer)
99 {
100 ecore_timer_del(ac->delay_timer);
101 ac->delay_timer = NULL;
102 }
103}
104
105static void
106_access_obj_del_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
107{
108 Elm_Access_Info *ac;
109
110 evas_object_event_callback_del_full(obj, EVAS_CALLBACK_MOUSE_IN,
111 _access_obj_mouse_in_cb, data);
112 evas_object_event_callback_del_full(obj, EVAS_CALLBACK_MOUSE_OUT,
113 _access_obj_mouse_out_cb, data);
114 evas_object_event_callback_del_full(obj, EVAS_CALLBACK_DEL,
115 _access_obj_del_cb, data);
116 ac = evas_object_data_get(data, "_elm_access");
117 evas_object_data_del(data, "_elm_access");
118 if (ac)
119 {
120 _elm_access_clear(ac);
121 free(ac);
122 }
123}
124
125static void
126_access_read_done(void *data __UNUSED__)
127{
128 printf("read done\n");
129}
130
131//-------------------------------------------------------------------------//
132
133EAPI void
134_elm_access_clear(Elm_Access_Info *ac)
135{
136 Elm_Access_Item *ai;
137
138 if (!ac) return;
139 if (ac->delay_timer)
140 {
141 ecore_timer_del(ac->delay_timer);
142 ac->delay_timer = NULL;
143 }
144 EINA_LIST_FREE(ac->items, ai)
145 {
146 if (!ai->func)
147 {
148 if (ai->data) eina_stringshare_del(ai->data);
149 }
150 free(ai);
151 }
152}
153
154EAPI void
155_elm_access_text_set(Elm_Access_Info *ac, int type, const char *text)
156{
157 Elm_Access_Item *ai = _access_add_set(ac, type);
158 if (!ai) return;
159 ai->data = eina_stringshare_add(text);
160}
161
162EAPI void
163_elm_access_callback_set(Elm_Access_Info *ac, int type, Elm_Access_Content_Cb func, const void *data)
164{
165 Elm_Access_Item *ai = _access_add_set(ac, type);
166 if (!ai) return;
167 ai->func = func;
168 ai->data = data;
169}
170
171EAPI char *
172_elm_access_text_get(Elm_Access_Info *ac, int type, Evas_Object *obj, Elm_Widget_Item *item)
173{
174 Elm_Access_Item *ai;
175 Eina_List *l;
176
177 if (!ac) return NULL;
178 EINA_LIST_FOREACH(ac->items, l, ai)
179 {
180 if (ai->type == type)
181 {
182 if (ai->func) return ai->func(ai->data, obj, item);
183 else if (ai->data) return strdup(ai->data);
184 return NULL;
185 }
186 }
187 return NULL;
188}
189
190EAPI void
191_elm_access_read(Elm_Access_Info *ac, int type, Evas_Object *obj, Elm_Widget_Item *item)
192{
193 char *txt = _elm_access_text_get(ac, type, obj, item);
194
195 _access_init();
196 if (mapi)
197 {
198 if (mapi->out_done_callback_set)
199 mapi->out_done_callback_set(_access_read_done, NULL);
200 if (type == ELM_ACCESS_DONE)
201 {
202 if (mapi->out_read_done) mapi->out_read_done();
203 }
204 else if (type == ELM_ACCESS_CANCEL)
205 {
206 if (mapi->out_cancel) mapi->out_cancel();
207 }
208 else
209 {
210 if (txt)
211 {
212 if (mapi->out_read) mapi->out_read(txt);
213 if (mapi->out_read) mapi->out_read(".\n");
214 }
215 }
216 }
217 if (txt) free(txt);
218}
219
220EAPI Elm_Access_Info *
221_elm_access_object_get(Evas_Object *obj)
222{
223 return evas_object_data_get(obj, "_elm_access");
224}
225
226EAPI void
227_elm_access_object_register(Evas_Object *obj, Evas_Object *hoverobj)
228{
229 Elm_Access_Info *ac;
230
231 evas_object_event_callback_add(hoverobj, EVAS_CALLBACK_MOUSE_IN,
232 _access_obj_mouse_in_cb, obj);
233 evas_object_event_callback_add(hoverobj, EVAS_CALLBACK_MOUSE_OUT,
234 _access_obj_mouse_out_cb, obj);
235 evas_object_event_callback_add(hoverobj, EVAS_CALLBACK_DEL,
236 _access_obj_del_cb, obj);
237 ac = calloc(1, sizeof(Elm_Access_Info));
238 evas_object_data_set(obj, "_elm_access", ac);
239}
240
241// XXX special version for items
242//EAPI void
243//_elm_access_item_hover_register(Elm_Widget_Item *item, Evas_Object *hoverobj)
244//{
245//}
diff --git a/src/lib/elm_button.c b/src/lib/elm_button.c
index 1a4ae1de7..aba086999 100644
--- a/src/lib/elm_button.c
+++ b/src/lib/elm_button.c
@@ -316,6 +316,14 @@ _elm_button_label_get(const Evas_Object *obj, const char *item)
316 return wd->label; 316 return wd->label;
317} 317}
318 318
319static char *
320_access_info_cb(const void *data, Evas_Object *obj, Elm_Widget_Item *item)
321{
322 const char *txt = _elm_button_label_get(obj, NULL);
323 if (txt) return strdup(txt);
324 return txt;
325}
326
319EAPI Evas_Object * 327EAPI Evas_Object *
320elm_button_add(Evas_Object *parent) 328elm_button_add(Evas_Object *parent)
321{ 329{
@@ -359,6 +367,12 @@ elm_button_add(Evas_Object *parent)
359 // TODO: convert Elementary to subclassing of Evas_Smart_Class 367 // TODO: convert Elementary to subclassing of Evas_Smart_Class
360 // TODO: and save some bytes, making descriptions per-class and not instance! 368 // TODO: and save some bytes, making descriptions per-class and not instance!
361 evas_object_smart_callbacks_descriptions_set(obj, _signals); 369 evas_object_smart_callbacks_descriptions_set(obj, _signals);
370
371 _elm_access_object_register(obj, wd->btn);
372 _elm_access_text_set(_elm_access_object_get(obj),
373 ELM_ACCESS_TYPE, E_("Button"));
374 _elm_access_callback_set(_elm_access_object_get(obj),
375 ELM_ACCESS_INFO, _access_info_cb, obj);
362 return obj; 376 return obj;
363} 377}
364 378
diff --git a/src/lib/elm_widget.h b/src/lib/elm_widget.h
index 5d17bb940..9706e4931 100644
--- a/src/lib/elm_widget.h
+++ b/src/lib/elm_widget.h
@@ -192,11 +192,45 @@ typedef struct _Elm_Tooltip Elm_Tooltip;
192typedef struct _Elm_Cursor Elm_Cursor; 192typedef struct _Elm_Cursor Elm_Cursor;
193typedef struct _Elm_Widget_Item Elm_Widget_Item; /**< base structure for all widget items that are not Elm_Widget themselves */ 193typedef struct _Elm_Widget_Item Elm_Widget_Item; /**< base structure for all widget items that are not Elm_Widget themselves */
194 194
195typedef void (*Elm_Widget_On_Text_Set_Cb)(void *, const char *part, const char *text); 195typedef struct _Elm_Access_Info Elm_Access_Info; /**< accessibility information to be able to set and get from the access API */
196typedef void (*Elm_Widget_On_Content_Set_Cb)(void *, const char *part, Evas_Object *content); 196typedef struct _Elm_Access_Item Elm_Access_Item; /**< accessibility info item */
197typedef const char *(*Elm_Widget_On_Text_Get_Cb)(const void *, const char *part); 197
198typedef Evas_Object *(*Elm_Widget_On_Content_Get_Cb)(const void *, const char *part); 198typedef void (*Elm_Widget_On_Text_Set_Cb)(void *data, const char *part, const char *text);
199typedef Evas_Object *(*Elm_Widget_On_Content_Unset_Cb)(const void *, const char *part); 199typedef void (*Elm_Widget_On_Content_Set_Cb)(void *data, const char *part, Evas_Object *content);
200typedef const char *(*Elm_Widget_On_Text_Get_Cb)(const void *data, const char *part);
201typedef Evas_Object *(*Elm_Widget_On_Content_Get_Cb)(const void *data, const char *part);
202typedef Evas_Object *(*Elm_Widget_On_Content_Unset_Cb)(const void *data, const char *part);
203
204#define ELM_ACCESS_TYPE 0 // when reading out widget or item this is read first
205#define ELM_ACCESS_INFO 1 // next read is info - this is normally label
206#define ELM_ACCESS_STATE 2 // if there is a state (eg checkbox) then read state out
207#define ELM_ACCESS_CONTENT 3 // read ful content - eg all of the label, not a shortened version
208
209#define ELM_ACCESS_DONE -1 // sentence done - send done event here
210#define ELM_ACCESS_CANCEL -2 // stop reading immediately
211
212typedef char *(*Elm_Access_Content_Cb)(const void *data, Evas_Object *obj, Elm_Widget_Item *item);
213
214struct _Elm_Access_Item
215{
216 int type;
217 const void *data;
218 Elm_Access_Content_Cb func;
219};
220
221struct _Elm_Access_Info
222{
223 Eina_List *items;
224 Ecore_Timer *delay_timer;
225};
226
227EAPI void _elm_access_clear(Elm_Access_Info *ac);
228EAPI void _elm_access_text_set(Elm_Access_Info *ac, int type, const char *text);
229EAPI void _elm_access_callback_set(Elm_Access_Info *ac, int type, Elm_Access_Content_Cb func, const void *data);
230EAPI char *_elm_access_text_get(Elm_Access_Info *ac, int type, Evas_Object *obj, Elm_Widget_Item *item);
231EAPI void _elm_access_read(Elm_Access_Info *ac, int type, Evas_Object *obj, Elm_Widget_Item *item);
232EAPI Elm_Access_Info *_elm_access_object_get(Evas_Object *obj);
233EAPI void _elm_access_object_register(Evas_Object *obj, Evas_Object *hoverobj);
200 234
201struct _Elm_Widget_Item 235struct _Elm_Widget_Item
202{ 236{
diff --git a/src/modules/Makefile.am b/src/modules/Makefile.am
index b00ad7ef7..9354af629 100644
--- a/src/modules/Makefile.am
+++ b/src/modules/Makefile.am
@@ -3,4 +3,5 @@ MAINTAINERCLEANFILES = Makefile.in
3 3
4SUBDIRS = \ 4SUBDIRS = \
5test_entry \ 5test_entry \
6test_map 6test_map \
7access_output
diff --git a/src/modules/access_output/Makefile.am b/src/modules/access_output/Makefile.am
new file mode 100644
index 000000000..0cf21873d
--- /dev/null
+++ b/src/modules/access_output/Makefile.am
@@ -0,0 +1,33 @@
1
2MAINTAINERCLEANFILES = Makefile.in
3
4AM_CPPFLAGS = \
5-I. \
6-I$(top_builddir) \
7-I$(top_srcdir) \
8-I$(top_srcdir)/src/lib \
9-I$(top_builddir)/src/lib \
10-DPACKAGE_DATA_DIR=\"$(datadir)/$(PACKAGE)\" \
11-DPACKAGE_LIB_DIR=\"$(libdir)\" \
12@ELEMENTARY_CFLAGS@ \
13@ELEMENTARY_X_CFLAGS@ \
14@ELEMENTARY_FB_CFLAGS@ \
15@ELEMENTARY_WIN32_CFLAGS@ \
16@ELEMENTARY_WINCE_CFLAGS@ \
17@ELEMENTARY_EDBUS_CFLAGS@ \
18@ELEMENTARY_EFREET_CFLAGS@ \
19@ELEMENTARY_ETHUMB_CFLAGS@ \
20@ELEMENTARY_EMAP_CFLAGS@
21
22if ELEMENTARY_WINDOWS_BUILD
23AM_CPPFLAGS += -DELEMENTARY_BUILD
24endif
25
26pkgdir = $(libdir)/elementary/modules/access_output/$(MODULE_ARCH)
27pkg_LTLIBRARIES = module.la
28
29module_la_SOURCES = mod.c
30
31module_la_LIBADD = $(top_builddir)/src/lib/libelementary.la
32module_la_LDFLAGS = -no-undefined @lt_enable_auto_import@ -module -avoid-version
33module_la_LIBTOOLFLAGS = --tag=disable-static
diff --git a/src/modules/access_output/mod.c b/src/modules/access_output/mod.c
new file mode 100644
index 000000000..79e97990d
--- /dev/null
+++ b/src/modules/access_output/mod.c
@@ -0,0 +1,116 @@
1#include <Elementary.h>
2#ifdef HAVE_CONFIG_H
3# include "elementary_config.h"
4#endif
5
6/* to enable this module
7export ELM_MODULES="access_output>access/api"
8 */
9
10static void (*cb_func) (void *data);
11static void *cb_data;
12static Ecore_Exe *espeak = NULL;
13static Ecore_Event_Handler *exe_exit_handler = NULL;
14static char *tmpf = NULL;
15static int tmpfd = -1;
16
17static Eina_Bool
18_exe_del(void *data __UNUSED__, int type __UNUSED__, void *event)
19{
20 Ecore_Exe_Event_Del *ev = event;
21
22 if ((espeak) && (ev->exe == espeak))
23 {
24 if (tmpf)
25 {
26 unlink(tmpf);
27 free(tmpf);
28 tmpf = NULL;
29 close(tmpfd);
30 }
31 espeak = NULL;
32 if (cb_func) cb_func(cb_data);
33 }
34 return ECORE_CALLBACK_RENEW;
35}
36
37// module api funcs needed
38EAPI int
39elm_modapi_init(void *m __UNUSED__)
40{
41 exe_exit_handler =
42 ecore_event_handler_add(ECORE_EXE_EVENT_DEL,
43 _exe_del, NULL);
44 return 1; // succeed always
45}
46
47EAPI int
48elm_modapi_shutdown(void *m __UNUSED__)
49{
50 if (exe_exit_handler)
51 {
52 ecore_event_handler_del(exe_exit_handler);
53 exe_exit_handler = NULL;
54 }
55 return 1; // succeed always
56}
57
58// module fucns for the specific module type
59EAPI void
60out_read(const char *txt)
61{
62 if (!tmpf)
63 {
64 char buf[PATH_MAX];
65
66 snprintf(buf, sizeof(buf), "/tmp/.elm-speak-XXXXXX");
67 tmpfd = mkstemp(buf);
68 if (tmpfd >= 0) tmpf = strdup(buf);
69 else return;
70 }
71 if (write(tmpfd, txt, strlen(txt)) < 0) perror("write to tmpfile (espeak)");
72}
73
74EAPI void
75out_read_done(void)
76{
77 char buf[PATH_MAX];
78
79 if (espeak)
80 {
81 ecore_exe_interrupt(espeak);
82 espeak = NULL;
83 }
84 if (tmpf)
85 {
86 close(tmpfd);
87 snprintf(buf, sizeof(buf), "espeak -m -a 20 -f %s", tmpf);
88 espeak = ecore_exe_pipe_run(buf,
89 ECORE_EXE_NOT_LEADER,
90 NULL);
91 }
92}
93
94EAPI void
95out_cancel(void)
96{
97 if (espeak)
98 {
99 ecore_exe_interrupt(espeak);
100 espeak = NULL;
101 }
102 if (tmpf)
103 {
104 unlink(tmpf);
105 free(tmpf);
106 tmpf = NULL;
107 close(tmpfd);
108 }
109}
110
111EAPI void
112out_done_callback_set(void (*func) (void *data), const void *data)
113{
114 cb_func = func;
115 cb_data = (void *)data;
116}