atspi: make possible to merge two atspi subtrees from different processes. 22/66322/9
authorLukasz Stanislawski <l.stanislaws@samsung.com>
Wed, 6 May 2015 12:21:31 +0000 (14:21 +0200)
committerPrasoon Singh <prasoon.16@samsung.com>
Wed, 4 May 2016 08:23:48 +0000 (13:53 +0530)
Conflicts:
src/lib/elm_atspi_app_object.c
src/lib/elm_plug.eo
src/lib/elm_priv.h
src/lib/elm_web.eo
src/lib/elm_widget.h

Change-Id: I8291311bef3d257ccb29187095bd455db552cae6

13 files changed:
src/lib/Elementary.h.in
src/lib/Makefile.am
src/lib/elm_atspi_app_object.c
src/lib/elm_atspi_bridge.c
src/lib/elm_atspi_proxy.c [new file with mode: 0644]
src/lib/elm_atspi_proxy.eo [new file with mode: 0644]
src/lib/elm_atspi_proxy.h [new file with mode: 0644]
src/lib/elm_plug.c
src/lib/elm_plug.eo
src/lib/elm_priv.h
src/lib/elm_widget.c
src/lib/elm_widget.h
src/lib/elm_win.c

index 894a7b93c607206a294ecb35f56813fca8931fd9..cd0910736ce0c3573d1dde3b4b5e8284c9f5e6c2 100644 (file)
@@ -195,6 +195,7 @@ EAPI extern Elm_Version *elm_version;
 #include <elm_app.h>
 #include <elm_atspi_app_object.h>
 #include <elm_atspi_bridge.h>
+#include <elm_atspi_proxy.h>
 #include <elm_bg.h>
 #include <elm_box.h>
 
index 16d3f8e248679ec187fe1286ebdf3353cf5608a8..5e295f03e549a6e574203e44d90da51ee9f4b7dd 100644 (file)
@@ -156,6 +156,7 @@ elm_app_client_view_eo.h \
 elm_app_client_view.h \
 elm_app.h \
 elm_atspi_app_object.h \
+elm_atspi_proxy.h \
 elm_authors.h \
 elm_bg.h \
 elm_bg_eo.h \
@@ -404,6 +405,7 @@ elm_app_server_view.c \
 elm_app_client.c \
 elm_app_client_view.c \
 elm_atspi_app_object.c \
+elm_atspi_proxy.c \
 elm_atspi_bridge.c \
 elm_bg.c \
 elm_box.c \
@@ -523,6 +525,7 @@ elm_app_client_view.eo \
 elm_app_server.eo \
 elm_app_server_view.eo \
 elm_atspi_app_object.eo \
+elm_atspi_proxy.eo \
 elm_bg.eo \
 elm_box.eo \
 elm_bubble.eo \
index 6e49891379cf29db7c39b7c28b621153f0719301..882174ad4746468222f9e3b195d869699fc4d4a5 100644 (file)
@@ -33,7 +33,8 @@ _elm_atspi_app_object_elm_interface_atspi_accessible_children_get(Eo *obj EINA_U
 
    EINA_LIST_FOREACH(_elm_win_list, l, win)
      {
-        if (eo_isa(win, ELM_INTERFACE_ATSPI_ACCESSIBLE_MIXIN))
+        if (eo_isa(win, ELM_INTERFACE_ATSPI_ACCESSIBLE_MIXIN) &&
+            (elm_win_type_get(win) != ELM_WIN_SOCKET_IMAGE))
           accs = eina_list_append(accs, win);
      }
 
index 581455edfc70bdf8e62238e3a38bb015a301492a..0b642092cd24c99cec6dd36cf98e464260808ac4 100644 (file)
@@ -34,6 +34,8 @@
 #define ELM_ACCESS_OBJECT_PATH_PREFIX2  "/org/a11y/atspi/accessible"
 #define ELM_ACCESS_OBJECT_REFERENCE_TEMPLATE ELM_ACCESS_OBJECT_PATH_PREFIX "%llu"
 
+#define ELM_ATSPI_DBUS_INTERFACE_PROXY "elm.atspi.bridge.proxy.Socket"
+
 #define SIZE(x) sizeof(x)/sizeof(x[0])
 #define ELM_ATSPI_BRIDGE_CLASS_NAME "__Elm_Atspi_Bridge"
 
@@ -96,6 +98,8 @@ typedef struct _Elm_Atspi_Bridge_Data
    } interfaces;
    Elm_Atspi_Event_Handler *event_hdlr;
    Eina_Hash *event_hash;
+   Eina_List *socket_queue;
+   Eina_List *plug_queue;
    Eina_Bool connected : 1;
 } Elm_Atspi_Bridge_Data;
 
