2 * AT-SPI - Assistive Technology Service Provider Interface
3 * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
5 * Copyright 2001, 2002, 2003 Sun Microsystems Inc.,
6 * Copyright 2001, 2002, 2003 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 CORBA_string_dup (* (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 cspi_internal_event_get_rect (const InternalEvent *e)
372 g_return_val_if_fail (e, NULL);
373 g_return_val_if_fail (e->data, NULL);
374 any = (CORBA_any *) e->data;
375 if (CORBA_TypeCode_equivalent (any->_type, TC_Accessibility_BoundingBox, NULL))
377 SPIRect *rect = g_new (SPIRect, 1);
378 Accessibility_BoundingBox *bounds = (Accessibility_BoundingBox *) any->_value;
381 rect->width = bounds->width;
382 rect->height = bounds->height;
387 #ifdef EVENT_CONTEXT_DEBUG
388 fprintf (stderr, "requested string, TC is not TC_Accessible_RectBounds! (%u)\n",
389 (unsigned) any->_type);
396 * AccessibleTextChangedEvent_getChangeString:
397 * @e: a pointer to the #AccessibleEvent being queried.
399 * Queries an #AccessibleEvent of type "object:text-changed",
400 * returning the text inserted or deleted.
402 * Returns: a UTF-8 text string indicating the text inserted,
403 * deleted, or substituted by this event.
406 AccessibleTextChangedEvent_getChangeString (const AccessibleEvent *e)
408 const InternalEvent *foo = (InternalEvent *) e;
409 /* TODO: check the event type. */
410 return cspi_internal_event_get_text (foo);
414 * AccessibleTextSelectionChangedEvent_getSelectionString:
415 * @e: a pointer to the #AccessibleEvent being queried.
417 * Queries an #AccessibleEvent of type "object:text-selection-changed",
418 * returning the newly added, removed, or modified selection string.
420 * Returns: a UTF-8 text string indicating the recently changed selection.
423 AccessibleTextSelectionChangedEvent_getSelectionString (const AccessibleEvent *e)
425 const InternalEvent *foo = (InternalEvent *) e;
426 /* TODO: check the event type. */
427 return cspi_internal_event_get_text (foo);
431 * AccessibleWindowEvent_getTitleString:
432 * @e: a pointer to the #AccessibleEvent being queried.
434 * Queries an #AccessibleEvent of type "window:",
435 * returning the window title.
437 * Returns: a UTF-8 text string representing the title of the
438 * recently changed window.
441 AccessibleWindowEvent_getTitleString (const AccessibleEvent *e)
443 const InternalEvent *foo = (InternalEvent *) e;
444 /* TODO: check the event type. */
445 return cspi_internal_event_get_text (foo);
449 * AccessibleChildChangedEvent_getChildAccessible:
450 * @e: a pointer to the #AccessibleEvent being queried.
452 * Queries an #AccessibleEvent of type "object:children_changed"
453 * to get a reference to the changed #Accessible.
454 * Note that context #Accessibles are not guaranteed to outlive
455 * event delivery, in which case this call may return %NULL
456 * even if the object existed at the time of dispatch.
458 * Returns: the context #Accessible for the event, or %NULL if
459 * there is no longer a valid context #Accessible
460 * object for the event.
463 AccessibleChildChangedEvent_getChildAccessible (const AccessibleEvent *e)
465 const InternalEvent *foo = (InternalEvent *) e;
466 return (Accessible *) cspi_internal_event_get_object (foo);
470 * AccessibleParentChangedEvent_getParentAccessible:
471 * @e: a pointer to the #AccessibleEvent being queried.
473 * Queries an #AccessibleEvent of type "object:property-change:accessible-parent"
474 * to get a reference to the changed #Accessible.
475 * Note that context #Accessibles are not guaranteed to outlive
476 * event delivery, in which case this call may return %NULL
477 * even if the object existed at the time of dispatch.
479 * Returns: an #Accessible pointer representing the new parent object.
482 AccessibleParentChangedEvent_getParentAccessible (const AccessibleEvent *e)
484 const InternalEvent *foo = (InternalEvent *) e;
485 return (Accessible *) cspi_internal_event_get_object (foo);
489 * AccessibleActiveDescendantChangedEvent_getActiveDescendant:
490 * @e: a pointer to the #AccessibleEvent being queried.
492 * Queries an #AccessibleEvent of type "object:active-descendant-changed"
493 * to get a reference to the changed #Accessible.
494 * Note that context #Accessibles are not guaranteed to outlive
495 * event delivery, in which case this call may return %NULL
496 * even if the object existed at the time of dispatch.
498 * Returns: an #Accessible pointer representing the new active descendant.
501 AccessibleActiveDescendantChangedEvent_getActiveDescendant (const AccessibleEvent *e)
503 const InternalEvent *foo = (InternalEvent *) e;
504 return (Accessible *) cspi_internal_event_get_object (foo);
508 * AccessibleTableSummaryChangedEvent_getSummaryAccessible:
509 * @e: a pointer to the #AccessibleEvent being queried.
511 * Queries an #AccessibleEvent of type "object:property-changed:accessible-table-summary"
512 * to get a reference to the changed #Accessible.
513 * Note that context #Accessibles are not guaranteed to outlive
514 * event delivery, in which case this call may return %NULL
515 * even if the object existed at the time of dispatch.
517 * Returns: an #Accessible pointer representing the new table summary.
520 AccessibleTableSummaryChangedEvent_getSummaryAccessible (const AccessibleEvent *e)
522 const InternalEvent *foo = (InternalEvent *) e;
523 return (Accessible *) cspi_internal_event_get_object (foo);
527 * AccessibleTableHeaderChangedEvent_getHeaderAccessible:
528 * @e: a pointer to the #AccessibleEvent being queried.
530 * Queries an #AccessibleEvent of type
531 * "object:property-changed:accessible-table-row-header" or
532 * "object:property-changed:accessible-table-column-header"
533 * to get a reference to the changed #Accessible.
534 * Note that context #Accessibles are not guaranteed to outlive
535 * event delivery, in which case this call may return %NULL
536 * even if the object existed at the time of dispatch.
538 * Returns: an #Accessible pointer representing the new table header.
541 AccessibleTableHeaderChangedEvent_getHeaderAccessible (const AccessibleEvent *e)
543 const InternalEvent *foo = (InternalEvent *) e;
544 return (Accessible *) cspi_internal_event_get_object (foo);
549 * AccessibleTableCaptionChangedEvent_getCaptionString:
550 * @e: a pointer to the #AccessibleEvent being queried.
552 * Queries an #AccessibleEvent of type
553 * "object:property-changed:accessible-table-caption-object"
554 * returning the text in the caption, if present.
556 * Returns: a UTF-8 text string indicating the text in the caption.
559 AccessibleTableCaptionChangedEvent_getCaptionString (const AccessibleEvent *e)
561 const InternalEvent *foo = (InternalEvent *) e;
562 /* TODO: check the event type. */
563 return cspi_internal_event_get_text (foo);
567 * AccessibleTableRowDescriptionChangedEvent_getDescriptionString:
568 * @e: a pointer to the #AccessibleEvent being queried.
570 * Queries an #AccessibleEvent of type
571 * "object:property-changed:accessible-table-row-description"
572 * returning the new table row description.
574 * Returns: a UTF-8 text string representing the recently changed
575 * table row description
578 AccessibleTableRowDescriptionChangedEvent_getDescriptionString (const AccessibleEvent *e)
580 const InternalEvent *foo = (InternalEvent *) e;
581 /* TODO: check the event type. */
582 return cspi_internal_event_get_text (foo);
586 * AccessibleTableColumnDescriptionChangedEvent_getDescriptionString:
587 * @e: a pointer to the #AccessibleEvent being queried.
589 * Queries an #AccessibleEvent of type
590 * "object:property-changed:accessible-table-column-description"
591 * returning the new table column description.
593 * Returns: a UTF-8 text string representing the recently changed
594 * table column description
597 AccessibleTableColumnDescriptionChangedEvent_getDescriptionString (const AccessibleEvent *e)
599 const InternalEvent *foo = (InternalEvent *) e;
600 /* TODO: check the event type. */
601 return cspi_internal_event_get_text (foo);
605 * AccessibleDescriptionChangedEvent_getDescriptionString:
606 * @e: a pointer to the #AccessibleEvent being queried.
608 * Queries an #AccessibleEvent of type
609 * "object:property-changed:accessible-description"
610 * returning the new description.
612 * Returns: a UTF-8 text string representing the recently changed
616 AccessibleDescriptionChangedEvent_getDescriptionString (const AccessibleEvent *e)
618 const InternalEvent *foo = (InternalEvent *) e;
619 /* TODO: check the event type. */
620 return cspi_internal_event_get_text (foo);
624 * AccessibleBoundsChangedEvent_getNewBounds:
625 * @e: a pointer to the #AccessibleEvent being queried.
627 * Queries an #AccessibleEvent of type "object:bounds-changed",
628 * returning a pointer to an SPIRect structure containing the
629 * new bounds, or NULL on error.
630 * The returned structure should be freed with SPI_freeRect when
631 * the caller has finished referencing it.
633 * Returns: a pointer to an SPIRect defining the new object bounds.
636 AccessibleBoundsChangedEvent_getNewBounds (const AccessibleEvent *e)
638 const InternalEvent *foo = (InternalEvent *) e;
639 /* TODO: check the event type. */
640 return cspi_internal_event_get_rect (foo);
644 cspi_event_compare (gconstpointer p1, gconstpointer p2)
646 const InternalEvent *e1 = p1, *e2 = p2;
647 return (gint) ((long) e2->id - (long) e1->id);
650 static InternalEvent *
651 cspi_internal_event_lookup (const InternalEvent *e)
653 InternalEvent *internal = NULL;
655 g_slist_find_custom (_cspi_event_queue, e, cspi_event_compare);
661 static const InternalEvent *
662 cspi_internal_event_check (const AccessibleEvent *e)
664 InternalEvent *internal = (InternalEvent *) e;
665 if (internal->magic == SPI_INTERNAL_EVENT_MAGIC)
671 static InternalEvent *
672 cspi_internal_event_add (const InternalEvent *e)
674 _cspi_event_queue = g_slist_prepend (_cspi_event_queue, (gpointer) e);
675 return (InternalEvent *) e;
679 cspi_internal_event_remove (const InternalEvent *e)
681 GSList *link = g_slist_find_custom (_cspi_event_queue, e, cspi_event_compare);
683 _cspi_event_queue = g_slist_remove_link (_cspi_event_queue, link);
687 * AccessibleNameChangedEvent_getNameString:
688 * @e: a pointer to the #AccessibleEvent being queried.
690 * Queries an #AccessibleEvent of type "object:property-change:accessible_name:",
691 * returning the name.
693 * Returns: a UTF-8 text string representing the name of the
694 * object which recently changed.
697 AccessibleNameChangedEvent_getNameString (const AccessibleEvent *e)
699 const InternalEvent *foo = (InternalEvent *) e;
700 return cspi_internal_event_get_text (foo);
704 * AccessibleEvent_ref:
705 * @e: a pointer to the #AccessibleEvent being referenced.
707 * Increments by 1 the reference count of the event
709 * Returns: TRUE if the function succeeded; FALSE if the pointer is not a
713 AccessibleEvent_ref (const AccessibleEvent *e)
715 const InternalEvent *private = cspi_internal_event_check (e);
718 InternalEvent *event = cspi_internal_event_lookup (private);
720 * put event in the cache if it's not there already,
721 * and increment refcount
725 event = cspi_internal_event_add (private);
735 * AccessibleEvent_unref:
736 * @e: a pointer to the #AccessibleEvent being referenced.
738 * Decrements by 1 the reference count of the event. The event is destroyed
739 * when the reference count recahes zero.
743 AccessibleEvent_unref (const AccessibleEvent *e)
745 const InternalEvent *private = cspi_internal_event_check (e);
746 /* decrement refcount and remove if appropriate */
749 InternalEvent *event = cspi_internal_event_lookup (private);
753 if (event->ref_count < 1)
755 cspi_internal_event_remove (event);
756 g_free ((gpointer)e->type);
757 Accessible_unref (e->source);
758 CORBA_free (event->data);
759 g_free ((gpointer)e);