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 "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.freedesktop.atspi.Event.Document"
45 #define ITF_EVENT_FOCUS "org.freedesktop.atspi.Event.Focus"
47 /*---------------------------------------------------------------------------*/
50 set_reply (DBusPendingCall * pending, void *user_data)
52 void **replyptr = (void **) user_data;
54 *replyptr = dbus_pending_call_steal_reply (pending);
58 send_and_allow_reentry (DBusConnection * bus, DBusMessage * message)
60 DBusPendingCall *pending;
61 DBusMessage *reply = NULL;
63 if (!dbus_connection_send_with_reply (bus, message, &pending, -1))
67 dbus_pending_call_set_notify (pending, set_reply, (void *) &reply, NULL);
70 if (!dbus_connection_read_write_dispatch (bus, -1))
76 /*---------------------------------------------------------------------------*/
79 * Functionality related to sending device events from the application.
81 * This is used for forwarding key events on to the registry daemon.
85 Accessibility_DeviceEventController_NotifyListenersSync (const
86 Accessibility_DeviceEvent
91 dbus_bool_t consumed = FALSE;
94 dbus_message_new_method_call (SPI_DBUS_NAME_REGISTRY,
96 SPI_DBUS_INTERFACE_DEC,
97 "NotifyListenersSync");
99 dbus_error_init (&error);
100 if (spi_dbus_marshal_deviceEvent (message, key_event))
103 send_and_allow_reentry (spi_global_app_data->bus, message);
107 dbus_error_init (&error);
108 dbus_message_get_args (reply, &error, DBUS_TYPE_BOOLEAN, &consumed,
110 dbus_message_unref (reply);
113 dbus_message_unref (message);
118 spi_init_keystroke_from_atk_key_event (Accessibility_DeviceEvent * keystroke,
119 AtkKeyEventStruct * event)
121 keystroke->id = (dbus_int32_t) event->keyval;
122 keystroke->hw_code = (dbus_int16_t) event->keycode;
123 keystroke->timestamp = (dbus_uint32_t) event->timestamp;
124 keystroke->modifiers = (dbus_uint16_t) (event->state & 0xFFFF);
129 keystroke->event_string = g_strdup (event->string);
130 c = g_utf8_get_char_validated (event->string, -1);
131 if (c > 0 && g_unichar_isprint (c))
132 keystroke->is_text = TRUE;
134 keystroke->is_text = FALSE;
138 keystroke->event_string = g_strdup ("");
139 keystroke->is_text = FALSE;
143 case (ATK_KEY_EVENT_PRESS):
144 keystroke->type = Accessibility_KEY_PRESSED_EVENT;
146 case (ATK_KEY_EVENT_RELEASE):
147 keystroke->type = Accessibility_KEY_RELEASED_EVENT;
155 ("key_event type %d; val=%d code=%d modifiers=%x name=%s is_text=%d, time=%lx\n",
156 (int) keystroke->type, (int) keystroke->id, (int) keystroke->hw_code,
157 (int) keystroke->modifiers, keystroke->event_string,
158 (int) keystroke->is_text, (unsigned long) keystroke->timestamp);
164 spi_atk_bridge_key_listener (AtkKeyEventStruct * event, gpointer data)
167 Accessibility_DeviceEvent key_event;
169 spi_init_keystroke_from_atk_key_event (&key_event, event);
172 Accessibility_DeviceEventController_NotifyListenersSync (&key_event);
174 if (key_event.event_string)
175 g_free (key_event.event_string);
180 /*---------------------------------------------------------------------------*/
183 convert_signal_name (const gchar * s)
185 gchar *ret = g_strdup (s);
190 ret[0] = toupper (ret[0]);
191 while ((t = strchr (ret, '-')) != NULL)
193 memmove (t, t + 1, strlen (t));
200 replace_null (const gint type,
205 case DBUS_TYPE_STRING:
206 case DBUS_TYPE_OBJECT_PATH:
217 append_basic (DBusMessageIter *iter,
223 dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, type, &sub);
225 val = replace_null ((int) *type, val);
226 dbus_message_iter_append_basic(&sub, (int) *type, &val);
228 dbus_message_iter_close_container(iter, &sub);
232 append_rect (DBusMessageIter *iter,
236 DBusMessageIter variant, sub;
237 const AtkRectangle *rect = (const AtkRectangle *) val;
239 dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, type, &variant);
241 dbus_message_iter_open_container (&variant, DBUS_TYPE_STRUCT, NULL, &sub);
243 dbus_message_iter_append_basic (&sub, DBUS_TYPE_INT32, &(rect->x));
244 dbus_message_iter_append_basic (&sub, DBUS_TYPE_INT32, &(rect->y));
245 dbus_message_iter_append_basic (&sub, DBUS_TYPE_INT32, &(rect->width));
246 dbus_message_iter_append_basic (&sub, DBUS_TYPE_INT32, &(rect->height));
248 dbus_message_iter_close_container (&variant, &sub);
250 dbus_message_iter_close_container(iter, &variant);
254 append_object (DBusMessageIter *iter,
258 spi_object_append_v_reference (iter, ATK_OBJECT (val));
262 * Emits an AT-SPI event.
263 * AT-SPI events names are split into three parts:
265 * This is mapped onto D-Bus events as:
266 * D-Bus Interface:Signal Name:Detail argument
268 * Marshals a basic type into the 'any_data' attribute of
272 emit_event (AtkObject *obj,
276 dbus_int32_t detail1,
277 dbus_int32_t detail2,
280 void (*append_variant) (DBusMessageIter *, const char *, const void *))
282 DBusConnection *bus = spi_global_app_data->bus;
283 const char *path = spi_register_object_to_path (spi_global_register,
288 DBusMessageIter iter;
290 if (!klass) klass = "";
291 if (!major) major = "";
292 if (!minor) minor = "";
293 if (!type) type = "u";
296 * This is very annoying, but as '-' isn't a legal signal
297 * name in D-Bus (Why not??!?) The names need converting
298 * on this side, and again on the client side.
300 cname = g_strdup(major);
301 while ((t = strchr(cname, '-')) != NULL) *t = '_';
302 sig = dbus_message_new_signal(path, klass, cname);
305 dbus_message_iter_init_append(sig, &iter);
307 dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &minor);
308 dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &detail1);
309 dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &detail2);
311 append_variant (&iter, type, val);
313 dbus_connection_send(bus, sig, NULL);
314 dbus_message_unref(sig);
317 /*---------------------------------------------------------------------------*/
320 * The focus listener handles the ATK 'focus' signal and forwards it
321 * as the AT-SPI event, 'focus:'
324 focus_tracker (AtkObject * accessible)
326 emit_event (accessible, ITF_EVENT_FOCUS, "focus", "", 0, 0,
327 DBUS_TYPE_INT32_AS_STRING, 0, append_basic);
330 /*---------------------------------------------------------------------------*/
332 #define PCHANGE "property-change"
335 * This handler handles the following ATK signals and
336 * converts them to AT-SPI events:
338 * Gtk:AtkObject:property-change -> object:property-change:(property-name)
340 * The property-name is part of the ATK property-change signal.
343 property_event_listener (GSignalInvocationHint * signal_hint,
344 guint n_param_values,
345 const GValue * param_values, gpointer data)
347 AtkObject *accessible;
348 AtkPropertyValues *values;
350 const gchar *pname = NULL;
356 accessible = g_value_get_object (¶m_values[0]);
357 values = (AtkPropertyValues *) g_value_get_pointer (¶m_values[1]);
359 pname = values[0].property_name;
361 /* TODO Could improve this control statement by matching
362 * on only the end of the signal names,
364 if (strcmp (pname, "accessible-name") == 0)
366 s1 = atk_object_get_name (accessible);
368 emit_event (accessible, ITF_EVENT_OBJECT, PCHANGE, pname, 0, 0,
369 DBUS_TYPE_STRING_AS_STRING, s1, append_basic);
371 if (strcmp (pname, "accessible-description") == 0)
373 s1 = atk_object_get_description (accessible);
375 emit_event (accessible, ITF_EVENT_OBJECT, PCHANGE, pname, 0, 0,
376 DBUS_TYPE_STRING_AS_STRING, s1, append_basic);
378 if (strcmp (pname, "accessible-parent") == 0)
380 otemp = atk_object_get_parent (accessible);
382 emit_event (accessible, ITF_EVENT_OBJECT, PCHANGE, pname, 0, 0,
383 "(so)", otemp, append_object);
385 if (strcmp (pname, "accessible-table-summary") == 0)
387 otemp = atk_table_get_summary (ATK_TABLE (accessible));
389 emit_event (accessible, ITF_EVENT_OBJECT, PCHANGE, pname, 0, 0,
390 "(so)", otemp, append_object);
392 else if (strcmp (pname, "accessible-table-column-header") == 0)
394 i = g_value_get_int (&(values->new_value));
395 otemp = atk_table_get_column_header (ATK_TABLE (accessible), i);
397 emit_event (accessible, ITF_EVENT_OBJECT, PCHANGE, pname, 0, 0,
398 "(so)", otemp, append_object);
400 else if (strcmp (pname, "accessible-table-row-header") == 0)
402 i = g_value_get_int (&(values->new_value));
403 otemp = atk_table_get_row_header (ATK_TABLE (accessible), i);
405 emit_event (accessible, ITF_EVENT_OBJECT, PCHANGE, pname, 0, 0,
406 "(so)", otemp, append_object);
408 else if (strcmp (pname, "accessible-table-row-description") == 0)
410 i = g_value_get_int (&(values->new_value));
411 s1 = atk_table_get_row_description (ATK_TABLE (accessible), i);
412 emit_event (accessible, ITF_EVENT_OBJECT, PCHANGE, pname, 0, 0,
413 DBUS_TYPE_STRING_AS_STRING, s1, append_basic);
415 else if (strcmp (pname, "accessible-table-column-description") == 0)
417 i = g_value_get_int (&(values->new_value));
418 s1 = atk_table_get_column_description (ATK_TABLE (accessible), i);
419 emit_event (accessible, ITF_EVENT_OBJECT, PCHANGE, pname, 0, 0,
420 DBUS_TYPE_STRING_AS_STRING, s1, append_basic);
422 else if (strcmp (pname, "accessible-table-caption-object") == 0)
424 otemp = atk_table_get_caption (ATK_TABLE (accessible));
425 emit_event (accessible, ITF_EVENT_OBJECT, PCHANGE, pname, 0, 0,
426 "(so)", otemp, append_object);
430 emit_event (accessible, ITF_EVENT_OBJECT, PCHANGE, pname, 0, 0,
431 DBUS_TYPE_INT32_AS_STRING, 0, append_basic);
436 /*---------------------------------------------------------------------------*/
438 #define STATE_CHANGED "state-changed"
441 * The state event listener handles 'Gtk:AtkObject:state-change' ATK signals
442 * and forwards them as object:state-changed:(param-name) AT-SPI events. Where
443 * the param-name is part of the ATK state-change signal.
446 state_event_listener (GSignalInvocationHint * signal_hint,
447 guint n_param_values,
448 const GValue * param_values, gpointer data)
450 AtkObject *accessible;
454 accessible = ATK_OBJECT (g_value_get_object (¶m_values[0]));
455 pname = g_strdup (g_value_get_string (¶m_values[1]));
457 /* TODO - Possibly ignore a change to the 'defunct' state.
458 * This is because without reference counting defunct objects should be removed.
460 detail1 = (g_value_get_boolean (¶m_values[2])) ? 1 : 0;
461 emit_event (accessible, ITF_EVENT_OBJECT, STATE_CHANGED, pname, detail1, 0,
462 DBUS_TYPE_INT32_AS_STRING, 0, append_basic);
467 /*---------------------------------------------------------------------------*/
470 * The window event listener handles the following ATK signals and forwards
471 * them as AT-SPI events:
473 * window:create -> window:create
474 * window:destroy -> window:destroy
475 * window:minimize -> window:minimize
476 * window:maximize -> window:maximize
477 * window:activate -> window:activate
478 * window:deactivate -> window:deactivate
481 window_event_listener (GSignalInvocationHint * signal_hint,
482 guint n_param_values,
483 const GValue * param_values, gpointer data)
485 AtkObject *accessible;
486 GSignalQuery signal_query;
487 const gchar *name, *s;
489 g_signal_query (signal_hint->signal_id, &signal_query);
490 name = signal_query.signal_name;
492 accessible = ATK_OBJECT (g_value_get_object (¶m_values[0]));
493 s = atk_object_get_name (accessible);
494 emit_event (accessible, ITF_EVENT_WINDOW, name, "", 0, 0,
495 DBUS_TYPE_STRING_AS_STRING, s, append_basic);
500 /*---------------------------------------------------------------------------*/
503 * The document event listener handles the following ATK signals
504 * and converts them to AT-SPI events:
506 * Gtk:AtkDocument:load-complete -> document:load-complete
507 * Gtk:AtkDocument:load-stopped -> document:load-stopped
508 * Gtk:AtkDocument:reload -> document:reload
511 document_event_listener (GSignalInvocationHint * signal_hint,
512 guint n_param_values,
513 const GValue * param_values, gpointer data)
515 AtkObject *accessible;
516 GSignalQuery signal_query;
517 const gchar *name, *s;
519 g_signal_query (signal_hint->signal_id, &signal_query);
520 name = signal_query.signal_name;
522 accessible = ATK_OBJECT (g_value_get_object (¶m_values[0]));
523 s = atk_object_get_name (accessible);
524 emit_event (accessible, ITF_EVENT_DOCUMENT, name, "", 0, 0,
525 DBUS_TYPE_STRING_AS_STRING, s, append_basic);
530 /*---------------------------------------------------------------------------*/
533 * Signal handler for "Gtk:AtkComponent:bounds-changed". Converts
534 * this to an AT-SPI event - "object:bounds-changed".
537 bounds_event_listener (GSignalInvocationHint * signal_hint,
538 guint n_param_values,
539 const GValue * param_values, gpointer data)
541 AtkObject *accessible;
542 AtkRectangle *atk_rect;
543 GSignalQuery signal_query;
544 const gchar *name, *s;
546 g_signal_query (signal_hint->signal_id, &signal_query);
547 name = signal_query.signal_name;
549 accessible = ATK_OBJECT (g_value_get_object (¶m_values[0]));
551 if (G_VALUE_HOLDS_BOXED (param_values + 1))
553 atk_rect = g_value_get_boxed (param_values + 1);
555 emit_event (accessible, ITF_EVENT_OBJECT, name, "", 0, 0,
556 "(iiii)", atk_rect, append_rect);
561 /*---------------------------------------------------------------------------*/
564 * Handles the ATK signal 'Gtk:AtkObject:active-descendant-changed' and
565 * converts it to the AT-SPI signal - 'object:active-descendant-changed'.
569 active_descendant_event_listener (GSignalInvocationHint * signal_hint,
570 guint n_param_values,
571 const GValue * param_values, gpointer data)
573 AtkObject *accessible;
575 GSignalQuery signal_query;
576 const gchar *name, *minor;
580 g_signal_query (signal_hint->signal_id, &signal_query);
581 name = signal_query.signal_name;
583 accessible = ATK_OBJECT (g_value_get_object (¶m_values[0]));
584 child = ATK_OBJECT (g_value_get_pointer (¶m_values[1]));
585 g_return_val_if_fail (ATK_IS_OBJECT (child), TRUE);
586 minor = g_quark_to_string (signal_hint->detail);
588 detail1 = atk_object_get_index_in_parent (child);
590 emit_event (accessible, ITF_EVENT_OBJECT, name, "", detail1, 0,
591 "(so)", child, append_object);
596 /*---------------------------------------------------------------------------*/
599 * Handles the ATK signal 'Gtk:AtkHypertext:link-selected' and
600 * converts it to the AT-SPI signal - 'object:link-selected'
604 link_selected_event_listener (GSignalInvocationHint * signal_hint,
605 guint n_param_values,
606 const GValue * param_values, gpointer data)
608 AtkObject *accessible;
609 GSignalQuery signal_query;
610 const gchar *name, *minor;
613 g_signal_query (signal_hint->signal_id, &signal_query);
614 name = signal_query.signal_name;
616 accessible = ATK_OBJECT (g_value_get_object (¶m_values[0]));
617 minor = g_quark_to_string (signal_hint->detail);
619 if (G_VALUE_TYPE (¶m_values[1]) == G_TYPE_INT)
620 detail1 = g_value_get_int (¶m_values[1]);
622 emit_event (accessible, ITF_EVENT_OBJECT, name, minor, detail1, 0,
623 DBUS_TYPE_INT32_AS_STRING, 0, append_basic);
627 /*---------------------------------------------------------------------------*/
630 * Handles the ATK signal 'Gtk:AtkText:text-changed' and
631 * converts it to the AT-SPI signal - 'object:text-changed'
635 text_changed_event_listener (GSignalInvocationHint * signal_hint,
636 guint n_param_values,
637 const GValue * param_values, gpointer data)
639 AtkObject *accessible;
640 GSignalQuery signal_query;
641 const gchar *name, *minor;
643 gint detail1, detail2;
645 g_signal_query (signal_hint->signal_id, &signal_query);
646 name = signal_query.signal_name;
648 accessible = ATK_OBJECT (g_value_get_object (¶m_values[0]));
649 minor = g_quark_to_string (signal_hint->detail);
651 if (G_VALUE_TYPE (¶m_values[1]) == G_TYPE_INT)
652 detail1 = g_value_get_int (¶m_values[1]);
654 if (G_VALUE_TYPE (¶m_values[2]) == G_TYPE_INT)
655 detail2 = g_value_get_int (¶m_values[2]);
658 atk_text_get_text (ATK_TEXT (accessible), detail1, detail1 + detail2);
660 emit_event (accessible, ITF_EVENT_OBJECT, name, minor, detail1, detail2,
661 DBUS_TYPE_STRING_AS_STRING, selected, append_basic);
665 /*---------------------------------------------------------------------------*/
668 * Handles the ATK signal 'Gtk:AtkText:text-selection-changed' and
669 * converts it to the AT-SPI signal - 'object:text-selection-changed'
673 text_selection_changed_event_listener (GSignalInvocationHint * signal_hint,
674 guint n_param_values,
675 const GValue * param_values,
678 AtkObject *accessible;
679 GSignalQuery signal_query;
680 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 emit_event (accessible, ITF_EVENT_OBJECT, name, minor, detail1, detail2,
696 DBUS_TYPE_STRING_AS_STRING, "", append_basic);
700 /*---------------------------------------------------------------------------*/
703 * Generic signal converter and forwarder.
705 * Klass (Interface) org.freedesktop.atspi.Event.Object
706 * Major is the signal name.
713 generic_event_listener (GSignalInvocationHint * signal_hint,
714 guint n_param_values,
715 const GValue * param_values, gpointer data)
717 AtkObject *accessible;
718 GSignalQuery signal_query;
720 int detail1 = 0, detail2 = 0;
722 g_signal_query (signal_hint->signal_id, &signal_query);
723 name = signal_query.signal_name;
725 accessible = ATK_OBJECT (g_value_get_object (¶m_values[0]));
727 if (n_param_values > 1 && G_VALUE_TYPE (¶m_values[1]) == G_TYPE_INT)
728 detail1 = g_value_get_int (¶m_values[1]);
730 if (n_param_values > 2 && G_VALUE_TYPE (¶m_values[2]) == G_TYPE_INT)
731 detail2 = g_value_get_int (¶m_values[2]);
733 emit_event (accessible, ITF_EVENT_OBJECT, name, "", detail1, detail2,
734 DBUS_TYPE_INT32_AS_STRING, 0, append_basic);
738 /*---------------------------------------------------------------------------*/
741 * Registers the provided function as a handler for the given signal name
742 * and stores the signal id returned so that the function may be
743 * de-registered later.
746 add_signal_listener (GSignalEmissionHook listener, const char *signal_name)
750 id = atk_add_global_event_listener (listener, signal_name);
751 g_array_append_val (listener_ids, id);
755 * Initialization for the signal handlers.
757 * Registers all required signal handlers.
760 spi_atk_register_event_listeners (void)
763 * Kludge to make sure the Atk interface types are registered, otherwise
764 * the AtkText signal handlers below won't get registered
766 GObject *ao = g_object_new (ATK_TYPE_OBJECT, NULL);
767 AtkObject *bo = atk_no_op_object_new (ao);
769 g_object_unref (G_OBJECT (bo));
772 /* Register for focus event notifications, and register app with central registry */
773 listener_ids = g_array_sized_new (FALSE, TRUE, sizeof (guint), 16);
775 atk_bridge_focus_tracker_id = atk_add_focus_tracker (focus_tracker);
777 add_signal_listener (property_event_listener,
778 "Gtk:AtkObject:property-change");
779 add_signal_listener (window_event_listener, "window:create");
780 add_signal_listener (window_event_listener, "window:destroy");
781 add_signal_listener (window_event_listener, "window:minimize");
782 add_signal_listener (window_event_listener, "window:maximize");
783 add_signal_listener (window_event_listener, "window:restore");
784 add_signal_listener (window_event_listener, "window:activate");
785 add_signal_listener (window_event_listener, "window:deactivate");
786 add_signal_listener (document_event_listener,
787 "Gtk:AtkDocument:load-complete");
788 add_signal_listener (document_event_listener, "Gtk:AtkDocument:reload");
789 add_signal_listener (document_event_listener,
790 "Gtk:AtkDocument:load-stopped");
791 /* TODO Fake this event on the client side */
792 add_signal_listener (state_event_listener, "Gtk:AtkObject:state-change");
794 add_signal_listener (active_descendant_event_listener,
795 "Gtk:AtkObject:active-descendant-changed");
796 add_signal_listener (bounds_event_listener,
797 "Gtk:AtkComponent:bounds-changed");
798 add_signal_listener (text_selection_changed_event_listener,
799 "Gtk:AtkText:text-selection-changed");
800 add_signal_listener (text_changed_event_listener,
801 "Gtk:AtkText:text-changed");
802 add_signal_listener (link_selected_event_listener,
803 "Gtk:AtkHypertext:link-selected");
804 add_signal_listener (generic_event_listener,
805 "Gtk:AtkObject:visible-data-changed");
806 add_signal_listener (generic_event_listener,
807 "Gtk:AtkSelection:selection-changed");
808 add_signal_listener (generic_event_listener,
809 "Gtk:AtkText:text-attributes-changed");
810 add_signal_listener (generic_event_listener,
811 "Gtk:AtkText:text-caret-moved");
812 add_signal_listener (generic_event_listener, "Gtk:AtkTable:row-inserted");
813 add_signal_listener (generic_event_listener, "Gtk:AtkTable:row-reordered");
814 add_signal_listener (generic_event_listener, "Gtk:AtkTable:row-deleted");
815 add_signal_listener (generic_event_listener,
816 "Gtk:AtkTable:column-inserted");
817 add_signal_listener (generic_event_listener,
818 "Gtk:AtkTable:column-reordered");
819 add_signal_listener (generic_event_listener, "Gtk:AtkTable:column-deleted");
820 add_signal_listener (generic_event_listener, "Gtk:AtkTable:model-changed");
823 * May add the following listeners to implement preemptive key listening for GTK+
825 * atk_add_global_event_listener (spi_atk_bridge_widgetkey_listener, "Gtk:GtkWidget:key-press-event");
826 * atk_add_global_event_listener (spi_atk_bridge_widgetkey_listener, "Gtk:GtkWidget:key-release-event");
828 atk_bridge_key_event_listener_id =
829 atk_add_key_event_listener (spi_atk_bridge_key_listener, NULL);
832 /*---------------------------------------------------------------------------*/
835 * De-registers all ATK signal handlers.
838 spi_atk_deregister_event_listeners (void)
841 GArray *ids = listener_ids;
844 if (atk_bridge_focus_tracker_id)
845 atk_remove_focus_tracker (atk_bridge_focus_tracker_id);
847 for (i = 0; ids && i < ids->len; i++)
849 atk_remove_global_event_listener (g_array_index (ids, guint, i));
852 if (atk_bridge_key_event_listener_id)
853 atk_remove_key_event_listener (atk_bridge_key_event_listener_id);
856 /*---------------------------------------------------------------------------*/
859 * TODO This function seems out of place here.
861 * Emits fake deactivate signals on all top-level windows.
862 * Used when shutting down AT-SPI, ensuring that all
863 * windows have been removed on the client side.
866 spi_atk_tidy_windows (void)
872 root = atk_get_root ();
873 n_children = atk_object_get_n_accessible_children (root);
874 for (i = 0; i < n_children; i++)
877 AtkStateSet *stateset;
880 child = atk_object_ref_accessible_child (root, i);
881 stateset = atk_object_ref_state_set (child);
883 name = atk_object_get_name (child);
884 if (atk_state_set_contains_state (stateset, ATK_STATE_ACTIVE))
886 emit_event (child, ITF_EVENT_WINDOW, "deactivate", NULL, 0, 0,
887 DBUS_TYPE_STRING_AS_STRING, name, append_basic);
889 g_object_unref (stateset);
891 emit_event (child, ITF_EVENT_WINDOW, "destroy", NULL, 0, 0,
892 DBUS_TYPE_STRING_AS_STRING, name, append_basic);
893 g_object_unref (child);
897 /*END------------------------------------------------------------------------*/