dbus/qt Makefile.am, 1.22, 1.23 dbuscpp2xml.cpp, NONE, 1.1 dbusidl2cpp.cpp, 1.4, 1.5 qdbusabstractadaptor.cpp, 1.4, 1.5 qdbusabstractinterface.cpp, 1.4, 1.5 qdbusabstractinterface.h, 1.4, 1.5 qdbusconnection.cpp, 1.7, 1.8 qdbusconnection_p.h, 1.9, 1.10 qdbusintegrator.cpp, 1.11, 1.12 qdbusinterface.cpp, 1.7, 1.8 qdbusinterface.h, 1.5, 1.6 qdbusinternalfilters.cpp, 1.5, 1.6 qdbusmacros.h, 1.5, 1.6 qdbusmetaobject.cpp, 1.2, 1.3 qdbusmisc.cpp, NONE, 1.1 qdbusxmlgenerator.cpp, NONE, 1.1

Thiago J. Macieira thiago at kemper.freedesktop.org
Mon May 29 11:17:11 PDT 2006


Update of /cvs/dbus/dbus/qt
In directory kemper:/tmp/cvs-serv20573/qt

Modified Files:
	Makefile.am dbusidl2cpp.cpp qdbusabstractadaptor.cpp 
	qdbusabstractinterface.cpp qdbusabstractinterface.h 
	qdbusconnection.cpp qdbusconnection_p.h qdbusintegrator.cpp 
	qdbusinterface.cpp qdbusinterface.h qdbusinternalfilters.cpp 
	qdbusmacros.h qdbusmetaobject.cpp 
Added Files:
	dbuscpp2xml.cpp qdbusmisc.cpp qdbusxmlgenerator.cpp 
Log Message:
        * 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.


Index: Makefile.am
===================================================================
RCS file: /cvs/dbus/dbus/qt/Makefile.am,v
retrieving revision 1.22
retrieving revision 1.23
diff -u -d -r1.22 -r1.23
--- Makefile.am	28 Apr 2006 20:09:17 -0000	1.22
+++ Makefile.am	29 May 2006 18:17:09 -0000	1.23
@@ -41,20 +41,25 @@
         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 @@
 
 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
 

