* qt/*: Update the QtDBus bindings up to revision 546310 in
authorThiago Macieira <thiago@kde.org>
Mon, 29 May 2006 18:17:09 +0000 (18:17 +0000)
committerThiago Macieira <thiago@kde.org>
Mon, 29 May 2006 18:17:09 +0000 (18:17 +0000)
        Subversion.
        This adds the dbuscpp2xml tool, that parses a C++ header and
        outputs a D-BUS Introspection XML.

17 files changed:
ChangeLog
qt/Makefile.am
qt/dbuscpp2xml.cpp [new file with mode: 0644]
qt/dbusidl2cpp.cpp
qt/qdbusabstractadaptor.cpp
qt/qdbusabstractinterface.cpp
qt/qdbusabstractinterface.h
qt/qdbusconnection.cpp
qt/qdbusconnection_p.h
qt/qdbusintegrator.cpp
qt/qdbusinterface.cpp
qt/qdbusinterface.h
qt/qdbusinternalfilters.cpp
qt/qdbusmacros.h
qt/qdbusmetaobject.cpp
qt/qdbusmisc.cpp [new file with mode: 0644]
qt/qdbusxmlgenerator.cpp [new file with mode: 0644]

index 8341441..d49cdc8 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2006-05-29  Thiago Macieira  <thiago.macieira@trolltech.com>
+
+       * qt/*: Update the QtDBus bindings up to revision 546310 in
+        Subversion.
+       This adds the dbuscpp2xml tool, that parses a C++ header and
+        outputs a D-BUS Introspection XML.
+
 2006-05-21  Havoc Pennington  <hp@redhat.com>
 
        * glib/dbus-gproxy.c: Put in a pile of assertions that the proxy name
index 38cf1d7..c91c342 100644 (file)
@@ -41,20 +41,25 @@ libdbus_qt4_1_la_SOURCES =      \
         qdbusmessage.cpp        \
         qdbusserver.cpp         \
         qdbustype.cpp           \
-        qdbusabstractinterface.cpp \
+        qdbusabstractinterface.cpp     \
         qdbusinterface.cpp      \
         qdbusxmlparser.cpp      \
         qdbusutil.cpp           \
         qdbusintrospection.cpp  \
-        qdbusabstractadaptor.cpp \
+        qdbusabstractadaptor.cpp       \
         qdbusthread.cpp         \
-        qdbusinternalfilters.cpp \
-        qdbusmetaobject.cpp
+        qdbusinternalfilters.cpp       \
+        qdbusmetaobject.cpp    \
+       qdbusmisc.cpp           \
+       qdbusxmlgenerator.cpp
 
-bin_PROGRAMS = dbusidl2cpp
+bin_PROGRAMS = dbusidl2cpp dbuscpp2xml
 dbusidl2cpp_SOURCES = dbusidl2cpp.cpp
 dbusidl2cpp_LDFLAGS = -no-undefined 
 dbusidl2cpp_LDADD = $(DBUS_QT_LIBS) libdbus-qt4-1.la
+dbuscpp2xml_SOURCES = dbuscpp2xml.cpp
+dbuscpp2xml_LDFLAGS = -no-undefined 
+dbuscpp2xml_LDADD = $(DBUS_QT_LIBS) libdbus-qt4-1.la
 
 qdbusabstractadaptor.lo: qdbusabstractadaptor.moc qdbusabstractadaptor_p.moc
 qdbusabstractinterface.lo: qdbusabstractinterface.moc
@@ -66,6 +71,7 @@ CLEANFILES=qdbusabstractadaptor.moc qdbusserver.moc qdbusconnection_p.moc qdbusc
 
 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
+libdbus_qt4_1_la_CPPFLAGS= -DQDBUS_MAKEDLL
 
 EXTRA_DIST = qt-dbus.qdocconf
 
diff --git a/qt/dbuscpp2xml.cpp b/qt/dbuscpp2xml.cpp
new file mode 100644 (file)
index 0000000..e111f11
--- /dev/null
@@ -0,0 +1,404 @@
+/* -*- 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.
+ *
+ */
+
+#include <QByteArray>
+#include <QString>
+#include <QVarLengthArray>
+#include <QFile>
+#include <QProcess>
+#include <QMetaObject>
+#include <QList>
+#include <QRegExp>
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include "qdbusconnection.h"    // for the Export* flags
+#include <dbus/dbus.h>          // for the XML DOCTYPE declaration
+
+// in qdbusxmlgenerator.cpp
+extern QDBUS_EXPORT QString qDBusGenerateMetaObjectXml(QString interface, const QMetaObject *mo,
+                                                       const QMetaObject *base, int flags);
+
+#define PROGRAMNAME     "dbuscpp2xml"
+#define PROGRAMVERSION  "0.1"
+#define PROGRAMCOPYRIGHT "Copyright (C) 2006 Trolltech AS. All rights reserved."
+
+static const char cmdlineOptions[] = "psmaPSMAo:";
+static const char *outputFile;
+static int flags;
+
+static const char help[] =
+    "Usage: " PROGRAMNAME " [options...] [files...]\n"
+    "Parses the C++ source or header file containing a QObject-derived class and\n"
+    "produces the D-Bus Introspection XML."
+    "\n"
+    "Options:\n"
+    "  -p|-s|-m       Only parse scriptable Properties, Signals and Methods (slots)\n"
+    "  -P|-S|-M       Parse all Properties, Signals and Methods (slots)\n"
+    "  -a             Output all scriptable contents (equivalent to -psm)\n"
+    "  -A             Output all contents (equivalent to -PSM)\n"
+    "  -o <filename>  Write the output to file <filename>\n"
+    "  -h             Show this information\n"
+    "  -V             Show the program version and quit.\n"
+    "\n";
+
+class MocParser
+{
+    void parseError();
+    QByteArray readLine();
+    void loadIntData(uint *&data);
+    void loadStringData(char *&stringdata);
+
+    QIODevice *input;
+    const char *filename;
+    int line;
+public:
+    ~MocParser();
+    void parse(const char *filename, QIODevice *input, int lineNumber = 0);
+
+    QList<QMetaObject> objects;
+};
+    
+void MocParser::parseError()
+{
+    fprintf(stderr, PROGRAMNAME ": error parsing input file '%s' line %d \n", filename, line);
+    exit(1);
+}
+
+QByteArray MocParser::readLine()
+{
+    ++line;
+    return input->readLine();
+}
+
+void MocParser::loadIntData(uint *&data)
+{
+    data = 0;                   // initialise
+    QVarLengthArray<uint> array;
+    QRegExp rx("(\\d+|0x[0-9abcdef]+)", Qt::CaseInsensitive);
+
+    while (!input->atEnd()) {
+        QString line = QLatin1String(readLine());
+        int pos = line.indexOf("//");
+        if (pos != -1)
+            line.truncate(pos); // drop comments
+
+        if (line == "};\n") {
+            // end of data
+            data = new uint[array.count()];
+            memcpy(data, array.data(), array.count() * sizeof(*data));
+            return;
+        }
+
+        pos = 0;
+        while ((pos = rx.indexIn(line, pos)) != -1) {
+            QString num = rx.cap(1);
+            if (num.startsWith("0x"))
+                array.append(num.mid(2).toUInt(0, 16));
+            else
+                array.append(num.toUInt());
+            pos += rx.matchedLength();
+        }
+    }
+
+    parseError();
+}
+
+void MocParser::loadStringData(char *&stringdata)
+{
+    stringdata = 0;
+    QVarLengthArray<char, 1024> array;
+
+    while (!input->atEnd()) {
+        QByteArray line = readLine();
+        if (line == "};\n") {
+            // end of data
+            stringdata = new char[array.count()];
+            memcpy(stringdata, array.data(), array.count() * sizeof(*stringdata));
+            return;
+        }
+
+        int start = line.indexOf('"');
+        if (start == -1)
+            parseError();
+
+        int len = line.length() - 1;
+        line.truncate(len);     // drop ending \n
+        if (line.at(len - 1) != '"')
+            parseError();
+
+        --len;
+        ++start;
+        for ( ; start < len; ++start)
+            if (line.at(start) == '\\') {
+                // parse escaped sequence
+                ++start;
+                if (start == len)
+                    parseError();
+
+                QChar c(QLatin1Char(line.at(start)));
+                if (!c.isDigit()) {
+                    switch (c.toLatin1()) {
+                    case 'a':
+                        array.append('\a');
+                        break;
+                    case 'b':
+                        array.append('\b');
+                        break;
+                    case 'f':
+                        array.append('\f');
+                        break;
+                    case 'n':
+                        array.append('\n');
+                        break;
+                    case 'r':
+                        array.append('\r');
+                        break;
+                    case 't':
+                        array.append('\t');
+                        break;
+                    case 'v':
+                        array.append('\v');
+                        break;
+                    case '\\':
+                    case '?':
+                    case '\'':
+                    case '"':
+                        array.append(c.toLatin1());
+                        break;
+
+                    case 'x':
+                        if (start + 2 <= len)
+                            parseError();
+                        array.append(char(line.mid(start + 1, 2).toInt(0, 16)));
+                        break;
+                        
+                    default:
+                        array.append(c.toLatin1());
+                        fprintf(stderr, PROGRAMNAME ": warning: invalid escape sequence '\\%c' found in input",
+                                c.toLatin1());
+                    }
+                } else {
+                    // octal
+                    QRegExp octal("([0-7]+)");
+                    if (octal.indexIn(QLatin1String(line), start) == -1)
+                        parseError();
+                    array.append(char(octal.cap(1).toInt(0, 8)));
+                }
+            } else {
+                array.append(line.at(start));
+            }
+    }
+
+    parseError();
+}                    
+
+void MocParser::parse(const char *fname, QIODevice *io, int lineNumber)
+{
+    filename = fname;
+    input = io;
+    line = lineNumber;
+
+    while (!input->atEnd()) {
+        QByteArray line = readLine();
+        if (line.startsWith("static const uint qt_meta_data_")) {
+            // start of new class data
+            uint *data;
+            loadIntData(data);
+
+            // find the start of the string data
+            do {
+                line = readLine();
+                if (input->atEnd())
+                    parseError();
+            } while (!line.startsWith("static const char qt_meta_stringdata_"));
+
+            char *stringdata;
+            loadStringData(stringdata);
+
+            QMetaObject mo;
+            mo.d.superdata = &QObject::staticMetaObject;
+            mo.d.stringdata = stringdata;
+            mo.d.data = data;
+            mo.d.extradata = 0;
+            objects.append(mo);
+        }
+    }
+
+    fname = 0;
+    input = 0;
+}
+
+MocParser::~MocParser()
+{
+    foreach (QMetaObject mo, objects) {
+        delete const_cast<char *>(mo.d.stringdata);
+        delete const_cast<uint *>(mo.d.data);
+    }
+}
+
+static void showHelp()
+{
+    printf("%s", help);
+    exit(0);
+}
+
+static void showVersion()
+{
+    printf("%s version %s\n", PROGRAMNAME, PROGRAMVERSION);
+    printf("D-Bus QObject-to-XML converter\n");
+    exit(0);
+}
+
+static void parseCmdLine(int argc, char **argv)
+{
+    int c;
+    opterr = true;
+    while ((c = getopt(argc, argv, cmdlineOptions)) != -1)
+        switch (c)
+        {
+        case 'p':
+            flags |= QDBusConnection::ExportProperties;
+            break;
+
+        case 's':
+            flags |= QDBusConnection::ExportSignals;
+            break;
+
+        case 'm':
+            flags |= QDBusConnection::ExportSlots;
+            break;
+
+        case 'a':
+            flags |= QDBusConnection::ExportContents;
+            break;
+
+        case 'P':
+            flags |= QDBusConnection::ExportAllProperties;
+            break;
+
+        case 'S':
+            flags |= QDBusConnection::ExportAllSignals;
+            break;
+
+        case 'M':
+            flags |= QDBusConnection::ExportAllSlots;
+            break;
+
+        case 'A':
+            flags |= QDBusConnection::ExportAllContents;
+            break;
+
+        case 'o':
+            outputFile = optarg;
+            break;
+
+        case 'h':
+            showHelp();
+            break;
+
+        case 'V':
+            showVersion();
+            break;
+
+        case '?':
+            exit(1);
+        default:
+            abort();
+        }
+
+    if (flags == 0)
+        flags = QDBusConnection::ExportAllContents;
+}
+
+int main(int argc, char **argv)
+{
+    MocParser parser;
+    parseCmdLine(argc, argv);
+
+    for (int i = 1; i < argc; ++i) {
+        FILE *in = fopen(argv[i], "r");
+        if (in == 0) {
+            fprintf(stderr, PROGRAMNAME ": could not open '%s': %s\n",
+                    argv[i], strerror(errno));
+            return 1;
+        }
+
+        QFile f;
+        f.open(in, QIODevice::ReadOnly);
+        f.readLine();
+
+        QByteArray line = f.readLine();
+        if (line.contains("Meta object code from reading C++ file"))
+            // this is a moc-generated file
+            parser.parse(argv[i], &f, 3);
+        else {
+            // run moc on this file
+            QProcess proc;
+            proc.start("moc", QStringList() << QFile::encodeName(argv[i]));
+            
+            if (!proc.waitForStarted()) {
+                fprintf(stderr, PROGRAMNAME ": could not execute moc! Aborting.\n");
+                return 1;
+            }
+
+            proc.closeWriteChannel();
+
+            if (!proc.waitForFinished() || proc.exitStatus() != QProcess::NormalExit ||
+                proc.exitCode() != 0) {
+                // output the moc errors:
+                fprintf(stderr, "%s", proc.readAllStandardError().constData());
+                fprintf(stderr, PROGRAMNAME ": exit code %d from moc. Aborting\n", proc.exitCode());
+                return 1;
+            }
+            fprintf(stderr, "%s", proc.readAllStandardError().constData());
+
+            parser.parse(argv[i], &proc, 1);
+        }
+
+        f.close();
+        fclose(in);
+    }
+
+    FILE *output = stdout;
+    if (outputFile != 0) {
+        output = fopen(outputFile, "w");
+        if (output == 0) {
+            fprintf(stderr, PROGRAMNAME ": could not open output file '%s': %s",
+                    outputFile, strerror(errno));
+            return 1;
+        }
+    }
+
+    fprintf(output, "%s<node>\n", DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE);
+    foreach (QMetaObject mo, parser.objects) {
+        QString xml = qDBusGenerateMetaObjectXml(QString(), &mo, &QObject::staticMetaObject,
+                                                 flags);
+        fprintf(output, "%s", qPrintable(xml));
+    }
+    fprintf(output, "</node>\n");
+
+    if (output != stdout)
+        fclose(output);
+}
+
index 8097a07..d329c18 100644 (file)
@@ -375,7 +375,7 @@ static QString stringify(const QString &data)
                 retval += "\\\"";
             else
                 retval += data[i];
