source
authorŁukasz Buśko <l.busko@samsung.com>
Wed, 31 Dec 2014 10:50:05 +0000 (11:50 +0100)
committerŁukasz Buśko <l.busko@samsung.com>
Wed, 31 Dec 2014 10:50:29 +0000 (11:50 +0100)
45 files changed:
CMakeLists.sub [new file with mode: 0755]
CMakeLists.txt [new file with mode: 0755]
README [new file with mode: 0644]
include/app_tracker.h [new file with mode: 0644]
include/etest.h [new file with mode: 0755]
include/flat_navi.h [new file with mode: 0644]
include/gesture_tracker.h [new file with mode: 0644]
include/keyboard_tracker.h [new file with mode: 0644]
include/logger.h [new file with mode: 0644]
include/navigator.h [new file with mode: 0644]
include/object_cache.h [new file with mode: 0644]
include/pivot_chooser.h [new file with mode: 0644]
include/position_sort.h [new file with mode: 0644]
include/screen_reader.h [new file with mode: 0644]
include/screen_reader_spi.h [new file with mode: 0644]
include/screen_reader_tts.h [new file with mode: 0644]
include/screen_reader_vconf.h [new file with mode: 0644]
include/screen_reader_xml.h [new file with mode: 0644]
include/structural_navi.h [new file with mode: 0644]
include/window_tracker.h [new file with mode: 0644]
include/xml_parser.h [new file with mode: 0644]
init [deleted file]
org.tizen.smart-navigator.manifest [new file with mode: 0644]
org.tizen.smart-navigator.xml [new file with mode: 0755]
packaging/org.tizen.etest.spec~ [new file with mode: 0644]
packaging/org.tizen.smart-navigator.spec [new file with mode: 0755]
res/icons/smart-navigator.png [new file with mode: 0755]
src/app_tracker.c [new file with mode: 0644]
src/flat_navi.c [new file with mode: 0644]
src/gesture_tracker.c [new file with mode: 0644]
src/keyboard_tracker.c [new file with mode: 0644]
src/logger.c [new file with mode: 0644]
src/main.c [new file with mode: 0755]
src/navigator.c [new file with mode: 0644]
src/object_cache.c [new file with mode: 0644]
src/pivot_chooser.c [new file with mode: 0644]
src/position_sort.c [new file with mode: 0644]
src/screen_reader.c [new file with mode: 0755]
src/screen_reader_spi.c [new file with mode: 0644]
src/screen_reader_tts.c [new file with mode: 0644]
src/screen_reader_vconf.c [new file with mode: 0644]
src/screen_reader_xml.c [new file with mode: 0644]
src/structural_navi.c [new file with mode: 0644]
src/window_tracker.c [new file with mode: 0644]
src/xml_parser.c [new file with mode: 0755]

