diff options
Diffstat (limited to 'qt/qdbusabstractadaptor.cpp')
-rw-r--r-- | qt/qdbusabstractadaptor.cpp | 490 |
1 files changed, 8 insertions, 482 deletions
diff --git a/qt/qdbusabstractadaptor.cpp b/qt/qdbusabstractadaptor.cpp index 4d6217a..e2ab096 100644 --- a/qt/qdbusabstractadaptor.cpp +++ b/qt/qdbusabstractadaptor.cpp @@ -31,9 +31,6 @@ #include "qdbusconnection_p.h" // for qDBusParametersForMethod #include "qdbusabstractadaptor_p.h" -/*! - \internal -*/ struct QDBusAdaptorInit { QSignalSpyCallbackSet callbacks; @@ -91,477 +88,8 @@ void QDBusAbstractAdaptorPrivate::saveIntrospectionXml(QDBusAbstractAdaptor *ada } /*! - \page UsingAdaptors Using Adaptors - - Adaptors are special classes that are attached to any QObject-derived class and provide the - interface to the external world using D-Bus. Adaptors are intended to be light-weight classes - whose main purpose is to relay calls to and from the real object, possibly validating or - converting the input from the external world and, thus, protecting the real object. - - Unlike multiple inheritance, adaptors can be added at any time to any object (but not removed), - which allows for greater flexibility when exporting existing classes. Another advantage of - adaptors is to provide similar but not identical functionality in methods of the same name in - different interfaces, a case which can be quite common when adding a new version of a standard - interface to an object. - - In order to use an adaptor, one must create a class which inherits QDBusAbstractAdaptor. Since - that is a standard QObject-derived class, the Q_OBJECT macro must appear in the declaration and - the source file must be processed with the \link moc \endlink tool. The class must also contain - one or more Q_CLASSINFO entries with the "D-Bus Interface" name, declaring which interfaces it - is exporting. - - Any public slot in the class will be accessible through the bus over messages of the MethodCall - type. (See \link DeclaringSlots \endlink for more information). Signals in the class will be - automatically relayed over D-Bus. However, not all types are allowed signals or slots' parameter - lists: see \link AllowedParameters \endlink for more information. - - Also, any property declared with Q_PROPERTY will be automatically exposed over the Properties - interface on D-Bus. Since the QObject property system does not allow for non-readable - properties, it is not possible to declare write-only properties using adaptors. - - More information: - - \subpage DeclaringSlots - - \subpage DeclaringSignals - - \subpage AllowedParameters - - \subpage UsingAnnotations - - \subpage AdaptorExample - - \sa QDBusAbstractAdaptor -*/ - -/*! - \page AdaptorExample Example of an interface implemented with an adaptor - - A sample usage of QDBusAbstractAdaptor is as follows: - \code - class MainApplicationAdaptor: public QDBusAbstractAdaptor - { - Q_OBJECT - Q_CLASSINFO("D-Bus Interface", "com.example.DBus.MainApplication") - Q_CLASSINFO("D-Bus Interface", "org.kde.DBus.MainApplication") - Q_PROPERTY(QString caption READ caption WRITE setCaption) - Q_PROPERTY(QString organizationName READ organizationName) - Q_PROPERTY(QString organizationDomain READ organizationDomain) - - private: - MyApplication *app; - - public: - MyInterfaceAdaptor(MyApplication *application) - : QDBusAbstractAdaptor(application), app(application) - { - connect(application, SIGNAL(aboutToQuit()), SIGNAL(aboutToQuit()); - connect(application, SIGNAL(focusChanged(QWidget*, QWidget*)), - SLOT(focusChangedSlot(QWidget*, QWidget*))); - } - - QString caption() - { - if (app->hasMainWindow()) - return app->mainWindow()->caption(); - return QString(); - } - - void setCaption(const QString &newCaption) - { - if (app->hasMainWindow()) - app->mainWindow()->setCaption(newCaption); - } - - QString organizationName() - { - return app->organizationName(); - } - - QString organizationDomain() - { - return app->organizationDomain(); - } - - public slots: - async void quit() - { app->quit(); } - - void reparseConfiguration() - { app->reparseConfiguration(); } - - QString mainWindowObject() - { - if (app->hasMainWindow()) - return QString("/%1/mainwindow").arg(app->applicationName()); - return QString(); - } - - void setSessionManagement(bool enable) - { - if (enable) - app->enableSessionManagement(); - else - app->disableSessionManagement(); - } - - private slots: - void focusChangedSlot(QWidget *, QWidget *now) - { - if (now == app->mainWindow()) - emit mainWindowHasFocus(); - } - - signals: - void aboutToQuit(); - void mainWindowHasFocus(); - }; - \endcode - - The code above would create an interface that could be represented more or less in the following - canonical representation: - \code - interface com.example.DBus.MainApplication - { - property readwrite STRING caption - property read STRING organizationName - property read STRING organizationDomain - - method quit() annotation("org.freedesktop.DBus.Method.NoReply", "true") - method reparseConfiguration() - method mainWindowObject(out STRING) - method disableSessionManagement(in BOOLEAN enable) - - signal aboutToQuit() - signal mainWindowHasFocus() - } - - interface org.kde.DBus.MainApplication - { - .... - } - \endcode - - This adaptor could be used in the application's constructor as follows: - \code - MyApplication::MyApplication() - { - [...] - - // create the MainApplication adaptor: - new MainApplicationAdaptor(this); - - // connect to D-Bus: - QDBusConnection connection = QDBusConnection::addConnection(QDBusConnection::SessionBus); - - // register us as an object: - connection.registerObject("/MainApplication", this); - - [...] - } - \endcode - - Break-down analysis: - - \subpage AdaptorExampleHeader - - \subpage AdaptorExampleProperties - - \subpage AdaptorExampleConstructor - - \subpage AdaptorExampleSlots - - \subpage AdaptorExampleSignals -*/ - -/*! - \page AdaptorExampleHeader The header - - The header of the example is: - \code - class MainApplicationAdaptor: public QDBusAbstractAdaptor - { - Q_OBJECT - Q_CLASSINFO("D-Bus Interface", "com.example.DBus.MainApplication") - Q_CLASSINFO("D-Bus Interface", "org.kde.DBus.MainApplication") - \endcode - - The code does the following: - - it declares the adaptor MainApplicationAdaptor, which descends from QDBusAbstractAdaptor - - it declares the Qt Meta Object data using the #Q_OBJECT macro - - it declares the names of two D-Bus interfaces it implements. Those interfaces are equal in all - aspects. -*/ - -/*! - \page AdaptorExampleProperties The properties - - The properties are declared as follows: - \code - Q_PROPERTY(QString caption READ caption WRITE setCaption) - Q_PROPERTY(QString organizationName READ organizationName) - Q_PROPERTY(QString organizationDomain READ organizationDomain) - \endcode - - And are implemented as follows: - \code - QString caption() - { - if (app->hasMainWindow()) - return app->mainWindow()->caption(); - return QString(); - } - - void setCaption(const QString &newCaption) - { - if (app->hasMainWindow()) - app->mainWindow()->setCaption(newCaption); - } - - QString organizationName() - { - return app->organizationName(); - } - - QString organizationDomain() - { - return app->organizationDomain(); - } - \endcode - - The code declares three properties: one of them is a read-write property called "caption" of - string type. The other two are read-only, also of the string type. - - The properties organizationName and organizationDomain are simple relays of the app object's - organizationName and organizationDomain properties. However, the caption property requires - verifying if the application has a main window associated with it: if there isn't any, the - caption property is empty. Note how it is possible to access data defined in other objects - through the getter/setter functions. - */ - -/*! - \page AdaptorExampleConstructor The constructor - - The constructor: - \code - MyInterfaceAdaptor(MyApplication *application) - : QDBusAbstractAdaptor(application), app(application) - { - connect(application, SIGNAL(aboutToQuit()), SIGNAL(aboutToQuit()); - connect(application, SIGNAL(focusChanged(QWidget*, QWidget*)), - SLOT(focusChangedSlot(QWidget*, QWidget*))); - } - \endcode - - The constructor does the following: - - it initialises its base class (QDBusAbstractAdaptor) with the parent object it is related to. - - it stores the app pointer in a member variable. Note that it would be possible to access the - same object using the QDBusAbstractAdaptor::object() function, but it would be necessary to - use \a static_cast<> to properly access the methods in MyApplication that are not part of - QObject. - - it connects the application's signal \a aboutToQuit to its own signal \a aboutToQuit. - - it connects the application's signal \a focusChanged to a private slot to do some further - processing before emitting a D-Bus signal. - - Note that there is no destructor in the example. An eventual destructor could be used to emit - one last signal before the object is destroyed, for instance. -*/ - -/*! - \page AdaptorExampleSlots Slots/methods - - The public slots in the example (which will be exported as D-Bus methods) are the following: - \code - public slots: - async void quit() - { app->quit(); } - - void reparseConfiguration() - { app->reparseConfiguration(); } - - QString mainWindowObject() - { - if (app->hasMainWindow()) - return QString("/%1/mainwindow").arg(app->applicationName()); - return QString(); - } - - void setSessionManagement(bool enable) - { - if (enable) - app->enableSessionManagement(); - else - app->disableSessionManagement(); - } - \endcode - - This snippet of code defines 4 methods with different properties each: - - \p quit: this method takes no parameters and is defined to be asynchronous. That is, callers - are expected to use "fire-and-forget" mechanism when calling this method, since it provides no - useful reply. This is represented in D-Bus by the use of the - org.freedesktop.DBus.Method.NoReply annotation. See #Q_ASYNC for more information on - asynchronous methods - - - \p reparseConfiguration: this simple method, with no input or output arguments simply relays - the call to the application's reparseConfiguration member function. - - - \p mainWindowObject: this method takes no input parameter, but returns one string output - argument, containing the path to the main window object (if the application has a main - window), or an empty string if it has no main window. Note that this method could have also - been written: void mainWindowObject(QString &path). - - - \p setSessionManagement: this method takes one input argument (a boolean) and, depending on - its value, it calls one function or another in the application. - - \sa #Q_ASYNC -*/ - -/*! - \page AdaptorExampleSignals Signals - - The signals in this example are defined as follows: - \code - signals: - void aboutToQuit(); - void mainWindowHasFocus(); - \endcode - - However, signal definition isn't enough: signals have to be emitted. One simple way of emitting - signals is to connect another signal to them, so that Qt's signal handling system chains them - automatically. This is what is done for the \a aboutToQuit signal (see \ref - AdaptorExampleConstructor). - - When this is the case, one can use the QDBusAbstractAdaptor::setAutoRelaySignals to - automatically connect every signal from the real object to the adaptor. - - When simple signal-to-signal connection isn't enough, one can use a private slot do do some - work. This is what was done for the mainWindowHasFocus signal: - \code - private slots: - void focusChangedSlot(QWidget *, QWidget *now) - { - if (now == app->mainWindow()) - emit mainWindowHasFocus(); - } - \endcode - - This private slot (which will not be exported as a method via D-Bus) was connected to the - \a focusChanged signal in the adaptor's constructor. It is therefore able to shape the - application's signal into what the interface expects it to be. -*/ - -/*! - \page DeclaringSlots Declaring slots - - Slots in D-Bus adaptors are declared just like normal, public slots, but their parameters must - follow certain rules (see \ref AllowedParameters for more information). Slots whose parameters - do not follow those rules or that are not public will not be accessible via D-Bus. - - Slots can be of three kinds: - -# Asynchronous - -# Input-only - -# Input-and-output - - \par Asynchronous slots - Asynchronous slots are those that do not normally return any reply to the caller. For that - reason, they cannot take any output parameters. In most cases, by the time the first line - of the slot is run, the caller function has already resumed working. - - \par - However, slots must rely on that behavior. Scheduling and message-dispatching issues could - change the order in which the slot is run. Code intending to synchronize with the caller - should provide its own method of synchronization. - - \par - Asynchronous slots are marked by the keyword \p #async or \p #Q_ASYNC in the method - signature, before the \p void return type and the slot name. (See the \p quit slot in the - \ref AdaptorExample "adaptor example"). - - \par Input-only slots - Input-only slots are normal slots that take parameters passed by value or by constant - reference. However, unlike asynchronous slots, the caller is usually waiting for completion - of the callee before resuming operation. Therefore, non-asynchronous slots should not block - or should state it its documentation that they may do so. - - \par - Input-only slots have no special marking in their signature, except that they take only - parameters passed by value or by constant reference. Optionally, slots can take a - QDBusMessage parameter as a last parameter, which can be used to perform additional - analysis of the method call message. - - \par Input and output slots - Like input-only slots, input-and-output slots are those that the caller is waiting for a - reply. Unlike input-only ones, though, this reply will contain data. Slots that output data - may contain non-constant references and may return a value as well. However, the output - parameters must all appear at the end of the argument list and may not have input arguments - interleaved. Optionally, a QDBusMessage argument may appear between the input and the - output arguments. - - \note When a caller places a method call and waits for a reply, it will only wait for so long. - Slots intending to take a long time to complete should make that fact clear in - documentation so that callers properly set higher timeouts. - - Method replies are generated automatically with the contents of the output parameters (if there - were any) by the QtDBus implementation. Slots need not worry about constructing proper - QDBusMessage objects and sending them over the connection. - - However, the possibility of doing so remains there. Should the slot find out it needs to send a - special reply or even an error, it can do so by using QDBusMessage::methodReply or - QDBusMessage::error on the QDBusMessage parameter and send it with QDBusConnection::send. The - QtDBus implementation will not generate any reply if the slot did so. - - \sa \ref UsingAdaptors, \ref DeclaringSignals, \ref AllowedParameters, QDBusConnection, - QDBusMessage -*/ - -/*! - \page DeclaringSignals Declaring signals - - Any signal in a class derived from QDBusAbstractAdaptor will be automatically relayed into - D-Bus, provided that the signal's parameters conform to certain rules (see \ref - AllowedParameters for more information). No special code is necessary to make this relay. - - However, signals must still be emitted. The easiest way to emit an adaptor signal is to connect - another signal to it, so that the Qt signal/slot mechanism automatically emits the adaptor - signal too. This can be done in the adaptor's constructor, as has been done in the \ref - AdaptorExample "adaptor example". - - The convenience function QDBusAbstractAdaptor::setAutoRelaySignals can also be used to connect - or disconnect every signal in the real object to the same signal in the adaptor. It will inspect - the list of signals in both classes and connect those that have exact parameter match. - - \sa \ref UsingAdaptors, \ref DeclaringSlots, \ref AllowedParameters, QDBusAbstractAdaptor -*/ - -/*! - \page AllowedParameters Allowed parameter types - - D-Bus has a very limited set of types that can be sent and received over the bus. They are - listed below, along with the D-Bus type they relate to: - - unsigned char / uchar (BYTE) - - short (INT16) - - unsigned short / ushort (UINT16) - - int (INT32) - - unsigned int / uint (UINT32) - - qlonglong (INT64) - - qulonglong (UINT64) - - bool (BOOLEAN) - - double (DOUBLE) - - QString (STRING) - - QByteArray (ARRAY of BYTE) - - QStringList (ARRAY of STRING) - - QVariant / QDBusVariant (VARIANT) - - QVariantList (ARRAY of VARIANT) - - QVariantMap (ARRAY of DICT_ENTRY of (STRING, VARIANT)) - - The last two types may be used to receive any array (except string and byte arrays), any structs - and any maps. However, it is currently not possible to generate external function definitions - containing specific types of lists, structs and maps. - - All of the types above may be passed by value or by constant reference for input arguments to - slots as well as the output arguments to signals. When used as output arguments for slots, they - can all be used as non-constant references or the return type. - - Additionally, slots can have one parameter of type \p const \p QDBusMessage \p \&, which must - appear at the end of the input parameter list, before any output parameters. Signals cannot have - this parameter. - - \warning You may not use any type that is not on the list above, including \a typedefs to the - types listed. This also includes QList<QVariant> and QMap<QString,QVariant>. -*/ - -/*! - \page UsingAnnotations Using annotations in adaptors + \page usingannotations.html + \title Using annotations in adaptors It is currently not possible to specify arbitrary annotations in adaptors. */ @@ -589,14 +117,12 @@ void QDBusAbstractAdaptorPrivate::saveIntrospectionXml(QDBusAbstractAdaptor *ada and must not be deleted by the user (they will be deleted automatically when the object they are connected to is also deleted). - \sa \ref UsingAdaptors, QDBusConnection + \sa {usingadaptors.html}{Using adaptors}, QDBusConnection */ /*! Constructs a QDBusAbstractAdaptor with \a parent as the object we refer to. - \param parent the real object we're the adaptor for - \warning Use object() to retrieve the object passed as \a parent to this constructor. The real parent object (as retrieved by QObject::parent()) may be something else. */ @@ -636,12 +162,12 @@ QObject* QDBusAbstractAdaptor::object() const 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. - \param enable if set to true, connect the signals; if set to false, disconnect all signals + 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(); + const QMetaObject *them = object()->metaObject(); for (int idx = staticMetaObject.methodCount(); idx < us->methodCount(); ++idx) { QMetaMethod mm = us->method(idx); @@ -655,7 +181,7 @@ void QDBusAbstractAdaptor::setAutoRelaySignals(bool enable) sig.prepend(QSIGNAL_CODE + '0'); object()->disconnect(sig, this, sig); if (enable) - connect(object(), sig, sig, Qt::QueuedConnection); + connect(object(), sig, sig); } } @@ -752,8 +278,7 @@ void QDBusAdaptorConnector::relay(QObject *sender) // break down the parameter list QList<int> types; - QByteArray signature = QMetaObject::normalizedSignature(mm.signature()); - int inputCount = qDBusParametersForMethod(signature, types); + int inputCount = qDBusParametersForMethod(mm, types); if (inputCount == -1) // invalid signal signature // qDBusParametersForMethod has already complained @@ -766,6 +291,7 @@ void QDBusAdaptorConnector::relay(QObject *sender) return; } + QByteArray signature = QMetaObject::normalizedSignature(mm.signature()); signature.truncate(signature.indexOf('(')); // remove parameter decoration QVariantList args; |