-        retval += "\"\n";
+        retval += "\\n\"\n";
     }
     return retval;
 }
index 2794293..b7c4188 100644 (file)
@@ -242,12 +242,11 @@ void QDBusAdaptorConnector::polish()
         return;                 // avoid working multiple times if multiple adaptors were added
 
     waitingForPolish = false;
-    const QObjectList &objs = children();
+    const QObjectList &objs = parent()->children();
     foreach (QObject *obj, objs) {
-        Q_ASSERT(qobject_cast<QDBusAbstractAdaptor *>(obj));
-
-        QDBusAbstractAdaptor *adaptor = static_cast<QDBusAbstractAdaptor *>(obj);
-        addAdaptor(adaptor);
+        QDBusAbstractAdaptor *adaptor = qobject_cast<QDBusAbstractAdaptor *>(obj);
+        if (adaptor)
+            addAdaptor(adaptor);
     }
 
     // sort the adaptor list
index 7c09b51..2a6bcf0 100644 (file)
@@ -131,6 +131,19 @@ QDBusAbstractInterface::~QDBusAbstractInterface()
 }
 
 /*!
+    Returns true if this is a valid reference to a remote object. It returns false if
+    there was an error during the creation of this interface (for instance, if the remote
+    application does not exist).
+
+    Note: when dealing with remote objects, it is not always possible to determine if it
+    exists when creating a QDBusInterface or QDBusInterfacePtr object.
+*/
+bool QDBusAbstractInterface::isValid() const
+{
+    return d_func()->isValid;
+}
+
+/*!
     Returns the connection this interface is assocated with.
 */
 QDBusConnection QDBusAbstractInterface::connection() const
