blob: 47758678e423a723b8598b5355119a50a436ed8a [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)
37 : object_(dbus_g_connection_ref(x.object_)) {
38 }
39
40 ~BusConnection() {
41 ::dbus_g_connection_unref(object_);
42 }
43
44 BusConnection& operator=(BusConnection x) {
45 swap(*this, x);
46 return *this;
47 }
48
Yusuke Satof8059812010-01-09 20:13:07 +090049 const value_type& g_connection() const {
50 DCHECK(object_) << "referencing an empty connection";
51 return object_;
52 }
53
rspangler@google.com570c65b2009-10-09 20:56:14 +000054 private:
55 friend void swap(BusConnection& x, BusConnection& y);
56
57 friend class Proxy;
58 friend BusConnection GetSystemBusConnection();
Yusuke Sato71da5ce2009-12-15 10:29:43 +090059 friend BusConnection GetPrivateBusConnection(const char* address);
rspangler@google.com570c65b2009-10-09 20:56:14 +000060
61 // Constructor takes ownership
62 explicit BusConnection(::DBusGConnection* x)
63 : object_(x) {
64 DCHECK(object_) << "Constructing BusConnection with NULL object.";
65 }
66
67 value_type object_;
68};
69
70inline void swap(BusConnection& x, BusConnection& y) {
71 std::swap(x.object_, y.object_);
72}
73
74// \brief Proxy manages the ref-count for a ::DBusGProxy*.
75//
76// Proxy has reference semantics and represents a connection to on object on
77// the bus. A proxy object is constructed with a connection to a bus, a name
78// to an entity on the bus, a path to an object owned by the entity, and an
79// interface protocol name used to communicate with the object.
80
81class Proxy {
82 public:
83 typedef ::DBusGProxy* value_type;
84
85 Proxy()
86 : object_(NULL) {
87 }
88
Yusuke Sato71da5ce2009-12-15 10:29:43 +090089 // Set |connect_to_name_owner| true if you'd like to use
90 // dbus_g_proxy_new_for_name_owner() rather than dbus_g_proxy_new_for_name().
91 Proxy(const BusConnection& connection,
92 const char* name,
93 const char* path,
94 const char* interface,
95 bool connect_to_name_owner)
96 : object_(GetGProxy(
97 connection, name, path, interface, connect_to_name_owner)) {
98 }
99
100 // Equivalent to Proxy(connection, name, path, interface, false).
rspangler@google.com570c65b2009-10-09 20:56:14 +0000101 Proxy(const BusConnection& connection,
102 const char* name,
103 const char* path,
104 const char* interface)
Yusuke Sato71da5ce2009-12-15 10:29:43 +0900105 : object_(GetGProxy(connection, name, path, interface, false)) {
rspangler@google.com570c65b2009-10-09 20:56:14 +0000106 }
107
Mitsuru Oshima93b37832010-05-18 14:17:57 -0700108 // Creates a peer proxy using dbus_g_proxy_new_for_peer.
109 Proxy(const BusConnection& connection,
110 const char* path,
111 const char* interface)
112 : object_(GetGPeerProxy(connection, path, interface)) {
113 }
114
rspangler@google.com570c65b2009-10-09 20:56:14 +0000115 Proxy(const Proxy& x)
116 : object_(x.object_) {
117 if (object_)
118 ::g_object_ref(object_);
119 }
120
121 ~Proxy() {
122 if (object_)
123 ::g_object_unref(object_);
124 }
125
126 Proxy& operator=(Proxy x) {
127 swap(*this, x);
128 return *this;
129 }
130
131 const char* path() const {
132 DCHECK(object_) << "referencing an empty proxy";
133 return ::dbus_g_proxy_get_path(object_);
134 }
135
136 // gproxy() returns a reference to the underlying ::DBusGProxy*. As this
137 // library evolves, the gproxy() will be moved to be private.
138
139 const value_type& gproxy() const {
140 DCHECK(object_) << "referencing an empty proxy";
141 return object_;
142 }
143
144 operator bool() const {
145 return object_;
146 }
147
148 private:
Yusuke Sato71da5ce2009-12-15 10:29:43 +0900149 static value_type GetGProxy(const BusConnection& connection,
150 const char* name,
151 const char* path,
152 const char* interface,
153 bool connect_to_name_owner);
154
Mitsuru Oshima93b37832010-05-18 14:17:57 -0700155 static value_type GetGPeerProxy(const BusConnection& connection,
156 const char* path,
157 const char* interface);
158
rspangler@google.com570c65b2009-10-09 20:56:14 +0000159 operator int() const; // for safe bool cast
160 friend void swap(Proxy& x, Proxy& y);
161
162 value_type object_;
163};
164
165inline void swap(Proxy& x, Proxy& y) {
166 std::swap(x.object_, y.object_);
167}
168
Chris Masonec8150f12010-01-12 12:23:22 -0800169// \brief RegisterExclusiveService configures a GObject to run as a service on
170// a supplied ::BusConnection.
171//
172// RegisterExclusiveService encapsulates the process of configuring the
173// supplied \param object at \param service_path on the \param connection.
174// Exclusivity is ensured by replacing any existing services at that named
175// location and confirming that the connection is the primary owner.
176//
177// Type information for the \param object must be installed with
178// dbus_g_object_type_install_info prior to use.
179
180bool RegisterExclusiveService(const BusConnection& connection,
181 const char* interface_name,
182 const char* service_name,
183 const char* service_path,
184 GObject* object);
185
rspangler@google.com570c65b2009-10-09 20:56:14 +0000186template <typename F> // F is a function signature
187class MonitorConnection;
188
189template <typename A1>
190class MonitorConnection<void (A1)> {
191 public:
192 MonitorConnection(const Proxy& proxy, const char* name,
193 void (*monitor)(void*, A1), void* object)
194 : proxy_(proxy), name_(name), monitor_(monitor), object_(object) {
195 }
196
197 static void Run(::DBusGProxy*, A1 x, MonitorConnection* self) {
198 self->monitor_(self->object_, x);
199 }
200 const Proxy& proxy() const {
201 return proxy_;
202 }
203 const std::string& name() const {
204 return name_;
205 }
206
207 private:
208 Proxy proxy_;
209 std::string name_;
210 void (*monitor_)(void*, A1);
211 void* object_;
212};
213
214template <typename A1, typename A2>
215class MonitorConnection<void (A1, A2)> {
216 public:
217 MonitorConnection(const Proxy& proxy, const char* name,
218 void (*monitor)(void*, A1, A2), void* object)
219 : proxy_(proxy), name_(name), monitor_(monitor), object_(object) {
220 }
221
222 static void Run(::DBusGProxy*, A1 x, A2 y, MonitorConnection* self) {
223 self->monitor_(self->object_, x, y);
224 }
225 const Proxy& proxy() const {
226 return proxy_;
227 }
228 const std::string& name() const {
229 return name_;
230 }
231
232 private:
233 Proxy proxy_;
234 std::string name_;
235 void (*monitor_)(void*, A1, A2);
236 void* object_;
237
238};
239
240template <typename A1>
241MonitorConnection<void (A1)>* Monitor(const Proxy& proxy, const char* name,
242 void (*monitor)(void*, A1),
243 void* object) {
244 typedef MonitorConnection<void (A1)> ConnectionType;
245
246 ConnectionType* result = new ConnectionType(proxy, name, monitor, object);
247
248 ::dbus_g_proxy_add_signal(proxy.gproxy(), name,
249 glib::type_to_gtypeid<A1>(), G_TYPE_INVALID);
250 ::dbus_g_proxy_connect_signal(proxy.gproxy(), name,
251 G_CALLBACK(&ConnectionType::Run),
252 result, NULL);
253 return result;
254}
255
256template <typename A1, typename A2>
257MonitorConnection<void (A1, A2)>* Monitor(const Proxy& proxy, const char* name,
258 void (*monitor)(void*, A1, A2),
259 void* object) {
260 typedef MonitorConnection<void (A1, A2)> ConnectionType;
261
262 ConnectionType* result = new ConnectionType(proxy, name, monitor, object);
263
264 ::dbus_g_proxy_add_signal(proxy.gproxy(), name,
265 glib::type_to_gtypeid<A1>(),
266 glib::type_to_gtypeid<A2>(),
267 G_TYPE_INVALID);
268 ::dbus_g_proxy_connect_signal(proxy.gproxy(), name,
269 G_CALLBACK(&ConnectionType::Run),
270 result, NULL);
271 return result;
272}
273
274template <typename F>
275void Disconnect(MonitorConnection<F>* connection) {
276 typedef MonitorConnection<F> ConnectionType;
277
278 ::dbus_g_proxy_disconnect_signal(connection->proxy().gproxy(),
279 connection->name().c_str(),
280 G_CALLBACK(&ConnectionType::Run),
281 connection);
282 delete connection;
283}
284
285// \brief call_PtrArray() invokes a method on a proxy returning a
286// glib::PtrArray.
287//
288// CallPtrArray is the first instance of what is likely to be a general
289// way to make method calls to a proxy. It will likely be replaced with
290// something like Call(proxy, method, arg1, arg2, ..., ResultType*) in the
291// future. However, I don't yet have enough cases to generalize from.
292
293bool CallPtrArray(const Proxy& proxy,
294 const char* method,
295 glib::ScopedPtrArray<const char*>* result);
296
297// \brief RetrieveProperty() retrieves a property of an object associated with a
298// proxy.
299//
300// Given a proxy to an object supporting the org.freedesktop.DBus.Properties
301// interface, the RetrieveProperty() call will retrieve a property of the
302// specified interface on the object storing it in \param result and returning
303// \true. If the dbus call fails or the object returned is not of type \param T,
304// then \false is returned and \param result is unchanged.
305//
306// \example
307// Proxy proxy(GetSystemBusConnection(),
308// "org.freedesktop.DeviceKit.Power", // A named entity on the bus
309// battery_name, // Path to a battery on the bus
310// "org.freedesktop.DBus.Properties") // Properties interface
311//
312// double x;
313// if (RetrieveProperty(proxy,
314// "org.freedesktop.DeviceKit.Power.Device",
315// "percentage")
316// std::cout << "Battery charge is " << x << "% of capacity.";
317// \end_example
318
319template <typename T>
320bool RetrieveProperty(const Proxy& proxy,
321 const char* interface,
322 const char* property,
323 T* result) {
324 glib::ScopedError error;
325 glib::Value value;
326
327 if (!::dbus_g_proxy_call(proxy.gproxy(), "Get", &Resetter(&error).lvalue(),
328 G_TYPE_STRING, interface,
329 G_TYPE_STRING, property,
330 G_TYPE_INVALID,
331 G_TYPE_VALUE, &value,
dhg@google.com7ec90e92009-10-27 16:44:35 +0000332 G_TYPE_INVALID)){
Yusuke Sato71da5ce2009-12-15 10:29:43 +0900333 LOG(ERROR) << "Getting property failed: "
334 << (error->message ? error->message : "Unknown Error.");
rspangler@google.com570c65b2009-10-09 20:56:14 +0000335 return false;
336
dhg@google.com7ec90e92009-10-27 16:44:35 +0000337 }
338 return glib::Retrieve(value, result);
rspangler@google.com570c65b2009-10-09 20:56:14 +0000339}
340
341// \brief RetrieveProperties returns a HashTable of all properties for the
342// specified interface.
343
344bool RetrieveProperties(const Proxy& proxy,
345 const char* interface,
346 glib::ScopedHashTable* result);
347
348// \brief Returns a connection to the system bus.
349
350BusConnection GetSystemBusConnection();
351
Yusuke Sato71da5ce2009-12-15 10:29:43 +0900352// \brief Returns a private connection to a bus at |address|.
353
354BusConnection GetPrivateBusConnection(const char* address);
355
rspangler@google.com570c65b2009-10-09 20:56:14 +0000356} // namespace dbus
357} // namespace chromeos
358
359#endif // CHROMEOS_DBUS_H_