Development/Tutorials/D-Bus/Accessing Interfaces: Difference between revisions

From KDE TechBase
Line 17: Line 17:
== Using QDBusMessage ==
== Using QDBusMessage ==


{{qt|QDBusMessage}} represents a D-BUS messages that can be sent or has been received over a given bus. It can be used directly to call methods in D-BUS services using the <tt>{{qt|QDbusMessage}}::createMethod( const QString & service, const QString & path, const QString & interface, const QString & method )</tt> static method. It returns a {{qt|QDBusMessage}} object that you can then use to make the call.
{{qt|QDBusMessage}} represents a D-BUS messages that can be sent or has been received over a given bus. Each message is one of four types, depending on the purpose of the message:
* method call
* signal
* reply
* error
* invalid
An enumeration covering each of these possibilities is defined in {{qt|QDBusMessage}}. A message's type can be access via the <tt>{{qt|QDBusMessage}}::type()</tt> method.
 
=== Calling a D-BUS Method ===
 
A {{qt|QDBusMessage}} can be used directly to call methods in D-BUS services using the <tt>{{qt|QDbusMessage}}::createMethod( const QString & service, const QString & path, const QString & interface, const QString & method )</tt> static method. It returns a {{qt|QDBusMessage}} object that you can then use to make the call.


The <tt>interface</tt> parameter is optional and only necessary if the method to be called is not unique in the accessed object address by the <tt>path</tt>. This can happen with the object implements multiple interfaces and those interfaces have methods with the same name. In such (rare) cases, if you do not  define the interface to use there is not guarantee as to which method will actually get called. However, usually you can simply pass an empty string (e.g. <tt>""</tt>) as the argument for <tt>interface</tt>.
The <tt>interface</tt> parameter is optional and only necessary if the method to be called is not unique in the accessed object address by the <tt>path</tt>. This can happen with the object implements multiple interfaces and those interfaces have methods with the same name. In such (rare) cases, if you do not  define the interface to use there is not guarantee as to which method will actually get called. However, usually you can simply pass an empty string (e.g. <tt>""</tt>) as the argument for <tt>interface</tt>.


By way of example, to access the (fictional) <tt>ping</tt> method on the {{path|/network}} object in the <tt>org.foo.bar</tt> service, one might do this:
By way of example, to access the (fictional) <tt>ping</tt> method on the {{path|/network}} object in the <tt>org.foo.bar</tt> service, one might do this:


<code cppqt n>QDBusMessage* m = QDBusMessage::createMessage("org.foo.bar",
<code cppqt n>QDBusMessage m = QDBusMessage::createMessage("org.foo.bar",
                                            "/network",
                                              "/network",
                                            "",
                                              "",
                                            "ping");
                                              "ping");
bool queued = QDBusConnection::sessionBus()->send(m);</code>
bool queued = QDBusConnection::sessionBus()->send(m);</code>


Line 38: Line 47:
=== Setting Parameters ===
=== Setting Parameters ===


Sending arguments along with the method call is quite straight forward. First we need to create a {{qt|QList}} of {{qt|QVariant}} objects and then add those to our dbus message. So if the <tt>ping</tt> method in the above took a hostname as a parameter, we might alter the code in this way:
Sending arguments along with the method call is quite straight forward. First we need to create a {{qt|QList}} of {{qt|QVariant}} objects and then add those to our dbus message. So if the <tt>ping</tt> method in the above took a hostname as a parameter, we might alter the code in this way (note lines 5 through 7):


<code cppqt n>QDBusMessage* m = QDBusMessage::createMessage("org.foo.bar",
<code cppqt n>QDBusMessage m = QDBusMessage::createMessage("org.foo.bar",
                                            "/network",
                                              "/network",
                                            "",
                                              "",
                                            "ping");
                                              "ping");
<b>QList<QVariant> args;
QList<QVariant> args;
args.append("kde.org");
args.append("kde.org");
m->setArguments(args);</b>
m.setArguments(args);
bool queued = QDBusConnection::sessionBus()->send(m);</code>
bool queued = QDBusConnection::sessionBus()->send(m);</code>


{{note|The arguments must appear in the {{qt|QList}} in the same order they are expected by the D-Bus method being called.}}
{{note|The arguments must appear in the {{qt|QList}} in the same order they are expected by the D-Bus method being called.}}
=== Getting Replies ===
If we wish to actually receive information back from the D-Bus method, we use the <tt>{{qt|QDBusConnect}}::call</tt> method instead. It will block until there is a reply or the call times out. If our <tt>ping</tt> method returned information on the host we provided in the arguments above, we might alter our code to look like this:
<code cppqt n>QDBusMessage m = QDBusMessage::createMessage("org.foo.bar",
                                              "/network",
                                              "",
                                              "ping");
