summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThiago Macieira <thiago@kde.org>2006-05-29 18:17:09 +0000
committerThiago Macieira <thiago@kde.org>2006-05-29 18:17:09 +0000
commit26ab02e91671548e2b55a16bb953b3d9e0a82497 (patch)
tree6618b0255fc1fc8c6b56ec3e9e13e0eea7aecccb
parent5bc9dc5cf03d05feb62f0e28e2d5e04faf33610b (diff)
* 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.
-rw-r--r--ChangeLog7
-rw-r--r--qt/Makefile.am16
-rw-r--r--qt/dbuscpp2xml.cpp404
-rw-r--r--qt/dbusidl2cpp.cpp2
-rw-r--r--qt/qdbusabstractadaptor.cpp9
-rw-r--r--qt/qdbusabstractinterface.cpp13
-rw-r--r--qt/qdbusabstractinterface.h1
-rw-r--r--qt/qdbusconnection.cpp29
-rw-r--r--qt/qdbusconnection_p.h15
-rw-r--r--qt/qdbusintegrator.cpp353
-rw-r--r--qt/qdbusinterface.cpp13
-rw-r--r--qt/qdbusinterface.h2
-rw-r--r--qt/qdbusinternalfilters.cpp173
-rw-r--r--qt/qdbusmacros.h5
-rw-r--r--qt/qdbusmetaobject.cpp6
-rw-r--r--qt/qdbusmisc.cpp156
-rw-r--r--qt/qdbusxmlgenerator.cpp192
17 files changed, 968 insertions, 428 deletions
diff --git a/ChangeLog b/ChangeLog
index 83414418..d49cdc8f 100644
--- 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
diff --git a/qt/Makefile.am b/qt/Makefile.am
index 38cf1d71..c91c3422 100644
--- a/qt/Makefile.am
+++ b/qt/Makefile.am
@@ -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
index 00000000..e111f113
--- /dev/null
+++ b/qt/dbuscpp2xml.cpp
@@ -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);
+}
+
diff --git a/qt/dbusidl2cpp.cpp b/qt/dbusidl2cpp.cpp
index 8097a075..d329c18e 100644
--- a/qt/dbusidl2cpp.cpp
+++ b/qt/dbusidl2cpp.cpp
@@ -375,7 +375,7 @@ static QString stringify(const QString &data)
retval += "\\\"";
else
retval += data[i];
- retval += "\"\n";
+ retval += "\\n\"\n";
}
return retval;
}
diff --git a/qt/qdbusabstractadaptor.cpp b/qt/qdbusabstractadaptor.cpp
index 2794293d..b7c41888 100644
--- a/qt/qdbusabstractadaptor.cpp
+++ b/qt/qdbusabstractadaptor.cpp
@@ -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
diff --git a/qt/qdbusabstractinterface.cpp b/qt/qdbusabstractinterface.cpp
index 7c09b510..2a6bcf04 100644
--- a/qt/qdbusabstractinterface.cpp
+++ b/qt/qdbusabstractinterface.cpp
@@ -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
diff --git a/qt/qdbusabstractinterface.h b/qt/qdbusabstractinterface.h
index 1ad1a532..aa6d00d7 100644
--- a/qt/qdbusabstractinterface.h
+++ b/qt/qdbusabstractinterface.h
@@ -51,6 +51,7 @@ public:
public:
virtual ~QDBusAbstractInterface();
+ bool isValid() const;
QDBusConnection connection() const;
diff --git a/qt/qdbusconnection.cpp b/qt/qdbusconnection.cpp
index 52875a07..7bbde9ac 100644
--- a/qt/qdbusconnection.cpp
+++ b/qt/qdbusconnection.cpp
@@ -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;
}
diff --git a/qt/qdbusconnection_p.h b/qt/qdbusconnection_p.h
index af572084..a9034498 100644
--- a/qt/qdbusconnection_p.h
+++ b/qt/qdbusconnection_p.h
@@ -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);
diff --git a/qt/qdbusintegrator.cpp b/qt/qdbusintegrator.cpp
index dc038abb..190c4686 100644
--- a/qt/qdbusintegrator.cpp
+++ b/qt/qdbusintegrator.cpp
@@ -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) {
diff --git a/qt/qdbusinterface.cpp b/qt/qdbusinterface.cpp
index 0afa452b..6367654d 100644
--- a/qt/qdbusinterface.cpp
+++ b/qt/qdbusinterface.cpp
@@ -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.
*/
diff --git a/qt/qdbusinterface.h b/qt/qdbusinterface.h
index 2e16e5ce..716ca8ac 100644
--- a/qt/qdbusinterface.h
+++ b/qt/qdbusinterface.h
@@ -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
diff --git a/qt/qdbusinternalfilters.cpp b/qt/qdbusinternalfilters.cpp
index 3d454277..8886d3bf 100644
--- a/qt/qdbusinternalfilters.cpp
+++ b/qt/qdbusinternalfilters.cpp
@@ -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 @@ 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);
}
diff --git a/qt/qdbusmacros.h b/qt/qdbusmacros.h
index a0553275..5b3c7d30 100644
--- a/qt/qdbusmacros.h
+++ b/qt/qdbusmacros.h
@@ -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
diff --git a/qt/qdbusmetaobject.cpp b/qt/qdbusmetaobject.cpp
index 2992c703..a923d79a 100644
--- a/qt/qdbusmetaobject.cpp
+++ b/qt/qdbusmetaobject.cpp
@@ -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
index 00000000..9aaf9f24
--- /dev/null
+++ b/qt/qdbusmisc.cpp
@@ -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
index 00000000..561985ab
--- /dev/null
+++ b/qt/qdbusxmlgenerator.cpp
@@ -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);
+}