elementary: small correction in the API of Efl.Access.Object to have proper lifecycle.

This API require more review, I have just fixed API that return type that are
inconsistent over time and fail to allow for proper lifecycle of event, which
lead to crash when those event trigger at unexpected point.

Differential Revision: https://phab.enlightenment.org/D6102
This commit is contained in:
Cedric BAIL 2018-05-04 14:17:15 -07:00
parent fe14abd929
commit dbbcfa4a59
5 changed files with 126 additions and 208 deletions

View File

@ -123,7 +123,7 @@ struct _Efl_Access_Event_Handler
struct _Efl_Access_Object_Data
{
Efl_Access_Relation_Set relations;
Eina_List *relations;
Eina_List *attr_list;
const char *name;
const char *description;
@ -377,10 +377,10 @@ _efl_access_object_state_set_get(const Eo *obj EINA_UNUSED, Efl_Access_Object_Da
return 0;
}
EOLIAN Efl_Access_Relation_Set
_efl_access_object_relation_set_get(const Eo *obj EINA_UNUSED, Efl_Access_Object_Data *pd)
EOLIAN Eina_Iterator *
_efl_access_object_relations_get(const Eo *obj EINA_UNUSED, Efl_Access_Object_Data *pd)
{
return efl_access_relation_set_clone(pd->relations);
return eina_list_iterator_new(pd->relations);
}
EAPI void efl_access_attributes_list_free(Eina_List *list)
@ -472,64 +472,60 @@ _efl_access_object_translation_domain_get(const Eo *obj EINA_UNUSED, Efl_Access_
return pd->translation_domain;
}
EAPI void
efl_access_relation_free(Efl_Access_Relation *relation)
{
eina_list_free(relation->objects);
free(relation);
}
EAPI Efl_Access_Relation *
efl_access_relation_clone(const Efl_Access_Relation *relation)
{
Efl_Access_Relation *ret = calloc(1, sizeof(Efl_Access_Relation));
if (!ret) return NULL;
ret->type = relation->type;
ret->objects = eina_list_clone(relation->objects);
return ret;
}
static void
_on_rel_obj_del(void *data, const Efl_Event *event)
{
Efl_Access_Relation_Set *set = data;
Efl_Access_Object_Data *sd = data;
Efl_Access_Relation *rel;
Eina_List *l, *l2, *p, *p2;
Eo *rel_obj;
EINA_LIST_FOREACH_SAFE(*set, l, l2, rel)
EINA_LIST_FOREACH_SAFE(sd->relations, l, l2, rel)
{
EINA_LIST_FOREACH_SAFE(rel->objects, p, p2, rel_obj)
{
if (rel_obj == event->object)
if (rel_obj == event->object)
rel->objects = eina_list_remove_list(rel->objects, p);
}
if (!rel->objects)
{
*set = eina_list_remove_list(*set, l);
sd->relations = eina_list_remove_list(sd->relations, l);
free(rel);
}
}
}
EAPI Eina_Bool
efl_access_relation_set_relation_append(Efl_Access_Relation_Set *set, Efl_Access_Relation_Type type, const Eo *rel_obj)
static void
efl_access_relation_set_free(Efl_Access_Object_Data *sd)
{
Efl_Access_Relation *rel;
Eo *obj;
EINA_LIST_FREE(sd->relations, rel)
{
Eina_List *l;
EINA_LIST_FOREACH(rel->objects, l, obj)
efl_event_callback_del(obj, EFL_EVENT_DEL, _on_rel_obj_del, sd);
eina_list_free(rel->objects);
free(rel);
}
}
EOLIAN static Eina_Bool
_efl_access_object_relationship_append(Eo *obj EINA_UNUSED, Efl_Access_Object_Data *sd, Efl_Access_Relation_Type type, const Efl_Access_Object *relation)
{
Efl_Access_Relation *rel;
Eina_List *l;
if (!efl_isa(rel_obj, EFL_ACCESS_OBJECT_MIXIN))
return EINA_FALSE;
EINA_LIST_FOREACH(*set, l, rel)
EINA_LIST_FOREACH(sd->relations, l, rel)
{
if (rel->type == type)
{
if (!eina_list_data_find(rel->objects, rel_obj))
if (!eina_list_data_find(rel->objects, relation))
{
rel->objects = eina_list_append(rel->objects, rel_obj);
efl_event_callback_add((Eo *) rel_obj, EFL_EVENT_DEL, _on_rel_obj_del, set);
rel->objects = eina_list_append(rel->objects, relation);
efl_event_callback_add((Eo *) relation, EFL_EVENT_DEL, _on_rel_obj_del, sd);
}
return EINA_TRUE;
}
@ -539,108 +535,56 @@ efl_access_relation_set_relation_append(Efl_Access_Relation_Set *set, Efl_Access
if (!rel) return EINA_FALSE;
rel->type = type;
rel->objects = eina_list_append(rel->objects, rel_obj);
*set = eina_list_append(*set, rel);
rel->objects = eina_list_append(rel->objects, relation);
sd->relations = eina_list_append(sd->relations, rel);
efl_event_callback_add((Eo *) relation, EFL_EVENT_DEL, _on_rel_obj_del, sd);
efl_event_callback_add((Eo *) rel_obj, EFL_EVENT_DEL, _on_rel_obj_del, set);
return EINA_TRUE;
}
EAPI void
efl_access_relation_set_relation_remove(Efl_Access_Relation_Set *set, Efl_Access_Relation_Type type, const Eo *rel_obj)
{
Eina_List *l;
Efl_Access_Relation *rel;
EINA_LIST_FOREACH(*set, l, rel)
{
if (rel->type == type)
{
if (eina_list_data_find(rel->objects, rel_obj))
{
efl_event_callback_del((Eo *) rel_obj, EFL_EVENT_DEL, _on_rel_obj_del, set);
rel->objects = eina_list_remove(rel->objects, rel_obj);
}
if (!rel->objects)
{
*set = eina_list_remove(*set, rel);
efl_access_relation_free(rel);
}
return;
}
}
}
EAPI void
efl_access_relation_set_relation_type_remove(Efl_Access_Relation_Set *set, Efl_Access_Relation_Type type)
{
Eina_List *l;
Efl_Access_Relation *rel;
Eo *obj;
EINA_LIST_FOREACH(*set, l, rel)
{
if (rel->type == type)
{
EINA_LIST_FOREACH(rel->objects, l, obj)
efl_event_callback_del(obj, EFL_EVENT_DEL, _on_rel_obj_del, set);
*set = eina_list_remove(*set, rel);
efl_access_relation_free(rel);
return;
}
}
}
EAPI void
efl_access_relation_set_free(Efl_Access_Relation_Set set)
{
Efl_Access_Relation *rel;
Eina_List *l;
Eo *obj;
EINA_LIST_FREE(set, rel)
{
EINA_LIST_FOREACH(rel->objects, l, obj)
efl_event_callback_del(obj, EFL_EVENT_DEL, _on_rel_obj_del, set);
efl_access_relation_free(rel);
}
}
EAPI Efl_Access_Relation_Set
efl_access_relation_set_clone(const Efl_Access_Relation_Set set)
{
Efl_Access_Relation_Set ret = NULL;
Eina_List *l;
Efl_Access_Relation *rel;
EINA_LIST_FOREACH(set, l, rel)
{
Efl_Access_Relation *cpy = efl_access_relation_clone(rel);
ret = eina_list_append(ret, cpy);
}
return ret;
}
EOLIAN static Eina_Bool
_efl_access_object_relationship_append(Eo *obj EINA_UNUSED, Efl_Access_Object_Data *sd, Efl_Access_Relation_Type type, const Efl_Access_Object *relation_obj)
{
return efl_access_relation_set_relation_append(&sd->relations, type, relation_obj);
}
EOLIAN static void
_efl_access_object_relationship_remove(Eo *obj EINA_UNUSED, Efl_Access_Object_Data *sd, Efl_Access_Relation_Type type, const Efl_Access_Object *relation_obj)
_efl_access_object_relationship_remove(Eo *obj EINA_UNUSED, Efl_Access_Object_Data *sd, Efl_Access_Relation_Type type, const Efl_Access_Object *relation)
{
if (relation_obj)
efl_access_relation_set_relation_remove(&sd->relations, type, relation_obj);
else
efl_access_relation_set_relation_type_remove(&sd->relations, type);
Efl_Access_Relation *rel;
Eina_List *l;
EINA_LIST_FOREACH(sd->relations, l, rel)
{
if (rel->type == type)
{
if (relation)
{
if (eina_list_data_find(rel->objects, relation))
{
efl_event_callback_del((Eo *) relation, EFL_EVENT_DEL, _on_rel_obj_del, sd);
rel->objects = eina_list_remove(rel->objects, relation);
}
if (!rel->objects)
{
sd->relations = eina_list_remove(sd->relations, rel);
free(rel);
}
}
else
{
Eina_List *ll;
Eo *ro;
EINA_LIST_FOREACH(rel->objects, ll, ro)
efl_event_callback_del(ro, EFL_EVENT_DEL, _on_rel_obj_del, sd);
sd->relations = eina_list_remove(sd->relations, rel);
free(rel);
}
return ;
}
}
}
EOLIAN static void
_efl_access_object_relationships_clear(Eo *obj EINA_UNUSED, Efl_Access_Object_Data *sd)
{
efl_access_relation_set_free(sd->relations);
efl_access_relation_set_free(sd);
sd->relations = NULL;
}
@ -682,13 +626,20 @@ _efl_access_object_access_type_set(Eo *obj, Efl_Access_Object_Data *pd, Efl_Acce
pd->type = val;
}
EOLIAN void
_efl_access_object_efl_object_invalidate(Eo *obj, Efl_Access_Object_Data *pd)
{
efl_access_relation_set_free(pd);
efl_invalidate(efl_super(obj, EFL_ACCESS_OBJECT_MIXIN));
}
EOLIAN void
_efl_access_object_efl_object_destructor(Eo *obj, Efl_Access_Object_Data *pd)
{
eina_stringshare_del(pd->name);
eina_stringshare_del(pd->description);
eina_stringshare_del(pd->translation_domain);
efl_access_relation_set_free(pd->relations);
efl_destructor(efl_super(obj, EFL_ACCESS_OBJECT_MIXIN));
}

View File

@ -239,8 +239,6 @@ struct Efl.Access.Relation
objects: list<Efl.Object>; [[List with relation objects]]
}
type Efl.Access.Relation_Set: list<ptr(Efl.Access.Relation)>; [[Elementary Accessibility relation set type]]
mixin Efl.Access.Object (Efl.Interface, Efl.Object)
{
[[Accessibility accessible mixin]]
@ -265,13 +263,9 @@ mixin Efl.Access.Object (Efl.Interface, Efl.Object)
i18n_name: string; [[Accessible name]]
}
}
@property relation_set @protected @beta {
relations_get @protected @beta @const {
[[Gets an all relations between accessible object and other accessible objects.]]
get {
}
values {
relations: Efl.Access.Relation_Set; [[Accessible relation set]]
}
return: iterator<ptr(Efl.Access.Relation)>; [[Accessible relation set]]
}
@property role @beta {
[[The role of the object in accessibility domain.]]
@ -456,6 +450,7 @@ mixin Efl.Access.Object (Efl.Interface, Efl.Object)
}
implements {
Efl.Object.destructor;
Efl.Object.invalidate;
Efl.Object.provider_find;
}
events {

View File

@ -30,41 +30,6 @@
*/
EAPI void efl_access_attributes_list_free(Eina_List *list);
/**
* Frees relation.
*/
EAPI void efl_access_relation_free(Efl_Access_Relation *relation);
/**
* Clones relation.
*/
EAPI Efl_Access_Relation * efl_access_relation_clone(const Efl_Access_Relation *relation);
/**
* Appends relation to relation set
*/
EAPI Eina_Bool efl_access_relation_set_relation_append(Efl_Access_Relation_Set *set, Efl_Access_Relation_Type type, const Eo *rel_obj);
/**
* Removes relation from relation set
*/
EAPI void efl_access_relation_set_relation_remove(Efl_Access_Relation_Set *set, Efl_Access_Relation_Type type, const Eo *rel_obj);
/**
* Removes all relation from relation set of a given type
*/
EAPI void efl_access_relation_set_relation_type_remove(Efl_Access_Relation_Set *set, Efl_Access_Relation_Type type);
/**
* Frees Efl_Access_Relation_Set
*/
EAPI void efl_access_relation_set_free(Efl_Access_Relation_Set set);
/**
* Clones Efl_Access_Relation_Set
*/
EAPI Efl_Access_Relation_Set efl_access_relation_set_clone(const Efl_Access_Relation_Set set);
#ifdef EFL_EO_API_SUPPORT
/**

View File

@ -805,9 +805,9 @@ _accessible_get_relation_set(const Eldbus_Service_Interface *iface EINA_UNUSED,
Eo *rel_obj, *obj = _bridge_object_from_path(bridge, obj_path);
Eldbus_Message *ret = NULL;
Eldbus_Message_Iter *iter = NULL, *iter_array = NULL, *iter_array2 = NULL, *iter_struct;
Efl_Access_Relation *rel;
Eina_List *l, *l2;
Efl_Access_Relation_Set rels;
const Efl_Access_Relation *rel;
Eina_List *l;
Eina_Iterator *it;
ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_OBJECT_MIXIN, msg);
@ -818,15 +818,14 @@ _accessible_get_relation_set(const Eldbus_Service_Interface *iface EINA_UNUSED,
iter_array = eldbus_message_iter_container_new(iter, 'a', "(ua(so))");
EINA_SAFETY_ON_NULL_GOTO(iter_array, fail);
rels = efl_access_object_relation_set_get(obj);
EINA_LIST_FOREACH(rels, l, rel)
it = efl_access_object_relations_get(obj);
EINA_ITERATOR_FOREACH(it, rel)
{
iter_struct = eldbus_message_iter_container_new(iter_array, 'r', NULL);
eldbus_message_iter_basic_append(iter_struct, 'u', _elm_relation_to_atspi_relation(rel->type));
iter_array2 = eldbus_message_iter_container_new(iter_struct, 'a', "(so)");
EINA_SAFETY_ON_NULL_GOTO(iter_array2, fail);
EINA_LIST_FOREACH(rel->objects, l2, rel_obj)
EINA_LIST_FOREACH(rel->objects, l, rel_obj)
{
_bridge_iter_object_reference_append(bridge, iter_array2, rel_obj);
_bridge_object_register(bridge, rel_obj);
@ -834,7 +833,7 @@ _accessible_get_relation_set(const Eldbus_Service_Interface *iface EINA_UNUSED,
eldbus_message_iter_container_close(iter_struct, iter_array2);
eldbus_message_iter_container_close(iter_array, iter_struct);
}
efl_access_relation_set_free(rels);
eina_iterator_free(it);
eldbus_message_iter_container_close(iter, iter_array);
return ret;

View File

@ -281,42 +281,46 @@ EFL_START_TEST (test_efl_access_object_relationship_append)
{
generate_app();
Efl_Access_Relation_Set set;
Efl_Access_Relation *rel, *rel_to, *rel_from;
Eina_List *l;
Eina_Iterator *it;
unsigned int i = 0;
efl_access_object_relationship_append(g_btn, EFL_ACCESS_RELATION_FLOWS_TO, g_bg);
efl_access_object_relationship_append(g_btn, EFL_ACCESS_RELATION_FLOWS_FROM, g_win);
set = efl_access_object_relation_set_get(g_btn);
it = efl_access_object_relations_get(g_btn);
ck_assert(set != NULL);
ck_assert(eina_list_count(set) >= 2);
ck_assert(it != NULL);
rel_to = rel_from = NULL;
EINA_LIST_FOREACH(set, l, rel)
EINA_ITERATOR_FOREACH(it, rel)
{
i++;
if (rel->type == EFL_ACCESS_RELATION_FLOWS_TO)
rel_to = rel;
if (rel->type == EFL_ACCESS_RELATION_FLOWS_FROM)
rel_from = rel;
}
ck_assert(i >= 2);
ck_assert(rel_to != NULL);
ck_assert(eina_list_data_find(rel_to->objects, g_bg) != NULL);
ck_assert(rel_from != NULL);
ck_assert(eina_list_data_find(rel_from->objects, g_win) != NULL);
efl_access_relation_set_free(set);
eina_iterator_free(it);
/* Check if append do not procude duplicated relations */
efl_access_object_relationship_append(g_btn, EFL_ACCESS_RELATION_FLOWS_TO, g_bg);
efl_access_object_relationship_append(g_btn, EFL_ACCESS_RELATION_FLOWS_FROM, g_win);
set = efl_access_object_relation_set_get(g_btn);
it = efl_access_object_relations_get(g_btn); i = 0;
rel_to = rel_from = NULL;
EINA_LIST_FOREACH(set, l, rel)
EINA_ITERATOR_FOREACH(it, rel)
{
i++;
if (rel->type == EFL_ACCESS_RELATION_FLOWS_TO)
rel_to = rel;
if (rel->type == EFL_ACCESS_RELATION_FLOWS_FROM)
@ -333,8 +337,7 @@ EFL_START_TEST (test_efl_access_object_relationship_append)
rel_from->objects = eina_list_remove(rel_from->objects, g_win);
ck_assert(eina_list_data_find(rel_from->objects, g_win) == NULL);
efl_access_relation_set_free(set);
eina_iterator_free(it);
}
EFL_END_TEST
@ -342,43 +345,48 @@ EFL_START_TEST (test_efl_access_object_relationship_remove)
{
generate_app();
Efl_Access_Relation_Set set;
Efl_Access_Relation *rel, *rel_to, *rel_from;
Eina_List *l;
Eina_Iterator *it;
unsigned int i = 0;
/* Test if removal of single relationship works */
efl_access_object_relationship_append(g_btn, EFL_ACCESS_RELATION_FLOWS_TO, g_bg);
efl_access_object_relationship_append(g_btn, EFL_ACCESS_RELATION_FLOWS_FROM, g_win);
efl_access_object_relationship_remove(g_btn, EFL_ACCESS_RELATION_FLOWS_TO, g_bg);
set = efl_access_object_relation_set_get(g_btn);
it = efl_access_object_relations_get(g_btn);
ck_assert(set != NULL);
ck_assert(eina_list_count(set) >= 1);
ck_assert(it != NULL);
rel_to = rel_from = NULL;
EINA_LIST_FOREACH(set, l, rel)
EINA_ITERATOR_FOREACH(it, rel)
{
i++;
if (rel->type == EFL_ACCESS_RELATION_FLOWS_TO)
rel_to = rel;
if (rel->type == EFL_ACCESS_RELATION_FLOWS_FROM)
rel_from = rel;
}
ck_assert(i >= 1);
if (rel_to) ck_assert(eina_list_data_find(rel_to->objects, g_bg) == NULL);
ck_assert(rel_from != NULL);
ck_assert(eina_list_data_find(rel_from->objects, g_win) != NULL);
efl_access_relation_set_free(set);
eina_iterator_free(it);
/* Test if removal of type relationship works */
efl_access_object_relationship_append(g_btn, EFL_ACCESS_RELATION_FLOWS_TO, g_bg);
efl_access_object_relationship_append(g_btn, EFL_ACCESS_RELATION_FLOWS_TO, g_win);
efl_access_object_relationship_remove(g_btn, EFL_ACCESS_RELATION_FLOWS_TO, NULL);
set = efl_access_object_relation_set_get(g_btn);
it = efl_access_object_relations_get(g_btn); i = 0;
rel_to = rel_from = NULL;
EINA_LIST_FOREACH(set, l, rel)
EINA_ITERATOR_FOREACH(it, rel)
{
i++;
if (rel->type == EFL_ACCESS_RELATION_FLOWS_TO)
rel_to = rel;
if (rel->type == EFL_ACCESS_RELATION_FLOWS_FROM)
@ -389,17 +397,19 @@ EFL_START_TEST (test_efl_access_object_relationship_remove)
ck_assert(rel_from != NULL);
ck_assert(eina_list_data_find(rel_from->objects, g_win) != NULL);
efl_access_relation_set_free(set);
eina_iterator_free(it);
/* Test if relationship is implicity removed when object is deleted */
efl_access_object_relationship_append(g_btn, EFL_ACCESS_RELATION_FLOWS_TO, g_bg);
efl_access_object_relationship_append(g_btn, EFL_ACCESS_RELATION_FLOWS_FROM, g_bg);
efl_del(g_bg);
set = efl_access_object_relation_set_get(g_btn);
it = efl_access_object_relations_get(g_btn); i = 0;
rel_to = rel_from = NULL;
EINA_LIST_FOREACH(set, l, rel)
EINA_ITERATOR_FOREACH(it, rel)
{
i++;
if (rel->type == EFL_ACCESS_RELATION_FLOWS_TO)
rel_to = rel;
if (rel->type == EFL_ACCESS_RELATION_FLOWS_FROM)
@ -409,15 +419,14 @@ EFL_START_TEST (test_efl_access_object_relationship_remove)
if (rel_to) ck_assert(eina_list_data_find(rel_to->objects, g_bg) == NULL);
if (rel_from) ck_assert(eina_list_data_find(rel_from->objects, g_bg) == NULL);
efl_access_relation_set_free(set);
eina_iterator_free(it);
}
EFL_END_TEST
EFL_START_TEST (test_efl_access_object_relationships_clear)
{
Efl_Access_Relation_Set set;
Efl_Access_Relation *rel;
Eina_List *l;
Eina_Iterator *it;
generate_app();
@ -428,16 +437,15 @@ EFL_START_TEST (test_efl_access_object_relationships_clear)
efl_access_object_relationships_clear(g_btn);
set = efl_access_object_relation_set_get(g_btn);
EINA_LIST_FOREACH(set, l, rel)
it = efl_access_object_relations_get(g_btn);
EINA_ITERATOR_FOREACH(it, rel)
{
ck_assert(!((rel->type == EFL_ACCESS_RELATION_FLOWS_TO) && eina_list_data_find(rel->objects, g_bg)));
ck_assert(!((rel->type == EFL_ACCESS_RELATION_FLOWS_FROM) && eina_list_data_find(rel->objects, g_bg)));
ck_assert(!((rel->type == EFL_ACCESS_RELATION_FLOWS_TO) && eina_list_data_find(rel->objects, g_win)));
ck_assert(!((rel->type == EFL_ACCESS_RELATION_FLOWS_FROM) && eina_list_data_find(rel->objects, g_win)));
}
efl_access_relation_set_free(set);
eina_iterator_free(it);
}
EFL_END_TEST