Sign in Join
Wiki copytemporary

FPC and DBus: what changed

Revision 0 to 1. Removed lines have a minus sign; added lines have a plus sign.

Title: FPC and DBus

OldNewLine
1+## Overview
2+
3+DBUS is a GNU library that implements inter-process communication. It's the default library of this kind for GNU applications. It can often be found on Linux machines.
4+
5+This library provides a simple way for applications to talk to one another, using a bus sytem. These headers are the translation of the low-level C API for DBUS. In the future it is desirable that these headers be wrapped around a class to make their use easier.
6+
7+## Documentation
8+
9+Independently from what you want to achieve, a lot of the code for a program that uses DBUS will be very similar. This is the startup and finalization code.
10+
11+### Startup
12+
13+On startup you need to connect to the bus. Usually there is a system and a session bus. Depending on the configuration of the system, you may not have access to the system bus. Next you need to request a name on the bus. Below is some simple startup code.
14+
15+``` pascal
16+var
17+ err: DBusError;
18+ conn: PDBusConnection;
19+ ret: cint;
20+begin
21+ { Initializes the error handling }
22+ dbus_error_init(@err);
23+
24+ { Connection }
25+ conn := dbus_bus_get(DBUS_BUS_SESSION, @err);
26+
27+ if dbus_error_is_set(@err) <> 0 then
28+ begin
29+ WriteLn('Connection Error: ' + err.message);
30+ dbus_error_free(@err);
31+ end;
32+
33+ if conn = nil then Exit;
34+
35+ { Request the name of the bus }
36+ ret := dbus_bus_request_name(conn, 'test.method.server', DBUS_NAME_FLAG_REPLACE_EXISTING, @err);
37+
38+ if dbus_error_is_set(@err) <> 0 then
39+ begin
40+ WriteLn('Name Error: ' + err.message);
41+ dbus_error_free(@err);
42+ end;
43+
44+ if ret <> DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER then Exit;
45+
46+ ....
47+```
48+
49+### Shutdown
50+
51+When you no longer need the bus, you should close the connection. A good place to do this in most cases is right before the application terminates. The method used to do this depends on whether the connection is shared or private. Private connections are created using dbus_connection_open_private() or dbus_bus_get_private() and are closed using dbus_connection_close();
52+
53+``` pascal
54+ { Finalization }
55+ dbus_connection_close(conn);
56+```
57+
58+Shared connections, created using dbus_connection_open() or dbus_bus_get() are owned by libdbus and applications should only unref them, never close them. Most connections are shared connections.
59+
60+``` pascal
61+ { Finalization }
62+ dbus_connection_unref(conn);
63+```
64+
65+### Sending a Signal
66+
67+Signals are broadcasts from a DBus object to any client applications that require the information that it carries. A signal message contains the name of the interface that specifies the signal; the name of the signal; the bus name of the process sending the signal; and any arguments.
68+
69+The originating application first creates a signal message with dbus_message_new_signal(), then appends any arguments before sending with dbus_connection_send().
70+
71+``` pascal
72+procedure SendSignalExample;
73+var
74+ DBusSerial: cardinal;
75+ err: DBusError;
76+ conn: PDBusConnection;
77+ ret: cint;
78+ msg: PDBusMessage;
79+ args: DBusMessageIter;
80+ SignalData: PChar;
81+begin
82+ DBusSerial := 0;
83+ SignalData := 'This string is sent with the signal';
84+
85+ // initialise the error value
86+ dbus_error_init(@err);
87+
88+ // connect to the DBUS system bus and check for errors
89+ conn := dbus_bus_get(DBUS_BUS_SESSION, @err);
90+ if (0 <> dbus_error_is_set(@err)) then
91+ begin
92+ writeln('Connection Error :', err.message);
93+ dbus_error_free(@err);
94+ end;
95+ if conn = nil then
96+ exit;
97+
98+ // request a name on the bus and check for errors
99+ ret := dbus_bus_request_name(conn, 'test.signal.source',
100+ DBUS_NAME_FLAG_REPLACE_EXISTING, @err);
101+ if (0 <> dbus_error_is_set(@err)) then
102+ begin
103+ writeln('Error: ', err.message);
104+ dbus_error_free(@err);
105+ end;
106+ if ret <> DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER then
107+ exit;
108+
109+ // create a signal and check for errors
110+ msg := dbus_message_new_signal('/test/signal/Object', // object name
111+ 'test.signal.Type', // interface name
112+ 'TestSignal'); // signal name
113+ if msg = nil then
114+ begin
115+ writeln('msg is nil');
116+ exit;
117+ end;
118+ // initialise argument payload
119+ dbus_message_iter_init_append(msg, @args);
120+
121+ // append arguments onto signal
122+ if (0 = dbus_message_iter_append_basic(@args, DBUS_TYPE_STRING, @SignalData)) then
123+ begin
124+ writeln('Out of memory(1)');
125+ exit;
126+ end;
127+
128+ // send the message and flush the connection
129+ if (0 = dbus_connection_send(conn, msg, @DBusSerial)) then
130+ begin
131+ writeln('Out of memory(2)');
132+ exit;
133+ end;
134+ dbus_connection_flush(conn);
135+
136+ // free the message and finish using the connection
137+ dbus_message_unref(msg);
138+ dbus_connection_unref(conn);
139+end;
140+```
141+
142+### Receiving a Signal
143+
144+In order to receive a signal a client application needs to register a "match rule" with DBus.The bus daemon examines the signal and identifies processes which are interested in it. It then sends the signal message to these processes.
145+
146+``` pascal
147+ // receive signals from interface "test.signal.Type"
148+ dbus_bus_add_match(conn, 'type=''signal'',interface=''test.signal.Type''', @err);
149+ dbus_connection_flush(conn);
150+ if (0<>dbus_error_is_set(@err)) then
151+ begin
152+ writeln('Match error: ', err.message);
153+ exit;
154+ end;
155+```
156+
157+### Calling a Method
158+
159+Client applications call methods to instruct a DBus object to execute a procedure or function. Methods may require input parameters and may return output data.
160+
161+This example connects to the System Bus and then calls the GetNetworkInterfaceNameByIndex() method of the org.freedesktop.Avahi.Server interface. The reply includes a string value which contains the network interface name.
162+
163+``` pascal
164+procedure CallMethodExample;
165+var
166+ err: DBusError;
167+ conn: PDBusConnection;
168+ msg, replymsg: PDBusMessage;
169+ args, replyargs: DBusMessageIter;
170+ Value: Int32;
171+ interfacename: PChar;
172+begin
173+ //initialise parameter value for example
174+ Value := 1;
175+
176+ // initialise the error value
177+ dbus_error_init(@err);
178+
179+ // connect to the DBUS system bus and check for errors
180+ conn := dbus_bus_get(DBUS_BUS_SYSTEM, @err);
181+ if (0 <> dbus_error_is_set(@err)) then
182+ begin
183+ writeln('Connection Error :', err.message);
184+ dbus_error_free(@err);
185+ end;
186+ if conn = nil then
187+ exit;
188+
189+ // create message and check for errors
190+ msg := dbus_message_new_method_call('org.freedesktop.Avahi', '/',
191+ 'org.freedesktop.Avahi.Server', 'GetNetworkInterfaceNameByIndex');
192+ if (msg = nil) then
193+ begin
194+ WriteLn('Could not construct message: ' + err.message);
195+ dbus_error_free(@err);
196+ end;
197+
198+ // initialise parameter list for appending
199+ dbus_message_iter_init_append(msg, @args);
200+
201+ // add parameter argument
202+ if (0 = dbus_message_iter_append_basic(@args, DBUS_TYPE_INT32, @Value)) then
203+ begin
204+ writeln('Out Of Memory!');
205+ exit;
206+ end;
207+
208+ // send message and block while waiting for reply
209+ replymsg := dbus_connection_send_with_reply_and_block(conn, msg, 1000, @err);
210+
211+ if (dbus_error_is_set(@err) <> 0) then
212+ begin
213+ WriteLn('Error waiting for reply: ' + err.message);
214+ dbus_error_free(@err);
215+ end;
216+
217+ // initialise reply argument list then check type of return value
218+ // before retrieving value
219+ if (dbus_message_iter_init(replymsg, @replyargs) = 0) then
220+ writeln('No return value')
221+ else if (DBUS_TYPE_STRING <> dbus_message_iter_get_arg_type(@replyargs)) then
222+ Writeln('Return value is not a string')
223+ else
224+ dbus_message_iter_get_basic(@replyargs, @interfacename);
225+ if (interfacename <> nil) then
226+ Writeln(interfacename);
227+
228+ // free the messages and finish using the connection
229+ dbus_message_unref(replymsg);
230+ dbus_message_unref(msg);
231+ dbus_connection_unref(conn);
232+end;
233+```
234+
235+This example uses dbus_connection_send_with_reply_and_block() to call the method and retrieve the return message. This is the simplest way of retrieving the reply but will cause problems if the method may take some time to complete. Two other DBus functions exist which can be used in such situations: dbus_connection_send() and dbus_connection_send_with_reply(). The first of these requires code which waits for incoming messages and intercepts the reply, while the second sends a message and registers a [[callback]] which will be executed when a reply is received.
236+
237+### Responding to Method calls
238+
239+### Properties
240+
241+A DBus object may also have properties which can be read and, optionally, set. Properties are accessed by calling the Get method of the org.freedesktop.DBus.Properties interface.
242+
243+``` pascal
244+ // create message and check for errors
245+ msg := dbus_message_new_method_call('org.freedesktop.NetworkManager',
246+ '/org/freedesktop/NetworkManager', 'org.freedesktop.DBus.Properties', 'Get');
247+ if (msg = nil) then
248+ begin
249+ WriteLn('Could not construct message: ' + err.message);
250+ dbus_error_free(@err);
251+ end;
252+
253+ v1 := 'org.freedesktop.NetworkManager';
254+ v2 := 'WirelessEnabled';
255+
256+ dbus_message_iter_init_append(msg, @args);
257+ if (0=dbus_message_iter_append_basic(@args, DBUS_TYPE_STRING, @v1)) then
258+ begin
259+ writeln('Out Of Memory!');
260+ exit;
261+ end;
262+ if (0=dbus_message_iter_append_basic(@args, DBUS_TYPE_STRING, @v2)) then
263+ begin
264+ writeln('Out Of Memory!');
265+ exit;
266+ end;
267+```
268+
269+A call to org.freedesktop.DBus.Properties.Get returns a value of type DBUS_TYPE_VARIANT which points to another structure of type DBusMessageIter which contains the return values. This is accessed using dbus_message_iter_recurse().
270+
271+``` pascal
272+ if (dbus_message_iter_init(replymsg, @replyargs) = 0) then
273+ writeln('No return value')
274+ else if (DBUS_TYPE_VARIANT = dbus_message_iter_get_arg_type(@replyargs)) then
275+ begin
276+ dbus_message_iter_recurse(@replyargs, @subargs);
277+ if (DBUS_TYPE_BOOLEAN <> dbus_message_iter_get_arg_type(@subargs)) then
278+ Writeln('Return value is not boolean')
279+ else
280+ dbus_message_iter_get_basic(@subargs, @dbusbool);
281+ if (dbusbool = 1) then
282+ writeln('TRUE')
283+ else
284+ writeln('FALSE');
285+ end;
286+```
287+
288+## Authors
289+
290+Felipe Monteiro de Carvalho
291+
292+## License
293+
294+## Status
295+
296+Status: Beta
297+
298+## Download
299+
300+### Installed by default
301+
302+The FPC package for DBUS resides in packages/[[dbus]] in the FPC (2.2.2+) packages tree.
303+
304+You can download a full FPC repository and it will be included.
305+
306+### Older versions
307+
308+For older versions: you can download the subversion version of this project using this command:
309+
310+``` bash
311+svn checkout http://svn.freepascal.org/svn/fpc/trunk/packages/dbus dbus
312+```
313+
314+### Pascal components
315+
316+Michael Van Canneyt has written DBus components which can be found in dbuscomp.pp in the [source code](https://www.freepascal.org/~michael/articles/dbus2/dbus-code.zip) which accompanies one of his articles on DBus. The components provide a flying start to using the protocol with Pascal although they do not cover every aspect of using DBus (eg. handling Properties) and do contain some bugs: the code in procedure TDBusMessage.EndGet should be commented out because this makes it impossible to retrieve more than one value from a DBus message.
317+
318+## Bug Reporting
319+
320+Tests are necessary to verify if all functions and structures are declared properly. Tests were done on Windows, FreeBSD and Linux operating systems. It is necessary to test if the modules work correctly in other operating system.
321+
322+You can post Bug Reports to the [regular bug tracker](http://bugs.freepascal.org) (make sure to choose the FPC project and select the Packages category)
323+
324+## Change Log
325+
326+- ??.??.06 DBus headers version 0.1
327+
328+1. Under construction
329+
330+- 03.11.2010 Updated DBus headers to version 1.2.16
331+
332+## Help
333+
334+Please send help requests to the Free Pascal mailling list or on apache-modules mailing list.
335+
336+## See also
337+
338+- [1](http://www.matthew.ath.cx/misc/dbus) - A Tutorial about using the DBus C API
339+- [2](https://www.freepascal.org/~michael/articles/#dbus2) - An introduction to using DBus with FPC, with source code
340+- [3](https://blog.avichalp.me/an-introduction-to-dbus-e89ad93c874d) - An overview of DBus with a concise glossary of concepts
341+
342+---
343+*From the Free Pascal wiki, page "FPC and DBus", as it stood on 2021-10-25 after a change by Kai Burghardt, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).*

Back to history