QList<QVariant> args;
args.append("kde.org");
m.setArguments(args);
QDBusMessage response = QDBusConnection::sessionBus()->call(m);</code>
The <tt>response</tt> will be either of type <tt>QDBusMessage::ReplyMessage</tt> or <tt>QDBusMessage::ErrorMessage</tt> depending on whether it was successful or not. We can look through the values returned by retreving the arguments with the <tt>{{qt|QDBusMessage}}::arguments()</tt> method which returns a <tt>{{qt|QList}}&lt;{{qt|QVariant}}&gt;</tt>.
=== Is This The Best Way? ===
Using QDBusMessage directly in this way to invoke remote D-BUS methods is not the easiest, best or even recommend way of doing things. Next we will look at the more convnient {{qt|QDBusInterface}} class and then look at accessing remote D-Bus interfaces as if they were local methods using a class auto-generated from the XML D-Bus interface description.


== Using QDBusInterface ==
== Using QDBusInterface ==

Revision as of 03:25, 1 January 2007

Abstract

D-Bus allows applications to expose internal API to the outside world. These APIs can then be accessed at run-time via the D-Bus protocol using command line applications or D-Bus libraries and bindings themselves. This tutorial looks at the latter method with examples that you can use in your applications.

Prerequisites

Technologies:

  • Qt4
  • D-Bus


Tutorials:

D-Bus Interfaces

Using QDBusMessage

QDBusMessage represents a D-BUS messages that can be sent or has been received over a given bus. Each message is one of four types, depending on the purpose of the message:

  • method call
  • signal
  • reply
  • error
  • invalid

An enumeration covering each of these possibilities is defined in QDBusMessage. A message's type can be access via the QDBusMessage::type() method.

Calling a D-BUS Method

A QDBusMessage can be used directly to call methods in D-BUS services using the QDbusMessage::createMethod( const QString & service, const QString & path, const QString & interface, const QString & method ) static method. It returns a QDBusMessage object that you can then use to make the call.

The interface parameter is optional and only necessary if the method to be called is not unique in the accessed object address by the path. This can happen with the object implements multiple interfaces and those interfaces have methods with the same name. In such (rare) cases, if you do not define the interface to use there is not guarantee as to which method will actually get called. However, usually you can simply pass an empty string (e.g. "") as the argument for interface.

By way of example, to access the (fictional) ping method on the /network object in the org.foo.bar service, one might do this:

QDBusMessage m = QDBusMessage::createMessage("org.foo.bar",

                                             "/network",
                                             "",
                                             "ping");

bool queued = QDBusConnection::sessionBus()->send(m);

In line 5 of the above example we queue the message for sending on the current session bus. We get a bool returned letting us know if the queuing was successful or not.

This leaves us with two questions, however:

  • How can one set parameters for a method call?
  • How can one get a return message in the case of D-Bus methods that have a return value?

Setting Parameters

Sending arguments along with the method call is quite straight forward. First we need to create a QList of QVariant objects and then add those to our dbus message. So if the ping method in the above took a hostname as a parameter, we might alter the code in this way (note lines 5 through 7):

QDBusMessage m = QDBusMessage::createMessage("org.foo.bar",

                                             "/network",
                                             "",
                                             "ping");

QList<QVariant> args; args.append("kde.org"); m.setArguments(args); bool queued = QDBusConnection::sessionBus()->send(m);

Note
The arguments must appear in the QList in the same order they are expected by the D-Bus method being called.


Getting Replies

If we wish to actually receive information back from the D-Bus method, we use the QDBusConnect::call method instead. It will block until there is a reply or the call times out. If our ping method returned information on the host we provided in the arguments above, we might alter our code to look like this:


QDBusMessage m = QDBusMessage::createMessage("org.foo.bar",

                                              "/network",
                                              "",
                                              "ping");

QList<QVariant> args; args.append("kde.org"); m.setArguments(args); QDBusMessage response = QDBusConnection::sessionBus()->call(m);

The response will be either of type QDBusMessage::ReplyMessage or QDBusMessage::ErrorMessage depending on whether it was successful or not. We can look through the values returned by retreving the arguments with the QDBusMessage::arguments() method which returns a QList<QVariant>.

Is This The Best Way?

Using QDBusMessage directly in this way to invoke remote D-BUS methods is not the easiest, best or even recommend way of doing things. Next we will look at the more convnient QDBusInterface class and then look at accessing remote D-Bus interfaces as if they were local methods using a class auto-generated from the XML D-Bus interface description.

Using QDBusInterface

Using An Interface

Connecting To Signals

Other Resources