summaryrefslogtreecommitdiff
path: root/qt/qdbusabstractadaptor.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'qt/qdbusabstractadaptor.cpp')
-rw-r--r--qt/qdbusabstractadaptor.cpp490
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;