~ubuntu-branches/ubuntu/trusty/geis/trusty

« back to all changes in this revision

Viewing changes to libgeis/server/geis_dbus_client_proxy.c

  • Committer: Package Import Robot
  • Author(s): Chase Douglas
  • Date: 2012-07-30 08:51:42 UTC
  • Revision ID: package-import@ubuntu.com-20120730085142-jrc33ygjvt0ob1wl
Tags: upstream-2.2.11
ImportĀ upstreamĀ versionĀ 2.2.11

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/**
 
2
 * @file geis_dbus_client_proxy.c
 
3
 * @brief Implementation of the GEIS DBus client proxy.
 
4
 *
 
5
 */
 
6
 
 
7
/*
 
8
 * Copyright 2011 Canonical Ltd.
 
9
 *
 
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
 
13
 * later version.
 
14
 *
 
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
 
18
 * details.
 
19
 *
 
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/>.
 
22
 */
 
23
#include "geis_config.h"
 
24
#include "geis_dbus_client_proxy.h"
 
25
 
 
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"
 
36
#include <stdlib.h>
 
37
 
 
38
 
 
39
struct GeisDBusClientProxy
 
40
{
 
41
  GeisDBusServer  server;
 
42
  DBusConnection *connection;
 
43
  GeisSubBag      subscriptions;
 
44
};
 
45
 
 
46
 
 
47
/**
 
48
 * Allocates a client proxy from a memory pool.
 
49
 *
 
50
 * This is a customization point for future refinement of object allocation.
 
51
 *
 
52
 * @returns an allocated GeisDBusClientProxy object or NULL on allocation
 
53
 * failure.
 
54
 */
 
55
GeisDBusClientProxy
 
56
_client_proxy_allocate()
 
57
{
 
58
  GeisDBusClientProxy proxy = calloc(1, sizeof(struct GeisDBusClientProxy));
 
59
  return proxy;
 
60
}
 
61
 
 
62
 
 
63
/**
 
64
 * Deallocates a client proxy object, returning its memory to a pool.
 
65
 *
 
66
 * @param[in] proxy The %GeisDBusClientProxy to deallocate.
 
67
 *
 
68
 * This is a customization point for future refinement of object allocation.
 
69
 */
 
70
void
 
71
_client_proxy_deallocate(GeisDBusClientProxy proxy)
 
72
{
 
73
  free(proxy);
 
74
}
 
75
 
 
76
 
 
77
/**
 
78
 * Handles subscription creation requests.
 
79
 *
 
80
 * @param[in] proxy    A %GeisDBusClientProxy.
 
81
 * @param[in] message  The DBus message from the proxied client.
 
82
 */
 
83
static DBusMessage *
 
84
_client_proxy_subscribe(GeisDBusClientProxy proxy, DBusMessage *message)
 
85
{
 
86
  Geis geis = geis_dbus_server_geis(proxy->server);
 
87
  GeisSubscription sub;
 
88
  DBusMessage *reply;
 
89
 
 
90
  sub = geis_dbus_subscription_from_create_call_message(geis, message);
 
91
  if (!sub)
 
92
  {
 
93
    reply = dbus_message_new_error(message,
 
94
                                   GEIS_DBUS_ERROR_SUBSCRIPTION_FAIL,
 
95
                                   "error creating proxy from DBus message");
 
96
    goto final_exit;
 
97
  }
 
98
 
 
99
  geis_subscription_bag_insert(proxy->subscriptions, sub);
 
100
 
 
101
  if (GEIS_STATUS_SUCCESS != geis_subscription_activate(sub))
 
102
  {
 
103
    reply = dbus_message_new_error(message,
 
104
                                   GEIS_DBUS_ERROR_SUBSCRIPTION_FAIL,
 
105
                                   "error activating proxy subscription");
 
106
    goto final_exit;
 
107
  }
 
108
 
 
109
  reply = geis_dbus_subscription_create_return_message(message, sub);
 
110
 
 
111
final_exit:
 
112
  return reply;
 
113
}
 
