/* 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