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 /*---------------------------------------------------------------------------*/
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)) return NULL;
76 Accessibility_DeviceEventController_notifyListenersSync(const Accessibility_DeviceEvent *key_event)
80 dbus_bool_t consumed = FALSE;
83 dbus_message_new_method_call(SPI_DBUS_NAME_REGISTRY,
85 SPI_DBUS_INTERFACE_DEC,
86 "notifyListenersSync");
88 dbus_error_init(&error);
89 if (spi_dbus_marshal_deviceEvent(message, key_event))
91 DBusMessage *reply = send_and_allow_reentry (atk_adaptor_app_data->bus, message);
95 dbus_error_init(&error);
96 dbus_message_get_args(reply, &error, DBUS_TYPE_BOOLEAN, &consumed, DBUS_TYPE_INVALID);
97 dbus_message_unref(reply);
100 dbus_message_unref(message);
105 spi_init_keystroke_from_atk_key_event (Accessibility_DeviceEvent *keystroke,
106 AtkKeyEventStruct *event)
108 keystroke->id = (dbus_int32_t) event->keyval;
109 keystroke->hw_code = (dbus_int16_t) event->keycode;
110 keystroke->timestamp = (dbus_uint32_t) event->timestamp;
111 keystroke->modifiers = (dbus_uint16_t) (event->state & 0xFFFF);
116 keystroke->event_string = g_strdup (event->string);
117 c = g_utf8_get_char_validated (event->string, -1);
118 if (c > 0 && g_unichar_isprint (c))
119 keystroke->is_text = TRUE;
121 keystroke->is_text = FALSE;
125 keystroke->event_string = g_strdup ("");
126 keystroke->is_text = FALSE;
130 case (ATK_KEY_EVENT_PRESS):
131 keystroke->type = Accessibility_KEY_PRESSED_EVENT;
133 case (ATK_KEY_EVENT_RELEASE):
134 keystroke->type = Accessibility_KEY_RELEASED_EVENT;
141 g_print ("key_event type %d; val=%d code=%d modifiers=%x name=%s is_text=%d, time=%lx\n",
142 (int) keystroke->type, (int) keystroke->id, (int) keystroke->hw_code,
143 (int) keystroke->modifiers,
144 keystroke->event_string, (int) keystroke->is_text, (unsigned long) keystroke->timestamp);
150 spi_atk_bridge_key_listener (AtkKeyEventStruct *event, gpointer data)
153 Accessibility_DeviceEvent key_event;
155 spi_init_keystroke_from_atk_key_event (&key_event, event);
157 result = Accessibility_DeviceEventController_notifyListenersSync (&key_event);
159 if (key_event.event_string) g_free (key_event.event_string);
165 /*---------------------------------------------------------------------------*/
168 * Emits an AT-SPI event.
169 * AT-SPI events names are split into three parts:
171 * This is mapped onto D-Bus events as:
172 * D-Bus Interface:Signal Name:Detail argument
174 * Marshals a basic type into the 'any_data' attribute of
179 emit(AtkObject *accessible,
183 dbus_int32_t detail1,
184 dbus_int32_t detail2,
190 path = atk_dbus_object_to_path (accessible);
192 /* Tough decision here
193 * We won't send events from accessible
194 * objects that have not yet been added to the accessible tree.
199 spi_dbus_emit_signal (atk_adaptor_app_data->bus, path, klass, major, minor, detail1, detail2, type, val);
203 /*---------------------------------------------------------------------------*/
206 * Emits an AT-SPI event, marshalling a BoundingBox structure into the
207 * 'any_data' variant of the event.
210 emit_rect(AtkObject *accessible,
217 DBusMessageIter iter, variant, sub;
218 gchar *path, *cname, *t;
219 dbus_int32_t dummy = 0;
221 path = atk_dbus_object_to_path (accessible);
223 /* Tough decision here
224 * We won't send events from accessible
225 * objects that have not yet been added to the accessible tree.
230 if (!klass) klass = "";
231 if (!major) major = "";
232 if (!minor) minor = "";
235 * This is very annoying, but as '-' isn't a legal signal
236 * name in D-Bus (Why not??!?) The names need converting
237 * on this side, and again on the client side.
239 cname = g_strdup(major);
240 while ((t = strchr(cname, '-')) != NULL) *t = '_';
242 sig = dbus_message_new_signal(path, klass, cname);
246 dbus_message_iter_init_append (sig, &iter);
247 dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &minor);
248 dbus_message_iter_append_basic (&iter, DBUS_TYPE_INT32, &dummy);
249 dbus_message_iter_append_basic (&iter, DBUS_TYPE_INT32, &dummy);
251 dbus_message_iter_open_container (&iter, DBUS_TYPE_VARIANT, "(iiii)", &variant);
252 dbus_message_iter_open_container (&variant, DBUS_TYPE_STRUCT, NULL, &sub);
253 dbus_message_iter_append_basic (&sub, DBUS_TYPE_INT32, &(rect->x));
254 dbus_message_iter_append_basic (&sub, DBUS_TYPE_INT32, &(rect->y));
255 dbus_message_iter_append_basic (&sub, DBUS_TYPE_INT32, &(rect->width));
256 dbus_message_iter_append_basic (&sub, DBUS_TYPE_INT32, &(rect->height));
257 dbus_message_iter_close_container (&variant, &sub);
258 dbus_message_iter_close_container (&iter, &variant);
260 dbus_connection_send(atk_adaptor_app_data->bus, sig, NULL);
263 /*---------------------------------------------------------------------------*/
266 * The focus listener handles the ATK 'focus' signal and forwards it
267 * as the AT-SPI event, 'focus:'
270 focus_tracker (AtkObject *accessible)
272 emit(accessible, ITF_EVENT_FOCUS, "focus", "", 0, 0, DBUS_TYPE_INT32_AS_STRING, 0);
275 /*---------------------------------------------------------------------------*/
277 #define PCHANGE "property-change"
280 * This handler handles the following ATK signals and
281 * converts them to AT-SPI events:
283 * Gtk:AtkObject:property-change -> object:property-change:(property-name)
285 * The property-name is part of the ATK property-change signal.
288 property_event_listener (GSignalInvocationHint *signal_hint,
289 guint n_param_values,
290 const GValue *param_values,
293 AtkObject *accessible;
294 AtkPropertyValues *values;
296 const gchar *pname = NULL;
302 accessible = g_value_get_object (¶m_values[0]);
303 values = (AtkPropertyValues*) g_value_get_pointer (¶m_values[1]);
305 pname = values[0].property_name;
307 /* TODO Could improve this control statement by matching
308 * on only the end of the signal names,
310 if (strcmp (pname, "accessible-table-summary") == 0)
312 otemp = atk_table_get_summary(ATK_TABLE (accessible));
313 stemp = atk_dbus_object_to_path (otemp);
315 emit(accessible, ITF_EVENT_OBJECT, PCHANGE, pname, 0, 0, DBUS_TYPE_OBJECT_PATH_AS_STRING, stemp);
317 else if (strcmp (pname, "accessible-table-column-header") == 0)
319 i = g_value_get_int (&(values->new_value));
320 otemp = atk_table_get_column_header(ATK_TABLE (accessible), i);
321 stemp = atk_dbus_object_to_path (otemp);
323 emit(accessible, ITF_EVENT_OBJECT, PCHANGE, pname, 0, 0, DBUS_TYPE_OBJECT_PATH_AS_STRING, stemp);
325 else if (strcmp (pname, "accessible-table-row-header") == 0)
327 i = g_value_get_int (&(values->new_value));
328 otemp = atk_table_get_row_header(ATK_TABLE (accessible), i);
329 stemp = atk_dbus_object_to_path (otemp);
331 emit(accessible, ITF_EVENT_OBJECT, PCHANGE, pname, 0, 0, DBUS_TYPE_OBJECT_PATH_AS_STRING, stemp);
333 else if (strcmp (pname, "accessible-table-row-description") == 0)
335 i = g_value_get_int (&(values->new_value));
336 stemp = atk_table_get_row_description(ATK_TABLE (accessible), i);
337 emit(accessible, ITF_EVENT_OBJECT, PCHANGE, pname, 0, 0, DBUS_TYPE_STRING_AS_STRING, stemp);
339 else if (strcmp (pname, "accessible-table-column-description") == 0)
341 i = g_value_get_int (&(values->new_value));
342 stemp = atk_table_get_column_description(ATK_TABLE (accessible), i);
343 emit(accessible, ITF_EVENT_OBJECT, PCHANGE, pname, 0, 0, DBUS_TYPE_STRING_AS_STRING, stemp);
345 else if (strcmp (pname, "accessible-table-caption-object") == 0)
347 otemp = atk_table_get_caption(ATK_TABLE(accessible));
348 stemp = atk_object_get_name(otemp);
349 emit(accessible, ITF_EVENT_OBJECT, PCHANGE, pname, 0, 0, DBUS_TYPE_STRING_AS_STRING, stemp);
353 emit(accessible, ITF_EVENT_OBJECT, PCHANGE, pname, 0, 0, DBUS_TYPE_INT32_AS_STRING, 0);
358 /*---------------------------------------------------------------------------*/
360 #define STATE_CHANGED "state-changed"
363 * The state event listener handles 'Gtk:AtkObject:state-change' ATK signals
364 * and forwards them as object:state-changed:(param-name) AT-SPI events. Where
365 * the param-name is part of the ATK state-change signal.
368 state_event_listener (GSignalInvocationHint *signal_hint,
369 guint n_param_values,
370 const GValue *param_values,
373 AtkObject *accessible;
377 accessible = ATK_OBJECT(g_value_get_object (¶m_values[0]));
378 pname = g_strdup (g_value_get_string (¶m_values[1]));
380 /* TODO - Possibly ignore a change to the 'defunct' state.
381 * This is because without reference counting defunct objects should be removed.
383 detail1 = (g_value_get_boolean (¶m_values[2])) ? 1 : 0;
384 emit(accessible, ITF_EVENT_OBJECT, STATE_CHANGED, pname, detail1, 0, DBUS_TYPE_INT32_AS_STRING, 0);
389 /*---------------------------------------------------------------------------*/
392 * The window event listener handles the following ATK signals and forwards
393 * them as AT-SPI events:
395 * window:create -> window:create
396 * window:destroy -> window:destroy
397 * window:minimize -> window:minimize
398 * window:maximize -> window:maximize
399 * window:activate -> window:activate
400 * window:deactivate -> window:deactivate
403 window_event_listener (GSignalInvocationHint *signal_hint,
404 guint n_param_values,
405 const GValue *param_values,
408 AtkObject *accessible;
409 GSignalQuery signal_query;
410 const gchar *name, *s;
412 g_signal_query (signal_hint->signal_id, &signal_query);
413 name = signal_query.signal_name;
415 accessible = ATK_OBJECT(g_value_get_object(¶m_values[0]));
416 s = atk_object_get_name (accessible);
417 emit(accessible, ITF_EVENT_WINDOW, name, "", 0, 0, DBUS_TYPE_STRING_AS_STRING, s);
422 /*---------------------------------------------------------------------------*/
425 * The document event listener handles the following ATK signals
426 * and converts them to AT-SPI events:
428 * Gtk:AtkDocument:load-complete -> document:load-complete
429 * Gtk:AtkDocument:load-stopped -> document:load-stopped
430 * Gtk:AtkDocument:reload -> document:reload
433 document_event_listener (GSignalInvocationHint *signal_hint,
434 guint n_param_values,
435 const GValue *param_values,
438 AtkObject *accessible;
439 GSignalQuery signal_query;
440 const gchar *name, *s;
442 g_signal_query (signal_hint->signal_id, &signal_query);
443 name = signal_query.signal_name;
445 accessible = ATK_OBJECT(g_value_get_object(¶m_values[0]));
446 s = atk_object_get_name (accessible);
447 emit(accessible, ITF_EVENT_DOCUMENT, name, "", 0, 0, DBUS_TYPE_STRING_AS_STRING, s);
452 /*---------------------------------------------------------------------------*/
455 * Signal handler for "Gtk:AtkComponent:bounds-changed". Converts
456 * this to an AT-SPI event - "object:bounds-changed".
459 bounds_event_listener (GSignalInvocationHint *signal_hint,
460 guint n_param_values,
461 const GValue *param_values,
464 AtkObject *accessible;
465 AtkRectangle *atk_rect;
466 GSignalQuery signal_query;
467 const gchar *name, *s;
469 g_signal_query (signal_hint->signal_id, &signal_query);
470 name = signal_query.signal_name;
472 accessible = ATK_OBJECT(g_value_get_object(¶m_values[0]));
474 if (G_VALUE_HOLDS_BOXED (param_values + 1))
475 atk_rect = g_value_get_boxed (param_values + 1);
477 emit_rect(accessible, ITF_EVENT_OBJECT, name, "", atk_rect);
481 /*---------------------------------------------------------------------------*/
484 * Handles the ATK signal 'Gtk:AtkObject:active-descendant-changed' and
485 * converts it to the AT-SPI signal - 'object:active-descendant-changed'.
489 active_descendant_event_listener (GSignalInvocationHint *signal_hint,
490 guint n_param_values,
491 const GValue *param_values,
494 AtkObject *accessible;
496 GSignalQuery signal_query;
497 const gchar *name, *minor;
501 g_signal_query (signal_hint->signal_id, &signal_query);
502 name = signal_query.signal_name;
504 accessible = ATK_OBJECT(g_value_get_object(¶m_values[0]));
505 child = ATK_OBJECT(g_value_get_pointer (¶m_values[1]));
506 g_return_val_if_fail (ATK_IS_OBJECT (child), TRUE);
507 minor = g_quark_to_string (signal_hint->detail);
509 detail1 = atk_object_get_index_in_parent (child);
510 s = atk_dbus_object_to_path (child);
517 emit(accessible, ITF_EVENT_OBJECT, name, "", detail1, 0, DBUS_TYPE_OBJECT_PATH_AS_STRING, s);
522 /*---------------------------------------------------------------------------*/
525 * Handles the ATK signal 'Gtk:AtkHypertext:link-selected' and
526 * converts it to the AT-SPI signal - 'object:link-selected'
530 link_selected_event_listener (GSignalInvocationHint *signal_hint,
531 guint n_param_values,
532 const GValue *param_values,
535 AtkObject *accessible;
536 GSignalQuery signal_query;
537 const gchar *name, *minor;
540 g_signal_query (signal_hint->signal_id, &signal_query);
541 name = signal_query.signal_name;
543 accessible = ATK_OBJECT(g_value_get_object(¶m_values[0]));
544 minor = g_quark_to_string (signal_hint->detail);
546 if (G_VALUE_TYPE (¶m_values[1]) == G_TYPE_INT)
547 detail1 = g_value_get_int (¶m_values[1]);
549 emit(accessible, ITF_EVENT_OBJECT, name, minor, detail1, 0, DBUS_TYPE_INT32_AS_STRING, 0);
553 /*---------------------------------------------------------------------------*/
556 * Handles the ATK signal 'Gtk:AtkText:text-changed' and
557 * converts it to the AT-SPI signal - 'object:text-changed'
561 text_changed_event_listener (GSignalInvocationHint *signal_hint,
562 guint n_param_values,
563 const GValue *param_values,
566 AtkObject *accessible;
567 GSignalQuery signal_query;
568 const gchar *name, *minor;
570 gint detail1, detail2;
572 g_signal_query (signal_hint->signal_id, &signal_query);
573 name = signal_query.signal_name;
575 accessible = ATK_OBJECT(g_value_get_object(¶m_values[0]));
576 minor = g_quark_to_string (signal_hint->detail);
578 if (G_VALUE_TYPE (¶m_values[1]) == G_TYPE_INT)
579 detail1 = g_value_get_int (¶m_values[1]);
581 if (G_VALUE_TYPE (¶m_values[2]) == G_TYPE_INT)
582 detail2 = g_value_get_int (¶m_values[2]);
584 selected = atk_text_get_text (ATK_TEXT (accessible), detail1, detail1+detail2);
586 emit(accessible, ITF_EVENT_OBJECT, name, minor, detail1, detail2, DBUS_TYPE_STRING_AS_STRING, selected);
590 /*---------------------------------------------------------------------------*/
593 * Handles the ATK signal 'Gtk:AtkText:text-selection-changed' and
594 * converts it to the AT-SPI signal - 'object:text-selection-changed'
598 text_selection_changed_event_listener (GSignalInvocationHint *signal_hint,
599 guint n_param_values,
600 const GValue *param_values,
603 AtkObject *accessible;
604 GSignalQuery signal_query;
605 const gchar *name, *minor;
606 gint detail1, detail2;
608 g_signal_query (signal_hint->signal_id, &signal_query);
609 name = signal_query.signal_name;
611 accessible = ATK_OBJECT(g_value_get_object(¶m_values[0]));
612 minor = g_quark_to_string (signal_hint->detail);
614 if (G_VALUE_TYPE (¶m_values[1]) == G_TYPE_INT)
615 detail1 = g_value_get_int (¶m_values[1]);
617 if (G_VALUE_TYPE (¶m_values[2]) == G_TYPE_INT)
618 detail2 = g_value_get_int (¶m_values[2]);
620 emit(accessible, ITF_EVENT_OBJECT, name, minor, detail1, detail2, DBUS_TYPE_STRING_AS_STRING, "");
624 /*---------------------------------------------------------------------------*/
627 * Generic signal converter and forwarder.
629 * Klass (Interface) org.freedesktop.atspi.Event.Object
630 * Major is the signal name.
637 generic_event_listener (GSignalInvocationHint *signal_hint,
638 guint n_param_values,
639 const GValue *param_values,
642 AtkObject *accessible;
643 GSignalQuery signal_query;
646 g_signal_query (signal_hint->signal_id, &signal_query);
647 name = signal_query.signal_name;
649 accessible = ATK_OBJECT(g_value_get_object(¶m_values[0]));
650 emit(accessible, ITF_EVENT_OBJECT, name, "", 0, 0, DBUS_TYPE_INT32_AS_STRING, 0);
654 /*---------------------------------------------------------------------------*/
657 * Registers the provided function as a handler for the given signal name
658 * and stores the signal id returned so that the function may be
659 * de-registered later.
662 add_signal_listener (GSignalEmissionHook listener, const char *signal_name)
666 id = atk_add_global_event_listener (listener, signal_name);
667 g_array_append_val (listener_ids, id);
671 * Initialization for the signal handlers.
673 * Registers all required signal handlers.
676 spi_atk_register_event_listeners (void)
679 * Kludge to make sure the Atk interface types are registered, otherwise
680 * the AtkText signal handlers below won't get registered
682 GObject *ao = g_object_new (ATK_TYPE_OBJECT, NULL);
683 AtkObject *bo = atk_no_op_object_new (ao);
685 g_object_unref (G_OBJECT (bo));
688 /* Register for focus event notifications, and register app with central registry */
689 listener_ids = g_array_sized_new (FALSE, TRUE, sizeof (guint), 16);
691 atk_bridge_focus_tracker_id = atk_add_focus_tracker (focus_tracker);
693 add_signal_listener (property_event_listener, "Gtk:AtkObject:property-change");
694 add_signal_listener (window_event_listener, "window:create");
695 add_signal_listener (window_event_listener, "window:destroy");
696 add_signal_listener (window_event_listener, "window:minimize");
697 add_signal_listener (window_event_listener, "window:maximize");
698 add_signal_listener (window_event_listener, "window:restore");
699 add_signal_listener (window_event_listener, "window:activate");
700 add_signal_listener (window_event_listener, "window:deactivate");
701 add_signal_listener (document_event_listener, "Gtk:AtkDocument:load-complete");
702 add_signal_listener (document_event_listener, "Gtk:AtkDocument:reload");
703 add_signal_listener (document_event_listener, "Gtk:AtkDocument:load-stopped");
704 add_signal_listener (state_event_listener, "Gtk:AtkObject:state-change");
705 add_signal_listener (active_descendant_event_listener, "Gtk:AtkObject:active-descendant-changed");
706 add_signal_listener (bounds_event_listener, "Gtk:AtkComponent:bounds-changed");
707 add_signal_listener (text_selection_changed_event_listener, "Gtk:AtkText:text-selection-changed");
708 add_signal_listener (text_changed_event_listener, "Gtk:AtkText:text-changed");
709 add_signal_listener (link_selected_event_listener, "Gtk:AtkHypertext:link-selected");
710 add_signal_listener (generic_event_listener, "Gtk:AtkObject:visible-data-changed");
711 add_signal_listener (generic_event_listener, "Gtk:AtkSelection:selection-changed");
712 add_signal_listener (generic_event_listener, "Gtk:AtkText:text-caret-moved");
713 add_signal_listener (generic_event_listener, "Gtk:AtkTable:row-inserted");
714 add_signal_listener (generic_event_listener, "Gtk:AtkTable:row-reordered");
715 add_signal_listener (generic_event_listener, "Gtk:AtkTable:row-deleted");
716 add_signal_listener (generic_event_listener, "Gtk:AtkTable:column-inserted");
717 add_signal_listener (generic_event_listener, "Gtk:AtkTable:column-reordered");
718 add_signal_listener (generic_event_listener, "Gtk:AtkTable:column-deleted");
719 add_signal_listener (generic_event_listener, "Gtk:AtkTable:model-changed");
722 * May add the following listeners to implement preemptive key listening for GTK+
724 * atk_add_global_event_listener (spi_atk_bridge_widgetkey_listener, "Gtk:GtkWidget:key-press-event");
725 * atk_add_global_event_listener (spi_atk_bridge_widgetkey_listener, "Gtk:GtkWidget:key-release-event");
727 atk_bridge_key_event_listener_id = atk_add_key_event_listener (spi_atk_bridge_key_listener, NULL);
730 /*---------------------------------------------------------------------------*/
733 * De-registers all ATK signal handlers.
736 spi_atk_deregister_event_listeners (void)
739 GArray *ids = listener_ids;
742 if (atk_bridge_focus_tracker_id)
743 atk_remove_focus_tracker (atk_bridge_focus_tracker_id);
745 for (i = 0; ids && i < ids->len; i++)
747 atk_remove_global_event_listener (g_array_index (ids, guint, i));
750 if (atk_bridge_key_event_listener_id)
751 atk_remove_key_event_listener (atk_bridge_key_event_listener_id);
754 /*---------------------------------------------------------------------------*/
757 * TODO This function seems out of place here.
759 * Emits fake deactivate signals on all top-level windows.
760 * Used when shutting down AT-SPI, ensuring that all
761 * windows have been removed on the client side.
764 spi_atk_tidy_windows (void)
770 root = atk_get_root ();
771 n_children = atk_object_get_n_accessible_children (root);
772 for (i = 0; i < n_children; i++)
775 AtkStateSet *stateset;
778 child = atk_object_ref_accessible_child (root, i);
779 stateset = atk_object_ref_state_set (child);
781 name = atk_object_get_name (child);
782 if (atk_state_set_contains_state (stateset, ATK_STATE_ACTIVE))
784 emit(child, ITF_EVENT_WINDOW, "deactivate", NULL, 0, 0, DBUS_TYPE_STRING_AS_STRING, name);
786 g_object_unref (stateset);
788 emit(child, ITF_EVENT_WINDOW, "destroy", NULL, 0, 0, DBUS_TYPE_STRING_AS_STRING, name);
789 g_object_unref (child);
793 /*END------------------------------------------------------------------------*/