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 /*---------------------------------------------------------------------------*/
57 Accessibility_DeviceEventController_notifyListenersSync(const Accessibility_DeviceEvent *key_event)
61 dbus_bool_t consumed = FALSE;
64 dbus_message_new_method_call(SPI_DBUS_NAME_REGISTRY,
65 SPI_DBUS_PATH_REGISTRY,
66 SPI_DBUS_INTERFACE_DEC,
67 "notifyListenersSync");
69 dbus_error_init(&error);
70 if (spi_dbus_marshal_deviceEvent(message, key_event))
72 DBusMessage *reply = dbus_connection_send_with_reply_and_block(atk_adaptor_app_data->bus, message, 1000, &error);
76 dbus_error_init(&error);
77 dbus_message_get_args(reply, &error, DBUS_TYPE_BOOLEAN, &consumed, DBUS_TYPE_INVALID);
78 dbus_message_unref(reply);
81 dbus_message_unref(message);
86 spi_init_keystroke_from_atk_key_event (Accessibility_DeviceEvent *keystroke,
87 AtkKeyEventStruct *event)
89 keystroke->id = (dbus_int32_t) event->keyval;
90 keystroke->hw_code = (dbus_int16_t) event->keycode;
91 keystroke->timestamp = (dbus_uint32_t) event->timestamp;
92 keystroke->modifiers = (dbus_uint16_t) (event->state & 0xFFFF);
97 keystroke->event_string = g_strdup (event->string);
98 c = g_utf8_get_char_validated (event->string, -1);
99 if (c > 0 && g_unichar_isprint (c))
100 keystroke->is_text = TRUE;
102 keystroke->is_text = FALSE;
106 keystroke->event_string = g_strdup ("");
107 keystroke->is_text = FALSE;
111 case (ATK_KEY_EVENT_PRESS):
112 keystroke->type = Accessibility_KEY_PRESSED_EVENT;
114 case (ATK_KEY_EVENT_RELEASE):
115 keystroke->type = Accessibility_KEY_RELEASED_EVENT;
122 g_print ("key_event type %d; val=%d code=%d modifiers=%x name=%s is_text=%d, time=%lx\n",
123 (int) keystroke->type, (int) keystroke->id, (int) keystroke->hw_code,
124 (int) keystroke->modifiers,
125 keystroke->event_string, (int) keystroke->is_text, (unsigned long) keystroke->timestamp);
131 spi_atk_bridge_key_listener (AtkKeyEventStruct *event, gpointer data)
134 Accessibility_DeviceEvent key_event;
136 spi_init_keystroke_from_atk_key_event (&key_event, event);
138 result = Accessibility_DeviceEventController_notifyListenersSync (&key_event);
140 if (key_event.event_string) g_free (key_event.event_string);
146 /*---------------------------------------------------------------------------*/
149 * Emits an AT-SPI event.
150 * AT-SPI events names are split into three parts:
152 * This is mapped onto D-Bus events as:
153 * D-Bus Interface:Signal Name:Detail argument
155 * Marshals a basic type into the 'any_data' attribute of
160 * This is a rather annoying function needed to replace
161 * NULL values of strings with the empty string. Null string
162 * values can be created by the atk_object_get_name or text selection
165 provide_defaults(const gint type,
170 case DBUS_TYPE_STRING:
171 case DBUS_TYPE_OBJECT_PATH:
182 /* TODO Should we bother emiting events for objects that have not yet
183 * been added to the tree?
185 * This gets difficult. Its entirely possible that an Accessible would have been
186 * added to the tree, but not yet reached the clients.
187 * In this case we would be wrongly surpressing an event.
190 emit(AtkObject *accessible,
194 dbus_int32_t detail1,
195 dbus_int32_t detail2,
200 DBusMessageIter iter, sub;
201 gchar *path, *cname, *t;
203 if (!klass) klass = "";
204 if (!major) major = "";
205 if (!minor) minor = "";
208 * This is very annoying, but as '-' isn't a legal signal
209 * name in D-Bus (Why not??!?) The names need converting
210 * on this side, and again on the client side.
212 cname = g_strdup(major);
213 while ((t = strchr(cname, '-')) != NULL) *t = '_';
215 path = atk_dbus_get_path(accessible);
216 sig = dbus_message_new_signal(path, klass, cname);
220 dbus_message_iter_init_append(sig, &iter);
222 dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &minor);
223 dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &detail1);
224 dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &detail2);
226 dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, type, &sub);
228 * I need to convert the string signature to an integer type signature.
229 * DBUS_TYPE_INT32 is defined as 'i' whereas the string is "i".
230 * I should just be able to cast the first character of the string to an
233 val = provide_defaults((int) *type, val);
234 dbus_message_iter_append_basic(&sub, (int) *type, &val);
235 dbus_message_iter_close_container(&iter, &sub);
237 dbus_connection_send(atk_adaptor_app_data->bus, sig, NULL);
238 dbus_message_unref(sig);
241 /*---------------------------------------------------------------------------*/
244 * Emits an AT-SPI event, marshalling a BoundingBox structure into the
245 * 'any_data' variant of the event.
248 emit_rect(AtkObject *accessible,
255 DBusMessageIter iter, variant, sub;
256 gchar *path, *cname, *t;
257 dbus_int32_t dummy = 0;
259 if (!klass) klass = "";
260 if (!major) major = "";
261 if (!minor) minor = "";
264 * This is very annoying, but as '-' isn't a legal signal
265 * name in D-Bus (Why not??!?) The names need converting
266 * on this side, and again on the client side.
268 cname = g_strdup(major);
269 while ((t = strchr(cname, '-')) != NULL) *t = '_';
271 path = atk_dbus_get_path(accessible);
272 sig = dbus_message_new_signal(path, klass, cname);
276 dbus_message_iter_init_append (sig, &iter);
277 dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &minor);
278 dbus_message_iter_append_basic (&iter, DBUS_TYPE_INT32, &dummy);
279 dbus_message_iter_append_basic (&iter, DBUS_TYPE_INT32, &dummy);
281 dbus_message_iter_open_container (&iter, DBUS_TYPE_VARIANT, "(iiii)", &variant);
282 dbus_message_iter_open_container (&variant, DBUS_TYPE_STRUCT, NULL, &sub);
283 dbus_message_iter_append_basic (&sub, DBUS_TYPE_INT32, &(rect->x));
284 dbus_message_iter_append_basic (&sub, DBUS_TYPE_INT32, &(rect->y));
285 dbus_message_iter_append_basic (&sub, DBUS_TYPE_INT32, &(rect->width));
286 dbus_message_iter_append_basic (&sub, DBUS_TYPE_INT32, &(rect->height));
287 dbus_message_iter_close_container (&variant, &sub);
288 dbus_message_iter_close_container (&iter, &variant);
290 dbus_connection_send(atk_adaptor_app_data->bus, sig, NULL);
293 /*---------------------------------------------------------------------------*/
296 * The tree update listener handles the following Atk signals:
298 * Gtk:AtkObject:property-change
300 * With the folowing property names:
303 * accessible-description
306 * It updates the server side accessible-object database, which
307 * will then syncronize with the client-side accessible cache.
311 tree_update_listener (GSignalInvocationHint *signal_hint,
312 guint n_param_values,
313 const GValue *param_values,
316 AtkObject *accessible;
317 AtkPropertyValues *values;
318 const gchar *pname = NULL;
320 accessible = g_value_get_object (¶m_values[0]);
321 values = (AtkPropertyValues*) g_value_get_pointer (¶m_values[1]);
323 pname = values[0].property_name;
325 if (strcmp (pname, "accessible-name") == 0)
327 atk_dbus_notify_change(accessible);
329 else if (strcmp (pname, "accessible-description") == 0)
331 atk_dbus_notify_change(accessible);
333 else if (strcmp (pname, "accessible-parent") == 0)
335 atk_dbus_notify_change(accessible);
341 * Handles the ATK signal 'Gtk:AtkObject:children-changed'.
343 * It updates the server side accessible-object database, which
344 * will then syncronize with the client-side accessible cache.
348 tree_update_children_listener (GSignalInvocationHint *signal_hint,
349 guint n_param_values,
350 const GValue *param_values,
353 AtkObject *accessible;
354 const gchar *detail = NULL;
356 gboolean child_needs_unref = FALSE;
358 if (signal_hint->detail)
359 detail = g_quark_to_string (signal_hint->detail);
361 accessible = g_value_get_object (¶m_values[0]);
362 if (!strcmp (detail, "add"))
365 int index = g_value_get_uint (param_values + 1);
366 child = g_value_get_pointer (param_values + 2);
367 if (ATK_IS_OBJECT (child))
368 g_object_ref (child);
370 child = atk_object_ref_accessible_child (accessible, index);
371 if (ATK_IS_OBJECT (child))
373 atk_dbus_register_subtree (child);
374 g_object_unref (child);
377 atk_dbus_register_subtree(accessible);
382 /*---------------------------------------------------------------------------*/
385 * The focus listener handles the ATK 'focus' signal and forwards it
386 * as the AT-SPI event, 'focus:'
389 focus_tracker (AtkObject *accessible)
391 emit(accessible, ITF_EVENT_FOCUS, "focus", "", 0, 0, DBUS_TYPE_INT32_AS_STRING, 0);
394 /*---------------------------------------------------------------------------*/
396 #define PCHANGE "property-change"
399 * This handler handles the following ATK signals and
400 * converts them to AT-SPI events:
402 * Gtk:AtkObject:property-change -> object:property-change:(property-name)
404 * The property-name is part of the ATK property-change signal.
407 property_event_listener (GSignalInvocationHint *signal_hint,
408 guint n_param_values,
409 const GValue *param_values,
412 AtkObject *accessible;
413 AtkPropertyValues *values;
415 const gchar *pname = NULL;
421 accessible = g_value_get_object (¶m_values[0]);
422 values = (AtkPropertyValues*) g_value_get_pointer (¶m_values[1]);
424 pname = values[0].property_name;
426 /* TODO Could improve this control statement by matching
427 * on only the end of the signal names,
429 if (strcmp (pname, "accessible-table-summary") == 0)
431 otemp = atk_table_get_summary(ATK_TABLE (accessible));
432 stemp = atk_dbus_get_path(otemp);
433 emit(accessible, ITF_EVENT_OBJECT, PCHANGE, pname, 0, 0, DBUS_TYPE_OBJECT_PATH_AS_STRING, stemp);
435 else if (strcmp (pname, "accessible-table-column-header") == 0)
437 i = g_value_get_int (&(values->new_value));
438 otemp = atk_table_get_column_header(ATK_TABLE (accessible), i);
439 stemp = atk_dbus_get_path(otemp);
440 emit(accessible, ITF_EVENT_OBJECT, PCHANGE, pname, 0, 0, DBUS_TYPE_OBJECT_PATH_AS_STRING, stemp);
442 else if (strcmp (pname, "accessible-table-row-header") == 0)
444 i = g_value_get_int (&(values->new_value));
445 otemp = atk_table_get_row_header(ATK_TABLE (accessible), i);
446 stemp = atk_dbus_get_path(otemp);
447 emit(accessible, ITF_EVENT_OBJECT, PCHANGE, pname, 0, 0, DBUS_TYPE_OBJECT_PATH_AS_STRING, stemp);
449 else if (strcmp (pname, "accessible-table-row-description") == 0)
451 i = g_value_get_int (&(values->new_value));
452 stemp = atk_table_get_row_description(ATK_TABLE (accessible), i);
453 emit(accessible, ITF_EVENT_OBJECT, PCHANGE, pname, 0, 0, DBUS_TYPE_STRING_AS_STRING, stemp);
455 else if (strcmp (pname, "accessible-table-column-description") == 0)
457 i = g_value_get_int (&(values->new_value));
458 stemp = atk_table_get_column_description(ATK_TABLE (accessible), i);
459 emit(accessible, ITF_EVENT_OBJECT, PCHANGE, pname, 0, 0, DBUS_TYPE_STRING_AS_STRING, stemp);
461 else if (strcmp (pname, "accessible-table-caption-object") == 0)
463 otemp = atk_table_get_caption(ATK_TABLE(accessible));
464 stemp = atk_object_get_name(otemp);
465 emit(accessible, ITF_EVENT_OBJECT, PCHANGE, pname, 0, 0, DBUS_TYPE_STRING_AS_STRING, stemp);
469 emit(accessible, ITF_EVENT_OBJECT, PCHANGE, pname, 0, 0, DBUS_TYPE_INT32_AS_STRING, 0);
474 /*---------------------------------------------------------------------------*/
476 #define STATE_CHANGED "state-changed"
479 * The state event listener handles 'Gtk:AtkObject:state-change' ATK signals
480 * and forwards them as object:state-changed:(param-name) AT-SPI events. Where
481 * the param-name is part of the ATK state-change signal.
484 state_event_listener (GSignalInvocationHint *signal_hint,
485 guint n_param_values,
486 const GValue *param_values,
489 AtkObject *accessible;
493 accessible = ATK_OBJECT(g_value_get_object (¶m_values[0]));
494 pname = g_strdup (g_value_get_string (¶m_values[1]));
496 /* TODO - Possibly ignore a change to the 'defunct' state.
497 * This is because without reference counting defunct objects should be removed.
499 detail1 = (g_value_get_boolean (¶m_values[2])) ? 1 : 0;
500 emit(accessible, ITF_EVENT_OBJECT, STATE_CHANGED, pname, detail1, 0, DBUS_TYPE_INT32_AS_STRING, 0);
505 /*---------------------------------------------------------------------------*/
508 * The window event listener handles the following ATK signals and forwards
509 * them as AT-SPI events:
511 * window:create -> window:create
512 * window:destroy -> window:destroy
513 * window:minimize -> window:minimize
514 * window:maximize -> window:maximize
515 * window:activate -> window:activate
516 * window:deactivate -> window:deactivate
519 window_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_WINDOW, name, "", 0, 0, DBUS_TYPE_STRING_AS_STRING, s);
538 /*---------------------------------------------------------------------------*/
541 * The document event listener handles the following ATK signals
542 * and converts them to AT-SPI events:
544 * Gtk:AtkDocument:load-complete -> document:load-complete
545 * Gtk:AtkDocument:load-stopped -> document:load-stopped
546 * Gtk:AtkDocument:reload -> document:reload
549 document_event_listener (GSignalInvocationHint *signal_hint,
550 guint n_param_values,
551 const GValue *param_values,
554 AtkObject *accessible;
555 GSignalQuery signal_query;
556 const gchar *name, *s;
558 g_signal_query (signal_hint->signal_id, &signal_query);
559 name = signal_query.signal_name;
561 accessible = ATK_OBJECT(g_value_get_object(¶m_values[0]));
562 s = atk_object_get_name (accessible);
563 emit(accessible, ITF_EVENT_DOCUMENT, name, "", 0, 0, DBUS_TYPE_STRING_AS_STRING, s);
568 /*---------------------------------------------------------------------------*/
571 * Signal handler for "Gtk:AtkComponent:bounds-changed". Converts
572 * this to an AT-SPI event - "object:bounds-changed".
575 bounds_event_listener (GSignalInvocationHint *signal_hint,
576 guint n_param_values,
577 const GValue *param_values,
580 AtkObject *accessible;
581 AtkRectangle *atk_rect;
582 GSignalQuery signal_query;
583 const gchar *name, *s;
585 g_signal_query (signal_hint->signal_id, &signal_query);
586 name = signal_query.signal_name;
588 accessible = ATK_OBJECT(g_value_get_object(¶m_values[0]));
590 if (G_VALUE_HOLDS_BOXED (param_values + 1))
591 atk_rect = g_value_get_boxed (param_values + 1);
593 emit_rect(accessible, ITF_EVENT_OBJECT, name, "", atk_rect);
597 /*---------------------------------------------------------------------------*/
600 * Handles the ATK signal 'Gtk:AtkObject:active-descendant-changed' and
601 * converts it to the AT-SPI signal - 'object:active-descendant-changed'.
605 active_descendant_event_listener (GSignalInvocationHint *signal_hint,
606 guint n_param_values,
607 const GValue *param_values,
610 AtkObject *accessible;
612 GSignalQuery signal_query;
613 const gchar *name, *minor;
617 g_signal_query (signal_hint->signal_id, &signal_query);
618 name = signal_query.signal_name;
620 accessible = ATK_OBJECT(g_value_get_object(¶m_values[0]));
621 child = ATK_OBJECT(g_value_get_pointer (¶m_values[1]));
622 g_return_val_if_fail (ATK_IS_OBJECT (child), TRUE);
623 minor = g_quark_to_string (signal_hint->detail);
625 detail1 = atk_object_get_index_in_parent (child);
626 s = atk_dbus_get_path(child);
628 emit(accessible, ITF_EVENT_OBJECT, name, "", detail1, 0, DBUS_TYPE_OBJECT_PATH_AS_STRING, s);
633 /*---------------------------------------------------------------------------*/
636 * Handles the ATK signal 'Gtk:AtkHypertext:link-selected' and
637 * converts it to the AT-SPI signal - 'object:link-selected'
641 link_selected_event_listener (GSignalInvocationHint *signal_hint,
642 guint n_param_values,
643 const GValue *param_values,
646 AtkObject *accessible;
647 GSignalQuery signal_query;
648 const gchar *name, *minor;
651 g_signal_query (signal_hint->signal_id, &signal_query);
652 name = signal_query.signal_name;
654 accessible = ATK_OBJECT(g_value_get_object(¶m_values[0]));
655 minor = g_quark_to_string (signal_hint->detail);
657 if (G_VALUE_TYPE (¶m_values[1]) == G_TYPE_INT)
658 detail1 = g_value_get_int (¶m_values[1]);
660 emit(accessible, ITF_EVENT_OBJECT, name, minor, detail1, 0, DBUS_TYPE_INT32_AS_STRING, 0);
664 /*---------------------------------------------------------------------------*/
667 * Handles the ATK signal 'Gtk:AtkText:text-changed' and
668 * converts it to the AT-SPI signal - 'object:text-changed'
672 text_changed_event_listener (GSignalInvocationHint *signal_hint,
673 guint n_param_values,
674 const GValue *param_values,
677 AtkObject *accessible;
678 GSignalQuery signal_query;
679 const gchar *name, *minor;
681 gint detail1, detail2;
683 g_signal_query (signal_hint->signal_id, &signal_query);
684 name = signal_query.signal_name;
686 accessible = ATK_OBJECT(g_value_get_object(¶m_values[0]));
687 minor = g_quark_to_string (signal_hint->detail);
689 if (G_VALUE_TYPE (¶m_values[1]) == G_TYPE_INT)
690 detail1 = g_value_get_int (¶m_values[1]);
692 if (G_VALUE_TYPE (¶m_values[2]) == G_TYPE_INT)
693 detail2 = g_value_get_int (¶m_values[2]);
695 selected = atk_text_get_text (ATK_TEXT (accessible), detail1, detail1+detail2);
697 emit(accessible, ITF_EVENT_OBJECT, name, minor, detail1, detail2, DBUS_TYPE_STRING_AS_STRING, selected);
701 /*---------------------------------------------------------------------------*/
704 * Handles the ATK signal 'Gtk:AtkText:text-selection-changed' and
705 * converts it to the AT-SPI signal - 'object:text-selection-changed'
709 text_selection_changed_event_listener (GSignalInvocationHint *signal_hint,
710 guint n_param_values,
711 const GValue *param_values,
714 AtkObject *accessible;
715 GSignalQuery signal_query;
716 const gchar *name, *minor;
717 gint detail1, detail2;
719 g_signal_query (signal_hint->signal_id, &signal_query);
720 name = signal_query.signal_name;
722 accessible = ATK_OBJECT(g_value_get_object(¶m_values[0]));
723 minor = g_quark_to_string (signal_hint->detail);
725 if (G_VALUE_TYPE (¶m_values[1]) == G_TYPE_INT)
726 detail1 = g_value_get_int (¶m_values[1]);
728 if (G_VALUE_TYPE (¶m_values[2]) == G_TYPE_INT)
729 detail2 = g_value_get_int (¶m_values[2]);
731 emit(accessible, ITF_EVENT_OBJECT, name, minor, detail1, detail2, DBUS_TYPE_STRING_AS_STRING, "");
735 /*---------------------------------------------------------------------------*/
738 * Generic signal converter and forwarder.
740 * Klass (Interface) org.freedesktop.atspi.Event.Object
741 * Major is the signal name.
748 generic_event_listener (GSignalInvocationHint *signal_hint,
749 guint n_param_values,
750 const GValue *param_values,
753 AtkObject *accessible;
754 GSignalQuery signal_query;
757 g_signal_query (signal_hint->signal_id, &signal_query);
758 name = signal_query.signal_name;
760 accessible = ATK_OBJECT(g_value_get_object(¶m_values[0]));
761 emit(accessible, ITF_EVENT_OBJECT, name, "", 0, 0, DBUS_TYPE_INT32_AS_STRING, 0);
765 /*---------------------------------------------------------------------------*/
768 * Registers the provided function as a handler for the given signal name
769 * and stores the signal id returned so that the function may be
770 * de-registered later.
773 add_signal_listener (GSignalEmissionHook listener, const char *signal_name)
777 id = atk_add_global_event_listener (listener, signal_name);
778 g_array_append_val (listener_ids, id);
782 * Initialization for the signal handlers.
784 * Registers all required signal handlers.
787 spi_atk_register_event_listeners (void)
790 * Kludge to make sure the Atk interface types are registered, otherwise
791 * the AtkText signal handlers below won't get registered
793 GObject *ao = g_object_new (ATK_TYPE_OBJECT, NULL);
794 AtkObject *bo = atk_no_op_object_new (ao);
796 g_object_unref (G_OBJECT (bo));
799 /* Register for focus event notifications, and register app with central registry */
800 listener_ids = g_array_sized_new (FALSE, TRUE, sizeof (guint), 16);
802 atk_bridge_focus_tracker_id = atk_add_focus_tracker (focus_tracker);
804 add_signal_listener (tree_update_listener, "Gtk:AtkObject:property-change");
805 add_signal_listener (tree_update_children_listener, "Gtk:AtkObject:children-changed");
807 add_signal_listener (property_event_listener, "Gtk:AtkObject:property-change");
808 add_signal_listener (window_event_listener, "window:create");
809 add_signal_listener (window_event_listener, "window:destroy");
810 add_signal_listener (window_event_listener, "window:minimize");
811 add_signal_listener (window_event_listener, "window:maximize");
812 add_signal_listener (window_event_listener, "window:restore");
813 add_signal_listener (window_event_listener, "window:activate");
814 add_signal_listener (window_event_listener, "window:deactivate");
815 add_signal_listener (document_event_listener, "Gtk:AtkDocument:load-complete");
816 add_signal_listener (document_event_listener, "Gtk:AtkDocument:reload");
817 add_signal_listener (document_event_listener, "Gtk:AtkDocument:load-stopped");
818 add_signal_listener (state_event_listener, "Gtk:AtkObject:state-change");
819 add_signal_listener (active_descendant_event_listener, "Gtk:AtkObject:active-descendant-changed");
820 add_signal_listener (bounds_event_listener, "Gtk:AtkComponent:bounds-changed");
821 add_signal_listener (text_selection_changed_event_listener, "Gtk:AtkText:text-selection-changed");
822 add_signal_listener (text_changed_event_listener, "Gtk:AtkText:text-changed");
823 add_signal_listener (link_selected_event_listener, "Gtk:AtkHypertext:link-selected");
824 add_signal_listener (generic_event_listener, "Gtk:AtkObject:visible-data-changed");
825 add_signal_listener (generic_event_listener, "Gtk:AtkSelection:selection-changed");
826 add_signal_listener (generic_event_listener, "Gtk:AtkText:text-caret-moved");
827 add_signal_listener (generic_event_listener, "Gtk:AtkTable:row-inserted");
828 add_signal_listener (generic_event_listener, "Gtk:AtkTable:row-reordered");
829 add_signal_listener (generic_event_listener, "Gtk:AtkTable:row-deleted");
830 add_signal_listener (generic_event_listener, "Gtk:AtkTable:column-inserted");
831 add_signal_listener (generic_event_listener, "Gtk:AtkTable:column-reordered");
832 add_signal_listener (generic_event_listener, "Gtk:AtkTable:column-deleted");
833 add_signal_listener (generic_event_listener, "Gtk:AtkTable:model-changed");
836 * May add the following listeners to implement preemptive key listening for GTK+
838 * atk_add_global_event_listener (spi_atk_bridge_widgetkey_listener, "Gtk:GtkWidget:key-press-event");
839 * atk_add_global_event_listener (spi_atk_bridge_widgetkey_listener, "Gtk:GtkWidget:key-release-event");
841 atk_bridge_key_event_listener_id = atk_add_key_event_listener (spi_atk_bridge_key_listener, NULL);
844 /*---------------------------------------------------------------------------*/
847 * De-registers all ATK signal handlers.
850 spi_atk_deregister_event_listeners (void)
853 GArray *ids = listener_ids;
856 if (atk_bridge_focus_tracker_id)
857 atk_remove_focus_tracker (atk_bridge_focus_tracker_id);
859 for (i = 0; ids && i < ids->len; i++)
861 atk_remove_global_event_listener (g_array_index (ids, guint, i));
864 if (atk_bridge_key_event_listener_id)
865 atk_remove_key_event_listener (atk_bridge_key_event_listener_id);
868 /*---------------------------------------------------------------------------*/
871 * TODO This function seems out of place here.
873 * Emits fake deactivate signals on all top-level windows.
874 * Used when shutting down AT-SPI, ensuring that all
875 * windows have been removed on the client side.
878 spi_atk_tidy_windows (void)
884 root = atk_get_root ();
885 n_children = atk_object_get_n_accessible_children (root);
886 for (i = 0; i < n_children; i++)
889 AtkStateSet *stateset;
892 child = atk_object_ref_accessible_child (root, i);
893 stateset = atk_object_ref_state_set (child);
895 name = atk_object_get_name (child);
896 if (atk_state_set_contains_state (stateset, ATK_STATE_ACTIVE))
898 emit(child, ITF_EVENT_WINDOW, "deactivate", NULL, 0, 0, DBUS_TYPE_STRING_AS_STRING, name);
900 g_object_unref (stateset);
902 emit(child, ITF_EVENT_WINDOW, "destroy", NULL, 0, 0, DBUS_TYPE_STRING_AS_STRING, name);
903 g_object_unref (child);
907 /*END------------------------------------------------------------------------*/