1 /* GAIL - The GNOME Accessibility Implementation Library
2 * Copyright 2001 Sun Microsystems Inc.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
26 #include "gailadjustment.h"
27 #include "gailarrow.h"
28 #include "gailbooleancell.h"
30 #include "gailbutton.h"
31 #include "gailcalendar.h"
33 #include "gailcheckmenuitem.h"
34 #include "gailcombobox.h"
35 #include "gailcontainer.h"
36 #include "gailcontainercell.h"
37 #include "gailexpander.h"
38 #include "gailframe.h"
39 #include "gailimage.h"
40 #include "gailimagecell.h"
41 #include "gaillinkbutton.h"
43 #include "gailmenushell.h"
44 #include "gailmenuitem.h"
45 #include "gailnotebook.h"
46 #include "gailpaned.h"
47 #include "gailprogressbar.h"
48 #include "gailradiobutton.h"
49 #include "gailradiomenuitem.h"
50 #include "gailrenderercell.h"
51 #include "gailrange.h"
52 #include "gailscalebutton.h"
53 #include "gailscrollbar.h"
54 #include "gailscrolledwindow.h"
55 #include "gailseparator.h"
56 #include "gailstatusbar.h"
57 #include "gailtextcell.h"
58 #include "gailtogglebutton.h"
59 #include "gailtoplevel.h"
60 #include "gailtreeview.h"
62 #include "gailwidget.h"
63 #include "gailwindow.h"
65 #include "gailfactory.h"
67 #define GNOME_ACCESSIBILITY_ENV "GNOME_ACCESSIBILITY"
69 static gboolean gail_focus_watcher (GSignalInvocationHint *ihint,
71 const GValue *param_values,
73 static gboolean gail_select_watcher (GSignalInvocationHint *ihint,
75 const GValue *param_values,
77 static gboolean gail_deselect_watcher (GSignalInvocationHint *ihint,
79 const GValue *param_values,
81 static gboolean gail_switch_page_watcher(GSignalInvocationHint *ihint,
83 const GValue *param_values,
85 static AtkObject* gail_get_accessible_for_widget (GtkWidget *widget,
87 static void gail_finish_select (GtkWidget *widget);
88 static void gail_map_cb (GtkWidget *widget);
89 static void gail_map_submenu_cb (GtkWidget *widget);
90 static gint gail_focus_idle_handler (gpointer data);
91 static void gail_focus_notify (GtkWidget *widget);
92 static void gail_focus_notify_when_idle (GtkWidget *widget);
94 static void gail_focus_tracker_init (void);
95 static void gail_focus_object_destroyed (gpointer data);
96 static void gail_focus_tracker (AtkObject *object);
97 static void gail_set_focus_widget (GtkWidget *focus_widget,
99 static void gail_set_focus_object (AtkObject *focus_obj,
102 GtkWidget* focus_widget = NULL;
103 static GtkWidget* next_focus_widget = NULL;
104 static gboolean was_deselect = FALSE;
105 static GtkWidget* subsequent_focus_widget = NULL;
106 static GtkWidget* focus_before_menu = NULL;
107 static guint focus_notify_handler = 0;
108 static guint focus_tracker_id = 0;
109 static GQuark quark_focus_object = 0;
111 GAIL_IMPLEMENT_FACTORY (GAIL_TYPE_WIDGET, GailWidget, gail_widget, GTK_TYPE_WIDGET)
112 GAIL_IMPLEMENT_FACTORY (GAIL_TYPE_CONTAINER, GailContainer, gail_container, GTK_TYPE_CONTAINER)
113 GAIL_IMPLEMENT_FACTORY (GAIL_TYPE_BUTTON, GailButton, gail_button, GTK_TYPE_BUTTON)
114 GAIL_IMPLEMENT_FACTORY (GAIL_TYPE_LINK_BUTTON, GailLinkButton, gail_link_button, GTK_TYPE_LINK_BUTTON)
115 GAIL_IMPLEMENT_FACTORY_WITH_FUNC (GAIL_TYPE_MENU_ITEM, GailMenuItem, gail_menu_item, gail_menu_item_new)
116 GAIL_IMPLEMENT_FACTORY (GAIL_TYPE_TOGGLE_BUTTON, GailToggleButton, gail_toggle_button, GTK_TYPE_TOGGLE_BUTTON)
117 GAIL_IMPLEMENT_FACTORY (GAIL_TYPE_IMAGE, GailImage, gail_image, GTK_TYPE_IMAGE)
118 GAIL_IMPLEMENT_FACTORY (GAIL_TYPE_COMBO_BOX, GailComboBox, gail_combo_box, GTK_TYPE_COMBO_BOX)
119 GAIL_IMPLEMENT_FACTORY (GAIL_TYPE_MENU_SHELL, GailMenuShell, gail_menu_shell, GTK_TYPE_MENU_SHELL)
120 GAIL_IMPLEMENT_FACTORY (GAIL_TYPE_MENU, GailMenu, gail_menu, GTK_TYPE_MENU)
121 GAIL_IMPLEMENT_FACTORY (GAIL_TYPE_WINDOW, GailWindow, gail_window, GTK_TYPE_BIN)
122 GAIL_IMPLEMENT_FACTORY (GAIL_TYPE_RANGE, GailRange, gail_range, GTK_TYPE_RANGE)
123 GAIL_IMPLEMENT_FACTORY (GAIL_TYPE_SCALE_BUTTON, GailScaleButton, gail_scale_button, GTK_TYPE_SCALE_BUTTON)
124 GAIL_IMPLEMENT_FACTORY (GAIL_TYPE_STATUSBAR, GailStatusbar, gail_statusbar, GTK_TYPE_STATUSBAR)
125 GAIL_IMPLEMENT_FACTORY (GAIL_TYPE_NOTEBOOK, GailNotebook, gail_notebook, GTK_TYPE_NOTEBOOK)
126 GAIL_IMPLEMENT_FACTORY (GAIL_TYPE_CALENDAR, GailCalendar, gail_calendar, GTK_TYPE_CALENDAR)
127 GAIL_IMPLEMENT_FACTORY (GAIL_TYPE_PROGRESS_BAR, GailProgressBar, gail_progress_bar, GTK_TYPE_PROGRESS_BAR)
128 GAIL_IMPLEMENT_FACTORY (GAIL_TYPE_TREE_VIEW, GailTreeView, gail_tree_view, GTK_TYPE_TREE_VIEW)
129 GAIL_IMPLEMENT_FACTORY (GAIL_TYPE_FRAME, GailFrame, gail_frame, GTK_TYPE_FRAME)
130 GAIL_IMPLEMENT_FACTORY (GAIL_TYPE_RADIO_BUTTON, GailRadioButton, gail_radio_button, GTK_TYPE_RADIO_BUTTON)
131 GAIL_IMPLEMENT_FACTORY (GAIL_TYPE_ARROW, GailArrow, gail_arrow, GTK_TYPE_ARROW)
132 GAIL_IMPLEMENT_FACTORY (GAIL_TYPE_SEPARATOR, GailSeparator, gail_separator, GTK_TYPE_SEPARATOR)
133 GAIL_IMPLEMENT_FACTORY (GAIL_TYPE_BOX, GailBox, gail_box, GTK_TYPE_BOX)
134 GAIL_IMPLEMENT_FACTORY (GAIL_TYPE_SCROLLED_WINDOW, GailScrolledWindow, gail_scrolled_window, GTK_TYPE_SCROLLED_WINDOW)
135 GAIL_IMPLEMENT_FACTORY (GAIL_TYPE_PANED, GailPaned, gail_paned, GTK_TYPE_PANED)
136 GAIL_IMPLEMENT_FACTORY (GAIL_TYPE_SCROLLBAR, GailScrollbar, gail_scrollbar, GTK_TYPE_SCROLLBAR)
137 GAIL_IMPLEMENT_FACTORY_WITH_FUNC (GAIL_TYPE_CHECK_MENU_ITEM, GailCheckMenuItem, gail_check_menu_item, gail_check_menu_item_new)
138 GAIL_IMPLEMENT_FACTORY_WITH_FUNC (GAIL_TYPE_RADIO_MENU_ITEM, GailRadioMenuItem, gail_radio_menu_item, gail_radio_menu_item_new)
139 GAIL_IMPLEMENT_FACTORY (GAIL_TYPE_EXPANDER, GailExpander, gail_expander, GTK_TYPE_EXPANDER)
140 GAIL_IMPLEMENT_FACTORY_WITH_FUNC_DUMMY (GAIL_TYPE_RENDERER_CELL, GailRendererCell, gail_renderer_cell, GTK_TYPE_CELL_RENDERER, gail_renderer_cell_new)
141 GAIL_IMPLEMENT_FACTORY_WITH_FUNC_DUMMY (GAIL_TYPE_BOOLEAN_CELL, GailBooleanCell, gail_boolean_cell, GTK_TYPE_CELL_RENDERER_TOGGLE, gail_boolean_cell_new)
142 GAIL_IMPLEMENT_FACTORY_WITH_FUNC_DUMMY (GAIL_TYPE_IMAGE_CELL, GailImageCell, gail_image_cell, GTK_TYPE_CELL_RENDERER_PIXBUF, gail_image_cell_new)
143 GAIL_IMPLEMENT_FACTORY_WITH_FUNC_DUMMY (GAIL_TYPE_TEXT_CELL, GailTextCell, gail_text_cell, GTK_TYPE_CELL_RENDERER_TEXT, gail_text_cell_new)
146 gail_get_accessible_for_widget (GtkWidget *widget,
149 AtkObject *obj = NULL;
155 if (GTK_IS_ENTRY (widget))
157 else if (GTK_IS_NOTEBOOK (widget))
159 GtkNotebook *notebook;
162 notebook = GTK_NOTEBOOK (widget);
163 page_num = gtk_notebook_get_current_page (notebook);
166 obj = gtk_widget_get_accessible (widget);
167 obj = atk_object_ref_accessible_child (obj, page_num);
168 g_object_unref (obj);
171 else if (GTK_IS_TOGGLE_BUTTON (widget))
173 GtkWidget *other_widget = gtk_widget_get_parent (widget);
174 if (GTK_IS_COMBO_BOX (other_widget))
176 gail_set_focus_widget (other_widget, widget);
177 widget = other_widget;
182 AtkObject *focus_object;
184 obj = gtk_widget_get_accessible (widget);
185 focus_object = g_object_get_qdata (G_OBJECT (obj), quark_focus_object);
187 * We check whether the object for this focus_object has been deleted.
188 * This can happen when navigating to an empty directory in nautilus.
191 if (ATK_IS_GOBJECT_ACCESSIBLE (focus_object))
193 if (!atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (focus_object)))
204 gail_focus_watcher (GSignalInvocationHint *ihint,
205 guint n_param_values,
206 const GValue *param_values,
213 object = g_value_get_object (param_values + 0);
214 g_return_val_if_fail (GTK_IS_WIDGET(object), FALSE);
216 event = g_value_get_boxed (param_values + 1);
217 widget = GTK_WIDGET (object);
219 if (event->type == GDK_FOCUS_CHANGE)
221 if (event->focus_change.in)
223 if (GTK_IS_WINDOW (widget))
225 GtkWidget *focus_widget;
229 window = GTK_WINDOW (widget);
230 focus_widget = gtk_window_get_focus (window);
231 g_object_get (window, "type", &type, NULL);
236 * If we already have a potential focus widget set this
237 * windows's focus widget to focus_before_menu so that
238 * it will be reported when menu item is unset.
240 if (next_focus_widget)
242 if (GTK_IS_MENU_ITEM (next_focus_widget) &&
245 void *vp_focus_before_menu = &focus_before_menu;
246 focus_before_menu = focus_widget;
247 g_object_add_weak_pointer (G_OBJECT (focus_before_menu), vp_focus_before_menu);
252 widget = focus_widget;
254 else if (type == GTK_WINDOW_POPUP)
256 if (GTK_IS_BIN (widget))
258 GtkWidget *child = gtk_bin_get_child (GTK_BIN (widget));
260 if (GTK_IS_WIDGET (child) && gtk_widget_has_grab (child))
262 if (GTK_IS_MENU_SHELL (child))
264 if (gtk_menu_shell_get_selected_item (GTK_MENU_SHELL (child)))
267 * We have a menu which has a menu item selected
268 * so we do not report focus on the menu.
276 else /* popup window has no children; this edge case occurs in some custom code (OOo for instance) */
281 else /* Widget is a non-popup toplevel with no focus children;
282 don't emit for this case either, as it's useless */
290 if (next_focus_widget)
294 toplevel = gtk_widget_get_toplevel (next_focus_widget);
295 if (toplevel == widget)
296 next_focus_widget = NULL;
304 if (event->type == GDK_MOTION_NOTIFY && gtk_widget_has_focus (widget))
306 if (widget == focus_widget)
317 #ifdef GDK_WINDOWING_X11
319 * If the focus widget is a GtkSocket without a plug
320 * then ignore the focus notification as the embedded
321 * plug will report a focus notification.
323 if (GTK_IS_SOCKET (widget) &&
324 gtk_socket_get_plug_window (GTK_SOCKET (widget)) != NULL)
329 * The widget may not yet be visible on the screen so we wait until it is.
331 gail_focus_notify_when_idle (widget);
336 gail_select_watcher (GSignalInvocationHint *ihint,
337 guint n_param_values,
338 const GValue *param_values,
344 object = g_value_get_object (param_values + 0);
345 g_return_val_if_fail (GTK_IS_WIDGET(object), FALSE);
347 widget = GTK_WIDGET (object);
349 if (!gtk_widget_get_mapped (widget))
351 g_signal_connect (widget, "map",
352 G_CALLBACK (gail_map_cb),
356 gail_finish_select (widget);
362 gail_finish_select (GtkWidget *widget)
364 if (GTK_IS_MENU_ITEM (widget))
366 GtkMenuItem* menu_item;
369 menu_item = GTK_MENU_ITEM (widget);
370 submenu = gtk_menu_item_get_submenu (menu_item);
372 !gtk_widget_get_mapped (submenu))
375 * If the submenu is not visble, wait until it is before
376 * reporting focus on the menu item.
380 handler_id = g_signal_handler_find (submenu,
382 g_signal_lookup ("map",
386 (gpointer) gail_map_submenu_cb,
389 g_signal_connect (submenu, "map",
390 G_CALLBACK (gail_map_submenu_cb),
395 * If we are waiting to report focus on a menubar or a menu item
396 * because of a previous deselect, cancel it.
399 focus_notify_handler &&
401 (GTK_IS_MENU_BAR (next_focus_widget) ||
402 GTK_IS_MENU_ITEM (next_focus_widget)))
404 void *vp_next_focus_widget = &next_focus_widget;
405 g_source_remove (focus_notify_handler);
406 g_object_remove_weak_pointer (G_OBJECT (next_focus_widget), vp_next_focus_widget);
407 next_focus_widget = NULL;
408 focus_notify_handler = 0;
409 was_deselect = FALSE;
413 * If previously focused widget is not a GtkMenuItem or a GtkMenu,
414 * keep track of it so we can return to it after menubar is deactivated
417 !GTK_IS_MENU_ITEM (focus_widget) &&
418 !GTK_IS_MENU (focus_widget))
420 void *vp_focus_before_menu = &focus_before_menu;
421 focus_before_menu = focus_widget;
422 g_object_add_weak_pointer (G_OBJECT (focus_before_menu), vp_focus_before_menu);
425 gail_focus_notify_when_idle (widget);
431 gail_map_cb (GtkWidget *widget)
433 gail_finish_select (widget);
437 gail_map_submenu_cb (GtkWidget *widget)
439 if (GTK_IS_MENU (widget))
441 GtkWidget *parent_menu_item;
443 parent_menu_item = gtk_menu_get_attach_widget (GTK_MENU (widget));
444 if (parent_menu_item)
445 gail_finish_select (parent_menu_item);
451 gail_deselect_watcher (GSignalInvocationHint *ihint,
452 guint n_param_values,
453 const GValue *param_values,
458 GtkWidget *menu_shell;
460 object = g_value_get_object (param_values + 0);
461 g_return_val_if_fail (GTK_IS_WIDGET(object), FALSE);
463 widget = GTK_WIDGET (object);
465 if (!GTK_IS_MENU_ITEM (widget))
468 if (subsequent_focus_widget == widget)
469 subsequent_focus_widget = NULL;
471 menu_shell = gtk_widget_get_parent (widget);
472 if (GTK_IS_MENU_SHELL (menu_shell))
474 GtkWidget *parent_menu_shell;
476 parent_menu_shell = gtk_menu_shell_get_parent_shell (GTK_MENU_SHELL (menu_shell));
477 if (parent_menu_shell)
479 GtkWidget *active_menu_item;
481 active_menu_item = gtk_menu_shell_get_selected_item (GTK_MENU_SHELL (parent_menu_shell));
482 if (active_menu_item)
484 gail_focus_notify_when_idle (active_menu_item);
489 if (!GTK_IS_MENU_BAR (menu_shell))
491 gail_focus_notify_when_idle (menu_shell);
500 gail_switch_page_watcher (GSignalInvocationHint *ihint,
501 guint n_param_values,
502 const GValue *param_values,
508 object = g_value_get_object (param_values + 0);
509 g_return_val_if_fail (GTK_IS_WIDGET(object), FALSE);
511 widget = GTK_WIDGET (object);
513 if (!GTK_IS_NOTEBOOK (widget))
516 if (gtk_notebook_get_current_page (GTK_NOTEBOOK (widget)) == -1)
519 gail_focus_notify_when_idle (widget);
524 gail_focus_idle_handler (gpointer data)
526 focus_notify_handler = 0;
528 * The widget which was to receive focus may have been removed
530 if (!next_focus_widget)
532 if (next_focus_widget != data)
537 void *vp_next_focus_widget = &next_focus_widget;
538 g_object_remove_weak_pointer (G_OBJECT (next_focus_widget), vp_next_focus_widget);
539 next_focus_widget = NULL;
542 gail_focus_notify (data);
548 gail_focus_notify (GtkWidget *widget)
553 if (widget != focus_widget)
557 void *vp_focus_widget = &focus_widget;
558 g_object_remove_weak_pointer (G_OBJECT (focus_widget), vp_focus_widget);
560 focus_widget = widget;
563 void *vp_focus_widget = &focus_widget;
564 g_object_add_weak_pointer (G_OBJECT (focus_widget), vp_focus_widget);
566 * The UI may not have been updated yet; e.g. in gtkhtml2
567 * html_view_layout() is called in a idle handler
569 if (focus_widget == focus_before_menu)
571 void *vp_focus_before_menu = &focus_before_menu;
572 g_object_remove_weak_pointer (G_OBJECT (focus_before_menu), vp_focus_before_menu);
573 focus_before_menu = NULL;
576 gail_focus_notify_when_idle (focus_widget);
581 atk_obj = gail_get_accessible_for_widget (focus_widget, &transient);
585 * Do not report focus on redundant object
588 (atk_object_get_role(atk_obj) != ATK_ROLE_REDUNDANT_OBJECT))
589 atk_focus_tracker_notify (atk_obj);
590 if (atk_obj && transient)
591 g_object_unref (atk_obj);
592 if (subsequent_focus_widget)
594 GtkWidget *tmp_widget = subsequent_focus_widget;
595 subsequent_focus_widget = NULL;
596 gail_focus_notify_when_idle (tmp_widget);
602 gail_focus_notify_when_idle (GtkWidget *widget)
604 if (focus_notify_handler)
609 * Ignore focus request when menu item is going to be focused.
612 if (GTK_IS_MENU_ITEM (next_focus_widget) && !GTK_IS_MENU_ITEM (widget))
615 if (next_focus_widget)
617 if (GTK_IS_MENU_ITEM (next_focus_widget) && GTK_IS_MENU_ITEM (widget))
619 if (gtk_menu_item_get_submenu (GTK_MENU_ITEM (next_focus_widget)) == gtk_widget_get_parent (widget))
621 if (subsequent_focus_widget)
622 g_assert_not_reached ();
623 subsequent_focus_widget = widget;
628 g_source_remove (focus_notify_handler);
629 if (next_focus_widget)
631 void *vp_next_focus_widget = &next_focus_widget;
632 g_object_remove_weak_pointer (G_OBJECT (next_focus_widget), vp_next_focus_widget);
633 next_focus_widget = NULL;
638 * Ignore if focus is being set to NULL and we are waiting to set focus
645 void *vp_next_focus_widget = &next_focus_widget;
646 next_focus_widget = widget;
647 g_object_add_weak_pointer (G_OBJECT (next_focus_widget), vp_next_focus_widget);
652 * We are about to report focus as NULL so remove the weak pointer
653 * for the widget we were waiting to report focus on.
655 if (next_focus_widget)
657 void *vp_next_focus_widget = &next_focus_widget;
658 g_object_remove_weak_pointer (G_OBJECT (next_focus_widget), vp_next_focus_widget);
659 next_focus_widget = NULL;
663 focus_notify_handler = gdk_threads_add_idle (gail_focus_idle_handler, widget);
667 gail_deactivate_watcher (GSignalInvocationHint *ihint,
668 guint n_param_values,
669 const GValue *param_values,
675 GtkWidget *focus = NULL;
677 object = g_value_get_object (param_values + 0);
678 g_return_val_if_fail (GTK_IS_WIDGET(object), FALSE);
679 widget = GTK_WIDGET (object);
681 g_return_val_if_fail (GTK_IS_MENU_SHELL(widget), TRUE);
682 shell = GTK_MENU_SHELL(widget);
683 if (! gtk_menu_shell_get_parent_shell (shell))
684 focus = focus_before_menu;
687 * If we are waiting to report focus on a menubar or a menu item
688 * because of a previous deselect, cancel it.
691 focus_notify_handler &&
693 (GTK_IS_MENU_BAR (next_focus_widget) ||
694 GTK_IS_MENU_ITEM (next_focus_widget)))
696 void *vp_next_focus_widget = &next_focus_widget;
697 g_source_remove (focus_notify_handler);
698 g_object_remove_weak_pointer (G_OBJECT (next_focus_widget), vp_next_focus_widget);
699 next_focus_widget = NULL;
700 focus_notify_handler = 0;
701 was_deselect = FALSE;
703 gail_focus_notify_when_idle (focus);
709 gail_focus_tracker_init (void)
711 static gboolean emission_hooks_added = FALSE;
713 if (!emission_hooks_added)
716 * We cannot be sure that the classes exist so we make sure that they do.
718 g_type_class_ref (GTK_TYPE_WIDGET);
719 g_type_class_ref (GTK_TYPE_MENU_ITEM);
720 g_type_class_ref (GTK_TYPE_MENU_SHELL);
721 g_type_class_ref (GTK_TYPE_NOTEBOOK);
724 * We listen for event_after signal and then check that the
725 * event was a focus in event so we get called after the event.
727 g_signal_add_emission_hook (
728 g_signal_lookup ("event-after", GTK_TYPE_WIDGET), 0,
729 gail_focus_watcher, NULL, (GDestroyNotify) NULL);
731 * A "select" signal is emitted when arrow key is used to
732 * move to a list item in the popup window of a GtkCombo or
733 * a menu item in a menu.
735 g_signal_add_emission_hook (
736 g_signal_lookup ("select", GTK_TYPE_MENU_ITEM), 0,
737 gail_select_watcher, NULL, (GDestroyNotify) NULL);
740 * A "deselect" signal is emitted when arrow key is used to
741 * move from a menu item in a menu to the parent menu.
743 g_signal_add_emission_hook (
744 g_signal_lookup ("deselect", GTK_TYPE_MENU_ITEM), 0,
745 gail_deselect_watcher, NULL, (GDestroyNotify) NULL);
748 * We listen for deactivate signals on menushells to determine
749 * when the "focus" has left the menus.
751 g_signal_add_emission_hook (
752 g_signal_lookup ("deactivate", GTK_TYPE_MENU_SHELL), 0,
753 gail_deactivate_watcher, NULL, (GDestroyNotify) NULL);
756 * We listen for "switch-page" signal on a GtkNotebook to notify
757 * when page has changed because of clicking on a notebook tab.
759 g_signal_add_emission_hook (
760 g_signal_lookup ("switch-page", GTK_TYPE_NOTEBOOK), 0,
761 gail_switch_page_watcher, NULL, (GDestroyNotify) NULL);
762 emission_hooks_added = TRUE;
767 gail_focus_object_destroyed (gpointer data)
771 obj = G_OBJECT (data);
772 g_object_set_qdata (obj, quark_focus_object, NULL);
773 g_object_unref (obj);
777 gail_focus_tracker (AtkObject *focus_object)
780 * Do not report focus on redundant object
783 (atk_object_get_role(focus_object) != ATK_ROLE_REDUNDANT_OBJECT))
785 AtkObject *old_focus_object;
787 if (!GTK_IS_ACCESSIBLE (focus_object))
791 parent = focus_object;
794 parent = atk_object_get_parent (parent);
797 if (GTK_IS_ACCESSIBLE (parent))
803 gail_set_focus_object (focus_object, parent);
808 old_focus_object = g_object_get_qdata (G_OBJECT (focus_object), quark_focus_object);
809 if (old_focus_object)
811 g_object_weak_unref (G_OBJECT (old_focus_object),
812 (GWeakNotify) gail_focus_object_destroyed,
814 g_object_set_qdata (G_OBJECT (focus_object), quark_focus_object, NULL);
815 g_object_unref (G_OBJECT (focus_object));
822 gail_set_focus_widget (GtkWidget *focus_widget,
825 AtkObject *focus_obj;
828 focus_obj = gtk_widget_get_accessible (focus_widget);
829 obj = gtk_widget_get_accessible (widget);
830 gail_set_focus_object (focus_obj, obj);
834 gail_set_focus_object (AtkObject *focus_obj,
837 AtkObject *old_focus_obj;
839 old_focus_obj = g_object_get_qdata (G_OBJECT (obj), quark_focus_object);
840 if (old_focus_obj != obj)
843 g_object_weak_unref (G_OBJECT (old_focus_obj),
844 (GWeakNotify) gail_focus_object_destroyed,
848 * We call g_object_ref as if obj is destroyed
849 * while the weak reference exists then destroying the
850 * focus_obj would cause gail_focus_object_destroyed to be
851 * called when obj is not a valid GObject.
855 g_object_weak_ref (G_OBJECT (focus_obj),
856 (GWeakNotify) gail_focus_object_destroyed,
858 g_object_set_qdata (G_OBJECT (obj), quark_focus_object, focus_obj);
862 static int gail_initialized = FALSE;
865 gail_accessibility_module_init (void)
867 const char *env_a_t_support;
868 gboolean a_t_support = FALSE;
870 if (gail_initialized)
874 gail_initialized = TRUE;
875 quark_focus_object = g_quark_from_static_string ("gail-focus-object");
877 env_a_t_support = g_getenv (GNOME_ACCESSIBILITY_ENV);
880 a_t_support = atoi (env_a_t_support);
882 fprintf (stderr, "GTK Accessibility Module initialized\n");
884 GAIL_WIDGET_SET_FACTORY (GTK_TYPE_WIDGET, gail_widget);
885 GAIL_WIDGET_SET_FACTORY (GTK_TYPE_CONTAINER, gail_container);
886 GAIL_WIDGET_SET_FACTORY (GTK_TYPE_BUTTON, gail_button);
887 GAIL_WIDGET_SET_FACTORY (GTK_TYPE_LINK_BUTTON, gail_link_button);
888 GAIL_WIDGET_SET_FACTORY (GTK_TYPE_MENU_ITEM, gail_menu_item);
889 GAIL_WIDGET_SET_FACTORY (GTK_TYPE_TOGGLE_BUTTON, gail_toggle_button);
890 GAIL_WIDGET_SET_FACTORY (GTK_TYPE_IMAGE, gail_image);
891 GAIL_WIDGET_SET_FACTORY (GTK_TYPE_COMBO_BOX, gail_combo_box);
892 GAIL_WIDGET_SET_FACTORY (GTK_TYPE_MENU_BAR, gail_menu_shell);
893 GAIL_WIDGET_SET_FACTORY (GTK_TYPE_MENU, gail_menu);
894 GAIL_WIDGET_SET_FACTORY (GTK_TYPE_WINDOW, gail_window);
895 GAIL_WIDGET_SET_FACTORY (GTK_TYPE_RANGE, gail_range);
896 GAIL_WIDGET_SET_FACTORY (GTK_TYPE_SCALE_BUTTON, gail_scale_button);
897 GAIL_WIDGET_SET_FACTORY (GTK_TYPE_STATUSBAR, gail_statusbar);
898 GAIL_WIDGET_SET_FACTORY (GTK_TYPE_NOTEBOOK, gail_notebook);
899 GAIL_WIDGET_SET_FACTORY (GTK_TYPE_CALENDAR, gail_calendar);
900 GAIL_WIDGET_SET_FACTORY (GTK_TYPE_PROGRESS_BAR, gail_progress_bar);
901 GAIL_WIDGET_SET_FACTORY (GTK_TYPE_TREE_VIEW, gail_tree_view);
902 GAIL_WIDGET_SET_FACTORY (GTK_TYPE_FRAME, gail_frame);
903 GAIL_WIDGET_SET_FACTORY (GTK_TYPE_CELL_RENDERER_TEXT, gail_text_cell);
904 GAIL_WIDGET_SET_FACTORY (GTK_TYPE_CELL_RENDERER_TOGGLE, gail_boolean_cell);
905 GAIL_WIDGET_SET_FACTORY (GTK_TYPE_CELL_RENDERER_PIXBUF, gail_image_cell);
906 GAIL_WIDGET_SET_FACTORY (GTK_TYPE_CELL_RENDERER, gail_renderer_cell);
907 GAIL_WIDGET_SET_FACTORY (GTK_TYPE_RADIO_BUTTON, gail_radio_button);
908 GAIL_WIDGET_SET_FACTORY (GTK_TYPE_ARROW, gail_arrow);
909 GAIL_WIDGET_SET_FACTORY (GTK_TYPE_SEPARATOR, gail_separator);
910 GAIL_WIDGET_SET_FACTORY (GTK_TYPE_BOX, gail_box);
911 GAIL_WIDGET_SET_FACTORY (GTK_TYPE_SCROLLED_WINDOW, gail_scrolled_window);
912 GAIL_WIDGET_SET_FACTORY (GTK_TYPE_PANED, gail_paned);
913 GAIL_WIDGET_SET_FACTORY (GTK_TYPE_SCROLLBAR, gail_scrollbar);
914 GAIL_WIDGET_SET_FACTORY (GTK_TYPE_CHECK_MENU_ITEM, gail_check_menu_item);
915 GAIL_WIDGET_SET_FACTORY (GTK_TYPE_RADIO_MENU_ITEM, gail_radio_menu_item);
916 GAIL_WIDGET_SET_FACTORY (GTK_TYPE_EXPANDER, gail_expander);
918 atk_focus_tracker_init (gail_focus_tracker_init);
919 focus_tracker_id = atk_add_focus_tracker (gail_focus_tracker);
921 /* Initialize the GailUtility class */
922 g_type_class_unref (g_type_class_ref (GAIL_TYPE_UTIL));
923 g_type_class_unref (g_type_class_ref (GAIL_TYPE_MISC));