Once you have installed dbus-cxx, you are now ready to start using it! If you're unfamiliar with DBus in general, you should read https://rm5248.com/d-bus-tutorial/ first.
The first thing that you must do is to properly setup your build system in order to properly find and link with the dbus-cxx library. This varies depending on the buildsystem that you use, but here are some general directions.
When you build and install dbus-cxx, there are several pkg-config files that are provided. They are as follows:
.pc file | Used for |
---|---|
dbus-cxx-2.0.pc | Using the library directly. If you're not using a framework/library, this is what you want to use |
dbus-cxx-qt-2.0.pc | Integrating dbus-cxx with Qt. Depends on dbus-cxx-2.0.pc |
dbus-cxx-glib-2.0.pc | Integrating dbus-cxx with GLib. Depends on dbus-cxx-2.0.pc |
There are two ways to configure your CMake build to use dbus-cxx. The first way is to use the pkg-config files with the FindPkgConfig
module. To do this, simply add the following lines to your CMakeLists.txt:
If you want to use the find_package
directive of CMake, your CMakeLists.txt file should look something like the following:
Note that you need to use both pkg-config and the find_package
directive, because libsigc++ does not provide a CMake package at this point.
Because of Qt's signal/slot mechanism, dbus-cxx will not work directly with Qt. Assuming that you are using QMake, you will need to add the following lines to your .pro file:
Note that this will also allow you to use the Qt integration with dbus-cxx.
At any point in your Qt program, you need to use Qt signals or slots, use the macros Q_SIGNALS or Q_SLOTS to define your signals/slots.
If you are using autotools, modify configure.ac (or configure.in ) with the following lines:
You can then use the symbols PROJECT_DBUSCXX_LIBS
and PROJECT_DBUSCXX_CFLAGS
in your Makefile.am files. For example, if you have a application named fooapp your Makefile.am might look like this:
A dbus-cxx Object is a collection of methods and signals. A method is an operation that may be invoked on a object and may or may not return a value. A signal is emitted by the object and does not have a return value.
A dbus-cxx ObjectProxy provides an abstration of a remote Object to a client application. The ObjectProxy provides method and signal proxies that have signatures equivalent to their server-side counterparts.
A method proxy assembles the parameters of the method call into a D-Bus message and transmits to the server. The response (if any) is returned in the form of a D-Bus message which is then unpacked and returned to the application as the return value from the proxy call.
A signal proxy is different from a method proxy in that it watches an Object for signal events. These signal events arrive as a D-Bus signal message. When a signal event arrives the parameters are unpacked and emitted locally through the signal proxy callback.
dbus-cxx relies heavily on libsigc++'s signal and slot system for both Objects and their proxies.
On the server side and object's methods rely upon slots to provide the underlying functionality. When an incoming method call is invoked, the parameters of the call are unpacked and passed to the slot associated with the method.
Slots are similar to function pointers in C, but can also be a method of a specific class.
Let's say that we have a free function that we want to have called:
We would then connect this function using the sigc::ptr_fun()
method like so:
If we have a function on a class that we want to call instead, we use sigc::mem_fun
in order to connect this code to be called. Assuming something similar as above, our code may look something like the following:
DBus-cxx makes extensive use of smart pointers to help manage the memory of a class. In order for this scheme to work properly, most classes cannot be initialized on their own(constructors are private). To create an instance of a class, use the create()
method on that class:
This example will demonstrate a simple server and client pair.
The server will only offer one method named add that will take two double parameters and return the sum as a double.
The client will use a proxy object for the server as well as a proxy for the add method.
This section provides an example of a simple server. The server will run for 10 seconds and then automatically shut-down.
This is an overview of the code we will need in our example server:
add
to our objectHere is the code in full, followed by a section-by-section discussion.
First, we need to include the main dbus-cxx library header:
Then we will define a function that will be our workhorse on the server side. This function will be the actual function that will be called when the dbus add
method is invoked, so we will name our function similarly. But, note that the actual name of the function in our program and the name in our dbus server do not have to match.
And now for the beginning of our main()
function. We'll also declare a variable ret
that can be used to check the return value of functions.
Now, we will create a dispatcher to handle incoming and outgoing messages. Handling incoming and outgoing messages can be messy and the Dispatcher class handles much of this for us.
Since this is just a standalone example, we will use the standalone dispatcher
Now that we have a dispatcher we need to create a connection to the session bus.
Next, we need to request a name that will identify our application on the session bus.
Now that our application has a name on the bus we need to add an object with its path.
We will now create a method named add
for our object. The functionality of the method will be provided by the function we declared above also named add()
. We must add this to an interface, and the D-Bus specification required that interface names must contain at least one .
(period) character so we will use the interface name "dbuscxx.Quickstart"
.
Note that our DBus object method named add
has nothing to do with C++ class methods. In essence we are creating virtual objects on the D-Bus and can choose to provide their functionality with either C++ class methods and/or plain functions.
Finally, we need to wait for incoming calls. We will sleep for 10 seconds in our main()
function and the calls will be handled in the dispatcher's threads.
This section provides an example of a simple client for our simple server.
This is an overview of the code we will need in our example client:
quickstart_0
objectadd
method for our proxy objectHere is the code in full, followed by a section-by-section discussion.
First, we need to include the main dbus-cxx library header. We'll also include the iostream
header since we'll print out the results of our addition.
Now, we will create a dispatcher to handle incoming and outgoing messages. Handling incoming and outgoing messages can be messy and the Dispatcher class handles much of this for us. Because this is a standalone example, we will use a StandloneDispatcher to do all of this work for us.
Now that we have a dispatcher we need to create a connection to the session bus.
Note that unlike the server example, we do not request a name on the bus. This is because we do not need to have a well-known name on the bus in order to call methods on other objects.
You'll notice that up to this point the code for the client and the server has been very similar. This is the point at which they will diverge. We will now create a proxy object for the object on the server.
Note that we must use the name the server requested as well as the object path the server used when it created it's object when we create the proxy object.
Now we create a proxy add
method for the server object's add
method. This will allow us to use function notation to call the method. When creating the proxy method we must use the same interface ( "dbuscxx.Quickstart"
) and method name ( "add"
) as the server used.
Now we can use our proxy method to call the method on the server using function notation. We'll keep things simple and just add 1.1
+ 2.2
.
Finally, we can print out the results.
The following pages provide the quick-start for dbus-cxx: