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