[dali_2.3.19] Merge branch 'devel/master'
[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         {
670           std::lock_guard< std::mutex > lock( globalEntriesMutex );
671           globalEntries.erase( v );
672         }
673         eldbus_service_interface_unregister( v );
674       });
675     }
676   }
677   static void listenerEventChangedCallback( void* data, Eldbus_Proxy* proxy EINA_UNUSED, void* event )
678   {
679     auto p = static_cast< std::function< void( Eldbus_Proxy_Event_Property_Changed* ) >* >( data );
680     ( *p )( static_cast< Eldbus_Proxy_Event_Property_Changed* >( event ) );
681   }
682   static void ProxyEventCallbackDelCb( void* data, const void *obj )
683   {
684     auto d = static_cast< std::function< void( Eldbus_Proxy_Event_Property_Changed* ) >* >( data );
685     delete d;
686   }
687   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 {
688     auto callbackLambdaPtr = new std::function< void( Eldbus_Proxy_Event_Property_Changed *epc ) >{
689       [cb, name, interface]( Eldbus_Proxy_Event_Property_Changed *ev ) {
690       const char* ifc = eldbus_proxy_interface_get( ev->proxy );
691       if( ev->name && ev->name == name && ifc && interface == ifc )
692       {
693         cb(ev->value);
694       }
695     } };
696     auto p = get(proxy);
697     eldbus_proxy_event_callback_add( p, ELDBUS_PROXY_EVENT_PROPERTY_CHANGED,
698                                      listenerEventChangedCallback, callbackLambdaPtr );
699     eldbus_proxy_free_cb_add( p, ProxyEventCallbackDelCb, callbackLambdaPtr );
700   }
701 };
702
703 std::unordered_map< const Eldbus_Service_Interface*, std::unique_ptr< DefaultDBusWrapper::Implementation > > DefaultDBusWrapper::globalEntries;
704 std::mutex DefaultDBusWrapper::globalEntriesMutex;
705
706 DBusWrapper *DBusWrapper::Installed()
707 {
708   if (!InstalledWrapper)
709     InstalledWrapper.reset(new DefaultDBusWrapper);
710   return InstalledWrapper.get();
711 }
712
713 void DBusWrapper::Install(std::unique_ptr<DBusWrapper> w)
714 {
715   InstalledWrapper = std::move(w);
716 }
717
718
719 struct TestDBusWrapper::ConnectionImpl : public TestDBusWrapper::Connection {
720 };
721
722 TestDBusWrapper::TestDBusWrapper()
723 {
724   eina_init();
725   connection = std::make_shared<ConnectionImpl>();
726   testMethods[std::tuple<std::string, std::string, std::string, MethodType>{"/org/a11y/bus", "org.a11y.Status", "ScreenReaderEnabled", MethodType::Getter}] =
727   testMethods[std::tuple<std::string, std::string, std::string, MethodType>{"/org/a11y/bus", "org.a11y.Status", "IsEnabled", MethodType::Getter}] =
728   [this](const DBusWrapper::MessagePtr &m) -> MessagePtr {
729     auto reply = newReplyMessage(m);
730     Encode(reply, std::tuple<TestDBusWrapper::Variant<bool>>{ TestDBusWrapper::Variant<bool>{ false} });
731     return reply;
732   };
733 }
734 TestDBusWrapper::~TestDBusWrapper()
735 {
736   eina_shutdown();
737 }
738
739 TestDBusWrapper::ConnectionPtr TestDBusWrapper::eldbus_address_connection_get_impl(const std::string &addr)
740 {
741   return connection;
742 }
743
744 struct TestDBusWrapper::MessageIterImpl : public TestDBusWrapper::MessageIter {
745   MessagePtr msg;
746   Element *elem;
747   bool write;
748   std::list<Element>::iterator it;
749   MessageIterImpl(MessagePtr msg, Element *elem, bool write) : msg(std::move(msg)), elem(elem), write(write) {
750     if (!write) it = elem->get<ElementList>().begin();
751   }
752   MessageIterImpl(MessagePtr msg, Element *elem, bool write, std::list<Element>::iterator it) : msg(std::move(msg)), elem(elem), write(write), it(it) { }
753 };
754
755 struct TestDBusWrapper::MessageImpl : public TestDBusWrapper::Message {
756   std::string bus, path, interface, name;
757   Element data;
758   bool reply, error = false;
759   std::string error_a, error_b;
760
761   MessageImpl(std::string bus, std::string path, std::string interface, std::string name, bool reply) :
762     bus(std::move(bus)), path(std::move(path)), interface(std::move(interface)), name(std::move(name)), data{ ElementList{} }, reply(reply) { }
763   MessageImpl(std::string bus, std::string path, std::string interface, std::string name, std::string error_a, std::string error_b) :
764     bus(std::move(bus)), path(std::move(path)), interface(std::move(interface)), name(std::move(name)), data{ ElementList{} },
765     reply(true), error(true), error_a(std::move(error_a)), error_b(std::move(error_b)) { }
766 };
767
768 struct TestDBusWrapper::ProxyImpl : public TestDBusWrapper::Proxy {
769   std::string bus, path, interface;
770   ProxyImpl(std::string bus, std::string path, std::string interface) : bus(std::move(bus)), path(std::move(path)), interface(std::move(interface)) { }
771 };
772 struct TestDBusWrapper::ObjectImpl : public TestDBusWrapper::Object {
773   std::string bus, path;
774   ObjectImpl(std::string bus, std::string path) : bus(std::move(bus)), path(std::move(path)) { }
775 };
776 #define DEFINE_TYPE(name) TestDBusWrapper::name ## Impl *TestDBusWrapper::get(const name ## Ptr &v) { return static_cast<name ## Impl*>(v.get()); }
777   DEFINE_TYPE(Connection)
778   DEFINE_TYPE(Proxy)
779   DEFINE_TYPE(Object)
780   DEFINE_TYPE(Message)
781   DEFINE_TYPE(MessageIter)
782 #undef DEFINE_TYPE
783
784 template <typename T> void TestDBusWrapperAppendBasic(const TestDBusWrapper::MessageIterPtr &it, T src) {
785   auto m = TestDBusWrapper::get(it);
786   if (!m->write) throw TestDBusWrapper::error{};
787   if (!m->elem->isContainer()) throw TestDBusWrapper::error{};
788   m->elem->get<TestDBusWrapper::ElementList>().push_back(TestDBusWrapper::Element{ src });
789 }
790 template <typename T> bool TestDBusWrapperGetBasicAndNext(const TestDBusWrapper::MessageIterPtr &it, T &src) {
791   auto m = TestDBusWrapper::get(it);
792   if (m->write) throw TestDBusWrapper::error{};
793   if (!m->elem->isContainer()) return false;
794   auto &lst = m->elem->get<TestDBusWrapper::ElementList>();
795   if (m->it == lst.end()) return false;
796   if (!m->it->is<T>()) return false;
797   src = m->it->get<T>();
798   ++m->it;
799   return true;
800 }
801
802 #define eldbus_message_iter_arguments_append_impl_basic_impl(type_set, type_get, sig) \
803 void TestDBusWrapper::eldbus_message_iter_arguments_append_impl(const MessageIterPtr &it, type_set src) { \
804   TestDBusWrapperAppendBasic(it, src); \
805 } \
806 bool TestDBusWrapper::eldbus_message_iter_get_and_next_impl(const MessageIterPtr &it, type_get &dst) { \
807   return TestDBusWrapperGetBasicAndNext(it, dst); \
808 }
809 #define eldbus_message_iter_arguments_append_impl_basic(type, sig) \
810 eldbus_message_iter_arguments_append_impl_basic_impl(type, type, sig)
811
812 eldbus_message_iter_arguments_append_impl_basic(uint8_t, y)
813 eldbus_message_iter_arguments_append_impl_basic(uint16_t, q)
814 eldbus_message_iter_arguments_append_impl_basic(uint32_t, u)
815 eldbus_message_iter_arguments_append_impl_basic(uint64_t, t)
816 eldbus_message_iter_arguments_append_impl_basic(int16_t, n)
817 eldbus_message_iter_arguments_append_impl_basic(int32_t, i)
818 eldbus_message_iter_arguments_append_impl_basic(int64_t, x)
819 eldbus_message_iter_arguments_append_impl_basic(double, d)
820 eldbus_message_iter_arguments_append_impl_basic(bool, b)
821 eldbus_message_iter_arguments_append_impl_basic_impl(const std::string &, std::string, s)
822 eldbus_message_iter_arguments_append_impl_basic_impl(const ObjectPath &, ObjectPath, o)
823
824 #undef eldbus_message_iter_arguments_append_impl_basic
825 #undef eldbus_message_iter_arguments_append_impl_basic_impl
826
827 TestDBusWrapper::MessageIterPtr TestDBusWrapper::eldbus_message_iter_container_new_impl(const MessageIterPtr &it, int type, const std::string &sig) {
828   auto m = get(it);
829   if (!m->write) throw error{};
830   if (!m->elem->isContainer()) throw error{};
831   auto &lst = m->elem->get<ElementList>();
832   if (type == 'r' || type == 'e' || type == 'a' || type == 'v') {
833     lst.push_back({ ElementList{}, type });
834     return std::make_shared<MessageIterImpl>(MessageIterImpl{ m->msg, &lst.back(), true });
835   }
836   throw error{};
837 }
838
839 TestDBusWrapper::MessageIterPtr TestDBusWrapper::eldbus_message_iter_get_and_next_by_type_impl(const MessageIterPtr &it, int type) {
840   auto m = get(it);
841   if (m->write) throw error{};
842   if (!m->elem->isContainer()) throw error{} << "not a container";
843   auto &lst = m->elem->get<ElementList>();
844   if (m->it == lst.end()) return {};
845   if (m->it->signature() != type) return {};
846   auto v = std::make_shared<MessageIterImpl>(MessageIterImpl{ m->msg, &*m->it, false });
847   ++m->it;
848   return v;
849 }
850
851 TestDBusWrapper::MessageIterPtr TestDBusWrapper::eldbus_message_iter_get_impl(const MessagePtr &it, bool write) {
852   auto m = get(it);
853   return std::make_shared<MessageIterImpl>(MessageIterImpl{ it, &m->data, write, m->data.get<ElementList>().begin() });
854 }
855
856 bool TestDBusWrapper::completed(const MessageIterPtr &iter)
857 {
858   auto m = get(iter);
859   assert(!m->write);
860   return m->it == m->elem->get<ElementList>().end();
861 }
862
863 TestDBusWrapper::MessagePtr TestDBusWrapper::eldbus_proxy_method_call_new_impl(const ProxyPtr &proxy, const std::string &funcName) {
864   auto p = get(proxy);
865   return std::make_shared<MessageImpl>(MessageImpl{
866     p->bus, p->path, p->interface, funcName, false
867   });
868 }
869 TestDBusWrapper::MessagePtr TestDBusWrapper::call(
870     std::unordered_map<std::tuple<std::string, std::string, std::string, MethodType>, std::function<MessagePtr(const MessagePtr&)>> &mp,
871     const std::string &mpName, const MessagePtr &msg, MethodType type) {
872   auto m = get(msg);
873   auto findMethod = [&](std::string path, const std::string &iname, const std::string &name, MethodType type) {
874     if (path.empty()) throw error{};
875     if (path[0] != '/') {
876       path = "/org/a11y/atspi/accessible/" + path;
877       m->path = path;
878     }
879     while(!path.empty()) {
880       auto it = mp.find(std::tuple<std::string, std::string, std::string, MethodType> { path, iname, name, type });
881       if (it != mp.end()) return it;
882       auto index = path.rfind('/');
883       if (index == std::string::npos) break;
884       path.resize(index);
885     }
886     return mp.end();
887   };
888   std::string iname, name;
889   if (type == MethodType::Method && m->interface == "org.freedesktop.DBus.Properties") {
890     type = m->name == "Get" ? MethodType::Getter : MethodType::Setter;
891     auto &lst = m->data.get<ElementList>();
892     assert(lst.size() >= 2);
893     iname = lst.front().get<std::string>();
894     lst.pop_front();
895     name = lst.front().get<std::string>();
896     lst.pop_front();
897   }
898   else {
899     iname = m->interface;
900     name = m->name;
901   }
902   auto it = findMethod(m->path, iname, name, type);
903   if (it == mp.end()) {
904     const char *mt;
905     if (type == MethodType::Method) mt = "MethodType::Method";
906     else if (type == MethodType::Getter) mt = "MethodType::Getter";
907     else if (type == MethodType::Setter) mt = "MethodType::Setter";
908     else assert(0);
909     throw error{} << "missing {\"" << m->path << "\", \"" << iname << "\", \"" << name << "\", " << mt << "} in " << mpName;
910   }
911   DBus::DBusServer::CurrentObjectSetter setter{ connection, m->path };
912   return it->second(msg);
913 }
914 TestDBusWrapper::MessagePtr TestDBusWrapper::eldbus_proxy_send_and_block_impl(const ProxyPtr &proxy, const MessagePtr &msg) {
915 // BART
916 //  auto p = get(proxy);
917 //  auto m = get(msg);
918 //  assert(p->bus == m->bus);
919 //  assert(p->path == m->path);
920 //  assert(p->interface == m->interface);
921   return call(testMethods, "testMethods", msg, MethodType::Method);
922 }
923
924 bool TestDBusWrapper::eldbus_message_error_get_impl(const MessagePtr &msg, std::string &name, std::string &text) {
925   auto m = get(msg);
926   name = m->error_a;
927   text = m->error_b;
928   return m->error;
929 }
930 static void calculate_signature(std::ostringstream &ostr, TestDBusWrapper::Element &e)
931 {
932   ostr << static_cast<char>(e.signature());
933   if (e.isContainer()) {
934     ostr << "(";
935     auto &lst = e.get<TestDBusWrapper::ElementList>();
936     for(auto &q : lst) calculate_signature(ostr, q);
937     ostr << ")";
938   }
939 }
940 std::string TestDBusWrapper::eldbus_message_signature_get_impl(const MessagePtr &msg) {
941   auto m = get(msg);
942   std::ostringstream ostr;
943   for(auto &q : m->data.get<ElementList>())
944     calculate_signature(ostr, q);
945   return ostr.str();
946 }
947 TestDBusWrapper::PendingPtr TestDBusWrapper::eldbus_proxy_send_impl(const ProxyPtr &proxy, const MessagePtr &msg, const SendCallback &callback) {
948 // BART
949 //  auto p = get(proxy);
950 //  auto m = get(msg);
951 //  assert(p->bus == m->bus);
952 //  assert(p->path == m->path);
953 //  assert(p->interface == m->interface);
954   asyncCalls.push_back([this, msg, callback]() {
955     auto r = call(testMethods, "testMethods", msg, MethodType::Method);
956     callback(r);
957   });
958   return {};
959 }
960 std::string TestDBusWrapper::eldbus_proxy_interface_get_impl(const ProxyPtr &proxy) {
961   auto p = get(proxy);
962   return p->interface;
963 }
964 void TestDBusWrapper::eldbus_proxy_signal_handler_add_impl(const ProxyPtr &proxy, const std::string &member, const std::function<void(const MessagePtr &)> &cb) {
965   auto p = get(proxy);
966   daliSignals[std::tuple<std::string, std::string, std::string> { p->path, p->interface, member }] = cb;
967 }
968 std::string TestDBusWrapper::eldbus_message_iter_signature_get_impl(const MessageIterPtr &iter) {
969   auto m = get(iter);
970   if (m->write) throw error{};
971   if (!m->elem->isContainer()) throw error{};
972   std::ostringstream ostr;
973   auto &lst = m->elem->get<ElementList>();
974   for(auto it = m->it; it != lst.end(); ++it)
975     calculate_signature(ostr, *it);
976   return ostr.str();
977 }
978 TestDBusWrapper::MessagePtr TestDBusWrapper::eldbus_message_method_return_new_impl( const MessagePtr &msg) {
979   auto m = get(msg);
980   return std::make_shared<MessageImpl>(MessageImpl{
981     m->bus, m->path, m->interface, m->name, true
982   });
983 }
984 TestDBusWrapper::MessagePtr TestDBusWrapper::eldbus_message_error_new_impl( const MessagePtr &msg, const std::string &err, const std::string &txt ) {
985   auto m = get(msg);
986   return std::make_shared<MessageImpl>(MessageImpl{
987     m->bus, m->path, m->interface, m->name, err, txt
988   });
989 }
990 TestDBusWrapper::PendingPtr TestDBusWrapper::eldbus_connection_send_impl(const ConnectionPtr &conn, const MessagePtr &msg) {
991   call(testMethods, "testMethods", msg, MethodType::Method);
992   return {};
993 }
994 std::shared_ptr<Eina_Value> TestDBusWrapper::createEinaValue(bool b) {
995   Eina_Value *value = eina_value_new(EINA_VALUE_TYPE_UCHAR);
996   eina_value_set(value, b);
997   return std::shared_ptr<Eina_Value>(value, [](Eina_Value *v) {
998     eina_value_free(v);
999   });
1000 }
1001
1002 TestDBusWrapper::MessagePtr TestDBusWrapper::newMessage(const std::string &path, const std::string &interface, const std::string &name, bool reply) {
1003   return std::make_shared<MessageImpl>(MessageImpl{
1004     "bus", path, interface, name, reply
1005   });
1006 }
1007
1008 TestDBusWrapper::MessagePtr TestDBusWrapper::newReplyMessage(const MessagePtr &msg) {
1009   auto m = get(msg);
1010   return newMessage(m->path, m->interface, m->name, true);
1011 }
1012
1013 TestDBusWrapper::MessagePtr TestDBusWrapper::eldbus_message_signal_new_impl(const std::string &path, const std::string &iface, const std::string &name) {
1014   return std::make_shared<MessageImpl>(MessageImpl{
1015     "bus", path, iface, name, true
1016   });
1017 }
1018 TestDBusWrapper::MessagePtr TestDBusWrapper::eldbus_message_ref_impl(const MessagePtr &msg) {
1019   return msg;
1020 }
1021 TestDBusWrapper::ConnectionPtr TestDBusWrapper::eldbus_connection_get_impl(ConnectionType type) {
1022   return connection;
1023 }
1024 std::string TestDBusWrapper::eldbus_connection_unique_name_get_impl(const ConnectionPtr &conn) {
1025   return "bus";
1026 }
1027 TestDBusWrapper::ObjectPtr TestDBusWrapper::eldbus_object_get_impl( const ConnectionPtr &conn, const std::string &bus, const std::string &path ) {
1028   return std::make_shared<ObjectImpl>(ObjectImpl{
1029     bus, path
1030   });
1031 }
1032 TestDBusWrapper::ProxyPtr TestDBusWrapper::eldbus_proxy_get_impl( const ObjectPtr &obj, const std::string &interface ) {
1033   auto o = get(obj);
1034   return std::make_shared<ProxyImpl>(ProxyImpl{ o->bus, o->path, interface });
1035 }
1036 TestDBusWrapper::ProxyPtr TestDBusWrapper::eldbus_proxy_copy_impl( const ProxyPtr &ptr) {
1037   return ptr;
1038 }
1039 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) {
1040   auto p = get(proxy);
1041   propertyChangeListeners[std::tuple<std::string, std::string, std::string>{ p->path, interface, name }] = cb;
1042 }
1043 void TestDBusWrapper::add_interface_impl( bool fallback, const std::string& path_,
1044                             const ConnectionPtr &connection,
1045                             std::vector<std::function<void()>> &destructors,
1046                             const std::string& interface,
1047                             std::vector< MethodInfo >& dscrMethods,
1048                             std::vector< PropertyInfo >& dscrProperties,
1049                             std::vector< SignalInfo >& dscrSignals ) {
1050   std::string bus = "bus";
1051   std::string path = path_;
1052   while(!path.empty() && path.back() == '/') path.pop_back();
1053   for(auto &m : dscrMethods) {
1054     auto key = std::make_tuple( "/org/a11y/atspi/accessible" + path, interface, m.memberName, MethodType::Method );
1055     daliMethods[key] = m.callback;
1056   }
1057   for(auto &m : dscrProperties) {
1058     auto key = std::make_tuple( "/org/a11y/atspi/accessible" + path, interface, m.memberName, MethodType::Getter );
1059     daliMethods[key] = [=](const MessagePtr &msg) -> MessagePtr {
1060       auto ret = std::make_shared<MessageImpl>(MessageImpl{
1061         "bus", path, interface, m.memberName, true
1062       });
1063       auto v = m.getCallback(msg, std::make_shared<MessageIterImpl>(MessageIterImpl{ ret, &ret->data, true }));
1064       ret->error = !v.empty();
1065       if (ret->error) {
1066         ret->error_a = "call failed";
1067         ret->error_b = std::move(v);
1068       }
1069       return ret;
1070     };
1071     std::get<3>(key) = MethodType::Setter;
1072     daliMethods[key] = [=](const MessagePtr &msg) -> MessagePtr {
1073       auto v = m.setCallback(msg, std::make_shared<MessageIterImpl>(MessageIterImpl{ msg, &get(msg)->data, false }));
1074       return v.empty() ? std::make_shared<MessageImpl>(MessageImpl{
1075         "bus", path, interface, m.memberName, true,
1076       }) : std::make_shared<MessageImpl>(MessageImpl{
1077         "bus", path, interface, m.memberName, "call failed", v
1078       });
1079        // interface is probably wrong, due to retarded way properties are handlded by dbus
1080     };
1081   }
1082   for(auto &m : dscrSignals) {
1083     daliSignalsMap[std::tuple<std::string, std::string, unsigned int>{ "/org/a11y/atspi/accessible" + path, interface, m.uniqueId }] = m.memberName;
1084   }
1085 }
1086
1087 /// \endcond