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"
28 AtspiDeviceListenerCB callback;
32 GObjectClass *device_parent_class;
34 static guint32 _e_id = 0;
40 static DeviceEventHandler *
41 device_event_handler_new (AtspiDeviceListenerCB callback, gpointer user_data)
43 DeviceEventHandler *eh = g_new0 (DeviceEventHandler, 1);
45 eh->callback = callback;
46 eh->user_data = user_data;
52 event_list_remove_by_cb (GList *list, AtspiDeviceListenerCB callback)
56 for (l = list; l; l = next)
58 DeviceEventHandler *eh = l->data;
61 if (eh->callback == callback)
63 list = g_list_delete_link (list, l);
72 * Standard event dispatcher
75 static guint listener_id = 0;
76 static GList *device_listeners = NULL;
83 for (l = device_listeners; l; l = g_list_next (l))
85 AtspiDeviceListener *listener = l->data;
86 if (listener->id == id) return FALSE;
92 remove_listener (GObject *obj, gpointer data)
94 device_listeners = g_list_remove (device_listeners, obj);
98 * Device event handler
101 atspi_device_event_dispatch (AtspiDeviceListener *listener,
102 const AtspiDeviceEvent *event)
105 AtspiDeviceEvent anevent;
106 gboolean handled = FALSE;
108 /* FIXME: re-enterancy hazard on this list */
109 for (l = listener->callbacks; l; l = l->next)
111 DeviceEventHandler *eh = l->data;
113 if ((handled = eh->callback (&anevent, eh->user_data)))
123 atspi_device_listener_init (AtspiDeviceListener *listener)
129 listener->id = listener_id++;
130 } while (!id_is_free (listener->id));
131 new_list = g_list_append (device_listeners, listener);
132 if (new_list) device_listeners = new_list;
136 atspi_device_listener_finalize (GObject *object)
138 AtspiDeviceListener *listener = (AtspiDeviceListener *) object;
141 for (l = listener->callbacks; l; l = l->next)
146 g_list_free (listener->callbacks);
148 device_parent_class->finalize (object);
152 atspi_device_listener_class_init (AtspiDeviceListenerClass *klass)
154 GObjectClass *object_class = (GObjectClass *) klass;
156 device_parent_class = g_type_class_peek_parent (klass);
157 object_class->finalize = atspi_device_listener_finalize;
159 klass->device_event = atspi_device_event_dispatch;
162 G_DEFINE_TYPE (AtspiDeviceListener, atspi_device_listener,
166 * atspi_device_listener_new:
167 * @callback: (scope call): an #AtspiDeviceListenerCB callback function,
169 * @user_data: (closure): a pointer to data which will be passed to the
170 * callback when invoked.
172 * Create a new #AtspiDeviceListener with a specified callback function.
174 * Returns: a pointer to a newly-created #AtspiDeviceListener.
177 AtspiDeviceListener *
178 atspi_device_listener_new (AtspiDeviceListenerCB callback)
180 AtspiDeviceListener *listener = g_object_new (atspi_device_listener_get_type (), NULL);
186 * atspi_device_listener_add_callback:
187 * @listener: the #AtspiDeviceListener instance to modify.
188 * @callback: (scope call): an #AtspiDeviceListenerCB function pointer.
189 * @user_data: (closure): a pointer to data which will be passed to the
190 * callback when invoked.
192 * Add an in-process callback function to an existing #AtspiDeviceListener.
194 * Returns: #TRUE if successful, otherwise #FALSE.
198 atspi_device_listener_add_callback (AtspiDeviceListener *listener,
199 AtspiDeviceListenerCB callback,
202 g_return_if_fail (ATSPI_IS_DEVICE_LISTENER (listener));
204 listener->callbacks = g_list_prepend (listener->callbacks,
205 device_event_handler_new ((void *)callback, user_data));
209 * atspi_device_listener_remove_callback:
210 * @listener: the #AtspiDeviceListener instance to modify.
211 * @callback: (scope call): an #AtspiDeviceListenerCB function pointer.
213 * Remove an in-process callback function from an existing #AtspiDeviceListener.
215 * Returns: #TRUE if successful, otherwise #FALSE.
219 atspi_device_listener_remove_callback (AtspiDeviceListener *listener,
220 AtspiDeviceListenerCB callback)
222 g_return_if_fail (ATSPI_IS_DEVICE_LISTENER (listener));
224 listener->callbacks = event_list_remove_by_cb (listener->callbacks, (void *) callback);
227 static const char *device_event_type = "(uinnisb)";
230 read_device_event_from_iter (DBusMessageIter *iter, AtspiDeviceEvent *event)
234 dbus_int16_t hw_code;
235 dbus_int16_t modifiers;
236 dbus_int32_t timestamp;
239 DBusMessageIter iter_struct;
241 dbus_message_iter_recurse (iter, &iter_struct);
243 dbus_message_iter_get_basic (&iter_struct, &type);
245 dbus_message_iter_next (&iter_struct);
247 dbus_message_iter_get_basic (&iter_struct, &id);
249 dbus_message_iter_next (&iter_struct);
251 dbus_message_iter_get_basic (&iter_struct, &hw_code);
252 event->hw_code = hw_code;
253 dbus_message_iter_next (&iter_struct);
255 dbus_message_iter_get_basic (&iter_struct, &modifiers);
256 event->modifiers = modifiers;
257 dbus_message_iter_next (&iter_struct);
259 dbus_message_iter_get_basic (&iter_struct, ×tamp);
260 event->timestamp = timestamp;
261 dbus_message_iter_next (&iter_struct);
263 dbus_message_iter_get_basic (&iter_struct, &event->event_string);
264 dbus_message_iter_next (&iter_struct);
266 dbus_message_iter_get_basic (&iter_struct, &is_text);
267 event->is_text = is_text;
271 * atspi_dbus_handle_DeviceEvent: (skip)
274 atspi_dbus_handle_DeviceEvent (DBusConnection *bus, DBusMessage *message, void *data)
276 const char *path = dbus_message_get_path (message);
278 AtspiDeviceEvent event;
279 AtspiDeviceListener *listener;
280 DBusMessageIter iter;
281 AtspiDeviceListenerClass *klass;
282 dbus_bool_t retval = FALSE;
287 if (strcmp (dbus_message_get_signature (message), "(uinnisb)") != 0)
289 g_warning ("Atspi: Unknown signature for an event");
293 if (sscanf (path, "/org/a11y/atspi/listeners/%d", &id) != 1)
295 g_warning ("Atspi: Bad listener path: %s\n", path);
299 for (l = device_listeners; l; l = g_list_next (l))
302 if (listener->id == id) break;
309 dbus_message_iter_init (message, &iter);
310 read_device_event_from_iter (&iter, &event);
311 klass = ATSPI_DEVICE_LISTENER_GET_CLASS (listener);
312 if (klass->device_event)
314 retval = (*klass->device_event) (listener, &event);
317 reply = dbus_message_new_method_return (message);
320 dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &retval, DBUS_TYPE_INVALID);
321 dbus_connection_send (_atspi_bus(), reply, NULL);
322 dbus_message_unref (reply);
324 return DBUS_HANDLER_RESULT_HANDLED;
328 _atspi_device_listener_get_path (AtspiDeviceListener *listener)
330 return g_strdup_printf ("/org/a11y/atspi/listeners/%d", listener->id);