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 *app_data;
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(app_data->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(app_data->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(app_data->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;
346 const gchar *detail = NULL;
348 gboolean child_needs_unref = FALSE;
350 if (signal_hint->detail)
351 detail = g_quark_to_string (signal_hint->detail);
353 accessible = g_value_get_object (¶m_values[0]);
354 if (!strcmp (detail, "add"))
357 int index = g_value_get_uint (param_values + 1);
358 child = g_value_get_pointer (param_values + 2);
359 if (ATK_IS_OBJECT (child))
360 g_object_ref (child);
362 child = atk_object_ref_accessible_child (accessible, index);
363 if (ATK_IS_OBJECT (child))
365 atk_dbus_register_subtree (child);
366 g_object_unref (child);
369 atk_dbus_register_subtree(accessible);
374 /*---------------------------------------------------------------------------*/
377 * The focus listener handles the ATK 'focus' signal and forwards it
378 * as the AT-SPI event, 'focus:'
381 focus_tracker (AtkObject *accessible)
383 emit(accessible, ITF_EVENT_FOCUS, "focus", "", 0, 0, DBUS_TYPE_INT32_AS_STRING, 0);
386 /*---------------------------------------------------------------------------*/
388 #define PCHANGE "property-change"
391 * This handler handles the following ATK signals and
392 * converts them to AT-SPI events:
394 * Gtk:AtkObject:property-change -> object:property-change:(property-name)
396 * The property-name is part of the ATK property-change signal.
399 property_event_listener (GSignalInvocationHint *signal_hint,
400 guint n_param_values,
401 const GValue *param_values,
404 AtkObject *accessible;
405 AtkPropertyValues *values;
407 const gchar *pname = NULL;
413 accessible = g_value_get_object (¶m_values[0]);
414 values = (AtkPropertyValues*) g_value_get_pointer (¶m_values[1]);
416 pname = values[0].property_name;
418 /* TODO Could improve this control statement by matching
419 * on only the end of the signal names,
421 if (strcmp (pname, "accessible-table-summary") == 0)
423 otemp = atk_table_get_summary(ATK_TABLE (accessible));
424 stemp = atk_dbus_get_path(otemp);
425 emit(accessible, ITF_EVENT_OBJECT, PCHANGE, pname, 0, 0, DBUS_TYPE_OBJECT_PATH_AS_STRING, stemp);
427 else if (strcmp (pname, "accessible-table-column-header") == 0)
429 i = g_value_get_int (&(values->new_value));
430 otemp = atk_table_get_column_header(ATK_TABLE (accessible), i);
431 stemp = atk_dbus_get_path(otemp);
432 emit(accessible, ITF_EVENT_OBJECT, PCHANGE, pname, 0, 0, DBUS_TYPE_OBJECT_PATH_AS_STRING, stemp);
434 else if (strcmp (pname, "accessible-table-row-header") == 0)
436 i = g_value_get_int (&(values->new_value));
437 otemp = atk_table_get_row_header(ATK_TABLE (accessible), i);
438 stemp = atk_dbus_get_path(otemp);
439 emit(accessible, ITF_EVENT_OBJECT, PCHANGE, pname, 0, 0, DBUS_TYPE_OBJECT_PATH_AS_STRING, stemp);
441 else if (strcmp (pname, "accessible-table-row-description") == 0)
443 i = g_value_get_int (&(values->new_value));
444 stemp = atk_table_get_row_description(ATK_TABLE (accessible), i);
445 emit(accessible, ITF_EVENT_OBJECT, PCHANGE, pname, 0, 0, DBUS_TYPE_STRING_AS_STRING, stemp);
447 else if (strcmp (pname, "accessible-table-column-description") == 0)
449 i = g_value_get_int (&(values->new_value));
450 stemp = atk_table_get_column_description(ATK_TABLE (accessible), i);
451 emit(accessible, ITF_EVENT_OBJECT, PCHANGE, pname, 0, 0, DBUS_TYPE_STRING_AS_STRING, stemp);
453 else if (strcmp (pname, "accessible-table-caption-object") == 0)
455 otemp = atk_table_get_caption(ATK_TABLE(accessible));
456 stemp = atk_object_get_name(otemp);
457 emit(accessible, ITF_EVENT_OBJECT, PCHANGE, pname, 0, 0, DBUS_TYPE_STRING_AS_STRING, stemp);
461 emit(accessible, ITF_EVENT_OBJECT, PCHANGE, pname, 0, 0, DBUS_TYPE_INT32_AS_STRING, 0);
466 /*---------------------------------------------------------------------------*/
468 #define STATE_CHANGED "state-changed"
471 * The state event listener handles 'Gtk:AtkObject:state-change' ATK signals
472 * and forwards them as object:state-changed:(param-name) AT-SPI events. Where
473 * the param-name is part of the ATK state-change signal.
476 state_event_listener (GSignalInvocationHint *signal_hint,
477 guint n_param_values,
478 const GValue *param_values,
481 AtkObject *accessible;
485 accessible = ATK_OBJECT(g_value_get_object (¶m_values[0]));
486 pname = g_strdup (g_value_get_string (¶m_values[1]));
488 /* TODO - Possibly ignore a change to the 'defunct' state.
489 * This is because without reference counting defunct objects should be removed.
491 detail1 = (g_value_get_boolean (¶m_values[2])) ? 1 : 0;
492 emit(accessible, ITF_EVENT_OBJECT, STATE_CHANGED, pname, detail1, 0, DBUS_TYPE_INT32_AS_STRING, 0);
497 /*---------------------------------------------------------------------------*/
500 * The window event listener handles the following ATK signals and forwards
501 * them as AT-SPI events:
503 * window:create -> window:create
504 * window:destroy -> window:destroy
505 * window:minimize -> window:minimize
506 * window:maximize -> window:maximize
507 * window:activate -> window:activate
508 * window:deactivate -> window:deactivate
511 window_event_listener (GSignalInvocationHint *signal_hint,
512 guint n_param_values,
513 const GValue *param_values,
516 AtkObject *accessible;
517 GSignalQuery signal_query;
518 const gchar *name, *s;
520 g_signal_query (signal_hint->signal_id, &signal_query);
521 name = signal_query.signal_name;
523 accessible = ATK_OBJECT(g_value_get_object(¶m_values[0]));
524 s = atk_object_get_name (accessible);
525 emit(accessible, ITF_EVENT_WINDOW, name, "", 0, 0, DBUS_TYPE_STRING_AS_STRING, s);
530 /*---------------------------------------------------------------------------*/
533 * The document event listener handles the following ATK signals
534 * and converts them to AT-SPI events:
536 * Gtk:AtkDocument:load-complete -> document:load-complete
537 * Gtk:AtkDocument:load-stopped -> document:load-stopped
538 * Gtk:AtkDocument:reload -> document:reload
541 document_event_listener (GSignalInvocationHint *signal_hint,
542 guint n_param_values,
543 const GValue *param_values,
546 AtkObject *accessible;
547 GSignalQuery signal_query;
548 const gchar *name, *s;
550 g_signal_query (signal_hint->signal_id, &signal_query);
551 name = signal_query.signal_name;
553 accessible = ATK_OBJECT(g_value_get_object(¶m_values[0]));
554 s = atk_object_get_name (accessible);
555 emit(accessible, ITF_EVENT_DOCUMENT, name, "", 0, 0, DBUS_TYPE_STRING_AS_STRING, s);
560 /*---------------------------------------------------------------------------*/
563 * Signal handler for "Gtk:AtkComponent:bounds-changed". Converts
564 * this to an AT-SPI event - "object:bounds-changed".
567 bounds_event_listener (GSignalInvocationHint *signal_hint,
568 guint n_param_values,
569 const GValue *param_values,
572 AtkObject *accessible;
573 AtkRectangle *atk_rect;
574 GSignalQuery signal_query;
575 const gchar *name, *s;
577 g_signal_query (signal_hint->signal_id, &signal_query);
578 name = signal_query.signal_name;
580 accessible = ATK_OBJECT(g_value_get_object(¶m_values[0]));
582 if (G_VALUE_HOLDS_BOXED (param_values + 1))
583 atk_rect = g_value_get_boxed (param_values + 1);
585 emit_rect(accessible, ITF_EVENT_OBJECT, name, "", atk_rect);
589 /*---------------------------------------------------------------------------*/
592 * Handles the ATK signal 'Gtk:AtkObject:active-descendant-changed' and
593 * converts it to the AT-SPI signal - 'object:active-descendant-changed'.
597 active_descendant_event_listener (GSignalInvocationHint *signal_hint,
598 guint n_param_values,
599 const GValue *param_values,
602 AtkObject *accessible;
604 GSignalQuery signal_query;
605 const gchar *name, *minor;
609 g_signal_query (signal_hint->signal_id, &signal_query);
610 name = signal_query.signal_name;
612 accessible = ATK_OBJECT(g_value_get_object(¶m_values[0]));
613 child = ATK_OBJECT(g_value_get_pointer (¶m_values[1]));
614 g_return_val_if_fail (ATK_IS_OBJECT (child), TRUE);
615 minor = g_quark_to_string (signal_hint->detail);
617 detail1 = atk_object_get_index_in_parent (child);
618 s = atk_dbus_get_path(child);
620 emit(accessible, ITF_EVENT_OBJECT, name, "", detail1, 0, DBUS_TYPE_OBJECT_PATH_AS_STRING, s);
625 /*---------------------------------------------------------------------------*/
628 * Handles the ATK signal 'Gtk:AtkHypertext:link-selected' and
629 * converts it to the AT-SPI signal - 'object:link-selected'
633 link_selected_event_listener (GSignalInvocationHint *signal_hint,
634 guint n_param_values,
635 const GValue *param_values,
638 AtkObject *accessible;
639 GSignalQuery signal_query;
640 const gchar *name, *minor;
643 g_signal_query (signal_hint->signal_id, &signal_query);
644 name = signal_query.signal_name;
646 accessible = ATK_OBJECT(g_value_get_object(¶m_values[0]));
647 minor = g_quark_to_string (signal_hint->detail);
649 if (G_VALUE_TYPE (¶m_values[1]) == G_TYPE_INT)
650 detail1 = g_value_get_int (¶m_values[1]);
652 emit(accessible, ITF_EVENT_OBJECT, name, minor, detail1, 0, DBUS_TYPE_INT32_AS_STRING, 0);
656 /*---------------------------------------------------------------------------*/
659 * Handles the ATK signal 'Gtk:AtkText:text-changed' and
660 * converts it to the AT-SPI signal - 'object:text-changed'
664 text_changed_event_listener (GSignalInvocationHint *signal_hint,
665 guint n_param_values,
666 const GValue *param_values,
669 AtkObject *accessible;
670 GSignalQuery signal_query;
671 const gchar *name, *minor;
673 gint detail1, detail2;
675 g_signal_query (signal_hint->signal_id, &signal_query);
676 name = signal_query.signal_name;
678 accessible = ATK_OBJECT(g_value_get_object(¶m_values[0]));
679 minor = g_quark_to_string (signal_hint->detail);
681 if (G_VALUE_TYPE (¶m_values[1]) == G_TYPE_INT)
682 detail1 = g_value_get_int (¶m_values[1]);
684 if (G_VALUE_TYPE (¶m_values[2]) == G_TYPE_INT)
685 detail2 = g_value_get_int (¶m_values[2]);
687 selected = atk_text_get_text (ATK_TEXT (accessible), detail1, detail1+detail2);
689 emit(accessible, ITF_EVENT_OBJECT, name, minor, detail1, detail2, DBUS_TYPE_STRING_AS_STRING, selected);
693 /*---------------------------------------------------------------------------*/
696 * Handles the ATK signal 'Gtk:AtkText:text-selection-changed' and
697 * converts it to the AT-SPI signal - 'object:text-selection-changed'
701 text_selection_changed_event_listener (GSignalInvocationHint *signal_hint,
702 guint n_param_values,
703 const GValue *param_values,
706 AtkObject *accessible;
707 GSignalQuery signal_query;
708 const gchar *name, *minor;
709 gint detail1, detail2;
711 g_signal_query (signal_hint->signal_id, &signal_query);
712 name = signal_query.signal_name;
714 accessible = ATK_OBJECT(g_value_get_object(¶m_values[0]));
715 minor = g_quark_to_string (signal_hint->detail);
717 if (G_VALUE_TYPE (¶m_values[1]) == G_TYPE_INT)
718 detail1 = g_value_get_int (¶m_values[1]);
720 if (G_VALUE_TYPE (¶m_values[2]) == G_TYPE_INT)
721 detail2 = g_value_get_int (¶m_values[2]);
723 emit(accessible, ITF_EVENT_OBJECT, name, minor, detail1, detail2, DBUS_TYPE_STRING_AS_STRING, "");
727 /*---------------------------------------------------------------------------*/
730 * Generic signal converter and forwarder.
732 * Klass (Interface) org.freedesktop.atspi.Event.Object
733 * Major is the signal name.
740 generic_event_listener (GSignalInvocationHint *signal_hint,
741 guint n_param_values,
742 const GValue *param_values,
745 AtkObject *accessible;
746 GSignalQuery signal_query;
749 g_signal_query (signal_hint->signal_id, &signal_query);
750 name = signal_query.signal_name;
752 accessible = ATK_OBJECT(g_value_get_object(¶m_values[0]));
753 emit(accessible, ITF_EVENT_OBJECT, name, "", 0, 0, DBUS_TYPE_INT32_AS_STRING, 0);
757 /*---------------------------------------------------------------------------*/
760 * Registers the provided function as a handler for the given signal name
761 * and stores the signal id returned so that the function may be
762 * de-registered later.
765 add_signal_listener (GSignalEmissionHook listener, const char *signal_name)
769 id = atk_add_global_event_listener (listener, signal_name);
770 g_array_append_val (listener_ids, id);
774 * Initialization for the signal handlers.
776 * Registers all required signal handlers.
779 spi_atk_register_event_listeners (void)
782 * Kludge to make sure the Atk interface types are registered, otherwise
783 * the AtkText signal handlers below won't get registered
785 GObject *ao = g_object_new (ATK_TYPE_OBJECT, NULL);
786 AtkObject *bo = atk_no_op_object_new (ao);
788 g_object_unref (G_OBJECT (bo));
791 /* Register for focus event notifications, and register app with central registry */
792 listener_ids = g_array_sized_new (FALSE, TRUE, sizeof (guint), 16);
794 atk_bridge_focus_tracker_id = atk_add_focus_tracker (focus_tracker);
796 add_signal_listener (tree_update_listener, "Gtk:AtkObject:property-change");
797 add_signal_listener (tree_update_children_listener, "Gtk:AtkObject:children-changed");
799 add_signal_listener (property_event_listener, "Gtk:AtkObject:property-change");
800 add_signal_listener (window_event_listener, "window:create");
801 add_signal_listener (window_event_listener, "window:destroy");
802 add_signal_listener (window_event_listener, "window:minimize");
803 add_signal_listener (window_event_listener, "window:maximize");
804 add_signal_listener (window_event_listener, "window:restore");
805 add_signal_listener (window_event_listener, "window:activate");
806 add_signal_listener (window_event_listener, "window:deactivate");
807 add_signal_listener (document_event_listener, "Gtk:AtkDocument:load-complete");
808 add_signal_listener (document_event_listener, "Gtk:AtkDocument:reload");
809 add_signal_listener (document_event_listener, "Gtk:AtkDocument:load-stopped");
810 add_signal_listener (state_event_listener, "Gtk:AtkObject:state-change");
811 add_signal_listener (active_descendant_event_listener, "Gtk:AtkObject:active-descendant-changed");
812 add_signal_listener (bounds_event_listener, "Gtk:AtkComponent:bounds-changed");
813 add_signal_listener (text_selection_changed_event_listener, "Gtk:AtkText:text-selection-changed");
814 add_signal_listener (text_changed_event_listener, "Gtk:AtkText:text-changed");
815 add_signal_listener (link_selected_event_listener, "Gtk:AtkHypertext:link-selected");
816 add_signal_listener (generic_event_listener, "Gtk:AtkObject:visible-data-changed");
817 add_signal_listener (generic_event_listener, "Gtk:AtkSelection:selection-changed");
818 add_signal_listener (generic_event_listener, "Gtk:AtkText:text-caret-moved");
819 add_signal_listener (generic_event_listener, "Gtk:AtkTable:row-inserted");
820 add_signal_listener (generic_event_listener, "Gtk:AtkTable:row-reordered");
821 add_signal_listener (generic_event_listener, "Gtk:AtkTable:row-deleted");
822 add_signal_listener (generic_event_listener, "Gtk:AtkTable:column-inserted");
823 add_signal_listener (generic_event_listener, "Gtk:AtkTable:column-reordered");
824 add_signal_listener (generic_event_listener, "Gtk:AtkTable:column-deleted");
825 add_signal_listener (generic_event_listener, "Gtk:AtkTable:model-changed");
828 * May add the following listeners to implement preemptive key listening for GTK+
830 * atk_add_global_event_listener (spi_atk_bridge_widgetkey_listener, "Gtk:GtkWidget:key-press-event");
831 * atk_add_global_event_listener (spi_atk_bridge_widgetkey_listener, "Gtk:GtkWidget:key-release-event");
833 atk_bridge_key_event_listener_id = atk_add_key_event_listener (spi_atk_bridge_key_listener, NULL);
836 /*---------------------------------------------------------------------------*/
839 * De-registers all ATK signal handlers.
842 spi_atk_deregister_event_listeners (void)
845 GArray *ids = listener_ids;
848 if (atk_bridge_focus_tracker_id)
849 atk_remove_focus_tracker (atk_bridge_focus_tracker_id);
851 for (i = 0; ids && i < ids->len; i++)
853 atk_remove_global_event_listener (g_array_index (ids, guint, i));
856 if (atk_bridge_key_event_listener_id)
857 atk_remove_key_event_listener (atk_bridge_key_event_listener_id);
860 /*---------------------------------------------------------------------------*/
863 * TODO This function seems out of place here.
865 * Emits fake deactivate signals on all top-level windows.
866 * Used when shutting down AT-SPI, ensuring that all
867 * windows have been removed on the client side.
870 spi_atk_tidy_windows (void)
876 root = atk_get_root ();
877 n_children = atk_object_get_n_accessible_children (root);
878 for (i = 0; i < n_children; i++)
881 AtkStateSet *stateset;
884 child = atk_object_ref_accessible_child (root, i);
885 stateset = atk_object_ref_state_set (child);
887 name = atk_object_get_name (child);
888 if (atk_state_set_contains_state (stateset, ATK_STATE_ACTIVE))
890 emit(child, ITF_EVENT_WINDOW, "deactivate", NULL, 0, 0, DBUS_TYPE_STRING_AS_STRING, name);
892 g_object_unref (stateset);
894 emit(child, ITF_EVENT_WINDOW, "destroy", NULL, 0, 0, DBUS_TYPE_STRING_AS_STRING, name);
895 g_object_unref (child);
899 /*END------------------------------------------------------------------------*/