114
 
 
115
 
 
116
/**
 
117
 * Handles subscription activation requests.
 
118
 *
 
119
 * @param[in] proxy    A %GeisDBusClientProxy.
 
120
 * @param[in] message  The DBus message from the proxied client.
 
121
 *
 
122
 * @returns a DBus reply message to send.
 
123
 *
 
124
 * @todo Implement subscription retrieval.
 
125
 */
 
126
static DBusMessage *
 
127
_client_proxy_activate(GeisDBusClientProxy  proxy GEIS_UNUSED,
 
128
                       DBusMessage         *message)
 
129
{
 
130
  GeisSubscription sub = NULL;
 
131
  DBusMessage *reply;
 
132
 
 
133
  reply = geis_dbus_subscription_activate_return_message(message, sub);
 
134
  return reply;
 
135
}
 
136
 
 
137
 
 
138
/**
 
139
 * Handles subscription deactivation requests.
 
140
 *
 
141
 * @param[in] proxy    A %GeisDBusClientProxy.
 
142
 * @param[in] message  The DBus message from the proxied client.
 
143
 *
 
144
 * @returns a DBus reply message to send.
 
145
 *
 
146
 * @todo Implement subscription retrieval.
 
147
 */
 
148
static DBusMessage *
 
149
_client_proxy_deactivate(GeisDBusClientProxy  proxy GEIS_UNUSED,
 
150
                         DBusMessage         *message)
 
151
{
 
152
  GeisSubscription sub = NULL;
 
153
  DBusMessage *reply;
 
154
 
 
155
  reply = geis_dbus_subscription_deactivate_return_message(message, sub);
 
156
  return reply;
 
157
}
 
158
 
 
159
 
 
160
/**
 
161
 * Handles subscription destroy requests.
 
162
 *
 
163
 * @param[in] proxy    A %GeisDBusClientProxy.
 
164
 * @param[in] message  The DBus message from the proxied client.
 
165
 *
 
166
 * @returns a DBus reply message to send.
 
167
 *
 
168
 * @todo Implement this function.
 
169
 */
 
170
static DBusMessage *
 
171
_client_proxy_unsubscribe(GeisDBusClientProxy  proxy GEIS_UNUSED,
 
172
                          DBusMessage         *message)
 
173
{
 
174
  dbus_int32_t server_sub_id;
 
175
  dbus_message_get_args(message, NULL,
 
176
                        DBUS_TYPE_INT32 , &server_sub_id,
 
177
                        DBUS_TYPE_INVALID);
 
178
  GeisSubscription sub = geis_subscription_bag_find(proxy->subscriptions,
 
179
                                                    server_sub_id);
 
180
  geis_subscription_deactivate(sub);
 
181
  geis_subscription_bag_remove(proxy->subscriptions, sub);
 
182
  geis_subscription_delete(sub);
 
183
 
 
184
  DBusMessage *reply = geis_dbus_subscription_destroy_return_message(message);
 
185
  return reply;
 
186
}
 
187
 
 
188
 
 
189
/**
 
190
 * The DBus message dispatch function for the client proxy.
 
191
 *
 
192
 * @param[in] connection  The %GeisDBusClientProxy DBus connection.
 
193
 * @param[in] message     The DBus message received.
 
194
 * @param[in] user_data   The %GeisDBusClientProxy.
 
195
 */
 
196
static DBusHandlerResult
 
197
_client_proxy_message_handler(DBusConnection *connection,
 
198
                              DBusMessage    *message,
 
199
                              void           *user_data)
 
200
{
 
201
  DBusHandlerResult result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 
202
  GeisDBusClientProxy proxy = (GeisDBusClientProxy)user_data;
 
203
 
 
204
  if (dbus_message_is_signal(message,
 
205
                             DBUS_INTERFACE_LOCAL,
 
206
                             "Disconnected"))
 
207
  {
 
208
    geis_dbus_server_client_disconnect(proxy->server, proxy);
 
209
    result = DBUS_HANDLER_RESULT_HANDLED;
 
210
  }
 
211
  else if (geis_dbus_message_is_subscription_create_call(message))
 
212
  {
 
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;
 
217
  }
 
218
  else if (geis_dbus_message_is_subscription_activate_call(message))
 
219
  {
 
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;
 
224
  }
 
225
  else if (geis_dbus_message_is_subscription_deactivate_call(message))
 
226
  {
 
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;
 
231
  }
 
232
  else if (geis_dbus_message_is_subscription_destroy_call(message))
 
233
  {
 
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;
 
238
  }
 
239
  else if (DBUS_MESSAGE_TYPE_ERROR == dbus_message_get_type(message))
 
240
  {
 
241
    const char *s = NULL;
 
242
    dbus_message_get_args(message, NULL,
 
243
                          DBUS_TYPE_STRING, &s,
 
244
                          DBUS_TYPE_INVALID);
 
245
    geis_error("error %s: %s", dbus_message_get_error_name(message), s);
 
246
  }
 
247
  else
 
248
  {
 
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) :
 
256
                 "(no path)");
 
