2 * AT-SPI - Assistive Technology Service Provider Interface
3 * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
5 * Copyright 2001, 2002 Sun Microsystems Inc.,
6 * Copyright 2001, 2002 Ximian, 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 <cspi/spi-private.h>
25 #include <cspi/bonobo/cspi-bonobo-listener.h>
27 static GSList *_cspi_event_queue = NULL;
30 * SPI_freeAccessibleKeySet:
31 * @keyset: An AccessibleKeyset to free.
33 * Release the memory used by an AccessibleKeySet.
37 SPI_freeAccessibleKeySet (AccessibleKeySet *keyset)
40 g_free (keyset->keysyms);
41 g_free (keyset->keycodes);
42 while (keyset->keystrings [i])
44 g_free (keyset->keystrings [i++]);
46 g_free (keyset->keystrings);
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
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.
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
70 * Returns: a pointer to a newly-created #AccessibleKeySet.
74 SPI_createAccessibleKeySet (int len, const char *keysyms, short *keycodes,
75 const char **keystrings)
77 AccessibleKeySet *keyset = g_new0 (AccessibleKeySet, 1);
78 int i, keysym_len = 0;
79 const char *keysym_ptr = keysyms;
81 keyset->keysyms = g_new0 (unsigned long, len);
82 keyset->keycodes = g_new0 (unsigned short, len);
83 keyset->keystrings = g_new0 (char *, len);
86 keysym_len = g_utf8_strlen (keysyms, -1);
88 for (i = 0; i < len; ++i)
92 keyset->keysyms [i] = (unsigned long) g_utf8_get_char (keysym_ptr);
93 keysym_ptr = g_utf8_find_next_char (keysym_ptr, NULL);
97 keyset->keysyms [i] = 0;
101 keyset->keycodes [i] = keycodes [i];
105 keyset->keystrings [i] = g_strdup (keystrings [i]);
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.
116 * Create a new #AccessibleEventListener with a specified (in-process) callback function.
118 * Returns: a pointer to a newly-created #AccessibleEventListener.
121 AccessibleEventListener *
122 SPI_createAccessibleEventListener (AccessibleEventListenerCB callback,
125 AccessibleEventListener *listener = cspi_event_listener_new ();
128 AccessibleEventListener_addCallback (listener, callback, user_data);
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.
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 ();
146 * Returns: #TRUE if successful, otherwise #FALSE.
150 AccessibleEventListener_addCallback (AccessibleEventListener *listener,
151 AccessibleEventListenerCB callback,
154 cspi_event_listener_add_cb (listener, callback, user_data);
159 * AccessibleEventListener_unref:
160 * @listener: a pointer to the #AccessibleEventListener being operated on.
162 * Decrements an #AccessibleEventListener's reference count.
165 AccessibleEventListener_unref (AccessibleEventListener *listener)
167 cspi_event_listener_unref (listener);
171 * AccessibleEventListener_removeCallback:
172 * @listener: the #AccessibleEventListener instance to modify.
173 * @callback: an #AccessibleEventListenerCB function pointer.
175 * Remove an in-process callback function from an existing AccessibleEventListener.
177 * Returns: #TRUE if successful, otherwise #FALSE.
181 AccessibleEventListener_removeCallback (AccessibleEventListener *listener,
182 AccessibleEventListenerCB callback)
184 cspi_event_listener_remove_cb (listener, callback);
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.
193 * Create a new #AccessibleKeystrokeListener with a specified callback function.
195 * Returns: a pointer to a newly-created #AccessibleKeystrokeListener.
198 AccessibleKeystrokeListener *
199 SPI_createAccessibleKeystrokeListener (AccessibleKeystrokeListenerCB callback,
202 AccessibleDeviceListener *listener = cspi_device_listener_new ();
205 AccessibleDeviceListener_addCallback (listener, callback, user_data);
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.
216 * Add an in-process callback function to an existing #AccessibleKeystrokeListener.
218 * Returns: #TRUE if successful, otherwise #FALSE.
222 AccessibleKeystrokeListener_addCallback (AccessibleKeystrokeListener *listener,
223 AccessibleKeystrokeListenerCB callback,
226 cspi_device_listener_add_cb (listener, callback, user_data);
231 * AccessibleKeystrokeListener_removeCallback:
232 * @listener: the #AccessibleKeystrokeListener instance to modify.
233 * @callback: an #AccessibleKeystrokeListenerCB function pointer.
235 * Remove an in-process callback function from an existing #AccessibleKeystrokeListener.
237 * Returns: #TRUE if successful, otherwise #FALSE.
241 AccessibleKeystrokeListener_removeCallback (AccessibleKeystrokeListener *listener,
242 AccessibleKeystrokeListenerCB callback)
244 cspi_device_listener_remove_cb (listener, callback);
249 * AccessibleKeystrokeListener_unref:
250 * @listener: a pointer to the #AccessibleKeystrokeListener being operated on.
252 * Decrements an #AccessibleKeystrokeListener's reference count.
255 AccessibleKeystrokeListener_unref (AccessibleKeystrokeListener *listener)
257 cspi_device_listener_unref (listener);
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.
265 * Create a new #AccessibleDeviceListener with a specified callback function.
267 * Returns: a pointer to a newly-created #AccessibleDeviceListener.
270 AccessibleDeviceListener *
271 SPI_createAccessibleDeviceListener (AccessibleDeviceListenerCB callback,
274 AccessibleDeviceListener *listener = cspi_device_listener_new ();
277 AccessibleDeviceListener_addCallback (listener, callback, user_data);
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.
288 * Add an in-process callback function to an existing #AccessibleDeviceListener.
290 * Returns: #TRUE if successful, otherwise #FALSE.
294 AccessibleDeviceListener_addCallback (AccessibleDeviceListener *listener,
295 AccessibleDeviceListenerCB callback,
298 cspi_device_listener_add_cb (listener, callback, user_data);
303 * AccessibleDeviceListener_removeCallback:
304 * @listener: the #AccessibleDeviceListener instance to modify.
305 * @callback: an #AccessibleDeviceListenerCB function pointer.
307 * Remove an in-process callback function from an existing #AccessibleDeviceListener.
309 * Returns: #TRUE if successful, otherwise #FALSE.
313 AccessibleDeviceListener_removeCallback (AccessibleDeviceListener *listener,
314 AccessibleDeviceListenerCB callback)
316 cspi_device_listener_remove_cb (listener, callback);
321 * AccessibleDeviceListener_unref:
322 * @listener: a pointer to the #AccessibleDeviceListener being operated on.
324 * Decrements an #AccessibleDeviceListener's reference count.
327 AccessibleDeviceListener_unref (AccessibleDeviceListener *listener)
329 cspi_device_listener_unref (listener);
333 cspi_internal_event_get_text (const InternalEvent *e)
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_CORBA_string, NULL))
341 return * (char **) any->_value;
345 #ifdef EVENT_CONTEXT_DEBUG
346 fprintf (stderr, "requested string, TC is not TC_CORBA_string! (%u)\n",
347 (unsigned) any->_type);
354 cspi_internal_event_get_object (const InternalEvent *e)
357 Accessible *accessible;
358 g_return_val_if_fail (e, NULL);
359 g_return_val_if_fail (e->data, NULL);
360 any = (CORBA_any *) e->data;
361 if (any->_type == TC_CORBA_Object)
362 return cspi_object_take (* (CORBA_Object *) any->_value);
368 * AccessibleTextChangedEvent_getChangeString:
369 * @event: a pointer to the #AccessibleEvent being queried.
371 * Queries an #AccessibleEvent of type "object:text-changed",
372 * returning the text inserted or deleted.
374 * Returns: a UTF-8 text string indicating the text inserted,
375 * deleted, or substituted by this event.
378 AccessibleTextChangedEvent_getChangeString (const AccessibleEvent *e)
380 const InternalEvent *foo = (InternalEvent *) e;
381 /* TODO: check the event type? expensive... */
382 return cspi_internal_event_get_text (foo);
386 * AccessibleTextSelectionChangedEvent_getSelectionString:
387 * @event: a pointer to the #AccessibleEvent being queried.
389 * Queries an #AccessibleEvent of type "object:text-selection-changed",
390 * returning the newly added, removed, or modified selection string.
392 * Returns: a UTF-8 text string indicating the recently changed selection.
395 AccessibleTextSelectionChangedEvent_getSelectionString (const AccessibleEvent *e)
397 const InternalEvent *foo = (InternalEvent *) e;
398 /* TODO: check the event type? expensive... */
399 return cspi_internal_event_get_text (foo);
403 * AccessibleWindowEvent_getTitleString:
404 * @event: a pointer to the #AccessibleEvent being queried.
406 * Queries an #AccessibleEvent of type "window:",
407 * returning the window title.
409 * Returns: a UTF-8 text string representing the title of the
410 * recently changed window.
413 AccessibleWindowEvent_getTitleString (const AccessibleEvent *e)
415 const InternalEvent *foo = (InternalEvent *) e;
416 /* TODO: check the event type? expensive... */
417 return cspi_internal_event_get_text (foo);
421 * AccessibleChildChangedEvent_getChildAccessible:
422 * @event: a pointer to the #AccessibleEvent being queried.
424 * Queries an #AccessibleEvent of type "object:children_changed"
425 * to get a reference to the changed #Accessible.
426 * Note that context #Accessibles are not guaranteed to outlive
427 * event delivery, in which case this call may return %NULL
428 * even if the object existed at the time of dispatch.
430 * Returns: the context #Accessible for the event, or %NULL if
431 * there is no longer a valid context #Accessible
432 * object for the event.
435 AccessibleChildChangedEvent_getChildAccessible (const AccessibleEvent *e)
437 const InternalEvent *foo = (InternalEvent *) e;
438 return (Accessible *) cspi_internal_event_get_object (foo);
442 * AccessibleParentChangedEvent_getParentAccessible:
443 * @event: a pointer to the #AccessibleEvent being queried.
445 * Queries an #AccessibleEvent of type "object:parent_changed"
446 * to get a reference to the changed #Accessible.
447 * Note that context #Accessibles are not guaranteed to outlive
448 * event delivery, in which case this call may return %NULL
449 * even if the object existed at the time of dispatch.
451 * Returns: an #Accessible pointer representing the new parent object.
454 AccessibleParentChangedEvent_getParentAccessible (const AccessibleEvent *e)
456 const InternalEvent *foo = (InternalEvent *) e;
457 return (Accessible *) cspi_internal_event_get_object (foo);
460 /** NEED TO DOCUMENT THESE **/
463 AccessibleActiveDescendantChangedEvent_getActiveDescendant (const AccessibleEvent *e)
465 const InternalEvent *foo = (InternalEvent *) e;
466 return (Accessible *) cspi_internal_event_get_object (foo);
470 AccessibleTableSummaryChangedEvent_getSummaryAccessible (const AccessibleEvent *e)
472 const InternalEvent *foo = (InternalEvent *) e;
473 return (Accessible *) cspi_internal_event_get_object (foo);
477 AccessibleTableHeaderChangedEvent_getHeaderAccessible (const AccessibleEvent *e)
484 AccessibleTableCaptionChangedEvent_getCaptionString (const AccessibleEvent *e)
490 AccessibleTableRowDescriptionChangedEvent_getDescriptionString (const AccessibleEvent *e)
496 AccessibleTableColumnDescriptionChangedEvent_getDescriptionString (const AccessibleEvent *e)
502 AccessibleDescriptionChangedEvent_getDescriptionString (const AccessibleEvent *e)
508 cspi_event_compare (gconstpointer p1, gconstpointer p2)
510 const InternalEvent *e1 = p1, *e2 = p2;
511 return (gint) ((long) e2->id - (long) e1->id);
514 static InternalEvent *
515 cspi_internal_event_lookup (const InternalEvent *e)
517 InternalEvent *internal = NULL;
519 g_slist_find_custom (_cspi_event_queue, e, cspi_event_compare);
525 static const InternalEvent *
526 cspi_internal_event_check (const AccessibleEvent *e)
528 InternalEvent *internal = (InternalEvent *) e;
529 if (internal->magic == SPI_INTERNAL_EVENT_MAGIC)
535 static InternalEvent *
536 cspi_internal_event_add (const InternalEvent *e)
538 _cspi_event_queue = g_slist_prepend (_cspi_event_queue, e);
539 return (InternalEvent *) e;
543 cspi_internal_event_remove (const InternalEvent *e)
545 GSList *link = g_slist_find_custom (_cspi_event_queue, e, cspi_event_compare);
547 _cspi_event_queue = g_slist_remove_link (_cspi_event_queue, link);
551 AccessibleNameChangedEvent_getNameString (const AccessibleEvent *e)
557 AccessibleEvent_ref (const AccessibleEvent *e)
559 const InternalEvent *private = cspi_internal_event_check (e);
562 InternalEvent *event = cspi_internal_event_lookup (private);
564 * put event in the cache if it's not there already,
565 * and increment refcount
569 event = cspi_internal_event_add (private);
579 AccessibleEvent_unref (const AccessibleEvent *e)
581 const InternalEvent *private = cspi_internal_event_check (e);
582 /* decrement refcount and remove if appropriate */
585 InternalEvent *event = cspi_internal_event_lookup (private);
589 if (event->ref_count < 1)
590 cspi_internal_event_remove (event);