2 * AT-SPI - Assistive Technology Service Provider Interface
3 * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
5 * Copyright 2008, Codethink Ltd.
6 * Copyright 2001, 2002, 2003 Sun Microsystems Inc.,
7 * Copyright 2001, 2002, 2003 Ximian, Inc.
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Library General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Library General Public License for more details.
19 * You should have received a copy of the GNU Library General Public
20 * License along with this library; if not, write to the
21 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 * Boston, MA 02111-1307, USA.
27 #include "accessible.h"
31 extern SpiAppData *this_app;
33 static GArray *listener_ids = NULL;
35 static gint atk_bridge_key_event_listener_id;
36 static gint atk_bridge_focus_tracker_id;
39 /*---------------------------------------------------------------------------*/
41 #define ITF_EVENT_OBJECT "org.freedesktop.atspi.Event.Object"
42 #define ITF_EVENT_WINDOW "org.freedesktop.atspi.Event.Window"
43 #define ITF_EVENT_DOCUMENT "org.freedekstop.atspi.Event.Document"
44 #define ITF_EVENT_FOCUS "org.freedesktop.atspi.Event.Focus"
46 /*---------------------------------------------------------------------------*/
49 Accessibility_DeviceEventController_notifyListenersSync(const Accessibility_DeviceEvent *key_event)
53 dbus_bool_t consumed = FALSE;
56 dbus_message_new_method_call(SPI_DBUS_NAME_REGISTRY,
57 SPI_DBUS_PATH_REGISTRY,
58 SPI_DBUS_INTERFACE_DEC,
59 "notifyListenersSync");
61 dbus_error_init(&error);
62 if (spi_dbus_marshal_deviceEvent(message, key_event))
64 DBusMessage *reply = dbus_connection_send_with_reply_and_block(this_app->droute.bus, message, 1000, &error);
68 dbus_error_init(&error);
69 dbus_message_get_args(reply, &error, DBUS_TYPE_BOOLEAN, &consumed, DBUS_TYPE_INVALID);
70 dbus_message_unref(reply);
73 dbus_message_unref(message);
78 spi_init_keystroke_from_atk_key_event (Accessibility_DeviceEvent *keystroke,
79 AtkKeyEventStruct *event)
81 keystroke->id = (dbus_int32_t) event->keyval;
82 keystroke->hw_code = (dbus_int16_t) event->keycode;
83 keystroke->timestamp = (dbus_uint32_t) event->timestamp;
84 keystroke->modifiers = (dbus_uint16_t) (event->state & 0xFFFF);
89 keystroke->event_string = g_strdup (event->string);
90 c = g_utf8_get_char_validated (event->string, -1);
91 if (c > 0 && g_unichar_isprint (c))
92 keystroke->is_text = TRUE;
94 keystroke->is_text = FALSE;
98 keystroke->event_string = g_strdup ("");
99 keystroke->is_text = FALSE;
103 case (ATK_KEY_EVENT_PRESS):
104 keystroke->type = Accessibility_KEY_PRESSED_EVENT;
106 case (ATK_KEY_EVENT_RELEASE):
107 keystroke->type = Accessibility_KEY_RELEASED_EVENT;
114 g_print ("key_event type %d; val=%d code=%d modifiers=%x name=%s is_text=%d, time=%lx\n",
115 (int) keystroke->type, (int) keystroke->id, (int) keystroke->hw_code,
116 (int) keystroke->modifiers,
117 keystroke->event_string, (int) keystroke->is_text, (unsigned long) keystroke->timestamp);
123 spi_atk_bridge_key_listener (AtkKeyEventStruct *event, gpointer data)
126 Accessibility_DeviceEvent key_event;
128 spi_init_keystroke_from_atk_key_event (&key_event, event);
130 result = Accessibility_DeviceEventController_notifyListenersSync (&key_event);
132 if (key_event.event_string) g_free (key_event.event_string);
138 /*---------------------------------------------------------------------------*/
141 * Emits an AT-SPI event.
142 * AT-SPI events names are split into three parts:
144 * This is mapped onto D-Bus events as:
145 * D-Bus Interface:Signal Name:Detail argument
147 * Marshals a basic type into the 'any_data' attribute of
152 * This is a rather annoying function needed to replace
153 * NULL values of strings with the empty string. Null string
154 * values can be created by the atk_object_get_name or text selection
157 provide_defaults(const gint type,
162 case DBUS_TYPE_STRING:
163 case DBUS_TYPE_OBJECT_PATH:
174 /* TODO Should we bother emiting events for objects that have not yet
175 * been added to the tree?
177 * This gets difficult. Its entirely possible that an Accessible would have been
178 * added to the tree, but not yet reached the clients.
179 * In this case we would be wrongly surpressing an event.
182 emit(AtkObject *accessible,
186 dbus_int32_t detail1,
187 dbus_int32_t detail2,
192 DBusMessageIter iter, sub;
193 gchar *path, *cname, *t;
195 if (!klass) klass = "";
196 if (!major) major = "";
197 if (!minor) minor = "";
200 * This is very annoying, but as '-' isn't a legal signal
201 * name in D-Bus (Why not??!?) The names need converting
202 * on this side, and again on the client side.
204 cname = g_strdup(major);
205 while ((t = strchr(cname, '-')) != NULL) *t = '_';
207 path = atk_dbus_get_path(accessible);
208 sig = dbus_message_new_signal(path, klass, cname);
212 dbus_message_iter_init_append(sig, &iter);
214 dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &minor);
215 dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &detail1);
216 dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &detail2);
218 dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, type, &sub);
220 * I need to convert the string signature to an integer type signature.
221 * DBUS_TYPE_INT32 is defined as 'i' whereas the string is "i".
222 * I should just be able to cast the first character of the string to an
225 val = provide_defaults((int) *type, val);
226 dbus_message_iter_append_basic(&sub, (int) *type, &val);
227 dbus_message_iter_close_container(&iter, &sub);
229 dbus_connection_send(this_app->droute.bus, sig, NULL);
230 dbus_message_unref(sig);
233 /*---------------------------------------------------------------------------*/
236 * Emits an AT-SPI event, marshalling a BoundingBox structure into the
237 * 'any_data' variant of the event.
240 emit_rect(AtkObject *accessible,
247 DBusMessageIter iter, variant, sub;
248 gchar *path, *cname, *t;
249 dbus_int32_t dummy = 0;
251 if (!klass) klass = "";
252 if (!major) major = "";
253 if (!minor) minor = "";
256 * This is very annoying, but as '-' isn't a legal signal
257 * name in D-Bus (Why not??!?) The names need converting
258 * on this side, and again on the client side.
260 cname = g_strdup(major);
261 while ((t = strchr(cname, '-')) != NULL) *t = '_';
263 path = atk_dbus_get_path(accessible);
264 sig = dbus_message_new_signal(path, klass, cname);
268 dbus_message_iter_init_append (sig, &iter);
269 dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &minor);
270 dbus_message_iter_append_basic (&iter, DBUS_TYPE_INT32, &dummy);
271 dbus_message_iter_append_basic (&iter, DBUS_TYPE_INT32, &dummy);
273 dbus_message_iter_open_container (&iter, DBUS_TYPE_VARIANT, "(iiii)", &variant);
274 dbus_message_iter_open_container (&variant, DBUS_TYPE_STRUCT, NULL, &sub);
275 dbus_message_iter_append_basic (&sub, DBUS_TYPE_INT32, &(rect->x));
276 dbus_message_iter_append_basic (&sub, DBUS_TYPE_INT32, &(rect->y));
277 dbus_message_iter_append_basic (&sub, DBUS_TYPE_INT32, &(rect->width));
278 dbus_message_iter_append_basic (&sub, DBUS_TYPE_INT32, &(rect->height));
279 dbus_message_iter_close_container (&variant, &sub);
280 dbus_message_iter_close_container (&iter, &variant);
282 dbus_connection_send(this_app->droute.bus, sig, NULL);
285 /*---------------------------------------------------------------------------*/
288 * The tree update listener handles the following Atk signals:
290 * Gtk:AtkObject:property-change
292 * With the folowing property names:
295 * accessible-description
298 * It updates the server side accessible-object database, which
299 * will then syncronize with the client-side accessible cache.
303 tree_update_listener (GSignalInvocationHint *signal_hint,
304 guint n_param_values,
305 const GValue *param_values,
308 AtkObject *accessible;
309 AtkPropertyValues *values;
310 const gchar *pname = NULL;
312 accessible = g_value_get_object (¶m_values[0]);
313 values = (AtkPropertyValues*) g_value_get_pointer (¶m_values[1]);
315 pname = values[0].property_name;
317 if (strcmp (pname, "accessible-name") == 0)
319 atk_dbus_notify_change(accessible);
321 else if (strcmp (pname, "accessible-description") == 0)
323 atk_dbus_notify_change(accessible);
325 else if (strcmp (pname, "accessible-parent") == 0)
327 atk_dbus_notify_change(accessible);
333 * Handles the ATK signal 'Gtk:AtkObject:children-changed'.
335 * It updates the server side accessible-object database, which
336 * will then syncronize with the client-side accessible cache.
340 tree_update_children_listener (GSignalInvocationHint *signal_hint,
341 guint n_param_values,
342 const GValue *param_values,
345 AtkObject *accessible;
347 accessible = g_value_get_object (¶m_values[0]);
348 atk_dbus_register_subtree(accessible);
352 /*---------------------------------------------------------------------------*/
355 * The focus listener handles the ATK 'focus' signal and forwards it
356 * as the AT-SPI event, 'focus:'
359 focus_tracker (AtkObject *accessible)
361 emit(accessible, ITF_EVENT_FOCUS, "focus", "", 0, 0, DBUS_TYPE_INT32_AS_STRING, 0);
364 /*---------------------------------------------------------------------------*/
366 #define PCHANGE "property-change"
369 * This handler handles the following ATK signals and
370 * converts them to AT-SPI events:
372 * Gtk:AtkObject:property-change -> object:property-change:(property-name)
374 * The property-name is part of the ATK property-change signal.
377 property_event_listener (GSignalInvocationHint *signal_hint,
378 guint n_param_values,
379 const GValue *param_values,
382 AtkObject *accessible;
383 AtkPropertyValues *values;
385 const gchar *pname = NULL;
391 accessible = g_value_get_object (¶m_values[0]);
392 values = (AtkPropertyValues*) g_value_get_pointer (¶m_values[1]);
394 pname = values[0].property_name;
396 /* TODO Could improve this control statement by matching
397 * on only the end of the signal names,
399 if (strcmp (pname, "accessible-table-summary") == 0)
401 otemp = atk_table_get_summary(ATK_TABLE (accessible));
402 stemp = atk_dbus_get_path(otemp);
403 emit(accessible, ITF_EVENT_OBJECT, PCHANGE, pname, 0, 0, DBUS_TYPE_OBJECT_PATH_AS_STRING, stemp);
405 else if (strcmp (pname, "accessible-table-column-header") == 0)
407 i = g_value_get_int (&(values->new_value));
408 otemp = atk_table_get_column_header(ATK_TABLE (accessible), i);
409 stemp = atk_dbus_get_path(otemp);
410 emit(accessible, ITF_EVENT_OBJECT, PCHANGE, pname, 0, 0, DBUS_TYPE_OBJECT_PATH_AS_STRING, stemp);
412 else if (strcmp (pname, "accessible-table-row-header") == 0)
414 i = g_value_get_int (&(values->new_value));
415 otemp = atk_table_get_row_header(ATK_TABLE (accessible), i);
416 stemp = atk_dbus_get_path(otemp);
417 emit(accessible, ITF_EVENT_OBJECT, PCHANGE, pname, 0, 0, DBUS_TYPE_OBJECT_PATH_AS_STRING, stemp);
419 else if (strcmp (pname, "accessible-table-row-description") == 0)
421 i = g_value_get_int (&(values->new_value));
422 stemp = atk_table_get_row_description(ATK_TABLE (accessible), i);
423 emit(accessible, ITF_EVENT_OBJECT, PCHANGE, pname, 0, 0, DBUS_TYPE_STRING_AS_STRING, stemp);
425 else if (strcmp (pname, "accessible-table-column-description") == 0)
427 i = g_value_get_int (&(values->new_value));
428 stemp = atk_table_get_column_description(ATK_TABLE (accessible), i);
429 emit(accessible, ITF_EVENT_OBJECT, PCHANGE, pname, 0, 0, DBUS_TYPE_STRING_AS_STRING, stemp);
431 else if (strcmp (pname, "accessible-table-caption-object") == 0)
433 otemp = atk_table_get_caption(ATK_TABLE(accessible));
434 stemp = atk_object_get_name(otemp);
435 emit(accessible, ITF_EVENT_OBJECT, PCHANGE, pname, 0, 0, DBUS_TYPE_STRING_AS_STRING, stemp);
439 emit(accessible, ITF_EVENT_OBJECT, PCHANGE, pname, 0, 0, DBUS_TYPE_INT32_AS_STRING, 0);
444 /*---------------------------------------------------------------------------*/
446 #define STATE_CHANGED "state-changed"
449 * The state event listener handles 'Gtk:AtkObject:state-change' ATK signals
450 * and forwards them as object:state-changed:(param-name) AT-SPI events. Where
451 * the param-name is part of the ATK state-change signal.
454 state_event_listener (GSignalInvocationHint *signal_hint,
455 guint n_param_values,
456 const GValue *param_values,
459 AtkObject *accessible;
463 accessible = ATK_OBJECT(g_value_get_object (¶m_values[0]));
464 pname = g_strdup (g_value_get_string (¶m_values[1]));
466 /* TODO - Possibly ignore a change to the 'defunct' state.
467 * This is because without reference counting defunct objects should be removed.
469 detail1 = (g_value_get_boolean (¶m_values[2])) ? 1 : 0;
470 emit(accessible, ITF_EVENT_OBJECT, STATE_CHANGED, pname, detail1, 0, DBUS_TYPE_INT32_AS_STRING, 0);
475 /*---------------------------------------------------------------------------*/
478 * The window event listener handles the following ATK signals and forwards
479 * them as AT-SPI events:
481 * window:create -> window:create
482 * window:destroy -> window:destroy
483 * window:minimize -> window:minimize
484 * window:maximize -> window:maximize
485 * window:activate -> window:activate
486 * window:deactivate -> window:deactivate
489 window_event_listener (GSignalInvocationHint *signal_hint,
490 guint n_param_values,
491 const GValue *param_values,
494 AtkObject *accessible;
495 GSignalQuery signal_query;
496 const gchar *name, *s;
498 g_signal_query (signal_hint->signal_id, &signal_query);
499 name = signal_query.signal_name;
501 accessible = ATK_OBJECT(g_value_get_object(¶m_values[0]));
502 s = atk_object_get_name (accessible);
503 emit(accessible, ITF_EVENT_WINDOW, name, "", 0, 0, DBUS_TYPE_STRING_AS_STRING, s);
508 /*---------------------------------------------------------------------------*/
511 * The document event listener handles the following ATK signals
512 * and converts them to AT-SPI events:
514 * Gtk:AtkDocument:load-complete -> document:load-complete
515 * Gtk:AtkDocument:load-stopped -> document:load-stopped
516 * Gtk:AtkDocument:reload -> document:reload
519 document_event_listener (GSignalInvocationHint *signal_hint,
520 guint n_param_values,
521 const GValue *param_values,
524 AtkObject *accessible;
525 GSignalQuery signal_query;
526 const gchar *name, *s;
528 g_signal_query (signal_hint->signal_id, &signal_query);
529 name = signal_query.signal_name;
531 accessible = ATK_OBJECT(g_value_get_object(¶m_values[0]));
532 s = atk_object_get_name (accessible);
533 emit(accessible, ITF_EVENT_DOCUMENT, name, "", 0, 0, DBUS_TYPE_STRING_AS_STRING, s);
538 /*---------------------------------------------------------------------------*/
541 * Signal handler for "Gtk:AtkComponent:bounds-changed". Converts
542 * this to an AT-SPI event - "object:bounds-changed".
545 bounds_event_listener (GSignalInvocationHint *signal_hint,
546 guint n_param_values,
547 const GValue *param_values,
550 AtkObject *accessible;
551 AtkRectangle *atk_rect;
552 GSignalQuery signal_query;
553 const gchar *name, *s;
555 g_signal_query (signal_hint->signal_id, &signal_query);
556 name = signal_query.signal_name;
558 accessible = ATK_OBJECT(g_value_get_object(¶m_values[0]));
560 if (G_VALUE_HOLDS_BOXED (param_values + 1))
561 atk_rect = g_value_get_boxed (param_values + 1);
563 emit_rect(accessible, ITF_EVENT_OBJECT, name, "", atk_rect);
567 /*---------------------------------------------------------------------------*/
570 * Handles the ATK signal 'Gtk:AtkObject:active-descendant-changed' and
571 * converts it to the AT-SPI signal - 'object:active-descendant-changed'.
575 active_descendant_event_listener (GSignalInvocationHint *signal_hint,
576 guint n_param_values,
577 const GValue *param_values,
580 AtkObject *accessible;
582 GSignalQuery signal_query;
583 const gchar *name, *minor;
587 g_signal_query (signal_hint->signal_id, &signal_query);
588 name = signal_query.signal_name;
590 accessible = ATK_OBJECT(g_value_get_object(¶m_values[0]));
591 child = ATK_OBJECT(g_value_get_pointer (¶m_values[1]));
592 g_return_val_if_fail (ATK_IS_OBJECT (child), TRUE);
593 minor = g_quark_to_string (signal_hint->detail);
595 detail1 = atk_object_get_index_in_parent (child);
596 s = atk_dbus_get_path(child);
598 emit(accessible, ITF_EVENT_OBJECT, name, "", detail1, 0, DBUS_TYPE_OBJECT_PATH_AS_STRING, s);
603 /*---------------------------------------------------------------------------*/
606 * Handles the ATK signal 'Gtk:AtkHypertext:link-selected' and
607 * converts it to the AT-SPI signal - 'object:link-selected'
611 link_selected_event_listener (GSignalInvocationHint *signal_hint,
612 guint n_param_values,
613 const GValue *param_values,
616 AtkObject *accessible;
617 GSignalQuery signal_query;
618 const gchar *name, *minor;
621 g_signal_query (signal_hint->signal_id, &signal_query);
622 name = signal_query.signal_name;
624 accessible = ATK_OBJECT(g_value_get_object(¶m_values[0]));
625 minor = g_quark_to_string (signal_hint->detail);
627 if (G_VALUE_TYPE (¶m_values[1]) == G_TYPE_INT)
628 detail1 = g_value_get_int (¶m_values[1]);
630 emit(accessible, ITF_EVENT_OBJECT, name, minor, detail1, 0, DBUS_TYPE_INT32_AS_STRING, 0);
634 /*---------------------------------------------------------------------------*/
637 * Handles the ATK signal 'Gtk:AtkText:text-changed' and
638 * converts it to the AT-SPI signal - 'object:text-changed'
642 text_changed_event_listener (GSignalInvocationHint *signal_hint,
643 guint n_param_values,
644 const GValue *param_values,
647 AtkObject *accessible;
648 GSignalQuery signal_query;
649 const gchar *name, *minor;
651 gint detail1, detail2;
653 g_signal_query (signal_hint->signal_id, &signal_query);
654 name = signal_query.signal_name;
656 accessible = ATK_OBJECT(g_value_get_object(¶m_values[0]));
657 minor = g_quark_to_string (signal_hint->detail);
659 if (G_VALUE_TYPE (¶m_values[1]) == G_TYPE_INT)
660 detail1 = g_value_get_int (¶m_values[1]);
662 if (G_VALUE_TYPE (¶m_values[2]) == G_TYPE_INT)
663 detail2 = g_value_get_int (¶m_values[2]);
665 selected = atk_text_get_text (ATK_TEXT (accessible), detail1, detail1+detail2);
667 emit(accessible, ITF_EVENT_OBJECT, name, minor, detail1, detail2, DBUS_TYPE_STRING_AS_STRING, selected);
671 /*---------------------------------------------------------------------------*/
674 * Handles the ATK signal 'Gtk:AtkText:text-selection-changed' and
675 * converts it to the AT-SPI signal - 'object:text-selection-changed'
679 text_selection_changed_event_listener (GSignalInvocationHint *signal_hint,
680 guint n_param_values,
681 const GValue *param_values,
684 AtkObject *accessible;
685 GSignalQuery signal_query;
686 const gchar *name, *minor;
687 gint detail1, detail2;
689 g_signal_query (signal_hint->signal_id, &signal_query);
690 name = signal_query.signal_name;
692 accessible = ATK_OBJECT(g_value_get_object(¶m_values[0]));
693 minor = g_quark_to_string (signal_hint->detail);
695 if (G_VALUE_TYPE (¶m_values[1]) == G_TYPE_INT)
696 detail1 = g_value_get_int (¶m_values[1]);
698 if (G_VALUE_TYPE (¶m_values[2]) == G_TYPE_INT)
699 detail2 = g_value_get_int (¶m_values[2]);
701 emit(accessible, ITF_EVENT_OBJECT, name, minor, detail1, detail2, DBUS_TYPE_STRING_AS_STRING, "");
705 /*---------------------------------------------------------------------------*/
708 * Generic signal converter and forwarder.
710 * Klass (Interface) org.freedesktop.atspi.Event.Object
711 * Major is the signal name.
718 generic_event_listener (GSignalInvocationHint *signal_hint,
719 guint n_param_values,
720 const GValue *param_values,
723 AtkObject *accessible;
724 GSignalQuery signal_query;
727 g_signal_query (signal_hint->signal_id, &signal_query);
728 name = signal_query.signal_name;
730 accessible = ATK_OBJECT(g_value_get_object(¶m_values[0]));
731 emit(accessible, ITF_EVENT_OBJECT, name, "", 0, 0, DBUS_TYPE_INT32_AS_STRING, 0);
735 /*---------------------------------------------------------------------------*/
738 * Registers the provided function as a handler for the given signal name
739 * and stores the signal id returned so that the function may be
740 * de-registered later.
743 add_signal_listener (GSignalEmissionHook listener, const char *signal_name)
747 id = atk_add_global_event_listener (listener, signal_name);
748 g_array_append_val (listener_ids, id);
752 * Initialization for the signal handlers.
754 * Registers all required signal handlers.
757 spi_atk_register_event_listeners (void)
760 * Kludge to make sure the Atk interface types are registered, otherwise
761 * the AtkText signal handlers below won't get registered
763 GObject *ao = g_object_new (ATK_TYPE_OBJECT, NULL);
764 AtkObject *bo = atk_no_op_object_new (ao);
766 g_object_unref (G_OBJECT (bo));
769 /* Register for focus event notifications, and register app with central registry */
770 listener_ids = g_array_sized_new (FALSE, TRUE, sizeof (guint), 16);
772 atk_bridge_focus_tracker_id = atk_add_focus_tracker (focus_tracker);
774 add_signal_listener (tree_update_listener, "Gtk:AtkObject:property-change");
775 add_signal_listener (tree_update_children_listener, "Gtk:AtkObject:children-changed");
777 add_signal_listener (property_event_listener, "Gtk:AtkObject:property-change");
778 add_signal_listener (window_event_listener, "window:create");
779 add_signal_listener (window_event_listener, "window:destroy");
780 add_signal_listener (window_event_listener, "window:minimize");
781 add_signal_listener (window_event_listener, "window:maximize");
782 add_signal_listener (window_event_listener, "window:restore");
783 add_signal_listener (window_event_listener, "window:activate");
784 add_signal_listener (window_event_listener, "window:deactivate");
785 add_signal_listener (document_event_listener, "Gtk:AtkDocument:load-complete");
786 add_signal_listener (document_event_listener, "Gtk:AtkDocument:reload");
787 add_signal_listener (document_event_listener, "Gtk:AtkDocument:load-stopped");
788 add_signal_listener (state_event_listener, "Gtk:AtkObject:state-change");
789 add_signal_listener (active_descendant_event_listener, "Gtk:AtkObject:active-descendant-changed");
790 add_signal_listener (bounds_event_listener, "Gtk:AtkComponent:bounds-changed");
791 add_signal_listener (text_selection_changed_event_listener, "Gtk:AtkText:text-selection-changed");
792 add_signal_listener (text_changed_event_listener, "Gtk:AtkText:text-changed");
793 add_signal_listener (link_selected_event_listener, "Gtk:AtkHypertext:link-selected");
794 add_signal_listener (generic_event_listener, "Gtk:AtkObject:visible-data-changed");
795 add_signal_listener (generic_event_listener, "Gtk:AtkSelection:selection-changed");
796 add_signal_listener (generic_event_listener, "Gtk:AtkText:text-caret-moved");
797 add_signal_listener (generic_event_listener, "Gtk:AtkTable:row-inserted");
798 add_signal_listener (generic_event_listener, "Gtk:AtkTable:row-reordered");
799 add_signal_listener (generic_event_listener, "Gtk:AtkTable:row-deleted");
800 add_signal_listener (generic_event_listener, "Gtk:AtkTable:column-inserted");
801 add_signal_listener (generic_event_listener, "Gtk:AtkTable:column-reordered");
802 add_signal_listener (generic_event_listener, "Gtk:AtkTable:column-deleted");
803 add_signal_listener (generic_event_listener, "Gtk:AtkTable:model-changed");
806 * May add the following listeners to implement preemptive key listening for GTK+
808 * atk_add_global_event_listener (spi_atk_bridge_widgetkey_listener, "Gtk:GtkWidget:key-press-event");
809 * atk_add_global_event_listener (spi_atk_bridge_widgetkey_listener, "Gtk:GtkWidget:key-release-event");
811 atk_bridge_key_event_listener_id = atk_add_key_event_listener (spi_atk_bridge_key_listener, NULL);
814 /*---------------------------------------------------------------------------*/
817 * De-registers all ATK signal handlers.
820 spi_atk_deregister_event_listeners (void)
823 GArray *ids = listener_ids;
826 if (atk_bridge_focus_tracker_id)
827 atk_remove_focus_tracker (atk_bridge_focus_tracker_id);
829 for (i = 0; ids && i < ids->len; i++)
831 atk_remove_global_event_listener (g_array_index (ids, guint, i));
834 if (atk_bridge_key_event_listener_id)
835 atk_remove_key_event_listener (atk_bridge_key_event_listener_id);
838 /*---------------------------------------------------------------------------*/
841 * TODO This function seems out of place here.
843 * Emits fake deactivate signals on all top-level windows.
844 * Used when shutting down AT-SPI, ensuring that all
845 * windows have been removed on the client side.
848 spi_atk_tidy_windows (void)
854 root = atk_get_root ();
855 n_children = atk_object_get_n_accessible_children (root);
856 for (i = 0; i < n_children; i++)
859 AtkStateSet *stateset;
862 child = atk_object_ref_accessible_child (root, i);
863 stateset = atk_object_ref_state_set (child);
865 name = atk_object_get_name (child);
866 if (atk_state_set_contains_state (stateset, ATK_STATE_ACTIVE))
868 emit(child, ITF_EVENT_WINDOW, "deactivate", NULL, 0, 0, DBUS_TYPE_STRING_AS_STRING, name);
870 g_object_unref (stateset);
872 emit(child, ITF_EVENT_WINDOW, "destroy", NULL, 0, 0, DBUS_TYPE_STRING_AS_STRING, name);
873 g_object_unref (child);
877 /*END------------------------------------------------------------------------*/