diff options
Diffstat (limited to 'src/dbus')
-rw-r--r-- | src/dbus/doc/qtdbus.qdocconf | 2 | ||||
-rw-r--r-- | src/dbus/qdbusargument.h | 17 | ||||
-rw-r--r-- | src/dbus/qdbusconnection.cpp | 47 | ||||
-rw-r--r-- | src/dbus/qdbusconnection_p.h | 8 | ||||
-rw-r--r-- | src/dbus/qdbusintegrator.cpp | 82 | ||||
-rw-r--r-- | src/dbus/qdbuspendingreply.cpp | 28 | ||||
-rw-r--r-- | src/dbus/qdbuspendingreply.h | 4 |
7 files changed, 134 insertions, 54 deletions
diff --git a/src/dbus/doc/qtdbus.qdocconf b/src/dbus/doc/qtdbus.qdocconf index 7a58dada63..1ff4c0d6c7 100644 --- a/src/dbus/doc/qtdbus.qdocconf +++ b/src/dbus/doc/qtdbus.qdocconf @@ -36,7 +36,7 @@ qhp.qtdbus.file = qtdbus.qhp # Namespace for the output file. This namespace is used to distinguish between # different documentation files in Creator/Assistant. -qhp.qtdbus.namespace = org.qt-project.qtdbus.501 +qhp.qtdbus.namespace = org.qt-project.qtdbus.510 # Title for the package, will be the main title for the package in # Assistant/Creator. diff --git a/src/dbus/qdbusargument.h b/src/dbus/qdbusargument.h index c0bce586ac..dc79843d1e 100644 --- a/src/dbus/qdbusargument.h +++ b/src/dbus/qdbusargument.h @@ -397,6 +397,23 @@ inline QDBusArgument &operator<<(QDBusArgument &arg, const QVariantHash &map) return arg; } +template <typename T1, typename T2> +inline QDBusArgument &operator<<(QDBusArgument &arg, const QPair<T1, T2> &pair) +{ + arg.beginStructure(); + arg << pair.first << pair.second; + arg.endStructure(); + return arg; +} + +template <typename T1, typename T2> +inline const QDBusArgument &operator>>(const QDBusArgument &arg, QPair<T1, T2> &pair) +{ + arg.beginStructure(); + arg >> pair.first >> pair.second; + arg.endStructure(); + return arg; +} QT_END_NAMESPACE diff --git a/src/dbus/qdbusconnection.cpp b/src/dbus/qdbusconnection.cpp index d576112f8d..74a3a752a5 100644 --- a/src/dbus/qdbusconnection.cpp +++ b/src/dbus/qdbusconnection.cpp @@ -803,13 +803,8 @@ bool QDBusConnection::registerObject(const QString &path, QObject *object, Regis return false; if (options & QDBusConnectionPrivate::VirtualObject) { - // technically the check for children needs to go even deeper - if (options & SubPath) { - foreach (const QDBusConnectionPrivate::ObjectTreeNode &child, node->children) { - if (child.obj) - return false; - } - } + if (options & SubPath && node->activeChildren) + return false; } else { if ((options & ExportChildObjects && !node->children.isEmpty())) return false; @@ -825,8 +820,8 @@ bool QDBusConnection::registerObject(const QString &path, QObject *object, Regis // if a virtual object occupies this path, return false if (node->obj && (node->flags & QDBusConnectionPrivate::VirtualObject) && (node->flags & QDBusConnection::SubPath)) { - qDebug("Cannot register object at %s because QDBusVirtualObject handles all sub-paths.", - qPrintable(path)); + //qDebug("Cannot register object at %s because QDBusVirtualObject handles all sub-paths.", + // qPrintable(path)); return false; } @@ -840,12 +835,13 @@ bool QDBusConnection::registerObject(const QString &path, QObject *object, Regis // are we allowed to go deeper? if (node->flags & ExportChildObjects) { // we're not - qDebug("Cannot register object at %s because %s exports its own child objects", - qPrintable(path), qPrintable(pathComponents.at(i))); + //qDebug("Cannot register object at %s because %s exports its own child objects", + // qPrintable(path), qPrintable(pathComponents.at(i))); return false; } } else { // add entry + ++node->activeChildren; node = node->children.insert(it, pathComponents.at(i)); } @@ -883,35 +879,8 @@ void QDBusConnection::unregisterObject(const QString &path, UnregisterMode mode) if (!d || !d->connection || !QDBusUtil::isValidObjectPath(path)) return; - QStringList pathComponents = path.split(QLatin1Char('/')); QDBusWriteLocker locker(UnregisterObjectAction, d); - QDBusConnectionPrivate::ObjectTreeNode *node = &d->rootNode; - int i = 1; - - // find the object - while (node) { - if (pathComponents.count() == i || !path.compare(QLatin1String("/"))) { - // found it - node->obj = 0; - node->flags = 0; - - if (mode == UnregisterTree) { - // clear the sub-tree as well - node->children.clear(); // can't disconnect the objects because we really don't know if they can - // be found somewhere else in the path too - } - - return; - } - - QDBusConnectionPrivate::ObjectTreeNode::DataList::Iterator it = - std::lower_bound(node->children.begin(), node->children.end(), pathComponents.at(i)); - if (it == node->children.end() || it->name != pathComponents.at(i)) - break; // node not found - - node = it; - ++i; - } + d->unregisterObject(path, mode); } /*! diff --git a/src/dbus/qdbusconnection_p.h b/src/dbus/qdbusconnection_p.h index 2c3ddefc50..bef0b88f78 100644 --- a/src/dbus/qdbusconnection_p.h +++ b/src/dbus/qdbusconnection_p.h @@ -140,14 +140,16 @@ public: { typedef QVector<ObjectTreeNode> DataList; - inline ObjectTreeNode() : obj(0), flags(0) { } + inline ObjectTreeNode() : obj(0), flags(0), activeChildren(0) { } inline ObjectTreeNode(const QString &n) // intentionally implicit - : name(n), obj(0), flags(0) { } + : name(n), obj(0), flags(0), activeChildren(0) { } inline ~ObjectTreeNode() { } inline bool operator<(const QString &other) const { return name < other; } inline bool operator<(const QStringRef &other) const { return QStringRef(&name) < other; } + inline bool isActive() const + { return obj || activeChildren; } QString name; union { @@ -155,6 +157,7 @@ public: QDBusVirtualObject *treeNode; }; int flags; + int activeChildren; DataList children; }; @@ -208,6 +211,7 @@ public: const QString &name, const QStringList &argumentMatch, const QString &signature, QObject *receiver, const char *slot); void registerObject(const ObjectTreeNode *node); + void unregisterObject(const QString &path, QDBusConnection::UnregisterMode mode); void connectRelay(const QString &service, const QString &path, const QString &interface, QDBusAbstractInterface *receiver, const QMetaMethod &signal); diff --git a/src/dbus/qdbusintegrator.cpp b/src/dbus/qdbusintegrator.cpp index 1cf9de5610..90f011de54 100644 --- a/src/dbus/qdbusintegrator.cpp +++ b/src/dbus/qdbusintegrator.cpp @@ -587,17 +587,76 @@ bool QDBusConnectionPrivate::handleMessage(const QDBusMessage &amsg) return false; } +static void garbageCollectChildren(QDBusConnectionPrivate::ObjectTreeNode &node) +{ + int size = node.children.count(); + if (node.activeChildren == 0) { + // easy case + node.children.clear(); + } else if (size > node.activeChildren * 3 || (size > 20 && size * 2 > node.activeChildren * 3)) { + // rewrite the vector, keeping only the active children + // if the vector is large (> 20 items) and has one third of inactives + // or if the vector is small and has two thirds of inactives. + QDBusConnectionPrivate::ObjectTreeNode::DataList::Iterator end = node.children.end(); + QDBusConnectionPrivate::ObjectTreeNode::DataList::Iterator it = node.children.begin(); + QDBusConnectionPrivate::ObjectTreeNode::DataList::Iterator tgt = it; + for ( ; it != end; ++it) { + if (it->isActive()) + *tgt++ = qMove(*it); + } + ++tgt; + node.children.erase(tgt, end); + } +} + static void huntAndDestroy(QObject *needle, QDBusConnectionPrivate::ObjectTreeNode &haystack) { QDBusConnectionPrivate::ObjectTreeNode::DataList::Iterator it = haystack.children.begin(); QDBusConnectionPrivate::ObjectTreeNode::DataList::Iterator end = haystack.children.end(); - for ( ; it != end; ++it) + for ( ; it != end; ++it) { + if (!it->isActive()) + continue; huntAndDestroy(needle, *it); + if (!it->isActive()) + --haystack.activeChildren; + } if (needle == haystack.obj) { haystack.obj = 0; haystack.flags = 0; } + + garbageCollectChildren(haystack); +} + +static void huntAndUnregister(const QStringList &pathComponents, int i, QDBusConnection::UnregisterMode mode, + QDBusConnectionPrivate::ObjectTreeNode *node) +{ + if (pathComponents.count() == i) { + // found it + node->obj = 0; + node->flags = 0; + + if (mode == QDBusConnection::UnregisterTree) { + // clear the sub-tree as well + node->activeChildren = 0; + node->children.clear(); // can't disconnect the objects because we really don't know if they can + // be found somewhere else in the path too + } + } else { + // keep going + QDBusConnectionPrivate::ObjectTreeNode::DataList::Iterator end = node->children.end(); + QDBusConnectionPrivate::ObjectTreeNode::DataList::Iterator it = + std::lower_bound(node->children.begin(), end, pathComponents.at(i)); + if (it == end || it->name != pathComponents.at(i) || !it->isActive()) + return; // node not found + + huntAndUnregister(pathComponents, i + 1, mode, it); + if (!it->isActive()) + --node->activeChildren; + + garbageCollectChildren(*node); + } } static void huntAndEmit(DBusConnection *connection, DBusMessage *msg, @@ -606,8 +665,10 @@ static void huntAndEmit(DBusConnection *connection, DBusMessage *msg, { QDBusConnectionPrivate::ObjectTreeNode::DataList::ConstIterator it = haystack.children.constBegin(); QDBusConnectionPrivate::ObjectTreeNode::DataList::ConstIterator end = haystack.children.constEnd(); - for ( ; it != end; ++it) - huntAndEmit(connection, msg, needle, *it, isScriptable, isAdaptor, path + QLatin1Char('/') + it->name); + for ( ; it != end; ++it) { + if (it->isActive()) + huntAndEmit(connection, msg, needle, *it, isScriptable, isAdaptor, path + QLatin1Char('/') + it->name); + } if (needle == haystack.obj) { // is this a signal we should relay? @@ -2249,6 +2310,21 @@ void QDBusConnectionPrivate::registerObject(const ObjectTreeNode *node) } } +void QDBusConnectionPrivate::unregisterObject(const QString &path, QDBusConnection::UnregisterMode mode) +{ + QDBusConnectionPrivate::ObjectTreeNode *node = &rootNode; + QStringList pathComponents; + int i; + if (path == QLatin1String("/")) { + i = 0; + } else { + pathComponents = path.split(QLatin1Char('/')); + i = 1; + } + + huntAndUnregister(pathComponents, i, mode, node); +} + void QDBusConnectionPrivate::connectRelay(const QString &service, const QString &path, const QString &interface, QDBusAbstractInterface *receiver, diff --git a/src/dbus/qdbuspendingreply.cpp b/src/dbus/qdbuspendingreply.cpp index cf99bb692c..c0e24bee06 100644 --- a/src/dbus/qdbuspendingreply.cpp +++ b/src/dbus/qdbuspendingreply.cpp @@ -185,6 +185,11 @@ function's return value is undefined (will probably cause an assertion failure), so it is important to verify that the processing is finished and the reply is valid. + + If the reply does not contain an argument at position \a index or if the + reply was an error, this function returns an invalid QVariant. Since D-Bus + messages can never contain invalid QVariants, this return can be used to + detect an error condition. */ /*! @@ -197,6 +202,11 @@ Note that, if the reply hasn't arrived, this function causes the calling thread to block until the reply is processed. + + If the reply does not contain an argument at position \c Index or if the + reply was an error, this function returns a \c Type object that is default + constructed, which may be indistinguishable from a valid value. To reliably + determine whether the message was an error, use isError(). */ /*! @@ -211,6 +221,10 @@ Note that, if the reply hasn't arrived, this function causes the calling thread to block until the reply is processed. + + If the reply is an error reply, this function returns a default-constructed + \c T1 object, which may be indistinguishable from a valid value. To + reliably determine whether the message was an error, use isError(). */ /*! @@ -225,6 +239,10 @@ Note that, if the reply hasn't arrived, this function causes the calling thread to block until the reply is processed. + + If the reply is an error reply, this function returns a default-constructed + \c T1 object, which may be indistinguishable from a valid value. To + reliably determine whether the message was an error, use isError(). */ /*! @@ -260,14 +278,12 @@ void QDBusPendingReplyData::assign(const QDBusMessage &message) QVariant QDBusPendingReplyData::argumentAt(int index) const { - if (d) - d->waitForFinished(); // bypasses "const" + if (!d) + return QVariant(); - Q_ASSERT_X(d && index >= 0 && index < d->replyMessage.arguments().count(), - "QDBusPendingReply::argumentAt", - "Index out of bounds"); + d->waitForFinished(); // bypasses "const" - return d->replyMessage.arguments().at(index); + return d->replyMessage.arguments().value(index); } void QDBusPendingReplyData::setMetaTypes(int count, const int *types) diff --git a/src/dbus/qdbuspendingreply.h b/src/dbus/qdbuspendingreply.h index 89cd846bf8..c7a030d78f 100644 --- a/src/dbus/qdbuspendingreply.h +++ b/src/dbus/qdbuspendingreply.h @@ -168,9 +168,7 @@ public: template<int Index> inline const typename Select<Index>::Type argumentAt() const { - // static assert? - Q_ASSERT_X(Index < count() && Index >= 0, "QDBusPendingReply::argumentAt", - "Index out of bounds"); + Q_STATIC_ASSERT_X(Index >= 0 && Index < Count, "Index out of bounds"); typedef typename Select<Index>::Type ResultType; return qdbus_cast<ResultType>(argumentAt(Index), 0); } |