From 685fb33d86d9273766b346e26134702c4839826c Mon Sep 17 00:00:00 2001 From: Marcel Hollerbach Date: Tue, 12 Dec 2017 12:11:57 +0100 Subject: [PATCH] efl_ui_focus_manager_calc: move the second stage result to another list holding them in the same list is a problem due to the fact that a member B in partners of A means that there also needs to be A in the partners of A. Due to this fact the cleanup logic before missed a few nodes and crashed in some cases. This is now fixed. --- .../elementary/efl_ui_focus_manager_calc.c | 94 ++++++++++++++----- 1 file changed, 69 insertions(+), 25 deletions(-) diff --git a/src/lib/elementary/efl_ui_focus_manager_calc.c b/src/lib/elementary/efl_ui_focus_manager_calc.c index 3c042c8834..00ed4ff20e 100644 --- a/src/lib/elementary/efl_ui_focus_manager_calc.c +++ b/src/lib/elementary/efl_ui_focus_manager_calc.c @@ -38,7 +38,9 @@ typedef struct _Border Border; typedef struct _Node Node; struct _Border { - Eina_List *partners; + Eina_List *partners; //partners that are linked in both directions + Eina_List *one_direction; //partners that are linked in one direction + Eina_List *cleanup_nodes; //a list of nodes that needs to be cleaned up when this node is deleted }; typedef enum { @@ -138,6 +140,49 @@ border_partners_set(Node *node, Efl_Ui_Focus_Direction direction, Eina_List *lis } } +static void +border_onedirection_set(Node *node, Efl_Ui_Focus_Direction direction, Eina_List *list) +{ + Node *partner; + Eina_List *lnode; + Border *border; + + EINA_SAFETY_ON_FALSE_RETURN(DIRECTION_IS_2D(direction)); + + border = &DIRECTION_ACCESS(node, direction); + + EINA_LIST_FREE(border->one_direction, partner) + { + Border *b = &DIRECTION_ACCESS(partner, _complement(direction)); + b->cleanup_nodes = eina_list_remove(b->cleanup_nodes, node); + } + + border->one_direction = list; + + EINA_LIST_FOREACH(border->one_direction, lnode, partner) + { + Border *comp_border = &DIRECTION_ACCESS(partner,_complement(direction)); + + comp_border->cleanup_nodes = eina_list_append(comp_border->cleanup_nodes, node); + } +} + +static void +border_onedirection_cleanup(Node *node, Efl_Ui_Focus_Direction direction) +{ + Node *partner; + Border *border; + + EINA_SAFETY_ON_FALSE_RETURN(DIRECTION_IS_2D(direction)); + + border = &DIRECTION_ACCESS(node, direction); + + EINA_LIST_FREE(border->cleanup_nodes, partner) + { + Border *b = &DIRECTION_ACCESS(partner, _complement(direction)); + b->one_direction = eina_list_remove(b->one_direction, node); + } +} /** * Create a new node */ @@ -185,6 +230,8 @@ node_item_free(Node *item) for(int i = EFL_UI_FOCUS_DIRECTION_UP;i < EFL_UI_FOCUS_DIRECTION_LAST; i++) { border_partners_set(item, i, NULL); + border_onedirection_cleanup(item, i); + border_onedirection_set(item, i, NULL); } //free the tree items @@ -514,7 +561,7 @@ _debug_node(Node *node) #endif static void -convert_border_set(Efl_Ui_Focus_Manager *obj, Efl_Ui_Focus_Manager_Calc_Data *pd, Node *node, Eina_List *focusable_list, Efl_Ui_Focus_Direction dir) +convert_set(Efl_Ui_Focus_Manager *obj, Efl_Ui_Focus_Manager_Calc_Data *pd, Node *node, Eina_List *focusable_list, Efl_Ui_Focus_Direction dir, void (*converter)(Node *node, Efl_Ui_Focus_Direction direction, Eina_List *list)) { Eina_List *partners = NULL; Efl_Ui_Focus_Object *fobj; @@ -532,7 +579,7 @@ convert_border_set(Efl_Ui_Focus_Manager *obj, Efl_Ui_Focus_Manager_Calc_Data *pd partners = eina_list_append(partners, entry); } - border_partners_set(node, dir, partners); + converter(node, dir, partners); } static void @@ -544,10 +591,11 @@ dirty_flush_node(Efl_Ui_Focus_Manager *obj EINA_UNUSED, Efl_Ui_Focus_Manager_Cal _calculate_node(pd, node->focusable, DIMENSION_X, &x_partners_pos, &x_partners_neg); _calculate_node(pd, node->focusable, DIMENSION_Y, &y_partners_pos, &y_partners_neg); - convert_border_set(obj, pd, node, x_partners_pos, EFL_UI_FOCUS_DIRECTION_RIGHT); - convert_border_set(obj, pd, node, x_partners_neg, EFL_UI_FOCUS_DIRECTION_LEFT); - convert_border_set(obj, pd, node, y_partners_neg, EFL_UI_FOCUS_DIRECTION_UP); - convert_border_set(obj, pd, node, y_partners_pos, EFL_UI_FOCUS_DIRECTION_DOWN); + convert_set(obj, pd, node, x_partners_pos, EFL_UI_FOCUS_DIRECTION_RIGHT, border_partners_set); + convert_set(obj, pd, node, x_partners_neg, EFL_UI_FOCUS_DIRECTION_LEFT, border_partners_set); + convert_set(obj, pd, node, y_partners_neg, EFL_UI_FOCUS_DIRECTION_UP, border_partners_set); + convert_set(obj, pd, node, y_partners_pos, EFL_UI_FOCUS_DIRECTION_DOWN, border_partners_set); + /* * Stage 2: if there is still no relation in a special direction, @@ -559,20 +607,9 @@ dirty_flush_node(Efl_Ui_Focus_Manager *obj EINA_UNUSED, Efl_Ui_Focus_Manager_Cal if (!DIRECTION_ACCESS(node, i).partners) { Eina_List *tmp = NULL; - Efl_Ui_Focus_Object *focusable; _calculate_node_indirection(pd, node->focusable, i, &tmp); - - EINA_LIST_FREE(tmp, focusable) - { - Border *b; - Node *n; - - b = &DIRECTION_ACCESS(node, i); - n = node_get(obj, pd, focusable); - b->partners = eina_list_append(b->partners, n); - } - + convert_set(obj, pd, node, tmp, i, border_onedirection_set); } } @@ -1176,16 +1213,22 @@ _coords_movement(Efl_Ui_Focus_Manager_Calc_Data *pd, Node *upper, Efl_Ui_Focus_D { Node *candidate; Eina_List *node_list; + Eina_List *lst; EINA_SAFETY_ON_FALSE_RETURN_VAL(DIRECTION_IS_2D(direction), NULL); + //decide which direction we take + lst = DIRECTION_ACCESS(upper, direction).partners; + if (!lst) + lst = DIRECTION_ACCESS(upper, direction).one_direction; + //we are searching which of the partners is lower to the history EINA_LIST_REVERSE_FOREACH(pd->focus_stack, node_list, candidate) { //we only calculate partners for normal nodes if (candidate->type == NODE_TYPE_NORMAL) continue; - if (eina_list_data_find(DIRECTION_ACCESS(upper, direction).partners, candidate)) + if (eina_list_data_find(lst, candidate)) { //this is the next accessible part return candidate; @@ -1194,13 +1237,11 @@ _coords_movement(Efl_Ui_Focus_Manager_Calc_Data *pd, Node *upper, Efl_Ui_Focus_D //if we haven't found anything in the history, use the widget with the smallest distance { - Eina_List *lst = DIRECTION_ACCESS(upper, direction).partners; Eina_List *n; Node *node, *min = NULL; Eina_Vector2 elem, other; float min_distance = 0.0; - _get_middle(upper->focusable, &elem); EINA_LIST_FOREACH(lst, n, node) @@ -1679,12 +1720,15 @@ _efl_ui_focus_manager_calc_efl_object_finalize(Eo *obj, Efl_Ui_Focus_Manager_Cal } static Eina_List* -_convert(Eina_List *node_list) +_convert(Border b) { Eina_List *n, *par = NULL; Node *node; - EINA_LIST_FOREACH(node_list, n, node) + EINA_LIST_FOREACH(b.partners, n, node) + par = eina_list_append(par, node->focusable); + + EINA_LIST_FOREACH(b.one_direction, n, node) par = eina_list_append(par, node->focusable); return par; @@ -1721,7 +1765,7 @@ _efl_ui_focus_manager_calc_efl_ui_focus_manager_fetch(Eo *obj, Efl_Ui_Focus_Mana efl_ui_focus_object_prepare_logical(n->tree.parent->focusable); efl_ui_focus_object_prepare_logical(n->focusable); -#define DIR_CLONE(dir) _convert(DIRECTION_ACCESS(n,dir).partners); +#define DIR_CLONE(dir) _convert(DIRECTION_ACCESS(n,dir)); res->right = DIR_CLONE(EFL_UI_FOCUS_DIRECTION_RIGHT); res->left = DIR_CLONE(EFL_UI_FOCUS_DIRECTION_LEFT);