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