diff --git a/CMakeLists.sub b/CMakeLists.sub
new file mode 100755 (executable)
index 0000000..0af29c3
--- /dev/null
@@ -0,0 +1,26 @@
+## PROJECT NAME
+PROJECT(smart-navigator C)
+
+## INCLUDES
+INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include)
+
+## DEFINITIONS
+ADD_DEFINITIONS("")
+
+## LIBRARY PATH
+SET(SLP_LD_PATH_FLAGS "")
+
+## LIBRARY
+SET(SLP_LD_FLAGS "")
+
+## DEBUG
+SET(SLP_DEBUG_FLAGS "-g")
+
+## OPTIMIZATION
+SET(SLP_OPT_FLAGS "-O0")
+
+## COMPILER FLAGS
+SET(SLP_COMPILER_FLAGS "-Wall -Wunused")
+
+## LINKER FLAGS
+SET(SLP_LINKER_FLAGS "")
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..10e6629
--- /dev/null
@@ -0,0 +1,46 @@
+CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
+
+# FIND ALL SOURCE IN A SOURCE DIRECTORY
+AUX_SOURCE_DIRECTORY(${CMAKE_SOURCE_DIR}/src SRCS)
+
+#INCLUDE FILE 
+INCLUDE(CMakeLists.sub)
+SET(RESOURCE_DIR "${CMAKE_SOURCE_DIR}/res")
+
+INCLUDE(FindPkgConfig)
+pkg_check_modules(pkgs REQUIRED
+       bundle
+       appcore-efl
+       eldbus
+       elementary
+       ecore
+       atspi-2
+       gobject-2.0
+       ecore-x
+       dlog
+       vconf
+       tts
+
+)
+
+FOREACH(flag ${pkgs_CFLAGS})
+       SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}")
+ENDFOREACH(flag)
+
+
+SET(CMAKE_C_FLAGS "${SLP_DEBUG_FLAGS} ${SLP_OPT_FLAGS} ${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} ${SLP_COMPILER_FLAGS}")
+SET(CMAKE_CXX_FLAGS "${SLP_DEBUG_FLAGS} ${SLP_OPT_FLAGS} ${CMAKE_CXX_FLAGS} ${EXTRA_CFLAGS} ${SLP_COMPILER_FLAGS}")
+
+MESSAGE(${CMAKE_C_FLAGS})
+
+ADD_EXECUTABLE(${PROJECT_NAME} ${SRCS})
+
+
+TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${pkgs_LDFLAGS} ${SLP_LD_PATH_FLAGS} ${SLP_LD_FLAGS} ${SLP_LINKER_FLAGS})
+
+# Install 
+INSTALL(TARGETS ${PROJECT_NAME} DESTINATION bin)
+INSTALL(DIRECTORY ${RESOURCE_DIR}/icons DESTINATION res) 
+# Install Manifest File
+INSTALL(FILES org.tizen.smart-navigator.xml DESTINATION /opt/share/packages)
+# End of a file
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..fc09a6f
--- /dev/null
+++ b/README
@@ -0,0 +1,9 @@
+Before running smart navigator extend /usr/lib/systemd/system/pulseaudio.service
+[Service]
+...
+ExecStartPre=/bin/chmod 777 /tmp/pulseaudio
+...
+To give other processes like smart-navigator access to pulseaudio tmp.
+
+Extending service with User=pulse or changing owner ship on /tmp/pulseaudio
+results with malfunction of service.
diff --git a/include/app_tracker.h b/include/app_tracker.h
new file mode 100644 (file)
index 0000000..f813ab9
--- /dev/null
@@ -0,0 +1,61 @@
+#ifndef APP_TRACKER_H_
+#define APP_TRACKER_H_
+
+#include <atspi/atspi.h>
+
+/**
+ * @brief Application events
+ *
+ * @APP_TRACKER_EVENT_VIEW_CHANGE_STARTED - occuring when any of application's
+ * UI parts has change its visuals, including moving, resizing widgets, scrolling etc.
+ *
+ * @APP_TRACKER_EVENT_VIEW_CHANGED occuring when any of application's
+ * UI parts has changed its visuals and a prefined time period elapsed 
+ *
+ */
+typedef enum {
+       APP_TRACKER_EVENT_VIEW_CHANGE_STARTED,
+       APP_TRACKER_EVENT_VIEW_CHANGED,
+       APP_TRACKER_EVENT_COUNT
+} AppTrackerEventType;
+
+/**
+ * @brief Callback
+ */
+typedef void (*AppTrackerEventCB)(AppTrackerEventType type, void *user_data);
+
+/**
+ * @brief Register listener on given event type.
+ *
+ * @param obj AtspiAccessible application object type
+ * @param event type of event to register on
+ * @param cb callback type
+ * @param user_data pointer passed to cb function.
+ */
+void app_tracker_callback_register(AtspiAccessible *app, AppTrackerEventType event, AppTrackerEventCB cb, void *user_data);
+
+/**
+ * @brief Unregister listener on given event type.
+ *
+ * @param obj AtspiAccessible application object type
+ * @param event type of event to register on
+ * @param cb callback type
+ * @param user_data pointer passed to cb function.
+ */
+void app_tracker_callback_unregister(AtspiAccessible *app, AppTrackerEventType event, AppTrackerEventCB cb, void *user_data);
+
+/**
+ * @brief Initialize app tracker module.
+ *
+ * @return initi count.
+ *
+ * @nore function atspi_init will be called.
+ */
+int app_tracker_init(void);
+
+/**
+ * @brief Shutdown app tracker module
+ */
+void app_tracker_shutdown(void);
+
+#endif /* end of include guard: APP_TRACKER_H_ */
diff --git a/include/etest.h b/include/etest.h
new file mode 100755 (executable)
index 0000000..4b1656e
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef __ETEST_H__
+#define __ETEST_H__
+
+#include <Elementary.h>
+#include <Ecore_X.h>
+#include <Elementary.h>
+#include <Evas.h>
+
+struct appdata {
+       Evas_Object *win;
+};
+
+#endif 
\ No newline at end of file
diff --git a/include/flat_navi.h b/include/flat_navi.h
new file mode 100644 (file)
index 0000000..0b4af28
--- /dev/null
@@ -0,0 +1,135 @@
+#ifndef FLAT_NAVI_H_
+#define FLAT_NAVI_H_
+
+#include <atspi/atspi.h>
+#include <Eina.h>
+
+typedef struct _FlatNaviContext FlatNaviContext;
+
+/**
+ * @brief Creates new FlatNaviContext.
+ *
+ * FlatNaviContext organizes UI elements in a way that is similar to
+ * reading orded (from left to right) and allow it traversing.
+ *
+ * @param root AtspiAccessible root object on which descendants FlatNaviContext
+ * will be builded.
+ *
+ * @return New FlatNaviContext. Should be free with flat_navi_context_free.
+ *
+ * @note Context will use positions obtain from object_cache. It is up
+ * to developer to guarantee that cache is up-to-date.
+ * @note Context will use position_sort to sort elements into lines.
+ * @note Context will use heuristics to those choose elements of UI
+ * that will be segmented into lines. Plese refer to source code for further details.
+ * @note default current element is first object in first line.
+ *
+ */
+FlatNaviContext *flat_navi_context_create(AtspiAccessible *root);
+
+/**
+ * @brief Frees FlatNaviContext
+ * @param ctx FlatNaviContext
+ */
+void flat_navi_context_free(FlatNaviContext *ctx);
+
+/**
+ * Advances to next element in natural reading order and returns
+ * new current element.
+ *
+ * @param ctx FlatNaviContext
+ *
+ * @return AtspiAccessible* pointer to current object
+ *
+ * @note If current element is last in line function advances to
+ * next line to first element.
+ * @note If current element is last in last line, function returns NULL
+ */
+AtspiAccessible *flat_navi_context_next(FlatNaviContext *ctx);
+
+/**
+ * Advances to previous element in natural reading order and returns
+ * new current element.
+ *
+ * @param ctx FlatNaviContext
+ *
+ * @return AtspiAccessible* pointer to current object
+ *
+ * @note If current element is first in line function advances to
+ * previous line to last element.
+ * @note If current element is first in first line, function returns NULL
+ */
+AtspiAccessible *flat_navi_context_prev(FlatNaviContext *ctx);
+
+/**
+ * Get current element
+ *
+ * @param ctx FlatNaviContext
+ *
+ * @return AtspiAccessible* pointer to current object
+ */
+AtspiAccessible *flat_navi_context_current_get(FlatNaviContext *ctx);
+
+/**
+ * Set current element.
+ *
+ * @note There might be situation when target object is not in FlatNaviContext.
+ * (eg. was filtered by internal heuristic) in this situations function returns
+ * EINA_FALSE.
+ *
+ * @param ctx FlatNaviContext
+ * @param target new current FlatNaviContext object
+ *
+ * @return EINA_TRUE is operation successed, EINA_FALSE otherwise
+ */
+Eina_Bool flat_navi_context_current_set(FlatNaviContext *ctx, AtspiAccessible *target);
+
+/**
+ * Advances to previous line in natural reading order and returns
+ * new current element.
+ *
+ * @param ctx FlatNaviContext
+ *
+ * @return AtspiAccessible* pointer to current object
+ *
+ * @note If current line is first one, function returns NULL
+ * @note current element will be first of line.
+ */
+AtspiAccessible *flat_navi_context_line_prev(FlatNaviContext *ctx);
+
+/**
+ * Advances to next line in natural reading order and returns
+ * new current element.
+ *
+ * @param ctx FlatNaviContext
+ *
+ * @return AtspiAccessible* pointer to current object
+ *
+ * @note If current line is last one, function returns NULL
+ * @note current element will be first of line.
+ */
+AtspiAccessible *flat_navi_context_line_next(FlatNaviContext *ctx);
+
+/**
+ * Advances to first line.
+ *
+ * @param ctx FlatNaviContext
+ *
+ * @return AtspiAccessible* pointer to current object
+ *
+ * @note current element will be first of line.
+ */
+AtspiAccessible *flat_navi_context_line_first(FlatNaviContext *ctx);
+
+/**
+ * Advances to first line.
+ *
+ * @param ctx FlatNaviContext
+ *
+ * @return AtspiAccessible* pointer to current object
+ *
+ * @note current element will be first of line.
+ */
+AtspiAccessible *flat_navi_context_line_last(FlatNaviContext *ctx);
+
+#endif /* end of include guard: FLAT_NAVI_H_ */
diff --git a/include/gesture_tracker.h b/include/gesture_tracker.h
new file mode 100644 (file)
index 0000000..5ae3ea9
--- /dev/null
@@ -0,0 +1,40 @@
+#include <eldbus-1/Eldbus.h>
+#include <atspi/atspi.h>
+
+/**
+ * @brief Accessibility gestures
+ */
+enum _Gesture {
+     ONE_FINGER_HOVER,
+     TWO_FINGERS_HOVER,
+     ONE_FINGER_FLICK_LEFT,
+     ONE_FINGER_FLICK_RIGHT,
+     ONE_FINGER_FLICK_UP,
+     ONE_FINGER_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,
+     TWO_FINGERS_FLICK_UP,
+     TWO_FINGERS_FLICK_LEFT,
+     TWO_FINGERS_FLICK_RIGHT,
+     TWO_FINGERS_FLICK_DOWN,
+     GESTURES_COUNT,
+};
+typedef enum _Gesture Gesture;
+
+typedef struct {
+     Gesture type;         // Type of recognized gesture
+     int x_begin, x_end;     // (x,y) coordinates when gesture begin
+     int y_begin, y_end;     // (x,y) coordinates when gesture ends
+     int state;              // 0 - gesture begins, 1 - continues, 2 - ended
+} Gesture_Info;
+
+
+typedef void (*Gesture_Tracker_Cb) (void *data, Gesture_Info *g);
+void gesture_tracker_init(Eldbus_Connection *conn);
+void gesture_tracker_register(Gesture_Tracker_Cb cb, void *data);
+void gesture_tracker_shutdown(void);
+AtspiAccessible* _get_active_win(void);
diff --git a/include/keyboard_tracker.h b/include/keyboard_tracker.h
new file mode 100644 (file)
index 0000000..4adb8eb
--- /dev/null
@@ -0,0 +1,17 @@
+/**
+ * @brief Supported Keys
+ */
+enum _Key {
+     KEY_LEFT,
+     KEY_RIGHT,
+     KEY_UP,
+     KEY_DOWN,
+     KEY_COUNT
+};
+
+typedef enum _Key Key;
+
+typedef void (*Keyboard_Tracker_Cb) (void *data, Key k);
+void keyboard_tracker_init(void);
+void keyboard_tracker_register(Keyboard_Tracker_Cb cb, void *data);
+void keyboard_tracker_shutdown(void);
diff --git a/include/logger.h b/include/logger.h
new file mode 100644 (file)
index 0000000..4980767
--- /dev/null
@@ -0,0 +1,9 @@
+#include <eina_log.h>
+int _eina_log_dom;
+
+int logger_init(void);
+void logger_shutdown(void);
+
+#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__);
diff --git a/include/navigator.h b/include/navigator.h
new file mode 100644 (file)
index 0000000..a797801
--- /dev/null
@@ -0,0 +1,2 @@
+void navigator_init(void);
+void navigator_shutdown(void);
diff --git a/include/object_cache.h b/include/object_cache.h
new file mode 100644 (file)
index 0000000..cd97d67
--- /dev/null
@@ -0,0 +1,58 @@
+#ifndef SMART_NAVI_OBJECT_CACHE_H_H
+#define SMART_NAVI_OBJECT_CACHE_H_H
+
+#include <atspi/atspi.h>
+
+typedef struct {
+    // Boundaries of object taken from atspi_component_get_extents function.
+    // NULL if object do not implemetn AtspiComponent interface
+    AtspiRect *bounds;
+} ObjectCache;
+
+typedef void (*ObjectCacheReadyCb)(void *data);
+
+/**
+ * @brief Recursivly build ObjectCache structures for root Accessible
+ * object from and its descendants. (Children's children also, etc.)
+ *
+ * @param root starting object.
+ *
+ * @remarks This function may block main-loop for significant ammount of time.
+ *          Flushes all previously cached items.
+ */
+void object_cache_build(AtspiAccessible *root);
+
+/**
+ * @brief Recursivly build ObjectCache structures for ever Accessible
+ * object from root and its all descendants.
+ *
+ * @param root starting object.
+ * @param bulk_size Ammount of AtspiAccessible that will be cached on every
+ * ecore_main_loop entering into 'idle' state.
+ * @param cb function to be called after creating cache is done.
+ * @param user_data passed to cb
+ *
+ * @remarks Flushes all previously cached items.
+ */
+void object_cache_build_async(AtspiAccessible *root, int bulk_size, ObjectCacheReadyCb cb, void *user_data);
+
+/**
+ * @brief Gets and ObjectCache item from accessible object
+ *
+ * @param obj AtspiAccessible
+ *
+ * @remarks If obj is not in cache function will block main loop and build ObjectCache
+ * struct.
+ */
+const ObjectCache *object_cache_get(AtspiAccessible *obj);
+
+/**
+ * @brief Shoutdown cache.
+ *
+ * Function will free all gathered caches.
+ *
+ * @remarks Use it after You have used any of above object_cache_* functions.
+ */
+void object_cache_shutdown(void);
+
+#endif /* end of include guard: OBJECT_CACHE_H_H */
diff --git a/include/pivot_chooser.h b/include/pivot_chooser.h
new file mode 100644 (file)
index 0000000..164e84c
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef SMART_NAVI_PIVOT_CHOOSER_H_
+#define SMART_NAVI_PIVOT_CHOOSER_H_
+
+#include <atspi/atspi.h>
+
+/**
+ * @brief Some heuristic choosing candidate to reacieve highlight.
+ *
+ * @param win Accessibility search tree object root.
+ *
+ * @return Highlight candidate
+ */
+AtspiAccessible *pivot_chooser_pivot_get(AtspiAccessible *win);
+
+#endif /* end of include guard: PIVOT_CHOOSER_H_ */
diff --git a/include/position_sort.h b/include/position_sort.h
new file mode 100644 (file)
index 0000000..9f9bbda
--- /dev/null
@@ -0,0 +1,37 @@
+#ifndef SMART_NAVI_POSITION_SORT_H_
+#define SMART_NAVI_POSITION_SORT_H_
+
+#include <atspi/atspi.h>
+#include <Eina.h>
+
+
+/**
+ * @brief Sort objects by position they appear on screen
+ *
+ *  example:
+ *
+ *  ------------------------------
+ *  |                   _______  |
+ *  |  _______          |     |  |
+ *  |  |     |  ______  |     |  |
+ *  |  |  A  |  |    |  |     |  |
+ *  |  |_____|  | B  |  |  C  |  |
+ *  |           |    |  |     |  |
+ *  |           |____|  |     |  |
+ *  |   _____           |     |  |             line 0: A, B, C
+ *  |   |   |           |_____|  |             line 1: D
+ *  |   | D |                    |    ====>    line 2: F
+ *  |   |___| _____              |             line 3: G
+ *  |         |   |              |
+ *  |         | F | _____        |
+ *  |         |___| |   |        |
+ *  |               | G |        |
+ *  |               |___|        |
+ *  |                            |
+ *  ------------------------------
+ *
+ * @ret list List of lists
+ */
+Eina_List *position_sort(const Eina_List *obj);
+
+#endif /* end of include guard: POSITION_SORT_H_ */
diff --git a/include/screen_reader.h b/include/screen_reader.h
new file mode 100644 (file)
index 0000000..dc7735e
--- /dev/null
@@ -0,0 +1,87 @@
+#ifndef __screen_reader_H__
+#define __screen_reader_H__
+
+#include <atspi/atspi.h>
+#include <Eldbus.h>
+#include <tts.h>
+
+#define LAN_NAME 6
+
+#define MAX_REACHED ", maximum value reached"
+#define MIN_REACHED ", minimum value reached"
+#define MAX_POS_REACHED ", end of text reached"
+#define MIN_POS_REACHED ", begin of text reached"
+
+#define HIGHLIGHT_SIG "highlighted"
+#define FOCUS_SIG "focused"
+
+#define HIGHLIGHT_CHANGED_SIG "object:state-changed:highlighted"
+#define FOCUS_CHANGED_SIG "object:state-changed:focused"
+#define VALUE_CHANGED_SIG "object:property-change:accessible-value"
+#define CARET_MOVED_SIG "object:text-caret-moved"
+
+typedef struct
+{
+       char *language;
+       int voice_type;
+} Voice_Info;
+
+
+typedef enum
+{
+       read_as_xml,
+       read_as_plain,
+       dont_read
+} Wrong_Validation_Reacction;
+
+typedef struct _Service_Data
+{
+       //Set by vconf
+       int information_level;
+       bool run_service;
+       char language[LAN_NAME];
+       int voice_type;
+       int reading_speed;
+       char *tracking_signal_name;
+
+       //Set by tts
+       tts_h tts;
+       Eina_List *available_languages;
+
+       char *text_to_say_text;
+       char *description_text;
+       char *text_to_say_info;
+       char *current_value;
+       char *current_char;
+
+       //Actions to do when tts state is 'ready'
+       int _dbus_txt_readed;
+       bool say_text;
+       bool update_language_list;
+
+       //Set by spi
+       AtspiEventListener *state_changed_listener;
+       AtspiEventListener *value_changed_listener;
+       AtspiEventListener *caret_moved_listener;
+
+       AtspiAccessible  *currently_focused;
+       AtspiAccessible  *mouse_down_widget;
+       AtspiAccessible  *clicked_widget;
+
+       //Set by dbus
+       Eldbus_Proxy *proxy;
+       char **last_tokens;
+       char *available_requests;
+       char **available_apps;
+
+       const char *text_from_dbus;
+
+} Service_Data;
+
+Service_Data *get_pointer_to_service_data_struct();
+
+int screen_reader_create_service(void *data);
+
+int screen_reader_terminate_service(void *data);
+
+#endif
diff --git a/include/screen_reader_spi.h b/include/screen_reader_spi.h
new file mode 100644 (file)
index 0000000..31e93dc
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * screen_reader_spi.h
+ *
+ *  Created on: Feb 20, 2014
+ *      Author: m.skorupinsk
+ */
+
+#ifndef SCREEN_READER_SPI_H_
+#define SCREEN_READER_SPI_H_
+
+#include <atspi/atspi.h>
+#include "screen_reader.h"
+
+void spi_init(Service_Data *sd);
+void spi_on_state_changed_cb(const AtspiEvent *event, void *user_data);
+void spi_on_caret_move_cb(const AtspiEvent *event, void *user_data);
+void spi_on_access_value_changed_cb(const AtspiEvent *event, void *user_data);
+
+#endif /* SCREEN_READER_SPI_H_ */
diff --git a/include/screen_reader_tts.h b/include/screen_reader_tts.h
new file mode 100644 (file)
index 0000000..8ab3092
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * screen_reader_tts.h
+ *
+ *  Created on: Feb 19, 2014
+ *      Author: m.skorupinsk
+ */
+
+#ifndef SCREEN_READER_TTS_H_
+#define SCREEN_READER_TTS_H_
+
+#include <tts.h>
+#include "screen_reader.h"
+
+extern tts_h h_tts;
+extern char* language;
+extern int voice;
+extern int speed;
+
+bool tts_init(void *data);
+void state_changed_cb(tts_h tts, tts_state_e previous, tts_state_e current, void* user_data);
+bool update_supported_voices(void *data);
+void spi_prepare_text(void *data);
+void tts_append_text(void *data);
+void spi_stop(void *data);
+
+#endif /* SCREEN_READER_TTS_H_ */
diff --git a/include/screen_reader_vconf.h b/include/screen_reader_vconf.h
new file mode 100644 (file)
index 0000000..fda47cc
--- /dev/null
@@ -0,0 +1,15 @@
+/*
+ * screen_reader_vconf.h
+ *
+ *  Created on: Feb 19, 2014
+ *      Author: m.skorupinsk
+ */
+
+#ifndef SCREEN_READER_VCONF_H_
+#define SCREEN_READER_VCONF_H_
+
+#include "screen_reader.h"
+
+bool vconf_init(Service_Data *service_data);
+
+#endif /* SCREEN_READER_VCONF_H_ */
diff --git a/include/screen_reader_xml.h b/include/screen_reader_xml.h
new file mode 100644 (file)
index 0000000..9a2afc1
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ * screen_reader_xml.h
+ *
+ *  Created on: Mar 26, 2014
+ *      Author: m.skorupinsk
+ */
+
+#ifndef SCREEN_READER_XML_H_
+#define SCREEN_READER_XML_H_
+
+#include <atspi/atspi.h>
+#include "screen_reader.h"
+
+void xml_init(Service_Data *sd);
+char *get_text_to_read(const char *action, AtspiAccessible *widget);
+
+#endif /* SCREEN_READER_XML_H_ */
diff --git a/include/structural_navi.h b/include/structural_navi.h
new file mode 100644 (file)
index 0000000..64db592
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef SMART_NAVI_STRUCTURAL_NAVI_H
+#define SMART_NAVI_STRUCTURAL_NAVI_H_
+
+#include <atspi/atspi.h>
+
+AtspiAccessible *structural_navi_same_level_next(AtspiAccessible *current);
+AtspiAccessible *structural_navi_same_level_prev(AtspiAccessible *current);
+
+AtspiAccessible *structural_navi_level_up(AtspiAccessible *current);
+AtspiAccessible *structural_navi_level_down(AtspiAccessible *current);
+
+AtspiAccessible *structural_navi_app_chain_next(AtspiAccessible *current);
+AtspiAccessible *structural_navi_app_chain_prev(AtspiAccessible *current);
+
+#endif /* end of include guard: STRUCTURAL_NAVI_KML0ETIJ */
diff --git a/include/window_tracker.h b/include/window_tracker.h
new file mode 100644 (file)
index 0000000..a36fd28
--- /dev/null
@@ -0,0 +1,8 @@
+#include <atspi/atspi.h>
+
+void window_tracker_init(void);
+void window_tracker_shutdown(void);
+
+typedef void (*Window_Tracker_Cb) (void *data, AtspiAccessible *window);
+void window_tracker_register(Window_Tracker_Cb cb, void *data);
+void window_tracker_active_window_request(void);
diff --git a/include/xml_parser.h b/include/xml_parser.h
new file mode 100644 (file)
index 0000000..9fc6742
--- /dev/null
@@ -0,0 +1,27 @@
+#ifndef __ETEST_H__
+#define __ETEST_H__
+
+#include <Eina.h>
+
+typedef struct
+{
+       char *tag_type;
+       Eina_Simple_XML_Attribute **pairs;
+} Tag;  //TODO: Zamienić na standard ??
+
+void test_fun();
+
+char *get_string_str(Tag *tags, char *descr, Eina_Simple_XML_Attribute **pairs, char *tag_name);
+
+void print_tree(Eina_Simple_XML_Node_Tag *tag, int text_offset);
+
+Eina_Simple_XML_Node_Tag *modify_tag(Tag *tags,  Eina_Simple_XML_Node_Tag *root,
+               const char *tag_name,     Eina_Simple_XML_Attribute **pairs,
+               const char *new_tag_name, Eina_Simple_XML_Attribute **new_pairs, const char *new_data);
+
+Eina_Simple_XML_Node_Tag *add_tag(Tag *tags,  Eina_Simple_XML_Node_Tag *root,
+               const char *tag, const char *data, Eina_Simple_XML_Attribute **pairs);
+
+Eina_Simple_XML_Node_Tag *add_tag_str(Tag *tags,  Eina_Simple_XML_Node_Root *root, const char *tag_str);
+
+#endif
diff --git a/init b/init
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/org.tizen.smart-navigator.manifest b/org.tizen.smart-navigator.manifest
new file mode 100644 (file)
index 0000000..f8c779a
--- /dev/null
@@ -0,0 +1,40 @@
+<manifest>
+ <define>
+    <domain name="smart-navigator" />
+    <permit>
+       <smack permit="dbus" type="rwx" />
+       <smack permit="atspi" type="rwx" />
+       <smack permit="e17" type="rwx" />
+       <smack permit="tts-server" type="rwx" />
+    </permit>
+    <request>
+       <smack request="sdbd" type="rwx" />
+       <smack request="atspi" type="rwx" />
+       <smack request="dbus" type="rwx" />
+       <smack request="xorg" type="rwx" />
+       <smack request="pulseaudio" type="rwxat" />
+       <smack request="pkgmgr::db" type="rwx" />
+       <smack request="device::app_logging" type="rwx" />
+       <smack request="ail::db" type="rwx" />
+       <smack request="system::vconf" type="rwx" />
+       <smack request="system::vconf_setting" type="rwx" />
+       <smack request="system::vconf_system" type="rwx" />
+       <smack request="system::vconf_inhouse" type="rwx" />
+       <smack request="system::vconf_multimedia" type="rwx" />
+       <smack request="system::vconf_misc" type="rwx" />
+       <smack request="isf" type="rwx" />
+       <smack request="system::homedir" type="rwx" />
+       <smack request="system::tmpdir" type="rwx" />
+       <smack request="sys-assert::core" type="rwxat" />
+       <smack request="device::sys_logging" type="rwx" />
+       <smack request="svi-data" type="rwx" />
+       <smack request="e17" type="rwx" />
+       <smack request="tts-server" type="rwx" />
+       <smack request="home-lite" type="rwx" />
+    </request>
+ </define>
+
+<request>
+<domain name="smart-navigator"/>
+</request>
+</manifest>
diff --git a/org.tizen.smart-navigator.xml b/org.tizen.smart-navigator.xml
new file mode 100755 (executable)
index 0000000..775dac0
--- /dev/null
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<manifest xmlns="http://tizen.org/ns/packages" package="org.tizen.smart-navigator" version="0.1.0" install-location="internal-only">
+        <label>smart-navigator</label>
+        <author email="m.szczecinsk@partner.samsung.com" href="www.samsung.com">Michal Szczecinski</author>
+        <description>SMART NAVIGATOR</description>
+        <ui-application appid="org.tizen.smart-navigator" exec="/usr/apps/org.tizen.smart-navigator/bin/smart-navigator" nodisplay="false" multiple="false" type="capp" taskmanage="true">
+                <label>smart-navigator</label>
+                <icon>/usr/apps/org.tizen.smart-navigator/res/icons/smart-navigator.png</icon>
+                <label xml:lang="en-us">smart-navigator</label>
+        </ui-application>
+</manifest>
+
diff --git a/packaging/org.tizen.etest.spec~ b/packaging/org.tizen.etest.spec~
new file mode 100644 (file)
index 0000000..5beebce
--- /dev/null
@@ -0,0 +1,46 @@
+%define AppInstallPath /opt/usr/apps/%{name}
+%define Exec etest
+
+
+Name:       org.tizen.etest
+Summary:    Empty app
+Version:    0.0.1
+Release:    1
+License:    Apache-2.0
+Source0:    %{name}-%{version}.tar.gz
+
+BuildRequires:  pkgconfig(appcore-efl)
+BuildRequires:  pkgconfig(ecore)
+BuildRequires:  pkgconfig(eina)
+BuildRequires:  pkgconfig(evas)
+BuildRequires:  pkgconfig(bundle)
+BuildRequires:  cmake
+BuildRequires:  tts
+BuildRequires:  tts-devel
+
+
+%description
+An utility library for developers of the menu screen.
+
+%prep
+%setup -q
+
+%build
+cmake . -DCMAKE_INSTALL_PREFIX="%{AppInstallPath}" -DCMAKE_TARGET="%{Exec}" -DCMAKE_PACKAGE="%{name}"
+make %{?jobs:-j%jobs}
+
+%install
+rm -rf %{buildroot}
+%make_install
+
+%post 
+/sbin/ldconfig
+
+%postun -p /sbin/ldconfig
+
+%files
+%{AppInstallPath}/bin/etest
+%{AppInstallPath}/res/icons/etest.png
+/opt/share/packages/%{name}.xml
+
+
diff --git a/packaging/org.tizen.smart-navigator.spec b/packaging/org.tizen.smart-navigator.spec
new file mode 100755 (executable)
index 0000000..da10dd3
--- /dev/null
@@ -0,0 +1,52 @@
+%define AppInstallPath /usr/apps/%{name}
+%define Exec smart-navigator
+
+
+Name:       org.tizen.smart-navigator
+Summary:    Empty app
+Version:    0.0.1
+Release:    1
+License:    Apache-2.0
+Source0:    %{name}-%{version}.tar.gz
+
+BuildRequires:  at-spi2-core
+BuildRequires:  at-spi2-core-devel
+BuildRequires:  cmake
+BuildRequires:  pkgconfig(appcore-efl)
+BuildRequires:  pkgconfig(ecore)
+BuildRequires:  pkgconfig(ecore-x)
+BuildRequires:  pkgconfig(eina)
+BuildRequires:  pkgconfig(eldbus)
+BuildRequires:  pkgconfig(elementary)
+BuildRequires:  tts
+BuildRequires:  tts-devel
+BuildRequires:  vconf
+
+%description
+An utility library for developers of the menu screen.
+
+%prep
+%setup -q
+
+%build
+cmake . -DCMAKE_INSTALL_PREFIX="%{AppInstallPath}" -DCMAKE_TARGET="%{Exec}" -DCMAKE_PACKAGE="%{name}"
+make %{?jobs:-j%jobs}
+
+%install
+rm -rf %{buildroot}
+%make_install
+
+%post 
+/sbin/ldconfig
+vconftool set -t string db/setting/accessibility/language "en_US" -u 5000 -s smart-navigator -f
+vconftool set -t int db/setting/accessibility/information_level 2 -u 5000 -s smart-navigator -f
+vconftool set -t int db/setting/accessibility/voice 1 -u 5000 -s smart-navigator -f
+vconftool set -t string db/setting/accessibility/tracking_signal "highlighted" -u 5000 -s smart-navigator -f
+
+%postun -p /sbin/ldconfig
+
+%files
+%manifest org.tizen.smart-navigator.manifest
+%{AppInstallPath}/bin/smart-navigator
+%{AppInstallPath}/res/icons/smart-navigator.png
+/opt/share/packages/%{name}.xml
diff --git a/res/icons/smart-navigator.png b/res/icons/smart-navigator.png
new file mode 100755 (executable)
index 0000000..778d06b
Binary files /dev/null and b/res/icons/smart-navigator.png differ
diff --git a/src/app_tracker.c b/src/app_tracker.c
new file mode 100644 (file)
index 0000000..17355a3
--- /dev/null
@@ -0,0 +1,218 @@
+#include "app_tracker.h"
+#include "logger.h"
+
+typedef struct {
+     AtspiAccessible *root;
+     GList *callbacks;
+     guint timer;
+} SubTreeRootData;
+
+typedef struct {
+     AppTrackerEventType type;
+     AppTrackerEventCB func;
+     void *user_data;
+} EventCallbackData;
+
+#define APP_TRACKER_INVACTIVITY_TIMEOUT 200
+
+static int _init_count;
+static GList *_roots;
+static AtspiEventListener *_listener;
+
+static int
+_is_descendant(AtspiAccessible *ancestor, AtspiAccessible *descendant)
+{
+   return 1;
+
+#if 0
+   do
+     {
+        if (ancestor == descendant) return 1;
+     }
+   while ((descendant = atspi_accessible_get_parent(descendant, NULL)) != NULL);
+
+   return 0;
+#endif
+}
+
+static void
+_subtree_callbacks_call(AppTrackerEventType event, SubTreeRootData *std)
+{
+   GList *l;
+   EventCallbackData *ecd;
+
+   for (l = std->callbacks; l != NULL; l = l->next)
+     {
+        ecd = l->data;
+        if (ecd->type == event)
+          {
+             ecd->func(event, ecd->user_data);
+          }
+     }
+}
+
+static gboolean
+_on_timeout_cb(gpointer user_data)
+{
+   SubTreeRootData *std = user_data;
+
+   _subtree_callbacks_call(APP_TRACKER_EVENT_VIEW_CHANGED, std);
+
+   std->timer = 0;
+
+   return FALSE;
+}
+
+static void 
+_on_atspi_event_cb(const AtspiEvent *event)
+{
+   GList *l;
+   SubTreeRootData *std;
+
+   if (!event || !event->source) return;
+
+   for (l = _roots; l != NULL; l = l->next)
+     {
+        std = l->data;
+        if (_is_descendant(std->root, event->source))
+          {
+             if (std->timer)
+               g_source_remove(std->timer);
+             else
+               _subtree_callbacks_call(APP_TRACKER_EVENT_VIEW_CHANGE_STARTED, std);
+
+             std->timer = g_timeout_add(APP_TRACKER_INVACTIVITY_TIMEOUT, _on_timeout_cb, std);
+          }
+     }
+}
+
+static int
+_app_tracker_init_internal(void)
+{
+   _listener = atspi_event_listener_new_simple(_on_atspi_event_cb, NULL);
+
+   atspi_event_listener_register(_listener, "object:state-changed:showing", NULL);
+   atspi_event_listener_register(_listener, "object:state-changed:visible", NULL);
+   atspi_event_listener_register(_listener, "object:children-changed", NULL);
+   atspi_event_listener_register(_listener, "object:bounds-changed", NULL);
+   atspi_event_listener_register(_listener, "object:visible-data-changed", NULL);
+
+   return 0;
+}
+
+static void
+_free_callbacks(gpointer data)
+{
+   g_free(data);
+}
+
+static void
+_free_rootdata(gpointer data)
+{
+   SubTreeRootData *std = data;
+   g_list_free_full(std->callbacks, _free_callbacks);
+   if (std->timer)
+     g_source_remove(std->timer);
+   g_free(std);
+}
+
+static void
+_app_tracker_shutdown_internal(void)
+{
+   atspi_event_listener_deregister(_listener, "object:state-changed:showing", NULL);
+   atspi_event_listener_deregister(_listener, "object:state-changed:visible", NULL);
+   atspi_event_listener_deregister(_listener, "object:children-changed", NULL);
+   atspi_event_listener_deregister(_listener, "object:bounds-changed", NULL);
+   atspi_event_listener_deregister(_listener, "object:visible-data-changed", NULL);
+
+   g_object_unref(_listener);
+   _listener = NULL;
+
+   g_list_free_full(_roots, _free_rootdata);
+   _roots = NULL;
+}
+
+int app_tracker_init(void)
+{
+   if (!_init_count)
+     if (_app_tracker_init_internal()) return -1;
+   return ++_init_count;
+}
+
+void app_tracker_shutdown(void)
+{
+   if (_init_count == 1)
+     _app_tracker_shutdown_internal();
+   if (--_init_count < 0) _init_count = 0;
+}
+
+void app_tracker_callback_register(AtspiAccessible *app, AppTrackerEventType event, AppTrackerEventCB cb, void *user_data)
+{
+   SubTreeRootData *rd = NULL;
+   EventCallbackData *cd;
+   GList *l;
+
+   if (!_init_count || !cb)
+     return;
+
+   for (l = _roots; l != NULL; l = l->next)
+     {
+        rd = l->data;
+        if (((SubTreeRootData*)l->data)->root == app)
+          {
+             rd = l->data;
+             break;
+          }
+     }
+
+   if (!rd)
+     {
+        rd = g_new(SubTreeRootData, 1);
+        rd->root = app;
+        rd->callbacks = NULL;
+        rd->timer = 0;
+        _roots = g_list_append(_roots, rd);
+     }
+
+   cd = g_new(EventCallbackData, 1);
+   cd->type = event;
+   cd->func = cb;
+   cd->user_data = user_data;
+
+   rd->callbacks = g_list_append(rd->callbacks, cd);
+}
+
+void app_tracker_callback_unregister(AtspiAccessible *app, AppTrackerEventType event, AppTrackerEventCB cb, void *user_data)
+{
+   GList *l;
+   EventCallbackData *ecd;
+   SubTreeRootData *std = NULL;
+
+   for (l = _roots; l != NULL; l = l->next)
+     {
+        if (((SubTreeRootData*)l->data)->root == app)
+          {
+             std = l->data;
+             break;
+          }
+     }
+
+   if (!std) return;
+
+   for (l = std->callbacks; l != NULL; l = l->next)
+     {
+        ecd = l->data;
+        if ((ecd->func == cb) && (ecd->user_data == user_data))
+          {
+             std->callbacks = g_list_delete_link(std->callbacks, l);
+             break;
+          }
+     }
+
+   if (!std->callbacks)
+     {
+        if (std->timer) g_source_remove(std->timer);
+        _roots = g_list_remove(_roots, std);
+        g_free(std);
+     }
+}
diff --git a/src/flat_navi.c b/src/flat_navi.c
new file mode 100644 (file)
index 0000000..48024c1
--- /dev/null
@@ -0,0 +1,374 @@
+#include "flat_navi.h"
+#include "position_sort.h"
+#include "object_cache.h"
+#include "logger.h"
+
+struct _FlatNaviContext {
+     AtspiAccessible *root;
+     Eina_List *current;
+     Eina_List *current_line;
+     Eina_List *lines;
+     Eina_List *candidates;
+};
+
+static const AtspiStateType required_states[] = {
+     ATSPI_STATE_VISIBLE,
+     ATSPI_STATE_SHOWING,
+     ATSPI_STATE_LAST_DEFINED
+};
+
+static const AtspiRole interesting_roles[] = {
+     ATSPI_ROLE_CHECK_BOX,
+     ATSPI_ROLE_COLOR_CHOOSER,
+     ATSPI_ROLE_COMBO_BOX,
+     ATSPI_ROLE_DATE_EDITOR,
+     ATSPI_ROLE_FILE_CHOOSER,
+     ATSPI_ROLE_FONT_CHOOSER,
+     ATSPI_ROLE_HEADER,
+     ATSPI_ROLE_HEADING,
+     ATSPI_ROLE_ICON,
+     ATSPI_ROLE_ENTRY,
+     ATSPI_ROLE_LABEL,
+     ATSPI_ROLE_LIST_ITEM,
+     ATSPI_ROLE_MENU_ITEM,
+     ATSPI_ROLE_PARAGRAPH,
+     ATSPI_ROLE_PASSWORD_TEXT,
+     ATSPI_ROLE_PUSH_BUTTON,
+     ATSPI_ROLE_PROGRESS_BAR,
+     ATSPI_ROLE_RADIO_BUTTON,
+     ATSPI_ROLE_RADIO_MENU_ITEM,
+     ATSPI_ROLE_SLIDER,
+     ATSPI_ROLE_SPIN_BUTTON,
+     ATSPI_ROLE_TABLE_CELL,
+     ATSPI_ROLE_TEXT,
+     ATSPI_ROLE_TOGGLE_BUTTON,
+     ATSPI_ROLE_TOOL_TIP,
+     ATSPI_ROLE_TREE_ITEM,
+     ATSPI_ROLE_LAST_DEFINED
+};
+
+/**
+ * @brief Returns a list of all descendants objects
+ *
+ * @return Eina_List of AtspiAccessible* type. List Should be
+ * be free with _accessible_list_free after usage
+ *
+ * @note obj parameter will also be included (in list head)
+ * @note every obj has increased ref. call g_object_unref on every
+ * object after usage.
+ */
+static Eina_List*
+_descendants_list_get(AtspiAccessible *obj)
+{
+   Eina_List *ret = NULL, *toprocess = NULL;
+   int i;
+
+   if (!obj) return NULL;
+
+   // to keep all refcounts in ret list +1
+   g_object_ref(obj);
+   toprocess = eina_list_append(toprocess, obj);
+
+   while (toprocess)
+     {
+        AtspiAccessible *obj = eina_list_data_get(toprocess);
+        toprocess = eina_list_remove_list(toprocess, toprocess);
+        int n = atspi_accessible_get_child_count(obj, NULL);
+        for (i = 0; i < n; i++)
+          {
+             AtspiAccessible *child = atspi_accessible_get_child_at_index(obj, i, NULL);
+             if (child) toprocess = eina_list_append(toprocess, child);
+          }
+
+        ret = eina_list_append(ret, obj);
+     }
+
+   return ret;
+}
+
+static void
+_accessible_list_free(Eina_List *d)
+{
+   AtspiAccessible *obj;
+
+   EINA_LIST_FREE(d, obj)
+      g_object_unref(obj);
+}
+
+typedef struct {
+     Eina_List *success;
+     Eina_List *failure;
+} FilterResult;
+
+static FilterResult
+_accessible_list_split_with_filter(Eina_List *list, Eina_Each_Cb cb, void *user_data)
+{
+   FilterResult ret = { NULL, NULL};
+   Eina_List *l, *ln;
+   AtspiAccessible *obj;
+
+   EINA_LIST_FOREACH_SAFE(list, l, ln, obj)
+     {
+        Eina_Bool res = cb(NULL, user_data, obj);
+        if (res)
+          eina_list_move_list(&ret.success, &list, l);
+        else
+          eina_list_move_list(&ret.failure, &list, l);
+     }
+
+   return ret;
+}
+
+static Eina_Bool
+_filter_state_cb(const void *container, void *data, void *fdata)
+{
+   AtspiStateType *state = data;
+   Eina_Bool ret = EINA_TRUE;
+   AtspiAccessible *obj = fdata;
+   AtspiStateSet *ss = atspi_accessible_get_state_set(obj);
+
+   while (*state != ATSPI_STATE_LAST_DEFINED)
+     {
+        if (!atspi_state_set_contains(ss, *state))
+          {
+             ret = EINA_FALSE;
+             break;
+          }
+        state++;
+     }
+
+   g_object_unref(ss);
+   return ret;
+}
+
+static Eina_Bool
+_filter_role_cb(const void *container, void *data, void *fdata)
+{
+   AtspiRole *role = data;
+   Eina_Bool ret = EINA_FALSE;
+   AtspiAccessible *obj = fdata;
+
+   while (*role != ATSPI_ROLE_LAST_DEFINED)
+     {
+        if (atspi_accessible_get_role(obj, NULL) == *role)
+          {
+             ret = EINA_TRUE;
+             break;
+          }
+        role++;
+     }
+
+   return ret;
+}
+
+static inline Eina_Bool
+_rectangle_intersect(int x1, int y1, int w1, int h1, int x2, int y2, int w2, int h2)
+{
+   return !(((y1 + h1) <= y2) || (y1 >= (y2 + h2)) || ((x1 + w1) <= x2) || (x1 >= (x2 + w2)));
+}
+
+static Eina_Bool
+_filter_viewport_cb(const void *container, void *data, void *fdata)
+{
+   const ObjectCache *oc, *ocr = data;
+   AtspiAccessible *obj = fdata;
+
+   oc = object_cache_get(obj);
+   if (!oc || !oc->bounds || (oc->bounds->height < 0) || (oc->bounds->width < 0))
+     return EINA_FALSE;
+
+   // at least one pixel of child have to be in viewport
+   return _rectangle_intersect(ocr->bounds->x, ocr->bounds->y, ocr->bounds->width, ocr->bounds->height,
+                               oc->bounds->x, oc->bounds->y, oc->bounds->width, oc->bounds->height);
+}
+
+static Eina_List*
+_flat_review_candidates_get(AtspiAccessible *root)
+{
+   Eina_List *desc, *ret = NULL;
+   FilterResult fr0;
+   
+   desc = _descendants_list_get(root);
+
+   DEBUG("Descendants: %d", eina_list_count(desc));
+
+   // remove object that are not in root's viewport
+   const ObjectCache *oc = object_cache_get(root);
+   if (!oc || !oc->bounds || (oc->bounds->height < 0) || (oc->bounds->width < 0))
+     {
+        ERROR("Invalid root object bounds. Unable to filter descendants by position");
+        fr0.success = desc;
+     }
+   else
+     {
+        fr0 = _accessible_list_split_with_filter(desc, _filter_viewport_cb, (void*)oc);
+        _accessible_list_free(fr0.failure);
+     }
+
+   // remove objects without required states
+   FilterResult fr1 = _accessible_list_split_with_filter(fr0.success, _filter_state_cb, (void*)required_states);
+   _accessible_list_free(fr1.failure);
+
+   // get 'interesting' objects
+   FilterResult fr2 = _accessible_list_split_with_filter(fr1.success, _filter_role_cb, (void*)interesting_roles);
+   ret = eina_list_merge(ret, fr2.success);
+   _accessible_list_free(fr2.failure);
+
+   DEBUG("Candidates: %d", eina_list_count(ret));
+
+   return ret;
+}
+
+static void
+debug(FlatNaviContext *ctx)
+{
+   Eina_List *l1, *l2, *line;
+   AtspiAccessible *obj;
+   int i, l = 0;
+
+   DEBUG("===============================");
+   EINA_LIST_FOREACH(ctx->lines, l1, line)
+     {
+        i = 0;
+        DEBUG("==== Line %d ====", l);
+        EINA_LIST_FOREACH(line, l2, obj)
+          {
+             char *name = atspi_accessible_get_name(obj, NULL);
+             char *role = atspi_accessible_get_role_name(obj, NULL);
+             const ObjectCache *oc = object_cache_get(obj);
+             DEBUG("%d %s %s, (%d %d %d %d)", i++, name, role,
+                   oc->bounds->x, oc->bounds->y, oc->bounds->width, oc->bounds->height);
+             if (name) g_free(name);
+             if (role) g_free(role);
+          }
+        l++;
+     }
+   DEBUG("===============================");
+}
+
+FlatNaviContext *flat_navi_context_create(AtspiAccessible *root)
+{
+   FlatNaviContext *ret;
+
+   ret = calloc(1, sizeof(FlatNaviContext));
+   if (!ret) return NULL;
+
+   ret->root = root;
+   ret->candidates = _flat_review_candidates_get(root);
+   ret->lines = position_sort(ret->candidates); 
+   ret->current_line = ret->lines;
+   ret->current = eina_list_data_get(ret->current_line);
+
+   debug(ret);
+
+   return ret;
+}
+
+void flat_navi_context_free(FlatNaviContext *ctx)
+{
+   Eina_List *l;
+   EINA_LIST_FREE(ctx->lines, l)
+      eina_list_free(l);
+   _accessible_list_free(ctx->candidates);
+   free(ctx);
+}
+
+AtspiAccessible *flat_navi_context_current_get(FlatNaviContext *ctx)
+{
+   return eina_list_data_get(ctx->current);
+}
+
+Eina_Bool flat_navi_context_current_set(FlatNaviContext *ctx, AtspiAccessible *target)
+{
+   Eina_List *l, *l2, *line;
+   AtspiAccessible *obj;
+   Eina_Bool found = EINA_FALSE;
+
+   EINA_LIST_FOREACH(ctx->lines, l, line)
+     {
+        EINA_LIST_FOREACH(line, l2, obj)
+           if (obj == target)
+             {
+                found = EINA_TRUE;
+                break;
+             }
+        if (found)
+          {
+             ctx->current_line = l;
+             ctx->current = l2;
+             break;
+          }
+     }
+
+   return found;
+}
+
+AtspiAccessible *flat_navi_context_next(FlatNaviContext *ctx)
+{
+   Eina_List *new = eina_list_next(ctx->current);
+
+   if (new)
+     ctx->current = new;
+   else
+     return flat_navi_context_line_next(ctx);
+
+   return eina_list_data_get(ctx->current);
+}
+
+AtspiAccessible *flat_navi_context_prev(FlatNaviContext *ctx)
+{
+   Eina_List *new = eina_list_prev(ctx->current);
+
+   if (new)
+     ctx->current = new;
+   else
+     {
+        if (!flat_navi_context_line_prev(ctx))
+          return NULL;
+        ctx->current = eina_list_last(eina_list_data_get(ctx->current_line));
+     }
+
+   return eina_list_data_get(ctx->current);
+}
+
+AtspiAccessible *flat_navi_context_line_next(FlatNaviContext *ctx)
+{
+   Eina_List *new = eina_list_next(ctx->current_line);
+   if (!new) return NULL;
+
+   ctx->current_line = new;
+   ctx->current = eina_list_data_get(ctx->current_line);
+
+   return eina_list_data_get(ctx->current);
+}
+
+AtspiAccessible *flat_navi_context_line_prev(FlatNaviContext *ctx)
+{
+   Eina_List *new = eina_list_prev(ctx->current_line);
+   if (!new) return NULL;
+
+   ctx->current_line = new;
+   ctx->current = eina_list_data_get(ctx->current_line);
+
+   return eina_list_data_get(ctx->current);
+}
+
+AtspiAccessible *flat_navi_context_line_first(FlatNaviContext *ctx)
+{
+   Eina_List *new = ctx->lines;
+
+   ctx->current_line = new;
+   ctx->current = eina_list_data_get(ctx->current_line);
+
+   return eina_list_data_get(ctx->current);
+}
+
+AtspiAccessible *flat_navi_context_line_last(FlatNaviContext *ctx)
+{
+   Eina_List *new = eina_list_last(ctx->current_line);
+
+   ctx->current_line = new;
+   ctx->current = eina_list_data_get(ctx->current_line);
+
+   return eina_list_data_get(ctx->current);
+}
diff --git a/src/gesture_tracker.c b/src/gesture_tracker.c
new file mode 100644 (file)
index 0000000..3d45446
--- /dev/null
@@ -0,0 +1,114 @@
+#include <string.h>
+#include "gesture_tracker.h"
+#include "logger.h"
+
+#define BUS "com.samsung.EModule"
+#define INTERFACE "com.samsung.GestureNavigation"
+#define PATH "/com/samsung/GestureNavigation"
+#define SIGNAL "GestureDetected"
+
+static Eldbus_Connection *a11y_conn;
+static Eldbus_Object *object;
+static Eldbus_Proxy *man;
+static Gesture_Tracker_Cb user_cb;
+static void *user_data;
+
+static Gesture gesture_name_to_enum (const char *gesture_name)
+{
+  if(!gesture_name)
+     return GESTURES_COUNT;
+  DEBUG("Dbus incoming gesture: %s", gesture_name);
+  if(!strcmp("OneFingerHover", gesture_name))
+     return ONE_FINGER_HOVER;
+
+  if(!strcmp("TwoFingersHover", gesture_name))
+     return TWO_FINGERS_HOVER;
+
+  if(!strcmp("OneFingerFlickLeft", gesture_name))
+     return ONE_FINGER_FLICK_LEFT;
+
+  if(!strcmp("OneFingerFlickRight", gesture_name))
+     return ONE_FINGER_FLICK_RIGHT;
+
+  if(!strcmp("OneFingerFlickUp", gesture_name))
+     return ONE_FINGER_FLICK_UP;
+
+  if(!strcmp("OneFingerFlickDown", gesture_name))
+     return ONE_FINGER_FLICK_DOWN;
+
+ if(!strcmp("ThreeFingersFlickLeft", gesture_name))
+     return THREE_FINGERS_FLICK_LEFT;
+
+ if(!strcmp("ThreeFingersFlickRight", gesture_name))
+     return THREE_FINGERS_FLICK_RIGHT;
+
+ if(!strcmp("ThreeFingersFlickUp", gesture_name))
+     return THREE_FINGERS_FLICK_UP;
+
+ if(!strcmp("ThreeFingersFlickDown", gesture_name))
+     return THREE_FINGERS_FLICK_DOWN;
+
+ if(!strcmp("OneFingerSingleTap", gesture_name))
+     return ONE_FINGER_SINGLE_TAP;
+
+ if(!strcmp("OneFingerDoubleTap", gesture_name))
+     return ONE_FINGER_DOUBLE_TAP;
+
+ if(!strcmp("TwoFingersFlickLeft", gesture_name))
+    return TWO_FINGERS_FLICK_LEFT;
+
+ if(!strcmp("TwoFingersFlickRight", gesture_name))
+    return TWO_FINGERS_FLICK_RIGHT;
+
+ if(!strcmp("TwoFingersFlickUp", gesture_name))
+    return TWO_FINGERS_FLICK_UP;
+
+ if(!strcmp("TwoFingersFlickDown", gesture_name))
+     return TWO_FINGERS_FLICK_DOWN;
+
+ return GESTURES_COUNT;
+}
+
+static void on_gesture_detected(void *context EINA_UNUSED, const Eldbus_Message *msg)
+{
+    const char *gesture_name;
+    int x_s, y_s, x_e, y_e, state;
+
+    if(!eldbus_message_arguments_get(msg, "siiiiu", &gesture_name, &x_s, &y_s, &x_e, &y_e, &state))
+        ERROR("error geting arguments on_gesture_detected");
+
+    Gesture_Info g;
+    g.type = gesture_name_to_enum(gesture_name);
+    g.x_begin = x_s;
+    g.y_begin = y_s;
+    g.x_end = x_e;
+    g.y_end = y_e;
+    g.state = state;
+
+    if(user_cb)
+        user_cb(user_data, &g);
+}
+
+void gesture_tracker_init(Eldbus_Connection *conn)
+{
+    a11y_conn = conn;
+    eldbus_connection_ref(conn);
+    object = eldbus_object_get(conn, BUS, PATH);
+    man = eldbus_proxy_get(object, INTERFACE);
+    eldbus_proxy_signal_handler_add(man, SIGNAL, on_gesture_detected, NULL);
+}
+
+void gesture_tracker_register(Gesture_Tracker_Cb cb, void *data)
+{
+   user_cb = cb;
+   user_data = data;
+}
+
+void gesture_tracker_shutdown(void)
+{
+    eldbus_proxy_unref(man);
+    eldbus_object_unref(object);
+    eldbus_connection_unref(a11y_conn);
+}
diff --git a/src/keyboard_tracker.c b/src/keyboard_tracker.c
new file mode 100644 (file)
index 0000000..190ecd9
--- /dev/null
@@ -0,0 +1,63 @@
+#include <string.h>
+#include <atspi/atspi.h>
+#include "keyboard_tracker.h"
+#include "logger.h"
+#include <Ecore.h>
+
+static Ecore_Thread *thread;
+static AtspiDeviceListener *listener;
+static Keyboard_Tracker_Cb user_cb;
+static void *user_data;
+
+static gboolean device_cb(const AtspiDeviceEvent *stroke, void *data)
+{
+  Key k;
+  if (!strcmp(stroke->event_string, "KP_Up"))
+      k = KEY_UP;
+  else if (!strcmp(stroke->event_string, "KP_Down"))
+      k = KEY_DOWN;
+  else if (!strcmp(stroke->event_string, "KP_Left"))
+      k = KEY_LEFT;
+  else if (!strcmp(stroke->event_string, "KP_Right"))
+      k = KEY_RIGHT;
+  else
+      return FALSE;
+
+    if(user_cb)
+         user_cb(user_data, k);
+
+   return TRUE;
+}
+
+void blocking(void *list, Ecore_Thread *th)
+{
+   atspi_event_main();
+}
+
+void cancel(void *list, Ecore_Thread *th)
+{
+   atspi_event_quit();
+}
+
+void keyboard_tracker_init(void)
+{
+   atspi_init();
+   listener =  atspi_device_listener_new(device_cb, NULL, NULL);
+   atspi_register_keystroke_listener(listener, NULL, 0, ATSPI_KEY_PRESSED, ATSPI_KEYLISTENER_SYNCHRONOUS|ATSPI_KEYLISTENER_CANCONSUME, NULL);
+
+   ecore_init();
+   thread = ecore_thread_run(blocking, NULL, cancel, NULL);
+   ERROR("keyboard tracker init");
+}
+
+void keyboard_tracker_register(Keyboard_Tracker_Cb cb, void *data)
+{
+   user_cb = cb;
+   user_data = data;
+}
+
+void keyboard_tracker_shutdown(void)
+{
+   ecore_thread_cancel(thread);
+   ERROR("keyboard tracker shutdown");
+}
diff --git a/src/logger.c b/src/logger.c
new file mode 100644 (file)
index 0000000..4e84bad
--- /dev/null
@@ -0,0 +1,25 @@
+#include "logger.h"
+
+int logger_init(void)
+{
+   if (!_eina_log_dom)
+     {
+        _eina_log_dom = eina_log_domain_register("smart-navigator", NULL);
+        if (_eina_log_dom  < 0)
+          {
+             fprintf(stderr, "Unable to register smart-navogator log domain");
+             return -1;
+          }
+     }
+   return 0;
+}
+
+void logger_shutdown(void)
+{
+   if (_eina_log_dom)
+     {
+        eina_log_domain_unregister(_eina_log_dom);
+        _eina_log_dom = 0;
+     }
+}
+
diff --git a/src/main.c b/src/main.c
new file mode 100755 (executable)
index 0000000..7047a92
--- /dev/null
@@ -0,0 +1,72 @@
+#include <appcore-efl.h>
+#include <eldbus-1/Eldbus.h>
+#include "navigator.h"
+#include "window_tracker.h"
+#include "gesture_tracker.h"
+#include "logger.h"
+#include "screen_reader.h"
+
+#define A11Y_BUS "org.a11y.Bus"
+#define A11Y_INTERFACE "org.a11y.Bus"
+#define A11Y_PATH "/org/a11y/bus"
+#define A11Y_GET_ADDRESS "GetAddress"
+
+Eldbus_Connection *a11y_conn;
+
+static void _init_modules(void *data, const Eldbus_Message *msg, Eldbus_Pending *pending EINA_UNUSED)
+{
+   const char *a11y_bus_address = NULL;
+
+   logger_init();
+   if(!eldbus_message_arguments_get(msg, "s", &a11y_bus_address))
+      ERROR("error geting arguments _init_modules");
+   Eldbus_Connection *a11y_conn = eldbus_address_connection_get(a11y_bus_address);
+   
+   gesture_tracker_init(a11y_conn);
+   navigator_init();
+}
+
+static int app_create(void *data)
+{
+    eldbus_init();
+
+    Eldbus_Connection *session_conn = eldbus_connection_get(ELDBUS_CONNECTION_TYPE_SESSION);
+    Eldbus_Object *a11y_obj = eldbus_object_get(session_conn, A11Y_BUS, A11Y_PATH);
+    Eldbus_Proxy *manager = eldbus_proxy_get(a11y_obj, A11Y_INTERFACE);
+    eldbus_proxy_call(manager, A11Y_GET_ADDRESS, _init_modules, data, -1, "");
+
+    screen_reader_create_service(data);
+
+    return 0;
+}
+
+static int app_terminate(void *data)
+{
+
+    screen_reader_terminate_service(data);
+
+    eldbus_connection_unref(a11y_conn);
+    gesture_tracker_shutdown();
+    navigator_shutdown();
+    eldbus_shutdown();
+    logger_shutdown();
+    return 0;
+}
+
+int main(int argc, char **argv)
+{
+    printf("Application Main Function \n");
+    
+    struct appcore_ops ops =
+    {
+        .create = app_create,
+        .terminate = app_terminate,
+        .pause = NULL,
+        .resume = NULL,
+        .reset = NULL
+    };
+
+    ops.data = get_pointer_to_service_data_struct();
+
+    return appcore_efl_main("Smart Navigation", &argc, &argv, &ops);
+}
diff --git a/src/navigator.c b/src/navigator.c
new file mode 100644 (file)
index 0000000..4b82100
--- /dev/null
@@ -0,0 +1,827 @@
+#include <Ecore_X.h>
+#include <Ecore.h>
+#include <math.h>
+#include "logger.h"
+#include "navigator.h"
+#include "gesture_tracker.h"
+#include "window_tracker.h"
+#include "keyboard_tracker.h"
+#include "pivot_chooser.h"
+#include "structural_navi.h"
+#include "object_cache.h"
+#include "flat_navi.h"
+#include "app_tracker.h"
+
+#define QUICKPANEL_DOWN TRUE
+#define QUICKPANEL_UP FALSE
+
+#define DISTANCE_NB 8
+
+#define DEBUG_MODE
+
+#define GERROR_CHECK(error)\
+  if (error)\
+   {\
+     ERROR("Error_log:%s",error->message);\
+     g_error_free(error);\
+   }
+
+static AtspiAccessible *current_obj;
+static AtspiAccessible *top_window;
+static AtspiScrollable *scrolled_obj;
+static Eina_Bool _window_cache_builded;
+static FlatNaviContext *context;
+
+static void
+_current_highlight_object_set(AtspiAccessible *obj)
+{
+   GError *err = NULL;
+   if (!obj)
+     {
+        DEBUG("Clearing highligjt object");
+        current_obj = NULL;
+        return;
+     }
+   if (current_obj == obj)
+     {
+        DEBUG("Object already highlighted");
+        return;
+     }
+    if (obj && ATSPI_IS_COMPONENT(obj))
+      {
+         AtspiComponent *comp = atspi_accessible_get_component(obj);
+         if (!comp)
+           {
+             ERROR("AtspiComponent *comp NULL");
+             return;
+           }
+         atspi_component_grab_highlight(comp, &err);
+         GERROR_CHECK(err)
+         gchar *name;
+         gchar *role;
+
+
+         current_obj = obj;
+         const ObjectCache *oc = object_cache_get(obj);
+
+         if (oc) {
+             name = atspi_accessible_get_name(obj, &err);
+             GERROR_CHECK(err)
+             role = atspi_accessible_get_role_name(obj, &err);
+             GERROR_CHECK(err)
+             DEBUG("New highlighted object: %s, role: %s, (%d %d %d %d)",
+               role,
+               name,
+               oc->bounds->x, oc->bounds->y, oc->bounds->width, oc->bounds->height);
+         }
+         else {
+           name = atspi_accessible_get_name(obj, &err);
+           GERROR_CHECK(err)
+           role = atspi_accessible_get_role_name(obj, &err);
+           GERROR_CHECK(err)
+           DEBUG("New highlighted object: %s, role: %s",
+               name,
+               role
+               );
+               }
+         g_free(role);
+         g_free(name);
+      }
+    else
+       DEBUG("Unable to highlight object");
+}
+
+void test_debug(AtspiAccessible *current_widget)
+{
+    int jdx;
+    int count_child;
+    gchar *role;
+    GError *err = NULL;
+    AtspiAccessible *child_iter = NULL;
+    AtspiAccessible *parent = atspi_accessible_get_parent(current_widget, &err);
+    GERROR_CHECK(err)
+
+    if(!parent)
+      return;
+    count_child = atspi_accessible_get_child_count(parent, &err);
+    GERROR_CHECK(err)
+    DEBUG("Total childs in parent: %d\n", count_child);
+    if(!count_child)
+        return;
+
+    for(jdx = 0; jdx < count_child; jdx++)
+    {
+        child_iter = atspi_accessible_get_child_at_index(parent, jdx, &err);
+        GERROR_CHECK(err)
+
+        if(current_widget == child_iter)
+          {
+            role = atspi_accessible_get_role_name(parent, &err);
+            DEBUG("Childen found in parent: %s at index: %d\n", role, jdx);
+          }
+        else
+          {
+            role = atspi_accessible_get_role_name(parent, &err);
+            DEBUG("Childen not found in parent: %s at index: %d\n", role, jdx);
+          }
+        g_free(role);
+        GERROR_CHECK(err)
+    }
+}
+
+#if 0
+static void object_get_x_y(AtspiAccessible * accessibleObject, int* x, int* y)
+{
+    GError * error = NULL;
+
+   if ( ATSPI_IS_COMPONENT(accessibleObject) )
+   {
+       AtspiComponent * component = ATSPI_COMPONENT(accessibleObject);
+       AtspiPoint *position = atspi_component_get_position (component, ATSPI_COORD_TYPE_SCREEN, &error);
+       if ( error != NULL )
+       {
+           g_error_free(error);
+       }
+       if ( position != NULL )
+       {
+           *x = position->x;
+           *y = position->y;
+           g_free ( position );
+       }
+   }
+}
+
+static void object_get_wh(AtspiAccessible * accessibleObject, int* width, int* height)
+{
+    GError * error = NULL;
+
+   if ( ATSPI_IS_COMPONENT(accessibleObject) )
+   {
+       AtspiComponent * component = ATSPI_COMPONENT(accessibleObject);
+       AtspiPoint * size = atspi_component_get_size (component, &error);
+       if ( error != NULL )
+       {
+           g_error_free(error);
+       }
+       if ( size != NULL )
+       {
+           *width = size->x;
+           *height = size->y;
+           g_free ( size );
+       }
+   }
+}
+
+static void find_objects(AtspiAccessible* parent, gint x, gint y, gint radius, double* distance, AtspiAccessible **find_app)
+{
+    AtspiAccessible* app = NULL;
+    GError* err = NULL;
+    int jdx, kdx;
+
+    int count_child = atspi_accessible_get_child_count(parent, &err);
+
+    for(jdx = 0; jdx < count_child; jdx++)
+    {
+        app = atspi_accessible_get_child_at_index(parent, jdx, &err);
+
+        AtspiStateSet* state_set = atspi_accessible_get_state_set (app);
+        AtspiStateType state =  ATSPI_STATE_VISIBLE;
+
+        int height = 0, width = 0, xpos1 = 0, ypos1 = 0, xpos2 = 0, ypos2 = 0;
+
+        object_get_wh(app, &width, &height); object_get_x_y(app, &xpos1, &ypos1);
+
+        gboolean is_visile = atspi_state_set_contains(state_set, state);
+
+        if(is_visile == TRUE && width > 0 && height > 0)
+        {
+            xpos2 = xpos1 + width;
+            ypos2 = ypos1 + height;
+
+            double set_distance[DISTANCE_NB] = {0};
+            double min_distance = DBL_MAX;
+
+            set_distance[0] = pow((x - xpos1), 2) + pow((y - ypos1), 2);
+            set_distance[1] = pow((x - xpos2), 2) + pow((y - ypos1), 2);
+            set_distance[2] = pow((x - xpos1), 2) + pow((y - ypos2), 2);
+            set_distance[3] = pow((x - xpos2), 2) + pow((y - ypos2), 2);
+            set_distance[4] = DBL_MAX;
+            set_distance[5] = DBL_MAX;
+            set_distance[6] = DBL_MAX;
+            set_distance[7] = DBL_MAX;
+
+            if(x >= fmin(xpos1, xpos2) && x <= fmax(xpos1, xpos2))
+            {
+                set_distance[4] = pow((y - ypos1), 2);
+                set_distance[5] = pow((y - ypos2), 2);
+            }
+
+            if(y >= fmin(ypos1, ypos2) && y <= fmax(ypos1, ypos2))
+            {
+                set_distance[6] = pow((x - xpos1), 2);
+                set_distance[7] = pow((x - xpos2), 2);
+            }
+
+            for(kdx = 0; kdx < DISTANCE_NB; kdx++)
+            {
+                if(set_distance[kdx] < min_distance)
+                    min_distance = set_distance[kdx];
+            }
+
+            if(min_distance <= *distance && (radius < 0 || (radius >= 0 && min_distance <= radius)))
+            {
+                *distance = min_distance;
+                *find_app = app;
+            }
+            find_objects(app, x, y, radius, distance, find_app);
+        }
+    }
+}
+
+static AtspiAccessible *get_nearest_widget(AtspiAccessible* app_obj, gint x_cord, gint y_cord, gint radius)
+{
+    int xn = 0, yn = 0;
+    GError *err = NULL;
+    AtspiAccessible* f_app_obj = app_obj;
+    double distance = DBL_MAX;
+    int jdx = 0;
+
+    int count_child = atspi_accessible_get_child_count(app_obj, &err);
+
+    find_objects(app_obj, x_cord, y_cord, radius, &distance, &f_app_obj);
+
+    return f_app_obj;
+}
+#endif
+
+static void _focus_widget(Gesture_Info *info)
+{
+    AtspiAccessible *target_widget;
+    AtspiComponent *window_component;
+    GError *err = NULL;
+
+    window_component = atspi_accessible_get_component(top_window);
+    if(!window_component)
+        return;
+
+    target_widget = atspi_component_get_accessible_at_point(window_component, info->x_begin, info->y_begin, ATSPI_COORD_TYPE_WINDOW, &err);
+    GERROR_CHECK(err)
+    if (target_widget) {
+         _current_highlight_object_set(target_widget);
+         if (!flat_navi_context_current_set(context, target_widget))
+           ERROR("Hoveed object not found in window context");
+    }
+    else
+      DEBUG("NO widget under (%d, %d) found",
+            info->x_begin, info->y_begin);
+}
+
+static void _focus_next(void)
+{
+   if (!context)
+     {
+        ERROR("No navigation context created");
+        return;
+     }
+   AtspiAccessible *obj = flat_navi_context_next(context);
+   if (obj)
+     _current_highlight_object_set(obj);
+   else
+     DEBUG("Next widget not found. Abort");
+}
+
+static void _focus_prev(void)
+{
+   if (!context)
+     {
+        ERROR("No navigation context created");
+        return;
+     }
+   AtspiAccessible *obj = flat_navi_context_prev(context);
+   if (obj)
+     _current_highlight_object_set(obj);
+   else
+     DEBUG("Previous widget not found. Abort");
+}
+
+static void _value_inc_widget(void)
+{
+    AtspiAccessible* current_widget = NULL;
+    AtspiText *text_interface;
+    gint current_offset;
+    gboolean ret;
+    GError *err = NULL;
+    gchar *role;
+
+    if(!current_obj)
+      return;
+
+    current_widget = current_obj;
+
+    role = atspi_accessible_get_role_name(current_widget, &err);
+    GERROR_CHECK(err)
+    if(!strcmp(role, "entry"))
+    {
+        text_interface = atspi_accessible_get_text(current_widget);
+        if(text_interface)
+        {
+            current_offset = atspi_text_get_caret_offset(text_interface, &err);
+            GERROR_CHECK(err)
+            ret = atspi_text_set_caret_offset(text_interface, current_offset + 1, &err);
+            GERROR_CHECK(err)
+            if(ret)
+            {
+                ERROR("Caret position increment done");
+            }
+            else
+            {
+                ERROR("Caret position increment error");
+            }
+        }
+        else
+            ERROR("No text interface supported!");
+        g_free(role);
+        return;
+    }
+    g_free(role);
+    AtspiValue *value_interface = atspi_accessible_get_value(current_widget);
+    if(value_interface)
+    {
+        ERROR("Value interface supported!\n");
+        gdouble current_val = atspi_value_get_current_value(value_interface, &err);
+        GERROR_CHECK(err)
+        ERROR("Current value: %f\n ", (double)current_val);
+        gdouble minimum_inc = atspi_value_get_minimum_increment(value_interface, &err);
+        ERROR("Minimum increment: %f\n ", (double)minimum_inc);
+        GERROR_CHECK(err)
+        atspi_value_set_current_value(value_interface, current_val + minimum_inc, &err);
+        GERROR_CHECK(err)
+    }
+    else
+        ERROR("No value interface supported!\n");
+}
+
+static void _value_dec_widget(void)
+{
+    AtspiAccessible* current_widget = NULL;
+    AtspiText *text_interface;
+    gint current_offset;
+    GError *err = NULL;
+    gboolean ret;
+    gchar *role;
+
+    if(!current_obj)
+      return;
+    current_widget = current_obj;
+
+    role = atspi_accessible_get_role_name(current_widget, &err);
+    GERROR_CHECK(err)
+    if(!strcmp(role, "entry"))
+    {
+        text_interface = atspi_accessible_get_text(current_widget);
+        if(text_interface)
+        {
+            current_offset = atspi_text_get_caret_offset(text_interface, &err);
+            GERROR_CHECK(err)
+            ret = atspi_text_set_caret_offset(text_interface, current_offset - 1, &err);
+            GERROR_CHECK(err)
+            if(ret)
+            {
+                ERROR("Caret position decrement done");
+            }
+            else
+            {
+                ERROR("Caret position decrement error");
+            }
+        }
+        else
+            ERROR("No text interface supported!");
+        g_free(role);
+        return;
+    }
+    g_free(role);
+
+    AtspiValue *value_interface = atspi_accessible_get_value(current_widget);
+    if(value_interface)
+    {
+        ERROR("Value interface supported!\n");
+        gdouble current_val = atspi_value_get_current_value(value_interface, &err);
+        GERROR_CHECK(err)
+        ERROR("Current value: %f\n ", (double)current_val);
+        gdouble minimum_inc = atspi_value_get_minimum_increment(value_interface, &err);
+        GERROR_CHECK(err)
+        ERROR("Minimum increment: %f\n ", (double)minimum_inc);
+        atspi_value_set_current_value(value_interface, current_val - minimum_inc, &err);
+        GERROR_CHECK(err)
+    }
+    else
+        ERROR("No value interface supported!\n");
+}
+
+static void _activate_widget(void)
+{
+    //activate the widget
+    //only if activate mean click
+    //special behavior for entry, caret should move from first/last last/first
+
+    AtspiAccessible *current_widget = NULL;
+    AtspiComponent *focus_component;
+    GError *err = NULL;
+
+    if(!current_obj)
+      return;
+
+    current_widget = current_obj;
+
+    gchar *roleName;
+    gchar *actionName;
+    roleName = atspi_accessible_get_role_name(current_widget, &err);
+    GERROR_CHECK(err)
+    ERROR("Widget role prev: %s\n", roleName);
+
+    if(!strcmp(roleName, "entry"))
+    {
+        focus_component = atspi_accessible_get_component(current_widget);
+        if (focus_component != NULL)
+        {
+            if (atspi_component_grab_focus(focus_component, &err) == TRUE)
+              {
+                ERROR("Entry activated\n");
+                GERROR_CHECK(err)
+              }
+            g_free(roleName);
+            return;
+        }
+    }
+    g_free(roleName);
+
+    AtspiAction *action;
+    gint number;
+    int i;
+    int k;
+
+    action = atspi_accessible_get_action(current_widget);
+
+    if(!action)
+      {
+        ERROR("Action null");
+        return;
+      }
+    number = atspi_action_get_n_actions(action, &err);
+    ERROR("Number of available action = %d\n", number);
+    GERROR_CHECK(err)
+        GArray *array = atspi_accessible_get_interfaces(current_widget);
+        ERROR("TAB LEN = %d \n", array->len);
+
+        for (k=0; k < array->len; k++)
+            ERROR("Interface = %s\n", g_array_index( array, gchar *, k ));
+
+        for (i=0; i<number; i++)
+        {
+            actionName = atspi_action_get_name(action, i, &err);
+            ERROR("Action name = %s\n", actionName);
+            GERROR_CHECK(err)
+
+            if (actionName && !strcmp("click", actionName))
+            {
+                atspi_action_do_action(action, 0, &err);
+                GERROR_CHECK(err)
+                #ifdef DEBUG_MODE
+                    test_debug(current_widget);
+                #endif
+            }
+        }
+
+}
+
+static void _quickpanel_change_state(gboolean quickpanel_switch)
+{
+    Ecore_X_Window xwin = 0;
+
+    ERROR(quickpanel_switch ? "QUICKPANEL STATE ON" : "QUICKPANEL STATE OFF");
+
+    Ecore_X_Illume_Quickpanel_State state;
+
+
+
+    ecore_x_window_prop_xid_get(ecore_x_window_root_first_get(),
+                                     ECORE_X_ATOM_NET_ACTIVE_WINDOW,
+                                     ECORE_X_ATOM_WINDOW,
+                                     &xwin, 1);
+
+    state = quickpanel_switch ? ECORE_X_ILLUME_QUICKPANEL_STATE_ON : ECORE_X_ILLUME_QUICKPANEL_STATE_OFF;
+
+    ecore_x_e_illume_quickpanel_state_set(xwin, state);
+
+    ecore_x_e_illume_quickpanel_state_send(ecore_x_e_illume_zone_get(xwin), state);
+
+    ecore_main_loop_iterate();
+}
+
+/**
+ * @brief Gets 'deepest' Scrollable accessible containing (x,y) point
+ */
+static AtspiScrollable*
+_find_scrollable_ancestor_at_xy(int x, int y)
+{
+   AtspiAccessible *ret = NULL;
+   AtspiRect *rect;
+   GError *err = NULL;
+
+   if (!top_window || !ATSPI_IS_COMPONENT(top_window))
+     {
+        DEBUG("No active window detected or no AtspiComponent interface available");
+        return NULL;
+     }
+
+   rect = atspi_component_get_extents(ATSPI_COMPONENT(top_window), ATSPI_COORD_TYPE_SCREEN, &err);
+   GERROR_CHECK(err)
+   if (!rect)
+     {
+        ERROR("Unable to fetch window screen coordinates");
+        return NULL;
+     }
+
+   // Scroll must originate within window borders
+   if ((x < rect->x) || (x > rect->x + rect->width) ||
+       (y < rect->y) || (y > rect->y + rect->height))
+     {
+        DEBUG("Scroll don't start within active window borders");
+        g_free(rect);
+        return NULL;
+     }
+
+   ret = atspi_component_get_accessible_at_point(ATSPI_COMPONENT(top_window), x, y, ATSPI_COORD_TYPE_SCREEN, &err);
+   GERROR_CHECK(err)
+   if (!ret)
+     {
+        ERROR("Unable to get accessible objct at (%d, %d) screen coordinates.", x, y);
+        return NULL;
+     }
+gchar *name;
+gchar *role;
+   // find accessible object with Scrollable interface
+   while (ret && (ret != top_window))
+     {
+       name = atspi_accessible_get_name(ret, &err);
+       GERROR_CHECK(err)
+       role = atspi_accessible_get_role_name(ret, &err);
+       GERROR_CHECK(err)
+       DEBUG("Testing for scrollability: %s %s",
+                   name, role);
+        if (atspi_accessible_get_scrollable(ret))
+          {
+             DEBUG("Scrollable widget found at (%d, %d), name: %s, role: %s", x, y,
+                   name ,role);
+             g_free(name);
+             g_free(role);
+             return ATSPI_SCROLLABLE(ret);
+          }
+        g_free(name);
+        g_free(role);
+        ret = atspi_accessible_get_parent(ret, &err);
+        if (err)
+          {
+             ERROR("Unable to fetch AT-SPI parent");
+             GERROR_CHECK(err)
+             return NULL;
+          }
+     }
+
+   return NULL;
+}
+
+static void _widget_scroll_begin(Gesture_Info *gi)
+{
+   GError *err = NULL;
+
+   if (scrolled_obj)
+     {
+        ERROR("Scrolling context active when initializing new scrolling context! This should never happen.");
+        ERROR("Force reset of current scrolling context...");
+        atspi_scrollable_scroll_after_pointer(scrolled_obj, ATSPI_SCROLL_POINTER_END, gi->x_begin, gi->y_begin, &err);
+        if (err)
+          {
+             ERROR("Failed to reset scroll context.");
+             GERROR_CHECK(err)
+             scrolled_obj = NULL;
+          }
+     }
+
+   scrolled_obj = _find_scrollable_ancestor_at_xy(gi->x_begin, gi->y_begin);
+
+   if (!scrolled_obj)
+     {
+        DEBUG("No scrollable widget found at (%d, %d) coordinates", gi->x_begin, gi->y_begin);
+        return;
+     }
+
+   atspi_scrollable_scroll_after_pointer(scrolled_obj, ATSPI_SCROLL_POINTER_START, gi->x_begin, gi->y_begin, &err);
+   if (err)
+     {
+        ERROR("Failed to initialize scroll operation");
+        GERROR_CHECK(err)
+        scrolled_obj = NULL;
+     }
+}
+
+static void _widget_scroll_continue(Gesture_Info *gi)
+{
+  GError *err = NULL;
+   if (!scrolled_obj)
+     {
+        DEBUG("Scrolling context not initialized!");
+        return;
+     }
+   atspi_scrollable_scroll_after_pointer(scrolled_obj, ATSPI_SCROLL_POINTER_CONTINUE, gi->x_begin, gi->y_begin, &err);
+   GERROR_CHECK(err)
+}
+
+static void _widget_scroll_end(Gesture_Info *gi)
+{
+  GError *err = NULL;
+   if (!scrolled_obj)
+     {
+        ERROR("Scrolling context not initialized!");
+        return;
+     }
+
+   atspi_scrollable_scroll_after_pointer(scrolled_obj, ATSPI_SCROLL_POINTER_END, gi->x_begin, gi->y_begin, &err);
+   scrolled_obj = NULL;
+   GERROR_CHECK(err)
+}
+
+#if 0
+// part of structural navigation
+static void _goto_children_widget(void)
+{
+   AtspiAccessible *obj;
+   if (!current_obj)
+     {
+        DEBUG("No current object is set. Aborting diving into children structure");
+        return;
+     }
+   obj = structural_navi_level_down(current_obj);
+   if (obj)
+     _current_highlight_object_set(obj);
+   else
+     DEBUG("Unable to find hihglightable children widget");
+}
+
+static void _escape_children_widget(void)
+{
+   AtspiAccessible *obj;
+   if (!current_obj)
+     {
+        DEBUG("No current object is set. Aborting escaping from children structure");
+        return;
+     }
+   obj = structural_navi_level_up(current_obj);
+   if (obj)
+     _current_highlight_object_set(obj);
+   else
+     DEBUG("Unable to find hihglightable parent widget");
+}
+#endif
+
+static void _widget_scroll(Gesture_Info *gi)
+{
+   switch (gi->state)
+     {
+      case 0:
+         _widget_scroll_begin(gi);
+         break;
+      case 1:
+         _widget_scroll_continue(gi);
+         break;
+      case 2:
+         _widget_scroll_end(gi);
+         break;
+      default:
+         ERROR("Unrecognized gesture state: %d", gi->state);
+     }
+}
+
+static void on_gesture_detected(void *data, Gesture_Info *info)
+{
+   switch(info->type)
+   {
+      case ONE_FINGER_HOVER:
+          _focus_widget(info);
+          break;
+      case TWO_FINGERS_HOVER:
+          _widget_scroll(info);
+          break;
+      case ONE_FINGER_FLICK_LEFT:
+          _focus_prev();
+          break;
+      case ONE_FINGER_FLICK_RIGHT:
+          _focus_next();
+          break;
+      case ONE_FINGER_FLICK_UP:
+          _value_inc_widget();
+          break;
+      case ONE_FINGER_FLICK_DOWN:
+          _value_dec_widget();
+          break;
+      case ONE_FINGER_SINGLE_TAP:
+          _focus_widget(info);
+          break;
+      case ONE_FINGER_DOUBLE_TAP:
+          _activate_widget();
+          break;
+      case THREE_FINGERS_FLICK_DOWN:
+          _quickpanel_change_state(QUICKPANEL_DOWN);
+          break;
+      case THREE_FINGERS_FLICK_UP:
+          _quickpanel_change_state(QUICKPANEL_UP);
+          break;
+      default:
+          DEBUG("Gesture type %d not handled in switch", info->type);
+   }
+}
+
+static void
+_on_cache_builded(void *data)
+{
+   DEBUG("Cache builded");
+   _window_cache_builded = EINA_TRUE;
+   AtspiAccessible *pivot = NULL;
+   if (context)
+     {
+        pivot = flat_navi_context_current_get(context);
+        flat_navi_context_free(context);
+     }
+   context = flat_navi_context_create(top_window);
+
+   // try to set previous object in new context
+   if (flat_navi_context_current_set(context, pivot))
+     _current_highlight_object_set(pivot);
+   else
+     _current_highlight_object_set(flat_navi_context_current_get(context));
+}
+
+static void
+_view_content_changed(AppTrackerEventType type, void *user_data)
+{
+   DEBUG("View content changed");
+   _window_cache_builded = EINA_FALSE;
+   if (top_window)
+      object_cache_build_async(top_window, 5, _on_cache_builded, NULL);
+}
+
+static void on_window_activate(void *data, AtspiAccessible *window)
+{
+      ERROR("... on window activate ...");
+
+      _current_highlight_object_set(NULL);
+
+      app_tracker_callback_unregister(top_window, APP_TRACKER_EVENT_VIEW_CHANGED, _view_content_changed, NULL);
+
+      if(window)
+      {
+         app_tracker_callback_register(window, APP_TRACKER_EVENT_VIEW_CHANGED, _view_content_changed, NULL);
+         ERROR("Window name: %s", atspi_accessible_get_name(window, NULL));
+         _window_cache_builded = EINA_FALSE;
+         object_cache_build_async(window, 5, _on_cache_builded, NULL);
+      }
+      else
+      {
+          ERROR("No top window found!");
+          scrolled_obj = NULL;
+      }
+      top_window = window;
+}
+
+void navigator_init(void)
+{
+   // register on gesture_getected
+   gesture_tracker_register(on_gesture_detected, NULL);
+   // register on active_window
+   window_tracker_init();
+   window_tracker_register(on_window_activate, NULL);
+   window_tracker_active_window_request();
+   app_tracker_init();
+}
+
+void navigator_shutdown(void)
+{
+  GError *err = NULL;
+   if (current_obj)
+     {
+       AtspiComponent *comp = atspi_accessible_get_component(current_obj);
+       if (comp)
+         {
+           atspi_component_clear_highlight(comp, &err);
+           GERROR_CHECK(err);
+         }
+     }
+   if (context)
+     {
+        flat_navi_context_free(context);
+        context = NULL;
+     }
+   object_cache_shutdown();
+   app_tracker_shutdown();
+   window_tracker_shutdown();
+}
diff --git a/src/object_cache.c b/src/object_cache.c
new file mode 100644 (file)
index 0000000..d88ca91
--- /dev/null
@@ -0,0 +1,226 @@
+#include <Eina.h>
+#include <Ecore.h>
+
+#include "object_cache.h"
+#include "logger.h"
+
+static Eina_Hash *cache;
+static Ecore_Idler *idler;
+static Eina_List *toprocess;
+static void *user_data;
+static ObjectCacheReadyCb callback;
+static int bulk;
+
+static void
+_cache_item_free_cb(void *data)
+{
+   ObjectCache *co = data;
+   g_free(co->bounds);
+   free(co);
+}
+
+static void
+_list_obj_unref_and_free(Eina_List *toprocess)
+{
+   AtspiAccessible *obj;
+   EINA_LIST_FREE(toprocess, obj)
+      g_object_unref(obj);
+}
+
+static void
+_object_cache_free_internal(void)
+{
+   if (idler)
+     {
+        ecore_idler_del(idler);
+        idler = NULL;
+     }
+   if (toprocess)
+     {
+        _list_obj_unref_and_free(toprocess);
+        toprocess = NULL;
+     }
+   if (cache)
+     {
+        eina_hash_free(cache);
+        cache = NULL;
+     }
+}
+
+/**
+ * Returnes a list of all accessible object implementing AtkCompoment interface
+ * Eina_List should be free with eina_list_free function.
+ * Every AtspiAccessible in list should be unrefed with g_object_unref.
+ */
+static Eina_List*
+_cache_candidates_list_prepare(AtspiAccessible *root)
+{
+   Eina_List *toprocess = NULL, *ret = NULL;
+   int n, i;
+
+   if (!root) return NULL;
+
+   // Keep ref counter +1 on every object in returned list
+   g_object_ref(root);
+   toprocess = eina_list_append(toprocess, root);
+
+   while (toprocess)
+     {
+        AtspiAccessible *obj = eina_list_data_get(toprocess);
+        toprocess = eina_list_remove_list(toprocess, toprocess);
+        n = atspi_accessible_get_child_count(obj, NULL);
+        for (i = 0; i < n; i++)
+          {
+             AtspiAccessible *cand = atspi_accessible_get_child_at_index(obj, i, NULL);
+             toprocess = eina_list_append(toprocess, cand);
+          }
+        ret = eina_list_append(ret, obj);
+     }
+
+   return ret;
+}
+
+static ObjectCache*
+_cache_item_construct(AtspiAccessible *obj)
+{
+   ObjectCache *ret;
+   AtspiComponent *comp;
+
+   ret = calloc(1, sizeof(ObjectCache));
+   if (!ret)
+     {
+        ERROR("out-of memory");
+        return NULL;
+     }
+
+   comp = atspi_accessible_get_component(obj);
+   if (!comp) {
+     ERROR("Cached Object do not implement Component interface");
+   }
+   else {
+      ret->bounds = atspi_component_get_extents(comp, ATSPI_COORD_TYPE_SCREEN, NULL);
+      g_object_unref(comp);
+   }
+
+   return ret;
+}
+
+static Eina_List*
+_cache_item_n_cache(Eina_List *objs, int count)
+{
+   int i = 0;
+   Eina_List *ret = objs;
+   ObjectCache *oc;
+   AtspiAccessible *obj;
+
+   for (i = 0; (i < count) && ret; i++)
+     {
+        obj = eina_list_data_get(ret);
+        ret = eina_list_remove_list(ret, ret);
+
+        oc = _cache_item_construct(obj);
+        if (!oc) break;
+
+        eina_hash_add(cache, &obj, oc);
+        g_object_unref(obj);
+     }
+
+   return ret;
+}
+
+static Eina_Hash*
+_object_cache_new(void)
+{
+   return eina_hash_pointer_new(_cache_item_free_cb);
+}
+
+void
+object_cache_build(AtspiAccessible *root)
+{
+   Eina_List *objs;
+
+   _object_cache_free_internal();
+   cache = _object_cache_new();
+   if (!cache)
+     {
+        ERROR("ObjectCache: hash table creation failed");
+        return;
+     }
+
+   objs = _cache_candidates_list_prepare(root);
+   _cache_item_n_cache(objs, eina_list_count(objs));
+
+   return;
+}
+
+static Eina_Bool
+_do_cache(void *data)
+{
+   toprocess = _cache_item_n_cache(toprocess, bulk);
+   idler = NULL;
+
+   if (toprocess)
+     idler = ecore_idler_add(_do_cache, NULL);
+   else if (callback) callback(user_data);
+
+   return EINA_FALSE;
+}
+
+void
+object_cache_build_async(AtspiAccessible *root, int bulk_size, ObjectCacheReadyCb cb, void *ud)
+{
+   _object_cache_free_internal();
+
+   callback = cb;
+   user_data = ud;
+   bulk = bulk_size;
+
+   cache = _object_cache_new();
+   if (!cache)
+     {
+        ERROR("ObjectCache: hash table creation failed");
+        return;
+     }
+
+   toprocess = _cache_candidates_list_prepare(root);
+   idler = ecore_idler_add(_do_cache, NULL);
+
+   return;
+}
+
+void
+object_cache_shutdown(void)
+{
+   _object_cache_free_internal();
+}
+
+const ObjectCache*
+object_cache_get(AtspiAccessible *obj)
+{
+   ObjectCache *ret = NULL;
+   if (idler)
+     {
+        ERROR("Invalid usage. Async cache build is ongoing...");
+        return NULL;
+     }
+
+   if (!cache)
+     {
+        cache = _object_cache_new();
+        if (!cache)
+          {
+             ERROR("ObjectCache: hash table creation failed");
+             return NULL;
+          }
+     }
+
+   ret = eina_hash_find(cache, &obj);
+   if (!ret)
+     {
+        // fallback to blocking d-bus call
+        ret = _cache_item_construct(obj);
+        eina_hash_add(cache, &obj, ret);
+     }
+
+   return ret;
+}
diff --git a/src/pivot_chooser.c b/src/pivot_chooser.c
new file mode 100644 (file)
index 0000000..ea7edd2
--- /dev/null
@@ -0,0 +1,129 @@
+#include <atspi/atspi.h>
+#include "logger.h"
+#include <Eina.h>
+
+
+/**
+ * @brief Finds first leaf in object hierarchy with given states,
+ * starting from object given as parent.
+ *
+ * This heuristic assumes that focused element have focused
+ * parent widgets.
+ */
+static AtspiAccessible*
+_pivot_with_state_top_down_find(AtspiAccessible *parent, AtspiStateType type)
+{
+   AtspiAccessible *ret = NULL;
+   AtspiStateSet *states;
+   int i;
+
+   states = atspi_accessible_get_state_set(parent);
+   if (!states || atspi_state_set_contains(states, type))
+     {
+        int n = atspi_accessible_get_child_count(parent, NULL);
+        if (n == 0) ret = parent;
+        for (i = 0; i < n; i++)
+          {
+             AtspiAccessible *child = atspi_accessible_get_child_at_index(parent, i, NULL);
+             if (!child) continue;
+
+             ret = _pivot_with_state_top_down_find(child, type);
+
+             g_object_unref(child);
+
+             if (ret) break;
+          }
+     }
+   g_object_unref(states);
+
+   return ret;
+}
+
+/**
+ * @brief Finds first leaf descendant of given object with state @p type
+ */
+static AtspiAccessible*
+_pivot_with_state_flat_find(AtspiAccessible *parent, AtspiStateType type)
+{
+   Eina_List *candidates = NULL, *queue = NULL;
+
+   // ref object to keep same ref count
+   g_object_ref(parent);
+   queue = eina_list_append(queue, parent);
+
+   while (queue)
+     {
+        AtspiAccessible *obj = eina_list_data_get(queue);
+        queue = eina_list_remove_list(queue, queue);
+
+        int n = atspi_accessible_get_child_count(obj, NULL);
+        if (n == 0)
+          candidates = eina_list_append(candidates, obj);
+        else
+          {
+             int i;
+             for (i = 0; i < n; i++)
+               {
+                  AtspiAccessible *child = atspi_accessible_get_child_at_index(obj, i, NULL);
+                  if (child)
+                     queue = eina_list_append(queue, child);
+               }
+             g_object_unref(obj);
+          }
+     }
+
+   // FIXME sort by (x,y) first ??
+   while (candidates)
+     {
+        AtspiAccessible *obj = eina_list_data_get(candidates);
+        candidates = eina_list_remove_list(candidates, candidates);
+
+        AtspiStateSet *states = atspi_accessible_get_state_set(obj);
+        if (states && atspi_state_set_contains(states, type))
+          {
+             g_object_unref(states);
+             g_object_unref(obj);
+             eina_list_free(candidates);
+
+             return obj;
+          }
+
+        g_object_unref(states);
+        g_object_unref(obj);
+     }
+
+   return NULL;
+}
+
+/**
+ * @brief Purpose of this methods is to find first visible object in
+ * hierarchy
+ */
+AtspiAccessible *pivot_chooser_pivot_get(AtspiAccessible *win)
+{
+   AtspiAccessible *ret;
+
+   if (atspi_accessible_get_role(win, NULL) != ATSPI_ROLE_WINDOW)
+     {
+        ERROR("Pivot search entry point must be a Window!");
+        return NULL;
+     }
+
+   DEBUG("Finding SHOWING widget using top-down method.");
+   ret = _pivot_with_state_top_down_find(win, ATSPI_STATE_SHOWING);
+   if (ret) return ret;
+
+   DEBUG("Finding SHOWING widget using top-down method.");
+   ret = _pivot_with_state_flat_find(win, ATSPI_STATE_SHOWING);
+   if (ret) return ret;
+
+   DEBUG("Finding FOCUSED widget using top-down method.");
+   ret = _pivot_with_state_top_down_find(win, ATSPI_STATE_FOCUSED);
+   if (ret) return ret;
+
+   DEBUG("Finding FOCUSED widget using flat search method.");
+   ret = _pivot_with_state_flat_find(win, ATSPI_STATE_FOCUSED);
+   if (ret) return ret;
+
+   return NULL;
+}
diff --git a/src/position_sort.c b/src/position_sort.c
new file mode 100644 (file)
index 0000000..5497128
--- /dev/null
@@ -0,0 +1,156 @@
+#include "logger.h"
+#include "object_cache.h"
+#include "position_sort.h"
+
+
+static int
+_sort_vertically(const void *a, const void *b)
+{
+   AtspiAccessible *objA, *objB;
+   const ObjectCache *cA, *cB;
+
+   objA = (AtspiAccessible*)a;
+   objB = (AtspiAccessible*)b;
+
+   cA = object_cache_get(objA);
+   cB = object_cache_get(objB);
+
+   if (cA->bounds->y == cB->bounds->y)
+     return 0;
+   else if (cA->bounds->y > cB->bounds->y)
+     return 1;
+   else
+     return -1;
+}
+
+static int
+_sort_horizontally(const void *a, const void *b)
+{
+   AtspiAccessible *objA, *objB;
+   const ObjectCache *cA, *cB;
+
+   objA = (AtspiAccessible*)a;
+   objB = (AtspiAccessible*)b;
+
+   cA = object_cache_get(objA);
+   cB = object_cache_get(objB);
+
+   if (cA->bounds->x == cB->bounds->x)
+     {
+        if (cA->bounds->y > cB->bounds->y)
+          return 1;
+        if (cA->bounds->y < cB->bounds->y)
+          return -1;
+        return 0;
+     }
+   else if (cA->bounds->x > cB->bounds->x)
+     return 1;
+   else
+     return -1;
+}
+
+static Eina_List*
+_get_zones(const Eina_List *objs)
+{
+   Eina_List *candidates = NULL;
+   const Eina_List *l;
+   AtspiAccessible *obj;
+   AtspiComponent *comp;
+   const ObjectCache *oc;
+
+   EINA_LIST_FOREACH(objs, l, obj)
+     {
+        if ((comp = atspi_accessible_get_component(obj)) != NULL)
+          {
+             oc = object_cache_get(obj);
+
+             // some objects may implement AtspiCompoment interface, however
+             // they do not have valid sizes.
+             if (!oc->bounds || (oc->bounds->width < 0) || oc->bounds->height < 0)
+               {
+                  DEBUG("Invalid bounds. skipping from zone list: %s %s",
+                   atspi_accessible_get_name(obj, NULL),
+                   atspi_accessible_get_role_name(obj, NULL));
+                  continue;
+               }
+             candidates = eina_list_append(candidates, obj);
+          }
+        else
+          DEBUG("No component interface: skipping %s %s",
+                atspi_accessible_get_name(obj, NULL),
+                atspi_accessible_get_role_name(obj, NULL));
+     }
+
+   // Sort object by y - coordinate
+   return eina_list_sort(candidates, 0, _sort_vertically);
+}
+
+static Eina_List*
+_get_lines(const Eina_List *objs)
+{
+   Eina_List *line = NULL, *lines = NULL;
+   const Eina_List *l;
+   AtspiAccessible *obj;
+   const ObjectCache *line_beg;
+
+   EINA_LIST_FOREACH(objs, l, obj)
+     {
+        if (!line) {
+          // set first object in line
+          line = eina_list_append(line, obj);
+          line_beg = object_cache_get(obj);
+          continue;
+        }
+
+        const ObjectCache *oc = object_cache_get(obj);
+        // Object are considered as present in same line, if
+        // its y coordinate begins maximum 25% below
+        // y coordinate% of first object in line.
+        if ((line_beg->bounds->y + (int)(0.25 * (double)line_beg->bounds->height)) >
+            oc->bounds->y)
+          {
+             line = eina_list_append(line, obj);
+             continue;
+          }
+        else
+          {
+             //finish line & set new line leader
+             lines = eina_list_append(lines, line);
+             line = NULL;
+             line = eina_list_append(line, obj);
+             line_beg = object_cache_get(obj);
+          }
+     }
+
+   // finish last line
+   if (line) lines = eina_list_append(lines, line);
+
+   return lines;
+}
+
+Eina_List *position_sort(const Eina_List *objs)
+{
+   Eina_List *l, *line, *zones, *lines = NULL;
+   int i = 0;
+
+   // Get list of objects occupying place on the screen
+   DEBUG("PositionSort: Candidates; %d", eina_list_count(objs));
+   zones = _get_zones(objs);
+
+   // Cluster all zones into lines - verticaly
+   DEBUG("PositionSort: Zones; %d", eina_list_count(zones));
+   lines = _get_lines(zones);
+
+   // sort all zones in line - horizontaly
+   DEBUG("PositionSort: Lines; %d", eina_list_count(lines));
+   EINA_LIST_FOREACH(lines, l, line)
+     {
+        DEBUG("PositionSort: Line %d: %d items", i++, eina_list_count(line));
+        line = eina_list_sort(line, 0, _sort_horizontally);
+        eina_list_data_set(l, line);
+     }
+
+   if (zones) eina_list_free(zones);
+
+   return lines;
+}
diff --git a/src/screen_reader.c b/src/screen_reader.c
new file mode 100755 (executable)
index 0000000..4108d71
--- /dev/null
@@ -0,0 +1,99 @@
+#include "screen_reader.h"
+#include "screen_reader_tts.h"
+#include <vconf.h>
+#include "logger.h"
+
+#ifdef RUN_IPC_TEST_SUIT
+       #include "test_suite/test_suite.h"
+       #include "test_suite/xml_parser_test.h"
+#endif
+
+#define BUF_SIZE 1024
+
+Service_Data service_data = {
+               //Set by vconf
+               .information_level = 1,
+               .run_service = 1,
+               .language = "en_US",
+               .voice_type = TTS_VOICE_TYPE_FEMALE,
+               .reading_speed = 2,
+               .tracking_signal_name = HIGHLIGHT_CHANGED_SIG,
+
+
+               //Set by tts
+               .tts = NULL,
+               .available_languages = NULL,
+
+               //Actions to do when tts state is 'ready'
+               .say_text = false,
+               .update_language_list = false,
+
+
+               .text_to_say_text = NULL,
+               .text_to_say_info = NULL
+};
+
+Service_Data *get_pointer_to_service_data_struct()
+{
+  return &service_data;
+}
+
+int screen_reader_create_service(void *data)
+{
+       DEBUG("Service Create Callback \n");
+
+       Service_Data *service_data = data;
+
+       tts_init(service_data);
+       vconf_init(service_data);
+       spi_init(service_data);
+       xml_init(service_data);
+
+
+       /* XML TEST */
+
+       #ifdef RUN_IPC_TEST_SUIT
+               run_xml_tests();
+               test_suite_init();
+       #endif
+
+       return 0;
+}
+
+int screen_reader_terminate_service(void *data)
+{
+       DEBUG("Service Terminate Callback \n");
+
+       Service_Data *service_data = data;
+
+       int vconf_ret = vconf_set_bool("db/setting/accessibility/screen_reader", EINA_FALSE);
+       if(vconf_ret == 0)
+       {
+               DEBUG("TTS key set to false");
+       }
+       else
+       {
+               DEBUG("COULD NOT SET tts key to 0");
+       }
+
+       
+       vconf_ret = vconf_set_bool(VCONFKEY_SETAPPL_ACCESSIBILITY_TTS, EINA_FALSE);
+       if(vconf_ret == 0)
+       {
+               DEBUG("TTS key set to false");
+       }
+       else
+       {
+               DEBUG("COULD NOT SET tts key to 0");
+       }
+
+       tts_stop(service_data->tts);
+       tts_unprepare(service_data->tts);
+       tts_destroy(service_data->tts);
+       service_data->text_to_say_text = NULL;
+       service_data->description_text = NULL;
+       service_data->text_from_dbus = NULL;
+       service_data->current_value = NULL;
+
+       return 0;
+}
diff --git a/src/screen_reader_spi.c b/src/screen_reader_spi.c
new file mode 100644 (file)
index 0000000..5cb5baf
--- /dev/null
@@ -0,0 +1,207 @@
+/*
+ * sreen_reader_spi.c
+ *
+ *  Created on: Feb 20, 2014
+ *  Author: m.skorupinsk
+ */
+
+#include "screen_reader_spi.h"
+#include "screen_reader_xml.h"
+#include "logger.h"
+#ifdef RUN_IPC_TEST_SUIT
+       #include "test_suite/test_suite.h"
+#endif
+
+static Service_Data *service_data;
+
+typedef struct
+{
+       char *key;
+       char *val;
+} Attr;
+
+static void display_info(const AtspiEvent *event)
+{
+       AtspiAccessible  *source = event->source;
+       gchar *name= atspi_accessible_get_name(source, NULL);
+       gchar *role= atspi_accessible_get_role_name(source, NULL);
+       gchar *toolkit = atspi_accessible_get_toolkit_name(source, NULL);
+
+       DEBUG("--------------------------------------------------------");
+       DEBUG("Toolkit: %s; Event_type: %s; (%d, %d)", toolkit, event->type, event->detail1, event->detail2);
+       DEBUG("Name: %s; Role: %s", name, role);
+       DEBUG("--------------------------------------------------------");
+}
+
+Eina_Bool double_click_timer_cb(void *data)
+{
+       Service_Data *sd = data;
+       sd->clicked_widget = NULL;
+
+       return EINA_FALSE;
+}
+
+void spi_on_state_changed_cb(const AtspiEvent *event, void *user_data)
+{
+       DEBUG("START");
+       DEBUG("STATE CHANGED");
+       Service_Data *sd = user_data;
+
+       display_info(event);
+       if(strcmp(event->type, sd->tracking_signal_name) == 0 && event->detail1 == 1)
+       {
+               sd->currently_focused = event->source;
+
+               DEBUG("->->->->->-> WIDGET GAINED HIGHLIGHT: %s <-<-<-<-<-<-<-",
+                               atspi_accessible_get_name(sd->currently_focused, NULL));
+
+               sd->description_text = atspi_accessible_get_description(sd->currently_focused, NULL);
+               if(strcmp(sd->description_text, "\0") == 0)
+               {
+                       sd->description_text = atspi_accessible_get_name(sd->currently_focused, NULL);
+                       if(strcmp(sd->description_text, "\0") == 0)
+                               sd->description_text = (char*)atspi_accessible_get_role_name(sd->currently_focused, NULL);
+               }
+               sd->text_to_say_text = get_text_to_read("on_focus", sd->currently_focused);
+               spi_prepare_text(sd);
+       }
+
+       DEBUG("END");
+}
+
+void spi_on_caret_move_cb(const AtspiEvent *event, void *user_data)
+{
+       DEBUG("START");
+       DEBUG("CARET MOVED");
+       Service_Data *sd = user_data;
+       int char_count;
+       gint caret_pos;
+       char buf[256];
+
+       display_info(event);
+       if(strcmp(event->type, CARET_MOVED_SIG) == 0)
+       {
+               sd->currently_focused = event->source;
+
+               AtspiText *text_interface = atspi_accessible_get_text(sd->currently_focused);
+               if(text_interface)
+               {
+                       DEBUG("->->->->->-> WIDGET CARET MOVED: %s <-<-<-<-<-<-<-",
+                                atspi_accessible_get_name(sd->currently_focused, NULL));
+
+                       char_count = (int)atspi_text_get_character_count(text_interface, NULL);
+                       caret_pos = atspi_text_get_caret_offset(text_interface, NULL);
+                       if(!caret_pos)
+                       {
+                               DEBUG("MIN POSITION REACHED");
+                               sprintf(buf, "%s %s", (char*)atspi_text_get_text(text_interface, caret_pos, caret_pos + 1, NULL), MIN_POS_REACHED);
+                       }
+                       else if(char_count == caret_pos)
+                       {
+                               DEBUG("MAX POSITION REACHED");
+                               sprintf(buf, "%s %s", (char*)atspi_text_get_text(text_interface, caret_pos, caret_pos + 1, NULL), MAX_POS_REACHED);
+                       }
+                       else
+                               sprintf(buf, "%s", (char*)atspi_text_get_text(text_interface, caret_pos, caret_pos + 1, NULL));
+
+                       sd->text_to_say_text = strdup(buf);
+                       spi_prepare_text(sd);
+               }
+       }
+
+       DEBUG("END");
+}
+
+void spi_on_access_value_changed_cb(const AtspiEvent *event, void *user_data)
+{
+       DEBUG("START");
+       DEBUG("STATE CHANGED");
+       Service_Data *sd = user_data;
+       double current_temp_value;
+       char buf[256];
+
+       display_info(event);
+       if(strcmp(event->type, VALUE_CHANGED_SIG) == 0)
+       {
+               sd->currently_focused = event->source;
+
+               AtspiValue *value_interface = atspi_accessible_get_value(sd->currently_focused);
+               if(value_interface)
+               {
+                       DEBUG("->->->->->-> WIDGET VALUE CHANGED: %s <-<-<-<-<-<-<-",
+                                atspi_accessible_get_name(sd->currently_focused, NULL));
+
+                       current_temp_value = (double)atspi_value_get_current_value(value_interface, NULL);
+                       if(current_temp_value == atspi_value_get_maximum_value(value_interface, NULL))
+                       {
+                               DEBUG("MAX VALUE REACHED");
+                               sprintf(buf, "%.2f %s", current_temp_value, MAX_REACHED);
+                       }
+                       else if(current_temp_value == atspi_value_get_minimum_value(value_interface, NULL))
+                       {
+                               DEBUG("MIN VALUE REACHED");
+                               sprintf(buf, "%.2f %s", current_temp_value, MIN_REACHED);
+                       }
+                       else
+                               sprintf(buf, "%.2f", current_temp_value);
+
+                       sd->text_to_say_text = strdup(buf);
+                       spi_prepare_text(sd);
+               }
+       }
+       DEBUG("END");
+}
+
+void spi_init(Service_Data *sd)
+{
+
+       DEBUG( "--------------------- SPI_init START ---------------------");
+       service_data = sd;
+
+       DEBUG( ">>> Creating listeners <<<");
+
+       sd->state_changed_listener = atspi_event_listener_new(spi_on_state_changed_cb, service_data, NULL);
+       if(sd->state_changed_listener == NULL)
+       {
+               DEBUG("FAILED TO CREATE spi state changed listener")
+       }
+
+       sd->caret_moved_listener = atspi_event_listener_new(spi_on_caret_move_cb, service_data, NULL);
+       if(sd->caret_moved_listener == NULL)
+       {
+               DEBUG("FAILED TO CREATE spi state changed listener")
+       }
+
+       sd->value_changed_listener = atspi_event_listener_new(spi_on_access_value_changed_cb, service_data, NULL);
+       if(sd->value_changed_listener == NULL)
+       {
+               DEBUG("FAILED TO CREATE spi state changed listener")
+       }
+
+       // ---------------------------------------------------------------------------------------------------
+
+       gboolean ret1 = atspi_event_listener_register(sd->state_changed_listener, sd->tracking_signal_name, NULL);
+       if(ret1 == false)
+       {
+               DEBUG("FAILED TO REGISTER spi focus/highlight listener");
+       }
+
+       gboolean ret2 = atspi_event_listener_register(sd->caret_moved_listener, CARET_MOVED_SIG, NULL);
+       if(ret2 == false)
+       {
+               DEBUG("FAILED TO REGISTER spi caret moved listener");
+       }
+
+       gboolean ret3 = atspi_event_listener_register(sd->value_changed_listener, VALUE_CHANGED_SIG, NULL);
+       if(ret3 == false)
+       {
+               DEBUG("FAILED TO REGISTER spi value changed listener");
+       }
+
+       if(ret1 == true && ret2 == true && ret3 == true)
+       {
+               DEBUG("spi listener REGISTERED");
+       }
+
+       DEBUG( "---------------------- SPI_init END ----------------------\n\n");
+}
diff --git a/src/screen_reader_tts.c b/src/screen_reader_tts.c
new file mode 100644 (file)
index 0000000..a9b032a
--- /dev/null
@@ -0,0 +1,242 @@
+/*
+ * screen_reader_tts.c
+ *
+ *  Created on: Feb 19, 2014
+ *  Author: m.skorupinsk
+ */
+#include <Ecore.h>
+#include "screen_reader_tts.h"
+#include "logger.h"
+
+// ---------------------------- DEBUG HELPERS ------------------------------
+
+static char * get_tts_error( int r )
+{
+       switch( r )
+       {
+               case TTS_ERROR_NONE:
+               {
+                       return "no error";
+               }
+               case TTS_ERROR_INVALID_PARAMETER:
+               {
+                       return "inv param";
+               }
+               case TTS_ERROR_OUT_OF_MEMORY:
+               {
+                       return "out of memory";
+               }
+               case TTS_ERROR_OPERATION_FAILED:
+               {
+                       return "oper failed";
+               }
+               case TTS_ERROR_INVALID_STATE:
+               {
+                       return "inv state";
+               }
+               default:
+               {
+                       return "inny error";
+               }
+       }
+}
+
+static char * get_tts_state( tts_state_e r )
+{
+       switch( r )
+       {
+               case TTS_STATE_CREATED:
+               {
+                       return "created";
+               }
+               case TTS_STATE_READY:
+               {
+                       return "ready";
+               }
+               case TTS_STATE_PLAYING:
+               {
+                       return "playing";
+               }
+               case TTS_STATE_PAUSED:
+               {
+                       return "pause";
+               }
+               default:
+               {
+                       return "uknown state";
+               }
+       }
+}
+
+// -------------------------------------------------------------------------------------------------
+
+bool get_supported_voices_cb(tts_h tts, const char* language, int voice_type, void* user_data)
+{
+       DEBUG("LANG: %s; TYPE: %d", language, voice_type);
+
+       Service_Data *sd = user_data;
+       Voice_Info *vi = calloc(1, sizeof(Voice_Info));
+
+       int len = strlen(language);
+
+       vi->language = calloc(len + 1, sizeof(char));
+       strcpy(vi->language, language);
+
+       vi->voice_type = voice_type;
+
+       sd->available_languages = eina_list_append(sd->available_languages, vi);
+
+       return ECORE_CALLBACK_RENEW;
+}
+
+static void __tts_test_utt_started_cb(tts_h tts, int utt_id, void* user_data)
+{
+       DEBUG("Utterance started : utt id(%d) \n", utt_id);
+
+       return;
+}
+
+static void __tts_test_utt_completed_cb(tts_h tts, int utt_id, void* user_data)
+{
+       DEBUG("Utterance completed : utt id(%d) \n", utt_id);
+
+       return;
+}
+
+bool tts_init(void *data)
+{
+       DEBUG( "--------------------- TTS_init START ---------------------");
+       Service_Data *sd = data;
+
+       int r = tts_create( &sd->tts );
+       DEBUG( "Create tts %d (%s)", r, get_tts_error( r ) );
+
+       r = tts_set_mode( sd->tts, TTS_MODE_DEFAULT );
+       DEBUG( "Set tts mode SR %d (%s)", r, get_tts_error( r ) );
+
+       r = tts_prepare( sd->tts );
+       DEBUG( "Prepare tts %d (%s)", r, get_tts_error( r ) );
+
+       tts_set_state_changed_cb(sd->tts, state_changed_cb, sd);
+
+       tts_set_utterance_started_cb(sd->tts, __tts_test_utt_started_cb, sd);
+       tts_set_utterance_completed_cb( sd->tts,  __tts_test_utt_completed_cb,  sd);
+
+       DEBUG( "---------------------- TTS_init END ----------------------\n\n");
+       return true;
+}
+
+Eina_Bool tts_speak( void * data )
+{
+       Service_Data *sd = data;
+       int speak_id;
+       const char * text_to_speak = NULL;
+
+       if (sd->_dbus_txt_readed == 0 && sd->text_from_dbus ) {
+               text_to_speak = sd->text_from_dbus;
+               sd->_dbus_txt_readed = 1;
+       }
+       else
+               text_to_speak = sd->text_to_say_text;
+
+       DEBUG( "tts_speak\n");
+       DEBUG( "text to say:%s\n", text_to_speak);
+       if ( !text_to_speak ) return EINA_FALSE;
+       if ( !text_to_speak[0] ) return EINA_FALSE;
+
+       tts_add_text( sd->tts, text_to_speak, NULL, TTS_VOICE_TYPE_AUTO, TTS_SPEED_AUTO, &speak_id );
+       DEBUG("added id to:%d\n", speak_id);
+
+       tts_play( sd->tts );
+       return EINA_FALSE;
+
+}
+
+bool update_supported_voices(void *data)
+{
+       DEBUG("START");
+       tts_state_e state;
+
+       Service_Data *sd = data;
+
+       int res = tts_get_state(sd->tts, &state);
+
+       if(res != TTS_ERROR_NONE)
+       {
+               DEBUG("CANNOT RETRIVE STATE");
+               return false;
+       }
+
+       if(state == TTS_STATE_READY)
+       {
+               tts_foreach_supported_voices(sd->tts, get_supported_voices_cb, sd);
+       }
+       else
+       {
+               sd->update_language_list = true;
+       }
+
+       DEBUG("END")
+       return true;
+}
+
+void state_changed_cb(tts_h tts, tts_state_e previous, tts_state_e current, void* user_data)
+{
+       DEBUG("++++++++++++++++state_changed_cb\n++++++++++++++++++");
+       DEBUG("current state:%s and previous state:%s\n", get_tts_state(current), get_tts_state(previous));
+       Service_Data *sd = user_data;
+
+       if(current == TTS_STATE_READY) {
+               DEBUG("State is ready after prepare\n");
+               tts_speak(sd);
+       }
+    else
+    {
+        DEBUG("State is diffrent then ready after prepare!\n");
+    }
+}
+
+void spi_prepare_text(void *data)
+{
+       Service_Data *sd = data;
+       sd->say_text = true;
+       sd->update_language_list = false;
+    DEBUG("PREPARE TEXT!!!!!!!!!!!!!!\n");
+        
+    tts_stop(sd->tts);
+    tts_append_text(sd);
+}
+
+void tts_append_text(void *data)
+{
+       Service_Data *sd = data;
+       tts_state_e state;
+       tts_get_state(sd->tts, &state);
+
+       DEBUG("text append:::!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
+       if(state == TTS_STATE_READY)
+       {
+        DEBUG("TTS state == ready!\n");
+               tts_speak(data);
+       }
+    else
+    {
+        DEBUG("TTS state != ready!\n");
+    }
+}
+
+void spi_stop( void *data)
+{
+       Service_Data *sd = data;
+       sd->say_text = false;
+       sd->update_language_list = false;
+       free(sd->text_to_say_text);
+       free(sd->description_text);
+       free((char*)sd->text_from_dbus);
+       free(sd->current_value);
+       sd->text_to_say_text = NULL;
+       sd->description_text = NULL;
+       sd->text_from_dbus = NULL;
+       sd->current_value = NULL;
+       tts_stop(sd->tts);
+}
diff --git a/src/screen_reader_vconf.c b/src/screen_reader_vconf.c
new file mode 100644 (file)
index 0000000..67ab205
--- /dev/null
@@ -0,0 +1,335 @@
+/*
+ * screen_reader_vconf.c
+ *
+ *  Created on: Feb 19, 2014
+ *      Author: m.skorupinsk
+ */
+#include <Elementary.h>
+#include <vconf.h>
+#include "screen_reader_vconf.h"
+#include "screen_reader_spi.h"
+#include "logger.h"
+
+#ifdef RUN_IPC_TEST_SUIT
+       #include "test_suite/test_suite.h"
+#endif
+
+#ifdef LOG_TAG
+       #undef LOG_TAG
+#endif
+#define LOG_TAG "SCREEN READER VCONF"
+
+
+keylist_t *keys = NULL;
+
+bool set_langauge(Service_Data *sd, const char *new_language, int new_voice)
+{
+       DEBUG("START");
+
+       Eina_List *l;
+       Voice_Info *vi;
+
+       if(strncmp(sd->language, new_language, LAN_NAME - 1) == 0 && sd->voice_type == new_voice)
+       {
+               DEBUG("No need to change accessibility language: %s(%d) -> %s(%d)",
+                               sd->language, sd->voice_type, new_language, new_voice);
+
+               return true;
+       }
+
+       EINA_LIST_FOREACH(sd->available_languages, l, vi)
+       {
+               DEBUG("foreach %s <- %s", vi->language, new_language);
+               if(strncmp(vi->language, new_language, LAN_NAME - 1) == 0 &&
+                               vi->voice_type == new_voice)
+               {
+                       DEBUG("str_cpy %s (%d) -> %s (%d)", sd->language, sd->voice_type, vi->language, vi->voice_type);
+                       strncpy(sd->language, vi->language, LAN_NAME - 1);
+                       sd->voice_type = vi->voice_type;
+                       DEBUG("after_str_cpy");
+
+                       DEBUG("ACCESSIBILITY LANGUAGE CHANGED");
+                       DEBUG("END");
+                       return true;
+               }
+       }
+
+       DEBUG("ACCESSIBILITY LANGUAGE FAILED TO CHANGED");
+
+       vconf_set_str("db/setting/accessibility/language", sd->language);
+       vconf_set_int("db/setting/accessibility/voice", sd->voice_type);
+
+       DEBUG("END");
+       return false;
+}
+
+char *fold_tracker_signal(const char *signal_name)
+{
+       if(strcmp(signal_name, FOCUS_SIG) == 0)
+       {
+               return FOCUS_CHANGED_SIG;
+       }
+       else
+       {
+               return HIGHLIGHT_CHANGED_SIG;
+       }
+}
+
+bool set_tracking_listener(Service_Data *sd, const char *signal_name)
+{
+       DEBUG("START");
+
+       char *new_tracking_signal;
+
+       new_tracking_signal = fold_tracker_signal(signal_name);
+
+       if(strcmp(sd->tracking_signal_name, new_tracking_signal) == 0)
+       {
+               DEBUG("No need to change accessibility tracking signal: %s == %s",
+                               sd->tracking_signal_name, new_tracking_signal);
+
+               return true;
+       }
+
+       gboolean ret = atspi_event_listener_deregister(sd->state_changed_listener, sd->tracking_signal_name, NULL);
+       if(ret == false)
+       {
+               DEBUG("Tracking signal listerner deregister successful");
+       }
+
+       sd->state_changed_listener = NULL;
+       sd->tracking_signal_name = strdup(new_tracking_signal);
+
+       sd->state_changed_listener = atspi_event_listener_new(spi_on_state_changed_cb, sd, NULL);
+       if(sd->state_changed_listener == NULL)
+       {
+               DEBUG("FAILED TO CREATE spi state changed listener")
+       }
+
+       gboolean ret1 = atspi_event_listener_register(sd->state_changed_listener, sd->tracking_signal_name, NULL);
+       if(ret1 == false)
+       {
+               DEBUG("FAILED TO REGISTER spi focus/highlight listener");
+               return false;
+       }
+       else
+       {
+               DEBUG("Tracking listener register for new signal");
+       }
+       return true;
+}
+
+// ------------------------------ vconf callbacks----------------------
+
+void information_level_cb(keynode_t *node, void *user_data)
+{
+       DEBUG("START");
+       DEBUG("Information level set: %d", node->value.i);
+
+       Service_Data *service_data = user_data;
+       service_data->information_level = node->value.i;
+
+       DEBUG("END");
+}
+
+void app_termination_cb(keynode_t *node, void *user_data)
+{
+       DEBUG("START");
+       DEBUG("Application terminate %d", !node->value.i);
+
+       Service_Data *service_data = user_data;
+       service_data->run_service = node->value.i;
+
+       if(service_data->run_service == 0)
+       {
+               elm_exit();
+       }
+
+       DEBUG("END");
+}
+
+void language_cb(keynode_t *node, void *user_data)
+{
+       DEBUG("START");
+       DEBUG("Trying to set language to: %s", node->value.s);
+
+       Service_Data *sd = user_data;
+
+       int voice_type;
+
+       vconf_get_int("db/setting/accessibility/voice", (int*)(&voice_type));
+       set_langauge(sd, node->value.s, voice_type);
+
+       DEBUG("END");
+}
+
+void voice_cb(keynode_t *node, void *user_data)
+{
+       DEBUG("START");
+       DEBUG("Voice set to: %d", node->value.i);
+
+       Service_Data *sd = user_data;
+
+       const char *lang = vconf_get_str("db/setting/accessibility/language");
+       set_langauge(sd, lang, (int)node->value.i);
+
+       DEBUG("END");
+}
+
+void reading_speed_cb(keynode_t *node, void *user_data)
+{
+       DEBUG("START");
+       DEBUG("Reading speed set to: %d", node->value.i);
+
+       Service_Data *service_data = user_data;
+       service_data->reading_speed = node->value.i;
+
+       DEBUG("END");
+}
+
+void tracking_signal_changed_cb(keynode_t *node, void *user_data)
+{
+       DEBUG("START");
+       DEBUG("Tracking signal set to: %s", node->value.s);
+
+       Service_Data *sd = user_data;
+       const char *tracking_signal = vconf_get_str("db/setting/accessibility/tracking_signal");
+       set_tracking_listener(sd, tracking_signal);
+}
+
+// --------------------------------------------------------------------
+
+int get_key_values(Service_Data *sd)
+{
+       DEBUG("START");
+
+       char *language = vconf_get_str("db/setting/accessibility/language");
+
+       if(sd->language == NULL)
+       {
+               DEBUG("FAILED TO SET LANGUAGE");
+       }
+
+       int ret = -1;
+       int to_ret = 0;
+
+
+       int voice;
+       ret = vconf_get_int("db/setting/accessibility/voice", &voice);
+       if(ret != 0)
+       {
+               to_ret -= -1;
+               DEBUG("FAILED TO SET VOICE TYPE: %d", ret);
+       }
+
+       set_langauge(sd, language, voice);
+
+       ret = vconf_get_int("db/setting/accessibility/speech_rate", &sd->reading_speed);
+       if(ret != 0)
+       {
+               to_ret -= -2;
+               DEBUG("FAILED TO SET READING SPEED: %d", ret);
+       }
+
+       ret = vconf_get_int("db/setting/accessibility/information_level", &sd->information_level);
+       if(ret != 0)
+       {
+               to_ret -= -4;
+               DEBUG("FAILED TO SET INFORMATION LEVEL: %d", ret);
+       }
+
+       DEBUG("SCREEN READER DATA SET TO: Language: %s; Voice: %d, Reading_Speed: %d, Information_Level: %d, Tracking signal: %s;",
+                       sd->language, sd->voice_type, sd->reading_speed, sd->information_level, sd->tracking_signal_name);
+
+       DEBUG("END");
+       return to_ret;
+}
+
+bool vconf_init(Service_Data *service_data)
+{
+       DEBUG( "--------------------- VCONF_init START ---------------------");
+       int ret = 0;
+
+       //TODO: Remove when adequate keys in the settings(control?) panel are added
+       // -----------------------  TEST ONLY -----------------------------------------------
+       DEBUG("TESTS START");
+       keys = vconf_keylist_new();
+       vconf_keylist_add_int(keys, "db/setting/accessibility/information_level", 2);
+       vconf_keylist_add_str(keys, "db/setting/accessibility/language", "en_US");
+       vconf_keylist_add_int(keys, "db/setting/accessibility/voice", 1);
+       vconf_keylist_add_str(keys, "db/setting/accessibility/tracking_signal", HIGHLIGHT_SIG);
+    //-----------------------------------------------------------------------------------
+       //vconf_set_bool(VCONFKEY_SETAPPL_ACCESSIBILITY_TTS, EINA_TRUE);
+
+       if(vconf_set(keys))
+       {
+               DEBUG("nothing is written\n");
+       }
+       else
+       {
+               DEBUG("everything is written\n");
+       }
+
+       vconf_keylist_free(keys);
+       // ----------------------------------------------------------------------------------
+
+       ret = get_key_values(service_data);
+       if(ret != 0)
+       {
+               DEBUG("Could not set data from vconf: %d", ret);
+       }
+
+       ret = vconf_notify_key_changed("db/setting/accessibility/information_level", information_level_cb, service_data);
+       if(ret != 0)
+       {
+               DEBUG("Could not add information level callback");
+               return false;
+       }
+
+       ret = vconf_notify_key_changed("db/setting/accessibility/screen_reader", app_termination_cb, service_data);
+       if(ret != 0)
+       {
+               DEBUG("Could not add app termination callback");
+               return false;
+       }
+
+       ret = vconf_notify_key_changed("db/menu_widget/language", language_cb, service_data);
+       if(ret != 0)
+       {
+               DEBUG("Could not add language callback");
+               return false;
+       }
+
+       ret = vconf_notify_key_changed("db/setting/accessibility/language", language_cb, service_data);
+       if(ret != 0)
+       {
+               DEBUG("Could not add language callback");
+               return false;
+       }
+
+       ret = vconf_notify_key_changed("db/setting/accessibility/voice", voice_cb, service_data);
+       if(ret != 0)
+       {
+               DEBUG("Could not add voice callback");
+               return false;
+       }
+
+       ret = vconf_notify_key_changed("db/setting/accessibility/speech_rate", reading_speed_cb, service_data);
+       if(ret != 0)
+       {
+               DEBUG("Could not add reading speed callback callback");
+               return false;
+       }
+
+       ret = vconf_notify_key_changed("db/setting/accessibility/tracking_signal", tracking_signal_changed_cb, service_data);
+       if(ret != 0)
+       {
+               DEBUG("Could not add reading speed callback callback");
+               return false;
+       }
+
+       DEBUG("ALL CALBACKS ADDED");
+
+       DEBUG( "---------------------- VCONF_init END ----------------------\n\n");
+       return true;
+}
diff --git a/src/screen_reader_xml.c b/src/screen_reader_xml.c
new file mode 100644 (file)
index 0000000..ffe2abf
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * screen_reader_xml.c
+ *
+ *  Created on: Mar 26, 2014
+ *      Author: m.skorupinsk
+ */
+
+#include "logger.h"
+#include "screen_reader_xml.h"
+
+static Service_Data *service_data;
+
+char *get_text_to_read(const char *action, AtspiAccessible *widget)
+{
+       char *description = service_data->description_text;
+
+       DEBUG("DESCRIPTION %s\n", description);
+
+       if(description == NULL)
+       {
+               DEBUG("NULL DESCRIPTION\n");
+               return NULL;
+       }
+       else if(description[0] == 0)
+       {
+               DEBUG("DESCRIPTION[0] = 0\n");
+               return NULL;
+       }
+
+       int level = service_data->information_level;
+
+       Eina_Simple_XML_Attribute *attributes[2] = {NULL, NULL};
+
+       char level_str[2];
+       snprintf(level_str, 2, "%d", level);
+
+       DEBUG("THE LEVEL STRING: %s LEVEL: %d\n", level_str, level);
+
+       attributes[0] = eina_simple_xml_attribute_new(NULL, "level", level_str);
+       char *ret_str = NULL;
+
+       ret_str = get_string_str(NULL, description, attributes, "Information_Level");
+
+       eina_simple_xml_attribute_free(attributes[0]);
+
+       DEBUG("\n\n-> -> -> THE STRING TO SAY: <- <- <- \n%s\n\n", ret_str);
+
+       return ret_str;
+}
+
+void xml_init(Service_Data *sd)
+{
+       service_data = sd;
+}
diff --git a/src/structural_navi.c b/src/structural_navi.c
new file mode 100644 (file)
index 0000000..5b59148
--- /dev/null
@@ -0,0 +1,162 @@
+#include "structural_navi.h"
+#include "position_sort.h"
+#include "logger.h"
+
+static Eina_List*
+_atspi_children_list_get(AtspiAccessible *parent)
+{
+   Eina_List *ret = NULL;
+   int count = atspi_accessible_get_child_count(parent, NULL);
+   int i;
+
+   for (i = 0; i < count; i++)
+     {
+        AtspiAccessible *child = atspi_accessible_get_child_at_index(parent, i, NULL);
+        if (child) ret = eina_list_append(ret, child);
+     }
+
+   return ret;
+}
+
+static void
+_atspi_children_list_free(Eina_List *children)
+{
+   AtspiAccessible *obj;
+
+   EINA_LIST_FREE(children, obj)
+      g_object_unref(obj);
+}
+
+static Eina_List*
+_flat_review_get(Eina_List *tosort)
+{
+   Eina_List *ret = NULL, *lines, *l, *line;
+
+   lines = position_sort(tosort);
+
+   EINA_LIST_FOREACH(lines, l, line)
+     {
+        ret = eina_list_merge(ret, line);
+     }
+
+   eina_list_free(lines);
+
+   return ret;
+}
+
+AtspiAccessible *structural_navi_same_level_next(AtspiAccessible *current)
+{
+    AtspiAccessible *parent;
+    AtspiRole role;
+
+    parent = atspi_accessible_get_parent(current, NULL);
+    if (!parent) return NULL;
+
+    role = atspi_accessible_get_role(parent, NULL);
+    if (role != ATSPI_ROLE_DESKTOP_FRAME)
+      {
+         Eina_List *children = _atspi_children_list_get(parent);
+         Eina_List *me = eina_list_data_find_list(children, current);
+         Eina_List *sorted = _flat_review_get(children);
+         me = eina_list_data_find_list(sorted, current);
+         AtspiAccessible *ret = eina_list_data_get(eina_list_next(me));
+
+         eina_list_free(sorted);
+         _atspi_children_list_free(children);
+
+         return ret;
+      }
+    return NULL;
+}
+
+AtspiAccessible *structural_navi_same_level_prev(AtspiAccessible *current)
+{
+    AtspiAccessible *parent;
+    AtspiRole role;
+
+    parent = atspi_accessible_get_parent(current, NULL);
+    if (!parent) return NULL;
+
+    role = atspi_accessible_get_role(parent, NULL);
+    if (role != ATSPI_ROLE_DESKTOP_FRAME)
+      {
+         Eina_List *children = _atspi_children_list_get(parent);
+         Eina_List *sorted = _flat_review_get(children);
+         Eina_List *me = eina_list_data_find_list(sorted, current);
+         AtspiAccessible *ret = eina_list_data_get(eina_list_prev(me));
+
+         eina_list_free(sorted);
+         _atspi_children_list_free(children);
+
+         return ret;
+      }
+    return NULL;
+}
+
+AtspiAccessible *structural_navi_level_up(AtspiAccessible *current)
+{
+    AtspiAccessible *parent;
+    AtspiRole role;
+
+    parent = atspi_accessible_get_parent(current, NULL);
+    if (!parent) return NULL;
+
+    role = atspi_accessible_get_role(parent, NULL);
+    if (role != ATSPI_ROLE_DESKTOP_FRAME)
+      {
+         return parent;
+      }
+    return NULL;
+}
+
+AtspiAccessible *structural_navi_level_down(AtspiAccessible *current)
+{
+   AtspiAccessible *ret;
+
+   Eina_List *children = _atspi_children_list_get(current);
+   Eina_List *sorted = _flat_review_get(children);
+
+   ret = eina_list_data_get(sorted);
+
+   eina_list_free(sorted);
+   _atspi_children_list_free(children);
+
+   return ret;
+}
+
+static AtspiAccessible*
+_navi_app_chain_next(AtspiAccessible *current, AtspiRelationType search_type)
+{
+   GArray *relations;
+   AtspiAccessible *ret = NULL;
+   AtspiRelation *relation;
+   AtspiRelationType type;
+   int i;
+
+   relations = atspi_accessible_get_relation_set(current, NULL);
+
+    for (i = 0; i < relations->len; i++)
+      {
+         relation = g_array_index (relations, AtspiRelation*, i);
+         type = atspi_relation_get_relation_type(relation);
+
+         if (type == search_type)
+           {
+              ret = atspi_relation_get_target(relation, 0);
+              break;
+           }
+      }
+
+   g_array_free(relations, TRUE);
+   return ret;
+}
+
+AtspiAccessible *structural_navi_app_chain_next(AtspiAccessible *current)
+{
+   return _navi_app_chain_next(current, ATSPI_RELATION_FLOWS_TO);
+}
+
+AtspiAccessible *structural_navi_app_chain_prev(AtspiAccessible *current)
+{
+   return _navi_app_chain_next(current, ATSPI_RELATION_FLOWS_FROM);
+}
diff --git a/src/window_tracker.c b/src/window_tracker.c
new file mode 100644 (file)
index 0000000..608a486
--- /dev/null
@@ -0,0 +1,90 @@
+#include <string.h>
+#include "window_tracker.h"
+#include "logger.h"
+
+static Window_Tracker_Cb user_cb;
+static void *user_data;
+static AtspiEventListener *listener;
+static AtspiAccessible *last_active_win;
+
+static void
+_on_atspi_window_cb(const AtspiEvent *event)
+{
+   if (!strcmp(event->type, "window:activate") ||
+       !strcmp(event->type, "window:restore"))
+     {
+        if (last_active_win != event->source)
+            {
+              if (user_cb) user_cb(user_data, event->source);
+              last_active_win = event->source;
+            }
+     }
+   else if (!strcmp(event->type, "window:deactivate") ||
+            !strcmp(event->type, "window:destroy"))
+     {
+        if ((last_active_win == event->source) &&
+            user_cb)
+          user_cb(user_data, NULL);
+        last_active_win = NULL;
+     }
+}
+
+static AtspiAccessible*
+_get_active_win(void)
+{
+   int i, j;
+   last_active_win = NULL;
+   AtspiAccessible *desktop = atspi_get_desktop(0);
+
+   for (i = 0; i < atspi_accessible_get_child_count(desktop, NULL); i++) {
+       AtspiAccessible *app = atspi_accessible_get_child_at_index(desktop, i, NULL);
+       for (j = 0; j < atspi_accessible_get_child_count(app, NULL); j++) {
+          AtspiAccessible *win = atspi_accessible_get_child_at_index(app, j, NULL);
+          AtspiStateSet *states = atspi_accessible_get_state_set(win);
+          AtspiRole role = atspi_accessible_get_role(win, NULL);
+
+          if ((atspi_state_set_contains(states, ATSPI_STATE_ACTIVE)) && (role == ATSPI_ROLE_WINDOW))
+            {
+               g_object_unref(states);
+               last_active_win = win;
+               break;
+            }
+          g_object_unref(states);
+       }
+   }
+   return last_active_win;
+}
+
+void window_tracker_init(void)
+{
+   listener = atspi_event_listener_new_simple(_on_atspi_window_cb, NULL);
+   atspi_event_listener_register(listener, "window:activate", NULL);
+   atspi_event_listener_register(listener, "window:deactivate", NULL);
+   atspi_event_listener_register(listener, "window:restore", NULL);
+   atspi_event_listener_register(listener, "window:destroy", NULL);
+}
+
+void window_tracker_shutdown(void)
+{
+   atspi_event_listener_deregister(listener, "window:activate", NULL);
+   atspi_event_listener_deregister(listener, "window:deactivate", NULL);
+   atspi_event_listener_deregister(listener, "window:restore", NULL);
+   atspi_event_listener_deregister(listener, "window:destroy", NULL);
+   g_object_unref(listener);
+   listener = NULL;
+   user_cb = NULL;
+   user_data = NULL;
+   last_active_win = NULL;
+}
+
+void window_tracker_register(Window_Tracker_Cb cb, void *data)
+{
+   user_cb = cb;
+   user_data = data;
+}
+
+void window_tracker_active_window_request(void)
+{
+   _get_active_win();
+   if (user_cb) user_cb(user_data, last_active_win);
+}
diff --git a/src/xml_parser.c b/src/xml_parser.c
new file mode 100755 (executable)
index 0000000..77d875a
--- /dev/null
@@ -0,0 +1,1196 @@
+#include <stdbool.h>
+#include <Eina.h>
+#include "xml_parser.h"
+#include "logger.h"
+
+#define BUF_SIZE 1024
+
+
+void test_fun()
+{
+       DEBUG("HELLO LIB\n");
+}
+
+
+typedef struct
+{
+       char *key;
+       int values_count;
+       char **values;
+} Attribute_Info;
+
+
+typedef struct
+{
+       int attribute_count;
+       char *tag_type;
+       Eina_Simple_XML_Type type;
+       Attribute_Info **available_arguments;
+} Item_Info;
+
+typedef struct
+{
+       const char *descr;
+       Item_Info *item_info;
+
+       const char *current_tag;
+       int current_tag_len;
+       int current_offset;
+       const char *error_message;
+
+       Eina_Bool xml_header;
+       Eina_Bool complex_header;
+       Eina_Bool tag_validation;
+
+       Eina_List *tag_stash;
+       Eina_List *available_tags;
+
+       int call_count;
+       int last_error_offset;
+       int last_error_line;
+
+
+       Eina_List *found_names;
+} S_is_xml;
+
+S_is_xml is_xml;
+
+#ifndef EINA_INLIST_FREE
+       #define EINA_INLIST_FREE(list, it) \
+               for(it = (__typeof__(it)) list; list; it = (__typeof__(it)) list)
+#endif
+
+
+// =========================================== Print ==============================
+
+void print_tree(Eina_Simple_XML_Node_Tag *tag, int text_offset)
+{
+       DEBUG(": %s start\n", __FUNCTION__);
+
+       if(tag == NULL)
+       {
+               DEBUG("No tree found\n");
+       }
+       else if(tag->base.type == EINA_SIMPLE_XML_NODE_ROOT)
+       {
+               DEBUG("Tree of root\n");
+       }
+
+       DEBUG("%s\n\n", eina_simple_xml_node_dump(&tag->base, " "));
+}
+
+// ========================= is xml description callbacks =========================
+
+static Eina_Bool
+is_xml_description_cb(void *data, Eina_Simple_XML_Type type, const char *content, unsigned offset, unsigned length)
+{
+       DEBUG(": %s start\n", __FUNCTION__);
+
+       S_is_xml *is_xml = data;
+
+       if(type != EINA_SIMPLE_XML_IGNORED)
+       {
+               is_xml->call_count++;
+       }
+
+       DEBUG("CONTENT: %.*s\n", length, content);
+
+       switch(type)
+       {
+               case EINA_SIMPLE_XML_PROCESSING:
+                       DEBUG("EINA_SIMPLE_XML_PROCESSING\n");
+                       if(!strncmp(content, "xml version=\"1.0\" encoding=\"UTF-8\"", length) && is_xml->call_count <= 2)
+                       {
+                               is_xml->xml_header = true;
+                       }
+               break;
+               case EINA_SIMPLE_XML_OPEN_EMPTY:
+                       DEBUG("EINA_SIMPLE_XML_OPEN_EMPTY\n");
+                       if(!strncmp(content, "org_tizen_complex_desc", length) && is_xml->call_count <= 2)
+                       {
+                               is_xml->complex_header = true;
+                       }
+               break;
+               default:
+               break;
+       }
+
+       if(is_xml->complex_header && is_xml->xml_header)
+       {
+               return EINA_FALSE;
+       }
+
+       return EINA_TRUE;
+}
+
+// ========================= is xml description =========================
+S_is_xml is_xml;
+
+Attribute_Info *attribute_info_new(char *key, char **values, int count)
+{
+       Attribute_Info *attr = calloc(1, sizeof(Attribute_Info));
+
+       attr->key = key;
+       attr->values = values;
+       attr->values_count = count;
+
+       return attr;
+}
+
+void add_test_tag(char *tag, Eina_Simple_XML_Type type, Attribute_Info **attr, int attribute_count)
+{
+       Item_Info *ii = calloc(1, sizeof(Item_Info));
+       ii->tag_type = tag;
+       ii->type = type;
+       ii->attribute_count = attribute_count;
+       ii->available_arguments = attr;
+
+
+       is_xml.available_tags = eina_list_append(is_xml.available_tags, ii);
+}
+
+Eina_Bool is_xml_description(char *desc)
+{
+       is_xml.descr = desc;
+       is_xml.xml_header = false;
+       is_xml.complex_header = false;
+       is_xml.tag_validation = true;
+       is_xml.available_tags = NULL;
+
+       is_xml.call_count = 0;
+       is_xml.last_error_offset = 0;
+       is_xml.last_error_line = 1;
+
+       is_xml.found_names = NULL;
+
+       Attribute_Info *attr_info[3];
+       attr_info[0] = attribute_info_new("name", NULL, 0);
+       attr_info[1] = attribute_info_new("level", NULL, 0);
+       char *actions_info[2];
+       actions_info[0] = "on_focus";
+       actions_info[1] = "on_activate";
+       attr_info[2] = attribute_info_new("action", actions_info, 2);
+       add_test_tag("Information_Level", EINA_SIMPLE_XML_OPEN, attr_info, 3);
+
+       int size = strlen(desc);
+
+       eina_simple_xml_parse(desc, size, EINA_TRUE, is_xml_description_cb, &is_xml);
+
+       if(is_xml.complex_header && is_xml.xml_header)
+       {
+               return true;
+       }
+       else
+       {
+               return false;
+       }
+}
+
+/* ****************************************************************************************************** */
+
+
+// =========================================== Create Tree ==============================
+Eina_Simple_XML_Node_Tag *find_item_by_params(Eina_Simple_XML_Attribute **pairs, const char *name, Eina_Simple_XML_Node_Tag *tag);
+const char *get_param(Eina_Simple_XML_Node_Tag *item, char *key);
+
+int find_children_count_by_params(Eina_Simple_XML_Attribute **pairs,
+               const char *searched_tag_name, Eina_Inlist *first, int limit)
+{
+       DEBUG(" ");
+       Eina_Simple_XML_Node *child_node;
+       Eina_Simple_XML_Node_Tag *to_ret;
+       Eina_Simple_XML_Attribute *attr;
+       int counter = 0;
+       int attr_count;
+
+       DEBUG("============================\n");
+       DEBUG("SEARCHED: %s\n",searched_tag_name);
+
+       int i =0;
+       for(i = 0; pairs[i] != NULL; ++i)
+       {
+               DEBUG("%s = \"%s\"\n", pairs[i]->key, pairs[i]->value);
+       }
+
+       DEBUG("END PAIRS\n");
+
+       if(first && eina_inlist_count(first) > 0)
+       {
+               EINA_INLIST_FOREACH(first, child_node)
+               {
+                       if(child_node->type == EINA_SIMPLE_XML_NODE_TAG)
+                       {
+                               Eina_Simple_XML_Node_Tag *child_tag = (Eina_Simple_XML_Node_Tag *)child_node;
+
+                               const char *name = get_param(child_tag, "name");
+                               int param_count = 0;
+
+                               for(i = 0; pairs[i] != NULL; ++i)
+                               {
+                                       param_count++;
+                               }
+
+                               if(name != NULL)
+                               {
+                                       attr_count = eina_inlist_count(child_tag->attributes) - 1;
+                               }
+                               else
+                               {
+                                       attr_count = eina_inlist_count(child_tag->attributes);
+                               }
+
+                               DEBUG("Child: %s > ", child_tag->name);
+                               EINA_INLIST_FOREACH(child_tag->attributes, attr)
+                               {
+                                       DEBUG("%s = \"%s\" ", attr->key, attr->value);
+                               }
+
+                               DEBUG("\n");
+
+                               DEBUG("ATTR COUNT: %d <>  PARAM_COUT: %d\n", attr_count, param_count);
+
+                               if(attr_count == param_count)
+                               {
+                                       to_ret = find_item_by_params(pairs, searched_tag_name, child_tag);
+
+                                       if(to_ret)
+                                       {
+                                               DEBUG("to_ret: %s > ", to_ret->name);
+                                               EINA_INLIST_FOREACH(to_ret->attributes, attr)
+                                               {
+                                                       DEBUG("%s = \"%s\" ", attr->key, attr->value);
+                                               }
+                                       }
+                                       else
+                                       {
+                                               DEBUG("to_ret == NULL");
+                                       }
+
+                                       DEBUG("\n");
+
+                                       if(to_ret != NULL)
+                                       {
+                                               counter++;
+                                       }
+
+
+                                       if(counter >= limit)
+                                       {
+                                               DEBUG("ERROR   \n");
+                                               return counter;
+                                       }
+                               }
+                       }
+               }
+       }
+
+       return counter;
+}
+
+void find_duplicates(Eina_Simple_XML_Node_Tag *pattern, Eina_Inlist *first)
+{
+       Eina_Simple_XML_Attribute **pairs = NULL;
+       int attr_count = eina_inlist_count(pattern->attributes);
+
+       Eina_Simple_XML_Attribute *key = NULL;
+
+       pairs = calloc(attr_count + 1, sizeof(Eina_Simple_XML_Attribute **));
+
+       int i = 0;
+       EINA_INLIST_FOREACH(pattern->attributes, key)
+       {
+
+               if(strcmp(key->key, "name") != 0)
+               {
+                       pairs[i] =  key;
+                       ++i;
+               }
+       }
+
+       int found_count = 0;
+       if(strcmp(pattern->name, "Information_Level") == 0)
+       {
+               found_count = find_children_count_by_params(pairs, pattern->name, first, 1);
+               DEBUG("FOUND COUNT %d\n", found_count);
+       }
+
+
+       if(found_count >= 1)
+       {
+               DEBUG("Found widgets: %d\n", found_count);
+               DEBUG("->->->->->->->->-> Error in XML tree: duplicate of %s found\n", pattern->name);
+       }
+
+
+}
+
+
+void traverse_xml_tree(Eina_Simple_XML_Node_Tag *top)
+{
+       Eina_Simple_XML_Node *node;
+       Eina_Simple_XML_Node_Tag *child;
+
+       EINA_INLIST_FOREACH(top->children, node)
+       {
+               if(node->type == EINA_SIMPLE_XML_NODE_TAG)
+               {
+                       child = (Eina_Simple_XML_Node_Tag *)node;
+
+                       DEBUG(">>>>>>>>>>>>>>> CHILD TYPE: %s\n", child->name);
+
+                       find_duplicates(child, EINA_INLIST_GET(node)->next);
+                       traverse_xml_tree(child);
+               }
+       }
+}
+
+
+Eina_Simple_XML_Node_Root *create_tree(char *desc, bool test_duplicates)
+{
+       DEBUG(": %s start\n", __FUNCTION__);
+       Eina_Simple_XML_Node_Root* root = eina_simple_xml_node_load(desc, strlen(desc) - 1, true);
+
+       print_tree(root, 4);
+
+       if(test_duplicates == true)
+       {
+               traverse_xml_tree(root);
+       }
+
+       return root;
+}
+
+
+// ========================= Search functions =========================
+Eina_Simple_XML_Node_Tag *find_item_by_params(Eina_Simple_XML_Attribute **pairs, const char *name, Eina_Simple_XML_Node_Tag *tag)
+{
+       int i = 0;
+
+       Eina_Simple_XML_Attribute *arg;
+
+       int conditions = 0;
+       int found_matches = 0;
+
+       DEBUG(": %s start\n", __FUNCTION__);
+
+       if(tag->base.type !=  EINA_SIMPLE_XML_NODE_TAG )
+       {
+               DEBUG("Not a tag\n");
+               return NULL;
+       }
+
+       if(name == NULL || !strcmp(name, tag->name)) //tag == NULL means that we don't care about tag name
+       {
+               DEBUG("Found tag with name: %s\n", tag->name);
+
+               if(pairs) //no attributes means that we search only by tag name
+               {
+                       for(i = 0; pairs[i] != NULL; ++i)
+                       {
+                                       conditions++;
+                       }
+
+                       EINA_INLIST_FOREACH(tag->attributes, arg)
+                       {
+                               for(i = 0; pairs[i] != NULL; ++i)
+                               {
+                                       int cmp1 = strcmp(pairs[i]->key, arg->key);
+                                       int cmp2 = strcmp(pairs[i]->value, arg->value); //Strange code needed for debuging
+
+                                       if(!cmp1 && !cmp2)
+                                       {
+                                               found_matches++;
+                                       }
+                               }
+
+                               if(found_matches == conditions)
+                               {
+                                       return tag;
+                               }
+                       }
+               }
+               else
+               {
+                       return tag;
+               }
+       }
+
+       DEBUG("%s RETURNING NULL\n", __FUNCTION__);
+       return NULL;
+}
+
+
+Eina_Simple_XML_Node_Tag *find_child_by_params(Eina_Simple_XML_Attribute **pairs, const char *searched_tag_name, Eina_Simple_XML_Node_Tag *tag)
+{
+       DEBUG(" ");
+       Eina_Simple_XML_Node *child_node;
+       Eina_Simple_XML_Node_Tag *to_ret;
+
+       if(tag->base.type !=  EINA_SIMPLE_XML_NODE_TAG && tag->base.type !=  EINA_SIMPLE_XML_NODE_ROOT)
+       {
+               return NULL;
+       }
+
+       if(tag->children && eina_inlist_count(tag->children) > 0)
+       {
+               EINA_INLIST_FOREACH(tag->children, child_node)
+               {
+                       to_ret = find_item_by_params(pairs, searched_tag_name, (Eina_Simple_XML_Node_Tag *)child_node);
+
+                       if(to_ret != NULL)
+                               return to_ret;
+               }
+       }
+
+       DEBUG("%s RETURNING NULL\n", __FUNCTION__);
+       return NULL;
+}
+
+Eina_Simple_XML_Node_Tag *find_item_by_params_recursive(Eina_Simple_XML_Attribute **pairs, const char *name, Eina_Simple_XML_Node_Tag *top_tag)
+{
+       Eina_Simple_XML_Node_Tag *tag = find_item_by_params(pairs, name, top_tag);
+
+       if(tag != NULL)
+       {
+               return tag;
+       }
+       else
+       {
+               return find_child_by_params(pairs, name, top_tag);
+       }
+
+       //TODO: Czy to napewno zadziała bo chyba nie
+
+}
+
+
+
+const char *get_param(Eina_Simple_XML_Node_Tag *item, char *key)
+{
+       DEBUG(" ");
+       Eina_Simple_XML_Attribute *attribute;
+
+       EINA_INLIST_FOREACH(item->attributes, attribute)
+       {
+               if(strcmp(attribute->key, key) == 0)
+               {
+                       return attribute->value;
+               }
+       }
+
+       return NULL;
+}
+
+Eina_Inlist *find_refs(Eina_Simple_XML_Node_Tag *root, Eina_Simple_XML_Node_Tag *tag, Eina_Inlist *refs)
+{
+       DEBUG(" ");
+       Eina_Simple_XML_Node *child;
+
+       Eina_Simple_XML_Attribute *names[2] = {NULL, NULL};
+       DEBUG("Tag name: %s\n", tag->name);
+
+       EINA_INLIST_FOREACH(tag->children, child)
+       {
+               DEBUG("Child type: %d\n", child->type);
+
+               if(child->type == EINA_SIMPLE_XML_NODE_TAG || child->type == EINA_SIMPLE_XML_NODE_ROOT)
+               {
+                       Eina_Simple_XML_Node_Tag *child_tag = (Eina_Simple_XML_Node_Tag *)child;
+                       DEBUG("CHILD TAG NAME: %s\n", child_tag->name);
+
+                       if(!strcmp(child_tag->name, "Ref"))
+                       {
+                               DEBUG("Ref found\n");
+                               const char *value = get_param(child_tag, "name");
+                               names[0] = eina_simple_xml_attribute_new(NULL, "name", value);
+
+
+                               Eina_Simple_XML_Node_Tag *found_child_tag = find_item_by_params_recursive(names,  NULL, root);
+                               Eina_Simple_XML_Node *found_child = &found_child_tag->base;
+
+                               refs = eina_inlist_append(refs, EINA_INLIST_GET(found_child));
+
+                               refs = find_refs(root, found_child_tag, refs);
+                       }
+               }
+       }
+
+       return refs;
+}
+
+Eina_Inlist *find_refs_and_children(Eina_Simple_XML_Node_Tag *root, Eina_Simple_XML_Node_Tag *tag, Eina_Inlist *refs, char **children_xml, Tag *tags, bool *selected)
+{
+       DEBUG(" ");
+       Eina_Simple_XML_Node *child;
+
+       Eina_Simple_XML_Attribute *names[2] = {NULL, NULL};
+       DEBUG("Tag name: %s\n", tag->name);
+
+       EINA_INLIST_FOREACH(tag->children, child)
+       {
+               DEBUG("Child type: %d\n", child->type);
+
+               if(child->type == EINA_SIMPLE_XML_NODE_TAG || child->type == EINA_SIMPLE_XML_NODE_ROOT)
+               {
+                       Eina_Simple_XML_Node_Tag *child_tag = (Eina_Simple_XML_Node_Tag *)child;
+                       DEBUG("CHILD TAG NAME: %s\n", child_tag->name);
+
+                       if(strcmp(child_tag->name, "Ref") == 0 || strcmp(child_tag->name, "Read_Children") == 0 || strcmp(child_tag->name, "Text_Block") == 0)
+                       {
+                               if(child_tag->name[2] == 'f')
+                               {
+                                       DEBUG("Ref found\n");
+                                       const char *value = get_param(child_tag, "name");
+                                       names[0] = eina_simple_xml_attribute_new(NULL, "name", value);
+
+
+                                       Eina_Simple_XML_Node_Tag *found_child_tag = find_item_by_params_recursive(names,  NULL, root);
+                                       Eina_Simple_XML_Node *found_child = &found_child_tag->base;
+
+                                       refs = eina_inlist_append(refs, EINA_INLIST_GET(found_child));
+                                       refs = find_refs_and_children(root, found_child_tag, refs, children_xml, tags, selected);
+                               }
+                               /*else if(child_tag->name[2] == 'x') //TODO
+                               {
+                                       DEBUG("Text_Block found\n");
+                                       refs = eina_inlist_append(refs, child);
+                                       refs = find_refs_and_children(root, child, refs, children_xml, tags, selected);
+                               }*/
+                               else if(child_tag->name[2] == 'a')
+                               {
+                                       int i = 0;
+                                       DEBUG("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! CHILDREN FOUND \n");
+
+                                       for(i = 0; children_xml[i] != NULL; ++i)
+                                       {
+                                               Eina_Simple_XML_Attribute *child_xml_attr[2] = {NULL, NULL};
+                                               const char *value = get_param(child_tag, "level");
+                                               const char *mode = get_param(child_tag, "mode");
+                                               bool mode_val;
+
+                                               if(mode != NULL && strcmp(mode, "selected") == 0)
+                                                       mode_val = true;
+                                               else
+                                                       mode_val = false;
+
+                                               DEBUG("selected: %d\n", selected[i]);
+                                               if((mode_val == true && selected[i] == true) || mode_val == false)
+                                               {
+                                                       child_xml_attr[0] = eina_simple_xml_attribute_new(NULL, "level", value);
+
+                                                       DEBUG("Attribute: %s=%s\n", child_xml_attr[0]->key, child_xml_attr[0]->value);
+
+                                                       char *string = get_string_str(tags, children_xml[i], child_xml_attr, "Information_Level");
+
+                                                       DEBUG("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! String from child %s\n", string);
+
+                                                       Eina_Simple_XML_Node_Data *found_node_data = eina_simple_xml_node_data_new(NULL, string, strlen(string)+ 1);
+                                                       Eina_Simple_XML_Node *found_data = &found_node_data->base;
+
+
+                                                       DEBUG("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! AFTER NEW NODE\n");
+
+                                                       refs = eina_inlist_append(refs, EINA_INLIST_GET(found_data));
+                                                       eina_simple_xml_attribute_free(child_xml_attr[0]);
+                                               }
+                                       }
+                               }
+                       }
+               }
+       }
+
+
+       DEBUG("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! RETURNING\n");
+       return refs;
+}
+
+
+char *concat_string(Eina_Inlist *nodes)
+{
+       DEBUG(" ");
+       Eina_Simple_XML_Node *node = NULL;
+       Eina_Simple_XML_Node_Tag *tag = NULL;
+
+       Eina_Simple_XML_Node *child_node = NULL;
+       Eina_Simple_XML_Node_Data *data = NULL;
+
+       Eina_Strbuf *buf = eina_strbuf_new();
+
+       EINA_INLIST_FOREACH(nodes, node)
+       {
+               tag = (Eina_Simple_XML_Node_Tag *)node;
+
+               if(node->type == EINA_SIMPLE_XML_NODE_TAG)
+               {
+                       EINA_INLIST_FOREACH(tag->children, child_node)
+                       {
+                               if(child_node->type == EINA_SIMPLE_XML_NODE_DATA)
+                               {
+                                       data = (Eina_Simple_XML_Node_Data *)child_node;
+                                       eina_strbuf_append_n(buf, data->data, data->length);
+                                       eina_strbuf_append(buf, ". ");
+                               }
+
+                       }
+               }
+               else if(node->type == EINA_SIMPLE_XML_NODE_DATA)
+               {
+                       data = (Eina_Simple_XML_Node_Data *)node;
+                       eina_strbuf_append_n(buf, data->data, data->length);
+                       eina_strbuf_append(buf, ". ");
+               }
+       }
+
+       char *to_ret = eina_strbuf_string_steal(buf);
+       eina_strbuf_free(buf);
+       return to_ret;
+}
+
+/* ========================= get string from description ========================= */
+char *get_string_tree(Tag *tags, Eina_Simple_XML_Node_Tag *root, Eina_Simple_XML_Attribute **pairs, char *tag_name)
+{
+       DEBUG(" ");
+       Eina_Simple_XML_Node_Tag *top_tag = root;
+       int i = 0;
+       Tag *current_tag = NULL;
+
+       DEBUG("BEFORE TAGS\n");
+       if(tags != NULL)
+       {
+               DEBUG("IN TAGS\n");
+               current_tag = &tags[0];
+
+               while(current_tag->tag_type != NULL)
+               {
+                       DEBUG("Top item before: %s\n", top_tag->name);
+
+                       top_tag = find_child_by_params(current_tag->pairs, current_tag->tag_type, top_tag);
+
+                       DEBUG("Top item after: %p\n", top_tag);
+
+                       i++;
+                       current_tag = &tags[i];
+               }
+
+               if(top_tag == NULL)
+               {
+                       DEBUG("%s RETURNING NULL\n", __FUNCTION__);
+                       return NULL;
+               }
+
+       }
+
+
+
+       DEBUG("-----------================   Searching...   ================-----------\n");
+
+       if(top_tag->base.type == EINA_SIMPLE_XML_NODE_TAG)
+       {
+               DEBUG("SEARCH TOP LEVEL: %s\n", top_tag->name);
+       }
+       else if(top_tag->base.type == EINA_SIMPLE_XML_NODE_ROOT)
+       {
+               DEBUG("SEARCH FROM ROOT\n");
+       }
+
+       Eina_Simple_XML_Node_Tag *tag = find_child_by_params(pairs, tag_name, top_tag);
+
+       Eina_Inlist *refs = NULL;
+
+       if(tag == NULL)
+       {
+               DEBUG("returning NULL %s\n", __FUNCTION__);
+               return NULL;
+       }
+
+       refs = find_refs(root, tag, refs);
+
+       Eina_Simple_XML_Node *node = &tag->base;
+       refs = eina_inlist_prepend(refs, EINA_INLIST_GET(node)); //need to add the found item to the list so it's
+                                                                                       //string can be added to output
+
+       char *the_string = concat_string(refs);
+
+       return the_string;
+}
+
+char *get_string_str(Tag *tags, char *descr, Eina_Simple_XML_Attribute **pairs, char *tag_name)
+{
+       DEBUG(" ");
+       bool xml = is_xml_description(descr);
+
+       if(xml == true)
+       {
+               Eina_Simple_XML_Node_Root *root = create_tree(descr, false);
+               char *the_string = get_string_tree(tags, root, pairs, tag_name);
+
+               return the_string;
+       }
+       else
+       {
+               return descr;
+       }
+}
+
+const char *list_pop(Eina_List **list)
+{
+       DEBUG("Popping tag\n");
+       Eina_List *l;
+       DEBUG("Get Last\n");
+       l = eina_list_last(*list);
+       DEBUG("Get data\n");
+       const char *content = eina_list_data_get(l);
+       DEBUG("Remove\n");
+       *list = eina_list_remove_list(*list, l);
+       return content;
+}
+
+
+//void get_error_messgage(const char *message, const char *tag, S_is_xml *is_xml, int offset, int length)
+void get_error_messgage(S_is_xml *is_xml)
+{
+       int line_count =is_xml->last_error_line;
+       int i = 0;
+       for(i = is_xml->last_error_offset; i < is_xml->current_offset; ++i)
+       {
+               if(is_xml->descr[i] == '\n')
+               {
+                       line_count++;
+               }
+       }
+
+       DEBUG("->->->->->->->->-> Error in XML validation: %s", is_xml->error_message);
+
+       if(is_xml->current_tag)
+       {
+               DEBUG(" %*.*s\n", is_xml->current_tag_len, is_xml->current_tag_len, is_xml->current_tag);
+       }
+
+       DEBUG(" line: %d\n", line_count);
+
+       is_xml->last_error_offset = is_xml->current_offset;
+       is_xml->last_error_line = line_count;
+
+}
+
+static Eina_Bool
+_xml_attr_cb(void *data, const char *key, const char *value)
+{
+       DEBUG("Test attribute\n");
+
+       S_is_xml *is_xml = data;
+       Item_Info *ii = is_xml->item_info;
+       Attribute_Info *ai;
+       int i, j;
+       Eina_Bool key_found = EINA_FALSE;
+       DEBUG("Tag NAME: %s\n", ii->tag_type);
+       Eina_List *l;
+       char *name = NULL;
+       bool name_found = false;
+
+       if(strcmp(key, "name") == 0)
+       {
+               DEBUG("NAME key found\n");
+               EINA_LIST_FOREACH(is_xml->found_names, l, name)
+               {
+                       DEBUG("Testing names: %s vs %s\n", name, value);
+
+                       if(name != NULL && strcmp(value, name) == 0)
+                       {
+                               name_found = true;
+                               break;
+                       }
+               }
+
+               DEBUG("After Loop\n");
+
+               if(name_found == false)
+               {
+                       DEBUG("Add name to list: %s\n", value);
+                       is_xml->found_names = eina_list_append(is_xml->found_names, eina_stringshare_add(value));
+               }
+               else
+               {
+                       DEBUG("Name already exists: %s\n", value);
+                       is_xml->error_message = "Name already exists";
+                       is_xml->tag_validation = 0;
+                       get_error_messgage(is_xml);
+               }
+       }
+       else if(strcmp(key, "refs") == 0)
+       {
+               DEBUG("NAME key found\n");
+               EINA_LIST_FOREACH(is_xml->found_names, l, name)
+               {
+                       DEBUG("Testing names: %s vs %s\n", name, value);
+
+                       if(name != NULL && strcmp(value, name) == 0)
+                       {
+                               name_found = true;
+                               break;
+                       }
+               }
+
+               DEBUG("Name already exists: %s\n", value);
+               is_xml->error_message = "Cannot reference tag with given name";
+               is_xml->tag_validation = 0;
+               get_error_messgage(is_xml);
+
+               DEBUG("After Loop\n");
+
+               if(name_found == false)
+               {
+                       DEBUG("Add name to list: %s\n", value);
+                       is_xml->found_names = eina_list_append(is_xml->found_names, eina_stringshare_add(value));
+               }
+               else
+               {
+
+               }
+       }
+
+
+
+       if(ii->attribute_count > 0)
+       {
+               for(i = 0; i < ii->attribute_count; ++i)
+               {
+                       DEBUG("Get attribute\n");
+
+                       ai = ii->available_arguments[i];
+
+                       DEBUG("Test attribute: \n%s\n%s   key_found: %d\n", key, ai->key, key_found);
+                       if(strcmp(key, ai->key) == 0)
+                       {
+                               DEBUG("Attribute found: \n%s\n%s\n", key, ai->key);
+                               key_found = EINA_TRUE;
+
+                               DEBUG("Iterate values count: %d\n", ai->values_count);
+                               if(ai->values_count)
+                               {
+                                       for(j = 0; j < ai->values_count; ++j)
+                                       {
+                                               DEBUG("Compare values \n%s\n%s\n", value, ai->values[j]);
+                                               if(strcmp(ai->values[j], value) == 0)
+                                               {
+                                                       return EINA_TRUE;
+                                               }
+                                       }
+                               }
+                               else
+                               {
+                                       DEBUG("KEY OK\n");
+                                       return EINA_TRUE;
+                               }
+                       }
+               }
+       }
+       else
+       {
+               DEBUG("->->->->->->->->->->->-> Argument in no-argument tag: %s in tag: %s\n", key, ii->tag_type);
+
+               is_xml->error_message = "Argument in no-argument tag";
+               is_xml->tag_validation = 0;
+               get_error_messgage(is_xml);
+               return EINA_FALSE;
+       }
+
+       DEBUG("key_found %d\n", key_found);
+
+       if(key_found == EINA_FALSE)
+       {
+               DEBUG("->->->->->->->->->->->-> Unknown attribute: %s in tag: %s\n", key, ii->tag_type);
+               is_xml->error_message = "Unknown attribute in";
+               is_xml->tag_validation = 0;
+               get_error_messgage(is_xml);
+       }
+       else
+       {
+               DEBUG("->->->->->->->->->->->-> Unknown attribute value: %s with key: %s. Tag: %s\n", value, key, ii->tag_type);
+               is_xml->error_message = "Unknown attribute value ";
+               is_xml->tag_validation = 0;
+               get_error_messgage(is_xml);
+       }
+
+       return EINA_TRUE;
+}
+
+
+Eina_Bool check_tag(S_is_xml *is_xml, Eina_Simple_XML_Type type, const char *tag, const char *attr, int str_len)
+{
+       DEBUG(" ");
+
+       if(is_xml->available_tags == NULL)
+       {
+               DEBUG("No available tags\n");
+               return true;
+       }
+
+       Eina_List *l;
+       Item_Info *ii;
+
+       int len = 0;
+       if(attr)
+       {
+               len = attr - tag - 1;
+       }
+       else
+       {
+               len = str_len;
+       }
+
+       DEBUG("TAG: %*.*s type: %d\n", len, len, tag, type);
+
+       EINA_LIST_FOREACH(is_xml->available_tags, l, ii)
+       {
+               DEBUG("Wzorzec: %*.*s %d\n", len, len, ii->tag_type, ii->type);
+
+               if(strncmp(tag, ii->tag_type, len - 1) == 0 && type == ii->type)
+               {
+                       is_xml->item_info = ii;
+                       is_xml->current_offset = tag - is_xml->descr;
+                       is_xml->current_tag_len = str_len;
+                       is_xml->current_tag = tag;
+                       eina_simple_xml_attributes_parse(attr, str_len - (attr - tag), _xml_attr_cb, is_xml);
+                       return EINA_TRUE;
+               }
+       }
+
+       return EINA_FALSE;
+}
+
+
+
+Eina_Simple_XML_Node_Tag *modify_tag(Tag *tags,  Eina_Simple_XML_Node_Tag *root,
+               const char *tag_name,     Eina_Simple_XML_Attribute **pairs,
+               const char *new_tag_name, Eina_Simple_XML_Attribute **new_pairs, const char *new_data)
+{
+       DEBUG(": %s start\n", __FUNCTION__);
+
+       Eina_Simple_XML_Node_Tag *top_tag = NULL;
+       Eina_Simple_XML_Node_Tag *tag = NULL;
+       Tag *current_tag = NULL;
+
+       if(root == NULL)
+       {
+               DEBUG("Root == NULL\n");
+
+               char *buf = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+                                       "<org_tizen_complex_desc/>\n";
+
+               root = eina_simple_xml_node_load (buf, strlen(buf), EINA_TRUE);
+               top_tag = root;
+       }
+       else
+       {
+               DEBUG("Root != NULL\n");
+               top_tag = root;
+
+               if(tags != NULL)
+               {
+                       DEBUG("Tags != NULL\n");
+                       DEBUG("IN TAGS\n");
+                       current_tag = &tags[0];
+
+                       int i = 0;
+                       while(current_tag->tag_type != NULL)
+                       {
+                               DEBUG("Top item before: %s\n", top_tag->name);
+
+                               top_tag = find_child_by_params(current_tag->pairs, current_tag->tag_type, top_tag);
+
+                               DEBUG("Top item after: %s\n", top_tag->name);
+
+                               i++;
+                               current_tag = &tags[i];
+                       }
+
+                       if(top_tag == NULL)
+                       {
+                               return NULL;
+                       }
+               }
+
+               if(top_tag->base.type == EINA_SIMPLE_XML_NODE_TAG)
+               {
+                       DEBUG("SEARCH TOP LEVEL: %s\n", top_tag->name);
+               }
+               else if(top_tag->base.type == EINA_SIMPLE_XML_NODE_ROOT)
+               {
+                       DEBUG("SEARCH FROM ROOT\n");
+               }
+
+               tag = find_child_by_params(pairs, tag_name, top_tag);
+       }
+
+       //add new tag to xml tree
+       if(tag == NULL)
+       {
+               DEBUG("Adding new tag\n");
+
+               tag = eina_simple_xml_node_tag_new(top_tag, new_tag_name);
+
+               DEBUG("Adding new tag %s\n", __FUNCTION__);
+
+               //removing attibutes;
+               Eina_Simple_XML_Attribute *attr;
+
+               EINA_INLIST_FOREACH(tag->attributes, attr)
+               {
+                       eina_simple_xml_attribute_free(attr);
+               }
+
+               int i = 0;
+               while(pairs[i] != NULL)
+               {
+                       Eina_Simple_XML_Attribute *attr = new_pairs[i];
+                       eina_simple_xml_attribute_new(tag, attr->key, attr->value);
+                       ++i;
+               }
+       }
+       //Modify existing tag
+       else
+       {
+               DEBUG("Modifying tag %s\n", tag->name);
+
+               Eina_Simple_XML_Node *node;
+               Eina_Simple_XML_Node_Tag *to_remove_tag;
+               Eina_Simple_XML_Node_Data *to_remove_data;
+
+               DEBUG("Removing children\n");
+               EINA_INLIST_FREE(tag->children, node)
+               {
+                       switch(node->type)
+                       {
+                               case EINA_SIMPLE_XML_NODE_ROOT:
+                               case EINA_SIMPLE_XML_NODE_TAG:
+                                       to_remove_tag = (Eina_Simple_XML_Node_Tag *)node;
+                                       eina_simple_xml_node_tag_free(to_remove_tag);
+                               break;
+                               case EINA_SIMPLE_XML_NODE_DATA:
+                                       to_remove_data = (Eina_Simple_XML_Node_Data *)node;
+                                       eina_simple_xml_node_data_free(to_remove_data);
+                               break;
+                               default:
+                               break;
+                       }
+
+               }
+
+               DEBUG("Adding attributes\n");
+
+               Eina_Simple_XML_Attribute *attr;
+
+               DEBUG("Removing old attributes\n");
+               EINA_INLIST_FREE(tag->attributes, attr)
+               {
+                       eina_simple_xml_attribute_free(attr);
+               }
+
+               DEBUG("Adding new attributes\n");
+
+               int i = 0;
+               while(pairs[i] != NULL)
+               {
+                       Eina_Simple_XML_Attribute *attr = new_pairs[i];
+                       eina_simple_xml_attribute_new(tag, attr->key, attr->value);
+                       ++i;
+               }
+
+               DEBUG("Setting name\n");
+               tag->name = eina_stringshare_add(new_tag_name);
+       }
+
+       if(new_data != NULL)
+       {
+               eina_simple_xml_node_data_new(tag, new_data, strlen(new_data));
+       }
+
+       return root;
+}
+
+Eina_Simple_XML_Node_Tag *add_tag(Tag *tags,  Eina_Simple_XML_Node_Tag *root,
+               const char *tag, const char *data, Eina_Simple_XML_Attribute **pairs)
+{
+       Eina_Simple_XML_Node_Tag * ret = modify_tag(tags,  root,
+                                                                                               tag, pairs,
+                                                                                               tag, pairs, data);
+
+       return ret;
+}
+
+Eina_Simple_XML_Node_Tag *add_tag_str(Tag *tags,  Eina_Simple_XML_Node_Root *root, const char *tag_str)
+{
+       Eina_Simple_XML_Node_Root *tag = eina_simple_xml_node_load (tag_str, strlen(tag_str) - 1, EINA_TRUE);
+       Eina_Simple_XML_Node_Tag * ret = root;
+
+       DEBUG("the tag tree:\n");
+       print_tree(tag, 4);
+
+
+       if(tag)
+       {
+               Eina_Simple_XML_Node *root_child_node = NULL;
+               Eina_Simple_XML_Node *child_node = NULL;
+               Eina_Simple_XML_Node_Data *child_node_data = NULL;
+               Eina_Simple_XML_Node_Tag *child_tag =NULL;
+               Eina_Simple_XML_Attribute *attr = NULL;
+               Eina_Simple_XML_Attribute **array = NULL;
+
+               DEBUG("finding data\n");
+
+               EINA_INLIST_FOREACH(tag->children, root_child_node)
+               {
+                       DEBUG("checking children list\n");
+
+                       if(root_child_node->type == EINA_SIMPLE_XML_NODE_TAG)
+                       {
+                               child_tag = (Eina_Simple_XML_Node_Tag *)root_child_node;
+
+                               EINA_INLIST_FOREACH(child_tag->children, child_node)
+                               {
+                                       if(child_node->type == EINA_SIMPLE_XML_NODE_DATA)
+                                       {
+                                               child_node_data = (Eina_Simple_XML_Node_Data *)child_node;
+                                       }
+                               }
+
+                               int list_count = eina_inlist_count(child_tag->attributes);
+                               array = calloc(list_count, sizeof(Eina_Simple_XML_Attribute *));
+
+                               DEBUG("creating attribute array\n");
+
+                               int i = 0;
+                               EINA_INLIST_FOREACH(child_tag->attributes, attr)
+                               {
+                                       array[i] = attr;
+                                       i++;
+                               }
+
+                               DEBUG("Calling modify\n");
+                               DEBUG("Tag name: %s\n", child_tag->name);
+
+                               if(child_node_data != NULL)
+                               {
+                                       ret = modify_tag(tags,  ret,
+                                                                       child_tag->name, array,
+                                                                       child_tag->name, array, child_node_data->data);
+                               }
+                               else
+                               {
+                                       ret = modify_tag(tags,  ret,
+                                                                       child_tag->name, array,
+                                                                       child_tag->name, array, NULL);
+                               }
+
+                               free(array);
+                       }
+               }
+
+               return ret;
+       }
+       else
+       {
+               return NULL;
+       }
+}