int y_beg, y_end; // (x,y) coordinates when gesture ends (screen coords)
pid_t pid; // pid of process on which gesture took place.
int state; // 0 - begin, 1 - ongoing, 2 - ended, 3 - aborted
+ int event_time;
} Gesture_Info;
/**
DEBUG("===============================");
}
+static void _flat_navi_context_current_line_and_object_get(FlatNaviContext *ctx, AtspiAccessible *obj, Eina_List **current_line, Eina_List **current)
+{
+ if(!ctx || !obj) return;
+ Eina_List *l, *l2, *line;
+ AtspiAccessible *tmp;
+
+ EINA_LIST_FOREACH(ctx->lines, l, line)
+ {
+ EINA_LIST_FOREACH(line, l2, tmp)
+ {
+ if (tmp == obj)
+ {
+ *current_line = l;
+ *current = l2;
+ break;
+ }
+ }
+ }
+}
+
+#ifdef SCREEN_READER_FLAT_NAVI_TEST_DUMMY_IMPLEMENTATION
+Eina_Bool flat_navi_context_current_at_x_y_set( FlatNaviContext *ctx, gint x_cord, gint y_cord , AtspiAccessible **target)
+{
+ return EINA_FALSE;
+}
+#else
+
static Eina_Bool
_contains(AtspiAccessible *obj, gint x, gint y)
{
return EINA_FALSE;
}
+static Eina_Bool _flat_navi_context_contains_object(FlatNaviContext *ctx, AtspiAccessible *obj)
+{
+ if(!ctx || !obj) return EINA_FALSE;
+
+ Eina_List *current_line = NULL, *current = NULL;
+
+ _flat_navi_context_current_line_and_object_get(ctx, obj, ¤t_line, ¤t);
+ return current_line != NULL;
+}
Eina_Bool flat_navi_context_current_at_x_y_set( FlatNaviContext *ctx, gint x_cord, gint y_cord , AtspiAccessible **target)
{
if(!ctx || !target) return EINA_FALSE;
- AtspiAccessible *current = flat_navi_context_current_get(ctx);
- if (current && _contains(current, x_cord, y_cord))
+ AtspiAccessible *current_obj = flat_navi_context_current_get(ctx);
+ if (current_obj && _contains(current_obj, x_cord, y_cord))
{
- *target = current;
+ *target = current_obj;
return EINA_TRUE;
}
- Eina_List *l, *l2, *line;
- Eina_Bool found = EINA_FALSE;
- AtspiAccessible *obj;
- EINA_LIST_FOREACH(ctx->lines, l, line)
- {
- EINA_LIST_FOREACH(line, l2, obj)
- if (_contains(obj, x_cord, y_cord))
- {
- found = EINA_TRUE;
- break;
- }
- if (found)
+ if (!ctx->root)
+ {
+ DEBUG("NO top window");
+ return EINA_FALSE;
+ }
+ Eina_Bool ret = EINA_FALSE;
+ GError * error = NULL;
+ AtspiAccessible *obj = g_object_ref(ctx->root);
+ AtspiAccessible *obj_under_finger = NULL;
+ AtspiAccessible *youngest_ancestor_in_context = (_flat_navi_context_contains_object(ctx, obj) ? g_object_ref(obj) : NULL);
+ AtspiComponent *component;
+ Eina_Bool look_for_next_descendant = EINA_TRUE;
+
+ for(;look_for_next_descendant;) {
+ component = atspi_accessible_get_component_iface(obj);
+ obj_under_finger = atspi_component_get_accessible_at_point(atspi_accessible_get_component_iface(obj),
+ x_cord,
+ y_cord,
+ ATSPI_COORD_TYPE_WINDOW,
+ &error
+ );
+ g_clear_object(&component);
+
+ if (error)
{
- *target = obj;
- ctx->current_line = l;
- ctx->current = l2;
- break;
+ DEBUG("Got error from atspi_component_get_accessible_at_point, domain: %i, code: %i, message: %s",
+ error->domain, error->code, error->message);
+ g_clear_error(&error);
+ g_clear_object(&obj);
+ g_clear_object(&obj_under_finger);
+ if (youngest_ancestor_in_context)
+ g_clear_object(&youngest_ancestor_in_context);
+ look_for_next_descendant = EINA_FALSE;
+ } else if (obj_under_finger) {
+ DEBUG("Found object %s, role %s", atspi_accessible_get_name(obj_under_finger, NULL), atspi_accessible_get_role_name(obj_under_finger, NULL));
+ if (_flat_navi_context_contains_object(ctx, obj_under_finger))
+ {
+ DEBUG("Context contains object %s with role %s", atspi_accessible_get_name(obj_under_finger, NULL), atspi_accessible_get_role_name(obj_under_finger, NULL));
+ if (youngest_ancestor_in_context)
+ g_object_unref(youngest_ancestor_in_context);
+ youngest_ancestor_in_context = g_object_ref(obj_under_finger);
+ }
+ g_object_unref(obj);
+ obj = g_object_ref(obj_under_finger);
+ g_clear_object(&obj_under_finger);
+ } else {
+ obj_under_finger = g_object_ref(obj);
+ g_object_unref(obj);
+ look_for_next_descendant = EINA_FALSE;
}
}
- return found;
+ if (obj_under_finger)
+ g_clear_object(&obj_under_finger);
+
+ if (youngest_ancestor_in_context)
+ {
+ if (youngest_ancestor_in_context == current_obj ||
+ flat_navi_context_current_set(ctx, youngest_ancestor_in_context))
+ {
+ DEBUG("Setting highlight to object %s with role %s",
+ atspi_accessible_get_name(youngest_ancestor_in_context, NULL),
+ atspi_accessible_get_role_name(youngest_ancestor_in_context, NULL));
+ *target = youngest_ancestor_in_context;
+ ret = EINA_TRUE;
+ }
+ }
+ else
+ DEBUG("NO widget under (%d, %d) found or the same widget under hover",
+ x_cord, y_cord);
+
+ DEBUG("END");
+ return ret;
}
+#endif
int flat_navi_context_current_children_count_visible_get( FlatNaviContext *ctx)
{
{
if(!ctx || !target) return EINA_FALSE;
- 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;
- }
+ Eina_List *current_line = NULL, *current = NULL;
+ _flat_navi_context_current_line_and_object_get(ctx, target, ¤t_line, ¤t);
+ if (current_line) {
+ ctx->current_line = current_line;
+ ctx->current = current;
}
-
- return found;
+ return current_line != NULL;
}
AtspiAccessible *flat_navi_context_next(FlatNaviContext *ctx)
#define TTS_MAX_TEXT_SIZE 2000
#define GESTURE_LIMIT 10
+//Timeout in ms which will be used as interval for handling ongoing
+//hoved gesture updates. It is introduced to improve performance.
+//Even if user makes many mouse move events within hover gesture
+//only 5 highlight updates a second will be performed. Else we will
+//highly pollute dbus bus and and decrease highlight performance.
+#define ONGOING_HOVER_GESTURE_INTERPRETATION_INTERVAL 200
+
#define DEBUG_MODE
#define GERROR_CHECK(error)\
static FlatNaviContext *context;
static bool prepared = false;
static int counter=0;
+unsigned int _last_hover_event_time = -1;
static struct
{
static void _focus_widget(Gesture_Info *info)
{
DEBUG("START");
+ if (info->type == ONE_FINGER_HOVER)
+ {
+ if (_last_hover_event_time < 0)
+ _last_hover_event_time = info->event_time;
+ //info->event_time and _last_hover_event_time contain timestamp in ms.
+ if (info->event_time - _last_hover_event_time < ONGOING_HOVER_GESTURE_INTERPRETATION_INTERVAL && info->state == 1)
+ return;
+
+ _last_hover_event_time = info->state != 1 ? -1 : info->event_time;
+ }
if ((last_focus.x == info->x_beg) && (last_focus.y == info->y_beg))
return;
- AtspiAccessible *obj;
-
+ AtspiAccessible *obj = NULL;
if (flat_navi_context_current_at_x_y_set(context, info->x_beg, info->y_beg, &obj))
- {
- if (obj == current_obj)
- {
- DEBUG("The same object");
- return;
- }
- last_focus.x = info->x_beg;
- last_focus.y = info->y_beg;
- _current_highlight_object_set(obj);
- }
- else
- DEBUG("NO widget under (%d, %d) found or the same widget under hover",
- info->x_beg, info->y_beg);
+ {
+ last_focus.x = info->x_beg;
+ last_focus.y = info->y_beg;
+ _current_highlight_object_set(obj);
+ }
DEBUG("END");
}
static void _hover_event_emit(Cover *cov, int state);
-static void _event_emit(Gesture g, int x, int y, int x_e, int y_e, int state)
+static void _event_emit(Gesture g, int x, int y, int x_e, int y_e, int state, int event_time)
{
Gesture_Info *info = calloc(sizeof(Gesture_Info), 1);
EINA_SAFETY_ON_NULL_RETURN(info);
info->y_beg = y;
info->y_end = y_e;
info->state = state;
+ info->event_time = event_time;
if (_global_cb)
_global_cb(_global_data, info);
type = THREE_FINGERS_FLICK_RIGHT_RETURN;
}
DEBUG("FLICK GESTURE: N: %d F: %d", cov->flick_gesture.n_fingers, cov->flick_gesture.dir);
- _event_emit(type, ax, ay, axe, aye, 2);
+ _event_emit(type, ax, ay, axe, aye, 2, cov->event_time);
}
static void
{
case 1:
INFO("ON FINGER HOVER");
- _event_emit(ONE_FINGER_HOVER, ax, ay, ax, ay, state);
+ _event_emit(ONE_FINGER_HOVER, ax, ay, ax, ay, state, cov->event_time);
break;
case 2:
INFO("TWO FINGERS HOVER");
- _event_emit(TWO_FINGERS_HOVER, ax, ay, ax, ay, state);
+ _event_emit(TWO_FINGERS_HOVER, ax, ay, ax, ay, state, cov->event_time);
if (state == 0)
start_scroll(ax, ay);
else if (state == 1)
_event_emit(ONE_FINGER_SINGLE_TAP,
cov->tap_gesture_data.x_org[0], cov->tap_gesture_data.y_org[0],
cov->tap_gesture_data.x_org[0], cov->tap_gesture_data.y_org[0],
- state);
+ state, cov->event_time);
}
else if(cov->tap_gesture_data.tap_type == TWO_FINGERS_GESTURE)
{
_event_emit(TWO_FINGERS_SINGLE_TAP,
cov->tap_gesture_data.x_org[0], cov->tap_gesture_data.y_org[0],
cov->tap_gesture_data.x_org[1], cov->tap_gesture_data.y_org[1],
- state);
+ state, cov->event_time);
}
else if(cov->tap_gesture_data.tap_type == THREE_FINGERS_GESTURE)
{
_event_emit(THREE_FINGERS_SINGLE_TAP,
cov->tap_gesture_data.x_org[0], cov->tap_gesture_data.y_org[0],
cov->tap_gesture_data.x_org[2], cov->tap_gesture_data.y_org[2],
- state);
+ state, cov->event_time);
}
else
{
_event_emit(ONE_FINGER_DOUBLE_TAP,
cov->tap_gesture_data.x_org[0], cov->tap_gesture_data.y_org[0],
cov->tap_gesture_data.x_org[0], cov->tap_gesture_data.y_org[0],
- state);
+ state, cov->event_time);
}
else if(cov->tap_gesture_data.tap_type == TWO_FINGERS_GESTURE)
{
_event_emit(TWO_FINGERS_DOUBLE_TAP,
cov->tap_gesture_data.x_org[0], cov->tap_gesture_data.y_org[0],
cov->tap_gesture_data.x_org[1], cov->tap_gesture_data.y_org[1],
- state);
+ state, cov->event_time);
}
else if(cov->tap_gesture_data.tap_type == THREE_FINGERS_GESTURE)
{
_event_emit(THREE_FINGERS_DOUBLE_TAP,
cov->tap_gesture_data.x_org[0], cov->tap_gesture_data.y_org[0],
cov->tap_gesture_data.x_org[2], cov->tap_gesture_data.y_org[2],
- state);
+ state, cov->event_time);
}
else
{
_event_emit(ONE_FINGER_TRIPLE_TAP,
cov->tap_gesture_data.x_org[0], cov->tap_gesture_data.y_org[0],
cov->tap_gesture_data.x_org[0], cov->tap_gesture_data.y_org[0],
- state);
+ state, cov->event_time);
}
else if(cov->tap_gesture_data.tap_type == TWO_FINGERS_GESTURE)
{
_event_emit(TWO_FINGERS_TRIPLE_TAP,
cov->tap_gesture_data.x_org[0], cov->tap_gesture_data.y_org[0],
cov->tap_gesture_data.x_org[1], cov->tap_gesture_data.y_org[1],
- state);
+ state, cov->event_time);
}
else if(cov->tap_gesture_data.tap_type == THREE_FINGERS_GESTURE)
{
_event_emit(THREE_FINGERS_TRIPLE_TAP,
cov->tap_gesture_data.x_org[0], cov->tap_gesture_data.y_org[0],
cov->tap_gesture_data.x_org[2], cov->tap_gesture_data.y_org[2],
- state);
+ state, cov->event_time);
}
else
{
${CMAKE_SOURCE_DIR}/src/flat_navi.c
${CMAKE_SOURCE_DIR}/src/position_sort.c
${CMAKE_SOURCE_DIR}/src/object_cache.c)
+ADD_DEFINITIONS(-DSCREEN_READER_FLAT_NAVI_TEST_DUMMY_IMPLEMENTATION)
ADD_EXECUTABLE(smart_navi_test_suite smart_navi_suite.c ${TESTED_SRCS})
TARGET_LINK_LIBRARIES(smart_navi_test_suite atspi ${tests_LDFLAGS} ${SLP_LD_PATH_FLAGS} ${SLP_LD_FLAGS} ${SLP_LINKER_FLAGS})