aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLukasz Stanislawski <l.stanislaws@samsung.com>2015-04-17 13:59:08 +0200
committerLukasz Stanislawski <l.stanislaws@samsung.com>2015-05-15 10:15:27 +0200
commit015df8afe94011f07883cb6a7bc3a69e7ba7de79 (patch)
tree90ad7a3a0d4a1bb050e8f5b29b819397bc473542
parentelc_popup: add scroller into popup content area (diff)
downloadelementary-devs/stanluk/relations.tar.gz
atspi: add new APIs for setting atspi relationship.devs/stanluk/relations
Introduce new APIs elm_object_atspi_relationship_append and elm_object_atspi_relationship_remove allowing to set developer-defined accessibility relationships between widgets.
-rw-r--r--src/lib/elm_atspi_bridge.c11
-rw-r--r--src/lib/elm_interface_atspi_accessible.c102
-rw-r--r--src/lib/elm_interface_atspi_accessible.eo2
-rw-r--r--src/lib/elm_interface_atspi_accessible.h39
-rw-r--r--src/lib/elm_main.c11
-rw-r--r--src/lib/elm_object.h28
-rw-r--r--src/lib/elm_widget.c43
-rw-r--r--src/lib/elm_widget.eo15
-rw-r--r--src/lib/elm_widget.h3
-rw-r--r--src/tests/elm_test_atspi.c84
10 files changed, 300 insertions, 38 deletions
diff --git a/src/lib/elm_atspi_bridge.c b/src/lib/elm_atspi_bridge.c
index ec9e2db15..4961f3033 100644
--- a/src/lib/elm_atspi_bridge.c
+++ b/src/lib/elm_atspi_bridge.c
@@ -652,7 +652,8 @@ _accessible_get_relation_set(const Eldbus_Service_Interface *iface EINA_UNUSED,
Eldbus_Message *ret = NULL;
Eldbus_Message_Iter *iter = NULL, *iter_array = NULL, *iter_array2 = NULL, *iter_struct;
Elm_Atspi_Relation *rel;
- Eina_List *rels;
+ Eina_List *l;
+ Elm_Atspi_Relation_Set rels;
ret = eldbus_message_method_return_new(msg);
EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
@@ -663,17 +664,19 @@ _accessible_get_relation_set(const Eldbus_Service_Interface *iface EINA_UNUSED,
eo_do(obj, rels = elm_interface_atspi_accessible_relation_set_get());
- EINA_LIST_FREE(rels, rel)
+ EINA_LIST_FOREACH(rels, l, rel)
{
+ Eo *rel_obj;
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);
- _iter_object_reference_append(iter_array2, rel->obj);
+ EINA_LIST_FOREACH(rel->objects, l, rel_obj)
+ _iter_object_reference_append(iter_array2, rel_obj);
eldbus_message_iter_container_close(iter_struct, iter_array2);
eldbus_message_iter_container_close(iter_array, iter_struct);
- free(rel);
}
+ elm_atspi_relation_set_free(&rels);
eldbus_message_iter_container_close(iter, iter_array);
return ret;
diff --git a/src/lib/elm_interface_atspi_accessible.c b/src/lib/elm_interface_atspi_accessible.c
index 36e0cc042..ac0480072 100644
--- a/src/lib/elm_interface_atspi_accessible.c
+++ b/src/lib/elm_interface_atspi_accessible.c
@@ -262,12 +262,13 @@ _elm_interface_atspi_accessible_state_set_get(Eo *obj EINA_UNUSED, void *pd EINA
return ret;
}
-EOLIAN Eina_List*
+EOLIAN Elm_Atspi_Relation_Set
_elm_interface_atspi_accessible_relation_set_get(Eo *obj EINA_UNUSED, void *pd EINA_UNUSED)
{
+ Elm_Atspi_Relation_Set ret = 0;
WRN("The %s object does not implement the \"accessible_relation_set\" function.",
eo_class_name_get(eo_class_get(obj)));
- return NULL;
+ return ret;
}
EAPI void elm_atspi_attributes_list_free(Eina_List *list)
@@ -281,4 +282,101 @@ EAPI void elm_atspi_attributes_list_free(Eina_List *list)
}
}
+EAPI void elm_atspi_relation_free(Elm_Atspi_Relation *relation)
+{
+ eina_list_free(relation->objects);
+ free(relation);
+}
+
+EAPI Elm_Atspi_Relation *elm_atspi_relation_clone(const Elm_Atspi_Relation *relation)
+{
+ Elm_Atspi_Relation *ret = calloc(sizeof(Elm_Atspi_Relation), 1);
+ ret->type = relation->type;
+ ret->objects = eina_list_clone(relation->objects);
+ return ret;
+}
+
+EAPI Eina_Bool elm_atspi_relation_set_relation_append(Elm_Atspi_Relation_Set *set, Elm_Atspi_Relation_Type type, const Eo *rel_obj)
+{
+ Elm_Atspi_Relation *rel;
+ Eina_List *l;
+
+ if (!eo_isa(rel_obj, ELM_INTERFACE_ATSPI_ACCESSIBLE_MIXIN))
+ return EINA_FALSE;
+
+ EINA_LIST_FOREACH(*set, l, rel)
+ {
+ if (rel->type == type)
+ {
+ if (!eina_list_data_find(rel->objects, rel_obj))
+ rel->objects = eina_list_append(rel->objects, rel_obj);
+ return EINA_TRUE;
+ }
+ }
+
+ rel = calloc(sizeof(Elm_Atspi_Relation), 1);
+ rel->type = type;
+ rel->objects = eina_list_append(rel->objects, rel_obj);
+ *set = eina_list_append(*set, rel);
+ return EINA_TRUE;
+}
+
+EAPI void elm_atspi_relation_set_relation_remove(Elm_Atspi_Relation_Set *set, Elm_Atspi_Relation_Type type, const Eo *rel_obj)
+{
+ Eina_List *l;
+ Elm_Atspi_Relation *rel;
+
+ EINA_LIST_FOREACH(*set, l, rel)
+ {
+ if (rel->type == type)
+ {
+ rel->objects = eina_list_remove(rel->objects, rel_obj);
+ if (!rel->objects)
+ {
+ *set = eina_list_remove(*set, rel);
+ elm_atspi_relation_free(rel);
+ }
+ return;
+ }
+ }
+}
+
+EAPI void elm_atspi_relation_set_relation_type_remove(Elm_Atspi_Relation_Set *set, Elm_Atspi_Relation_Type type)
+{
+ Eina_List *l;
+ Elm_Atspi_Relation *rel;
+
+ EINA_LIST_FOREACH(*set, l, rel)
+ {
+ if (rel->type == type)
+ {
+ *set = eina_list_remove(*set, rel);
+ elm_atspi_relation_free(rel);
+ return;
+ }
+ }
+}
+
+EAPI void elm_atspi_relation_set_free(Elm_Atspi_Relation_Set *set)
+{
+ Elm_Atspi_Relation *rel;
+ EINA_LIST_FREE(*set, rel)
+ elm_atspi_relation_free(rel);
+}
+
+EAPI Elm_Atspi_Relation_Set elm_atspi_relation_set_clone(const Elm_Atspi_Relation_Set *set)
+{
+ Elm_Atspi_Relation_Set ret = NULL;
+ Eina_List *l;
+ Elm_Atspi_Relation *rel;
+
+ EINA_LIST_FOREACH(*set, l, rel)
+ {
+ Elm_Atspi_Relation *cpy = elm_atspi_relation_clone(rel);
+ ret = eina_list_append(ret, cpy);
+ }
+
+ return ret;
+}
+
#include "elm_interface_atspi_accessible.eo.c"
diff --git a/src/lib/elm_interface_atspi_accessible.eo b/src/lib/elm_interface_atspi_accessible.eo
index 9556e5739..5e0c1b3e1 100644
--- a/src/lib/elm_interface_atspi_accessible.eo
+++ b/src/lib/elm_interface_atspi_accessible.eo
@@ -29,7 +29,7 @@ mixin Elm_Interface_Atspi_Accessible ()
elements Should be free by a user. */
}
values {
- own(list<own(Elm_Atspi_Relation *)> *) relations;
+ Elm_Atspi_Relation_Set relations;
}
}
@property role @protected {
diff --git a/src/lib/elm_interface_atspi_accessible.h b/src/lib/elm_interface_atspi_accessible.h
index acd152e1b..293a79f08 100644
--- a/src/lib/elm_interface_atspi_accessible.h
+++ b/src/lib/elm_interface_atspi_accessible.h
@@ -246,16 +246,53 @@ typedef struct _Elm_Atspi_Attribute Elm_Atspi_Attribute;
struct _Elm_Atspi_Relation
{
Elm_Atspi_Relation_Type type;
- const Eo *obj;
+ Eina_List *objects;
};
typedef struct _Elm_Atspi_Relation Elm_Atspi_Relation;
+typedef Eina_List *Elm_Atspi_Relation_Set;
+
/**
* Free Elm_Atspi_Attributes_List
*/
EAPI void elm_atspi_attributes_list_free(Eina_List *list);
+/**
+ * Free Elm_Atspi_Relation
+ */
+EAPI void elm_atspi_relation_free(Elm_Atspi_Relation *rel);
+
+/**
+ * Clones relation
+ */
+EAPI Elm_Atspi_Relation *elm_atspi_relation_clone(const Elm_Atspi_Relation *relation);
+
+/**
+ * Appends relation to relation set
+ */
+EAPI Eina_Bool elm_atspi_relation_set_relation_append(Elm_Atspi_Relation_Set *set, Elm_Atspi_Relation_Type type, const Eo *rel_obj);
+
+/**
+ * Removes relation from relation set
+ */
+EAPI void elm_atspi_relation_set_relation_remove(Elm_Atspi_Relation_Set *set, Elm_Atspi_Relation_Type type, const Eo *rel_obj);
+
+/**
+ * Removes all relation from relation set of a given type
+ */
+EAPI void elm_atspi_relation_set_relation_type_remove(Elm_Atspi_Relation_Set *set, Elm_Atspi_Relation_Type type);
+
+/**
+ * Frees Elm_Atspi_State_Set
+ */
+EAPI void elm_atspi_relation_set_free(Elm_Atspi_Relation_Set *set);
+
+/**
+ * Makes a deep copy of Elm_Atspi_State_Set
+ */
+EAPI Elm_Atspi_Relation_Set elm_atspi_relation_set_clone(const Elm_Atspi_Relation_Set *set);
+
#ifdef EFL_EO_API_SUPPORT
/**
diff --git a/src/lib/elm_main.c b/src/lib/elm_main.c
index c1f57c777..4ec0aa263 100644
--- a/src/lib/elm_main.c
+++ b/src/lib/elm_main.c
@@ -1731,3 +1731,14 @@ elm_object_focused_item_get(const Evas_Object *obj)
return elm_widget_focused_item_get(obj);
}
+EAPI Eina_Bool
+elm_object_atspi_relationship_append(Evas_Object *obj, Elm_Atspi_Relation_Type type, const Evas_Object *relation_obj)
+{
+ return elm_widget_atspi_relationship_append(obj, type, relation_obj);
+}
+
+EAPI void
+elm_object_atspi_relationship_remove(Evas_Object *obj, Elm_Atspi_Relation_Type type, const Evas_Object *relation_obj)
+{
+ elm_widget_atspi_relationship_remove(obj, type, relation_obj);
+}
diff --git a/src/lib/elm_object.h b/src/lib/elm_object.h
index df066d07b..e94664175 100644
--- a/src/lib/elm_object.h
+++ b/src/lib/elm_object.h
@@ -508,3 +508,31 @@ EAPI void elm_object_orientation_mode_disabled_set(Evas_Object *obj, Eina
*/
EAPI Eina_Bool elm_object_orientation_mode_disabled_get(const Evas_Object *obj);
+#ifdef ELM_BETA_API_SUPPORT
+
+/**
+ * Set ATSPI2 relationship between two elementary widgets.
+ *
+ * @param obj The Elementary widget.
+ * @param type Type of relationship.
+ * @param relation_obj object being second side of the relation.
+ *
+ * @since 1.15
+ *
+ * @ingroup General
+ */
+EAPI Eina_Bool elm_object_atspi_relationship_append(Evas_Object *obj, Elm_Atspi_Relation_Type type, Evas_Object *relation_obj);
+
+/**
+ * Removes ATSPI2 relationship between widgets.
+ *
+ * @param obj The Elementary widget.
+ * @param type Type of relationship.
+ * @param relation_obj object being second side of the relation.
+ *
+ * @since 1.15
+ *
+ * @ingroup General
+ */
+EAPI void elm_object_atspi_relationship_remove(Evas_Object *obj, Elm_Atspi_Relation_Type type, Evas_Object *relation_obj);
+#endif
diff --git a/src/lib/elm_widget.c b/src/lib/elm_widget.c
index 27221d55b..44e03fced 100644
--- a/src/lib/elm_widget.c
+++ b/src/lib/elm_widget.c
@@ -5456,6 +5456,9 @@ _elm_widget_eo_base_destructor(Eo *obj, Elm_Widget_Smart_Data *sd)
if (parent && !eo_destructed_is(parent))
elm_interface_atspi_accessible_children_changed_del_signal_emit(parent, obj);
+ if (sd->atspi_custom_relations)
+ elm_atspi_relation_set_free(&sd->atspi_custom_relations);
+
eo_do_super(obj, ELM_WIDGET_CLASS, eo_destructor());
}
@@ -5662,40 +5665,22 @@ _elm_widget_elm_interface_atspi_accessible_attributes_get(Eo *obj, Elm_Widget_Sm
return ret;
}
-static Elm_Atspi_Relation*
-_relation_new(Elm_Atspi_Relation_Type type, Eo *obj)
+EOLIAN static Elm_Atspi_Relation_Set
+_elm_widget_elm_interface_atspi_accessible_relation_set_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd)
{
- Elm_Atspi_Relation *rel = calloc(1, sizeof(Elm_Atspi_Relation));
- if (!rel) return NULL;
-
- rel->type = type;
- rel->obj = obj;
-
- return rel;
+ return elm_atspi_relation_set_clone(&sd->atspi_custom_relations);
}
-EOLIAN static Eina_List*
-_elm_widget_elm_interface_atspi_accessible_relation_set_get(Eo *obj, Elm_Widget_Smart_Data *pd EINA_UNUSED)
+EOLIAN static Eina_Bool
+_elm_widget_atspi_relationship_append(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd, Elm_Atspi_Relation_Type type, const Eo *relation_obj)
{
- Eina_List *list = NULL;
- Elm_Atspi_Relation *rel;
- Evas_Object *rel_obj;
-
- rel_obj = elm_object_focus_next_object_get(obj, ELM_FOCUS_NEXT);
- if (eo_isa(rel_obj, ELM_INTERFACE_ATSPI_ACCESSIBLE_MIXIN))
- {
- rel = _relation_new(ELM_ATSPI_RELATION_FLOWS_TO, rel_obj);
- list = eina_list_append(list, rel);
- }
-
- rel_obj = elm_object_focus_next_object_get(obj, ELM_FOCUS_PREVIOUS);
- if (eo_isa(rel_obj, ELM_INTERFACE_ATSPI_ACCESSIBLE_MIXIN))
- {
- rel = _relation_new(ELM_ATSPI_RELATION_FLOWS_FROM, rel_obj);
- list = eina_list_append(list, rel);
- }
+ return elm_atspi_relation_set_relation_append(&sd->atspi_custom_relations, type, relation_obj);
+}
- return list;
+EOLIAN static void
+_elm_widget_atspi_relationship_remove(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd, Elm_Atspi_Relation_Type type, const Eo *relation_obj)
+{
+ elm_atspi_relation_set_relation_remove(&sd->atspi_custom_relations, type, relation_obj);
}
EOLIAN static void
diff --git a/src/lib/elm_widget.eo b/src/lib/elm_widget.eo
index 75bc7d924..dd3efe985 100644
--- a/src/lib/elm_widget.eo
+++ b/src/lib/elm_widget.eo
@@ -790,6 +790,21 @@ abstract Elm.Widget (Evas.Object_Smart, Elm_Interface_Atspi_Accessible, Elm_Inte
@in Evas_Object *relative_child @optional;
}
}
+ atspi_relationship_append {
+ /*@ No description supplied by the EAPI. */
+ return: bool;
+ params {
+ @in Elm_Atspi_Relation_Type type;
+ @in const(Eo) *relation_object;
+ }
+ }
+ atspi_relationship_remove {
+ /*@ No description supplied by the EAPI. */
+ params {
+ @in Elm_Atspi_Relation_Type type;
+ @in const(Eo) *relation_object;
+ }
+ }
}
implements {
class.constructor;
diff --git a/src/lib/elm_widget.h b/src/lib/elm_widget.h
index a0189a80f..5350442de 100644
--- a/src/lib/elm_widget.h
+++ b/src/lib/elm_widget.h
@@ -410,6 +410,7 @@ typedef struct _Elm_Widget_Smart_Data
int role; /**< Accessibility role */
const char *description; /**< Accessibility description */
Eo *atspi_custom_parent; /**< Accessibility parent if different then parent_obj */
+ Elm_Atspi_Relation_Set atspi_custom_relations; /**< Developer-defined accessiblity relations @since 1.15 */
/* this is a hook to be set on-the-fly on widgets. this is code
* handling the request of showing a specific region from an inner
@@ -776,6 +777,8 @@ EAPI Elm_Object_Item *elm_widget_focused_item_get(const Evas_Object *obj);
EAPI void elm_widget_orientation_mode_disabled_set(Evas_Object *obj, Eina_Bool disabled);
EAPI Eina_Bool elm_widget_orientation_mode_disabled_get(const Evas_Object *obj);
EAPI void elm_widget_focus_highlight_geometry_get(const Evas_Object *obj, Evas_Coord *x, Evas_Coord *y, Evas_Coord *w, Evas_Coord *h);
+EAPI Eina_Bool elm_widget_atspi_relationship_append(Evas_Object *obj, Elm_Atspi_Relation_Type type, const Evas_Object *relation_obj);
+EAPI void elm_widget_atspi_relationship_remove(Evas_Object *obj, Elm_Atspi_Relation_Type type, const Evas_Object *relation_obj);
void _elm_widget_item_highlight_in_theme(Evas_Object *obj, Elm_Object_Item *it);
/**
diff --git a/src/tests/elm_test_atspi.c b/src/tests/elm_test_atspi.c
index da616ff07..e4e18fc3c 100644
--- a/src/tests/elm_test_atspi.c
+++ b/src/tests/elm_test_atspi.c
@@ -9,7 +9,7 @@
#include "elm_priv.h"
#include "elm_suite.h"
-static Evas_Object *g_win, *g_btn, *g_bg;
+static Evas_Object *g_win, *g_btn, *g_bg, *g_btn2, *g_btn3, *g_box, *g_lbl;
void generate_app(void)
{
@@ -25,6 +25,34 @@ void generate_app(void)
evas_object_show(g_win);
}
+void generate_app2(void)
+{
+ g_win = elm_win_add(NULL, "Title", ELM_WIN_BASIC);
+ evas_object_geometry_set(g_win, 100, 100, 100, 100);
+
+ g_bg = elm_bg_add(g_win);
+
+ g_box = elm_box_add(g_win);
+
+ g_btn = elm_button_add(g_win);
+ g_btn2 = elm_button_add(g_win);
+ g_btn3 = elm_button_add(g_win);
+ g_lbl = elm_label_add(g_win);
+
+ elm_box_pack_end(g_box, g_btn);
+ elm_box_pack_end(g_box, g_btn2);
+ elm_box_pack_end(g_box, g_btn3);
+ elm_box_pack_end(g_box, g_lbl);
+
+ evas_object_show(g_btn);
+ evas_object_show(g_bg);
+ evas_object_show(g_win);
+ evas_object_show(g_box);
+ evas_object_show(g_btn2);
+ evas_object_show(g_btn3);
+ evas_object_show(g_lbl);
+}
+
START_TEST (elm_atspi_name_get)
{
elm_init(0, NULL);
@@ -184,6 +212,59 @@ START_TEST (elm_atspi_children_and_parent2)
}
END_TEST
+START_TEST (elm_atspi_elm_widget_custom_relations)
+{
+ Elm_Atspi_Relation_Set set;
+ Elm_Atspi_Relation *rel, *rel_to, *rel_from;
+ Eina_List *l;
+
+ elm_init(0, NULL);
+ generate_app2();
+
+ eo_do(g_btn, set = elm_interface_atspi_accessible_relation_set_get());
+ ck_assert(set == NULL);
+
+ elm_widget_atspi_relationship_append(g_btn, ELM_ATSPI_RELATION_FLOWS_TO, g_lbl);
+ elm_widget_atspi_relationship_append(g_btn, ELM_ATSPI_RELATION_FLOWS_FROM, g_win);
+
+ eo_do(g_btn, set = elm_interface_atspi_accessible_relation_set_get());
+ ck_assert(set != NULL);
+ ck_assert(eina_list_count(set) >= 2);
+
+ rel_to = rel_from = NULL;
+ EINA_LIST_FOREACH(set, l, rel)
+ {
+ if (rel->type == ELM_ATSPI_RELATION_FLOWS_TO)
+ rel_to = rel;
+ if (rel->type == ELM_ATSPI_RELATION_FLOWS_FROM)
+ rel_from = rel;
+ }
+
+ ck_assert(rel_to != NULL);
+ ck_assert(rel_from != NULL);
+ ck_assert(eina_list_data_find(rel_to->objects, g_lbl) != NULL);
+ ck_assert(eina_list_data_find(rel_from->objects, g_win) != NULL);
+
+ elm_atspi_relation_set_free(&set);
+
+ elm_widget_atspi_relationship_remove(g_btn, ELM_ATSPI_RELATION_FLOWS_TO, g_lbl);
+ eo_do(g_btn, set = elm_interface_atspi_accessible_relation_set_get());
+ ck_assert(set != NULL);
+ ck_assert(eina_list_count(set) >= 1);
+
+ rel_to = rel_from = NULL;
+ EINA_LIST_FOREACH(set, l, rel)
+ {
+ if (rel->type == ELM_ATSPI_RELATION_FLOWS_TO)
+ ck_assert(EINA_FALSE);
+ }
+
+ elm_atspi_relation_set_free(&set);
+
+ elm_shutdown();
+}
+END_TEST
+
void elm_test_atspi(TCase *tc)
{
tcase_add_test(tc, elm_atspi_name_get);
@@ -193,4 +274,5 @@ void elm_test_atspi(TCase *tc)
tcase_add_test(tc, elm_atspi_description_set);
tcase_add_test(tc, elm_atspi_children_and_parent);
tcase_add_test(tc, elm_atspi_children_and_parent2);
+ tcase_add_test(tc, elm_atspi_elm_widget_custom_relations);
}