257
    geis_warning("  interface=\"%s\"",
 
258
                 dbus_message_get_interface(message) ?
 
259
                 dbus_message_get_interface(message) :
 
260
                 "(no interface)");
 
261
    geis_warning("  member=\"%s\"",
 
262
                 dbus_message_get_member(message) ?
 
263
                 dbus_message_get_member(message) :
 
264
                 "(no member)");
 
265
  }
 
266
  return result;
 
267
}
 
268
 
 
269
 
 
270
/**
 
271
 * Reports all currently-known gesture-capable input devices to the proxied
 
272
 * client.
 
273
 *
 
274
 * @param[in] proxy    A %GeisDBusClientProxy.
 
275
 */
 
276
static void
 
277
_client_proxy_report_devices(GeisDBusClientProxy proxy)
 
278
{
 
279
  GeisDeviceBag devices = geis_devices(geis_dbus_server_geis(proxy->server));
 
280
  for (GeisSize i = 0; i < geis_device_bag_count(devices); ++i)
 
281
  {
 
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);
 
286
  }
 
287
}
 
288
 
 
289
 
 
290
/**
 
291
 * Reports all currently-known gesture classes to the proxied client.
 
292
 *
 
293
 * @param[in] proxy    A %GeisDBusClientProxy.
 
294
 */
 
295
static void
 
296
_client_proxy_report_classes(GeisDBusClientProxy proxy)
 
297
{
 
298
  GeisGestureClassBag classes;
 
299
 
 
300
  classes = geis_gesture_classes(geis_dbus_server_geis(proxy->server));
 
301
  for (GeisSize i = 0; i < geis_gesture_class_bag_count(classes); ++i)
 
302
  {
 
303
    GeisGestureClass gesture_class;
 
304
    DBusMessage *message;
 
305
 
 
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);
 
310
  }
 
311
}
 
312
 
 
313
 
 
314
/**
 
315
 * Reports all currently-known regions to the proxied client.
 
316
 *
 
317
 * @param[in] proxy    A %GeisDBusClientProxy.
 
318
 *
 
319
 * OK, in reality, this just sends the valid and available filterable region
 
320
 * attributes.  Go wild.
 
321
 */
 
322
static void
 
323
_client_proxy_report_regions(GeisDBusClientProxy proxy GEIS_UNUSED)
 
324
{
 
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))
 
328
  {
 
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);
 
333
  }
 
334
}
 
335
 
 
336
 
 
337
/**
 
338
 * Adds the client proxy watches to the dispatcher watch list.
 
339
 *
 
340
 * @param[in] watch  A %DBusWatch.
 
341
 * @param[in] data   The %GeisDBusClientProxy.
 
342
 */
 
343
static dbus_bool_t
 
344
_client_proxy_add_watch(DBusWatch *watch, void *data)
 
345
{
 
346
  dbus_bool_t status = TRUE;
 
347
  GeisDBusClientProxy proxy = (GeisDBusClientProxy)data;
 
348
 
 
349
  geis_dbus_dispatcher_register(geis_dbus_server_dispatcher(proxy->server),
 
350
                                proxy->connection,
 
351
                                watch);
 
352
  return status;
 
353
}
 
354
 
 
355
 
 
356
/**
 
357
 * Toggles the enabled/disabled status of the client proxy watches.
 
358
 *
 
359
 * @param[in] watch  A %DBusWatch.
 
360
 * @param[in] data   The %GeisDBusClientProxy.
 
361
 */
 