index 1ad1a53..aa6d00d 100644 (file)
@@ -51,6 +51,7 @@ public:
 
 public:
     virtual ~QDBusAbstractInterface();
+    bool isValid() const;
 
     QDBusConnection connection() const;
 
index 52875a0..7bbde9a 100644 (file)
@@ -85,6 +85,7 @@ void QDBusConnectionManager::bindToApplication()
     }
 }
 
+QDBUS_EXPORT void qDBusBindToApplication();
 void qDBusBindToApplication()
 {
     manager()->bindToApplication();
@@ -351,12 +352,6 @@ void QDBusConnection::closeConnection(const QString &name)
     manager()->removeConnection(name);
 }
 
-void QDBusConnectionPrivate::timerEvent(QTimerEvent *e)
-{
-    DBusTimeout *timeout = timeouts.value(e->timerId(), 0);
-    dbus_timeout_handle(timeout);
-}
-
 /*!
     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.
@@ -367,7 +362,7 @@ bool QDBusConnection::send(const QDBusMessage &message) const
 {
     if (!d || !d->connection)
         return false;
-    return d->send(message);
+    return d->send(message) != 0;
 }
 
 /*!
@@ -445,25 +440,21 @@ bool QDBusConnection::connect(const QString &service, const QString &path, const
         if (source.isEmpty())
             return false;
     }
-    source += path;
 
     // check the slot
     QDBusConnectionPrivate::SignalHook hook;
-    if ((hook.midx = QDBusConnectionPrivate::findSlot(receiver, slot + 1, hook.params)) == -1)
-        return false;
-
-    hook.interface = interface;
-    hook.name = name;
+    QString key;
     hook.signature = signature;
-    hook.obj = receiver;
+    if (!d->prepareHook(hook, key, source, path, interface, name, receiver, slot, 0, false))
+        return false;           // don't connect
 
     // avoid duplicating:
     QWriteLocker locker(&d->lock);
-    QDBusConnectionPrivate::SignalHookHash::ConstIterator it = d->signalHooks.find(source);
-    for ( ; it != d->signalHooks.end() && it.key() == source; ++it) {
+    QDBusConnectionPrivate::SignalHookHash::ConstIterator it = d->signalHooks.find(key);
+    for ( ; it != d->signalHooks.end() && it.key() == key; ++it) {
         const QDBusConnectionPrivate::SignalHook &entry = it.value();
-        if (entry.interface == hook.interface &&
-            entry.name == hook.name &&
+        if (entry.sender == hook.sender &&
+            entry.path == hook.path &&
             entry.signature == hook.signature &&
             entry.obj == hook.obj &&
             entry.midx == hook.midx) {
@@ -473,7 +464,7 @@ bool QDBusConnection::connect(const QString &service, const QString &path, const
     }
 
 
-    d->connectSignal(source, hook);
+    d->connectSignal(key, hook);
     return true;
 }
 
index af57208..a903449 100644 (file)
@@ -85,7 +85,7 @@ public:
     struct SignalHook
     {
         inline SignalHook() : obj(0), midx(-1) { }
-        QString interface, name, signature;
+        QString sender, path, signature;
         QObject* obj;
         int midx;
         QList<int> params;
@@ -139,7 +139,7 @@ public:
 
     QString getNameOwner(const QString &service);    
 
-    bool send(const QDBusMessage &message) const;
+    int send(const QDBusMessage &message) const;
     QDBusMessage sendWithReply(const QDBusMessage &message, int mode);
     int sendWithReplyAsync(const QDBusMessage &message, QObject *receiver,
                            const char *method);
@@ -150,7 +150,7 @@ public:
     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 QString &key, const QDBusMessage &msg);
     bool handleSignal(const QDBusMessage &msg);
     bool handleObjectCall(const QDBusMessage &message);
     bool handleError();
@@ -176,6 +176,7 @@ private:
 
 public slots:
     // public slots
+    void doDispatch();
     void socketRead(int);
     void socketWrite(int);
     void objectDestroyed(QObject *o);
@@ -210,7 +211,12 @@ public:
     // static methods
     static int messageMetaType;
     static int registerMessageMetaType();
-    static int findSlot(QObject *obj, const char *slotName, QList<int>& params);
+    static int findSlot(QObject *obj, const QByteArray &normalizedName, QList<int>& params);
+    static bool prepareHook(QDBusConnectionPrivate::SignalHook &hook, QString &key,
+                            const QString &service, const QString &path,
+                            const QString &interface, const QString &name,
+                            QObject *receiver, const char *signal, int minMIdx,
+                            bool buildSignature);
     static DBusHandlerResult messageFilter(DBusConnection *, DBusMessage *, void *);
     static void messageResultReceived(DBusPendingCall *, void *);
 };
@@ -225,6 +231,7 @@ public slots:
     void reply(const QDBusMessage &msg);
 };
 
+// in qdbusmisc.cpp
 extern int qDBusParametersForMethod(const QMetaMethod &mm, QList<int>& metaTypes);
 extern int qDBusNameToTypeId(const char *name);
 extern bool qDBusCheckAsyncTag(const char *tag);
index dc038ab..190c468 100644 (file)
@@ -46,6 +46,9 @@
 
 int QDBusConnectionPrivate::messageMetaType = 0;
 
+typedef void (*qDBusSpyHook)(const QDBusMessage&);
+static qDBusSpyHook messageSpyHook;
+
 struct QDBusPendingCall
 {
     QPointer<QObject> receiver;
@@ -217,6 +220,12 @@ static void qDBusNewConnection(DBusServer *server, DBusConnection *c, void *data
     qDebug("SERVER: GOT A NEW CONNECTION"); // TODO
 }
 
+extern QDBUS_EXPORT void qDBusSetSpyHook(qDBusSpyHook);
+void qDBusSetSpyHook(qDBusSpyHook hook)
+{
+    messageSpyHook = hook;
+}
+
 #if USE_OUTSIDE_DISPATCH
 # define HANDLED     DBUS_HANDLER_RESULT_HANDLED_OUTSIDE_DISPATCH
 static DBusHandlerResult qDBusSignalFilterOutside(DBusConnection *connection,
@@ -262,6 +271,11 @@ DBusHandlerResult QDBusConnectionPrivate::messageFilter(DBusConnection *connecti
     QDBusMessage amsg = QDBusMessage::fromDBusMessage(message, QDBusConnection(d->name));
     qDebug() << "got message:" << amsg;
 
+    if (messageSpyHook) {
+        qDebug() << "calling the message spy hook";
+        (*messageSpyHook)(amsg);
+    }
+
     bool handled = false;
     int msgType = dbus_message_get_type(message);
     if (msgType == DBUS_MESSAGE_TYPE_SIGNAL) {
@@ -304,26 +318,6 @@ static void huntAndEmit(DBusConnection *connection, DBusMessage *msg,
     }
 }
 
-bool qDBusCheckAsyncTag(const char *tag)
-{
-    if (!tag || !*tag)
-        return false;
-
-    const char *p = strstr(tag, "async");
-    if (p != NULL &&
-        (p == tag || *(p-1) == ' ') &&
-        (p[5] == '\0' || p[5] == ' '))
-        return true;
-
-    p = strstr(tag, "Q_ASYNC");
-    if (p != NULL &&
-        (p == tag || *(p-1) == ' ') &&
-        (p[7] == '\0' || p[7] == ' '))
-        return true;
-
-    return false;
-}
-
 static bool typesMatch(int metaId, int variantType)
 {
     if (metaId == int(variantType))
@@ -351,112 +345,6 @@ static bool typesMatch(int metaId, int variantType)
     return false;               // no match
 }
 
-int qDBusNameToTypeId(const char *name)
-{
-    int id = static_cast<int>( QVariant::nameToType(name) );
-    if (id == QVariant::UserType)
-        id = QMetaType::type(name);
-
-    switch (id) {
-    case QVariant::Bool:
-    case QVariant::Int:
-    case QVariant::UInt:
-    case QVariant::Char:
-    case QMetaType::Short:
-    case QMetaType::UShort:
-    case QMetaType::UChar:
-    case QVariant::LongLong:
-    case QVariant::ULongLong:
-    case QVariant::Double:
-    case QVariant::String:
-    case QVariant::Date:
-    case QVariant::Time:
-    case QVariant::DateTime:
-    case QVariant::Map:
-    case QVariant::StringList:
-    case QVariant::ByteArray:
-    case QVariant::List:
-        return id;
-
-    default:
-        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
-    }
-}
-
-// calculates the metatypes for the method
-// the slot must have the parameters in the following form:
-//  - zero or more value or const-ref parameters of any kind
-//  - zero or one const ref of QDBusMessage
-//  - zero or more non-const ref parameters
-// No parameter may be a template.
-// this function returns -1 if the parameters don't match the above form
-// this function returns the number of *input* parameters, including the QDBusMessage one if any
-// this function does not check the return type, so metaTypes[0] is always 0 and always present
-// metaTypes.count() >= retval + 1 in all cases
-//
-// sig must be the normalised signature for the method
-int qDBusParametersForMethod(const QMetaMethod &mm, QList<int>& metaTypes)
-{
-    QList<QByteArray> parameterTypes = mm.parameterTypes();
-    metaTypes.clear();
-
-    metaTypes.append(0);        // return type
-    int inputCount = 0;
-    bool seenMessage = false;
-    foreach (QByteArray type, parameterTypes) {
-        if (type.endsWith('*')) {
-            qWarning("Could not parse the method '%s'", mm.signature());
-            // pointer?
-            return -1;
-        }
-
-        if (type.endsWith('&')) {
-            type.truncate(type.length() - 1);
-            int id = qDBusNameToTypeId(type);
-            if (id == 0) {
-                qWarning("Could not parse the method '%s'", mm.signature());
-                // invalid type in method parameter list
-                return -1;
-            }
-
-            metaTypes.append( id );
-            seenMessage = true; // it cannot appear anymore anyways
-            continue;
-        }
-
-        if (seenMessage) {      // && !type.endsWith('&')
-            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'", mm.signature());
-            // invalid type in method parameter list
-            return -1;
-        }
-        metaTypes.append(id);
-        ++inputCount;
-
-        if (id == QDBusConnectionPrivate::messageMetaType)
-            seenMessage = true;
-    }
-
-    return inputCount;
-}
-
 static int findSlot(const QMetaObject *mo, const QByteArray &name, int flags,
                     const QDBusTypeList &types, QList<int>& metaTypes)
 {
@@ -681,7 +569,7 @@ void QDBusConnectionPrivate::deliverCall(const CallDeliveryEvent& data) const
     QVarLengthArray<void *, 10> params;
     params.reserve(metaTypes.count());
 
-    QVarLengthArray<QVariant, 4> auxParameters;
+    QVariantList auxParameters;
     // let's create the parameter list
 
     // first one is the return type -- add it below
@@ -879,6 +767,10 @@ bool QDBusConnectionPrivate::handleError()
 void QDBusConnectionPrivate::bindToApplication()
 {
     // Yay, now that we have an application we are in business
+    Q_ASSERT_X(QCoreApplication::instance(), "QDBusConnection",
+               "qDBusBindToApplication called without an application");
+    moveToThread(QCoreApplication::instance()->thread());
+    
     // Re-add all watchers
     WatcherHash oldWatchers = watchers;
     watchers.clear();
@@ -887,6 +779,8 @@ void QDBusConnectionPrivate::bindToApplication()
         it.next();
         if (!it.value().read && !it.value().write) {
             qDBusAddWatch(it.value().watch, this);
+        } else {
+            watchers.insertMulti(it.key(), it.value());
         }
     }
 
@@ -895,6 +789,18 @@ void QDBusConnectionPrivate::bindToApplication()
        qDBusAddTimeout(pendingTimeouts.takeFirst(), this);
 }
 
+void QDBusConnectionPrivate::timerEvent(QTimerEvent *e)
+{
+    DBusTimeout *timeout = timeouts.value(e->timerId(), 0);
+    dbus_timeout_handle(timeout);
+}
+
+void QDBusConnectionPrivate::doDispatch()
+{
+    if (mode == ClientMode)
+        while (dbus_connection_dispatch(connection) == DBUS_DISPATCH_DATA_REMAINS);
+}
+
 void QDBusConnectionPrivate::socketRead(int fd)
 {
     QHashIterator<int, QDBusConnectionPrivate::Watcher> it(watchers);
@@ -905,8 +811,8 @@ void QDBusConnectionPrivate::socketRead(int fd)
                 qDebug("OUT OF MEM");
         }
     }
-    if (mode == ClientMode)
-        while (dbus_connection_dispatch(connection) == DBUS_DISPATCH_DATA_REMAINS);
+
+    doDispatch();
 }
 
 void QDBusConnectionPrivate::socketWrite(int fd)
@@ -963,13 +869,12 @@ int QDBusConnectionPrivate::registerMessageMetaType()
     return tp;
 }
 
-int QDBusConnectionPrivate::findSlot(QObject* obj, const char *slotName, QList<int>& params)
+int QDBusConnectionPrivate::findSlot(QObject* obj, const QByteArray &normalizedName,
+                                     QList<int> &params)
 {
-    Q_ASSERT(slotName);
-    QByteArray normalizedName = QMetaObject::normalizedSignature(slotName);
-    int midx = obj->metaObject()->indexOfSlot(normalizedName);
+    int midx = obj->metaObject()->indexOfMethod(normalizedName);
     if (midx == -1) {
-        qWarning("No such slot '%s' while connecting D-Bus", slotName);
+        qWarning("No such slot '%s' while connecting D-Bus", normalizedName.constData());
         return -1;
     }
 
@@ -980,6 +885,42 @@ int QDBusConnectionPrivate::findSlot(QObject* obj, const char *slotName, QList<i
     return midx;
 }
 
+bool QDBusConnectionPrivate::prepareHook(QDBusConnectionPrivate::SignalHook &hook, QString &key,
+                                         const QString &service, const QString &path,
+                                         const QString &interface, const QString &name,
+                                         QObject *receiver, const char *signal, int minMIdx,
+                                         bool buildSignature)
+{
+    QByteArray normalizedName = QMetaObject::normalizedSignature(signal + 1);
+    hook.midx = findSlot(receiver, normalizedName, hook.params);
+    if (hook.midx < minMIdx)
+        return false;
+
+    hook.sender = service;
+    hook.path = path;
+    hook.obj = receiver;
+
+    // build the D-Bus signal name and signature
+    QString mname = name;
+    if (mname.isEmpty()) {
+        normalizedName.truncate(normalizedName.indexOf('('));        
+        mname = QString::fromUtf8(normalizedName);
+    }
+    key = mname;
+    key.reserve(interface.length() + 1 + mname.length());
+    key += ':';
+    key += interface;
+
+    if (buildSignature) {
+        hook.signature.clear();
+        for (int i = 1; i < hook.params.count(); ++i)
+            if (hook.params.at(i) != messageMetaType)
+                hook.signature += QLatin1String( QDBusType::dbusSignature( QVariant::Type(hook.params.at(i)) ) );
+    }
+    
+    return true;                // connect to this signal
+}
+
 bool QDBusConnectionPrivate::activateInternalFilters(const ObjectTreeNode *node, const QDBusMessage &msg)
 {
     // object may be null
@@ -987,7 +928,8 @@ bool QDBusConnectionPrivate::activateInternalFilters(const ObjectTreeNode *node,
     if (msg.interface().isEmpty() || msg.interface() == QLatin1String(DBUS_INTERFACE_INTROSPECTABLE)) {
         if (msg.method() == QLatin1String("Introspect") && msg.signature().isEmpty())
             qDBusIntrospectObject(node, msg);
-        return true;
+        if (msg.interface() == QLatin1String(DBUS_INTERFACE_INTROSPECTABLE))
+            return true;
     }
 
     if (node->obj && (msg.interface().isEmpty() ||
@@ -996,10 +938,9 @@ bool QDBusConnectionPrivate::activateInternalFilters(const ObjectTreeNode *node,
             qDBusPropertyGet(node, msg);
         else if (msg.method() == QLatin1String("Set") && msg.signature() == QLatin1String("ssv"))
             qDBusPropertySet(node, msg);
-        else
-            return false;
-            
-        return true;
+
+        if (msg.interface() == QLatin1String(DBUS_INTERFACE_PROPERTIES))
+            return true;
     }
 
     return false;
@@ -1144,19 +1085,17 @@ bool QDBusConnectionPrivate::handleObjectCall(const QDBusMessage &msg)
     return false;
 }
 
-bool QDBusConnectionPrivate::handleSignal(const QString &path, const QDBusMessage &msg)
+bool QDBusConnectionPrivate::handleSignal(const QString &key, const QDBusMessage& msg)
 {
-    QReadLocker locker(&lock);
-
     bool result = false;
-    SignalHookHash::const_iterator it = signalHooks.find(path);
+    SignalHookHash::const_iterator it = signalHooks.find(key);
     //qDebug("looking for: %s", path.toLocal8Bit().constData());
     //qDebug() << signalHooks.keys();
-    for ( ; it != signalHooks.constEnd() && it.key() == path; ++ it) {
+    for ( ; it != signalHooks.constEnd() && it.key() == key; ++it) {
         const SignalHook &hook = it.value();
-        if ( !hook.name.isEmpty() && hook.name != msg.name() )
+        if ( !hook.sender.isEmpty() && hook.sender != msg.sender() )
             continue;
-        if ( !hook.interface.isEmpty() && hook.interface != msg.interface() )
+        if ( !hook.path.isEmpty() && hook.path != msg.path() )
             continue;
         if ( !hook.signature.isEmpty() && hook.signature != msg.signature() )
             continue;
@@ -1171,8 +1110,17 @@ bool QDBusConnectionPrivate::handleSignal(const QString &path, const QDBusMessag
 
 bool QDBusConnectionPrivate::handleSignal(const QDBusMessage& msg)
 {
-    // yes, it is a single "|" below...
-    return handleSignal(QString(), msg) | handleSignal(msg.sender() + msg.path(), msg);
+    QString key = msg.member();
+    key.reserve(key.length() + 1 + msg.interface().length());
+    key += ':';
+    key += msg.interface();
+
+    QReadLocker locker(&lock);
+    bool result = handleSignal(key, msg);    // one try
+
+    key.truncate(msg.member().length() + 1); // keep the ':'
+    result |= handleSignal(key, msg);        // second try
+    return result;
 }
 
 static dbus_int32_t server_slot = -1;
@@ -1247,6 +1195,9 @@ void QDBusConnectionPrivate::setConnection(DBusConnection *dbc)
 #endif
 
     //qDebug("base service: %s", service);
+
+    // schedule a dispatch:
+    QMetaObject::invokeMethod(this, "doDispatch", Qt::QueuedConnection);
 }
 
 extern "C"{
@@ -1255,6 +1206,7 @@ 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);
@@ -1284,18 +1236,22 @@ void QDBusConnectionPrivate::messageResultReceived(DBusPendingCall *pending, voi
     delete call;
 }
 
-bool QDBusConnectionPrivate::send(const QDBusMessage& message) const
+int QDBusConnectionPrivate::send(const QDBusMessage& message) const
 {
     DBusMessage *msg = message.toDBusMessage();
     if (!msg)
-        return false;
+        return 0;
 
     dbus_message_set_no_reply(msg, true); // the reply would not be delivered to anything
 
     qDebug() << "sending message:" << message;
     bool isOk = dbus_connection_send(connection, msg, 0);
+    int serial = 0;
+    if (isOk)
+        serial = dbus_message_get_serial(msg);
+
     dbus_message_unref(msg);
-    return isOk;
+    return serial;
 }
 
 QDBusMessage QDBusConnectionPrivate::sendWithReply(const QDBusMessage &message,
@@ -1306,6 +1262,7 @@ QDBusMessage QDBusConnectionPrivate::sendWithReply(const QDBusMessage &message,
         if (!msg)
             return QDBusMessage();
 
+        qDebug() << "sending message:" << message;
         DBusMessage *reply = dbus_connection_send_with_reply_and_block(connection, msg,
                                                                        -1, &error);
         handleError();
@@ -1314,7 +1271,12 @@ QDBusMessage QDBusConnectionPrivate::sendWithReply(const QDBusMessage &message,
         if (lastError.isValid())
             return QDBusMessage::fromError(lastError);
 
-        return QDBusMessage::fromDBusMessage(reply, QDBusConnection(name));
+        QDBusMessage amsg = QDBusMessage::fromDBusMessage(reply, QDBusConnection(name));
+        qDebug() << "got message:" << amsg;
+
+        if (dbus_connection_get_dispatch_status(connection) == DBUS_DISPATCH_DATA_REMAINS)
+            QMetaObject::invokeMethod(this, "doDispatch", Qt::QueuedConnection);
+        return amsg;
     } else {                    // use the event loop
         QDBusReplyWaiter waiter;
         if (sendWithReplyAsync(message, &waiter, SLOT(reply(const QDBusMessage&))) > 0) {
@@ -1332,14 +1294,21 @@ QDBusMessage QDBusConnectionPrivate::sendWithReply(const QDBusMessage &message,
 int QDBusConnectionPrivate::sendWithReplyAsync(const QDBusMessage &message, QObject *receiver,
                                                const char *method)
 {
-    DBusMessage *msg = message.toDBusMessage();
-    if (!msg)
-        return 0;
+    if (!receiver || !method || !*method)
+        // would not be able to deliver a reply
+        return send(message);
 
     int slotIdx = -1;
     QList<int> metaTypes;
-    if (receiver && method && *method)
-        slotIdx = findSlot(receiver, method + 1, metaTypes);
+    QByteArray normalizedName = QMetaObject::normalizedSignature(method + 1);
+    slotIdx = findSlot(receiver, normalizedName, metaTypes);
+    if (slotIdx == -1)
+        // would not be able to deliver a reply
+        return send(message);
+
+    DBusMessage *msg = message.toDBusMessage();
+    if (!msg)
+        return 0;
 
     qDebug() << "sending message:" << message;
     DBusPendingCall *pending = 0;
@@ -1388,45 +1357,27 @@ void QDBusConnectionPrivate::connectRelay(const QString &service, const QString
 {
     // 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)) ) );
+    QString key;
+    if (!prepareHook(hook, key, service, path, interface, QString(), receiver, signal,
+                     QDBusAbstractInterface::staticMetaObject.methodCount(), true))
+        return;                 // don't connect
 
     // add it to our list:
     QWriteLocker locker(&lock);
-    SignalHookHash::ConstIterator it = signalHooks.find(source);
+    SignalHookHash::ConstIterator it = signalHooks.find(key);
     SignalHookHash::ConstIterator end = signalHooks.end();
-    for ( ; it != end && it.key() == source; ++it) {
+    for ( ; it != end && it.key() == key; ++it) {
         const SignalHook &entry = it.value();
-        if (entry.interface == hook.interface &&
-            entry.name == hook.name &&
+        if (entry.sender == hook.sender &&
+            entry.path == hook.path &&
             entry.signature == hook.signature &&
             entry.obj == hook.obj &&
             entry.midx == hook.midx)
             return;             // already there, no need to re-add
     }
 
-    connectSignal(source, hook);
+    connectSignal(key, hook);
 }
 
 void QDBusConnectionPrivate::disconnectRelay(const QString &service, const QString &path,
@@ -1436,38 +1387,20 @@ void QDBusConnectionPrivate::disconnectRelay(const QString &service, const QStri
 {
     // 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)) ) );
+    QString key;
+    if (!prepareHook(hook, key, service, path, interface, QString(), receiver, signal,
+                     QDBusAbstractInterface::staticMetaObject.methodCount(), true))
+        return;                 // don't connect
 
     // remove it from our list:
     QWriteLocker locker(&lock);
-    SignalHookHash::Iterator it = signalHooks.find(source);
+    SignalHookHash::Iterator it = signalHooks.find(key);
     SignalHookHash::Iterator end = signalHooks.end();
-    for ( ; it != end && it.key() == source; ++it) {
+    for ( ; it != end && it.key() == key; ++it) {
         const SignalHook &entry = it.value();
-        if (entry.interface == hook.interface &&
-            entry.name == hook.name &&
+        if (entry.sender == hook.sender &&
+            entry.path == hook.path &&
             entry.signature == hook.signature &&
             entry.obj == hook.obj &&
             entry.midx == hook.midx) {
index 0afa452..6367654 100644 (file)
@@ -58,19 +58,6 @@ QDBusInterface::~QDBusInterface()
 }
 
 /*!
-    Returns true if this is a valid reference to a remote object. It returns false if
-    there was an error during the creation of this interface (for instance, if the remote
-    application does not exist).
-
-    Note: when dealing with remote objects, it is not always possible to determine if it
-    exists when creating a QDBusInterface or QDBusInterfacePtr object.
-*/
-bool QDBusInterface::isValid() const
-{
-    return d_func()->isValid;
-}
-
-/*!
     \internal
     Overrides QObject::metaObject to return our own copy.
 */
