From: Lukasz Stanislawski Date: Fri, 7 Feb 2014 14:03:07 +0000 (+0900) Subject: atspi: event broadcast added. Orca screen reader now ables to read UI. X-Git-Tag: v1.9.0-alpha1~43 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=71cd5a1a077807bc32a67d309fba9e1474fffa4d;p=platform%2Fupstream%2Felementary.git atspi: event broadcast added. Orca screen reader now ables to read UI. Summary: added broadcast of focus, window activate/deactivate events on a11y bus Orca screen reader is now able to read elementary application. Reviewers: raster, seoz, z.kosinski, kimcinoo Reviewed By: raster Differential Revision: https://phab.enlightenment.org/D508 --- diff --git a/src/lib/elm_atspi_bridge.c b/src/lib/elm_atspi_bridge.c index 5963e6a..cbede6c 100644 --- a/src/lib/elm_atspi_bridge.c +++ b/src/lib/elm_atspi_bridge.c @@ -5,6 +5,7 @@ #include #include #include "elm_priv.h" +#include #include "atspi/atspi-constants.h" @@ -14,6 +15,7 @@ #define A11Y_DBUS_NAME "org.a11y.Bus" #define A11Y_DBUS_PATH "/org/a11y/bus" #define A11Y_DBUS_INTERFACE "org.a11y.Bus" +#define ATSPI_DBUS_INTERFACE_EVENT_WINDOW "org.a11y.atspi.Event.Window" #define CACHE_ITEM_SIGNATURE "((so)(so)(so)a(so)assusau)" #define CACHE_INTERFACE_PATH "/org/a11y/atspi/cache" @@ -23,24 +25,137 @@ #define ELM_ACCESS_OBJECT_REFERENCE_TEMPLATE ELM_ACCESS_OBJECT_PATH_PREFIX "%llu" static int _init_count = 0; + static Eldbus_Connection *_a11y_bus = NULL; static Elm_Atspi_Object *_root; static Eina_Hash *_cache; static Eldbus_Service_Interface *_cache_interface = NULL; +static Eldbus_Signal_Handler *_register_hdl; +static Eldbus_Signal_Handler *_unregister_hdl; +static unsigned short _object_property_broadcast_mask; +static unsigned short _object_children_broadcast_mask; +static unsigned long long _object_state_broadcast_mask; +static unsigned long long _window_signal_broadcast_mask; + +static void _cache_update(void); static Elm_Atspi_Object * _access_object_from_path(const char *path); static char * _path_from_access_object(Elm_Atspi_Object *eo); static void object_append_reference(Eldbus_Message_Iter *iter, Elm_Atspi_Object *obj); static void object_append_desktop_reference(Eldbus_Message_Iter *iter); static const Eldbus_Service_Interface_Desc accessible_iface_desc; +static void _cache_object_register(Elm_Atspi_Object *node, Eina_Bool rec); + + +enum _Atspi_Object_Child_Event_Type +{ + ATSPI_OBJECT_CHILD_ADDED = 0, + ATSPI_OBJECT_CHILD_REMOVED +}; + +enum _Atspi_Object_Property +{ + ATSPI_OBJECT_PROPERTY_NAME = 0, + ATSPI_OBJECT_PROPERTY_DESCRIPTION, + ATSPI_OBJECT_PROPERTY_VALUE, + ATSPI_OBJECT_PROPERTY_ROLE, + ATSPI_OBJECT_PROPERTY_PARENT, +}; + +enum _Atspi_Object_Signals { + ATSPI_OBJECT_EVENT_PROPERTY_CHANGED, + ATSPI_OBJECT_EVENT_BOUNDS_CHANGED, + ATSPI_OBJECT_EVENT_LINK_SELECTED, + ATSPI_OBJECT_EVENT_STATE_CHANGED, + ATSPI_OBJECT_EVENT_CHILDREN_CHANGED, + ATSPI_OBJECT_EVENT_VISIBLE_DATA_CHANGED, + ATSPI_OBJECT_EVENT_SELECTION_CHANGED, + ATSPI_OBJECT_EVENT_MODEL_CHANGED, + ATSPI_OBJECT_EVENT_ACTIVE_DESCENDANT_CHANGED, + ATSPI_OBJECT_EVENT_ROW_INSERTED, + ATSPI_OBJECT_EVENT_ROW_REORDERED, + ATSPI_OBJECT_EVENT_ROW_DELETED, + ATSPI_OBJECT_EVENT_COLUMN_INSERTED, + ATSPI_OBJECT_EVENT_COLUMN_REORDERED, + ATSPI_OBJECT_EVENT_COLUMN_DELETED, + ATSPI_OBJECT_EVENT_TEXT_BOUNDS_CHANGED, + ATSPI_OBJECT_EVENT_TEXT_SELECTION_CHANGED, + ATSPI_OBJECT_EVENT_TEXT_CHANGED, + ATSPI_OBJECT_EVENT_TEXT_ATTRIBUTES_CHANGED, + ATSPI_OBJECT_EVENT_TEXT_CARET_MOVED, + ATSPI_OBJECT_EVENT_ATTRIBUTES_CHANGED, +}; -enum +enum _Atspi_Window_Signals { - ADD_ACCESSIBLE = 0, - REMOVE_ACCESSIBLE + ATSPI_WINDOW_EVENT_PROPERTY_CHANGE, + ATSPI_WINDOW_EVENT_MINIMIZE, + ATSPI_WINDOW_EVENT_MAXIMIZE, + ATSPI_WINDOW_EVENT_RESTORE, + ATSPI_WINDOW_EVENT_CLOSE, + ATSPI_WINDOW_EVENT_CREATE, + ATSPI_WINDOW_EVENT_REPARENT, + ATSPI_WINDOW_EVENT_DESKTOPCREATE, + ATSPI_WINDOW_EVENT_DESKTOPDESTROY, + ATSPI_WINDOW_EVENT_DESTROY, + ATSPI_WINDOW_EVENT_ACTIVATE, + ATSPI_WINDOW_EVENT_DEACTIVATE, + ATSPI_WINDOW_EVENT_RAISE, + ATSPI_WINDOW_EVENT_LOWER, + ATSPI_WINDOW_EVENT_MOVE, + ATSPI_WINDOW_EVENT_RESIZE, + ATSPI_WINDOW_EVENT_SHADE, + ATSPI_WINDOW_EVENT_UUSHADE, + ATSPI_WINDOW_EVENT_RESTYLE, +}; + +static const Eldbus_Signal _event_obj_signals[] = { + [ATSPI_OBJECT_EVENT_PROPERTY_CHANGED] = {"PropertyChange", ELDBUS_ARGS({"siiv(so)", NULL}), 0}, + [ATSPI_OBJECT_EVENT_BOUNDS_CHANGED] = {"BoundsChange", ELDBUS_ARGS({"siiv(so)", NULL}), 0}, + [ATSPI_OBJECT_EVENT_LINK_SELECTED] = {"LinkSelected", ELDBUS_ARGS({"siiv(so)", NULL}), 0}, + [ATSPI_OBJECT_EVENT_STATE_CHANGED] = {"StateChanged", ELDBUS_ARGS({"siiv(so)", NULL}), 0}, + [ATSPI_OBJECT_EVENT_CHILDREN_CHANGED] = {"ChildrenChanged", ELDBUS_ARGS({"siiv(so)", NULL}), 0}, + [ATSPI_OBJECT_EVENT_VISIBLE_DATA_CHANGED] = {"VisibleDataChanged", ELDBUS_ARGS({"siiv(so)", NULL}), 0}, + [ATSPI_OBJECT_EVENT_SELECTION_CHANGED] = {"SelectionChanged", ELDBUS_ARGS({"siiv(so)", NULL}), 0}, + [ATSPI_OBJECT_EVENT_MODEL_CHANGED] = {"ModelChanged", ELDBUS_ARGS({"siiv(so)", NULL}), 0}, + [ATSPI_OBJECT_EVENT_ACTIVE_DESCENDANT_CHANGED] = {"ActiveDescendantsChanged", ELDBUS_ARGS({"siiv(so)", NULL}), 0}, + [ATSPI_OBJECT_EVENT_ROW_INSERTED] = {"RowInserted", ELDBUS_ARGS({"siiv(so)", NULL}), 0}, + [ATSPI_OBJECT_EVENT_ROW_REORDERED] = {"RowReordered", ELDBUS_ARGS({"siiv(so)", NULL}), 0}, + [ATSPI_OBJECT_EVENT_ROW_DELETED] = {"RowDeleted", ELDBUS_ARGS({"siiv(so)", NULL}), 0}, + [ATSPI_OBJECT_EVENT_COLUMN_INSERTED] = {"ColumnInserted", ELDBUS_ARGS({"siiv(so)", NULL}), 0}, + [ATSPI_OBJECT_EVENT_COLUMN_REORDERED] = {"ColumnReordered", ELDBUS_ARGS({"siiv(so)", NULL}), 0}, + [ATSPI_OBJECT_EVENT_COLUMN_DELETED] = {"ColumnDeleted", ELDBUS_ARGS({"siiv(so)", NULL}), 0}, + [ATSPI_OBJECT_EVENT_TEXT_BOUNDS_CHANGED] = {"TextBoundsChanged", ELDBUS_ARGS({"siiv(so)", NULL}), 0}, + [ATSPI_OBJECT_EVENT_TEXT_SELECTION_CHANGED] = {"SelectionChanged", ELDBUS_ARGS({"siiv(so)", NULL}), 0}, + [ATSPI_OBJECT_EVENT_TEXT_CHANGED] = {"TextChaged", ELDBUS_ARGS({"siiv(so)", NULL}), 0}, + [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}, +}; + +static const Eldbus_Signal _window_obj_signals[] = { + [ATSPI_WINDOW_EVENT_PROPERTY_CHANGE] = {"PropertyChange", ELDBUS_ARGS({"siiv(so)", NULL}), 0}, + [ATSPI_WINDOW_EVENT_MINIMIZE] = {"Minimize", ELDBUS_ARGS({"siiv(so)", NULL}), 0}, + [ATSPI_WINDOW_EVENT_MAXIMIZE] = {"Maximize", ELDBUS_ARGS({"siiv(so)", NULL}), 0}, + [ATSPI_WINDOW_EVENT_RESTORE] = {"Restore", ELDBUS_ARGS({"siiv(so)", NULL}), 0}, + [ATSPI_WINDOW_EVENT_CLOSE] = {"Close", ELDBUS_ARGS({"siiv(so)", NULL}), 0}, + [ATSPI_WINDOW_EVENT_CREATE] = {"Create", ELDBUS_ARGS({"siiv(so)", NULL}), 0}, + [ATSPI_WINDOW_EVENT_REPARENT] = {"Reparent", ELDBUS_ARGS({"siiv(so)", NULL}), 0}, + [ATSPI_WINDOW_EVENT_DESKTOPCREATE] = {"DesktopCreate", ELDBUS_ARGS({"siiv(so)", NULL}), 0}, + [ATSPI_WINDOW_EVENT_DESKTOPDESTROY] = {"DesktopDestroy", ELDBUS_ARGS({"siiv(so)", NULL}), 0}, + [ATSPI_WINDOW_EVENT_DESTROY] = {"Destroy", ELDBUS_ARGS({"siiv(so)", NULL}), 0}, + [ATSPI_WINDOW_EVENT_ACTIVATE] = {"Activate", ELDBUS_ARGS({"siiv(so)", NULL}), 0}, + [ATSPI_WINDOW_EVENT_DEACTIVATE] = {"Deactivate", ELDBUS_ARGS({"siiv(so)", NULL}), 0}, + [ATSPI_WINDOW_EVENT_RAISE] = {"Raise", ELDBUS_ARGS({"siiv(so)", NULL}), 0}, + [ATSPI_WINDOW_EVENT_LOWER] = {"Lower", ELDBUS_ARGS({"siiv(so)", NULL}), 0}, + [ATSPI_WINDOW_EVENT_MOVE] = {"Move", ELDBUS_ARGS({"siiv(so)", NULL}), 0}, + [ATSPI_WINDOW_EVENT_RESIZE] = {"Resize", ELDBUS_ARGS({"siiv(so)", NULL}), 0}, + [ATSPI_WINDOW_EVENT_SHADE] = {"Shade", ELDBUS_ARGS({"siiv(so)", NULL}), 0}, + [ATSPI_WINDOW_EVENT_UUSHADE] = {"uUshade", ELDBUS_ARGS({"siiv(so)", NULL}), 0}, + [ATSPI_WINDOW_EVENT_RESTYLE] = {"Restyle", ELDBUS_ARGS({"siiv(so)", NULL}), 0}, }; static Eldbus_Message * -_accessible_get_role(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg) +_accessible_get_role(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg) { const char *obj_path = eldbus_service_object_path_get(iface); Elm_Atspi_Object *obj = _access_object_from_path(obj_path); @@ -48,64 +163,77 @@ _accessible_get_role(const Eldbus_Service_Interface *iface EINA_UNUSED, const El eo_do(obj, elm_atspi_obj_role_get(&role)); Eldbus_Message *ret = eldbus_message_method_return_new(msg); + EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL); eldbus_message_arguments_append(ret, "u", role); return ret; } static Eldbus_Message * -_accessible_get_role_name(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg) +_accessible_get_role_name(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg) { const char *role_name, *obj_path = eldbus_service_object_path_get(iface); Elm_Atspi_Object *obj = _access_object_from_path(obj_path); eo_do(obj, elm_atspi_obj_role_name_get(&role_name)); Eldbus_Message *ret = eldbus_message_method_return_new(msg); + EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL); eldbus_message_arguments_append(ret, "s", role_name); return ret; } static Eldbus_Message * -_accessible_get_localized_role_name(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg) +_accessible_get_localized_role_name(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg) { const char *l_role_name, *obj_path = eldbus_service_object_path_get(iface); Elm_Atspi_Object *obj = _access_object_from_path(obj_path); eo_do(obj, elm_atspi_obj_localized_role_name_get(&l_role_name)); Eldbus_Message *ret = eldbus_message_method_return_new(msg); + EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL); eldbus_message_arguments_append(ret, "s", l_role_name); return ret; } static Eldbus_Message * -_accessible_get_children(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg) +_accessible_get_children(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg) { const char *obj_path = eldbus_service_object_path_get(iface); Elm_Atspi_Object *obj = _access_object_from_path(obj_path); Eina_List *children_list = NULL, *l; Eldbus_Message *ret; + Eldbus_Message_Iter *iter, *iter_array; Elm_Atspi_Object *children; eo_do(obj, elm_atspi_obj_children_get(&children_list)); ret = eldbus_message_method_return_new(msg); + EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL); + iter = eldbus_message_iter_get(ret); iter_array = eldbus_message_iter_container_new(iter, 'a', "(so)"); + EINA_SAFETY_ON_NULL_GOTO(iter_array, fail); EINA_LIST_FOREACH(children_list, l, children) object_append_reference(iter_array, children); eldbus_message_iter_container_close(iter, iter_array); eina_list_free(children_list); + return ret; + +fail: + if (ret) eldbus_message_unref(ret); + return NULL; } static Eldbus_Message * _accessible_get_application(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg) { Eldbus_Message *ret = eldbus_message_method_return_new(msg); + EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL); Eldbus_Message_Iter *iter = eldbus_message_iter_get(ret); object_append_reference(iter, _root); @@ -113,17 +241,42 @@ _accessible_get_application(const Eldbus_Service_Interface *iface EINA_UNUSED, c } static Eldbus_Message * -_accessible_get_state(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg) +_accessible_get_state(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg) { - Eldbus_Message *ret = eldbus_message_method_return_new(msg); - Eldbus_Message_Iter *iter = eldbus_message_iter_get(ret); - Eldbus_Message_Iter *iter_array; + Eldbus_Message *ret; + Eldbus_Message_Iter *iter, *iter_array; + Elm_Atspi_State states; + + const char *obj_path = eldbus_service_object_path_get(iface); + Elm_Atspi_Object *obj = _access_object_from_path(obj_path); + + if (!obj) + { + ERR("Atspi Object %s not found in cache!", obj_path); + return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Invalid object path."); + } + ret = eldbus_message_method_return_new(msg); + EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL); + + iter = eldbus_message_iter_get(ret); iter_array = eldbus_message_iter_container_new(iter, 'a', "u"); - /* TODO: states are not implemented yet*/ + EINA_SAFETY_ON_NULL_GOTO(iter_array, fail); + + eo_do(obj, elm_atspi_obj_state_get(&states)); + + unsigned int s1 = states & 0xFFFFFFFF; + unsigned int s2 = (states >> 32) & 0xFFFFFFFF; + + eldbus_message_iter_basic_append(iter_array, 'u', s1); + eldbus_message_iter_basic_append(iter_array, 'u', s2); eldbus_message_iter_container_close(iter, iter_array); return ret; + +fail: + if (ret) eldbus_message_unref(ret); + return NULL; } static Eldbus_Message * @@ -131,9 +284,12 @@ _accessible_get_index_in_parent(const Eldbus_Service_Interface *iface EINA_UNUSE { const char *obj_path = eldbus_service_object_path_get(iface); Elm_Atspi_Object *obj = _access_object_from_path(obj_path); - Eldbus_Message *ret = eldbus_message_method_return_new(msg); + Eldbus_Message *ret; int idx; + ret = eldbus_message_method_return_new(msg); + EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL); + eo_do(obj, elm_atspi_obj_index_in_parent_get(&idx)); eldbus_message_arguments_append(ret, "i", idx); @@ -154,6 +310,8 @@ _accessible_child_at_index(const Eldbus_Service_Interface *iface EINA_UNUSED, co return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Invalid index type."); ret = eldbus_message_method_return_new(msg); + EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL); + iter = eldbus_message_iter_get(ret); eo_do(obj, elm_atspi_obj_child_at_index_get(idx, &child)); object_append_reference(iter, child); @@ -161,11 +319,17 @@ _accessible_child_at_index(const Eldbus_Service_Interface *iface EINA_UNUSED, co return ret; } +static Eldbus_Message * +_accessible_get_relation_set(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg) +{ + return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.NotSupported", "Relation states not implemented."); +} + static const Eldbus_Method accessible_methods[] = { { "GetChildAtIndex", ELDBUS_ARGS({"i", "index"}), ELDBUS_ARGS({"(so)", "Accessible"}), _accessible_child_at_index, 0 }, { "GetChildren", NULL, ELDBUS_ARGS({"a(so)", "children"}), _accessible_get_children, 0 }, { "GetIndexInParent", NULL, ELDBUS_ARGS({"i", "index"}), _accessible_get_index_in_parent, 0 }, - { "GetRelationSet", NULL, ELDBUS_ARGS({"a(ua(so))", NULL}), _accessible_get_state, 0 }, + { "GetRelationSet", NULL, ELDBUS_ARGS({"a(ua(so))", NULL}), _accessible_get_relation_set, 0 }, { "GetRole", NULL, ELDBUS_ARGS({"u", "Role"}), _accessible_get_role, 0 }, { "GetRoleName", NULL, ELDBUS_ARGS({"s", "Name"}), _accessible_get_role_name, 0 }, { "GetLocalizedRoleName", NULL, ELDBUS_ARGS({"s", "LocalizedName"}), _accessible_get_localized_role_name, 0}, @@ -216,9 +380,7 @@ _accessible_property_get(const Eldbus_Service_Interface *interface, const char * Eldbus_Message **error EINA_UNUSED) { const char *ret, *obj_path = eldbus_service_object_path_get(interface); - Elm_Atspi_Object *ret_obj = NULL, *obj = _access_object_from_path(obj_path); - EINA_SAFETY_ON_NULL_RETURN_VAL(obj, EINA_FALSE); if (!strcmp(property, "Name")) @@ -260,10 +422,10 @@ _accessible_property_get(const Eldbus_Service_Interface *interface, const char * } static const Eldbus_Property accessible_properties[] = { - { "Name", "s", NULL, NULL, 0 }, - { "Description", "s", NULL, NULL, 0 }, - { "Parent", "(so)", NULL, NULL, 0 }, - { "ChildCount", "i", NULL, NULL, 0 }, + { "Name", "s", _accessible_property_get, NULL, 0 }, + { "Description", "s", _accessible_property_get, NULL, 0 }, + { "Parent", "(so)", _accessible_property_get, NULL, 0 }, + { "ChildCount", "i", _accessible_property_get, NULL, 0 }, { NULL, NULL, NULL, NULL, 0 } }; @@ -271,10 +433,19 @@ static const Eldbus_Service_Interface_Desc accessible_iface_desc = { ATSPI_DBUS_INTERFACE_ACCESSIBLE, accessible_methods, NULL, accessible_properties, _accessible_property_get, NULL }; -static void -object_append_reference(Eldbus_Message_Iter *iter, Elm_Atspi_Object *obj){ +static const Eldbus_Service_Interface_Desc event_iface_desc = { + ATSPI_DBUS_INTERFACE_EVENT_OBJECT, NULL, _event_obj_signals, NULL, NULL, NULL +}; + +static const Eldbus_Service_Interface_Desc window_iface_desc = { + ATSPI_DBUS_INTERFACE_EVENT_WINDOW, NULL, _window_obj_signals, NULL, NULL, NULL +}; +static void +object_append_reference(Eldbus_Message_Iter *iter, Elm_Atspi_Object *obj) +{ Eldbus_Message_Iter *iter_struct = eldbus_message_iter_container_new(iter, 'r', NULL); + EINA_SAFETY_ON_NULL_RETURN(iter); char *path = _path_from_access_object(obj); eldbus_message_iter_basic_append(iter_struct, 's', eldbus_connection_unique_name_get(_a11y_bus)); eldbus_message_iter_basic_append(iter_struct, 'o', path); @@ -283,9 +454,10 @@ object_append_reference(Eldbus_Message_Iter *iter, Elm_Atspi_Object *obj){ } static void -object_append_desktop_reference(Eldbus_Message_Iter *iter){ - +object_append_desktop_reference(Eldbus_Message_Iter *iter) +{ Eldbus_Message_Iter *iter_struct = eldbus_message_iter_container_new(iter, 'r', NULL); + EINA_SAFETY_ON_NULL_RETURN(iter); eldbus_message_iter_basic_append(iter_struct, 's', ATSPI_DBUS_NAME_REGISTRY); eldbus_message_iter_basic_append(iter_struct, 'o', ATSPI_DBUS_PATH_ROOT); @@ -295,17 +467,19 @@ object_append_desktop_reference(Eldbus_Message_Iter *iter){ static Eina_Bool _append_item_fn(const Eina_Hash *hash EINA_UNUSED, const void *key EINA_UNUSED, void *data, void *fdata) { - if (!eo_ref_get(data) || eo_destructed_is(data)) return EINA_TRUE; Eldbus_Message_Iter *iter_struct, *iter_sub_array; Eldbus_Message_Iter *iter_array = fdata; - + Elm_Atspi_State states; AtspiRole role; + eo_do(data, elm_atspi_obj_role_get(&role)); iter_struct = eldbus_message_iter_container_new(iter_array, 'r', NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(iter_struct, EINA_TRUE); + /* Marshall object path */ object_append_reference(iter_struct, data); @@ -326,6 +500,8 @@ _append_item_fn(const Eina_Hash *hash EINA_UNUSED, const void *key EINA_UNUSED, eo_do(data, elm_atspi_obj_children_get(&children_list)); iter_sub_array = eldbus_message_iter_container_new(iter_struct, 'a', "(so)"); + EINA_SAFETY_ON_NULL_GOTO(iter_sub_array, fail); + EINA_LIST_FOREACH(children_list, l, child) object_append_reference(iter_sub_array, child); @@ -334,6 +510,7 @@ _append_item_fn(const Eina_Hash *hash EINA_UNUSED, const void *key EINA_UNUSED, /* Marshall interfaces */ iter_sub_array = eldbus_message_iter_container_new(iter_struct, 'a', "s"); + EINA_SAFETY_ON_NULL_GOTO(iter_sub_array, fail); eldbus_message_iter_basic_append(iter_sub_array, 's', ATSPI_DBUS_INTERFACE_ACCESSIBLE); if (eo_isa(data, ELM_ATSPI_COMPONENT_INTERFACE)) @@ -360,24 +537,44 @@ _append_item_fn(const Eina_Hash *hash EINA_UNUSED, const void *key EINA_UNUSED, /* Marshall state set */ iter_sub_array = eldbus_message_iter_container_new(iter_struct, 'a', "u"); - /* TODO: states are not implemented yet*/ - eldbus_message_iter_container_close(iter_struct, iter_sub_array); + EINA_SAFETY_ON_NULL_GOTO(iter_sub_array, fail); + eo_do(data, elm_atspi_obj_state_get(&states)); + unsigned int s1 = states & 0xFFFFFFFF; + unsigned int s2 = (states >> 32) & 0xFFFFFFFF; + eldbus_message_iter_basic_append(iter_sub_array, 'u', s1); + eldbus_message_iter_basic_append(iter_sub_array, 'u', s2); + + eldbus_message_iter_container_close(iter_struct, iter_sub_array); eldbus_message_iter_container_close(iter_array, iter_struct); return EINA_TRUE; + +fail: + if (iter_struct) eldbus_message_iter_del(iter_struct); + return EINA_TRUE; } static Eldbus_Message * _cache_get_items(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg) { - Eldbus_Message *ret = eldbus_message_method_return_new(msg); Eldbus_Message_Iter *iter, *iter_array; + Eldbus_Message *ret = eldbus_message_method_return_new(msg); + EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL); + + _cache_update(); + iter = eldbus_message_iter_get(ret); iter_array = eldbus_message_iter_container_new(iter, 'a', CACHE_ITEM_SIGNATURE); + EINA_SAFETY_ON_NULL_GOTO(iter_array, fail); + eina_hash_foreach(_cache, _append_item_fn, iter_array); eldbus_message_iter_container_close(iter, iter_array); + return ret; +fail: + if (ret) eldbus_message_unref(ret); + return NULL; } static const Eldbus_Method cache_methods[] = { @@ -386,8 +583,8 @@ static const Eldbus_Method cache_methods[] = { }; static const Eldbus_Signal cache_signals[] = { - [ADD_ACCESSIBLE] = { "AddAccessible", ELDBUS_ARGS({"((so)(so)a(so)assusau)", "added"}), 0}, - [REMOVE_ACCESSIBLE] = { "RemoveAccessible", ELDBUS_ARGS({ "(so)", "removed" }), 0}, + [ATSPI_OBJECT_CHILD_ADDED] = { "AddAccessible", ELDBUS_ARGS({"((so)(so)a(so)assusau)", "added"}), 0}, + [ATSPI_OBJECT_CHILD_REMOVED] = { "RemoveAccessible", ELDBUS_ARGS({ "(so)", "removed" }), 0}, {NULL, NULL, 0} }; @@ -412,6 +609,8 @@ _component_contains(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eld eo_do(obj, elm_atspi_component_interface_contains(x, y, coord_type, &contains)); ret = eldbus_message_method_return_new(msg); + EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL); + eldbus_message_arguments_append(ret, "b", contains); return ret; @@ -432,6 +631,8 @@ _component_get_accessible_at_point(const Eldbus_Service_Interface *iface EINA_UN return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Invalid index type."); ret = eldbus_message_method_return_new(msg); + EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL); + iter = eldbus_message_iter_get(ret); eo_do(obj, elm_atspi_component_interface_accessible_at_point_get(x, y, coord_type, &accessible)); object_append_reference(iter, accessible); @@ -447,23 +648,30 @@ _component_get_extents(const Eldbus_Service_Interface *iface EINA_UNUSED, const int x, y, w, h; AtspiCoordType coord_type; Eldbus_Message *ret; - Eldbus_Message_Iter *iter, *iter_struct; - + Eldbus_Message_Iter *iter, *iter_struct; if (!eldbus_message_arguments_get(msg, "u", &coord_type)) return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Invalid index type."); ret = eldbus_message_method_return_new(msg); + EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL); + iter = eldbus_message_iter_get(ret); eo_do(obj, elm_atspi_component_interface_extents_get(&x, &y, &w, &h, coord_type)); iter_struct = eldbus_message_iter_container_new(iter, 'r', NULL); + EINA_SAFETY_ON_NULL_GOTO(iter_struct, fail); + eldbus_message_iter_basic_append(iter_struct, 'i', x); eldbus_message_iter_basic_append(iter_struct, 'i', y); eldbus_message_iter_basic_append(iter_struct, 'i', w); eldbus_message_iter_basic_append(iter_struct, 'i', h); + eldbus_message_iter_container_close(iter, iter_struct); return ret; +fail: + if (iter_struct) eldbus_message_iter_del(iter_struct); + return NULL; } static Eldbus_Message * @@ -481,6 +689,8 @@ _component_get_position(const Eldbus_Service_Interface *iface EINA_UNUSED, const eo_do(obj, elm_atspi_component_interface_position_get(&x, &y, coord_type)); ret = eldbus_message_method_return_new(msg); + EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL); + eldbus_message_arguments_append(ret, "i", x); eldbus_message_arguments_append(ret, "i", y); @@ -498,6 +708,8 @@ _component_get_size(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eld eo_do(obj, elm_atspi_component_interface_size_get(&x, &y)); ret = eldbus_message_method_return_new(msg); + EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL); + eldbus_message_arguments_append(ret, "i", x); eldbus_message_arguments_append(ret, "i", y); @@ -515,6 +727,8 @@ _component_get_layer(const Eldbus_Service_Interface *iface EINA_UNUSED, const El eo_do(obj, elm_atspi_component_interface_layer_get(&layer)); ret = eldbus_message_method_return_new(msg); + EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL); + eldbus_message_arguments_append(ret, "u", layer); return ret; @@ -531,6 +745,8 @@ _component_grab_focus(const Eldbus_Service_Interface *iface EINA_UNUSED, const E eo_do(obj, elm_atspi_component_interface_focus_grab(&focus)); ret = eldbus_message_method_return_new(msg); + EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL); + eldbus_message_arguments_append(ret, "b", focus); return ret; @@ -547,6 +763,8 @@ _component_get_alpha(const Eldbus_Service_Interface *iface EINA_UNUSED, const El eo_do(obj, elm_atspi_component_interface_alpha_get(&alpha)); ret = eldbus_message_method_return_new(msg); + EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL); + eldbus_message_arguments_append(ret, "d", alpha); return ret; @@ -568,6 +786,8 @@ _component_set_extends(const Eldbus_Service_Interface *iface EINA_UNUSED, const eo_do(obj, elm_atspi_component_interface_extents_set(x, y, w, h, coord_type, &result)); ret = eldbus_message_method_return_new(msg); + EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL); + eldbus_message_arguments_append(ret, "b", result); return ret; @@ -589,6 +809,8 @@ _component_set_position(const Eldbus_Service_Interface *iface EINA_UNUSED, const eo_do(obj, elm_atspi_component_interface_position_set(x, y, coord_type, &result)); ret = eldbus_message_method_return_new(msg); + EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL); + eldbus_message_arguments_append(ret, "b", result); return ret; @@ -609,6 +831,8 @@ _component_set_size(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eld eo_do(obj, elm_atspi_component_interface_size_set(w, h, &result)); ret = eldbus_message_method_return_new(msg); + EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL); + eldbus_message_arguments_append(ret, "b", result); return ret; @@ -635,19 +859,17 @@ static const Eldbus_Service_Interface_Desc component_iface_desc = { }; static Eina_Bool -_atspi_object_del_cb(void *data, Eo *obj, const Eo_Event_Description *desc EINA_UNUSED, void *event_info EINA_UNUSED) +_cache_object_del_cb(void *data, Eo *obj, const Eo_Event_Description *desc EINA_UNUSED, void *event_info EINA_UNUSED) { Eldbus_Message *msg; Eldbus_Message_Iter *iter; char* path; - msg = eldbus_service_signal_new(_cache_interface, REMOVE_ACCESSIBLE); + msg = eldbus_service_signal_new(_cache_interface, ATSPI_OBJECT_CHILD_REMOVED); iter = eldbus_message_iter_get(msg); object_append_reference(iter, obj); path = _path_from_access_object(obj); - //ERR("_atspi_object_del_cbi: %d", eo_ref_get(obj)); - eldbus_service_signal_send(_cache_interface, msg); eina_hash_del(_cache, path, obj); @@ -658,37 +880,50 @@ _atspi_object_del_cb(void *data, Eo *obj, const Eo_Event_Description *desc EINA_ } static void -_atspi_object_register_interfaces(const char* path, Elm_Atspi_Object *node) +_cache_object_register_interfaces(const char *path, Elm_Atspi_Object *node) { Eldbus_Service_Interface *accessible = NULL; + Eldbus_Service_Interface *events = NULL; + Eldbus_Service_Interface *window = NULL; - if (eo_isa(node, ELM_ATSPI_CLASS)) - { - accessible = eldbus_service_interface_register(_a11y_bus, path, &accessible_iface_desc); - eo_do(node, eo_event_callback_add(EO_EV_DEL, _atspi_object_del_cb, accessible)); - } + if (eina_hash_find(_cache, path)) + return; + else + eina_hash_add(_cache, path, node); + + if (!eo_isa(node, ELM_ATSPI_CLASS)) return; + + accessible = eldbus_service_interface_register(_a11y_bus, path, &accessible_iface_desc); + events = eldbus_service_interface_register(_a11y_bus, path, &event_iface_desc); + eo_do(node, eo_base_data_set("atspi_event_interface", events, NULL)); + eo_do(node, eo_event_callback_add(EO_EV_DEL, _cache_object_del_cb, accessible)); if (eo_isa(node, ELM_ATSPI_COMPONENT_INTERFACE)) eldbus_service_interface_register(_a11y_bus, path, &component_iface_desc); + + if (eo_isa(node, ELM_ATSPI_WINDOW_INTERFACE)) + { + window = eldbus_service_interface_register(_a11y_bus, path, &window_iface_desc); + eo_do(node, eo_base_data_set("window_event_interface", window, NULL)); + } } static void -_atspi_objects_register_rec(Elm_Atspi_Object *node) +_cache_object_register(Elm_Atspi_Object *node, Eina_Bool rec) { EINA_SAFETY_ON_NULL_RETURN(node); Eina_List *children_list = NULL, *l; Elm_Atspi_Object *child; char* path = _path_from_access_object(node); - // register in cache - eina_hash_add(_cache, path, node); - - _atspi_object_register_interfaces(path, node); + _cache_object_register_interfaces(path, node); free(path); + if (!rec) return; + eo_do(node, elm_atspi_obj_children_get(&children_list)); EINA_LIST_FOREACH(children_list, l, child) - _atspi_objects_register_rec(child); + _cache_object_register(child, rec); eina_list_free(children_list); } @@ -707,7 +942,7 @@ _on_app_register(void *data EINA_UNUSED, const Eldbus_Message *msg, Eldbus_Pendi } static Eina_Bool -_app_register(Eldbus_Connection *a11y_bus) +_app_register(void) { Eldbus_Message *message = eldbus_message_method_call_new(ATSPI_DBUS_NAME_REGISTRY, ATSPI_DBUS_PATH_ROOT, @@ -716,27 +951,381 @@ _app_register(Eldbus_Connection *a11y_bus) Eldbus_Message_Iter *iter = eldbus_message_iter_get(message); object_append_reference(iter, _root); + eldbus_connection_send(_a11y_bus, message, _on_app_register, NULL, -1); + + return EINA_TRUE; +} - eldbus_connection_send(a11y_bus, message, _on_app_register, NULL, -1); +static void +_cache_update(void) +{ + _cache_object_register(_root, EINA_TRUE); +} + +static void +_bus_objects_register(void) +{ + _cache_interface = eldbus_service_interface_register(_a11y_bus, CACHE_INTERFACE_PATH, &cache_iface_desc); +} + +static void +_set_broadcast_flag(const char *event) +{ + char **tokens; + + tokens = eina_str_split(event, ":", 3); + + if (!tokens) return; + + if (!strcmp(tokens[0], "Object")) + { + if (!tokens[1] || *tokens[1] == '\0') return; // do not handle "Object:*" + else if (!strcmp(tokens[1], "StateChanged")) + { + if (!tokens[2] || *tokens[2] == '\0') + _object_state_broadcast_mask = -1; // broadcast all + else if (!strcmp(tokens[2], "Focused")) + BIT_FLAG_SET(_object_state_broadcast_mask, ATSPI_STATE_FOCUSED); + else if (!strcmp(tokens[2], "Showing")) + BIT_FLAG_SET(_object_state_broadcast_mask, ATSPI_STATE_SHOWING); + } + else if (!strcmp(tokens[1], "PropertyChange")) + { + if (!tokens[2] || *tokens[2] == '\0') + _object_property_broadcast_mask = -1; //broadcast all + else if (!strcmp(tokens[2], "AccessibleValue")) + BIT_FLAG_SET(_object_property_broadcast_mask, ATSPI_OBJECT_PROPERTY_VALUE); + else if (!strcmp(tokens[2], "AccessibleName")) + BIT_FLAG_SET(_object_property_broadcast_mask, ATSPI_OBJECT_PROPERTY_NAME); + else if (!strcmp(tokens[2], "AccessibleDescription")) + BIT_FLAG_SET(_object_property_broadcast_mask, ATSPI_OBJECT_PROPERTY_DESCRIPTION); + else if (!strcmp(tokens[2], "AccessibleParent")) + BIT_FLAG_SET(_object_property_broadcast_mask, ATSPI_OBJECT_PROPERTY_PARENT); + else if (!strcmp(tokens[2], "AccessibleRole")) + BIT_FLAG_SET(_object_property_broadcast_mask, ATSPI_OBJECT_PROPERTY_ROLE); + } + else if (!strcmp(tokens[1], "ChildrenChanged")) + { + if (!tokens[2] || *tokens[2] == '\0') + _object_children_broadcast_mask = -1; // broadcast all + else if (!strcmp(tokens[2], "add")) + BIT_FLAG_SET(_object_children_broadcast_mask, ATSPI_OBJECT_CHILD_ADDED); + else if (!strcmp(tokens[2], "remove")) + BIT_FLAG_SET(_object_children_broadcast_mask, ATSPI_OBJECT_CHILD_ADDED); + } + } + else if (!strcmp(tokens[0], "Window")) + { + if (!tokens[1] || *tokens[1] == '\0') + _window_signal_broadcast_mask = -1; // broadcast all + else if (!strcmp(tokens[1], "Create")) + BIT_FLAG_SET(_window_signal_broadcast_mask, ATSPI_WINDOW_EVENT_CREATE); + else if (!strcmp(tokens[1], "Activate")) + BIT_FLAG_SET(_window_signal_broadcast_mask, ATSPI_WINDOW_EVENT_ACTIVATE); + else if (!strcmp(tokens[1], "Deactivate")) + BIT_FLAG_SET(_window_signal_broadcast_mask, ATSPI_WINDOW_EVENT_DEACTIVATE); + } + + free(tokens[0]); + free(tokens); +} + +static void +_registered_listeners_get(void *data EINA_UNUSED, const Eldbus_Message *msg, Eldbus_Pending *pending EINA_UNUSED) +{ + DBG("Updating ATSPI2 clients registered events list."); + _object_children_broadcast_mask = 0; + _object_property_broadcast_mask = 0; + _object_state_broadcast_mask = 0; + _window_signal_broadcast_mask = 0; + + const char *event, *bus; + Eldbus_Message_Iter *iter, *siter; + if (!eldbus_message_arguments_get(msg, "a(ss)", &iter)) + { + ERR("Invalid answer type from GetRegisteredEvents method call!"); + return; + } + while (eldbus_message_iter_get_and_next(iter, 'r', &siter)) + { + eldbus_message_iter_arguments_get(siter, "ss", &bus, &event); + _set_broadcast_flag(event); + } +} + +static void +_registered_events_list_update(void) +{ + Eldbus_Message *msg; + msg = eldbus_message_method_call_new(ATSPI_DBUS_NAME_REGISTRY, ATSPI_DBUS_PATH_REGISTRY, ATSPI_DBUS_INTERFACE_REGISTRY, "GetRegisteredEvents"); + eldbus_connection_send(_a11y_bus, msg, _registered_listeners_get, NULL, -1); +} + +static void +_handle_listener_change(void *data EINA_UNUSED, const Eldbus_Message *msg) +{ + 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(); +} + +static void +_send_signal_state_changed(Elm_Atspi_Object *obj, AtspiStateType type, Eina_Bool new_value) +{ + Eldbus_Message *msg; + Eldbus_Message_Iter *iter, *viter; + Eldbus_Service_Interface *events = NULL; + char *desc; + + if (!BIT_FLAG_GET(_object_state_broadcast_mask, type)) + { + DBG("Masking event: %d", type); + return; + } + + switch (type) { + case ATSPI_STATE_FOCUSED: + desc = "focused"; + break; + case ATSPI_STATE_SHOWING: + desc = "showing"; + break; + case ATSPI_STATE_VISIBLE: + desc = "visible"; + break; + default: + desc = NULL; + } + + eo_do(obj, eo_base_data_get("atspi_event_interface", (void **)&events)); + if (!events) + { + ERR("Atspi object does not have event interface!"); + return; + } + msg = eldbus_service_signal_new(events, ATSPI_OBJECT_EVENT_STATE_CHANGED); + iter = eldbus_message_iter_get(msg); + + eldbus_message_iter_arguments_append(iter, "sii", desc, new_value, 0); + + viter = eldbus_message_iter_container_new(iter, 'v', "i"); + EINA_SAFETY_ON_NULL_RETURN(viter); + + eldbus_message_iter_arguments_append(viter, "i", 0); + eldbus_message_iter_container_close(iter, viter); + + object_append_reference(iter, obj); + + eldbus_service_signal_send(events, msg); + DBG("signal sent StateChanged:%s:%d", desc, new_value); +} + +static void +_send_signal_property_changed(Elm_Atspi_Object *ao, enum _Atspi_Object_Property prop) +{ + const char *desc; + Eldbus_Message *msg; + Eldbus_Message_Iter *iter, *siter, *viter; + Eldbus_Service_Interface *events = NULL; + + if (!BIT_FLAG_GET(_object_property_broadcast_mask, prop)) + return; + + switch(prop) + { + case ATSPI_OBJECT_PROPERTY_NAME: + desc = "accessible-name"; + break; + case ATSPI_OBJECT_PROPERTY_DESCRIPTION: + desc = "accessible-description"; + break; + case ATSPI_OBJECT_PROPERTY_ROLE: + desc = "accessible-role"; + break; + case ATSPI_OBJECT_PROPERTY_PARENT: + desc = "accessible-parent"; + break; + case ATSPI_OBJECT_PROPERTY_VALUE: + desc = "accessible-value"; + break; + default: + desc = NULL; + } + eo_do(ao, eo_base_data_get("atspi_event_interface", (void**)&events)); + if (!events) + { + ERR("Atspi object does not have event interface!"); + return; + } + msg = eldbus_service_signal_new(events, ATSPI_OBJECT_EVENT_PROPERTY_CHANGED); + EINA_SAFETY_ON_NULL_RETURN(msg); + + iter = eldbus_message_iter_get(msg); + siter = eldbus_message_iter_container_new(iter, 'r', NULL); + EINA_SAFETY_ON_NULL_RETURN(siter); + + eldbus_message_iter_arguments_append(siter, "suu", desc, 0, 0); + + viter = eldbus_message_iter_container_new(siter, 'v', "s"); + EINA_SAFETY_ON_NULL_RETURN(viter); + + eldbus_message_iter_arguments_append(viter, "s", _path_from_access_object(ao)); + + eldbus_message_iter_arguments_append(siter, "v", viter); + eldbus_message_iter_container_close(siter, viter); + + eldbus_message_iter_container_close(iter, siter); + eldbus_service_signal_send(events, msg); + DBG("signal sent PropertyChanged:%s", desc); +} + +static void +_send_signal_children_changed(Elm_Atspi_Object *parent, Elm_Atspi_Object *child, enum _Atspi_Object_Child_Event_Type type) +{ + Eldbus_Service_Interface *events = NULL; + Eldbus_Message_Iter *iter, *viter; + Eldbus_Message *msg; + const char *desc = NULL; + int idx; + + if (!BIT_FLAG_GET(_object_children_broadcast_mask, type)) + return; + + _cache_object_register(parent, EINA_FALSE); + _cache_object_register(child, EINA_FALSE); + + eo_do(parent, eo_base_data_get("atspi_event_interface", (void **)&events)); + if (!events) + { + ERR("Atspi object does not have event interface! %p %p %s", parent, _root, eo_class_name_get(eo_class_get(parent))); + return; + } + + switch(type) + { + case ATSPI_OBJECT_CHILD_ADDED: + desc = "add"; + eo_do(child, elm_atspi_obj_index_in_parent_get(&idx)); + break; + case ATSPI_OBJECT_CHILD_REMOVED: + desc = "remove"; + idx = -1; + break; + } + msg = eldbus_service_signal_new(events, ATSPI_OBJECT_EVENT_CHILDREN_CHANGED); + EINA_SAFETY_ON_NULL_RETURN(msg); + + iter = eldbus_message_iter_get(msg); + eldbus_message_iter_arguments_append(iter, "sii", desc, idx, 0); + + viter = eldbus_message_iter_container_new(iter, 'v', "(so)"); + EINA_SAFETY_ON_NULL_RETURN(viter); + + object_append_reference(viter, child); + eldbus_message_iter_container_close(iter, viter); + + object_append_reference(iter, _root); + + eldbus_service_signal_send(events, msg); + DBG("signal sent childrenChanged:%s:%d", desc, idx); +} + +static void +_send_signal_window(Elm_Atspi_Object *eo, enum _Atspi_Window_Signals type) +{ + const char *desc; + Eldbus_Message *msg; + Eldbus_Message_Iter *iter, *viter; + Eldbus_Service_Interface *window = NULL; + + if (!BIT_FLAG_GET(_window_signal_broadcast_mask, type)) + return; + + eo_do(eo, eo_base_data_get("window_event_interface", (void**)&window)); + if (!window) + { + ERR("Atspi object does not have window interface!"); + return; + } + + switch(type) + { + case ATSPI_WINDOW_EVENT_DEACTIVATE: + desc = "Deactivate"; + break; + case ATSPI_WINDOW_EVENT_ACTIVATE: + desc = "Activate"; + break; + default: + desc = ""; + } + + msg = eldbus_service_signal_new(window, type); + EINA_SAFETY_ON_NULL_RETURN(msg); + + iter = eldbus_message_iter_get(msg); + eldbus_message_iter_arguments_append(iter, "sii", desc, 0, 0); + + viter = eldbus_message_iter_container_new(iter, 'v', "i"); + EINA_SAFETY_ON_NULL_RETURN(viter); + + eldbus_message_iter_arguments_append(viter, "i", 0); + eldbus_message_iter_container_close(iter, viter); + + object_append_reference(iter, eo); + + eldbus_service_signal_send(window, msg); + DBG("signal sent Window:%s", desc); +} + +static Eina_Bool +_handle_atspi_event(void *data EINA_UNUSED, Elm_Atspi_Object *ao, const Eo_Event_Description *desc, void *event_info) +{ + if (desc == EV_ATSPI_OBJ_NAME_CHANGED) + _send_signal_property_changed(ao, ATSPI_OBJECT_PROPERTY_NAME); + else if (desc == EV_ATSPI_OBJ_STATE_CHANGED) + { + int *event_data = event_info; + _send_signal_state_changed(ao, (AtspiStateType)event_data[0], (Eina_Bool)event_data[1]); + } + else if (desc == EV_ATSPI_OBJ_CHILD_ADD) + _send_signal_children_changed(ao, event_info, ATSPI_OBJECT_CHILD_ADDED); + else if (desc == EV_ATSPI_OBJ_CHILD_DEL) + _send_signal_children_changed(ao, event_info, ATSPI_OBJECT_CHILD_REMOVED); + else if (desc == EV_ATSPI_OBJ_WINDOW_ACTIVATED) + _send_signal_window(ao, ATSPI_WINDOW_EVENT_ACTIVATE); + else if (desc == EV_ATSPI_OBJ_WINDOW_DEACTIVATED) + _send_signal_window(ao, ATSPI_WINDOW_EVENT_DEACTIVATE); return EINA_TRUE; } static void -_bus_objects_register(Eldbus_Connection *a11y_bus) +_event_handlers_register(void) { - _cache_interface = eldbus_service_interface_register(a11y_bus, CACHE_INTERFACE_PATH, &cache_iface_desc); - _atspi_objects_register_rec(_root); - DBG("%d elements registered in cache", eina_hash_population(_cache)); + _registered_events_list_update(); + + // register signal handlers in order to update list of registered listeners of ATSPI-Clients + _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); + + // handle incoming events from Elm_Atspi_Objects + _elm_atspi_object_global_callback_add(_handle_atspi_event, NULL); } static void _a11y_bus_initialize(const char *socket_addr) { - Eldbus_Connection *a11y_bus = eldbus_address_connection_get(socket_addr); - _a11y_bus = a11y_bus; - _bus_objects_register(a11y_bus); - _app_register(a11y_bus); + _a11y_bus = eldbus_address_connection_get(socket_addr); + + _cache_update(); + _bus_objects_register(); + _app_register(); + _event_handlers_register(); } static void @@ -771,11 +1360,18 @@ _elm_atspi_bridge_init(void) if (!_init_count && _elm_config->access_mode == ELM_ACCESS_MODE_ON) { + _elm_atspi_object_init(); session_bus = eldbus_connection_get(ELDBUS_CONNECTION_TYPE_SESSION); + EINA_SAFETY_ON_NULL_RETURN(session_bus); msg = eldbus_message_method_call_new(A11Y_DBUS_NAME, A11Y_DBUS_PATH, A11Y_DBUS_INTERFACE, "GetAddress"); + if (!msg) + { + eldbus_connection_unref(session_bus); + return; + } eldbus_connection_send(session_bus, msg, _a11y_bus_address_get, session_bus, -1); _cache = eina_hash_string_superfast_new(NULL); - _root = elm_atspi_root_object_get(); + _root = _elm_atspi_root_object_get(); _init_count = 1; } } @@ -785,7 +1381,15 @@ _elm_atspi_bridge_shutdown(void) { if (_init_count) { - eo_unref(_root); + _elm_atspi_object_shutdown(); + + if (_register_hdl) + eldbus_signal_handler_del(_register_hdl); + _register_hdl = NULL; + + if (_unregister_hdl) + eldbus_signal_handler_del(_unregister_hdl); + _unregister_hdl = NULL; if (_cache_interface) eldbus_service_object_unregister(_cache_interface); diff --git a/src/lib/elm_atspi_object.c b/src/lib/elm_atspi_object.c index 612130a..790d3d2 100644 --- a/src/lib/elm_atspi_object.c +++ b/src/lib/elm_atspi_object.c @@ -5,9 +5,21 @@ #include #include "elm_widget.h" #include "elm_priv.h" +#include "assert.h" #include "atspi/atspi-constants.h" +static Elm_Atspi_Object *_app; +static Eina_List *_global_callbacks; + +typedef struct _Elm_Atspi_Global_Callback_Info Elm_Atspi_Global_Callback_Info; + +struct _Elm_Atspi_Global_Callback_Info +{ + Eo_Event_Cb cb; + void *user_data; +}; + const char* Atspi_Name[] = { "invalid", "accelerator label", @@ -115,177 +127,313 @@ const char* Atspi_Name[] = { "last defined" }; -#define ARG_GET(valist, type) va_arg(*valist, type) +extern Eina_List *_elm_win_list; -static Elm_Atspi_Object * _elm_atspi_factory_construct(Evas_Object *obj, Elm_Atspi_Object *); +EAPI Eo_Op ELM_ATSPI_OBJ_BASE_ID = EO_NOOP; -extern Eina_List *_elm_win_list; +EAPI const Eo_Event_Description _EV_ATSPI_OBJ_NAME_CHANGED = + EO_EVENT_DESCRIPTION("name,changed", "Called when accessible object text has changed."); -typedef struct _Atspi_Object_Data Atspi_Object_Data; +EAPI const Eo_Event_Description _EV_ATSPI_OBJ_CHILD_ADD = + EO_EVENT_DESCRIPTION("child,added", "Called when accessible object children was created."); -struct _Atspi_Object_Data -{ - const char *name; - const char *description; - AtspiRole role; -}; +EAPI const Eo_Event_Description _EV_ATSPI_OBJ_CHILD_DEL = + EO_EVENT_DESCRIPTION("child,removed", "Called when accessible object children was destroyed."); -EAPI Eo_Op ELM_ATSPI_OBJ_BASE_ID = EO_NOOP; +EAPI const Eo_Event_Description _EV_ATSPI_OBJ_STATE_CHANGED = + EO_EVENT_DESCRIPTION("state,changed", "Called when accessible object state has changed."); + +EAPI const Eo_Event_Description _EV_ATSPI_OBJ_WINDOW_ACTIVATED = + EO_EVENT_DESCRIPTION("widnow,created", "Called when new window has been activated. (unfocuesed)"); + +EAPI const Eo_Event_Description _EV_ATSPI_OBJ_WINDOW_DEACTIVATED = + EO_EVENT_DESCRIPTION("widnow,created", "Called when new window has been deactivated (unfocused)."); + +static void +_eo_emit_state_changed_event(void *data, Evas *e EINA_UNUSED, Evas_Object *eo EINA_UNUSED, void *event_info EINA_UNUSED) +{ + Elm_Atspi_Object *ao = data; + int event_data[2] = {ATSPI_STATE_VISIBLE, 1}; + eo_do(ao, eo_event_callback_call(EV_ATSPI_OBJ_STATE_CHANGED, &event_data[0], NULL)); +} static void -_description_get(Eo *obj EINA_UNUSED, void *_pd, va_list *list) +_constructor(Eo *obj, void *_pd EINA_UNUSED, va_list *list EINA_UNUSED) { - const char **ret = ARG_GET(list, const char **); - Atspi_Object_Data *ad = _pd; + Evas_Object *internal_obj = NULL; + eo_do_super(obj, ELM_ATSPI_CLASS, eo_constructor()); + + eo_do(obj, eo_parent_get(&internal_obj)); - *ret = ad->description; + /* Evas_Object can only hold refs to atspi-object */ + assert(eo_isa(internal_obj, EVAS_OBJ_SMART_CLASS)); + + evas_object_data_set(internal_obj, "_atspi_object", obj); + evas_object_event_callback_add(internal_obj, EVAS_CALLBACK_SHOW, _eo_emit_state_changed_event, obj); +} + +static void +_destructor(Eo *obj, void *_pd EINA_UNUSED, va_list *list EINA_UNUSED) +{ + eo_do_super(obj, ELM_ATSPI_CLASS, eo_destructor()); } static void -_description_set(Eo *obj EINA_UNUSED, void *_pd, va_list *list) +_child_at_index_get(Eo *obj, void *_pd EINA_UNUSED, va_list *list) { - const char *desc = ARG_GET(list, const char *); - Atspi_Object_Data *ad = _pd; + EO_PARAMETER_GET(int, idx, list); + EO_PARAMETER_GET(Elm_Atspi_Object**, ao, list); + Eina_List *children = NULL; - if (ad->description) - eina_stringshare_del(ad->description); + eo_do(obj, elm_atspi_obj_children_get(&children)); + if (!children) return; - ad->description = eina_stringshare_add(desc); + if (ao) *ao = eina_list_nth(children, idx); + eina_list_free(children); } static void -_parent_get(Eo *obj EINA_UNUSED, void *_pd EINA_UNUSED, va_list *list) +_object_get(Eo *obj, void *_pd EINA_UNUSED, va_list *list) { - Elm_Atspi_Object **ret = ARG_GET(list, Elm_Atspi_Object**); + EO_PARAMETER_GET(Evas_Object**, ret, list); eo_do(obj, eo_parent_get(ret)); } static void -_name_get(Eo *obj EINA_UNUSED, void *_pd EINA_UNUSED, va_list *list EINA_UNUSED) +_index_in_parent_get(Eo *obj, void *_pd EINA_UNUSED, va_list *list) { - const char **ret = ARG_GET(list, const char **); - Atspi_Object_Data *ad = _pd; + EO_PARAMETER_GET(unsigned int*, idx, list); + Elm_Atspi_Object *chld, *parent = NULL; + Eina_List *l, *children = NULL; + unsigned int tmp = 0; + + eo_do(obj, elm_atspi_obj_parent_get(&parent)); + if (!parent) return; + eo_do(parent, elm_atspi_obj_children_get(&children)); - *ret = ad->name; + EINA_LIST_FOREACH(children, l, chld) + { + if (chld == obj) + { + if (idx) *idx = tmp; + break; + } + tmp++; + } + if (tmp == eina_list_count(children)) + ERR("Access object not present in parent's children list!"); + + eina_list_free(children); } static void -_name_set(Eo *obj EINA_UNUSED, void *_pd EINA_UNUSED, va_list *list EINA_UNUSED) +_role_name_get(Eo *obj, void *_pd EINA_UNUSED, va_list *list) { - const char *name = ARG_GET(list, const char *); - Atspi_Object_Data *ad = _pd; + EO_PARAMETER_GET(const char **, ret, list); + AtspiRole role = ATSPI_ROLE_INVALID; + + eo_do(obj, elm_atspi_obj_role_get(&role)); + + if (role >= ATSPI_ROLE_LAST_DEFINED) + { + ERR("Invalid role enum for atspi-object: %d.", role); + return; + } - if (ad->name) - eina_stringshare_del(ad->name); + if (ret) *ret = Atspi_Name[role]; +} - ad->name = eina_stringshare_add(name); +static void +_description_get(Eo *obj EINA_UNUSED, void *_pd EINA_UNUSED, va_list *list EINA_UNUSED) +{ + EO_PARAMETER_GET(const char **, ret, list); + *ret = NULL; } static void -_role_get(Eo *obj EINA_UNUSED, void *_pd EINA_UNUSED, va_list *list EINA_UNUSED) +_localized_role_name_get(Eo *obj, void *_pd EINA_UNUSED, va_list *list) { - AtspiRole *ret = ARG_GET(list, AtspiRole *); - Atspi_Object_Data *ad = _pd; + EO_PARAMETER_GET(const char **, ret, list); + const char *name = NULL; - *ret = ad->role; + eo_do(obj, elm_atspi_obj_role_name_get(&name)); + if (!name) return; +#ifdef ENABLE_NLS + if (ret) *ret = gettext(name); +#else + if (ret) *ret = name; +#endif } static void -_role_set(Eo *obj EINA_UNUSED, void *_pd EINA_UNUSED, va_list *list EINA_UNUSED) +_state_get(Eo *obj, void *_pd EINA_UNUSED, va_list *list) { - AtspiRole role = ARG_GET(list, int); - Atspi_Object_Data *ad = _pd; + EO_PARAMETER_GET(Elm_Atspi_State *, ret, list); + Evas_Object *evobj = NULL; + Elm_Atspi_State states = 0; + eo_do(obj, elm_atspi_obj_object_get(&evobj)); - ad->role = role; + if (evas_object_visible_get(evobj)) + BIT_FLAG_SET(states, ATSPI_STATE_VISIBLE); + + if (ret) *ret = states; } static void -_constructor(Eo *obj, void *_pd EINA_UNUSED, va_list *list EINA_UNUSED) +_comp_access_at_point_get(Eo *obj, void *_pd EINA_UNUSED, va_list *list) { - eo_do_super(obj, ELM_ATSPI_CLASS, eo_constructor()); - Atspi_Object_Data *ad = _pd; - ad->name = ad->description = NULL; + EO_PARAMETER_GET(int, x, list); + EO_PARAMETER_GET(int, y, list); + EO_PARAMETER_GET(AtspiCoordType, type, list); + EO_PARAMETER_GET(Evas_Object **, ret, list); + int ee_x, ee_y; + Eina_List *l, *objs; + Evas_Object *evobj = NULL; + + eo_do(obj, elm_atspi_obj_object_get(&evobj)); + + if (!evobj) return; + if (type == ATSPI_COORD_TYPE_SCREEN) + { + Ecore_Evas *ee = ecore_evas_ecore_evas_get(evas_object_evas_get(evobj)); + if (!ee) return; + ecore_evas_geometry_get(ee, &ee_x, &ee_y, NULL, NULL); + x -= ee_x; + y -= ee_y; + } + objs = evas_objects_at_xy_get(evas_object_evas_get(evobj), x, y, EINA_TRUE, EINA_TRUE); + EINA_LIST_FOREACH(objs, l, evobj) + { + // return first only, test if there is atspi interface for eo + Elm_Atspi_Object *acc = _elm_atspi_factory_construct(evobj); + if (acc) + { + *ret = evobj; + break; + } + } + eina_list_free(objs); } static void -_destructor(Eo *obj, void *_pd EINA_UNUSED, va_list *list EINA_UNUSED) +_comp_extents_get(Eo *obj, void *_pd EINA_UNUSED, va_list *list) { - Atspi_Object_Data *ad = _pd; + EO_PARAMETER_GET(int *, x, list); + EO_PARAMETER_GET(int*, y, list); + EO_PARAMETER_GET(int*, w, list); + EO_PARAMETER_GET(int*, h, list); + EO_PARAMETER_GET(AtspiCoordType, type, list); + int ee_x, ee_y; + Evas_Object *evobj = NULL; - eina_stringshare_del(ad->name); - eina_stringshare_del(ad->description); + eo_do(obj, elm_atspi_obj_object_get(&evobj)); + if (!evobj) return; - eo_do_super(obj, ELM_ATSPI_CLASS, eo_destructor()); + evas_object_geometry_get(evobj, x, y, w, h); + if (type == ATSPI_COORD_TYPE_SCREEN) + { + Ecore_Evas *ee = ecore_evas_ecore_evas_get(evas_object_evas_get(evobj)); + if (!ee) return; + ecore_evas_geometry_get(ee, &ee_x, &ee_y, NULL, NULL); + if (x) *x += ee_x; + if (y) *y += ee_y; + } } static void -_role_name_get(Eo *obj EINA_UNUSED, void *_pd EINA_UNUSED, va_list *list EINA_UNUSED) +_comp_extents_set(Eo *obj, void *_pd EINA_UNUSED, va_list *list) { - const char **ret = ARG_GET(list, const char **); - Atspi_Object_Data *ad = _pd; + EO_PARAMETER_GET(int, x, list); + EO_PARAMETER_GET(int, y, list); + EO_PARAMETER_GET(int, w, list); + EO_PARAMETER_GET(int, h, list); + EO_PARAMETER_GET(AtspiCoordType, type, list); + EO_PARAMETER_GET(Eina_Bool *, ret, list); + int wx, wy; + Evas_Object *evobj = NULL; + + if (ret) *ret = EINA_FALSE; + if ((x < 0) || (y < 0) || (w < 0) || (h < 0)) return; + + eo_do(obj, elm_atspi_obj_object_get(&evobj)); + if (!evobj) return; + + if (type == ATSPI_COORD_TYPE_SCREEN) + { + Ecore_Evas *ee = ecore_evas_ecore_evas_get(evas_object_evas_get(evobj)); + if (!ee) return; + evas_object_geometry_get(evobj, &wx, &wy, NULL, NULL); + ecore_evas_move(ee, x - wx, y - wy); + } + else + evas_object_move(evobj, x, y); - *ret = Atspi_Name[ad->role]; + evas_object_resize(evobj, w, h); + if (ret) *ret = EINA_TRUE; } static void -_localized_role_name_get(Eo *obj EINA_UNUSED, void *_pd EINA_UNUSED, va_list *list EINA_UNUSED) +_comp_layer_get(Eo *obj, void *_pd EINA_UNUSED, va_list *list) { - const char **ret = ARG_GET(list, const char **); - Atspi_Object_Data *ad = _pd; + EO_PARAMETER_GET(int *, ret, list); + Elm_Object_Layer layer; + Evas_Object *evobj = NULL; + AtspiComponentLayer spi_layer; + + eo_do(obj, elm_atspi_obj_object_get(&evobj)); + if (!evobj) return; + + layer = evas_object_layer_get(evobj); + switch (layer) { + case ELM_OBJECT_LAYER_BACKGROUND: + spi_layer = ATSPI_LAYER_BACKGROUND; + break; + case ELM_OBJECT_LAYER_FOCUS: + case ELM_OBJECT_LAYER_TOOLTIP: + case ELM_OBJECT_LAYER_CURSOR: + spi_layer = ATSPI_LAYER_OVERLAY; + break; + default: + spi_layer = ATSPI_LAYER_WIDGET; + } + if (ret) *ret = spi_layer; +} -#ifdef ENABLE_NLS - *ret = gettext(Atspi_Name[ad->role]); -#else - *ret = Atspi_Name[ad->role]; -#endif +static void +_comp_z_order_get(Eo *obj EINA_UNUSED, void *_pd EINA_UNUSED, va_list *list EINA_UNUSED) +{ + // FIXME } static void -_child_at_index_get(Eo *obj EINA_UNUSED, void *_pd EINA_UNUSED, va_list *list) +_cb_call(Eo *obj, void *_pd EINA_UNUSED, va_list *list) { - int idx = ARG_GET(list, int); - Elm_Atspi_Object **ao = ARG_GET(list, Elm_Atspi_Object**); - Eina_List *children = NULL; - eo_do(obj, elm_atspi_obj_children_get(&children)); + Elm_Atspi_Global_Callback_Info *info; + Eina_List *l; + EO_PARAMETER_GET(const Eo_Event_Description *, desc, list); + EO_PARAMETER_GET(void *, event_info, list); + EO_PARAMETER_GET(Eina_Bool *, ret, list); - if (children) - *ao = eina_list_nth(children, idx); - else - *ao = NULL; + EINA_LIST_FOREACH(_global_callbacks, l, info) + { + if (info->cb) info->cb(info->user_data, obj, desc, event_info); + } - eina_list_free(children); + eo_do_super(obj, ELM_ATSPI_CLASS, eo_event_callback_call(desc, event_info, ret)); } static void -_index_in_parent_get(Eo *obj EINA_UNUSED, void *_pd EINA_UNUSED, va_list *list) +_comp_alpha_get(Eo *obj, void *_pd EINA_UNUSED, va_list *list) { - unsigned int *idx = ARG_GET(list, unsigned int*); - Elm_Atspi_Object *chld, *parent = NULL; - Eina_List *l, *children = NULL; - unsigned int tmp = 0; - eo_do(obj, elm_atspi_obj_parent_get(&parent)); + EO_PARAMETER_GET(double *, ret, list); + Evas_Object *evobj = NULL; + int alpha; - if (parent) - { - eo_do(parent, elm_atspi_obj_children_get(&children)); - EINA_LIST_FOREACH(children, l, chld) - { - if (chld == obj) - { - *idx = tmp; - break; - } - tmp++; - } - if (tmp == eina_list_count(children)) - ERR("Access object not present in parent's children list!"); - EINA_LIST_FREE(children, chld) - eo_unref(chld); + eo_do(obj, elm_atspi_obj_object_get(&evobj)); + if (!evobj) return; - eo_unref(parent); - } - else - DBG("Access Object has no parent."); + evas_object_color_get(evobj, NULL, NULL, NULL, &alpha); + if (ret) *ret = (double)alpha / 255.0; } static void @@ -294,17 +442,20 @@ _class_constructor(Eo_Class *klass) const Eo_Op_Func_Description func_desc[] = { EO_OP_FUNC(EO_BASE_ID(EO_BASE_SUB_ID_CONSTRUCTOR), _constructor), EO_OP_FUNC(EO_BASE_ID(EO_BASE_SUB_ID_DESTRUCTOR), _destructor), - EO_OP_FUNC(ELM_ATSPI_OBJ_ID(ELM_ATSPI_OBJ_SUB_ID_NAME_GET), _name_get), - EO_OP_FUNC(ELM_ATSPI_OBJ_ID(ELM_ATSPI_OBJ_SUB_ID_NAME_SET), _name_set), - EO_OP_FUNC(ELM_ATSPI_OBJ_ID(ELM_ATSPI_OBJ_SUB_ID_DESCRIPTION_GET), _description_get), - EO_OP_FUNC(ELM_ATSPI_OBJ_ID(ELM_ATSPI_OBJ_SUB_ID_DESCRIPTION_SET), _description_set), - EO_OP_FUNC(ELM_ATSPI_OBJ_ID(ELM_ATSPI_OBJ_SUB_ID_PARENT_GET), _parent_get), + EO_OP_FUNC(EO_BASE_ID(EO_BASE_SUB_ID_EVENT_CALLBACK_CALL), _cb_call), + EO_OP_FUNC(ELM_ATSPI_OBJ_ID(ELM_ATSPI_OBJ_SUB_ID_OBJECT_GET), _object_get), EO_OP_FUNC(ELM_ATSPI_OBJ_ID(ELM_ATSPI_OBJ_SUB_ID_CHILD_AT_INDEX_GET), _child_at_index_get), EO_OP_FUNC(ELM_ATSPI_OBJ_ID(ELM_ATSPI_OBJ_SUB_ID_INDEX_IN_PARENT_GET), _index_in_parent_get), - EO_OP_FUNC(ELM_ATSPI_OBJ_ID(ELM_ATSPI_OBJ_SUB_ID_ROLE_GET), _role_get), - EO_OP_FUNC(ELM_ATSPI_OBJ_ID(ELM_ATSPI_OBJ_SUB_ID_ROLE_SET), _role_set), EO_OP_FUNC(ELM_ATSPI_OBJ_ID(ELM_ATSPI_OBJ_SUB_ID_ROLE_NAME_GET), _role_name_get), + EO_OP_FUNC(ELM_ATSPI_OBJ_ID(ELM_ATSPI_OBJ_SUB_ID_DESCRIPTION_GET), _description_get), EO_OP_FUNC(ELM_ATSPI_OBJ_ID(ELM_ATSPI_OBJ_SUB_ID_LOCALIZED_ROLE_NAME_GET), _localized_role_name_get), + EO_OP_FUNC(ELM_ATSPI_OBJ_ID(ELM_ATSPI_OBJ_SUB_ID_STATE_GET), _state_get), + EO_OP_FUNC(ELM_ATSPI_COMPONENT_INTERFACE_ID(ELM_ATSPI_COMPONENT_INTERFACE_SUB_ID_ACCESSIBLE_AT_POINT_GET), _comp_access_at_point_get), + EO_OP_FUNC(ELM_ATSPI_COMPONENT_INTERFACE_ID(ELM_ATSPI_COMPONENT_INTERFACE_SUB_ID_EXTENTS_GET), _comp_extents_get), + EO_OP_FUNC(ELM_ATSPI_COMPONENT_INTERFACE_ID(ELM_ATSPI_COMPONENT_INTERFACE_SUB_ID_EXTENTS_SET), _comp_extents_set), + EO_OP_FUNC(ELM_ATSPI_COMPONENT_INTERFACE_ID(ELM_ATSPI_COMPONENT_INTERFACE_SUB_ID_LAYER_GET), _comp_layer_get), + EO_OP_FUNC(ELM_ATSPI_COMPONENT_INTERFACE_ID(ELM_ATSPI_COMPONENT_INTERFACE_SUB_ID_Z_ORDER_GET), _comp_z_order_get), + EO_OP_FUNC(ELM_ATSPI_COMPONENT_INTERFACE_ID(ELM_ATSPI_COMPONENT_INTERFACE_SUB_ID_ALPHA_GET), _comp_alpha_get), EO_OP_FUNC_SENTINEL }; eo_class_funcs_set(klass, func_desc); @@ -312,17 +463,14 @@ _class_constructor(Eo_Class *klass) static const Eo_Op_Description op_desc[] = { EO_OP_DESCRIPTION(ELM_ATSPI_OBJ_SUB_ID_NAME_GET, ""), - EO_OP_DESCRIPTION(ELM_ATSPI_OBJ_SUB_ID_NAME_SET, ""), EO_OP_DESCRIPTION(ELM_ATSPI_OBJ_SUB_ID_DESCRIPTION_GET, ""), - EO_OP_DESCRIPTION(ELM_ATSPI_OBJ_SUB_ID_DESCRIPTION_SET, ""), - EO_OP_DESCRIPTION(ELM_ATSPI_OBJ_SUB_ID_PARENT_GET, ""), EO_OP_DESCRIPTION(ELM_ATSPI_OBJ_SUB_ID_CHILD_AT_INDEX_GET, ""), EO_OP_DESCRIPTION(ELM_ATSPI_OBJ_SUB_ID_CHILDREN_GET, ""), + EO_OP_DESCRIPTION(ELM_ATSPI_OBJ_SUB_ID_PARENT_GET, ""), + EO_OP_DESCRIPTION(ELM_ATSPI_OBJ_SUB_ID_OBJECT_GET, ""), EO_OP_DESCRIPTION(ELM_ATSPI_OBJ_SUB_ID_INDEX_IN_PARENT_GET, ""), EO_OP_DESCRIPTION(ELM_ATSPI_OBJ_SUB_ID_RELATION_SET_GET, ""), - EO_OP_DESCRIPTION(ELM_ATSPI_OBJ_SUB_ID_RELATION_SET_SET, ""), EO_OP_DESCRIPTION(ELM_ATSPI_OBJ_SUB_ID_ROLE_GET, ""), - EO_OP_DESCRIPTION(ELM_ATSPI_OBJ_SUB_ID_ROLE_SET, ""), EO_OP_DESCRIPTION(ELM_ATSPI_OBJ_SUB_ID_ROLE_NAME_GET, ""), EO_OP_DESCRIPTION(ELM_ATSPI_OBJ_SUB_ID_LOCALIZED_ROLE_NAME_GET, ""), EO_OP_DESCRIPTION(ELM_ATSPI_OBJ_SUB_ID_STATE_GET, ""), @@ -330,18 +478,26 @@ static const Eo_Op_Description op_desc[] = { EO_OP_DESCRIPTION_SENTINEL }; +static const Eo_Event_Description *event_desc[] = { + EV_ATSPI_OBJ_NAME_CHANGED, + EV_ATSPI_OBJ_STATE_CHANGED, + EV_ATSPI_OBJ_CHILD_ADD, + EV_ATSPI_OBJ_CHILD_DEL, + NULL +}; + static const Eo_Class_Description class_desc = { EO_VERSION, - "Access_Object", + "Elm_Atspi_Object", EO_CLASS_TYPE_REGULAR, EO_CLASS_DESCRIPTION_OPS(&ELM_ATSPI_OBJ_BASE_ID, op_desc, ELM_ATSPI_OBJ_SUB_ID_LAST), - NULL, - sizeof(Atspi_Object_Data), + event_desc, + 0, _class_constructor, NULL }; -EO_DEFINE_CLASS(elm_atspi_obj_class_get, &class_desc, EO_BASE_CLASS, NULL); +EO_DEFINE_CLASS(elm_atspi_obj_class_get, &class_desc, EO_BASE_CLASS, ELM_ATSPI_COMPONENT_INTERFACE, NULL); // Component interface EAPI Eo_Op ELM_ATSPI_COMPONENT_INTERFACE_BASE_ID = EO_NOOP; @@ -349,9 +505,9 @@ EAPI Eo_Op ELM_ATSPI_COMPONENT_INTERFACE_BASE_ID = EO_NOOP; static void _comp_interface_position_get(Eo *obj EINA_UNUSED, void *_pd EINA_UNUSED, va_list *list EINA_UNUSED) { - int *x = ARG_GET(list, int*); - int *y = ARG_GET(list, int*); - AtspiCoordType type = ARG_GET(list, AtspiCoordType); + EO_PARAMETER_GET(int *, x, list); + EO_PARAMETER_GET(int *, y, list); + EO_PARAMETER_GET(AtspiCoordType, type, list); eo_do(obj, elm_atspi_component_interface_extents_get(x, y, NULL, NULL, type)); } @@ -359,10 +515,10 @@ _comp_interface_position_get(Eo *obj EINA_UNUSED, void *_pd EINA_UNUSED, va_list static void _comp_interface_position_set(Eo *obj EINA_UNUSED, void *_pd EINA_UNUSED, va_list *list EINA_UNUSED) { - int x = ARG_GET(list, int); - int y = ARG_GET(list, int); - AtspiCoordType type = ARG_GET(list, AtspiCoordType); - Eina_Bool *ret = ARG_GET(list, Eina_Bool*); + EO_PARAMETER_GET(int, x, list); + EO_PARAMETER_GET(int, y, list); + EO_PARAMETER_GET(AtspiCoordType, type, list); + EO_PARAMETER_GET(Eina_Bool*, ret, list); int c_w, c_h; eo_do(obj, elm_atspi_component_interface_extents_get(NULL, NULL, &c_w, &c_h, type)); @@ -372,9 +528,9 @@ _comp_interface_position_set(Eo *obj EINA_UNUSED, void *_pd EINA_UNUSED, va_list static void _comp_interface_size_set(Eo *obj EINA_UNUSED, void *_pd EINA_UNUSED, va_list *list EINA_UNUSED) { - int w = ARG_GET(list, int); - int h = ARG_GET(list, int); - Eina_Bool *ret = ARG_GET(list, Eina_Bool*); + EO_PARAMETER_GET(int, w, list); + EO_PARAMETER_GET(int, h, list); + EO_PARAMETER_GET(Eina_Bool*, ret, list); int c_x, c_y; eo_do(obj, elm_atspi_component_interface_extents_get(&c_x, &c_y, NULL, NULL, ATSPI_COORD_TYPE_WINDOW)); @@ -384,8 +540,8 @@ _comp_interface_size_set(Eo *obj EINA_UNUSED, void *_pd EINA_UNUSED, va_list *li static void _comp_interface_size_get(Eo *obj EINA_UNUSED, void *_pd EINA_UNUSED, va_list *list EINA_UNUSED) { - int *w = ARG_GET(list, int*); - int *h = ARG_GET(list, int*); + EO_PARAMETER_GET(int*, w, list); + EO_PARAMETER_GET(int*, h, list); eo_do(obj, elm_atspi_component_interface_extents_get(NULL, NULL, w, h, ATSPI_COORD_TYPE_WINDOW)); } @@ -393,32 +549,25 @@ _comp_interface_size_get(Eo *obj EINA_UNUSED, void *_pd EINA_UNUSED, va_list *li static void _comp_interface_contains(Eo *obj EINA_UNUSED, void *_pd EINA_UNUSED, va_list *list) { - int x = ARG_GET(list, int); - int y = ARG_GET(list, int); - AtspiCoordType type = ARG_GET(list, AtspiCoordType); - Eina_Bool *ret = ARG_GET(list, Eina_Bool*); + EO_PARAMETER_GET(int, x, list); + EO_PARAMETER_GET(int, y, list); + EO_PARAMETER_GET(AtspiCoordType, type, list); + EO_PARAMETER_GET(Eina_Bool*, ret, list); int w_x, w_y, w_w, w_h; - *ret = EINA_FALSE; + if (ret) *ret = EINA_FALSE; if (!eo_do(obj, elm_atspi_component_interface_extents_get(&w_x, &w_y, &w_w, &w_h, type))) return; if ((x >= w_x) && (x <= w_x + w_w) && (y >= w_y) && (y <= w_y + w_h)) - *ret = EINA_TRUE; -} - -static void -_component_constructor(Eo *obj, void *_pd EINA_UNUSED, va_list *list EINA_UNUSED) -{ - eo_do_super(obj, ELM_ATSPI_COMPONENT_INTERFACE, eo_constructor()); + if (ret) *ret = EINA_TRUE; } static void _component_interface_constructor(Eo_Class *klass) { const Eo_Op_Func_Description func_desc[] = { - EO_OP_FUNC(EO_BASE_ID(EO_BASE_SUB_ID_CONSTRUCTOR), _component_constructor), EO_OP_FUNC(ELM_ATSPI_COMPONENT_INTERFACE_ID(ELM_ATSPI_COMPONENT_INTERFACE_SUB_ID_POSITION_GET), _comp_interface_position_get), EO_OP_FUNC(ELM_ATSPI_COMPONENT_INTERFACE_ID(ELM_ATSPI_COMPONENT_INTERFACE_SUB_ID_POSITION_SET), _comp_interface_position_set), EO_OP_FUNC(ELM_ATSPI_COMPONENT_INTERFACE_ID(ELM_ATSPI_COMPONENT_INTERFACE_SUB_ID_CONTAINS), _comp_interface_contains), @@ -459,232 +608,174 @@ static const Eo_Class_Description component_interface_desc = { EO_DEFINE_CLASS(elm_atspi_component_interface_get, &component_interface_desc, NULL, NULL); -/// Elm_Atspi_Widget base class -#define ELM_ATSPI_WIDGET_CLASS elm_atspi_widget_obj_class_get() +// Window Interface -const Eo_Class *elm_atspi_widget_obj_class_get(void) EINA_CONST; - -typedef struct _Access_Widget_Object_Data Access_Widget_Object_Data; +static const Eo_Event_Description *window_event_desc[] = { + EV_ATSPI_OBJ_WINDOW_ACTIVATED, + EV_ATSPI_OBJ_WINDOW_DEACTIVATED, + NULL +}; -struct _Access_Widget_Object_Data -{ - Evas_Object *obj; +static const Eo_Class_Description window_interface_desc = { + EO_VERSION, + "Elm_Atspi_Window_Interface", + EO_CLASS_TYPE_INTERFACE, + EO_CLASS_DESCRIPTION_OPS(NULL, NULL, 0), + window_event_desc, + 0, + NULL, + NULL }; -static void -_del_ao_obj(void *data, Evas *e EINA_UNUSED, Evas_Object *eo EINA_UNUSED, void *event_info EINA_UNUSED) -{ - Elm_Atspi_Object *obj = data; - Access_Widget_Object_Data *ad = eo_data_scope_get(obj, ELM_ATSPI_WIDGET_CLASS); - ad->obj = NULL; - // below will cause Accessibility object destruction while evas object is destroyed and access object has none extra refs - eo_unref(obj); -} +EO_DEFINE_CLASS(elm_atspi_window_interface_get, &window_interface_desc, NULL, NULL); +/// Elm_Atspi_Widget base class static void -_widget_constructor(Eo *obj, void *_pd, va_list *list) +_emit_atspi_state_changed_focused_event(void *data, Evas_Object *eo EINA_UNUSED, void *event_info EINA_UNUSED) { - Evas_Object *widget = ARG_GET(list, Evas_Object*); - Access_Widget_Object_Data *ad = _pd; - const char *name; - - eo_do_super(obj, ELM_ATSPI_WIDGET_CLASS, eo_constructor()); - name = evas_object_type_get(widget); - - evas_object_event_callback_add(widget, EVAS_CALLBACK_DEL, _del_ao_obj, obj); - - ad->obj = widget; - eo_do(obj, elm_atspi_obj_name_set(name)); - eo_do(obj, elm_atspi_obj_role_set(ATSPI_ROLE_UNKNOWN)); + Elm_Atspi_Object *ao = data; + int evdata[2] = {ATSPI_STATE_FOCUSED, 1}; + eo_do(ao, eo_event_callback_call(EV_ATSPI_OBJ_STATE_CHANGED, &evdata[0], NULL)); } static void -_widget_destructor(Eo *obj, void *_pd, va_list *list EINA_UNUSED) +_emit_atspi_state_changed_unfocused_event(void *data, Evas_Object *eo EINA_UNUSED, void *event_info EINA_UNUSED) { - Access_Widget_Object_Data *ad = _pd; - if (ad->obj) - evas_object_event_callback_del(ad->obj, EVAS_CALLBACK_DEL, _del_ao_obj); - - eo_do_super(obj, ELM_ATSPI_WIDGET_CLASS, eo_destructor()); + Elm_Atspi_Object *ao = data; + int evdata[2] = {ATSPI_STATE_FOCUSED, 0}; + eo_do(ao, eo_event_callback_call(EV_ATSPI_OBJ_STATE_CHANGED, &evdata[0], NULL)); } static void -_widget_children_get(Eo *obj, void *_pd, va_list *list) +_widget_constructor(Eo *obj, void *_pd EINA_UNUSED, va_list *list EINA_UNUSED) { - Eina_List **ret = ARG_GET(list, Eina_List**); - Access_Widget_Object_Data *ad = _pd; - Eina_List *l, *al = NULL; - Evas_Object *sub; - Elm_Atspi_Object *ao; - Elm_Widget_Smart_Data *sd; - - EINA_SAFETY_ON_NULL_GOTO(ad->obj, fail); + Evas_Object *internal_obj = NULL; + eo_do_super(obj, ELM_ATSPI_WIDGET_CLASS, eo_constructor()); - sd = eo_data_scope_get(ad->obj, ELM_OBJ_WIDGET_CLASS); - EINA_SAFETY_ON_NULL_GOTO(sd, fail); + eo_do(obj, eo_parent_get(&internal_obj)); - EINA_LIST_FOREACH(sd->subobjs, l, sub) { - if (!sub) continue; - ao = _elm_atspi_factory_construct(sub, obj); - if (ao) - al = eina_list_append(al, ao); - } + /* Evas_Object can only hold refs to atspi-object */ + assert(eo_isa(internal_obj, ELM_OBJ_WIDGET_CLASS)); - *ret = al; - return; - -fail: - *ret = NULL; - return; + evas_object_smart_callback_add(internal_obj, "focused", _emit_atspi_state_changed_focused_event, obj); + evas_object_smart_callback_add(internal_obj, "unfocused", _emit_atspi_state_changed_unfocused_event, obj); } - static void -_widget_state_get(Eo *obj EINA_UNUSED, void *_pd EINA_UNUSED, va_list *list EINA_UNUSED) +_widget_name_get(Eo *obj, void *_pd EINA_UNUSED, va_list *list) { - // FIXME -} + EO_PARAMETER_GET(const char **, ret, list); + Evas_Object *widget = NULL; + const char *name = NULL; - -static void -_widget_comp_access_at_point_get(Eo *obj, void *_pd, va_list *list) -{ - int x = ARG_GET(list, int); - int y = ARG_GET(list, int); - AtspiCoordType type = ARG_GET(list, AtspiCoordType); - Elm_Atspi_Object **ret = ARG_GET(list, Elm_Atspi_Object**); - int ee_x, ee_y; - Access_Widget_Object_Data *ad = _pd; - Eina_List *l, *objs; - Evas_Object *wid; - - if (ad->obj) - { - if (type == ATSPI_COORD_TYPE_SCREEN) - { - Ecore_Evas *ee = ecore_evas_ecore_evas_get(evas_object_evas_get(ad->obj)); - ecore_evas_geometry_get(ee, &ee_x, &ee_y, NULL, NULL); - x -= ee_x; - y -= ee_y; - } - objs = evas_objects_at_xy_get(evas_object_evas_get(ad->obj), x, y, EINA_TRUE, EINA_TRUE); - EINA_LIST_FOREACH(objs, l, wid) - { - // return first only - if (elm_object_widget_check(wid)) - { - *ret = _elm_atspi_factory_construct(wid, obj); - break; - } - } - eina_list_free(objs); - } + eo_do(obj, elm_atspi_obj_object_get(&widget)); + name = elm_object_text_get(widget); + if (ret) *ret = name; } static void -_widget_comp_extents_get(Eo *obj EINA_UNUSED, void *_pd, va_list *list) +_widget_role_get(Eo *obj, void *_pd EINA_UNUSED, va_list *list) { - Access_Widget_Object_Data *ad = _pd; - int *x, *y, *w, *h; - int ee_x, ee_y; - x = ARG_GET(list, int*); - y = ARG_GET(list, int*); - w = ARG_GET(list, int*); - h = ARG_GET(list, int*); - AtspiCoordType type = ARG_GET(list, AtspiCoordType); + EO_PARAMETER_GET(AtspiRole*, ret, list); + const char *type; + AtspiRole role; + Evas_Object *widget = NULL; + eo_do(obj, elm_atspi_obj_object_get(&widget)); + if (!widget) return; + type = evas_object_type_get(widget); + + // FIXME make it hash or cast some first bytes to int. + if (!strcmp(type, "elm_win")) + role = ATSPI_ROLE_WINDOW; + else if (!strcmp(type, "elm_button")) + role = ATSPI_ROLE_PUSH_BUTTON; + else + role = ATSPI_ROLE_UNKNOWN; - if (ad->obj) - { - evas_object_geometry_get(ad->obj, x, y, w, h); - if (type == ATSPI_COORD_TYPE_SCREEN) - { - Ecore_Evas *ee = ecore_evas_ecore_evas_get(evas_object_evas_get(ad->obj)); - ecore_evas_geometry_get(ee, &ee_x, &ee_y, NULL, NULL); - if (x) *x += ee_x; - if (y) *y += ee_y; - } - } + if (ret) *ret = role; } static void -_widget_comp_extents_set(Eo *obj EINA_UNUSED, void *_pd, va_list *list) +_widget_parent_get(Eo *obj, void *_pd EINA_UNUSED, va_list *list) { - Access_Widget_Object_Data *ad = _pd; - int x, y, w, h; - int wx, wy; - x = ARG_GET(list, int); - y = ARG_GET(list, int); - w = ARG_GET(list, int); - h = ARG_GET(list, int); - AtspiCoordType type = ARG_GET(list, AtspiCoordType); - Eina_Bool *ret = ARG_GET(list, Eina_Bool*); + EO_PARAMETER_GET(Elm_Atspi_Object **, ret, list); + Evas_Object *widget = NULL; + Elm_Atspi_Object *parent; - *ret = EINA_FALSE; + eo_do(obj, elm_atspi_obj_object_get(&widget)); + widget = elm_object_parent_widget_get(widget); - if ((x < 0) || (y < 0) || (w < 0) || (h < 0)) return; + if (widget) + parent = _elm_atspi_factory_construct(widget); + else // if parent is not found, attach it to atspi root object. + parent = _elm_atspi_root_object_get(); - if (ad->obj) - { - if (type == ATSPI_COORD_TYPE_SCREEN) - { - Ecore_Evas *ee = ecore_evas_ecore_evas_get(evas_object_evas_get(ad->obj)); - evas_object_geometry_get(ad->obj, &wx, &wy, NULL, NULL); - ecore_evas_move(ee, x - wx, y - wy); - } - else - evas_object_move(ad->obj, x, y); - - evas_object_resize(ad->obj, w, h); - *ret = EINA_TRUE; - } + if (ret) *ret = parent; } - static void -_widget_comp_layer_get(Eo *obj EINA_UNUSED, void *_pd, va_list *list) +_widget_children_get(Eo *obj, void *_pd EINA_UNUSED, va_list *list) { - int *l = ARG_GET(list, int *); - Access_Widget_Object_Data *ad = _pd; + EO_PARAMETER_GET(Eina_List **, ret, list); + Evas_Object *widget = NULL; + Eina_List *l, *accs = NULL; + Elm_Widget_Smart_Data *sd; + Elm_Atspi_Object *aobj; - if (ad->obj) - *l = evas_object_layer_get(ad->obj); -} + eo_do(obj, elm_atspi_obj_object_get(&widget)); -static void -_widget_comp_z_order_get(Eo *obj EINA_UNUSED, void *_pd EINA_UNUSED, va_list *list EINA_UNUSED) -{ - // FIXME + sd = eo_data_scope_get(widget, ELM_OBJ_WIDGET_CLASS); + if (!sd) return; + + EINA_LIST_FOREACH(sd->subobjs, l, widget) + { + if (!elm_object_widget_check(widget)) continue; + aobj = _elm_atspi_factory_construct(widget); + if (aobj) + accs = eina_list_append(accs, aobj); + } + if (ret) + *ret = accs; + else + eina_list_free(accs); } static void -_widget_comp_focus_grab(Eo *obj EINA_UNUSED, void *_pd, va_list *list) +_widget_state_get(Eo *obj, void *_pd EINA_UNUSED, va_list *list) { - Eina_Bool *ret = ARG_GET(list, Eina_Bool*); - Access_Widget_Object_Data *ad = _pd; + EO_PARAMETER_GET(Elm_Atspi_State *, ret, list); + Evas_Object *widget; + Elm_Atspi_State states; + eo_do(obj, elm_atspi_obj_object_get(&widget)); - *ret = EINA_FALSE; + eo_do_super(obj, ELM_ATSPI_WIDGET_CLASS, elm_atspi_obj_state_get(&states)); - if (ad->obj && elm_object_focus_allow_get(ad->obj)) - { - Ecore_Evas *ee = ecore_evas_ecore_evas_get(evas_object_evas_get(ad->obj)); + if (elm_object_focus_get(widget)) + BIT_FLAG_SET(states, ATSPI_STATE_FOCUSED); + if (elm_object_focus_allow_get(widget)) + BIT_FLAG_SET(states, ATSPI_STATE_FOCUSABLE); + if (!elm_object_disabled_get(widget)) + BIT_FLAG_SET(states, ATSPI_STATE_ENABLED); - ecore_evas_activate(ee); - elm_object_focus_set(ad->obj, EINA_TRUE); - *ret = EINA_TRUE; - } + if (ret) *ret = states; } static void -_widget_comp_alpha_get(Eo *obj EINA_UNUSED, void *_pd, va_list *list) +_widget_comp_focus_grab(Eo *obj, void *_pd EINA_UNUSED, va_list *list) { - double *ret = ARG_GET(list, double*); - int alpha; - Access_Widget_Object_Data *ad = _pd; + EO_PARAMETER_GET(Eina_Bool*, ret, list); + Evas_Object *evobj = NULL; + if (ret) *ret = EINA_FALSE; - if (ad->obj) + eo_do(obj, elm_atspi_obj_object_get(&evobj)); + EINA_SAFETY_ON_NULL_RETURN(evobj); + if (elm_object_focus_allow_get(evobj)) { - evas_object_color_get(ad->obj, NULL, NULL, NULL, &alpha); - *ret = (double)alpha/255.0; + Ecore_Evas *ee = ecore_evas_ecore_evas_get(evas_object_evas_get(evobj)); + if (!ee) return; + ecore_evas_activate(ee); + elm_object_focus_set(evobj, EINA_TRUE); + if (ret) *ret = EINA_TRUE; } } @@ -693,16 +784,12 @@ _widget_class_constructor(Eo_Class *klass) { const Eo_Op_Func_Description func_desc[] = { EO_OP_FUNC(EO_BASE_ID(EO_BASE_SUB_ID_CONSTRUCTOR), _widget_constructor), - EO_OP_FUNC(EO_BASE_ID(EO_BASE_SUB_ID_DESTRUCTOR), _widget_destructor), + EO_OP_FUNC(ELM_ATSPI_OBJ_ID(ELM_ATSPI_OBJ_SUB_ID_NAME_GET), _widget_name_get), + EO_OP_FUNC(ELM_ATSPI_OBJ_ID(ELM_ATSPI_OBJ_SUB_ID_ROLE_GET), _widget_role_get), + EO_OP_FUNC(ELM_ATSPI_OBJ_ID(ELM_ATSPI_OBJ_SUB_ID_PARENT_GET), _widget_parent_get), EO_OP_FUNC(ELM_ATSPI_OBJ_ID(ELM_ATSPI_OBJ_SUB_ID_CHILDREN_GET), _widget_children_get), EO_OP_FUNC(ELM_ATSPI_OBJ_ID(ELM_ATSPI_OBJ_SUB_ID_STATE_GET), _widget_state_get), - EO_OP_FUNC(ELM_ATSPI_COMPONENT_INTERFACE_ID(ELM_ATSPI_COMPONENT_INTERFACE_SUB_ID_ACCESSIBLE_AT_POINT_GET), _widget_comp_access_at_point_get), - EO_OP_FUNC(ELM_ATSPI_COMPONENT_INTERFACE_ID(ELM_ATSPI_COMPONENT_INTERFACE_SUB_ID_EXTENTS_GET), _widget_comp_extents_get), - EO_OP_FUNC(ELM_ATSPI_COMPONENT_INTERFACE_ID(ELM_ATSPI_COMPONENT_INTERFACE_SUB_ID_EXTENTS_SET), _widget_comp_extents_set), - EO_OP_FUNC(ELM_ATSPI_COMPONENT_INTERFACE_ID(ELM_ATSPI_COMPONENT_INTERFACE_SUB_ID_LAYER_GET), _widget_comp_layer_get), - EO_OP_FUNC(ELM_ATSPI_COMPONENT_INTERFACE_ID(ELM_ATSPI_COMPONENT_INTERFACE_SUB_ID_Z_ORDER_GET), _widget_comp_z_order_get), EO_OP_FUNC(ELM_ATSPI_COMPONENT_INTERFACE_ID(ELM_ATSPI_COMPONENT_INTERFACE_SUB_ID_FOCUS_GRAB), _widget_comp_focus_grab), - EO_OP_FUNC(ELM_ATSPI_COMPONENT_INTERFACE_ID(ELM_ATSPI_COMPONENT_INTERFACE_SUB_ID_ALPHA_GET), _widget_comp_alpha_get), EO_OP_FUNC_SENTINEL }; eo_class_funcs_set(klass, func_desc); @@ -710,77 +797,65 @@ _widget_class_constructor(Eo_Class *klass) static const Eo_Class_Description widget_class_desc = { EO_VERSION, - "Elm_Widget Access_Object", + "Elm_Widget_Access_Object", EO_CLASS_TYPE_REGULAR, EO_CLASS_DESCRIPTION_OPS(NULL, NULL, 0), NULL, - sizeof(Access_Widget_Object_Data), + 0, _widget_class_constructor, NULL }; -EO_DEFINE_CLASS(elm_atspi_widget_obj_class_get, &widget_class_desc, ELM_ATSPI_CLASS, ELM_ATSPI_COMPONENT_INTERFACE, NULL); +EO_DEFINE_CLASS(elm_atspi_widget_obj_class_get, &widget_class_desc, ELM_ATSPI_CLASS, NULL); -static Elm_Atspi_Object * -_elm_atspi_factory_construct(Evas_Object *obj, Elm_Atspi_Object *parent) -{ - Elm_Atspi_Object *ret; - EINA_SAFETY_ON_NULL_RETURN_VAL(obj, NULL); - EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL); - - if (!elm_object_widget_check(obj)) - return NULL; - - if (!strcmp(evas_object_type_get(obj), "elm_access")) - return NULL; - - ret = evas_object_data_get(obj, "_atspi_object"); - if (!ret) - { - ret = eo_add(ELM_ATSPI_WIDGET_CLASS, parent, obj); - evas_object_data_set(obj, "_atspi_object", ret); - eo_unref(ret); // only parent should hold reference to atspi object - } - else - { - Elm_Atspi_Object *tmp; - eo_do(ret, eo_parent_get(&tmp)); - if (!tmp) - eo_do(ret, eo_parent_set(parent)); - } - - return ret; -} /// Elm_Atspi_App base class -const Eo_Class *elm_atspi_app_obj_class_get(void) EINA_CONST; #define ELM_ATSPI_APP_CLASS elm_atspi_app_obj_class_get() static void -_app_children_get(Eo *obj, void *_pd EINA_UNUSED, va_list *list) +_app_children_get(Eo *obj EINA_UNUSED, void *_pd EINA_UNUSED, va_list *list) { - Eina_List **ret = ARG_GET(list, Eina_List**); - Eina_List *l, *objs = NULL; + EO_PARAMETER_GET(Eina_List **, ret, list); + Eina_List *l, *accs = NULL; + Elm_Atspi_Object *aobj; Evas_Object *win; - Elm_Atspi_Object *o = NULL; EINA_LIST_FOREACH(_elm_win_list, l, win) { - if (!win) continue; - o = _elm_atspi_factory_construct(win, obj); - if (o) - objs = eina_list_append(objs, o); + if (!win) continue; + aobj = _elm_atspi_factory_construct(win); + if (aobj) + accs = eina_list_append(accs, aobj); } - *ret = objs; + + if (ret) *ret = accs; } static void _app_constructor(Eo *obj, void *_pd EINA_UNUSED, va_list *list EINA_UNUSED) { - eo_do_super(obj, ELM_ATSPI_APP_CLASS, eo_constructor()); + eo_do_super(obj, ELM_ATSPI_CLASS, eo_constructor()); +} - eo_do(obj, elm_atspi_obj_name_set(elm_app_name_get())); - eo_do(obj, elm_atspi_obj_role_set(ATSPI_ROLE_APPLICATION)); +static void +_app_name_get(Eo *obj EINA_UNUSED, void *_pd EINA_UNUSED, va_list *list EINA_UNUSED) +{ + EO_PARAMETER_GET(const char **, name, list); + if (name) *name = elm_app_name_get(); +} + +static void +_app_role_get(Eo *obj EINA_UNUSED, void *_pd EINA_UNUSED, va_list *list EINA_UNUSED) +{ + EO_PARAMETER_GET(AtspiRole *, ret, list); + if (ret) *ret = ATSPI_ROLE_APPLICATION; +} + +static void +_app_parent_get(Eo *obj EINA_UNUSED, void *_pd EINA_UNUSED, va_list *list EINA_UNUSED) +{ + EO_PARAMETER_GET(Elm_Atspi_Object **, ret, list); + if (ret) *ret = NULL; } static void @@ -788,6 +863,9 @@ _app_class_constructor(Eo_Class *klass) { const Eo_Op_Func_Description func_desc[] = { EO_OP_FUNC(EO_BASE_ID(EO_BASE_SUB_ID_CONSTRUCTOR), _app_constructor), + EO_OP_FUNC(ELM_ATSPI_OBJ_ID(ELM_ATSPI_OBJ_SUB_ID_NAME_GET), _app_name_get), + EO_OP_FUNC(ELM_ATSPI_OBJ_ID(ELM_ATSPI_OBJ_SUB_ID_ROLE_GET), _app_role_get), + EO_OP_FUNC(ELM_ATSPI_OBJ_ID(ELM_ATSPI_OBJ_SUB_ID_PARENT_GET), _app_parent_get), EO_OP_FUNC(ELM_ATSPI_OBJ_ID(ELM_ATSPI_OBJ_SUB_ID_CHILDREN_GET), _app_children_get), EO_OP_FUNC_SENTINEL }; @@ -800,7 +878,7 @@ static const Eo_Op_Description app_op_desc[] = { static const Eo_Class_Description app_class_desc = { EO_VERSION, - "App Access_Object", + "Elm_App_Access_Object", EO_CLASS_TYPE_REGULAR, EO_CLASS_DESCRIPTION_OPS(NULL, NULL, 0), NULL, @@ -811,14 +889,165 @@ static const Eo_Class_Description app_class_desc = { EO_DEFINE_CLASS(elm_atspi_app_obj_class_get, &app_class_desc, ELM_ATSPI_CLASS, NULL); -Elm_Atspi_Object * elm_atspi_root_object_get(void) +// elm_win wrapper + +const Eo_Class *elm_atspi_win_obj_class_get(void) EINA_CONST; +#define ELM_ATSPI_WIN_CLASS elm_atspi_win_obj_class_get() + +static void +_win_focused(void *data, Evas_Object *eo EINA_UNUSED, void *event_info EINA_UNUSED) +{ + Elm_Atspi_Object *ao = data; + eo_do(ao, eo_event_callback_call(EV_ATSPI_OBJ_WINDOW_ACTIVATED, NULL, NULL)); +} + +static void +_win_unfocused(void *data, Evas_Object *eo EINA_UNUSED, void *event_info EINA_UNUSED) { - static Elm_Atspi_Object *app; + Elm_Atspi_Object *ao = data; + eo_do(ao, eo_event_callback_call(EV_ATSPI_OBJ_WINDOW_DEACTIVATED, NULL, NULL)); +} - if (!app) - app = eo_add(ELM_ATSPI_APP_CLASS, NULL); +static void +_win_constructor(Eo *obj, void *_pd EINA_UNUSED, va_list *list EINA_UNUSED) +{ + eo_do_super(obj, ELM_ATSPI_WIN_CLASS, eo_constructor()); + Evas_Object *evobj = NULL; + + eo_do(obj, elm_atspi_obj_object_get(&evobj)); + + evas_object_smart_callback_add(evobj, "focused", _win_focused, obj); + evas_object_smart_callback_add(evobj, "unfocused", _win_unfocused, obj); +} + +static void +_win_destructor(Eo *obj, void *_pd EINA_UNUSED, va_list *list EINA_UNUSED) +{ + Elm_Atspi_Object *root = _elm_atspi_root_object_get(); + eo_do(root, eo_event_callback_call(EV_ATSPI_OBJ_CHILD_DEL, obj, NULL)); + + eo_do_super(obj, ELM_ATSPI_WIN_CLASS, eo_destructor()); +} + +static void +_win_name_get(Eo *obj, void *_pd EINA_UNUSED, va_list *list EINA_UNUSED) +{ + EO_PARAMETER_GET(const char **, ret, list); + Evas_Object *evobj = NULL; + + eo_do(obj, elm_atspi_obj_object_get(&evobj)); + EINA_SAFETY_ON_NULL_RETURN(evobj); + + if (ret) *ret = elm_win_title_get(evobj); +} + +static void +_win_parent_get(Eo *obj EINA_UNUSED, void *_pd EINA_UNUSED, va_list *list EINA_UNUSED) +{ + EO_PARAMETER_GET(Elm_Atspi_Object **, ret, list); + if (ret) *ret = _elm_atspi_root_object_get(); +} + +static void +_win_class_constructor(Eo_Class *klass) +{ + const Eo_Op_Func_Description func_desc[] = { + EO_OP_FUNC(EO_BASE_ID(EO_BASE_SUB_ID_CONSTRUCTOR), _win_constructor), + EO_OP_FUNC(EO_BASE_ID(EO_BASE_SUB_ID_DESTRUCTOR), _win_destructor), + EO_OP_FUNC(ELM_ATSPI_OBJ_ID(ELM_ATSPI_OBJ_SUB_ID_NAME_GET), _win_name_get), + EO_OP_FUNC(ELM_ATSPI_OBJ_ID(ELM_ATSPI_OBJ_SUB_ID_PARENT_GET), _win_parent_get), + EO_OP_FUNC_SENTINEL + }; + eo_class_funcs_set(klass, func_desc); +} + +static const Eo_Class_Description win_class_desc = { + EO_VERSION, + "Elm_Win_Access_Object", + EO_CLASS_TYPE_REGULAR, + EO_CLASS_DESCRIPTION_OPS(NULL, NULL, 0), + NULL, + 0, + _win_class_constructor, + NULL +}; + +EO_DEFINE_CLASS(elm_atspi_win_obj_class_get, &win_class_desc, ELM_ATSPI_WIDGET_CLASS, ELM_ATSPI_WINDOW_INTERFACE, NULL); + +Elm_Atspi_Object* +_elm_atspi_root_object_get(void) +{ + if (!_app) + _app = eo_add(ELM_ATSPI_APP_CLASS, NULL); else - eo_ref(app); + eo_ref(_app); + + return _app; +} + +Elm_Atspi_Object * +_elm_atspi_factory_construct(Evas_Object *obj) +{ + Elm_Atspi_Object *ret; + const char *type; + + EINA_SAFETY_ON_NULL_RETURN_VAL(obj, NULL); + + ret = evas_object_data_get(obj, "_atspi_object"); + if (ret) return ret; - return app; + type = evas_object_type_get(obj); + + //FIXME add possibility to install new handlers + if (!strcmp(type, "elm_access")) + { + DBG("Unable to create ATSPI object for elm_access widget."); + return NULL; + } + else if (!strcmp(type, "elm_win")) + ret = eo_add(ELM_ATSPI_WIN_CLASS, obj); + else if (!strncmp(type, "elm_", 4)) // defaults to implementation for elm_widget class. + ret = eo_add(ELM_ATSPI_WIDGET_CLASS, obj); + + eo_unref(ret); // only evas_object should hold reference to atspi object + + return ret; +} + +void _elm_atspi_object_init(void) +{ +} + +void _elm_atspi_object_shutdown(void) +{ + Elm_Atspi_Global_Callback_Info *info; + if (_app) + eo_del(_app); + + EINA_LIST_FREE(_global_callbacks, info) + free(info); + _global_callbacks = NULL; +} + +void _elm_atspi_object_global_callback_add(Eo_Event_Cb cb, void *user_data) +{ + Elm_Atspi_Global_Callback_Info *info = calloc(1, sizeof(Elm_Atspi_Global_Callback_Info)); + if (!info) return; + info->user_data = user_data; + info->cb = cb; + _global_callbacks = eina_list_append(_global_callbacks, info); +} + +void _elm_atspi_object_global_callback_del(Eo_Event_Cb cb) +{ + Elm_Atspi_Global_Callback_Info *info; + Eina_List *l; + EINA_LIST_FOREACH(_global_callbacks, l, info) + { + if ((info->cb == cb)) + { + _global_callbacks = eina_list_remove(_global_callbacks, info); + free(info); + } + } } diff --git a/src/lib/elm_atspi_object_common.h b/src/lib/elm_atspi_object_common.h index fdc533b..767f74b 100644 --- a/src/lib/elm_atspi_object_common.h +++ b/src/lib/elm_atspi_object_common.h @@ -1 +1,24 @@ typedef Eo Elm_Atspi_Object; + +typedef uint64_t Elm_Atspi_State; + +typedef enum _Elm_Atspi_Event Elm_Atspi_Event; + +#define BIT_FLAG_SET(mask, bit) (mask |= (1 << bit)) +#define BIT_FLAG_UNSET(mask, bit) (mask &= ~(1 << bit)) +#define BIT_FLAG_GET(mask, bit) (mask & (1 << bit)) + +/* + * @brief Gets root (application) type atspi-object. + */ +Elm_Atspi_Object * _elm_atspi_root_object_get(void); + +/* + * @brief Constructs atspi-object for evas_object + */ +Elm_Atspi_Object * _elm_atspi_factory_construct(Evas_Object *obj); + +void _elm_atspi_object_init(void); + +void _elm_atspi_object_shutdown(void); + diff --git a/src/lib/elm_atspi_object_eo.h b/src/lib/elm_atspi_object_eo.h index 67a07c6..d1ff2b7 100644 --- a/src/lib/elm_atspi_object_eo.h +++ b/src/lib/elm_atspi_object_eo.h @@ -1,32 +1,47 @@ -#define ELM_ATSPI_CLASS elm_atspi_obj_class_get() +void _elm_atspi_object_global_callback_add(Eo_Event_Cb cv, void *user_data); +void _elm_atspi_object_global_callback_del(Eo_Event_Cb cv); +#define ELM_ATSPI_CLASS elm_atspi_obj_class_get() const Eo_Class *elm_atspi_obj_class_get(void) EINA_CONST; +#define ELM_ATSPI_WIDGET_CLASS elm_atspi_widget_obj_class_get() +const Eo_Class *elm_atspi_widget_obj_class_get(void) EINA_CONST; + extern EAPI Eo_Op ELM_ATSPI_OBJ_BASE_ID; enum { - ELM_ATSPI_OBJ_SUB_ID_NAME_GET, - ELM_ATSPI_OBJ_SUB_ID_NAME_SET, - ELM_ATSPI_OBJ_SUB_ID_DESCRIPTION_GET, - ELM_ATSPI_OBJ_SUB_ID_DESCRIPTION_SET, - ELM_ATSPI_OBJ_SUB_ID_PARENT_GET, + ELM_ATSPI_OBJ_SUB_ID_NAME_GET, /* virtual */ + ELM_ATSPI_OBJ_SUB_ID_DESCRIPTION_GET, /* virtual */ ELM_ATSPI_OBJ_SUB_ID_CHILD_AT_INDEX_GET, - ELM_ATSPI_OBJ_SUB_ID_CHILDREN_GET, + ELM_ATSPI_OBJ_SUB_ID_CHILDREN_GET, /* virtual */ + ELM_ATSPI_OBJ_SUB_ID_PARENT_GET, /* virtual */ + ELM_ATSPI_OBJ_SUB_ID_OBJECT_GET, ELM_ATSPI_OBJ_SUB_ID_INDEX_IN_PARENT_GET, - ELM_ATSPI_OBJ_SUB_ID_RELATION_SET_GET, - ELM_ATSPI_OBJ_SUB_ID_RELATION_SET_SET, - ELM_ATSPI_OBJ_SUB_ID_ROLE_GET, - ELM_ATSPI_OBJ_SUB_ID_ROLE_SET, + ELM_ATSPI_OBJ_SUB_ID_RELATION_SET_GET, /* virtual */ + ELM_ATSPI_OBJ_SUB_ID_ROLE_GET, /* virtual */ ELM_ATSPI_OBJ_SUB_ID_ROLE_NAME_GET, ELM_ATSPI_OBJ_SUB_ID_LOCALIZED_ROLE_NAME_GET, - ELM_ATSPI_OBJ_SUB_ID_STATE_GET, - ELM_ATSPI_OBJ_SUB_ID_ATTRIBUTES_GET, + ELM_ATSPI_OBJ_SUB_ID_STATE_GET, /* virtual */ + ELM_ATSPI_OBJ_SUB_ID_ATTRIBUTES_GET, /* virtual */ ELM_ATSPI_OBJ_SUB_ID_LAST }; #define ELM_ATSPI_OBJ_ID(sub_id) (ELM_ATSPI_OBJ_BASE_ID + sub_id) +/* Elm_Atspi_Object events */ +extern const Eo_Event_Description _EV_ATSPI_OBJ_NAME_CHANGED; +#define EV_ATSPI_OBJ_NAME_CHANGED (&(_EV_ATSPI_OBJ_NAME_CHANGED)) + +extern const Eo_Event_Description _EV_ATSPI_OBJ_CHILD_ADD; +#define EV_ATSPI_OBJ_CHILD_ADD (&(_EV_ATSPI_OBJ_CHILD_ADD)) + +extern const Eo_Event_Description _EV_ATSPI_OBJ_CHILD_DEL; +#define EV_ATSPI_OBJ_CHILD_DEL (&(_EV_ATSPI_OBJ_CHILD_DEL)) + +extern const Eo_Event_Description _EV_ATSPI_OBJ_STATE_CHANGED; +#define EV_ATSPI_OBJ_STATE_CHANGED (&(_EV_ATSPI_OBJ_STATE_CHANGED)) + /* Component Interface */ #define ELM_ATSPI_COMPONENT_INTERFACE elm_atspi_component_interface_get() @@ -54,6 +69,17 @@ enum #define ELM_ATSPI_COMPONENT_INTERFACE_ID(sub_id) (ELM_ATSPI_COMPONENT_INTERFACE_BASE_ID + sub_id) /* Component Interface - END */ +/* Window Interface */ +#define ELM_ATSPI_WINDOW_INTERFACE elm_atspi_window_interface_get() +const Eo_Class *elm_atspi_window_interface_get(void) EINA_CONST; + +extern const Eo_Event_Description _EV_ATSPI_OBJ_WINDOW_ACTIVATED; +#define EV_ATSPI_OBJ_WINDOW_ACTIVATED (&(_EV_ATSPI_OBJ_WINDOW_ACTIVATED)) + +extern const Eo_Event_Description _EV_ATSPI_OBJ_WINDOW_DEACTIVATED; +#define EV_ATSPI_OBJ_WINDOW_DEACTIVATED (&(_EV_ATSPI_OBJ_WINDOW_DEACTIVATED)) +/* Window Interface - END */ + /* Action Interface */ #define ELM_ATSPI_ACTION_INTERFACE elm_accessible_action_interface_get() @@ -108,6 +134,7 @@ enum }; /* Text Interface - END */ + /* EditableText Interface */ #define ELM_ATSPI_EDITABLE_TEXT_INTERFACE elm_accessible_editable_text_interface_get() @@ -127,10 +154,9 @@ enum }; /* EditableText Interface - END */ +/* Value Interface */ #define ELM_ATSPI_VALUE_INTERFACE elm_accessible_value_interface_get() - -/* Value Interface */ const Eo_Class *elm_accessible_value_interface_get(void) EINA_CONST; extern EAPI Eo_Op ELM_ATSPI_VALUE_INTERFACE_BASE_ID; @@ -184,18 +210,10 @@ enum ELM_ATSPI_OBJ_ID(ELM_ATSPI_OBJ_SUB_ID_NAME_GET), \ EO_TYPECHECK(const char **, ret) -#define elm_atspi_obj_name_set(name)\ - ELM_ATSPI_OBJ_ID(ELM_ATSPI_OBJ_SUB_ID_NAME_SET),\ - EO_TYPECHECK(const char *, name) - #define elm_atspi_obj_role_get(role)\ ELM_ATSPI_OBJ_ID(ELM_ATSPI_OBJ_SUB_ID_ROLE_GET), \ EO_TYPECHECK(AtspiRole*, role) -#define elm_atspi_obj_role_set(role)\ - ELM_ATSPI_OBJ_ID(ELM_ATSPI_OBJ_SUB_ID_ROLE_SET),\ - EO_TYPECHECK(AtspiRole, role) - #define elm_atspi_obj_role_name_get(ret)\ ELM_ATSPI_OBJ_ID(ELM_ATSPI_OBJ_SUB_ID_ROLE_NAME_GET),\ EO_TYPECHECK(const char **, ret) @@ -208,14 +226,6 @@ enum ELM_ATSPI_OBJ_ID(ELM_ATSPI_OBJ_SUB_ID_DESCRIPTION_GET),\ EO_TYPECHECK(const char **, ret) -#define elm_atspi_obj_description_set(desc)\ - ELM_ATSPI_OBJ_ID(ELM_ATSPI_OBJ_SUB_ID_DESCRIPTION_SET),\ - EO_TYPECHECK(const char *, desc) - -#define elm_atspi_obj_parent_get(ret)\ - ELM_ATSPI_OBJ_ID(ELM_ATSPI_OBJ_SUB_ID_PARENT_GET),\ - EO_TYPECHECK(Elm_Atspi_Object**, ret) - #define elm_atspi_obj_child_at_index_get(idx, ret)\ ELM_ATSPI_OBJ_ID(ELM_ATSPI_OBJ_SUB_ID_CHILD_AT_INDEX_GET), \ EO_TYPECHECK(int, idx),\ @@ -225,6 +235,14 @@ enum ELM_ATSPI_OBJ_ID(ELM_ATSPI_OBJ_SUB_ID_CHILDREN_GET),\ EO_TYPECHECK(Eina_List**, ret) +#define elm_atspi_obj_parent_get(ret)\ + ELM_ATSPI_OBJ_ID(ELM_ATSPI_OBJ_SUB_ID_PARENT_GET),\ + EO_TYPECHECK(Elm_Atspi_Object**, ret) + +#define elm_atspi_obj_object_get(ret)\ + ELM_ATSPI_OBJ_ID(ELM_ATSPI_OBJ_SUB_ID_OBJECT_GET),\ + EO_TYPECHECK(Evas_Object**, ret) + #define elm_atspi_obj_index_in_parent_get(ret)\ ELM_ATSPI_OBJ_ID(ELM_ATSPI_OBJ_SUB_ID_INDEX_IN_PARENT_GET),\ EO_TYPECHECK(int*, ret) @@ -233,11 +251,13 @@ enum ELM_ATSPI_OBJ_ID(ELM_ATSPI_OBJ_SUB_ID_RELATION_SET_GET),\ EO_TYPECHECK() -#define elm_atspi_obj_relation_set_set() ELM_ATSPI_OBJ_ID(ELM_ATSPI_OBJ_SUB_ID_RELATION_SET_SET), EO_TYPECHECK() - -#define elm_atspi_obj_state_get() ELM_ATSPI_OBJ_ID(ELM_ATSPI_OBJ_SUB_ID_STATE_GET), EO_TYPECHECK() +#define elm_atspi_obj_state_get(ret)\ + ELM_ATSPI_OBJ_ID(ELM_ATSPI_OBJ_SUB_ID_STATE_GET),\ + EO_TYPECHECK(Elm_Atspi_State*, ret) -#define elm_atspi_obj_attributes_get() ELM_ATSPI_OBJ_ID(ELM_ATSPI_OBJ_SUB_ID_ATTRIBUTES_GET), EO_TYPECHECK() +#define elm_atspi_obj_attributes_get()\ + ELM_ATSPI_OBJ_ID(ELM_ATSPI_OBJ_SUB_ID_ATTRIBUTES_GET),\ + EO_TYPECHECK() #define elm_atspi_component_interface_contains(x, y, type, ret)\ ELM_ATSPI_COMPONENT_INTERFACE_ID(ELM_ATSPI_COMPONENT_INTERFACE_SUB_ID_CONTAINS),\ diff --git a/src/lib/elm_atspi_object_legacy.h b/src/lib/elm_atspi_object_legacy.h index ea5e93b..5ec21a3 100644 --- a/src/lib/elm_atspi_object_legacy.h +++ b/src/lib/elm_atspi_object_legacy.h @@ -1 +1,2 @@ -EAPI Elm_Atspi_Object * elm_atspi_root_object_get(void); +// to be removed to private: + diff --git a/src/lib/elm_widget.c b/src/lib/elm_widget.c index 4cb6010..5671efb 100644 --- a/src/lib/elm_widget.c +++ b/src/lib/elm_widget.c @@ -6318,6 +6318,19 @@ elm_widget_tree_dot_dump(const Evas_Object *top, #endif } +static Eina_Bool +_atspi_obj_create(void *data) +{ + Elm_Atspi_Object *parent = NULL; + Elm_Atspi_Object *obj = _elm_atspi_factory_construct(data); + if (obj) + { + eo_do(obj, elm_atspi_obj_parent_get(&parent)); + eo_do(parent, eo_event_callback_call(EV_ATSPI_OBJ_CHILD_ADD, obj, NULL)); + } + return EINA_FALSE; +} + static void _constructor(Eo *obj, void *class_data EINA_UNUSED, va_list *list EINA_UNUSED) { @@ -6331,6 +6344,9 @@ _constructor(Eo *obj, void *class_data EINA_UNUSED, va_list *list EINA_UNUSED) eo_parent_get(&parent)); eo_do(obj, elm_wdg_parent_set(parent)); sd->on_create = EINA_FALSE; + + if (_elm_config->access_mode == ELM_ACCESS_MODE_ON) + ecore_idle_enterer_add(_atspi_obj_create, obj); } static void