summaryrefslogtreecommitdiffstats
path: root/src/dbus/qdbusabstractadaptor.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/dbus/qdbusabstractadaptor.cpp')
-rw-r--r--src/dbus/qdbusabstractadaptor.cpp380
1 files changed, 380 insertions, 0 deletions
diff --git a/src/dbus/qdbusabstractadaptor.cpp b/src/dbus/qdbusabstractadaptor.cpp
new file mode 100644
index 0000000..883aabf
--- /dev/null
+++ b/src/dbus/qdbusabstractadaptor.cpp
@@ -0,0 +1,380 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtDBus module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdbusabstractadaptor.h"
+
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qmetaobject.h>
+#include <QtCore/qset.h>
+#include <QtCore/qtimer.h>
+#include <QtCore/qthread.h>
+
+#include "qdbusconnection.h"
+
+#include "qdbusconnection_p.h" // for qDBusParametersForMethod
+#include "qdbusabstractadaptor_p.h"
+#include "qdbusmetatype_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QDBusAdaptorConnector *qDBusFindAdaptorConnector(QObject *obj)
+{
+ if (!obj)
+ return 0;
+ const QObjectList &children = obj->children();
+ QObjectList::ConstIterator it = children.constBegin();
+ QObjectList::ConstIterator end = children.constEnd();
+ for ( ; it != end; ++it) {
+ QDBusAdaptorConnector *connector = qobject_cast<QDBusAdaptorConnector *>(*it);
+ if (connector) {
+ connector->polish();
+ return connector;
+ }
+ }
+ return 0;
+}
+
+QDBusAdaptorConnector *qDBusFindAdaptorConnector(QDBusAbstractAdaptor *adaptor)
+{
+ return qDBusFindAdaptorConnector(adaptor->parent());
+}
+
+QDBusAdaptorConnector *qDBusCreateAdaptorConnector(QObject *obj)
+{
+ QDBusAdaptorConnector *connector = qDBusFindAdaptorConnector(obj);
+ if (connector)
+ return connector;
+ return new QDBusAdaptorConnector(obj);
+}
+
+QString QDBusAbstractAdaptorPrivate::retrieveIntrospectionXml(QDBusAbstractAdaptor *adaptor)
+{
+ return adaptor->d_func()->xml;
+}
+
+void QDBusAbstractAdaptorPrivate::saveIntrospectionXml(QDBusAbstractAdaptor *adaptor,
+ const QString &xml)
+{
+ adaptor->d_func()->xml = xml;
+}
+
+/*!
+ \class QDBusAbstractAdaptor
+ \inmodule QtDBus
+ \since 4.2
+
+ \brief The QDBusAbstractAdaptor class is the base class of D-Bus adaptor classes.
+
+ The QDBusAbstractAdaptor class is the starting point for all objects intending to provide
+ interfaces to the external world using D-Bus. This is accomplished by attaching a one or more
+ classes derived from QDBusAbstractAdaptor to a normal QObject and then registering that QObject
+ with QDBusConnection::registerObject. QDBusAbstractAdaptor objects are intended to be
+ light-weight wrappers, mostly just relaying calls into the real object (its parent) and the
+ signals from it.
+
+ Each QDBusAbstractAdaptor-derived class should define the D-Bus interface it is implementing
+ using the Q_CLASSINFO macro in the class definition. Note that only one interface can be
+ exposed in this way.
+
+ QDBusAbstractAdaptor uses the standard QObject mechanism of signals, slots and properties to
+ determine what signals, methods and properties to export to the bus. Any signal emitted by
+ QDBusAbstractAdaptor-derived classes will be automatically be relayed through any D-Bus
+ connections the object is registered on.
+
+ Classes derived from QDBusAbstractAdaptor must be created on the heap using the \a new operator
+ and must not be deleted by the user (they will be deleted automatically when the object they are
+ connected to is also deleted).
+
+ \sa {usingadaptors.html}{Using adaptors}, QDBusConnection
+*/
+
+/*!
+ Constructs a QDBusAbstractAdaptor with \a obj as the parent object.
+*/
+QDBusAbstractAdaptor::QDBusAbstractAdaptor(QObject* obj)
+ : QObject(*new QDBusAbstractAdaptorPrivate, obj)
+{
+ QDBusAdaptorConnector *connector = qDBusCreateAdaptorConnector(obj);
+
+ connector->waitingForPolish = true;
+ QMetaObject::invokeMethod(connector, "polish", Qt::QueuedConnection);
+}
+
+/*!
+ Destroys the adaptor.
+
+ \warning Adaptors are destroyed automatically when the real object they refer to is
+ destroyed. Do not delete the adaptors yourself.
+*/
+QDBusAbstractAdaptor::~QDBusAbstractAdaptor()
+{
+}
+
+/*!
+ Toggles automatic signal relaying from the real object (see object()).
+
+ Automatic signal relaying consists of signal-to-signal connection of the signals on the parent
+ that have the exact same method signatue in both classes.
+
+ If \a enable is set to true, connect the signals; if set to false, disconnect all signals.
+*/
+void QDBusAbstractAdaptor::setAutoRelaySignals(bool enable)
+{
+ const QMetaObject *us = metaObject();
+ const QMetaObject *them = parent()->metaObject();
+ bool connected = false;
+ for (int idx = staticMetaObject.methodCount(); idx < us->methodCount(); ++idx) {
+ QMetaMethod mm = us->method(idx);
+
+ if (mm.methodType() != QMetaMethod::Signal)
+ continue;
+
+ // try to connect/disconnect to a signal on the parent that has the same method signature
+ QByteArray sig = QMetaObject::normalizedSignature(mm.signature());
+ if (them->indexOfSignal(sig) == -1)
+ continue;
+ sig.prepend(QSIGNAL_CODE + '0');
+ parent()->disconnect(sig, this, sig);
+ if (enable)
+ connected = connect(parent(), sig, sig) || connected;
+ }
+ d_func()->autoRelaySignals = connected;
+}
+
+/*!
+ Returns true if automatic signal relaying from the real object (see object()) is enabled,
+ otherwiser returns false.
+
+ \sa setAutoRelaySignals()
+*/
+bool QDBusAbstractAdaptor::autoRelaySignals() const
+{
+ return d_func()->autoRelaySignals;
+}
+
+QDBusAdaptorConnector::QDBusAdaptorConnector(QObject *obj)
+ : QObject(obj), waitingForPolish(false)
+{
+}
+
+QDBusAdaptorConnector::~QDBusAdaptorConnector()
+{
+}
+
+void QDBusAdaptorConnector::addAdaptor(QDBusAbstractAdaptor *adaptor)
+{
+ // find the interface name
+ const QMetaObject *mo = adaptor->metaObject();
+ int ciid = mo->indexOfClassInfo(QCLASSINFO_DBUS_INTERFACE);
+ if (ciid != -1) {
+ QMetaClassInfo mci = mo->classInfo(ciid);
+ if (*mci.value()) {
+ // find out if this interface exists first
+ const char *interface = mci.value();
+ AdaptorMap::Iterator it = qLowerBound(adaptors.begin(), adaptors.end(),
+ QByteArray(interface));
+ if (it != adaptors.end() && qstrcmp(interface, it->interface) == 0) {
+ // exists. Replace it (though it's probably the same)
+ if (it->adaptor != adaptor) {
+ // reconnect the signals
+ disconnectAllSignals(it->adaptor);
+ connectAllSignals(adaptor);
+ }
+ it->adaptor = adaptor;
+ } else {
+ // create a new one
+ AdaptorData entry;
+ entry.interface = interface;
+ entry.adaptor = adaptor;
+ adaptors << entry;
+
+ // connect the adaptor's signals to our relaySlot slot
+ connectAllSignals(adaptor);
+ }
+ }
+ }
+}
+
+void QDBusAdaptorConnector::disconnectAllSignals(QObject *obj)
+{
+ QMetaObject::disconnect(obj, -1, this, metaObject()->methodOffset());
+}
+
+void QDBusAdaptorConnector::connectAllSignals(QObject *obj)
+{
+ QMetaObject::connect(obj, -1, this, metaObject()->methodOffset(), Qt::DirectConnection);
+}
+
+void QDBusAdaptorConnector::polish()
+{
+ if (!waitingForPolish)
+ return; // avoid working multiple times if multiple adaptors were added
+
+ waitingForPolish = false;
+ const QObjectList &objs = parent()->children();
+ QObjectList::ConstIterator it = objs.constBegin();
+ QObjectList::ConstIterator end = objs.constEnd();
+ for ( ; it != end; ++it) {
+ QDBusAbstractAdaptor *adaptor = qobject_cast<QDBusAbstractAdaptor *>(*it);
+ if (adaptor)
+ addAdaptor(adaptor);
+ }
+
+ // sort the adaptor list
+ qSort(adaptors);
+}
+
+void QDBusAdaptorConnector::relaySlot(void **argv)
+{
+ QObjectPrivate *d = static_cast<QObjectPrivate *>(d_ptr);
+ relay(d->currentSender->sender, d->currentSender->signal, argv);
+}
+
+void QDBusAdaptorConnector::relay(QObject *senderObj, int lastSignalIdx, void **argv)
+{
+ if (lastSignalIdx < QObject::staticMetaObject.methodCount())
+ // QObject signal (destroyed(QObject *)) -- ignore
+ return;
+
+ const QMetaObject *senderMetaObject = senderObj->metaObject();
+ QMetaMethod mm = senderMetaObject->method(lastSignalIdx);
+
+ QObject *realObject = senderObj;
+ if (qobject_cast<QDBusAbstractAdaptor *>(senderObj))
+ // it's an adaptor, so the real object is in fact its parent
+ realObject = realObject->parent();
+
+ // break down the parameter list
+ QList<int> types;
+ int inputCount = qDBusParametersForMethod(mm, types);
+ if (inputCount == -1)
+ // invalid signal signature
+ // qDBusParametersForMethod has already complained
+ return;
+ if (inputCount + 1 != types.count() ||
+ types.at(inputCount) == QDBusMetaTypeId::message) {
+ // invalid signal signature
+ // qDBusParametersForMethod has not yet complained about this one
+ qWarning("QDBusAbstractAdaptor: Cannot relay signal %s::%s",
+ senderMetaObject->className(), mm.signature());
+ return;
+ }
+
+ QVariantList args;
+ for (int i = 1; i < types.count(); ++i)
+ args << QVariant(types.at(i), argv[i]);
+
+ // now emit the signal with all the information
+ emit relaySignal(realObject, senderMetaObject, lastSignalIdx, args);
+}
+
+// our Meta Object
+// modify carefully: this has been hand-edited!
+// the relaySlot slot has local ID 0 (we use this when calling QMetaObject::connect)
+// it also gets called with the void** array
+
+static const uint qt_meta_data_QDBusAdaptorConnector[] = {
+ // content:
+ 1, // revision
+ 0, // classname
+ 0, 0, // classinfo
+ 3, 10, // methods
+ 0, 0, // properties
+ 0, 0, // enums/sets
+
+ // slots: signature, parameters, type, tag, flags
+ 106, 22, 22, 22, 0x0a,
+ 118, 22, 22, 22, 0x0a,
+
+ // signals: signature, parameters, type, tag, flags
+ 47, 23, 22, 22, 0x05,
+
+ 0 // eod
+};
+
+static const char qt_meta_stringdata_QDBusAdaptorConnector[] = {
+ "QDBusAdaptorConnector\0\0obj,metaobject,sid,args\0"
+ "relaySignal(QObject*,const QMetaObject*,int,QVariantList)\0\0relaySlot()\0"
+ "polish()\0"
+};
+
+const QMetaObject QDBusAdaptorConnector::staticMetaObject = {
+ { &QObject::staticMetaObject, qt_meta_stringdata_QDBusAdaptorConnector,
+ qt_meta_data_QDBusAdaptorConnector, 0 }
+};
+
+const QMetaObject *QDBusAdaptorConnector::metaObject() const
+{
+ return &staticMetaObject;
+}
+
+void *QDBusAdaptorConnector::qt_metacast(const char *_clname)
+{
+ if (!_clname) return 0;
+ if (!strcmp(_clname, qt_meta_stringdata_QDBusAdaptorConnector))
+ return static_cast<void*>(const_cast<QDBusAdaptorConnector*>(this));
+ return QObject::qt_metacast(_clname);
+}
+
+int QDBusAdaptorConnector::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
+{
+ _id = QObject::qt_metacall(_c, _id, _a);
+ if (_id < 0)
+ return _id;
+ if (_c == QMetaObject::InvokeMetaMethod) {
+ switch (_id) {
+ case 0: relaySlot(_a); break; // HAND EDIT: add the _a parameter
+ case 1: polish(); break;
+ case 2: relaySignal((*reinterpret_cast< QObject*(*)>(_a[1])),(*reinterpret_cast< const QMetaObject*(*)>(_a[2])),(*reinterpret_cast< int(*)>(_a[3])),(*reinterpret_cast< const QVariantList(*)>(_a[4]))); break;
+ }
+ _id -= 3;
+ }
+ return _id;
+}
+
+// SIGNAL 0
+void QDBusAdaptorConnector::relaySignal(QObject * _t1, const QMetaObject * _t2, int _t3, const QVariantList & _t4)
+{
+ 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)) };
+ QMetaObject::activate(this, &staticMetaObject, 2, _a);
+}
+
+QT_END_NAMESPACE