/* Copyright (C) 2010 The giomm Development Team * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . */ #include #include #include #include #include #include #include #include #ifdef G_OS_UNIX #include #endif #include #include namespace { extern "C" { static void DBusConnection_Signal_giomm_callback(GDBusConnection* connection, const char* sender_name, const char* object_path, const char* interface_name, const char* signal_name, GVariant* parameters, void* user_data) { Gio::DBus::Connection::SlotSignal* the_slot = static_cast(user_data); try { (*the_slot)(Glib::wrap(connection, true), (sender_name ? sender_name : ""), (object_path ? object_path : ""), (interface_name ? interface_name : ""), (signal_name ? signal_name : ""), Glib::VariantContainerBase(parameters, true)); } catch (...) { Glib::exception_handlers_invoke(); } } static void DBusConnection_Signal_giomm_callback_destroy(void* data) { delete static_cast(data); } static GDBusMessage* DBusConnection_Message_Filter_giomm_callback( GDBusConnection* connection, GDBusMessage* message, gboolean incoming, void* user_data) { Gio::DBus::Connection::SlotMessageFilter* the_slot = static_cast(user_data); try { auto result = (*the_slot)( Glib::wrap(connection, true), Glib::wrap(message, true), static_cast(incoming)); return (result) ? result->gobj_copy() : nullptr; } catch (...) { Glib::exception_handlers_invoke(); } return message; } static void DBusConnection_Message_Filter_giomm_callback_destroy(void* data) { delete static_cast(data); } } // extern "C" // Glib::wrap(GDBusConnection* object, bool take_copy) must be protected by a // mutex while a C++ wrapper is being constructed. The same GDBusConnection // instance can be used in more than one thread. The wrap() function can be // called simultaneously in different threads for the same GDBusConnection // instance before it has been given a C++ wrapper. // https://gitlab.gnome.org/GNOME/glibmm/issues/56 std::mutex wrap_mutex; } // anonymous namespace namespace Gio { namespace DBus { Connection::Connection(const Glib::RefPtr& stream, const std::string& guid, const Glib::RefPtr& observer, const SlotAsyncReady& slot, const Glib::RefPtr& cancellable, ConnectionFlags flags) : _CONSTRUCT("stream", Glib::unwrap(stream), "guid", Glib::c_str_or_nullptr(guid), "flags", static_cast(flags), "authentication-observer", Glib::unwrap(observer)) { init_async(slot, cancellable); } Connection::Connection(const Glib::RefPtr& stream, const std::string& guid, const SlotAsyncReady& slot, const Glib::RefPtr& cancellable, ConnectionFlags flags) : _CONSTRUCT("stream", Glib::unwrap(stream), "guid", Glib::c_str_or_nullptr(guid), "flags", static_cast(flags), "authentication-observer", static_cast(nullptr)) { init_async(slot, cancellable); } Connection::Connection(const Glib::RefPtr& stream, const std::string& guid, const Glib::RefPtr& observer, const SlotAsyncReady& slot, ConnectionFlags flags) : _CONSTRUCT("stream", Glib::unwrap(stream), "guid", Glib::c_str_or_nullptr(guid), "flags", static_cast(flags), "authentication-observer", Glib::unwrap(observer)) { init_async(slot); } Connection::Connection(const Glib::RefPtr& stream, const std::string& guid, const SlotAsyncReady& slot, ConnectionFlags flags) : _CONSTRUCT("stream", Glib::unwrap(stream), "guid", Glib::c_str_or_nullptr(guid), "flags", static_cast(flags), "authentication-observer", static_cast(nullptr)) { init_async(slot); } Connection::Connection(const std::string& address, const Glib::RefPtr& observer, const SlotAsyncReady& slot, const Glib::RefPtr& cancellable, ConnectionFlags flags) : _CONSTRUCT("address", Glib::c_str_or_nullptr(address), "flags", static_cast(flags), "authentication-observer", Glib::unwrap(observer)) { init_async(slot, cancellable); } Connection::Connection(const std::string& address, const SlotAsyncReady& slot, const Glib::RefPtr& cancellable, ConnectionFlags flags) : _CONSTRUCT("address", Glib::c_str_or_nullptr(address), "flags", static_cast(flags), "authentication-observer", static_cast(nullptr)) { init_async(slot, cancellable); } Connection::Connection(const std::string& address, const Glib::RefPtr& observer, const SlotAsyncReady& slot, ConnectionFlags flags) : _CONSTRUCT("address", Glib::c_str_or_nullptr(address), "flags", static_cast(flags), "authentication-observer", Glib::unwrap(observer)) { init_async(slot); } Connection::Connection( const std::string& address, const SlotAsyncReady& slot, ConnectionFlags flags) : _CONSTRUCT("address", Glib::c_str_or_nullptr(address), "flags", static_cast(flags), "authentication-observer", static_cast(nullptr)) { init_async(slot); } Connection::Connection(const Glib::RefPtr& stream, const std::string& guid, const Glib::RefPtr& observer, const Glib::RefPtr& cancellable, ConnectionFlags flags) : _CONSTRUCT("stream", Glib::unwrap(stream), "guid", Glib::c_str_or_nullptr(guid), "flags", static_cast(flags), "authentication-observer", Glib::unwrap(observer)) { init(cancellable); } Connection::Connection(const Glib::RefPtr& stream, const std::string& guid, const Glib::RefPtr& cancellable, ConnectionFlags flags) : _CONSTRUCT("stream", Glib::unwrap(stream), "guid", Glib::c_str_or_nullptr(guid), "flags", static_cast(flags), "authentication-observer", static_cast(nullptr)) { init(cancellable); } Connection::Connection(const Glib::RefPtr& stream, const std::string& guid, const Glib::RefPtr& observer, ConnectionFlags flags) : _CONSTRUCT("stream", Glib::unwrap(stream), "guid", Glib::c_str_or_nullptr(guid), "flags", static_cast(flags), "authentication-observer", Glib::unwrap(observer)) { init(); } Connection::Connection( const Glib::RefPtr& stream, const std::string& guid, ConnectionFlags flags) : _CONSTRUCT("stream", Glib::unwrap(stream), "guid", Glib::c_str_or_nullptr(guid), "flags", static_cast(flags), "authentication-observer", static_cast(nullptr)) { init(); } Connection::Connection(const std::string& address, const Glib::RefPtr& observer, const Glib::RefPtr& cancellable, ConnectionFlags flags) : _CONSTRUCT("address", Glib::c_str_or_nullptr(address), "flags", static_cast(flags), "authentication-observer", Glib::unwrap(observer)) { init(cancellable); } Connection::Connection( const std::string& address, const Glib::RefPtr& cancellable, ConnectionFlags flags) : _CONSTRUCT("address", Glib::c_str_or_nullptr(address), "flags", static_cast(flags), "authentication-observer", static_cast(nullptr)) { init(cancellable); } Connection::Connection( const std::string& address, const Glib::RefPtr& observer, ConnectionFlags flags) : _CONSTRUCT("address", Glib::c_str_or_nullptr(address), "flags", static_cast(flags), "authentication-observer", Glib::unwrap(observer)) { init(); } Connection::Connection(const std::string& address, ConnectionFlags flags) : _CONSTRUCT("address", Glib::c_str_or_nullptr(address), "flags", static_cast(flags), "authentication-observer", static_cast(nullptr)) { init(); } // static void Connection::create(const Glib::RefPtr& stream, const std::string& guid, const Glib::RefPtr& observer, const SlotAsyncReady& slot, const Glib::RefPtr& cancellable, ConnectionFlags flags) { // Note that this does not return anything, because it is async - see // create_finish(). Connection(stream, guid, observer, slot, cancellable, flags); } // static void Connection::create(const Glib::RefPtr& stream, const std::string& guid, const SlotAsyncReady& slot, const Glib::RefPtr& cancellable, ConnectionFlags flags) { // Note that this does not return anything, because it is async - see // create_finish(). Connection(stream, guid, slot, cancellable, flags); } // static void Connection::create(const Glib::RefPtr& stream, const std::string& guid, const Glib::RefPtr& observer, const SlotAsyncReady& slot, ConnectionFlags flags) { // Note that this does not return anything, because it is async - see // create_finish(). Connection(stream, guid, observer, slot, flags); } // static void Connection::create(const Glib::RefPtr& stream, const std::string& guid, const SlotAsyncReady& slot, ConnectionFlags flags) { // Note that this does not return anything, because it is async - see // create_finish(). Connection(stream, guid, slot, flags); } // static Glib::RefPtr Connection::create_sync(const Glib::RefPtr& stream, const std::string& guid, const Glib::RefPtr& observer, const Glib::RefPtr& cancellable, ConnectionFlags flags) { return Glib::make_refptr_for_instance(new Connection(stream, guid, observer, cancellable, flags)); } // static Glib::RefPtr Connection::create_sync(const Glib::RefPtr& stream, const std::string& guid, const Glib::RefPtr& cancellable, ConnectionFlags flags) { return Glib::make_refptr_for_instance(new Connection(stream, guid, cancellable, flags)); } // static Glib::RefPtr Connection::create_sync(const Glib::RefPtr& stream, const std::string& guid, const Glib::RefPtr& observer, ConnectionFlags flags) { return Glib::make_refptr_for_instance(new Connection(stream, guid, observer, flags)); } // static Glib::RefPtr Connection::create_sync( const Glib::RefPtr& stream, const std::string& guid, ConnectionFlags flags) { return Glib::make_refptr_for_instance(new Connection(stream, guid, flags)); } // static void Connection::create_for_address(const std::string& address, const Glib::RefPtr& observer, const SlotAsyncReady& slot, const Glib::RefPtr& cancellable, ConnectionFlags flags) { // Note that this does not return anything, because it is async - see // create_finish(). Connection(address, observer, slot, cancellable, flags); } // static void Connection::create_for_address(const std::string& address, const SlotAsyncReady& slot, const Glib::RefPtr& cancellable, ConnectionFlags flags) { // Note that this does not return anything, because it is async - see // create_finish(). Connection(address, slot, cancellable, flags); } // static void Connection::create_for_address(const std::string& address, const Glib::RefPtr& observer, const SlotAsyncReady& slot, ConnectionFlags flags) { // Note that this does not return anything, because it is async - see // create_finish(). Connection(address, observer, slot, flags); } // static void Connection::create_for_address( const std::string& address, const SlotAsyncReady& slot, ConnectionFlags flags) { // Note that this does not return anything, because it is async - see // create_finish(). Connection(address, slot, flags); } // static Glib::RefPtr Connection::create_for_address_sync(const std::string& address, const Glib::RefPtr& observer, const Glib::RefPtr& cancellable, ConnectionFlags flags) { return Glib::make_refptr_for_instance(new Connection(address, observer, cancellable, flags)); } // static Glib::RefPtr Connection::create_for_address_sync( const std::string& address, const Glib::RefPtr& cancellable, ConnectionFlags flags) { return Glib::make_refptr_for_instance(new Connection(address, cancellable, flags)); } // static Glib::RefPtr Connection::create_for_address_sync( const std::string& address, const Glib::RefPtr& observer, ConnectionFlags flags) { return Glib::make_refptr_for_instance(new Connection(address, observer, flags)); } // static Glib::RefPtr Connection::create_for_address_sync(const std::string& address, ConnectionFlags flags) { return Glib::make_refptr_for_instance(new Connection(address, flags)); } // static void Connection::get( BusType bus_type, const SlotAsyncReady& slot, const Glib::RefPtr& cancellable) { auto slot_copy = new SlotAsyncReady(slot); g_bus_get(static_cast(bus_type), Glib::unwrap(cancellable), &giomm_SignalProxy_async_callback, slot_copy); } // static void Connection::get(BusType bus_type, const SlotAsyncReady& slot) { auto slot_copy = new SlotAsyncReady(slot); g_bus_get(static_cast(bus_type), nullptr, &giomm_SignalProxy_async_callback, slot_copy); } void Connection::close() { g_dbus_connection_close(gobj(), nullptr, nullptr, nullptr); } void Connection::close(const SlotAsyncReady& slot, const Glib::RefPtr& cancellable) { auto slot_copy = new SlotAsyncReady(slot); g_dbus_connection_close( gobj(), Glib::unwrap(cancellable), &giomm_SignalProxy_async_callback, slot_copy); } void Connection::close(const SlotAsyncReady& slot) { auto slot_copy = new SlotAsyncReady(slot); g_dbus_connection_close(gobj(), nullptr, &giomm_SignalProxy_async_callback, slot_copy); } void Connection::flush() { g_dbus_connection_flush(gobj(), nullptr, nullptr, nullptr); } void Connection::flush(const SlotAsyncReady& slot, const Glib::RefPtr& cancellable) { auto slot_copy = new SlotAsyncReady(slot); g_dbus_connection_flush( gobj(), Glib::unwrap(cancellable), &giomm_SignalProxy_async_callback, slot_copy); } void Connection::flush(const SlotAsyncReady& slot) { auto slot_copy = new SlotAsyncReady(slot); g_dbus_connection_flush(gobj(), nullptr, &giomm_SignalProxy_async_callback, slot_copy); } bool Connection::send_message(const Glib::RefPtr& message, SendMessageFlags flags) { GError* gerror = nullptr; const bool result = g_dbus_connection_send_message( gobj(), Glib::unwrap(message), static_cast(flags), nullptr, &gerror); if (gerror) ::Glib::Error::throw_exception(gerror); return result; } void Connection::send_message_with_reply(const Glib::RefPtr& message, int timeout_msec, const SlotAsyncReady& slot, const Glib::RefPtr& cancellable) { auto slot_copy = new SlotAsyncReady(slot); volatile guint32 out_serial = 0; g_dbus_connection_send_message_with_reply(gobj(), Glib::unwrap(message), static_cast(message->get_flags()), timeout_msec, &out_serial, Glib::unwrap(cancellable), &giomm_SignalProxy_async_callback, slot_copy); message->set_serial(out_serial); } void Connection::send_message_with_reply( const Glib::RefPtr& message, int timeout_msec, const SlotAsyncReady& slot) { auto slot_copy = new SlotAsyncReady(slot); volatile guint32 out_serial = 0; g_dbus_connection_send_message_with_reply(gobj(), Glib::unwrap(message), static_cast(message->get_flags()), timeout_msec, &out_serial, nullptr, &giomm_SignalProxy_async_callback, slot_copy); message->set_serial(out_serial); } Glib::RefPtr Connection::send_message_with_reply_sync(const Glib::RefPtr& message, const Glib::RefPtr& cancellable, gint timeout_msec) { volatile guint32 out_serial = 0; GError* gerror = nullptr; GDBusMessage* result = g_dbus_connection_send_message_with_reply_sync(gobj(), Glib::unwrap(message), static_cast(message->get_flags()), timeout_msec, &out_serial, Glib::unwrap(cancellable), &gerror); if (gerror) ::Glib::Error::throw_exception(gerror); message->set_serial(out_serial); return Glib::wrap(result); } Glib::RefPtr Connection::send_message_with_reply_sync(const Glib::RefPtr& message, gint timeout_msec) { volatile guint32 out_serial = 0; GError* gerror = nullptr; GDBusMessage* result = g_dbus_connection_send_message_with_reply_sync(gobj(), Glib::unwrap(message), static_cast(message->get_flags()), timeout_msec, &out_serial, nullptr, &gerror); if (gerror) ::Glib::Error::throw_exception(gerror); message->set_serial(out_serial); return Glib::wrap(result); } void Connection::call(const Glib::ustring& object_path, const Glib::ustring& interface_name, const Glib::ustring& method_name, const Glib::VariantContainerBase& parameters, const SlotAsyncReady& slot, const Glib::RefPtr& cancellable, const Glib::ustring& bus_name, int timeout_msec, CallFlags flags, const Glib::VariantType& reply_type) { // Create a copy of the slot. // A pointer to it will be passed through the callback's data parameter // and deleted in the callback. auto slot_copy = new SlotAsyncReady(slot); g_dbus_connection_call(gobj(), Glib::c_str_or_nullptr(bus_name), object_path.c_str(), interface_name.c_str(), method_name.c_str(), const_cast(parameters.gobj()), reply_type.gobj(), static_cast(flags), timeout_msec, Glib::unwrap(cancellable), &giomm_SignalProxy_async_callback, slot_copy); } // Non-cancellable version. void Connection::call(const Glib::ustring& object_path, const Glib::ustring& interface_name, const Glib::ustring& method_name, const Glib::VariantContainerBase& parameters, const SlotAsyncReady& slot, const Glib::ustring& bus_name, int timeout_msec, CallFlags flags, const Glib::VariantType& reply_type) { // Create a copy of the slot. // A pointer to it will be passed through the callback's data parameter // and deleted in the callback. auto slot_copy = new SlotAsyncReady(slot); g_dbus_connection_call(gobj(), Glib::c_str_or_nullptr(bus_name), object_path.c_str(), interface_name.c_str(), method_name.c_str(), const_cast(parameters.gobj()), reply_type.gobj(), static_cast(flags), timeout_msec, nullptr, &giomm_SignalProxy_async_callback, slot_copy); } Glib::VariantContainerBase Connection::call_sync(const Glib::ustring& object_path, const Glib::ustring& interface_name, const Glib::ustring& method_name, const Glib::VariantContainerBase& parameters, const Glib::RefPtr& cancellable, const Glib::ustring& bus_name, int timeout_msec, CallFlags flags, const Glib::VariantType& reply_type) { GError* gerror = nullptr; GVariant* const gvariant = g_dbus_connection_call_sync(gobj(), Glib::c_str_or_nullptr(bus_name), object_path.c_str(), interface_name.c_str(), method_name.c_str(), const_cast(parameters.gobj()), reply_type.gobj(), static_cast(flags), timeout_msec, Glib::unwrap(cancellable), &gerror); if (gerror) ::Glib::Error::throw_exception(gerror); return Glib::VariantContainerBase(gvariant, false); // Dont' take an extra reference. } // Non-cancellable version. Glib::VariantContainerBase Connection::call_sync(const Glib::ustring& object_path, const Glib::ustring& interface_name, const Glib::ustring& method_name, const Glib::VariantContainerBase& parameters, const Glib::ustring& bus_name, int timeout_msec, CallFlags flags, const Glib::VariantType& reply_type) { GError* gerror = nullptr; GVariant* const gvariant = g_dbus_connection_call_sync(gobj(), Glib::c_str_or_nullptr(bus_name), object_path.c_str(), interface_name.c_str(), method_name.c_str(), const_cast(parameters.gobj()), reply_type.gobj(), static_cast(flags), timeout_msec, nullptr, &gerror); if (gerror) ::Glib::Error::throw_exception(gerror); return Glib::VariantContainerBase(gvariant, false); // Dont' take an extra reference. } #ifdef G_OS_UNIX // With a UnixFDList. void Connection::call(const Glib::ustring& object_path, const Glib::ustring& interface_name, const Glib::ustring& method_name, const Glib::VariantContainerBase& parameters, const SlotAsyncReady& slot, const Glib::RefPtr& cancellable, const Glib::RefPtr& fd_list, const Glib::ustring& bus_name, int timeout_msec, CallFlags flags, const Glib::VariantType& reply_type) { // Create a copy of the slot. // A pointer to it will be passed through the callback's data parameter // and deleted in the callback. auto slot_copy = new SlotAsyncReady(slot); g_dbus_connection_call_with_unix_fd_list(gobj(), Glib::c_str_or_nullptr(bus_name), object_path.c_str(), interface_name.c_str(), method_name.c_str(), const_cast(parameters.gobj()), reply_type.gobj(), static_cast(flags), timeout_msec, Glib::unwrap(fd_list), Glib::unwrap(cancellable), &giomm_SignalProxy_async_callback, slot_copy); } // Non-cancellable version (with a UnixFDList). void Connection::call(const Glib::ustring& object_path, const Glib::ustring& interface_name, const Glib::ustring& method_name, const Glib::VariantContainerBase& parameters, const SlotAsyncReady& slot, const Glib::RefPtr& fd_list, const Glib::ustring& bus_name, int timeout_msec, CallFlags flags, const Glib::VariantType& reply_type) { // Create a copy of the slot. // A pointer to it will be passed through the callback's data parameter // and deleted in the callback. auto slot_copy = new SlotAsyncReady(slot); g_dbus_connection_call_with_unix_fd_list(gobj(), Glib::c_str_or_nullptr(bus_name), object_path.c_str(), interface_name.c_str(), method_name.c_str(), const_cast(parameters.gobj()), reply_type.gobj(), static_cast(flags), timeout_msec, Glib::unwrap(fd_list), nullptr, &giomm_SignalProxy_async_callback, slot_copy); } #endif // G_OS_UNIX void Connection::emit_signal(const Glib::ustring& object_path, const Glib::ustring& interface_name, const Glib::ustring& signal_name, const Glib::ustring& destination_bus_name, const Glib::VariantContainerBase& parameters) { GError* gerror = nullptr; // destination_bus_name is checked to see if it is empty so that nullptr can be passed // to the C API. This is done because the bus name can be nullptr in the C API, // meaning that the signal should be emitted to all the listeners. g_dbus_connection_emit_signal(gobj(), Glib::c_str_or_nullptr(destination_bus_name), object_path.c_str(), interface_name.c_str(), signal_name.c_str(), const_cast(parameters.gobj()), &gerror); if (gerror) ::Glib::Error::throw_exception(gerror); } guint Connection::signal_subscribe(const SlotSignal& slot, const Glib::ustring& sender, const Glib::ustring& interface_name, const Glib::ustring& member, const Glib::ustring& object_path, const Glib::ustring& arg0, SignalFlags flags) { auto slot_copy = new SlotSignal(slot); return g_dbus_connection_signal_subscribe(gobj(), Glib::c_str_or_nullptr(sender), Glib::c_str_or_nullptr(interface_name), Glib::c_str_or_nullptr(member), Glib::c_str_or_nullptr(object_path), Glib::c_str_or_nullptr(arg0), static_cast(flags), &DBusConnection_Signal_giomm_callback, slot_copy, &DBusConnection_Signal_giomm_callback_destroy); } guint Connection::add_filter(const SlotMessageFilter& slot) { auto slot_copy = new SlotMessageFilter(slot); return g_dbus_connection_add_filter(gobj(), &DBusConnection_Message_Filter_giomm_callback, slot_copy, DBusConnection_Message_Filter_giomm_callback_destroy); } guint Connection::register_object(const Glib::ustring& object_path, const Glib::RefPtr& interface_info, const InterfaceVTable& vtable) { GError* gerror = nullptr; const guint result = g_dbus_connection_register_object(gobj(), object_path.c_str(), Glib::unwrap(interface_info), vtable.gobj(), const_cast(&vtable), nullptr, &gerror); if (gerror) ::Glib::Error::throw_exception(gerror); return result; } guint Connection::register_object( const Glib::ustring& object_path, const Glib::RefPtr& interface_info) { GError* gerror = nullptr; const guint result = g_dbus_connection_register_object( gobj(), object_path.c_str(), Glib::unwrap(interface_info), nullptr, nullptr, nullptr, &gerror); if (gerror) ::Glib::Error::throw_exception(gerror); return result; } guint Connection::register_subtree( const Glib::ustring& object_path, const SubtreeVTable& vtable, SubtreeFlags flags) { GError* gerror = nullptr; const guint result = g_dbus_connection_register_subtree(gobj(), object_path.c_str(), vtable.gobj(), static_cast(flags), const_cast(&vtable), nullptr, &gerror); if (gerror) ::Glib::Error::throw_exception(gerror); return result; } } // namespace DBus } // namespace Gio namespace Glib { Glib::RefPtr wrap(GDBusConnection* object, bool take_copy) { Glib::ObjectBase* pCppObject = nullptr; if (!ObjectBase::_get_current_wrapper((GObject*)object)) { // 'object' does not yet have a C++ wrapper. Construction of the C++ wrapper // must be thread-safe. See comments at the definition of wrap_mutex. std::lock_guard lock(wrap_mutex); pCppObject = Glib::wrap_auto((GObject*)object, take_copy); } else pCppObject = Glib::wrap_auto((GObject*)object, take_copy); return Glib::make_refptr_for_instance(dynamic_cast(pCppObject)); //We use dynamic_cast<> in case of multiple inheritance. } } // namespace Glib