add access module - bare bones, but intercepts all mouse events and
authorCarsten Haitzler <raster@rasterman.com>
Tue, 22 May 2012 12:13:18 +0000 (12:13 +0000)
committerCarsten Haitzler <raster@rasterman.com>
Tue, 22 May 2012 12:13:18 +0000 (12:13 +0000)
handles gestures and passes on commands to the focused app or maybe
fakes a tap event on the screen location - depending. things that
could be done here:

1. config to select which actions happen as a result of which
events/gestures
2. config to determine which zones get this access setup and whihc
don't.

SVN revision: 71323

src/modules/Makefile.am
src/modules/access/Makefile.am [new file with mode: 0644]
src/modules/access/e-module-access.edj [new file with mode: 0644]
src/modules/access/e_mod_config.c [new file with mode: 0644]
src/modules/access/e_mod_main.c [new file with mode: 0644]
src/modules/access/e_mod_main.h [new file with mode: 0644]
src/modules/access/module.desktop.in [new file with mode: 0644]

index 83bf770..0701b45 100644 (file)
@@ -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 (file)
index 0000000..e2c08dd
--- /dev/null
@@ -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 (file)
index 0000000..75aa3dc
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 (file)
index 0000000..ba854a5
--- /dev/null
@@ -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 (file)
index 0000000..5f58d30
--- /dev/null
@@ -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 (file)
index 0000000..f884cc0
--- /dev/null
@@ -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 (file)
index 0000000..fd83f3c
--- /dev/null
@@ -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.