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.
28 #include <droute/droute.h>
33 #include "spi-common/spi-dbus.h"
35 static GArray *listener_ids = NULL;
37 static gint atk_bridge_key_event_listener_id;
38 static gint atk_bridge_focus_tracker_id;
40 /* Amazingly the ATK event callbacks dont have a user
41 * data parameter. Instead, with great sadness, we use
42 * some global data. Data is declared and initialized
45 extern SpiAppData *atk_adaptor_app_data;
47 /*---------------------------------------------------------------------------*/
49 #define ITF_EVENT_OBJECT "org.freedesktop.atspi.Event.Object"
50 #define ITF_EVENT_WINDOW "org.freedesktop.atspi.Event.Window"
51 #define ITF_EVENT_DOCUMENT "org.freedekstop.atspi.Event.Document"
52 #define ITF_EVENT_FOCUS "org.freedesktop.atspi.Event.Focus"
54 /*---------------------------------------------------------------------------*/
56 /* When sending events it is safe to register an accessible object if
57 * one does not already exist for a given AtkObject.
58 * This is because the cache update signal should then be send before
59 * the event signal is sent.
62 get_object_path (AtkObject *accessible)
66 ref = atk_dbus_register_accessible (accessible);
67 return atk_dbus_ref_to_path (ref);
70 /*---------------------------------------------------------------------------*/
73 Accessibility_DeviceEventController_notifyListenersSync(const Accessibility_DeviceEvent *key_event)
77 dbus_bool_t consumed = FALSE;
80 dbus_message_new_method_call(SPI_DBUS_NAME_REGISTRY,
81 SPI_DBUS_PATH_REGISTRY,
82 SPI_DBUS_INTERFACE_DEC,
83 "notifyListenersSync");
85 dbus_error_init(&error);
86 if (spi_dbus_marshal_deviceEvent(message, key_event))
88 DBusMessage *reply = dbus_connection_send_with_reply_and_block(atk_adaptor_app_data->bus, message, 1000, &error);
92 dbus_error_init(&error);
93 dbus_message_get_args(reply, &error, DBUS_TYPE_BOOLEAN, &consumed, DBUS_TYPE_INVALID);
94 dbus_message_unref(reply);
97 dbus_message_unref(message);
102 spi_init_keystroke_from_atk_key_event (Accessibility_DeviceEvent *keystroke,
103 AtkKeyEventStruct *event)
105 keystroke->id = (dbus_int32_t) event->keyval;
106 keystroke->hw_code = (dbus_int16_t) event->keycode;
107 keystroke->timestamp = (dbus_uint32_t) event->timestamp;
108 keystroke->modifiers = (dbus_uint16_t) (event->state & 0xFFFF);
113 keystroke->event_string = g_strdup (event->string);
114 c = g_utf8_get_char_validated (event->string, -1);
115 if (c > 0 && g_unichar_isprint (c))
116 keystroke->is_text = TRUE;
118 keystroke->is_text = FALSE;
122 keystroke->event_string = g_strdup ("");
123 keystroke->is_text = FALSE;
127 case (ATK_KEY_EVENT_PRESS):
128 keystroke->type = Accessibility_KEY_PRESSED_EVENT;
130 case (ATK_KEY_EVENT_RELEASE):
131 keystroke->type = Accessibility_KEY_RELEASED_EVENT;
138 g_print ("key_event type %d; val=%d code=%d modifiers=%x name=%s is_text=%d, time=%lx\n",
139 (int) keystroke->type, (int) keystroke->id, (int) keystroke->hw_code,
140 (int) keystroke->modifiers,
141 keystroke->event_string, (int) keystroke->is_text, (unsigned long) keystroke->timestamp);
147 spi_atk_bridge_key_listener (AtkKeyEventStruct *event, gpointer data)
150 Accessibility_DeviceEvent key_event;
152 spi_init_keystroke_from_atk_key_event (&key_event, event);
154 result = Accessibility_DeviceEventController_notifyListenersSync (&key_event);
156 if (key_event.event_string) g_free (key_event.event_string);
162 /*---------------------------------------------------------------------------*/
165 * Emits an AT-SPI event.
166 * AT-SPI events names are split into three parts:
168 * This is mapped onto D-Bus events as:
169 * D-Bus Interface:Signal Name:Detail argument
171 * Marshals a basic type into the 'any_data' attribute of
176 * This is a rather annoying function needed to replace
177 * NULL values of strings with the empty string. Null string
178 * values can be created by the atk_object_get_name or text selection
181 provide_defaults(const gint type,
186 case DBUS_TYPE_STRING:
187 case DBUS_TYPE_OBJECT_PATH:
198 emit(AtkObject *accessible,
202 dbus_int32_t detail1,
203 dbus_int32_t detail2,
208 DBusMessageIter iter, sub;
209 gchar *path, *cname, *t;
211 path = get_object_path (accessible);
213 /* Tough decision here
214 * We won't send events from accessible
215 * objects that have not yet been added to the accessible tree.
220 if (!klass) klass = "";
221 if (!major) major = "";
222 if (!minor) minor = "";
225 * This is very annoying, but as '-' isn't a legal signal
226 * name in D-Bus (Why not??!?) The names need converting
227 * on this side, and again on the client side.
229 cname = g_strdup(major);
230 while ((t = strchr(cname, '-')) != NULL) *t = '_';
232 sig = dbus_message_new_signal(path, klass, cname);
236 dbus_message_iter_init_append(sig, &iter);
238 dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &minor);
239 dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &detail1);
240 dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &detail2);
242 dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, type, &sub);
244 * I need to convert the string signature to an integer type signature.
245 * DBUS_TYPE_INT32 is defined as 'i' whereas the string is "i".
246 * I should just be able to cast the first character of the string to an
249 val = provide_defaults((int) *type, val);
250 dbus_message_iter_append_basic(&sub, (int) *type, &val);
251 dbus_message_iter_close_container(&iter, &sub);
253 dbus_connection_send(atk_adaptor_app_data->bus, sig, NULL);
254 dbus_message_unref(sig);
257 /*---------------------------------------------------------------------------*/
260 * Emits an AT-SPI event, marshalling a BoundingBox structure into the
261 * 'any_data' variant of the event.
264 emit_rect(AtkObject *accessible,
271 DBusMessageIter iter, variant, sub;
272 gchar *path, *cname, *t;
273 dbus_int32_t dummy = 0;
275 path = get_object_path (accessible);
277 /* Tough decision here
278 * We won't send events from accessible
279 * objects that have not yet been added to the accessible tree.
284 if (!klass) klass = "";
285 if (!major) major = "";
286 if (!minor) minor = "";
289 * This is very annoying, but as '-' isn't a legal signal
290 * name in D-Bus (Why not??!?) The names need converting
291 * on this side, and again on the client side.
293 cname = g_strdup(major);
294 while ((t = strchr(cname, '-')) != NULL) *t = '_';
296 sig = dbus_message_new_signal(path, klass, cname);
300 dbus_message_iter_init_append (sig, &iter);
301 dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &minor);
302 dbus_message_iter_append_basic (&iter, DBUS_TYPE_INT32, &dummy);
303 dbus_message_iter_append_basic (&iter, DBUS_TYPE_INT32, &dummy);
305 dbus_message_iter_open_container (&iter, DBUS_TYPE_VARIANT, "(iiii)", &variant);
306 dbus_message_iter_open_container (&variant, DBUS_TYPE_STRUCT, NULL, &sub);
307 dbus_message_iter_append_basic (&sub, DBUS_TYPE_INT32, &(rect->x));
308 dbus_message_iter_append_basic (&sub, DBUS_TYPE_INT32, &(rect->y));
309 dbus_message_iter_append_basic (&sub, DBUS_TYPE_INT32, &(rect->width));
310 dbus_message_iter_append_basic (&sub, DBUS_TYPE_INT32, &(rect->height));
311 dbus_message_iter_close_container (&variant, &sub);
312 dbus_message_iter_close_container (&iter, &variant);
314 dbus_connection_send(atk_adaptor_app_data->bus, sig, NULL);
317 /*---------------------------------------------------------------------------*/
320 * The tree update listener handles the following Atk signals:
322 * Gtk:AtkObject:property-change
324 * With the folowing property names:
327 * accessible-description
330 * It updates the server side accessible-object database, which
331 * will then syncronize with the client-side accessible cache.
335 tree_update_listener (GSignalInvocationHint *signal_hint,
336 guint n_param_values,
337 const GValue *param_values,
340 AtkObject *accessible;
341 AtkPropertyValues *values;
342 const gchar *pname = NULL;
344 accessible = g_value_get_object (¶m_values[0]);
345 values = (AtkPropertyValues*) g_value_get_pointer (¶m_values[1]);
347 pname = values[0].property_name;
349 if (strcmp (pname, "accessible-name") == 0 ||
350 strcmp (pname, "accessible-description") == 0 ||
351 strcmp (pname, "accessible-parent") == 0)
353 atk_dbus_update_accessible (accessible);
359 * Handles the ATK signal 'Gtk:AtkObject:children-changed'.
361 * It updates the server side accessible-object database, which
362 * will then syncronize with the client-side accessible cache.
366 tree_update_children_listener (GSignalInvocationHint *signal_hint,
367 guint n_param_values,
368 const GValue *param_values,
371 AtkObject *accessible;
372 const gchar *detail = NULL;
374 gboolean child_needs_unref = FALSE;
376 if (signal_hint->detail)
377 detail = g_quark_to_string (signal_hint->detail);
379 accessible = g_value_get_object (¶m_values[0]);
380 if (!strcmp (detail, "add"))
383 int index = g_value_get_uint (param_values + 1);
384 child = g_value_get_pointer (param_values + 2);
386 if (ATK_IS_OBJECT (child))
387 g_object_ref (child);
389 child = atk_object_ref_accessible_child (accessible, index);
391 atk_dbus_register_accessible (child);
392 g_object_unref (child);
397 /*---------------------------------------------------------------------------*/
400 * The focus listener handles the ATK 'focus' signal and forwards it
401 * as the AT-SPI event, 'focus:'
404 focus_tracker (AtkObject *accessible)
406 emit(accessible, ITF_EVENT_FOCUS, "focus", "", 0, 0, DBUS_TYPE_INT32_AS_STRING, 0);
409 /*---------------------------------------------------------------------------*/
411 #define PCHANGE "property-change"
414 * This handler handles the following ATK signals and
415 * converts them to AT-SPI events:
417 * Gtk:AtkObject:property-change -> object:property-change:(property-name)
419 * The property-name is part of the ATK property-change signal.
422 property_event_listener (GSignalInvocationHint *signal_hint,
423 guint n_param_values,
424 const GValue *param_values,
427 AtkObject *accessible;
428 AtkPropertyValues *values;
430 const gchar *pname = NULL;
436 accessible = g_value_get_object (¶m_values[0]);
437 values = (AtkPropertyValues*) g_value_get_pointer (¶m_values[1]);
439 pname = values[0].property_name;
441 /* TODO Could improve this control statement by matching
442 * on only the end of the signal names,
444 if (strcmp (pname, "accessible-table-summary") == 0)
446 otemp = atk_table_get_summary(ATK_TABLE (accessible));
447 stemp = get_object_path (otemp);
448 emit(accessible, ITF_EVENT_OBJECT, PCHANGE, pname, 0, 0, DBUS_TYPE_OBJECT_PATH_AS_STRING, stemp);
450 else if (strcmp (pname, "accessible-table-column-header") == 0)
452 i = g_value_get_int (&(values->new_value));
453 otemp = atk_table_get_column_header(ATK_TABLE (accessible), i);
454 stemp = get_object_path (otemp);
455 emit(accessible, ITF_EVENT_OBJECT, PCHANGE, pname, 0, 0, DBUS_TYPE_OBJECT_PATH_AS_STRING, stemp);
457 else if (strcmp (pname, "accessible-table-row-header") == 0)
459 i = g_value_get_int (&(values->new_value));
460 otemp = atk_table_get_row_header(ATK_TABLE (accessible), i);
461 stemp = get_object_path (otemp);
462 emit(accessible, ITF_EVENT_OBJECT, PCHANGE, pname, 0, 0, DBUS_TYPE_OBJECT_PATH_AS_STRING, stemp);
464 else if (strcmp (pname, "accessible-table-row-description") == 0)
466 i = g_value_get_int (&(values->new_value));
467 stemp = atk_table_get_row_description(ATK_TABLE (accessible), i);
468 emit(accessible, ITF_EVENT_OBJECT, PCHANGE, pname, 0, 0, DBUS_TYPE_STRING_AS_STRING, stemp);
470 else if (strcmp (pname, "accessible-table-column-description") == 0)
472 i = g_value_get_int (&(values->new_value));
473 stemp = atk_table_get_column_description(ATK_TABLE (accessible), i);
474 emit(accessible, ITF_EVENT_OBJECT, PCHANGE, pname, 0, 0, DBUS_TYPE_STRING_AS_STRING, stemp);
476 else if (strcmp (pname, "accessible-table-caption-object") == 0)
478 otemp = atk_table_get_caption(ATK_TABLE(accessible));
479 stemp = atk_object_get_name(otemp);
480 emit(accessible, ITF_EVENT_OBJECT, PCHANGE, pname, 0, 0, DBUS_TYPE_STRING_AS_STRING, stemp);
484 emit(accessible, ITF_EVENT_OBJECT, PCHANGE, pname, 0, 0, DBUS_TYPE_INT32_AS_STRING, 0);
489 /*---------------------------------------------------------------------------*/
491 #define STATE_CHANGED "state-changed"
494 * The state event listener handles 'Gtk:AtkObject:state-change' ATK signals
495 * and forwards them as object:state-changed:(param-name) AT-SPI events. Where
496 * the param-name is part of the ATK state-change signal.
499 state_event_listener (GSignalInvocationHint *signal_hint,
500 guint n_param_values,
501 const GValue *param_values,
504 AtkObject *accessible;
508 accessible = ATK_OBJECT(g_value_get_object (¶m_values[0]));
509 pname = g_strdup (g_value_get_string (¶m_values[1]));
511 /* TODO - Possibly ignore a change to the 'defunct' state.
512 * This is because without reference counting defunct objects should be removed.
514 detail1 = (g_value_get_boolean (¶m_values[2])) ? 1 : 0;
515 emit(accessible, ITF_EVENT_OBJECT, STATE_CHANGED, pname, detail1, 0, DBUS_TYPE_INT32_AS_STRING, 0);
520 /*---------------------------------------------------------------------------*/
523 * The window event listener handles the following ATK signals and forwards
524 * them as AT-SPI events:
526 * window:create -> window:create
527 * window:destroy -> window:destroy
528 * window:minimize -> window:minimize
529 * window:maximize -> window:maximize
530 * window:activate -> window:activate
531 * window:deactivate -> window:deactivate
534 window_event_listener (GSignalInvocationHint *signal_hint,
535 guint n_param_values,
536 const GValue *param_values,
539 AtkObject *accessible;
540 GSignalQuery signal_query;
541 const gchar *name, *s;
543 g_signal_query (signal_hint->signal_id, &signal_query);
544 name = signal_query.signal_name;
546 accessible = ATK_OBJECT(g_value_get_object(¶m_values[0]));
547 s = atk_object_get_name (accessible);
548 emit(accessible, ITF_EVENT_WINDOW, name, "", 0, 0, DBUS_TYPE_STRING_AS_STRING, s);
553 /*---------------------------------------------------------------------------*/
556 * The document event listener handles the following ATK signals
557 * and converts them to AT-SPI events:
559 * Gtk:AtkDocument:load-complete -> document:load-complete
560 * Gtk:AtkDocument:load-stopped -> document:load-stopped
561 * Gtk:AtkDocument:reload -> document:reload
564 document_event_listener (GSignalInvocationHint *signal_hint,
565 guint n_param_values,
566 const GValue *param_values,
569 AtkObject *accessible;
570 GSignalQuery signal_query;
571 const gchar *name, *s;
573 g_signal_query (signal_hint->signal_id, &signal_query);
574 name = signal_query.signal_name;
576 accessible = ATK_OBJECT(g_value_get_object(¶m_values[0]));
577 s = atk_object_get_name (accessible);
578 emit(accessible, ITF_EVENT_DOCUMENT, name, "", 0, 0, DBUS_TYPE_STRING_AS_STRING, s);
583 /*---------------------------------------------------------------------------*/
586 * Signal handler for "Gtk:AtkComponent:bounds-changed". Converts
587 * this to an AT-SPI event - "object:bounds-changed".
590 bounds_event_listener (GSignalInvocationHint *signal_hint,
591 guint n_param_values,
592 const GValue *param_values,
595 AtkObject *accessible;
596 AtkRectangle *atk_rect;
597 GSignalQuery signal_query;
598 const gchar *name, *s;
600 g_signal_query (signal_hint->signal_id, &signal_query);
601 name = signal_query.signal_name;
603 accessible = ATK_OBJECT(g_value_get_object(¶m_values[0]));
605 if (G_VALUE_HOLDS_BOXED (param_values + 1))
606 atk_rect = g_value_get_boxed (param_values + 1);
608 emit_rect(accessible, ITF_EVENT_OBJECT, name, "", atk_rect);
612 /*---------------------------------------------------------------------------*/
615 * Handles the ATK signal 'Gtk:AtkObject:active-descendant-changed' and
616 * converts it to the AT-SPI signal - 'object:active-descendant-changed'.
620 active_descendant_event_listener (GSignalInvocationHint *signal_hint,
621 guint n_param_values,
622 const GValue *param_values,
625 AtkObject *accessible;
627 GSignalQuery signal_query;
628 const gchar *name, *minor;
632 g_signal_query (signal_hint->signal_id, &signal_query);
633 name = signal_query.signal_name;
635 accessible = ATK_OBJECT(g_value_get_object(¶m_values[0]));
636 child = ATK_OBJECT(g_value_get_pointer (¶m_values[1]));
637 g_return_val_if_fail (ATK_IS_OBJECT (child), TRUE);
638 minor = g_quark_to_string (signal_hint->detail);
640 detail1 = atk_object_get_index_in_parent (child);
641 s = get_object_path (child);
643 emit(accessible, ITF_EVENT_OBJECT, name, "", detail1, 0, DBUS_TYPE_OBJECT_PATH_AS_STRING, s);
648 /*---------------------------------------------------------------------------*/
651 * Handles the ATK signal 'Gtk:AtkHypertext:link-selected' and
652 * converts it to the AT-SPI signal - 'object:link-selected'
656 link_selected_event_listener (GSignalInvocationHint *signal_hint,
657 guint n_param_values,
658 const GValue *param_values,
661 AtkObject *accessible;
662 GSignalQuery signal_query;
663 const gchar *name, *minor;
666 g_signal_query (signal_hint->signal_id, &signal_query);
667 name = signal_query.signal_name;
669 accessible = ATK_OBJECT(g_value_get_object(¶m_values[0]));
670 minor = g_quark_to_string (signal_hint->detail);
672 if (G_VALUE_TYPE (¶m_values[1]) == G_TYPE_INT)
673 detail1 = g_value_get_int (¶m_values[1]);
675 emit(accessible, ITF_EVENT_OBJECT, name, minor, detail1, 0, DBUS_TYPE_INT32_AS_STRING, 0);
679 /*---------------------------------------------------------------------------*/
682 * Handles the ATK signal 'Gtk:AtkText:text-changed' and
683 * converts it to the AT-SPI signal - 'object:text-changed'
687 text_changed_event_listener (GSignalInvocationHint *signal_hint,
688 guint n_param_values,
689 const GValue *param_values,
692 AtkObject *accessible;
693 GSignalQuery signal_query;
694 const gchar *name, *minor;
696 gint detail1, detail2;
698 g_signal_query (signal_hint->signal_id, &signal_query);
699 name = signal_query.signal_name;
701 accessible = ATK_OBJECT(g_value_get_object(¶m_values[0]));
702 minor = g_quark_to_string (signal_hint->detail);
704 if (G_VALUE_TYPE (¶m_values[1]) == G_TYPE_INT)
705 detail1 = g_value_get_int (¶m_values[1]);
707 if (G_VALUE_TYPE (¶m_values[2]) == G_TYPE_INT)
708 detail2 = g_value_get_int (¶m_values[2]);
710 selected = atk_text_get_text (ATK_TEXT (accessible), detail1, detail1+detail2);
712 emit(accessible, ITF_EVENT_OBJECT, name, minor, detail1, detail2, DBUS_TYPE_STRING_AS_STRING, selected);
716 /*---------------------------------------------------------------------------*/
719 * Handles the ATK signal 'Gtk:AtkText:text-selection-changed' and
720 * converts it to the AT-SPI signal - 'object:text-selection-changed'
724 text_selection_changed_event_listener (GSignalInvocationHint *signal_hint,
725 guint n_param_values,
726 const GValue *param_values,
729 AtkObject *accessible;
730 GSignalQuery signal_query;
731 const gchar *name, *minor;
732 gint detail1, detail2;
734 g_signal_query (signal_hint->signal_id, &signal_query);
735 name = signal_query.signal_name;
737 accessible = ATK_OBJECT(g_value_get_object(¶m_values[0]));
738 minor = g_quark_to_string (signal_hint->detail);
740 if (G_VALUE_TYPE (¶m_values[1]) == G_TYPE_INT)
741 detail1 = g_value_get_int (¶m_values[1]);
743 if (G_VALUE_TYPE (¶m_values[2]) == G_TYPE_INT)
744 detail2 = g_value_get_int (¶m_values[2]);
746 emit(accessible, ITF_EVENT_OBJECT, name, minor, detail1, detail2, DBUS_TYPE_STRING_AS_STRING, "");
750 /*---------------------------------------------------------------------------*/
753 * Generic signal converter and forwarder.
755 * Klass (Interface) org.freedesktop.atspi.Event.Object
756 * Major is the signal name.
763 generic_event_listener (GSignalInvocationHint *signal_hint,
764 guint n_param_values,
765 const GValue *param_values,
768 AtkObject *accessible;
769 GSignalQuery signal_query;
772 g_signal_query (signal_hint->signal_id, &signal_query);
773 name = signal_query.signal_name;
775 accessible = ATK_OBJECT(g_value_get_object(¶m_values[0]));
776 emit(accessible, ITF_EVENT_OBJECT, name, "", 0, 0, DBUS_TYPE_INT32_AS_STRING, 0);
780 /*---------------------------------------------------------------------------*/
783 * Registers the provided function as a handler for the given signal name
784 * and stores the signal id returned so that the function may be
785 * de-registered later.
788 add_signal_listener (GSignalEmissionHook listener, const char *signal_name)
792 id = atk_add_global_event_listener (listener, signal_name);
793 g_array_append_val (listener_ids, id);
797 * Initialization for the signal handlers.
799 * Registers all required signal handlers.
802 spi_atk_register_event_listeners (void)
805 * Kludge to make sure the Atk interface types are registered, otherwise
806 * the AtkText signal handlers below won't get registered
808 GObject *ao = g_object_new (ATK_TYPE_OBJECT, NULL);
809 AtkObject *bo = atk_no_op_object_new (ao);
811 g_object_unref (G_OBJECT (bo));
814 /* Register for focus event notifications, and register app with central registry */
815 listener_ids = g_array_sized_new (FALSE, TRUE, sizeof (guint), 16);
817 atk_bridge_focus_tracker_id = atk_add_focus_tracker (focus_tracker);
819 add_signal_listener (tree_update_listener, "Gtk:AtkObject:property-change");
820 add_signal_listener (tree_update_children_listener, "Gtk:AtkObject:children-changed");
822 add_signal_listener (property_event_listener, "Gtk:AtkObject:property-change");
823 add_signal_listener (window_event_listener, "window:create");
824 add_signal_listener (window_event_listener, "window:destroy");
825 add_signal_listener (window_event_listener, "window:minimize");
826 add_signal_listener (window_event_listener, "window:maximize");
827 add_signal_listener (window_event_listener, "window:restore");
828 add_signal_listener (window_event_listener, "window:activate");
829 add_signal_listener (window_event_listener, "window:deactivate");
830 add_signal_listener (document_event_listener, "Gtk:AtkDocument:load-complete");
831 add_signal_listener (document_event_listener, "Gtk:AtkDocument:reload");
832 add_signal_listener (document_event_listener, "Gtk:AtkDocument:load-stopped");
833 add_signal_listener (state_event_listener, "Gtk:AtkObject:state-change");
834 add_signal_listener (active_descendant_event_listener, "Gtk:AtkObject:active-descendant-changed");
835 add_signal_listener (bounds_event_listener, "Gtk:AtkComponent:bounds-changed");
836 add_signal_listener (text_selection_changed_event_listener, "Gtk:AtkText:text-selection-changed");
837 add_signal_listener (text_changed_event_listener, "Gtk:AtkText:text-changed");
838 add_signal_listener (link_selected_event_listener, "Gtk:AtkHypertext:link-selected");
839 add_signal_listener (generic_event_listener, "Gtk:AtkObject:visible-data-changed");
840 add_signal_listener (generic_event_listener, "Gtk:AtkSelection:selection-changed");
841 add_signal_listener (generic_event_listener, "Gtk:AtkText:text-caret-moved");
842 add_signal_listener (generic_event_listener, "Gtk:AtkTable:row-inserted");
843 add_signal_listener (generic_event_listener, "Gtk:AtkTable:row-reordered");
844 add_signal_listener (generic_event_listener, "Gtk:AtkTable:row-deleted");
845 add_signal_listener (generic_event_listener, "Gtk:AtkTable:column-inserted");
846 add_signal_listener (generic_event_listener, "Gtk:AtkTable:column-reordered");
847 add_signal_listener (generic_event_listener, "Gtk:AtkTable:column-deleted");
848 add_signal_listener (generic_event_listener, "Gtk:AtkTable:model-changed");
851 * May add the following listeners to implement preemptive key listening for GTK+
853 * atk_add_global_event_listener (spi_atk_bridge_widgetkey_listener, "Gtk:GtkWidget:key-press-event");
854 * atk_add_global_event_listener (spi_atk_bridge_widgetkey_listener, "Gtk:GtkWidget:key-release-event");
856 atk_bridge_key_event_listener_id = atk_add_key_event_listener (spi_atk_bridge_key_listener, NULL);
859 /*---------------------------------------------------------------------------*/
862 * De-registers all ATK signal handlers.
865 spi_atk_deregister_event_listeners (void)
868 GArray *ids = listener_ids;
871 if (atk_bridge_focus_tracker_id)
872 atk_remove_focus_tracker (atk_bridge_focus_tracker_id);
874 for (i = 0; ids && i < ids->len; i++)
876 atk_remove_global_event_listener (g_array_index (ids, guint, i));
879 if (atk_bridge_key_event_listener_id)
880 atk_remove_key_event_listener (atk_bridge_key_event_listener_id);
883 /*---------------------------------------------------------------------------*/
886 * TODO This function seems out of place here.
888 * Emits fake deactivate signals on all top-level windows.
889 * Used when shutting down AT-SPI, ensuring that all
890 * windows have been removed on the client side.
893 spi_atk_tidy_windows (void)
899 root = atk_get_root ();
900 n_children = atk_object_get_n_accessible_children (root);
901 for (i = 0; i < n_children; i++)
904 AtkStateSet *stateset;
907 child = atk_object_ref_accessible_child (root, i);
908 stateset = atk_object_ref_state_set (child);
910 name = atk_object_get_name (child);
911 if (atk_state_set_contains_state (stateset, ATK_STATE_ACTIVE))
913 emit(child, ITF_EVENT_WINDOW, "deactivate", NULL, 0, 0, DBUS_TYPE_STRING_AS_STRING, name);
915 g_object_unref (stateset);
917 emit(child, ITF_EVENT_WINDOW, "destroy", NULL, 0, 0, DBUS_TYPE_STRING_AS_STRING, name);
918 g_object_unref (child);
922 /*END------------------------------------------------------------------------*/