ce0cc498b9e095a91c4b804c26530a913037ce0c
[profile/ivi/qtbase.git] / src / dbus / qdbusabstractadaptor.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the QtDBus module of the Qt Toolkit.
7 **
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.
16 **
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.
20 **
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.
28 **
29 ** Other Usage
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.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qdbusabstractadaptor.h"
43
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>
49
50 #include "qdbusconnection.h"
51
52 #include "qdbusconnection_p.h"  // for qDBusParametersForMethod
53 #include "qdbusabstractadaptor_p.h"
54 #include "qdbusmetatype_p.h"
55
56 #include <algorithm>
57
58 #ifndef QT_NO_DBUS
59
60 QT_BEGIN_NAMESPACE
61
62 static int cachedRelaySlotMethodIndex = -1;
63
64 int QDBusAdaptorConnector::relaySlotMethodIndex()
65 {
66     if (cachedRelaySlotMethodIndex == -1) {
67         cachedRelaySlotMethodIndex = staticMetaObject.indexOfMethod("relaySlot()");
68         Q_ASSERT(cachedRelaySlotMethodIndex != -1);
69     }
70     return cachedRelaySlotMethodIndex;
71 }
72
73 QDBusAdaptorConnector *qDBusFindAdaptorConnector(QObject *obj)
74 {
75     if (!obj)
76         return 0;
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);
82         if (connector) {
83             connector->polish();
84             return connector;
85         }
86     }
87     return 0;
88 }
89
90 QDBusAdaptorConnector *qDBusFindAdaptorConnector(QDBusAbstractAdaptor *adaptor)
91 {
92     return qDBusFindAdaptorConnector(adaptor->parent());
93 }
94
95 QDBusAdaptorConnector *qDBusCreateAdaptorConnector(QObject *obj)
96 {
97     QDBusAdaptorConnector *connector = qDBusFindAdaptorConnector(obj);
98     if (connector)
99         return connector;
100     return new QDBusAdaptorConnector(obj);
101 }
102
103 QString QDBusAbstractAdaptorPrivate::retrieveIntrospectionXml(QDBusAbstractAdaptor *adaptor)
104 {
105     return adaptor->d_func()->xml;
106 }
107
108 void QDBusAbstractAdaptorPrivate::saveIntrospectionXml(QDBusAbstractAdaptor *adaptor,
109                                                        const QString &xml)
110 {
111     adaptor->d_func()->xml = xml;
112 }
113
114 /*!
115     \class QDBusAbstractAdaptor
116     \inmodule QtDBus
117     \since 4.2
118
119     \brief The QDBusAbstractAdaptor class is the base class of D-Bus adaptor classes.
120
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
126     signals from it.
127
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
130     exposed in this way.
131
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.
136
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).
140
141     \sa {usingadaptors.html}{Using adaptors}, QDBusConnection
142 */
143
144 /*!
145     Constructs a QDBusAbstractAdaptor with \a obj as the parent object.
146 */
147 QDBusAbstractAdaptor::QDBusAbstractAdaptor(QObject* obj)
148     : QObject(*new QDBusAbstractAdaptorPrivate, obj)
149 {
150     QDBusAdaptorConnector *connector = qDBusCreateAdaptorConnector(obj);
151
152     connector->waitingForPolish = true;
153     QMetaObject::invokeMethod(connector, "polish", Qt::QueuedConnection);
154 }
155
156 /*!
157     Destroys the adaptor.
158
159     \warning Adaptors are destroyed automatically when the real object they refer to is
160              destroyed. Do not delete the adaptors yourself.
161 */
162 QDBusAbstractAdaptor::~QDBusAbstractAdaptor()
163 {
164 }
165
166 /*!
167     Toggles automatic signal relaying from the real object (see object()).
168
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.
171
172     If \a enable is set to true, connect the signals; if set to false, disconnect all signals.
173 */
174 void QDBusAbstractAdaptor::setAutoRelaySignals(bool enable)
175 {
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);
181
182         if (mm.methodType() != QMetaMethod::Signal)
183             continue;
184
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)
188             continue;
189         sig.prepend(QSIGNAL_CODE + '0');
190         parent()->disconnect(sig, this, sig);
191         if (enable)
192             connected = connect(parent(), sig, sig) || connected;
193     }
194     d_func()->autoRelaySignals = connected;
195 }
196
197 /*!
198     Returns true if automatic signal relaying from the real object (see object()) is enabled,
199     otherwiser returns false.
200
201     \sa setAutoRelaySignals()
202 */
203 bool QDBusAbstractAdaptor::autoRelaySignals() const
204 {
205     return d_func()->autoRelaySignals;
206 }
207
208 QDBusAdaptorConnector::QDBusAdaptorConnector(QObject *obj)
209     : QObject(obj), waitingForPolish(false)
210 {
211 }
212
213 QDBusAdaptorConnector::~QDBusAdaptorConnector()
214 {
215 }
216
217 void QDBusAdaptorConnector::addAdaptor(QDBusAbstractAdaptor *adaptor)
218 {
219     // find the interface name
220     const QMetaObject *mo = adaptor->metaObject();
221     int ciid = mo->indexOfClassInfo(QCLASSINFO_DBUS_INTERFACE);
222     if (ciid != -1) {
223         QMetaClassInfo mci = mo->classInfo(ciid);
224         if (*mci.value()) {
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);
235                 }
236                 it->adaptor = adaptor;
237             } else {
238                 // create a new one
239                 AdaptorData entry;
240                 entry.interface = interface;
241                 entry.adaptor = adaptor;
242                 adaptors << entry;
243
244                 // connect the adaptor's signals to our relaySlot slot
245                 connectAllSignals(adaptor);
246             }
247         }
248     }
249 }
250
251 void QDBusAdaptorConnector::disconnectAllSignals(QObject *obj)
252 {
253     QMetaObject::disconnect(obj, -1, this, relaySlotMethodIndex());
254 }
255
256 void QDBusAdaptorConnector::connectAllSignals(QObject *obj)
257 {
258     QMetaObject::connect(obj, -1, this, relaySlotMethodIndex(), Qt::DirectConnection);
259 }
260
261 void QDBusAdaptorConnector::polish()
262 {
263     if (!waitingForPolish)
264         return;                 // avoid working multiple times if multiple adaptors were added
265
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);
272         if (adaptor)
273             addAdaptor(adaptor);
274     }
275
276     // sort the adaptor list
277     qSort(adaptors);
278 }
279
280 void QDBusAdaptorConnector::relaySlot(void **argv)
281 {
282     relay(sender(), senderSignalIndex(), argv);
283 }
284
285 void QDBusAdaptorConnector::relay(QObject *senderObj, int lastSignalIdx, void **argv)
286 {
287     if (lastSignalIdx < QObject::staticMetaObject.methodCount())
288         // QObject signal (destroyed(QObject *)) -- ignore
289         return;
290
291     const QMetaObject *senderMetaObject = senderObj->metaObject();
292     QMetaMethod mm = senderMetaObject->method(lastSignalIdx);
293
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();
298
299     // break down the parameter list
300     QVector<int> types;
301     int inputCount = qDBusParametersForMethod(mm, types);
302     if (inputCount == -1)
303         // invalid signal signature
304         // qDBusParametersForMethod has already complained
305         return;
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());
312         return;
313     }
314
315     QVariantList args;
316     for (int i = 1; i < types.count(); ++i)
317         args << QVariant(types.at(i), argv[i]);
318
319     // now emit the signal with all the information
320     emit relaySignal(realObject, senderMetaObject, lastSignalIdx, args);
321 }
322
323 // our Meta Object
324 // modify carefully: this has been hand-edited!
325 // the relaySlot slot gets called with the void** array
326
327 struct qt_meta_stringdata_QDBusAdaptorConnector_t {
328     QByteArrayData data[10];
329     char stringdata[96];
330 };
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) \
335     )
336 static const qt_meta_stringdata_QDBusAdaptorConnector_t qt_meta_stringdata_QDBusAdaptorConnector = {
337     {
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)
348     },
349     "QDBusAdaptorConnector\0relaySignal\0\0"
350     "obj\0const QMetaObject*\0metaObject\0sid\0"
351     "args\0relaySlot\0polish\0"
352 };
353 #undef QT_MOC_LITERAL
354
355 static const uint qt_meta_data_QDBusAdaptorConnector[] = {
356
357  // content:
358        7,       // revision
359        0,       // classname
360        0,    0, // classinfo
361        3,   14, // methods
362        0,    0, // properties
363        0,    0, // enums/sets
364        0,    0, // constructors
365        0,       // flags
366        1,       // signalCount
367
368  // signals: name, argc, parameters, tag, flags
369        1,    4,   29,    2, 0x05,
370
371  // slots: name, argc, parameters, tag, flags
372        8,    0,   38,    2, 0x0a,
373        9,    0,   39,    2, 0x0a,
374
375  // signals: parameters
376     QMetaType::Void, QMetaType::QObjectStar, 0x80000000 | 4, QMetaType::Int, QMetaType::QVariantList,    3,    5,    6,    7,
377
378  // slots: parameters
379     QMetaType::Void,
380     QMetaType::Void,
381
382        0        // eod
383 };
384
385 void QDBusAdaptorConnector::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
386 {
387     if (_c == QMetaObject::InvokeMetaMethod) {
388         Q_ASSERT(staticMetaObject.cast(_o));
389         QDBusAdaptorConnector *_t = static_cast<QDBusAdaptorConnector *>(_o);
390         switch (_id) {
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;
394         default: ;
395         }
396     }
397 }
398
399 const QMetaObject QDBusAdaptorConnector::staticMetaObject = {
400     { &QObject::staticMetaObject, qt_meta_stringdata_QDBusAdaptorConnector.data,
401       qt_meta_data_QDBusAdaptorConnector, qt_static_metacall, 0, 0 }
402 };
403
404 const QMetaObject *QDBusAdaptorConnector::metaObject() const
405 {
406     return &staticMetaObject;
407 }
408
409 void *QDBusAdaptorConnector::qt_metacast(const char *_clname)
410 {
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);
415 }
416
417 int QDBusAdaptorConnector::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
418 {
419     _id = QObject::qt_metacall(_c, _id, _a);
420     if (_id < 0)
421         return _id;
422     if (_c == QMetaObject::InvokeMetaMethod) {
423         if (_id < 3)
424             qt_static_metacall(this, _c, _id, _a);
425         _id -= 3;
426     }
427     return _id;
428 }
429
430 // SIGNAL 0
431 void QDBusAdaptorConnector::relaySignal(QObject * _t1, const QMetaObject * _t2, int _t3, const QVariantList & _t4)
432 {
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);
435 }
436
437 QT_END_NAMESPACE
438
439 #endif // QT_NO_DBUS