index 2e16e5c..716ca8a 100644 (file)
@@ -35,7 +35,6 @@ private:
     
 public:
     ~QDBusInterface();
-    bool isValid() const;
     
     virtual const QMetaObject *metaObject() const;
     virtual void *qt_metacast(const char *);
@@ -43,6 +42,7 @@ public:
 
 private:
     Q_DECLARE_PRIVATE(QDBusInterface);
+    Q_DISABLE_COPY(QDBusInterface)
 };
 
 struct QDBUS_EXPORT QDBusInterfacePtr
index 3d45427..8886d3b 100644 (file)
 
 #include "qdbusabstractadaptor.h"
 #include "qdbusabstractadaptor_p.h"
-#include "qdbusinterface_p.h"   // for ANNOTATION_NO_WAIT
+#include "qdbusconnection.h"
 #include "qdbusmessage.h"
+#include "qdbustypehelper_p.h"
 #include "qdbusutil.h"
 
+// defined in qdbusxmlgenerator.cpp
+extern QString qDBusGenerateMetaObjectXml(QString interface, const QMetaObject *mo,
+                                          const QMetaObject *base, int flags);
+
 static const char introspectableInterfaceXml[] =
     "  <interface name=\"org.freedesktop.DBus.Introspectable\">\n"
     "    <method name=\"Introspect\">\n"
