Add atk-bridge
[platform/core/uifw/at-spi2-atk.git] / cspi / spi_event.c
1 /*
2  * AT-SPI - Assistive Technology Service Provider Interface
3  * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
4  *
5  * Copyright 2001, 2002, 2003 Sun Microsystems Inc.,
6  * Copyright 2001, 2002, 2003 Ximian, 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 <cspi/spi-private.h>
25 #include <cspi/bonobo/cspi-bonobo-listener.h>
26
27 static GSList *_cspi_event_queue = NULL;
28
29 /**
30  * SPI_freeAccessibleKeySet:
31  * @keyset: An AccessibleKeyset to free.
32  *
33  * Release the memory used by an AccessibleKeySet.
34  *
35  **/
36 void
37 SPI_freeAccessibleKeySet (AccessibleKeySet *keyset)
38 {
39   int i = 0;    
40   g_free (keyset->keysyms);
41   g_free (keyset->keycodes);
42   while (keyset->keystrings [i])
43     {
44       g_free (keyset->keystrings [i++]);
45     }
46   g_free (keyset->keystrings);
47   g_free (keyset);
48 }
49
50 /**
51  * SPI_createAccessibleKeySet:
52  * @len: the number of key values in the key set.
53  * @keysyms: a UTF-8 string containing symbolic key values to be matched, or NULL if
54  *           matching is performed against other key values instead.
55  * @keycodes: an array of unsigned short values which are the hardware keycodes
56  *           to be matched, or NULL if the keyset is specified solely by keysyms
57  *           and/or keystrings.
58  * @keystrings: an array of null-terminated character strings which specify key
59  *             name values to match, or NULL if the keyset is specified solely by
60  *             keycodes and/or keysyms.
61  *
62  * Create a new #AccessibleKeySet of a specified length.
63  * A KeySet is used typically to match key event values, and a matches are made
64  * using the following criteria: a match exists with a key event if all non-null
65  * i-th members of the keyset match the key event.
66  * If both keystring and keysym values are NULL, a keycode value match is
67  * forced, thus the match for keysym=0, keycode=0, keystring=NULL is
68  * keycode 0.
69  *
70  * Returns: a pointer to a newly-created #AccessibleKeySet.
71  *
72  **/
73 AccessibleKeySet *
74 SPI_createAccessibleKeySet (int len, const char *keysyms, short *keycodes,
75                             const char **keystrings)
76 {
77   AccessibleKeySet *keyset = g_new0 (AccessibleKeySet, 1);
78   int i, keysym_len = 0;
79   const char *keysym_ptr = keysyms;
80   keyset->len = len;
81   keyset->keysyms = g_new0 (unsigned long, len);
82   keyset->keycodes = g_new0 (unsigned short, len);
83   keyset->keystrings = g_new0 (char *, len);
84   if (keysyms)
85     {
86       keysym_len = g_utf8_strlen (keysyms, -1);
87     }
88   for (i = 0; i < len; ++i)
89     {
90       if (i < keysym_len)
91         {
92           keyset->keysyms [i] = (unsigned long) g_utf8_get_char (keysym_ptr);
93           keysym_ptr = g_utf8_find_next_char (keysym_ptr, NULL);
94         }
95       else
96         {
97           keyset->keysyms [i] = 0;
98         }
99       if (keycodes)
100         {
101           keyset->keycodes [i] = keycodes [i];
102         }
103       if (keystrings)
104         {
105           keyset->keystrings [i] = g_strdup (keystrings [i]);
106         }
107     }
108   return keyset;        
109 }
110
111 /**
112  * SPI_createAccessibleEventListener:
113  * @callback : an #AccessibleEventListenerCB callback function, or NULL.
114  * @user_data: a pointer to data which will be passed to the callback when invoked.
115  *
116  * Create a new #AccessibleEventListener with a specified (in-process) callback function.
117  *
118  * Returns: a pointer to a newly-created #AccessibleEventListener.
119  *
120  **/
121 AccessibleEventListener *
122 SPI_createAccessibleEventListener (AccessibleEventListenerCB callback,
123                                    void                     *user_data)
124 {
125   AccessibleEventListener *listener = cspi_event_listener_new ();
126   if (callback)
127     {
128       AccessibleEventListener_addCallback (listener, callback, user_data);
129     }
130   return listener;
131 }
132
133 /**
134  * AccessibleEventListener_addCallback:
135  * @listener: the #AccessibleEventListener instance to modify.
136  * @callback: an #AccessibleEventListenerCB function pointer.
137  * @user_data: a pointer to data which will be passed to the callback when invoked.
138  *
139  * Add an in-process callback function to an existing AccessibleEventListener.
140  * Note that the callback function must live in the same address
141  * space as the AccessibleEventListener implementation code, thus one should not
142  * use this function to attach callbacks to a 'remote' event listener
143  * (that is, one that was not created by a client call to
144  * createAccessibleEventListener ();
145  *
146  * Returns: #TRUE if successful, otherwise #FALSE.
147  *
148  **/
149 SPIBoolean
150 AccessibleEventListener_addCallback (AccessibleEventListener *listener,
151                                      AccessibleEventListenerCB callback,
152                                      void                     *user_data)
153 {
154   cspi_event_listener_add_cb (listener, callback, user_data);
155   return TRUE;
156 }
157
158 /**
159  * AccessibleEventListener_unref:
160  * @listener: a pointer to the #AccessibleEventListener being operated on.
161  *
162  * Decrements an #AccessibleEventListener's reference count.
163  **/
164 void
165 AccessibleEventListener_unref (AccessibleEventListener *listener)
166 {
167   cspi_event_listener_unref (listener);
168 }
169
170 /**
171  * AccessibleEventListener_removeCallback:
172  * @listener: the #AccessibleEventListener instance to modify.
173  * @callback: an #AccessibleEventListenerCB function pointer.
174  *
175  * Remove an in-process callback function from an existing AccessibleEventListener.
176  *
177  * Returns: #TRUE if successful, otherwise #FALSE.
178  *
179  **/
180 SPIBoolean
181 AccessibleEventListener_removeCallback (AccessibleEventListener  *listener,
182                                         AccessibleEventListenerCB callback)
183 {
184   cspi_event_listener_remove_cb (listener, callback);
185   return TRUE;
186 }
187
188 /**
189  * SPI_createAccessibleKeystrokeListener:
190  * @callback : an #AccessibleKeystrokeListenerCB callback function, or NULL.
191  * @user_data: a pointer to data which will be passed to the callback when invoked.
192  *
193  * Create a new #AccessibleKeystrokeListener with a specified callback function.
194  *
195  * Returns: a pointer to a newly-created #AccessibleKeystrokeListener.
196  *
197  **/
198 AccessibleKeystrokeListener *
199 SPI_createAccessibleKeystrokeListener (AccessibleKeystrokeListenerCB callback,
200                                        void                         *user_data)
201 {
202   AccessibleDeviceListener *listener = cspi_device_listener_new ();
203   if (callback)
204     {
205       AccessibleDeviceListener_addCallback (listener, callback, user_data);
206     }
207   return listener;
208 }
209
210 /**
211  * AccessibleKeystrokeListener_addCallback:
212  * @listener: the #AccessibleKeystrokeListener instance to modify.
213  * @callback: an #AccessibleKeystrokeListenerCB function pointer.
214  * @user_data: a pointer to data which will be passed to the callback when invoked.
215  *
216  * Add an in-process callback function to an existing #AccessibleKeystrokeListener.
217  *
218  * Returns: #TRUE if successful, otherwise #FALSE.
219  *
220  **/
221 SPIBoolean
222 AccessibleKeystrokeListener_addCallback (AccessibleKeystrokeListener *listener,
223                                          AccessibleKeystrokeListenerCB callback,
224                                          void                         *user_data)
225 {
226   cspi_device_listener_add_cb (listener, callback, user_data);
227   return TRUE;
228 }
229
230 /**
231  * AccessibleKeystrokeListener_removeCallback:
232  * @listener: the #AccessibleKeystrokeListener instance to modify.
233  * @callback: an #AccessibleKeystrokeListenerCB function pointer.
234  *
235  * Remove an in-process callback function from an existing #AccessibleKeystrokeListener.
236  *
237  * Returns: #TRUE if successful, otherwise #FALSE.
238  *
239  **/
240 SPIBoolean
241 AccessibleKeystrokeListener_removeCallback (AccessibleKeystrokeListener *listener,
242                                             AccessibleKeystrokeListenerCB callback)
243 {
244   cspi_device_listener_remove_cb (listener, callback);
245   return TRUE;
246 }
247
248 /**
249  * AccessibleKeystrokeListener_unref:
250  * @listener: a pointer to the #AccessibleKeystrokeListener being operated on.
251  *
252  * Decrements an #AccessibleKeystrokeListener's reference count.
253  **/
254 void
255 AccessibleKeystrokeListener_unref (AccessibleKeystrokeListener *listener)
256 {
257   cspi_device_listener_unref (listener);
258 }
259
260 /**
261  * SPI_createAccessibleDeviceListener:
262  * @callback : an #AccessibleDeviceListenerCB callback function, or NULL.
263  * @user_data: a pointer to data which will be passed to the callback when invoked.
264  *
265  * Create a new #AccessibleDeviceListener with a specified callback function.
266  *
267  * Returns: a pointer to a newly-created #AccessibleDeviceListener.
268  *
269  **/
270 AccessibleDeviceListener *
271 SPI_createAccessibleDeviceListener (AccessibleDeviceListenerCB callback,
272                                        void                         *user_data)
273 {
274   AccessibleDeviceListener *listener = cspi_device_listener_new ();
275   if (callback)
276     {
277       AccessibleDeviceListener_addCallback (listener, callback, user_data);
278     }
279   return listener;
280 }
281
282 /**
283  * AccessibleDeviceListener_addCallback:
284  * @listener: the #AccessibleDeviceListener instance to modify.
285  * @callback: an #AccessibleDeviceListenerCB function pointer.
286  * @user_data: a pointer to data which will be passed to the callback when invoked.
287  *
288  * Add an in-process callback function to an existing #AccessibleDeviceListener.
289  *
290  * Returns: #TRUE if successful, otherwise #FALSE.
291  *
292  **/
293 SPIBoolean
294 AccessibleDeviceListener_addCallback (AccessibleDeviceListener *listener,
295                                          AccessibleDeviceListenerCB callback,
296                                          void                         *user_data)
297 {
298   cspi_device_listener_add_cb (listener, callback, user_data);
299   return TRUE;
300 }
301
302 /**
303  * AccessibleDeviceListener_removeCallback:
304  * @listener: the #AccessibleDeviceListener instance to modify.
305  * @callback: an #AccessibleDeviceListenerCB function pointer.
306  *
307  * Remove an in-process callback function from an existing #AccessibleDeviceListener.
308  *
309  * Returns: #TRUE if successful, otherwise #FALSE.
310  *
311  **/
312 SPIBoolean
313 AccessibleDeviceListener_removeCallback (AccessibleDeviceListener *listener,
314                                             AccessibleDeviceListenerCB callback)
315 {
316   cspi_device_listener_remove_cb (listener, callback);
317   return TRUE;
318 }
319
320 /**
321  * AccessibleDeviceListener_unref:
322  * @listener: a pointer to the #AccessibleDeviceListener being operated on.
323  *
324  * Decrements an #AccessibleDeviceListener's reference count.
325  **/
326 void
327 AccessibleDeviceListener_unref (AccessibleDeviceListener *listener)
328 {
329   cspi_device_listener_unref (listener);
330 }
331
332 static char *
333 cspi_internal_event_get_text (const InternalEvent *e)
334 {
335   CORBA_any *any;
336   g_return_val_if_fail (e, NULL);
337   g_return_val_if_fail (e->data, NULL);
338   any = (CORBA_any *) e->data;
339   if (CORBA_TypeCode_equivalent (any->_type, TC_Accessibility_EventDetails, NULL)) 
340     {
341       Accessibility_EventDetails *details = (Accessibility_EventDetails *)any->_value;
342       if (CORBA_TypeCode_equal (details->any_data._type, TC_CORBA_string, cspi_ev()))
343           return CORBA_string_dup (* (char **) (details->any_data._value));
344       else
345           return CORBA_string_dup ("");
346       return CORBA_string_dup (* (char **) (details->any_data._value));
347     }
348   else if (CORBA_TypeCode_equivalent (any->_type, TC_CORBA_string, NULL)) 
349     {
350       return CORBA_string_dup (* (char **) any->_value);
351     } 
352   else
353     {
354 #ifdef EVENT_CONTEXT_DEBUG
355       fprintf (stderr, "requested string, TC is not TC_CORBA_string! (%u)\n",
356                (unsigned) any->_type);
357 #endif
358       return NULL;
359     }
360 }
361
362 static Accessible *
363 cspi_internal_event_get_object (const InternalEvent *e)
364 {
365   CORBA_any *any;
366
367   g_return_val_if_fail (e, NULL);
368   g_return_val_if_fail (e->data, NULL);
369
370   any = (CORBA_any *) e->data;
371   if (CORBA_TypeCode_equivalent (any->_type, TC_Accessibility_EventDetails, NULL)) 
372     {
373       Accessibility_EventDetails *details = (Accessibility_EventDetails *)any->_value;
374       if (CORBA_TypeCode_equal (details->any_data._type, TC_CORBA_Object, cspi_ev()))
375           return cspi_object_take (* (CORBA_Object *) (details->any_data._value));
376       else
377           return NULL;
378     }
379   else if (CORBA_TypeCode_equal (any->_type, TC_CORBA_Object, cspi_ev()))
380     return cspi_object_take (* (CORBA_Object *) any->_value);
381   else 
382     return NULL;
383 }
384
385 static SPIRect *
386 cspi_internal_event_get_rect (const InternalEvent *e)
387 {
388   CORBA_any *any;
389   g_return_val_if_fail (e, NULL);
390   g_return_val_if_fail (e->data, NULL);
391   any = (CORBA_any *) e->data;
392   if (CORBA_TypeCode_equivalent (any->_type, TC_Accessibility_EventDetails, NULL)) 
393     {
394       Accessibility_EventDetails *details = (Accessibility_EventDetails *)any->_value;
395       SPIRect *rect = g_new (SPIRect, 1);
396       if (CORBA_TypeCode_equal (details->any_data._type, TC_Accessibility_BoundingBox, cspi_ev()))
397       {
398           Accessibility_BoundingBox *bounds = (Accessibility_BoundingBox *) details->any_data._value;
399           rect->x = bounds->x;
400           rect->y = bounds->y;
401           rect->width = bounds->width;
402           rect->height = bounds->height;
403           return rect;
404       }
405       else
406           return NULL;
407     }
408   if (CORBA_TypeCode_equivalent (any->_type, TC_Accessibility_BoundingBox, NULL)) 
409     {
410       SPIRect *rect = g_new (SPIRect, 1);
411       Accessibility_BoundingBox *bounds = (Accessibility_BoundingBox *) any->_value;
412       rect->x = bounds->x;
413       rect->y = bounds->y;
414       rect->width = bounds->width;
415       rect->height = bounds->height;
416       return rect;
417     } 
418   else
419     {
420 #ifdef EVENT_CONTEXT_DEBUG
421       fprintf (stderr, "requested string, TC is not TC_Accessible_RectBounds! (%u)\n",
422                (unsigned) any->_type);
423 #endif
424       return NULL;
425     }
426 }
427
428 /**
429  * AccessibleEvent_getSourceName:
430  * @e: an #AccessibleEvent to be queried. 
431  *
432  * Get the 'accessible-name' of the object emitting the event.
433  *
434  * Returns: The name of the event source, or NULL if the event source cannot be identified
435  *          or does not report a name.
436  */
437 char*        AccessibleEvent_getSourceName (const AccessibleEvent *e)
438 {
439     InternalEvent *ie = (InternalEvent *)e;
440     CORBA_any *any = ((ie && ie->data) ? (CORBA_any *)ie->data : NULL);
441     if (any &&
442         CORBA_TypeCode_equivalent (any->_type, 
443                                    TC_Accessibility_EventDetails, NULL))
444       {
445           Accessibility_EventDetails *details = (Accessibility_EventDetails *) any->_value;
446           return CORBA_string_dup (details->source_name);
447       }
448     else
449         return NULL;
450 }
451
452 /**
453  * AccessibleEvent_getSourceRole:
454  * @e: an #AccessibleEvent to be queried. 
455  *
456  * Get the #AccessibleRole of the object emitting the event.
457  *
458  * Returns: #AccessibleRole of the event source, or SPI_ROLE_UNKNOWN
459  *          if the event source's role is unknown or unspecified.
460  *          (Some kinds of events, such as 'mouse:' events or
461  *          toolkit events, don't have associated object roles.)
462  */
463 AccessibleRole AccessibleEvent_getSourceRole (const AccessibleEvent *e)
464 {
465     InternalEvent *ie = (InternalEvent *)e;
466     CORBA_any *any = ((ie && ie->data) ? (CORBA_any *)ie->data : NULL);
467     if (any &&
468         CORBA_TypeCode_equivalent (any->_type, 
469                                    TC_Accessibility_EventDetails, NULL))
470       {
471           Accessibility_EventDetails *details = (Accessibility_EventDetails *) any->_value;
472           return cspi_role_from_spi_role (details->source_role);
473       }
474     else
475         return SPI_ROLE_UNKNOWN;
476 }
477
478 /**
479  * AccessibleEvent_getSourceApplication:
480  * @e: an #AccessibleEvent to be queried. 
481  *
482  * Get the #Application hosting the object which emitted the event.
483  *
484  * Returns: A pointer to the host #Application contining the event source
485  *          component.
486  */
487 AccessibleApplication* AccessibleEvent_getSourceApplication (const AccessibleEvent *e)
488 {
489     InternalEvent *ie = (InternalEvent *)e;
490     CORBA_any *any = ((ie && ie->data) ? (CORBA_any *)ie->data : NULL);
491     if (any &&
492         CORBA_TypeCode_equivalent (any->_type, 
493                                    TC_Accessibility_EventDetails, NULL))
494       {
495           Accessibility_EventDetails *details = (Accessibility_EventDetails *) any->_value;
496           return  cspi_object_take (details->host_application);
497       }
498     else
499         return NULL;
500 }
501
502 /**
503  * AccessibleEvent_getSourceDetails:
504  * @e: an #AccessibleEvent to be queried. 
505  * @name: a pointer to a character string which will point to the name of the event source 
506  * on successful completion of the call.
507  * @role: a pointer to an #AccessibleRole which will point to the role of the event source
508  * on successful completion of the call.
509  * @app: A pointer to an #AccessibleApplication which points to the host application for this event
510  * on successful completion of the call.
511  *
512  * Get the host #Application, "accessible name", and #AccessibleRole 
513  * of the object which emitted the event.
514  *
515  * Returns: TRUE if the source details were successfully retrieved, 
516  *          FALSE if they were not, either due to error, incomplete data,
517  *          or the fact that the event did not encapsulate the required data.
518  */
519 SPIBoolean   AccessibleEvent_getSourceDetails (const AccessibleEvent *e, 
520                                                char **name, AccessibleRole *role, 
521                                                AccessibleApplication **app)
522 {
523     InternalEvent *ie = (InternalEvent *)e;
524     CORBA_any *any = ((ie && ie->data) ? (CORBA_any *)ie->data : NULL);
525     if (any &&
526         CORBA_TypeCode_equivalent (any->_type, 
527                                    TC_Accessibility_EventDetails, NULL))
528       {
529           Accessibility_EventDetails *details = (Accessibility_EventDetails *) any->_value;
530           *name = CORBA_string_dup (details->source_name);
531           *role = cspi_role_from_spi_role (details->source_role);
532           *app = cspi_object_take (details->host_application);
533           return TRUE;
534       }
535     else
536       {
537         *name = NULL;
538         *role = SPI_ROLE_UNKNOWN;
539         *app = NULL;
540         return FALSE;
541       }
542 }
543
544 /**
545  * AccessibleTextChangedEvent_getChangeString:
546  * @e: a pointer to the #AccessibleEvent being queried.
547  *
548  * Queries an #AccessibleEvent of type "object:text-changed", 
549  *         returning the text inserted or deleted.
550  *
551  * Returns: a UTF-8 text string indicating the text inserted,
552  *          deleted, or substituted by this event.
553  **/
554 char *
555 AccessibleTextChangedEvent_getChangeString (const AccessibleEvent *e)
556 {
557   const InternalEvent *foo = (InternalEvent *) e;
558   /* TODO: check the event type. */
559   return cspi_internal_event_get_text (foo);
560 }
561
562 /**
563  * AccessibleTextSelectionChangedEvent_getSelectionString:
564  * @e: a pointer to the #AccessibleEvent being queried.
565  *
566  * Queries an #AccessibleEvent of type "object:text-selection-changed", 
567  *         returning the newly added, removed, or modified selection string.
568  *
569  * Returns: a UTF-8 text string indicating the recently changed selection.
570  **/
571 char *
572 AccessibleTextSelectionChangedEvent_getSelectionString (const AccessibleEvent *e)
573 {
574   const InternalEvent *foo = (InternalEvent *) e;
575   /* TODO: check the event type. */
576   return cspi_internal_event_get_text (foo);
577 }
578
579 /**
580  * AccessibleWindowEvent_getTitleString:
581  * @e: a pointer to the #AccessibleEvent being queried.
582  *
583  * Queries an #AccessibleEvent of type "window:", 
584  *         returning the window title.
585  *
586  * Returns: a UTF-8 text string representing the title of the 
587  *         recently changed window.
588  **/
589 char *
590 AccessibleWindowEvent_getTitleString (const AccessibleEvent *e)
591 {
592   const InternalEvent *foo = (InternalEvent *) e;
593   /* TODO: check the event type. */
594   return cspi_internal_event_get_text (foo);
595 }
596
597 /**
598  * AccessibleChildChangedEvent_getChildAccessible:
599  * @e: a pointer to the #AccessibleEvent being queried.
600  *
601  * Queries an #AccessibleEvent of type "object:children_changed"
602  *         to get a reference to the changed #Accessible.
603  *         Note that context #Accessibles are not guaranteed to outlive
604  *         event delivery, in which case this call may return %NULL
605  *         even if the object existed at the time of dispatch.
606  *
607  * Returns: the context #Accessible for the event, or %NULL if
608  *          there is no longer a valid context #Accessible 
609  *          object for the event.
610  **/
611 Accessible *
612 AccessibleChildChangedEvent_getChildAccessible (const AccessibleEvent *e)
613 {
614   const InternalEvent *foo = (InternalEvent *) e;
615   return (Accessible *) cspi_internal_event_get_object (foo);
616 }
617
618 /**
619  * AccessibleParentChangedEvent_getParentAccessible:
620  * @e: a pointer to the #AccessibleEvent being queried.
621  *
622  * Queries an #AccessibleEvent of type "object:property-change:accessible-parent"
623  *         to get a reference to the changed #Accessible.
624  *         Note that context #Accessibles are not guaranteed to outlive
625  *         event delivery, in which case this call may return %NULL
626  *         even if the object existed at the time of dispatch.
627  *
628  * Returns: an #Accessible pointer representing the new parent object.
629  **/
630 Accessible *
631 AccessibleParentChangedEvent_getParentAccessible (const AccessibleEvent *e)
632 {
633   const InternalEvent *foo = (InternalEvent *) e;
634   return (Accessible *) cspi_internal_event_get_object (foo);
635 }
636
637 /**
638  * AccessibleActiveDescendantChangedEvent_getActiveDescendant:
639  * @e: a pointer to the #AccessibleEvent being queried.
640  *
641  * Queries an #AccessibleEvent of type "object:active-descendant-changed"
642  *         to get a reference to the changed #Accessible.
643  *         Note that context #Accessibles are not guaranteed to outlive
644  *         event delivery, in which case this call may return %NULL
645  *         even if the object existed at the time of dispatch.
646  *
647  * Returns: an #Accessible pointer representing the new active descendant.
648  **/
649 Accessible *
650 AccessibleActiveDescendantChangedEvent_getActiveDescendant (const AccessibleEvent *e) 
651 {
652   const InternalEvent *foo = (InternalEvent *) e;
653   return (Accessible *) cspi_internal_event_get_object (foo);
654 }
655
656 /**
657  * AccessibleTableSummaryChangedEvent_getSummaryAccessible:
658  * @e: a pointer to the #AccessibleEvent being queried.
659  *
660  * Queries an #AccessibleEvent of type "object:property-changed:accessible-table-summary"
661  *         to get a reference to the changed #Accessible.
662  *         Note that context #Accessibles are not guaranteed to outlive
663  *         event delivery, in which case this call may return %NULL
664  *         even if the object existed at the time of dispatch.
665  *
666  * Returns: an #Accessible pointer representing the new table summary.
667  **/
668 Accessible *
669 AccessibleTableSummaryChangedEvent_getSummaryAccessible (const AccessibleEvent *e) 
670 {
671   const InternalEvent *foo = (InternalEvent *) e;
672   return (Accessible *) cspi_internal_event_get_object (foo);
673 }
674
675 /**
676  * AccessibleTableHeaderChangedEvent_getHeaderAccessible:
677  * @e: a pointer to the #AccessibleEvent being queried.
678  *
679  * Queries an #AccessibleEvent of type 
680  *         "object:property-changed:accessible-table-row-header" or
681  *         "object:property-changed:accessible-table-column-header"
682  *         to get a reference to the changed #Accessible.
683  *         Note that context #Accessibles are not guaranteed to outlive
684  *         event delivery, in which case this call may return %NULL
685  *         even if the object existed at the time of dispatch.
686  *
687  * Returns: an #Accessible pointer representing the new table header.
688  **/
689 Accessible *
690 AccessibleTableHeaderChangedEvent_getHeaderAccessible (const AccessibleEvent *e)
691 {
692   const InternalEvent *foo = (InternalEvent *) e;
693   return (Accessible *) cspi_internal_event_get_object (foo);
694 }
695
696
697 /**
698  * AccessibleTableCaptionChangedEvent_getCaptionString:
699  * @e: a pointer to the #AccessibleEvent being queried.
700  *
701  * Queries an #AccessibleEvent of type 
702  *         "object:property-changed:accessible-table-caption-object" 
703  *         returning the text in the caption, if present.
704  *
705  * Returns: a UTF-8 text string indicating the text in the caption.
706  **/
707 char *
708 AccessibleTableCaptionChangedEvent_getCaptionString (const AccessibleEvent *e)
709 {
710   const InternalEvent *foo = (InternalEvent *) e;
711   /* TODO: check the event type. */
712   return cspi_internal_event_get_text (foo);
713 }
714
715 /**
716  * AccessibleTableRowDescriptionChangedEvent_getDescriptionString:
717  * @e: a pointer to the #AccessibleEvent being queried.
718  *
719  * Queries an #AccessibleEvent of type 
720  *         "object:property-changed:accessible-table-row-description" 
721  *         returning the new table row description.
722  *
723  * Returns: a UTF-8 text string representing the recently changed
724  *         table row description 
725  **/
726 char *
727 AccessibleTableRowDescriptionChangedEvent_getDescriptionString (const AccessibleEvent *e)
728 {
729   const InternalEvent *foo = (InternalEvent *) e;
730   /* TODO: check the event type. */
731   return cspi_internal_event_get_text (foo);
732 }
733
734 /**
735  * AccessibleTableColumnDescriptionChangedEvent_getDescriptionString:
736  * @e: a pointer to the #AccessibleEvent being queried.
737  *
738  * Queries an #AccessibleEvent of type 
739  *         "object:property-changed:accessible-table-column-description" 
740  *         returning the new table column description.
741  *
742  * Returns: a UTF-8 text string representing the recently changed
743  *         table column description 
744  **/
745 char *
746 AccessibleTableColumnDescriptionChangedEvent_getDescriptionString (const AccessibleEvent *e)
747 {
748   const InternalEvent *foo = (InternalEvent *) e;
749   /* TODO: check the event type. */
750   return cspi_internal_event_get_text (foo);
751 }
752
753 /**
754  * AccessibleDescriptionChangedEvent_getDescriptionString:
755  * @e: a pointer to the #AccessibleEvent being queried.
756  *
757  * Queries an #AccessibleEvent of type 
758  *         "object:property-changed:accessible-description" 
759  *         returning the new description.
760  *
761  * Returns: a UTF-8 text string representing the recently changed
762  *         description 
763  **/
764 char *
765 AccessibleDescriptionChangedEvent_getDescriptionString (const AccessibleEvent *e)
766 {
767   const InternalEvent *foo = (InternalEvent *) e;
768   /* TODO: check the event type. */
769   return cspi_internal_event_get_text (foo);
770 }
771
772 /**
773  * AccessibleBoundsChangedEvent_getNewBounds:
774  * @e: a pointer to the #AccessibleEvent being queried.
775  *
776  * Queries an #AccessibleEvent of type "object:bounds-changed", 
777  *         returning a pointer to an SPIRect structure containing the
778  *         new bounds, or NULL on error.
779  *         The returned structure should be freed with SPI_freeRect when 
780  *         the caller has finished referencing it.
781  *
782  * @Since: AT-SPI 1.6
783  *
784  * Returns: a pointer to an SPIRect defining the new object bounds.
785  **/
786 SPIRect *
787 AccessibleBoundsChangedEvent_getNewBounds (const AccessibleEvent *e)
788 {
789   const InternalEvent *foo = (InternalEvent *) e;
790   /* TODO: check the event type. */
791   return cspi_internal_event_get_rect (foo);
792 }
793
794 static gint
795 cspi_event_compare (gconstpointer p1, gconstpointer p2)
796 {
797   const InternalEvent *e1 = p1, *e2 = p2;
798   return (gint) ((long) e2->id  - (long) e1->id);
799 }
800
801 static InternalEvent *
802 cspi_internal_event_lookup (const InternalEvent *e)
803 {
804   InternalEvent *internal = NULL;
805   GSList *p =
806     g_slist_find_custom (_cspi_event_queue, e, cspi_event_compare);
807   if (p)
808     internal = p->data;
809   return internal;
810 }
811
812 static const InternalEvent *
813 cspi_internal_event_check (const AccessibleEvent *e)
814 {
815   InternalEvent *internal = (InternalEvent *) e;
816   if (internal->magic == SPI_INTERNAL_EVENT_MAGIC) 
817     return internal;
818   else
819     return NULL;
820 }
821
822 static InternalEvent *
823 cspi_internal_event_add (const InternalEvent *e)
824 {
825   _cspi_event_queue = g_slist_prepend (_cspi_event_queue, (gpointer) e);
826   return (InternalEvent *) e;
827 }
828
829 static void
830 cspi_internal_event_remove (const InternalEvent *e)
831 {
832   GSList *link = g_slist_find_custom (_cspi_event_queue, e, cspi_event_compare);
833   if (link)
834     _cspi_event_queue = g_slist_remove_link (_cspi_event_queue, link);
835 }
836
837 /**
838  * AccessibleNameChangedEvent_getNameString:
839  * @e: a pointer to the #AccessibleEvent being queried.
840  *
841  * Queries an #AccessibleEvent of type "object:property-change:accessible_name:", 
842  *         returning the name.
843  *
844  * Returns: a UTF-8 text string representing the name of the 
845  *         object which recently changed.
846  **/
847 char *
848 AccessibleNameChangedEvent_getNameString (const AccessibleEvent *e)
849 {
850   const InternalEvent *foo = (InternalEvent *) e;
851   return cspi_internal_event_get_text (foo);
852 }
853
854 /**
855  * AccessibleEvent_ref:
856  * @e: a pointer to the #AccessibleEvent being referenced.
857  *
858  * Increments by 1 the reference count of the event
859  *
860  * Returns: TRUE if the function succeeded; FALSE if the pointer is not a
861  *         valid event.
862  **/
863 SPIBoolean
864 AccessibleEvent_ref (const AccessibleEvent *e)
865 {
866   const InternalEvent *private = cspi_internal_event_check (e);
867   if (private)
868     {
869       InternalEvent *event = cspi_internal_event_lookup (private);
870       /* 
871        * put event in the cache if it's not there already, 
872        * and increment refcount 
873        */
874       if (!event)
875         {
876           event = cspi_internal_event_add (private);
877         }
878       event->ref_count++;
879       return TRUE;
880     }
881   else
882     return FALSE;
883 }
884
885 /**
886  * AccessibleEvent_unref:
887  * @e: a pointer to the #AccessibleEvent being referenced.
888  *
889  * Decrements by 1 the reference count of the event. The event is destroyed
890  * when the reference count recahes zero.
891  *
892  **/
893 void
894 AccessibleEvent_unref (const AccessibleEvent *e)
895 {
896   const InternalEvent *private = cspi_internal_event_check (e);
897   /* decrement refcount and remove if appropriate */
898   if (private)
899     {
900       InternalEvent *event = cspi_internal_event_lookup (private);
901       if (event) 
902         {
903           event->ref_count--;
904           if (event->ref_count < 1)
905             {
906               cspi_internal_event_remove (event);
907               g_free ((gpointer)e->type);
908               Accessible_unref (e->source);
909               CORBA_free (event->data);
910               g_free ((gpointer)e);
911             }
912         }
913     }
914 }