em-ruby-dbus 0.11.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/COPYING +504 -0
- data/NEWS +253 -0
- data/README.md +93 -0
- data/Rakefile +58 -0
- data/VERSION +1 -0
- data/doc/Reference.md +207 -0
- data/doc/Tutorial.md +480 -0
- data/doc/ex-calling-methods.body.rb +8 -0
- data/doc/ex-calling-methods.rb +3 -0
- data/doc/ex-properties.body.rb +9 -0
- data/doc/ex-properties.rb +3 -0
- data/doc/ex-setup.rb +7 -0
- data/doc/ex-signal.body.rb +20 -0
- data/doc/ex-signal.rb +3 -0
- data/doc/example-helper.rb +6 -0
- data/em-ruby-dbus.gemspec +20 -0
- data/examples/gdbus/gdbus +255 -0
- data/examples/gdbus/gdbus.glade +184 -0
- data/examples/gdbus/launch.sh +4 -0
- data/examples/no-introspect/nm-test.rb +21 -0
- data/examples/no-introspect/tracker-test.rb +16 -0
- data/examples/rhythmbox/playpause.rb +25 -0
- data/examples/service/call_service.rb +25 -0
- data/examples/service/service_newapi.rb +51 -0
- data/examples/simple/call_introspect.rb +34 -0
- data/examples/simple/properties.rb +19 -0
- data/examples/utils/listnames.rb +11 -0
- data/examples/utils/notify.rb +19 -0
- data/lib/dbus.rb +82 -0
- data/lib/dbus/auth.rb +269 -0
- data/lib/dbus/bus.rb +739 -0
- data/lib/dbus/core_ext/array/extract_options.rb +31 -0
- data/lib/dbus/core_ext/class/attribute.rb +129 -0
- data/lib/dbus/core_ext/kernel/singleton_class.rb +8 -0
- data/lib/dbus/core_ext/module/remove_method.rb +14 -0
- data/lib/dbus/error.rb +46 -0
- data/lib/dbus/export.rb +128 -0
- data/lib/dbus/introspect.rb +219 -0
- data/lib/dbus/logger.rb +31 -0
- data/lib/dbus/loop-em.rb +19 -0
- data/lib/dbus/marshall.rb +434 -0
- data/lib/dbus/matchrule.rb +101 -0
- data/lib/dbus/message.rb +276 -0
- data/lib/dbus/message_queue.rb +166 -0
- data/lib/dbus/proxy_object.rb +149 -0
- data/lib/dbus/proxy_object_factory.rb +41 -0
- data/lib/dbus/proxy_object_interface.rb +128 -0
- data/lib/dbus/type.rb +193 -0
- data/lib/dbus/xml.rb +161 -0
- data/test/async_spec.rb +47 -0
- data/test/binding_spec.rb +74 -0
- data/test/bus_and_xml_backend_spec.rb +39 -0
- data/test/bus_driver_spec.rb +20 -0
- data/test/bus_spec.rb +20 -0
- data/test/byte_array_spec.rb +38 -0
- data/test/err_msg_spec.rb +42 -0
- data/test/introspect_xml_parser_spec.rb +26 -0
- data/test/introspection_spec.rb +32 -0
- data/test/main_loop_spec.rb +82 -0
- data/test/property_spec.rb +53 -0
- data/test/server_robustness_spec.rb +66 -0
- data/test/server_spec.rb +53 -0
- data/test/service_newapi.rb +217 -0
- data/test/session_bus_spec_manual.rb +15 -0
- data/test/signal_spec.rb +90 -0
- data/test/spec_helper.rb +33 -0
- data/test/thread_safety_spec.rb +31 -0
- data/test/tools/dbus-launch-simple +35 -0
- data/test/tools/dbus-limited-session.conf +28 -0
- data/test/tools/test_env +13 -0
- data/test/tools/test_server +39 -0
- data/test/type_spec.rb +19 -0
- data/test/value_spec.rb +81 -0
- data/test/variant_spec.rb +66 -0
- metadata +145 -0
data/doc/Tutorial.md
ADDED
@@ -0,0 +1,480 @@
|
|
1
|
+
<style>
|
2
|
+
code { background-color: #F0E7E7; }
|
3
|
+
pre code { background-color: #F0DDDD; }
|
4
|
+
pre {
|
5
|
+
font-size: 90%;
|
6
|
+
overflow: hidden;
|
7
|
+
padding-left: 10pt;
|
8
|
+
border: thin solid #F0B4B4;
|
9
|
+
background-color: #F0DDDD;
|
10
|
+
}
|
11
|
+
</style>
|
12
|
+
|
13
|
+
Welcome
|
14
|
+
=======
|
15
|
+
|
16
|
+
This is the Ruby D-Bus tutorial. It aims to show you the features of Ruby
|
17
|
+
D-Bus and as you read through the tutorial also how to use them.
|
18
|
+
|
19
|
+
© Arnaud Cornet and Paul van Tilburg; this tutorial is part of
|
20
|
+
free software; you can redistribute it and/or modify it under the
|
21
|
+
terms of the [GNU Lesser General Public License,
|
22
|
+
version 2.1](http://www.gnu.org/licenses/lgpl.html) as published by the
|
23
|
+
[Free Software Foundation](http://www.fsf.org/).
|
24
|
+
|
25
|
+
Introduction
|
26
|
+
============
|
27
|
+
|
28
|
+
This is a tutorial for Ruby D-Bus, a library to access D-Bus facilities of your
|
29
|
+
system.
|
30
|
+
|
31
|
+
What is D-Bus?
|
32
|
+
--------------
|
33
|
+
|
34
|
+
D-Bus is an RPC(Remote Procedure Call) protocol. A common setup can have
|
35
|
+
multiple D-Bus daemons running that route procedure calls and signals in
|
36
|
+
the form of messages. Each of these daemons supports a bus. A bus that
|
37
|
+
is often used by modern desktop environments, and is available per session, is
|
38
|
+
called the _session bus_. Another bus that can be available, but in a
|
39
|
+
system-wide manner, is called the _system bus_. It is used for example by
|
40
|
+
the [Hardware Abstraction Layer](http://hal.freedesktop.org/) daemon. Note
|
41
|
+
that theoretically the D-Bus RPC protocol can be used without a system or
|
42
|
+
session bus. I never came across any actual use of this though.
|
43
|
+
|
44
|
+
At the desktop level, D-Bus allows some components to interact. Typically
|
45
|
+
if you are writing an application or a personal script that wants to
|
46
|
+
interact with your web browser, your music player, or that simply wants to
|
47
|
+
pop-up a desktop notification, D-Bus comes into play.
|
48
|
+
|
49
|
+
At the system level, the Hardware Abstraction Layer is a privileged daemon
|
50
|
+
that notifies other software of hardware activities. Typically, if you
|
51
|
+
want to be notified if a CD-ROM has been loaded in, of if you want to
|
52
|
+
explore hardware, the system daemon comes into play.
|
53
|
+
|
54
|
+
The D-Bus RPC system is as we will see _object oriented_.
|
55
|
+
|
56
|
+
Buses provide access to _services_ provided in turn by running or ready to
|
57
|
+
run processes. Let me introduce some D-Bus terminology before we discuss
|
58
|
+
the API of Ruby D-Bus.
|
59
|
+
|
60
|
+
Client
|
61
|
+
------
|
62
|
+
|
63
|
+
A D-Bus client is a process that connects to a D-Bus. They issue method
|
64
|
+
calls and register to the bus for signals and events.
|
65
|
+
|
66
|
+
Service
|
67
|
+
-------
|
68
|
+
|
69
|
+
A connected client can export some of its objects and let other clients
|
70
|
+
call some of its methods. Such clients typically register a special name
|
71
|
+
like `org.freedesktop.Notifications`, the service name.
|
72
|
+
|
73
|
+
There is slightly different type of service. They are provided by
|
74
|
+
processes that can be launched by a D-Bus daemon on demand. Once they are
|
75
|
+
started by D-Bus they register a service name and behave like another
|
76
|
+
client.
|
77
|
+
|
78
|
+
Note that the buses themselves provide the `org.freedesktop.DBus` service,
|
79
|
+
and provide some features through it.
|
80
|
+
|
81
|
+
Object path
|
82
|
+
-----------
|
83
|
+
|
84
|
+
An object path is the D-Bus way to specify an object _instance_ address. A
|
85
|
+
service can provide different object instances to the outside world, so
|
86
|
+
that external processes can call methods on each of them. An object path
|
87
|
+
is an address of an instance in a very similar way that the path is an
|
88
|
+
address of a file on a file system. For example:
|
89
|
+
`/org/freedesktop/Notification` is an object path of an object provided by
|
90
|
+
the `org.freedesktop.Notification` service
|
91
|
+
|
92
|
+
**Beware**: service names and object paths can, but do _not_ have to be
|
93
|
+
related! You'll probably encounter a lot of cases though, where the
|
94
|
+
object path is a slashed version of the dotted service name.
|
95
|
+
|
96
|
+
Interface
|
97
|
+
---------
|
98
|
+
|
99
|
+
Classically in an object model, classes can implement interfaces. That is,
|
100
|
+
some method definitions grouped in an interface. This is exactly what a
|
101
|
+
D-Bus interface is as well. In D-Bus interfaces have names. These names must be
|
102
|
+
specified on method calls.
|
103
|
+
|
104
|
+
The `org.freedesktop.Notification` service provides an object instance
|
105
|
+
called `/org/freedesktop/Notification`. This instance object implements an
|
106
|
+
interface called `org.freedesktop.Notifications`. It also provides two
|
107
|
+
special D-Bus specific interfaces: `org.freedesktop.DBus.Introspect` and
|
108
|
+
`org.freedesktop.DBus.Properties`. Again, object paths, service names,
|
109
|
+
and interface names can be related but do not have to be.
|
110
|
+
|
111
|
+
Basically the `org.freedesktop.DBus.Introspect` has an `Introspect` method,
|
112
|
+
that returns XML data describing the `/org/freedesktop/Notification` object
|
113
|
+
interfaces. This is used heavily internally by Ruby D-Bus.
|
114
|
+
|
115
|
+
Method
|
116
|
+
------
|
117
|
+
|
118
|
+
A method is, well, a method in the classical meaning. It's a function that
|
119
|
+
is called in the context of an object instance. Methods have typed
|
120
|
+
parameters and return typed return values.
|
121
|
+
|
122
|
+
Signal
|
123
|
+
------
|
124
|
+
|
125
|
+
Signals are simplified method calls that do not have a return value. They
|
126
|
+
do have typed parameters though.
|
127
|
+
|
128
|
+
Message
|
129
|
+
-------
|
130
|
+
|
131
|
+
Method calls, method returns, signals, errors: all are encoded as D-Bus
|
132
|
+
messages sent over a bus. They are made of a packet header with source and
|
133
|
+
destination address, a type (method call, method reply, signal) and the
|
134
|
+
body containing the parameters (for signals and method calls) or the return
|
135
|
+
values (for a method return message).
|
136
|
+
|
137
|
+
Signature
|
138
|
+
---------
|
139
|
+
|
140
|
+
Because D-Bus is typed and dynamic, each message comes with a signature that
|
141
|
+
describes the types of the data that is contained within the message. The
|
142
|
+
signature is a string with an extremely basic language that only describes
|
143
|
+
a data type. You will need to have some knowledge of what a signature
|
144
|
+
looks like if you are setting up a service. If you are just programming a
|
145
|
+
D-Bus client, you can live without knowing about them.
|
146
|
+
|
147
|
+
Client Usage
|
148
|
+
============
|
149
|
+
|
150
|
+
This chapter discusses basic client usage
|
151
|
+
and has the following topics:
|
152
|
+
|
153
|
+
Using the library
|
154
|
+
-----------------
|
155
|
+
|
156
|
+
If you want to use the library, you have to make Ruby load it by issuing:
|
157
|
+
|
158
|
+
require 'dbus'
|
159
|
+
|
160
|
+
That's all! Now we can move on to really using it...
|
161
|
+
|
162
|
+
Connecting to a bus
|
163
|
+
-------------------
|
164
|
+
|
165
|
+
On a typical system, two buses are running, the system bus and the session
|
166
|
+
bus. The system bus can be accessed by:
|
167
|
+
|
168
|
+
bus = DBus::SystemBus.instance
|
169
|
+
|
170
|
+
Probably you already have guessed how to access the session bus. This
|
171
|
+
can be done by:
|
172
|
+
|
173
|
+
bus = DBus::SessionBus.instance
|
174
|
+
|
175
|
+
Performing method calls
|
176
|
+
-----------------------
|
177
|
+
|
178
|
+
Let me continue this example using the session bus. Let's say that I want
|
179
|
+
to access an object of some client on the session bus. This particular
|
180
|
+
D-Bus client provides a service called `org.gnome.Rhythmbox`. Let me
|
181
|
+
access this service:
|
182
|
+
|
183
|
+
rb_service = bus.service("org.gnome.Rhythmbox")
|
184
|
+
|
185
|
+
In this example I access the `org.gnome.Rhythmbox` service, which is
|
186
|
+
provided by the application
|
187
|
+
[Rhythmbox](http://www.gnome.org/projects/rhythmbox/).
|
188
|
+
OK, I have a service handle now, and I know that it exports the object
|
189
|
+
"/org/gnome/Rhythmbox/Player". I will trivially access this remote object
|
190
|
+
using:
|
191
|
+
|
192
|
+
rb_player = rb_service.object("/org/gnome/Rhythmbox/Player")
|
193
|
+
|
194
|
+
Introspection
|
195
|
+
-------------
|
196
|
+
|
197
|
+
Well, that was easy. Let's say that I know that this particular object is
|
198
|
+
introspectable. In real life most of them are. The `rb_object` object we
|
199
|
+
have here is just a handle of a remote object, in general they are called
|
200
|
+
_proxy objects_, because they are the local handle of a remote object. It
|
201
|
+
would be nice to be able to make it have methods, and that its methods send
|
202
|
+
a D-Bus call to remotely execute the actual method in another process.
|
203
|
+
Well, instating these methods for a _introspectable_ object is trivial:
|
204
|
+
|
205
|
+
rb_player.introspect
|
206
|
+
|
207
|
+
And there you go. Note that not all services or objects can be
|
208
|
+
introspected, therefore you have to do this manually! Let me remind you
|
209
|
+
that objects in D-Bus have interfaces and interfaces have methods. Let's
|
210
|
+
now access these methods:
|
211
|
+
|
212
|
+
rb_player_iface = rb_player["org.gnome.Rhythmbox.Player"]
|
213
|
+
puts rb_player_iface.getPlayingUri
|
214
|
+
|
215
|
+
As you can see, when you want to call a method on an instance object, you have
|
216
|
+
to get the correct interface. It is a bit tedious, so we have the following
|
217
|
+
shortcut that does the same thing as before:
|
218
|
+
|
219
|
+
rb_player.default_iface = "org.gnome.Rhythmbox.Player"
|
220
|
+
puts rb_player.getPlayingUri
|
221
|
+
|
222
|
+
The `default_iface=` call specifies the default interface that should be
|
223
|
+
used when non existing methods are called directly on a proxy object, and
|
224
|
+
not on one of its interfaces.
|
225
|
+
|
226
|
+
Note that the bus itself has a corresponding introspectable object. You can
|
227
|
+
access it with `bus.proxy` method. For example, you can retrieve an array of
|
228
|
+
exported service names of a bus like this:
|
229
|
+
|
230
|
+
bus.proxy.ListNames[0]
|
231
|
+
|
232
|
+
Properties
|
233
|
+
----------
|
234
|
+
|
235
|
+
Some D-Bus objects provide access to properties. They are accessed by
|
236
|
+
treating a proxy interface as a hash:
|
237
|
+
|
238
|
+
nm_iface = network_manager_object["org.freedesktop.NetworkManager"]
|
239
|
+
enabled = nm_iface["WirelessEnabled"]
|
240
|
+
puts "Wireless is " + (enabled ? "enabled":"disabled")
|
241
|
+
puts "Toggling wireless"
|
242
|
+
nm_iface["WirelessEnabled"] = ! enabled
|
243
|
+
|
244
|
+
|
245
|
+
Calling a method asynchronously
|
246
|
+
-------------------------------
|
247
|
+
|
248
|
+
D-Bus is _asynchronous_. This means that you do not have to wait for a
|
249
|
+
reply when you send a message. When you call a remote method that takes a
|
250
|
+
lot of time to process remotely, you don't want your application to hang,
|
251
|
+
right? Well the asychronousness exists for this reason. What if you dont'
|
252
|
+
want to wait for the return value of a method, but still you want to take
|
253
|
+
some action when you receive it?
|
254
|
+
|
255
|
+
There is a classical method to program this event-driven mechanism. You do
|
256
|
+
some computation, perform some method call, and at the same time you setup
|
257
|
+
a callback that will be triggered once you receive a reply. Then you run a
|
258
|
+
main loop that is responsible to call the callbacks properly. Here is how
|
259
|
+
you do it:
|
260
|
+
|
261
|
+
rb_player.getPlayingUri do |resp|
|
262
|
+
puts "The playing URI is #{resp}"
|
263
|
+
end
|
264
|
+
puts "See, I'm not waiting!"
|
265
|
+
loop = DBus::Main.new
|
266
|
+
loop << bus
|
267
|
+
loop.run
|
268
|
+
|
269
|
+
This code will print the following:
|
270
|
+
|
271
|
+
See, I'm not waiting!
|
272
|
+
The playing URI is file:///music/papapingoin.mp3
|
273
|
+
|
274
|
+
Waiting for a signal
|
275
|
+
--------------------
|
276
|
+
|
277
|
+
Signals are calls from the remote object to your program. As a client, you
|
278
|
+
set yourself up to receive a signal and handle it with a callback. Then running
|
279
|
+
the main loop triggers the callback. You can register a callback handler
|
280
|
+
as allows:
|
281
|
+
|
282
|
+
rb_player.on_signal("elapsedChanged") do |u|
|
283
|
+
puts u
|
284
|
+
end
|
285
|
+
|
286
|
+
More about introspection
|
287
|
+
------------------------
|
288
|
+
|
289
|
+
There are various ways to inspect a remote service. You can simply call
|
290
|
+
`Introspect()` and read the XML output. However, in this tutorial I assume
|
291
|
+
that you want to do it using the Ruby D-Bus API.
|
292
|
+
|
293
|
+
Notice that you can introspect a service, and not only objects:
|
294
|
+
|
295
|
+
rb_service = bus.service("org.gnome.Rhythmbox")
|
296
|
+
rb_service.introspect
|
297
|
+
p rb_service.root
|
298
|
+
|
299
|
+
This dumps a tree-like structure that represents multiple object paths. In
|
300
|
+
this particular case the output is:
|
301
|
+
|
302
|
+
</: {org => {gnome => {Rhythmbox => {Player => ..fdbe625de {},Shell => ..fdbe6852e {},PlaylistManager => ..fdbe4e340 {}}>
|
303
|
+
|
304
|
+
Read this left to right: the root node is "/", it has one child node "org",
|
305
|
+
"org" has one child node "gnome", and "gnome" has one child node "Rhythmbox".
|
306
|
+
Rhythmbox has Tree child nodes "Player", "Shell" and "PlaylistManager".
|
307
|
+
These three last child nodes have a weird digit that means it has an object
|
308
|
+
instance. Such object instances are already introspected.
|
309
|
+
|
310
|
+
If the prose wasn't clear, maybe the following ASCII art will help you:
|
311
|
+
|
312
|
+
/
|
313
|
+
org
|
314
|
+
gnome
|
315
|
+
Rhythmbox
|
316
|
+
Shell (with object)
|
317
|
+
Player (with object)
|
318
|
+
PlaylistManager (with object)
|
319
|
+
|
320
|
+
### Walking the object tree
|
321
|
+
|
322
|
+
You can have an object on any node, i.e. it is not limited to leaves.
|
323
|
+
You can access a specific node like this:
|
324
|
+
|
325
|
+
rb_player = rb_service.root["org"]["gnome"]["Rhythmbox"]["Player"]
|
326
|
+
rb_player = rb_service.object("/org/gnome/Rhythmbox/Player")
|
327
|
+
|
328
|
+
The difference between the two is that for the first one, `rb_service`
|
329
|
+
needs to have been introspected. Also the obtained `rb_player` is already
|
330
|
+
introspected whereas the second `rb_player` isn't yet.
|
331
|
+
|
332
|
+
Errors
|
333
|
+
------
|
334
|
+
|
335
|
+
D-Bus calls can reply with an error instead of a return value. An error is
|
336
|
+
translated to a Ruby exception.
|
337
|
+
|
338
|
+
begin
|
339
|
+
network_manager.sleep
|
340
|
+
rescue DBus::Error => e
|
341
|
+
puts e unless e.name == "org.freedesktop.NetworkManager.AlreadyAsleepOrAwake"
|
342
|
+
end
|
343
|
+
|
344
|
+
Creating a Service
|
345
|
+
==================
|
346
|
+
|
347
|
+
This chapter deals with the opposite side of the basic client usage, namely
|
348
|
+
the creation of a D-Bus service.
|
349
|
+
|
350
|
+
Registering a service
|
351
|
+
---------------------
|
352
|
+
|
353
|
+
Now that you know how to perform D-Bus calls, and how to wait for and
|
354
|
+
handle signals, you might want to learn how to publish some object and
|
355
|
+
interface to provide them to the D-Bus world. Here is how you do that.
|
356
|
+
|
357
|
+
As you should already know, D-Bus clients that provide some object to be
|
358
|
+
called remotely are services. Here is how to allocate a name on a bus:
|
359
|
+
|
360
|
+
bus = DBus.session_bus
|
361
|
+
service = bus.request_service("org.ruby.service")
|
362
|
+
|
363
|
+
Now this client is know to the outside world as `org.ruby.service`.
|
364
|
+
Note that this is a request and it _can_ be denied! When it
|
365
|
+
is denied, an exception (`DBus::NameRequestError`) is thrown.
|
366
|
+
|
367
|
+
Exporting an object
|
368
|
+
-------------------
|
369
|
+
|
370
|
+
Now, let's define a class that we want to export:
|
371
|
+
|
372
|
+
class Test < DBus::Object
|
373
|
+
# Create an interface.
|
374
|
+
dbus_interface "org.ruby.SampleInterface" do
|
375
|
+
# Create a hello method in that interface.
|
376
|
+
dbus_method :hello, "in name:s, in name2:s" do |name, name2|
|
377
|
+
puts "hello(#{name}, #{name2})"
|
378
|
+
end
|
379
|
+
end
|
380
|
+
end
|
381
|
+
|
382
|
+
As you can see, we define a `Test` class in which we define a
|
383
|
+
`org.ruby.SampleInterface` interface. In this interface, we define a
|
384
|
+
method. The given code block is the method's implementation. This will be
|
385
|
+
executed when remote programs performs a D-Bus call. Now the annoying part:
|
386
|
+
the actual method definition. As you can guess the call
|
387
|
+
|
388
|
+
dbus_method :hello, "in name:s, in name2:s" do ...
|
389
|
+
|
390
|
+
creates a `hello` method that takes two parameters both of type string.
|
391
|
+
The _:s_ means "of type string". Let's have a look at some other common
|
392
|
+
parameter types:
|
393
|
+
|
394
|
+
- *u* means unsigned integer
|
395
|
+
- *i* means integer
|
396
|
+
- *y* means byte
|
397
|
+
- *(ui)* means a structure having a unsigned integer and a signed one.
|
398
|
+
- *a* means array, so that "ai" means array of integers
|
399
|
+
- *as* means array of string
|
400
|
+
- *a(is)* means array of structures, each having an integer and a string.
|
401
|
+
|
402
|
+
For a full description of the available D-Bus types, please refer to the
|
403
|
+
[D-Bus specification](http://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-signatures).
|
404
|
+
|
405
|
+
Now that the class has been defined, we can instantiate an object
|
406
|
+
and export it as follows:
|
407
|
+
|
408
|
+
exported_obj = Test.new("/org/ruby/MyInstance")
|
409
|
+
service.export(exported_obj)
|
410
|
+
|
411
|
+
This piece of code above instantiates a `Test` object with a D-Bus object
|
412
|
+
path. This object is reachable from the outside world after
|
413
|
+
`service.export(exported_obj)` is called.
|
414
|
+
|
415
|
+
We also need a loop which will read and process the calls coming over the bus:
|
416
|
+
|
417
|
+
loop = DBus::Main.new
|
418
|
+
loop << bus
|
419
|
+
loop.run
|
420
|
+
|
421
|
+
### Using the exported object
|
422
|
+
|
423
|
+
Now, let's consider another program that will access our newly created service:
|
424
|
+
|
425
|
+
ruby_service = bus.service("org.ruby.service")
|
426
|
+
obj = ruby_service.object("/org/ruby/MyInstance")
|
427
|
+
obj.introspect
|
428
|
+
obj.default_iface = "org.ruby.SampleInterface"
|
429
|
+
obj.hello("giligiligiligili", "haaaaaaa")
|
430
|
+
|
431
|
+
As you can see, the object we defined earlier is automatically introspectable.
|
432
|
+
See also "Basic Client Usage".
|
433
|
+
|
434
|
+
Emitting a signal
|
435
|
+
-----------------
|
436
|
+
|
437
|
+
Let's add some example method so you can see how to return a value to the
|
438
|
+
caller and let's also define another example interface that has a signal.
|
439
|
+
|
440
|
+
class Test2 < DBus::Object
|
441
|
+
# Create an interface
|
442
|
+
dbus_interface "org.ruby.SampleInterface" do
|
443
|
+
# Create a hello method in the interface:
|
444
|
+
dbus_method :hello, "in name:s, in name2:s" do |name, name2|
|
445
|
+
puts "hello(#{name}, #{name2})"
|
446
|
+
end
|
447
|
+
# Define a signal in the interface:
|
448
|
+
dbus_signal :SomethingJustHappened, "toto:s, tutu:u"
|
449
|
+
end
|
450
|
+
|
451
|
+
dbus_interface "org.ruby.AnotherInterface" do
|
452
|
+
dbus_method :ThatsALongMethodNameIThink, "in name:s, out ret:s" do |name|
|
453
|
+
["So your name is #{name}"]
|
454
|
+
end
|
455
|
+
end
|
456
|
+
end
|
457
|
+
|
458
|
+
Triggering the signal is a easy as calling a method, but then this time on
|
459
|
+
a local (exported) object and not on a remote/proxy object:
|
460
|
+
|
461
|
+
exported_obj.SomethingJustHappened("blah", 1)
|
462
|
+
|
463
|
+
Note that the `ThatsALongMethodNameIThink` method is returning a single
|
464
|
+
value to the caller. Notice that you always have to return an array. If
|
465
|
+
you want to return multiple values, just have an array with multiple
|
466
|
+
values.
|
467
|
+
|
468
|
+
Replying with an error
|
469
|
+
----------------------
|
470
|
+
|
471
|
+
To reply to a dbus_method with a D-Bus error, raise a `DBus::Error`,
|
472
|
+
as constructed by the `error` convenience function:
|
473
|
+
|
474
|
+
raise DBus.error("org.example.Error.SeatOccupied"), "Seat #{seat} is occupied"
|
475
|
+
|
476
|
+
If the error name is not specified, the generic
|
477
|
+
`org.freedesktop.DBus.Error.Failed` is used.
|
478
|
+
|
479
|
+
raise DBus.error, "Seat #{seat} is occupied"
|
480
|
+
raise DBus.error
|