d59df195dd3356ab890138f034aae90ef781c9cd
[platform/core/uifw/dali-toolkit.git] / automated-tests / src / dali-toolkit-internal / dali-toolkit-test-utils / dbus-wrapper.cpp
1 /*
2  * Copyright 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 // CLASS HEADER
18 #include "dbus-wrapper.h"
19
20 //#include <dali/internal/accessibility/bridge/accessibility-common.h>
21
22 // EXTERNAL INCLUDES
23 #include <sstream>
24 #include <iostream>
25 #include <mutex>
26
27 #include <Eldbus.h>
28 #include <Ecore_Input.h>
29
30 // INTERNAL INCLUDES
31 #include <dali/public-api/dali-adaptor-common.h>
32
33 #define DBUS_INTERFACE_PROPERTIES "org.freedesktop.DBus.Properties"
34
35 #undef EINA_FALSE
36 #undef EINA_TRUE
37 #define EINA_TRUE static_cast< Eina_Bool >( 1 )
38 #define EINA_FALSE static_cast< Eina_Bool >( 0 )
39
40 //#define DBUS_DEBUG(...) do { DBus::debugPrint(__FILE__, __LINE__, __VA_ARGS__); } while (0)
41
42 // BART QUICK HACK
43 #undef assert
44 #define assert(x) do{}while(0)
45
46 std::atomic< unsigned int > DBus::detail::CallId::LastId{0};
47 static std::function< void( const char*, size_t ) > debugPrinter;
48 static std::mutex debugLock;
49
50 thread_local std::string DBus::DBusServer::currentObjectPath;
51 thread_local DBusWrapper::ConnectionPtr DBus::DBusServer::currentConnection;
52
53 void DBus::setDebugPrinter( std::function< void( const char*, size_t ) > printer )
54 {
55   std::lock_guard< std::mutex > lock( debugLock );
56   debugPrinter = std::move( printer );
57 }
58
59 void DBus::debugPrint( const char* file, size_t line, const char* format, ... )
60 {
61   std::function< void( const char*, size_t ) > debugPrintFunc;
62   {
63     std::lock_guard< std::mutex > lock( debugLock );
64     if( !debugPrinter )
65       return;
66     debugPrintFunc = debugPrinter;
67   }
68   std::vector< char > buf( 4096 );
69   int offset;
70   while( true )
71   {
72     offset = snprintf( buf.data(), buf.size(), "%s:%u: ", file, static_cast< unsigned int >( line ) );
73     if( offset < 0 )
74       return;
75     if( static_cast< size_t >( offset ) < buf.size() )
76       break;
77     buf.resize( offset + 1 );
78   }
79
80   while( true )
81   {
82     va_list args;
83     va_start( args, format );
84     int z = vsnprintf( buf.data() + offset, buf.size() - offset, format, args );
85     va_end( args );
86     if( z < 0 )
87       return;
88     bool done = static_cast< size_t >( z ) + static_cast< size_t >( offset ) < buf.size();
89     buf.resize( static_cast< size_t >( z ) + static_cast< size_t >( offset ) );
90     if( done )
91       break;
92   }
93   debugPrintFunc( buf.data(), buf.size() );
94 }
95
96 DBusWrapper::ConnectionPtr DBus::getDBusConnectionByName( const std::string& name )
97 {
98   return DBUS_W->eldbus_address_connection_get_impl( name );
99 }
100
101 DBusWrapper::ConnectionPtr DBus::getDBusConnectionByType( ConnectionType connectionType )
102 {
103   return DBUS_W->eldbus_connection_get_impl(connectionType);
104 }
105
106 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 ) )
107 {
108 }
109
110 DBus::DBusClient::DBusClient( std::string busName, std::string pathName, std::string interfaceName, const DBusWrapper::ConnectionPtr &conn )
111 {
112   if( !conn )
113     connectionState->connection = getDBusConnectionByType( ConnectionType::SESSION );
114   else
115     connectionState->connection = conn;
116
117   std::ostringstream o;
118   o << "bus = " << busName << " path = " << pathName << " connection = " << DBUS_W->eldbus_connection_unique_name_get_impl( connectionState->connection );
119   info = o.str();
120
121   connectionState->object = DBUS_W->eldbus_object_get_impl( connectionState->connection, busName.c_str(), pathName.c_str() );
122   if( connectionState->object )
123   {
124     connectionState->proxy = DBUS_W->eldbus_proxy_get_impl( connectionState->object, interfaceName );
125     if( interfaceName != DBUS_INTERFACE_PROPERTIES )
126     {
127       connectionState->propertiesProxy = DBUS_W->eldbus_proxy_get_impl( connectionState->object, DBUS_INTERFACE_PROPERTIES );
128     }
129     else
130     {
131       connectionState->propertiesProxy = DBUS_W->eldbus_proxy_copy_impl( connectionState->proxy );
132     }
133   }
134   connectionInfo = std::make_shared< ConnectionInfo >();
135   connectionInfo->busName = std::move( busName );
136   connectionInfo->pathName = std::move( pathName );
137   connectionInfo->interfaceName = std::move( interfaceName );
138 }
139
140 DBus::DBusServer::DBusServer( ConnectionType tp ) : DBus::DBusServer( DBus::getDBusConnectionByType( tp ) )
141 {
142 }
143
144 DBus::DBusServer::DBusServer( const DBusWrapper::ConnectionPtr &conn )
145 {
146   if( !conn )
147     connection = getDBusConnectionByType( ConnectionType::SESSION );
148   else
149     connection = conn;
150 }
151
152 DBus::DBusInterfaceDescription::DBusInterfaceDescription( std::string interfaceName ) : interfaceName( std::move( interfaceName ) )
153 {
154 }
155
156 void DBus::DBusServer::addInterface( const std::string& pathName, DBusInterfaceDescription& dscr, bool fallback )
157 {
158   DBUS_W->add_interface_impl( fallback, pathName, connection, destructorObject->destructors, dscr.interfaceName, dscr.methods, dscr.properties, dscr.signals );
159 }
160
161 std::string DBus::DBusServer::getBusName() const
162 {
163   return getConnectionName( connection );
164 }
165
166 std::string DBus::getConnectionName( const DBusWrapper::ConnectionPtr &c )
167 {
168   return DBUS_W->eldbus_connection_unique_name_get_impl( c );
169 }
170
171 bool DBus::DBusClient::getFromEinaValue(const _Eina_Value *v, void *dst)
172 {
173   return eina_value_get(const_cast<Eina_Value*>(v), dst);
174 }
175
176 /// \cond
177 static std::unique_ptr<DBusWrapper> InstalledWrapper;
178
179 struct DefaultDBusWrapper : public DBusWrapper {
180   constexpr static int ELDBUS_CALL_TIMEOUT = 1000;
181
182   DefaultDBusWrapper() {
183   }
184   ~DefaultDBusWrapper() {
185   }
186   #define DEFINE_GS(name, eldbus_name, unref_call) \
187     static eldbus_name *get(const std::shared_ptr<name> &a) { \
188       return static_cast<name ## Impl*>(a.get())->Value; \
189     } \
190     static eldbus_name *release(const std::shared_ptr<name> &a) { \
191       auto z = static_cast<name ## Impl*>(a.get())->Value; \
192       static_cast<name ## Impl*>(a.get())->Value = nullptr; \
193       return z; \
194     } \
195     template <typename ... ARGS> static std::shared_ptr<name> create(const eldbus_name *v, ARGS && ... args) { \
196       return std::make_shared<name ## Impl>(const_cast<eldbus_name*>(v), std::forward<ARGS>(args)...); \
197     }
198
199   #define DEFINE_TYPE(name, eldbus_name, unref_call) \
200   struct name ## Impl : public name { \
201     eldbus_name *Value = nullptr; \
202     bool EraseOnExit = false; \
203     name ## Impl(eldbus_name *Value, bool EraseOnExit = false) : Value(Value), EraseOnExit(EraseOnExit) { } \
204     ~name ## Impl() { \
205       if (EraseOnExit && Value) { unref_call; } \
206     } \
207   }; \
208   DEFINE_GS(name, eldbus_name, unref_call)
209
210   struct ConnectionImpl : public Connection {
211     Eldbus_Connection *Value = nullptr;
212     bool EraseOnExit = false;
213     ConnectionImpl(Eldbus_Connection *Value, bool EraseOnExit = false) : Value(Value), EraseOnExit(EraseOnExit) {
214       ecore_event_init();
215       eldbus_init();
216     }
217     ~ConnectionImpl() {
218       if (EraseOnExit && Value) {
219         eldbus_connection_unref( Value );
220       }
221       eldbus_shutdown();
222       ecore_event_shutdown();
223     }
224   };
225   struct MessageIterImpl : public MessageIter {
226     Eldbus_Message_Iter *Value = nullptr, *Parent = nullptr;
227     bool EraseOnExit = false;
228     MessageIterImpl(Eldbus_Message_Iter *Value, Eldbus_Message_Iter *Parent, bool EraseOnExit = false) : Value(Value), Parent(Parent), EraseOnExit(EraseOnExit) { }
229     ~MessageIterImpl() {
230       if (EraseOnExit && Value && Parent)
231         eldbus_message_iter_container_close(Parent, Value);
232     }
233   };
234
235   DEFINE_GS(Connection, Eldbus_Connection, )
236   DEFINE_GS(MessageIter, Eldbus_Message_Iter, )
237   DEFINE_TYPE(Message, Eldbus_Message, eldbus_message_unref( Value ))
238   DEFINE_TYPE(Proxy, Eldbus_Proxy, )
239   DEFINE_TYPE(Object, Eldbus_Object, eldbus_object_unref( Value ))
240   DEFINE_TYPE(Pending, Eldbus_Pending, )
241   DEFINE_TYPE(EventPropertyChanged, Eldbus_Proxy_Event_Property_Changed, )
242   #undef DEFINE_TYPE
243
244   std::shared_ptr<Connection> eldbus_address_connection_get_impl(const std::string &addr) override {
245     eldbus_init();
246     auto p = eldbus_address_connection_get(addr.c_str());
247     auto w = create(p, true);
248     eldbus_shutdown();
249     return w;
250   }
251
252 #define eldbus_message_iter_arguments_append_impl_basic(type, sig) \
253   void eldbus_message_iter_arguments_append_impl(const MessageIterPtr &it, type src) override { \
254     eldbus_message_iter_arguments_append( get(it), #sig, src ); \
255   } \
256   bool eldbus_message_iter_get_and_next_impl(const MessageIterPtr &it, type &dst) override { \
257     return eldbus_message_iter_get_and_next( get(it), (#sig)[0], &dst ); \
258   }
259
260   eldbus_message_iter_arguments_append_impl_basic(uint8_t, y)
261   eldbus_message_iter_arguments_append_impl_basic(uint16_t, q)
262   eldbus_message_iter_arguments_append_impl_basic(uint32_t, u)
263   eldbus_message_iter_arguments_append_impl_basic(uint64_t, t)
264   eldbus_message_iter_arguments_append_impl_basic(int16_t, n)
265   eldbus_message_iter_arguments_append_impl_basic(int32_t, i)
266   eldbus_message_iter_arguments_append_impl_basic(int64_t, x)
267   eldbus_message_iter_arguments_append_impl_basic(double, d)
268
269 #undef eldbus_message_iter_arguments_append_impl_basic
270
271   void eldbus_message_iter_arguments_append_impl(const MessageIterPtr &it, bool src) override {
272     eldbus_message_iter_arguments_append( get(it), "b", src ? 1 : 0 );
273   }
274   bool eldbus_message_iter_get_and_next_impl(const MessageIterPtr &it, bool &dst) override {
275     unsigned char q;
276     auto z = eldbus_message_iter_get_and_next( get(it), 'b', &q );
277     dst = q != 0;
278     return z;
279   }
280   void eldbus_message_iter_arguments_append_impl(const MessageIterPtr &it, const std::string &src) override {
281     eldbus_message_iter_arguments_append( get(it), "s", src.c_str() );
282   }
283   bool eldbus_message_iter_get_and_next_impl(const MessageIterPtr &it, std::string &dst) override {
284     auto iter = get(it);
285     const char* q;
286     if( !eldbus_message_iter_get_and_next( iter, 's', &q ) )
287     {
288       if( !eldbus_message_iter_get_and_next( iter, 'o', &q ) )
289         return false;
290     }
291     dst = q;
292     return true;
293   }
294   void eldbus_message_iter_arguments_append_impl(const MessageIterPtr &it, const ObjectPath &src) override {
295     eldbus_message_iter_arguments_append( get(it), "o", src.value.c_str() );
296   }
297   bool eldbus_message_iter_get_and_next_impl(const MessageIterPtr &it, ObjectPath &dst) override {
298     const char* q;
299     if( !eldbus_message_iter_get_and_next( get(it), 'o', &q ) )
300       return false;
301     dst.value = q;
302     return true;
303   }
304
305   MessageIterPtr eldbus_message_iter_container_new_impl(const MessageIterPtr &it, int type, const std::string &sig) override {
306     auto z = eldbus_message_iter_container_new( get(it), type, !sig.empty() ? sig.c_str() : NULL );
307     return create(z, get(it), true);
308   }
309   MessageIterPtr eldbus_message_iter_get_and_next_by_type_impl(const MessageIterPtr &it, int type) override {
310     Eldbus_Message_Iter* entry;
311     if (!eldbus_message_iter_get_and_next( get(it), type, &entry ) ) return {};
312     return create(entry, get(it), false);
313   }
314   MessageIterPtr eldbus_message_iter_get_impl(const MessagePtr &msg, bool) override {
315     return create(eldbus_message_iter_get(get(msg)), nullptr, false);
316   }
317   MessagePtr eldbus_proxy_method_call_new_impl(const ProxyPtr &proxy, const std::string &funcName) {
318     return create(eldbus_proxy_method_call_new( get(proxy), funcName.c_str() ) );
319   }
320   MessagePtr eldbus_proxy_send_and_block_impl(const ProxyPtr &proxy, const MessagePtr &msg) override {
321     return create(eldbus_proxy_send_and_block(get(proxy), release(msg), ELDBUS_CALL_TIMEOUT) );
322   }
323   bool eldbus_message_error_get_impl(const MessagePtr &msg, std::string &name, std::string &text) override {
324     const char *errname, *errmsg;
325     if( eldbus_message_error_get( get(msg), &errname, &errmsg ) ) {
326       name = errname;
327       text = errmsg;
328       return true;
329     }
330     return false;
331   }
332   std::string eldbus_message_signature_get_impl(const MessagePtr &msg) override {
333     return eldbus_message_signature_get(get(msg));
334   }
335
336   static void callAsyncCb( void* data, const Eldbus_Message *msg,  Eldbus_Pending *pending )
337   {
338     auto d = static_cast< SendCallback* >( data );
339     (*d)( create(msg, false) );
340   }
341   static void pendingFreeCb( void* data, const void* )
342   {
343     auto d = static_cast< SendCallback* >( data );
344     delete d;
345   }
346   static void listenerCallbackFree( void* data, const void* )
347   {
348     auto d = static_cast< std::function< void( const Eldbus_Message* msg ) >* >( data );
349     delete d;
350   }
351
352   PendingPtr eldbus_proxy_send_impl(const ProxyPtr &proxy, const MessagePtr &msg, const SendCallback &callback) override {
353     auto cb = new SendCallback{ callback };
354     auto pending = eldbus_proxy_send( get(proxy), release(msg), callAsyncCb, cb, ELDBUS_CALL_TIMEOUT );
355     if( pending )
356     {
357       eldbus_pending_free_cb_add( pending, pendingFreeCb, cb );
358     }
359     else
360     {
361       delete cb;
362     }
363     return create(pending, false);
364   }
365   std::string eldbus_proxy_interface_get_impl(const ProxyPtr &proxy) override {
366     return eldbus_proxy_interface_get( get(proxy) );
367   }
368   static void listenerCallback( void* data, const Eldbus_Message* msg )
369   {
370     auto p = static_cast< std::function< void( const Eldbus_Message* msg ) >* >( data );
371     ( *p )( msg );
372   }
373   void eldbus_proxy_signal_handler_add_impl(const ProxyPtr &proxy, const std::string &member, const std::function<void(const MessagePtr &)> &cb) override {
374     auto tmp = new std::function< void( const Eldbus_Message* msg ) >{
375       [cb](const Eldbus_Message* msg) {
376         cb(create(msg, false));
377       }
378     };
379     auto handler = eldbus_proxy_signal_handler_add( get(proxy), member.c_str(), listenerCallback, tmp );
380     if( handler )
381       eldbus_proxy_free_cb_add( get(proxy), listenerCallbackFree, tmp );
382     else
383       delete tmp;
384   }
385   std::string eldbus_message_iter_signature_get_impl(const MessageIterPtr &iter) override {
386     return eldbus_message_iter_signature_get( get(iter) );
387   }
388   MessagePtr eldbus_message_method_return_new_impl( const MessagePtr &msg) override {
389     return create(eldbus_message_method_return_new( get(msg) ) );
390   }
391   MessagePtr eldbus_message_error_new_impl( const MessagePtr &msg, const std::string &err, const std::string &txt ) override {
392     return create(eldbus_message_error_new( get(msg), err.c_str(), txt.c_str() ) );
393   }
394   PendingPtr eldbus_connection_send_impl(const ConnectionPtr &conn, const MessagePtr &msg) override {
395     return create(eldbus_connection_send( get(conn), get(msg), NULL, NULL, -1 ) );
396   }
397   MessagePtr eldbus_message_signal_new_impl(const std::string &path, const std::string &iface, const std::string &name) override {
398     return create(eldbus_message_signal_new( path.c_str(), iface.c_str(), name.c_str() ) );
399   }
400   MessagePtr eldbus_message_ref_impl(const MessagePtr &msg) override {
401     return create(eldbus_message_ref( get(msg) ), true );
402   }
403   ConnectionPtr eldbus_connection_get_impl(ConnectionType type) override {
404     Eldbus_Connection_Type eldbusType = ELDBUS_CONNECTION_TYPE_SYSTEM;
405
406     switch( type )
407     {
408       case ConnectionType::SYSTEM:
409       {
410         eldbusType = ELDBUS_CONNECTION_TYPE_SYSTEM;
411         break;
412       }
413       case ConnectionType::SESSION:
414       {
415         eldbusType = ELDBUS_CONNECTION_TYPE_SESSION;
416         break;
417       }
418     }
419
420     eldbus_init();
421     auto p = eldbus_connection_get( eldbusType );
422     auto w = create(p, true);
423     eldbus_shutdown();
424     return w;
425   }
426   std::string eldbus_connection_unique_name_get_impl(const ConnectionPtr &conn) override {
427     return eldbus_connection_unique_name_get( get(conn) );
428   }
429   ObjectPtr eldbus_object_get_impl( const ConnectionPtr &conn, const std::string &bus, const std::string &path ) override {
430       return create(eldbus_object_get(get(conn), bus.c_str(), path.c_str() ), true );
431   }
432   ProxyPtr eldbus_proxy_get_impl( const ObjectPtr &obj, const std::string &interface ) override {
433     return create(eldbus_proxy_get(get(obj), interface.c_str() ), false );
434   }
435   ProxyPtr eldbus_proxy_copy_impl( const ProxyPtr &ptr) override {
436     return create(get(ptr), false );
437   }
438
439
440
441
442
443
444   struct Implementation
445   {
446     Eldbus_Service_Interface_Desc dsc;
447     std::vector< std::vector< Eldbus_Arg_Info > > argsInfos;
448     std::vector< Eldbus_Method > methods;
449     std::vector< Eldbus_Signal > signals;
450     std::vector< Eldbus_Property > properties;
451
452     std::unordered_map< std::string, DBusWrapper::MethodInfo > methodsMap;
453     std::unordered_map< std::string, DBusWrapper::PropertyInfo > propertiesMap;
454     std::unordered_map< unsigned int, DBusWrapper::SignalInfo > signalsMap;
455
456     DBusWrapper::ConnectionWeakPtr connection;
457   };
458
459   static std::unordered_map< const Eldbus_Service_Interface*, std::unique_ptr< Implementation > > globalEntries;
460   static std::mutex globalEntriesMutex;
461
462 #undef EINA_FALSE
463 #undef EINA_TRUE
464 #define EINA_FALSE static_cast<Eina_Bool>(0)
465 #define EINA_TRUE static_cast<Eina_Bool>(1)
466
467   static Eina_Bool property_get_callback( const Eldbus_Service_Interface* iface, const char* propertyName, Eldbus_Message_Iter* iter,
468                                           const Eldbus_Message* message, Eldbus_Message** error )
469   {
470     Implementation* impl = nullptr;
471     {
472       std::lock_guard< std::mutex > lock( globalEntriesMutex );
473       auto it = globalEntries.find( iface );
474       if( it != globalEntries.end() )
475         impl = it->second.get();
476     }
477     if( !impl )
478       return EINA_FALSE;
479
480     auto it = impl->propertiesMap.find( propertyName );
481     if( it == impl->propertiesMap.end() || !it->second.getCallback )
482       return EINA_FALSE;
483
484     auto connection = impl->connection.lock();
485     if( !connection )
486       return EINA_FALSE;
487
488     DBus::DBusServer::CurrentObjectSetter currentObjectSetter( connection, eldbus_message_path_get( message ) );
489     auto reply = it->second.getCallback( create(message, false), create(iter, nullptr, false) );
490     if( !reply.empty() )
491     {
492       if( error )
493         *error = eldbus_message_error_new( message, "org.freedesktop.DBus.Error.Failed", reply.c_str() );
494       return EINA_FALSE;
495     }
496
497     return EINA_TRUE;
498   }
499
500   static Eldbus_Message* property_set_callback( const Eldbus_Service_Interface* iface, const char* propertyName, Eldbus_Message_Iter* iter,
501                                                 const Eldbus_Message* message )
502   {
503     Implementation* impl = nullptr;
504     {
505       std::lock_guard< std::mutex > lock( globalEntriesMutex );
506       auto it = globalEntries.find( iface );
507       if( it != globalEntries.end() )
508         impl = it->second.get();
509     }
510     if( !impl )
511     {
512       auto ret = eldbus_message_error_new( message, "org.freedesktop.DBus.Error.Failed", "Unknown interface" );
513       return ret;
514     }
515     auto it = impl->propertiesMap.find( propertyName );
516     if( it == impl->propertiesMap.end() || !it->second.setCallback )
517     {
518       auto ret = eldbus_message_error_new( message, "org.freedesktop.DBus.Error.Failed", "Unknown setter" );
519       return ret;
520     }
521     auto connection = impl->connection.lock();
522     if( !connection )
523     {
524       auto ret = eldbus_message_error_new( message, "org.freedesktop.DBus.Error.Failed", "Connection lost" );
525       return ret;
526     }
527
528     DBus::DBusServer::CurrentObjectSetter currentObjectSetter( connection, eldbus_message_path_get( message ) );
529     auto reply = it->second.setCallback( create(message, false), create(iter, nullptr, false) );
530
531     Eldbus_Message* ret = nullptr;
532     if( !reply.empty() )
533     {
534       ret = eldbus_message_error_new( message, "org.freedesktop.DBus.Error.Failed", reply.c_str() );
535     }
536     else
537     {
538       ret = eldbus_message_method_return_new( message );
539     }
540     return ret;
541   }
542
543   static Eldbus_Message* method_callback( const Eldbus_Service_Interface* iface, const Eldbus_Message* message )
544   {
545     Implementation* impl = nullptr;
546     {
547       std::lock_guard< std::mutex > lock( globalEntriesMutex );
548       auto it = globalEntries.find( iface );
549       if( it != globalEntries.end() )
550         impl = it->second.get();
551     }
552     if( !impl )
553     {
554       auto ret = eldbus_message_error_new( message, "org.freedesktop.DBus.Error.Failed", "Unknown interface" );
555       return ret;
556     }
557     std::string memberName = eldbus_message_member_get( message );
558     auto it = impl->methodsMap.find( memberName );
559     if( it == impl->methodsMap.end() )
560     {
561       auto ret = eldbus_message_error_new( message, "org.freedesktop.DBus.Error.Failed", "Unknown method" );
562       return ret;
563     }
564     auto connection = impl->connection.lock();
565     if( !connection )
566     {
567       auto ret = eldbus_message_error_new( message, "org.freedesktop.DBus.Error.Failed", "Connection lost" );
568       return ret;
569     }
570     DBus::DBusServer::CurrentObjectSetter currentObjectSetter( connection, eldbus_message_path_get( message ) );
571     auto reply = it->second.callback( create(message) );
572     return release(reply);
573   }
574
575   void add_interface_impl( bool fallback, const std::string& pathName,
576                               const ConnectionPtr &connection,
577                               std::vector<std::function<void()>> &destructors,
578                               const std::string& interfaceName,
579                               std::vector< MethodInfo >& dscrMethods,
580                               std::vector< PropertyInfo >& dscrProperties,
581                               std::vector< SignalInfo >& dscrSignals ) override
582   {
583     std::vector< Eldbus_Method > methods;
584     std::vector< Eldbus_Signal > signals;
585     std::vector< Eldbus_Property > properties;
586     std::vector< std::vector< Eldbus_Arg_Info > > argsInfos;
587     std::unordered_map< std::string, DBus::DBusInterfaceDescription::MethodInfo > methodsMap;
588     std::unordered_map< std::string, DBus::DBusInterfaceDescription::PropertyInfo > propertiesMap;
589     std::unordered_map< unsigned int, DBus::DBusInterfaceDescription::SignalInfo > signalsMap;
590
591     DBUS_DEBUG( "interface %s path %s on bus %s", interfaceName.c_str(), pathName.c_str(), DBus::getConnectionName( connection ).c_str() );
592     auto makeArgInfo = [&](const std::vector<std::pair<std::string, std::string>> &input) {
593       argsInfos.push_back({});
594       auto &dst = argsInfos.back();
595       for(auto &s : input) {
596         auto a = Strings.add(s.first);
597         auto b = Strings.add(s.second);
598         dst.push_back({ a, b });
599       }
600       dst.push_back({ nullptr, nullptr });
601       return dst.data();
602     };
603     for( auto& ee : dscrMethods )
604     {
605       auto key = ee.memberName;
606       DBUS_DEBUG( "adding method %s", ee.memberName.c_str() );
607       for( auto& r : ee.in )
608       {
609         DBUS_DEBUG( "in %s '%s'", r.first.c_str(), r.second.c_str() );
610       }
611       for( auto& r : ee.out )
612       {
613         DBUS_DEBUG( "out %s '%s'", r.first.c_str(), r.second.c_str() );
614       }
615       auto& e = ( methodsMap[key] = std::move( ee ) );
616       methods.push_back( {} );
617       auto& m = methods.back();
618       m.member = e.memberName.c_str();
619       m.in = makeArgInfo(e.in);
620       m.out = makeArgInfo(e.out);
621       m.cb = method_callback;
622       m.flags = 0;
623     }
624     for( auto& ee : dscrProperties )
625     {
626       auto key = ee.memberName;
627       DBUS_DEBUG( "adding property %s", ee.memberName.c_str() );
628       auto& e = ( propertiesMap[key] = std::move( ee ) );
629       properties.push_back( {} );
630       auto& m = properties.back();
631       m.name = e.memberName.c_str();
632       m.type = e.typeSignature.c_str();
633       m.get_func = e.getCallback ? property_get_callback : nullptr;
634       m.set_func = e.setCallback ? property_set_callback : nullptr;
635       m.flags = 0;
636     }
637     dscrMethods.clear();
638     dscrProperties.clear();
639     dscrSignals.clear();
640
641     methods.push_back( {nullptr, nullptr, nullptr, nullptr, 0} );
642     signals.push_back( {nullptr, nullptr, 0} );
643     properties.push_back( {nullptr, nullptr, nullptr, nullptr, 0} );
644
645     auto impl = std::unique_ptr< Implementation >( new Implementation{
646         {interfaceName.c_str(),
647         methods.data(),
648         signals.data(),
649         properties.data(),
650         nullptr,
651         nullptr},
652         std::move( argsInfos ),
653         std::move( methods ),
654         std::move( signals ),
655         std::move( properties ),
656         std::move( methodsMap ),
657         std::move( propertiesMap ),
658         std::move( signalsMap ),
659         connection} );
660
661     {
662       std::lock_guard< std::mutex > lock( globalEntriesMutex );
663       auto v = fallback ? eldbus_service_interface_fallback_register( get(connection), pathName.c_str(), &impl->dsc ) : eldbus_service_interface_register( get(connection), pathName.c_str(), &impl->dsc );
664       assert( v );
665       globalEntries[v] = std::move( impl );
666       DBUS_DEBUG( "registering interface %p (%d)", v, fallback ? 1 : 0 );
667       destructors.push_back([=]() {
668         DBUS_DEBUG( "unregistering interface %p", v );
669         eldbus_service_interface_unregister( v );
670         std::lock_guard< std::mutex > lock( globalEntriesMutex );
671         globalEntries.erase( v );
672       });
673     }
674   }
675   static void listenerEventChangedCallback( void* data, Eldbus_Proxy* proxy EINA_UNUSED, void* event )
676   {
677     auto p = static_cast< std::function< void( Eldbus_Proxy_Event_Property_Changed* ) >* >( data );
678     ( *p )( static_cast< Eldbus_Proxy_Event_Property_Changed* >( event ) );
679   }
680   static void ProxyEventCallbackDelCb( void* data, const void *obj )
681   {
682     auto d = static_cast< std::function< void( Eldbus_Proxy_Event_Property_Changed* ) >* >( data );
683     delete d;
684   }
685   void add_property_changed_event_listener_impl( const ProxyPtr &proxy, const std::string &interface, const std::string &name, std::function< void( const Eina_Value * ) > cb) override {
686     auto callbackLambdaPtr = new std::function< void( Eldbus_Proxy_Event_Property_Changed *epc ) >{
687       [cb, name, interface]( Eldbus_Proxy_Event_Property_Changed *ev ) {
688       const char* ifc = eldbus_proxy_interface_get( ev->proxy );
689       if( ev->name && ev->name == name && ifc && interface == ifc )
690       {
691         cb(ev->value);
692       }
693     } };
694     auto p = get(proxy);
695     eldbus_proxy_event_callback_add( p, ELDBUS_PROXY_EVENT_PROPERTY_CHANGED,
696                                      listenerEventChangedCallback, callbackLambdaPtr );
697     eldbus_proxy_free_cb_add( p, ProxyEventCallbackDelCb, callbackLambdaPtr );
698   }
699 };
700
701 std::unordered_map< const Eldbus_Service_Interface*, std::unique_ptr< DefaultDBusWrapper::Implementation > > DefaultDBusWrapper::globalEntries;
702 std::mutex DefaultDBusWrapper::globalEntriesMutex;
703
704 DBusWrapper *DBusWrapper::Installed()
705 {
706   if (!InstalledWrapper)
707     InstalledWrapper.reset(new DefaultDBusWrapper);
708   return InstalledWrapper.get();
709 }
710
711 void DBusWrapper::Install(std::unique_ptr<DBusWrapper> w)
712 {
713   InstalledWrapper = std::move(w);
714 }
715
716
717 struct TestDBusWrapper::ConnectionImpl : public TestDBusWrapper::Connection {
718 };
719
720 TestDBusWrapper::TestDBusWrapper()
721 {
722   eina_init();
723   connection = std::make_shared<ConnectionImpl>();
724   testMethods[std::tuple<std::string, std::string, std::string, MethodType>{"/org/a11y/bus", "org.a11y.Status", "ScreenReaderEnabled", MethodType::Getter}] =
725   testMethods[std::tuple<std::string, std::string, std::string, MethodType>{"/org/a11y/bus", "org.a11y.Status", "IsEnabled", MethodType::Getter}] =
726   [this](const DBusWrapper::MessagePtr &m) -> MessagePtr {
727     auto reply = newReplyMessage(m);
728     Encode(reply, std::tuple<TestDBusWrapper::Variant<bool>>{ TestDBusWrapper::Variant<bool>{ false} });
729     return reply;
730   };
731 }
732 TestDBusWrapper::~TestDBusWrapper()
733 {
734   eina_shutdown();
735 }
736
737 TestDBusWrapper::ConnectionPtr TestDBusWrapper::eldbus_address_connection_get_impl(const std::string &addr)
738 {
739   return connection;
740 }
741
742 struct TestDBusWrapper::MessageIterImpl : public TestDBusWrapper::MessageIter {
743   MessagePtr msg;
744   Element *elem;
745   bool write;
746   std::list<Element>::iterator it;
747   MessageIterImpl(MessagePtr msg, Element *elem, bool write) : msg(std::move(msg)), elem(elem), write(write) {
748     if (!write) it = elem->get<ElementList>().begin();
749   }
750   MessageIterImpl(MessagePtr msg, Element *elem, bool write, std::list<Element>::iterator it) : msg(std::move(msg)), elem(elem), write(write), it(it) { }
751 };
752
753 struct TestDBusWrapper::MessageImpl : public TestDBusWrapper::Message {
754   std::string bus, path, interface, name;
755   Element data;
756   bool reply, error = false;
757   std::string error_a, error_b;
758
759   MessageImpl(std::string bus, std::string path, std::string interface, std::string name, bool reply) :
760     bus(std::move(bus)), path(std::move(path)), interface(std::move(interface)), name(std::move(name)), data{ ElementList{} }, reply(reply) { }
761   MessageImpl(std::string bus, std::string path, std::string interface, std::string name, std::string error_a, std::string error_b) :
762     bus(std::move(bus)), path(std::move(path)), interface(std::move(interface)), name(std::move(name)), data{ ElementList{} },
763     reply(true), error(true), error_a(std::move(error_a)), error_b(std::move(error_b)) { }
764 };
765
766 struct TestDBusWrapper::ProxyImpl : public TestDBusWrapper::Proxy {
767   std::string bus, path, interface;
768   ProxyImpl(std::string bus, std::string path, std::string interface) : bus(std::move(bus)), path(std::move(path)), interface(std::move(interface)) { }
769 };
770 struct TestDBusWrapper::ObjectImpl : public TestDBusWrapper::Object {
771   std::string bus, path;
772   ObjectImpl(std::string bus, std::string path) : bus(std::move(bus)), path(std::move(path)) { }
773 };
774 #define DEFINE_TYPE(name) TestDBusWrapper::name ## Impl *TestDBusWrapper::get(const name ## Ptr &v) { return static_cast<name ## Impl*>(v.get()); }
775   DEFINE_TYPE(Connection)
776   DEFINE_TYPE(Proxy)
777   DEFINE_TYPE(Object)
778   DEFINE_TYPE(Message)
779   DEFINE_TYPE(MessageIter)
780 #undef DEFINE_TYPE
781
782 template <typename T> void TestDBusWrapperAppendBasic(const TestDBusWrapper::MessageIterPtr &it, T src) {
783   auto m = TestDBusWrapper::get(it);
784   if (!m->write) throw TestDBusWrapper::error{};
785   if (!m->elem->isContainer()) throw TestDBusWrapper::error{};
786   m->elem->get<TestDBusWrapper::ElementList>().push_back(TestDBusWrapper::Element{ src });
787 }
788 template <typename T> bool TestDBusWrapperGetBasicAndNext(const TestDBusWrapper::MessageIterPtr &it, T &src) {
789   auto m = TestDBusWrapper::get(it);
790   if (m->write) throw TestDBusWrapper::error{};
791   if (!m->elem->isContainer()) return false;
792   auto &lst = m->elem->get<TestDBusWrapper::ElementList>();
793   if (m->it == lst.end()) return false;
794   if (!m->it->is<T>()) return false;
795   src = m->it->get<T>();
796   ++m->it;
797   return true;
798 }
799
800 #define eldbus_message_iter_arguments_append_impl_basic_impl(type_set, type_get, sig) \
801 void TestDBusWrapper::eldbus_message_iter_arguments_append_impl(const MessageIterPtr &it, type_set src) { \
802   TestDBusWrapperAppendBasic(it, src); \
803 } \
804 bool TestDBusWrapper::eldbus_message_iter_get_and_next_impl(const MessageIterPtr &it, type_get &dst) { \
805   return TestDBusWrapperGetBasicAndNext(it, dst); \
806 }
807 #define eldbus_message_iter_arguments_append_impl_basic(type, sig) \
808 eldbus_message_iter_arguments_append_impl_basic_impl(type, type, sig)
809
810 eldbus_message_iter_arguments_append_impl_basic(uint8_t, y)
811 eldbus_message_iter_arguments_append_impl_basic(uint16_t, q)
812 eldbus_message_iter_arguments_append_impl_basic(uint32_t, u)
813 eldbus_message_iter_arguments_append_impl_basic(uint64_t, t)
814 eldbus_message_iter_arguments_append_impl_basic(int16_t, n)
815 eldbus_message_iter_arguments_append_impl_basic(int32_t, i)
816 eldbus_message_iter_arguments_append_impl_basic(int64_t, x)
817 eldbus_message_iter_arguments_append_impl_basic(double, d)
818 eldbus_message_iter_arguments_append_impl_basic(bool, b)
819 eldbus_message_iter_arguments_append_impl_basic_impl(const std::string &, std::string, s)
820 eldbus_message_iter_arguments_append_impl_basic_impl(const ObjectPath &, ObjectPath, o)
821
822 #undef eldbus_message_iter_arguments_append_impl_basic
823 #undef eldbus_message_iter_arguments_append_impl_basic_impl
824
825 TestDBusWrapper::MessageIterPtr TestDBusWrapper::eldbus_message_iter_container_new_impl(const MessageIterPtr &it, int type, const std::string &sig) {
826   auto m = get(it);
827   if (!m->write) throw error{};
828   if (!m->elem->isContainer()) throw error{};
829   auto &lst = m->elem->get<ElementList>();
830   if (type == 'r' || type == 'e' || type == 'a' || type == 'v') {
831     lst.push_back({ ElementList{}, type });
832     return std::make_shared<MessageIterImpl>(MessageIterImpl{ m->msg, &lst.back(), true });
833   }
834   throw error{};
835 }
836
837 TestDBusWrapper::MessageIterPtr TestDBusWrapper::eldbus_message_iter_get_and_next_by_type_impl(const MessageIterPtr &it, int type) {
838   auto m = get(it);
839   if (m->write) throw error{};
840   if (!m->elem->isContainer()) throw error{} << "not a container";
841   auto &lst = m->elem->get<ElementList>();
842   if (m->it == lst.end()) return {};
843   if (m->it->signature() != type) return {};
844   auto v = std::make_shared<MessageIterImpl>(MessageIterImpl{ m->msg, &*m->it, false });
845   ++m->it;
846   return v;
847 }
848
849 TestDBusWrapper::MessageIterPtr TestDBusWrapper::eldbus_message_iter_get_impl(const MessagePtr &it, bool write) {
850   auto m = get(it);
851   return std::make_shared<MessageIterImpl>(MessageIterImpl{ it, &m->data, write, m->data.get<ElementList>().begin() });
852 }
853
854 bool TestDBusWrapper::completed(const MessageIterPtr &iter)
855 {
856   auto m = get(iter);
857   assert(!m->write);
858   return m->it == m->elem->get<ElementList>().end();
859 }
860
861 TestDBusWrapper::MessagePtr TestDBusWrapper::eldbus_proxy_method_call_new_impl(const ProxyPtr &proxy, const std::string &funcName) {
862   auto p = get(proxy);
863   return std::make_shared<MessageImpl>(MessageImpl{
864     p->bus, p->path, p->interface, funcName, false
865   });
866 }
867 TestDBusWrapper::MessagePtr TestDBusWrapper::call(
868     std::unordered_map<std::tuple<std::string, std::string, std::string, MethodType>, std::function<MessagePtr(const MessagePtr&)>> &mp,
869     const std::string &mpName, const MessagePtr &msg, MethodType type) {
870   auto m = get(msg);
871   auto findMethod = [&](std::string path, const std::string &iname, const std::string &name, MethodType type) {
872     if (path.empty()) throw error{};
873     if (path[0] != '/') {
874       path = "/org/a11y/atspi/accessible/" + path;
875       m->path = path;
876     }
877     while(!path.empty()) {
878       auto it = mp.find(std::tuple<std::string, std::string, std::string, MethodType> { path, iname, name, type });
879       if (it != mp.end()) return it;
880       auto index = path.rfind('/');
881       if (index == std::string::npos) break;
882       path.resize(index);
883     }
884     return mp.end();
885   };
886   std::string iname, name;
887   if (type == MethodType::Method && m->interface == "org.freedesktop.DBus.Properties") {
888     type = m->name == "Get" ? MethodType::Getter : MethodType::Setter;
889     auto &lst = m->data.get<ElementList>();
890     assert(lst.size() >= 2);
891     iname = lst.front().get<std::string>();
892     lst.pop_front();
893     name = lst.front().get<std::string>();
894     lst.pop_front();
895   }
896   else {
897     iname = m->interface;
898     name = m->name;
899   }
900   auto it = findMethod(m->path, iname, name, type);
901   if (it == mp.end()) {
902     const char *mt;
903     if (type == MethodType::Method) mt = "MethodType::Method";
904     else if (type == MethodType::Getter) mt = "MethodType::Getter";
905     else if (type == MethodType::Setter) mt = "MethodType::Setter";
906     else assert(0);
907     throw error{} << "missing {\"" << m->path << "\", \"" << iname << "\", \"" << name << "\", " << mt << "} in " << mpName;
908   }
909   DBus::DBusServer::CurrentObjectSetter setter{ connection, m->path };
910   return it->second(msg);
911 }
912 TestDBusWrapper::MessagePtr TestDBusWrapper::eldbus_proxy_send_and_block_impl(const ProxyPtr &proxy, const MessagePtr &msg) {
913 // BART
914 //  auto p = get(proxy);
915 //  auto m = get(msg);
916 //  assert(p->bus == m->bus);
917 //  assert(p->path == m->path);
918 //  assert(p->interface == m->interface);
919   return call(testMethods, "testMethods", msg, MethodType::Method);
920 }
921
922 bool TestDBusWrapper::eldbus_message_error_get_impl(const MessagePtr &msg, std::string &name, std::string &text) {
923   auto m = get(msg);
924   name = m->error_a;
925   text = m->error_b;
926   return m->error;
927 }
928 static void calculate_signature(std::ostringstream &ostr, TestDBusWrapper::Element &e)
929 {
930   ostr << static_cast<char>(e.signature());
931   if (e.isContainer()) {
932     ostr << "(";
933     auto &lst = e.get<TestDBusWrapper::ElementList>();
934     for(auto &q : lst) calculate_signature(ostr, q);
935     ostr << ")";
936   }
937 }
938 std::string TestDBusWrapper::eldbus_message_signature_get_impl(const MessagePtr &msg) {
939   auto m = get(msg);
940   std::ostringstream ostr;
941   for(auto &q : m->data.get<ElementList>())
942     calculate_signature(ostr, q);
943   return ostr.str();
944 }
945 TestDBusWrapper::PendingPtr TestDBusWrapper::eldbus_proxy_send_impl(const ProxyPtr &proxy, const MessagePtr &msg, const SendCallback &callback) {
946 // BART
947 //  auto p = get(proxy);
948 //  auto m = get(msg);
949 //  assert(p->bus == m->bus);
950 //  assert(p->path == m->path);
951 //  assert(p->interface == m->interface);
952   asyncCalls.push_back([this, msg, callback]() {
953     auto r = call(testMethods, "testMethods", msg, MethodType::Method);
954     callback(r);
955   });
956   return {};
957 }
958 std::string TestDBusWrapper::eldbus_proxy_interface_get_impl(const ProxyPtr &proxy) {
959   auto p = get(proxy);
960   return p->interface;
961 }
962 void TestDBusWrapper::eldbus_proxy_signal_handler_add_impl(const ProxyPtr &proxy, const std::string &member, const std::function<void(const MessagePtr &)> &cb) {
963   auto p = get(proxy);
964   daliSignals[std::tuple<std::string, std::string, std::string> { p->path, p->interface, member }] = cb;
965 }
966 std::string TestDBusWrapper::eldbus_message_iter_signature_get_impl(const MessageIterPtr &iter) {
967   auto m = get(iter);
968   if (m->write) throw error{};
969   if (!m->elem->isContainer()) throw error{};
970   std::ostringstream ostr;
971   auto &lst = m->elem->get<ElementList>();
972   for(auto it = m->it; it != lst.end(); ++it)
973     calculate_signature(ostr, *it);
974   return ostr.str();
975 }
976 TestDBusWrapper::MessagePtr TestDBusWrapper::eldbus_message_method_return_new_impl( const MessagePtr &msg) {
977   auto m = get(msg);
978   return std::make_shared<MessageImpl>(MessageImpl{
979     m->bus, m->path, m->interface, m->name, true
980   });
981 }
982 TestDBusWrapper::MessagePtr TestDBusWrapper::eldbus_message_error_new_impl( const MessagePtr &msg, const std::string &err, const std::string &txt ) {
983   auto m = get(msg);
984   return std::make_shared<MessageImpl>(MessageImpl{
985     m->bus, m->path, m->interface, m->name, err, txt
986   });
987 }
988 TestDBusWrapper::PendingPtr TestDBusWrapper::eldbus_connection_send_impl(const ConnectionPtr &conn, const MessagePtr &msg) {
989   call(testMethods, "testMethods", msg, MethodType::Method);
990   return {};
991 }
992 std::shared_ptr<Eina_Value> TestDBusWrapper::createEinaValue(bool b) {
993   Eina_Value *value = eina_value_new(EINA_VALUE_TYPE_UCHAR);
994   eina_value_set(value, b);
995   return std::shared_ptr<Eina_Value>(value, [](Eina_Value *v) {
996     eina_value_free(v);
997   });
998 }
999
1000 TestDBusWrapper::MessagePtr TestDBusWrapper::newMessage(const std::string &path, const std::string &interface, const std::string &name, bool reply) {
1001   return std::make_shared<MessageImpl>(MessageImpl{
1002     "bus", path, interface, name, reply
1003   });
1004 }
1005
1006 TestDBusWrapper::MessagePtr TestDBusWrapper::newReplyMessage(const MessagePtr &msg) {
1007   auto m = get(msg);
1008   return newMessage(m->path, m->interface, m->name, true);
1009 }
1010
1011 TestDBusWrapper::MessagePtr TestDBusWrapper::eldbus_message_signal_new_impl(const std::string &path, const std::string &iface, const std::string &name) {
1012   return std::make_shared<MessageImpl>(MessageImpl{
1013     "bus", path, iface, name, true
1014   });
1015 }
1016 TestDBusWrapper::MessagePtr TestDBusWrapper::eldbus_message_ref_impl(const MessagePtr &msg) {
1017   return msg;
1018 }
1019 TestDBusWrapper::ConnectionPtr TestDBusWrapper::eldbus_connection_get_impl(ConnectionType type) {
1020   return connection;
1021 }
1022 std::string TestDBusWrapper::eldbus_connection_unique_name_get_impl(const ConnectionPtr &conn) {
1023   return "bus";
1024 }
1025 TestDBusWrapper::ObjectPtr TestDBusWrapper::eldbus_object_get_impl( const ConnectionPtr &conn, const std::string &bus, const std::string &path ) {
1026   return std::make_shared<ObjectImpl>(ObjectImpl{
1027     bus, path
1028   });
1029 }
1030 TestDBusWrapper::ProxyPtr TestDBusWrapper::eldbus_proxy_get_impl( const ObjectPtr &obj, const std::string &interface ) {
1031   auto o = get(obj);
1032   return std::make_shared<ProxyImpl>(ProxyImpl{ o->bus, o->path, interface });
1033 }
1034 TestDBusWrapper::ProxyPtr TestDBusWrapper::eldbus_proxy_copy_impl( const ProxyPtr &ptr) {
1035   return ptr;
1036 }
1037 void TestDBusWrapper::add_property_changed_event_listener_impl( const ProxyPtr &proxy, const std::string &interface, const std::string &name, std::function< void( const Eina_Value * ) > cb) {
1038   auto p = get(proxy);
1039   propertyChangeListeners[std::tuple<std::string, std::string, std::string>{ p->path, interface, name }] = cb;
1040 }
1041 void TestDBusWrapper::add_interface_impl( bool fallback, const std::string& path_,
1042                             const ConnectionPtr &connection,
1043                             std::vector<std::function<void()>> &destructors,
1044                             const std::string& interface,
1045                             std::vector< MethodInfo >& dscrMethods,
1046                             std::vector< PropertyInfo >& dscrProperties,
1047                             std::vector< SignalInfo >& dscrSignals ) {
1048   std::string bus = "bus";
1049   std::string path = path_;
1050   while(!path.empty() && path.back() == '/') path.pop_back();
1051   for(auto &m : dscrMethods) {
1052     auto key = std::make_tuple( "/org/a11y/atspi/accessible" + path, interface, m.memberName, MethodType::Method );
1053     daliMethods[key] = m.callback;
1054   }
1055   for(auto &m : dscrProperties) {
1056     auto key = std::make_tuple( "/org/a11y/atspi/accessible" + path, interface, m.memberName, MethodType::Getter );
1057     daliMethods[key] = [=](const MessagePtr &msg) -> MessagePtr {
1058       auto ret = std::make_shared<MessageImpl>(MessageImpl{
1059         "bus", path, interface, m.memberName, true
1060       });
1061       auto v = m.getCallback(msg, std::make_shared<MessageIterImpl>(MessageIterImpl{ ret, &ret->data, true }));
1062       ret->error = !v.empty();
1063       if (ret->error) {
1064         ret->error_a = "call failed";
1065         ret->error_b = std::move(v);
1066       }
1067       return ret;
1068     };
1069     std::get<3>(key) = MethodType::Setter;
1070     daliMethods[key] = [=](const MessagePtr &msg) -> MessagePtr {
1071       auto v = m.setCallback(msg, std::make_shared<MessageIterImpl>(MessageIterImpl{ msg, &get(msg)->data, false }));
1072       return v.empty() ? std::make_shared<MessageImpl>(MessageImpl{
1073         "bus", path, interface, m.memberName, true,
1074       }) : std::make_shared<MessageImpl>(MessageImpl{
1075         "bus", path, interface, m.memberName, "call failed", v
1076       });
1077        // interface is probably wrong, due to retarded way properties are handlded by dbus
1078     };
1079   }
1080   for(auto &m : dscrSignals) {
1081     daliSignalsMap[std::tuple<std::string, std::string, unsigned int>{ "/org/a11y/atspi/accessible" + path, interface, m.uniqueId }] = m.memberName;
1082   }
1083 }
1084
1085 /// \endcond