--- NEW FILE: dbuscpp2xml.cpp ---
/* -*- C++ -*-
 *
 * Copyright (C) 2006 Trolltech AS. All rights reserved.
 *    Author: Thiago Macieira <thiago.macieira at 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: dbusidl2cpp.cpp
===================================================================
RCS file: /cvs/dbus/dbus/qt/dbusidl2cpp.cpp,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -d -r1.4 -r1.5
--- dbusidl2cpp.cpp	2 May 2006 14:00:27 -0000	1.4
+++ dbusidl2cpp.cpp	29 May 2006 18:17:09 -0000	1.5
@@ -375,7 +375,7 @@
                 retval += "\\\"";
             else
                 retval += data[i];
-        retval += "\"\n";
+        retval += "\\n\"\n";
     }
     return retval;
 }

Index: qdbusabstractadaptor.cpp
===================================================================
RCS file: /cvs/dbus/dbus/qt/qdbusabstractadaptor.cpp,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -d -r1.4 -r1.5
--- qdbusabstractadaptor.cpp	2 May 2006 14:00:27 -0000	1.4
+++ qdbusabstractadaptor.cpp	29 May 2006 18:17:09 -0000	1.5
@@ -242,12 +242,11 @@
         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: qdbusabstractinterface.cpp
===================================================================
RCS file: /cvs/dbus/dbus/qt/qdbusabstractinterface.cpp,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -d -r1.4 -r1.5
--- qdbusabstractinterface.cpp	2 May 2006 14:00:27 -0000	1.4
+++ qdbusabstractinterface.cpp	29 May 2006 18:17:09 -0000	1.5
@@ -131,6 +131,19 @@
 }
 
 /*!
+    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: qdbusabstractinterface.h
===================================================================
RCS file: /cvs/dbus/dbus/qt/qdbusabstractinterface.h,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -d -r1.4 -r1.5
--- qdbusabstractinterface.h	2 May 2006 14:00:27 -0000	1.4
+++ qdbusabstractinterface.h	29 May 2006 18:17:09 -0000	1.5
@@ -51,6 +51,7 @@
 
 public:
     virtual ~QDBusAbstractInterface();
+    bool isValid() const;
 
     QDBusConnection connection() const;
 

Index: qdbusconnection.cpp
===================================================================
RCS file: /cvs/dbus/dbus/qt/qdbusconnection.cpp,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -d -r1.7 -r1.8
--- qdbusconnection.cpp	23 Apr 2006 19:04:53 -0000	1.7
+++ qdbusconnection.cpp	29 May 2006 18:17:09 -0000	1.8
@@ -85,6 +85,7 @@
     }
 }
 
+QDBUS_EXPORT void qDBusBindToApplication();
 void qDBusBindToApplication()
 {
     manager()->bindToApplication();
@@ -351,12 +352,6 @@
     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 @@
 {
     if (!d || !d->connection)
         return false;
-    return d->send(message);
+    return d->send(message) != 0;
 }
 
 /*!
@@ -445,25 +440,21 @@
         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 @@
     }
 
 
-    d->connectSignal(source, hook);
+    d->connectSignal(key, hook);
     return true;
 }
 

Index: qdbusconnection_p.h
===================================================================
RCS file: /cvs/dbus/dbus/qt/qdbusconnection_p.h,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -d -r1.9 -r1.10
--- qdbusconnection_p.h	29 Apr 2006 12:44:31 -0000	1.9
+++ qdbusconnection_p.h	29 May 2006 18:17:09 -0000	1.10
@@ -85,7 +85,7 @@
     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 @@
 
     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 @@
     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 @@
 
 public slots:
     // public slots
+    void doDispatch();
     void socketRead(int);
     void socketWrite(int);
     void objectDestroyed(QObject *o);
@@ -210,7 +211,12 @@
     // 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 @@
     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: qdbusintegrator.cpp
===================================================================
RCS file: /cvs/dbus/dbus/qt/qdbusintegrator.cpp,v
retrieving revision 1.11
retrieving revision 1.12
diff -u -d -r1.11 -r1.12
--- qdbusintegrator.cpp	6 May 2006 10:37:59 -0000	1.11
+++ qdbusintegrator.cpp	29 May 2006 18:17:09 -0000	1.12
@@ -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 @@
     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 @@
     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 @@
     }
 }
 
-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 @@
     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 @@
     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 @@
 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 @@
         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 @@
        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 @@
                 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 @@
     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 @@
     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 @@
     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 @@
             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 @@
     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 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 @@
 #endif
 
     //qDebug("base service: %s", service);
+
+    // schedule a dispatch:
+    QMetaObject::invokeMethod(this, "doDispatch", Qt::QueuedConnection);
 }
 
 extern "C"{
@@ -1255,6 +1206,7 @@
     QDBusConnectionPrivate::messageResultReceived(pending, user_data);
 }
 }
+
 void QDBusConnectionPrivate::messageResultReceived(DBusPendingCall *pending, void *user_data)
 {
     QDBusPendingCall *call = reinterpret_cast<QDBusPendingCall *>(user_data);
@@ -1284,18 +1236,22 @@
     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 @@
         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 @@
         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 @@
 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 @@
 {
     // 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 @@
 {
     // 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: qdbusinterface.cpp
===================================================================
RCS file: /cvs/dbus/dbus/qt/qdbusinterface.cpp,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -d -r1.7 -r1.8
--- qdbusinterface.cpp	2 May 2006 14:00:27 -0000	1.7
+++ qdbusinterface.cpp	29 May 2006 18:17:09 -0000	1.8
@@ -58,19 +58,6 @@
 }
 
 /*!
-    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: qdbusinterface.h
===================================================================
RCS file: /cvs/dbus/dbus/qt/qdbusinterface.h,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- qdbusinterface.h	29 Apr 2006 12:44:31 -0000	1.5
+++ qdbusinterface.h	29 May 2006 18:17:09 -0000	1.6
@@ -35,7 +35,6 @@
     
 public:
     ~QDBusInterface();
-    bool isValid() const;
     
     virtual const QMetaObject *metaObject() const;
     virtual void *qt_metacast(const char *);
@@ -43,6 +42,7 @@
 
 private:
     Q_DECLARE_PRIVATE(QDBusInterface);
+    Q_DISABLE_COPY(QDBusInterface)
 };
 
 struct QDBUS_EXPORT QDBusInterfacePtr

Index: qdbusinternalfilters.cpp
===================================================================
RCS file: /cvs/dbus/dbus/qt/qdbusinternalfilters.cpp,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- qdbusinternalfilters.cpp	29 Apr 2006 12:44:31 -0000	1.5
+++ qdbusinternalfilters.cpp	29 May 2006 18:17:09 -0000	1.6
@@ -30,10 +30,15 @@
 
 #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 @@
     "    </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 @@
         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 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: qdbusmacros.h
===================================================================
RCS file: /cvs/dbus/dbus/qt/qdbusmacros.h,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- qdbusmacros.h	28 Mar 2006 18:56:08 -0000	1.5
+++ qdbusmacros.h	29 May 2006 18:17:09 -0000	1.6
@@ -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: qdbusmetaobject.cpp
===================================================================
RCS file: /cvs/dbus/dbus/qt/qdbusmetaobject.cpp,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -d -r1.2 -r1.3
--- qdbusmetaobject.cpp	23 Apr 2006 19:04:53 -0000	1.2
+++ qdbusmetaobject.cpp	29 May 2006 18:17:09 -0000	1.3
@@ -48,8 +48,8 @@
         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 @@
     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());

--- NEW FILE: qdbusmisc.cpp ---
/* qdbusmisc.cpp Miscellaneous routines that didn't fit anywhere else
 *
 * Copyright (C) 2006 Trolltech AS. All rights reserved.
 *    Author: Thiago Macieira <thiago.macieira at 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;
}

--- NEW FILE: qdbusxmlgenerator.cpp ---
/* -*- mode: C++ -*-
 *
 * Copyright (C) 2006 Trolltech AS. All rights reserved.
 *    Author: Thiago Macieira <thiago.macieira at 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);
}



More information about the dbus-commit mailing list