efl/src/lib/elementary/elm_atspi_bridge.c

5295 lines
189 KiB
C
Raw Normal View History

#ifdef HAVE_CONFIG_H
# include "elementary_config.h"
#endif
#define EFL_ACCESS_COMPONENT_PROTECTED
#define EFL_ACCESS_OBJECT_PROTECTED
#define EFL_ACCESS_ACTION_PROTECTED
#define EFL_ACCESS_VALUE_PROTECTED
#define EFL_ACCESS_SELECTION_PROTECTED
#define EFL_ACCESS_TEXT_PROTECTED
#define EFL_ACCESS_EDITABLE_TEXT_PROTECTED
#include "atspi/atspi-constants.h"
#include <stdint.h>
#include <assert.h>
#include <Elementary.h>
#include "elm_priv.h"
/*
* Accessibility Bus info not defined in atspi-constants.h
*/
#define A11Y_DBUS_NAME "org.a11y.Bus"
#define A11Y_DBUS_PATH "/org/a11y/bus"
#define A11Y_DBUS_INTERFACE "org.a11y.Bus"
#define A11Y_DBUS_STATUS_INTERFACE "org.a11y.Status"
#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"
#define ELM_ACCESS_OBJECT_PATH_ROOT "root"
#define ELM_ACCESS_OBJECT_PATH_PREFIX "/org/a11y/atspi/accessible/"
#define ELM_ACCESS_OBJECT_PATH_PREFIX2 "/org/a11y/atspi/accessible"
#define ELM_ACCESS_OBJECT_REFERENCE_TEMPLATE ELM_ACCESS_OBJECT_PATH_PREFIX "%llu"
#define SIZE(x) sizeof(x)/sizeof(x[0])
#define ELM_ATSPI_BRIDGE_CLASS_NAME "__Elm_Atspi_Bridge"
#define ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(obj, sd) \
Elm_Atspi_Bridge_Data *sd = efl_data_scope_get(obj, ELM_ATSPI_BRIDGE_CLASS); \
if (!sd) return;
#define ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN_VAL(obj, sd, val) \
Elm_Atspi_Bridge_Data *sd = efl_data_scope_get(obj, ELM_ATSPI_BRIDGE_CLASS); \
if (!sd) return val;
#define ELM_ATSPI_PROPERTY_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, class, msg, error) \
if (!(obj) || !efl_isa(obj, class)) \
{ \
*(error) = _dbus_invalid_ref_error_new(msg); \
return EINA_FALSE; \
}
#define ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, class, msg) \
if (!(obj) || !efl_isa(obj, class)) \
return _dbus_invalid_ref_error_new(msg);
#define ELM_ATSPI_ON_NULL_RETURN_DBUS_ERROR(obj, msg) \
if (!obj) \
return _dbus_invalid_ref_error_new(msg);
typedef struct Key_Event_Info {
Ecore_Event_Key event;
int type;
Eo *bridge;
} Key_Event_Info;
typedef struct _Elm_Atspi_Bridge_Data
{
Eldbus_Connection *session_bus;
Eldbus_Connection *a11y_bus;
Eina_Hash *cache;
Eldbus_Service_Interface *cache_interface;
Eldbus_Signal_Handler *register_hdl;
Eldbus_Signal_Handler *unregister_hdl;
unsigned long object_broadcast_mask;
unsigned long object_property_broadcast_mask;
unsigned long object_children_broadcast_mask;
unsigned long long object_state_broadcast_mask;
unsigned long long window_signal_broadcast_mask;
Ecore_Event_Filter *key_flr;
Eldbus_Object *bus_obj;
Eina_List *pending_requests;
int id;
2015-07-06 14:32:35 -07:00
Eina_Hash *state_hash;
struct {
Eldbus_Service_Interface *accessible;
Eldbus_Service_Interface *application;
Eldbus_Service_Interface *action;
Eldbus_Service_Interface *component;
Eldbus_Service_Interface *collection;
Eldbus_Service_Interface *editable_text;
Eldbus_Service_Interface *image;
Eldbus_Service_Interface *selection;
Eldbus_Service_Interface *text;
Eldbus_Service_Interface *value;
} interfaces;
Efl_Access_Event_Handler *event_hdlr;
Eina_Hash *event_hash;
Eina_Bool connected : 1;
} Elm_Atspi_Bridge_Data;
struct collection_match_rule {
Efl_Access_State_Set states;
AtspiCollectionMatchType statematchtype;
Eina_List *attributes;
AtspiCollectionMatchType attributematchtype;
uint64_t roles[2];
AtspiCollectionMatchType rolematchtype;
Eina_List *ifaces;
AtspiCollectionMatchType interfacematchtype;
Eina_Bool reverse : 1;
};
static Eo *_instance;
static int _init_count = 0;
// Object Event handlers
static void _state_changed_signal_send(void *data, const Efl_Event *event);
static void _bounds_changed_signal_send(void *data, const Efl_Event *event);
static void _property_changed_signal_send(void *data, const Efl_Event *event);
static void _value_property_changed_signal_send(void *data, const Efl_Event *event);
static void _children_changed_signal_send(void *data, const Efl_Event *event);
static void _window_signal_send(void *data, const Efl_Event *event);
static void _visible_data_changed_signal_send(void *data, const Efl_Event *event);
static void _active_descendant_changed_signal_send(void *data, const Efl_Event *event);
static void _selection_signal_send(void *data, const Efl_Event *event);
static void _text_text_inserted_send(void *data, const Efl_Event *event);
static void _text_text_removed_send(void *data, const Efl_Event *event);
static void _text_caret_moved_send(void *data, const Efl_Event *event);
static void _text_selection_changed_send(void *data, const Efl_Event *event);
// bridge private methods
static void _bridge_object_register(Eo *bridge, Eo *obj);
static void _bridge_object_unregister(Eo *bridge, Eo *obj);
static const char * _path_from_object(const Eo *eo);
static void _bridge_signal_send(Eo *bridge, Eo *obj, const char *ifc, const Eldbus_Signal *signal, const char *minor, unsigned int det1, unsigned int det2, const char *variant_sig, ...);
static Eo * _bridge_object_from_path(Eo *bridge, const char *path);
static void _bridge_iter_object_reference_append(Eo *bridge, Eldbus_Message_Iter *iter, const Eo *obj);
// utility functions
static void _iter_interfaces_append(Eldbus_Message_Iter *iter, const Eo *obj);
static Eina_Bool _elm_atspi_bridge_key_filter(void *data, void *loop, int type, void *event);
static void _object_desktop_reference_append(Eldbus_Message_Iter *iter);
static void _on_object_add(void *data, const Efl_Event *event);
static void _on_object_del(void *data, const Efl_Event *event);
typedef struct {
const Efl_Event_Description *desc;
const Efl_Event_Cb callback;
} Elm_Atspi_Bridge_Event_Handler;
static const Elm_Atspi_Bridge_Event_Handler event_handlers[] = {
{ EFL_ACCESS_OBJECT_EVENT_CHILDREN_CHANGED, _children_changed_signal_send},
{ EFL_ACCESS_OBJECT_EVENT_PROPERTY_CHANGED, _property_changed_signal_send},
{ EFL_ACCESS_OBJECT_EVENT_BOUNDS_CHANGED, _bounds_changed_signal_send},
{ EFL_ACCESS_OBJECT_EVENT_STATE_CHANGED, _state_changed_signal_send},
{ EFL_ACCESS_OBJECT_EVENT_VISIBLE_DATA_CHANGED, _visible_data_changed_signal_send},
{ EFL_ACCESS_OBJECT_EVENT_ACTIVE_DESCENDANT_CHANGED, _active_descendant_changed_signal_send},
{ EFL_ACCESS_OBJECT_EVENT_ADDED, _on_object_add},
{ EFL_ACCESS_OBJECT_EVENT_REMOVED, _on_object_del},
{ EFL_ACCESS_WINDOW_EVENT_WINDOW_CREATED, _window_signal_send},
{ EFL_ACCESS_WINDOW_EVENT_WINDOW_DESTROYED, _window_signal_send},
{ EFL_ACCESS_WINDOW_EVENT_WINDOW_ACTIVATED, _window_signal_send},
{ EFL_ACCESS_WINDOW_EVENT_WINDOW_DEACTIVATED, _window_signal_send},
{ EFL_ACCESS_WINDOW_EVENT_WINDOW_MAXIMIZED, _window_signal_send},
{ EFL_ACCESS_WINDOW_EVENT_WINDOW_MINIMIZED, _window_signal_send},
{ EFL_ACCESS_WINDOW_EVENT_WINDOW_RESTORED, _window_signal_send},
{ EFL_ACCESS_SELECTION_EVENT_ACCESS_SELECTION_CHANGED, _selection_signal_send},
{ EFL_ACCESS_TEXT_EVENT_ACCESS_TEXT_CARET_MOVED, _text_caret_moved_send },
{ EFL_ACCESS_TEXT_EVENT_ACCESS_TEXT_INSERTED, _text_text_inserted_send },
{ EFL_ACCESS_TEXT_EVENT_ACCESS_TEXT_REMOVED, _text_text_removed_send },
{ EFL_ACCESS_TEXT_EVENT_ACCESS_TEXT_SELECTION_CHANGED, _text_selection_changed_send },
{ EFL_UI_RANGE_EVENT_CHANGED, _value_property_changed_signal_send }
};
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,
ATSPI_OBJECT_PROPERTY_LAST
};
enum _Atspi_Object_Signals {
ATSPI_OBJECT_EVENT_PROPERTY_CHANGED = 0,
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 _Atspi_Window_Signals
{
ATSPI_WINDOW_EVENT_PROPERTY_CHANGE = 0,
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] = {"BoundsChanged", ELDBUS_ARGS({"siiv(iiii)", 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},
2015-10-19 04:39:56 -07:00
[ATSPI_OBJECT_EVENT_ACTIVE_DESCENDANT_CHANGED] = {"ActiveDescendantChanged", 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},
2015-06-03 07:58:23 -07:00
[ATSPI_OBJECT_EVENT_TEXT_SELECTION_CHANGED] = {"TextSelectionChanged", ELDBUS_ARGS({"siiv(so)", NULL}), 0},
[ATSPI_OBJECT_EVENT_TEXT_CHANGED] = {"TextChanged", 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},
{NULL, ELDBUS_ARGS({NULL, 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},
{NULL, ELDBUS_ARGS({NULL, NULL}), 0}
};
static const int elm_roles_to_atspi_roles[][2] = {
{ EFL_ACCESS_ROLE_INVALID, ATSPI_ROLE_INVALID },
{ EFL_ACCESS_ROLE_ACCELERATOR_LABEL, ATSPI_ROLE_ACCELERATOR_LABEL },
{ EFL_ACCESS_ROLE_ALERT, ATSPI_ROLE_ALERT },
{ EFL_ACCESS_ROLE_ANIMATION, ATSPI_ROLE_ANIMATION },
{ EFL_ACCESS_ROLE_ARROW, ATSPI_ROLE_ARROW },
{ EFL_ACCESS_ROLE_CALENDAR, ATSPI_ROLE_CALENDAR },
{ EFL_ACCESS_ROLE_CANVAS, ATSPI_ROLE_CANVAS },
{ EFL_ACCESS_ROLE_CHECK_BOX, ATSPI_ROLE_CHECK_BOX },
{ EFL_ACCESS_ROLE_CHECK_MENU_ITEM, ATSPI_ROLE_CHECK_MENU_ITEM },
{ EFL_ACCESS_ROLE_COLOR_CHOOSER, ATSPI_ROLE_COLOR_CHOOSER },
{ EFL_ACCESS_ROLE_COLUMN_HEADER, ATSPI_ROLE_COLUMN_HEADER },
{ EFL_ACCESS_ROLE_COMBO_BOX, ATSPI_ROLE_COMBO_BOX },
{ EFL_ACCESS_ROLE_DATE_EDITOR, ATSPI_ROLE_DATE_EDITOR },
{ EFL_ACCESS_ROLE_DESKTOP_ICON, ATSPI_ROLE_DESKTOP_ICON },
{ EFL_ACCESS_ROLE_DESKTOP_FRAME, ATSPI_ROLE_DESKTOP_FRAME },
{ EFL_ACCESS_ROLE_DIAL, ATSPI_ROLE_DIAL },
{ EFL_ACCESS_ROLE_DIALOG, ATSPI_ROLE_DIALOG },
{ EFL_ACCESS_ROLE_DIRECTORY_PANE, ATSPI_ROLE_DIRECTORY_PANE },
{ EFL_ACCESS_ROLE_DRAWING_AREA, ATSPI_ROLE_DRAWING_AREA },
{ EFL_ACCESS_ROLE_FILE_CHOOSER, ATSPI_ROLE_FILE_CHOOSER },
{ EFL_ACCESS_ROLE_FILLER, ATSPI_ROLE_FILLER },
{ EFL_ACCESS_ROLE_FOCUS_TRAVERSABLE, ATSPI_ROLE_FOCUS_TRAVERSABLE },
{ EFL_ACCESS_ROLE_FONT_CHOOSER, ATSPI_ROLE_FONT_CHOOSER },
{ EFL_ACCESS_ROLE_FRAME, ATSPI_ROLE_FRAME },
{ EFL_ACCESS_ROLE_GLASS_PANE, ATSPI_ROLE_GLASS_PANE },
{ EFL_ACCESS_ROLE_HTML_CONTAINER, ATSPI_ROLE_HTML_CONTAINER },
{ EFL_ACCESS_ROLE_ICON, ATSPI_ROLE_ICON },
{ EFL_ACCESS_ROLE_IMAGE, ATSPI_ROLE_IMAGE },
{ EFL_ACCESS_ROLE_INTERNAL_FRAME, ATSPI_ROLE_INTERNAL_FRAME },
{ EFL_ACCESS_ROLE_LABEL, ATSPI_ROLE_LABEL },
{ EFL_ACCESS_ROLE_LAYERED_PANE, ATSPI_ROLE_LAYERED_PANE },
{ EFL_ACCESS_ROLE_LIST, ATSPI_ROLE_LIST },
{ EFL_ACCESS_ROLE_LIST_ITEM, ATSPI_ROLE_LIST_ITEM },
{ EFL_ACCESS_ROLE_MENU, ATSPI_ROLE_MENU },
{ EFL_ACCESS_ROLE_MENU_BAR, ATSPI_ROLE_MENU_BAR },
{ EFL_ACCESS_ROLE_MENU_ITEM, ATSPI_ROLE_MENU_ITEM },
{ EFL_ACCESS_ROLE_OPTION_PANE, ATSPI_ROLE_OPTION_PANE },
{ EFL_ACCESS_ROLE_PAGE_TAB, ATSPI_ROLE_PAGE_TAB },
{ EFL_ACCESS_ROLE_PAGE_TAB_LIST, ATSPI_ROLE_PAGE_TAB_LIST },
{ EFL_ACCESS_ROLE_PANEL, ATSPI_ROLE_PANEL },
{ EFL_ACCESS_ROLE_PASSWORD_TEXT, ATSPI_ROLE_PASSWORD_TEXT },
{ EFL_ACCESS_ROLE_POPUP_MENU, ATSPI_ROLE_POPUP_MENU },
{ EFL_ACCESS_ROLE_PROGRESS_BAR, ATSPI_ROLE_PROGRESS_BAR },
{ EFL_ACCESS_ROLE_PUSH_BUTTON, ATSPI_ROLE_PUSH_BUTTON },
{ EFL_ACCESS_ROLE_RADIO_BUTTON, ATSPI_ROLE_RADIO_BUTTON },
{ EFL_ACCESS_ROLE_RADIO_MENU_ITEM, ATSPI_ROLE_RADIO_MENU_ITEM },
{ EFL_ACCESS_ROLE_ROOT_PANE, ATSPI_ROLE_ROOT_PANE },
{ EFL_ACCESS_ROLE_ROW_HEADER, ATSPI_ROLE_ROW_HEADER },
{ EFL_ACCESS_ROLE_SCROLL_BAR, ATSPI_ROLE_SCROLL_BAR },
{ EFL_ACCESS_ROLE_SCROLL_PANE, ATSPI_ROLE_SCROLL_PANE },
{ EFL_ACCESS_ROLE_SEPARATOR, ATSPI_ROLE_SEPARATOR },
{ EFL_ACCESS_ROLE_SLIDER, ATSPI_ROLE_SLIDER },
{ EFL_ACCESS_ROLE_SPIN_BUTTON, ATSPI_ROLE_SPIN_BUTTON },
{ EFL_ACCESS_ROLE_SPLIT_PANE, ATSPI_ROLE_SPLIT_PANE },
{ EFL_ACCESS_ROLE_STATUS_BAR, ATSPI_ROLE_STATUS_BAR },
{ EFL_ACCESS_ROLE_TABLE, ATSPI_ROLE_TABLE },
{ EFL_ACCESS_ROLE_TABLE_CELL, ATSPI_ROLE_TABLE_CELL },
{ EFL_ACCESS_ROLE_TABLE_COLUMN_HEADER, ATSPI_ROLE_TABLE_COLUMN_HEADER },
{ EFL_ACCESS_ROLE_TABLE_ROW_HEADER, ATSPI_ROLE_TABLE_ROW_HEADER },
{ EFL_ACCESS_ROLE_TEAROFF_MENU_ITEM, ATSPI_ROLE_TEAROFF_MENU_ITEM },
{ EFL_ACCESS_ROLE_TERMINAL, ATSPI_ROLE_TERMINAL },
{ EFL_ACCESS_ROLE_TEXT, ATSPI_ROLE_TEXT },
{ EFL_ACCESS_ROLE_TOGGLE_BUTTON, ATSPI_ROLE_TOGGLE_BUTTON },
{ EFL_ACCESS_ROLE_TOOL_BAR, ATSPI_ROLE_TOOL_BAR },
{ EFL_ACCESS_ROLE_TOOL_TIP, ATSPI_ROLE_TOOL_TIP },
{ EFL_ACCESS_ROLE_TREE, ATSPI_ROLE_TREE },
{ EFL_ACCESS_ROLE_TREE_TABLE, ATSPI_ROLE_TREE_TABLE },
{ EFL_ACCESS_ROLE_UNKNOWN, ATSPI_ROLE_UNKNOWN },
{ EFL_ACCESS_ROLE_VIEWPORT, ATSPI_ROLE_VIEWPORT },
{ EFL_ACCESS_ROLE_WINDOW, ATSPI_ROLE_WINDOW },
{ EFL_ACCESS_ROLE_EXTENDED, ATSPI_ROLE_EXTENDED },
{ EFL_ACCESS_ROLE_HEADER, ATSPI_ROLE_HEADER },
{ EFL_ACCESS_ROLE_FOOTER, ATSPI_ROLE_FOOTER },
{ EFL_ACCESS_ROLE_PARAGRAPH, ATSPI_ROLE_PARAGRAPH },
{ EFL_ACCESS_ROLE_RULER, ATSPI_ROLE_RULER },
{ EFL_ACCESS_ROLE_APPLICATION, ATSPI_ROLE_APPLICATION },
{ EFL_ACCESS_ROLE_AUTOCOMPLETE, ATSPI_ROLE_AUTOCOMPLETE },
{ EFL_ACCESS_ROLE_EDITBAR, ATSPI_ROLE_EDITBAR },
{ EFL_ACCESS_ROLE_EMBEDDED, ATSPI_ROLE_EMBEDDED },
{ EFL_ACCESS_ROLE_ENTRY, ATSPI_ROLE_ENTRY },
{ EFL_ACCESS_ROLE_CHART, ATSPI_ROLE_CHART },
{ EFL_ACCESS_ROLE_CAPTION, ATSPI_ROLE_CAPTION },
{ EFL_ACCESS_ROLE_DOCUMENT_FRAME, ATSPI_ROLE_DOCUMENT_FRAME },
{ EFL_ACCESS_ROLE_HEADING, ATSPI_ROLE_HEADING },
{ EFL_ACCESS_ROLE_PAGE, ATSPI_ROLE_PAGE },
{ EFL_ACCESS_ROLE_SECTION, ATSPI_ROLE_SECTION },
{ EFL_ACCESS_ROLE_REDUNDANT_OBJECT, ATSPI_ROLE_REDUNDANT_OBJECT },
{ EFL_ACCESS_ROLE_FORM, ATSPI_ROLE_FORM },
{ EFL_ACCESS_ROLE_LINK, ATSPI_ROLE_LINK },
{ EFL_ACCESS_ROLE_INPUT_METHOD_WINDOW, ATSPI_ROLE_INPUT_METHOD_WINDOW },
{ EFL_ACCESS_ROLE_TABLE_ROW, ATSPI_ROLE_TABLE_ROW },
{ EFL_ACCESS_ROLE_TREE_ITEM, ATSPI_ROLE_TREE_ITEM },
{ EFL_ACCESS_ROLE_DOCUMENT_SPREADSHEET, ATSPI_ROLE_DOCUMENT_SPREADSHEET },
{ EFL_ACCESS_ROLE_DOCUMENT_PRESENTATION, ATSPI_ROLE_DOCUMENT_PRESENTATION },
{ EFL_ACCESS_ROLE_DOCUMENT_TEXT, ATSPI_ROLE_DOCUMENT_TEXT },
{ EFL_ACCESS_ROLE_DOCUMENT_WEB, ATSPI_ROLE_DOCUMENT_WEB },
{ EFL_ACCESS_ROLE_DOCUMENT_EMAIL, ATSPI_ROLE_DOCUMENT_EMAIL },
{ EFL_ACCESS_ROLE_COMMENT, ATSPI_ROLE_COMMENT },
{ EFL_ACCESS_ROLE_LIST_BOX, ATSPI_ROLE_LIST_BOX },
{ EFL_ACCESS_ROLE_GROUPING, ATSPI_ROLE_GROUPING },
{ EFL_ACCESS_ROLE_IMAGE_MAP, ATSPI_ROLE_IMAGE_MAP },
{ EFL_ACCESS_ROLE_NOTIFICATION, ATSPI_ROLE_NOTIFICATION },
{ EFL_ACCESS_ROLE_INFO_BAR, ATSPI_ROLE_INFO_BAR },
{ EFL_ACCESS_ROLE_LAST_DEFINED, ATSPI_ROLE_LAST_DEFINED },
};
2015-07-06 14:32:35 -07:00
struct atspi_state_desc
{
Efl_Access_State_Type elm_state;
2015-07-06 14:32:35 -07:00
AtspiStateType atspi_state;
const char *name;
};
static const struct atspi_state_desc elm_states_to_atspi_state[] = {
{ EFL_ACCESS_STATE_TYPE_INVALID, ATSPI_STATE_INVALID, "invalid" },
{ EFL_ACCESS_STATE_TYPE_ACTIVE, ATSPI_STATE_ACTIVE, "active" },
{ EFL_ACCESS_STATE_TYPE_ARMED, ATSPI_STATE_ARMED, "armed" },
{ EFL_ACCESS_STATE_TYPE_BUSY, ATSPI_STATE_BUSY, "busy" },
{ EFL_ACCESS_STATE_TYPE_CHECKED, ATSPI_STATE_CHECKED, "checked" },
{ EFL_ACCESS_STATE_TYPE_COLLAPSED, ATSPI_STATE_COLLAPSED, "collapsed" },
{ EFL_ACCESS_STATE_TYPE_DEFUNCT, ATSPI_STATE_DEFUNCT, "defunct" },
{ EFL_ACCESS_STATE_TYPE_EDITABLE, ATSPI_STATE_EDITABLE, "editable" },
{ EFL_ACCESS_STATE_TYPE_ENABLED, ATSPI_STATE_ENABLED, "enabled" },
{ EFL_ACCESS_STATE_TYPE_EXPANDABLE, ATSPI_STATE_EXPANDABLE, "expandable" },
{ EFL_ACCESS_STATE_TYPE_EXPANDED, ATSPI_STATE_EXPANDED, "expanded" },
{ EFL_ACCESS_STATE_TYPE_FOCUSABLE, ATSPI_STATE_FOCUSABLE, "focusable" },
{ EFL_ACCESS_STATE_TYPE_FOCUSED, ATSPI_STATE_FOCUSED, "focused" },
{ EFL_ACCESS_STATE_TYPE_HAS_TOOLTIP, ATSPI_STATE_HAS_TOOLTIP, "has-tooltip" },
{ EFL_ACCESS_STATE_TYPE_HORIZONTAL, ATSPI_STATE_HORIZONTAL, "horizontal" },
{ EFL_ACCESS_STATE_TYPE_MINIMIZED, ATSPI_STATE_ICONIFIED, "minimized" },
{ EFL_ACCESS_STATE_TYPE_MODAL, ATSPI_STATE_MODAL, "modal" },
{ EFL_ACCESS_STATE_TYPE_MULTI_LINE, ATSPI_STATE_MULTI_LINE, "multi-line" },
{ EFL_ACCESS_STATE_TYPE_MULTISELECTABLE, ATSPI_STATE_MULTISELECTABLE, "multiselectable" },
{ EFL_ACCESS_STATE_TYPE_OPAQUE, ATSPI_STATE_OPAQUE, "opaque" },
{ EFL_ACCESS_STATE_TYPE_PRESSED, ATSPI_STATE_PRESSED, "pressed" },
{ EFL_ACCESS_STATE_TYPE_RESIZABLE, ATSPI_STATE_RESIZABLE, "resizable" },
{ EFL_ACCESS_STATE_TYPE_SELECTABLE, ATSPI_STATE_SELECTABLE, "selectable" },
{ EFL_ACCESS_STATE_TYPE_SELECTED, ATSPI_STATE_SELECTED, "selected" },
{ EFL_ACCESS_STATE_TYPE_SENSITIVE, ATSPI_STATE_SENSITIVE, "sensitive" },
{ EFL_ACCESS_STATE_TYPE_SHOWING, ATSPI_STATE_SHOWING, "showing" },
{ EFL_ACCESS_STATE_TYPE_SINGLE_LINE, ATSPI_STATE_SINGLE_LINE, "single-line" },
{ EFL_ACCESS_STATE_TYPE_STALE, ATSPI_STATE_STALE, "stale" },
{ EFL_ACCESS_STATE_TYPE_TRANSIENT, ATSPI_STATE_TRANSIENT, "transient" },
{ EFL_ACCESS_STATE_TYPE_VERTICAL, ATSPI_STATE_VERTICAL, "vertical" },
{ EFL_ACCESS_STATE_TYPE_VISIBLE, ATSPI_STATE_VISIBLE, "visible" },
{ EFL_ACCESS_STATE_TYPE_MANAGES_DESCENDANTS, ATSPI_STATE_MANAGES_DESCENDANTS, "manages-descendants" },
{ EFL_ACCESS_STATE_TYPE_INDETERMINATE, ATSPI_STATE_INDETERMINATE, "indeterminate" },
{ EFL_ACCESS_STATE_TYPE_REQUIRED, ATSPI_STATE_REQUIRED, "required" },
{ EFL_ACCESS_STATE_TYPE_TRUNCATED, ATSPI_STATE_TRUNCATED, "truncated" },
{ EFL_ACCESS_STATE_TYPE_ANIMATED, ATSPI_STATE_ANIMATED, "animated" },
{ EFL_ACCESS_STATE_TYPE_INVALID_ENTRY, ATSPI_STATE_INVALID_ENTRY, "invalid-entry" },
{ EFL_ACCESS_STATE_TYPE_SUPPORTS_AUTOCOMPLETION, ATSPI_STATE_SUPPORTS_AUTOCOMPLETION, "supports-autocompletion" },
{ EFL_ACCESS_STATE_TYPE_SELECTABLE_TEXT, ATSPI_STATE_SELECTABLE_TEXT, "selectable-text" },
{ EFL_ACCESS_STATE_TYPE_IS_DEFAULT, ATSPI_STATE_IS_DEFAULT, "is-default" },
{ EFL_ACCESS_STATE_TYPE_VISITED, ATSPI_STATE_VISITED, "visited" },
{ EFL_ACCESS_STATE_TYPE_LAST_DEFINED, ATSPI_STATE_LAST_DEFINED, "last-defined" },
};
static const int elm_relation_to_atspi_relation_mapping[] = {
[EFL_ACCESS_RELATION_TYPE_NULL] = ATSPI_RELATION_NULL,
[EFL_ACCESS_RELATION_TYPE_LABEL_FOR] = ATSPI_RELATION_LABEL_FOR,
[EFL_ACCESS_RELATION_TYPE_LABELLED_BY] = ATSPI_RELATION_LABELLED_BY,
[EFL_ACCESS_RELATION_TYPE_CONTROLLER_FOR] = ATSPI_RELATION_CONTROLLER_FOR,
[EFL_ACCESS_RELATION_TYPE_CONTROLLED_BY] = ATSPI_RELATION_CONTROLLED_BY,
[EFL_ACCESS_RELATION_TYPE_MEMBER_OF] = ATSPI_RELATION_MEMBER_OF,
[EFL_ACCESS_RELATION_TYPE_TOOLTIP_FOR] = ATSPI_RELATION_TOOLTIP_FOR,
[EFL_ACCESS_RELATION_TYPE_NODE_CHILD_OF] = ATSPI_RELATION_NODE_CHILD_OF,
[EFL_ACCESS_RELATION_TYPE_NODE_PARENT_OF] = ATSPI_RELATION_NODE_PARENT_OF,
[EFL_ACCESS_RELATION_TYPE_EXTENDED] = ATSPI_RELATION_EXTENDED,
[EFL_ACCESS_RELATION_TYPE_FLOWS_TO] = ATSPI_RELATION_FLOWS_TO,
[EFL_ACCESS_RELATION_TYPE_FLOWS_FROM] = ATSPI_RELATION_FLOWS_FROM,
[EFL_ACCESS_RELATION_TYPE_SUBWINDOW_OF] = ATSPI_RELATION_SUBWINDOW_OF,
[EFL_ACCESS_RELATION_TYPE_EMBEDS] = ATSPI_RELATION_EMBEDS,
[EFL_ACCESS_RELATION_TYPE_EMBEDDED_BY] = ATSPI_RELATION_EMBEDDED_BY,
[EFL_ACCESS_RELATION_TYPE_POPUP_FOR] = ATSPI_RELATION_POPUP_FOR,
[EFL_ACCESS_RELATION_TYPE_PARENT_WINDOW_OF] = ATSPI_RELATION_PARENT_WINDOW_OF,
[EFL_ACCESS_RELATION_TYPE_DESCRIPTION_FOR] = ATSPI_RELATION_DESCRIPTION_FOR,
[EFL_ACCESS_RELATION_TYPE_DESCRIBED_BY] = ATSPI_RELATION_DESCRIBED_BY,
[EFL_ACCESS_RELATION_TYPE_LAST_DEFINED] = ATSPI_RELATION_LAST_DEFINED,
};
static inline Eldbus_Message *_dbus_invalid_ref_error_new(const Eldbus_Message *msg)
{
return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.UnknownObject", "Path is not valid accessible object reference.");
}
static AtspiRelationType _elm_relation_to_atspi_relation(Efl_Access_Relation_Type type)
{
if ((type < EFL_ACCESS_RELATION_TYPE_LAST_DEFINED) && (type > EFL_ACCESS_RELATION_TYPE_NULL))
return elm_relation_to_atspi_relation_mapping[type];
2015-07-29 07:21:17 -07:00
return ATSPI_RELATION_NULL;
}
static Eldbus_Message *
_accessible_get_role(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
{
const char *obj_path = eldbus_message_path_get(msg);
Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
Eo *obj = _bridge_object_from_path(bridge, obj_path);
AtspiRole atspi_role = ATSPI_ROLE_INVALID;
Efl_Access_Role role;
ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_OBJECT_MIXIN, msg);
role = efl_access_object_role_get(obj);
Eldbus_Message *ret = eldbus_message_method_return_new(msg);
EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
atspi_role = role > EFL_ACCESS_ROLE_LAST_DEFINED ? ATSPI_ROLE_LAST_DEFINED : elm_roles_to_atspi_roles[role][1];
eldbus_message_arguments_append(ret, "u", atspi_role);
return ret;
}
static Eldbus_Message *
_accessible_get_role_name(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
{
const char *role_name = NULL, *obj_path = eldbus_message_path_get(msg);
Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
Eo *obj = _bridge_object_from_path(bridge, obj_path);
ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_OBJECT_MIXIN, msg);
role_name = efl_access_object_role_name_get(obj);
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, const Eldbus_Message *msg)
{
const char *l_role_name = NULL, *obj_path = eldbus_message_path_get(msg);
Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
Eo *obj = _bridge_object_from_path(bridge, obj_path);
ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_OBJECT_MIXIN, msg);
l_role_name = efl_access_object_localized_role_name_get(obj);
EINA_SAFETY_ON_NULL_RETURN_VAL(l_role_name, NULL);
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, const Eldbus_Message *msg)
{
const char *obj_path = eldbus_message_path_get(msg);
Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
Eo *obj = _bridge_object_from_path(bridge, obj_path);
Eina_List *children_list = NULL, *l;
Eldbus_Message *ret;
Eldbus_Message_Iter *iter, *iter_array;
Eo *children;
ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_OBJECT_MIXIN, msg);
children_list = efl_access_object_access_children_get(obj);
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)
{
_bridge_iter_object_reference_append(bridge, iter_array, children);
_bridge_object_register(bridge, 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, const Eldbus_Message *msg)
{
Eldbus_Message *ret;
const char *obj_path = eldbus_message_path_get(msg);
Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
Eo *root, *obj = _bridge_object_from_path(bridge, obj_path);
ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_OBJECT_MIXIN, msg);
ret = eldbus_message_method_return_new(msg);
EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
Eldbus_Message_Iter *iter = eldbus_message_iter_get(ret);
root = efl_access_object_access_root_get();
_bridge_iter_object_reference_append(bridge, iter, root);
return ret;
}
static Eldbus_Message *
_accessible_attributes_get(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
{
Eina_List *attrs = NULL, *l;
Efl_Access_Attribute *attr;
Eldbus_Message_Iter *iter, *iter_dict = NULL, *iter_entry;
Eldbus_Message *ret;
const char *obj_path = eldbus_message_path_get(msg);
Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
Eo *obj = _bridge_object_from_path(bridge, obj_path);
ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_OBJECT_MIXIN, msg);
ret = eldbus_message_method_return_new(msg);
if (!ret) goto error;
attrs = efl_access_object_attributes_get(obj);
iter = eldbus_message_iter_get(ret);
if (!iter) goto error;
iter_dict = eldbus_message_iter_container_new(iter, 'a', "{ss}");
if (!iter_dict) goto error;
EINA_LIST_FOREACH(attrs, l, attr)
{
iter_entry = eldbus_message_iter_container_new(iter_dict, 'e', NULL);
if (!iter_entry) goto error;
eldbus_message_iter_arguments_append(iter_entry, "ss", attr->key, attr->value);
eldbus_message_iter_container_close(iter_dict, iter_entry);
}
eldbus_message_iter_container_close(iter, iter_dict);
efl_access_attributes_list_free(attrs);
return ret;
error:
if (iter_dict) eldbus_message_iter_container_close(iter, iter_dict);
if (ret) eldbus_message_unref(ret);
efl_access_attributes_list_free(attrs);
return NULL;
}
static Eldbus_Message *
_accessible_interfaces_get(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
{
Eldbus_Message *ret;
Eldbus_Message_Iter *iter;
const char *obj_path = eldbus_message_path_get(msg);
Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
Eo *obj = _bridge_object_from_path(bridge, obj_path);
ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_OBJECT_MIXIN, msg);
ret = eldbus_message_method_return_new(msg);
EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
iter = eldbus_message_iter_get(ret);
_iter_interfaces_append(iter, obj);
return ret;
}
static uint64_t
_elm_atspi_state_set_to_atspi_state_set(Efl_Access_State_Set states)
{
uint64_t ret = 0;
unsigned int i = 0;
for (i = 0; i < SIZE(elm_states_to_atspi_state); i++)
{
2015-07-06 14:32:35 -07:00
if (STATE_TYPE_GET(states, elm_states_to_atspi_state[i].elm_state))
STATE_TYPE_SET(ret, elm_states_to_atspi_state[i].atspi_state);
}
return ret;
}
static Efl_Access_State_Set
_atspi_state_set_to_elm_atspi_state_set(uint64_t states)
{
//Currently Elm_Atspi_State and Atspi_State_Set are binary compatible,
//implement proper coversion when it will be needed.
Efl_Access_State_Set ret = states;
return ret;
}
2015-07-06 14:32:35 -07:00
static Eina_Hash*
_elm_atspi_state_hash_build(void)
{
Eina_Hash *ret = eina_hash_string_superfast_new(NULL);
unsigned int i = 0;
for (i = 0; i < SIZE(elm_states_to_atspi_state); i++)
eina_hash_add(ret, elm_states_to_atspi_state[i].name, &elm_states_to_atspi_state[i]);
return ret;
}
static Eina_Hash*
_elm_atspi_event_hash_build(void)
{
Eina_Hash *ret = eina_hash_pointer_new(NULL);
unsigned int i = 0;
for (i = 0; i < SIZE(event_handlers); i++)
eina_hash_add(ret, &(event_handlers[i].desc), event_handlers[i].callback);
return ret;
}
static Eldbus_Message *
_accessible_get_state(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
{
Eldbus_Message *ret;
Eldbus_Message_Iter *iter, *iter_array;
Efl_Access_State_Set states;
uint64_t atspi_states = 0;
const char *obj_path = eldbus_message_path_get(msg);
Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
Eo *obj = _bridge_object_from_path(bridge, obj_path);
ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_OBJECT_MIXIN, msg);
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");
EINA_SAFETY_ON_NULL_GOTO(iter_array, fail);
states = efl_access_object_state_set_get(obj);
atspi_states = _elm_atspi_state_set_to_atspi_state_set(states);
unsigned int s1 = atspi_states & 0xFFFFFFFF;
unsigned int s2 = (atspi_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 *
_accessible_get_index_in_parent(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg)
{
const char *obj_path = eldbus_message_path_get(msg);
Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
Eo *obj = _bridge_object_from_path(bridge, obj_path);
Eldbus_Message *ret;
int idx = -1;
ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_OBJECT_MIXIN, msg);
ret = eldbus_message_method_return_new(msg);
EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
idx = efl_access_object_index_in_parent_get(obj);
eldbus_message_arguments_append(ret, "i", idx);
return ret;
}
static Eldbus_Message *
_accessible_child_at_index(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg)
{
const char *obj_path = eldbus_message_path_get(msg);
Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
Eo *obj = _bridge_object_from_path(bridge, obj_path);
Eo *child = NULL;
Eina_List *children = NULL;
int idx;
Eldbus_Message *ret;
Eldbus_Message_Iter *iter;
ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_OBJECT_MIXIN, msg);
if (!eldbus_message_arguments_get(msg, "i", &idx))
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);
children = efl_access_object_access_children_get(obj);
child = eina_list_nth(children, idx);
_bridge_iter_object_reference_append(bridge, iter, child);
_bridge_object_register(bridge, child);
eina_list_free(children);
return ret;
}
static Eldbus_Message *
_accessible_get_relation_set(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg)
{
const char *obj_path = eldbus_message_path_get(msg);
Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
Eo *rel_obj, *obj = _bridge_object_from_path(bridge, obj_path);
Eldbus_Message *ret = NULL;
Eldbus_Message_Iter *iter = NULL, *iter_array = NULL, *iter_array2 = NULL, *iter_struct;
const Efl_Access_Relation *rel;
Eina_List *l;
Eina_Iterator *it;
ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_OBJECT_MIXIN, msg);
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', "(ua(so))");
EINA_SAFETY_ON_NULL_GOTO(iter_array, fail);
it = efl_access_object_relations_get(obj);
EINA_ITERATOR_FOREACH(it, rel)
{
iter_struct = eldbus_message_iter_container_new(iter_array, 'r', NULL);
eldbus_message_iter_basic_append(iter_struct, 'u', _elm_relation_to_atspi_relation(rel->type));
iter_array2 = eldbus_message_iter_container_new(iter_struct, 'a', "(so)");
EINA_SAFETY_ON_NULL_GOTO(iter_array2, fail);
EINA_LIST_FOREACH(rel->objects, l, rel_obj)
{
_bridge_iter_object_reference_append(bridge, iter_array2, rel_obj);
_bridge_object_register(bridge, rel_obj);
}
eldbus_message_iter_container_close(iter_struct, iter_array2);
eldbus_message_iter_container_close(iter_array, iter_struct);
}
eina_iterator_free(it);
eldbus_message_iter_container_close(iter, iter_array);
return ret;
fail:
eldbus_message_unref(ret);
return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.Failed", "Unable to get relation set.");
}
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_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},
{ "GetState", NULL, ELDBUS_ARGS({"au", NULL}), _accessible_get_state, 0},
{ "GetApplication", NULL, ELDBUS_ARGS({"(so)", NULL}), _accessible_get_application, 0},
{ "GetAttributes", NULL, ELDBUS_ARGS({"a{ss}", NULL}), _accessible_attributes_get, 0},
{ "GetInterfaces", NULL, ELDBUS_ARGS({"as", NULL}), _accessible_interfaces_get, 0},
{ NULL, NULL, NULL, NULL, 0 }
};
static Eldbus_Message *
_selection_selected_child_get(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg)
{
const char *obj_path = eldbus_message_path_get(msg);
Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
Eo *obj = _bridge_object_from_path(bridge, obj_path);
Eo *child = NULL;
int idx;
Eldbus_Message *ret;
Eldbus_Message_Iter *iter;
ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_SELECTION_INTERFACE, msg);
if (!eldbus_message_arguments_get(msg, "i", &idx))
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);
child = efl_access_selection_selected_child_get(obj, idx);
_bridge_iter_object_reference_append(bridge, iter, child);
_bridge_object_register(bridge, child);
return ret;
}
static Eldbus_Message *
_selection_child_select(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
{
const char *obj_path = eldbus_message_path_get(msg);
Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
Eo *obj = _bridge_object_from_path(bridge, obj_path);
int idx;
Eldbus_Message *ret;
Eina_Bool result;
ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_SELECTION_INTERFACE, msg);
if (!eldbus_message_arguments_get(msg, "i", &idx))
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);
result = efl_access_selection_child_select(obj, idx);
eldbus_message_arguments_append(ret, "b", result);
return ret;
}
static Eldbus_Message *
_selection_selected_child_deselect(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
{
const char *obj_path = eldbus_message_path_get(msg);
Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
Eo *obj = _bridge_object_from_path(bridge, obj_path);
int idx;
Eldbus_Message *ret;
Eina_Bool result;
ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_SELECTION_INTERFACE, msg);
if (!eldbus_message_arguments_get(msg, "i", &idx))
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);
result = efl_access_selection_selected_child_deselect(obj, idx);
eldbus_message_arguments_append(ret, "b", result);
return ret;
}
static Eldbus_Message *
_selection_is_child_selected(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
{
const char *obj_path = eldbus_message_path_get(msg);
Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
Eo *obj = _bridge_object_from_path(bridge, obj_path);
int idx;
Eldbus_Message *ret;
Eina_Bool result;
ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_SELECTION_INTERFACE, msg);
if (!eldbus_message_arguments_get(msg, "i", &idx))
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);
result = efl_access_selection_is_child_selected(obj, idx);
eldbus_message_arguments_append(ret, "b", result);
return ret;
}
static Eldbus_Message *
_selection_all_children_select(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
{
const char *obj_path = eldbus_message_path_get(msg);
Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
Eo *obj = _bridge_object_from_path(bridge, obj_path);
Eldbus_Message *ret;
Eina_Bool result;
ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_SELECTION_INTERFACE, msg);
ret = eldbus_message_method_return_new(msg);
EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
result = efl_access_selection_all_children_select(obj);
eldbus_message_arguments_append(ret, "b", result);
return ret;
}
static Eldbus_Message *
_selection_clear(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
{
const char *obj_path = eldbus_message_path_get(msg);
Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
Eo *obj = _bridge_object_from_path(bridge, obj_path);
Eldbus_Message *ret;
Eina_Bool result;
ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_SELECTION_INTERFACE, msg);
ret = eldbus_message_method_return_new(msg);
EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
result = efl_access_selection_clear(obj);
eldbus_message_arguments_append(ret, "b", result);
return ret;
}
static Eldbus_Message *
_selection_child_deselect(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
{
const char *obj_path = eldbus_message_path_get(msg);
Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
Eo *obj = _bridge_object_from_path(bridge, obj_path);
int idx;
Eldbus_Message *ret;
Eina_Bool result;
ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_SELECTION_INTERFACE, msg);
if (!eldbus_message_arguments_get(msg, "i", &idx))
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);
result = efl_access_selection_child_deselect(obj, idx);
eldbus_message_arguments_append(ret, "b", result);
return ret;
}
static const Eldbus_Method selection_methods[] = {
{ "GetSelectedChild", ELDBUS_ARGS({"i", "selectedChildIndex"}), ELDBUS_ARGS({"(so)", "Accessible"}), _selection_selected_child_get, 0 },
{ "SelectChild", ELDBUS_ARGS({"i", "childIndex"}), ELDBUS_ARGS({"b", "result"}), _selection_child_select, 0 },
{ "DeselectSelectedChild", ELDBUS_ARGS({"i", "selectedChildIndex"}), ELDBUS_ARGS({"b", "result"}), _selection_selected_child_deselect, 0 },
{ "IsChildSelected", ELDBUS_ARGS({"i", "childIndex"}), ELDBUS_ARGS({"b", "result"}), _selection_is_child_selected, 0 },
{ "SelectAll", NULL, ELDBUS_ARGS({"b", "result"}), _selection_all_children_select, 0},
{ "ClearSelection", NULL, ELDBUS_ARGS({"b", "result"}), _selection_clear, 0},
{ "DeselectChild", ELDBUS_ARGS({"i", "childIndex"}), ELDBUS_ARGS({"b", "result"}), _selection_child_deselect, 0 },
{ NULL, NULL, NULL, NULL, 0 }
};
static Eldbus_Message *
_action_description_get(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
{
const char *description, *obj_path = eldbus_message_path_get(msg);
Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
Eo *obj = _bridge_object_from_path(bridge, obj_path);
int idx;
Eldbus_Message *ret;
ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_ACTION_MIXIN, msg);
if (!eldbus_message_arguments_get(msg, "i", &idx))
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);
description = efl_access_action_description_get(obj, idx);
description = description ? description : "";
eldbus_message_arguments_append(ret, "s", description);
return ret;
}
static Eldbus_Message *
_action_name_get(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
{
const char *name, *obj_path = eldbus_message_path_get(msg);
Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
Eo *obj = _bridge_object_from_path(bridge, obj_path);
int idx;
Eldbus_Message *ret;
ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_ACTION_MIXIN, msg);
if (!eldbus_message_arguments_get(msg, "i", &idx))
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);
name = efl_access_action_name_get(obj, idx);
name = name ? name : "";
eldbus_message_arguments_append(ret, "s", name);
return ret;
}
static Eldbus_Message *
_action_localized_name_get(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
{
const char *name, *obj_path = eldbus_message_path_get(msg);
Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
Eo *obj = _bridge_object_from_path(bridge, obj_path);
int idx;
Eldbus_Message *ret;
ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_ACTION_MIXIN, msg);
if (!eldbus_message_arguments_get(msg, "i", &idx))
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);
name = efl_access_action_localized_name_get(obj, idx);
name = name ? name : "";
eldbus_message_arguments_append(ret, "s", name);
return ret;
}
static Eldbus_Message *
_action_key_binding_get(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
{
const char *obj_path = eldbus_message_path_get(msg);
char *key;
Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
Eo *obj = _bridge_object_from_path(bridge, obj_path);
int idx;
Eldbus_Message *ret;
ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_ACTION_MIXIN, msg);
if (!eldbus_message_arguments_get(msg, "i", &idx))
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);
key = efl_access_action_keybinding_get(obj, idx);
eldbus_message_arguments_append(ret, "s", key ? key : "");
if (key) free(key);
return ret;
}
static Eldbus_Message *
_action_actions_get(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
{
const char *action, *obj_path = eldbus_message_path_get(msg);
Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
Eo *obj = _bridge_object_from_path(bridge, obj_path);
Eina_List *actions;
Eldbus_Message *ret;
Eldbus_Message_Iter *iter, *iter_array = NULL;
ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_ACTION_MIXIN, msg);
ret = eldbus_message_method_return_new(msg);
if (!ret) goto error;
iter = eldbus_message_iter_get(ret);
if (!iter) goto error;
iter_array = eldbus_message_iter_container_new(iter, 'a', "sss");
if (!iter_array) goto error;
actions = efl_access_action_actions_get(obj);
int id = 0;
EINA_LIST_FREE(actions, action)
{
const char *descr;
char *key;
key = efl_access_action_keybinding_get(obj, id);
descr = efl_access_action_description_get(obj, id);
descr = descr ? descr : "";
eldbus_message_iter_arguments_append(iter_array, "sss", action, descr, key ? key : "");
if (key) free(key);
id++;
}
eldbus_message_iter_container_close(iter, iter_array);
return ret;
error:
if (ret) eldbus_message_unref(ret);
return NULL;
}
static Eldbus_Message *
_action_action_do(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
{
const char *obj_path = eldbus_message_path_get(msg);
Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
Eo *obj = _bridge_object_from_path(bridge, obj_path);
int idx;
Eldbus_Message *ret;
Eina_Bool result;
ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_ACTION_MIXIN, msg);
if (!eldbus_message_arguments_get(msg, "i", &idx))
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);
result = efl_access_action_do(obj, idx);
eldbus_message_arguments_append(ret, "b", result);
return ret;
}
static const Eldbus_Method action_methods[] = {
{ "GetDescription", ELDBUS_ARGS({"i", "index"}), ELDBUS_ARGS({"s", "description"}), _action_description_get, 0 },
{ "GetName", ELDBUS_ARGS({"i", "index"}), ELDBUS_ARGS({"s", "name"}), _action_name_get, 0 },
{ "GetLocalizedName", ELDBUS_ARGS({"i", "index"}), ELDBUS_ARGS({"s", "name"}), _action_localized_name_get, 0 },
{ "GetKeyBinding", ELDBUS_ARGS({"i", "index"}), ELDBUS_ARGS({"s", "key"}), _action_key_binding_get, 0 },
{ "GetActions", NULL, ELDBUS_ARGS({"a(sss)", "actions"}), _action_actions_get, 0 },
{ "DoAction", ELDBUS_ARGS({"i", "index"}), ELDBUS_ARGS({"b", "result"}), _action_action_do, 0 },
{ NULL, NULL, NULL, NULL, 0 }
};
static Eldbus_Message *
_image_extents_get(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
{
AtspiCoordType type;
Eldbus_Message *ret;
const char *obj_path = eldbus_message_path_get(msg);
Eina_Bool screen_coords;
Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
Eo *obj = _bridge_object_from_path(bridge, obj_path);
Eina_Rect r;
ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_OBJECT_MIXIN, msg);
if (!eldbus_message_arguments_get(msg, "u", &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);
screen_coords = type == ATSPI_COORD_TYPE_SCREEN ? EINA_TRUE : EINA_FALSE;
r = efl_access_component_extents_get(obj, screen_coords);
eldbus_message_arguments_append(ret, "iiii", r.x, r.y, r.w, r.h);
return ret;
}
static Eldbus_Message *
_image_position_get(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
{
AtspiCoordType type;
Eldbus_Message *ret;
const char *obj_path = eldbus_message_path_get(msg);
Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
Eo *obj = _bridge_object_from_path(bridge, obj_path);
int x = -1, y = -1;
Eina_Bool screen_coords;
ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_OBJECT_MIXIN, msg);
if (!eldbus_message_arguments_get(msg, "u", &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);
screen_coords = type == ATSPI_COORD_TYPE_SCREEN ? EINA_TRUE : EINA_FALSE;
if (screen_coords)
efl_access_component_screen_position_get(obj, &x, &y);
else
evas_object_geometry_get(obj, &x, &y, NULL, NULL);
eldbus_message_arguments_append(ret, "i", x);
eldbus_message_arguments_append(ret, "i", y);
return ret;
}
static Eldbus_Message *
_image_size_get(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
{
Eldbus_Message *ret;
const char *obj_path = eldbus_message_path_get(msg);
Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
Eo *obj = _bridge_object_from_path(bridge, obj_path);
int w = -1, h = -1;
ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_OBJECT_MIXIN, msg);
ret = eldbus_message_method_return_new(msg);
EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
evas_object_geometry_get(obj, NULL, NULL, &w, &h);
eldbus_message_arguments_append(ret, "i", w);
eldbus_message_arguments_append(ret, "i", h);
return ret;
}
static const Eldbus_Method image_methods[] = {
{ "GetImageExtents", ELDBUS_ARGS({"u", "coordType"}), ELDBUS_ARGS({"iiii", "extents"}), _image_extents_get, 0 },
{ "GetImagePosition", ELDBUS_ARGS({"u", "coordType"}), ELDBUS_ARGS({"i", "x"}, {"i", "y"}), _image_position_get, 0 },
{ "GetImageSize", NULL, ELDBUS_ARGS({"i", "width"}, {"i", "height"}), _image_size_get, 0 },
{ NULL, NULL, NULL, NULL, 0 }
};
static Eldbus_Message *
_text_string_at_offset_get(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
{
const char *obj_path = eldbus_message_path_get(msg);
char *str;
Efl_Access_Text_Granularity gran;
int start = 0, end = 0;
Eldbus_Message *ret;
Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
Eo *obj = _bridge_object_from_path(bridge, obj_path);
ELM_ATSPI_ON_NULL_RETURN_DBUS_ERROR(obj, msg);
if (!eldbus_message_arguments_get(msg, "iu", &start, &gran))
return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Offset and granularity expected.");
if (efl_isa(obj, EFL_TEXT_INTERACTIVE_INTERFACE))
{
Efl_Text_Cursor_Object *sel1 = efl_ui_textbox_cursor_create(obj);
Efl_Text_Cursor_Object *sel2 = efl_ui_textbox_cursor_create(obj);
efl_text_cursor_object_position_set(sel1, start);
efl_text_cursor_object_position_set(sel2, start);
switch(gran)
{
case EFL_ACCESS_TEXT_GRANULARITY_CHAR:
efl_text_cursor_object_move(sel2, EFL_TEXT_CURSOR_MOVE_TYPE_CHARACTER_NEXT);
break;
case EFL_ACCESS_TEXT_GRANULARITY_WORD:
efl_text_cursor_object_move(sel1, EFL_TEXT_CURSOR_MOVE_TYPE_WORD_START);
efl_text_cursor_object_move(sel2, EFL_TEXT_CURSOR_MOVE_TYPE_WORD_END);
break;
case EFL_ACCESS_TEXT_GRANULARITY_LINE:
efl_text_cursor_object_move(sel1, EFL_TEXT_CURSOR_MOVE_TYPE_LINE_START);
efl_text_cursor_object_move(sel2, EFL_TEXT_CURSOR_MOVE_TYPE_LINE_END);
break;
case EFL_ACCESS_TEXT_GRANULARITY_PARAGRAPH:
efl_text_cursor_object_move(sel1, EFL_TEXT_CURSOR_MOVE_TYPE_PARAGRAPH_START);
efl_text_cursor_object_move(sel2, EFL_TEXT_CURSOR_MOVE_TYPE_PARAGRAPH_END);
break;
case EFL_ACCESS_TEXT_GRANULARITY_SENTENCE: /* this one is not supported by efl */
default:
efl_del(sel1);
efl_del(sel2);
return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Granularity not suported.");
}
str = efl_text_cursor_object_range_text_get(sel1, sel2);
start = efl_text_cursor_object_position_get(sel1);
end = efl_text_cursor_object_position_get(sel2);
efl_del(sel1);
efl_del(sel2);
}
else if (efl_isa(obj, EFL_ACCESS_TEXT_INTERFACE))
{
efl_access_text_string_get(obj, gran, &start, &end, &str);
}
else
{
return _dbus_invalid_ref_error_new(msg);
}
str = str ? str : strdup("");
ret = eldbus_message_method_return_new(msg);
EINA_SAFETY_ON_NULL_GOTO(ret, cleanup);
eldbus_message_arguments_append(ret, "sii", str, start, end);
cleanup:
free(str);
return ret;
}
static Eldbus_Message *
_text_text_get(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
{
const char *obj_path = eldbus_message_path_get(msg);
char *str;
Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
Eo *obj = _bridge_object_from_path(bridge, obj_path);
int start, end;
ELM_ATSPI_ON_NULL_RETURN_DBUS_ERROR(obj, msg);
if (!eldbus_message_arguments_get(msg, "ii", &start, &end))
return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Start and end offset expected.");
if (efl_isa(obj, EFL_TEXT_INTERACTIVE_INTERFACE))
{
Efl_Text_Cursor_Object *sel1 = efl_ui_textbox_cursor_create(obj);
Efl_Text_Cursor_Object *sel2 = efl_ui_textbox_cursor_create(obj);
efl_text_cursor_object_position_set(sel1, start);
efl_text_cursor_object_position_set(sel2, end);
str = efl_text_cursor_object_range_text_get(sel1, sel2);
efl_del(sel1);
efl_del(sel2);
}
else if (efl_isa(obj, EFL_ACCESS_TEXT_INTERFACE))
{
str = efl_access_text_get(obj, start, end);
}
else
{
return _dbus_invalid_ref_error_new(msg);
}
str = str ? str : strdup("");
Eldbus_Message *ret = eldbus_message_method_return_new(msg);
EINA_SAFETY_ON_NULL_GOTO(ret, cleanup);
eldbus_message_arguments_append(ret, "s", str);
cleanup:
free(str);
return ret;
}
static Eldbus_Message *
_text_caret_offset_set(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
{
const char *obj_path = eldbus_message_path_get(msg);
Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
Eo *obj = _bridge_object_from_path(bridge, obj_path);
int offset;
Eldbus_Message *ret;
Eina_Bool res;
ELM_ATSPI_ON_NULL_RETURN_DBUS_ERROR(obj, msg);
if (!eldbus_message_arguments_get(msg, "i", &offset))
return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Offset expected.");
if (efl_isa(obj, EFL_TEXT_INTERACTIVE_INTERFACE))
{
Efl_Text_Cursor_Object *cur = efl_text_interactive_main_cursor_get(obj);
efl_text_cursor_object_position_set(cur, offset);
res = EINA_TRUE;
}
else if (efl_isa(obj, EFL_ACCESS_TEXT_INTERFACE))
{
res = efl_access_text_caret_offset_set(obj, offset);
}
else
{
return _dbus_invalid_ref_error_new(msg);
}
ret = eldbus_message_method_return_new(msg);
EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
eldbus_message_arguments_append(ret, "b", res);
return ret;
}
static Eldbus_Message *
_text_character_at_offset_get(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
{
const char *obj_path = eldbus_message_path_get(msg);
Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
Eo *obj = _bridge_object_from_path(bridge, obj_path);
int offset;
Eldbus_Message *ret;
Eina_Unicode res;
ELM_ATSPI_ON_NULL_RETURN_DBUS_ERROR(obj, msg);
if (!eldbus_message_arguments_get(msg, "i", &offset))
return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Offset expected.");
if (efl_isa(obj, EFL_TEXT_INTERACTIVE_INTERFACE))
{
Efl_Text_Cursor_Object *cur = efl_ui_textbox_cursor_create(obj);
efl_text_cursor_object_position_set(cur, offset);
res = efl_text_cursor_object_content_get(cur);
efl_del(cur);
}
else if (efl_isa(obj, EFL_ACCESS_TEXT_INTERFACE))
{
res = efl_access_text_character_get(obj, offset);
}
else
{
return _dbus_invalid_ref_error_new(msg);
}
ret = eldbus_message_method_return_new(msg);
EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
eldbus_message_arguments_append(ret, "i", res);
return ret;
}
static Efl_Access_Text_Attribute*
_text_attribute_value_get_text_attribute(Efl_Text_Attribute_Handle *annotation)
{
Efl_Access_Text_Attribute *ret;
const char *txt;
txt = efl_text_formatter_attribute_get(annotation);
if (!txt) return NULL;
ret = calloc(1, sizeof(Efl_Access_Text_Attribute));
if (!ret) return NULL;
ret->value = eina_stringshare_add(txt);
int size = strlen(txt);
ret->name = eina_stringshare_add_length(txt, size);
return ret;
}
static Eldbus_Message *
_text_attribute_value_get(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
{
const char *name, *obj_path = eldbus_message_path_get(msg);
char *value = NULL;
Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
Eo *obj = _bridge_object_from_path(bridge, obj_path);
int start = 0, end = 0;
Eldbus_Message *ret;
Eina_Bool res = EINA_FALSE;
Eina_Iterator *annotations;
Efl_Access_Text_Attribute *attr;
Efl_Text_Attribute_Handle *an;
ELM_ATSPI_ON_NULL_RETURN_DBUS_ERROR(obj, msg);
if (!eldbus_message_arguments_get(msg, "is", &start, &name))
return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Offset and attribute name expected.");
if (efl_isa(obj, EFL_TEXT_INTERACTIVE_INTERFACE))
{
Efl_Text_Cursor_Object *sel1 = efl_ui_textbox_cursor_create(obj);
Efl_Text_Cursor_Object *sel2 = efl_ui_textbox_cursor_create(obj);
end = start+1;
efl_text_cursor_object_position_set(sel1, start);
efl_text_cursor_object_position_set(sel2, end);
annotations = efl_text_formatter_range_attributes_get(sel1, sel2);
if (annotations)
{
EINA_ITERATOR_FOREACH(annotations, an)
{
attr = _text_attribute_value_get_text_attribute(an);
if (!attr) continue;
if (!strcmp(attr->name, name))
{
value = attr->value ? eina_strdup(attr->value) : NULL;
res = EINA_TRUE;
}
elm_atspi_text_text_attribute_free(attr);
if (res)
break;
}
eina_iterator_free(annotations);
}
efl_del(sel1);
efl_del(sel2);
}
else if (efl_isa(obj, EFL_ACCESS_TEXT_INTERFACE))
{
res = efl_access_text_attribute_get(obj, name, &start, &end, &value);
}
else
{
return _dbus_invalid_ref_error_new(msg);
}
ret = eldbus_message_method_return_new(msg);
EINA_SAFETY_ON_NULL_GOTO(ret, cleanup);
eldbus_message_arguments_append(ret, "siib", value ? value : "", start, end, res);
cleanup:
free(value);
return ret;
}
static Eldbus_Message *
_text_attributes_get(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
{
const char *obj_path = eldbus_message_path_get(msg);
Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
Eo *obj = _bridge_object_from_path(bridge, obj_path);
int start = 0, end = 0;
Eldbus_Message *ret;
Eldbus_Message_Iter *iter, *iter_array;
Efl_Access_Text_Attribute *attr;
ELM_ATSPI_ON_NULL_RETURN_DBUS_ERROR(obj, msg);
if (!eldbus_message_arguments_get(msg, "i", &start))
return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Offset expected.");
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', "{ss}");
EINA_SAFETY_ON_NULL_GOTO(iter_array, fail);
if (efl_isa(obj, EFL_TEXT_INTERACTIVE_INTERFACE))
{
Eina_Iterator *annotations;
Efl_Text_Attribute_Handle *an;
Efl_Text_Cursor_Object *sel1 = efl_ui_textbox_cursor_create(obj);
Efl_Text_Cursor_Object *sel2 = efl_ui_textbox_cursor_create(obj);
end = start+1;
efl_text_cursor_object_position_set(sel1, start);
efl_text_cursor_object_position_set(sel2, end);
annotations = efl_text_formatter_range_attributes_get(sel1, sel2);
efl_del(sel1);
efl_del(sel2);
if (annotations)
{
EINA_ITERATOR_FOREACH(annotations, an)
{
attr = _text_attribute_value_get_text_attribute(an);
if (!attr) continue;
eldbus_message_iter_arguments_append(iter_array, "ss", attr->name, attr->value);
elm_atspi_text_text_attribute_free(attr);
}
eina_iterator_free(annotations);
}
}
else if (efl_isa(obj, EFL_ACCESS_TEXT_INTERFACE))
{
Eina_List *attrs = NULL;
efl_access_text_attributes_get(obj, &start, &end, &attrs);
EINA_LIST_FREE(attrs, attr)
{
eldbus_message_iter_arguments_append(iter_array, "ss", attr->name, attr->value);
elm_atspi_text_text_attribute_free(attr);
}
}
else
{
eldbus_message_iter_container_close(iter, iter_array);
goto fail;
}
eldbus_message_iter_container_close(iter, iter_array);
eldbus_message_iter_arguments_append(iter, "ii", start, end);
return ret;
fail:
if (ret) eldbus_message_unref(ret);
return NULL;
}
static Eldbus_Message *
_text_default_attributes_get(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
{
const char *obj_path = eldbus_message_path_get(msg);
Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
Eo *obj = _bridge_object_from_path(bridge, obj_path);
Eldbus_Message *ret;
Eldbus_Message_Iter *iter, *iter_array;
Eina_List *attrs = NULL;
Efl_Access_Text_Attribute *attr;
ELM_ATSPI_ON_NULL_RETURN_DBUS_ERROR(obj, msg);
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', "{ss}");
EINA_SAFETY_ON_NULL_GOTO(iter_array, fail);
if (efl_isa(obj, EFL_TEXT_INTERACTIVE_INTERFACE))
{
Eina_Iterator *annotations;
Efl_Text_Attribute_Handle *an;
Efl_Text_Cursor_Object *sel1 = efl_ui_textbox_cursor_create(obj);
Efl_Text_Cursor_Object *sel2 = efl_ui_textbox_cursor_create(obj);
efl_text_cursor_object_move(sel1, EFL_TEXT_CURSOR_MOVE_TYPE_FIRST);
efl_text_cursor_object_move(sel2, EFL_TEXT_CURSOR_MOVE_TYPE_LAST);
annotations = efl_text_formatter_range_attributes_get(sel1, sel2);
EINA_ITERATOR_FOREACH(annotations, an)
{
Efl_Access_Text_Attribute *attr = _text_attribute_value_get_text_attribute(an);
if (!attr) continue;
attrs = eina_list_append(attrs, attr);
}
eina_iterator_free(annotations);
efl_del(sel1);
efl_del(sel2);
}
else if (efl_isa(obj, EFL_ACCESS_TEXT_INTERFACE))
{
attrs = efl_access_text_default_attributes_get(obj);
}
else
{
eldbus_message_unref(ret);
eldbus_message_iter_container_close(iter, iter_array);
return _dbus_invalid_ref_error_new(msg);
}
EINA_LIST_FREE(attrs, attr)
{
eldbus_message_iter_arguments_append(iter_array, "ss", attr->name, attr->value);
elm_atspi_text_text_attribute_free(attr);
}
eldbus_message_iter_container_close(iter, iter_array);
return ret;
fail:
if (ret) eldbus_message_unref(ret);
return NULL;
}
static Eina_Rect
_text_interactive_get_pos(Eo *obj, Eina_Rect rect, Eina_Bool screen_coords)
{
Eina_Position2D scroller_shift = efl_ui_scrollable_content_pos_get(obj);
Eina_Rect viewport = efl_ui_scrollable_viewport_geometry_get(obj);
Eina_Rect r_obj = efl_access_component_extents_get(obj, EINA_TRUE);
/* In widget coords */
rect.x -= scroller_shift.x;
rect.y -= scroller_shift.y;
rect.x += viewport.x;
rect.y += viewport.y;
/* Is it still visible? */
if (rect.x < viewport.x)
{
rect.w += rect.x - viewport.x;
rect.x = viewport.x;
}
if (rect.y < viewport.y)
{
rect.h += rect.y - viewport.y;
rect.y = viewport.y;
}
rect.w = viewport.w < (rect.x + rect.w) ? viewport.w - rect.x : rect.w;
rect.h = viewport.h < (rect.y + rect.h) ? viewport.h - rect.y : rect.h;
/* If not visible set to 0 both sides */
if (rect.w <= 0 || rect.h <= 0)
{
rect.w = 0;
rect.h = 0;
}
/* Transform to screen coords */
rect.x += r_obj.x;
rect.y += r_obj.y;
/* Transform to window coords */
if (!screen_coords)
{
Eo *win = elm_object_top_widget_get(obj);
Eina_Rect r_win = efl_access_component_extents_get(win, EINA_TRUE);
rect.x -= r_win.x;
rect.y -= r_win.y;
}
return rect;
}
static Eldbus_Message *
_text_character_extents_get(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
{
const char *obj_path = eldbus_message_path_get(msg);
Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
Eo *obj = _bridge_object_from_path(bridge, obj_path);
int offset;
Eina_Rect rect;
AtspiCoordType type;
Eina_Bool screen_coords, res;
Eldbus_Message *ret;
ELM_ATSPI_ON_NULL_RETURN_DBUS_ERROR(obj, msg);
if (!eldbus_message_arguments_get(msg, "iu", &offset, &type))
return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Offset and coordinates type expected.");
screen_coords = type == ATSPI_COORD_TYPE_SCREEN ? EINA_TRUE : EINA_FALSE;
if (efl_isa(obj, EFL_TEXT_INTERACTIVE_INTERFACE))
{
Efl_Text_Cursor_Object *cur = efl_ui_textbox_cursor_create(obj);
efl_text_cursor_object_position_set(cur, offset);
rect = efl_text_cursor_object_cursor_geometry_get(cur, EFL_TEXT_CURSOR_TYPE_UNDER);
efl_del(cur);
rect = _text_interactive_get_pos(obj, rect, screen_coords);
res = rect.w != 0 ? EINA_TRUE : EINA_FALSE;
}
else if (efl_isa(obj, EFL_ACCESS_TEXT_INTERFACE))
{
res = efl_access_text_character_extents_get(obj, offset, screen_coords, &rect);
}
else
{
return _dbus_invalid_ref_error_new(msg);
}
if (!res)
return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.Failed", "Unable to get character extents.");
ret = eldbus_message_method_return_new(msg);
EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
eldbus_message_arguments_append(ret, "iiii", rect.x, rect.y, rect.w, rect.h);
return ret;
}
static Eldbus_Message *
_text_offset_at_point_get(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
{
const char *obj_path = eldbus_message_path_get(msg);
Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
Eo *obj = _bridge_object_from_path(bridge, obj_path);
int offset, x, y;
AtspiCoordType type;
Eina_Bool screen_coords;
Eldbus_Message *ret;
ELM_ATSPI_ON_NULL_RETURN_DBUS_ERROR(obj, msg);
if (!eldbus_message_arguments_get(msg, "iiu", &x, &y, &type))
return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Offset and coordinates type expected.");
screen_coords = type == ATSPI_COORD_TYPE_SCREEN ? EINA_TRUE : EINA_FALSE;
if (efl_isa(obj, EFL_TEXT_INTERACTIVE_INTERFACE))
{
if (screen_coords)
{
Eina_Rect rect = efl_access_component_extents_get(obj, screen_coords);
x -= rect.x;
y -= rect.y;
}
else
{
Eo *win = elm_object_top_widget_get(obj);
Eina_Rect r_win = efl_access_component_extents_get(win, EINA_TRUE);
Eina_Rect r_obj = efl_access_component_extents_get(obj, EINA_TRUE);
x -= r_obj.x - r_win.x;
y -= r_obj.y - r_win.y;
}
Efl_Text_Cursor_Object *cur = efl_ui_textbox_cursor_create(obj);
efl_text_cursor_object_char_coord_set(cur, EINA_POSITION2D(x,y));
offset = efl_text_cursor_object_position_get(cur);
efl_del(cur);
}
else if (efl_isa(obj, EFL_ACCESS_TEXT_INTERFACE))
{
offset = efl_access_text_offset_at_point_get(obj, screen_coords, x, y);
}
else
{
return _dbus_invalid_ref_error_new(msg);
}
ret = eldbus_message_method_return_new(msg);
EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
eldbus_message_arguments_append(ret, "i", offset);
return ret;
}
static Eldbus_Message *
_text_n_selections_get(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
{
const char *obj_path = eldbus_message_path_get(msg);
Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
Eo *obj = _bridge_object_from_path(bridge, obj_path);
int n;
Eldbus_Message *ret;
ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_TEXT_INTERFACE, msg);
ret = eldbus_message_method_return_new(msg);
EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
n = efl_access_text_selections_count_get(obj);
eldbus_message_arguments_append(ret, "i", n);
return ret;
}
static Eldbus_Message *
_text_selection_get(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
{
const char *obj_path = eldbus_message_path_get(msg);
Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
Eo *obj = _bridge_object_from_path(bridge, obj_path);
int sel_num, start = 0, end = 0;
Eldbus_Message *ret;
ELM_ATSPI_ON_NULL_RETURN_DBUS_ERROR(obj, msg);
if (!eldbus_message_arguments_get(msg, "i", &sel_num))
return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Selection number expected.");
if (efl_isa(obj, EFL_TEXT_INTERACTIVE_INTERFACE))
{
if (sel_num == 0)
{
Efl_Text_Cursor_Object *sel1, *sel2;
efl_text_interactive_selection_cursors_get(obj, &sel1, &sel2);
start = efl_text_cursor_object_position_get(sel1);
end = efl_text_cursor_object_position_get(sel2);
}
}
else if (efl_isa(obj, EFL_ACCESS_TEXT_INTERFACE))
{
efl_access_text_access_selection_get(obj, sel_num, &start, &end);
}
else
{
return _dbus_invalid_ref_error_new(msg);
}
ret = eldbus_message_method_return_new(msg);
EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
eldbus_message_arguments_append(ret, "ii", start, end);
return ret;
}
static Eldbus_Message *
_text_selection_add(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
{
const char *obj_path = eldbus_message_path_get(msg);
Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
Eo *obj = _bridge_object_from_path(bridge, obj_path);
int start, end;
Eina_Bool res;
Eldbus_Message *ret;
ELM_ATSPI_ON_NULL_RETURN_DBUS_ERROR(obj, msg);
if (!eldbus_message_arguments_get(msg, "ii", &start, &end))
return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Start and end text offset expected.");
if (efl_isa(obj, EFL_TEXT_INTERACTIVE_INTERFACE))
{
Efl_Text_Cursor_Object *sel1, *sel2;
efl_text_interactive_selection_cursors_get(obj, &sel1, &sel2);
efl_text_cursor_object_position_set(sel1, start);
efl_text_cursor_object_position_set(sel2, end);
res = EINA_TRUE;
}
else if (efl_isa(obj, EFL_ACCESS_TEXT_INTERFACE))
{
res = efl_access_text_selection_add(obj, start, end);
}
else
{
return _dbus_invalid_ref_error_new(msg);
}
ret = eldbus_message_method_return_new(msg);
EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
eldbus_message_arguments_append(ret, "b", res);
return ret;
}
static Eldbus_Message *
_text_selection_remove(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
{
const char *obj_path = eldbus_message_path_get(msg);
Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
Eo *obj = _bridge_object_from_path(bridge, obj_path);
int sel_num;
Eina_Bool res = EINA_FALSE;
Eldbus_Message *ret;
ELM_ATSPI_ON_NULL_RETURN_DBUS_ERROR(obj, msg);
if (!eldbus_message_arguments_get(msg, "i", &sel_num))
return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Selection number expected.");
if (efl_isa(obj, EFL_TEXT_INTERACTIVE_INTERFACE))
{
if (sel_num == 0)
{
Efl_Text_Cursor_Object *sel1, *sel2;
efl_text_interactive_selection_cursors_get(obj, &sel1, &sel2);
efl_text_cursor_object_range_delete(sel1, sel2);
res = EINA_TRUE;
}
}
else if (efl_isa(obj, EFL_ACCESS_TEXT_INTERFACE))
{
res = efl_access_text_selection_remove(obj, sel_num);
}
else
{
return _dbus_invalid_ref_error_new(msg);
}
ret = eldbus_message_method_return_new(msg);
EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
eldbus_message_arguments_append(ret, "b", res);
return ret;
}
static Eldbus_Message *
_text_selection_set(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
{
const char *obj_path = eldbus_message_path_get(msg);
Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
Eo *obj = _bridge_object_from_path(bridge, obj_path);
int sel_num, start, end;
Eina_Bool res = EINA_FALSE;
Eldbus_Message *ret;
ELM_ATSPI_ON_NULL_RETURN_DBUS_ERROR(obj, msg);
if (!eldbus_message_arguments_get(msg, "iii", &sel_num, &start, &end))
return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Selection number expected.");
if (efl_isa(obj, EFL_TEXT_INTERACTIVE_INTERFACE))
{
if (sel_num == 0)
{
Efl_Text_Cursor_Object *sel1, *sel2;
efl_text_interactive_selection_cursors_get(obj, &sel1, &sel2);
efl_text_cursor_object_position_set(sel1, start);
efl_text_cursor_object_position_set(sel2, end);
res = EINA_TRUE;
}
}
else if (efl_isa(obj, EFL_ACCESS_TEXT_INTERFACE))
{
res = efl_access_text_access_selection_set(obj, sel_num, start, end);
}
else
{
return _dbus_invalid_ref_error_new(msg);
}
ret = eldbus_message_method_return_new(msg);
EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
eldbus_message_arguments_append(ret, "b", res);
return ret;
}
static Eldbus_Message *
_text_range_extents_get(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
{
const char *obj_path = eldbus_message_path_get(msg);
Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
Eo *obj = _bridge_object_from_path(bridge, obj_path);
int start, end;
Eina_Rect rect;
Eina_Bool screen_coords, res;
AtspiCoordType type;
Eldbus_Message *ret;
ELM_ATSPI_ON_NULL_RETURN_DBUS_ERROR(obj, msg);
if (!eldbus_message_arguments_get(msg, "iiu", &start, &end, &type))
return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Selection number expected.");
screen_coords = type == ATSPI_COORD_TYPE_SCREEN ? EINA_TRUE : EINA_FALSE;
if (efl_isa(obj, EFL_TEXT_INTERACTIVE_INTERFACE))
{
Eina_Rectangle *r;
Efl_Text_Cursor_Object *sel1 = efl_ui_textbox_cursor_create(obj);
Efl_Text_Cursor_Object *sel2 = efl_ui_textbox_cursor_create(obj);
efl_text_cursor_object_position_set(sel1, start);
efl_text_cursor_object_position_set(sel2, end);
Eina_Iterator *range = efl_text_cursor_object_range_precise_geometry_get(sel1, sel2);
/* This rect represent coordinates x1, y1, x2, y2 (not x,y,w,h).
* In this way we bypass corner cases
* (like range is empty or first rectangle is empty). */
rect = EINA_RECT(1000000, 1000000, 0, 0);
EINA_ITERATOR_FOREACH(range, r)
{
rect.x = r->x < rect.x ? r->x : rect.x;
rect.y = r->y < rect.y ? r->y : rect.y;
rect.w = r->x+r->w > rect.w ? r->x+r->w : rect.w;
rect.h = r->y+r->h > rect.h ? r->y+r->h : rect.h;
}
eina_iterator_free(range);
efl_del(sel1);
efl_del(sel2);
/* Let's change coordinates to x,y,w,h */
rect.w -= rect.x;
rect.h -= rect.y;
rect = _text_interactive_get_pos(obj, rect, screen_coords);
res = rect.w != 0 ? EINA_TRUE : EINA_FALSE;
}
else if (efl_isa(obj, EFL_ACCESS_TEXT_INTERFACE))
{
res = efl_access_text_range_extents_get(obj, screen_coords, start, end, &rect);
}
else
{
return _dbus_invalid_ref_error_new(msg);
}
if (!res)
{
return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.Failed", "Can't get range extents.");
}
ret = eldbus_message_method_return_new(msg);
EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
eldbus_message_arguments_append(ret, "iiii", rect.x, rect.y, rect.w, rect.h);
return ret;
}
static Eldbus_Message *
_text_bounded_ranges_get(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
{
const char *obj_path = eldbus_message_path_get(msg);
Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
Eo *obj = _bridge_object_from_path(bridge, obj_path);
Eina_Rect rect;
Eina_Bool screen_coords;
AtspiCoordType type;
Efl_Access_Text_Clip_Type xclip, yclip;
Eina_List *ranges;
Eldbus_Message *ret;
Efl_Access_Text_Range *range;
Eldbus_Message_Iter *iter, *iter_array, *iter_struct, *iter_var;
ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_TEXT_INTERFACE, msg);
2015-07-29 07:21:17 -07:00
if (!eldbus_message_arguments_get(msg, "iiiiuuu", &rect.x, &rect.y, &rect.w, &rect.h, &type, &xclip, &yclip))
return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Expected (x,y,w,h) of bounding box, screen coord type and x, y text clip types.");
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', "(iisv)");
EINA_SAFETY_ON_NULL_GOTO(iter_array, fail);
screen_coords = type == ATSPI_COORD_TYPE_SCREEN ? EINA_TRUE : EINA_FALSE;
ranges = efl_access_text_bounded_ranges_get(obj, screen_coords, rect, xclip, yclip);
EINA_LIST_FREE(ranges, range)
{
iter_struct = eldbus_message_iter_container_new(iter_array, 'r', NULL);
if (iter_struct)
{
eldbus_message_iter_basic_append(iter_struct, 'i', range->start_offset);
eldbus_message_iter_basic_append(iter_struct, 'i', range->end_offset);
eldbus_message_iter_basic_append(iter_struct, 's', range->content ? range->content : "");
/* AT-SPI specification requires variant type in return, however
* ATK or other implementations as well as AT Clients don't use it .
* To cover spec a dummy value will be returned */
iter_var = eldbus_message_iter_container_new(iter_struct, 'v', "i");
if (iter_var)
{
eldbus_message_iter_basic_append(iter_var, 'i', 0);
eldbus_message_iter_container_close(iter_struct, iter_var);
}
eldbus_message_iter_container_close(iter_array, iter_struct);
}
elm_atspi_text_text_range_free(range);
}
eldbus_message_iter_container_close(iter, iter_array);
return ret;
fail:
if (ret) eldbus_message_unref(ret);
return NULL;
}
static Eldbus_Message *
_text_run_attributes_get(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
{
const char *obj_path = eldbus_message_path_get(msg);
Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
Eo *obj = _bridge_object_from_path(bridge, obj_path);
int start = 0, end = 0;
Eldbus_Message *ret;
Eldbus_Message_Iter *iter, *iter_array;
Eina_List *attrs, *defaults;
Efl_Access_Text_Attribute *attr;
Eina_Bool incl_def;
ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_TEXT_INTERFACE, msg);
if (!eldbus_message_arguments_get(msg, "ib", &start, &incl_def))
return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Offset and include defaults flag expected.");
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', "{ss}");
EINA_SAFETY_ON_NULL_GOTO(iter_array, fail);
efl_access_text_attributes_get(obj, &start, &end, &attrs);
if (incl_def)
{
defaults = efl_access_text_default_attributes_get(obj);
attrs = eina_list_merge(attrs, defaults);
}
EINA_LIST_FREE(attrs, attr)
{
eldbus_message_iter_arguments_append(iter_array, "ss", attr->name, attr->value);
elm_atspi_text_text_attribute_free(attr);
}
eldbus_message_iter_container_close(iter, iter_array);
eldbus_message_iter_arguments_append(iter, "ii", start, end);
return ret;
fail:
if (ret) eldbus_message_unref(ret);
return NULL;
}
static const Eldbus_Method text_methods[] = {
{ "GetTextAtOffset", ELDBUS_ARGS({"i", "offset"}, {"u", "granularity"}), ELDBUS_ARGS({"s", "string"}, {"i", "startOffset"}, {"i", "endOffset"}), _text_string_at_offset_get, 0 },
{ "GetText", ELDBUS_ARGS({"i", "startOffset"}, {"i", "endOffset"}), ELDBUS_ARGS({"s", "string"}), _text_text_get, 0 },
{ "SetCaretOffset", ELDBUS_ARGS({"i", "offset"}), ELDBUS_ARGS({"b", NULL}), _text_caret_offset_set, 0 },
{ "GetCharacterAtOffset", ELDBUS_ARGS({"i", "offset"}), ELDBUS_ARGS({"i", NULL}), _text_character_at_offset_get, 0 },
{ "GetAttributeValue", ELDBUS_ARGS({"i", "offset"}, {"s", "attributeName"}), ELDBUS_ARGS({"s", NULL}, {"i", "startOffset"}, {"i", "endOffset"}, {"b", "defined"}), _text_attribute_value_get, 0 },
{ "GetAttributes", ELDBUS_ARGS({"i", "offset"}), ELDBUS_ARGS({"a(ss)", NULL}, {"i", "startOffset"}, {"i", "endOffset"}), _text_attributes_get, 0 },
{ "GetDefaultAttributes", NULL, ELDBUS_ARGS({"a(ss)", NULL}), _text_default_attributes_get, 0 },
{ "GetCharacterExtents", ELDBUS_ARGS({"i", "offset"}, {"u", "coordType"}), ELDBUS_ARGS({"i", "x"}, {"i", "y"}, {"i","w"}, {"i","h"}), _text_character_extents_get, 0 },
{ "GetOffsetAtPoint", ELDBUS_ARGS({"i", "x"}, {"i","y"}, {"u", "coordType"}), ELDBUS_ARGS({"i", NULL}), _text_offset_at_point_get, 0 },
{ "GetNSelections", NULL, ELDBUS_ARGS({"i", NULL}), _text_n_selections_get, 0 },
{ "GetSelection", ELDBUS_ARGS({"i", "selectionNum"}), ELDBUS_ARGS({"i", "startOffset"}, {"i", "endOffset"}), _text_selection_get, 0 },
{ "AddSelection", ELDBUS_ARGS({"i", "startOffset"}, {"i", "endOffset"}), ELDBUS_ARGS({"b", NULL}), _text_selection_add, 0 },
{ "RemoveSelection", ELDBUS_ARGS({"i", "selectionNum"}), ELDBUS_ARGS({"b", NULL}), _text_selection_remove, 0 },
{ "SetSelection", ELDBUS_ARGS({"i", "selectionNum"}, {"i", "startOffset"}, {"i", "endOffset"}), ELDBUS_ARGS({"b", NULL}), _text_selection_set, 0 },
{ "GetRangeExtents", ELDBUS_ARGS({"i", "startOffset"}, {"i", "endOffset"}, {"u", "coordType"}), ELDBUS_ARGS({"i", "x"}, {"i", "y"}, {"i","w"}, {"i","h"}), _text_range_extents_get, 0 },
{ "GetBoundedRanges", ELDBUS_ARGS({"i", "x"}, {"i", "y"}, {"i", "w"}, {"i", "h"}, {"u", "coordType"}, {"u", "xClipType"}, {"u", "yClipType"}), ELDBUS_ARGS({"a(issv)", NULL}), _text_bounded_ranges_get, 0 },
{ "GetAttributeRun", ELDBUS_ARGS({"i", "offset"}, {"b", "includeDefaults"}), ELDBUS_ARGS({"a(ss)", NULL}, {"i", "startOffset"}, {"i", "endOffset"}), _text_run_attributes_get, 0 },
{ NULL, NULL, NULL, NULL, 0 }
};
static Eldbus_Message *
_editable_text_text_content_set(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
{
const char *obj_path = eldbus_message_path_get(msg);
Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
Eo *obj = _bridge_object_from_path(bridge, obj_path);
const char *content;
Eldbus_Message *ret;
Eina_Bool res;
ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_EDITABLE_TEXT_INTERFACE, msg);
if (!eldbus_message_arguments_get(msg, "s", &content))
return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "String expected.");
ret = eldbus_message_method_return_new(msg);
EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
res = efl_access_editable_text_content_set(obj, content);
eldbus_message_arguments_append(ret, "b", res);
return ret;
}
static Eldbus_Message *
_editable_text_text_insert(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
{
const char *obj_path = eldbus_message_path_get(msg);
Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
Eo *obj = _bridge_object_from_path(bridge, obj_path);
const char *text;
Eldbus_Message *ret;
int pos, len;
Eina_Bool res;
ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_EDITABLE_TEXT_INTERFACE, msg);
if (!eldbus_message_arguments_get(msg, "isi", &pos, &text, &len))
return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Position, string, length expected.");
ret = eldbus_message_method_return_new(msg);
EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
res = efl_access_editable_text_insert(obj, text, pos);
eldbus_message_arguments_append(ret, "b", res);
return ret;
}
static Eldbus_Message *
_editable_text_text_copy(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
{
const char *obj_path = eldbus_message_path_get(msg);
Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
Eo *obj = _bridge_object_from_path(bridge, obj_path);
Eldbus_Message *ret;
int start, end;
Eina_Bool res;
ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_EDITABLE_TEXT_INTERFACE, msg);
if (!eldbus_message_arguments_get(msg, "ii", &start, &end))
return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Start and end index expected.");
ret = eldbus_message_method_return_new(msg);
EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
res = efl_access_editable_text_copy(obj, start, end);
eldbus_message_arguments_append(ret, "b", res);
return ret;
}
static Eldbus_Message *
_editable_text_text_cut(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
{
const char *obj_path = eldbus_message_path_get(msg);
Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
Eo *obj = _bridge_object_from_path(bridge, obj_path);
Eldbus_Message *ret;
int start, end;
Eina_Bool res;
ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_EDITABLE_TEXT_INTERFACE, msg);
if (!eldbus_message_arguments_get(msg, "ii", &start, &end))
return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Start and end index expected.");
ret = eldbus_message_method_return_new(msg);
EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
res = efl_access_editable_text_cut(obj, start, end);
eldbus_message_arguments_append(ret, "b", res);
return ret;
}
static Eldbus_Message *
_editable_text_text_delete(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
{
const char *obj_path = eldbus_message_path_get(msg);
Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
Eo *obj = _bridge_object_from_path(bridge, obj_path);
Eldbus_Message *ret;
int start, end;
Eina_Bool res;
ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_EDITABLE_TEXT_INTERFACE, msg);
if (!eldbus_message_arguments_get(msg, "ii", &start, &end))
return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Start and end index expected.");
ret = eldbus_message_method_return_new(msg);
EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
res = efl_access_editable_text_delete(obj, start, end);
eldbus_message_arguments_append(ret, "b", res);
return ret;
}
static Eldbus_Message *
_editable_text_text_paste(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
{
const char *obj_path = eldbus_message_path_get(msg);
Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
Eo *obj = _bridge_object_from_path(bridge, obj_path);
Eldbus_Message *ret;
int pos;
Eina_Bool res;
ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_EDITABLE_TEXT_INTERFACE, msg);
if (!eldbus_message_arguments_get(msg, "i", &pos))
return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Start and end index expected.");
ret = eldbus_message_method_return_new(msg);
EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
res = efl_access_editable_text_paste(obj, pos);
eldbus_message_arguments_append(ret, "b", res);
return ret;
}
static const Eldbus_Method editable_text_methods[] = {
{ "SetTextContents", ELDBUS_ARGS({"s", "newcontents"}), ELDBUS_ARGS({"b", NULL}), _editable_text_text_content_set, 0 },
{ "InsertText", ELDBUS_ARGS({"i", "position"}, {"s", "text"}, {"i", "length"}), ELDBUS_ARGS({"b", NULL}), _editable_text_text_insert, 0 },
{ "CopyText", ELDBUS_ARGS({"i", "startPos"}, {"i", "endPos"}), NULL, _editable_text_text_copy, 0 },
{ "CutText", ELDBUS_ARGS({"i", "startPos"}, {"i", "endPos"}), ELDBUS_ARGS({"b", NULL}), _editable_text_text_cut, 0 },
{ "DeleteText", ELDBUS_ARGS({"i", "startPos"}, {"i", "endPos"}), ELDBUS_ARGS({"b", NULL}), _editable_text_text_delete, 0 },
{ "PasteText", ELDBUS_ARGS({"i", "position"}), ELDBUS_ARGS({"b", NULL}), _editable_text_text_paste, 0 },
{ NULL, NULL, NULL, NULL, 0 }
};
static Eo *
_bridge_object_from_path(Eo *bridge, const char *path)
{
EINA_SAFETY_ON_NULL_RETURN_VAL(path, NULL);
unsigned long long eo_ptr = 0;
Eo *eo = NULL;
const char *tmp = path;
Eo *ret, *root;
int len = strlen(ELM_ACCESS_OBJECT_PATH_PREFIX);
if (strncmp(path, ELM_ACCESS_OBJECT_PATH_PREFIX, len))
return NULL;
tmp = path + len; /* Skip over the prefix */
if (!strcmp(ELM_ACCESS_OBJECT_PATH_ROOT, tmp))
{
root = efl_access_object_access_root_get();
return root;
}
sscanf(tmp, "%llu", &eo_ptr);
eo = (Eo *) (uintptr_t) eo_ptr;
ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN_VAL(bridge, pd, NULL);
if (!eina_hash_find(pd->cache, &eo))
{
WRN("Request for non-registered object: %s", path);
return NULL;
}
ret = efl_isa(eo, EFL_ACCESS_OBJECT_MIXIN) ? eo : NULL;
return ret;
}
static const char *
_path_from_object(const Eo *eo)
{
static char path[64];
Eo *root;
if (!eo)
return ATSPI_DBUS_PATH_NULL;
root = efl_access_object_access_root_get();
if (eo == root)
snprintf(path, sizeof(path), "%s%s", ELM_ACCESS_OBJECT_PATH_PREFIX, ELM_ACCESS_OBJECT_PATH_ROOT);
else
snprintf(path, sizeof(path), ELM_ACCESS_OBJECT_REFERENCE_TEMPLATE, (unsigned long long)(uintptr_t)eo);
return path;
}
static Eina_Bool
_accessible_property_get(const Eldbus_Service_Interface *interface, const char *property,
Eldbus_Message_Iter *iter, const Eldbus_Message *request_msg,
Eldbus_Message **error)
{
const char *ret = NULL, *obj_path = eldbus_message_path_get(request_msg);
Eo *bridge = eldbus_service_object_data_get(interface, ELM_ATSPI_BRIDGE_CLASS_NAME);
Eo *ret_obj = NULL, *obj = _bridge_object_from_path(bridge, obj_path);
ELM_ATSPI_PROPERTY_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_OBJECT_MIXIN, request_msg, error);
if (!strcmp(property, "Name"))
{
ret = efl_access_object_i18n_name_get(obj);
if (!ret)
ret = "";
eldbus_message_iter_basic_append(iter, 's', ret);
return EINA_TRUE;
}
else if (!strcmp(property, "Description"))
{
ret = efl_access_object_description_get(obj);
if (!ret)
ret = "";
eldbus_message_iter_basic_append(iter, 's', ret);
return EINA_TRUE;
}
else if (!strcmp(property, "Parent"))
{
ret_obj = efl_provider_find(efl_parent_get(obj), EFL_ACCESS_OBJECT_MIXIN);
Efl_Access_Role role = EFL_ACCESS_ROLE_INVALID;
role = efl_access_object_role_get(obj);
if ((!ret_obj) && (EFL_ACCESS_ROLE_APPLICATION == role))
_object_desktop_reference_append(iter);
else
_bridge_iter_object_reference_append(bridge, iter, ret_obj);
return EINA_TRUE;
}
else if (!strcmp(property, "ChildCount"))
{
Eina_List *l = NULL;
l = efl_access_object_access_children_get(obj);
eldbus_message_iter_basic_append(iter, 'i', eina_list_count(l));
eina_list_free(l);
return EINA_TRUE;
}
return EINA_FALSE;
}
static Eina_Bool
_selection_property_get(const Eldbus_Service_Interface *interface, const char *property,
Eldbus_Message_Iter *iter, const Eldbus_Message *request_msg,
Eldbus_Message **error)
{
int n;
const char *obj_path = eldbus_message_path_get(request_msg);
Eo *bridge = eldbus_service_object_data_get(interface, ELM_ATSPI_BRIDGE_CLASS_NAME);
Eo *obj = _bridge_object_from_path(bridge, obj_path);
ELM_ATSPI_PROPERTY_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_SELECTION_INTERFACE, request_msg, error);
if (!strcmp(property, "NSelectedChildren"))
{
n = efl_access_selection_selected_children_count_get(obj);
eldbus_message_iter_basic_append(iter, 'i', n);
return EINA_TRUE;
}
return EINA_FALSE;
}
static Eina_Bool
_action_property_get(const Eldbus_Service_Interface *interface, const char *property,
Eldbus_Message_Iter *iter, const Eldbus_Message *request_msg,
Eldbus_Message **error)
{
Eina_List *actions;
const char *obj_path = eldbus_message_path_get(request_msg);
Eo *bridge = eldbus_service_object_data_get(interface, ELM_ATSPI_BRIDGE_CLASS_NAME);
Eo *obj = _bridge_object_from_path(bridge, obj_path);
ELM_ATSPI_PROPERTY_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_ACTION_MIXIN, request_msg, error);
if (!strcmp(property, "NActions"))
{
actions = efl_access_action_actions_get(obj);
eldbus_message_iter_basic_append(iter, 'i', eina_list_count(actions));
eina_list_free(actions);
return EINA_TRUE;
}
return EINA_FALSE;
}
static Eldbus_Message*
_value_properties_set(const Eldbus_Service_Interface *interface, const char *property,
Eldbus_Message_Iter *iter, const Eldbus_Message *request_msg)
{
double value;
Eina_Bool ret;
const char *obj_path = eldbus_message_path_get(request_msg);
Eo *bridge = eldbus_service_object_data_get(interface, ELM_ATSPI_BRIDGE_CLASS_NAME);
Eo *obj = _bridge_object_from_path(bridge, obj_path);
if (elm_widget_is_legacy(obj)) {
ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_VALUE_INTERFACE, request_msg);
}
else if(efl_isa(obj, EFL_UI_RANGE_DISPLAY_INTERFACE)) {
ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_UI_RANGE_DISPLAY_INTERFACE, request_msg);
}
if (!eldbus_message_iter_arguments_get(iter, "d", &value))
{
return eldbus_message_error_new(request_msg, "org.freedesktop.DBus.Error.InvalidArgs", "Expected value of type: double.");
}
if (!strcmp(property, "CurrentValue"))
{
if (elm_widget_is_legacy(obj))
ret = efl_access_value_and_text_set(obj, value, NULL);
else if(efl_isa(obj, EFL_UI_RANGE_DISPLAY_INTERFACE)) {
efl_ui_range_value_set(obj, value);
ret = EINA_DBL_EQ(efl_ui_range_value_get(obj), value);
}
else ret = EINA_FALSE;
Eldbus_Message *answer = eldbus_message_method_return_new(request_msg);
eldbus_message_arguments_append(answer, "b", ret);
return answer;
}
return NULL;
}
static Eina_Bool
_value_properties_get(const Eldbus_Service_Interface *interface, const char *property,
Eldbus_Message_Iter *iter, const Eldbus_Message *request_msg,
Eldbus_Message **error)
{
double value;
const char *obj_path = eldbus_message_path_get(request_msg);
Eo *bridge = eldbus_service_object_data_get(interface, ELM_ATSPI_BRIDGE_CLASS_NAME);
Eo *obj = _bridge_object_from_path(bridge, obj_path);
ELM_ATSPI_PROPERTY_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_UI_RANGE_DISPLAY_INTERFACE, request_msg, error);
if (!strcmp(property, "CurrentValue"))
{
value = efl_ui_range_value_get(obj);
eldbus_message_iter_basic_append(iter, 'd', value);
return EINA_TRUE;
}
if (!strcmp(property, "MinimumValue"))
{
efl_ui_range_limits_get(obj, &value, NULL);
eldbus_message_iter_basic_append(iter, 'd', value);
return EINA_TRUE;
}
if (!strcmp(property, "MaximumValue"))
{
efl_ui_range_limits_get(obj, NULL, &value);
eldbus_message_iter_basic_append(iter, 'd', value);
return EINA_TRUE;
}
if (!strcmp(property, "MinimumIncrement"))
{
if(efl_isa(obj, EFL_UI_RANGE_INTERACTIVE_INTERFACE)) {
value = efl_ui_range_step_get(obj);
}
else { value = 0; }
eldbus_message_iter_basic_append(iter, 'd', value);
return EINA_TRUE;
}
return EINA_FALSE;
}
static Eina_Bool
_image_properties_get(const Eldbus_Service_Interface *interface, const char *property,
Eldbus_Message_Iter *iter, const Eldbus_Message *request_msg,
Eldbus_Message **error)
{
const char *value;
const char *obj_path = eldbus_message_path_get(request_msg);
Eo *bridge = eldbus_service_object_data_get(interface, ELM_ATSPI_BRIDGE_CLASS_NAME);
Eo *obj = _bridge_object_from_path(bridge, obj_path);
ELM_ATSPI_PROPERTY_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_OBJECT_MIXIN, request_msg, error);
if (!strcmp(property, "ImageDescription"))
{
value = efl_access_object_description_get(obj);
value = value ? value : "";
eldbus_message_iter_basic_append(iter, 's', value);
return EINA_TRUE;
}
if (!strcmp(property, "ImageLocale"))
{
value = efl_access_object_translation_domain_get(obj);
value = value ? value : "";
eldbus_message_iter_basic_append(iter, 's', value);
return EINA_TRUE;
}
return EINA_FALSE;
}
static Eina_Bool
_text_properties_get(const Eldbus_Service_Interface *interface, const char *property,
Eldbus_Message_Iter *iter, const Eldbus_Message *request_msg,
Eldbus_Message **error)
{
const char *obj_path = eldbus_message_path_get(request_msg);
Eo *bridge = eldbus_service_object_data_get(interface, ELM_ATSPI_BRIDGE_CLASS_NAME);
Eo *obj = _bridge_object_from_path(bridge, obj_path);
int result;
Eina_Bool checkCarretOffset = EINA_FALSE;
Eina_Bool checkCharacterCount = EINA_FALSE;
if (!obj)
{
*(error) = _dbus_invalid_ref_error_new(request_msg);
return EINA_FALSE;
}
if (!strcmp(property, "CharacterCount"))
checkCharacterCount = EINA_TRUE;
else if (!strcmp(property, "CaretOffset"))
checkCarretOffset = EINA_TRUE;
else
return EINA_FALSE;
if (efl_isa(obj, EFL_TEXT_INTERACTIVE_INTERFACE))
{
if (checkCharacterCount)
{
Efl_Text_Cursor_Object *cur = efl_ui_textbox_cursor_create(obj);
efl_text_cursor_object_move(cur, EFL_TEXT_CURSOR_MOVE_TYPE_LAST);
result = efl_text_cursor_object_position_get(cur);
efl_del(cur);
}
if (checkCarretOffset)
{
Efl_Text_Cursor_Object *main_cur = efl_text_interactive_main_cursor_get(obj);
result = efl_text_cursor_object_position_get(main_cur);
}
}
else if (efl_isa(obj, EFL_ACCESS_TEXT_INTERFACE))
{
if (checkCharacterCount)
result = efl_access_text_character_count_get(obj);
if (checkCarretOffset)
result = efl_access_text_caret_offset_get(obj);
}
else
{
*(error) = _dbus_invalid_ref_error_new(request_msg);
return EINA_FALSE;
}
eldbus_message_iter_basic_append(iter, 'i', result);
return EINA_TRUE;
}
static Eldbus_Message*
_application_properties_set(const Eldbus_Service_Interface *iface, const char *property, Eldbus_Message_Iter *iter, const Eldbus_Message *input_msg)
{
Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
const char *obj_path = eldbus_message_path_get(input_msg);
Eo *obj = _bridge_object_from_path(bridge, obj_path);
int value;
ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN_VAL(bridge, pd, NULL);
ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, ELM_ATSPI_APP_OBJECT_CLASS, input_msg);
if (!eldbus_message_iter_arguments_get(iter, "i", &value))
{
return eldbus_message_error_new(input_msg, "org.freedesktop.DBus.Error.InvalidArgs", "Expected value of type: int.");
}
if (!strcmp(property, "Id"))
{
pd->id = value;
Eldbus_Message *answer = eldbus_message_method_return_new(input_msg);
eldbus_message_arguments_append(answer, "b", EINA_TRUE);
return answer;
}
return NULL;
}
static Eina_Bool
_application_properties_get(const Eldbus_Service_Interface *interface, const char *property,
Eldbus_Message_Iter *iter, const Eldbus_Message *request_msg,
Eldbus_Message **error)
{
const char *obj_path = eldbus_message_path_get(request_msg);
Eo *bridge = eldbus_service_object_data_get(interface, ELM_ATSPI_BRIDGE_CLASS_NAME);
Eo *obj = _bridge_object_from_path(bridge, obj_path);
ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN_VAL(bridge, pd, EINA_FALSE);
ELM_ATSPI_PROPERTY_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, ELM_ATSPI_APP_OBJECT_CLASS, request_msg, error);
if (!strcmp(property, "ToolkitName"))
{
eldbus_message_iter_basic_append(iter, 's', "elementary");
return EINA_TRUE;
}
if (!strcmp(property, "Version"))
{
char buf[64];
snprintf(buf, sizeof(buf), "%d.%d", ELM_VERSION_MAJOR, ELM_VERSION_MINOR);
eldbus_message_iter_basic_append(iter, 's', buf);
return EINA_TRUE;
}
if (!strcmp(property, "Id"))
{
eldbus_message_iter_basic_append(iter, 'i', pd->id);
return EINA_TRUE;
}
return EINA_FALSE;
}
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 },
{ NULL, NULL, NULL, NULL, 0 }
};
static const Eldbus_Property action_properties[] = {
{ "NActions", "i", _action_property_get, NULL, 0 },
{ NULL, NULL, NULL, NULL, 0 }
};
static const Eldbus_Property value_properties[] = {
{ "MinimumValue", "d", NULL, NULL, 0 },
{ "MaximumValue", "d", NULL, NULL, 0 },
{ "MinimumIncrement", "d", NULL, NULL, 0 },
{ "CurrentValue", "d", NULL, NULL, 0 },
{ NULL, NULL, NULL, NULL, 0 }
};
static const Eldbus_Property image_properties[] = {
{ "ImageDescription", "s", NULL, NULL, 0 },
{ "ImageLocale", "s", NULL, NULL, 0 },
{ NULL, NULL, NULL, NULL, 0 }
};
static const Eldbus_Property selection_properties[] = {
{ "NSelectedChildren", "i", _selection_property_get, NULL, 0 },
{ NULL, NULL, NULL, NULL, 0 }
};
static const Eldbus_Property text_properties[] = {
{ "CharacterCount", "i", NULL, NULL, 0 },
{ "CaretOffset", "i", NULL, NULL, 0 },
{ NULL, NULL, NULL, NULL, 0 }
};
static const Eldbus_Property application_properties[] = {
{ "ToolkitName", "s", NULL, NULL, 0 },
{ "Version", "s", NULL, NULL, 0 },
{ "Id", "i", NULL, NULL, 0 },
{ NULL, NULL, NULL, NULL, 0 }
};
static const Eldbus_Service_Interface_Desc accessible_iface_desc = {
ATSPI_DBUS_INTERFACE_ACCESSIBLE, accessible_methods, NULL, accessible_properties, _accessible_property_get, NULL
};
static const Eldbus_Service_Interface_Desc action_iface_desc = {
ATSPI_DBUS_INTERFACE_ACTION, action_methods, NULL, action_properties, NULL, NULL
};
static const Eldbus_Service_Interface_Desc value_iface_desc = {
ATSPI_DBUS_INTERFACE_VALUE, NULL, NULL, value_properties, _value_properties_get, _value_properties_set
};
static const Eldbus_Service_Interface_Desc image_iface_desc = {
ATSPI_DBUS_INTERFACE_IMAGE, image_methods, NULL, image_properties, _image_properties_get, NULL
};
static const Eldbus_Service_Interface_Desc selection_iface_desc = {
ATSPI_DBUS_INTERFACE_SELECTION, selection_methods, NULL, selection_properties, NULL, NULL
};
static const Eldbus_Service_Interface_Desc text_iface_desc = {
ATSPI_DBUS_INTERFACE_TEXT, text_methods, NULL, text_properties, _text_properties_get, NULL
};
static const Eldbus_Service_Interface_Desc editable_text_iface_desc = {
ATSPI_DBUS_INTERFACE_EDITABLE_TEXT, editable_text_methods, NULL, NULL, NULL, NULL
};
static const Eldbus_Service_Interface_Desc application_iface_desc = {
ATSPI_DBUS_INTERFACE_APPLICATION, NULL, NULL, application_properties, _application_properties_get, _application_properties_set
};
void
_collection_match_rule_free(struct collection_match_rule *rule)
{
Efl_Access_Attribute *attr;
eina_list_free(rule->ifaces);
EINA_LIST_FREE(rule->attributes, attr)
{
eina_stringshare_del(attr->key);
eina_stringshare_del(attr->value);
}
}
static void
_collection_roles_convert(uint64_t roles[2])
{
// Currently elm roles and atspi roles are binary compatible.
// Implement this function when it will be needed.
(void)roles;
}
static Eina_Bool
_collection_iter_match_rule_get(Eldbus_Message_Iter *iter, struct collection_match_rule *rule)
{
Eldbus_Message_Iter *states_iter, *attrib_iter, *iter_arg, *role_iter, *ifc_iter;
unsigned int *array;
int array_count, state_match, attrib_match, role_match, ifc_match, reverse;
const char *ifc_name;
if (!eldbus_message_iter_arguments_get(iter, "aiia{ss}iaiiasib", &states_iter, &state_match, &attrib_iter, &attrib_match, &role_iter, &role_match, &ifc_iter, &ifc_match, &reverse))
{
ERR("Unable to get message arguments");
return EINA_FALSE;
}
memset(rule, 0x0, sizeof(struct collection_match_rule));
rule->statematchtype = state_match;
rule->attributematchtype = attrib_match;
rule->rolematchtype = role_match;
rule->interfacematchtype = ifc_match;
rule->reverse = reverse;
if (!eldbus_message_iter_fixed_array_get(states_iter, 'i', &array, &array_count))
return EINA_FALSE;
//Roles according to libatspi implementation are transferred in 2-int element fixed bit array
if (array_count != 2)
{
ERR("Unexpected states array size");
return EINA_FALSE;
}
uint64_t states = ((uint64_t)array[0] | ((uint64_t)array[1] << 32));
rule->states = _atspi_state_set_to_elm_atspi_state_set(states);
//Roles according to libatspi implementation are transferred in 4-int element fixed bit array
if (!eldbus_message_iter_fixed_array_get(role_iter, 'i', &array, &array_count))
return EINA_FALSE;
if (array_count != 4)
{
ERR("Unexpected roles array size");
return EINA_FALSE;
}
//convert atspi roles to elm_roles
rule->roles[0] = ((uint64_t)array[0] | ((uint64_t)array[1] << 32));
rule->roles[1] = ((uint64_t)array[2] | ((uint64_t)array[3] << 32));
_collection_roles_convert(rule->roles);
//Get matching properties
while (eldbus_message_iter_get_and_next(attrib_iter, '{', &iter_arg))
{
const char *key, *value;
if (eldbus_message_iter_arguments_get(iter_arg, "ss", &key, &value))
{
Efl_Access_Attribute *attrib = calloc(1, sizeof(Efl_Access_Attribute));
attrib->key = eina_stringshare_add(key);
attrib->value = eina_stringshare_add(value);
rule->attributes = eina_list_append(rule->attributes, attrib);
}
}
//Get interfaces to match
while (eldbus_message_iter_get_and_next(ifc_iter, 's', &ifc_name))
{
const Efl_Class *class = NULL;
if (!strcmp(ifc_name, "action"))
class = EFL_ACCESS_ACTION_MIXIN;
else if (!strcmp(ifc_name, "component"))
class = EFL_ACCESS_COMPONENT_MIXIN;
else if (!strcmp(ifc_name, "editabletext"))
class = EFL_ACCESS_EDITABLE_TEXT_INTERFACE;
else if (!strcmp(ifc_name, "text"))
class = EFL_ACCESS_TEXT_INTERFACE;
else if (!strcmp(ifc_name, "image"))
class = EFL_ACCESS_SELECTION_INTERFACE;
else if (!strcmp(ifc_name, "value"))
{
class = EFL_ACCESS_VALUE_INTERFACE;
rule->ifaces = eina_list_append(rule->ifaces, EFL_UI_RANGE_DISPLAY_INTERFACE); //alternative interface
}
if (class)
rule->ifaces = eina_list_append(rule->ifaces, class);
else
{
_collection_match_rule_free(rule);
return EINA_FALSE;
}
}
return EINA_TRUE;
}
static Eina_Bool
_collection_match_interfaces_helper(Eo *obj, Eina_List *ifcs, Eina_Bool condition, Eina_Bool ret_if_true, Eina_Bool ret_if_false)
{
Efl_Class *class;
Eina_List *l;
EINA_LIST_FOREACH(ifcs, l, class)
{
if (efl_isa(obj, class) == condition)
return ret_if_true;
}
return ret_if_false;
}
static Eina_Bool
_collection_match_interfaces_lookup(Eo *obj, struct collection_match_rule *rule)
{
Eina_Bool ret = EINA_FALSE;
switch (rule->interfacematchtype)
{
case ATSPI_Collection_MATCH_INVALID:
ret = EINA_TRUE;
break;
case ATSPI_Collection_MATCH_ALL:
ret = _collection_match_interfaces_helper(
obj, rule->ifaces, EINA_FALSE, EINA_FALSE, EINA_TRUE);
break;
case ATSPI_Collection_MATCH_ANY:
ret = _collection_match_interfaces_helper(
obj, rule->ifaces, EINA_TRUE, EINA_TRUE, EINA_FALSE);
break;
case ATSPI_Collection_MATCH_NONE:
ret = _collection_match_interfaces_helper(
obj, rule->ifaces, EINA_TRUE, EINA_FALSE, EINA_TRUE);
break;
default:
break;
}
return ret;
}
static Eina_Bool
_collection_match_states_lookup(Eo *obj, struct collection_match_rule *rule)
{
Eina_Bool ret = EINA_FALSE;
Efl_Access_State_Set ss;
ss = efl_access_object_state_set_get(obj);
switch (rule->statematchtype)
{
case ATSPI_Collection_MATCH_INVALID:
ret = EINA_TRUE;
break;
case ATSPI_Collection_MATCH_ALL:
ret = (ss & rule->states) == rule->states;
break;
case ATSPI_Collection_MATCH_ANY:
ret = (ss & rule->states) > 0;
break;
case ATSPI_Collection_MATCH_NONE:
ret = (ss & rule->states) == 0;
break;
default:
break;
}
return ret;
}
static Eina_Bool
_collection_match_roles_lookup(Eo *obj, struct collection_match_rule *rule)
{
Eina_Bool ret = EINA_FALSE;
Efl_Access_Role role;
int64_t role_set;
role = efl_access_object_role_get(obj);
if (role >= 64)
{
role -= 64;
role_set = rule->roles[1];
}
else
role_set = rule->roles[0];
if (role >= 64)
{
ERR("Efl_Access_Role enum value exceeds 127. Unable to compare with roles bit field.");
return EINA_FALSE;
}
switch (rule->rolematchtype)
{
case ATSPI_Collection_MATCH_INVALID:
ret = EINA_TRUE;
break;
case ATSPI_Collection_MATCH_ALL:
case ATSPI_Collection_MATCH_ANY:
ret = (role_set & (1ULL << role)) > 0;
break;
case ATSPI_Collection_MATCH_NONE:
ret = (role_set & (1ULL << role)) == 0;
break;
default:
break;
}
return ret;
}
static Eina_Bool
_collection_match_attributes_helper(Eina_List *obj_attribs, Eina_List *attribs, AtspiCollectionMatchType mode)
{
Eina_List *l, *l2;
Efl_Access_Attribute *attr, *attr2;
Eina_Bool obj_empty = eina_list_count(obj_attribs) == 0;
Eina_Bool empty = eina_list_count(attribs) == 0;
switch (mode)
{
case ATSPI_Collection_MATCH_ANY:
if (empty || obj_empty) return EINA_FALSE;
break;
case ATSPI_Collection_MATCH_ALL:
if (empty) return EINA_TRUE;
if (obj_empty) return EINA_FALSE;
break;
case ATSPI_Collection_MATCH_NONE:
if (empty || obj_empty) return EINA_TRUE;
break;
case ATSPI_Collection_MATCH_EMPTY:
if (empty && obj_empty) return EINA_TRUE;
if (empty || obj_empty) return EINA_FALSE;
break;
case ATSPI_Collection_MATCH_INVALID:
case ATSPI_Collection_MATCH_LAST_DEFINED:
assert(0);
break;
}
EINA_LIST_FOREACH(attribs, l, attr)
{
Eina_Bool found = EINA_FALSE;
EINA_LIST_FOREACH(obj_attribs, l2, attr2)
{
Eina_Bool compare = (attr->key && attr2->key &&
attr->value && attr2->value &&
!strcmp(attr->key, attr2->key) &&
!strcmp(attr->value, attr2->value));
if (compare)
{
found = EINA_TRUE;
break;
}
}
switch (mode)
{
case ATSPI_Collection_MATCH_EMPTY:
case ATSPI_Collection_MATCH_ALL:
if (!found) return EINA_FALSE;
break;
case ATSPI_Collection_MATCH_ANY:
if (found) return EINA_TRUE;
break;
case ATSPI_Collection_MATCH_NONE:
if (found) return EINA_FALSE;
break;
case ATSPI_Collection_MATCH_INVALID:
case ATSPI_Collection_MATCH_LAST_DEFINED:
assert(0);
break;
}
}
switch (mode)
{
case ATSPI_Collection_MATCH_EMPTY:
case ATSPI_Collection_MATCH_ALL:
case ATSPI_Collection_MATCH_NONE:
return EINA_TRUE;
case ATSPI_Collection_MATCH_ANY:
return EINA_FALSE;
case ATSPI_Collection_MATCH_INVALID:
case ATSPI_Collection_MATCH_LAST_DEFINED:
assert(0);
break;
}
return EINA_FALSE;
}
static Eina_Bool
_collection_match_attributes_lookup(Eo *obj, struct collection_match_rule *rule)
{
Eina_Bool ret = EINA_FALSE;
Eina_List *obj_attribs;
obj_attribs = efl_access_object_attributes_get(obj);
switch (rule->attributematchtype)
{
case ATSPI_Collection_MATCH_INVALID:
ret = EINA_TRUE;
break;
case ATSPI_Collection_MATCH_ALL:
case ATSPI_Collection_MATCH_ANY:
case ATSPI_Collection_MATCH_NONE:
case ATSPI_Collection_MATCH_EMPTY:
ret = _collection_match_attributes_helper(obj_attribs, rule->attributes, rule->attributematchtype);
break;
default:
DBG("invalid match type");
break;
}
efl_access_attributes_list_free(obj_attribs);
return ret;
}
static int
_collection_sort_order_canonical(struct collection_match_rule *rule, Eina_List **ls,
int count, int max,
Eo *obj, long index, Eina_Bool flag,
Eo *pobj, Eina_Bool recurse, Eina_Bool traverse)
{
int i = index;
Eina_List *children;
children = efl_access_object_access_children_get(obj);
long acount = eina_list_count(children);
Eina_Bool prev = pobj ? EINA_TRUE : EINA_FALSE;
for (; i < acount && (max == 0 || count < max); i++)
{
Eo *child = eina_list_nth(children, i);
if (prev && child == pobj)
{
eina_list_free(children);
return count;
}
if (flag && _collection_match_interfaces_lookup(child, rule)
&& _collection_match_states_lookup(child, rule)
&& _collection_match_roles_lookup(child, rule)
&& _collection_match_attributes_lookup(child, rule))
{
*ls = eina_list_append(*ls, child);
count++;
}
if (!flag)
flag = EINA_TRUE;
if (recurse && traverse)
count = _collection_sort_order_canonical(rule, ls, count,
max, child, 0, EINA_TRUE,
pobj, recurse, traverse);
}
eina_list_free(children);
return count;
}
static int
_collection_sort_order_reverse_canonical(struct collection_match_rule *rule, Eina_List **ls,
int count, int max, Eo *obj, Eina_Bool flag, Eo *pobj)
{
Eo *nextobj, *parent;
long indexinparent;
Eina_List *children;
/* This breaks us out of the recursion. */
if (!obj || obj == pobj)
{
return count;
}
/* Add to the list if it matches */
if (flag && _collection_match_interfaces_lookup(obj, rule)
&& _collection_match_states_lookup(obj, rule)
&& _collection_match_roles_lookup(obj, rule)
&& _collection_match_attributes_lookup(obj, rule)
&& (max == 0 || count < max))
{
*ls = eina_list_append(*ls, obj);
count++;
}
if (!flag)
flag = EINA_TRUE;
/* Get the current nodes index in it's parent and the parent object. */
indexinparent = efl_access_object_index_in_parent_get(obj);
parent = efl_provider_find(efl_parent_get(obj), EFL_ACCESS_OBJECT_MIXIN);
if ((indexinparent > 0) && ((max == 0) || (count < max)))
{
/* there are still some siblings to visit so get the previous sibling
and get it's last descendant.
First, get the previous sibling */
children = efl_access_object_access_children_get(parent);
nextobj = eina_list_nth(children, indexinparent - 1);
eina_list_free(children);
/* Now, drill down the right side to the last descendant */
do {
children = efl_access_object_access_children_get(nextobj);
if (children) nextobj = eina_list_last_data_get(children);
eina_list_free(children);
} while (children);
/* recurse with the last descendant */
count = _collection_sort_order_reverse_canonical(rule, ls, count, max,
nextobj, EINA_TRUE, pobj);
}
else if (max == 0 || count < max)
{
/* no more siblings so next node must be the parent */
count = _collection_sort_order_reverse_canonical(rule, ls, count, max,
parent, EINA_TRUE, pobj);
}
return count;
}
static int
_collection_inbackorder(Eo *collection, struct collection_match_rule *rule, Eina_List **list,
int max, Eo *obj)
{
*list = eina_list_append(*list, obj);
_collection_sort_order_reverse_canonical(rule, list, 0, max, obj, EINA_TRUE, collection);
*list = eina_list_remove_list(*list, *list);
return 0;
}
static int
_collection_inorder(Eo *collection, struct collection_match_rule *rule, Eina_List **list,
int count, int max, Eo *obj, Eina_Bool traverse)
{
int idx = 0;
count = _collection_sort_order_canonical(rule, list, count, max, obj, 0, EINA_TRUE, NULL, EINA_TRUE, traverse);
while ((max == 0 || count < max) && obj && obj != collection)
{
Eo *parent;
parent = efl_provider_find(efl_parent_get(obj), EFL_ACCESS_OBJECT_MIXIN);
idx = efl_access_object_index_in_parent_get(obj);
count = _collection_sort_order_canonical(rule, list, count, max, parent,
idx + 1, EINA_TRUE, NULL, EINA_TRUE, traverse);
obj = parent;
}
if (max == 0 || count < max)
count = _collection_sort_order_canonical(rule, list, count, max,
obj, idx + 1, EINA_TRUE, NULL, EINA_TRUE, traverse);
return count;
}
static int
_collection_query(struct collection_match_rule *rule, AtspiCollectionSortOrder sortby,
Eina_List **list, int count, int max, Eo *obj, long index,
Eina_Bool flag, Eo *pobj, Eina_Bool recurse, Eina_Bool traverse)
{
switch (sortby)
{
case ATSPI_Collection_SORT_ORDER_CANONICAL:
count = _collection_sort_order_canonical(rule, list, 0, max, obj, index, flag,
pobj, recurse, traverse);
break;
case ATSPI_Collection_SORT_ORDER_REVERSE_CANONICAL:
count = _collection_sort_order_canonical(rule, list, 0, max, obj, index, flag,
pobj, recurse, traverse);
*list = eina_list_reverse(*list);
break;
default:
count = 0;
WRN("Unhandled sort method");
break;
}
return count;
}
static Eldbus_Message*
_collection_return_msg_from_list(Elm_Atspi_Bridge *bridge, const Eldbus_Message *msg, const Eina_List *objs)
{
Eldbus_Message *ret;
const Eina_List *l;
Eldbus_Message_Iter *iter, *array_iter;
Eo *obj;
ret = eldbus_message_method_return_new(msg);
if (!ret) return NULL;
iter = eldbus_message_iter_get(ret);
array_iter = eldbus_message_iter_container_new(iter, 'a', "(so)");
EINA_LIST_FOREACH(objs, l, obj)
{
_bridge_object_register(bridge, obj);
_bridge_iter_object_reference_append(bridge, array_iter, obj);
}
eldbus_message_iter_container_close(iter, array_iter);
return ret;
}
static Eina_List*
_collection_get_matches_from_handle(Eo *collection, Eo *current, struct collection_match_rule *rule, AtspiCollectionSortOrder sortby, AtspiCollectionTreeTraversalType tree, int max, Eina_Bool traverse)
{
Eina_List *result = NULL;
Eo *parent;
int idx;
switch (tree)
{
case ATSPI_Collection_TREE_INORDER:
_collection_inorder(collection, rule, &result, 0, max, current, traverse);
if (sortby == ATSPI_Collection_SORT_ORDER_REVERSE_CANONICAL)
result = eina_list_reverse(result);
break;
case ATSPI_Collection_TREE_RESTRICT_CHILDREN:
idx = efl_access_object_index_in_parent_get(current);
parent = efl_provider_find(efl_parent_get(current), EFL_ACCESS_OBJECT_MIXIN);
_collection_query(rule, sortby, &result, 0, max, parent, idx, EINA_FALSE, NULL, EINA_TRUE, traverse);
break;
case ATSPI_Collection_TREE_RESTRICT_SIBLING:
_collection_query(rule, sortby, &result, 0, max, current, 0, EINA_FALSE, NULL, EINA_TRUE, traverse);
break;
default:
ERR("Tree parameter value not handled");
break;
}
return result;
}
static Eldbus_Message*
_collection_get_matches_from(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg EINA_UNUSED)
{
const char *obj_path = eldbus_message_path_get(msg);
Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
Eo *current, *obj = _bridge_object_from_path(bridge, obj_path);
Eldbus_Message *ret;
Eldbus_Message_Iter *iter, *rule_iter;
struct collection_match_rule rule;
int count;
AtspiCollectionTreeTraversalType tree;
Eina_Bool traverse;
AtspiCollectionSortOrder sortby;
Eina_List *result = NULL;
ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_OBJECT_MIXIN, msg);
iter = eldbus_message_iter_get(msg);
EINA_SAFETY_ON_NULL_RETURN_VAL(iter, NULL);
if (!eldbus_message_iter_arguments_get(iter, "o(aiia{ss}iaiiasib)uuib", &obj_path, &rule_iter, &sortby, &tree, &count, &traverse))
{
return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.Failed", "Unable to get matchule, sortby, count or traverse values.");
}
current = _bridge_object_from_path(bridge, obj_path);
ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(current, EFL_ACCESS_OBJECT_MIXIN, msg);
if (!_collection_iter_match_rule_get(rule_iter, &rule))
return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.Failed", "Invalid match rule parameters.");
result = _collection_get_matches_from_handle(obj, current, &rule, sortby, tree, count, traverse);
ret = _collection_return_msg_from_list(bridge, msg, result);
eina_list_free(result);
_collection_match_rule_free(&rule);
return ret;
}
static Eina_List*
_collection_get_matches_to_handle(Eo *obj, Eo *current, struct collection_match_rule *rule, AtspiCollectionSortOrder sortby, AtspiCollectionTreeTraversalType tree, Eina_Bool limit, int max, Eina_Bool traverse)
{
Eina_List *result = NULL;
Eo *collection = obj;
if (limit)
collection = efl_provider_find(efl_parent_get(obj), EFL_ACCESS_OBJECT_MIXIN);
switch (tree)
{
case ATSPI_Collection_TREE_INORDER:
_collection_inbackorder(obj, rule, &result, max, current);
if (sortby == ATSPI_Collection_SORT_ORDER_REVERSE_CANONICAL)
result = eina_list_reverse(result);
break;
case ATSPI_Collection_TREE_RESTRICT_CHILDREN:
_collection_query(rule, sortby, &result, 0, max, collection, 0, EINA_FALSE, current, EINA_TRUE, traverse);
break;
case ATSPI_Collection_TREE_RESTRICT_SIBLING:
_collection_query(rule, sortby, &result, 0, max, collection, 0, EINA_FALSE, current, EINA_TRUE, traverse);
break;
default:
ERR("Tree parameter value not handled");
break;
}
return result;
}
static Eldbus_Message*
_collection_get_matches_to(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg EINA_UNUSED)
{
const char *obj_path = eldbus_message_path_get(msg);
Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
Eo *current, *obj = _bridge_object_from_path(bridge, obj_path);
Eldbus_Message *ret;
Eldbus_Message_Iter *iter, *rule_iter;
struct collection_match_rule rule;
int count;
AtspiCollectionTreeTraversalType tree;
Eina_Bool traverse;
AtspiCollectionSortOrder sortby;
Eina_List *result = NULL;
Eina_Bool limit;
ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_OBJECT_MIXIN, msg);
iter = eldbus_message_iter_get(msg);
EINA_SAFETY_ON_NULL_RETURN_VAL(iter, NULL);
if (!eldbus_message_iter_arguments_get(iter, "o(aiia{ss}iaiiasib)uubib", &obj_path, &rule_iter, &sortby, &tree, &limit, &count, &traverse))
{
return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.Failed", "Unable to get matchule, sortby, tree, limit count or traverse values.");
}
current = _bridge_object_from_path(bridge, obj_path);
ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(current, EFL_ACCESS_OBJECT_MIXIN, msg);
if (!_collection_iter_match_rule_get(rule_iter, &rule))
return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.Failed", "Invalid match rule parameters.");
result = _collection_get_matches_to_handle(obj, current, &rule, sortby, tree, limit, count, traverse);
ret = _collection_return_msg_from_list(bridge, msg, result);
eina_list_free(result);
_collection_match_rule_free(&rule);
return ret;
}
static Eldbus_Message*
_collection_get_matches(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
{
const char *obj_path = eldbus_message_path_get(msg);
Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
Eo *obj = _bridge_object_from_path(bridge, obj_path);
Eldbus_Message *ret;
Eldbus_Message_Iter *iter, *rule_iter;
struct collection_match_rule rule;
int count;
Eina_Bool traverse;
AtspiCollectionSortOrder sortby;
Eina_List *result = NULL;
ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_OBJECT_MIXIN, msg);
iter = eldbus_message_iter_get(msg);
EINA_SAFETY_ON_NULL_RETURN_VAL(iter, NULL);
if (!eldbus_message_iter_arguments_get(iter, "(aiia{ss}iaiiasib)uib", &rule_iter, &sortby, &count, &traverse))
{
return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.Failed", "Unable to get matchule, sortby, count or traverse values.");
}
if (!_collection_iter_match_rule_get(rule_iter, &rule))
return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.Failed", "Invalid match rule parameters.");
_collection_query(&rule, sortby, &result, 0, count, obj, 0, EINA_TRUE, NULL, EINA_TRUE, traverse);
ret = _collection_return_msg_from_list(bridge, msg, result);
eina_list_free(result);
_collection_match_rule_free(&rule);
return ret;
}
static const Eldbus_Method collection_methods[] = {
{ "GetMatchesFrom",
ELDBUS_ARGS({"o", "current_object"}, {"(aiia{ss}iaiiasib)", "match_rule"},
{"u", "sortby"}, {"u", "tree"}, {"i", "count"}, {"b", "traverse"}),
ELDBUS_ARGS({"a(so)", "objects"}), _collection_get_matches_from, 0 },
{ "GetMatchesTo",
ELDBUS_ARGS({"o", "current_object"}, {"(aiia{ss}iaiiasib)", "match_rule"},
{"u", "sortby"}, {"u", "tree"}, {"b", "limit_scope"},
{"i", "count"}, {"b", "traverse"}),
ELDBUS_ARGS({"a(so)", "objects"}), _collection_get_matches_to, 0 },
{ "GetMatches",
ELDBUS_ARGS({"(aiia{ss}iaiiasib)", "match_rule"},
{"u", "sortby"}, {"i", "count"}, {"b", "traverse"}),
ELDBUS_ARGS({"a(so)", "objects"}), _collection_get_matches, 0 },
{ NULL, NULL, NULL, NULL, 0 }
};
static const Eldbus_Service_Interface_Desc collection_iface_desc = {
ATSPI_DBUS_INTERFACE_COLLECTION, collection_methods, NULL, NULL, NULL, NULL
};
static void
_bridge_iter_object_reference_append(Eo *bridge, Eldbus_Message_Iter *iter, const Eo *obj)
{
ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(bridge, pd);
Eldbus_Message_Iter *iter_struct = eldbus_message_iter_container_new(iter, 'r', NULL);
EINA_SAFETY_ON_NULL_RETURN(iter);
const char *path = _path_from_object(obj);
eldbus_message_iter_basic_append(iter_struct, 's', eldbus_connection_unique_name_get(pd->a11y_bus));
eldbus_message_iter_basic_append(iter_struct, 'o', path);
eldbus_message_iter_container_close(iter, iter_struct);
}
static void
_object_desktop_reference_append(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);
eldbus_message_iter_container_close(iter, iter_struct);
}
static void
_iter_interfaces_append(Eldbus_Message_Iter *iter, const Eo *obj)
{
Eldbus_Message_Iter *iter_array;
iter_array = eldbus_message_iter_container_new(iter, 'a', "s");
if (!iter_array) return;
if (efl_isa(obj, EFL_ACCESS_OBJECT_MIXIN))
{
eldbus_message_iter_basic_append(iter_array, 's', ATSPI_DBUS_INTERFACE_ACCESSIBLE);
eldbus_message_iter_basic_append(iter_array, 's', ATSPI_DBUS_INTERFACE_COLLECTION);
}
if (efl_isa(obj, EFL_ACCESS_ACTION_MIXIN))
eldbus_message_iter_basic_append(iter_array, 's', ATSPI_DBUS_INTERFACE_ACTION);
if (efl_isa(obj, ELM_ATSPI_APP_OBJECT_CLASS))
eldbus_message_iter_basic_append(iter_array, 's', ATSPI_DBUS_INTERFACE_APPLICATION);
if (efl_isa(obj, EFL_ACCESS_COMPONENT_MIXIN))
eldbus_message_iter_basic_append(iter_array, 's', ATSPI_DBUS_INTERFACE_COMPONENT);
if (efl_isa(obj, EFL_ACCESS_EDITABLE_TEXT_INTERFACE))
eldbus_message_iter_basic_append(iter_array, 's', ATSPI_DBUS_INTERFACE_EDITABLE_TEXT);
if (efl_isa(obj, EFL_ACCESS_OBJECT_MIXIN))
eldbus_message_iter_basic_append(iter_array, 's', ATSPI_DBUS_INTERFACE_IMAGE);
if (efl_isa(obj, EFL_ACCESS_SELECTION_INTERFACE))
eldbus_message_iter_basic_append(iter_array, 's', ATSPI_DBUS_INTERFACE_SELECTION);
if (efl_isa(obj, EFL_ACCESS_TEXT_INTERFACE))
eldbus_message_iter_basic_append(iter_array, 's', ATSPI_DBUS_INTERFACE_TEXT);
if (efl_isa(obj, EFL_ACCESS_VALUE_INTERFACE))
eldbus_message_iter_basic_append(iter_array, 's', ATSPI_DBUS_INTERFACE_VALUE);
if (efl_isa(obj, EFL_UI_RANGE_DISPLAY_INTERFACE))
eldbus_message_iter_basic_append(iter_array, 's', ATSPI_DBUS_INTERFACE_VALUE);
eldbus_message_iter_container_close(iter, iter_array);
}
static Eina_Bool
_cache_item_reference_append_cb(Eo *bridge, Eo *data, Eldbus_Message_Iter *iter_array)
{
if (!efl_ref_count(data) || efl_destructed_is(data))
return EINA_TRUE;
Eldbus_Message_Iter *iter_struct, *iter_sub_array;
Efl_Access_State_Set states;
Efl_Access_Role role;
Eo *root;
root = efl_access_object_access_root_get();
role = efl_access_object_role_get(data);
iter_struct = eldbus_message_iter_container_new(iter_array, 'r', NULL);
EINA_SAFETY_ON_NULL_RETURN_VAL(iter_struct, EINA_TRUE);
/* Marshall object path */
_bridge_iter_object_reference_append(bridge, iter_struct, data);
/* Marshall application */
_bridge_iter_object_reference_append(bridge, iter_struct, root);
Eo *parent = NULL;
parent = efl_provider_find(efl_parent_get(data), EFL_ACCESS_OBJECT_MIXIN);
/* Marshall parent */
if ((!parent) && (EFL_ACCESS_ROLE_APPLICATION == role))
_object_desktop_reference_append(iter_struct);
else
_bridge_iter_object_reference_append(bridge, iter_struct, parent);
/* Marshall children */
Eina_List *children_list = NULL, *l;
Eo *child;
children_list = efl_access_object_access_children_get(data);
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)
_bridge_iter_object_reference_append(bridge, iter_sub_array, child);
eldbus_message_iter_container_close(iter_struct, iter_sub_array);
eina_list_free(children_list);
/* Marshall interfaces */
_iter_interfaces_append(iter_struct, data);
/* Marshall name */
const char *name = NULL;
name = efl_access_object_i18n_name_get(data);
if (!name)
name = "";
eldbus_message_iter_basic_append(iter_struct, 's', name);
/* Marshall role */
eldbus_message_iter_basic_append(iter_struct, 'u', role);
/* Marshall description */
const char* description = NULL;
description = efl_access_object_description_get(data);
if (!description)
description = "";
eldbus_message_iter_basic_append(iter_struct, 's', description);
/* Marshall state set */
iter_sub_array = eldbus_message_iter_container_new(iter_struct, 'a', "u");
EINA_SAFETY_ON_NULL_GOTO(iter_sub_array, fail);
states = efl_access_object_state_set_get(data);
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, const Eldbus_Message *msg)
{
Eldbus_Message_Iter *iter, *iter_array;
Eldbus_Message *ret;
Eina_List *to_process;
Eo *root;
Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
if (!bridge) return NULL;
ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN_VAL(bridge, pd, NULL);
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', CACHE_ITEM_SIGNATURE);
EINA_SAFETY_ON_NULL_GOTO(iter_array, fail);
root = efl_access_object_access_root_get();
to_process = eina_list_append(NULL, root);
while (to_process)
{
Eo *obj = eina_list_data_get(to_process);
to_process = eina_list_remove_list(to_process, to_process);
_cache_item_reference_append_cb(bridge, obj, iter_array);
_bridge_object_register(bridge, obj);
Eina_List *children;
children = efl_access_object_access_children_get(obj);
to_process = eina_list_merge(to_process, children);
}
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[] = {
{ "GetItems", NULL, ELDBUS_ARGS({CACHE_ITEM_SIGNATURE, "items"}), _cache_get_items, 0 },
{ NULL, NULL, NULL, NULL, 0 }
};
static const Eldbus_Signal cache_signals[] = {
[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}
};
static const Eldbus_Service_Interface_Desc cache_iface_desc = {
ATSPI_DBUS_INTERFACE_CACHE, cache_methods, cache_signals, NULL, NULL, NULL
};
// Component interface
static Eldbus_Message *
_component_contains(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg)
{
const char *obj_path = eldbus_message_path_get(msg);
Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
Eo *obj = _bridge_object_from_path(bridge, obj_path);
int x, y;
2014-04-03 06:45:21 -07:00
Eina_Bool contains = EINA_FALSE;
AtspiCoordType coord_type;
Eldbus_Message *ret;
ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_COMPONENT_MIXIN, msg);
if (!eldbus_message_arguments_get(msg, "iiu", &x, &y, &coord_type))
return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Invalid index type.");
Eina_Bool type = coord_type == ATSPI_COORD_TYPE_SCREEN ? EINA_TRUE : EINA_FALSE;
contains = efl_access_component_contains(obj, type, x, y);
ret = eldbus_message_method_return_new(msg);
EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
eldbus_message_arguments_append(ret, "b", contains);
return ret;
}
static Eldbus_Message *
_component_get_accessible_at_point(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg)
{
const char *obj_path = eldbus_message_path_get(msg);
Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
Eo *obj = _bridge_object_from_path(bridge, obj_path);
int x, y;
Eo *accessible = NULL;
AtspiCoordType coord_type;
Eldbus_Message *ret;
Eldbus_Message_Iter *iter;
ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_COMPONENT_MIXIN, msg);
if (!eldbus_message_arguments_get(msg, "iiu", &x, &y, &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);
Eina_Bool type = coord_type == ATSPI_COORD_TYPE_SCREEN ? EINA_TRUE : EINA_FALSE;
accessible = efl_access_component_accessible_at_point_get(obj, type, x, y);
_bridge_iter_object_reference_append(bridge, iter, accessible);
_bridge_object_register(bridge, accessible);
return ret;
}
static Eldbus_Message *
_component_get_extents(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg)
{
const char *obj_path = eldbus_message_path_get(msg);
Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
Eo *obj = _bridge_object_from_path(bridge, obj_path);
AtspiCoordType coord_type;
Eldbus_Message *ret;
Eldbus_Message_Iter *iter, *iter_struct;
Eina_Rect r;
ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_COMPONENT_MIXIN, msg);
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);
2017-09-13 01:32:35 -07:00
r = efl_access_component_extents_get(obj, (coord_type == ATSPI_COORD_TYPE_SCREEN));
iter_struct = eldbus_message_iter_container_new(iter, 'r', NULL);
EINA_SAFETY_ON_NULL_GOTO(iter_struct, fail);
2017-09-13 01:32:35 -07:00
eldbus_message_iter_basic_append(iter_struct, 'i', r.x);
eldbus_message_iter_basic_append(iter_struct, 'i', r.y);
eldbus_message_iter_basic_append(iter_struct, 'i', r.w);
eldbus_message_iter_basic_append(iter_struct, 'i', r.h);
eldbus_message_iter_container_close(iter, iter_struct);
return ret;
2014-02-09 05:54:19 -08:00
fail:
if (ret) eldbus_message_unref(ret);
return NULL;
}
static Eldbus_Message *
_component_get_position(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg)
{
const char *obj_path = eldbus_message_path_get(msg);
Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
Eo *obj = _bridge_object_from_path(bridge, obj_path);
int x = 1, y = 1;
AtspiCoordType coord_type;
Eldbus_Message *ret;
ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_COMPONENT_MIXIN, msg);
if (!eldbus_message_arguments_get(msg, "u", &coord_type))
return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Invalid index type.");
Eina_Bool type = coord_type == ATSPI_COORD_TYPE_SCREEN ? EINA_TRUE : EINA_FALSE;
if (efl_gfx_entity_visible_get(obj))
{
if (type)
efl_access_component_screen_position_get(obj, &x, &y);
else
evas_object_geometry_get(obj, &x, &y, NULL, NULL);
}
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);
return ret;
}
static Eldbus_Message *
_component_get_size(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg)
{
const char *obj_path = eldbus_message_path_get(msg);
Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
Eo *obj = _bridge_object_from_path(bridge, obj_path);
int x = -1, y = -1;
Eldbus_Message *ret;
ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_COMPONENT_MIXIN, msg);
if (efl_gfx_entity_visible_get(obj))
evas_object_geometry_get(obj, NULL, NULL, &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);
return ret;
}
static AtspiComponentLayer
_elm_layer_2_atspi_layer(int layer)
{
if (layer <= ELM_OBJECT_LAYER_BACKGROUND) return ATSPI_LAYER_CANVAS;
if (layer < ELM_OBJECT_LAYER_FOCUS) return ATSPI_LAYER_WIDGET;
if (layer <= ELM_OBJECT_LAYER_TOOLTIP) return ATSPI_LAYER_POPUP;
return ATSPI_LAYER_OVERLAY;
}
static Eldbus_Message *
_component_get_layer(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg)
{
const char *obj_path = eldbus_message_path_get(msg);
Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
Eo *obj = _bridge_object_from_path(bridge, obj_path);
int layer = -1;
Eldbus_Message *ret;
AtspiComponentLayer atspi_layer;
ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_COMPONENT_MIXIN, msg);
if (efl_gfx_entity_visible_get(obj))
layer = evas_object_layer_get(obj);
ret = eldbus_message_method_return_new(msg);
EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
atspi_layer = _elm_layer_2_atspi_layer(layer);
eldbus_message_arguments_append(ret, "u", atspi_layer);
return ret;
}
static Eldbus_Message *
_component_grab_focus(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg)
{
const char *obj_path = eldbus_message_path_get(msg);
Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
Eo *obj = _bridge_object_from_path(bridge, obj_path);
Eldbus_Message *ret;
2014-04-03 06:45:21 -07:00
Eina_Bool focus = EINA_FALSE;
if (!obj)
return _dbus_invalid_ref_error_new(msg);
focus = efl_access_component_focus_grab(obj);
ret = eldbus_message_method_return_new(msg);
EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
eldbus_message_arguments_append(ret, "b", focus);
return ret;
}
static Eldbus_Message *
_component_get_alpha(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg)
{
const char *obj_path = eldbus_message_path_get(msg);
Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
Eo *obj = _bridge_object_from_path(bridge, obj_path);
Eldbus_Message *ret;
double alpha = -1;
int a;
if (!obj)
return _dbus_invalid_ref_error_new(msg);
if (efl_gfx_entity_visible_get(obj))
{
evas_object_color_get(obj, NULL, NULL, NULL, &a);
alpha = a / 255.0;
}
ret = eldbus_message_method_return_new(msg);
EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
eldbus_message_arguments_append(ret, "d", alpha);
return ret;
}
static Eldbus_Message *
_component_set_extends(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg)
{
const char *obj_path = eldbus_message_path_get(msg);
Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
Eo *obj = _bridge_object_from_path(bridge, obj_path);
AtspiCoordType coord_type;
Eldbus_Message *ret;
2017-09-13 01:32:35 -07:00
int x, y, w, h;
Eina_Bool result = EINA_FALSE;
ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_COMPONENT_MIXIN, msg);
if (!eldbus_message_arguments_get(msg, "iiiiu", &x, &y, &w, &h, &coord_type))
return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Invalid index type.");
Eina_Bool type = coord_type == ATSPI_COORD_TYPE_SCREEN ? EINA_TRUE : EINA_FALSE;
result = efl_access_component_extents_set(obj, type, EINA_RECT(x, y, w, h));
ret = eldbus_message_method_return_new(msg);
EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
eldbus_message_arguments_append(ret, "b", result);
return ret;
}
static Eldbus_Message *
_component_set_position(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg)
{
const char *obj_path = eldbus_message_path_get(msg);
Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
Eo *obj = _bridge_object_from_path(bridge, obj_path);
int x = -1, y = -1;
2014-04-03 06:45:21 -07:00
Eina_Bool result = EINA_FALSE;
AtspiCoordType coord_type;
Eldbus_Message *ret;
ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_COMPONENT_MIXIN, msg);
if (!eldbus_message_arguments_get(msg, "iiu", &x, &y, &coord_type))
return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Invalid index type.");
Eina_Bool type = coord_type == ATSPI_COORD_TYPE_SCREEN ? EINA_TRUE : EINA_FALSE;
if (efl_gfx_entity_visible_get(obj))
{
if (type)
result = efl_access_component_screen_position_set(obj, x, y);
else
{
result = EINA_TRUE;
evas_object_move(obj, x, y);
}
}
ret = eldbus_message_method_return_new(msg);
EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
eldbus_message_arguments_append(ret, "b", result);
return ret;
}
static Eldbus_Message *
_component_set_size(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg)
{
const char *obj_path = eldbus_message_path_get(msg);
Eo *bridge = eldbus_service_object_data_get(iface, ELM_ATSPI_BRIDGE_CLASS_NAME);
Eo *obj = _bridge_object_from_path(bridge, obj_path);
int w, h;
Eina_Bool result = EINA_TRUE;
Eldbus_Message *ret;
ELM_ATSPI_OBJ_CHECK_OR_RETURN_DBUS_ERROR(obj, EFL_ACCESS_COMPONENT_MIXIN, msg);
if (!eldbus_message_arguments_get(msg, "ii", &w, &h))
return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Invalid index type.");
evas_object_resize(obj, w, h);
ret = eldbus_message_method_return_new(msg);
EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
eldbus_message_arguments_append(ret, "b", result);
return ret;
}
static const Eldbus_Method component_methods[] = {
{ "Contains", ELDBUS_ARGS({"i", "x"}, {"i", "y"}, {"u", "coord_type"}), ELDBUS_ARGS({"b", "contains"}), _component_contains, 0 },
{ "GetAccessibleAtPoint", ELDBUS_ARGS({"i", "x"}, {"i", "y"}, {"u", "coord_type"}), ELDBUS_ARGS({"(so)", "accessible"}), _component_get_accessible_at_point, 0 },
{ "GetExtents", ELDBUS_ARGS({"u", "coord_type"}), ELDBUS_ARGS({"(iiii)", "extents"}), _component_get_extents, 0 },
{ "GetPosition", ELDBUS_ARGS({"u", "coord_type"}), ELDBUS_ARGS({"i", "x"}, {"i","y"}), _component_get_position, 0 },
{ "GetSize", NULL, ELDBUS_ARGS({"i", "w"}, {"i", "h"}), _component_get_size, 0 },
{ "GetLayer", NULL, ELDBUS_ARGS({"u", "layer"}), _component_get_layer, 0 },
// { "GetMDIZOrder", NULL, ELDBUS_ARGS({"n", "MDIZOrder"}), _component_get_mdizorder, 0 },
{ "GrabFocus", NULL, ELDBUS_ARGS({"b", "focus"}), _component_grab_focus, 0 },
{ "GetAlpha", NULL, ELDBUS_ARGS({"d", "alpha"}), _component_get_alpha, 0 },
{ "SetExtents", ELDBUS_ARGS({"i", "x"}, {"i", "y"}, {"i", "width"}, {"i", "height"}, {"u", "coord_type"}), ELDBUS_ARGS({"b", "result"}), _component_set_extends, 0 },
{ "SetPosition", ELDBUS_ARGS({"i", "x"}, {"i", "y"}, {"u", "coord_type"}), ELDBUS_ARGS({"b", "result"}), _component_set_position, 0 },
{ "SetSize", ELDBUS_ARGS({"i", "width"}, {"i", "height"}), ELDBUS_ARGS({"b", "result"}), _component_set_size, 0 },
{ NULL, NULL, NULL, NULL, 0 }
};
static const Eldbus_Service_Interface_Desc component_iface_desc = {
ATSPI_DBUS_INTERFACE_COMPONENT, component_methods, NULL, NULL, NULL, NULL
};
static void
_on_elm_atspi_bridge_app_register(void *data EINA_UNUSED, const Eldbus_Message *msg, Eldbus_Pending *pending EINA_UNUSED)
{
const char *errname, *errmsg;
if (eldbus_message_error_get(msg, &errname, &errmsg))
{
ERR("%s %s", errname, errmsg);
return;
}
DBG("Application successfully registered at ATSPI2 bus.");
}
elementary: Rename EAPI macro to ELM_API in Elementary library Patch from a series of patches to rename EAPI symbols to specific library DSOs. = The Rationale = This patch is from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass `__attribute__ ((visibility ("default")))` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as `__atttribute__((visibility("default")))`. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why LIBAPI is the only solution that works for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev>
2020-10-11 09:00:04 -07:00
ELM_API Eina_Bool
_elm_atspi_bridge_app_register(Eo *bridge)
{
Eo *root;
ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN_VAL(bridge, pd, EINA_FALSE);
Eldbus_Message *message = eldbus_message_method_call_new(ATSPI_DBUS_NAME_REGISTRY,
ATSPI_DBUS_PATH_ROOT,
ATSPI_DBUS_INTERFACE_SOCKET,
"Embed");
Eldbus_Message_Iter *iter = eldbus_message_iter_get(message);
root = efl_access_object_access_root_get();
_bridge_iter_object_reference_append(bridge, iter, root);
eldbus_connection_send(pd->a11y_bus, message, _on_elm_atspi_bridge_app_register, NULL, -1);
return EINA_TRUE;
}
elementary: Rename EAPI macro to ELM_API in Elementary library Patch from a series of patches to rename EAPI symbols to specific library DSOs. = The Rationale = This patch is from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass `__attribute__ ((visibility ("default")))` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as `__atttribute__((visibility("default")))`. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why LIBAPI is the only solution that works for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev>
2020-10-11 09:00:04 -07:00
ELM_API Eina_Bool
_elm_atspi_bridge_app_unregister(Eo *bridge)
{
Eo *root;
ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN_VAL(bridge, pd, EINA_FALSE);
root = efl_access_object_access_root_get();
Eldbus_Message *message = eldbus_message_method_call_new(ATSPI_DBUS_NAME_REGISTRY,
ATSPI_DBUS_PATH_ROOT,
ATSPI_DBUS_INTERFACE_SOCKET,
"Unembed");
Eldbus_Message_Iter *iter = eldbus_message_iter_get(message);
_bridge_iter_object_reference_append(bridge, iter, root);
eldbus_connection_send(pd->a11y_bus, message, NULL, NULL, -1);
return EINA_TRUE;
}
static void
_cache_register(Eo *obj)
{
ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(obj, pd);
pd->cache_interface = eldbus_service_interface_register(pd->a11y_bus, CACHE_INTERFACE_PATH, &cache_iface_desc);
eldbus_service_object_data_set(pd->cache_interface, ELM_ATSPI_BRIDGE_CLASS_NAME, obj);
}
static void
_set_broadcast_flag(const char *event, Eo *bridge)
{
char **tokens;
ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(bridge, pd);
tokens = eina_str_split(event, ":", 3);
if (!tokens) return;
if (!strcmp(tokens[0], "Object"))
{
if (!tokens[1] || *tokens[1] == '\0') goto end; // do not handle "Object:*"
else if (!strcmp(tokens[1], "StateChanged"))
{
if (!tokens[2] || *tokens[2] == '\0')
pd->object_state_broadcast_mask = -1; // broadcast all
2015-07-06 14:32:35 -07:00
eina_str_tolower(&tokens[2]);
struct atspi_state_desc *sd = eina_hash_find(pd->state_hash, tokens[2]);
if (sd)
STATE_TYPE_SET(pd->object_state_broadcast_mask, sd->elm_state);
}
else if (!strcmp(tokens[1], "PropertyChange"))
{
if (!tokens[2] || *tokens[2] == '\0')
pd->object_property_broadcast_mask = -1; //broadcast all
else if (!strcmp(tokens[2], "AccessibleValue"))
STATE_TYPE_SET(pd->object_property_broadcast_mask, ATSPI_OBJECT_PROPERTY_VALUE);
else if (!strcmp(tokens[2], "AccessibleName"))
STATE_TYPE_SET(pd->object_property_broadcast_mask, ATSPI_OBJECT_PROPERTY_NAME);
else if (!strcmp(tokens[2], "AccessibleDescription"))
STATE_TYPE_SET(pd->object_property_broadcast_mask, ATSPI_OBJECT_PROPERTY_DESCRIPTION);
else if (!strcmp(tokens[2], "AccessibleParent"))
STATE_TYPE_SET(pd->object_property_broadcast_mask, ATSPI_OBJECT_PROPERTY_PARENT);
else if (!strcmp(tokens[2], "AccessibleRole"))
STATE_TYPE_SET(pd->object_property_broadcast_mask, ATSPI_OBJECT_PROPERTY_ROLE);
}
else if (!strcmp(tokens[1], "ChildrenChanged"))
{
if (!tokens[2] || *tokens[2] == '\0')
pd->object_children_broadcast_mask = -1; // broadcast all
else if (!strcmp(tokens[2], "add"))
STATE_TYPE_SET(pd->object_children_broadcast_mask, ATSPI_OBJECT_CHILD_ADDED);
else if (!strcmp(tokens[2], "remove"))
STATE_TYPE_SET(pd->object_children_broadcast_mask, ATSPI_OBJECT_CHILD_REMOVED);
}
else if (!strcmp(tokens[1], "TextChanged"))
STATE_TYPE_SET(pd->object_broadcast_mask, ATSPI_OBJECT_EVENT_TEXT_CHANGED);
else if (!strcmp(tokens[1], "TextCaretMoved"))
STATE_TYPE_SET(pd->object_broadcast_mask, ATSPI_OBJECT_EVENT_TEXT_CARET_MOVED);
else if (!strcmp(tokens[1], "TextBoundsChanged"))
STATE_TYPE_SET(pd->object_broadcast_mask, ATSPI_OBJECT_EVENT_TEXT_BOUNDS_CHANGED);
else if (!strcmp(tokens[1], "TextSelectionChanged"))
STATE_TYPE_SET(pd->object_broadcast_mask, ATSPI_OBJECT_EVENT_TEXT_SELECTION_CHANGED);
else if (!strcmp(tokens[1], "TextAttributesChanged"))
STATE_TYPE_SET(pd->object_broadcast_mask, ATSPI_OBJECT_EVENT_TEXT_ATTRIBUTES_CHANGED);
else if (!strcmp(tokens[1], "VisibleDataChanged"))
STATE_TYPE_SET(pd->object_broadcast_mask, ATSPI_OBJECT_EVENT_VISIBLE_DATA_CHANGED);
2015-10-19 04:39:56 -07:00
else if (!strcmp(tokens[1], "ActiveDescendantChanged"))
STATE_TYPE_SET(pd->object_broadcast_mask, ATSPI_OBJECT_EVENT_ACTIVE_DESCENDANT_CHANGED);
2015-11-27 09:14:54 -08:00
else if (!strcmp(tokens[1], "SelectionChanged"))
STATE_TYPE_SET(pd->object_broadcast_mask, ATSPI_OBJECT_EVENT_SELECTION_CHANGED);
else if (!strcmp(tokens[1], "BoundsChanged"))
STATE_TYPE_SET(pd->object_broadcast_mask, ATSPI_OBJECT_EVENT_BOUNDS_CHANGED);
}
else if (!strcmp(tokens[0], "Window"))
{
if (!tokens[1] || *tokens[1] == '\0')
pd->window_signal_broadcast_mask = -1; // broadcast all
else if (!strcmp(tokens[1], "Create"))
STATE_TYPE_SET(pd->window_signal_broadcast_mask, ATSPI_WINDOW_EVENT_CREATE);
else if (!strcmp(tokens[1], "Destroy"))
STATE_TYPE_SET(pd->window_signal_broadcast_mask, ATSPI_WINDOW_EVENT_DESTROY);
else if (!strcmp(tokens[1], "Activate"))
STATE_TYPE_SET(pd->window_signal_broadcast_mask, ATSPI_WINDOW_EVENT_ACTIVATE);
else if (!strcmp(tokens[1], "Deactivate"))
STATE_TYPE_SET(pd->window_signal_broadcast_mask, ATSPI_WINDOW_EVENT_DEACTIVATE);
else if (!strcmp(tokens[1], "Maximize"))
STATE_TYPE_SET(pd->window_signal_broadcast_mask, ATSPI_WINDOW_EVENT_MAXIMIZE);
else if (!strcmp(tokens[1], "Minimize"))
STATE_TYPE_SET(pd->window_signal_broadcast_mask, ATSPI_WINDOW_EVENT_MINIMIZE);
else if (!strcmp(tokens[1], "Resize"))
STATE_TYPE_SET(pd->window_signal_broadcast_mask, ATSPI_WINDOW_EVENT_RESIZE);
else if (!strcmp(tokens[1], "Restore"))
STATE_TYPE_SET(pd->window_signal_broadcast_mask, ATSPI_WINDOW_EVENT_RESTORE);
}
end:
free(tokens[0]);
free(tokens);
}
static void
_registered_listeners_get(void *data, const Eldbus_Message *msg, Eldbus_Pending *pending)
{
const char *event, *bus;
ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(data, pd);
pd->pending_requests = eina_list_remove(pd->pending_requests, pending);
DBG("Updating registered ATSPI signals list.");
pd->object_broadcast_mask = 0;
pd->object_children_broadcast_mask = 0;
pd->object_property_broadcast_mask = 0;
pd->object_state_broadcast_mask = 0;
pd->window_signal_broadcast_mask = 0;
if (eldbus_message_error_get(msg, &event, &bus))
{
WRN("%s %s", event, bus);
return;
}
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))
{
if (!eldbus_message_iter_arguments_get(siter, "ss", &bus, &event))
ERR("Cannot get bus and event from registered listener");
else _set_broadcast_flag(event, data);
}
if (!pd->connected)
efl_event_callback_legacy_call(data, ELM_ATSPI_BRIDGE_EVENT_CONNECTED, NULL);
pd->connected = EINA_TRUE;
}
static void
_registered_events_list_update(Eo *bridge)
{
Eldbus_Message *msg;
ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(bridge, pd);
Eldbus_Pending *p;
msg = eldbus_message_method_call_new(ATSPI_DBUS_NAME_REGISTRY, ATSPI_DBUS_PATH_REGISTRY, ATSPI_DBUS_INTERFACE_REGISTRY, "GetRegisteredEvents");
p = eldbus_connection_send(pd->a11y_bus, msg, _registered_listeners_get, bridge, -1);
pd->pending_requests = eina_list_append(pd->pending_requests, p);
}
static void
_handle_listener_change(void *data, const Eldbus_Message *msg EINA_UNUSED)
{
_registered_events_list_update(data);
}
static void
_state_changed_signal_send(void *data, const Efl_Event *event)
{
Efl_Access_Event_State_Changed_Data *state_data = event->info;
2015-07-06 14:32:35 -07:00
const char *type_desc;
ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(data, pd);
if (!STATE_TYPE_GET(pd->object_state_broadcast_mask, state_data->type))
{
efl_event_callback_stop(event->object);
return;
}
if ((state_data->type > EFL_ACCESS_STATE_TYPE_LAST_DEFINED) ||
2015-07-29 07:21:17 -07:00
(int)state_data->type < 0)
{
efl_event_callback_stop(event->object);
return;
}
2015-07-06 14:32:35 -07:00
type_desc = elm_states_to_atspi_state[state_data->type].name;
_bridge_signal_send(data, event->object, ATSPI_DBUS_INTERFACE_EVENT_OBJECT,
&_event_obj_signals[ATSPI_OBJECT_EVENT_STATE_CHANGED], type_desc, state_data->new_value, 0, NULL);
}
static void
_bounds_changed_signal_send(void *data, const Efl_Event *event)
{
Efl_Access_Event_Geometry_Changed_Data *geo_data = event->info;
_bridge_signal_send(data, event->object, ATSPI_DBUS_INTERFACE_EVENT_OBJECT,
&_event_obj_signals[ATSPI_OBJECT_EVENT_BOUNDS_CHANGED], "", 0, 0, "(iiii)",
geo_data->x, geo_data->y, geo_data->width, geo_data->height);
}
static void
_property_changed_signal_send(void *data, const Efl_Event *event)
{
const char *property = event->info;
char *atspi_desc;
enum _Atspi_Object_Property prop = ATSPI_OBJECT_PROPERTY_LAST;
ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(data, pd);
if (!strcmp(property, "parent"))
{
prop = ATSPI_OBJECT_PROPERTY_PARENT;
atspi_desc = "accessible-parent";
}
2018-02-14 18:14:52 -08:00
else if (!strcmp(property, "i18n_name"))
{
prop = ATSPI_OBJECT_PROPERTY_NAME;
atspi_desc = "accessible-name";
}
else if (!strcmp(property, "description"))
{
prop = ATSPI_OBJECT_PROPERTY_DESCRIPTION;
atspi_desc = "accessible-description";
}
else if (!strcmp(property, "role"))
{
prop = ATSPI_OBJECT_PROPERTY_ROLE;
atspi_desc = "accessible-role";
}
else if (!strcmp(property, "value"))
{
prop = ATSPI_OBJECT_PROPERTY_VALUE;
atspi_desc = "accessible-value";
}
if (prop == ATSPI_OBJECT_PROPERTY_LAST)
{
ERR("Unrecognized property name!");
efl_event_callback_stop(event->object);
return;
}
if (!STATE_TYPE_GET(pd->object_property_broadcast_mask, prop))
{
DBG("Masking property %s changed event.", property);
efl_event_callback_stop(event->object);
return;
}
_bridge_signal_send(data, event->object, ATSPI_DBUS_INTERFACE_EVENT_OBJECT,
&_event_obj_signals[ATSPI_OBJECT_EVENT_PROPERTY_CHANGED], atspi_desc, 0, 0, NULL);
}
static void
_value_property_changed_signal_send(void *data, const Efl_Event *event)
{
ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(data, pd);
_bridge_signal_send(data, event->object, ATSPI_DBUS_INTERFACE_EVENT_OBJECT,
&_event_obj_signals[ATSPI_OBJECT_EVENT_PROPERTY_CHANGED], "accessible-value", 0, 0, NULL);
}
static void
_visible_data_changed_signal_send(void *data, const Efl_Event *event)
{
ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(data, pd);
if (!STATE_TYPE_GET(pd->object_broadcast_mask, ATSPI_OBJECT_EVENT_VISIBLE_DATA_CHANGED))
{
efl_event_callback_stop(event->object);
return;
}
_bridge_signal_send(data, event->object, ATSPI_DBUS_INTERFACE_EVENT_OBJECT,
&_event_obj_signals[ATSPI_OBJECT_EVENT_VISIBLE_DATA_CHANGED], "",
0, 0, NULL);
}
static void
_active_descendant_changed_signal_send(void *data, const Efl_Event *event)
{
Eo *child = event->info;
int idx;
ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(data, pd);
if (!STATE_TYPE_GET(pd->object_broadcast_mask, ATSPI_OBJECT_EVENT_ACTIVE_DESCENDANT_CHANGED))
{
efl_event_callback_stop(event->object);
return;
}
idx = efl_access_object_index_in_parent_get(child);
_bridge_signal_send(data, event->object, ATSPI_DBUS_INTERFACE_EVENT_OBJECT,
&_event_obj_signals[ATSPI_OBJECT_EVENT_ACTIVE_DESCENDANT_CHANGED], "",
idx, 0, "(so)", eldbus_connection_unique_name_get(pd->a11y_bus), child);
}
static void
_children_changed_signal_send(void *data, const Efl_Event *event)
{
const char *atspi_desc = NULL;
Efl_Access_Event_Children_Changed_Data *ev_data = event->info;
int idx;
enum _Atspi_Object_Child_Event_Type type;
ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(data, pd);
if (ev_data->is_added)
{
type = ATSPI_OBJECT_CHILD_ADDED;
atspi_desc = "add";
}
else
{
type = ATSPI_OBJECT_CHILD_REMOVED;
atspi_desc = "remove";
}
if (!STATE_TYPE_GET(pd->object_children_broadcast_mask, type))
{
efl_event_callback_stop(event->object);
return;
}
idx = efl_access_object_index_in_parent_get(ev_data->child);
_bridge_signal_send(data, event->object, ATSPI_DBUS_INTERFACE_EVENT_OBJECT,
&_event_obj_signals[ATSPI_OBJECT_EVENT_CHILDREN_CHANGED], atspi_desc,
idx, 0, "(so)", eldbus_connection_unique_name_get(pd->a11y_bus), ev_data->child);
}
static void
_window_signal_send(void *data, const Efl_Event *event)
{
enum _Atspi_Window_Signals type;
ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(data, pd);
if (event->desc == EFL_ACCESS_WINDOW_EVENT_WINDOW_CREATED)
type = ATSPI_WINDOW_EVENT_CREATE;
else if (event->desc == EFL_ACCESS_WINDOW_EVENT_WINDOW_DESTROYED)
type = ATSPI_WINDOW_EVENT_DESTROY;
else if (event->desc == EFL_ACCESS_WINDOW_EVENT_WINDOW_DEACTIVATED)
type = ATSPI_WINDOW_EVENT_DEACTIVATE;
else if (event->desc == EFL_ACCESS_WINDOW_EVENT_WINDOW_ACTIVATED)
type = ATSPI_WINDOW_EVENT_ACTIVATE;
else if (event->desc == EFL_ACCESS_WINDOW_EVENT_WINDOW_MAXIMIZED)
type = ATSPI_WINDOW_EVENT_MAXIMIZE;
else if (event->desc == EFL_ACCESS_WINDOW_EVENT_WINDOW_MINIMIZED)
type = ATSPI_WINDOW_EVENT_MINIMIZE;
else if (event->desc == EFL_ACCESS_WINDOW_EVENT_WINDOW_RESTORED)
type = ATSPI_WINDOW_EVENT_RESTORE;
else
{
efl_event_callback_stop(event->object);
return;
}
if (!STATE_TYPE_GET(pd->window_signal_broadcast_mask, type))
{
efl_event_callback_stop(event->object);
return;
}
if (!pd->a11y_bus)
{
ERR("A11Y connection closed. Unable to send ATSPI event.");
efl_event_callback_stop(event->object);
return;
}
_bridge_signal_send(data, event->object, ATSPI_DBUS_INTERFACE_EVENT_WINDOW,
&_window_obj_signals[type], "", 0, 0, "i", 0);
}
static void
_selection_signal_send(void *data, const Efl_Event *event)
{
ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(data, pd);
if (!STATE_TYPE_GET(pd->object_broadcast_mask, ATSPI_OBJECT_EVENT_SELECTION_CHANGED))
{
efl_event_callback_stop(event->object);
return;
}
_bridge_signal_send(data, event->object, ATSPI_DBUS_INTERFACE_EVENT_OBJECT,
&_event_obj_signals[ATSPI_OBJECT_EVENT_SELECTION_CHANGED], "", 0, 0, "i", 0);
}
static void _bridge_signal_send(Eo *bridge, Eo *obj, const char *infc, const Eldbus_Signal *signal, const char *minor, unsigned int det1, unsigned int det2, const char *variant_sig, ...)
{
Eldbus_Message *msg;
Eldbus_Message_Iter *iter , *iter_stack[64], *iter_struct;
va_list va;
Eo *atspi_obj, *root;
const char *path;
int top = 0;
EINA_SAFETY_ON_NULL_RETURN(infc);
EINA_SAFETY_ON_NULL_RETURN(signal);
EINA_SAFETY_ON_NULL_RETURN(minor);
EINA_SAFETY_ON_NULL_RETURN(obj);
ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(bridge, pd);
path = _path_from_object(obj);
root = efl_access_object_access_root_get();
msg = eldbus_message_signal_new(path, infc, signal->name);
if (!msg) return;
va_start(va, variant_sig);
iter = eldbus_message_iter_get(msg);
eldbus_message_iter_arguments_append(iter, "sii", minor, det1, det2);
if (variant_sig)
{
iter_stack[top] = eldbus_message_iter_container_new(iter, 'v', variant_sig);
const char *tmp = variant_sig;
while (*tmp)
{
switch (*tmp)
{
case '(':
iter_stack[top + 1] = eldbus_message_iter_container_new(iter_stack[top], 'r', NULL);
top++;
break;
case 's':
eldbus_message_iter_basic_append(iter_stack[top], 's', va_arg(va, char*));
break;
case 'i':
eldbus_message_iter_basic_append(iter_stack[top], 'i', va_arg(va, int));
break;
case 'o':
atspi_obj = va_arg(va, Eo*);
path = _path_from_object(atspi_obj);
eldbus_message_iter_basic_append(iter_stack[top], 'o', path);
break;
case ')':
eldbus_message_iter_container_close(iter_stack[top - 1], iter_stack[top]);
top--;
break;
default:
ERR("Not supported d-bus type: %c.", *tmp);
break;
}
tmp++;
}
}
else // AT-SPI implementation forces checks on variant in signature even if not used.
{
iter_stack[top] = eldbus_message_iter_container_new(iter, 'v', "i");
eldbus_message_iter_basic_append(iter_stack[top], 'i', 0);
}
va_end(va);
if (top != 0)
ERR("Invalid d-bus signature: () do not match.");
eldbus_message_iter_container_close(iter, iter_stack[0]);
iter_struct = eldbus_message_iter_container_new(iter, 'r', NULL);
path = _path_from_object(root);
eldbus_message_iter_basic_append(iter_struct, 's', eldbus_connection_unique_name_get(pd->a11y_bus));
eldbus_message_iter_basic_append(iter_struct, 'o', path);
eldbus_message_iter_container_close(iter, iter_struct);
eldbus_connection_send(pd->a11y_bus, msg, NULL, NULL, -1);
DBG("Send %s.%s[%s,%d,%d]", infc, signal->name, minor, det1, det2);
}
static void
_text_caret_moved_send(void *data, const Efl_Event *event)
{
int cursor_pos = 0;
ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(data, pd);
if (!STATE_TYPE_GET(pd->object_broadcast_mask, ATSPI_OBJECT_EVENT_TEXT_CARET_MOVED))
return;
cursor_pos = efl_access_text_caret_offset_get(event->object);
_bridge_signal_send(data, event->object, ATSPI_DBUS_INTERFACE_EVENT_OBJECT,
&_event_obj_signals[ATSPI_OBJECT_EVENT_TEXT_CARET_MOVED], "", cursor_pos, 0, NULL);
}
static void
_text_text_inserted_send(void *data, const Efl_Event *event)
{
Efl_Access_Text_Change_Info *info = event->info;
ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(data, pd);
if (!STATE_TYPE_GET(pd->object_broadcast_mask, ATSPI_OBJECT_EVENT_TEXT_CHANGED))
return;
if (!info->content)
{
WRN("Try to send signal with NULL value");
return;
}
_bridge_signal_send(data, event->object, ATSPI_DBUS_INTERFACE_EVENT_OBJECT,
&_event_obj_signals[ATSPI_OBJECT_EVENT_TEXT_CHANGED], "insert", info->pos, info->len, "s", info->content);
}
static void
_text_text_removed_send(void *data, const Efl_Event *event)
{
Efl_Access_Text_Change_Info *info = event->info;
ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(data, pd);
if (!STATE_TYPE_GET(pd->object_broadcast_mask, ATSPI_OBJECT_EVENT_TEXT_CHANGED))
return;
if (!info->content)
{
WRN("Try to send signal with NULL value");
return;
}
_bridge_signal_send(data, event->object, ATSPI_DBUS_INTERFACE_EVENT_OBJECT,
&_event_obj_signals[ATSPI_OBJECT_EVENT_TEXT_CHANGED], "delete", info->pos, info->len, "s", info->content);
}
static void
_text_selection_changed_send(void *data, const Efl_Event *event)
{
ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(data, pd);
if (!STATE_TYPE_GET(pd->object_broadcast_mask, ATSPI_OBJECT_EVENT_TEXT_SELECTION_CHANGED))
return;
_bridge_signal_send(data, event->object, ATSPI_DBUS_INTERFACE_EVENT_OBJECT,
&_event_obj_signals[ATSPI_OBJECT_EVENT_TEXT_SELECTION_CHANGED], "", 0, 0, NULL);
}
static void
_event_handlers_register(Eo *bridge)
{
ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(bridge, pd);
_registered_events_list_update(bridge);
// register signal handlers in order to update list of registered listeners of ATSPI-Clients
pd->register_hdl = eldbus_signal_handler_add(pd->a11y_bus, ATSPI_DBUS_NAME_REGISTRY, ATSPI_DBUS_PATH_REGISTRY, ATSPI_DBUS_INTERFACE_REGISTRY, "EventListenerRegistered", _handle_listener_change, bridge);
pd->unregister_hdl = eldbus_signal_handler_add(pd->a11y_bus, ATSPI_DBUS_NAME_REGISTRY, ATSPI_DBUS_PATH_REGISTRY, ATSPI_DBUS_INTERFACE_REGISTRY, "EventListenerDeregistered", _handle_listener_change, bridge);
pd->key_flr = ecore_event_filter_add(NULL, _elm_atspi_bridge_key_filter, NULL, bridge);
}
static void
_bridge_object_unregister(Eo *bridge, Eo *obj)
{
ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(bridge, pd);
eina_hash_del(pd->cache, &obj, obj);
}
static void
_on_object_add(void *data, const Efl_Event *event)
{
Eldbus_Message *sig;
Eldbus_Message_Iter *iter;
ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(data, pd);
sig = eldbus_service_signal_new(pd->cache_interface, ATSPI_OBJECT_CHILD_ADDED);
iter = eldbus_message_iter_get(sig);
_cache_item_reference_append_cb(data, event->object, iter);
eldbus_service_signal_send(pd->cache_interface, sig);
}
static void
_on_object_del(void *data, const Efl_Event *event)
{
Eldbus_Message *sig;
ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(data, pd);
_bridge_object_unregister(data, event->object);
sig = eldbus_service_signal_new(pd->cache_interface, ATSPI_OBJECT_CHILD_REMOVED);
Eldbus_Message_Iter *iter = eldbus_message_iter_get(sig);
_bridge_iter_object_reference_append(data, iter, event->object);
eldbus_service_signal_send(pd->cache_interface, sig);
}
static void
_interfaces_unregister(Eo *bridge)
{
ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(bridge, pd);
#define INTERFACE_SAFE_FREE(ifc) \
if (ifc) \
eldbus_service_interface_unregister(ifc); \
ifc = NULL;
INTERFACE_SAFE_FREE(pd->interfaces.accessible);
INTERFACE_SAFE_FREE(pd->interfaces.application);
INTERFACE_SAFE_FREE(pd->interfaces.action);
INTERFACE_SAFE_FREE(pd->interfaces.component);
INTERFACE_SAFE_FREE(pd->interfaces.collection);
INTERFACE_SAFE_FREE(pd->interfaces.editable_text);
INTERFACE_SAFE_FREE(pd->interfaces.image);
INTERFACE_SAFE_FREE(pd->interfaces.selection);
INTERFACE_SAFE_FREE(pd->interfaces.text);
INTERFACE_SAFE_FREE(pd->interfaces.value);
}
static void
_a11y_connection_shutdown(Eo *bridge)
{
ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(bridge, pd);
Eldbus_Pending *pending;
if (pd->connected)
_elm_atspi_bridge_app_unregister(bridge);
if (pd->cache)
eina_hash_free(pd->cache);
pd->cache = NULL;
if (pd->cache_interface)
eldbus_service_object_unregister(pd->cache_interface);
pd->cache_interface = NULL;
_interfaces_unregister(bridge);
if (pd->key_flr) ecore_event_filter_del(pd->key_flr);
pd->key_flr = NULL;
if (pd->register_hdl) eldbus_signal_handler_del(pd->register_hdl);
pd->register_hdl = NULL;
if (pd->unregister_hdl) eldbus_signal_handler_del(pd->unregister_hdl);
pd->unregister_hdl = NULL;
EINA_LIST_FREE(pd->pending_requests, pending)
eldbus_pending_cancel(pending);
pd->pending_requests = NULL;
if (pd->a11y_bus) eldbus_connection_unref(pd->a11y_bus);
pd->a11y_bus = NULL;
2015-07-06 14:32:35 -07:00
if (pd->state_hash) eina_hash_free(pd->state_hash);
pd->state_hash = NULL;
if (pd->event_hash) eina_hash_free(pd->event_hash);
pd->event_hash = NULL;
efl_access_object_event_handler_del(pd->event_hdlr);
pd->event_hdlr = NULL;
efl_event_callback_legacy_call(bridge, ELM_ATSPI_BRIDGE_EVENT_DISCONNECTED, NULL);
pd->connected = EINA_FALSE;
}
static void _disconnect_cb(void *data, Eldbus_Connection *conn EINA_UNUSED, void *event_info EINA_UNUSED)
{
_a11y_connection_shutdown(data);
}
static void
_interfaces_register(Eo *bridge)
{
ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(bridge, pd);
pd->interfaces.accessible =
eldbus_service_interface_fallback_register(pd->a11y_bus, ELM_ACCESS_OBJECT_PATH_PREFIX2, &accessible_iface_desc);
eldbus_service_object_data_set(pd->interfaces.accessible, ELM_ATSPI_BRIDGE_CLASS_NAME, bridge);
pd->interfaces.application =
eldbus_service_interface_fallback_register(pd->a11y_bus, ELM_ACCESS_OBJECT_PATH_PREFIX2, &application_iface_desc);
eldbus_service_object_data_set(pd->interfaces.application, ELM_ATSPI_BRIDGE_CLASS_NAME, bridge);
pd->interfaces.action =
eldbus_service_interface_fallback_register(pd->a11y_bus, ELM_ACCESS_OBJECT_PATH_PREFIX2, &action_iface_desc);
eldbus_service_object_data_set(pd->interfaces.action, ELM_ATSPI_BRIDGE_CLASS_NAME, bridge);
pd->interfaces.component =
eldbus_service_interface_fallback_register(pd->a11y_bus, ELM_ACCESS_OBJECT_PATH_PREFIX2, &component_iface_desc);
eldbus_service_object_data_set(pd->interfaces.component, ELM_ATSPI_BRIDGE_CLASS_NAME, bridge);
pd->interfaces.collection =
eldbus_service_interface_fallback_register(pd->a11y_bus, ELM_ACCESS_OBJECT_PATH_PREFIX2, &collection_iface_desc);
eldbus_service_object_data_set(pd->interfaces.collection, ELM_ATSPI_BRIDGE_CLASS_NAME, bridge);
pd->interfaces.editable_text =
eldbus_service_interface_fallback_register(pd->a11y_bus, ELM_ACCESS_OBJECT_PATH_PREFIX2, &editable_text_iface_desc);
eldbus_service_object_data_set(pd->interfaces.editable_text, ELM_ATSPI_BRIDGE_CLASS_NAME, bridge);
pd->interfaces.image =
eldbus_service_interface_fallback_register(pd->a11y_bus, ELM_ACCESS_OBJECT_PATH_PREFIX2, &image_iface_desc);
eldbus_service_object_data_set(pd->interfaces.image, ELM_ATSPI_BRIDGE_CLASS_NAME, bridge);
pd->interfaces.selection =
eldbus_service_interface_fallback_register(pd->a11y_bus, ELM_ACCESS_OBJECT_PATH_PREFIX2, &selection_iface_desc);
eldbus_service_object_data_set(pd->interfaces.selection, ELM_ATSPI_BRIDGE_CLASS_NAME, bridge);
pd->interfaces.text =
eldbus_service_interface_fallback_register(pd->a11y_bus, ELM_ACCESS_OBJECT_PATH_PREFIX2, &text_iface_desc);
eldbus_service_object_data_set(pd->interfaces.text, ELM_ATSPI_BRIDGE_CLASS_NAME, bridge);
pd->interfaces.value =
eldbus_service_interface_fallback_register(pd->a11y_bus, ELM_ACCESS_OBJECT_PATH_PREFIX2, &value_iface_desc);
eldbus_service_object_data_set(pd->interfaces.value, ELM_ATSPI_BRIDGE_CLASS_NAME, bridge);
}
static void
_bridge_accessible_event_dispatch(void *data, const Efl_Event *event)
{
ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(data, pd);
_bridge_object_register(data, event->object);
Efl_Event_Cb cb = eina_hash_find(pd->event_hash, &event->desc);
return cb ? cb(data, event) : EINA_TRUE;
}
static void
_a11y_bus_initialize(Eo *obj, const char *socket_addr)
{
ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(obj, pd);
pd->a11y_bus = eldbus_private_address_connection_get(socket_addr);
if (!pd->a11y_bus)
return;
eldbus_connection_event_callback_add(pd->a11y_bus, ELDBUS_CONNECTION_EVENT_DISCONNECTED, _disconnect_cb, obj);
// init data structures
pd->cache = eina_hash_pointer_new(NULL);
2015-07-06 14:32:35 -07:00
pd->state_hash = _elm_atspi_state_hash_build();
pd->event_hash = _elm_atspi_event_hash_build();
// dbus init
_cache_register(obj);
_interfaces_register(obj);
_event_handlers_register(obj);
_elm_atspi_bridge_app_register(obj);
// register accessible object event listener
pd->event_hdlr = efl_access_object_event_handler_add(_bridge_accessible_event_dispatch, obj);
}
static void
_a11y_bus_address_get(void *data, const Eldbus_Message *msg, Eldbus_Pending *pending)
{
const char *errname, *errmsg, *sock_addr = NULL;
ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(data, pd);
pd->pending_requests = eina_list_remove(pd->pending_requests, pending);
if (eldbus_message_error_get(msg, &errname, &errmsg))
{
ERR("%s %s", errname, errmsg);
return;
}
if (!eldbus_message_arguments_get(msg, "s", &sock_addr) || !sock_addr)
{
ERR("Could not get A11Y Bus socket address.");
return;
}
_a11y_bus_initialize((Eo*)data, sock_addr);
}
static void _a11y_connection_init(Eo *bridge)
{
ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(bridge, pd);
Eina_Bool is_connected;
is_connected = elm_obj_atspi_bridge_connected_get(bridge);
if (is_connected) return;
Eldbus_Message *m = eldbus_object_method_call_new(pd->bus_obj, A11Y_DBUS_INTERFACE, "GetAddress");
Eldbus_Pending *p = eldbus_object_send(pd->bus_obj, m, _a11y_bus_address_get, bridge, 100);
if (p)
pd->pending_requests = eina_list_append(pd->pending_requests, p);
}
static void
_screen_reader_enabled_get(void *data, const Eldbus_Message *msg, Eldbus_Pending *pending)
{
ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(data, pd);
const char *errname, *errmsg;
Eina_Bool is_enabled;
Eldbus_Message_Iter *variant;
pd->pending_requests = eina_list_remove(pd->pending_requests, pending);
if (eldbus_message_error_get(msg, &errname, &errmsg))
{
/* don't print warnings for user-canceled calls */
if (!eina_streq(errname, "org.enlightenment.DBus.Canceled"))
WRN("%s %s", errname, errmsg);
return;
}
if (!eldbus_message_arguments_get(msg, "v", &variant))
{
ERR("'ScreenReaderEnabled' not packed into variant.");
return;
}
if (!eldbus_message_iter_arguments_get(variant, "b", &is_enabled))
{
ERR("Could not get 'ScreenReaderEnabled' boolean property");
return;
}
if (is_enabled)
_a11y_connection_init(data);
else
DBG("AT-SPI2 stack not enabled.");
}
static void _bridge_object_register(Eo *bridge, Eo *obj)
{
ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(bridge, pd);
if (!efl_isa(obj, EFL_ACCESS_OBJECT_MIXIN))
{
WRN("Unable to register class w/o Efl_Access_Object!");
return;
}
if (eina_hash_find(pd->cache, &obj))
return;
eina_hash_add(pd->cache, &obj, obj);
}
void
_elm_atspi_bridge_init(void)
{
if (!_init_count)
{
_instance = efl_add_ref(ELM_ATSPI_BRIDGE_CLASS, NULL);
_init_count = 1;
}
}
elementary: Rename EAPI macro to ELM_API in Elementary library Patch from a series of patches to rename EAPI symbols to specific library DSOs. = The Rationale = This patch is from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass `__attribute__ ((visibility ("default")))` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as `__atttribute__((visibility("default")))`. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why LIBAPI is the only solution that works for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev>
2020-10-11 09:00:04 -07:00
ELM_API Eo*
_elm_atspi_bridge_get(void)
{
return _instance;
}
void
_elm_atspi_bridge_shutdown(void)
{
if (_init_count)
{
efl_unref(_instance);
_init_count = 0;
}
_efl_access_shutdown();
}
static Key_Event_Info*
_key_event_info_new(int event_type, const Ecore_Event_Key *data, Eo *bridge)
{
Key_Event_Info *ret;
EINA_SAFETY_ON_NULL_RETURN_VAL(data, NULL);
ret = calloc(1, sizeof(Key_Event_Info));
ret->type = event_type;
ret->event = *data;
ret->bridge = bridge;
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);
ret->event.modifiers = data->modifiers;
// not sure why it is here, but explicite keep it NULLed.
ret->event.data = NULL;
return ret;
}
static void
_key_event_info_free(Key_Event_Info *data)
{
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);
free(data);
}
static short
_ecore_modifiers_2_atspi(unsigned int modifiers)
{
short ret = 0;
if (modifiers & ECORE_EVENT_MODIFIER_SHIFT)
ret |= (1 << ATSPI_MODIFIER_SHIFT);
if (modifiers & ECORE_EVENT_MODIFIER_CAPS)
ret |= (1 << ATSPI_MODIFIER_SHIFTLOCK);
if (modifiers & ECORE_EVENT_MODIFIER_CTRL)
ret |= (1 << ATSPI_MODIFIER_CONTROL);
if (modifiers & ECORE_EVENT_MODIFIER_ALT)
ret |= (1 << ATSPI_MODIFIER_ALT);
if (modifiers & ECORE_EVENT_MODIFIER_WIN)
2015-11-21 07:19:53 -08:00
ret |= (1 << ATSPI_MODIFIER_META);
if (modifiers & ECORE_EVENT_MODIFIER_NUM)
ret |= (1 << ATSPI_MODIFIER_NUMLOCK);
return ret;
}
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 = 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, "uinnisb", type, 0, data->event.keycode, _ecore_modifiers_2_atspi(data->event.modifiers), data->event.timestamp, str, is_text);
eldbus_message_iter_container_close(iter, struct_iter);
}
static Eina_Bool
_elm_atspi_bridge_key_filter(void *data, void *loop EINA_UNUSED, int type, void *event)
{
Ecore_Event_Key *key_event = event;
Key_Event_Info *ke;
Eldbus_Object *dobj;
Eldbus_Proxy *proxy;
Eldbus_Message *req;
Eldbus_Message_Iter *iter;
Eldbus_Message *reply;
Eina_Bool ret = EINA_TRUE;
const char *errname = NULL, *errmsg = NULL;
Eo *bridge = data;
ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN_VAL(bridge, pd, EINA_TRUE);
if ((type != ECORE_EVENT_KEY_DOWN) && (type != ECORE_EVENT_KEY_UP)) return EINA_TRUE;
if (!(dobj = eldbus_object_get(pd->a11y_bus, ATSPI_DBUS_NAME_REGISTRY, ATSPI_DBUS_PATH_DEC)))
{
ERR("Failed to create eldbus object for: " ATSPI_DBUS_PATH_DEC);
return EINA_TRUE;
}
if (!(proxy = eldbus_proxy_get(dobj, ATSPI_DBUS_INTERFACE_DEC)))
{
ERR("Failed to create proxy object for: " ATSPI_DBUS_INTERFACE_DEC);
return EINA_TRUE;
}
if (!(req = eldbus_proxy_method_call_new(proxy, "NotifyListenersSync")))
{
ERR("Failed to create method call on: " ATSPI_DBUS_INTERFACE_DEC "." "NotifyListenersSync");
return EINA_TRUE;
}
ke = _key_event_info_new(type, key_event, bridge);
if (!ke)
{
eldbus_message_unref(req);
return EINA_TRUE;
}
iter = eldbus_message_iter_get(req);
_iter_marshall_key_event(iter, ke);
_key_event_info_free(ke);
// timeout should be kept reasonably low to avoid delays
if (!(reply = eldbus_proxy_send_and_block(proxy, req, 100)))
{
ERR("Unable to call method " ATSPI_DBUS_INTERFACE_DEC "." "NotifyListenersSync");
return EINA_TRUE;
}
if (eldbus_message_error_get(reply, &errname, &errmsg))
ERR("Error in call method " ATSPI_DBUS_INTERFACE_DEC "." "NotifyListenersSync" ": %s %s", errname, errmsg);
else
if (!eldbus_message_arguments_get(reply, "b", &ret))
ERR("Invalid answer signature");
eldbus_message_unref(reply);
if (ret)
return EINA_FALSE;
return EINA_FALSE;
}
EOLIAN Eina_Bool
_elm_atspi_bridge_connected_get(const Eo *obj EINA_UNUSED, Elm_Atspi_Bridge_Data *pd)
{
return pd->connected;
}
static void
_properties_changed_cb(void *data, Eldbus_Proxy *proxy EINA_UNUSED, void *event)
{
Eldbus_Proxy_Event_Property_Changed *ev = event;
Eo *bridge = data;
Eina_Bool val;
const char *ifc = eldbus_proxy_interface_get(ev->proxy);
if (ev->name && !strcmp(ev->name, "ScreenReaderEnabled" ) &&
ifc && !strcmp(A11Y_DBUS_STATUS_INTERFACE, ifc))
{
if (!eina_value_get(ev->value, &val))
{
ERR("Unable to get ScreenReaderEnabled property value");
return;
}
if (val)
_a11y_connection_init(bridge);
else
_a11y_connection_shutdown(bridge);
}
}
EOLIAN Efl_Object*
_elm_atspi_bridge_efl_object_constructor(Eo *obj, Elm_Atspi_Bridge_Data *pd)
{
Eldbus_Proxy *proxy;
Eldbus_Pending *req;
efl_constructor(efl_super(obj, ELM_ATSPI_BRIDGE_CLASS));
elm_need_eldbus();
if (!(pd->session_bus = eldbus_connection_get(ELDBUS_CONNECTION_TYPE_SESSION)))
{
ERR("Unable to connect to Session Bus");
return NULL;
}
if (!(pd->bus_obj = eldbus_object_get(pd->session_bus, A11Y_DBUS_NAME, A11Y_DBUS_PATH)))
{
ERR("Could not get /org/a11y/bus object");
goto obj_err;
}
if (!(proxy = eldbus_proxy_get(pd->bus_obj, A11Y_DBUS_STATUS_INTERFACE)))
{
ERR("Could not get proxy object for %s interface", A11Y_DBUS_STATUS_INTERFACE);
goto proxy_err;
}
if (!(req = eldbus_proxy_property_get(proxy, "ScreenReaderEnabled", _screen_reader_enabled_get, obj)))
{
ERR("Could not send PropertyGet request");
goto proxy_err;
}
pd->pending_requests = eina_list_append(pd->pending_requests, req);
eldbus_proxy_properties_monitor(proxy, EINA_TRUE);
eldbus_proxy_event_callback_add(proxy, ELDBUS_PROXY_EVENT_PROPERTY_CHANGED,
_properties_changed_cb, obj);
return obj;
proxy_err:
eldbus_object_unref(pd->bus_obj);
pd->bus_obj = NULL;
obj_err:
eldbus_connection_unref(pd->session_bus);
pd->session_bus = NULL;
return NULL;
}
EOLIAN void
_elm_atspi_bridge_efl_object_destructor(Eo *obj, Elm_Atspi_Bridge_Data *pd)
{
_a11y_connection_shutdown(obj);
if (pd->bus_obj) eldbus_object_unref(pd->bus_obj);
if (pd->session_bus) eldbus_connection_unref(pd->session_bus);
efl_destructor(efl_super(obj, ELM_ATSPI_BRIDGE_CLASS));
}
#include "elm_atspi_bridge_eo.c"