5854 lines
201 KiB
C++
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
|