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.
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
18 * You should have received a copy of the GNU Library General Public
19 * License along with this library; if not, write to the
20 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 * Boston, MA 02111-1307, USA.
24 #include "atspi-private.h"
29 AtspiDeviceListenerCB callback;
31 GDestroyNotify callback_destroyed;
34 GObjectClass *device_parent_class;
40 static DeviceEventHandler *
41 device_event_handler_new (AtspiDeviceListenerCB callback,
42 GDestroyNotify callback_destroyed,
45 DeviceEventHandler *eh = g_new0 (DeviceEventHandler, 1);
47 eh->callback = callback;
48 eh->callback_destroyed = callback_destroyed;
49 eh->user_data = user_data;
55 device_remove_datum (const AtspiDeviceEvent *event, void *user_data)
57 AtspiDeviceListenerSimpleCB cb = user_data;
62 device_event_handler_free (DeviceEventHandler *eh)
65 /* TODO; Test this; it will probably crash with pyatspi for unknown reasons */
66 if (eh->callback_destroyed)
68 gpointer rea_callback = (eh->callback == device_remove_datum ?
69 eh->user_data : eh->callback);
70 (*eh->callback_destroyed) (real_callback);
77 event_list_remove_by_cb (GList *list, AtspiDeviceListenerCB callback)
81 for (l = list; l; l = next)
83 DeviceEventHandler *eh = l->data;
86 if (eh->callback == callback)
88 list = g_list_delete_link (list, l);
89 device_event_handler_free (eh);
97 * Standard event dispatcher
100 static guint listener_id = 0;
101 static GList *device_listeners = NULL;
104 id_is_free (guint id)
108 for (l = device_listeners; l; l = g_list_next (l))
110 AtspiDeviceListener *listener = l->data;
111 if (listener->id == id) return FALSE;
116 static AtspiDeviceEvent *
117 atspi_device_event_copy (AtspiDeviceEvent *src)
119 AtspiDeviceEvent *dst = g_new0 (AtspiDeviceEvent, 1);
122 dst->type = src->type;
124 dst->hw_code = src->hw_code;
125 dst->modifiers = src->modifiers;
126 dst->timestamp = src->timestamp;
127 if (src->event_string)
128 dst->event_string = g_strdup (src->event_string);
129 dst->is_text = src->is_text;
134 atspi_device_event_free (AtspiDeviceEvent *event)
136 if (event->event_string)
137 g_free (event->event_string);
142 * Device event handler
145 atspi_device_event_dispatch (AtspiDeviceListener *listener,
146 const AtspiDeviceEvent *event)
149 gboolean handled = FALSE;
151 /* FIXME: re-enterancy hazard on this list */
152 for (l = listener->callbacks; l; l = l->next)
154 DeviceEventHandler *eh = l->data;
156 if ((handled = eh->callback (atspi_device_event_copy (event), eh->user_data)))
166 atspi_device_listener_init (AtspiDeviceListener *listener)
172 listener->id = listener_id++;
173 } while (!id_is_free (listener->id));
174 new_list = g_list_append (device_listeners, listener);
175 if (new_list) device_listeners = new_list;
179 atspi_device_listener_finalize (GObject *object)
181 AtspiDeviceListener *listener = (AtspiDeviceListener *) object;
184 for (l = listener->callbacks; l; l = l->next)
186 device_event_handler_free (l->data);
189 g_list_free (listener->callbacks);
191 device_parent_class->finalize (object);
195 atspi_device_listener_class_init (AtspiDeviceListenerClass *klass)
197 GObjectClass *object_class = (GObjectClass *) klass;
199 device_parent_class = g_type_class_peek_parent (klass);
200 object_class->finalize = atspi_device_listener_finalize;
202 klass->device_event = atspi_device_event_dispatch;
205 G_DEFINE_TYPE (AtspiDeviceListener, atspi_device_listener,
209 * atspi_device_listener_new:
210 * @callback: (scope notify): an #AtspiDeviceListenerCB callback function,
212 * @callback_destroyed: A #GDestroyNotify called when the listener is freed
213 * and data associated with the callback should be freed. Can be NULL.
214 * @user_data: (closure): a pointer to data which will be passed to the
215 * callback when invoked.
217 * Create a new #AtspiDeviceListener with a specified callback function.
219 * Returns: a pointer to a newly-created #AtspiDeviceListener.
222 AtspiDeviceListener *
223 atspi_device_listener_new (AtspiDeviceListenerCB callback,
224 GDestroyNotify callback_destroyed,
227 AtspiDeviceListener *listener = g_object_new (atspi_device_listener_get_type (), NULL);
230 atspi_device_listener_add_callback (listener, callback, callback_destroyed,
236 * atspi_device_listener_new_simple:
237 * @callback: (scope notify): an #AtspiDeviceListenerCB callback function,
239 * @callback_destroyed: A #GDestroyNotify called when the listener is freed
240 * and data associated with the callback should be freed. Can be NULL.
242 * Create a new #AtspiDeviceListener with a specified callback function.
243 * Like atspi_device_listener_new, but callback takes no user data.
245 * Returns: a pointer to a newly-created #AtspiDeviceListener.
248 AtspiDeviceListener *
249 atspi_device_listener_new_simple (AtspiDeviceListenerSimpleCB callback,
250 GDestroyNotify callback_destroyed)
252 return atspi_device_listener_new (device_remove_datum, callback_destroyed, callback);
256 * atspi_device_listener_add_callback:
257 * @listener: the #AtspiDeviceListener instance to modify.
258 * @callback: (scope notify): an #AtspiDeviceListenerCB function pointer.
259 * @user_data: (closure): a pointer to data which will be passed to the
260 * callback when invoked.
261 * @callback_destroyed: A #GDestroyNotify called when the listener is freed
262 * and data associated with the callback should be freed. Can be NULL.
264 * Add an in-process callback function to an existing #AtspiDeviceListener.
266 * Returns: #TRUE if successful, otherwise #FALSE.
270 atspi_device_listener_add_callback (AtspiDeviceListener *listener,
271 AtspiDeviceListenerCB callback,
272 GDestroyNotify callback_destroyed,
275 g_return_if_fail (ATSPI_IS_DEVICE_LISTENER (listener));
276 DeviceEventHandler *new_handler;
278 new_handler = device_event_handler_new (callback,
279 callback_destroyed, user_data);
284 new_list = g_list_prepend (listener->callbacks, new_handler);
286 listener->callbacks = new_list;
291 * atspi_device_listener_remove_callback:
292 * @listener: the #AtspiDeviceListener instance to modify.
293 * @callback: (scope call): an #AtspiDeviceListenerCB function pointer.
295 * Remove an in-process callback function from an existing #AtspiDeviceListener.
297 * Returns: #TRUE if successful, otherwise #FALSE.
301 atspi_device_listener_remove_callback (AtspiDeviceListener *listener,
302 AtspiDeviceListenerCB callback)
304 g_return_if_fail (ATSPI_IS_DEVICE_LISTENER (listener));
306 listener->callbacks = event_list_remove_by_cb (listener->callbacks, (void *) callback);
310 read_device_event_from_iter (DBusMessageIter *iter, AtspiDeviceEvent *event)
314 dbus_int16_t hw_code;
315 dbus_int16_t modifiers;
316 dbus_int32_t timestamp;
318 DBusMessageIter iter_struct;
320 dbus_message_iter_recurse (iter, &iter_struct);
322 dbus_message_iter_get_basic (&iter_struct, &type);
324 dbus_message_iter_next (&iter_struct);
326 dbus_message_iter_get_basic (&iter_struct, &id);
328 dbus_message_iter_next (&iter_struct);
330 dbus_message_iter_get_basic (&iter_struct, &hw_code);
331 event->hw_code = hw_code;
332 dbus_message_iter_next (&iter_struct);
334 dbus_message_iter_get_basic (&iter_struct, &modifiers);
335 event->modifiers = modifiers;
336 dbus_message_iter_next (&iter_struct);
338 dbus_message_iter_get_basic (&iter_struct, ×tamp);
339 event->timestamp = timestamp;
340 dbus_message_iter_next (&iter_struct);
342 dbus_message_iter_get_basic (&iter_struct, &event->event_string);
343 dbus_message_iter_next (&iter_struct);
345 dbus_message_iter_get_basic (&iter_struct, &is_text);
346 event->is_text = is_text;
350 * atspi_dbus_handle_DeviceEvent: (skip)
353 atspi_dbus_handle_DeviceEvent (DBusConnection *bus, DBusMessage *message, void *data)
355 const char *path = dbus_message_get_path (message);
357 AtspiDeviceEvent event;
358 AtspiDeviceListener *listener;
359 DBusMessageIter iter;
360 AtspiDeviceListenerClass *klass;
361 dbus_bool_t retval = FALSE;
365 if (strcmp (dbus_message_get_signature (message), "(uinnisb)") != 0)
367 g_warning ("Atspi: Unknown signature for an event");
371 if (sscanf (path, "/org/a11y/atspi/listeners/%d", &id) != 1)
373 g_warning ("Atspi: Bad listener path: %s\n", path);
377 for (l = device_listeners; l; l = g_list_next (l))
380 if (listener->id == id) break;
387 dbus_message_iter_init (message, &iter);
388 read_device_event_from_iter (&iter, &event);
389 klass = ATSPI_DEVICE_LISTENER_GET_CLASS (listener);
390 if (klass->device_event)
392 retval = (*klass->device_event) (listener, &event);
395 reply = dbus_message_new_method_return (message);
398 dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &retval, DBUS_TYPE_INVALID);
399 dbus_connection_send (_atspi_bus(), reply, NULL);
400 dbus_message_unref (reply);
402 return DBUS_HANDLER_RESULT_HANDLED;
406 _atspi_device_listener_get_path (AtspiDeviceListener *listener)
408 return g_strdup_printf ("/org/a11y/atspi/listeners/%d", listener->id);
411 G_DEFINE_BOXED_TYPE (AtspiDeviceEvent,
413 atspi_device_event_copy,
414 atspi_device_event_free)