From 38948bd86563a3db00148f7dd0905139b160e648 Mon Sep 17 00:00:00 2001 From: Lukasz Stanislawski Date: Mon, 6 Apr 2015 10:54:57 +0200 Subject: [PATCH] Backport atspi patches from Elementary 1.14 RC Merge branch 'devs/stanluk/eo_object_items_atspi' Make elm object items atspi-aware objects. Implement atspi support for elm_genlist, elm_gengrid and elm_toolbar items. atspi: add missing signals array sentiel. @fix Change-Id: I3269f3e958cf45e7daf6888be17872e1f6410dce --- src/lib/Makefile.am | 3 - src/lib/elm_atspi_app_object.c | 6 +- src/lib/elm_atspi_bridge.c | 165 ++++++++++++++----- src/lib/elm_entry.c | 12 ++ src/lib/elm_entry.eo | 1 + src/lib/elm_gengrid.c | 108 +++++++++++- src/lib/elm_gengrid.eo | 6 +- src/lib/elm_gengrid_item.eo | 3 + src/lib/elm_genlist.c | 129 +++++++++++++++ src/lib/elm_genlist.eo | 2 + src/lib/elm_genlist_item.eo | 3 + src/lib/elm_interface_atspi_accessible.c | 7 +- src/lib/elm_interface_atspi_accessible.eo | 5 +- src/lib/elm_interface_atspi_accessible.h | 8 +- src/lib/elm_interface_atspi_widget.c | 204 ----------------------- src/lib/elm_interface_atspi_widget.eo | 19 --- src/lib/elm_interfaces.h | 2 - src/lib/elm_list.c | 161 +++++++++++++++++- src/lib/elm_list.eo | 11 +- src/lib/elm_list_item.eo | 7 +- src/lib/elm_radio.c | 21 +++ src/lib/elm_radio.eo | 1 + src/lib/elm_spinner.c | 5 +- src/lib/elm_toolbar.c | 53 ++++++ src/lib/elm_toolbar.eo | 2 + src/lib/elm_toolbar_item.eo | 2 + src/lib/elm_widget.c | 263 ++++++++++++++++++++++++++++++ src/lib/elm_widget.eo | 15 +- src/lib/elm_widget.h | 8 + src/lib/elm_widget_item.eo | 8 +- src/tests/elm_test_gengrid.c | 2 +- src/tests/elm_test_genlist.c | 168 ++++++++++++++++++- 32 files changed, 1108 insertions(+), 302 deletions(-) delete mode 100644 src/lib/elm_interface_atspi_widget.c delete mode 100644 src/lib/elm_interface_atspi_widget.eo diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am index cd28380..04c4e5b 100644 --- a/src/lib/Makefile.am +++ b/src/lib/Makefile.am @@ -448,7 +448,6 @@ elm_interface_atspi_image.c \ elm_interface_atspi_selection.c \ elm_interface_atspi_text.c \ elm_interface_atspi_value.c \ -elm_interface_atspi_widget.c \ elm_interface_atspi_widget_action.c \ elm_interface_atspi_window.c \ elm_interface_fileselector.c \ @@ -561,7 +560,6 @@ elm_interface_atspi_image.eo \ elm_interface_atspi_selection.eo \ elm_interface_atspi_text.eo \ elm_interface_atspi_value.eo \ -elm_interface_atspi_widget.eo \ elm_interface_atspi_widget_action.eo \ elm_interface_atspi_window.eo \ elm_interface_fileselector.eo \ @@ -664,7 +662,6 @@ elementaryeolianfiles_DATA = \ elm_interface_atspi_selection.eo \ elm_interface_atspi_text.eo \ elm_interface_atspi_value.eo \ - elm_interface_atspi_widget.eo \ elm_interface_atspi_widget_action.eo \ elm_interface_atspi_window.eo \ elm_bg.eo \ diff --git a/src/lib/elm_atspi_app_object.c b/src/lib/elm_atspi_app_object.c index 08932cf..4d8b37f 100644 --- a/src/lib/elm_atspi_app_object.c +++ b/src/lib/elm_atspi_app_object.c @@ -41,10 +41,12 @@ _elm_atspi_app_object_elm_interface_atspi_accessible_children_get(Eo *obj EINA_U return accs; } -EOLIAN static const char* +EOLIAN static char* _elm_atspi_app_object_elm_interface_atspi_accessible_name_get(Eo *obj EINA_UNUSED, Elm_Atspi_App_Object_Data *_pd EINA_UNUSED) { - return elm_app_name_get(); + const char *ret; + ret = elm_app_name_get(); + return ret ? strdup(ret) : NULL; } EOLIAN static const char* diff --git a/src/lib/elm_atspi_bridge.c b/src/lib/elm_atspi_bridge.c index a3f5e24..9a21e67 100644 --- a/src/lib/elm_atspi_bridge.c +++ b/src/lib/elm_atspi_bridge.c @@ -35,9 +35,14 @@ #define SIZE(x) sizeof(x)/sizeof(x[0]) -static int _init_count = 0; +typedef struct Key_Event_Info { + Ecore_Event_Key event; + int type; +} Key_Event_Info; +static int _init_count = 0; static Eldbus_Connection *_a11y_bus = NULL; +static Eina_List *reemited_events; static Eo *_root; static Ecore_Idler *_cache_update_idler; static Eina_List *_pending_objects; @@ -50,7 +55,7 @@ static unsigned long _object_property_broadcast_mask; static unsigned long _object_children_broadcast_mask; static unsigned long long _object_state_broadcast_mask; static unsigned long long _window_signal_broadcast_mask; -static Ecore_Event_Handler *_key_hdl; +static Ecore_Event_Filter *_key_flr; static Eina_Bool _state_changed_signal_send(void *data, Eo *obj, const Eo_Event_Description *desc, void *event_info); static Eina_Bool _property_changed_signal_send(void *data, Eo *obj, const Eo_Event_Description *desc EINA_UNUSED, void *event_info); @@ -68,7 +73,7 @@ static void _object_append_desktop_reference(Eldbus_Message_Iter *iter); static void _cache_build(void *obj); static void _object_register(Eo *obj, char *path); static void _iter_interfaces_append(Eldbus_Message_Iter *iter, const Eo *obj); -static Eina_Bool _elm_atspi_bridge_key_down_event_notify(void *data, int type, void *event); +static Eina_Bool _elm_atspi_bridge_key_filter(void *data, void *loop, int type, void *event); static void _object_signal_send(Eldbus_Service_Interface *infc, int sig_id, const char *minor, unsigned int det1, unsigned int det2, const char *variant_sig, ...); EO_CALLBACKS_ARRAY_DEFINE(_events_cb, @@ -183,6 +188,7 @@ static const Eldbus_Signal _event_obj_signals[] = { [ATSPI_OBJECT_EVENT_TEXT_ATTRIBUTES_CHANGED] = {"TextAttributesChanged", ELDBUS_ARGS({"siiv(so)", NULL}), 0}, [ATSPI_OBJECT_EVENT_TEXT_CARET_MOVED] = {"TextCaretMoved", ELDBUS_ARGS({"siiv(so)", NULL}), 0}, [ATSPI_OBJECT_EVENT_ATTRIBUTES_CHANGED] = {"AttributesChanged", ELDBUS_ARGS({"siiv(so)", NULL}), 0}, + {NULL, ELDBUS_ARGS({NULL, NULL}), 0} }; static const Eldbus_Signal _window_obj_signals[] = { @@ -1767,10 +1773,12 @@ _accessible_property_get(const Eldbus_Service_Interface *interface, const char * if (!strcmp(property, "Name")) { - eo_do(obj, ret = elm_interface_atspi_accessible_name_get()); - if (!ret) - ret = ""; - eldbus_message_iter_basic_append(iter, 's', ret); + char *ret2; + eo_do(obj, ret2 = elm_interface_atspi_accessible_name_get()); + if (!ret2) + ret2 = strdup(""); + eldbus_message_iter_basic_append(iter, 's', ret2); + free(ret2); return EINA_TRUE; } else if (!strcmp(property, "Description")) @@ -2135,11 +2143,13 @@ _append_item_fn(const Eina_Hash *hash EINA_UNUSED, const void *key EINA_UNUSED, _iter_interfaces_append(iter_struct, data); /* Marshall name */ - const char *name = NULL; + char *name = NULL; eo_do(data, name = elm_interface_atspi_accessible_name_get()); if (!name) - name = ""; + name = strdup(""); + eldbus_message_iter_basic_append(iter_struct, 's', name); + free(name); /* Marshall role */ eldbus_message_iter_basic_append(iter_struct, 'u', role); @@ -2649,14 +2659,8 @@ _registered_events_list_update(void) } static void -_handle_listener_change(void *data EINA_UNUSED, const Eldbus_Message *msg) +_handle_listener_change(void *data EINA_UNUSED, const Eldbus_Message *msg EINA_UNUSED) { - const char *bus, *event; - if (!eldbus_message_arguments_get(msg, "ss", &bus, &event)) - { - ERR("Invalid org.a11y.Registry signal message args."); - return; - } _registered_events_list_update(); } @@ -2764,17 +2768,6 @@ _property_changed_signal_send(void *data, Eo *obj EINA_UNUSED, const Eo_Event_De } static Eina_Bool -_idler_cb(void *data EINA_UNUSED) -{ - Eo *obj; - EINA_LIST_FREE(_pending_objects, obj) - _cache_build(obj); - _pending_objects = NULL; - _cache_update_idler = NULL; - return EINA_FALSE; -} - -static Eina_Bool _children_changed_signal_send(void *data, Eo *obj, const Eo_Event_Description *desc EINA_UNUSED, void *event_info) { Eldbus_Service_Interface *events = data; @@ -2788,9 +2781,7 @@ _children_changed_signal_send(void *data, Eo *obj, const Eo_Event_Description *d // update cached objects if (ev_data->is_added) { - _pending_objects = eina_list_append(_pending_objects, obj); - if (!_cache_update_idler) - _cache_update_idler = ecore_idler_add(_idler_cb, NULL); + _cache_build(obj); } if (!STATE_TYPE_GET(_object_children_broadcast_mask, type)) @@ -3048,7 +3039,7 @@ _event_handlers_register(void) _register_hdl = eldbus_signal_handler_add(_a11y_bus, ATSPI_DBUS_NAME_REGISTRY, ATSPI_DBUS_PATH_REGISTRY, ATSPI_DBUS_INTERFACE_REGISTRY, "EventListenerRegistered", _handle_listener_change, NULL); _unregister_hdl = eldbus_signal_handler_add(_a11y_bus, ATSPI_DBUS_NAME_REGISTRY, ATSPI_DBUS_PATH_REGISTRY, ATSPI_DBUS_INTERFACE_REGISTRY, "EventListenerDeregistered", _handle_listener_change, NULL); - _key_hdl = ecore_event_handler_add(ECORE_EVENT_KEY_DOWN, _elm_atspi_bridge_key_down_event_notify, NULL); + _key_flr = ecore_event_filter_add(NULL, _elm_atspi_bridge_key_filter, NULL, NULL); } static Eina_Bool @@ -3252,46 +3243,132 @@ _elm_atspi_bridge_shutdown(void) eldbus_connection_unref(_a11y_bus); _a11y_bus = NULL; - if (_key_hdl) - ecore_event_handler_del(_key_hdl); - _key_hdl = NULL; + if (_key_flr) + ecore_event_filter_del(_key_flr); + _key_flr = NULL; _init_count = 0; _root = NULL; } } +static Key_Event_Info* +_key_event_info_new(int event_type, const Ecore_Event_Key *data) +{ + Key_Event_Info *ret; + EINA_SAFETY_ON_NULL_RETURN_VAL(data, NULL); + + ret = calloc(sizeof(Key_Event_Info), 1); + + ret->type = event_type; + ret->event = *data; + + ret->event.keyname = eina_stringshare_add(data->keyname); + ret->event.key = eina_stringshare_add(data->key); + ret->event.string = eina_stringshare_add(data->string); + ret->event.compose = eina_stringshare_add(data->compose); + + // not sure why it is here, but explicite keep it NULLed. + ret->event.data = NULL; + + return ret; +} + static void -_iter_marshall_key_down_event(Eldbus_Message_Iter *iter, Ecore_Event_Key *event) +_key_event_info_free(Key_Event_Info *data) { - Eldbus_Message_Iter *struct_iter; + EINA_SAFETY_ON_NULL_RETURN(data); + + eina_stringshare_del(data->event.keyname); + eina_stringshare_del(data->event.key); + eina_stringshare_del(data->event.string); + eina_stringshare_del(data->event.compose); - EINA_SAFETY_ON_NULL_RETURN(event); + free(data); +} + +static void +_iter_marshall_key_event(Eldbus_Message_Iter *iter, Key_Event_Info *data) +{ + Eldbus_Message_Iter *struct_iter; + EINA_SAFETY_ON_NULL_RETURN(data); struct_iter = eldbus_message_iter_container_new(iter, 'r', NULL); - const char *str = event->keyname ? event->keyname : ""; - int is_text = event->keyname? 1 : 0; - eldbus_message_iter_arguments_append(struct_iter, "uiiiisb", ATSPI_KEY_PRESSED_EVENT, 0, event->keycode, 0, event->timestamp, str, is_text); + const char *str = data->event.keyname ? data->event.keyname : ""; + int is_text = data->event.keyname ? 1 : 0; + int type; + if (data->type == ECORE_EVENT_KEY_DOWN) + type = ATSPI_KEY_PRESSED_EVENT; + else + type = ATSPI_KEY_RELEASED_EVENT; + eldbus_message_iter_arguments_append(struct_iter, "uiiiisb", type, 0, data->event.keycode, 0, data->event.timestamp, str, is_text); eldbus_message_iter_container_close(iter, struct_iter); } +static void +_on_event_del(void *user_data, void *func_data EINA_UNUSED) +{ + Key_Event_Info *info = user_data; + _key_event_info_free(info); +} + +static void +_on_listener_answer(void *data, const Eldbus_Message *msg, Eldbus_Pending *pending EINA_UNUSED) +{ + Key_Event_Info *info = data; + const char *errname, *errmsg; + Eina_Bool ret = EINA_TRUE; + + if (eldbus_message_error_get(msg, &errname, &errmsg)) + { + ERR("%s %s", errname, errmsg); + goto reemit; + } + if (!eldbus_message_arguments_get(msg, "b", &ret)) + { + ERR("Return message doen not contian return value"); + goto reemit; + } + if (ret) + { + _key_event_info_free(info); + return; + } +reemit: + ecore_event_add(info->type, &info->event, _on_event_del, info); + reemited_events = eina_list_append(reemited_events, &info->event); +} + static Eina_Bool -_elm_atspi_bridge_key_down_event_notify(void *data EINA_UNUSED, int type EINA_UNUSED, void *event) +_elm_atspi_bridge_key_filter(void *data EINA_UNUSED, void *loop EINA_UNUSED, int type, void *event) { Eldbus_Message *msg; Eldbus_Message_Iter *iter; Ecore_Event_Key *key_event = event; + Key_Event_Info *ke; if (!_init_count) return EINA_TRUE; + if ((type != ECORE_EVENT_KEY_DOWN) && (type != ECORE_EVENT_KEY_UP)) return EINA_TRUE; + + // check if reemited + if (eina_list_data_find(reemited_events, event)) + { + reemited_events = eina_list_remove(reemited_events, event); + return EINA_TRUE; + } + + ke = _key_event_info_new(type, key_event); + if (!ke) return EINA_TRUE; msg = eldbus_message_method_call_new(ATSPI_DBUS_NAME_REGISTRY, ATSPI_DBUS_PATH_DEC, ATSPI_DBUS_INTERFACE_DEC, "NotifyListenersSync"); iter = eldbus_message_iter_get(msg); - _iter_marshall_key_down_event(iter, key_event); + _iter_marshall_key_event(iter, ke); - eldbus_connection_send(_a11y_bus, msg, NULL, NULL, -1); + // timeout should be kept reasonaby low to avoid + eldbus_connection_send(_a11y_bus, msg, _on_listener_answer, ke, 500); - return EINA_TRUE; + return EINA_FALSE; } diff --git a/src/lib/elm_entry.c b/src/lib/elm_entry.c index e7f018c..f9d7bd3 100644 --- a/src/lib/elm_entry.c +++ b/src/lib/elm_entry.c @@ -5571,4 +5571,16 @@ _elm_entry_elm_interface_atspi_editable_text_cut(Eo *obj, Elm_Entry_Data *_pd EI return EINA_TRUE; } +EOLIAN static Elm_Atspi_State_Set +_elm_entry_elm_interface_atspi_accessible_state_set_get(Eo *obj, Elm_Entry_Data *_pd EINA_UNUSED) +{ + Elm_Atspi_State_Set ret; + eo_do_super(obj, ELM_ENTRY_CLASS, ret = elm_interface_atspi_accessible_state_set_get()); + + if (elm_entry_editable_get(obj)) + STATE_TYPE_SET(ret, ELM_ATSPI_STATE_EDITABLE); + + return ret; +} + #include "elm_entry.eo.c" diff --git a/src/lib/elm_entry.eo b/src/lib/elm_entry.eo index 278247b..4e5b9f6 100644 --- a/src/lib/elm_entry.eo +++ b/src/lib/elm_entry.eo @@ -1201,6 +1201,7 @@ class Elm_Entry (Elm_Layout, Elm_Interface_Scrollable, Evas.Clickable_Interface, Elm_Layout.content_aliases.get; Elm_Interface_Scrollable.policy.set; Elm_Interface_Scrollable.bounce_allow.set; + Elm_Interface_Atspi_Accessible.state_set.get; Elm_Interface_Atspi_Text.text.get; Elm_Interface_Atspi_Text.string.get; Elm_Interface_Atspi_Text.attribute.get; diff --git a/src/lib/elm_gengrid.c b/src/lib/elm_gengrid.c index 8ab1e73..35f9c49 100644 --- a/src/lib/elm_gengrid.c +++ b/src/lib/elm_gengrid.c @@ -1647,6 +1647,8 @@ _elm_gengrid_item_focused(Elm_Object_Item *eo_it) evas_object_raise(VIEW(it)); } evas_object_smart_callback_call(obj, SIG_ITEM_FOCUSED, eo_it); + if (_elm_config->atspi_mode) + elm_interface_atspi_accessible_state_changed_signal_emit(eo_it, ELM_ATSPI_STATE_FOCUSED, EINA_TRUE); } static void @@ -1675,6 +1677,8 @@ _elm_gengrid_item_unfocused(Elm_Object_Item *eo_it) sd->focused_item = NULL; evas_object_smart_callback_call(obj, SIG_ITEM_UNFOCUSED, eo_it); + if (_elm_config->atspi_mode) + elm_interface_atspi_accessible_state_changed_signal_emit(eo_it, ELM_ATSPI_STATE_FOCUSED, EINA_FALSE); } static Eina_Bool @@ -3629,6 +3633,7 @@ _elm_gengrid_item_eo_base_constructor(Eo *eo_it, Elm_Gen_Item *it) { eo_do_super(eo_it, ELM_GENGRID_ITEM_CLASS, eo_constructor()); it->base = eo_data_scope_get(eo_it, ELM_WIDGET_ITEM_CLASS); + eo_do(eo_it, elm_interface_atspi_accessible_role_set(ELM_ATSPI_ROLE_LIST_ITEM)); } static Elm_Gen_Item * @@ -3818,7 +3823,7 @@ _elm_gengrid_eo_base_constructor(Eo *obj, Elm_Gengrid_Data *sd) eo_do(obj, evas_obj_type_set(MY_CLASS_NAME_LEGACY), evas_obj_smart_callbacks_descriptions_set(_smart_callbacks), - elm_interface_atspi_accessible_role_set(ELM_ATSPI_ROLE_TABLE)); + elm_interface_atspi_accessible_role_set(ELM_ATSPI_ROLE_TREE_TABLE)); } EOLIAN static void @@ -4900,6 +4905,83 @@ _elm_gengrid_item_select_mode_get(Eo *eo_it EINA_UNUSED, Elm_Gen_Item *it) return it->select_mode; } +EOLIAN Elm_Atspi_State_Set +_elm_gengrid_item_elm_interface_atspi_accessible_state_set_get(Eo *eo_it, Elm_Gen_Item *it EINA_UNUSED) +{ + Elm_Atspi_State_Set ret; + Eina_Bool sel; + + eo_do_super(eo_it, ELM_GENGRID_ITEM_CLASS, ret = elm_interface_atspi_accessible_state_set_get()); + + eo_do(eo_it, sel = elm_obj_gengrid_item_selected_get()); + + STATE_TYPE_SET(ret, ELM_ATSPI_STATE_SELECTABLE); + + if (sel) + STATE_TYPE_SET(ret, ELM_ATSPI_STATE_SELECTED); + + return ret; +} + +EOLIAN char* +_elm_gengrid_item_elm_interface_atspi_accessible_name_get(Eo *eo_it EINA_UNUSED, Elm_Gen_Item *it) +{ + char *ret; + Eina_Strbuf *buf; + + buf = eina_strbuf_new(); + + if (it->itc->func.text_get) + { + Eina_List *texts; + const char *key; + + texts = + elm_widget_stringlist_get(edje_object_data_get(VIEW(it), "texts")); + + EINA_LIST_FREE(texts, key) + { + char *s = it->itc->func.text_get + ((void *)WIDGET_ITEM_DATA_GET(EO_OBJ(it)), WIDGET(it), key); + + s = _elm_util_mkup_to_text(s); + + if (s) + { + if (eina_strbuf_length_get(buf) > 0) + eina_strbuf_append(buf, ", "); + eina_strbuf_append(buf, s); + free(s); + } + } + } + + ret = eina_strbuf_string_steal(buf); + eina_strbuf_free(buf); + 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) { @@ -5031,5 +5113,29 @@ _elm_gengrid_elm_interface_atspi_widget_action_elm_actions_get(Eo *obj EINA_UNUS return &atspi_actions[0]; } +EOLIAN Eina_List* +_elm_gengrid_elm_interface_atspi_accessible_children_get(Eo *obj EINA_UNUSED, Elm_Gengrid_Data *sd) +{ + Eina_List *ret = NULL; + Elm_Gen_Item *it; + + EINA_INLIST_FOREACH(sd->items, it) + ret = eina_list_append(ret, EO_OBJ(it)); + + return ret; +} + +EOLIAN Elm_Atspi_State_Set +_elm_gengrid_elm_interface_atspi_accessible_state_set_get(Eo *obj, Elm_Gengrid_Data *sd EINA_UNUSED) +{ + Elm_Atspi_State_Set ret; + + eo_do_super(obj, ELM_GENGRID_CLASS, ret = elm_interface_atspi_accessible_state_set_get()); + + STATE_TYPE_SET(ret, ELM_ATSPI_STATE_MANAGES_DESCENDANTS); + + return ret; +} + #include "elm_gengrid.eo.c" #include "elm_gengrid_item.eo.c" diff --git a/src/lib/elm_gengrid.eo b/src/lib/elm_gengrid.eo index 506f0c3..d808ef6 100644 --- a/src/lib/elm_gengrid.eo +++ b/src/lib/elm_gengrid.eo @@ -1,4 +1,5 @@ -class Elm_Gengrid (Elm_Layout, Elm_Interface_Scrollable, Evas.Clickable_Interface) +class Elm_Gengrid (Elm_Layout, Elm_Interface_Scrollable, + Evas.Clickable_Interface, Elm_Interface_Atspi_Widget_Action) { eo_prefix: elm_obj_gengrid; properties { @@ -703,6 +704,9 @@ class Elm_Gengrid (Elm_Layout, Elm_Interface_Scrollable, Evas.Clickable_Interfac Elm_Layout.sizing_eval; Elm_Interface_Scrollable.bounce_allow.set; Elm_Interface_Scrollable.policy; + Elm_Interface_Atspi_Accessible.children.get; + Elm_Interface_Atspi_Accessible.state_set.get; + Elm_Interface_Atspi_Widget_Action.elm_actions.get; } events { language,changed; diff --git a/src/lib/elm_gengrid_item.eo b/src/lib/elm_gengrid_item.eo index a7966ac..bb2fae1 100644 --- a/src/lib/elm_gengrid_item.eo +++ b/src/lib/elm_gengrid_item.eo @@ -242,6 +242,9 @@ class Elm_Gengrid_Item(Elm_Widget_Item) Elm_Widget_Item.tooltip_unset; Elm_Widget_Item.cursor.set; Elm_Widget_Item.cursor_unset; + Elm_Interface_Atspi_Accessible.name.get; + Elm_Interface_Atspi_Accessible.state_set.get; + Elm_Interface_Atspi_Accessible.children.get; } } diff --git a/src/lib/elm_genlist.c b/src/lib/elm_genlist.c index 68d0459..d45ad4e 100644 --- a/src/lib/elm_genlist.c +++ b/src/lib/elm_genlist.c @@ -328,6 +328,8 @@ _item_text_realize(Elm_Gen_Item *it, { edje_object_part_text_set(target, key, ""); } + if (_elm_config->atspi_mode) + elm_interface_atspi_accessible_name_changed_signal_emit(EO_OBJ(it)); } } @@ -369,6 +371,8 @@ _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", @@ -2563,6 +2567,8 @@ _elm_genlist_item_focused(Elm_Object_Item *eo_it) evas_object_raise(VIEW(it)); } evas_object_smart_callback_call(obj, SIG_ITEM_FOCUSED, eo_it); + if (_elm_config->atspi_mode) + elm_interface_atspi_accessible_state_changed_signal_emit(eo_it, ELM_ATSPI_STATE_FOCUSED, EINA_TRUE); } static void @@ -2589,6 +2595,8 @@ _elm_genlist_item_unfocused(Elm_Object_Item *eo_it) sd->focused_item = NULL; evas_object_smart_callback_call(obj, SIG_ITEM_UNFOCUSED, eo_it); + if (_elm_config->atspi_mode) + elm_interface_atspi_accessible_state_changed_signal_emit(eo_it, ELM_ATSPI_STATE_FOCUSED, EINA_FALSE); } static Eina_Bool @@ -5819,7 +5827,9 @@ EOLIAN static void _elm_genlist_item_eo_base_constructor(Eo *eo_it, Elm_Gen_Item *it) { eo_do_super(eo_it, ELM_GENLIST_ITEM_CLASS, eo_constructor()); + it->base = eo_data_scope_get(eo_it, ELM_WIDGET_ITEM_CLASS); + eo_do(eo_it, elm_interface_atspi_accessible_role_set(ELM_ATSPI_ROLE_LIST_ITEM)); } static Elm_Gen_Item * @@ -5973,6 +5983,9 @@ _elm_genlist_item_append(Eo *obj EINA_UNUSED, Elm_Genlist_Data *sd, const Elm_Ge it->item->before = EINA_FALSE; _item_queue(sd, it, NULL); + if (_elm_config->atspi_mode) + elm_interface_atspi_accessible_children_changed_added_signal_emit(sd->obj, EO_OBJ(it)); + return EO_OBJ(it); } @@ -6017,6 +6030,9 @@ _elm_genlist_item_prepend(Eo *obj EINA_UNUSED, Elm_Genlist_Data *sd, const Elm_G it->item->before = EINA_TRUE; _item_queue(sd, it, NULL); + if (_elm_config->atspi_mode) + elm_interface_atspi_accessible_children_changed_added_signal_emit(sd->obj, EO_OBJ(it)); + return EO_OBJ(it); } @@ -6064,6 +6080,9 @@ _elm_genlist_item_insert_after(Eo *obj EINA_UNUSED, Elm_Genlist_Data *sd, const it->item->before = EINA_FALSE; _item_queue(sd, it, NULL); + if (_elm_config->atspi_mode) + elm_interface_atspi_accessible_children_changed_added_signal_emit(sd->obj, EO_OBJ(it)); + return EO_OBJ(it); } @@ -6111,6 +6130,9 @@ _elm_genlist_item_insert_before(Eo *obj, Elm_Genlist_Data *sd, const Elm_Genlist it->item->before = EINA_TRUE; _item_queue(sd, it, NULL); + if (_elm_config->atspi_mode) + elm_interface_atspi_accessible_children_changed_added_signal_emit(sd->obj, EO_OBJ(it)); + return EO_OBJ(it); } @@ -6214,6 +6236,9 @@ _elm_genlist_item_sorted_insert(Eo *obj, Elm_Genlist_Data *sd, const Elm_Genlist _item_queue(sd, it, _elm_genlist_item_list_compare); + if (_elm_config->atspi_mode) + elm_interface_atspi_accessible_children_changed_added_signal_emit(sd->obj, eo_it); + return eo_it; } @@ -7561,6 +7586,86 @@ _elm_genlist_item_select_mode_get(Eo *eo_it EINA_UNUSED, Elm_Gen_Item *it) return it->select_mode; } +EOLIAN Elm_Atspi_State_Set +_elm_genlist_item_elm_interface_atspi_accessible_state_set_get(Eo *eo_it, Elm_Gen_Item *it EINA_UNUSED) +{ + Elm_Atspi_State_Set ret; + Eina_Bool sel; + + eo_do_super(eo_it, ELM_GENLIST_ITEM_CLASS, ret = elm_interface_atspi_accessible_state_set_get()); + + eo_do(eo_it, sel = elm_obj_genlist_item_selected_get()); + + STATE_TYPE_SET(ret, ELM_ATSPI_STATE_SELECTABLE); + + if (sel) + STATE_TYPE_SET(ret, ELM_ATSPI_STATE_SELECTED); + + return ret; +} + +EOLIAN char* +_elm_genlist_item_elm_interface_atspi_accessible_name_get(Eo *eo_it EINA_UNUSED, + Elm_Gen_Item *it) +{ + char *ret; + Eina_Strbuf *buf; + + buf = eina_strbuf_new(); + + if (it->itc->func.text_get) + { + Eina_List *texts; + const char *key; + + texts = + elm_widget_stringlist_get(edje_object_data_get(VIEW(it), "texts")); + + EINA_LIST_FREE(texts, key) + { + char *s = it->itc->func.text_get + ((void *)WIDGET_ITEM_DATA_GET(EO_OBJ(it)), WIDGET(it), key); + + s = _elm_util_mkup_to_text(s); + + if (s) + { + if (eina_strbuf_length_get(buf) > 0) eina_strbuf_append(buf, ", "); + eina_strbuf_append(buf, s); + free(s); + } + } + } + + ret = eina_strbuf_string_steal(buf); + eina_strbuf_free(buf); + 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) { @@ -7748,5 +7853,29 @@ _elm_genlist_elm_interface_atspi_widget_action_elm_actions_get(Eo *obj EINA_UNUS return &atspi_actions[0]; } +EOLIAN Eina_List* +_elm_genlist_elm_interface_atspi_accessible_children_get(Eo *obj EINA_UNUSED, Elm_Genlist_Data *sd) +{ + Eina_List *ret = NULL; + Elm_Gen_Item *it; + + EINA_INLIST_FOREACH(sd->items, it) + ret = eina_list_append(ret, EO_OBJ(it)); + + return ret; +} + +EOLIAN Elm_Atspi_State_Set +_elm_genlist_elm_interface_atspi_accessible_state_set_get(Eo *obj, Elm_Genlist_Data *sd EINA_UNUSED) +{ + Elm_Atspi_State_Set ret; + + eo_do_super(obj, ELM_GENLIST_CLASS, ret = elm_interface_atspi_accessible_state_set_get()); + + STATE_TYPE_SET(ret, ELM_ATSPI_STATE_MANAGES_DESCENDANTS); + + return ret; +} + #include "elm_genlist.eo.c" #include "elm_genlist_item.eo.c" diff --git a/src/lib/elm_genlist.eo b/src/lib/elm_genlist.eo index 026a93d..537a801 100644 --- a/src/lib/elm_genlist.eo +++ b/src/lib/elm_genlist.eo @@ -728,6 +728,8 @@ class Elm_Genlist (Elm_Layout, Elm_Interface_Scrollable, Evas.Clickable_Interfac Elm_Layout.sizing_eval; Elm_Interface_Scrollable.bounce_allow; Elm_Interface_Scrollable.policy; + Elm_Interface_Atspi_Accessible.children.get; + Elm_Interface_Atspi_Accessible.state_set.get; Elm_Interface_Atspi_Widget_Action.elm_actions.get; } events { diff --git a/src/lib/elm_genlist_item.eo b/src/lib/elm_genlist_item.eo index 34a6179..80984ab 100644 --- a/src/lib/elm_genlist_item.eo +++ b/src/lib/elm_genlist_item.eo @@ -505,6 +505,9 @@ class Elm_Genlist_Item(Elm_Widget_Item) Elm_Widget_Item.tooltip_unset; Elm_Widget_Item.cursor.set; Elm_Widget_Item.cursor_unset; + Elm_Interface_Atspi_Accessible.name.get; + Elm_Interface_Atspi_Accessible.state_set.get; + Elm_Interface_Atspi_Accessible.children.get; } } diff --git a/src/lib/elm_interface_atspi_accessible.c b/src/lib/elm_interface_atspi_accessible.c index 4ddb369..36e0cc0 100644 --- a/src/lib/elm_interface_atspi_accessible.c +++ b/src/lib/elm_interface_atspi_accessible.c @@ -138,8 +138,9 @@ _elm_interface_atspi_accessible_index_in_parent_get(Eo *obj, void *pd EINA_UNUSE if (ret == (int)eina_list_count(children)) { ERR("Object %s not present in its AT-SPI parents (%s) children list! This should never happen.", eo_class_name_get(eo_class_get(obj)), eo_class_name_get(eo_class_get(parent))); - return -1; + ret = -1; } + eina_list_free(children); return ret; } @@ -193,7 +194,7 @@ _elm_interface_atspi_accessible_role_name_get(Eo *obj EINA_UNUSED, void *pd EINA return role > ELM_ATSPI_ROLE_LAST_DEFINED ? "" : Atspi_Name[role]; } -EOLIAN const char * +EOLIAN char * _elm_interface_atspi_accessible_name_get(Eo *obj EINA_UNUSED, void *pd EINA_UNUSED) { WRN("The %s object does not implement the \"accessible_name_get\" function.", @@ -202,7 +203,7 @@ _elm_interface_atspi_accessible_name_get(Eo *obj EINA_UNUSED, void *pd EINA_UNUS } EOLIAN static void -_elm_interface_atspi_accessible_name_set(Eo *obj, void *pd EINA_UNUSED, const char *val EINA_UNUSED) +_elm_interface_atspi_accessible_name_set(Eo *obj, void *pd EINA_UNUSED, char *val EINA_UNUSED) { WRN("The %s object does not implement the \"accessible_name_set\" function.", eo_class_name_get(eo_class_get(obj))); diff --git a/src/lib/elm_interface_atspi_accessible.eo b/src/lib/elm_interface_atspi_accessible.eo index 9ee5980..d277e3a 100644 --- a/src/lib/elm_interface_atspi_accessible.eo +++ b/src/lib/elm_interface_atspi_accessible.eo @@ -14,12 +14,13 @@ mixin Elm_Interface_Atspi_Accessible () } name @protected { get { - /*@ Gets an string describing ATSPI widget role name. */ + /*@ Gets an string describing ATSPI widget role name. + Should be free by a user. */ } set { } values { - const(char)* name; /*@ obj name */ + char* name; /*@ obj name */ } } relation_set @protected { diff --git a/src/lib/elm_interface_atspi_accessible.h b/src/lib/elm_interface_atspi_accessible.h index 32c9b95..acd152e 100644 --- a/src/lib/elm_interface_atspi_accessible.h +++ b/src/lib/elm_interface_atspi_accessible.h @@ -304,8 +304,8 @@ EAPI void elm_atspi_attributes_list_free(Eina_List *list); */ #define elm_interface_atspi_accessible_children_changed_added_signal_emit(obj, child) \ do { \ - Elm_Atspi_Event_Children_Changed_Data data = { EINA_TRUE, child }; \ - eo_do(obj, eo_event_callback_call(ELM_INTERFACE_ATSPI_ACCESSIBLE_EVENT_CHILDREN_CHANGED, &data)); \ + Elm_Atspi_Event_Children_Changed_Data atspi_data = { EINA_TRUE, child }; \ + eo_do(obj, eo_event_callback_call(ELM_INTERFACE_ATSPI_ACCESSIBLE_EVENT_CHILDREN_CHANGED, &atspi_data)); \ } while(0); /** @@ -313,8 +313,8 @@ EAPI void elm_atspi_attributes_list_free(Eina_List *list); */ #define elm_interface_atspi_accessible_children_changed_del_signal_emit(obj, child) \ do { \ - Elm_Atspi_Event_Children_Changed_Data data = { EINA_FALSE, child }; \ - eo_do(obj, eo_event_callback_call(ELM_INTERFACE_ATSPI_ACCESSIBLE_EVENT_CHILDREN_CHANGED, &data)); \ + Elm_Atspi_Event_Children_Changed_Data atspi_data = { EINA_FALSE, child }; \ + eo_do(obj, eo_event_callback_call(ELM_INTERFACE_ATSPI_ACCESSIBLE_EVENT_CHILDREN_CHANGED, &atspi_data)); \ } while(0); /** diff --git a/src/lib/elm_interface_atspi_widget.c b/src/lib/elm_interface_atspi_widget.c deleted file mode 100644 index cf04d89..0000000 --- a/src/lib/elm_interface_atspi_widget.c +++ /dev/null @@ -1,204 +0,0 @@ -#ifdef HAVE_CONFIG_H - #include "elementary_config.h" -#endif - -#define ELM_INTERFACE_ATSPI_ACCESSIBLE_PROTECTED -#define ELM_INTERFACE_ATSPI_COMPONENT_PROTECTED - -#include -#include "elm_widget.h" -#include "elm_priv.h" - -#include "assert.h" - -typedef struct _Elm_Interface_Atspi_Widget_Data Elm_Interface_Atspi_Widget_Data; - -struct _Elm_Interface_Atspi_Widget_Data { - Elm_Atspi_Role role; - const char *description; -}; - -static void -_on_focus_change(void *data, Evas_Object *obj, void *event_info EINA_UNUSED) -{ - Eina_Bool val = data ? EINA_TRUE : EINA_FALSE; - elm_interface_atspi_accessible_state_changed_signal_emit(obj, ELM_ATSPI_STATE_FOCUSED, val); -} - -EOLIAN void -_elm_interface_atspi_widget_eo_base_constructor(Eo *obj EINA_UNUSED, Elm_Interface_Atspi_Widget_Data *pd) -{ - eo_do_super(obj, ELM_INTERFACE_ATSPI_WIDGET_MIXIN, eo_constructor()); - - pd->role = ELM_ATSPI_ROLE_UNKNOWN; - - // Elm_Widget_Access_Object can only be constructed on top of Elm_Widget - assert(eo_isa(obj, ELM_WIDGET_CLASS)); - - evas_object_smart_callback_add(obj, "focused", _on_focus_change, (void*)1); - evas_object_smart_callback_add(obj, "unfocused", _on_focus_change, NULL); -} - -EOLIAN void -_elm_interface_atspi_widget_eo_base_destructor(Eo *obj EINA_UNUSED, Elm_Interface_Atspi_Widget_Data *pd) -{ - Eo *parent; - if (pd->description) eina_stringshare_del(pd->description); - - eo_do(obj, parent = elm_interface_atspi_accessible_parent_get()); - - if (parent && !eo_destructed_is(parent)) - elm_interface_atspi_accessible_children_changed_del_signal_emit(parent, obj); - - eo_do_super(obj, ELM_INTERFACE_ATSPI_WIDGET_MIXIN, eo_destructor()); -} - -EOLIAN static Eina_Bool -_elm_interface_atspi_widget_elm_interface_atspi_component_focus_grab(Eo *obj, Elm_Interface_Atspi_Widget_Data *pd EINA_UNUSED) -{ - if (elm_object_focus_allow_get(obj)) - { - Ecore_Evas *ee = ecore_evas_ecore_evas_get(evas_object_evas_get(obj)); - if (!ee) return EINA_FALSE; - ecore_evas_activate(ee); - elm_object_focus_set(obj, EINA_TRUE); - return EINA_TRUE; - } - return EINA_FALSE; -} - -EOLIAN static const char* -_elm_interface_atspi_widget_elm_interface_atspi_accessible_name_get(Eo *obj EINA_UNUSED, Elm_Interface_Atspi_Widget_Data *_pd EINA_UNUSED) -{ - return elm_object_text_get(obj); -} - -EOLIAN static const char* -_elm_interface_atspi_widget_elm_interface_atspi_accessible_description_get(Eo *obj EINA_UNUSED, Elm_Interface_Atspi_Widget_Data *_pd) -{ - return _pd->description; -} - -EOLIAN static void -_elm_interface_atspi_widget_elm_interface_atspi_accessible_description_set(Eo *obj EINA_UNUSED, Elm_Interface_Atspi_Widget_Data *_pd, const char *descr) -{ - eina_stringshare_replace(&_pd->description, descr); -} - -EOLIAN static Elm_Atspi_Role -_elm_interface_atspi_widget_elm_interface_atspi_accessible_role_get(Eo *obj EINA_UNUSED, Elm_Interface_Atspi_Widget_Data *pd EINA_UNUSED) -{ - return pd->role; -} - -EOLIAN static void -_elm_interface_atspi_widget_elm_interface_atspi_accessible_role_set(Eo *obj EINA_UNUSED, Elm_Interface_Atspi_Widget_Data *pd, Elm_Atspi_Role role) -{ - pd->role = role; -} - -EOLIAN static Eina_List* -_elm_interface_atspi_widget_elm_interface_atspi_accessible_children_get(Eo *obj EINA_UNUSED, Elm_Interface_Atspi_Widget_Data *pd EINA_UNUSED) -{ - Eina_List *l, *accs = NULL; - Elm_Widget_Smart_Data *wd; - Evas_Object *widget; - - wd = eo_data_scope_get(obj, ELM_WIDGET_CLASS); - if (!wd) return NULL; - - EINA_LIST_FOREACH(wd->subobjs, l, widget) - { - if (!elm_object_widget_check(widget)) continue; - if (eo_isa(widget, ELM_INTERFACE_ATSPI_ACCESSIBLE_MIXIN)) - accs = eina_list_append(accs, widget); - } - return accs; -} - -EOLIAN static Elm_Atspi_State_Set -_elm_interface_atspi_widget_elm_interface_atspi_accessible_state_set_get(Eo *obj, Elm_Interface_Atspi_Widget_Data *pd EINA_UNUSED) -{ - Elm_Atspi_State_Set states = 0; - Evas *evas = NULL; - - eo_do_super(obj, ELM_INTERFACE_ATSPI_WIDGET_MIXIN, states = elm_interface_atspi_accessible_state_set_get()); - - if (evas_object_visible_get(obj)) - STATE_TYPE_SET(states, ELM_ATSPI_STATE_VISIBLE); - evas = evas_object_evas_get(obj); - if (evas) - { - Evas_Coord x, y, w, h, wx, wy, ww, wh; - - evas_output_viewport_get(evas, &x, &y, &w, &h); - evas_object_geometry_get(obj, &wx, &wy, &ww, &wh); - if (!(((wx < x) && (wx + ww < x)) || ((wx > x + w) && (wx + ww > x + w)) || - ((wy < y) && (wy + wh < y)) || ((wy > y+ h) && (wy + wh > y + h)))) - STATE_TYPE_SET(states, ELM_ATSPI_STATE_SHOWING); - } - if (elm_object_focus_get(obj)) - STATE_TYPE_SET(states, ELM_ATSPI_STATE_FOCUSED); - if (elm_object_focus_allow_get(obj)) - STATE_TYPE_SET(states, ELM_ATSPI_STATE_FOCUSABLE); - if (!elm_object_disabled_get(obj)) - { - STATE_TYPE_SET(states, ELM_ATSPI_STATE_ENABLED); - STATE_TYPE_SET(states, ELM_ATSPI_STATE_ACTIVE); - STATE_TYPE_SET(states, ELM_ATSPI_STATE_SENSITIVE); - } - - return states; -} - -EOLIAN static Eina_List* -_elm_interface_atspi_widget_elm_interface_atspi_accessible_attributes_get(Eo *obj, Elm_Interface_Atspi_Widget_Data *pd EINA_UNUSED) -{ - Eina_List *ret = NULL; - Elm_Atspi_Attribute *attr = calloc(1, sizeof(Elm_Atspi_Attribute)); - if (!attr) return NULL; - - attr->key = eina_stringshare_add("type"); - attr->value = eina_stringshare_add(evas_object_type_get(obj)); - - ret = eina_list_append(ret, attr); - return ret; -} - -static Elm_Atspi_Relation* -_relation_new(Elm_Atspi_Relation_Type type, Eo *obj) -{ - Elm_Atspi_Relation *rel = calloc(1, sizeof(Elm_Atspi_Relation)); - if (!rel) return NULL; - - rel->type = type; - rel->obj = obj; - - return rel; -} - -EOLIAN static Eina_List* -_elm_interface_atspi_widget_elm_interface_atspi_accessible_relation_set_get(Eo *obj, Elm_Interface_Atspi_Widget_Data *pd EINA_UNUSED) -{ - 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 list; -} - -#include "elm_interface_atspi_widget.eo.c" diff --git a/src/lib/elm_interface_atspi_widget.eo b/src/lib/elm_interface_atspi_widget.eo deleted file mode 100644 index 672d212..0000000 --- a/src/lib/elm_interface_atspi_widget.eo +++ /dev/null @@ -1,19 +0,0 @@ -mixin Elm_Interface_Atspi_Widget (Elm_Interface_Atspi_Accessible, Elm_Interface_Atspi_Component, Eo.Base) -{ - eo_prefix: elm_interface_atspi_widget; - data: Elm_Interface_Atspi_Widget_Data; - implements { - Eo.Base.constructor; - Eo.Base.destructor; - Elm_Interface_Atspi_Accessible.name.get; - Elm_Interface_Atspi_Accessible.description.get; - Elm_Interface_Atspi_Accessible.description.set; - Elm_Interface_Atspi_Accessible.role.get; - Elm_Interface_Atspi_Accessible.role.set; - Elm_Interface_Atspi_Accessible.state_set.get; - Elm_Interface_Atspi_Accessible.children.get; - Elm_Interface_Atspi_Accessible.attributes.get; - Elm_Interface_Atspi_Accessible.relation_set.get; - Elm_Interface_Atspi_Component.focus_grab; - } -} diff --git a/src/lib/elm_interfaces.h b/src/lib/elm_interfaces.h index a77c8cb..61a359e 100644 --- a/src/lib/elm_interfaces.h +++ b/src/lib/elm_interfaces.h @@ -11,7 +11,6 @@ #include "elm_interface_atspi_image.eo.h" #include "elm_interface_atspi_selection.eo.h" #include "elm_interface_atspi_value.eo.h" -#include "elm_interface_atspi_widget.eo.h" #include "elm_interface_atspi_window.eo.h" #endif #endif @@ -23,7 +22,6 @@ #include "elm_interface_atspi_image.eo.legacy.h" #include "elm_interface_atspi_selection.eo.legacy.h" #include "elm_interface_atspi_value.eo.legacy.h" -#include "elm_interface_atspi_widget.eo.legacy.h" #include "elm_interface_atspi_window.eo.legacy.h" #endif #endif diff --git a/src/lib/elm_list.c b/src/lib/elm_list.c index 0f361db..6033714 100644 --- a/src/lib/elm_list.c +++ b/src/lib/elm_list.c @@ -4,6 +4,7 @@ #define ELM_INTERFACE_ATSPI_ACCESSIBLE_PROTECTED #define ELM_INTERFACE_ATSPI_WIDGET_ACTION_PROTECTED +#define ELM_INTERFACE_ATSPI_SELECTION_PROTECTED #define ELM_WIDGET_ITEM_PROTECTED #include @@ -1158,6 +1159,8 @@ _elm_list_item_focused(Elm_Object_Item *eo_it) evas_object_raise(VIEW(it)); evas_object_smart_callback_call (WIDGET(it), SIG_ITEM_FOCUSED, eo_it); + if (_elm_config->atspi_mode) + elm_interface_atspi_accessible_state_changed_signal_emit(eo_it, ELM_ATSPI_STATE_FOCUSED, EINA_TRUE); } static void @@ -1183,6 +1186,8 @@ _elm_list_item_unfocused(Elm_Object_Item *eo_it) sd->focused_item = NULL; evas_object_smart_callback_call(obj, SIG_ITEM_UNFOCUSED, eo_it); + if (_elm_config->atspi_mode) + elm_interface_atspi_accessible_state_changed_signal_emit(eo_it, ELM_ATSPI_STATE_FOCUSED, EINA_FALSE); } /* @@ -2158,6 +2163,42 @@ _elm_list_item_elm_widget_item_focus_get(Eo *eo_it, Elm_List_Item_Data *it) return EINA_FALSE; } +EOLIAN static Elm_Atspi_State_Set +_elm_list_item_elm_interface_atspi_accessible_state_set_get(Eo *eo_it, Elm_List_Item_Data *data EINA_UNUSED) +{ + Elm_Atspi_State_Set ret; + Eina_Bool sel; + + eo_do_super(eo_it, ELM_LIST_ITEM_CLASS, ret = elm_interface_atspi_accessible_state_set_get()); + eo_do(eo_it, sel = elm_obj_list_item_selected_get()); + + if (sel) + STATE_TYPE_SET(ret, ELM_ATSPI_STATE_SELECTED); + else + STATE_TYPE_UNSET(ret, ELM_ATSPI_STATE_SELECTED); + + return ret; +} + +EOLIAN static char* +_elm_list_item_elm_interface_atspi_accessible_name_get(Eo *eo_it EINA_UNUSED, Elm_List_Item_Data *data) +{ + 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) { @@ -2280,6 +2321,7 @@ _elm_list_item_eo_base_constructor(Eo *eo_it, Elm_List_Item_Data *it) { eo_do_super(eo_it, ELM_LIST_ITEM_CLASS, eo_constructor()); it->base = eo_data_scope_get(eo_it, ELM_WIDGET_ITEM_CLASS); + eo_do(eo_it, elm_interface_atspi_accessible_role_set(ELM_ATSPI_ROLE_LIST_ITEM)); } static Elm_List_Item_Data * @@ -2778,6 +2820,9 @@ _elm_list_item_append(Eo *obj, Elm_List_Data *sd, const char *label, Evas_Object it->node = eina_list_last(sd->items); elm_box_pack_end(sd->box, VIEW(it)); + if (_elm_config->atspi_mode) + elm_interface_atspi_accessible_children_changed_added_signal_emit(obj, EO_OBJ(it)); + return EO_OBJ(it); } @@ -2792,6 +2837,9 @@ _elm_list_item_prepend(Eo *obj, Elm_List_Data *sd, const char *label, Evas_Objec it->node = sd->items; elm_box_pack_start(sd->box, VIEW(it)); + if (_elm_config->atspi_mode) + elm_interface_atspi_accessible_children_changed_added_signal_emit(obj, EO_OBJ(it)); + return EO_OBJ(it); } @@ -2811,6 +2859,9 @@ _elm_list_item_insert_before(Eo *obj, Elm_List_Data *sd, Elm_Object_Item *eo_bef it->node = before_it->node->prev; elm_box_pack_before(sd->box, VIEW(it), VIEW(before_it)); + if (_elm_config->atspi_mode) + elm_interface_atspi_accessible_children_changed_added_signal_emit(obj, EO_OBJ(it)); + return EO_OBJ(it); } @@ -2830,6 +2881,9 @@ _elm_list_item_insert_after(Eo *obj, Elm_List_Data *sd, Elm_Object_Item *eo_afte it->node = after_it->node->next; elm_box_pack_after(sd->box, VIEW(it), VIEW(after_it)); + if (_elm_config->atspi_mode) + elm_interface_atspi_accessible_children_changed_added_signal_emit(obj, EO_OBJ(it)); + return EO_OBJ(it); } @@ -2858,16 +2912,23 @@ _elm_list_item_sorted_insert(Eo *obj, Elm_List_Data *sd, const char *label, Evas elm_box_pack_before(sd->box, VIEW(it), VIEW(before)); } + if (_elm_config->atspi_mode) + elm_interface_atspi_accessible_children_changed_added_signal_emit(obj, EO_OBJ(it)); + return EO_OBJ(it); } EOLIAN static void -_elm_list_item_separator_set(Eo *eo_item EINA_UNUSED, Elm_List_Item_Data *it, - Eina_Bool setting) +_elm_list_item_separator_set(Eo *eo_item, Elm_List_Item_Data *it, Eina_Bool setting) { ELM_LIST_ITEM_CHECK_OR_RETURN(it); it->is_separator = !!setting; + + if (it->is_separator) + eo_do(eo_item, elm_interface_atspi_accessible_role_set(ELM_ATSPI_ROLE_SEPARATOR)); + else + eo_do(eo_item, elm_interface_atspi_accessible_role_set(ELM_ATSPI_ROLE_LIST_ITEM)); } EOLIAN static Eina_Bool @@ -3166,5 +3227,101 @@ _elm_list_elm_interface_atspi_widget_action_elm_actions_get(Eo *obj EINA_UNUSED, }; return &atspi_actions[0]; } + +EOLIAN Eina_List* +_elm_list_elm_interface_atspi_accessible_children_get(Eo *eo_item EINA_UNUSED, Elm_List_Data *pd) +{ + return eina_list_clone(pd->items); +} + +EOLIAN int +_elm_list_elm_interface_atspi_selection_selected_children_count_get(Eo *objm EINA_UNUSED, Elm_List_Data *pd) +{ + return eina_list_count(pd->selected); +} + +EOLIAN Eo* +_elm_list_elm_interface_atspi_selection_selected_child_get(Eo *obj EINA_UNUSED, Elm_List_Data *pd, int child_idx) +{ + return eina_list_nth(pd->selected, child_idx); +} + +EOLIAN Eina_Bool +_elm_list_elm_interface_atspi_selection_child_select(Eo *obj EINA_UNUSED, Elm_List_Data *pd, int child_index) +{ + if (pd->select_mode != ELM_OBJECT_SELECT_MODE_NONE) + { + Eo *item = eina_list_nth(pd->items, child_index); + if (item) + elm_list_item_selected_set(item, EINA_TRUE); + return EINA_TRUE; + } + return EINA_FALSE; +} + +EOLIAN Eina_Bool +_elm_list_elm_interface_atspi_selection_selected_child_deselect(Eo *obj EINA_UNUSED, Elm_List_Data *pd, int child_index) +{ + Eo *item = eina_list_nth(pd->selected, child_index); + if (item) + { + elm_list_item_selected_set(item, EINA_FALSE); + return EINA_TRUE; + } + return EINA_FALSE; +} + +EOLIAN Eina_Bool +_elm_list_elm_interface_atspi_selection_is_child_selected(Eo *obj EINA_UNUSED, Elm_List_Data *pd, int child_index) +{ + Eo *item = eina_list_nth(pd->items, child_index); + if (item) + return elm_list_item_selected_get(item); + + return EINA_FALSE; +} + +EOLIAN Eina_Bool +_elm_list_elm_interface_atspi_selection_all_children_select(Eo *obj EINA_UNUSED, Elm_List_Data *pd) +{ + Eo *it; + Eina_List *l; + + if (pd->select_mode == ELM_OBJECT_SELECT_MODE_NONE) + return EINA_FALSE; + + EINA_LIST_FOREACH(pd->items, l, it) + elm_list_item_selected_set(it, EINA_TRUE); + + return EINA_TRUE; +} + +EOLIAN Eina_Bool +_elm_list_elm_interface_atspi_selection_clear(Eo *obj EINA_UNUSED, Elm_List_Data *pd) +{ + Eo *it; + Eina_List *l; + + if (pd->select_mode == ELM_OBJECT_SELECT_MODE_NONE) + return EINA_FALSE; + + EINA_LIST_FOREACH(pd->items, l, it) + elm_list_item_selected_set(it, EINA_FALSE); + + return EINA_TRUE; +} + +EOLIAN Eina_Bool +_elm_list_elm_interface_atspi_selection_child_deselect(Eo *obj EINA_UNUSED, Elm_List_Data *pd, int child_index) +{ + Eo *item = eina_list_nth(pd->items, child_index); + if (item) + { + elm_list_item_selected_set(item, EINA_FALSE); + return EINA_TRUE; + } + return EINA_FALSE; +} + #include "elm_list.eo.c" #include "elm_list_item.eo.c" diff --git a/src/lib/elm_list.eo b/src/lib/elm_list.eo index f1b9556..9685ca0 100644 --- a/src/lib/elm_list.eo +++ b/src/lib/elm_list.eo @@ -1,5 +1,5 @@ class Elm_List (Elm_Layout, Elm_Interface_Scrollable, - Elm_Interface_Atspi_Widget_Action) + Elm_Interface_Atspi_Widget_Action, Elm_Interface_Atspi_Selection) { eo_prefix: elm_obj_list; properties { @@ -609,6 +609,15 @@ class Elm_List (Elm_Layout, Elm_Interface_Scrollable, Elm_Layout.sizing_eval; Elm_Interface_Scrollable.policy.set; Elm_Interface_Atspi_Widget_Action.elm_actions.get; + Elm_Interface_Atspi_Accessible.children.get; + Elm_Interface_Atspi_Selection.selected_children_count.get; + Elm_Interface_Atspi_Selection.selected_child.get; + Elm_Interface_Atspi_Selection.selected_child_deselect; + Elm_Interface_Atspi_Selection.child_select; + Elm_Interface_Atspi_Selection.child_deselect; + Elm_Interface_Atspi_Selection.is_child_selected; + Elm_Interface_Atspi_Selection.all_children_select; + Elm_Interface_Atspi_Selection.clear; } events { activated; diff --git a/src/lib/elm_list_item.eo b/src/lib/elm_list_item.eo index 597be64..7fa8c84 100644 --- a/src/lib/elm_list_item.eo +++ b/src/lib/elm_list_item.eo @@ -6,9 +6,7 @@ class Elm_List_Item(Elm_Widget_Item) get { /*@ Get a value whether item is a separator or not. - - @see elm_list_item_separator_set() for details. - +@see elm_list_item_separator_set() for details. @ingroup List */ } @@ -163,6 +161,9 @@ class Elm_List_Item(Elm_Widget_Item) Elm_Widget_Item.part_content.get; Elm_Widget_Item.part_content.set; 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; } } diff --git a/src/lib/elm_radio.c b/src/lib/elm_radio.c index da253f1..604e823 100644 --- a/src/lib/elm_radio.c +++ b/src/lib/elm_radio.c @@ -57,6 +57,15 @@ _state_set(Evas_Object *obj, Eina_Bool state) elm_layout_signal_emit(obj, "elm,state,radio,on", "elm"); else elm_layout_signal_emit(obj, "elm,state,radio,off", "elm"); + if (_elm_config->atspi_mode) + { + if (sd->state) + { + elm_interface_atspi_accessible_state_changed_signal_emit(obj, ELM_ATSPI_STATE_CHECKED, EINA_TRUE); + } + else + elm_interface_atspi_accessible_state_changed_signal_emit(obj, ELM_ATSPI_STATE_CHECKED, EINA_FALSE); + } } } @@ -452,4 +461,16 @@ _elm_radio_elm_interface_atspi_widget_action_elm_actions_get(Eo *obj EINA_UNUSED return &atspi_actions[0]; } +EOLIAN Elm_Atspi_State_Set +_elm_radio_elm_interface_atspi_accessible_state_set_get(Eo *obj, Elm_Radio_Data *pd EINA_UNUSED) +{ + Elm_Atspi_State_Set ret; + + eo_do_super(obj, ELM_RADIO_CLASS, ret = elm_interface_atspi_accessible_state_set_get()); + if (obj == elm_radio_selected_object_get(obj)) + STATE_TYPE_SET(ret, ELM_ATSPI_STATE_CHECKED); + + return ret; +} + #include "elm_radio.eo.c" diff --git a/src/lib/elm_radio.eo b/src/lib/elm_radio.eo index 566afdf..7a644aa 100644 --- a/src/lib/elm_radio.eo +++ b/src/lib/elm_radio.eo @@ -112,6 +112,7 @@ class Elm_Radio (Elm_Layout, Elm_Interface_Atspi_Widget_Action) Elm_Layout.text_aliases.get; Elm_Layout.content_aliases.get; Elm_Layout.sizing_eval; + Elm_Interface_Atspi_Accessible.state_set.get; Elm_Interface_Atspi_Widget_Action.elm_actions.get; } events { diff --git a/src/lib/elm_spinner.c b/src/lib/elm_spinner.c index 77725eb..f800765 100644 --- a/src/lib/elm_spinner.c +++ b/src/lib/elm_spinner.c @@ -1114,10 +1114,11 @@ _elm_spinner_elm_interface_atspi_value_increment_get(Eo *obj EINA_UNUSED, Elm_Sp return sd->step; } -EOLIAN static const char* +EOLIAN static char* _elm_spinner_elm_interface_atspi_accessible_name_get(Eo *obj, Elm_Spinner_Data *sd EINA_UNUSED) { - return elm_layout_text_get(obj, "elm.text"); + const char *ret = elm_layout_text_get(obj, "elm.text"); + return ret ? strdup(ret) : NULL; } EOLIAN static const Elm_Atspi_Action* diff --git a/src/lib/elm_toolbar.c b/src/lib/elm_toolbar.c index 92e217b..2e6ef22 100644 --- a/src/lib/elm_toolbar.c +++ b/src/lib/elm_toolbar.c @@ -634,6 +634,8 @@ _elm_toolbar_item_focused(Elm_Object_Item *eo_it) evas_object_raise(VIEW(it)); evas_object_smart_callback_call (obj, SIG_ITEM_FOCUSED, EO_OBJ(it)); + if (_elm_config->atspi_mode) + elm_interface_atspi_accessible_state_changed_signal_emit(EO_OBJ(it), ELM_ATSPI_STATE_FOCUSED, EINA_TRUE); } static void @@ -659,6 +661,8 @@ _elm_toolbar_item_unfocused(Elm_Object_Item *eo_it) sd->focused_item = NULL; evas_object_smart_callback_call (obj, SIG_ITEM_UNFOCUSED, eo_it); + if (_elm_config->atspi_mode) + elm_interface_atspi_accessible_state_changed_signal_emit(eo_it, ELM_ATSPI_STATE_FOCUSED, EINA_TRUE); } /* @@ -2304,6 +2308,7 @@ _elm_toolbar_item_eo_base_constructor(Eo *eo_it, Elm_Toolbar_Item_Data *it) { eo_do_super(eo_it, ELM_TOOLBAR_ITEM_CLASS, eo_constructor()); it->base = eo_data_scope_get(eo_it, ELM_WIDGET_ITEM_CLASS); + eo_do(eo_it, elm_interface_atspi_accessible_role_set(ELM_ATSPI_ROLE_MENU_ITEM)); } static Elm_Toolbar_Item_Data * @@ -3823,6 +3828,30 @@ _elm_toolbar_item_bring_in(Eo *eo_item EINA_UNUSED, Elm_Toolbar_Item_Data *item, (x, y, w, h)); } +EOLIAN static char* +_elm_toolbar_item_elm_interface_atspi_accessible_name_get(Eo *eo_item EINA_UNUSED, Elm_Toolbar_Item_Data *item) +{ + return item->label ? strdup(item->label) : NULL; +} + +EOLIAN static Elm_Atspi_State_Set +_elm_toolbar_item_elm_interface_atspi_accessible_state_set_get(Eo *eo_it, Elm_Toolbar_Item_Data *item EINA_UNUSED) +{ + Elm_Atspi_State_Set ret; + Eina_Bool sel; + + eo_do_super(eo_it, ELM_TOOLBAR_ITEM_CLASS, ret = elm_interface_atspi_accessible_state_set_get()); + + eo_do(eo_it, sel = elm_obj_toolbar_item_selected_get()); + + STATE_TYPE_SET(ret, ELM_ATSPI_STATE_SELECTABLE); + + if (sel) + STATE_TYPE_SET(ret, ELM_ATSPI_STATE_SELECTED); + + return ret; +} + EOLIAN static Elm_Object_Item * _elm_toolbar_elm_widget_focused_item_get(Eo *obj EINA_UNUSED, Elm_Toolbar_Data *sd) { @@ -3849,5 +3878,29 @@ _elm_toolbar_elm_interface_atspi_widget_action_elm_actions_get(Eo *obj EINA_UNUS return &atspi_actions[0]; } +EOLIAN static Eina_List* +_elm_toolbar_elm_interface_atspi_accessible_children_get(Eo *obj EINA_UNUSED, Elm_Toolbar_Data *sd) +{ + Eina_List *ret = NULL; + Elm_Toolbar_Item_Data *it; + + EINA_INLIST_FOREACH(sd->items, it) + ret = eina_list_append(ret, EO_OBJ(it)); + + return ret; +} + +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; +} + #include "elm_toolbar.eo.c" #include "elm_toolbar_item.eo.c" diff --git a/src/lib/elm_toolbar.eo b/src/lib/elm_toolbar.eo index fe09f25..7d572e5 100644 --- a/src/lib/elm_toolbar.eo +++ b/src/lib/elm_toolbar.eo @@ -514,6 +514,8 @@ class Elm_Toolbar (Elm_Widget, Elm_Interface_Scrollable, Elm_Widget.focus_highlight_geometry_get; Elm_Widget.focused_item.get; Elm_Interface_Atspi_Widget_Action.elm_actions.get; + Elm_Interface_Atspi_Accessible.children.get; + Elm_Interface_Atspi_Accessible.state_set.get; } events { scroll; diff --git a/src/lib/elm_toolbar_item.eo b/src/lib/elm_toolbar_item.eo index 9d0e802..f0cb928 100644 --- a/src/lib/elm_toolbar_item.eo +++ b/src/lib/elm_toolbar_item.eo @@ -424,5 +424,7 @@ class Elm_Toolbar_Item(Elm_Widget_Item) Elm_Widget_Item.part_content.get; Elm_Widget_Item.part_content.set; Elm_Widget_Item.part_content_unset; + Elm_Interface_Atspi_Accessible.name.get; + Elm_Interface_Atspi_Accessible.state_set.get; } } diff --git a/src/lib/elm_widget.c b/src/lib/elm_widget.c index a465e17..3ad7e66 100644 --- a/src/lib/elm_widget.c +++ b/src/lib/elm_widget.c @@ -2,6 +2,8 @@ # include "elementary_config.h" #endif +#define ELM_INTERFACE_ATSPI_ACCESSIBLE_PROTECTED +#define ELM_INTERFACE_ATSPI_COMPONENT_PROTECTED #define ELM_WIDGET_ITEM_PROTECTED #include @@ -541,6 +543,13 @@ _elm_widget_evas_object_smart_show(Eo *obj, Elm_Widget_Smart_Data *_pd EINA_UNUS Eina_Iterator *it; Evas_Object *o; + if (_elm_config->atspi_mode) + { + Eo *parent; + eo_do(obj, parent = elm_interface_atspi_accessible_parent_get()); + elm_interface_atspi_accessible_children_changed_added_signal_emit(parent, obj); + } + it = evas_object_smart_iterator_new(obj); EINA_ITERATOR_FOREACH(it, o) { @@ -1283,6 +1292,8 @@ _elm_widget_sub_object_del(Eo *obj, Elm_Widget_Smart_Data *sd, Evas_Object *sobj sd->subobjs = eina_list_remove(sd->subobjs, sobj); + if (_elm_config->atspi_mode) + elm_interface_atspi_accessible_children_changed_del_signal_emit(obj, sobj); _callbacks_del(sobj, obj); return EINA_TRUE; @@ -4274,6 +4285,12 @@ _elm_widget_item_eo_base_destructor(Eo *eo_item, Elm_Widget_Item_Data *item) } eina_hash_free(item->labels); + if (item->description) + eina_stringshare_del(item->description); + + if (_elm_config->atspi_mode) + elm_interface_atspi_accessible_children_changed_del_signal_emit(item->widget, eo_item); + EINA_MAGIC_SET(item, EINA_MAGIC_NONE); eo_do_super(eo_item, ELM_WIDGET_ITEM_CLASS, eo_destructor()); @@ -4396,6 +4413,61 @@ _elm_widget_item_widget_get(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item) return item->widget; } +EOLIAN static const char* +_elm_widget_item_elm_interface_atspi_accessible_description_get(Eo *eo_item EINA_UNUSED, + Elm_Widget_Item_Data *item) +{ + return item->description; +} + +EOLIAN static void +_elm_widget_item_elm_interface_atspi_accessible_description_set(Eo *eo_item EINA_UNUSED, + Elm_Widget_Item_Data *item, + const char *descr) +{ + eina_stringshare_replace(&item->description, descr); +} + +EOLIAN static Elm_Atspi_Role +_elm_widget_item_elm_interface_atspi_accessible_role_get(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item) +{ + return item->role; +} + +EOLIAN static void +_elm_widget_item_elm_interface_atspi_accessible_role_set(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item, + Elm_Atspi_Role role) +{ + item->role = role; +} + +EOLIAN static Elm_Atspi_State_Set +_elm_widget_item_elm_interface_atspi_accessible_state_set_get(Eo *eo_item EINA_UNUSED, + Elm_Widget_Item_Data *item EINA_UNUSED) +{ + Elm_Atspi_State_Set states = 0; + + STATE_TYPE_SET(states, ELM_ATSPI_STATE_FOCUSABLE); + + if (elm_object_item_focus_get(eo_item)) + STATE_TYPE_SET(states, ELM_ATSPI_STATE_FOCUSED); + if (!elm_object_item_disabled_get(eo_item)) + { + STATE_TYPE_SET(states, ELM_ATSPI_STATE_ACTIVE); + STATE_TYPE_SET(states, ELM_ATSPI_STATE_ENABLED); + STATE_TYPE_SET(states, ELM_ATSPI_STATE_SENSITIVE); + } + + 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) @@ -5354,6 +5426,13 @@ elm_widget_tree_dot_dump(const Evas_Object *top, #endif } +static void +_on_focus_change(void *data, Evas_Object *obj, void *event_info EINA_UNUSED) +{ + Eina_Bool val = data ? EINA_TRUE : EINA_FALSE; + elm_interface_atspi_accessible_state_changed_signal_emit(obj, ELM_ATSPI_STATE_FOCUSED, val); +} + EOLIAN static void _elm_widget_eo_base_constructor(Eo *obj, Elm_Widget_Smart_Data *sd) { @@ -5367,6 +5446,23 @@ _elm_widget_eo_base_constructor(Eo *obj, Elm_Widget_Smart_Data *sd) parent = eo_parent_get()); eo_do(obj, elm_obj_widget_parent_set(parent)); sd->on_create = EINA_FALSE; + + sd->role = ELM_ATSPI_ROLE_UNKNOWN; + evas_object_smart_callback_add(obj, "focused", _on_focus_change, (void*)1); + evas_object_smart_callback_add(obj, "unfocused", _on_focus_change, NULL); +} + +EOLIAN static void +_elm_widget_eo_base_destructor(Eo *obj, Elm_Widget_Smart_Data *sd) +{ + Eo *parent; + if (sd->description) eina_stringshare_del(sd->description); + + eo_do(obj, parent = elm_interface_atspi_accessible_parent_get()); + if (parent && !eo_destructed_is(parent)) + elm_interface_atspi_accessible_children_changed_del_signal_emit(parent, obj); + + eo_do_super(obj, ELM_WIDGET_CLASS, eo_destructor()); } EOLIAN static Eina_Bool @@ -5435,5 +5531,172 @@ _elm_widget_class_constructor(Eo_Class *klass) evas_smart_legacy_type_register(MY_CLASS_NAME_LEGACY, klass); } +EOLIAN static Eina_Bool +_elm_widget_elm_interface_atspi_component_focus_grab(Eo *obj, Elm_Widget_Smart_Data *pd EINA_UNUSED) +{ + if (elm_object_focus_allow_get(obj)) + { + Ecore_Evas *ee = ecore_evas_ecore_evas_get(evas_object_evas_get(obj)); + if (!ee) return EINA_FALSE; + ecore_evas_activate(ee); + elm_object_focus_set(obj, EINA_TRUE); + return EINA_TRUE; + } + return EINA_FALSE; +} + +EOLIAN static char* +_elm_widget_elm_interface_atspi_accessible_name_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *_pd EINA_UNUSED) +{ + const char *ret; + ret = elm_object_text_get(obj); + if (!ret) return NULL; + + return _elm_util_mkup_to_text(ret); +} + +EOLIAN static const char* +_elm_widget_elm_interface_atspi_accessible_description_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *_pd) +{ + return _pd->description; +} + +EOLIAN static void +_elm_widget_elm_interface_atspi_accessible_description_set(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *_pd, const char *descr) +{ + eina_stringshare_replace(&_pd->description, descr); +} + +EOLIAN static Elm_Atspi_Role +_elm_widget_elm_interface_atspi_accessible_role_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *pd EINA_UNUSED) +{ + return pd->role; +} + +EOLIAN static void +_elm_widget_elm_interface_atspi_accessible_role_set(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *pd, Elm_Atspi_Role role) +{ + pd->role = role; +} + +EOLIAN static Eina_List* +_elm_widget_elm_interface_atspi_accessible_children_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *pd EINA_UNUSED) +{ + Eina_List *l, *accs = NULL; + Elm_Widget_Smart_Data *wd; + Evas_Object *widget; + + wd = eo_data_scope_get(obj, ELM_WIDGET_CLASS); + if (!wd) return NULL; + + EINA_LIST_FOREACH(wd->subobjs, l, widget) + { + if (!elm_object_widget_check(widget)) continue; + if (eo_isa(widget, ELM_INTERFACE_ATSPI_ACCESSIBLE_MIXIN)) + accs = eina_list_append(accs, widget); + } + return accs; +} + +EOLIAN static Eo* +_elm_widget_elm_interface_atspi_accessible_parent_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *pd) +{ + if (pd->atspi_custom_parent) + return pd->atspi_custom_parent; + else + return pd->parent_obj; +} + +EOLIAN static void +_elm_widget_elm_interface_atspi_accessible_parent_set(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *pd, Eo *parent) +{ + pd->atspi_custom_parent = parent; +} + +EOLIAN static Elm_Atspi_State_Set +_elm_widget_elm_interface_atspi_accessible_state_set_get(Eo *obj, Elm_Widget_Smart_Data *pd EINA_UNUSED) +{ + Elm_Atspi_State_Set states = 0; + Evas *evas = NULL; + + eo_do_super(obj, ELM_WIDGET_CLASS, states = elm_interface_atspi_accessible_state_set_get()); + + if (evas_object_visible_get(obj)) + STATE_TYPE_SET(states, ELM_ATSPI_STATE_VISIBLE); + evas = evas_object_evas_get(obj); + if (evas) + { + Evas_Coord x, y, w, h, wx, wy, ww, wh; + + evas_output_viewport_get(evas, &x, &y, &w, &h); + evas_object_geometry_get(obj, &wx, &wy, &ww, &wh); + if (!(((wx < x) && (wx + ww < x)) || ((wx > x + w) && (wx + ww > x + w)) || + ((wy < y) && (wy + wh < y)) || ((wy > y+ h) && (wy + wh > y + h)))) + STATE_TYPE_SET(states, ELM_ATSPI_STATE_SHOWING); + } + if (elm_object_focus_get(obj)) + STATE_TYPE_SET(states, ELM_ATSPI_STATE_FOCUSED); + if (elm_object_focus_allow_get(obj)) + STATE_TYPE_SET(states, ELM_ATSPI_STATE_FOCUSABLE); + if (!elm_object_disabled_get(obj)) + { + STATE_TYPE_SET(states, ELM_ATSPI_STATE_ENABLED); + STATE_TYPE_SET(states, ELM_ATSPI_STATE_ACTIVE); + STATE_TYPE_SET(states, ELM_ATSPI_STATE_SENSITIVE); + } + + return states; +} + +EOLIAN static Eina_List* +_elm_widget_elm_interface_atspi_accessible_attributes_get(Eo *obj, Elm_Widget_Smart_Data *pd EINA_UNUSED) +{ + Eina_List *ret = NULL; + Elm_Atspi_Attribute *attr = calloc(1, sizeof(Elm_Atspi_Attribute)); + if (!attr) return NULL; + + attr->key = eina_stringshare_add("type"); + attr->value = eina_stringshare_add(evas_object_type_get(obj)); + + ret = eina_list_append(ret, attr); + return ret; +} + +static Elm_Atspi_Relation* +_relation_new(Elm_Atspi_Relation_Type type, Eo *obj) +{ + Elm_Atspi_Relation *rel = calloc(1, sizeof(Elm_Atspi_Relation)); + if (!rel) return NULL; + + rel->type = type; + rel->obj = obj; + + return rel; +} + +EOLIAN static Eina_List* +_elm_widget_elm_interface_atspi_accessible_relation_set_get(Eo *obj, Elm_Widget_Smart_Data *pd EINA_UNUSED) +{ + 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 list; +} + #include "elm_widget_item.eo.c" #include "elm_widget.eo.c" diff --git a/src/lib/elm_widget.eo b/src/lib/elm_widget.eo index 9df00f8..53e3c4f 100644 --- a/src/lib/elm_widget.eo +++ b/src/lib/elm_widget.eo @@ -1,4 +1,4 @@ -abstract Elm_Widget (Evas.Object_Smart, Elm_Interface_Atspi_Widget) +abstract Elm_Widget (Evas.Object_Smart, Elm_Interface_Atspi_Accessible, Elm_Interface_Atspi_Component) { eo_prefix: elm_obj_widget; data: Elm_Widget_Smart_Data; @@ -796,6 +796,7 @@ abstract Elm_Widget (Evas.Object_Smart, Elm_Interface_Atspi_Widget) implements { class.constructor; Eo.Base.constructor; + Eo.Base.destructor; Eo.Base.dbg_info_get; Evas.Object_Smart.hide; Evas.Object_Smart.calculate; @@ -812,5 +813,17 @@ abstract Elm_Widget (Evas.Object_Smart, Elm_Interface_Atspi_Widget) @virtual .focus_direction; @virtual .focus_next; @virtual .parent_widget.get; + Elm_Interface_Atspi_Accessible.name.get; + Elm_Interface_Atspi_Accessible.description.get; + Elm_Interface_Atspi_Accessible.description.set; + Elm_Interface_Atspi_Accessible.role.get; + Elm_Interface_Atspi_Accessible.role.set; + Elm_Interface_Atspi_Accessible.state_set.get; + Elm_Interface_Atspi_Accessible.children.get; + Elm_Interface_Atspi_Accessible.parent.get; + Elm_Interface_Atspi_Accessible.parent.set; + Elm_Interface_Atspi_Accessible.attributes.get; + Elm_Interface_Atspi_Accessible.relation_set.get; + Elm_Interface_Atspi_Component.focus_grab; } } diff --git a/src/lib/elm_widget.h b/src/lib/elm_widget.h index e7b91ed..84c3442 100644 --- a/src/lib/elm_widget.h +++ b/src/lib/elm_widget.h @@ -407,6 +407,10 @@ typedef struct _Elm_Widget_Smart_Data Eina_List *focus_chain; Eina_List *event_cb; + int role; /**< Accessibility role */ + const char *description; /**< Accessibility description */ + Eo *atspi_custom_parent; /**< Accessibility parent if different then parent_obj */ + /* 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 * widget (mainly issued by entries, on cursor moving) */ @@ -614,6 +618,10 @@ struct _Elm_Widget_Item_Data Eina_Hash *labels; Evas_Object *track_obj; + /**< A11Y info */ + const char *description; + int role; + Eina_Bool disabled : 1; Eina_Bool on_deletion : 1; Eina_Bool on_translate : 1; diff --git a/src/lib/elm_widget_item.eo b/src/lib/elm_widget_item.eo index 2c080fa..431d237 100644 --- a/src/lib/elm_widget_item.eo +++ b/src/lib/elm_widget_item.eo @@ -1,4 +1,4 @@ -class Elm_Widget_Item(Eo.Base) +class Elm_Widget_Item(Eo.Base, Elm_Interface_Atspi_Accessible) { eo_prefix: elm_wdg_item; legacy_prefix: elm_object_item; @@ -726,5 +726,11 @@ class Elm_Widget_Item(Eo.Base) implements { Eo.Base.constructor; Eo.Base.destructor; + Elm_Interface_Atspi_Accessible.description.get; + Elm_Interface_Atspi_Accessible.description.set; + Elm_Interface_Atspi_Accessible.role.get; + Elm_Interface_Atspi_Accessible.role.set; + Elm_Interface_Atspi_Accessible.state_set.get; + Elm_Interface_Atspi_Accessible.parent.get; } } diff --git a/src/tests/elm_test_gengrid.c b/src/tests/elm_test_gengrid.c index cd10fd7..1d95a67 100644 --- a/src/tests/elm_test_gengrid.c +++ b/src/tests/elm_test_gengrid.c @@ -18,7 +18,7 @@ START_TEST (elm_atspi_role_get) gengrid = elm_gengrid_add(win); eo_do(gengrid, role = elm_interface_atspi_accessible_role_get()); - ck_assert(role == ELM_ATSPI_ROLE_TABLE); + ck_assert(role == ELM_ATSPI_ROLE_TREE_TABLE); elm_shutdown(); } diff --git a/src/tests/elm_test_genlist.c b/src/tests/elm_test_genlist.c index d3bb70d..ade75c8 100644 --- a/src/tests/elm_test_genlist.c +++ b/src/tests/elm_test_genlist.c @@ -6,16 +6,26 @@ #include #include "elm_suite.h" +static Evas_Object *win, *genlist; +static Elm_Gen_Item_Class itc; +static Eo *current; +static int counter; +static Elm_Atspi_Event_Children_Changed_Data ev_data; -START_TEST (elm_atspi_role_get) +void test_init(void) { - Evas_Object *win, *genlist; - Elm_Atspi_Role role; - elm_init(1, NULL); + elm_config_atspi_mode_set(EINA_TRUE); win = elm_win_add(NULL, "genlist", ELM_WIN_BASIC); - genlist = elm_genlist_add(win); +} + +START_TEST (elm_atspi_role_get) +{ + test_init(); + + Elm_Atspi_Role role; + eo_do(genlist, role = elm_interface_atspi_accessible_role_get()); ck_assert(role == ELM_ATSPI_ROLE_LIST); @@ -24,7 +34,153 @@ START_TEST (elm_atspi_role_get) } END_TEST +START_TEST(elm_atspi_children_get1) +{ + test_init(); + Eina_List *children; + Elm_Object_Item *it[3]; + + eo_do(genlist, children = elm_interface_atspi_accessible_children_get()); + ck_assert(children == NULL); + + it[0] = elm_genlist_item_append(genlist, &itc, NULL, NULL, ELM_GENLIST_ITEM_NONE, NULL, NULL); + it[1] = elm_genlist_item_append(genlist, &itc, NULL, NULL, ELM_GENLIST_ITEM_NONE, NULL, NULL); + it[2] = elm_genlist_item_append(genlist, &itc, NULL, NULL, ELM_GENLIST_ITEM_NONE, NULL, NULL); + + eo_do(genlist, children = elm_interface_atspi_accessible_children_get()); + ck_assert(eina_list_count(children) == 3); + ck_assert(eina_list_nth(children, 0) == it[0]); + ck_assert(eina_list_nth(children, 1) == it[1]); + ck_assert(eina_list_nth(children, 2) == it[2]); + + eina_list_free(children); + + elm_shutdown(); +} +END_TEST + +START_TEST(elm_atspi_children_get2) +{ + test_init(); + Eina_List *children; + Elm_Object_Item *it[3]; + + it[0] = elm_genlist_item_append(genlist, &itc, NULL, NULL, ELM_GENLIST_ITEM_NONE, NULL, NULL); + it[1] = elm_genlist_item_prepend(genlist, &itc, NULL, NULL, ELM_GENLIST_ITEM_GROUP, NULL, NULL); + it[2] = elm_genlist_item_append(genlist, &itc, NULL, NULL, ELM_GENLIST_ITEM_TREE, NULL, NULL); + + eo_do(genlist, children = elm_interface_atspi_accessible_children_get()); + ck_assert(eina_list_nth(children, 1) == it[0]); + ck_assert(eina_list_nth(children, 0) == it[1]); + ck_assert(eina_list_nth(children, 2) == it[2]); + + elm_shutdown(); +} +END_TEST + +static Eina_Bool +_children_changed_cb(void *data EINA_UNUSED, Eo *obj EINA_UNUSED, + const Eo_Event_Description *desc EINA_UNUSED, void *event_info EINA_UNUSED) +{ + ev_data = *(Elm_Atspi_Event_Children_Changed_Data*)event_info; + current = obj; + counter++; + + return EINA_TRUE; +} + +START_TEST(elm_atspi_children_events_add) +{ + test_init(); + + current = NULL; + counter = 0; + + Elm_Object_Item *it[3]; + + eo_do(genlist, eo_event_callback_add(ELM_INTERFACE_ATSPI_ACCESSIBLE_EVENT_CHILDREN_CHANGED, _children_changed_cb, NULL)); + + it[0] = elm_genlist_item_append(genlist, &itc, NULL, NULL, ELM_GENLIST_ITEM_NONE, NULL, NULL); + ck_assert(genlist == current); + ck_assert(counter == 1); + ck_assert(ev_data.is_added == EINA_TRUE); + ck_assert(ev_data.child == it[0]); + + it[1] = elm_genlist_item_prepend(genlist, &itc, it[0], NULL, ELM_GENLIST_ITEM_GROUP, NULL, NULL); + ck_assert(genlist == current); + ck_assert(counter == 2); + ck_assert(ev_data.is_added == EINA_TRUE); + ck_assert(ev_data.child == it[1]); + + it[2] = elm_genlist_item_append(genlist, &itc, NULL, NULL, ELM_GENLIST_ITEM_TREE, NULL, NULL); + ck_assert(genlist == current); + ck_assert(counter == 3); + ck_assert(ev_data.is_added == EINA_TRUE); + ck_assert(ev_data.child == it[2]); + + elm_shutdown(); +} +END_TEST + +START_TEST(elm_atspi_children_events_del1) +{ + test_init(); + + current = NULL; + counter = 0; + + Elm_Object_Item *it[3]; + + it[0] = elm_genlist_item_append(genlist, &itc, NULL, NULL, ELM_GENLIST_ITEM_NONE, NULL, NULL); + it[1] = elm_genlist_item_prepend(genlist, &itc, NULL, NULL, ELM_GENLIST_ITEM_NONE, NULL, NULL); + it[2] = elm_genlist_item_append(genlist, &itc, NULL, NULL, ELM_GENLIST_ITEM_TREE, NULL, NULL); + + eo_do(genlist, eo_event_callback_add(ELM_INTERFACE_ATSPI_ACCESSIBLE_EVENT_CHILDREN_CHANGED, _children_changed_cb, NULL)); + + elm_object_item_del(it[0]); + ck_assert(genlist == current); + ck_assert(counter == 1); + ck_assert(ev_data.is_added == EINA_FALSE); + ck_assert(ev_data.child == it[0]); + + elm_object_item_del(it[2]); + ck_assert(genlist == current); + ck_assert(counter == 2); + ck_assert(ev_data.is_added == EINA_FALSE); + ck_assert(ev_data.child == it[2]); + + elm_shutdown(); +} +END_TEST + +START_TEST(elm_atspi_children_events_del2) +{ + test_init(); + + Elm_Object_Item *it; + current = NULL; + counter = 0; + + it = elm_genlist_item_append(genlist, &itc, NULL, NULL, ELM_GENLIST_ITEM_NONE, NULL, NULL); + + eo_do(genlist, eo_event_callback_add(ELM_INTERFACE_ATSPI_ACCESSIBLE_EVENT_CHILDREN_CHANGED, _children_changed_cb, NULL)); + elm_genlist_clear(genlist); + + ck_assert(genlist == current); + ck_assert(counter == 1); + ck_assert(ev_data.is_added == EINA_FALSE); + ck_assert(ev_data.child == it); + + elm_shutdown(); +} +END_TEST + void elm_test_genlist(TCase *tc) { - tcase_add_test(tc, elm_atspi_role_get); + tcase_add_test(tc, elm_atspi_role_get); + tcase_add_test(tc, elm_atspi_children_get1); + tcase_add_test(tc, elm_atspi_children_get2); + 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); } -- 2.7.4