diff options
author | Thiago Macieira <thiago.macieira@trolltech.com> | 2006-03-28 18:56:08 +0000 |
---|---|---|
committer | John Palmieri <johnp@remedyz.boston.redhat.com> | 2006-06-28 08:15:13 -0400 |
commit | ed506643a1016ac8510634f0ac358433338f81b2 (patch) | |
tree | 6b7c50cd4367e121bd8f488910fa3eecff555d22 /qt | |
parent | c4fa768951cfce4d5bb8d02beb69024bc1868d5a (diff) |
* qt/*: * dbus/qdbus.h: Sync with KDE Subversion revision 523647. Hopefully, this will be the last of the source-incompatible changes. Documentation has been improved; support for QList<basic-types> has been added; QDBusObject is gone; QDBus(Abstract)Interface is now a QObject with auto-generated meta-object; QDBusIntrospection is marked private, since QMetaObject can be used now; lots of bugfixes.
Diffstat (limited to 'qt')
41 files changed, 4028 insertions, 3622 deletions
diff --git a/qt/Makefile.am b/qt/Makefile.am index 1f87216..7450267 100644 --- a/qt/Makefile.am +++ b/qt/Makefile.am @@ -1,80 +1,72 @@ if HAVE_QT INCLUDES=-I$(top_srcdir) $(DBUS_CLIENT_CFLAGS) $(DBUS_QT_CFLAGS) -DDBUS_COMPILATION -dbusincludedir=$(includedir)/dbus-1.0/dbus - lib_LTLIBRARIES=libdbus-qt4-1.la -dbusinclude_HEADERS= \ - qdbusmacros.h \ - qdbuserror.h \ - qdbusmessage.h \ - qdbusserver.h \ - qdbusconnection.h \ - qdbusvariant.h \ - qdbusobject.h \ - qdbusinterface.h \ - qdbustype.h \ - qdbusstandardinterfaces.h \ - qdbusutil.h \ - qdbusintrospection.h \ - qdbusabstractadaptor.h \ - qdbusreply.h +dbusincludedir=$(includedir)/dbus-1.0/dbus +dbusinclude_HEADERS= \ + qdbus.h \ + qdbusbus.h \ + qdbusmacros.h \ + qdbuserror.h \ + qdbusmessage.h \ + qdbusserver.h \ + qdbusconnection.h \ + qdbusabstractinterface.h \ + qdbusinterface.h \ + qdbusutil.h \ + qdbusabstractadaptor.h \ + qdbusreply.h \ + qdbustypehelper_p.h -libdbus_qt4_1_la_SOURCES = \ - qdbusconnection.cpp \ - qdbuserror.cpp \ - qdbusintegrator.cpp \ - qdbusinternalfilters.cpp \ - qdbusmarshall.cpp \ - qdbusmessage.cpp \ - qdbusserver.cpp \ - qdbustype.cpp \ - qdbusobject.cpp \ - qdbusinterface.cpp \ - qdbusstandardinterfaces.cpp \ - qdbusxmlparser.cpp \ - qdbusutil.cpp \ - qdbusintrospection.cpp \ - qdbusabstractadaptor.cpp \ - qdbusthread.cpp \ - \ - qdbusabstractadaptor.h \ +noinst_HEADERS= \ qdbusabstractadaptor_p.h \ - qdbusconnection.h \ + qdbusabstractinterface_p.h \ qdbusconnection_p.h \ - qdbuserror.h \ - qdbusinterface.h \ qdbusinterface_p.h \ - qdbusintrospection.h \ - qdbusmacros.h \ + qdbusintrospection_p.h \ qdbusmarshall_p.h \ - qdbusmessage.h \ qdbusmessage_p.h \ - qdbusobject.h \ - qdbusobject_p.h \ - qdbusreply.h \ - qdbusserver.h \ - qdbusstandardinterfaces.h \ - qdbustype.h \ - qdbusvariant.h \ - qdbusxmlparser_p.h + qdbusmetaobject_p.h \ + qdbustype_p.h \ + qdbusxmlparser_p.h + +libdbus_qt4_1_la_SOURCES = \ + qdbusbus.cpp \ + qdbusconnection.cpp \ + qdbuserror.cpp \ + qdbusintegrator.cpp \ + qdbusmarshall.cpp \ + qdbusmessage.cpp \ + qdbusserver.cpp \ + qdbustype.cpp \ + qdbusabstractinterface.cpp \ + qdbusinterface.cpp \ + qdbusxmlparser.cpp \ + qdbusutil.cpp \ + qdbusintrospection.cpp \ + qdbusabstractadaptor.cpp \ + qdbusthread.cpp \ + qdbusinternalfilters.cpp \ + qdbusmetaobject.cpp bin_PROGRAMS = dbusidl2cpp dbusidl2cpp_SOURCES = dbusidl2cpp.cpp -dbusidl2cpp_LDFLAGS = $(all_libraries) -no-undefined -dbusidl2cpp_LDADD = $(LIB_QTCORE) libdbus-qt4-1.la +dbusidl2cpp_LDFLAGS = -no-undefined +dbusidl2cpp_LDADD = $(DBUS_QT_LIBS) libdbus-qt4-1.la qdbusabstractadaptor.lo: qdbusabstractadaptor.moc qdbusabstractadaptor_p.moc +qdbusabstractinterface.lo: qdbusabstractinterface.moc +qdbusbus.lo: qdbusbus.moc qdbusserver.lo: qdbusserver.moc qdbusconnection.lo: qdbusconnection_p.moc -CLEANFILES=qdbusabstractadaptor.moc qdbusserver.moc qdbusconnection.moc qdbusabstractadaptor_p.moc +CLEANFILES=qdbusabstractadaptor.moc qdbusserver.moc qdbusconnection.moc qdbusconnection_p.moc qdbusabstractadaptor_p.moc qdbusbus.moc qdbusabstractinterface.moc libdbus_qt4_1_la_LIBADD= $(DBUS_QT_LIBS) $(top_builddir)/dbus/libdbus-1.la libdbus_qt4_1_la_LDFLAGS= -version-info 1:0 -no-undefined -EXTRA_DIST = Doxyfile +EXTRA_DIST = qt-dbus.qdocconf %.moc: %.h $(QT_MOC) $< > $@ diff --git a/qt/dbusidl2cpp.cpp b/qt/dbusidl2cpp.cpp index 51fb8e4..67bd649 100644 --- a/qt/dbusidl2cpp.cpp +++ b/qt/dbusidl2cpp.cpp @@ -28,23 +28,28 @@ #include <QtCore/qdatetime.h> #include <QtCore/qfile.h> #include <QtCore/qstring.h> +#include <QtCore/qstringlist.h> #include <QtCore/qtextstream.h> #include <QtCore/qset.h> #include <dbus/qdbus.h> +#include "qdbusmetaobject_p.h" +#include "qdbusintrospection_p.h" #define PROGRAMNAME "dbusidl2cpp" -#define PROGRAMVERSION "0.1" +#define PROGRAMVERSION "0.3" #define PROGRAMCOPYRIGHT "Copyright (C) 2006 Trolltech AS. All rights reserved." #define ANNOTATION_NO_WAIT "org.freedesktop.DBus.Method.NoReply" -static const char cmdlineOptions[] = "a:h:Np:vV"; +static const char cmdlineOptions[] = "a:c:hmNp:vV"; +static const char *globalClassName; static const char *proxyFile; static const char *adaptorFile; static const char *inputFile; static bool skipNamespaces; static bool verbose; +static bool includeMocs; static QStringList wantedInterfaces; static const char help[] = @@ -54,7 +59,9 @@ static const char help[] = "\n" "Options:\n" " -a <filename> Write the adaptor code to <filename>\n" + " -c <classname> Use <classname> as the class name for the generated classes\n" " -h Show this information\n" + " -m Generate #include \"filename.moc\" statements in the .cpp files\n" " -N Don't use namespaces\n" " -p <filename> Write the proxy code to <filename>\n" " -v Be verbose.\n" @@ -63,6 +70,22 @@ static const char help[] = "If the file name given to the options -a and -p does not end in .cpp or .h, the\n" "program will automatically append the suffixes and produce both files.\n"; +static const char includeList[] = + "#include <QtCore/QByteArray>\n" + "#include <QtCore/QList>\n" + "#include <QtCore/QMap>\n" + "#include <QtCore/QString>\n" + "#include <QtCore/QStringList>\n" + "#include <QtCore/QVariant>\n"; + +static const char forwardDeclarations[] = + "class QByteArray;\n" + "template<class T> class QList;\n" + "template<class Key, class Value> class QMap;\n" + "class QString;\n" + "class QStringList;\n" + "class QVariant;\n"; + static void showHelp() { printf("%s", help); @@ -86,11 +109,19 @@ static void parseCmdLine(int argc, char **argv) case 'a': adaptorFile = optarg; break; + + case 'c': + globalClassName = optarg; + break; case 'v': verbose = true; break; + case 'm': + includeMocs = true; + break; + case 'N': skipNamespaces = true; break; @@ -123,7 +154,7 @@ static void parseCmdLine(int argc, char **argv) static QDBusIntrospection::Interfaces readInput() { QFile input(QFile::decodeName(inputFile)); - if (inputFile) + if (inputFile && QLatin1String("-") != inputFile) input.open(QIODevice::ReadOnly); else input.open(stdin, QIODevice::ReadOnly); @@ -201,6 +232,9 @@ static QTextStream &writeHeader(QTextStream &ts, bool changesWillBeLost) enum ClassType { Proxy, Adaptor }; static QString classNameForInterface(const QString &interface, ClassType classType) { + if (globalClassName) + return QLatin1String(globalClassName); + QStringList parts = interface.split('.'); QString retval; @@ -222,53 +256,34 @@ static QString classNameForInterface(const QString &interface, ClassType classTy return retval; } -static QString templateArg(const QString &arg) +static QByteArray qtTypeName(const QString &signature) { - if (!arg.endsWith('>')) - return arg; - - return arg + ' '; + QVariant::Type type = QDBusUtil::signatureToType(signature); + if (type == QVariant::Invalid) + qFatal("Got unknown type `%s'", qPrintable(signature)); + + return QVariant::typeToName(type); } -static QString constRefArg(const QString &arg) +static QString nonConstRefArg(const QByteArray &arg) { - if (!arg.startsWith('Q')) - return arg + ' '; - else - return QString("const %1 &").arg(arg); + return QLatin1String(arg + " &"); } -static QString makeQtName(const QString &dbusName) +static QString templateArg(const QByteArray &arg) { - QString name = dbusName; - if (name.length() > 3 && name.startsWith("Get")) - name = name.mid(3); // strip Get from GetXXXX - - // recapitalize the name - QChar *p = name.data(); - while (!p->isNull()) { - // capitalized letter - // leave it - if (!p->isNull()) - ++p; - - // lowercase all the next capital letters, except for the last one - while (!p->isNull() && p->isUpper()) { - if (!p[1].isNull() && p[1].isUpper()) - *p = p->toLower(); - ++p; - } - - if (p->isUpper()) - ++p; + if (!arg.endsWith('>')) + return QLatin1String(arg); - // non capital letters: skip them - while (!p->isNull() && !p->isUpper()) - ++p; - } + return QLatin1String(arg + ' '); +} - name[0] = name[0].toLower(); // lowercase the first one - return name; +static QString constRefArg(const QByteArray &arg) +{ + if (!arg.startsWith('Q')) + return QLatin1String(arg + ' '); + else + return QString("const %1 &").arg( QLatin1String(arg) ); } static QStringList makeArgNames(const QDBusIntrospection::Arguments &inputArgs, @@ -306,7 +321,7 @@ static void writeArgList(QTextStream &ts, const QStringList &argNames, int argPos = 0; for (int i = 0; i < inputArgs.count(); ++i) { const QDBusIntrospection::Argument &arg = inputArgs.at(i); - QString type = constRefArg(arg.type.toString(QDBusType::QVariantNames)); + QString type = constRefArg(qtTypeName(arg.type)); if (!first) ts << ", "; @@ -324,7 +339,7 @@ static void writeArgList(QTextStream &ts, const QStringList &argNames, if (!first) ts << ", "; - ts << arg.type.toString(QDBusType::QVariantNames) << " &" << argNames.at(argPos++); + ts << nonConstRefArg(qtTypeName(arg.type)) << argNames.at(argPos++); first = false; } } @@ -348,22 +363,25 @@ static QString stringify(const QString &data) static void writeProxy(const char *proxyFile, const QDBusIntrospection::Interfaces &interfaces) { // open the file - QString name = header(proxyFile); - QFile file(name); - if (!name.isEmpty()) + QString headerName = header(proxyFile); + QFile file(headerName); + if (!headerName.isEmpty()) file.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text); else file.open(stdout, QIODevice::WriteOnly | QIODevice::Text); + QTextStream hs(&file); - QTextStream ts(&file); + QString cppName = cpp(proxyFile); + QByteArray cppData; + QTextStream cs(&cppData); // write the header: - writeHeader(ts, true); + writeHeader(hs, true); // include guards: QString includeGuard; - if (!name.isEmpty()) { - includeGuard = name.toUpper().replace(QChar('.'), QChar('_')); + if (!headerName.isEmpty()) { + includeGuard = headerName.toUpper().replace(QChar('.'), QChar('_')); int pos = includeGuard.lastIndexOf('/'); if (pos != -1) includeGuard = includeGuard.mid(pos + 1); @@ -374,54 +392,42 @@ static void writeProxy(const char *proxyFile, const QDBusIntrospection::Interfac .arg(includeGuard) .arg(getpid()) .arg(QDateTime::currentDateTime().toTime_t()); - ts << "#ifndef " << includeGuard << endl + hs << "#ifndef " << includeGuard << endl << "#define " << includeGuard << endl << endl; // include our stuff: - ts << "#include <QtCore/QObject>" << endl + hs << "#include <QtCore/QObject>" << endl + << includeList << "#include <dbus/qdbus.h>" << endl << endl; + if (cppName != headerName) { + writeHeader(cs, false); + cs << "#include \"" << headerName << "\"" << endl + << endl; + } + foreach (const QDBusIntrospection::Interface *interface, interfaces) { + QString className = classNameForInterface(interface->name, Proxy); + // comment: - ts << "/*" << endl + hs << "/*" << endl << " * Proxy class for interface " << interface->name << endl << " */" << endl; + cs << "/*" << endl + << " * Implementation of interface class " << className << endl + << " */" << endl + << endl; // class header: - QString className = classNameForInterface(interface->name, Proxy); - ts << "class " << className << ": public QDBusInterface" << endl + hs << "class " << className << ": public QDBusAbstractInterface" << endl << "{" << endl - << "public:" << endl - << " static inline const char *staticInterfaceName()" << endl - << " { return \"" << interface->name << "\"; }" << endl - << endl - << " static inline const char *staticIntrospectionData()" << endl - << " { return \"\"" << endl - << stringify(interface->introspection) - << " \"\"; }" << endl - << endl; - - // constructors/destructors: - ts << "public:" << endl - << " explicit inline " << className << "(const QDBusObject &obj)" << endl - << " : QDBusInterface(obj, staticInterfaceName())" << endl - << " { }" << endl - << endl - << " inline ~" << className << "()" << endl - << " { }" << endl - << endl; - - // the introspection virtual: - ts << " inline virtual QString introspectionData() const" << endl - << " { return QString::fromUtf8(staticIntrospectionData()); }" << endl - << endl; - + << " Q_OBJECT" << endl; + // properties: - ts << "public: // PROPERTIES" << endl; foreach (const QDBusIntrospection::Property &property, interface->properties) { - QString type = property.type.toString(QDBusType::QVariantNames); + QByteArray type = qtTypeName(property.type); QString templateType = templateArg(type); QString constRefType = constRefArg(type); QString getter = property.name; @@ -429,42 +435,46 @@ static void writeProxy(const char *proxyFile, const QDBusIntrospection::Interfac getter[0] = getter[0].toLower(); setter[3] = setter[3].toUpper(); + hs << " Q_PROPERTY(" << type << " " << property.name; + // getter: - if (property.access != QDBusIntrospection::Property::Write) { - ts << " inline QDBusReply<" << templateType << "> " << getter << "() const" << endl - << " {" << endl - << " QDBusReply<QDBusVariant> retval = QDBusPropertiesInterface(object())" << endl - << " .get(QLatin1String(\"" << interface->name << "\"), QLatin1String(\"" - << property.name << "\"));" << endl - << " return QDBusReply<" << templateType << ">::fromVariant(retval);" << endl - << " }" << endl; - } + if (property.access != QDBusIntrospection::Property::Write) + // it's readble + hs << " READ" << getter; // setter - if (property.access != QDBusIntrospection::Property::Read) { - ts << " inline QDBusReply<void> " << setter << "(" << constRefType << "value)" << endl - << " {" << endl - << " QDBusVariant v(value, QDBusType("; - - QString sig = property.type.dbusSignature(); - if (sig.length() == 1) - ts << "'" << sig.at(0) << "'"; - else - ts << "\"" << sig << "\""; - - ts << "));" << endl - << " return QDBusPropertiesInterface(object())" << endl - << " .set(QLatin1String(\"" << interface->name << "\"), QLatin1String(\"" - << property.name << "\"), v);" << endl - << " }" << endl; - } + if (property.access != QDBusIntrospection::Property::Read) + // it's writeable + hs << " WRITE" << setter; - ts << endl; + hs << ")" << endl; } + + // the interface name + hs << "public:" << endl + << " static inline const char *staticInterfaceName()" << endl + << " { return \"" << interface->name << "\"; }" << endl + << endl; + // constructors/destructors: + hs << "public:" << endl + << " explicit " << className << "(QDBusAbstractInterfacePrivate *p);" << endl + << endl + << " ~" << className << "();" << endl + << endl; + cs << className << "::" << className << "(QDBusAbstractInterfacePrivate *p)" << endl + << " : QDBusAbstractInterface(p)" << endl + << "{" << endl + << "}" << endl + << endl + << className << "::~" << className << "()" << endl + << "{" << endl + << "}" << endl + << endl; + // methods: - ts << "public: // METHODS" << endl; + hs << "public slots: // METHODS" << endl; foreach (const QDBusIntrospection::Method &method, interface->methods) { bool isAsync = method.annotations.value(ANNOTATION_NO_WAIT) == "true"; if (isAsync && !method.outputArgs.isEmpty()) { @@ -473,72 +483,83 @@ static void writeProxy(const char *proxyFile, const QDBusIntrospection::Interfac continue; } - ts << " inline "; - - QString returnType; + hs << " inline "; if (method.annotations.value("org.freedesktop.DBus.Deprecated") == "true") - ts << "Q_DECL_DEPRECATED "; + hs << "Q_DECL_DEPRECATED "; if (isAsync) - ts << "Q_ASYNC void "; + hs << "Q_ASYNC void "; else if (method.outputArgs.isEmpty()) - ts << "QDBusReply<void> "; + hs << "QDBusReply<void> "; else { - returnType = method.outputArgs.first().type.toString(QDBusType::QVariantNames); - ts << "QDBusReply<" << templateArg(returnType) << "> "; + hs << "QDBusReply<" << templateArg(qtTypeName(method.outputArgs.first().type)) << "> "; } - QString name = makeQtName(method.name); - ts << name << "("; + hs << method.name << "("; QStringList argNames = makeArgNames(method.inputArgs, method.outputArgs); - writeArgList(ts, argNames, method.inputArgs, method.outputArgs); + writeArgList(hs, argNames, method.inputArgs, method.outputArgs); - ts << ")" << endl + hs << ")" << endl << " {" << endl; if (method.outputArgs.count() > 1) - ts << " QDBusMessage reply = call(QLatin1String(\""; + hs << " QDBusMessage reply = call(QLatin1String(\""; else if (!isAsync) - ts << " return call(QLatin1String(\""; + hs << " return call(QLatin1String(\""; else - ts << " callAsync(QLatin1String(\""; + hs << " callAsync(QLatin1String(\""; + // rebuild the method input signature: QString signature = QChar('.'); foreach (const QDBusIntrospection::Argument &arg, method.inputArgs) - signature += arg.type.dbusSignature(); + signature += arg.type; if (signature.length() == 1) signature.clear(); - ts << method.name << signature << "\")"; + hs << method.name << signature << "\")"; int argPos = 0; for (int i = 0; i < method.inputArgs.count(); ++i) - ts << ", " << argNames.at(argPos++); + hs << ", " << argNames.at(argPos++); // close the QDBusIntrospection::call/callAsync call - ts << ");" << endl; + hs << ");" << endl; argPos++; if (method.outputArgs.count() > 1) { - ts << " if (reply.type() == QDBusMessage::ReplyMessage) {" << endl; + hs << " if (reply.type() == QDBusMessage::ReplyMessage) {" << endl; // yes, starting from 1 for (int i = 1; i < method.outputArgs.count(); ++i) - ts << " " << argNames.at(argPos++) << " = qvariant_cast<" - << templateArg(method.outputArgs.at(i).type.toString(QDBusType::QVariantNames)) + hs << " " << argNames.at(argPos++) << " = qvariant_cast<" + << templateArg(qtTypeName(method.outputArgs.at(i).type)) << ">(reply.at(" << i << "));" << endl; - ts << " }" << endl + hs << " }" << endl << " return reply;" << endl; } // close the function: - ts << " }" << endl + hs << " }" << endl << endl; } + hs << "signals: // SIGNALS" << endl; + foreach (const QDBusIntrospection::Signal &signal, interface->signals_) { + hs << " "; + if (signal.annotations.value("org.freedesktop.DBus.Deprecated") == "true") + hs << "Q_DECL_DEPRECATED "; + + hs << "void " << signal.name << "("; + + QStringList argNames = makeArgNames(signal.outputArgs); + writeArgList(hs, argNames, signal.outputArgs); + + hs << ");" << endl; // finished for header + } + // close the class: - ts << "};" << endl + hs << "};" << endl << endl; } @@ -561,15 +582,15 @@ static void writeProxy(const char *proxyFile, const QDBusIntrospection::Interfac // i parts matched // close last.count() - i namespaces: for (int j = i; j < last.count(); ++j) - ts << QString((last.count() - j - 1 + i) * 2, ' ') << "}" << endl; + hs << QString((last.count() - j - 1 + i) * 2, ' ') << "}" << endl; // open current.count() - i namespaces for (int j = i; j < current.count(); ++j) - ts << QString(j * 2, ' ') << "namespace " << current.at(j) << " {" << endl; + hs << QString(j * 2, ' ') << "namespace " << current.at(j) << " {" << endl; // add this class: if (!name.isEmpty()) { - ts << QString(current.count() * 2, ' ') + hs << QString(current.count() * 2, ' ') << "typedef ::" << classNameForInterface(it->constData()->name, Proxy) << " " << name << ";" << endl; } @@ -582,7 +603,22 @@ static void writeProxy(const char *proxyFile, const QDBusIntrospection::Interfac } // close the include guard - ts << "#endif" << endl; + hs << "#endif" << endl; + + if (includeMocs) + cs << endl + << "#include \"" << proxyFile << ".moc\"" << endl; + + cs.flush(); + hs.flush(); + if (headerName == cppName) + file.write(cppData); + else { + // write to cpp file + QFile f(cppName); + f.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text); + f.write(cppData); + } } static void writeAdaptor(const char *adaptorFile, const QDBusIntrospection::Interfaces &interfaces) @@ -624,17 +660,23 @@ static void writeAdaptor(const char *adaptorFile, const QDBusIntrospection::Inte // include our stuff: hs << "#include <QtCore/QObject>" << endl; if (cppName == headerName) - hs << "#include <QtCore/QMetaObject>" << endl; - hs << "#include <dbus/qdbus.h>" << endl - << endl; - + hs << "#include <QtCore/QMetaObject>" << endl + << "#include <QtCore/QVariant>" << endl; + hs << "#include <dbus/qdbus.h>" << endl; + if (cppName != headerName) { writeHeader(cs, false); cs << "#include \"" << headerName << "\"" << endl << "#include <QtCore/QMetaObject>" << endl + << includeList << endl; + hs << forwardDeclarations; + } else { + hs << includeList; } + hs << endl; + foreach (const QDBusIntrospection::Interface *interface, interfaces) { QString className = classNameForInterface(interface->name, Adaptor); @@ -676,14 +718,14 @@ static void writeAdaptor(const char *adaptorFile, const QDBusIntrospection::Inte hs << "public: // PROPERTIES" << endl; foreach (const QDBusIntrospection::Property &property, interface->properties) { - QString type = property.type.toString(QDBusType::QVariantNames); + QByteArray type = qtTypeName(property.type); QString constRefType = constRefArg(type); QString getter = property.name; QString setter = "set" + property.name; getter[0] = getter[0].toLower(); setter[3] = setter[3].toUpper(); - hs << " Q_PROPERTY(" << type << " " << getter; + hs << " Q_PROPERTY(" << type << " " << property.name; if (property.access != QDBusIntrospection::Property::Write) hs << " READ " << getter; if (property.access != QDBusIntrospection::Property::Read) @@ -728,20 +770,21 @@ static void writeAdaptor(const char *adaptorFile, const QDBusIntrospection::Inte hs << " "; if (method.annotations.value("org.freedesktop.DBus.Deprecated") == "true") hs << "Q_DECL_DEPRECATED "; - + + QByteArray returnType; if (isAsync) { hs << "Q_ASYNC void "; - cs << "Q_ASYNC void "; + cs << "void "; } else if (method.outputArgs.isEmpty()) { hs << "void "; cs << "void "; } else { - QString type = method.outputArgs.first().type.toString(QDBusType::QVariantNames); - hs << type << " "; - cs << type << " "; + returnType = qtTypeName(method.outputArgs.first().type); + hs << returnType << " "; + cs << returnType << " "; } - QString name = makeQtName(method.name); + QString name = method.name; hs << name << "("; cs << className << "::" << name << "("; @@ -756,8 +799,8 @@ static void writeAdaptor(const char *adaptorFile, const QDBusIntrospection::Inte // create the return type int j = method.inputArgs.count(); - cs << " " << method.outputArgs.at(0).type.toString(QDBusType::QVariantNames) - << " " << argNames.at(j) << ";" << endl; + if (!returnType.isEmpty()) + cs << " " << returnType << " " << argNames.at(j) << ";" << endl; // make the call if (method.inputArgs.count() <= 10 && method.outputArgs.count() <= 1) { @@ -767,14 +810,14 @@ static void writeAdaptor(const char *adaptorFile, const QDBusIntrospection::Inte if (!method.outputArgs.isEmpty()) cs << ", Q_RETURN_ARG(" - << method.outputArgs.at(0).type.toString(QDBusType::QVariantNames) + << qtTypeName(method.outputArgs.at(0).type) << ", " << argNames.at(method.inputArgs.count()) << ")"; for (int i = 0; i < method.inputArgs.count(); ++i) cs << ", Q_ARG(" - << method.inputArgs.at(i).type.toString(QDBusType::QVariantNames) + << qtTypeName(method.inputArgs.at(i).type) << ", " << argNames.at(i) << ")"; @@ -814,8 +857,7 @@ static void writeAdaptor(const char *adaptorFile, const QDBusIntrospection::Inte if (signal.annotations.value("org.freedesktop.DBus.Deprecated") == "true") hs << "Q_DECL_DEPRECATED "; - QString name = makeQtName(signal.name); - hs << "void " << name << "("; + hs << "void " << signal.name << "("; QStringList argNames = makeArgNames(signal.outputArgs); writeArgList(hs, argNames, signal.outputArgs); @@ -830,6 +872,10 @@ static void writeAdaptor(const char *adaptorFile, const QDBusIntrospection::Inte // close the include guard hs << "#endif" << endl; + + if (includeMocs) + cs << endl + << "#include \"" << adaptorFile << ".moc\"" << endl; cs.flush(); hs.flush(); @@ -859,23 +905,22 @@ int main(int argc, char **argv) } /*! - \page dbusidl2cpp QtDBus IDL compiler (dbusidl2cpp) + \page dbusidl2cpp.html + \title QtDBus IDL compiler (dbusidl2cpp) The QtDBus IDL compiler is a tool that can be used to parse interface descriptions and produce static code representing those interfaces, which can then be used to make calls to remote objects or implement said interfaces. - \p %dbusidl2dcpp has two modes of operation, that correspond to the two possible outputs it can - produce: the interface (proxy) class or the adaptor class. The former is similar to the - \ref StandardInterfaces classes that are part of the QtDBus API and consists of a single .h file, - which should not be edited. The latter consists of both a C++ header and a source file, which - are meant to be edited and adapted to your needs. + \c dbusidl2dcpp has two modes of operation, that correspond to the two possible outputs it can + produce: the interface (proxy) class or the adaptor class.The latter consists of both a C++ + header and a source file, which are meant to be edited and adapted to your needs. - The \p %dbusidl2dcpp tool is not meant to be run every time you compile your + The \c dbusidl2dcpp tool is not meant to be run every time you compile your application. Instead, it's meant to be used when developing the code or when the interface changes. - The adaptor classes generated by \p %dbusidl2cpp are just a skeleton that must be completed. It + The adaptor classes generated by \c dbusidl2cpp are just a skeleton that must be completed. It generates, by default, calls to slots with the same name on the object the adaptor is attached to. However, you may modify those slots or the property accessor functions to suit your needs. */ diff --git a/qt/qdbusabstractadaptor.cpp b/qt/qdbusabstractadaptor.cpp index 4d6217a..e2ab096 100644 --- a/qt/qdbusabstractadaptor.cpp +++ b/qt/qdbusabstractadaptor.cpp @@ -31,9 +31,6 @@ #include "qdbusconnection_p.h" // for qDBusParametersForMethod #include "qdbusabstractadaptor_p.h" -/*! - \internal -*/ struct QDBusAdaptorInit { QSignalSpyCallbackSet callbacks; @@ -91,477 +88,8 @@ void QDBusAbstractAdaptorPrivate::saveIntrospectionXml(QDBusAbstractAdaptor *ada } /*! - \page UsingAdaptors Using Adaptors - - Adaptors are special classes that are attached to any QObject-derived class and provide the - interface to the external world using D-Bus. Adaptors are intended to be light-weight classes - whose main purpose is to relay calls to and from the real object, possibly validating or - converting the input from the external world and, thus, protecting the real object. - - Unlike multiple inheritance, adaptors can be added at any time to any object (but not removed), - which allows for greater flexibility when exporting existing classes. Another advantage of - adaptors is to provide similar but not identical functionality in methods of the same name in - different interfaces, a case which can be quite common when adding a new version of a standard - interface to an object. - - In order to use an adaptor, one must create a class which inherits QDBusAbstractAdaptor. Since - that is a standard QObject-derived class, the Q_OBJECT macro must appear in the declaration and - the source file must be processed with the \link moc \endlink tool. The class must also contain - one or more Q_CLASSINFO entries with the "D-Bus Interface" name, declaring which interfaces it - is exporting. - - Any public slot in the class will be accessible through the bus over messages of the MethodCall - type. (See \link DeclaringSlots \endlink for more information). Signals in the class will be - automatically relayed over D-Bus. However, not all types are allowed signals or slots' parameter - lists: see \link AllowedParameters \endlink for more information. - - Also, any property declared with Q_PROPERTY will be automatically exposed over the Properties - interface on D-Bus. Since the QObject property system does not allow for non-readable - properties, it is not possible to declare write-only properties using adaptors. - - More information: - - \subpage DeclaringSlots - - \subpage DeclaringSignals - - \subpage AllowedParameters - - \subpage UsingAnnotations - - \subpage AdaptorExample - - \sa QDBusAbstractAdaptor -*/ - -/*! - \page AdaptorExample Example of an interface implemented with an adaptor - - A sample usage of QDBusAbstractAdaptor is as follows: - \code - class MainApplicationAdaptor: public QDBusAbstractAdaptor - { - Q_OBJECT - Q_CLASSINFO("D-Bus Interface", "com.example.DBus.MainApplication") - Q_CLASSINFO("D-Bus Interface", "org.kde.DBus.MainApplication") - Q_PROPERTY(QString caption READ caption WRITE setCaption) - Q_PROPERTY(QString organizationName READ organizationName) - Q_PROPERTY(QString organizationDomain READ organizationDomain) - - private: - MyApplication *app; - - public: - MyInterfaceAdaptor(MyApplication *application) - : QDBusAbstractAdaptor(application), app(application) - { - connect(application, SIGNAL(aboutToQuit()), SIGNAL(aboutToQuit()); - connect(application, SIGNAL(focusChanged(QWidget*, QWidget*)), - SLOT(focusChangedSlot(QWidget*, QWidget*))); - } - - QString caption() - { - if (app->hasMainWindow()) - return app->mainWindow()->caption(); - return QString(); - } - - void setCaption(const QString &newCaption) - { - if (app->hasMainWindow()) - app->mainWindow()->setCaption(newCaption); - } - - QString organizationName() - { - return app->organizationName(); - } - - QString organizationDomain() - { - return app->organizationDomain(); - } - - public slots: - async void quit() - { app->quit(); } - - void reparseConfiguration() - { app->reparseConfiguration(); } - - QString mainWindowObject() - { - if (app->hasMainWindow()) - return QString("/%1/mainwindow").arg(app->applicationName()); - return QString(); - } - - void setSessionManagement(bool enable) - { - if (enable) - app->enableSessionManagement(); - else - app->disableSessionManagement(); - } - - private slots: - void focusChangedSlot(QWidget *, QWidget *now) - { - if (now == app->mainWindow()) - emit mainWindowHasFocus(); - } - - signals: - void aboutToQuit(); - void mainWindowHasFocus(); - }; - \endcode - - The code above would create an interface that could be represented more or less in the following - canonical representation: - \code - interface com.example.DBus.MainApplication - { - property readwrite STRING caption - property read STRING organizationName - property read STRING organizationDomain - - method quit() annotation("org.freedesktop.DBus.Method.NoReply", "true") - method reparseConfiguration() - method mainWindowObject(out STRING) - method disableSessionManagement(in BOOLEAN enable) - - signal aboutToQuit() - signal mainWindowHasFocus() - } - - interface org.kde.DBus.MainApplication - { - .... - } - \endcode - - This adaptor could be used in the application's constructor as follows: - \code - MyApplication::MyApplication() - { - [...] - - // create the MainApplication adaptor: - new MainApplicationAdaptor(this); - - // connect to D-Bus: - QDBusConnection connection = QDBusConnection::addConnection(QDBusConnection::SessionBus); - - // register us as an object: - connection.registerObject("/MainApplication", this); - - [...] - } - \endcode - - Break-down analysis: - - \subpage AdaptorExampleHeader - - \subpage AdaptorExampleProperties - - \subpage AdaptorExampleConstructor - - \subpage AdaptorExampleSlots - - \subpage AdaptorExampleSignals -*/ - -/*! - \page AdaptorExampleHeader The header - - The header of the example is: - \code - class MainApplicationAdaptor: public QDBusAbstractAdaptor - { - Q_OBJECT - Q_CLASSINFO("D-Bus Interface", "com.example.DBus.MainApplication") - Q_CLASSINFO("D-Bus Interface", "org.kde.DBus.MainApplication") - \endcode - - The code does the following: - - it declares the adaptor MainApplicationAdaptor, which descends from QDBusAbstractAdaptor - - it declares the Qt Meta Object data using the #Q_OBJECT macro - - it declares the names of two D-Bus interfaces it implements. Those interfaces are equal in all - aspects. -*/ - -/*! - \page AdaptorExampleProperties The properties - - The properties are declared as follows: - \code - Q_PROPERTY(QString caption READ caption WRITE setCaption) - Q_PROPERTY(QString organizationName READ organizationName) - Q_PROPERTY(QString organizationDomain READ organizationDomain) - \endcode - - And are implemented as follows: - \code - QString caption() - { - if (app->hasMainWindow()) - return app->mainWindow()->caption(); - return QString(); - } - - void setCaption(const QString &newCaption) - { - if (app->hasMainWindow()) - app->mainWindow()->setCaption(newCaption); - } - - QString organizationName() - { - return app->organizationName(); - } - - QString organizationDomain() - { - return app->organizationDomain(); - } - \endcode - - The code declares three properties: one of them is a read-write property called "caption" of - string type. The other two are read-only, also of the string type. - - The properties organizationName and organizationDomain are simple relays of the app object's - organizationName and organizationDomain properties. However, the caption property requires - verifying if the application has a main window associated with it: if there isn't any, the - caption property is empty. Note how it is possible to access data defined in other objects - through the getter/setter functions. - */ - -/*! - \page AdaptorExampleConstructor The constructor - - The constructor: - \code - MyInterfaceAdaptor(MyApplication *application) - : QDBusAbstractAdaptor(application), app(application) - { - connect(application, SIGNAL(aboutToQuit()), SIGNAL(aboutToQuit()); - connect(application, SIGNAL(focusChanged(QWidget*, QWidget*)), - SLOT(focusChangedSlot(QWidget*, QWidget*))); - } - \endcode - - The constructor does the following: - - it initialises its base class (QDBusAbstractAdaptor) with the parent object it is related to. - - it stores the app pointer in a member variable. Note that it would be possible to access the - same object using the QDBusAbstractAdaptor::object() function, but it would be necessary to - use \a static_cast<> to properly access the methods in MyApplication that are not part of - QObject. - - it connects the application's signal \a aboutToQuit to its own signal \a aboutToQuit. - - it connects the application's signal \a focusChanged to a private slot to do some further - processing before emitting a D-Bus signal. - - Note that there is no destructor in the example. An eventual destructor could be used to emit - one last signal before the object is destroyed, for instance. -*/ - -/*! - \page AdaptorExampleSlots Slots/methods - - The public slots in the example (which will be exported as D-Bus methods) are the following: - \code - public slots: - async void quit() - { app->quit(); } - - void reparseConfiguration() - { app->reparseConfiguration(); } - - QString mainWindowObject() - { - if (app->hasMainWindow()) - return QString("/%1/mainwindow").arg(app->applicationName()); - return QString(); - } - - void setSessionManagement(bool enable) - { - if (enable) - app->enableSessionManagement(); - else - app->disableSessionManagement(); - } - \endcode - - This snippet of code defines 4 methods with different properties each: - - \p quit: this method takes no parameters and is defined to be asynchronous. That is, callers - are expected to use "fire-and-forget" mechanism when calling this method, since it provides no - useful reply. This is represented in D-Bus by the use of the - org.freedesktop.DBus.Method.NoReply annotation. See #Q_ASYNC for more information on - asynchronous methods - - - \p reparseConfiguration: this simple method, with no input or output arguments simply relays - the call to the application's reparseConfiguration member function. - - - \p mainWindowObject: this method takes no input parameter, but returns one string output - argument, containing the path to the main window object (if the application has a main - window), or an empty string if it has no main window. Note that this method could have also - been written: void mainWindowObject(QString &path). - - - \p setSessionManagement: this method takes one input argument (a boolean) and, depending on - its value, it calls one function or another in the application. - - \sa #Q_ASYNC -*/ - -/*! - \page AdaptorExampleSignals Signals - - The signals in this example are defined as follows: - \code - signals: - void aboutToQuit(); - void mainWindowHasFocus(); - \endcode - - However, signal definition isn't enough: signals have to be emitted. One simple way of emitting - signals is to connect another signal to them, so that Qt's signal handling system chains them - automatically. This is what is done for the \a aboutToQuit signal (see \ref - AdaptorExampleConstructor). - - When this is the case, one can use the QDBusAbstractAdaptor::setAutoRelaySignals to - automatically connect every signal from the real object to the adaptor. - - When simple signal-to-signal connection isn't enough, one can use a private slot do do some - work. This is what was done for the mainWindowHasFocus signal: - \code - private slots: - void focusChangedSlot(QWidget *, QWidget *now) - { - if (now == app->mainWindow()) - emit mainWindowHasFocus(); - } - \endcode - - This private slot (which will not be exported as a method via D-Bus) was connected to the - \a focusChanged signal in the adaptor's constructor. It is therefore able to shape the - application's signal into what the interface expects it to be. -*/ - -/*! - \page DeclaringSlots Declaring slots - - Slots in D-Bus adaptors are declared just like normal, public slots, but their parameters must - follow certain rules (see \ref AllowedParameters for more information). Slots whose parameters - do not follow those rules or that are not public will not be accessible via D-Bus. - - Slots can be of three kinds: - -# Asynchronous - -# Input-only - -# Input-and-output - - \par Asynchronous slots - Asynchronous slots are those that do not normally return any reply to the caller. For that - reason, they cannot take any output parameters. In most cases, by the time the first line - of the slot is run, the caller function has already resumed working. - - \par - However, slots must rely on that behavior. Scheduling and message-dispatching issues could - change the order in which the slot is run. Code intending to synchronize with the caller - should provide its own method of synchronization. - - \par - Asynchronous slots are marked by the keyword \p #async or \p #Q_ASYNC in the method - signature, before the \p void return type and the slot name. (See the \p quit slot in the - \ref AdaptorExample "adaptor example"). - - \par Input-only slots - Input-only slots are normal slots that take parameters passed by value or by constant - reference. However, unlike asynchronous slots, the caller is usually waiting for completion - of the callee before resuming operation. Therefore, non-asynchronous slots should not block - or should state it its documentation that they may do so. - - \par - Input-only slots have no special marking in their signature, except that they take only - parameters passed by value or by constant reference. Optionally, slots can take a - QDBusMessage parameter as a last parameter, which can be used to perform additional - analysis of the method call message. - - \par Input and output slots - Like input-only slots, input-and-output slots are those that the caller is waiting for a - reply. Unlike input-only ones, though, this reply will contain data. Slots that output data - may contain non-constant references and may return a value as well. However, the output - parameters must all appear at the end of the argument list and may not have input arguments - interleaved. Optionally, a QDBusMessage argument may appear between the input and the - output arguments. - - \note When a caller places a method call and waits for a reply, it will only wait for so long. - Slots intending to take a long time to complete should make that fact clear in - documentation so that callers properly set higher timeouts. - - Method replies are generated automatically with the contents of the output parameters (if there - were any) by the QtDBus implementation. Slots need not worry about constructing proper - QDBusMessage objects and sending them over the connection. - - However, the possibility of doing so remains there. Should the slot find out it needs to send a - special reply or even an error, it can do so by using QDBusMessage::methodReply or - QDBusMessage::error on the QDBusMessage parameter and send it with QDBusConnection::send. The - QtDBus implementation will not generate any reply if the slot did so. - - \sa \ref UsingAdaptors, \ref DeclaringSignals, \ref AllowedParameters, QDBusConnection, - QDBusMessage -*/ - -/*! - \page DeclaringSignals Declaring signals - - Any signal in a class derived from QDBusAbstractAdaptor will be automatically relayed into - D-Bus, provided that the signal's parameters conform to certain rules (see \ref - AllowedParameters for more information). No special code is necessary to make this relay. - - However, signals must still be emitted. The easiest way to emit an adaptor signal is to connect - another signal to it, so that the Qt signal/slot mechanism automatically emits the adaptor - signal too. This can be done in the adaptor's constructor, as has been done in the \ref - AdaptorExample "adaptor example". - - The convenience function QDBusAbstractAdaptor::setAutoRelaySignals can also be used to connect - or disconnect every signal in the real object to the same signal in the adaptor. It will inspect - the list of signals in both classes and connect those that have exact parameter match. - - \sa \ref UsingAdaptors, \ref DeclaringSlots, \ref AllowedParameters, QDBusAbstractAdaptor -*/ - -/*! - \page AllowedParameters Allowed parameter types - - D-Bus has a very limited set of types that can be sent and received over the bus. They are - listed below, along with the D-Bus type they relate to: - - unsigned char / uchar (BYTE) - - short (INT16) - - unsigned short / ushort (UINT16) - - int (INT32) - - unsigned int / uint (UINT32) - - qlonglong (INT64) - - qulonglong (UINT64) - - bool (BOOLEAN) - - double (DOUBLE) - - QString (STRING) - - QByteArray (ARRAY of BYTE) - - QStringList (ARRAY of STRING) - - QVariant / QDBusVariant (VARIANT) - - QVariantList (ARRAY of VARIANT) - - QVariantMap (ARRAY of DICT_ENTRY of (STRING, VARIANT)) - - The last two types may be used to receive any array (except string and byte arrays), any structs - and any maps. However, it is currently not possible to generate external function definitions - containing specific types of lists, structs and maps. - - All of the types above may be passed by value or by constant reference for input arguments to - slots as well as the output arguments to signals. When used as output arguments for slots, they - can all be used as non-constant references or the return type. - - Additionally, slots can have one parameter of type \p const \p QDBusMessage \p \&, which must - appear at the end of the input parameter list, before any output parameters. Signals cannot have - this parameter. - - \warning You may not use any type that is not on the list above, including \a typedefs to the - types listed. This also includes QList<QVariant> and QMap<QString,QVariant>. -*/ - -/*! - \page UsingAnnotations Using annotations in adaptors + \page usingannotations.html + \title Using annotations in adaptors It is currently not possible to specify arbitrary annotations in adaptors. */ @@ -589,14 +117,12 @@ void QDBusAbstractAdaptorPrivate::saveIntrospectionXml(QDBusAbstractAdaptor *ada and must not be deleted by the user (they will be deleted automatically when the object they are connected to is also deleted). - \sa \ref UsingAdaptors, QDBusConnection + \sa {usingadaptors.html}{Using adaptors}, QDBusConnection */ /*! Constructs a QDBusAbstractAdaptor with \a parent as the object we refer to. - \param parent the real object we're the adaptor for - \warning Use object() to retrieve the object passed as \a parent to this constructor. The real parent object (as retrieved by QObject::parent()) may be something else. */ @@ -636,12 +162,12 @@ QObject* QDBusAbstractAdaptor::object() const Automatic signal relaying consists of signal-to-signal connection of the signals on the parent that have the exact same method signatue in both classes. - \param enable if set to true, connect the signals; if set to false, disconnect all signals + If \a enable is set to true, connect the signals; if set to false, disconnect all signals. */ void QDBusAbstractAdaptor::setAutoRelaySignals(bool enable) { const QMetaObject *us = metaObject(); - const QMetaObject *them = parent()->metaObject(); + const QMetaObject *them = object()->metaObject(); for (int idx = staticMetaObject.methodCount(); idx < us->methodCount(); ++idx) { QMetaMethod mm = us->method(idx); @@ -655,7 +181,7 @@ void QDBusAbstractAdaptor::setAutoRelaySignals(bool enable) sig.prepend(QSIGNAL_CODE + '0'); object()->disconnect(sig, this, sig); if (enable) - connect(object(), sig, sig, Qt::QueuedConnection); + connect(object(), sig, sig); } } @@ -752,8 +278,7 @@ void QDBusAdaptorConnector::relay(QObject *sender) // break down the parameter list QList<int> types; - QByteArray signature = QMetaObject::normalizedSignature(mm.signature()); - int inputCount = qDBusParametersForMethod(signature, types); + int inputCount = qDBusParametersForMethod(mm, types); if (inputCount == -1) // invalid signal signature // qDBusParametersForMethod has already complained @@ -766,6 +291,7 @@ void QDBusAdaptorConnector::relay(QObject *sender) return; } + QByteArray signature = QMetaObject::normalizedSignature(mm.signature()); signature.truncate(signature.indexOf('(')); // remove parameter decoration QVariantList args; diff --git a/qt/qdbusabstractinterface.cpp b/qt/qdbusabstractinterface.cpp new file mode 100644 index 0000000..127b161 --- /dev/null +++ b/qt/qdbusabstractinterface.cpp @@ -0,0 +1,266 @@ +/* -*- C++ -*- + * + * Copyright (C) 2005 Thiago Macieira <thiago@kde.org> + * Copyright (C) 2006 Trolltech AS. All rights reserved. + * Author: Thiago Macieira <thiago.macieira@trolltech.com> + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "qdbusabstractinterface.h" + +#include "qdbusabstractinterface_p.h" +#include "qdbusmetaobject_p.h" +#include "qdbusconnection_p.h" + +/*! + \class QDBusAbstractInterface + \brief Base class for all D-Bus interfaces in the QtDBus binding, allowing access to remote interfaces. + + Generated-code classes also derive from QDBusAbstractInterface, all methods described here are also + valid for generated-code classes. In addition to those described here, generated-code classes + provide member functions for the remote methods, which allow for compile-time checking of the + correct parameters and return values, as well as property type-matching and signal + parameter-matching. + + \sa {dbusidl2cpp.html}{The dbusidl2cpp compiler}, QDBusInterface +*/ + +/*! + \enum QDBusAbstractInterface::CallMode + + Specifies how a call should be placed. The valid options are: + \value NoWaitForReply place the call but don't wait for the reply (the reply's contents + will be discarded) + \value NoUseEventLoop don't use an event loop to wait for a reply, but instead block on + network operations while waiting. This option means the + user-interface may not be updated for the duration of the call. + \value UseEventLoop use the Qt event loop to wait for a reply. This option means the + user-interface will update, but it also means other events may + happen, like signal delivery and other D-Bus method calls. + + When using UseEventLoop, applications must be prepared for reentrancy in any function. +*/ + +/*! + \internal +*/ +QDBusAbstractInterface::QDBusAbstractInterface(QDBusAbstractInterfacePrivate* d) +#if QT_VERSION < 0x040200 + : d_ptr(d) +{ + d_ptr->q_ptr = this; +} +#endif + +/*! + Releases this object's resources. +*/ +QDBusAbstractInterface::~QDBusAbstractInterface() +{ + delete d_ptr; +} + +/*! + Returns the connection this interface is assocated with. +*/ +QDBusConnection QDBusAbstractInterface::connection() const +{ + return d_func()->conn; +} + +/*! + Returns the name of the service this interface is associated with. +*/ +QString QDBusAbstractInterface::service() const +{ + return d_func()->service; +} + +/*! + Returns the object path that this interface is associated with. +*/ +QString QDBusAbstractInterface::path() const +{ + return d_func()->path; +} + +/*! + Returns the name of this interface. +*/ +QString QDBusAbstractInterface::interface() const +{ + return d_func()->interface; +} + +/*! + Returns the error the last operation produced, or an invalid error if the last operation did not + produce an error. +*/ +QDBusError QDBusAbstractInterface::lastError() const +{ + return d_func()->lastError; +} + +/*! + \threadsafe + Places a call to the remote method specified by \a method on this interface, using \a args as + arguments. This function returns the message that was received as a reply, which can be a normal + QDBusMessage::ReplyMessage (indicating success) or QDBusMessage::ErrorMessage (if the call + failed). The \a mode parameter specifies how this call should be placed. + + If the call succeeds, lastError() will be cleared; otherwise, it will contain the error this + call produced. + + Normally, you should place calls using call(). + + \warning If you use \c UseEventLoop, your code must be prepared to deal with any reentrancy: + other method calls and signals may be delivered before this function returns, as well + as other Qt queued signals and events. +*/ +QDBusMessage QDBusAbstractInterface::callWithArgs(const QString& method, const QList<QVariant>& args, + CallMode mode) +{ + Q_D(QDBusAbstractInterface); + + QString m = method, sig; + // split out the signature from the method + int pos = method.indexOf(QLatin1Char('.')); + if (pos != -1) { + m.truncate(pos); + sig = method.mid(pos + 1); + } + + QDBusMessage msg = QDBusMessage::methodCall(service(), path(), interface(), m); + msg.setSignature(sig); + msg.QList<QVariant>::operator=(args); + + QDBusMessage reply; + if (mode != NoWaitForReply) + reply = d->conn.sendWithReply(msg, mode == UseEventLoop ? + QDBusConnection::UseEventLoop : QDBusConnection::NoUseEventLoop); + else + d->conn.send(msg); + + d->lastError = reply; // will clear if reply isn't an error + + // ensure that there is at least one element + if (reply.isEmpty()) + reply << QVariant(); + + return reply; +} + +/*! + \overload + Places a call to the remote method specified by \a method on this interface, using \a args as + arguments. This function will return immediately after queueing the call. The reply from the + remote function or any errors emitted by it will be delivered to the \a slot slot on object \a + receiver. + + This function returns true if the queueing succeeded: it does not indicate that the call + succeeded. If it failed, the slot will be called with an error message. lastError() will not be + set under those circumstances. + + \sa QDBusError, QDBusMessage +*/ +bool QDBusAbstractInterface::callWithArgs(const QString &method, QObject *receiver, const char *slot, + const QList<QVariant> &args) +{ + Q_D(QDBusAbstractInterface); + + QString m = method, sig; + // split out the signature from the method + int pos = method.indexOf(QLatin1Char('.')); + if (pos != -1) { + m.truncate(pos); + sig = method.mid(pos + 1); + } + + QDBusMessage msg = QDBusMessage::methodCall(service(), path(), interface(), m); + msg.setSignature(sig); + msg.QList<QVariant>::operator=(args); + + d->lastError = 0; // clear + return d->conn.sendWithReplyAsync(msg, receiver, slot); +} + +/*! + \internal + Catch signal connections. +*/ +void QDBusAbstractInterface::connectNotify(const char *signal) +{ + // someone connecting to one of our signals + Q_D(QDBusAbstractInterface); + + d->connp->connectRelay(d->service, d->path, d->interface, this, signal); +} + +/*! + \internal + Catch signal disconnections. +*/ +void QDBusAbstractInterface::disconnectNotify(const char *signal) +{ + // someone disconnecting from one of our signals + Q_D(QDBusAbstractInterface); + + d->connp->disconnectRelay(d->service, d->path, d->interface, this, signal); +} + +/*! + \overload + \fn QDBusMessage QDBusAbstractInterface::call(const QString &method) + + Calls the method \a method on this interface and passes the parameters to this function to the + method. + + The parameters to \c call are passed on to the remote function via D-Bus as input + arguments. Output arguments are returned in the QDBusMessage reply. If the reply is an error + reply, lastError() will also be set to the contents of the error message. + + This function is implemented by actually 9 different function overloads called \c call, so you + can pass up to 8 parameters to your function call, which can be of any type accepted by QtDBus + (see the \l {allowedparameters.html}{allowed parameters} page for information on what types are + accepted). + + It can be used the following way: + + \code + QString value = retrieveValue(); + QDBusMessage reply; + + QDBusReply<int> api = interface->call(QLatin1String("GetAPIVersion")); + if (api >= 14) + reply = interface->call(QLatin1String("ProcessWorkUnicode"), value); + else + reply = interface->call(QLatin1String("ProcessWork"), QLatin1String("UTF-8"), value.toUtf8()); + \endcode + + This example illustrates function calling with 0, 1 and 2 parameters and illustrates different + parameter types passed in each (the first call to \c "ProcessWorkUnicode" will contain one + Unicode string, the second call to \c "ProcessWork" will contain one string and one byte array). + + \warning This function reenters the Qt event loop in order to wait for the reply, excluding user + input. During the wait, it may deliver signals and other method calls to your + application. Therefore, it must be prepared to handle a reentrancy whenever a call is + placed with call(). +*/ + +#include "qdbusabstractinterface.moc" diff --git a/qt/qdbusabstractinterface.h b/qt/qdbusabstractinterface.h new file mode 100644 index 0000000..5c34677 --- /dev/null +++ b/qt/qdbusabstractinterface.h @@ -0,0 +1,169 @@ +/* -*- C++ -*- + * + * Copyright (C) 2005 Thiago Macieira <thiago@kde.org> + * Copyright (C) 2006 Trolltech AS. All rights reserved. + * Author: Thiago Macieira <thiago.macieira@trolltech.com> + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef QDBUSABSTRACTINTERFACE_H +#define QDBUSABSTRACTINTERFACE_H + +#include <QtCore/qstring.h> +#include <QtCore/qvariant.h> +#include <QtCore/qlist.h> +#include <QtCore/qobject.h> + +#include "qdbusmessage.h" +#include "qdbustypehelper_p.h" + +class QDBusConnection; +class QDBusError; + +class QDBusAbstractInterfacePrivate; +class QDBUS_EXPORT QDBusAbstractInterface: public QObject +{ + Q_OBJECT + +public: + enum CallMode { + NoWaitForReply, + UseEventLoop, + NoUseEventLoop + }; + +public: + virtual ~QDBusAbstractInterface(); + + QDBusConnection connection() const; + + QString service() const; + QString path() const; + QString interface() const; + + QDBusError lastError() const; + + QDBusMessage callWithArgs(const QString &method, const QList<QVariant> &args = QList<QVariant>(), + CallMode mode = UseEventLoop); + bool callWithArgs(const QString &method, QObject *receiver, const char *slot, + const QList<QVariant> &args = QList<QVariant>()); + + inline QDBusMessage call(const QString &m) + { + return callWithArgs(m); + } + +#ifndef Q_QDOC +private: + template<typename T> inline QVariant qvfv(const T &t) + { return QDBusTypeHelper<T>::toVariant(t); } + +public: + template<typename T1> + inline QDBusMessage call(const QString &m, const T1 &t1) + { + QList<QVariant> args; + args << qvfv(t1); + return callWithArgs(m, args); + } + + template<typename T1, typename T2> + inline QDBusMessage call(const QString &m, const T1 &t1, const T2 &t2) + { + QList<QVariant> args; + args << qvfv(t1) << qvfv(t2); + return callWithArgs(m, args); + } + + template<typename T1, typename T2, typename T3> + inline QDBusMessage call(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); + } + + template<typename T1, typename T2, typename T3, typename T4> + inline QDBusMessage call(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); + } + + template<typename T1, typename T2, typename T3, typename T4, typename T5> + inline QDBusMessage call(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); + } + + template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6> + inline QDBusMessage call(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); + } + + template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7> + inline QDBusMessage call(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); + } + + template<typename T1, typename T2, typename T3, typename T4, typename T5, + typename T6, typename T7, typename T8> + inline QDBusMessage call(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); + } +#endif + +protected: + QDBusAbstractInterface(QDBusAbstractInterfacePrivate *); + void connectNotify(const char *signal); + void disconnectNotify(const char *signal); + +private: + friend class QDBusInterface; + QDBusAbstractInterfacePrivate *d_ptr; // remove for Qt 4.2.0 + + Q_DECLARE_PRIVATE(QDBusAbstractInterface) + Q_DISABLE_COPY(QDBusAbstractInterface) +}; + +#endif diff --git a/qt/qdbusobject_p.h b/qt/qdbusabstractinterface_p.h index 181fceb..38cc422 100644 --- a/qt/qdbusobject_p.h +++ b/qt/qdbusabstractinterface_p.h @@ -1,5 +1,6 @@ /* * + * Copyright (C) 2006 Thiago José Macieira <thiago@kde.org> * Copyright (C) 2006 Trolltech AS. All rights reserved. * Author: Thiago Macieira <thiago.macieira@trolltech.com> * @@ -33,37 +34,34 @@ // // -#ifndef QDBUSOBJECTPRIVATE_H -#define QDBUSOBJECTPRIVATE_H +#ifndef QDBUSABSTRACTINTERFACEPRIVATE_H +#define QDBUSABSTRACTINTERFACEPRIVATE_H -#include "QtCore/qatomic.h" -#include "QtCore/qstringlist.h" -#include "qdbusobject.h" -#include "qdbusinterface.h" -#include "qdbusconnection_p.h" +#include "qdbusabstractinterface.h" +#include "qdbusconnection.h" +#include "qdbuserror.h" -class QDBusObject; -class QDBusInterface; -class QDBusXmlParser; +#define ANNOTATION_NO_WAIT "org.freedesktop.DBus.Method.NoReply" -class QDBusObjectPrivate: public QSharedData +class QDBusAbstractInterfacePrivate//: public QObjectPrivate { public: - inline QDBusObjectPrivate(QDBusConnectionPrivate* ptr, const QString &service, - const QString &path) - : parent(ptr), - data( ) - { - QDBusIntrospection::Object * d = ptr->findObject(service, path); - d->ref.ref(); - data = d; - } + Q_DECLARE_PUBLIC(QDBusAbstractInterface) + + QDBusAbstractInterface *q_ptr; // remove in Qt 4.2 + QDBusConnection conn; + QDBusConnectionPrivate *connp; + QString service; + QString path; + QString interface; + QDBusError lastError; - inline ~QDBusObjectPrivate() - { parent->disposeOf(this); } + inline QDBusAbstractInterfacePrivate(const QDBusConnection& con, QDBusConnectionPrivate *conp, + const QString &serv, const QString &p, const QString &iface) + : conn(con), connp(conp), service(serv), path(p), interface(iface) + { } + virtual ~QDBusAbstractInterfacePrivate() { } +}; - QDBusConnectionPrivate* parent; - const QDBusIntrospection::Object* data; -}; #endif diff --git a/qt/qdbusbus.cpp b/qt/qdbusbus.cpp new file mode 100644 index 0000000..02c231e --- /dev/null +++ b/qt/qdbusbus.cpp @@ -0,0 +1,302 @@ +/* -*- C++ -*- + * + * Copyright (C) 2006 Trolltech AS. All rights reserved. + * Author: Thiago Macieira <thiago.macieira@trolltech.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This file was generated by dbusidl2cpp version 0.3 + * when processing input file - + * + * dbusidl2cpp is Copyright (C) 2006 Trolltech AS. All rights reserved. + * + * This file has been hand-edited! Be careful when re-generating it! + * + */ + +#include "qdbusbus.h" + +#include <QtCore/QByteArray> +#include <QtCore/QList> +#include <QtCore/QMap> +#include <QtCore/QString> +#include <QtCore/QStringList> +#include <QtCore/QVariant> + +/* + * Implementation of interface class QDBusBusService + */ + +/*! + \class QDBusBusService + \brief Provides access to the D-Bus bus daemon service. + +*/ + +/*! + \enum QDBusBusService::RequestNameOption + + Flags for requesting a name on the bus. + + \value AllowReplacingName Allow another application requesting the same name to take the name + from this application. + \value ReplaceExistingName If another application already has the name and allows replacing, + take the name and assign it to us. + \value DoNotQueueName Without this flag, if an application requests a name that is already + owned and does not allow replacing, it will be queued until the + name is given up. If this flag is given, no queueing will be + performed and the requestName() call will simply fail. +*/ + +/*! + \enum QDBusBusService::RequestNameReply + + The possible return values from requestName(): + + \value PrimaryOwnerReply The caller is now the primary owner of the name. + \value InQueueReply The caller is in queue for the name, but does not own it. + \value NameExistsReply The name exists and could not be replaced, or the caller did + specify DoNotQueueName. + \value AlreadyOwnerReply The caller tried to request a name that it already owns. +*/ + +/*! + \enum QDBusBusService::ReleaseNameReply + + The possible return values from releaseName(): + + \value NameReleasedReply The caller released his claim on the name. + \value NameNonExistentReply The caller tried to release a name that did not exist. + \value NotOwnerReply The caller tried to release a name that it did not own or was not in + queue for. +*/ + +/*! + \enum QDBusBusService::StartServiceReply + + The possible return values from startServiceByName(): + + \value Success The service was successfully started. + \value AlreadyRunning The service was already running. +*/ + +/*! + \internal +*/ +const char *QDBusBusService::staticInterfaceName() +{ return "org.freedesktop.DBus"; } + + +/*! + \internal +*/ +QDBusBusService::QDBusBusService(QDBusAbstractInterfacePrivate *p) + : QDBusAbstractInterface(p) +{ + connect(this, SIGNAL(NameAcquired(QString)), this, SIGNAL(nameAcquired(QString))); + connect(this, SIGNAL(NameLost(QString)), this, SIGNAL(nameLost(QString))); + connect(this, SIGNAL(NameOwnerChanged(QString,QString,QString)), + this, SIGNAL(nameOwnerChanged(QString,QString,QString))); +} + +/*! + \internal +*/ +QDBusBusService::~QDBusBusService() +{ +} + +/*! + \fn QDBusBusService::hello() + \internal + Sends a "Hello" request to the bus service. You do not want to call this. +*/ +QDBusReply<QString> QDBusBusService::Hello() +{ + return call(QLatin1String("Hello")); +} + +/*! + \fn QDBusBusService::nameOwner(const QString &name) + Returns the unique connection name of the primary owner of the name \a name. If the requested + name doesn't have an owner, returns a org.freedesktop.DBus.Error.NameHasNoOwner error. +*/ +QDBusReply<QString> QDBusBusService::GetNameOwner(const QString &name) +{ + return call(QLatin1String("GetNameOwner.s"), name); +} + +/*! + \fn QDBusBusService::listNames() + Lists all names currently existing on the bus. +*/ +QDBusReply<QStringList> QDBusBusService::ListNames() +{ + return call(QLatin1String("ListNames")); +} + +/*! + \fn QDBusBusService::listQueuedOwners(const QString &service) + Returns a list of all unique connection names in queue for the service name \a service. +*/ +QDBusReply<QStringList> QDBusBusService::ListQueuedOwners(const QString &service) +{ + return call(QLatin1String("ListQueuedOwners.s"), service); +} + +/*! + \fn QDBusBusService::nameHasOwner(const QString &service) + Returns true if the service name \a service has an owner. +*/ +QDBusReply<bool> QDBusBusService::NameHasOwner(const QString &service) +{ + return call(QLatin1String("NameHasOwner.s"), service); +} + +/*! + \fn QDBusBusService::addMatch(const QString &rule) + Adds the rule \a rule for requesting messages from the bus. + + \sa removeMatch() +*/ +QDBusReply<void> QDBusBusService::AddMatch(const QString &rule) +{ + return call(QLatin1String("AddMatch.s"), rule); +} + +/*! + \fn QDBusBusService::removeMatch(const QString &rule) + Removes the rule \a rule, that had previously been added with addMatch(). +*/ +QDBusReply<void> QDBusBusService::RemoveMatch(const QString &rule) +{ + return call(QLatin1String("RemoveMatch.s"), rule); +} + +/*! + \fn QDBusBusService::connectionSELinuxSecurityContext(const QString &service) + Returns the SELinux security context of the process currently holding the bus service \a + service. +*/ +QDBusReply<QByteArray> QDBusBusService::GetConnectionSELinuxSecurityContext(const QString &service) +{ + return call(QLatin1String("GetConnectionSELinuxSecurityContext.s"), service); +} + +/*! + \fn QDBusBusService::connectionUnixProcessID(const QString &service) + Returns the Unix Process ID (PID) for the process currently holding the bus service \a service. +*/ +QDBusReply<uint> QDBusBusService::GetConnectionUnixProcessID(const QString &service) +{ + return call(QLatin1String("GetConnectionUnixProcessID.s"), service); +} + +/*! + \fn QDBusBusService::connectionUnixUser(const QString &service) + Returns the Unix User ID (UID) for the process currently holding the bus service \a service. +*/ +QDBusReply<uint> QDBusBusService::GetConnectionUnixUser(const QString &service) +{ + return call(QLatin1String("GetConnectionUnixUser.s"), service); +} + +/*! + \fn QDBusBusService::reloadConfig() + Asks the D-Bus server daemon to reload its configuration. +*/ +QDBusReply<void> QDBusBusService::ReloadConfig() +{ + return call(QLatin1String("ReloadConfig")); +} + +inline QDBUS_EXPORT int qDBusMetaTypeId(QDBusBusService::StartServiceReply *) +{ return QVariant::Int; } + +/*! + \fn QDBusBusService::startServiceByName(const QString &name, uint flags) + Requests that the bus start the service given by the name \a name. + + The \a flags parameter is currently not used. +*/ +QDBusReply<QDBusBusService::StartServiceReply> +QDBusBusService::StartServiceByName(const QString &name, uint flags) +{ + return call(QLatin1String("StartServiceByName.su"), name, flags); +} + +inline QDBUS_EXPORT int qDBusMetaTypeId(QDBusBusService::RequestNameReply *) +{ return QVariant::Int; } + +/*! + \fn QDBusBusService::requestName(const QString &service, RequestNameOptions flags) + Requests the bus service name \a service from the bus. The \a flags parameter specifies how the + bus server daemon should act when the same name is requested by two different applications. + + \sa releaseName() +*/ +QDBusReply<QDBusBusService::RequestNameReply> +QDBusBusService::RequestName(const QString &service, RequestNameOptions flags) +{ + return call(QLatin1String("RequestName.su"), service, uint(int(flags))); +} + +inline QDBUS_EXPORT int qDBusMetaTypeId(QDBusBusService::ReleaseNameReply *) +{ return QVariant::Int; } + +/*! + \fn QDBusBusService::releaseName(const QString &service) + Releases the claim on the bus service name \a service, that had been previously requested with + requestName(). If this application had ownership of the name, it will be released for other + applications to claim. If it only had the name queued, it gives up its position in the queue. +*/ +QDBusReply<QDBusBusService::ReleaseNameReply> +QDBusBusService::ReleaseName(const QString &service) +{ + return call(QLatin1String("ReleaseName.s"), service); +} + +// signals +/*! + \fn QDBusBusService::nameAcquired(const QString &service) + + This signal is emitted by the D-Bus bus server when the bus service name (unique connection name + or well-known service name) given by \a service is acquired by this application. + + Name acquisition happens after the application requested a name using requestName(). +*/ + +/*! + \fn QDBusBusService::nameLost(const QString &service) + + This signal is emitted by the D-Bus bus server when the application loses ownership of the bus + service name given by \a service. +*/ + +/*! + \fn QDBusBusService::nameOwnerChanged(const QString &name, const QString &oldOwner, const QString &newOwner) + + This signal is emitted by the D-Bus bus server whenever a name ownership change happens in the + bus, including apparition and disparition of names. + + This signal means the application \a oldOwner lost ownership of bus name \a name to application + \a newOwner. If \a oldOwner is an empty string, it means the name \a name has just been created; + if \a newOwner is empty, the name \a name has no current owner. +*/ + +#include "qdbusbus.moc" diff --git a/qt/qdbusbus.h b/qt/qdbusbus.h new file mode 100644 index 0000000..ae2720e --- /dev/null +++ b/qt/qdbusbus.h @@ -0,0 +1,158 @@ +/* -*- C++ -*- + * + * Copyright (C) 2006 Trolltech AS. All rights reserved. + * Author: Thiago Macieira <thiago.macieira@trolltech.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This file was generated by dbusidl2cpp version 0.3 + * when processing input file - + * + * dbusidl2cpp is Copyright (C) 2006 Trolltech AS. All rights reserved. + * + * This file has been hand-edited! Be careful when re-generating it! + * + */ + +#ifndef QDBUSBUS_H +#define QDBUSBUS_H + +#include <QtCore/qstringlist.h> + +#include "qdbusabstractinterface.h" +#include "qdbusreply.h" + +class QDBusConnection; +class QString; +class QByteArray; + +/* + * Proxy class for interface org.freedesktop.DBus + */ +class QDBUS_EXPORT QDBusBusService: public QDBusAbstractInterface +{ + Q_OBJECT + friend class QDBusConnection; + static inline const char *staticInterfaceName(); + + explicit QDBusBusService(QDBusAbstractInterfacePrivate *p); + + ~QDBusBusService(); + +public: + // taken out of http://dbus.freedesktop.org/doc/dbus-specification.html + // update if the standard updates + enum RequestNameOption { + AllowReplacingName = 0x1, + ReplaceExistingName = 0x2, + DoNotQueueName = 0x4 + }; + Q_DECLARE_FLAGS(RequestNameOptions, RequestNameOption) + + enum RequestNameReply { + PrimaryOwnerReply = 1, + InQueueReply = 2, + NameExistsReply = 3, + AlreadyOwnerReply = 4 + }; + + enum ReleaseNameReply { + NameReleasedReply = 1, + NameNonExistentReply = 2, + NotOwnerReply = 3 + }; + + enum StartServiceReply { + Success = 1, + AlreadyRunning = 2 + }; + +#ifndef Q_QDOC + // D-Bus names +public: // METHODS + QDBusReply<QString> Hello(); + QDBusReply<void> ReloadConfig(); + + QDBusReply<QStringList> ListNames(); + + QDBusReply<bool> NameHasOwner(const QString &service); + QDBusReply<QString> GetNameOwner(const QString &name); + QDBusReply<ReleaseNameReply> ReleaseName(const QString &service); + QDBusReply<RequestNameReply> RequestName(const QString &service, RequestNameOptions flags); + QDBusReply<QStringList> ListQueuedOwners(const QString &service); + + QDBusReply<void> AddMatch(const QString &rule); + QDBusReply<void> RemoveMatch(const QString &rule); + + QDBusReply<QByteArray> GetConnectionSELinuxSecurityContext(const QString &service); + QDBusReply<uint> GetConnectionUnixProcessID(const QString &service); + QDBusReply<uint> GetConnectionUnixUser(const QString &service); + + QDBusReply<StartServiceReply> StartServiceByName(const QString &name, uint flags); + +signals: // SIGNALS + void NameAcquired(const QString &service); + void NameLost(const QString &service); + void NameOwnerChanged(const QString &name, const QString &oldOwner, const QString &newOwner); +#endif + + // Qt-style naming +public slots: + QDBusReply<QString> hello() + { return Hello(); } + QDBusReply<void> reloadConfig() + { return ReloadConfig(); } + + QDBusReply<QStringList> listNames() + { return ListNames(); } + + QDBusReply<bool> nameHasOwner(const QString &service) + { return NameHasOwner(service); } + QDBusReply<QString> nameOwner(const QString &name) + { return GetNameOwner(name); } + QDBusReply<ReleaseNameReply> releaseName(const QString &service) + { return ReleaseName(service); } + QDBusReply<RequestNameReply> requestName(const QString &service, RequestNameOptions flags) + { return RequestName(service, flags); } + QDBusReply<QStringList> listQueuedOwners(const QString &service) + { return ListQueuedOwners(service); } + + QDBusReply<void> addMatch(const QString &rule) + { return AddMatch(rule); } + QDBusReply<void> removeMatch(const QString &rule) + { return RemoveMatch(rule); } + + QDBusReply<QByteArray> connectionSELinuxSecurityContext(const QString &service) + { return GetConnectionSELinuxSecurityContext(service); } + QDBusReply<uint> connectionUnixProcessID(const QString &service) + { return GetConnectionUnixProcessID(service); } + QDBusReply<uint> connectionUnixUser(const QString &service) + { return GetConnectionUnixUser(service); } + + QDBusReply<StartServiceReply> startServiceByName(const QString &name, uint flags) + { return StartServiceByName(name, flags); } + +signals: + void nameAcquired(const QString &service); + void nameLost(const QString &service); + void nameOwnerChanged(const QString &name, const QString &oldOwner, const QString &newOwner); +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(QDBusBusService::RequestNameOptions); + +#endif diff --git a/qt/qdbusconnection.cpp b/qt/qdbusconnection.cpp index 422b087..668cef5 100644 --- a/qt/qdbusconnection.cpp +++ b/qt/qdbusconnection.cpp @@ -24,13 +24,14 @@ #include <qdebug.h> #include <qcoreapplication.h> +#include <qstringlist.h> +#include "qdbusbus.h" #include "qdbusconnection.h" #include "qdbuserror.h" #include "qdbusmessage.h" #include "qdbusconnection_p.h" #include "qdbusinterface_p.h" -#include "qdbusobject_p.h" #include "qdbusutil.h" class QDBusConnectionManager @@ -97,6 +98,7 @@ void QDBusConnectionManager::setConnection(const QString &name, QDBusConnectionP /*! \fn QDBusConnection QDBus::sessionBus() + \relates QDBusConnection Returns a QDBusConnection object opened with the session bus. The object reference returned by this function is valid until the QCoreApplication's destructor is run, when the @@ -104,6 +106,7 @@ void QDBusConnectionManager::setConnection(const QString &name, QDBusConnectionP */ /*! \fn QDBusConnection QDBus::systemBus() + \relates QDBusConnection Returns a QDBusConnection object opened with the system bus. The object reference returned by this function is valid until the QCoreApplication's destructor is run, when the @@ -117,22 +120,22 @@ void QDBusConnectionManager::setConnection(const QString &name, QDBusConnectionP This class is the initial point in a D-Bus session. Using it, you can get access to remote objects, interfaces; connect remote signals to your object's slots; register objects, etc. - D-Bus connections are created using the QDBusConnection::addConnection function, which opens a + D-Bus connections are created using the QDBusConnection::addConnection() function, which opens a connection to the server daemon and does the initial handshaking, associating that connection with a name. Further attempts to connect using the same name will return the same connection. - The connection is then torn down using the QDBusConnection::closeConnection function. + The connection is then torn down using the QDBusConnection::closeConnection() function. - As a convenience for the two most common connection types, the QDBus::sessionBus and - QDBus::systemBus functions return open connections to the session server daemon and the system + As a convenience for the two most common connection types, the QDBus::sessionBus() and + QDBus::systemBus() functions return open connections to the session server daemon and the system server daemon, respectively. Those connections are opened when first used and are closed when the QCoreApplication destructor is run. D-Bus also supports peer-to-peer connections, without the need for a bus server daemon. Using this facility, two applications can talk to each other and exchange messages. This can be - achieved by passing an address to QDBusConnection::addConnection(const QString &, const QString - &) function, which was opened by another D-Bus application using QDBusServer. + achieved by passing an address to QDBusConnection::addConnection() + function, which was opened by another D-Bus application using QDBusServer. */ /*! @@ -146,15 +149,23 @@ void QDBusConnectionManager::setConnection(const QString &name, QDBusConnectionP On the Session Bus, one can find other applications by the same user that are sharing the same desktop session (hence the name). On the System Bus, however, processes shared for the whole system are usually found. - - \todo Find out what the ActivationBus is for */ /*! - \enum QDBusConnection::NameRequestMode - Specifies the flags for when requesting a name in the bus. + \enum QDBusConnection::WaitMode + Specifies the call waiting mode. + + \value UseEventLoop use the Qt Event Loop to wait for the reply + \value NoUseEventLoop don't use the event loop + + The \c UseEventLoop option allows for the application to continue to update its UI while the + call is performed, but it also opens up the possibility for reentrancy: socket notifiers may + fire, signals may be delivered and other D-Bus calls may be processed. The \c NoUseEventLoop + does not use the event loop, thus being safe from those problems, but it may block the + application for a noticeable period of time, in case the remote application fails to respond. - \bug Change the enum into flags and update with the new flags from the spec. + Also note that calls that go back to the local application can only be placed in \c UseEventLoop + mode. */ /*! @@ -169,21 +180,21 @@ void QDBusConnectionManager::setConnection(const QString &name, QDBusConnectionP \value ExportContents shorthand form for ExportSlots | ExportSignals | ExportProperties - \value ExportNonScriptableSlots export all of this object's slots, including + \value ExportAllSlots export all of this object's slots, including non-scriptable ones - \value ExportNonScriptableSignals export all of this object's signals, including + \value ExportAllSignals export all of this object's signals, including non-scriptable ones - \value ExportNonScriptableProperties export all of this object's properties, including + \value ExportAllProperties export all of this object's properties, including non-scriptable ones - \value ExportNonScriptableContents export all of this object's slots, signals and + \value ExportAllContents export all of this object's slots, signals and properties, including non-scriptable ones \value ExportChildObjects export this object's child objects - \note It is currently not possible to export signals from objects. If you pass the flag - ExportSignals or ExportNonScriptableSignals, the registerObject() function will print a warning. + \warning It is currently not possible to export signals from objects. If you pass the flag + ExportSignals or ExportAllSignals, the registerObject() function will print a warning. - \sa QDBusConnection::registerObject, QDBusAbstractAdaptor, \ref UsingAdaptors + \sa registerObject(), QDBusAbstractAdaptor, {usingadaptors.html}{Using adaptors} */ /*! @@ -198,7 +209,7 @@ void QDBusConnectionManager::setConnection(const QString &name, QDBusConnectionP */ /*! - Creates a QDBusConnection object attached to the connection with name \p name. + Creates a QDBusConnection object attached to the connection with name \a name. This does not open the connection. You have to call QDBusConnection::addConnection to open it. */ @@ -210,7 +221,7 @@ QDBusConnection::QDBusConnection(const QString &name) } /*! - Creates a copy of the \p other connection. + Creates a copy of the \a other connection. */ QDBusConnection::QDBusConnection(const QDBusConnection &other) { @@ -230,7 +241,7 @@ QDBusConnection::~QDBusConnection() } /*! - Creates a copy of the connection \p other in this object. The connection this object referenced + Creates a copy of the connection \a other in this object. The connection this object referenced before the copy is not spontaneously disconnected. See QDBusConnection::closeConnection for more information. */ @@ -247,8 +258,8 @@ QDBusConnection &QDBusConnection::operator=(const QDBusConnection &other) } /*! - Opens a connection of type \p type to one of the known busses and associate with it the - connection name \p name. Returns a QDBusConnection object associated with that connection. + Opens a connection of type \a type to one of the known busses and associate with it the + connection name \a name. Returns a QDBusConnection object associated with that connection. */ QDBusConnection QDBusConnection::addConnection(BusType type, const QString &name) { @@ -276,12 +287,25 @@ QDBusConnection QDBusConnection::addConnection(BusType type, const QString &name manager()->setConnection(name, d); - return QDBusConnection(name); + QDBusConnection retval(name); + + // create the bus service + QDBusAbstractInterfacePrivate *p; + p = retval.findInterface_helper(QLatin1String(DBUS_SERVICE_DBUS), + QLatin1String(DBUS_PATH_DBUS), + QLatin1String(DBUS_INTERFACE_DBUS)); + if (p) { + d->busService = new QDBusBusService(p); + d->busService->setParent(d); // auto-deletion + d->ref.deref(); // busService has a increased the refcounting to us + } + + return retval; } /*! - Opens a peer-to-peer connection on address \p address and associate with it the - connection name \p name. Returns a QDBusConnection object associated with that connection. + Opens a peer-to-peer connection on address \a address and associate with it the + connection name \a name. Returns a QDBusConnection object associated with that connection. */ QDBusConnection QDBusConnection::addConnection(const QString &address, const QString &name) @@ -299,11 +323,24 @@ QDBusConnection QDBusConnection::addConnection(const QString &address, manager()->setConnection(name, d); - return QDBusConnection(name); + QDBusConnection retval(name); + + // create the bus service + QDBusAbstractInterfacePrivate *p; + p = retval.findInterface_helper(QLatin1String(DBUS_SERVICE_DBUS), + QLatin1String(DBUS_PATH_DBUS), + QLatin1String(DBUS_INTERFACE_DBUS)); + if (p) { + d->busService = new QDBusBusService(p); + d->busService->setParent(d); // auto-deletion + d->ref.deref(); // busService has a increased the refcounting to us + } + + return retval; } /*! - Closes the connection of name \p name. + Closes the connection of name \a name. Note that if there are still QDBusConnection objects associated with the same connection, the connection will not be closed until all references are dropped. However, no further references @@ -321,10 +358,10 @@ void QDBusConnectionPrivate::timerEvent(QTimerEvent *e) } /*! - Sends the message over this connection, without waiting for a reply. This is suitable for errors, - signals, and return values as well as calls whose return values are not necessary. + Sends the \a message over this connection, without waiting for a reply. This is suitable for + errors, signals, and return values as well as calls whose return values are not necessary. - \returns true if the message was queued successfully, false otherwise + Returns true if the message was queued successfully, false otherwise. */ bool QDBusConnection::send(const QDBusMessage &message) const { @@ -334,14 +371,14 @@ bool QDBusConnection::send(const QDBusMessage &message) const } /*! - Sends the message over this connection and returns immediately after queueing it. When the reply - is received, the slot \p method is called in the object \p receiver. This function is suitable - for method calls only. + Sends the \a message over this connection and returns immediately after queueing it. When the + reply is received, the slot \a method is called in the object \a receiver. This function is + suitable for method calls only. This function guarantees that the slot will be called exactly once with the reply, as long as the parameter types match. If they don't, the reply cannot be delivered. - \returns true if the message was queued successfully, false otherwise. + Returns the identification of the message that was sent or 0 if nothing was sent. */ int QDBusConnection::sendWithReplyAsync(const QDBusMessage &message, QObject *receiver, const char *method) const @@ -353,67 +390,34 @@ int QDBusConnection::sendWithReplyAsync(const QDBusMessage &message, QObject *re } /*! - Sends the message over this connection and blocks, waiting for a reply. This function is + Sends the \a message over this connection and blocks, waiting for a reply. This function is suitable for method calls only. It returns the reply message as its return value, which will be either of type QDBusMessage::ReplyMessage or QDBusMessage::ErrorMessage. See the QDBusInterface::call function for a more friendly way of placing calls. - \warning This function reenters the Qt event loop in order to wait for the reply, excluding user - input. During the wait, it may deliver signals and other method calls to your - application. Therefore, it must be prepared to handle a reentrancy whenever a call is - placed with sendWithReply(). + \warning If \a mode is \c UseEventLoop, this function will reenter the Qt event loop in order to + wait for the reply. During the wait, it may deliver signals and other method calls to + your application. Therefore, it must be prepared to handle a reentrancy whenever a call + is placed with sendWithReply. */ -QDBusMessage QDBusConnection::sendWithReply(const QDBusMessage &message) const +QDBusMessage QDBusConnection::sendWithReply(const QDBusMessage &message, WaitMode mode) const { if (!d || !d->connection) - return QDBusMessage::fromDBusMessage(0, *this); - - if (!QCoreApplication::instance()) { - DBusMessage *msg = message.toDBusMessage(); - if (!msg) - return QDBusMessage::fromDBusMessage(0, *this); - - DBusMessage *reply = dbus_connection_send_with_reply_and_block(d->connection, msg, - -1, &d->error); - d->handleError(); - dbus_message_unref(msg); - - if (lastError().isValid()) - return QDBusMessage::fromError(lastError()); - - return QDBusMessage::fromDBusMessage(reply, *this); - } else { - QDBusReplyWaiter waiter; - if (d->sendWithReplyAsync(message, &waiter, SLOT(reply(const QDBusMessage&))) > 0) { - // enter the event loop and wait for a reply - waiter.exec(QEventLoop::ExcludeUserInputEvents | QEventLoop::WaitForMoreEvents); - - d->lastError = waiter.replyMsg; // set or clear error - return waiter.replyMsg; - } - - return QDBusMessage::fromDBusMessage(0, *this); - } + return QDBusMessage(); + return d->sendWithReply(message, mode); } /*! - Connects the signal to the slot \p slot in object \p receiver. - - \param service the service that will emit the signal, or QString() to wait for the signal - coming from any remote application - \param path the path that will emit the signal, or QString() to wait for the signal - coming from any object path (usually associated with an empty \p service) - \param interface the name of the interface to for this signal - \param name the name of the signal - \param receiver the object to connect to - \param slot the slot that will be invoked when the signal is emitted - \returns true if the connection was successful - - \note The signal will only be delivered to the slot if the parameters match. This verification - can be done only when the signal is received, not at connection time. - - \bug does not allow an empty service + Connects the signal specified by the \a service, \a path, \a interface and \a name parameters to + the slot \a slot in object \a receiver. The arguments \a service and \a path can be empty, + denoting a connection to any signal of the \a interface - \a name pair, from any remote + application. + + Returns true if the connection was successful. + + \warning The signal will only be delivered to the slot if the parameters match. This verification + can be done only when the signal is received, not at connection time. */ bool QDBusConnection::connect(const QString &service, const QString &path, const QString& interface, const QString &name, QObject *receiver, const char *slot) @@ -423,12 +427,10 @@ bool QDBusConnection::connect(const QString &service, const QString &path, const /*! \overload - Connects the signal to the slot \p slot in object \p receiver. Unlike the other + Connects the signal to the slot \a slot in object \a receiver. Unlike the other QDBusConnection::connect overload, this function allows one to specify the parameter signature - to be connected. The function will then verify that this signature can be delivered to the slot - specified by \p slot and return false otherwise. - - \bug does not validate signature vs slot yet + to be connected using the \a signature variable. The function will then verify that this + signature can be delivered to the slot specified by \a slot and return false otherwise. */ bool QDBusConnection::connect(const QString &service, const QString &path, const QString& interface, const QString &name, const QString &signature, @@ -439,7 +441,7 @@ bool QDBusConnection::connect(const QString &service, const QString &path, const QString source; if (!service.isEmpty()) { - source = getNameOwner(service); + source = d->getNameOwner(service); if (source.isEmpty()) return false; } @@ -456,6 +458,7 @@ bool QDBusConnection::connect(const QString &service, const QString &path, const hook.obj = receiver; // avoid duplicating: + QWriteLocker locker(&d->lock); QDBusConnectionPrivate::SignalHookHash::ConstIterator it = d->signalHooks.find(source); for ( ; it != d->signalHooks.end() && it.key() == source; ++it) { const QDBusConnectionPrivate::SignalHook &entry = it.value(); @@ -475,11 +478,12 @@ bool QDBusConnection::connect(const QString &service, const QString &path, const } /*! - Registers the object \p object at path \p path and returns true if the registration was - successful. + Registers the object \a object at path \a path and returns true if the registration was + successful. The \a options parameter specifies how much of the object \a object will be exposed + through D-Bus. This function does not replace existing objects: if there is already an object registered at - path \p path, this function will return false. Use unregisterObject() to unregister it first. + path \a path, this function will return false. Use unregisterObject() to unregister it first. You cannot register an object as a child object of an object that was registered with QDBusConnection::ExportChildObjects. @@ -552,8 +556,8 @@ bool QDBusConnection::registerObject(const QString &path, QObject *object, Regis } /*! - Unregisters an object that was registered with the registerObject() function and, if \p mode is - QDBusConnection::UnregisterTree, all of its sub-objects too. + Unregisters an object that was registered with the registerObject() at the object path given by + \a path and, if \a mode is QDBusConnection::UnregisterTree, all of its sub-objects too. Note that you cannot unregister objects that were not registered with registerObject(). */ @@ -594,61 +598,81 @@ void QDBusConnection::unregisterObject(const QString &path, UnregisterMode mode) } /*! - Returns a QDBusInterface associated with the interface \p interface on object at path \p path on - service \p service. -*/ -QDBusInterface QDBusConnection::findInterface(const QString& service, const QString& path, - const QString& interface) -{ - // create one - QDBusInterfacePrivate *priv = new QDBusInterfacePrivate(*this); - - if (!(interface.isEmpty() || QDBusUtil::isValidInterfaceName(interface)) || - !QDBusUtil::isValidObjectPath(path)) - return QDBusInterface(priv); - - // check if it's there first - QString owner = getNameOwner(service); - if (owner.isEmpty()) - return QDBusInterface(priv); + Returns a dynamic QDBusInterface associated with the interface \a interface on object at path \a + path on service \a service. - // getNameOwner returns empty if d is 0 - Q_ASSERT(d); - priv->service = owner; - priv->path = path; - priv->data = d->findInterface(interface).constData(); + This function creates a new object. It is your resposibility to ensure it is properly deleted + (you can use all normal QObject deletion mechanisms, including the QObject::deleteLater() slot + and QObject::setParent()). - return QDBusInterface(priv); // will increment priv's refcount + If the searching for this interface on the remote object failed, this function returns 0. +*/ +QDBusInterface *QDBusConnection::findInterface(const QString& service, const QString& path, + const QString& interface) +{ + if (!d) + return 0; + + QDBusInterfacePrivate *p = d->findInterface(service, path, interface); + if (!p) + return 0; + QDBusInterface *retval = new QDBusInterface(p); + retval->setParent(d); + return retval; } /*! \fn QDBusConnection::findInterface(const QString &service, const QString &path) - Returns an interface of type \p Interface associated with the object on path \p path at service - \p service. + Returns an interface of type \c Interface associated with the object on path \a path at service + \a service. + + \c Interface must be a class generated by \l {dbusidl2cpp.html}. - \p Interface must be a class derived from QDBusInterface. + This function creates a new object. It is your resposibility to ensure it is properly deleted + (you can use all normal QObject deletion mechanisms, including the QObject::deleteLater() slot + and QObject::setParent()). */ /*! - Returns a QDBusObject associated with the object on path \p path at service \p service. + Returns a QDBusBusService object that represents the D-Bus bus service on this connection. + + This function returns 0 for peer-to-peer connections. */ -QDBusObject QDBusConnection::findObject(const QString& service, const QString& path) +QDBusBusService *QDBusConnection::busService() const { - QDBusObjectPrivate* priv = 0; - if (d && QDBusUtil::isValidObjectPath(path)) { - QString owner = getNameOwner(service); + if (!d) + return 0; + return d->busService; +}; - if (!owner.isEmpty()) - priv = new QDBusObjectPrivate(d, owner, path); - } - return QDBusObject(priv, *this); +QDBusAbstractInterfacePrivate * +QDBusConnection::findInterface_helper(const QString &service, const QString &path, + const QString &interface) +{ + if (!d) + return 0; + if (!interface.isEmpty() && !QDBusUtil::isValidInterfaceName(interface)) + return 0; + + QString owner; + if (!service.isEmpty()) { + if (!QDBusUtil::isValidObjectPath(path)) + return 0; + + // check if it's there first -- FIXME: add binding mode + owner = d->getNameOwner(service); + if (owner.isEmpty()) + return 0; + } else if (!path.isEmpty()) + return 0; + + return new QDBusAbstractInterfacePrivate(*this, d, owner, path, interface); } - /*! Returns true if this QDBusConnection object is connected. - \note If it isn't connected, calling QDBusConnection::addConnection on the same connection name + If it isn't connected, calling QDBusConnection::addConnection on the same connection name will not make be connected. You need to call the QDBusConnection constructor again. */ bool QDBusConnection::isConnected( ) const @@ -686,130 +710,55 @@ QString QDBusConnection::baseService() const : QString(); } -/*! - Sends a request to the D-Bus server daemon to request the service name \p name. The flags \p - mode indicate how to proceed if the name is already taken or when another D-Bus client requests - the same name. - - Service names are used to publish well-known services on the D-Bus bus, by associating a - friendly name to this connection. Other D-Bus clients will then be able to contact this - connection and the objects registered on it by using this name instead of the unique connection - name (see baseService()). This also allows one application to always have the same name, while - its unique connection name changes. - - This function has no meaning in peer-to-peer connections. - - This function returns true if the name is assigned to this connection now (including the case - when it was already assigned). - - \todo probably move to the QObject representing the bus - \todo update the NameRequestMode flags -*/ -bool QDBusConnection::requestName(const QString &name, NameRequestMode mode) -{ - static const int DBusModes[] = { DBUS_NAME_FLAG_ALLOW_REPLACEMENT, 0, - DBUS_NAME_FLAG_REPLACE_EXISTING | DBUS_NAME_FLAG_ALLOW_REPLACEMENT}; - - int retval = dbus_bus_request_name(d->connection, name.toUtf8(), DBusModes[mode], &d->error); - d->handleError(); - return retval == DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER || - retval == DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER; -} - -/*! - Releases a name that had been requested using requestName(). This function returns true if the - name has been released, false otherwise. - - This function has no meaning in peer-to-peer connections. - - You cannot cause a name owned by another application to be released using releaseName(). Use - requestName() instead to assign it to your application. - - \todo probably move to the QObject representing the bus -*/ -bool QDBusConnection::releaseName(const QString &name) -{ - int retval = dbus_bus_release_name(d->connection, name.toUtf8(), &d->error); - d->handleError(); - if (lastError().isValid()) - return false; - return retval == DBUS_RELEASE_NAME_REPLY_RELEASED; -} - -/*! - Returns the unique connection name of the client that currently has the \p name - requested. Returns an empty QString in case there is no such name on the bus or if \p name is - not a well-formed bus name. +Q_GLOBAL_STATIC(QMutex, defaultBussesMutex); +static const char sessionBusName[] = "qt_default_session_bus"; +static const char systemBusName[] = "qt_default_system_bus"; +static QDBusConnection *sessionBus = 0; +static QDBusConnection *systemBus = 0; - \todo probably move to the QObject representing the bus -*/ -QString QDBusConnection::getNameOwner(const QString& name) +static void closeConnections() { - if (QDBusUtil::isValidUniqueConnectionName(name)) - return name; - if (!d || !QDBusUtil::isValidBusName(name)) - return QString(); - - QDBusMessage msg = QDBusMessage::methodCall(QLatin1String(DBUS_SERVICE_DBUS), - QLatin1String(DBUS_PATH_DBUS), QLatin1String(DBUS_INTERFACE_DBUS), - QLatin1String("GetNameOwner")); - msg << name; - QDBusMessage reply = sendWithReply(msg); - if (!lastError().isValid() && reply.type() == QDBusMessage::ReplyMessage) - return reply.first().toString(); - return QString(); + QMutexLocker locker(defaultBussesMutex()); + delete sessionBus; + delete systemBus; + QDBusConnection::closeConnection(QLatin1String(sessionBusName)); + QDBusConnection::closeConnection(QLatin1String(systemBusName)); + sessionBus = systemBus = 0; } -/*! - \internal -*/ -template<int type> -struct DefaultBus +static QDBusConnection *openConnection(QDBusConnection::BusType type) { - DefaultBus() - { - QDBusConnection con = QDBusConnection::addConnection(QDBusConnection::BusType(type), - QLatin1String(busName)); - bus = new QDBusConnection(con); - qAddPostRoutine(clear); - } - - ~DefaultBus() - { - delete bus; - } - - static void clear() - { - delete bus; - bus = 0; - QDBusConnection::closeConnection(QLatin1String(busName)); + QMutexLocker locker(defaultBussesMutex()); + qAddPostRoutine(closeConnections); + + if (type == QDBusConnection::SystemBus) { + if (systemBus) + // maybe it got created before we locked the mutex + return systemBus; + systemBus = new QDBusConnection(QDBusConnection::addConnection(QDBusConnection::SystemBus, + QLatin1String(systemBusName))); + return systemBus; + } else { + if (sessionBus) + // maybe it got created before we locked the mutex + return sessionBus; + sessionBus = new QDBusConnection(QDBusConnection::addConnection(QDBusConnection::SessionBus, + QLatin1String(sessionBusName))); + return sessionBus; } - - static QDBusConnection *bus; - static const char busName[]; -}; - -Q_GLOBAL_STATIC(DefaultBus<QDBusConnection::SessionBus>, sessionBusPtr); -Q_GLOBAL_STATIC(DefaultBus<QDBusConnection::SystemBus>, systemBusPtr); - -template<> -QT_STATIC_CONST_IMPL char DefaultBus<QDBusConnection::SessionBus>::busName[] = "qt_default_session_bus"; -template<> -QT_STATIC_CONST_IMPL char DefaultBus<QDBusConnection::SystemBus>::busName[] = "qt_default_system_bus"; - -template<> QDBusConnection *DefaultBus<QDBusConnection::SessionBus>::bus = 0; -template<> QDBusConnection *DefaultBus<QDBusConnection::SystemBus>::bus = 0; +} namespace QDBus { QDBusConnection &sessionBus() { - return *sessionBusPtr()->bus; + if (::sessionBus) return *::sessionBus; + return *openConnection(QDBusConnection::SessionBus); } QDBusConnection &systemBus() { - return *systemBusPtr()->bus; + if (::systemBus) return *::systemBus; + return *openConnection(QDBusConnection::SystemBus); } } diff --git a/qt/qdbusconnection.h b/qt/qdbusconnection.h index dc3eb47..60116e1 100644 --- a/qt/qdbusconnection.h +++ b/qt/qdbusconnection.h @@ -28,20 +28,19 @@ #include "qdbusmacros.h" #include <QtCore/qstring.h> -class QDBusConnectionPrivate; -class QDBusXmlParser; -class QDBusObject; +class QDBusAbstractInterfacePrivate; class QDBusInterface; class QDBusError; class QDBusMessage; -class QByteArray; +class QDBusBusService; class QObject; +class QDBusConnectionPrivate; class QDBUS_EXPORT QDBusConnection { public: enum BusType { SessionBus, SystemBus, ActivationBus }; - enum NameRequestMode { NoReplace = 0, ProhibitReplace = 1, ReplaceExisting = 2 }; + enum WaitMode { UseEventLoop, NoUseEventLoop }; enum RegisterOption { ExportAdaptors = 0x01, @@ -50,10 +49,10 @@ public: ExportProperties = 0x40, ExportContents = 0xf0, - ExportNonScriptableSlots = 0x110, - ExportNonScriptableSignals = 0x220, - ExportNonScriptableProperties = 0x440, - ExportNonScriptableContents = 0xff0, + ExportAllSlots = 0x110, + ExportAllSignals = 0x220, + ExportAllProperties = 0x440, + ExportAllContents = 0xff0, ExportChildObjects = 0x1000 }; @@ -75,7 +74,7 @@ public: QDBusError lastError() const; bool send(const QDBusMessage &message) const; - QDBusMessage sendWithReply(const QDBusMessage &message) const; + QDBusMessage sendWithReply(const QDBusMessage &message, WaitMode mode = UseEventLoop) const; int sendWithReplyAsync(const QDBusMessage &message, QObject *receiver, const char *slot) const; @@ -87,42 +86,38 @@ public: bool registerObject(const QString &path, QObject *object, RegisterOptions options = ExportAdaptors); - void unregisterObject(const QString &path, UnregisterMode = UnregisterNode); - - QDBusObject findObject(const QString& service, const QString& path); - QDBusInterface findInterface(const QString& service, const QString& path, const QString& interface); + void unregisterObject(const QString &path, UnregisterMode mode = UnregisterNode); -#ifndef QT_NO_MEMBER_TEMPLATES template<class Interface> - inline Interface findInterface(const QString &service, const QString &path) - { return Interface(findObject(service, path)); } -#endif + inline Interface *findInterface(const QString &service, const QString &path); + QDBusInterface *findInterface(const QString& service, const QString& path, + const QString& interface = QString()); - bool requestName(const QString &name, NameRequestMode mode = NoReplace); - bool releaseName(const QString& name); - QString getNameOwner(const QString& name); + QDBusBusService *busService() const; - static QDBusConnection addConnection(BusType type, - const QString &name); - static QDBusConnection addConnection(const QString &address, - const QString &name); + static QDBusConnection addConnection(BusType type, const QString &name); + static QDBusConnection addConnection(const QString &address, const QString &name); static void closeConnection(const QString &name); private: - friend class QDBusObject; + QDBusAbstractInterfacePrivate *findInterface_helper(const QString &, const QString &, + const QString&); QDBusConnectionPrivate *d; }; -namespace QDBus { - QDBusConnection &sessionBus(); - QDBusConnection &systemBus(); -} - template<class Interface> -inline Interface qDBusConnectionFindInterface(QDBusConnection &connection, const QString &service, - const QString &path) +inline Interface *QDBusConnection::findInterface(const QString &service, const QString &path) { - return Interface(connection.findObject(service, path)); + register QDBusAbstractInterfacePrivate *d; + d = findInterface_helper(service, path, Interface::staticInterfaceName()); + if (d) + return new Interface(d); + return 0; +} + +namespace QDBus { + QDBUS_EXPORT QDBusConnection &sessionBus(); + QDBUS_EXPORT QDBusConnection &systemBus(); } Q_DECLARE_OPERATORS_FOR_FLAGS(QDBusConnection::RegisterOptions) diff --git a/qt/qdbusconnection_p.h b/qt/qdbusconnection_p.h index 7904a84..53cb436 100644 --- a/qt/qdbusconnection_p.h +++ b/qt/qdbusconnection_p.h @@ -52,13 +52,17 @@ #include <dbus/dbus.h> #include "qdbusmessage.h" -#include "qdbusintrospection.h" class QDBusMessage; class QSocketNotifier; class QTimerEvent; class QDBusObjectPrivate; class CallDeliveryEvent; +class QMetaMethod; +class QDBusInterfacePrivate; +class QDBusMetaObject; +class QDBusAbstractInterface; +class QDBusBusService; typedef struct DBusConnection; typedef struct DBusServer; @@ -119,8 +123,7 @@ public: typedef QMultiHash<int, Watcher> WatcherHash; typedef QHash<int, DBusTimeout *> TimeoutHash; typedef QMultiHash<QString, SignalHook> SignalHookHash; - typedef QHash<QString, QSharedDataPointer<QDBusIntrospection::Interface> > KnownInterfacesHash; - typedef QHash<QString, QDBusIntrospection::Object* > KnownObjectsHash; + typedef QHash<QString, QDBusMetaObject* > MetaObjectHash; public: // public methods @@ -134,23 +137,24 @@ public: void closeConnection(); void timerEvent(QTimerEvent *e); + QString getNameOwner(const QString &service); + bool send(const QDBusMessage &message) const; + QDBusMessage sendWithReply(const QDBusMessage &message, int mode); int sendWithReplyAsync(const QDBusMessage &message, QObject *receiver, - const char *method) const; + const char *method); void connectSignal(const QString &key, const SignalHook &hook); void registerObject(const ObjectTreeNode *node); + void connectRelay(const QString &service, const QString &path, const QString &interface, + QDBusAbstractInterface *receiver, const char *signal); + void disconnectRelay(const QString &service, const QString &path, const QString &interface, + QDBusAbstractInterface *receiver, const char *signal); bool handleSignal(const QString &path, const QDBusMessage &msg); bool handleSignal(const QDBusMessage &msg); bool handleObjectCall(const QDBusMessage &message); bool handleError(); - void disposeOfLocked(QDBusIntrospection::Object* obj); - void disposeOf(QDBusObjectPrivate* obj); - QSharedDataPointer<QDBusIntrospection::Interface> findInterface(const QString& name); - QDBusIntrospection::Object* findObject(const QString& service, - const QString& path); - bool activateSignal(const SignalHook& hook, const QDBusMessage &msg); bool activateCall(QObject* object, int flags, const QDBusMessage &msg); bool activateObject(const ObjectTreeNode *node, const QDBusMessage &msg); @@ -160,9 +164,16 @@ public: CallDeliveryEvent *postedCallDeliveryEvent(); void deliverCall(const CallDeliveryEvent &data) const; + QDBusInterfacePrivate *findInterface(const QString &service, const QString &path, + const QString &interface); + protected: virtual void customEvent(QEvent *event); +private: + QDBusMetaObject *findMetaObject(const QString &service, const QString &path, + QString &interface); + public slots: // public slots void socketRead(int); @@ -182,6 +193,7 @@ public: ConnectionMode mode; DBusConnection *connection; DBusServer *server; + QDBusBusService *busService; WatcherHash watchers; TimeoutHash timeouts; @@ -189,20 +201,18 @@ public: QList<DBusTimeout *> pendingTimeouts; ObjectTreeNode rootNode; + MetaObjectHash cachedMetaObjects; QMutex callDeliveryMutex; CallDeliveryEvent *callDeliveryState; // protected by the callDeliveryMutex mutex public: - // public mutable member variables - mutable KnownInterfacesHash knownInterfaces; - mutable KnownObjectsHash knownObjects; - -public: // static methods static int messageMetaType; static int registerMessageMetaType(); static int findSlot(QObject *obj, const char *slotName, QList<int>& params); + static DBusHandlerResult messageFilter(DBusConnection *, DBusMessage *, void *); + static void messageResultReceived(DBusPendingCall *, void *); }; class QDBusReplyWaiter: public QEventLoop @@ -215,7 +225,7 @@ public slots: void reply(const QDBusMessage &msg); }; -extern int qDBusParametersForMethod(const QByteArray &sig, QList<int>& metaTypes); +extern int qDBusParametersForMethod(const QMetaMethod &mm, QList<int>& metaTypes); extern int qDBusNameToTypeId(const char *name); extern bool qDBusCheckAsyncTag(const char *tag); diff --git a/qt/qdbuserror.cpp b/qt/qdbuserror.cpp index ec066e1..d5cd675 100644 --- a/qt/qdbuserror.cpp +++ b/qt/qdbuserror.cpp @@ -25,10 +25,73 @@ #include "qdbuserror.h" #include <qdebug.h> +#include <qvarlengtharray.h> #include <dbus/dbus.h> #include "qdbusmessage.h" +struct ErrorMessageMapping +{ + ErrorMessageMapping(); + QVarLengthArray<const char*, QDBusError::qKnownErrorsMax> messages; + + inline const char *get(QDBusError::KnownErrors code) const + { + if (code <= QDBusError::Other || code > QDBusError::qKnownErrorsMax) + return messages[int(QDBusError::Other) - 1]; + return messages[int(code) - 1]; + } + + inline QDBusError::KnownErrors get(const char *name) const + { + if (!name || !*name) + return QDBusError::NoError; + for (int i = QDBusError::Other; i <= QDBusError::qKnownErrorsMax; ++i) + if (strcmp(name, messages[i - 1]) == 0) + return QDBusError::KnownErrors(i); + return QDBusError::Other; + } +}; + +static const char errorMessages_string[] = + // in the same order as KnownErrors! + "other\0" // Other -- shouldn't happen + DBUS_ERROR_FAILED "\0" // Failed + DBUS_ERROR_NO_MEMORY "\0" // NoMemory + DBUS_ERROR_SERVICE_UNKNOWN "\0" // ServiceUnknown + DBUS_ERROR_NO_REPLY "\0" // NoReply + DBUS_ERROR_BAD_ADDRESS "\0" // BadAddress + DBUS_ERROR_NOT_SUPPORTED "\0" // NotSupported + DBUS_ERROR_LIMITS_EXCEEDED "\0" // LimitsExceeded + DBUS_ERROR_ACCESS_DENIED "\0" // AccessDenied + DBUS_ERROR_NO_SERVER "\0" // NoServer + DBUS_ERROR_TIMEOUT "\0" // Timeout + DBUS_ERROR_NO_NETWORK "\0" // NoNetwork + DBUS_ERROR_ADDRESS_IN_USE "\0" // AddressInUse + DBUS_ERROR_DISCONNECTED "\0" // Disconnected + DBUS_ERROR_INVALID_ARGS "\0" // InvalidArgs + DBUS_ERROR_UNKNOWN_METHOD "\0" // UnknownMethod + DBUS_ERROR_TIMED_OUT "\0" // TimedOut + DBUS_ERROR_INVALID_SIGNATURE "\0" // InvalidSignature + "com.trolltech.QtDBus.Error.UnknownInterface\0" // UnknownInterface + "com.trolltech.QtDBus.Error.InternalError\0" // InternalError + "\0"; + +ErrorMessageMapping::ErrorMessageMapping() + : messages(int(QDBusError::qKnownErrorsMax)) +{ + // create the list: + const char *p = errorMessages_string; + int i = 0; + while (*p) { + messages[i] = p; + p += strlen(p) + 1; + ++i; + } +} + +Q_GLOBAL_STATIC(ErrorMessageMapping, errorMessages) + /*! \class QDBusError \brief Represents an error received from the D-Bus bus or from remote applications found in the bus. @@ -46,7 +109,54 @@ remote applications. You should not create such objects yourself to signal error conditions when called from D-Bus: instead, use QDBusMessage::error and QDBusConnection::send. - \sa QDBusConnection::send, QDBusMessage, QDBusReply + \sa QDBusConnection::send(), QDBusMessage, QDBusReply +*/ + +/*! + \enum QDBusError::KnownErrors + + In order to facilitate verification of the most common D-Bus errors generated by the D-Bus + implementation and by the bus daemon itself, QDBusError can be compared to a set of pre-defined + values: + + \value NoError QDBusError is invalid (i.e., the call succeeded) + \value Other QDBusError contains an error that is one of the well-known ones + \value Failed The call failed (\c org.freedesktop.DBus.Error.Failed) + \value NoMemory Out of memory (\c org.freedesktop.DBus.Error.NoMemory) + \value ServiceUnknown The called service is not known + (\c org.freedesktop.DBus.Error.ServiceUnknown) + \value NoReply The called method did not reply within the specified timeout + (\c org.freedesktop.DBus.Error.NoReply) + \value BadAddress The address given is not valid + (\c org.freedesktop.DBus.Error.BadAddress) + \value NotSupported The call/operation is not supported + (\c org.freedesktop.DBus.Error.NotSupported) + \value LimitsExceeded The limits allocated to this process/call/connection exceeded the + pre-defined values (\c org.freedesktop.DBus.Error.LimitsExceeded) + \value AccessDenied The call/operation tried to access a resource it isn't allowed to + (\c org.freedesktop.DBus.Error.AccessDenied) + \value NoServer \i{Documentation doesn't say what this is for} + (\c org.freedesktop.DBus.Error.NoServer) + \value Timeout \i{Documentation doesn't say what this is for or how it's used} + (\c org.freedesktop.DBus.Error.Timeout) + \value NoNetwork \i{Documentation doesn't say what this is for} + (\c org.freedesktop.DBus.Error.NoNetwork) + \value AddressInUse QDBusServer tried to bind to an address that is already in use + (\c org.freedesktop.DBus.Error.AddressInUse) + \value Disconnected The call/process/message was sent after QDBusConnection disconnected + (\c org.freedesktop.DBus.Error.Disconnected) + \value InvalidArgs The arguments passed to this call/operation are not valid + (\c org.freedesktop.DBus.Error.InvalidArgs) + \value UnknownMethod The method called was not found in this object/interface with the + given parameters (\c org.freedesktop.DBus.Error.UnknownMethod) + \value TimedOut \i{Documentation doesn't say...} + (\c org.freedesktop.DBus.Error.TimedOut) + \value InvalidSignature The type signature is not valid or compatible + (\c org.freedesktop.DBus.Error.InvalidSignature) + \value UnknownInterface The interface is not known + \value InternalError An internal error occurred + (\c com.trolltech.QtDBus.Error.InternalError) + */ /*! @@ -54,10 +164,12 @@ Constructs a QDBusError from a DBusError structure. */ QDBusError::QDBusError(const DBusError *error) + : code(NoError) { if (!error || !dbus_error_is_set(error)) return; + code = errorMessages()->get(error->name); nm = QString::fromUtf8(error->name); msg = QString::fromUtf8(error->message); } @@ -67,6 +179,7 @@ QDBusError::QDBusError(const DBusError *error) Constructs a QDBusError from a QDBusMessage. */ QDBusError::QDBusError(const QDBusMessage &qdmsg) + : code(Other) { if (qdmsg.type() != QDBusMessage::ErrorMessage) return; @@ -74,14 +187,19 @@ QDBusError::QDBusError(const QDBusMessage &qdmsg) nm = qdmsg.name(); if (qdmsg.count()) msg = qdmsg[0].toString(); + code = errorMessages()->get(nm.toUtf8().constData()); } /*! - \fn QDBusError::QDBusError(const QString &name, const QString &message) \internal - - Constructs an error by passing the name and message. + Constructs a QDBusError from a well-known error code */ +QDBusError::QDBusError(KnownErrors error, const QString &message) + : code(error) +{ + nm = errorMessages()->get(error); + msg = message; +} /*! \fn QDBusError::name() const @@ -101,6 +219,20 @@ QDBusError::QDBusError(const QDBusMessage &qdmsg) Returns true if this is a valid error condition (i.e., if there was an error), false otherwise. */ +/*! + \fn QDBusError::operator==(KnownErrors error) const + Compares this QDBusError against the well-known error code \a error and returns true if they + match. +*/ + +/*! + \fn operator==(QDBusError::KnownErrors p1, const QDBusError &p2) + \relates QDBusError + + Compares the QDBusError \a p2 against the well-known error code \a p1 and returns true if they + match. +*/ + #ifndef QT_NO_DEBUG QDebug operator<<(QDebug dbg, const QDBusError &msg) { diff --git a/qt/qdbuserror.h b/qt/qdbuserror.h index da3d026..71c636d 100644 --- a/qt/qdbuserror.h +++ b/qt/qdbuserror.h @@ -34,20 +34,58 @@ class QDBusMessage; class QDBUS_EXPORT QDBusError { public: + enum KnownErrors { + NoError = 0, + Other = 1, + Failed, + NoMemory, + ServiceUnknown, + NoReply, + BadAddress, + NotSupported, + LimitsExceeded, + AccessDenied, + NoServer, + Timeout, + NoNetwork, + AddressInUse, + Disconnected, + InvalidArgs, + UnknownMethod, + TimedOut, + InvalidSignature, + UnknownInterface, + InternalError, + +#ifndef Q_QDOC + // don't use this one! + qKnownErrorsMax = InternalError +#endif + }; + QDBusError(const DBusError *error = 0); QDBusError(const QDBusMessage& msg); - inline QDBusError(const QString &name, const QString &message) - : nm(name), msg(message) - { } + QDBusError(KnownErrors error, const QString &message); inline QString name() const { return nm; } inline QString message() const { return msg; } inline bool isValid() const { return !nm.isNull() && !msg.isNull(); } + inline bool operator==(KnownErrors error) const + { return code == error; } + private: + KnownErrors code; QString nm, msg; }; +inline bool operator==(QDBusError::KnownErrors p1, const QDBusError &p2) +{ return p2 == p1; } +inline bool operator!=(QDBusError::KnownErrors p1, const QDBusError &p2) +{ return !(p2 == p1); } +inline bool operator!=(const QDBusError &p1, QDBusError::KnownErrors p2) +{ return !(p1 == p2); } + #ifndef QT_NO_DEBUG QDebug operator<<(QDebug, const QDBusError &); #endif diff --git a/qt/qdbusintegrator.cpp b/qt/qdbusintegrator.cpp index f108fc4..38f71a1 100644 --- a/qt/qdbusintegrator.cpp +++ b/qt/qdbusintegrator.cpp @@ -28,15 +28,17 @@ #include <qmetaobject.h> #include <qobject.h> #include <qsocketnotifier.h> +#include <qstringlist.h> #include <qtimer.h> -#include "qdbusvariant.h" #include "qdbusconnection_p.h" #include "qdbusinterface_p.h" -#include "qdbusobject_p.h" #include "qdbusmessage.h" #include "qdbusabstractadaptor.h" #include "qdbusabstractadaptor_p.h" +#include "qdbustypehelper_p.h" +#include "qdbusutil.h" +#include "qdbustype_p.h" #ifndef USE_OUTSIDE_DISPATCH # define USE_OUTSIDE_DISPATCH 0 @@ -44,9 +46,6 @@ int QDBusConnectionPrivate::messageMetaType = 0; -/*! - \internal -*/ struct QDBusPendingCall { QPointer<QObject> receiver; @@ -56,9 +55,6 @@ struct QDBusPendingCall const QDBusConnectionPrivate *connection; }; -/*! - \internal -*/ class CallDeliveryEvent: public QEvent { public: @@ -75,18 +71,6 @@ public: int slotIdx; }; -#if __BYTE_ORDER != __LITTLE_ENDIAN -/*! - \internal -*/ -union integer -{ - short s; - unsigned short us; - unsigned char uc; -}; -#endif - static dbus_bool_t qDBusAddTimeout(DBusTimeout *timeout, void *data) { Q_ASSERT(timeout); @@ -137,7 +121,7 @@ static void qDBusToggleTimeout(DBusTimeout *timeout, void *data) Q_ASSERT(timeout); Q_ASSERT(data); - qDebug("ToggleTimeout"); + //qDebug("ToggleTimeout"); qDBusRemoveTimeout(timeout, data); qDBusAddTimeout(timeout, data); @@ -155,7 +139,7 @@ static dbus_bool_t qDBusAddWatch(DBusWatch *watch, void *data) QDBusConnectionPrivate::Watcher watcher; if (flags & DBUS_WATCH_READABLE) { - qDebug("addReadWatch %d", fd); + //qDebug("addReadWatch %d", fd); watcher.watch = watch; if (QCoreApplication::instance()) { watcher.read = new QSocketNotifier(fd, QSocketNotifier::Read, d); @@ -164,7 +148,7 @@ static dbus_bool_t qDBusAddWatch(DBusWatch *watch, void *data) } } if (flags & DBUS_WATCH_WRITABLE) { - qDebug("addWriteWatch %d", fd); + //qDebug("addWriteWatch %d", fd); watcher.watch = watch; if (QCoreApplication::instance()) { watcher.write = new QSocketNotifier(fd, QSocketNotifier::Write, d); @@ -182,7 +166,7 @@ static void qDBusRemoveWatch(DBusWatch *watch, void *data) Q_ASSERT(watch); Q_ASSERT(data); - qDebug("remove watch"); + //qDebug("remove watch"); QDBusConnectionPrivate *d = static_cast<QDBusConnectionPrivate *>(data); int fd = dbus_watch_get_fd(watch); @@ -213,7 +197,7 @@ static void qDBusToggleWatch(DBusWatch *watch, void *data) bool enabled = dbus_watch_get_enabled(watch); int flags = dbus_watch_get_flags(watch); - qDebug("toggle watch %d to %d (write: %d, read: %d)", dbus_watch_get_fd(watch), enabled, flags & DBUS_WATCH_WRITABLE, flags & DBUS_WATCH_READABLE); + //qDebug("toggle watch %d to %d (write: %d, read: %d)", dbus_watch_get_fd(watch), enabled, flags & DBUS_WATCH_WRITABLE, flags & DBUS_WATCH_READABLE); if (flags & DBUS_WATCH_READABLE && i.value().read) i.value().read->setEnabled(enabled); @@ -228,6 +212,7 @@ static void qDBusToggleWatch(DBusWatch *watch, void *data) static void qDBusNewConnection(DBusServer *server, DBusConnection *c, void *data) { Q_ASSERT(data); Q_ASSERT(server); Q_ASSERT(c); + Q_UNUSED(data); Q_UNUSED(server); Q_UNUSED(c); qDebug("SERVER: GOT A NEW CONNECTION"); // TODO } @@ -256,8 +241,16 @@ static DBusHandlerResult qDBusSignalFilterOutside(DBusConnection *connection, # define HANDLED DBUS_HANDLER_RESULT_HANDLED #endif -static DBusHandlerResult qDBusSignalFilter(DBusConnection *connection, - DBusMessage *message, void *data) +extern "C" { +static DBusHandlerResult +qDBusSignalFilter(DBusConnection *connection, DBusMessage *message, void *data) +{ + return QDBusConnectionPrivate::messageFilter(connection, message, data); +} +} + +DBusHandlerResult QDBusConnectionPrivate::messageFilter(DBusConnection *connection, + DBusMessage *message, void *data) { Q_ASSERT(data); Q_UNUSED(connection); @@ -303,7 +296,7 @@ static void huntAndEmit(DBusConnection *connection, DBusMessage *msg, QByteArray p = path.toLatin1(); if (p.isEmpty()) p = "/"; - qDebug() << p; + //qDebug() << p; DBusMessage *msg2 = dbus_message_copy(msg); dbus_message_set_path(msg2, p); dbus_connection_send(connection, msg2, 0); @@ -319,39 +312,21 @@ bool qDBusCheckAsyncTag(const char *tag) const char *p = strstr(tag, "async"); if (p != NULL && (p == tag || *(p-1) == ' ') && - (p[6] == '\0' || p[6] == ' ')) + (p[5] == '\0' || p[5] == ' ')) return true; p = strstr(tag, "Q_ASYNC"); if (p != NULL && (p == tag || *(p-1) == ' ') && - (p[8] == '\0' || p[8] == ' ')) + (p[7] == '\0' || p[7] == ' ')) return true; return false; } -static QList<QByteArray> splitParameters(const char *p) -{ - QList<QByteArray> retval; - ++p; - const char *e = p; - while (*e != ')') { - while (*e != ')' && *e != ',') - ++e; - - // found the end of this parameter - retval += QByteArray(p, e - p); - - if (*e != ')') - p = ++e; - } - return retval; -} - -static bool typesMatch(int metaId, QVariant::Type variantType) +static bool typesMatch(int metaId, int variantType) { - if (metaId == (int)variantType) + if (metaId == int(variantType)) return true; if (variantType == QVariant::Int && metaId == QMetaType::Short) @@ -361,6 +336,18 @@ static bool typesMatch(int metaId, QVariant::Type variantType) metaId == QMetaType::UChar)) return true; + if (variantType == QVariant::List) { + if (metaId == QDBusTypeHelper<bool>::listId() || + metaId == QDBusTypeHelper<short>::listId() || + metaId == QDBusTypeHelper<ushort>::listId() || + metaId == QDBusTypeHelper<int>::listId() || + metaId == QDBusTypeHelper<uint>::listId() || + metaId == QDBusTypeHelper<qlonglong>::listId() || + metaId == QDBusTypeHelper<qulonglong>::listId() || + metaId == QDBusTypeHelper<double>::listId()) + return true; + } + return false; // no match } @@ -392,7 +379,15 @@ int qDBusNameToTypeId(const char *name) return id; default: - if (id == qMetaTypeId<QDBusVariant>() || id == QDBusConnectionPrivate::messageMetaType) + if (id == QDBusConnectionPrivate::messageMetaType || + id == QDBusTypeHelper<QVariant>::id() || + id == QDBusTypeHelper<bool>::listId() || + id == QDBusTypeHelper<short>::listId() || + id == QDBusTypeHelper<ushort>::listId() || + id == QDBusTypeHelper<int>::listId() || + id == QDBusTypeHelper<qlonglong>::listId() || + id == QDBusTypeHelper<qulonglong>::listId() || + id == QDBusTypeHelper<double>::listId()) return id; return 0; // invalid @@ -411,16 +406,9 @@ int qDBusNameToTypeId(const char *name) // metaTypes.count() >= retval + 1 in all cases // // sig must be the normalised signature for the method -int qDBusParametersForMethod(const QByteArray &sig, QList<int>& metaTypes) +int qDBusParametersForMethod(const QMetaMethod &mm, QList<int>& metaTypes) { - if (sig.indexOf('<') != -1) { - qWarning("Could not parse the method '%s'", sig.constData()); - // there's no type with templates that we can handle - return -1; - } - - int paren = sig.indexOf('('); - QList<QByteArray> parameterTypes = splitParameters(sig.data() + paren); + QList<QByteArray> parameterTypes = mm.parameterTypes(); metaTypes.clear(); metaTypes.append(0); // return type @@ -428,7 +416,7 @@ int qDBusParametersForMethod(const QByteArray &sig, QList<int>& metaTypes) bool seenMessage = false; foreach (QByteArray type, parameterTypes) { if (type.endsWith('*')) { - qWarning("Could not parse the method '%s'", sig.constData()); + qWarning("Could not parse the method '%s'", mm.signature()); // pointer? return -1; } @@ -437,7 +425,7 @@ int qDBusParametersForMethod(const QByteArray &sig, QList<int>& metaTypes) type.truncate(type.length() - 1); int id = qDBusNameToTypeId(type); if (id == 0) { - qWarning("Could not parse the method '%s'", sig.constData()); + qWarning("Could not parse the method '%s'", mm.signature()); // invalid type in method parameter list return -1; } @@ -448,14 +436,14 @@ int qDBusParametersForMethod(const QByteArray &sig, QList<int>& metaTypes) } if (seenMessage) { // && !type.endsWith('&') - qWarning("Could not parse the method '%s'", sig.constData()); + qWarning("Could not parse the method '%s'", mm.signature()); // non-output parameters after message or after output params return -1; // not allowed } int id = qDBusNameToTypeId(type); if (id == 0) { - qWarning("Could not parse the method '%s'", sig.constData()); + qWarning("Could not parse the method '%s'", mm.signature()); // invalid type in method parameter list return -1; } @@ -478,7 +466,7 @@ static int findSlot(const QMetaObject *mo, const QByteArray &name, int flags, super != &QDBusAbstractAdaptor::staticMetaObject) super = super->superClass(); - int attributeMask = (flags & QDBusConnection::ExportNonScriptableSlots) ? + int attributeMask = (flags & QDBusConnection::ExportAllSlots) ? 0 : QMetaMethod::Scriptable; for (int idx = super->methodCount() ; idx <= mo->methodCount(); ++idx) { @@ -506,7 +494,7 @@ static int findSlot(const QMetaObject *mo, const QByteArray &name, int flags, if (isAsync && returnType != QMetaType::Void) continue; - int inputCount = qDBusParametersForMethod(sig, metaTypes); + int inputCount = qDBusParametersForMethod(mm, metaTypes); if (inputCount == -1) continue; // problem parsing @@ -630,12 +618,13 @@ bool QDBusConnectionPrivate::activateCall(QObject* object, int flags, { const QMetaObject *mo = object->metaObject(); QDBusTypeList typeList(msg.signature().toUtf8()); + QByteArray name = msg.name().toUtf8(); // find a slot that matches according to the rules above - idx = ::findSlot(mo, msg.name().toUtf8(), flags, typeList, metaTypes); + idx = ::findSlot(mo, name, flags, typeList, metaTypes); if (idx == -1) { // try with no parameters, but with a QDBusMessage - idx = ::findSlot(mo, msg.name().toUtf8(), flags, QDBusTypeList(), metaTypes); + idx = ::findSlot(mo, name, flags, QDBusTypeList(), metaTypes); if (metaTypes.count() != 2 || metaTypes.at(1) != messageMetaType) return false; } @@ -692,9 +681,7 @@ void QDBusConnectionPrivate::deliverCall(const CallDeliveryEvent& data) const QVarLengthArray<void *, 10> params; params.reserve(metaTypes.count()); -#if __BYTE_ORDER != __LITTLE_ENDIAN - QVarLengthArray<integer, 4> auxParameters; -#endif + QVarLengthArray<QVariant, 4> auxParameters; // let's create the parameter list // first one is the return type -- add it below @@ -707,25 +694,65 @@ void QDBusConnectionPrivate::deliverCall(const CallDeliveryEvent& data) const if (id == QDBusConnectionPrivate::messageMetaType) break; -#if __BYTE_ORDER == __LITTLE_ENDIAN - params.append(const_cast<void *>( msg.at(i - 1).constData() )); -#else - if (id == int(msg.at(i).type())) + if (id == int(msg.at(i - 1).userType())) + // no conversion needed params.append(const_cast<void *>( msg.at(i - 1).constData() )); else { - // need some help - integer aux; - const QVariant &var = msg.at(i - 1); - if (id == QMetaType::Short) - aux.s = var.toInt(); - else if (id == QMetaType::UShort) - aux.us = var.toUInt(); - else - aux.uc = var.toUInt(); - auxParameters.append(aux); - params.append( &auxParameters[auxParameters.count()] ); + // convert to what the function expects + auxParameters.append(QVariant()); + + const QVariant &in = msg.at(i - 1); + QVariant &out = auxParameters[auxParameters.count() - 1]; + + bool error = false; + if (id == QVariant::List) { + int mid = in.userType(); + // the only conversion possible here is from a specialised QList<T> to QVariantList + if (mid == QDBusTypeHelper<bool>::listId()) + out = qVariantFromValue(QDBusTypeHelper<bool>::toVariantList(in)); + else if (mid == QDBusTypeHelper<short>::listId()) + out = qVariantFromValue(QDBusTypeHelper<short>::toVariantList(in)); + else if (mid == QDBusTypeHelper<ushort>::listId()) + out = qVariantFromValue(QDBusTypeHelper<ushort>::toVariantList(in)); + else if (mid == QDBusTypeHelper<int>::listId()) + out = qVariantFromValue(QDBusTypeHelper<int>::toVariantList(in)); + else if (mid == QDBusTypeHelper<uint>::listId()) + out = qVariantFromValue(QDBusTypeHelper<uint>::toVariantList(in)); + else if (mid == QDBusTypeHelper<qlonglong>::listId()) + out = qVariantFromValue(QDBusTypeHelper<qlonglong>::toVariantList(in)); + else if (mid == QDBusTypeHelper<qulonglong>::listId()) + out = qVariantFromValue(QDBusTypeHelper<qulonglong>::toVariantList(in)); + else if (mid == QDBusTypeHelper<double>::listId()) + out = qVariantFromValue(QDBusTypeHelper<double>::toVariantList(in)); + else + error = true; + } else if (in.type() == QVariant::UInt) { + if (id == QMetaType::UChar) { + uchar uc = in.toUInt(); + out = qVariantFromValue(uc); + } else if (id == QMetaType::UShort) { + ushort us = in.toUInt(); + out = qVariantFromValue(us); + } else { + error = true; + } + } else if (in.type() == QVariant::Int) { + if (id == QMetaType::Short) { + short s = in.toInt(); + out = qVariantFromValue(s); + } else { + error = true; + } + } else { + error = true; + } + + if (error) + qFatal("Internal error: got invalid meta type %d when trying to convert to meta type %d", + in.userType(), id); + + params.append( const_cast<void *>(out.constData()) ); } -#endif } bool takesMessage = false; @@ -740,13 +767,13 @@ void QDBusConnectionPrivate::deliverCall(const CallDeliveryEvent& data) const void *null = 0; if (metaTypes[0] != QMetaType::Void) { QVariant arg(metaTypes[0], null); - params.append( arg.data() ); outputArgs.append( arg ); + params[0] = const_cast<void*>(outputArgs.at( outputArgs.count() - 1 ).constData()); } for ( ; i < metaTypes.count(); ++i) { QVariant arg(metaTypes[i], null); - params.append( arg.data() ); outputArgs.append( arg ); + params.append( const_cast<void*>(outputArgs.at( outputArgs.count() - 1 ).constData()) ); } // make call: @@ -770,10 +797,9 @@ void QDBusConnectionPrivate::deliverCall(const CallDeliveryEvent& data) const } else { // generate internal error - QDBusMessage reply = QDBusMessage::error(msg, - QLatin1String("com.trolltech.QtDBus.InternalError"), - QLatin1String("Failed to deliver message")); - qDebug("Internal error: Failed to deliver message"); + QDBusMessage reply = QDBusMessage::error(msg, QDBusError(QDBusError::InternalError, + QLatin1String("Failed to deliver message"))); + qWarning("Internal error: Failed to deliver message"); send(reply); } } @@ -793,14 +819,16 @@ void QDBusConnectionPrivate::customEvent(QEvent *event) } QDBusConnectionPrivate::QDBusConnectionPrivate(QObject *parent) - : QObject(parent), ref(1), mode(InvalidMode), connection(0), server(0) + : QObject(parent), ref(1), mode(InvalidMode), connection(0), server(0), busService(0) { extern bool qDBusInitThreads(); static const int msgType = registerMessageMetaType(); static const bool threads = qDBusInitThreads(); + static const bool metatypes = QDBusMetaTypeId::innerInitialize(); Q_UNUSED(msgType); Q_UNUSED(threads); + Q_UNUSED(metatypes); dbus_error_init(&error); @@ -809,23 +837,12 @@ QDBusConnectionPrivate::QDBusConnectionPrivate(QObject *parent) QDBusConnectionPrivate::~QDBusConnectionPrivate() { - Q_ASSERT(knownObjects.isEmpty()); - if (dbus_error_is_set(&error)) dbus_error_free(&error); closeConnection(); - - KnownInterfacesHash::iterator it = knownInterfaces.begin(); - while (it != knownInterfaces.end()) { - const QSharedDataPointer<QDBusIntrospection::Interface>& item = *it; - - const_cast<QDBusIntrospection::Interface*>(item.constData())->ref.deref(); - - it = knownInterfaces.erase(it); - } - rootNode.clear(); // free resources + qDeleteAll(cachedMetaObjects); } void QDBusConnectionPrivate::closeConnection() @@ -933,8 +950,8 @@ void QDBusConnectionPrivate::relaySignal(QObject *obj, const char *interface, co return; } - qDebug() << "Emitting signal" << message; - qDebug() << "for paths:"; + //qDebug() << "Emitting signal" << message; + //qDebug() << "for paths:"; dbus_message_set_no_reply(msg, true); // the reply would not be delivered to anything huntAndEmit(connection, msg, obj, &rootNode); dbus_message_unref(msg); @@ -956,7 +973,7 @@ int QDBusConnectionPrivate::findSlot(QObject* obj, const char *slotName, QList<i return -1; } - int inputCount = qDBusParametersForMethod(normalizedName, params); + int inputCount = qDBusParametersForMethod(obj->metaObject()->method(midx), params); if ( inputCount == -1 || inputCount + 1 != params.count() ) return -1; // failed to parse or invalid arguments or output arguments @@ -996,7 +1013,7 @@ bool QDBusConnectionPrivate::activateObject(const ObjectTreeNode *node, const QD QDBusAdaptorConnector *connector; if (node->flags & QDBusConnection::ExportAdaptors && (connector = qDBusFindAdaptorConnector(node->obj))) { - int newflags = node->flags | QDBusConnection::ExportNonScriptableSlots; + int newflags = node->flags | QDBusConnection::ExportAllSlots; if (msg.interface().isEmpty()) { // place the call in all interfaces @@ -1023,12 +1040,13 @@ bool QDBusConnectionPrivate::activateObject(const ObjectTreeNode *node, const QD // try the object itself: if (node->flags & QDBusConnection::ExportSlots && activateCall(node->obj, node->flags, msg)) return true; - +#if 0 // nothing matched qDebug("Call failed: no match for %s%s%s at %s", qPrintable(msg.interface()), msg.interface().isEmpty() ? "" : ".", qPrintable(msg.name()), qPrintable(msg.path())); +#endif return false; } @@ -1101,8 +1119,8 @@ bool QDBusConnectionPrivate::handleSignal(const QString &path, const QDBusMessag bool result = false; SignalHookHash::const_iterator it = signalHooks.find(path); - qDebug("looking for: %s", path.toLocal8Bit().constData()); - qDebug() << signalHooks.keys(); + //qDebug("looking for: %s", path.toLocal8Bit().constData()); + //qDebug() << signalHooks.keys(); for ( ; it != signalHooks.constEnd() && it.key() == path; ++ it) { const SignalHook &hook = it.value(); if ( !hook.name.isEmpty() && hook.name != msg.name() ) @@ -1197,11 +1215,17 @@ void QDBusConnectionPrivate::setConnection(DBusConnection *dbc) dbus_connection_add_filter(connection, qDBusSignalFilter, this, 0); #endif - qDebug("base service: %s", service); + //qDebug("base service: %s", service); } +extern "C" static void qDBusResultReceived(DBusPendingCall *pending, void *user_data) { + QDBusConnectionPrivate::messageResultReceived(pending, user_data); +} + +void QDBusConnectionPrivate::messageResultReceived(DBusPendingCall *pending, void *user_data) +{ QDBusPendingCall *call = reinterpret_cast<QDBusPendingCall *>(user_data); QDBusConnectionPrivate *connection = const_cast<QDBusConnectionPrivate *>(call->connection); Q_ASSERT(call->pending == pending); @@ -1216,11 +1240,14 @@ static void qDBusResultReceived(DBusPendingCall *pending, void *user_data) // The slot may have less parameters than the message // The slot may optionally have one final parameter that is QDBusMessage // The slot receives read-only copies of the message (i.e., pass by value or by const-ref) - CallDeliveryEvent *e = prepareReply(call->receiver, call->methodIdx, call->metaTypes, - QDBusMessage::fromDBusMessage(reply, - QDBusConnection(connection->name))); + + QDBusMessage msg = QDBusMessage::fromDBusMessage(reply, QDBusConnection(connection->name)); + qDebug() << "got message: " << msg; + CallDeliveryEvent *e = prepareReply(call->receiver, call->methodIdx, call->metaTypes, msg); if (e) connection->deliverCall(*e); + else + qDebug() << "Deliver failed!"; delete e; } dbus_pending_call_unref(pending); @@ -1241,8 +1268,39 @@ bool QDBusConnectionPrivate::send(const QDBusMessage& message) const return isOk; } +QDBusMessage QDBusConnectionPrivate::sendWithReply(const QDBusMessage &message, + int mode) +{ + if (!QCoreApplication::instance() || mode == QDBusConnection::NoUseEventLoop) { + DBusMessage *msg = message.toDBusMessage(); + if (!msg) + return QDBusMessage(); + + DBusMessage *reply = dbus_connection_send_with_reply_and_block(connection, msg, + -1, &error); + handleError(); + dbus_message_unref(msg); + + if (lastError.isValid()) + return QDBusMessage::fromError(lastError); + + return QDBusMessage::fromDBusMessage(reply, QDBusConnection(name)); + } else { // use the event loop + QDBusReplyWaiter waiter; + if (sendWithReplyAsync(message, &waiter, SLOT(reply(const QDBusMessage&))) > 0) { + // enter the event loop and wait for a reply + waiter.exec(QEventLoop::ExcludeUserInputEvents | QEventLoop::WaitForMoreEvents); + + lastError = waiter.replyMsg; // set or clear error + return waiter.replyMsg; + } + + return QDBusMessage(); + } +} + int QDBusConnectionPrivate::sendWithReplyAsync(const QDBusMessage &message, QObject *receiver, - const char *method) const + const char *method) { DBusMessage *msg = message.toDBusMessage(); if (!msg) @@ -1286,76 +1344,192 @@ void QDBusConnectionPrivate::registerObject(const ObjectTreeNode *node) QDBusAdaptorConnector *connector = qDBusCreateAdaptorConnector(node->obj); // disconnect and reconnect to avoid duplicates - connector->disconnect(SIGNAL(relaySignal(QObject *,const char*, const char*,QVariantList)), - this, SLOT(relaySignal(QObject*, const char*, const char*,QVariantList))); - connect(connector, SIGNAL(relaySignal(QObject *,const char*, const char*,QVariantList)), - SLOT(relaySignal(QObject*, const char*, const char*,QVariantList))); + connector->disconnect(SIGNAL(relaySignal(QObject*,const char*,const char*,QVariantList)), + this, SLOT(relaySignal(QObject*,const char*,const char*,QVariantList))); + connect(connector, SIGNAL(relaySignal(QObject*,const char*,const char*,QVariantList)), + SLOT(relaySignal(QObject*,const char*,const char*,QVariantList))); } } -QSharedDataPointer<QDBusIntrospection::Interface> -QDBusConnectionPrivate::findInterface(const QString& name) +void QDBusConnectionPrivate::connectRelay(const QString &service, const QString &path, + const QString &interface, + QDBusAbstractInterface *receiver, + const char *signal) { + // this function is called by QDBusAbstractInterface when one of its signals is connected + // we set up a relay from D-Bus into it + + // similar to QDBusConnectionPrivate::findSlot! Merge! + QByteArray normalizedName = QMetaObject::normalizedSignature(signal + 1); + SignalHook hook; + hook.midx = receiver->metaObject()->indexOfSignal(normalizedName); + Q_ASSERT(hook.midx != -1); // cannot happen + if (hook.midx < QDBusAbstractInterface::staticMetaObject.methodCount()) + return; // don't connect to this signal + + int inputCount = qDBusParametersForMethod(receiver->metaObject()->method(hook.midx), hook.params); + if ( inputCount == -1 || inputCount + 1 != hook.params.count() ) + return; // failed to parse or invalid arguments or output arguments + + // build the D-Bus signal name and signature + QString source = service; + source += path; + normalizedName.truncate(normalizedName.indexOf('(')); + hook.name = QString::fromUtf8(normalizedName); + hook.interface = interface; + hook.obj = receiver; + for (int i = 1; i <= inputCount; ++i) + if (hook.params.at(i) != messageMetaType) + hook.signature += QLatin1String( QDBusType::dbusSignature( QVariant::Type(hook.params.at(i)) ) ); + + // add it to our list: QWriteLocker locker(&lock); - QSharedDataPointer<QDBusIntrospection::Interface> data = knownInterfaces.value(name); - if (!data) { - data = new QDBusIntrospection::Interface; - data->name = name; - data->ref.ref(); // don't delete - - knownInterfaces.insert(name, data); + SignalHookHash::ConstIterator it = signalHooks.find(source); + SignalHookHash::ConstIterator end = signalHooks.end(); + for ( ; it != end && it.key() == source; ++it) { + const SignalHook &entry = it.value(); + if (entry.interface == hook.interface && + entry.name == hook.name && + entry.signature == hook.signature && + entry.obj == hook.obj && + entry.midx == hook.midx) + return; // already there, no need to re-add } - return data; + + connectSignal(source, hook); } -QDBusIntrospection::Object* -QDBusConnectionPrivate::findObject(const QString& service, const QString& path) +void QDBusConnectionPrivate::disconnectRelay(const QString &service, const QString &path, + const QString &interface, + QDBusAbstractInterface *receiver, + const char *signal) { + // this function is called by QDBusAbstractInterface when one of its signals is disconnected + // we remove relay from D-Bus into it + + // similar to QDBusConnectionPrivate::findSlot! Merge! + QByteArray normalizedName = QMetaObject::normalizedSignature(signal + 1); + SignalHook hook; + hook.midx = receiver->metaObject()->indexOfSignal(normalizedName); + Q_ASSERT(hook.midx != -1); // cannot happen + if (hook.midx < QDBusAbstractInterface::staticMetaObject.methodCount()) + return; // we won't find it, so don't bother + + int inputCount = qDBusParametersForMethod(receiver->metaObject()->method(hook.midx), hook.params); + if ( inputCount == -1 || inputCount + 1 != hook.params.count() ) + return; // failed to parse or invalid arguments or output arguments + + // build the D-Bus signal name and signature + QString source = service; + source += path; + normalizedName.truncate(normalizedName.indexOf('(')); + hook.name = QString::fromUtf8(normalizedName); + hook.interface = interface; + hook.obj = receiver; + for (int i = 1; i <= inputCount; ++i) + if (hook.params.at(i) != messageMetaType) + hook.signature += QLatin1String( QDBusType::dbusSignature( QVariant::Type(hook.params.at(i)) ) ); + + // remove it from our list: QWriteLocker locker(&lock); - QDBusIntrospection::Object* data = knownObjects.value(service + path); - if (!data) { - data = new QDBusIntrospection::Object; - data->service = service; - data->path = path; - - knownObjects.insert(service + path, data); + SignalHookHash::Iterator it = signalHooks.find(source); + SignalHookHash::Iterator end = signalHooks.end(); + for ( ; it != end && it.key() == source; ++it) { + const SignalHook &entry = it.value(); + if (entry.interface == hook.interface && + entry.name == hook.name && + entry.signature == hook.signature && + entry.obj == hook.obj && + entry.midx == hook.midx) { + // found it + signalHooks.erase(it); + return; + } } - return data; + qWarning("QDBusConnectionPrivate::disconnectRelay called for a signal that was not found"); } -void QDBusConnectionPrivate::disposeOfLocked(QDBusIntrospection::Object* p) +QString QDBusConnectionPrivate::getNameOwner(const QString& name) { - if (p && !p->ref.deref()) { // ref-- - // no one else is using it - // get rid of the reference - QString objName = p->service + p->path; - -#ifndef QT_NO_DEBUG - // debug code - Q_ASSERT(p == knownObjects.take(objName)); -#else - // non-debug - knownObjects.remove(objName); -#endif + if (QDBusUtil::isValidUniqueConnectionName(name)) + return name; + if (!connection || !QDBusUtil::isValidBusName(name)) + return QString(); + + QDBusMessage msg = QDBusMessage::methodCall(QLatin1String(DBUS_SERVICE_DBUS), + QLatin1String(DBUS_PATH_DBUS), QLatin1String(DBUS_INTERFACE_DBUS), + QLatin1String("GetNameOwner")); + msg << name; + QDBusMessage reply = sendWithReply(msg, QDBusConnection::NoUseEventLoop); + if (!lastError.isValid() && reply.type() == QDBusMessage::ReplyMessage) + return reply.first().toString(); + return QString(); +} - // remove sub-objects too - if (!objName.endsWith(QLatin1Char('/'))) - objName.append(QLatin1Char('/')); - foreach (QString subObjName, p->childObjects) - disposeOfLocked(knownObjects.value(objName + subObjName)); +QDBusInterfacePrivate * +QDBusConnectionPrivate::findInterface(const QString &service, + const QString &path, + const QString &interface) +{ + + if (!connection || !QDBusUtil::isValidObjectPath(path)) + return 0; + if (!interface.isEmpty() && !QDBusUtil::isValidInterfaceName(interface)) + return 0; - delete p; - } + // check if it's there first -- FIXME: add binding mode + QString owner = getNameOwner(service); + if (owner.isEmpty()) + return 0; + + QString tmp(interface); + QDBusMetaObject *mo = findMetaObject(owner, path, tmp); + if (mo) + return new QDBusInterfacePrivate(QDBusConnection(name), this, owner, path, tmp, mo); + return 0; // error has been set } -void QDBusConnectionPrivate::disposeOf(QDBusObjectPrivate* p) +QDBusMetaObject * +QDBusConnectionPrivate::findMetaObject(const QString &service, const QString &path, + QString &interface) { - // We're called from QDBusConnectionPrivate's destructor - // that means the object it represents is going out of scope + if (!interface.isEmpty()) { + QReadLocker locker(&lock); + QDBusMetaObject *mo = cachedMetaObjects.value(interface, 0); + if (mo) + return mo; + } + + // 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); + + // it doesn't exist yet, we have to create it QWriteLocker locker(&lock); - disposeOfLocked( const_cast<QDBusIntrospection::Object*>(p->data) ); + 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; + + QString xml; + if (reply.type() == QDBusMessage::ReplyMessage) + // fetch the XML description + xml = reply.first().toString(); + else { + lastError = reply; + if (reply.type() != QDBusMessage::ErrorMessage || lastError != QDBusError::UnknownMethod) + return 0; // error + } + + // release the lock and return + return QDBusMetaObject::createMetaObject(interface, xml, cachedMetaObjects, lastError); } void QDBusReplyWaiter::reply(const QDBusMessage &msg) @@ -1363,4 +1537,5 @@ void QDBusReplyWaiter::reply(const QDBusMessage &msg) replyMsg = msg; QTimer::singleShot(0, this, SLOT(quit())); } + #include "qdbusconnection_p.moc" diff --git a/qt/qdbusinterface.cpp b/qt/qdbusinterface.cpp index 1572b2a..e0d1049 100644 --- a/qt/qdbusinterface.cpp +++ b/qt/qdbusinterface.cpp @@ -1,6 +1,5 @@ /* -*- C++ -*- * - * Copyright (C) 2005 Thiago Macieira <thiago@kde.org> * Copyright (C) 2006 Trolltech AS. All rights reserved. * Author: Thiago Macieira <thiago.macieira@trolltech.com> * @@ -23,485 +22,219 @@ */ #include "qdbusinterface.h" -#include "qdbusobject.h" -#include "qdbusstandardinterfaces.h" -#include "qdbusinterface_p.h" +#include <dbus/dbus.h> +#include <QtCore/qpointer.h> -/*! - \internal -*/ -struct EmptyInterfaceInitializer -{ - QDBusIntrospection::Interface *data; - EmptyInterfaceInitializer() - { - data = new QDBusIntrospection::Interface; - data->ref = 1; - data->introspection = QLatin1String(""); - } - - ~EmptyInterfaceInitializer() - { - Q_ASSERT(data->ref == 1); - delete data; - data = 0; - } -}; - -Q_GLOBAL_STATIC(EmptyInterfaceInitializer, emptyDataInit); - -const QDBusIntrospection::Interface* -QDBusInterfacePrivate::emptyData() -{ - return emptyDataInit()->data; -} +#include "qdbusinterface_p.h" +#include "qdbusconnection_p.h" /*! \class QDBusInterface - \brief Base class for all D-Bus interfaces in the QtDBus binding, allowing access to remote interfaces. + \brief Proxy class for interfaces on remote objects. QDBusInterface is a generic accessor class that is used to place calls to remote objects, connect to signals exported by remote objects and get/set the value of remote properties. This class is useful for dynamic access to remote objects: that is, when you do not have a generated code that represents the remote interface. - Generated-code classes also derive from QDBusInterface, all methods described here are also - valid for generated-code classes. In addition to those described here, generated-code classes - provide member functions for the remote methods, which allow for compile-time checking of the - correct parameters and return values, as well as property type-matching and signal - parameter-matching. - Calls are usually placed by using the call() function, which constructs the message, sends it over the bus, waits for the reply and decodes the reply. Signals are connected to by using the - connect() family of functions, whose behavior is similar to QObject::connect(). Finally, - properties are accessed using the property() and setProperty() functions, whose behaviour is - also similar to QObject::property() and QObject::setProperty(). - - \sa \ref StandardInterfaces, \ref dbusidl2cpp -*/ - -/*! - \enum QDBusInterface::CallMode - \todo turn this into flags and add UseEventLoop/NoUseEventLoop - - Specifies how a call should be placed. The valid options are: - \value NoWaitForReply place the call but don't wait for the reply (the reply's contents - will be discarded) - \value WaitForReply place the call and wait for the method to finish before returning - (the reply's contents will be returned) - \value NoUseEventLoop don't use an event loop to wait for a reply, but instead block on - network operations while waiting. This option means the - user-interface may not be updated for the duration of the call. - \value UseEventLoop use the Qt event loop to wait for a reply. This option means the - user-interface will update, but it also means other events may - happen, like signal delivery and other D-Bus method calls. - - When using UseEventLoop, applications must be prepared for reentrancy in any function. + normal QObject::connect() function. Finally, properties are accessed using the + QObject::property() and QObject::setProperty() functions. */ -QDBusInterface::QDBusInterface(QDBusInterfacePrivate* p) - : d(p) +QDBusInterface::QDBusInterface(QDBusInterfacePrivate *p) + : QDBusAbstractInterface(p) { - d->ref.ref(); } /*! - Constructs a QDBusInterface object by associating it with the interface \p name in the remote - object \p obj. -*/ -QDBusInterface::QDBusInterface(const QDBusObject& obj, const QString& name) - : d(0) -{ - *this = obj.connection().findInterface(obj.service(), obj.path(), name); -} - -/*! - Constructs a copy QDBusInterface object. -*/ -QDBusInterface::QDBusInterface(const QDBusInterface &other) - : d(0) -{ - *this = other; -} - -/*! - Releases this object's resources. + Destroy the object interface and frees up any resource used. */ QDBusInterface::~QDBusInterface() { - if (!d->ref.deref()) - delete d; -} - -/*! - Constructs a copy QDBusInterface object. -*/ -QDBusInterface& QDBusInterface::operator=(const QDBusInterface& other) -{ - other.d->ref.ref(); - QDBusInterfacePrivate* old = qAtomicSetPtr(&d, other.d); - if (old && !old->ref.deref()) - delete old; - - return *this; -} - -/*! - \fn QDBusInterface::object() - Returns the object associated with this interface. -*/ - -/*! - \fn QDBusInterface::object() const - \overload - Returns the object associated with this interface. -*/ - -/*! - \fn "QDBusInterface::operator QDBusObject" - \overload - Returns the object associated with this interface. -*/ - -/*! - \fn "QDBusInterface::operator const QDBusObject" - \overload - Returns the object associated with this interface. -*/ - -/*! - Returns the connection this interface is assocated with. -*/ -QDBusConnection QDBusInterface::connection() const -{ - return d->conn; -} - -/*! - Returns the name of the service this interface is associated with. -*/ -QString QDBusInterface::service() const -{ - return d->service; -} - -/*! - Returns the object path that this interface is associated with. -*/ -QString QDBusInterface::path() const -{ - return d->path; -} - -/*! - Returns the name of this interface. -*/ -QString QDBusInterface::interface() const -{ - return d->data->name; -} - -/*! - Returns the XML document fragment that describes the introspection of this interface. This is - the raw XML form of the structures returned by interfaceData(). - */ -QString QDBusInterface::introspectionData() const -{ - d->introspect(); - return d->data->introspection; -} - -/*! - Returns the interface data for this interface. This is the parsed form of the XML introspection - data, as returned by introspectionData(). - */ -const QDBusIntrospection::Interface& QDBusInterface::interfaceData() const -{ - d->introspect(); - return *d->data; -} - -/*! - Returns the annotations present in this interface, if any. - This information can also be found in the data returned by interfaceData(). -*/ -const QDBusIntrospection::Annotations& QDBusInterface::annotationData() const -{ - d->introspect(); - return d->data->annotations; + // resources are freed in QDBusInterfacePrivate::~QDBusInterfacePrivate() } /*! - Returns a map of all the methods found in this interface. - This information can also be found in the data returned by interfaceData(). -*/ -const QDBusIntrospection::Methods& QDBusInterface::methodData() const -{ - d->introspect(); - return d->data->methods; -} - -/*! - Returns a map of all the signals found in this interface. - This information can also be found in the data returned by interfaceData(). + \internal + Overrides QObject::metaObject to return our own copy. */ -const QDBusIntrospection::Signals& QDBusInterface::signalData() const +const QMetaObject *QDBusInterface::metaObject() const { - d->introspect(); - return d->data->signals_; + return d_func()->metaObject; } /*! - Returns a map of all the properties found in this interface. - This information can also be found in the data returned by interfaceData(). + \internal + Override QObject::qt_metacast to catch the interface name too. */ -const QDBusIntrospection::Properties& QDBusInterface::propertyData() const +void *QDBusInterface::qt_metacast(const char *_clname) { - d->introspect(); - return d->data->properties; + if (!_clname) return 0; + if (!strcmp(_clname, "QDBusInterface")) + return static_cast<void*>(const_cast<QDBusInterface*>(this)); + if (d_func()->interface == _clname) + return static_cast<void*>(const_cast<QDBusInterface*>(this)); + return QDBusAbstractInterface::qt_metacast(_clname); } /*! - Places a call to the remote method specified by \p method on this interface, using \p a_args as - arguments. - - Normally, you should place calls using call(). -*/ -QDBusMessage QDBusInterface::callWithArgs(const QDBusIntrospection::Method& method, - const QList<QVariant>& a_args, - CallMode mode) -{ - QString signature = QLatin1String(""); // empty, not null - QVariantList args = a_args; - - if (!method.inputArgs.isEmpty()) - { - // go over the list of parameters for the method - QDBusIntrospection::Arguments::const_iterator it = method.inputArgs.begin(), - end = method.inputArgs.end(); - int arg; - for (arg = 0; it != end; ++it, ++arg) - { - // find the marshalled name for this type - QString typeSig = QLatin1String(it->type.dbusSignature()); - signature += typeSig; + \internal + Dispatch the call through the private. +*/ +int QDBusInterface::qt_metacall(QMetaObject::Call _c, int _id, void **_a) +{ + _id = QDBusAbstractInterface::qt_metacall(_c, _id, _a); + if (_id < 0) + return _id; + return d_func()->metacall(_c, _id, _a); +} + +int QDBusInterfacePrivate::metacall(QMetaObject::Call c, int id, void **argv) +{ + Q_Q(QDBusInterface); + + if (c == QMetaObject::InvokeMetaMethod) { + int offset = metaObject->methodOffset(); + QMetaMethod mm = metaObject->method(id + offset); + + if (mm.methodType() == QMetaMethod::Signal) { + // signal relay from D-Bus world to Qt world + QMetaObject::activate(q, metaObject, id, argv); + + } else if (mm.methodType() == QMetaMethod::Slot) { + // method call relay from Qt world to D-Bus world + // get D-Bus equivalent signature + QString methodName = metaObject->dbusNameForMethod(id); + const int *inputTypes = metaObject->inputTypesForMethod(id); + const int *outputTypes = metaObject->outputTypesForMethod(id); + + int inputTypesCount = *inputTypes; + int outputTypesCount = *outputTypes++; + + // we will assume that the input arguments were passed correctly + QVariantList args; + for (int i = 1; i <= inputTypesCount; ++i) + args << QVariant(inputTypes[i], argv[i]); + + // make the call + QPointer<QDBusInterface> qq = q; + QDBusMessage reply = q->callWithArgs(methodName, args); + args.clear(); + + // access to "this" or to "q" below this point must check for "qq" + // we may have been deleted! + + // check if we got the right number of parameters back: + bool success = false; + if (reply.count() == outputTypesCount) { + // copy the values out + for (int i = 0; i < outputTypesCount; ++i) { + // treat the return value specially, since it may be null: + if (i == 0 && argv[0] == 0) + continue; + + // ensure that the types are correct: + const QVariant &item = reply.at(i); + if (outputTypes[i] != item.userType()) { + success = false; + break; + } + + if (i == 0) + QDBusMetaObject::assign(argv[0], item); + else + QDBusMetaObject::assign(argv[inputTypesCount + i], item); + } + } + + // bail out, something weird happened + if (!success && !qq.isNull()) { + QString errmsg = QLatin1String("Invalid signature `%1' in return from call to %2.%3"); + lastError = QDBusError(QDBusError::InvalidSignature, + errmsg.arg(reply.signature(), interface, methodName)); + } + + // done + return -1; } - } - else - args.clear(); - - if (method.annotations.value(QLatin1String(ANNOTATION_NO_WAIT)) == QLatin1String("true")) - mode = NoWaitForReply; - - return callWithArgs(method.name, signature, args, mode); -} - -/*! - \overload - Places a call to the remote method specified by \p method on this interface, using \p args as - arguments. - - Normally, you should place calls using call(). -*/ -QDBusMessage QDBusInterface::callWithArgs(const QString& method, const QList<QVariant>& args, - CallMode mode) -{ - QString m = method, sig; - // split out the signature from the method - int pos = method.indexOf(QLatin1Char('.')); - if (pos != -1) { - m.truncate(pos); - sig = method.mid(pos + 1); - } - return callWithArgs(m, sig, args, mode); -} - -/*! - \overload - Places a call to the remote method specified by \p method on this interface, using \p args as - arguments. The \p signature parameter specifies how the arguments should be marshalled over the - connection. (It also serves to distinguish between overloading of remote methods by name) - - Normally, you should place calls using call(). -*/ -QDBusMessage QDBusInterface::callWithArgs(const QString& method, const QString& signature, - const QList<QVariant>& args, CallMode mode) -{ - QDBusMessage msg = QDBusMessage::methodCall(service(), path(), interface(), method); - msg.setSignature(signature); - msg.QList<QVariant>::operator=(args); - - QDBusMessage reply; - if (mode == WaitForReply) - reply = d->conn.sendWithReply(msg); - else - d->conn.send(msg); - - d->lastError = reply; // will clear if reply isn't an error - - // ensure that there is at least one element - if (reply.isEmpty()) - reply << QVariant(); - - return reply; -} - -/*! - Connects the D-Bus signal specified by \p sig to the given slot \p slot in the object \p obj. - - This function is similar to QObject::connect. -*/ -bool QDBusInterface::connect(const QDBusIntrospection::Signal& sig, QObject* obj, const char *slot) -{ - QString signature = QLatin1String(""); // empty, not null - - if (!sig.outputArgs.isEmpty()) - { - // go over the list of parameters for the method - QDBusIntrospection::Arguments::const_iterator it = sig.outputArgs.begin(), - end = sig.outputArgs.end(); - int arg; - for (arg = 0; it != end; ++it, ++arg) - { - // find the marshalled name for this type - QString typeSig = QLatin1String(it->type.dbusSignature()); - signature += typeSig; + } 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 + + // try to read this property + QDBusMessage msg = QDBusMessage::methodCall(service, path, DBUS_INTERFACE_PROPERTIES, + QLatin1String("Get")); + msg << interface << QString::fromUtf8(mp.name()); + + QPointer<QDBusAbstractInterface> qq = q; + QDBusMessage reply = connp->sendWithReply(msg, QDBusConnection::UseEventLoop); + + // access to "this" or to "q" below this point must check for "qq" + // we may have been deleted! + + if (reply.type() == QDBusMessage::ReplyMessage && reply.count() == 1 && + reply.signature() == QLatin1String("v")) { + QVariant value = QDBusTypeHelper<QVariant>::fromVariant(reply.at(0)); + + // make sure the type is right + if (strcmp(mp.typeName(), value.typeName()) == 0) { + if (mp.type() == QVariant::LastType) + // QVariant is special in this context + *reinterpret_cast<QVariant *>(argv[0]) = value; + else + QDBusMetaObject::assign(argv[0], value); + return -1; + } } - } - return connect(sig.name, signature, obj, slot); -} - -/*! - \overload - Connects the D-Bus signal specified by \p signalName to the given slot \p slot in the object \p - obj. - - This function is similar to QObject::connect. -*/ -bool QDBusInterface::connect(const QString& signalName, QObject* obj, const char *slot) -{ - QString s = signalName, sig; - // split out the signature from the name - int pos = signalName.indexOf(QLatin1Char('.')); - if (pos != -1) { - s.truncate(pos); - sig = QLatin1String("") + signalName.mid(pos + 1); - } - return connect(s, sig, obj, slot); -} - -/*! - \overload - Connects the D-Bus signal specified by \p signalName to the given slot \p slot in the object \p - obj. The \p signature parameter allows one to connect to the signal only if it is emitted with - the parameters matching the given type signature. - - This function is similar to QObject::connect. -*/ -bool QDBusInterface::connect(const QString& signalName, const QString& signature, - QObject* obj, const char *slot) -{ - return d->conn.connect(service(), path(), interface(), signalName, signature, obj, slot); -} - -/*! - Retrieves the value of the property \p prop in the remote object. This function returns an error - if you try to read the value of a write-only property. -*/ -QDBusReply<QDBusVariant> QDBusInterface::property(const QDBusIntrospection::Property& prop) -{ - // sanity checking - if (prop.access == QDBusIntrospection::Property::Write) - // write-only prop - return QDBusError(QLatin1String(DBUS_ERROR_ACCESS_DENIED), - QString::fromLatin1("Property %1 in interface %2 in object %3 is write-only") - .arg(prop.name, interface(), path())); - - QDBusPropertiesInterface pi(object()); - return pi.get(interface(), prop.name); -} + // got an error + if (qq.isNull()) + return -1; // bail out + + if (reply.type() == QDBusMessage::ErrorMessage) + lastError = reply; + else 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())); + } else { + QString errmsg = QLatin1String("Unexpected type `%1' when retrieving property " + "`%2 %3.%4'"); + lastError = QDBusError(QDBusError::InvalidSignature, + errmsg.arg(QLatin1String(reply.at(0).typeName()), + QLatin1String(mp.typeName()), + interface, QString::fromUtf8(mp.name()))); + } + return -1; + } 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(metaObject->propertyMetaType(id), argv[0]); + QMetaProperty mp = metaObject->property(id + metaObject->propertyOffset()); -/*! - \overload - Retrieves the value of the property \p propname in the remote object. This function returns an - error if you try to read the value of a write-only property. -*/ -QDBusReply<QDBusVariant> QDBusInterface::property(const QString& propName) -{ - // can't do sanity checking - QDBusPropertiesInterface pi(object()); - return pi.get(interface(), propName); -} + // send the value + QDBusMessage msg = QDBusMessage::methodCall(service, path, DBUS_INTERFACE_PROPERTIES, + QLatin1String("Set")); + msg.setSignature(QLatin1String("ssv")); + msg << interface << QString::fromUtf8(mp.name()) << value; -/*! - Sets the value of the property \p prop to \p newValue in the remote object. This function - automatically changes the type of \p newValue to the property's type, but the call will fail if - the types don't match. + QPointer<QDBusAbstractInterface> qq = q; + QDBusMessage reply = connp->sendWithReply(msg, QDBusConnection::UseEventLoop); - This function returns an error if the property is read-only. -*/ -QDBusReply<void> QDBusInterface::setProperty(const QDBusIntrospection::Property& prop, - const QDBusVariant &newValue) -{ - // sanity checking - if (prop.access == QDBusIntrospection::Property::Read) - // read-only prop - return QDBusError(QLatin1String(DBUS_ERROR_ACCESS_DENIED), - QString::fromLatin1("Property %1 in interface %2 in object %3 is read-only") - .arg(prop.name, interface(), path())); - - // set the property type - QDBusVariant value = newValue; - value.type = prop.type; - - QDBusPropertiesInterface pi(object()); - return pi.set(interface(), prop.name, value); -} + // access to "this" or to "q" below this point must check for "qq" + // we may have been deleted! -/*! - \overload - Sets the value of the property \p propName to \p newValue in the remote object. This function - will not change \p newValue's type to match the property, so it is your responsibility to make - sure it is of the correct type. + if (!qq.isNull() && reply.type() != QDBusMessage::ReplyMessage) + lastError = reply; - This function returns an error if the property is read-only. -*/ -QDBusReply<void> QDBusInterface::setProperty(const QString& propName, const QDBusVariant &newValue) -{ - // can't do sanity checking - QDBusPropertiesInterface pi(object()); - return pi.set(interface(), propName, newValue); + return -1; + } + return id; } -/*! - \fn QDBusMessage QDBusInterface::call(const QDBusIntrospection::Method &method, ...) - - Calls the method \p method on this interface and passes the parameters to this function to the - method. - - The parameters to \a call are passed on to the remote function via D-Bus as input - arguments. Output arguments are returned in the QDBusMessage reply. - - \warning This function reenters the Qt event loop in order to wait for the reply, excluding user - input. During the wait, it may deliver signals and other method calls to your - application. Therefore, it must be prepared to handle a reentrancy whenever a call is - placed with call(). -*/ - -/*! - \overload - \fn QDBusMessage QDBusInterface::call(const QString &method, ...) - - Calls the method \p method on this interface and passes the parameters to this function to the - method. - - The parameters to \a call are passed on to the remote function via D-Bus as input - arguments. Output arguments are returned in the QDBusMessage reply. - - \warning This function reenters the Qt event loop in order to wait for the reply, excluding user - input. During the wait, it may deliver signals and other method calls to your - application. Therefore, it must be prepared to handle a reentrancy whenever a call is - placed with call(). -*/ diff --git a/qt/qdbusinterface.h b/qt/qdbusinterface.h index 966a470..0495ada 100644 --- a/qt/qdbusinterface.h +++ b/qt/qdbusinterface.h @@ -1,6 +1,5 @@ /* -*- C++ -*- * - * Copyright (C) 2005 Thiago Macieira <thiago@kde.org> * Copyright (C) 2006 Trolltech AS. All rights reserved. * Author: Thiago Macieira <thiago.macieira@trolltech.com> * @@ -25,163 +24,23 @@ #ifndef QDBUSINTERFACE_H #define QDBUSINTERFACE_H -#include "qdbusmessage.h" -#include "qdbusobject.h" -#include "qdbusintrospection.h" -#include "qdbusreply.h" -#include "qdbusvariant.h" -#include <QtCore/qstring.h> -#include <QtCore/qvariant.h> -#include <QtCore/qlist.h> - -class QDBusConnection; +#include "qdbusabstractinterface.h" class QDBusInterfacePrivate; -class QDBUS_EXPORT QDBusInterface +class QDBUS_EXPORT QDBusInterface: public QDBusAbstractInterface { friend class QDBusConnection; - -public: - enum CallMode { - WaitForReply, - NoWaitForReply - }; - -public: - QDBusInterface(const QDBusObject& obj, const QString& name); - QDBusInterface(const QDBusInterface&); - virtual ~QDBusInterface(); - - QDBusInterface& operator=(const QDBusInterface&); - - inline QDBusObject object() - { return QDBusObject(*this); } - - inline const QDBusObject object() const - { return QDBusObject(*this); } - - inline operator QDBusObject() - { return QDBusObject(*this); } - - inline operator const QDBusObject() const - { return QDBusObject(*this); } - +private: + QDBusInterface(QDBusInterfacePrivate *p); - QDBusConnection connection() const; - - QString service() const; - QString path() const; - QString interface() const; - - virtual QString introspectionData() const; - const QDBusIntrospection::Interface& interfaceData() const; - const QDBusIntrospection::Annotations& annotationData() const; - const QDBusIntrospection::Methods& methodData() const; - const QDBusIntrospection::Signals& signalData() const; - const QDBusIntrospection::Properties& propertyData() const; - - QDBusMessage callWithArgs(const QDBusIntrospection::Method& method, - const QList<QVariant>& args = QList<QVariant>(), - CallMode mode = WaitForReply); - QDBusMessage callWithArgs(const QString& method, const QList<QVariant>& args = QList<QVariant>(), - CallMode mode = WaitForReply); - QDBusMessage callWithArgs(const QString& method, const QString& signature, - const QList<QVariant>& args = QList<QVariant>(), - CallMode mode = WaitForReply); - - bool connect(const QDBusIntrospection::Signal&, QObject* obj, const char *slot); - bool connect(const QString& signalName, QObject* obj, const char *slot); - bool connect(const QString& signalName, const QString& signature, - QObject* obj, const char *slot); - - QDBusReply<QDBusVariant> property(const QDBusIntrospection::Property&); - QDBusReply<QDBusVariant> property(const QString& property); - - QDBusReply<void> setProperty(const QDBusIntrospection::Property&, const QDBusVariant& newValue); - QDBusReply<void> setProperty(const QString& property, const QDBusVariant& newValue); - -#ifndef DOXYGEN_SHOULD_SKIP_THIS - template<typename MethodType> - inline QDBusMessage call(MethodType m) - { - return callWithArgs(m); - } - - template<typename MethodType, typename T1> - inline QDBusMessage call(MethodType m, T1 t1) - { - QList<QVariant> args; - args << t1; - return callWithArgs(m, args); - } - - template<typename MethodType, typename T1, typename T2> - inline QDBusMessage call(MethodType m, T1 t1, T2 t2) - { - QList<QVariant> args; - args << t1 << t2; - return callWithArgs(m, args); - } - - template<typename MethodType, typename T1, typename T2, typename T3> - inline QDBusMessage call(MethodType m, T1 t1, T2 t2, T3 t3) - { - QList<QVariant> args; - args << t1 << t2 << t3; - return callWithArgs(m, args); - } - - template<typename MethodType, typename T1, typename T2, typename T3, typename T4> - inline QDBusMessage call(MethodType m, T1 t1, T2 t2, T3 t3, T4 t4) - { - QList<QVariant> args; - args << t1 << t2 << t3 << t4; - return callWithArgs(m, args); - } - - template<typename MethodType, typename T1, typename T2, typename T3, typename T4, typename T5> - inline QDBusMessage call(MethodType m, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5) - { - QList<QVariant> args; - args << t1 << t2 << t3 << t4 << t5; - return callWithArgs(m, args); - } - - template<typename MethodType, typename T1, typename T2, typename T3, typename T4, typename T5, - typename T6> - inline QDBusMessage call(MethodType m, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6) - { - QList<QVariant> args; - args << t1 << t2 << t3 << t4 << t5 << t6; - return callWithArgs(m, args); - } - - template<typename MethodType, typename T1, typename T2, typename T3, typename T4, typename T5, - typename T6, typename T7> - inline QDBusMessage call(MethodType m, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7) - { - QList<QVariant> args; - args << t1 << t2 << t3 << t4 << t5 << t6 << t7; - return callWithArgs(m, args); - } - - template<typename MethodType, typename T1, typename T2, typename T3, typename T4, typename T5, - typename T6, typename T7, typename T8> - inline QDBusMessage call(MethodType m, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8) - { - QList<QVariant> args; - args << t1 << t2 << t3 << t4 << t5 << t6 << t7 << t8; - return callWithArgs(m, args); - } -#else - // fool Doxygen - inline QDBusMessage call(const QDBusIntrospection::Method &method, ...); - inline QDBusMessage call(const QString &method, ...); -#endif +public: + ~QDBusInterface(); + virtual const QMetaObject *metaObject() const; + virtual void *qt_metacast(const char *); + virtual int qt_metacall(QMetaObject::Call, int, void **); private: - QDBusInterface(QDBusInterfacePrivate*); - QDBusInterfacePrivate *d; + Q_DECLARE_PRIVATE(QDBusInterface); }; #endif diff --git a/qt/qdbusinterface_p.h b/qt/qdbusinterface_p.h index 04aa243..70b732c 100644 --- a/qt/qdbusinterface_p.h +++ b/qt/qdbusinterface_p.h @@ -1,6 +1,5 @@ /* * - * Copyright (C) 2006 Thiago José Macieira <thiago@kde.org> * Copyright (C) 2006 Trolltech AS. All rights reserved. * Author: Thiago Macieira <thiago.macieira@trolltech.com> * @@ -37,36 +36,30 @@ #ifndef QDBUSINTERFACEPRIVATE_H #define QDBUSINTERFACEPRIVATE_H -#include "qdbusobject.h" +#include "qdbusabstractinterface_p.h" +#include "qdbusmetaobject_p.h" #include "qdbusinterface.h" -#include "qdbusconnection.h" -#include "qdbuserror.h" -#define ANNOTATION_NO_WAIT "org.freedesktop.DBus.Method.NoReply" - -class QDBusInterfacePrivate +class QDBusInterfacePrivate: public QDBusAbstractInterfacePrivate { public: - QAtomic ref; - QDBusConnection conn; - QString service; - QString path; - QDBusError lastError; - - //QConstSharedDataPointer<QDBusIntrospection::Interface> data; - const QDBusIntrospection::Interface* data; - - inline QDBusInterfacePrivate(const QDBusConnection &other) : conn(other), data(emptyData()) - { } + Q_DECLARE_PUBLIC(QDBusInterface) - inline bool needsIntrospection() const - { return data && data->introspection.isNull(); } + QDBusMetaObject *metaObject; - inline void introspect() - { if (needsIntrospection()) conn.findObject(service, path).introspect(); } + inline QDBusInterfacePrivate(const QDBusConnection &con, QDBusConnectionPrivate *conp, + const QString &serv, const QString &p, const QString &iface, + QDBusMetaObject *mo = 0) + : QDBusAbstractInterfacePrivate(con, conp, serv, p, iface), metaObject(mo) + { + } + ~QDBusInterfacePrivate() + { + if (!metaObject->cached) + delete metaObject; + } - static const QDBusIntrospection::Interface *emptyData(); + int metacall(QMetaObject::Call c, int id, void **argv); }; - #endif diff --git a/qt/qdbusinternalfilters.cpp b/qt/qdbusinternalfilters.cpp index 984a878..e5a7fc9 100644 --- a/qt/qdbusinternalfilters.cpp +++ b/qt/qdbusinternalfilters.cpp @@ -26,26 +26,38 @@ #include <dbus/dbus.h> #include <QtCore/qcoreapplication.h> #include <QtCore/qmetaobject.h> +#include <QtCore/qstringlist.h> -#include "qdbusstandardinterfaces.h" #include "qdbusabstractadaptor.h" #include "qdbusabstractadaptor_p.h" #include "qdbusinterface_p.h" // for ANNOTATION_NO_WAIT #include "qdbusmessage.h" -#include "qdbustype.h" -#include "qdbusvariant.h" +#include "qdbusutil.h" + +static const char introspectableInterfaceXml[] = + " <interface name=\"org.freedesktop.DBus.Introspectable\">\n" + " <method name=\"Introspect\">\n" + " <arg name=\"xml_data\" type=\"s\" direction=\"out\"/>\n" + " </method>\n" + " </interface>\n"; + +static const char propertiesInterfaceXml[] = + " <interface name=\"org.freedesktop.DBus.Properties\">\n" + " <method name=\"Get\">\n" + " <arg name=\"interface_name\" type=\"s\" direction=\"in\"/>\n" + " <arg name=\"property_name\" type=\"s\" direction=\"in\"/>\n" + " <arg name=\"value\" type=\"v\" direction=\"out\"/>\n" + " </method>\n" + " <method name=\"Set\">\n" + " <arg name=\"interface_name\" type=\"s\" direction=\"in\"/>\n" + " <arg name=\"property_name\" type=\"s\" direction=\"in\"/>\n" + " <arg name=\"value\" type=\"v\" direction=\"in\"/>\n" + " </method>\n" + " </interface>\n"; // implement the D-Bus org.freedesktop.DBus.Introspectable interface // we do that by analysing the metaObject of all the adaptor interfaces -static inline QString dbusMemberName(const char *qtMemberName) -{ - QString retval = QLatin1String(qtMemberName); - if (!retval.isEmpty()) - retval[0] = retval[0].toUpper(); - return retval; -} - static QString generateInterfaceXml(const QMetaObject *mo, int flags, int methodOffset, int propOffset) { QString retval; @@ -57,8 +69,8 @@ static QString generateInterfaceXml(const QMetaObject *mo, int flags, int method QMetaProperty mp = mo->property(i); - if (!mp.isScriptable() && (flags & QDBusConnection::ExportNonScriptableProperties) != - QDBusConnection::ExportNonScriptableProperties) + if (!mp.isScriptable() && (flags & QDBusConnection::ExportAllProperties) != + QDBusConnection::ExportAllProperties) continue; int access = 0; @@ -72,8 +84,8 @@ static QString generateInterfaceXml(const QMetaObject *mo, int flags, int method continue; retval += QString(QLatin1String(" <property name=\"%1\" type=\"%2\" access=\"%3\" />\n")) - .arg(dbusMemberName(mp.name())) - .arg(QLatin1String(QDBusType::dbusSignature( QVariant::Type(typeId) ))) + .arg(mp.name()) + .arg(QLatin1String( QDBusUtil::typeToSignature( QVariant::Type(typeId) ))) .arg(QLatin1String( accessvalues[access] )); } } @@ -99,20 +111,19 @@ static QString generateInterfaceXml(const QMetaObject *mo, int flags, int method QString xml = QString(QLatin1String(" <%1 name=\"%2\">\n")) .arg(isSignal ? QLatin1String("signal") : QLatin1String("method")) - .arg(dbusMemberName(signature.left(paren))); + .arg(QLatin1String(signature.left(paren))); // check the return type first int typeId = qDBusNameToTypeId(mm.typeName()); if (typeId) xml += QString(QLatin1String(" <arg type=\"%1\" direction=\"out\"/>\n")) - .arg(QLatin1String(QDBusType::dbusSignature( QVariant::Type(typeId) ))); + .arg(QLatin1String(QDBusUtil::typeToSignature( QVariant::Type(typeId) ))); else if (*mm.typeName()) continue; // wasn't a valid type QList<QByteArray> names = mm.parameterNames(); QList<int> types; - int inputCount = qDBusParametersForMethod(QMetaObject::normalizedSignature(signature), - types); + int inputCount = qDBusParametersForMethod(mm, types); if (inputCount == -1) continue; // invalid form if (isSignal && inputCount + 1 != types.count()) @@ -137,12 +148,12 @@ static QString generateInterfaceXml(const QMetaObject *mo, int flags, int method xml += QString(QLatin1String(" <arg %1type=\"%2\" direction=\"%3\"/>\n")) .arg(name) - .arg(QLatin1String(QDBusType::dbusSignature( QVariant::Type(types.at(j)) ))) + .arg(QLatin1String(QDBusUtil::typeToSignature( QVariant::Type(types.at(j)) ))) .arg(isOutput ? QLatin1String("out") : QLatin1String("in")); } if (!isScriptable && - !(flags & (QDBusConnection::ExportNonScriptableSlots | QDBusConnection::ExportNonScriptableSignals))) + !(flags & (QDBusConnection::ExportAllSlots | QDBusConnection::ExportAllSignals))) continue; if (qDBusCheckAsyncTag(mm.tag())) @@ -194,7 +205,7 @@ static QString generateMetaObjectXml(QString interface, const QMetaObject *mo, c else xml = generateInterfaceXml(mo, flags, base->methodCount(), base->propertyCount()); - return QString(QLatin1String(" <interface name=\"%1\">\n%2 </interface>")) + return QString(QLatin1String(" <interface name=\"%1\">\n%2 </interface>\n")) .arg(interface, xml); } @@ -219,9 +230,6 @@ void qDBusIntrospectObject(const QDBusConnectionPrivate::ObjectTreeNode *node, xml_data += QLatin1String("<node>\n"); if (node->obj) { - xml_data += QLatin1String( QDBusIntrospectableInterface::staticIntrospectionData() ); - xml_data += QLatin1String( QDBusPropertiesInterface::staticIntrospectionData() ); - if (node->flags & QDBusConnection::ExportContents) { const QMetaObject *mo = node->obj->metaObject(); for ( ; mo != &QObject::staticMetaObject; mo = mo->superClass()) @@ -244,7 +252,7 @@ void qDBusIntrospectObject(const QDBusConnectionPrivate::ObjectTreeNode *node, // add the interface's contents: ifaceXml += generateMetaObjectXml(it->interface, it->metaObject, &QDBusAbstractAdaptor::staticMetaObject, - QDBusConnection::ExportNonScriptableContents); + QDBusConnection::ExportAllContents); QDBusAbstractAdaptorPrivate::saveIntrospectionXml(it->adaptor, ifaceXml); } @@ -252,6 +260,9 @@ void qDBusIntrospectObject(const QDBusConnectionPrivate::ObjectTreeNode *node, xml_data += ifaceXml; } } + + xml_data += QLatin1String( introspectableInterfaceXml ); + xml_data += QLatin1String( propertiesInterfaceXml ); } if (node->flags & QDBusConnection::ExportChildObjects) { @@ -308,8 +319,8 @@ void qDBusPropertyGet(const QDBusConnectionPrivate::ObjectTreeNode *node, const int pidx = node->obj->metaObject()->indexOfProperty(property_name); if (pidx != -1) { QMetaProperty mp = node->obj->metaObject()->property(pidx); - if (mp.isScriptable() || (node->flags & QDBusConnection::ExportNonScriptableProperties) == - QDBusConnection::ExportNonScriptableProperties) + if (mp.isScriptable() || (node->flags & QDBusConnection::ExportAllProperties) == + QDBusConnection::ExportAllProperties) value = mp.read(node->obj); } } @@ -331,7 +342,7 @@ void qDBusPropertySet(const QDBusConnectionPrivate::ObjectTreeNode *node, const Q_ASSERT(msg.count() == 3); QString interface_name = msg.at(0).toString(); QByteArray property_name = msg.at(1).toString().toUtf8(); - QVariant value = msg.at(2).value<QDBusVariant>(); + QVariant value = QDBusTypeHelper<QVariant>::fromVariant(msg.at(2)); QDBusAdaptorConnector *connector; if (node->flags & QDBusConnection::ExportAdaptors && @@ -353,8 +364,8 @@ void qDBusPropertySet(const QDBusConnectionPrivate::ObjectTreeNode *node, const int pidx = node->obj->metaObject()->indexOfProperty(property_name); if (pidx != -1) { QMetaProperty mp = node->obj->metaObject()->property(pidx); - if (mp.isScriptable() || (node->flags & QDBusConnection::ExportNonScriptableProperties) == - QDBusConnection::ExportNonScriptableProperties) { + if (mp.isScriptable() || (node->flags & QDBusConnection::ExportAllProperties) == + QDBusConnection::ExportAllProperties) { if (mp.write(node->obj, value)) { msg.connection().send(QDBusMessage::methodReply(msg)); diff --git a/qt/qdbusintrospection.cpp b/qt/qdbusintrospection.cpp index 634ee9d..20acbd2 100644 --- a/qt/qdbusintrospection.cpp +++ b/qt/qdbusintrospection.cpp @@ -21,12 +21,13 @@ * */ -#include "qdbusintrospection.h" +#include "qdbusintrospection_p.h" #include "qdbusxmlparser_p.h" /*! \class QDBusIntrospection \brief Information about introspected objects and interfaces on D-Bus. + \internal This class provides structures and methods for parsing the XML introspection data for D-Bus. Normally, you don't have to use the methods provided here: QDBusInterface and QDBusObject will @@ -36,7 +37,7 @@ */ /*! - \struct QDBusIntrospection::Argument + \class QDBusIntrospection::Argument \brief One argument to a D-Bus method or signal. This struct represents one argument passed to a method or received from a method or signal in @@ -54,12 +55,12 @@ */ /*! - \fn QDBusIntrospection::Argument::operator== - Compares this object against \p other and return true if they are the same. + \fn QDBusIntrospection::Argument::operator==(const Argument &other) const + Compares this object against \a other and return true if they are the same. */ /*! - \struct QDBusIntrospection::Method + \class QDBusIntrospection::Method \brief Information about one method. This struct represents one method discovered through introspection. A method is composed of @@ -89,12 +90,12 @@ */ /*! - \fn QDBusIntrospection::Method::operator== - Compares this object against \p other and return true if they are the same. + \fn QDBusIntrospection::Method::operator==(const Method &other) const + Compares this object against \a other and return true if they are the same. */ /*! - \struct QDBusIntrospection::Signal + \class QDBusIntrospection::Signal \brief Information about one signal. This struct represents one signal discovered through introspection. A signal is composed of @@ -118,12 +119,12 @@ */ /*! - \fn QDBusIntrospection::Signal::operator== - Compares this object against \p other and return true if they are the same. + \fn QDBusIntrospection::Signal::operator==(const Signal& other) const + Compares this object against \a other and return true if they are the same. */ /*! - \struct QDBusIntrospection::Property + \class QDBusIntrospection::Property \brief Information about one property. This struct represents one property discovered through introspection. A property is composed of @@ -143,9 +144,9 @@ /*! \enum QDBusIntrospection::Property::Access The possible access rights for a property: - - Read - - Write - - ReadWrite + \value Read + \value Write + \value ReadWrite */ /*! @@ -160,12 +161,12 @@ */ /*! - \fn QDBusIntrospection::Property::operator== - Compares this object against \p other and return true if they are the same. + \fn QDBusIntrospection::Property::operator==(const Property &other) const + Compares this object against \a other and return true if they are the same. */ /*! - \struct QDBusIntrospection::Interface + \class QDBusIntrospection::Interface \brief Information about one interface on the bus. Each interface on D-Bus has an unique \a name, identifying where that interface was defined. @@ -211,15 +212,15 @@ */ /*! - \fn QDBusIntrospection::Interface::operator== - Compares this object against \p other and return true if they are the same. + \fn QDBusIntrospection::Interface::operator==(const Interface &other) const + Compares this object against \a other and return true if they are the same. Note that two interfaces are considered to be the same if they have the same name. The internal structures in the objects are not compared. */ /*! - \struct QDBusIntrospection::Object + \class QDBusIntrospection::Object \brief Information about one object on the bus. An object on the D-Bus bus is represented by its service and path on the service but, unlike @@ -234,14 +235,14 @@ \var QDBusIntrospection::Object::service The object's service name. - \sa parseObject, parseObjectTree + \sa parseObject(), parseObjectTree() */ /*! \var QDBusIntrospection::Object::path The object's path on the service. This is an absolute path. - \sa parseObject, parseObjectTree + \sa parseObject(), parseObjectTree() */ /*! @@ -260,11 +261,12 @@ /*! \var QDBusIntrospection::Object::childObjects The list of child object names in this object. Note that this is a relative name, not an - absolute path. To obtain the absolute path, concatenate with \ref path. + absolute path. To obtain the absolute path, concatenate with \l + {QDBusIntrospection::Object::path}{path}. */ /*! - \struct QDBusIntrospection::ObjectTree + \class QDBusIntrospection::ObjectTree \brief Complete information about one object node and its descendency. This struct contains the same data as QDBusIntrospection::Object, plus the actual data for the @@ -324,20 +326,17 @@ \typedef QDBusIntrospection::Objects Contains a QMap of objects and their paths relative to their immediate parent. - \sa parseObjectTree + \sa parseObjectTree() */ /*! - Parses the XML document fragment containing one interface. + Parses the XML document fragment (given by \a xml) containing one interface. The first element tag in this XML data must be either \<node\> or \<interface\>. If it is \<node\>, then the \<interface\> tag must be a child tag of the \<node\> one. If there are multiple interfaces in this XML data, it is undefined which one will be returned. - - \param xml the XML data to be parsed - \returns the parsed interface */ QDBusIntrospection::Interface QDBusIntrospection::parseInterface(const QString &xml) @@ -352,23 +351,22 @@ QDBusIntrospection::parseInterface(const QString &xml) } /*! - Parses the XML document fragment containing several interfaces. + Parses the XML document fragment (given by \a xml) containing several interfaces. If the first element tag in this document fragment is \<node\>, the interfaces parsed will be those found as child elements of the \<node\> tag. - - \param xml the XML data to be parsed - \returns the parsed interfaces */ QDBusIntrospection::Interfaces QDBusIntrospection::parseInterfaces(const QString &xml) { - QDBusXmlParser parser(QString(), QString(), xml); + QString null; + QDBusXmlParser parser(null, null, xml); return parser.interfaces(); } /*! - Parses the XML document fragment containing one object. + Parses the XML document fragment (given by \a xml) containing one object, found at the service + \a service and path \a path. The first element tag in this document must be \<node\>. If that tag does not contain a name attribute, the \a path argument will be used to determine the path of this @@ -376,11 +374,6 @@ QDBusIntrospection::parseInterfaces(const QString &xml) This function does not parse the interfaces contained in the node, nor sub-object's contents. It will only list their names. If you need to know their contents, use parseObjectTree. - - \param xml the XML data to be parsed - \param service the service where this object is found - \param path the absolute path to this node on the remote service - \returns the parsed object */ QDBusIntrospection::Object QDBusIntrospection::parseObject(const QString &xml, const QString &service, const QString &path) @@ -393,15 +386,11 @@ QDBusIntrospection::parseObject(const QString &xml, const QString &service, cons } /*! - Parses the XML document fragment containing one object node and returns all the information - about the interfaces and sub-objects. + Parses the XML document fragment (given by \a xml) containing one object node and returns all + the information about the interfaces and sub-objects, found at the service \a service and path + \a path. The Objects map returned will contain the absolute path names in the key. - - \param xml the XML data to be parsed - \param service the service where this object is found - \param path the absolute path to this node on the remote service - \returns the parsed objects and interfaces */ QDBusIntrospection::ObjectTree QDBusIntrospection::parseObjectTree(const QString &xml, const QString &service, const QString &path) diff --git a/qt/qdbusintrospection.h b/qt/qdbusintrospection_p.h index 86f8524..0e4e901 100644 --- a/qt/qdbusintrospection.h +++ b/qt/qdbusintrospection_p.h @@ -30,7 +30,6 @@ #include <QtCore/qmap.h> #include <QtCore/qpair.h> #include <QtCore/qshareddata.h> -#include "qdbustype.h" #include "qdbusmacros.h" class QDBUS_EXPORT QDBusIntrospection @@ -59,7 +58,7 @@ public: struct Argument { - QDBusType type; + QString type; QString name; inline bool operator==(const Argument& other) const @@ -93,7 +92,7 @@ public: { enum Access { Read, Write, ReadWrite }; QString name; - QDBusType type; + QString type; Access access; Annotations annotations; diff --git a/qt/qdbusmacros.h b/qt/qdbusmacros.h index 72db643..a055327 100644 --- a/qt/qdbusmacros.h +++ b/qt/qdbusmacros.h @@ -30,46 +30,23 @@ #define QDBUSMACROS_H #include <QtCore/qglobal.h> +#include <QtCore/qmetatype.h> +#include <QtCore/qvariant.h> -#ifdef DBUS_COMPILATION -/// \internal +#ifdef QT_NO_MEMBER_TEMPLATES +# error Sorry, you need a compiler with support for template member functions to compile QtDBus. +#endif + +#if defined(DBUS_COMPILATION) && defined(QDBUS_MAKEDLL) # define QDBUS_EXPORT Q_DECL_EXPORT #else -/// \internal # define QDBUS_EXPORT Q_DECL_IMPORT #endif #ifndef Q_MOC_RUN -/*! - \relates QDBusAbstractAdaptor - \brief Marks a method as "asynchronous" - - The Q_ASYNC macro can be used to mark a method to be called and not wait for it to finish - processing before returning from QDBusInterface::call. The called method cannot return any - output arguments and, if it does, any such arguments will be discarded. - - You can use this macro in your own adaptors by placing it before your method's return value - (which must be "void") in the class declaration, as shown in the example: - \code - Q_ASYNC void myMethod(); - \endcode - - Its presence in the method implementation (outside the class declaration) is optional. - - \sa #async, \ref UsingAdaptors -*/ # define Q_ASYNC #endif #ifndef QT_NO_KEYWORDS - -/*! - \relates QDBusAbstractAdaptor - \brief Marks a method as "asynchronous" - - This macro is the same as #Q_ASYNC and is provided as a shorthand. However, it is not defined if - QT_NO_KEYWORDS is defined, which makes Qt not use its extensions to the C++ language (keywords - emit, signals, slots). -*/ # define async Q_ASYNC #endif diff --git a/qt/qdbusmarshall.cpp b/qt/qdbusmarshall.cpp index eb9493b..3420215 100644 --- a/qt/qdbusmarshall.cpp +++ b/qt/qdbusmarshall.cpp @@ -23,8 +23,8 @@ */ #include "qdbusmarshall_p.h" -#include "qdbustype.h" -#include "qdbusvariant.h" +#include "qdbustype_p.h" +#include "qdbustypehelper_p.h" #include <qdebug.h> #include <qvariant.h> @@ -36,6 +36,8 @@ #include <dbus/dbus.h> +static QVariant qFetchParameter(DBusMessageIter *it); + template <typename T> inline T qIterGet(DBusMessageIter *it) { @@ -44,6 +46,32 @@ inline T qIterGet(DBusMessageIter *it) return t; } +template<> +inline QVariant qIterGet(DBusMessageIter *it) +{ + DBusMessageIter sub; + dbus_message_iter_recurse(it, &sub); + return QDBusTypeHelper<QVariant>::toVariant(qFetchParameter(&sub)); +} + +template <typename DBusType, typename QtType> +inline QVariant qFetchList(DBusMessageIter *arrayIt) +{ + QList<QtType> list; + + DBusMessageIter it; + dbus_message_iter_recurse(arrayIt, &it); + + if (!dbus_message_iter_has_next(&it)) + return QDBusTypeHelper<QList<QtType> >::toVariant(list); + + do { + list.append( static_cast<QtType>( qIterGet<DBusType>(&it) ) ); + } while (dbus_message_iter_next(&it)); + + return QDBusTypeHelper<QList<QtType> >::toVariant(list); +} + static QStringList qFetchStringList(DBusMessageIter *arrayIt) { QStringList list; @@ -51,6 +79,9 @@ static QStringList qFetchStringList(DBusMessageIter *arrayIt) DBusMessageIter it; dbus_message_iter_recurse(arrayIt, &it); + if (!dbus_message_iter_has_next(&it)) + return list; + do { list.append(QString::fromUtf8(qIterGet<char *>(&it))); } while (dbus_message_iter_next(&it)); @@ -62,11 +93,11 @@ static QVariant qFetchParameter(DBusMessageIter *it) { switch (dbus_message_iter_get_arg_type(it)) { case DBUS_TYPE_BYTE: - return qIterGet<unsigned char>(it); + return qVariantFromValue(qIterGet<unsigned char>(it)); case DBUS_TYPE_INT16: - return qIterGet<dbus_int16_t>(it); + return qVariantFromValue(qIterGet<dbus_int16_t>(it)); case DBUS_TYPE_UINT16: - return qIterGet<dbus_uint16_t>(it); + return qVariantFromValue(qIterGet<dbus_uint16_t>(it)); case DBUS_TYPE_INT32: return qIterGet<dbus_int32_t>(it); case DBUS_TYPE_UINT32: @@ -74,7 +105,7 @@ static QVariant qFetchParameter(DBusMessageIter *it) case DBUS_TYPE_DOUBLE: return qIterGet<double>(it); case DBUS_TYPE_BOOLEAN: - return qIterGet<dbus_bool_t>(it); + return bool(qIterGet<dbus_bool_t>(it)); case DBUS_TYPE_INT64: return static_cast<qlonglong>(qIterGet<dbus_int64_t>(it)); case DBUS_TYPE_UINT64: @@ -83,19 +114,44 @@ static QVariant qFetchParameter(DBusMessageIter *it) case DBUS_TYPE_OBJECT_PATH: case DBUS_TYPE_SIGNATURE: return QString::fromUtf8(qIterGet<char *>(it)); + case DBUS_TYPE_VARIANT: + return qIterGet<QVariant>(it); case DBUS_TYPE_ARRAY: { int arrayType = dbus_message_iter_get_element_type(it); - if (arrayType == DBUS_TYPE_STRING || arrayType == DBUS_TYPE_OBJECT_PATH || - arrayType == DBUS_TYPE_SIGNATURE) { - return qFetchStringList(it); - } else if (arrayType == DBUS_TYPE_BYTE) { + switch (arrayType) + { + case DBUS_TYPE_BYTE: { + // QByteArray DBusMessageIter sub; dbus_message_iter_recurse(it, &sub); int len = dbus_message_iter_get_array_len(&sub); char* data; dbus_message_iter_get_fixed_array(&sub,&data,&len); return QByteArray(data,len); - } else if (arrayType == DBUS_TYPE_DICT_ENTRY) { + } + case DBUS_TYPE_INT16: + return qFetchList<dbus_int16_t, short>(it); + case DBUS_TYPE_UINT16: + return qFetchList<dbus_uint16_t, ushort>(it); + case DBUS_TYPE_INT32: + return qFetchList<dbus_int32_t, int>(it); + case DBUS_TYPE_UINT32: + return qFetchList<dbus_uint32_t, uint>(it); + case DBUS_TYPE_BOOLEAN: + return qFetchList<dbus_bool_t, bool>(it); + case DBUS_TYPE_DOUBLE: + return qFetchList<double, double>(it); + case DBUS_TYPE_INT64: + return qFetchList<dbus_int64_t, qlonglong>(it); + case DBUS_TYPE_UINT64: + return qFetchList<dbus_uint64_t, qulonglong>(it); + case DBUS_TYPE_STRING: + case DBUS_TYPE_OBJECT_PATH: + case DBUS_TYPE_SIGNATURE: + return qFetchStringList(it); + case DBUS_TYPE_VARIANT: + return qFetchList<QVariant, QVariant>(it); + case DBUS_TYPE_DICT_ENTRY: { // ### support other types of maps? QMap<QString, QVariant> map; DBusMessageIter sub; @@ -115,9 +171,10 @@ static QVariant qFetchParameter(DBusMessageIter *it) } while (dbus_message_iter_next(&sub)); return map; } + } } // fall through - // common handling for structs and lists + // common handling for structs and lists of lists (for now) case DBUS_TYPE_STRUCT: { QList<QVariant> list; DBusMessageIter sub; @@ -129,14 +186,6 @@ static QVariant qFetchParameter(DBusMessageIter *it) } while (dbus_message_iter_next(&sub)); return list; } - case DBUS_TYPE_VARIANT: { - QDBusVariant dvariant; - DBusMessageIter sub; - dbus_message_iter_recurse(it, &sub); - dvariant.type = QDBusType(dbus_message_iter_get_signature(&sub)); - dvariant.value = qFetchParameter(&sub); - return qVariantFromValue(dvariant); - } default: qWarning("Don't know how to handle type %d '%c'", dbus_message_iter_get_arg_type(it), dbus_message_iter_get_arg_type(it)); @@ -169,26 +218,20 @@ static bool checkType(QVariant &var, QDBusType &type) return true; } - // only catch the conversions that won't work - // let QVariant do the hard work - - // QVariant can't convert QDBusVariant: - if (var.userType() == qMetaTypeId<QDBusVariant>()) { - if (type.dbusType() == DBUS_TYPE_VARIANT) - return true; // no change - - // convert manually - QDBusVariant dvariant = qvariant_cast<QDBusVariant>(var); - var = dvariant.value; - return checkType(var, type); - } + int id = var.userType(); if (type.dbusType() == DBUS_TYPE_VARIANT) { - // variant can handle anything. Let it pass + // this is a non symmetrical operation: + // nest a QVariant if we want variant and it isn't so + if (id != QDBusTypeHelper<QVariant>::id()) { + QVariant tmp = var; + var = QDBusTypeHelper<QVariant>::toVariant(tmp); + } return true; } - switch (var.userType()) { + switch (id) { + case QVariant::Bool: case QMetaType::Short: case QMetaType::UShort: case QMetaType::UChar: @@ -249,10 +292,35 @@ static bool checkType(QVariant &var, QDBusType &type) return true; - case QVariant::Invalid: + case QVariant::Invalid: { // create an empty variant - var.convert(type.qvariantType()); - break; + void *null = 0; + var = QVariant(type.qvariantType(), null); + break; + } + + default: + if (id == QDBusTypeHelper<QVariant>::id()) { + // if we got here, it means the match above for DBUS_TYPE_VARIANT didn't work + qWarning("Invalid conversion from nested variant to '%s'", + type.dbusSignature().constData()); + return false; + } else if (type.dbusType() == DBUS_TYPE_ARRAY) { + int subType = type.arrayElement().dbusType(); + if ((id == QDBusTypeHelper<bool>::listId() && subType == DBUS_TYPE_BOOLEAN) || + (id == QDBusTypeHelper<short>::listId() && subType == DBUS_TYPE_INT16) || + (id == QDBusTypeHelper<ushort>::listId() && subType == DBUS_TYPE_UINT16) || + (id == QDBusTypeHelper<int>::listId() && subType == DBUS_TYPE_INT32) || + (id == QDBusTypeHelper<uint>::listId() && subType == DBUS_TYPE_UINT32) || + (id == QDBusTypeHelper<qlonglong>::listId() && subType == DBUS_TYPE_INT64) || + (id == QDBusTypeHelper<qulonglong>::listId() && subType == DBUS_TYPE_UINT64) || + (id == QDBusTypeHelper<double>::listId() && subType == DBUS_TYPE_DOUBLE)) + return true; + } + + qWarning("Invalid conversion from %s to '%s'", var.typeName(), + type.dbusSignature().constData()); + return false; } qWarning("Found unknown QVariant type %d (%s) when converting to DBus", (int)var.type(), @@ -271,7 +339,16 @@ template<typename T> static void qIterAppend(DBusMessageIter *it, const QDBusType &type, T arg) { dbus_message_iter_append_basic(it, type.dbusType(), &arg); -} +} + +template<typename DBusType, typename QtType> +static void qAppendListToMessage(DBusMessageIter *it, const QDBusType &subType, + const QVariant &var) +{ + QList<QtType> list = QDBusTypeHelper<QList<QtType> >::fromVariant(var); + foreach (const QtType &item, list) + qIterAppend(it, subType, static_cast<DBusType>(item)); +} static void qAppendArrayToMessage(DBusMessageIter *it, const QDBusType &subType, const QVariant &var) @@ -319,10 +396,33 @@ static void qAppendArrayToMessage(DBusMessageIter *it, const QDBusType &subType, break; } - default: - qFatal("qAppendArrayToMessage got unknown type!"); + default: { + int id = var.userType(); + if (id == QDBusTypeHelper<bool>::listId()) + qAppendListToMessage<dbus_bool_t,bool>(&sub, subType, var); + else if (id == QDBusTypeHelper<short>::listId()) + qAppendListToMessage<dbus_int16_t,short>(&sub, subType, var); + else if (id == QDBusTypeHelper<ushort>::listId()) + qAppendListToMessage<dbus_uint16_t,ushort>(&sub, subType, var); + else if (id == QDBusTypeHelper<int>::listId()) + qAppendListToMessage<dbus_int32_t,int>(&sub, subType, var); + else if (id == QDBusTypeHelper<uint>::listId()) + qAppendListToMessage<dbus_uint32_t,uint>(&sub, subType, var); + else if (id == QDBusTypeHelper<qlonglong>::listId()) + qAppendListToMessage<dbus_int64_t,qlonglong>(&sub, subType, var); + else if (id == QDBusTypeHelper<qulonglong>::listId()) + qAppendListToMessage<dbus_uint64_t,qulonglong>(&sub, subType, var); + else if (id == QDBusTypeHelper<double>::listId()) + qAppendListToMessage<double,double>(&sub, subType, var); +#if 0 // never reached, since QVariant::List mached + else if (id == QDBusTypeHelper<QVariant>::listId()) + qAppendListToMessage<QVariant,QVariant>(&sub, subType, var); +#endif + else + qFatal("qAppendArrayToMessage got unknown type!"); break; } + } dbus_message_iter_close_container(it, &sub); } @@ -336,28 +436,21 @@ static void qAppendStructToMessage(DBusMessageIter *it, const QDBusTypeList &typ dbus_message_iter_close_container(it, &sub); } -static void qAppendVariantToMessage(DBusMessageIter *it, const QDBusType & /* type */, +static void qAppendVariantToMessage(DBusMessageIter *it, const QDBusType &type, const QVariant &var) { - QVariant v; - QDBusType t; - - if (var.userType() == qMetaTypeId<QDBusVariant>()) { - QDBusVariant dvariant = qvariant_cast<QDBusVariant>(var); - v = dvariant.value; - t = dvariant.type; - } - else { - v = var; - } + Q_UNUSED(type); // type is 'v' - if (!t.isValid()) - t = QDBusType::guessFromVariant(v); + QVariant arg = var; + if (var.userType() == QDBusTypeHelper<QVariant>::id()) + arg = QDBusTypeHelper<QVariant>::fromVariant(var); // extract the inner variant + + QDBusType t = QDBusType::guessFromVariant(arg); // now add this variant DBusMessageIter sub; dbus_message_iter_open_container(it, DBUS_TYPE_VARIANT, t.dbusSignature(), &sub); - qVariantToIteratorInternal(&sub, v, t); + qVariantToIteratorInternal(&sub, arg, t); dbus_message_iter_close_container(it, &sub); } @@ -376,16 +469,16 @@ static void qVariantToIteratorInternal(DBusMessageIter *it, const QVariant &var, { switch (type.dbusType()) { case DBUS_TYPE_BYTE: - qIterAppend( it, type, static_cast<unsigned char>(var.toUInt()) ); + qIterAppend( it, type, QDBusTypeHelper<uchar>::fromVariant(var) ); break; case DBUS_TYPE_BOOLEAN: qIterAppend( it, type, static_cast<dbus_bool_t>(var.toBool()) ); break; case DBUS_TYPE_INT16: - qIterAppend( it, type, static_cast<dbus_int16_t>(var.toInt()) ); + qIterAppend( it, type, QDBusTypeHelper<short>::fromVariant(var) ); break; case DBUS_TYPE_UINT16: - qIterAppend( it, type, static_cast<dbus_uint16_t>(var.toUInt()) ); + qIterAppend( it, type, QDBusTypeHelper<ushort>::fromVariant(var) ); break; case DBUS_TYPE_INT32: qIterAppend( it, type, static_cast<dbus_int32_t>(var.toInt()) ); @@ -461,4 +554,3 @@ void QDBusMarshall::listToMessage(const QList<QVariant> &list, DBusMessage *msg, else qListToIterator(&it, list, QDBusTypeList(signature.toUtf8())); } - diff --git a/qt/qdbusmessage.cpp b/qt/qdbusmessage.cpp index 15364a7..308ad77 100644 --- a/qt/qdbusmessage.cpp +++ b/qt/qdbusmessage.cpp @@ -32,9 +32,10 @@ #include "qdbuserror.h" #include "qdbusmarshall_p.h" #include "qdbusmessage_p.h" +#include "qdbustypehelper_p.h" -QDBusMessagePrivate::QDBusMessagePrivate(QDBusMessage *qq) - : connection(QString()), msg(0), reply(0), q(qq), type(DBUS_MESSAGE_TYPE_INVALID), +QDBusMessagePrivate::QDBusMessagePrivate() + : connection(QString()), msg(0), reply(0), type(DBUS_MESSAGE_TYPE_INVALID), timeout(-1), ref(1), repliedTo(false) { } @@ -54,10 +55,12 @@ QDBusMessagePrivate::~QDBusMessagePrivate() This object can represent any of four different types of messages possible on the bus (see MessageType) - - Method calls - - Method return values - - Signal emissions - - Error codes + \list + \o Method calls + \o Method return values + \o Signal emissions + \o Error codes + \endlist Objects of this type are created with the four static functions signal, methodCall, methodReply and error. @@ -79,128 +82,112 @@ QDBusMessagePrivate::~QDBusMessagePrivate() from one application and is received by all applications that are listening for that signal from that interface. - \param path the path of the object that is emitting the signal - \param interface the interface that is emitting the signal - \param name the name of the signal (a.k.a. method name) - \returns a QDBusMessage object that can be sent with with QDBusConnection::send + The signal will be constructed to represent a signal coming from the path \a path, interface \a + interface and signal name \a name. + + The QDBusMessage object that is returned can be sent with QDBusConnection::send(). */ QDBusMessage QDBusMessage::signal(const QString &path, const QString &interface, const QString &name) { QDBusMessage message; - message.d->type = DBUS_MESSAGE_TYPE_SIGNAL; - message.d->path = path; - message.d->interface = interface; - message.d->name = name; + message.d_ptr->type = DBUS_MESSAGE_TYPE_SIGNAL; + message.d_ptr->path = path; + message.d_ptr->interface = interface; + message.d_ptr->name = name; return message; } /*! Constructs a new DBus message representing a method call. A method call always informs - its destination address (service, path, interface and method). + its destination address (\a service, \a path, \a interface and \a method). The DBus bus allows calling a method on a given remote object without specifying the destination interface, if the method name is unique. However, if two interfaces on the remote object export the same method name, the result is undefined (one of the two may be called or an error may be returned). - When using DBus in a peer-to-peer context (i.e., not on a bus), the service parameter is + When using DBus in a peer-to-peer context (i.e., not on a bus), the \a service parameter is optional. - Optionally, a signature parameter can be passed, indicating the type of the parameters to - be marshalled over the bus. If there are more arguments thanentries in the signature, the - tailing arguments will be silently dropped and not sent. If there are less arguments, - default values will be inserted (default values are those created by QVariant::convert - when a variant of type QVariant::Invalid is converted to the type). - The QDBusObject and QDBusInterface classes provide a simpler abstraction to synchronous method calling. - \param service the remote service to be called (can be a well-known name, a bus - address or null) - \param path the path of the object on the remote service to be called - \param interface the remote interface that is wanted (can be null) - \param method the remote method to be called (a.k.a., name) - \returns a QDBusMessage object that can be sent with QDBusConnection::send, - QDBusConnection::sendWithReply, or QDBusConnection::sendWithReplyAsync + This function returns a QDBusMessage object that can be sent with QDBusConnection::send(), + QDBusConnection::sendWithReply(), or QDBusConnection::sendWithReplyAsync(). */ QDBusMessage QDBusMessage::methodCall(const QString &service, const QString &path, const QString &interface, const QString &method) { QDBusMessage message; - message.d->type = DBUS_MESSAGE_TYPE_METHOD_CALL; - message.d->service = service; - message.d->path = path; - message.d->interface = interface; - message.d->name = method; + message.d_ptr->type = DBUS_MESSAGE_TYPE_METHOD_CALL; + message.d_ptr->service = service; + message.d_ptr->path = path; + message.d_ptr->interface = interface; + message.d_ptr->name = method; return message; } /*! - Constructs a new DBus message representing the return values from a called method. - - \param other the method call DBus message that this is a reply to - \returns a QDBusMessage object that can be sent with QDBusConnection::send + Constructs a new DBus message representing the return values from a called method. The \a other + variable represents the method call that the reply will be for. + + This function returns a QDBusMessage object that can be sent with QDBusConnection::send(). */ QDBusMessage QDBusMessage::methodReply(const QDBusMessage &other) { - Q_ASSERT(other.d->msg); + Q_ASSERT(other.d_ptr->msg); QDBusMessage message; - message.d->connection = other.d->connection; - message.d->type = DBUS_MESSAGE_TYPE_METHOD_RETURN; - message.d->reply = dbus_message_ref(other.d->msg); - other.d->repliedTo = true; + message.d_ptr->connection = other.d_ptr->connection; + message.d_ptr->type = DBUS_MESSAGE_TYPE_METHOD_RETURN; + message.d_ptr->reply = dbus_message_ref(other.d_ptr->msg); + other.d_ptr->repliedTo = true; return message; } /*! - Constructs a DBus message representing an error condition. + Constructs a DBus message representing an error condition described by the \a name + parameter. The \a msg parameter is optional and may contain a human-readable description of the + error. The \a other variable represents the method call that this error relates to. - \param other the QDBusMessage object that generated this error - \param name the DBus error name (error names must follow the same convention that - interface names do) - \param msg the error message - \return a QDBusMessage object that can be sent with QDBusMessage::send + This function returns a QDBusMessage object that can be sent with QDBusMessage::send(). */ QDBusMessage QDBusMessage::error(const QDBusMessage &other, const QString &name, const QString &msg) { - Q_ASSERT(other.d->msg); + Q_ASSERT(other.d_ptr->msg); QDBusMessage message; - message.d->connection = other.d->connection; - message.d->type = DBUS_MESSAGE_TYPE_ERROR; - message.d->name = name; - message.d->message = msg; - message.d->reply = dbus_message_ref(other.d->msg); - other.d->repliedTo = true; + message.d_ptr->connection = other.d_ptr->connection; + message.d_ptr->type = DBUS_MESSAGE_TYPE_ERROR; + message.d_ptr->name = name; + message.d_ptr->message = msg; + message.d_ptr->reply = dbus_message_ref(other.d_ptr->msg); + other.d_ptr->repliedTo = true; return message; } /*! \overload - Constructs a DBus message representing an error condition. - - \param other the QDBusMessage object that generated this error - \param error the QDBusError object representing this error - \return a QDBusMessage object that can be sent with QDBusMessage::send + Constructs a DBus message representing an error, where \a other is the method call that + generated this error and \a error is the error code. */ QDBusMessage QDBusMessage::error(const QDBusMessage &other, const QDBusError &error) { - Q_ASSERT(other.d->msg); + Q_ASSERT(other.d_ptr->msg); QDBusMessage message; - message.d->connection = other.d->connection; - message.d->type = DBUS_MESSAGE_TYPE_ERROR; - message.d->name = error.name(); - message.d->message = error.message(); - message.d->reply = dbus_message_ref(other.d->msg); - other.d->repliedTo = true; + message.d_ptr->connection = other.d_ptr->connection; + message.d_ptr->type = DBUS_MESSAGE_TYPE_ERROR; + message.d_ptr->name = error.name(); + message.d_ptr->message = error.message(); + message.d_ptr->reply = dbus_message_ref(other.d_ptr->msg); + other.d_ptr->repliedTo = true; return message; } @@ -208,21 +195,21 @@ QDBusMessage QDBusMessage::error(const QDBusMessage &other, const QDBusError &er /*! Constructs an empty, invalid QDBusMessage object. - \sa methodCall, methodReply, signal, error + \sa methodCall(), methodReply(), signal(), error() */ QDBusMessage::QDBusMessage() { - d = new QDBusMessagePrivate(this); + d_ptr = new QDBusMessagePrivate; } /*! - Constructs a copy of the other object. + Constructs a copy of the object given by \a other. */ QDBusMessage::QDBusMessage(const QDBusMessage &other) : QList<QVariant>(other) { - d = other.d; - d->ref.ref(); + d_ptr = other.d_ptr; + d_ptr->ref.ref(); } /*! @@ -230,17 +217,17 @@ QDBusMessage::QDBusMessage(const QDBusMessage &other) */ QDBusMessage::~QDBusMessage() { - if (!d->ref.deref()) - delete d; + if (!d_ptr->ref.deref()) + delete d_ptr; } /*! - Copies the contents of the other object. + Copies the contents of the object given by \a other. */ QDBusMessage &QDBusMessage::operator=(const QDBusMessage &other) { QList<QVariant>::operator=(other); - qAtomicAssign(d, other.d); + qAtomicAssign(d_ptr, other.d_ptr); return *this; } @@ -258,26 +245,26 @@ DBusMessage *QDBusMessage::toDBusMessage() const { DBusMessage *msg = 0; - switch (d->type) { + switch (d_ptr->type) { case DBUS_MESSAGE_TYPE_METHOD_CALL: - msg = dbus_message_new_method_call(data(d->service.toUtf8()), data(d->path.toUtf8()), - data(d->interface.toUtf8()), data(d->name.toUtf8())); + msg = dbus_message_new_method_call(data(d_ptr->service.toUtf8()), data(d_ptr->path.toUtf8()), + data(d_ptr->interface.toUtf8()), data(d_ptr->name.toUtf8())); break; case DBUS_MESSAGE_TYPE_SIGNAL: - msg = dbus_message_new_signal(data(d->path.toUtf8()), data(d->interface.toUtf8()), - data(d->name.toUtf8())); + msg = dbus_message_new_signal(data(d_ptr->path.toUtf8()), data(d_ptr->interface.toUtf8()), + data(d_ptr->name.toUtf8())); break; case DBUS_MESSAGE_TYPE_METHOD_RETURN: - msg = dbus_message_new_method_return(d->reply); + msg = dbus_message_new_method_return(d_ptr->reply); break; case DBUS_MESSAGE_TYPE_ERROR: - msg = dbus_message_new_error(d->reply, data(d->name.toUtf8()), data(d->message.toUtf8())); + msg = dbus_message_new_error(d_ptr->reply, data(d_ptr->name.toUtf8()), data(d_ptr->message.toUtf8())); break; } if (!msg) return 0; - QDBusMarshall::listToMessage(*this, msg, d->signature); + QDBusMarshall::listToMessage(*this, msg, d_ptr->signature); return msg; } @@ -291,16 +278,16 @@ QDBusMessage QDBusMessage::fromDBusMessage(DBusMessage *dmsg, const QDBusConnect if (!dmsg) return message; - message.d->connection = connection; - message.d->type = dbus_message_get_type(dmsg); - message.d->path = QString::fromUtf8(dbus_message_get_path(dmsg)); - message.d->interface = QString::fromUtf8(dbus_message_get_interface(dmsg)); - message.d->name = message.d->type == DBUS_MESSAGE_TYPE_ERROR ? + message.d_ptr->connection = connection; + message.d_ptr->type = dbus_message_get_type(dmsg); + message.d_ptr->path = QString::fromUtf8(dbus_message_get_path(dmsg)); + message.d_ptr->interface = QString::fromUtf8(dbus_message_get_interface(dmsg)); + message.d_ptr->name = message.d_ptr->type == DBUS_MESSAGE_TYPE_ERROR ? QString::fromUtf8(dbus_message_get_error_name(dmsg)) : QString::fromUtf8(dbus_message_get_member(dmsg)); - message.d->service = QString::fromUtf8(dbus_message_get_sender(dmsg)); - message.d->signature = QString::fromUtf8(dbus_message_get_signature(dmsg)); - message.d->msg = dbus_message_ref(dmsg); + message.d_ptr->service = QString::fromUtf8(dbus_message_get_sender(dmsg)); + message.d_ptr->signature = QString::fromUtf8(dbus_message_get_signature(dmsg)); + message.d_ptr->msg = dbus_message_ref(dmsg); QDBusMarshall::messageToList(message, dmsg); return message; @@ -312,8 +299,8 @@ QDBusMessage QDBusMessage::fromDBusMessage(DBusMessage *dmsg, const QDBusConnect QDBusMessage QDBusMessage::fromError(const QDBusError &error) { QDBusMessage message; - message.d->type = DBUS_MESSAGE_TYPE_ERROR; - message.d->name = error.name(); + message.d_ptr->type = DBUS_MESSAGE_TYPE_ERROR; + message.d_ptr->name = error.name(); message << error.message(); return message; } @@ -324,7 +311,7 @@ QDBusMessage QDBusMessage::fromError(const QDBusError &error) */ QString QDBusMessage::path() const { - return d->path; + return d_ptr->path; } /*! @@ -333,17 +320,17 @@ QString QDBusMessage::path() const */ QString QDBusMessage::interface() const { - return d->interface; + return d_ptr->interface; } /*! Returns the name of the signal that was emitted or the name of the error that was received. - \sa member + \sa member() */ QString QDBusMessage::name() const { - return d->name; + return d_ptr->name; } /*! @@ -362,7 +349,7 @@ QString QDBusMessage::name() const */ QString QDBusMessage::service() const { - return d->service; + return d_ptr->service; } /*! @@ -375,17 +362,16 @@ QString QDBusMessage::service() const */ int QDBusMessage::timeout() const { - return d->timeout; + return d_ptr->timeout; } /*! - Sets the timeout for this message to be processed. - - \param ms the time, in milliseconds + Sets the timeout for this message to be processed, given by \a ms, in milliseconds. */ void QDBusMessage::setTimeout(int ms) { - d->timeout = ms; + qAtomicDetach(d_ptr); + d_ptr->timeout = ms; } /*! @@ -395,9 +381,9 @@ void QDBusMessage::setTimeout(int ms) */ bool QDBusMessage::noReply() const { - if (!d->msg) + if (!d_ptr->msg) return false; - return dbus_message_get_no_reply(d->msg); + return dbus_message_get_no_reply(d_ptr->msg); } /*! @@ -406,9 +392,9 @@ bool QDBusMessage::noReply() const */ int QDBusMessage::serialNumber() const { - if (!d->msg) + if (!d_ptr->msg) return 0; - return dbus_message_get_serial(d->msg); + return dbus_message_get_serial(d_ptr->msg); } /*! @@ -421,9 +407,9 @@ int QDBusMessage::serialNumber() const */ int QDBusMessage::replySerialNumber() const { - if (!d->msg) + if (!d_ptr->msg) return 0; - return dbus_message_get_reply_serial(d->msg); + return dbus_message_get_reply_serial(d_ptr->msg); } /*! @@ -432,7 +418,7 @@ int QDBusMessage::replySerialNumber() const */ bool QDBusMessage::wasRepliedTo() const { - return d->repliedTo; + return d_ptr->repliedTo; } /*! @@ -441,16 +427,25 @@ bool QDBusMessage::wasRepliedTo() const */ QString QDBusMessage::signature() const { - return d->signature; + return d_ptr->signature; } /*! - Sets the signature for the output arguments of this method call. This function has no meaning - in other types of messages or when dealing with received method calls. + Sets the signature for the output arguments of this method call to be the value of \a + signature. This function has no meaning in other types of messages or when dealing with received + method calls. + + A message's signature indicate the type of the parameters to + be marshalled over the bus. If there are more arguments than entries in the signature, the + tailing arguments will be silently dropped and not sent. If there are less arguments, + default values will be inserted (default values are those created by QVariant::convert + when a variant of type QVariant::Invalid is converted to the type). + */ void QDBusMessage::setSignature(const QString &signature) { - d->signature = signature; + qAtomicDetach(d_ptr); + d_ptr->signature = signature; } /*! @@ -459,7 +454,7 @@ void QDBusMessage::setSignature(const QString &signature) */ QDBusConnection QDBusMessage::connection() const { - return d->connection; + return d_ptr->connection; } /*! @@ -467,7 +462,7 @@ QDBusConnection QDBusMessage::connection() const */ QDBusMessage::MessageType QDBusMessage::type() const { - switch (d->type) { + switch (d_ptr->type) { case DBUS_MESSAGE_TYPE_METHOD_CALL: return MethodCallMessage; case DBUS_MESSAGE_TYPE_METHOD_RETURN: @@ -493,7 +488,7 @@ QDBusMessage::MessageType QDBusMessage::type() const It can be used in the following manner: \code - QDBusReply<QString> reply = interface.call("RemoteMethod"); + QDBusReply<QString> reply = interface->call("RemoteMethod"); if (reply.isSuccess()) // use the returned value useValue(reply.value()); @@ -504,7 +499,7 @@ QDBusMessage::MessageType QDBusMessage::type() const If the remote method call cannot fail, you can skip the error checking: \code - QString reply = interface.call("RemoteMethod"); + QString reply = interface->call("RemoteMethod"); \endcode However, if it does fail under those conditions, the value returned by QDBusReply::value() is @@ -515,18 +510,18 @@ QDBusMessage::MessageType QDBusMessage::type() const or not, by calling isError() and isSuccess(), and inspecting the error condition by calling error(). You cannot call value(). - \sa QDBusMessage, QDBusInterface, \ref StandardInterfaces + \sa QDBusMessage, QDBusInterface */ /*! \fn QDBusReply::QDBusReply(const QDBusMessage &reply) - Automatically construct a QDBusReply object from the reply message \p reply, extracting the + Automatically construct a QDBusReply object from the reply message \a reply, extracting the first return value from it if it is a success reply. */ /*! \fn QDBusReply::QDBusReply(const QDBusError &error) - Construct an error reply from the D-Bus error. + Constructs an error reply from the D-Bus error code given by \a error. */ /*! @@ -554,71 +549,26 @@ QDBusMessage::MessageType QDBusMessage::type() const the return value of this function is undefined and may be undistinguishable from a valid return value. - This function is not available if the remote call returns "void". + This function is not available if the remote call returns \c void. */ /*! \fn QDBusReply::operator Type() Returns the same as value(). - This function is not available if the remote call returns "void". + This function is not available if the remote call returns \c void. */ /*! - \fn QDBusReply::fromVariant(const QDBusReply<QDBusVariant> &variantReply)> - Converts the QDBusReply<QDBusVariant> object to this type by converting the variant contained in - \p variantReply to the template's type and copying the error condition. + \internal + \fn QDBusReply::fromVariant(const QDBusReply<QVariant> &variantReply) + Converts the QDBusReply<QVariant> object to this type by converting the variant contained in + \a variantReply to the template's type and copying the error condition. - If the QDBusVariant in variantReply is not convertible to this type, it will assume an undefined + If the QVariant in variantReply is not convertible to this type, it will assume an undefined value. */ -// document QDBusVariant here too -/*! - \class QDBusVariant - \brief Represents the D-Bus type VARIANT. - - This class represents a D-Bus argument of type VARIANT, which is composed of a type description - and its value. -*/ - -/*! - \var QDBusVariant::type - Contains the VARIANT's type. It will contain an invalid type if this QDBusVariant argument was - constructed, as opposed to being received over the D-Bus connection. -*/ - -/*! - \var QDBusVariant::value - Contain's the VARIANT's value. -*/ - -/*! - \fn QDBusVariant::QDBusVariant() - Constructs an empty variant. An empty variant cannot be sent over D-Bus without being - initialized first. -*/ - -/*! - \fn QDBusVariant::QDBusVariant(const QVariant &variant) - Constructs a D-Bus Variant from the QVariant value \p variant. The D-Bus type, if not set, will - be guessed from the QVariant value when actually sending the argument over D-Bus by calling - QDBusType::guessFromVariant. You should explicitly set the type if are unsure the automatic - guessing will produce the correct type. -*/ - -/*! - \fn QDBusVariant::QDBusVariant(const QVariant &variant, const QDBusType &forcetype) - Constructs a D-Bus Variant from the QVariant of value \p variant and sets the type to \p - forcetype. The actual transformation of the QVariant to the proper D-Bus type will happen only - when sending this argument over D-Bus. -*/ - -/*! - \fn QDBusVariant::operator const QVariant &() const - Returns the value #value. -*/ - #ifndef QT_NO_DEBUG QDebug operator<<(QDebug dbg, QDBusMessage::MessageType t) { @@ -637,6 +587,106 @@ QDebug operator<<(QDebug dbg, QDBusMessage::MessageType t) } } +static void debugVariantList(QDebug dbg, const QVariantList &list); +static void debugVariantMap(QDebug dbg, const QVariantMap &map); + +static void debugVariant(QDebug dbg, const QVariant &v) +{ + dbg.nospace() << v.typeName() << "("; + switch (v.userType()) + { + case QVariant::Bool: + dbg.nospace() << v.toBool(); + break; + case QMetaType::UChar: + dbg.nospace() << qvariant_cast<uchar>(v); + break; + case QMetaType::Short: + dbg.nospace() << qvariant_cast<short>(v); + break; + case QMetaType::UShort: + dbg.nospace() << qvariant_cast<ushort>(v); + break; + case QVariant::Int: + dbg.nospace() << v.toInt(); + break; + case QVariant::UInt: + dbg.nospace() << v.toUInt(); + break; + case QVariant::LongLong: + dbg.nospace() << v.toLongLong(); + break; + case QVariant::ULongLong: + dbg.nospace() << v.toULongLong(); + break; + case QVariant::Double: + dbg.nospace() << v.toDouble(); + break; + case QVariant::String: + dbg.nospace() << v.toString(); + break; + case QVariant::ByteArray: + dbg.nospace() << v.toByteArray(); + break; + case QVariant::StringList: + dbg.nospace() << v.toStringList(); + break; + case QVariant::List: + debugVariantList(dbg, v.toList()); + break; + case QVariant::Map: + debugVariantMap(dbg, v.toMap()); + break; + + default: { + int id = v.userType(); + if (id == QDBusTypeHelper<QVariant>::id()) + debugVariant(dbg, QDBusTypeHelper<QVariant>::fromVariant(v)); + else if (id == QDBusTypeHelper<bool>::listId()) + dbg.nospace() << QDBusTypeHelper<QList<bool> >::fromVariant(v); + else if (id == QDBusTypeHelper<short>::listId()) + dbg.nospace() << QDBusTypeHelper<QList<short> >::fromVariant(v); + else if (id == QDBusTypeHelper<ushort>::listId()) + dbg.nospace() << QDBusTypeHelper<QList<ushort> >::fromVariant(v); + else if (id == QDBusTypeHelper<int>::listId()) + dbg.nospace() << QDBusTypeHelper<QList<int> >::fromVariant(v); + else if (id == QDBusTypeHelper<uint>::listId()) + dbg.nospace() << QDBusTypeHelper<QList<uint> >::fromVariant(v); + else if (id == QDBusTypeHelper<qlonglong>::listId()) + dbg.nospace() << QDBusTypeHelper<QList<qlonglong> >::fromVariant(v); + else if (id == QDBusTypeHelper<qulonglong>::listId()) + dbg.nospace() << QDBusTypeHelper<QList<qulonglong> >::fromVariant(v); + else if (id == QDBusTypeHelper<double>::listId()) + dbg.nospace() << QDBusTypeHelper<QList<double> >::fromVariant(v); + else + dbg.nospace() << "unknown"; + } + } + dbg.nospace() << ")"; +} + +static void debugVariantList(QDebug dbg, const QVariantList &list) +{ + bool first = true; + foreach (const QVariant &v, list) { + if (!first) + dbg.nospace() << ", "; + debugVariant(dbg, v); + first = false; + } +} + +static void debugVariantMap(QDebug dbg, const QVariantMap &map) +{ + QVariantMap::ConstIterator it = map.constBegin(); + QVariantMap::ConstIterator end = map.constEnd(); + for ( ; it != end; ++it) { + dbg << "(" << it.key() << ", "; + debugVariant(dbg, it.value()); + dbg << ") "; + } +} + QDebug operator<<(QDebug dbg, const QDBusMessage &msg) { dbg.nospace() << "QDBusMessage(type=" << msg.type() @@ -645,7 +695,9 @@ QDebug operator<<(QDebug dbg, const QDBusMessage &msg) << ", interface=" << msg.interface() << ", name=" << msg.name() << ", signature=" << msg.signature() - << ", contents=" << static_cast<QList<QVariant> >(msg) << ")"; + << ", contents=("; + debugVariantList(dbg, msg); + dbg.nospace() << " ) )"; return dbg.space(); } #endif diff --git a/qt/qdbusmessage.h b/qt/qdbusmessage.h index 6af5785..f8feeae 100644 --- a/qt/qdbusmessage.h +++ b/qt/qdbusmessage.h @@ -26,19 +26,21 @@ #define QDBUSMESSAGE_H #include "qdbusmacros.h" +#include "qdbuserror.h" #include <QtCore/qlist.h> #include <QtCore/qvariant.h> #include <limits.h> class QDBusMessagePrivate; -class QDBusError; class QDBusConnection; +class QDBusConnectionPrivate; struct DBusMessage; class QDBUS_EXPORT QDBusMessage: public QList<QVariant> { - friend class QDBusConnection; + //friend class QDBusConnection; + friend class QDBusConnectionPrivate; public: enum { DefaultTimeout = -1, NoTimeout = INT_MAX}; enum MessageType { InvalidMessage, MethodCallMessage, ReplyMessage, @@ -78,16 +80,15 @@ public: QDBusConnection connection() const; -//protected: - DBusMessage *toDBusMessage() const; - static QDBusMessage fromDBusMessage(DBusMessage *dmsg, const QDBusConnection &connection); - static QDBusMessage fromError(const QDBusError& error); int serialNumber() const; int replySerialNumber() const; bool wasRepliedTo() const; private: - QDBusMessagePrivate *d; + DBusMessage *toDBusMessage() const; + static QDBusMessage fromDBusMessage(DBusMessage *dmsg, const QDBusConnection &connection); + static QDBusMessage fromError(const QDBusError& error); + QDBusMessagePrivate *d_ptr; }; #ifndef QT_NO_DEBUG diff --git a/qt/qdbusmessage_p.h b/qt/qdbusmessage_p.h index 22180db..ea958b2 100644 --- a/qt/qdbusmessage_p.h +++ b/qt/qdbusmessage_p.h @@ -33,14 +33,13 @@ struct DBusMessage; class QDBusMessagePrivate { public: - QDBusMessagePrivate(QDBusMessage *qq); + QDBusMessagePrivate(); ~QDBusMessagePrivate(); QString service, path, interface, name, message, signature; QDBusConnection connection; DBusMessage *msg; DBusMessage *reply; - QDBusMessage *q; int type; int timeout; QAtomic ref; diff --git a/qt/qdbusmetaobject.cpp b/qt/qdbusmetaobject.cpp new file mode 100644 index 0000000..ccc3865 --- /dev/null +++ b/qt/qdbusmetaobject.cpp @@ -0,0 +1,675 @@ +/* -*- C++ -*- + * + * Copyright (C) 2006 Trolltech AS. All rights reserved. + * Author: Thiago Macieira <thiago.macieira@trolltech.com> + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "qdbusmetaobject_p.h" + +#include <QtCore/qbytearray.h> +#include <QtCore/qhash.h> +#include <QtCore/qstring.h> +#include <QtCore/qvarlengtharray.h> + +#include "qdbusutil.h" +#include "qdbuserror.h" +#include "qdbusintrospection_p.h" +#include "qdbusabstractinterface_p.h" + +class QDBusMetaObjectGenerator +{ +public: + QDBusMetaObjectGenerator(const QString &interface, + const QDBusIntrospection::Interface *parsedData); + void write(QDBusMetaObject *obj); + void writeWithoutXml(QDBusMetaObject *obj); + +private: + struct Method { + QByteArray parameters; + QByteArray typeName; + QByteArray tag; + QByteArray inputSignature; + QByteArray outputSignature; + QVarLengthArray<int, 6> inputTypes; + QVarLengthArray<int, 2> outputTypes; + int flags; + }; + + struct Property { + QByteArray typeName; + QByteArray signature; + int type; + int flags; + }; + + enum PropertyFlags { + Invalid = 0x00000000, + Readable = 0x00000001, + Writable = 0x00000002, + Resettable = 0x00000004, + EnumOrFlag = 0x00000008, + StdCppSet = 0x00000100, + // Override = 0x00000200, + Designable = 0x00001000, + ResolveDesignable = 0x00002000, + Scriptable = 0x00004000, + ResolveScriptable = 0x00008000, + Stored = 0x00010000, + ResolveStored = 0x00020000, + Editable = 0x00040000, + ResolveEditable = 0x00080000, + User = 0x00100000, + ResolveUser = 0x00200000 + }; + + enum MethodFlags { + AccessPrivate = 0x00, + AccessProtected = 0x01, + AccessPublic = 0x02, + AccessMask = 0x03, //mask + + MethodMethod = 0x00, + MethodSignal = 0x04, + MethodSlot = 0x08, + MethodTypeMask = 0x0c, + + MethodCompatibility = 0x10, + MethodCloned = 0x20, + MethodScriptable = 0x40 + }; + + QMap<QByteArray, Method> methods; + QMap<QByteArray, Property> properties; + + const QDBusIntrospection::Interface *data; + QString interface; + + void parseMethods(); + void parseSignals(); + void parseProperties(); +}; + +static const int intsPerProperty = 2; +static const int intsPerMethod = 4; + +// ### from kernel/qmetaobject.cpp (Qt 4.1.2): +struct QDBusMetaObjectPrivate +{ + int revision; + int className; + int classInfoCount, classInfoData; + int methodCount, methodData; + int propertyCount, propertyData; + int enumeratorCount, enumeratorData; + + // this is specific for QDBusMetaObject: + int propertyDBusData; + int methodDBusData; +}; + +QDBusMetaObjectGenerator::QDBusMetaObjectGenerator(const QString &interfaceName, + const QDBusIntrospection::Interface *parsedData) + : data(parsedData), interface(interfaceName) +{ + if (data) { + parseProperties(); + parseSignals(); // call parseSignals first so that slots override signals + parseMethods(); + } +} + +void QDBusMetaObjectGenerator::parseMethods() +{ + foreach (const QDBusIntrospection::Method &m, data->methods) { + Method mm; + + QByteArray prototype = m.name.toLatin1(); + prototype += '('; + + bool ok = true; + + // build the input argument list + foreach (const QDBusIntrospection::Argument &arg, m.inputArgs) { + int typeId = QDBusUtil::signatureToType(arg.type); + if (typeId == QVariant::Invalid) { + ok = false; + break; + } + + mm.inputSignature += arg.type; + mm.inputTypes.append(typeId); + + mm.parameters.append(arg.name.toLatin1()); + mm.parameters.append(','); + + prototype.append( QVariant::typeToName( QVariant::Type(typeId) ) ); + prototype.append(','); + } + if (!ok) continue; + + // build the output argument list: + for (int i = 0; i < m.outputArgs.count(); ++i) { + const QDBusIntrospection::Argument &arg = m.outputArgs.at(i); + + int typeId = QDBusUtil::signatureToType(arg.type); + if (typeId == QVariant::Invalid) { + ok = false; + break; + } + + mm.outputSignature += arg.type; + mm.outputTypes.append(typeId); + + if (i == 0) { + // return value + mm.typeName = QVariant::typeToName( QVariant::Type(typeId) ); + } else { + // non-const ref parameter + mm.parameters.append(arg.name.toLatin1()); + mm.parameters.append(','); + + prototype.append( QVariant::typeToName( QVariant::Type(typeId) ) ); + prototype.append("&,"); + } + } + if (!ok) continue; + + // convert the last commas: + if (!mm.parameters.isEmpty()) { + mm.parameters.truncate(mm.parameters.length() - 1); + prototype[prototype.length() - 1] = ')'; + } else { + prototype.append(')'); + } + + // check the async tag + if (m.annotations.value(QLatin1String(ANNOTATION_NO_WAIT)) == QLatin1String("true")) + mm.tag = "Q_ASYNC"; + + // meta method flags + mm.flags = AccessPublic | MethodSlot | MethodScriptable; + + // add + methods.insert(QMetaObject::normalizedSignature(prototype), mm); + } +} + +void QDBusMetaObjectGenerator::parseSignals() +{ + foreach (const QDBusIntrospection::Signal &s, data->signals_) { + Method mm; + + QByteArray prototype = s.name.toLatin1(); + prototype += '('; + + bool ok = true; + + // build the output argument list + foreach (const QDBusIntrospection::Argument &arg, s.outputArgs) { + int typeId = QDBusUtil::signatureToType(arg.type); + if (typeId == QVariant::Invalid) { + ok = false; + break; + } + + mm.inputSignature += arg.type; + mm.inputTypes.append(typeId); + + mm.parameters.append(arg.name.toLatin1()); + mm.parameters.append(','); + + prototype.append( QVariant::typeToName( QVariant::Type(typeId) ) ); + prototype.append(','); + } + if (!ok) continue; + + // convert the last commas: + if (!mm.parameters.isEmpty()) { + mm.parameters.truncate(mm.parameters.length() - 1); + prototype[prototype.length() - 1] = ')'; + } else { + prototype.append(')'); + } + + // meta method flags + mm.flags = AccessProtected | MethodSignal | MethodScriptable; + + // add + methods.insert(QMetaObject::normalizedSignature(prototype), mm); + } +} + +void QDBusMetaObjectGenerator::parseProperties() +{ + foreach (const QDBusIntrospection::Property &p, data->properties) { + Property mp; + mp.type = QDBusUtil::signatureToType(p.type); + if (mp.type == QVariant::Invalid) + continue; + + QByteArray name = p.name.toLatin1(); + mp.signature = p.type.toLatin1(); + mp.typeName = QVariant::typeToName( QVariant::Type(mp.type) ); + + // build the flags: + mp.flags = StdCppSet | Scriptable | Stored; + if (p.access != QDBusIntrospection::Property::Write) + mp.flags |= Readable; + if (p.access != QDBusIntrospection::Property::Read) + mp.flags |= Writable; + + if (mp.typeName == "QVariant") + mp.flags |= 0xff << 24; + else if (mp.type < 0xff) + // encode the type in the flags + mp.flags |= mp.type << 24; + + // add the property: + properties.insert(name, mp); + } +} + +void QDBusMetaObjectGenerator::write(QDBusMetaObject *obj) +{ + // this code here is mostly copied from qaxbase.cpp + // with a few modifications to make it cleaner + + QString className = interface; + className.replace(QLatin1Char('.'), QLatin1String("::")); + if (className.isEmpty()) + className = QLatin1String("QDBusInterface"); + + QVarLengthArray<uint> data; + data.resize(sizeof(QDBusMetaObjectPrivate) / sizeof(int)); + + QDBusMetaObjectPrivate *header = reinterpret_cast<QDBusMetaObjectPrivate *>(data.data()); + header->revision = 1; + header->className = 0; + header->classInfoCount = 0; + header->classInfoData = 0; + header->methodCount = methods.count(); + header->methodData = data.size(); + header->propertyCount = properties.count(); + header->propertyData = header->methodData + header->methodCount * 5; + header->enumeratorCount = 0; + header->enumeratorData = 0; + header->propertyDBusData = header->propertyData + header->propertyCount * 3; + header->methodDBusData = header->propertyDBusData + header->propertyCount * intsPerProperty; + + int data_size = data.size() + + (header->methodCount * (5+intsPerMethod)) + + (header->propertyCount * (3+intsPerProperty)); + foreach (const Method &mm, methods) + data_size += 2 + mm.inputTypes.count() + mm.outputTypes.count(); + data.resize(data_size + 1); + + char null('\0'); + QByteArray stringdata = className.toLatin1(); + stringdata += null; + stringdata.reserve(8192); + + int offset = header->methodData; + int signatureOffset = header->methodDBusData; + int typeidOffset = header->methodDBusData + header->methodCount * intsPerMethod; + data[typeidOffset++] = 0; // eod + + // add each method: + for (QMap<QByteArray, Method>::ConstIterator it = methods.constBegin(); + it != methods.constEnd(); ++it) { + // form "prototype\0parameters\0typeName\0tag\0inputSignature\0outputSignature" + const Method &mm = it.value(); + + data[offset++] = stringdata.length(); + stringdata += it.key(); // prototype + stringdata += null; + data[offset++] = stringdata.length(); + stringdata += mm.parameters; + stringdata += null; + data[offset++] = stringdata.length(); + stringdata += mm.typeName; + stringdata += null; + data[offset++] = stringdata.length(); + stringdata += mm.tag; + stringdata += null; + data[offset++] = mm.flags; + + data[signatureOffset++] = stringdata.length(); + stringdata += mm.inputSignature; + stringdata += null; + data[signatureOffset++] = stringdata.length(); + stringdata += mm.outputSignature; + stringdata += null; + + data[signatureOffset++] = typeidOffset; + data[typeidOffset++] = mm.inputTypes.count(); + memcpy(data.data() + typeidOffset, mm.inputTypes.data(), mm.inputTypes.count() * sizeof(int)); + typeidOffset += mm.inputTypes.count(); + + data[signatureOffset++] = typeidOffset; + data[typeidOffset++] = mm.outputTypes.count(); + memcpy(data.data() + typeidOffset, mm.outputTypes.data(), mm.outputTypes.count() * sizeof(int)); + typeidOffset += mm.outputTypes.count(); + } + + Q_ASSERT(offset == header->propertyData); + Q_ASSERT(signatureOffset == header->methodDBusData + header->methodCount * intsPerMethod); + Q_ASSERT(typeidOffset == data.size()); + + // add each property + signatureOffset = header->propertyDBusData; + for (QMap<QByteArray, Property>::ConstIterator it = properties.constBegin(); + it != properties.constEnd(); ++it) { + const Property &mp = it.value(); + + // form is "name\0typeName\0signature\0" + data[offset++] = stringdata.length(); + stringdata += it.key(); // name + stringdata += null; + data[offset++] = stringdata.length(); + stringdata += mp.typeName; + stringdata += null; + data[offset++] = mp.flags; + + data[signatureOffset++] = stringdata.length(); + stringdata += mp.signature; + stringdata += null; + data[signatureOffset++] = mp.type; + } + + Q_ASSERT(offset == header->propertyDBusData); + Q_ASSERT(signatureOffset == header->methodDBusData); + + char *string_data = new char[stringdata.length()]; + memcpy(string_data, stringdata, stringdata.length()); + + uint *uint_data = new uint[data.size()]; + memcpy(uint_data, data.data(), data.size() * sizeof(int)); + + // put the metaobject together + obj->d.data = uint_data; + obj->d.extradata = 0; + obj->d.stringdata = string_data; + obj->d.superdata = &QDBusAbstractInterface::staticMetaObject; +} + +#if 0 +void QDBusMetaObjectGenerator::writeWithoutXml(const QString &interface) +{ + // no XML definition + QString tmp(interface); + tmp.replace(QLatin1Char('.'), QLatin1String("::")); + QByteArray name(tmp.toLatin1()); + + QDBusMetaObjectPrivate *header = new QDBusMetaObjectPrivate; + memset(header, 0, sizeof *header); + header->revision = 1; + // leave the rest with 0 + + char *stringdata = new char[name.length() + 1]; + stringdata[name.length()] = '\0'; + + d.data = reinterpret_cast<uint*>(header); + d.extradata = 0; + d.stringdata = stringdata; + d.superdata = &QDBusAbstractInterface::staticMetaObject; + cached = false; +} +#endif + +///////// +// class QDBusMetaObject + +QDBusMetaObject *QDBusMetaObject::createMetaObject(QString &interface, const QString &xml, + QHash<QString, QDBusMetaObject *> &cache, + QDBusError &error) +{ + error = QDBusError(); + QDBusIntrospection::Interfaces parsed = QDBusIntrospection::parseInterfaces(xml); + + QDBusMetaObject *we = 0; + QDBusIntrospection::Interfaces::ConstIterator it = parsed.constBegin(); + QDBusIntrospection::Interfaces::ConstIterator end = parsed.constEnd(); + for ( ; it != end; ++it) { + // check if it's in the cache + QDBusMetaObject *obj = cache.value(it.key(), 0); + if (!obj) { + // not in cache; create + obj = new QDBusMetaObject; + QDBusMetaObjectGenerator generator(it.key(), it.value().constData()); + generator.write(obj); + + if ( (obj->cached = !it.key().startsWith( QLatin1String("local.") )) ) + // cache it + cache.insert(it.key(), obj); + + } + + if (it.key() == interface) { + // it's us + we = obj; + } else if (interface.isEmpty() && + !it.key().startsWith(QLatin1String("org.freedesktop.DBus."))) { + // also us + we = obj; + interface = it.key(); + } + } + + if (we) + return we; + // still nothing? + + if (parsed.isEmpty()) { + // object didn't return introspection + we = new QDBusMetaObject; + QDBusMetaObjectGenerator generator(interface, 0); + generator.write(we); + we->cached = false; + return we; + } + + // mark as an error + error = QDBusError(QDBusError::UnknownInterface, + QString( QLatin1String("Interface '%1' was not found") ) + .arg(interface)); + return 0; +} + +QDBusMetaObject::QDBusMetaObject() +{ +} + +inline const QDBusMetaObjectPrivate *priv(const uint* data) +{ + return reinterpret_cast<const QDBusMetaObjectPrivate *>(data); +} + +const char *QDBusMetaObject::dbusNameForMethod(int id) const +{ + //id -= methodOffset(); + if (id >= 0 && id < priv(d.data)->methodCount) { + int handle = priv(d.data)->methodDBusData + id*intsPerMethod; + return d.stringdata + d.data[handle]; + } + return 0; +} + +const char *QDBusMetaObject::inputSignatureForMethod(int id) const +{ + //id -= methodOffset(); + if (id >= 0 && id < priv(d.data)->methodCount) { + int handle = priv(d.data)->methodDBusData + id*intsPerMethod; + return d.stringdata + d.data[handle + 1]; + } + return 0; +} + +const char *QDBusMetaObject::outputSignatureForMethod(int id) const +{ + //id -= methodOffset(); + if (id >= 0 && id < priv(d.data)->methodCount) { + int handle = priv(d.data)->methodDBusData + id*intsPerMethod; + return d.stringdata + d.data[handle + 2]; + } + return 0; +} + +const int *QDBusMetaObject::inputTypesForMethod(int id) const +{ + //id -= methodOffset(); + if (id >= 0 && id < priv(d.data)->methodCount) { + int handle = priv(d.data)->methodDBusData + id*intsPerMethod; + return reinterpret_cast<const int*>(d.data + d.data[handle + 3]); + } + return 0; +} + +const int *QDBusMetaObject::outputTypesForMethod(int id) const +{ + //id -= methodOffset(); + if (id >= 0 && id < priv(d.data)->methodCount) { + int handle = priv(d.data)->methodDBusData + id*intsPerMethod; + return reinterpret_cast<const int*>(d.data + d.data[handle + 4]); + } + return 0; +} + +int QDBusMetaObject::propertyMetaType(int id) const +{ + //id -= propertyOffset(); + if (id >= 0 && id < priv(d.data)->propertyCount) { + int handle = priv(d.data)->propertyDBusData + id*intsPerProperty; + return d.data[handle + 1]; + } + return 0; +} + +template<typename T> +static inline void assign_helper(void *ptr, const QVariant &value) +{ + *reinterpret_cast<T *>(ptr) = qvariant_cast<T>(value); +} + +void QDBusMetaObject::assign(void *ptr, const QVariant &value) +{ + switch (value.userType()) + { + case QVariant::Bool: + assign_helper<bool>(ptr, value); + return; + + case QMetaType::UChar: + assign_helper<uchar>(ptr, value); + return; + + case QMetaType::Short: + assign_helper<short>(ptr, value); + return; + + case QMetaType::UShort: + assign_helper<ushort>(ptr, value); + return; + + case QVariant::Int: + assign_helper<int>(ptr, value); + return; + + case QVariant::UInt: + assign_helper<uint>(ptr, value); + return; + + case QVariant::LongLong: + assign_helper<qlonglong>(ptr, value); + return; + + case QVariant::ULongLong: + assign_helper<qulonglong>(ptr, value); + return; + + case QVariant::Double: + assign_helper<double>(ptr, value); + return; + + case QVariant::String: + assign_helper<QString>(ptr, value); + return; + + case QVariant::ByteArray: + assign_helper<QByteArray>(ptr, value); + return; + + case QVariant::List: + assign_helper<QVariantList>(ptr, value); + return; + + case QVariant::Map: + assign_helper<QVariantMap>(ptr, value); + return; + + default: + ; + } +} + +bool QDBusMetaTypeId::initialized = false; +int QDBusMetaTypeId::variant = 0; +int QDBusMetaTypeId::boollist = 0; +int QDBusMetaTypeId::shortlist = 0; +int QDBusMetaTypeId::ushortlist = 0; +int QDBusMetaTypeId::intlist = 0; +int QDBusMetaTypeId::uintlist = 0; +int QDBusMetaTypeId::longlonglist = 0; +int QDBusMetaTypeId::ulonglonglist = 0; +int QDBusMetaTypeId::doublelist = 0; + +bool QDBusMetaTypeId::innerInitialize() +{ + variant = qRegisterMetaType<QVariant>("QVariant"); + boollist = qRegisterMetaType<QList<bool> >("QList<bool>"); + shortlist = qRegisterMetaType<QList<short> >("QList<short>"); + ushortlist = qRegisterMetaType<QList<ushort> >("QList<ushort>"); + intlist = qRegisterMetaType<QList<int> >("QList<int>"); + uintlist = qRegisterMetaType<QList<uint> >("QList<uint>"); + longlonglist = qRegisterMetaType<QList<qlonglong> >("QList<qlonglong>"); + ulonglonglist = qRegisterMetaType<QList<qulonglong> >("QList<qulonglong>"); + doublelist = qRegisterMetaType<QList<double> >("QList<double>"); + initialized = true; + return true; +} + +int qDBusMetaTypeId(QVariant *) +{ QDBusMetaTypeId::initialize(); return QDBusMetaTypeId::variant; } +int qDBusMetaTypeId(QList<bool> *) +{ QDBusMetaTypeId::initialize(); return QDBusMetaTypeId::boollist; } +int qDBusMetaTypeId(QList<short> *) +{ QDBusMetaTypeId::initialize(); return QDBusMetaTypeId::shortlist; } +int qDBusMetaTypeId(QList<ushort> *) +{ QDBusMetaTypeId::initialize(); return QDBusMetaTypeId::ushortlist; } +int qDBusMetaTypeId(QList<int> *) +{ QDBusMetaTypeId::initialize(); return QDBusMetaTypeId::intlist; } +int qDBusMetaTypeId(QList<uint> *) +{ QDBusMetaTypeId::initialize(); return QDBusMetaTypeId::uintlist; } +int qDBusMetaTypeId(QList<qlonglong> *) +{ QDBusMetaTypeId::initialize(); return QDBusMetaTypeId::longlonglist; } +int qDBusMetaTypeId(QList<qulonglong> *) +{ QDBusMetaTypeId::initialize(); return QDBusMetaTypeId::ulonglonglist; } +int qDBusMetaTypeId(QList<double> *) +{ QDBusMetaTypeId::initialize(); return QDBusMetaTypeId::doublelist; } diff --git a/qt/qdbusmetaobject_p.h b/qt/qdbusmetaobject_p.h new file mode 100644 index 0000000..c62c972 --- /dev/null +++ b/qt/qdbusmetaobject_p.h @@ -0,0 +1,96 @@ +/* + * + * Copyright (C) 2006 Trolltech AS. All rights reserved. + * Author: Thiago Macieira <thiago.macieira@trolltech.com> + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the public API. This header file may +// change from version to version without notice, or even be +// removed. +// +// We mean it. +// +// + +#ifndef QDBUSMETAOBJECTPRIVATE_H +#define QDBUSMETAOBJECTPRIVATE_H + +#include <QtCore/qmetaobject.h> +#include "qdbusmacros.h" + +class QDBusError; + +class QDBusMetaObjectPrivate; +struct QDBUS_EXPORT QDBusMetaObject: public QMetaObject +{ + bool cached; + + static QDBusMetaObject *createMetaObject(QString &interface, const QString &xml, + QHash<QString, QDBusMetaObject *> &map, + QDBusError &error); + ~QDBusMetaObject() + { + delete [] d.stringdata; + delete [] d.data; + } + + // methods (slots & signals): + const char *dbusNameForMethod(int id) const; + const char *inputSignatureForMethod(int id) const; + const char *outputSignatureForMethod(int id) const; + const int *inputTypesForMethod(int id) const; + const int *outputTypesForMethod(int id) const; + + // properties: + int propertyMetaType(int id) const; + + // helper function: + static void assign(void *, const QVariant &value); + +private: + QDBusMetaObject(); +}; + +struct QDBusMetaTypeId +{ + static bool innerInitialize(); + static bool initialized; + static inline void initialize() + { + if (initialized) return; + innerInitialize(); + } + + static int variant; + static int boollist; + static int shortlist; + static int ushortlist; + static int intlist; + static int uintlist; + static int longlonglist; + static int ulonglonglist; + static int doublelist; +}; + +#endif diff --git a/qt/qdbusobject.cpp b/qt/qdbusobject.cpp deleted file mode 100644 index 3fd9a5b..0000000 --- a/qt/qdbusobject.cpp +++ /dev/null @@ -1,248 +0,0 @@ -/* -*- C++ -*- - * - * Copyright (C) 2005 Thiago Macieira <thiago@kde.org> - * Copyright (C) 2006 Trolltech AS. All rights reserved. - * Author: Thiago Macieira <thiago.macieira@trolltech.com> - * - * Licensed under the Academic Free License version 2.1 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - */ - -#include "qdbusmessage.h" -#include "qdbusconnection.h" -#include "qdbusobject.h" -#include "qdbusinterface.h" -#include "qdbusstandardinterfaces.h" -#include "qdbuserror.h" - -#include "qdbusxmlparser_p.h" -#include "qdbusobject_p.h" -#include "qdbusutil.h" - -/*! - \class QDBusObject - \brief Base object for referencing remote D-Bus Objects - - This class provides the basic functionality for referencing remote objects. It does not, - however, allow you to place calls to the remote object: you have to use the QDBusInterface class - for that. -*/ - -/*! - \internal -*/ -QDBusObject::QDBusObject(QDBusObjectPrivate* p, const QDBusConnection& conn) - :d(p), m_conn(conn) -{ -} - -/*! - Creates a QDBusObject that references the same object that the QDBusInterface class does. -*/ -QDBusObject::QDBusObject(const QDBusInterface& iface) - : m_conn(iface.connection()) -{ - *this = m_conn.findObject(iface.service(), iface.path()); -} - -/*! - Copy constructor: creates a copy of the \p other object. -*/ -QDBusObject::QDBusObject(const QDBusObject& other) - : d(other.d), m_conn(other.m_conn) -{ -} - -/*! - Destroys this object and frees any resource it held. -*/ -QDBusObject::~QDBusObject() -{ -} - -/*! - Assignment operator: copy the contents of the \p other QDBusObject. -*/ -QDBusObject& QDBusObject::operator=(const QDBusObject& other) -{ -#if 0 - if (other.d) - other.d->ref.ref(); - - QDBusObjectPrivate* old = qAtomicSetPtr(&d, other.d); - if (old && !old->ref.deref()) - m_conn.d->disposeOf(d); -#endif - d = other.d; - - return *this; -} - -/*! - Returns the connection this object is bound to. -*/ -QDBusConnection QDBusObject::connection() const -{ - return m_conn; -} - -/*! - Returns the service this object is associated to. - \sa connection -*/ -QString QDBusObject::service() const -{ - return d ? d->data->service : QString(); -} - -/*! - Returns the path on the remote service this object is on. - \sa connection, service -*/ -QString QDBusObject::path() const -{ - return d ? d->data->path : QString(); -} - -/*! - Places an Introspect call to the remote object and return the XML data that describes its - contents. This is the raw XML data of the structures introspectionData() returns. - - \bug We should not cache here. The remote object can change. -*/ -QString QDBusObject::introspect() const -{ - if (!d) - // not connected - return QString(); - - if (d->data->introspection.isNull()) { - // Try to introspect - QDBusIntrospectableInterface iface(*this); - QDBusReply<QString> reply = iface.introspect(); - - if (reply.isSuccess()) { - // this will change the contents of d->data - QDBusXmlParser::parse(d, reply); - } - } - return d->data->introspection; -} - -/*! - Places an Introspect call to the remote object and return the parsed structures representing the - object's interfaces and child objects. The raw XML data corresponding to this function's - structures can be obtained using introspect(). -*/ -QSharedDataPointer<QDBusIntrospection::Object> QDBusObject::introspectionData() const -{ - QSharedDataPointer<QDBusIntrospection::Object> retval; - if (d) - retval = const_cast<QDBusIntrospection::Object*>(d->data); - return retval; -} - -/*! - Returns a list of all the interfaces in this object. This is the same value as the found in the - \ref QDBusIntrospection::Object::interfaces "interfaces" member of the value returned by - introspectionData(). -*/ -QStringList QDBusObject::interfaces() const -{ - introspect(); - return d ? d->data->interfaces : QStringList(); -} - -/*! - Returns a map of all the children object in this object along with pre-created QDBusObjects for - referencing them. - - \todo Write this function! -*/ -QMap<QString, QDBusObject> QDBusObject::children() const -{ - QMap<QString, QDBusObject> retval; -#if 0 - if (!d) - return retval; - - QString prefix = d->path; - if (!prefix.endsWith('/')) - prefix.append('/'); - foreach (QString sub, d->childObjects) - retval.insert(sub, QDBusObject( m_conn.d->findObject(d->path, prefix + sub), m_conn )); - - return retval; -#endif - qFatal("fixme!"); - return retval; -} - -/*! - Returns true if we're referencing a valid object service and path. This does not mean the object - actually exists in the remote application or that the remote application exists. -*/ -bool QDBusObject::isValid() const -{ - return d && m_conn.isConnected() && QDBusUtil::isValidBusName(d->data->service) && - QDBusUtil::isValidObjectPath(d->data->path); -} - -#if 0 // we don't have a way of determining if an object exists or not -/*! - Returns true if the object being referenced exists. -*/ -bool QDBusObject::exists() const -{ - if (!isValid()) - return false; - - // call a non-existant interface/method - QDBusMessage msg = QDBusMessage::methodCall(d->service, d->path, - "org.freedesktop.DBus.NonExistant", "NonExistant"); - QDBusMessage reply = m_conn.sendWithReply(msg); - // ignore the reply - - QDBusError err = m_conn.lastError(); - if (!err.isValid()) { - qWarning("D-Bus call to %s:%s on a supposedly non-existant interface worked!", - qPrintable(d->service), qPrintable(d->path)); - return true; - } - - if (err.name == DBUS_ERROR_SERVICE_UNKNOWN || - err.name == DBUS_ERROR_BAD_ADDRESS) - return !m_conn.lastError().isValid(); -} -#endif - -/*! - \fn QDBusObject::operator Interface() - Cast this object to an interface, if possible. -*/ - -/*! - \fn QDBusObject::operator const Interface() - Cast this object to an interface, if possible. -*/ - -/*! - \fn qdbus_cast - \relates QDBusObject - - Casts a QDBusObject to the QDBusInterface-derived class of type Interface. -*/ diff --git a/qt/qdbusobject.h b/qt/qdbusobject.h deleted file mode 100644 index 584f3b2..0000000 --- a/qt/qdbusobject.h +++ /dev/null @@ -1,102 +0,0 @@ -/* -*- C++ -*- - * - * Copyright (C) 2005 Thiago Macieira <thiago@kde.org> - * Copyright (C) 2006 Trolltech AS. All rights reserved. - * Author: Thiago Macieira <thiago.macieira@trolltech.com> - * - * Licensed under the Academic Free License version 2.1 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - */ - -#ifndef QDBUSOBJECT_H -#define QDBUSOBJECT_H - -#include <QtCore/qstring.h> -#include <QtCore/qvariant.h> -#include <QtCore/qlist.h> -#include <QtCore/qshareddata.h> - -#include "qdbusconnection.h" -#include "qdbusintrospection.h" - -class QDBusInterface; -class QDBusObject; - -template<class Interface> -inline Interface qdbus_cast(QDBusObject& obj, Interface * = 0); - -template<class Interface> -inline const Interface qdbus_cast(const QDBusObject& obj, Interface * = 0); - -class QDBusObjectPrivate; -class QDBUS_EXPORT QDBusObject -{ - friend class QDBusConnection; -public: - // public constructors - QDBusObject(const QDBusObject& other); - QDBusObject(const QDBusInterface& iface); - - // public destructors - ~QDBusObject(); - -public: - // public functions - QDBusObject& operator=(const QDBusObject&); - - QDBusConnection connection() const; - QString service() const; - QString path() const; - - QString introspect() const; - QSharedDataPointer<QDBusIntrospection::Object> introspectionData() const; - - QStringList interfaces() const; - QMap<QString, QDBusObject> children() const; - - //bool exists() const; - bool isValid() const; - -#ifndef QT_NO_MEMBER_TEMPLATES - template<typename Interface> - inline operator Interface() - { return qdbus_cast<Interface>(*this); } - - template<typename Interface> - inline operator const Interface() const - { return qdbus_cast<Interface>(*this); } -#endif - -private: - QDBusObject(QDBusObjectPrivate*, const QDBusConnection& conn); - QSharedDataPointer<QDBusObjectPrivate> d; - QDBusConnection m_conn; -}; - -template<class Interface> -inline Interface qdbus_cast(QDBusObject& obj, Interface *) -{ - return Interface(obj); -} - -template<class Interface> -inline const Interface qdbus_cast(const QDBusObject& obj, Interface *) -{ - return Interface(obj); -} - -#endif // QDBUSOBJECT_H diff --git a/qt/qdbusreply.h b/qt/qdbusreply.h index 3d7a008..f22082c 100644 --- a/qt/qdbusreply.h +++ b/qt/qdbusreply.h @@ -30,22 +30,22 @@ #include "qdbusmacros.h" #include "qdbusmessage.h" #include "qdbuserror.h" -#include "qdbusvariant.h" + +#include "qdbustypehelper_p.h" template<typename T> class QDBUS_EXPORT QDBusReply { typedef T Type; public: - inline QDBusReply(const QDBusMessage &reply) - : m_error(reply) + : m_error(reply), m_data(Type()) { if (isSuccess()) - m_data = qvariant_cast<Type>(reply.at(0)); + m_data = QDBusTypeHelper<Type>::fromVariant(reply.at(0)); } inline QDBusReply(const QDBusError &error) - : m_error(error) + : m_error(error), m_data(Type()) { } @@ -64,14 +64,14 @@ public: return m_data; } - static QDBusReply<T> fromVariant(const QDBusReply<QDBusVariant> &variantReply) + static QDBusReply<T> fromVariant(const QDBusReply<QVariant> &variantReply) { QDBusReply<T> retval; retval.m_error = variantReply.m_error; if (retval.isSuccess()) { - retval.m_data = qvariant_cast<Type>(variantReply.value); - if (!qVariantCanConvert<Type>(variantReply.value)) - retval.m_error = QDBusError(QLatin1String(DBUS_ERROR_INVALID_SIGNATURE), + retval.m_data = qvariant_cast<Type>(variantReply.m_data); + if (!qVariantCanConvert<Type>(variantReply.m_data)) + retval.m_error = QDBusError(QDBusError::InvalidSignature, QLatin1String("Unexpected reply signature")); } return retval; @@ -82,7 +82,7 @@ private: Type m_data; }; -#ifndef DOXYGEN_SHOULD_SKIP_THIS +# ifndef Q_QDOC // specialize for void: template<> class QDBUS_EXPORT QDBusReply<void> @@ -105,6 +105,6 @@ public: private: QDBusError m_error; }; -#endif +# endif #endif diff --git a/qt/qdbusstandardinterfaces.cpp b/qt/qdbusstandardinterfaces.cpp deleted file mode 100644 index e444d97..0000000 --- a/qt/qdbusstandardinterfaces.cpp +++ /dev/null @@ -1,302 +0,0 @@ -/* -*- C++ -*- - * - * Copyright (C) 2005 Thiago Macieira <thiago@kde.org> - * Copyright (C) 2006 Trolltech AS. All rights reserved. - * Author: Thiago Macieira <thiago.macieira@trolltech.com> - * - * Licensed under the Academic Free License version 2.1 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - */ - -#include "qdbusstandardinterfaces.h" - -/*! - \page StandardInterfaces Standard D-Bus Interfaces - - The standard, well-known interfaces provided by D-Bus are as follows: - \value org.freedesktop.DBus.Peer Peer detection - \value org.freedesktop.DBus.Introspectable Introspection of remote object's contents - \value org.freedesktop.DBus.Properties Access to remote object's properties - - The QtDBus implementation provides easy access to those three interfaces with the - QDBusPeerInterface, QDBusIntrospectableInterface and QDBusPropertiesInterface classes. As a - convenience form, they can also be accessed by the classes org::freedesktop::DBus::Peer, - org::freedesktop::DBus::Introspectable and org::freedesktop::DBus::Properties. - - Those three classes also illustrate code-generation by the \ref dbusidl2cpp tool: the methods - defined in those three interfaces are provided as member functions in the QtDBus classes, which - are capable of type-checking the parameters at compile-time, in order to guarantee that they - conform to the types expected by the remote objects. -*/ - -/*! - \typedef org::freedesktop::DBus::Peer -*/ - -/*! - \typedef org::freedesktop::DBus::Introspectable -*/ - -/*! - \typedef org::freedesktop::DBus::Properties -*/ - -/*! - \class QDBusPeerInterface - \brief Provides access to the \a org.freedesktop.DBus.Peer interface. - - This interface has only one method: ping(). Calling this method will generate a success reply if - the target service exists or a failure if it doesn't. The target object path is irrelevant in - this case. -*/ - -/*! - \fn QDBusPeerInterface::staticInterfaceName - Returns the interface name: "org.freedesktop.DBus.Peer" -*/ - -/*! - \fn QDBusPeerInterface::staticIntrospectionData - Returns the XML fragment corresponding to this interface's definition. -*/ - -/*! - \fn QDBusPeerInterface::QDBusPeerInterface(const QDBusObject &) - Creates a QDBusPeerInterface object accessing interface the \a org.freedesktop.DBus.Peer - interface on object \p obj. -*/ - -/*! - \fn QDBusPeerInterface::introspectionData() const - Returns the XML fragment corresponding to this interface's definition. -*/ - -/*! - \fn QDBusPeerInterface::ping - Emits an \a org.freedesktop.DBus.Peer.Ping call to the remote object. -*/ - -/*! - Destroys this object. -*/ -QDBusPeerInterface::~QDBusPeerInterface() -{ -} - -/*! - \class QDBusIntrospectableInterface - \brief Provides access to the \a org.freedesktop.DBus.Introspectable interface. - - The \a Introspectable interface is used to obtain information about the remote object's - internals. Its one method, \a introspect(), returns a XML document describing the interfaces and - child objects of a remote object in the D-Bus bus. - - The QtDBus implementation automatically introspects remote objects in order to construct the - introspection structures found in QDBusIntrospection and QDBusInterface. - - \sa QDBusInterface, QDBusIntrospection, QDBusObject::interfaces, QDBusObject::childObjects, - QDBusObject::introspect -*/ - -/*! - \fn QDBusIntrospectableInterface::staticInterfaceName - Returns the interface name: "org.freedesktop.DBus.Introspection" -*/ - -/*! - \fn QDBusIntrospectableInterface::staticIntrospectionData - Returns the XML fragment corresponding to this interface's definition. -*/ - -/*! - \fn QDBusIntrospectableInterface::QDBusIntrospectableInterface(const QDBusObject &) - Creates a QDBusIntrospectableInterface object accessing interface the \a - org.freedesktop.DBus.Introspectable interface on object \p obj. -*/ - -/*! - \fn QDBusIntrospectableInterface::introspectionData() const - Returns the XML fragment corresponding to this interface's definition. -*/ - -/*! - \fn QDBusIntrospectableInterface::introspect - Places an \a org.freedesktop.DBus.Introspectable.Introspect call to the remote object and - return the XML result. -*/ - -/*! - Destroys the object. -*/ -QDBusIntrospectableInterface::~QDBusIntrospectableInterface() -{ -} - -/*! - \class QDBusPropertiesInterface - \brief Provides access to the \a org.freedesktop.DBus.Properties interface - - D-Bus interfaces can export properties, much like the ones used in QObject. In order to access - those properties, two methods are defined in the \a org.freedesktop.DBus.Properties interface: - get() and set(), which are similar in functionality to QObject::property and - QObject::setProperty. -*/ - -/*! - \fn QDBusPropertiesInterface::staticInterfaceName - Returns the interface name: "org.freedesktop.DBus.Properties" -*/ - -/*! - \fn QDBusPropertiesInterface::staticIntrospectionData - Returns the XML fragment corresponding to this interface's definition. -*/ - -/*! - \fn QDBusPropertiesInterface::QDBusPropertiesInterface(const QDBusObject &) - Creates a QDBusPropertiesInterface object accessing interface the \a - org.freedesktop.DBus.Properties interface on object \p obj. -*/ - -/*! - \fn QDBusPropertiesInterface::introspectionData() const - Returns the XML fragment corresponding to this interface's definition. -*/ - -/*! - \fn QDBusPropertiesInterface::set(const QString &interfaceName, const QString &propertyName, - const QDBusVariant &value) - Sets the property named \a propertyName in interface \a interfaceName in the remote object this - QDBusPropertiesInterface object points to to the value specified by \a value. This function is - analogous to QObject::setProperty. - - If the type of the \a value parameter is not what the remote interface declared, the result is - undefined. See QDBusInterface::properties for information on remote properties. - - \sa QDBusInterface::setProperty -*/ - -/*! - \fn QDBusPropertiesInterface::get(const QString &interfaceName, const QString &propertyName) - Retrieves the value of property named \a propertyName in interface \a interfaceName in the - remote object this QDBusPropertiesInterface object points to. This function is analogous to - QObject::property. - - \sa QDBusInterface::property -*/ - -/*! - Destroys the object. -*/ -QDBusPropertiesInterface::~QDBusPropertiesInterface() -{ -} - -#if 0 -/*! - \class QDBusBusInterface - \internal - \brief Provides access to the \a org.freedesktop.DBus interface found in the D-Bus server - daemon. - - The org.freedesktop.DBus interface is found only in the D-Bus daemon server. It is used to - communicate with it and to request information about the bus itself and other applications in - it. - - Normally, you don't need to use this interface in your application. Instead, use the methods in - QDBusConnection. - - \sa QDBusConnection -*/ - -QDBusBusInterface::~QDBusBusInterface() -{ -} - -const char* QDBusBusInterface::staticIntrospectionData() -{ - // FIXME! - // This should be auto-generated! - - return - "<interface name=\"org.freedesktop.DBus\">" - "<method name=\"RequestName\">" - "<arg direction=\"in\" type=\"s\"/>" - "<arg direction=\"in\" type=\"u\"/>" - "<arg direction=\"out\" type=\"u\"/>" - "</method>" - "<method name=\"ReleaseName\">" - "<arg direction=\"in\" type=\"s\"/>" - "<arg direction=\"out\" type=\"u\"/>" - "</method>" - "<method name=\"StartServiceByName\">" - "<arg direction=\"in\" type=\"s\"/>" - "<arg direction=\"in\" type=\"u\"/>" - "<arg direction=\"out\" type=\"u\"/>" - "</method>" - "<method name=\"Hello\">" - "<arg direction=\"out\" type=\"s\"/>" - "</method>" - "<method name=\"NameHasOwner\">" - "<arg direction=\"in\" type=\"s\"/>" - "<arg direction=\"out\" type=\"b\"/>" - "</method>" - "<method name=\"ListNames\">" - "<arg direction=\"out\" type=\"as\"/>" - "</method>" - "<method name=\"AddMatch\">" - "<arg direction=\"in\" type=\"s\"/>" - "</method>" - "<method name=\"RemoveMatch\">" - "<arg direction=\"in\" type=\"s\"/>" - "</method>" - "<method name=\"GetNameOwner\">" - "<arg direction=\"in\" type=\"s\"/>" - "<arg direction=\"out\" type=\"s\"/>" - "</method>" - "<method name=\"ListQueuedOwners\">" - "<arg direction=\"in\" type=\"s\"/>" - "<arg direction=\"out\" type=\"as\"/>" - "</method>" - "<method name=\"GetConnectionUnixUser\">" - "<arg direction=\"in\" type=\"s\"/>" - "<arg direction=\"out\" type=\"u\"/>" - "</method>" - "<method name=\"GetConnectionUnixProcessID\">" - "<arg direction=\"in\" type=\"s\"/>" - "<arg direction=\"out\" type=\"u\"/>" - "</method>" - "<method name=\"GetConnectionSELinuxSecurityContext\">" - "<arg direction=\"in\" type=\"s\"/>" - "<arg direction=\"out\" type=\"ay\"/>" - "</method>" - "<method name=\"ReloadConfig\">" - "</method>" - "<signal name=\"NameOwnerChanged\">" - "<arg type=\"s\"/>" - "<arg type=\"s\"/>" - "<arg type=\"s\"/>" - "</signal>" - "<signal name=\"NameLost\">" - "<arg type=\"s\"/>" - "</signal>" - "<signal name=\"NameAcquired\">" - "<arg type=\"s\"/>" - "</signal>" - "</interface>"; -} -#endif diff --git a/qt/qdbusstandardinterfaces.h b/qt/qdbusstandardinterfaces.h deleted file mode 100644 index f2c88c3..0000000 --- a/qt/qdbusstandardinterfaces.h +++ /dev/null @@ -1,206 +0,0 @@ -/* -*- C++ -*- - * - * Copyright (C) 2005 Thiago Macieira <thiago@kde.org> - * Copyright (C) 2006 Trolltech AS. All rights reserved. - * Author: Thiago Macieira <thiago.macieira@trolltech.com> - * - * Licensed under the Academic Free License version 2.1 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - */ - -#ifndef QDBUS_STANDARD_INTERFACES_H -#define QDBUS_STANDARD_INTERFACES_H - -#include "qdbusinterface.h" -#include "qdbusreply.h" -#include <QtCore/qstring.h> -#include <QtCore/qstringlist.h> -#include <dbus/dbus.h> - -class QDBusConnection; - -class QDBUS_EXPORT QDBusPeerInterface: public QDBusInterface -{ -public: - static inline const char* staticInterfaceName() - { return DBUS_INTERFACE_PEER; } - - static inline const char* staticIntrospectionData() - { - return - " <interface name=\"org.freedesktop.DBus.Peer\">\n" - " <method name=\"Ping\" />\n" - " </interface>\n"; - } - -public: - explicit QDBusPeerInterface(const QDBusObject& obj) - : QDBusInterface(obj, QLatin1String(staticInterfaceName())) - { } - - ~QDBusPeerInterface(); - - inline virtual QString introspectionData() const - { return QString::fromLatin1(staticIntrospectionData()); } - - inline QDBusReply<void> ping() - { return call(QLatin1String("Ping")); } -}; - -class QDBUS_EXPORT QDBusIntrospectableInterface: public QDBusInterface -{ -public: - static inline const char* staticInterfaceName() - { return DBUS_INTERFACE_INTROSPECTABLE; } - - static inline const char* staticIntrospectionData() - { - return - " <interface name=\"org.freedesktop.DBus.Introspectable\">\n" - " <method name=\"Introspect\">\n" - " <arg name=\"xml_data\" type=\"s\" direction=\"out\"/>\n" - " </method>\n" - " </interface>\n"; - } -public: - explicit QDBusIntrospectableInterface(const QDBusObject& obj) - : QDBusInterface(obj, QLatin1String(staticInterfaceName())) - { } - - ~QDBusIntrospectableInterface(); - - inline virtual QString introspectionData() const - { return QLatin1String(staticIntrospectionData()); } - - inline QDBusReply<QString> introspect() - { return call(QLatin1String("Introspect")); } -}; - -class QDBUS_EXPORT QDBusPropertiesInterface: public QDBusInterface -{ -public: - static inline const char* staticInterfaceName() - { return DBUS_INTERFACE_PROPERTIES; } - - static inline const char* staticIntrospectionData() - { - return - " <interface name=\"org.freedesktop.DBus.Properties\">\n" - " <method name=\"Get\">\n" - " <arg name=\"interface_name\" type=\"s\" direction=\"in\"/>\n" - " <arg name=\"property_name\" type=\"s\" direction=\"in\"/>\n" - " <arg name=\"value\" type=\"v\" direction=\"out\"/>\n" - " </method>\n" - " <method name=\"Set\">\n" - " <arg name=\"interface_name\" type=\"s\" direction=\"in\"/>\n" - " <arg name=\"property_name\" type=\"s\" direction=\"in\"/>\n" - " <arg name=\"value\" type=\"v\" direction=\"in\"/>\n" - " </method>\n" - " </interface>\n"; - } -public: - explicit QDBusPropertiesInterface(const QDBusObject& obj) - : QDBusInterface(obj, QLatin1String(staticInterfaceName())) - { } - - ~QDBusPropertiesInterface(); - - inline virtual QString introspectionData() const - { return QString::fromLatin1(staticIntrospectionData()); } - - inline QDBusReply<void> set(const QString& interfaceName, const QString& propertyName, - const QDBusVariant &value) - { return call(QLatin1String("Set.ssv"), interfaceName, propertyName, value); } - - inline QDBusReply<QDBusVariant> get(const QString& interfaceName, const QString& propertyName) - { return call(QLatin1String("Get.ss"), interfaceName, propertyName); } -}; - -#if 0 -class QDBUS_EXPORT QDBusBusInterface: public QDBusInterface -{ -public: - static inline const char* staticInterfaceName() - { return DBUS_INTERFACE_DBUS; } - - static const char* staticIntrospectionData(); - -public: - explicit QDBusBusInterface(const QDBusObject& obj) - : QDBusInterface(obj, staticInterfaceName()) - { } - - ~QDBusBusInterface(); - - inline virtual QString introspectionData() const - { return staticIntrospectionData(); } - - inline QDBusReply<unsigned> requestName(const QString& name, unsigned flags) - { return call(QLatin1String("RequestName.su"), name, flags); } - - inline QDBusReply<unsigned> releaseName(const QString& name) - { return call(QLatin1String("ReleaseName.s"), name); } - - inline QDBusReply<unsigned> startServiceByName(const QString& name, unsigned flags) - { return call(QLatin1String("StartServiceByName.su"), name, flags); } - - inline QDBusReply<QString> Hello() - { return call(QLatin1String("Hello")); } - - inline QDBusReply<bool> nameHasOwner(const QString& name) - { return call(QLatin1String("NameHasOwner.s"), name); } - - inline QDBusReply<QStringList> listNames() - { return call(QLatin1String("ListNames")); } - - inline QDBusReply<void> addMatch(const QString& rule) - { return call(QLatin1String("AddMatch"), rule); } - - inline QDBusReply<void> removeMatch(const QString& rule) - { return call(QLatin1String("RemoveMatch"), rule); } - - inline QDBusReply<QString> getNameOwner(const QString& name) - { return call(QLatin1String("GetNameOwner.s"), name); } - - inline QDBusReply<QStringList> listQueuedOwners(const QString& name) - { return call(QLatin1String("ListQueuedOwners.s"), name); } - - inline QDBusReply<quint32> getConnectionUnixUser(const QString& connectionName) - { return call(QLatin1String("GetConnectionUnixUser.s"), connectionName); } - - inline QDBusReply<quint32> getConnectionUnixProcessID(const QString& connectionName) - { return call(QLatin1String("GetConnectionUnixProcessID.s"), connectionName); } - - inline QDBusReply<QByteArray> getConnectionSELinuxSecurityContext(const QString& connectionName) - { return call(QLatin1String("GetConnectionSELinuxSecurityContext.s"), connectionName); } - - inline QDBusReply<void> reloadConfig() - { return call(QLatin1String("ReloadConfig")); } -}; -#endif - -namespace org { - namespace freedesktop { - namespace DBus { - typedef ::QDBusPeerInterface Peer; - typedef ::QDBusIntrospectableInterface Introspectable; - typedef ::QDBusPropertiesInterface Properties; - } - } -} - -#endif diff --git a/qt/qdbustype.cpp b/qt/qdbustype.cpp index 97c9e15..7f17a37 100644 --- a/qt/qdbustype.cpp +++ b/qt/qdbustype.cpp @@ -22,264 +22,17 @@ * */ -#include "qdbustype.h" -#include "qdbusvariant.h" +#include "qdbustype_p.h" +#include "qdbustypehelper_p.h" #include <dbus/dbus.h> #include <QtCore/qstringlist.h> -/// \internal -class QDBusPrettyTypeBase -{ -public: - struct Entry - { - const char* prettyName; - char signature; - }; - - enum Direction - { - In, - Out - }; - - enum Access - { - Read, - Write, - ReadWrite - }; - - // so that the compiler doesn't complain - virtual ~QDBusPrettyTypeBase() { } - - virtual QString addElementsToArray(const QString& subType) = 0; - virtual QString addElementsToMap(const QString& key, const QString& value) = 0; - virtual QString addElementsToStruct(const QStringList& subTypes) = 0; - virtual const Entry* entryMap() = 0; - - QString toString(const QDBusType& type); - QString toString(const QDBusTypeList& list); -}; - -/// \internal -class QDBusConventionalNames: public QDBusPrettyTypeBase -{ -public: - virtual QString addElementsToArray(const QString& subType); - virtual QString addElementsToMap(const QString& key, const QString& value); - virtual QString addElementsToStruct(const QStringList& subTypes) ; - virtual const Entry* entryMap(); -}; - -/// \internal -class QDBusQtNames: public QDBusPrettyTypeBase -{ -public: - virtual QString addElementsToArray(const QString& subType); - virtual QString addElementsToMap(const QString& key, const QString& value); - virtual QString addElementsToStruct(const QStringList& subTypes) ; - virtual const Entry* entryMap(); -}; - -//! \internal -class QDBusQVariantNames: public QDBusQtNames -{ -public: - virtual QString addElementsToArray(const QString& subType); - virtual QString addElementsToMap(const QString& key, const QString& value); - virtual QString addElementsToStruct(const QStringList& subTypes) ; -}; - -static QString findInMap(char type, const QDBusPrettyTypeBase::Entry* map) -{ - for ( ; map->signature; ++map) - if (type == map->signature) - return QLatin1String(map->prettyName); - return QString(); -} - -// -// Input MUST be valid -// -inline QString QDBusPrettyTypeBase::toString(const QDBusType& type) -{ - const Entry* map = entryMap(); - - const QDBusTypeList subTypes = type.subTypes(); - switch (type.dbusType()) { - case DBUS_TYPE_STRUCT: { - // handle a struct - // find its sub-types - - QStringList subStrings; - QDBusTypeList subTypes = type.subTypes(); - foreach (QDBusType t, subTypes) - subStrings << toString( t ); - - return addElementsToStruct(subStrings); - } - - case DBUS_TYPE_DICT_ENTRY: { - Q_ASSERT_X(subTypes.size() == 2, "QDBusType::toString", - "maps must have exactly two elements"); - - QString key = findInMap( subTypes.at(0).dbusType(), map ); - QString value = toString( subTypes.at(1) ); - - Q_ASSERT(!key.isNull()); - - return addElementsToMap( key, value ); - } - case DBUS_TYPE_ARRAY: { - Q_ASSERT_X(subTypes.size() == 1, "QDBusType::toString", - "more than one element in array"); - - if (type.qvariantType() == QVariant::Map) - return toString( subTypes.first() ); - return addElementsToArray( toString( subTypes.at(0) ) ); - } - - default: { - // normal, non-compound type - QString name = findInMap(type.dbusType(), map); - Q_ASSERT(!name.isNull()); - return name; - } - } -} - -const QDBusPrettyTypeBase::Entry* QDBusConventionalNames::entryMap() -{ - static QDBusPrettyTypeBase::Entry translation[] = { - { "BYTE", DBUS_TYPE_BYTE }, - { "BOOLEAN", DBUS_TYPE_BOOLEAN }, - { "INT16", DBUS_TYPE_INT16 }, - { "UINT16", DBUS_TYPE_UINT16 }, - { "INT32", DBUS_TYPE_INT32 }, - { "UINT32", DBUS_TYPE_UINT32 }, - { "INT64", DBUS_TYPE_INT64 }, - { "UINT64", DBUS_TYPE_UINT64 }, - { "DOUBLE", DBUS_TYPE_DOUBLE }, - { "STRING", DBUS_TYPE_STRING }, - { "OBJECT_PATH", DBUS_TYPE_OBJECT_PATH }, - { "SIGNATURE", DBUS_TYPE_SIGNATURE }, - { "VARIANT", DBUS_TYPE_VARIANT } - }; - return translation; -} - -QString QDBusConventionalNames::addElementsToStruct(const QStringList& subTypes) -{ - return QString( QLatin1String("STRUCT of (%1)") ) - .arg( subTypes.join( QLatin1String(",") ) ); -} - -QString QDBusConventionalNames::addElementsToMap(const QString& key, const QString& value) -{ - return QString( QLatin1String("ARRAY of DICT_ENTRY of (%1,%2)") ) - .arg(key).arg(value); -} - -QString QDBusConventionalNames::addElementsToArray(const QString& subType) -{ - return QString( QLatin1String("ARRAY of %1") ) - .arg(subType); -} - -const QDBusPrettyTypeBase::Entry* QDBusQtNames::entryMap() -{ - static QDBusPrettyTypeBase::Entry translation[] = { - { "uchar", DBUS_TYPE_BYTE }, - { "bool", DBUS_TYPE_BOOLEAN }, - { "short", DBUS_TYPE_INT16 }, - { "ushort", DBUS_TYPE_UINT16 }, - { "int", DBUS_TYPE_INT32 }, - { "uint", DBUS_TYPE_UINT32 }, - { "qlonglong", DBUS_TYPE_INT64 }, - { "qulonglong", DBUS_TYPE_UINT64 }, - { "double", DBUS_TYPE_DOUBLE }, - { "QString", DBUS_TYPE_STRING }, - { "QString", DBUS_TYPE_OBJECT_PATH }, - { "QString", DBUS_TYPE_SIGNATURE }, - { "QDBusVariant", DBUS_TYPE_VARIANT } - }; - return translation; -} - -static inline QString templateArg(const QString& input) -{ - if (input.endsWith(QLatin1Char('>'))) - return input + QLatin1Char(' '); - return input; -} - -QString QDBusQtNames::addElementsToStruct(const QStringList& subTypes) -{ - Q_UNUSED(subTypes); - - return QLatin1String("QVariantList"); // CHANGEME in the future -} - -QString QDBusQtNames::addElementsToMap(const QString& key, const QString& value) -{ - if (key == QLatin1String("QString") && value == QLatin1String("QDBusVariant")) - return QLatin1String("QVariantMap"); - - return QString( QLatin1String("QMap<%1, %2>") ) - .arg(key) - .arg( templateArg(value) ); -} - -QString QDBusQtNames::addElementsToArray(const QString& subType) -{ - if (subType == QLatin1String("uchar")) - // special case - return QLatin1String("QByteArray"); - else if (subType == QLatin1String("QString")) - // special case - return QLatin1String("QStringList"); - - return QString( QLatin1String("QList<%1>") ) - .arg( templateArg(subType) ); -} - -QString QDBusQVariantNames::addElementsToStruct(const QStringList& subTypes) -{ - Q_UNUSED(subTypes); - - return QLatin1String("QVariantList"); -} - -QString QDBusQVariantNames::addElementsToMap(const QString& key, const QString& value) -{ - Q_UNUSED(key); - Q_UNUSED(value); - - return QLatin1String("QVariantMap"); -} - -QString QDBusQVariantNames::addElementsToArray(const QString& subType) -{ - if (subType == QLatin1String("uchar")) - // special case - return QLatin1String("QByteArray"); - else if (subType == QLatin1String("QString")) - // special case - return QLatin1String("QStringList"); - - return QLatin1String("QVariantList"); -} - -/*! - \internal -*/ class QDBusTypePrivate: public QSharedData { public: int code; - mutable QVariant::Type qvariantType; + mutable int qvariantType; mutable QByteArray signature; QDBusTypeList subTypes; @@ -291,6 +44,7 @@ public: /*! \class QDBusType \brief Represents one single D-Bus type. + \internal D-Bus provides a set of primitive types that map to normal, C++ types and to QString, as well as the possibility to extend the set with the so-called "container" types. The available types are @@ -322,18 +76,6 @@ public: */ /*! - \enum QDBusType::StringFormat - - This enum is used in QDBusType::toString to determine which type of formatting - to apply to the D-Bus types: - - \value ConventionalNames Use the DBus conventional names, such as STRING, BOOLEAN or - ARRAY of BYTE. - \value QtNames Use the Qt type names, such as QString, bool and QList<quint32> - \value QVariantNames Same as QtNames, but for containers, use QVariantList and QVariantMap -*/ - -/*! Constructs an empty (invalid) type. */ QDBusType::QDBusType() @@ -342,7 +84,7 @@ QDBusType::QDBusType() } /*! - Constructs the type based on the given DBus type. + Constructs the type based on the D-Bus type given by \a type. */ QDBusType::QDBusType(int type) { @@ -351,7 +93,7 @@ QDBusType::QDBusType(int type) } /*! - Constructs the type based on the given QVariant type. + Constructs the type based on the QVariant type given by \a type. \sa QVariant::Type */ @@ -360,38 +102,33 @@ QDBusType::QDBusType(QVariant::Type type) const char *sig = dbusSignature(type); // it never returns NULL + // but it may return an empty string: if (sig[0] == '\0') return; - d = new QDBusTypePrivate; - d->qvariantType = type; - d->code = sig[0]; - if (sig[1] == '\0') - // single-letter type - return; - else if (sig[2] == '\0') { - // two-letter type - // must be an array + if (qstrlen(sig) > 2) { + *this = QDBusType(sig); + } else { + d = new QDBusTypePrivate; + d->qvariantType = type; d->code = sig[0]; - QDBusType t; - t.d = new QDBusTypePrivate; - t.d->code = sig[1]; - d->subTypes << t; - } - else { - // the only longer type is "a{sv}" - Q_ASSERT(sig[1] == '{' && sig[5] == '\0'); - - static QDBusType map("a{sv}"); - d->subTypes = map.d->subTypes; + if (sig[1] == '\0') + // single-letter type + return; + else { + // two-letter type + // must be an array + d->code = sig[0]; + QDBusType t; + t.d = new QDBusTypePrivate; + t.d->code = sig[1]; + d->subTypes << t; + } } } /*! - Parses the given DBus signature and constructs the type it represents. - - \param signature the signature to parse. It must represent one single type, but can be - a container type. + Parses the D-Bus signature given by \a signature and constructs the type it represents. */ QDBusType::QDBusType(const char* signature) { @@ -406,10 +143,8 @@ QDBusType::QDBusType(const char* signature) } /*! - Parses the given DBus signature and constructs the type it represents. - - \param str the signature to parse. It must represent one single type, but can - a container type. + \overload + Parses the D-Bus signature given by \a str and constructs the type it represents. */ QDBusType::QDBusType(const QString& str) { @@ -417,10 +152,8 @@ QDBusType::QDBusType(const QString& str) } /*! - Parses the given DBus signature and constructs the type it represents. - - \param str the signature to parse. It must represent one single type, but can - a container type. + \overload + Parses the D-Bus signature given by \a str and constructs the type it represents. */ QDBusType::QDBusType(const QByteArray& str) { @@ -430,8 +163,6 @@ QDBusType::QDBusType(const QByteArray& str) /*! \internal Creates a QDBusType object based on the current element pointed to by \a iter. - - \param iter the iterator. Can be pointing to container types. */ QDBusType::QDBusType(DBusSignatureIter* iter) : d(new QDBusTypePrivate) @@ -458,7 +189,7 @@ QDBusType::QDBusType(DBusSignatureIter* iter) } /*! - Copies the type from the other object. + Copies the type from the object \a other. */ QDBusType::QDBusType(const QDBusType& other) : d(other.d) @@ -473,7 +204,7 @@ QDBusType::~QDBusType() } /*! - Copies the type from the other object. + Copies the type from the object given by \a other. */ QDBusType& QDBusType::operator=(const QDBusType& other) { @@ -550,24 +281,15 @@ QByteArray QDBusType::dbusSignature() const /*! Returns the QVariant::Type for this entry. */ -QVariant::Type QDBusType::qvariantType() const +int QDBusType::qvariantType() const { if (d && d->qvariantType != QVariant::Invalid) return d->qvariantType; - // check the special array cases: - if (isArray()) { - QDBusType t = arrayElement(); - - if (t.dbusType() == DBUS_TYPE_BYTE) - return QVariant::ByteArray; - else if (t.dbusType() == DBUS_TYPE_DICT_ENTRY) - return QVariant::Map; - else if (t.isBasic() && t.qvariantType() == QVariant::String) - return QVariant::StringList; - } + if (!d) + return QVariant::Invalid; - return qvariantType(dbusType()); + return d->qvariantType = qvariantType(dbusSignature().constData()); } /*! @@ -580,8 +302,6 @@ bool QDBusType::isValid() const /*! Returns true if this type is a basic one. - - \sa dbus_type_is_basic */ bool QDBusType::isBasic() const { @@ -590,8 +310,6 @@ bool QDBusType::isBasic() const /*! Returns true if this type is a container. - - \sa dbus_type_is_container */ bool QDBusType::isContainer() const { @@ -601,7 +319,7 @@ bool QDBusType::isContainer() const /*! Returns the subtypes of this type, if this is a container. - \sa isContainer + \sa isContainer() */ QDBusTypeList QDBusType::subTypes() const { @@ -613,7 +331,7 @@ QDBusTypeList QDBusType::subTypes() const /*! Returns true if this type is an array. - \sa isContainer, arrayElement + \sa isContainer(), arrayElement() */ bool QDBusType::isArray() const { @@ -624,7 +342,7 @@ bool QDBusType::isArray() const This is a convenience function that returns the element type of an array. If this object is not an array, it returns an invalid QDBusType. - \sa isArray + \sa isArray() */ QDBusType QDBusType::arrayElement() const { @@ -636,7 +354,7 @@ QDBusType QDBusType::arrayElement() const /*! Returns true if this type is a map (i.e., an array of dictionary entries). - \sa isContainer, isArray, arrayElement + \sa isContainer(), isArray(), arrayElement() */ bool QDBusType::isMap() const { @@ -647,7 +365,7 @@ bool QDBusType::isMap() const If this object is a map, returns the (basic) type that corresponds to the key type. If this object is not a map, returns an invalid QDBusType. - \sa isMap + \sa isMap() */ QDBusType QDBusType::mapKey() const { @@ -660,7 +378,7 @@ QDBusType QDBusType::mapKey() const If this object is a map, returns the type that corresponds to the value type. If this object is not a map, returns an invalid QDBusType. - \sa isMap + \sa isMap() */ QDBusType QDBusType::mapValue() const { @@ -670,7 +388,7 @@ QDBusType QDBusType::mapValue() const } /*! - Returns true if the two types match. + Returns true if this type is the same one as \a other. */ bool QDBusType::operator==(const QDBusType& other) const { @@ -682,37 +400,23 @@ bool QDBusType::operator==(const QDBusType& other) const } /*! - Returns a string representation of this type. + \fn QDBusType::operator!=(const QDBusType &other) const + Returns true if the this type and the one given by \a other are different. */ -QString QDBusType::toString(StringFormat sf) const -{ - switch (sf) { - case ConventionalNames: - return QDBusConventionalNames().toString(*this); - - case QtNames: - return QDBusQtNames().toString(*this); - - case QVariantNames: - return QDBusQVariantNames().toString(*this); - } - - return QString(); // invalid -} /*! - Converts the DBus type to QVariant::Type + Converts the DBus type code \a type to QVariant::Type. */ -QVariant::Type QDBusType::qvariantType(int type) +int QDBusType::qvariantType(int type) { char c[2] = { type, 0 }; return qvariantType(c); } /*! - Converts the DBus type signature to QVariant::Type. + Converts the DBus type signature \a signature to QVariant::Type. */ -QVariant::Type QDBusType::qvariantType(const char* signature) +int QDBusType::qvariantType(const char* signature) { if (!signature) return QVariant::Invalid; @@ -736,12 +440,18 @@ QVariant::Type QDBusType::qvariantType(const char* signature) case DBUS_TYPE_BOOLEAN: return QVariant::Bool; + case DBUS_TYPE_BYTE: + return QMetaType::UChar; + case DBUS_TYPE_INT16: - case DBUS_TYPE_INT32: - return QVariant::Int; + return QMetaType::Short; - case DBUS_TYPE_BYTE: case DBUS_TYPE_UINT16: + return QMetaType::UShort; + + case DBUS_TYPE_INT32: + return QVariant::Int; + case DBUS_TYPE_UINT32: return QVariant::UInt; @@ -763,23 +473,51 @@ QVariant::Type QDBusType::qvariantType(const char* signature) return QVariant::List; // change to QDBusStruct in the future case DBUS_TYPE_VARIANT: - return QVariant::UserType; // must set user-type too + return QDBusTypeHelper<QVariant>::id(); case DBUS_TYPE_ARRAY: // special case - // check if it's a string list - if (qvariantType(signature + 1) == QVariant::String) - return QVariant::StringList; + switch (signature[1]) { + case DBUS_TYPE_BOOLEAN: + return QDBusTypeHelper<bool>::listId(); - // maybe it's a byte array - if (DBUS_TYPE_BYTE == signature[1]) + case DBUS_TYPE_BYTE: return QVariant::ByteArray; - // check if it's a dict - if (DBUS_DICT_ENTRY_BEGIN_CHAR == signature[1]) - return QVariant::Map; + case DBUS_TYPE_INT16: + return QDBusTypeHelper<short>::listId(); + + case DBUS_TYPE_UINT16: + return QDBusTypeHelper<ushort>::listId(); + + case DBUS_TYPE_INT32: + return QDBusTypeHelper<int>::listId(); - return QVariant::List; + case DBUS_TYPE_UINT32: + return QDBusTypeHelper<uint>::listId(); + + case DBUS_TYPE_INT64: + return QDBusTypeHelper<qlonglong>::listId(); + + case DBUS_TYPE_UINT64: + return QDBusTypeHelper<qulonglong>::listId(); + + case DBUS_TYPE_DOUBLE: + return QDBusTypeHelper<double>::listId(); + + case DBUS_TYPE_STRING: + case DBUS_TYPE_OBJECT_PATH: + case DBUS_TYPE_SIGNATURE: + return QVariant::StringList; + case DBUS_TYPE_VARIANT: + return QVariant::List; + + case DBUS_DICT_ENTRY_BEGIN_CHAR: + return QVariant::Map; + + default: + return QVariant::List; + } default: return QVariant::Invalid; @@ -787,9 +525,7 @@ QVariant::Type QDBusType::qvariantType(const char* signature) } /*! - Converts the QVariant::Type to a DBus type code. - - \param t the type to convert + Converts the QVariant::Type \a t to a DBus type code. */ int QDBusType::dbusType(QVariant::Type t) { @@ -802,7 +538,6 @@ int QDBusType::dbusType(QVariant::Type t) return DBUS_TYPE_INT32; case QVariant::UInt: - case QVariant::Char: return DBUS_TYPE_UINT32; case QVariant::LongLong: @@ -825,9 +560,6 @@ int QDBusType::dbusType(QVariant::Type t) return DBUS_TYPE_BYTE; case QVariant::String: - case QVariant::Date: - case QVariant::Time: - case QVariant::DateTime: return DBUS_TYPE_STRING; case QVariant::Map: @@ -841,22 +573,20 @@ int QDBusType::dbusType(QVariant::Type t) return DBUS_TYPE_ARRAY; case QVariant::UserType: - return DBUS_TYPE_VARIANT; + return DBUS_TYPE_INVALID; // invalid default: break; // avoid compiler warnings } - if (int(t) == QMetaTypeId<QDBusVariant>::qt_metatype_id()) + if (int(t) == QDBusTypeHelper<QVariant>::id()) return DBUS_TYPE_VARIANT; return DBUS_TYPE_INVALID; } /*! - Converts the QVariant::Type to a DBus type signature. - - \param t the type to convert + Converts the QVariant::Type \a t to a DBus type signature. */ const char* QDBusType::dbusSignature(QVariant::Type t) { @@ -869,7 +599,6 @@ const char* QDBusType::dbusSignature(QVariant::Type t) return DBUS_TYPE_INT32_AS_STRING; case QVariant::UInt: - case QVariant::Char: return DBUS_TYPE_UINT32_AS_STRING; case QMetaType::Short: @@ -891,9 +620,6 @@ const char* QDBusType::dbusSignature(QVariant::Type t) return DBUS_TYPE_DOUBLE_AS_STRING; case QVariant::String: - case QVariant::Date: - case QVariant::Time: - case QVariant::DateTime: return DBUS_TYPE_STRING_AS_STRING; case QVariant::Map: @@ -920,8 +646,24 @@ const char* QDBusType::dbusSignature(QVariant::Type t) DBUS_TYPE_VARIANT_AS_STRING; // av default: - if (int(t) == qMetaTypeId<QDBusVariant>()) + if (int(t) == QDBusTypeHelper<QVariant>::id()) return DBUS_TYPE_VARIANT_AS_STRING; + if (int(t) == QDBusTypeHelper<bool>::listId()) + return DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_BOOLEAN_AS_STRING; + if (int(t) == QDBusTypeHelper<short>::listId()) + return DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_INT16_AS_STRING; + if (int(t) == QDBusTypeHelper<ushort>::listId()) + return DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_UINT16_AS_STRING; + if (int(t) == QDBusTypeHelper<int>::listId()) + return DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_INT32_AS_STRING; + if (int(t) == QDBusTypeHelper<uint>::listId()) + return DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_UINT32_AS_STRING; + if (int(t) == QDBusTypeHelper<qlonglong>::listId()) + return DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_INT64_AS_STRING; + if (int(t) == QDBusTypeHelper<qulonglong>::listId()) + return DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_UINT64_AS_STRING; + if (int(t) == QDBusTypeHelper<double>::listId()) + return DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_DOUBLE_AS_STRING; return DBUS_TYPE_INVALID_AS_STRING; } @@ -931,12 +673,10 @@ const char* QDBusType::dbusSignature(QVariant::Type t) \enum QDBusType::VariantListMode Defines how the guessFromVariant() function will behave when the QVariant is of type QVariant::List. - - \todo Improve the algorithm */ /*! - Guesses the DBus type from the given variant. + Guesses the DBus type from the given \a variant. */ QDBusType QDBusType::guessFromVariant(const QVariant& variant, VariantListMode mode) { @@ -944,46 +684,36 @@ QDBusType QDBusType::guessFromVariant(const QVariant& variant, VariantListMode m // investigate deeper QDBusType t; t.d = new QDBusTypePrivate; + const QVariantList list = variant.toList(); - if (mode == ListIsArray) { - t.d->code = DBUS_TYPE_ARRAY; - - const QVariantList list = variant.toList(); - if (!list.isEmpty()) { - // check if all elements have the same type - QVariant::Type type = list.first().type(); - foreach (const QVariant& v, list) - if (type != v.type()) { - // at least one is different - type = QVariant::Invalid; - break; - } - - if (type != QVariant::Invalid) { - // all are of the same type - t.d->subTypes << guessFromVariant(list.first()); - return t; + t.d->code = DBUS_TYPE_ARRAY; + if (!list.isEmpty()) { + // check if all elements have the same type + QVariant::Type type = list.first().type(); + foreach (const QVariant& v, list) + if (type != v.type()) { + // at least one is different + type = QVariant::Invalid; + break; } + + if (type != QVariant::Invalid) { + // all are of the same type + t.d->subTypes << guessFromVariant(list.first()); + return t; } - - // internal information has been lost or there are many types - QDBusType nested; - nested.d = new QDBusTypePrivate; - nested.d->code = DBUS_TYPE_VARIANT; - t.d->subTypes << nested; - return t; - } - else { - // treat it as a struct - t.d->code = DBUS_TYPE_STRUCT; - - // add the elements: - const QVariantList list = variant.toList(); - foreach (const QVariant& v, list) - t.d->subTypes << guessFromVariant(v, mode); - + } else { + // an array of "something" + t.d->subTypes << QDBusType('v'); return t; } + + // treat it as a struct + t.d->code = DBUS_TYPE_STRUCT; + foreach (const QVariant& v, list) + t.d->subTypes << guessFromVariant(v, mode); + + return t; } else if (variant.type() == QVariant::Map) { // investigate deeper @@ -1029,12 +759,13 @@ QDBusType QDBusType::guessFromVariant(const QVariant& variant, VariantListMode m return t; } else - return QDBusType(variant.type()); + return QDBusType( QVariant::Type( variant.userType() ) ); } /*! \class QDBusTypeList \brief A list of DBus types. + \internal Represents zero or more DBus types in sequence, such as those used in argument lists or in subtypes of structs and maps. @@ -1049,21 +780,18 @@ QDBusType QDBusType::guessFromVariant(const QVariant& variant, VariantListMode m /*! \fn QDBusTypeList::QDBusTypeList(const QDBusTypeList& other) - Copy constructor. - \param other the list to copy - */ + Copy constructor: copies the type list from \a other. +*/ /*! \fn QDBusTypeList::QDBusTypeList(const QList<QDBusType>& other) - Copy constructor. - \param other the list to copy - */ + Copy constructor: copies the type list from \a other. +*/ /*! - Constructs a type list by parsing the signature given. - \param signature the signature to be parsed - */ + Constructs a type list by parsing the given \a signature. +*/ QDBusTypeList::QDBusTypeList(const char* signature) { if (!signature || !*signature) @@ -1085,8 +813,6 @@ QDBusTypeList::QDBusTypeList(const char* signature) /*! \internal Constructs a type list by parsing the elements on this iterator level. - - \param iter the iterator containing the elements on this level */ QDBusTypeList::QDBusTypeList(DBusSignatureIter* iter) { diff --git a/qt/qdbustype.h b/qt/qdbustype_p.h index 094f390..b719960 100644 --- a/qt/qdbustype.h +++ b/qt/qdbustype_p.h @@ -39,13 +39,6 @@ class QDBusTypePrivate; class QDBUS_EXPORT QDBusType { public: - enum StringFormat - { - ConventionalNames, - QtNames, - QVariantNames - }; - QDBusType(); explicit QDBusType(int type); explicit QDBusType(QVariant::Type type); @@ -59,7 +52,7 @@ public: QDBusType& operator=(const QDBusType& other); - QVariant::Type qvariantType() const; + int qvariantType() const; int dbusType() const; QByteArray dbusSignature() const; @@ -77,11 +70,11 @@ public: QDBusType mapValue() const; bool operator==(const QDBusType& other) const; + inline bool operator!=(const QDBusType &other) const + { return !(*this == other); } - QString toString(StringFormat = QtNames) const; - - static QVariant::Type qvariantType(int type); - static QVariant::Type qvariantType(const char* signature); + static int qvariantType(int type); + static int qvariantType(const char* signature); static int dbusType(QVariant::Type); static const char* dbusSignature(QVariant::Type); diff --git a/qt/qdbustypehelper_p.h b/qt/qdbustypehelper_p.h new file mode 100644 index 0000000..bcb0896 --- /dev/null +++ b/qt/qdbustypehelper_p.h @@ -0,0 +1,231 @@ +/* qdbuslisthelper_p.h Helper class to convert to and from QVariantList + * + * Copyright (C) 2005 Harald Fernengel <harry@kdevelop.org> + * Copyright (C) 2006 Trolltech AS. All rights reserved. + * Author: Thiago Macieira <thiago.macieira@trolltech.com> + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the public API. This header file may +// change from version to version without notice, or even be +// removed. +// +// We mean it. +// +// + +#ifndef QDBUSTYPEHELPERPRIVATE_H +#define QDBUSTYPEHELPERPRIVATE_H + +#include <QtCore/qlist.h> +#include <QtCore/qvariant.h> +#include <QtCore/qmetatype.h> + +// we're going to support all D-Bus primitive types here: +// uchar -- not needed: QByteArray +// bool +// short +// ushort +// int +// uint +// qlonglong +// qulonglong +// double +// QString -- not needed: QStringList +// QList -- not possible: will use QVariant +// QVariant +// QDBusStruct -- not yet existant +// QMap -- not possible: will use QVariant + +inline QDBUS_EXPORT int qDBusMetaTypeId(bool *) { return QVariant::Bool; } +inline QDBUS_EXPORT int qDBusMetaTypeId(uchar *) { return QMetaType::UChar; } +inline QDBUS_EXPORT int qDBusMetaTypeId(short *) { return QMetaType::Short; } +inline QDBUS_EXPORT int qDBusMetaTypeId(ushort *) { return QMetaType::UShort; } +inline QDBUS_EXPORT int qDBusMetaTypeId(int *) { return QVariant::Int; } +inline QDBUS_EXPORT int qDBusMetaTypeId(uint *) { return QVariant::UInt; } +inline QDBUS_EXPORT int qDBusMetaTypeId(qlonglong *) { return QVariant::LongLong; } +inline QDBUS_EXPORT int qDBusMetaTypeId(qulonglong *) { return QVariant::ULongLong; } +inline QDBUS_EXPORT int qDBusMetaTypeId(double *) { return QVariant::Double; } +inline QDBUS_EXPORT int qDBusMetaTypeId(QString *) { return QVariant::String; } +QDBUS_EXPORT int qDBusMetaTypeId(QVariant *); +QDBUS_EXPORT int qDBusMetaTypeId(QList<bool> *); +inline QDBUS_EXPORT int qDBusMetaTypeId(QByteArray *) { return QVariant::ByteArray; } +QDBUS_EXPORT int qDBusMetaTypeId(QList<short> *); +QDBUS_EXPORT int qDBusMetaTypeId(QList<ushort> *); +QDBUS_EXPORT int qDBusMetaTypeId(QList<int> *); +QDBUS_EXPORT int qDBusMetaTypeId(QList<uint> *); +QDBUS_EXPORT int qDBusMetaTypeId(QList<qlonglong> *); +QDBUS_EXPORT int qDBusMetaTypeId(QList<qulonglong> *); +QDBUS_EXPORT int qDBusMetaTypeId(QList<double> *); +inline QDBUS_EXPORT int qDBusMetaTypeId(QStringList *) { return QVariant::StringList; } +inline QDBUS_EXPORT int qDBusMetaTypeId(QVariantList *) { return QVariant::List; } +inline QDBUS_EXPORT int qDBusMetaTypeId(QVariantMap *) { return QVariant::Map; } + +// implement the copy mechanism +template<class T> +struct QDBusTypeHelper +{ + typedef T Type; + typedef QList<T> List; + + static inline int id() + { + Type* t = 0; + return qDBusMetaTypeId(t); + } + + static inline int listId() + { + List *l = 0; + return qDBusMetaTypeId(l); + } + + static inline QVariant toVariant(const Type &t) + { + return QVariant(id(), &t); + } + + static bool canSpecialConvert(const QVariant &); + static Type specialConvert(const QVariant &); + + static inline Type fromVariant(const QVariant &v) + { + if (canSpecialConvert(v)) + return specialConvert(v); + + QVariant copy(v); + if (copy.convert( QVariant::Type(id()) )) + return *reinterpret_cast<const Type *>(copy.constData()); + return Type(); + } + + static inline QVariantList toVariantList(const List &list) + { + QVariantList tmp; + foreach (const Type &t, list) + tmp.append(toVariant(t)); + return tmp; + } + + static inline QVariantList toVariantList(const QVariant &v) + { + return toVariantList(QDBusTypeHelper<List>::fromVariant(v)); + } + + static inline List fromVariantList(const QVariantList &list) + { + List tmp; + foreach (const QVariant &v, list) + tmp.append(fromVariant(v)); + return tmp; + } +}; + +template<> +struct QDBusTypeHelper<QVariant> +{ + static inline int id() + { + QVariant *t = 0; + return qDBusMetaTypeId(t); + } + + static inline int listId() + { + return QVariant::List; + } + + static inline QVariant toVariant(const QVariant &t) + { + return QVariant(id(), &t); + } + + static inline QVariant fromVariant(const QVariant &v) + { + if (v.userType() == id()) + return *reinterpret_cast<const QVariant *>(v.constData()); + return v; + } + + static inline QVariantList toVariantList(const QVariantList &list) + { + return list; + } + + static inline QVariantList fromVariantList(const QVariantList &list) + { + return list; + } +}; + +#if !defined(QT_NO_CAST_FROM_ASCII) && !defined(QT_NO_CAST_TO_ASCII) +template<> +struct QDBusTypeHelper<char *> +{ + static inline int id() + { return QVariant::String; } + + static inline QVariant toVariant(const char *t) + { return QVariant(t); } + + static inline QByteArray fromVariant(const QVariant &v) + { return v.toString().toAscii(); } +}; + +template<> +struct QDBusTypeHelper<const char *> +{ + static inline int id() + { return QVariant::String; } + + static inline QVariant toVariant(const char *t) + { return QVariant(t); } + + static inline QByteArray fromVariant(const QVariant &v) + { return v.toString().toAscii(); } +}; +#endif + +// support three exceptions: uchar, short and ushort +// we have to do this as long as QVariant can't convert to/from the integer metatypes +template<> inline bool QDBusTypeHelper<short>::canSpecialConvert(const QVariant &v) +{ return v.userType() < int(QVariant::UserType); } +template<> inline short QDBusTypeHelper<short>::specialConvert(const QVariant &v) +{ return v.toInt(); } + +template<> inline bool QDBusTypeHelper<ushort>::canSpecialConvert(const QVariant &v) +{ return v.userType() < int(QVariant::UserType); } +template<> inline ushort QDBusTypeHelper<ushort>::specialConvert(const QVariant &v) +{ return v.toUInt(); } + +template<> inline bool QDBusTypeHelper<uchar>::canSpecialConvert(const QVariant &v) +{ return v.userType() < int(QVariant::UserType); } +template<> inline uchar QDBusTypeHelper<uchar>::specialConvert(const QVariant &v) +{ return v.toUInt(); } + +template<typename T> inline bool QDBusTypeHelper<T>::canSpecialConvert(const QVariant &) +{ return false; } +template<typename T> inline T QDBusTypeHelper<T>::specialConvert(const QVariant &) +{ return T(); } + +#endif diff --git a/qt/qdbusutil.cpp b/qt/qdbusutil.cpp index d4a8659..872434c 100644 --- a/qt/qdbusutil.cpp +++ b/qt/qdbusutil.cpp @@ -28,17 +28,27 @@ #include <QtCore/qstringlist.h> #include <QtCore/qregexp.h> +#include "qdbustype_p.h" + +/*! + \namespace QDBusUtil + The QDBusUtil namespace contains a few functions that are of general use when dealing with D-Bus + strings. +*/ namespace QDBusUtil { /*! - Returns true if this is \p ifaceName is a valid interface name. + \fn QDBusUtil::isValidInterfaceName(const QString &ifaceName) + Returns true if this is \a ifaceName is a valid interface name. Valid interface names must: - - not be empty - - not exceed 255 characters in length - - be composed of dot-separated string components that contain only ASCII letters, digits and the - underscore ("_") character - - contain at least two such components + \list + \o not be empty + \o not exceed 255 characters in length + \o be composed of dot-separated string components that contain only ASCII letters, digits + and the underscore ("_") character + \o contain at least two such components + \endlist */ bool isValidInterfaceName(const QString& ifaceName) { @@ -57,7 +67,8 @@ namespace QDBusUtil } /*! - Returns true if \p connName is a valid unique connection name. + \fn QDBusUtil::isValidUniqueConnectionName(const QString &connName) + Returns true if \a connName is a valid unique connection name. Unique connection names start with a colon (":") and are followed by a list of dot-separated components composed of ASCII letters, digits, the hypen or the underscore ("_") character. @@ -81,16 +92,19 @@ namespace QDBusUtil } /*! - Returns true if \p busName is a valid bus name. + \fn QDBusUtil::isValidBusName(const QString &busName) + Returns true if \a busName is a valid bus name. A valid bus name is either a valid unique connection name or follows the rules: - - is not empty - - does not exceed 255 characters in length - - be composed of dot-separated string components that contain only ASCII letters, digits, - hyphens or underscores ("_"), but don't start with a digit - - contains at least two such elements - - \see isValidUniqueConnectionName + \list + \o is not empty + \o does not exceed 255 characters in length + \o be composed of dot-separated string components that contain only ASCII letters, digits, + hyphens or underscores ("_"), but don't start with a digit + \o contains at least two such elements + \endlist + + \sa isValidUniqueConnectionName() */ bool isValidBusName(const QString &busName) { @@ -113,7 +127,8 @@ namespace QDBusUtil } /*! - Returns true if \p memberName is a valid member name. A valid member name does not exceed + \fn QDBusUtil::isValidMemberName(const QString &memberName) + Returns true if \a memberName is a valid member name. A valid member name does not exceed 255 characters in length, is not empty, is composed only of ASCII letters, digits and underscores, but does not start with a digit. */ @@ -127,7 +142,8 @@ namespace QDBusUtil } /*! - Returns true if \p errorName is a valid error name. Valid error names are valid interface + \fn QDBusUtil::isValidErrorName(const QString &errorName) + Returns true if \a errorName is a valid error name. Valid error names are valid interface names and vice-versa, so this function is actually an alias for isValidInterfaceName. */ bool isValidErrorName(const QString &errorName) @@ -136,14 +152,17 @@ namespace QDBusUtil } /*! - Returns true if \p path is valid object path. + \fn QDBusUtil::isValidObjectPath(const QString &path) + Returns true if \a path is valid object path. Valid object paths follow the rules: - - start with the slash character ("/") - - do not end in a slash, unless the path is just the initial slash - - do not contain any two slashes in sequence - - contain slash-separated parts, each of which is composed of ASCII letters, digits and - underscores ("_") + \list + \o start with the slash character ("/") + \o do not end in a slash, unless the path is just the initial slash + \o do not contain any two slashes in sequence + \o contain slash-separated parts, each of which is composed of ASCII letters, digits and + underscores ("_") + \endlist */ bool isValidObjectPath(const QString &path) { @@ -167,11 +186,12 @@ namespace QDBusUtil } /*! - Returns true if \p signature is a valid D-Bus type signature for one or more types. - This function returns true if it can all of \p signature into valid, individual types and no - characters remain in \p signature. + \fn QDBusUtil::isValidSignature(const QString &signature) + Returns true if \a signature is a valid D-Bus type signature for one or more types. + This function returns true if it can all of \a signature into valid, individual types and no + characters remain in \a signature. - \see isValidSingleSignature + \sa isValidSingleSignature() */ bool isValidSignature(const QString &signature) { @@ -179,7 +199,8 @@ namespace QDBusUtil } /*! - Returns true if \p signature is a valid D-Bus type signature for exactly one full type. This + \fn QDBusUtil::isValidSingleSignature(const QString &signature) + Returns true if \a signature is a valid D-Bus type signature for exactly one full type. This function tries to convert the type signature into a D-Bus type and, if it succeeds and no characters remain in the signature, it returns true. */ @@ -188,4 +209,27 @@ namespace QDBusUtil return dbus_signature_validate_single(signature.toUtf8(), 0); } + /*! + \fn QDBusUtil::signatureToType(const QString &signature) + Returns the Qt meta type id for the given D-Bus signature for exactly one full type, given + by \a signature. + + \sa isValidSingleSignature(), typeToSignature(), QVariant::type(), QVariant::userType() + */ + QVariant::Type signatureToType(const QString &signature) + { + return QVariant::Type( QDBusType::qvariantType(signature.toLatin1().constData()) ); + } + + /*! + \fn QDBusUtil::typeToSignature(QVariant::Type type) + Returns the D-Bus signature equivalent to the supplied meta type id \a type. + + \sa isValidSingleSignature(), signatureToType(), QVariant::type(), QVariant::userType() + */ + const char *typeToSignature(QVariant::Type type) + { + return QDBusType::dbusSignature( type ); + } + } // namespace QDBusUtil diff --git a/qt/qdbusutil.h b/qt/qdbusutil.h index 4c3bac6..dd2b4df 100644 --- a/qt/qdbusutil.h +++ b/qt/qdbusutil.h @@ -25,26 +25,31 @@ #define QDBUSUTIL_H #include <QtCore/qstring.h> +#include <QtCore/qvariant.h> #include "qdbusmacros.h" namespace QDBusUtil { - bool isValidInterfaceName(const QString &ifaceName) QDBUS_EXPORT; + QDBUS_EXPORT bool isValidInterfaceName(const QString &ifaceName); - bool isValidUniqueConnectionName(const QString &busName) QDBUS_EXPORT; + QDBUS_EXPORT bool isValidUniqueConnectionName(const QString &busName); - bool isValidBusName(const QString &busName) QDBUS_EXPORT; + QDBUS_EXPORT bool isValidBusName(const QString &busName); - bool isValidMemberName(const QString &memberName) QDBUS_EXPORT; + QDBUS_EXPORT bool isValidMemberName(const QString &memberName); - bool isValidErrorName(const QString &errorName) QDBUS_EXPORT; + QDBUS_EXPORT bool isValidErrorName(const QString &errorName); - bool isValidObjectPath(const QString &path) QDBUS_EXPORT; + QDBUS_EXPORT bool isValidObjectPath(const QString &path); - bool isValidSignature(const QString &signature) QDBUS_EXPORT; + QDBUS_EXPORT bool isValidSignature(const QString &signature); - bool isValidSingleSignature(const QString &signature) QDBUS_EXPORT; + QDBUS_EXPORT bool isValidSingleSignature(const QString &signature); + + QDBUS_EXPORT QVariant::Type signatureToType(const QString &signature); + + QDBUS_EXPORT const char *typeToSignature(QVariant::Type type); } #endif diff --git a/qt/qdbusvariant.h b/qt/qdbusvariant.h deleted file mode 100644 index 0a6d41e..0000000 --- a/qt/qdbusvariant.h +++ /dev/null @@ -1,51 +0,0 @@ -/* qdbusvariant.h DBUS variant struct - * - * Copyright (C) 2005 Harald Fernengel <harry@kdevelop.org> - * Copyright (C) 2006 Trolltech AS. All rights reserved. - * Author: Thiago Macieira <thiago.macieira@trolltech.com> - * - * Licensed under the Academic Free License version 2.1 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - */ - -#ifndef QDBUSVARIANT_H -#define QDBUSVARIANT_H - -#include "qdbusmacros.h" -#include "qdbustype.h" -#include <qvariant.h> - -struct QDBUS_EXPORT QDBusVariant -{ - QDBusType type; - QVariant value; - - inline QDBusVariant() - { } - inline QDBusVariant(const QVariant &variant) : value(variant) - { } - inline QDBusVariant(const QVariant &variant, const QDBusType &forcetype) - : type(forcetype), value(variant) - { } - - inline operator const QVariant &() const - { return value; } -}; -Q_DECLARE_METATYPE(QDBusVariant) - -#endif - diff --git a/qt/qdbusxmlparser.cpp b/qt/qdbusxmlparser.cpp index 5586217..0370cb2 100644 --- a/qt/qdbusxmlparser.cpp +++ b/qt/qdbusxmlparser.cpp @@ -26,7 +26,7 @@ #include "qdbusinterface.h" #include "qdbusinterface_p.h" #include "qdbusconnection_p.h" -#include "qdbusobject_p.h" +#include "qdbusutil.h" #include <QtXml/qdom.h> #include <QtCore/qmap.h> @@ -56,14 +56,6 @@ parseAnnotations(const QDomElement& elem) return retval; } -static QDBusType -parseType(const QString& type) -{ - if (type.isEmpty()) - return QDBusType(); - return QDBusType(type); -} - static QDBusIntrospection::Arguments parseArgs(const QDomElement& elem, const QLatin1String& direction, bool acceptEmpty = false) { @@ -81,9 +73,8 @@ parseArgs(const QDomElement& elem, const QLatin1String& direction, bool acceptEm QDBusIntrospection::Argument argData; if (arg.hasAttribute(QLatin1String("name"))) argData.name = arg.attribute(QLatin1String("name")); // can be empty - argData.type = parseType(arg.attribute(QLatin1String("type"))); - - if (!argData.type.isValid()) + argData.type = arg.attribute(QLatin1String("type")); + if (!QDBusUtil::isValidSingleSignature(argData.type)) continue; retval << argData; @@ -93,8 +84,8 @@ parseArgs(const QDomElement& elem, const QLatin1String& direction, bool acceptEm } QDBusXmlParser::QDBusXmlParser(const QString& service, const QString& path, - const QString& xmlData, QDBusConnectionPrivate* store) - : m_service(service), m_path(path), m_store(store) + const QString& xmlData) + : m_service(service), m_path(path) { QDomDocument doc; doc.setContent(xmlData); @@ -102,16 +93,9 @@ QDBusXmlParser::QDBusXmlParser(const QString& service, const QString& path, } QDBusXmlParser::QDBusXmlParser(const QString& service, const QString& path, - const QDomElement& node, QDBusConnectionPrivate* store) - : m_service(service), m_path(path), m_node(node), m_store(store) -{ -} - -void QDBusXmlParser::parse(const QDBusObjectPrivate* d, const QString &xml) + const QDomElement& node) + : m_service(service), m_path(path), m_node(node) { - QDBusXmlParser parser(d->data->service, d->data->path, xml, d->parent); - parser.object(); - parser.interfaces(); } QDBusIntrospection::Interfaces @@ -130,27 +114,8 @@ QDBusXmlParser::interfaces() const if (iface.isNull() || ifaceName.isEmpty()) continue; // for whatever reason - QDBusIntrospection::Interface *ifaceData = 0; // make gcc shut up - if (m_store) { - QSharedDataPointer<QDBusIntrospection::Interface> knownData = - m_store->findInterface(ifaceName); - if (!knownData.constData()->introspection.isEmpty()) { - // it's already known - // we don't have to re-parse - retval.insert(ifaceName, knownData); - continue; - } - - // ugly, but ok - // we don't want to detach - // we *WANT* to modify the shared data - ifaceData = const_cast<QDBusIntrospection::Interface*>( knownData.constData() ); - } - else { - ifaceData = new QDBusIntrospection::Interface; - ifaceData->name = ifaceName; - } - + QDBusIntrospection::Interface *ifaceData = new QDBusIntrospection::Interface; + ifaceData->name = ifaceName; { // save the data QTextStream ts(&ifaceData->introspection); @@ -214,10 +179,10 @@ QDBusXmlParser::interfaces() const // parse data propertyData.name = propertyName; - propertyData.type = parseType(property.attribute(QLatin1String("type"))); + propertyData.type = property.attribute(QLatin1String("type")); propertyData.annotations = parseAnnotations(property); - if (!propertyData.type.isValid()) + if (!QDBusUtil::isValidSingleSignature(propertyData.type)) // cannot be! continue; @@ -251,16 +216,10 @@ QDBusXmlParser::object() const if (m_node.isNull()) return QSharedDataPointer<QDBusIntrospection::Object>(); - // check if the store knows about this one QDBusIntrospection::Object* objData; - if (m_store) { - objData = m_store->findObject(m_service, m_path); - } - else { - objData = new QDBusIntrospection::Object; - objData->service = m_service; - objData->path = m_path; - } + objData = new QDBusIntrospection::Object; + objData->service = m_service; + objData->path = m_path; // check if we have anything to process if (objData->introspection.isNull() && !m_node.firstChild().isNull()) { @@ -337,7 +296,7 @@ QDBusXmlParser::objectTree() const objAbsName.append(QLatin1Char('/')); objAbsName += objName; - QDBusXmlParser parser(m_service, objAbsName, obj, m_store); + QDBusXmlParser parser(m_service, objAbsName, obj); retval->childObjectData.insert(objName, parser.objectTree()); } diff --git a/qt/qdbusxmlparser_p.h b/qt/qdbusxmlparser_p.h index c4c45be..8f4f69b 100644 --- a/qt/qdbusxmlparser_p.h +++ b/qt/qdbusxmlparser_p.h @@ -28,32 +28,26 @@ #include <QtCore/qmap.h> #include <QtXml/qdom.h> #include "qdbusmacros.h" -#include "qdbusintrospection.h" +#include "qdbusintrospection_p.h" -class QDBusConnectionPrivate; -class QDBusObjectPrivate; - -/** - * @internal - */ +/*! + \internal +*/ class QDBusXmlParser { QString m_service; QString m_path; QDomElement m_node; - QDBusConnectionPrivate* m_store; public: QDBusXmlParser(const QString& service, const QString& path, - const QString& xmlData, QDBusConnectionPrivate* store = 0); + const QString& xmlData); QDBusXmlParser(const QString& service, const QString& path, - const QDomElement& node, QDBusConnectionPrivate* store = 0); + const QDomElement& node); QDBusIntrospection::Interfaces interfaces() const; QSharedDataPointer<QDBusIntrospection::Object> object() const; QSharedDataPointer<QDBusIntrospection::ObjectTree> objectTree() const; - - static void parse(const QDBusObjectPrivate* d, const QString &xml); }; #endif diff --git a/qt/qt-dbus.qdocconf b/qt/qt-dbus.qdocconf new file mode 100644 index 0000000..5c5ef6c --- /dev/null +++ b/qt/qt-dbus.qdocconf @@ -0,0 +1,132 @@ +project = QtDBus +description = QtDBus Reference Documentation +url = http://developer.kde.org/~thiago/QtDBus +indexes = $QTDIR/doc/html/qt.index + +outputdir = ../doc/api/html + +language = Cpp +headerdirs = . +sourcedirs = . doc +imagedirs = doc +extraimages.HTML = qt-logo \ + trolltech-logo +sources.fileextensions = "*.cpp *.qdoc" +defines = Q_QDOC \ + QT_.*_SUPPORT \ + QT_.*_LIB \ + QT_COMPAT \ + QT3_SUPPORT \ + Q_WS_.* \ + Q_OS_.* \ + Q_BYTE_ORDER \ + __cplusplus + +macro.key = "\\bold" +macro.menu = "\\bold" +macro.gui = "\\bold" +macro.reg.HTML = "<sup>®</sup>" +macro.raisedaster.HTML = "<sup>*</sup>" +macro.BR.HTML = "<br />" +macro.QD = "\\e{Qt Designer}" +macro.QA = "\\e{Qt Assistant}" +macro.aring.HTML = "å" +macro.Auml.HTML = "Ä" +macro.var = "\\variable" + +Cpp.ignoretokens = QAXFACTORY_EXPORT \ + QDESIGNER_COMPONENTS_LIBRARY \ + QDESIGNER_EXTENSION_LIBRARY \ + QDESIGNER_SDK_LIBRARY \ + QDESIGNER_SHARED_LIBRARY \ + QDESIGNER_UILIB_LIBRARY \ + QM_EXPORT_CANVAS \ + QM_EXPORT_DNS \ + QM_EXPORT_DOM \ + QM_EXPORT_FTP \ + QM_EXPORT_HTTP \ + QM_EXPORT_ICONVIEW \ + QM_EXPORT_NETWORK \ + QM_EXPORT_OPENGL \ + QM_EXPORT_SQL \ + QM_EXPORT_TABLE \ + QM_EXPORT_WORKSPACE \ + QM_EXPORT_XML \ + QT_DESIGNER_STATIC \ + QT_WIDGET_PLUGIN_EXPORT \ + Q_COMPAT_EXPORT \ + Q_CORE_EXPORT \ + Q_EXPLICIT \ + Q_EXPORT \ + Q_EXPORT_CODECS_CN \ + Q_EXPORT_CODECS_JP \ + Q_EXPORT_CODECS_KR \ + Q_EXPORT_PLUGIN \ + Q_GFX_INLINE \ + Q_GUI_EXPORT \ + Q_GUI_EXPORT_STYLE_CDE \ + Q_GUI_EXPORT_STYLE_COMPACT \ + Q_GUI_EXPORT_STYLE_MAC \ + Q_GUI_EXPORT_STYLE_MOTIF \ + Q_GUI_EXPORT_STYLE_MOTIFPLUS \ + Q_GUI_EXPORT_STYLE_PLATINUM \ + Q_GUI_EXPORT_STYLE_POCKETPC \ + Q_GUI_EXPORT_STYLE_SGI \ + Q_GUI_EXPORT_STYLE_WINDOWS \ + Q_GUI_EXPORT_STYLE_WINDOWSXP \ + Q_INLINE_TEMPLATE \ + Q_NETWORK_EXPORT \ + Q_OPENGL_EXPORT \ + Q_OUTOFLINE_TEMPLATE \ + Q_SQL_EXPORT \ + Q_SVG_EXPORT \ + Q_TESTLIB_EXPORT \ + Q_TYPENAME \ + Q_XML_EXPORT \ + QDBUS_EXPORT \ + Q_ASYNC +Cpp.ignoredirectives = Q_DECLARE_HANDLE \ + Q_DECLARE_INTERFACE \ + Q_DECLARE_METATYPE \ + Q_DECLARE_OPERATORS_FOR_FLAGS \ + Q_DECLARE_PRIVATE \ + Q_DECLARE_PUBLIC \ + Q_DECLARE_SHARED \ + Q_DECLARE_TR_FUNCTIONS \ + Q_DECLARE_TYPEINFO \ + Q_DISABLE_COPY \ + Q_DUMMY_COMPARISON_OPERATOR \ + Q_ENUMS \ + Q_FLAGS \ + Q_INTERFACES \ + __attribute__ +HTML.style = "h3.fn,span.fn { margin-left: 1cm; text-indent: -1cm; }\n" \ + "a:link { color: #004faf; text-decoration: none }\n" \ + "a:visited { color: #672967; text-decoration: none }\n" \ + "td.postheader { font-family: sans-serif }\n" \ + "tr.address { font-family: sans-serif }\n" \ + "body { background: #ffffff; color: black; }\n" \ + "pre { background: #dddddd; }" + +HTML.postheader = "<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" width=\"100%\">\n" \ + "<tr>\n" \ + "<td align=\"left\" valign=\"top\" width=\"32\">" \ + "<img src=\"images/qt-logo.png\" align=\"left\" width=\"32\" height=\"32\" border=\"0\" />" \ + "</td>\n" \ + "<td width=\"1\"> </td>" \ + "<td class=\"postheader\" valign=\"center\">" \ + "<a href=\"index.html\">" \ + "<font color=\"#004faf\">Home</font></a> ·" \ + " <a href=\"classes.html\">" \ + "<font color=\"#004faf\">Classes</font></a> ·" \ + " <a href=\"namespaces.html\">" \ + "<font color=\"#004faf\">Namespaces</font></a>" \ + "</td>\n" \ + "<td align=\"right\" valign=\"top\" width=\"230\"><img src=\"images/trolltech-logo.png\" align=\"right\" width=\"203\" height=\"32\" border=\"0\" /></td></tr></table>" + +HTML.footer = "<p /><address><hr /><div align=\"center\">\n" \ + "<table width=\"100%\" cellspacing=\"0\" border=\"0\"><tr class=\"address\">\n" \ + "<td width=\"30%\">Copyright © 2006 <a href=\"trolltech.html\">Trolltech</a></td>\n" \ + "<td width=\"40%\" align=\"center\"> </td>\n" \ + "<td width=\"30%\" align=\"right\"><div align=\"right\">QtDBus \\version</div></td>\n" \ + "</tr></table></div></address>" |