blob: 2bc44b9d0ce6a0bd3173954fa8f81188e433d56f [file] [log] [blame]
rspangler@google.com570c65b2009-10-09 20:56:14 +00001// Copyright (c) 2009 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef CHROMEOS_DBUS_H_
6#define CHROMEOS_DBUS_H_
7
8#include <dbus/dbus-glib.h>
9#include <glib-object.h>
rspangler@google.com570c65b2009-10-09 20:56:14 +000010
11#include <algorithm>
12#include <string>
13
seanparent@google.comf2ea0242009-11-04 21:04:51 +000014#include "base/logging.h"
rspangler@google.com570c65b2009-10-09 20:56:14 +000015#include "chromeos/glib/object.h"
16
17namespace chromeos {
18
19// \precondition No functions in the dbus namespace can be called before
20// ::g_type_init();
21
22namespace dbus {
23
24// \brief BusConnection manages the ref-count for a ::DBusGConnection*.
25//
26// A BusConnection has reference semantics bound to a particular communication
27// bus.
28//
29// \models Copyable, Assignable
30// \related GetSystemBusConnection()
31
32class BusConnection {
33 public:
34 typedef ::DBusGConnection* value_type;
35
36 BusConnection(const BusConnection& x)
Yusuke Sato35371c82010-06-23 19:04:02 +090037 : object_(x.object_) {
38 if (object_)
39 ::dbus_g_connection_ref(object_);
rspangler@google.com570c65b2009-10-09 20:56:14 +000040 }
41
42 ~BusConnection() {
Yusuke Sato35371c82010-06-23 19:04:02 +090043 if (object_)
44 ::dbus_g_connection_unref(object_);
rspangler@google.com570c65b2009-10-09 20:56:14 +000045 }
46
47 BusConnection& operator=(BusConnection x) {
48 swap(*this, x);
49 return *this;
50 }
51
Yusuke Satof8059812010-01-09 20:13:07 +090052 const value_type& g_connection() const {
53 DCHECK(object_) << "referencing an empty connection";
54 return object_;
55 }
56
Yusuke Sato35371c82010-06-23 19:04:02 +090057 operator bool() const {
58 return object_;
59 }
60
61 bool HasConnection() const {
62 return object_;
63 }
64
rspangler@google.com570c65b2009-10-09 20:56:14 +000065 private:
66 friend void swap(BusConnection& x, BusConnection& y);
67
68 friend class Proxy;
69 friend BusConnection GetSystemBusConnection();
Yusuke Sato71da5ce2009-12-15 10:29:43 +090070 friend BusConnection GetPrivateBusConnection(const char* address);
rspangler@google.com570c65b2009-10-09 20:56:14 +000071
72 // Constructor takes ownership
73 explicit BusConnection(::DBusGConnection* x)
74 : object_(x) {
rspangler@google.com570c65b2009-10-09 20:56:14 +000075 }
76
77 value_type object_;
78};
79
80inline void swap(BusConnection& x, BusConnection& y) {
81 std::swap(x.object_, y.object_);
82}
83
84// \brief Proxy manages the ref-count for a ::DBusGProxy*.
85//
86// Proxy has reference semantics and represents a connection to on object on
87// the bus. A proxy object is constructed with a connection to a bus, a name
88// to an entity on the bus, a path to an object owned by the entity, and an
89// interface protocol name used to communicate with the object.
90
91class Proxy {
92 public:
93 typedef ::DBusGProxy* value_type;
94
95 Proxy()
96 : object_(NULL) {
97 }
98
Yusuke Sato71da5ce2009-12-15 10:29:43 +090099 // Set |connect_to_name_owner| true if you'd like to use
100 // dbus_g_proxy_new_for_name_owner() rather than dbus_g_proxy_new_for_name().
101 Proxy(const BusConnection& connection,
102 const char* name,
103 const char* path,
104 const char* interface,
105 bool connect_to_name_owner)
106 : object_(GetGProxy(
107 connection, name, path, interface, connect_to_name_owner)) {
108 }
109
110 // Equivalent to Proxy(connection, name, path, interface, false).
rspangler@google.com570c65b2009-10-09 20:56:14 +0000111 Proxy(const BusConnection& connection,
112 const char* name,
113 const char* path,
114 const char* interface)
Yusuke Sato71da5ce2009-12-15 10:29:43 +0900115 : object_(GetGProxy(connection, name, path, interface, false)) {
rspangler@google.com570c65b2009-10-09 20:56:14 +0000116 }
117
Mitsuru Oshima93b37832010-05-18 14:17:57 -0700118 // Creates a peer proxy using dbus_g_proxy_new_for_peer.
119 Proxy(const BusConnection& connection,
120 const char* path,
121 const char* interface)
122 : object_(GetGPeerProxy(connection, path, interface)) {
123 }
124
rspangler@google.com570c65b2009-10-09 20:56:14 +0000125 Proxy(const Proxy& x)
126 : object_(x.object_) {
127 if (object_)
128 ::g_object_ref(object_);
129 }
130
131 ~Proxy() {
132 if (object_)
133 ::g_object_unref(object_);
134 }
135
136 Proxy& operator=(Proxy x) {
137 swap(*this, x);
138 return *this;
139 }
140
141 const char* path() const {
142 DCHECK(object_) << "referencing an empty proxy";
143 return ::dbus_g_proxy_get_path(object_);
144 }
145
146 // gproxy() returns a reference to the underlying ::DBusGProxy*. As this
147 // library evolves, the gproxy() will be moved to be private.
148
149 const value_type& gproxy() const {
150 DCHECK(object_) << "referencing an empty proxy";
151 return object_;
152 }
153
154 operator bool() const {
155 return object_;
156 }
157
158 private:
Yusuke Sato71da5ce2009-12-15 10:29:43 +0900159 static value_type GetGProxy(const BusConnection& connection,
160 const char* name,
161 const char* path,
162 const char* interface,
163 bool connect_to_name_owner);
164
Mitsuru Oshima93b37832010-05-18 14:17:57 -0700165 static value_type GetGPeerProxy(const BusConnection& connection,
166 const char* path,
167 const char* interface);
168
rspangler@google.com570c65b2009-10-09 20:56:14 +0000169 operator int() const; // for safe bool cast
170 friend void swap(Proxy& x, Proxy& y);
171
172 value_type object_;
173};
174
175inline void swap(Proxy& x, Proxy& y) {
176 std::swap(x.object_, y.object_);
177}
178
Chris Masonec8150f12010-01-12 12:23:22 -0800179// \brief RegisterExclusiveService configures a GObject to run as a service on
180// a supplied ::BusConnection.
181//
182// RegisterExclusiveService encapsulates the process of configuring the
183// supplied \param object at \param service_path on the \param connection.
184// Exclusivity is ensured by replacing any existing services at that named
185// location and confirming that the connection is the primary owner.
186//
187// Type information for the \param object must be installed with
188// dbus_g_object_type_install_info prior to use.
189
190bool RegisterExclusiveService(const BusConnection& connection,
191 const char* interface_name,
192 const char* service_name,
193 const char* service_path,
194 GObject* object);
195
rspangler@google.com570c65b2009-10-09 20:56:14 +0000196template <typename F> // F is a function signature
197class MonitorConnection;
198
199template <typename A1>
200class MonitorConnection<void (A1)> {
201 public:
202 MonitorConnection(const Proxy& proxy, const char* name,
203 void (*monitor)(void*, A1), void* object)
204 : proxy_(proxy), name_(name), monitor_(monitor), object_(object) {
205 }
206
207 static void Run(::DBusGProxy*, A1 x, MonitorConnection* self) {
208 self->monitor_(self->object_, x);
209 }
210 const Proxy& proxy() const {
211 return proxy_;
212 }
213 const std::string& name() const {
214 return name_;
215 }
216
217 private:
218 Proxy proxy_;
219 std::string name_;
220 void (*monitor_)(void*, A1);
221 void* object_;
222};
223
224template <typename A1, typename A2>
225class MonitorConnection<void (A1, A2)> {
226 public:
227 MonitorConnection(const Proxy& proxy, const char* name,
228 void (*monitor)(void*, A1, A2), void* object)
229 : proxy_(proxy), name_(name), monitor_(monitor), object_(object) {
230 }
231
232 static void Run(::DBusGProxy*, A1 x, A2 y, MonitorConnection* self) {
233 self->monitor_(self->object_, x, y);
234 }
235 const Proxy& proxy() const {
236 return proxy_;
237 }
238 const std::string& name() const {
239 return name_;
240 }
241
242 private:
243 Proxy proxy_;
244 std::string name_;
245 void (*monitor_)(void*, A1, A2);
246 void* object_;
247
248};
249
Toni Barzicfa027112010-08-16 19:21:34 -0700250template <typename A1, typename A2, typename A3>
251class MonitorConnection<void (A1, A2, A3)> {
252 public:
253 MonitorConnection(const Proxy& proxy, const char* name,
254 void (*monitor)(void*, A1, A2, A3), void* object)
255 : proxy_(proxy), name_(name), monitor_(monitor), object_(object) {
256 }
257
258 static void Run(::DBusGProxy*, A1 x, A2 y, A3 z, MonitorConnection* self) {
259 self->monitor_(self->object_, x, y, z);
260 }
261 const Proxy& proxy() const {
262 return proxy_;
263 }
264 const std::string& name() const {
265 return name_;
266 }
267
268 private:
269 Proxy proxy_;
270 std::string name_;
271 void (*monitor_)(void*, A1, A2, A3);
272 void* object_;
273
274};
275
rspangler@google.com570c65b2009-10-09 20:56:14 +0000276template <typename A1>
277MonitorConnection<void (A1)>* Monitor(const Proxy& proxy, const char* name,
278 void (*monitor)(void*, A1),
279 void* object) {
280 typedef MonitorConnection<void (A1)> ConnectionType;
281
282 ConnectionType* result = new ConnectionType(proxy, name, monitor, object);
283
284 ::dbus_g_proxy_add_signal(proxy.gproxy(), name,
285 glib::type_to_gtypeid<A1>(), G_TYPE_INVALID);
286 ::dbus_g_proxy_connect_signal(proxy.gproxy(), name,
287 G_CALLBACK(&ConnectionType::Run),
288 result, NULL);
289 return result;
290}
291
292template <typename A1, typename A2>
293MonitorConnection<void (A1, A2)>* Monitor(const Proxy& proxy, const char* name,
294 void (*monitor)(void*, A1, A2),
295 void* object) {
296 typedef MonitorConnection<void (A1, A2)> ConnectionType;
297
298 ConnectionType* result = new ConnectionType(proxy, name, monitor, object);
299
300 ::dbus_g_proxy_add_signal(proxy.gproxy(), name,
301 glib::type_to_gtypeid<A1>(),
302 glib::type_to_gtypeid<A2>(),
303 G_TYPE_INVALID);
304 ::dbus_g_proxy_connect_signal(proxy.gproxy(), name,
305 G_CALLBACK(&ConnectionType::Run),
306 result, NULL);
307 return result;
308}
309
Toni Barzicfa027112010-08-16 19:21:34 -0700310template <typename A1, typename A2, typename A3>
311MonitorConnection<void (A1, A2, A3)>* Monitor(const Proxy& proxy,
312 const char* name,
313 void (*monitor)(void*, A1, A2, A3),
314 void* object) {
315 typedef MonitorConnection<void (A1, A2, A3)> ConnectionType;
316
317 ConnectionType* result = new ConnectionType(proxy, name, monitor, object);
318
319 ::dbus_g_proxy_add_signal(proxy.gproxy(), name,
320 glib::type_to_gtypeid<A1>(),
321 glib::type_to_gtypeid<A2>(),
322 glib::type_to_gtypeid<A3>(),
323 G_TYPE_INVALID);
324 ::dbus_g_proxy_connect_signal(proxy.gproxy(), name,
325 G_CALLBACK(&ConnectionType::Run),
326 result, NULL);
327 return result;
328}
329
rspangler@google.com570c65b2009-10-09 20:56:14 +0000330template <typename F>
331void Disconnect(MonitorConnection<F>* connection) {
332 typedef MonitorConnection<F> ConnectionType;
333
334 ::dbus_g_proxy_disconnect_signal(connection->proxy().gproxy(),
335 connection->name().c_str(),
336 G_CALLBACK(&ConnectionType::Run),
337 connection);
338 delete connection;
339}
340
341// \brief call_PtrArray() invokes a method on a proxy returning a
342// glib::PtrArray.
343//
344// CallPtrArray is the first instance of what is likely to be a general
345// way to make method calls to a proxy. It will likely be replaced with
346// something like Call(proxy, method, arg1, arg2, ..., ResultType*) in the
347// future. However, I don't yet have enough cases to generalize from.
348
349bool CallPtrArray(const Proxy& proxy,
350 const char* method,
351 glib::ScopedPtrArray<const char*>* result);
352
353// \brief RetrieveProperty() retrieves a property of an object associated with a
354// proxy.
355//
356// Given a proxy to an object supporting the org.freedesktop.DBus.Properties
357// interface, the RetrieveProperty() call will retrieve a property of the
358// specified interface on the object storing it in \param result and returning
359// \true. If the dbus call fails or the object returned is not of type \param T,
360// then \false is returned and \param result is unchanged.
361//
362// \example
363// Proxy proxy(GetSystemBusConnection(),
364// "org.freedesktop.DeviceKit.Power", // A named entity on the bus
365// battery_name, // Path to a battery on the bus
366// "org.freedesktop.DBus.Properties") // Properties interface
367//
368// double x;
369// if (RetrieveProperty(proxy,
370// "org.freedesktop.DeviceKit.Power.Device",
371// "percentage")
372// std::cout << "Battery charge is " << x << "% of capacity.";
373// \end_example
374
375template <typename T>
376bool RetrieveProperty(const Proxy& proxy,
377 const char* interface,
378 const char* property,
379 T* result) {
380 glib::ScopedError error;
381 glib::Value value;
382
383 if (!::dbus_g_proxy_call(proxy.gproxy(), "Get", &Resetter(&error).lvalue(),
384 G_TYPE_STRING, interface,
385 G_TYPE_STRING, property,
386 G_TYPE_INVALID,
387 G_TYPE_VALUE, &value,
dhg@google.com7ec90e92009-10-27 16:44:35 +0000388 G_TYPE_INVALID)){
Yusuke Sato71da5ce2009-12-15 10:29:43 +0900389 LOG(ERROR) << "Getting property failed: "
390 << (error->message ? error->message : "Unknown Error.");
rspangler@google.com570c65b2009-10-09 20:56:14 +0000391 return false;
392
dhg@google.com7ec90e92009-10-27 16:44:35 +0000393 }
394 return glib::Retrieve(value, result);
rspangler@google.com570c65b2009-10-09 20:56:14 +0000395}
396
397// \brief RetrieveProperties returns a HashTable of all properties for the
398// specified interface.
399
400bool RetrieveProperties(const Proxy& proxy,
401 const char* interface,
402 glib::ScopedHashTable* result);
403
404// \brief Returns a connection to the system bus.
405
406BusConnection GetSystemBusConnection();
407
Yusuke Sato71da5ce2009-12-15 10:29:43 +0900408// \brief Returns a private connection to a bus at |address|.
409
410BusConnection GetPrivateBusConnection(const char* address);
411
rspangler@google.com570c65b2009-10-09 20:56:14 +0000412} // namespace dbus
413} // namespace chromeos
414
415#endif // CHROMEOS_DBUS_H_