blob: f11a7ef4547f93801b9b7a9af74c1d2f5c95188e [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
49 private:
50 friend void swap(BusConnection& x, BusConnection& y);
51
52 friend class Proxy;
53 friend BusConnection GetSystemBusConnection();
Yusuke Sato71da5ce2009-12-15 10:29:43 +090054 friend BusConnection GetPrivateBusConnection(const char* address);
rspangler@google.com570c65b2009-10-09 20:56:14 +000055
56 // Constructor takes ownership
57 explicit BusConnection(::DBusGConnection* x)
58 : object_(x) {
59 DCHECK(object_) << "Constructing BusConnection with NULL object.";
60 }
61
62 value_type object_;
63};
64
65inline void swap(BusConnection& x, BusConnection& y) {
66 std::swap(x.object_, y.object_);
67}
68
69// \brief Proxy manages the ref-count for a ::DBusGProxy*.
70//
71// Proxy has reference semantics and represents a connection to on object on
72// the bus. A proxy object is constructed with a connection to a bus, a name
73// to an entity on the bus, a path to an object owned by the entity, and an
74// interface protocol name used to communicate with the object.
75
76class Proxy {
77 public:
78 typedef ::DBusGProxy* value_type;
79
80 Proxy()
81 : object_(NULL) {
82 }
83
Yusuke Sato71da5ce2009-12-15 10:29:43 +090084 // Set |connect_to_name_owner| true if you'd like to use
85 // dbus_g_proxy_new_for_name_owner() rather than dbus_g_proxy_new_for_name().
86 Proxy(const BusConnection& connection,
87 const char* name,
88 const char* path,
89 const char* interface,
90 bool connect_to_name_owner)
91 : object_(GetGProxy(
92 connection, name, path, interface, connect_to_name_owner)) {
93 }
94
95 // Equivalent to Proxy(connection, name, path, interface, false).
rspangler@google.com570c65b2009-10-09 20:56:14 +000096 Proxy(const BusConnection& connection,
97 const char* name,
98 const char* path,
99 const char* interface)
Yusuke Sato71da5ce2009-12-15 10:29:43 +0900100 : object_(GetGProxy(connection, name, path, interface, false)) {
rspangler@google.com570c65b2009-10-09 20:56:14 +0000101 }
102
103 Proxy(const Proxy& x)
104 : object_(x.object_) {
105 if (object_)
106 ::g_object_ref(object_);
107 }
108
109 ~Proxy() {
110 if (object_)
111 ::g_object_unref(object_);
112 }
113
114 Proxy& operator=(Proxy x) {
115 swap(*this, x);
116 return *this;
117 }
118
119 const char* path() const {
120 DCHECK(object_) << "referencing an empty proxy";
121 return ::dbus_g_proxy_get_path(object_);
122 }
123
124 // gproxy() returns a reference to the underlying ::DBusGProxy*. As this
125 // library evolves, the gproxy() will be moved to be private.
126
127 const value_type& gproxy() const {
128 DCHECK(object_) << "referencing an empty proxy";
129 return object_;
130 }
131
132 operator bool() const {
133 return object_;
134 }
135
136 private:
Yusuke Sato71da5ce2009-12-15 10:29:43 +0900137 static value_type GetGProxy(const BusConnection& connection,
138 const char* name,
139 const char* path,
140 const char* interface,
141 bool connect_to_name_owner);
142
rspangler@google.com570c65b2009-10-09 20:56:14 +0000143 operator int() const; // for safe bool cast
144 friend void swap(Proxy& x, Proxy& y);
145
146 value_type object_;
147};
148
149inline void swap(Proxy& x, Proxy& y) {
150 std::swap(x.object_, y.object_);
151}
152
153template <typename F> // F is a function signature
154class MonitorConnection;
155
156template <typename A1>
157class MonitorConnection<void (A1)> {
158 public:
159 MonitorConnection(const Proxy& proxy, const char* name,
160 void (*monitor)(void*, A1), void* object)
161 : proxy_(proxy), name_(name), monitor_(monitor), object_(object) {
162 }
163
164 static void Run(::DBusGProxy*, A1 x, MonitorConnection* self) {
165 self->monitor_(self->object_, x);
166 }
167 const Proxy& proxy() const {
168 return proxy_;
169 }
170 const std::string& name() const {
171 return name_;
172 }
173
174 private:
175 Proxy proxy_;
176 std::string name_;
177 void (*monitor_)(void*, A1);
178 void* object_;
179};
180
181template <typename A1, typename A2>
182class MonitorConnection<void (A1, A2)> {
183 public:
184 MonitorConnection(const Proxy& proxy, const char* name,
185 void (*monitor)(void*, A1, A2), void* object)
186 : proxy_(proxy), name_(name), monitor_(monitor), object_(object) {
187 }
188
189 static void Run(::DBusGProxy*, A1 x, A2 y, MonitorConnection* self) {
190 self->monitor_(self->object_, x, y);
191 }
192 const Proxy& proxy() const {
193 return proxy_;
194 }
195 const std::string& name() const {
196 return name_;
197 }
198
199 private:
200 Proxy proxy_;
201 std::string name_;
202 void (*monitor_)(void*, A1, A2);
203 void* object_;
204
205};
206
207template <typename A1>
208MonitorConnection<void (A1)>* Monitor(const Proxy& proxy, const char* name,
209 void (*monitor)(void*, A1),
210 void* object) {
211 typedef MonitorConnection<void (A1)> ConnectionType;
212
213 ConnectionType* result = new ConnectionType(proxy, name, monitor, object);
214
215 ::dbus_g_proxy_add_signal(proxy.gproxy(), name,
216 glib::type_to_gtypeid<A1>(), G_TYPE_INVALID);
217 ::dbus_g_proxy_connect_signal(proxy.gproxy(), name,
218 G_CALLBACK(&ConnectionType::Run),
219 result, NULL);
220 return result;
221}
222
223template <typename A1, typename A2>
224MonitorConnection<void (A1, A2)>* Monitor(const Proxy& proxy, const char* name,
225 void (*monitor)(void*, A1, A2),
226 void* object) {
227 typedef MonitorConnection<void (A1, A2)> ConnectionType;
228
229 ConnectionType* result = new ConnectionType(proxy, name, monitor, object);
230
231 ::dbus_g_proxy_add_signal(proxy.gproxy(), name,
232 glib::type_to_gtypeid<A1>(),
233 glib::type_to_gtypeid<A2>(),
234 G_TYPE_INVALID);
235 ::dbus_g_proxy_connect_signal(proxy.gproxy(), name,
236 G_CALLBACK(&ConnectionType::Run),
237 result, NULL);
238 return result;
239}
240
241template <typename F>
242void Disconnect(MonitorConnection<F>* connection) {
243 typedef MonitorConnection<F> ConnectionType;
244
245 ::dbus_g_proxy_disconnect_signal(connection->proxy().gproxy(),
246 connection->name().c_str(),
247 G_CALLBACK(&ConnectionType::Run),
248 connection);
249 delete connection;
250}
251
252// \brief call_PtrArray() invokes a method on a proxy returning a
253// glib::PtrArray.
254//
255// CallPtrArray is the first instance of what is likely to be a general
256// way to make method calls to a proxy. It will likely be replaced with
257// something like Call(proxy, method, arg1, arg2, ..., ResultType*) in the
258// future. However, I don't yet have enough cases to generalize from.
259
260bool CallPtrArray(const Proxy& proxy,
261 const char* method,
262 glib::ScopedPtrArray<const char*>* result);
263
264// \brief RetrieveProperty() retrieves a property of an object associated with a
265// proxy.
266//
267// Given a proxy to an object supporting the org.freedesktop.DBus.Properties
268// interface, the RetrieveProperty() call will retrieve a property of the
269// specified interface on the object storing it in \param result and returning
270// \true. If the dbus call fails or the object returned is not of type \param T,
271// then \false is returned and \param result is unchanged.
272//
273// \example
274// Proxy proxy(GetSystemBusConnection(),
275// "org.freedesktop.DeviceKit.Power", // A named entity on the bus
276// battery_name, // Path to a battery on the bus
277// "org.freedesktop.DBus.Properties") // Properties interface
278//
279// double x;
280// if (RetrieveProperty(proxy,
281// "org.freedesktop.DeviceKit.Power.Device",
282// "percentage")
283// std::cout << "Battery charge is " << x << "% of capacity.";
284// \end_example
285
286template <typename T>
287bool RetrieveProperty(const Proxy& proxy,
288 const char* interface,
289 const char* property,
290 T* result) {
291 glib::ScopedError error;
292 glib::Value value;
293
294 if (!::dbus_g_proxy_call(proxy.gproxy(), "Get", &Resetter(&error).lvalue(),
295 G_TYPE_STRING, interface,
296 G_TYPE_STRING, property,
297 G_TYPE_INVALID,
298 G_TYPE_VALUE, &value,
dhg@google.com7ec90e92009-10-27 16:44:35 +0000299 G_TYPE_INVALID)){
Yusuke Sato71da5ce2009-12-15 10:29:43 +0900300 LOG(ERROR) << "Getting property failed: "
301 << (error->message ? error->message : "Unknown Error.");
rspangler@google.com570c65b2009-10-09 20:56:14 +0000302 return false;
303
dhg@google.com7ec90e92009-10-27 16:44:35 +0000304 }
305 return glib::Retrieve(value, result);
rspangler@google.com570c65b2009-10-09 20:56:14 +0000306}
307
308// \brief RetrieveProperties returns a HashTable of all properties for the
309// specified interface.
310
311bool RetrieveProperties(const Proxy& proxy,
312 const char* interface,
313 glib::ScopedHashTable* result);
314
315// \brief Returns a connection to the system bus.
316
317BusConnection GetSystemBusConnection();
318
Yusuke Sato71da5ce2009-12-15 10:29:43 +0900319// \brief Returns a private connection to a bus at |address|.
320
321BusConnection GetPrivateBusConnection(const char* address);
322
rspangler@google.com570c65b2009-10-09 20:56:14 +0000323} // namespace dbus
324} // namespace chromeos
325
326#endif // CHROMEOS_DBUS_H_