57f0bfbb17dcafc1f40160d9de92fe65ed969818
[platform/core/uifw/at-spi2-atk.git] / cspi / spi-listener.c
1 /*
2  * AT-SPI - Assistive Technology Service Provider Interface
3  * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
4  *
5  * Copyright 2002 Ximian Inc.
6  * Copyright 2002 Sun Microsystems, Inc.
7  *
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.
12  *
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.
17  *
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.
22  */
23
24 #include "spi-private.h"
25 #include <stdio.h>
26
27 typedef struct
28 {
29   union
30     {
31       AccessibleEventListenerCB     event;
32       AccessibleDeviceListenerCB    device_event;
33       gpointer                      method;
34     } cb;
35   gpointer user_data;
36 } EventHandler;
37
38 GObjectClass *event_parent_class;
39 GObjectClass *device_parent_class;
40
41 static guint32 _e_id = 0;
42
43 /*
44  * Misc. helpers.
45  */
46
47 static EventHandler *
48 cspi_event_handler_new (gpointer method, gpointer user_data)
49 {
50   EventHandler *eh = g_new0 (EventHandler, 1);
51
52   eh->cb.method = method;
53   eh->user_data = user_data;
54
55   return eh;
56 }
57
58 static void
59 cspi_event_handler_free (EventHandler *handler)
60 {
61   g_free (handler);
62 }
63
64 static GList *
65 cspi_event_list_remove_by_cb (GList *list, gpointer callback)
66 {
67   GList *l, *next;
68         
69   for (l = list; l; l = next)
70     {
71       EventHandler *eh = l->data;
72       next = l->next;
73
74       if (eh->cb.method == callback)
75       {
76         list = g_list_delete_link (list, l);
77         cspi_event_handler_free (eh);
78       }
79     }
80
81   return list;
82 }
83
84 /*
85  * Standard event dispatcher
86  */
87
88 G_DEFINE_TYPE (CSpiEventListener, cspi_event_listener,
89                           G_TYPE_OBJECT)
90
91 static void
92 cspi_event (CSpiEventListener    *listener,
93             AccessibleEvent *event)
94 {
95   GList *l;
96   CSpiEventListener *clistener = (CSpiEventListener *) listener;
97   InternalEvent     *ievent;
98   AccessibleEvent   *aevent;
99   
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)
107   {
108     ievent->event.v.text = g_strdup (event->v.text);
109   }
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);
117
118   /* FIXME: re-enterancy hazard on this list */
119   for (l = clistener->callbacks; l; l = l->next)
120     {
121       EventHandler *eh = l->data;
122       /* cast hides our private stuff from client handlers */
123       eh->cb.event (aevent, eh->user_data);
124     }
125
126   AccessibleEvent_unref (aevent);
127 }
128
129 static guint listener_id = 0;
130 static GList *device_listeners = NULL;
131
132 static gboolean
133 id_is_free (guint id)
134 {
135   GList *l;
136
137   for (l = device_listeners; l; l = g_list_next (l))
138   {
139     CSpiDeviceListener *listener = l->data;
140     if (listener->id == id) return FALSE;
141   }
142   return TRUE;
143 }
144
145 static void remove_listener (GObject *obj, gpointer data)
146 {
147   device_listeners = g_list_remove (device_listeners, obj);
148 }
149
150 static void
151 cspi_event_listener_instance_init (CSpiEventListener *listener)
152 {
153 }
154
155 static void
156 cspi_event_listener_finalize (GObject *object)
157 {
158   CSpiEventListener *listener = (CSpiEventListener *) object;
159   GList *l;
160   
161   for (l = listener->callbacks; l; l = l->next)
162     {
163       cspi_event_handler_free (l->data);
164     }
165   
166   g_list_free (listener->callbacks);
167
168   event_parent_class->finalize (object);
169 }
170
171 static void
172 cspi_event_listener_class_init (CSpiEventListenerClass *klass)
173 {
174   GObjectClass *object_class = (GObjectClass *) klass;
175
176   event_parent_class = g_type_class_peek_parent (klass);
177   object_class->finalize = cspi_event_listener_finalize;
178
179   klass->event = cspi_event;
180 }
181
182 gpointer
183 cspi_event_listener_new (void)
184 {
185   CSpiEventListener *listener;
186
187   listener = g_object_new (cspi_event_listener_get_type (), NULL);
188
189   return listener;
190 }
191
192 static void
193 cspi_event_listener_init (CSpiEventListener *listener)
194 {
195 }
196
197 void
198 cspi_event_listener_add_cb (AccessibleEventListener  *al,
199                             AccessibleEventListenerCB callback,
200                             void                     *user_data)
201 {
202   CSpiEventListener *listener = al;
203
204   g_return_if_fail (CSPI_IS_EVENT_LISTENER (listener));
205
206   listener->callbacks = g_list_prepend (listener->callbacks,
207                                         cspi_event_handler_new ((void *) callback, user_data));
208 }
209
210 void
211 cspi_event_listener_remove_cb (AccessibleEventListener  *al,
212                                AccessibleEventListenerCB callback)
213 {
214   CSpiEventListener *listener = al;
215
216   g_return_if_fail (CSPI_IS_EVENT_LISTENER (listener));
217
218   listener->callbacks = cspi_event_list_remove_by_cb (listener->callbacks, (void *) callback);
219 }
220
221 /* 
222  * Device event handler
223  */
224 static gboolean
225 cspi_device_event (CSpiDeviceListener               *listener,
226                    const Accessibility_DeviceEvent *event)
227 {
228   GList *l;
229   CSpiDeviceListener *clistener = (CSpiDeviceListener *) listener;
230   AccessibleDeviceEvent anevent;
231   gboolean handled = FALSE;
232
233   switch (event->type)
234     {
235       case Accessibility_KEY_PRESSED_EVENT:
236         anevent.type = SPI_KEY_PRESSED;
237         break;
238       case Accessibility_KEY_RELEASED_EVENT:
239         anevent.type = SPI_KEY_RELEASED;
240         break;
241       case Accessibility_BUTTON_PRESSED_EVENT:
242         anevent.type = SPI_BUTTON_PRESSED;
243         break;
244       case Accessibility_BUTTON_RELEASED_EVENT:
245         anevent.type = SPI_BUTTON_RELEASED;
246         break;
247       default:
248         anevent.type = 0;
249         break;
250     }
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;
257
258   /* FIXME: re-enterancy hazard on this list */
259   for (l = clistener->callbacks; l; l = l->next)
260     {
261       EventHandler *eh = l->data;
262
263       if ((handled = eh->cb.device_event (&anevent, eh->user_data)))
264         {
265           break;
266         }
267     }
268   g_free (anevent.keystring);
269
270   return handled;
271 }
272
273 static void
274 cspi_device_listener_init (CSpiDeviceListener *listener)
275 {
276   GList *new_list;
277
278   do
279   {
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;
284 }
285
286 static void
287 cspi_device_listener_finalize (GObject *object)
288 {
289   CSpiDeviceListener *listener = (CSpiDeviceListener *) object;
290   GList *l;
291   
292   for (l = listener->callbacks; l; l = l->next)
293     {
294       cspi_event_handler_free (l->data);
295     }
296   
297   g_list_free (listener->callbacks);
298
299   device_parent_class->finalize (object);
300 }
301
302 static void
303 cspi_device_listener_class_init (CSpiDeviceListenerClass *klass)
304 {
305   GObjectClass *object_class = (GObjectClass *) klass;
306
307   device_parent_class = g_type_class_peek_parent (klass);
308   object_class->finalize = cspi_device_listener_finalize;
309
310   klass->device_event = cspi_device_event;
311 }
312
313 G_DEFINE_TYPE (CSpiDeviceListener, cspi_device_listener,
314                           G_TYPE_OBJECT)
315
316 gpointer
317 cspi_device_listener_new (void)
318 {
319   CSpiEventListener *listener = g_object_new (cspi_device_listener_get_type (), NULL);
320
321   return listener;
322 }
323
324 void
325 cspi_device_listener_add_cb (AccessibleDeviceListener  *al,
326                              AccessibleDeviceListenerCB callback,
327                              void                      *user_data)
328 {
329   CSpiDeviceListener *listener = al;
330
331   g_return_if_fail (CSPI_IS_DEVICE_LISTENER (listener));
332
333   listener->callbacks = g_list_prepend (listener->callbacks,
334                                         cspi_event_handler_new ((void *)callback, user_data));
335 }
336
337 void
338 cspi_device_listener_remove_cb (AccessibleDeviceListener  *al,
339                                 AccessibleDeviceListenerCB callback)
340 {
341   CSpiDeviceListener *listener = al;
342
343   g_return_if_fail (CSPI_IS_DEVICE_LISTENER (listener));
344
345   listener->callbacks = cspi_event_list_remove_by_cb (listener->callbacks, (void *) callback);
346 }
347
348 void
349 cspi_event_listener_unref (AccessibleEventListener *listener)
350 {
351   g_object_unref (G_OBJECT (listener));
352 }
353
354 void
355 cspi_device_listener_unref (AccessibleDeviceListener *listener)
356 {
357   g_object_unref (G_OBJECT (listener));
358 }
359
360 static const char *deviceEvent_type = "(uinnisb)";
361
362 DBusHandlerResult
363 cspi_dbus_handle_deviceEvent (DBusConnection *bus, DBusMessage *message, void *data)
364 {
365   const char *path = dbus_message_get_path (message);
366   int id;
367   Accessibility_DeviceEvent event;
368     CSpiDeviceListener *listener;
369   DBusMessageIter iter;
370   CSpiDeviceListenerClass *klass;
371   dbus_bool_t retval = FALSE;
372   GList *l;
373   DBusMessage *reply;
374   void *p = &event;
375
376   if (sscanf (path, "/org/freedesktop/atspi/listeners/%d", &id) != 1)
377   {
378     g_warning ("Bad listener path: %s\n", path);
379     goto done;
380   }
381   for (l = device_listeners; l; l = g_list_next (l))
382   {
383     listener = l->data;
384     if (listener->id == id) break;
385   }
386   if (!l)
387   {
388     goto done;
389   }
390   dbus_message_iter_init (message, &iter);
391   dbind_any_demarshal (iter, &deviceEvent_type, &p);
392   klass = CSPI_DEVICE_LISTENER_GET_CLASS (listener);
393   if (klass->device_event)
394   {
395     retval = (*klass->device_event) (listener, &event);
396   }
397 done:
398   reply = dbus_message_new_method_return (message);
399   if (reply)
400   {
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);
404   }
405   return DBUS_HANDLER_RESULT_HANDLED;
406 }