diff -ur libdbus-1-qt3-0.8.1/qdbusintegrator.cpp ../dbus-qt4-qt3backport/qdbusintegrator.cpp --- libdbus-1-qt3-0.8.1/qdbusintegrator.cpp 2007-12-17 12:34:08.000000000 +0100 +++ ../dbus-qt4-qt3backport/qdbusintegrator.cpp 2008-03-13 10:28:54.000000000 +0100 @@ -121,7 +121,7 @@ QDBusConnectionPrivate *d = static_cast<QDBusConnectionPrivate *>(data); int flags = dbus_watch_get_flags(watch); - int fd = dbus_watch_get_fd(watch); + int fd = dbus_watch_get_unix_fd(watch); QDBusConnectionPrivate::Watcher watcher; if (flags & DBUS_WATCH_READABLE) { @@ -163,7 +163,7 @@ //qDebug("remove watch"); QDBusConnectionPrivate *d = static_cast<QDBusConnectionPrivate *>(data); - int fd = dbus_watch_get_fd(watch); + int fd = dbus_watch_get_unix_fd(watch); QDBusConnectionPrivate::WatcherHash::iterator it = d->watchers.find(fd); if (it != d->watchers.end()) @@ -205,7 +205,7 @@ //qDebug("toggle watch"); QDBusConnectionPrivate *d = static_cast<QDBusConnectionPrivate *>(data); - int fd = dbus_watch_get_fd(watch); + int fd = dbus_watch_get_unix_fd(watch); QDBusConnectionPrivate::WatcherHash::iterator it = d->watchers.find(fd); if (it != d->watchers.end()) { @@ -218,7 +218,7 @@ int flags = dbus_watch_get_flags(watch); // qDebug("toggle watch %d to %d (write: %d, read: %d)", -// dbus_watch_get_fd(watch), enabled, +// dbus_watch_get_unix_fd(watch), enabled, // flags & DBUS_WATCH_WRITABLE, flags & DBUS_WATCH_READABLE); if (flags & DBUS_WATCH_READABLE && (*wit).read) diff -ur libdbus-1-qt3-0.8.1/tools/dbusxml2qt3/classgen.cpp ../dbus-qt4-qt3backport/tools/dbusxml2qt3/classgen.cpp --- libdbus-1-qt3-0.8.1/tools/dbusxml2qt3/classgen.cpp 2007-12-17 12:34:08.000000000 +0100 +++ ../dbus-qt4-qt3backport/tools/dbusxml2qt3/classgen.cpp 2008-03-13 10:28:54.000000000 +0100 @@ -38,6 +38,11 @@ insert(key, true); } + void removeString(const QString& key) + { + erase(key); + } + void insertStringList(const QStringList& list) { QStringList::const_iterator it = list.begin(); @@ -194,6 +199,14 @@ forwards.insertString("class QDomElement"); if (!classData.signals.isEmpty()) forwards.insertString("class QString"); + if (!classData.asyncMethods.isEmpty()) + { + includes["Qt"].insertString("<qmap.h>"); + forwards.erase("template <typename K, typename V> class QMap"); + + includes["qdbus"].insertString("<dbus/qdbusmessage.h>"); + forwards.erase("class QDBusMessage"); + } break; case Class::Proxy: @@ -205,6 +218,11 @@ forwards.insertString("class QString"); if (!classData.properties.isEmpty()) forwards.insertString("class QDBusVariant"); + if (!classData.asyncMethods.isEmpty()) + { + includes["Qt"].insertString("<qmap.h>"); + forwards.erase("template <typename K, typename V> class QMap"); + } break; case Class::Node: @@ -345,7 +363,7 @@ stream << "#include \"" << (*it).name.lower() << ".h\"" << endl; } - stream << "#include \"introspectable.h\"" << endl; + stream << "#include \"introspectableinterface.h\"" << endl; stream << endl; } @@ -442,7 +460,30 @@ static void writeMethodDeclarations(const Class& classData, Class::Role role, QTextStream& stream) { - if (!classData.methods.isEmpty()) + if (role == Class::Interface && !classData.asyncReplyMethods.isEmpty()) + { + stream << "public:" << endl; + + QValueList<Method>::const_iterator it = + classData.asyncReplyMethods.begin(); + QValueList<Method>::const_iterator endIt = + classData.asyncReplyMethods.end(); + for (; it != endIt; ++it) + { + Method method = *it; + method.name += "AsyncReply"; + + stream << " virtual void "; + MethodGenerator::writeMethodDeclaration(method, false, false, stream); + + stream << " virtual void " << (*it).name + << "AsyncError(int asyncCallId, const QDBusError& error);" + << endl; + stream << endl; + } + } + + if (!classData.methods.isEmpty() || !classData.asyncMethods.isEmpty()) { bool pureVirtual = true; switch (role) @@ -465,9 +506,35 @@ QValueList<Method>::const_iterator endIt = classData.methods.end(); for (; it != endIt; ++it) { + if ((*it).async) continue; + stream << " virtual bool "; MethodGenerator::writeMethodDeclaration(*it, pureVirtual, true, stream); } + + it = classData.asyncMethods.begin(); + endIt = classData.asyncMethods.end(); + for (; it != endIt; ++it) + { + Method method = *it; + method.name += "Async"; + + switch (role) + { + case Class::Interface: + stream << " virtual void "; + MethodGenerator::writeMethodDeclaration(method, pureVirtual, false, stream); + break; + + case Class::Proxy: + stream << " virtual bool "; + MethodGenerator::writeMethodDeclaration(method, pureVirtual, true, stream); + break; + + case Class::Node: // no async methods + break; + } + } } if (!classData.properties.isEmpty()) @@ -511,7 +578,7 @@ switch (role) { case Class::Interface: - if (!classData.methods.isEmpty()) + if (!classData.methods.isEmpty() || !classData.asyncMethods.isEmpty()) { stream << "protected: // implement sending replies" << endl; stream << " virtual void handleMethodReply(const QDBusMessage& reply) = 0;" << endl; @@ -527,15 +594,35 @@ break; case Class::Proxy: + { if (!classData.signals.isEmpty()) { stream << "protected slots: // usually no need to reimplement" << endl; stream << " virtual void slotHandleDBusSignal(const QDBusMessage& message);" << endl; stream << endl; } + + if (!classData.asyncReplySignals.isEmpty()) + { + if (classData.signals.isEmpty()) + { + stream << "protected slots: // usually no need to reimplement" << endl; + } + stream << " virtual void slotHandleAsyncReply(int id, const QDBusMessage& message);" << endl; + stream << endl; + } + stream << "protected:" << endl; stream << " QDBusProxy* m_baseProxy;" << endl; + + if (!classData.asyncMethods.isEmpty()) + { + stream << endl; + stream << " QMap<int, QString> m_asyncCalls;" << endl; + } + break; + } case Class::Node: // not variable methods break; @@ -547,7 +634,8 @@ static void writeSignalDeclarations(const Class& classData, Class::Role role, QTextStream& stream) { - if (classData.signals.isEmpty()) return; + if (classData.signals.isEmpty() && classData.asyncReplySignals.isEmpty()) + return; QString prefix; switch (role) @@ -578,6 +666,18 @@ MethodGenerator::writeMethodDeclaration(*it, false, false, stream); } + it = classData.asyncReplySignals.begin(); + endIt = classData.asyncReplySignals.end(); + for (; it != endIt; ++it) + { + stream << prefix; + + Method signal = *it; + signal.name += "AsyncReply"; + + MethodGenerator::writeMethodDeclaration(signal, false, false, stream); + } + stream << endl; } @@ -598,8 +698,6 @@ static void writeMethodCallDeclarations(const Class& classData, QTextStream& stream) { - if (classData.methods.isEmpty()) return; - QValueList<Method>::const_iterator it = classData.methods.begin(); QValueList<Method>::const_iterator endIt = classData.methods.end(); for (; it != endIt; ++it) @@ -607,6 +705,26 @@ stream << " "; MethodGenerator::writeMethodCallDeclaration(*it, stream); } + + if (!classData.asyncReplyMethods.isEmpty()) + { + stream << "protected:" << endl; + stream << " QMap<int, QDBusMessage> m_asyncCalls;" << endl; + stream << endl; + } +} + +static void writeInterfaceAsyncReplyHandlers(const Class& classData, + QTextStream& stream) +{ + if (classData.asyncReplyMethods.isEmpty()) return; + + QValueList<Method>::const_iterator it = classData.asyncReplyMethods.begin(); + QValueList<Method>::const_iterator endIt = classData.asyncReplyMethods.end(); + for (; it != endIt; ++it) + { + MethodGenerator::writeInterfaceAsyncReplyHandler(classData, *it, stream); + } } static void writeMethodCalls(const Class& classData, QTextStream& stream) @@ -615,6 +733,15 @@ QValueList<Method>::const_iterator endIt = classData.methods.end(); for (; it != endIt; ++it) { + if ((*it).async) continue; + + MethodGenerator::writeMethodCall(classData, *it, stream); + } + + it = classData.asyncMethods.begin(); + endIt = classData.asyncMethods.end(); + for (; it != endIt; ++it) + { MethodGenerator::writeMethodCall(classData, *it, stream); } } @@ -625,6 +752,15 @@ QValueList<Method>::const_iterator endIt = classData.methods.end(); for (; it != endIt; ++it) { + if ((*it).async) continue; + + MethodGenerator::writeProxyMethod(classData.name, *it, stream); + } + + it = classData.asyncMethods.begin(); + endIt = classData.asyncMethods.end(); + for (; it != endIt; ++it) + { MethodGenerator::writeProxyMethod(classData.name, *it, stream); } } @@ -643,6 +779,121 @@ } } +static void splitAsyncProxyMethods(Class& classData) +{ + // create the async identifier + Argument idArgMethod; + idArgMethod.name = "asyncCallId"; + idArgMethod.signature = "int"; + idArgMethod.isPrimitive = true; + idArgMethod.direction = Argument::Out; + + Argument idArgSignal = idArgMethod; + idArgSignal.direction = Argument::In; + + QValueList<Method>::iterator it = classData.methods.begin(); + QValueList<Method>::iterator endIt = classData.methods.end(); + for (; it != endIt; ++it) + { + if (!(*it).async) continue; + + Method method = *it; + + QValueList<Argument> methodArgs; + QValueList<Argument> signalArgs; + + // add id argument + methodArgs << idArgMethod; + signalArgs << idArgSignal; + + // split in/out arguments: "in" belong to the method, "out" to the new signal + QValueList<Argument>::const_iterator argIt = method.arguments.begin(); + QValueList<Argument>::const_iterator argEndIt = method.arguments.end(); + for (; argIt != argEndIt; ++argIt) + { + if ((*argIt).direction == Argument::Out) + { + // signal parameters are "out" but have "in" signature, + // e.g. "const T&" + Argument arg = *argIt; + arg.direction = Argument::In; + + signalArgs << arg; + } + else + methodArgs << *argIt; + } + + // change method + method.arguments = methodArgs; + + classData.asyncMethods << method; + + // create "callback" signal + Method signal = method; + signal.arguments = signalArgs; + + classData.asyncReplySignals << signal; + } +} + +static void splitAsyncInterfaceMethods(Class& classData) +{ + // create the async identifier + Argument idArgMethod; + idArgMethod.name = "asyncCallId"; + idArgMethod.signature = "int"; + idArgMethod.isPrimitive = true; + idArgMethod.direction = Argument::In; + + Argument idArgReply = idArgMethod; + + QValueList<Method>::iterator it = classData.methods.begin(); + QValueList<Method>::iterator endIt = classData.methods.end(); + for (; it != endIt; ++it) + { + if (!(*it).async) continue; + + Method method = *it; + + QValueList<Argument> methodArgs; + QValueList<Argument> replyArgs; + + // add id argument + methodArgs << idArgMethod; + replyArgs << idArgReply; + + // split in/out arguments: "in" belong to the call, "out" to the reply + QValueList<Argument>::const_iterator argIt = method.arguments.begin(); + QValueList<Argument>::const_iterator argEndIt = method.arguments.end(); + for (; argIt != argEndIt; ++argIt) + { + if ((*argIt).direction == Argument::Out) + { + // reply parameters are "out" for the service but "in" for + // the reply handler + Argument arg = *argIt; + arg.direction = Argument::In; + + replyArgs << arg; + } + else + methodArgs << *argIt; + } + + // change method + method.arguments = methodArgs; + + classData.asyncMethods << method; + + // create reply handler + Method reply = method; + reply.arguments = replyArgs; + + classData.asyncReplyMethods << reply; + } +} + bool ClassGenerator::initStreams(const QString& baseName, QTextStream& headerStream, QTextStream& sourceStream) @@ -680,7 +931,6 @@ { closeIncludeGuard(baseName, headerStream); writeFileFooter(headerStream); - writeFileFooter(sourceStream); QIODevice* device = headerStream.device(); @@ -717,33 +967,36 @@ QTextStream& headerStream, QTextStream& sourceStream) { + Class classDataCopy = classData; + splitAsyncInterfaceMethods(classDataCopy); + // create header - writeHeaderIncludes(classData, Class::Interface, headerStream); + writeHeaderIncludes(classDataCopy, Class::Interface, headerStream); - openNamespaces(classData.namespaces, headerStream); - openClassDeclaration(classData, Class::Interface, headerStream); + openNamespaces(classDataCopy.namespaces, headerStream); + openClassDeclaration(classDataCopy, Class::Interface, headerStream); - writeSignalDeclarations(classData, Class::Interface, headerStream); - writeMethodDeclarations(classData, Class::Interface, headerStream); - writeMethodCallDeclarations(classData, headerStream); + writeSignalDeclarations(classDataCopy, Class::Interface, headerStream); + writeMethodDeclarations(classDataCopy, Class::Interface, headerStream); + writeMethodCallDeclarations(classDataCopy, headerStream); - closeClassDeclaration(classData, Class::Interface, headerStream); - closeNamespaces(classData.namespaces, headerStream); + closeClassDeclaration(classDataCopy, Class::Interface, headerStream); + closeNamespaces(classDataCopy.namespaces, headerStream); // create source - writeSourceIncludes(classData, Class::Interface, sourceStream); - - openNamespaces(classData.namespaces, sourceStream); + writeSourceIncludes(classDataCopy, Class::Interface, sourceStream); - MethodGenerator::writeIntrospectionDataMethod(classData, sourceStream); + openNamespaces(classDataCopy.namespaces, sourceStream); - writeSignalEmitters(classData, sourceStream); + MethodGenerator::writeIntrospectionDataMethod(classDataCopy, sourceStream); - writeMethodCalls(classData, sourceStream); + writeSignalEmitters(classDataCopy, sourceStream); + writeInterfaceAsyncReplyHandlers(classDataCopy, sourceStream); + writeMethodCalls(classDataCopy, sourceStream); - MethodGenerator::writeInterfaceMainMethod(classData, sourceStream); + MethodGenerator::writeInterfaceMainMethod(classDataCopy, sourceStream); - closeNamespaces(classData.namespaces, sourceStream); + closeNamespaces(classDataCopy.namespaces, sourceStream); return true; } @@ -752,33 +1005,39 @@ QTextStream& headerStream, QTextStream& sourceStream) { + Class classDataCopy = classData; + splitAsyncProxyMethods(classDataCopy); + // create header - writeHeaderIncludes(classData, Class::Proxy, headerStream); + writeHeaderIncludes(classDataCopy, Class::Proxy, headerStream); - openNamespaces(classData.namespaces, headerStream); - openClassDeclaration(classData, Class::Proxy, headerStream); + openNamespaces(classDataCopy.namespaces, headerStream); + openClassDeclaration(classDataCopy, Class::Proxy, headerStream); - writeSignalDeclarations(classData, Class::Proxy, headerStream); - writeMethodDeclarations(classData, Class::Proxy, headerStream); + writeSignalDeclarations(classDataCopy, Class::Proxy, headerStream); + writeMethodDeclarations(classDataCopy, Class::Proxy, headerStream); - closeClassDeclaration(classData, Class::Proxy, headerStream); - closeNamespaces(classData.namespaces, headerStream); + closeClassDeclaration(classDataCopy, Class::Proxy, headerStream); + closeNamespaces(classDataCopy.namespaces, headerStream); // create source - writeSourceIncludes(classData, Class::Proxy, sourceStream); + writeSourceIncludes(classDataCopy, Class::Proxy, sourceStream); - openNamespaces(classData.namespaces, sourceStream); + openNamespaces(classDataCopy.namespaces, sourceStream); - MethodGenerator::writeProxyBegin(classData, sourceStream); + MethodGenerator::writeProxyBegin(classDataCopy, sourceStream); - writeProxyMethods(classData, sourceStream); + writeProxyMethods(classDataCopy, sourceStream); - writeProxyProperties(classData, sourceStream); + writeProxyProperties(classDataCopy, sourceStream); - if (!classData.signals.isEmpty()) - MethodGenerator::writeSignalHandler(classData, sourceStream); + if (!classDataCopy.signals.isEmpty()) + MethodGenerator::writeSignalHandler(classDataCopy, sourceStream); - closeNamespaces(classData.namespaces, sourceStream); + if (!classDataCopy.asyncReplySignals.isEmpty()) + MethodGenerator::writeProxyAsyncReplyHandler(classDataCopy, sourceStream); + + closeNamespaces(classDataCopy.namespaces, sourceStream); return true; } @@ -796,7 +1055,6 @@ closeClassDeclaration(classData, Class::Node, headerStream); closeNamespaces(classData.namespaces, headerStream); - closeIncludeGuard(classData.name, headerStream); // create source writeSourceIncludes(classData, Class::Node, sourceStream); diff -ur libdbus-1-qt3-0.8.1/tools/dbusxml2qt3/main.cpp ../dbus-qt4-qt3backport/tools/dbusxml2qt3/main.cpp --- libdbus-1-qt3-0.8.1/tools/dbusxml2qt3/main.cpp 2007-12-17 12:34:08.000000000 +0100 +++ ../dbus-qt4-qt3backport/tools/dbusxml2qt3/main.cpp 2008-03-13 10:28:54.000000000 +0100 @@ -153,12 +153,16 @@ exit(3); } - QStringList nameParts = QStringList::split("::", options["classname"]); + // class name for node is handled differently later on + if (!generateNode) + { + QStringList nameParts = QStringList::split("::", options["classname"]); - interfaces[0].name = nameParts.back(); + interfaces[0].name = nameParts.back(); - nameParts.pop_back(); - interfaces[0].namespaces = nameParts; + nameParts.pop_back(); + interfaces[0].namespaces = nameParts; + } } if (checkForOption(options, "namespace")) @@ -284,6 +288,7 @@ Method method; method.name = "Introspect"; method.noReply = false; + method.async = false; Argument argument; argument.name = "data"; diff -ur libdbus-1-qt3-0.8.1/tools/dbusxml2qt3/methodgen.cpp ../dbus-qt4-qt3backport/tools/dbusxml2qt3/methodgen.cpp --- libdbus-1-qt3-0.8.1/tools/dbusxml2qt3/methodgen.cpp 2007-12-17 12:34:08.000000000 +0100 +++ ../dbus-qt4-qt3backport/tools/dbusxml2qt3/methodgen.cpp 2008-03-13 10:28:54.000000000 +0100 @@ -279,6 +279,24 @@ return annotations; } +static bool hasAnnotation(const QDomElement& element, const QString& annotation, QString* value = 0) +{ + for (QDomNode node = element.firstChild(); !node.isNull(); + node = node.nextSibling()) + { + if (!node.isElement()) continue; + + QDomElement childElement = node.toElement(); + if (childElement.tagName() != "annotation") continue; + if (childElement.attribute("name") != annotation) continue; + + if (value != 0) *value = childElement.attribute("value"); + return true; + } + + return false; +} + static QValueList<Argument> extractArguments(const QDomElement& methodElement, Class& classData) { @@ -568,9 +586,13 @@ method.name = element.attribute("name"); method.arguments = extractArguments(element, classData); method.noReply = false; + method.async = false; if (element.tagName() == "method") + { + method.async = hasAnnotation(element, "org.freedesktop.DBus.GLib.Async"); classData.methods.append(method); + } else classData.signals.append(method); } @@ -689,36 +711,85 @@ void MethodGenerator::writeMethodCallDeclaration(const Method& method, QTextStream& stream) { - stream << "QDBusMessage call" << method.name - << "(const QDBusMessage& mesage);" << endl; + if (method.async) + stream << "void call" << method.name << "Async"; + else + stream << "QDBusMessage call" << method.name; + + stream << "(const QDBusMessage& message);" << endl; stream << endl; } void MethodGenerator::writeMethodCall(const Class& classData, const Method& method, QTextStream& stream) { - stream << "QDBusMessage " << classData.name << "::call" << method.name - << "(const QDBusMessage& message)" << endl;; + if (method.async) + stream << "void " << classData.name << "::call" << method.name << "Async"; + else + stream << "QDBusMessage " << classData.name << "::call" << method.name; + + stream << "(const QDBusMessage& message)" << endl; stream << "{" << endl; - stream << " QDBusError error;" << endl; - stream << " QDBusMessage reply;" << endl; - stream << endl; - writeVariables(" ", method, stream); + if (method.async) + { + // FIXME: using writeVariables by removing asyncCallId argument + Method reducedMethod = method; + reducedMethod.arguments.pop_front(); + + writeVariables(" ", reducedMethod, stream); + } + else + { + stream << " QDBusError error;" << endl; + stream << " QDBusMessage reply;" << endl; + stream << endl; + + writeVariables(" ", method, stream); + } stream << endl; - stream << " if (" << method.name << "("; + + if (method.async) + { + stream << " int _asyncCallId = 0;" << endl; + stream << " while (m_asyncCalls.find(_asyncCallId) != m_asyncCalls.end())" + << endl; + stream << " {" << endl; + stream << " ++_asyncCallId;" << endl; + stream << " }" << endl; + stream << " m_asyncCalls.insert(_asyncCallId, message);" << endl; + stream << endl; + + stream << " " << method.name << "Async("; + } + else + stream << " if (" << method.name << "("; QValueList<Argument>::const_iterator it = method.arguments.begin(); QValueList<Argument>::const_iterator endIt = method.arguments.end(); - for (; it != endIt; ++it) + while (it != endIt) { - stream << "_" << (*it).name << ", "; + stream << "_" << (*it).name; + + ++it; + if (it != endIt) stream << ", "; } - stream << "error))" << endl; + if (method.async) + { + stream << ");" << endl; + stream << endl; + + stream << " return;" << endl; + stream << "}" << endl; + stream << endl; + return; + } + if (method.arguments.count() > 0) stream << ", "; + stream << "error))" << endl; stream << " {" << endl; stream << " reply = QDBusMessage::methodReply(message);" << endl; @@ -878,6 +949,102 @@ stream << endl; } + +void MethodGenerator::writeInterfaceAsyncReplyHandler(const Class& classData, + const Method& method, QTextStream& stream) +{ + stream << "void " << classData.name << "::" << method.name + << "AsyncReply("; + + QValueList<Argument>::const_iterator it = method.arguments.begin(); + QValueList<Argument>::const_iterator endIt = method.arguments.end(); + while (it != endIt) + { + if (!(*it).isPrimitive && (*it).direction == Argument::In) + stream << "const "; + + stream << (*it).signature; + + if (!(*it).isPrimitive || (*it).direction == Argument::Out) stream << "&"; + + stream << " " << (*it).name; + + ++it; + if (it != endIt) stream << ", "; + } + stream << ")" << endl; + stream << endl; + stream << "{" << endl; + + stream << " QMap<int, QDBusMessage>::iterator findIt = m_asyncCalls.find(asyncCallId);" << endl; + stream << " if (findIt == m_asyncCalls.end()) return;" << endl; + stream << endl; + + stream << " QDBusMessage call = findIt.data();" << endl; + stream << " m_asyncCalls.erase(findIt);" << endl; + stream << endl; + + stream << " QDBusMessage reply = QDBusMessage::methodReply(call);" + << endl; + + it = method.arguments.begin(); + for (++it; it != endIt; ++it) // skip asyncCallId at beginning + { + if (!(*it).annotatedType.isEmpty()) + { + stream << " QDBusData " << (*it).name << "Data;" << endl; + + // TODO error handling + stream << " if (QDBusDataConverter::convertToQDBusData<" + << (*it).annotatedType << ">(" << (*it).name << ", " + << (*it).name << "Data" + << ") != QDBusDataConverter::Success) return false;" + << endl; + stream << " reply << " << (*it).name << "Data;" << endl; + } + else if (!(*it).accessor.isEmpty()) + { + stream << " reply << QDBusData::from" << (*it).accessor << "("; + + if ((*it).subAccessor.isEmpty()) + stream << (*it).name; + else + stream << (*it).containerClass << "(" << (*it).name << ")"; + + stream << ");" << endl; + } + else + stream << " reply << " << (*it).name << ";" << endl; + } + stream << endl; + + stream << " handleMethodReply(reply);" << endl; + + stream << "}" << endl; + stream << endl; + + stream << "void " << classData.name << "::" << method.name + << "AsyncError(int asyncCallId, const QDBusError& error)"; + stream << endl; + + stream << "{" << endl; + + stream << " QMap<int, QDBusMessage>::iterator findIt = m_asyncCalls.find(asyncCallId);" << endl; + stream << " if (findIt == m_asyncCalls.end()) return;" << endl; + stream << endl; + + stream << " QDBusMessage call = findIt.data();" << endl; + stream << " m_asyncCalls.erase(findIt);" << endl; + stream << endl; + + stream << " QDBusMessage reply = QDBusMessage::methodError(call, error);" + << endl; + stream << " handleMethodReply(reply);" << endl; + + stream << "}" << endl; + stream << endl; +} + void MethodGenerator::writeInterfaceMainMethod(const Class& classData, QTextStream& stream) { @@ -897,10 +1064,19 @@ { stream << " if (message.member() == \"" << (*it).name << "\")" << endl; stream << " {" << endl; - stream << " QDBusMessage reply = call" << (*it).name << "(message);" - << endl; - stream << " handleMethodReply(reply);" << endl; - stream << endl; + + if ((*it).async) + { + stream << " call" << (*it).name << "Async(message);" << endl; + stream << endl; + } + else + { + stream << " QDBusMessage reply = call" << (*it).name + << "(message);" << endl; + stream << " handleMethodReply(reply);" << endl; + stream << endl; + } stream << " return true;" << endl; stream << " }" << endl; stream << endl; @@ -967,6 +1143,15 @@ << endl; } + if (!classData.asyncReplySignals.isEmpty()) + { + stream << " QObject::connect(m_baseProxy, " + << "SIGNAL(asyncReply(int, const QDBusMessage&))," << endl; + stream << " this, " + << " SLOT(slotHandleAsyncReply(int, const QDBusMessage&)));" + << endl; + } + stream << "}" << endl; stream << endl; @@ -988,7 +1173,8 @@ void MethodGenerator::writeProxyMethod(const QString& className, const Method& method, QTextStream& stream) { - stream << "bool " << className << "::" << method.name << "("; + stream << "bool " << className << "::" << method.name + << (method.async ? "Async(" : "("); QValueList<Argument>::const_iterator it = method.arguments.begin(); QValueList<Argument>::const_iterator endIt = method.arguments.end(); @@ -1064,6 +1250,22 @@ return; } + if (method.async) + { + stream << " asyncCallId = m_baseProxy->sendWithAsyncReply(\""; + stream << method.name << "\", parameters);" << endl; + stream << endl; + + stream << " if (asyncCallId != 0) m_asyncCalls[asyncCallId] = \"" + << method.name << "\";" << endl; + stream << endl; + + stream << " return (asyncCallId != 0);" << endl; + stream << "}" << endl; + stream << endl; + return; + } + stream << " QDBusMessage reply = m_baseProxy->sendWithReply(\""; stream << method.name << "\", parameters, &error);" << endl; stream << endl; @@ -1335,6 +1537,58 @@ } } +void MethodGenerator::writeProxyAsyncReplyHandler(const Class& classData, + QTextStream& stream) +{ + stream << "void " << classData.name + << "::slotHandleAsyncReply(int asyncCallId, const QDBusMessage& message)" << endl; + stream << "{" << endl; + + stream << " QMap<int, QString>::iterator findIt = " + << "m_asyncCalls.find(asyncCallId);" << endl; + stream << " if (findIt == m_asyncCalls.end()) return;" << endl; + stream << endl; + stream << " const QString signalName = findIt.data();" << endl; + stream << " m_asyncCalls.erase(findIt);" << endl; + stream << endl; + + QValueList<Method>::const_iterator it = classData.asyncReplySignals.begin(); + QValueList<Method>::const_iterator endIt = classData.asyncReplySignals.end(); + bool first = true; + for (; it != endIt; ++it) + { + stream << " "; + + if (!first) + stream << "else "; + else + first = false; + + stream << "if (signalName == \"" << (*it).name << "\")" << endl; + stream << " {" << endl; + + // FIXME tricking writeVariables and writeSignalEmit into writing + // the reply emit code by manipulating arguments and name + stream << " int _asyncCallId = asyncCallId;" << endl; + + Method signal = *it; + signal.arguments.pop_front(); + + writeVariables(" ", signal, stream); + stream << endl; + + signal = *it; + signal.name += "AsyncReply"; + + writeSignalEmit(signal, stream); + + stream << " }" << endl; + } + + stream << "}" << endl; + stream << endl; +} + void MethodGenerator::writeIntrospectionDataMethod(const Class& classData, QTextStream& stream) { diff -ur libdbus-1-qt3-0.8.1/tools/dbusxml2qt3/methodgen.h ../dbus-qt4-qt3backport/tools/dbusxml2qt3/methodgen.h --- libdbus-1-qt3-0.8.1/tools/dbusxml2qt3/methodgen.h 2007-12-17 12:34:08.000000000 +0100 +++ ../dbus-qt4-qt3backport/tools/dbusxml2qt3/methodgen.h 2008-03-13 10:28:55.000000000 +0100 @@ -61,6 +61,7 @@ QString name; QValueList<Argument> arguments; bool noReply; + bool async; }; class Property : public Argument @@ -86,6 +87,10 @@ QValueList<Method> methods; QValueList<Method> signals; QValueList<Property> properties; + + QValueList<Method> asyncMethods; + QValueList<Method> asyncReplySignals; + QValueList<Method> asyncReplyMethods; }; class MethodGenerator @@ -109,6 +114,10 @@ static void writeSignalEmitter(const Class& classData, const Method& method, QTextStream& stream); + static void writeInterfaceAsyncReplyHandler(const Class& classData, + const Method& method, + QTextStream& stream); + static void writeInterfaceMainMethod(const Class& classData, QTextStream& stream); @@ -125,6 +134,9 @@ static void writeProxyProperty(const Class& classData, const Property& property, QTextStream& stream); + static void writeProxyAsyncReplyHandler(const Class& classData, + QTextStream& stream); + static void writeIntrospectionDataMethod(const Class& classData, QTextStream& stream);