[AT-SPI] Remove check for DEFUNCT in BridgeBase::Find
[platform/core/uifw/dali-adaptor.git] / dali / internal / accessibility / bridge / bridge-base.cpp
1 /*
2  * Copyright (c) 2019 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali/internal/accessibility/bridge/bridge-base.h>
20
21 // EXTERNAL INCLUDES
22 #include <atomic>
23 #include <cstdlib>
24 #include <memory>
25
26 // INTERNAL INCLUDES
27 #include <dali/public-api/adaptor-framework/timer.h>
28
29 using namespace Dali::Accessibility;
30
31 static Dali::Timer tickTimer;
32
33 BridgeBase::~BridgeBase()
34 {
35 }
36
37 BridgeBase::BridgeBase()
38 {
39 }
40
41 void BridgeBase::addFilteredEvent( FilteredEvents kind, Dali::Accessibility::Accessible* obj, float delay, std::function<void()> functor )
42 {
43   if( delay < 0 )
44   {
45     delay = 0;
46   }
47
48   auto it = filteredEvents.insert({ { kind, obj }, { static_cast<unsigned int>(delay * 10), {} } });
49   if (it.second)
50   {
51     functor();
52   }
53   else
54   {
55     it.first->second.second = std::move(functor);
56   }
57
58   if (!tickTimer)
59   {
60     tickTimer = Dali::Timer::New(100);
61     tickTimer.TickSignal().Connect(this, &BridgeBase::tickFilteredEvents);
62   }
63 }
64
65 bool BridgeBase::tickFilteredEvents()
66 {
67   for(auto it = filteredEvents.begin(); it != filteredEvents.end(); )
68   {
69     if (it->second.first)
70     {
71       --it->second.first;
72     }
73     else
74     {
75       if (it->second.second)
76       {
77         it->second.second();
78         it->second.second = {};
79       }
80       else
81       {
82         it = filteredEvents.erase(it);
83         continue;
84       }
85     }
86     ++it;
87   }
88   return !filteredEvents.empty();
89 }
90
91 BridgeBase::ForceUpResult BridgeBase::ForceUp()
92 {
93   if( Bridge::ForceUp() == ForceUpResult::ALREADY_UP )
94   {
95     return ForceUpResult::ALREADY_UP;
96   }
97   auto proxy = DBus::DBusClient{dbusLocators::atspi::BUS, dbusLocators::atspi::OBJ_PATH, dbusLocators::atspi::BUS_INTERFACE, DBus::ConnectionType::SESSION};
98   auto addr = proxy.method< std::string() >( dbusLocators::atspi::GET_ADDRESS ).call();
99
100   if( !addr )
101   {
102     throw std::domain_error{std::string( "failed at call '" ) + dbusLocators::atspi::GET_ADDRESS + "': " + addr.getError().message};
103   }
104
105   con = DBusWrapper::Installed()->eldbus_address_connection_get_impl( std::get< 0 >( addr ) );
106   data->busName = DBus::getConnectionName( con );
107   dbusServer = { con };
108
109   {
110     DBus::DBusInterfaceDescription desc{"org.a11y.atspi.Cache"};
111     AddFunctionToInterface( desc, "GetItems", &BridgeBase::GetItems );
112     dbusServer.addInterface( "/org/a11y/atspi/cache", desc );
113   }
114   {
115     DBus::DBusInterfaceDescription desc{"org.a11y.atspi.Application"};
116     AddGetSetPropertyToInterface( desc, "Id", &BridgeBase::IdGet, &BridgeBase::IdSet );
117     dbusServer.addInterface( AtspiPath, desc );
118   }
119
120   return ForceUpResult::JUST_STARTED;
121 }
122
123 void BridgeBase::ForceDown()
124 {
125   Bridge::ForceDown();
126   dbusServer = {};
127   con = {};
128 }
129
130 const std::string& BridgeBase::GetBusName() const
131 {
132   static std::string empty;
133   return data ? data->busName : empty;
134 }
135
136 Accessible* BridgeBase::FindByPath( const std::string& name ) const
137 {
138   try
139   {
140     return Find( name );
141   }
142   catch( std::domain_error& )
143   {
144     return nullptr;
145   }
146 }
147
148 void BridgeBase::AddPopup( Accessible* obj )
149 {
150   if( std::find( popups.begin(), popups.end(), obj ) != popups.end() )
151   {
152     return;
153   }
154   popups.push_back( obj );
155   if (IsUp())
156   {
157     obj->Emit( WindowEvent::ACTIVATE, 0 );
158   }
159 }
160
161 void BridgeBase::RemovePopup( Accessible* obj )
162 {
163   auto it = std::find( popups.begin(), popups.end(), obj );
164   if( it == popups.end() )
165   {
166     return;
167   }
168   popups.erase( it );
169   if (IsUp())
170   {
171     obj->Emit( WindowEvent::DEACTIVATE, 0 );
172     if( popups.empty() )
173     {
174       application.children.back()->Emit( WindowEvent::ACTIVATE, 0 );
175     }
176     else
177     {
178       popups.back()->Emit( WindowEvent::ACTIVATE, 0 );
179     }
180   }
181 }
182
183 void BridgeBase::AddTopLevelWindow( Accessible* root )
184 {
185   application.children.push_back( root );
186   SetIsOnRootLevel( root );
187 }
188
189 void BridgeBase::RemoveTopLevelWindow( Accessible* root )
190 {
191   for(auto i = 0u; i < application.children.size(); ++i)
192   {
193     if( application.children[i] == root )
194     {
195       application.children.erase(application.children.begin() + i);
196       break;
197     }
198   }
199 }
200
201 std::string BridgeBase::StripPrefix( const std::string& path )
202 {
203   auto size = strlen( AtspiPath );
204   return path.substr( size + 1 );
205 }
206
207 Accessible* BridgeBase::Find( const std::string& path ) const
208 {
209   if( path == "root" )
210   {
211     return &application;
212   }
213   void* p;
214   std::istringstream tmp{ path };
215   if (! ( tmp >> p) )
216   {
217     throw std::domain_error{"invalid path '" + path + "'"};
218   }
219   auto it = data->knownObjects.find( static_cast<Accessible*>( p ) );
220   if( it == data->knownObjects.end() )
221   {
222     throw std::domain_error{"unknown object '" + path + "'"};
223   }
224   return static_cast<Accessible*>( p );
225 }
226
227 Accessible* BridgeBase::Find( const Address& ptr ) const
228 {
229   assert( ptr.GetBus() == data->busName );
230   return Find( ptr.GetPath() );
231 }
232
233 Accessible* BridgeBase::FindSelf() const
234 {
235   auto pth = DBus::DBusServer::getCurrentObjectPath();
236   auto size = strlen( AtspiPath );
237   if( pth.size() <= size )
238   {
239     throw std::domain_error{"invalid path '" + pth + "'"};
240   }
241   if( pth.substr( 0, size ) != AtspiPath )
242   {
243     throw std::domain_error{"invalid path '" + pth + "'"};
244   }
245   if( pth[size] != '/' )
246   {
247     throw std::domain_error{"invalid path '" + pth + "'"};
248   }
249   return Find( StripPrefix( pth ) );
250 }
251
252 void BridgeBase::IdSet( int id )
253 {
254   this->id = id;
255 }
256
257 int BridgeBase::IdGet()
258 {
259   return this->id;
260 }
261
262 auto BridgeBase::GetItems() -> DBus::ValueOrError< std::vector< CacheElementType > >
263 {
264   auto root = &application;
265
266   std::vector< CacheElementType > res;
267
268   std::function< void(Accessible*) > proc =
269     [&]( Accessible* item )
270     {
271       res.emplace_back( std::move( CreateCacheElement( root ) ) );
272       for( auto i = 0u; i < item->GetChildCount(); ++i )
273       {
274         proc( item->GetChildAtIndex( i ) );
275       }
276     };
277
278   return res;
279 }
280
281 auto BridgeBase::CreateCacheElement( Accessible* item ) -> CacheElementType
282 {
283   if( !item )
284   {
285     return {};
286   }
287
288   auto root = &application;
289   auto parent = item->GetParent();
290
291   std::vector< Address > children;
292   for( auto i = 0u; i < item->GetChildCount(); ++i )
293   {
294     children.emplace_back( item->GetChildAtIndex( i )->GetAddress() );
295   }
296
297   return std::make_tuple(
298     item->GetAddress(),
299     root->GetAddress(),
300     parent ? parent->GetAddress() : Address{},
301     children,
302     item->GetInterfaces(),
303     item->GetName(),
304     item->GetRole(),
305     item->GetDescription(),
306     item->GetStates().GetRawData()
307   );
308 }
309