summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/corelib/kernel/qmetaobject.cpp23
-rw-r--r--src/dbus/qdbusabstractinterface.cpp252
-rw-r--r--src/dbus/qdbusabstractinterface.h18
-rw-r--r--src/dbus/qdbusabstractinterface_p.h8
-rw-r--r--src/dbus/qdbusargument_p.h3
-rw-r--r--src/dbus/qdbusconnection_p.h5
-rw-r--r--src/dbus/qdbuserror.cpp11
-rw-r--r--src/dbus/qdbuserror.h6
-rw-r--r--src/dbus/qdbusintegrator.cpp100
-rw-r--r--src/dbus/qdbusinterface.cpp146
-rw-r--r--src/dbus/qdbusinternalfilters.cpp167
-rw-r--r--src/dbus/qdbusmarshaller.cpp35
-rw-r--r--src/dbus/qdbusmessage.cpp78
-rw-r--r--src/dbus/qdbusmessage.h6
-rw-r--r--src/dbus/qdbusmessage_p.h11
-rw-r--r--src/dbus/qdbusmisc.cpp47
-rw-r--r--src/dbus/qdbuspendingcall.cpp36
-rw-r--r--src/dbus/qdbuspendingcall.h3
-rw-r--r--src/dbus/qdbuspendingcall_p.h3
-rw-r--r--src/dbus/qdbusutil_p.h68
-rw-r--r--src/dbus/qdbusxmlgenerator.cpp37
-rw-r--r--tests/auto/auto.pro1
-rw-r--r--tests/auto/qdbusabstractadaptor/tst_qdbusabstractadaptor.cpp21
-rw-r--r--tests/auto/qdbusabstractinterface/com.trolltech.QtDBus.Pinger.xml30
-rw-r--r--tests/auto/qdbusabstractinterface/interface.cpp48
-rw-r--r--tests/auto/qdbusabstractinterface/interface.h113
-rw-r--r--tests/auto/qdbusabstractinterface/pinger.cpp67
-rw-r--r--tests/auto/qdbusabstractinterface/pinger.h145
-rw-r--r--tests/auto/qdbusabstractinterface/qdbusabstractinterface.pro15
-rw-r--r--tests/auto/qdbusabstractinterface/tst_qdbusabstractinterface.cpp576
-rw-r--r--tests/auto/qdbusinterface/tst_qdbusinterface.cpp194
-rw-r--r--tests/auto/qdbusmarshall/tst_qdbusmarshall.cpp121
-rw-r--r--tools/qdbus/qdbusxml2cpp/qdbusxml2cpp.cpp11
33 files changed, 2074 insertions, 331 deletions
diff --git a/src/corelib/kernel/qmetaobject.cpp b/src/corelib/kernel/qmetaobject.cpp
index 215f6ae..3184244 100644
--- a/src/corelib/kernel/qmetaobject.cpp
+++ b/src/corelib/kernel/qmetaobject.cpp
@@ -2136,8 +2136,15 @@ QVariant QMetaProperty::read(const QObject *object) const
return QVariant();
}
}
+
+ // the status variable is changed by qt_metacall to indicate what it did
+ // this feature is currently only used by QtDBus and should not be depended
+ // upon. Don't change it without looking into QDBusAbstractInterface first
+ // -1 (unchanged): normal qt_metacall, result stored in argv[0]
+ // changed: result stored directly in value
+ int status = -1;
QVariant value;
- void *argv[2] = { 0, &value };
+ void *argv[] = { 0, &value, &status };
if (t == QVariant::LastType) {
argv[0] = &value;
} else {
@@ -2147,8 +2154,8 @@ QVariant QMetaProperty::read(const QObject *object) const
const_cast<QObject*>(object)->qt_metacall(QMetaObject::ReadProperty,
idx + mobj->propertyOffset(),
argv);
- if (argv[1] == 0)
- // "value" was changed
+
+ if (status != -1)
return value;
if (t != QVariant::LastType && argv[0] != value.data())
// pointer or reference
@@ -2206,13 +2213,19 @@ bool QMetaProperty::write(QObject *object, const QVariant &value) const
return false;
}
- void *argv[2] = { 0, &v };
+ // the status variable is changed by qt_metacall to indicate what it did
+ // this feature is currently only used by QtDBus and should not be depended
+ // upon. Don't change it without looking into QDBusAbstractInterface first
+ // -1 (unchanged): normal qt_metacall, result stored in argv[0]
+ // changed: result stored directly in value, return the value of status
+ int status = -1;
+ void *argv[] = { 0, &v, &status };
if (t == QVariant::LastType)
argv[0] = &v;
else
argv[0] = v.data();
object->qt_metacall(QMetaObject::WriteProperty, idx + mobj->propertyOffset(), argv);
- return true;
+ return status;
}
/*!
diff --git a/src/dbus/qdbusabstractinterface.cpp b/src/dbus/qdbusabstractinterface.cpp
index 85c3274..7c520df 100644
--- a/src/dbus/qdbusabstractinterface.cpp
+++ b/src/dbus/qdbusabstractinterface.cpp
@@ -44,6 +44,7 @@
#include "qdbusargument.h"
#include "qdbuspendingcall.h"
+#include "qdbusmessage_p.h"
#include "qdbusmetaobject_p.h"
#include "qdbusmetatype_p.h"
#include "qdbusutil_p.h"
@@ -52,99 +53,83 @@
QT_BEGIN_NAMESPACE
+static QDBusError checkIfValid(const QString &service, const QString &path,
+ const QString &interface, bool isDynamic)
+{
+ // We should be throwing exceptions here... oh well
+ QDBusError error;
+
+ // dynamic interfaces (QDBusInterface) can have empty interfaces, but not service and object paths
+ // non-dynamic is the opposite: service and object paths can be empty, but not the interface
+ if (!isDynamic) {
+ // use assertion here because this should never happen, at all
+ Q_ASSERT_X(!interface.isEmpty(), "QDBusAbstractInterface", "Interface name cannot be empty");
+ }
+ if (!QDBusUtil::checkBusName(service, isDynamic ? QDBusUtil::EmptyNotAllowed : QDBusUtil::EmptyAllowed, &error))
+ return error;
+ if (!QDBusUtil::checkObjectPath(path, isDynamic ? QDBusUtil::EmptyNotAllowed : QDBusUtil::EmptyAllowed, &error))
+ return error;
+ if (!QDBusUtil::checkInterfaceName(interface, QDBusUtil::EmptyAllowed, &error))
+ return error;
+
+ // no error
+ return QDBusError();
+}
+
QDBusAbstractInterfacePrivate::QDBusAbstractInterfacePrivate(const QString &serv,
const QString &p,
const QString &iface,
const QDBusConnection& con,
bool isDynamic)
- : connection(con), service(serv), path(p), interface(iface), isValid(true)
+ : connection(con), service(serv), path(p), interface(iface),
+ lastError(checkIfValid(serv, p, iface, isDynamic)),
+ isValid(!lastError.isValid())
{
- if (isDynamic) {
- // QDBusInterface: service and object path can't be empty, but interface can
-#if 0
- Q_ASSERT_X(QDBusUtil::isValidBusName(service),
- "QDBusInterface::QDBusInterface", "Invalid service name");
- Q_ASSERT_X(QDBusUtil::isValidObjectPath(path),
- "QDBusInterface::QDBusInterface", "Invalid object path given");
- Q_ASSERT_X(interface.isEmpty() || QDBusUtil::isValidInterfaceName(interface),
- "QDBusInterface::QDBusInterface", "Invalid interface name");
-#else
- if (!QDBusUtil::isValidBusName(service)) {
- lastError = QDBusError(QDBusError::Disconnected,
- QLatin1String("Invalid service name"));
- isValid = false;
- } else if (!QDBusUtil::isValidObjectPath(path)) {
- lastError = QDBusError(QDBusError::Disconnected,
- QLatin1String("Invalid object name given"));
- isValid = false;
- } else if (!interface.isEmpty() && !QDBusUtil::isValidInterfaceName(interface)) {
- lastError = QDBusError(QDBusError::Disconnected,
- QLatin1String("Invalid interface name"));
- isValid = false;
- }
-#endif
- } else {
- // all others: service and path can be empty here, but interface can't
-#if 0
- Q_ASSERT_X(service.isEmpty() || QDBusUtil::isValidBusName(service),
- "QDBusAbstractInterface::QDBusAbstractInterface", "Invalid service name");
- Q_ASSERT_X(path.isEmpty() || QDBusUtil::isValidObjectPath(path),
- "QDBusAbstractInterface::QDBusAbstractInterface", "Invalid object path given");
- Q_ASSERT_X(QDBusUtil::isValidInterfaceName(interface),
- "QDBusAbstractInterface::QDBusAbstractInterface", "Invalid interface class!");
-#else
- if (!service.isEmpty() && !QDBusUtil::isValidBusName(service)) {
- lastError = QDBusError(QDBusError::Disconnected,
- QLatin1String("Invalid service name"));
- isValid = false;
- } else if (!path.isEmpty() && !QDBusUtil::isValidObjectPath(path)) {
- lastError = QDBusError(QDBusError::Disconnected,
- QLatin1String("Invalid object path given"));
- isValid = false;
- } else if (!QDBusUtil::isValidInterfaceName(interface)) {
- lastError = QDBusError(QDBusError::Disconnected,
- QLatin1String("Invalid interface class"));
- isValid = false;
- }
-#endif
- }
-
if (!isValid)
return;
if (!connection.isConnected()) {
lastError = QDBusError(QDBusError::Disconnected,
QLatin1String("Not connected to D-Bus server"));
- isValid = false;
} else if (!service.isEmpty()) {
currentOwner = connectionPrivate()->getNameOwner(service); // verify the name owner
if (currentOwner.isEmpty()) {
- isValid = false;
lastError = connectionPrivate()->lastError;
}
}
}
-QVariant QDBusAbstractInterfacePrivate::property(const QMetaProperty &mp) const
+bool QDBusAbstractInterfacePrivate::canMakeCalls() const
{
- if (!connection.isConnected()) // not connected
- return QVariant();
+ // recheck only if we have a wildcard (i.e. empty) service or path
+ // if any are empty, set the error message according to QDBusUtil
+ if (service.isEmpty())
+ return QDBusUtil::checkBusName(service, QDBusUtil::EmptyNotAllowed, &lastError);
+ if (path.isEmpty())
+ return QDBusUtil::checkObjectPath(path, QDBusUtil::EmptyNotAllowed, &lastError);
+ return true;
+}
+
+void QDBusAbstractInterfacePrivate::property(const QMetaProperty &mp, QVariant &where) const
+{
+ if (!isValid || !canMakeCalls()) { // can't make calls
+ where.clear();
+ return;
+ }
// is this metatype registered?
- int mid;
- const char *expectedSignature;
- if (mp.type() == QVariant::LastType) {
- // We're asking to read a QVariant
- mid = qMetaTypeId<QDBusVariant>();
- expectedSignature = "v";
- } else {
- mid = QMetaType::type(mp.typeName());
- expectedSignature = QDBusMetaType::typeToSignature(mid);
+ const char *expectedSignature = "";
+ if (mp.type() != 0xff) {
+ expectedSignature = QDBusMetaType::typeToSignature(where.userType());
if (expectedSignature == 0) {
qWarning("QDBusAbstractInterface: type %s must be registered with QtDBus before it can be "
"used to read property %s.%s",
mp.typeName(), qPrintable(interface), mp.name());
- return QVariant();
+ lastError = QDBusError(QDBusError::Failed,
+ QString::fromLatin1("Unregistered type %1 cannot be handled")
+ .arg(QLatin1String(mp.typeName())));
+ where.clear();
+ return;
}
}
@@ -152,26 +137,33 @@ QVariant QDBusAbstractInterfacePrivate::property(const QMetaProperty &mp) const
QDBusMessage msg = QDBusMessage::createMethodCall(service, path,
QLatin1String(DBUS_INTERFACE_PROPERTIES),
QLatin1String("Get"));
+ QDBusMessagePrivate::setParametersValidated(msg, true);
msg << interface << QString::fromUtf8(mp.name());
QDBusMessage reply = connection.call(msg, QDBus::Block);
if (reply.type() != QDBusMessage::ReplyMessage) {
lastError = reply;
- return QVariant();
+ where.clear();
+ return;
}
if (reply.signature() != QLatin1String("v")) {
QString errmsg = QLatin1String("Invalid signature `%1' in return from call to "
DBUS_INTERFACE_PROPERTIES);
lastError = QDBusError(QDBusError::InvalidSignature, errmsg.arg(reply.signature()));
- return QVariant();
+ where.clear();
+ return;
}
QByteArray foundSignature;
const char *foundType = 0;
QVariant value = qvariant_cast<QDBusVariant>(reply.arguments().at(0)).variant();
- if (value.userType() == mid)
- return value; // simple match
+ if (value.userType() == where.userType() || mp.type() == 0xff
+ || (expectedSignature[0] == 'v' && expectedSignature[1] == '\0')) {
+ // simple match
+ where = value;
+ return;
+ }
if (value.userType() == qMetaTypeId<QDBusArgument>()) {
QDBusArgument arg = qvariant_cast<QDBusArgument>(value);
@@ -179,14 +171,9 @@ QVariant QDBusAbstractInterfacePrivate::property(const QMetaProperty &mp) const
foundType = "user type";
foundSignature = arg.currentSignature().toLatin1();
if (foundSignature == expectedSignature) {
- void *null = 0;
- QVariant result(mid, null);
- QDBusMetaType::demarshall(arg, mid, result.data());
-
- if (mp.type() == QVariant::LastType)
- // special case: QVariant
- return qvariant_cast<QDBusVariant>(result).variant();
- return result;
+ // signatures match, we can demarshall
+ QDBusMetaType::demarshall(arg, where.userType(), where.data());
+ return;
}
} else {
foundType = value.typeName();
@@ -203,23 +190,28 @@ QVariant QDBusAbstractInterfacePrivate::property(const QMetaProperty &mp) const
QString::fromUtf8(mp.name()),
QString::fromLatin1(mp.typeName()),
QString::fromLatin1(expectedSignature)));
- return QVariant();
+ where.clear();
+ return;
}
-void QDBusAbstractInterfacePrivate::setProperty(const QMetaProperty &mp, const QVariant &value)
+bool QDBusAbstractInterfacePrivate::setProperty(const QMetaProperty &mp, const QVariant &value)
{
- if (!connection.isConnected()) // not connected
- return;
+ if (!isValid || !canMakeCalls()) // can't make calls
+ return false;
// send the value
QDBusMessage msg = QDBusMessage::createMethodCall(service, path,
QLatin1String(DBUS_INTERFACE_PROPERTIES),
QLatin1String("Set"));
+ QDBusMessagePrivate::setParametersValidated(msg, true);
msg << interface << QString::fromUtf8(mp.name()) << qVariantFromValue(QDBusVariant(value));
QDBusMessage reply = connection.call(msg, QDBus::Block);
- if (reply.type() != QDBusMessage::ReplyMessage)
+ if (reply.type() != QDBusMessage::ReplyMessage) {
lastError = reply;
+ return false;
+ }
+ return true;
}
void QDBusAbstractInterfacePrivate::_q_serviceOwnerChanged(const QString &name,
@@ -230,10 +222,36 @@ void QDBusAbstractInterfacePrivate::_q_serviceOwnerChanged(const QString &name,
//qDebug() << "QDBusAbstractInterfacePrivate serviceOwnerChanged" << name << oldOwner << newOwner;
if (name == service) {
currentOwner = newOwner;
- isValid = !newOwner.isEmpty();
}
}
+QDBusAbstractInterfaceBase::QDBusAbstractInterfaceBase(QDBusAbstractInterfacePrivate &d, QObject *parent)
+ : QObject(d, parent)
+{
+}
+
+int QDBusAbstractInterfaceBase::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
+{
+ int saved_id = _id;
+ _id = QObject::qt_metacall(_c, _id, _a);
+ if (_id < 0)
+ return _id;
+
+ if (_c == QMetaObject::ReadProperty || _c == QMetaObject::WriteProperty) {
+ QMetaProperty mp = metaObject()->property(saved_id);
+ int &status = *reinterpret_cast<int *>(_a[2]);
+ QVariant &variant = *reinterpret_cast<QVariant *>(_a[1]);
+
+ if (_c == QMetaObject::WriteProperty) {
+ status = d_func()->setProperty(mp, variant) ? 1 : 0;
+ } else {
+ d_func()->property(mp, variant);
+ status = variant.isValid() ? 1 : 0;
+ }
+ _id = -1;
+ }
+ return _id;
+}
/*!
\class QDBusAbstractInterface
@@ -258,10 +276,10 @@ void QDBusAbstractInterfacePrivate::_q_serviceOwnerChanged(const QString &name,
This is the constructor called from QDBusInterface::QDBusInterface.
*/
QDBusAbstractInterface::QDBusAbstractInterface(QDBusAbstractInterfacePrivate &d, QObject *parent)
- : QObject(d, parent)
+ : QDBusAbstractInterfaceBase(d, parent)
{
// keep track of the service owner
- if (d_func()->isValid)
+ if (!d_func()->currentOwner.isEmpty())
QObject::connect(d_func()->connectionPrivate(), SIGNAL(serviceOwnerChanged(QString,QString,QString)),
this, SLOT(_q_serviceOwnerChanged(QString,QString,QString)));
}
@@ -274,7 +292,7 @@ QDBusAbstractInterface::QDBusAbstractInterface(QDBusAbstractInterfacePrivate &d,
QDBusAbstractInterface::QDBusAbstractInterface(const QString &service, const QString &path,
const char *interface, const QDBusConnection &con,
QObject *parent)
- : QObject(*new QDBusAbstractInterfacePrivate(service, path, QString::fromLatin1(interface),
+ : QDBusAbstractInterfaceBase(*new QDBusAbstractInterfacePrivate(service, path, QString::fromLatin1(interface),
con, false), parent)
{
// keep track of the service owner
@@ -300,7 +318,7 @@ QDBusAbstractInterface::~QDBusAbstractInterface()
*/
bool QDBusAbstractInterface::isValid() const
{
- return d_func()->isValid;
+ return !d_func()->currentOwner.isEmpty();
}
/*!
@@ -367,6 +385,9 @@ QDBusMessage QDBusAbstractInterface::callWithArgumentList(QDBus::CallMode mode,
{
Q_D(QDBusAbstractInterface);
+ if (!d->isValid || !d->canMakeCalls())
+ return QDBusMessage::createError(d->lastError);
+
QString m = method;
// split out the signature from the method
int pos = method.indexOf(QLatin1Char('.'));
@@ -397,6 +418,7 @@ QDBusMessage QDBusAbstractInterface::callWithArgumentList(QDBus::CallMode mode,
// qDebug() << "QDBusAbstractInterface" << "Service" << service() << "Path:" << path();
QDBusMessage msg = QDBusMessage::createMethodCall(service(), path(), interface(), m);
+ QDBusMessagePrivate::setParametersValidated(msg, true);
msg.setArguments(args);
QDBusMessage reply = d->connection.call(msg, mode);
@@ -425,7 +447,11 @@ QDBusPendingCall QDBusAbstractInterface::asyncCallWithArgumentList(const QString
{
Q_D(QDBusAbstractInterface);
+ if (!d->isValid || !d->canMakeCalls())
+ return QDBusPendingCall::fromError(d->lastError);
+
QDBusMessage msg = QDBusMessage::createMethodCall(service(), path(), interface(), method);
+ QDBusMessagePrivate::setParametersValidated(msg, true);
msg.setArguments(args);
return d->connection.asyncCall(msg);
}
@@ -440,7 +466,8 @@ QDBusPendingCall QDBusAbstractInterface::asyncCallWithArgumentList(const QString
This function returns true if the queueing succeeds. It does
not indicate that the executed call succeeded. If it fails,
- the \a errorMethod is called.
+ the \a errorMethod is called. If the queueing failed, this
+ function returns false and no slot will be called.
The \a returnMethod must have as its parameters the types returned
by the function call. Optionally, it may have a QDBusMessage
@@ -453,22 +480,26 @@ QDBusPendingCall QDBusAbstractInterface::asyncCallWithArgumentList(const QString
bool QDBusAbstractInterface::callWithCallback(const QString &method,
const QList<QVariant> &args,
QObject *receiver,
- const char *returnMethod,
+ const char *returnMethod,
const char *errorMethod)
{
Q_D(QDBusAbstractInterface);
+ if (!d->isValid || !d->canMakeCalls())
+ return false;
+
QDBusMessage msg = QDBusMessage::createMethodCall(service(),
- path(),
- interface(),
- method);
+ path(),
+ interface(),
+ method);
+ QDBusMessagePrivate::setParametersValidated(msg, true);
msg.setArguments(args);
d->lastError = 0;
return d->connection.callWithCallback(msg,
- receiver,
- returnMethod,
- errorMethod);
+ receiver,
+ returnMethod,
+ errorMethod);
}
/*!
@@ -492,7 +523,7 @@ bool QDBusAbstractInterface::callWithCallback(const QString &method,
bool QDBusAbstractInterface::callWithCallback(const QString &method,
const QList<QVariant> &args,
QObject *receiver,
- const char *slot)
+ const char *slot)
{
return callWithCallback(method, args, receiver, slot, 0);
}
@@ -503,13 +534,15 @@ bool QDBusAbstractInterface::callWithCallback(const QString &method,
*/
void QDBusAbstractInterface::connectNotify(const char *signal)
{
+ // someone connecting to one of our signals
+ Q_D(QDBusAbstractInterface);
+ if (!d->isValid)
+ return;
+
// we end up recursing here, so optimise away
if (qstrcmp(signal + 1, "destroyed(QObject*)") == 0)
return;
- // someone connecting to one of our signals
- Q_D(QDBusAbstractInterface);
-
QDBusConnectionPrivate *conn = d->connectionPrivate();
if (conn)
conn->connectRelay(d->service, d->currentOwner, d->path, d->interface,
@@ -524,6 +557,8 @@ void QDBusAbstractInterface::disconnectNotify(const char *signal)
{
// someone disconnecting from one of our signals
Q_D(QDBusAbstractInterface);
+ if (!d->isValid)
+ return;
QDBusConnectionPrivate *conn = d->connectionPrivate();
if (conn)
@@ -540,11 +575,7 @@ QVariant QDBusAbstractInterface::internalPropGet(const char *propname) const
// assume this property exists and is readable
// we're only called from generated code anyways
- int idx = metaObject()->indexOfProperty(propname);
- if (idx != -1)
- return d_func()->property(metaObject()->property(idx));
- qWarning("QDBusAbstractInterface::internalPropGet called with unknown property '%s'", propname);
- return QVariant(); // error
+ return property(propname);
}
/*!
@@ -553,16 +584,7 @@ QVariant QDBusAbstractInterface::internalPropGet(const char *propname) const
*/
void QDBusAbstractInterface::internalPropSet(const char *propname, const QVariant &value)
{
- Q_D(QDBusAbstractInterface);
-
- // assume this property exists and is writeable
- // we're only called from generated code anyways
-
- int idx = metaObject()->indexOfProperty(propname);
- if (idx != -1)
- d->setProperty(metaObject()->property(idx), value);
- else
- qWarning("QDBusAbstractInterface::internalPropGet called with unknown property '%s'", propname);
+ setProperty(propname, value);
}
/*!
diff --git a/src/dbus/qdbusabstractinterface.h b/src/dbus/qdbusabstractinterface.h
index 6400b26..e525f77 100644
--- a/src/dbus/qdbusabstractinterface.h
+++ b/src/dbus/qdbusabstractinterface.h
@@ -61,7 +61,23 @@ class QDBusError;
class QDBusPendingCall;
class QDBusAbstractInterfacePrivate;
-class QDBUS_EXPORT QDBusAbstractInterface: public QObject
+
+class QDBUS_EXPORT QDBusAbstractInterfaceBase: public QObject
+{
+public:
+ int qt_metacall(QMetaObject::Call, int, void**);
+protected:
+ QDBusAbstractInterfaceBase(QDBusAbstractInterfacePrivate &dd, QObject *parent);
+private:
+ Q_DECLARE_PRIVATE(QDBusAbstractInterface)
+};
+
+class QDBUS_EXPORT QDBusAbstractInterface:
+#ifdef Q_QDOC
+ public QObject
+#else
+ public QDBusAbstractInterfaceBase
+#endif
{
Q_OBJECT
diff --git a/src/dbus/qdbusabstractinterface_p.h b/src/dbus/qdbusabstractinterface_p.h
index e2ea058..65df902 100644
--- a/src/dbus/qdbusabstractinterface_p.h
+++ b/src/dbus/qdbusabstractinterface_p.h
@@ -75,15 +75,19 @@ public:
QString path;
QString interface;
mutable QDBusError lastError;
+
+ // this is set during creation and never changed
+ // it can't be const because QDBusInterfacePrivate has one more check
bool isValid;
QDBusAbstractInterfacePrivate(const QString &serv, const QString &p,
const QString &iface, const QDBusConnection& con, bool dynamic);
virtual ~QDBusAbstractInterfacePrivate() { }
+ bool canMakeCalls() const;
// these functions do not check if the property is valid
- QVariant property(const QMetaProperty &mp) const;
- void setProperty(const QMetaProperty &mp, const QVariant &value);
+ void property(const QMetaProperty &mp, QVariant &where) const;
+ bool setProperty(const QMetaProperty &mp, const QVariant &value);
// return conn's d pointer
inline QDBusConnectionPrivate *connectionPrivate() const
diff --git a/src/dbus/qdbusargument_p.h b/src/dbus/qdbusargument_p.h
index b49a517..78bc683 100644
--- a/src/dbus/qdbusargument_p.h
+++ b/src/dbus/qdbusargument_p.h
@@ -130,7 +130,7 @@ public:
QDBusMarshaller *endCommon();
void open(QDBusMarshaller &sub, int code, const char *signature);
void close();
- void error();
+ void error(const QString &message);
bool appendVariantInternal(const QVariant &arg);
bool appendRegisteredType(const QVariant &arg);
@@ -140,6 +140,7 @@ public:
DBusMessageIter iterator;
QDBusMarshaller *parent;
QByteArray *ba;
+ QString errorString;
char closeCode;
bool ok;
diff --git a/src/dbus/qdbusconnection_p.h b/src/dbus/qdbusconnection_p.h
index 5c37509..a156a71 100644
--- a/src/dbus/qdbusconnection_p.h
+++ b/src/dbus/qdbusconnection_p.h
@@ -300,6 +300,8 @@ public:
extern int qDBusParametersForMethod(const QMetaMethod &mm, QList<int>& metaTypes);
extern int qDBusNameToTypeId(const char *name);
extern bool qDBusCheckAsyncTag(const char *tag);
+extern bool qDBusInterfaceInObject(QObject *obj, const QString &interface_name);
+extern QString qDBusInterfaceFromMetaObject(const QMetaObject *mo);
// in qdbusinternalfilters.cpp
extern QString qDBusIntrospectObject(const QDBusConnectionPrivate::ObjectTreeNode &node);
@@ -310,9 +312,6 @@ extern QDBusMessage qDBusPropertySet(const QDBusConnectionPrivate::ObjectTreeNod
extern QDBusMessage qDBusPropertyGetAll(const QDBusConnectionPrivate::ObjectTreeNode &node,
const QDBusMessage &msg);
-// in qdbusxmlgenerator.cpp
-extern QString qDBusInterfaceFromMetaObject(const QMetaObject *mo);
-
QT_END_NAMESPACE
#endif
diff --git a/src/dbus/qdbuserror.cpp b/src/dbus/qdbuserror.cpp
index 4f50e4f..b2d21ec 100644
--- a/src/dbus/qdbuserror.cpp
+++ b/src/dbus/qdbuserror.cpp
@@ -91,6 +91,10 @@ org.freedesktop.DBus.Error.InvalidSignature
org.freedesktop.DBus.Error.UnknownInterface
com.trolltech.QtDBus.Error.InternalError
org.freedesktop.DBus.Error.UnknownObject
+com.trolltech.QtDBus.Error.InvalidService
+com.trolltech.QtDBus.Error.InvalidObjectPath
+com.trolltech.QtDBus.Error.InvalidInterface
+com.trolltech.QtDBus.Error.InvalidMember
*/
// in the same order as KnownErrors!
@@ -116,12 +120,17 @@ static const char errorMessages_string[] =
"org.freedesktop.DBus.Error.UnknownInterface\0"
"com.trolltech.QtDBus.Error.InternalError\0"
"org.freedesktop.DBus.Error.UnknownObject\0"
+ "com.trolltech.QtDBus.Error.InvalidService\0"
+ "com.trolltech.QtDBus.Error.InvalidObjectPath\0"
+ "com.trolltech.QtDBus.Error.InvalidInterface\0"
+ "com.trolltech.QtDBus.Error.InvalidMember\0"
"\0";
static const int errorMessages_indices[] = {
0, 6, 40, 76, 118, 153, 191, 231,
273, 313, 349, 384, 421, 461, 501, 540,
- 581, 617, 661, 705, 746, 0
+ 581, 617, 661, 705, 746, 787, 829, 874,
+ 918, 0
};
static const int errorMessages_count = sizeof errorMessages_indices /
diff --git a/src/dbus/qdbuserror.h b/src/dbus/qdbuserror.h
index 7b77fd5..4e348dd 100644
--- a/src/dbus/qdbuserror.h
+++ b/src/dbus/qdbuserror.h
@@ -81,10 +81,14 @@ public:
UnknownInterface,
InternalError,
UnknownObject,
+ InvalidService,
+ InvalidObjectPath,
+ InvalidInterface,
+ InvalidMember,
#ifndef Q_QDOC
// don't use this one!
- LastErrorType = UnknownObject
+ LastErrorType = InvalidMember
#endif
};
diff --git a/src/dbus/qdbusintegrator.cpp b/src/dbus/qdbusintegrator.cpp
index 97a4545..e6c69b6 100644
--- a/src/dbus/qdbusintegrator.cpp
+++ b/src/dbus/qdbusintegrator.cpp
@@ -1143,10 +1143,14 @@ void QDBusConnectionPrivate::relaySignal(QObject *obj, const QMetaObject *mo, in
QDBusReadLocker locker(RelaySignalAction, this);
QDBusMessage message = QDBusMessage::createSignal(QLatin1String("/"), interface,
QLatin1String(memberName));
+ QDBusMessagePrivate::setParametersValidated(message, true);
message.setArguments(args);
- DBusMessage *msg = QDBusMessagePrivate::toDBusMessage(message);
+ QDBusError error;
+ DBusMessage *msg = QDBusMessagePrivate::toDBusMessage(message, &error);
if (!msg) {
- qWarning("QDBusConnection: Could not emit signal %s.%s", qPrintable(interface), memberName.constData());
+ qWarning("QDBusConnection: Could not emit signal %s.%s: %s", qPrintable(interface), memberName.constData(),
+ qPrintable(error.message()));
+ lastError = error;
return;
}
@@ -1359,12 +1363,8 @@ void QDBusConnectionPrivate::activateObject(ObjectTreeNode &node, const QDBusMes
// try the object itself:
if (node.flags & (QDBusConnection::ExportScriptableSlots|QDBusConnection::ExportNonScriptableSlots)) {
bool interfaceFound = true;
- if (!msg.interface().isEmpty()) {
- // check if the interface name matches anything in the class hierarchy
- const QMetaObject *mo = node.obj->metaObject();
- for ( ; !interfaceFound && mo != &QObject::staticMetaObject; mo = mo->superClass())
- interfaceFound = msg.interface() == qDBusInterfaceFromMetaObject(mo);
- }
+ if (!msg.interface().isEmpty())
+ interfaceFound = qDBusInterfaceInObject(node.obj, msg.interface());
if (interfaceFound) {
if (!activateCall(node.obj, node.flags, msg))
@@ -1702,21 +1702,26 @@ int QDBusConnectionPrivate::send(const QDBusMessage& message)
return -1; // don't send; the reply will be retrieved by the caller
// through the d_ptr->localReply link
- DBusMessage *msg = QDBusMessagePrivate::toDBusMessage(message);
+ QDBusError error;
+ DBusMessage *msg = QDBusMessagePrivate::toDBusMessage(message, &error);
if (!msg) {
if (message.type() == QDBusMessage::MethodCallMessage)
- qWarning("QDBusConnection: error: could not send message to service \"%s\" path \"%s\" interface \"%s\" member \"%s\"",
+ qWarning("QDBusConnection: error: could not send message to service \"%s\" path \"%s\" interface \"%s\" member \"%s\": %s",
qPrintable(message.service()), qPrintable(message.path()),
- qPrintable(message.interface()), qPrintable(message.member()));
+ qPrintable(message.interface()), qPrintable(message.member()),
+ qPrintable(error.message()));
else if (message.type() == QDBusMessage::SignalMessage)
- qWarning("QDBusConnection: error: could not send signal path \"%s\" interface \"%s\" member \"%s\"",
+ qWarning("QDBusConnection: error: could not send signal path \"%s\" interface \"%s\" member \"%s\": %s",
qPrintable(message.path()), qPrintable(message.interface()),
- qPrintable(message.member()));
+ qPrintable(message.member()),
+ qPrintable(error.message()));
else
- qWarning("QDBusConnection: error: could not send %s message to service \"%s\"",
+ qWarning("QDBusConnection: error: could not send %s message to service \"%s\": %s",
message.type() == QDBusMessage::ReplyMessage ? "reply" :
message.type() == QDBusMessage::ErrorMessage ? "error" :
- "invalid", qPrintable(message.service()));
+ "invalid", qPrintable(message.service()),
+ qPrintable(error.message()));
+ lastError = error;
return 0;
}
@@ -1743,12 +1748,15 @@ QDBusMessage QDBusConnectionPrivate::sendWithReply(const QDBusMessage &message,
return sendWithReplyLocal(message);
if (!QCoreApplication::instance() || sendMode == QDBus::Block) {
- DBusMessage *msg = QDBusMessagePrivate::toDBusMessage(message);
+ QDBusError err;
+ DBusMessage *msg = QDBusMessagePrivate::toDBusMessage(message, &err);
if (!msg) {
- qWarning("QDBusConnection: error: could not send message to service \"%s\" path \"%s\" interface \"%s\" member \"%s\"",
+ qWarning("QDBusConnection: error: could not send message to service \"%s\" path \"%s\" interface \"%s\" member \"%s\": %s",
qPrintable(message.service()), qPrintable(message.path()),
- qPrintable(message.interface()), qPrintable(message.member()));
- return QDBusMessage();
+ qPrintable(message.interface()), qPrintable(message.member()),
+ qPrintable(err.message()));
+ lastError = err;
+ return QDBusMessage::createError(err);
}
qDBusDebug() << QThread::currentThread() << "sending message (blocking):" << message;
@@ -1758,9 +1766,8 @@ QDBusMessage QDBusConnectionPrivate::sendWithReply(const QDBusMessage &message,
q_dbus_message_unref(msg);
if (!!error) {
- QDBusError qe = error;
- lastError = qe;
- return QDBusMessage::createError(qe);
+ lastError = err = error;
+ return QDBusMessage::createError(err);
}
QDBusMessage amsg = QDBusMessagePrivate::fromDBusMessage(reply);
@@ -1770,16 +1777,17 @@ QDBusMessage QDBusConnectionPrivate::sendWithReply(const QDBusMessage &message,
return amsg;
} else { // use the event loop
QDBusPendingCallPrivate *pcall = sendWithReplyAsync(message, timeout);
- if (!pcall)
- return QDBusMessage();
+ Q_ASSERT(pcall);
- pcall->watcherHelper = new QDBusPendingCallWatcherHelper;
- QEventLoop loop;
- loop.connect(pcall->watcherHelper, SIGNAL(reply(QDBusMessage)), SLOT(quit()));
- loop.connect(pcall->watcherHelper, SIGNAL(error(QDBusError,QDBusMessage)), SLOT(quit()));
+ if (pcall->replyMessage.type() != QDBusMessage::InvalidMessage) {
+ pcall->watcherHelper = new QDBusPendingCallWatcherHelper;
+ QEventLoop loop;
+ loop.connect(pcall->watcherHelper, SIGNAL(reply(QDBusMessage)), SLOT(quit()));
+ loop.connect(pcall->watcherHelper, SIGNAL(error(QDBusError,QDBusMessage)), SLOT(quit()));
- // enter the event loop and wait for a reply
- loop.exec(QEventLoop::ExcludeUserInputEvents | QEventLoop::WaitForMoreEvents);
+ // enter the event loop and wait for a reply
+ loop.exec(QEventLoop::ExcludeUserInputEvents | QEventLoop::WaitForMoreEvents);
+ }
QDBusMessage reply = pcall->replyMessage;
lastError = reply; // set or clear error
@@ -1835,20 +1843,25 @@ QDBusPendingCallPrivate *QDBusConnectionPrivate::sendWithReplyAsync(const QDBusM
return pcall;
}
- DBusMessage *msg = QDBusMessagePrivate::toDBusMessage(message);
+ checkThread();
+ QDBusPendingCallPrivate *pcall = new QDBusPendingCallPrivate;
+ pcall->sentMessage = message;
+ pcall->ref = 0;
+
+ QDBusError error;
+ DBusMessage *msg = QDBusMessagePrivate::toDBusMessage(message, &error);
if (!msg) {
- qWarning("QDBusConnection: error: could not send message to service \"%s\" path \"%s\" interface \"%s\" member \"%s\"",
+ qWarning("QDBusConnection: error: could not send message to service \"%s\" path \"%s\" interface \"%s\" member \"%s\": %s",
qPrintable(message.service()), qPrintable(message.path()),
- qPrintable(message.interface()), qPrintable(message.member()));
- return 0;
+ qPrintable(message.interface()), qPrintable(message.member()),
+ qPrintable(error.message()));
+ pcall->replyMessage = QDBusMessage::createError(error);
+ lastError = error;
+ return pcall;
}
- checkThread();
qDBusDebug() << QThread::currentThread() << "sending message (async):" << message;
DBusPendingCall *pending = 0;
- QDBusPendingCallPrivate *pcall = new QDBusPendingCallPrivate;
- pcall->sentMessage = message;
- pcall->ref = 0;
QDBusDispatchLocker locker(SendWithReplyAsyncAction, this);
if (q_dbus_connection_send_with_reply(connection, msg, &pending, timeout)) {
@@ -1862,14 +1875,14 @@ QDBusPendingCallPrivate *QDBusConnectionPrivate::sendWithReplyAsync(const QDBusM
return pcall;
} else {
// we're probably disconnected at this point
- lastError = QDBusError(QDBusError::Disconnected, QLatin1String("Not connected to server"));
+ lastError = error = QDBusError(QDBusError::Disconnected, QLatin1String("Not connected to server"));
}
} else {
- lastError = QDBusError(QDBusError::NoMemory, QLatin1String("Out of memory"));
+ lastError = error = QDBusError(QDBusError::NoMemory, QLatin1String("Out of memory"));
}
q_dbus_message_unref(msg);
- pcall->replyMessage = QDBusMessage::createError(lastError);
+ pcall->replyMessage = QDBusMessage::createError(error);
return pcall;
}
@@ -1878,8 +1891,7 @@ int QDBusConnectionPrivate::sendWithReplyAsync(const QDBusMessage &message, QObj
int timeout)
{
QDBusPendingCallPrivate *pcall = sendWithReplyAsync(message, timeout);
- if (!pcall)
- return 0;
+ Q_ASSERT(pcall);
// has it already finished (dispatched locally)?
if (pcall->replyMessage.type() == QDBusMessage::ReplyMessage) {
@@ -2081,6 +2093,7 @@ QString QDBusConnectionPrivate::getNameOwner(const QString& serviceName)
QDBusMessage msg = QDBusMessage::createMethodCall(QLatin1String(DBUS_SERVICE_DBUS),
QLatin1String(DBUS_PATH_DBUS), QLatin1String(DBUS_INTERFACE_DBUS),
QLatin1String("GetNameOwner"));
+ QDBusMessagePrivate::setParametersValidated(msg, true);
msg << serviceName;
QDBusMessage reply = sendWithReply(msg, QDBus::Block);
if (reply.type() == QDBusMessage::ReplyMessage)
@@ -2104,6 +2117,7 @@ QDBusConnectionPrivate::findMetaObject(const QString &service, const QString &pa
QDBusMessage msg = QDBusMessage::createMethodCall(service, path,
QLatin1String(DBUS_INTERFACE_INTROSPECTABLE),
QLatin1String("Introspect"));
+ QDBusMessagePrivate::setParametersValidated(msg, true);
QDBusMessage reply = sendWithReply(msg, QDBus::Block);
diff --git a/src/dbus/qdbusinterface.cpp b/src/dbus/qdbusinterface.cpp
index 211b717..5f6df0a 100644
--- a/src/dbus/qdbusinterface.cpp
+++ b/src/dbus/qdbusinterface.cpp
@@ -51,6 +51,102 @@
QT_BEGIN_NAMESPACE
+static void copyArgument(void *to, int id, const QVariant &arg)
+{
+ if (id == arg.userType()) {
+ switch (id) {
+ case QVariant::Bool:
+ *reinterpret_cast<bool *>(to) = arg.toBool();
+ return;
+
+ case QMetaType::UChar:
+ *reinterpret_cast<uchar *>(to) = arg.value<uchar>();
+ return;
+
+ case QMetaType::Short:
+ *reinterpret_cast<short *>(to) = arg.value<short>();
+ return;
+
+ case QMetaType::UShort:
+ *reinterpret_cast<ushort *>(to) = arg.value<ushort>();
+ return;
+
+ case QVariant::Int:
+ *reinterpret_cast<int *>(to) = arg.toInt();
+ return;
+
+ case QVariant::UInt:
+ *reinterpret_cast<uint *>(to) = arg.toUInt();
+ return;
+
+ case QVariant::LongLong:
+ *reinterpret_cast<qlonglong *>(to) = arg.toLongLong();
+ return;
+
+ case QVariant::ULongLong:
+ *reinterpret_cast<qulonglong *>(to) = arg.toULongLong();
+ return;
+
+ case QVariant::Double:
+ *reinterpret_cast<double *>(to) = arg.toDouble();
+ return;
+
+ case QVariant::String:
+ *reinterpret_cast<QString *>(to) = arg.toString();
+ return;
+
+ case QVariant::ByteArray:
+ *reinterpret_cast<QByteArray *>(to) = arg.toByteArray();
+ return;
+
+ case QVariant::StringList:
+ *reinterpret_cast<QStringList *>(to) = arg.toStringList();
+ return;
+ }
+
+ if (id == QDBusMetaTypeId::variant) {
+ *reinterpret_cast<QDBusVariant *>(to) = arg.value<QDBusVariant>();
+ return;
+ } else if (id == QDBusMetaTypeId::objectpath) {
+ *reinterpret_cast<QDBusObjectPath *>(to) = arg.value<QDBusObjectPath>();
+ return;
+ } else if (id == QDBusMetaTypeId::signature) {
+ *reinterpret_cast<QDBusSignature *>(to) = arg.value<QDBusSignature>();
+ return;
+ }
+
+ // those above are the only types possible
+ // the demarshaller code doesn't demarshall anything else
+ qFatal("Found a decoded basic type in a D-Bus reply that shouldn't be there");
+ }
+
+ // if we got here, it's either an un-dermarshalled type or a mismatch
+ if (arg.userType() != QDBusMetaTypeId::argument) {
+ // it's a mismatch
+ //qWarning?
+ return;
+ }
+
+ // is this type registered?
+ const char *userSignature = QDBusMetaType::typeToSignature(id);
+ if (!userSignature || !*userSignature) {
+ // type not registered
+ //qWarning?
+ return;
+ }
+
+ // is it the same signature?
+ QDBusArgument dbarg = arg.value<QDBusArgument>();
+ if (dbarg.currentSignature() != QLatin1String(userSignature)) {
+ // not the same signature, another mismatch
+ //qWarning?
+ return;
+ }
+
+ // we can demarshall
+ QDBusMetaType::demarshall(dbarg, id, to);
+}
+
QDBusInterfacePrivate::QDBusInterfacePrivate(const QString &serv, const QString &p,
const QString &iface, const QDBusConnection &con)
: QDBusAbstractInterfacePrivate(serv, p, iface, con, true), metaObject(0)
@@ -186,45 +282,39 @@ int QDBusInterfacePrivate::metacall(QMetaObject::Call c, int id, void **argv)
// we will assume that the input arguments were passed correctly
QVariantList args;
- for (int i = 1; i <= inputTypesCount; ++i)
+ int i = 1;
+ for ( ; i <= inputTypesCount; ++i)
args << QVariant(inputTypes[i], argv[i]);
// make the call
- QPointer<QDBusInterface> qq = q;
QDBusMessage reply = q->callWithArgumentList(QDBus::Block, methodName, args);
- args.clear();
- // we ignore return values
+ if (reply.type() == QDBusMessage::ReplyMessage) {
+ // attempt to demarshall the return values
+ args = reply.arguments();
+ QVariantList::ConstIterator it = args.constBegin();
+ const int *outputTypes = metaObject->outputTypesForMethod(id);
+ int outputTypesCount = *outputTypes++;
+
+ if (*mm.typeName()) {
+ // this method has a return type
+ if (argv[0] && it != args.constEnd())
+ copyArgument(argv[0], *outputTypes++, *it);
- // access to "this" or to "q" below this point must check for "qq"
- // we may have been deleted!
+ // skip this argument even if we didn't copy it
+ --outputTypesCount;
+ ++it;
+ }
- if (!qq.isNull())
- lastError = reply;
+ for (int j = 0; j < outputTypesCount && it != args.constEnd(); ++i, ++j, ++it) {
+ copyArgument(argv[i], outputTypes[j], *it);
+ }
+ }
// done
+ lastError = reply;
return -1;
}
- } else if (c == QMetaObject::ReadProperty) {
- // Qt doesn't support non-readable properties
- // we have to re-check
- QMetaProperty mp = metaObject->property(id + metaObject->propertyOffset());
- if (!mp.isReadable())
- return -1; // don't read
-
- QVariant *value = reinterpret_cast<QVariant*>(argv[1]);
- argv[1] = 0;
- *value = property(mp);
-
- return -1; // handled, error or not
- } else if (c == QMetaObject::WriteProperty) {
- // QMetaProperty::write has already checked that we're writable
- // it has also checked that the type is right
- QVariant *value = reinterpret_cast<QVariant *>(argv[1]);
- QMetaProperty mp = metaObject->property(id + metaObject->propertyOffset());
-
- setProperty(mp, *value);
- return -1;
}
return id;
}
diff --git a/src/dbus/qdbusinternalfilters.cpp b/src/dbus/qdbusinternalfilters.cpp
index 416144d..45cbbb0 100644
--- a/src/dbus/qdbusinternalfilters.cpp
+++ b/src/dbus/qdbusinternalfilters.cpp
@@ -53,6 +53,7 @@
#include "qdbusextratypes.h"
#include "qdbusmessage.h"
#include "qdbusmetatype.h"
+#include "qdbusmetatype_p.h"
#include "qdbusmessage_p.h"
#include "qdbusutil_p.h"
@@ -177,14 +178,25 @@ QString qDBusIntrospectObject(const QDBusConnectionPrivate::ObjectTreeNode &node
// implement the D-Bus interface org.freedesktop.DBus.Properties
-static QDBusMessage qDBusPropertyError(const QDBusMessage &msg, const QString &interface_name)
+static inline QDBusMessage interfaceNotFoundError(const QDBusMessage &msg, const QString &interface_name)
{
- return msg.createErrorReply(QLatin1String(DBUS_ERROR_INVALID_ARGS),
+ return msg.createErrorReply(QDBusError::UnknownInterface,
QString::fromLatin1("Interface %1 was not found in object %2")
.arg(interface_name)
.arg(msg.path()));
}
+static inline QDBusMessage
+propertyNotFoundError(const QDBusMessage &msg, const QString &interface_name, const QByteArray &property_name)
+{
+ return msg.createErrorReply(QDBusError::InvalidArgs,
+ QString::fromLatin1("Property %1%2%3 was not found in object %4")
+ .arg(interface_name,
+ QString::fromLatin1(interface_name.isEmpty() ? "" : "."),
+ QString::fromLatin1(property_name),
+ msg.path()));
+}
+
QDBusMessage qDBusPropertyGet(const QDBusConnectionPrivate::ObjectTreeNode &node,
const QDBusMessage &msg)
{
@@ -198,6 +210,7 @@ QDBusMessage qDBusPropertyGet(const QDBusConnectionPrivate::ObjectTreeNode &node
QDBusAdaptorConnector *connector;
QVariant value;
+ bool interfaceFound = false;
if (node.flags & QDBusConnection::ExportAdaptors &&
(connector = qDBusFindAdaptorConnector(node.obj))) {
@@ -217,31 +230,122 @@ QDBusMessage qDBusPropertyGet(const QDBusConnectionPrivate::ObjectTreeNode &node
QDBusAdaptorConnector::AdaptorMap::ConstIterator it;
it = qLowerBound(connector->adaptors.constBegin(), connector->adaptors.constEnd(),
interface_name);
- if (it != connector->adaptors.constEnd() && interface_name == QLatin1String(it->interface))
+ if (it != connector->adaptors.constEnd() && interface_name == QLatin1String(it->interface)) {
+ interfaceFound = true;
value = it->adaptor->property(property_name);
+ }
}
}
- if (!value.isValid() && node.flags & (QDBusConnection::ExportAllProperties |
- QDBusConnection::ExportNonScriptableProperties)) {
+ if (!interfaceFound && !value.isValid()
+ && node.flags & (QDBusConnection::ExportAllProperties |
+ QDBusConnection::ExportNonScriptableProperties)) {
// try the object itself
- int pidx = node.obj->metaObject()->indexOfProperty(property_name);
- if (pidx != -1) {
- QMetaProperty mp = node.obj->metaObject()->property(pidx);
- if ((mp.isScriptable() && (node.flags & QDBusConnection::ExportScriptableProperties)) ||
- (!mp.isScriptable() && (node.flags & QDBusConnection::ExportNonScriptableProperties)))
- value = mp.read(node.obj);
+ if (!interface_name.isEmpty())
+ interfaceFound = qDBusInterfaceInObject(node.obj, interface_name);
+
+ if (interfaceFound) {
+ int pidx = node.obj->metaObject()->indexOfProperty(property_name);
+ if (pidx != -1) {
+ QMetaProperty mp = node.obj->metaObject()->property(pidx);
+ if ((mp.isScriptable() && (node.flags & QDBusConnection::ExportScriptableProperties)) ||
+ (!mp.isScriptable() && (node.flags & QDBusConnection::ExportNonScriptableProperties)))
+ value = mp.read(node.obj);
+ }
}
}
if (!value.isValid()) {
// the property was not found
- return qDBusPropertyError(msg, interface_name);
+ if (!interfaceFound)
+ return interfaceNotFoundError(msg, interface_name);
+ return propertyNotFoundError(msg, interface_name, property_name);
}
return msg.createReply(qVariantFromValue(QDBusVariant(value)));
}
+enum PropertyWriteResult {
+ PropertyWriteSuccess = 0,
+ PropertyNotFound,
+ PropertyTypeMismatch,
+ PropertyWriteFailed
+};
+
+static QDBusMessage propertyWriteReply(const QDBusMessage &msg, const QString &interface_name,
+ const QByteArray &property_name, int status)
+{
+ switch (status) {
+ case PropertyNotFound:
+ return propertyNotFoundError(msg, interface_name, property_name);
+ case PropertyTypeMismatch:
+ return msg.createErrorReply(QDBusError::InvalidArgs,
+ QString::fromLatin1("Invalid arguments for writing to property %1%2%3")
+ .arg(interface_name,
+ QString::fromLatin1(interface_name.isEmpty() ? "" : "."),
+ QString::fromLatin1(property_name)));
+ case PropertyWriteFailed:
+ return msg.createErrorReply(QDBusError::InternalError,
+ QString::fromLatin1("Internal error"));
+
+ case PropertyWriteSuccess:
+ return msg.createReply();
+ }
+ Q_ASSERT_X(false, "", "Should not be reached");
+ return QDBusMessage();
+}
+
+static int writeProperty(QObject *obj, const QByteArray &property_name, QVariant value,
+ int propFlags = QDBusConnection::ExportAllProperties)
+{
+ const QMetaObject *mo = obj->metaObject();
+ int pidx = mo->indexOfProperty(property_name);
+ if (pidx == -1) {
+ // this object has no property by that name
+ return PropertyNotFound;
+ }
+
+ QMetaProperty mp = mo->property(pidx);
+
+ // check if this property is exported
+ bool isScriptable = mp.isScriptable();
+ if (!(propFlags & QDBusConnection::ExportScriptableProperties) && isScriptable)
+ return PropertyNotFound;
+ if (!(propFlags & QDBusConnection::ExportNonScriptableProperties) && !isScriptable)
+ return PropertyNotFound;
+
+ // we found our property
+ // do we have the right type?
+ int id = mp.type();
+ if (id == QVariant::UserType) {
+ // dynamic type
+ id = qDBusNameToTypeId(mp.typeName());
+ if (id == -1) {
+ // type not registered?
+ qWarning("QDBusConnection: Unable to handle unregistered datatype '%s' for property '%s::%s'",
+ mp.typeName(), mo->className(), property_name.constData());
+ return PropertyWriteFailed;
+ }
+ }
+
+ if (id != 0xff && value.userType() == QDBusMetaTypeId::argument) {
+ // we have to demarshall before writing
+ void *null = 0;
+ QVariant other(id, null);
+ if (!QDBusMetaType::demarshall(qVariantValue<QDBusArgument>(value), id, other.data())) {
+ qWarning("QDBusConnection: type `%s' (%d) is not registered with QtDBus. "
+ "Use qDBusRegisterMetaType to register it",
+ mp.typeName(), id);
+ return PropertyWriteFailed;
+ }
+
+ value = other;
+ }
+
+ // the property type here should match
+ return mp.write(obj, value) ? PropertyWriteSuccess : PropertyWriteFailed;
+}
+
QDBusMessage qDBusPropertySet(const QDBusConnectionPrivate::ObjectTreeNode &node,
const QDBusMessage &msg)
{
@@ -263,38 +367,39 @@ QDBusMessage qDBusPropertySet(const QDBusConnectionPrivate::ObjectTreeNode &node
if (interface_name.isEmpty()) {
for (QDBusAdaptorConnector::AdaptorMap::ConstIterator it = connector->adaptors.constBegin(),
end = connector->adaptors.constEnd(); it != end; ++it) {
- const QMetaObject *mo = it->adaptor->metaObject();
- int pidx = mo->indexOfProperty(property_name);
- if (pidx != -1) {
- mo->property(pidx).write(it->adaptor, value);
- return msg.createReply();
- }
+ int status = writeProperty(it->adaptor, property_name, value);
+ if (status == PropertyNotFound)
+ continue;
+ return propertyWriteReply(msg, interface_name, property_name, status);
}
} else {
QDBusAdaptorConnector::AdaptorMap::ConstIterator it;
it = qLowerBound(connector->adaptors.constBegin(), connector->adaptors.constEnd(),
interface_name);
- if (it != connector->adaptors.end() && interface_name == QLatin1String(it->interface))
- if (it->adaptor->setProperty(property_name, value))
- return msg.createReply();
+ if (it != connector->adaptors.end() && interface_name == QLatin1String(it->interface)) {
+ return propertyWriteReply(msg, interface_name, property_name,
+ writeProperty(it->adaptor, property_name, value));
+ }
}
}
if (node.flags & (QDBusConnection::ExportScriptableProperties |
QDBusConnection::ExportNonScriptableProperties)) {
// try the object itself
- int pidx = node.obj->metaObject()->indexOfProperty(property_name);
- if (pidx != -1) {
- QMetaProperty mp = node.obj->metaObject()->property(pidx);
- if ((mp.isScriptable() && (node.flags & QDBusConnection::ExportScriptableProperties)) ||
- (!mp.isScriptable() && (node.flags & QDBusConnection::ExportNonScriptableProperties)))
- if (mp.write(node.obj, value))
- return msg.createReply();
+ bool interfaceFound = true;
+ if (!interface_name.isEmpty())
+ interfaceFound = qDBusInterfaceInObject(node.obj, interface_name);
+
+ if (interfaceFound) {
+ return propertyWriteReply(msg, interface_name, property_name,
+ writeProperty(node.obj, property_name, value, node.flags));
}
}
- // the property was not found or not written to
- return qDBusPropertyError(msg, interface_name);
+ // the property was not found
+ if (!interface_name.isEmpty())
+ return interfaceNotFoundError(msg, interface_name);
+ return propertyWriteReply(msg, interface_name, property_name, PropertyNotFound);
}
// unite two QVariantMaps, but don't generate duplicate keys
@@ -385,7 +490,7 @@ QDBusMessage qDBusPropertyGetAll(const QDBusConnectionPrivate::ObjectTreeNode &n
if (!interfaceFound && !interface_name.isEmpty()) {
// the interface was not found
- return qDBusPropertyError(msg, interface_name);
+ return interfaceNotFoundError(msg, interface_name);
}
return msg.createReply(qVariantFromValue(result));
diff --git a/src/dbus/qdbusmarshaller.cpp b/src/dbus/qdbusmarshaller.cpp
index 7ada1ed..bb7fa6b 100644
--- a/src/dbus/qdbusmarshaller.cpp
+++ b/src/dbus/qdbusmarshaller.cpp
@@ -121,7 +121,7 @@ inline void QDBusMarshaller::append(const QDBusObjectPath &arg)
{
QByteArray data = arg.path().toUtf8();
if (!ba && data.isEmpty())
- error();
+ error(QLatin1String("Invalid object path passed in arguments"));
const char *cdata = data.constData();
qIterAppend(&iterator, ba, DBUS_TYPE_OBJECT_PATH, &cdata);
}
@@ -130,7 +130,7 @@ inline void QDBusMarshaller::append(const QDBusSignature &arg)
{
QByteArray data = arg.signature().toUtf8();
if (!ba && data.isEmpty())
- error();
+ error(QLatin1String("Invalid signature passed in arguments"));
const char *cdata = data.constData();
qIterAppend(&iterator, ba, DBUS_TYPE_SIGNATURE, &cdata);
}
@@ -161,7 +161,7 @@ inline bool QDBusMarshaller::append(const QDBusVariant &arg)
QVariant::Type id = QVariant::Type(value.userType());
if (id == QVariant::Invalid) {
qWarning("QDBusMarshaller: cannot add a null QDBusVariant");
- error();
+ error(QLatin1String("Variant containing QVariant::Invalid passed in arguments"));
return false;
}
@@ -180,7 +180,8 @@ inline bool QDBusMarshaller::append(const QDBusVariant &arg)
qWarning("QDBusMarshaller: type `%s' (%d) is not registered with D-BUS. "
"Use qDBusRegisterMetaType to register it",
QVariant::typeToName( id ), id);
- error();
+ error(QString::fromLatin1("Unregistered type %1 passed in arguments")
+ .arg(QLatin1String(QVariant::typeToName(id))));
return false;
}
@@ -220,7 +221,8 @@ inline QDBusMarshaller *QDBusMarshaller::beginArray(int id)
qWarning("QDBusMarshaller: type `%s' (%d) is not registered with D-BUS. "
"Use qDBusRegisterMetaType to register it",
QVariant::typeToName( QVariant::Type(id) ), id);
- error();
+ error(QString::fromLatin1("Unregistered type %1 passed in arguments")
+ .arg(QLatin1String(QVariant::typeToName(QVariant::Type(id)))));
return this;
}
@@ -234,22 +236,26 @@ inline QDBusMarshaller *QDBusMarshaller::beginMap(int kid, int vid)
qWarning("QDBusMarshaller: type `%s' (%d) is not registered with D-BUS. "
"Use qDBusRegisterMetaType to register it",
QVariant::typeToName( QVariant::Type(kid) ), kid);
- error();
+ error(QString::fromLatin1("Unregistered type %1 passed in arguments")
+ .arg(QLatin1String(QVariant::typeToName(QVariant::Type(kid)))));
return this;
}
if (ksignature[1] != 0 || !q_dbus_type_is_basic(*ksignature)) {
qWarning("QDBusMarshaller: type '%s' (%d) cannot be used as the key type in a D-BUS map.",
QVariant::typeToName( QVariant::Type(kid) ), kid);
- error();
+ error(QString::fromLatin1("Type %1 passed in arguments cannot be used as a key in a map")
+ .arg(QLatin1String(QVariant::typeToName(QVariant::Type(kid)))));
return this;
}
const char *vsignature = QDBusMetaType::typeToSignature( QVariant::Type(vid) );
if (!vsignature) {
+ const char *typeName = QVariant::typeToName(QVariant::Type(vid));
qWarning("QDBusMarshaller: type `%s' (%d) is not registered with D-BUS. "
"Use qDBusRegisterMetaType to register it",
- QVariant::typeToName( QVariant::Type(vid) ), vid);
- error();
+ typeName, vid);
+ error(QString::fromLatin1("Unregistered type %1 passed in arguments")
+ .arg(QLatin1String(typeName)));
return this;
}
@@ -328,11 +334,13 @@ void QDBusMarshaller::close()
}
}
-void QDBusMarshaller::error()
+void QDBusMarshaller::error(const QString &msg)
{
ok = false;
if (parent)
- parent->error();
+ parent->error(msg);
+ else
+ errorString = msg;
}
bool QDBusMarshaller::appendVariantInternal(const QVariant &arg)
@@ -340,7 +348,7 @@ bool QDBusMarshaller::appendVariantInternal(const QVariant &arg)
int id = arg.userType();
if (id == QVariant::Invalid) {
qWarning("QDBusMarshaller: cannot add an invalid QVariant");
- error();
+ error(QLatin1String("Variant containing QVariant::Invalid passed in arguments"));
return false;
}
@@ -371,7 +379,8 @@ bool QDBusMarshaller::appendVariantInternal(const QVariant &arg)
qWarning("QDBusMarshaller: type `%s' (%d) is not registered with D-BUS. "
"Use qDBusRegisterMetaType to register it",
QVariant::typeToName( QVariant::Type(id) ), id);
- error();
+ error(QString::fromLatin1("Unregistered type %1 passed in arguments")
+ .arg(QLatin1String(QVariant::typeToName(QVariant::Type(id)))));
return false;
}
diff --git a/src/dbus/qdbusmessage.cpp b/src/dbus/qdbusmessage.cpp
index 9150295..78de6d9 100644
--- a/src/dbus/qdbusmessage.cpp
+++ b/src/dbus/qdbusmessage.cpp
@@ -62,7 +62,8 @@ static inline const char *data(const QByteArray &arr)
QDBusMessagePrivate::QDBusMessagePrivate()
: msg(0), reply(0), type(DBUS_MESSAGE_TYPE_INVALID),
- timeout(-1), localReply(0), ref(1), delayedReply(false), localMessage(false)
+ timeout(-1), localReply(0), ref(1), delayedReply(false), localMessage(false),
+ parametersValidated(false)
{
}
@@ -94,11 +95,17 @@ QString QDBusMessage::errorMessage() const
\internal
Constructs a DBusMessage object from this object. The returned value must be de-referenced
with q_dbus_message_unref.
+
+ The \a error object is set to indicate the error if anything went wrong with the
+ marshalling. Usually, this error message will be placed in the reply, as if the call failed.
+ The \a error pointer must not be null.
*/
-DBusMessage *QDBusMessagePrivate::toDBusMessage(const QDBusMessage &message)
+DBusMessage *QDBusMessagePrivate::toDBusMessage(const QDBusMessage &message, QDBusError *error)
{
- if (!qdbus_loadLibDBus())
+ if (!qdbus_loadLibDBus()) {
+ *error = QDBusError(QDBusError::Failed, QLatin1String("Could not open lidbus-1 library"));
return 0;
+ }
DBusMessage *msg = 0;
const QDBusMessagePrivate *d_ptr = message.d_ptr;
@@ -108,10 +115,19 @@ DBusMessage *QDBusMessagePrivate::toDBusMessage(const QDBusMessage &message)
//qDebug() << "QDBusMessagePrivate::toDBusMessage" << "message is invalid";
break;
case DBUS_MESSAGE_TYPE_METHOD_CALL:
- // only interface can be empty
- if (d_ptr->service.isEmpty() || d_ptr->path.isEmpty() || d_ptr->name.isEmpty())
- break;
- msg = q_dbus_message_new_method_call(d_ptr->service.toUtf8(), d_ptr->path.toUtf8(),
+ // only service and interface can be empty -> path and name must not be empty
+ if (!d_ptr->parametersValidated) {
+ if (!QDBusUtil::checkBusName(d_ptr->service, QDBusUtil::EmptyAllowed, error))
+ return 0;
+ if (!QDBusUtil::checkObjectPath(d_ptr->path, QDBusUtil::EmptyNotAllowed, error))
+ return 0;
+ if (!QDBusUtil::checkInterfaceName(d_ptr->interface, QDBusUtil::EmptyAllowed, error))
+ return 0;
+ if (!QDBusUtil::checkMemberName(d_ptr->name, QDBusUtil::EmptyNotAllowed, error, "method"))
+ return 0;
+ }
+
+ msg = q_dbus_message_new_method_call(data(d_ptr->service.toUtf8()), d_ptr->path.toUtf8(),
data(d_ptr->interface.toUtf8()), d_ptr->name.toUtf8());
break;
case DBUS_MESSAGE_TYPE_METHOD_RETURN:
@@ -123,8 +139,10 @@ DBusMessage *QDBusMessagePrivate::toDBusMessage(const QDBusMessage &message)
break;
case DBUS_MESSAGE_TYPE_ERROR:
// error name can't be empty
- if (d_ptr->name.isEmpty())
- break;
+ if (!d_ptr->parametersValidated
+ && !QDBusUtil::checkErrorName(d_ptr->name, QDBusUtil::EmptyNotAllowed, error))
+ return 0;
+
msg = q_dbus_message_new(DBUS_MESSAGE_TYPE_ERROR);
q_dbus_message_set_error_name(msg, d_ptr->name.toUtf8());
if (!d_ptr->localMessage) {
@@ -134,8 +152,15 @@ DBusMessage *QDBusMessagePrivate::toDBusMessage(const QDBusMessage &message)
break;
case DBUS_MESSAGE_TYPE_SIGNAL:
// nothing can be empty here
- if (d_ptr->path.isEmpty() || d_ptr->interface.isEmpty() || d_ptr->name.isEmpty())
- break;
+ if (!d_ptr->parametersValidated) {
+ if (!QDBusUtil::checkObjectPath(d_ptr->path, QDBusUtil::EmptyNotAllowed, error))
+ return 0;
+ if (!QDBusUtil::checkInterfaceName(d_ptr->interface, QDBusUtil::EmptyAllowed, error))
+ return 0;
+ if (!QDBusUtil::checkMemberName(d_ptr->name, QDBusUtil::EmptyNotAllowed, error, "method"))
+ return 0;
+ }
+
msg = q_dbus_message_new_signal(d_ptr->path.toUtf8(), d_ptr->interface.toUtf8(),
d_ptr->name.toUtf8());
break;
@@ -143,16 +168,11 @@ DBusMessage *QDBusMessagePrivate::toDBusMessage(const QDBusMessage &message)
Q_ASSERT(false);
break;
}
-#if 0
- DBusError err;
- q_dbus_error_init(&err);
- if (q_dbus_error_is_set(&err)) {
- QDBusError qe(&err);
- qDebug() << "QDBusMessagePrivate::toDBusMessage" << qe;
- }
-#endif
- if (!msg)
- return 0;
+
+ // if we got here, the parameters validated
+ // and since the message parameters cannot be changed once the message is created
+ // we can record this fact
+ d_ptr->parametersValidated = true;
QDBusMarshaller marshaller;
QVariantList::ConstIterator it = d_ptr->arguments.constBegin();
@@ -170,6 +190,7 @@ DBusMessage *QDBusMessagePrivate::toDBusMessage(const QDBusMessage &message)
// not ok;
q_dbus_message_unref(msg);
+ *error = QDBusError(QDBusError::Failed, QLatin1String("Marshalling failed: ") + marshaller.errorString);
return 0;
}
@@ -247,7 +268,13 @@ QDBusMessage QDBusMessagePrivate::makeLocal(const QDBusConnectionPrivate &conn,
// yes, we are
// we must marshall and demarshall again so as to create QDBusArgument
// entries for the complex types
- DBusMessage *message = toDBusMessage(asSent);
+ QDBusError error;
+ DBusMessage *message = toDBusMessage(asSent, &error);
+ if (!message) {
+ // failed to marshall, so it's a call error
+ return QDBusMessage::createError(error);
+ }
+
q_dbus_message_set_sender(message, conn.baseService.toUtf8());
QDBusMessage retval = fromDBusMessage(message);
@@ -466,6 +493,13 @@ QDBusMessage QDBusMessage::createErrorReply(const QString name, const QString &m
Constructs a new DBus reply message for the error type \a type using
the message \a msg. Returns the DBus message.
*/
+QDBusMessage QDBusMessage::createErrorReply(QDBusError::ErrorType atype, const QString &amsg) const
+{
+ QDBusMessage msg = createErrorReply(QDBusError::errorString(atype), amsg);
+ msg.d_ptr->parametersValidated = true;
+ return msg;
+}
+
/*!
Constructs an empty, invalid QDBusMessage object.
diff --git a/src/dbus/qdbusmessage.h b/src/dbus/qdbusmessage.h
index 55f388a..34b1635 100644
--- a/src/dbus/qdbusmessage.h
+++ b/src/dbus/qdbusmessage.h
@@ -87,8 +87,9 @@ public:
QDBusMessage createErrorReply(const QString name, const QString &msg) const;
inline QDBusMessage createErrorReply(const QDBusError &err) const
{ return createErrorReply(err.name(), err.message()); }
- inline QDBusMessage createErrorReply(QDBusError::ErrorType type, const QString &msg) const;
+ QDBusMessage createErrorReply(QDBusError::ErrorType type, const QString &msg) const;
+ // there are no setters; if this changes, see qdbusmessage_p.h
QString service() const;
QString path() const;
QString interface() const;
@@ -113,9 +114,6 @@ private:
QDBusMessagePrivate *d_ptr;
};
-inline QDBusMessage QDBusMessage::createErrorReply(QDBusError::ErrorType atype, const QString &amsg) const
-{ return createErrorReply(QDBusError::errorString(atype), amsg); }
-
#ifndef QT_NO_DEBUG_STREAM
QDBUS_EXPORT QDebug operator<<(QDebug, const QDBusMessage &);
#endif
diff --git a/src/dbus/qdbusmessage_p.h b/src/dbus/qdbusmessage_p.h
index 12a9500..b8f23dc 100644
--- a/src/dbus/qdbusmessage_p.h
+++ b/src/dbus/qdbusmessage_p.h
@@ -55,6 +55,7 @@
#include <qatomic.h>
#include <qstring.h>
+#include <qdbusmessage.h>
struct DBusMessage;
@@ -69,7 +70,11 @@ public:
~QDBusMessagePrivate();
QList<QVariant> arguments;
+
+ // the following parameters are "const": they are not changed after the constructors
+ // the parametersValidated member below controls whether they've been validated already
QString service, path, interface, name, message, signature;
+
DBusMessage *msg;
DBusMessage *reply;
int type;
@@ -79,8 +84,12 @@ public:
mutable uint delayedReply : 1;
uint localMessage : 1;
+ mutable uint parametersValidated : 1;
+
+ static void setParametersValidated(QDBusMessage &msg, bool enable)
+ { msg.d_ptr->parametersValidated = enable; }
- static DBusMessage *toDBusMessage(const QDBusMessage &message);
+ static DBusMessage *toDBusMessage(const QDBusMessage &message, QDBusError *error);
static QDBusMessage fromDBusMessage(DBusMessage *dmsg);
static bool isLocal(const QDBusMessage &msg);
diff --git a/src/dbus/qdbusmisc.cpp b/src/dbus/qdbusmisc.cpp
index e5c1da6..1b77a9b 100644
--- a/src/dbus/qdbusmisc.cpp
+++ b/src/dbus/qdbusmisc.cpp
@@ -41,12 +41,14 @@
#include <string.h>
+#include <QtCore/qcoreapplication.h>
#include <QtCore/qvariant.h>
#include <QtCore/qmetaobject.h>
#include "qdbusutil_p.h"
#include "qdbusconnection_p.h"
#include "qdbusmetatype_p.h"
+#include "qdbusabstractadaptor_p.h" // for QCLASSINFO_DBUS_*
QT_BEGIN_NAMESPACE
@@ -73,6 +75,51 @@ int qDBusNameToTypeId(const char *name)
return id;
}
+QString qDBusInterfaceFromMetaObject(const QMetaObject *mo)
+{
+ QString interface;
+
+ int idx = mo->indexOfClassInfo(QCLASSINFO_DBUS_INTERFACE);
+ if (idx >= mo->classInfoOffset()) {
+ interface = QLatin1String(mo->classInfo(idx).value());
+ } else {
+ interface = QLatin1String(mo->className());
+ interface.replace(QLatin1String("::"), QLatin1String("."));
+
+ if (interface.startsWith(QLatin1String("QDBus"))) {
+ interface.prepend(QLatin1String("com.trolltech.QtDBus."));
+ } else if (interface.startsWith(QLatin1Char('Q')) &&
+ interface.length() >= 2 && interface.at(1).isUpper()) {
+ // assume it's Qt
+ interface.prepend(QLatin1String("com.trolltech.Qt."));
+ } else if (!QCoreApplication::instance()||
+ QCoreApplication::instance()->applicationName().isEmpty()) {
+ interface.prepend(QLatin1String("local."));
+ } else {
+ interface.prepend(QLatin1Char('.')).prepend(QCoreApplication::instance()->applicationName());
+ QStringList domainName =
+ QCoreApplication::instance()->organizationDomain().split(QLatin1Char('.'),
+ QString::SkipEmptyParts);
+ if (domainName.isEmpty())
+ interface.prepend(QLatin1String("local."));
+ else
+ for (int i = 0; i < domainName.count(); ++i)
+ interface.prepend(QLatin1Char('.')).prepend(domainName.at(i));
+ }
+ }
+
+ return interface;
+}
+
+bool qDBusInterfaceInObject(QObject *obj, const QString &interface_name)
+{
+ const QMetaObject *mo = obj->metaObject();
+ for ( ; mo != &QObject::staticMetaObject; mo = mo->superClass())
+ if (interface_name == qDBusInterfaceFromMetaObject(mo))
+ return true;
+ return false;
+}
+
// calculates the metatypes for the method
// the slot must have the parameters in the following form:
// - zero or more value or const-ref parameters of any kind
diff --git a/src/dbus/qdbuspendingcall.cpp b/src/dbus/qdbuspendingcall.cpp
index 1797ed0..7807543 100644
--- a/src/dbus/qdbuspendingcall.cpp
+++ b/src/dbus/qdbuspendingcall.cpp
@@ -409,6 +409,42 @@ bool QDBusPendingCall::setReplyCallback(QObject *target, const char *member)
}
#endif
+/*!
+ Creates a QDBusPendingCall object based on the error condition
+ \a error. The resulting pending call object will be in the
+ "finished" state and QDBusPendingReply::isError() will return true.
+
+ \sa fromCompletedCall()
+*/
+QDBusPendingCall QDBusPendingCall::fromError(const QDBusError &error)
+{
+ return fromCompletedCall(QDBusMessage::createError(error));
+}
+
+/*!
+ Creates a QDBusPendingCall object based on the message \a msg.
+ The message must be of type QDBusMessage::ErrorMessage or
+ QDBusMessage::ReplyMessage (that is, a message that is typical
+ of a completed call).
+
+ This function is useful for code that requires simulating a pending
+ call, but that has already finished.
+
+ \sa fromError()
+*/
+QDBusPendingCall QDBusPendingCall::fromCompletedCall(const QDBusMessage &msg)
+{
+ QDBusPendingCallPrivate *d = 0;
+ if (msg.type() == QDBusMessage::ErrorMessage ||
+ msg.type() == QDBusMessage::ReplyMessage) {
+ d = new QDBusPendingCallPrivate;
+ d->replyMessage = msg;
+ d->connection = 0;
+ }
+
+ return QDBusPendingCall(d);
+}
+
class QDBusPendingCallWatcherPrivate: public QObjectPrivate
{
diff --git a/src/dbus/qdbuspendingcall.h b/src/dbus/qdbuspendingcall.h
index 8881920..8dbbb3c 100644
--- a/src/dbus/qdbuspendingcall.h
+++ b/src/dbus/qdbuspendingcall.h
@@ -78,6 +78,9 @@ public:
QDBusMessage reply() const;
#endif
+ static QDBusPendingCall fromError(const QDBusError &error);
+ static QDBusPendingCall fromCompletedCall(const QDBusMessage &message);
+
protected:
QExplicitlySharedDataPointer<QDBusPendingCallPrivate> d;
friend class QDBusPendingCallPrivate;
diff --git a/src/dbus/qdbuspendingcall_p.h b/src/dbus/qdbuspendingcall_p.h
index 7136f67..5577451 100644
--- a/src/dbus/qdbuspendingcall_p.h
+++ b/src/dbus/qdbuspendingcall_p.h
@@ -63,6 +63,7 @@
QT_BEGIN_NAMESPACE
+class QDBusPendingCall;
class QDBusPendingCallWatcher;
class QDBusPendingCallWatcherHelper;
class QDBusConnectionPrivate;
@@ -94,6 +95,8 @@ public:
void waitForFinished();
void setMetaTypes(int count, const int *types);
void checkReceivedSignature();
+
+ static QDBusPendingCall fromMessage(const QDBusMessage &msg);
};
class QDBusPendingCallWatcherHelper: public QObject
diff --git a/src/dbus/qdbusutil_p.h b/src/dbus/qdbusutil_p.h
index 13031fd..5c1e4cd 100644
--- a/src/dbus/qdbusutil_p.h
+++ b/src/dbus/qdbusutil_p.h
@@ -57,6 +57,7 @@
#include <QtCore/qvariant.h>
#include <QtDBus/qdbusmacros.h>
+#include <QtDBus/qdbuserror.h>
QT_BEGIN_HEADER
@@ -83,6 +84,73 @@ namespace QDBusUtil
QDBUS_EXPORT bool isValidSingleSignature(const QString &signature);
QDBUS_EXPORT QString argumentToString(const QVariant &variant);
+
+ enum AllowEmptyFlag {
+ EmptyAllowed,
+ EmptyNotAllowed
+ };
+
+ inline bool checkInterfaceName(const QString &name, AllowEmptyFlag empty, QDBusError *error)
+ {
+ if (name.isEmpty()) {
+ if (empty == EmptyAllowed) return true;
+ *error = QDBusError(QDBusError::InvalidInterface, QLatin1String("Interface name cannot be empty"));
+ return false;
+ }
+ if (isValidInterfaceName(name)) return true;
+ *error = QDBusError(QDBusError::InvalidInterface, QString::fromLatin1("Invalid interface class: %1").arg(name));
+ return false;
+ }
+
+ inline bool checkBusName(const QString &name, AllowEmptyFlag empty, QDBusError *error)
+ {
+ if (name.isEmpty()) {
+ if (empty == EmptyAllowed) return true;
+ *error = QDBusError(QDBusError::InvalidService, QLatin1String("Service name cannot be empty"));
+ return false;
+ }
+ if (isValidBusName(name)) return true;
+ *error = QDBusError(QDBusError::InvalidService, QString::fromLatin1("Invalid service name: %1").arg(name));
+ return false;
+ }
+
+ inline bool checkObjectPath(const QString &path, AllowEmptyFlag empty, QDBusError *error)
+ {
+ if (path.isEmpty()) {
+ if (empty == EmptyAllowed) return true;
+ *error = QDBusError(QDBusError::InvalidObjectPath, QLatin1String("Object path cannot be empty"));
+ return false;
+ }
+ if (isValidObjectPath(path)) return true;
+ *error = QDBusError(QDBusError::InvalidObjectPath, QString::fromLatin1("Invalid object path: %1").arg(path));
+ return false;
+ }
+
+ inline bool checkMemberName(const QString &name, AllowEmptyFlag empty, QDBusError *error, const char *nameType = 0)
+ {
+ if (!nameType) nameType = "member";
+ if (name.isEmpty()) {
+ if (empty == EmptyAllowed) return true;
+ *error = QDBusError(QDBusError::InvalidMember, QLatin1String(nameType) + QLatin1String(" name cannot be empty"));
+ return false;
+ }
+ if (isValidMemberName(name)) return true;
+ *error = QDBusError(QDBusError::InvalidMember, QString::fromLatin1("Invalid %1 name: %2")
+ .arg(QString::fromLatin1(nameType), name));
+ return false;
+ }
+
+ inline bool checkErrorName(const QString &name, AllowEmptyFlag empty, QDBusError *error)
+ {
+ if (name.isEmpty()) {
+ if (empty == EmptyAllowed) return true;
+ *error = QDBusError(QDBusError::InvalidInterface, QLatin1String("Error name cannot be empty"));
+ return false;
+ }
+ if (isValidErrorName(name)) return true;
+ *error = QDBusError(QDBusError::InvalidInterface, QString::fromLatin1("Invalid error name: %1").arg(name));
+ return false;
+ }
}
QT_END_NAMESPACE
diff --git a/src/dbus/qdbusxmlgenerator.cpp b/src/dbus/qdbusxmlgenerator.cpp
index 82bd762..b426abd 100644
--- a/src/dbus/qdbusxmlgenerator.cpp
+++ b/src/dbus/qdbusxmlgenerator.cpp
@@ -39,7 +39,6 @@
**
****************************************************************************/
-#include <QtCore/qcoreapplication.h>
#include <QtCore/qmetaobject.h>
#include <QtCore/qstringlist.h>
@@ -232,42 +231,6 @@ static QString generateInterfaceXml(const QMetaObject *mo, int flags, int method
return retval;
}
-QString qDBusInterfaceFromMetaObject(const QMetaObject *mo)
-{
- QString interface;
-
- int idx = mo->indexOfClassInfo(QCLASSINFO_DBUS_INTERFACE);
- if (idx >= mo->classInfoOffset()) {
- interface = QLatin1String(mo->classInfo(idx).value());
- } else {
- interface = QLatin1String(mo->className());
- interface.replace(QLatin1String("::"), QLatin1String("."));
-
- if (interface.startsWith(QLatin1String("QDBus"))) {
- interface.prepend(QLatin1String("com.trolltech.QtDBus."));
- } else if (interface.startsWith(QLatin1Char('Q')) &&
- interface.length() >= 2 && interface.at(1).isUpper()) {
- // assume it's Qt
- interface.prepend(QLatin1String("com.trolltech.Qt."));
- } else if (!QCoreApplication::instance()||
- QCoreApplication::instance()->applicationName().isEmpty()) {
- interface.prepend(QLatin1String("local."));
- } else {
- interface.prepend(QLatin1Char('.')).prepend(QCoreApplication::instance()->applicationName());
- QStringList domainName =
- QCoreApplication::instance()->organizationDomain().split(QLatin1Char('.'),
- QString::SkipEmptyParts);
- if (domainName.isEmpty())
- interface.prepend(QLatin1String("local."));
- else
- for (int i = 0; i < domainName.count(); ++i)
- interface.prepend(QLatin1Char('.')).prepend(domainName.at(i));
- }
- }
-
- return interface;
- }
-
QString qDBusGenerateMetaObjectXml(QString interface, const QMetaObject *mo,
const QMetaObject *base, int flags)
{
diff --git a/tests/auto/auto.pro b/tests/auto/auto.pro
index 5e4764d..9924904 100644
--- a/tests/auto/auto.pro
+++ b/tests/auto/auto.pro
@@ -435,6 +435,7 @@ xmlpatternsxslts.depends = xmlpatternsxqts
unix:!embedded:contains(QT_CONFIG, dbus):SUBDIRS += \
qdbusabstractadaptor \
+ qdbusabstractinterface \
qdbusconnection \
qdbusinterface \
qdbuslocalcalls \
diff --git a/tests/auto/qdbusabstractadaptor/tst_qdbusabstractadaptor.cpp b/tests/auto/qdbusabstractadaptor/tst_qdbusabstractadaptor.cpp
index c70c619..5d08c63 100644
--- a/tests/auto/qdbusabstractadaptor/tst_qdbusabstractadaptor.cpp
+++ b/tests/auto/qdbusabstractadaptor/tst_qdbusabstractadaptor.cpp
@@ -609,19 +609,22 @@ void tst_QDBusAbstractAdaptor::methodCalls()
QVERIFY(con.isConnected());
//QDBusInterface emptycon.baseService(), "/", QString());
- QDBusInterface if1(con.baseService(), "/", "local.Interface1", con);
- QDBusInterface if2(con.baseService(), "/", "local.Interface2", con);
- QDBusInterface if3(con.baseService(), "/", "local.Interface3", con);
- QDBusInterface if4(con.baseService(), "/", "local.Interface4", con);
- // must fail: no object
- //QCOMPARE(empty->call("method").type(), QDBusMessage::ErrorMessage);
- QCOMPARE(if1.call(QDBus::BlockWithGui, "method").type(), QDBusMessage::ErrorMessage);
+ {
+ // must fail: no object
+ QDBusInterface if1(con.baseService(), "/", "local.Interface1", con);
+ QCOMPARE(if1.call(QDBus::BlockWithGui, "method").type(), QDBusMessage::ErrorMessage);
+ }
QFETCH(int, nInterfaces);
MyObject obj(nInterfaces);
con.registerObject("/", &obj);
+ QDBusInterface if1(con.baseService(), "/", "local.Interface1", con);
+ QDBusInterface if2(con.baseService(), "/", "local.Interface2", con);
+ QDBusInterface if3(con.baseService(), "/", "local.Interface3", con);
+ QDBusInterface if4(con.baseService(), "/", "local.Interface4", con);
+
// must fail: no such method
QCOMPARE(if1.call(QDBus::BlockWithGui, "method").type(), QDBusMessage::ErrorMessage);
if (!nInterfaces--)
@@ -670,11 +673,11 @@ void tst_QDBusAbstractAdaptor::methodCallScriptable()
QDBusConnection con = QDBusConnection::sessionBus();
QVERIFY(con.isConnected());
- QDBusInterface if2(con.baseService(), "/", "local.Interface2", con);
-
MyObject obj(2);
con.registerObject("/", &obj);
+ QDBusInterface if2(con.baseService(), "/", "local.Interface2", con);
+
QCOMPARE(if2.call(QDBus::BlockWithGui,"scriptableMethod").type(), QDBusMessage::ReplyMessage);
QCOMPARE(slotSpy, "void Interface2::scriptableMethod()");
}
diff --git a/tests/auto/qdbusabstractinterface/com.trolltech.QtDBus.Pinger.xml b/tests/auto/qdbusabstractinterface/com.trolltech.QtDBus.Pinger.xml
new file mode 100644
index 0000000..fb2aab8
--- /dev/null
+++ b/tests/auto/qdbusabstractinterface/com.trolltech.QtDBus.Pinger.xml
@@ -0,0 +1,30 @@
+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
+<node>
+ <interface name="com.trolltech.QtDBus.Pinger">
+ <property name="stringProp" type="s" access="readwrite"/>
+ <property name="variantProp" type="v" access="readwrite"/>
+ <property name="complexProp" type="(s)" access="readwrite">
+ <annotation name="com.trolltech.QtDBus.QtTypeName" value="RegisteredType"/>
+ </property>
+ <signal name="voidSignal"/>
+ <signal name="stringSignal">
+ <arg type="s"/>
+ </signal>
+ <signal name="complexSignal">
+ <arg name="" type="(s)"/>
+ <annotation name="com.trolltech.QtDBus.QtTypeName.In0" value="RegisteredType"/>
+ </signal>
+ <method name="voidMethod" />
+ <method name="stringMethod">
+ <arg type="s" direction="out"/>
+ </method>
+ <method name="complexMethod">
+ <arg type="(s)" direction="out"/>
+ <annotation name="com.trolltech.QtDBus.QtTypeName.Out0" value="RegisteredType"/>
+ </method>
+ <method name="multiOutMethod">
+ <arg type="s" direction="out"/>
+ <arg type="i" direction="out"/
+ </method>
+ </interface>
+</node>
diff --git a/tests/auto/qdbusabstractinterface/interface.cpp b/tests/auto/qdbusabstractinterface/interface.cpp
new file mode 100644
index 0000000..1c391ce
--- /dev/null
+++ b/tests/auto/qdbusabstractinterface/interface.cpp
@@ -0,0 +1,48 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "interface.h"
+
+Interface::Interface()
+{
+}
+
+#include "moc_interface.cpp"
diff --git a/tests/auto/qdbusabstractinterface/interface.h b/tests/auto/qdbusabstractinterface/interface.h
new file mode 100644
index 0000000..f6d34a7
--- /dev/null
+++ b/tests/auto/qdbusabstractinterface/interface.h
@@ -0,0 +1,113 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef INTERFACE_H
+#define INTERFACE_H
+
+#include <QtCore/QObject>
+#include <QtDBus/QDBusArgument>
+
+struct RegisteredType
+{
+ inline RegisteredType(const QString &str = QString()) : s(str) {}
+ inline bool operator==(const RegisteredType &other) const { return s == other.s; }
+ QString s;
+};
+Q_DECLARE_METATYPE(RegisteredType)
+
+inline QDBusArgument &operator<<(QDBusArgument &s, const RegisteredType &data)
+{
+ s.beginStructure();
+ s << data.s;
+ s.endStructure();
+ return s;
+}
+
+inline const QDBusArgument &operator>>(const QDBusArgument &s, RegisteredType &data)
+{
+ s.beginStructure();
+ s >> data.s;
+ s.endStructure();
+ return s;
+}
+
+struct UnregisteredType
+{
+ QString s;
+};
+Q_DECLARE_METATYPE(UnregisteredType)
+
+class Interface: public QObject
+{
+ Q_OBJECT
+ Q_CLASSINFO("D-Bus Interface", "com.trolltech.QtDBus.Pinger")
+ Q_PROPERTY(QString stringProp READ stringProp WRITE setStringProp SCRIPTABLE true)
+ Q_PROPERTY(QDBusVariant variantProp READ variantProp WRITE setVariantProp SCRIPTABLE true)
+ Q_PROPERTY(RegisteredType complexProp READ complexProp WRITE setComplexProp SCRIPTABLE true)
+
+ friend class tst_QDBusAbstractInterface;
+ QString m_stringProp;
+ QDBusVariant m_variantProp;
+ RegisteredType m_complexProp;
+
+public:
+ Interface();
+
+ QString stringProp() const { return m_stringProp; }
+ void setStringProp(const QString &s) { m_stringProp = s; }
+ QDBusVariant variantProp() const { return m_variantProp; }
+ void setVariantProp(const QDBusVariant &v) { m_variantProp = v; }
+ RegisteredType complexProp() const { return m_complexProp; }
+ void setComplexProp(const RegisteredType &r) { m_complexProp = r; }
+
+public slots:
+ Q_SCRIPTABLE void voidMethod() {}
+ Q_SCRIPTABLE QString stringMethod() { return "Hello, world"; }
+ Q_SCRIPTABLE RegisteredType complexMethod() { return RegisteredType("Hello, world"); }
+ Q_SCRIPTABLE QString multiOutMethod(int &value) { value = 42; return "Hello, world"; }
+
+signals:
+ Q_SCRIPTABLE void voidSignal();
+ Q_SCRIPTABLE void stringSignal(const QString &);
+ Q_SCRIPTABLE void complexSignal(RegisteredType);
+};
+
+#endif // INTERFACE_H
diff --git a/tests/auto/qdbusabstractinterface/pinger.cpp b/tests/auto/qdbusabstractinterface/pinger.cpp
new file mode 100644
index 0000000..4fcb89a
--- /dev/null
+++ b/tests/auto/qdbusabstractinterface/pinger.cpp
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDBus module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*
+ * This file was generated by qdbusxml2cpp version 0.7
+ * Command line was: qdbusxml2cpp -i interface.h -p pinger com.trolltech.QtDBus.Pinger.xml
+ *
+ * qdbusxml2cpp is Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * This is an auto-generated file.
+ * This file may have been hand-edited. Look for HAND-EDIT comments
+ * before re-generating it.
+ */
+
+#include "pinger.h"
+
+/*
+ * Implementation of interface class ComTrolltechQtDBusPingerInterface
+ */
+
+ComTrolltechQtDBusPingerInterface::ComTrolltechQtDBusPingerInterface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent)
+ : QDBusAbstractInterface(service, path, staticInterfaceName(), connection, parent)
+{
+}
+
+ComTrolltechQtDBusPingerInterface::~ComTrolltechQtDBusPingerInterface()
+{
+}
+
diff --git a/tests/auto/qdbusabstractinterface/pinger.h b/tests/auto/qdbusabstractinterface/pinger.h
new file mode 100644
index 0000000..fb8adda
--- /dev/null
+++ b/tests/auto/qdbusabstractinterface/pinger.h
@@ -0,0 +1,145 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDBus module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*
+ * This file was generated by qdbusxml2cpp version 0.7
+ * Command line was: qdbusxml2cpp -i interface.h -p pinger com.trolltech.QtDBus.Pinger.xml
+ *
+ * qdbusxml2cpp is Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * This is an auto-generated file.
+ * Do not edit! All changes made to it will be lost.
+ */
+
+#ifndef PINGER_H_1246463415
+#define PINGER_H_1246463415
+
+#include <QtCore/QObject>
+#include <QtCore/QByteArray>
+#include <QtCore/QList>
+#include <QtCore/QMap>
+#include <QtCore/QString>
+#include <QtCore/QStringList>
+#include <QtCore/QVariant>
+#include <QtDBus/QtDBus>
+#include "interface.h"
+
+/*
+ * Proxy class for interface com.trolltech.QtDBus.Pinger
+ */
+class ComTrolltechQtDBusPingerInterface: public QDBusAbstractInterface
+{
+ Q_OBJECT
+public:
+ static inline const char *staticInterfaceName()
+ { return "com.trolltech.QtDBus.Pinger"; }
+
+public:
+ ComTrolltechQtDBusPingerInterface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = 0);
+
+ ~ComTrolltechQtDBusPingerInterface();
+
+ Q_PROPERTY(RegisteredType complexProp READ complexProp WRITE setComplexProp)
+ inline RegisteredType complexProp() const
+ { return qvariant_cast< RegisteredType >(property("complexProp")); }
+ inline void setComplexProp(RegisteredType value)
+ { setProperty("complexProp", qVariantFromValue(value)); }
+
+ Q_PROPERTY(QString stringProp READ stringProp WRITE setStringProp)
+ inline QString stringProp() const
+ { return qvariant_cast< QString >(property("stringProp")); }
+ inline void setStringProp(const QString &value)
+ { setProperty("stringProp", qVariantFromValue(value)); }
+
+ Q_PROPERTY(QDBusVariant variantProp READ variantProp WRITE setVariantProp)
+ inline QDBusVariant variantProp() const
+ { return qvariant_cast< QDBusVariant >(property("variantProp")); }
+ inline void setVariantProp(const QDBusVariant &value)
+ { setProperty("variantProp", qVariantFromValue(value)); }
+
+public Q_SLOTS: // METHODS
+ inline QDBusPendingReply<RegisteredType> complexMethod()
+ {
+ QList<QVariant> argumentList;
+ return asyncCallWithArgumentList(QLatin1String("complexMethod"), argumentList);
+ }
+
+ inline QDBusPendingReply<QString, int> multiOutMethod()
+ {
+ QList<QVariant> argumentList;
+ return asyncCallWithArgumentList(QLatin1String("multiOutMethod"), argumentList);
+ }
+ inline QDBusReply<QString> multiOutMethod(int &out1)
+ {
+ QList<QVariant> argumentList;
+ QDBusMessage reply = callWithArgumentList(QDBus::Block, QLatin1String("multiOutMethod"), argumentList);
+ if (reply.type() == QDBusMessage::ReplyMessage && reply.arguments().count() == 2) {
+ out1 = qdbus_cast<int>(reply.arguments().at(1));
+ }
+ return reply;
+ }
+
+ inline QDBusPendingReply<QString> stringMethod()
+ {
+ QList<QVariant> argumentList;
+ return asyncCallWithArgumentList(QLatin1String("stringMethod"), argumentList);
+ }
+
+ inline QDBusPendingReply<> voidMethod()
+ {
+ QList<QVariant> argumentList;
+ return asyncCallWithArgumentList(QLatin1String("voidMethod"), argumentList);
+ }
+
+Q_SIGNALS: // SIGNALS
+ void complexSignal(RegisteredType in0);
+ void stringSignal(const QString &in0);
+ void voidSignal();
+};
+
+namespace com {
+ namespace trolltech {
+ namespace QtDBus {
+ typedef ::ComTrolltechQtDBusPingerInterface Pinger;
+ }
+ }
+}
+#endif
diff --git a/tests/auto/qdbusabstractinterface/qdbusabstractinterface.pro b/tests/auto/qdbusabstractinterface/qdbusabstractinterface.pro
new file mode 100644
index 0000000..a4853b8
--- /dev/null
+++ b/tests/auto/qdbusabstractinterface/qdbusabstractinterface.pro
@@ -0,0 +1,15 @@
+load(qttest_p4)
+QT = core
+contains(QT_CONFIG,dbus): {
+ SOURCES += tst_qdbusabstractinterface.cpp interface.cpp
+ HEADERS += interface.h
+ QT += dbus
+
+ # These are generated sources
+ # To regenerate, see the command-line at the top of the files
+ SOURCES += pinger.cpp
+ HEADERS += pinger.h
+}
+else:SOURCES += ../qdbusmarshall/dummy.cpp
+
+OTHER_FILES += com.trolltech.QtDBus.Pinger.xml
diff --git a/tests/auto/qdbusabstractinterface/tst_qdbusabstractinterface.cpp b/tests/auto/qdbusabstractinterface/tst_qdbusabstractinterface.cpp
new file mode 100644
index 0000000..fa5e332
--- /dev/null
+++ b/tests/auto/qdbusabstractinterface/tst_qdbusabstractinterface.cpp
@@ -0,0 +1,576 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <qcoreapplication.h>
+#include <qdebug.h>
+#include <qsharedpointer.h>
+
+#include <QtTest/QtTest>
+
+#include <QtDBus>
+
+#include "interface.h"
+#include "pinger.h"
+
+typedef QSharedPointer<com::trolltech::QtDBus::Pinger> Pinger;
+
+class tst_QDBusAbstractInterface: public QObject
+{
+ Q_OBJECT
+ Interface targetObj;
+
+ Pinger getPinger(QString service = "", const QString &path = "/")
+ {
+ QDBusConnection con = QDBusConnection::sessionBus();
+ if (!con.isConnected())
+ return Pinger();
+ if (service.isEmpty() && !service.isNull())
+ service = con.baseService();
+ return Pinger(new com::trolltech::QtDBus::Pinger(service, path, con));
+ }
+
+public:
+ tst_QDBusAbstractInterface();
+
+private slots:
+ void initTestCase();
+
+ void makeVoidCall();
+ void makeStringCall();
+ void makeComplexCall();
+ void makeMultiOutCall();
+
+ void makeAsyncVoidCall();
+ void makeAsyncStringCall();
+ void makeAsyncComplexCall();
+ void makeAsyncMultiOutCall();
+
+ void stringPropRead();
+ void stringPropWrite();
+ void variantPropRead();
+ void variantPropWrite();
+ void complexPropRead();
+ void complexPropWrite();
+
+ void stringPropDirectRead();
+ void stringPropDirectWrite();
+ void variantPropDirectRead();
+ void variantPropDirectWrite();
+ void complexPropDirectRead();
+ void complexPropDirectWrite();
+
+ void getVoidSignal_data();
+ void getVoidSignal();
+ void getStringSignal_data();
+ void getStringSignal();
+ void getComplexSignal_data();
+ void getComplexSignal();
+
+ void createErrors_data();
+ void createErrors();
+
+ void callErrors_data();
+ void callErrors();
+ void asyncCallErrors_data();
+ void asyncCallErrors();
+
+ void propertyReadErrors_data();
+ void propertyReadErrors();
+ void propertyWriteErrors_data();
+ void propertyWriteErrors();
+ void directPropertyReadErrors_data();
+ void directPropertyReadErrors();
+ void directPropertyWriteErrors_data();
+ void directPropertyWriteErrors();
+};
+
+tst_QDBusAbstractInterface::tst_QDBusAbstractInterface()
+{
+ // register the meta types
+ qDBusRegisterMetaType<RegisteredType>();
+ qRegisterMetaType<UnregisteredType>();
+}
+
+void tst_QDBusAbstractInterface::initTestCase()
+{
+ // register the object
+ QDBusConnection con = QDBusConnection::sessionBus();
+ QVERIFY(con.isConnected());
+ con.registerObject("/", &targetObj, QDBusConnection::ExportScriptableContents);
+}
+
+void tst_QDBusAbstractInterface::makeVoidCall()
+{
+ Pinger p = getPinger();
+ QVERIFY2(p, "Not connected to D-Bus");
+
+ QDBusReply<void> r = p->voidMethod();
+ QVERIFY(r.isValid());
+}
+
+void tst_QDBusAbstractInterface::makeStringCall()
+{
+ Pinger p = getPinger();
+ QVERIFY2(p, "Not connected to D-Bus");
+
+ QDBusReply<QString> r = p->stringMethod();
+ QVERIFY(r.isValid());
+ QCOMPARE(r.value(), targetObj.stringMethod());
+}
+
+void tst_QDBusAbstractInterface::makeComplexCall()
+{
+ Pinger p = getPinger();
+ QVERIFY2(p, "Not connected to D-Bus");
+
+ QDBusReply<RegisteredType> r = p->complexMethod();
+ QVERIFY(r.isValid());
+ QCOMPARE(r.value(), targetObj.complexMethod());
+}
+
+void tst_QDBusAbstractInterface::makeMultiOutCall()
+{
+ Pinger p = getPinger();
+ QVERIFY2(p, "Not connected to D-Bus");
+
+ int value;
+ QDBusReply<QString> r = p->multiOutMethod(value);
+ QVERIFY(r.isValid());
+
+ int expectedValue;
+ QCOMPARE(r.value(), targetObj.multiOutMethod(expectedValue));
+ QCOMPARE(value, expectedValue);
+}
+
+void tst_QDBusAbstractInterface::makeAsyncVoidCall()
+{
+ Pinger p = getPinger();
+ QVERIFY2(p, "Not connected to D-Bus");
+
+ QDBusPendingReply<void> r = p->voidMethod();
+ r.waitForFinished();
+ QVERIFY(r.isValid());
+}
+
+void tst_QDBusAbstractInterface::makeAsyncStringCall()
+{
+ Pinger p = getPinger();
+ QVERIFY2(p, "Not connected to D-Bus");
+
+ QDBusPendingReply<QString> r = p->stringMethod();
+ r.waitForFinished();
+ QVERIFY(r.isValid());
+ QCOMPARE(r.value(), targetObj.stringMethod());
+}
+
+void tst_QDBusAbstractInterface::makeAsyncComplexCall()
+{
+ Pinger p = getPinger();
+ QVERIFY2(p, "Not connected to D-Bus");
+
+ QDBusPendingReply<RegisteredType> r = p->complexMethod();
+ r.waitForFinished();
+ QVERIFY(r.isValid());
+ QCOMPARE(r.value(), targetObj.complexMethod());
+}
+
+void tst_QDBusAbstractInterface::makeAsyncMultiOutCall()
+{
+ Pinger p = getPinger();
+ QVERIFY2(p, "Not connected to D-Bus");
+
+ QDBusPendingReply<QString, int> r = p->multiOutMethod();
+ r.waitForFinished();
+ QVERIFY(r.isValid());
+
+ int expectedValue;
+ QCOMPARE(r.value(), targetObj.multiOutMethod(expectedValue));
+ QCOMPARE(r.argumentAt<1>(), expectedValue);
+}
+
+void tst_QDBusAbstractInterface::stringPropRead()
+{
+ Pinger p = getPinger();
+ QVERIFY2(p, "Not connected to D-Bus");
+
+ QString expectedValue = targetObj.m_stringProp = "This is a test";
+ QVariant v = p->property("stringProp");
+ QVERIFY(v.isValid());
+ QCOMPARE(v.toString(), expectedValue);
+}
+
+void tst_QDBusAbstractInterface::stringPropWrite()
+{
+ Pinger p = getPinger();
+ QVERIFY2(p, "Not connected to D-Bus");
+
+ QString expectedValue = "This is a value";
+ QVERIFY(p->setProperty("stringProp", expectedValue));
+ QCOMPARE(targetObj.m_stringProp, expectedValue);
+}
+
+void tst_QDBusAbstractInterface::variantPropRead()
+{
+ Pinger p = getPinger();
+ QVERIFY2(p, "Not connected to D-Bus");
+
+ QDBusVariant expectedValue = targetObj.m_variantProp = QDBusVariant(QVariant(42));
+ QVariant v = p->property("variantProp");
+ QVERIFY(v.isValid());
+ QDBusVariant value = v.value<QDBusVariant>();
+ QCOMPARE(value.variant().userType(), expectedValue.variant().userType());
+ QCOMPARE(value.variant(), expectedValue.variant());
+}
+
+void tst_QDBusAbstractInterface::variantPropWrite()
+{
+ Pinger p = getPinger();
+ QVERIFY2(p, "Not connected to D-Bus");
+
+ QDBusVariant expectedValue = QDBusVariant(Q_INT64_C(-47));
+ QVERIFY(p->setProperty("variantProp", qVariantFromValue(expectedValue)));
+ QCOMPARE(targetObj.m_variantProp.variant(), expectedValue.variant());
+}
+
+void tst_QDBusAbstractInterface::complexPropRead()
+{
+ Pinger p = getPinger();
+ QVERIFY2(p, "Not connected to D-Bus");
+
+ RegisteredType expectedValue = targetObj.m_complexProp = RegisteredType("This is a test");
+ QVariant v = p->property("complexProp");
+ QVERIFY(v.userType() == qMetaTypeId<RegisteredType>());
+ QCOMPARE(v.value<RegisteredType>(), targetObj.m_complexProp);
+}
+
+void tst_QDBusAbstractInterface::complexPropWrite()
+{
+ Pinger p = getPinger();
+ QVERIFY2(p, "Not connected to D-Bus");
+
+ RegisteredType expectedValue = RegisteredType("This is a value");
+ QVERIFY(p->setProperty("complexProp", qVariantFromValue(expectedValue)));
+ QCOMPARE(targetObj.m_complexProp, expectedValue);
+}
+
+void tst_QDBusAbstractInterface::stringPropDirectRead()
+{
+ Pinger p = getPinger();
+ QVERIFY2(p, "Not connected to D-Bus");
+
+ QString expectedValue = targetObj.m_stringProp = "This is a test";
+ QCOMPARE(p->stringProp(), expectedValue);
+}
+
+void tst_QDBusAbstractInterface::stringPropDirectWrite()
+{
+ Pinger p = getPinger();
+ QVERIFY2(p, "Not connected to D-Bus");
+
+ QString expectedValue = "This is a value";
+ p->setStringProp(expectedValue);
+ QCOMPARE(targetObj.m_stringProp, expectedValue);
+}
+
+void tst_QDBusAbstractInterface::variantPropDirectRead()
+{
+ Pinger p = getPinger();
+ QVERIFY2(p, "Not connected to D-Bus");
+
+ QDBusVariant expectedValue = targetObj.m_variantProp = QDBusVariant(42);
+ QCOMPARE(p->variantProp().variant(), expectedValue.variant());
+}
+
+void tst_QDBusAbstractInterface::variantPropDirectWrite()
+{
+ Pinger p = getPinger();
+ QVERIFY2(p, "Not connected to D-Bus");
+
+ QDBusVariant expectedValue = QDBusVariant(Q_INT64_C(-47));
+ p->setVariantProp(expectedValue);
+ QCOMPARE(targetObj.m_variantProp.variant().userType(), expectedValue.variant().userType());
+ QCOMPARE(targetObj.m_variantProp.variant(), expectedValue.variant());
+}
+
+void tst_QDBusAbstractInterface::complexPropDirectRead()
+{
+ Pinger p = getPinger();
+ QVERIFY2(p, "Not connected to D-Bus");
+
+ RegisteredType expectedValue = targetObj.m_complexProp = RegisteredType("This is a test");
+ QCOMPARE(p->complexProp(), targetObj.m_complexProp);
+}
+
+void tst_QDBusAbstractInterface::complexPropDirectWrite()
+{
+ Pinger p = getPinger();
+ QVERIFY2(p, "Not connected to D-Bus");
+
+ RegisteredType expectedValue = RegisteredType("This is a value");
+ p->setComplexProp(expectedValue);
+ QCOMPARE(targetObj.m_complexProp, expectedValue);
+}
+
+void tst_QDBusAbstractInterface::getVoidSignal_data()
+{
+ QTest::addColumn<QString>("service");
+ QTest::addColumn<QString>("path");
+
+ QTest::newRow("specific") << QDBusConnection::sessionBus().baseService() << "/";
+ QTest::newRow("service-wildcard") << QString() << "/";
+ QTest::newRow("path-wildcard") << QDBusConnection::sessionBus().baseService() << QString();
+ QTest::newRow("full-wildcard") << QString() << QString();
+}
+
+void tst_QDBusAbstractInterface::getVoidSignal()
+{
+ QFETCH(QString, service);
+ QFETCH(QString, path);
+ Pinger p = getPinger(service, path);
+ QVERIFY2(p, "Not connected to D-Bus");
+
+ // we need to connect the signal somewhere in order for D-Bus to enable the rules
+ QTestEventLoop::instance().connect(p.data(), SIGNAL(voidSignal()), SLOT(exitLoop()));
+ QSignalSpy s(p.data(), SIGNAL(voidSignal()));
+
+ emit targetObj.voidSignal();
+ QTestEventLoop::instance().enterLoop(2);
+ QVERIFY(!QTestEventLoop::instance().timeout());
+
+ QVERIFY(s.size() == 1);
+ QVERIFY(s.at(0).size() == 0);
+}
+
+void tst_QDBusAbstractInterface::getStringSignal_data()
+{
+ getVoidSignal_data();
+}
+
+void tst_QDBusAbstractInterface::getStringSignal()
+{
+ QFETCH(QString, service);
+ QFETCH(QString, path);
+ Pinger p = getPinger(service, path);
+ QVERIFY2(p, "Not connected to D-Bus");
+
+ // we need to connect the signal somewhere in order for D-Bus to enable the rules
+ QTestEventLoop::instance().connect(p.data(), SIGNAL(stringSignal(QString)), SLOT(exitLoop()));
+ QSignalSpy s(p.data(), SIGNAL(stringSignal(QString)));
+
+ QString expectedValue = "Good morning";
+ emit targetObj.stringSignal(expectedValue);
+ QTestEventLoop::instance().enterLoop(2);
+ QVERIFY(!QTestEventLoop::instance().timeout());
+
+ QVERIFY(s.size() == 1);
+ QVERIFY(s[0].size() == 1);
+ QCOMPARE(s[0][0].userType(), int(QVariant::String));
+ QCOMPARE(s[0][0].toString(), expectedValue);
+}
+
+void tst_QDBusAbstractInterface::getComplexSignal_data()
+{
+ getVoidSignal_data();
+}
+
+void tst_QDBusAbstractInterface::getComplexSignal()
+{
+ QFETCH(QString, service);
+ QFETCH(QString, path);
+ Pinger p = getPinger(service, path);
+ QVERIFY2(p, "Not connected to D-Bus");
+
+ // we need to connect the signal somewhere in order for D-Bus to enable the rules
+ QTestEventLoop::instance().connect(p.data(), SIGNAL(complexSignal(RegisteredType)), SLOT(exitLoop()));
+ QSignalSpy s(p.data(), SIGNAL(complexSignal(RegisteredType)));
+
+ RegisteredType expectedValue("Good evening");
+ emit targetObj.complexSignal(expectedValue);
+ QTestEventLoop::instance().enterLoop(2);
+ QVERIFY(!QTestEventLoop::instance().timeout());
+
+ QVERIFY(s.size() == 1);
+ QVERIFY(s[0].size() == 1);
+ QCOMPARE(s[0][0].userType(), qMetaTypeId<RegisteredType>());
+ QCOMPARE(s[0][0].value<RegisteredType>(), expectedValue);
+}
+
+void tst_QDBusAbstractInterface::createErrors_data()
+{
+ QTest::addColumn<QString>("service");
+ QTest::addColumn<QString>("path");
+ QTest::addColumn<QString>("errorName");
+
+ QTest::newRow("invalid-service") << "this isn't valid" << "/" << "com.trolltech.QtDBus.Error.InvalidService";
+ QTest::newRow("invalid-path") << QDBusConnection::sessionBus().baseService() << "this isn't valid"
+ << "com.trolltech.QtDBus.Error.InvalidObjectPath";
+}
+
+void tst_QDBusAbstractInterface::createErrors()
+{
+ QFETCH(QString, service);
+ QFETCH(QString, path);
+ Pinger p = getPinger(service, path);
+ QVERIFY2(p, "Not connected to D-Bus");
+
+ QVERIFY(!p->isValid());
+ QTEST(p->lastError().name(), "errorName");
+}
+
+void tst_QDBusAbstractInterface::callErrors_data()
+{
+ createErrors_data();
+ QTest::newRow("service-wildcard") << QString() << "/" << "com.trolltech.QtDBus.Error.InvalidService";
+ QTest::newRow("path-wildcard") << QDBusConnection::sessionBus().baseService() << QString()
+ << "com.trolltech.QtDBus.Error.InvalidObjectPath";
+ QTest::newRow("full-wildcard") << QString() << QString() << "com.trolltech.QtDBus.Error.InvalidService";
+}
+
+void tst_QDBusAbstractInterface::callErrors()
+{
+ QFETCH(QString, service);
+ QFETCH(QString, path);
+ Pinger p = getPinger(service, path);
+ QVERIFY2(p, "Not connected to D-Bus");
+
+ // we shouldn't be able to make this call:
+ QDBusReply<QString> r = p->stringMethod();
+ QVERIFY(!r.isValid());
+ QTEST(r.error().name(), "errorName");
+ QCOMPARE(p->lastError().name(), r.error().name());
+}
+
+void tst_QDBusAbstractInterface::asyncCallErrors_data()
+{
+ callErrors_data();
+}
+
+void tst_QDBusAbstractInterface::asyncCallErrors()
+{
+ QFETCH(QString, service);
+ QFETCH(QString, path);
+ Pinger p = getPinger(service, path);
+ QVERIFY2(p, "Not connected to D-Bus");
+
+ // we shouldn't be able to make this call:
+ QDBusPendingReply<QString> r = p->stringMethod();
+ QVERIFY(r.isError());
+ QTEST(r.error().name(), "errorName");
+ QCOMPARE(p->lastError().name(), r.error().name());
+}
+
+void tst_QDBusAbstractInterface::propertyReadErrors_data()
+{
+ callErrors_data();
+}
+
+void tst_QDBusAbstractInterface::propertyReadErrors()
+{
+ QFETCH(QString, service);
+ QFETCH(QString, path);
+ Pinger p = getPinger(service, path);
+ QVERIFY2(p, "Not connected to D-Bus");
+
+ // we shouldn't be able to get this value:
+ QVariant v = p->property("stringProp");
+ QVERIFY(v.isNull());
+ QVERIFY(!v.isValid());
+ QTEST(p->lastError().name(), "errorName");
+}
+
+void tst_QDBusAbstractInterface::propertyWriteErrors_data()
+{
+ callErrors_data();
+}
+
+void tst_QDBusAbstractInterface::propertyWriteErrors()
+{
+ QFETCH(QString, service);
+ QFETCH(QString, path);
+ Pinger p = getPinger(service, path);
+ QVERIFY2(p, "Not connected to D-Bus");
+
+ // we shouldn't be able to get this value:
+ if (p->isValid())
+ QCOMPARE(int(p->lastError().type()), int(QDBusError::NoError));
+ QVERIFY(!p->setProperty("stringProp", ""));
+ QTEST(p->lastError().name(), "errorName");
+}
+
+void tst_QDBusAbstractInterface::directPropertyReadErrors_data()
+{
+ callErrors_data();
+}
+
+void tst_QDBusAbstractInterface::directPropertyReadErrors()
+{
+ QFETCH(QString, service);
+ QFETCH(QString, path);
+ Pinger p = getPinger(service, path);
+ QVERIFY2(p, "Not connected to D-Bus");
+
+ // we shouldn't be able to get this value:
+ QString v = p->stringProp();
+ QVERIFY(v.isNull());
+ QTEST(p->lastError().name(), "errorName");
+}
+
+void tst_QDBusAbstractInterface::directPropertyWriteErrors_data()
+{
+ callErrors_data();
+}
+
+void tst_QDBusAbstractInterface::directPropertyWriteErrors()
+{
+ QFETCH(QString, service);
+ QFETCH(QString, path);
+ Pinger p = getPinger(service, path);
+ QVERIFY2(p, "Not connected to D-Bus");
+
+ // we shouldn't be able to get this value:
+ // but there's no direct way of verifying that the setting failed
+ if (p->isValid())
+ QCOMPARE(int(p->lastError().type()), int(QDBusError::NoError));
+ p->setStringProp("");
+ QTEST(p->lastError().name(), "errorName");
+}
+
+QTEST_MAIN(tst_QDBusAbstractInterface)
+#include "tst_qdbusabstractinterface.moc"
diff --git a/tests/auto/qdbusinterface/tst_qdbusinterface.cpp b/tests/auto/qdbusinterface/tst_qdbusinterface.cpp
index c4d4b08..60afe4e 100644
--- a/tests/auto/qdbusinterface/tst_qdbusinterface.cpp
+++ b/tests/auto/qdbusinterface/tst_qdbusinterface.cpp
@@ -60,6 +60,9 @@ class MyObject: public QObject
Q_CLASSINFO("D-Bus Introspection", ""
" <interface name=\"com.trolltech.QtDBus.MyObject\" >\n"
" <property access=\"readwrite\" type=\"i\" name=\"prop1\" />\n"
+" <property name=\"complexProp\" type=\"ai\" access=\"readwrite\">\n"
+" <annotation name=\"com.trolltech.QtDBus.QtTypeName\" value=\"QList&lt;int&gt;\"/>\n"
+" </property>\n"
" <signal name=\"somethingHappened\" >\n"
" <arg direction=\"out\" type=\"s\" />\n"
" </signal>\n"
@@ -73,8 +76,17 @@ class MyObject: public QObject
" <arg direction=\"out\" type=\"v\" name=\"pong1\" />\n"
" <arg direction=\"out\" type=\"v\" name=\"pong2\" />\n"
" </method>\n"
+" <method name=\"ping\" >\n"
+" <arg direction=\"in\" type=\"ai\" name=\"ping\" />\n"
+" <arg direction=\"out\" type=\"ai\" name=\"ping\" />\n"
+" <annotation name=\"com.trolltech.QtDBus.QtTypeName.In0\" value=\"QList&lt;int&gt;\"/>\n"
+" <annotation name=\"com.trolltech.QtDBus.QtTypeName.Out0\" value=\"QList&lt;int&gt;\"/>\n"
+" </method>\n"
" </interface>\n"
"")
+ Q_PROPERTY(int prop1 READ prop1 WRITE setProp1)
+ Q_PROPERTY(QList<int> complexProp READ complexProp WRITE setComplexProp)
+
public:
static int callCount;
static QVariantList callArgs;
@@ -84,6 +96,30 @@ public:
subObject->setObjectName("subObject");
}
+ int m_prop1;
+ int prop1() const
+ {
+ ++callCount;
+ return m_prop1;
+ }
+ void setProp1(int value)
+ {
+ ++callCount;
+ m_prop1 = value;
+ }
+
+ QList<int> m_complexProp;
+ QList<int> complexProp() const
+ {
+ ++callCount;
+ return m_complexProp;
+ }
+ void setComplexProp(const QList<int> &value)
+ {
+ ++callCount;
+ m_complexProp = value;
+ }
+
public slots:
void ping(QDBusMessage msg)
@@ -144,8 +180,16 @@ private slots:
void introspect();
void callMethod();
void invokeMethod();
+ void invokeMethodWithReturn();
+ void invokeMethodWithMultiReturn();
+ void invokeMethodWithComplexReturn();
void signal();
+
+ void propertyRead();
+ void propertyWrite();
+ void complexPropertyRead();
+ void complexPropertyWrite();
};
void tst_QDBusInterface::initTestCase()
@@ -154,7 +198,7 @@ void tst_QDBusInterface::initTestCase()
QVERIFY(con.isConnected());
QTest::qWait(500);
- con.registerObject("/", &obj, QDBusConnection::ExportAdaptors
+ con.registerObject("/", &obj, QDBusConnection::ExportAllProperties
| QDBusConnection::ExportAllSlots
| QDBusConnection::ExportChildObjects);
}
@@ -228,11 +272,12 @@ void tst_QDBusInterface::introspect()
const QMetaObject *mo = iface.metaObject();
- QCOMPARE(mo->methodCount() - mo->methodOffset(), 3);
+ QCOMPARE(mo->methodCount() - mo->methodOffset(), 4);
QVERIFY(mo->indexOfSignal(TEST_SIGNAL_NAME "(QString)") != -1);
- QCOMPARE(mo->propertyCount() - mo->propertyOffset(), 1);
+ QCOMPARE(mo->propertyCount() - mo->propertyOffset(), 2);
QVERIFY(mo->indexOfProperty("prop1") != -1);
+ QVERIFY(mo->indexOfProperty("complexProp") != -1);
}
void tst_QDBusInterface::callMethod()
@@ -281,6 +326,87 @@ void tst_QDBusInterface::invokeMethod()
QCOMPARE(dv.variant().toString(), QString("foo"));
}
+void tst_QDBusInterface::invokeMethodWithReturn()
+{
+ QDBusConnection con = QDBusConnection::sessionBus();
+ QDBusInterface iface(QDBusConnection::sessionBus().baseService(), QLatin1String("/"),
+ TEST_INTERFACE_NAME);
+
+ // make the call without a return type
+ MyObject::callCount = 0;
+ QDBusVariant arg("foo");
+ QDBusVariant retArg;
+ QVERIFY(QMetaObject::invokeMethod(&iface, "ping", Q_RETURN_ARG(QDBusVariant, retArg), Q_ARG(QDBusVariant, arg)));
+ QCOMPARE(MyObject::callCount, 1);
+
+ // verify what the callee received
+ QCOMPARE(MyObject::callArgs.count(), 1);
+ QVariant v = MyObject::callArgs.at(0);
+ QDBusVariant dv = qdbus_cast<QDBusVariant>(v);
+ QCOMPARE(dv.variant().type(), QVariant::String);
+ QCOMPARE(dv.variant().toString(), arg.variant().toString());
+
+ // verify that we got the reply as expected
+ QCOMPARE(retArg.variant(), arg.variant());
+}
+
+void tst_QDBusInterface::invokeMethodWithMultiReturn()
+{
+ QDBusConnection con = QDBusConnection::sessionBus();
+ QDBusInterface iface(QDBusConnection::sessionBus().baseService(), QLatin1String("/"),
+ TEST_INTERFACE_NAME);
+
+ // make the call without a return type
+ MyObject::callCount = 0;
+ QDBusVariant arg("foo"), arg2("bar");
+ QDBusVariant retArg, retArg2;
+ QVERIFY(QMetaObject::invokeMethod(&iface, "ping",
+ Q_RETURN_ARG(QDBusVariant, retArg),
+ Q_ARG(QDBusVariant, arg),
+ Q_ARG(QDBusVariant, arg2),
+ Q_ARG(QDBusVariant&, retArg2)));
+ QCOMPARE(MyObject::callCount, 1);
+
+ // verify what the callee received
+ QCOMPARE(MyObject::callArgs.count(), 2);
+ QVariant v = MyObject::callArgs.at(0);
+ QDBusVariant dv = qdbus_cast<QDBusVariant>(v);
+ QCOMPARE(dv.variant().type(), QVariant::String);
+ QCOMPARE(dv.variant().toString(), arg.variant().toString());
+
+ v = MyObject::callArgs.at(1);
+ dv = qdbus_cast<QDBusVariant>(v);
+ QCOMPARE(dv.variant().type(), QVariant::String);
+ QCOMPARE(dv.variant().toString(), arg2.variant().toString());
+
+ // verify that we got the replies as expected
+ QCOMPARE(retArg.variant(), arg.variant());
+ QCOMPARE(retArg2.variant(), arg2.variant());
+}
+
+void tst_QDBusInterface::invokeMethodWithComplexReturn()
+{
+ QDBusConnection con = QDBusConnection::sessionBus();
+ QDBusInterface iface(QDBusConnection::sessionBus().baseService(), QLatin1String("/"),
+ TEST_INTERFACE_NAME);
+
+ // make the call without a return type
+ MyObject::callCount = 0;
+ QList<int> arg = QList<int>() << 42 << -47;
+ QList<int> retArg;
+ QVERIFY(QMetaObject::invokeMethod(&iface, "ping", Q_RETURN_ARG(QList<int>, retArg), Q_ARG(QList<int>, arg)));
+ QCOMPARE(MyObject::callCount, 1);
+
+ // verify what the callee received
+ QCOMPARE(MyObject::callArgs.count(), 1);
+ QVariant v = MyObject::callArgs.at(0);
+ QCOMPARE(v.userType(), qMetaTypeId<QDBusArgument>());
+ QCOMPARE(qdbus_cast<QList<int> >(v), arg);
+
+ // verify that we got the reply as expected
+ QCOMPARE(retArg, arg);
+}
+
void tst_QDBusInterface::signal()
{
QDBusConnection con = QDBusConnection::sessionBus();
@@ -322,6 +448,68 @@ void tst_QDBusInterface::signal()
}
}
+void tst_QDBusInterface::propertyRead()
+{
+ QDBusConnection con = QDBusConnection::sessionBus();
+ QDBusInterface iface(QDBusConnection::sessionBus().baseService(), QLatin1String("/"),
+ TEST_INTERFACE_NAME);
+
+ int arg = obj.m_prop1 = 42;
+ MyObject::callCount = 0;
+
+ QVariant v = iface.property("prop1");
+ QVERIFY(v.isValid());
+ QCOMPARE(v.userType(), int(QVariant::Int));
+ QCOMPARE(v.toInt(), arg);
+ QCOMPARE(MyObject::callCount, 1);
+}
+
+void tst_QDBusInterface::propertyWrite()
+{
+ QDBusConnection con = QDBusConnection::sessionBus();
+ QDBusInterface iface(QDBusConnection::sessionBus().baseService(), QLatin1String("/"),
+ TEST_INTERFACE_NAME);
+
+ int arg = 42;
+ obj.m_prop1 = 0;
+ MyObject::callCount = 0;
+
+ QVERIFY(iface.setProperty("prop1", arg));
+ QCOMPARE(MyObject::callCount, 1);
+ QCOMPARE(obj.m_prop1, arg);
+}
+
+void tst_QDBusInterface::complexPropertyRead()
+{
+ QDBusConnection con = QDBusConnection::sessionBus();
+ QDBusInterface iface(QDBusConnection::sessionBus().baseService(), QLatin1String("/"),
+ TEST_INTERFACE_NAME);
+
+ QList<int> arg = obj.m_complexProp = QList<int>() << 42 << -47;
+ MyObject::callCount = 0;
+
+ QVariant v = iface.property("complexProp");
+ QVERIFY(v.isValid());
+ QCOMPARE(v.userType(), qMetaTypeId<QList<int> >());
+ QCOMPARE(v.value<QList<int> >(), arg);
+ QCOMPARE(MyObject::callCount, 1);
+}
+
+void tst_QDBusInterface::complexPropertyWrite()
+{
+ QDBusConnection con = QDBusConnection::sessionBus();
+ QDBusInterface iface(QDBusConnection::sessionBus().baseService(), QLatin1String("/"),
+ TEST_INTERFACE_NAME);
+
+ QList<int> arg = QList<int>() << -47 << 42;
+ obj.m_complexProp.clear();
+ MyObject::callCount = 0;
+
+ QVERIFY(iface.setProperty("complexProp", qVariantFromValue(arg)));
+ QCOMPARE(MyObject::callCount, 1);
+ QCOMPARE(obj.m_complexProp, arg);
+}
+
QTEST_MAIN(tst_QDBusInterface)
#include "tst_qdbusinterface.moc"
diff --git a/tests/auto/qdbusmarshall/tst_qdbusmarshall.cpp b/tests/auto/qdbusmarshall/tst_qdbusmarshall.cpp
index e5b2ebb..e304712 100644
--- a/tests/auto/qdbusmarshall/tst_qdbusmarshall.cpp
+++ b/tests/auto/qdbusmarshall/tst_qdbusmarshall.cpp
@@ -84,12 +84,17 @@ private slots:
void sendArgument_data();
void sendArgument();
- void sendErrors();
+ void sendSignalErrors();
+ void sendCallErrors_data();
+ void sendCallErrors();
private:
QProcess proc;
};
+struct UnregisteredType { };
+Q_DECLARE_METATYPE(UnregisteredType)
+
class WaitForQPong: public QObject
{
Q_OBJECT
@@ -784,7 +789,7 @@ void tst_QDBusMarshall::sendArgument()
QCOMPARE(extracted, value);
}
-void tst_QDBusMarshall::sendErrors()
+void tst_QDBusMarshall::sendSignalErrors()
{
QDBusConnection con = QDBusConnection::sessionBus();
@@ -793,7 +798,7 @@ void tst_QDBusMarshall::sendErrors()
"signalName");
msg << qVariantFromValue(QDBusObjectPath());
- QTest::ignoreMessage(QtWarningMsg, "QDBusConnection: error: could not send signal path \"/foo\" interface \"local.interfaceName\" member \"signalName\"");
+ QTest::ignoreMessage(QtWarningMsg, "QDBusConnection: error: could not send signal path \"/foo\" interface \"local.interfaceName\" member \"signalName\": Marshalling failed: Invalid object path passed in arguments");
QVERIFY(!con.send(msg));
msg.setArguments(QVariantList());
@@ -803,9 +808,117 @@ void tst_QDBusMarshall::sendErrors()
path.setPath("abc");
msg << qVariantFromValue(path);
- QTest::ignoreMessage(QtWarningMsg, "QDBusConnection: error: could not send signal path \"/foo\" interface \"local.interfaceName\" member \"signalName\"");
+ QTest::ignoreMessage(QtWarningMsg, "QDBusConnection: error: could not send signal path \"/foo\" interface \"local.interfaceName\" member \"signalName\": Marshalling failed: Invalid object path passed in arguments");
+ QVERIFY(!con.send(msg));
+
+ QDBusSignature sig;
+ msg.setArguments(QVariantList() << qVariantFromValue(sig));
+ QTest::ignoreMessage(QtWarningMsg, "QDBusConnection: error: could not send signal path \"/foo\" interface \"local.interfaceName\" member \"signalName\": Marshalling failed: Invalid signature passed in arguments");
+ QVERIFY(!con.send(msg));
+
+ QTest::ignoreMessage(QtWarningMsg, "QDBusSignature: invalid signature \"a\"");
+ sig.setSignature("a");
+ msg.setArguments(QVariantList());
+ msg << qVariantFromValue(sig);
+ QTest::ignoreMessage(QtWarningMsg, "QDBusConnection: error: could not send signal path \"/foo\" interface \"local.interfaceName\" member \"signalName\": Marshalling failed: Invalid signature passed in arguments");
QVERIFY(!con.send(msg));
}
+void tst_QDBusMarshall::sendCallErrors_data()
+{
+ QTest::addColumn<QString>("service");
+ QTest::addColumn<QString>("path");
+ QTest::addColumn<QString>("interface");
+ QTest::addColumn<QString>("method");
+ QTest::addColumn<QVariantList>("arguments");
+ QTest::addColumn<QString>("errorName");
+ QTest::addColumn<QString>("errorMsg");
+ QTest::addColumn<QString>("ignoreMsg");
+
+ // this error comes from the bus server
+ QTest::newRow("empty-service") << "" << objectPath << interfaceName << "ping" << QVariantList()
+ << "org.freedesktop.DBus.Error.UnknownMethod"
+ << "Method \"ping\" with signature \"\" on interface \"com.trolltech.autotests.qpong\" doesn't exist\n" << (const char*)0;
+
+ QTest::newRow("invalid-service") << "this isn't valid" << objectPath << interfaceName << "ping" << QVariantList()
+ << "com.trolltech.QtDBus.Error.InvalidService"
+ << "Invalid service name: this isn't valid" << "";
+
+ QTest::newRow("empty-path") << serviceName << "" << interfaceName << "ping" << QVariantList()
+ << "com.trolltech.QtDBus.Error.InvalidObjectPath"
+ << "Object path cannot be empty" << "";
+ QTest::newRow("invalid-path") << serviceName << "//" << interfaceName << "ping" << QVariantList()
+ << "com.trolltech.QtDBus.Error.InvalidObjectPath"
+ << "Invalid object path: //" << "";
+
+ // empty interfaces are valid
+ QTest::newRow("invalid-interface") << serviceName << objectPath << "this isn't valid" << "ping" << QVariantList()
+ << "com.trolltech.QtDBus.Error.InvalidInterface"
+ << "Invalid interface class: this isn't valid" << "";
+
+ QTest::newRow("empty-method") << serviceName << objectPath << interfaceName << "" << QVariantList()
+ << "com.trolltech.QtDBus.Error.InvalidMember"
+ << "method name cannot be empty" << "";
+ QTest::newRow("invalid-method") << serviceName << objectPath << interfaceName << "this isn't valid" << QVariantList()
+ << "com.trolltech.QtDBus.Error.InvalidMember"
+ << "Invalid method name: this isn't valid" << "";
+
+ QTest::newRow("invalid-variant1") << serviceName << objectPath << interfaceName << "ping"
+ << (QVariantList() << QVariant())
+ << "org.freedesktop.DBus.Error.Failed"
+ << "Marshalling failed: Variant containing QVariant::Invalid passed in arguments"
+ << "QDBusMarshaller: cannot add an invalid QVariant";
+ QTest::newRow("invalid-variant1") << serviceName << objectPath << interfaceName << "ping"
+ << (QVariantList() << qVariantFromValue(QDBusVariant()))
+ << "org.freedesktop.DBus.Error.Failed"
+ << "Marshalling failed: Variant containing QVariant::Invalid passed in arguments"
+ << "QDBusMarshaller: cannot add a null QDBusVariant";
+
+ QTest::newRow("builtin-unregistered") << serviceName << objectPath << interfaceName << "ping"
+ << (QVariantList() << QLocale::c())
+ << "org.freedesktop.DBus.Error.Failed"
+ << "Marshalling failed: Unregistered type QLocale passed in arguments"
+ << "QDBusMarshaller: type `QLocale' (18) is not registered with D-BUS. Use qDBusRegisterMetaType to register it";
+
+ // this type is known to the meta type system, but not registered with D-Bus
+ qRegisterMetaType<UnregisteredType>();
+ QTest::newRow("extra-unregistered") << serviceName << objectPath << interfaceName << "ping"
+ << (QVariantList() << qVariantFromValue(UnregisteredType()))
+ << "org.freedesktop.DBus.Error.Failed"
+ << "Marshalling failed: Unregistered type UnregisteredType passed in arguments"
+ << QString("QDBusMarshaller: type `UnregisteredType' (%1) is not registered with D-BUS. Use qDBusRegisterMetaType to register it")
+ .arg(qMetaTypeId<UnregisteredType>());
+}
+
+void tst_QDBusMarshall::sendCallErrors()
+{
+ QDBusConnection con = QDBusConnection::sessionBus();
+ QVERIFY(con.isConnected());
+
+ QFETCH(QString, service);
+ QFETCH(QString, path);
+ QFETCH(QString, interface);
+ QFETCH(QString, method);
+ QFETCH(QVariantList, arguments);
+ QFETCH(QString, errorMsg);
+
+ QFETCH(QString, ignoreMsg);
+ if (!ignoreMsg.isEmpty())
+ QTest::ignoreMessage(QtWarningMsg, ignoreMsg.toLatin1());
+ if (!ignoreMsg.isNull())
+ QTest::ignoreMessage(QtWarningMsg,
+ QString("QDBusConnection: error: could not send message to service \"%1\" path \"%2\" interface \"%3\" member \"%4\": %5")
+ .arg(service, path, interface, method, errorMsg)
+ .toLatin1());
+
+ QDBusMessage msg = QDBusMessage::createMethodCall(service, path, interface, method);
+ msg.setArguments(arguments);
+
+ QDBusMessage reply = con.call(msg, QDBus::Block);
+ QCOMPARE(reply.type(), QDBusMessage::ErrorMessage);
+ QTEST(reply.errorName(), "errorName");
+ QCOMPARE(reply.errorMessage(), errorMsg);
+}
+
QTEST_MAIN(tst_QDBusMarshall)
#include "tst_qdbusmarshall.moc"
diff --git a/tools/qdbus/qdbusxml2cpp/qdbusxml2cpp.cpp b/tools/qdbus/qdbusxml2cpp/qdbusxml2cpp.cpp
index 5d1ac32..b8b9338 100644
--- a/tools/qdbus/qdbusxml2cpp/qdbusxml2cpp.cpp
+++ b/tools/qdbus/qdbusxml2cpp/qdbusxml2cpp.cpp
@@ -613,18 +613,15 @@ static void writeProxy(const QString &filename, const QDBusIntrospection::Interf
// getter:
if (property.access != QDBusIntrospection::Property::Write) {
- hs << " inline " << type << " " << getter << "() const" << endl;
- if (type != "QVariant")
- hs << " { return qvariant_cast< " << type << " >(internalPropGet(\""
- << property.name << "\")); }" << endl;
- else
- hs << " { return internalPropGet(\"" << property.name << "\"); }" << endl;
+ hs << " inline " << type << " " << getter << "() const" << endl
+ << " { return qvariant_cast< " << type << " >(property(\""
+ << property.name << "\")); }" << endl;
}
// setter:
if (property.access != QDBusIntrospection::Property::Read) {
hs << " inline void " << setter << "(" << constRefArg(type) << "value)" << endl
- << " { internalPropSet(\"" << property.name
+ << " { setProperty(\"" << property.name
<< "\", qVariantFromValue(value)); }" << endl;
}