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)
358 g_return_val_if_fail (e, NULL);
359 g_return_val_if_fail (e->data, NULL);
361 any = (CORBA_any *) e->data;
362 if (CORBA_TypeCode_equal (any->_type, TC_CORBA_Object, cspi_ev()))
363 return cspi_object_take (* (CORBA_Object *) any->_value);
369 * AccessibleTextChangedEvent_getChangeString:
370 * @event: a pointer to the #AccessibleEvent being queried.
372 * Queries an #AccessibleEvent of type "object:text-changed",
373 * returning the text inserted or deleted.
375 * Returns: a UTF-8 text string indicating the text inserted,
376 * deleted, or substituted by this event.
379 AccessibleTextChangedEvent_getChangeString (const AccessibleEvent *e)
381 const InternalEvent *foo = (InternalEvent *) e;
382 /* TODO: check the event type? expensive... */
383 return cspi_internal_event_get_text (foo);
387 * AccessibleTextSelectionChangedEvent_getSelectionString:
388 * @event: a pointer to the #AccessibleEvent being queried.
390 * Queries an #AccessibleEvent of type "object:text-selection-changed",
391 * returning the newly added, removed, or modified selection string.
393 * Returns: a UTF-8 text string indicating the recently changed selection.
396 AccessibleTextSelectionChangedEvent_getSelectionString (const AccessibleEvent *e)
398 const InternalEvent *foo = (InternalEvent *) e;
399 /* TODO: check the event type? expensive... */
400 return cspi_internal_event_get_text (foo);
404 * AccessibleWindowEvent_getTitleString:
405 * @event: a pointer to the #AccessibleEvent being queried.
407 * Queries an #AccessibleEvent of type "window:",
408 * returning the window title.
410 * Returns: a UTF-8 text string representing the title of the
411 * recently changed window.
414 AccessibleWindowEvent_getTitleString (const AccessibleEvent *e)
416 const InternalEvent *foo = (InternalEvent *) e;
417 /* TODO: check the event type? expensive... */
418 return cspi_internal_event_get_text (foo);
422 * AccessibleChildChangedEvent_getChildAccessible:
423 * @event: a pointer to the #AccessibleEvent being queried.
425 * Queries an #AccessibleEvent of type "object:children_changed"
426 * to get a reference to the changed #Accessible.
427 * Note that context #Accessibles are not guaranteed to outlive
428 * event delivery, in which case this call may return %NULL
429 * even if the object existed at the time of dispatch.
431 * Returns: the context #Accessible for the event, or %NULL if
432 * there is no longer a valid context #Accessible
433 * object for the event.
436 AccessibleChildChangedEvent_getChildAccessible (const AccessibleEvent *e)
438 const InternalEvent *foo = (InternalEvent *) e;
439 return (Accessible *) cspi_internal_event_get_object (foo);
443 * AccessibleParentChangedEvent_getParentAccessible:
444 * @event: a pointer to the #AccessibleEvent being queried.
446 * Queries an #AccessibleEvent of type "object:parent_changed"
447 * to get a reference to the changed #Accessible.
448 * Note that context #Accessibles are not guaranteed to outlive
449 * event delivery, in which case this call may return %NULL
450 * even if the object existed at the time of dispatch.
452 * Returns: an #Accessible pointer representing the new parent object.
455 AccessibleParentChangedEvent_getParentAccessible (const AccessibleEvent *e)
457 const InternalEvent *foo = (InternalEvent *) e;
458 return (Accessible *) cspi_internal_event_get_object (foo);
461 /** NEED TO DOCUMENT THESE **/
464 AccessibleActiveDescendantChangedEvent_getActiveDescendant (const AccessibleEvent *e)
466 const InternalEvent *foo = (InternalEvent *) e;
467 return (Accessible *) cspi_internal_event_get_object (foo);
471 AccessibleTableSummaryChangedEvent_getSummaryAccessible (const AccessibleEvent *e)
473 const InternalEvent *foo = (InternalEvent *) e;
474 return (Accessible *) cspi_internal_event_get_object (foo);
478 AccessibleTableHeaderChangedEvent_getHeaderAccessible (const AccessibleEvent *e)
485 AccessibleTableCaptionChangedEvent_getCaptionString (const AccessibleEvent *e)
491 AccessibleTableRowDescriptionChangedEvent_getDescriptionString (const AccessibleEvent *e)
497 AccessibleTableColumnDescriptionChangedEvent_getDescriptionString (const AccessibleEvent *e)
503 AccessibleDescriptionChangedEvent_getDescriptionString (const AccessibleEvent *e)
509 cspi_event_compare (gconstpointer p1, gconstpointer p2)
511 const InternalEvent *e1 = p1, *e2 = p2;
512 return (gint) ((long) e2->id - (long) e1->id);
515 static InternalEvent *
516 cspi_internal_event_lookup (const InternalEvent *e)
518 InternalEvent *internal = NULL;
520 g_slist_find_custom (_cspi_event_queue, e, cspi_event_compare);
526 static const InternalEvent *
527 cspi_internal_event_check (const AccessibleEvent *e)
529 InternalEvent *internal = (InternalEvent *) e;
530 if (internal->magic == SPI_INTERNAL_EVENT_MAGIC)
536 static InternalEvent *
537 cspi_internal_event_add (const InternalEvent *e)
539 _cspi_event_queue = g_slist_prepend (_cspi_event_queue, (gpointer) e);
540 return (InternalEvent *) e;
544 cspi_internal_event_remove (const InternalEvent *e)
546 GSList *link = g_slist_find_custom (_cspi_event_queue, e, cspi_event_compare);
548 _cspi_event_queue = g_slist_remove_link (_cspi_event_queue, link);
552 AccessibleNameChangedEvent_getNameString (const AccessibleEvent *e)
558 AccessibleEvent_ref (const AccessibleEvent *e)
560 const InternalEvent *private = cspi_internal_event_check (e);
563 InternalEvent *event = cspi_internal_event_lookup (private);
565 * put event in the cache if it's not there already,
566 * and increment refcount
570 event = cspi_internal_event_add (private);
580 AccessibleEvent_unref (const AccessibleEvent *e)
582 const InternalEvent *private = cspi_internal_event_check (e);
583 /* decrement refcount and remove if appropriate */
586 InternalEvent *event = cspi_internal_event_lookup (private);
590 if (event->ref_count < 1)
591 cspi_internal_event_remove (event);