1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtDBus module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "qdbusabstractadaptor.h"
43 #include "qdbusabstractadaptor_p.h"
45 #include <QtCore/qcoreapplication.h>
46 #include <QtCore/qmetaobject.h>
47 #include <QtCore/qset.h>
48 #include <QtCore/qtimer.h>
49 #include <QtCore/qthread.h>
51 #include "qdbusconnection.h"
53 #include "qdbusconnection_p.h" // for qDBusParametersForMethod
54 #include "qdbusmetatype_p.h"
62 static int cachedRelaySlotMethodIndex = -1;
64 int QDBusAdaptorConnector::relaySlotMethodIndex()
66 if (cachedRelaySlotMethodIndex == -1) {
67 cachedRelaySlotMethodIndex = staticMetaObject.indexOfMethod("relaySlot()");
68 Q_ASSERT(cachedRelaySlotMethodIndex != -1);
70 return cachedRelaySlotMethodIndex;
73 QDBusAdaptorConnector *qDBusFindAdaptorConnector(QObject *obj)
77 const QObjectList &children = obj->children();
78 QObjectList::ConstIterator it = children.constBegin();
79 QObjectList::ConstIterator end = children.constEnd();
80 for ( ; it != end; ++it) {
81 QDBusAdaptorConnector *connector = qobject_cast<QDBusAdaptorConnector *>(*it);
90 QDBusAdaptorConnector *qDBusFindAdaptorConnector(QDBusAbstractAdaptor *adaptor)
92 return qDBusFindAdaptorConnector(adaptor->parent());
95 QDBusAdaptorConnector *qDBusCreateAdaptorConnector(QObject *obj)
97 QDBusAdaptorConnector *connector = qDBusFindAdaptorConnector(obj);
100 return new QDBusAdaptorConnector(obj);
103 QString QDBusAbstractAdaptorPrivate::retrieveIntrospectionXml(QDBusAbstractAdaptor *adaptor)
105 return adaptor->d_func()->xml;
108 void QDBusAbstractAdaptorPrivate::saveIntrospectionXml(QDBusAbstractAdaptor *adaptor,
111 adaptor->d_func()->xml = xml;
115 \class QDBusAbstractAdaptor
119 \brief The QDBusAbstractAdaptor class is the base class of D-Bus adaptor classes.
121 The QDBusAbstractAdaptor class is the starting point for all objects intending to provide
122 interfaces to the external world using D-Bus. This is accomplished by attaching a one or more
123 classes derived from QDBusAbstractAdaptor to a normal QObject and then registering that QObject
124 with QDBusConnection::registerObject. QDBusAbstractAdaptor objects are intended to be
125 light-weight wrappers, mostly just relaying calls into the real object (its parent) and the
128 Each QDBusAbstractAdaptor-derived class should define the D-Bus interface it is implementing
129 using the Q_CLASSINFO macro in the class definition. Note that only one interface can be
132 QDBusAbstractAdaptor uses the standard QObject mechanism of signals, slots and properties to
133 determine what signals, methods and properties to export to the bus. Any signal emitted by
134 QDBusAbstractAdaptor-derived classes will be automatically be relayed through any D-Bus
135 connections the object is registered on.
137 Classes derived from QDBusAbstractAdaptor must be created on the heap using the \a new operator
138 and must not be deleted by the user (they will be deleted automatically when the object they are
139 connected to is also deleted).
141 \sa {usingadaptors.html}{Using adaptors}, QDBusConnection
145 Constructs a QDBusAbstractAdaptor with \a obj as the parent object.
147 QDBusAbstractAdaptor::QDBusAbstractAdaptor(QObject* obj)
148 : QObject(*new QDBusAbstractAdaptorPrivate, obj)
150 QDBusAdaptorConnector *connector = qDBusCreateAdaptorConnector(obj);
152 connector->waitingForPolish = true;
153 QMetaObject::invokeMethod(connector, "polish", Qt::QueuedConnection);
157 Destroys the adaptor.
159 \warning Adaptors are destroyed automatically when the real object they refer to is
160 destroyed. Do not delete the adaptors yourself.
162 QDBusAbstractAdaptor::~QDBusAbstractAdaptor()
167 Toggles automatic signal relaying from the real object (see object()).
169 Automatic signal relaying consists of signal-to-signal connection of the signals on the parent
170 that have the exact same method signatue in both classes.
172 If \a enable is set to true, connect the signals; if set to false, disconnect all signals.
174 void QDBusAbstractAdaptor::setAutoRelaySignals(bool enable)
176 const QMetaObject *us = metaObject();
177 const QMetaObject *them = parent()->metaObject();
178 bool connected = false;
179 for (int idx = staticMetaObject.methodCount(); idx < us->methodCount(); ++idx) {
180 QMetaMethod mm = us->method(idx);
182 if (mm.methodType() != QMetaMethod::Signal)
185 // try to connect/disconnect to a signal on the parent that has the same method signature
186 QByteArray sig = QMetaObject::normalizedSignature(mm.methodSignature().constData());
187 if (them->indexOfSignal(sig) == -1)
189 sig.prepend(QSIGNAL_CODE + '0');
190 parent()->disconnect(sig, this, sig);
192 connected = connect(parent(), sig, sig) || connected;
194 d_func()->autoRelaySignals = connected;
198 Returns true if automatic signal relaying from the real object (see object()) is enabled,
199 otherwiser returns false.
201 \sa setAutoRelaySignals()
203 bool QDBusAbstractAdaptor::autoRelaySignals() const
205 return d_func()->autoRelaySignals;
208 QDBusAdaptorConnector::QDBusAdaptorConnector(QObject *obj)
209 : QObject(obj), waitingForPolish(false)
213 QDBusAdaptorConnector::~QDBusAdaptorConnector()
217 void QDBusAdaptorConnector::addAdaptor(QDBusAbstractAdaptor *adaptor)
219 // find the interface name
220 const QMetaObject *mo = adaptor->metaObject();
221 int ciid = mo->indexOfClassInfo(QCLASSINFO_DBUS_INTERFACE);
223 QMetaClassInfo mci = mo->classInfo(ciid);
225 // find out if this interface exists first
226 const char *interface = mci.value();
227 AdaptorMap::Iterator it = std::lower_bound(adaptors.begin(), adaptors.end(),
228 QByteArray(interface));
229 if (it != adaptors.end() && qstrcmp(interface, it->interface) == 0) {
230 // exists. Replace it (though it's probably the same)
231 if (it->adaptor != adaptor) {
232 // reconnect the signals
233 disconnectAllSignals(it->adaptor);
234 connectAllSignals(adaptor);
236 it->adaptor = adaptor;
240 entry.interface = interface;
241 entry.adaptor = adaptor;
244 // connect the adaptor's signals to our relaySlot slot
245 connectAllSignals(adaptor);
251 void QDBusAdaptorConnector::disconnectAllSignals(QObject *obj)
253 QMetaObject::disconnect(obj, -1, this, relaySlotMethodIndex());
256 void QDBusAdaptorConnector::connectAllSignals(QObject *obj)
258 QMetaObject::connect(obj, -1, this, relaySlotMethodIndex(), Qt::DirectConnection);
261 void QDBusAdaptorConnector::polish()
263 if (!waitingForPolish)
264 return; // avoid working multiple times if multiple adaptors were added
266 waitingForPolish = false;
267 const QObjectList &objs = parent()->children();
268 QObjectList::ConstIterator it = objs.constBegin();
269 QObjectList::ConstIterator end = objs.constEnd();
270 for ( ; it != end; ++it) {
271 QDBusAbstractAdaptor *adaptor = qobject_cast<QDBusAbstractAdaptor *>(*it);
276 // sort the adaptor list
280 void QDBusAdaptorConnector::relaySlot(void **argv)
282 relay(sender(), senderSignalIndex(), argv);
285 void QDBusAdaptorConnector::relay(QObject *senderObj, int lastSignalIdx, void **argv)
287 if (lastSignalIdx < QObject::staticMetaObject.methodCount())
288 // QObject signal (destroyed(QObject *)) -- ignore
291 const QMetaObject *senderMetaObject = senderObj->metaObject();
292 QMetaMethod mm = senderMetaObject->method(lastSignalIdx);
294 QObject *realObject = senderObj;
295 if (qobject_cast<QDBusAbstractAdaptor *>(senderObj))
296 // it's an adaptor, so the real object is in fact its parent
297 realObject = realObject->parent();
299 // break down the parameter list
301 int inputCount = qDBusParametersForMethod(mm, types);
302 if (inputCount == -1)
303 // invalid signal signature
304 // qDBusParametersForMethod has already complained
306 if (inputCount + 1 != types.count() ||
307 types.at(inputCount) == QDBusMetaTypeId::message) {
308 // invalid signal signature
309 // qDBusParametersForMethod has not yet complained about this one
310 qWarning("QDBusAbstractAdaptor: Cannot relay signal %s::%s",
311 senderMetaObject->className(), mm.methodSignature().constData());
316 for (int i = 1; i < types.count(); ++i)
317 args << QVariant(types.at(i), argv[i]);
319 // now emit the signal with all the information
320 emit relaySignal(realObject, senderMetaObject, lastSignalIdx, args);
324 // modify carefully: this has been hand-edited!
325 // the relaySlot slot gets called with the void** array
327 struct qt_meta_stringdata_QDBusAdaptorConnector_t {
328 QByteArrayData data[10];
331 #define QT_MOC_LITERAL(idx, ofs, len) \
332 Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, \
333 offsetof(qt_meta_stringdata_QDBusAdaptorConnector_t, stringdata) + ofs \
334 - idx * sizeof(QByteArrayData) \
336 static const qt_meta_stringdata_QDBusAdaptorConnector_t qt_meta_stringdata_QDBusAdaptorConnector = {
338 QT_MOC_LITERAL(0, 0, 21),
339 QT_MOC_LITERAL(1, 22, 11),
340 QT_MOC_LITERAL(2, 34, 0),
341 QT_MOC_LITERAL(3, 35, 3),
342 QT_MOC_LITERAL(4, 39, 18),
343 QT_MOC_LITERAL(5, 58, 10),
344 QT_MOC_LITERAL(6, 69, 3),
345 QT_MOC_LITERAL(7, 73, 4),
346 QT_MOC_LITERAL(8, 78, 9),
347 QT_MOC_LITERAL(9, 88, 6)
349 "QDBusAdaptorConnector\0relaySignal\0\0"
350 "obj\0const QMetaObject*\0metaObject\0sid\0"
351 "args\0relaySlot\0polish\0"
353 #undef QT_MOC_LITERAL
355 static const uint qt_meta_data_QDBusAdaptorConnector[] = {
364 0, 0, // constructors
368 // signals: name, argc, parameters, tag, flags
371 // slots: name, argc, parameters, tag, flags
375 // signals: parameters
376 QMetaType::Void, QMetaType::QObjectStar, 0x80000000 | 4, QMetaType::Int, QMetaType::QVariantList, 3, 5, 6, 7,
385 void QDBusAdaptorConnector::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
387 if (_c == QMetaObject::InvokeMetaMethod) {
388 Q_ASSERT(staticMetaObject.cast(_o));
389 QDBusAdaptorConnector *_t = static_cast<QDBusAdaptorConnector *>(_o);
391 case 0: _t->relaySignal((*reinterpret_cast< QObject*(*)>(_a[1])),(*reinterpret_cast< const QMetaObject*(*)>(_a[2])),(*reinterpret_cast< int(*)>(_a[3])),(*reinterpret_cast< const QVariantList(*)>(_a[4]))); break;
392 case 1: _t->relaySlot(_a); break; // HAND EDIT: add the _a parameter
393 case 2: _t->polish(); break;
399 const QMetaObject QDBusAdaptorConnector::staticMetaObject = {
400 { &QObject::staticMetaObject, qt_meta_stringdata_QDBusAdaptorConnector.data,
401 qt_meta_data_QDBusAdaptorConnector, qt_static_metacall, 0, 0 }
404 const QMetaObject *QDBusAdaptorConnector::metaObject() const
406 return &staticMetaObject;
409 void *QDBusAdaptorConnector::qt_metacast(const char *_clname)
411 if (!_clname) return 0;
412 if (!strcmp(_clname, qt_meta_stringdata_QDBusAdaptorConnector.stringdata))
413 return static_cast<void*>(const_cast< QDBusAdaptorConnector*>(this));
414 return QObject::qt_metacast(_clname);
417 int QDBusAdaptorConnector::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
419 _id = QObject::qt_metacall(_c, _id, _a);
422 if (_c == QMetaObject::InvokeMetaMethod) {
424 qt_static_metacall(this, _c, _id, _a);
431 void QDBusAdaptorConnector::relaySignal(QObject * _t1, const QMetaObject * _t2, int _t3, const QVariantList & _t4)
433 void *_a[] = { 0, const_cast<void*>(reinterpret_cast<const void*>(&_t1)), const_cast<void*>(reinterpret_cast<const void*>(&_t2)), const_cast<void*>(reinterpret_cast<const void*>(&_t3)), const_cast<void*>(reinterpret_cast<const void*>(&_t4)) };
434 QMetaObject::activate(this, &staticMetaObject, 0, _a);