Fixed highlight on click when genlist was flicked
authorTomasz Olszak <t.olszak@samsung.com>
Fri, 3 Jul 2015 16:34:03 +0000 (18:34 +0200)
committerLukasz Stanislawski <l.stanislaws@samsung.com>
Fri, 10 Jul 2015 14:50:08 +0000 (23:50 +0900)
Change-Id: Ib5a7b35703b010523670d0b167878bd7e4934199
Signed-off-by: Tomasz Olszak <t.olszak@samsung.com>
include/screen_reader_gestures.h
src/flat_navi.c
src/navigator.c
src/screen_reader_gestures.c
tests/CMakeLists.txt

index f952466..12c4445 100644 (file)
@@ -56,6 +56,7 @@ typedef struct
    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;
 
 /**
index d2ecad3..4c63216 100644 (file)
@@ -330,6 +330,33 @@ debug(FlatNaviContext *ctx)
    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)
 {
@@ -345,40 +372,102 @@ _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, &current_line, &current);
+   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)
 {
@@ -446,29 +535,13 @@ Eina_Bool flat_navi_context_current_set(FlatNaviContext *ctx, AtspiAccessible *t
 {
    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, &current_line, &current);
+   if (current_line) {
+       ctx->current_line = current_line;
+       ctx->current = current;
    }
-
-   return found;
+   return current_line != NULL;
 }
 
 AtspiAccessible *flat_navi_context_next(FlatNaviContext *ctx)
index dc614f0..18b5f3f 100644 (file)
 #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)\
@@ -53,6 +60,7 @@ static Eina_Bool _window_top_changed;
 static FlatNaviContext *context;
 static bool prepared = false;
 static int counter=0;
+unsigned int _last_hover_event_time = -1;
 
 static struct
 {
@@ -605,26 +613,27 @@ static AtspiAccessible *get_nearest_widget(AtspiAccessible* app_obj, gint x_cord
 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");
 }
index 4a4658a..be26d4e 100644 (file)
@@ -107,7 +107,7 @@ static Cover *cov;
 
 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);
@@ -118,6 +118,7 @@ static void _event_emit(Gesture g, int x, int y, int x_e, int y_e, int state)
    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);
@@ -296,7 +297,7 @@ _flick_event_emit(Cover *cov)
             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
@@ -653,11 +654,11 @@ _hover_event_emit(Cover *cov, int state)
       {
       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)
@@ -708,7 +709,7 @@ _tap_event_emit(Cover *cov, int state)
                _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)
             {
@@ -716,7 +717,7 @@ _tap_event_emit(Cover *cov, int state)
                _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)
             {
@@ -724,7 +725,7 @@ _tap_event_emit(Cover *cov, int state)
                _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
             {
@@ -738,7 +739,7 @@ _tap_event_emit(Cover *cov, int state)
                _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)
             {
@@ -746,7 +747,7 @@ _tap_event_emit(Cover *cov, int state)
                _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)
             {
@@ -754,7 +755,7 @@ _tap_event_emit(Cover *cov, int state)
                _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
             {
@@ -768,7 +769,7 @@ _tap_event_emit(Cover *cov, int state)
                _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)
             {
@@ -776,7 +777,7 @@ _tap_event_emit(Cover *cov, int state)
                _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)
             {
@@ -784,7 +785,7 @@ _tap_event_emit(Cover *cov, int state)
                _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
             {
index 2bf90f6..ea0e588 100644 (file)
@@ -39,6 +39,7 @@ SET(TESTED_SRCS ${CMAKE_SOURCE_DIR}/src/screen_reader.c
                 ${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})