2
* AT-SPI - Assistive Technology Service Provider Interface
3
* (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
5
* Copyright 2002 Ximian Inc.
6
* Copyright 2002 Sun Microsystems, Inc.
7
* Copyright 2010, 2011 Novell, Inc.
9
* This library is free software; you can redistribute it and/or
10
* modify it under the terms of the GNU Library General Public
11
* License as published by the Free Software Foundation; either
12
* version 2 of the License, or (at your option) any later version.
14
* This library is distributed in the hope that it will be useful,
15
* but WITHOUT ANY WARRANTY; without even the implied warranty of
16
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17
* Library General Public License for more details.
19
* You should have received a copy of the GNU Library General Public
20
* License along with this library; if not, write to the
21
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22
* Boston, MA 02111-1307, USA.
25
#include "atspi-private.h"
30
AtspiDeviceListenerCB callback;
32
GDestroyNotify callback_destroyed;
35
GObjectClass *device_parent_class;
41
static DeviceEventHandler *
42
device_event_handler_new (AtspiDeviceListenerCB callback,
43
GDestroyNotify callback_destroyed,
46
DeviceEventHandler *eh = g_new0 (DeviceEventHandler, 1);
48
eh->callback = callback;
49
eh->callback_destroyed = callback_destroyed;
50
eh->user_data = user_data;
56
device_remove_datum (const AtspiDeviceEvent *event, void *user_data)
58
AtspiDeviceListenerSimpleCB cb = user_data;
63
device_event_handler_free (DeviceEventHandler *eh)
66
/* TODO; Test this; it will probably crash with pyatspi for unknown reasons */
67
if (eh->callback_destroyed)
69
gpointer rea_callback = (eh->callback == device_remove_datum ?
70
eh->user_data : eh->callback);
71
(*eh->callback_destroyed) (real_callback);
78
event_list_remove_by_cb (GList *list, AtspiDeviceListenerCB callback)
82
for (l = list; l; l = next)
84
DeviceEventHandler *eh = l->data;
87
if (eh->callback == callback)
89
list = g_list_delete_link (list, l);
90
device_event_handler_free (eh);
98
* Standard event dispatcher
101
static guint listener_id = 0;
102
static GList *device_listeners = NULL;
105
id_is_free (guint id)
109
for (l = device_listeners; l; l = g_list_next (l))
111
AtspiDeviceListener *listener = l->data;
112
if (listener->id == id) return FALSE;
117
static AtspiDeviceEvent *
118
atspi_device_event_copy (const AtspiDeviceEvent *src)
120
AtspiDeviceEvent *dst = g_new0 (AtspiDeviceEvent, 1);
121
dst->type = src->type;
123
dst->hw_code = src->hw_code;
124
dst->modifiers = src->modifiers;
125
dst->timestamp = src->timestamp;
126
if (src->event_string)
127
dst->event_string = g_strdup (src->event_string);
128
dst->is_text = src->is_text;
133
atspi_device_event_free (AtspiDeviceEvent *event)
135
if (event->event_string)
136
g_free (event->event_string);
141
* Device event handler
144
atspi_device_event_dispatch (AtspiDeviceListener *listener,
145
const AtspiDeviceEvent *event)
148
gboolean handled = FALSE;
150
/* FIXME: re-enterancy hazard on this list */
151
for (l = listener->callbacks; l; l = l->next)
153
DeviceEventHandler *eh = l->data;
155
if ((handled = eh->callback (atspi_device_event_copy (event), eh->user_data)))
165
atspi_device_listener_init (AtspiDeviceListener *listener)
170
listener->id = listener_id++;
171
} while (!id_is_free (listener->id));
172
device_listeners = g_list_append (device_listeners, listener);
176
atspi_device_listener_finalize (GObject *object)
178
AtspiDeviceListener *listener = (AtspiDeviceListener *) object;
181
for (l = listener->callbacks; l; l = l->next)
183
device_event_handler_free (l->data);
186
g_list_free (listener->callbacks);
188
device_parent_class->finalize (object);
192
atspi_device_listener_class_init (AtspiDeviceListenerClass *klass)
194
GObjectClass *object_class = (GObjectClass *) klass;
196
device_parent_class = g_type_class_peek_parent (klass);
197
object_class->finalize = atspi_device_listener_finalize;
199
klass->device_event = atspi_device_event_dispatch;
202
G_DEFINE_TYPE (AtspiDeviceListener, atspi_device_listener,
206
* atspi_device_listener_new:
207
* @callback: (scope notified): an #AtspiDeviceListenerCB callback function,
209
* @user_data: (closure): a pointer to data which will be passed to the
210
* callback when invoked.
211
* @callback_destroyed: A #GDestroyNotify called when the listener is freed
212
* and data associated with the callback should be freed. It can be NULL.
214
* Creates a new #AtspiDeviceListener with a specified callback function.
216
* Returns: (transfer full): a pointer to a newly-created #AtspiDeviceListener.
219
AtspiDeviceListener *
220
atspi_device_listener_new (AtspiDeviceListenerCB callback,
222
GDestroyNotify callback_destroyed)
224
AtspiDeviceListener *listener = g_object_new (atspi_device_listener_get_type (), NULL);
227
atspi_device_listener_add_callback (listener, callback, callback_destroyed,
233
* atspi_device_listener_new_simple: (skip)
234
* @callback: (scope notified): an #AtspiDeviceListenerCB callback function,
236
* @callback_destroyed: A #GDestroyNotify called when the listener is freed
237
* and data associated with the callback should be freed. It an be NULL.
239
* Creates a new #AtspiDeviceListener with a specified callback function.
240
* This method is similar to #atspi_device_listener_new, but callback
241
* takes no user data.
243
* Returns: a pointer to a newly-created #AtspiDeviceListener.
246
AtspiDeviceListener *
247
atspi_device_listener_new_simple (AtspiDeviceListenerSimpleCB callback,
248
GDestroyNotify callback_destroyed)
250
return atspi_device_listener_new (device_remove_datum, callback, callback_destroyed);
254
* atspi_device_listener_add_callback:
255
* @listener: the #AtspiDeviceListener instance to modify.
256
* @callback: (scope notified): an #AtspiDeviceListenerCB function pointer.
257
* @callback_destroyed: A #GDestroyNotify called when the listener is freed
258
* and data associated with the callback should be freed. It can be NULL.
259
* @user_data: (closure): a pointer to data which will be passed to the
260
* callback when invoked.
262
* Adds an in-process callback function to an existing #AtspiDeviceListener.
264
* Returns: #TRUE if successful, otherwise #FALSE.
268
atspi_device_listener_add_callback (AtspiDeviceListener *listener,
269
AtspiDeviceListenerCB callback,
270
GDestroyNotify callback_destroyed,
273
g_return_if_fail (ATSPI_IS_DEVICE_LISTENER (listener));
274
DeviceEventHandler *new_handler;
276
new_handler = device_event_handler_new (callback,
277
callback_destroyed, user_data);
279
listener->callbacks = g_list_prepend (listener->callbacks, new_handler);
283
* atspi_device_listener_remove_callback:
284
* @listener: the #AtspiDeviceListener instance to modify.
285
* @callback: (scope call): an #AtspiDeviceListenerCB function pointer.
287
* Removes an in-process callback function from an existing
288
* #AtspiDeviceListener.
290
* Returns: #TRUE if successful, otherwise #FALSE.
294
atspi_device_listener_remove_callback (AtspiDeviceListener *listener,
295
AtspiDeviceListenerCB callback)
297
g_return_if_fail (ATSPI_IS_DEVICE_LISTENER (listener));
299
listener->callbacks = event_list_remove_by_cb (listener->callbacks, (void *) callback);
303
read_device_event_from_iter (DBusMessageIter *iter, AtspiDeviceEvent *event)
307
dbus_int32_t hw_code;
308
dbus_int32_t modifiers;
309
dbus_int32_t timestamp;
311
DBusMessageIter iter_struct;
313
dbus_message_iter_recurse (iter, &iter_struct);
315
dbus_message_iter_get_basic (&iter_struct, &type);
317
dbus_message_iter_next (&iter_struct);
319
dbus_message_iter_get_basic (&iter_struct, &id);
321
dbus_message_iter_next (&iter_struct);
323
/* TODO: Remove cast from next two on ABI break */
324
dbus_message_iter_get_basic (&iter_struct, &hw_code);
325
event->hw_code = (gushort) hw_code;
326
dbus_message_iter_next (&iter_struct);
328
dbus_message_iter_get_basic (&iter_struct, &modifiers);
329
event->modifiers = (gushort) modifiers;
330
dbus_message_iter_next (&iter_struct);
332
dbus_message_iter_get_basic (&iter_struct, ×tamp);
333
event->timestamp = timestamp;
334
dbus_message_iter_next (&iter_struct);
336
dbus_message_iter_get_basic (&iter_struct, &event->event_string);
337
dbus_message_iter_next (&iter_struct);
339
dbus_message_iter_get_basic (&iter_struct, &is_text);
340
event->is_text = is_text;
344
_atspi_dbus_handle_DeviceEvent (DBusConnection *bus, DBusMessage *message, void *data)
346
const char *path = dbus_message_get_path (message);
348
AtspiDeviceEvent event;
349
AtspiDeviceListener *listener;
350
DBusMessageIter iter;
351
AtspiDeviceListenerClass *klass;
352
dbus_bool_t retval = FALSE;
356
if (strcmp (dbus_message_get_signature (message), "(uiuuisb)") != 0)
358
g_warning ("Atspi: Unknown signature for an event");
362
if (sscanf (path, "/org/a11y/atspi/listeners/%d", &id) != 1)
364
g_warning ("Atspi: Bad listener path: %s\n", path);
368
for (l = device_listeners; l; l = g_list_next (l))
371
if (listener->id == id) break;
378
dbus_message_iter_init (message, &iter);
379
read_device_event_from_iter (&iter, &event);
380
klass = ATSPI_DEVICE_LISTENER_GET_CLASS (listener);
381
if (klass->device_event)
383
retval = (*klass->device_event) (listener, &event);
384
if (retval != 0 && retval != 1)
386
g_warning ("at-spi: device event handler returned %d; should be 0 or 1", retval);
391
reply = dbus_message_new_method_return (message);
394
dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &retval, DBUS_TYPE_INVALID);
395
dbus_connection_send (_atspi_bus(), reply, NULL);
396
dbus_message_unref (reply);
398
return DBUS_HANDLER_RESULT_HANDLED;
402
_atspi_device_listener_get_path (AtspiDeviceListener *listener)
403
{ return g_strdup_printf ("/org/a11y/atspi/listeners/%d", listener->id);
406
G_DEFINE_BOXED_TYPE (AtspiDeviceEvent,
408
atspi_device_event_copy,
409
atspi_device_event_free)