Documentation/Maemo 5 Developer Guide/DBus/DBus Basics

(D-Bus)
(Programming Directly with libdbus: reformat image)
 
(19 intermediate revisions not shown)
Line 1: Line 1:
-
= D-Bus =
+
For interprocess communications (IPC), [[Maemo]] relies heavily on [http://www.freedesktop.org/wiki/Software/dbus D-Bus]. D-Bus makes it possible for programs to export their programming interfaces, so that other processes can call them in a consistent manner, without having to define a custom IPC protocol. Using these exported APIs is also language agnostic, which means that as long as a programming language supports D-Bus, it can also access the interfaces.
-
For interprocess communications (IPC), Maemo relies heavily on D-Bus. D-Bus makes it possible for programs to export their programming interfaces, so that other processes can call them in a consistent manner, without having to define a custom IPC protocol. Using these exported APIs is also language agnostic, which means that as long as a programming language supports D-Bus, it can also access the interfaces.
+
A Maemo-specific library called [[../../Application Development/LibOSSO library|libOSSO]] provides helpful wrappers for D-Bus communication. It also contains the required functionality for every Maemo application, and applications must be initialized using the library. With the library, applications can connect to listen to system hardware state messages, for example the "battery low" message. The library is also used for application state-saving and the auto-save functionality. Section [[../../Application Development/LibOSSO library|LibOSSO Library]] of the chapter [[../../Application Development|Application Development]] of [[Documentation/Maemo 5 Developer Guide|Maemo Reference Manual]] provides a good introduction to libOSSO.
-
 
+
-
A Maemo-specific library called ''libOSSO'' provides helpful wrappers for D-BUS communication. It also contains the required functionality for every Maemo application, and applications must be initialized using the library. With the library, applications can connect to listen to system hardware state messages, for example the "battery low" message. The library is also used for application state-saving and the auto-save functionality. Section ''LibOSSO Library'' [/node7.html#sec:libosso_library 6.18.2] of the chapter ''Application Development'' of Maemo Reference Manual provides a good introduction to libOSSO.
+
== Introduction ==
== Introduction ==
-
D-Bus (the D originally stood for "Desktop") is a relatively new interprocess communication (IPC) mechanism designed to be used as a unified middleware layer in free desktop environments. Example projects where D-Bus is used are GNOME and Hildon. Compared to other middleware layers for IPC, D-Bus lacks many of the more refined (and complicated) features, which makes it faster and simpler.
+
D-Bus (the D originally stood for "Desktop") is an interprocess communication (IPC) mechanism designed to be used as a unified middleware layer in free desktop environments. Example projects where D-Bus is used are [http://www.gnome.org/ GNOME] and [[Hildon]]. Compared to other middleware layers for IPC, D-Bus lacks many of the more refined (and complicated) features, which makes it faster and simpler.
D-Bus does not directly compete with low-level IPC mechanisms, such as sockets, shared memory or message queues. Each of these mechanisms have their uses, which normally do not overlap the ones in D-Bus. Instead, D-Bus aims to provide higher level functionality, for example:
D-Bus does not directly compete with low-level IPC mechanisms, such as sockets, shared memory or message queues. Each of these mechanisms have their uses, which normally do not overlap the ones in D-Bus. Instead, D-Bus aims to provide higher level functionality, for example:
Line 27: Line 25:
== D-Bus Architecture and Terminology ==
== D-Bus Architecture and Terminology ==
-
In D-Bus, the ''bus'' is a central concept. It is the channel through which applications can make the method calls, send signals and listen to signals. Two pre-defined buses exist: the ''session bus'' and the ''system bus''.
+
In D-Bus, the ''bus'' is a central concept. Applications can make the method calls, send signals and listen to signals through the bus. Two pre-defined buses exist: the ''session bus'' and the ''system bus''.
-
* The session bus is meant for communication between applications that are connected to the same desktop session, and normally started and run by one user (using the same user identifier, or UID).
+
* The session bus is intended for communication between applications that are connected to the same desktop session, and normally started and run by one user (using the same user identifier, or UID).
-
* The system bus is meant for communication when applications (or services), running with disparate sessions, wish to communicate with each other. The most common use for this bus is sending system-wide notifications, when system-wide events occur. Adding of a new storage device, network connectivity change events and shutdown-related events are all examples of when system bus would be the more suitable bus for communication.
+
* The system bus is intended for communication when applications (or services), running with separate sessions, wish to communicate with each other. The most common use for this bus is sending system-wide notifications when system-wide events occur. The adding of a new storage device, network connectivity change events and shutdown-related events are all examples of system-wide events for which the system bus must be used.
-
In addition to the single system bus will exist, a system may a separate session bus for each desktop session. Because all user applications in a Maemo compatible device run with the same user ID, the device only has one session bus as well.
+
In addition to the single system bus, a separate session bus for each desktop session can exist. Because all user applications in a Maemo-compatible device run with the same user ID, the device only has one session bus as well.
-
A bus exists in the system in the form of a ''bus daemon'', a process that specializes in passing messages from one process to another. The daemon will also forward notifications to all applications on the bus. At the lowest level, D-Bus only supports point-to-point communication, normally using the local domain sockets (AF_UNIX) between the application and the bus daemon. The point-to-point aspect of D-Bus is however abstracted by the bus daemon, which will implement addressing and message passing functionality, so that applications do not need to care about which specific process will receive each method call or notification.
+
A bus exists in the system in the form of a ''bus daemon'', a process that specializes in passing messages from one process to another. The daemon also forwards notifications to all applications on the bus. At the lowest level, D-Bus only supports point-to-point communication, normally using the local domain sockets (<code>AF_UNIX</code>) between the application and the bus daemon. The point-to-point aspect of D-Bus is, however, abstracted by the bus daemon, which implements the addressing and message passing functionality. This means that applications do not need to care about which specific process receives each method call or notification.
-
The above means that sending a message using D-Bus will always involve the following steps (under normal conditions):
+
According to the above-mentioned details, sending a message using D-Bus always involves the following steps (under normal conditions):
-
* Creation and sending of the message to the bus daemon. This will cause at minimum two context switches.
+
* Creating and sending the message to the bus daemon. This causes a minimum of two context switches.
-
* Processing of the message by the bus daemon and forwarding it to the target process. This will again cause at minimum two context switches.
+
* The bus daemon processing the message and forwarding it to the target process. Again, this causes a minimum of two context switches.
-
* The target application will receive the message. Depending on the message type, it will either need to acknowledge it, respond with a reply or ignore it. The last case is only possible with notifications (i.e., ''signals'' in D-Bus terminology). An acknowledgment or reply will cause further context switches.
+
* The target application receiving the message. Depending on the message type, the target application needs to acknowledge the message, respond to the message with a reply or ignore it. The last case is only possible with notifications (''signals'' in D-Bus terminology). An acknowledgment or reply causes further context switches.
-
Coupled together, the above rules mean that if planning to transfer large amounts of data between processes, D-Bus will not be the most efficient way to do it. The most efficient way would be using some kind of shared memory arrangement. However, it is often quite complex to implement correctly.
+
Coupled together, the above rules mean that if transferring large amounts of data between processes is planned, using D-Bus is not the most efficient way to do it. Instead, using a shared memory arrangement is recommended, although such arrangements are often quite complex to implement correctly.
-
== Addressing and Names in D-Bus ==
+
== Addressing and Names in D-Bus ==
-
In order for the messages to reach the intended recipient, the IPC mechanism needs to support some form of addressing. The addressing scheme in D-Bus has been designed to be flexible, but at the same time efficient. Each bus has its private name space, which is not directly related to any other bus.
+
The IPC mechanism needs to support some form of addressing so that the messages reach the intended recipient. The addressing scheme in D-Bus has been designed to be flexible yet efficient. Each bus has its private name space, which is not directly related to any other bus.
-
In order to send a message, a destination address is needed. It is formed in a hierarchical manner from the following elements:
+
A destination address is needed for sending messages. The address is formed in a hierarchical manner from the following elements:
-
* The bus on which the message is to be sent. A bus is normally opened only once per application lifetime. The bus connection will then be used for sending and receiving messages for as long as necessary. This way, the target bus will form a transparent part of the message address (i.e., it is not specified separately for each message sent).
+
* The bus on which the message is to be sent. A bus is normally opened only once per application lifetime. The bus connection is then used for sending and receiving messages for as long as necessary. This way, the target bus forms a transparent part of the message address (it is not specified separately for each message sent).
-
* The ''well-known name'' for the service provided by the recipient. A close analogy to this would be the DNS system in Internet, where people normally use names to connect to services, instead of specific IP addresses providing the services. The idea in D-Bus well-known names is very similar, since the same service might be implemented in different ways in different applications. It should be noted, however, that currently most of the existing D-Bus services are "unique" in that each of them provides their own well-known name, and replacing one implementation with another is not common.
+
* The ''well-known name'' for the service provided by the recipient. A close analogy to this is the DNS system in Internet, where people normally use names to connect to services, instead of specific IP addresses providing the services. The idea of the D-Bus well-known names is very similar, because the same service can be implemented in different ways in different applications. It should be noted, however, that currently most of the existing D-Bus services are "unique" in that each of them provides their own well-known name, and replacing one implementation with another is not common.
** A well-known name consists of characters A-Z (lower or uppercase), dot characters, dashes and underscores. A well-known name must contain at least two dot-separated elements. Unlike DNS, the dots do not carry any additional information about management (zones), meaning that the well-known names are NOT hierarchical.
** A well-known name consists of characters A-Z (lower or uppercase), dot characters, dashes and underscores. A well-known name must contain at least two dot-separated elements. Unlike DNS, the dots do not carry any additional information about management (zones), meaning that the well-known names are NOT hierarchical.
-
** In order to reduce clashes in the D-Bus name space, it is recommended that the name is formed by reversing the order of labels of a DNS domain that you own. A similar approach is used in Java for package names.
+
** In order to reduce clashes in the D-Bus name space, the recommendation is that the name is formed by reversing the order of labels of a DNS domain that you own. A similar approach is used in Java for package names.
-
** Examples: org.maemo.Alert and org.freedesktop.Notifications.
+
** Examples: <code>org.maemo.Alert</code> and <code>org.freedesktop.Notifications</code>.
-
* Each service can contain multiple different objects, each of which provides a different (or same) service. In order to separate one object from another, ''object paths'' are used. A PIM information store, for example, might include separate objects to manage the contact information and synchronization.
+
* Each service can contain multiple different objects, each of which provides a different (or the same) service. In order to separate one object from another, ''object paths'' are used. A personal information manager (PIM) information store, for example, might include separate objects to manage the contact information and synchronization.
-
** Object paths look like file paths (elements separated with the character '/').
+
** Object paths look like file paths (elements separated with the '<code>/</code>' character).
-
** In D-Bus, it is also possible to make a "lazy binding", so that a specific function in the recipient will be called on all remote method calls, irrespective of object paths in the calls. This allows on-demand targeting of method calls, so that a user might remove a specific object in an address book service (using an object path similar to /org/maemo/AddressBook/Contacts/ShortName). Due to the limitations in characters that can be put into the object path, this is not recommended. A better way would be to supply the ShortName as a method call argument instead (as a UTF-8 formatted string).
+
** In D-Bus, "lazy binding" can also be made, so that a specific function in the recipient is called on all remote method calls, irrespective of the object paths in the calls. This allows the on-demand targeting of method calls, so that the user can remove a specific object in an address book service (using an object path similar to <code>/org/maemo/AddressBook/Contacts/ShortName</code>). Due to the limitations on characters that can be put into the object path, this is not recommended. A better way is to supply the ShortName as a method call argument instead (as a UTF-8 formatted string).
-
** It is common to form the object path using the same elements as in the well-known name, but replacing the dots with slashes, and appending a specific object name to the end. For example: /org/maemo/Alert/Alerter. It is a convention, but also solves a specific problem, when a process might re-use an existing D-Bus connection without explicitly knowing about it (using a library that encapsulates D-Bus functionality). Using short names here would increase the risk of name-space collisions within that process.
+
** The object path is usually formed using the same elements as in the well-known name, but replacing the dots with slashes, and appending a specific object name to the end. For example: <code>/org/maemo/Alert/Alerter</code>. This is the common convention, but it also solves a specific problem if a process could re-use an existing D-Bus connection without explicitly knowing about it (using a library that encapsulates D-Bus functionality). In such cases, using short names increases the risk of name-space collisions within that process.
-
** Similar to well-known names, object paths do not have inherent hierarchy, even if the path separator is used. The only place where some hierarchy might be seen because of path components is the introspection interface (which is out of the scope of this material).
+
** Object paths do not have inherent hierarchy, even if the path separator is used. The only place where some hierarchy can be seen because of the path components is the introspection interface (which is out of the scope of this material).
-
* In order to support object-oriented mapping, where objects are the units providing the service, D-Bus also implements a naming unit called the ''interface''. The interface specifies the legal (i.e. defined and implemented) method calls, their parameters (called ''arguments'' in D-Bus) and possible signals. It is then possible to re-use the same interface across multiple separate objects implementing the same service, or more commonly, a single object can implement multiple different services. An example of the latter is the implementation of the org.freedesktop.DBus.Introspectable interface, which defines the method necessary to support D-Bus introspection (more about this later on). When using the GLib/D-Bus wrappers to generate parts of the D-Bus code, the objects will automatically also support the introspection interface.
+
* In order to support object-oriented mapping, where objects are the units providing the service, D-Bus also implements a naming unit called ''interface''. The interface specifies the legal (defined and implemented) method calls, their parameters (called ''arguments'' in D-Bus) and possible signals. Thus, re-using the same interface across multiple separate objects implementing the same service is possible. More commonly, a single object can implement multiple different services. An example of the latter is the implementation of the <code>org.freedesktop.DBus.Introspectable</code> interface, which defines the method necessary to support D-Bus introspection. When using the GLib/D-Bus wrappers to generate parts of the D-Bus code, the objects support automatically also the introspection interface.
-
** Interface names use the same naming rules as well-known names. This might seem somewhat confusing at start, since well-known names serve a completely different purpose, but with time, one will get used to it.
+
** Interface names use the same naming rules as the well-known names. This can seem somewhat confusing in the beginning, because the well-known names serve a completely different purpose.
-
** For simple services, it is common to repeat the well-known name in the interface name. This is the most common scenario with existing services.
+
** For simple services, the well-known name is often repeated in the interface name. This is the most common scenario with the existing services.
-
* The last part of the message address is the member name. When dealing with remote procedure calls, this is also sometimes called ''method name'', and when dealing with signals, ''signal name''. The member name selects the procedure to call, or the signal to emit. It needs to be unique only within the interface that an object will implement.
+
* The last part of the message address is the member name. When dealing with remote procedure calls, the member name can sometimes be called ''method name'', and when dealing with signals, it can be called ''signal name''. The member name selects the procedure to call or the signal to emit. The name needs to be unique only within the interface that an object implements.
-
** Member names can have letters, digits and underscores in them. For example: RetrieveQuote.
+
** Member names can have letters, digits and underscores in them. For example, RetrieveQuote.
-
* For a more in-depth review on these, please see the [http://www.freedesktop.org/wiki/IntroductionToDBus Introduction]to D-Bus page.
+
* For more information, see the [http://www.freedesktop.org/wiki/IntroductionToDBus Introduction to D-Bus] page.
-
That about covers the most important rules in D-Bus addresses that one is likely to encounter. Below is an example of all four components that will also be used shortly to send a simple message (a method call) in the SDK:
+
Examples of all four components that are used for sending a simple message (a method call) in the [[Documentation/Maemo 5 Final SDK|SDK]] can be found below:
-
<tt><span>'''<span><font color="#000080"><nowiki>#define</nowiki></font></span>'''</span> SYSNOTE_NAME  <span><font color="#FF0000">"org.freedesktop.Notifications"</font></span>
+
<source lang="c">
-
<span>'''<span><font color="#000080"><nowiki>#define</nowiki></font></span>'''</span> SYSNOTE_OPATH <span><font color="#FF0000">"/org/freedesktop/Notifications"</font></span>
+
#define SYSNOTE_NAME  "org.freedesktop.Notifications"
-
<span>'''<span><font color="#000080"><nowiki>#define</nowiki></font></span>'''</span> SYSNOTE_IFACE <span><font color="#FF0000">"org.freedesktop.Notifications"</font></span>
+
#define SYSNOTE_OPATH "/org/freedesktop/Notifications"
-
<span>'''<span><font color="#000080"><nowiki>#define</nowiki></font></span>'''</span> SYSNOTE_NOTE  <span><font color="#FF0000">"SystemNoteDialog"</font></span></tt>
+
#define SYSNOTE_IFACE "org.freedesktop.Notifications"
 +
#define SYSNOTE_NOTE  "SystemNoteDialog"
 +
</source>
-
Even if switching to use the LibOSSO RPC functions (which encapsulate a lot of the D-Bus machinery), operations will still be performed with all of the D-Bus naming components.
+
When switching to the LibOSSO RPC functions (which encapsulate a lot of the D-Bus machinery), operations are still performed with all of the D-Bus naming components.
-
== Role of D-Bus in Maemo ==
+
== Role of D-Bus in Maemo ==
-
D-Bus has been selected as de facto IPC mechanism in maemo, to carry messages between the various software components. The main reason for this is that a lot of software developed for the GNOME environment is already exposing its functionality through D-Bus. Using a generic interface, which is not bound to any specific service, makes it also easier to deal with different software license requirements.
+
D-Bus has been selected as de facto IPC mechanism in Maemo, to carry messages between the various software components. The main reason for this is that a lot of software developed for the GNOME environment is already exposing its functionality through D-Bus. Using a generic interface, which is not bound to any specific service, makes it easier to deal with different software license requirements.
-
The SDK unfortunately does not come with a lot of software that is exposed via D-Bus, but this document will be using one component of the application framework as demonstration (it works also in the SDK).
+
Unfortunately, the SDK is not delivered with many of the software products that are exposed via D-Bus. This document uses one component of the application framework for demonstration purposes (it also works in the SDK).
-
An item of particular interest is asking the notification framework component to display a Note dialog. The dialog is modal, which means that users cannot proceed in their graphical environment, unless they first acknowledge the dialog. Normally such GUI decisions should be avoided, but later in this document it will be discussed why and when this feature can be useful. N.B. The SystemNoteDialog member is an extension to the draft org.freedesktop.Notifications specification, and as such, is not documented in that draft.
+
An item of particular interest is asking the notification framework component to display a Note dialog. The dialog is modal, which means that the user cannot proceed in their graphical environment unless they first acknowledge the dialog. Normally this kind of behavior in the GUI should be avoided, but a modal dialog can also be useful in certain circumstances.
-
The notification server is listening for method calls on the .freedesktop.Notifications well-known name. The object that implements the necessary interface is located at /org/freedesktop/Notifications object path. The method to display the note dialog is called SystemNoteDialog, and is defined in the org.freedesktop.Notifications D-Bus interface.
+
The SystemNoteDialog member is an extension to the draft org.freedesktop.Notifications specification, and as such, it is not documented in the draft document.
-
D-Bus comes with a handy tool to experiment with method calls and signals: dbus-send. The following snippet will attempt to use it to display the dialog:
+
The notification server is listening for method calls on the <code>.freedesktop.Notifications</code> well-known name. The object that implements the necessary interface is located at the <code>/org/freedesktop/Notifications</code> object path. The method to display the note dialog is called <code>SystemNoteDialog</code> and it is defined in the <code>org.freedesktop.Notifications</code> D-Bus interface.
-
<div class="graybox">
+
D-Bus comes with a handy tool to experiment with method calls and signals: <code>dbus-send</code>. The following snippet attempts to use it to display the dialog:
-
  [sbox-DIABLO_X86: ~] &gt; run-standalone.sh dbus-send --print-reply  \
+
 
-
  --type=method_call --dest=org.freedesktop.Notifications  \
+
<pre>
-
  /org/freedesktop/Notifications org.freedesktop.Notifications
+
[sbox-DIABLO_X86: ~] > run-standalone.sh dbus-send --print-reply  \
 +
--type=method_call --dest=org.freedesktop.Notifications  \
 +
/org/freedesktop/Notifications org.freedesktop.Notifications
  Error org.freedesktop.DBus.Error.UnknownMethod: Method "Notifications" with
  Error org.freedesktop.DBus.Error.UnknownMethod: Method "Notifications" with
-
  signature "" on interface "org.freedesktop" doesn't exist
+
signature "" on interface "org.freedesktop" does not exist
-
</div>
+
</pre>
-
 
+
Parameters for dbus-send:
Parameters for dbus-send:
-
* <code>--session</code><nowiki>: (implicit since default) which bus to use for sending (the other option being system) </nowiki>
+
* <code>--session</code>: (implicit because it is the default) which bus to use for sending (the other option being system)
-
* <code>--print-reply</code><nowiki>: ask the tool to wait for a reply to the method call, and print out the results (if any) </nowiki>
+
* <code>--print-reply</code>: ask the tool to wait for a reply to the method call, and print out the results (if any)
-
* <code>--type=method_call</code><nowiki>: instead of sending a signal (which is the default), make a method call </nowiki>
+
* <code>--type=method_call</code>: instead of sending a signal (which is the default), make a method call
-
* <code>--dest=org.freedesktop.Notifications</code><nowiki>: the well-known name for the target service </nowiki>
+
* <code>--dest=org.freedesktop.Notifications</code>: the well-known name for the target service
-
* <code>/org/freedesktop/Notifications</code><nowiki>: object path within the target process that implements the interface </nowiki>
+
* <code>/org/freedesktop/Notifications</code>: object path within the target process that implements the interface
-
* <code>org.freedesktop.Notifications</code><nowiki>: (incorrectly specified) interface name defining the method </nowiki>
+
* <code>org.freedesktop.Notifications</code>: (incorrectly specified) interface name defining the method
-
When using dbus-send, extra care needs to be taken, when specifying the interface and member names. The tool expects both of them to be combined into one parameter (without spaces in between). Thus, the command line needs to be modified a bit before a new try:
+
When using <code>dbus-send</code>, specify the interface and member names carefully. The tool expects both of them to be combined into one parameter (without spaces in between). Thus, modify the command line before a new try in the following way:
-
<div class="graybox">
+
<pre>
-
  [sbox-DIABLO_X86: ~] &gt; run-standalone.sh dbus-send --print-reply  \
+
  [sbox-DIABLO_X86: ~] > run-standalone.sh dbus-send --print-reply  \
   --type=method_call --dest=org.freedesktop.Notifications  \
   --type=method_call --dest=org.freedesktop.Notifications  \
   /org/freedesktop/Notifications org.freedesktop.Notifications.SystemNoteDialog
   /org/freedesktop/Notifications org.freedesktop.Notifications.SystemNoteDialog
  Error org.freedesktop.DBus.Error.UnknownMethod: Method "SystemNoteDialog" with
  Error org.freedesktop.DBus.Error.UnknownMethod: Method "SystemNoteDialog" with
-
   signature "" on interface "org.freedesktop.Notifications" doesn't exist
+
   signature "" on interface "org.freedesktop.Notifications" does not exist
-
</div>
+
</pre>
-
Seems that the RPC call is still missing something. Most RPC methods will expect a series of parameters (or arguments, as D-Bus calls them).
+
Most RPC methods expect a series of parameters (or arguments, as D-Bus calls them).
-
SystemNoteDialog expects these three parameters (in the following order):
+
<code>SystemNoteDialog</code> expects these three parameters (in the following order):
-
* string: The message to display
+
* <code>string</code>: The message to display.
-
* uint32: An unsigned integer giving the style of the dialog. Styles 0-4 mean different icons, and style 5 is a special animated "progress indicator" dialog.
+
* <code>uint32</code>: An unsigned integer giving the style of the dialog. Styles 0-4 mean different icons, and style 5 is a special animated "progress indicator" dialog.
-
* string: Message to use for the "Ok" button that the user needs to press to dismiss the dialog. Using an empty string will cause the default text to be used (which is "Ok").
+
* <code>string</code>: Message to use for the "OK" button that the user needs to press to dismiss the dialog. Using an empty string causes the default text to be used (which is "OK").
Arguments are specified by giving the argument type and its contents separated with a colon as follows:
Arguments are specified by giving the argument type and its contents separated with a colon as follows:
-
<div class="graybox">
+
<pre>
-
[sbox-DIABLO_X86: ~] &gt; run-standalone.sh dbus-send --print-reply  \
+
[sbox-DIABLO_X86: ~] > run-standalone.sh dbus-send --print-reply  \
-
  --type=method_call --dest=org.freedesktop.Notifications  \
+
--type=method_call --dest=org.freedesktop.Notifications  \
-
  /org/freedesktop/Notifications org.freedesktop.Notifications.SystemNoteDialog  \
+
/org/freedesktop/Notifications org.freedesktop.Notifications.SystemNoteDialog  \
-
  string:'Hello, world!' uint32:0 string:'NAO OK!'
+
string:'Hello, world!' uint32:0 string:'NAO OK!'
-
method return sender=:1.1 -&gt; dest=:1.15
+
method return sender=:1.1 -> dest=:1.15
-
    uint32 4
+
  uint32 4
 +
</pre>
-
</div>
+
Because <code>dbus-send</code> was asked to print replies, the reply comes out as a single unsigned integer, with the value 4. This is the unique number for this notification and can be used with the <code>CloseNotification</code> method of the <code>Notifications</code> interface to pre-emptively close the dialog. It is useful if the software notices that some warning condition has ended and there is no need to bother the user with the warning anymore.
-
Since dbus-send was asked to print replies, the reply will come out as a single unsigned integer, with value of 4. This is the unique number for this notification, and could be used with the CloseNotification method of the Notifications interface to pre-emptively close the dialog. It might be especially useful, if the software can notice that some warning condition has ended, and there is no need to bother the user with the warning anymore.
+
Assuming that the above command is run while the application framework is already running, the end result looks like this:
-
Assuming that the above command is run while the application framework is already running, the end result should more or less look like this:
+
[[Image:dbus-send-SystemNoteDialog.png|frame|center|alt=Screenshot of Note dialog showing text ‘Hello, world!’|System note dialog]]
-
<div align="CENTER">[[Image:dbus-send-SystemNoteDialog.png|Image dbus-send-SystemNoteDialog]]</div>
+
If the command is repeated multiple times, the notification service is capable of displaying only one dialog at a time. This makes sense because the dialog is modal. Furthermore, the method calls are queued, not lost; the notification service displays all of the requested dialogs. The service also acknowledges the RPC method call without delay (which is not always the obvious thing to do), giving a different return value each time (incrementing by one each time).
-
If the command is repeated multiple times, one will notice that the notification service is capable of displaying only one dialog at a time. This makes sense, as the dialog is modal anyway. It can also be noticed that the method calls are queued somewhere, and not lost (i.e. the notification service will display all of the requested dialogs). The service also acknowledges the RPC method call without delay (which is not always the obvious thing to do), giving a different return value each time (incrementing by one each time).
+
== Programming Directly with libdbus ==
-
== Programming Directly with Libdbus ==
+
The lowest level library to be used for D-Bus programming is <code>libdbus</code>. Using this library directly is discouraged, mostly because it contains a lot of specific code to integrate into various main-loop designs that the higher level language bindings use.
-
The lowest level library to use for D-Bus programming is libdbus. Using this library directly is discouraged, mostly because it contains a lot of specific code to integrate into various main-loop designs that the higher level language bindings use.
+
The [http://maemo.org/api_refs/5.0/5.0-final/dbus/api/ libdbus API reference] documentation contains a helpful note:
-
The libdbus API reference documentation [[/node19.html#maemoapi 52]] contains a helpful note:
+
<source lang="c">
 +
/**
 +
* Uses the low-level libdbus which should not be used directly.
 +
* As the D-Bus API reference puts it "If you use this low-level API
 +
* directly, you are signing up for some pain".
 +
*/
 +
</source>
-
<tt><span>''<span><font color="#9A1900">/**</font></span>''</span>
+
At this point, this example ignores the warnings, and uses the library to implement a simple program that replicates the earlier <code>dbus-send</code> example. To do this with the minimum amount of code, the code does not process (or expect) any responses to the method call. However, the code demonstrates the bare minimum function calls that are needed to send messages on the bus.
-
<span>''<span><font color="#9A1900"> * Uses the low-level libdbus which shouldn't be used directly.</font></span>''</span>
+
-
<span>''<span><font color="#9A1900"> * As the D-Bus API reference puts it "If you use this low-level API</font></span>''</span>
+
-
<span>''<span><font color="#9A1900"> * directly, you're signing up for some pain".</font></span>''</span>
+
-
<span>''<span><font color="#9A1900"> */</font></span>''</span></tt>
+
-
At this point, this example will ignore the warnings, and use the library to implement a simple program that will replicate the dbus-send example that was seen before. In order to do this with the minimum amount of code, the code will not process (or expect) any responses to the method call. It will, however, demonstrate the bare minimum function calls that are needed to use to send messages on the bus.
+
The first step is to introduce the necessary header files. [https://vcs.maemo.org/svn/maemoexamples/trunk/libdbus-example/dbus-example.c libdbus-example/dbus-example.c]
-
The first step is to introduce the necessary header files. libdbus-example/dbus-example.c
+
<source lang="c">
 +
#include <dbus/dbus.h> /* Pull in all of D-Bus headers. */
 +
#include <stdio.h>    /* printf, fprintf, stderr */
 +
#include <stdlib.h>    /* EXIT_FAILURE, EXIT_SUCCESS */
 +
#include <assert.h>    /* assert */
 +
/* Symbolic defines for the D-Bus well-known name, interface, object
 +
  path and method name that we are going to use. */
 +
#define SYSNOTE_NAME  "org.freedesktop.Notifications"
 +
#define SYSNOTE_OPATH "/org/freedesktop/Notifications"
 +
#define SYSNOTE_IFACE "org.freedesktop.Notifications"
 +
#define SYSNOTE_NOTE  "SystemNoteDialog"
 +
</source>
-
<tt><span>'''<span><font color="#000080"><nowiki>#include</nowiki></font></span>'''</span> <span><font color="#FF0000">&lt;dbus/dbus.h&gt;</font></span> <span>''<span><font color="#9A1900">/* Pull in all of D-Bus headers. */</font></span>''</span>
+
Unlike the rest of the code in this material, the dbus example does not use GLib or other support libraries (other than libdbus). This explains why the example uses printf and other functions that are normally replaced with GLib equivalents.
-
<span>'''<span><font color="#000080"><nowiki>#include</nowiki></font></span>'''</span> <span><font color="#FF0000">&lt;stdio.h&gt;</font></span>    <span>''<span><font color="#9A1900">/* printf, fprintf, stderr */</font></span>''</span>
+
-
<span>'''<span><font color="#000080"><nowiki>#include</nowiki></font></span>'''</span> <span><font color="#FF0000">&lt;stdlib.h&gt;</font></span>    <span>''<span><font color="#9A1900">/* EXIT_FAILURE, EXIT_SUCCESS */</font></span>''</span>
+
-
<span>'''<span><font color="#000080"><nowiki>#include</nowiki></font></span>'''</span> <span><font color="#FF0000">&lt;assert.h&gt;</font></span>    <span>''<span><font color="#9A1900">/* assert */</font></span>''</span>
+
-
<span>''<span><font color="#9A1900">/* Symbolic defines for the D-Bus well-known name, interface, object</font></span>''</span>
+
-
<span>''<span><font color="#9A1900">  path and method name that we're going to use. */</font></span>''</span>
+
-
<span>'''<span><font color="#000080"><nowiki>#define</nowiki></font></span>'''</span> SYSNOTE_NAME  <span><font color="#FF0000">"org.freedesktop.Notifications"</font></span>
+
-
<span>'''<span><font color="#000080"><nowiki>#define</nowiki></font></span>'''</span> SYSNOTE_OPATH <span><font color="#FF0000">"/org/freedesktop/Notifications"</font></span>
+
-
<span>'''<span><font color="#000080"><nowiki>#define</nowiki></font></span>'''</span> SYSNOTE_IFACE <span><font color="#FF0000">"org.freedesktop.Notifications"</font></span>
+
-
<span>'''<span><font color="#000080"><nowiki>#define</nowiki></font></span>'''</span> SYSNOTE_NOTE  <span><font color="#FF0000">"SystemNoteDialog"</font></span></tt>
+
-
Unlike the rest of the code in this material, dbus-example does not use GLib or other support libraries (other than libdbus). This explains why it uses printf and other functions that would normally be replaced with GLib equivalents.
+
Connecting to the session bus yields a <code>DBusConnection</code> structure: [https://vcs.maemo.org/svn/maemoexamples/trunk/libdbus-example/dbus-example.c libdbus-example/dbus-example.c]
-
Connecting to the session bus will (hopefully) yield a DBusConnection structure: libdbus-example/dbus-example.c
+
<source lang="c">
 +
/**
 +
* The main program that demonstrates a simple "fire & forget" RPC
 +
* method invocation.
 +
*/
 +
int main(int argc, char** argv) {
-
<tt><span>''<span><font color="#9A1900">/**</font></span>''</span>
+
  /* Structure representing the connection to a bus. */
-
<span>''<span><font color="#9A1900"> * The main program that demonstrates a simple "fire &amp; forget" RPC</font></span>''</span>
+
  DBusConnection* bus = NULL;
-
<span>''<span><font color="#9A1900"> * method invocation.</font></span>''</span>
+
  /* The method call message. */
-
<span>''<span><font color="#9A1900"> */</font></span>''</span>
+
  DBusMessage* msg = NULL;
-
<span><font color="#009900">int</font></span> <span>'''<span><font color="#000000">main</font></span>'''</span><span><font color="#990000">(</font></span><span><font color="#009900">int</font></span> argc<span><font color="#990000">,</font></span> <span><font color="#009900">char</font></span><span><font color="#990000"><nowiki>**</nowiki></font></span> argv<span><font color="#990000">)</font></span> <span><font color="#FF0000">{</font></span>
+
-
+
-
  <span>''<span><font color="#9A1900">/* Structure representing the connection to a bus. */</font></span>''</span>
+
-
  DBusConnection<span><font color="#990000"><nowiki>*</nowiki></font></span> bus <span><font color="#990000"><nowiki>=</nowiki></font></span> NULL<span><font color="#990000"><nowiki>;</nowiki></font></span>
+
-
  <span>''<span><font color="#9A1900">/* The method call message. */</font></span>''</span>
+
-
  DBusMessage<span><font color="#990000"><nowiki>*</nowiki></font></span> msg <span><font color="#990000"><nowiki>=</nowiki></font></span> NULL<span><font color="#990000"><nowiki>;</nowiki></font></span>
+
-
+
-
  <span>''<span><font color="#9A1900">/* D-Bus will report problems and exceptions using the DBusError</font></span>''</span>
+
-
<span>''<span><font color="#9A1900">    structure. We'll allocate one in stack (so that we don't need to</font></span>''</span>
+
-
<span>''<span><font color="#9A1900">    free it explicitly. */</font></span>''</span>
+
-
  DBusError error<span><font color="#990000"><nowiki>;</nowiki></font></span>
+
-
+
-
  <span>''<span><font color="#9A1900">/* Message to display. */</font></span>''</span>
+
-
  <span>'''<span><font color="#0000FF">const</font></span>'''</span> <span><font color="#009900">char</font></span><span><font color="#990000"><nowiki>*</nowiki></font></span> dispMsg <span><font color="#990000"><nowiki>=</nowiki></font></span> <span><font color="#FF0000">"Hello World!"</font></span><span><font color="#990000"><nowiki>;</nowiki></font></span>
+
-
  <span>''<span><font color="#9A1900">/* Text to use for the acknowledgement button. "" means default. */</font></span>''</span>
+
-
  <span>'''<span><font color="#0000FF">const</font></span>'''</span> <span><font color="#009900">char</font></span><span><font color="#990000"><nowiki>*</nowiki></font></span> buttonText <span><font color="#990000"><nowiki>=</nowiki></font></span> <span><font color="#FF0000">""</font></span><span><font color="#990000"><nowiki>;</nowiki></font></span>
+
-
  <span>''<span><font color="#9A1900">/* Type of icon to use in the dialog (1 = OSSO_GN_ERROR). We could</font></span>''</span>
+
-
<span>''<span><font color="#9A1900">    have just used the symbolic version here as well, but that would</font></span>''</span>
+
-
<span>''<span><font color="#9A1900">    have required pulling the LibOSSO-header files. And this example</font></span>''</span>
+
-
<span>''<span><font color="#9A1900">    must work without LibOSSO, so this is why a number is used. */</font></span>''</span>
+
-
  <span><font color="#009900">int</font></span> iconType <span><font color="#990000"><nowiki>=</nowiki></font></span> <span><font color="#993399">1</font></span><span><font color="#990000"><nowiki>;</nowiki></font></span>
+
-
+
-
  <span>''<span><font color="#9A1900">/* Clean the error state. */</font></span>''</span>
+
-
  <span>'''<span><font color="#000000">dbus_error_init</font></span>'''</span><span><font color="#990000">(&amp;</font></span>error<span><font color="#990000">);</font></span>
+
-
+
-
  <span>'''<span><font color="#000000">printf</font></span>'''</span><span><font color="#990000">(</font></span><span><font color="#FF0000">"Connecting to Session D-Bus</font></span><span><font color="#CC33CC">\n</font></span><span><font color="#FF0000">"</font></span><span><font color="#990000">);</font></span>
+
-
  bus <span><font color="#990000"><nowiki>=</nowiki></font></span> <span>'''<span><font color="#000000">dbus_bus_get</font></span>'''</span><span><font color="#990000">(</font></span>DBUS_BUS_SESSION<span><font color="#990000">,</font></span> <span><font color="#990000">&amp;</font></span>error<span><font color="#990000">);</font></span>
+
-
  <span>'''<span><font color="#000000">terminateOnError</font></span>'''</span><span><font color="#990000">(</font></span><span><font color="#FF0000">"Failed to open Session bus</font></span><span><font color="#CC33CC">\n</font></span><span><font color="#FF0000">"</font></span><span><font color="#990000">,</font></span> <span><font color="#990000">&amp;</font></span>error<span><font color="#990000">);</font></span>
+
-
  <span>'''<span><font color="#000000">assert</font></span>'''</span><span><font color="#990000">(</font></span>bus <span><font color="#990000"><nowiki>!=</nowiki></font></span> NULL<span><font color="#990000">);</font></span></tt>
+
-
N.B. Libdbus will attempt to share existing connection structures when the same process is connecting to the same bus. This is done to avoid the somewhat costly connection set-up time. Sharing connections is beneficial, when the program is using libraries that would also open their own connections to the same buses.
+
  /* D-Bus reports problems and exceptions using the DBusError
 +
    structure. We allocate one in stack (so that we don't need to
 +
    free it explicitly. */
 +
  DBusError error;
-
In order to communicate errors, libdbus uses DBusError structures, whose contents are pretty simple. The dbus_error_init will be used to guarantee that the error structure contains a non-error state before connecting to the bus. If there is an error, it will be handled in terminateOnError: libdbus-example/dbus-example.c
+
  /* Message to display. */
 +
  const char* dispMsg = "Hello World!";
 +
  /* Text to use for the acknowledgement button. "" means default. */
 +
  const char* buttonText = "";
 +
  /* Type of icon to use in the dialog (1 = OSSO_GN_ERROR). We could
 +
    have just used the symbolic version here as well, but that would
 +
    have required pulling the LibOSSO-header files. And this example
 +
    must work without LibOSSO, so this is why a number is used. */
 +
  int iconType = 1;
-
<tt><span>''<span><font color="#9A1900">/**</font></span>''</span>
+
  /* Clean the error state. */
-
<span>''<span><font color="#9A1900"> * Utility to terminate if given DBusError is set.</font></span>''</span>
+
  dbus_error_init(&error);
-
<span>''<span><font color="#9A1900"> * Will print out the message and error before terminating.</font></span>''</span>
+
-
<span>''<span><font color="#9A1900"> *</font></span>''</span>
+
-
<span>''<span><font color="#9A1900"> * If error is not set, will do nothing.</font></span>''</span>
+
-
<span>''<span><font color="#9A1900"> *</font></span>''</span>
+
-
<span>''<span><font color="#9A1900"> * NOTE: In real applications you should spend a moment or two</font></span>''</span>
+
-
<span>''<span><font color="#9A1900"> *      thinking about the exit-paths from your application and</font></span>''</span>
+
-
<span>''<span><font color="#9A1900"> *      whether you need to close/unreference all resources that you</font></span>''</span>
+
-
<span>''<span><font color="#9A1900"> *      have allocated. In this program, we rely on the kernel to do</font></span>''</span>
+
-
<span>''<span><font color="#9A1900"> *      all necessary cleanup (closing sockets, releasing memory),</font></span>''</span>
+
-
<span>''<span><font color="#9A1900"> *      but in real life you need to be more careful.</font></span>''</span>
+
-
<span>''<span><font color="#9A1900"> *</font></span>''</span>
+
-
<span>''<span><font color="#9A1900"> *      One possible solution model to this is implemented in</font></span>''</span>
+
-
<span>''<span><font color="#9A1900"> *      "flashlight", a simple program that is presented later.</font></span>''</span>
+
-
<span>''<span><font color="#9A1900"> */</font></span>''</span>
+
-
<span>'''<span><font color="#0000FF">static</font></span>'''</span> <span><font color="#009900">void</font></span> <span>'''<span><font color="#000000">terminateOnError</font></span>'''</span><span><font color="#990000">(</font></span><span>'''<span><font color="#0000FF">const</font></span>'''</span> <span><font color="#009900">char</font></span><span><font color="#990000"><nowiki>*</nowiki></font></span> msg<span><font color="#990000">,</font></span>
+
-
                              <span>'''<span><font color="#0000FF">const</font></span>'''</span> DBusError<span><font color="#990000"><nowiki>*</nowiki></font></span> error<span><font color="#990000">)</font></span> <span><font color="#FF0000">{</font></span>
+
-
+
-
  <span>'''<span><font color="#000000">assert</font></span>'''</span><span><font color="#990000">(</font></span>msg <span><font color="#990000"><nowiki>!=</nowiki></font></span> NULL<span><font color="#990000">);</font></span>
+
-
  <span>'''<span><font color="#000000">assert</font></span>'''</span><span><font color="#990000">(</font></span>error <span><font color="#990000"><nowiki>!=</nowiki></font></span> NULL<span><font color="#990000">);</font></span>
+
-
+
-
  <span>'''<span><font color="#0000FF">if</font></span>'''</span> <span><font color="#990000">(</font></span><span>'''<span><font color="#000000">dbus_error_is_set</font></span>'''</span><span><font color="#990000">(</font></span>error<span><font color="#990000">))</font></span> <span><font color="#FF0000">{</font></span>
+
-
    <span>'''<span><font color="#000000">fprintf</font></span>'''</span><span><font color="#990000">(</font></span>stderr<span><font color="#990000">,</font></span> msg<span><font color="#990000">);</font></span>
+
-
    <span>'''<span><font color="#000000">fprintf</font></span>'''</span><span><font color="#990000">(</font></span>stderr<span><font color="#990000">,</font></span> <span><font color="#FF0000">"DBusError.name: %s</font></span><span><font color="#CC33CC">\n</font></span><span><font color="#FF0000">"</font></span><span><font color="#990000">,</font></span> error<span><font color="#990000">-&gt;</font></span>name<span><font color="#990000">);</font></span>
+
-
    <span>'''<span><font color="#000000">fprintf</font></span>'''</span><span><font color="#990000">(</font></span>stderr<span><font color="#990000">,</font></span> <span><font color="#FF0000">"DBusError.message: %s</font></span><span><font color="#CC33CC">\n</font></span><span><font color="#FF0000">"</font></span><span><font color="#990000">,</font></span> error<span><font color="#990000">-&gt;</font></span>message<span><font color="#990000">);</font></span>
+
-
    <span>''<span><font color="#9A1900">/* If the program wouldn't exit because of the error, freeing the</font></span>''</span>
+
-
<span>''<span><font color="#9A1900">      DBusError needs to be done (with dbus_error_free(error)).</font></span>''</span>
+
-
<span>''<span><font color="#9A1900">      NOTE:</font></span>''</span>
+
-
<span>''<span><font color="#9A1900">        dbus_error_free(error) would only free the error if it was</font></span>''</span>
+
-
<span>''<span><font color="#9A1900">        set, so it is safe to use even when you're unsure. */</font></span>''</span>
+
-
    <span>'''<span><font color="#000000">exit</font></span>'''</span><span><font color="#990000">(</font></span>EXIT_FAILURE<span><font color="#990000">);</font></span>
+
-
  <span><font color="#FF0000">}</font></span>
+
-
<span><font color="#FF0000">}</font></span></tt>
+
-
libdbus also contains some utility functions, so that everything does not have to be coded manually. One such utility is dbus_bus_name_has_owner that checks, whether there is at least some process that owns the given well-known name at that moment: libdbus-example/dbus-example.c
+
  printf("Connecting to Session D-Bus\n");
 +
  bus = dbus_bus_get(DBUS_BUS_SESSION, &error);
 +
  terminateOnError("Failed to open Session bus\n", &error);
 +
  assert(bus != NULL);
 +
</source>
-
<tt>  <span>''<span><font color="#9A1900">/* Normally one would just do the RPC call immediately without</font></span>''</span>
+
Libdbus attempts to share the existing connection structures when the same process is connecting to the same bus. This is done to avoid the costly connection set-up time. Sharing connections is beneficial when the program is using libraries that would also open their own connections to the same buses.
-
<span>''<span><font color="#9A1900">    checking for name existence first. However, sometimes it is useful</font></span>''</span>
+
-
<span>''<span><font color="#9A1900">    to check whether a specific name even exists on a platform on</font></span>''</span>
+
-
<span>''<span><font color="#9A1900">    which you are planning to use D-Bus.</font></span>''</span>
+
-
+
-
<span>''<span><font color="#9A1900">    In our case it acts as a reminder to run this program using the</font></span>''</span>
+
-
<span>''<span><font color="#9A1900">    run-standalone.sh script when running in the SDK.</font></span>''</span>
+
-
+
-
<span>''<span><font color="#9A1900">    The existence check is not necessary if the recipient is</font></span>''</span>
+
-
<span>''<span><font color="#9A1900">    startable/activateable by D-Bus. In that case, if the recipient</font></span>''</span>
+
-
<span>''<span><font color="#9A1900">    is not already running, the D-Bus daemon will start the</font></span>''</span>
+
-
<span>''<span><font color="#9A1900">    recipient (a process that has been registered for that</font></span>''</span>
+
-
<span>''<span><font color="#9A1900">    well-known name) and then passes the message to it. This</font></span>''</span>
+
-
<span>''<span><font color="#9A1900">    automatic starting mechanism will avoid the race condition</font></span>''</span>
+
-
<span>''<span><font color="#9A1900">    discussed below and also makes sure that only one instance of</font></span>''</span>
+
-
<span>''<span><font color="#9A1900">    the service is running at any given time. */</font></span>''</span>
+
-
  <span>'''<span><font color="#000000">printf</font></span>'''</span><span><font color="#990000">(</font></span><span><font color="#FF0000">"Checking whether the target name exists ("</font></span>
+
-
          SYSNOTE_NAME <span><font color="#FF0000">")</font></span><span><font color="#CC33CC">\n</font></span><span><font color="#FF0000">"</font></span><span><font color="#990000">);</font></span>
+
-
  <span>'''<span><font color="#0000FF">if</font></span>'''</span> <span><font color="#990000">(!</font></span><span>'''<span><font color="#000000">dbus_bus_name_has_owner</font></span>'''</span><span><font color="#990000">(</font></span>bus<span><font color="#990000">,</font></span> SYSNOTE_NAME<span><font color="#990000">,</font></span> <span><font color="#990000">&amp;</font></span>error<span><font color="#990000">))</font></span> <span><font color="#FF0000">{</font></span>
+
-
    <span>'''<span><font color="#000000">fprintf</font></span>'''</span><span><font color="#990000">(</font></span>stderr<span><font color="#990000">,</font></span> <span><font color="#FF0000">"Name has no owner on the bus!</font></span><span><font color="#CC33CC">\n</font></span><span><font color="#FF0000">"</font></span><span><font color="#990000">);</font></span>
+
-
    <span>'''<span><font color="#0000FF">return</font></span>'''</span> EXIT_FAILURE<span><font color="#990000"><nowiki>;</nowiki></font></span>
+
-
  <span><font color="#FF0000">}</font></span>
+
-
  <span>'''<span><font color="#000000">terminateOnError</font></span>'''</span><span><font color="#990000">(</font></span><span><font color="#FF0000">"Failed to check for name ownership</font></span><span><font color="#CC33CC">\n</font></span><span><font color="#FF0000">"</font></span><span><font color="#990000">,</font></span> <span><font color="#990000">&amp;</font></span>error<span><font color="#990000">);</font></span>
+
-
  <span>''<span><font color="#9A1900">/* Someone on the Session bus owns the name. So we can proceed in</font></span>''</span>
+
-
<span>''<span><font color="#9A1900">    relative safety. There is a chance of a race. If the name owner</font></span>''</span>
+
-
<span>''<span><font color="#9A1900">    decides to drop out from the bus just after we check that it is</font></span>''</span>
+
-
<span>''<span><font color="#9A1900">    owned, our RPC call (below) will fail anyway. */</font></span>''</span>
+
-
</tt>
+
-
Creating a method call using libdbus is slightly more tedious than using the higher-level interfaces, but not very difficult. The process is separated into two steps: creating a message structure, and appending the arguments to the message: libdbus-example/dbus-example.c
+
To communicate errors, libdbus uses <code>DBusError</code> structures, whose contents are simple. The dbus_error_init is used for guaranteeing that the error structure contains a non-error state before connecting to the bus. If there is an error, it is handled in <code>terminateOnError</code>: [https://vcs.maemo.org/svn/maemoexamples/trunk/libdbus-example/dbus-example.c libdbus-example/dbus-example.c]
-
<tt>  <span>''<span><font color="#9A1900">/* Construct a DBusMessage that represents a method call.</font></span>''</span>
+
<source lang="c">
-
  <span>''<span><font color="#9A1900">    Parameters will be added later. The internal type of the message</font></span>''</span>
+
/**
-
  <span>''<span><font color="#9A1900">    will be DBUS_MESSAGE_TYPE_METHOD_CALL. */</font></span>''</span>
+
  * Utility to terminate if given DBusError is set.
-
  <span>'''<span><font color="#000000">printf</font></span>'''</span><span><font color="#990000">(</font></span><span><font color="#FF0000">"Creating a message object</font></span><span><font color="#CC33CC">\n</font></span><span><font color="#FF0000">"</font></span><span><font color="#990000">);</font></span>
+
  * Prints out the message and error before terminating.
-
  msg <span><font color="#990000"><nowiki>=</nowiki></font></span> <span>'''<span><font color="#000000">dbus_message_new_method_call</font></span>'''</span><span><font color="#990000">(</font></span>SYSNOTE_NAME<span><font color="#990000">,</font></span> <span>''<span><font color="#9A1900">/* destination */</font></span>''</span>
+
*
-
                                      SYSNOTE_OPATH<span><font color="#990000">,</font></span> <span>''<span><font color="#9A1900">/* obj. path */</font></span>''</span>
+
  * If error is not set, does nothing.
-
                                      SYSNOTE_IFACE<span><font color="#990000">,</font></span> <span>''<span><font color="#9A1900">/* interface */</font></span>''</span>
+
  *
-
                                      SYSNOTE_NOTE<span><font color="#990000">);</font></span> <span>''<span><font color="#9A1900">/* method str */</font></span>''</span>
+
* NOTE: In real applications you should spend a moment or two
-
  <span>'''<span><font color="#0000FF">if</font></span>'''</span> <span><font color="#990000">(</font></span>msg <span><font color="#990000"><nowiki>==</nowiki></font></span> NULL<span><font color="#990000">)</font></span> <span><font color="#FF0000">{</font></span>
+
*      thinking about the exit-paths from your application and
-
    <span>'''<span><font color="#000000">fprintf</font></span>'''</span><span><font color="#990000">(</font></span>stderr<span><font color="#990000">,</font></span> <span><font color="#FF0000">"Ran out of memory when creating a message</font></span><span><font color="#CC33CC">\n</font></span><span><font color="#FF0000">"</font></span><span><font color="#990000">);</font></span>
+
  *       whether you need to close/unreference all resources that you
-
    <span>'''<span><font color="#000000">exit</font></span>'''</span><span><font color="#990000">(</font></span>EXIT_FAILURE<span><font color="#990000">);</font></span>
+
  *       have allocated. In this program, we rely on the kernel to do
-
  <span><font color="#FF0000">}</font></span>
+
  *       all necessary cleanup (closing sockets, releasing memory),
-
   
+
  *       but in real life you need to be more careful.
-
  <span>''<span><font color="#9A1900">/*... Listing cut for brevity ...*/</font></span>''</span>
+
  *
-
   
+
  *       One possible solution model to this is implemented in
-
  <span>''<span><font color="#9A1900">/* Add the arguments to the message. For the Note dialog, we need</font></span>''</span>
+
  *      "flashlight", a simple program that is presented later.
-
  <span>''<span><font color="#9A1900">    three arguments:</font></span>''</span>
+
  */
-
<span>''<span><font color="#9A1900">       arg0: (STRING) "message to display, in UTF-8"</font></span>''</span>
+
static void terminateOnError(const char* msg,
-
  <span>''<span><font color="#9A1900">       arg1: (UINT32) type of dialog to display. We will use 1.</font></span>''</span>
+
                            const DBusError* error) {
-
  <span>''<span><font color="#9A1900">                      (libosso.h/OSSO_GN_ERROR).</font></span>''</span>
+
-
  <span>''<span><font color="#9A1900">       arg2: (STRING) "text to use for the ack button". "" means</font></span>''</span>
+
-
<span>''<span><font color="#9A1900">                      default text (OK in our case).</font></span>''</span>
+
-
   
+
-
<span>''<span><font color="#9A1900">    When listing the arguments, the type needs to be specified first</font></span>''</span>
+
-
<span>''<span><font color="#9A1900">    (by using the libdbus constants) and then a pointer to the</font></span>''</span>
+
-
<span>''<span><font color="#9A1900">    argument content needs to be given.</font></span>''</span>
+
-
   
+
-
<span>''<span><font color="#9A1900">    NOTE: It is always a pointer to the argument value, not the value</font></span>''</span>
+
-
<span>''<span><font color="#9A1900">          itself!</font></span>''</span>
+
-
+
-
<span>''<span><font color="#9A1900">    We terminate the list with DBUS_TYPE_INVALID. */</font></span>''</span>
+
-
  <span>'''<span><font color="#000000">printf</font></span>'''</span><span><font color="#990000">(</font></span><span><font color="#FF0000">"Appending arguments to the message</font></span><span><font color="#CC33CC">\n</font></span><span><font color="#FF0000">"</font></span><span><font color="#990000">);</font></span>
+
-
  <span>'''<span><font color="#0000FF">if</font></span>'''</span> <span><font color="#990000">(!</font></span><span>'''<span><font color="#000000">dbus_message_append_args</font></span>'''</span><span><font color="#990000">(</font></span>msg<span><font color="#990000">,</font></span>
+
-
                                DBUS_TYPE_STRING<span><font color="#990000">,</font></span> <span><font color="#990000">&amp;</font></span>dispMsg<span><font color="#990000">,</font></span>
+
-
                                DBUS_TYPE_UINT32<span><font color="#990000">,</font></span> <span><font color="#990000">&amp;</font></span>iconType<span><font color="#990000">,</font></span>
+
-
                                DBUS_TYPE_STRING<span><font color="#990000">,</font></span> <span><font color="#990000">&amp;</font></span>buttonText<span><font color="#990000">,</font></span>
+
-
                                DBUS_TYPE_INVALID<span><font color="#990000">))</font></span> <span><font color="#FF0000">{</font></span>
+
-
    <span>'''<span><font color="#000000">fprintf</font></span>'''</span><span><font color="#990000">(</font></span>stderr<span><font color="#990000">,</font></span> <span><font color="#FF0000">"Ran out of memory while constructing args</font></span><span><font color="#CC33CC">\n</font></span><span><font color="#FF0000">"</font></span><span><font color="#990000">);</font></span>
+
-
    <span>'''<span><font color="#000000">exit</font></span>'''</span><span><font color="#990000">(</font></span>EXIT_FAILURE<span><font color="#990000">);</font></span>
+
-
  <span><font color="#FF0000">}</font></span></tt>
+
-
When arguments are appended to the message, their content is copied, and possibly converted into a format that will be sent over the connection to the daemon. This process is called marshaling, and is a common feature to most RPC systems. The method call will require two parameters (as before), the first being the text to display, and the second one being the style of the icon to use. Parameters passed to libdbus are always passed by address. This is different from the higher level libraries, and this will be discussed later.
+
  assert(msg != NULL);
 +
  assert(error != NULL);
-
The arguments are encoded, so that their type code is followed by the pointer where the marshaling functions can find the content. The argument list is terminated with DBUS_TYPE_INVALID, so that the function knows where the argument list ends (since the function prototype ends with an ellipsis, ...). libdbus-example/dbus-example.c
+
  if (dbus_error_is_set(error)) {
 +
    fprintf(stderr, msg);
 +
    fprintf(stderr, "DBusError.name: %s\n", error->name);
 +
    fprintf(stderr, "DBusError.message: %s\n", error->message);
 +
    /* If the program does not exit because of the error, freeing the
 +
      DBusError needs to be done (with dbus_error_free(error)).
 +
      NOTE:
 +
        dbus_error_free(error) would only free the error if it was
 +
        set, so it is safe to use even when you are unsure. */
 +
    exit(EXIT_FAILURE);
 +
  }
 +
}
 +
</source>
-
<tt>  <span>''<span><font color="#9A1900">/* Set the "no-reply-wanted" flag into the message. This also means</font></span>''</span>
+
libdbus also contains some utility functions so that everything does not have to be coded manually. One such utility is <code>dbus_bus_name_has_owner</code>, that checks whether there is at least some process that owns the given well-known name at that moment: [https://vcs.maemo.org/svn/maemoexamples/trunk/libdbus-example/dbus-example.c libdbus-example/dbus-example.c]
-
<span>''<span><font color="#9A1900">    that we cannot reliably know whether the message was delivered or</font></span>''</span>
+
-
<span>''<span><font color="#9A1900">    not, but since we don't have reply message handling here, it</font></span>''</span>
+
-
<span>''<span><font color="#9A1900">    doesn't matter. The "no-reply" is a potential flag for the remote</font></span>''</span>
+
-
<span>''<span><font color="#9A1900">    end so that they know that they don't need to respond to us.</font></span>''</span>
+
-
<span>''<span><font color="#9A1900">    If the no-reply flag is set, the D-Bus daemon makes sure that the</font></span>''</span>
+
-
<span>''<span><font color="#9A1900">    possible reply is discarded and not sent to us. */</font></span>''</span>
+
-
  <span>'''<span><font color="#000000">dbus_message_set_no_reply</font></span>'''</span><span><font color="#990000">(</font></span>msg<span><font color="#990000">,</font></span> TRUE<span><font color="#990000">);</font></span></tt>
+
-
Setting the no-reply-flag effectively tells the bus daemon that even if there is a reply coming back for this RPC method, it is not wanted. In this case, the daemon will not send one.
+
<source lang="c">
 +
  /* Normally one would just do the RPC call immediately without
 +
    checking for name existence first. However, sometimes it is useful
 +
    to check whether a specific name even exists on a platform on
 +
    which you are planning to use D-Bus.
-
Once the message is fully constructed, it can be added to the sending queue of the program. Messages are not sent immediately by libdbus. Normally this allows the message queue to accumulate to more than one message, and all of the messages will be sent at once to the daemon. This in turn cuts down the number of context switches necessary. In this case, this will be the only message that the program ever sends, so the send queue is instructed to be flushed immediately, and this will instruct the library to send all messages to the daemon without a delay: libdbus-example/dbus-example.c
+
    In our case it acts as a reminder to run this program using the
 +
    run-standalone.sh script when running in the SDK.
-
<tt>  <span>'''<span><font color="#000000">printf</font></span>'''</span><span><font color="#990000">(</font></span><span><font color="#FF0000">"Adding message to client's send-queue</font></span><span><font color="#CC33CC">\n</font></span><span><font color="#FF0000">"</font></span><span><font color="#990000">);</font></span>
+
    The existence check is not necessary if the recipient is
-
  <span>''<span><font color="#9A1900">/* We could also get a serial number (dbus_uint32_t) for the message</font></span>''</span>
+
    startable/activateable by D-Bus. In that case, if the recipient
-
<span>''<span><font color="#9A1900">    so that we could correlate responses to sent messages later. In</font></span>''</span>
+
    is not already running, the D-Bus daemon starts the
-
<span>''<span><font color="#9A1900">    our case there won't be a response anyway, so we don't care about</font></span>''</span>
+
    recipient (a process that has been registered for that
-
<span>''<span><font color="#9A1900">    the serial, so we pass a NULL as the last parameter. */</font></span>''</span>
+
    well-known name) and then passes the message to it. This
-
  <span>'''<span><font color="#0000FF">if</font></span>'''</span> <span><font color="#990000">(!</font></span><span>'''<span><font color="#000000">dbus_connection_send</font></span>'''</span><span><font color="#990000">(</font></span>bus<span><font color="#990000">,</font></span> msg<span><font color="#990000">,</font></span> NULL<span><font color="#990000">))</font></span> <span><font color="#FF0000">{</font></span>
+
    automatic starting mechanism avoids the race condition
-
    <span>'''<span><font color="#000000">fprintf</font></span>'''</span><span><font color="#990000">(</font></span>stderr<span><font color="#990000">,</font></span> <span><font color="#FF0000">"Ran out of memory while queueing message</font></span><span><font color="#CC33CC">\n</font></span><span><font color="#FF0000">"</font></span><span><font color="#990000">);</font></span>
+
    discussed below and also makes sure that only one instance of
-
    <span>'''<span><font color="#000000">exit</font></span>'''</span><span><font color="#990000">(</font></span>EXIT_FAILURE<span><font color="#990000">);</font></span>
+
    the service is running at any given time. */
-
  <span><font color="#FF0000">}</font></span>
+
  printf("Checking whether the target name exists ("
-
+
        SYSNOTE_NAME ")\n");
-
  <span>'''<span><font color="#000000">printf</font></span>'''</span><span><font color="#990000">(</font></span><span><font color="#FF0000">"Waiting for send-queue to be sent out</font></span><span><font color="#CC33CC">\n</font></span><span><font color="#FF0000">"</font></span><span><font color="#990000">);</font></span>
+
  if (!dbus_bus_name_has_owner(bus, SYSNOTE_NAME, &error)) {
-
  <span>'''<span><font color="#000000">dbus_connection_flush</font></span>'''</span><span><font color="#990000">(</font></span>bus<span><font color="#990000">);</font></span>
+
    fprintf(stderr, "Name has no owner on the bus!\n");
-
+
    return EXIT_FAILURE;
-
  <span>'''<span><font color="#000000">printf</font></span>'''</span><span><font color="#990000">(</font></span><span><font color="#FF0000">"Queue is now empty</font></span><span><font color="#CC33CC">\n</font></span><span><font color="#FF0000">"</font></span><span><font color="#990000">);</font></span></tt>
+
  }
 +
  terminateOnError("Failed to check for name ownership\n", &error);
 +
  /* Someone on the Session bus owns the name. So we can proceed in
 +
    relative safety. There is a chance of a race. If the name owner
 +
    decides to drop out from the bus just after we check that it is
 +
    owned, our RPC call (below) fails anyway. */
 +
</source>
-
After the message is sent, the reserved resources should be freed. Here, the first one to be freed is the message, and then the connection structure. libdbus-example/dbus-example.c
+
Creating a method call using libdbus is slightly more tedious than using the higher-level interfaces. The process is separated into two steps: creating a message structure, and appending the arguments to the message: [https://vcs.maemo.org/svn/maemoexamples/trunk/libdbus-example/dbus-example.c libdbus-example/dbus-example.c]
-
<tt>  <span>'''<span><font color="#000000">printf</font></span>'''</span><span><font color="#990000">(</font></span><span><font color="#FF0000">"Cleaning up</font></span><span><font color="#CC33CC">\n</font></span><span><font color="#FF0000">"</font></span><span><font color="#990000">);</font></span>
+
<source lang="c">
-
+
  /* Construct a DBusMessage that represents a method call.
-
  <span>''<span><font color="#9A1900">/* Free up the allocated message. Most D-Bus objects have internal</font></span>''</span>
+
    Parameters are added later. The internal type of the message
-
<span>''<span><font color="#9A1900">    reference count and sharing possibility, so _unref() functions</font></span>''</span>
+
    is DBUS_MESSAGE_TYPE_METHOD_CALL. */
-
<span>''<span><font color="#9A1900">    are quite common. */</font></span>''</span>
+
  printf("Creating a message object\n");
-
  <span>'''<span><font color="#000000">dbus_message_unref</font></span>'''</span><span><font color="#990000">(</font></span>msg<span><font color="#990000">);</font></span>
+
  msg = dbus_message_new_method_call(SYSNOTE_NAME, /* destination */
-
  msg <span><font color="#990000"><nowiki>=</nowiki></font></span> NULL<span><font color="#990000"><nowiki>;</nowiki></font></span>
+
                                    SYSNOTE_OPATH, /* obj. path */
-
   
+
                                    SYSNOTE_IFACE,  /* interface */
-
  <span>''<span><font color="#9A1900">/* Free-up the connection. libdbus attempts to share existing</font></span>''</span>
+
                                    SYSNOTE_NOTE); /* method str */
-
<span>''<span><font color="#9A1900">    connections for the same client, so instead of closing down a</font></span>''</span>
+
  if (msg == NULL) {
-
  <span>''<span><font color="#9A1900">    connection object, it is unreferenced. The D-Bus library will</font></span>''</span>
+
    fprintf(stderr, "Ran out of memory when creating a message\n");
-
<span>''<span><font color="#9A1900">    keep an internal reference to each shared connection, to</font></span>''</span>
+
    exit(EXIT_FAILURE);
-
<span>''<span><font color="#9A1900">    prevent accidental closing of shared connections before the</font></span>''</span>
+
  }
-
<span>''<span><font color="#9A1900">    library is finalized. */</font></span>''</span>
+
-
  <span>'''<span><font color="#000000">dbus_connection_unref</font></span>'''</span><span><font color="#990000">(</font></span>bus<span><font color="#990000">);</font></span>
+
-
  bus <span><font color="#990000"><nowiki>=</nowiki></font></span> NULL<span><font color="#990000"><nowiki>;</nowiki></font></span>
+
-
+
-
  <span>'''<span><font color="#000000">printf</font></span>'''</span><span><font color="#990000">(</font></span><span><font color="#FF0000">"Quitting (success)</font></span><span><font color="#CC33CC">\n</font></span><span><font color="#FF0000">"</font></span><span><font color="#990000">);</font></span>
+
-
+
-
  <span>'''<span><font color="#0000FF">return</font></span>'''</span> EXIT_SUCCESS<span><font color="#990000"><nowiki>;</nowiki></font></span>
+
-
<span><font color="#FF0000">}</font></span></tt>
+
-
After building the program, attempt to run it:
+
  /*... Listing cut for brevity ...*/
-
<div class="graybox">
+
  /* Add the arguments to the message. For the Note dialog, we need
-
   [sbox-DIABLO_X86: ~/libdbus-example] &gt; ./dbus-example
+
    three arguments:
-
Connecting to Session D-Bus
+
      arg0: (STRING) "message to display, in UTF-8"
-
process 6120: D-Bus library appears to be incorrectly set up;
+
      arg1: (UINT32) type of dialog to display. We use 1.
-
   failed to read machine uuid:
+
                      (libosso.h/OSSO_GN_ERROR).
-
  Failed to open "/var/lib/dbus/machine-id": No such file or directory
+
      arg2: (STRING) "text to use for the ack button". "" means
-
See the manual page for dbus-uuidgen to correct this issue.
+
                      default text (OK in our case).
-
  D-Bus not built with -rdynamic so unable to print a backtrace
+
 
-
Aborted (core dumped)
+
    When listing the arguments, the type needs to be specified first
 +
    (by using the libdbus constants) and then a pointer to the
 +
    argument content needs to be given.
 +
 
 +
    NOTE: It is always a pointer to the argument value, not the value
 +
          itself!
 +
 
 +
    We terminate the list with DBUS_TYPE_INVALID. */
 +
   printf("Appending arguments to the message\n");
 +
  if (!dbus_message_append_args(msg,
 +
                                DBUS_TYPE_STRING, &dispMsg,
 +
                                DBUS_TYPE_UINT32, &iconType,
 +
                                DBUS_TYPE_STRING, &buttonText,
 +
                                DBUS_TYPE_INVALID)) {
 +
    fprintf(stderr, "Ran out of memory while constructing args\n");
 +
    exit(EXIT_FAILURE);
 +
  }
 +
</source>
 +
 
 +
When arguments are appended to the message, their content is copied, and possibly converted into a format that is sent over the connection to the daemon. This process is called marshaling, and is a common feature to most RPC systems. The method call requires two parameters (as before), the first being the text to be displayed, and the second being the style of the icon to be used. Parameters passed to libdbus are always passed by address. This is different from the higher level libraries.
 +
 
 +
The arguments are encoded, so that their type code is followed by the pointer where the marshaling functions can find the content. The argument list is terminated with <code>DBUS_TYPE_INVALID</code>, so that the function knows where the argument list ends (since the function prototype ends with an ellipsis, ...). [https://vcs.maemo.org/svn/maemoexamples/trunk/libdbus-example/dbus-example.c libdbus-example/dbus-example.c]
 +
 
 +
<source lang="c">
 +
  /* Set the "no-reply-wanted" flag into the message. This also means
 +
    that we cannot reliably know whether the message was delivered or
 +
    not, but because we do not have reply message handling here, it
 +
    does not matter. The "no-reply" is a potential flag for the remote
 +
    end so that they know that they do not need to respond to us.
 +
    If the no-reply flag is set, the D-Bus daemon makes sure that the
 +
    possible reply is discarded and not sent to us. */
 +
  dbus_message_set_no_reply(msg, TRUE);
 +
</source>
 +
 
 +
Setting the no-reply-flag effectively tells the bus daemon that even if there is a reply coming back for this RPC method, it is not wanted. In this case, the daemon does not send a reply.
 +
 
 +
Once the message is fully constructed, it can be added to the sending queue of the program. Messages are not sent immediately by libdbus. Normally this allows the message queue to accumulate to more than one message, and all of the messages are sent at once to the daemon. This in turn cuts down the number of the necessary context switches. In this case, this message is the only message that the program ever sends, so the send queue is instructed to be flushed immediately, which in turn instructs the library to send all messages to the daemon without a delay: [https://vcs.maemo.org/svn/maemoexamples/trunk/libdbus-example/dbus-example.c libdbus-example/dbus-example.c]
 +
 
 +
<source lang="c">
 +
  printf("Adding message to client's send-queue\n");
 +
   /* We could also get a serial number (dbus_uint32_t) for the message
 +
    so that we could correlate responses to sent messages later. In
 +
    our case there is not going to be a response anyway, so we do not care about
 +
    the serial, so we pass a NULL as the last parameter. */
 +
  if (!dbus_connection_send(bus, msg, NULL)) {
 +
    fprintf(stderr, "Ran out of memory while queueing message\n");
 +
    exit(EXIT_FAILURE);
 +
  }
 +
 
 +
  printf("Waiting for send-queue to be sent out\n");
 +
  dbus_connection_flush(bus);
 +
 
 +
  printf("Queue is now empty\n");
 +
</source>
 +
 
 +
After the message is sent, the reserved resources must be freed. Here, the first one to be freed is the message, and then the connection structure. [https://vcs.maemo.org/svn/maemoexamples/trunk/libdbus-example/dbus-example.c libdbus-example/dbus-example.c]
 +
 
 +
<source lang="c">
 +
  printf("Cleaning up\n");
 +
 
 +
  /* Free up the allocated message. Most D-Bus objects have internal
 +
    reference count and sharing possibility, so _unref() functions
 +
    are quite common. */
 +
  dbus_message_unref(msg);
 +
  msg = NULL;
 +
 
 +
  /* Free-up the connection. libdbus attempts to share existing
 +
    connections for the same client, so instead of closing down a
 +
    connection object, it is unreferenced. The D-Bus library
 +
    keeps an internal reference to each shared connection, to
 +
    prevent accidental closing of shared connections before the
 +
    library is finalized. */
 +
  dbus_connection_unref(bus);
 +
  bus = NULL;
 +
 
 +
  printf("Quitting (success)\n");
 +
 
 +
  return EXIT_SUCCESS;
 +
}
 +
</source>
 +
 
 +
After building the program, attempt to run it:
-
</div>
+
<pre>
 +
[sbox-DIABLO_X86: ~/libdbus-example] > ./dbus-example
 +
Connecting to Session D-Bus
 +
process 6120: D-Bus library appears to be incorrectly set up;
 +
failed to read machine uuid:
 +
  Failed to open "/var/lib/dbus/machine-id": No such file or directory
 +
See the manual page for dbus-uuidgen to correct this issue.
 +
  D-Bus not built with -rdynamic so unable to print a backtrace
 +
Aborted (core dumped)
 +
</pre>
-
The D-Bus library needs environmental variables set correctly in order to locate the session daemon. The command was not prepended with run-standalone.sh, and this caused the library to internally abort the execution. Normally, dbus_bus_get would have returned a NULL pointer and set the error structure, but the version on the 4.1 SDK will assert internally in this condition, and programs cannot avoid the abort. After correcting this, try again:
+
The D-Bus library needs environmental variables set correctly in order to locate the session daemon. The command was not prepended with run-standalone.sh, and this caused the library to internally abort the execution. Normally, <code>dbus_bus_get</code> returns a <code>NULL</code> pointer and sets the error structure, but the version on the 4.1 SDK asserts internally in this condition, and programs cannot avoid the abort. After correcting this, try again:
-
<div class="graybox">
+
<pre>
-
  [sbox-DIABLO_X86: ~/libdbus-example] &gt; run-standalone.sh ./dbus-example
+
[sbox-DIABLO_X86: ~/libdbus-example] > run-standalone.sh ./dbus-example
-
Connecting to Session D-Bus
+
Connecting to Session D-Bus
-
Checking whether the target name exists (org.freedesktop.Notifications)
+
Checking whether the target name exists (org.freedesktop.Notifications)
-
Creating a message object
+
Creating a message object
-
Appending arguments to the message
+
Appending arguments to the message
-
Adding message to client's send-queue
+
Adding message to client's send-queue
-
Waiting for send-queue to be sent out
+
Waiting for send-queue to be sent out
-
Queue is now empty
+
Queue is now empty
-
Cleaning up
+
Cleaning up
-
Quitting (success)
+
Quitting (success)
-
/dev/dsp: No such file or directory
+
/dev/dsp: No such file or directory
 +
</pre>
-
</div>
+
The error message (about <code>/dev/dsp</code>) printed to the same terminal where AF was started is normal behavior (in SDK). Displaying the Note dialog normally also causes an "Alert" sound to be played. The sound system has not been setup in the SDK, so the notification component complains about failing to open the sound device.
-
The error message (about /dev/dsp) printed to the same terminal where AF was started is normal (in SDK). Displaying the Note dialog normally also causes an "Alert" sound to be played. The sound system has not been setup in the SDK, so the notification component complains about failing to open the sound device.
+
[[Image:libdbus-example.png|frame|center|alt=Screenshot of message ‘Hello World!’|The friendly error message, using low-level D-Bus]]
-
<div align="CENTER">[[Image:libdbus-example.png|Image libdbus-example]]</div><div align="CENTER"><font size="-1">The friendly error message, using low-level D-Bus</font></div>
+
To get libdbus integrated into makefiles, use pkg-config. One possible solution is presented below (see section [[Documentation/Maemo 5 Developer Guide/GNU Build System#GNU Make and Makefiles|GNU Make and Makefiles]] in chapter [[Documentation/Maemo 5 Developer Guide/GNU Build System|GNU Build System]], if necessary): [https://vcs.maemo.org/svn/maemoexamples/trunk/libdbus-example/Makefile libdbus-example/Makefile]
-
In order to get libdbus integrated into makefiles, pkg-config has to be used. One possible solution is presented below (see section ''GNU Make and Makefiles'' [/node5.html#sec:gnu_make_makefiles 4.2] in chapter ''GNU Build System'', if necessary): libdbus-example/Makefile
+
<source lang="make">
 +
# Define a list of pkg-config packages we want to use
 +
pkg_packages := dbus-glib-1
 +
PKG_CFLAGS  := $(shell pkg-config -cflags $(pkg_packages))
 +
PKG_LDFLAGS := $(shell pkg-config -libs $(pkg_packages))
 +
# Additional flags for the compiler:
 +
#    -g : Add debugging symbols
 +
# -Wall : Enable most gcc warnings
 +
ADD_CFLAGS := -g -Wall
 +
# Combine user supplied, additional, and pkg-config flags
 +
CFLAGS  := $(PKG_CFLAGS) $(ADD_CFLAGS) $(CFLAGS)
 +
LDFLAGS := $(PKG_LDFLAGS) $(LDFLAGS)
 +
</source>
-
<tt><span>''<span><font color="#9A1900"><nowiki># Define a list of pkg-config packages we want to use</nowiki></font></span>''</span>
+
The above example shows one possibility to integrate user-supplied variables into makefiles, so that they are still passed along the toolchain. This allows the user to execute make with custom flags, overriding those that are introduced using other means. For example: "CFLAGS='-g0' make" results in the -g0 being interpreted after the -g that is in the Makefile, and this leads to debugging symbols being disabled. Environmental variables can be taken into account in exactly the same way.
-
pkg_packages <span><font color="#990000"><nowiki>:=</nowiki></font></span> dbus-glib-<span><font color="#993399">1</font></span>
+
-
PKG_CFLAGS  <span><font color="#990000"><nowiki>:=</nowiki></font></span> <span><font color="#009900">$(</font></span>shell pkg-config -cflags <span><font color="#009900">$(pkg_packages))</font></span>
+
-
PKG_LDFLAGS <span><font color="#990000"><nowiki>:=</nowiki></font></span> <span><font color="#009900">$(</font></span>shell pkg-config -libs <span><font color="#009900">$(pkg_packages))</font></span>
+
-
<span>''<span><font color="#9A1900"><nowiki># Additional flags for the compiler:</nowiki></font></span>''</span>
+
-
<span>''<span><font color="#9A1900"><nowiki>#    -g : Add debugging symbols</nowiki></font></span>''</span>
+
-
<span>''<span><font color="#9A1900"><nowiki># -Wall : Enable most gcc warnings</nowiki></font></span>''</span>
+
-
ADD_CFLAGS <span><font color="#990000"><nowiki>:=</nowiki></font></span> -g -Wall
+
-
<span>''<span><font color="#9A1900"><nowiki># Combine user supplied, additional, and pkg-config flags</nowiki></font></span>''</span>
+
-
CFLAGS  <span><font color="#990000"><nowiki>:=</nowiki></font></span> <span><font color="#009900">$(PKG_CFLAGS)</font></span> <span><font color="#009900">$(ADD_CFLAGS)</font></span> <span><font color="#009900">$(CFLAGS)</font></span>
+
-
LDFLAGS <span><font color="#990000"><nowiki>:=</nowiki></font></span> <span><font color="#009900">$(PKG_LDFLAGS)</font></span> <span><font color="#009900">$(LDFLAGS)</font></span></tt>
+
-
The above shows one possibility to integrate user-supplied variables into makefiles, so that they will still be passed along the toolchain. This allows the user to execute make with custom flags, overriding those that are introduced via other means. For example: "CFLAGS='-g0' make" would result in -g0 being interpreted after the -g that is in the Makefile, and this would lead to debugging symbols being disabled. Environmental variables can be taken into account in exactly the same way.
+
For more complicated programs, that multiple different <code>CFLAGS</code> settings are probably required for different object files or multiple different programs that are being built. In that case, the combining in each target rule is performed separately. In this material, all the example programs are self-contained and rather simple, so the above-mentioned mechanism is used in all example makefiles.
-
For more complicated programs, it is likely that multiple different CFLAGS settings are required for different object files or multiple different programs that are being built. In that case, the combining in each target rule would be performed separately. In this material, all the example programs are self-contained and rather simple, so the above mechanism will be used in all the example makefiles.
+
[[Category:Development]]
 +
[[Category:Documentation]]
 +
[[Category:Fremantle]]

Latest revision as of 14:09, 26 November 2010

For interprocess communications (IPC), Maemo relies heavily on D-Bus. D-Bus makes it possible for programs to export their programming interfaces, so that other processes can call them in a consistent manner, without having to define a custom IPC protocol. Using these exported APIs is also language agnostic, which means that as long as a programming language supports D-Bus, it can also access the interfaces.

A Maemo-specific library called libOSSO provides helpful wrappers for D-Bus communication. It also contains the required functionality for every Maemo application, and applications must be initialized using the library. With the library, applications can connect to listen to system hardware state messages, for example the "battery low" message. The library is also used for application state-saving and the auto-save functionality. Section LibOSSO Library of the chapter Application Development of Maemo Reference Manual provides a good introduction to libOSSO.

Contents

[edit] Introduction

D-Bus (the D originally stood for "Desktop") is an interprocess communication (IPC) mechanism designed to be used as a unified middleware layer in free desktop environments. Example projects where D-Bus is used are GNOME and Hildon. Compared to other middleware layers for IPC, D-Bus lacks many of the more refined (and complicated) features, which makes it faster and simpler.

D-Bus does not directly compete with low-level IPC mechanisms, such as sockets, shared memory or message queues. Each of these mechanisms have their uses, which normally do not overlap the ones in D-Bus. Instead, D-Bus aims to provide higher level functionality, for example:

  • Structured name spaces
  • Architecture-independent data formatting
  • Support for the most common data elements in messages
  • A generic remote call interface with support for exceptions (errors)
  • A generic signaling interface to support "broadcast" type communication
  • Clear separation of per-user and system-wide scopes, which is important when dealing with multi-user systems
  • No bindings to any specific programming languages (while providing a design that readily maps to most higher level languages using language-specific bindings)

The design of D-Bus benefits from the long experience of using other middleware IPC solutions in the desktop arena, and this has allowed the design to be optimized. Furthermore, it does not yet suffer from "creeping featurism", for example having extra features just to satisfy niche use cases.

The main problem area that D-Bus aims to solve is facilitating easy IPC between related (often graphical) desktop software applications.

D-Bus has a very important role in Maemo, as it is the IPC mechanism to use when using the services provided in the platform (and devices). Providing services over D-Bus is also the easiest way to assure component re-use from other applications.

[edit] D-Bus Architecture and Terminology

In D-Bus, the bus is a central concept. Applications can make the method calls, send signals and listen to signals through the bus. Two pre-defined buses exist: the session bus and the system bus.

  • The session bus is intended for communication between applications that are connected to the same desktop session, and normally started and run by one user (using the same user identifier, or UID).
  • The system bus is intended for communication when applications (or services), running with separate sessions, wish to communicate with each other. The most common use for this bus is sending system-wide notifications when system-wide events occur. The adding of a new storage device, network connectivity change events and shutdown-related events are all examples of system-wide events for which the system bus must be used.

In addition to the single system bus, a separate session bus for each desktop session can exist. Because all user applications in a Maemo-compatible device run with the same user ID, the device only has one session bus as well.

A bus exists in the system in the form of a bus daemon, a process that specializes in passing messages from one process to another. The daemon also forwards notifications to all applications on the bus. At the lowest level, D-Bus only supports point-to-point communication, normally using the local domain sockets (AF_UNIX) between the application and the bus daemon. The point-to-point aspect of D-Bus is, however, abstracted by the bus daemon, which implements the addressing and message passing functionality. This means that applications do not need to care about which specific process receives each method call or notification.

According to the above-mentioned details, sending a message using D-Bus always involves the following steps (under normal conditions):

  • Creating and sending the message to the bus daemon. This causes a minimum of two context switches.
  • The bus daemon processing the message and forwarding it to the target process. Again, this causes a minimum of two context switches.
  • The target application receiving the message. Depending on the message type, the target application needs to acknowledge the message, respond to the message with a reply or ignore it. The last case is only possible with notifications (signals in D-Bus terminology). An acknowledgment or reply causes further context switches.

Coupled together, the above rules mean that if transferring large amounts of data between processes is planned, using D-Bus is not the most efficient way to do it. Instead, using a shared memory arrangement is recommended, although such arrangements are often quite complex to implement correctly.

[edit] Addressing and Names in D-Bus

The IPC mechanism needs to support some form of addressing so that the messages reach the intended recipient. The addressing scheme in D-Bus has been designed to be flexible yet efficient. Each bus has its private name space, which is not directly related to any other bus.

A destination address is needed for sending messages. The address is formed in a hierarchical manner from the following elements:

  • The bus on which the message is to be sent. A bus is normally opened only once per application lifetime. The bus connection is then used for sending and receiving messages for as long as necessary. This way, the target bus forms a transparent part of the message address (it is not specified separately for each message sent).
  • The well-known name for the service provided by the recipient. A close analogy to this is the DNS system in Internet, where people normally use names to connect to services, instead of specific IP addresses providing the services. The idea of the D-Bus well-known names is very similar, because the same service can be implemented in different ways in different applications. It should be noted, however, that currently most of the existing D-Bus services are "unique" in that each of them provides their own well-known name, and replacing one implementation with another is not common.
    • A well-known name consists of characters A-Z (lower or uppercase), dot characters, dashes and underscores. A well-known name must contain at least two dot-separated elements. Unlike DNS, the dots do not carry any additional information about management (zones), meaning that the well-known names are NOT hierarchical.
    • In order to reduce clashes in the D-Bus name space, the recommendation is that the name is formed by reversing the order of labels of a DNS domain that you own. A similar approach is used in Java for package names.
    • Examples: org.maemo.Alert and org.freedesktop.Notifications.
  • Each service can contain multiple different objects, each of which provides a different (or the same) service. In order to separate one object from another, object paths are used. A personal information manager (PIM) information store, for example, might include separate objects to manage the contact information and synchronization.
    • Object paths look like file paths (elements separated with the '/' character).
    • In D-Bus, "lazy binding" can also be made, so that a specific function in the recipient is called on all remote method calls, irrespective of the object paths in the calls. This allows the on-demand targeting of method calls, so that the user can remove a specific object in an address book service (using an object path similar to /org/maemo/AddressBook/Contacts/ShortName). Due to the limitations on characters that can be put into the object path, this is not recommended. A better way is to supply the ShortName as a method call argument instead (as a UTF-8 formatted string).
    • The object path is usually formed using the same elements as in the well-known name, but replacing the dots with slashes, and appending a specific object name to the end. For example: /org/maemo/Alert/Alerter. This is the common convention, but it also solves a specific problem if a process could re-use an existing D-Bus connection without explicitly knowing about it (using a library that encapsulates D-Bus functionality). In such cases, using short names increases the risk of name-space collisions within that process.
    • Object paths do not have inherent hierarchy, even if the path separator is used. The only place where some hierarchy can be seen because of the path components is the introspection interface (which is out of the scope of this material).
  • In order to support object-oriented mapping, where objects are the units providing the service, D-Bus also implements a naming unit called interface. The interface specifies the legal (defined and implemented) method calls, their parameters (called arguments in D-Bus) and possible signals. Thus, re-using the same interface across multiple separate objects implementing the same service is possible. More commonly, a single object can implement multiple different services. An example of the latter is the implementation of the org.freedesktop.DBus.Introspectable interface, which defines the method necessary to support D-Bus introspection. When using the GLib/D-Bus wrappers to generate parts of the D-Bus code, the objects support automatically also the introspection interface.
    • Interface names use the same naming rules as the well-known names. This can seem somewhat confusing in the beginning, because the well-known names serve a completely different purpose.
    • For simple services, the well-known name is often repeated in the interface name. This is the most common scenario with the existing services.
  • The last part of the message address is the member name. When dealing with remote procedure calls, the member name can sometimes be called method name, and when dealing with signals, it can be called signal name. The member name selects the procedure to call or the signal to emit. The name needs to be unique only within the interface that an object implements.
    • Member names can have letters, digits and underscores in them. For example, RetrieveQuote.
  • For more information, see the Introduction to D-Bus page.

Examples of all four components that are used for sending a simple message (a method call) in the SDK can be found below:

#define SYSNOTE_NAME  "org.freedesktop.Notifications"
#define SYSNOTE_OPATH "/org/freedesktop/Notifications"
#define SYSNOTE_IFACE "org.freedesktop.Notifications"
#define SYSNOTE_NOTE  "SystemNoteDialog"

When switching to the LibOSSO RPC functions (which encapsulate a lot of the D-Bus machinery), operations are still performed with all of the D-Bus naming components.

[edit] Role of D-Bus in Maemo

D-Bus has been selected as de facto IPC mechanism in Maemo, to carry messages between the various software components. The main reason for this is that a lot of software developed for the GNOME environment is already exposing its functionality through D-Bus. Using a generic interface, which is not bound to any specific service, makes it easier to deal with different software license requirements.

Unfortunately, the SDK is not delivered with many of the software products that are exposed via D-Bus. This document uses one component of the application framework for demonstration purposes (it also works in the SDK).

An item of particular interest is asking the notification framework component to display a Note dialog. The dialog is modal, which means that the user cannot proceed in their graphical environment unless they first acknowledge the dialog. Normally this kind of behavior in the GUI should be avoided, but a modal dialog can also be useful in certain circumstances.

The SystemNoteDialog member is an extension to the draft org.freedesktop.Notifications specification, and as such, it is not documented in the draft document.

The notification server is listening for method calls on the .freedesktop.Notifications well-known name. The object that implements the necessary interface is located at the /org/freedesktop/Notifications object path. The method to display the note dialog is called SystemNoteDialog and it is defined in the org.freedesktop.Notifications D-Bus interface.

D-Bus comes with a handy tool to experiment with method calls and signals: dbus-send. The following snippet attempts to use it to display the dialog:

 [sbox-DIABLO_X86: ~] > run-standalone.sh dbus-send --print-reply  \
--type=method_call --dest=org.freedesktop.Notifications  \
/org/freedesktop/Notifications org.freedesktop.Notifications
 Error org.freedesktop.DBus.Error.UnknownMethod: Method "Notifications" with
 signature "" on interface "org.freedesktop" does not exist

Parameters for dbus-send:

  • --session: (implicit because it is the default) which bus to use for sending (the other option being system)
  • --print-reply: ask the tool to wait for a reply to the method call, and print out the results (if any)
  • --type=method_call: instead of sending a signal (which is the default), make a method call
  • --dest=org.freedesktop.Notifications: the well-known name for the target service
  • /org/freedesktop/Notifications: object path within the target process that implements the interface
  • org.freedesktop.Notifications: (incorrectly specified) interface name defining the method

When using dbus-send, specify the interface and member names carefully. The tool expects both of them to be combined into one parameter (without spaces in between). Thus, modify the command line before a new try in the following way:

 [sbox-DIABLO_X86: ~] > run-standalone.sh dbus-send --print-reply  \
  --type=method_call --dest=org.freedesktop.Notifications  \
  /org/freedesktop/Notifications org.freedesktop.Notifications.SystemNoteDialog
 Error org.freedesktop.DBus.Error.UnknownMethod: Method "SystemNoteDialog" with
  signature "" on interface "org.freedesktop.Notifications" does not exist

Most RPC methods expect a series of parameters (or arguments, as D-Bus calls them).

SystemNoteDialog expects these three parameters (in the following order):

  • string: The message to display.
  • uint32: An unsigned integer giving the style of the dialog. Styles 0-4 mean different icons, and style 5 is a special animated "progress indicator" dialog.
  • string: Message to use for the "OK" button that the user needs to press to dismiss the dialog. Using an empty string causes the default text to be used (which is "OK").

Arguments are specified by giving the argument type and its contents separated with a colon as follows:

[sbox-DIABLO_X86: ~] > run-standalone.sh dbus-send --print-reply  \
 --type=method_call --dest=org.freedesktop.Notifications  \
 /org/freedesktop/Notifications org.freedesktop.Notifications.SystemNoteDialog  \
 string:'Hello, world!' uint32:0 string:'NAO OK!'
method return sender=:1.1 -> dest=:1.15
   uint32 4

Because dbus-send was asked to print replies, the reply comes out as a single unsigned integer, with the value 4. This is the unique number for this notification and can be used with the CloseNotification method of the Notifications interface to pre-emptively close the dialog. It is useful if the software notices that some warning condition has ended and there is no need to bother the user with the warning anymore.

Assuming that the above command is run while the application framework is already running, the end result looks like this:

Screenshot of Note dialog showing text ‘Hello, world!’
System note dialog

If the command is repeated multiple times, the notification service is capable of displaying only one dialog at a time. This makes sense because the dialog is modal. Furthermore, the method calls are queued, not lost; the notification service displays all of the requested dialogs. The service also acknowledges the RPC method call without delay (which is not always the obvious thing to do), giving a different return value each time (incrementing by one each time).

[edit] Programming Directly with libdbus

The lowest level library to be used for D-Bus programming is libdbus. Using this library directly is discouraged, mostly because it contains a lot of specific code to integrate into various main-loop designs that the higher level language bindings use.

The libdbus API reference documentation contains a helpful note:

/**
 * Uses the low-level libdbus which should not be used directly.
 * As the D-Bus API reference puts it "If you use this low-level API
 * directly, you are signing up for some pain".
 */

At this point, this example ignores the warnings, and uses the library to implement a simple program that replicates the earlier dbus-send example. To do this with the minimum amount of code, the code does not process (or expect) any responses to the method call. However, the code demonstrates the bare minimum function calls that are needed to send messages on the bus.

The first step is to introduce the necessary header files. libdbus-example/dbus-example.c

#include <dbus/dbus.h> /* Pull in all of D-Bus headers. */
#include <stdio.h>     /* printf, fprintf, stderr */
#include <stdlib.h>    /* EXIT_FAILURE, EXIT_SUCCESS */
#include <assert.h>    /* assert */
/* Symbolic defines for the D-Bus well-known name, interface, object
   path and method name that we are going to use. */
#define SYSNOTE_NAME  "org.freedesktop.Notifications"
#define SYSNOTE_OPATH "/org/freedesktop/Notifications"
#define SYSNOTE_IFACE "org.freedesktop.Notifications"
#define SYSNOTE_NOTE  "SystemNoteDialog"

Unlike the rest of the code in this material, the dbus example does not use GLib or other support libraries (other than libdbus). This explains why the example uses printf and other functions that are normally replaced with GLib equivalents.

Connecting to the session bus yields a DBusConnection structure: libdbus-example/dbus-example.c

/**
 * The main program that demonstrates a simple "fire & forget" RPC
 * method invocation.
 */
int main(int argc, char** argv) {
 
  /* Structure representing the connection to a bus. */
  DBusConnection* bus = NULL;
  /* The method call message. */
  DBusMessage* msg = NULL;
 
  /* D-Bus reports problems and exceptions using the DBusError
     structure. We allocate one in stack (so that we don't need to
     free it explicitly. */
  DBusError error;
 
  /* Message to display. */
  const char* dispMsg = "Hello World!";
  /* Text to use for the acknowledgement button. "" means default. */
  const char* buttonText = "";
  /* Type of icon to use in the dialog (1 = OSSO_GN_ERROR). We could
     have just used the symbolic version here as well, but that would
     have required pulling the LibOSSO-header files. And this example
     must work without LibOSSO, so this is why a number is used. */
  int iconType = 1;
 
  /* Clean the error state. */
  dbus_error_init(&error);
 
  printf("Connecting to Session D-Bus\n");
  bus = dbus_bus_get(DBUS_BUS_SESSION, &error);
  terminateOnError("Failed to open Session bus\n", &error);
  assert(bus != NULL);

Libdbus attempts to share the existing connection structures when the same process is connecting to the same bus. This is done to avoid the costly connection set-up time. Sharing connections is beneficial when the program is using libraries that would also open their own connections to the same buses.

To communicate errors, libdbus uses DBusError structures, whose contents are simple. The dbus_error_init is used for guaranteeing that the error structure contains a non-error state before connecting to the bus. If there is an error, it is handled in terminateOnError: libdbus-example/dbus-example.c

/**
 * Utility to terminate if given DBusError is set.
 * Prints out the message and error before terminating.
 *
 * If error is not set, does nothing.
 *
 * NOTE: In real applications you should spend a moment or two
 *       thinking about the exit-paths from your application and
 *       whether you need to close/unreference all resources that you
 *       have allocated. In this program, we rely on the kernel to do
 *       all necessary cleanup (closing sockets, releasing memory),
 *       but in real life you need to be more careful.
 *
 *       One possible solution model to this is implemented in
 *       "flashlight", a simple program that is presented later.
 */
static void terminateOnError(const char* msg,
                             const DBusError* error) {
 
  assert(msg != NULL);
  assert(error != NULL);
 
  if (dbus_error_is_set(error)) {
    fprintf(stderr, msg);
    fprintf(stderr, "DBusError.name: %s\n", error->name);
    fprintf(stderr, "DBusError.message: %s\n", error->message);
    /* If the program does not exit because of the error, freeing the
       DBusError needs to be done (with dbus_error_free(error)).
       NOTE:
         dbus_error_free(error) would only free the error if it was
         set, so it is safe to use even when you are unsure. */
    exit(EXIT_FAILURE);
  }
}

libdbus also contains some utility functions so that everything does not have to be coded manually. One such utility is dbus_bus_name_has_owner, that checks whether there is at least some process that owns the given well-known name at that moment: libdbus-example/dbus-example.c

  /* Normally one would just do the RPC call immediately without
     checking for name existence first. However, sometimes it is useful
     to check whether a specific name even exists on a platform on
     which you are planning to use D-Bus.
 
     In our case it acts as a reminder to run this program using the
     run-standalone.sh script when running in the SDK.
 
     The existence check is not necessary if the recipient is
     startable/activateable by D-Bus. In that case, if the recipient
     is not already running, the D-Bus daemon starts the
     recipient (a process that has been registered for that
     well-known name) and then passes the message to it. This
     automatic starting mechanism avoids the race condition
     discussed below and also makes sure that only one instance of
     the service is running at any given time. */
  printf("Checking whether the target name exists ("
         SYSNOTE_NAME ")\n");
  if (!dbus_bus_name_has_owner(bus, SYSNOTE_NAME, &error)) {
    fprintf(stderr, "Name has no owner on the bus!\n");
    return EXIT_FAILURE;
  }
  terminateOnError("Failed to check for name ownership\n", &error);
  /* Someone on the Session bus owns the name. So we can proceed in
     relative safety. There is a chance of a race. If the name owner
     decides to drop out from the bus just after we check that it is
     owned, our RPC call (below) fails anyway. */

Creating a method call using libdbus is slightly more tedious than using the higher-level interfaces. The process is separated into two steps: creating a message structure, and appending the arguments to the message: libdbus-example/dbus-example.c

  /* Construct a DBusMessage that represents a method call.
     Parameters are added later. The internal type of the message
     is DBUS_MESSAGE_TYPE_METHOD_CALL. */
  printf("Creating a message object\n");
  msg = dbus_message_new_method_call(SYSNOTE_NAME, /* destination */
                                     SYSNOTE_OPATH,  /* obj. path */
                                     SYSNOTE_IFACE,  /* interface */
                                     SYSNOTE_NOTE); /* method str */
  if (msg == NULL) {
    fprintf(stderr, "Ran out of memory when creating a message\n");
    exit(EXIT_FAILURE);
  }
 
  /*... Listing cut for brevity ...*/
 
  /* Add the arguments to the message. For the Note dialog, we need
     three arguments:
       arg0: (STRING) "message to display, in UTF-8"
       arg1: (UINT32) type of dialog to display. We use 1.
                      (libosso.h/OSSO_GN_ERROR).
       arg2: (STRING) "text to use for the ack button". "" means
                      default text (OK in our case).
 
     When listing the arguments, the type needs to be specified first
     (by using the libdbus constants) and then a pointer to the
     argument content needs to be given.
 
     NOTE: It is always a pointer to the argument value, not the value
           itself!
 
     We terminate the list with DBUS_TYPE_INVALID. */
  printf("Appending arguments to the message\n");
  if (!dbus_message_append_args(msg,
                                DBUS_TYPE_STRING, &dispMsg,
                                DBUS_TYPE_UINT32, &iconType,
                                DBUS_TYPE_STRING, &buttonText,
                                DBUS_TYPE_INVALID)) {
    fprintf(stderr, "Ran out of memory while constructing args\n");
    exit(EXIT_FAILURE);
  }

When arguments are appended to the message, their content is copied, and possibly converted into a format that is sent over the connection to the daemon. This process is called marshaling, and is a common feature to most RPC systems. The method call requires two parameters (as before), the first being the text to be displayed, and the second being the style of the icon to be used. Parameters passed to libdbus are always passed by address. This is different from the higher level libraries.

The arguments are encoded, so that their type code is followed by the pointer where the marshaling functions can find the content. The argument list is terminated with DBUS_TYPE_INVALID, so that the function knows where the argument list ends (since the function prototype ends with an ellipsis, ...). libdbus-example/dbus-example.c

  /* Set the "no-reply-wanted" flag into the message. This also means
     that we cannot reliably know whether the message was delivered or
     not, but because we do not have reply message handling here, it
     does not matter. The "no-reply" is a potential flag for the remote
     end so that they know that they do not need to respond to us.
     If the no-reply flag is set, the D-Bus daemon makes sure that the
     possible reply is discarded and not sent to us. */
  dbus_message_set_no_reply(msg, TRUE);

Setting the no-reply-flag effectively tells the bus daemon that even if there is a reply coming back for this RPC method, it is not wanted. In this case, the daemon does not send a reply.

Once the message is fully constructed, it can be added to the sending queue of the program. Messages are not sent immediately by libdbus. Normally this allows the message queue to accumulate to more than one message, and all of the messages are sent at once to the daemon. This in turn cuts down the number of the necessary context switches. In this case, this message is the only message that the program ever sends, so the send queue is instructed to be flushed immediately, which in turn instructs the library to send all messages to the daemon without a delay: libdbus-example/dbus-example.c

  printf("Adding message to client's send-queue\n");
  /* We could also get a serial number (dbus_uint32_t) for the message
     so that we could correlate responses to sent messages later. In
     our case there is not going to be a response anyway, so we do not care about
     the serial, so we pass a NULL as the last parameter. */
  if (!dbus_connection_send(bus, msg, NULL)) {
    fprintf(stderr, "Ran out of memory while queueing message\n");
    exit(EXIT_FAILURE);
  }
 
  printf("Waiting for send-queue to be sent out\n");
  dbus_connection_flush(bus);
 
  printf("Queue is now empty\n");

After the message is sent, the reserved resources must be freed. Here, the first one to be freed is the message, and then the connection structure. libdbus-example/dbus-example.c

  printf("Cleaning up\n");
 
  /* Free up the allocated message. Most D-Bus objects have internal
     reference count and sharing possibility, so _unref() functions
     are quite common. */
  dbus_message_unref(msg);
  msg = NULL;
 
  /* Free-up the connection. libdbus attempts to share existing
     connections for the same client, so instead of closing down a
     connection object, it is unreferenced. The D-Bus library
     keeps an internal reference to each shared connection, to
     prevent accidental closing of shared connections before the
     library is finalized. */
  dbus_connection_unref(bus);
  bus = NULL;
 
  printf("Quitting (success)\n");
 
  return EXIT_SUCCESS;
}

After building the program, attempt to run it:

 [sbox-DIABLO_X86: ~/libdbus-example] > ./dbus-example
Connecting to Session D-Bus
process 6120: D-Bus library appears to be incorrectly set up;
 failed to read machine uuid:
  Failed to open "/var/lib/dbus/machine-id": No such file or directory
See the manual page for dbus-uuidgen to correct this issue.
  D-Bus not built with -rdynamic so unable to print a backtrace
Aborted (core dumped)

The D-Bus library needs environmental variables set correctly in order to locate the session daemon. The command was not prepended with run-standalone.sh, and this caused the library to internally abort the execution. Normally, dbus_bus_get returns a NULL pointer and sets the error structure, but the version on the 4.1 SDK asserts internally in this condition, and programs cannot avoid the abort. After correcting this, try again:

 [sbox-DIABLO_X86: ~/libdbus-example] > run-standalone.sh ./dbus-example
Connecting to Session D-Bus
Checking whether the target name exists (org.freedesktop.Notifications)
Creating a message object
Appending arguments to the message
Adding message to client's send-queue
Waiting for send-queue to be sent out
Queue is now empty
Cleaning up
Quitting (success)
/dev/dsp: No such file or directory

The error message (about /dev/dsp) printed to the same terminal where AF was started is normal behavior (in SDK). Displaying the Note dialog normally also causes an "Alert" sound to be played. The sound system has not been setup in the SDK, so the notification component complains about failing to open the sound device.

Screenshot of message ‘Hello World!’
The friendly error message, using low-level D-Bus

To get libdbus integrated into makefiles, use pkg-config. One possible solution is presented below (see section GNU Make and Makefiles in chapter GNU Build System, if necessary): libdbus-example/Makefile

# Define a list of pkg-config packages we want to use
pkg_packages := dbus-glib-1
PKG_CFLAGS  := $(shell pkg-config -cflags $(pkg_packages))
PKG_LDFLAGS := $(shell pkg-config -libs $(pkg_packages))
# Additional flags for the compiler:
#    -g : Add debugging symbols
# -Wall : Enable most gcc warnings
ADD_CFLAGS := -g -Wall
# Combine user supplied, additional, and pkg-config flags
CFLAGS  := $(PKG_CFLAGS) $(ADD_CFLAGS) $(CFLAGS)
LDFLAGS := $(PKG_LDFLAGS) $(LDFLAGS)

The above example shows one possibility to integrate user-supplied variables into makefiles, so that they are still passed along the toolchain. This allows the user to execute make with custom flags, overriding those that are introduced using other means. For example: "CFLAGS='-g0' make" results in the -g0 being interpreted after the -g that is in the Makefile, and this leads to debugging symbols being disabled. Environmental variables can be taken into account in exactly the same way.

For more complicated programs, that multiple different CFLAGS settings are probably required for different object files or multiple different programs that are being built. In that case, the combining in each target rule is performed separately. In this material, all the example programs are self-contained and rather simple, so the above-mentioned mechanism is used in all example makefiles.