[Tizen][ATSPI] Accessibility initial implementation 35/177135/2
authorRadoslaw Cybulski <r.cybulski@partner.samsung.com>
Wed, 25 Apr 2018 13:33:21 +0000 (15:33 +0200)
committerdongsug.song <dongsug.song@samsung.com>
Mon, 30 Apr 2018 12:38:37 +0000 (21:38 +0900)
Change-Id: Ida2c9d1be49d2c09a3bf1dd0e461955eb42fe433

39 files changed:
build/tizen/adaptor/Makefile.am
build/tizen/adaptor/module.list
dali/dali-bridge/file.list [new file with mode: 0644]
dali/dali-bridge/src/Accessible.cpp [new file with mode: 0755]
dali/dali-bridge/src/BridgeAccessible.cpp [new file with mode: 0755]
dali/dali-bridge/src/BridgeAccessible.hpp [new file with mode: 0644]
dali/dali-bridge/src/BridgeAction.cpp [new file with mode: 0755]
dali/dali-bridge/src/BridgeAction.hpp [new file with mode: 0644]
dali/dali-bridge/src/BridgeBase.cpp [new file with mode: 0755]
dali/dali-bridge/src/BridgeBase.hpp [new file with mode: 0644]
dali/dali-bridge/src/BridgeCollection.cpp [new file with mode: 0644]
dali/dali-bridge/src/BridgeCollection.hpp [new file with mode: 0644]
dali/dali-bridge/src/BridgeComponent.cpp [new file with mode: 0644]
dali/dali-bridge/src/BridgeComponent.hpp [new file with mode: 0644]
dali/dali-bridge/src/BridgeEditableText.cpp [new file with mode: 0644]
dali/dali-bridge/src/BridgeEditableText.hpp [new file with mode: 0644]
dali/dali-bridge/src/BridgeImpl.cpp [new file with mode: 0644]
dali/dali-bridge/src/BridgeImpl.hpp [new file with mode: 0644]
dali/dali-bridge/src/BridgeObject.cpp [new file with mode: 0644]
dali/dali-bridge/src/BridgeObject.hpp [new file with mode: 0644]
dali/dali-bridge/src/BridgeText.cpp [new file with mode: 0644]
dali/dali-bridge/src/BridgeText.hpp [new file with mode: 0644]
dali/dali-bridge/src/BridgeValue.cpp [new file with mode: 0644]
dali/dali-bridge/src/BridgeValue.hpp [new file with mode: 0644]
dali/dali-bridge/src/Common.hpp [new file with mode: 0755]
dali/dali-bridge/src/Component.cpp [new file with mode: 0644]
dali/dali-bridge/src/DBus.cpp [new file with mode: 0644]
dali/dali-bridge/src/DBus.hpp [new file with mode: 0755]
dali/dali-bridge/src/Optional.hpp [new file with mode: 0755]
dali/dali-bridge/src/dbusLocators.hpp [new file with mode: 0644]
dali/devel-api/adaptor-framework/accessibility.h [new file with mode: 0644]
dali/devel-api/file.list [changed mode: 0644->0755]
dali/internal/accessibility/accessibility-impl.cpp [new file with mode: 0644]
dali/internal/accessibility/file.list
dali/internal/adaptor/common/adaptor-impl.cpp
dali/internal/adaptor/common/adaptor-impl.h
dali/public-api/adaptor-framework/accessibility.h [new file with mode: 0644]
dali/public-api/file.list
packaging/dali-adaptor.spec [changed mode: 0644->0755]

index 190aab1..90f7104 100644 (file)
@@ -40,6 +40,7 @@ LIBDALI_ADAPTOR_LA_SOURCES = \
                   $(adaptor_clipboard_common_src_files) \
                   $(adaptor_clipboard_ubuntu_x11_src_files) \
                   $(devel_api_src_files) \
+                  $(bridge_src_files) \
                   $(adaptor_devel_api_text_abstraction_src_files) \
                   $(adaptor_graphics_common_src_files) \
                   $(adaptor_graphics_gles20_src_files) \
@@ -95,6 +96,7 @@ LIBDALI_ADAPTOR_LA_SOURCES = \
                   $(adaptor_adaptor_tizen_wayland_src_files) \
                   $(adaptor_clipboard_common_src_files) \
                   $(devel_api_src_files) \
+                  $(bridge_src_files) \
                   $(adaptor_devel_api_text_abstraction_src_files) \
                   $(adaptor_graphics_common_src_files) \
                   $(adaptor_graphics_gles20_src_files) \
@@ -158,6 +160,7 @@ LIBDALI_ADAPTOR_LA_SOURCES = \
                   $(adaptor_adaptor_tizen_wayland_src_files) \
                   $(adaptor_clipboard_common_src_files) \
                   $(devel_api_src_files) \
+                  $(bridge_src_files) \
                   $(adaptor_devel_api_text_abstraction_src_files) \
                   $(adaptor_graphics_common_src_files) \
                   $(adaptor_graphics_gles20_src_files) \
@@ -221,6 +224,7 @@ LIBDALI_ADAPTOR_LA_SOURCES = \
                   $(adaptor_adaptor_tizen_wayland_src_files) \
                   $(adaptor_clipboard_common_src_files) \
                   $(devel_api_src_files) \
+                  $(bridge_src_files) \
                   $(adaptor_devel_api_text_abstraction_src_files) \
                   $(adaptor_graphics_common_src_files) \
                   $(adaptor_graphics_gles20_src_files) \
@@ -282,6 +286,7 @@ LIBDALI_ADAPTOR_LA_SOURCES = \
                   $(adaptor_adaptor_tizen_wayland_src_files) \
                   $(adaptor_clipboard_common_src_files) \
                   $(devel_api_src_files) \
+                  $(bridge_src_files) \
                   $(adaptor_devel_api_text_abstraction_src_files) \
                   $(adaptor_graphics_common_src_files) \
                   $(adaptor_graphics_gles20_src_files) \
@@ -346,6 +351,7 @@ LIBDALI_ADAPTOR_LA_SOURCES = \
                   $(adaptor_adaptor_tizen_wearable_src_files) \
                   $(adaptor_clipboard_common_src_files) \
                   $(devel_api_src_files) \
+                  $(bridge_src_files) \
                   $(adaptor_devel_api_text_abstraction_src_files) \
                   $(adaptor_graphics_common_src_files) \
                   $(adaptor_graphics_gles20_src_files) \
index 297e0b3..c38a303 100755 (executable)
@@ -7,6 +7,10 @@ include ../../../dali/internal/accessibility/file.list
 adaptor_adaptor_dir = ../../../dali/internal/adaptor
 include ../../../dali/internal/adaptor/file.list
 
+# Module: atspi-bridge
+bridge_src_dir = ../../../dali/dali-bridge
+include ../../../dali/dali-bridge/file.list
+
 # Module: clipboard
 adaptor_clipboard_dir = ../../../dali/internal/clipboard
 include ../../../dali/internal/clipboard/file.list
@@ -59,7 +63,7 @@ include ../../../dali/internal/video/file.list
 adaptor_web_engine_dir = ../../../dali/internal/web-engine-lite
 include ../../../dali/internal/web-engine-lite/file.list
 
-# Module: window-system 
+# Module: window-system
 adaptor_window_system_dir = ../../../dali/internal/window-system
 include ../../../dali/internal/window-system/file.list
 
