atspi: always use widget's subobj as accessible children

Patch fixes issue when widgets could be orphaned in accessibility tree
due to overloaded accessible_children_get methods in widgets returning
Elm_Object_Items. Widgets like genlist, gengrid, list and toolbar returned
only items as its accessibility children so if some widget was attached
directly to those widgets (like ctxpopup/popup) it become orphaned
in accessibility tree.
This commit is contained in:
Lukasz Stanislawski 2015-12-01 16:55:12 +01:00
parent 0b1cfd791c
commit d1baa35b1a
12 changed files with 50 additions and 163 deletions

View File

@ -900,9 +900,6 @@ _item_content_realize(Elm_Gen_Item *it,
elm_widget_sub_object_add(WIDGET(it), content);
if (eo_do_ret(EO_OBJ(it), tmp, elm_wdg_item_disabled_get()))
elm_widget_disabled_set(content, EINA_TRUE);
if (_elm_config->atspi_mode && eo_isa(content, ELM_INTERFACE_ATSPI_ACCESSIBLE_MIXIN))
eo_do(content, elm_interface_atspi_accessible_parent_set(EO_OBJ(it)));
}
}
}
@ -5534,27 +5531,6 @@ _elm_gengrid_item_elm_interface_atspi_accessible_name_get(Eo *eo_it EINA_UNUSED,
return ret;
}
EOLIAN Eina_List*
_elm_gengrid_item_elm_interface_atspi_accessible_children_get(Eo *eo_it EINA_UNUSED, Elm_Gen_Item *it)
{
Eina_List *ret = NULL;
if (VIEW(it))
{
Eina_List *parts;
const char *key;
parts = elm_widget_stringlist_get(edje_object_data_get(VIEW(it), "contents"));
EINA_LIST_FREE(parts, key)
{
Evas_Object *part;
part = edje_object_part_swallow_get(VIEW(it), key);
if (part && eo_isa(part, ELM_INTERFACE_ATSPI_ACCESSIBLE_MIXIN))
ret = eina_list_append(ret, part);
}
}
return ret;
}
EAPI Elm_Object_Item *
elm_gengrid_nth_item_get(const Evas_Object *obj, unsigned int nth)
{
@ -5687,15 +5663,17 @@ _elm_gengrid_elm_interface_atspi_widget_action_elm_actions_get(Eo *obj EINA_UNUS
}
EOLIAN Eina_List*
_elm_gengrid_elm_interface_atspi_accessible_children_get(Eo *obj EINA_UNUSED, Elm_Gengrid_Data *sd)
_elm_gengrid_elm_interface_atspi_accessible_children_get(Eo *obj, Elm_Gengrid_Data *sd)
{
Eina_List *ret = NULL;
Eina_List *ret = NULL, *ret2 = NULL;
Elm_Gen_Item *it;
EINA_INLIST_FOREACH(sd->items, it)
ret = eina_list_append(ret, EO_OBJ(it));
return ret;
eo_do_super(obj, ELM_GENGRID_CLASS, ret2 = elm_interface_atspi_accessible_children_get());
return eina_list_merge(ret, ret2);
}
EOLIAN Elm_Atspi_State_Set

View File

@ -211,6 +211,5 @@ class Elm.Gengrid_Item(Elm.Widget_Item)
Elm.Widget_Item.cursor_unset;
Elm_Interface_Atspi_Accessible.name.get;
Elm_Interface_Atspi_Accessible.state_set.get;
Elm_Interface_Atspi_Accessible.children.get;
}
}

View File

