/* Copyright (C) 2019 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 _DEFS(giomm,gio) _PINCLUDE(glibmm/private/object_p.h) namespace Gio { namespace DBus { //The GMMPROC_EXTRA_NAMESPACE() macro is a hint to generate_wrap_init.pl to put it in the DBus sub-namespace _GMMPROC_EXTRA_NAMESPACE(DBus) /** Client-side object manager. * * %Gio::DBus::ObjectManagerClient is used to create, monitor and delete object * proxies for remote objects exported by a Gio::DBus::ObjectManagerServer (or any * code implementing the * * org.freedesktop.DBus.ObjectManager interface. * * Once an instance of this type has been created, you can connect to * Gio::DBus::ObjectManager::signal_object_added() and * Gio::DBus::ObjectManager::signal_object_removed() and inspect the * Gio::DBus::Object objects returned by Gio::DBus::ObjectManager::get_objects(). * * If the name for a %Gio::DBus::ObjectManagerClient is not owned by anyone at * object construction time, the default behavior is to request the * message bus to launch an owner for the name. This behavior can be * disabled using the Gio::DBus::ObjectManagerClient::Flags::DO_NOT_AUTO_START * flag. It's also worth noting that this only works if the name of * interest is activatable in the first place. E.g. in some cases it * is not possible to launch an owner for the requested name. In this * case, %ObjectManagerClient object construction still succeeds but * there will be no object proxies * (e.g. get_objects() returns an empty vector) and * property_name_owner() is an empty string. * * The owner of the requested name can come and go (for example * consider a system service being restarted) – %ObjectManagerClient * handles this case too; simply connect to property_name_owner().signal_changed() * to watch for changes on property_name_owner(). * When the name owner vanishes, the behavior is that * property_name_owner() is set to an empty string (this includes * emission of signal_changed()) and then * signal_object_removed() signals are synthesized * for all currently existing object proxies. Since * property_name_owner() is an empty string when this happens, you can * use this information to disambiguate a synthesized signal from a * genuine signal caused by object removal on the remote * Gio::DBus::ObjectManager. Similarly, when a new name owner appears, * signal_object_added() signals are synthesized * while property_namename_owner() is still an empty string. Only when all * object proxies have been added, property_name_owner() * is set to the new name owner (this includes emission of the * signal_changed()). Furthermore, you are guaranteed that * property_name_owner() will alternate between a name owner * (e.g. `:1.42`) and an empty string even in the case where * the name of interest is atomically replaced. * * Ultimately, %ObjectManagerClient is used to obtain Gio::DBus::Proxy * instances. All signals (including the * org.freedesktop.DBus.Properties::PropertiesChanged signal) * delivered to Gio::DBus::Proxy instances are guaranteed to originate * from the name owner. This guarantee along with the behavior * described above, means that certain race conditions including the * "half the proxy is from the old owner and the other half is from * the new owner" problem cannot happen. * * To avoid having the application connect to signals on the returned * Gio::DBus::Object and Gio::DBus::Proxy objects, * Gio::DBus::Object::signal_interface_added(), * Gio::DBus::Object::signal_interface_removed(), * Gio::DBus::Proxy::signal_properties_changed() and * Gio::DBus::Proxy::signal_signal() * are also emitted on the %ObjectManagerClient instance managing these * objects. The signals emitted are * signal_interface_added(), signal_interface_removed(), * signal_interface_proxy_properties_changed() and * signal_interface_proxy_signal(). * * Note that all callbacks and signals are emitted in the * thread-default main context * that the %ObjectManagerClient object was constructed * in. Additionally, the Gio::DBus::ObjectProxy and Gio::DBus::Proxy objects * originating from the %ObjectManagerClient object will be created in * the same context and, consequently, will deliver signals in the * same main loop. * * @newin{2,62} * @ingroup DBus */ class GIOMM_API ObjectManagerClient : public Glib::Object, public Initable, public AsyncInitable, public ObjectManager { _CLASS_GOBJECT(ObjectManagerClient, GDBusObjectManagerClient, G_DBUS_OBJECT_MANAGER_CLIENT, Glib::Object, GObject, , , GIOMM_API) _IMPLEMENTS_INTERFACE(Initable) _IMPLEMENTS_INTERFACE(AsyncInitable) _IMPLEMENTS_INTERFACE(DBus::ObjectManager) public: _WRAP_ENUM(Flags, GDBusObjectManagerClientFlags, gtype_func g_dbus_object_manager_client_flags_get_type, decl_prefix GIOMM_API) /** A slot that will be called to determine the GType to use for an interface proxy * (if interface_name is not an empty string) or object proxy (if interface_name is * an empty string). * * This function is called in the thread-default main loop that @a manager was constructed in. * * For instance: * @code * GType on_proxy_type(const Glib::RefPtr& manager, * const Glib::ustring& object_path, const Glib::ustring& interface_name); * @endcode * * @param manager A Gio::DBus::ObjectManagerClient. * @param object_path The object path of the remote object. * @param interface_name The interface name of the remote object, or an empty * string if a GDBusObjectProxy GType is requested. * @returns A GType to use for the remote object. The returned type must be * a GDBusProxy or GDBusObjectProxy-derived type. */ using SlotProxyType = sigc::slot&, const Glib::ustring&, const Glib::ustring&)>; protected: ObjectManagerClient(const Glib::RefPtr& connection, const Glib::ustring& name, const Glib::ustring& object_path, const SlotAsyncReady& slot_async_ready, const Glib::RefPtr& cancellable, const SlotProxyType& slot_proxy_type, Flags flags); ObjectManagerClient(BusType bus_type, const Glib::ustring& name, const Glib::ustring& object_path, const SlotAsyncReady& slot_async_ready, const Glib::RefPtr& cancellable, const SlotProxyType& slot_proxy_type, Flags flags); _IGNORE(g_dbus_object_manager_client_new, g_dbus_object_manager_client_new_for_bus, g_dbus_object_manager_client_new_sync, g_dbus_object_manager_client_new_for_bus_sync) public: /** Creates a new %Gio::DBus::ObjectManagerClient object. * * This is an asynchronous failable constructor. When the result is * ready, @a slot_async_ready will be invoked in the * thread-default main context of the thread you are calling this method from. * You can then call create_finish() to get the result. * See create_sync() for the synchronous version. * * @param connection A Gio::DBus::Connection. * @param name The owner of the control object (unique or well-known name). * @param object_path The object path of the control object. * @param slot_async_ready A SlotAsyncReady slot to call when the request is satisfied. * @param cancellable A Cancellable or an empty Glib::RefPtr. * @param slot_proxy_type A SlotProxyType slot, or an empty slot to always construct * GDBusProxy or GDBusObjectProxy proxies. * @param flags Zero or more flags from the Gio::DBus::ObjectManagerClient::Flags enumeration. */ static void create(const Glib::RefPtr& connection, const Glib::ustring& name, const Glib::ustring& object_path, const SlotAsyncReady& slot_async_ready, const Glib::RefPtr& cancellable = {}, const SlotProxyType& slot_proxy_type = {}, Flags flags = Flags::NONE); // g_dbus_object_manager_client_new_finish() and g_dbus_object_manager_client_new_for_bus_finish() // return GDBusObjectManager pointers, although they are GDBusObjectManagerClient pointers. #m4 _CONVERSION(`GDBusObjectManager*',`Glib::RefPtr',`Glib::wrap((GDBusObjectManagerClient*)($3))') /** Finishes an operation started with create(). * * @param res An AsyncResult obtained from the SlotAsyncReady passed to create(). * @return A %Gio::DBus::ObjectManagerClient object. If an error has occurred, * a Glib::Error is thrown and nothing is returned. * @throw Glib::Error. */ _WRAP_METHOD(static Glib::RefPtr create_finish(const Glib::RefPtr& res), g_dbus_object_manager_client_new_finish, errthrow) /** Creates a new %Gio::DBus::ObjectManagerClient object. * * This is a synchronous failable constructor - the calling thread is * blocked until a reply is received. See create() for the asynchronous version. * * @param connection A Gio::DBus::Connection. * @param name The owner of the control object (unique or well-known name). * @param object_path The object path of the control object. * @param cancellable A Cancellable or an empty Glib::RefPtr. * @param slot_proxy_type A SlotProxyType slot, or an empty slot to always construct * GDBusProxy or GDBusObjectProxy proxies. * @param flags Zero or more flags from the Gio::DBus::ObjectManagerClient::Flags enumeration. * @throw Glib::Error */ static Glib::RefPtr create_sync( const Glib::RefPtr& connection, const Glib::ustring& name, const Glib::ustring& object_path, const Glib::RefPtr& cancellable = {}, const SlotProxyType& slot_proxy_type = {}, Flags flags = Flags::NONE); /** Creates a new %Gio::DBus::ObjectManagerClient object. * * Like create() but takes a Gio::DBus::BusType instead of a Gio::DBus::Connection. * * This is an asynchronous failable constructor. When the result is * ready, @a slot_async_ready will be invoked in the * thread-default main context of the thread you are calling this method from. * You can then call create_for_bus_finish() to get the result. * See create_for_bus_sync() for the synchronous version. * * @param bus_type A Gio::DBus::BusType. * @param name The owner of the control object (unique or well-known name). * @param object_path The object path of the control object. * @param slot_async_ready A SlotAsyncReady slot to call when the request is satisfied. * @param cancellable A Cancellable or an empty Glib::RefPtr. * @param slot_proxy_type A SlotProxyType slot, or an empty slot to always construct * GDBusProxy or GDBusObjectProxy proxies. * @param flags Zero or more flags from the Gio::DBus::ObjectManagerClient::Flags enumeration. */ static void create_for_bus(BusType bus_type, const Glib::ustring& name, const Glib::ustring& object_path, const SlotAsyncReady& slot_async_ready, const Glib::RefPtr& cancellable = {}, const SlotProxyType& slot_proxy_type = {}, Flags flags = Flags::NONE); /** Finishes an operation started with create_for_bus(). * * @param res An AsyncResult obtained from the SlotAsyncReady passed to create_for_bus(). * @return A %Gio::DBus::ObjectManagerClient object. If an error has occurred, * a Glib::Error is thrown and nothing is returned. * @throw Glib::Error. */ _WRAP_METHOD(static Glib::RefPtr create_for_bus_finish(const Glib::RefPtr& res), g_dbus_object_manager_client_new_for_bus_finish, errthrow) /** Creates a new %Gio::DBus::ObjectManagerClient object. * * Like create_sync() but takes a Gio::DBus::BusType instead of a * Gio::DBus::Connection. * * This is a synchronous failable constructor - the calling thread is * blocked until a reply is received. See create_for_bus() * for the asynchronous version. * * @param bus_type A Gio::DBus::BusType. * @param name The owner of the control object (unique or well-known name). * @param object_path The object path of the control object. * @param cancellable A Cancellable or an empty Glib::RefPtr. * @param slot_proxy_type A SlotProxyType slot, or an empty slot to always construct * GDBusProxy or GDBusObjectProxy proxies. * @param flags Zero or more flags from the Gio::DBus::ObjectManagerClient::Flags enumeration. * @throw Glib::Error */ static Glib::RefPtr create_for_bus_sync( BusType bus_type, const Glib::ustring& name, const Glib::ustring& object_path, const Glib::RefPtr& cancellable = {}, const SlotProxyType& slot_proxy_type = {}, Flags flags = Flags::NONE); _WRAP_METHOD(Glib::RefPtr get_connection(), g_dbus_object_manager_client_get_connection, refreturn) _WRAP_METHOD(Glib::RefPtr get_connection() const, g_dbus_object_manager_client_get_connection, refreturn, constversion) _WRAP_METHOD(Flags get_flags() const, g_dbus_object_manager_client_get_flags) _WRAP_METHOD(Glib::ustring get_name() const, g_dbus_object_manager_client_get_name) _WRAP_METHOD(Glib::ustring get_name_owner() const, g_dbus_object_manager_client_get_name_owner) _WRAP_PROPERTY("connection", Glib::RefPtr) _WRAP_PROPERTY("flags", Flags) _WRAP_PROPERTY("object-path", Glib::ustring) _WRAP_PROPERTY("name", Glib::ustring) _WRAP_PROPERTY("name-owner", Glib::ustring) //_WRAP_PROPERTY("bus-type", BusType) // write-only construct-only // The get-proxy-type-func, get-proxy-type-user-data and get-proxy-type-destroy-notify properties // can't be wrapped individually. Perhaps add set_slot_proxy_type() and get_slot_proxy_type() methods? #m4 _CONVERSION(`GDBusObjectProxy*',`const Glib::RefPtr&',`Glib::wrap($3, true)') #m4 _CONVERSION(`GDBusProxy*',`const Glib::RefPtr&',`Glib::wrap($3, true)') #m4 _CONVERSION(`GVariant*', `const Glib::VariantContainerBase&', `Glib::VariantContainerBase($3, true)') #m4 _CONVERSION(`const Glib::VariantContainerBase&', `GVariant*', `const_cast(($3).gobj())') _WRAP_SIGNAL(void interface_proxy_signal( const Glib::RefPtr& object_proxy, const Glib::RefPtr& interface_proxy, const Glib::ustring& sender_name, const Glib::ustring& signal_name, const Glib::VariantContainerBase& parameters), "interface-proxy-signal") using MapChangedProperties = std::map; // The DBus API ensures that the variant changed_properties is of type "DICT" #m4 _CONVERSION(`GVariant*', `const MapChangedProperties&', `Glib::Variant($3, true).get()') #m4 _CONVERSION(`const MapChangedProperties&', `GVariant*', `const_cast(Glib::Variant::create($3).gobj())') #m4 _CONVERSION(`const std::vector&', `const gchar*const*',`Glib::ArrayHandler::vector_to_array($3).data()') #m4 _CONVERSION(`const gchar*const*', `const std::vector&', `Glib::ArrayHandler::array_to_vector($3, Glib::OWNERSHIP_NONE)') _WRAP_SIGNAL(void interface_proxy_properties_changed( const Glib::RefPtr& object_proxy, const Glib::RefPtr& interface_proxy, const MapChangedProperties& changed_properties, const std::vector& invalidated_properties), "interface-proxy-properties-changed") }; } //namespace } // namespace Gio