3
// Copyright (C) 2011, 2012, 2013 Rob Caelers <robc@krandor.nl>
4
// All rights reserved.
6
// This program is free software: you can redistribute it and/or modify
7
// it under the terms of the GNU General Public License as published by
8
// the Free Software Foundation, either version 3 of the License, or
9
// (at your option) any later version.
11
// This program is distributed in the hope that it will be useful,
12
// but WITHOUT ANY WARRANTY; without even the implied warranty of
13
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
// GNU General Public License for more details.
16
// You should have received a copy of the GNU General Public License
17
// along with this program. If not, see <http://www.gnu.org/licenses/>.
24
#include "DBus-gio.hh"
33
#include "DBusException.hh"
34
#include "DBusBinding-gio.hh"
37
using namespace workrave;
39
const GDBusInterfaceVTable DBus::interface_vtable =
41
&DBus::on_method_call,
42
&DBus::on_get_property,
43
&DBus::on_set_property,
47
//! Construct a new D-BUS bridge
54
//! Destruct the D-BUS bridge
57
for (ServicesCIter i = services.begin(); i != services.end(); i++)
59
g_bus_unown_name(i->second);
62
for (ObjectIter object_it = objects.begin();object_it != objects.end(); object_it++)
64
for (InterfaceIter interface_it = object_it->second.interfaces.begin();
65
interface_it != object_it->second.interfaces.end();
68
if (interface_it->second.registration_id != 0)
70
g_dbus_connection_unregister_object(connection, interface_it->second.registration_id);
73
if (interface_it->second.introspection_data != NULL)
75
g_dbus_node_info_unref(interface_it->second.introspection_data);
82
//! Initialize D-BUS bridge
89
//! Registers the specified service
91
DBus::register_service(const std::string &service_name)
95
owner_id = g_bus_own_name(G_BUS_TYPE_SESSION,
97
G_BUS_NAME_OWNER_FLAGS_NONE,
98
&DBus::on_bus_acquired,
99
NULL, //&DBus::on_name_acquired,
100
NULL, //&DBus::on_name_lost,
104
services[service_name] = owner_id;
108
//! Registers the specified object path
110
DBus::register_object_path(const string &object_path)
112
objects[object_path].registered = true;
117
DBus::update_object_registration(InterfaceData &data)
119
TRACE_ENTER_MSG("DBus::update_object_registration", data.object_path);
120
if (connection == NULL)
122
TRACE_RETURN("No Connection");
126
if (data.registration_id != 0)
128
g_dbus_connection_unregister_object(connection, data.registration_id);
131
string introspection_xml = get_introspect(data.object_path, data.interface_name);
132
TRACE_MSG("Intro: %s" << introspection_xml);
134
GError *error = NULL;
135
data.introspection_data = g_dbus_node_info_new_for_xml(introspection_xml.c_str(), &error);
139
TRACE_MSG("Error: " << error->message);
143
data.registration_id = g_dbus_connection_register_object(connection,
144
data.object_path.c_str(),
145
data.introspection_data->interfaces[0],
153
//! Connect a D-DBUS object/interface to a C object
155
DBus::connect(const std::string &object_path, const std::string &interface_name, void *object)
157
DBusBindingBase *binding = find_binding(interface_name);
160
throw DBusSystemException("No such interface");
163
ObjectIter oit = objects.find(object_path);
164
if (oit == objects.end())
166
objects[object_path].registered = false;
169
ObjectData &object_data = objects[object_path];
171
InterfaceIter iit = object_data.interfaces.find(interface_name);
172
if (iit != object_data.interfaces.end())
174
throw DBusSystemException("Interface already registered");
177
InterfaceData &interface_data = object_data.interfaces[interface_name];
178
interface_data.object_path = object_path;
179
interface_data.interface_name = interface_name;
180
interface_data.object = object;
182
if (object_data.registered)
184
update_object_registration(interface_data);
189
//! Disconnect a D-DBUS object/interface to a C object
191
DBus::disconnect(const std::string &object_path, const std::string &interface_name)
193
ObjectIter it = objects.find(object_path);
194
if (it != objects.end())
196
Interfaces &interfaces = it->second.interfaces;
198
if (interfaces[interface_name].registration_id != 0)
200
g_dbus_connection_unregister_object(connection, interfaces[interface_name].registration_id);
203
if (interfaces[interface_name].introspection_data != NULL)
205
g_dbus_node_info_unref(interfaces[interface_name].introspection_data);
208
interfaces.erase(interface_name);
213
//! Register an interface binding
215
DBus::register_binding(const std::string &name, DBusBindingBase *interface)
217
bindings[name] = interface;
221
//! Find an interface binding
223
DBus::find_binding(const std::string &interface_name) const
225
DBusBindingBase *ret = NULL;
227
BindingCIter it = bindings.find(interface_name);
228
if (it != bindings.end())
238
DBus::find_object(const std::string &path, const std::string &interface_name) const
242
ObjectCIter object_it = objects.find(path);
243
if (object_it != objects.end())
245
InterfaceCIter interface_it = object_it->second.interfaces.find(interface_name);
247
if (interface_it != object_it->second.interfaces.end())
249
object = interface_it->second.object;
258
DBus::is_running(const std::string &name) const
260
TRACE_ENTER("DBus::is_owner");
261
GError *error = NULL;
262
gboolean running = FALSE;
264
GDBusProxy *proxy = g_dbus_proxy_new_for_bus_sync(G_BUS_TYPE_SESSION,
265
G_DBUS_PROXY_FLAGS_NONE,
267
"org.freedesktop.DBus",
268
"/org/freedesktop/DBus",
269
"org.freedesktop.DBus",
275
TRACE_MSG("Error: " << error->message);
279
if (error == NULL && proxy != NULL)
281
GVariant *result = g_dbus_proxy_call_sync(proxy,
283
g_variant_new("(s)", name.c_str()),
284
G_DBUS_CALL_FLAGS_NONE,
291
TRACE_MSG("Error: " << error->message);
296
GVariant *first = g_variant_get_child_value(result, 0);
297
running = g_variant_get_boolean(first);
298
g_variant_unref(first);
299
g_variant_unref(result);
303
TRACE_RETURN(running);
309
DBus::is_available() const
315
DBus::on_bus_name_appeared(GDBusConnection *connection, const gchar *name, const gchar *name_owner, gpointer user_data)
319
DBus *dbus = (DBus *)user_data;
320
dbus->watched[name].seen = true;
321
dbus->bus_name_presence(name, true);
325
DBus::on_bus_name_vanished(GDBusConnection *connection, const gchar *name, gpointer user_data)
328
DBus *dbus = (DBus *)user_data;
329
if (dbus->watched[name].seen)
331
dbus->bus_name_presence(name, false);
336
DBus::bus_name_presence(const std::string &name, bool present)
338
if (watched.find(name) != watched.end())
340
watched[name].callback->bus_name_presence(name, present);
345
DBus::watch(const std::string &name, IDBusWatch *cb)
347
guint id = g_bus_watch_name_on_connection(connection,
349
G_BUS_NAME_WATCHER_FLAGS_NONE,
350
on_bus_name_appeared,
351
on_bus_name_vanished,
354
watched[name].id = id;
355
watched[name].callback = cb;
356
watched[name].seen = false;
360
DBus::unwatch(const std::string &name)
362
guint id = watched[name].id;
363
g_bus_unwatch_name(id);
369
DBus::get_introspect(const string &object_path, const string &interface_name)
371
TRACE_ENTER_MSG("DBus::get_introspect", object_path);
374
str += "<!DOCTYPE node PUBLIC '-//freedesktop//DTD D-BUS Object Introspection 1.0//EN' 'http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd'>\n";
375
str += "<node name='" + object_path + "'>\n";
377
ObjectCIter object_it = objects.find(object_path);
378
if (object_it != objects.end())
380
InterfaceCIter interface_it = object_it->second.interfaces.find(interface_name);
381
if (interface_it != object_it->second.interfaces.end())
383
DBusBindingBase *binding = find_binding(interface_it->first);
386
throw DBusSystemException("Internal error, unknown interface");
389
const char *interface_introspect = binding->get_interface_introspect();
390
str += string(interface_introspect);
401
DBus::on_method_call(GDBusConnection *connection,
403
const gchar *object_path,
404
const gchar *interface_name,
405
const gchar *method_name,
406
GVariant *parameters,
407
GDBusMethodInvocation *invocation,
415
DBus *self = (DBus *) user_data;
417
void *object = self->find_object(object_path, interface_name);
420
throw DBusUsageException(string("No such object: ") + object_path + " " + interface_name );
423
DBusBindingBase *binding = self->find_binding(interface_name);
426
throw DBusSystemException(string("No such binding: ") + interface_name );
429
binding->call(method_name, object, invocation, sender, parameters);
431
catch (DBusException &e)
433
g_dbus_method_invocation_return_error (invocation,
435
G_IO_ERROR_FAILED_HANDLED,
436
e.details().c_str());
442
DBus::on_get_property(GDBusConnection *connection,
444
const gchar *object_path,
445
const gchar *interface_name,
446
const gchar *property_name,
453
(void) interface_name;
454
(void) property_name;
463
DBus::on_set_property(GDBusConnection *connection,
465
const gchar *object_path,
466
const gchar *interface_name,
467
const gchar *property_name,
475
(void) interface_name;
476
(void) property_name;
486
DBus::on_bus_acquired(GDBusConnection *connection, const gchar *name, gpointer user_data)
489
TRACE_ENTER_MSG("DBus::on_bus_acquired", name);
491
DBus *self = (DBus *) user_data;
492
self->connection = connection;
494
for (ObjectIter object_it = self->objects.begin();object_it != self->objects.end(); object_it++)
496
for (InterfaceIter interface_it = object_it->second.interfaces.begin();
497
interface_it != object_it->second.interfaces.end();
500
self->update_object_registration(interface_it->second);
508
DBus::on_name_acquired(GDBusConnection *connection, const gchar *name, gpointer user_data)
513
TRACE_ENTER_MSG("DBus::on_name_acquired", name);
519
DBus::on_name_lost(GDBusConnection *connection, const gchar *name, gpointer user_data)
524
TRACE_ENTER_MSG("DBus::on_name_lost", name);