+2006-04-29 Thiago Macieira <thiago.macieira@trolltech.com>
+
+ * qt/qdbusinterface.h: Rename QDBusRef to QDBusInterfacePtr
+ and disable the copy operators. (r533772, r534746)
+
+ * qt/qdbuserror.h: Remove the automatic cast to bool. (r533929)
+
+ * qt/qdbusabstractinterface.cpp:
+ * qt/qdbusabstractinterface.h: Change the default call mode to
+ not use the event loop. Add convenience call() methods that
+ take a CallMode parameter. (r534042)
+
+ * qt/qdbusconnection.h: Change the default call mode to not
+ use the event loop. (r534042)
+
+ * qt/qdbusinterface.cpp:
+ * qt/qdbusinterface.h: Add a method to tell us if the
+ interface is valid (since we don't return a null pointer
+ anymore) (r534099)
+
+ * qt/qdbusinterface_p.h: Don't crash if metaObject is 0
+ (r534101)
+
+ * qt/qdbusinternalfilters.cpp: Decouple the introspection
+ function in two so taht we get the chance to introspect
+ without having a QDBusMessage (r534102)
+
+ * qt/qdbusbus.h:
+ * qt/qdbusconnection.cpp:
+ * qt/qdbusconnection_p.h:
+ * qt/qdbusintegrator.cpp: Keep a list of our own names to
+ avoid a round-trip to the server when attempting to introspect
+ one of our own objects. Also make sure the filter functions
+ match the empty interface as well. (r534108)
+ Don't keep the connection names. Instead, trust the unique
+ connection name (r534111)
+ Remove event loop usage (r534112)
+
2006-04-29 Thiago Macieira <thiago.macieira@trolltech.com>
* qt/qdbusintegrator.cpp: Fix assertion failure spotted by
if (mode == AutoDetect) {
// determine if this a sync or async call
- mode = UseEventLoop;
+ mode = NoUseEventLoop;
const QMetaObject *mo = metaObject();
QByteArray match = method.toLatin1() + '(';
{
return callWithArgs(m);
}
+
+ inline QDBusMessage call(CallMode mode, const QString &m)
+ {
+ return callWithArgs(m, QList<QVariant>(), mode);
+ }
#ifndef Q_QDOC
private:
<< qvfv(t7) << qvfv(t8);
return callWithArgs(m, args);
}
+
+ template<typename T1>
+ inline QDBusMessage call(CallMode mode, const QString &m, const T1 &t1)
+ {
+ QList<QVariant> args;
+ args << qvfv(t1);
+ return callWithArgs(m, args, mode);
+ }
+
+ template<typename T1, typename T2>
+ inline QDBusMessage call(CallMode mode, const QString &m, const T1 &t1, const T2 &t2)
+ {
+ QList<QVariant> args;
+ args << qvfv(t1) << qvfv(t2);
+ return callWithArgs(m, args, mode);
+ }
+
+ template<typename T1, typename T2, typename T3>
+ inline QDBusMessage call(CallMode mode, const QString &m, const T1 &t1, const T2 &t2,
+ const T3 &t3)
+ {
+ QList<QVariant> args;
+ args << qvfv(t1) << qvfv(t2) << qvfv(t3);
+ return callWithArgs(m, args, mode);
+ }
+
+ template<typename T1, typename T2, typename T3, typename T4>
+ inline QDBusMessage call(CallMode mode, const QString &m, const T1 &t1, const T2 &t2,
+ const T3 &t3, const T4 &t4)
+ {
+ QList<QVariant> args;
+ args << qvfv(t1) << qvfv(t2) << qvfv(t3)
+ << qvfv(t4);
+ return callWithArgs(m, args, mode);
+ }
+
+ template<typename T1, typename T2, typename T3, typename T4, typename T5>
+ inline QDBusMessage call(CallMode mode, const QString &m, const T1 &t1, const T2 &t2,
+ const T3 &t3, const T4 &t4, const T5 &t5)
+ {
+ QList<QVariant> args;
+ args << qvfv(t1) << qvfv(t2) << qvfv(t3)
+ << qvfv(t4) << qvfv(t5);
+ return callWithArgs(m, args, mode);
+ }
+
+ template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6>
+ inline QDBusMessage call(CallMode mode, const QString &m, const T1 &t1, const T2 &t2,
+ const T3 &t3, const T4 &t4, const T5 &t5, const T6 &t6)
+ {
+ QList<QVariant> args;
+ args << qvfv(t1) << qvfv(t2) << qvfv(t3)
+ << qvfv(t4) << qvfv(t5) << qvfv(t6);
+ return callWithArgs(m, args, mode);
+ }
+
+ template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7>
+ inline QDBusMessage call(CallMode mode, const QString &m, const T1 &t1, const T2 &t2,
+ const T3 &t3, const T4 &t4, const T5 &t5, const T6 &t6, const T7 &t7)
+ {
+ QList<QVariant> args;
+ args << qvfv(t1) << qvfv(t2) << qvfv(t3)
+ << qvfv(t4) << qvfv(t5) << qvfv(t6)
+ << qvfv(t7);
+ return callWithArgs(m, args, mode);
+ }
+
+ template<typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8>
+ inline QDBusMessage call(CallMode mode, const QString &m, const T1 &t1, const T2 &t2,
+ const T3 &t3, const T4 &t4, const T5 &t5, const T6 &t6, const T7 &t7,
+ const T8 &t8)
+ {
+ QList<QVariant> args;
+ args << qvfv(t1) << qvfv(t2) << qvfv(t3)
+ << qvfv(t4) << qvfv(t5) << qvfv(t6)
+ << qvfv(t7) << qvfv(t8);
+ return callWithArgs(m, args, mode);
+ }
#endif
protected:
signals:
void nameAcquired(const QString &service);
void nameLost(const QString &service);
- void nameOwnerChanged(const QString &name, const QString &oldOwner, const QString &newOwner);
+ void nameOwnerChanged(const QString &name, const QString &oldOwner, const QString &newOwner);
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QDBusBusService::RequestNameOptions);
QDBusError lastError() const;
bool send(const QDBusMessage &message) const;
- QDBusMessage sendWithReply(const QDBusMessage &message, WaitMode mode = UseEventLoop) const;
+ QDBusMessage sendWithReply(const QDBusMessage &message, WaitMode mode = NoUseEventLoop) const;
int sendWithReplyAsync(const QDBusMessage &message, QObject *receiver,
const char *slot) const;
extern bool qDBusCheckAsyncTag(const char *tag);
// in qdbusinternalfilters.cpp
+extern QString qDBusIntrospectObject(const QDBusConnectionPrivate::ObjectTreeNode *node);
extern void qDBusIntrospectObject(const QDBusConnectionPrivate::ObjectTreeNode *node,
const QDBusMessage &msg);
extern void qDBusPropertyGet(const QDBusConnectionPrivate::ObjectTreeNode *node,
{
// object may be null
- if (msg.interface() == QLatin1String(DBUS_INTERFACE_INTROSPECTABLE)) {
+ if (msg.interface().isEmpty() || msg.interface() == QLatin1String(DBUS_INTERFACE_INTROSPECTABLE)) {
if (msg.method() == QLatin1String("Introspect") && msg.signature().isEmpty())
qDBusIntrospectObject(node, msg);
return true;
}
- if (node->obj && msg.interface() == QLatin1String(DBUS_INTERFACE_PROPERTIES)) {
+ if (node->obj && (msg.interface().isEmpty() ||
+ msg.interface() == QLatin1String(DBUS_INTERFACE_PROPERTIES))) {
if (msg.method() == QLatin1String("Get") && msg.signature() == QLatin1String("ss"))
qDBusPropertyGet(node, msg);
else if (msg.method() == QLatin1String("Set") && msg.signature() == QLatin1String("ssv"))
return false;
}
-bool QDBusConnectionPrivate::handleObjectCall(const QDBusMessage &msg)
+template<typename Func>
+static bool applyForObject(QDBusConnectionPrivate::ObjectTreeNode *root, const QString &fullpath,
+ Func& functor)
{
- QReadLocker locker(&lock);
-
// walk the object tree
- QStringList path = msg.path().split(QLatin1Char('/'));
+ QStringList path = fullpath.split(QLatin1Char('/'));
if (path.last().isEmpty())
path.removeLast(); // happens if path is "/"
int i = 1;
- ObjectTreeNode *node = &rootNode;
+ QDBusConnectionPrivate::ObjectTreeNode *node = root;
// try our own tree first
while (node && !(node->flags & QDBusConnection::ExportChildObjects) ) {
if (i == path.count()) {
// found our object
- return activateObject(node, msg);
+ functor(node);
+ return true;
}
- QVector<ObjectTreeNode::Data>::ConstIterator it =
+ QVector<QDBusConnectionPrivate::ObjectTreeNode::Data>::ConstIterator it =
qLowerBound(node->children.constBegin(), node->children.constEnd(), path.at(i));
if (it != node->children.constEnd() && it->name == path.at(i))
// match
while (obj) {
if (i == path.count()) {
// we're at the correct level
- ObjectTreeNode fakenode(*node);
+ QDBusConnectionPrivate::ObjectTreeNode fakenode(*node);
fakenode.obj = obj;
- return activateObject(&fakenode, msg);
+ functor(&fakenode);
+ return true;
}
const QObjectList &children = obj->children();
}
}
+ // object not found
+ return false;
+}
+
+struct qdbus_activateObject
+{
+ QDBusConnectionPrivate *self;
+ const QDBusMessage &msg;
+ bool returnVal;
+ inline qdbus_activateObject(QDBusConnectionPrivate *s, const QDBusMessage &m)
+ : self(s), msg(m)
+ { }
+
+ inline void operator()(QDBusConnectionPrivate::ObjectTreeNode *node)
+ { returnVal = self->activateObject(node, msg); }
+};
+
+bool QDBusConnectionPrivate::handleObjectCall(const QDBusMessage &msg)
+{
+ QReadLocker locker(&lock);
+
+ qdbus_activateObject apply(this, msg);
+ if (applyForObject(&rootNode, msg.path(), apply))
+ return apply.returnVal;
+
qDebug("Call failed: no object found at %s", qPrintable(msg.path()));
return false;
}
QString owner = getNameOwner(service);
if (connection && !owner.isEmpty() && QDBusUtil::isValidObjectPath(path) &&
(interface.isEmpty() || QDBusUtil::isValidInterfaceName(interface)))
+ // always call here with the unique connection name
mo = findMetaObject(owner, path, interface);
QDBusInterfacePrivate *p = new QDBusInterfacePrivate(QDBusConnection(name), this, owner, path, interface, mo);
return p;
}
+struct qdbus_Introspect
+{
+ QString xml;
+ inline void operator()(QDBusConnectionPrivate::ObjectTreeNode *node)
+ { xml = qDBusIntrospectObject(node); }
+};
+
QDBusMetaObject *
QDBusConnectionPrivate::findMetaObject(const QString &service, const QString &path,
const QString &interface)
{
+ // service must be a unique connection name
if (!interface.isEmpty()) {
QReadLocker locker(&lock);
QDBusMetaObject *mo = cachedMetaObjects.value(interface, 0);
if (mo)
return mo;
}
+ if (service == QString::fromUtf8(dbus_bus_get_unique_name(connection))) {
+ // it's one of our own
+ QWriteLocker locker(&lock);
+ QDBusMetaObject *mo = 0;
+ if (!interface.isEmpty())
+ mo = cachedMetaObjects.value(interface, 0);
+ if (mo)
+ // maybe it got created when we switched from read to write lock
+ return mo;
+
+ qdbus_Introspect apply;
+ if (!applyForObject(&rootNode, path, apply)) {
+ lastError = QDBusError(QDBusError::InvalidArgs,
+ QString(QLatin1String("No object at %1")).arg(path));
+ return 0; // no object at path
+ }
+
+ // release the lock and return
+ return QDBusMetaObject::createMetaObject(interface, apply.xml, cachedMetaObjects, lastError);
+ }
- // introspect the target object:
+ // not local: introspect the target object:
QDBusMessage msg = QDBusMessage::methodCall(service, path,
QLatin1String(DBUS_INTERFACE_INTROSPECTABLE),
QLatin1String("Introspect"));
- // we have to spin the event loop because the call could be targetting ourselves
- QDBusMessage reply = sendWithReply(msg, QDBusConnection::UseEventLoop);
+
+ QDBusMessage reply = sendWithReply(msg, QDBusConnection::NoUseEventLoop);
// it doesn't exist yet, we have to create it
QWriteLocker locker(&lock);
// resources are freed in QDBusInterfacePrivate::~QDBusInterfacePrivate()
}
+/*!
+ Returns true if this is a valid reference to a remote object. It returns false if
+ there was an error during the creation of this interface (for instance, if the remote
+ application does not exist).
+
+ Note: when dealing with remote objects, it is not always possible to determine if it
+ exists when creating a QDBusInterface or QDBusInterfacePtr object.
+*/
+bool QDBusInterface::isValid() const
+{
+ return d_func()->isValid;
+}
+
/*!
\internal
Overrides QObject::metaObject to return our own copy.
return id;
}
-QDBusRef::QDBusRef(QDBusConnection &conn, const QString &service, const QString &path,
+QDBusInterfacePtr::QDBusInterfacePtr(QDBusConnection &conn, const QString &service, const QString &path,
const QString &interface)
: d(conn.findInterface(service, path, interface))
{
}
-QDBusRef::QDBusRef(const QString &service, const QString &path, const QString &interface)
+QDBusInterfacePtr::QDBusInterfacePtr(const QString &service, const QString &path, const QString &interface)
: d(QDBus::sessionBus().findInterface(service, path, interface))
{
}
public:
~QDBusInterface();
+ bool isValid() const;
+
virtual const QMetaObject *metaObject() const;
virtual void *qt_metacast(const char *);
virtual int qt_metacall(QMetaObject::Call, int, void **);
Q_DECLARE_PRIVATE(QDBusInterface);
};
-struct QDBUS_EXPORT QDBusRef
+struct QDBUS_EXPORT QDBusInterfacePtr
{
- QDBusRef(QDBusConnection &conn, const QString &service, const QString &path,
+ QDBusInterfacePtr(QDBusInterface *iface) : d(iface) { }
+ QDBusInterfacePtr(QDBusConnection &conn, const QString &service, const QString &path,
const QString &interface = QString());
- QDBusRef(const QString &service, const QString &path, const QString &interface = QString());
- ~QDBusRef() { delete d; }
+ QDBusInterfacePtr(const QString &service, const QString &path, const QString &interface = QString());
+ ~QDBusInterfacePtr() { delete d; }
- QDBusInterface* operator->() const { return d; }
+ QDBusInterface *interface() { return d; }
+ QDBusInterface *operator->() { return d; }
private:
QDBusInterface *const d;
+ Q_DISABLE_COPY(QDBusInterfacePtr)
};
#endif
}
~QDBusInterfacePrivate()
{
- if (!metaObject->cached)
+ if (metaObject && !metaObject->cached)
delete metaObject;
}
return retval;
}
-void qDBusIntrospectObject(const QDBusConnectionPrivate::ObjectTreeNode *node,
- const QDBusMessage &msg)
+QString qDBusIntrospectObject(const QDBusConnectionPrivate::ObjectTreeNode *node)
{
// object may be null
}
xml_data += QLatin1String("</node>\n");
+ return xml_data;
+}
+void qDBusIntrospectObject(const QDBusConnectionPrivate::ObjectTreeNode *node,
+ const QDBusMessage &msg)
+{
// now send it
QDBusMessage reply = QDBusMessage::methodReply(msg);
- reply << xml_data;
+ reply << qDBusIntrospectObject(node);
msg.connection().send(reply);
}