diff --git a/dali/dali-bridge/file.list b/dali/dali-bridge/file.list
new file mode 100644 (file)
index 0000000..0cb402d
--- /dev/null
@@ -0,0 +1,14 @@
+bridge_src_files = \
+  $(bridge_src_dir)/src/Accessible.cpp \
+  $(bridge_src_dir)/src/Component.cpp \
+  $(bridge_src_dir)/src/BridgeAccessible.cpp \
+  $(bridge_src_dir)/src/BridgeCollection.cpp \
+  $(bridge_src_dir)/src/BridgeBase.cpp \
+  $(bridge_src_dir)/src/BridgeComponent.cpp \
+  $(bridge_src_dir)/src/BridgeAction.cpp \
+  $(bridge_src_dir)/src/BridgeValue.cpp \
+  $(bridge_src_dir)/src/BridgeObject.cpp \
+  $(bridge_src_dir)/src/BridgeImpl.cpp \
+  $(bridge_src_dir)/src/DBus.cpp \
+  $(bridge_src_dir)/src/BridgeText.cpp \
+  $(bridge_src_dir)/src/BridgeEditableText.cpp
diff --git a/dali/dali-bridge/src/Accessible.cpp b/dali/dali-bridge/src/Accessible.cpp
new file mode 100755 (executable)
index 0000000..9612143
--- /dev/null
@@ -0,0 +1,157 @@
+#include "Common.hpp"
+
+using namespace Dali::Accessibility;
+
+std::vector< std::string > Accessible::GetInterfaces()
+{
+  std::vector< std::string > tmp;
+  tmp.push_back( ATSPI_DBUS_INTERFACE_ACCESSIBLE );
+  if( dynamic_cast< Collection* >( this ) )
+    tmp.push_back( ATSPI_DBUS_INTERFACE_COLLECTION );
+  if( dynamic_cast< Text* >( this ) )
+    tmp.push_back( ATSPI_DBUS_INTERFACE_TEXT );
+  if( dynamic_cast< Value* >( this ) )
+    tmp.push_back( ATSPI_DBUS_INTERFACE_VALUE );
+  if( dynamic_cast< Component* >( this ) )
+    tmp.push_back( ATSPI_DBUS_INTERFACE_COMPONENT );
+  if( auto d = dynamic_cast< Action* >( this ) )
+  {
+    if( d->GetActionCount() > 0 )
+      tmp.push_back( ATSPI_DBUS_INTERFACE_ACTION );
+  }
+  return tmp;
+}
+
+thread_local std::atomic< Bridge* > threadLocalBridge{};
+std::atomic< Bridge* > allThreads{};
+
+Bridge* Bridge::GetCurrentBridge()
+{
+  auto p = threadLocalBridge.load();
+  if( !p )
+    p = allThreads.load();
+  return p;
+}
+
+Accessible::Accessible()
+{
+}
+
+Accessible::~Accessible()
+{
+  auto b = bridgeData.lock();
+  if( b )
+    b->objects.erase( it );
+}
+
+void Bridge::MakePublic( Visibility vis )
+{
+  bool res = false;
+  Bridge* expected = this;
+
+  switch( vis )
+  {
+    case Visibility::hidden:
+    {
+      threadLocalBridge.compare_exchange_strong( expected, nullptr );
+      allThreads.compare_exchange_strong( expected, nullptr );
+      break;
+    }
+    case Visibility::thisThreadOnly:
+    {
+      res = threadLocalBridge.exchange( this );
+      assert( !res );
+      break;
+    }
+    case Visibility::allThreads:
+    {
+      res = allThreads.exchange( this );
+      assert( !res );
+      break;
+    }
+  }
+}
+
+void Accessible::EmitShowing( bool showing )
+{
+  if( auto b = GetBridgeData() )
+  {
+    b->bridge->EmitStateChanged( this, State::Showing, showing ? 1 : 0, 0 );
+  }
+}
+
+void Accessible::EmitVisible( bool visible )
+{
+  if( auto b = GetBridgeData() )
+  {
+    b->bridge->EmitStateChanged( this, State::Visible, visible ? 1 : 0, 0 );
+  }
+}
+
+void Accessible::EmitHighlighted( bool set )
+{
+  if( auto b = GetBridgeData() )
+  {
+    b->bridge->EmitStateChanged( this, State::Highlighted, set ? 1 : 0, 0 );
+  }
+}
+
+void Accessible::Emit( WindowEvent we, unsigned int detail1 )
+{
+  if( auto b = GetBridgeData() )
+  {
+    b->bridge->Emit( this, we, detail1 );
+  }
+}
+
+std::vector< Accessible* > Accessible::GetChildren()
+{
+  std::vector< Accessible* > tmp( GetChildCount() );
+  for( auto i = 0u; i < tmp.size(); ++i )
+  {
+    tmp[i] = GetChildAtIndex( i );
+  }
+  return tmp;
+}
+
+std::shared_ptr< Bridge::Data > Accessible::GetBridgeData()
+{
+  auto b = bridgeData.lock();
+  if( !b )
+  {
+    auto p = Bridge::GetCurrentBridge();
+    if( !p )
+      return {};
+    b = p->data;
+  }
+  return b;
+}
+
+Address Accessible::GetAddress()
+{
+  auto b = bridgeData.lock();
+  if( !b )
+  {
+    b = GetBridgeData();
+    assert( b );
+    b->bridge->RegisterOnBridge( this );
+  }
+  return {b->busName, b->root == this ? "root" : std::to_string( it->first )};
+}
+
+void Bridge::RegisterOnBridge( Accessible* obj )
+{
+  assert( !obj->bridgeData.lock() || obj->bridgeData.lock() == data );
+  if( !obj->bridgeData.lock() )
+  {
+    assert( data );
+    auto oid = ++data->objectId;
+    obj->it = data->objects.insert( {oid, obj} ).first;
+    obj->bridgeData = data;
+  }
+}
+
+bool Accessible::IsProxy()
+{
+  return false;
+}
diff --git a/dali/dali-bridge/src/BridgeAccessible.cpp b/dali/dali-bridge/src/BridgeAccessible.cpp
new file mode 100755 (executable)
index 0000000..eafa947
--- /dev/null
@@ -0,0 +1,732 @@
+#include "BridgeAccessible.hpp"
+#include <iostream>
+
+using namespace Dali::Accessibility;
+
+#define GET_NAVIGABLE_AT_POINT_MAX_RECURSION_DEPTH 10000
+
+BridgeAccessible::BridgeAccessible()
+{
+}
+
+void BridgeAccessible::RegisterInterfaces()
+{
+  DBus::DBusInterfaceDescription desc{ATSPI_DBUS_INTERFACE_ACCESSIBLE};
+  AddGetPropertyToInterface( desc, "ChildCount", &BridgeAccessible::GetChildCount );
+  AddGetPropertyToInterface( desc, "Name", &BridgeAccessible::GetName );
+  AddGetPropertyToInterface( desc, "Description", &BridgeAccessible::GetDescription );
+  AddGetPropertyToInterface( desc, "Parent", &BridgeAccessible::GetParent );
+  AddFunctionToInterface( desc, "GetRole", &BridgeAccessible::GetRole );
+  AddFunctionToInterface( desc, "GetRoleName", &BridgeAccessible::GetRoleName );
+  AddFunctionToInterface( desc, "GetLocalizedRoleName", &BridgeAccessible::GetLocalizedRoleName );
+  AddFunctionToInterface( desc, "GetState", &BridgeAccessible::GetStates );
+  AddFunctionToInterface( desc, "GetAttributes", &BridgeAccessible::GetAttributes );
+  AddFunctionToInterface( desc, "GetInterfaces", &BridgeAccessible::GetInterfaces );
+  AddFunctionToInterface( desc, "GetChildAtIndex", &BridgeAccessible::GetChildAtIndex );
+  AddFunctionToInterface( desc, "GetChildren", &BridgeAccessible::GetChildren );
+  AddFunctionToInterface( desc, "GetIndexInParent", &BridgeAccessible::GetIndexInParent );
+  AddFunctionToInterface( desc, "GetNavigableAtPoint", &BridgeAccessible::GetNavigableAtPoint );
+  AddFunctionToInterface( desc, "GetNeighbor", &BridgeAccessible::GetNeighbor );
+  AddFunctionToInterface( desc, "GetDefaultLabelInfo", &BridgeAccessible::GetDefaultLabelInfo );
+  AddFunctionToInterface( desc, "DoGesture", &BridgeAccessible::DoGesture );
+  AddFunctionToInterface( desc, "GetReadingMaterial", &BridgeAccessible::GetReadingMaterial );
+  dbusServer.addInterface( "/", desc, true );
+}
+
+static bool AcceptObjectCheckRole( Component* obj )
+{
+  if( !obj )
+    return false;
+  switch( obj->GetRole() )
+  {
+    case Role::Application:
+    case Role::Filler:
+    case Role::ScrollPane:
+    case Role::SplitPane:
+    case Role::Window:
+    case Role::Image:
+    case Role::ImageMap:
+    case Role::List:
+    case Role::Icon:
+    case Role::ToolBar:
+    case Role::RedundantObject:
+    case Role::ColorChooser:
+    case Role::TreeTable:
+    case Role::PageTabList:
+    case Role::PageTab:
+    case Role::SpinButton:
+    case Role::InputMethodWindow:
+    case Role::Embedded:
+    case Role::Invalid:
+    case Role::Notification:
+    case Role::DateEditor:
+    {
+      return false;
+    }
+    default:
+    {
+      break;
+    }
+  }
+
+  return true;
+}
+
+static Component* GetScrollableParent( Accessible* obj )
+{
+  while( obj )
+  {
+    obj = obj->GetParent();
+    auto comp = dynamic_cast< Component* >( obj );
+    if( comp && comp->IsScrollable() )
+      return comp;
+  }
+  return nullptr;
+}
+
+static bool ObjectIsItem( Component* obj )
+{
+  if( !obj )
+    return false;
+  auto role = obj->GetRole();
+  return role == Role::ListItem || role == Role::MenuItem;
+}
+
+static bool ObjectIsCollapsed( Component* obj )
+{
+  if( !obj )
+    return false;
+  const auto states = obj->GetStates();
+  return states[State::Expandable] && !states[State::Expanded];
+}
+
+static bool OobjectIsZeroSize( Component* obj )
+{
+  if( !obj )
+    return false;
+  auto size = obj->GetExtents( CoordType::Window ).size;
+  return size.height == 0 || size.width == 0;
+}
+
+static bool AcceptObject( Component* obj )
+{
+  if( !obj )
+    return false;
+  const auto states = obj->GetStates();
+  if( !states[State::Visible] )
+    return false;
+  if( !AcceptObjectCheckRole( obj ) )
+    return false;
+/*
+  TODO: add relations
+  if (CALL(get_object_in_relation_by_type, obj, ATSPI_RELATION_CONTROLLED_BY) != NULL) return 0;
+*/
+  if( !states[State::Highlightable] )
+    return false;
+
+  if( GetScrollableParent( obj ) != nullptr )
+  {
+    auto parent = dynamic_cast< Component* >( obj->GetParent() );
+
+    if( parent )
+    {
+      return !ObjectIsItem( obj ) || !ObjectIsCollapsed( parent );
+    }
+  }
+  else
+  {
+    if( OobjectIsZeroSize( obj ) )
+    {
+      return false;
+    }
+    if( !states[State::Showing] )
+    {
+      return false;
+    }
+  }
+  return true;
+}
+
+static bool AcceptObject( Accessible* obj )
+{
+  auto c = dynamic_cast< Component* >( obj );
+  return AcceptObject( c );
+}
+
+static bool AcceptObjectOrProxy( Component* obj )
+{
+  return obj->IsProxy() || AcceptObject( obj );
+}
+
+static Component* CalculateNavigableAccessibleAtPoint( Accessible* root, Point p, CoordType cType, unsigned int maxRecursionDepth )
+{
+  if( !root || maxRecursionDepth == 0 )
+    return nullptr;
+  auto root_component = dynamic_cast< Component* >( root );
+  if( root_component && !root_component->Contains( p, cType ) )
+  {
+    return nullptr;
+  }
+
+  auto children = root->GetChildren();
+  for( auto childIt = children.rbegin(); childIt != children.rend(); childIt++ )
+  {
+    auto result = CalculateNavigableAccessibleAtPoint( *childIt, p, cType, maxRecursionDepth - 1 );
+    if( result )
+      return result;
+  }
+  if( root_component && AcceptObjectOrProxy( root_component ) )
+    return root_component;
+  return nullptr;
+
+  /*
+  TODO: add relations
+  void *relation_obj = CALL(get_object_in_relation_by_type, root, ATSPI_RELATION_CONTROLLED_BY);
+  unsigned char contains = 0;
+  if (relation_obj)
+  {
+    contains = CALL(object_contains, relation_obj, x, y, coordinates_are_screen_based);
+    if (contains) root = relation_obj;
+  }
+  */
+}
+
+BridgeAccessible::ReadingMaterialType BridgeAccessible::GetReadingMaterial()
+{
+  auto self = FindSelf();
+  auto attributes = self->GetAttributes();
+  auto name = self->GetName();
+  std::string labeledByName = "";
+  std::string textIfceName = "";
+  auto role = static_cast< uint32_t >( self->GetRole() );
+  auto states = self->GetStates();
+  auto localizedName = self->GetLocalizedRoleName();
+  auto childCount = static_cast< int32_t >( self->GetChildCount() );
+
+  double currentValue = 0.0;
+  double minimumIncrement = 0.0;
+  double maximumValue = 0.0;
+  double minimumValue = 0.0;
+
+  auto description = self->GetDescription();
+  auto indexInParent = static_cast< int32_t >( self->GetIndexInParent() );
+  bool isSelectedInParent = false;
+  bool hasCheckBoxChild = false;
+  int32_t firstSelectedChildIndex = 0;
+  int32_t selectedChildCount = 0;
+
+  for( auto i = 0u; i < static_cast< size_t >( childCount ); ++i )
+  {
+    auto q = self->GetChildAtIndex( i );
+    auto s = q->GetStates();
+    if( s[State::Selectable] )
+    {
+      ++selectedChildCount;
+      if( s[State::Selected] )
+      {
+        if( firstSelectedChildIndex < 0 )
+          firstSelectedChildIndex = static_cast< int32_t >( i );
+      }
+    }
+    if( q->GetRole() == Role::CheckBox )
+      hasCheckBoxChild = true;
+  }
+
+  int32_t listChildrenCount = 0;
+  Accessible* parent = self->GetParent();
+  auto parentStateSet = parent ? parent->GetStates() : States{};
+  auto parentChildCount = parent ? static_cast< int32_t >( parent->GetChildCount() ) : 0;
+  auto parentRole = static_cast< uint32_t >( parent ? parent->GetRole() : Role{} );
+  Accessible* describedByObject = nullptr;
+
+  return {
+      attributes,
+      name,
+      labeledByName,
+      textIfceName,
+      role,
+      states,
+      localizedName,
+      childCount,
+      currentValue,
+      minimumIncrement,
+      maximumValue,
+      minimumValue,
+      description,
+      indexInParent,
+      isSelectedInParent,
+      hasCheckBoxChild,
+      listChildrenCount,
+      firstSelectedChildIndex,
+      parent,
+      parentStateSet,
+      parentChildCount,
+      parentRole,
+      selectedChildCount,
+      describedByObject};
+}
+
+DBus::ValueOrError< bool > BridgeAccessible::DoGesture( int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, uint32_t )
+{
+  return false;
+}
+
+DBus::ValueOrError< Accessible*, uint8_t, Accessible* > BridgeAccessible::GetNavigableAtPoint( int32_t x, int32_t y, uint32_t coordType )
+{
+  SCOPE();
+  Accessible* deputy = nullptr;
+  auto accessible = FindSelf();
+  auto cType = static_cast< CoordType >( coordType );
+  auto component = CalculateNavigableAccessibleAtPoint( accessible, {x, y}, cType, GET_NAVIGABLE_AT_POINT_MAX_RECURSION_DEPTH );
+  bool recurse = false;
+  if( component )
+  {
+    const auto states = component->GetStates();
+    if( states[State::Modal] )
+    {
+      component = nullptr;
+    }
+  }
+  if( component )
+  {
+    recurse = component->IsProxy();
+  }
+  //TODO: add deputy
+  return {component, recurse, deputy};
+}
+
+static bool CheckChainEndWithAttribute( Accessible* obj, unsigned char forward )
+{
+  if( !obj )
+    return false;
+  auto attrs = obj->GetAttributes();
+  for( auto& attr : attrs )
+  {
+    if( attr.first == "relation_chain_end" )
+    {
+      if( ( attr.second == "prev,end" && forward == 0 ) || ( attr.second == "next,end" && forward == 1 ) || attr.second == "prev,next,end" )
+      {
+        return true;
+      }
+    }
+  }
+  return false;
+}
+
+static Accessible* DeputyOfProxyInParentGet( Accessible* obj )
+{
+  return nullptr;
+/*
+if (!obj)
+  return nullptr;
+
+Accessible *deputy = nullptr;
+auto children = obj->GetChildren();
+unsigned int index = 0;
+for (auto child : children) {
+  if (child->IsProxy()) {
+    if (index == 0) {
+      //WRN("Proxy does not have deputy object");
+      break;
+    }
+    deputy = children[index - 1];
+    break;
+  }
+  index++;
+}
+return deputy;
+*/
+}
+
+Accessible* BridgeAccessible::GetCurrentlyHighlighted()
+{
+  //TODO: add currently highlighted object
+  return nullptr;
+}
+
+std::vector< Accessible* > BridgeAccessible::ValidChildrenGet( const std::vector< Accessible* >& children, Accessible* start, Accessible* root )
+{
+  /* condition to find first(last) object regardless of scrollable parent.
+      looping navigation does not care scrollable parent.
+      1. currently highlighted object exists
+      2. both start and root are same */
+
+  /* TODO: add code, we need a scrollable implementation first
+  Accessible *current = GetCurrentlyHighlighted();
+   if (current && start == root) return children;
+   if(children.size() == 0) return {};
+
+   Eo *child = children[0];
+
+   if (child)
+     {
+        Evas_Coord x = 0, y = 0, w = 0, h = 0;
+        Evas_Coord sx = 0, sy = 0, sw = 0, sh = 0;
+
+        if (_new_scrollable_parent_viewport_geometry_get(child, start,
+                                                   &sx, &sy, &sw, &sh))
+          {
+             Eina_List *l, *l_next;
+             EINA_LIST_FOREACH_SAFE(children, l, l_next, child)
+               {
+                  eo_do(child,
+                        elm_interface_atspi_component_extents_get(EINA_FALSE,
+                                                             &x, &y, &w, &h));
+                  if (w == 0 || h == 0 ||
+                      !ELM_RECTS_INTERSECT(x, y, w, h, sx, sy, sw, sh))
+                     children = eina_list_remove_list(children, l);
+               }
+          }
+     }
+     */
+  return children;
+}
+
+static bool DeputyIs( Accessible* obj )
+{
+  //TODO: add deputy
+  return false;
+}
+
+static Accessible* GetObjectInRelationFlow( Accessible* ptr, RelationType type )
+{
+  //TODO: add relations
+  return nullptr;
+}
+static Accessible* ProxyInParentGet( Accessible* obj )
+{
+  if( !obj )
+    return nullptr;
+  auto children = obj->GetChildren();
+  for( auto& child : children )
+  {
+    if( child->IsProxy() )
+      return child;
+  }
+  return nullptr;
+}
+
+static bool ObjectRoleIsAcceptableWhenNavigatingNextPrev( Accessible* obj )
+{
+  if( !obj )
+    return false;
+  auto role = obj->GetRole();
+  return role != Role::PopupMenu && role != Role::Dialog;
+}
+
+template < class T >
+struct CycleDetection
+{
+  CycleDetection( const T value ) : key( value ), currentSearchSize( 1 ), counter( 1 ) {}
+  bool check( const T value )
+  {
+    if( key == value )
+      return true;
+    if( --counter == 0 )
+    {
+      currentSearchSize <<= 1;
+      if( currentSearchSize == 0 )
+        return true; // UNDEFINED BEHAVIOR
+      counter = currentSearchSize;
+      key = value;
+    }
+    return false;
+  }
+  T key;
+  unsigned int currentSearchSize;
+  unsigned int counter;
+};
+
+static Accessible* FindNonDefunctChild( const std::vector< Accessible* >& children, unsigned int currentIndex, unsigned char forward )
+{
+  unsigned int childrenCount = children.size();
+  for( ; currentIndex < childrenCount; forward ? ++currentIndex : --currentIndex )
+  {
+    Accessible* n = children[currentIndex];
+    if( n && !n->GetStates()[State::Defunct] )
+      return n;
+  }
+  return nullptr;
+}
+
+static Accessible* DirectionalDepthFirstSearchTryNonDefunctChild( Accessible* node, const std::vector< Accessible* >& children, unsigned char forward )
+{
+  if( !node )
+    return nullptr;
+  auto childrenCount = children.size();
+  if( childrenCount > 0 )
+  {
+    const bool isShowing = GetScrollableParent( node ) == nullptr ? node->GetStates()[State::Showing] : true;
+    if( isShowing )
+    {
+      return FindNonDefunctChild( children, forward ? 0 : childrenCount - 1, forward );
+    }
+  }
+  return nullptr;
+}
+
+Accessible* BridgeAccessible::GetNextNonDefunctSibling( Accessible* obj, Accessible* start, Accessible* root, unsigned char forward )
+{
+  if( !obj )
+    return nullptr;
+  auto parent = obj->GetParent();
+  if( !parent )
+    return nullptr;
+
+  auto children = ValidChildrenGet( parent->GetChildren(), start, root );
+
+  unsigned int children_count = children.size();
+  if( children_count == 0 )
+  {
+    return nullptr;
+  }
+  unsigned int current = 0;
+  for( ; current < children_count && children[current] != obj; ++current )
+    ;
+  if( current >= children_count )
+  {
+    return nullptr;
+  }
+  forward ? ++current : --current;
+  auto ret = FindNonDefunctChild( children, current, forward );
+  return ret;
+}
+
+Accessible* BridgeAccessible::DirectionalDepthFirstSearchTryNonDefunctSibling( bool& all_children_visited, Accessible* node, Accessible* start, Accessible* root, unsigned char forward )
+{
+  while( true )
+  {
+    Accessible* sibling = GetNextNonDefunctSibling( node, start, root, forward );
+    if( sibling )
+    {
+      node = sibling;
+      all_children_visited = false;
+      break;
+    }
+    // walk up...
+    node = node->GetParent();
+    if( node == nullptr || node == root )
+      return nullptr;
+
+    // in backward traversing stop the walk up on parent
+    if( !forward )
+      break;
+  }
+  return node;
+}
+
+Accessible* BridgeAccessible::CalculateNeighbor( Accessible* root, Accessible* start, unsigned char forward, BridgeAccessible::GetNeighborSearchMode search_mode )
+{
+  if( start && CheckChainEndWithAttribute( start, forward ) )
+    return start;
+  if( root && root->GetStates()[State::Defunct] )
+    return NULL;
+  if( start && start->GetStates()[State::Defunct] )
+  {
+    start = NULL;
+    forward = 1;
+  }
+
+  if( search_mode == BridgeAccessible::GetNeighborSearchMode::recurseToOutside )
+  {
+    /* This only works if we navigate backward, and it is not possible to
+     find in embedded process. In this case the deputy should be used */
+    return DeputyOfProxyInParentGet( start );
+  }
+
+  Accessible* node = start ? start : root;
+  if( !node )
+    return nullptr;
+
+  // initialization of all-children-visited flag for start node - we assume
+  // that when we begin at start node and we navigate backward, then all children
+  // are visited, so navigation will ignore start's children and go to
+  // previous sibling available.
+  /* Regarding condtion (start != root):
+   The last object can be found only if all_children_visited is false.
+   The start is same with root, when looking for the last object. */
+  bool all_children_visited = ( start != root ) && ( search_mode != BridgeAccessible::GetNeighborSearchMode::recurseFromRoot && !forward );
+  // true, if starting element should be ignored. this is only used in rare case of
+  // recursive search failing to find an object.
+  // consider tree, where element A on bus BUS_A has child B on bus BUS_B. when going "next" from
+  // element A algorithm has to descend into BUS_B and search element B and its children. this is done
+  // by returning to our caller object B with special flag set (meaning - continue the search from B on bus BUS_B).
+  // if next object will be found there (on BUS_B), then search ends. but if not, then our caller will find it out
+  // and will call us again with object A and flag search_mode set to NEIGHBOR_SEARCH_MODE_CONTINUE_AFTER_FAILED_RECURSING.
+  // this flag means, that object A was already checked previously and we should skip it and its children.
+  bool force_next = ( search_mode == BridgeAccessible::GetNeighborSearchMode::continueAfterFailedRecursion );
+
+  CycleDetection< Accessible* > cycleDetection( node );
+  while( node )
+  {
+    if( node->GetStates()[State::Defunct] )
+      return nullptr;
+
+    // always accept proxy object from different world
+    if( !force_next && node->IsProxy() )
+      return node;
+
+    auto children = node->GetChildren();
+    children = ValidChildrenGet( children, start, root );
+
+    // do accept:
+    // 1. not start node
+    // 2. parent after all children in backward traversing
+    // 3. Nodes with roles: ATSPI_ROLE_PAGE_TAB, ATSPI_ROLE_POPUP_MENU and ATSPI_ROLE_DIALOG, only when looking for first or last element.
+    //    Objects with those roles shouldnt be reachable, when navigating next / prev.
+    bool all_children_visited_or_moving_forward = ( children.size() == 0 || forward || all_children_visited );
+    if( !force_next && node != start && all_children_visited_or_moving_forward && AcceptObject( node ) )
+    {
+      if( start == NULL || ObjectRoleIsAcceptableWhenNavigatingNextPrev( node ) )
+        return node;
+    }
+
+    Accessible* next_related_in_direction = !force_next ? GetObjectInRelationFlow( node, forward ? RelationType::FlowsTo : RelationType::FlowsFrom ) : nullptr;
+    /* force_next means that the search_mode is NEIGHBOR_SEARCH_MODE_CONTINUE_AFTER_FAILED_RECURSING
+      in this case the node is elm_layout which is parent of proxy object.
+      There is an access object working for the proxy object, and the access
+      object could have relation information. This relation information should
+      be checked first before using the elm_layout as a node. */
+    if( force_next && forward )
+    {
+      auto deputy = DeputyOfProxyInParentGet( node );
+      next_related_in_direction =
+          GetObjectInRelationFlow( deputy, forward ? RelationType::FlowsTo : RelationType::FlowsFrom );
+    }
+
+    if( next_related_in_direction && start->GetStates()[State::Defunct] )
+      next_related_in_direction = NULL;
+    unsigned char want_cycle_detection = 0;
+    if( next_related_in_direction )
+    {
+      /* Check next_related_in_direction is deputy object */
+      Accessible* parent;
+      if( !forward )
+      {
+        /* If the prev object is deputy, then go to inside of its proxy first */
+        if( DeputyIs( next_related_in_direction ) )
+        {
+          parent = next_related_in_direction->GetParent();
+          next_related_in_direction = ProxyInParentGet( parent );
+        }
+      }
+      else
+      {
+        /* If current object is deputy, and it has relation next object,
+                   then do not use the relation next object, and use proxy first */
+        if( DeputyIs( node ) )
+        {
+          parent = node->GetParent();
+          next_related_in_direction = ProxyInParentGet( parent );
+        }
+      }
+      node = next_related_in_direction;
+      want_cycle_detection = 1;
+    }
+    else
+    {
+      auto child = !force_next && !all_children_visited ? DirectionalDepthFirstSearchTryNonDefunctChild( node, children, forward ) : nullptr;
+      if( child )
+      {
+        want_cycle_detection = 1;
+      }
+      else
+      {
+        if( !force_next && node == root )
+          return NULL;
+        all_children_visited = true;
+        child = DirectionalDepthFirstSearchTryNonDefunctSibling( all_children_visited, node, start, root, forward );
+      }
+      node = child;
+    }
+    force_next = 0;
+    if( want_cycle_detection && cycleDetection.check( node ) )
+    {
+      return NULL;
+    }
+  }
+  return NULL;
+}
+
+DBus::ValueOrError< Accessible*, uint8_t > BridgeAccessible::GetNeighbor( std::string rootPath, int32_t direction, int32_t search_mode )
+{
+  auto start = FindSelf();
+  rootPath = StripPrefix( rootPath );
+  auto root = !rootPath.empty() ? Find( rootPath ) : nullptr;
+  auto accessible = CalculateNeighbor( root, start, direction == 1, static_cast< GetNeighborSearchMode >( search_mode ) );
+  unsigned char recurse = 0;
+  if( accessible )
+  {
+    recurse = accessible->IsProxy();
+  }
+  return {accessible, recurse};
+}
+
+Accessible* BridgeAccessible::GetParent()
+{
+  // NOTE: currently bridge supports single application root element.
+  // only element set as application root might return nullptr from GetParent
+  // if you want more, then you need to change setApplicationRoot to
+  // add/remove ApplicationRoot and make roots a vector.
+  auto z = FindSelf();
+  auto p = z->GetParent();
+  assert( p );
+  return p;
+}
+DBus::ValueOrError< std::vector< Accessible* > > BridgeAccessible::GetChildren()
+{
+  return FindSelf()->GetChildren();
+}
+std::string BridgeAccessible::GetDescription()
+{
+  return FindSelf()->GetDescription();
+}
+DBus::ValueOrError< uint32_t > BridgeAccessible::GetRole()
+{
+  return static_cast< unsigned int >( FindSelf()->GetRole() );
+}
+DBus::ValueOrError< std::string > BridgeAccessible::GetRoleName()
+{
+  return FindSelf()->GetRoleName();
+}
+DBus::ValueOrError< std::string > BridgeAccessible::GetLocalizedRoleName()
+{
+  return FindSelf()->GetLocalizedRoleName();
+}
+DBus::ValueOrError< int32_t > BridgeAccessible::GetIndexInParent()
+{
+  return FindSelf()->GetIndexInParent();
+}
+DBus::ValueOrError< std::array< uint32_t, 2 > > BridgeAccessible::GetStates()
+{
+  return FindSelf()->GetStates().GetRawData();
+}
+DBus::ValueOrError< std::unordered_map< std::string, std::string > > BridgeAccessible::GetAttributes()
+{
+  return FindSelf()->GetAttributes();
+}
+DBus::ValueOrError< std::vector< std::string > > BridgeAccessible::GetInterfaces()
+{
+  return FindSelf()->GetInterfaces();
+}
+int BridgeAccessible::GetChildCount()
+{
+  return FindSelf()->GetChildCount();
+}
+DBus::ValueOrError< Accessible* > BridgeAccessible::GetChildAtIndex( int index )
+{
+  if( index < 0 )
+    throw AccessibleError{"negative index (" + std::to_string( index ) + ")"};
+  return FindSelf()->GetChildAtIndex( static_cast< size_t >( index ) );
+}
+
+std::string BridgeAccessible::GetName()
+{
+  return FindSelf()->GetName();
+}
+
+DBus::ValueOrError< Accessible*, uint32_t > BridgeAccessible::GetDefaultLabelInfo()
+{
+  auto p = FindSelf();
+  return {p, static_cast< uint32_t >( p->GetRole() )};
+}
diff --git a/dali/dali-bridge/src/BridgeAccessible.hpp b/dali/dali-bridge/src/BridgeAccessible.hpp
new file mode 100644 (file)
index 0000000..fcc4217
--- /dev/null
@@ -0,0 +1,80 @@
+#ifndef BRIDGE_ACCESSIBLE_HPP
+#define BRIDGE_ACCESSIBLE_HPP
+
+#include "BridgeBase.hpp"
+#include <array>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+class BridgeAccessible : public virtual BridgeBase
+{
+protected:
+  BridgeAccessible();
+
+  void RegisterInterfaces();
+
+public:
+  enum class GetNeighborSearchMode
+  {
+    normal = 0,
+    recurseFromRoot = 1,
+    continueAfterFailedRecursion = 2,
+    recurseToOutside = 3,
+  };
+  int GetChildCount();
+  DBus::ValueOrError< Dali::Accessibility::Accessible* > GetChildAtIndex( int index );
+  Dali::Accessibility::Accessible* GetParent();
+  DBus::ValueOrError< std::vector< Dali::Accessibility::Accessible* > > GetChildren();
+  std::string GetName();
+  std::string GetDescription();
+  DBus::ValueOrError< uint32_t > GetRole();
+  DBus::ValueOrError< std::string > GetRoleName();
+  DBus::ValueOrError< std::string > GetLocalizedRoleName();
+  DBus::ValueOrError< int32_t > GetIndexInParent();
+  DBus::ValueOrError< std::array< uint32_t, 2 > > GetStates();
+  DBus::ValueOrError< std::unordered_map< std::string, std::string > > GetAttributes();
+  DBus::ValueOrError< std::vector< std::string > > GetInterfaces();
+  DBus::ValueOrError< Dali::Accessibility::Accessible*, uint8_t, Dali::Accessibility::Accessible* > GetNavigableAtPoint( int32_t x, int32_t y, uint32_t coordType );
+  DBus::ValueOrError< Dali::Accessibility::Accessible*, uint8_t > GetNeighbor( std::string root_path, int32_t direction, int32_t search_mode );
+  DBus::ValueOrError< Dali::Accessibility::Accessible*, uint32_t > GetDefaultLabelInfo();
+  using ReadingMaterialType = DBus::ValueOrError<
+      std::unordered_map< std::string, std::string >, // attributes
+      std::string,                                    // name
+      std::string,                                    // labeledByName
+      std::string,                                    // textIfceName
+      uint32_t,
+      Dali::Accessibility::States,
+      std::string,                      // localized name
+      int32_t,                          // child count
+      double,                           // current value
+      double,                           // minimum increment
+      double,                           // maximum value
+      double,                           // minimum value
+      std::string,                      // description
+      int32_t,                          // index in parent
+      bool,                             // isSelectedInParent
+      bool,                             // hasCheckBoxChild
+      int32_t,                          // listChildrenCount
+      int32_t,                          // firstSelectedChildIndex
+      Dali::Accessibility::Accessible*, // parent
+      Dali::Accessibility::States,      // parentStateSet
+      int32_t,                          // parentChildCount
+      uint32_t,                         // parentRole
+      int32_t,                          // selectedChildCount,
+      Dali::Accessibility::Accessible*  // describedByObject
+      >;
+
+  ReadingMaterialType GetReadingMaterial();
+
+  DBus::ValueOrError< bool > DoGesture( int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, uint32_t );
+
+private:
+  Dali::Accessibility::Accessible* CalculateNeighbor( Dali::Accessibility::Accessible* root, Dali::Accessibility::Accessible* start, unsigned char forward, GetNeighborSearchMode search_mode );
+  std::vector< Dali::Accessibility::Accessible* > ValidChildrenGet( const std::vector< Dali::Accessibility::Accessible* >& children, Dali::Accessibility::Accessible* start, Dali::Accessibility::Accessible* root );
+  Dali::Accessibility::Accessible* GetCurrentlyHighlighted();
+  Dali::Accessibility::Accessible* DirectionalDepthFirstSearchTryNonDefunctSibling( bool& all_children_visited, Dali::Accessibility::Accessible* node, Dali::Accessibility::Accessible* start, Dali::Accessibility::Accessible* root, unsigned char forward );
+  Dali::Accessibility::Accessible* GetNextNonDefunctSibling( Dali::Accessibility::Accessible* obj, Dali::Accessibility::Accessible* start, Dali::Accessibility::Accessible* root, unsigned char forward );
+};
+
+#endif
diff --git a/dali/dali-bridge/src/BridgeAction.cpp b/dali/dali-bridge/src/BridgeAction.cpp
new file mode 100755 (executable)
index 0000000..664a665
--- /dev/null
@@ -0,0 +1,80 @@
+#include "BridgeAction.hpp"
+#include <iostream>
+
+using namespace Dali::Accessibility;
+
+void BridgeAction::RegisterInterfaces()
+{
+  DBus::DBusInterfaceDescription desc{ATSPI_DBUS_INTERFACE_ACTION};
+
+  AddGetPropertyToInterface( desc, "NActions", &BridgeAction::GetActionCount );
+
+  AddFunctionToInterface( desc, "GetName", &BridgeAction::GetActionName );
+  AddFunctionToInterface( desc, "GetLocalizedName", &BridgeAction::GetLocalizedActionName );
+  AddFunctionToInterface( desc, "GetDescription", &BridgeAction::GetActionDescription );
+  AddFunctionToInterface( desc, "GetKeyBinding", &BridgeAction::GetActionKeyBinding );
+  AddFunctionToInterface( desc, "DoAction", &BridgeAction::DoAction );
+  AddFunctionToInterface( desc, "DoActionName", &BridgeAction::DoActionName );
+  dbusServer.addInterface( "/", desc, true );
+}
+
+Action* BridgeAction::FindSelf() const
+{
+  auto s = BridgeBase::FindSelf();
+  assert( s );
+  auto s2 = dynamic_cast< Action* >( s );
+  if( !s2 )
+    throw AccessibleError{"object " + s->GetAddress().ToString() + " doesn't have Action interface"};
+  return s2;
+}
+
+DBus::ValueOrError< std::string > BridgeAction::GetActionName( int32_t index )
+{
+  auto self = FindSelf();
+  return self->GetActionName( index );
+}
+
+DBus::ValueOrError< std::string > BridgeAction::GetLocalizedActionName( int32_t index )
+{
+  auto self = FindSelf();
+  return self->GetLocalizedActionName( index );
+}
+
+DBus::ValueOrError< std::string > BridgeAction::GetActionDescription( int32_t index )
+{
+  auto self = FindSelf();
+  return self->GetActionDescription( index );
+}
+
+DBus::ValueOrError< std::string > BridgeAction::GetActionKeyBinding( int32_t index )
+{
+  auto self = FindSelf();
+  return self->GetActionKeyBinding( index );
+}
+
+DBus::ValueOrError< int32_t > BridgeAction::GetActionCount()
+{
+  auto self = FindSelf();
+  return self->GetActionCount();
+  ;
+}
+
+DBus::ValueOrError< bool > BridgeAction::DoAction( int32_t index )
+{
+  auto self = FindSelf();
+  return self->DoAction( index );
+}
+
+DBus::ValueOrError< bool > BridgeAction::DoActionName( std::string name )
+{
+  auto self = FindSelf();
+  auto cnt = self->GetActionCount();
+  for( auto i = 0u; i < cnt; ++i )
+  {
+    if( self->GetActionName( i ) == name )
+    {
+      return self->DoAction( i );
+    }
+  }
+  throw AccessibleError{"object " + self->GetAddress().ToString() + " doesn't have action '" + name + "'"};
+}
diff --git a/dali/dali-bridge/src/BridgeAction.hpp b/dali/dali-bridge/src/BridgeAction.hpp
new file mode 100644 (file)
index 0000000..5ff10e8
--- /dev/null
@@ -0,0 +1,28 @@
+#ifndef BRIDGE_ACTION_HPP
+#define BRIDGE_ACTION_HPP
+
+#include "BridgeBase.hpp"
+
+#include <tuple>
+#include <vector>
+
+class BridgeAction : public virtual BridgeBase
+{
+protected:
+  BridgeAction() = default;
+
+  void RegisterInterfaces();
+
+  Dali::Accessibility::Action* FindSelf() const;
+
+public:
+  DBus::ValueOrError< std::string > GetActionName( int32_t index );
+  DBus::ValueOrError< std::string > GetLocalizedActionName( int32_t index );
+  DBus::ValueOrError< std::string > GetActionDescription( int32_t index );
+  DBus::ValueOrError< std::string > GetActionKeyBinding( int32_t index );
+  DBus::ValueOrError< int32_t > GetActionCount();
+  DBus::ValueOrError< bool > DoAction( int32_t index );
+  DBus::ValueOrError< bool > DoActionName( std::string name );
+};
+
+#endif
diff --git a/dali/dali-bridge/src/BridgeBase.cpp b/dali/dali-bridge/src/BridgeBase.cpp
new file mode 100755 (executable)
index 0000000..d607c01
--- /dev/null
@@ -0,0 +1,165 @@
+#include "BridgeBase.hpp"
+#include <atomic>
+#include <cstdlib>
+
+using namespace Dali::Accessibility;
+
+BridgeBase::BridgeBase()
+{
+}
+
+BridgeBase::ForceUpResult BridgeBase::ForceUp()
+{
+  if( Bridge::ForceUp() == ForceUpResult::alreadyUp )
+    return ForceUpResult::alreadyUp;
+  auto proxy = DBus::DBusClient{dbusLocators::atspi::BUS, dbusLocators::atspi::OBJ_PATH,
+                                dbusLocators::atspi::BUS_INTERFACE, DBus::ConnectionType::SESSION};
+  auto addr = proxy.method< std::string() >( dbusLocators::atspi::GET_ADDRESS ).call();
+
+  if( !addr )
+    throw AccessibleError{std::string( "failed at call '" ) + dbusLocators::atspi::GET_ADDRESS +
+                          "': " + addr.getError().message};
+
+  con = std::make_shared< DBus::EldbusConnection >( eldbus_address_connection_get( std::get< 0 >( addr ).c_str() ) );
+  data->busName = DBus::getConnectionName( con );
+  data->root = &application;
+  dbusServer = {con};
+
+  {
+    DBus::DBusInterfaceDescription desc{"org.a11y.atspi.Cache"};
+    AddFunctionToInterface( desc, "GetItems", &BridgeBase::GetItems );
+    dbusServer.addInterface( "/org/a11y/atspi/cache", desc );
+  }
+  {
+    DBus::DBusInterfaceDescription desc{"org.a11y.atspi.Application"};
+    AddGetSetPropertyToInterface( desc, "Id", &BridgeBase::IdGet, &BridgeBase::IdSet );
+    dbusServer.addInterface( ATSPI_PATH, desc );
+  }
+  return ForceUpResult::justStarted;
+}
+
+void BridgeBase::ForceDown()
+{
+  Bridge::ForceDown();
+  dbusServer = {};
+  con = {};
+}
+
+const std::string& BridgeBase::GetBusName() const
+{
+  static std::string empty;
+  return data ? data->busName : empty;
+}
+
+Accessible* BridgeBase::FindByPath( const std::string& name ) const
+{
+  try
+  {
+    return Find( name );
+  }
+  catch( AccessibleError )
+  {
+    return nullptr;
+  }
+}
+
+void BridgeBase::SetApplicationChild( Accessible* root )
+{
+  // for now you can set root only once.
+  // to set it multiple times you'd have to remove old one first, which usually involves
+  // a lot of messy events and cornercases (imagine old root becoming child of new-not-yet-announced one)
+  application.children.push_back( root );
+  SetIsOnRootLevel( root );
+}
+
+// Accessible *BridgeBase::getApplicationRoot() const
+// {
+//     return rootElement;
+// }
+
+std::string BridgeBase::StripPrefix( const std::string& path )
+{
+  auto size = strlen( ATSPI_PATH );
+  return path.substr( size + 1 );
+}
+
+Accessible* BridgeBase::Find( const std::string& path ) const
+{
+  if( path == "root" )
+    return &application;
+  char* p;
+  auto val = std::strtoll( path.c_str(), &p, 10 );
+  if( p == path.c_str() )
+    throw AccessibleError{"invalid path '" + path + "'"};
+  auto it = data->objects.find( val );
+  if( it == data->objects.end() )
+    throw AccessibleError{"unknown object '" + path + "'"};
+  return it->second;
+}
+
+Accessible* BridgeBase::Find( const Address& ptr ) const
+{
+  assert( ptr.GetBus() == data->busName );
+  return Find( ptr.GetPath() );
+}
+
+Accessible* BridgeBase::FindSelf() const
+{
+  auto pth = DBus::DBusServer::getCurrentObjectPath();
+  auto size = strlen( ATSPI_PATH );
+  if( pth.size() <= size )
+    throw AccessibleError{"invalid path '" + pth + "'"};
+  if( pth.substr( 0, size ) != ATSPI_PATH )
+    throw AccessibleError{"invalid path '" + pth + "'"};
+  if( pth[size] != '/' )
+    throw AccessibleError{"invalid path '" + pth + "'"};
+  return Find( StripPrefix( pth ) );
+}
+
+void BridgeBase::IdSet( int id )
+{
+  this->id = id;
+}
+int BridgeBase::IdGet()
+{
+  return this->id;
+}
+
+auto BridgeBase::GetItems() -> DBus::ValueOrError< std::vector< CacheElementType > >
+{
+  auto root = &application;
+
+  std::vector< CacheElementType > res;
+
+  res.emplace_back( std::move( CreateCacheElement( root ) ) );
+  for( auto const& it : data->objects )
+    res.emplace_back( std::move( CreateCacheElement( it.second ) ) );
+
+  return res;
+}
+
+auto BridgeBase::CreateCacheElement( Accessible* item ) -> CacheElementType
+{
+  if( !item )
+    return {};
+
+  auto root = &application;
+  auto parent = item->GetParent();
+
+  std::vector< Address > children;
+  for( auto i = 0u; i < item->GetChildCount(); ++i )
+  {
+    children.emplace_back( item->GetChildAtIndex( i )->GetAddress() );
+  }
+
+  return std::make_tuple(
+      item->GetAddress(),
+      root->GetAddress(),
+      parent->GetAddress(),
+      children,
+      item->GetInterfaces(),
+      item->GetName(),
+      item->GetRole(),
+      item->GetDescription(),
+      item->GetStates().GetRawData() );
+}
diff --git a/dali/dali-bridge/src/BridgeBase.hpp b/dali/dali-bridge/src/BridgeBase.hpp
new file mode 100644 (file)
index 0000000..10a16a1
--- /dev/null
@@ -0,0 +1,215 @@
+#ifndef BRIDGE_HPP
+#define BRIDGE_HPP
+
+#include "Common.hpp"
+#include <memory>
+
+class AppAccessible : public virtual Dali::Accessibility::Accessible, public virtual Dali::Accessibility::Collection
+{
+public:
+  Dali::Accessibility::EmptyAccessibleWithAddress parent;
+  std::vector< Dali::Accessibility::Accessible* > children;
+  std::string name;
+
+  std::string GetName() override
+  {
+    return name;
+  }
+  std::string GetDescription() override
+  {
+    return "";
+  }
+  Dali::Accessibility::Accessible* GetParent() override
+  {
+    return &parent;
+  }
+  size_t GetChildCount() override
+  {
+    return children.size();
+  }
+  Dali::Accessibility::Accessible* GetChildAtIndex( size_t index ) override
+  {
+    auto s = children.size();
+    if( index >= s )
+      throw Dali::Accessibility::AccessibleError{"invalid index " + std::to_string( index ) + " for object with " + std::to_string( s ) + " children"};
+    return children[index];
+  }
+  size_t GetIndexInParent() override
+  {
+    throw Dali::Accessibility::AccessibleError{"can't call GetIndexInParent on application object"};
+  }
+  Dali::Accessibility::Role GetRole() override
+  {
+    return Dali::Accessibility::Role::Application;
+  }
+  Dali::Accessibility::States GetStates() override
+  {
+    return {};
+  }
+  Dali::Accessibility::Attributes GetAttributes() override
+  {
+    return {};
+  }
+  Dali::Accessibility::Accessible* getActiveWindow()
+  {
+    return children.empty() ? nullptr : children[0];
+  }
+};
+
+class BridgeBase : public Dali::Accessibility::Bridge
+{
+public:
+  const std::string& GetBusName() const override;
+  void SetApplicationChild( Dali::Accessibility::Accessible* root ) override;
+  Dali::Accessibility::Accessible* GetApplication() const override
+  {
+    return &application;
+  }
+
+  template < typename SELF, typename... RET, typename... ARGS >
+  void AddFunctionToInterface(
+      DBus::DBusInterfaceDescription& desc, const std::string& funcName,
+      DBus::ValueOrError< RET... > ( SELF::*funcPtr )( ARGS... ) )
+  {
+    desc.addMethod< DBus::ValueOrError< RET... >( ARGS... ) >( funcName,
+                                                               [=]( ARGS... args ) -> DBus::ValueOrError< RET... > {
+                                                                 try
+                                                                 {
+                                                                   return ( dynamic_cast< SELF* >( this )->*funcPtr )( std::move( args )... );
+                                                                 }
+                                                                 catch( Dali::Accessibility::AccessibleError& e )
+                                                                 {
+                                                                   return DBus::Error{e.what()};
+                                                                 }
+                                                               } );
+  }
+  template < typename T, typename SELF >
+  void AddGetPropertyToInterface( DBus::DBusInterfaceDescription& desc,
+                                  const std::string& funcName, T ( SELF::*funcPtr )() )
+  {
+    desc.addProperty< T >( funcName,
+                           [=]() -> DBus::ValueOrError< T > {
+                             try
+                             {
+                               return ( dynamic_cast< SELF* >( this )->*funcPtr )();
+                             }
+                             catch( Dali::Accessibility::AccessibleError& e )
+                             {
+                               return DBus::Error{e.what()};
+                             }
+                           },
+                           {} );
+  }
+  template < typename T, typename SELF >
+  void AddSetPropertyToInterface( DBus::DBusInterfaceDescription& desc,
+                                  const std::string& funcName, void ( SELF::*funcPtr )( T ) )
+  {
+    desc.addProperty< T >( funcName, {},
+                           [=]( T t ) -> DBus::ValueOrError< void > {
+                             try
+                             {
+                               ( dynamic_cast< SELF* >( this )->*funcPtr )( std::move( t ) );
+                               return {};
+                             }
+                             catch( Dali::Accessibility::AccessibleError& e )
+                             {
+                               return DBus::Error{e.what()};
+                             }
+                           } );
+  }
+  template < typename T, typename T1, typename SELF >
+  void AddGetSetPropertyToInterface( DBus::DBusInterfaceDescription& desc,
+                                     const std::string& funcName, T1 ( SELF::*funcPtrGet )(), DBus::ValueOrError< void > ( SELF::*funcPtrSet )( T ) )
+  {
+    desc.addProperty< T >( funcName,
+                           [=]() -> DBus::ValueOrError< T > {
+                             try
+                             {
+                               return ( dynamic_cast< SELF* >( this )->*funcPtrGet )();
+                             }
+                             catch( Dali::Accessibility::AccessibleError& e )
+                             {
+                               return DBus::Error{e.what()};
+                             }
+                           },
+                           [=]( T t ) -> DBus::ValueOrError< void > {
+                             try
+                             {
+                               ( dynamic_cast< SELF* >( this )->*funcPtrSet )( std::move( t ) );
+                               return {};
+                             }
+                             catch( Dali::Accessibility::AccessibleError& e )
+                             {
+                               return DBus::Error{e.what()};
+                             }
+                           } );
+  }
+  template < typename T, typename T1, typename SELF >
+  void AddGetSetPropertyToInterface( DBus::DBusInterfaceDescription& desc,
+                                     const std::string& funcName, T1 ( SELF::*funcPtrGet )(), void ( SELF::*funcPtrSet )( T ) )
+  {
+    desc.addProperty< T >( funcName,
+                           [=]() -> DBus::ValueOrError< T > {
+                             try
+                             {
+                               return ( dynamic_cast< SELF* >( this )->*funcPtrGet )();
+                             }
+                             catch( Dali::Accessibility::AccessibleError& e )
+                             {
+                               return DBus::Error{e.what()};
+                             }
+                           },
+                           [=]( T t ) -> DBus::ValueOrError< void > {
+                             try
+                             {
+                               ( dynamic_cast< SELF* >( this )->*funcPtrSet )( std::move( t ) );
+                               return {};
+                             }
+                             catch( Dali::Accessibility::AccessibleError& e )
+                             {
+                               return DBus::Error{e.what()};
+                             }
+                           } );
+  }
+  static std::string StripPrefix( const std::string& path );
+
+  Dali::Accessibility::Accessible* Find( const std::string& path ) const;
+  Dali::Accessibility::Accessible* Find( const Dali::Accessibility::Address& ptr ) const;
+  Dali::Accessibility::Accessible* FindSelf() const;
+  Dali::Accessibility::Accessible* FindByPath( const std::string& name ) const override;
+  void SetApplicationName( std::string name ) override
+  {
+    application.name = std::move( name );
+  }
+
+protected:
+  mutable AppAccessible application;
+
+private:
+  void IdSet( int id );
+  int IdGet();
+
+  using CacheElementType = std::tuple<
+      Dali::Accessibility::Address, Dali::Accessibility::Address, Dali::Accessibility::Address,
+      std::vector< Dali::Accessibility::Address >,
+      std::vector< std::string >,
+      std::string,
+      Dali::Accessibility::Role,
+      std::string,
+      std::array< uint32_t, 2 > >;
+  DBus::ValueOrError< std::vector< CacheElementType > > GetItems();
+  CacheElementType CreateCacheElement( Dali::Accessibility::Accessible* item );
+
+protected:
+  BridgeBase();
+  virtual ~BridgeBase() = default;
+
+  ForceUpResult ForceUp() override;
+  void ForceDown() override;
+
+  DBus::DBusServer dbusServer;
+  std::shared_ptr< DBus::EldbusConnection > con;
+  int id = 0;
+};
+
+#endif
diff --git a/dali/dali-bridge/src/BridgeCollection.cpp b/dali/dali-bridge/src/BridgeCollection.cpp
new file mode 100644 (file)
index 0000000..22fcddc
--- /dev/null
@@ -0,0 +1,366 @@
+#include "BridgeCollection.hpp"
+#include <algorithm>
+#include <iostream>
+#include <unordered_set>
+#include <vector>
+
+using namespace Dali::Accessibility;
+
+void BridgeCollection::RegisterInterfaces()
+{
+  DBus::DBusInterfaceDescription desc{ATSPI_DBUS_INTERFACE_COLLECTION};
+  AddFunctionToInterface( desc, "GetMatches", &BridgeCollection::GetMatches );
+  dbusServer.addInterface( "/", desc, true );
+}
+
+Collection* BridgeCollection::FindSelf() const
+{
+  auto s = BridgeBase::FindSelf();
+  assert( s );
+  auto s2 = dynamic_cast< Collection* >( s );
+  if( !s2 )
+    throw AccessibleError{"object " + s->GetAddress().ToString() + " doesn't have Collection interface"};
+  return s2;
+}
+
+enum
+{
+  ATSPI_Collection_MATCH_INVALID,
+  ATSPI_Collection_MATCH_ALL,
+  ATSPI_Collection_MATCH_ANY,
+  ATSPI_Collection_MATCH_NONE,
+  ATSPI_Collection_MATCH_EMPTY,
+  ATSPI_Collection_MATCH_LAST_DEFINED,
+};
+
+struct BridgeCollection::Comparer
+{
+  using Mode = MatchType;
+
+  enum class CompareFuncExit
+  {
+    firstFound,
+    firstNotFound
+  };
+
+  static Mode ConvertToMatchType( int32_t mode )
+  {
+    switch( mode )
+    {
+      case ATSPI_Collection_MATCH_INVALID:
+      {
+        return Mode::Invalid;
+      }
+      case ATSPI_Collection_MATCH_ALL:
+      {
+        return Mode::All;
+      }
+      case ATSPI_Collection_MATCH_ANY:
+      {
+        return Mode::Any;
+      }
+      case ATSPI_Collection_MATCH_NONE:
+      {
+        return Mode::None;
+      }
+      case ATSPI_Collection_MATCH_EMPTY:
+      {
+        return Mode::Empty;
+      }
+    }
+    return Mode::Invalid;
+  }
+
+  struct ComparerInterfaces
+  {
+    std::unordered_set< std::string > object;
+    std::vector< std::string > requested;
+    Mode mode = Mode::Invalid;
+
+    ComparerInterfaces( MatchRule* rule ) : mode( ConvertToMatchType( std::get< Index::InterfacesMatchType >( *rule ) ) )
+    {
+      requested = {std::get< Index::Interfaces >( *rule ).begin(), std::get< Index::Interfaces >( *rule ).end()};
+    }
+    void Update( Accessible* obj )
+    {
+      object.clear();
+      for( auto& q : obj->GetInterfaces() )
+        object.insert( std::move( q ) );
+    }
+    bool RequestEmpty() const { return requested.empty(); }
+    bool ObjectEmpty() const { return object.empty(); }
+    bool Compare( CompareFuncExit exit )
+    {
+      bool foundAny = false;
+      for( auto& iname : requested )
+      {
+        bool found = ( object.find( iname ) != object.end() );
+        if( found )
+          foundAny = true;
+        if( found == ( exit == CompareFuncExit::firstFound ) )
+          return found;
+      }
+      return foundAny;
+    }
+  };
+  struct ComparerAttributes
+  {
+    std::unordered_map< std::string, std::string > requested, object;
+    Mode mode = Mode::Invalid;
+
+    ComparerAttributes( MatchRule* rule ) : mode( ConvertToMatchType( std::get< Index::AttributesMatchType >( *rule ) ) )
+    {
+      requested = std::get< Index::Attributes >( *rule );
+    }
+    void Update( Accessible* obj )
+    {
+      object = obj->GetAttributes();
+    }
+    bool RequestEmpty() const { return requested.empty(); }
+    bool ObjectEmpty() const { return object.empty(); }
+    bool Compare( CompareFuncExit exit )
+    {
+      bool foundAny = false;
+      for( auto& iname : requested )
+      {
+        auto it = object.find( iname.first );
+        bool found = it != object.end() && iname.second == it->second;
+        if( found )
+          foundAny = true;
+        if( found == ( exit == CompareFuncExit::firstFound ) )
+        {
+          return found;
+        }
+      }
+      return foundAny;
+    }
+  };
+  struct ComparerRoles
+  {
+    using Roles = BitStates< 4, Role >;
+    Roles requested, object;
+    Mode mode = Mode::Invalid;
+
+    ComparerRoles( MatchRule* rule ) : mode( ConvertToMatchType( std::get< Index::RolesMatchType >( *rule ) ) )
+    {
+      requested = Roles{std::get< Index::Roles >( *rule )};
+    }
+    void Update( Accessible* obj )
+    {
+      object = {};
+      object[obj->GetRole()] = true;
+      assert( object );
+    }
+    bool RequestEmpty() const { return !requested; }
+    bool ObjectEmpty() const { return !object; }
+    bool Compare( CompareFuncExit exit )
+    {
+      switch( mode )
+      {
+        case Mode::Invalid:
+        {
+          return true;
+        }
+        case Mode::Empty:
+        case Mode::All:
+        {
+          return requested == ( object & requested );
+        }
+        case Mode::Any:
+        {
+          return bool( object & requested );
+        }
+        case Mode::None:
+        {
+          return bool( object & requested );
+        }
+      }
+      return false;
+    }
+  };
+  struct ComparerStates
+  {
+    States requested, object;
+    Mode mode = Mode::Invalid;
+
+    ComparerStates( MatchRule* rule ) : mode( ConvertToMatchType( std::get< Index::StatesMatchType >( *rule ) ) )
+    {
+      requested = States{std::get< Index::States >( *rule )};
+    }
+    void Update( Accessible* obj )
+    {
+      object = obj->GetStates();
+    }
+    bool RequestEmpty() const { return !requested; }
+    bool ObjectEmpty() const { return !object; }
+    bool Compare( CompareFuncExit exit )
+    {
+      switch( mode )
+      {
+        case Mode::Invalid:
+        {
+          return true;
+        }
+        case Mode::Empty:
+        case Mode::All:
+        {
+          return requested == ( object & requested );
+        }
+        case Mode::Any:
+        {
+          return bool( object & requested );
+        }
+        case Mode::None:
+        {
+          return bool( object & requested );
+        }
+      }
+      return false;
+    }
+  };
+
+  template < typename T >
+  bool compareFunc( T& cmp, Accessible* obj )
+  {
+    if( cmp.mode == Mode::Invalid )
+      return true;
+    cmp.Update( obj );
+    switch( cmp.mode )
+    {
+      case Mode::Any:
+      {
+        if( cmp.RequestEmpty() || cmp.ObjectEmpty() )
+          return false;
+        break;
+      }
+      case Mode::All:
+      {
+        if( cmp.RequestEmpty() )
+          return true;
+        if( cmp.ObjectEmpty() )
+          return false;
+        break;
+      }
+      case Mode::None:
+      {
+        if( cmp.RequestEmpty() || cmp.ObjectEmpty() )
+          return true;
+        break;
+      }
+      case Mode::Empty:
+      {
+        if( cmp.RequestEmpty() && cmp.ObjectEmpty() )
+          return true;
+        if( cmp.RequestEmpty() || cmp.ObjectEmpty() )
+          return false;
+        break;
+      }
+      case Mode::Invalid:
+      {
+        return true;
+      }
+    }
+
+    switch( cmp.mode )
+    {
+      case Mode::Empty:
+      case Mode::All:
+      {
+        if( !cmp.Compare( CompareFuncExit::firstNotFound ) )
+          return false;
+        break;
+      }
+      case Mode::Any:
+      {
+        if( cmp.Compare( CompareFuncExit::firstFound ) )
+          return true;
+        break;
+      }
+      case Mode::None:
+      {
+        if( cmp.Compare( CompareFuncExit::firstFound ) )
+          return false;
+        break;
+      }
+      case Mode::Invalid:
+      {
+        return true;
+      }
+    }
+    switch( cmp.mode )
+    {
+      case Mode::Empty:
+      case Mode::All:
+      case Mode::None:
+      {
+        return true;
+      }
+      case Mode::Any:
+      {
+        return false;
+      }
+      case Mode::Invalid:
+      {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  ComparerInterfaces ci;
+  ComparerAttributes ca;
+  ComparerRoles cr;
+  ComparerStates cs;
+
+  Comparer( MatchRule* mr ) : ci( mr ), ca( mr ), cr( mr ), cs( mr ) {}
+
+  bool operator()( Accessible* obj )
+  {
+    return compareFunc( ci, obj ) &&
+           compareFunc( ca, obj ) &&
+           compareFunc( cr, obj ) &&
+           compareFunc( cs, obj );
+  }
+};
+
+void BridgeCollection::VisitNodes( Accessible* obj, std::vector< Accessible* >& result, Comparer& cmp, size_t maxCount )
+{
+  if( result.size() >= maxCount )
+    return;
+
+  if( cmp( obj ) )
+    result.emplace_back( obj );
+
+  for( auto i = 0u; i < obj->GetChildCount(); ++i )
+    VisitNodes( obj->GetChildAtIndex( i ), result, cmp, maxCount );
+}
+
+DBus::ValueOrError< std::vector< Accessible* > > BridgeCollection::GetMatches( MatchRule rule, uint32_t sortBy, int32_t count, bool traverse )
+{
+  std::vector< Accessible* > res;
+  auto self = BridgeBase::FindSelf();
+  auto matcher = Comparer{&rule};
+  VisitNodes( self, res, matcher, count );
+
+  switch( static_cast< SortOrder >( sortBy ) )
+  {
+    case SortOrder::Canonical:
+    {
+      break;
+    }
+
+    case SortOrder::ReverseCanonical:
+    {
+      std::reverse( res.begin(), res.end() );
+      break;
+    }
+
+    default:
+    {
+      throw AccessibleError{"unsupported sorting order"};
+    }
+      //TODO: other cases
+  }
+
+  return res;
+}
diff --git a/dali/dali-bridge/src/BridgeCollection.hpp b/dali/dali-bridge/src/BridgeCollection.hpp
new file mode 100644 (file)
index 0000000..ba92f30
--- /dev/null
@@ -0,0 +1,49 @@
+#ifndef BRIDGE_COLLECTION_HPP
+#define BRIDGE_COLLECTION_HPP
+
+#include "BridgeBase.hpp"
+
+#include <array>
+#include <tuple>
+#include <unordered_map>
+#include <vector>
+
+class BridgeCollection : public virtual BridgeBase
+{
+private:
+  struct Comparer;
+  static void VisitNodes( Dali::Accessibility::Accessible* obj, std::vector< Dali::Accessibility::Accessible* >& result, Comparer& cmp, size_t maxCount );
+
+protected:
+  BridgeCollection() = default;
+
+  void RegisterInterfaces();
+
+  Dali::Accessibility::Collection* FindSelf() const;
+
+public:
+  using MatchRule = std::tuple<
+      std::array< int32_t, 2 >, int32_t,
+      std::unordered_map< std::string, std::string >, int32_t,
+      std::array< int32_t, 4 >, int32_t,
+      std::vector< std::string >, int32_t,
+      bool >;
+  struct Index
+  {
+    enum
+    {
+      States,
+      StatesMatchType,
+      Attributes,
+      AttributesMatchType,
+      Roles,
+      RolesMatchType,
+      Interfaces,
+      InterfacesMatchType,
+    };
+  };
+
+  DBus::ValueOrError< std::vector< Dali::Accessibility::Accessible* > > GetMatches( MatchRule rule, uint32_t sortBy, int32_t count, bool traverse );
+};
+
+#endif
diff --git a/dali/dali-bridge/src/BridgeComponent.cpp b/dali/dali-bridge/src/BridgeComponent.cpp
new file mode 100644 (file)
index 0000000..6bbfaff
--- /dev/null
@@ -0,0 +1,75 @@
+#include "BridgeComponent.hpp"
+#include <iostream>
+
+#define DBUS_INTERFACE_PROPERTIES "org.freedesktop.DBus.Properties"
+
+using namespace Dali::Accessibility;
+
+BridgeComponent::BridgeComponent()
+{
+}
+
+void BridgeComponent::RegisterInterfaces()
+{
+  DBus::DBusInterfaceDescription desc{ATSPI_DBUS_INTERFACE_COMPONENT};
+  AddFunctionToInterface( desc, "Contains", &BridgeComponent::Contains );
+  AddFunctionToInterface( desc, "GetAccessibleAtPoint", &BridgeComponent::GetAccessibleAtPoint );
+  AddFunctionToInterface( desc, "GetExtents", &BridgeComponent::GetExtents );
+  AddFunctionToInterface( desc, "GetPosition", &BridgeComponent::GetPosition );
+  AddFunctionToInterface( desc, "GetSize", &BridgeComponent::GetSize );
+  AddFunctionToInterface( desc, "GetLayer", &BridgeComponent::GetLayer );
+  AddFunctionToInterface( desc, "GetAlpha", &BridgeComponent::GetAlpha );
+  AddFunctionToInterface( desc, "GrabHighlight", &BridgeComponent::GrabHighlight );
+  AddFunctionToInterface( desc, "ClearHighlight", &BridgeComponent::ClearHighlight );
+  dbusServer.addInterface( "/", desc, true );
+}
+
+Component* BridgeComponent::FindSelf() const
+{
+  auto s = BridgeBase::FindSelf();
+  assert( s );
+  auto s2 = dynamic_cast< Component* >( s );
+  if( !s2 )
+    throw AccessibleError{"object " + s->GetAddress().ToString() + " doesn't have Component interface"};
+  return s2;
+}
+
+DBus::ValueOrError< bool > BridgeComponent::Contains( int32_t x, int32_t y, uint32_t coordType )
+{
+  return FindSelf()->Contains( {x, y}, static_cast< CoordType >( coordType ) );
+}
+DBus::ValueOrError< Accessible* > BridgeComponent::GetAccessibleAtPoint( int32_t x, int32_t y, uint32_t coordType )
+{
+  return FindSelf()->GetAccessibleAtPoint( {x, y}, static_cast< CoordType >( coordType ) );
+}
+DBus::ValueOrError< std::tuple< int32_t, int32_t, int32_t, int32_t > > BridgeComponent::GetExtents( uint32_t coordType )
+{
+  auto p = FindSelf()->GetExtents( static_cast< CoordType >( coordType ) );
+  return std::tuple< int32_t, int32_t, int32_t, int32_t >{p.position.x, p.position.y, p.size.width, p.size.height};
+}
+DBus::ValueOrError< int32_t, int32_t > BridgeComponent::GetPosition( uint32_t coordType )
+{
+  auto p = FindSelf()->GetExtents( static_cast< CoordType >( coordType ) );
+  return {p.position.x, p.position.y};
+}
+DBus::ValueOrError< int32_t, int32_t > BridgeComponent::GetSize( uint32_t coordType )
+{
+  auto p = FindSelf()->GetExtents( static_cast< CoordType >( coordType ) );
+  return {p.size.width, p.size.height};
+}
+DBus::ValueOrError< ComponentLayer > BridgeComponent::GetLayer()
+{
+  return FindSelf()->GetLayer();
+}
+DBus::ValueOrError< double > BridgeComponent::GetAlpha()
+{
+  return FindSelf()->GetAlpha();
+}
+DBus::ValueOrError< bool > BridgeComponent::GrabHighlight()
+{
+  return FindSelf()->GrabHighlight();
+}
+DBus::ValueOrError< bool > BridgeComponent::ClearHighlight()
+{
+  return FindSelf()->ClearHighlight();
+}
diff --git a/dali/dali-bridge/src/BridgeComponent.hpp b/dali/dali-bridge/src/BridgeComponent.hpp
new file mode 100644 (file)
index 0000000..8a2a5d4
--- /dev/null
@@ -0,0 +1,32 @@
+#ifndef BRIDGE_COMPONENT_HPP
+#define BRIDGE_COMPONENT_HPP
+
+#include "BridgeBase.hpp"
+#include <array>
+#include <string>
+#include <tuple>
+#include <unordered_map>
+#include <vector>
+
+class BridgeComponent : public virtual BridgeBase
+{
+protected:
+  BridgeComponent();
+
+  void RegisterInterfaces();
+
+  Dali::Accessibility::Component* FindSelf() const;
+
+public:
+  DBus::ValueOrError< bool > Contains( int32_t x, int32_t y, uint32_t coordType );
+  DBus::ValueOrError< Dali::Accessibility::Accessible* > GetAccessibleAtPoint( int32_t x, int32_t y, uint32_t coordType );
+  DBus::ValueOrError< std::tuple< int32_t, int32_t, int32_t, int32_t > > GetExtents( uint32_t coordType );
+  DBus::ValueOrError< int32_t, int32_t > GetPosition( uint32_t coordType );
+  DBus::ValueOrError< int32_t, int32_t > GetSize( uint32_t coordType );
+  DBus::ValueOrError< Dali::Accessibility::ComponentLayer > GetLayer();
+  DBus::ValueOrError< double > GetAlpha();
+  DBus::ValueOrError< bool > GrabHighlight();
+  DBus::ValueOrError< bool > ClearHighlight();
+};
+
+#endif
diff --git a/dali/dali-bridge/src/BridgeEditableText.cpp b/dali/dali-bridge/src/BridgeEditableText.cpp
new file mode 100644 (file)
index 0000000..4c3e5e9
--- /dev/null
@@ -0,0 +1,45 @@
+#include "BridgeEditableText.hpp"
+
+#include <dali/internal/clipboard/common/clipboard-impl.h>
+#include <dali/internal/input/common/imf-manager-impl.h>
+
+using namespace Dali::Accessibility;
+
+void BridgeEditableText::RegisterInterfaces()
+{
+  DBus::DBusInterfaceDescription desc{ATSPI_DBUS_INTERFACE_EDITABLE_TEXT};
+  AddFunctionToInterface( desc, "CopyText", &BridgeEditableText::CopyText );
+  AddFunctionToInterface( desc, "CutText", &BridgeEditableText::CutText );
+  AddFunctionToInterface( desc, "PasteText", &BridgeEditableText::PasteText );
+  dbusServer.addInterface( "/", desc, true );
+}
+
+EditableText* BridgeEditableText::FindSelf() const
+{
+  auto s = BridgeBase::FindSelf();
+  assert( s );
+  auto s2 = dynamic_cast< EditableText* >( s );
+  if( !s2 )
+    throw AccessibleError{"object " + s->GetAddress().ToString() + " doesn't have Text interface"};
+  return s2;
+}
+
+DBus::ValueOrError< bool > BridgeEditableText::CopyText( int32_t startPos, int32_t endPos )
+{
+  return FindSelf()->CopyText( startPos, endPos );
+}
+
+DBus::ValueOrError< bool > BridgeEditableText::CutText( int32_t startPos, int32_t endPos )
+{
+  return FindSelf()->CutText( startPos, endPos );
+}
+
+DBus::ValueOrError< bool > BridgeEditableText::PasteText( int32_t pos )
+{
+  auto imfManager = Dali::Internal::Adaptor::ImfManager::Get();
+  imfManager.SetCursorPosition( pos );
+  auto clipboard = Dali::Internal::Adaptor::Clipboard::Get();
+  clipboard.RequestItem();
+
+  return true;
+}
diff --git a/dali/dali-bridge/src/BridgeEditableText.hpp b/dali/dali-bridge/src/BridgeEditableText.hpp
new file mode 100644 (file)
index 0000000..37008a4
--- /dev/null
@@ -0,0 +1,21 @@
+#ifndef BRIDGE_EDITABLE_TEXT_HPP
+#define BRIDGE_EDITABLE_TEXT_HPP
+
+#include "BridgeBase.hpp"
+
+class BridgeEditableText : public virtual BridgeBase
+{
+protected:
+  BridgeEditableText() = default;
+
+  void RegisterInterfaces();
+
+  Dali::Accessibility::EditableText* FindSelf() const;
+
+public:
+  DBus::ValueOrError< bool > CopyText( int32_t startPos, int32_t endPos );
+  DBus::ValueOrError< bool > CutText( int32_t startPos, int32_t endPos );
+  DBus::ValueOrError< bool > PasteText( int32_t pos );
+};
+
+#endif
diff --git a/dali/dali-bridge/src/BridgeImpl.cpp b/dali/dali-bridge/src/BridgeImpl.cpp
new file mode 100644 (file)
index 0000000..6ad9a1b
--- /dev/null
@@ -0,0 +1,160 @@
+#include "BridgeImpl.hpp"
+#include "BridgeAccessible.hpp"
+#include "BridgeAction.hpp"
+#include "BridgeCollection.hpp"
+#include "BridgeComponent.hpp"
+#include "BridgeObject.hpp"
+#include "BridgeValue.hpp"
+#include "DBus.hpp"
+#include <iostream>
+
+#include <dali/integration-api/debug.h>
+
+using namespace Dali::Accessibility;
+
+class BridgeImpl : public virtual BridgeBase, public BridgeAccessible, public BridgeObject, public BridgeComponent, public BridgeCollection, public BridgeAction, public BridgeValue
+{
+  DBus::DBusClient listenOnAtspiEnabledSignalClient;
+  DBus::DBusClient registryClient;
+  Accessible* currentWindow = nullptr;
+  bool screenReaderEnabled = false, isEnabled = false;
+
+public:
+  BridgeImpl()
+  {
+    DBus::setDebugPrinter( []( const char* buf, size_t len ) {
+      std::string s{buf, len};
+      Dali::Integration::Log::LogMessage( Dali::Integration::Log::DebugInfo, "%s", s.c_str() );
+    } );
+  }
+
+  Consumed Emit( KeyEventType type, unsigned int keyCode, const std::string& keyName, unsigned int timeStamp, bool isText ) override
+  {
+    unsigned int evType = 0;
+
+    switch( type )
+    {
+      case KeyEventType::KeyPressed:
+        evType = 0;
+        {
+          break;
+        }
+      case KeyEventType::KeyReleased:
+        evType = 1;
+        {
+          break;
+        }
+      default:
+      {
+        return Consumed::No;
+      }
+    }
+    auto m = registryClient.method< bool( std::tuple< uint32_t, int32_t, int32_t, int32_t, int32_t, std::string, bool > ) >( "NotifyListenersSync" );
+    auto result = m.call( std::tuple< uint32_t, int32_t, int32_t, int32_t, int32_t, std::string, bool >{evType, 0, static_cast< int32_t >( keyCode ), 0, static_cast< int32_t >( timeStamp ), keyName, isText ? 1 : 0} );
+    if( !result )
+    {
+      LOG() << result.getError().message;
+      return Consumed::No;
+    }
+    return std::get< 0 >( result ) ? Consumed::Yes : Consumed::No;
+  }
+
+  void ForceDown() override
+  {
+    ApplicationHidden();
+    BridgeAccessible::ForceDown();
+    registryClient = {};
+  }
+
+  ForceUpResult ForceUp() override
+  {
+    if( BridgeAccessible::ForceUp() == ForceUpResult::alreadyUp )
+      return ForceUpResult::alreadyUp;
+
+    BridgeObject::RegisterInterfaces();
+    BridgeAccessible::RegisterInterfaces();
+    BridgeComponent::RegisterInterfaces();
+    BridgeCollection::RegisterInterfaces();
+    BridgeAction::RegisterInterfaces();
+    BridgeValue::RegisterInterfaces();
+
+    RegisterOnBridge( &application );
+
+    registryClient = {ATSPI_DBUS_NAME_REGISTRY, ATSPI_DBUS_PATH_DEC, ATSPI_DBUS_INTERFACE_DEC, con};
+    auto proxy = DBus::DBusClient{ATSPI_DBUS_NAME_REGISTRY, ATSPI_DBUS_PATH_ROOT, ATSPI_DBUS_INTERFACE_SOCKET, con};
+    Address root{
+        data->busName, "root"};
+    auto res = proxy.method< Address( Address ) >( "Embed" ).call( root );
+    assert( res );
+    application.parent.SetAddress( std::move( std::get< 0 >( res ) ) );
+    ApplicationShown();
+    return ForceUpResult::justStarted;
+  }
+
+  void ApplicationHidden() override
+  {
+    if( currentWindow )
+    {
+      currentWindow->Emit( WindowEvent::Deactivate, 0 );
+      currentWindow = nullptr;
+    }
+  }
+  void ApplicationShown() override
+  {
+    auto win = application.getActiveWindow();
+    if( win && win != currentWindow )
+    {
+      currentWindow = win;
+      win->Emit( WindowEvent::Activate, 0 );
+    }
+  }
+  void Initialize() override
+  {
+    auto req = DBus::DBusClient{A11Y_DBUS_NAME, A11Y_DBUS_PATH, A11Y_DBUS_STATUS_INTERFACE, DBus::ConnectionType::SESSION};
+    auto p = req.property< bool >( "ScreenReaderEnabled" ).get();
+    if( p )
+      screenReaderEnabled = std::get< 0 >( p );
+    p = req.property< bool >( "IsEnabled" ).get();
+    if( p )
+      isEnabled = std::get< 0 >( p );
+    if( screenReaderEnabled || isEnabled )
+      ForceUp();
+  }
+  static std::shared_ptr< Bridge > Create()
+  {
+    auto ptr = std::make_shared< BridgeImpl >();
+    ptr->MakePublic( Bridge::Visibility::allThreads );
+    ptr->listenOnAtspiEnabledSignalClient = DBus::DBusClient{A11Y_DBUS_NAME, A11Y_DBUS_PATH, A11Y_DBUS_STATUS_INTERFACE,
+                                                             DBus::ConnectionType::SESSION};
+    {
+      auto p = ptr.get();
+      ptr->listenOnAtspiEnabledSignalClient.addPropertyChangedEvent< bool >( "ScreenReaderEnabled", [p]( bool res ) {
+        p->screenReaderEnabled = res;
+        if( p->screenReaderEnabled || p->isEnabled )
+          p->ForceUp();
+        else
+          p->ForceDown();
+      } );
+      ptr->listenOnAtspiEnabledSignalClient.addPropertyChangedEvent< bool >( "IsEnabled", [p]( bool res ) {
+        p->isEnabled = res;
+        if( p->screenReaderEnabled || p->isEnabled )
+          p->ForceUp();
+        else
+          p->ForceDown();
+      } );
+    }
+    return ptr;
+  }
+};
+
+std::shared_ptr< Bridge > Dali::Accessibility::CreateBridge()
+{
+  try
+  {
+    return BridgeImpl::Create();
+  }
+  catch( AccessibleError& e )
+  {
+    return {};
+  }
+}
diff --git a/dali/dali-bridge/src/BridgeImpl.hpp b/dali/dali-bridge/src/BridgeImpl.hpp
new file mode 100644 (file)
index 0000000..e068478
--- /dev/null
@@ -0,0 +1,4 @@
+#ifndef BRIDGE_IMPL_HPP
+#define BRIDGE_IMPL_HPP
+
+#endif
diff --git a/dali/dali-bridge/src/BridgeObject.cpp b/dali/dali-bridge/src/BridgeObject.cpp
new file mode 100644 (file)
index 0000000..f28dcbe
--- /dev/null
@@ -0,0 +1,401 @@
+#include "BridgeObject.hpp"
+#include <iostream>
+#include <string>
+
+using namespace Dali::Accessibility;
+
+BridgeObject::BridgeObject()
+{
+}
+
+void BridgeObject::RegisterInterfaces()
+{
+  // DBus::DBusInterfaceDescription desc{ ATSPI_DBUS_INTERFACE_EVENT_OBJECT };
+  // stateChanged = addSignal<std::string, int, int, DBus::EldbusVariant<int>, Accessible*>(desc, "StateChanged");
+  // dbusServer.addInterface("/", desc, true);
+}
+
+void BridgeObject::Emit( Accessible* obj, WindowEvent we, unsigned int detail1 )
+{
+  const char* name = nullptr;
+  switch( we )
+  {
+    case WindowEvent::PropertyChange:
+    {
+      name = "PropertyChange";
+      break;
+    }
+    case WindowEvent::Minimize:
+    {
+      name = "Minimize";
+      break;
+    }
+    case WindowEvent::Maximize:
+    {
+      name = "Maximize";
+      break;
+    }
+    case WindowEvent::Restore:
+    {
+      name = "Restore";
+      break;
+    }
+    case WindowEvent::Close:
+    {
+      name = "Close";
+      break;
+    }
+    case WindowEvent::Create:
+    {
+      name = "Create";
+      break;
+    }
+    case WindowEvent::Reparent:
+    {
+      name = "Reparent";
+      break;
+    }
+    case WindowEvent::DesktopCreate:
+    {
+      name = "DesktopCreate";
+      break;
+    }
+    case WindowEvent::DesktopDestroy:
+    {
+      name = "DesktopDestroy";
+      break;
+    }
+    case WindowEvent::Destroy:
+    {
+      name = "Destroy";
+      break;
+    }
+    case WindowEvent::Activate:
+    {
+      name = "Activate";
+      break;
+    }
+    case WindowEvent::Deactivate:
+    {
+      name = "Deactivate";
+      break;
+    }
+    case WindowEvent::Raise:
+    {
+      name = "Raise";
+      break;
+    }
+    case WindowEvent::Lower:
+    {
+      name = "Lower";
+      break;
+    }
+    case WindowEvent::Move:
+    {
+      name = "Move";
+      break;
+    }
+    case WindowEvent::Resize:
+    {
+      name = "Resize";
+      break;
+    }
+    case WindowEvent::Shade:
+    {
+      name = "Shade";
+      break;
+    }
+    case WindowEvent::UuShade:
+    {
+      name = "uUshade";
+      break;
+    }
+    case WindowEvent::Restyle:
+    {
+      name = "Restyle";
+      break;
+    }
+  }
+  if( name )
+  {
+    auto addr = obj->GetAddress();
+    const auto prefixPath = "/org/a11y/atspi/accessible/";
+    const auto nullPath = "/org/a11y/atspi/null";
+    std::string p;
+    if( addr )
+      p = prefixPath + addr.GetPath();
+    else
+      p = nullPath;
+    dbusServer.emit2< std::string, int, int, DBus::EldbusVariant< int >, Address >(
+        p,
+        ATSPI_DBUS_INTERFACE_EVENT_WINDOW,
+        name,
+        "",
+        detail1,
+        0,
+        {0},
+        {GetBusName(), "root"} );
+  }
+}
+
+void BridgeObject::EmitStateChanged( Accessible* obj, State state, int newValue1, int newValue2 )
+{
+  const char* stateName = nullptr;
+  switch( state )
+  {
+    case State::Invalid:
+    {
+      stateName = "invalid";
+      break;
+    }
+    case State::Active:
+    {
+      stateName = "active";
+      break;
+    }
+    case State::Armed:
+    {
+      stateName = "armed";
+      break;
+    }
+    case State::Busy:
+    {
+      stateName = "busy";
+      break;
+    }
+    case State::Checked:
+    {
+      stateName = "checked";
+      break;
+    }
+    case State::Collapsed:
+    {
+      stateName = "collapsed";
+      break;
+    }
+    case State::Defunct:
+    {
+      stateName = "defunct";
+      break;
+    }
+    case State::Editable:
+    {
+      stateName = "editable";
+      break;
+    }
+    case State::Enabled:
+    {
+      stateName = "enabled";
+      break;
+    }
+    case State::Expandable:
+    {
+      stateName = "expandable";
+      break;
+    }
+    case State::Expanded:
+    {
+      stateName = "expanded";
+      break;
+    }
+    case State::Focusable:
+    {
+      stateName = "focusable";
+      break;
+    }
+    case State::Focused:
+    {
+      stateName = "focused";
+      break;
+    }
+    case State::HasTooltip:
+    {
+      stateName = "has-tooltip";
+      break;
+    }
+    case State::Horizontal:
+    {
+      stateName = "horizontal";
+      break;
+    }
+    case State::Iconified:
+    {
+      stateName = "iconified";
+      break;
+    }
+    case State::Modal:
+    {
+      stateName = "modal";
+      break;
+    }
+    case State::MultiLine:
+    {
+      stateName = "multi-line";
+      break;
+    }
+    case State::MultiSelectable:
+    {
+      stateName = "multiselectable";
+      break;
+    }
+    case State::Opaque:
+    {
+      stateName = "opaque";
+      break;
+    }
+    case State::Pressed:
+    {
+      stateName = "pressed";
+      break;
+    }
+    case State::Resizeable:
+    {
+      stateName = "resizable";
+      break;
+    }
+    case State::Selectable:
+    {
+      stateName = "selectable";
+      break;
+    }
+    case State::Selected:
+    {
+      stateName = "selected";
+      break;
+    }
+    case State::Sensitive:
+    {
+      stateName = "sensitive";
+      break;
+    }
+    case State::Showing:
+    {
+      stateName = "showing";
+      break;
+    }
+    case State::SingleLine:
+    {
+      stateName = "single-line";
+      break;
+    }
+    case State::Stale:
+    {
+      stateName = "stale";
+      break;
+    }
+    case State::Transient:
+    {
+      stateName = "transient";
+      break;
+    }
+    case State::Vertical:
+    {
+      stateName = "vertical";
+      break;
+    }
+    case State::Visible:
+    {
+      stateName = "visible";
+      break;
+    }
+    case State::ManagesDescendants:
+    {
+      stateName = "manages-descendants";
+      break;
+    }
+    case State::Indeterminate:
+    {
+      stateName = "indeterminate";
+      break;
+    }
+    case State::Required:
+    {
+      stateName = "required";
+      break;
+    }
+    case State::Truncated:
+    {
+      stateName = "truncated";
+      break;
+    }
+    case State::Animated:
+    {
+      stateName = "animated";
+      break;
+    }
+    case State::InvalidEntry:
+    {
+      stateName = "invalid-entry";
+      break;
+    }
+    case State::SupportsAutocompletion:
+    {
+      stateName = "supports-autocompletion";
+      break;
+    }
+    case State::SelectableText:
+    {
+      stateName = "selectable-text";
+      break;
+    }
+    case State::IsDefault:
+    {
+      stateName = "is-default";
+      break;
+    }
+    case State::Visited:
+    {
+      stateName = "visited";
+      break;
+    }
+    case State::Checkable:
+    {
+      stateName = "checkable";
+      break;
+    }
+    case State::HasPopup:
+    {
+      stateName = "has-popup";
+      break;
+    }
+    case State::ReadOnly:
+    {
+      stateName = "read-only";
+      break;
+    }
+    case State::Highlighted:
+    {
+      stateName = "highlighted";
+      break;
+    }
+    case State::Highlightable:
+    {
+      stateName = "highlightable";
+      break;
+    }
+    case State::_Count:
+    {
+      break;
+    }
+  }
+  if( stateName )
+  {
+    auto addr = obj->GetAddress();
+    const auto prefixPath = "/org/a11y/atspi/accessible/";
+    const auto nullPath = "/org/a11y/atspi/null";
+    std::string p;
+    if( addr )
+      p = prefixPath + addr.GetPath();
+    else
+      p = nullPath;
+    dbusServer.emit2< std::string, int, int, DBus::EldbusVariant< int >, Address >(
+        p,
+        ATSPI_DBUS_INTERFACE_EVENT_OBJECT,
+        "StateChanged",
+        stateName,
+        newValue1,
+        newValue2,
+        {0},
+        {GetBusName(), "root"} );
+  }
+}
diff --git a/dali/dali-bridge/src/BridgeObject.hpp b/dali/dali-bridge/src/BridgeObject.hpp
new file mode 100644 (file)
index 0000000..af496d1
--- /dev/null
@@ -0,0 +1,38 @@
+#ifndef BRIDGE_OBJECT_HPP
+#define BRIDGE_OBJECT_HPP
+
+#include "BridgeBase.hpp"
+#include <array>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+class BridgeObject : public virtual BridgeBase
+{
+protected:
+  BridgeObject();
+
+  void RegisterInterfaces();
+
+  DBus::DBusInterfaceDescription::SignalId stateChanged;
+
+  void EmitStateChanged( Dali::Accessibility::Accessible* obj, Dali::Accessibility::State state, int val1, int val2 ) override;
+  void Emit( Dali::Accessibility::Accessible* obj, Dali::Accessibility::WindowEvent we, unsigned int detail1 ) override;
+
+public:
+  int GetChildCount();
+  DBus::ValueOrError< Dali::Accessibility::Accessible* > GetChildAtIndex( int index );
+  Dali::Accessibility::Accessible* GetParent();
+  DBus::ValueOrError< std::vector< Dali::Accessibility::Accessible* > > GetChildren();
+  std::string GetName();
+  std::string GetDescription();
+  DBus::ValueOrError< uint32_t > GetRole();
+  DBus::ValueOrError< std::string > GetRoleName();
+  DBus::ValueOrError< std::string > GetLocalizedRoleName();
+  DBus::ValueOrError< int32_t > GetIndexInParent();
+  DBus::ValueOrError< std::array< uint32_t, 2 > > GetStates();
+  DBus::ValueOrError< std::unordered_map< std::string, std::string > > GetAttributes();
+  DBus::ValueOrError< std::vector< std::string > > GetInterfaces();
+};
+
+#endif
\ No newline at end of file
diff --git a/dali/dali-bridge/src/BridgeText.cpp b/dali/dali-bridge/src/BridgeText.cpp
new file mode 100644 (file)
index 0000000..651b981
--- /dev/null
@@ -0,0 +1,74 @@
+#include "BridgeText.hpp"
+
+#include <dali/internal/input/common/imf-manager-impl.h>
+
+using namespace Dali::Accessibility;
+
+void BridgeText::RegisterInterfaces()
+{
+  DBus::DBusInterfaceDescription desc{ATSPI_DBUS_INTERFACE_TEXT};
+  AddFunctionToInterface( desc, "GetText", &BridgeText::GetText );
+  AddGetPropertyToInterface( desc, "CharacterCount", &BridgeText::GetCharacterCount );
+  AddGetPropertyToInterface( desc, "CaretOffset", &BridgeText::GetCaretOffset );
+  AddFunctionToInterface( desc, "SetCaretOffset", &BridgeText::SetCaretOffset );
+  AddFunctionToInterface( desc, "GetTextAtOffset", &BridgeText::GetTextAtOffset );
+  AddFunctionToInterface( desc, "GetSelection", &BridgeText::GetSelection );
+  AddFunctionToInterface( desc, "SetSelection", &BridgeText::SetSelection );
+  AddFunctionToInterface( desc, "RemoveSelection", &BridgeText::RemoveSelection );
+  dbusServer.addInterface( "/", desc, true );
+}
+
+Text* BridgeText::FindSelf() const
+{
+  auto s = BridgeBase::FindSelf();
+  assert( s );
+  auto s2 = dynamic_cast< Text* >( s );
+  if( !s2 )
+    throw AccessibleError{"object " + s->GetAddress().ToString() + " doesn't have Text interface"};
+  return s2;
+}
+
+DBus::ValueOrError< std::string > BridgeText::GetText( int startOffset, int endOffset )
+{
+  return FindSelf()->GetText( startOffset, endOffset );
+}
+
+DBus::ValueOrError< int32_t > BridgeText::GetCharacterCount()
+{
+  return FindSelf()->GetCharacterCount();
+}
+
+DBus::ValueOrError< int32_t > BridgeText::GetCaretOffset()
+{
+  auto imfManager = Dali::Internal::Adaptor::ImfManager::Get();
+  return imfManager.GetCursorPosition();
+}
+
+DBus::ValueOrError< bool > BridgeText::SetCaretOffset( int32_t offset )
+{
+  auto imfManager = Dali::Internal::Adaptor::ImfManager::Get();
+  imfManager.SetCursorPosition( offset );
+  return true;
+}
+
+DBus::ValueOrError< std::string, int, int > BridgeText::GetTextAtOffset( int32_t offset, uint32_t boundary )
+{
+  auto r = FindSelf()->GetTextAtOffset( offset, static_cast< TextBoundary >( boundary ) );
+  return {r.content, static_cast< int >( r.startOffset ), static_cast< int >( r.endOffset )};
+}
+
+DBus::ValueOrError< int, int > BridgeText::GetSelection( int32_t selectionNum )
+{
+  auto r = FindSelf()->GetSelection( selectionNum );
+  return {static_cast< int >( r.startOffset ), static_cast< int >( r.endOffset )};
+}
+
+DBus::ValueOrError< bool > BridgeText::RemoveSelection( int32_t selectionNum )
+{
+  return FindSelf()->RemoveSelection( selectionNum );
+}
+
+DBus::ValueOrError< bool > BridgeText::SetSelection( int32_t selectionNum, int32_t startOffset, int32_t endOffset )
+{
+  return FindSelf()->SetSelection( selectionNum, startOffset, endOffset );
+}
diff --git a/dali/dali-bridge/src/BridgeText.hpp b/dali/dali-bridge/src/BridgeText.hpp
new file mode 100644 (file)
index 0000000..fdb0894
--- /dev/null
@@ -0,0 +1,26 @@
+#ifndef BRIDGE_TEXT_HPP
+#define BRIDGE_TEXT_HPP
+
+#include "BridgeBase.hpp"
+
+class BridgeText : public virtual BridgeBase
+{
+protected:
+  BridgeText() = default;
+
+  void RegisterInterfaces();
+
+  Dali::Accessibility::Text* FindSelf() const;
+
+public:
+  DBus::ValueOrError< std::string > GetText( int startOffset, int endOffset );
+  DBus::ValueOrError< int32_t > GetCharacterCount();
+  DBus::ValueOrError< int32_t > GetCaretOffset();
+  DBus::ValueOrError< bool > SetCaretOffset( int32_t offset );
+  DBus::ValueOrError< std::string, int, int > GetTextAtOffset( int32_t offset, uint32_t boundary );
+  DBus::ValueOrError< int, int > GetSelection( int32_t selectionNum );
+  DBus::ValueOrError< bool > RemoveSelection( int32_t selectionNum );
+  DBus::ValueOrError< bool > SetSelection( int32_t selectionNum, int32_t startOffset, int32_t endOffset );
+};
+
+#endif
diff --git a/dali/dali-bridge/src/BridgeValue.cpp b/dali/dali-bridge/src/BridgeValue.cpp
new file mode 100644 (file)
index 0000000..7c158b6
--- /dev/null
@@ -0,0 +1,48 @@
+#include "BridgeValue.hpp"
+#include <iostream>
+
+using namespace Dali::Accessibility;
+
+BridgeValue::BridgeValue()
+{
+}
+
+void BridgeValue::RegisterInterfaces()
+{
+  DBus::DBusInterfaceDescription desc{ATSPI_DBUS_INTERFACE_VALUE};
+  AddGetSetPropertyToInterface( desc, "CurrentValue", &BridgeValue::GetCurrentValue, &BridgeValue::SetCurrentValue );
+  AddGetPropertyToInterface( desc, "MaximumValue", &BridgeValue::GetMaximumValue );
+  AddGetPropertyToInterface( desc, "MinimumIncrement", &BridgeValue::GetMinimumIncrement );
+  AddGetPropertyToInterface( desc, "MinimumValue", &BridgeValue::GetMinimumValue );
+  dbusServer.addInterface( "/", desc, true );
+}
+
+Value* BridgeValue::FindSelf() const
+{
+  auto s = BridgeBase::FindSelf();
+  assert( s );
+  auto s2 = dynamic_cast< Value* >( s );
+  if( !s2 )
+    throw AccessibleError{"object " + s->GetAddress().ToString() + " doesn't have Value interface"};
+  return s2;
+}
+double BridgeValue::GetCurrentValue()
+{
+  return FindSelf()->GetCurrent();
+}
+void BridgeValue::SetCurrentValue( double new_value )
+{
+  FindSelf()->SetCurrent( new_value );
+}
+double BridgeValue::GetMaximumValue()
+{
+  return FindSelf()->GetMaximum();
+}
+double BridgeValue::GetMinimumIncrement()
+{
+  return FindSelf()->GetMinimumIncrement();
+}
+double BridgeValue::GetMinimumValue()
+{
+  return FindSelf()->GetMinimum();
+}
diff --git a/dali/dali-bridge/src/BridgeValue.hpp b/dali/dali-bridge/src/BridgeValue.hpp
new file mode 100644 (file)
index 0000000..beb1d86
--- /dev/null
@@ -0,0 +1,28 @@
+#ifndef BRIDGE_VALUE_HPP
+#define BRIDGE_VALUE_HPP
+
+#include "BridgeBase.hpp"
+#include <array>
+#include <string>
+#include <tuple>
+#include <unordered_map>
+#include <vector>
+
+class BridgeValue : public virtual BridgeBase
+{
+protected:
+  BridgeValue();
+
+  void RegisterInterfaces();
+
+  Dali::Accessibility::Value* FindSelf() const;
+
+public:
+  double GetCurrentValue();
+  void SetCurrentValue( double new_value );
+  double GetMaximumValue();
+  double GetMinimumIncrement();
+  double GetMinimumValue();
+};
+
+#endif
diff --git a/dali/dali-bridge/src/Common.hpp b/dali/dali-bridge/src/Common.hpp
new file mode 100755 (executable)
index 0000000..acbef6f
--- /dev/null
@@ -0,0 +1,267 @@
+#ifndef COMMON_HPP
+#define COMMON_HPP
+
+#include "DBus.hpp"
+#include "dbusLocators.hpp"
+#include <dali/devel-api/adaptor-framework/accessibility.h>
+#include <dali/integration-api/debug.h>
+#include <iomanip>
+#include <sstream>
+#include <string>
+
+#define A11Y_DBUS_NAME "org.a11y.Bus"
+#define A11Y_DBUS_PATH "/org/a11y/bus"
+#define A11Y_DBUS_STATUS_INTERFACE "org.a11y.Status"
+#define ATSPI_DBUS_NAME_REGISTRY "org.a11y.atspi.Registry"
+#define ATSPI_DBUS_PATH_ROOT "/org/a11y/atspi/accessible/root"
+#define ATSPI_DBUS_INTERFACE_SOCKET "org.a11y.atspi.Socket"
+#define ATSPI_PATH "/org/a11y/atspi/accessible"
+#define ATSPI_DBUS_INTERFACE_ACCESSIBLE "org.a11y.atspi.Accessible"
+#define ATSPI_DBUS_INTERFACE_ACTION "org.a11y.atspi.Action"
+#define ATSPI_DBUS_INTERFACE_APPLICATION "org.a11y.atspi.Application"
+#define ATSPI_DBUS_INTERFACE_COLLECTION "org.a11y.atspi.Collection"
+#define ATSPI_DBUS_INTERFACE_COMPONENT "org.a11y.atspi.Component"
+#define ATSPI_DBUS_INTERFACE_DOCUMENT "org.a11y.atspi.Document"
+#define ATSPI_DBUS_INTERFACE_EDITABLE_TEXT "org.a11y.atspi.EditableText"
+#define ATSPI_DBUS_INTERFACE_EVENT_KEYBOARD "org.a11y.atspi.Event.Keyboard"
+#define ATSPI_DBUS_INTERFACE_EVENT_MOUSE "org.a11y.atspi.Event.Mouse"
+#define ATSPI_DBUS_INTERFACE_EVENT_OBJECT "org.a11y.atspi.Event.Object"
+#define ATSPI_DBUS_INTERFACE_HYPERLINK "org.a11y.atspi.Hyperlink"
+#define ATSPI_DBUS_INTERFACE_HYPERTEXT "org.a11y.atspi.Hypertext"
+#define ATSPI_DBUS_INTERFACE_IMAGE "org.a11y.atspi.Image"
+#define ATSPI_DBUS_INTERFACE_SELECTION "org.a11y.atspi.Selection"
+#define ATSPI_DBUS_INTERFACE_TABLE "org.a11y.atspi.Table"
+#define ATSPI_DBUS_INTERFACE_TABLE_CELL "org.a11y.atspi.TableCell"
+#define ATSPI_DBUS_INTERFACE_TEXT "org.a11y.atspi.Text"
+#define ATSPI_DBUS_INTERFACE_VALUE "org.a11y.atspi.Value"
+#define ATSPI_DBUS_INTERFACE_SOCKET "org.a11y.atspi.Socket"
+#define ATSPI_DBUS_INTERFACE_EVENT_WINDOW "org.a11y.atspi.Event.Window"
+
+#define ATSPI_DBUS_PATH_DEC "/org/a11y/atspi/registry/deviceeventcontroller"
+#define ATSPI_DBUS_INTERFACE_DEC "org.a11y.atspi.DeviceEventController"
+#define ATSPI_DBUS_INTERFACE_DEVICE_EVENT_LISTENER "org.a11y.atspi.DeviceEventListener"
+
+namespace DBus
+{
+class CurrentBridgePtr
+{
+  static Dali::Accessibility::Bridge*& get()
+  {
+    static thread_local Dali::Accessibility::Bridge* b = nullptr;
+    return b;
+  }
+  Dali::Accessibility::Bridge* prev;
+  CurrentBridgePtr( const CurrentBridgePtr& ) = delete;
+  CurrentBridgePtr( CurrentBridgePtr&& ) = delete;
+  CurrentBridgePtr& operator=( const CurrentBridgePtr& ) = delete;
+  CurrentBridgePtr& operator=( CurrentBridgePtr&& ) = delete;
+
+public:
+  CurrentBridgePtr( Dali::Accessibility::Bridge* b ) : prev( get() ) { get() = b; }
+  ~CurrentBridgePtr() { get() = prev; }
+
+  static Dali::Accessibility::Bridge* current() { return get(); }
+};
+namespace detail
+{
+template < typename T >
+struct signature_accessible_impl
+{
+  using subtype = std::pair< std::string, DBus::ObjectPath >;
+
+  /**
+      * @brief Returns name of type marshalled, for informative purposes
+      */
+  static std::string name()
+  {
+    return "AtspiAccessiblePtr";
+  }
+  /**
+      * @brief Returns DBUS' signature of type marshalled
+      */
+  static std::string sig()
+  {
+    return "(so)";
+  }
+  /**
+      * @brief Marshals value v as marshalled type into message
+      */
+  static void set( Eldbus_Message_Iter* iter, T* t )
+  {
+    const auto prefixPath = "/org/a11y/atspi/accessible/";
+    const auto nullPath = "/org/a11y/atspi/null";
+
+    if( t )
+    {
+      auto v = t->GetAddress();
+      signature< subtype >::set( iter, {v.GetBus(), DBus::ObjectPath{std::string{prefixPath} + v.GetPath()}} );
+    }
+    else
+    {
+      signature< subtype >::set( iter, {"", DBus::ObjectPath{nullPath}} );
+    }
+  }
+  /**
+      * @brief Marshals value from marshalled type into variable v
+      */
+  static bool get( Eldbus_Message_Iter* iter, T*& v )
+  {
+    const auto prefixPath = "/org/a11y/atspi/accessible/";
+    const auto nullPath = "/org/a11y/atspi/null";
+    subtype tmp;
+    if( !signature< subtype >::get( iter, tmp ) )
+      return false;
+    if( tmp.second.value == nullPath )
+    {
+      v = nullptr;
+      return true;
+    }
+    if( tmp.second.value.substr( 0, strlen( prefixPath ) ) != prefixPath )
+      return false;
+    auto b = CurrentBridgePtr::current();
+    if( b->GetBusName() != tmp.first )
+      return false;
+    v = b->FindByPath( tmp.second.value.substr( strlen( prefixPath ) ) );
+    return v != nullptr;
+  }
+};
+template <>
+struct signature< Dali::Accessibility::Accessible* > : public signature_accessible_impl< Dali::Accessibility::Accessible >
+{
+};
+
+template <>
+struct signature< Dali::Accessibility::Address >
+{
+  using subtype = std::pair< std::string, DBus::ObjectPath >;
+
+  /**
+      * @brief Returns name of type marshalled, for informative purposes
+      */
+  static std::string name()
+  {
+    return "AtspiAccessiblePtr";
+  }
+  /**
+      * @brief Returns DBUS' signature of type marshalled
+      */
+  static std::string sig()
+  {
+    return "(so)";
+  }
+  /**
+      * @brief Marshals value v as marshalled type into message
+      */
+  static void set( Eldbus_Message_Iter* iter, const Dali::Accessibility::Address& v )
+  {
+    const auto prefixPath = "/org/a11y/atspi/accessible/";
+    const auto nullPath = "/org/a11y/atspi/null";
+
+    if( v )
+    {
+      signature< subtype >::set( iter, {v.GetBus(), DBus::ObjectPath{std::string{prefixPath} + v.GetPath()}} );
+    }
+    else
+    {
+      signature< subtype >::set( iter, {v.GetBus(), DBus::ObjectPath{nullPath}} );
+    }
+  }
+  /**
+      * @brief Marshals value from marshalled type into variable v
+      */
+  static bool get( Eldbus_Message_Iter* iter, Dali::Accessibility::Address& v )
+  {
+    const auto prefixPath = "/org/a11y/atspi/accessible/";
+    const auto nullPath = "/org/a11y/atspi/null";
+    subtype tmp;
+    if( !signature< subtype >::get( iter, tmp ) )
+      return false;
+    if( tmp.second.value == nullPath )
+    {
+      v = {};
+      return true;
+    }
+    if( tmp.second.value.substr( 0, strlen( prefixPath ) ) != prefixPath )
+      return false;
+    v = {std::move( tmp.first ), tmp.second.value.substr( strlen( prefixPath ) )};
+    return true;
+  }
+};
+template <>
+struct signature< Dali::Accessibility::States >
+{
+  using subtype = std::array< uint32_t, 2 >;
+
+  /**
+      * @brief Returns name of type marshalled, for informative purposes
+      */
+  static std::string name()
+  {
+    return signature< subtype >::name();
+  }
+  /**
+      * @brief Returns DBUS' signature of type marshalled
+      */
+  static std::string sig()
+  {
+    return signature< subtype >::sig();
+  }
+  /**
+      * @brief Marshals value v as marshalled type into message
+      */
+  static void set( Eldbus_Message_Iter* iter, const Dali::Accessibility::States& v )
+  {
+    signature< subtype >::set( iter, v.GetRawData() );
+  }
+  /**
+      * @brief Marshals value from marshalled type into variable v
+      */
+  static bool get( Eldbus_Message_Iter* iter, Dali::Accessibility::States& v )
+  {
+    subtype tmp;
+    if( !signature< subtype >::get( iter, tmp ) )
+      return false;
+    v = Dali::Accessibility::States{tmp};
+    return true;
+  }
+};
+}
+}
+
+struct _Logger
+{
+  const char* file;
+  int line;
+  std::ostringstream tmp;
+
+  _Logger( const char* f, int l ) : file( f ), line( l ) {}
+  ~_Logger()
+  {
+    Dali::Integration::Log::LogMessage( Dali::Integration::Log::DebugInfo, "%s:%d: %s", file, line, tmp.str().c_str() );
+  }
+  template < typename T >
+  _Logger& operator<<( T&& t )
+  {
+    tmp << std::forward< T >( t );
+    return *this;
+  }
+};
+
+struct _LoggerScope
+{
+  const char* file;
+  int line;
+
+  _LoggerScope( const char* f, int l ) : file( f ), line( l )
+  {
+    Dali::Integration::Log::LogMessage( Dali::Integration::Log::DebugInfo, "%s:%d: +", file, line );
+  }
+  ~_LoggerScope()
+  {
+    Dali::Integration::Log::LogMessage( Dali::Integration::Log::DebugInfo, "%s:%d: -", file, line );
+  }
+};
+#define LOG() _Logger( __FILE__, __LINE__ )
+#define SCOPE() _LoggerScope _l##__LINE__( __FILE__, __LINE__ )
+
+#endif
diff --git a/dali/dali-bridge/src/Component.cpp b/dali/dali-bridge/src/Component.cpp
new file mode 100644 (file)
index 0000000..8085569
--- /dev/null
@@ -0,0 +1,29 @@
+#include "Common.hpp"
+#include <iostream>
+
+using namespace Dali::Accessibility;
+
+bool Component::Contains( Point p, CoordType ctype )
+{
+  auto extents = GetExtents( ctype );
+  return p.x >= extents.position.x && p.y >= extents.position.y && p.x <= extents.position.x + extents.size.width && p.y <= extents.position.y + extents.size.height;
+}
+
+Component* Component::GetAccessibleAtPoint( Point p, CoordType ctype )
+{
+  auto children = GetChildren();
+  for( auto childIt = children.rbegin(); childIt != children.rend(); childIt++ )
+  {
+    auto component = dynamic_cast< Component* >( *childIt );
+    if( component && component->Contains( p, ctype ) )
+    {
+      return component;
+    }
+  }
+  return nullptr;
+}
+
+bool Component::IsScrollable()
+{
+  return false;
+}
diff --git a/dali/dali-bridge/src/DBus.cpp b/dali/dali-bridge/src/DBus.cpp
new file mode 100644 (file)
index 0000000..f8af9bc
--- /dev/null
@@ -0,0 +1,490 @@
+/*
+ * Copyright 2017  Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "DBus.hpp"
+#include <sstream>
+//#include "Atspi.hpp"
+#include <iostream>
+#include <mutex>
+
+#define DBUS_INTERFACE_PROPERTIES "org.freedesktop.DBus.Properties"
+
+#undef EINA_FALSE
+#undef EINA_TRUE
+#define EINA_TRUE static_cast< Eina_Bool >( 1 )
+#define EINA_FALSE static_cast< Eina_Bool >( 0 )
+
+//#define DBUS_DEBUG(...) do { DBus::debugPrint(__FILE__, __LINE__, __VA_ARGS__); } while (0)
+
+std::atomic< unsigned int > DBus::detail::CallId::LastId{0};
+static std::function< void( const char*, size_t ) > debugPrinter;
+static std::function< void( DBus::DBusAction ) > notificationCallback;
+static std::mutex debugLock, notificationLock;
+
+DBus::detail::CallOnDestructionList& DBus::detail::CallOnDestructionList::operator=( DBus::detail::CallOnDestructionList&& d )
+{
+  for( auto& q : functions )
+  {
+    q();
+  }
+  functions = std::move( d.functions );
+  d.functions.clear();
+  return *this;
+}
+
+void DBus::detail::CallOnDestructionList::add( const std::function< void() >& c )
+{
+  functions.push_back( c );
+}
+
+void DBus::setDBusActionNotifier( std::function< void( DBus::DBusAction ) > callback )
+{
+  std::lock_guard< std::mutex > lock( notificationLock );
+  notificationCallback = std::move( callback );
+}
+
+void DBus::detail::emitNotification( const char* bus, const char* path, const char* interface, const char* member, DBus::DBusActionType type )
+{
+  std::lock_guard< std::mutex > lock( notificationLock );
+  if( notificationCallback )
+  {
+    notificationCallback( DBusAction{type, bus, path, interface, member} );
+  }
+}
+
+void DBus::setDebugPrinter( std::function< void( const char*, size_t ) > printer )
+{
+  std::lock_guard< std::mutex > lock( debugLock );
+  debugPrinter = std::move( printer );
+}
+
+void DBus::debugPrint( const char* file, size_t line, const char* format, ... )
+{
+  std::function< void( const char*, size_t ) > debugPrintFunc;
+  {
+    std::lock_guard< std::mutex > lock( debugLock );
+    if( !debugPrinter )
+      return;
+    debugPrintFunc = debugPrinter;
+  }
+  std::vector< char > buf( 4096 );
+  int offset;
+  while( true )
+  {
+    offset = snprintf( buf.data(), buf.size(), "%s:%u: ", file, static_cast< unsigned int >( line ) );
+    if( offset < 0 )
+      return;
+    if( static_cast< size_t >( offset ) < buf.size() )
+      break;
+    buf.resize( offset + 1 );
+  }
+
+  while( true )
+  {
+    va_list args;
+    va_start( args, format );
+    int z = vsnprintf( buf.data() + offset, buf.size() - offset, format, args );
+    va_end( args );
+    if( z < 0 )
+      return;
+    bool done = static_cast< size_t >( z ) + static_cast< size_t >( offset ) < buf.size();
+    buf.resize( static_cast< size_t >( z ) + static_cast< size_t >( offset ) );
+    if( done )
+      break;
+  }
+  debugPrintFunc( buf.data(), buf.size() );
+}
+
+std::shared_ptr< DBus::EldbusConnection > DBus::getDBusConnectionByName( const std::string& name )
+{
+  eldbus_init();
+  auto z = getDBusConnectionByType( ConnectionType::SYSTEM );
+  auto connection = eldbus_address_connection_get( name.c_str() );
+  auto ptr = std::make_shared< EldbusConnection >( connection );
+  eldbus_shutdown();
+  return ptr;
+}
+
+std::shared_ptr< DBus::EldbusConnection > DBus::getDBusConnectionByType( ConnectionType connectionType )
+{
+  Eldbus_Connection_Type eldbusType = ELDBUS_CONNECTION_TYPE_SYSTEM;
+
+  switch( connectionType )
+  {
+    case ConnectionType::SYSTEM:
+    {
+      eldbusType = ELDBUS_CONNECTION_TYPE_SYSTEM;
+      break;
+    }
+    case ConnectionType::SESSION:
+    {
+      eldbusType = ELDBUS_CONNECTION_TYPE_SESSION;
+      break;
+    }
+  }
+
+  eldbus_init();
+  auto connection = eldbus_connection_get( eldbusType );
+  auto ptr = std::make_shared< EldbusConnection >( connection );
+  eldbus_shutdown();
+  return ptr;
+}
+
+DBus::DBusClient::DBusClient( std::string busName, std::string pathName, std::string interfaceName, ConnectionType tp ) : DBusClient( std::move( busName ), std::move( pathName ), std::move( interfaceName ), getDBusConnectionByType( tp ) )
+{
+}
+
+struct caller_eldbus_object_unref
+{
+  void operator()( Eldbus_Object* p ) const
+  {
+    eldbus_object_unref( p );
+  }
+};
+
+DBus::DBusClient::DBusClient( std::string busName, std::string pathName, std::string interfaceName, const std::shared_ptr< DBus::EldbusConnection >& conn )
+{
+  if( !conn )
+    connectionState.connection = getDBusConnectionByType( ConnectionType::SESSION );
+  else
+    connectionState.connection = conn;
+
+  std::ostringstream o;
+  o << "bus = " << busName << " path = " << pathName << " connection = " << eldbus_connection_unique_name_get( connectionState.connection->get() );
+  info = o.str();
+
+  auto c = connectionState.connection;
+  connectionState.object = {
+      eldbus_object_get( connectionState.connection->get(), busName.c_str(), pathName.c_str() ),
+      [c]( Eldbus_Object* p ) {
+        eldbus_object_unref( p );
+      }};
+  if( connectionState.object )
+  {
+    auto obj = connectionState.object;
+    connectionState.proxy = {
+        eldbus_proxy_get( connectionState.object.get(), interfaceName.c_str() ),
+        [obj]( Eldbus_Proxy* p ) {
+          eldbus_proxy_unref( p );
+        }};
+    if( interfaceName != DBUS_INTERFACE_PROPERTIES )
+    {
+      auto obj = connectionState.object;
+      connectionState.propertiesProxy = {
+          eldbus_proxy_get( connectionState.object.get(), DBUS_INTERFACE_PROPERTIES ),
+          [obj]( Eldbus_Proxy* p ) {
+            eldbus_proxy_unref( p );
+          }};
+    }
+    else
+    {
+      connectionState.propertiesProxy = connectionState.proxy;
+    }
+  }
+  connectionInfo = std::make_shared< ConnectionInfo >();
+  connectionInfo->busName = std::move( busName );
+  connectionInfo->pathName = std::move( pathName );
+  connectionInfo->interfaceName = std::move( interfaceName );
+}
+
+DBus::DBusServer::DBusServer( ConnectionType tp ) : DBus::DBusServer( DBus::getDBusConnectionByType( tp ) )
+{
+}
+
+DBus::DBusServer::DBusServer( const std::shared_ptr< DBus::EldbusConnection >& conn )
+{
+  if( !conn )
+    connection = getDBusConnectionByType( ConnectionType::SESSION );
+  else
+    connection = conn;
+}
+
+DBus::DBusInterfaceDescription::DBusInterfaceDescription( std::string interfaceName ) : interfaceName( std::move( interfaceName ) )
+{
+}
+
+struct Implementation
+{
+  Eldbus_Service_Interface_Desc dsc;
+  std::vector< Eldbus_Method > methods;
+  std::vector< Eldbus_Signal > signals;
+  std::vector< Eldbus_Property > properties;
+  DBus::detail::StringStorage strings;
+
+  std::unordered_map< std::string, DBus::DBusInterfaceDescription::MethodInfo > methodsMap;
+  std::unordered_map< std::string, DBus::DBusInterfaceDescription::PropertyInfo > propertiesMap;
+  std::unordered_map< unsigned int, DBus::DBusInterfaceDescription::SignalInfo > signalsMap;
+
+  std::shared_ptr< DBus::EldbusConnection > connection;
+};
+
+static std::unordered_map< const Eldbus_Service_Interface*, std::unique_ptr< Implementation > > globalEntries;
+static std::mutex globalEntriesMutex;
+static thread_local const char* currentObjectPath = "";
+static thread_local std::shared_ptr< DBus::EldbusConnection > currentConnection;
+
+class CurrentObjectSetter
+{
+public:
+  CurrentObjectSetter( std::shared_ptr< DBus::EldbusConnection > con, const Eldbus_Message* m )
+  {
+    currentObjectPath = eldbus_message_path_get( m );
+    currentConnection = std::move( con );
+  }
+  ~CurrentObjectSetter()
+  {
+    currentObjectPath = "";
+    currentConnection = {};
+  }
+  CurrentObjectSetter( const CurrentObjectSetter& ) = delete;
+  CurrentObjectSetter( CurrentObjectSetter&& ) = delete;
+  void operator=( const CurrentObjectSetter& ) = delete;
+  void operator=( CurrentObjectSetter&& ) = delete;
+};
+
+std::string DBus::DBusServer::getCurrentObjectPath()
+{
+  return currentObjectPath;
+}
+
+std::shared_ptr< DBus::EldbusConnection > DBus::DBusServer::getCurrentConnection()
+{
+  return currentConnection;
+}
+
+static Eina_Bool property_get_callback( const Eldbus_Service_Interface* iface, const char* propertyName, Eldbus_Message_Iter* iter,
+                                        const Eldbus_Message* message, Eldbus_Message** error )
+{
+  Implementation* impl = nullptr;
+  {
+    std::lock_guard< std::mutex > lock( globalEntriesMutex );
+    auto it = globalEntries.find( iface );
+    if( it != globalEntries.end() )
+      impl = it->second.get();
+  }
+  if( !impl )
+    return EINA_FALSE;
+
+  auto it = impl->propertiesMap.find( propertyName );
+  if( it == impl->propertiesMap.end() || !it->second.getCallback )
+    return EINA_FALSE;
+
+  CurrentObjectSetter currentObjectSetter( impl->connection, message );
+  auto reply = it->second.getCallback( message, iter );
+  if( !reply )
+  {
+    if( error )
+      *error = eldbus_message_error_new( message, "org.freedesktop.DBus.Error.Failed", reply.getError().message.c_str() );
+    return EINA_FALSE;
+  }
+
+  return EINA_TRUE;
+}
+
+static Eldbus_Message* property_set_callback( const Eldbus_Service_Interface* iface, const char* propertyName, Eldbus_Message_Iter* iter,
+                                              const Eldbus_Message* message )
+{
+  Implementation* impl = nullptr;
+  {
+    std::lock_guard< std::mutex > lock( globalEntriesMutex );
+    auto it = globalEntries.find( iface );
+    if( it != globalEntries.end() )
+      impl = it->second.get();
+  }
+  if( !impl )
+  {
+    auto ret = eldbus_message_error_new( message, "org.freedesktop.DBus.Error.Failed", "Unknown interface" );
+    return ret;
+  }
+  auto it = impl->propertiesMap.find( propertyName );
+  if( it == impl->propertiesMap.end() || !it->second.setCallback )
+  {
+    auto ret = eldbus_message_error_new( message, "org.freedesktop.DBus.Error.Failed", "Unknown setter" );
+    return ret;
+  }
+  CurrentObjectSetter currentObjectSetter( impl->connection, message );
+  auto reply = it->second.setCallback( message, iter );
+
+  Eldbus_Message* ret = nullptr;
+  if( !reply )
+  {
+    ret = eldbus_message_error_new( message, "org.freedesktop.DBus.Error.Failed", reply.getError().message.c_str() );
+  }
+  else
+  {
+    ret = eldbus_message_method_return_new( message );
+  }
+  return ret;
+}
+
+static Eldbus_Message* method_callback( const Eldbus_Service_Interface* iface, const Eldbus_Message* message )
+{
+  Implementation* impl = nullptr;
+  {
+    std::lock_guard< std::mutex > lock( globalEntriesMutex );
+    auto it = globalEntries.find( iface );
+    if( it != globalEntries.end() )
+      impl = it->second.get();
+  }
+  if( !impl )
+  {
+    auto ret = eldbus_message_error_new( message, "org.freedesktop.DBus.Error.Failed", "Unknown interface" );
+    return ret;
+  }
+  std::string memberName = eldbus_message_member_get( message );
+  auto it = impl->methodsMap.find( memberName );
+  if( it == impl->methodsMap.end() )
+  {
+    auto ret = eldbus_message_error_new( message, "org.freedesktop.DBus.Error.Failed", "Unknown method" );
+    return ret;
+  }
+  CurrentObjectSetter currentObjectSetter( impl->connection, message );
+  auto reply = it->second.callback( message );
+  return reply;
+}
+
+static void addInterfaceImpl( bool fallback, const std::string& pathName,
+                              const std::shared_ptr< DBus::EldbusConnection >& connection,
+                              const std::string& interfaceName,
+                              std::unordered_map< unsigned int, std::pair< const Eldbus_Service_Interface*, unsigned int > >& signalData,
+                              DBus::detail::StringStorage& strings,
+                              std::vector< DBus::DBusInterfaceDescription::MethodInfo >& dscrMethods,
+                              std::vector< DBus::DBusInterfaceDescription::PropertyInfo >& dscrProperties,
+                              std::vector< DBus::DBusInterfaceDescription::SignalInfo >& dscrSignals,
+                              DBus::detail::CallOnDestructionList& destructors )
+{
+  std::vector< Eldbus_Method > methods;
+  std::vector< Eldbus_Signal > signals;
+  std::vector< Eldbus_Property > properties;
+  std::unordered_map< std::string, DBus::DBusInterfaceDescription::MethodInfo > methodsMap;
+  std::unordered_map< std::string, DBus::DBusInterfaceDescription::PropertyInfo > propertiesMap;
+  std::unordered_map< unsigned int, DBus::DBusInterfaceDescription::SignalInfo > signalsMap;
+
+  DBUS_DEBUG( "interface %s path %s on bus %s", interfaceName.c_str(), pathName.c_str(), DBus::getConnectionName( connection ).c_str() );
+  for( auto& ee : dscrMethods )
+  {
+    auto key = ee.memberName;
+    DBUS_DEBUG( "adding method %s", ee.memberName.c_str() );
+    for( auto& r : ee.in )
+    {
+      if( !r.name )
+        break;
+      DBUS_DEBUG( "in %s '%s'", r.name, r.signature );
+    }
+    for( auto& r : ee.out )
+    {
+      if( !r.name )
+        break;
+      DBUS_DEBUG( "out %s '%s'", r.name, r.signature );
+    }
+    auto& e = ( methodsMap[key] = std::move( ee ) );
+    methods.push_back( {} );
+    auto& m = methods.back();
+    m.member = e.memberName.c_str();
+    m.in = e.in.data();
+    m.out = e.out.data();
+    m.cb = method_callback;
+    m.flags = 0;
+  }
+  for( auto& ee : dscrProperties )
+  {
+    auto key = ee.memberName;
+    DBUS_DEBUG( "adding property %s", ee.memberName.c_str() );
+    auto& e = ( propertiesMap[key] = std::move( ee ) );
+    properties.push_back( {} );
+    auto& m = properties.back();
+    m.name = e.memberName.c_str();
+    m.type = e.typeSignature.c_str();
+    m.get_func = e.getCallback ? property_get_callback : nullptr;
+    m.set_func = e.setCallback ? property_set_callback : nullptr;
+    m.flags = 0;
+  }
+  unsigned int signalIndex = 0;
+  std::vector< unsigned int > signalIds;
+  for( auto& ee : dscrSignals )
+  {
+    DBUS_DEBUG( "adding signal %s", ee.memberName.c_str() );
+    auto& e = ( signalsMap[ee.id.id] = std::move( ee ) );
+    signals.push_back( {} );
+    auto& m = signals.back();
+    m.name = e.memberName.c_str();
+    m.args = e.args.data();
+    m.flags = 0;
+    signalData[e.id.id].second = signalIndex++;
+    signalIds.push_back( e.id.id );
+  }
+  dscrMethods.clear();
+  dscrProperties.clear();
+  dscrSignals.clear();
+
+  methods.push_back( {nullptr, nullptr, nullptr, nullptr, 0} );
+  signals.push_back( {nullptr, nullptr, 0} );
+  properties.push_back( {nullptr, nullptr, nullptr, nullptr, 0} );
+
+  auto impl = std::unique_ptr< Implementation >( new Implementation{
+      {interfaceName.c_str(),
+       methods.data(),
+       signals.data(),
+       properties.data(),
+       nullptr,
+       nullptr},
+      std::move( methods ),
+      std::move( signals ),
+      std::move( properties ),
+      std::move( strings ),
+      std::move( methodsMap ),
+      std::move( propertiesMap ),
+      std::move( signalsMap ),
+      connection} );
+
+  {
+    std::lock_guard< std::mutex > lock( globalEntriesMutex );
+    auto v = fallback ? eldbus_service_interface_fallback_register( connection->get(), pathName.c_str(), &impl->dsc ) : eldbus_service_interface_register( connection->get(), pathName.c_str(), &impl->dsc );
+    assert( v );
+    globalEntries[v] = std::move( impl );
+    DBUS_DEBUG( "registering interface %p (%d)", v, fallback ? 1 : 0 );
+    destructors.add( [=]() {
+      eldbus_service_interface_unregister( v );
+      std::lock_guard< std::mutex > lock( globalEntriesMutex );
+      globalEntries.erase( v );
+      DBUS_DEBUG( "unregistering interface %p (%d)", v, fallback ? 1 : 0 );
+    } );
+    for( auto id : signalIds )
+    {
+      signalData[id].first = v;
+    }
+  }
+}
+
+std::shared_ptr< DBus::EldbusConnection > DBus::DBusServer::getConnection()
+{
+  return connection;
+}
+
+void DBus::DBusServer::addInterface( const std::string& pathName, DBusInterfaceDescription& dscr, bool fallback )
+{
+  addInterfaceImpl( fallback, pathName, connection, dscr.interfaceName, signalData, dscr.strings, dscr.methods, dscr.properties, dscr.signals, destructors );
+}
+
+std::string DBus::DBusServer::getBusName() const
+{
+  return getConnectionName( connection );
+}
+
+std::string DBus::getConnectionName( const std::shared_ptr< DBus::EldbusConnection >& c )
+{
+  return eldbus_connection_unique_name_get( c->get() );
+}
diff --git a/dali/dali-bridge/src/DBus.hpp b/dali/dali-bridge/src/DBus.hpp
new file mode 100755 (executable)
index 0000000..5e956df
--- /dev/null
@@ -0,0 +1,3104 @@
+/*
+ * Copyright 2017  Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef DBUS_HPP
+#define DBUS_HPP
+
+#include <Eldbus.h>
+#include <memory>
+
+#include "Optional.hpp"
+#include <array>
+#include <atomic>
+#include <cstdint>
+#include <map>
+#include <sstream>
+#include <string>
+#include <thread>
+#include <tuple>
+#include <type_traits>
+#include <unordered_map>
+#include <vector>
+
+#define DBUS_DEBUG( ... )                                \
+  do                                                     \
+  {                                                      \
+    DBus::debugPrint( __FILE__, __LINE__, __VA_ARGS__ ); \
+  } while( 0 )
+
+/**
+ * @brief Template based, single file, wrapper library around eldbus for DBUS based communication.
+ *
+ * Main motivation was missing asynchronous calls in AT-SPI library and difficulties,
+ * when using eldbus from C++.
+ *
+ * The library:
+ * - takes care of marshalling arguments to and from DBUS calls.
+ * - allows synchronous and asynchronous calls.
+ * - allows synchronous and asynchronous listeners on signals.
+ * - manages all involved objects' lifetimes.
+ * - errors are passed as optional-alike objects, no exceptions are used.
+ * - allows setting additional debug-print function for more details about
+ *   what's going on
+ *
+ * DBUS's method signatures (and expected return values) are specified as template argument,
+ * using functor syntax. For example:
+ * \code{.cpp}
+ * auto dbus = DBusClient{ ... };
+ * auto v = dbus.method<std::tuple<int, float>(float, float, std::string)>("foo").call(1.0f, 2.0f, "qwe");
+ * \endcode
+ * means (synchronous) call on dbus object, which takes three arguments (thus making call signature \b dds)
+ * of types float, float and string (float will be automatically converted to double).
+ * Expected return value is std::tuple<int, float>, which gives signature <B>(id)</B> - std::tuple acts
+ * as struct container. Returned value v will be of type ValueOrError<std::tuple<int, float>>.\n
+ * Slightly different (asynchronous) example:
+ * \code{.cpp}
+ * auto dbus = DBusClient{ ... };
+ * std::function<void(ValueOrError<int, float>)> callback;
+ * dbus.method<ValueOrError<int, float>(float, float, std::string)>("foo").asyncCall(callback, 1.0f, 2.0f, "qwe");
+ * \endcode
+ * Now the call takes the same arguments and has the same signature. But expected values are different -
+ * now the signature is simply \b id. ValueOrError acts in this case as placeholder for list of values,
+ * which DBUS allows as return data. The call itself is asynchronous - instead of expecting reply
+ * you need to pass a callback, which will be called either with received data and error message.
+ *
+ * Library is not thread-safe, the same object shouldn't be called from different threads without
+ * synchronization. There's no guarantee, that callbacks will be executed on the same thread.
+ */
+namespace DBus
+{
+/// \cond
+class DBusServer;
+class DBusClient;
+class DBusInterfaceDescription;
+
+/**
+   * @brief DBus action enumeration
+   *
+   * @param METHOD_CALL DBus is about to call a method on some external target
+   * @param SETTER_CALL DBus is about to call a setter method on some external target
+   * @param GETTER_CALL DBus is about to call a getter method on some external target
+   * @param SIGNAL_RECEIVED DBus just received a signal
+   * @param METHOD_RESPONSE DBus server received a method call
+   * @param SETTER_RESPONSE DBus server received a setter call
+   * @param GETTER_RESPONSE DBus server received a getter call
+   * @param SIGNAL_EMIT DBus server is about to emit a signal
+   */
+enum class DBusActionType
+{
+  METHOD_CALL,
+  SETTER_CALL,
+  GETTER_CALL,
+  SIGNAL_RECEIVED,
+  METHOD_RESPONSE,
+  SETTER_RESPONSE,
+  GETTER_RESPONSE,
+  SIGNAL_EMIT,
+};
+
+/**
+   * @brief Structure containing information about DBus activity, when calling notification callback
+   *
+   * @param type type of the action
+   * @param path path of the object, that's involved in action
+   * @param interface interface, on which member was acted upon. Note, that in case of getters and setters
+   *        this will be real interface, not org.freedesktop.DBus.Properties
+   * @param member member name, that was involved (either method / setter / getter / signal)
+   */
+struct DBusAction
+{
+  const DBusActionType type;
+  const char* const bus = nullptr;
+  const char* const path = nullptr;
+  const char* const interface = nullptr;
+  const char* const member = nullptr;
+
+  DBusAction( const DBusActionType type,
+              const char* const bus = nullptr,
+              const char* const path = nullptr,
+              const char* const interface = nullptr,
+              const char* const member = nullptr ) : type( type ), bus( bus ), path( path ), interface( interface ), member( member ) {}
+};
+
+/**
+   * @brief Formats debug message and calls debug printer (if any) with it
+   */
+void debugPrint( const char* file, size_t line, const char* format, ... );
+
+/**
+   * @brief Sets debug printer callback, which will be called with debug messages
+   *
+   * Callback will be called in various moments of DBus activity. First value passed to callback
+   * is pointer to text, second it's length. Text is ended with 0 (not counted towards it's size),
+   * user can safely printf it.
+   */
+void setDebugPrinter( std::function< void( const char*, size_t ) > );
+
+/**
+   * @brief Sets notification callback about processing of DBus call
+   *
+   * Notification callback can be set independently either on client or server.
+   * On client's side callback will be called, when user calls method / getter / setter
+   * or when client has received a signal.
+   * On server's side callback will be called, when sever has received a request to
+   * handle method / getter / setter or when server is going to emit a signal.
+   * Callback should returns as fast as possible.
+   * User can't call setDBusActionNotifier from inside the callback call -
+   * it will cause a deadlock
+   */
+void setDBusActionNotifier( std::function< void( DBusAction ) > callback );
+
+namespace detail
+{
+void emitNotification( const char* bus, const char* path, const char* interface, const char* member, DBusActionType type );
+}
+
+struct Error
+{
+  std::string message;
+
+  Error() = default;
+  Error( std::string msg ) : message( std::move( msg ) )
+  {
+    assert( !message.empty() );
+  }
+};
+struct Success
+{
+};
+/// \endcond
+
+/**
+   * @brief Value representing data, that came from DBUS or error message
+   *
+   * Object of this class either helds series of values (of types ARGS...)
+   * or error message. This object will be true in boolean context, if has data
+   * and false, if an error occured.
+   * It's valid to create ValueOrError object with empty argument list or void:
+   * \code{.cpp}
+   * ValueOrError<> v1;
+   * ValueOrError<void> v2;
+   * \endcode
+   * Both mean the same - ValueOrError containing no real data and being a marker,
+   * wherever operation successed or failed and containing possible error message.
+   */
+template < typename... ARGS >
+class ValueOrError
+{
+public:
+  /**
+     * @brief Empty constructor. Valid only, if all ARGS types are default constructible.
+     */
+  ValueOrError() = default;
+
+  /**
+     * @brief Value constructor.
+     *
+     * This will be initialized as success with passed in values.
+     */
+  ValueOrError( ARGS... t ) : value( std::move( t )... ) {}
+
+  /**
+     * @brief Alternative Value constructor.
+     *
+     * This will be initialized as success with passed in values.
+     */
+  ValueOrError( std::tuple< ARGS... > t ) : value( std::move( t ) ) {}
+
+  /**
+     * @brief Error constructor. This will be initialized as failure with given error message.
+     */
+  ValueOrError( Error e ) : error( std::move( e ) )
+  {
+    assert( !error.message.empty() );
+  }
+
+  /**
+     * @brief bool operator.
+     *
+     * Returns true, if operation was successful (getValues member is callable), or false
+     * when operation failed (getError is callable).
+     */
+  explicit operator bool() const
+  {
+    return error.message.empty();
+  }
+
+  /**
+     * @brief Returns error message object.
+     *
+     * Returns object containing error message associated with the failed operation.
+     * Only callable, if operation actually failed, otherwise will assert.
+     */
+  const Error& getError() const
+  {
+    return error;
+  }
+
+  /**
+     * @brief Returns modifiable tuple of held data.
+     *
+     * Returns reference to the internal tuple containing held data.
+     * User can modify (or move) data safely.
+     * Only callable, if operation actually successed, otherwise will assert.
+     */
+  std::tuple< ARGS... >& getValues()
+  {
+    assert( *this );
+    return value;
+  }
+
+  /**
+     * @brief Returns const tuple of held data.
+     *
+     * Returns const reference to the internal tuple containing held data.
+     * Only callable, if operation actually successed, otherwise will assert.
+     */
+  const std::tuple< ARGS... >& getValues() const
+  {
+    assert( *this );
+    return value;
+  }
+
+protected:
+  /// \cond
+  std::tuple< ARGS... > value;
+  Error error;
+  /// \endcond
+};
+
+/// \cond
+template <>
+class ValueOrError<>
+{
+public:
+  ValueOrError() = default;
+  ValueOrError( std::tuple<> t ) {}
+  ValueOrError( Error e ) : error( std::move( e ) )
+  {
+    assert( !error.message.empty() );
+  }
+
+  explicit operator bool() const
+  {
+    return error.message.empty();
+  }
+  const Error& getError() const
+  {
+    return error;
+  }
+  std::tuple<>& getValues()
+  {
+    assert( *this );
+    static std::tuple<> t;
+    return t;
+  }
+  std::tuple<> getValues() const
+  {
+    assert( *this );
+    return {};
+  }
+
+protected:
+  Error error;
+};
+
+template <>
+class ValueOrError< void >
+{
+public:
+  ValueOrError() = default;
+  ValueOrError( Success ) {}
+  ValueOrError( Error e ) : error( std::move( e ) )
+  {
+    assert( !error.message.empty() );
+  }
+
+  explicit operator bool() const
+  {
+    return error.message.empty();
+  }
+  const Error& getError() const
+  {
+    return error;
+  }
+  std::tuple<>& getValues()
+  {
+    assert( *this );
+    static std::tuple<> t;
+    return t;
+  }
+  std::tuple<> getValues() const
+  {
+    assert( *this );
+    return {};
+  }
+
+protected:
+  Error error;
+};
+struct ObjectPath
+{
+  std::string value;
+};
+namespace detail
+{
+class CallOnDestructionList
+{
+public:
+  CallOnDestructionList() = default;
+  CallOnDestructionList( const CallOnDestructionList& ) = delete;
+  CallOnDestructionList( CallOnDestructionList&& ) = default;
+
+  CallOnDestructionList& operator=( const CallOnDestructionList& ) = delete;
+  CallOnDestructionList& operator=( CallOnDestructionList&& );
+
+  void add( const std::function< void() >& c );
+
+private:
+  std::vector< std::function< void() > > functions;
+};
+
+struct caller_eldbus_connection_unref
+{
+  void operator()( Eldbus_Connection* p ) const
+  {
+    eldbus_connection_unref( p );
+  }
+};
+
+struct caller_eldbus_message_unref
+{
+  void operator()( Eldbus_Message* p ) const
+  {
+    eldbus_message_unref( p );
+  }
+};
+
+struct caller_eldbus_proxy_unref
+{
+  void operator()( Eldbus_Proxy* p ) const
+  {
+    eldbus_proxy_unref( p );
+  }
+};
+}
+/// \endcond
+
+/**
+   * @brief Class used to marshall DBUS's variant type
+   *
+   * Minimalistic class, that allows user to specify DBUS variant type
+   * as argument or return value. You need to pass real type hidden under variant as
+   * template type \b A. At this point library doesn't allow to expected one of few classes
+   * as return data in variant. So for example user can't specify method call, which on return
+   * expects DBUS variant holding either string or int.
+   */
+template < typename A >
+struct EldbusVariant
+{
+  A value;
+};
+
+/// \cond
+class EldbusConnection
+{
+  Eldbus_Connection* ptr = nullptr;
+
+public:
+  EldbusConnection( Eldbus_Connection* c ) : ptr( c )
+  {
+    eldbus_init();
+  }
+  EldbusConnection() = delete;
+  EldbusConnection( const EldbusConnection& ) = delete;
+  EldbusConnection( EldbusConnection&& ) = delete;
+  ~EldbusConnection()
+  {
+    eldbus_connection_unref( ptr );
+    eldbus_shutdown();
+  }
+
+  Eldbus_Connection* get() const
+  {
+    return ptr;
+  }
+};
+//using EldbusConnectionCallbackHandle = std::shared_ptr<Eldbus_Connection>;
+using EldbusMessageCallbackHandle = std::unique_ptr< Eldbus_Message, detail::caller_eldbus_message_unref >;
+using EldbusObjectCallbackHandle = std::shared_ptr< Eldbus_Object >;
+using EldbusProxyHandle = std::shared_ptr< Eldbus_Proxy >;
+/// \endcond
+
+/**
+   * @brief Namespace for private, internal functions and classes
+   *
+   */
+namespace detail
+{
+/// \cond
+template < typename T, typename = void >
+struct signature;
+template < typename... ARGS >
+struct signature< std::tuple< ARGS... > >;
+template < typename A, typename B >
+struct signature< std::pair< A, B > >;
+template < typename A >
+struct signature< std::vector< A > >;
+template < typename A, size_t N >
+struct signature< std::array< A, N > >;
+template < typename A, typename B >
+struct signature< std::unordered_map< A, B > >;
+template < typename A, typename B >
+struct signature< std::map< A, B > >;
+
+template < typename T >
+struct signature< T, typename std::enable_if< std::is_enum< T >::value, void >::type >
+{
+  /**
+      * @brief Returns name of type marshalled, for informative purposes
+      */
+  static std::string name()
+  {
+    return "enum";
+  }
+  /**
+      * @brief Returns DBUS' signature of type marshalled
+      */
+  static std::string sig()
+  {
+    // TODO: add check for failure in marshalling arguments
+    return "i";
+  }
+  /**
+      * @brief Marshals value v as marshalled type into message
+      */
+  static void set( Eldbus_Message_Iter* iter, T v )
+  {
+    eldbus_message_iter_arguments_append( iter, sig().c_str(), static_cast< int >( v ) );
+  }
+  /**
+      * @brief Marshals value from marshalled type into variable v
+      */
+  static bool get( Eldbus_Message_Iter* iter, T& v )
+  {
+    int q;
+    auto z = eldbus_message_iter_get_and_next( iter, sig()[0], &q );
+    v = static_cast< T >( q );
+    return z;
+  }
+};
+/// \endcond
+
+/**
+     * @brief Signature class for marshalling uint8 type.
+     */
+template <>
+struct signature< uint8_t >
+{
+  /**
+      * @brief Returns name of type marshalled, for informative purposes
+      */
+  static std::string name()
+  {
+    return "uint8_t";
+  }
+  /**
+      * @brief Returns DBUS' signature of type marshalled
+      */
+  static std::string sig()
+  {
+    return "y";
+  }
+  /**
+      * @brief Marshals value v as marshalled type into message
+      */
+  static void set( Eldbus_Message_Iter* iter, uint8_t v )
+  {
+    eldbus_message_iter_arguments_append( iter, sig().c_str(), v );
+  }
+  /**
+      * @brief Marshals value from marshalled type into variable v
+      */
+  static bool get( Eldbus_Message_Iter* iter, uint8_t& v )
+  {
+    return eldbus_message_iter_get_and_next( iter, sig()[0], &v );
+  }
+};
+
+/**
+     * @brief Signature class for marshalling uint16 type.
+     */
+template <>
+struct signature< uint16_t >
+{
+  /**
+      * @brief Returns name of type marshalled, for informative purposes
+      */
+  static std::string name()
+  {
+    return "uint16_t";
+  }
+  /**
+      * @brief Returns DBUS' signature of type marshalled
+      */
+  static std::string sig()
+  {
+    return "q";
+  }
+  /**
+      * @brief Marshals value v as marshalled type into message
+      */
+  static void set( Eldbus_Message_Iter* iter, uint16_t v )
+  {
+    eldbus_message_iter_arguments_append( iter, sig().c_str(), v );
+  }
+  /**
+      * @brief Marshals value from marshalled type into variable v
+      */
+  static bool get( Eldbus_Message_Iter* iter, uint16_t& v )
+  {
+    return eldbus_message_iter_get_and_next( iter, sig()[0], &v );
+  }
+};
+
+/**
+     * @brief Signature class for marshalling uint32 type.
+     */
+template <>
+struct signature< uint32_t >
+{
+  /**
+      * @brief Returns name of type marshalled, for informative purposes
+      */
+  static std::string name()
+  {
+    return "uint32_t";
+  }
+  /**
+      * @brief Returns DBUS' signature of type marshalled
+      */
+  static std::string sig()
+  {
+    return "u";
+  }
+  /**
+      * @brief Marshals value v as marshalled type into message
+      */
+  static void set( Eldbus_Message_Iter* iter, uint32_t v )
+  {
+    eldbus_message_iter_arguments_append( iter, sig().c_str(), v );
+  }
+  /**
+      * @brief Marshals value from marshalled type into variable v
+      */
+  static bool get( Eldbus_Message_Iter* iter, uint32_t& v )
+  {
+    return eldbus_message_iter_get_and_next( iter, sig()[0], &v );
+  }
+};
+
+/**
+     * @brief Signature class for marshalling uint64 type.
+     */
+template <>
+struct signature< uint64_t >
+{
+  /**
+      * @brief Returns name of type marshalled, for informative purposes
+      */
+  static std::string name()
+  {
+    return "uint64_t";
+  }
+  /**
+      * @brief Returns DBUS' signature of type marshalled
+      */
+  static std::string sig()
+  {
+    return "t";
+  }
+  /**
+      * @brief Marshals value v as marshalled type into message
+      */
+  static void set( Eldbus_Message_Iter* iter, uint64_t v )
+  {
+    eldbus_message_iter_arguments_append( iter, sig().c_str(), v );
+  }
+  /**
+      * @brief Marshals value from marshalled type into variable v
+      */
+  static bool get( Eldbus_Message_Iter* iter, uint64_t& v )
+  {
+    return eldbus_message_iter_get_and_next( iter, sig()[0], &v );
+  }
+};
+
+/**
+     * @brief Signature class for marshalling int16 type.
+     */
+template <>
+struct signature< int16_t >
+{
+  /**
+      * @brief Returns name of type marshalled, for informative purposes
+      */
+  static std::string name()
+  {
+    return "int16_t";
+  }
+  /**
+      * @brief Returns DBUS' signature of type marshalled
+      */
+  static std::string sig()
+  {
+    return "n";
+  }
+  /**
+      * @brief Marshals value v as marshalled type into message
+      */
+  static void set( Eldbus_Message_Iter* iter, int16_t v )
+  {
+    eldbus_message_iter_arguments_append( iter, sig().c_str(), v );
+  }
+  /**
+      * @brief Marshals value from marshalled type into variable v
+      */
+  static bool get( Eldbus_Message_Iter* iter, int16_t& v )
+  {
+    return eldbus_message_iter_get_and_next( iter, sig()[0], &v );
+  }
+};
+
+/**
+     * @brief Signature class for marshalling int32 type.
+     */
+template <>
+struct signature< int32_t >
+{
+  /**
+      * @brief Returns name of type marshalled, for informative purposes
+      */
+  static std::string name()
+  {
+    return "int32_t";
+  }
+  /**
+      * @brief Returns DBUS' signature of type marshalled
+      */
+  static std::string sig()
+  {
+    return "i";
+  }
+  /**
+      * @brief Marshals value v as marshalled type into message
+      */
+  static void set( Eldbus_Message_Iter* iter, int32_t v )
+  {
+    eldbus_message_iter_arguments_append( iter, sig().c_str(), v );
+  }
+  /**
+      * @brief Marshals value from marshalled type into variable v
+      */
+  static bool get( Eldbus_Message_Iter* iter, int32_t& v )
+  {
+    return eldbus_message_iter_get_and_next( iter, sig()[0], &v );
+  }
+};
+
+/**
+     * @brief Signature class for marshalling int64 type.
+     */
+template <>
+struct signature< int64_t >
+{
+  /**
+      * @brief Returns name of type marshalled, for informative purposes
+      */
+  static std::string name()
+  {
+    return "int64_t";
+  }
+  /**
+      * @brief Returns DBUS' signature of type marshalled
+      */
+  static std::string sig()
+  {
+    return "x";
+  }
+  /**
+      * @brief Marshals value v as marshalled type into message
+      */
+  static void set( Eldbus_Message_Iter* iter, int64_t v )
+  {
+    eldbus_message_iter_arguments_append( iter, sig().c_str(), v );
+  }
+  /**
+      * @brief Marshals value from marshalled type into variable v
+      */
+  static bool get( Eldbus_Message_Iter* iter, int64_t& v )
+  {
+    return eldbus_message_iter_get_and_next( iter, sig()[0], &v );
+  }
+};
+
+/**
+     * @brief Signature class for marshalling double type.
+     */
+template <>
+struct signature< double >
+{
+  /**
+      * @brief Returns name of type marshalled, for informative purposes
+      */
+  static std::string name()
+  {
+    return "double";
+  }
+  /**
+      * @brief Returns DBUS' signature of type marshalled
+      */
+  static std::string sig()
+  {
+    return "d";
+  }
+  /**
+      * @brief Marshals value v as marshalled type into message
+      */
+  static void set( Eldbus_Message_Iter* iter, double v )
+  {
+    eldbus_message_iter_arguments_append( iter, sig().c_str(), v );
+  }
+  /**
+      * @brief Marshals value from marshalled type into variable v
+      */
+  static bool get( Eldbus_Message_Iter* iter, double& v )
+  {
+    return eldbus_message_iter_get_and_next( iter, sig()[0], &v );
+  }
+  /**
+      * @brief Marshals value from marshalled type into variable v
+      */
+  static bool get( Eldbus_Message_Iter* iter, float& v2 )
+  {
+    double v = 0;
+    auto r = eldbus_message_iter_get_and_next( iter, sig()[0], &v );
+    v2 = static_cast< float >( v );
+    return r;
+  }
+};
+
+/**
+     * @brief Signature class for marshalling float type.
+     */
+template <>
+struct signature< float >
+{
+  /**
+      * @brief Returns name of type marshalled, for informative purposes
+      */
+  static std::string name()
+  {
+    return "float";
+  }
+  /**
+      * @brief Returns DBUS' signature of type marshalled
+      */
+  static std::string sig()
+  {
+    return "d";
+  }
+  /**
+      * @brief Marshals value v as marshalled type into message
+      */
+  static void set( Eldbus_Message_Iter* iter, float v )
+  {
+    eldbus_message_iter_arguments_append( iter, sig().c_str(), v );
+  }
+  /**
+      * @brief Marshals value from marshalled type into variable v
+      */
+  static bool get( Eldbus_Message_Iter* iter, double& v )
+  {
+    return eldbus_message_iter_get_and_next( iter, sig()[0], &v );
+  }
+  /**
+      * @brief Marshals value from marshalled type into variable v
+      */
+  static bool get( Eldbus_Message_Iter* iter, float& v2 )
+  {
+    double v = 0;
+    auto r = eldbus_message_iter_get_and_next( iter, sig()[0], &v );
+    v2 = static_cast< float >( v );
+    return r;
+  }
+};
+
+/**
+     * @brief Signature class for marshalling boolean type.
+     */
+template <>
+struct signature< bool >
+{
+  /**
+      * @brief Returns name of type marshalled, for informative purposes
+      */
+  static std::string name()
+  {
+    return "bool";
+  }
+  /**
+      * @brief Returns DBUS' signature of type marshalled
+      */
+  static std::string sig()
+  {
+    return "b";
+  }
+  /**
+      * @brief Marshals value v as marshalled type into message
+      */
+  static void set( Eldbus_Message_Iter* iter, bool v )
+  {
+    eldbus_message_iter_arguments_append( iter, sig().c_str(), v ? 1 : 0 );
+  }
+  /**
+      * @brief Marshals value from marshalled type into variable v
+      */
+  static bool get( Eldbus_Message_Iter* iter, bool& v )
+  {
+    unsigned char q;
+    auto z = eldbus_message_iter_get_and_next( iter, sig()[0], &q );
+    v = q != 0;
+    return z;
+  }
+};
+
+/**
+     * @brief Signature class for marshalling string type.
+     *
+     * Both (const) char * and std::string types are accepted as value to send.
+     * Only std::string is accepted as value to receive.
+     */
+template <>
+struct signature< std::string >
+{
+  /**
+      * @brief Returns name of type marshalled, for informative purposes
+      */
+  static std::string name()
+  {
+    return "string";
+  }
+  /**
+      * @brief Returns DBUS' signature of type marshalled
+      */
+  static std::string sig()
+  {
+    return "s";
+  }
+  /**
+      * @brief Marshals value v as marshalled type into message
+      */
+  static void set( Eldbus_Message_Iter* iter, const std::string& v )
+  {
+    eldbus_message_iter_arguments_append( iter, sig().c_str(), v.c_str() );
+  }
+  /**
+      * @brief Marshals value v as marshalled type into message
+      */
+  static void set( Eldbus_Message_Iter* iter, const char* v )
+  {
+    eldbus_message_iter_arguments_append( iter, sig().c_str(), v );
+  }
+  /**
+      * @brief Marshals value from marshalled type into variable v
+      */
+  static bool get( Eldbus_Message_Iter* iter, std::string& v )
+  {
+    const char* q;
+    if( !eldbus_message_iter_get_and_next( iter, 's', &q ) )
+    {
+      if( !eldbus_message_iter_get_and_next( iter, 'o', &q ) )
+        return false;
+    }
+    v = q;
+    return true;
+  }
+};
+template <>
+struct signature< ObjectPath >
+{
+  /**
+      * @brief Returns name of type marshalled, for informative purposes
+      */
+  static std::string name()
+  {
+    return "path";
+  }
+  /**
+      * @brief Returns DBUS' signature of type marshalled
+      */
+  static std::string sig()
+  {
+    return "o";
+  }
+  /**
+      * @brief Marshals value v as marshalled type into message
+      */
+  static void set( Eldbus_Message_Iter* iter, const std::string& v )
+  {
+    eldbus_message_iter_arguments_append( iter, sig().c_str(), v.c_str() );
+  }
+  /**
+      * @brief Marshals value v as marshalled type into message
+      */
+  static void set( Eldbus_Message_Iter* iter, const ObjectPath& v )
+  {
+    eldbus_message_iter_arguments_append( iter, sig().c_str(), v.value.c_str() );
+  }
+  /**
+      * @brief Marshals value v as marshalled type into message
+      */
+  static void set( Eldbus_Message_Iter* iter, const char* v )
+  {
+    eldbus_message_iter_arguments_append( iter, sig().c_str(), v );
+  }
+  /**
+      * @brief Marshals value from marshalled type into variable v
+      */
+  static bool get( Eldbus_Message_Iter* iter, ObjectPath& v )
+  {
+    const char* q;
+    if( !eldbus_message_iter_get_and_next( iter, 'o', &q ) )
+      return false;
+    v.value = q;
+    return true;
+  }
+  /**
+      * @brief Marshals value from marshalled type into variable v
+      */
+  static bool get( Eldbus_Message_Iter* iter, std::string& v )
+  {
+    const char* q;
+    if( !eldbus_message_iter_get_and_next( iter, 'o', &q ) )
+      return false;
+    v = q;
+    return true;
+  }
+};
+
+/**
+     * @brief Signature class for marshalling (const) char * type.
+     *
+     * Both (const) char * and std::string types are accepted as value to send.
+     * You can't use (const) char * variable type to receive value.
+     */
+template <>
+struct signature< char* >
+{
+  /**
+      * @brief Returns name of type marshalled, for informative purposes
+      */
+  static std::string name()
+  {
+    return "string";
+  }
+  /**
+      * @brief Returns DBUS' signature of type marshalled
+      */
+  static std::string sig()
+  {
+    return "s";
+  }
+  /**
+      * @brief Marshals value v as marshalled type into message
+      */
+  static void set( Eldbus_Message_Iter* iter, const std::string& v )
+  {
+    eldbus_message_iter_arguments_append( iter, sig().c_str(), v.c_str() );
+  }
+  /**
+      * @brief Marshals value v as marshalled type into message
+      */
+  static void set( Eldbus_Message_Iter* iter, const char* v )
+  {
+    eldbus_message_iter_arguments_append( iter, sig().c_str(), v );
+  }
+};
+
+/**
+     * @brief Signature class for marshalling (const) char[N] type.
+     *
+     * Both (const) char[N] and std::string types are accepted as value to send.
+     * You can't use (const) char[N] variable type to receive value.
+     */
+template < size_t N >
+struct signature< char[N] >
+{
+  /**
+      * @brief Returns name of type marshalled, for informative purposes
+      */
+  static std::string name()
+  {
+    return "string";
+  }
+  /**
+      * @brief Returns DBUS' signature of type marshalled
+      */
+  static std::string sig()
+  {
+    return "s";
+  }
+  /**
+      * @brief Marshals value v as marshalled type into message
+      */
+  static void set( Eldbus_Message_Iter* iter, const std::string& v )
+  {
+    eldbus_message_iter_arguments_append( iter, sig().c_str(), v.c_str() );
+  }
+  /**
+      * @brief Marshals value v as marshalled type into message
+      */
+  static void set( Eldbus_Message_Iter* iter, const char* v )
+  {
+    eldbus_message_iter_arguments_append( iter, sig().c_str(), v );
+  }
+};
+/// \cond
+template < size_t INDEX, typename A, typename... ARGS >
+struct signature_tuple_element_type_helper
+{
+  using type = typename signature_tuple_element_type_helper< INDEX - 1, ARGS... >::type;
+};
+template < typename A, typename... ARGS >
+struct signature_tuple_element_type_helper< 0, A, ARGS... >
+{
+  using type = A;
+};
+/// \endcond
+
+/**
+     * @brief Helper class to marshall tuples
+     *
+     * This class marshals all elements of the tuple value starting at the index INDEX
+     * and incrementing. This class recursively calls itself with increasing INDEX value
+     * until INDEX is equal to SIZE, where recursive calling ends.
+     */
+template < size_t INDEX, size_t SIZE, typename... ARGS >
+struct signature_tuple_helper
+{
+  using current_type = typename signature_tuple_element_type_helper< INDEX, ARGS... >::type;
+
+  /**
+      * @brief Returns name of type marshalled, for informative purposes
+      */
+  static std::string name()
+  {
+    if( INDEX + 1 >= SIZE )
+      return signature< current_type >::name();
+    return signature< current_type >::name() + ", " + signature_tuple_helper< INDEX + 1, SIZE, ARGS... >::name();
+  }
+  /**
+      * @brief Returns DBUS' signature of type marshalled
+      */
+  static std::string sig()
+  {
+    return signature< current_type >::sig() + signature_tuple_helper< INDEX + 1, SIZE, ARGS... >::sig();
+  }
+  /**
+      * @brief Marshals value v as marshalled type into message
+      */
+  static void set( Eldbus_Message_Iter* iter, const std::tuple< ARGS... >& args )
+  {
+    signature< current_type >::set( iter, std::get< INDEX >( args ) );
+    signature_tuple_helper< INDEX + 1, SIZE, ARGS... >::set( iter, args );
+  }
+  /**
+      * @brief Marshals value from marshalled type into variable v
+      */
+  static bool get( Eldbus_Message_Iter* iter, std::tuple< ARGS... >& args )
+  {
+    return signature< current_type >::get( iter, std::get< INDEX >( args ) ) &&
+           signature_tuple_helper< INDEX + 1, SIZE, ARGS... >::get( iter, args );
+  }
+};
+
+/**
+     * @brief Helper class to marshall tuples
+     *
+     * This class marks end of the tuple marshalling. Members of this class are called
+     * when INDEX value is equal to SIZE.
+     */
+template < size_t SIZE, typename... ARGS >
+struct signature_tuple_helper< SIZE, SIZE, ARGS... >
+{
+  /**
+      * @brief Returns name of type marshalled, for informative purposes
+      */
+  static std::string name()
+  {
+    return "";
+  }
+  /**
+      * @brief Returns DBUS' signature of type marshalled
+      */
+  static std::string sig()
+  {
+    return "";
+  }
+  /**
+      * @brief Marshals value v as marshalled type into message
+      */
+  static void set( Eldbus_Message_Iter* iter, const std::tuple< ARGS... >& args )
+  {
+  }
+  /**
+      * @brief Marshals value from marshalled type into variable v
+      */
+  static bool get( Eldbus_Message_Iter* iter, std::tuple< ARGS... >& args )
+  {
+    return true;
+  }
+};
+
+/**
+     * @brief Signature class for marshalling tuple of values
+     *
+     * This class marshalls tuple of values. This represents
+     * DBUS struct typle, encoded with character 'r'
+     */
+template < typename... ARGS >
+struct signature< std::tuple< ARGS... > >
+{
+  /**
+      * @brief Returns name of type marshalled, for informative purposes
+      */
+  static std::string name()
+  {
+    return "tuple<" + signature_tuple_helper< 0, sizeof...( ARGS ), ARGS... >::name() + ">";
+  }
+  /**
+      * @brief Returns DBUS' signature of type marshalled
+      */
+  static std::string sig()
+  {
+    return "(" + signature_tuple_helper< 0, sizeof...( ARGS ), ARGS... >::sig() + ")";
+  }
+  /**
+      * @brief Marshals value v as marshalled type into message
+      */
+  static void set( Eldbus_Message_Iter* iter, const std::tuple< ARGS... >& args )
+  {
+    auto entry = eldbus_message_iter_container_new( iter, 'r', NULL );
+    signature_tuple_helper< 0, sizeof...( ARGS ), ARGS... >::set( entry, args );
+    eldbus_message_iter_container_close( iter, entry );
+  }
+  /**
+      * @brief Marshals value from marshalled type into variable v
+      */
+  static bool get( Eldbus_Message_Iter* iter, std::tuple< ARGS... >& args )
+  {
+    Eldbus_Message_Iter* entry;
+    if( !eldbus_message_iter_get_and_next( iter, 'r', &entry ) )
+      return false;
+    auto z = signature_tuple_helper< 0, sizeof...( ARGS ), ARGS... >::get( entry, args );
+    return z;
+  }
+};
+/**
+     * @brief Signature class for marshalling ValueOrError template type
+     *
+     * ValueOrError template type is used to marshall list of values passed to
+     * DBUS (or received from) at the "top" level. For example ss(s) is represented as
+     * \code{.cpp} ValueOrError<std::string, std::string, std::tuple<std::string>> \endcode
+     * While (ss(s)) is represented as
+     * \code{.cpp} std::tuple<std::string, std::string, std::tuple<std::string>> \endcode
+     * or
+     * \code{.cpp} ValueOrError<std::tuple<std::string, std::string, std::tuple<std::string>>> \endcode
+     */
+template < typename... ARGS >
+struct signature< ValueOrError< ARGS... > >
+{
+  /**
+      * @brief Returns name of type marshalled, for informative purposes
+      */
+  static std::string name()
+  {
+    return "ValueOrError<" + signature_tuple_helper< 0, sizeof...( ARGS ), ARGS... >::name() + ">";
+  }
+  /**
+      * @brief Returns DBUS' signature of type marshalled
+      */
+  static std::string sig()
+  {
+    return signature_tuple_helper< 0, sizeof...( ARGS ), ARGS... >::sig();
+  }
+  /**
+      * @brief Marshals value v as marshalled type into message
+      */
+  static void set( Eldbus_Message_Iter* iter, const ValueOrError< ARGS... >& args )
+  {
+    signature_tuple_helper< 0, sizeof...( ARGS ), ARGS... >::set( iter, args.getValues() );
+  }
+  /**
+      * @brief Marshals value from marshalled type into variable v
+      */
+  static bool get( Eldbus_Message_Iter* iter, ValueOrError< ARGS... >& args )
+  {
+    return signature_tuple_helper< 0, sizeof...( ARGS ), ARGS... >::get( iter, args.getValues() );
+  }
+};
+/**
+     * @brief Signature class for marshalling ValueOrError<void> type
+     */
+template <>
+struct signature< ValueOrError< void > >
+{
+  /**
+      * @brief Returns name of type marshalled, for informative purposes
+      */
+  static std::string name()
+  {
+    return "ValueOrError<void>";
+  }
+  /**
+      * @brief Returns DBUS' signature of type marshalled
+      */
+  static std::string sig()
+  {
+    return "";
+  }
+  /**
+      * @brief Marshals value v as marshalled type into message
+      */
+  static void set( Eldbus_Message_Iter* iter, const ValueOrError< void >& args )
+  {
+  }
+  /**
+      * @brief Marshals value from marshalled type into variable v
+      */
+  static bool get( Eldbus_Message_Iter* iter, ValueOrError< void >& args )
+  {
+    return true;
+  }
+};
+/**
+     * @brief Signature class for marshalling ValueOrError<> type
+     */
+template <>
+struct signature< ValueOrError<> >
+{
+  /**
+      * @brief Returns name of type marshalled, for informative purposes
+      */
+  static std::string name()
+  {
+    return "ValueOrError<>";
+  }
+  /**
+      * @brief Returns DBUS' signature of type marshalled
+      */
+  static std::string sig()
+  {
+    return "";
+  }
+  /**
+      * @brief Marshals value v as marshalled type into message
+      */
+  static void set( Eldbus_Message_Iter* iter, const ValueOrError<>& args )
+  {
+  }
+  /**
+      * @brief Marshals value from marshalled type into variable v
+      */
+  static bool get( Eldbus_Message_Iter* iter, ValueOrError<>& args )
+  {
+    return true;
+  }
+};
+/**
+     * @brief Signature class for marshalling pair of types
+     */
+template < typename A, typename B >
+struct signature< std::pair< A, B > >
+{
+  /**
+      * @brief Returns name of type marshalled, for informative purposes
+      */
+  static std::string name()
+  {
+    return "pair<" + signature_tuple_helper< 0, 2, A, B >::name() + ">";
+  }
+  /**
+      * @brief Returns DBUS' signature of type marshalled
+      */
+  static std::string sig()
+  {
+    return "(" + signature_tuple_helper< 0, 2, A, B >::sig() + ")";
+  }
+  /**
+      * @brief Marshals value v as marshalled type into message
+      */
+  static void set( Eldbus_Message_Iter* iter, const std::pair< A, B >& ab, bool dictionary = false )
+  {
+    auto entry = eldbus_message_iter_container_new( iter, dictionary ? 'e' : 'r', NULL );
+    signature_tuple_helper< 0, 2, A, B >::set( entry, ab );
+    eldbus_message_iter_container_close( iter, entry );
+  }
+  /**
+      * @brief Marshals value from marshalled type into variable v
+      */
+  static bool get( Eldbus_Message_Iter* iter, std::pair< A, B >& ab )
+  {
+    char sg = 'r';
+    char* t = eldbus_message_iter_signature_get( iter );
+    if( t && t[0] == '{' )
+      sg = '{';
+    free( t );
+
+    Eldbus_Message_Iter* entry;
+    if( !eldbus_message_iter_get_and_next( iter, sg, &entry ) )
+      return false;
+    std::tuple< A, B > ab_tmp;
+    auto z = signature_tuple_helper< 0, 2, A, B >::get( entry, ab_tmp );
+    if( z )
+    {
+      ab.first = std::move( std::get< 0 >( ab_tmp ) );
+      ab.second = std::move( std::get< 1 >( ab_tmp ) );
+    }
+    return z;
+  }
+};
+/**
+     * @brief Signature class for marshalling std::vector template type
+     *
+     * This marshals container's content as DBUS a ascii character type code.
+     */
+template < typename A >
+struct signature< std::vector< A > >
+{
+  /**
+      * @brief Returns name of type marshalled, for informative purposes
+      */
+  static std::string name()
+  {
+    return "vector<" + signature< A >::name() + ">";
+  }
+  /**
+      * @brief Returns DBUS' signature of type marshalled
+      */
+  static std::string sig()
+  {
+    return "a" + signature< A >::sig();
+  }
+  /**
+      * @brief Marshals value v as marshalled type into message
+      */
+  static void set( Eldbus_Message_Iter* iter, const std::vector< A >& v )
+  {
+    auto lst = eldbus_message_iter_container_new( iter, 'a', signature< A >::sig().c_str() );
+    assert( lst );
+    for( auto& a : v )
+    {
+      signature< A >::set( lst, a );
+    }
+    eldbus_message_iter_container_close( iter, lst );
+  }
+  /**
+      * @brief Marshals value from marshalled type into variable v
+      */
+  static bool get( Eldbus_Message_Iter* iter, std::vector< A >& v )
+  {
+    Eldbus_Message_Iter* s;
+    v.clear();
+    if( !eldbus_message_iter_get_and_next( iter, 'a', &s ) )
+      return false;
+    A a;
+    while( signature< A >::get( s, a ) )
+      v.push_back( std::move( a ) );
+
+    return true;
+  }
+};
+
+/**
+     * @brief Signature class for marshalling std::array template type
+     *
+     * This marshals container's content as DBUS a ascii character type code.
+     */
+template < typename A, size_t N >
+struct signature< std::array< A, N > >
+{
+  /**
+      * @brief Returns name of type marshalled, for informative purposes
+      */
+  static std::string name()
+  {
+    return "array<" + signature< A >::name() + ", " + std::to_string( N ) + ">";
+  }
+  /**
+      * @brief Returns DBUS' signature of type marshalled
+      */
+  static std::string sig()
+  {
+    return "a" + signature< A >::sig();
+  }
+  /**
+      * @brief Marshals value v as marshalled type into message
+      */
+  static void set( Eldbus_Message_Iter* iter, const std::array< A, N >& v )
+  {
+    auto lst = eldbus_message_iter_container_new( iter, 'a', signature< A >::sig().c_str() );
+    assert( lst );
+    for( auto& a : v )
+    {
+      signature< A >::set( lst, a );
+    }
+    eldbus_message_iter_container_close( iter, lst );
+  }
+  /**
+      * @brief Marshals value from marshalled type into variable v
+      */
+  static bool get( Eldbus_Message_Iter* iter, std::array< A, N >& v )
+  {
+    Eldbus_Message_Iter* s;
+    if( !eldbus_message_iter_get_and_next( iter, 'a', &s ) )
+      return false;
+    for( auto& a : v )
+    {
+      if( !signature< A >::get( s, a ) )
+        return false;
+    }
+    return true;
+  }
+};
+
+/**
+     * @brief Signature class for marshalling EldbusVariant type
+     *
+     * This marshals variant's content as DBUS v ascii character type code.
+     */
+template < typename A >
+struct signature< EldbusVariant< A > >
+{
+  /**
+      * @brief Returns name of type marshalled, for informative purposes
+      */
+  static std::string name()
+  {
+    return "variant<" + signature< A >::name() + ">";
+  }
+  /**
+      * @brief Returns DBUS' signature of type marshalled
+      */
+  static std::string sig()
+  {
+    return "v";
+  }
+  /**
+      * @brief Marshals value v as marshalled type into message
+      */
+  static void set( Eldbus_Message_Iter* iter, const EldbusVariant< A >& v )
+  {
+    set( iter, v.value );
+  }
+  /**
+      * @brief Marshals value v as marshalled type into message
+      */
+  static void set( Eldbus_Message_Iter* iter, const A& v )
+  {
+    auto var = eldbus_message_iter_container_new( iter, 'v', signature< A >::sig().c_str() );
+    signature< A >::set( var, v );
+    eldbus_message_iter_container_close( iter, var );
+  }
+  /**
+      * @brief Marshals value from marshalled type into variable v
+      */
+  static bool get( Eldbus_Message_Iter* iter, EldbusVariant< A >& v )
+  {
+    Eldbus_Message_Iter* s;
+    if( !eldbus_message_iter_get_and_next( iter, 'v', &s ) )
+      return false;
+    return signature< A >::get( s, v.value );
+  }
+};
+/**
+     * @brief Signature class for marshalling std::unordered_map template type
+     *
+     * This marshals container's content as DBUS {} ascii character type code.
+     * Note, that library doesnt check, if the key is basic type, as DBUS
+     * specification mandates.
+     * User can always exchange std::unordered_map for std::map and the reverse.
+     * User can receive such values as std::vector of std::pair<key, value> values.
+     * Order of such values is unspecified.
+     */
+template < typename A, typename B >
+struct signature< std::unordered_map< A, B > >
+{
+  /**
+      * @brief Returns name of type marshalled, for informative purposes
+      */
+  static std::string name()
+  {
+    return "unordered_map<" + signature< A >::name() + ", " + signature< B >::name() + ">";
+  }
+  /**
+      * @brief Returns DBUS' signature of type marshalled
+      */
+  static std::string sig()
+  {
+    return "a{" + signature_tuple_helper< 0, 2, A, B >::sig() + "}";
+  }
+  /**
+      * @brief Marshals value v as marshalled type into message
+      */
+  static void set( Eldbus_Message_Iter* iter, const std::unordered_map< A, B >& v )
+  {
+    auto sig = "{" + signature_tuple_helper< 0, 2, A, B >::sig() + "}";
+    auto lst = eldbus_message_iter_container_new( iter, 'a', sig.c_str() );
+    assert( lst );
+    for( auto& a : v )
+    {
+      signature< std::pair< A, B > >::set( lst, a, true );
+    }
+    eldbus_message_iter_container_close( iter, lst );
+  }
+  /**
+      * @brief Marshals value from marshalled type into variable v
+      */
+  static bool get( Eldbus_Message_Iter* iter, std::unordered_map< A, B >& v )
+  {
+    Eldbus_Message_Iter* s;
+    v.clear();
+    if( !eldbus_message_iter_get_and_next( iter, 'a', &s ) )
+      return false;
+    std::pair< A, B > a;
+    while( signature< std::pair< A, B > >::get( s, a ) )
+      v.insert( std::move( a ) );
+    return true;
+  }
+};
+/**
+     * @brief Signature class for marshalling std::unordered_map template type
+     *
+     * This marshals container's content as DBUS {} ascii character type code.
+     * Note, that library doesnt check, if the key is basic type, as DBUS
+     * specification mandates.
+     * User can always exchange std::unordered_map for std::map and the reverse.
+     * User can receive such values as std::vector of std::pair<key, value> values.
+     * Order of such values is unspecified.
+     */
+template < typename A, typename B >
+struct signature< std::map< A, B > >
+{
+  /**
+      * @brief Returns name of type marshalled, for informative purposes
+      */
+  static std::string name()
+  {
+    return "map<" + signature< A >::name() + ", " + signature< B >::name() + ">";
+  }
+  /**
+      * @brief Returns DBUS' signature of type marshalled
+      */
+  static std::string sig()
+  {
+    return "a{" + signature_tuple_helper< 0, 2, A, B >::sig() + "}";
+  }
+  /**
+      * @brief Marshals value v as marshalled type into message
+      */
+  static void set( Eldbus_Message_Iter* iter, const std::map< A, B >& v )
+  {
+    auto sig = "{" + signature_tuple_helper< 0, 2, A, B >::sig() + "}";
+    auto lst = eldbus_message_iter_container_new( iter, 'a', sig.c_str() );
+    assert( lst );
+    for( auto& a : v )
+    {
+      signature< std::pair< A, B > >::set( lst, a, true );
+    }
+    eldbus_message_iter_container_close( iter, lst );
+  }
+  /**
+      * @brief Marshals value from marshalled type into variable v
+      */
+  static bool get( Eldbus_Message_Iter* iter, std::map< A, B >& v )
+  {
+    Eldbus_Message_Iter* s;
+    if( !eldbus_message_iter_get_and_next( iter, 'a', &s ) )
+      return false;
+    std::pair< A, B > a;
+    while( signature< std::pair< A, B > >::get( s, a ) )
+      v.insert( std::move( a ) );
+    return true;
+  }
+};
+/**
+     * @brief Signature helper class for marshalling const reference types
+     */
+template < typename A >
+struct signature< const A& >
+{
+  /**
+      * @brief Returns name of type marshalled, for informative purposes
+      */
+  static std::string name()
+  {
+    return "const " + signature< A >::name() + "&";
+  }
+  /**
+      * @brief Returns DBUS' signature of type marshalled
+      */
+  static std::string sig()
+  {
+    return signature< A >::sig();
+  }
+  /**
+      * @brief Marshals value v as marshalled type into message
+      */
+  static void set( Eldbus_Message_Iter* iter, const A& v )
+  {
+    signature< A >::set( iter, v );
+  }
+  /**
+      * @brief Marshals value from marshalled type into variable v
+      */
+  static void get( Eldbus_Message_Iter* iter, A& v )
+  {
+    signature< A >::get( iter, v );
+  }
+};
+/**
+     * @brief Signature helper class for marshalling reference types
+     */
+template < typename A >
+struct signature< A& >
+{
+  /**
+      * @brief Returns name of type marshalled, for informative purposes
+      */
+  static std::string name()
+  {
+    return signature< A >::name() + "&";
+  }
+  /**
+      * @brief Returns DBUS' signature of type marshalled
+      */
+  static std::string sig()
+  {
+    return signature< A >::sig();
+  }
+  /**
+      * @brief Marshals value v as marshalled type into message
+      */
+  static void set( Eldbus_Message_Iter* iter, const A& v )
+  {
+    signature< A >::set( iter, v );
+  }
+  /**
+      * @brief Marshals value from marshalled type into variable v
+      */
+  static void get( Eldbus_Message_Iter* iter, A& v )
+  {
+    signature< A >::get( iter, v );
+  }
+};
+/**
+     * @brief Signature helper class for marshalling const types
+     */
+template < typename A >
+struct signature< const A >
+{
+  /**
+      * @brief Returns name of type marshalled, for informative purposes
+      */
+  static std::string name()
+  {
+    return "const " + signature< A >::name();
+  }
+  /**
+      * @brief Returns DBUS' signature of type marshalled
+      */
+  static std::string sig()
+  {
+    return signature< A >::sig();
+  }
+  /**
+      * @brief Marshals value v as marshalled type into message
+      */
+  static void set( Eldbus_Message_Iter* iter, const A& v )
+  {
+    signature< A >::set( iter, v );
+  }
+  /**
+      * @brief Marshals value from marshalled type into variable v
+      */
+  static void get( Eldbus_Message_Iter* iter, A& v )
+  {
+    signature< A >::get( iter, v );
+  }
+};
+// /**
+//  * @brief Signature helper class for marshalling AT-SPI Accessible pointer values
+//  *
+//  * In AT-SPI specification those values are mandated to be marshalled as struct (so)
+//  * where o is object (exactly as string, but with different ascii
+//  * character code.
+//  */
+// template <> struct signature<std::shared_ptr<AtspiAccessible>> {
+//  using subtype = std::pair<std::string, std::string>;
+
+//  /**
+//  * @brief Returns name of type marshalled, for informative purposes
+//  */
+//  static std::string name()
+//  {
+//    return "AtspiAccessiblePtr";
+//  }
+//  /**
+//  * @brief Returns DBUS' signature of type marshalled
+//  */
+//  static std::string sig()
+//  {
+//    return "(so)";
+//  }
+//  /**
+//  * @brief Marshals value v as marshalled type into message
+//  */
+//  static void set(Eldbus_Message_Iter *iter, const std::shared_ptr<AtspiAccessible> &v)
+//  {
+//    const auto prefixPath = "/org/a11y/atspi/accessible/";
+//    const auto nullPath = "/org/a11y/atspi/null";
+
+//    if (v) {
+//      auto bus = atspi_accessible_get_bus_name(v.get(), NULL);
+//      auto path = atspi_accessible_get_path(v.get(), NULL);
+//      signature<subtype>::set(iter, { bus, std::string{prefixPath} + path });
+//      g_free(path);
+//      g_free(bus);
+//    } else {
+//      signature<subtype>::set(iter, { {}, std::string{nullPath} });
+//    }
+//  }
+//  /**
+//  * @brief Marshals value from marshalled type into variable v
+//  */
+//  static bool get(Eldbus_Message_Iter *iter, std::shared_ptr<AtspiAccessible> &v);
+// };
+/// \cond
+struct CallId
+{
+  friend class ::DBus::DBusServer;
+  friend class ::DBus::DBusClient;
+  friend class ::DBus::DBusInterfaceDescription;
+  static std::atomic< unsigned int > LastId;
+  unsigned int id = ++LastId;
+};
+template < typename ValueType >
+ValueType unpackValues( CallId callId, const Eldbus_Message* msg )
+{
+  auto iter = eldbus_message_iter_get( msg );
+  ValueType r;
+
+  if( iter )
+  {
+    if( !signature< ValueType >::get( iter, r ) )
+    {
+      DBUS_DEBUG( "ValueType is %s", signature< ValueType >::name().c_str() );
+      r = Error{"call " + std::to_string( callId.id ) + ": failed to unpack values, got signature '" +
+                eldbus_message_signature_get( msg ) + "', expected '" + signature< ValueType >::sig() + "'"};
+    }
+  }
+  else
+  {
+    r = Error{"call " + std::to_string( callId.id ) + ": failed to get iterator"};
+  }
+  return r;
+}
+inline void packValues_helper( Eldbus_Message_Iter* iter ) {}
+template < typename A, typename... ARGS >
+void packValues_helper( Eldbus_Message_Iter* iter, A&& a, ARGS&&... r )
+{
+  signature< A >::set( iter, std::forward< A >( a ) );
+  packValues_helper( iter, std::forward< ARGS >( r )... );
+}
+template < typename... ARGS >
+void packValues( CallId callId, Eldbus_Message* msg, ARGS&&... r )
+{
+  auto iter = eldbus_message_iter_get( msg );
+  packValues_helper( iter, std::forward< ARGS >( r )... );
+}
+
+template < typename >
+struct ReturnType;
+template < typename R, typename... ARGS >
+struct ReturnType< R( ARGS... ) >
+{
+  using type = R;
+};
+template < typename R, typename... ARGS >
+struct ReturnType< std::function< R( ARGS... ) > >
+{
+  using type = R;
+};
+template < int... >
+struct sequence
+{
+};
+template < int N, int... S >
+struct sequence_gen : sequence_gen< N - 1, N - 1, S... >
+{
+};
+template < int... S >
+struct sequence_gen< 0, S... >
+{
+  typedef sequence< S... > type;
+};
+template < typename C, typename... ARGS >
+struct apply_helper
+{
+  const std::function< C >& c;
+  const std::tuple< ARGS... >& args;
+
+  template < int... S >
+  auto apply_2( sequence< S... > ) const -> decltype( c( std::get< S >( args )... ) )
+  {
+    return c( std::get< S >( args )... );
+  }
+  auto apply_1() const -> decltype( apply_2( typename sequence_gen< sizeof...( ARGS ) >::type() ) )
+  {
+    return apply_2( typename sequence_gen< sizeof...( ARGS ) >::type() );
+  }
+};
+template < typename C, typename A, typename... ARGS >
+struct apply_helper_2
+{
+  const std::function< C >& c;
+  const A& a;
+  const std::tuple< ARGS... >& args;
+
+  template < int... S >
+  auto apply_2( sequence< S... > ) const -> decltype( c( a, std::get< S >( args )... ) )
+  {
+    return c( a, std::get< S >( args )... );
+  }
+  auto apply_1() const -> decltype( apply_2( typename sequence_gen< sizeof...( ARGS ) >::type() ) )
+  {
+    return apply_2( typename sequence_gen< sizeof...( ARGS ) >::type() );
+  }
+};
+template < typename C, typename... ARGS >
+auto apply( const std::function< C >& c, const std::tuple< ARGS... >& args ) -> typename ReturnType< C >::type
+{
+  apply_helper< C, ARGS... > ah{c, args};
+  return ah.apply_1();
+}
+template < typename C, typename D, typename... ARGS >
+auto apply( const std::function< C >& c, const D& d, const std::tuple< ARGS... >& args ) -> typename ReturnType< C >::type
+{
+  apply_helper_2< C, D, ARGS... > ah{c, d, args};
+  return ah.apply_1();
+}
+
+struct EldbusProxyBase
+{
+  EldbusProxyBase()
+  {
+    eldbus_init();
+  }
+  ~EldbusProxyBase()
+  {
+    eldbus_shutdown();
+  }
+};
+
+constexpr static int ELDBUS_CALL_TIMEOUT = 1000;
+
+struct ConnectionState
+{
+  std::shared_ptr< DBus::EldbusConnection > connection;
+  EldbusObjectCallbackHandle object;
+  EldbusProxyHandle proxy;
+  EldbusProxyHandle propertiesProxy;
+};
+using CallAsyncDataType = std::tuple< CallId, std::function< void( const Eldbus_Message* ) > >;
+
+static void callAsyncCb( void* data, const Eldbus_Message* msg, Eldbus_Pending* pending )
+{
+  auto d = static_cast< CallAsyncDataType* >( data );
+  DBUS_DEBUG( "call %d: got reply", std::get< 0 >( *d ).id );
+  std::get< 1 > ( *d )( msg );
+}
+static void pendingFreeCb( void* data, const void* )
+{
+  auto d = static_cast< CallAsyncDataType* >( data );
+  DBUS_DEBUG( "call %d: deleting", std::get< 0 >( *d ).id );
+  delete d;
+}
+template < typename RETTYPE, typename... ARGS >
+RETTYPE call( CallId callId, ConnectionState& connectionState, bool property, const std::string& funcName, const ARGS&... args )
+{
+  auto proxy = property ? connectionState.propertiesProxy : connectionState.proxy;
+  if( !proxy )
+  {
+    DBUS_DEBUG( "call %d: not initialized", callId.id );
+    return Error{"not initialized"};
+  }
+
+  DBUS_DEBUG( "call %d: calling '%s'", callId.id, funcName.c_str() );
+  EldbusMessageCallbackHandle msg{eldbus_proxy_method_call_new( proxy.get(), funcName.c_str() )};
+  if( !msg )
+  {
+    DBUS_DEBUG( "call %d: failed", callId.id );
+    return Error{"failed to create message"};
+  }
+
+  detail::packValues( callId, msg.get(), args... );
+  auto replyRawPtr = eldbus_proxy_send_and_block( proxy.get(), msg.release(), ELDBUS_CALL_TIMEOUT );
+  EldbusMessageCallbackHandle reply{replyRawPtr};
+  DBUS_DEBUG( "call %d: calling '%s' done", callId.id, funcName.c_str() );
+  if( !reply )
+  {
+    DBUS_DEBUG( "call %d: failed", callId.id );
+    return Error{"eldbus returned null as reply"};
+  }
+  const char *errname, *errmsg;
+  if( eldbus_message_error_get( reply.get(), &errname, &errmsg ) )
+  {
+    DBUS_DEBUG( "call %d: %s: %s", callId.id, errname, errmsg );
+    return Error{std::string( errname ) + ": " + errmsg};
+  }
+  DBUS_DEBUG( "call %d: got reply with signature '%s'", callId.id, eldbus_message_signature_get( reply.get() ) );
+  return detail::unpackValues< RETTYPE >( callId, reply.get() );
+}
+
+template < typename RETTYPE, typename... ARGS >
+void asyncCall( CallId callId, ConnectionState connectionState,
+                bool property, const std::string& funcName,
+                std::function< void( RETTYPE ) > callback, const ARGS&... args )
+{
+  auto proxy = property ? connectionState.propertiesProxy : connectionState.proxy;
+  if( !proxy )
+  {
+    DBUS_DEBUG( "call %d: not initialized", callId.id );
+    callback( Error{"not initialized"} );
+    return;
+  }
+
+  EldbusMessageCallbackHandle msg{eldbus_proxy_method_call_new( proxy.get(), funcName.c_str() )};
+  if( !msg )
+  {
+    DBUS_DEBUG( "call %d: failed", callId.id );
+    callback( Error{"failed to create message"} );
+    return;
+  }
+
+  auto cbData = new CallAsyncDataType{callId, [callback, callId, proxy]( const Eldbus_Message* reply ) {
+                                        DBUS_DEBUG( "call %d: calling done", callId.id );
+                                        if( !reply )
+                                        {
+                                          DBUS_DEBUG( "call %d: failed", callId.id );
+                                          callback( Error{"eldbus returned null as reply"} );
+                                        }
+                                        else
+                                        {
+                                          const char *errname, *errmsg;
+                                          if( eldbus_message_error_get( reply, &errname, &errmsg ) )
+                                          {
+                                            DBUS_DEBUG( "call %d: %s: %s", callId.id, errname, errmsg );
+                                            callback( Error{std::string( errname ) + ": " + errmsg} );
+                                          }
+                                          else
+                                          {
+                                            DBUS_DEBUG( "call %d: got reply with signature '%s'", callId.id, eldbus_message_signature_get( reply ) );
+                                            callback( detail::unpackValues< RETTYPE >( callId, reply ) );
+                                          }
+                                        }
+                                      }};
+  detail::packValues( callId, msg.get(), args... );
+  auto pending = eldbus_proxy_send( proxy.get(), msg.release(), callAsyncCb, cbData, ELDBUS_CALL_TIMEOUT );
+  if( pending )
+  {
+    eldbus_pending_free_cb_add( pending, pendingFreeCb, cbData );
+    DBUS_DEBUG( "call %d: call sent", callId.id );
+  }
+  else
+  {
+    DBUS_DEBUG( "call %d: failed to send call", callId.id );
+    callback( Error{"failed to send call"} );
+  }
+}
+inline void displayDebugCallInfo( CallId callId, const std::string& funcName, const std::string& info, const std::string& interfaceName )
+{
+  DBUS_DEBUG( "call %d: %s iname = %s fname = %s", callId.id, info.c_str(), interfaceName.c_str(), funcName.c_str() );
+}
+inline void displayDebugCallInfoSignal( CallId callId, const std::string& funcName, const std::string& info, const std::string& interfaceName )
+{
+  DBUS_DEBUG( "call %d: %s signal iname = %s fname = %s", callId.id, info.c_str(), interfaceName.c_str(), funcName.c_str() );
+}
+inline void displayDebugCallInfoProperty( CallId callId, const std::string& funcName, std::string info, const std::string& interfaceName,
+                                          const std::string& propertyName )
+{
+  DBUS_DEBUG( "call %d: %s iname = %s pname = %s", callId.id, info.c_str(), interfaceName.c_str(), propertyName.c_str() );
+}
+
+class StringStorage
+{
+  struct char_ptr_deleter
+  {
+    void operator()( char* p )
+    {
+      free( p );
+    }
+  };
+  std::vector< std::unique_ptr< char, char_ptr_deleter > > storage;
+
+public:
+  const char* add( const char* txt )
+  {
+    auto ptr = strdup( txt );
+    storage.push_back( std::unique_ptr< char, char_ptr_deleter >( ptr ) );
+    return storage.back().get();
+  }
+  const char* add( const std::string& txt )
+  {
+    return add( txt.c_str() );
+  }
+};
+template < typename A, typename... ARGS >
+struct EldbusArgGenerator_Helper
+{
+  static void add( std::vector< Eldbus_Arg_Info >& r, StringStorage& strings )
+  {
+    auto s = r.size();
+    auto sig = signature< A >::sig();
+    assert( !sig.empty() );
+    auto name = "p" + std::to_string( s + 1 );
+    r.push_back( Eldbus_Arg_Info{strings.add( sig ), strings.add( name )} );
+    EldbusArgGenerator_Helper< ARGS... >::add( r, strings );
+  }
+};
+template <>
+struct EldbusArgGenerator_Helper< void >
+{
+  static void add( std::vector< Eldbus_Arg_Info >&, StringStorage& )
+  {
+  }
+};
+template <>
+struct EldbusArgGenerator_Helper< ValueOrError< void >, void >
+{
+  static void add( std::vector< Eldbus_Arg_Info >&, StringStorage& )
+  {
+  }
+};
+template <>
+struct EldbusArgGenerator_Helper< ValueOrError<>, void >
+{
+  static void add( std::vector< Eldbus_Arg_Info >&, StringStorage& )
+  {
+  }
+};
+template < typename... ARGS >
+struct EldbusArgGenerator_Helper< std::tuple< ARGS... > >
+{
+  static void add( std::vector< Eldbus_Arg_Info >& r, StringStorage& strings )
+  {
+    EldbusArgGenerator_Helper< ARGS..., void >::add( r, strings );
+  }
+};
+template < typename RetType >
+struct dbus_interface_return_type_traits
+{
+  using type = ValueOrError< RetType >;
+};
+template < typename... ARGS >
+struct dbus_interface_return_type_traits< ValueOrError< ARGS... > >
+{
+  using type = ValueOrError< ARGS... >;
+};
+template < typename T >
+struct dbus_interface_traits;
+template < typename RetType, typename... ARGS >
+struct dbus_interface_traits< RetType( ARGS... ) >
+{
+  using Ret = typename dbus_interface_return_type_traits< RetType >::type;
+  using SyncCB = std::function< Ret( ARGS... ) >;
+  using AsyncCB = std::function< void( std::function< void( Ret ) >, ARGS... ) >;
+  using VEArgs = ValueOrError< ARGS... >;
+};
+template < typename T >
+struct EldbusArgGenerator_Args;
+template < typename RetType, typename... ARGS >
+struct EldbusArgGenerator_Args< RetType( ARGS... ) >
+{
+  static std::string name()
+  {
+    return signature_tuple_helper< 0, sizeof...( ARGS ), ARGS... >::name();
+  }
+  static std::vector< Eldbus_Arg_Info > get( StringStorage& strings )
+  {
+    std::vector< Eldbus_Arg_Info > tmp;
+    EldbusArgGenerator_Helper< ARGS..., void >::add( tmp, strings );
+    tmp.push_back( {nullptr, nullptr} );
+    return tmp;
+  }
+};
+template < typename T >
+struct EldbusArgGenerator_ReturnType;
+template < typename RetType, typename... ARGS >
+struct EldbusArgGenerator_ReturnType< RetType( ARGS... ) >
+{
+  static std::string name()
+  {
+    return signature< RetType >::name();
+  }
+  static std::vector< Eldbus_Arg_Info > get( StringStorage& strings )
+  {
+    std::vector< Eldbus_Arg_Info > tmp;
+    EldbusArgGenerator_Helper< RetType, void >::add( tmp, strings );
+    tmp.push_back( {nullptr, nullptr} );
+    return tmp;
+  }
+};
+template < typename T >
+struct EldbusArgGenerator_ReturnType;
+template < typename... ARGS >
+struct EldbusArgGenerator_ReturnType< void( ARGS... ) >
+{
+  static std::string name()
+  {
+    return "";
+  }
+  static std::vector< Eldbus_Arg_Info > get( StringStorage& strings )
+  {
+    std::vector< Eldbus_Arg_Info > tmp;
+    tmp.push_back( {nullptr, nullptr} );
+    return tmp;
+  }
+};
+/// \endcond
+}
+
+/**
+  * @brief Enumeration determining, which DBUS session user wants to connect to.
+  */
+enum class ConnectionType
+{
+  SYSTEM,
+  SESSION
+};
+
+/**
+  * @brief Class representing client's end of DBUS connection
+  *
+  * Allows calling (synchronous and asynchronos) methods on selected interface
+  * Allows (synchronous and asynchronos) setting / getting properties.
+  * Allows registering signals.
+  */
+class DBusClient : private detail::EldbusProxyBase
+{
+  /// \cond
+  struct ConnectionInfo
+  {
+    std::string interfaceName, busName, pathName;
+    void emit( const char* member, DBusActionType type )
+    {
+      detail::emitNotification( busName.c_str(), pathName.c_str(), interfaceName.c_str(), member, type );
+    }
+  };
+  /// \endcond
+public:
+  /**
+    * @brief Default constructor, creates non-connected object.
+    */
+  DBusClient() = default;
+  /**
+    * @brief Connects to dbus choosen by tp, using given arguments
+    *
+    * @param bus_name name of the bus to connect to
+    * @param path_name object's path
+    * @param interface_name interface name
+    */
+  DBusClient( std::string busName_, std::string pathName_, std::string interfaceName_,
+              ConnectionType tp );
+  /**
+    * @brief Connects to dbus using connection conn
+    *
+    * @param bus_name name of the bus to connect to
+    * @param path_name object's path
+    * @param interface_name interface name
+    * @param conn connection object from getDBusConnectionByType call
+    */
+  DBusClient( std::string busName_, std::string pathName_, std::string interfaceName_,
+              const std::shared_ptr< DBus::EldbusConnection >& conn = {} );
+  /**
+    * @brief Destructor object.
+    *
+    * All signals added will be disconnected.
+    * All asynchronous calls will be cancelled, their callback's will be called
+    * with failure message.
+    */
+  ~DBusClient() = default;
+  DBusClient( const DBusClient& ) = delete;
+  DBusClient( DBusClient&& ) = default;
+
+  DBusClient& operator=( DBusClient&& ) = default;
+  DBusClient& operator=( const DBusClient& ) = delete;
+
+  /**
+    * @brief bool operator
+    *
+    * Returns true, if object is connected to DBUS
+    */
+  explicit operator bool() const
+  {
+    return bool( connectionState.proxy );
+  }
+
+  /**
+    * @brief Helper class for calling a method
+    *
+    * Template type T defines both arguments sent to the method
+    * and expected values. Receiving different values will be reported as
+    * error. For example:
+    * \code{.cpp} Method<int(float, float)> \endcode
+    * defines method, which takes two arguments (two floats) and return
+    * single value of type int.
+    */
+  template < typename T >
+  struct Method
+  {
+    /// \cond
+    using RetType = typename detail::dbus_interface_traits< T >::Ret;
+    detail::ConnectionState connectionState;
+    std::string funcName;
+    std::string info;
+    std::shared_ptr< ConnectionInfo > connectionInfo;
+    /// \endcond
+
+    /**
+       * @brief Executes synchronous call on DBUS's method
+       *
+       * The function returns ValueOrError<...> object, which
+       * contains either received values or error message.
+       *
+       * @param args arguments to pass to the method
+       */
+    template < typename... ARGS >
+    RetType call( const ARGS&... args )
+    {
+      detail::CallId callId;
+      detail::displayDebugCallInfo( callId, funcName, info, connectionInfo->interfaceName );
+      return detail::call< RetType >( callId, connectionState, false, funcName, args... );
+    }
+
+    /**
+       * @brief Executes asynchronous call on DBUS's method
+       *
+       * The function calls callback with either received values or error message.
+       *
+       * @param callback callback functor, which will be called with return value(s) or error message
+       * @param args arguments to pass to the method
+       */
+    template < typename... ARGS >
+    void asyncCall( std::function< void( RetType ) > callback, const ARGS&... args )
+    {
+      detail::CallId callId;
+      detail::displayDebugCallInfo( callId, funcName, info, connectionInfo->interfaceName );
+      auto connectionState = this->connectionState;
+      detail::asyncCall< RetType >( callId, connectionState, false, funcName, std::move( callback ), args... );
+    }
+  };
+
+  /**
+    * @brief Helper class for calling a property
+    *
+    * Template type T defines type of the value hidden under property.
+    * Note, that library automatically wraps both sent and received value into
+    * DBUS's wrapper type.
+    */
+  template < typename T >
+  struct Property
+  {
+    /// \cond
+    using RetType = typename detail::dbus_interface_return_type_traits< T >::type;
+    using VariantRetType = typename detail::dbus_interface_return_type_traits< EldbusVariant< T > >::type;
+    detail::ConnectionState connectionState;
+    std::string propName;
+    std::string info;
+    std::shared_ptr< ConnectionInfo > connectionInfo;
+    /// \endcond
+
+    /**
+      * @brief executes synchronous get on property
+      *
+      * The function returns ValueOrError<...> object, which
+      * contains either received values or error message.
+      */
+    RetType get()
+    {
+      connectionInfo->emit( propName.c_str(), DBusActionType::GETTER_CALL );
+      detail::CallId callId;
+      detail::displayDebugCallInfoProperty( callId, "Get", info, connectionInfo->interfaceName, propName );
+      auto z = detail::call< VariantRetType >( callId, connectionState, true, "Get", connectionInfo->interfaceName, propName );
+      if( !z )
+        return z.getError();
+      return {std::get< 0 >( z.getValues() ).value};
+    }
+
+    /**
+      * @brief executes asynchronous get on property
+      *
+      * The function calls callback with either received values or error message.
+      *
+      * @param callback callback functor, which will be called with return value(s) or error message
+      */
+    void asyncGet( std::function< void( RetType ) > callback )
+    {
+      connectionInfo->emit( propName.c_str(), DBusActionType::GETTER_CALL );
+      detail::CallId callId;
+      detail::displayDebugCallInfoProperty( callId, "Get", info, connectionInfo->interfaceName, propName );
+      auto connectionState = this->connectionState;
+      auto cc = [callback]( VariantRetType reply ) {
+        if( reply )
+          callback( std::move( std::get< 0 >( reply.getValues() ).value ) );
+        else
+          callback( reply.getError() );
+      };
+      detail::asyncCall< VariantRetType >( callId, connectionState, true, "Get", std::move( cc ), connectionInfo->interfaceName, propName );
+    }
+
+    /**
+      * @brief executes synchronous set on property
+      *
+      * The function returns ValueOrError<void> object, with
+      * possible error message.
+      */
+    ValueOrError< void > set( const T& r )
+    {
+      connectionInfo->emit( propName.c_str(), DBusActionType::SETTER_CALL );
+      detail::CallId callId;
+      detail::displayDebugCallInfoProperty( callId, "Set", info, connectionInfo->interfaceName, propName );
+      EldbusVariant< T > variantValue{std::move( r )};
+      return detail::call< ValueOrError< void > >( callId, connectionState, true, "Set", connectionInfo->interfaceName, propName, variantValue );
+    }
+
+    /**
+      * @brief executes asynchronous get on property
+      *
+      * The function calls callback with either received values or error message.
+      *
+      * @param callback callback functor, which will be called with return value(s) or error message
+      */
+    void asyncSet( std::function< void( ValueOrError< void > ) > callback, const T& r )
+    {
+      connectionInfo->emit( propName.c_str(), DBusActionType::SETTER_CALL );
+      detail::CallId callId;
+      detail::displayDebugCallInfoProperty( callId, "Set", info, connectionInfo->interfaceName, propName );
+      EldbusVariant< T > variantValue{std::move( r )};
+      detail::asyncCall< ValueOrError< void > >( callId, connectionState, true, "Set", std::move( callback ), connectionInfo->interfaceName, propName, variantValue );
+    }
+  };
+
+  /**
+    * @brief Constructs Property<...> object for calling properties
+    *
+    * The function constructs and returns proxy object for calling property.
+    *
+    * @param propName property name to set and / or query
+    */
+  template < typename PropertyType >
+  Property< PropertyType > property( std::string propName )
+  {
+    return Property< PropertyType >{connectionState, std::move( propName ), info, connectionInfo};
+  }
+
+  /**
+    * @brief Constructs Method<...> object for calling methods
+    *
+    * The function constructs and returns proxy object for calling method.
+    *
+    * @param funcName function name to call
+    */
+  template < typename MethodType >
+  Method< MethodType > method( std::string funcName )
+  {
+    return Method< MethodType >{connectionState, std::move( funcName ), info, connectionInfo};
+  }
+
+  /**
+     * @brief Registers notification callback, when property has changed
+     *
+     * The callback will be called with new value, when property's value has changed.
+     * Note, that template type V must match expected type, otherwise undefined behavior will occur,
+     * there's no check for this.
+     */
+  template < typename V >
+  void addPropertyChangedEvent( std::string propertyName, std::function< void( V ) > callback )
+  {
+    detail::CallId callId;
+    detail::displayDebugCallInfoSignal( callId, propertyName, info, connectionInfo->interfaceName );
+    DBUS_DEBUG( "call %d: adding property", callId.id );
+    auto cS = this->connectionState;
+    auto cI = this->connectionInfo;
+    auto callbackLambdaPtr = new std::function< void( Eldbus_Proxy_Event_Property_Changed* ) >;
+    *callbackLambdaPtr = [callId, cS, callback, propertyName, cI]( Eldbus_Proxy_Event_Property_Changed* ev ) {
+      const char* ifc = eldbus_proxy_interface_get( ev->proxy );
+      DBUS_DEBUG( "call %d: property changed iname = %s pname = %s (name %s iface %s)",
+                  callId.id, cI->interfaceName.c_str(), propertyName.c_str(), ev->name, ifc );
+      V val = 0;
+      if( ev->name && ev->name == propertyName && ifc && cI->interfaceName == ifc )
+      {
+        if( !eina_value_get( ev->value, &val ) )
+        {
+          DBUS_DEBUG( "unable to get property's value" );
+          return;
+        }
+        DBUS_DEBUG( ". %d", val );
+        callback( val );
+        DBUS_DEBUG( "." );
+      }
+      DBUS_DEBUG( "." );
+    };
+    auto p = connectionState.proxy.get();
+    eldbus_proxy_event_callback_add( p, ELDBUS_PROXY_EVENT_PROPERTY_CHANGED,
+                                     listenerEventChangedCallback, callbackLambdaPtr );
+    destructors.add( [=]() {
+      eldbus_proxy_event_callback_del( p, ELDBUS_PROXY_EVENT_PROPERTY_CHANGED,
+                                       listenerEventChangedCallback, callbackLambdaPtr );
+      delete callbackLambdaPtr;
+    } );
+  }
+  /**
+    * @brief Registers callback on the DBUS' signal
+    *
+    * The function registers callback signalName. When signal comes, callback will be called.
+    * Callback object will exists as long as signal is registered. You can unregister signal
+    * by destroying DBusClient object.
+    *
+    * @param signalName name of the signal to register
+    * @param callback callback to call
+    */
+  template < typename SignalType >
+  void addSignal( std::string signalName, std::function< SignalType > callback )
+  {
+    detail::CallId callId;
+    detail::displayDebugCallInfoSignal( callId, signalName, info, connectionInfo->interfaceName );
+    auto cS = this->connectionState;
+    auto cI = this->connectionInfo;
+    auto callbackLambda = [callId, cS, callback, signalName, cI]( const Eldbus_Message* msg ) -> void {
+      const char *errname, *aux;
+      if( eldbus_message_error_get( msg, &errname, &aux ) )
+      {
+        DBUS_DEBUG( "call %d: Eldbus error: %s %s", callId.id, errname, aux );
+        return;
+      }
+      cI->emit( signalName.c_str(), DBusActionType::SIGNAL_RECEIVED );
+      DBUS_DEBUG( "call %d: received signal with signature '%s'", callId.id, eldbus_message_signature_get( msg ) );
+      using ParamsType = typename detail::dbus_interface_traits< SignalType >::VEArgs;
+      auto params = detail::unpackValues< ParamsType >( callId, msg );
+      if( !params )
+      {
+        DBUS_DEBUG( "call %d: failed: %s", callId.id, params.getError().message.c_str() );
+        return;
+      }
+      try
+      {
+        detail::apply( callback, params.getValues() );
+      }
+      catch( ... )
+      {
+        DBUS_DEBUG( "unhandled exception" );
+        assert( 0 );
+      }
+    };
+    auto tmp = new std::function< void( const Eldbus_Message* msg ) >{std::move( callbackLambda )};
+    auto handler = eldbus_proxy_signal_handler_add( connectionState.proxy.get(), signalName.c_str(), listenerCallback, tmp );
+    destructors.add( [=]() {
+      eldbus_signal_handler_del( handler );
+      delete tmp;
+    } );
+  }
+
+private:
+  /// \cond
+  detail::ConnectionState connectionState;
+  detail::CallOnDestructionList destructors;
+  std::string info;
+  std::shared_ptr< ConnectionInfo > connectionInfo;
+  void emitNotification( DBusActionType type );
+
+  static void listenerCallback( void* data, const Eldbus_Message* msg )
+  {
+    auto p = static_cast< std::function< void( const Eldbus_Message* msg ) >* >( data );
+    ( *p )( msg );
+  }
+  static void listenerEventChangedCallback( void* data, Eldbus_Proxy* proxy EINA_UNUSED, void* event )
+  {
+    auto p = static_cast< std::function< void( Eldbus_Proxy_Event_Property_Changed* ) >* >( data );
+    ( *p )( static_cast< Eldbus_Proxy_Event_Property_Changed* >( event ) );
+  }
+  /// \endcond
+};
+
+/**
+   * @brief Helper class describing DBUS's server interface
+   *
+   */
+class DBusInterfaceDescription
+{
+  friend class DBusServer;
+
+public:
+  /// \cond
+  struct MethodInfo
+  {
+    detail::CallId id;
+    std::string memberName;
+    std::vector< Eldbus_Arg_Info > in, out;
+    std::function< Eldbus_Message*( const Eldbus_Message* msg ) > callback;
+  };
+  struct SignalInfo
+  {
+    detail::CallId id;
+    std::string memberName;
+    std::vector< Eldbus_Arg_Info > args;
+    unsigned int uniqueId;
+  };
+  struct PropertyInfo
+  {
+    detail::CallId setterId, getterId;
+    std::string memberName, typeSignature;
+    std::function< ValueOrError< void >( const Eldbus_Message*src, Eldbus_Message_Iter*dst ) > getCallback, setCallback;
+  };
+  class SignalId
+  {
+    friend class ::DBus::DBusServer;
+    friend class ::DBus::DBusClient;
+    friend class ::DBus::DBusInterfaceDescription;
+    detail::CallId id;
+
+    SignalId( detail::CallId id ) : id( id ) {}
+
+  public:
+    SignalId() = default;
+  };
+  /// \endcond
+
+  /**
+     * @brief Creates empty interface description with given name
+     *
+     * @param interfaceName name of the interface
+     */
+  DBusInterfaceDescription( std::string interfaceName );
+
+  /**
+     * @brief adds new, synchronous method to the interface
+     *
+     * When method memberName is called on DBUS, callback functor will be called
+     * with values received from DBUS. callback won't be called, if method was
+     * called with invalid signature. Value returned from functor (or error message)
+     * will be marshalled back to the caller.
+     *
+     * Template type T defines both arguments sent to the method
+     * and expected values. Receiving different values will be reported as
+     * error. For example:
+     * \code{.cpp} Method<int(float, float)> \endcode
+     * defines method, which takes two arguments (two floats) and return
+     * single value of type int.
+     *
+     * @param memberName name of the method
+     * @param callback functor, which will be called
+     */
+  template < typename T >
+  void addMethod( const std::string& memberName, typename detail::dbus_interface_traits< T >::SyncCB callback )
+  {
+    detail::CallId callId;
+    MethodInfo mi;
+    methods.push_back( std::move( mi ) );
+    auto& z = methods.back();
+    z.in = detail::EldbusArgGenerator_Args< T >::get( strings );
+    z.out = detail::EldbusArgGenerator_ReturnType< T >::get( strings );
+    z.memberName = memberName;
+    DBUS_DEBUG( "call %d: method %s, in %s, out %s", callId.id, memberName.c_str(),
+                detail::EldbusArgGenerator_Args< T >::name().c_str(),
+                detail::EldbusArgGenerator_ReturnType< T >::name().c_str() );
+    z.callback = construct< T >( callId, callback );
+    z.id = callId;
+  }
+
+  /**
+     * @brief adds new, asynchronous method to the interface
+     *
+     * When method memberName is called on DBUS, callback functor will be called
+     * with values received from DBUS. callback won't be called, if method was
+     * called with invalid signature. callback will called with reply callback functor.
+     * Reply callback functor must be called with reply value, when it's ready.
+     * It's safe to ignore calling reply callback, but some resources might be kept
+     * as long as either reply callback exists or reply timeout hasn't yet been met.
+     *
+     * Template type T defines both arguments sent to the method
+     * and expected values. Receiving different values will be reported as
+     * error. For example:
+     * \code{.cpp} Method<int(float, float)> \endcode
+     * defines method, which takes two arguments (two floats) and return
+     * single value of type int.
+     *
+     * @param memberName name of the method
+     * @param callback functor, which will be called
+     */
+  template < typename T >
+  void addAsyncMethod( const std::string& memberName, typename detail::dbus_interface_traits< T >::AsyncCB callback );
+
+  /**
+     * @brief adds new, synchronous property to the interface
+     *
+     * When property memberName is called on DBUS, respective callback functor will be called
+     * with values received from DBUS. callback won't be called, if method was
+     * called with invalid signature. Value returned from functor (or error message)
+     * will be marshalled back to the caller.
+     *
+     * Template type T defines type of the value hidden under property.
+     * Note, that library automatically wraps both sent and received value into
+     * DBUS's wrapper type.
+     *
+     * @param memberName name of the method
+     * @param getter functor, which will be called when property is being read
+     * @param setter functor, which will be called when property is being set
+     */
+  template < typename T >
+  void addProperty( const std::string& memberName, std::function< ValueOrError< T >() > getter, std::function< ValueOrError< void >( T ) > setter )
+  {
+    properties.push_back( {} );
+    auto& z = properties.back();
+    z.memberName = memberName;
+    z.typeSignature = detail::signature< T >::sig();
+    if( getter )
+    {
+      detail::CallId getterId;
+      z.getterId = getterId;
+      DBUS_DEBUG( "call %d: property %s (get) type %s", getterId.id, memberName.c_str(), detail::signature< T >::name().c_str() );
+      z.getCallback = [=]( const Eldbus_Message* src, Eldbus_Message_Iter* dst ) -> ValueOrError< void > {
+        detail::emitNotification( eldbus_message_sender_get( src ),
+                                  eldbus_message_path_get( src ), interfaceName.c_str(), memberName.c_str(), DBusActionType::GETTER_RESPONSE );
+        try
+        {
+          auto v = detail::apply( getter, std::tuple<>{} );
+          if( v )
+          {
+            detail::signature< T >::set( dst, std::get< 0 >( v.getValues() ) );
+            DBUS_DEBUG( "call %d: success", getterId.id );
+            return Success{};
+          }
+          DBUS_DEBUG( "call %d: failed: %s", getterId.id, v.getError().message.c_str() );
+          return v.getError();
+        }
+        catch( std::exception& e )
+        {
+          return Error{std::string( "unhandled exception (" ) + e.what() + ")"};
+        }
+        catch( ... )
+        {
+          return Error{"unhandled exception"};
+        }
+      };
+    }
+    if( setter )
+    {
+      detail::CallId setterId;
+      z.setterId = setterId;
+      DBUS_DEBUG( "call %d: property %s (set) type %s", setterId.id, memberName.c_str(), detail::signature< T >::name().c_str() );
+      z.setCallback = [=]( const Eldbus_Message* src, Eldbus_Message_Iter* src_iter ) -> ValueOrError< void > {
+        detail::emitNotification( eldbus_message_sender_get( src ),
+                                  eldbus_message_path_get( src ), interfaceName.c_str(), memberName.c_str(), DBusActionType::SETTER_RESPONSE );
+        std::tuple< T > value;
+        auto src_signature = eldbus_message_iter_signature_get( src_iter );
+        if( detail::signature< T >::get( src_iter, std::get< 0 >( value ) ) )
+        {
+          try
+          {
+            auto v = detail::apply( setter, std::move( value ) );
+            if( v )
+            {
+              DBUS_DEBUG( "call %d: success", setterId.id );
+              return Success{};
+            }
+            DBUS_DEBUG( "call %d: failed: %s", setterId.id, v.getError().message.c_str() );
+            free( src_signature );
+            return v.getError();
+          }
+          catch( std::exception& e )
+          {
+            return Error{std::string( "unhandled exception (" ) + e.what() + ")"};
+          }
+          catch( ... )
+          {
+            return Error{"unhandled exception"};
+          }
+        }
+        DBUS_DEBUG( "call %d: failed to unpack values, got signature '%s', expected '%s'", setterId.id,
+                    src_signature, detail::signature< T >::sig().c_str() );
+        return Error{"call " + std::to_string( setterId.id ) + ": failed to unpack values, got signature '" +
+                     src_signature + "', expected '" + detail::signature< T >::sig() + "'"};
+      };
+    }
+  }
+
+  /**
+     * @brief adds new signal to the interface
+     *
+     * Template types ARGS defines values, which will be emited with the signal
+     *
+     * @param memberName name of the method
+     */
+  template < typename... ARGS >
+  SignalId addSignal( const std::string& memberName )
+  {
+    detail::CallId callId;
+    signals.push_back( {} );
+    auto& z = signals.back();
+    z.memberName = memberName;
+    z.args = detail::EldbusArgGenerator_Args< void( ARGS... ) >::get( strings );
+    z.id = callId;
+    DBUS_DEBUG( "call %d: signal %s", callId.id, memberName.c_str() );
+    return SignalId{callId};
+  }
+
+private:
+  /// \cond
+  std::vector< MethodInfo > methods;
+  std::vector< PropertyInfo > properties;
+  std::vector< SignalInfo > signals;
+  std::string interfaceName;
+  detail::StringStorage strings;
+
+  template < typename T >
+  std::function< Eldbus_Message*( const Eldbus_Message* msg ) > construct( detail::CallId callId,
+                                                                           typename detail::dbus_interface_traits< T >::SyncCB callback )
+  {
+    using VEArgs = typename detail::dbus_interface_traits< T >::VEArgs;
+    return [=]( const Eldbus_Message* msg ) -> Eldbus_Message* {
+      DBUS_DEBUG( "call %d: entering", callId.id );
+      detail::emitNotification( eldbus_message_sender_get( msg ),
+                                eldbus_message_path_get( msg ), interfaceName.c_str(), eldbus_message_member_get( msg ), DBusActionType::METHOD_RESPONSE );
+      Eldbus_Message* ret = nullptr;
+      auto args = detail::unpackValues< VEArgs >( callId, msg );
+      if( args )
+      {
+        try
+        {
+          auto v = detail::apply( callback, std::move( args.getValues() ) );
+          if( v )
+          {
+            DBUS_DEBUG( "call %d: success", callId.id );
+            ret = eldbus_message_method_return_new( msg );
+            packValues( callId, ret, v );
+          }
+          else
+          {
+            DBUS_DEBUG( "call %d: failed: %s", callId.id, v.getError().message.c_str() );
+            ret = eldbus_message_error_new( msg, "org.freedesktop.DBus.Error.Failed", v.getError().message.c_str() );
+          }
+        }
+        catch( std::exception& e )
+        {
+          auto txt = std::string( "unhandled exception (" ) + e.what() + ")";
+          DBUS_DEBUG( "call %d: failed: %s", callId.id, txt.c_str() );
+          ret = eldbus_message_error_new( msg, "org.freedesktop.DBus.Error.Failed", txt.c_str() );
+        }
+        catch( ... )
+        {
+          DBUS_DEBUG( "call %d: failed: %s", callId.id, "unhandled exception" );
+          ret = eldbus_message_error_new( msg, "org.freedesktop.DBus.Error.Failed", "unhandled exception" );
+        }
+      }
+      else
+      {
+        std::ostringstream err;
+        err << "expected signature '" << detail::signature< VEArgs >::sig() << "', got '" << eldbus_message_signature_get( msg ) << "'";
+        auto str = err.str();
+        DBUS_DEBUG( "call %d: failed: %s", callId.id, str.c_str() );
+        ret = eldbus_message_error_new( msg, "org.freedesktop.DBus.Error.InvalidArgs", str.c_str() );
+      }
+      return ret;
+    };
+  }
+  /// \endcond
+};
+
+/**
+  * @brief Class representing server's end of DBUS connection
+  *
+  * Allows listening (synchronously and asynchronosly) on methods on selected interface
+  * Allows listening (synchronously and asynchronosly) on setting / getting properties.
+  * Allows emiting signals.
+  */
+class DBusServer : private detail::EldbusProxyBase
+{
+public:
+  /**
+     * @brief Constructs non-connected dbus server.
+     */
+  DBusServer() = default;
+
+  /**
+     * @brief Constructs dbus server on either system or user dbus connection.
+     */
+
+  DBusServer( ConnectionType tp );
+  /**
+     * @brief Constructs dbus server on connection from getDBusConnectionByType
+     */
+
+  DBusServer( const std::shared_ptr< DBus::EldbusConnection >& conn );
+  /**
+     * @brief Destructor
+     *
+     * Destructor will properly destroy everything. Destructor will cancel
+     * pending replies.
+     */
+  ~DBusServer() = default;
+
+  DBusServer( const DBusServer& ) = delete;
+  DBusServer( DBusServer&& ) = default;
+
+  DBusServer& operator=( DBusServer&& ) = default;
+  DBusServer& operator=( const DBusServer& ) = delete;
+
+  /**
+     * @brief Registers interface on given path name
+     *
+     * @param pathName path object to register interface on.
+     * @param dscr
+     * @param fallback
+     */
+  void addInterface( const std::string& pathName, DBusInterfaceDescription& dscr, bool fallback = false );
+
+  /**
+     * @brief Gets bus name of the current connection (must be connected)
+     */
+  std::string getBusName() const;
+
+  /**
+     * @brief Returns connection object for this dbus server object
+     *
+     * @return connection object
+     */
+  std::shared_ptr< DBus::EldbusConnection > getConnection();
+
+  /**
+     * @brief Emits signal
+     *
+     * You must pass identifier of the signal, got as result of calling DBusInterfaceDescription::addSignal.
+     * Types of the arguments must match EXACTLY types used to call addSignal.
+     *
+     * @param signal identifier of the signal
+     * @param args values to emit
+     */
+  template < typename... ARGS >
+  void emit( DBusInterfaceDescription::SignalId signal, const ARGS&... args )
+  {
+    auto it = signalData.find( signal.id.id );
+    if( it != signalData.end() )
+    {
+      auto msg = eldbus_service_signal_new( it->second.first, it->second.second );
+      detail::packValues( signal.id, msg, args... );
+      eldbus_service_signal_send( it->second.first, msg );
+    }
+    else
+    {
+      DBUS_DEBUG( "signal %d not found", signal.id.id );
+    }
+  }
+
+  /**
+     * @brief Emits signal
+     *
+     * Emits signal based only on data passed to the function
+     *
+     * @param signal identifier of the signal
+     * @param args values to emit
+     */
+  template < typename... ARGS >
+  void emit2( const std::string& path, const std::string& interfaceName,
+              const std::string& signalName, const ARGS&... args )
+  {
+    auto msg = eldbus_message_signal_new( path.c_str(), interfaceName.c_str(), signalName.c_str() );
+    detail::CallId id;
+    detail::packValues( id, msg, args... );
+    eldbus_connection_send( connection->get(), msg, nullptr, nullptr, -1 );
+  }
+  /**
+     * @brief Returns current object path, when handling call to property / method
+     *
+     * User can call this function from inside callback used to handle property / method calls.
+     * It will retrieve object's path used in the call. Note, that in asynchronous handling
+     * of those calls user need to retrieve and store the current object / current connection
+     * as the value will change at the moment user's callback handling will exit. For example:
+     * \code{.cpp}
+     * DBusInterfaceDescription interface{"name"};
+     * auto handler_later = [](std::function<void(void)> done_cb) {
+     *   // process something later on
+     *   DBusServer::getCurrentObjectPath(); // this will return empty string
+     * };
+     * interface.addAsyncMethod<void()>("m", [=](std::function<void(void)> done_cb) {
+     *   DBusServer::getCurrentObjectPath(); // this will current object's path
+     *
+     *   // do some processing later on and call done_cb, when it's done
+     *   register_to_call_sometime_later_on(std::move(done_cb));
+     * };
+     * \endcode
+     */
+  static std::string getCurrentObjectPath();
+
+  /**
+     * @brief Returns current connection object, when handling call to property / method
+     *
+     * User can call this function from inside callback used to handle property / method calls.
+     * It will retrieve object's path used in the call. Note, that in asynchronous handling
+     * of those calls user need to retrieve and store the current object / current connection
+     * as the value will change at the moment user's callback handling will exit. For example:
+     * \code{.cpp}
+     * DBusInterfaceDescription interface{"name"};
+     * auto handler_later = [](std::function<void(void)> done_cb) {
+     *   // process something later on
+     *   DBusServer::getCurrentObjectPath(); // this will return empty string
+     * };
+     * interface.addAsyncMethod<void()>("m", [=](std::function<void(void)> done_cb) {
+     *   DBusServer::getCurrentObjectPath(); // this will current object's path
+     *
+     *   // do some processing later on and call done_cb, when it's done
+     *   register_to_call_sometime_later_on(std::move(done_cb));
+     * };
+     * \endcode
+     */
+  static std::shared_ptr< DBus::EldbusConnection > getCurrentConnection();
+
+private:
+  /// \cond
+  std::shared_ptr< DBus::EldbusConnection > connection;
+  detail::CallOnDestructionList destructors;
+  std::unordered_map< unsigned int, std::pair< const Eldbus_Service_Interface*, unsigned int > > signalData;
+  /// \endcond
+};
+
+template < typename T >
+void DBusInterfaceDescription::addAsyncMethod( const std::string& memberName, typename detail::dbus_interface_traits< T >::AsyncCB callback )
+{
+  detail::CallId callId;
+  MethodInfo mi;
+  methods.push_back( std::move( mi ) );
+  auto& z = methods.back();
+  z.in = detail::EldbusArgGenerator_Args< T >::get( strings );
+  z.out = detail::EldbusArgGenerator_ReturnType< T >::get( strings );
+  z.memberName = memberName;
+  DBUS_DEBUG( "call %d: method %s, in %s, out %s", callId.id, memberName.c_str(),
+              detail::EldbusArgGenerator_Args< T >::name().c_str(),
+              detail::EldbusArgGenerator_ReturnType< T >::name().c_str() );
+  using VEArgs = typename detail::dbus_interface_traits< T >::VEArgs;
+  z.callback = [=]( const Eldbus_Message* msg ) -> Eldbus_Message* {
+    detail::emitNotification( eldbus_message_sender_get( msg ),
+                              eldbus_message_path_get( msg ), interfaceName.c_str(), memberName.c_str(), DBusActionType::METHOD_RESPONSE );
+    struct CallState
+    {
+      bool replyRunning = true;
+      Eldbus_Message* reply = nullptr;
+      EldbusMessageCallbackHandle message;
+    };
+    auto callState = std::make_shared< CallState >();
+    callState->message.reset( eldbus_message_ref( const_cast< Eldbus_Message* >( msg ) ) );
+    auto connection = DBusServer::getCurrentConnection();
+    auto retCallback = [=]( typename detail::dbus_interface_traits< T >::Ret v ) {
+      if( v )
+      {
+        callState->reply = eldbus_message_method_return_new( callState->message.get() );
+        packValues( callId, callState->reply, v );
+      }
+      else
+      {
+        DBUS_DEBUG( "call %d: failed: %s", callId.id, v.getError().message.c_str() );
+        callState->reply = eldbus_message_error_new( callState->message.get(), "org.freedesktop.DBus.Error.Failed", v.getError().message.c_str() );
+      }
+      if( !callState->replyRunning )
+      {
+        eldbus_connection_send( connection->get(), callState->reply, NULL, NULL, -1 );
+      }
+    };
+    Eldbus_Message* ret = nullptr;
+    auto args = detail::unpackValues< VEArgs >( callId, msg );
+    if( args )
+    {
+      auto error = [&]( const std::string& txt ) {
+        if( !callState->reply )
+        {
+          DBUS_DEBUG( "call %d: failed: %s", callId.id, txt.c_str() );
+          callState->reply = eldbus_message_error_new( callState->message.get(), "org.freedesktop.DBus.Error.Failed", txt.c_str() );
+        }
+      };
+      try
+      {
+        detail::apply( callback, std::move( retCallback ), std::move( args.getValues() ) );
+      }
+      catch( std::exception& e )
+      {
+        error( std::string( "unhandled exception (" ) + e.what() + ")" );
+      }
+      catch( ... )
+      {
+        error( "unhandled exception" );
+      }
+
+      callState->replyRunning = false;
+      ret = callState->reply;
+    }
+    else
+    {
+      std::ostringstream err;
+      err << "expected signature '" << detail::signature< VEArgs >::sig() << "', got '" << eldbus_message_signature_get( msg ) << "'";
+      auto str = err.str();
+      ret = eldbus_message_error_new( msg, "org.freedesktop.DBus.Error.InvalidArgs", str.c_str() );
+    }
+    return ret;
+  };
+
+  z.id = callId;
+}
+
+/// \cond
+std::shared_ptr< EldbusConnection > getDBusConnectionByType( ConnectionType tp );
+std::shared_ptr< EldbusConnection > getDBusConnectionByName( const std::string& name );
+std::string getConnectionName( const std::shared_ptr< EldbusConnection >& );
+/// \endcond
+}
+
+/// \cond
+namespace std
+{
+template < size_t INDEX, typename... ARGS >
+inline auto get( DBus::ValueOrError< ARGS... >& v ) -> decltype( std::get< INDEX >( v.getValues() ) ) &
+{
+  return std::get< INDEX >( v.getValues() );
+}
+template < size_t INDEX, typename... ARGS >
+inline auto get( const DBus::ValueOrError< ARGS... >& v ) -> decltype( std::get< INDEX >( v.getValues() ) )
+{
+  return std::get< INDEX >( v.getValues() );
+}
+}
+/// \endcond
+
+#endif
diff --git a/dali/dali-bridge/src/Optional.hpp b/dali/dali-bridge/src/Optional.hpp
new file mode 100755 (executable)
index 0000000..d4401fe
--- /dev/null
@@ -0,0 +1,281 @@
+/*
+ * Copyright 2017  Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef OPTIONAL_HPP
+#define OPTIONAL_HPP
+
+/**
+ * Minimalistic implementation of standard library std::optional (c++17) for c++11 compiler.
+ *
+ * After project conversion to C++17 standard, this template class will be deleted and
+ * Optional will point to std::optional.
+ *
+ * Allowed operations (note, to make code simplier, than original, value class must have accessible copy and move constructor):
+ *  - constructing empty (valueless) object
+ *  - copying Optional (with and without value)
+ *  - moving Optional (with and without value)
+ *  - querying, if Optional has value (via explicit operator bool), for example:
+ *        Optional<int> v = ...;
+ *        if (v) ... // if v has value, then do something
+ *  - accessing value (via operator *), for example:
+ *        Optional<int> v = ...;
+ *        auto z = *v; // z now has the same int, as v (copied)
+ *        auto &y = *v; // y now has REFERENCE to int inside v, so modifying y modifies v
+ */
+
+#include <cassert>
+#include <new>
+#include <type_traits>
+#include <utility>
+
+template < typename A >
+class Optional
+{
+  /// \cond
+  union
+  {
+    A place;
+  };
+  bool hasValue = false;
+  /// \endcond
+public:
+  /**
+   * @brief Empty constructor.
+   * Creates empty Optional object, which will be false in boolean context.
+   * So:
+   *   \code{.cpp}
+   *   Optional<int> o;
+   *   if (o) printf("1\n");
+   *   \endcode
+   * won't print 1.
+   */
+  Optional() {}
+
+  /**
+   * @brief Single element constructor, when implicit convertion can be applied.
+   *
+   * This constructor will be selected, when type of given argument (U) is
+   * implicitly convertable to expected type A. In other words following
+   * code must be valid:
+   *   \code{.cpp}
+   *   A foo() {
+   *     return U();
+   *   }
+   *   \endcode
+   *
+   * @param a value held by Optional object will be initialized from a.
+   */
+  template < typename U = A, typename std::enable_if<
+                                 std::is_convertible< U&&, A >::value &&
+                                     std::is_constructible< A, U&& >::value &&
+                                     !std::is_same< typename std::decay< U >::type, Optional< A > >::value,
+                                 int* >::type = nullptr >
+  constexpr Optional( U&& a )
+      : place( std::forward< U >( a ) ), hasValue( true )
+  {
+  }
+
+  /**
+   * @brief Single element constructor, when only explicit convertion can be applied.
+   *
+   * This constructor will be selected, when type of given argument (U) is
+   * convertable to expected type A.
+   *
+   * @param a value held by Optional object will be initialized from a.
+   */
+  template < typename U = A, typename std::enable_if<
+                                 !std::is_convertible< U&&, A >::value &&
+                                     std::is_constructible< A, U&& >::value &&
+                                     !std::is_same< typename std::decay< U >::type, Optional< A > >::value,
+                                 int* >::type = nullptr >
+  explicit constexpr Optional( U&& a )
+      : place( std::forward< U >( a ) ), hasValue( true )
+  {
+  }
+
+  /**
+   * @brief Copy constructor.
+   *
+   * @param v Optional value to copy from. Will cause to copy data held by object v,
+   * if v has data.
+   */
+  Optional( const Optional& v ) : hasValue( v.hasValue )
+  {
+    if( hasValue )
+      new( &place ) A( v.place );
+  }
+
+  /**
+   * @brief Move constructor.
+   *
+   * @param v Optional value to copy from. Will move data help by v, if any.
+   * After construction \code{.cpp} bool(v) \endcode will be false.
+   */
+  Optional( Optional&& v ) : hasValue( v.hasValue )
+  {
+    if( hasValue )
+      new( &place ) A( std::move( v.place ) );
+  }
+
+  /**
+   * @brief Destructor.
+   */
+  ~Optional()
+  {
+    if( hasValue )
+    {
+      place.~A();
+    }
+  }
+
+  /**
+   * @brief Explicit bool operator
+   *
+   * Will return true if and only if object is helding data.
+   */
+  explicit operator bool() const
+  {
+    return hasValue;
+  }
+
+  /**
+   * @brief Accessor (*) operator
+   *
+   * Will return modifiable reference to held object. Will assert, if not object is held.
+   */
+  A& operator*()
+  {
+    assert( hasValue );
+    return place;
+  }
+
+  /**
+   * @brief Accessor (*) const operator
+   *
+   * Will return const reference to held object. Will assert, if not object is held.
+   */
+  const A& operator*() const
+  {
+    assert( hasValue );
+    return place;
+  }
+
+  /**
+   * @brief Accessor (->) operator
+   *
+   * Will return pointer to held object allowing access to the value's members.
+   * Will assert, if not object is held.
+   */
+  A* operator->()
+  {
+    assert( hasValue );
+    return &place;
+  }
+
+  /**
+   * @brief Accessor (->) operator
+   *
+   * Will return pointer to (const) held object allowing access to the value's members.
+   * Will assert, if not object is held.
+   */
+  const A* operator->() const
+  {
+    assert( hasValue );
+    return &place;
+  }
+
+  /**
+   * @brief Assignment operator
+   *
+   * Will copy held value from v, if any.
+   *
+   * @param v Value to copy from
+   */
+  Optional& operator=( const Optional& v )
+  {
+    if( this != &v )
+    {
+      if( hasValue != v.hasValue )
+      {
+        if( v.hasValue )
+          new( &place ) A( v.place );
+        else
+          place.~A();
+        hasValue = v.hasValue;
+      }
+      else if( hasValue )
+      {
+        place = v.place;
+      }
+    }
+    return *this;
+  }
+
+  /**
+   * @brief Assignment move operator
+   *
+   * Will move held value from v, if any. In all cases v won't held a value
+   * after assignment is done.
+   *
+   * @param v Value to copy from
+   */
+  Optional& operator=( Optional&& v )
+  {
+    if( this != &v )
+    {
+      if( hasValue != v.hasValue )
+      {
+        if( v.hasValue )
+          new( &place ) A( std::move( v.place ) );
+        else
+          place.~A();
+        hasValue = v.hasValue;
+      }
+      else if( hasValue )
+      {
+        place = std::move( v.place );
+      }
+    }
+    return *this;
+  }
+
+  /**
+   * @brief Assignment operator from value of type held.
+   *
+   * Will initialize held value from given parameter a.
+   * Type of the parameter must be the same (barring cv convertions),
+   * as the type of the value held.
+   *
+   * @param a Value to copy from
+   */
+  template < class U, class = typename std::enable_if<
+                          std::is_same< typename std::remove_reference< U >::type, A >::value &&
+                          std::is_constructible< A, U >::value &&
+                          std::is_assignable< A&, U >::value >::type >
+  Optional& operator=( U&& a )
+  {
+    if( hasValue )
+      place = std::forward< U >( a );
+    else
+    {
+      hasValue = true;
+      new( &place ) A( std::forward< U >( a ) );
+    }
+    return *this;
+  }
+};
+
+#endif
diff --git a/dali/dali-bridge/src/dbusLocators.hpp b/dali/dali-bridge/src/dbusLocators.hpp
new file mode 100644 (file)
index 0000000..9b34bbe
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2017  Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef DBUS_LOCATORS_HPP
+#define DBUS_LOCATORS_HPP
+
+namespace dbusLocators
+{
+namespace callmgr
+{
+static constexpr const char* BUS = "org.tizen.callmgr";
+static constexpr const char* OBJ_PATH = "/org/tizen/callmgr";
+static constexpr const char* INTERFACE = "org.tizen.callmgr";
+}
+
+namespace accessibilityEMod
+{
+static constexpr const char* BUS = "org.enlightenment.wm-screen-reader";
+static constexpr const char* OBJ_PATH = "/org/tizen/GestureNavigation";
+static constexpr const char* INTERFACE = "org.tizen.GestureNavigation";
+
+static constexpr const char* ACCESSORIES_SP_ENABLED = "AccessoriesSwitchProviderEnabled";
+static constexpr const char* KEY_DOWN_SIGNAL = "KeyDown";
+static constexpr const char* KEY_UP_SIGNAL = "KeyUp";
+
+static constexpr const char* SCREEN_SP_ENABLED = "ScreenSwitchProviderEnabled";
+static constexpr const char* MOUSE_DOWN_SIGNAL = "MouseDown";
+static constexpr const char* MOUSE_UP_SIGNAL = "MouseUp";
+
+static constexpr const char* BACK_BUTTON_INTERCEPTION_ENABLED = "BackButtonInterceptionEnabled";
+static constexpr const char* BACK_BUTTON_DOWN_SIGNAL = "BackButtonDown";
+static constexpr const char* BACK_BUTTON_UP_SIGNAL = "BackButtonUp";
+}
+
+namespace freeDesktop
+{
+static constexpr const char* BUS = "org.freedesktop.DBus";
+static constexpr const char* OBJ_PATH = "/org/freedesktop/DBus";
+static constexpr const char* INTERFACE = "org.freedesktop.DBus";
+static constexpr const char* PROPERTIES_INTERFACE = "org.freedesktop.DBus.Properties";
+static constexpr const char* GET_CONNECTION_UNIX_PROCESS_ID = "GetConnectionUnixProcessID";
+static constexpr const char* SET = "Set";
+static constexpr const char* GET = "Get";
+}
+
+namespace windowManager
+{
+static constexpr const char* BUS = "org.enlightenment.wm";
+static constexpr const char* OBJ_PATH = "/org/enlightenment/wm";
+static constexpr const char* INTERFACE = "org.enlightenment.wm.proc";
+static constexpr const char* GET_VISIBLE_WIN_INFO = "GetVisibleWinInfo";
+static constexpr const char* GET_FOCUS_PROC = "GetFocusProc";
+}
+
+namespace atspi
+{
+static constexpr const char* BUS = "org.a11y.Bus";
+static constexpr const char* OBJ_PATH = "/org/a11y/bus";
+static constexpr const char* BUS_INTERFACE = "org.a11y.Bus";
+static constexpr const char* STATUS_INTERFACE = "org.a11y.Status";
+
+static constexpr const char* GET_ADDRESS = "GetAddress";
+static constexpr const char* IS_ENABLED = "IsEnabled";
+static constexpr const char* GET_ATTRIBUTES = "GetAttributes";
+static constexpr const char* DO_ACTION_NAME = "DoActionName";
+static constexpr const char* PARENT = "Parent";
+static constexpr const char* GET_MATCHES = "GetMatches";
+static constexpr const char* GET_INDEX_IN_PARENT = "GetIndexInParent";
+static constexpr const char* SELECT_CHILD = "SelectChild";
+static constexpr const char* NAME = "Name";
+static constexpr const char* GET_ROLE = "GetRole";
+static constexpr const char* CHILD_COUNT = "ChildCount";
+static constexpr const char* GET_CHILD_AT_INDEX = "GetChildAtIndex";
+static constexpr const char* GET_STATE = "GetState";
+static constexpr const char* GET_RELATION_SET = "GetRelationSet";
+static constexpr const char* GET_EXTENTS = "GetExtents";
+static constexpr const char* CURRENT_VALUE = "CurrentValue";
+static constexpr const char* MAXIMUM_VALUE = "MaximumValue";
+static constexpr const char* MINIMUM_VALUE = "MinimumValue";
+static constexpr const char* GET_INTERFACES = "GetInterfaces";
+static constexpr const char* GET_NAVIGABLE_AT_POINT = "GetNavigableAtPoint";
+}
+}
+
+#endif
diff --git a/dali/devel-api/adaptor-framework/accessibility.h b/dali/devel-api/adaptor-framework/accessibility.h
new file mode 100644 (file)
index 0000000..15881b0
--- /dev/null
@@ -0,0 +1,248 @@
+#ifndef ATSPI_BRIDGE_HPP
+#define ATSPI_BRIDGE_HPP
+
+#include <dali/public-api/actors/actor.h>
+#include <dali/public-api/adaptor-framework/accessibility.h>
+
+#include <atomic>
+#include <bitset>
+#include <exception>
+#include <functional>
+#include <memory>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+namespace Dali
+{
+namespace Accessibility
+{
+class Accessible;
+class Text;
+class Value;
+class Component;
+class Collection;
+class Action;
+
+using ObjectsMapType = std::unordered_map< unsigned int, Accessible* >;
+
+struct DALI_IMPORT_API Bridge
+{
+  enum class Visibility
+  {
+    hidden,
+    thisThreadOnly,
+    allThreads
+  };
+  enum class ForceUpResult
+  {
+    justStarted,
+    alreadyUp
+  };
+  virtual ~Bridge() = default;
+
+  virtual const std::string& GetBusName() const = 0;
+  virtual void SetApplicationChild( Accessible* ) = 0;
+  virtual void SetApplicationName( std::string ) = 0;
+  virtual Accessible* GetApplication() const = 0;
+  virtual Accessible* FindByPath( const std::string& ) const = 0;
+  virtual void ApplicationShown() = 0;
+  virtual void ApplicationHidden() = 0;
+  virtual void Initialize() = 0;
+  virtual ForceUpResult ForceUp()
+  {
+    if( data )
+      return ForceUpResult::alreadyUp;
+    data = std::make_shared< Data >();
+    data->bridge = this;
+    return ForceUpResult::justStarted;
+  }
+  virtual void ForceDown()
+  {
+    data = {};
+  }
+  bool IsUp() const { return bool(data); }
+
+  virtual void EmitStateChanged( Accessible* obj, State state, int val1, int val2 = 0 ) = 0;
+  virtual void Emit( Accessible* obj, WindowEvent we, unsigned int detail1 = 0 ) = 0;
+  virtual Consumed Emit( KeyEventType type, unsigned int keyCode, const std::string& keyName, unsigned int timeStamp, bool isText ) = 0;
+  void MakePublic( Visibility );
+
+  static Bridge* GetCurrentBridge();
+
+protected:
+  struct Data
+  {
+    ObjectsMapType objects;
+    std::atomic< unsigned int > objectId;
+    std::string busName;
+    Accessible* root = nullptr;
+    Bridge* bridge = nullptr;
+  };
+  std::shared_ptr< Data > data;
+  friend class Accessible;
+
+  void RegisterOnBridge( Accessible* );
+  void SetIsOnRootLevel( Accessible* );
+};
+
+inline bool IsUp()
+{
+  return Bridge::GetCurrentBridge()->IsUp();
+}
+
+class DALI_IMPORT_API Accessible
+{
+protected:
+  Accessible();
+
+  Accessible( const Accessible& ) = delete;
+  Accessible( Accessible&& ) = delete;
+
+  Accessible& operator=( const Accessible& ) = delete;
+  Accessible& operator=( Accessible&& ) = delete;
+
+public:
+  virtual ~Accessible();
+
+  void EmitShowing( bool showing );
+  void EmitVisible( bool visible );
+  void EmitHighlighted( bool set );
+  void Emit( WindowEvent we, unsigned int detail1 = 0 );
+
+  virtual std::string GetName() = 0;
+  virtual std::string GetDescription() = 0;
+  virtual Accessible* GetParent() = 0;
+  virtual size_t GetChildCount() = 0;
+  virtual std::vector< Accessible* > GetChildren();
+  virtual Accessible* GetChildAtIndex( size_t index ) = 0;
+  virtual size_t GetIndexInParent() = 0;
+  virtual Role GetRole() = 0;
+  virtual std::string GetRoleName();
+  virtual std::string GetLocalizedRoleName();
+  virtual States GetStates() = 0;
+  virtual Attributes GetAttributes() = 0;
+  virtual bool IsProxy();
+  virtual Address GetAddress();
+
+  std::vector< std::string > GetInterfaces();
+  bool GetIsOnRootLevel() const { return isOnRootLevel; }
+
+  static void RegisterControlAccessibilityGetter( std::function< Accessible*( Dali::Actor ) > );
+  static Accessible* Get( Dali::Actor actor );
+
+protected:
+  std::shared_ptr< Bridge::Data > GetBridgeData();
+
+private:
+  friend class Bridge;
+
+  std::weak_ptr< Bridge::Data > bridgeData;
+  ObjectsMapType::iterator it;
+  bool isOnRootLevel = false;
+};
+
+class DALI_IMPORT_API Action : public virtual Accessible
+{
+public:
+  virtual std::string GetActionName( size_t index ) = 0;
+  virtual std::string GetLocalizedActionName( size_t index ) = 0;
+  virtual std::string GetActionDescription( size_t index ) = 0;
+  virtual std::string GetActionKeyBinding( size_t index ) = 0;
+  virtual size_t GetActionCount() = 0;
+  virtual bool DoAction( size_t index ) = 0;
+};
+
+class DALI_IMPORT_API Collection : public virtual Accessible
+{
+public:
+};
+
+class DALI_IMPORT_API Component : public virtual Accessible
+{
+public:
+  virtual Rectangle GetExtents( CoordType ctype ) = 0;
+  virtual ComponentLayer GetLayer() = 0;
+  virtual int GetMdiZOrder() = 0;
+  virtual bool GrabFocus() = 0;
+  virtual double GetAlpha() = 0;
+  virtual bool SetExtents( Rectangle rect, CoordType ctype ) = 0;
+  virtual bool GrabHighlight() = 0;
+  virtual bool ClearHighlight() = 0;
+  virtual int GetHighlightIndex() = 0;
+  virtual bool IsScrollable();
+  virtual Component* GetAccessibleAtPoint( Point p, CoordType ctype );
+  virtual bool Contains( Point p, CoordType ctype );
+};
+
+class DALI_IMPORT_API Value : public virtual Accessible
+{
+public:
+  virtual double GetMinimum() = 0;
+  virtual double GetCurrent() = 0;
+  virtual double GetMaximum() = 0;
+  virtual bool SetCurrent( double ) = 0;
+  virtual double GetMinimumIncrement() = 0;
+};
+
+class DALI_IMPORT_API Text : public virtual Accessible
+{
+public:
+  virtual std::string GetText( size_t startOffset, size_t endOffset ) = 0;
+  virtual size_t GetCharacterCount() = 0;
+  virtual Range GetTextAtOffset( size_t offset, TextBoundary boundary ) = 0;
+  virtual Range GetSelection( size_t selectionNum ) = 0;
+  virtual bool RemoveSelection( size_t selectionNum ) = 0;
+  virtual bool SetSelection( size_t selectionNum, size_t startOffset, size_t endOffset ) = 0;
+};
+
+class DALI_IMPORT_API EditableText : public virtual Accessible
+{
+public:
+  virtual bool CopyText( size_t startPosition, size_t endPosition ) = 0;
+  virtual bool CutText( size_t startPosition, size_t endPosition ) = 0;
+};
+
+/**
+         * @brief minimalistic, always empty Accessible object with settable address
+         *
+         * For those situations, where you want to return address in different bridge
+         * (embedding for example), but the object itself ain't planned to be used otherwise.
+         * This object has null parent, no children, empty name and so on
+         */
+class DALI_IMPORT_API EmptyAccessibleWithAddress : public virtual Accessible
+{
+public:
+  EmptyAccessibleWithAddress() = default;
+  EmptyAccessibleWithAddress( Address address ) : address( std::move( address ) ) {}
+
+  void SetAddress( Address address ) { this->address = std::move( address ); }
+
+  std::string GetName() override { return ""; }
+  std::string GetDescription() override { return ""; }
+  Accessible* GetParent() override { return nullptr; }
+  size_t GetChildCount() override { return 0; }
+  std::vector< Accessible* > GetChildren() override { return {}; }
+  Accessible* GetChildAtIndex( size_t index ) override
+  {
+    throw AccessibleError{"out of bounds index (" + std::to_string( index ) + ") - no children"};
+  }
+  size_t GetIndexInParent() override { return static_cast< size_t >( -1 ); }
+  Role GetRole() override { return {}; }
+  std::string GetRoleName() override;
+  States GetStates() override { return {}; }
+  Attributes GetAttributes() override { return {}; }
+  Address GetAddress() override
+  {
+    return address;
+  }
+
+private:
+  Address address;
+};
+
+std::shared_ptr< Bridge > CreateBridge();
+}
+}
+
+#endif
old mode 100644 (file)
new mode 100755 (executable)
index 696291a..e62fef3
@@ -67,8 +67,9 @@ devel_api_adaptor_framework_header_files = \
   $(adaptor_devel_api_dir)/adaptor-framework/key-extension-plugin.h \
   $(adaptor_devel_api_dir)/adaptor-framework/virtual-keyboard.h \
   $(adaptor_devel_api_dir)/adaptor-framework/physical-keyboard.h \
-  $(adaptor_devel_api_dir)/adaptor-framework/key-devel.h
+  $(adaptor_devel_api_dir)/adaptor-framework/key-devel.h \
+  $(adaptor_devel_api_dir)/adaptor-framework/accessibility.h
+
 devel_api_text_abstraction_src_files = \
    $(adaptor_devel_api_dir)/text-abstraction/bidirectional-support.cpp \
    $(adaptor_devel_api_dir)/text-abstraction/font-client.cpp \
diff --git a/dali/internal/accessibility/accessibility-impl.cpp b/dali/internal/accessibility/accessibility-impl.cpp
new file mode 100644 (file)
index 0000000..7e6fb7d
--- /dev/null
@@ -0,0 +1,646 @@
+#include <dali/devel-api/adaptor-framework/accessibility.h>
+#include <dali/integration-api/debug.h>
+#include <dali/public-api/actors/actor.h>
+#include <dali/public-api/actors/layer.h>
+#include <dali/public-api/common/stage.h>
+#include <dali/public-api/object/base-object.h>
+#include <dali/public-api/object/object-registry.h>
+#include <dali/public-api/object/type-info.h>
+#include <dali/public-api/object/type-registry-helper.h>
+
+using namespace Dali::Accessibility;
+
+std::string EmptyAccessibleWithAddress::GetRoleName()
+{
+  return "";
+}
+
+std::string Accessible::GetLocalizedRoleName()
+{
+  return GetRoleName();
+}
+
+std::string Accessible::GetRoleName()
+{
+  switch( GetRole() )
+  {
+    case Role::Invalid:
+    {
+      return "invalid";
+    }
+    case Role::AcceleratorLabel:
+    {
+      return "accelerator label";
+    }
+    case Role::Alert:
+    {
+      return "alert";
+    }
+    case Role::Animation:
+    {
+      return "animation";
+    }
+    case Role::Arrow:
+    {
+      return "arrow";
+    }
+    case Role::Calendar:
+    {
+      return "calendar";
+    }
+    case Role::Canvas:
+    {
+      return "canvas";
+    }
+    case Role::CheckBox:
+    {
+      return "check box";
+    }
+    case Role::CheckMenuItem:
+    {
+      return "check menu item";
+    }
+    case Role::ColorChooser:
+    {
+      return "color chooser";
+    }
+    case Role::ColumnHeader:
+    {
+      return "column header";
+    }
+    case Role::ComboBox:
+    {
+      return "combo box";
+    }
+    case Role::DateEditor:
+    {
+      return "date editor";
+    }
+    case Role::DesktopIcon:
+    {
+      return "desktop icon";
+    }
+    case Role::DesktopFrame:
+    {
+      return "desktop frame";
+    }
+    case Role::Dial:
+    {
+      return "dial";
+    }
+    case Role::Dialog:
+    {
+      return "dialog";
+    }
+    case Role::DirectoryPane:
+    {
+      return "directory pane";
+    }
+    case Role::DrawingArea:
+    {
+      return "drawing area";
+    }
+    case Role::FileChooser:
+    {
+      return "file chooser";
+    }
+    case Role::Filler:
+    {
+      return "filler";
+    }
+    case Role::FocusTraversable:
+    {
+      return "focus traversable";
+    }
+    case Role::FontChooser:
+    {
+      return "font chooser";
+    }
+    case Role::Frame:
+    {
+      return "frame";
+    }
+    case Role::GlassPane:
+    {
+      return "glass pane";
+    }
+    case Role::HtmlContainer:
+    {
+      return "html container";
+    }
+    case Role::Icon:
+    {
+      return "icon";
+    }
+    case Role::Image:
+    {
+      return "image";
+    }
+    case Role::InternalFrame:
+    {
+      return "internal frame";
+    }
+    case Role::Label:
+    {
+      return "label";
+    }
+    case Role::LayeredPane:
+    {
+      return "layered pane";
+    }
+    case Role::List:
+    {
+      return "list";
+    }
+    case Role::ListItem:
+    {
+      return "list item";
+    }
+    case Role::Menu:
+    {
+      return "menu";
+    }
+    case Role::MenuBar:
+    {
+      return "menu bar";
+    }
+    case Role::MenuItem:
+    {
+      return "menu item";
+    }
+    case Role::OptionPane:
+    {
+      return "option pane";
+    }
+    case Role::PageTab:
+    {
+      return "page tab";
+    }
+    case Role::PageTabList:
+    {
+      return "page tab list";
+    }
+    case Role::Panel:
+    {
+      return "panel";
+    }
+    case Role::PasswordText:
+    {
+      return "password text";
+    }
+    case Role::PopupMenu:
+    {
+      return "popup menu";
+    }
+    case Role::ProgressBar:
+    {
+      return "progress bar";
+    }
+    case Role::PushButton:
+    {
+      return "push button";
+    }
+    case Role::RadioButton:
+    {
+      return "radio button";
+    }
+    case Role::RadioMenuItem:
+    {
+      return "radio menu item";
+    }
+    case Role::RootPane:
+    {
+      return "root pane";
+    }
+    case Role::RowHeader:
+    {
+      return "row header";
+    }
+    case Role::ScrollBar:
+    {
+      return "scroll bar";
+    }
+    case Role::ScrollPane:
+    {
+      return "scroll pane";
+    }
+    case Role::Separator:
+    {
+      return "separator";
+    }
+    case Role::Slider:
+    {
+      return "slider";
+    }
+    case Role::SpinButton:
+    {
+      return "spin button";
+    }
+    case Role::SplitPane:
+    {
+      return "split pane";
+    }
+    case Role::StatusBar:
+    {
+      return "status bar";
+    }
+    case Role::Table:
+    {
+      return "table";
+    }
+    case Role::TableCell:
+    {
+      return "table cell";
+    }
+    case Role::TableColumnHeader:
+    {
+      return "table column header";
+    }
+    case Role::TableRowHeader:
+    {
+      return "table row header";
+    }
+    case Role::TearoffMenuItem:
+    {
+      return "tearoff menu item";
+    }
+    case Role::Terminal:
+    {
+      return "terminal";
+    }
+    case Role::Text:
+    {
+      return "text";
+    }
+    case Role::ToggleButton:
+    {
+      return "toggle button";
+    }
+    case Role::ToolBar:
+    {
+      return "tool bar";
+    }
+    case Role::ToolTip:
+    {
+      return "tool tip";
+    }
+    case Role::Tree:
+    {
+      return "tree";
+    }
+    case Role::TreeTable:
+    {
+      return "tree table";
+    }
+    case Role::Unknown:
+    {
+      return "unknown";
+    }
+    case Role::Viewport:
+    {
+      return "viewport";
+    }
+    case Role::Window:
+    {
+      return "window";
+    }
+    case Role::Extended:
+    {
+      return "extended";
+    }
+    case Role::Header:
+    {
+      return "header";
+    }
+    case Role::Footer:
+    {
+      return "footer";
+    }
+    case Role::Paragraph:
+    {
+      return "paragraph";
+    }
+    case Role::Ruler:
+    {
+      return "ruler";
+    }
+    case Role::Application:
+    {
+      return "application";
+    }
+    case Role::Autocomplete:
+    {
+      return "autocomplete";
+    }
+    case Role::Editbar:
+    {
+      return "edit bar";
+    }
+    case Role::Embedded:
+    {
+      return "embedded";
+    }
+    case Role::Entry:
+    {
+      return "entry";
+    }
+    case Role::Chart:
+    {
+      return "chart";
+    }
+    case Role::Caption:
+    {
+      return "caution";
+    }
+    case Role::DocumentFrame:
+    {
+      return "document frame";
+    }
+    case Role::Heading:
+    {
+      return "heading";
+    }
+    case Role::Page:
+    {
+      return "page";
+    }
+    case Role::Section:
+    {
+      return "section";
+    }
+    case Role::RedundantObject:
+    {
+      return "redundant object";
+    }
+    case Role::Form:
+    {
+      return "form";
+    }
+    case Role::Link:
+    {
+      return "link";
+    }
+    case Role::InputMethodWindow:
+    {
+      return "input method window";
+    }
+    case Role::TableRow:
+    {
+      return "table row";
+    }
+    case Role::TreeItem:
+    {
+      return "tree item";
+    }
+    case Role::DocumentSpreadsheet:
+    {
+      return "document spreadsheet";
+    }
+    case Role::DocumentPresentation:
+    {
+      return "document presentation";
+    }
+    case Role::DocumentText:
+    {
+      return "document text";
+    }
+    case Role::DocumentWeb:
+    {
+      return "document web";
+    }
+    case Role::DocumentEmail:
+    {
+      return "document email";
+    }
+    case Role::Comment:
+    {
+      return "comment";
+    }
+    case Role::ListBox:
+    {
+      return "list box";
+    }
+    case Role::Grouping:
+    {
+      return "grouping";
+    }
+    case Role::ImageMap:
+    {
+      return "image map";
+    }
+    case Role::Notification:
+    {
+      return "notification";
+    }
+    case Role::InfoBar:
+    {
+      return "info bar";
+    }
+    case Role::LevelBar:
+    {
+      return "level bar";
+    }
+    case Role::TitleBar:
+    {
+      return "title bar";
+    }
+    case Role::BlockQuote:
+    {
+      return "block quote";
+    }
+    case Role::Audio:
+    {
+      return "audio";
+    }
+    case Role::Video:
+    {
+      return "video";
+    }
+    case Role::Definition:
+    {
+      return "definition";
+    }
+    case Role::Article:
+    {
+      return "article";
+    }
+    case Role::Landmark:
+    {
+      return "landmark";
+    }
+    case Role::Log:
+    {
+      return "log";
+    }
+    case Role::Marquee:
+    {
+      return "marquee";
+    }
+    case Role::Math:
+    {
+      return "math";
+    }
+    case Role::Rating:
+    {
+      return "rating";
+    }
+    case Role::Timer:
+    {
+      return "timer";
+    }
+    case Role::Static:
+    {
+      return "static";
+    }
+    case Role::MathFraction:
+    {
+      return "math fraction";
+    }
+    case Role::MathRoot:
+    {
+      return "math root";
+    }
+    case Role::Subscript:
+    {
+      return "subscript";
+    }
+    case Role::Superscript:
+    {
+      return "superscript";
+    }
+    case Role::_Count:
+    {
+      break;
+    }
+  }
+  return "";
+}
+
+void Bridge::SetIsOnRootLevel( Accessible* o )
+{
+  o->isOnRootLevel = true;
+}
+
+class NonControlAccessible : public virtual Accessible, public virtual Collection
+{
+public:
+  Dali::Actor actor;
+  bool root = false;
+
+  NonControlAccessible( Dali::Actor actor ) : actor( actor )
+  {
+    Dali::Stage stage = Dali::Stage::GetCurrent();
+    root = stage.GetRootLayer() == actor;
+  }
+
+  std::string GetName() override
+  {
+    return actor.GetName();
+  }
+  std::string GetDescription() override
+  {
+    return "";
+  }
+  Accessible* GetParent() override
+  {
+    if( GetIsOnRootLevel() )
+    {
+      auto b = GetBridgeData();
+      return b->bridge->GetApplication();
+    }
+    return Get( actor.GetParent() );
+  }
+  size_t GetChildCount() override
+  {
+    return static_cast< size_t >( actor.GetChildCount() );
+  }
+  Accessible* GetChildAtIndex( size_t index ) override
+  {
+    auto s = static_cast< size_t >( actor.GetChildCount() );
+    if( index >= s )
+      throw AccessibleError{"invalid index " + std::to_string( index ) + " for object with " + std::to_string( s ) + " children"};
+    return Get( actor.GetChildAt( static_cast< unsigned int >( index ) ) );
+  }
+  size_t GetIndexInParent() override
+  {
+    auto p = actor.GetParent();
+    if( !p )
+      return 0;
+    auto s = static_cast< size_t >( p.GetChildCount() );
+    for( auto i = 0u; i < s; ++i )
+    {
+      if( p.GetChildAt( i ) == actor )
+        return i;
+    }
+    throw AccessibleError{"actor is not a child of it's parent"};
+  }
+  Role GetRole() override
+  {
+    return root ? Role::Window : Role::RedundantObject;
+  }
+  States GetStates() override
+  {
+    States s;
+    if( root )
+    {
+      s[State::Highlightable] = true;
+      s[State::Enabled] = true;
+      s[State::Sensitive] = true;
+      s[State::Showing] = true;
+      s[State::Active] = true;
+    }
+    else
+    {
+      auto t = GetParent()->GetStates();
+      s[State::Showing] = t[State::Showing];
+      s[State::Visible] = t[State::Visible];
+    }
+    return s;
+  }
+  Attributes GetAttributes() override
+  {
+    Dali::TypeInfo type;
+    actor.GetTypeInfo( type );
+    return {
+        {"t", type.GetName()},
+    };
+  }
+};
+
+using NonControlAccessiblesType = std::unordered_map< const Dali::RefObject*, std::unique_ptr< NonControlAccessible > >;
+static NonControlAccessiblesType nonControlAccessibles;
+
+static std::function< Accessible*( Dali::Actor ) > convertingFunctor = []( Dali::Actor ) -> Accessible* {
+  return nullptr;
+};
+
+void Accessible::RegisterControlAccessibilityGetter( std::function< Accessible*( Dali::Actor ) > functor )
+{
+  convertingFunctor = functor;
+}
+
+Accessible* Accessible::Get( Dali::Actor actor )
+{
+  if( !actor )
+  {
+    return nullptr;
+  }
+  auto p = convertingFunctor( actor );
+  if( !p )
+  {
+    if( nonControlAccessibles.empty() )
+    {
+      auto registry = Dali::Stage::GetCurrent().GetObjectRegistry();
+      registry.ObjectDestroyedSignal().Connect( []( const Dali::RefObject* obj ) {
+        nonControlAccessibles.erase( obj );
+      } );
+    }
+    auto it = nonControlAccessibles.emplace( &actor.GetBaseObject(), nullptr );
+    if( it.second )
+    {
+      it.first->second.reset( new NonControlAccessible( actor ) );
+    }
+    p = it.first->second.get();
+  }
+  return p;
+}
index 8ccdb83..2278f8e 100644 (file)
@@ -2,6 +2,7 @@
 
 # module: accessibility, backend: common
 adaptor_accessibility_common_src_files=\
+    ${adaptor_accessibility_dir}/accessibility-impl.cpp \
     ${adaptor_accessibility_dir}/common/tts-player-factory.cpp \
     ${adaptor_accessibility_dir}/common/tts-player-impl.cpp \
     ${adaptor_accessibility_dir}/common/accessibility-adaptor-impl.cpp \
index 3fa8e3f..f14eb95 100644 (file)
 #include <dali/internal/window-system/common/display-connection.h>
 #include <dali/internal/window-system/common/window-impl.h>
 
-#include <dali/internal/system/common/logging.h>
+#include <dali/devel-api/adaptor-framework/accessibility.h>
 #include <dali/devel-api/adaptor-framework/image-loading.h>
+#include <dali/internal/system/common/logging.h>
 
 #include <dali/internal/system/common/locale-utils.h>
 
+#include <aul.h>
+#include <unistd.h>
+
 using Dali::TextAbstraction::FontClient;
 
 namespace Dali
@@ -243,6 +247,38 @@ void Adaptor::Initialize( Dali::Configuration::ContextLoss configuration )
   }
 
   SetupSystemInformation();
+
+  Dali::Stage stage = Dali::Stage::GetCurrent();
+
+  char appname[4096] = {0};
+  int pid = getpid();
+  aul_app_get_pkgname_bypid( pid, appname, sizeof( appname ) );
+
+  accessibilityObserver.atspiBridge = Accessibility::CreateBridge();
+  auto accessible = Accessibility::Accessible::Get( stage.GetRootLayer() );
+  accessibilityObserver.atspiBridge->SetApplicationChild( accessible );
+  accessibilityObserver.atspiBridge->SetApplicationName( appname );
+  accessibilityObserver.atspiBridge->Initialize();
+
+  Dali::Stage::GetCurrent().KeyEventSignal().Connect( &accessibilityObserver, &AccessibilityObserver::OnAccessibleKeyEvent );
+}
+
+void Adaptor::AccessibilityObserver::OnAccessibleKeyEvent( const KeyEvent& event )
+{
+  Accessibility::KeyEventType type;
+  if( event.state == KeyEvent::Down )
+  {
+    type = Accessibility::KeyEventType::KeyPressed;
+  }
+  else if( event.state == KeyEvent::Up )
+  {
+    type = Accessibility::KeyEventType::KeyReleased;
+  }
+  else
+  {
+    return;
+  }
+  atspiBridge->Emit( type, event.keyCode, event.keyPressedName, event.time, !event.keyPressed.empty() );
 }
 
 Adaptor::~Adaptor()
@@ -748,6 +784,8 @@ void Adaptor::OnWindowShown()
 {
   if ( PAUSED_WHILE_HIDDEN == mState )
   {
+    accessibilityObserver.atspiBridge->ApplicationShown();
+
     // Adaptor can now be resumed
     mState = PAUSED;
 
@@ -762,6 +800,8 @@ void Adaptor::OnWindowHidden()
 {
   if ( RUNNING == mState )
   {
+    accessibilityObserver.atspiBridge->ApplicationHidden();
+
     Pause();
 
     // Adaptor cannot be resumed until the window is shown
index 27508e6..2476136 100644 (file)
 namespace Dali
 {
 
+namespace Accessibility
+{
+class Bridge;
+}
+
 class RenderSurface;
 class Window;
 
@@ -603,8 +608,18 @@ private: // Data
   SocketFactory                         mSocketFactory;               ///< Socket factory
   const bool                            mEnvironmentOptionsOwned:1;   ///< Whether we own the EnvironmentOptions (and thus, need to delete it)
   bool                                  mUseRemoteSurface;            ///< whether the remoteSurface is used or not
+
+  class AccessibilityObserver : public ConnectionTracker
+  {
+  public:
+    std::shared_ptr< Dali::Accessibility::Bridge > atspiBridge;
+
+    void OnAccessibleKeyEvent( const KeyEvent& event );
+  };
+  AccessibilityObserver accessibilityObserver;
+
 public:
-  inline static Adaptor& GetImplementation(Dali::Adaptor& adaptor) {return *adaptor.mImpl;}
+  inline static Adaptor& GetImplementation(Dali::Adaptor& adaptor) { return *adaptor.mImpl; }
 };
 
 } // namespace Internal
diff --git a/dali/public-api/adaptor-framework/accessibility.h b/dali/public-api/adaptor-framework/accessibility.h
new file mode 100644 (file)
index 0000000..6faa6f5
--- /dev/null
@@ -0,0 +1,503 @@
+#ifndef __DALI_ACCESSIBILITY_H__
+#define __DALI_ACCESSIBILITY_H__
+
+#include <dali/public-api/actors/actor.h>
+
+#include <atomic>
+#include <bitset>
+#include <exception>
+#include <functional>
+#include <memory>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+namespace Dali
+{
+class Actor;
+
+namespace Accessibility
+{
+enum class RelationType
+{
+  FlowsFrom,
+  FlowsTo
+};
+
+enum class MatchType : int32_t
+{
+  Invalid,
+  All,
+  Any,
+  None,
+  Empty
+};
+
+enum class SortOrder : uint32_t
+{
+  Invalid,
+  Canonical,
+  Flow,
+  Tab,
+  ReverseCanonical,
+  ReverseFlow,
+  ReverseTab,
+  LastDefined
+};
+
+enum class CoordType
+{
+  Screen,
+  Window
+};
+
+enum class NeighborSearchDirection
+{
+  Forward,
+  Backward
+};
+
+enum class ComponentLayer
+{
+  Invalid,
+  Background,
+  Canvas,
+  Widget,
+  Mdi,
+  Popup,
+  Overlay,
+  Window,
+  LastDefined,
+};
+
+enum class Role : uint32_t
+{
+  Invalid,
+  AcceleratorLabel,
+  Alert,
+  Animation,
+  Arrow,
+  Calendar,
+  Canvas,
+  CheckBox,
+  CheckMenuItem,
+  ColorChooser,
+  ColumnHeader,
+  ComboBox,
+  DateEditor,
+  DesktopIcon,
+  DesktopFrame,
+  Dial,
+  Dialog,
+  DirectoryPane,
+  DrawingArea,
+  FileChooser,
+  Filler,
+  FocusTraversable,
+  FontChooser,
+  Frame,
+  GlassPane,
+  HtmlContainer,
+  Icon,
+  Image,
+  InternalFrame,
+  Label,
+  LayeredPane,
+  List,
+  ListItem,
+  Menu,
+  MenuBar,
+  MenuItem,
+  OptionPane,
+  PageTab,
+  PageTabList,
+  Panel,
+  PasswordText,
+  PopupMenu,
+  ProgressBar,
+  PushButton,
+  RadioButton,
+  RadioMenuItem,
+  RootPane,
+  RowHeader,
+  ScrollBar,
+  ScrollPane,
+  Separator,
+  Slider,
+  SpinButton,
+  SplitPane,
+  StatusBar,
+  Table,
+  TableCell,
+  TableColumnHeader,
+  TableRowHeader,
+  TearoffMenuItem,
+  Terminal,
+  Text,
+  ToggleButton,
+  ToolBar,
+  ToolTip,
+  Tree,
+  TreeTable,
+  Unknown,
+  Viewport,
+  Window,
+  Extended,
+  Header,
+  Footer,
+  Paragraph,
+  Ruler,
+  Application,
+  Autocomplete,
+  Editbar,
+  Embedded,
+  Entry,
+  Chart,
+  Caption,
+  DocumentFrame,
+  Heading,
+  Page,
+  Section,
+  RedundantObject,
+  Form,
+  Link,
+  InputMethodWindow,
+  TableRow,
+  TreeItem,
+  DocumentSpreadsheet,
+  DocumentPresentation,
+  DocumentText,
+  DocumentWeb,
+  DocumentEmail,
+  Comment,
+  ListBox,
+  Grouping,
+  ImageMap,
+  Notification,
+  InfoBar,
+  LevelBar,
+  TitleBar,
+  BlockQuote,
+  Audio,
+  Video,
+  Definition,
+  Article,
+  Landmark,
+  Log,
+  Marquee,
+  Math,
+  Rating,
+  Timer,
+  Static,
+  MathFraction,
+  MathRoot,
+  Subscript,
+  Superscript,
+  _Count,
+};
+
+enum class State : uint32_t
+{
+  Invalid,
+  Active,
+  Armed,
+  Busy,
+  Checked,
+  Collapsed,
+  Defunct,
+  Editable,
+  Enabled,
+  Expandable,
+  Expanded,
+  Focusable,
+  Focused,
+  HasTooltip,
+  Horizontal,
+  Iconified,
+  Modal,
+  MultiLine,
+  MultiSelectable,
+  Opaque,
+  Pressed,
+  Resizeable,
+  Selectable,
+  Selected,
+  Sensitive,
+  Showing,
+  SingleLine,
+  Stale,
+  Transient,
+  Vertical,
+  Visible,
+  ManagesDescendants,
+  Indeterminate,
+  Required,
+  Truncated,
+  Animated,
+  InvalidEntry,
+  SupportsAutocompletion,
+  SelectableText,
+  IsDefault,
+  Visited,
+  Checkable,
+  HasPopup,
+  ReadOnly,
+  Highlighted,
+  Highlightable,
+  _Count
+};
+
+enum class WindowEvent
+{
+  PropertyChange,
+  Minimize,
+  Maximize,
+  Restore,
+  Close,
+  Create,
+  Reparent,
+  DesktopCreate,
+  DesktopDestroy,
+  Destroy,
+  Activate,
+  Deactivate,
+  Raise,
+  Lower,
+  Move,
+  Resize,
+  Shade,
+  UuShade,
+  Restyle,
+};
+
+enum class TextBoundary : uint32_t
+{
+  Character,
+  WordStart,
+  WordEnd,
+  SentenceStart,
+  SentenceEnd,
+  LineStart,
+  LineEnd,
+  _Count
+};
+
+template < size_t I, typename S >
+class BitStates
+{
+  std::array< uint32_t, I > data;
+
+public:
+  BitStates()
+  {
+    for( auto& u : data )
+      u = 0;
+  }
+  explicit BitStates( std::array< uint32_t, I > d )
+  {
+    for( auto i = 0u; i < I; ++i )
+      data[i] = d[i];
+  }
+  explicit BitStates( std::array< int32_t, I > d )
+  {
+    for( auto i = 0u; i < I; ++i )
+      data[i] = static_cast< uint32_t >( d[i] );
+  }
+
+  struct reference
+  {
+    std::array< uint32_t, I >& data;
+    size_t pos;
+    bool operator=( reference r )
+    {
+      return ( *this ) = static_cast< bool >( r );
+    }
+    bool operator=( bool v )
+    {
+      if( v )
+        data[pos / 32] |= 1 << ( pos & 31 );
+      else
+        data[pos / 32] &= ~( 1 << ( pos & 31 ) );
+      return v;
+    }
+    operator bool() const
+    {
+      auto i = static_cast< size_t >( pos );
+      return ( data[i / 32] & ( 1 << ( i & 31 ) ) ) != 0;
+    }
+  };
+  reference operator[]( S index ) { return {data, static_cast< size_t >( index )}; }
+  bool operator[]( S index ) const
+  {
+    auto i = static_cast< size_t >( index );
+    return ( data[i / 32] & ( 1 << ( i & 31 ) ) ) != 0;
+  }
+  std::array< uint32_t, I > GetRawData() const { return data; }
+
+  BitStates operator|( BitStates b ) const
+  {
+    BitStates r;
+    for( auto i = 0u; i < I; ++i )
+      r.data[i] = data[i] | b.data[i];
+    return r;
+  }
+  BitStates operator&( BitStates b ) const
+  {
+    BitStates r;
+    for( auto i = 0u; i < I; ++i )
+      r.data[i] = data[i] & b.data[i];
+    return r;
+  }
+  bool operator==( BitStates b ) const
+  {
+    for( auto i = 0u; i < I; ++i )
+      if( data[i] != b.data[i] )
+        return false;
+    return true;
+  }
+  explicit operator bool() const
+  {
+    for( auto& u : data )
+      if( u )
+        return true;
+    return false;
+  }
+};
+
+using States = BitStates< 2, State >;
+using Attributes = std::unordered_map< std::string, std::string >;
+
+class DALI_IMPORT_API Address
+{
+public:
+  Address() = default;
+  Address( std::string bus, std::string path ) : bus( std::move( bus ) ), path( std::move( path ) ) {}
+
+  explicit operator bool() const { return !path.empty(); }
+  std::string ToString() const
+  {
+    return *this ? bus + ":" + path : "::null";
+  }
+  const std::string& GetBus() const { return bus; }
+  const std::string& GetPath() const { return path; }
+
+private:
+  std::string bus, path;
+};
+
+enum class KeyEventType
+{
+  KeyPressed,
+  KeyReleased,
+};
+enum class Consumed
+{
+  No,
+  Yes
+};
+struct DALI_IMPORT_API Point
+{
+  int x = 0;
+  int y = 0;
+
+  Point() = default;
+  Point( int x, int y ) : x( x ), y( y ) {}
+
+  bool operator==( Point p ) const
+  {
+    return x == p.x && y == p.y;
+  }
+  bool operator!=( Point p ) const
+  {
+    return !( *this == p );
+  }
+};
+
+struct DALI_IMPORT_API Size
+{
+  int width = 0;
+  int height = 0;
+
+  Size() = default;
+  Size( int w, int h ) : width( w ), height( h ) {}
+
+  bool operator==( Size p ) const
+  {
+    return width == p.width && height == p.height;
+  }
+  bool operator!=( Size p ) const
+  {
+    return !( *this == p );
+  }
+};
+
+struct DALI_IMPORT_API Rectangle
+{
+  Point position;
+  Size size;
+
+  bool operator==( Rectangle p ) const
+  {
+    return position == p.position && size == p.size;
+  }
+  bool operator!=( Rectangle p ) const
+  {
+    return !( *this == p );
+  }
+};
+struct DALI_IMPORT_API Range
+{
+  int startOffset = 0;
+  int endOffset = 0;
+  std::string content;
+
+  Range() = default;
+  Range( size_t start, size_t end ) : startOffset( start ), endOffset( end )
+  {
+  }
+  Range( size_t start, size_t end, std::string content ) : startOffset( start ), endOffset( end ), content( content )
+  {
+  }
+};
+
+class DALI_IMPORT_API AccessibleError : public std::exception
+{
+public:
+  AccessibleError( std::string msg ) : msg( std::move( msg ) ) {}
+  const char* what() const noexcept override { return msg.c_str(); }
+
+private:
+  std::string msg;
+};
+}
+}
+
+namespace std
+{
+template <>
+struct hash< Dali::Accessibility::Point >
+{
+  size_t operator()( Dali::Accessibility::Point p )
+  {
+    return static_cast< size_t >( p.x ) ^ ( static_cast< size_t >( p.y ) * 11 );
+  }
+};
+template <>
+struct hash< Dali::Accessibility::Size >
+{
+  size_t operator()( Dali::Accessibility::Size p )
+  {
+    return static_cast< size_t >( p.width ) ^ ( static_cast< size_t >( p.height ) * 11 );
+  }
+};
+template <>
+struct hash< Dali::Accessibility::Rectangle >
+{
+  size_t operator()( Dali::Accessibility::Rectangle p )
+  {
+    return hash< Dali::Accessibility::Point >()( p.position ) ^ ( hash< Dali::Accessibility::Size >()( p.size ) * 11 );
+  }
+};
+}
+
+#endif
index 2f1471d..fc24b4f 100644 (file)
@@ -21,6 +21,7 @@ public_api_adaptor_framework_header_files = \
   $(adaptor_public_api_dir)/adaptor-framework/device-status.h \
   $(adaptor_public_api_dir)/adaptor-framework/input-method.h \
   $(adaptor_public_api_dir)/adaptor-framework/key.h \
+  $(adaptor_public_api_dir)/adaptor-framework/accessibility.h \
   $(adaptor_public_api_dir)/adaptor-framework/key-grab.h \
   $(adaptor_public_api_dir)/adaptor-framework/style-change.h \
   $(adaptor_public_api_dir)/adaptor-framework/timer.h \
old mode 100644 (file)
new mode 100755 (executable)