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"
44 #include <QtCore/qcoreapplication.h>
45 #include <QtCore/qmetaobject.h>
46 #include <QtCore/qset.h>
47 #include <QtCore/qtimer.h>
48 #include <QtCore/qthread.h>
50 #include "qdbusconnection.h"
52 #include "qdbusconnection_p.h" // for qDBusParametersForMethod
53 #include "qdbusabstractadaptor_p.h"
54 #include "qdbusmetatype_p.h"
60 static int cachedRelaySlotMethodIndex = -1;
62 int QDBusAdaptorConnector::relaySlotMethodIndex()
64 if (cachedRelaySlotMethodIndex == -1) {
65 cachedRelaySlotMethodIndex = staticMetaObject.indexOfMethod("relaySlot()");
66 Q_ASSERT(cachedRelaySlotMethodIndex != -1);
68 return cachedRelaySlotMethodIndex;
71 QDBusAdaptorConnector *qDBusFindAdaptorConnector(QObject *obj)
75 const QObjectList &children = obj->children();
76 QObjectList::ConstIterator it = children.constBegin();
77 QObjectList::ConstIterator end = children.constEnd();
78 for ( ; it != end; ++it) {
79 QDBusAdaptorConnector *connector = qobject_cast<QDBusAdaptorConnector *>(*it);
88 QDBusAdaptorConnector *qDBusFindAdaptorConnector(QDBusAbstractAdaptor *adaptor)
90 return qDBusFindAdaptorConnector(adaptor->parent());
93 QDBusAdaptorConnector *qDBusCreateAdaptorConnector(QObject *obj)
95 QDBusAdaptorConnector *connector = qDBusFindAdaptorConnector(obj);
98 return new QDBusAdaptorConnector(obj);
101 QString QDBusAbstractAdaptorPrivate::retrieveIntrospectionXml(QDBusAbstractAdaptor *adaptor)
103 return adaptor->d_func()->xml;
106 void QDBusAbstractAdaptorPrivate::saveIntrospectionXml(QDBusAbstractAdaptor *adaptor,
109 adaptor->d_func()->xml = xml;
113 \class QDBusAbstractAdaptor
117 \brief The QDBusAbstractAdaptor class is the base class of D-Bus adaptor classes.
119 The QDBusAbstractAdaptor class is the starting point for all objects intending to provide
120 interfaces to the external world using D-Bus. This is accomplished by attaching a one or more
121 classes derived from QDBusAbstractAdaptor to a normal QObject and then registering that QObject
122 with QDBusConnection::registerObject. QDBusAbstractAdaptor objects are intended to be
123 light-weight wrappers, mostly just relaying calls into the real object (its parent) and the
126 Each QDBusAbstractAdaptor-derived class should define the D-Bus interface it is implementing
127 using the Q_CLASSINFO macro in the class definition. Note that only one interface can be
130 QDBusAbstractAdaptor uses the standard QObject mechanism of signals, slots and properties to
131 determine what signals, methods and properties to export to the bus. Any signal emitted by
132 QDBusAbstractAdaptor-derived classes will be automatically be relayed through any D-Bus
133 connections the object is registered on.
135 Classes derived from QDBusAbstractAdaptor must be created on the heap using the \a new operator
136 and must not be deleted by the user (they will be deleted automatically when the object they are
137 connected to is also deleted).
139 \sa {usingadaptors.html}{Using adaptors}, QDBusConnection
143 Constructs a QDBusAbstractAdaptor with \a obj as the parent object.
145 QDBusAbstractAdaptor::QDBusAbstractAdaptor(QObject* obj)
146 : QObject(*new QDBusAbstractAdaptorPrivate, obj)
148 QDBusAdaptorConnector *connector = qDBusCreateAdaptorConnector(obj);
150 connector->waitingForPolish = true;
151 QMetaObject::invokeMethod(connector, "polish", Qt::QueuedConnection);
155 Destroys the adaptor.
157 \warning Adaptors are destroyed automatically when the real object they refer to is
158 destroyed. Do not delete the adaptors yourself.
160 QDBusAbstractAdaptor::~QDBusAbstractAdaptor()
165 Toggles automatic signal relaying from the real object (see object()).
167 Automatic signal relaying consists of signal-to-signal connection of the signals on the parent
168 that have the exact same method signatue in both classes.
170 If \a enable is set to true, connect the signals; if set to false, disconnect all signals.
172 void QDBusAbstractAdaptor::setAutoRelaySignals(bool enable)
174 const QMetaObject *us = metaObject();
175 const QMetaObject *them = parent()->metaObject();
176 bool connected = false;
177 for (int idx = staticMetaObject.methodCount(); idx < us->methodCount(); ++idx) {
178 QMetaMethod mm = us->method(idx);
180 if (mm.methodType() != QMetaMethod::Signal)
183 // try to connect/disconnect to a signal on the parent that has the same method signature
184 QByteArray sig = QMetaObject::normalizedSignature(mm.methodSignature().constData());
185 if (them->indexOfSignal(sig) == -1)
187 sig.prepend(QSIGNAL_CODE + '0');
188 parent()->disconnect(sig, this, sig);
190 connected = connect(parent(), sig, sig) || connected;
192 d_func()->autoRelaySignals = connected;
196 Returns true if automatic signal relaying from the real object (see object()) is enabled,
197 otherwiser returns false.
199 \sa setAutoRelaySignals()
201 bool QDBusAbstractAdaptor::autoRelaySignals() const
203 return d_func()->autoRelaySignals;
206 QDBusAdaptorConnector::QDBusAdaptorConnector(QObject *obj)
207 : QObject(obj), waitingForPolish(false)
211 QDBusAdaptorConnector::~QDBusAdaptorConnector()
215 void QDBusAdaptorConnector::addAdaptor(QDBusAbstractAdaptor *adaptor)
217 // find the interface name
218 const QMetaObject *mo = adaptor->metaObject();
219 int ciid = mo->indexOfClassInfo(QCLASSINFO_DBUS_INTERFACE);
221 QMetaClassInfo mci = mo->classInfo(ciid);
223 // find out if this interface exists first
224 const char *interface = mci.value();
225 AdaptorMap::Iterator it = qLowerBound(adaptors.begin(), adaptors.end(),
226 QByteArray(interface));
227 if (it != adaptors.end() && qstrcmp(interface, it->interface) == 0) {
228 // exists. Replace it (though it's probably the same)
229 if (it->adaptor != adaptor) {
230 // reconnect the signals
231 disconnectAllSignals(it->adaptor);
232 connectAllSignals(adaptor);
234 it->adaptor = adaptor;
238 entry.interface = interface;
239 entry.adaptor = adaptor;
242 // connect the adaptor's signals to our relaySlot slot
243 connectAllSignals(adaptor);
249 void QDBusAdaptorConnector::disconnectAllSignals(QObject *obj)
251 QMetaObject::disconnect(obj, -1, this, relaySlotMethodIndex());
254 void QDBusAdaptorConnector::connectAllSignals(QObject *obj)
256 QMetaObject::connect(obj, -1, this, relaySlotMethodIndex(), Qt::DirectConnection);
259 void QDBusAdaptorConnector::polish()
261 if (!waitingForPolish)
262 return; // avoid working multiple times if multiple adaptors were added
264 waitingForPolish = false;
265 const QObjectList &objs = parent()->children();
266 QObjectList::ConstIterator it = objs.constBegin();
267 QObjectList::ConstIterator end = objs.constEnd();
268 for ( ; it != end; ++it) {
269 QDBusAbstractAdaptor *adaptor = qobject_cast<QDBusAbstractAdaptor *>(*it);
274 // sort the adaptor list
278 void QDBusAdaptorConnector::relaySlot(void **argv)
280 QObjectPrivate *d = static_cast<QObjectPrivate *>(d_ptr.data());
281 relay(d->currentSender->sender, d->currentSender->signal, argv);
284 void QDBusAdaptorConnector::relay(QObject *senderObj, int lastSignalIdx, void **argv)
286 if (lastSignalIdx < QObject::staticMetaObject.methodCount())
287 // QObject signal (destroyed(QObject *)) -- ignore
290 const QMetaObject *senderMetaObject = senderObj->metaObject();
291 QMetaMethod mm = senderMetaObject->method(lastSignalIdx);
293 QObject *realObject = senderObj;
294 if (qobject_cast<QDBusAbstractAdaptor *>(senderObj))
295 // it's an adaptor, so the real object is in fact its parent
296 realObject = realObject->parent();
298 // break down the parameter list
300 int inputCount = qDBusParametersForMethod(mm, types);
301 if (inputCount == -1)
302 // invalid signal signature
303 // qDBusParametersForMethod has already complained
305 if (inputCount + 1 != types.count() ||
306 types.at(inputCount) == QDBusMetaTypeId::message) {
307 // invalid signal signature
308 // qDBusParametersForMethod has not yet complained about this one
309 qWarning("QDBusAbstractAdaptor: Cannot relay signal %s::%s",
310 senderMetaObject->className(), mm.methodSignature().constData());
315 for (int i = 1; i < types.count(); ++i)
316 args << QVariant(types.at(i), argv[i]);
318 // now emit the signal with all the information
319 emit relaySignal(realObject, senderMetaObject, lastSignalIdx, args);
323 // modify carefully: this has been hand-edited!
324 // the relaySlot slot gets called with the void** array
326 struct qt_meta_stringdata_QDBusAdaptorConnector_t {
327 QByteArrayData data[10];
330 #define QT_MOC_LITERAL(idx, ofs, len) \
331 Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, \
332 offsetof(qt_meta_stringdata_QDBusAdaptorConnector_t, stringdata) + ofs \
333 - idx * sizeof(QByteArrayData) \
335 static const qt_meta_stringdata_QDBusAdaptorConnector_t qt_meta_stringdata_QDBusAdaptorConnector = {
337 QT_MOC_LITERAL(0, 0, 21),
338 QT_MOC_LITERAL(1, 22, 11),
339 QT_MOC_LITERAL(2, 34, 0),
340 QT_MOC_LITERAL(3, 35, 3),
341 QT_MOC_LITERAL(4, 39, 18),
342 QT_MOC_LITERAL(5, 58, 10),
343 QT_MOC_LITERAL(6, 69, 3),
344 QT_MOC_LITERAL(7, 73, 4),
345 QT_MOC_LITERAL(8, 78, 9),
346 QT_MOC_LITERAL(9, 88, 6)
348 "QDBusAdaptorConnector\0relaySignal\0\0"
349 "obj\0const QMetaObject*\0metaObject\0sid\0"
350 "args\0relaySlot\0polish\0"
352 #undef QT_MOC_LITERAL
354 static const uint qt_meta_data_QDBusAdaptorConnector[] = {
363 0, 0, // constructors
367 // signals: name, argc, parameters, tag, flags
370 // slots: name, argc, parameters, tag, flags
374 // signals: parameters
375 QMetaType::Void, QMetaType::QObjectStar, 0x80000000 | 4, QMetaType::Int, QMetaType::QVariantList, 3, 5, 6, 7,
384 void QDBusAdaptorConnector::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
386 if (_c == QMetaObject::InvokeMetaMethod) {
387 Q_ASSERT(staticMetaObject.cast(_o));
388 QDBusAdaptorConnector *_t = static_cast<QDBusAdaptorConnector *>(_o);
390 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;
391 case 1: _t->relaySlot(_a); break; // HAND EDIT: add the _a parameter
392 case 2: _t->polish(); break;
398 const QMetaObject QDBusAdaptorConnector::staticMetaObject = {
399 { &QObject::staticMetaObject, qt_meta_stringdata_QDBusAdaptorConnector.data,
400 qt_meta_data_QDBusAdaptorConnector, qt_static_metacall, 0, 0 }
403 const QMetaObject *QDBusAdaptorConnector::metaObject() const
405 return &staticMetaObject;
408 void *QDBusAdaptorConnector::qt_metacast(const char *_clname)
410 if (!_clname) return 0;
411 if (!strcmp(_clname, qt_meta_stringdata_QDBusAdaptorConnector.stringdata))
412 return static_cast<void*>(const_cast< QDBusAdaptorConnector*>(this));
413 return QObject::qt_metacast(_clname);
416 int QDBusAdaptorConnector::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
418 _id = QObject::qt_metacall(_c, _id, _a);
421 if (_c == QMetaObject::InvokeMetaMethod) {
423 qt_static_metacall(this, _c, _id, _a);
430 void QDBusAdaptorConnector::relaySignal(QObject * _t1, const QMetaObject * _t2, int _t3, const QVariantList & _t4)
432 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)) };
433 QMetaObject::activate(this, &staticMetaObject, 0, _a);