syncevolution/src/gdbusxx/gdbus-cxx-bridge.h

5854 lines
201 KiB
C++

/*
* Copyright (C) 2009 Intel Corporation
*
* 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) version 3.
*
* 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301 USA
*/
/**
* This file contains everything that a D-Bus server needs to
* integrate a normal C++ class into D-Bus. Argument and result
* marshaling is done in wrapper functions which convert directly
* to normal C++ types (bool, integers, std::string, std::map<>, ...).
* See dbus_traits for the full list of supported types.
*
* Before explaining the binding, some terminology first:
* - A function has a return type and multiple parameters.
* - Input parameters are read-only arguments of the function.
* - The function can return values to the caller via the
* return type and output parameters (retvals).
*
* The C++ binding roughly looks like this:
* - Arguments can be passed as plain types or const references:
void foo(int arg); void bar(const std::string &str);
* - A single result can be returned as return value:
* int foo();
* - Multiple results can be copied into instances provided by
* the wrapper, passed by reference: void foo(std::string &res);
* - A return value, arguments and retvals can be combined
* arbitrarily. In the D-Bus reply the return code comes before
* all return values.
*
* Asynchronous methods are possible by declaring one parameter as a
* Result pointer and later calling the virtual function provided by
* it. Parameter passing of results is less flexible than that of
* method parameters: the later allows both std::string as well as
* const std::string &, for results only the const reference is
* supported. The Result instance is passed as pointer and then owned
* by the called method.
*
* Reference counting via boost::intrusive_ptr ensures that all
* D-Bus objects are handled automatically internally.
*/
#ifndef INCL_GDBUS_CXX_BRIDGE
#define INCL_GDBUS_CXX_BRIDGE
#include "gdbus-cxx.h"
#include <stdint.h>
#include <gio/gio.h>
#include <glib-object.h>
#include <map>
#include <list>
#include <vector>
#include <deque>
#include <utility>
#include <boost/bind.hpp>
#include <boost/intrusive_ptr.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/variant.hpp>
#include <boost/variant/get.hpp>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/algorithm/string/join.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/utility.hpp>
#include <boost/type_traits/is_signed.hpp>
/* The SyncEvolution exception handler must integrate into the D-Bus
* C++ wrapper. In contrast to the rest of the code, that handler uses
* some of the internal classes.
*
* To keep changes to a minimum while supporting both dbus
* implementations, this is made to be a define. The intention is to
* remove the define once the in-tree gdbus is dropped. */
#define DBUS_NEW_ERROR_MSG g_dbus_message_new_method_error
// allow some code to deal with API differences betwee GDBus C++ for GIO
// and the version for libdbus
#define GDBUS_CXX_GIO 1
// Boost docs want this in the boost:: namespace, but
// that fails with clang 2.9 depending on the inclusion order of
// header files. Global namespace works in all cases.
void intrusive_ptr_add_ref(GDBusConnection *con);
void intrusive_ptr_release(GDBusConnection *con);
void intrusive_ptr_add_ref(GDBusMessage *msg);
void intrusive_ptr_release(GDBusMessage *msg);
namespace GDBusCXX {
// GDBusCXX aliases for the underlying types.
// Useful for some external dbus_traits which
// need to pass pointers to these types in their
// append()/get() methods without depending on GIO or
// libdbus types.
typedef GDBusConnection connection_type;
typedef GDBusMessage message_type;
typedef GVariantBuilder builder_type;
typedef GVariantIter reader_type;
struct GDBusMessageUnref
{
void operator () (GDBusMessage *ptr) const { g_object_unref(ptr); }
};
typedef std::unique_ptr<GDBusMessage, GDBusMessageUnref> GDBusMessageUnique;
/**
* Simple unique_ptr for GVariant.
*/
class GVariantCXX : boost::noncopyable
{
GVariant *m_var;
public:
/** takes over ownership */
GVariantCXX(GVariant *var = NULL) : m_var(var) {}
~GVariantCXX() { if (m_var) { g_variant_unref(m_var); } }
operator GVariant * () { return m_var; }
GVariantCXX &operator = (GVariant *var) {
if (m_var != var) {
if (m_var) {
g_variant_unref(m_var);
}
m_var = var;
}
return *this;
}
};
class GVariantIterCXX : boost::noncopyable
{
GVariantIter *m_var;
public:
/** takes over ownership */
GVariantIterCXX(GVariantIter *var = NULL) : m_var(var) {}
~GVariantIterCXX() { if (m_var) { g_variant_iter_free(m_var); } }
operator GVariantIter * () { return m_var; }
GVariantIterCXX &operator = (GVariantIter *var) {
if (m_var != var) {
if (m_var) {
g_variant_iter_free(m_var);
}
m_var = var;
}
return *this;
}
};
class DBusMessagePtr;
inline void throwFailure(const std::string &object,
const std::string &operation,
GError *error)
{
std::string description = object;
if (!description.empty()) {
description += ": ";
}
description += operation;
if (error) {
description += ": ";
description += error->message;
g_clear_error(&error);
} else {
description += " failed";
}
throw std::runtime_error(description);
}
class DBusConnectionPtr : public boost::intrusive_ptr<GDBusConnection>
{
/**
* Bus name of client, as passed to dbus_get_bus_connection().
* The name will be requested in dbus_bus_connection_undelay() =
* undelay(), to give the caller a chance to register objects on
* the new connection.
*/
std::string m_name;
public:
DBusConnectionPtr() {}
// connections are typically created once, so increment the ref counter by default
DBusConnectionPtr(GDBusConnection *conn, bool add_ref = true) :
boost::intrusive_ptr<GDBusConnection>(conn, add_ref)
{}
DBusConnectionPtr(const DBusConnectionPtr &other) :
boost::intrusive_ptr<GDBusConnection>(other),
m_name(other.m_name)
{}
DBusConnectionPtr & operator = (const DBusConnectionPtr &other)
{
*static_cast<boost::intrusive_ptr<GDBusConnection> *>(this) = static_cast<const boost::intrusive_ptr<GDBusConnection> &>(other);
m_name = other.m_name;
return *this;
}
GDBusConnection *reference(void) throw()
{
GDBusConnection *conn = get();
g_object_ref(conn);
return conn;
}
/**
* Ensure that all IO is sent out of the process.
* Blocks. Only use it right before shutting down.
*/
void flush();
typedef boost::function<void ()> Disconnect_t;
void setDisconnect(const Disconnect_t &func);
// #define GDBUS_CXX_HAVE_DISCONNECT 1
/**
* Starts processing of messages,
* claims the bus name set with addName() or
* when creating the connection (legacy API,
* done that way for compatibility with GDBus for libdbus).
*/
void undelay() const;
void addName(const std::string &name) { m_name = name; }
/**
* Claims another name on the connection.
*
* The callback will be invoked with true as
* parameter once the name was successfully
* claimed. If that fails, false will be passed.
*
* The caller should be prepared to get called
* again later on, when loosing an already obtained
* name. Currently this shouldn't happen, though,
* because name transfer is not enabled when
* registering the name.
*
* The callback is allowed to be empty.
*/
void ownNameAsync(const std::string &name,
const boost::function<void (bool)> &obtainedCB) const;
};
class DBusMessagePtr : public boost::intrusive_ptr<GDBusMessage>
{
public:
DBusMessagePtr() {}
// expected to be used for messages created anew,
// so use the reference already incremented for us
// and don't increment by default
DBusMessagePtr(GDBusMessage *msg, bool add_ref = false) :
boost::intrusive_ptr<GDBusMessage>(msg, add_ref)
{}
GDBusMessage *reference(void) throw()
{
GDBusMessage *msg = get();
g_object_ref(msg);
return msg;
}
};
/**
* wrapper around GError which initializes
* the struct automatically, then can be used to
* throw an exception
*/
class DBusErrorCXX
{
GError *m_error;
public:
DBusErrorCXX(GError *error = NULL)
: m_error(error)
{
}
DBusErrorCXX(const DBusErrorCXX &dbus_error)
: m_error(NULL)
{
if (dbus_error.m_error) {
m_error = g_error_copy (dbus_error.m_error);
}
}
DBusErrorCXX & operator=(const DBusErrorCXX &dbus_error)
{
if (this != &dbus_error) {
set(dbus_error.m_error ?
g_error_copy(dbus_error.m_error) :
NULL);
}
return *this;
}
void set(GError *error) {
if (m_error) {
g_error_free (m_error);
}
m_error = error;
}
~DBusErrorCXX() {
if (m_error) {
g_error_free (m_error);
}
}
void throwFailure(const std::string &operation, const std::string &explanation = " failed")
{
std::string error_message(m_error ? (std::string(": ") + m_error->message) : "");
throw std::runtime_error(operation + explanation + error_message);
}
std::string getMessage() const { return m_error ? m_error->message : ""; }
};
DBusConnectionPtr dbus_get_bus_connection(const char *busType,
const char *name,
bool unshared,
DBusErrorCXX *err);
DBusConnectionPtr dbus_get_bus_connection(const std::string &address,
DBusErrorCXX *err);
inline void dbus_bus_connection_undelay(const DBusConnectionPtr &conn) { conn.undelay(); }
/**
* Wrapper around DBusServer. Does intentionally not expose
* any of the underlying methods so that the public API
* can be implemented differently for GIO libdbus.
*/
class DBusServerCXX : private boost::noncopyable
{
public:
~DBusServerCXX();
/**
* Called for each new connection. Callback must store the DBusConnectionPtr,
* otherwise it will be unref'ed after the callback returns.
* If the new connection is not wanted, then it is good style to close it
* explicitly in the callback. Message processing is delayed on the new
* connection, so the callback can set up objects and then must undelay
* the connection.
*/
typedef boost::function<void (DBusServerCXX &, DBusConnectionPtr &)> NewConnection_t;
/**
* Start listening for new connections. Mimics the libdbus DBusServer API, but
* underneath sets up a single connection via pipes. The caller must fork
* the process which calls dbus_get_bus_connection() before entering the main
* event loop again because that is when the DBusServerCXX will finish
* the connection setup (close child fd, call newConnection).
*
* All errors are reported via exceptions, not "err".
*/
static boost::shared_ptr<DBusServerCXX> listen(const NewConnection_t &newConnection, DBusErrorCXX *err);
/**
* address used by the server
*/
std::string getAddress() const { return m_address; }
private:
DBusServerCXX(const std::string &address);
DBusConnectionPtr m_connection;
NewConnection_t m_newConnection;
guint m_connectionIdle;
int m_childfd;
std::string m_address;
static gboolean onIdleOnce(gpointer custom);
};
/**
* Special type for object paths. A string in practice.
*/
class DBusObject_t : public std::string
{
public:
DBusObject_t() {}
template <class T> DBusObject_t(T val) : std::string(val) {}
template <class T> DBusObject_t &operator = (T val) { assign(val); return *this; }
};
/**
* specializations of this must defined methods for encoding and
* decoding type C and declare its signature
*/
template<class C> struct dbus_traits {};
struct dbus_traits_base
{
/**
* A C++ method or function can handle a call asynchronously by
* asking to be passed a "boost::shared_ptr<Result*>" parameter.
* The dbus_traits for those parameters have "asynchronous" set to
* true, which skips all processing after calling the method.
*/
static const bool asynchronous = false;
};
/**
* Append a varying number of parameters as result to the
* message, using AppendRetvals(msg) << res1 << res2 << ...;
*
* Types can be anything that has a dbus_traits, including
* types which are normally recognized as input parameters in D-Bus
* method calls.
*/
class AppendRetvals {
GDBusMessage *m_msg;
GVariantBuilder m_builder;
public:
AppendRetvals(DBusMessagePtr &msg) {
m_msg = msg.get();
g_variant_builder_init(&m_builder, G_VARIANT_TYPE_TUPLE);
}
~AppendRetvals()
{
g_dbus_message_set_body(m_msg, g_variant_builder_end(&m_builder));
}
template<class A> AppendRetvals & operator << (const A &a) {
dbus_traits<A>::append(m_builder, a);
return *this;
}
};
/**
* Append a varying number of method parameters as result to the reply
* message, using AppendArgs(msg) << Set<A1>(res1) << Set<A2>(res2) << ...;
*/
struct AppendArgs {
GDBusMessage *m_msg;
GVariantBuilder m_builder;
AppendArgs(const GDBusMessageUnique &msg) {
m_msg = msg.get();
if (!m_msg) {
throw std::runtime_error("NULL GDBusMessage reply");
}
g_variant_builder_init(&m_builder, G_VARIANT_TYPE_TUPLE);
}
~AppendArgs() {
g_dbus_message_set_body(m_msg, g_variant_builder_end(&m_builder));
}
/** syntactic sugar: redirect << into Set instance */
template<class A> AppendArgs & operator << (const A &a) {
return a.set(*this);
}
/**
* Always append argument, including those types which
* would be recognized by << as parameters and thus get
* skipped.
*/
template<class A> AppendArgs & operator + (const A &a) {
dbus_traits<A>::append(m_builder, a);
return *this;
}
};
/** default: skip it, not a result of the method */
template<class A> struct Set
{
Set(typename dbus_traits<A>::host_type &a) {}
AppendArgs &set(AppendArgs &context) const {
return context;
}
};
/** same for const reference */
template<class A> struct Set <const A &>
{
Set(typename dbus_traits<A>::host_type &a) {}
AppendArgs &set(AppendArgs &context) const {
return context;
}
};
/** specialization for reference: marshal result */
template<class A> struct Set <A &>
{
typename dbus_traits<A>::host_type &m_a;
Set(typename dbus_traits<A>::host_type &a) : m_a(a) {}
AppendArgs &set(AppendArgs &context) const {
dbus_traits<A>::append(context.m_builder, m_a);
return context;
}
};
/**
* Extract values from a message, using ExtractArgs(conn, msg) >> Get<A1>(val1) >> Get<A2>(val2) >> ...;
*
* This complements AppendArgs: it skips over those method arguments
* which are results of the method. Which values are skipped and
* which are marshalled depends on the specialization of Get and thus
* ultimately on the prototype of the method.
*/
struct ExtractArgs {
// always set
GDBusConnection *m_conn;
// only set when handling a method call
GDBusMessage **m_msg;
// only set for method call or response
GVariantIter m_iter;
// only set when m_msg is NULL (happens when handling signal)
const char *m_sender;
const char *m_path;
const char *m_interface;
const char *m_signal;
protected:
void init(GDBusConnection *conn,
GDBusMessage **msg,
GVariant *msgBody,
const char *sender,
const char *path,
const char *interface,
const char *signal);
ExtractArgs() {}
public:
/** constructor for parsing a method invocation message, which must not be NULL */
ExtractArgs(GDBusConnection *conn, GDBusMessage *&msg);
/** constructor for parsing signal parameters */
ExtractArgs(GDBusConnection *conn,
const char *sender,
const char *path,
const char *interface,
const char *signal);
/** syntactic sugar: redirect >> into Get instance */
template<class A> ExtractArgs & operator >> (const A &a) {
return a.get(*this);
}
};
/**
* Need separate class because overloading ExtractArgs constructor
* with "GDBusMessage &*msg" (for method calls and its special
* DBusResult semantic) and "GDBusMessage *msg" (here) is not
* possible. We can't just use the former in, for example,
* Ret1Traits::demarshal() because we only have a temporary value on
* the stack to bind the reference to.
*/
class ExtractResponse : public ExtractArgs
{
public:
/** constructor for message response */
ExtractResponse(GDBusConnection *conn, GDBusMessage *msg);
};
/** default: extract data from message */
template<class A> struct Get
{
typename dbus_traits<A>::host_type &m_a;
Get(typename dbus_traits<A>::host_type &a) : m_a(a) {}
ExtractArgs &get(ExtractArgs &context) const {
dbus_traits<A>::get(context, context.m_iter, m_a);
return context;
}
};
/** same for const reference */
template<class A> struct Get <const A &>
{
typename dbus_traits<A>::host_type &m_a;
Get(typename dbus_traits<A>::host_type &a) : m_a(a) {}
ExtractArgs &get(ExtractArgs &context) const {
dbus_traits<A>::get(context, context.m_iter, m_a);
return context;
}
};
/** specialization for reference: skip it, not an input parameter */
template<class A> struct Get <A &>
{
Get(typename dbus_traits<A>::host_type &a) {}
ExtractArgs &get(ExtractArgs &context) const {
return context;
}
};
/**
* combines D-Bus connection, path and interface
*/
class DBusObject
{
protected:
DBusConnectionPtr m_conn;
DBusObject_t m_path;
std::string m_interface;
private:
bool m_closeConnection;
public:
/**
* @param closeConnection set to true if the connection
* is private and this instance of
* DBusObject is meant to be the
* last user of the connection;
* when this DBusObject deconstructs,
* it'll close the connection
* (required by libdbus for private
* connections; the mechanism in GDBus for
* this didn't work)
*/
DBusObject(const DBusConnectionPtr &conn,
const std::string &path,
const std::string &interface,
bool closeConnection = false) :
m_conn(conn),
m_path(path),
m_interface(interface),
m_closeConnection(closeConnection)
{}
virtual ~DBusObject() {
if (m_closeConnection &&
m_conn) {
// TODO: is this also necessary for GIO GDBus?
// dbus_connection_close(m_conn.get());
}
}
GDBusConnection *getConnection() const { return m_conn.get(); }
const char *getPath() const { return m_path.c_str(); }
const DBusObject_t &getObject() const { return m_path; }
const char *getInterface() const { return m_interface.c_str(); }
};
/**
* adds destination to D-Bus connection, path and interface
*/
class DBusRemoteObject : public DBusObject
{
protected:
std::string m_destination;
public:
DBusRemoteObject(const DBusConnectionPtr &conn,
const std::string &path,
const std::string &interface,
const std::string &destination,
bool closeConnection = false) :
DBusObject(conn, path, interface, closeConnection),
m_destination(destination)
{}
const char *getDestination() const { return m_destination.c_str(); }
};
template<bool optional> class EmitSignalHelper
{
protected:
const DBusObject &m_object;
const std::string m_signal;
EmitSignalHelper(const DBusObject &object,
const std::string &signal) :
m_object(object),
m_signal(signal)
{}
void sendMsg(const DBusMessagePtr &msg)
{
if (optional) {
g_dbus_connection_send_message(m_object.getConnection(), msg.get(),
G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
} else {
if (!msg) {
throwFailure(m_signal, "g_dbus_message_new_signal()", NULL);
}
GError *error = NULL;
if (!g_dbus_connection_send_message(m_object.getConnection(), msg.get(),
G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, &error)) {
throwFailure(m_signal, "g_dbus_connection_send_message()", error);
}
}
}
};
template<bool optional = false> class EmitSignal0Template : private EmitSignalHelper<optional>
{
public:
EmitSignal0Template(const DBusObject &object,
const std::string &signal) :
EmitSignalHelper<optional>(object, signal)
{}
typedef void result_type;
void operator () ()
{
DBusMessagePtr msg(g_dbus_message_new_signal(EmitSignalHelper<optional>::m_object.getPath(),
EmitSignalHelper<optional>::m_object.getInterface(),
EmitSignalHelper<optional>::m_signal.c_str()));
if (!msg) {
if (optional) {
return;
}
throwFailure(EmitSignalHelper<optional>::m_signal, "g_dbus_message_new_signal()", NULL);
}
EmitSignalHelper<optional>::sendMsg(msg);
}
GDBusSignalInfo *makeSignalEntry() const
{
GDBusSignalInfo *entry = g_new0(GDBusSignalInfo, 1);
entry->name = g_strdup(EmitSignalHelper<optional>::m_signal.c_str());
entry->ref_count = 1;
return entry;
}
};
typedef EmitSignal0Template<false> EmitSignal0;
void appendArgInfo(GPtrArray *pa, const std::string &type);
template <typename Arg>
void appendNewArg(GPtrArray *pa)
{
// "in" direction
appendArgInfo(pa, dbus_traits<Arg>::getSignature());
}
template <typename Arg>
void appendNewArgForReply(GPtrArray *pa)
{
// "out" direction
appendArgInfo(pa, dbus_traits<Arg>::getReply());
}
template <typename Arg>
void appendNewArgForReturn(GPtrArray *pa)
{
// "out" direction, type must not be skipped
appendArgInfo(pa, dbus_traits<Arg>::getType());
}
template <typename A1, bool optional = false>
class EmitSignal1 : private EmitSignalHelper<optional>
{
public:
EmitSignal1(const DBusObject &object,
const std::string &signal) :
EmitSignalHelper<optional>(object, signal)
{}
typedef void result_type;
void operator () (A1 a1)
{
DBusMessagePtr msg(g_dbus_message_new_signal(EmitSignalHelper<optional>::m_object.getPath(),
EmitSignalHelper<optional>::m_object.getInterface(),
EmitSignalHelper<optional>::m_signal.c_str()));
if (!msg) {
if (optional) {
return;
}
throwFailure(EmitSignalHelper<optional>::m_signal, "g_dbus_message_new_signal()", NULL);
}
AppendRetvals(msg) << a1;
EmitSignalHelper<optional>::sendMsg(msg);
}
GDBusSignalInfo *makeSignalEntry() const
{
GDBusSignalInfo *entry = g_new0(GDBusSignalInfo, 1);
GPtrArray *args = g_ptr_array_new();
appendNewArg<A1>(args);
g_ptr_array_add(args, NULL);
entry->name = g_strdup(EmitSignalHelper<optional>::m_signal.c_str());
entry->args = (GDBusArgInfo **)g_ptr_array_free (args, FALSE);
entry->ref_count = 1;
return entry;
}
};
template <typename A1, typename A2, bool optional = false>
class EmitSignal2 : private EmitSignalHelper<optional>
{
public:
EmitSignal2(const DBusObject &object,
const std::string &signal) :
EmitSignalHelper<optional>(object, signal)
{}
typedef void result_type;
void operator () (A1 a1, A2 a2)
{
DBusMessagePtr msg(g_dbus_message_new_signal(EmitSignalHelper<optional>::m_object.getPath(),
EmitSignalHelper<optional>::m_object.getInterface(),
EmitSignalHelper<optional>::m_signal.c_str()));
if (!msg) {
if (optional) {
return;
}
throwFailure(EmitSignalHelper<optional>::m_signal, "g_dbus_message_new_signal()", NULL);
}
AppendRetvals(msg) << a1 << a2;
EmitSignalHelper<optional>::sendMsg(msg);
}
GDBusSignalInfo *makeSignalEntry() const
{
GDBusSignalInfo *entry = g_new0(GDBusSignalInfo, 1);
GPtrArray *args = g_ptr_array_new();
appendNewArg<A1>(args);
appendNewArg<A2>(args);
g_ptr_array_add(args, NULL);
entry->name = g_strdup(EmitSignalHelper<optional>::m_signal.c_str());
entry->args = (GDBusArgInfo **)g_ptr_array_free (args, FALSE);
entry->ref_count = 1;
return entry;
}
};
template <typename A1, typename A2, typename A3, bool optional = false>
class EmitSignal3 : private EmitSignalHelper<optional>
{
public:
EmitSignal3(const DBusObject &object,
const std::string &signal) :
EmitSignalHelper<optional>(object, signal)
{}
typedef void result_type;
void operator () (A1 a1, A2 a2, A3 a3)
{
DBusMessagePtr msg(g_dbus_message_new_signal(EmitSignalHelper<optional>::m_object.getPath(),
EmitSignalHelper<optional>::m_object.getInterface(),
EmitSignalHelper<optional>::m_signal.c_str()));
if (!msg) {
if (optional) {
return;
}
throwFailure(EmitSignalHelper<optional>::m_signal, "g_dbus_message_new_signal()", NULL);
}
AppendRetvals(msg) << a1 << a2 << a3;
EmitSignalHelper<optional>::sendMsg(msg);
}
GDBusSignalInfo *makeSignalEntry() const
{
GDBusSignalInfo *entry = g_new0(GDBusSignalInfo, 1);
GPtrArray *args = g_ptr_array_new();
appendNewArg<A1>(args);
appendNewArg<A2>(args);
appendNewArg<A3>(args);
g_ptr_array_add(args, NULL);
entry->name = g_strdup(EmitSignalHelper<optional>::m_signal.c_str());
entry->args = (GDBusArgInfo **)g_ptr_array_free (args, FALSE);
entry->ref_count = 1;
return entry;
}
};
template <typename A1, typename A2, typename A3, typename A4, bool optional = false>
class EmitSignal4 : private EmitSignalHelper<optional>
{
public:
EmitSignal4(const DBusObject &object,
const std::string &signal) :
EmitSignalHelper<optional>(object, signal)
{}
typedef void result_type;
void operator () (A1 a1, A2 a2, A3 a3, A4 a4)
{
DBusMessagePtr msg(g_dbus_message_new_signal(EmitSignalHelper<optional>::m_object.getPath(),
EmitSignalHelper<optional>::m_object.getInterface(),
EmitSignalHelper<optional>::m_signal.c_str()));
if (!msg) {
if (optional) {
return;
}
throwFailure(EmitSignalHelper<optional>::m_signal, "g_dbus_message_new_signal()", NULL);
}
AppendRetvals(msg) << a1 << a2 << a3 << a4;
EmitSignalHelper<optional>::sendMsg(msg);
}
GDBusSignalInfo *makeSignalEntry() const
{
GDBusSignalInfo *entry = g_new0(GDBusSignalInfo, 1);
GPtrArray *args = g_ptr_array_new();
appendNewArg<A1>(args);
appendNewArg<A2>(args);
appendNewArg<A3>(args);
appendNewArg<A4>(args);
g_ptr_array_add(args, NULL);
entry->name = g_strdup(EmitSignalHelper<optional>::m_signal.c_str());
entry->args = (GDBusArgInfo **)g_ptr_array_free (args, FALSE);
entry->ref_count = 1;
return entry;
}
};
template <typename A1, typename A2, typename A3, typename A4, typename A5, bool optional = false>
class EmitSignal5 : private EmitSignalHelper<optional>
{
public:
EmitSignal5(const DBusObject &object,
const std::string &signal) :
EmitSignalHelper<optional>(object, signal)
{}
typedef void result_type;
void operator () (A1 a1, A2 a2, A3 a3, A4 a4, A5 a5)
{
DBusMessagePtr msg(g_dbus_message_new_signal(EmitSignalHelper<optional>::m_object.getPath(),
EmitSignalHelper<optional>::m_object.getInterface(),
EmitSignalHelper<optional>::m_signal.c_str()));
if (!msg) {
if (optional) {
return;
}
throwFailure(EmitSignalHelper<optional>::m_signal, "g_dbus_message_new_signal()", NULL);
}
AppendRetvals(msg) << a1 << a2 << a3 << a4 << a5;
EmitSignalHelper<optional>::sendMsg(msg);
}
GDBusSignalInfo *makeSignalEntry() const
{
GDBusSignalInfo *entry = g_new0(GDBusSignalInfo, 1);
GPtrArray *args = g_ptr_array_new();
appendNewArg<A1>(args);
appendNewArg<A2>(args);
appendNewArg<A3>(args);
appendNewArg<A4>(args);
appendNewArg<A5>(args);
g_ptr_array_add(args, NULL);
entry->name = g_strdup(EmitSignalHelper<optional>::m_signal.c_str());
entry->args = (GDBusArgInfo **)g_ptr_array_free (args, FALSE);
entry->ref_count = 1;
return entry;
}
};
template <typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, bool optional = false>
class EmitSignal6 : private EmitSignalHelper<optional>
{
public:
EmitSignal6(const DBusObject &object,
const std::string &signal) :
EmitSignalHelper<optional>(object, signal)
{}
typedef void result_type;
void operator () (A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6)
{
DBusMessagePtr msg(g_dbus_message_new_signal(EmitSignalHelper<optional>::m_object.getPath(),
EmitSignalHelper<optional>::m_object.getInterface(),
EmitSignalHelper<optional>::m_signal.c_str()));
if (!msg) {
if (optional) {
return;
}
throwFailure(EmitSignalHelper<optional>::m_signal, "g_dbus_message_new_signal()", NULL);
}
AppendRetvals(msg) << a1 << a2 << a3 << a4 << a5 << a6;
EmitSignalHelper<optional>::sendMsg(msg);
}
GDBusSignalInfo *makeSignalEntry() const
{
GDBusSignalInfo *entry = g_new0(GDBusSignalInfo, 1);
GPtrArray *args = g_ptr_array_sized_new(7);
appendNewArg<A1>(args);
appendNewArg<A2>(args);
appendNewArg<A3>(args);
appendNewArg<A4>(args);
appendNewArg<A5>(args);
appendNewArg<A6>(args);
g_ptr_array_add(args, NULL);
entry->name = g_strdup(EmitSignalHelper<optional>::m_signal.c_str());
entry->args = (GDBusArgInfo **)g_ptr_array_free (args, FALSE);
entry->ref_count = 1;
return entry;
}
};
struct FunctionWrapperBase {
void* m_func_ptr;
FunctionWrapperBase(void* func_ptr)
: m_func_ptr(func_ptr)
{}
virtual ~FunctionWrapperBase() {}
};
template<typename M>
struct FunctionWrapper : public FunctionWrapperBase {
FunctionWrapper(boost::function<M>* func_ptr)
: FunctionWrapperBase(reinterpret_cast<void*>(func_ptr))
{}
virtual ~FunctionWrapper() {
delete reinterpret_cast<boost::function<M>*>(m_func_ptr);
}
};
struct MethodHandler
{
typedef GDBusMessage *(*MethodFunction)(GDBusConnection *conn, GDBusMessage *msg, void *data);
typedef boost::shared_ptr<FunctionWrapperBase> FuncWrapper;
typedef std::pair<MethodFunction, FuncWrapper > CallbackPair;
typedef std::map<const std::string, CallbackPair > MethodMap;
static MethodMap m_methodMap;
static boost::function<void (void)> m_callback;
static std::string make_prefix(const char *object_path) {
return std::string(object_path) + "~";
}
static std::string make_method_key(const char *object_path,
const char *method_name) {
return make_prefix(object_path) + method_name;
}
static void handler(GDBusConnection *connection,
const gchar *sender,
const gchar *object_path,
const gchar *interface_name,
const gchar *method_name,
GVariant *parameters,
GDBusMethodInvocation *invocation,
gpointer user_data)
{
MethodMap::iterator it;
it = m_methodMap.find(make_method_key(object_path, method_name));
if (it == m_methodMap.end()) {
g_dbus_method_invocation_return_dbus_error(invocation,
"org.SyncEvolution.NoMatchingMethodName",
"No methods registered with this name");
return;
}
// http://developer.gnome.org/gio/stable/GDBusConnection.html#GDBusInterfaceMethodCallFunc
// does not say so explicitly, but it seems that 'invocation' was created for us.
// If we don't unref it, it leaks (visible in refdbg).
//
// The documentation for the class itself says that 'the normal way to obtain a
// GDBusMethodInvocation object is to receive it as an argument to the
// handle_method_call()' - note the word 'obtain', which seems to imply ownership.
// This is consistent with the transfer of ownership to calls like
// g_dbus_method_invocation_return_dbus_error(), which take over ownership
// of the invocation instance.
//
// Because we work with messages directly for the reply from now on, we
// unref 'invocation' immediately after referencing the underlying message.
DBusMessagePtr msg(g_dbus_method_invocation_get_message(invocation), true);
g_object_unref(invocation);
// Set to NULL, just to be sure we remember that it is gone.
// cppcheck-suppress uselessAssignmentPtrArg
invocation = NULL;
// We are calling callback because we want to keep server alive as long
// as possible. This callback is in fact delaying server's autotermination.
if (m_callback) {
m_callback();
}
MethodFunction methodFunc = it->second.first;
void *methodData = reinterpret_cast<void*>(it->second.second->m_func_ptr);
GDBusMessage *reply;
reply = (methodFunc)(connection,
msg.get(),
methodData);
if (!reply) {
// probably asynchronous, might also be out-of-memory;
// either way, don't send a reply now
return;
}
GError *error = NULL;
g_dbus_connection_send_message(connection,
reply,
G_DBUS_SEND_MESSAGE_FLAGS_NONE,
NULL,
&error);
g_object_unref(reply);
// Cannot throw an exception, glib event loop won't know what to do with it;
// pretend that the problem didn't happen.
if (error != NULL) {
g_error_free (error);
}
}
};
template <class M>
struct MakeMethodEntry
{
// There is no generic implementation of this method.
// If you get an error about it missing, then write
// a specialization for your type M (the method pointer).
//
// static GDBusMethodEntry make(const char *name)
};
// Wrapper around g_dbus_method_info_unref or g_dbus_signal_info_unref
// with additional NULL check. The methods themselves crash on NULL,
// which happens when appending the terminating NULL to m_methods/m_signals
// below.
template<class I, void (*f)(I *)> void InfoDestroy(gpointer ptr)
{
if (ptr) {
I *info = static_cast<I *>(ptr);
f(info);
}
}
/**
* utility class for registering an interface
*/
class DBusObjectHelper : public DBusObject
{
// 0 when not registered (= activated).
guint m_connId;
GDBusInterfaceInfo m_ifInfo;
GDBusInterfaceVTable m_ifVTable;
// These arrays must stay valid as long as we are active,
// because our GDBusInterfaceInfo points to it without
// ever freeing the memory.
GPtrArray *m_methods;
GPtrArray *m_signals;
public:
typedef boost::function<void (void)> Callback_t;
DBusObjectHelper(const DBusConnectionPtr &conn,
const std::string &path,
const std::string &interface,
const Callback_t &callback = Callback_t(),
bool closeConnection = false) :
DBusObject(conn, path, interface, closeConnection),
m_connId(0),
m_methods(g_ptr_array_new_with_free_func(InfoDestroy<GDBusMethodInfo, g_dbus_method_info_unref>)),
m_signals(g_ptr_array_new_with_free_func(InfoDestroy<GDBusSignalInfo, g_dbus_signal_info_unref>))
{
memset(&m_ifInfo, 0, sizeof(m_ifInfo));
memset(&m_ifVTable, 0, sizeof(m_ifVTable));
if (!MethodHandler::m_callback) {
MethodHandler::m_callback = callback;
}
}
~DBusObjectHelper()
{
deactivate();
MethodHandler::MethodMap::iterator iter(MethodHandler::m_methodMap.begin());
MethodHandler::MethodMap::iterator iter_end(MethodHandler::m_methodMap.end());
MethodHandler::MethodMap::iterator first_to_erase(iter_end);
MethodHandler::MethodMap::iterator last_to_erase(iter_end);
const std::string prefix(MethodHandler::make_prefix(getPath()));
while (iter != iter_end) {
const bool prefix_equal(!iter->first.compare(0, prefix.size(), prefix));
if (prefix_equal && (first_to_erase == iter_end)) {
first_to_erase = iter;
} else if (!prefix_equal && (first_to_erase != iter_end)) {
last_to_erase = iter;
break;
}
++iter;
}
if (first_to_erase != iter_end) {
MethodHandler::m_methodMap.erase(first_to_erase, last_to_erase);
}
g_ptr_array_free(m_methods, TRUE);
g_ptr_array_free(m_signals, TRUE);
}
/**
* binds a member to the this pointer of its instance
* and invokes it when the specified method is called
*/
template <class A1, class C, class M> void add(A1 instance, M C::*method, const char *name)
{
if (m_connId) {
throw std::logic_error("You can't add new methods after registration!");
}
typedef MakeMethodEntry< boost::function<M> > entry_type;
g_ptr_array_add(m_methods, entry_type::make(name));
boost::function<M> *func = new boost::function<M>(entry_type::boostptr(method, instance));
MethodHandler::FuncWrapper wrapper(new FunctionWrapper<M>(func));
MethodHandler::CallbackPair methodAndData = std::make_pair(entry_type::methodFunction, wrapper);
const std::string key(MethodHandler::make_method_key(getPath(), name));
MethodHandler::m_methodMap.insert(std::make_pair(key, methodAndData));
}
/**
* binds a plain function pointer with no additional arguments and
* invokes it when the specified method is called
*/
template <class M> void add(M *function, const char *name)
{
if (m_connId) {
throw std::logic_error("You can't add new functions after registration!");
}
typedef MakeMethodEntry< boost::function<M> > entry_type;
g_ptr_array_add(m_methods, entry_type::make(name));
boost::function<M> *func = new boost::function<M>(function);
MethodHandler::FuncWrapper wrapper(new FunctionWrapper<M>(func));
MethodHandler::CallbackPair methodAndData = std::make_pair(entry_type::methodFunction,
wrapper);
const std::string key(MethodHandler::make_method_key(getPath(), name));
MethodHandler::m_methodMap.insert(std::make_pair(key, methodAndData));
}
/**
* add an existing signal entry
*/
template <class S> void add(const S &s)
{
if (m_connId) {
throw std::logic_error("You can't add new signals after registration!");
}
g_ptr_array_add(m_signals, s.makeSignalEntry());
}
void activate() {
// method and signal array must be NULL-terminated.
if (m_connId) {
throw std::logic_error("This object was already activated.");
}
if (m_methods->len &&
m_methods->pdata[m_methods->len - 1] != NULL) {
g_ptr_array_add(m_methods, NULL);
}
if (m_signals->len &&
m_signals->pdata[m_signals->len - 1] != NULL) {
g_ptr_array_add(m_signals, NULL);
}
// Meta data is owned by this instance, not GDBus.
// This is what most examples do and deviating from that
// can (did!) lead to memory leaks. For example,
// the ownership of the method array cannot be transferred
// to GDBusInterfaceInfo.
m_ifInfo.ref_count = -1;
m_ifInfo.name = const_cast<char *>(getInterface()); // Due to ref_count == -1, m_ifInfo.name is not going to get freed despite the missing const.
m_ifInfo.methods = (GDBusMethodInfo **)m_methods->pdata;
m_ifInfo.signals = (GDBusSignalInfo **)m_signals->pdata;
m_ifVTable.method_call = MethodHandler::handler;
m_connId = g_dbus_connection_register_object(getConnection(),
getPath(),
&m_ifInfo,
&m_ifVTable,
this,
NULL,
NULL);
if (m_connId == 0) {
throw std::runtime_error(std::string("g_dbus_connection_register_object() failed for ") +
getPath() + " " + getInterface());
}
}
void deactivate()
{
if (m_connId) {
if (!g_dbus_connection_unregister_object(getConnection(), m_connId)) {
throw std::runtime_error(std::string("g_dbus_connection_unregister_object() failed for ") +
getPath() + " " + getInterface());
}
m_connId = 0;
}
}
};
/**
* to be used for plain parameters like int32_t:
* treat as arguments which have to be extracted
* from the GVariants and can be skipped when
* encoding the reply
*/
struct VariantTypeBoolean { static const GVariantType* getVariantType() { return G_VARIANT_TYPE_BOOLEAN; } };
struct VariantTypeByte { static const GVariantType* getVariantType() { return G_VARIANT_TYPE_BYTE; } };
struct VariantTypeInt16 { static const GVariantType* getVariantType() { return G_VARIANT_TYPE_INT16; } };
struct VariantTypeUInt16 { static const GVariantType* getVariantType() { return G_VARIANT_TYPE_UINT16; } };
struct VariantTypeInt32 { static const GVariantType* getVariantType() { return G_VARIANT_TYPE_INT32; } };
struct VariantTypeUInt32 { static const GVariantType* getVariantType() { return G_VARIANT_TYPE_UINT32; } };
struct VariantTypeInt64 { static const GVariantType* getVariantType() { return G_VARIANT_TYPE_INT64; } };
struct VariantTypeUInt64 { static const GVariantType* getVariantType() { return G_VARIANT_TYPE_UINT64; } };
struct VariantTypeDouble { static const GVariantType* getVariantType() { return G_VARIANT_TYPE_DOUBLE; } };
#define GDBUS_CXX_QUOTE(x) #x
#define GDBUS_CXX_LINE(l) GDBUS_CXX_QUOTE(l)
#define GDBUS_CXX_SOURCE_INFO __FILE__ ":" GDBUS_CXX_LINE(__LINE__)
template<class host, class VariantTraits> struct basic_marshal : public dbus_traits_base
{
typedef host host_type;
typedef host arg_type;
/**
* copy value from GVariant iterator into variable
*/
static void get(ExtractArgs &context,
GVariantIter &iter, host &value)
{
GVariantCXX var(g_variant_iter_next_value(&iter));
if (var == NULL || !g_variant_type_equal(g_variant_get_type(var), VariantTraits::getVariantType())) {
throw std::runtime_error("g_variant failure " GDBUS_CXX_SOURCE_INFO);
}
const char *type = g_variant_get_type_string(var);
g_variant_get(var, type, &value);
}
/**
* copy value into D-Bus iterator
*/
static void append(GVariantBuilder &builder, arg_type value)
{
const gchar *typeStr = g_variant_type_dup_string(VariantTraits::getVariantType());
g_variant_builder_add(&builder, typeStr, value);
g_free((gpointer)typeStr);
}
};
template<> struct dbus_traits<uint8_t> :
public basic_marshal< uint8_t, VariantTypeByte >
{
/**
* plain type, regardless of whether used as
* input or output parameter
*/
static std::string getType() { return "y"; }
/**
* plain type => input parameter => non-empty signature
*/
static std::string getSignature() {return getType(); }
/**
* plain type => not returned to caller
*/
static std::string getReply() { return ""; }
};
/** if the app wants to use signed char, let it and treat it like a byte */
template<> struct dbus_traits<int8_t> : dbus_traits<uint8_t>
{
typedef int8_t host_type;
typedef int8_t arg_type;
static void get(ExtractArgs &context,
GVariantIter &iter, host_type &value)
{
dbus_traits<uint8_t>::get(context, iter, reinterpret_cast<uint8_t &>(value));
}
};
/** runtime detection of integer representation */
template<typename I, bool issigned, size_t bytes> struct dbus_traits_integer_switch {};
template<typename I> struct dbus_traits_integer_switch<I, true, 2> :
public basic_marshal< I, VariantTypeInt16 >
{
static std::string getType() { return "n"; }
static std::string getSignature() {return getType(); }
static std::string getReply() { return ""; }
};
template<typename I> struct dbus_traits_integer_switch<I, false, 2> :
public basic_marshal< I, VariantTypeUInt16 >
{
static std::string getType() { return "q"; }
static std::string getSignature() {return getType(); }
static std::string getReply() { return ""; }
};
template<typename I> struct dbus_traits_integer_switch<I, true, 4> :
public basic_marshal< I, VariantTypeInt32 >
{
static std::string getType() { return "i"; }
static std::string getSignature() {return getType(); }
static std::string getReply() { return ""; }
};
template<typename I> struct dbus_traits_integer_switch<I, false, 4> :
public basic_marshal< I, VariantTypeUInt32 >
{
static std::string getType() { return "u"; }
static std::string getSignature() {return getType(); }
static std::string getReply() { return ""; }
};
template<typename I> struct dbus_traits_integer_switch<I, true, 8> :
public basic_marshal< I, VariantTypeInt64 >
{
static std::string getType() { return "x"; }
static std::string getSignature() {return getType(); }
static std::string getReply() { return ""; }
};
template<typename I> struct dbus_traits_integer_switch<I, false, 8> :
public basic_marshal< I, VariantTypeUInt64 >
{
static std::string getType() { return "t"; }
static std::string getSignature() {return getType(); }
static std::string getReply() { return ""; }
};
template<typename I> struct dbus_traits_integer : public dbus_traits_integer_switch<I, boost::is_signed<I>::value, sizeof(I)> {};
// Some of these types may have the same underlying representation, but they are
// still considered different types by the compiler and thus we must have dbus_traits
// for all of them.
template<> struct dbus_traits<signed short> : public dbus_traits_integer<signed short> {};
template<> struct dbus_traits<unsigned short> : public dbus_traits_integer<unsigned short> {};
template<> struct dbus_traits<signed int> : public dbus_traits_integer<signed int> {};
template<> struct dbus_traits<unsigned int> : public dbus_traits_integer<unsigned int> {};
template<> struct dbus_traits<signed long> : public dbus_traits_integer<signed long> {};
template<> struct dbus_traits<unsigned long> : public dbus_traits_integer<unsigned long> {};
// Needed for int64_t and uint64. Not used internally, but occurs in
// external D-Bus APIs (for example, Bluez5 obexd). The assumption here
// is that "long long" is a valid type. If that assumption doesn't hold
// on some platform, then we need a configure check and ifdefs here.
template<> struct dbus_traits<signed long long> : public dbus_traits_integer<signed long long> {};
template<> struct dbus_traits<unsigned long long> : public dbus_traits_integer<unsigned long long> {};
template<> struct dbus_traits<double> :
public basic_marshal< double, VariantTypeDouble >
{
static std::string getType() { return "d"; }
static std::string getSignature() {return getType(); }
static std::string getReply() { return ""; }
};
template<> struct dbus_traits<bool> : public dbus_traits_base
// cannot use basic_marshal because VariantTypeBoolean packs/unpacks
// a gboolean, which is not a C++ bool (4 bytes vs 1 on x86_64)
// public basic_marshal< bool, VariantTypeBoolean >
{
static std::string getType() { return "b"; }
static std::string getSignature() {return getType(); }
static std::string getReply() { return ""; }
typedef bool host_type;
typedef bool arg_type;
static void get(ExtractArgs &context,
GVariantIter &iter, bool &value)
{
GVariantCXX var(g_variant_iter_next_value(&iter));
if (var == NULL || !g_variant_type_equal(g_variant_get_type(var), VariantTypeBoolean::getVariantType())) {
throw std::runtime_error("g_variant failure " GDBUS_CXX_SOURCE_INFO);
}
gboolean buffer;
const char *type = g_variant_get_type_string(var);
g_variant_get(var, type, &buffer);
value = buffer;
}
static void append(GVariantBuilder &builder, bool value)
{
const gchar *typeStr = g_variant_type_dup_string(VariantTypeBoolean::getVariantType());
g_variant_builder_add(&builder, typeStr, (gboolean)value);
g_free((gpointer)typeStr);
}
};
template<> struct dbus_traits<std::string> : public dbus_traits_base
{
static std::string getType() { return "s"; }
static std::string getSignature() {return getType(); }
static std::string getReply() { return ""; }
static void get(ExtractArgs &context,
GVariantIter &iter, std::string &value)
{
GVariantCXX var(g_variant_iter_next_value(&iter));
if (var == NULL || !g_variant_type_equal(g_variant_get_type(var), G_VARIANT_TYPE_STRING)) {
throw std::runtime_error("g_variant failure " GDBUS_CXX_SOURCE_INFO);
}
const char *str = g_variant_get_string(var, NULL);
value = str;
}
static void append(GVariantBuilder &builder, const std::string &value)
{
// g_variant_new_string() will log an assertion and/or return NULL
// (as in FDO #90118) when the string contains non-UTF-8 content.
// We must check in advance to avoid the assertion, even if that
// means duplicating the check (once here and once inside g_variant_new_string().
//
// Strictly speaking, this is something that the caller should
// have checked for, but as this should only happen for
// invalid external data (like broken iCalendar 2.0 events,
// see FDO #90118) and the only reasonable error handling in
// SyncEvolution would consist of filtering the data, so it is
// less intrusive overall to do that here: a question mark
// substitutes all invalid bytes.
const char *start = value.c_str(),
*end = value.c_str() + value.size();
const gchar *invalid;
bool valid = g_utf8_validate(start, end - start, &invalid);
GVariant *tmp;
if (valid) {
tmp = g_variant_new_string(value.c_str());
} else {
std::string buffer;
buffer.reserve(value.size());
while (true) {
if (valid) {
buffer.append(start, end - start);
// Empty string is valid, so we end up here in all cases.
break;
} else {
buffer.append(start, invalid - start);
buffer.append("?");
start = invalid + 1;
}
valid = g_utf8_validate(start, end - start, &invalid);
}
tmp = g_variant_new_string(buffer.c_str());
}
g_variant_builder_add_value(&builder, tmp);
}
typedef std::string host_type;
typedef const std::string &arg_type;
};
template<> struct dbus_traits<const char *> : public dbus_traits_base
{
static std::string getType() { return "s"; }
static std::string getSignature() {return getType(); }
static std::string getReply() { return ""; }
// Cannot copy into that type. Can only be used for encoding.
static void append(GVariantBuilder &builder, const char *value)
{
g_variant_builder_add_value(&builder, g_variant_new_string(value ? value : ""));
}
typedef const char *host_type;
typedef const char *arg_type;
};
template <> struct dbus_traits<DBusObject_t> : public dbus_traits_base
{
static std::string getType() { return "o"; }
static std::string getSignature() {return getType(); }
static std::string getReply() { return ""; }
static void get(ExtractArgs &context,
GVariantIter &iter, DBusObject_t &value)
{
GVariantCXX var(g_variant_iter_next_value(&iter));
if (var == NULL || !g_variant_type_equal(g_variant_get_type(var), G_VARIANT_TYPE_OBJECT_PATH)) {
throw std::runtime_error("g_variant failure " GDBUS_CXX_SOURCE_INFO);
}
const char *objPath = g_variant_get_string(var, NULL);
value = objPath;
}
static void append(GVariantBuilder &builder, const DBusObject_t &value)
{
if (!g_variant_is_object_path(value.c_str())) {
throw std::runtime_error("g_variant failure " GDBUS_CXX_SOURCE_INFO);
}
g_variant_builder_add_value(&builder, g_variant_new_object_path(value.c_str()));
}
typedef DBusObject_t host_type;
typedef const DBusObject_t &arg_type;
};
/**
* pseudo-parameter: not part of D-Bus signature,
* but rather extracted from message attributes
*/
template <> struct dbus_traits<Caller_t> : public dbus_traits_base
{
static std::string getType() { return ""; }
static std::string getSignature() { return ""; }
static std::string getReply() { return ""; }
static void get(ExtractArgs &context,
GVariantIter &iter, Caller_t &value)
{
const char *peer = (context.m_msg && *context.m_msg) ?
g_dbus_message_get_sender(*context.m_msg) :
context.m_sender;
if (!peer) {
throw std::runtime_error("D-Bus method call without sender?!");
}
value = peer;
}
typedef Caller_t host_type;
typedef const Caller_t &arg_type;
};
/**
* pseudo-parameter: not part of D-Bus signature,
* but rather extracted from message attributes
*/
template <> struct dbus_traits<Path_t> : public dbus_traits_base
{
static std::string getType() { return ""; }
static std::string getSignature() { return ""; }
static std::string getReply() { return ""; }
static void get(ExtractArgs &context,
GVariantIter &iter, Path_t &value)
{
const char *path = (context.m_msg && *context.m_msg) ?
g_dbus_message_get_path(*context.m_msg) :
context.m_path;
if (!path) {
throw std::runtime_error("D-Bus message without path?!");
}
value = path;
}
typedef Path_t host_type;
typedef const Path_t &arg_type;
};
/**
* pseudo-parameter: not part of D-Bus signature,
* but rather extracted from message attributes
*/
template <> struct dbus_traits<Interface_t> : public dbus_traits_base
{
static std::string getType() { return ""; }
static std::string getSignature() { return ""; }
static std::string getReply() { return ""; }
static void get(ExtractArgs &context,
GVariantIter &iter, Interface_t &value)
{
const char *path = (context.m_msg && *context.m_msg) ?
g_dbus_message_get_interface(*context.m_msg) :
context.m_interface;
if (!path) {
throw std::runtime_error("D-Bus message without interface?!");
}
value = path;
}
typedef Interface_t host_type;
typedef const Interface_t &arg_type;
};
/**
* pseudo-parameter: not part of D-Bus signature,
* but rather extracted from message attributes
*/
template <> struct dbus_traits<Member_t> : public dbus_traits_base
{
static std::string getType() { return ""; }
static std::string getSignature() { return ""; }
static std::string getReply() { return ""; }
static void get(ExtractArgs &context,
GVariantIter &iter, Member_t &value)
{
const char *path = (context.m_msg && *context.m_msg) ?
g_dbus_message_get_member(*context.m_msg) :
NULL;
if (!path) {
throw std::runtime_error("D-Bus message without member?!");
}
value = path;
}
typedef Member_t host_type;
typedef const Member_t &arg_type;
};
/**
* a std::pair - maps to D-Bus struct
*/
template<class A, class B> struct dbus_traits< std::pair<A,B> > : public dbus_traits_base
{
static std::string getContainedType()
{
return dbus_traits<A>::getType() + dbus_traits<B>::getType();
}
static std::string getType()
{
return "(" + getContainedType() + ")";
}
static std::string getSignature() {return getType(); }
static std::string getReply() { return ""; }
typedef std::pair<A,B> host_type;
typedef const std::pair<A,B> &arg_type;
static void get(ExtractArgs &context,
GVariantIter &iter, host_type &pair)
{
GVariantCXX var(g_variant_iter_next_value(&iter));
if (var == NULL || !g_variant_type_is_subtype_of(g_variant_get_type(var), G_VARIANT_TYPE_TUPLE)) {
throw std::runtime_error("g_variant failure " GDBUS_CXX_SOURCE_INFO);
}
GVariantIter tupIter;
g_variant_iter_init(&tupIter, var);
dbus_traits<A>::get(context, tupIter, pair.first);
dbus_traits<B>::get(context, tupIter, pair.second);
}
static void append(GVariantBuilder &builder, arg_type pair)
{
g_variant_builder_open(&builder, G_VARIANT_TYPE(getType().c_str()));
dbus_traits<A>::append(builder, pair.first);
dbus_traits<B>::append(builder, pair.second);
g_variant_builder_close(&builder);
}
};
/**
* a boost::tuple - maps to D-Bus struct
*/
template<class A, class B> struct dbus_traits< boost::tuple<A,B> > : public dbus_traits_base
{
static std::string getContainedType()
{
return dbus_traits<A>::getType() + dbus_traits<B>::getType();
}
static std::string getType()
{
return "(" + getContainedType() + ")";
}
static std::string getSignature() {return getType(); }
static std::string getReply() { return ""; }
typedef boost::tuple<A,B> host_type;
typedef const boost::tuple<A,B> &arg_type;
static void get(ExtractArgs &context,
GVariantIter &iter, host_type &t)
{
GVariantCXX var(g_variant_iter_next_value(&iter));
if (var == NULL || !g_variant_type_is_subtype_of(g_variant_get_type(var), G_VARIANT_TYPE_TUPLE)) {
throw std::runtime_error("g_variant failure " GDBUS_CXX_SOURCE_INFO);
}
GVariantIter tupIter;
g_variant_iter_init(&tupIter, var);
dbus_traits<A>::get(context, tupIter, boost::tuples::get<0>(t));
dbus_traits<B>::get(context, tupIter, boost::tuples::get<1>(t));
}
static void append(GVariantBuilder &builder, arg_type t)
{
g_variant_builder_open(&builder, G_VARIANT_TYPE(getType().c_str()));
dbus_traits<A>::append(builder, boost::tuples::get<0>(t));
dbus_traits<B>::append(builder, boost::tuples::get<1>(t));
g_variant_builder_close(&builder);
}
};
/**
* a boost::tuple - maps to D-Bus struct
*/
template<class A, class B, class C> struct dbus_traits< boost::tuple<A,B,C> > : public dbus_traits_base
{
static std::string getContainedType()
{
return dbus_traits<A>::getType() + dbus_traits<B>::getType() + dbus_traits<C>::getType();
}
static std::string getType()
{
return "(" + getContainedType() + ")";
}
static std::string getSignature() {return getType(); }
static std::string getReply() { return ""; }
typedef boost::tuple<A,B,C> host_type;
typedef const boost::tuple<A,B,C> &arg_type;
static void get(ExtractArgs &context,
GVariantIter &iter, host_type &t)
{
GVariantCXX var(g_variant_iter_next_value(&iter));
if (var == NULL || !g_variant_type_is_subtype_of(g_variant_get_type(var), G_VARIANT_TYPE_TUPLE)) {
throw std::runtime_error("g_variant failure " GDBUS_CXX_SOURCE_INFO);
}
GVariantIter tupIter;
g_variant_iter_init(&tupIter, var);
dbus_traits<A>::get(context, tupIter, boost::tuples::get<0>(t));
dbus_traits<B>::get(context, tupIter, boost::tuples::get<1>(t));
dbus_traits<C>::get(context, tupIter, boost::tuples::get<2>(t));
}
static void append(GVariantBuilder &builder, arg_type t)
{
g_variant_builder_open(&builder, G_VARIANT_TYPE(getType().c_str()));
dbus_traits<A>::append(builder, boost::tuples::get<0>(t));
dbus_traits<B>::append(builder, boost::tuples::get<1>(t));
dbus_traits<C>::append(builder, boost::tuples::get<2>(t));
g_variant_builder_close(&builder);
}
};
/**
* a boost::tuple - maps to D-Bus struct
*/
template<class A, class B, class C, class D> struct dbus_traits< boost::tuple<A,B,C,D> > : public dbus_traits_base
{
static std::string getContainedType()
{
return dbus_traits<A>::getType() + dbus_traits<B>::getType() + dbus_traits<C>::getType() + dbus_traits<D>::getType();
}
static std::string getType()
{
return "(" + getContainedType() + ")";
}
static std::string getSignature() {return getType(); }
static std::string getReply() { return ""; }
typedef boost::tuple<A,B,C,D> host_type;
typedef const boost::tuple<A,B,C,D> &arg_type;
static void get(ExtractArgs &context,
GVariantIter &iter, host_type &t)
{
GVariantCXX var(g_variant_iter_next_value(&iter));
if (var == NULL || !g_variant_type_is_subtype_of(g_variant_get_type(var), G_VARIANT_TYPE_TUPLE)) {
throw std::runtime_error("g_variant failure " GDBUS_CXX_SOURCE_INFO);
}
GVariantIter tupIter;
g_variant_iter_init(&tupIter, var);
dbus_traits<A>::get(context, tupIter, boost::tuples::get<0>(t));
dbus_traits<B>::get(context, tupIter, boost::tuples::get<1>(t));
dbus_traits<C>::get(context, tupIter, boost::tuples::get<2>(t));
dbus_traits<D>::get(context, tupIter, boost::tuples::get<3>(t));
}
static void append(GVariantBuilder &builder, arg_type t)
{
g_variant_builder_open(&builder, G_VARIANT_TYPE(getType().c_str()));
dbus_traits<A>::append(builder, boost::tuples::get<0>(t));
dbus_traits<B>::append(builder, boost::tuples::get<1>(t));
dbus_traits<C>::append(builder, boost::tuples::get<2>(t));
dbus_traits<D>::append(builder, boost::tuples::get<3>(t));
g_variant_builder_close(&builder);
}
};
/**
* dedicated type for chunk of data, to distinguish this case from
* a normal std::pair of two values
*/
template<class V> class DBusArray : public std::pair<size_t, const V *>
{
public:
DBusArray() :
std::pair<size_t, const V *>(0, NULL)
{}
DBusArray(size_t len, const V *data) :
std::pair<size_t, const V *>(len, data)
{}
};
template<class V> class DBusArray<V> makeDBusArray(size_t len, const V *data) { return DBusArray<V>(len, data); }
/**
* Pass array of basic type plus its number of entries.
* Can only be used in cases where the caller owns the
* memory and can discard it when the call returns, in
* other words, for method calls, asynchronous replys and
* signals, but not for return values.
*/
template<class V> struct dbus_traits< DBusArray<V> > : public dbus_traits_base
{
static std::string getContainedType()
{
return dbus_traits<V>::getType();
}
static std::string getType()
{
return std::string("a") +
dbus_traits<V>::getType();
}
static std::string getSignature() {return getType(); }
static std::string getReply() { return ""; }
typedef DBusArray<V> host_type;
typedef const host_type &arg_type;
static void get(ExtractArgs &context,
GVariantIter &iter, host_type &array)
{
GVariantCXX var(g_variant_iter_next_value(&iter));
if (var == NULL || !g_variant_type_is_subtype_of(g_variant_get_type(var), G_VARIANT_TYPE_ARRAY)) {
throw std::runtime_error("g_variant failure " GDBUS_CXX_SOURCE_INFO);
}
typedef typename dbus_traits<V>::host_type V_host_type;
gsize nelements;
V_host_type *data;
data = (V_host_type *) g_variant_get_fixed_array(var,
&nelements,
static_cast<gsize>(sizeof(V_host_type)));
array.first = nelements;
array.second = data;
}
static void append(GVariantBuilder &builder, arg_type array)
{
g_variant_builder_add_value(&builder,
g_variant_new_from_data(G_VARIANT_TYPE(getType().c_str()),
(gconstpointer)array.second,
array.first,
true, // data is trusted to be in serialized form
NULL, NULL // no need to free data
));
}
};
/**
* a std::map - treat it like a D-Bus dict
*/
template<class K, class V, class C> struct dbus_traits< std::map<K, V, C> > : public dbus_traits_base
{
static std::string getContainedType()
{
return std::string("{") +
dbus_traits<K>::getType() +
dbus_traits<V>::getType() +
"}";
}
static std::string getType()
{
return std::string("a") +
getContainedType();
}
static std::string getSignature() {return getType(); }
static std::string getReply() { return ""; }
typedef std::map<K, V, C> host_type;
typedef const host_type &arg_type;
static void get(ExtractArgs &context,
GVariantIter &iter, host_type &dict)
{
GVariantCXX var(g_variant_iter_next_value(&iter));
if (var == NULL || !g_variant_type_is_subtype_of(g_variant_get_type(var), G_VARIANT_TYPE_ARRAY)) {
throw std::runtime_error("g_variant failure " GDBUS_CXX_SOURCE_INFO);
}
GVariantIter contIter;
GVariantCXX child;
g_variant_iter_init(&contIter, var);
while((child = g_variant_iter_next_value(&contIter)) != NULL) {
K key;
V value;
GVariantIter childIter;
g_variant_iter_init(&childIter, child);
dbus_traits<K>::get(context, childIter, key);
dbus_traits<V>::get(context, childIter, value);
dict.insert(std::make_pair(key, value));
}
}
static void append(GVariantBuilder &builder, arg_type dict)
{
g_variant_builder_open(&builder, G_VARIANT_TYPE(getType().c_str()));
for(typename host_type::const_iterator it = dict.begin();
it != dict.end();
++it) {
g_variant_builder_open(&builder, G_VARIANT_TYPE(getContainedType().c_str()));
dbus_traits<K>::append(builder, it->first);
dbus_traits<V>::append(builder, it->second);
g_variant_builder_close(&builder);
}
g_variant_builder_close(&builder);
}
};
/**
* A collection of items (works for std::list, std::vector, std::deque, ...).
* Maps to D-Bus array, but with inefficient marshaling
* because we cannot get a base pointer for the whole array.
*/
template<class C, class V> struct dbus_traits_collection : public dbus_traits_base
{
static std::string getContainedType()
{
return dbus_traits<V>::getType();
}
static std::string getType()
{
return std::string("a") +
getContainedType();
}
static std::string getSignature() {return getType(); }
static std::string getReply() { return ""; }
typedef C host_type;
typedef const C &arg_type;
static void get(ExtractArgs &context,
GVariantIter &iter, host_type &array)
{
GVariantCXX var(g_variant_iter_next_value(&iter));
if (var == NULL || !g_variant_type_is_subtype_of(g_variant_get_type(var), G_VARIANT_TYPE_ARRAY)) {
throw std::runtime_error("g_variant failure " GDBUS_CXX_SOURCE_INFO);
}
int nelements = g_variant_n_children(var);
GVariantIter childIter;
g_variant_iter_init(&childIter, var);
for(int i = 0; i < nelements; ++i) {
V value;
dbus_traits<V>::get(context, childIter, value);
array.push_back(value);
}
}
static void append(GVariantBuilder &builder, arg_type array)
{
g_variant_builder_open(&builder, G_VARIANT_TYPE(getType().c_str()));
for(typename host_type::const_iterator it = array.begin();
it != array.end();
++it) {
dbus_traits<V>::append(builder, *it);
}
g_variant_builder_close(&builder);
}
};
template<class V> struct dbus_traits< std::vector<V> > : public dbus_traits_collection<std::vector<V>, V> {};
template<class V> struct dbus_traits< std::list<V> > : public dbus_traits_collection<std::list<V>, V> {};
template<class V> struct dbus_traits< std::deque<V> > : public dbus_traits_collection<std::deque<V>, V> {};
struct append_visitor : public boost::static_visitor<>
{
GVariantBuilder &builder;
append_visitor(GVariantBuilder &b) : builder(b) {}
template <class V> void operator()(const V &v) const
{
dbus_traits<V>::append(builder, v);
}
};
/**
* A boost::variant <V> maps to a dbus variant, only care about values of
* type V but will not throw error if type is not matched, this is useful if
* application is interested on only a sub set of possible value types
* in variant.
*/
template<class BV> struct dbus_variant_base : public dbus_traits_base
{
static std::string getType() { return "v"; }
static std::string getSignature() { return getType(); }
static std::string getReply() { return ""; }
typedef BV host_type;
typedef const BV &arg_type;
static void append(GVariantBuilder &builder, const BV &value)
{
g_variant_builder_open(&builder, G_VARIANT_TYPE(getType().c_str()));
boost::apply_visitor(append_visitor(builder), value);
g_variant_builder_close(&builder);
}
};
template <class V> struct dbus_traits <boost::variant <V> > :
public dbus_variant_base< boost::variant <V> >
{
static void get(ExtractArgs &context,
GVariantIter &iter, boost::variant <V> &value)
{
GVariantCXX var(g_variant_iter_next_value(&iter));
if (var == NULL || !g_variant_type_equal(g_variant_get_type(var), G_VARIANT_TYPE_VARIANT)) {
throw std::runtime_error("g_variant failure " GDBUS_CXX_SOURCE_INFO);
}
GVariantIter varIter;
g_variant_iter_init(&varIter, var);
GVariantCXX varVar(g_variant_iter_next_value(&varIter));
const char *type = g_variant_get_type_string(varVar);
if (dbus_traits<V>::getSignature() != type) {
//ignore unrecognized sub type in variant
return;
}
V val;
// Note: Reset the iterator so that the call to dbus_traits<V>::get() will get the right variant;
g_variant_iter_init(&varIter, var);
dbus_traits<V>::get(context, varIter, val);
value = val;
}
};
template <class V1, class V2> struct dbus_traits <boost::variant <V1, V2> > :
public dbus_variant_base< boost::variant <V1, V2> >
{
static void get(ExtractArgs &context,
GVariantIter &iter, boost::variant <V1, V2> &value)
{
GVariantCXX var(g_variant_iter_next_value(&iter));
if (var == NULL || !g_variant_type_equal(g_variant_get_type(var), G_VARIANT_TYPE_VARIANT)) {
throw std::runtime_error("g_variant failure " GDBUS_CXX_SOURCE_INFO);
}
GVariantIter varIter;
g_variant_iter_init(&varIter, var);
GVariantCXX varVar(g_variant_iter_next_value(&varIter));
const char *type = g_variant_get_type_string(varVar);
if (dbus_traits<V1>::getSignature() == type) {
V1 val;
// Note: Reset the iterator so that the call to dbus_traits<V>::get() will get the right variant;
g_variant_iter_init(&varIter, var);
dbus_traits<V1>::get(context, varIter, val);
value = val;
} else if (dbus_traits<V2>::getSignature() == type) {
V2 val;
g_variant_iter_init(&varIter, var);
dbus_traits<V2>::get(context, varIter, val);
value = val;
} else {
// ignore unrecognized sub type in variant
return;
}
}
};
template <class V1, class V2, class V3> struct dbus_traits <boost::variant <V1, V2, V3> > :
public dbus_variant_base< boost::variant <V1, V2, V3> >
{
static void get(ExtractArgs &context,
GVariantIter &iter, boost::variant <V1, V2, V3> &value)
{
GVariantCXX var(g_variant_iter_next_value(&iter));
if (var == NULL || !g_variant_type_equal(g_variant_get_type(var), G_VARIANT_TYPE_VARIANT)) {
throw std::runtime_error("g_variant failure " GDBUS_CXX_SOURCE_INFO);
}
GVariantIter varIter;
g_variant_iter_init(&varIter, var);
GVariantCXX varVar(g_variant_iter_next_value(&varIter));
const char *type = g_variant_get_type_string(varVar);
if (dbus_traits<V1>::getSignature() == type) {
V1 val;
// Note: Reset the iterator so that the call to dbus_traits<V>::get() will get the right variant;
g_variant_iter_init(&varIter, var);
dbus_traits<V1>::get(context, varIter, val);
value = val;
} else if (dbus_traits<V2>::getSignature() == type) {
V2 val;
g_variant_iter_init(&varIter, var);
dbus_traits<V2>::get(context, varIter, val);
value = val;
} else if (dbus_traits<V3>::getSignature() == type) {
V3 val;
g_variant_iter_init(&varIter, var);
dbus_traits<V3>::get(context, varIter, val);
value = val;
} else {
// ignore unrecognized sub type in variant
return;
}
}
};
template <class V1, class V2, class V3, class V4> struct dbus_traits <boost::variant <V1, V2, V3, V4> > :
public dbus_variant_base< boost::variant <V1, V2, V3, V4> >
{
static void get(ExtractArgs &context,
GVariantIter &iter, boost::variant <V1, V2, V3> &value)
{
GVariantCXX var(g_variant_iter_next_value(&iter));
if (var == NULL || !g_variant_type_equal(g_variant_get_type(var), G_VARIANT_TYPE_VARIANT)) {
throw std::runtime_error("g_variant failure " GDBUS_CXX_SOURCE_INFO);
}
GVariantIter varIter;
g_variant_iter_init(&varIter, var);
GVariantCXX varVar(g_variant_iter_next_value(&varIter));
const char *type = g_variant_get_type_string(varVar);
if (dbus_traits<V1>::getSignature() == type) {
V1 val;
// Note: Reset the iterator so that the call to dbus_traits<V>::get() will get the right variant;
g_variant_iter_init(&varIter, var);
dbus_traits<V1>::get(context, varIter, val);
value = val;
} else if (dbus_traits<V2>::getSignature() == type) {
V2 val;
g_variant_iter_init(&varIter, var);
dbus_traits<V2>::get(context, varIter, val);
value = val;
} else if (dbus_traits<V3>::getSignature() == type) {
V3 val;
g_variant_iter_init(&varIter, var);
dbus_traits<V3>::get(context, varIter, val);
value = val;
} else if (dbus_traits<V4>::getSignature() == type) {
V4 val;
g_variant_iter_init(&varIter, var);
dbus_traits<V4>::get(context, varIter, val);
value = val;
} else {
// ignore unrecognized sub type in variant
return;
}
}
};
template <class V1, class V2, class V3, class V4, class V5> struct dbus_traits <boost::variant <V1, V2, V3, V4, V5> > :
public dbus_variant_base< boost::variant <V1, V2, V3, V4, V5> >
{
static void get(ExtractArgs &context,
GVariantIter &iter, boost::variant <V1, V2, V3> &value)
{
GVariantCXX var(g_variant_iter_next_value(&iter));
if (var == NULL || !g_variant_type_equal(g_variant_get_type(var), G_VARIANT_TYPE_VARIANT)) {
throw std::runtime_error("g_variant failure " GDBUS_CXX_SOURCE_INFO);
}
GVariantIter varIter;
g_variant_iter_init(&varIter, var);
GVariantCXX varVar(g_variant_iter_next_value(&varIter));
const char *type = g_variant_get_type_string(varVar);
if (dbus_traits<V1>::getSignature() == type) {
V1 val;
// Note: Reset the iterator so that the call to dbus_traits<V>::get() will get the right variant;
g_variant_iter_init(&varIter, var);
dbus_traits<V1>::get(context, varIter, val);
value = val;
} else if (dbus_traits<V2>::getSignature() == type) {
V2 val;
g_variant_iter_init(&varIter, var);
dbus_traits<V2>::get(context, varIter, val);
value = val;
} else if (dbus_traits<V3>::getSignature() == type) {
V3 val;
g_variant_iter_init(&varIter, var);
dbus_traits<V3>::get(context, varIter, val);
value = val;
} else if (dbus_traits<V4>::getSignature() == type) {
V4 val;
g_variant_iter_init(&varIter, var);
dbus_traits<V4>::get(context, varIter, val);
value = val;
} else if (dbus_traits<V5>::getSignature() == type) {
V5 val;
g_variant_iter_init(&varIter, var);
dbus_traits<V5>::get(context, varIter, val);
value = val;
} else {
// ignore unrecognized sub type in variant
return;
}
}
};
/**
* A recursive variant. Can represent values of a certain type V and
* vectors with a mixture of such values and the variant. Limiting
* this to vectors is done for the sake of simplicity and because
* vector is fairly efficient to work with, in particular when
* implementing methods.
*
* It would be nice to not refer to boost internals here. But using
* "typename boost::make_recursive_variant<V, std::vector< boost::recursive_variant_ > >::type"
* instead of the expanded
* "boost::variant< boost::detail::variant::recursive_flag<V>, A>"
* leads to a compiler error:
* class template partial specialization contains a template parameter that can not be deduced; this partial specialization will never be used [-Werror]
* ...dbus_traits < typename boost::make_recursive_variant<V, std::vector< boost::recursive_variant_ > >::type > ...
* ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
template <class V, class A> struct dbus_traits < boost::variant<boost::detail::variant::recursive_flag<V>, A> > : public dbus_traits_base
{
static std::string getType() { return "v"; }
static std::string getSignature() { return getType(); }
static std::string getReply() { return ""; }
typedef boost::variant<boost::detail::variant::recursive_flag<V>, A> host_type;
typedef const host_type &arg_type;
static void get(ExtractArgs &context,
GVariantIter &iter, host_type &value)
{
GVariantIterCXX itercopy(g_variant_iter_copy(&iter));
// Peek at next element, then decide what to do with it.
GVariantCXX var(g_variant_iter_next_value(&iter));
// We accept a variant, the plain type V, or an array.
// This is necessary for clients like Python which
// send [['foo', 'bar']] as 'aas' when seeing 'v'
// as signature.
if (var == NULL) {
throw std::runtime_error("g_variant failure " GDBUS_CXX_SOURCE_INFO);
}
const char *type = g_variant_get_type_string(var);
if (!strcmp(type, "v")) {
// Strip the outer variant and decode the inner value recursively, in
// our own else branch.
GVariantIter varIter;
g_variant_iter_init(&varIter, var);
dbus_traits<host_type>::get(context, varIter, value);
} else if (dbus_traits<V>::getSignature() == type) {
V val;
dbus_traits<V>::get(context, *itercopy, val);
value = val;
} else if (type[0] == 'a') {
std::vector<host_type> val;
dbus_traits< std::vector<host_type> >::get(context, *itercopy, val);
value = val;
} else if (type[0] == '(') {
// Treat a tuple like an array. We have to iterate ourself here.
std::vector<host_type> val;
GVariantIter tupIter;
g_variant_iter_init(&tupIter, var);
GVariantIterCXX copy(g_variant_iter_copy(&tupIter));
// Step through the elements in lockstep. We need this
// because we must not call the get() method when there is
// nothing to unpack.
while (GVariantCXX(g_variant_iter_next_value(copy))) {
host_type tmp;
dbus_traits<host_type>::get(context, tupIter, tmp);
val.push_back(tmp);
}
value = val;
} else {
// More strict than the other variants, because it is mostly used for
// method calls where we don't want to silently ignore parts of the
// parameter.
throw std::runtime_error(std::string("expected recursive variant containing " + dbus_traits<V>::getSignature() + ", got " + type));
return;
}
}
static void append(GVariantBuilder &builder, const boost::variant<V> &value)
{
g_variant_builder_open(&builder, G_VARIANT_TYPE(getType().c_str()));
boost::apply_visitor(append_visitor(builder), value);
g_variant_builder_close(&builder);
}
};
/**
* a single member m of type V in a struct K
*/
template<class K, class V, V K::*m> struct dbus_member_single
{
static std::string getType()
{
return dbus_traits<V>::getType();
}
typedef V host_type;
static void get(ExtractArgs &context,
GVariantIter &iter, K &val)
{
dbus_traits<V>::get(context, iter, val.*m);
}
static void append(GVariantBuilder &builder, const K &val)
{
dbus_traits<V>::append(builder, val.*m);
}
};
/**
* a member m of type V in a struct K, followed by another dbus_member
* or dbus_member_single to end the chain
*/
template<class K, class V, V K::*m, class M> struct dbus_member
{
static std::string getType()
{
return dbus_traits<V>::getType() + M::getType();
}
typedef V host_type;
static void get(ExtractArgs &context,
GVariantIter &iter, K &val)
{
dbus_traits<V>::get(context, iter, val.*m);
M::get(context, iter, val);
}
static void append(GVariantBuilder &builder, const K &val)
{
dbus_traits<V>::append(builder, val.*m);
M::append(builder, val);
}
};
/**
* The base class of type V of a struct K, followed by another dbus_member
* or dbus_member_single to end the chain
*/
template<class K, class V, class M> struct dbus_base
{
static std::string getType()
{
return dbus_traits<V>::getType() + M::getType();
}
typedef V host_type;
static void get(ExtractArgs &context,
GVariantIter &iter, K &val)
{
dbus_traits<V>::get(context, iter, val);
M::get(context, iter, val);
}
static void append(GVariantBuilder &builder, const K &val)
{
dbus_traits<V>::append(builder, val);
M::append(builder, val);
}
};
/**
* a helper class which implements dbus_traits for
* a class, use with:
* struct foo { int a; std::string b; };
* template<> struct dbus_traits< foo > : dbus_struct_traits< foo,
* dbus_member<foo, int, &foo::a,
* dbus_member_single<foo, std::string, &foo::b> > > {};
*/
template<class K, class M> struct dbus_struct_traits : public dbus_traits_base
{
static std::string getContainedType()
{
return M::getType();
}
static std::string getType()
{
return std::string("(") +
getContainedType() +
")";
}
static std::string getSignature() {return getType(); }
static std::string getReply() { return ""; }
typedef K host_type;
typedef const K &arg_type;
static void get(ExtractArgs &context,
GVariantIter &iter, host_type &val)
{
GVariantCXX var(g_variant_iter_next_value(&iter));
if (var == NULL || !g_variant_type_is_subtype_of(g_variant_get_type(var), G_VARIANT_TYPE_TUPLE)) {
throw std::runtime_error("g_variant failure " GDBUS_CXX_SOURCE_INFO);
}
GVariantIter tupIter;
g_variant_iter_init(&tupIter, var);
M::get(context, tupIter, val);
}
static void append(GVariantBuilder &builder, arg_type val)
{
g_variant_builder_open(&builder, G_VARIANT_TYPE(getType().c_str()));
M::append(builder, val);
g_variant_builder_close(&builder);
}
};
/**
* a helper class which implements dbus_traits for an enum,
* parameterize it with the enum type and an integer type
* large enough to hold all valid enum values
*/
template<class E, class I> struct dbus_enum_traits : public dbus_traits<I>
{
typedef E host_type;
typedef E arg_type;
// cast from enum to int in append() is implicit; in
// get() we have to make it explicit
static void get(ExtractArgs &context,
GVariantIter &iter, host_type &val)
{
I ival;
dbus_traits<I>::get(context, iter, ival);
val = static_cast<E>(ival);
}
};
/**
* special case const reference parameter:
* treat like pass-by-value input argument
*
* Example: const std::string &arg
*/
template<class C> struct dbus_traits<const C &> : public dbus_traits<C> {};
/**
* special case writeable reference parameter:
* must be a return value
*
* Example: std::string &retval
*/
template<class C> struct dbus_traits<C &> : public dbus_traits<C>
{
static std::string getSignature() { return ""; }
static std::string getReply() { return dbus_traits<C>::getType(); }
};
/**
* dbus-cxx base exception thrown in dbus server
* org.syncevolution.gdbuscxx.Exception
* This base class only contains interfaces, no data members
*/
class DBusCXXException
{
public:
/**
* get exception name, used to convert to dbus error name
* subclasses should override it
*/
virtual std::string getName() const { return "org.syncevolution.gdbuscxx.Exception"; }
/**
* get error message
*/
virtual const char* getMessage() const { return "unknown"; }
};
static GDBusMessage *handleException(GDBusMessage *&callerMsg)
{
// We provide a reply to the message. Clear the "msg" variable
// in our caller's context to make it as done.
GDBusMessage *msg = callerMsg;
callerMsg = NULL;
try {
#ifdef DBUS_CXX_EXCEPTION_HANDLER
return DBUS_CXX_EXCEPTION_HANDLER(msg);
#else
throw;
#endif
} catch (const dbus_error &ex) {
return g_dbus_message_new_method_error_literal(msg, ex.dbusName().c_str(), ex.what());
} catch (const DBusCXXException &ex) {
return g_dbus_message_new_method_error_literal(msg, ex.getName().c_str(), ex.getMessage());
} catch (const std::runtime_error &ex) {
return g_dbus_message_new_method_error_literal(msg, "org.syncevolution.gdbuscxx.Exception", ex.what());
} catch (...) {
return g_dbus_message_new_method_error_literal(msg, "org.syncevolution.gdbuscxx.Exception", "unknown");
}
}
/**
* Check presence of a certain D-Bus client.
*/
class Watch : private boost::noncopyable
{
DBusConnectionPtr m_conn;
boost::function<void (void)> m_callback;
bool m_called;
guint m_watchID;
std::string m_peer;
static void nameOwnerChanged(GDBusConnection *connection,
const gchar *sender_name,
const gchar *object_path,
const gchar *interface_name,
const gchar *signal_name,
GVariant *parameters,
gpointer user_data);
void disconnected();
public:
Watch(const DBusConnectionPtr &conn,
const boost::function<void (void)> &callback = boost::function<void (void)>());
~Watch();
/**
* Changes the callback triggered by this Watch. If the watch has
* already fired, the callback is invoked immediately.
*/
void setCallback(const boost::function<void (void)> &callback);
/**
* Starts watching for disconnect of that peer
* and also checks whether it is currently
* still around.
*/
void activate(const char *peer);
};
void getWatch(ExtractArgs &context, boost::shared_ptr<Watch> &value);
/**
* pseudo-parameter: not part of D-Bus signature,
* but rather extracted from message attributes
*/
template <> struct dbus_traits< boost::shared_ptr<Watch> > : public dbus_traits_base
{
static std::string getType() { return ""; }
static std::string getSignature() { return ""; }
static std::string getReply() { return ""; }
static void get(ExtractArgs &context,
GVariantIter &iter, boost::shared_ptr<Watch> &value) { getWatch(context, value); }
static void append(GVariantBuilder &builder, const boost::shared_ptr<Watch> &value) {}
typedef boost::shared_ptr<Watch> host_type;
typedef const boost::shared_ptr<Watch> &arg_type;
};
/**
* base class for D-Bus results,
* keeps references to required objects and provides the
* failed() method
*/
class DBusResult : virtual public Result
{
protected:
DBusConnectionPtr m_conn; /**< connection via which the message was received */
DBusMessagePtr m_msg; /**< the method invocation message */
bool m_haveOwnership; /**< this class is responsible for sending a method reply */
bool m_replied; /**< a response was sent */
void sendMsg(const DBusMessagePtr &msg)
{
m_replied = true;
GError *error = NULL;
if (!g_dbus_connection_send_message(m_conn.get(), msg.get(),
G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, &error)) {
throwFailure("", "g_dbus_connection_send_message()", error);
}
}
public:
DBusResult(GDBusConnection *conn,
GDBusMessage *msg) :
m_conn(conn, true),
m_msg(msg, true),
m_haveOwnership(false),
m_replied(false)
{}
~DBusResult()
{
if (m_haveOwnership && !m_replied) {
try {
failed(dbus_error("org.syncevolution.gdbus", "processing the method call failed"));
} catch (...) {
// Ignore failure, we are probably shutting down
// anyway, which will tell the caller that the
// method won't be processed.
}
}
}
void transferOwnership() throw ()
{
m_haveOwnership = true;
}
virtual void failed(const dbus_error &error)
{
DBusMessagePtr errMsg(g_dbus_message_new_method_error(m_msg.get(), error.dbusName().c_str(),
"%s", error.what()));
sendMsg(errMsg);
}
virtual Watch *createWatch(const boost::function<void (void)> &callback)
{
std::unique_ptr<Watch> watch(new Watch(m_conn, callback));
watch->activate(g_dbus_message_get_sender(m_msg.get()));
return watch.release();
}
};
class DBusResult0 :
public Result0,
public DBusResult
{
public:
DBusResult0(GDBusConnection *conn,
GDBusMessage *msg) :
DBusResult(conn, msg)
{}
virtual void done()
{
DBusMessagePtr reply(g_dbus_message_new_method_reply(m_msg.get()));
if (!reply) {
throw std::runtime_error("no GDBusMessage");
}
sendMsg(reply);
}
static std::string getSignature() { return ""; }
};
template <typename A1>
class DBusResult1 :
public Result1<A1>,
public DBusResult
{
public:
DBusResult1(GDBusConnection *conn,
GDBusMessage *msg) :
DBusResult(conn, msg)
{}
virtual void done(A1 a1)
{
DBusMessagePtr reply(g_dbus_message_new_method_reply(m_msg.get()));
if (!reply) {
throw std::runtime_error("no GDBusMessage");
}
AppendRetvals(reply) << a1;
sendMsg(reply);
}
static std::string getSignature() { return dbus_traits<A1>::getSignature(); }
static const bool asynchronous = dbus_traits<A1>::asynchronous;
};
template <typename A1, typename A2>
class DBusResult2 :
public Result2<A1, A2>,
public DBusResult
{
public:
DBusResult2(GDBusConnection *conn,
GDBusMessage *msg) :
DBusResult(conn, msg)
{}
virtual void done(A1 a1, A2 a2)
{
DBusMessagePtr reply(g_dbus_message_new_method_reply(m_msg.get()));
if (!reply) {
throw std::runtime_error("no GDBusMessage");
}
AppendRetvals(reply) << a1 << a2;
sendMsg(reply);
}
static std::string getSignature() {
return dbus_traits<A1>::getSignature() +
DBusResult1<A2>::getSignature();
}
static const bool asynchronous =
dbus_traits<A1>::asynchronous ||
DBusResult1<A2>::asynchronous;
};
template <typename A1, typename A2, typename A3>
class DBusResult3 :
public Result3<A1, A2, A3>,
public DBusResult
{
public:
DBusResult3(GDBusConnection *conn,
GDBusMessage *msg) :
DBusResult(conn, msg)
{}
virtual void done(A1 a1, A2 a2, A3 a3)
{
DBusMessagePtr reply(g_dbus_message_new_method_reply(m_msg.get()));
if (!reply) {
throw std::runtime_error("no GDBusMessage");
}
AppendRetvals(reply) << a1 << a2 << a3;
sendMsg(reply);
}
static std::string getSignature() {
return dbus_traits<A1>::getSignature() +
DBusResult2<A2, A3>::getSignature();
}
static const bool asynchronous =
dbus_traits<A1>::asynchronous ||
DBusResult2<A2, A3>::asynchronous;
};
template <typename A1, typename A2, typename A3, typename A4>
class DBusResult4 :
public Result4<A1, A2, A3, A4>,
public DBusResult
{
public:
DBusResult4(GDBusConnection *conn,
GDBusMessage *msg) :
DBusResult(conn, msg)
{}
virtual void done(A1 a1, A2 a2, A3 a3, A4 a4)
{
DBusMessagePtr reply(g_dbus_message_new_method_reply(m_msg.get()));
if (!reply) {
throw std::runtime_error("no GDBusMessage");
}
AppendRetvals(reply) << a1 << a2 << a3 << a4;
sendMsg(reply);
}
static std::string getSignature() {
return dbus_traits<A1>::getSignature() +
DBusResult3<A2, A3, A4>::getSignature();
}
static const bool asynchronous =
dbus_traits<A1>::asynchronous ||
DBusResult3<A2, A3, A4>::asynchronous;
};
template <typename A1, typename A2, typename A3, typename A4, typename A5>
class DBusResult5 :
public Result5<A1, A2, A3, A4, A5>,
public DBusResult
{
public:
DBusResult5(GDBusConnection *conn,
GDBusMessage *msg) :
DBusResult(conn, msg)
{}
virtual void done(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5)
{
DBusMessagePtr reply(g_dbus_message_new_method_reply(m_msg.get()));
if (!reply) {
throw std::runtime_error("no GDBusMessage");
}
AppendRetvals(reply) << a1 << a2 << a3 << a4 << a5;
sendMsg(reply);
}
static std::string getSignature() {
return dbus_traits<A1>::getSignature() +
DBusResult4<A2, A3, A4, A5>::getSignature();
}
static const bool asynchronous =
dbus_traits<A1>::asynchronous ||
DBusResult4<A2, A3, A4, A5>::asynchronous;
};
template <typename A1, typename A2, typename A3, typename A4, typename A5,
typename A6>
class DBusResult6 :
public Result6<A1, A2, A3, A4, A5, A6>,
public DBusResult
{
public:
DBusResult6(GDBusConnection *conn,
GDBusMessage *msg) :
DBusResult(conn, msg)
{}
virtual void done(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6)
{
DBusMessagePtr reply(g_dbus_message_new_method_reply(m_msg.get()));
if (!reply) {
throw std::runtime_error("no GDBusMessage");
}
AppendRetvals(reply) << a1 << a2 << a3 << a4 << a5 << a6;
sendMsg(reply);
}
static std::string getSignature() {
return dbus_traits<A1>::getSignature() +
DBusResult5<A2, A3, A4, A5, A6>::getSignature();
}
static const bool asynchronous =
dbus_traits<A1>::asynchronous ||
DBusResult5<A2, A3, A4, A5, A6>::asynchronous;
};
template <typename A1, typename A2, typename A3, typename A4, typename A5,
typename A6, typename A7>
class DBusResult7 :
public Result7<A1, A2, A3, A4, A5, A6, A7>,
public DBusResult
{
public:
DBusResult7(GDBusConnection *conn,
GDBusMessage *msg) :
DBusResult(conn, msg)
{}
virtual void done(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7)
{
DBusMessagePtr reply(g_dbus_message_new_method_reply(m_msg.get()));
if (!reply) {
throw std::runtime_error("no GDBusMessage");
}
AppendRetvals(reply) << a1 << a2 << a3 << a4 << a5 << a6 << a7;
sendMsg(reply);
}
static std::string getSignature() {
return dbus_traits<A1>::getSignature() +
DBusResult6<A2, A3, A4, A5, A6, A7>::getSignature();
}
static const bool asynchronous =
dbus_traits<A1>::asynchronous ||
DBusResult6<A2, A3, A4, A5, A6, A7>::asynchronous;
};
template <typename A1, typename A2, typename A3, typename A4, typename A5,
typename A6, typename A7, typename A8>
class DBusResult8 :
public Result8<A1, A2, A3, A4, A5, A6, A7, A8>,
public DBusResult
{
public:
DBusResult8(GDBusConnection *conn,
GDBusMessage *msg) :
DBusResult(conn, msg)
{}
virtual void done(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8)
{
DBusMessagePtr reply(g_dbus_message_new_method_reply(m_msg.get()));
if (!reply) {
throw std::runtime_error("no GDBusMessage");
}
AppendRetvals(reply) << a1 << a2 << a3 << a4 << a5 << a6 << a7 << a8;
sendMsg(reply);
}
static std::string getSignature() {
return dbus_traits<A1>::getSignature() +
DBusResult7<A2, A3, A4, A5, A6, A7, A8>::getSignature();
}
static const bool asynchronous =
dbus_traits<A1>::asynchronous ||
DBusResult7<A2, A3, A4, A5, A6, A7, A8>::asynchronous;
};
template <typename A1, typename A2, typename A3, typename A4, typename A5,
typename A6, typename A7, typename A8, typename A9>
class DBusResult9 :
public Result9<A1, A2, A3, A4, A5, A6, A7, A8, A9>,
public DBusResult
{
public:
DBusResult9(GDBusConnection *conn,
GDBusMessage *msg) :
DBusResult(conn, msg)
{}
virtual void done(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9)
{
DBusMessagePtr reply(g_dbus_message_new_method_reply(m_msg.get()));
if (!reply) {
throw std::runtime_error("no GDBusMessage");
}
AppendRetvals(reply) << a1 << a2 << a3 << a4 << a5 << a6 << a7 << a8 << a9;
sendMsg(reply);
}
static std::string getSignature() {
return dbus_traits<A1>::getSignature() +
DBusResult8<A2, A3, A4, A5, A6, A7, A8, A9>::getSignature();
}
static const bool asynchronous =
dbus_traits<A1>::asynchronous ||
DBusResult8<A2, A3, A4, A5, A6, A7, A8, A9>::asynchronous;
};
template <typename A1, typename A2, typename A3, typename A4, typename A5,
typename A6, typename A7, typename A8, typename A9, typename A10>
class DBusResult10 :
public Result10<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10>,
public DBusResult
{
public:
DBusResult10(GDBusConnection *conn,
GDBusMessage *msg) :
DBusResult(conn, msg)
{}
virtual void done(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10)
{
DBusMessagePtr reply(g_dbus_message_new_method_reply(m_msg.get()));
if (!reply) {
throw std::runtime_error("no GDBusMessage");
}
AppendRetvals(reply) << a1 << a2 << a3 << a4 << a5 << a6 << a7 << a8 << a9 << a10;
sendMsg(reply);
}
static std::string getSignature() {
return dbus_traits<A1>::getSignature() +
DBusResult9<A2, A3, A4, A5, A6, A7, A8, A9, A10>::getSignature();
}
static const bool asynchronous =
dbus_traits<A1>::asynchronous ||
DBusResult9<A2, A3, A4, A5, A6, A7, A8, A9, A10>::asynchronous;
};
/**
* Helper class for constructing a DBusResult: while inside the
* initial method call handler, we have a try/catch block which will
* reply to the caller. Once we leave that block, this class here
* destructs and transfers the responsibility for sending a reply to
* the DBusResult instance.
*/
template <class DBusR> class DBusResultGuard : public boost::shared_ptr<DBusR>
{
GDBusMessage **m_msg;
public:
DBusResultGuard() : m_msg(NULL) {}
~DBusResultGuard() throw ()
{
DBusR *result = boost::shared_ptr<DBusR>::get();
// Our caller has not cleared its "msg" instance,
// which means that from now on it will be our
// responsibility to provide a response.
if (result && m_msg && *m_msg) {
result->transferOwnership();
}
}
void initDBusResult(ExtractArgs &context)
{
m_msg = context.m_msg;
boost::shared_ptr<DBusR>::reset(new DBusR(context.m_conn, context.m_msg ? *context.m_msg : NULL));
}
};
/**
* A parameter which points towards one of our Result* structures.
* All of the types contained in it count towards the Reply signature.
* The requested Result type itself is constructed here.
*
* @param R Result0, Result1<type>, ...
* @param DBusR the class implementing R
*/
template <class R, class DBusR> struct dbus_traits_result
{
static std::string getType() { return DBusR::getSignature(); }
static std::string getSignature() { return ""; }
static std::string getReply() { return getType(); }
typedef DBusResultGuard<DBusR> host_type;
typedef boost::shared_ptr<R> &arg_type;
static const bool asynchronous = true;
static void get(ExtractArgs &context,
GVariantIter &iter, host_type &value)
{
value.initDBusResult(context);
}
};
template <>
struct dbus_traits< boost::shared_ptr<Result0> > :
public dbus_traits_result<Result0, DBusResult0>
{};
template <class A1>
struct dbus_traits< boost::shared_ptr< Result1<A1> > >:
public dbus_traits_result< Result1<A1>, DBusResult1<A1> >
{};
template <class A1, class A2>
struct dbus_traits< boost::shared_ptr< Result2<A1, A2> > >:
public dbus_traits_result< Result2<A1, A2>, DBusResult2<A1, A2> >
{};
template <class A1, class A2, class A3>
struct dbus_traits< boost::shared_ptr< Result3<A1, A2, A3> > >:
public dbus_traits_result< Result3<A1, A2, A3>, DBusResult3<A1, A2, A3> >
{};
template <class A1, class A2, class A3, class A4>
struct dbus_traits< boost::shared_ptr< Result4<A1, A2, A3, A4> > >:
public dbus_traits_result< Result4<A1, A2, A3, A4>, DBusResult4<A1, A2, A3, A4> >
{};
template <class A1, class A2, class A3, class A4, class A5>
struct dbus_traits< boost::shared_ptr< Result5<A1, A2, A3, A4, A5> > >:
public dbus_traits_result< Result5<A1, A2, A3, A4, A5>, DBusResult5<A1, A2, A3, A4, A5> >
{};
template <class A1, class A2, class A3, class A4, class A5, class A6>
struct dbus_traits< boost::shared_ptr< Result6<A1, A2, A3, A4, A5, A6> > >:
public dbus_traits_result< Result6<A1, A2, A3, A4, A5, A6>, DBusResult6<A1, A2, A3, A4, A5, A6> >
{};
template <class A1, class A2, class A3, class A4, class A5, class A6, class A7>
struct dbus_traits< boost::shared_ptr< Result7<A1, A2, A3, A4, A5, A6, A7> > >:
public dbus_traits_result< Result7<A1, A2, A3, A4, A5, A6, A7>, DBusResult7<A1, A2, A3, A4, A5, A6, A7> >
{};
template <class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8>
struct dbus_traits< boost::shared_ptr< Result8<A1, A2, A3, A4, A5, A6, A7, A8> > >:
public dbus_traits_result< Result8<A1, A2, A3, A4, A5, A6, A7, A8>, DBusResult8<A1, A2, A3, A4, A5, A6, A7, A8> >
{};
template <class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8, class A9>
struct dbus_traits< boost::shared_ptr< Result9<A1, A2, A3, A4, A5, A6, A7, A8, A9> > >:
public dbus_traits_result< Result9<A1, A2, A3, A4, A5, A6, A7, A8, A9>, DBusResult9<A1, A2, A3, A4, A5, A6, A7, A8, A9> >
{};
template <class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8, class A9, class A10>
struct dbus_traits< boost::shared_ptr< Result10<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10> > >:
public dbus_traits_result< Result10<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10>, DBusResult10<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10> >
{};
/** ===> 10 parameters */
template <class A1, class A2, class A3, class A4, class A5,
class A6, class A7, class A8, class A9, class A10>
struct MakeMethodEntry< boost::function<void (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10)> >
{
typedef void (Mptr)(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10);
typedef boost::function<Mptr> M;
template <class I, class C> static M bind(Mptr C::*method, I instance) {
// this fails because bind() only supports up to 9 parameters, including
// the initial this pointer
return boost::bind(method, instance, _1, _2, _3, _4, _5, _6, _7, _8, _9 /* _10 */);
}
static const bool asynchronous = dbus_traits< DBusResult10<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10> >::asynchronous;
static GDBusMessage *methodFunction(GDBusConnection *conn,
GDBusMessage *msg, void *data)
{
try {
GDBusMessageUnique reply;
typename dbus_traits<A1>::host_type a1;
typename dbus_traits<A2>::host_type a2;
typename dbus_traits<A3>::host_type a3;
typename dbus_traits<A4>::host_type a4;
typename dbus_traits<A5>::host_type a5;
typename dbus_traits<A6>::host_type a6;
typename dbus_traits<A7>::host_type a7;
typename dbus_traits<A8>::host_type a8;
typename dbus_traits<A9>::host_type a9;
typename dbus_traits<A10>::host_type a10;
try {
ExtractArgs(conn, msg) >> Get<A1>(a1) >> Get<A2>(a2) >> Get<A3>(a3) >> Get<A4>(a4) >> Get<A5>(a5)
>> Get<A6>(a6) >> Get<A7>(a7) >> Get<A8>(a8) >> Get<A9>(a9) >> Get<A10>(a10);
(*static_cast<M *>(data))(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10);
if (asynchronous) {
return NULL;
}
reply.reset(g_dbus_message_new_method_reply(msg));
AppendArgs(reply) << Set<A1>(a1) << Set<A2>(a2) << Set<A3>(a3) << Set<A4>(a4) << Set<A5>(a5)
<< Set<A6>(a6) << Set<A7>(a7) << Set<A8>(a8) << Set<A9>(a9) << Set<A10>(a10);
} catch (...) {
return handleException(msg);
}
return reply.release();
} catch (...) {
return handleException(msg);
}
}
static GDBusMethodInfo *make(const char *name)
{
GDBusMethodInfo *entry = g_new0(GDBusMethodInfo, 1);
GPtrArray *inArgs = g_ptr_array_new();
appendNewArg<A1>(inArgs);
appendNewArg<A2>(inArgs);
appendNewArg<A3>(inArgs);
appendNewArg<A4>(inArgs);
appendNewArg<A5>(inArgs);
appendNewArg<A6>(inArgs);
appendNewArg<A7>(inArgs);
appendNewArg<A8>(inArgs);
appendNewArg<A9>(inArgs);
appendNewArg<A10>(inArgs);
g_ptr_array_add(inArgs, NULL);
GPtrArray *outArgs = g_ptr_array_new();
appendNewArgForReply<A1>(outArgs);
appendNewArgForReply<A2>(outArgs);
appendNewArgForReply<A3>(outArgs);
appendNewArgForReply<A4>(outArgs);
appendNewArgForReply<A5>(outArgs);
appendNewArgForReply<A6>(outArgs);
appendNewArgForReply<A7>(outArgs);
appendNewArgForReply<A8>(outArgs);
appendNewArgForReply<A9>(outArgs);
appendNewArgForReply<A10>(outArgs);
g_ptr_array_add(outArgs, NULL);
entry->name = g_strdup(name);
entry->in_args = (GDBusArgInfo **)g_ptr_array_free(inArgs, FALSE);
entry->out_args = (GDBusArgInfo **)g_ptr_array_free(outArgs, FALSE);
entry->ref_count = 1;
return entry;
}
};
/** 9 arguments, 1 return value */
template <class R,
class A1, class A2, class A3, class A4, class A5,
class A6, class A7, class A8, class A9>
struct MakeMethodEntry< boost::function<R (A1, A2, A3, A4, A5, A6, A7, A8, A9)> >
{
typedef R (Mptr)(A1, A2, A3, A4, A5, A6, A7, A8, A9);
typedef boost::function<Mptr> M;
template <class I, class C> static M boostptr(Mptr C::*method, I instance) {
// this fails because bind() only supports up to 9 parameters, including
// the initial this pointer
return boost::bind(method, instance, _1, _2, _3, _4, _5, _6, _7, _8, _9);
}
static const bool asynchronous = DBusResult9<A1, A2, A3, A4, A5, A6, A7, A8, A9>::asynchronous;
static GDBusMessage *methodFunction(GDBusConnection *conn,
GDBusMessage *msg, void *data)
{
try {
GDBusMessageUnique reply;
typename dbus_traits<R>::host_type r;
typename dbus_traits<A1>::host_type a1;
typename dbus_traits<A2>::host_type a2;
typename dbus_traits<A3>::host_type a3;
typename dbus_traits<A4>::host_type a4;
typename dbus_traits<A5>::host_type a5;
typename dbus_traits<A6>::host_type a6;
typename dbus_traits<A7>::host_type a7;
typename dbus_traits<A8>::host_type a8;
typename dbus_traits<A9>::host_type a9;
try {
ExtractArgs(conn, msg) >> Get<A1>(a1) >> Get<A2>(a2) >> Get<A3>(a3) >> Get<A4>(a4) >> Get<A5>(a5)
>> Get<A6>(a6) >> Get<A7>(a7) >> Get<A8>(a8) >> Get<A9>(a9);
r = (*static_cast<M *>(data))(a1, a2, a3, a4, a5, a6, a7, a8, a9);
if (asynchronous) {
return NULL;
}
reply.reset(g_dbus_message_new_method_reply(msg));
AppendArgs(reply) + r << Set<A1>(a1) << Set<A2>(a2) << Set<A3>(a3) << Set<A4>(a4) << Set<A5>(a5)
<< Set<A6>(a6) << Set<A7>(a7) << Set<A8>(a8) << Set<A9>(a9);
} catch (...) {
return handleException(msg);
}
return reply.release();
} catch (...) {
return handleException(msg);
}
}
static GDBusMethodInfo *make(const char *name)
{
GDBusMethodInfo *entry = g_new0(GDBusMethodInfo, 1);
GPtrArray *inArgs = g_ptr_array_new();
appendNewArg<A1>(inArgs);
appendNewArg<A2>(inArgs);
appendNewArg<A3>(inArgs);
appendNewArg<A4>(inArgs);
appendNewArg<A5>(inArgs);
appendNewArg<A6>(inArgs);
appendNewArg<A7>(inArgs);
appendNewArg<A8>(inArgs);
appendNewArg<A9>(inArgs);
g_ptr_array_add(inArgs, NULL);
GPtrArray *outArgs = g_ptr_array_new();
appendNewArgForReturn<R>(outArgs);
appendNewArgForReply<A1>(outArgs);
appendNewArgForReply<A2>(outArgs);
appendNewArgForReply<A3>(outArgs);
appendNewArgForReply<A4>(outArgs);
appendNewArgForReply<A5>(outArgs);
appendNewArgForReply<A6>(outArgs);
appendNewArgForReply<A7>(outArgs);
appendNewArgForReply<A8>(outArgs);
appendNewArgForReply<A9>(outArgs);
g_ptr_array_add(outArgs, NULL);
entry->name = g_strdup(name);
entry->in_args = (GDBusArgInfo **)g_ptr_array_free(inArgs, FALSE);
entry->out_args = (GDBusArgInfo **)g_ptr_array_free(outArgs, FALSE);
entry->ref_count = 1;
return entry;
}
};
/** ===> 9 parameters */
template <class A1, class A2, class A3, class A4, class A5,
class A6, class A7, class A8, class A9>
struct MakeMethodEntry< boost::function<void (A1, A2, A3, A4, A5, A6, A7, A8, A9)> >
{
typedef void (Mptr)(A1, A2, A3, A4, A5, A6, A7, A8, A9);
typedef boost::function<Mptr> M;
template <class I, class C> static M boostptr(Mptr C::*method, I instance) {
return boost::bind(method, instance, _1, _2, _3, _4, _5, _6, _7, _8, _9);
}
static const bool asynchronous = DBusResult9<A1, A2, A3, A4, A5, A6, A7, A8, A9>::asynchronous;
static GDBusMessage *methodFunction(GDBusConnection *conn,
GDBusMessage *msg, void *data)
{
try {
GDBusMessageUnique reply;
typename dbus_traits<A1>::host_type a1;
typename dbus_traits<A2>::host_type a2;
typename dbus_traits<A3>::host_type a3;
typename dbus_traits<A4>::host_type a4;
typename dbus_traits<A5>::host_type a5;
typename dbus_traits<A6>::host_type a6;
typename dbus_traits<A7>::host_type a7;
typename dbus_traits<A8>::host_type a8;
typename dbus_traits<A9>::host_type a9;
try {
ExtractArgs(conn, msg) >> Get<A1>(a1) >> Get<A2>(a2) >> Get<A3>(a3) >> Get<A4>(a4) >> Get<A5>(a5)
>> Get<A6>(a6) >> Get<A7>(a7) >> Get<A8>(a8) >> Get<A9>(a9);
(*static_cast<M *>(data))(a1, a2, a3, a4, a5, a6, a7, a8, a9);
if (asynchronous) {
return NULL;
}
reply.reset(g_dbus_message_new_method_reply(msg));
AppendArgs(reply) << Set<A1>(a1) << Set<A2>(a2) << Set<A3>(a3) << Set<A4>(a4) << Set<A5>(a5)
<< Set<A6>(a6) << Set<A7>(a7) << Set<A8>(a8) << Set<A9>(a9);
} catch (...) {
return handleException(msg);
}
return reply.release();
} catch (...) {
return handleException(msg);
}
}
static GDBusMethodInfo *make(const char *name)
{
GDBusMethodInfo *entry = g_new0(GDBusMethodInfo, 1);
GPtrArray *inArgs = g_ptr_array_new();
appendNewArg<A1>(inArgs);
appendNewArg<A2>(inArgs);
appendNewArg<A3>(inArgs);
appendNewArg<A4>(inArgs);
appendNewArg<A5>(inArgs);
appendNewArg<A6>(inArgs);
appendNewArg<A7>(inArgs);
appendNewArg<A8>(inArgs);
appendNewArg<A9>(inArgs);
g_ptr_array_add(inArgs, NULL);
GPtrArray *outArgs = g_ptr_array_new();
appendNewArgForReply<A1>(outArgs);
appendNewArgForReply<A2>(outArgs);
appendNewArgForReply<A3>(outArgs);
appendNewArgForReply<A4>(outArgs);
appendNewArgForReply<A5>(outArgs);
appendNewArgForReply<A6>(outArgs);
appendNewArgForReply<A7>(outArgs);
appendNewArgForReply<A8>(outArgs);
appendNewArgForReply<A9>(outArgs);
g_ptr_array_add(outArgs, NULL);
entry->name = g_strdup(name);
entry->in_args = (GDBusArgInfo **)g_ptr_array_free(inArgs, FALSE);
entry->out_args = (GDBusArgInfo **)g_ptr_array_free(outArgs, FALSE);
entry->ref_count = 1;
return entry;
}
};
/** 8 arguments, 1 return value */
template <class R,
class A1, class A2, class A3, class A4, class A5,
class A6, class A7, class A8>
struct MakeMethodEntry< boost::function<R (A1, A2, A3, A4, A5, A6, A7, A8)> >
{
typedef R (Mptr)(A1, A2, A3, A4, A5, A6, A7, A8);
typedef boost::function<Mptr> M;
template <class I, class C> static M boostptr(Mptr C::*method, I instance) {
return boost::bind(method, instance, _1, _2, _3, _4, _5, _6, _7, _8);
}
static const bool asynchronous = DBusResult8<A1, A2, A3, A4, A5, A6, A7, A8>::asynchronous;
static GDBusMessage *methodFunction(GDBusConnection *conn,
GDBusMessage *msg, void *data)
{
try {
GDBusMessageUnique reply;
typename dbus_traits<R>::host_type r;
typename dbus_traits<A1>::host_type a1;
typename dbus_traits<A2>::host_type a2;
typename dbus_traits<A3>::host_type a3;
typename dbus_traits<A4>::host_type a4;
typename dbus_traits<A5>::host_type a5;
typename dbus_traits<A6>::host_type a6;
typename dbus_traits<A7>::host_type a7;
typename dbus_traits<A8>::host_type a8;
try {
ExtractArgs(conn, msg) >> Get<A1>(a1) >> Get<A2>(a2) >> Get<A3>(a3) >> Get<A4>(a4) >>
Get<A5>(a5) >> Get<A6>(a6) >> Get<A7>(a7) >> Get<A8>(a8);
r = (*static_cast<M *>(data))(a1, a2, a3, a4, a5, a6, a7, a8);
if (asynchronous) {
return NULL;
}
reply.reset(g_dbus_message_new_method_reply(msg));
AppendArgs(reply) + r << Set<A1>(a1) << Set<A2>(a2) << Set<A3>(a3) << Set<A4>(a4)
<< Set<A5>(a5) << Set<A6>(a6) << Set<A7>(a7) << Set<A8>(a8);
} catch (...) {
return handleException(msg);
}
return reply.release();
} catch (...) {
return handleException(msg);
}
}
static GDBusMethodInfo *make(const char *name)
{
GDBusMethodInfo *entry = g_new0(GDBusMethodInfo, 1);
GPtrArray *inArgs = g_ptr_array_new();
appendNewArg<A1>(inArgs);
appendNewArg<A2>(inArgs);
appendNewArg<A3>(inArgs);
appendNewArg<A4>(inArgs);
appendNewArg<A5>(inArgs);
appendNewArg<A6>(inArgs);
appendNewArg<A7>(inArgs);
appendNewArg<A8>(inArgs);
g_ptr_array_add(inArgs, NULL);
GPtrArray *outArgs = g_ptr_array_new();
appendNewArgForReturn<R>(outArgs);
appendNewArgForReply<A1>(outArgs);
appendNewArgForReply<A2>(outArgs);
appendNewArgForReply<A3>(outArgs);
appendNewArgForReply<A4>(outArgs);
appendNewArgForReply<A5>(outArgs);
appendNewArgForReply<A6>(outArgs);
appendNewArgForReply<A7>(outArgs);
appendNewArgForReply<A8>(outArgs);
g_ptr_array_add(outArgs, NULL);
entry->name = g_strdup(name);
entry->in_args = (GDBusArgInfo **)g_ptr_array_free(inArgs, FALSE);
entry->out_args = (GDBusArgInfo **)g_ptr_array_free(outArgs, FALSE);
entry->ref_count = 1;
return entry;
}
};
/** ===> 8 parameters */
template <class A1, class A2, class A3, class A4, class A5,
class A6, class A7, class A8>
struct MakeMethodEntry< boost::function<void (A1, A2, A3, A4, A5, A6, A7, A8)> >
{
typedef void (Mptr)(A1, A2, A3, A4, A5, A6, A7, A8);
typedef boost::function<Mptr> M;
template <class I, class C> static M boostptr(Mptr C::*method, I instance) {
return boost::bind(method, instance, _1, _2, _3, _4, _5, _6, _7, _8);
}
static const bool asynchronous = DBusResult8<A1, A2, A3, A4, A5, A6, A7, A8>::asynchronous;
static GDBusMessage *methodFunction(GDBusConnection *conn,
GDBusMessage *msg, void *data)
{
try {
GDBusMessageUnique reply;
typename dbus_traits<A1>::host_type a1;
typename dbus_traits<A2>::host_type a2;
typename dbus_traits<A3>::host_type a3;
typename dbus_traits<A4>::host_type a4;
typename dbus_traits<A5>::host_type a5;
typename dbus_traits<A6>::host_type a6;
typename dbus_traits<A7>::host_type a7;
typename dbus_traits<A8>::host_type a8;
try {
ExtractArgs(conn, msg) >> Get<A1>(a1) >> Get<A2>(a2) >> Get<A3>(a3) >> Get<A4>(a4)
>> Get<A5>(a5) >> Get<A6>(a6) >> Get<A7>(a7) >> Get<A8>(a8);
(*static_cast<M *>(data))(a1, a2, a3, a4, a5, a6, a7, a8);
if (asynchronous) {
return NULL;
}
reply.reset(g_dbus_message_new_method_reply(msg));
AppendArgs(reply) << Set<A1>(a1) << Set<A2>(a2) << Set<A3>(a3) << Set<A4>(a4)
<< Set<A5>(a5) << Set<A6>(a6) << Set<A7>(a7) << Set<A8>(a8);
} catch (...) {
return handleException(msg);
}
return reply.release();
} catch (...) {
return handleException(msg);
}
}
static GDBusMethodInfo *make(const char *name)
{
GDBusMethodInfo *entry = g_new0(GDBusMethodInfo, 1);
GPtrArray *inArgs = g_ptr_array_new();
appendNewArg<A1>(inArgs);
appendNewArg<A2>(inArgs);
appendNewArg<A3>(inArgs);
appendNewArg<A4>(inArgs);
appendNewArg<A5>(inArgs);
appendNewArg<A6>(inArgs);
appendNewArg<A7>(inArgs);
appendNewArg<A8>(inArgs);
g_ptr_array_add(inArgs, NULL);
GPtrArray *outArgs = g_ptr_array_new();
appendNewArgForReply<A1>(outArgs);
appendNewArgForReply<A2>(outArgs);
appendNewArgForReply<A3>(outArgs);
appendNewArgForReply<A4>(outArgs);
appendNewArgForReply<A5>(outArgs);
appendNewArgForReply<A6>(outArgs);
appendNewArgForReply<A7>(outArgs);
appendNewArgForReply<A8>(outArgs);
g_ptr_array_add(outArgs, NULL);
entry->name = g_strdup(name);
entry->in_args = (GDBusArgInfo **)g_ptr_array_free(inArgs, FALSE);
entry->out_args = (GDBusArgInfo **)g_ptr_array_free(outArgs, FALSE);
entry->ref_count = 1;
return entry;
}
};
/** 7 arguments, 1 return value */
template <class R,
class A1, class A2, class A3, class A4, class A5,
class A6, class A7>
struct MakeMethodEntry< boost::function<R (A1, A2, A3, A4, A5, A6, A7)> >
{
typedef R (Mptr)(A1, A2, A3, A4, A5, A6, A7);
typedef boost::function<Mptr> M;
template <class I, class C> static M boostptr(Mptr C::*method, I instance) {
return boost::bind(method, instance, _1, _2, _3, _4, _5, _6, _7);
}
static const bool asynchronous = DBusResult7<A1, A2, A3, A4, A5, A6, A7>::asynchronous;
static GDBusMessage *methodFunction(GDBusConnection *conn,
GDBusMessage *msg, void *data)
{
try {
GDBusMessageUnique reply;
typename dbus_traits<R>::host_type r;
typename dbus_traits<A1>::host_type a1;
typename dbus_traits<A2>::host_type a2;
typename dbus_traits<A3>::host_type a3;
typename dbus_traits<A4>::host_type a4;
typename dbus_traits<A5>::host_type a5;
typename dbus_traits<A6>::host_type a6;
typename dbus_traits<A7>::host_type a7;
try {
ExtractArgs(conn, msg) >> Get<A1>(a1) >> Get<A2>(a2) >> Get<A3>(a3) >> Get<A4>(a4)
>> Get<A5>(a5) >> Get<A6>(a6) >> Get<A7>(a7);
r = (*static_cast<M *>(data))(a1, a2, a3, a4, a5, a6, a7);
if (asynchronous) {
return NULL;
}
reply.reset(g_dbus_message_new_method_reply(msg));
AppendArgs(reply) + r << Set<A1>(a1) << Set<A2>(a2) << Set<A3>(a3) << Set<A4>(a4)
<< Set<A5>(a5) << Set<A6>(a6) << Set<A7>(a7);
} catch (...) {
return handleException(msg);
}
return reply.release();
} catch (...) {
return handleException(msg);
}
}
static GDBusMethodInfo *make(const char *name)
{
GDBusMethodInfo *entry = g_new0(GDBusMethodInfo, 1);
GPtrArray *inArgs = g_ptr_array_new();
appendNewArg<A1>(inArgs);
appendNewArg<A2>(inArgs);
appendNewArg<A3>(inArgs);
appendNewArg<A4>(inArgs);
appendNewArg<A5>(inArgs);
appendNewArg<A6>(inArgs);
appendNewArg<A7>(inArgs);
g_ptr_array_add(inArgs, NULL);
GPtrArray *outArgs = g_ptr_array_new();
appendNewArgForReturn<R>(outArgs);
appendNewArgForReply<A1>(outArgs);
appendNewArgForReply<A2>(outArgs);
appendNewArgForReply<A3>(outArgs);
appendNewArgForReply<A4>(outArgs);
appendNewArgForReply<A5>(outArgs);
appendNewArgForReply<A6>(outArgs);
appendNewArgForReply<A7>(outArgs);
g_ptr_array_add(outArgs, NULL);
entry->name = g_strdup(name);
entry->in_args = (GDBusArgInfo **)g_ptr_array_free(inArgs, FALSE);
entry->out_args = (GDBusArgInfo **)g_ptr_array_free(outArgs, FALSE);
entry->ref_count = 1;
return entry;
}
};
/** ===> 7 parameters */
template <class A1, class A2, class A3, class A4, class A5,
class A6, class A7>
struct MakeMethodEntry< boost::function<void (A1, A2, A3, A4, A5, A6, A7)> >
{
typedef void (Mptr)(A1, A2, A3, A4, A5, A6, A7);
typedef boost::function<Mptr> M;
template <class I, class C> static M boostptr(Mptr C::*method, I instance) {
return boost::bind(method, instance, _1, _2, _3, _4, _5, _6, _7);
}
static const bool asynchronous = DBusResult7<A1, A2, A3, A4, A5, A6, A7>::asynchronous;
static GDBusMessage *methodFunction(GDBusConnection *conn,
GDBusMessage *msg, void *data)
{
try {
GDBusMessageUnique reply;
typename dbus_traits<A1>::host_type a1;
typename dbus_traits<A2>::host_type a2;
typename dbus_traits<A3>::host_type a3;
typename dbus_traits<A4>::host_type a4;
typename dbus_traits<A5>::host_type a5;
typename dbus_traits<A6>::host_type a6;
typename dbus_traits<A7>::host_type a7;
try {
ExtractArgs(conn, msg) >> Get<A1>(a1) >> Get<A2>(a2) >> Get<A3>(a3) >> Get<A4>(a4)
>> Get<A5>(a5) >> Get<A6>(a6) >> Get<A7>(a7);
(*static_cast<M *>(data))(a1, a2, a3, a4, a5, a6, a7);
if (asynchronous) {
return NULL;
}
reply.reset(g_dbus_message_new_method_reply(msg));
AppendArgs(reply) << Set<A1>(a1) << Set<A2>(a2) << Set<A3>(a3) << Set<A4>(a4)
<< Set<A5>(a5) << Set<A6>(a6) << Set<A7>(a7);
} catch (...) {
return handleException(msg);
}
return reply.release();
} catch (...) {
return handleException(msg);
}
}
static GDBusMethodInfo *make(const char *name)
{
GDBusMethodInfo *entry = g_new0(GDBusMethodInfo, 1);
GPtrArray *inArgs = g_ptr_array_new();
appendNewArg<A1>(inArgs);
appendNewArg<A2>(inArgs);
appendNewArg<A3>(inArgs);
appendNewArg<A4>(inArgs);
appendNewArg<A5>(inArgs);
appendNewArg<A6>(inArgs);
appendNewArg<A7>(inArgs);
g_ptr_array_add(inArgs, NULL);
GPtrArray *outArgs = g_ptr_array_new();
appendNewArgForReply<A1>(outArgs);
appendNewArgForReply<A2>(outArgs);
appendNewArgForReply<A3>(outArgs);
appendNewArgForReply<A4>(outArgs);
appendNewArgForReply<A5>(outArgs);
appendNewArgForReply<A6>(outArgs);
appendNewArgForReply<A7>(outArgs);
g_ptr_array_add(outArgs, NULL);
entry->name = g_strdup(name);
entry->in_args = (GDBusArgInfo **)g_ptr_array_free(inArgs, FALSE);
entry->out_args = (GDBusArgInfo **)g_ptr_array_free(outArgs, FALSE);
entry->ref_count = 1;
return entry;
}
};
/** 6 arguments, 1 return value */
template <class R,
class A1, class A2, class A3, class A4, class A5,
class A6>
struct MakeMethodEntry< boost::function<R (A1, A2, A3, A4, A5, A6)> >
{
typedef R (Mptr)(A1, A2, A3, A4, A5, A6);
typedef boost::function<Mptr> M;
template <class I, class C> static M boostptr(Mptr C::*method, I instance) {
return boost::bind(method, instance, _1, _2, _3, _4, _5, _6);
}
static const bool asynchronous = DBusResult6<A1, A2, A3, A4, A5, A6>::asynchronous;
static GDBusMessage *methodFunction(GDBusConnection *conn,
GDBusMessage *msg, void *data)
{
try {
GDBusMessageUnique reply;
typename dbus_traits<R>::host_type r;
typename dbus_traits<A1>::host_type a1;
typename dbus_traits<A2>::host_type a2;
typename dbus_traits<A3>::host_type a3;
typename dbus_traits<A4>::host_type a4;
typename dbus_traits<A5>::host_type a5;
typename dbus_traits<A6>::host_type a6;
try {
ExtractArgs(conn, msg) >> Get<A1>(a1) >> Get<A2>(a2) >> Get<A3>(a3)
>> Get<A4>(a4) >> Get<A5>(a5) >> Get<A6>(a6);
r = (*static_cast<M *>(data))(a1, a2, a3, a4, a5, a6);
if (asynchronous) {
return NULL;
}
reply.reset(g_dbus_message_new_method_reply(msg));
AppendArgs(reply) + r << Set<A1>(a1) << Set<A2>(a2) << Set<A3>(a3)
<< Set<A4>(a4) << Set<A5>(a5) << Set<A6>(a6);
} catch (...) {
return handleException(msg);
}
return reply.release();
} catch (...) {
return handleException(msg);
}
}
static GDBusMethodInfo *make(const char *name)
{
GDBusMethodInfo *entry = g_new0(GDBusMethodInfo, 1);
GPtrArray *inArgs = g_ptr_array_new();
appendNewArg<A1>(inArgs);
appendNewArg<A2>(inArgs);
appendNewArg<A3>(inArgs);
appendNewArg<A4>(inArgs);
appendNewArg<A5>(inArgs);
appendNewArg<A6>(inArgs);
g_ptr_array_add(inArgs, NULL);
GPtrArray *outArgs = g_ptr_array_new();
appendNewArgForReturn<R>(outArgs);
appendNewArgForReply<A1>(outArgs);
appendNewArgForReply<A2>(outArgs);
appendNewArgForReply<A3>(outArgs);
appendNewArgForReply<A4>(outArgs);
appendNewArgForReply<A5>(outArgs);
appendNewArgForReply<A6>(outArgs);
g_ptr_array_add(outArgs, NULL);
entry->name = g_strdup(name);
entry->in_args = (GDBusArgInfo **)g_ptr_array_free(inArgs, FALSE);
entry->out_args = (GDBusArgInfo **)g_ptr_array_free(outArgs, FALSE);
entry->ref_count = 1;
return entry;
}
};
/** ===> 6 parameters */
template <class A1, class A2, class A3, class A4, class A5,
class A6>
struct MakeMethodEntry< boost::function<void (A1, A2, A3, A4, A5, A6)> >
{
typedef void (Mptr)(A1, A2, A3, A4, A5, A6);
typedef boost::function<Mptr> M;
template <class I, class C> static M boostptr(Mptr C::*method, I instance) {
return boost::bind(method, instance, _1, _2, _3, _4, _5, _6);
}
static const bool asynchronous = DBusResult6<A1, A2, A3, A4, A5, A6>::asynchronous;
static GDBusMessage *methodFunction(GDBusConnection *conn,
GDBusMessage *msg, void *data)
{
try {
GDBusMessageUnique reply;
typename dbus_traits<A1>::host_type a1;
typename dbus_traits<A2>::host_type a2;
typename dbus_traits<A3>::host_type a3;
typename dbus_traits<A4>::host_type a4;
typename dbus_traits<A5>::host_type a5;
typename dbus_traits<A6>::host_type a6;
try {
ExtractArgs(conn, msg) >> Get<A1>(a1) >> Get<A2>(a2) >> Get<A3>(a3)
>> Get<A4>(a4) >> Get<A5>(a5) >> Get<A6>(a6);
(*static_cast<M *>(data))(a1, a2, a3, a4, a5, a6);
if (asynchronous) {
return NULL;
}
reply.reset(g_dbus_message_new_method_reply(msg));
AppendArgs(reply) << Set<A1>(a1) << Set<A2>(a2) << Set<A3>(a3)
<< Set<A4>(a4) << Set<A5>(a5) << Set<A6>(a6);
} catch (...) {
return handleException(msg);
}
return reply.release();
} catch (...) {
return handleException(msg);
}
}
static GDBusMethodInfo *make(const char *name)
{
GDBusMethodInfo *entry = g_new0(GDBusMethodInfo, 1);
GPtrArray *inArgs = g_ptr_array_new();
appendNewArg<A1>(inArgs);
appendNewArg<A2>(inArgs);
appendNewArg<A3>(inArgs);
appendNewArg<A4>(inArgs);
appendNewArg<A5>(inArgs);
appendNewArg<A6>(inArgs);
g_ptr_array_add(inArgs, NULL);
GPtrArray *outArgs = g_ptr_array_new();
appendNewArgForReply<A1>(outArgs);
appendNewArgForReply<A2>(outArgs);
appendNewArgForReply<A3>(outArgs);
appendNewArgForReply<A4>(outArgs);
appendNewArgForReply<A5>(outArgs);
appendNewArgForReply<A6>(outArgs);
g_ptr_array_add(outArgs, NULL);
entry->name = g_strdup(name);
entry->in_args = (GDBusArgInfo **)g_ptr_array_free(inArgs, FALSE);
entry->out_args = (GDBusArgInfo **)g_ptr_array_free(outArgs, FALSE);
entry->ref_count = 1;
return entry;
}
};
/** 5 arguments, 1 return value */
template <class R,
class A1, class A2, class A3, class A4, class A5>
struct MakeMethodEntry< boost::function<R (A1, A2, A3, A4, A5)> >
{
typedef R (Mptr)(A1, A2, A3, A4, A5);
typedef boost::function<Mptr> M;
template <class I, class C> static M boostptr(Mptr C::*method, I instance) {
return boost::bind(method, instance, _1, _2, _3, _4, _5);
}
static const bool asynchronous = DBusResult5<A1, A2, A3, A4, A5>::asynchronous;
static GDBusMessage *methodFunction(GDBusConnection *conn,
GDBusMessage *msg, void *data)
{
try {
GDBusMessageUnique reply;
typename dbus_traits<R>::host_type r;
typename dbus_traits<A1>::host_type a1;
typename dbus_traits<A2>::host_type a2;
typename dbus_traits<A3>::host_type a3;
typename dbus_traits<A4>::host_type a4;
typename dbus_traits<A5>::host_type a5;
try {
ExtractArgs(conn, msg) >> Get<A1>(a1) >> Get<A2>(a2) >> Get<A3>(a3)
>> Get<A4>(a4) >> Get<A5>(a5);
r = (*static_cast<M *>(data))(a1, a2, a3, a4, a5);
if (asynchronous) {
return NULL;
}
reply.reset(g_dbus_message_new_method_reply(msg));
AppendArgs(reply) + r << Set<A1>(a1) << Set<A2>(a2) << Set<A3>(a3)
<< Set<A4>(a4) << Set<A5>(a5);
} catch (...) {
return handleException(msg);
}
return reply.release();
} catch (...) {
return handleException(msg);
}
}
static GDBusMethodInfo *make(const char *name)
{
GDBusMethodInfo *entry = g_new0(GDBusMethodInfo, 1);
GPtrArray *inArgs = g_ptr_array_new();
appendNewArg<A1>(inArgs);
appendNewArg<A2>(inArgs);
appendNewArg<A3>(inArgs);
appendNewArg<A4>(inArgs);
appendNewArg<A5>(inArgs);
g_ptr_array_add(inArgs, NULL);
GPtrArray *outArgs = g_ptr_array_new();
appendNewArgForReturn<R>(outArgs);
appendNewArgForReply<A1>(outArgs);
appendNewArgForReply<A2>(outArgs);
appendNewArgForReply<A3>(outArgs);
appendNewArgForReply<A4>(outArgs);
appendNewArgForReply<A5>(outArgs);
g_ptr_array_add(outArgs, NULL);
entry->name = g_strdup(name);
entry->in_args = (GDBusArgInfo **)g_ptr_array_free(inArgs, FALSE);
entry->out_args = (GDBusArgInfo **)g_ptr_array_free(outArgs, FALSE);
entry->ref_count = 1;
return entry;
}
};
/** ===> 5 parameters */
template <class A1, class A2, class A3, class A4, class A5>
struct MakeMethodEntry< boost::function<void (A1, A2, A3, A4, A5)> >
{
typedef void (Mptr)(A1, A2, A3, A4, A5);
typedef boost::function<Mptr> M;
template <class I, class C> static M boostptr(Mptr C::*method, I instance) {
return boost::bind(method, instance, _1, _2, _3, _4, _5);
}
static const bool asynchronous = DBusResult5<A1, A2, A3, A4, A5>::asynchronous;
static GDBusMessage *methodFunction(GDBusConnection *conn,
GDBusMessage *msg, void *data)
{
try {
GDBusMessageUnique reply;
typename dbus_traits<A1>::host_type a1;
typename dbus_traits<A2>::host_type a2;
typename dbus_traits<A3>::host_type a3;
typename dbus_traits<A4>::host_type a4;
typename dbus_traits<A5>::host_type a5;
try {
ExtractArgs(conn, msg) >> Get<A1>(a1) >> Get<A2>(a2) >> Get<A3>(a3)
>> Get<A4>(a4) >> Get<A5>(a5);
(*static_cast<M *>(data))(a1, a2, a3, a4, a5);
if (asynchronous) {
return NULL;
}
reply.reset(g_dbus_message_new_method_reply(msg));
AppendArgs(reply) << Set<A1>(a1) << Set<A2>(a2) << Set<A3>(a3)
<< Set<A4>(a4) << Set<A5>(a5);
} catch (...) {
return handleException(msg);
}
return reply.release();
} catch (...) {
return handleException(msg);
}
}
static GDBusMethodInfo *make(const char *name)
{
GDBusMethodInfo *entry = g_new0(GDBusMethodInfo, 1);
GPtrArray *inArgs = g_ptr_array_new();
appendNewArg<A1>(inArgs);
appendNewArg<A2>(inArgs);
appendNewArg<A3>(inArgs);
appendNewArg<A4>(inArgs);
appendNewArg<A5>(inArgs);
g_ptr_array_add(inArgs, NULL);
GPtrArray *outArgs = g_ptr_array_new();
appendNewArgForReply<A1>(outArgs);
appendNewArgForReply<A2>(outArgs);
appendNewArgForReply<A3>(outArgs);
appendNewArgForReply<A4>(outArgs);
appendNewArgForReply<A5>(outArgs);
g_ptr_array_add(outArgs, NULL);
entry->name = g_strdup(name);
entry->in_args = (GDBusArgInfo **)g_ptr_array_free(inArgs, FALSE);
entry->out_args = (GDBusArgInfo **)g_ptr_array_free(outArgs, FALSE);
entry->ref_count = 1;
return entry;
}
};
/** 4 arguments, 1 return value */
template <class R,
class A1, class A2, class A3, class A4>
struct MakeMethodEntry< boost::function<R (A1, A2, A3, A4)> >
{
typedef R (Mptr)(A1, A2, A3, A4);
typedef boost::function<Mptr> M;
template <class I, class C> static M boostptr(Mptr C::*method, I instance) {
return boost::bind(method, instance, _1, _2, _3, _4);
}
static const bool asynchronous = DBusResult4<A1, A2, A3, A4>::asynchronous;
static GDBusMessage *methodFunction(GDBusConnection *conn,
GDBusMessage *msg, void *data)
{
try {
GDBusMessageUnique reply;
typename dbus_traits<R>::host_type r;
typename dbus_traits<A1>::host_type a1;
typename dbus_traits<A2>::host_type a2;
typename dbus_traits<A3>::host_type a3;
typename dbus_traits<A4>::host_type a4;
try {
ExtractArgs(conn, msg) >> Get<A1>(a1) >> Get<A2>(a2) >> Get<A3>(a3) >> Get<A4>(a4);
r = (*static_cast<M *>(data))(a1, a2, a3, a4);
if (asynchronous) {
return NULL;
}
reply.reset(g_dbus_message_new_method_reply(msg));
AppendArgs(reply) + r << Set<A1>(a1) << Set<A2>(a2) << Set<A3>(a3) << Set<A4>(a4);
} catch (...) {
return handleException(msg);
}
return reply.release();
} catch (...) {
return handleException(msg);
}
}
static GDBusMethodInfo *make(const char *name)
{
GDBusMethodInfo *entry = g_new0(GDBusMethodInfo, 1);
GPtrArray *inArgs = g_ptr_array_new();
appendNewArg<A1>(inArgs);
appendNewArg<A2>(inArgs);
appendNewArg<A3>(inArgs);
appendNewArg<A4>(inArgs);
g_ptr_array_add(inArgs, NULL);
GPtrArray *outArgs = g_ptr_array_new();
appendNewArgForReturn<R>(outArgs);
appendNewArgForReply<A1>(outArgs);
appendNewArgForReply<A2>(outArgs);
appendNewArgForReply<A3>(outArgs);
appendNewArgForReply<A4>(outArgs);
g_ptr_array_add(outArgs, NULL);
entry->name = g_strdup(name);
entry->in_args = (GDBusArgInfo **)g_ptr_array_free(inArgs, FALSE);
entry->out_args = (GDBusArgInfo **)g_ptr_array_free(outArgs, FALSE);
entry->ref_count = 1;
return entry;
}
};
/** ===> 4 parameters */
template <class A1, class A2, class A3, class A4>
struct MakeMethodEntry< boost::function<void (A1, A2, A3, A4)> >
{
typedef void (Mptr)(A1, A2, A3, A4);
typedef boost::function<Mptr> M;
template <class I, class C> static M boostptr(Mptr C::*method, I instance) {
return boost::bind(method, instance, _1, _2, _3, _4);
}
static const bool asynchronous = DBusResult4<A1, A2, A3, A4>::asynchronous;
static GDBusMessage *methodFunction(GDBusConnection *conn,
GDBusMessage *msg, void *data)
{
try {
GDBusMessageUnique reply;
typename dbus_traits<A1>::host_type a1;
typename dbus_traits<A2>::host_type a2;
typename dbus_traits<A3>::host_type a3;
typename dbus_traits<A4>::host_type a4;
try {
ExtractArgs(conn, msg) >> Get<A1>(a1) >> Get<A2>(a2) >> Get<A3>(a3) >> Get<A4>(a4);
(*static_cast<M *>(data))(a1, a2, a3, a4);
if (asynchronous) {
return NULL;
}
reply.reset(g_dbus_message_new_method_reply(msg));
AppendArgs(reply) << Set<A1>(a1) << Set<A2>(a2) << Set<A3>(a3) << Set<A4>(a4);
} catch (...) {
return handleException(msg);
}
return reply.release();
} catch (...) {
return handleException(msg);
}
}
static GDBusMethodInfo *make(const char *name)
{
GDBusMethodInfo *entry = g_new0(GDBusMethodInfo, 1);
GPtrArray *inArgs = g_ptr_array_new();
appendNewArg<A1>(inArgs);
appendNewArg<A2>(inArgs);
appendNewArg<A3>(inArgs);
appendNewArg<A4>(inArgs);
g_ptr_array_add(inArgs, NULL);
GPtrArray *outArgs = g_ptr_array_new();
appendNewArgForReply<A1>(outArgs);
appendNewArgForReply<A2>(outArgs);
appendNewArgForReply<A3>(outArgs);
appendNewArgForReply<A4>(outArgs);
g_ptr_array_add(outArgs, NULL);
entry->name = g_strdup(name);
entry->in_args = (GDBusArgInfo **)g_ptr_array_free(inArgs, FALSE);
entry->out_args = (GDBusArgInfo **)g_ptr_array_free(outArgs, FALSE);
entry->ref_count = 1;
return entry;
}
};
/** 3 arguments, 1 return value */
template <class R,
class A1, class A2, class A3>
struct MakeMethodEntry< boost::function<R (A1, A2, A3)> >
{
typedef R (Mptr)(A1, A2, A3);
typedef boost::function<Mptr> M;
template <class I, class C> static M boostptr(Mptr C::*method, I instance) {
return boost::bind(method, instance, _1, _2, _3);
}
static const bool asynchronous = DBusResult3<A1, A2, A3>::asynchronous;
static GDBusMessage *methodFunction(GDBusConnection *conn,
GDBusMessage *msg, void *data)
{
try {
GDBusMessageUnique reply;
typename dbus_traits<R>::host_type r;
typename dbus_traits<A1>::host_type a1;
typename dbus_traits<A2>::host_type a2;
typename dbus_traits<A3>::host_type a3;
try {
ExtractArgs(conn, msg) >> Get<A1>(a1) >> Get<A2>(a2) >> Get<A3>(a3);
r = (*static_cast<M *>(data))(a1, a2, a3);
if (asynchronous) {
return NULL;
}
reply.reset(g_dbus_message_new_method_reply(msg));
AppendArgs(reply) + r << Set<A1>(a1) << Set<A2>(a2) << Set<A3>(a3);
} catch (...) {
return handleException(msg);
}
return reply.release();
} catch (...) {
return handleException(msg);
}
}
static GDBusMethodInfo *make(const char *name)
{
GDBusMethodInfo *entry = g_new0(GDBusMethodInfo, 1);
GPtrArray *inArgs = g_ptr_array_new();
appendNewArg<A1>(inArgs);
appendNewArg<A2>(inArgs);
appendNewArg<A3>(inArgs);
g_ptr_array_add(inArgs, NULL);
GPtrArray *outArgs = g_ptr_array_new();
appendNewArgForReturn<R>(outArgs);
appendNewArgForReply<A1>(outArgs);
appendNewArgForReply<A2>(outArgs);
appendNewArgForReply<A3>(outArgs);
g_ptr_array_add(outArgs, NULL);
entry->name = g_strdup(name);
entry->in_args = (GDBusArgInfo **)g_ptr_array_free(inArgs, FALSE);
entry->out_args = (GDBusArgInfo **)g_ptr_array_free(outArgs, FALSE);
entry->ref_count = 1;
return entry;
}
};
/** ===> 3 parameters */
template <class A1, class A2, class A3>
struct MakeMethodEntry< boost::function<void (A1, A2, A3)> >
{
typedef void (Mptr)(A1, A2, A3);
typedef boost::function<Mptr> M;
template <class I, class C> static M boostptr(Mptr C::*method, I instance) {
return boost::bind(method, instance, _1, _2, _3);
}
static const bool asynchronous = DBusResult3<A1, A2, A3>::asynchronous;
static GDBusMessage *methodFunction(GDBusConnection *conn,
GDBusMessage *msg, void *data)
{
try {
GDBusMessageUnique reply;
typename dbus_traits<A1>::host_type a1;
typename dbus_traits<A2>::host_type a2;
typename dbus_traits<A3>::host_type a3;
try {
ExtractArgs(conn, msg) >> Get<A1>(a1) >> Get<A2>(a2) >> Get<A3>(a3);
(*static_cast<M *>(data))(a1, a2, a3);
if (asynchronous) {
return NULL;
}
reply.reset(g_dbus_message_new_method_reply(msg));
AppendArgs(reply) << Set<A1>(a1) << Set<A2>(a2) << Set<A3>(a3);
} catch (...) {
return handleException(msg);
}
return reply.release();
} catch (...) {
return handleException(msg);
}
}
static GDBusMethodInfo *make(const char *name)
{
GDBusMethodInfo *entry = g_new0(GDBusMethodInfo, 1);
GPtrArray *inArgs = g_ptr_array_new();
appendNewArg<A1>(inArgs);
appendNewArg<A2>(inArgs);
appendNewArg<A3>(inArgs);
g_ptr_array_add(inArgs, NULL);
GPtrArray *outArgs = g_ptr_array_new();
appendNewArgForReply<A1>(outArgs);
appendNewArgForReply<A2>(outArgs);
appendNewArgForReply<A3>(outArgs);
g_ptr_array_add(outArgs, NULL);
entry->name = g_strdup(name);
entry->in_args = (GDBusArgInfo **)g_ptr_array_free(inArgs, FALSE);
entry->out_args = (GDBusArgInfo **)g_ptr_array_free(outArgs, FALSE);
entry->ref_count = 1;
return entry;
}
};
/** 2 arguments, 1 return value */
template <class R,
class A1, class A2>
struct MakeMethodEntry< boost::function<R (A1, A2)> >
{
typedef R (Mptr)(A1, A2);
typedef boost::function<Mptr> M;
template <class I, class C> static M boostptr(Mptr C::*method, I instance) {
return boost::bind(method, instance, _1, _2);
}
static const bool asynchronous = DBusResult2<A1, A2>::asynchronous;
static GDBusMessage *methodFunction(GDBusConnection *conn,
GDBusMessage *msg, void *data)
{
try {
GDBusMessageUnique reply;
typename dbus_traits<R>::host_type r;
typename dbus_traits<A1>::host_type a1;
typename dbus_traits<A2>::host_type a2;
try {
ExtractArgs(conn, msg) >> Get<A1>(a1) >> Get<A2>(a2);
r = (*static_cast<M *>(data))(a1, a2);
if (asynchronous) {
return NULL;
}
reply.reset(g_dbus_message_new_method_reply(msg));
AppendArgs(reply) + r << Set<A1>(a1) << Set<A2>(a2);
} catch (...) {
return handleException(msg);
}
return reply.release();
} catch (...) {
return handleException(msg);
}
}
static GDBusMethodInfo *make(const char *name)
{
GDBusMethodInfo *entry = g_new0(GDBusMethodInfo, 1);
GPtrArray *inArgs = g_ptr_array_new();
appendNewArg<A1>(inArgs);
appendNewArg<A2>(inArgs);
g_ptr_array_add(inArgs, NULL);
GPtrArray *outArgs = g_ptr_array_new();
appendNewArgForReturn<R>(outArgs);
appendNewArgForReply<A1>(outArgs);
appendNewArgForReply<A2>(outArgs);
g_ptr_array_add(outArgs, NULL);
entry->name = g_strdup(name);
entry->in_args = (GDBusArgInfo **)g_ptr_array_free(inArgs, FALSE);
entry->out_args = (GDBusArgInfo **)g_ptr_array_free(outArgs, FALSE);
entry->ref_count = 1;
return entry;
}
};
/** ===> 2 parameters */
template <class A1, class A2>
struct MakeMethodEntry< boost::function<void (A1, A2)> >
{
typedef void (Mptr)(A1, A2);
typedef boost::function<Mptr> M;
template <class I, class C> static M boostptr(Mptr C::*method, I instance) {
return boost::bind(method, instance, _1, _2);
}
static const bool asynchronous = DBusResult2<A1, A2>::asynchronous;
static GDBusMessage *methodFunction(GDBusConnection *conn,
GDBusMessage *msg, void *data)
{
try {
GDBusMessageUnique reply;
typename dbus_traits<A1>::host_type a1;
typename dbus_traits<A2>::host_type a2;
try {
ExtractArgs(conn, msg) >> Get<A1>(a1) >> Get<A2>(a2);
(*static_cast<M *>(data))(a1, a2);
if (asynchronous) {
return NULL;
}
reply.reset(g_dbus_message_new_method_reply(msg));
AppendArgs(reply) << Set<A1>(a1) << Set<A2>(a2);
} catch (...) {
return handleException(msg);
}
return reply.release();
} catch (...) {
return handleException(msg);
}
}
static GDBusMethodInfo *make(const char *name)
{
GDBusMethodInfo *entry = g_new0(GDBusMethodInfo, 1);
GPtrArray *inArgs = g_ptr_array_new();
appendNewArg<A1>(inArgs);
appendNewArg<A2>(inArgs);
g_ptr_array_add(inArgs, NULL);
GPtrArray *outArgs = g_ptr_array_new();
appendNewArgForReply<A1>(outArgs);
appendNewArgForReply<A2>(outArgs);
g_ptr_array_add(outArgs, NULL);
entry->name = g_strdup(name);
entry->in_args = (GDBusArgInfo **)g_ptr_array_free(inArgs, FALSE);
entry->out_args = (GDBusArgInfo **)g_ptr_array_free(outArgs, FALSE);
entry->ref_count = 1;
return entry;
}
};
/** 1 argument, 1 return value */
template <class R,
class A1>
struct MakeMethodEntry< boost::function<R (A1)> >
{
typedef R (Mptr)(A1);
typedef boost::function<Mptr> M;
template <class I, class C> static M boostptr(Mptr C::*method, I instance) {
return boost::bind(method, instance, _1);
}
static const bool asynchronous = DBusResult1<A1>::asynchronous;
static GDBusMessage *methodFunction(GDBusConnection *conn,
GDBusMessage *msg, void *data)
{
try {
GDBusMessageUnique reply;
typename dbus_traits<R>::host_type r;
typename dbus_traits<A1>::host_type a1;
try {
ExtractArgs(conn, msg) >> Get<A1>(a1);
r = (*static_cast<M *>(data))(a1);
if (asynchronous) {
return NULL;
}
reply.reset(g_dbus_message_new_method_reply(msg));
AppendArgs(reply) + r << Set<A1>(a1);
} catch (...) {
return handleException(msg);
}
return reply.release();
} catch (...) {
return handleException(msg);
}
}
static GDBusMethodInfo *make(const char *name)
{
GDBusMethodInfo *entry = g_new0(GDBusMethodInfo, 1);
GPtrArray *inArgs = g_ptr_array_new();
appendNewArg<A1>(inArgs);
g_ptr_array_add(inArgs, NULL);
GPtrArray *outArgs = g_ptr_array_new();
appendNewArgForReturn<R>(outArgs);
appendNewArgForReply<A1>(outArgs);
g_ptr_array_add(outArgs, NULL);
entry->name = g_strdup(name);
entry->in_args = (GDBusArgInfo **)g_ptr_array_free(inArgs, FALSE);
entry->out_args = (GDBusArgInfo **)g_ptr_array_free(outArgs, FALSE);
entry->ref_count = 1;
return entry;
}
};
/** ===> 1 parameter */
template <class A1>
struct MakeMethodEntry< boost::function<void (A1)> >
{
typedef void (Mptr)(A1);
typedef boost::function<void (A1)> M;
template <class I, class C> static M boostptr(Mptr C::*method, I instance) {
return boost::bind(method, instance, _1);
}
static const bool asynchronous = DBusResult1<A1>::asynchronous;
static GDBusMessage *methodFunction(GDBusConnection *conn,
GDBusMessage *msg, void *data)
{
try {
GDBusMessageUnique reply;
typename dbus_traits<A1>::host_type a1;
try {
ExtractArgs(conn, msg) >> Get<A1>(a1);
(*static_cast<M *>(data))(a1);
if (asynchronous) {
return NULL;
}
reply.reset(g_dbus_message_new_method_reply(msg));
AppendArgs(reply) << Set<A1>(a1);
} catch (...) {
return handleException(msg);
}
return reply.release();
} catch (...) {
return handleException(msg);
}
}
static GDBusMethodInfo *make(const char *name)
{
GDBusMethodInfo *entry = g_new0(GDBusMethodInfo, 1);
GPtrArray *inArgs = g_ptr_array_new();
appendNewArg<A1>(inArgs);
g_ptr_array_add(inArgs, NULL);
GPtrArray *outArgs = g_ptr_array_new();
appendNewArgForReply<A1>(outArgs);
g_ptr_array_add(outArgs, NULL);
entry->name = g_strdup(name);
entry->in_args = (GDBusArgInfo **)g_ptr_array_free(inArgs, FALSE);
entry->out_args = (GDBusArgInfo **)g_ptr_array_free(outArgs, FALSE);
entry->ref_count = 1;
return entry;
}
};
/** 0 arguments, 1 return value */
template <class R>
struct MakeMethodEntry< boost::function<R ()> >
{
typedef R (Mptr)();
typedef boost::function<Mptr> M;
template <class I, class C> static M boostptr(Mptr C::*method, I instance) {
return boost::bind(method, instance);
}
static GDBusMessage *methodFunction(GDBusConnection *conn,
GDBusMessage *msg, void *data)
{
try {
GDBusMessageUnique reply;
typename dbus_traits<R>::host_type r;
try {
r = (*static_cast<M *>(data))();
reply.reset(g_dbus_message_new_method_reply(msg));
AppendArgs(reply) + r;
} catch (...) {
return handleException(msg);
}
return reply.release();
} catch (...) {
return handleException(msg);
}
}
static GDBusMethodInfo *make(const char *name)
{
GDBusMethodInfo *entry = g_new0(GDBusMethodInfo, 1);
GPtrArray *outArgs = g_ptr_array_new();
appendNewArgForReturn<R>(outArgs);
g_ptr_array_add(outArgs, NULL);
entry->name = g_strdup(name);
entry->in_args = NULL;
entry->out_args = (GDBusArgInfo **)g_ptr_array_free(outArgs, FALSE);
entry->ref_count = 1;
return entry;
}
};
/** ===> 0 parameter */
template <>
struct MakeMethodEntry< boost::function<void ()> >
{
typedef void (Mptr)();
typedef boost::function<Mptr> M;
template <class I, class C> static M boostptr(Mptr C::*method, I instance) {
return boost::bind(method, instance);
}
static GDBusMessage *methodFunction(GDBusConnection *conn,
GDBusMessage *msg, void *data)
{
try {
(*static_cast<M *>(data))();
GDBusMessage *reply = g_dbus_message_new_method_reply(msg);
return reply;
} catch (...) {
return handleException(msg);
}
}
static GDBusMethodInfo *make(const char *name)
{
GDBusMethodInfo *entry = g_new0(GDBusMethodInfo, 1);
entry->name = g_strdup(name);
entry->in_args = NULL;
entry->out_args = NULL;
entry->ref_count = 1;
return entry;
}
};
template <class Cb, class Ret>
struct TraitsBase
{
typedef Cb Callback_t;
typedef Ret Return_t;
struct CallbackData
{
//only keep connection, for DBusClientCall instance is absent when 'dbus client call' returns
//suppose connection is available in the callback handler
const DBusConnectionPtr m_conn;
Callback_t m_callback;
CallbackData(const DBusConnectionPtr &conn, const Callback_t &callback)
: m_conn(conn), m_callback(callback)
{}
};
};
struct VoidReturn {};
struct VoidTraits : public TraitsBase<boost::function<void (const std::string &)>, VoidReturn>
{
typedef TraitsBase<boost::function<void (const std::string &)>, VoidReturn> base;
typedef base::Callback_t Callback_t;
typedef base::Return_t Return_t;
static Return_t demarshal(DBusMessagePtr &/*reply*/, const DBusConnectionPtr &/*conn*/)
{
return Return_t();
}
static void handleMessage(DBusMessagePtr &reply, base::CallbackData *data, GError* error)
{
std::string error_msg;
//unmarshal the return results and call user callback
if (error != NULL || g_dbus_message_to_gerror(reply.get(), &error)) {
if (boost::starts_with(error->message, "GDBus.Error:")) {
error_msg = error->message + 12;
} else {
error_msg = error->message;
}
}
if (data->m_callback) {
data->m_callback(error_msg);
}
delete data;
if (error != NULL) {
g_error_free (error);
}
}
};
template <class R1>
struct Ret1Traits : public TraitsBase<boost::function<void (const R1 &, const std::string &)>, R1>
{
typedef TraitsBase<boost::function<void (const R1 &, const std::string &)>, R1> base;
typedef typename base::Callback_t Callback_t;
typedef typename base::Return_t Return_t;
static Return_t demarshal(DBusMessagePtr &reply, const DBusConnectionPtr &conn)
{
typename dbus_traits<R1>::host_type r;
ExtractResponse(conn.get(), reply.get()) >> Get<R1>(r);
return r;
}
static void handleMessage(DBusMessagePtr &reply, typename base::CallbackData *data, GError* error)
{
typename dbus_traits<R1>::host_type r;
std::string error_msg;
if (error == NULL && !g_dbus_message_to_gerror(reply.get(), &error)) {
ExtractResponse(data->m_conn.get(), reply.get()) >> Get<R1>(r);
} else if (boost::starts_with(error->message, "GDBus.Error:")) {
error_msg = error->message + 12;
} else {
error_msg = error->message;
}
//unmarshal the return results and call user callback
if (data->m_callback) {
data->m_callback(r, error_msg);
}
delete data;
// cppcheck-suppress nullPointer
// Looks invalid: cppcheck warning: nullPointer - Possible null pointer dereference: error - otherwise it is redundant to check it against null.
if (error != NULL) {
g_error_free (error);
}
}
};
template <class R1, class R2>
struct Ret2Traits : public TraitsBase<boost::function<void (const R1 &, const R2 &, const std::string &)>, std::pair<R1, R2> >
{
typedef TraitsBase<boost::function<void (const R1 &, const R2 &, const std::string &)>, std::pair<R1, R2> > base;
typedef typename base::Callback_t Callback_t;
typedef typename base::Return_t Return_t;
static Return_t demarshal(DBusMessagePtr &reply, const DBusConnectionPtr &conn)
{
Return_t r;
ExtractResponse(conn.get(), reply.get()) >> Get<R1>(r.first) >> Get<R2>(r.second);
return r;
}
static void handleMessage(DBusMessagePtr &reply, typename base::CallbackData *data, GError* error)
{
typename dbus_traits<R1>::host_type r1;
typename dbus_traits<R2>::host_type r2;
std::string error_msg;
if (error == NULL && !g_dbus_message_to_gerror(reply.get(), &error)) {
ExtractResponse(data->m_conn.get(), reply.get()) >> Get<R1>(r1) >> Get<R2>(r2);
} else if (boost::starts_with(error->message, "GDBus.Error:")) {
error_msg = error->message + 12;
} else {
error_msg = error->message;
}
//unmarshal the return results and call user callback
if (data->m_callback) {
data->m_callback(r1, r2, error_msg);
}
delete data;
// cppcheck-suppress nullPointer
// Looks invalid: cppcheck warning: nullPointer - Possible null pointer dereference: error - otherwise it is redundant to check it against null.
if (error != NULL) {
g_error_free (error);
}
}
};
template <class R1, class R2, class R3>
struct Ret3Traits : public TraitsBase<boost::function<void (const R1 &, const R2 &, const R3 &, const std::string &)>, boost::tuple<R1, R2, R3> >
{
typedef TraitsBase<boost::function<void (const R1 &, const R2 &, const R3 &, const std::string &)>, boost::tuple<R1, R2, R3> > base;
typedef typename base::Callback_t Callback_t;
typedef typename base::Return_t Return_t;
static Return_t demarshal(DBusMessagePtr &reply, const DBusConnectionPtr &conn)
{
Return_t r;
ExtractResponse(conn.get(), reply.get()) >> Get<R1>(boost::get<0>(r)) >> Get<R2>(boost::get<1>(r)) >> Get<R3>(boost::get<2>(r));
return r;
}
static void handleMessage(DBusMessagePtr &reply, typename base::CallbackData *data, GError* error)
{
typename dbus_traits<R1>::host_type r1;
typename dbus_traits<R2>::host_type r2;
typename dbus_traits<R3>::host_type r3;
std::string error_msg;
if (error == NULL && !g_dbus_message_to_gerror(reply.get(), &error)) {
ExtractResponse(data->m_conn.get(), reply.get()) >> Get<R1>(r1) >> Get<R2>(r2) >> Get<R3>(r3);
} else if (boost::starts_with(error->message, "GDBus.Error:")) {
error_msg = error->message + 12;
} else {
error_msg = error->message;
}
//unmarshal the return results and call user callback
if (data->m_callback) {
data->m_callback(r1, r2, r3, error_msg);
}
delete data;
// cppcheck-suppress nullPointer
// Looks invalid: cppcheck warning: nullPointer - Possible null pointer dereference: error - otherwise it is redundant to check it against null.
if (error != NULL) {
g_error_free (error);
}
}
};
template <class CallTraits>
class DBusClientCall
{
public:
typedef typename CallTraits::Callback_t Callback_t;
typedef typename CallTraits::Return_t Return_t;
typedef typename CallTraits::base::CallbackData CallbackData;
protected:
const std::string m_destination;
const std::string m_path;
const std::string m_interface;
const std::string m_method;
const DBusConnectionPtr m_conn;
static void dbusCallback (GObject *src_obj, GAsyncResult *res, void *user_data) throw ()
{
try {
CallbackData *data = static_cast<CallbackData *>(user_data);
GError *err = NULL;
DBusMessagePtr reply(g_dbus_connection_send_message_with_reply_finish(data->m_conn.get(), res, &err));
CallTraits::handleMessage(reply, data, err);
} catch (const std::exception &ex) {
g_error("unexpected exception caught in dbusCallback(): %s", ex.what());
} catch (...) {
g_error("unexpected exception caught in dbusCallback()");
}
}
void prepare(DBusMessagePtr &msg) const
{
// Constructor steals reference, reset() doesn't!
// Therefore use constructor+copy instead of reset().
msg = DBusMessagePtr(g_dbus_message_new_method_call(m_destination.c_str(),
m_path.c_str(),
m_interface.c_str(),
m_method.c_str()));
if (!msg) {
throw std::runtime_error("g_dbus_message_new_method_call() failed");
}
}
void send(DBusMessagePtr &msg, const Callback_t &callback) const
{
CallbackData *data = new CallbackData(m_conn, callback);
g_dbus_connection_send_message_with_reply(m_conn.get(), msg.get(), G_DBUS_SEND_MESSAGE_FLAGS_NONE,
G_MAXINT, // no timeout
NULL, NULL, dbusCallback, data);
}
Return_t sendAndReturn(DBusMessagePtr &msg) const
{
GError* error = NULL;
DBusMessagePtr reply(g_dbus_connection_send_message_with_reply_sync(m_conn.get(),
msg.get(),
G_DBUS_SEND_MESSAGE_FLAGS_NONE,
G_MAXINT, // no timeout
NULL,
NULL,
&error));
if (error || g_dbus_message_to_gerror(reply.get(), &error)) {
DBusErrorCXX(error).throwFailure(m_method);
}
return CallTraits::demarshal(reply, m_conn);
}
public:
DBusClientCall(const DBusRemoteObject &object, const std::string &method)
:m_destination (object.getDestination()),
m_path (object.getPath()),
m_interface (object.getInterface()),
m_method (method),
m_conn (object.getConnection())
{
}
GDBusConnection *getConnection() { return m_conn.get(); }
std::string getMethod() const { return m_method; }
Return_t operator () ()
{
DBusMessagePtr msg;
prepare(msg);
return sendAndReturn(msg);
}
void start(const Callback_t &callback) const
{
DBusMessagePtr msg;
prepare(msg);
send(msg, callback);
}
template <class A1>
Return_t operator () (const A1 &a1) const
{
DBusMessagePtr msg;
prepare(msg);
AppendRetvals(msg) << a1;
return sendAndReturn(msg);
}
template <class A1>
void start(const A1 &a1, const Callback_t &callback) const
{
DBusMessagePtr msg;
prepare(msg);
AppendRetvals(msg) << a1;
send(msg, callback);
}
template <class A1, class A2>
Return_t operator () (const A1 &a1, const A2 &a2) const
{
DBusMessagePtr msg;
prepare(msg);
AppendRetvals(msg) << a1 << a2;
return sendAndReturn(msg);
}
template <class A1, class A2>
void start(const A1 &a1, const A2 &a2, const Callback_t &callback) const
{
DBusMessagePtr msg;
prepare(msg);
AppendRetvals(msg) << a1 << a2;
send(msg, callback);
}
template <class A1, class A2, class A3>
void operator () (const A1 &a1, const A2 &a2, const A3 &a3) const
{
DBusMessagePtr msg;
prepare(msg);
AppendRetvals(msg) << a1 << a2 << a3;
sendAndReturn(msg);
}
template <class A1, class A2, class A3>
void start(const A1 &a1, const A2 &a2, const A3 &a3, const Callback_t &callback) const
{
DBusMessagePtr msg;
prepare(msg);
AppendRetvals(msg) << a1 << a2 << a3;
send(msg, callback);
}
template <class A1, class A2, class A3, class A4>
void operator () (const A1 &a1, const A2 &a2, const A3 &a3, const A4 &a4) const
{
DBusMessagePtr msg;
prepare(msg);
AppendRetvals(msg) << a1 << a2 << a3 << a4;
sendAndReturn(msg);
}
template <class A1, class A2, class A3, class A4>
void start(const A1 &a1, const A2 &a2, const A3 &a3, const A4 &a4, const Callback_t &callback) const
{
DBusMessagePtr msg;
prepare(msg);
AppendRetvals(msg) << a1 << a2 << a3 << a4;
send(msg, callback);
}
template <class A1, class A2, class A3, class A4, class A5>
void operator () (const A1 &a1, const A2 &a2, const A3 &a3, const A4 &a4, const A5 &a5) const
{
DBusMessagePtr msg;
prepare(msg);
AppendRetvals(msg) << a1 << a2 << a3 << a4 << a5;
sendAndReturn(msg);
}
template <class A1, class A2, class A3, class A4, class A5>
void start(const A1 &a1, const A2 &a2, const A3 &a3, const A4 &a4, const A5 &a5, const Callback_t &callback) const
{
DBusMessagePtr msg;
prepare(msg);
AppendRetvals(msg) << a1 << a2 << a3 << a4 << a5;
send(msg, callback);
}
template <class A1, class A2, class A3, class A4, class A5, class A6>
void operator () (const A1 &a1, const A2 &a2, const A3 &a3, const A4 &a4, const A5 &a5,
const A6 &a6) const
{
DBusMessagePtr msg;
prepare(msg);
AppendRetvals(msg) << a1 << a2 << a3 << a4 << a5 << a6;
sendAndReturn(msg);
}
template <class A1, class A2, class A3, class A4, class A5, class A6>
void start(const A1 &a1, const A2 &a2, const A3 &a3, const A4 &a4, const A5 &a5,
const A6 &a6,
const Callback_t &callback) const
{
DBusMessagePtr msg;
prepare(msg);
AppendRetvals(msg) << a1 << a2 << a3 << a4 << a5 << a6;
send(msg, callback);
}
template <class A1, class A2, class A3, class A4, class A5, class A6, class A7>
void operator () (const A1 &a1, const A2 &a2, const A3 &a3, const A4 &a4, const A5 &a5,
const A6 &a6, const A7 &a7) const
{
DBusMessagePtr msg;
prepare(msg);
AppendRetvals(msg) << a1 << a2 << a3 << a4 << a5 << a6 << a7;
sendAndReturn(msg);
}
template <class A1, class A2, class A3, class A4, class A5, class A6, class A7>
void start(const A1 &a1, const A2 &a2, const A3 &a3, const A4 &a4, const A5 &a5,
const A6 &a6, const A7 &a7,
const Callback_t &callback) const
{
DBusMessagePtr msg;
prepare(msg);
AppendRetvals(msg) << a1 << a2 << a3 << a4 << a5 << a6 << a7;
send(msg, callback);
}
template <class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8>
void operator () (const A1 &a1, const A2 &a2, const A3 &a3, const A4 &a4, const A5 &a5,
const A6 &a6, const A7 &a7, const A8 &a8) const
{
DBusMessagePtr msg;
prepare(msg);
AppendRetvals(msg) << a1 << a2 << a3 << a4 << a5 << a6 << a7 << a8;
sendAndReturn(msg);
}
template <class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8>
void start(const A1 &a1, const A2 &a2, const A3 &a3, const A4 &a4, const A5 &a5,
const A6 &a6, const A7 &a7, const A8 &a8,
const Callback_t &callback) const
{
DBusMessagePtr msg;
prepare(msg);
AppendRetvals(msg) << a1 << a2 << a3 << a4 << a5 << a6 << a7 << a8;
send(msg, callback);
}
template <class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8, class A9>
void operator () (const A1 &a1, const A2 &a2, const A3 &a3, const A4 &a4, const A5 &a5,
const A6 &a6, const A7 &a7, const A8 &a8, const A9 &a9) const
{
DBusMessagePtr msg;
prepare(msg);
AppendRetvals(msg) << a1 << a2 << a3 << a4 << a5 << a6 << a7 << a8 << a9;
sendAndReturn(msg);
}
template <class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8, class A9>
void start(const A1 &a1, const A2 &a2, const A3 &a3, const A4 &a4, const A5 &a5,
const A6 &a6, const A7 &a7, const A8 &a8, const A9 &a9,
const Callback_t &callback) const
{
DBusMessagePtr msg;
prepare(msg);
AppendRetvals(msg) << a1 << a2 << a3 << a4 << a5 << a6 << a7 << a8 << a9;
send(msg, callback);
}
template <class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8, class A9, class A10>
void operator () (const A1 &a1, const A2 &a2, const A3 &a3, const A4 &a4, const A5 &a5,
const A6 &a6, const A7 &a7, const A8 &a8, const A9 &a9, const A10 &a10) const
{
DBusMessagePtr msg;
prepare(msg);
AppendRetvals(msg) << a1 << a2 << a3 << a4 << a5 << a6 << a7 << a8 << a9 << a10;
sendAndReturn(msg);
}
template <class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8, class A9, class A10>
void start(const A1 &a1, const A2 &a2, const A3 &a3, const A4 &a4, const A5 &a5,
const A6 &a6, const A7 &a7, const A8 &a8, const A9 &a9, const A10 &a10,
const Callback_t &callback) const
{
DBusMessagePtr msg;
prepare(msg);
AppendRetvals(msg) << a1 << a2 << a3 << a4 << a5 << a6 << a7 << a8 << a9 << a10;
send(msg, callback);
}
};
/*
* A DBus Client Call object handling zero or more parameter and
* zero return value.
*/
class DBusClientCall0 : public DBusClientCall<VoidTraits>
{
public:
DBusClientCall0 (const DBusRemoteObject &object, const std::string &method)
: DBusClientCall<VoidTraits>(object, method)
{
}
};
/** 1 return value and 0 or more parameters */
template <class R1>
class DBusClientCall1 : public DBusClientCall<Ret1Traits<R1> >
{
public:
DBusClientCall1 (const DBusRemoteObject &object, const std::string &method)
: DBusClientCall<Ret1Traits<R1> >(object, method)
{
}
};
/** 2 return value and 0 or more parameters */
template <class R1, class R2>
class DBusClientCall2 : public DBusClientCall<Ret2Traits<R1, R2> >
{
public:
DBusClientCall2 (const DBusRemoteObject &object, const std::string &method)
: DBusClientCall<Ret2Traits<R1, R2> >(object, method)
{
}
};
/** 3 return value and 0 or more parameters */
template <class R1, class R2, class R3>
class DBusClientCall3 : public DBusClientCall<Ret3Traits<R1, R2, R3> >
{
public:
DBusClientCall3 (const DBusRemoteObject &object, const std::string &method)
: DBusClientCall<Ret3Traits<R1, R2, R3> >(object, method)
{
}
};
/**
* Describes which signals are meant to be received by the callback in
* a SignalWatch. Only available when using GDBus C++ for GIO (this
* code here). GDBus libdbus only supports passing a DBusRemoteObject
* to the SignalWatch constructors, which does a match based on object
* path, interface name, and signal name.
*
* Traditionally, all three strings had to be given. Now if any of
* them is empty, it is excluded from the filter entirely (any string
* matches).
*
* Using this class adds the possibility to do a path prefix match or,
* in the future, other kind of matches.
*
* TODO: add support for filtering by sender. Not doing so leads to
* a situation where a malicious local process can fake signals.
*
* Avoid situations where different SignalWatches use exactly the same
* filter. Creating both watches will work, but when one is destroyed
* it might happen that the process stops receiving signals from the
* D-Bus daemon because the watch for that signal filter was removed
* from the connection (neither D-Bus spec nor D-Bus GIO guarantee
* that the match is ref counted).
*/
class SignalFilter : public DBusRemoteObject
{
public:
enum Flags {
SIGNAL_FILTER_NONE,
/**
* Normally, a path must match completely. With this flag set,
* any signal which has the given path as prefix
* matches.
*
* The path filter must not end in a slash.
*
* Example: "/foo/bar/xyz" matches "/foo/bar" only if
* SIGNAL_FILTER_PATH_PREFIX is set. "/foo/barxyz" does not
* match it in any case.
*
*/
SIGNAL_FILTER_PATH_PREFIX = 1<<0
};
/**
* Match based on object path and interface as stored in object
* and based on signal name as passed separately. Does a full
* match of all unless a a string is empty, in which case
* that criteria is ignored.
*/
SignalFilter(const DBusRemoteObject &object,
const std::string &signal) :
DBusRemoteObject(object),
m_signal(signal),
m_flags(SIGNAL_FILTER_NONE)
{}
/**
* Full control over filtering.
*/
SignalFilter(const DBusConnectionPtr &conn,
const std::string &path,
const std::string &interface,
const std::string &signal,
Flags flags) :
DBusRemoteObject(conn, path, interface, ""),
m_signal(signal),
m_flags(flags)
{}
const char *getSignal() const { return m_signal.c_str(); }
Flags getFlags() const { return Flags(m_flags); }
/**
* Check that current signal matches the filter. Necessary
* because GIO D-Bus does not know about "path_namespace" and
* because G_DBUS_SIGNAL_FLAGS_NO_MATCH_RULE seems to disable all
* signal filtering by GIO.
*/
bool matches(const ExtractArgs &context) const
{
return
(m_interface.empty() || m_interface == context.m_interface) &&
(m_signal.empty() || m_signal == context.m_signal) &&
(m_path.empty() ||
((m_flags & SIGNAL_FILTER_PATH_PREFIX) ?
(strlen(context.m_path) > m_path.size() &&
!m_path.compare(0, m_path.size(),
context.m_path, m_path.size()) &&
context.m_path[m_path.size()] == '/') :
m_path == context.m_path));
}
private:
std::string m_signal;
Flags m_flags;
};
/**
* Helper class for builting a match rule.
*/
class Criteria : public std::list<std::string> {
public:
void add(const char *keyword, const char *value) {
if (value && value[0]) {
std::string buffer;
buffer.reserve(strlen(keyword) + strlen(value) + 3);
buffer += keyword;
buffer += '=';
buffer += '\'';
buffer += value;
buffer += '\'';
push_back(buffer);
}
}
std::string createMatchRule() const { return boost::join(*this, ","); }
};
/**
* Common functionality of all SignalWatch* classes.
* @param T boost::function with the right signature
*/
template <class T> class SignalWatch : public SignalFilter
{
public:
SignalWatch(const DBusRemoteObject &object,
const std::string &signal,
bool = true)
: SignalFilter(object, signal), m_tag(0), m_manualMatch(false)
{
}
SignalWatch(const SignalFilter &filter)
: SignalFilter(filter), m_tag(0), m_manualMatch(false)
{
}
~SignalWatch()
{
try {
if (m_tag) {
GDBusConnection *connection = getConnection();
if (connection) {
g_dbus_connection_signal_unsubscribe(connection, m_tag);
}
}
if (m_manualMatch) {
DBusClientCall0(GDBusCXX::DBusRemoteObject(getConnection(),
"/org/freedesktop/DBus",
"org.freedesktop.DBus",
"org.freedesktop.DBus"),
"RemoveMatch")(m_matchRule);
}
} catch (...) {
// TODO (?): log error
}
}
typedef T Callback_t;
const Callback_t &getCallback() const { return m_callback; }
protected:
guint m_tag;
T m_callback;
bool m_manualMatch;
std::string m_matchRule;
void activateInternal(const Callback_t &callback, GDBusSignalCallback cb)
{
m_callback = callback;
m_tag = g_dbus_connection_signal_subscribe(getConnection(),
NULL,
getInterface()[0] ? getInterface() : NULL,
getSignal()[0] ? getSignal() : NULL,
(!(getFlags() & SIGNAL_FILTER_PATH_PREFIX) && getPath()[0]) ? getPath() : NULL,
NULL,
(getFlags() & SIGNAL_FILTER_PATH_PREFIX) ?
G_DBUS_SIGNAL_FLAGS_NO_MATCH_RULE :
G_DBUS_SIGNAL_FLAGS_NONE,
cb,
this,
NULL);
if (!m_tag) {
throw std::runtime_error(std::string("activating signal failed: ") +
"path " + getPath() +
" interface " + getInterface() +
" member " + getSignal());
}
if (getFlags() & SignalFilter::SIGNAL_FILTER_PATH_PREFIX) {
// Need to set up match rules manually.
Criteria criteria;
criteria.push_back("type='signal'");
criteria.add("interface", getInterface());
criteria.add("member", getSignal());
criteria.add("path_namespace", getPath());
m_matchRule = criteria.createMatchRule();
DBusClientCall0(GDBusCXX::DBusRemoteObject(getConnection(),
"/org/freedesktop/DBus",
"org.freedesktop.DBus",
"org.freedesktop.DBus"),
"AddMatch")(m_matchRule);
m_manualMatch = true;
}
}
};
class SignalWatch0 : public SignalWatch< boost::function<void (void)> >
{
typedef boost::function<void (void)> Callback_t;
public:
SignalWatch0(const DBusRemoteObject &object,
const std::string &signal,
bool = true)
: SignalWatch<Callback_t>(object, signal)
{
}
SignalWatch0(const SignalFilter &filter)
: SignalWatch<Callback_t>(filter)
{}
static void internalCallback(GDBusConnection *conn,
const gchar *sender,
const gchar *path,
const gchar *interface,
const gchar *signal,
GVariant *params,
gpointer data) throw ()
{
try {
SignalWatch<Callback_t> *watch = static_cast< SignalWatch<Callback_t> *>(data);
ExtractArgs context(conn, sender, path, interface, signal);
if (!watch->matches(context)) {
return;
}
const Callback_t &cb = watch->getCallback();
cb();
} catch (const std::exception &ex) {
g_error("unexpected exception caught in internalCallback(): %s", ex.what());
} catch (...) {
g_error("unexpected exception caught in internalCallback()");
}
}
void activate(const Callback_t &callback)
{
SignalWatch< boost::function<void (void)> >::activateInternal(callback, internalCallback);
}
};
template <typename A1>
class SignalWatch1 : public SignalWatch< boost::function<void (const A1 &)> >
{
typedef boost::function<void (const A1 &)> Callback_t;
public:
SignalWatch1(const DBusRemoteObject &object,
const std::string &signal,
bool = true)
: SignalWatch<Callback_t>(object, signal)
{
}
SignalWatch1(const SignalFilter &filter)
: SignalWatch<Callback_t>(filter)
{}
static void internalCallback(GDBusConnection *conn,
const gchar *sender,
const gchar *path,
const gchar *interface,
const gchar *signal,
GVariant *params,
gpointer data) throw()
{
try {
SignalWatch<Callback_t> *watch = static_cast< SignalWatch<Callback_t> *>(data);
ExtractArgs context(conn, sender, path, interface, signal);
if (!watch->matches(context)) {
return;
}
typename dbus_traits<A1>::host_type a1;
GVariantIter iter;
g_variant_iter_init(&iter, params);
dbus_traits<A1>::get(context, iter, a1);
const Callback_t &cb = watch->getCallback();
cb(a1);
} catch (const std::exception &ex) {
g_error("unexpected exception caught in internalCallback(): %s", ex.what());
} catch (...) {
g_error("unexpected exception caught in internalCallback()");
}
}
void activate(const Callback_t &callback)
{
SignalWatch< boost::function<void (const A1 &)> >::activateInternal(callback, internalCallback);
}
};
template <typename A1, typename A2>
class SignalWatch2 : public SignalWatch< boost::function<void (const A1 &, const A2 &)> >
{
typedef boost::function<void (const A1 &, const A2 &)> Callback_t;
public:
SignalWatch2(const DBusRemoteObject &object,
const std::string &signal,
bool = true)
: SignalWatch<Callback_t>(object, signal)
{
}
SignalWatch2(const SignalFilter &filter)
: SignalWatch<Callback_t>(filter)
{}
static void internalCallback(GDBusConnection *conn,
const gchar *sender,
const gchar *path,
const gchar *interface,
const gchar *signal,
GVariant *params,
gpointer data) throw ()
{
try {
SignalWatch<Callback_t> *watch = static_cast< SignalWatch<Callback_t> *>(data);
ExtractArgs context(conn, sender, path, interface, signal);
if (!watch->matches(context)) {
return;
}
typename dbus_traits<A1>::host_type a1;
typename dbus_traits<A2>::host_type a2;
GVariantIter iter;
g_variant_iter_init(&iter, params);
dbus_traits<A1>::get(context, iter, a1);
dbus_traits<A2>::get(context, iter, a2);
const Callback_t &cb = watch->getCallback();
cb(a1, a2);
} catch (const std::exception &ex) {
g_error("unexpected exception caught in internalCallback(): %s", ex.what());
} catch (...) {
g_error("unexpected exception caught in internalCallback()");
}
}
void activate(const Callback_t &callback)
{
SignalWatch< boost::function<void (const A1 &, const A2 &)> >::activateInternal(callback,
internalCallback);
}
};
template <typename A1, typename A2, typename A3>
class SignalWatch3 : public SignalWatch< boost::function<void (const A1 &, const A2 &, const A3 &)> >
{
typedef boost::function<void (const A1 &, const A2 &, const A3 &)> Callback_t;
public:
SignalWatch3(const DBusRemoteObject &object,
const std::string &signal,
bool = true)
: SignalWatch<Callback_t>(object, signal)
{
}
SignalWatch3(const SignalFilter &filter)
: SignalWatch<Callback_t>(filter)
{}
static void internalCallback(GDBusConnection *conn,
const gchar *sender,
const gchar *path,
const gchar *interface,
const gchar *signal,
GVariant *params,
gpointer data) throw ()
{
try {
SignalWatch<Callback_t> *watch = static_cast< SignalWatch<Callback_t> *>(data);
ExtractArgs context(conn, sender, path, interface, signal);
if (!watch->matches(context)) {
return;
}
typename dbus_traits<A1>::host_type a1;
typename dbus_traits<A2>::host_type a2;
typename dbus_traits<A3>::host_type a3;
GVariantIter iter;
g_variant_iter_init(&iter, params);
dbus_traits<A1>::get(context, iter, a1);
dbus_traits<A2>::get(context, iter, a2);
dbus_traits<A3>::get(context, iter, a3);
const Callback_t &cb = watch->getCallback();
cb(a1, a2, a3);
} catch (const std::exception &ex) {
g_error("unexpected exception caught in internalCallback(): %s", ex.what());
} catch (...) {
g_error("unexpected exception caught in internalCallback()");
}
}
void activate(const Callback_t &callback)
{
SignalWatch< boost::function<void (const A1 &,
const A2 &,
const A3 &)> >::activateInternal(callback,
internalCallback);
}
};
template <typename A1, typename A2, typename A3, typename A4>
class SignalWatch4 : public SignalWatch< boost::function<void (const A1 &, const A2 &,
const A3 &, const A4 &)> >
{
typedef boost::function<void (const A1 &, const A2 &, const A3 &, const A4 &)> Callback_t;
public:
SignalWatch4(const DBusRemoteObject &object,
const std::string &signal,
bool = true)
: SignalWatch<Callback_t>(object, signal)
{
}
SignalWatch4(const SignalFilter &filter)
: SignalWatch<Callback_t>(filter)
{}
static void internalCallback(GDBusConnection *conn,
const gchar *sender,
const gchar *path,
const gchar *interface,
const gchar *signal,
GVariant *params,
gpointer data) throw ()
{
try {
SignalWatch<Callback_t> *watch = static_cast< SignalWatch<Callback_t> *>(data);
ExtractArgs context(conn, sender, path, interface, signal);
if (!watch->matches(context)) {
return;
}
typename dbus_traits<A1>::host_type a1;
typename dbus_traits<A2>::host_type a2;
typename dbus_traits<A3>::host_type a3;
typename dbus_traits<A4>::host_type a4;
GVariantIter iter;
g_variant_iter_init(&iter, params);
dbus_traits<A1>::get(context, iter, a1);
dbus_traits<A2>::get(context, iter, a2);
dbus_traits<A3>::get(context, iter, a3);
dbus_traits<A4>::get(context, iter, a4);
const Callback_t &cb = watch->getCallback();
cb(a1, a2, a3, a4);
} catch (const std::exception &ex) {
g_error("unexpected exception caught in internalCallback(): %s", ex.what());
} catch (...) {
g_error("unexpected exception caught in internalCallback()");
}
}
void activate(const Callback_t &callback)
{
SignalWatch< boost::function<void (const A1 &, const A2 &,
const A3 &, const A4 &)> >::activateInternal(callback,
internalCallback);
}
};
template <typename A1, typename A2, typename A3, typename A4, typename A5>
class SignalWatch5 : public SignalWatch< boost::function<void (const A1 &, const A2 &, const A3 &, const A4 &, const A5 &)> >
{
typedef boost::function<void (const A1 &, const A2 &, const A3 &, const A4 &, const A5 &)> Callback_t;
public:
SignalWatch5(const DBusRemoteObject &object,
const std::string &signal,
bool = true)
: SignalWatch<Callback_t>(object, signal)
{
}
SignalWatch5(const SignalFilter &filter)
: SignalWatch<Callback_t>(filter)
{}
static void internalCallback(GDBusConnection *conn,
const gchar *sender,
const gchar *path,
const gchar *interface,
const gchar *signal,
GVariant *params,
gpointer data)
{
try {
SignalWatch<Callback_t> *watch = static_cast< SignalWatch<Callback_t> *>(data);
ExtractArgs context(conn, sender, path, interface, signal);
if (!watch->matches(context)) {
return;
}
typename dbus_traits<A1>::host_type a1;
typename dbus_traits<A2>::host_type a2;
typename dbus_traits<A3>::host_type a3;
typename dbus_traits<A4>::host_type a4;
typename dbus_traits<A5>::host_type a5;
GVariantIter iter;
g_variant_iter_init(&iter, params);
dbus_traits<A1>::get(context, iter, a1);
dbus_traits<A2>::get(context, iter, a2);
dbus_traits<A3>::get(context, iter, a3);
dbus_traits<A4>::get(context, iter, a4);
dbus_traits<A5>::get(context, iter, a5);
const Callback_t &cb = watch->getCallback();
cb(a1, a2, a3, a4, a5);
} catch (const std::exception &ex) {
g_error("unexpected exception caught in internalCallback(): %s", ex.what());
} catch (...) {
g_error("unexpected exception caught in internalCallback()");
}
}
void activate(const Callback_t &callback)
{
SignalWatch< boost::function<void (const A1 &, const A2 &,
const A3 &, const A4 &,
const A5 &)> >::activateInternal(callback, internalCallback);
}
};
template <typename A1, typename A2, typename A3, typename A4, typename A5, typename A6>
class SignalWatch6 : public SignalWatch< boost::function<void (const A1 &, const A2 &, const A3 &,
const A4 &, const A5 &, const A6 &)> >
{
typedef boost::function<void (const A1 &, const A2 &, const A3 &,
const A4 &, const A5 &, const A6 &)> Callback_t;
public:
SignalWatch6(const DBusRemoteObject &object,
const std::string &signal,
bool = true)
: SignalWatch<Callback_t>(object, signal)
{
}
SignalWatch6(const SignalFilter &filter)
: SignalWatch<Callback_t>(filter)
{}
static void internalCallback(GDBusConnection *conn,
const gchar *sender,
const gchar *path,
const gchar *interface,
const gchar *signal,
GVariant *params,
gpointer data) throw ()
{
try {
SignalWatch<Callback_t> *watch = static_cast< SignalWatch<Callback_t> *>(data);
ExtractArgs context(conn, sender, path, interface, signal);
if (!watch->matches(context)) {
return;
}
typename dbus_traits<A1>::host_type a1;
typename dbus_traits<A2>::host_type a2;
typename dbus_traits<A3>::host_type a3;
typename dbus_traits<A4>::host_type a4;
typename dbus_traits<A5>::host_type a5;
typename dbus_traits<A6>::host_type a6;
GVariantIter iter;
g_variant_iter_init(&iter, params);
dbus_traits<A1>::get(context, iter, a1);
dbus_traits<A2>::get(context, iter, a2);
dbus_traits<A3>::get(context, iter, a3);
dbus_traits<A4>::get(context, iter, a4);
dbus_traits<A5>::get(context, iter, a5);
dbus_traits<A6>::get(context, iter, a6);
const Callback_t &cb = watch->getCallback();
cb(a1, a2, a3, a4, a5, a6);
} catch (const std::exception &ex) {
g_error("unexpected exception caught in internalCallback(): %s", ex.what());
} catch (...) {
g_error("unexpected exception caught in internalCallback()");
}
}
void activate(const Callback_t &callback)
{
SignalWatch< boost::function<void (const A1 &, const A2 &,
const A3 &, const A4 &,
const A5 &, const A6 &)> >::activateInternal(callback,
internalCallback);
}
};
} // namespace GDBusCXX
#endif // INCL_GDBUS_CXX_BRIDGE