@ -381,8 +381,6 @@ _item_content_realize(Elm_Gen_Item *it,
((void *)WIDGET_ITEM_DATA_GET(EO_OBJ(it)), WIDGET(it), key);
if (!content) continue;
*contents = eina_list_append(*contents, content);
if (_elm_config->atspi_mode && eo_isa(content, ELM_INTERFACE_ATSPI_ACCESSIBLE_MIXIN))
eo_do(content, elm_interface_atspi_accessible_parent_set(EO_OBJ(it)));
if (!edje_object_part_swallow(target, key, content))
{
ERR("%s (%p) can not be swallowed into %s",
@ -396,12 +394,6 @@ _item_content_realize(Elm_Gen_Item *it,
snprintf(buf, sizeof(buf), "elm,state,%s,visible", key);
edje_object_signal_emit(target, buf, "elm");
if (_elm_config->atspi_mode && eo_isa(content, ELM_INTERFACE_ATSPI_ACCESSIBLE_MIXIN))
{
eo_do(content, elm_interface_atspi_accessible_parent_set(EO_OBJ(it)));
elm_interface_atspi_accessible_children_changed_added_signal_emit(EO_OBJ(it), content);
}
}
}
}
@ -5903,6 +5895,8 @@ _elm_genlist_item_elm_widget_item_del_pre(Eo *eo_it EINA_UNUSED,
sd->items = eina_inlist_remove(sd->items, EINA_INLIST_GET(it));
return EINA_FALSE;
}
if (_elm_config->atspi_mode)
elm_interface_atspi_accessible_children_changed_del_signal_emit(WIDGET(it),eo_it);
_item_del(it);
return EINA_TRUE;
@ -8109,30 +8103,6 @@ _elm_genlist_item_elm_interface_atspi_accessible_name_get(Eo *eo_it EINA_UNUSED,
return ret;
}
EOLIAN Eina_List*
_elm_genlist_item_elm_interface_atspi_accessible_children_get(Eo *eo_it EINA_UNUSED, Elm_Gen_Item *it)
{
Eina_List *ret = NULL;
if (VIEW(it))
{
Eina_List *parts;
const char *key;
parts = elm_widget_stringlist_get(edje_object_data_get(VIEW(it), "contents"));
EINA_LIST_FREE(parts, key)
{
Evas_Object *part;
part = edje_object_part_swallow_get(VIEW(it), key);
if (part && eo_isa(part, ELM_INTERFACE_ATSPI_ACCESSIBLE_MIXIN))
{
ret = eina_list_append(ret, part);
eo_do(part, elm_interface_atspi_accessible_parent_set(eo_it));
}
}
}
return ret;
}
EOLIAN static void
_elm_genlist_tree_effect_enabled_set(Eo *obj EINA_UNUSED, Elm_Genlist_Data *sd, Eina_Bool enabled)
{
@ -8306,15 +8276,17 @@ _elm_genlist_elm_interface_atspi_widget_action_elm_actions_get(Eo *obj EINA_UNUS
}
EOLIAN Eina_List*
_elm_genlist_elm_interface_atspi_accessible_children_get(Eo *obj EINA_UNUSED, Elm_Genlist_Data *sd)
_elm_genlist_elm_interface_atspi_accessible_children_get(Eo *obj, Elm_Genlist_Data *sd)
{
Eina_List *ret = NULL;
Eina_List *ret = NULL, *ret2 = NULL;
Elm_Gen_Item *it;
EINA_INLIST_FOREACH(sd->items, it)
ret = eina_list_append(ret, EO_OBJ(it));
return ret;
eo_do_super(obj, ELM_GENLIST_CLASS, ret2 = elm_interface_atspi_accessible_children_get());
return eina_list_merge(ret, ret2);
}
EOLIAN Elm_Atspi_State_Set

View File

@ -436,6 +436,5 @@ class Elm.Genlist_Item(Elm.Widget_Item)
Elm.Widget_Item.cursor_unset;
Elm_Interface_Atspi_Accessible.name.get;
Elm_Interface_Atspi_Accessible.state_set.get;
Elm_Interface_Atspi_Accessible.children.get;
}
}

View File

