summaryrefslogtreecommitdiff
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
parentb7a4c27e3655076889a5d142e7bdeb83435225fd (diff)
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 = \
94 lib/elementary/efl_config_global.eo \ 94 lib/elementary/efl_config_global.eo \
95 lib/elementary/elm_code_widget.eo \ 95 lib/elementary/elm_code_widget.eo \
96 lib/elementary/elm_bus_watcher.eo \ 96 lib/elementary/elm_bus_watcher.eo \
97 lib/elementary/elm_atspi_bus_watcher.eo \
97 $(NULL) 98 $(NULL)
98 99
99# More public files -- FIXME 100# More public files -- FIXME
@@ -749,6 +750,7 @@ lib_elementary_libelementary_la_SOURCES = \
749 lib/elementary/efl_ui_list_segarray.c \ 750 lib/elementary/efl_ui_list_segarray.c \
750 lib/elementary/efl_ui_layout_factory.c \ 751 lib/elementary/efl_ui_layout_factory.c \
751 lib/elementary/elm_bus_watcher.c \ 752 lib/elementary/elm_bus_watcher.c \
753 lib/elementary/elm_atspi_bus_watcher.c \
752 $(NULL) 754 $(NULL)
753 755
754 756
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 \
184efl_thread_win32_4.c \ 184efl_thread_win32_4.c \
185efl_ui_list_example_1.c \ 185efl_ui_list_example_1.c \
186efl_ui_list_example_2.c \ 186efl_ui_list_example_2.c \
187efl_ui_list_example_3.c 187efl_ui_list_example_3.c \
188bus_watcher.c 188bus_watcher.c \
189atspi_bus_watcher.c
189 190
190SRCS += \ 191SRCS += \
191bg_cxx_example_01.cc \ 192bg_cxx_example_01.cc \
@@ -379,7 +380,8 @@ efl_thread_6 \
379efl_ui_list_example_1 \ 380efl_ui_list_example_1 \
380efl_ui_list_example_2 \ 381efl_ui_list_example_2 \
381efl_ui_list_example_3 \ 382efl_ui_list_example_3 \
382bus_watcher 383bus_watcher \
384atspi_bus_watcher
383#benchmark3d 385#benchmark3d
384#sphere-hunter 386#sphere-hunter
385 387
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 @@
1#define EFL_EO_API_SUPPORT
2#define EFL_BETA_API_SUPPORT
3
4#include <Elementary.h>
5#include <stdio.h>
6
7#define TEST_WRITE 1
8
9
10static void _cb1(void *data EINA_UNUSED, const Efl_Event *event EINA_UNUSED)
11{
12 printf("A11y stack enabled\n");
13}
14
15static void _cb2(void *data EINA_UNUSED, const Efl_Event *event EINA_UNUSED)
16{
17 printf("A11y stack disabled\n");
18}
19
20static void _cb3(void *data EINA_UNUSED, const Efl_Event *event)
21{
22 Atspi_Bus_Property *property = event->info;
23 switch (*property)
24 {
25 case ATSPI_BUS_PROPERTY_SCREENREADERENABLED:
26 printf("ScreenReaderEnabled property changed\n");
27 break;
28 case ATSPI_BUS_PROPERTY_ISENABLED:
29 printf("IsEnabled property changed\n");
30 break;
31 }
32}
33
34static Eina_Value
35_success(void *data, Eina_Value value)
36{
37 printf("Getting address successed.\n");
38 Eina_Value_Type *type = eina_value_type_get(&value);
39
40 if (type == EINA_VALUE_TYPE_STRUCT)
41 {
42 char *address = NULL;
43 if (!eina_value_struct_get(&value, "arg0", &address))
44 printf("failed to get arg0 value.\n");
45 printf("address is %s\n", address);
46 }
47 else {
48 printf("invalid answer type\n");
49 }
50 return value;
51}
52
53static Eina_Value
54_failed(void *data, Eina_Value value)
55{
56 printf("Getting address failed.\n");
57 return value;
58}
59
60static void _registered(void *data, const Efl_Event *event EINA_UNUSED)
61{
62 Elm_Atspi_Bus_Watcher *watcher = data;
63
64 elm_atspi_bus_watcher_property_try_set(watcher, ATSPI_BUS_PROPERTY_SCREENREADERENABLED, EINA_TRUE);
65 Eina_Future *address_feature = elm_atspi_bus_watcher_a11y_bus_address_get(watcher);
66 eina_future_cance(address_feature);
67 //eina_future_then_easy(address_feature, _success, NULL, NULL, NULL, NULL);
68}
69
70EAPI_MAIN int
71elm_main(int argc EINA_UNUSED, char **argv EINA_UNUSED)
72{
73 Elm_Atspi_Bus_Watcher *watcher = efl_add(ELM_ATSPI_BUS_WATCHER_CLASS, NULL);
74 Eldbus_Connection *conn = eldbus_connection_get(ELDBUS_CONNECTION_TYPE_SESSION);
75
76 elm_bus_watcher_connection_set(watcher, conn);
77 efl_event_callback_add(watcher, ELM_ATSPI_BUS_WATCHER_EVENT_ENABLED, _cb1, watcher);
78 efl_event_callback_add(watcher, ELM_ATSPI_BUS_WATCHER_EVENT_DISABLED, _cb2, watcher);
79 efl_event_callback_add(watcher, ELM_ATSPI_BUS_WATCHER_EVENT_PROPERTY_CHANGED, _cb3, watcher);
80 efl_event_callback_add(watcher, ELM_BUS_WATCHER_EVENT_REGISTERED, _registered, watcher);
81
82 eldbus_connection_unref(conn);
83
84 elm_run();
85 efl_unref(watcher);
86
87 return 0;
88}
89ELM_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;
323# include <efl_ui_list.eo.h> 323# include <efl_ui_list.eo.h>
324# include <efl_ui_list_pan.eo.h> 324# include <efl_ui_list_pan.eo.h>
325# include <elm_bus_watcher.eo.h> 325# include <elm_bus_watcher.eo.h>
326# include <elm_atspi_bus_watcher.eo.h>
326#endif 327#endif
327 328
328/* include deprecated calls last of all */ 329/* 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 @@
22/* 22/*
23 * Accessibility Bus info not defined in atspi-constants.h 23 * Accessibility Bus info not defined in atspi-constants.h
24 */ 24 */
25#define A11Y_DBUS_NAME "org.a11y.Bus"
26#define A11Y_DBUS_PATH "/org/a11y/bus"
27#define A11Y_DBUS_INTERFACE "org.a11y.Bus"
28#define A11Y_DBUS_STATUS_INTERFACE "org.a11y.Status"
29#define ATSPI_DBUS_INTERFACE_EVENT_WINDOW "org.a11y.atspi.Event.Window" 25#define ATSPI_DBUS_INTERFACE_EVENT_WINDOW "org.a11y.atspi.Event.Window"
30 26
31#define CACHE_ITEM_SIGNATURE "((so)(so)(so)a(so)assusau)" 27#define CACHE_ITEM_SIGNATURE "((so)(so)(so)a(so)assusau)"
@@ -66,8 +62,11 @@ typedef struct Key_Event_Info {
66 62
67typedef struct _Elm_Atspi_Bridge_Data 63typedef struct _Elm_Atspi_Bridge_Data
68{ 64{
69 Eldbus_Connection *session_bus; 65 Elm_Atspi_Bus_Watcher *bus_obj;
66 Eina_Future *bus_address_future;
67
70 Eldbus_Connection *a11y_bus; 68 Eldbus_Connection *a11y_bus;
69
71 Eina_List *reemited_events; 70 Eina_List *reemited_events;
72 Eina_Hash *cache; 71 Eina_Hash *cache;
73 Eldbus_Service_Interface *cache_interface; 72 Eldbus_Service_Interface *cache_interface;
@@ -79,7 +78,6 @@ typedef struct _Elm_Atspi_Bridge_Data
79 unsigned long long object_state_broadcast_mask; 78 unsigned long long object_state_broadcast_mask;
80 unsigned long long window_signal_broadcast_mask; 79 unsigned long long window_signal_broadcast_mask;
81 Ecore_Event_Filter *key_flr; 80 Ecore_Event_Filter *key_flr;
82 Eldbus_Object *bus_obj;
83 Eina_List *pending_requests; 81 Eina_List *pending_requests;
84 int id; 82 int id;
85 Eina_Hash *state_hash; 83 Eina_Hash *state_hash;
@@ -4390,77 +4388,6 @@ _a11y_bus_initialize(Eo *obj, const char *socket_addr)
4390 pd->event_hdlr = efl_access_event_handler_add(EFL_ACCESS_MIXIN, _bridge_accessible_event_dispatch, obj); 4388 pd->event_hdlr = efl_access_event_handler_add(EFL_ACCESS_MIXIN, _bridge_accessible_event_dispatch, obj);
4391} 4389}
4392 4390
4393static void
4394_a11y_bus_address_get(void *data, const Eldbus_Message *msg, Eldbus_Pending *pending)
4395{
4396 const char *errname, *errmsg, *sock_addr = NULL;
4397 ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(data, pd);
4398
4399 pd->pending_requests = eina_list_remove(pd->pending_requests, pending);
4400
4401 if (eldbus_message_error_get(msg, &errname, &errmsg))
4402 {
4403 ERR("%s %s", errname, errmsg);
4404 return;
4405 }
4406
4407 if (!eldbus_message_arguments_get(msg, "s", &sock_addr) || !sock_addr)
4408 {
4409 ERR("Could not get A11Y Bus socket address.");
4410 return;
4411 }
4412
4413 _a11y_bus_initialize((Eo*)data, sock_addr);
4414}
4415
4416static void _a11y_connection_init(Eo *bridge)
4417{
4418 ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(bridge, pd);
4419 Eina_Bool is_connected;
4420
4421 is_connected = elm_obj_atspi_bridge_connected_get(bridge);
4422
4423 if (is_connected) return;
4424
4425 Eldbus_Message *m = eldbus_object_method_call_new(pd->bus_obj, A11Y_DBUS_INTERFACE, "GetAddress");
4426 Eldbus_Pending *p = eldbus_object_send(pd->bus_obj, m, _a11y_bus_address_get, bridge, 100);
4427
4428 if (p)
4429 pd->pending_requests = eina_list_append(pd->pending_requests, p);
4430}
4431
4432static void
4433_screen_reader_enabled_get(void *data, const Eldbus_Message *msg, Eldbus_Pending *pending)
4434{
4435 ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(data, pd);
4436 const char *errname, *errmsg;
4437 Eina_Bool is_enabled;
4438 Eldbus_Message_Iter *variant;
4439
4440 pd->pending_requests = eina_list_remove(pd->pending_requests, pending);
4441
4442 if (eldbus_message_error_get(msg, &errname, &errmsg))
4443 {
4444 WRN("%s %s", errname, errmsg);
4445 return;
4446 }
4447 if (!eldbus_message_arguments_get(msg, "v", &variant))
4448 {
4449 ERR("'ScreenReaderEnabled' not packed into variant.");
4450 return;
4451 }
4452 if (!eldbus_message_iter_arguments_get(variant, "b", &is_enabled))
4453 {
4454 ERR("Could not get 'ScreenReaderEnabled' boolean property");
4455 return;
4456 }
4457
4458 if (is_enabled)
4459 _a11y_connection_init(data);
4460 else
4461 DBG("AT-SPI2 stack not enabled.");
4462}
4463
4464static void _bridge_object_register(Eo *bridge, Eo *obj) 4391static void _bridge_object_register(Eo *bridge, Eo *obj)
4465{ 4392{
4466 ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(bridge, pd); 4393 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)
4659 return pd->connected; 4586 return pd->connected;
4660} 4587}
4661 4588
4662static void 4589static Eina_Value
4663_properties_changed_cb(void *data, Eldbus_Proxy *proxy EINA_UNUSED, void *event) 4590_elm_atspi_bridge_bus_address_get_success(void *data, Eina_Value value)
4664{ 4591{
4665 Eldbus_Proxy_Event_Property_Changed *ev = event; 4592 Elm_Atspi_Bridge *bridge = data;
4666 Eo *bridge = data; 4593 ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN_VAL(bridge, pd, EINA_VALUE_EMPTY);
4667 Eina_Bool val; 4594 const Eina_Value_Type *type;
4668 const char *ifc = eldbus_proxy_interface_get(ev->proxy);
4669 if (ev->name && !strcmp(ev->name, "ScreenReaderEnabled" ) &&
4670 ifc && !strcmp(A11Y_DBUS_STATUS_INTERFACE, ifc))
4671 {
4672 if (!eina_value_get(ev->value, &val))
4673 {
4674 ERR("Unable to get ScreenReaderEnabled property value");
4675 return;
4676 }
4677 if (val)
4678 _a11y_connection_init(bridge);
4679 else
4680 _a11y_connection_shutdown(bridge);
4681 }
4682}
4683 4595
4684EOLIAN Efl_Object* 4596 pd->bus_address_future = NULL;
4685_elm_atspi_bridge_efl_object_constructor(Eo *obj, Elm_Atspi_Bridge_Data *pd)
4686{
4687 Eldbus_Proxy *proxy;
4688 Eldbus_Pending *req;
4689 4597
4690 efl_constructor(efl_super(obj, ELM_ATSPI_BRIDGE_CLASS)); 4598 if (elm_obj_atspi_bridge_connected_get(bridge))
4599 return EINA_VALUE_EMPTY;
4691 4600
4692 elm_need_eldbus(); 4601 type = eina_value_type_get(&value);
4602 if (type != EINA_VALUE_TYPE_STRUCT)
4603 return value;
4693 4604
4694 if (!(pd->session_bus = eldbus_connection_get(ELDBUS_CONNECTION_TYPE_SESSION))) 4605 const char *address = NULL;
4695 { 4606 if (eina_value_struct_get(&value, "arg0", &address))
4696 ERR("Unable to connect to Session Bus");
4697 return NULL;
4698 }
4699 if (!(pd->bus_obj = eldbus_object_get(pd->session_bus, A11Y_DBUS_NAME, A11Y_DBUS_PATH)))
4700 { 4607 {
4701 ERR("Could not get /org/a11y/bus object"); 4608 _a11y_bus_initialize(bridge, address);
4702 goto obj_err;
4703 } 4609 }
4704 if (!(proxy = eldbus_proxy_get(pd->bus_obj, A11Y_DBUS_STATUS_INTERFACE))) 4610 else
4705 { 4611 {
4706 ERR("Could not get proxy object for %s interface", A11Y_DBUS_STATUS_INTERFACE); 4612 ERR("Argument arg0 not found. Cannot initialize atspi bridge.");
4707 goto proxy_err;
4708 } 4613 }
4709 if (!(req = eldbus_proxy_property_get(proxy, "ScreenReaderEnabled", _screen_reader_enabled_get, obj))) 4614
4615 return value;
4616}
4617
4618static Eina_Value
4619_elm_atspi_bridge_bus_address_get_error(void *data, const Eina_Error error EINA_UNUSED)
4620{
4621 Elm_Atspi_Bridge *bridge = data;
4622 ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN_VAL(bridge, pd, EINA_VALUE_EMPTY);
4623 pd->bus_address_future = NULL;
4624 return EINA_VALUE_EMPTY;
4625}
4626
4627static void
4628_elm_atspi_bridge_a11y_bus_available(void *data, const Efl_Event *event EINA_UNUSED)
4629{
4630 Elm_Atspi_Bridge *bridge = data;
4631 ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(bridge, pd);
4632
4633 if (pd->bus_address_future)
4710 { 4634 {
4711 ERR("Could not send PropertyGet request"); 4635 eina_future_cancel(pd->bus_address_future);
4712 goto proxy_err; 4636 pd->bus_address_future = NULL;
4713 } 4637 }
4714 pd->pending_requests = eina_list_append(pd->pending_requests, req);
4715 4638
4716 eldbus_proxy_properties_monitor(proxy, EINA_TRUE); 4639 Eina_Bool enabled_flag = elm_atspi_bus_watcher_property_get(event->object,
4717 eldbus_proxy_event_callback_add(proxy, ELDBUS_PROXY_EVENT_PROPERTY_CHANGED, 4640 ATSPI_BUS_PROPERTY_SCREENREADERENABLED);
4718 _properties_changed_cb, obj);
4719 4641
4720 return obj; 4642 if (!enabled_flag) return;
4721 4643
4722proxy_err: 4644 pd->bus_address_future = elm_atspi_bus_watcher_a11y_bus_address_get(event->object);
4723 eldbus_object_unref(pd->bus_obj); 4645 eina_future_then_easy(pd->bus_address_future, _elm_atspi_bridge_bus_address_get_success,
4724 pd->bus_obj = NULL; 4646 _elm_atspi_bridge_bus_address_get_error, NULL, NULL, bridge);
4725obj_err:
4726 eldbus_connection_unref(pd->session_bus);
4727 pd->session_bus = NULL;
4728 return NULL;
4729} 4647}
4730 4648
4731EOLIAN void 4649static void
4732_elm_atspi_bridge_efl_object_destructor(Eo *obj, Elm_Atspi_Bridge_Data *pd) 4650_elm_atspi_bridge_a11y_bus_unavailable(void *data, const Efl_Event *event EINA_UNUSED)
4733{ 4651{
4734 _a11y_connection_shutdown(obj); 4652 _a11y_connection_shutdown((Eo*)data);
4653}
4654
4655static void
4656_elm_atspi_bridge_a11y_bus_status_updated(void *data, const Efl_Event *event EINA_UNUSED)
4657{
4658 Elm_Atspi_Bridge *bridge = data;
4659 ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(bridge, pd);
4660
4661}
4662
4663EOLIAN Efl_Object*
4664_elm_atspi_bridge_efl_object_constructor(Eo *obj, Elm_Atspi_Bridge_Data *pd)
4665{
4666 Eldbus_Connection *session_con;
4667 obj = efl_constructor(efl_super(obj, ELM_ATSPI_BRIDGE_CLASS));
4668
4669 session_con = eldbus_connection_get(ELDBUS_CONNECTION_TYPE_SESSION);
4670 if (!session_con)
4671 return NULL;
4672
4673 pd->bus_obj = efl_add(ELM_ATSPI_BUS_WATCHER_CLASS, obj);
4674 elm_bus_watcher_connection_set(pd->bus_obj, session_con);
4735 4675
4736 if (pd->bus_obj) eldbus_object_unref(pd->bus_obj); 4676 efl_event_callback_add(pd->bus_obj, ELM_BUS_WATCHER_EVENT_REGISTERED,
4737 if (pd->session_bus) eldbus_connection_unref(pd->session_bus); 4677 _elm_atspi_bridge_a11y_bus_available, obj);
4678 efl_event_callback_add(pd->bus_obj, ELM_BUS_WATCHER_EVENT_UNREGISTERED,
4679 _elm_atspi_bridge_a11y_bus_unavailable, obj);
4680 efl_event_callback_add(pd->bus_obj, ELM_ATSPI_BUS_WATCHER_EVENT_PROPERTY_CHANGED,
4681 _elm_atspi_bridge_a11y_bus_status_updated, obj);
4738 4682
4683 eldbus_connection_unref(session_con);
4684 return obj;
4685}
4686
4687EOLIAN void
4688_elm_atspi_bridge_efl_object_destructor(Eo *obj, Elm_Atspi_Bridge_Data *pd EINA_UNUSED)
4689{
4690 _a11y_connection_shutdown(obj);
4739 efl_destructor(efl_super(obj, ELM_ATSPI_BRIDGE_CLASS)); 4691 efl_destructor(efl_super(obj, ELM_ATSPI_BRIDGE_CLASS));
4740} 4692}
4741 4693
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 @@
1#ifdef HAVE_CONFIG_H
2#include "elementary_config.h"
3#endif
4
5#define ELM_BUS_WATCHER_PROTECTED
6#define ELM_ATSPI_BUS_WATCHER_PROTECTED
7
8// dbus interface description used by at-spi2 accesibility
9#define A11Y_DBUS_NAME "org.a11y.Bus"
10#define A11Y_DBUS_PATH "/org/a11y/bus"
11#define A11Y_DBUS_INTERFACE "org.a11y.Bus"
12#define A11Y_DBUS_STATUS_INTERFACE "org.a11y.Status"
13#define SCREEN_READER_ENABLED_PROPERTY_NAME "ScreenReaderEnabled"
14#define IS_ENABLED_PROPERTY_NAME "IsEnabled"
15#define GET_ADDRESS_METHOD_NAME "GetAddress"
16
17#include <Elementary.h>
18#include "elm_priv.h"
19#include "elm_atspi_bus_watcher.eo.h"
20
21typedef struct _Elm_Atspi_Bus_Watcher_Data
22{
23 Eldbus_Object *bus_object;
24 Eldbus_Proxy *status_proxy;
25
26 // cached properties values,
27 Eina_Bool cached_properties[2];
28} Elm_Atspi_Bus_Watcher_Data;
29
30static void _cached_property_set(Eo *obj, Elm_Atspi_Bus_Watcher_Data *pd, Atspi_Bus_Property property, Eina_Bool val);
31
32static inline void _is_enabled_try_set(Eo *obj, Elm_Atspi_Bus_Watcher_Data *pd, Eina_Bool val);
33static inline void _screen_reader_enabled_try_set(Eo *obj, Elm_Atspi_Bus_Watcher_Data *pd, Eina_Bool val);
34
35static Eina_Future* _eldbus_object_future_send(Eina_Future_Scheduler *scheduler, Eldbus_Object *proxy, Eldbus_Message *msg, int timeout);
36static inline void _eldbus_proxy_boolean_property_set(Eldbus_Proxy *proxy, const char *property_name, Eina_Bool v);
37
38EOLIAN static Eo*
39_elm_atspi_bus_watcher_efl_object_constructor(Eo *obj, Elm_Atspi_Bus_Watcher_Data *pd EINA_UNUSED)
40{
41 obj = efl_constructor(efl_super(obj, ELM_ATSPI_BUS_WATCHER_CLASS));
42 elm_bus_watcher_service_add(obj, A11Y_DBUS_NAME);
43 return obj;
44}
45
46EOLIAN static void
47_elm_atspi_bus_watcher_efl_object_destructor(Eo *obj, Elm_Atspi_Bus_Watcher_Data *pd EINA_UNUSED)
48{
49 if (pd->status_proxy) eldbus_proxy_unref(pd->status_proxy);
50 if (pd->bus_object) eldbus_object_unref(pd->bus_object);
51 efl_destructor(efl_super(obj, ELM_ATSPI_BUS_WATCHER_CLASS));
52}
53
54// Set cached value of property. Fires property changed and enabled events when neccessary.
55static void
56_cached_property_set(Eo *obj, Elm_Atspi_Bus_Watcher_Data *pd, Atspi_Bus_Property property, Eina_Bool val)
57{
58 if (pd->cached_properties[property] == val)
59 return;
60
61 pd->cached_properties[property] = val;
62 efl_event_callback_call(obj, ELM_ATSPI_BUS_WATCHER_EVENT_PROPERTY_CHANGED, &property);
63}
64
65static inline void
66_screen_reader_enabled_try_set(Eo *obj EINA_UNUSED, Elm_Atspi_Bus_Watcher_Data *pd, Eina_Bool val)
67{
68 _eldbus_proxy_boolean_property_set(pd->status_proxy, SCREEN_READER_ENABLED_PROPERTY_NAME, val);
69}
70
71static inline void
72_is_enabled_try_set(Eo *obj EINA_UNUSED, Elm_Atspi_Bus_Watcher_Data *pd, Eina_Bool val)
73{
74 _eldbus_proxy_boolean_property_set(pd->status_proxy, IS_ENABLED_PROPERTY_NAME, val);
75}
76
77static Eina_Bool
78_proxy_boolean_property_fetch(Eldbus_Proxy *proxy, const char *name, Eina_Bool *out_value)
79{
80 Eina_Value *val = eldbus_proxy_property_local_get(proxy, name);
81 if (!val) return EINA_FALSE;
82 if (eina_value_type_get(val) != EINA_VALUE_TYPE_UCHAR) return EINA_FALSE;
83 return eina_value_get(val, out_value);
84}
85
86static void
87_elm_atspi_bus_watcher_update_all_properties(Elm_Atspi_Bus_Watcher *watcher, Eldbus_Proxy *proxy)
88{
89 Elm_Atspi_Bus_Watcher_Data *pd = efl_data_scope_get(watcher, ELM_ATSPI_BUS_WATCHER_CLASS);
90 Eina_Bool val;
91
92 if (_proxy_boolean_property_fetch(proxy, SCREEN_READER_ENABLED_PROPERTY_NAME, &val))
93 _cached_property_set(watcher, pd, ATSPI_BUS_PROPERTY_SCREENREADERENABLED, val);
94
95 if (_proxy_boolean_property_fetch(proxy, IS_ENABLED_PROPERTY_NAME, &val))
96 _cached_property_set(watcher, pd, ATSPI_BUS_PROPERTY_ISENABLED, val);
97}
98
99static void
100_status_proxy_properties_changed_cb(void *data, Eldbus_Proxy *proxy, void *event EINA_UNUSED)
101{
102 Elm_Atspi_Bus_Watcher *watcher = data;
103 _elm_atspi_bus_watcher_update_all_properties(watcher, proxy);
104}
105
106EOLIAN static void
107_elm_atspi_bus_watcher_elm_bus_watcher_on_registered(Eo *obj, Elm_Atspi_Bus_Watcher_Data *pd,
108 const char *service_name)
109{
110 if (!service_name || strcmp(service_name, A11Y_DBUS_NAME))
111 return;
112
113 pd->bus_object = eldbus_object_get(elm_bus_watcher_connection_get(obj),
114 A11Y_DBUS_NAME, A11Y_DBUS_PATH);
115 pd->status_proxy = eldbus_proxy_get(pd->bus_object, A11Y_DBUS_STATUS_INTERFACE);
116
117 eldbus_proxy_event_callback_add(pd->status_proxy, ELDBUS_PROXY_EVENT_PROPERTY_CHANGED,
118 _status_proxy_properties_changed_cb, obj);
119 eldbus_proxy_event_callback_add(pd->status_proxy, ELDBUS_PROXY_EVENT_PROPERTY_LOADED,
120 _status_proxy_properties_changed_cb, obj);
121 eldbus_proxy_properties_monitor(pd->status_proxy, EINA_TRUE);
122}
123
124/* Analysis of cohesion
125 *
126 * functional
127 * sequential
128 * communicational
129 * procedural
130 * temporal
131 * logical
132 * coincidential
133 */
134EOLIAN static void
135_elm_atspi_bus_watcher_elm_bus_watcher_on_unregistered(Eo *obj, Elm_Atspi_Bus_Watcher_Data *pd,
136 const char *service_name)
137{
138 if (!service_name || strcmp(service_name, A11Y_DBUS_NAME))
139 return;
140
141 eldbus_proxy_unref(pd->status_proxy);
142 eldbus_object_unref(pd->bus_object);
143 pd->bus_object = NULL;
144 pd->status_proxy = NULL;
145
146 // reset status variables since we lost connection with org.a11y.Bus
147 _cached_property_set(obj, pd, ATSPI_BUS_PROPERTY_ISENABLED, EINA_FALSE);
148 _cached_property_set(obj, pd, ATSPI_BUS_PROPERTY_SCREENREADERENABLED, EINA_FALSE);
149}
150
151EOLIAN static Eina_Bool
152_elm_atspi_bus_watcher_property_get(Eo *obj EINA_UNUSED,
153 Elm_Atspi_Bus_Watcher_Data *pd, Atspi_Bus_Property property)
154{
155 return pd->cached_properties[property];
156}
157
158EOLIAN static void
159_elm_atspi_bus_watcher_property_try_set(Eo *obj EINA_UNUSED,
160 Elm_Atspi_Bus_Watcher_Data *pd,
161 Atspi_Bus_Property property, Eina_Bool val)
162{
163 switch (property)
164 {
165 case ATSPI_BUS_PROPERTY_SCREENREADERENABLED:
166 _screen_reader_enabled_try_set(obj, pd, val);
167 break;
168 case ATSPI_BUS_PROPERTY_ISENABLED:
169 _is_enabled_try_set(obj, pd, val);
170 break;
171 default:
172 ERR("Invalid property value.");
173 break;
174 }
175}
176
177static void
178_dummy_cancel_cb(void *data EINA_UNUSED, const Eina_Promise *dead_ptr EINA_UNUSED)
179{
180}
181
182static inline void
183_eldbus_proxy_boolean_property_set(Eldbus_Proxy *proxy, const char *property_name,
184 Eina_Bool val)
185{
186 eldbus_proxy_property_set(proxy, property_name, "b", (void*)val, NULL, NULL);
187}
188
189static void
190_eldbus_object_call_cb(void *data, const Eldbus_Message *msg,
191 Eldbus_Pending *pending EINA_UNUSED)
192{
193 Eina_Promise *promise = data;
194 Eina_Value *value = eldbus_message_to_eina_value(msg);
195 eina_promise_resolve(promise, *value);
196}
197
198static Eina_Future*
199_eldbus_object_future_send(Eina_Future_Scheduler *scheduler, Eldbus_Object *obj,
200 Eldbus_Message *msg, int timeout)
201{
202 Eina_Promise *p = eina_promise_new(scheduler, _dummy_cancel_cb, NULL);
203 if (!p) goto on_err;
204
205 if (!eldbus_object_send(obj, msg, _eldbus_object_call_cb, p, timeout))
206 goto on_err;
207
208 return eina_future_new(p);
209
210on_err:
211 eldbus_message_unref(msg);
212 return eina_future_rejected(scheduler, -1);
213}
214
215EOLIAN static Eina_Future*
216_elm_atspi_bus_watcher_a11y_bus_address_get(Eo *obj EINA_UNUSED, Elm_Atspi_Bus_Watcher_Data *pd)
217{
218 Eina_Future_Scheduler *scheduler = efl_loop_future_scheduler_get(ecore_main_loop_get());
219 Eldbus_Message *msg = eldbus_object_method_call_new(pd->bus_object,
220 A11Y_DBUS_INTERFACE,
221 GET_ADDRESS_METHOD_NAME);
222 if (!msg) return eina_future_rejected(scheduler, -1); //TODO add recent error code
223
224 return _eldbus_object_future_send(scheduler, pd->bus_object, msg, 100);
225}
226
227#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 @@
1import eina_types;
2
3enum Atspi.Bus.Property
4{
5 ScreenReaderEnabled,
6 IsEnabled
7}
8
9class Elm.Atspi.Bus.Watcher (Elm.Bus.Watcher)
10{
11 methods {
12 a11y_bus_address_get {
13 return: ptr(Eina.Future);
14 }
15 property_get {
16 params {
17 @in property: Atspi.Bus.Property;
18 }
19 return: bool;
20 }
21 property_try_set {
22 params {
23 @in property: Atspi.Bus.Property;
24 @in val: bool;
25 }
26 }
27 }
28 implements {
29 Efl.Object.constructor;
30 Efl.Object.destructor;
31 Elm.Bus.Watcher.on_registered;
32
33 Elm.Bus.Watcher.on_unregistered;
34 }
35 events {
36 property,changed: Atspi.Bus.Property; [[ called when Atspi.Bus properties has been changed]]
37 }
38}