52014da16a7364d54ae441aaac858ebd631c9cc1
[platform/core/uifw/dali-adaptor.git] / dali / internal / accessibility / bridge / dbus / dbus-tizen.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/accessibility-common.h>
19 #include <dali/internal/accessibility/bridge/dbus/dbus.h>
20
21 // EXTERNAL INCLUDES
22 #include <iostream>
23 #include <mutex>
24 #include <sstream>
25
26 #include <Ecore_Input.h>
27 #include <Eldbus.h>
28
29 // INTERNAL INCLUDES
30 #include <dali/public-api/dali-adaptor-common.h>
31
32 #define DBUS_INTERFACE_PROPERTIES "org.freedesktop.DBus.Properties"
33
34 #undef EINA_FALSE
35 #undef EINA_TRUE
36 #define EINA_TRUE static_cast<Eina_Bool>(1)
37 #define EINA_FALSE static_cast<Eina_Bool>(0)
38
39 //#define DBUS_DEBUG(...) do { DBus::debugPrint(__FILE__, __LINE__, __VA_ARGS__); } while (0)
40
41 std::atomic<unsigned int>                       DBus::detail::CallId::LastId{0};
42 static std::function<void(const char*, size_t)> debugPrinter;
43 static std::mutex                               debugLock;
44
45 thread_local std::string                DBus::DBusServer::currentObjectPath;
46 thread_local DBusWrapper::ConnectionPtr DBus::DBusServer::currentConnection;
47
48 void DBus::setDebugPrinter(std::function<void(const char*, size_t)> printer)
49 {
50   std::lock_guard<std::mutex> lock(debugLock);
51   debugPrinter = std::move(printer);
52 }
53
54 void DBus::debugPrint(const char* file, size_t line, const char* format, ...)
55 {
56   std::function<void(const char*, size_t)> debugPrintFunc;
57   {
58     std::lock_guard<std::mutex> lock(debugLock);
59     if(!debugPrinter)
60       return;
61     debugPrintFunc = debugPrinter;
62   }
63   std::vector<char> buf(4096);
64   int               offset;
65   while(true)
66   {
67     offset = snprintf(buf.data(), buf.size(), "%s:%u: ", file, static_cast<unsigned int>(line));
68     if(offset < 0)
69       return;
70     if(static_cast<size_t>(offset) < buf.size())
71       break;
72     buf.resize(offset + 1);
73   }
74
75   while(true)
76   {
77     va_list args;
78     va_start(args, format);
79     int z = vsnprintf(buf.data() + offset, buf.size() - offset, format, args);
80     va_end(args);
81     if(z < 0)
82       return;
83     bool done = static_cast<size_t>(z) + static_cast<size_t>(offset) < buf.size();
84     buf.resize(static_cast<size_t>(z) + static_cast<size_t>(offset));
85     if(done)
86       break;
87   }
88   debugPrintFunc(buf.data(), buf.size());
89 }
90
91 DBusWrapper::ConnectionPtr DBus::getDBusConnectionByName(const std::string& name)
92 {
93   return DBUS_W->eldbus_address_connection_get_impl(name);
94 }
95
96 DBusWrapper::ConnectionPtr DBus::getDBusConnectionByType(ConnectionType connectionType)
97 {
98   return DBUS_W->eldbus_connection_get_impl(connectionType);
99 }
100
101 DBus::DBusClient::DBusClient(std::string busName, std::string pathName, std::string interfaceName, ConnectionType tp)
102 : 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
114   if (!connectionState->connection)
115   {
116     DALI_LOG_ERROR("DBusClient connection is not ready\n");
117     return;
118   }
119
120   connectionState->object = DBUS_W->eldbus_object_get_impl(connectionState->connection, busName.c_str(), pathName.c_str());
121   if(connectionState->object)
122   {
123     connectionState->proxy = DBUS_W->eldbus_proxy_get_impl(connectionState->object, interfaceName);
124     if(interfaceName != DBUS_INTERFACE_PROPERTIES)
125     {
126       connectionState->propertiesProxy = DBUS_W->eldbus_proxy_get_impl(connectionState->object, DBUS_INTERFACE_PROPERTIES);
127     }
128     else
129     {
130       connectionState->propertiesProxy = DBUS_W->eldbus_proxy_copy_impl(connectionState->proxy);
131     }
132   }
133   connectionInfo                = std::make_shared<ConnectionInfo>();
134   connectionInfo->busName       = std::move(busName);
135   connectionInfo->pathName      = std::move(pathName);
136   connectionInfo->interfaceName = std::move(interfaceName);
137 }
138
139 DBus::DBusServer::DBusServer(ConnectionType tp)
140 : 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)
153 : interfaceName(std::move(interfaceName))
154 {
155 }
156
157 void DBus::DBusServer::addInterface(const std::string& pathName, DBusInterfaceDescription& dscr, bool fallback)
158 {
159   DBUS_W->add_interface_impl(fallback, pathName, connection, destructorObject->destructors, dscr.interfaceName, dscr.methods, dscr.properties, dscr.signals);
160 }
161
162 std::string DBus::DBusServer::getBusName() const
163 {
164   return getConnectionName(connection);
165 }
166
167 std::string DBus::getConnectionName(const DBusWrapper::ConnectionPtr& c)
168 {
169   return DBUS_W->eldbus_connection_unique_name_get_impl(c);
170 }
171
172 void DBus::requestBusName(const DBusWrapper::ConnectionPtr& conn, const std::string& bus)
173 {
174   DBUS_W->eldbus_name_request_impl(conn, bus);
175 }
176
177 void DBus::releaseBusName(const DBusWrapper::ConnectionPtr& conn, const std::string& bus)
178 {
179   DBUS_W->eldbus_name_release_impl(conn, bus);
180 }
181
182 bool DBus::DBusClient::getFromEinaValue(const _Eina_Value* v, void* dst)
183 {
184   return eina_value_get(const_cast<Eina_Value*>(v), dst);
185 }
186
187 static std::unique_ptr<DBusWrapper> InstalledWrapper;
188
189 struct DefaultDBusWrapper : public DBusWrapper
190 {
191   constexpr static int ELDBUS_CALL_TIMEOUT = 1000;
192
193   DefaultDBusWrapper()
194   {
195   }
196
197   ~DefaultDBusWrapper()
198   {
199   }
200
201 #define DEFINE_GS(name, eldbus_name, unref_call)                                                   \
202   static eldbus_name* get(const std::shared_ptr<name>& a)                                          \
203   {                                                                                                \
204     return static_cast<name##Impl*>(a.get())->Value;                                               \
205   }                                                                                                \
206   static eldbus_name* release(const std::shared_ptr<name>& a)                                      \
207   {                                                                                                \
208     auto z                                   = static_cast<name##Impl*>(a.get())->Value;           \
209     static_cast<name##Impl*>(a.get())->Value = nullptr;                                            \
210     return z;                                                                                      \
211   }                                                                                                \
212   template<typename... ARGS>                                                                       \
213   static std::shared_ptr<name> create(const eldbus_name* v, ARGS&&... args)                        \
214   {                                                                                                \
215     return std::make_shared<name##Impl>(const_cast<eldbus_name*>(v), std::forward<ARGS>(args)...); \
216   }
217
218 #define DEFINE_TYPE(name, eldbus_name, unref_call)                                     \
219   struct name##Impl : public name                                                      \
220   {                                                                                    \
221     eldbus_name* Value       = nullptr;                                                \
222     bool         EraseOnExit = false;                                                  \
223     name##Impl(eldbus_name* Value, bool EraseOnExit = false): Value(Value),            \
224                                                               EraseOnExit(EraseOnExit) \
225     {                                                                                  \
226     }                                                                                  \
227     ~name##Impl()                                                                      \
228     {                                                                                  \
229       if(EraseOnExit && Value)                                                         \
230       {                                                                                \
231         unref_call;                                                                    \
232       }                                                                                \
233     }                                                                                  \
234   };                                                                                   \
235   DEFINE_GS(name, eldbus_name, unref_call)
236
237   struct ConnectionImpl : public Connection
238   {
239     Eldbus_Connection* Value       = nullptr;
240     bool               EraseOnExit = false;
241     ConnectionImpl(Eldbus_Connection* Value, bool EraseOnExit = false)
242     : Value(Value),
243       EraseOnExit(EraseOnExit)
244     {
245       ecore_event_init();
246       eldbus_init();
247     }
248
249     ~ConnectionImpl()
250     {
251       if(EraseOnExit && Value)
252       {
253         eldbus_connection_unref(Value);
254       }
255       eldbus_shutdown();
256       ecore_event_shutdown();
257     }
258   };
259
260   struct MessageIterImpl : public MessageIter
261   {
262     Eldbus_Message_Iter *Value = nullptr, *Parent = nullptr;
263     bool                 EraseOnExit = false;
264     MessageIterImpl(Eldbus_Message_Iter* Value, Eldbus_Message_Iter* Parent, bool EraseOnExit = false)
265     : Value(Value),
266       Parent(Parent),
267       EraseOnExit(EraseOnExit)
268     {
269     }
270
271     ~MessageIterImpl()
272     {
273       if(EraseOnExit && Value && Parent)
274       {
275         eldbus_message_iter_container_close(Parent, Value);
276       }
277     }
278   };
279
280   DEFINE_GS(Connection, Eldbus_Connection, )
281   DEFINE_GS(MessageIter, Eldbus_Message_Iter, )
282   DEFINE_TYPE(Message, Eldbus_Message, eldbus_message_unref(Value))
283   DEFINE_TYPE(Proxy, Eldbus_Proxy, )
284   DEFINE_TYPE(Object, Eldbus_Object, eldbus_object_unref(Value))
285   DEFINE_TYPE(Pending, Eldbus_Pending, )
286   DEFINE_TYPE(EventPropertyChanged, Eldbus_Proxy_Event_Property_Changed, )
287 #undef DEFINE_TYPE
288
289   std::shared_ptr<Connection> eldbus_address_connection_get_impl(const std::string& addr) override
290   {
291     eldbus_init();
292     auto p = eldbus_address_connection_get(addr.c_str());
293     auto w = create(p, true);
294     eldbus_shutdown();
295     return w;
296   }
297
298 #define eldbus_message_iter_arguments_append_impl_basic(type, sig)                            \
299   void eldbus_message_iter_arguments_append_impl(const MessageIterPtr& it, type src) override \
300   {                                                                                           \
301     eldbus_message_iter_arguments_append(get(it), #sig, src);                                 \
302   }                                                                                           \
303   bool eldbus_message_iter_get_and_next_impl(const MessageIterPtr& it, type& dst) override    \
304   {                                                                                           \
305     return eldbus_message_iter_get_and_next(get(it), (#sig)[0], &dst);                        \
306   }
307
308   // clang-format off
309   eldbus_message_iter_arguments_append_impl_basic(uint8_t, y)
310   eldbus_message_iter_arguments_append_impl_basic(uint16_t, q)
311   eldbus_message_iter_arguments_append_impl_basic(uint32_t, u)
312   eldbus_message_iter_arguments_append_impl_basic(uint64_t, t)
313   eldbus_message_iter_arguments_append_impl_basic(int16_t, n)
314   eldbus_message_iter_arguments_append_impl_basic(int32_t, i)
315   eldbus_message_iter_arguments_append_impl_basic(int64_t, x)
316   eldbus_message_iter_arguments_append_impl_basic(double, d)
317   // clang-format on
318
319 #undef eldbus_message_iter_arguments_append_impl_basic
320
321                   void eldbus_message_iter_arguments_append_impl(const MessageIterPtr& it, bool src) override
322   {
323     eldbus_message_iter_arguments_append(get(it), "b", src ? 1 : 0);
324   }
325
326   bool eldbus_message_iter_get_and_next_impl(const MessageIterPtr& it, bool& dst) override
327   {
328     unsigned char q;
329     auto          z = eldbus_message_iter_get_and_next(get(it), 'b', &q);
330     dst             = q != 0;
331     return z;
332   }
333
334   void eldbus_message_iter_arguments_append_impl(const MessageIterPtr& it, const std::string& src) override
335   {
336     eldbus_message_iter_arguments_append(get(it), "s", src.c_str());
337   }
338
339   bool eldbus_message_iter_get_and_next_impl(const MessageIterPtr& it, std::string& dst) override
340   {
341     auto        iter = get(it);
342     const char* q;
343     if(!eldbus_message_iter_get_and_next(iter, 's', &q))
344     {
345       if(!eldbus_message_iter_get_and_next(iter, 'o', &q))
346       {
347         return false;
348       }
349     }
350     dst = q;
351     return true;
352   }
353
354   void eldbus_message_iter_arguments_append_impl(const MessageIterPtr& it, const ObjectPath& src) override
355   {
356     eldbus_message_iter_arguments_append(get(it), "o", src.value.c_str());
357   }
358
359   bool eldbus_message_iter_get_and_next_impl(const MessageIterPtr& it, ObjectPath& dst) override
360   {
361     const char* q;
362     if(!eldbus_message_iter_get_and_next(get(it), 'o', &q))
363     {
364       return false;
365     }
366     dst.value = q;
367     return true;
368   }
369
370   MessageIterPtr eldbus_message_iter_container_new_impl(const MessageIterPtr& it, int type, const std::string& sig) override
371   {
372     auto z = eldbus_message_iter_container_new(get(it), type, !sig.empty() ? sig.c_str() : NULL);
373     return create(z, get(it), true);
374   }
375
376   MessageIterPtr eldbus_message_iter_get_and_next_by_type_impl(const MessageIterPtr& it, int type) override
377   {
378     Eldbus_Message_Iter* entry;
379     if(!eldbus_message_iter_get_and_next(get(it), type, &entry))
380     {
381       return {};
382     }
383     return create(entry, get(it), false);
384   }
385
386   MessageIterPtr eldbus_message_iter_get_impl(const MessagePtr& msg, bool) override
387   {
388     return create(eldbus_message_iter_get(get(msg)), nullptr, false);
389   }
390
391   MessagePtr eldbus_proxy_method_call_new_impl(const ProxyPtr& proxy, const std::string& funcName)
392   {
393     return create(eldbus_proxy_method_call_new(get(proxy), funcName.c_str()));
394   }
395
396   MessagePtr eldbus_proxy_send_and_block_impl(const ProxyPtr& proxy, const MessagePtr& msg) override
397   {
398     return create(eldbus_proxy_send_and_block(get(proxy), release(msg), ELDBUS_CALL_TIMEOUT));
399   }
400
401   bool eldbus_message_error_get_impl(const MessagePtr& msg, std::string& name, std::string& text) override
402   {
403     const char *errname, *errmsg;
404     if(eldbus_message_error_get(get(msg), &errname, &errmsg))
405     {
406       name = errname;
407       text = errmsg;
408       return true;
409     }
410     return false;
411   }
412
413   std::string eldbus_message_signature_get_impl(const MessagePtr& msg) override
414   {
415     return eldbus_message_signature_get(get(msg));
416   }
417
418   static void callAsyncCb(void* data, const Eldbus_Message* msg, Eldbus_Pending* pending)
419   {
420     auto d = static_cast<SendCallback*>(data);
421     (*d)(create(msg, false));
422   }
423
424   static void pendingFreeCb(void* data, const void*)
425   {
426     auto d = static_cast<SendCallback*>(data);
427     delete d;
428   }
429
430   static void listenerCallbackFree(void* data, const void*)
431   {
432     auto d = static_cast<std::function<void(const Eldbus_Message* msg)>*>(data);
433     delete d;
434   }
435
436   PendingPtr eldbus_proxy_send_impl(const ProxyPtr& proxy, const MessagePtr& msg, const SendCallback& callback) override
437   {
438     auto cb      = new SendCallback{callback};
439     auto pending = eldbus_proxy_send(get(proxy), release(msg), callAsyncCb, cb, ELDBUS_CALL_TIMEOUT);
440     if(pending)
441     {
442       eldbus_pending_free_cb_add(pending, pendingFreeCb, cb);
443     }
444     else
445     {
446       delete cb;
447     }
448     return create(pending, false);
449   }
450
451   std::string eldbus_proxy_interface_get_impl(const ProxyPtr& proxy) override
452   {
453     return eldbus_proxy_interface_get(get(proxy));
454   }
455
456   static void listenerCallback(void* data, const Eldbus_Message* msg)
457   {
458     auto p = static_cast<std::function<void(const Eldbus_Message* msg)>*>(data);
459     (*p)(msg);
460   }
461
462   void eldbus_proxy_signal_handler_add_impl(const ProxyPtr& proxy, const std::string& member, const std::function<void(const MessagePtr&)>& cb) override
463   {
464     auto tmp = new std::function<void(const Eldbus_Message* msg)>{
465       [cb](const Eldbus_Message* msg) {
466         cb(create(msg, false));
467       }};
468     auto handler = eldbus_proxy_signal_handler_add(get(proxy), member.c_str(), listenerCallback, tmp);
469     if(handler)
470     {
471       eldbus_proxy_free_cb_add(get(proxy), listenerCallbackFree, tmp);
472     }
473     else
474     {
475       delete tmp;
476     }
477   }
478
479   std::string eldbus_message_iter_signature_get_impl(const MessageIterPtr& iter) override
480   {
481     return eldbus_message_iter_signature_get(get(iter));
482   }
483
484   MessagePtr eldbus_message_method_return_new_impl(const MessagePtr& msg) override
485   {
486     return create(eldbus_message_method_return_new(get(msg)));
487   }
488
489   MessagePtr eldbus_message_error_new_impl(const MessagePtr& msg, const std::string& err, const std::string& txt) override
490   {
491     return create(eldbus_message_error_new(get(msg), err.c_str(), txt.c_str()));
492   }
493
494   PendingPtr eldbus_connection_send_impl(const ConnectionPtr& conn, const MessagePtr& msg) override
495   {
496     return create(eldbus_connection_send(get(conn), get(msg), NULL, NULL, -1));
497   }
498
499   MessagePtr eldbus_message_signal_new_impl(const std::string& path, const std::string& iface, const std::string& name) override
500   {
501     return create(eldbus_message_signal_new(path.c_str(), iface.c_str(), name.c_str()));
502   }
503
504   MessagePtr eldbus_message_ref_impl(const MessagePtr& msg) override
505   {
506     return create(eldbus_message_ref(get(msg)), true);
507   }
508
509   ConnectionPtr eldbus_connection_get_impl(ConnectionType type) override
510   {
511     Eldbus_Connection_Type eldbusType = ELDBUS_CONNECTION_TYPE_SYSTEM;
512
513     switch(type)
514     {
515       case ConnectionType::SYSTEM:
516       {
517         eldbusType = ELDBUS_CONNECTION_TYPE_SYSTEM;
518         break;
519       }
520       case ConnectionType::SESSION:
521       {
522         eldbusType = ELDBUS_CONNECTION_TYPE_SESSION;
523         break;
524       }
525     }
526
527     auto p = eldbus_connection_get(eldbusType);
528     if (!p)
529     {
530       DALI_LOG_ERROR("cannot get dbus connection\n");
531       return NULL;
532     }
533     auto w = create(p, true);
534     return w;
535   }
536
537   std::string eldbus_connection_unique_name_get_impl(const ConnectionPtr& conn) override
538   {
539     return eldbus_connection_unique_name_get(get(conn));
540   }
541
542   ObjectPtr eldbus_object_get_impl(const ConnectionPtr& conn, const std::string& bus, const std::string& path) override
543   {
544     return create(eldbus_object_get(get(conn), bus.c_str(), path.c_str()), true);
545   }
546
547   ProxyPtr eldbus_proxy_get_impl(const ObjectPtr& obj, const std::string& interface) override
548   {
549     return create(eldbus_proxy_get(get(obj), interface.c_str()), false);
550   }
551
552   ProxyPtr eldbus_proxy_copy_impl(const ProxyPtr& ptr) override
553   {
554     return create(get(ptr), false);
555   }
556
557   void eldbus_name_request_impl(const ConnectionPtr& conn, const std::string& bus) override
558   {
559     eldbus_name_request(get(conn), bus.c_str(), ELDBUS_NAME_REQUEST_FLAG_DO_NOT_QUEUE, nullptr, nullptr);
560   }
561
562   void eldbus_name_release_impl(const ConnectionPtr& conn, const std::string& bus) override
563   {
564     eldbus_name_release(get(conn), bus.c_str(), nullptr, nullptr);
565   }
566
567   struct Implementation
568   {
569     Eldbus_Service_Interface_Desc             dsc;
570     std::vector<std::vector<Eldbus_Arg_Info>> argsInfos;
571     std::vector<Eldbus_Method>                methods;
572     std::vector<Eldbus_Signal>                signals;
573     std::vector<Eldbus_Property>              properties;
574
575     std::unordered_map<std::string, DBusWrapper::MethodInfo>   methodsMap;
576     std::unordered_map<std::string, DBusWrapper::PropertyInfo> propertiesMap;
577     std::unordered_map<unsigned int, DBusWrapper::SignalInfo>  signalsMap;
578
579     DBusWrapper::ConnectionWeakPtr connection;
580   };
581
582   static std::unordered_map<const Eldbus_Service_Interface*, std::unique_ptr<Implementation>> globalEntries;
583   static std::mutex                                                                           globalEntriesMutex;
584
585 #undef EINA_FALSE
586 #undef EINA_TRUE
587 #define EINA_FALSE static_cast<Eina_Bool>(0)
588 #define EINA_TRUE static_cast<Eina_Bool>(1)
589
590   static Eina_Bool property_get_callback(const Eldbus_Service_Interface* iface, const char* propertyName, Eldbus_Message_Iter* iter, const Eldbus_Message* message, Eldbus_Message** error)
591   {
592     Implementation* impl = nullptr;
593     {
594       std::lock_guard<std::mutex> lock(globalEntriesMutex);
595       auto                        it = globalEntries.find(iface);
596       if(it != globalEntries.end())
597       {
598         impl = it->second.get();
599       }
600     }
601     if(!impl)
602     {
603       return EINA_FALSE;
604     }
605
606     auto it = impl->propertiesMap.find(propertyName);
607     if(it == impl->propertiesMap.end() || !it->second.getCallback)
608     {
609       return EINA_FALSE;
610     }
611
612     auto connection = impl->connection.lock();
613     if(!connection)
614     {
615       return EINA_FALSE;
616     }
617
618     DBus::DBusServer::CurrentObjectSetter currentObjectSetter(connection, eldbus_message_path_get(message));
619     auto                                  reply = it->second.getCallback(create(message, false), create(iter, nullptr, false));
620     if(!reply.empty())
621     {
622       if(error)
623       {
624         *error = eldbus_message_error_new(message, "org.freedesktop.DBus.Error.Failed", reply.c_str());
625       }
626       return EINA_FALSE;
627     }
628
629     return EINA_TRUE;
630   }
631
632   static Eldbus_Message* property_set_callback(const Eldbus_Service_Interface* iface, const char* propertyName, Eldbus_Message_Iter* iter, const Eldbus_Message* message)
633   {
634     Implementation* impl = nullptr;
635     {
636       std::lock_guard<std::mutex> lock(globalEntriesMutex);
637       auto                        it = globalEntries.find(iface);
638       if(it != globalEntries.end())
639       {
640         impl = it->second.get();
641       }
642     }
643     if(!impl)
644     {
645       auto ret = eldbus_message_error_new(message, "org.freedesktop.DBus.Error.Failed", "Unknown interface");
646       return ret;
647     }
648     auto it = impl->propertiesMap.find(propertyName);
649     if(it == impl->propertiesMap.end() || !it->second.setCallback)
650     {
651       auto ret = eldbus_message_error_new(message, "org.freedesktop.DBus.Error.Failed", "Unknown setter");
652       return ret;
653     }
654     auto connection = impl->connection.lock();
655     if(!connection)
656     {
657       auto ret = eldbus_message_error_new(message, "org.freedesktop.DBus.Error.Failed", "Connection lost");
658       return ret;
659     }
660
661     DBus::DBusServer::CurrentObjectSetter currentObjectSetter(connection, eldbus_message_path_get(message));
662     auto                                  reply = it->second.setCallback(create(message, false), create(iter, nullptr, false));
663
664     Eldbus_Message* ret = nullptr;
665     if(!reply.empty())
666     {
667       ret = eldbus_message_error_new(message, "org.freedesktop.DBus.Error.Failed", reply.c_str());
668     }
669     else
670     {
671       ret = eldbus_message_method_return_new(message);
672     }
673     return ret;
674   }
675
676   static Eldbus_Message* method_callback(const Eldbus_Service_Interface* iface, const Eldbus_Message* message)
677   {
678     Implementation* impl = nullptr;
679     {
680       std::lock_guard<std::mutex> lock(globalEntriesMutex);
681       auto                        it = globalEntries.find(iface);
682       if(it != globalEntries.end())
683         impl = it->second.get();
684     }
685     if(!impl)
686     {
687       auto ret = eldbus_message_error_new(message, "org.freedesktop.DBus.Error.Failed", "Unknown interface");
688       return ret;
689     }
690     std::string memberName = eldbus_message_member_get(message);
691     auto        it         = impl->methodsMap.find(memberName);
692     if(it == impl->methodsMap.end())
693     {
694       auto ret = eldbus_message_error_new(message, "org.freedesktop.DBus.Error.Failed", "Unknown method");
695       return ret;
696     }
697     auto connection = impl->connection.lock();
698     if(!connection)
699     {
700       auto ret = eldbus_message_error_new(message, "org.freedesktop.DBus.Error.Failed", "Connection lost");
701       return ret;
702     }
703     DBus::DBusServer::CurrentObjectSetter currentObjectSetter(connection, eldbus_message_path_get(message));
704     auto                                  reply = it->second.callback(create(message));
705     return release(reply);
706   }
707
708   void add_interface_impl(bool                                fallback,
709                           const std::string&                  pathName,
710                           const ConnectionPtr&                connection,
711                           std::vector<std::function<void()>>& destructors,
712                           const std::string&                  interfaceName,
713                           std::vector<MethodInfo>&            dscrMethods,
714                           std::vector<PropertyInfo>&          dscrProperties,
715                           std::vector<SignalInfo>&            dscrSignals) override
716   {
717     std::vector<Eldbus_Method>                                                    methods;
718     std::vector<Eldbus_Signal>                                                    signals;
719     std::vector<Eldbus_Property>                                                  properties;
720     std::vector<std::vector<Eldbus_Arg_Info>>                                     argsInfos;
721     std::unordered_map<std::string, DBus::DBusInterfaceDescription::MethodInfo>   methodsMap;
722     std::unordered_map<std::string, DBus::DBusInterfaceDescription::PropertyInfo> propertiesMap;
723     std::unordered_map<unsigned int, DBus::DBusInterfaceDescription::SignalInfo>  signalsMap;
724
725     DBUS_DEBUG("interface %s path %s on bus %s", interfaceName.c_str(), pathName.c_str(), DBus::getConnectionName(connection).c_str());
726     auto makeArgInfo = [&](const std::vector<std::pair<std::string, std::string>>& input) {
727       argsInfos.push_back({});
728       auto& dst = argsInfos.back();
729       for(auto& s : input)
730       {
731         auto a = Strings.add(s.first);
732         auto b = Strings.add(s.second);
733         dst.push_back({a, b});
734       }
735       dst.push_back({nullptr, nullptr});
736       return dst.data();
737     };
738     for(auto& ee : dscrMethods)
739     {
740       auto key = ee.memberName;
741       DBUS_DEBUG("adding method %s", ee.memberName.c_str());
742       for(auto& r : ee.in)
743       {
744         DBUS_DEBUG("in %s '%s'", r.first.c_str(), r.second.c_str());
745       }
746       for(auto& r : ee.out)
747       {
748         DBUS_DEBUG("out %s '%s'", r.first.c_str(), r.second.c_str());
749       }
750       auto& e = (methodsMap[key] = std::move(ee));
751       methods.push_back({});
752       auto& m  = methods.back();
753       m.member = e.memberName.c_str();
754       m.in     = makeArgInfo(e.in);
755       m.out    = makeArgInfo(e.out);
756       m.cb     = method_callback;
757       m.flags  = 0;
758     }
759     for(auto& ee : dscrProperties)
760     {
761       auto key = ee.memberName;
762       DBUS_DEBUG("adding property %s", ee.memberName.c_str());
763       auto& e = (propertiesMap[key] = std::move(ee));
764       properties.push_back({});
765       auto& m    = properties.back();
766       m.name     = e.memberName.c_str();
767       m.type     = e.typeSignature.c_str();
768       m.get_func = e.getCallback ? property_get_callback : nullptr;
769       m.set_func = e.setCallback ? property_set_callback : nullptr;
770       m.flags    = 0;
771     }
772     dscrMethods.clear();
773     dscrProperties.clear();
774     dscrSignals.clear();
775
776     methods.push_back({nullptr, nullptr, nullptr, nullptr, 0});
777     signals.push_back({nullptr, nullptr, 0});
778     properties.push_back({nullptr, nullptr, nullptr, nullptr, 0});
779
780     auto impl = std::unique_ptr<Implementation>(new Implementation{
781       {interfaceName.c_str(),
782        methods.data(),
783        signals.data(),
784        properties.data(),
785        nullptr,
786        nullptr},
787       std::move(argsInfos),
788       std::move(methods),
789       std::move(signals),
790       std::move(properties),
791       std::move(methodsMap),
792       std::move(propertiesMap),
793       std::move(signalsMap),
794       connection});
795
796     {
797       std::lock_guard<std::mutex> lock(globalEntriesMutex);
798       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);
799       assert(v);
800       globalEntries[v] = std::move(impl);
801       DBUS_DEBUG("registering interface %p (%d)", v, fallback ? 1 : 0);
802       destructors.push_back([=]() {
803         DBUS_DEBUG("unregistering interface %p", v);
804         {
805           std::lock_guard<std::mutex> lock(globalEntriesMutex);
806           globalEntries.erase(v);
807         }
808         eldbus_service_interface_unregister(v);
809       });
810     }
811   }
812
813   static void listenerEventChangedCallback(void* data, Eldbus_Proxy* proxy EINA_UNUSED, void* event)
814   {
815     auto p = static_cast<std::function<void(Eldbus_Proxy_Event_Property_Changed*)>*>(data);
816     (*p)(static_cast<Eldbus_Proxy_Event_Property_Changed*>(event));
817   }
818
819   static void ProxyEventCallbackDelCb(void* data, const void* obj)
820   {
821     auto d = static_cast<std::function<void(Eldbus_Proxy_Event_Property_Changed*)>*>(data);
822     delete d;
823   }
824
825   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
826   {
827     auto callbackLambdaPtr = new std::function<void(Eldbus_Proxy_Event_Property_Changed * epc)>{
828       [cb, name, interface](Eldbus_Proxy_Event_Property_Changed* ev) {
829         const char* ifc = eldbus_proxy_interface_get(ev->proxy);
830         if(ev->name && ev->name == name && ifc && interface == ifc)
831         {
832           cb(ev->value);
833         }
834       }};
835     auto p = get(proxy);
836     eldbus_proxy_event_callback_add(p, ELDBUS_PROXY_EVENT_PROPERTY_CHANGED, listenerEventChangedCallback, callbackLambdaPtr);
837     eldbus_proxy_free_cb_add(p, ProxyEventCallbackDelCb, callbackLambdaPtr);
838   }
839 };
840
841 std::unordered_map<const Eldbus_Service_Interface*, std::unique_ptr<DefaultDBusWrapper::Implementation>> DefaultDBusWrapper::globalEntries;
842 std::mutex                                                                                               DefaultDBusWrapper::globalEntriesMutex;
843
844 DBusWrapper* DBusWrapper::Installed()
845 {
846   if(!InstalledWrapper)
847   {
848     InstalledWrapper.reset(new DefaultDBusWrapper);
849   }
850   return InstalledWrapper.get();
851 }
852
853 void DBusWrapper::Install(std::unique_ptr<DBusWrapper> w)
854 {
855   InstalledWrapper = std::move(w);
856 }