Introduction to QtDBus class
from: http://doc.qt.io/qt-5/qtdbus-index.html
参考: http://blog.51cto.com/9291927/2118468
声明与链接
如使用qmake构建程序,需要在工程文件中增加下列代码来链接QtDBus库:
QT += qdbus
QtDBus类型系统
- Primitive Types
- Compound Types
- Extending the Type System
- The Type System in Use
QtDBus常用类
QDBusMessage
The QDBusMessage class represents one message sent or received over the D-Bus bus.
This object can represent any of the four different types of messages (MessageType) that can occur on the bus:
- MethodCallMessage
- SignalMessage
- ReplyMessage
- ErrorMessage
Objects of this type are created with the static createError(), createMethodCall() and createSignal() functions. Use the QDBusConnection::send() function to send the messages.
QDBusConnection
The QDBusConnection class represents a connection to the D-Bus bus daemon.
This class is the initial point in a D-Bus session. Using it, you can get access to remote objects, interfaces; connect remote signals to your object's slots; register objects, etc.
- D-Bus connections are created using the connectToBus() function, which opens a connection to the server daemon and does the initial handshaking, associating that connection with a name.
- The connection is then torn down using the disconnectFromBus() function.
- As a convenience for the two most common connection types, the sessionBus() and systemBus() functions return open connections to the session server daemon and the system server daemon, respectively.
- D-Bus also supports peer-to-peer connections, without the need for a bus server daemon. Using this facility, two applications can talk to each other and exchange messages. This can be achieved by passing an address to connectToBus() function, which was opened by another D-Bus application using QDBusServer.
- connectToPeer() & disconnectFromPeer()
- localMachineId(): Returns the local machine ID as known to the D-Bus system. Each node or host that runs D-Bus has a unique identifier that can be used to distinguish it from other hosts if they are sharing resources like the filesystem.
- call() & asyncCall()
- registerObject(): Registers the object object at path.
- registerService(): Attempts to register the serviceName on the D-Bus server.
QDBusConnectionInterface
The QDBusConnectionInterface class provides access to the D-Bus bus daemon service.
The D-Bus bus server daemon provides one special interface org.freedesktop. DBus that allows clients to access certain properties of the bus, such as the current list of clients connected. The QDBusConnectionInterface class provides access to that interface.
- register and unregister service names on the bus using the registerService() and unregisterService() functions
- query about existing names using the isServiceRegistered(), registeredServiceNames() and serviceOwner() functions
- receive notification that a client has registered or de-registered through the serviceRegistered(), serviceUnregistered() and serviceOwnerChanged() signals.
QDBusInterface
The QDBusInterface class is a proxy for interfaces on remote objects.
QDBusInterface is a generic accessor class that is used to place calls to remote objects, connect to signals exported by remote objects and get/set the value of remote properties. This class is useful for dynamic access to remote objects: that is, when you do not have a generated code that represents the remote interface.
- Calls are usually placed by using the call() function, which constructs the message, sends it over the bus, waits for the reply and decodes the reply. Signals are connected to by using the normal QObject::connect() function. Finally, properties are accessed using the QObject::property() and QObject::setProperty() functions.
QDBusInterface remoteApp( "com.example.Calculator", "/Calculator/Operations", "org.mathematics.RPNCalculator" ); remoteApp.call( "PushOperand", 2 ); remoteApp.call( "PushOperand", 2 ); remoteApp.call( "ExecuteOperation", "+" ); QDBusReply<int> reply = remoteApp.call( "PopOperand" ); if ( reply.isValid() ) printf( "%d", reply.value() ); // prints 4
QDBusAbstractInterface
The QDBusAbstractInterface class is the base class for all D-Bus interfaces in the Qt D-Bus binding, allowing access to remote interfaces.
Generated-code classes also derive from QDBusAbstractInterface, all methods described here are also valid for generated-code classes. In addition to those described here, generated-code classes provide member functions for the remote methods, which allow for compile-time checking of the correct parameters and return values, as well as property type-matching and signal parameter-matching.
- call (const QString &method, const QVariant &arg1 = QVariant() ... ) -> return QDBusMessage
- asyncCall (const QString &method, const QVariant &arg1 = QVariant() ... ) -> return QDBusPendingCall
QString value = retrieveValue(); QDBusMessage reply; QDBusReply<int> api = interface->call(QLatin1String("GetAPIVersion")); if (api >= 14) reply = interface->call(QLatin1String("ProcessWorkUnicode"), value); else reply = interface->call(QLatin1String("ProcessWork"), QLatin1String("UTF-8"), value.toUtf8());
QString value = retrieveValue(); QDBusPendingCall pcall = interface->asyncCall(QLatin1String("Process"), value); QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pcall, this); QObject::connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), this, SLOT(callFinishedSlot(QDBusPendingCallWatcher*)));
QDBusReply
The QDBusReply class stores the reply for a method call to a remote object.
A QDBusReply object is a subset of the QDBusMessage object that represents a method call's reply. It contains only the first output argument or the error code and is used by QDBusInterface-derived classes to allow returning the error code as the function's return argument.
QDBusReply objects are used for remote calls that have no output arguments or return values (i.e., they have a "void" return type). Use the isValid() function to test if the reply succeeded.
QDBusReply<QString> reply = interface->call("RemoteMethod"); if (reply.isValid()) // use the returned value useValue(reply.value()); else // call failed. Show an error condition. showError(reply.error());
If the remote method call cannot fail, you can skip the error checking:
QString reply = interface->call("RemoteMethod");
However, if it does fail under those conditions, the value returned by QDBusReply<T>::value() is a default-constructed value. It may be indistinguishable from a valid return value.
QDBusArgument
The QDBusArgument class is used to marshall and demarshall D-Bus arguments.
The class is used to send arguments over D-Bus to remote applications and to receive them back. D-Bus offers an extensible type system, based on a few primitive types and associations of them. See the Qt D-Bus Type System page for more information on the type system.
QDBusArgument is the central class in the Qt D-Bus type system, providing functions to marshall and demarshall the primitive types. The compound types are then created by association of one or more of the primitive types in arrays, dictionaries or structures.
struct MyStructure { int count; QString name; }; Q_DECLARE_METATYPE(MyStructure) // Marshall the MyStructure data into a D-Bus argument QDBusArgument &operator<<(QDBusArgument &argument, const MyStructure &mystruct) { argument.beginStructure(); argument << mystruct.count << mystruct.name; argument.endStructure(); return argument; } // Retrieve the MyStructure data from the D-Bus argument const QDBusArgument &operator>>(const QDBusArgument &argument, MyStructure &mystruct) { argument.beginStructure(); argument >> mystruct.count >> mystruct.name; argument.endStructure(); return argument; }
The type has to be registered with qDBusRegisterMetaType() before it can be used with QDBusArgument. Therefore, somewhere in your program, you should add the following code:
qDBusRegisterMetaType<MyStructure>();
Once registered, a type can be used in outgoing method calls (placed with QDBusAbstractInterface::call() ), signal emissions from registered objects or in incoming calls from remote applications.
It is important to note that the operator<< and operator>> streaming functions must always produce the same number of entries in case of structures, both in reading and in writing (marshalling and demarshalling), otherwise calls and signals may start to silently fail.
The following example illustrates this wrong usage in context of a class that may contain invalid data:
//bad code // Wrongly marshall the MyTime data into a D-Bus argument QDBusArgument &operator<<(QDBusArgument &argument, const MyTime &mytime) { argument.beginStructure(); if (mytime.isValid) argument << true << mytime.hour << mytime.minute << mytime.second; else argument << false; argument.endStructure(); return argument; }
In this example, both the operator<< and the operator>> functions may produce a different number of reads/writes. This can confuse the Qt D-Bus type system and should be avoided.
QDBusAbstractAdaptor
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 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).
QDBusPendingCall
The QDBusPendingCall class refers to one pending asynchronous call.
In most programs, the QDBusPendingCall class will not be used directly. It can be safely replaced with the template-based QDBusPendingReply, in order to access the contents of the reply or wait for it to be complete.
The QDBusPendingCallWatcher class allows one to connect to a signal that will indicate when the reply has arrived or if the call has timed out. It also provides the QDBusPendingCallWatcher::waitForFinished() method which will suspend the execution of the program until the reply has arrived.
Note: If you create a copy of a QDBusPendingCall object, all information will be shared among the many copies. Therefore, QDBusPendingCall is an explicitly-shared object and does not provide a method of detaching the copies (since they refer to the same pending call)
QDBusPendingReply
The QDBusPendingReply class contains the reply to an asynchronous method call.
The QDBusPendingReply is a template class with up to 8 template parameters. Those parameters are the types that will be used to extract the contents of the reply's data.
This class is similar in functionality to QDBusReply, but with two important differences:
- QDBusReply accepts exactly one return type, whereas QDBusPendingReply can have from 1 to 8 types
- QDBusReply only works on already completed replies, whereas QDBusPendingReply allows one to wait for replies from pending calls
QDBusPendingReply<QString> reply = interface->asyncCall("RemoteMethod"); reply.waitForFinished(); if (reply.isError()) // call failed. Show an error condition. showError(reply.error()); else // use the returned value useValue(reply.value());
For method calls that have more than one output argument:
QDBusPendingReply<bool, QString> reply = interface->asyncCall("RemoteMethod"); reply.waitForFinished(); if (!reply.isError()) { if (reply.argumentAt<0>()) showSuccess(reply.argumentAt<1>()); else showFailure(reply.argumentAt<1>()); }
QDBusPendingCallWatcher
The QDBusPendingCallWatcher class provides a convenient way for waiting for asynchronous replies.
The QDBusPendingCallWatcher provides the finished() signal that will be emitted when a reply arrives.
It is usually used like the following example:
QDBusPendingCall async = iface->asyncCall("RemoteMethod", value1, value2); QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(async, this); QObject::connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), this, SLOT(callFinishedSlot(QDBusPendingCallWatcher*)));
Note that it is not necessary to keep the original QDBusPendingCall object around since QDBusPendingCallWatcher inherits from that class too.
The slot connected to by the above code could be something similar to the following:
void MyClass::callFinishedSlot(QDBusPendingCallWatcher *call) { QDBusPendingReply<QString, QByteArray> reply = *call; if (reply.isError()) { showError(); } else { QString text = reply.argumentAt<0>(); QByteArray data = reply.argumentAt<1>(); showReply(text, data); } call->deleteLater(); }
Note the use of QDBusPendingReply to validate the argument types in the reply. If the reply did not contain exactly two arguments (one string and one QByteArray), QDBusPendingReply::isError() will return true.
QDBusServer
The QDBusServer class provides peer-to-peer communication between processes on the same computer.
QDBusServiceWatcher
The QDBusServiceWatcher class allows the user to watch for a bus service change.
A QDBusServiceWatcher object can be used to notify the application about an ownership change of a service name on the bus. It has three watch modes:
- Watching for service registration only.
- Watching for service unregistration only.
- Watching for any kind of service ownership change (the default mode).
Besides being created or deleted, services may change owners without a unregister/register operation happening. So the serviceRegistered() and serviceUnregistered() signals may not be emitted if that happens.
This class is more efficient than using the QDBusConnectionInterface::serviceOwnerChanged() signal because it allows one to receive only the signals for which the class is interested in.
QDBusVariant
The QDBusVariant class enables the programmer to identify the variant type provided by the D-Bus typesystem.
Qt D-Bus XML compiler (qdbusxml2cpp)
The Qt D-Bus XML compiler is a tool that can be used to parse interface descriptions and produce static code representing those interfaces, which can then be used to make calls to remote objects or implement said interfaces.
qdbusxml2cpp
has two modes of operation, that correspond to the two possible outputs it can produce: the interface (proxy) class or the adaptor class. The latter consists of both a C++ header and a source file, which are meant to be edited and adapted to your needs.
The qdbusxml2cpp
tool is not meant to be run every time you compile your application. Instead, it's meant to be used when developing the code or when the interface changes.
The adaptor classes generated by qdbusxml2cpp
are just a skeleton that must be completed. It generates, by default, calls to slots with the same name on the object the adaptor is attached to. However, you may modify those slots or the property accessor functions to suit your needs.