@@ -55,164 +60,6 @@ static const char propertiesInterfaceXml[] =
     "    </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 QString generateInterfaceXml(const QMetaObject *mo, int flags, int methodOffset, int propOffset)
-{
-    QString retval;
-
-    // start with properties:
-    if (flags & QDBusConnection::ExportProperties) {
-        for (int i = propOffset; i < mo->propertyCount(); ++i) {
-            static const char *accessvalues[] = {0, "read", "write", "readwrite"};
-
-            QMetaProperty mp = mo->property(i);
-
-            if (!mp.isScriptable() && (flags & QDBusConnection::ExportAllProperties) !=
-                QDBusConnection::ExportAllProperties)
-                continue;
-
-            int access = 0;
-            if (mp.isReadable())
-                access |= 1;
-            if (mp.isWritable())
-                access |= 2;
-
-            int typeId = qDBusNameToTypeId(mp.typeName());
-            if (!typeId)
-                continue;
-
-            retval += QString(QLatin1String("    <property name=\"%1\" type=\"%2\" access=\"%3\" />\n"))
-                      .arg(mp.name())
-                      .arg(QLatin1String( QDBusUtil::typeToSignature( QVariant::Type(typeId) )))
-                      .arg(QLatin1String( accessvalues[access] ));
-        }
-    }
-
-    // now add methods:
-    for (int i = methodOffset; i < mo->methodCount(); ++i) {
-        QMetaMethod mm = mo->method(i);
-        QByteArray signature = mm.signature();
-        int paren = signature.indexOf('(');
-
-        bool isSignal;
-        if (mm.methodType() == QMetaMethod::Signal)
-            // adding a signal
-            isSignal = true;
-        else if (mm.methodType() == QMetaMethod::Slot && mm.access() == QMetaMethod::Public)
-            isSignal = false;
-        else
-            continue;           // neither signal nor public slot
-
-        if ((isSignal && !(flags & QDBusConnection::ExportSignals)) ||
-            (!isSignal && !(flags & QDBusConnection::ExportSlots)))
-            continue;
-
-        QString xml = QString(QLatin1String("    <%1 name=\"%2\">\n"))
-                      .arg(isSignal ? QLatin1String("signal") : QLatin1String("method"))
-                      .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(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(mm, types);
-        if (inputCount == -1)
-            continue;           // invalid form
-        if (isSignal && inputCount + 1 != types.count())
-            continue;           // signal with output arguments?
-        if (isSignal && types.at(inputCount) == QDBusConnectionPrivate::messageMetaType)
-            continue;           // signal with QDBusMessage argument?
-
-        int j;
-        bool isScriptable = mm.attributes() & QMetaMethod::Scriptable;
-        for (j = 1; j < types.count(); ++j) {
-            // input parameter for a slot or output for a signal
-            if (types.at(j) == QDBusConnectionPrivate::messageMetaType) {
-                isScriptable = true;
-                continue;
-            }
-
-            QString name;
-            if (!names.at(j - 1).isEmpty())
-                name = QString(QLatin1String("name=\"%1\" ")).arg(QLatin1String(names.at(j - 1)));
-
-            bool isOutput = isSignal || j > inputCount;
-
-            xml += QString(QLatin1String("      <arg %1type=\"%2\" direction=\"%3\"/>\n"))
-                   .arg(name)
-                   .arg(QLatin1String(QDBusUtil::typeToSignature( QVariant::Type(types.at(j)) )))
-                   .arg(isOutput ? QLatin1String("out") : QLatin1String("in"));
-        }
-
-        if (!isScriptable) {
-            // check if this was added by other means
-            if (isSignal && (flags & QDBusConnection::ExportAllSignals) != QDBusConnection::ExportAllSignals)
-                continue;
-            if (!isSignal && (flags & QDBusConnection::ExportAllSlots) != QDBusConnection::ExportAllSlots)
-                continue;
-        }
-
-        if (qDBusCheckAsyncTag(mm.tag()))
-            // add the no-reply annotation
-            xml += QLatin1String("      <annotation name=\"" ANNOTATION_NO_WAIT "\""
-                                 " value=\"true\"/>\n");
-
-        retval += xml;
-        retval += QString(QLatin1String("    </%1>\n"))
-                  .arg(isSignal ? QLatin1String("signal") : QLatin1String("method"));
-    }
-
-    return retval;
-}
-
-static QString generateMetaObjectXml(QString interface, const QMetaObject *mo, const QMetaObject *base,
-                                     int flags)
-{
-    if (interface.isEmpty()) {
-        // generate the interface name from the meta object
-        int idx = mo->indexOfClassInfo(QCLASSINFO_DBUS_INTERFACE);
-        if (idx >= mo->classInfoOffset()) {
-            interface = QLatin1String(mo->classInfo(idx).value());
-        } else {
-            interface = QLatin1String(mo->className());
-            interface.replace(QLatin1String("::"), QLatin1String("."));
-
-            if (interface.startsWith( QLatin1String("QDBus") )) {
-                interface.prepend( QLatin1String("com.trolltech.QtDBus.") );
-            } else if (interface.startsWith( QLatin1Char('Q') )) {
-                // assume it's Qt
-                interface.prepend( QLatin1String("com.trolltech.Qt.") );
-            } else if (!QCoreApplication::instance() ||
-                       QCoreApplication::instance()->applicationName().isEmpty()) {
-                interface.prepend( QLatin1String("local.") );
-            } else {
-                interface.prepend(QLatin1Char('.')).prepend( QCoreApplication::instance()->applicationName() );
-                QStringList domainName = QCoreApplication::instance()->organizationDomain().split(QLatin1Char('.'));
-                foreach (const QString &part, domainName)
-                    interface.prepend(QLatin1Char('.')).prepend(part);
-            }
-        }
-    }
-
-    QString xml;
-    int idx = mo->indexOfClassInfo(QCLASSINFO_DBUS_INTROSPECTION);
-    if (idx >= mo->classInfoOffset())
-        xml = QString::fromUtf8(mo->classInfo(idx).value());
-    else
-        xml = generateInterfaceXml(mo, flags, base->methodCount(), base->propertyCount());
-
-    return QString(QLatin1String("  <interface name=\"%1\">\n%2  </interface>\n"))
-        .arg(interface, xml);
-}
-
 static QString generateSubObjectXml(QObject *object)
 {
     QString retval;
@@ -236,7 +83,7 @@ QString qDBusIntrospectObject(const QDBusConnectionPrivate::ObjectTreeNode *node
         if (node->flags & QDBusConnection::ExportContents) {
             const QMetaObject *mo = node->obj->metaObject();
             for ( ; mo != &QObject::staticMetaObject; mo = mo->superClass())
-                xml_data += generateMetaObjectXml(QString(), mo, mo->superClass(),
+                xml_data += qDBusGenerateMetaObjectXml(QString(), mo, mo->superClass(),
                                                   node->flags);
         }
 
@@ -253,9 +100,9 @@ QString qDBusIntrospectObject(const QDBusConnectionPrivate::ObjectTreeNode *node
                 QString ifaceXml = QDBusAbstractAdaptorPrivate::retrieveIntrospectionXml(it->adaptor);
                 if (ifaceXml.isEmpty()) {
                     // add the interface's contents:
-                    ifaceXml += generateMetaObjectXml(it->interface, it->metaObject,
-                                                      &QDBusAbstractAdaptor::staticMetaObject,
-                                                      QDBusConnection::ExportAllContents);
+                    ifaceXml += qDBusGenerateMetaObjectXml(it->interface, it->metaObject,
+                                                           &QDBusAbstractAdaptor::staticMetaObject,
+                                                           QDBusConnection::ExportAllContents);
 
                     QDBusAbstractAdaptorPrivate::saveIntrospectionXml(it->adaptor, ifaceXml);
                 }
index a055327..5b3c7d3 100644 (file)
@@ -37,7 +37,7 @@
 # error Sorry, you need a compiler with support for template member functions to compile QtDBus.
 #endif
 
-#if defined(DBUS_COMPILATION) && defined(QDBUS_MAKEDLL)
+#if defined(QDBUS_MAKEDLL)
 # define QDBUS_EXPORT Q_DECL_EXPORT
 #else
 # define QDBUS_EXPORT Q_DECL_IMPORT
@@ -46,8 +46,5 @@
 #ifndef Q_MOC_RUN
 # define Q_ASYNC
 #endif
-#ifndef QT_NO_KEYWORDS
-# define async  Q_ASYNC
-#endif
 
 #endif
index 2992c70..a923d79 100644 (file)
@@ -48,8 +48,8 @@ private:
         QByteArray tag;
         QByteArray inputSignature;
         QByteArray outputSignature;
-        QVarLengthArray<int, 6> inputTypes;
-        QVarLengthArray<int, 2> outputTypes;
+        QVarLengthArray<int, 4> inputTypes;
+        QVarLengthArray<int, 4> outputTypes;
         int flags;
     };
     
@@ -297,7 +297,7 @@ void QDBusMetaObjectGenerator::write(QDBusMetaObject *obj)
     if (className.isEmpty())
         className = QLatin1String("QDBusInterface");
 
-    QVarLengthArray<uint> data;
+    QVarLengthArray<int> data;
     data.resize(sizeof(QDBusMetaObjectPrivate) / sizeof(int));
 
     QDBusMetaObjectPrivate *header = reinterpret_cast<QDBusMetaObjectPrivate *>(data.data());
diff --git a/qt/qdbusmisc.cpp b/qt/qdbusmisc.cpp
new file mode 100644 (file)
index 0000000..9aaf9f2
--- /dev/null
@@ -0,0 +1,156 @@
+/* qdbusmisc.cpp Miscellaneous routines that didn't fit anywhere else
+ *
+ * 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 <string.h>
+
+#include <QtCore/qvariant.h>
+#include <QtCore/qmetaobject.h>
+
+#include "qdbusconnection_p.h"
+#include "qdbustypehelper_p.h"
+
+bool qDBusCheckAsyncTag(const char *tag)
+{
+    if (!tag || !*tag)
+        return false;
+
+    const char *p = strstr(tag, "async");
+    if (p != NULL &&
+        (p == tag || *(p-1) == ' ') &&
+        (p[5] == '\0' || p[5] == ' '))
+        return true;
+
+    p = strstr(tag, "Q_ASYNC");
+    if (p != NULL &&
+        (p == tag || *(p-1) == ' ') &&
+        (p[7] == '\0' || p[7] == ' '))
+        return true;
+
+    return false;
+}
+
+int qDBusNameToTypeId(const char *name)
+{
+    int id = static_cast<int>( QVariant::nameToType(name) );
+    if (id == QVariant::UserType)
+        id = QMetaType::type(name);
+
+    switch (id) {
+    case QVariant::Bool:
+    case QVariant::Int:
+    case QVariant::UInt:
+    case QVariant::Char:
+    case QMetaType::Short:
+    case QMetaType::UShort:
+    case QMetaType::UChar:
+    case QVariant::LongLong:
+    case QVariant::ULongLong:
+    case QVariant::Double:
+    case QVariant::String:
+    case QVariant::Date:
+    case QVariant::Time:
+    case QVariant::DateTime:
+    case QVariant::Map:
+    case QVariant::StringList:
+    case QVariant::ByteArray:
+    case QVariant::List:
+        return id;
+
+    default:
+        if (id == QDBusConnectionPrivate::registerMessageMetaType() ||
+            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
+    }
+}
+
+// calculates the metatypes for the method
+// the slot must have the parameters in the following form:
+//  - zero or more value or const-ref parameters of any kind
+//  - zero or one const ref of QDBusMessage
+//  - zero or more non-const ref parameters
+// No parameter may be a template.
+// this function returns -1 if the parameters don't match the above form
+// this function returns the number of *input* parameters, including the QDBusMessage one if any
+// this function does not check the return type, so metaTypes[0] is always 0 and always present
+// metaTypes.count() >= retval + 1 in all cases
+//
+// sig must be the normalised signature for the method
+int qDBusParametersForMethod(const QMetaMethod &mm, QList<int>& metaTypes)
+{
+    QList<QByteArray> parameterTypes = mm.parameterTypes();
+    metaTypes.clear();
+
+    metaTypes.append(0);        // return type
+    int inputCount = 0;
+    bool seenMessage = false;
+    foreach (QByteArray type, parameterTypes) {
+        if (type.endsWith('*')) {
+            //qWarning("Could not parse the method '%s'", mm.signature());
+            // pointer?
+            return -1;
+        }
+
+        if (type.endsWith('&')) {
+            type.truncate(type.length() - 1);
+            int id = qDBusNameToTypeId(type);
+            if (id == 0) {
+                //qWarning("Could not parse the method '%s'", mm.signature());
+                // invalid type in method parameter list
+                return -1;
+            }
+
+            metaTypes.append( id );
+            seenMessage = true; // it cannot appear anymore anyways
+            continue;
+        }
+
+        if (seenMessage) {      // && !type.endsWith('&')
+            //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'", mm.signature());
+            // invalid type in method parameter list
+            return -1;
+        }
+        metaTypes.append(id);
+        ++inputCount;
+
+        if (id == QDBusConnectionPrivate::registerMessageMetaType())
+            seenMessage = true;
+    }
+
+    return inputCount;
+}
diff --git a/qt/qdbusxmlgenerator.cpp b/qt/qdbusxmlgenerator.cpp
new file mode 100644 (file)
index 0000000..561985a
--- /dev/null
@@ -0,0 +1,192 @@
+/* -*- mode: 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 <QtCore/qcoreapplication.h>
+#include <QtCore/qmetaobject.h>
+#include <QtCore/qstringlist.h>
+
+#include "qdbusinterface_p.h"   // for ANNOTATION_NO_WAIT
+#include "qdbusabstractadaptor_p.h" // for QCLASSINFO_DBUS_*
+#include "qdbusconnection_p.h"  // for the flags
+#include "qdbusutil.h"
+
+extern QDBUS_EXPORT QString qDBusGenerateMetaObjectXml(QString interface, const QMetaObject *mo,
+                                                       const QMetaObject *base, int flags);
+
+// implement the D-Bus org.freedesktop.DBus.Introspectable interface
+// we do that by analysing the metaObject of all the adaptor interfaces
+
+static QString generateInterfaceXml(const QMetaObject *mo, int flags, int methodOffset, int propOffset)
+{
+    QString retval;
+
+    // start with properties:
+    if (flags & QDBusConnection::ExportProperties) {
+        for (int i = propOffset; i < mo->propertyCount(); ++i) {
+            static const char *accessvalues[] = {0, "read", "write", "readwrite"};
+
+            QMetaProperty mp = mo->property(i);
+
+            if (!mp.isScriptable() && (flags & QDBusConnection::ExportAllProperties) !=
+                QDBusConnection::ExportAllProperties)
+                continue;
+
+            int access = 0;
+            if (mp.isReadable())
+                access |= 1;
+            if (mp.isWritable())
+                access |= 2;
+
+            int typeId = qDBusNameToTypeId(mp.typeName());
+            if (!typeId)
+                continue;
+
+            retval += QString(QLatin1String("    <property name=\"%1\" type=\"%2\" access=\"%3\" />\n"))
+                      .arg(mp.name())
+                      .arg(QLatin1String( QDBusUtil::typeToSignature( QVariant::Type(typeId) )))
+                      .arg(QLatin1String( accessvalues[access] ));
+        }
+    }
+
+    // now add methods:
+    for (int i = methodOffset; i < mo->methodCount(); ++i) {
+        QMetaMethod mm = mo->method(i);
+        QByteArray signature = mm.signature();
+        int paren = signature.indexOf('(');
+
+        bool isSignal;
+        if (mm.methodType() == QMetaMethod::Signal)
+            // adding a signal
+            isSignal = true;
+        else if (mm.methodType() == QMetaMethod::Slot && mm.access() == QMetaMethod::Public)
+            isSignal = false;
+        else
+            continue;           // neither signal nor public slot
+
+        if ((isSignal && !(flags & QDBusConnection::ExportSignals)) ||
+            (!isSignal && !(flags & QDBusConnection::ExportSlots)))
+            continue;
+
+        QString xml = QString(QLatin1String("    <%1 name=\"%2\">\n"))
+                      .arg(isSignal ? QLatin1String("signal") : QLatin1String("method"))
+                      .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(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(mm, types);
+        if (inputCount == -1)
+            continue;           // invalid form
+        if (isSignal && inputCount + 1 != types.count())
+            continue;           // signal with output arguments?
+        if (isSignal && types.at(inputCount) == QDBusConnectionPrivate::messageMetaType)
+            continue;           // signal with QDBusMessage argument?
+
+        int j;
+        bool isScriptable = mm.attributes() & QMetaMethod::Scriptable;
+        for (j = 1; j < types.count(); ++j) {
+            // input parameter for a slot or output for a signal
+            if (types.at(j) == QDBusConnectionPrivate::messageMetaType) {
+                isScriptable = true;
+                continue;
+            }
+
+            QString name;
+            if (!names.at(j - 1).isEmpty())
+                name = QString(QLatin1String("name=\"%1\" ")).arg(QLatin1String(names.at(j - 1)));
+
+            bool isOutput = isSignal || j > inputCount;
+
+            xml += QString(QLatin1String("      <arg %1type=\"%2\" direction=\"%3\"/>\n"))
+                   .arg(name)
+                   .arg(QLatin1String(QDBusUtil::typeToSignature( QVariant::Type(types.at(j)) )))
+                   .arg(isOutput ? QLatin1String("out") : QLatin1String("in"));
+        }
+
+        if (!isScriptable) {
+            // check if this was added by other means
+            if (isSignal && (flags & QDBusConnection::ExportAllSignals) != QDBusConnection::ExportAllSignals)
+                continue;
+            if (!isSignal && (flags & QDBusConnection::ExportAllSlots) != QDBusConnection::ExportAllSlots)
+                continue;
+        }
+
+        if (qDBusCheckAsyncTag(mm.tag()))
+            // add the no-reply annotation
+            xml += QLatin1String("      <annotation name=\"" ANNOTATION_NO_WAIT "\""
+                                 " value=\"true\"/>\n");
+
+        retval += xml;
+        retval += QString(QLatin1String("    </%1>\n"))
+                  .arg(isSignal ? QLatin1String("signal") : QLatin1String("method"));
+    }
+
+    return retval;
+}
+
+QString qDBusGenerateMetaObjectXml(QString interface, const QMetaObject *mo, const QMetaObject *base,
+                                   int flags)
+{
+    if (interface.isEmpty()) {
+        // generate the interface name from the meta object
+        int idx = mo->indexOfClassInfo(QCLASSINFO_DBUS_INTERFACE);
+        if (idx >= mo->classInfoOffset()) {
+            interface = QLatin1String(mo->classInfo(idx).value());
+        } else {
+            interface = QLatin1String(mo->className());
+            interface.replace(QLatin1String("::"), QLatin1String("."));
+
+            if (interface.startsWith( QLatin1String("QDBus") )) {
+                interface.prepend( QLatin1String("com.trolltech.QtDBus.") );
+            } else if (interface.startsWith( QLatin1Char('Q') )) {
+                // assume it's Qt
+                interface.prepend( QLatin1String("com.trolltech.Qt.") );
+            } else if (!QCoreApplication::instance() ||
+                       QCoreApplication::instance()->applicationName().isEmpty()) {
+                interface.prepend( QLatin1String("local.") );
+            } else {
+                interface.prepend(QLatin1Char('.')).prepend( QCoreApplication::instance()->applicationName() );
+                QStringList domainName = QCoreApplication::instance()->organizationDomain().split(QLatin1Char('.'));
+                foreach (const QString &part, domainName)
+                    interface.prepend(QLatin1Char('.')).prepend(part);
+            }
+        }
+    }
+
+    QString xml;
+    int idx = mo->indexOfClassInfo(QCLASSINFO_DBUS_INTROSPECTION);
+    if (idx >= mo->classInfoOffset())
+        return QString::fromUtf8(mo->classInfo(idx).value());
+    else
+        xml = generateInterfaceXml(mo, flags, base->methodCount(), base->propertyCount());
+
+    return QString(QLatin1String("  <interface name=\"%1\">\n%2  </interface>\n"))
+        .arg(interface, xml);
+}