Fixes for #149962, #136986, #144086.
[platform/core/uifw/at-spi2-atk.git] / cspi / bonobo / cspi-bonobo-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 <libbonobo.h>
25 #include "../spi-private.h"
26 #include "cspi-bonobo-listener.h"
27
28 typedef struct
29 {
30   union
31     {
32       AccessibleEventListenerCB     event;
33       AccessibleDeviceListenerCB    device_event;
34       gpointer                      method;
35     } cb;
36   gpointer user_data;
37 } EventHandler;
38
39 GObjectClass *event_parent_class;
40 GObjectClass *device_parent_class;
41
42 static guint32 _e_id = 0;
43
44 /*
45  * Misc. helpers.
46  */
47
48 static EventHandler *
49 cspi_event_handler_new (gpointer method, gpointer user_data)
50 {
51   EventHandler *eh = g_new0 (EventHandler, 1);
52
53   eh->cb.method = method;
54   eh->user_data = user_data;
55
56   return eh;
57 }
58
59 static void
60 cspi_event_handler_free (EventHandler *handler)
61 {
62   g_free (handler);
63 }
64
65 static GList *
66 cspi_event_list_remove_by_cb (GList *list, gpointer callback)
67 {
68   GList *l, *next;
69         
70   for (l = list; l; l = next)
71     {
72       EventHandler *eh = l->data;
73       next = l->next;
74       
75       list = g_list_delete_link (list, l);
76       
77       cspi_event_handler_free (eh);
78     }
79
80   return list;
81 }
82
83 /*
84  * Standard event dispatcher
85  */
86
87 BONOBO_CLASS_BOILERPLATE (CSpiEventListener, cspi_event_listener,
88                           GObject, spi_event_listener_get_type ())
89
90 static void
91 cspi_event (SpiEventListener    *listener,
92             Accessibility_Event *event)
93 {
94   GList *l;
95   CSpiEventListener *clistener = (CSpiEventListener *) listener;
96   InternalEvent     *ievent;
97   AccessibleEvent   *aevent;
98   Accessible        *source = cspi_object_borrow (event->source);
99   
100   ievent = g_new0(InternalEvent, 1);
101   ievent->event.type    = g_strdup (event->type);
102   ievent->event.source  = source;
103   ievent->event.detail1 = event->detail1;
104   ievent->event.detail2 = event->detail2;
105   ievent->id            = _e_id++;
106   ievent->magic         = SPI_INTERNAL_EVENT_MAGIC;
107   ievent->ref_count     = 0;
108   ievent->data          = CORBA_any__alloc ();
109   CORBA_any__copy (ievent->data, &event->any_data);
110   aevent = (AccessibleEvent *)ievent;
111   Accessible_ref (source);
112   AccessibleEvent_ref (aevent);
113
114   /* FIXME: re-enterancy hazard on this list */
115   for (l = clistener->callbacks; l; l = l->next)
116     {
117       EventHandler *eh = l->data;
118       /* cast hides our private stuff from client handlers */
119       eh->cb.event (aevent, eh->user_data);
120     }
121
122   AccessibleEvent_unref (aevent);
123   cspi_object_return (source);
124 }
125
126 static void
127 cspi_event_listener_instance_init (CSpiEventListener *listener)
128 {
129 }
130
131 static void
132 cspi_event_listener_finalize (GObject *object)
133 {
134   CSpiEventListener *listener = (CSpiEventListener *) object;
135   GList *l;
136   
137   for (l = listener->callbacks; l; l = l->next)
138     {
139       cspi_event_handler_free (l->data);
140     }
141   
142   g_list_free (listener->callbacks);
143
144   event_parent_class->finalize (object);
145 }
146
147 static void
148 cspi_event_listener_class_init (CSpiEventListenerClass *klass)
149 {
150   GObjectClass *object_class = (GObjectClass *) klass;
151
152   event_parent_class = g_type_class_peek_parent (klass);
153   object_class->finalize = cspi_event_listener_finalize;
154
155   klass->event = cspi_event;
156 }
157
158 gpointer
159 cspi_event_listener_new (void)
160 {
161   CSpiEventListener *listener;
162
163   listener = g_object_new (cspi_event_listener_get_type (), NULL);
164
165   return listener;
166 }
167
168 void
169 cspi_event_listener_add_cb (AccessibleEventListener  *al,
170                             AccessibleEventListenerCB callback,
171                             void                     *user_data)
172 {
173   CSpiEventListener *listener = al;
174
175   g_return_if_fail (CSPI_IS_EVENT_LISTENER (listener));
176
177   listener->callbacks = g_list_prepend (listener->callbacks,
178                                         cspi_event_handler_new ((void *) callback, user_data));
179 }
180
181 void
182 cspi_event_listener_remove_cb (AccessibleEventListener  *al,
183                                AccessibleEventListenerCB callback)
184 {
185   CSpiEventListener *listener = al;
186
187   g_return_if_fail (CSPI_IS_EVENT_LISTENER (listener));
188
189   listener->callbacks = cspi_event_list_remove_by_cb (listener->callbacks, (void *) callback);
190 }
191
192 /* 
193  * Device event handler
194  */
195 static gboolean
196 cspi_device_event (SpiDeviceListener               *listener,
197                    const Accessibility_DeviceEvent *event)
198 {
199   GList *l;
200   CSpiDeviceListener *clistener = (CSpiDeviceListener *) listener;
201   AccessibleDeviceEvent anevent;
202   gboolean handled = FALSE;
203
204   switch (event->type)
205     {
206       case Accessibility_KEY_PRESSED_EVENT:
207         anevent.type = SPI_KEY_PRESSED;
208         break;
209       case Accessibility_KEY_RELEASED_EVENT:
210         anevent.type = SPI_KEY_RELEASED;
211         break;
212       case Accessibility_BUTTON_PRESSED_EVENT:
213         anevent.type = SPI_BUTTON_PRESSED;
214         break;
215       case Accessibility_BUTTON_RELEASED_EVENT:
216         anevent.type = SPI_BUTTON_RELEASED;
217         break;
218       default:
219         anevent.type = 0;
220         break;
221     }
222   anevent.keyID     = event->id;
223   anevent.keycode   = event->hw_code;
224   anevent.timestamp = event->timestamp;
225   anevent.keystring = g_strdup (event->event_string);
226   anevent.modifiers = event->modifiers;
227   anevent.is_text = event->is_text;
228
229   /* FIXME: re-enterancy hazard on this list */
230   for (l = clistener->callbacks; l; l = l->next)
231     {
232       EventHandler *eh = l->data;
233
234       if ((handled = eh->cb.device_event (&anevent, eh->user_data)))
235         {
236           break;
237         }
238     }
239   
240   return handled;
241 }
242
243 static void
244 cspi_device_listener_init (CSpiDeviceListener *listener)
245 {
246 }
247
248 static void
249 cspi_device_listener_finalize (GObject *object)
250 {
251   CSpiDeviceListener *listener = (CSpiDeviceListener *) object;
252   GList *l;
253   
254   for (l = listener->callbacks; l; l = l->next)
255     {
256       cspi_event_handler_free (l->data);
257     }
258   
259   g_list_free (listener->callbacks);
260
261   device_parent_class->finalize (object);
262 }
263
264 static void
265 cspi_device_listener_class_init (CSpiDeviceListenerClass *klass)
266 {
267   GObjectClass *object_class = (GObjectClass *) klass;
268
269   device_parent_class = g_type_class_peek_parent (klass);
270   object_class->finalize = cspi_device_listener_finalize;
271
272   klass->device_event = cspi_device_event;
273 }
274
275 BONOBO_TYPE_FUNC (CSpiDeviceListener, 
276                   spi_device_listener_get_type (),
277                   cspi_device_listener)
278
279 gpointer
280 cspi_device_listener_new (void)
281 {
282   CSpiEventListener *listener = g_object_new (cspi_device_listener_get_type (), NULL);
283
284   return listener;
285 }
286
287 void
288 cspi_device_listener_add_cb (AccessibleDeviceListener  *al,
289                              AccessibleDeviceListenerCB callback,
290                              void                      *user_data)
291 {
292   CSpiDeviceListener *listener = al;
293
294   g_return_if_fail (CSPI_IS_DEVICE_LISTENER (listener));
295
296   listener->callbacks = g_list_prepend (listener->callbacks,
297                                         cspi_event_handler_new ((void *)callback, user_data));
298 }
299
300 void
301 cspi_device_listener_remove_cb (AccessibleDeviceListener  *al,
302                                 AccessibleDeviceListenerCB callback)
303 {
304   CSpiDeviceListener *listener = al;
305
306   g_return_if_fail (CSPI_IS_DEVICE_LISTENER (listener));
307
308   listener->callbacks = cspi_event_list_remove_by_cb (listener->callbacks, (void *) callback);
309 }
310
311 void
312 cspi_event_listener_unref (AccessibleEventListener *listener)
313 {
314   bonobo_object_unref (BONOBO_OBJECT (listener));
315 }
316
317 void
318 cspi_device_listener_unref (AccessibleDeviceListener *listener)
319 {
320   bonobo_object_unref (BONOBO_OBJECT (listener));
321 }
322
323
324 CORBA_Object
325 cspi_event_listener_get_corba (AccessibleEventListener *listener)
326 {
327   return BONOBO_OBJREF (listener);
328 }
329
330 CORBA_Object
331 cspi_device_listener_get_corba (AccessibleDeviceListener *listener)
332 {
333   return BONOBO_OBJREF (listener);
334 }
335