diff --git a/src/modules/Makefile.am b/src/modules/Makefile.am index 83bf77018..0701b45b8 100644 --- a/src/modules/Makefile.am +++ b/src/modules/Makefile.am @@ -199,6 +199,10 @@ if USE_MODULE_TILING SUBDIRS += tiling endif +if USE_MODULE_ACCESS +SUBDIRS += access +endif + #if HAVE_WAYLAND_DRM # SUBDIRS += wl_drm #endif diff --git a/src/modules/access/Makefile.am b/src/modules/access/Makefile.am new file mode 100644 index 000000000..e2c08dd3a --- /dev/null +++ b/src/modules/access/Makefile.am @@ -0,0 +1,29 @@ +MAINTAINERCLEANFILES = Makefile.in +MODULE = access + +# data files for the module +filesdir = $(libdir)/enlightenment/modules/$(MODULE) +files_DATA = \ +e-module-$(MODULE).edj module.desktop + +EXTRA_DIST = $(files_DATA) + +# the module .so file +INCLUDES = -I. \ + -I$(top_srcdir) \ + -I$(top_srcdir)/src/modules/$(MODULE) \ + -I$(top_srcdir)/src/bin \ + -I$(top_builddir)/src/bin \ + -I$(top_srcdir)/src/modules \ + @e_cflags@ +pkgdir = $(libdir)/enlightenment/modules/$(MODULE)/$(MODULE_ARCH) +pkg_LTLIBRARIES = module.la +module_la_SOURCES = e_mod_main.c \ + e_mod_main.h \ + e_mod_config.c +module_la_LIBADD = @e_libs@ @dlopen_libs@ +module_la_LDFLAGS = -module -avoid-version +module_la_DEPENDENCIES = $(top_builddir)/config.h + +uninstall: + rm -rf $(DESTDIR)$(libdir)/enlightenment/modules/$(MODULE) diff --git a/src/modules/access/e-module-access.edj b/src/modules/access/e-module-access.edj new file mode 100644 index 000000000..75aa3dc0b Binary files /dev/null and b/src/modules/access/e-module-access.edj differ diff --git a/src/modules/access/e_mod_config.c b/src/modules/access/e_mod_config.c new file mode 100644 index 000000000..ba854a54f --- /dev/null +++ b/src/modules/access/e_mod_config.c @@ -0,0 +1,80 @@ +#include "e.h" +#include "e_mod_main.h" + +struct _E_Config_Dialog_Data +{ + int dummy; +}; + +/* local function prototypes */ +static void *_create_data (E_Config_Dialog *cfd); +static void _fill_data (E_Config_Dialog_Data *cfdata); +static void _free_data (E_Config_Dialog *cfd __UNUSED__, E_Config_Dialog_Data *cfdata); +static Evas_Object *_basic_create(E_Config_Dialog *cfd __UNUSED__, Evas *evas, E_Config_Dialog_Data *cfdata); +static int _basic_apply (E_Config_Dialog *cfd __UNUSED__, E_Config_Dialog_Data *cfdata); + +void +_config_pager_module(void) +{ + E_Config_Dialog *cfd; + E_Config_Dialog_View *v; + E_Container *con; + + if (e_config_dialog_find("E", "_e_mod_access_config_dialog")) + return; + v = E_NEW(E_Config_Dialog_View, 1); + if (!v) return; + + v->create_cfdata = _create_data; + v->free_cfdata = _free_data; + v->basic.create_widgets = _basic_create; + v->basic.apply_cfdata = _basic_apply; + + con = e_container_current_get(e_manager_current_get()); + cfd = e_config_dialog_new(con, _("Access Settings"), "E", + "_e_mod_access_config_dialog", + "preferences-desktop-access", 0, v, NULL); +} + +/* local function prototypes */ +static void * +_create_data(E_Config_Dialog *cfd __UNUSED__) +{ + E_Config_Dialog_Data *cfdata; + + cfdata = E_NEW(E_Config_Dialog_Data, 1); + _fill_data(cfdata); + return cfdata; +} + +static void +_fill_data(E_Config_Dialog_Data *cfdata) +{ + cfdata->dummy = 1; +} + +static void +_free_data(E_Config_Dialog *cfd __UNUSED__, E_Config_Dialog_Data *cfdata) +{ + E_FREE(cfdata); +} + +static Evas_Object * +_basic_create(E_Config_Dialog *cfd __UNUSED__, Evas *evas, E_Config_Dialog_Data *cfdata) +{ + Evas_Object *ol, *of; + + ol = e_widget_list_add(evas, 0, 0); + + of = e_widget_framelist_add(evas, _("General"), 0); + e_widget_list_object_append(ol, of, 1, 0, 0.5); + + return ol; +} + +static int +_basic_apply(E_Config_Dialog *cfd __UNUSED__, E_Config_Dialog_Data *cfdata) +{ + e_config_save_queue(); + return 1; +} diff --git a/src/modules/access/e_mod_main.c b/src/modules/access/e_mod_main.c new file mode 100644 index 000000000..5f58d3005 --- /dev/null +++ b/src/modules/access/e_mod_main.c @@ -0,0 +1,404 @@ +#include "e.h" +#include "e_mod_main.h" + +typedef struct +{ + E_Zone *zone; + Ecore_X_Window win; + Ecore_Timer *timer; + int x, y, dx, dy; + unsigned int dt; + Eina_Bool down : 1; +} Cover; + +static Eina_List *covers = NULL; +static Eina_List *handlers = NULL; + +static Ecore_X_Window +_mouse_win_in_get(Cover *cov, int x, int y) +{ + Eina_List *l; + Ecore_X_Window *skip, inwin; + Cover *cov2; + int i; + + skip = alloca(sizeof(Ecore_X_Window) * eina_list_count(covers)); + i = 0; + EINA_LIST_FOREACH(covers, l, cov2) + { + skip[i] = cov2->win; + i++; + } + inwin = ecore_x_window_shadow_tree_at_xy_with_skip_get + (cov->zone->container->manager->root, x, y, skip, i); + return inwin; +} + +static void +_mouse_win_fake_tap(Cover *cov, Ecore_Event_Mouse_Button *ev) +{ + Ecore_X_Window inwin; + int x, y; + + inwin = _mouse_win_in_get(cov, ev->root.x, ev->root.y); + ecore_x_pointer_xy_get(inwin, &x, &y); + ecore_x_mouse_in_send(inwin, x, y); + ecore_x_mouse_move_send(inwin, x, y); + ecore_x_mouse_down_send(inwin, x, y, 1); + ecore_x_mouse_up_send(inwin, x, y, 1); + ecore_x_mouse_out_send(inwin, x, y); +} + +static Eina_Bool +_mouse_longpress(void *data) +{ + Cover *cov = data; + int distance = 40; + int dx, dy; + + cov->timer = NULL; + dx = cov->x - cov->dx; + dy = cov->y - cov->dy; + if (((dx * dx) + (dy * dy)) < (distance * distance)) + { + E_Border *bd = e_border_focused_get(); + + cov->down = EINA_FALSE; + printf("longpress\n"); + if (bd) + ecore_x_e_illume_access_action_read_send(bd->client.win); + } + return EINA_FALSE; +} + +static void +_mouse_down(Cover *cov, Ecore_Event_Mouse_Button *ev) +{ + double longtime = 0.5; + + cov->dx = ev->x; + cov->dy = ev->y; + cov->x = ev->x; + cov->y = ev->y; + cov->dt = ev->timestamp; + cov->down = EINA_TRUE; + cov->timer = ecore_timer_add(longtime, _mouse_longpress, cov); +} + +static void +_mouse_up(Cover *cov, Ecore_Event_Mouse_Button *ev) +{ + double timeout = 0.15; + int distance = 40; + int dx, dy; + E_Border *bd = e_border_focused_get(); + + if (cov->timer) + { + ecore_timer_del(cov->timer); + cov->timer = NULL; + } + if (!cov->down) return; + dx = ev->x - cov->dx; + dy = ev->y - cov->dy; + if (((dx * dx) + (dy * dy)) < (distance * distance)) + { + if ((ev->timestamp - cov->dt) > (timeout * 1000)) + { + printf("tap\n"); + _mouse_win_fake_tap(cov, ev); + } + else if (ev->double_click) + { + printf("double click\n"); + if (bd) + ecore_x_e_illume_access_action_activate_send(bd->client.win); + } + } + else + { + if (abs(dx) > abs(dy)) // left or right + { + if (dx > 0) // right + { + printf("right\n"); + if (bd) + ecore_x_e_illume_access_action_read_next_send(bd->client.win); + } + else // left + { + printf("left\n"); + if (bd) + ecore_x_e_illume_access_action_read_prev_send(bd->client.win); + } + } + else // up or down + { + if (dy > 0) // down + { + printf("down\n"); + if (bd) + ecore_x_e_illume_access_action_next_send(bd->client.win); + } + else // up + { + printf("up\n"); + if (bd) + ecore_x_e_illume_access_action_prev_send(bd->client.win); + } + } + } + cov->down = EINA_FALSE; +} + +static void +_mouse_move(Cover *cov, Ecore_Event_Mouse_Move *ev) +{ + if (!cov->down) return; + cov->x = ev->x; + cov->y = ev->y; +} + +static void +_mouse_wheel(Cover *cov __UNUSED__, Ecore_Event_Mouse_Wheel *ev __UNUSED__) +{ + // XXX: fake wheel? +} + +static Eina_Bool +_cb_mouse_down(void *data __UNUSED__, + int type __UNUSED__, + void *event) +{ + Ecore_Event_Mouse_Button *ev = event; + Eina_List *l; + Cover *cov; + + EINA_LIST_FOREACH(covers, l, cov) + { + if (ev->window == cov->win) + { + if ((ev->buttons == 1) && (ev->multi.device == 0)) + _mouse_down(cov, ev); + return ECORE_CALLBACK_PASS_ON; + } + } + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_cb_mouse_up(void *data __UNUSED__, + int type __UNUSED__, + void *event) +{ + Ecore_Event_Mouse_Button *ev = event; + Eina_List *l; + Cover *cov; + + EINA_LIST_FOREACH(covers, l, cov) + { + if (ev->window == cov->win) + { + if ((ev->buttons == 1) && (ev->multi.device == 0)) + _mouse_up(cov, ev); + return ECORE_CALLBACK_PASS_ON; + } + } + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_cb_mouse_move(void *data __UNUSED__, + int type __UNUSED__, + void *event) +{ + Ecore_Event_Mouse_Move *ev = event; + Eina_List *l; + Cover *cov; + + EINA_LIST_FOREACH(covers, l, cov) + { + if (ev->window == cov->win) + { + if (ev->multi.device == 0) + _mouse_move(cov, ev); + return ECORE_CALLBACK_PASS_ON; + } + } + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_cb_mouse_wheel(void *data __UNUSED__, + int type __UNUSED__, + void *event) +{ + Ecore_Event_Mouse_Wheel *ev = event; + Eina_List *l; + Cover *cov; + + EINA_LIST_FOREACH(covers, l, cov) + { + if (ev->window == cov->win) + { + _mouse_wheel(cov, ev); + return ECORE_CALLBACK_PASS_ON; + } + } + return ECORE_CALLBACK_PASS_ON; +} + +static Cover * +_cover_new(E_Zone *zone) +{ + Cover *cov; + + cov = E_NEW(Cover, 1); + if (!cov) return NULL; + cov->zone = zone; + cov->win = ecore_x_window_input_new(zone->container->manager->root, + zone->container->x + zone->x, + zone->container->y + zone->y, + zone->w, zone->h); + ecore_x_window_ignore_set(cov->win, 1); + ecore_x_window_configure(cov->win, + ECORE_X_WINDOW_CONFIGURE_MASK_SIBLING | + ECORE_X_WINDOW_CONFIGURE_MASK_STACK_MODE, + 0, 0, 0, 0, 0, + zone->container->layers[8].win, + ECORE_X_WINDOW_STACK_ABOVE); + ecore_x_window_show(cov->win); + return cov; +} + +static void +_covers_init(void) +{ + Eina_List *l, *l2, *l3; + E_Manager *man; + + EINA_LIST_FOREACH(e_manager_list(), l, man) + { + E_Container *con; + + EINA_LIST_FOREACH(man->containers, l2, con) + { + E_Zone *zone; + + EINA_LIST_FOREACH(con->zones, l3, zone) + { + Cover *cov = _cover_new(zone); + if (cov) covers = eina_list_append(covers, cov); + } + } + } +} + +static void +_covers_shutdown(void) +{ + Cover *cov; + + EINA_LIST_FREE(covers, cov) + { + ecore_x_window_ignore_set(cov->win, 0); + ecore_x_window_free(cov->win); + if (cov->timer) + { + ecore_timer_del(cov->timer); + cov->timer = NULL; + } + free(cov); + } +} + +static Eina_Bool +_cb_zone_add(void *data __UNUSED__, + int type __UNUSED__, + void *event __UNUSED__) +{ + _covers_init(); + _covers_shutdown(); + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_cb_zone_del(void *data __UNUSED__, + int type __UNUSED__, + void *event __UNUSED__) +{ + _covers_init(); + _covers_shutdown(); + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_cb_zone_move_resize(void *data __UNUSED__, + int type __UNUSED__, + void *event __UNUSED__) +{ + _covers_init(); + _covers_shutdown(); + return ECORE_CALLBACK_PASS_ON; +} + +static void +_events_init(void) +{ + handlers = eina_list_append + (handlers, ecore_event_handler_add(ECORE_EVENT_MOUSE_BUTTON_DOWN, + _cb_mouse_down, NULL)); + handlers = eina_list_append + (handlers, ecore_event_handler_add(ECORE_EVENT_MOUSE_BUTTON_UP, + _cb_mouse_up, NULL)); + handlers = eina_list_append + (handlers, ecore_event_handler_add(ECORE_EVENT_MOUSE_MOVE, + _cb_mouse_move, NULL)); + handlers = eina_list_append + (handlers, ecore_event_handler_add(ECORE_EVENT_MOUSE_WHEEL, + _cb_mouse_wheel, NULL)); + handlers = eina_list_append + (handlers, ecore_event_handler_add(E_EVENT_ZONE_ADD, + _cb_zone_add, NULL)); + handlers = eina_list_append + (handlers, ecore_event_handler_add(E_EVENT_ZONE_DEL, + _cb_zone_del, NULL)); + handlers = eina_list_append + (handlers, ecore_event_handler_add(E_EVENT_ZONE_MOVE_RESIZE, + _cb_zone_move_resize, NULL)); +} + +static void +_events_shutdown(void) +{ + E_FREE_LIST(handlers, ecore_event_handler_del); +} + +/***************************************************************************/ +/* module setup */ +EAPI E_Module_Api e_modapi = +{ + E_MODULE_API_VERSION, "Access" +}; + +EAPI void * +e_modapi_init(E_Module *m) +{ + _events_init(); + _covers_init(); + return m; +} + +EAPI int +e_modapi_shutdown(E_Module *m __UNUSED__) +{ + _covers_shutdown(); + _events_shutdown(); + return 1; +} + +EAPI int +e_modapi_save(E_Module *m __UNUSED__) +{ + return 1; +} diff --git a/src/modules/access/e_mod_main.h b/src/modules/access/e_mod_main.h new file mode 100644 index 000000000..f884cc0aa --- /dev/null +++ b/src/modules/access/e_mod_main.h @@ -0,0 +1,10 @@ +#ifndef E_MOD_MAIN_H +#define E_MOD_MAIN_H + +EAPI extern E_Module_Api e_modapi; + +EAPI void *e_modapi_init(E_Module *m); +EAPI int e_modapi_shutdown(E_Module *m); +EAPI int e_modapi_save(E_Module *m); + +#endif diff --git a/src/modules/access/module.desktop.in b/src/modules/access/module.desktop.in new file mode 100644 index 000000000..fd83f3c00 --- /dev/null +++ b/src/modules/access/module.desktop.in @@ -0,0 +1,6 @@ +[Desktop Entry] +Type=Link +Name=Access +Icon=e-module-access +X-Enlightenment-ModuleType=utils +Comment=Accessibility module designed to improve ease of use for the vision impaired and the blind.