@ -128,7 +128,6 @@ struct _Elm_Interface_Atspi_Accessible_Data
const char *description;
const char *translation_domain;
Elm_Atspi_Relation_Set relations;
Elm_Interface_Atspi_Accessible *parent;
Elm_Atspi_Type type: 2;
};
@ -167,13 +166,11 @@ _elm_interface_atspi_accessible_index_in_parent_get(Eo *obj, Elm_Interface_Atspi
}
EOLIAN static Elm_Interface_Atspi_Accessible *
_elm_interface_atspi_accessible_parent_get(Eo *obj EINA_UNUSED, Elm_Interface_Atspi_Accessible_Data *pd)
_elm_interface_atspi_accessible_parent_get(Eo *obj EINA_UNUSED, Elm_Interface_Atspi_Accessible_Data *pd EINA_UNUSED)
{
Elm_Atspi_Type type;
Eo *parent = obj;
if (pd->parent) return pd->parent;
do {
eo_do(obj, parent = eo_parent_get());
if (eo_isa(parent, ELM_INTERFACE_ATSPI_ACCESSIBLE_MIXIN))
@ -187,13 +184,10 @@ _elm_interface_atspi_accessible_parent_get(Eo *obj EINA_UNUSED, Elm_Interface_At
}
EOLIAN static void
_elm_interface_atspi_accessible_parent_set(Eo *obj, Elm_Interface_Atspi_Accessible_Data *pd EINA_UNUSED, Elm_Interface_Atspi_Accessible *new_parent)
_elm_interface_atspi_accessible_parent_set(Eo *obj, Elm_Interface_Atspi_Accessible_Data *pd EINA_UNUSED, Elm_Interface_Atspi_Accessible *new_parent EINA_UNUSED)
{
if (pd->parent != new_parent)
{
pd->parent = new_parent;
elm_interface_atspi_accessible_parent_changed_signal_emit(obj);
}
WRN("The %s object does not implement the \"accessible_parent_set\" function.",
eo_class_name_get(eo_class_get(obj)));
}
EOLIAN Eina_List*
@ -587,8 +581,20 @@ _elm_interface_atspi_accessible_type_get(Eo *obj EINA_UNUSED, Elm_Interface_Atsp
}
EOLIAN void
_elm_interface_atspi_accessible_type_set(Eo *obj EINA_UNUSED, Elm_Interface_Atspi_Accessible_Data *pd, Elm_Atspi_Type val)
_elm_interface_atspi_accessible_type_set(Eo *obj, Elm_Interface_Atspi_Accessible_Data *pd, Elm_Atspi_Type val)
{
if (val == pd->type)
return;
switch (val)
{
case ELM_ATSPI_TYPE_DISABLED:
case ELM_ATSPI_TYPE_SKIPPED:
elm_interface_atspi_accessible_removed(obj);
break;
case ELM_ATSPI_TYPE_REGULAR:
elm_interface_atspi_accessible_added(obj);
}
pd->type = val;
}

View File

@ -2157,19 +2157,6 @@ _elm_list_item_elm_interface_atspi_accessible_name_get(Eo *eo_it EINA_UNUSED, El
return data->label ? strdup(data->label) : NULL;
}
EOLIAN static Eina_List*
_elm_list_item_elm_interface_atspi_accessible_children_get(Eo *eo_it EINA_UNUSED, Elm_List_Item_Data *data)
{
Eina_List *ret = NULL;
if (data->icon && eo_isa(data->icon, ELM_INTERFACE_ATSPI_ACCESSIBLE_MIXIN))
ret = eina_list_append(ret, data->icon);
if (data->end && eo_isa(data->end, ELM_INTERFACE_ATSPI_ACCESSIBLE_MIXIN))
ret = eina_list_append(ret, data->end);
return ret;
}
static char *
_access_info_cb(void *data, Evas_Object *obj EINA_UNUSED)
{
@ -2337,19 +2324,19 @@ _item_new(Evas_Object *obj,
if (it->icon)
{
eo_do(it->icon, elm_interface_atspi_accessible_parent_set(eo_it));
elm_widget_sub_object_add(obj, it->icon);
evas_object_event_callback_add
(it->icon, EVAS_CALLBACK_CHANGED_SIZE_HINTS, _size_hints_changed_cb,
obj);
eo_do(it->icon, elm_interface_atspi_accessible_type_set(ELM_ATSPI_TYPE_DISABLED));
}
if (it->end)
{
eo_do(it->end, elm_interface_atspi_accessible_parent_set(eo_it));
elm_widget_sub_object_add(obj, it->end);
evas_object_event_callback_add
(it->end, EVAS_CALLBACK_CHANGED_SIZE_HINTS, _size_hints_changed_cb,
obj);
eo_do(it->end, elm_interface_atspi_accessible_type_set(ELM_ATSPI_TYPE_DISABLED));
}
if (_elm_config->atspi_mode)
@ -2452,6 +2439,7 @@ _elm_list_evas_object_smart_add(Eo *obj, Elm_List_Data *priv)
priv->box = elm_box_add(obj);
evas_object_size_hint_weight_set(priv->box, EVAS_HINT_EXPAND, 0.0);
evas_object_size_hint_align_set(priv->box, EVAS_HINT_FILL, 0.0);
eo_do(priv->box, elm_interface_atspi_accessible_type_set(ELM_ATSPI_TYPE_DISABLED));
/* FIXME: change this ugly code path later */
elm_widget_on_show_region_hook_set(priv->box, _show_region_hook, obj);
@ -3208,9 +3196,11 @@ _elm_list_elm_interface_atspi_widget_action_elm_actions_get(Eo *obj EINA_UNUSED,
}
EOLIAN Eina_List*
_elm_list_elm_interface_atspi_accessible_children_get(Eo *eo_item EINA_UNUSED, Elm_List_Data *pd)
_elm_list_elm_interface_atspi_accessible_children_get(Eo *obj, Elm_List_Data *pd)
{
return eina_list_clone(pd->items);
Eina_List *ret;
eo_do_super(obj, ELM_LIST_CLASS, ret = elm_interface_atspi_accessible_children_get());
return eina_list_merge(eina_list_clone(pd->items), ret);
}
EOLIAN int

View File

@ -118,7 +118,6 @@ class Elm.List_Item(Elm.Widget_Item)
Elm.Widget_Item.part_content_unset;
Elm_Interface_Atspi_Accessible.name.get;
Elm_Interface_Atspi_Accessible.state_set.get;
Elm_Interface_Atspi_Accessible.children.get;
}
}

View File

@ -2370,6 +2370,7 @@ _item_new(Evas_Object *obj,
VIEW(it) = elm_layout_add(obj);
evas_object_data_set(VIEW(it), "item", it);
eo_do(VIEW(it), elm_interface_atspi_accessible_type_set(ELM_ATSPI_TYPE_DISABLED));
icon_obj = elm_icon_add(VIEW(it));
elm_icon_order_lookup_set(icon_obj, sd->lookup_order);
@ -2377,9 +2378,6 @@ _item_new(Evas_Object *obj,
if (_elm_config->access_mode == ELM_ACCESS_MODE_ON)
_access_widget_item_register(it);
eo_do(icon_obj, elm_interface_atspi_accessible_parent_set(VIEW(it)));
eo_do(VIEW(it), elm_interface_atspi_accessible_parent_set(eo_it));
if (_item_icon_set(icon_obj, "toolbar/", icon))
{
it->icon = icon_obj;
@ -2758,6 +2756,7 @@ _elm_toolbar_evas_object_smart_add(Eo *obj, Elm_Toolbar_Data *priv)
else
elm_object_signal_emit(priv->more, "elm,orient,horizontal", "elm");
eo_do(priv->more, elm_interface_atspi_accessible_type_set(ELM_ATSPI_TYPE_DISABLED));
elm_widget_sub_object_add(obj, priv->more);
evas_object_show(priv->more);
@ -3850,24 +3849,22 @@ _elm_toolbar_elm_interface_atspi_widget_action_elm_actions_get(Eo *obj EINA_UNUS
EOLIAN static Eina_List*
_elm_toolbar_elm_interface_atspi_accessible_children_get(Eo *obj EINA_UNUSED, Elm_Toolbar_Data *sd)
{
Eina_List *ret = NULL;
Eina_List *ret = NULL, *ret2 = NULL;
Elm_Toolbar_Item_Data *it;
eo_do_super(obj, ELM_TOOLBAR_CLASS, ret2 = elm_interface_atspi_accessible_children_get());
EINA_INLIST_FOREACH(sd->items, it)
ret = eina_list_append(ret, EO_OBJ(it));
return ret;
return eina_list_merge(ret, ret2);
}
EOLIAN static Elm_Atspi_State_Set
_elm_toolbar_elm_interface_atspi_accessible_state_set_get(Eo *obj, Elm_Toolbar_Data *sd EINA_UNUSED)
{
Elm_Atspi_State_Set ret;
eo_do_super(obj, ELM_TOOLBAR_CLASS, ret = elm_interface_atspi_accessible_state_set_get());
STATE_TYPE_SET(ret, ELM_ATSPI_STATE_MANAGES_DESCENDANTS);
return ret;
}

View File

@ -1207,12 +1207,12 @@ _elm_widget_sub_object_add(Eo *obj, Elm_Widget_Smart_Data *sd, Evas_Object *sobj
elm_widget_display_mode_set(sobj,
evas_object_size_hint_display_mode_get(obj));
if (_elm_config->atspi_mode && !sdc->on_create)
if (_elm_config->atspi_mode && !sd->on_create)
{
Elm_Interface_Atspi_Accessible *aparent;
eo_do(sobj, aparent = elm_interface_atspi_accessible_parent_get());
if (obj == aparent)
elm_interface_atspi_accessible_children_changed_added_signal_emit(obj, sobj);
if (aparent)
elm_interface_atspi_accessible_children_changed_added_signal_emit(aparent, sobj);
}
}
@ -1289,8 +1289,8 @@ _elm_widget_sub_object_del(Eo *obj, Elm_Widget_Smart_Data *sd, Evas_Object *sobj
{
Elm_Interface_Atspi_Accessible *aparent;
eo_do(sobj, aparent = elm_interface_atspi_accessible_parent_get());
if (obj == aparent)
elm_interface_atspi_accessible_children_changed_del_signal_emit(obj, sobj);
if (aparent)
elm_interface_atspi_accessible_children_changed_del_signal_emit(aparent, sobj);
}
ELM_WIDGET_DATA_GET(sobj, sdc);
@ -4474,9 +4474,6 @@ _elm_widget_item_eo_base_destructor(Eo *eo_item, Elm_Widget_Item_Data *item)
elm_interface_atspi_accessible_relationships_clear()
);
if (_elm_config->atspi_mode && item->widget)
elm_interface_atspi_accessible_children_changed_del_signal_emit(item->widget, eo_item);
elm_interface_atspi_accessible_removed(eo_item);
EINA_MAGIC_SET(item, EINA_MAGIC_NONE);
@ -4678,14 +4675,6 @@ _elm_widget_item_elm_interface_atspi_accessible_state_set_get(Eo *eo_item,
return states;
}
EOLIAN static Eo*
_elm_widget_item_elm_interface_atspi_accessible_parent_get(Eo *eo_item, Elm_Widget_Item_Data *item EINA_UNUSED)
{
Eo *parent;
eo_do(eo_item, parent = eo_parent_get());
return parent;
}
EAPI void
elm_object_item_data_set(Elm_Object_Item *it, void *data)
{
@ -5888,13 +5877,8 @@ EOLIAN static Eo*
_elm_widget_elm_interface_atspi_accessible_parent_get(Eo *obj, Elm_Widget_Smart_Data *pd EINA_UNUSED)
{
Elm_Atspi_Type type;
Elm_Interface_Atspi_Accessible *parent;
Elm_Interface_Atspi_Accessible *parent = obj;
eo_do_super(obj, ELM_WIDGET_CLASS, parent = elm_interface_atspi_accessible_parent_get());
if (parent)
return parent;
parent = obj;
do {
ELM_WIDGET_DATA_GET_OR_RETURN(parent, wd, NULL);
parent = wd->parent_obj;

View File

@ -530,7 +530,6 @@ class Elm.Widget_Item(Eo.Base, Elm_Interface_Atspi_Accessible,
Eo.Base.constructor;
Eo.Base.destructor;
Elm_Interface_Atspi_Accessible.state_set.get;
Elm_Interface_Atspi_Accessible.parent.get;
Elm_Interface_Atspi_Component.extents.get;
Elm_Interface_Atspi_Component.extents.set;
Elm_Interface_Atspi_Component.alpha.get;

View File

@ -180,41 +180,6 @@ START_TEST(elm_atspi_children_events_del2)
}
END_TEST
static Evas_Object *
gl_content_get(void *data EINA_UNUSED, Evas_Object *obj, const char *part EINA_UNUSED)
{
content = elm_button_add(obj);
return content;
}
/**
* Validate if genlist implementation properly reset AT-SPI parent to Elm_Genlist_Item
* from Elm_Genlist
*/
START_TEST(elm_atspi_children_parent)
{
test_init();
evas_object_show(genlist);
Elm_Object_Item *it;
Elm_Interface_Atspi_Accessible *parent;
content = NULL;
itc.item_style = "default";
itc.func.content_get = gl_content_get;
it = elm_genlist_item_append(genlist, &itc, NULL, NULL, ELM_GENLIST_ITEM_NONE, NULL, NULL);
elm_genlist_item_fields_update(it, "*.", ELM_GENGRID_ITEM_FIELD_CONTENT);
ck_assert(content != NULL);
eo_do(content, parent = elm_interface_atspi_accessible_parent_get());
ck_assert(it == parent);
elm_shutdown();
}
END_TEST
void elm_test_genlist(TCase *tc)
{
tcase_add_test(tc, elm_atspi_role_get);
@ -223,5 +188,4 @@ void elm_test_genlist(TCase *tc)
tcase_add_test(tc, elm_atspi_children_events_add);
tcase_add_test(tc, elm_atspi_children_events_del1);
tcase_add_test(tc, elm_atspi_children_events_del2);
tcase_add_test(tc, elm_atspi_children_parent);
}

View File

@ -216,15 +216,15 @@ START_TEST(elm_atspi_children_parent)
Evas_Object *end = elm_icon_add(win);
Evas_Object *list = elm_list_add(win);
Elm_Object_Item *it = elm_list_item_append(list, "First Element", icon, end, NULL, NULL);
elm_list_item_append(list, "First Element", icon, end, NULL, NULL);
evas_object_show(list);
eo_do(icon, parent = elm_interface_atspi_accessible_parent_get());
ck_assert(it == parent);
ck_assert(list == parent);
eo_do(end, parent = elm_interface_atspi_accessible_parent_get());
ck_assert(it == parent);
ck_assert(list == parent);
elm_shutdown();
}