362
static void
 
363
_client_proxy_toggle_watch(DBusWatch *watch, void *data)
 
364
{
 
365
  GeisDBusClientProxy proxy = (GeisDBusClientProxy)data;
 
366
 
 
367
  geis_dbus_dispatcher_toggle_watch(geis_dbus_server_dispatcher(proxy->server),
 
368
                                    watch);
 
369
}
 
370
 
 
371
 
 
372
/**
 
373
 * Removes the client proxy watches from the dispatcher watch list.
 
374
 *
 
375
 * @param[in] watch  A %DBusWatch.
 
376
 * @param[in] data   The %GeisDBusClientProxy.
 
377
 */
 
378
static void
 
379
_client_proxy_remove_watch(DBusWatch *watch, void *data)
 
380
{
 
381
  GeisDBusClientProxy proxy = (GeisDBusClientProxy)data;
 
382
 
 
383
  geis_dbus_dispatcher_unregister(geis_dbus_server_dispatcher(proxy->server),
 
384
                                  watch);
 
385
}
 
386
 
 
387
 
 
388
/*
 
389
 * Creates a new %GeisDBusClientProxy object.
 
390
 */
 
391
GeisDBusClientProxy
 
392
geis_dbus_client_proxy_new(GeisDBusServer server, DBusConnection *connection)
 
393
{
 
394
  GeisDBusClientProxy proxy = _client_proxy_allocate();
 
395
  if (!proxy)
 
396
  {
 
397
    geis_error("error allocating client proxy");
 
398
    goto final_exit;
 
399
  }
 
400
 
 
401
  proxy->server = server;
 
402
  proxy->connection = dbus_connection_ref(connection);
 
403
  proxy->subscriptions = geis_subscription_bag_new(2);
 
404
  if (!proxy->subscriptions)
 
405
  {
 
406
    dbus_connection_unref(proxy->connection);
 
407
    goto final_exit;
 
408
  }
 
409
 
 
410
  /* Don't shut down the app on disconnect, that would be unmutual. */
 
411
  dbus_connection_set_exit_on_disconnect(proxy->connection, FALSE);
 
412
  
 
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,
 
418
                                      proxy, 0);
 
419
 
 
420
  /* Install a handler for any and all messages. */
 
421
  dbus_connection_add_filter(proxy->connection,
 
422
                             _client_proxy_message_handler,
 
423
                             proxy, 0);
 
424
 
 
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);
 
429
 
 
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);
 
436
 
 
437
final_exit:
 
438
  return proxy;
 
439
}
 
440
 
 
441
 
 
442
/*
 
443
 * Destroys a %GeisDBusClientProxy.
 
444
 */
 
445
void
 
446
geis_dbus_client_proxy_delete(GeisDBusClientProxy proxy)
 
447
{
 
448
  geis_subscription_bag_delete(proxy->subscriptions);
 
449
  dbus_connection_unref(proxy->connection);
 
450
  _client_proxy_deallocate(proxy);
 
451
}
 
452
 
 
453
 
 
454
/*
 
455
 * Handles a GEIS event.
 
456
 *
 
457
 * GEIS events are generally gesture events.  Don;t be fooled, though, there may
 
458
 * be others and this function is incomplete.
 
459
 *
 
460
 * @todo Refine this function to handle non-gesture events.
 
461
 */
 
462
void
 
463
geis_dbus_client_proxy_handle_geis_event(GeisDBusClientProxy proxy,
 
464
                                         GeisEvent           event)
 
465
{
 
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))
 
469
  {
 
470
    for (GeisFilterIterator fit = geis_subscription_filter_begin(*sit);
 
471
         fit != geis_subscription_filter_end(*sit);
 
472
         fit = geis_subscription_filter_next(*sit, fit))
 
473
    {
 
474
      if (geis_filter_pass_event(*fit, event))
 
475
      {
 
476
        DBusMessage *message;
 
477
 
 
478
        message = geis_dbus_gesture_event_message_from_geis_event(event);
 
479
        dbus_connection_send(proxy->connection, message, NULL);
 
480
        dbus_message_unref(message);
 
481
      }
 
482
    }
 
483
  }
 
484
}
 
485
 
 
486