2 * Copyright 2019 Samsung Electronics Co., Ltd
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 #include "dbus-wrapper.h"
20 //#include <dali/internal/accessibility/bridge/accessibility-common.h>
28 #include <Ecore_Input.h>
31 #include <dali/public-api/dali-adaptor-common.h>
33 #define DBUS_INTERFACE_PROPERTIES "org.freedesktop.DBus.Properties"
37 #define EINA_TRUE static_cast< Eina_Bool >( 1 )
38 #define EINA_FALSE static_cast< Eina_Bool >( 0 )
40 //#define DBUS_DEBUG(...) do { DBus::debugPrint(__FILE__, __LINE__, __VA_ARGS__); } while (0)
44 #define assert(x) do{}while(0)
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;
50 thread_local std::string DBus::DBusServer::currentObjectPath;
51 thread_local DBusWrapper::ConnectionPtr DBus::DBusServer::currentConnection;
53 void DBus::setDebugPrinter( std::function< void( const char*, size_t ) > printer )
55 std::lock_guard< std::mutex > lock( debugLock );
56 debugPrinter = std::move( printer );
59 void DBus::debugPrint( const char* file, size_t line, const char* format, ... )
61 std::function< void( const char*, size_t ) > debugPrintFunc;
63 std::lock_guard< std::mutex > lock( debugLock );
66 debugPrintFunc = debugPrinter;
68 std::vector< char > buf( 4096 );
72 offset = snprintf( buf.data(), buf.size(), "%s:%u: ", file, static_cast< unsigned int >( line ) );
75 if( static_cast< size_t >( offset ) < buf.size() )
77 buf.resize( offset + 1 );
83 va_start( args, format );
84 int z = vsnprintf( buf.data() + offset, buf.size() - offset, format, args );
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 ) );
93 debugPrintFunc( buf.data(), buf.size() );
96 DBusWrapper::ConnectionPtr DBus::getDBusConnectionByName( const std::string& name )
98 return DBUS_W->eldbus_address_connection_get_impl( name );
101 DBusWrapper::ConnectionPtr DBus::getDBusConnectionByType( ConnectionType connectionType )
103 return DBUS_W->eldbus_connection_get_impl(connectionType);
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 ) )
110 DBus::DBusClient::DBusClient( std::string busName, std::string pathName, std::string interfaceName, const DBusWrapper::ConnectionPtr &conn )
113 connectionState->connection = getDBusConnectionByType( ConnectionType::SESSION );
115 connectionState->connection = conn;
117 std::ostringstream o;
118 o << "bus = " << busName << " path = " << pathName << " connection = " << DBUS_W->eldbus_connection_unique_name_get_impl( connectionState->connection );
121 connectionState->object = DBUS_W->eldbus_object_get_impl( connectionState->connection, busName.c_str(), pathName.c_str() );
122 if( connectionState->object )
124 connectionState->proxy = DBUS_W->eldbus_proxy_get_impl( connectionState->object, interfaceName );
125 if( interfaceName != DBUS_INTERFACE_PROPERTIES )
127 connectionState->propertiesProxy = DBUS_W->eldbus_proxy_get_impl( connectionState->object, DBUS_INTERFACE_PROPERTIES );
131 connectionState->propertiesProxy = DBUS_W->eldbus_proxy_copy_impl( connectionState->proxy );
134 connectionInfo = std::make_shared< ConnectionInfo >();
135 connectionInfo->busName = std::move( busName );
136 connectionInfo->pathName = std::move( pathName );
137 connectionInfo->interfaceName = std::move( interfaceName );
140 DBus::DBusServer::DBusServer( ConnectionType tp ) : DBus::DBusServer( DBus::getDBusConnectionByType( tp ) )
144 DBus::DBusServer::DBusServer( const DBusWrapper::ConnectionPtr &conn )
147 connection = getDBusConnectionByType( ConnectionType::SESSION );
152 DBus::DBusInterfaceDescription::DBusInterfaceDescription( std::string interfaceName ) : interfaceName( std::move( interfaceName ) )
156 void DBus::DBusServer::addInterface( const std::string& pathName, DBusInterfaceDescription& dscr, bool fallback )
158 DBUS_W->add_interface_impl( fallback, pathName, connection, destructorObject->destructors, dscr.interfaceName, dscr.methods, dscr.properties, dscr.signals );
161 std::string DBus::DBusServer::getBusName() const
163 return getConnectionName( connection );
166 std::string DBus::getConnectionName( const DBusWrapper::ConnectionPtr &c )
168 return DBUS_W->eldbus_connection_unique_name_get_impl( c );
171 bool DBus::DBusClient::getFromEinaValue(const _Eina_Value *v, void *dst)
173 return eina_value_get(const_cast<Eina_Value*>(v), dst);
177 static std::unique_ptr<DBusWrapper> InstalledWrapper;
179 struct DefaultDBusWrapper : public DBusWrapper {
180 constexpr static int ELDBUS_CALL_TIMEOUT = 1000;
182 DefaultDBusWrapper() {
184 ~DefaultDBusWrapper() {
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; \
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; \
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)...); \
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) { } \
205 if (EraseOnExit && Value) { unref_call; } \
208 DEFINE_GS(name, eldbus_name, unref_call)
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) {
218 if (EraseOnExit && Value) {
219 eldbus_connection_unref( Value );
222 ecore_event_shutdown();
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) { }
230 if (EraseOnExit && Value && Parent)
231 eldbus_message_iter_container_close(Parent, Value);
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, )
244 std::shared_ptr<Connection> eldbus_address_connection_get_impl(const std::string &addr) override {
246 auto p = eldbus_address_connection_get(addr.c_str());
247 auto w = create(p, true);
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 ); \
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 ); \
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)
269 #undef eldbus_message_iter_arguments_append_impl_basic
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 );
274 bool eldbus_message_iter_get_and_next_impl(const MessageIterPtr &it, bool &dst) override {
276 auto z = eldbus_message_iter_get_and_next( get(it), 'b', &q );
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() );
283 bool eldbus_message_iter_get_and_next_impl(const MessageIterPtr &it, std::string &dst) override {
286 if( !eldbus_message_iter_get_and_next( iter, 's', &q ) )
288 if( !eldbus_message_iter_get_and_next( iter, 'o', &q ) )
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() );
297 bool eldbus_message_iter_get_and_next_impl(const MessageIterPtr &it, ObjectPath &dst) override {
299 if( !eldbus_message_iter_get_and_next( get(it), 'o', &q ) )
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);
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);
314 MessageIterPtr eldbus_message_iter_get_impl(const MessagePtr &msg, bool) override {
315 return create(eldbus_message_iter_get(get(msg)), nullptr, false);
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() ) );
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) );
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 ) ) {
332 std::string eldbus_message_signature_get_impl(const MessagePtr &msg) override {
333 return eldbus_message_signature_get(get(msg));
336 static void callAsyncCb( void* data, const Eldbus_Message *msg, Eldbus_Pending *pending )
338 auto d = static_cast< SendCallback* >( data );
339 (*d)( create(msg, false) );
341 static void pendingFreeCb( void* data, const void* )
343 auto d = static_cast< SendCallback* >( data );
346 static void listenerCallbackFree( void* data, const void* )
348 auto d = static_cast< std::function< void( const Eldbus_Message* msg ) >* >( data );
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 );
357 eldbus_pending_free_cb_add( pending, pendingFreeCb, cb );
363 return create(pending, false);
365 std::string eldbus_proxy_interface_get_impl(const ProxyPtr &proxy) override {
366 return eldbus_proxy_interface_get( get(proxy) );
368 static void listenerCallback( void* data, const Eldbus_Message* msg )
370 auto p = static_cast< std::function< void( const Eldbus_Message* msg ) >* >( data );
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));
379 auto handler = eldbus_proxy_signal_handler_add( get(proxy), member.c_str(), listenerCallback, tmp );
381 eldbus_proxy_free_cb_add( get(proxy), listenerCallbackFree, tmp );
385 std::string eldbus_message_iter_signature_get_impl(const MessageIterPtr &iter) override {
386 return eldbus_message_iter_signature_get( get(iter) );
388 MessagePtr eldbus_message_method_return_new_impl( const MessagePtr &msg) override {
389 return create(eldbus_message_method_return_new( get(msg) ) );
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() ) );
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 ) );
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() ) );
400 MessagePtr eldbus_message_ref_impl(const MessagePtr &msg) override {
401 return create(eldbus_message_ref( get(msg) ), true );
403 ConnectionPtr eldbus_connection_get_impl(ConnectionType type) override {
404 Eldbus_Connection_Type eldbusType = ELDBUS_CONNECTION_TYPE_SYSTEM;
408 case ConnectionType::SYSTEM:
410 eldbusType = ELDBUS_CONNECTION_TYPE_SYSTEM;
413 case ConnectionType::SESSION:
415 eldbusType = ELDBUS_CONNECTION_TYPE_SESSION;
421 auto p = eldbus_connection_get( eldbusType );
422 auto w = create(p, true);
426 std::string eldbus_connection_unique_name_get_impl(const ConnectionPtr &conn) override {
427 return eldbus_connection_unique_name_get( get(conn) );
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 );
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 );
435 ProxyPtr eldbus_proxy_copy_impl( const ProxyPtr &ptr) override {
436 return create(get(ptr), false );
444 struct Implementation
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;
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;
456 DBusWrapper::ConnectionWeakPtr connection;
459 static std::unordered_map< const Eldbus_Service_Interface*, std::unique_ptr< Implementation > > globalEntries;
460 static std::mutex globalEntriesMutex;
464 #define EINA_FALSE static_cast<Eina_Bool>(0)
465 #define EINA_TRUE static_cast<Eina_Bool>(1)
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 )
470 Implementation* impl = nullptr;
472 std::lock_guard< std::mutex > lock( globalEntriesMutex );
473 auto it = globalEntries.find( iface );
474 if( it != globalEntries.end() )
475 impl = it->second.get();
480 auto it = impl->propertiesMap.find( propertyName );
481 if( it == impl->propertiesMap.end() || !it->second.getCallback )
484 auto connection = impl->connection.lock();
488 DBus::DBusServer::CurrentObjectSetter currentObjectSetter( connection, eldbus_message_path_get( message ) );
489 auto reply = it->second.getCallback( create(message, false), create(iter, nullptr, false) );
493 *error = eldbus_message_error_new( message, "org.freedesktop.DBus.Error.Failed", reply.c_str() );
500 static Eldbus_Message* property_set_callback( const Eldbus_Service_Interface* iface, const char* propertyName, Eldbus_Message_Iter* iter,
501 const Eldbus_Message* message )
503 Implementation* impl = nullptr;
505 std::lock_guard< std::mutex > lock( globalEntriesMutex );
506 auto it = globalEntries.find( iface );
507 if( it != globalEntries.end() )
508 impl = it->second.get();
512 auto ret = eldbus_message_error_new( message, "org.freedesktop.DBus.Error.Failed", "Unknown interface" );
515 auto it = impl->propertiesMap.find( propertyName );
516 if( it == impl->propertiesMap.end() || !it->second.setCallback )
518 auto ret = eldbus_message_error_new( message, "org.freedesktop.DBus.Error.Failed", "Unknown setter" );
521 auto connection = impl->connection.lock();
524 auto ret = eldbus_message_error_new( message, "org.freedesktop.DBus.Error.Failed", "Connection lost" );
528 DBus::DBusServer::CurrentObjectSetter currentObjectSetter( connection, eldbus_message_path_get( message ) );
529 auto reply = it->second.setCallback( create(message, false), create(iter, nullptr, false) );
531 Eldbus_Message* ret = nullptr;
534 ret = eldbus_message_error_new( message, "org.freedesktop.DBus.Error.Failed", reply.c_str() );
538 ret = eldbus_message_method_return_new( message );
543 static Eldbus_Message* method_callback( const Eldbus_Service_Interface* iface, const Eldbus_Message* message )
545 Implementation* impl = nullptr;
547 std::lock_guard< std::mutex > lock( globalEntriesMutex );
548 auto it = globalEntries.find( iface );
549 if( it != globalEntries.end() )
550 impl = it->second.get();
554 auto ret = eldbus_message_error_new( message, "org.freedesktop.DBus.Error.Failed", "Unknown interface" );
557 std::string memberName = eldbus_message_member_get( message );
558 auto it = impl->methodsMap.find( memberName );
559 if( it == impl->methodsMap.end() )
561 auto ret = eldbus_message_error_new( message, "org.freedesktop.DBus.Error.Failed", "Unknown method" );
564 auto connection = impl->connection.lock();
567 auto ret = eldbus_message_error_new( message, "org.freedesktop.DBus.Error.Failed", "Connection lost" );
570 DBus::DBusServer::CurrentObjectSetter currentObjectSetter( connection, eldbus_message_path_get( message ) );
571 auto reply = it->second.callback( create(message) );
572 return release(reply);
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
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;
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 });
600 dst.push_back({ nullptr, nullptr });
603 for( auto& ee : dscrMethods )
605 auto key = ee.memberName;
606 DBUS_DEBUG( "adding method %s", ee.memberName.c_str() );
607 for( auto& r : ee.in )
609 DBUS_DEBUG( "in %s '%s'", r.first.c_str(), r.second.c_str() );
611 for( auto& r : ee.out )
613 DBUS_DEBUG( "out %s '%s'", r.first.c_str(), r.second.c_str() );
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;
624 for( auto& ee : dscrProperties )
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;
638 dscrProperties.clear();
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} );
645 auto impl = std::unique_ptr< Implementation >( new Implementation{
646 {interfaceName.c_str(),
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 ),
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 );
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 );
670 std::lock_guard< std::mutex > lock( globalEntriesMutex );
671 globalEntries.erase( v );
673 eldbus_service_interface_unregister( v );
677 static void listenerEventChangedCallback( void* data, Eldbus_Proxy* proxy EINA_UNUSED, void* event )
679 auto p = static_cast< std::function< void( Eldbus_Proxy_Event_Property_Changed* ) >* >( data );
680 ( *p )( static_cast< Eldbus_Proxy_Event_Property_Changed* >( event ) );
682 static void ProxyEventCallbackDelCb( void* data, const void *obj )
684 auto d = static_cast< std::function< void( Eldbus_Proxy_Event_Property_Changed* ) >* >( data );
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 )
697 eldbus_proxy_event_callback_add( p, ELDBUS_PROXY_EVENT_PROPERTY_CHANGED,
698 listenerEventChangedCallback, callbackLambdaPtr );
699 eldbus_proxy_free_cb_add( p, ProxyEventCallbackDelCb, callbackLambdaPtr );
703 std::unordered_map< const Eldbus_Service_Interface*, std::unique_ptr< DefaultDBusWrapper::Implementation > > DefaultDBusWrapper::globalEntries;
704 std::mutex DefaultDBusWrapper::globalEntriesMutex;
706 DBusWrapper *DBusWrapper::Installed()
708 if (!InstalledWrapper)
709 InstalledWrapper.reset(new DefaultDBusWrapper);
710 return InstalledWrapper.get();
713 void DBusWrapper::Install(std::unique_ptr<DBusWrapper> w)
715 InstalledWrapper = std::move(w);
719 struct TestDBusWrapper::ConnectionImpl : public TestDBusWrapper::Connection {
722 TestDBusWrapper::TestDBusWrapper()
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} });
734 TestDBusWrapper::~TestDBusWrapper()
739 TestDBusWrapper::ConnectionPtr TestDBusWrapper::eldbus_address_connection_get_impl(const std::string &addr)
744 struct TestDBusWrapper::MessageIterImpl : public TestDBusWrapper::MessageIter {
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();
752 MessageIterImpl(MessagePtr msg, Element *elem, bool write, std::list<Element>::iterator it) : msg(std::move(msg)), elem(elem), write(write), it(it) { }
755 struct TestDBusWrapper::MessageImpl : public TestDBusWrapper::Message {
756 std::string bus, path, interface, name;
758 bool reply, error = false;
759 std::string error_a, error_b;
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)) { }
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)) { }
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)) { }
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)
781 DEFINE_TYPE(MessageIter)
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 });
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>();
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); \
806 bool TestDBusWrapper::eldbus_message_iter_get_and_next_impl(const MessageIterPtr &it, type_get &dst) { \
807 return TestDBusWrapperGetBasicAndNext(it, dst); \
809 #define eldbus_message_iter_arguments_append_impl_basic(type, sig) \
810 eldbus_message_iter_arguments_append_impl_basic_impl(type, type, sig)
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)
824 #undef eldbus_message_iter_arguments_append_impl_basic
825 #undef eldbus_message_iter_arguments_append_impl_basic_impl
827 TestDBusWrapper::MessageIterPtr TestDBusWrapper::eldbus_message_iter_container_new_impl(const MessageIterPtr &it, int type, const std::string &sig) {
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 });
839 TestDBusWrapper::MessageIterPtr TestDBusWrapper::eldbus_message_iter_get_and_next_by_type_impl(const MessageIterPtr &it, int type) {
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 });
851 TestDBusWrapper::MessageIterPtr TestDBusWrapper::eldbus_message_iter_get_impl(const MessagePtr &it, bool write) {
853 return std::make_shared<MessageIterImpl>(MessageIterImpl{ it, &m->data, write, m->data.get<ElementList>().begin() });
856 bool TestDBusWrapper::completed(const MessageIterPtr &iter)
860 return m->it == m->elem->get<ElementList>().end();
863 TestDBusWrapper::MessagePtr TestDBusWrapper::eldbus_proxy_method_call_new_impl(const ProxyPtr &proxy, const std::string &funcName) {
865 return std::make_shared<MessageImpl>(MessageImpl{
866 p->bus, p->path, p->interface, funcName, false
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) {
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;
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;
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>();
895 name = lst.front().get<std::string>();
899 iname = m->interface;
902 auto it = findMethod(m->path, iname, name, type);
903 if (it == mp.end()) {
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";
909 throw error{} << "missing {\"" << m->path << "\", \"" << iname << "\", \"" << name << "\", " << mt << "} in " << mpName;
911 DBus::DBusServer::CurrentObjectSetter setter{ connection, m->path };
912 return it->second(msg);
914 TestDBusWrapper::MessagePtr TestDBusWrapper::eldbus_proxy_send_and_block_impl(const ProxyPtr &proxy, const MessagePtr &msg) {
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);
924 bool TestDBusWrapper::eldbus_message_error_get_impl(const MessagePtr &msg, std::string &name, std::string &text) {
930 static void calculate_signature(std::ostringstream &ostr, TestDBusWrapper::Element &e)
932 ostr << static_cast<char>(e.signature());
933 if (e.isContainer()) {
935 auto &lst = e.get<TestDBusWrapper::ElementList>();
936 for(auto &q : lst) calculate_signature(ostr, q);
940 std::string TestDBusWrapper::eldbus_message_signature_get_impl(const MessagePtr &msg) {
942 std::ostringstream ostr;
943 for(auto &q : m->data.get<ElementList>())
944 calculate_signature(ostr, q);
947 TestDBusWrapper::PendingPtr TestDBusWrapper::eldbus_proxy_send_impl(const ProxyPtr &proxy, const MessagePtr &msg, const SendCallback &callback) {
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);
960 std::string TestDBusWrapper::eldbus_proxy_interface_get_impl(const ProxyPtr &proxy) {
964 void TestDBusWrapper::eldbus_proxy_signal_handler_add_impl(const ProxyPtr &proxy, const std::string &member, const std::function<void(const MessagePtr &)> &cb) {
966 daliSignals[std::tuple<std::string, std::string, std::string> { p->path, p->interface, member }] = cb;
968 std::string TestDBusWrapper::eldbus_message_iter_signature_get_impl(const MessageIterPtr &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);
978 TestDBusWrapper::MessagePtr TestDBusWrapper::eldbus_message_method_return_new_impl( const MessagePtr &msg) {
980 return std::make_shared<MessageImpl>(MessageImpl{
981 m->bus, m->path, m->interface, m->name, true
984 TestDBusWrapper::MessagePtr TestDBusWrapper::eldbus_message_error_new_impl( const MessagePtr &msg, const std::string &err, const std::string &txt ) {
986 return std::make_shared<MessageImpl>(MessageImpl{
987 m->bus, m->path, m->interface, m->name, err, txt
990 TestDBusWrapper::PendingPtr TestDBusWrapper::eldbus_connection_send_impl(const ConnectionPtr &conn, const MessagePtr &msg) {
991 call(testMethods, "testMethods", msg, MethodType::Method);
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) {
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
1008 TestDBusWrapper::MessagePtr TestDBusWrapper::newReplyMessage(const MessagePtr &msg) {
1010 return newMessage(m->path, m->interface, m->name, true);
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
1018 TestDBusWrapper::MessagePtr TestDBusWrapper::eldbus_message_ref_impl(const MessagePtr &msg) {
1021 TestDBusWrapper::ConnectionPtr TestDBusWrapper::eldbus_connection_get_impl(ConnectionType type) {
1024 std::string TestDBusWrapper::eldbus_connection_unique_name_get_impl(const ConnectionPtr &conn) {
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{
1032 TestDBusWrapper::ProxyPtr TestDBusWrapper::eldbus_proxy_get_impl( const ObjectPtr &obj, const std::string &interface ) {
1034 return std::make_shared<ProxyImpl>(ProxyImpl{ o->bus, o->path, interface });
1036 TestDBusWrapper::ProxyPtr TestDBusWrapper::eldbus_proxy_copy_impl( const ProxyPtr &ptr) {
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;
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;
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
1063 auto v = m.getCallback(msg, std::make_shared<MessageIterImpl>(MessageIterImpl{ ret, &ret->data, true }));
1064 ret->error = !v.empty();
1066 ret->error_a = "call failed";
1067 ret->error_b = std::move(v);
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
1079 // interface is probably wrong, due to retarded way properties are handlded by dbus
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;