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 "spi-private.h"
31 AccessibleEventListenerCB event;
32 AccessibleDeviceListenerCB device_event;
38 GObjectClass *event_parent_class;
39 GObjectClass *device_parent_class;
41 static guint32 _e_id = 0;
48 cspi_event_handler_new (gpointer method, gpointer user_data)
50 EventHandler *eh = g_new0 (EventHandler, 1);
52 eh->cb.method = method;
53 eh->user_data = user_data;
59 cspi_event_handler_free (EventHandler *handler)
65 cspi_event_list_remove_by_cb (GList *list, gpointer callback)
69 for (l = list; l; l = next)
71 EventHandler *eh = l->data;
74 if (eh->cb.method == callback)
76 list = g_list_delete_link (list, l);
77 cspi_event_handler_free (eh);
85 * Standard event dispatcher
88 G_DEFINE_TYPE (CSpiEventListener, cspi_event_listener,
92 cspi_event (CSpiEventListener *listener,
93 AccessibleEvent *event)
96 CSpiEventListener *clistener = (CSpiEventListener *) listener;
97 InternalEvent *ievent;
98 AccessibleEvent *aevent;
100 ievent = g_new0(InternalEvent, 1);
101 ievent->event.type = g_strdup (event->type);
102 ievent->event.source = event->source;
103 ievent->event.detail1 = event->detail1;
104 ievent->event.detail2 = event->detail2;
105 ievent->event.v_type = event->v_type;
106 if (event->v_type == EVENT_DATA_STRING)
108 ievent->event.v.text = g_strdup (event->v.text);
110 else memcpy (&ievent->event.v, &event->v, sizeof(event->v));
111 ievent->id = _e_id++;
112 ievent->magic = SPI_INTERNAL_EVENT_MAGIC;
113 ievent->ref_count = 0;
114 aevent = (AccessibleEvent *)ievent;
115 Accessible_ref (aevent->source);
116 AccessibleEvent_ref (aevent);
118 /* FIXME: re-enterancy hazard on this list */
119 for (l = clistener->callbacks; l; l = l->next)
121 EventHandler *eh = l->data;
122 /* cast hides our private stuff from client handlers */
123 eh->cb.event (aevent, eh->user_data);
126 AccessibleEvent_unref (aevent);
129 static guint listener_id = 0;
130 static GList *device_listeners = NULL;
133 id_is_free (guint id)
137 for (l = device_listeners; l; l = g_list_next (l))
139 CSpiDeviceListener *listener = l->data;
140 if (listener->id == id) return FALSE;
145 static void remove_listener (GObject *obj, gpointer data)
147 device_listeners = g_list_remove (device_listeners, obj);
151 cspi_event_listener_instance_init (CSpiEventListener *listener)
156 cspi_event_listener_finalize (GObject *object)
158 CSpiEventListener *listener = (CSpiEventListener *) object;
161 for (l = listener->callbacks; l; l = l->next)
163 cspi_event_handler_free (l->data);
166 g_list_free (listener->callbacks);
168 event_parent_class->finalize (object);
172 cspi_event_listener_class_init (CSpiEventListenerClass *klass)
174 GObjectClass *object_class = (GObjectClass *) klass;
176 event_parent_class = g_type_class_peek_parent (klass);
177 object_class->finalize = cspi_event_listener_finalize;
179 klass->event = cspi_event;
183 cspi_event_listener_new (void)
185 CSpiEventListener *listener;
187 listener = g_object_new (cspi_event_listener_get_type (), NULL);
193 cspi_event_listener_init (CSpiEventListener *listener)
198 cspi_event_listener_add_cb (AccessibleEventListener *al,
199 AccessibleEventListenerCB callback,
202 CSpiEventListener *listener = al;
204 g_return_if_fail (CSPI_IS_EVENT_LISTENER (listener));
206 listener->callbacks = g_list_prepend (listener->callbacks,
207 cspi_event_handler_new ((void *) callback, user_data));
211 cspi_event_listener_remove_cb (AccessibleEventListener *al,
212 AccessibleEventListenerCB callback)
214 CSpiEventListener *listener = al;
216 g_return_if_fail (CSPI_IS_EVENT_LISTENER (listener));
218 listener->callbacks = cspi_event_list_remove_by_cb (listener->callbacks, (void *) callback);
222 * Device event handler
225 cspi_device_event (CSpiDeviceListener *listener,
226 const Accessibility_DeviceEvent *event)
229 CSpiDeviceListener *clistener = (CSpiDeviceListener *) listener;
230 AccessibleDeviceEvent anevent;
231 gboolean handled = FALSE;
235 case Accessibility_KEY_PRESSED_EVENT:
236 anevent.type = SPI_KEY_PRESSED;
238 case Accessibility_KEY_RELEASED_EVENT:
239 anevent.type = SPI_KEY_RELEASED;
241 case Accessibility_BUTTON_PRESSED_EVENT:
242 anevent.type = SPI_BUTTON_PRESSED;
244 case Accessibility_BUTTON_RELEASED_EVENT:
245 anevent.type = SPI_BUTTON_RELEASED;
251 anevent.keyID = event->id;
252 anevent.keycode = event->hw_code;
253 anevent.timestamp = event->timestamp;
254 anevent.keystring = g_strdup (event->event_string);
255 anevent.modifiers = event->modifiers;
256 anevent.is_text = event->is_text;
258 /* FIXME: re-enterancy hazard on this list */
259 for (l = clistener->callbacks; l; l = l->next)
261 EventHandler *eh = l->data;
263 if ((handled = eh->cb.device_event (&anevent, eh->user_data)))
268 g_free (anevent.keystring);
274 cspi_device_listener_init (CSpiDeviceListener *listener)
280 listener->id = listener_id++;
281 } while (!id_is_free (listener->id));
282 new_list = g_list_append (device_listeners, listener);
283 if (new_list) device_listeners = new_list;
287 cspi_device_listener_finalize (GObject *object)
289 CSpiDeviceListener *listener = (CSpiDeviceListener *) object;
292 for (l = listener->callbacks; l; l = l->next)
294 cspi_event_handler_free (l->data);
297 g_list_free (listener->callbacks);
299 device_parent_class->finalize (object);
303 cspi_device_listener_class_init (CSpiDeviceListenerClass *klass)
305 GObjectClass *object_class = (GObjectClass *) klass;
307 device_parent_class = g_type_class_peek_parent (klass);
308 object_class->finalize = cspi_device_listener_finalize;
310 klass->device_event = cspi_device_event;
313 G_DEFINE_TYPE (CSpiDeviceListener, cspi_device_listener,
317 cspi_device_listener_new (void)
319 CSpiEventListener *listener = g_object_new (cspi_device_listener_get_type (), NULL);
325 cspi_device_listener_add_cb (AccessibleDeviceListener *al,
326 AccessibleDeviceListenerCB callback,
329 CSpiDeviceListener *listener = al;
331 g_return_if_fail (CSPI_IS_DEVICE_LISTENER (listener));
333 listener->callbacks = g_list_prepend (listener->callbacks,
334 cspi_event_handler_new ((void *)callback, user_data));
338 cspi_device_listener_remove_cb (AccessibleDeviceListener *al,
339 AccessibleDeviceListenerCB callback)
341 CSpiDeviceListener *listener = al;
343 g_return_if_fail (CSPI_IS_DEVICE_LISTENER (listener));
345 listener->callbacks = cspi_event_list_remove_by_cb (listener->callbacks, (void *) callback);
349 cspi_event_listener_unref (AccessibleEventListener *listener)
351 g_object_unref (G_OBJECT (listener));
355 cspi_device_listener_unref (AccessibleDeviceListener *listener)
357 g_object_unref (G_OBJECT (listener));
360 static const char *deviceEvent_type = "(uinnisb)";
363 cspi_dbus_handle_deviceEvent (DBusConnection *bus, DBusMessage *message, void *data)
365 const char *path = dbus_message_get_path (message);
367 Accessibility_DeviceEvent event;
368 CSpiDeviceListener *listener;
369 DBusMessageIter iter;
370 CSpiDeviceListenerClass *klass;
371 dbus_bool_t retval = FALSE;
376 if (sscanf (path, "/org/a11y/atspi/listeners/%d", &id) != 1)
378 g_warning ("Bad listener path: %s\n", path);
381 for (l = device_listeners; l; l = g_list_next (l))
384 if (listener->id == id) break;
390 dbus_message_iter_init (message, &iter);
391 dbind_any_demarshal (&iter, (char **) &deviceEvent_type, &p);
392 klass = CSPI_DEVICE_LISTENER_GET_CLASS (listener);
393 if (klass->device_event)
395 retval = (*klass->device_event) (listener, &event);
398 reply = dbus_message_new_method_return (message);
401 dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &retval, DBUS_TYPE_INVALID);
402 dbus_connection_send (SPI_bus(), reply, NULL);
403 dbus_message_unref (reply);
405 return DBUS_HANDLER_RESULT_HANDLED;