3 * Copyright (C) 2006 Trolltech AS. All rights reserved.
4 * Author: Thiago Macieira <thiago.macieira@trolltech.com>
6 * Licensed under the Academic Free License version 2.1
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software Foundation
20 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
24 #include <QtCore/qcoreapplication.h>
25 #include <QtCore/qmetaobject.h>
26 #include <QtCore/qstringlist.h>
28 #include "qdbusinterface_p.h" // for ANNOTATION_NO_WAIT
29 #include "qdbusabstractadaptor_p.h" // for QCLASSINFO_DBUS_*
30 #include "qdbusconnection_p.h" // for the flags
31 #include "qdbusutil.h"
33 extern QDBUS_EXPORT QString qDBusGenerateMetaObjectXml(QString interface, const QMetaObject *mo,
34 const QMetaObject *base, int flags);
36 // implement the D-Bus org.freedesktop.DBus.Introspectable interface
37 // we do that by analysing the metaObject of all the adaptor interfaces
39 static QString generateInterfaceXml(const QMetaObject *mo, int flags, int methodOffset, int propOffset)
43 // start with properties:
44 if (flags & QDBusConnection::ExportProperties) {
45 for (int i = propOffset; i < mo->propertyCount(); ++i) {
46 static const char *accessvalues[] = {0, "read", "write", "readwrite"};
48 QMetaProperty mp = mo->property(i);
50 if (!mp.isScriptable() && (flags & QDBusConnection::ExportAllProperties) !=
51 QDBusConnection::ExportAllProperties)
60 int typeId = qDBusNameToTypeId(mp.typeName());
64 retval += QString(QLatin1String(" <property name=\"%1\" type=\"%2\" access=\"%3\" />\n"))
66 .arg(QLatin1String( QDBusUtil::typeToSignature( QVariant::Type(typeId) )))
67 .arg(QLatin1String( accessvalues[access] ));
72 for (int i = methodOffset; i < mo->methodCount(); ++i) {
73 QMetaMethod mm = mo->method(i);
74 QByteArray signature = mm.signature();
75 int paren = signature.indexOf('(');
78 if (mm.methodType() == QMetaMethod::Signal)
81 else if (mm.methodType() == QMetaMethod::Slot && mm.access() == QMetaMethod::Public)
84 continue; // neither signal nor public slot
86 if ((isSignal && !(flags & QDBusConnection::ExportSignals)) ||
87 (!isSignal && !(flags & QDBusConnection::ExportSlots)))
90 QString xml = QString(QLatin1String(" <%1 name=\"%2\">\n"))
91 .arg(isSignal ? QLatin1String("signal") : QLatin1String("method"))
92 .arg(QLatin1String(signature.left(paren)));
94 // check the return type first
95 int typeId = qDBusNameToTypeId(mm.typeName());
97 xml += QString(QLatin1String(" <arg type=\"%1\" direction=\"out\"/>\n"))
98 .arg(QLatin1String(QDBusUtil::typeToSignature( QVariant::Type(typeId) )));
99 else if (*mm.typeName())
100 continue; // wasn't a valid type
102 QList<QByteArray> names = mm.parameterNames();
104 int inputCount = qDBusParametersForMethod(mm, types);
105 if (inputCount == -1)
106 continue; // invalid form
107 if (isSignal && inputCount + 1 != types.count())
108 continue; // signal with output arguments?
109 if (isSignal && types.at(inputCount) == QDBusConnectionPrivate::messageMetaType)
110 continue; // signal with QDBusMessage argument?
113 bool isScriptable = mm.attributes() & QMetaMethod::Scriptable;
114 for (j = 1; j < types.count(); ++j) {
115 // input parameter for a slot or output for a signal
116 if (types.at(j) == QDBusConnectionPrivate::messageMetaType) {
122 if (!names.at(j - 1).isEmpty())
123 name = QString(QLatin1String("name=\"%1\" ")).arg(QLatin1String(names.at(j - 1)));
125 bool isOutput = isSignal || j > inputCount;
127 xml += QString(QLatin1String(" <arg %1type=\"%2\" direction=\"%3\"/>\n"))
129 .arg(QLatin1String(QDBusUtil::typeToSignature( QVariant::Type(types.at(j)) )))
130 .arg(isOutput ? QLatin1String("out") : QLatin1String("in"));
134 // check if this was added by other means
135 if (isSignal && (flags & QDBusConnection::ExportAllSignals) != QDBusConnection::ExportAllSignals)
137 if (!isSignal && (flags & QDBusConnection::ExportAllSlots) != QDBusConnection::ExportAllSlots)
141 if (qDBusCheckAsyncTag(mm.tag()))
142 // add the no-reply annotation
143 xml += QLatin1String(" <annotation name=\"" ANNOTATION_NO_WAIT "\""
144 " value=\"true\"/>\n");
147 retval += QString(QLatin1String(" </%1>\n"))
148 .arg(isSignal ? QLatin1String("signal") : QLatin1String("method"));
154 QString qDBusGenerateMetaObjectXml(QString interface, const QMetaObject *mo, const QMetaObject *base,
157 if (interface.isEmpty()) {
158 // generate the interface name from the meta object
159 int idx = mo->indexOfClassInfo(QCLASSINFO_DBUS_INTERFACE);
160 if (idx >= mo->classInfoOffset()) {
161 interface = QLatin1String(mo->classInfo(idx).value());
163 interface = QLatin1String(mo->className());
164 interface.replace(QLatin1String("::"), QLatin1String("."));
166 if (interface.startsWith( QLatin1String("QDBus") )) {
167 interface.prepend( QLatin1String("com.trolltech.QtDBus.") );
168 } else if (interface.startsWith( QLatin1Char('Q') )) {
170 interface.prepend( QLatin1String("com.trolltech.Qt.") );
171 } else if (!QCoreApplication::instance() ||
172 QCoreApplication::instance()->applicationName().isEmpty()) {
173 interface.prepend( QLatin1String("local.") );
175 interface.prepend(QLatin1Char('.')).prepend( QCoreApplication::instance()->applicationName() );
176 QStringList domainName = QCoreApplication::instance()->organizationDomain().split(QLatin1Char('.'));
177 foreach (const QString &part, domainName)
178 interface.prepend(QLatin1Char('.')).prepend(part);
184 int idx = mo->indexOfClassInfo(QCLASSINFO_DBUS_INTROSPECTION);
185 if (idx >= mo->classInfoOffset())
186 return QString::fromUtf8(mo->classInfo(idx).value());
188 xml = generateInterfaceXml(mo, flags, base->methodCount(), base->propertyCount());
191 return QString(); // don't add an empty interface
192 return QString(QLatin1String(" <interface name=\"%1\">\n%2 </interface>\n"))
193 .arg(interface, xml);