2
* @file geis_dbus_client_proxy.c
3
* @brief Implementation of the GEIS DBus client proxy.
8
* Copyright 2011 Canonical Ltd.
10
* This library is free software; you can redistribute it and/or modify it under
11
* the terms of the GNU Lesser General Public License as published by the Free
12
* Software Foundation; either version 3 of the License, or (at your option) any
15
* This library is distributed in the hope that it will be useful, but WITHOUT
16
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
20
* You should have received a copy of the GNU General Public License
21
* along with this program. If not, see <http://www.gnu.org/licenses/>.
23
#include "geis_config.h"
24
#include "geis_dbus_client_proxy.h"
26
#include "geis_dbus.h"
27
#include "geis_dbus_class.h"
28
#include "geis_dbus_device.h"
29
#include "geis_dbus_gesture_event.h"
30
#include "geis_dbus_region.h"
31
#include "geis_dbus_subscription.h"
32
#include "geis_device.h"
33
#include "geis_filter.h"
34
#include "geis_logging.h"
35
#include "geis_private.h"
39
struct GeisDBusClientProxy
41
GeisDBusServer server;
42
DBusConnection *connection;
43
GeisSubBag subscriptions;
48
* Allocates a client proxy from a memory pool.
50
* This is a customization point for future refinement of object allocation.
52
* @returns an allocated GeisDBusClientProxy object or NULL on allocation
56
_client_proxy_allocate()
58
GeisDBusClientProxy proxy = calloc(1, sizeof(struct GeisDBusClientProxy));
64
* Deallocates a client proxy object, returning its memory to a pool.
66
* @param[in] proxy The %GeisDBusClientProxy to deallocate.
68
* This is a customization point for future refinement of object allocation.
71
_client_proxy_deallocate(GeisDBusClientProxy proxy)
78
* Handles subscription creation requests.
80
* @param[in] proxy A %GeisDBusClientProxy.
81
* @param[in] message The DBus message from the proxied client.
84
_client_proxy_subscribe(GeisDBusClientProxy proxy, DBusMessage *message)
86
Geis geis = geis_dbus_server_geis(proxy->server);
90
sub = geis_dbus_subscription_from_create_call_message(geis, message);
93
reply = dbus_message_new_error(message,
94
GEIS_DBUS_ERROR_SUBSCRIPTION_FAIL,
95
"error creating proxy from DBus message");
99
geis_subscription_bag_insert(proxy->subscriptions, sub);
101
if (GEIS_STATUS_SUCCESS != geis_subscription_activate(sub))
103
reply = dbus_message_new_error(message,
104
GEIS_DBUS_ERROR_SUBSCRIPTION_FAIL,
105
"error activating proxy subscription");
109
reply = geis_dbus_subscription_create_return_message(message, sub);
117
* Handles subscription activation requests.
119
* @param[in] proxy A %GeisDBusClientProxy.
120
* @param[in] message The DBus message from the proxied client.
122
* @returns a DBus reply message to send.
124
* @todo Implement subscription retrieval.
127
_client_proxy_activate(GeisDBusClientProxy proxy GEIS_UNUSED,
128
DBusMessage *message)
130
GeisSubscription sub = NULL;
133
reply = geis_dbus_subscription_activate_return_message(message, sub);
139
* Handles subscription deactivation requests.
141
* @param[in] proxy A %GeisDBusClientProxy.
142
* @param[in] message The DBus message from the proxied client.
144
* @returns a DBus reply message to send.
146
* @todo Implement subscription retrieval.
149
_client_proxy_deactivate(GeisDBusClientProxy proxy GEIS_UNUSED,
150
DBusMessage *message)
152
GeisSubscription sub = NULL;
155
reply = geis_dbus_subscription_deactivate_return_message(message, sub);
161
* Handles subscription destroy requests.
163
* @param[in] proxy A %GeisDBusClientProxy.
164
* @param[in] message The DBus message from the proxied client.
166
* @returns a DBus reply message to send.
168
* @todo Implement this function.
171
_client_proxy_unsubscribe(GeisDBusClientProxy proxy GEIS_UNUSED,
172
DBusMessage *message)
174
dbus_int32_t server_sub_id;
175
dbus_message_get_args(message, NULL,
176
DBUS_TYPE_INT32 , &server_sub_id,
178
GeisSubscription sub = geis_subscription_bag_find(proxy->subscriptions,
180
geis_subscription_deactivate(sub);
181
geis_subscription_bag_remove(proxy->subscriptions, sub);
182
geis_subscription_delete(sub);
184
DBusMessage *reply = geis_dbus_subscription_destroy_return_message(message);
190
* The DBus message dispatch function for the client proxy.
192
* @param[in] connection The %GeisDBusClientProxy DBus connection.
193
* @param[in] message The DBus message received.
194
* @param[in] user_data The %GeisDBusClientProxy.
196
static DBusHandlerResult
197
_client_proxy_message_handler(DBusConnection *connection,
198
DBusMessage *message,
201
DBusHandlerResult result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
202
GeisDBusClientProxy proxy = (GeisDBusClientProxy)user_data;
204
if (dbus_message_is_signal(message,
205
DBUS_INTERFACE_LOCAL,
208
geis_dbus_server_client_disconnect(proxy->server, proxy);
209
result = DBUS_HANDLER_RESULT_HANDLED;
211
else if (geis_dbus_message_is_subscription_create_call(message))
213
DBusMessage *reply = _client_proxy_subscribe(proxy, message);
214
dbus_connection_send(connection, reply, NULL);
215
dbus_message_unref(reply);
216
result = DBUS_HANDLER_RESULT_HANDLED;
218
else if (geis_dbus_message_is_subscription_activate_call(message))
220
DBusMessage *reply = _client_proxy_activate(proxy, message);
221
dbus_connection_send(connection, reply, NULL);
222
dbus_message_unref(reply);
223
result = DBUS_HANDLER_RESULT_HANDLED;
225
else if (geis_dbus_message_is_subscription_deactivate_call(message))
227
DBusMessage *reply = _client_proxy_deactivate(proxy, message);
228
dbus_connection_send(connection, reply, NULL);
229
dbus_message_unref(reply);
230
result = DBUS_HANDLER_RESULT_HANDLED;
232
else if (geis_dbus_message_is_subscription_destroy_call(message))
234
DBusMessage *reply = _client_proxy_unsubscribe(proxy, message);
235
dbus_connection_send(connection, reply, NULL);
236
dbus_message_unref(reply);
237
result = DBUS_HANDLER_RESULT_HANDLED;
239
else if (DBUS_MESSAGE_TYPE_ERROR == dbus_message_get_type(message))
241
const char *s = NULL;
242
dbus_message_get_args(message, NULL,
243
DBUS_TYPE_STRING, &s,
245
geis_error("error %s: %s", dbus_message_get_error_name(message), s);
249
geis_warning("unhandled DBus %s received:",
250
dbus_message_type_to_string(dbus_message_get_type(message)));
251
geis_warning(" signature=\"%s\"", dbus_message_get_signature(message));
252
geis_warning(" sender=\"%s\"", dbus_message_get_sender(message));
253
geis_warning(" path=\"%s\"",
254
dbus_message_get_path(message) ?
255
dbus_message_get_path(message) :
257
geis_warning(" interface=\"%s\"",
258
dbus_message_get_interface(message) ?
259
dbus_message_get_interface(message) :
261
geis_warning(" member=\"%s\"",
262
dbus_message_get_member(message) ?
263
dbus_message_get_member(message) :
271
* Reports all currently-known gesture-capable input devices to the proxied
274
* @param[in] proxy A %GeisDBusClientProxy.
277
_client_proxy_report_devices(GeisDBusClientProxy proxy)
279
GeisDeviceBag devices = geis_devices(geis_dbus_server_geis(proxy->server));
280
for (GeisSize i = 0; i < geis_device_bag_count(devices); ++i)
282
GeisDevice device = geis_device_bag_device(devices, i);
283
DBusMessage *message = geis_dbus_device_available_message_from_device(device);
284
dbus_connection_send(proxy->connection, message, NULL);
285
dbus_message_unref(message);
291
* Reports all currently-known gesture classes to the proxied client.
293
* @param[in] proxy A %GeisDBusClientProxy.
296
_client_proxy_report_classes(GeisDBusClientProxy proxy)
298
GeisGestureClassBag classes;
300
classes = geis_gesture_classes(geis_dbus_server_geis(proxy->server));
301
for (GeisSize i = 0; i < geis_gesture_class_bag_count(classes); ++i)
303
GeisGestureClass gesture_class;
304
DBusMessage *message;
306
gesture_class = geis_gesture_class_bag_gesture_class(classes, i);
307
message = geis_dbus_class_available_message_from_class(gesture_class);
308
dbus_connection_send(proxy->connection, message, NULL);
309
dbus_message_unref(message);
315
* Reports all currently-known regions to the proxied client.
317
* @param[in] proxy A %GeisDBusClientProxy.
319
* OK, in reality, this just sends the valid and available filterable region
320
* attributes. Go wild.
323
_client_proxy_report_regions(GeisDBusClientProxy proxy GEIS_UNUSED)
325
Geis geis = geis_dbus_server_geis(proxy->server);
326
GeisFilterableAttributeBagIter it = geis_region_filter_attrs_begin(geis);
327
while (it != geis_region_filter_attrs_end(geis))
329
DBusMessage *message = geis_dbus_region_available_message_from_region(&*it);
330
dbus_connection_send(proxy->connection, message, NULL);
331
dbus_message_unref(message);
332
it = geis_region_filter_attrs_next(geis, it);
338
* Adds the client proxy watches to the dispatcher watch list.
340
* @param[in] watch A %DBusWatch.
341
* @param[in] data The %GeisDBusClientProxy.
344
_client_proxy_add_watch(DBusWatch *watch, void *data)
346
dbus_bool_t status = TRUE;
347
GeisDBusClientProxy proxy = (GeisDBusClientProxy)data;
349
geis_dbus_dispatcher_register(geis_dbus_server_dispatcher(proxy->server),
357
* Toggles the enabled/disabled status of the client proxy watches.
359
* @param[in] watch A %DBusWatch.
360
* @param[in] data The %GeisDBusClientProxy.
363
_client_proxy_toggle_watch(DBusWatch *watch, void *data)
365
GeisDBusClientProxy proxy = (GeisDBusClientProxy)data;
367
geis_dbus_dispatcher_toggle_watch(geis_dbus_server_dispatcher(proxy->server),
373
* Removes the client proxy watches from the dispatcher watch list.
375
* @param[in] watch A %DBusWatch.
376
* @param[in] data The %GeisDBusClientProxy.
379
_client_proxy_remove_watch(DBusWatch *watch, void *data)
381
GeisDBusClientProxy proxy = (GeisDBusClientProxy)data;
383
geis_dbus_dispatcher_unregister(geis_dbus_server_dispatcher(proxy->server),
389
* Creates a new %GeisDBusClientProxy object.
392
geis_dbus_client_proxy_new(GeisDBusServer server, DBusConnection *connection)
394
GeisDBusClientProxy proxy = _client_proxy_allocate();
397
geis_error("error allocating client proxy");
401
proxy->server = server;
402
proxy->connection = dbus_connection_ref(connection);
403
proxy->subscriptions = geis_subscription_bag_new(2);
404
if (!proxy->subscriptions)
406
dbus_connection_unref(proxy->connection);
410
/* Don't shut down the app on disconnect, that would be unmutual. */
411
dbus_connection_set_exit_on_disconnect(proxy->connection, FALSE);
413
/* Integrate with the app event loop via the GEIS multiplexor. */
414
dbus_connection_set_watch_functions(proxy->connection,
415
_client_proxy_add_watch,
416
_client_proxy_remove_watch,
417
_client_proxy_toggle_watch,
420
/* Install a handler for any and all messages. */
421
dbus_connection_add_filter(proxy->connection,
422
_client_proxy_message_handler,
425
/* Kick off reporting devices and classes. */
426
_client_proxy_report_devices(proxy);
427
_client_proxy_report_classes(proxy);
428
_client_proxy_report_regions(proxy);
430
/* Tell the remote end it's a go. */
431
DBusMessage *message = dbus_message_new_signal(GEIS_DBUS_SERVICE_PATH,
432
GEIS_DBUS_SERVICE_INTERFACE,
433
GEIS_DBUS_INIT_COMPLETE);
434
dbus_connection_send(proxy->connection, message, NULL);
435
dbus_message_unref(message);
443
* Destroys a %GeisDBusClientProxy.
446
geis_dbus_client_proxy_delete(GeisDBusClientProxy proxy)
448
geis_subscription_bag_delete(proxy->subscriptions);
449
dbus_connection_unref(proxy->connection);
450
_client_proxy_deallocate(proxy);
455
* Handles a GEIS event.
457
* GEIS events are generally gesture events. Don;t be fooled, though, there may
458
* be others and this function is incomplete.
460
* @todo Refine this function to handle non-gesture events.
463
geis_dbus_client_proxy_handle_geis_event(GeisDBusClientProxy proxy,
466
for (GeisSubBagIterator sit = geis_subscription_bag_begin(proxy->subscriptions);
467
sit != geis_subscription_bag_end(proxy->subscriptions);
468
sit = geis_subscription_bag_iterator_next(proxy->subscriptions, sit))
470
for (GeisFilterIterator fit = geis_subscription_filter_begin(*sit);
471
fit != geis_subscription_filter_end(*sit);
472
fit = geis_subscription_filter_next(*sit, fit))
474
if (geis_filter_pass_event(*fit, event))
476
DBusMessage *message;
478
message = geis_dbus_gesture_event_message_from_geis_event(event);
479
dbus_connection_send(proxy->connection, message, NULL);
480
dbus_message_unref(message);