tizen 2.4 release accepted/tizen_2.4_mobile tizen_2.4 accepted/tizen/2.4/mobile/20151029.031134 submit/tizen_2.4/20151028.064919 tizen_2.4_mobile_release
authorjk7744.park <jk7744.park@samsung.com>
Mon, 26 Oct 2015 06:51:48 +0000 (15:51 +0900)
committerjk7744.park <jk7744.park@samsung.com>
Mon, 26 Oct 2015 06:51:48 +0000 (15:51 +0900)
20 files changed:
AUTHORS [new file with mode: 0644]
COPYING [new file with mode: 0644]
ChangeLog [new file with mode: 0644]
INSTALL [new file with mode: 0644]
Makefile.am [new file with mode: 0644]
NEWS [new file with mode: 0644]
README [new file with mode: 0644]
autogen.sh [new file with mode: 0755]
configure.ac [new file with mode: 0644]
e17-mod-tizen-screen-reader.manifest [new file with mode: 0644]
packaging/e17-mod-tizen-screen-reader.spec [new file with mode: 0755]
src/Makefile.am [new file with mode: 0644]
src/e17.xml [new file with mode: 0644]
src/e_mod_config.c [new file with mode: 0644]
src/e_mod_config.h [new file with mode: 0644]
src/e_mod_gestures.c [new file with mode: 0644]
src/e_mod_main.c [new file with mode: 0644]
src/e_mod_main.h [new file with mode: 0644]
src/e_mod_private.h [new file with mode: 0644]
src/e_mod_window_tracker.c [new file with mode: 0644]