@@ -114,6 +118,7 @@ struct collection_match_rule {
 
 static Eo *_instance;
 static int _init_count = 0;
+static const char *_a11y_socket_address;
 
 // Object Event handlers
 static Eina_Bool _state_changed_signal_send(void *data, Eo *obj, const Eo_Event_Description *desc, void *event_info);
@@ -129,6 +134,7 @@ static Eina_Bool _text_caret_moved_send(void *data, Eo *obj, const Eo_Event_Desc
 static Eina_Bool _text_selection_changed_send(void *data, Eo *obj, const Eo_Event_Description *desc, void *event_info EINA_UNUSED);
 
 // bridge private methods
+static void _bridge_cache_build(Eo *bridge, void *obj);
 static void _bridge_object_register(Eo *bridge, Eo *obj);
 static void _bridge_object_unregister(Eo *bridge, Eo *obj);
 static const char * _bridge_path_from_object(Eo *bridge, const Eo *eo);
@@ -142,6 +148,8 @@ static Eina_Bool _elm_atspi_bridge_key_filter(void *data, void *loop, int type,
 static void _object_desktop_reference_append(Eldbus_Message_Iter *iter);
 static Eina_Bool _on_object_add(void *data, Eo *obj, const Eo_Event_Description *event EINA_UNUSED, void *event_info EINA_UNUSED);
 static Eina_Bool _on_object_del(void *data, Eo *obj, const Eo_Event_Description *event EINA_UNUSED, void *event_info EINA_UNUSED);
+static void _plug_connect(Eldbus_Connection *conn, Eo *proxy);
+static void _socket_ifc_create(Eldbus_Connection *conn, Eo *proxy);
 
 typedef struct {
      const Eo_Event_Description *desc;
@@ -1996,6 +2004,58 @@ _editable_text_text_paste(const Eldbus_Service_Interface *iface, const Eldbus_Me
    return ret;
 }
 
+Eina_Bool
+_elm_atspi_bridge_plug_id_split(const char *plug_id, char **bus, char **path)
+{
+   if (!plug_id || !strcmp(plug_id, "")) return EINA_FALSE;
+   unsigned int tokens = 0;
+   char **split = eina_str_split_full(plug_id, ":", 0, &tokens);
+   Eina_Bool ret = EINA_FALSE;
+   if (tokens == 2)
+     {
+        if (bus) *bus = strdup(split[1]);
+        if (path) *path = strdup(split[2]);
+        ret = EINA_TRUE;
+     }
+   else if (tokens == 3)
+     {
+        char buf[128];
+        snprintf(buf, sizeof(buf), ":%s", split[1]);
+        if (bus) *bus = strdup(buf);
+        if (path) *path = strdup(split[2]);
+        ret = EINA_TRUE;
+     }
+
+   free(split[0]);
+   free(split);
+   return ret;
+}
+
+static Eldbus_Message *
+_socket_embedded(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
+{
+   Eo *proxy;
+   const char *obj_path = eldbus_service_object_path_get(iface);
+   const char *bus, *path;
+   Eo *bridge = _elm_atspi_bridge_get();
+   Eo *obj = _bridge_object_from_path(bridge, obj_path);
+   eo_do(obj, proxy = elm_interface_atspi_accessible_parent_get());
+
+   if (!eo_isa(proxy, ELM_ATSPI_PROXY_CLASS))
+     return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.Failed", "Unable to embed object.");
+
+   if (!eldbus_message_arguments_get(msg, "s", &path))
+     return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidArgs", "Plug id expected.");
+
+   bus = eldbus_message_sender_get(msg);
+
+   eo_do(proxy, elm_obj_atspi_proxy_address_set(bus, path));
+
+   _bridge_cache_build(bridge, proxy);
+
+   return eldbus_message_method_return_new(msg);
+}
+
 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 },
@@ -2006,6 +2066,28 @@ static const Eldbus_Method editable_text_methods[] = {
    { NULL, NULL, NULL, NULL, 0 }
 };
 
+static const Eldbus_Method socket_methods[] = {
+   { "Embedded", ELDBUS_ARGS({"s", "id"}), ELDBUS_ARGS({NULL, NULL}), _socket_embedded, 0 },
+   { NULL, NULL, NULL, NULL, 0 }
+};
+
+static const Eldbus_Service_Interface_Desc socket_iface_desc = {
+   ATSPI_DBUS_INTERFACE_SOCKET, socket_methods, NULL, NULL, NULL, NULL
+};
+
+static void _socket_interface_register(Eldbus_Connection *conn, Eo *proxy)
+{
+   Eo *parent;
+   Eo *bridge = _elm_atspi_bridge_get();
+
+   eo_do(proxy, parent = eo_parent_get());
+   if (!eo_isa(parent, ELM_INTERFACE_ATSPI_ACCESSIBLE_MIXIN))
+     return;
+
+   const char *path = _bridge_path_from_object(bridge, parent);
+   eldbus_service_interface_register(conn, path, &socket_iface_desc);
+}
+
 static Eo *
 _bridge_object_from_path(Eo *bridge, const char *path)
 {
@@ -3966,6 +4048,10 @@ _children_changed_signal_send(void *data, Eo *obj, const Eo_Event_Description *d
 
    type = ev_data->is_added ? ATSPI_OBJECT_CHILD_ADDED : ATSPI_OBJECT_CHILD_REMOVED;
 
+   // update cached objects
+   if (ev_data->is_added)
+     _bridge_cache_build(data, ev_data->child);
+
    if (!STATE_TYPE_GET(pd->object_children_broadcast_mask, type))
      return EINA_FALSE;
 
@@ -4243,6 +4329,36 @@ _on_object_del(void *data, Eo *obj, const Eo_Event_Description *event EINA_UNUSE
    return EINA_TRUE;
 }
 
+static void
+_bridge_cache_build(Eo *bridge, void *obj)
+{
+   Eina_List *children;
+   Elm_Atspi_State_Set ss;
+   Eo *child;
+
+   ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(bridge, pd);
+
+   if (!eo_isa(obj, ELM_INTERFACE_ATSPI_ACCESSIBLE_MIXIN))
+     return;
+
+   if (!eo_isa(obj, ELM_ATSPI_PROXY_CLASS))
+      _bridge_object_register(bridge, obj);
+
+   eo_do(obj, ss = elm_interface_atspi_accessible_state_set_get());
+   if (STATE_TYPE_GET(ss, ELM_ATSPI_STATE_MANAGES_DESCENDANTS))
+     return;
+   if (eo_isa(obj, ELM_INTERFACE_ATSPI_WINDOW_INTERFACE))
+     {
+        if (STATE_TYPE_GET(ss, ELM_ATSPI_STATE_ACTIVE))
+          _window_signal_send(bridge, obj, ELM_INTERFACE_ATSPI_WINDOW_EVENT_WINDOW_ACTIVATED, NULL);
+        else
+          _window_signal_send(bridge, obj, ELM_INTERFACE_ATSPI_WINDOW_EVENT_WINDOW_DEACTIVATED, NULL);
+     }
+   eo_do(obj, children = elm_interface_atspi_accessible_children_get());
+   EINA_LIST_FREE(children, child)
+      _bridge_cache_build(bridge, child);
+}
+
 static void
 _interfaces_unregister(Eo *bridge)
 {
@@ -4379,7 +4495,7 @@ static void
 _a11y_bus_initialize(Eo *obj, const char *socket_addr)
 {
    ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(obj, pd);
-
+   Eo *root;
    pd->a11y_bus = eldbus_private_address_connection_get(socket_addr);
    if (!pd->a11y_bus)
      return;
@@ -4395,10 +4511,23 @@ _a11y_bus_initialize(Eo *obj, const char *socket_addr)
    _cache_register(obj);
    _interfaces_register(obj);
    _event_handlers_register(obj);
-   _elm_atspi_bridge_app_register(obj);
+   if (!getenv("ELM_ATSPI_NO_EMBED"))
+     _elm_atspi_bridge_app_register(obj);
+
+   // buid cache
+   eo_do(obj, root = elm_obj_atspi_bridge_root_get());
+   _bridge_cache_build(obj, root);
 
    // register accesible object event listener
    eo_do(ELM_INTERFACE_ATSPI_ACCESSIBLE_MIXIN, pd->event_hdlr = elm_interface_atspi_accessible_event_handler_add(_bridge_accessible_event_dispatch, obj));
+
+   // additionally register all socket objects and its descendants
+   EINA_LIST_FREE(pd->plug_queue, obj)
+   _plug_connect(pd->a11y_bus, obj);
+   EINA_LIST_FREE(pd->socket_queue, obj)
+   _socket_ifc_create(pd->a11y_bus, obj);
+   pd->plug_queue = pd->socket_queue = NULL;
+
 }
 
 static void
@@ -4421,6 +4550,7 @@ _a11y_bus_address_get(void *data, const Eldbus_Message *msg, Eldbus_Pending *pen
         return;
      }
 
+   _a11y_socket_address = eina_stringshare_add(sock_addr);
    _a11y_bus_initialize((Eo*)data, sock_addr);
 }
 
@@ -4439,7 +4569,6 @@ static void _a11y_connection_init(Eo *bridge)
    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)
 {
@@ -4512,6 +4641,9 @@ _elm_atspi_bridge_shutdown(void)
         eo_del(_instance);
         _init_count = 0;
      }
+   if (_a11y_socket_address)
+     eina_stringshare_del(_a11y_socket_address);
+   _a11y_socket_address = NULL;
 }
 
 static Key_Event_Info*
@@ -4740,4 +4872,306 @@ _elm_atspi_bridge_eo_base_destructor(Eo *obj, Elm_Atspi_Bridge_Data *pd)
    eo_do_super(obj, ELM_ATSPI_BRIDGE_CLASS, eo_destructor());
 }
 
+EAPI Eina_Bool
+elm_atspi_bridge_object_address_get(Eo *obj, char **bus, char **path)
+{
+   Eo *bridge = _elm_atspi_bridge_get();
+   if (!bridge)
+     {
+        ERR("Connection with accessibility bus not established.");
+        return EINA_FALSE;
+     }
+   ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN_VAL(bridge, pd, EINA_FALSE);
+   if (!eo_isa(obj, ELM_INTERFACE_ATSPI_ACCESSIBLE_MIXIN))
+     {
+        ERR("Connection with accessibility bus not established.");
+        return EINA_FALSE;
+     }
+   if (bus) *bus = strdup(eldbus_connection_unique_name_get(pd->a11y_bus));
+   if (path) *path = strdup(_bridge_path_from_object(bridge, obj));
+
+   return EINA_TRUE;
+}
+
+static Eina_Bool
+_proxy_property_get(const Eldbus_Service_Interface *interface, const char *property,
+                         Eldbus_Message_Iter *iter, const Eldbus_Message *request_msg EINA_UNUSED,
+                         Eldbus_Message **error EINA_UNUSED)
+{
+   char *bus, *path;
+   Eo *obj = eldbus_service_object_data_get(interface, "_atspi_obj");
+   EINA_SAFETY_ON_NULL_RETURN_VAL(obj, EINA_FALSE);
+
+   if (!strcmp(property, "Object"))
+     {
+       Eo *parent;
+       eo_do(obj, parent = eo_parent_get());
+       if (!elm_atspi_bridge_object_address_get(parent, &bus, &path))
+          return EINA_FALSE;
+
+       Eldbus_Message_Iter *iter_struct = eldbus_message_iter_container_new(iter, 'r', NULL);
+       if (iter_struct)
+         {
+            eldbus_message_iter_basic_append(iter_struct, 's', bus);
+            eldbus_message_iter_basic_append(iter_struct, 'o', path);
+            eldbus_message_iter_container_close(iter, iter_struct);
+         }
+       free(bus);
+       free(path);
+       return EINA_TRUE;
+     }
+   return EINA_FALSE;
+}
+
+static const Eldbus_Property proxy_properties[] = {
+   { "Object", "(so)", _proxy_property_get, NULL, 0 },
+   { NULL, NULL, NULL, NULL, 0 }
+};
+
+static const Eldbus_Service_Interface_Desc _proxy_iface_desc = {
+   ELM_ATSPI_DBUS_INTERFACE_PROXY, NULL, NULL, proxy_properties, NULL, NULL
+};
+
+static void _embedded_reply_cb(void *data, const Eldbus_Message *msg, Eldbus_Pending *pending EINA_UNUSED)
+{
+   Eo *parent, *proxy = data;
+   const char *err, *txt;
+
+   if (eldbus_message_error_get(msg, &err, &txt))
+     {
+        ERR("AT-SPI: Embedded method call failed: %s %s", err, txt);
+        eo_do(proxy, eo_event_callback_call(ELM_ATSPI_PROXY_EVENT_DISCONNECTED, NULL));
+        return;
+     }
+   eo_do(proxy, eo_event_callback_call(ELM_ATSPI_PROXY_EVENT_CONNECTED, NULL));
+
+   eo_do(proxy, parent = eo_parent_get());
+   if (parent)
+     elm_interface_atspi_accessible_children_changed_added_signal_emit(parent, proxy)
+}
+
+static void
+_plug_embedded_send(Eldbus_Connection *conn, Eo *proxy, const char *bus, const char *path)
+{
+   char *obj_path = NULL;
+   Eo *parent;
+   Eldbus_Message *msg = NULL;
+
+   eo_do(proxy, parent = eo_parent_get());
+   if (!parent) goto fail;
+
+   msg = eldbus_message_method_call_new(bus, path, ATSPI_DBUS_INTERFACE_SOCKET, "Embedded");
+   if (!msg) goto fail;
+
+   if (!elm_atspi_bridge_object_address_get(parent, NULL, &obj_path))
+     goto fail;
+
+   if (!eldbus_message_arguments_append(msg, "s", obj_path))
+     goto fail;
+
+   free(obj_path);
+
+   if (!eldbus_connection_send(conn, msg, _embedded_reply_cb, proxy, 100))
+     goto fail;
+
+   return;
+
+fail:
+   ERR("AT-SPI: Unable to send Embedded request.");
+   if (msg) eldbus_message_unref(msg);
+   free(obj_path);
+   eo_do(proxy, eo_event_callback_call(ELM_ATSPI_PROXY_EVENT_DISCONNECTED, NULL));
+}
+
+static void _socket_addr_get_cb(void *data, const Eldbus_Message *msg, Eldbus_Pending *pending EINA_UNUSED)
+{
+   Eo *proxy = data;
+   const char *bus, *path, *err, *txt;
+   Eldbus_Message_Iter *iter, *iter_variant, *iter_struct;
+
+   ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(proxy, pd);
+
+   if (eldbus_message_error_get(msg, &err, &txt))
+     {
+        ERR("Unable to connect to socket: %s %s", err, txt);
+        goto fail;
+     }
+
+   iter = eldbus_message_iter_get(msg);
+   if (!eldbus_message_iter_arguments_get(iter, "v", &iter_variant))
+     {
+        ERR("Unable to get variant parameter");
+        goto fail;
+     }
+
+   if (!eldbus_message_iter_arguments_get(iter_variant, "(so)", &iter_struct))
+     {
+        ERR("Unable to get so parameters");
+        goto fail;
+     }
+
+   if (!eldbus_message_iter_arguments_get(iter_struct, "so", &bus, &path))
+     {
+        ERR("Unable to get so parameters");
+        goto fail;
+     }
+
+   eo_do(proxy, elm_obj_atspi_proxy_address_set(bus, path));
+
+   _plug_embedded_send(pd->a11y_bus, proxy, bus, path);
+
+   return;
+
+fail:
+   eo_do(proxy, eo_event_callback_call(ELM_ATSPI_PROXY_EVENT_DISCONNECTED, NULL));
+}
+
+static void _free_stringshared(void *data)
+{
+   eina_stringshare_del(data);
+}
+
+static void
+_plug_address_discover(Eldbus_Connection *conn, Eo *proxy, const char *svc_bus, const char *svc_path)
+{
+   Eldbus_Object *dobj;
+   dobj = eldbus_object_get(conn, svc_bus, svc_path);
+
+   Eldbus_Message *msg = eldbus_object_method_call_new(dobj, ELDBUS_FDO_INTERFACE_PROPERTIES, "Get");
+   eldbus_message_arguments_append(msg, "ss", ELM_ATSPI_DBUS_INTERFACE_PROXY, "Object");
+   eldbus_object_send(dobj, msg, _socket_addr_get_cb, proxy, 100);
+}
+
+static void _plug_connect(Eldbus_Connection *conn, Eo *proxy)
+{
+   const char *bus, *path;
+
+   eo_do(proxy, bus = eo_key_data_get("__svc_bus"));
+   eo_do(proxy, path = eo_key_data_get("__svc_path"));
+
+   if (bus && path)
+     {
+        _plug_address_discover(conn, proxy, bus, path);
+        return;
+     }
+   else
+     {
+        eo_do(proxy, elm_obj_atspi_proxy_address_get(&bus, &path));
+        if (!bus || !path)
+          {
+             ERR("AT-SPI: Elm_Atspi_Proxy bus or path not set. Unable to connect");
+             eo_do(proxy, eo_event_callback_call(ELM_ATSPI_PROXY_EVENT_DISCONNECTED, NULL));
+             return;
+          }
+        _plug_embedded_send(conn, proxy, bus, path);
+     }
+   return;
+}
+
+static Eina_Bool _from_list_remove(void *data, Eo *obj, const Eo_Event_Description *desc EINA_UNUSED, void *event_info EINA_UNUSED)
+{
+   Eina_List **list = data;
+   *list = eina_list_remove(*list, obj);
+   return EINA_TRUE;
+}
+
+EAPI void elm_atspi_bridge_utils_proxy_connect(Eo *proxy)
+{
+   Eo *bridge = _elm_atspi_bridge_get();
+
+   if (!bridge)
+     {
+        ERR("AT-SPI: Atspi bridge is not enabled.");
+        eo_do(proxy, eo_event_callback_call(ELM_ATSPI_PROXY_EVENT_DISCONNECTED, NULL));
+        return;
+     }
+   ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(bridge, pd);
+
+   if (!pd->a11y_bus)
+     {
+        if (!eina_list_data_find(pd->plug_queue, proxy))
+          {
+             pd->plug_queue = eina_list_append(pd->plug_queue, proxy);
+             eo_do(proxy, eo_event_callback_add(EO_EV_DEL, _from_list_remove, &pd->plug_queue));
+          }
+        return;
+     }
+   _plug_connect(pd->a11y_bus, proxy);
+}
+
+Eo* _elm_atspi_bridge_utils_proxy_create(Eo *parent, const char *svcname, int svcnum, Elm_Atspi_Proxy_Type type)
+{
+   Eo *ret;
+   char bus[64], path[64];
+
+   ret = eo_add(ELM_ATSPI_PROXY_CLASS, parent, elm_obj_atspi_proxy_constructor(type));
+   if (!ret) return NULL;
+
+   snprintf(bus, sizeof(bus), "elm.atspi.proxy.socket.%s-%d", svcname, svcnum);
+   snprintf(path, sizeof(path), "/elm/atspi/proxy/socket/%s/%d", svcname, svcnum);
+
+   eo_do(ret, eo_key_data_set("__svc_bus", eina_stringshare_add(bus)));
+   eo_do(ret, eo_key_data_set("__svc_path", eina_stringshare_add(path)));
+
+   return ret;
+}
+
+static Eina_Bool
+_on_socket_del(void *data, Eo *obj, const Eo_Event_Description *event EINA_UNUSED, void *event_info EINA_UNUSED)
+{
+   Eldbus_Service_Interface *ifc = data;
+   const char *bus;
+   Eldbus_Connection *conn = eldbus_service_connection_get(ifc);
+   eo_do(obj, bus = eo_key_data_get("__svc_bus"));
+   eldbus_name_release(conn, bus, NULL, NULL);
+   eldbus_service_interface_unregister(ifc);
+   return EINA_TRUE;
+}
+
+static void
+_proxy_interface_register(Eldbus_Connection *conn, Eo *proxy, const char *bus, const char *path)
+{
+   Eldbus_Service_Interface *proxy_infc;
+   ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(proxy, pd);
+   eldbus_name_request(conn, bus, ELDBUS_NAME_REQUEST_FLAG_DO_NOT_QUEUE, NULL, NULL);
+   proxy_infc = eldbus_service_interface_register(pd->a11y_bus, path, &_proxy_iface_desc);
+   if (!proxy_infc)
+     ERR("AT-SPI: Proxy interface registration failed");
+   eo_do(proxy, eo_event_callback_add(EO_EV_DEL, _on_socket_del, proxy_infc));
+   eldbus_service_object_data_set(proxy_infc, "_atspi_obj", proxy);
+}
+
+static void _socket_ifc_create(Eldbus_Connection *conn, Eo *proxy)
+{
+   const char *bus, *path;
+
+   eo_do(proxy, bus = eo_key_data_get("__svc_bus"));
+   eo_do(proxy, path = eo_key_data_get("__svc_path"));
+
+   if (bus && path)
+     _proxy_interface_register(conn, proxy, bus, path);
+
+   _socket_interface_register(conn, proxy);
+}
+
+EAPI void elm_atspi_bridge_utils_proxy_listen(Eo *proxy)
+{
+   Eo *bridge = _elm_atspi_bridge_get();
+   if (!bridge)
+     {
+        ERR("AT-SPI: Atspi bridge is not enabled.");
+        return;
+     }
+   ELM_ATSPI_BRIDGE_DATA_GET_OR_RETURN(bridge, pd);
+   if (!pd->a11y_bus)
+     {
+        if (!eina_list_data_find(pd->socket_queue, proxy))
+          {
+             pd->socket_queue = eina_list_append(pd->socket_queue, proxy);
+             eo_do(proxy, eo_event_callback_add(EO_EV_DEL, _from_list_remove, &pd->socket_queue));
+          }
+        return;
+     }
+   _socket_ifc_create(pd->a11y_bus, proxy);
+}
 #include "elm_atspi_bridge.eo.c"
diff --git a/src/lib/elm_atspi_proxy.c b/src/lib/elm_atspi_proxy.c
new file mode 100644 (file)
index 0000000..3aac6d5
--- /dev/null
@@ -0,0 +1,101 @@
+#ifdef HAVE_CONFIG_H
+  #include "elementary_config.h"
+#endif
+
+#define ELM_INTERFACE_ATSPI_ACCESSIBLE_PROTECTED
+
+#include <Elementary.h>
+#include "elm_widget.h"
+#include "elm_priv.h"
+
+
+static Eina_List *_socket_list;
+
+typedef struct _Elm_Atspi_Proxy_Data Elm_Atspi_Proxy_Data;
+
+struct _Elm_Atspi_Proxy_Data
+{
+   Elm_Atspi_Proxy_Type type;
+   const char *bus;
+   const char *path;
+};
+
+EOLIAN static void
+_elm_atspi_proxy_eo_base_destructor(Eo *obj, Elm_Atspi_Proxy_Data *_pd)
+{
+   if (_pd->type == ELM_ATSPI_PROXY_TYPE_SOCKET)
+      _socket_list = eina_list_remove(_socket_list, obj);
+
+   if (_pd->bus) eina_stringshare_del(_pd->bus);
+   if (_pd->path) eina_stringshare_del(_pd->path);
+
+   eo_do_super(obj, ELM_ATSPI_PROXY_CLASS, eo_destructor());
+}
+
+EOLIAN static void
+_elm_atspi_proxy_constructor(Eo *obj, Elm_Atspi_Proxy_Data *_pd, Elm_Atspi_Proxy_Type type)
+{
+   Eo *parent;
+
+   _pd->type = type;
+   eo_do(obj, parent = eo_parent_get());
+   if (!parent || !eo_isa(parent, ELM_INTERFACE_ATSPI_ACCESSIBLE_MIXIN))
+     {
+        CRI("Elm_Atspi_Proxy parent (%s) must implement ELM_INTERFACE_ATSPI_ACCESSIBLE_MIXIN", eo_class_name_get(eo_class_get(parent)));
+        abort();
+     }
+   if (type == ELM_ATSPI_PROXY_TYPE_SOCKET)
+      _socket_list = eina_list_append(_socket_list, obj);
+}
+
+EOLIAN Elm_Atspi_Proxy_Type
+_elm_atspi_proxy_type_get(Eo *obj EINA_UNUSED, Elm_Atspi_Proxy_Data *_pd)
+{
+   return _pd->type;
+}
+
+EOLIAN void
+_elm_atspi_proxy_address_get(Eo *obj EINA_UNUSED, Elm_Atspi_Proxy_Data *_pd, const char **bus, const char **path)
+{
+   if (bus) *bus = _pd->bus;
+   if (path) *path = _pd->path;
+}
+
+EOLIAN void
+_elm_atspi_proxy_address_set(Eo *obj EINA_UNUSED, Elm_Atspi_Proxy_Data *_pd, const char *bus, const char *path)
+{
+   if (bus) eina_stringshare_replace(&_pd->bus, bus);
+   if (path) eina_stringshare_replace(&_pd->path, path);
+}
+
+EOLIAN Eina_List*
+_elm_atspi_proxy_elm_interface_atspi_accessible_children_get(Eo *obj EINA_UNUSED, Elm_Atspi_Proxy_Data *_pd)
+{
+   Eina_List *ret = NULL;
+   if (_pd->type == ELM_ATSPI_PROXY_TYPE_SOCKET)
+     {
+        Eo *parent;
+        eo_do(obj, parent = eo_parent_get());
+        ret = eina_list_append(ret, parent);
+     }
+   return ret;
+}
+
+EOLIAN Eo*
+_elm_atspi_proxy_elm_interface_atspi_accessible_parent_get(Eo *obj EINA_UNUSED, Elm_Atspi_Proxy_Data *_pd)
+{
+   Eo *ret = NULL;
+   if (_pd->type == ELM_ATSPI_PROXY_TYPE_PLUG)
+     {
+        eo_do(obj, ret = eo_parent_get());
+     }
+   return ret;
+}
+
+Eina_List*
+_elm_atspi_proxy_socket_list_get(void)
+{
+   return eina_list_clone(_socket_list);
+}
+
+#include "elm_atspi_proxy.eo.c"
diff --git a/src/lib/elm_atspi_proxy.eo b/src/lib/elm_atspi_proxy.eo
new file mode 100644 (file)
index 0000000..1670649
--- /dev/null
@@ -0,0 +1,42 @@
+class Elm_Atspi_Proxy (Eo.Base, Elm_Interface_Atspi_Accessible)
+{
+   eo_prefix: elm_obj_atspi_proxy;
+   data: Elm_Atspi_Proxy_Data;
+   methods {
+      constructor {
+         [[ No description supplied by the EAPI.]]
+         params {
+            @in type: Elm_Atspi_Proxy_Type;
+         }
+      }
+      @property address {
+         set {
+         }
+         get {
+         }
+         values {
+            bus: const(char)*;
+            path: const(char)*;
+         }
+      }
+      @property type {
+         get {
+         }
+         values {
+            ret:Elm_Atspi_Proxy_Type;
+         }
+      }
+   }
+   constructors {
+      .constructor;
+   }
+   implements {
+      Eo.Base.destructor;
+      Elm_Interface_Atspi_Accessible.children.get;
+      Elm_Interface_Atspi_Accessible.parent.get;
+   }
+   events {
+      connected;
+      disconnected;
+   }
+}
diff --git a/src/lib/elm_atspi_proxy.h b/src/lib/elm_atspi_proxy.h
new file mode 100644 (file)
index 0000000..47cb538
--- /dev/null
@@ -0,0 +1,15 @@
+
+enum _Elm_Atspi_Proxy_Type
+{
+   ELM_ATSPI_PROXY_TYPE_SOCKET,
+   ELM_ATSPI_PROXY_TYPE_PLUG
+};
+typedef enum _Elm_Atspi_Proxy_Type Elm_Atspi_Proxy_Type;
+
+#ifdef EFL_EO_API_SUPPORT
+#include "elm_atspi_proxy.eo.h"
+#endif
+#ifndef EFL_NOLEGACY_API_SUPPORT
+#include "elm_atspi_proxy.eo.legacy.h"
+#endif
+
index 3b132f2396b133b3edb13e45b78321e54eaee6a4..a028aa43b15199f3fdc453119671a6886e1e1f19 100644 (file)
@@ -178,12 +178,27 @@ _elm_plug_connect(Eo *obj, void *sd EINA_UNUSED, const char *svcname, int svcnum
         ecore_evas_data_set(ee, PLUG_KEY, obj);
         ecore_evas_callback_delete_request_set(ee, _elm_plug_disconnected);
         ecore_evas_callback_resize_set(ee, _elm_plug_resized);
+
+        if (_elm_config->atspi_mode)
+          {
+             Eo *proxy = _elm_atspi_bridge_utils_proxy_create(obj, svcname, svcnum, ELM_ATSPI_PROXY_TYPE_PLUG);
+             elm_atspi_bridge_utils_proxy_connect(proxy);
+          }
+
         return EINA_TRUE;
      }
 
    return EINA_FALSE;
 }
 
+EOLIAN static Eina_List*
+_elm_plug_elm_interface_atspi_accessible_children_get(Eo *obj, void *sd EINA_UNUSED)
+{
+   Eina_List *ret;
+   eo_do_super(obj, ELM_WIDGET_CLASS, ret = elm_interface_atspi_accessible_children_get());
+   return ret;
+}
+
 EOLIAN static void
 _elm_plug_class_constructor(Eo_Class *klass)
 {
index 3fe1af385585be2b8c1b126a80814486368bf871..f23795af58fe6207b763f324455b3b6a9bb29cf1 100644 (file)
@@ -33,6 +33,7 @@ class Elm.Plug (Elm.Widget, Evas.Clickable_Interface)
       Evas.Object_Smart.add;
       Elm.Widget.theme_apply;
       Elm.Widget.on_focus;
+      Elm_Interface_Atspi_Accessible.children.get;
    }
    events {
       image,deleted;
index b53158f072e6fbcf0bd1bb4fccc566b29d50e29a..c4699a77e9b6cb92bc730573368b15926ca70752 100644 (file)
@@ -534,6 +534,9 @@ void                *_elm_icon_signal_callback_del(Evas_Object *obj,
                                                    const char *emission,
                                                    const char *source,
                                                    Edje_Signal_Cb func_cb);
+Eo*                  _elm_atspi_bridge_utils_proxy_create(Eo *parent, const char *svcname, int svcnum, Elm_Atspi_Proxy_Type type);
+void                 elm_atspi_bridge_utils_proxy_listen(Eo *proxy);
+void                 elm_atspi_bridge_utils_proxy_connect(Eo *proxy);
 /* end of DEPRECATED */
 
 
index fab3e374b95cbc5065282ec9ba5da5b7337a36c8..565283a027058ab3b9c73a0c45c4191f8ece7d13 100644 (file)
@@ -534,7 +534,7 @@ _elm_widget_evas_object_smart_show(Eo *obj, Elm_Widget_Smart_Data *_pd EINA_UNUS
      {
         Eo *parent;
         eo_do(obj, parent = elm_interface_atspi_accessible_parent_get());
-        elm_interface_atspi_accessible_children_changed_added_signal_emit(parent, obj);
+        if (parent) elm_interface_atspi_accessible_children_changed_added_signal_emit(parent, obj);
      }
 
    it = evas_object_smart_iterator_new(obj);
index e0f383a07aa5965e3aff30d052db20034155b864..965809da161c2bae8803665911c2d0c9e6117cc3 100644 (file)
@@ -816,6 +816,8 @@ EAPI void             elm_widget_focus_move_policy_automatic_set(Evas_Object *ob
 EAPI void             elm_widget_focus_region_show_mode_set(Evas_Object *obj, Elm_Focus_Region_Show_Mode mode);
 EAPI Elm_Focus_Region_Show_Mode elm_widget_focus_region_show_mode_get(const Evas_Object *obj);
 EAPI void             elm_widget_focus_reconfigure(Evas_Object *obj);
+EAPI Eo*              _elm_atspi_bridge_utils_plug_create(Eo *parent, const char *svcname, int svcnum);
+EAPI Eo*              _elm_atspi_bridge_utils_socket_create(Eo *parent, const char *svcname, int svcnum);
 
 /**
  * Function to operate on a given widget's scrollabe children when necessary.
index a0943bfde26aac00466b508a860d961910042d33..df12dbae8845240cc8e2bc49fb0c2ca9d9de35d9 100644 (file)
@@ -211,6 +211,8 @@ struct _Elm_Win_Data
       Eina_Bool    use : 1; /* set ture when application use window manager rotation. */
    } wm_rot;
 
+   Eo *socket_proxy; /* reference object to atspi object in separate process @since 1.15 */
+
    void *trap_data;
 
    struct
@@ -5969,6 +5971,14 @@ _elm_win_socket_listen(Eo *obj EINA_UNUSED, Elm_Win_Data *sd, const char *svcnam
    if (!ecore_evas_extn_socket_listen(sd->ee, svcname, svcnum, svcsys))
      return EINA_FALSE;
 
+   if (_elm_config->atspi_mode)
+     {
+        if (sd->socket_proxy)
+          eo_unref(sd->socket_proxy);
+        sd->socket_proxy = _elm_atspi_bridge_utils_proxy_create(obj, svcname, svcnum, ELM_ATSPI_PROXY_TYPE_SOCKET);
+        elm_atspi_bridge_utils_proxy_listen(sd->socket_proxy);
+     }
+
    return EINA_TRUE;
 }