2 * AT-SPI - Assistive Technology Service Provider Interface
3 * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
5 * Copyright 2008, 2009, 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>
31 #include "accessible-register.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 /*---------------------------------------------------------------------------*/
42 #define ITF_EVENT_OBJECT "org.freedesktop.atspi.Event.Object"
43 #define ITF_EVENT_WINDOW "org.freedesktop.atspi.Event.Window"
44 #define ITF_EVENT_DOCUMENT "org.freedekstop.atspi.Event.Document"
45 #define ITF_EVENT_FOCUS "org.freedesktop.atspi.Event.Focus"
47 /*---------------------------------------------------------------------------*/
49 /* When sending events it is safe to register an accessible object if
50 * one does not already exist for a given AtkObject.
51 * This is because the cache update signal should then be send before
52 * the event signal is sent.
55 get_object_path (AtkObject *accessible)
59 ref = atk_dbus_register_accessible (accessible);
60 return atk_dbus_ref_to_path (ref);
63 /*---------------------------------------------------------------------------*/
66 Accessibility_DeviceEventController_notifyListenersSync(const Accessibility_DeviceEvent *key_event)
70 dbus_bool_t consumed = FALSE;
73 dbus_message_new_method_call(SPI_DBUS_NAME_REGISTRY,
74 SPI_DBUS_PATH_REGISTRY,
75 SPI_DBUS_INTERFACE_DEC,
76 "notifyListenersSync");
78 dbus_error_init(&error);
79 if (spi_dbus_marshal_deviceEvent(message, key_event))
81 DBusMessage *reply = dbus_connection_send_with_reply_and_block(atk_adaptor_app_data->bus, message, 1000, &error);
85 dbus_error_init(&error);
86 dbus_message_get_args(reply, &error, DBUS_TYPE_BOOLEAN, &consumed, DBUS_TYPE_INVALID);
87 dbus_message_unref(reply);
90 dbus_message_unref(message);
95 spi_init_keystroke_from_atk_key_event (Accessibility_DeviceEvent *keystroke,
96 AtkKeyEventStruct *event)
98 keystroke->id = (dbus_int32_t) event->keyval;
99 keystroke->hw_code = (dbus_int16_t) event->keycode;
100 keystroke->timestamp = (dbus_uint32_t) event->timestamp;
101 keystroke->modifiers = (dbus_uint16_t) (event->state & 0xFFFF);
106 keystroke->event_string = g_strdup (event->string);
107 c = g_utf8_get_char_validated (event->string, -1);
108 if (c > 0 && g_unichar_isprint (c))
109 keystroke->is_text = TRUE;
111 keystroke->is_text = FALSE;
115 keystroke->event_string = g_strdup ("");
116 keystroke->is_text = FALSE;
120 case (ATK_KEY_EVENT_PRESS):
121 keystroke->type = Accessibility_KEY_PRESSED_EVENT;
123 case (ATK_KEY_EVENT_RELEASE):
124 keystroke->type = Accessibility_KEY_RELEASED_EVENT;
131 g_print ("key_event type %d; val=%d code=%d modifiers=%x name=%s is_text=%d, time=%lx\n",
132 (int) keystroke->type, (int) keystroke->id, (int) keystroke->hw_code,
133 (int) keystroke->modifiers,
134 keystroke->event_string, (int) keystroke->is_text, (unsigned long) keystroke->timestamp);
140 spi_atk_bridge_key_listener (AtkKeyEventStruct *event, gpointer data)
143 Accessibility_DeviceEvent key_event;
145 spi_init_keystroke_from_atk_key_event (&key_event, event);
147 result = Accessibility_DeviceEventController_notifyListenersSync (&key_event);
149 if (key_event.event_string) g_free (key_event.event_string);
155 /*---------------------------------------------------------------------------*/
158 * Emits an AT-SPI event.
159 * AT-SPI events names are split into three parts:
161 * This is mapped onto D-Bus events as:
162 * D-Bus Interface:Signal Name:Detail argument
164 * Marshals a basic type into the 'any_data' attribute of
169 * This is a rather annoying function needed to replace
170 * NULL values of strings with the empty string. Null string
171 * values can be created by the atk_object_get_name or text selection
174 provide_defaults(const gint type,
179 case DBUS_TYPE_STRING:
180 case DBUS_TYPE_OBJECT_PATH:
191 emit(AtkObject *accessible,
195 dbus_int32_t detail1,
196 dbus_int32_t detail2,
201 DBusMessageIter iter, sub;
202 gchar *path, *cname, *t;
204 path = get_object_path (accessible);
206 /* Tough decision here
207 * We won't send events from accessible
208 * objects that have not yet been added to the accessible tree.
213 if (!klass) klass = "";
214 if (!major) major = "";
215 if (!minor) minor = "";
218 * This is very annoying, but as '-' isn't a legal signal
219 * name in D-Bus (Why not??!?) The names need converting
220 * on this side, and again on the client side.
222 cname = g_strdup(major);
223 while ((t = strchr(cname, '-')) != NULL) *t = '_';
225 sig = dbus_message_new_signal(path, klass, cname);
229 dbus_message_iter_init_append(sig, &iter);
231 dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &minor);
232 dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &detail1);
233 dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &detail2);
235 dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, type, &sub);
237 * I need to convert the string signature to an integer type signature.
238 * DBUS_TYPE_INT32 is defined as 'i' whereas the string is "i".
239 * I should just be able to cast the first character of the string to an
242 val = provide_defaults((int) *type, val);
243 dbus_message_iter_append_basic(&sub, (int) *type, &val);
244 dbus_message_iter_close_container(&iter, &sub);
246 dbus_connection_send(atk_adaptor_app_data->bus, sig, NULL);
247 dbus_message_unref(sig);
250 /*---------------------------------------------------------------------------*/
253 * Emits an AT-SPI event, marshalling a BoundingBox structure into the
254 * 'any_data' variant of the event.
257 emit_rect(AtkObject *accessible,
264 DBusMessageIter iter, variant, sub;
265 gchar *path, *cname, *t;
266 dbus_int32_t dummy = 0;
268 path = get_object_path (accessible);
270 /* Tough decision here
271 * We won't send events from accessible
272 * objects that have not yet been added to the accessible tree.
277 if (!klass) klass = "";
278 if (!major) major = "";
279 if (!minor) minor = "";
282 * This is very annoying, but as '-' isn't a legal signal
283 * name in D-Bus (Why not??!?) The names need converting
284 * on this side, and again on the client side.
286 cname = g_strdup(major);
287 while ((t = strchr(cname, '-')) != NULL) *t = '_';
289 sig = dbus_message_new_signal(path, klass, cname);
293 dbus_message_iter_init_append (sig, &iter);
294 dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &minor);
295 dbus_message_iter_append_basic (&iter, DBUS_TYPE_INT32, &dummy);
296 dbus_message_iter_append_basic (&iter, DBUS_TYPE_INT32, &dummy);
298 dbus_message_iter_open_container (&iter, DBUS_TYPE_VARIANT, "(iiii)", &variant);
299 dbus_message_iter_open_container (&variant, DBUS_TYPE_STRUCT, NULL, &sub);
300 dbus_message_iter_append_basic (&sub, DBUS_TYPE_INT32, &(rect->x));
301 dbus_message_iter_append_basic (&sub, DBUS_TYPE_INT32, &(rect->y));
302 dbus_message_iter_append_basic (&sub, DBUS_TYPE_INT32, &(rect->width));
303 dbus_message_iter_append_basic (&sub, DBUS_TYPE_INT32, &(rect->height));
304 dbus_message_iter_close_container (&variant, &sub);
305 dbus_message_iter_close_container (&iter, &variant);
307 dbus_connection_send(atk_adaptor_app_data->bus, sig, NULL);
310 /*---------------------------------------------------------------------------*/
313 * The tree update listener handles the following Atk signals:
315 * Gtk:AtkObject:property-change
317 * With the folowing property names:
320 * accessible-description
323 * It updates the server side accessible-object database, which
324 * will then syncronize with the client-side accessible cache.
328 tree_update_listener (GSignalInvocationHint *signal_hint,
329 guint n_param_values,
330 const GValue *param_values,
333 AtkObject *accessible;
334 AtkPropertyValues *values;
335 const gchar *pname = NULL;
337 accessible = g_value_get_object (¶m_values[0]);
338 values = (AtkPropertyValues*) g_value_get_pointer (¶m_values[1]);
340 pname = values[0].property_name;
342 if (strcmp (pname, "accessible-name") == 0 ||
343 strcmp (pname, "accessible-description") == 0 ||
344 strcmp (pname, "accessible-parent") == 0)
346 atk_dbus_update_accessible (accessible);
352 * Handles the ATK signal 'Gtk:AtkObject:children-changed'.
354 * It updates the server side accessible-object database, which
355 * will then syncronize with the client-side accessible cache.
359 tree_update_children_listener (GSignalInvocationHint *signal_hint,
360 guint n_param_values,
361 const GValue *param_values,
364 AtkObject *accessible;
365 const gchar *detail = NULL;
367 gboolean child_needs_unref = FALSE;
369 if (signal_hint->detail)
370 detail = g_quark_to_string (signal_hint->detail);
372 accessible = g_value_get_object (¶m_values[0]);
373 if (!strcmp (detail, "add"))
376 int index = g_value_get_uint (param_values + 1);
377 child = g_value_get_pointer (param_values + 2);
379 if (ATK_IS_OBJECT (child))
380 g_object_ref (child);
382 child = atk_object_ref_accessible_child (accessible, index);
384 atk_dbus_register_accessible (child);
385 g_object_unref (child);
390 /*---------------------------------------------------------------------------*/
393 * The focus listener handles the ATK 'focus' signal and forwards it
394 * as the AT-SPI event, 'focus:'
397 focus_tracker (AtkObject *accessible)
399 emit(accessible, ITF_EVENT_FOCUS, "focus", "", 0, 0, DBUS_TYPE_INT32_AS_STRING, 0);
402 /*---------------------------------------------------------------------------*/
404 #define PCHANGE "property-change"
407 * This handler handles the following ATK signals and
408 * converts them to AT-SPI events:
410 * Gtk:AtkObject:property-change -> object:property-change:(property-name)
412 * The property-name is part of the ATK property-change signal.
415 property_event_listener (GSignalInvocationHint *signal_hint,
416 guint n_param_values,
417 const GValue *param_values,
420 AtkObject *accessible;
421 AtkPropertyValues *values;
423 const gchar *pname = NULL;
429 accessible = g_value_get_object (¶m_values[0]);
430 values = (AtkPropertyValues*) g_value_get_pointer (¶m_values[1]);
432 pname = values[0].property_name;
434 /* TODO Could improve this control statement by matching
435 * on only the end of the signal names,
437 if (strcmp (pname, "accessible-table-summary") == 0)
439 otemp = atk_table_get_summary(ATK_TABLE (accessible));
440 stemp = get_object_path (otemp);
441 emit(accessible, ITF_EVENT_OBJECT, PCHANGE, pname, 0, 0, DBUS_TYPE_OBJECT_PATH_AS_STRING, stemp);
443 else if (strcmp (pname, "accessible-table-column-header") == 0)
445 i = g_value_get_int (&(values->new_value));
446 otemp = atk_table_get_column_header(ATK_TABLE (accessible), i);
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-row-header") == 0)
452 i = g_value_get_int (&(values->new_value));
453 otemp = atk_table_get_row_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-description") == 0)
459 i = g_value_get_int (&(values->new_value));
460 stemp = atk_table_get_row_description(ATK_TABLE (accessible), i);
461 emit(accessible, ITF_EVENT_OBJECT, PCHANGE, pname, 0, 0, DBUS_TYPE_STRING_AS_STRING, stemp);
463 else if (strcmp (pname, "accessible-table-column-description") == 0)
465 i = g_value_get_int (&(values->new_value));
466 stemp = atk_table_get_column_description(ATK_TABLE (accessible), i);
467 emit(accessible, ITF_EVENT_OBJECT, PCHANGE, pname, 0, 0, DBUS_TYPE_STRING_AS_STRING, stemp);
469 else if (strcmp (pname, "accessible-table-caption-object") == 0)
471 otemp = atk_table_get_caption(ATK_TABLE(accessible));
472 stemp = atk_object_get_name(otemp);
473 emit(accessible, ITF_EVENT_OBJECT, PCHANGE, pname, 0, 0, DBUS_TYPE_STRING_AS_STRING, stemp);
477 emit(accessible, ITF_EVENT_OBJECT, PCHANGE, pname, 0, 0, DBUS_TYPE_INT32_AS_STRING, 0);
482 /*---------------------------------------------------------------------------*/
484 #define STATE_CHANGED "state-changed"
487 * The state event listener handles 'Gtk:AtkObject:state-change' ATK signals
488 * and forwards them as object:state-changed:(param-name) AT-SPI events. Where
489 * the param-name is part of the ATK state-change signal.
492 state_event_listener (GSignalInvocationHint *signal_hint,
493 guint n_param_values,
494 const GValue *param_values,
497 AtkObject *accessible;
501 accessible = ATK_OBJECT(g_value_get_object (¶m_values[0]));
502 pname = g_strdup (g_value_get_string (¶m_values[1]));
504 /* TODO - Possibly ignore a change to the 'defunct' state.
505 * This is because without reference counting defunct objects should be removed.
507 detail1 = (g_value_get_boolean (¶m_values[2])) ? 1 : 0;
508 emit(accessible, ITF_EVENT_OBJECT, STATE_CHANGED, pname, detail1, 0, DBUS_TYPE_INT32_AS_STRING, 0);
513 /*---------------------------------------------------------------------------*/
516 * The window event listener handles the following ATK signals and forwards
517 * them as AT-SPI events:
519 * window:create -> window:create
520 * window:destroy -> window:destroy
521 * window:minimize -> window:minimize
522 * window:maximize -> window:maximize
523 * window:activate -> window:activate
524 * window:deactivate -> window:deactivate
527 window_event_listener (GSignalInvocationHint *signal_hint,
528 guint n_param_values,
529 const GValue *param_values,
532 AtkObject *accessible;
533 GSignalQuery signal_query;
534 const gchar *name, *s;
536 g_signal_query (signal_hint->signal_id, &signal_query);
537 name = signal_query.signal_name;
539 accessible = ATK_OBJECT(g_value_get_object(¶m_values[0]));
540 s = atk_object_get_name (accessible);
541 emit(accessible, ITF_EVENT_WINDOW, name, "", 0, 0, DBUS_TYPE_STRING_AS_STRING, s);
546 /*---------------------------------------------------------------------------*/
549 * The document event listener handles the following ATK signals
550 * and converts them to AT-SPI events:
552 * Gtk:AtkDocument:load-complete -> document:load-complete
553 * Gtk:AtkDocument:load-stopped -> document:load-stopped
554 * Gtk:AtkDocument:reload -> document:reload
557 document_event_listener (GSignalInvocationHint *signal_hint,
558 guint n_param_values,
559 const GValue *param_values,
562 AtkObject *accessible;
563 GSignalQuery signal_query;
564 const gchar *name, *s;
566 g_signal_query (signal_hint->signal_id, &signal_query);
567 name = signal_query.signal_name;
569 accessible = ATK_OBJECT(g_value_get_object(¶m_values[0]));
570 s = atk_object_get_name (accessible);
571 emit(accessible, ITF_EVENT_DOCUMENT, name, "", 0, 0, DBUS_TYPE_STRING_AS_STRING, s);
576 /*---------------------------------------------------------------------------*/
579 * Signal handler for "Gtk:AtkComponent:bounds-changed". Converts
580 * this to an AT-SPI event - "object:bounds-changed".
583 bounds_event_listener (GSignalInvocationHint *signal_hint,
584 guint n_param_values,
585 const GValue *param_values,
588 AtkObject *accessible;
589 AtkRectangle *atk_rect;
590 GSignalQuery signal_query;
591 const gchar *name, *s;
593 g_signal_query (signal_hint->signal_id, &signal_query);
594 name = signal_query.signal_name;
596 accessible = ATK_OBJECT(g_value_get_object(¶m_values[0]));
598 if (G_VALUE_HOLDS_BOXED (param_values + 1))
599 atk_rect = g_value_get_boxed (param_values + 1);
601 emit_rect(accessible, ITF_EVENT_OBJECT, name, "", atk_rect);
605 /*---------------------------------------------------------------------------*/
608 * Handles the ATK signal 'Gtk:AtkObject:active-descendant-changed' and
609 * converts it to the AT-SPI signal - 'object:active-descendant-changed'.
613 active_descendant_event_listener (GSignalInvocationHint *signal_hint,
614 guint n_param_values,
615 const GValue *param_values,
618 AtkObject *accessible;
620 GSignalQuery signal_query;
621 const gchar *name, *minor;
625 g_signal_query (signal_hint->signal_id, &signal_query);
626 name = signal_query.signal_name;
628 accessible = ATK_OBJECT(g_value_get_object(¶m_values[0]));
629 child = ATK_OBJECT(g_value_get_pointer (¶m_values[1]));
630 g_return_val_if_fail (ATK_IS_OBJECT (child), TRUE);
631 minor = g_quark_to_string (signal_hint->detail);
633 detail1 = atk_object_get_index_in_parent (child);
634 s = get_object_path (child);
636 emit(accessible, ITF_EVENT_OBJECT, name, "", detail1, 0, DBUS_TYPE_OBJECT_PATH_AS_STRING, s);
641 /*---------------------------------------------------------------------------*/
644 * Handles the ATK signal 'Gtk:AtkHypertext:link-selected' and
645 * converts it to the AT-SPI signal - 'object:link-selected'
649 link_selected_event_listener (GSignalInvocationHint *signal_hint,
650 guint n_param_values,
651 const GValue *param_values,
654 AtkObject *accessible;
655 GSignalQuery signal_query;
656 const gchar *name, *minor;
659 g_signal_query (signal_hint->signal_id, &signal_query);
660 name = signal_query.signal_name;
662 accessible = ATK_OBJECT(g_value_get_object(¶m_values[0]));
663 minor = g_quark_to_string (signal_hint->detail);
665 if (G_VALUE_TYPE (¶m_values[1]) == G_TYPE_INT)
666 detail1 = g_value_get_int (¶m_values[1]);
668 emit(accessible, ITF_EVENT_OBJECT, name, minor, detail1, 0, DBUS_TYPE_INT32_AS_STRING, 0);
672 /*---------------------------------------------------------------------------*/
675 * Handles the ATK signal 'Gtk:AtkText:text-changed' and
676 * converts it to the AT-SPI signal - 'object:text-changed'
680 text_changed_event_listener (GSignalInvocationHint *signal_hint,
681 guint n_param_values,
682 const GValue *param_values,
685 AtkObject *accessible;
686 GSignalQuery signal_query;
687 const gchar *name, *minor;
689 gint detail1, detail2;
691 g_signal_query (signal_hint->signal_id, &signal_query);
692 name = signal_query.signal_name;
694 accessible = ATK_OBJECT(g_value_get_object(¶m_values[0]));
695 minor = g_quark_to_string (signal_hint->detail);
697 if (G_VALUE_TYPE (¶m_values[1]) == G_TYPE_INT)
698 detail1 = g_value_get_int (¶m_values[1]);
700 if (G_VALUE_TYPE (¶m_values[2]) == G_TYPE_INT)
701 detail2 = g_value_get_int (¶m_values[2]);
703 selected = atk_text_get_text (ATK_TEXT (accessible), detail1, detail1+detail2);
705 emit(accessible, ITF_EVENT_OBJECT, name, minor, detail1, detail2, DBUS_TYPE_STRING_AS_STRING, selected);
709 /*---------------------------------------------------------------------------*/
712 * Handles the ATK signal 'Gtk:AtkText:text-selection-changed' and
713 * converts it to the AT-SPI signal - 'object:text-selection-changed'
717 text_selection_changed_event_listener (GSignalInvocationHint *signal_hint,
718 guint n_param_values,
719 const GValue *param_values,
722 AtkObject *accessible;
723 GSignalQuery signal_query;
724 const gchar *name, *minor;
725 gint detail1, detail2;
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 minor = g_quark_to_string (signal_hint->detail);
733 if (G_VALUE_TYPE (¶m_values[1]) == G_TYPE_INT)
734 detail1 = g_value_get_int (¶m_values[1]);
736 if (G_VALUE_TYPE (¶m_values[2]) == G_TYPE_INT)
737 detail2 = g_value_get_int (¶m_values[2]);
739 emit(accessible, ITF_EVENT_OBJECT, name, minor, detail1, detail2, DBUS_TYPE_STRING_AS_STRING, "");
743 /*---------------------------------------------------------------------------*/
746 * Generic signal converter and forwarder.
748 * Klass (Interface) org.freedesktop.atspi.Event.Object
749 * Major is the signal name.
756 generic_event_listener (GSignalInvocationHint *signal_hint,
757 guint n_param_values,
758 const GValue *param_values,
761 AtkObject *accessible;
762 GSignalQuery signal_query;
765 g_signal_query (signal_hint->signal_id, &signal_query);
766 name = signal_query.signal_name;
768 accessible = ATK_OBJECT(g_value_get_object(¶m_values[0]));
769 emit(accessible, ITF_EVENT_OBJECT, name, "", 0, 0, DBUS_TYPE_INT32_AS_STRING, 0);
773 /*---------------------------------------------------------------------------*/
776 * Registers the provided function as a handler for the given signal name
777 * and stores the signal id returned so that the function may be
778 * de-registered later.
781 add_signal_listener (GSignalEmissionHook listener, const char *signal_name)
785 id = atk_add_global_event_listener (listener, signal_name);
786 g_array_append_val (listener_ids, id);
790 * Initialization for the signal handlers.
792 * Registers all required signal handlers.
795 spi_atk_register_event_listeners (void)
798 * Kludge to make sure the Atk interface types are registered, otherwise
799 * the AtkText signal handlers below won't get registered
801 GObject *ao = g_object_new (ATK_TYPE_OBJECT, NULL);
802 AtkObject *bo = atk_no_op_object_new (ao);
804 g_object_unref (G_OBJECT (bo));
807 /* Register for focus event notifications, and register app with central registry */
808 listener_ids = g_array_sized_new (FALSE, TRUE, sizeof (guint), 16);
810 atk_bridge_focus_tracker_id = atk_add_focus_tracker (focus_tracker);
812 add_signal_listener (tree_update_listener, "Gtk:AtkObject:property-change");
813 add_signal_listener (tree_update_children_listener, "Gtk:AtkObject:children-changed");
815 add_signal_listener (property_event_listener, "Gtk:AtkObject:property-change");
816 add_signal_listener (window_event_listener, "window:create");
817 add_signal_listener (window_event_listener, "window:destroy");
818 add_signal_listener (window_event_listener, "window:minimize");
819 add_signal_listener (window_event_listener, "window:maximize");
820 add_signal_listener (window_event_listener, "window:restore");
821 add_signal_listener (window_event_listener, "window:activate");
822 add_signal_listener (window_event_listener, "window:deactivate");
823 add_signal_listener (document_event_listener, "Gtk:AtkDocument:load-complete");
824 add_signal_listener (document_event_listener, "Gtk:AtkDocument:reload");
825 add_signal_listener (document_event_listener, "Gtk:AtkDocument:load-stopped");
826 add_signal_listener (state_event_listener, "Gtk:AtkObject:state-change");
827 add_signal_listener (active_descendant_event_listener, "Gtk:AtkObject:active-descendant-changed");
828 add_signal_listener (bounds_event_listener, "Gtk:AtkComponent:bounds-changed");
829 add_signal_listener (text_selection_changed_event_listener, "Gtk:AtkText:text-selection-changed");
830 add_signal_listener (text_changed_event_listener, "Gtk:AtkText:text-changed");
831 add_signal_listener (link_selected_event_listener, "Gtk:AtkHypertext:link-selected");
832 add_signal_listener (generic_event_listener, "Gtk:AtkObject:visible-data-changed");
833 add_signal_listener (generic_event_listener, "Gtk:AtkSelection:selection-changed");
834 add_signal_listener (generic_event_listener, "Gtk:AtkText:text-caret-moved");
835 add_signal_listener (generic_event_listener, "Gtk:AtkTable:row-inserted");
836 add_signal_listener (generic_event_listener, "Gtk:AtkTable:row-reordered");
837 add_signal_listener (generic_event_listener, "Gtk:AtkTable:row-deleted");
838 add_signal_listener (generic_event_listener, "Gtk:AtkTable:column-inserted");
839 add_signal_listener (generic_event_listener, "Gtk:AtkTable:column-reordered");
840 add_signal_listener (generic_event_listener, "Gtk:AtkTable:column-deleted");
841 add_signal_listener (generic_event_listener, "Gtk:AtkTable:model-changed");
844 * May add the following listeners to implement preemptive key listening for GTK+
846 * atk_add_global_event_listener (spi_atk_bridge_widgetkey_listener, "Gtk:GtkWidget:key-press-event");
847 * atk_add_global_event_listener (spi_atk_bridge_widgetkey_listener, "Gtk:GtkWidget:key-release-event");
849 atk_bridge_key_event_listener_id = atk_add_key_event_listener (spi_atk_bridge_key_listener, NULL);
852 /*---------------------------------------------------------------------------*/
855 * De-registers all ATK signal handlers.
858 spi_atk_deregister_event_listeners (void)
861 GArray *ids = listener_ids;
864 if (atk_bridge_focus_tracker_id)
865 atk_remove_focus_tracker (atk_bridge_focus_tracker_id);
867 for (i = 0; ids && i < ids->len; i++)
869 atk_remove_global_event_listener (g_array_index (ids, guint, i));
872 if (atk_bridge_key_event_listener_id)
873 atk_remove_key_event_listener (atk_bridge_key_event_listener_id);
876 /*---------------------------------------------------------------------------*/
879 * TODO This function seems out of place here.
881 * Emits fake deactivate signals on all top-level windows.
882 * Used when shutting down AT-SPI, ensuring that all
883 * windows have been removed on the client side.
886 spi_atk_tidy_windows (void)
892 root = atk_get_root ();
893 n_children = atk_object_get_n_accessible_children (root);
894 for (i = 0; i < n_children; i++)
897 AtkStateSet *stateset;
900 child = atk_object_ref_accessible_child (root, i);
901 stateset = atk_object_ref_state_set (child);
903 name = atk_object_get_name (child);
904 if (atk_state_set_contains_state (stateset, ATK_STATE_ACTIVE))
906 emit(child, ITF_EVENT_WINDOW, "deactivate", NULL, 0, 0, DBUS_TYPE_STRING_AS_STRING, name);
908 g_object_unref (stateset);
910 emit(child, ITF_EVENT_WINDOW, "destroy", NULL, 0, 0, DBUS_TYPE_STRING_AS_STRING, name);
911 g_object_unref (child);
915 /*END------------------------------------------------------------------------*/