diff --git a/AUTHORS b/AUTHORS
new file mode 100644 (file)
index 0000000..9d307d2
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1 @@
+l.stanislaws@samsung.com
diff --git a/COPYING b/COPYING
new file mode 100644 (file)
index 0000000..4556b54
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,25 @@
+Copyright notice for Enlightenment:
+
+Copyright (C) 2000-2012 Carsten Haitzler and various contributors (see AUTHORS)
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+   1. Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+   2. Redistributions in binary form must reproduce the above copyright 
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/ChangeLog b/ChangeLog
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/INSTALL b/INSTALL
new file mode 100644 (file)
index 0000000..f903286
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,25 @@
+Installation:
+
+
+Config adjustment:
+
+1. Dump current e.cfg content to text file.
+$ eet -d e.cfg config > e.dump
+
+2. Edit e.dump file, in "modules" group add following entry:
+
+Example (this can be changed depending on your needs):
+
+    group "E_Config_Module" struct {
+      value "name" string: "e-atspi";
+      value "enabled" uchar: 1;
+      value "delayed" uchar: 1;
+      value "priority" int: -3000;
+    }
+
+3. Encode e.dump as eet file
+
+$ eet -e e.cfg config e.dump 1
+
+4. Ensuer that enlightenment process will have access to created e.cfg file.
+   (check user, group, smack label)
diff --git a/Makefile.am b/Makefile.am
new file mode 100644 (file)
index 0000000..ea62ff3
--- /dev/null
@@ -0,0 +1,6 @@
+SUBDIRS = src
+
+MAINTAINERCLEANFILES = \
+                      Makefile.in
+
+EXTRA_DIST = README AUTHORS COPYING autogen.sh
diff --git a/NEWS b/NEWS
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/autogen.sh b/autogen.sh
new file mode 100755 (executable)
index 0000000..2e01663
--- /dev/null
@@ -0,0 +1,8 @@
+#!/bin/sh
+# Run this to generate all the initial makefiles, etc.
+
+rm -rf autom4te.cache
+rm -f aclocal.m4 ltmain.sh
+
+echo "Running autoreconf..." ; autoreconf -v --install || exit 1
+echo "Running configure..." ; ./configure "$@"
diff --git a/configure.ac b/configure.ac
new file mode 100644 (file)
index 0000000..9079d1e
--- /dev/null
@@ -0,0 +1,33 @@
+# Process this file with autoconf to produce a configure script.
+dnl Process this file with autoconf to produce a configure script.
+
+# get rid of that stupid cache mechanism
+rm -f config.cache
+
+AC_INIT([e17-mod-tizen-screen-reader], [0.1.0], [dev@lists.tizen.org])
+AC_PREREQ([2.52])
+AC_CONFIG_SRCDIR([configure.ac])
+AM_CONFIG_HEADER([config.h])
+
+AM_INIT_AUTOMAKE([1.8])
+
+AC_PROG_CC
+AM_PROG_CC_STDC
+AM_PROG_CC_C_O
+AC_PROG_LIBTOOL
+
+PKG_CHECK_MODULES(ENLIGHTENMENT, [enlightenment, vconf, dlog])
+AC_SUBST(ENLIGHTENMENT_CFLAGS)
+AC_SUBST(ENLIGHTENMENT_LIBS)
+
+release=$(pkg-config --variable=release enlightenment)
+MODULE_ARCH="$host_os-$host_cpu-$release"
+AC_SUBST(MODULE_ARCH)
+AC_DEFINE_UNQUOTED(MODULE_ARCH, "$MODULE_ARCH", "Module architecture")
+
+AC_CONFIG_FILES([
+Makefile
+src/Makefile
+])
+
+AC_OUTPUT
diff --git a/e17-mod-tizen-screen-reader.manifest b/e17-mod-tizen-screen-reader.manifest
new file mode 100644 (file)
index 0000000..5cfabc0
--- /dev/null
@@ -0,0 +1,13 @@
+<manifest>
+   <define>
+      <domain name="e17-mod-tizen-screen-reader"/>
+   </define>
+   <request>
+      <domain name="e17-mod-tizen-screen-reader"/>
+   </request>
+   <assign>
+      <filesystem path="/usr/bin/extndialog" label="e17" exec_label="e17" />
+      <filesystem path="/usr/bin/elogwatcher" label="_" exec_label="none" />
+      <filesystem path="/usr/bin/keygrab_status" label="_" exec_label="none" />
+   </assign>
+</manifest>
diff --git a/packaging/e17-mod-tizen-screen-reader.spec b/packaging/e17-mod-tizen-screen-reader.spec
new file mode 100755 (executable)
index 0000000..a23fb73
--- /dev/null
@@ -0,0 +1,33 @@
+Name:       e17-mod-tizen-screen-reader
+Summary:    The Enlightenment module providing screen-wide gestures recognition.
+Version:    0.1.1
+Release:    1
+Group:      System/GUI/Other
+License:    BSD 2-clause
+Source0:    %{name}-%{version}.tar.gz
+BuildRequires:  pkgconfig(enlightenment)
+BuildRequires:  pkgconfig(vconf)
+BuildRequires:  cmake
+BuildRequires:  gettext
+BuildRequires:  edje-tools
+
+%description
+The Enlightenment extra module providing screen-wide gestures recognition api
+over dbus.
+
+%prep
+%setup -q
+
+
+%build
+%autogen --prefix=/usr
+make %{?jobs:-j%jobs}
+
+%install
+rm -rf %{buildroot}
+%make_install
+
+%files
+%manifest e17-mod-tizen-screen-reader.manifest
+%defattr(-,root,root,-)
+%{_libdir}/enlightenment/modules/e17-mod-tizen-screen-reader
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644 (file)
index 0000000..d838d62
--- /dev/null
@@ -0,0 +1,15 @@
+MAINTAINERCLEANFILES = Makefile.in
+MODULE = e17-mod-tizen-screen-reader
+
+LDFLAGS +=
+
+pkgdir                 = $(libdir)/enlightenment/modules/$(MODULE)/$(MODULE_ARCH)
+pkg_LTLIBRARIES        = module.la
+module_la_SOURCES      = e_mod_main.c \
+                         e_mod_config.c \
+                         e_mod_gestures.c \
+                         e_mod_window_tracker.c
+
+module_la_LIBADD       =
+module_la_CFLAGS       = @ENLIGHTENMENT_CFLAGS@
+module_la_LDFLAGS      = -module -avoid-version @ENLIGHTENMENT_LIBS@
diff --git a/src/e17.xml b/src/e17.xml
new file mode 100644 (file)
index 0000000..8a76087
--- /dev/null
@@ -0,0 +1,35 @@
+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
+"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
+
+<bus name="com.samsung.EATSPI">
+<node name="/com/samsung/GestureNavigation">
+       <interface name="com.samsung.GestureNaviation">
+               <property name="Enabled" type="b" access="readwrite"/>
+               <method name="GetSupportedGestures">
+                       <arg name="types" type="as" direction="out"/>
+               </method>
+               -- ssii signature describes:
+               -- s: gesture name (specification later).
+               -- i: x coordiantes where gesture begin
+               -- i: y coordiantes where gesture begin
+               -- i: x coordiantes where gesture ended
+               -- i: y coordiantes where gesture ended
+               <signal name="GestureDetected">
+                       <arg name="type" type="siiiiu"/>
+               </signal>
+</node>
+<node name="/com/samsung/WindowTracker">
+       </interface>
+       <interface name="com.samsung.WindowTracker">
+               -- i: pid of process creating window
+               -- i: X-ish id of window
+               <method name="GetActiveWindow">
+                       <arg name="types" type="ii" direction="out"/>
+               </method>
+               -- i: pid of process creating window
+               -- i: X-ish id of window
+               <signal name="ActiveWindowChanged">
+                       <arg name="type" type="ii"/>
+               </signal>
+       </interface>
+</node>
diff --git a/src/e_mod_config.c b/src/e_mod_config.c
new file mode 100644 (file)
index 0000000..a61e12a
--- /dev/null
@@ -0,0 +1,63 @@
+#include <e.h>
+#include <e_mod_config.h>
+#include <e_mod_private.h>
+
+Gestures_Config *_e_mod_config;
+
+static E_Config_DD *_conf_edd;
+
+
+static void
+_e_mod_config_new(void)
+{
+   _e_mod_config = E_NEW(Gestures_Config, 1);
+
+   _e_mod_config->one_finger_flick_min_length = 100;
+   _e_mod_config->one_finger_flick_max_time = 400;
+   _e_mod_config->one_finger_hover_longpress_timeout = 0.81;
+   _e_mod_config->two_fingers_hover_longpress_timeout = 0.1;
+   _e_mod_config->one_finger_tap_timeout = 0.4;
+   _e_mod_config->one_finger_tap_radius = 100;
+}
+
+int _e_mod_atspi_config_init(void)
+{
+   DEBUG("Config init");
+   _conf_edd = E_CONFIG_DD_NEW("Gestures_Config", Gestures_Config);
+
+#define T Gestures_Config
+#define D _conf_edd
+   E_CONFIG_VAL(D, T, one_finger_flick_min_length, INT);
+   E_CONFIG_VAL(D, T, one_finger_flick_max_time, INT);
+   E_CONFIG_VAL(D, T, one_finger_hover_longpress_timeout, DOUBLE);
+   E_CONFIG_VAL(D, T, two_fingers_hover_longpress_timeout, DOUBLE);
+   E_CONFIG_VAL(D, T, one_finger_tap_timeout, DOUBLE);
+   E_CONFIG_VAL(D, T, one_finger_tap_radius, INT);
+
+   _e_mod_config = e_config_domain_load(E_ATSPI_CFG, _conf_edd);
+
+   if (!_e_mod_config)
+     {
+        _e_mod_config_new();
+        _e_mod_atspi_config_save();
+        INFO("New config file for e17-mod-tizen-screen-reader module created.");
+     }
+   else
+     INFO("Config file for e17-mod-tizen-screen-reader module loaded successfully.");
+
+   return 0;
+}
+
+int _e_mod_atspi_config_shutdown(void)
+{
+   DEBUG("Config shutdown");
+   E_FREE(_e_mod_config);
+   E_CONFIG_DD_FREE(_conf_edd);
+
+   return 0;
+}
+
+int _e_mod_atspi_config_save(void)
+{
+   return e_config_domain_save(E_ATSPI_CFG, _conf_edd, _e_mod_config);
+}
diff --git a/src/e_mod_config.h b/src/e_mod_config.h
new file mode 100644 (file)
index 0000000..7a52c66
--- /dev/null
@@ -0,0 +1,31 @@
+#ifndef _E_MOD_CONFIG_H__
+#define _E_MOD_CONFIG_H__
+
+#define E_ATSPI_CFG       "module.e17-mod-tizen-screen-reader"
+
+struct _Gestures_Config
+{
+   // minimal required length of flick gesture (in pixels)
+   int one_finger_flick_min_length;
+   // maximal time of gesture
+   int one_finger_flick_max_time;
+   // timeout period to activate hover gesture (first longpress timeout)
+   double one_finger_hover_longpress_timeout;
+   // tap timeout - maximal ammount of time allowed between seqiential taps
+   double two_fingers_hover_longpress_timeout;
+   // tap timeout - maximal ammount of time allowed between seqiential taps
+   double one_finger_tap_timeout;
+   // tap radius(in pixels)
+   int one_finger_tap_radius;
+};
+
+typedef struct _Gestures_Config Gestures_Config;
+
+int _e_mod_atspi_config_init(void);
+int _e_mod_atspi_config_shutdown(void);
+int _e_mod_atspi_config_save(void);
+
+/*< External config handle - valid after initalization */
+extern Gestures_Config *_e_mod_config;
+
+#endif
diff --git a/src/e_mod_gestures.c b/src/e_mod_gestures.c
new file mode 100644 (file)
index 0000000..275679b
--- /dev/null
@@ -0,0 +1,1192 @@
+#include "e.h"
+#include "e_mod_private.h"
+#include "e_mod_config.h"
+
+#define HISTORY_MAX 8
+#define LONGPRESS_TIMEOUT 0.4
+
+typedef enum {
+     FLICK_DIRECTION_UNDEFINED,
+     FLICK_DIRECTION_DOWN,
+     FLICK_DIRECTION_UP,
+     FLICK_DIRECTION_LEFT,
+     FLICK_DIRECTION_RIGHT,
+     FLICK_DIRECTION_DOWN_RETURN,
+     FLICK_DIRECTION_UP_RETURN,
+     FLICK_DIRECTION_LEFT_RETURN,
+     FLICK_DIRECTION_RIGHT_RETURN,
+} flick_direction_e;
+
+typedef enum {
+     GESTURE_NOT_STARTED = 0, // Gesture is ready to start
+     GESTURE_ONGOING,         // Gesture in progress.
+     GESTURE_FINISHED,        // Gesture finished - should be emited
+     GESTURE_ABORTED          // Gesture aborted
+} gesture_state_e;
+
+typedef enum {
+      ONE_FINGER_GESTURE = 1,
+      TWO_FINGERS_GESTURE,
+      THREE_FINGERS_GESTURE
+} gesture_type_e;
+
+struct _Cover
+{
+   E_Zone         *zone; /**< E_Zone on wich accessible layer is implemented */
+   Ecore_X_Window  win;  /**< Input window covering given zone */
+   unsigned int    n_taps; /**< Number of fingers touching screen */
+   unsigned int    event_time;
+
+   struct {
+        gesture_state_e state;     // current state of gesture
+        unsigned int timestamp[3]; // time of gesture;
+        int finger[3];             // finger number which initiates gesture
+        int x_org[3], y_org[3];    // coorinates of finger down event
+        int x_end[3], y_end[3];    // coorinates of finger up event
+        flick_direction_e dir;     // direction of flick
+        int n_fingers;             // number of fingers in gesture
+        int n_fingers_left;        // number of fingers in gesture
+                                   //         still touching screen
+        Eina_Bool finger_out[3];   // finger is out of the finger boundary
+        Eina_Bool return_flick[3];
+   } flick_gesture;
+
+   struct {
+        gesture_state_e state;   // currest gesture state
+        int x[2], y[2];
+        int n_fingers;
+        int finger[2];
+        unsigned int timestamp; // time of gesture;
+        unsigned int last_emission_time; // last time of gesture emission
+        Ecore_Timer *timer;
+        Eina_Bool longpressed;
+   } hover_gesture;
+
+   struct {
+        Eina_Bool started; // indicates if taps recognition process has started
+        Eina_Bool pressed; // indicates if finger is down
+        int n_taps;        // number of taps captures in sequence
+        int finger[3];        // device id of finget
+        Ecore_Timer *timer;  // sequence expiration timer
+        int x_org[3], y_org[3];    // coordinates of first tap
+        gesture_type_e tap_type;
+   } tap_gesture_data;
+};
+typedef struct _Cover Cover;
+
+int E_EVENT_ATSPI_GESTURE_DETECTED;
+
+static Eina_List *covers;
+static Eina_List *handlers;
+
+static void _covers_init(void);
+static void _covers_shutdown(void);
+static void _hover_event_emit(Cover *cov, int state);
+
+static void
+_gesture_info_free(void *data, void *info)
+{
+   free(data);
+}
+
+static void _event_emit(Gesture g, int x, int y, int x_e, int y_e, int state)
+{
+   Gesture_Info *info = calloc(sizeof(Gesture_Info), 1);
+   EINA_SAFETY_ON_NULL_RETURN(info);
+
+   info->type = g;
+   info->x_beg = x;
+   info->x_end = x_e;
+   info->y_beg = y;
+   info->y_end = y_e;
+   info->state = state;
+
+   ecore_event_add(E_EVENT_ATSPI_GESTURE_DETECTED, info, _gesture_info_free, NULL);
+}
+
+static void
+_flick_gesture_mouse_down(Ecore_Event_Mouse_Button *ev, Cover *cov)
+{
+   if (cov->flick_gesture.state == GESTURE_NOT_STARTED)
+     {
+        cov->flick_gesture.state = GESTURE_ONGOING;
+        cov->flick_gesture.finger[0] = ev->multi.device;
+        cov->flick_gesture.x_org[0] = ev->root.x;
+        cov->flick_gesture.y_org[0] = ev->root.y;
+        cov->flick_gesture.timestamp[0] = ev->timestamp;
+        cov->flick_gesture.n_fingers = 1;
+        cov->flick_gesture.n_fingers_left = 1;
+        cov->flick_gesture.dir = FLICK_DIRECTION_UNDEFINED;
+        cov->flick_gesture.finger_out[0] = EINA_FALSE;
+        cov->flick_gesture.return_flick[0] = EINA_FALSE;
+     }
+   else if (cov->flick_gesture.state == GESTURE_ONGOING)
+     {
+        // abort gesture if too many fingers touched screen
+        if ((cov->n_taps > 3) || (cov->flick_gesture.n_fingers > 2))
+          {
+             cov->flick_gesture.state = GESTURE_ABORTED;
+             return;
+          }
+
+        cov->flick_gesture.x_org[cov->flick_gesture.n_fingers] = ev->root.x;
+        cov->flick_gesture.y_org[cov->flick_gesture.n_fingers] = ev->root.y;
+        cov->flick_gesture.timestamp[cov->flick_gesture.n_fingers] = ev->timestamp;
+        cov->flick_gesture.finger[cov->flick_gesture.n_fingers] = ev->multi.device;
+        cov->flick_gesture.n_fingers++;
+        cov->flick_gesture.n_fingers_left++;
+         if (cov->flick_gesture.n_fingers < 3) /* n_fingers == 3 makes out of bounds write */
+           {
+              cov->flick_gesture.finger_out[cov->flick_gesture.n_fingers] = EINA_FALSE;
+              cov->flick_gesture.return_flick[cov->flick_gesture.n_fingers] = EINA_FALSE;
+           }
+     }
+}
+
+static Eina_Bool
+_flick_gesture_time_check(unsigned int event_time, unsigned int gesture_time)
+{
+   DEBUG("Flick time: %d", event_time - gesture_time);
+   if ((event_time - gesture_time) < _e_mod_config->one_finger_flick_max_time * 2) //Double time because of the possible of return flick
+     return EINA_TRUE;
+   else
+     return EINA_FALSE;
+}
+
+static Eina_Bool
+_flick_gesture_length_check(int x, int y, int x_org, int y_org)
+{
+   int dx = x - x_org;
+   int dy = y - y_org;
+
+   if ((dx * dx + dy * dy) > (_e_mod_config->one_finger_flick_min_length *
+                            _e_mod_config->one_finger_flick_min_length))
+     return EINA_TRUE;
+   else
+     return EINA_FALSE;
+}
+
+static flick_direction_e
+_flick_gesture_direction_get(int x, int y, int x_org, int y_org)
+{
+   int dx = x - x_org;
+   int dy = y - y_org;
+
+   if ((dy < 0) && (abs(dx) < -dy))
+     return FLICK_DIRECTION_UP;
+   if ((dy > 0) && (abs(dx) < dy))
+     return FLICK_DIRECTION_DOWN;
+   if ((dx > 0) && (dx > abs(dy)))
+     return FLICK_DIRECTION_RIGHT;
+   if ((dx < 0) && (-dx > abs(dy)))
+     return FLICK_DIRECTION_LEFT;
+
+   return FLICK_DIRECTION_UNDEFINED;
+}
+
+static void
+_flick_event_emit(Cover *cov)
+{
+   int ax, ay, axe, aye, i, type = -1;
+   ax = ay = axe = aye = 0;
+
+   for (i = 0; i < cov->flick_gesture.n_fingers; i++)
+     {
+        ax += cov->flick_gesture.x_org[i];
+        ay += cov->flick_gesture.y_org[i];
+        axe += cov->flick_gesture.x_end[i];
+        aye += cov->flick_gesture.y_end[i];
+     }
+
+   ax /= cov->flick_gesture.n_fingers;
+   ay /= cov->flick_gesture.n_fingers;
+   axe /= cov->flick_gesture.n_fingers;
+   aye /= cov->flick_gesture.n_fingers;
+
+   if (cov->flick_gesture.dir == FLICK_DIRECTION_LEFT)
+     {
+        if (cov->flick_gesture.n_fingers == 1)
+          type = ONE_FINGER_FLICK_LEFT;
+        if (cov->flick_gesture.n_fingers == 2)
+          type = TWO_FINGERS_FLICK_LEFT;
+        if (cov->flick_gesture.n_fingers == 3)
+          type = THREE_FINGERS_FLICK_LEFT;
+     }
+   else if (cov->flick_gesture.dir == FLICK_DIRECTION_RIGHT)
+     {
+        if (cov->flick_gesture.n_fingers == 1)
+          type = ONE_FINGER_FLICK_RIGHT;
+        if (cov->flick_gesture.n_fingers == 2)
+          type = TWO_FINGERS_FLICK_RIGHT;
+        if (cov->flick_gesture.n_fingers == 3)
+          type = THREE_FINGERS_FLICK_RIGHT;
+     }
+   else if (cov->flick_gesture.dir == FLICK_DIRECTION_UP)
+     {
+        if (cov->flick_gesture.n_fingers == 1)
+          type = ONE_FINGER_FLICK_UP;
+        if (cov->flick_gesture.n_fingers == 2)
+          type = TWO_FINGERS_FLICK_UP;
+        if (cov->flick_gesture.n_fingers == 3)
+          type = THREE_FINGERS_FLICK_UP;
+     }
+   else if (cov->flick_gesture.dir == FLICK_DIRECTION_DOWN)
+     {
+        if (cov->flick_gesture.n_fingers == 1)
+          type = ONE_FINGER_FLICK_DOWN;
+        if (cov->flick_gesture.n_fingers == 2)
+          type = TWO_FINGERS_FLICK_DOWN;
+        if (cov->flick_gesture.n_fingers == 3)
+          type = THREE_FINGERS_FLICK_DOWN;
+     }
+   else if (cov->flick_gesture.dir == FLICK_DIRECTION_DOWN_RETURN)
+     {
+        if (cov->flick_gesture.n_fingers == 1)
+          type = ONE_FINGER_FLICK_DOWN_RETURN;
+        if (cov->flick_gesture.n_fingers == 2)
+          type = TWO_FINGERS_FLICK_DOWN_RETURN;
+        if (cov->flick_gesture.n_fingers == 3)
+          type = THREE_FINGERS_FLICK_DOWN_RETURN;
+     }
+   else if (cov->flick_gesture.dir == FLICK_DIRECTION_UP_RETURN)
+     {
+        if (cov->flick_gesture.n_fingers == 1)
+          type = ONE_FINGER_FLICK_UP_RETURN;
+        if (cov->flick_gesture.n_fingers == 2)
+          type = TWO_FINGERS_FLICK_UP_RETURN;
+        if (cov->flick_gesture.n_fingers == 3)
+          type = THREE_FINGERS_FLICK_UP_RETURN;
+     }
+   else if (cov->flick_gesture.dir == FLICK_DIRECTION_LEFT_RETURN)
+     {
+        if (cov->flick_gesture.n_fingers == 1)
+          type = ONE_FINGER_FLICK_LEFT_RETURN;
+        if (cov->flick_gesture.n_fingers == 2)
+          type = TWO_FINGERS_FLICK_LEFT_RETURN;
+        if (cov->flick_gesture.n_fingers == 3)
+          type = THREE_FINGERS_FLICK_LEFT_RETURN;
+     }
+   else if (cov->flick_gesture.dir == FLICK_DIRECTION_RIGHT_RETURN)
+     {
+        if (cov->flick_gesture.n_fingers == 1)
+          type = ONE_FINGER_FLICK_RIGHT_RETURN;
+        if (cov->flick_gesture.n_fingers == 2)
+          type = TWO_FINGERS_FLICK_RIGHT_RETURN;
+        if (cov->flick_gesture.n_fingers == 3)
+          type = THREE_FINGERS_FLICK_RIGHT_RETURN;
+     }
+   _event_emit(type, ax, ay, axe, aye, 2);
+}
+
+static void
+_flick_gesture_mouse_up(Ecore_Event_Mouse_Button *ev, Cover *cov)
+{
+   if (cov->flick_gesture.state == GESTURE_ONGOING)
+     {
+        int i;
+        // check if fingers match
+        for (i = 0; i < cov->flick_gesture.n_fingers; i++)
+          {
+             if (cov->flick_gesture.finger[i] == ev->multi.device)
+               break;
+          }
+        if (i == cov->flick_gesture.n_fingers)
+          {
+             DEBUG("Finger id not recognized. Gesture aborted.");
+             cov->flick_gesture.state = GESTURE_ABORTED;
+             goto end;
+          }
+
+        // check if flick for given finger is valid
+        if (!_flick_gesture_time_check(ev->timestamp,
+                                       cov->flick_gesture.timestamp[i]))
+          {
+             DEBUG("finger flick gesture timeout expired. Gesture aborted.");
+             cov->flick_gesture.state = GESTURE_ABORTED;
+             goto end;
+          }
+
+        // check minimal flick length
+        if (!_flick_gesture_length_check(ev->root.x, ev->root.y,
+                                        cov->flick_gesture.x_org[i],
+                                        cov->flick_gesture.y_org[i]))
+          {
+             if (!cov->flick_gesture.finger_out[i])
+               {
+                  DEBUG("Minimal gesture length not reached and no return flick. Gesture aborted.");
+                  cov->flick_gesture.state = GESTURE_ABORTED;
+                  goto end;
+               }
+             cov->flick_gesture.return_flick[i] = EINA_TRUE;
+          }
+
+        flick_direction_e s = cov->flick_gesture.return_flick[i] ?
+                                       cov->flick_gesture.dir :
+                                       _flick_gesture_direction_get(ev->root.x, ev->root.y,
+                                                                     cov->flick_gesture.x_org[i],
+                                                                     cov->flick_gesture.y_org[i]);
+
+        cov->flick_gesture.n_fingers_left--;
+
+        if ((cov->flick_gesture.dir == FLICK_DIRECTION_UNDEFINED ||
+               cov->flick_gesture.dir > FLICK_DIRECTION_RIGHT)
+               && cov->flick_gesture.return_flick[i] == EINA_FALSE)
+         {
+            DEBUG("Flick gesture");
+            cov->flick_gesture.dir = s;
+         }
+
+        // gesture is valid only if all flicks are in same direction
+        if (cov->flick_gesture.dir != s)
+          {
+             DEBUG("Flick in different direction. Gesture aborted.");
+             cov->flick_gesture.state = GESTURE_ABORTED;
+             goto end;
+          }
+
+        cov->flick_gesture.x_end[i] = ev->root.x;
+        cov->flick_gesture.y_end[i] = ev->root.y;
+
+        if (!cov->flick_gesture.n_fingers_left)
+          {
+             _flick_event_emit(cov);
+             cov->flick_gesture.state = GESTURE_NOT_STARTED;
+          }
+     }
+
+end:
+   // if no finger is touching a screen, gesture will be reseted.
+   if ((cov->flick_gesture.state == GESTURE_ABORTED) && (cov->n_taps == 0))
+     {
+        DEBUG("Restet flick gesture");
+        cov->flick_gesture.state = GESTURE_NOT_STARTED;
+     }
+}
+
+static void
+_flick_gesture_mouse_move(Ecore_Event_Mouse_Move *ev, Cover *cov)
+{
+   if (cov->flick_gesture.state == GESTURE_ONGOING)
+      {
+         int i;
+         for(i = 0; i < cov->flick_gesture.n_fingers; ++i)
+            {
+               if (cov->flick_gesture.finger[i] == ev->multi.device)
+               break;
+            }
+         if (i == cov->flick_gesture.n_fingers)
+          {
+             if (cov->flick_gesture.n_fingers >= 3) //that is because of the EFL bug. Mouse move event before mouse down(!)
+               {
+                  ERROR("Finger id not recognized. Gesture aborted.");
+                  cov->flick_gesture.state = GESTURE_ABORTED;
+                  return;
+               }
+          }
+         if(!cov->flick_gesture.finger_out[i])
+            {
+               int dx = ev->root.x - cov->flick_gesture.x_org[i];
+               int dy = ev->root.y - cov->flick_gesture.y_org[i];
+
+               if (dx < 0) dx *= -1;
+              if (dy < 0) dy *= -1;
+
+              if (dx > _e_mod_config->one_finger_flick_min_length)
+                  {
+                     cov->flick_gesture.finger_out[i] = EINA_TRUE;
+                     if (ev->root.x > cov->flick_gesture.x_org[i])
+                        {
+                           if (cov->flick_gesture.dir == FLICK_DIRECTION_UNDEFINED ||
+                                 cov->flick_gesture.dir == FLICK_DIRECTION_RIGHT_RETURN)
+                              {
+                                 cov->flick_gesture.dir = FLICK_DIRECTION_RIGHT_RETURN;
+                              }
+                           else
+                              {
+                                 ERROR("Invalid direction, abort");
+                                 cov->flick_gesture.state = GESTURE_ABORTED;
+                              }
+                        }
+                     else
+                        {
+                           if (cov->flick_gesture.dir == FLICK_DIRECTION_UNDEFINED ||
+                                 cov->flick_gesture.dir == FLICK_DIRECTION_LEFT_RETURN)
+                              {
+                                 cov->flick_gesture.dir = FLICK_DIRECTION_LEFT_RETURN;
+                              }
+                           else
+                              {
+                                 ERROR("Invalid direction, abort");
+                                 cov->flick_gesture.state = GESTURE_ABORTED;
+                              }
+                        }
+                     return;
+                  }
+
+               else if (dy > _e_mod_config->one_finger_flick_min_length)
+                  {
+                     cov->flick_gesture.finger_out[i] = EINA_TRUE;
+                     if (ev->root.y > cov->flick_gesture.y_org[i])
+                        {
+                           if (cov->flick_gesture.dir == FLICK_DIRECTION_UNDEFINED ||
+                                 cov->flick_gesture.dir == FLICK_DIRECTION_DOWN_RETURN)
+                              {
+                                 cov->flick_gesture.dir = FLICK_DIRECTION_DOWN_RETURN;
+                              }
+                           else
+                              {
+                                 ERROR("Invalid direction, abort");
+                                 cov->flick_gesture.state = GESTURE_ABORTED;
+                              }
+                        }
+                     else
+                        {
+                           if (cov->flick_gesture.dir == FLICK_DIRECTION_UNDEFINED ||
+                                 cov->flick_gesture.dir == FLICK_DIRECTION_UP_RETURN)
+                              {
+                                 cov->flick_gesture.dir = FLICK_DIRECTION_UP_RETURN;
+                              }
+                           else
+                              {
+                                 ERROR("Invalid direction, abort");
+                                 cov->flick_gesture.state = GESTURE_ABORTED;
+                              }
+                        }
+                     return;
+                  }
+            }
+      }
+   return;
+}
+
+static Eina_Bool
+_on_hover_timeout(void *data)
+{
+   Cover *cov = data;
+   DEBUG("Hover timer expierd");
+
+   cov->hover_gesture.longpressed = EINA_TRUE;
+   cov->hover_gesture.timer = NULL;
+
+   if (cov->hover_gesture.last_emission_time == -1)
+     {
+        _hover_event_emit(cov, 0);
+        cov->hover_gesture.last_emission_time = cov->event_time;
+     }
+   return EINA_FALSE;
+}
+
+static void
+_hover_gesture_timer_reset(Cover *cov, double time)
+{
+   DEBUG("Hover timer reset");
+   cov->hover_gesture.longpressed = EINA_FALSE;
+   if (cov->hover_gesture.timer)
+     {
+        ecore_timer_reset(cov->hover_gesture.timer);
+        return;
+     }
+   cov->hover_gesture.timer = ecore_timer_add(time, _on_hover_timeout, cov);
+}
+
+static void
+_hover_gesture_mouse_down(Ecore_Event_Mouse_Button *ev, Cover *cov)
+{
+   if (cov->hover_gesture.state == GESTURE_NOT_STARTED &&
+       cov->n_taps == 1)
+     {
+        cov->hover_gesture.state = GESTURE_ONGOING;
+        cov->hover_gesture.timestamp = ev->timestamp;
+        cov->hover_gesture.last_emission_time = -1;
+        cov->hover_gesture.x[0] = ev->root.x;
+        cov->hover_gesture.y[0] = ev->root.y;
+        cov->hover_gesture.finger[0] = ev->multi.device;
+        cov->hover_gesture.n_fingers = 1;
+        _hover_gesture_timer_reset(cov, _e_mod_config->one_finger_hover_longpress_timeout);
+     }
+   if (cov->hover_gesture.state == GESTURE_ONGOING &&
+       cov->n_taps == 2)
+     {
+        if (cov->hover_gesture.longpressed)
+          {
+             _hover_event_emit(cov, 2);
+             goto abort;
+          }
+        cov->hover_gesture.timestamp = -1;
+        cov->hover_gesture.last_emission_time = -1;
+        cov->hover_gesture.x[1] = ev->root.x;
+        cov->hover_gesture.y[1] = ev->root.y;
+        cov->hover_gesture.finger[1] = ev->multi.device;
+        cov->hover_gesture.n_fingers = 2;
+        cov->hover_gesture.longpressed = EINA_TRUE;
+        if (cov->hover_gesture.timer)
+          ecore_timer_del(cov->hover_gesture.timer);
+        cov->hover_gesture.timer = NULL;
+        _hover_event_emit(cov, 0);
+     }
+   // abort gesture if more then 2 fingers touched screen
+   if ((cov->hover_gesture.state == GESTURE_ONGOING) &&
+       cov->n_taps > 2)
+     {
+        DEBUG("More then 2 finged. Abort hover gesture");
+        _hover_event_emit(cov, 2);
+        goto abort;
+     }
+   return;
+
+abort:
+   cov->hover_gesture.state = GESTURE_ABORTED;
+   if (cov->hover_gesture.timer)
+     ecore_timer_del(cov->hover_gesture.timer);
+   cov->hover_gesture.timer = NULL;
+}
+
+static void
+_hover_gesture_mouse_up(Ecore_Event_Mouse_Button *ev, Cover *cov)
+{
+   int i;
+   if (cov->hover_gesture.state == GESTURE_ONGOING)
+     {
+
+        for (i = 0; i < cov->hover_gesture.n_fingers; i++)
+          {
+             if (cov->hover_gesture.finger[i] == ev->multi.device)
+              break;
+          }
+        if (i == cov->hover_gesture.n_fingers)
+          {
+             DEBUG("Invalid finger id: %d", ev->multi.device);
+             return;
+          }
+        else
+          {
+             cov->hover_gesture.state = GESTURE_ABORTED;
+             if (cov->hover_gesture.timer)
+               ecore_timer_del(cov->hover_gesture.timer);
+             cov->hover_gesture.timer = NULL;
+             // aditionally emit event to complete sequence
+             if (cov->hover_gesture.longpressed)
+                _hover_event_emit(cov, 2);
+          }
+     }
+   // reset gesture only if user released all his fingers
+   if (cov->n_taps == 0)
+     cov->hover_gesture.state = GESTURE_NOT_STARTED;
+}
+
+static void
+_hover_event_emit(Cover *cov, int state)
+{
+   DEBUG("Emit hover event");
+   int ax = 0, ay = 0, j;
+   for (j = 0; j < cov->hover_gesture.n_fingers; j++)
+     {
+        ax += cov->hover_gesture.x[j];
+        ay += cov->hover_gesture.y[j];
+     }
+
+   ax /= cov->hover_gesture.n_fingers;
+   ay /= cov->hover_gesture.n_fingers;
+
+   switch (cov->hover_gesture.n_fingers)
+     {
+      case 1:
+         _event_emit(ONE_FINGER_HOVER, ax, ay, ax, ay, state);
+         break;
+      case 2:
+         _event_emit(TWO_FINGERS_HOVER, ax, ay, ax, ay, state);
+         break;
+      default:
+         break;
+     }
+}
+
+static void
+_hover_gesture_mouse_move(Ecore_Event_Mouse_Move *ev, Cover *cov)
+{
+   if (cov->hover_gesture.state == GESTURE_ONGOING)
+     {
+        // check fingers
+        int i;
+        if (!cov->hover_gesture.longpressed)
+          return;
+
+        for (i = 0; i < cov->hover_gesture.n_fingers; i++)
+          {
+             if (cov->hover_gesture.finger[i] == ev->multi.device)
+               break;
+          }
+        if (i == cov->hover_gesture.n_fingers)
+          {
+             DEBUG("Invalid finger id: %d", ev->multi.device);
+             return;
+          }
+          cov->hover_gesture.x[i] = ev->root.x;
+          cov->hover_gesture.y[i] = ev->root.y;
+          _hover_event_emit(cov, 1);
+      }
+}
+
+static void
+_tap_event_emit(Cover *cov)
+{
+   switch (cov->tap_gesture_data.n_taps)
+     {
+      case 1:
+         if(cov->tap_gesture_data.tap_type == ONE_FINGER_GESTURE)
+            {
+               DEBUG("ONE_FINGER_SINGLE_TAP");
+               _event_emit(ONE_FINGER_SINGLE_TAP,
+                     cov->tap_gesture_data.x_org[0], cov->tap_gesture_data.y_org[0],
+                     cov->tap_gesture_data.x_org[0], cov->tap_gesture_data.y_org[0],
+                     2);
+            }
+         else if(cov->tap_gesture_data.tap_type == TWO_FINGERS_GESTURE)
+            {
+               DEBUG("TWO_FINGERS_SINGLE_TAP");
+               _event_emit(TWO_FINGERS_SINGLE_TAP,
+                     cov->tap_gesture_data.x_org[0], cov->tap_gesture_data.y_org[0],
+                     cov->tap_gesture_data.x_org[1], cov->tap_gesture_data.y_org[1],
+                     2);
+            }
+         else if(cov->tap_gesture_data.tap_type == THREE_FINGERS_GESTURE)
+            {
+               DEBUG("THREE_FINGERS_SINGLE_TAP");
+               _event_emit(THREE_FINGERS_SINGLE_TAP,
+                     cov->tap_gesture_data.x_org[0], cov->tap_gesture_data.y_org[0],
+                     cov->tap_gesture_data.x_org[2], cov->tap_gesture_data.y_org[2],
+                     2);
+            }
+         else
+            {
+               ERROR("Unknown tap");
+            }
+         break;
+      case 2:
+         if(cov->tap_gesture_data.tap_type == ONE_FINGER_GESTURE)
+            {
+               DEBUG("ONE_FINGER_DOUBLE_TAP");
+               _event_emit(ONE_FINGER_DOUBLE_TAP,
+                     cov->tap_gesture_data.x_org[0], cov->tap_gesture_data.y_org[0],
+                     cov->tap_gesture_data.x_org[0], cov->tap_gesture_data.y_org[0],
+                     2);
+            }
+         else if(cov->tap_gesture_data.tap_type == TWO_FINGERS_GESTURE)
+            {
+               DEBUG("TWO_FINGERS_DOUBLE_TAP");
+               _event_emit(TWO_FINGERS_DOUBLE_TAP,
+                     cov->tap_gesture_data.x_org[0], cov->tap_gesture_data.y_org[0],
+                     cov->tap_gesture_data.x_org[1], cov->tap_gesture_data.y_org[1],
+                     2);
+            }
+         else if(cov->tap_gesture_data.tap_type == THREE_FINGERS_GESTURE)
+            {
+               DEBUG("THREE_FINGERS_DOUBLE_TAP");
+               _event_emit(THREE_FINGERS_DOUBLE_TAP,
+                     cov->tap_gesture_data.x_org[0], cov->tap_gesture_data.y_org[0],
+                     cov->tap_gesture_data.x_org[2], cov->tap_gesture_data.y_org[2],
+                     2);
+            }
+         else
+            {
+               ERROR("Unknown tap");
+            }
+         break;
+      case 3:
+         if(cov->tap_gesture_data.tap_type == ONE_FINGER_GESTURE)
+            {
+               DEBUG("ONE_FINGER_TRIPLE_TAP");
+               _event_emit(ONE_FINGER_TRIPLE_TAP,
+                     cov->tap_gesture_data.x_org[0], cov->tap_gesture_data.y_org[0],
+                     cov->tap_gesture_data.x_org[0], cov->tap_gesture_data.y_org[0],
+                     2);
+            }
+         else if(cov->tap_gesture_data.tap_type == TWO_FINGERS_GESTURE)
+            {
+               DEBUG("TWO_FINGERS_TRIPLE_TAP");
+               _event_emit(TWO_FINGERS_TRIPLE_TAP,
+                     cov->tap_gesture_data.x_org[0], cov->tap_gesture_data.y_org[0],
+                     cov->tap_gesture_data.x_org[1], cov->tap_gesture_data.y_org[1],
+                     2);
+            }
+         else if(cov->tap_gesture_data.tap_type == THREE_FINGERS_GESTURE)
+            {
+               DEBUG("THREE_FINGERS_TRIPLE_TAP");
+               _event_emit(THREE_FINGERS_TRIPLE_TAP,
+                     cov->tap_gesture_data.x_org[0], cov->tap_gesture_data.y_org[0],
+                     cov->tap_gesture_data.x_org[2], cov->tap_gesture_data.y_org[2],
+                     2);
+            }
+         else
+            {
+               ERROR("Unknown tap");
+            }
+         break;
+      default:
+         ERROR("Unknown tap");
+         break;
+     }
+}
+
+static Eina_Bool
+_on_tap_timer_expire(void *data)
+{
+   Cover *cov = data;
+   DEBUG("Timer expired");
+
+   if (cov->tap_gesture_data.started && !cov->tap_gesture_data.pressed)
+     _tap_event_emit(cov);
+
+   // finish gesture
+   cov->tap_gesture_data.started = EINA_FALSE;
+   cov->tap_gesture_data.timer = NULL;
+   cov->tap_gesture_data.tap_type = ONE_FINGER_GESTURE;
+   cov->tap_gesture_data.finger[0] = -1;
+   cov->tap_gesture_data.finger[1] = -1;
+   cov->tap_gesture_data.finger[2] = -1;
+
+   return EINA_FALSE;
+}
+
+static int _tap_gesture_finger_check(Cover *cov, int x, int y)
+{
+   int dx = x - cov->tap_gesture_data.x_org[0];
+   int dy = y - cov->tap_gesture_data.y_org[0];
+
+   if (cov->tap_gesture_data.finger[0] != -1 &&
+         (dx * dx + dy * dy < _e_mod_config->one_finger_tap_radius *
+         _e_mod_config->one_finger_tap_radius))
+      {
+         return 0;
+      }
+
+   dx = x - cov->tap_gesture_data.x_org[1];
+   dy = y - cov->tap_gesture_data.y_org[1];
+   if (cov->tap_gesture_data.finger[1] != -1 &&
+            (dx * dx + dy * dy < _e_mod_config->one_finger_tap_radius *
+            _e_mod_config->one_finger_tap_radius))
+      {
+         return 1;
+      }
+
+   dx = x - cov->tap_gesture_data.x_org[2];
+   dy = y - cov->tap_gesture_data.y_org[2];
+   if (cov->tap_gesture_data.finger[2] != -1 &&
+            (dx * dx + dy * dy < _e_mod_config->one_finger_tap_radius *
+            _e_mod_config->one_finger_tap_radius))
+      {
+         return 2;
+      }
+
+   return -1;
+}
+
+static void
+_tap_gestures_mouse_down(Ecore_Event_Mouse_Button *ev, Cover *cov)
+{
+   if (cov->n_taps > 4)
+      {
+         ERROR("Too many fingers");
+         return;
+      }
+
+   cov->tap_gesture_data.pressed = EINA_TRUE;
+
+   if (cov->tap_gesture_data.started == EINA_FALSE)
+      {
+         DEBUG("First finger down");
+         cov->tap_gesture_data.started = EINA_TRUE;
+         cov->tap_gesture_data.finger[0] = ev->multi.device;
+         cov->tap_gesture_data.x_org[0] = ev->root.x;
+         cov->tap_gesture_data.y_org[0] = ev->root.y;
+         cov->tap_gesture_data.finger[1] = -1;
+         cov->tap_gesture_data.finger[2] = -1;
+         cov->tap_gesture_data.n_taps = 0;
+         cov->tap_gesture_data.timer = ecore_timer_add(
+                                           _e_mod_config->one_finger_tap_timeout,
+                                           _on_tap_timer_expire, cov);
+         cov->tap_gesture_data.tap_type = ONE_FINGER_GESTURE;
+      }
+
+   else
+      {
+         int finger = _tap_gesture_finger_check(cov, ev->root.x, ev->root.y);
+
+         if (ev->multi.device == cov->tap_gesture_data.finger[0])
+            {
+               DEBUG("First finger down");
+
+               if (_tap_gesture_finger_check(cov, ev->root.x, ev->root.y) == -1)
+                  {
+                     ERROR("Abort gesture");
+                     cov->tap_gesture_data.started = EINA_FALSE;
+                     ecore_timer_del(cov->tap_gesture_data.timer);
+                     cov->tap_gesture_data.timer = NULL;
+                     cov->tap_gesture_data.tap_type = ONE_FINGER_GESTURE;
+                     cov->tap_gesture_data.finger[0] = -1;
+                     cov->tap_gesture_data.finger[1] = -1;
+                     cov->tap_gesture_data.finger[2] = -1;
+                     _tap_gestures_mouse_down(ev, cov);
+                     return;
+                  }
+
+               int dx = ev->root.x - cov->tap_gesture_data.x_org[0];
+               int dy = ev->root.y - cov->tap_gesture_data.y_org[0];
+
+               cov->tap_gesture_data.x_org[0] = ev->root.x;
+               cov->tap_gesture_data.y_org[0] = ev->root.y;
+            }
+         else if (cov->tap_gesture_data.finger[1] == -1 ||
+                  cov->tap_gesture_data.finger[1] == ev->multi.device)
+            {
+               DEBUG("Second finger down");
+               cov->tap_gesture_data.finger[1] = ev->multi.device;
+
+               cov->tap_gesture_data.x_org[1] = ev->root.x;
+               cov->tap_gesture_data.y_org[1] = ev->root.y;
+               if (cov->tap_gesture_data.tap_type < TWO_FINGERS_GESTURE)
+                  cov->tap_gesture_data.tap_type = TWO_FINGERS_GESTURE;
+            }
+         else if (cov->tap_gesture_data.finger[2] == -1 ||
+                  cov->tap_gesture_data.finger[2] == ev->multi.device)
+            {
+               DEBUG("Third finger down");
+               cov->tap_gesture_data.finger[2] = ev->multi.device;
+
+               cov->tap_gesture_data.x_org[2] = ev->root.x;
+               cov->tap_gesture_data.y_org[2] = ev->root.y;
+               if (cov->tap_gesture_data.tap_type < THREE_FINGERS_GESTURE)
+                  cov->tap_gesture_data.tap_type = THREE_FINGERS_GESTURE;
+            }
+         else
+            {
+               ERROR("Unknown finger down");
+            }
+         ecore_timer_reset(cov->tap_gesture_data.timer);
+      }
+}
+
+static void
+_tap_gestures_mouse_up(Ecore_Event_Mouse_Button *ev, Cover *cov)
+{
+   if (cov->tap_gesture_data.timer)
+      {
+         cov->tap_gesture_data.pressed = EINA_FALSE;
+
+         if (ev->multi.device == cov->tap_gesture_data.finger[0])
+            {
+               DEBUG("First finger up");
+
+               int dx = ev->root.x - cov->tap_gesture_data.x_org[0];
+               int dy = ev->root.y - cov->tap_gesture_data.y_org[0];
+
+               if((dx * dx + dy * dy) < _e_mod_config->one_finger_tap_radius *
+                     _e_mod_config->one_finger_tap_radius)
+                  {
+                     if (cov->n_taps == 0)
+                        {
+                           cov->tap_gesture_data.n_taps++;
+                        }
+                  }
+               else
+                  {
+                     ERROR("Abort gesture");
+                     cov->tap_gesture_data.started = EINA_FALSE;
+                  }
+            }
+         else if (ev->multi.device == cov->tap_gesture_data.finger[1])
+            {
+               DEBUG("Second finger up");
+
+               int dx = ev->root.x - cov->tap_gesture_data.x_org[1];
+               int dy = ev->root.y - cov->tap_gesture_data.y_org[1];
+
+               if((dx * dx + dy * dy) < _e_mod_config->one_finger_tap_radius *
+                     _e_mod_config->one_finger_tap_radius)
+                  {
+                     if (cov->n_taps == 0)
+                        {
+                           cov->tap_gesture_data.n_taps++;
+                        }
+                  }
+               else
+                  {
+                     ERROR("Abort gesture");
+                     cov->tap_gesture_data.started = EINA_FALSE;
+                  }
+            }
+         else if (ev->multi.device == cov->tap_gesture_data.finger[2])
+            {
+               DEBUG("Third finger up");
+
+               int dx = ev->root.x - cov->tap_gesture_data.x_org[2];
+               int dy = ev->root.y - cov->tap_gesture_data.y_org[2];
+
+               if((dx * dx + dy * dy) < _e_mod_config->one_finger_tap_radius *
+                     _e_mod_config->one_finger_tap_radius)
+                  {
+                     if (cov->n_taps == 0)
+                        {
+                           cov->tap_gesture_data.n_taps++;
+                        }
+                  }
+               else
+                  {
+                     ERROR("Abort gesture");
+                     cov->tap_gesture_data.started = EINA_FALSE;
+                  }
+            }
+         else
+            {
+               ERROR("Unknown finger up, abort gesture");
+               cov->tap_gesture_data.started = EINA_FALSE;
+            }
+      }
+}
+
+static void
+_tap_gestures_move(Ecore_Event_Mouse_Move *ev, Cover *cov)
+{
+   if(_tap_gesture_finger_check(cov, ev->root.x, ev->root.y) == -1)
+   {
+       ERROR("Abort gesture");
+       cov->tap_gesture_data.started = EINA_FALSE;
+       ecore_timer_del(cov->tap_gesture_data.timer);
+       cov->tap_gesture_data.timer = NULL;
+       cov->tap_gesture_data.tap_type = ONE_FINGER_GESTURE;
+       cov->tap_gesture_data.finger[0] = -1;
+       cov->tap_gesture_data.finger[1] = -1;
+       cov->tap_gesture_data.finger[2] = -1;
+       return;
+   }
+}
+
+static Eina_Bool
+_cb_mouse_down(void    *data EINA_UNUSED,
+               int      type EINA_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)
+          {
+             cov->n_taps++;
+             cov->event_time = ev->timestamp;
+
+             DEBUG("mouse down: multi.device: %d, taps: %d", ev->multi.device, cov->n_taps);
+
+             _flick_gesture_mouse_down(ev, cov);
+             _hover_gesture_mouse_down(ev, cov);
+             _tap_gestures_mouse_down(ev, cov);
+
+             return ECORE_CALLBACK_PASS_ON;
+          }
+     }
+
+   return ECORE_CALLBACK_PASS_ON;
+}
+
+static Eina_Bool
+_cb_mouse_up(void    *data EINA_UNUSED,
+             int      type EINA_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)
+          {
+             cov->n_taps--;
+             cov->event_time = ev->timestamp;
+
+             DEBUG("mouse up, multi.device: %d, taps: %d", ev->multi.device, cov->n_taps);
+
+             _flick_gesture_mouse_up(ev, cov);
+             _hover_gesture_mouse_up(ev, cov);
+             _tap_gestures_mouse_up(ev, cov);
+
+             return ECORE_CALLBACK_PASS_ON;
+          }
+     }
+   return ECORE_CALLBACK_PASS_ON;
+}
+
+static Eina_Bool
+_cb_mouse_move(void    *data EINA_UNUSED,
+               int      type EINA_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)
+          {
+             cov->event_time = ev->timestamp;
+
+             _flick_gesture_mouse_move(ev, cov);
+             _hover_gesture_mouse_move(ev, cov);
+             _tap_gestures_move(ev, cov);
+             return ECORE_CALLBACK_PASS_ON;
+          }
+     }
+   return ECORE_CALLBACK_PASS_ON;
+}
+
+static Eina_Bool
+_cb_zone_add(void    *data EINA_UNUSED,
+             int      type EINA_UNUSED,
+             void    *event EINA_UNUSED)
+{
+   _covers_shutdown();
+   _covers_init();
+   return ECORE_CALLBACK_PASS_ON;
+}
+
+static Eina_Bool
+_cb_zone_del(void    *data EINA_UNUSED,
+             int      type EINA_UNUSED,
+             void    *event EINA_UNUSED)
+{
+   _covers_shutdown();
+   _covers_init();
+   return ECORE_CALLBACK_PASS_ON;
+}
+
+static Eina_Bool
+_cb_zone_move_resize(void    *data EINA_UNUSED,
+                     int      type EINA_UNUSED,
+                     void    *event EINA_UNUSED)
+{
+   _covers_shutdown();
+   _covers_init();
+   return ECORE_CALLBACK_PASS_ON;
+}
+
+
+static void
+_events_init(void)
+{
+#define HANDLER_APPEND(event, cb) \
+   handlers = eina_list_append( \
+      handlers, ecore_event_handler_add(event, cb, NULL));
+   HANDLER_APPEND(ECORE_EVENT_MOUSE_BUTTON_DOWN, _cb_mouse_down);
+   HANDLER_APPEND(ECORE_EVENT_MOUSE_BUTTON_UP, _cb_mouse_up);
+   HANDLER_APPEND(ECORE_EVENT_MOUSE_MOVE, _cb_mouse_move);
+   HANDLER_APPEND(E_EVENT_ZONE_ADD, _cb_zone_add);
+   HANDLER_APPEND(E_EVENT_ZONE_DEL, _cb_zone_del);
+   HANDLER_APPEND(E_EVENT_ZONE_MOVE_RESIZE, _cb_zone_move_resize);
+#undef APPEND_HANDLER
+
+   if (!E_EVENT_ATSPI_GESTURE_DETECTED)
+      E_EVENT_ATSPI_GESTURE_DETECTED = ecore_event_type_new();
+}
+
+static void
+_events_shutdown(void)
+{
+   E_FREE_LIST(handlers, ecore_event_handler_del);
+}
+
+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_input_multi_select(cov->win);
+
+   ecore_x_icccm_title_set(cov->win, "atspi-service-input");
+   ecore_x_netwm_name_set(cov->win, "atspi-service-input");
+
+   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);
+   ecore_x_window_raise(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);
+               }
+          }
+     }
+   DEBUG("Created %d covers.", eina_list_count(covers));
+}
+
+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->tap_gesture_data.timer)
+          ecore_timer_del(cov->tap_gesture_data.timer);
+        if (cov->hover_gesture.timer)
+          ecore_timer_del(cov->hover_gesture.timer);
+        free(cov);
+     }
+}
+
+int _e_mod_atspi_gestures_init(void)
+{
+   DEBUG("gesture init");
+   ecore_x_event_mask_set(ecore_x_window_root_first_get(),
+                          ECORE_X_EVENT_MASK_WINDOW_CONFIGURE);
+   ecore_x_event_mask_set(ecore_x_window_root_first_get(),
+                          ECORE_X_EVENT_MASK_WINDOW_PROPERTY);
+
+   _covers_init();
+   _events_init();
+
+   return 0;
+}
+
+int _e_mod_atspi_gestures_shutdown(void)
+{
+   DEBUG("gesture shutdown");
+
+   _covers_shutdown();
+   _events_shutdown();
+
+   return 0;
+}
diff --git a/src/e_mod_main.c b/src/e_mod_main.c
new file mode 100644 (file)
index 0000000..c7f5a9c
--- /dev/null
@@ -0,0 +1,628 @@
+#include "e.h"
+#include "e_mod_main.h"
+#include "e_mod_private.h"
+#include "e_mod_config.h"
+
+#include <vconf.h>
+
+#define E_A11Y_SERVICE_BUS_NAME "com.samsung.EModule"
+#define E_A11Y_SERVICE_NAVI_IFC_NAME "com.samsung.GestureNavigation"
+#define E_A11Y_SERVICE_NAVI_OBJ_PATH "/com/samsung/GestureNavigation"
+#define E_A11Y_SERVICE_TRACKER_IFC_NAME "com.samsung.WindowTracker"
+#define E_A11Y_SERVICE_TRACKER_OBJ_PATH "/com/samsung/WindowTracker"
+
+#define VCONF_ATSPI_KEY "db/setting/accessibility/atspi"
+#define E_ATSPI_BUS_TIMEOUT 4000
+
+int _eina_log_dom;
+
+static int g_enabled;
+static int g_gesture_navi;
+static Eina_List *handlers;
+static const char *_a11y_bus_address;
+static E_DBus_Connection *_a11y_conn;
+static E_DBus_Object *_dbus_obj;
+static E_DBus_Object *_wt_dbus_obj;
+static DBusPendingCall *_bus_request;
+
+/* module setup */
+EAPI E_Module_Api e_modapi =
+{
+   E_MODULE_API_VERSION,
+   "E17 ATSPI Service"
+};
+
+int _a11y_bus_register(void);
+static const char *_gesture_enum_to_string(Gesture g);
+static void _events_shutdown();
+static void _events_init();
+
+static void _on_get_a11y_address(void *data, DBusMessage *msg, DBusError *err)
+{
+   const char *address = NULL;
+
+   _bus_request = NULL;
+
+   if (dbus_error_is_set(err))
+     {
+        ERROR("Dbus error occured: %s", err->message);
+     }
+   else if (dbus_message_get_type(msg) != DBUS_MESSAGE_TYPE_ERROR)
+     {
+        DBusError err2;
+        dbus_error_init(&err2);
+        if (dbus_message_get_args(msg, &err2, DBUS_TYPE_STRING, &address, DBUS_TYPE_INVALID))
+          {
+             eina_stringshare_replace(&_a11y_bus_address, address);
+             DEBUG("AT-SPI bus address: %s", address);
+             _a11y_bus_register();
+          }
+     }
+   else
+     ERROR("GetAddress method call failed: %s", dbus_message_get_error_name(msg));
+}
+
+/**
+ * @brief Get accessibility bus address
+ */
+static int
+_fetch_a11y_bus_address(void)
+{
+   E_DBus_Connection *conn = NULL;
+   DBusMessage *msg = NULL;
+
+   if (_bus_request)
+     return 0;
+
+   conn = e_dbus_bus_get(DBUS_BUS_SESSION);
+   if (!conn)
+     {
+        ERROR("unable to get system bus");
+        goto fail;
+     }
+
+   msg = dbus_message_new_method_call("org.a11y.Bus", "/org/a11y/bus",
+                                      "org.a11y.Bus", "GetAddress");
+   if (!msg)
+     {
+        ERROR("DBus message allocation failed");
+        goto fail;
+     }
+
+   _bus_request = e_dbus_message_send(conn, msg, _on_get_a11y_address,
+                                      E_ATSPI_BUS_TIMEOUT, NULL);
+   dbus_message_unref(msg);
+
+   return 0;
+fail:
+   if (msg) dbus_message_unref(msg);
+   return -1;
+}
+
+static DBusMessage *_on_get_active_window(E_DBus_Object *obj, DBusMessage *msg)
+{
+   DBusMessage *reply;
+
+   Ecore_X_Window win = _e_mod_atspi_window_tracker_top_window_get();
+   pid_t pid = _e_mod_atspi_window_tracker_top_window_pid_get();
+
+   if (pid == -1)
+     {
+        ERROR("Invalid PID");
+        return dbus_message_new_error(msg, "org.freedesktop.", "Invalid");
+     }
+
+   reply = dbus_message_new_method_return(msg);
+   if (!reply)
+     {
+        ERROR("Unable to create return message.");
+        return NULL;
+     }
+
+   if (!dbus_message_append_args(reply, DBUS_TYPE_INT32, &pid, DBUS_TYPE_INT32, &win,
+                                 DBUS_TYPE_INVALID))
+     {
+        ERROR("Appending replay args faild.");
+        dbus_message_unref(reply);
+        return NULL;
+     }
+
+   INFO("GetActiveWindow method called");
+   return reply;
+}
+
+static DBusMessage *_on_get_supported_gestures(E_DBus_Object *obj, DBusMessage *msg)
+{
+   DBusMessage *reply;
+   DBusMessageIter iter, iter2;
+   Gesture g;
+
+   reply = dbus_message_new_method_return(msg);
+   if (!reply) return NULL;
+
+   if (!dbus_message_iter_init(msg, &iter))
+     goto fail;
+
+   if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &iter2))
+     goto fail;
+
+   for (g = ONE_FINGER_FLICK_LEFT; g < GESTURES_COUNT; g++)
+     {
+        if (!dbus_message_iter_append_basic(&iter2, DBUS_TYPE_STRING, _gesture_enum_to_string(g)))
+          goto fail;
+     }
+
+   if (!dbus_message_iter_close_container(&iter, &iter2))
+     goto fail;
+
+   DEBUG("Get supported gestures method called");
+   return reply;
+
+fail:
+   dbus_message_unref(reply);
+   return NULL;
+}
+
+static void _propety_get(E_DBus_Object *obj, const char *property, int *type, void **value)
+{
+   DEBUG("Get property request");
+   if (property && !strcmp(property, "AccessibilityGestureNavigation"))
+     {
+        if (type) *type = DBUS_TYPE_BOOLEAN;
+        if (value) *value = &g_gesture_navi;
+     }
+   else
+     if (type) *type = DBUS_TYPE_INVALID;
+}
+
+static int _propety_set(E_DBus_Object *obj, const char *property, int type, void *value)
+{
+   DEBUG("Set property request");
+   if (property && !strcmp(property, "AccessibilityGestureNavigation"))
+     {
+        if (value && !g_gesture_navi)
+          {
+             _e_mod_atspi_gestures_init();
+             g_gesture_navi = EINA_TRUE;
+          }
+        else if (g_gesture_navi)
+          {
+             _e_mod_atspi_gestures_shutdown();
+             g_gesture_navi = EINA_TRUE;
+          }
+        return 0;
+     }
+   return -1;
+}
+
+static void
+_on_name_cb(void *data, DBusMessage *msg, DBusError *err)
+{
+   DEBUG("On_name_cb");
+}
+
+int _a11y_bus_register(void)
+{
+   DBusConnection *conn;
+   E_DBus_Interface *ifc, *wt_ifc;
+   DBusError err;
+
+   if (_a11y_conn) return 0;
+   conn = dbus_connection_open_private(_a11y_bus_address, NULL);
+   if (!conn)
+     {
+        ERROR("Unable to connect with %s", _a11y_bus_address);
+        return -1;
+     }
+
+   dbus_error_init(&err);
+   if (dbus_bus_register(conn, &err) != TRUE)
+     {
+        ERROR("Registering on AT-SPI bus failed.");
+        dbus_connection_close(conn);
+        dbus_connection_unref(conn);
+        return -1;
+     }
+
+   _a11y_conn = e_dbus_connection_setup(conn);
+   if (!_a11y_conn)
+     {
+        ERROR("Unable to integrate with ecore_main_loop");
+        dbus_connection_close(conn);
+        dbus_connection_unref(conn);
+        return -1;
+     }
+
+   e_dbus_request_name(_a11y_conn, E_A11Y_SERVICE_BUS_NAME,
+                       DBUS_NAME_FLAG_DO_NOT_QUEUE, _on_name_cb, NULL);
+   ifc = e_dbus_interface_new(E_A11Y_SERVICE_NAVI_IFC_NAME);
+   wt_ifc = e_dbus_interface_new(E_A11Y_SERVICE_TRACKER_IFC_NAME);
+
+   _dbus_obj = e_dbus_object_add(_a11y_conn, E_A11Y_SERVICE_NAVI_OBJ_PATH, NULL);
+   _wt_dbus_obj = e_dbus_object_add(_a11y_conn, E_A11Y_SERVICE_TRACKER_OBJ_PATH, NULL);
+
+   e_dbus_interface_method_add(ifc, "GetSupportedGestures", NULL, "as", _on_get_supported_gestures);
+   e_dbus_interface_signal_add(ifc, "GestureDetected", "siii");
+
+   e_dbus_interface_method_add(wt_ifc, "GetActiveWindow", NULL, "ii", _on_get_active_window);
+   e_dbus_interface_signal_add(wt_ifc, "ActiveWindowChanged", "ii");
+
+   e_dbus_object_interface_attach(_dbus_obj, ifc);
+   e_dbus_object_interface_attach(_wt_dbus_obj, wt_ifc);
+
+   e_dbus_object_property_get_cb_set(_dbus_obj, _propety_get);
+   e_dbus_object_property_set_cb_set(_dbus_obj, _propety_set);
+
+   DEBUG("AT-SPI dbus service initialized.");
+   return 0;
+}
+
+int _a11y_bus_unregister(void)
+{
+   if (!_a11y_conn) return 0;
+
+   e_dbus_release_name(_a11y_conn, E_A11Y_SERVICE_BUS_NAME, NULL, NULL);
+
+   if (_dbus_obj) e_dbus_object_free(_dbus_obj);
+   _dbus_obj = NULL;
+   if (_wt_dbus_obj) e_dbus_object_free(_wt_dbus_obj);
+   _wt_dbus_obj = NULL;
+
+   e_dbus_connection_close(_a11y_conn);
+   _a11y_conn = NULL;
+
+   return 0;
+}
+
+int _e_mod_atspi_dbus_init(void)
+{
+   DEBUG("dbus init");
+
+   e_dbus_init();
+
+   return _fetch_a11y_bus_address();
+}
+
+int _e_mod_atspi_dbus_shutdown(void)
+{
+   DEBUG("dbus shutdown");
+   if (_a11y_bus_address)
+     eina_stringshare_del(_a11y_bus_address);
+   _a11y_bus_address = NULL;
+
+   if (_bus_request)
+     dbus_pending_call_cancel(_bus_request);
+   _bus_request = NULL;
+
+   _a11y_bus_unregister();
+
+   e_dbus_shutdown();
+
+   return 0;
+}
+
+static const char *_gesture_enum_to_string(Gesture g)
+{
+   switch(g)
+     {
+      case ONE_FINGER_HOVER:
+         return "OneFingerHover";
+      case TWO_FINGERS_HOVER:
+         return "TwoFingersHover";
+      case THREE_FINGERS_HOVER:
+         return "ThreeFingersHover";
+      case ONE_FINGER_FLICK_LEFT:
+         return "OneFingerFlickLeft";
+      case ONE_FINGER_FLICK_RIGHT:
+         return "OneFingerFlickRight";
+      case ONE_FINGER_FLICK_UP:
+         return "OneFingerFlickUp";
+      case ONE_FINGER_FLICK_DOWN:
+         return "OneFingerFlickDown";
+      case TWO_FINGERS_FLICK_UP:
+         return "TwoFingersFlickUp";
+      case TWO_FINGERS_FLICK_DOWN:
+         return "TwoFingersFlickDown";
+      case TWO_FINGERS_FLICK_LEFT:
+         return "TwoFingersFlickLeft";
+      case TWO_FINGERS_FLICK_RIGHT:
+         return "TwoFingersFlickRight";
+      case THREE_FINGERS_FLICK_LEFT:
+         return "ThreeFingersFlickLeft";
+      case THREE_FINGERS_FLICK_RIGHT:
+         return "ThreeFingersFlickRight";
+      case THREE_FINGERS_FLICK_UP:
+         return "ThreeFingersFlickUp";
+      case THREE_FINGERS_FLICK_DOWN:
+         return "ThreeFingersFlickDown";
+      case ONE_FINGER_SINGLE_TAP:
+         return "OneFingerSingleTap";
+      case ONE_FINGER_DOUBLE_TAP:
+         return "OneFingerDoubleTap";
+      case ONE_FINGER_TRIPLE_TAP:
+         return "OneFingerTripleTap";
+      case TWO_FINGERS_SINGLE_TAP:
+         return "TwoFingersSingleTap";
+      case TWO_FINGERS_DOUBLE_TAP:
+         return "TwoFingersDoubleTap";
+      case TWO_FINGERS_TRIPLE_TAP:
+         return "TwoFingersTripleTap";
+      case THREE_FINGERS_SINGLE_TAP:
+         return "ThreeFingersSingleTap";
+      case THREE_FINGERS_DOUBLE_TAP:
+         return "ThreeFingersDoubleTap";
+      case THREE_FINGERS_TRIPLE_TAP:
+         return "ThreeFingersTripleTap";
+      case ONE_FINGER_FLICK_LEFT_RETURN:
+         return "OneFingerFlickLeftReturn";
+      case ONE_FINGER_FLICK_RIGHT_RETURN:
+         return "OneFingerFlickRightReturn";
+      case ONE_FINGER_FLICK_UP_RETURN:
+         return "OneFingerFlickUpReturn";
+      case ONE_FINGER_FLICK_DOWN_RETURN:
+         return "OneFingerFlickDownReturn";
+      case TWO_FINGERS_FLICK_LEFT_RETURN:
+         return "TwoFingersFlickLeftReturn";
+      case TWO_FINGERS_FLICK_RIGHT_RETURN:
+         return "TwoFingersFlickRightReturn";
+      case TWO_FINGERS_FLICK_UP_RETURN:
+         return "TwoFingersFlickUpReturn";
+      case TWO_FINGERS_FLICK_DOWN_RETURN:
+         return "TwoFingersFlickDownReturn";
+      case THREE_FINGERS_FLICK_LEFT_RETURN:
+         return "ThreeFingersFlickLeftReturn";
+      case THREE_FINGERS_FLICK_RIGHT_RETURN:
+         return "ThreeFingersFlickRightReturn";
+      case THREE_FINGERS_FLICK_UP_RETURN:
+         return "ThreeFingersFlickUpReturn";
+      case THREE_FINGERS_FLICK_DOWN_RETURN:
+         return "ThreeFingersFlickDownReturn";
+      default:
+         ERROR("[atspi] dbus: unhandled gesture enum");
+         return NULL;
+     }
+}
+
+int _e_mod_atpis_dbus_windown_changed_broadcast(pid_t pid, int id)
+{
+   DBusMessage *sig;
+   if (!_a11y_conn) return -1;
+
+   sig = dbus_message_new_signal(E_A11Y_SERVICE_TRACKER_OBJ_PATH,
+                                 E_A11Y_SERVICE_TRACKER_IFC_NAME, "ActiveWindowChanged");
+   if (!sig) return -1;
+
+   if (!dbus_message_append_args(sig, DBUS_TYPE_INT32, &pid, DBUS_TYPE_INT32, &id, DBUS_TYPE_INVALID))
+     {
+        dbus_message_unref(sig);
+        return -1;
+     }
+   if (!e_dbus_message_send(_a11y_conn, sig, NULL, 0, NULL))
+     {
+        ERROR("Sending ActiveWindowChanged signal failed!");
+        dbus_message_unref(sig);
+        return -1;
+     }
+   INFO("ActiveWindowChanged Dbus signal send");
+   dbus_message_unref(sig);
+   return 0;
+}
+
+int _e_mod_atspi_dbus_broadcast(Gesture_Info *gi)
+{
+   const char *name;
+   DBusMessage *sig;
+
+   if (!_a11y_conn) return -1;
+
+   name = _gesture_enum_to_string(gi->type);
+   if (!name) return -1;
+
+   sig = dbus_message_new_signal(E_A11Y_SERVICE_NAVI_OBJ_PATH,
+                                 E_A11Y_SERVICE_NAVI_IFC_NAME, "GestureDetected");
+   if (!sig) return -1;
+
+   if (!dbus_message_append_args(sig, DBUS_TYPE_STRING, &name,
+                                 DBUS_TYPE_INT32, &gi->x_beg, DBUS_TYPE_INT32, &gi->y_beg,
+                                 DBUS_TYPE_INT32, &gi->x_end, DBUS_TYPE_INT32, &gi->y_end,
+                                 DBUS_TYPE_UINT32, &gi->state,
+                                 DBUS_TYPE_INVALID))
+     {
+        dbus_message_unref(sig);
+        return -1;
+     }
+
+   if (!e_dbus_message_send(_a11y_conn, sig, NULL, 0, NULL))
+     {
+        ERROR("Sending GestureDetected signal failed!");
+        dbus_message_unref(sig);
+        return -1;
+     }
+
+   INFO("GestureDetected %s (%d %d %d %d %d)", name, gi->x_beg, gi->y_beg, gi->x_end, gi->y_end, gi->state);
+   dbus_message_unref(sig);
+   return 0;
+}
+
+static void
+_e_mod_submodules_init(void)
+{
+   INFO("Init subsystems...");
+
+   if (_e_mod_atspi_config_init())
+     goto fail;
+   if (_e_mod_atspi_gestures_init())
+     goto fail_gestures;
+   if (_e_mod_atspi_dbus_init())
+     goto fail_dbus;
+   if (_e_mod_atspi_window_tracker_init())
+     goto fail_window_tracker;
+
+   _events_init();
+   g_gesture_navi = EINA_TRUE;
+
+   return;
+
+fail_window_tracker:
+   ERROR("Window tracker submodule initialization failed.");
+   _e_mod_atspi_dbus_shutdown();
+fail_dbus:
+   ERROR("Dbus submodule initialization failed.");
+   _e_mod_atspi_gestures_shutdown();
+fail_gestures:
+   ERROR("Gestures submodule initialization failed.");
+   _e_mod_atspi_config_shutdown();
+fail:
+   ERROR("Module initialization failed.");
+}
+
+static void
+_e_mod_submodules_shutdown(void)
+{
+   INFO("Shutdown subsystems...");
+   _e_mod_atspi_config_save();
+   _e_mod_atspi_config_shutdown();
+   _e_mod_atspi_window_tracker_shutdown();
+   _e_mod_atspi_gestures_shutdown();
+   g_gesture_navi = EINA_FALSE;
+   _events_shutdown();
+   _e_mod_atspi_dbus_shutdown();
+}
+
+static Eina_Bool
+_gesture_cb(void    *data,
+            int      type EINA_UNUSED,
+            void    *event)
+{
+   Gesture_Info *gi = event;
+
+   if (g_gesture_navi)
+     _e_mod_atspi_dbus_broadcast(gi);
+
+   return EINA_TRUE;
+}
+
+
+static Eina_Bool
+_top_window_changed_cb(void    *data,
+            int      type EINA_UNUSED,
+            void    *event)
+{
+   Ecore_X_Window win = _e_mod_atspi_window_tracker_top_window_get();
+   pid_t pid = _e_mod_atspi_window_tracker_top_window_pid_get();
+
+   _e_mod_atpis_dbus_windown_changed_broadcast(pid, win);
+   return EINA_TRUE;
+}
+
+static void
+_events_init(void)
+{
+#define HANDLER_APPEND(event, cb) \
+   handlers = eina_list_append( \
+      handlers, ecore_event_handler_add(event, cb, NULL));
+   HANDLER_APPEND(E_EVENT_ATSPI_GESTURE_DETECTED, _gesture_cb);
+   HANDLER_APPEND(E_EVENT_ATSPI_TOP_WINDOW_CHANGED, _top_window_changed_cb);
+#undef APPEND_HANDLER
+}
+
+static void
+_events_shutdown(void)
+{
+   E_FREE_LIST(handlers, ecore_event_handler_del);
+}
+
+static void
+_vconf_atspi_accessibility_change(keynode_t *node,
+                                   void      *data)
+{
+   INFO("vconf %s key changed\n", VCONF_ATSPI_KEY);
+#if 0
+   int val;
+   if (vconf_get_bool(VCONF_ATSPI_KEY, &val))
+     {
+        ERROR("vconf key \"atspi\" get failed\n");
+        return;
+     }
+
+   if (!!g_enabled == !!val) return;
+
+   if (val)
+     _e_mod_submodules_init();
+   else
+     _e_mod_submodules_shutdown();
+
+   g_enabled = val;
+#endif
+}
+
+
+EAPI void *
+e_modapi_init(E_Module *m)
+{
+   DEBUG("module init\n");
+
+   _e_mod_log_init();
+#if 0
+   if (vconf_notify_key_changed(VCONF_ATSPI_KEY,
+                            _vconf_atspi_accessibility_change,
+                            NULL))
+      ERROR("Unable to register on vconf atspi change");
+
+   if (vconf_get_bool(VCONF_ATSPI_KEY, &g_enabled))
+     {
+        ERROR("Unable to get vconf key\n");
+        return m;
+     }
+#endif
+
+   if (g_enabled)
+     _e_mod_submodules_init();
+
+   return m;
+}
+
+EAPI int
+e_modapi_shutdown(E_Module *m)
+{
+   DEBUG("module shutdown");
+
+   if (g_enabled)
+     _e_mod_atspi_dbus_shutdown();
+
+   g_enabled = 0;
+
+   _e_mod_log_shutdown();
+
+   return 1;
+}
+
+EAPI int
+e_modapi_save(E_Module *m)
+{
+   DEBUG("module saved");
+   return 1;
+}
+
+int _e_mod_log_init(void)
+{
+   if (!_eina_log_dom)
+     {
+        _eina_log_dom = eina_log_domain_register("e17-mod-tizen-screen-reader", NULL);
+        if (_eina_log_dom  < 0)
+          {
+             fprintf(stderr, "Unable to register e17-mod-tizen-screen-reader log domain");
+             return -1;
+          }
+     }
+   return 0;
+}
+
+void _e_mod_log_shutdown(void)
+{
+   if (_eina_log_dom)
+     {
+        eina_log_domain_unregister(_eina_log_dom);
+        _eina_log_dom = 0;
+     }
+}
diff --git a/src/e_mod_main.h b/src/e_mod_main.h
new file mode 100644 (file)
index 0000000..ec696b2
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef _E_MOD_MAIN_H__
+#define _E_MOD_MAIN_H__
+
+#include "e.h"
+
+#define VCONF_ATSPI_KEY "db/setting/accessibility/atspi"
+
+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/e_mod_private.h b/src/e_mod_private.h
new file mode 100644 (file)
index 0000000..a624d07
--- /dev/null
@@ -0,0 +1,79 @@
+#ifndef _E_MOD_A11Y_H__
+#define _E_MOD_A11Y_H__
+
+#include "e.h"
+#include "E_DBus.h"
+
+extern int _eina_log_dom;
+
+#define INFO(...) EINA_LOG_DOM_INFO(_eina_log_dom, __VA_ARGS__);
+#define DEBUG(...) EINA_LOG_DOM_DBG(_eina_log_dom, __VA_ARGS__);
+#define ERROR(...) EINA_LOG_DOM_ERR(_eina_log_dom, __VA_ARGS__);
+
+/**
+ * @brief Accessibility gestures
+ */
+enum _Gesture {
+     ONE_FINGER_HOVER,
+     TWO_FINGERS_HOVER,
+     THREE_FINGERS_HOVER,
+     ONE_FINGER_FLICK_LEFT,
+     ONE_FINGER_FLICK_RIGHT,
+     ONE_FINGER_FLICK_UP,
+     ONE_FINGER_FLICK_DOWN,
+     TWO_FINGERS_FLICK_LEFT,
+     TWO_FINGERS_FLICK_RIGHT,
+     TWO_FINGERS_FLICK_UP,
+     TWO_FINGERS_FLICK_DOWN,
+     THREE_FINGERS_FLICK_LEFT,
+     THREE_FINGERS_FLICK_RIGHT,
+     THREE_FINGERS_FLICK_UP,
+     THREE_FINGERS_FLICK_DOWN,
+     ONE_FINGER_SINGLE_TAP,
+     ONE_FINGER_DOUBLE_TAP,
+     ONE_FINGER_TRIPLE_TAP,
+     TWO_FINGERS_SINGLE_TAP,
+     TWO_FINGERS_DOUBLE_TAP,
+     TWO_FINGERS_TRIPLE_TAP,
+     THREE_FINGERS_SINGLE_TAP,
+     THREE_FINGERS_DOUBLE_TAP,
+     THREE_FINGERS_TRIPLE_TAP,
+     ONE_FINGER_FLICK_LEFT_RETURN,
+     ONE_FINGER_FLICK_RIGHT_RETURN,
+     ONE_FINGER_FLICK_UP_RETURN,
+     ONE_FINGER_FLICK_DOWN_RETURN,
+     TWO_FINGERS_FLICK_LEFT_RETURN,
+     TWO_FINGERS_FLICK_RIGHT_RETURN,
+     TWO_FINGERS_FLICK_UP_RETURN,
+     TWO_FINGERS_FLICK_DOWN_RETURN,
+     THREE_FINGERS_FLICK_LEFT_RETURN,
+     THREE_FINGERS_FLICK_RIGHT_RETURN,
+     THREE_FINGERS_FLICK_UP_RETURN,
+     THREE_FINGERS_FLICK_DOWN_RETURN,
+     GESTURES_COUNT,
+};
+typedef enum _Gesture Gesture;
+
+typedef struct {
+     Gesture type;         // Type of recognized gesture
+     int x_beg, x_end;     // (x,y) coordinates when gesture begin
+     int y_beg, y_end;     // (x,y) coordinates when gesture ends
+     int state;            // 0 - begin, 1 - ongoing, 2 - ended
+} Gesture_Info;
+
+int _e_mod_log_init(void);
+void _e_mod_log_shutdown(void);
+
+extern int E_EVENT_ATSPI_GESTURE_DETECTED;
+
+int _e_mod_atspi_gestures_init(void);
+int _e_mod_atspi_gestures_shutdown(void);
+
+extern int E_EVENT_ATSPI_TOP_WINDOW_CHANGED;
+
+int _e_mod_atspi_window_tracker_init(void);
+Ecore_X_Window _e_mod_atspi_window_tracker_top_window_get(void);
+pid_t _e_mod_atspi_window_tracker_top_window_pid_get(void);
+int _e_mod_atspi_window_tracker_shutdown(void);
+
+#endif
diff --git a/src/e_mod_window_tracker.c b/src/e_mod_window_tracker.c
new file mode 100644 (file)
index 0000000..8ccc484
--- /dev/null
@@ -0,0 +1,176 @@
+#include "e.h"
+#include "e_mod_main.h"
+#include "e_mod_private.h"
+#include "e_mod_config.h"
+
+int E_EVENT_ATSPI_TOP_WINDOW_CHANGED;
+
+static Eina_List *handlers;
+static E_Border *target_border;
+
+static void
+_top_border_get(E_Zone *zone)
+{
+   E_Border *bd;
+   E_Border_List *bl = NULL;
+
+   bl = e_container_border_list_last(zone->container);
+   if (!bl) return;
+
+   while ((bd = e_container_border_list_prev(bl)))
+     {
+        if (!bd->visible) continue;
+        if (E_CONTAINS(zone->x, zone->y, zone->w, zone->h, bd->x, bd->y, bd->w, bd->h))
+          {
+             if (target_border != bd)
+               {
+                  target_border = bd;
+                  ecore_event_add(E_EVENT_ATSPI_TOP_WINDOW_CHANGED, NULL, NULL, NULL);
+                  INFO("Top border changed: pid: %d, winid:%d", bd->client.netwm.pid, bd->client.win);
+               }
+             break;
+          }
+     }
+   e_container_border_list_free(bl);
+}
+
+static Eina_Bool
+_cb_property_change(void *data EINA_UNUSED,
+                   int   type EINA_UNUSED,
+                   void *ev)
+{
+   E_Border *bd;
+   Ecore_X_Event_Window_Property *event = ev;
+
+   if (event->atom == ECORE_X_ATOM_NET_ACTIVE_WINDOW)
+     {
+        bd = e_border_focused_get();
+        if (bd) target_border = bd;
+     }
+
+   return ECORE_CALLBACK_PASS_ON;
+}
+
+static Eina_Bool
+_cb_border_move(void *data EINA_UNUSED,
+               int   type EINA_UNUSED,
+               void *event)
+{
+   E_Border *bd;
+   E_Event_Border_Move *ev = event;
+
+   bd = ev->border;
+   if (!bd) return ECORE_CALLBACK_PASS_ON;
+
+   _top_border_get(bd->zone);
+
+   return ECORE_CALLBACK_PASS_ON;
+}
+
+static Eina_Bool
+_cb_border_hide(void *data EINA_UNUSED,
+               int   type EINA_UNUSED,
+               void *event)
+{
+   E_Border *bd;
+   E_Event_Border_Hide *ev = event;
+
+   bd = ev->border;
+   if (!bd) return ECORE_CALLBACK_PASS_ON;
+
+   _top_border_get(bd->zone);
+
+   return ECORE_CALLBACK_PASS_ON;
+}
+
+static Eina_Bool _cb_border_stack(void *data EINA_UNUSED,
+                                  int type EINA_UNUSED,
+                                  void *event)
+{
+   E_Border *bd;
+   E_Event_Border_Stack *ev = event;
+
+   bd = ev->border;
+   if (!bd) return ECORE_CALLBACK_PASS_ON;
+
+   _top_border_get(bd->zone);
+
+   return ECORE_CALLBACK_PASS_ON;
+}
+
+static Eina_Bool
+_cb_border_show(void *data EINA_UNUSED,
+               int   type EINA_UNUSED,
+               void *event)
+{
+   E_Border *bd;
+   E_Event_Border_Show *ev = event;
+
+   bd = ev->border;
+   if (!bd) return ECORE_CALLBACK_PASS_ON;
+
+   _top_border_get(bd->zone);
+
+   return ECORE_CALLBACK_PASS_ON;
+}
+
+static void
+_events_init(void)
+{
+#define HANDLER_APPEND(event, cb) \
+   handlers = eina_list_append( \
+      handlers, ecore_event_handler_add(event, cb, NULL));
+   HANDLER_APPEND(ECORE_X_EVENT_WINDOW_PROPERTY,  _cb_property_change);
+   HANDLER_APPEND(E_EVENT_BORDER_SHOW,  _cb_border_show);
+   HANDLER_APPEND(E_EVENT_BORDER_MOVE,  _cb_border_move);
+   HANDLER_APPEND(E_EVENT_BORDER_HIDE,  _cb_border_hide);
+   HANDLER_APPEND(E_EVENT_BORDER_STACK,  _cb_border_stack);
+#undef APPEND_HANDLER
+
+   if (!E_EVENT_ATSPI_TOP_WINDOW_CHANGED)
+      E_EVENT_ATSPI_TOP_WINDOW_CHANGED = ecore_event_type_new();
+}
+
+static void
+_events_shutdown(void)
+{
+   E_FREE_LIST(handlers, ecore_event_handler_del);
+}
+
+int _e_mod_atspi_window_tracker_init(void)
+{
+   DEBUG("Window tracker init");
+   _events_init();
+
+   target_border = e_border_focused_get();
+
+   return 0;
+}
+
+int _e_mod_atspi_window_tracker_shutdown(void)
+{
+   DEBUG("Window tracker shutdown");
+   _events_shutdown();
+   target_border = NULL;
+
+   return 0;
+}
+
+Ecore_X_Window 
+_e_mod_atspi_window_tracker_top_window_get(void)
+{
+   if (target_border)
+     return target_border->client.win;
+
+   return -1;
+}
+
+pid_t
+_e_mod_atspi_window_tracker_top_window_pid_get(void)
+{
+   if (target_border)
+     return target_border->client.netwm.pid;
+
+   return -1;
+}
+