aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLukasz Stanislawski <lukasz.stanislawski@gmail.com>2017-12-15 19:48:41 +0100
committerLukasz Stanislawski <lukasz.stanislawski@gmail.com>2017-12-17 18:16:14 +0100
commit34a440738487a3296bb2d71970bea73e7ba8c9cd (patch)
tree3a8ad59fba5c91400c08a0b659f03d8931693f7e
parentelm: implement elm_bus_watcher class (diff)
downloadefl-devs/stanluk/split2.tar.gz
Implement elm_atspi_bus_watcherdevs/stanluk/split2
Summary: Change-Id: If486eee49666640277cfbe9790e1ae5cf5bdb537 Subscribers: cedric, jpeg Differential Revision: https://phab.enlightenment.org/D5572
-rw-r--r--src/Makefile_Elementary.am2
-rw-r--r--src/examples/elementary/Makefile.am8
-rw-r--r--src/examples/elementary/atspi_bus_watcher.c89
-rw-r--r--src/lib/elementary/Elementary.h1
-rw-r--r--src/lib/elementary/elm_atspi_bridge.c222
-rw-r--r--src/lib/elementary/elm_atspi_bus_watcher.c227
-rw-r--r--src/lib/elementary/elm_atspi_bus_watcher.eo38
7 files changed, 449 insertions, 138 deletions
diff --git a/src/Makefile_Elementary.am b/src/Makefile_Elementary.am
index cb283e350d..6ff3304028 100644
--- a/src/Makefile_Elementary.am
+++ b/src/Makefile_Elementary.am
@@ -94,6 +94,7 @@ elm_public_eolian_files = \
lib/elementary/efl_config_global.eo \
lib/elementary/elm_code_widget.eo \
lib/elementary/elm_bus_watcher.eo \
+ lib/elementary/elm_atspi_bus_watcher.eo \
$(NULL)
# More public files -- FIXME
@@ -749,6 +750,7 @@ lib_elementary_libelementary_la_SOURCES = \
lib/elementary/efl_ui_list_segarray.c \
lib/elementary/efl_ui_layout_factory.c \
lib/elementary/elm_bus_watcher.c \
+ lib/elementary/elm_atspi_bus_watcher.c \
$(NULL)
diff --git a/src/examples/elementary/Makefile.am b/src/examples/elementary/Makefile.am
index 89bbc39d90..0599d3ca38 100644
--- a/src/examples/elementary/Makefile.am
+++ b/src/examples/elementary/Makefile.am
@@ -184,8 +184,9 @@ efl_thread_win32_3.c \
efl_thread_win32_4.c \
efl_ui_list_example_1.c \
efl_ui_list_example_2.c \
-efl_ui_list_example_3.c
-bus_watcher.c
+efl_ui_list_example_3.c \
+bus_watcher.c \
+atspi_bus_watcher.c
SRCS += \
bg_cxx_example_01.cc \
@@ -379,7 +380,8 @@ efl_thread_6 \
efl_ui_list_example_1 \
efl_ui_list_example_2 \
efl_ui_list_example_3 \
-bus_watcher
+bus_watcher \
+atspi_bus_watcher
#benchmark3d
#sphere-hunter
diff --git a/src/examples/elementary/atspi_bus_watcher.c b/src/examples/elementary/atspi_bus_watcher.c
new file mode 100644
index 0000000000..472f4de196
--- /dev/null
+++ b/src/examples/elementary/atspi_bus_watcher.c
@@ -0,0 +1,89 @@
+#define EFL_EO_API_SUPPORT
+#define EFL_BETA_API_SUPPORT
+
+#include <Elementary.h>
+#include <stdio.h>
+
+#define TEST_WRITE 1
+
+
+static void _cb1(void *data EINA_UNUSED, const Efl_Event *event EINA_UNUSED)
+{
+ printf("A11y stack enabled\n");
+}
+
+static void _cb2(void *data EINA_UNUSED, const Efl_Event *event EINA_UNUSED)
+{
+ printf("A11y stack disabled\n");
+}
+
+static void _cb3(void *data EINA_UNUSED, const Efl_Event *event)
+{
+ Atspi_Bus_Property *property = event->info;
+ switch (*property)
+ {
+ case ATSPI_BUS_PROPERTY_SCREENREADERENABLED:
+ printf("ScreenReaderEnabled property changed\n");
+ break;
+ case ATSPI_BUS_PROPERTY_ISENABLED:
+ printf("IsEnabled property changed\n");
+ break;
+ }
+}
+
+static Eina_Value
+_success(void *data, Eina_Value value)
+{
+ printf("Getting address successed.\n");
+ Eina_Value_Type *type = eina_value_type_get(&value);
+
+ if (type == EINA_VALUE_TYPE_STRUCT)
+ {
+ char *address = NULL;
+ if (!eina_value_struct_get(&value, "arg0", &address))
+ printf("failed to get arg0 value.\n");
+ printf("address is %s\n", address);
+ }
+ else {
+ printf("invalid answer type\n");
+ }
+ return value;
+}
+
+static Eina_Value
+_failed(void *data, Eina_Value value)
+{
+ printf("Getting address failed.\n");
+ return value;
+}
+
+static void _registered(void *data, const Efl_Event *event EINA_UNUSED)
+{
+ Elm_Atspi_Bus_Watcher *watcher = data;
+
+ elm_atspi_bus_watcher_property_try_set(watcher, ATSPI_BUS_PROPERTY_SCREENREADERENABLED, EINA_TRUE);
+ Eina_Future *address_feature = elm_atspi_bus_watcher_a11y_bus_address_get(watcher);
+ eina_future_cance(address_feature);
+ //eina_future_then_easy(address_feature, _success, NULL, NULL, NULL, NULL);
+}
+
+EAPI_MAIN int
+elm_main(int argc EINA_UNUSED, char **argv EINA_UNUSED)
+{
+ Elm_Atspi_Bus_Watcher *watcher = efl_add(ELM_ATSPI_BUS_WATCHER_CLASS, NULL);
+ Eldbus_Connection *conn = eldbus_connection_get(ELDBUS_CONNECTION_TYPE_SESSION);
+
+ elm_bus_watcher_connection_set(watcher, conn);
+ efl_event_callback_add(watcher, ELM_ATSPI_BUS_WATCHER_EVENT_ENABLED, _cb1, watcher);
+ efl_event_callback_add(watcher, ELM_ATSPI_BUS_WATCHER_EVENT_DISABLED, _cb2, watcher);
+ efl_event_callback_add(watcher, ELM_ATSPI_BUS_WATCHER_EVENT_PROPERTY_CHANGED, _cb3, watcher);
+ efl_event_callback_add(watcher, ELM_BUS_WATCHER_EVENT_REGISTERED, _registered, watcher);
+
+ eldbus_connection_unref(conn);
+
+ elm_run();
+ efl_unref(watcher);
+
+ return 0;
+}
+ELM_MAIN()
diff --git a/src/lib/elementary/Elementary.h b/src/lib/elementary/Elementary.h
index d90c812e8c..87a11cca9d 100644
--- a/src/lib/elementary/Elementary.h
+++ b/src/lib/elementary/Elementary.h
@@ -323,6 +323,7 @@ EAPI extern Elm_Version *elm_version;
# include <efl_ui_list.eo.h>
# include <efl_ui_list_pan.eo.h>
# include <elm_bus_watcher.eo.h>
+# include <elm_atspi_bus_watcher.eo.h>
#endif
/* include deprecated calls last of all */
diff --git a/src/lib/elementary/elm_atspi_bridge.c b/src/lib/elementary/elm_atspi_bridge.c
index 09ea6a1693..931f92cca0 100644
--- a/src/lib/elementary/elm_atspi_bridge.c
+++ b/src/lib/elementary/elm_atspi_bridge.c
@@ -22,10 +22,6 @@
/*
* 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)"
@@ -66,8 +62,11 @@ typedef struct Key_Event_Info {
typedef struct _Elm_Atspi_Bridge_Data
{
- Eldbus_Connection *session_bus;
+ Elm_Atspi_Bus_Watcher *bus_obj;
+ Eina_Future *bus_address_future;
+
Eldbus_Connection *a11y_bus;
+
Eina_List *reemited_events;
Eina_Hash *cache;
Eldbus_Service_Interface *cache_interface;
@@ -79,7 +78,6 @@ typedef struct _Elm_Atspi_Bridge_Data
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;
Eina_Hash *state_hash;
@@ -4390,77 +4388,6 @@ _a11y_bus_initialize(Eo *obj, const char *socket_addr)
pd->event_hdlr = efl_access_event_handler_add(EFL_ACCESS_MIXIN, _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))
- {
- 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);
@@ -4659,83 +4586,108 @@ _elm_atspi_bridge_connected_get(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)
+static Eina_Value
+_elm_atspi_bridge_bus_address_get_success(void *data, Eina_Value value)
{
- 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);
- }
-}
+ Elm_Atspi_Bridge *bridge = data;
+ ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN_VAL(bridge, pd, EINA_VALUE_EMPTY);
+ const Eina_Value_Type *type;
-EOLIAN Efl_Object*
-_elm_atspi_bridge_efl_object_constructor(Eo *obj, Elm_Atspi_Bridge_Data *pd)
-{
- Eldbus_Proxy *proxy;
- Eldbus_Pending *req;
+ pd->bus_address_future = NULL;
- efl_constructor(efl_super(obj, ELM_ATSPI_BRIDGE_CLASS));
+ if (elm_obj_atspi_bridge_connected_get(bridge))
+ return EINA_VALUE_EMPTY;
- elm_need_eldbus();
+ type = eina_value_type_get(&value);
+ if (type != EINA_VALUE_TYPE_STRUCT)
+ return value;
- 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)))
+ const char *address = NULL;
+ if (eina_value_struct_get(&value, "arg0", &address))
{
- ERR("Could not get /org/a11y/bus object");
- goto obj_err;
+ _a11y_bus_initialize(bridge, address);
}
- if (!(proxy = eldbus_proxy_get(pd->bus_obj, A11Y_DBUS_STATUS_INTERFACE)))
+ else
{
- ERR("Could not get proxy object for %s interface", A11Y_DBUS_STATUS_INTERFACE);
- goto proxy_err;
+ ERR("Argument arg0 not found. Cannot initialize atspi bridge.");
}
- if (!(req = eldbus_proxy_property_get(proxy, "ScreenReaderEnabled", _screen_reader_enabled_get, obj)))
+
+ return value;
+}
+
+static Eina_Value
+_elm_atspi_bridge_bus_address_get_error(void *data, const Eina_Error error EINA_UNUSED)
+{
+ Elm_Atspi_Bridge *bridge = data;
+ ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN_VAL(bridge, pd, EINA_VALUE_EMPTY);
+ pd->bus_address_future = NULL;
+ return EINA_VALUE_EMPTY;
+}
+
+static void
+_elm_atspi_bridge_a11y_bus_available(void *data, const Efl_Event *event EINA_UNUSED)
+{
+ Elm_Atspi_Bridge *bridge = data;
+ ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(bridge, pd);
+
+ if (pd->bus_address_future)
{
- ERR("Could not send PropertyGet request");
- goto proxy_err;
+ eina_future_cancel(pd->bus_address_future);
+ pd->bus_address_future = NULL;
}
- 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);
+ Eina_Bool enabled_flag = elm_atspi_bus_watcher_property_get(event->object,
+ ATSPI_BUS_PROPERTY_SCREENREADERENABLED);
- return obj;
+ if (!enabled_flag) return;
-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;
+ pd->bus_address_future = elm_atspi_bus_watcher_a11y_bus_address_get(event->object);
+ eina_future_then_easy(pd->bus_address_future, _elm_atspi_bridge_bus_address_get_success,
+ _elm_atspi_bridge_bus_address_get_error, NULL, NULL, bridge);
}
-EOLIAN void
-_elm_atspi_bridge_efl_object_destructor(Eo *obj, Elm_Atspi_Bridge_Data *pd)
+static void
+_elm_atspi_bridge_a11y_bus_unavailable(void *data, const Efl_Event *event EINA_UNUSED)
{
- _a11y_connection_shutdown(obj);
+ _a11y_connection_shutdown((Eo*)data);
+}
+
+static void
+_elm_atspi_bridge_a11y_bus_status_updated(void *data, const Efl_Event *event EINA_UNUSED)
+{
+ Elm_Atspi_Bridge *bridge = data;
+ ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(bridge, pd);
+
+}
+
+EOLIAN Efl_Object*
+_elm_atspi_bridge_efl_object_constructor(Eo *obj, Elm_Atspi_Bridge_Data *pd)
+{
+ Eldbus_Connection *session_con;
+ obj = efl_constructor(efl_super(obj, ELM_ATSPI_BRIDGE_CLASS));
+
+ session_con = eldbus_connection_get(ELDBUS_CONNECTION_TYPE_SESSION);
+ if (!session_con)
+ return NULL;
+
+ pd->bus_obj = efl_add(ELM_ATSPI_BUS_WATCHER_CLASS, obj);
+ elm_bus_watcher_connection_set(pd->bus_obj, session_con);
- if (pd->bus_obj) eldbus_object_unref(pd->bus_obj);
- if (pd->session_bus) eldbus_connection_unref(pd->session_bus);
+ efl_event_callback_add(pd->bus_obj, ELM_BUS_WATCHER_EVENT_REGISTERED,
+ _elm_atspi_bridge_a11y_bus_available, obj);
+ efl_event_callback_add(pd->bus_obj, ELM_BUS_WATCHER_EVENT_UNREGISTERED,
+ _elm_atspi_bridge_a11y_bus_unavailable, obj);
+ efl_event_callback_add(pd->bus_obj, ELM_ATSPI_BUS_WATCHER_EVENT_PROPERTY_CHANGED,
+ _elm_atspi_bridge_a11y_bus_status_updated, obj);
+ eldbus_connection_unref(session_con);
+ return obj;
+}
+
+EOLIAN void
+_elm_atspi_bridge_efl_object_destructor(Eo *obj, Elm_Atspi_Bridge_Data *pd EINA_UNUSED)
+{
+ _a11y_connection_shutdown(obj);
efl_destructor(efl_super(obj, ELM_ATSPI_BRIDGE_CLASS));
}
diff --git a/src/lib/elementary/elm_atspi_bus_watcher.c b/src/lib/elementary/elm_atspi_bus_watcher.c
new file mode 100644
index 0000000000..cba6aa9896
--- /dev/null
+++ b/src/lib/elementary/elm_atspi_bus_watcher.c
@@ -0,0 +1,227 @@
+#ifdef HAVE_CONFIG_H
+#include "elementary_config.h"
+#endif
+
+#define ELM_BUS_WATCHER_PROTECTED
+#define ELM_ATSPI_BUS_WATCHER_PROTECTED
+
+// dbus interface description used by at-spi2 accesibility
+#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 SCREEN_READER_ENABLED_PROPERTY_NAME "ScreenReaderEnabled"
+#define IS_ENABLED_PROPERTY_NAME "IsEnabled"
+#define GET_ADDRESS_METHOD_NAME "GetAddress"
+
+#include <Elementary.h>
+#include "elm_priv.h"
+#include "elm_atspi_bus_watcher.eo.h"
+
+typedef struct _Elm_Atspi_Bus_Watcher_Data
+{
+ Eldbus_Object *bus_object;
+ Eldbus_Proxy *status_proxy;
+
+ // cached properties values,
+ Eina_Bool cached_properties[2];
+} Elm_Atspi_Bus_Watcher_Data;
+
+static void _cached_property_set(Eo *obj, Elm_Atspi_Bus_Watcher_Data *pd, Atspi_Bus_Property property, Eina_Bool val);
+
+static inline void _is_enabled_try_set(Eo *obj, Elm_Atspi_Bus_Watcher_Data *pd, Eina_Bool val);
+static inline void _screen_reader_enabled_try_set(Eo *obj, Elm_Atspi_Bus_Watcher_Data *pd, Eina_Bool val);
+
+static Eina_Future* _eldbus_object_future_send(Eina_Future_Scheduler *scheduler, Eldbus_Object *proxy, Eldbus_Message *msg, int timeout);
+static inline void _eldbus_proxy_boolean_property_set(Eldbus_Proxy *proxy, const char *property_name, Eina_Bool v);
+
+EOLIAN static Eo*
+_elm_atspi_bus_watcher_efl_object_constructor(Eo *obj, Elm_Atspi_Bus_Watcher_Data *pd EINA_UNUSED)
+{
+ obj = efl_constructor(efl_super(obj, ELM_ATSPI_BUS_WATCHER_CLASS));
+ elm_bus_watcher_service_add(obj, A11Y_DBUS_NAME);
+ return obj;
+}
+
+EOLIAN static void
+_elm_atspi_bus_watcher_efl_object_destructor(Eo *obj, Elm_Atspi_Bus_Watcher_Data *pd EINA_UNUSED)
+{
+ if (pd->status_proxy) eldbus_proxy_unref(pd->status_proxy);
+ if (pd->bus_object) eldbus_object_unref(pd->bus_object);
+ efl_destructor(efl_super(obj, ELM_ATSPI_BUS_WATCHER_CLASS));
+}
+
+// Set cached value of property. Fires property changed and enabled events when neccessary.
+static void
+_cached_property_set(Eo *obj, Elm_Atspi_Bus_Watcher_Data *pd, Atspi_Bus_Property property, Eina_Bool val)
+{
+ if (pd->cached_properties[property] == val)
+ return;
+
+ pd->cached_properties[property] = val;
+ efl_event_callback_call(obj, ELM_ATSPI_BUS_WATCHER_EVENT_PROPERTY_CHANGED, &property);
+}
+
+static inline void
+_screen_reader_enabled_try_set(Eo *obj EINA_UNUSED, Elm_Atspi_Bus_Watcher_Data *pd, Eina_Bool val)
+{
+ _eldbus_proxy_boolean_property_set(pd->status_proxy, SCREEN_READER_ENABLED_PROPERTY_NAME, val);
+}
+
+static inline void
+_is_enabled_try_set(Eo *obj EINA_UNUSED, Elm_Atspi_Bus_Watcher_Data *pd, Eina_Bool val)
+{
+ _eldbus_proxy_boolean_property_set(pd->status_proxy, IS_ENABLED_PROPERTY_NAME, val);
+}
+
+static Eina_Bool
+_proxy_boolean_property_fetch(Eldbus_Proxy *proxy, const char *name, Eina_Bool *out_value)
+{
+ Eina_Value *val = eldbus_proxy_property_local_get(proxy, name);
+ if (!val) return EINA_FALSE;
+ if (eina_value_type_get(val) != EINA_VALUE_TYPE_UCHAR) return EINA_FALSE;
+ return eina_value_get(val, out_value);
+}
+
+static void
+_elm_atspi_bus_watcher_update_all_properties(Elm_Atspi_Bus_Watcher *watcher, Eldbus_Proxy *proxy)
+{
+ Elm_Atspi_Bus_Watcher_Data *pd = efl_data_scope_get(watcher, ELM_ATSPI_BUS_WATCHER_CLASS);
+ Eina_Bool val;
+
+ if (_proxy_boolean_property_fetch(proxy, SCREEN_READER_ENABLED_PROPERTY_NAME, &val))
+ _cached_property_set(watcher, pd, ATSPI_BUS_PROPERTY_SCREENREADERENABLED, val);
+
+ if (_proxy_boolean_property_fetch(proxy, IS_ENABLED_PROPERTY_NAME, &val))
+ _cached_property_set(watcher, pd, ATSPI_BUS_PROPERTY_ISENABLED, val);
+}
+
+static void
+_status_proxy_properties_changed_cb(void *data, Eldbus_Proxy *proxy, void *event EINA_UNUSED)
+{
+ Elm_Atspi_Bus_Watcher *watcher = data;
+ _elm_atspi_bus_watcher_update_all_properties(watcher, proxy);
+}
+
+EOLIAN static void
+_elm_atspi_bus_watcher_elm_bus_watcher_on_registered(Eo *obj, Elm_Atspi_Bus_Watcher_Data *pd,
+ const char *service_name)
+{
+ if (!service_name || strcmp(service_name, A11Y_DBUS_NAME))
+ return;
+
+ pd->bus_object = eldbus_object_get(elm_bus_watcher_connection_get(obj),
+ A11Y_DBUS_NAME, A11Y_DBUS_PATH);
+ pd->status_proxy = eldbus_proxy_get(pd->bus_object, A11Y_DBUS_STATUS_INTERFACE);
+
+ eldbus_proxy_event_callback_add(pd->status_proxy, ELDBUS_PROXY_EVENT_PROPERTY_CHANGED,
+ _status_proxy_properties_changed_cb, obj);
+ eldbus_proxy_event_callback_add(pd->status_proxy, ELDBUS_PROXY_EVENT_PROPERTY_LOADED,
+ _status_proxy_properties_changed_cb, obj);
+ eldbus_proxy_properties_monitor(pd->status_proxy, EINA_TRUE);
+}
+
+/* Analysis of cohesion
+ *
+ * functional
+ * sequential
+ * communicational
+ * procedural
+ * temporal
+ * logical
+ * coincidential
+ */
+EOLIAN static void
+_elm_atspi_bus_watcher_elm_bus_watcher_on_unregistered(Eo *obj, Elm_Atspi_Bus_Watcher_Data *pd,
+ const char *service_name)
+{
+ if (!service_name || strcmp(service_name, A11Y_DBUS_NAME))
+ return;
+
+ eldbus_proxy_unref(pd->status_proxy);
+ eldbus_object_unref(pd->bus_object);
+ pd->bus_object = NULL;
+ pd->status_proxy = NULL;
+
+ // reset status variables since we lost connection with org.a11y.Bus
+ _cached_property_set(obj, pd, ATSPI_BUS_PROPERTY_ISENABLED, EINA_FALSE);
+ _cached_property_set(obj, pd, ATSPI_BUS_PROPERTY_SCREENREADERENABLED, EINA_FALSE);
+}
+
+EOLIAN static Eina_Bool
+_elm_atspi_bus_watcher_property_get(Eo *obj EINA_UNUSED,
+ Elm_Atspi_Bus_Watcher_Data *pd, Atspi_Bus_Property property)
+{
+ return pd->cached_properties[property];
+}
+
+EOLIAN static void
+_elm_atspi_bus_watcher_property_try_set(Eo *obj EINA_UNUSED,
+ Elm_Atspi_Bus_Watcher_Data *pd,
+ Atspi_Bus_Property property, Eina_Bool val)
+{
+ switch (property)
+ {
+ case ATSPI_BUS_PROPERTY_SCREENREADERENABLED:
+ _screen_reader_enabled_try_set(obj, pd, val);
+ break;
+ case ATSPI_BUS_PROPERTY_ISENABLED:
+ _is_enabled_try_set(obj, pd, val);
+ break;
+ default:
+ ERR("Invalid property value.");
+ break;
+ }
+}
+
+static void
+_dummy_cancel_cb(void *data EINA_UNUSED, const Eina_Promise *dead_ptr EINA_UNUSED)
+{
+}
+
+static inline void
+_eldbus_proxy_boolean_property_set(Eldbus_Proxy *proxy, const char *property_name,
+ Eina_Bool val)
+{
+ eldbus_proxy_property_set(proxy, property_name, "b", (void*)val, NULL, NULL);
+}
+
+static void
+_eldbus_object_call_cb(void *data, const Eldbus_Message *msg,
+ Eldbus_Pending *pending EINA_UNUSED)
+{
+ Eina_Promise *promise = data;
+ Eina_Value *value = eldbus_message_to_eina_value(msg);
+ eina_promise_resolve(promise, *value);
+}
+
+static Eina_Future*
+_eldbus_object_future_send(Eina_Future_Scheduler *scheduler, Eldbus_Object *obj,
+ Eldbus_Message *msg, int timeout)
+{
+ Eina_Promise *p = eina_promise_new(scheduler, _dummy_cancel_cb, NULL);
+ if (!p) goto on_err;
+
+ if (!eldbus_object_send(obj, msg, _eldbus_object_call_cb, p, timeout))
+ goto on_err;
+
+ return eina_future_new(p);
+
+on_err:
+ eldbus_message_unref(msg);
+ return eina_future_rejected(scheduler, -1);
+}
+
+EOLIAN static Eina_Future*
+_elm_atspi_bus_watcher_a11y_bus_address_get(Eo *obj EINA_UNUSED, Elm_Atspi_Bus_Watcher_Data *pd)
+{
+ Eina_Future_Scheduler *scheduler = efl_loop_future_scheduler_get(ecore_main_loop_get());
+ Eldbus_Message *msg = eldbus_object_method_call_new(pd->bus_object,
+ A11Y_DBUS_INTERFACE,
+ GET_ADDRESS_METHOD_NAME);
+ if (!msg) return eina_future_rejected(scheduler, -1); //TODO add recent error code
+
+ return _eldbus_object_future_send(scheduler, pd->bus_object, msg, 100);
+}
+
+#include "elm_atspi_bus_watcher.eo.c"
diff --git a/src/lib/elementary/elm_atspi_bus_watcher.eo b/src/lib/elementary/elm_atspi_bus_watcher.eo
new file mode 100644
index 0000000000..45bea126ce
--- /dev/null
+++ b/src/lib/elementary/elm_atspi_bus_watcher.eo
@@ -0,0 +1,38 @@
+import eina_types;
+
+enum Atspi.Bus.Property
+{
+ ScreenReaderEnabled,
+ IsEnabled
+}
+
+class Elm.Atspi.Bus.Watcher (Elm.Bus.Watcher)
+{
+ methods {
+ a11y_bus_address_get {
+ return: ptr(Eina.Future);
+ }
+ property_get {
+ params {
+ @in property: Atspi.Bus.Property;
+ }
+ return: bool;
+ }
+ property_try_set {
+ params {
+ @in property: Atspi.Bus.Property;
+ @in val: bool;
+ }
+ }
+ }
+ implements {
+ Efl.Object.constructor;
+ Efl.Object.destructor;
+ Elm.Bus.Watcher.on_registered;
+
+ Elm.Bus.Watcher.on_unregistered;
+ }
+ events {
+ property,changed: Atspi.Bus.Property; [[ called when Atspi.Bus properties has been changed]]
+ }
+}