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.
27 #include "gailfactory.h"
29 #define GNOME_ACCESSIBILITY_ENV "GNOME_ACCESSIBILITY"
31 static gboolean gail_focus_watcher (GSignalInvocationHint *ihint,
33 const GValue *param_values,
35 static gboolean gail_select_watcher (GSignalInvocationHint *ihint,
37 const GValue *param_values,
39 static gboolean gail_deselect_watcher (GSignalInvocationHint *ihint,
41 const GValue *param_values,
43 static gboolean gail_switch_page_watcher(GSignalInvocationHint *ihint,
45 const GValue *param_values,
47 static AtkObject* gail_get_accessible_for_widget (GtkWidget *widget,
49 static void gail_finish_select (GtkWidget *widget);
50 static void gail_map_cb (GtkWidget *widget);
51 static void gail_map_submenu_cb (GtkWidget *widget);
52 static gint gail_focus_idle_handler (gpointer data);
53 static void gail_focus_notify (GtkWidget *widget);
54 static void gail_focus_notify_when_idle (GtkWidget *widget);
56 static void gail_focus_tracker_init (void);
57 static void gail_focus_object_destroyed (gpointer data);
58 static void gail_focus_tracker (AtkObject *object);
59 static void gail_set_focus_widget (GtkWidget *focus_widget,
61 static void gail_set_focus_object (AtkObject *focus_obj,
64 GtkWidget* focus_widget = NULL;
65 static GtkWidget* next_focus_widget = NULL;
66 static gboolean was_deselect = FALSE;
67 static GtkWidget* subsequent_focus_widget = NULL;
68 static GtkWidget* focus_before_menu = NULL;
69 static guint focus_notify_handler = 0;
70 static guint focus_tracker_id = 0;
71 static GQuark quark_focus_object = 0;
73 GAIL_IMPLEMENT_FACTORY (GAIL_TYPE_OBJECT, GailObject, gail_object, GTK_TYPE_OBJECT)
74 GAIL_IMPLEMENT_FACTORY (GAIL_TYPE_WIDGET, GailWidget, gail_widget, GTK_TYPE_WIDGET)
75 GAIL_IMPLEMENT_FACTORY (GAIL_TYPE_CONTAINER, GailContainer, gail_container, GTK_TYPE_CONTAINER)
76 GAIL_IMPLEMENT_FACTORY (GAIL_TYPE_BUTTON, GailButton, gail_button, GTK_TYPE_BUTTON)
77 GAIL_IMPLEMENT_FACTORY (GAIL_TYPE_ITEM, GailItem, gail_item, GTK_TYPE_ITEM)
78 GAIL_IMPLEMENT_FACTORY_WITH_FUNC (GAIL_TYPE_MENU_ITEM, GailMenuItem, gail_menu_item, gail_menu_item_new)
79 GAIL_IMPLEMENT_FACTORY (GAIL_TYPE_TOGGLE_BUTTON, GailToggleButton, gail_toggle_button, GTK_TYPE_TOGGLE_BUTTON)
80 GAIL_IMPLEMENT_FACTORY (GAIL_TYPE_IMAGE, GailImage, gail_image, GTK_TYPE_IMAGE)
81 GAIL_IMPLEMENT_FACTORY (GAIL_TYPE_TEXT_VIEW, GailTextView, gail_text_view, GTK_TYPE_TEXT_VIEW)
82 GAIL_IMPLEMENT_FACTORY (GAIL_TYPE_COMBO, GailCombo, gail_combo, GTK_TYPE_COMBO)
83 GAIL_IMPLEMENT_FACTORY (GAIL_TYPE_COMBO_BOX, GailComboBox, gail_combo_box, GTK_TYPE_COMBO_BOX)
84 GAIL_IMPLEMENT_FACTORY (GAIL_TYPE_ENTRY, GailEntry, gail_entry, GTK_TYPE_ENTRY)
85 GAIL_IMPLEMENT_FACTORY (GAIL_TYPE_MENU_SHELL, GailMenuShell, gail_menu_shell, GTK_TYPE_MENU_SHELL)
86 GAIL_IMPLEMENT_FACTORY (GAIL_TYPE_MENU, GailMenu, gail_menu, GTK_TYPE_MENU)
87 GAIL_IMPLEMENT_FACTORY (GAIL_TYPE_WINDOW, GailWindow, gail_window, GTK_TYPE_BIN)
88 GAIL_IMPLEMENT_FACTORY (GAIL_TYPE_RANGE, GailRange, gail_range, GTK_TYPE_RANGE)
89 GAIL_IMPLEMENT_FACTORY (GAIL_TYPE_SCALE, GailScale, gail_scale, GTK_TYPE_SCALE)
90 GAIL_IMPLEMENT_FACTORY (GAIL_TYPE_CLIST, GailCList, gail_clist, GTK_TYPE_CLIST)
91 GAIL_IMPLEMENT_FACTORY (GAIL_TYPE_LABEL, GailLabel, gail_label, GTK_TYPE_LABEL)
92 GAIL_IMPLEMENT_FACTORY (GAIL_TYPE_STATUSBAR, GailStatusbar, gail_statusbar, GTK_TYPE_STATUSBAR)
93 GAIL_IMPLEMENT_FACTORY (GAIL_TYPE_NOTEBOOK, GailNotebook, gail_notebook, GTK_TYPE_NOTEBOOK)
94 GAIL_IMPLEMENT_FACTORY (GAIL_TYPE_CALENDAR, GailCalendar, gail_calendar, GTK_TYPE_CALENDAR)
95 GAIL_IMPLEMENT_FACTORY (GAIL_TYPE_PROGRESS_BAR, GailProgressBar, gail_progress_bar, GTK_TYPE_PROGRESS_BAR)
96 GAIL_IMPLEMENT_FACTORY (GAIL_TYPE_SPIN_BUTTON, GailSpinButton, gail_spin_button, GTK_TYPE_SPIN_BUTTON)
97 GAIL_IMPLEMENT_FACTORY (GAIL_TYPE_TREE_VIEW, GailTreeView, gail_tree_view, GTK_TYPE_TREE_VIEW)
98 GAIL_IMPLEMENT_FACTORY (GAIL_TYPE_FRAME, GailFrame, gail_frame, GTK_TYPE_FRAME)
99 GAIL_IMPLEMENT_FACTORY (GAIL_TYPE_RADIO_BUTTON, GailRadioButton, gail_radio_button, GTK_TYPE_RADIO_BUTTON)
100 GAIL_IMPLEMENT_FACTORY (GAIL_TYPE_ARROW, GailArrow, gail_arrow, GTK_TYPE_ARROW)
101 GAIL_IMPLEMENT_FACTORY (GAIL_TYPE_PIXMAP, GailPixmap, gail_pixmap, GTK_TYPE_PIXMAP)
102 GAIL_IMPLEMENT_FACTORY (GAIL_TYPE_SEPARATOR, GailSeparator, gail_separator, GTK_TYPE_SEPARATOR)
103 GAIL_IMPLEMENT_FACTORY (GAIL_TYPE_BOX, GailBox, gail_box, GTK_TYPE_BOX)
104 GAIL_IMPLEMENT_FACTORY (GAIL_TYPE_SCROLLED_WINDOW, GailScrolledWindow, gail_scrolled_window, GTK_TYPE_SCROLLED_WINDOW)
105 GAIL_IMPLEMENT_FACTORY (GAIL_TYPE_LIST, GailList, gail_list, GTK_TYPE_LIST)
106 GAIL_IMPLEMENT_FACTORY (GAIL_TYPE_PANED, GailPaned, gail_paned, GTK_TYPE_PANED)
107 GAIL_IMPLEMENT_FACTORY (GAIL_TYPE_SCROLLBAR, GailScrollbar, gail_scrollbar, GTK_TYPE_SCROLLBAR)
108 GAIL_IMPLEMENT_FACTORY (GAIL_TYPE_OPTION_MENU, GailOptionMenu, gail_option_menu, GTK_TYPE_OPTION_MENU)
109 GAIL_IMPLEMENT_FACTORY_WITH_FUNC (GAIL_TYPE_CHECK_MENU_ITEM, GailCheckMenuItem, gail_check_menu_item, gail_check_menu_item_new)
110 GAIL_IMPLEMENT_FACTORY_WITH_FUNC (GAIL_TYPE_RADIO_MENU_ITEM, GailRadioMenuItem, gail_radio_menu_item, gail_radio_menu_item_new)
111 GAIL_IMPLEMENT_FACTORY (GAIL_TYPE_EXPANDER, GailExpander, gail_expander, GTK_TYPE_EXPANDER)
112 GAIL_IMPLEMENT_FACTORY_WITH_FUNC_DUMMY (GAIL_TYPE_RENDERER_CELL, GailRendererCell, gail_renderer_cell, GTK_TYPE_CELL_RENDERER, gail_renderer_cell_new)
113 GAIL_IMPLEMENT_FACTORY_WITH_FUNC_DUMMY (GAIL_TYPE_BOOLEAN_CELL, GailBooleanCell, gail_boolean_cell, GTK_TYPE_CELL_RENDERER_TOGGLE, gail_boolean_cell_new)
114 GAIL_IMPLEMENT_FACTORY_WITH_FUNC_DUMMY (GAIL_TYPE_IMAGE_CELL, GailImageCell, gail_image_cell, GTK_TYPE_CELL_RENDERER_PIXBUF, gail_image_cell_new)
115 GAIL_IMPLEMENT_FACTORY_WITH_FUNC_DUMMY (GAIL_TYPE_TEXT_CELL, GailTextCell, gail_text_cell, GTK_TYPE_CELL_RENDERER_TEXT, gail_text_cell_new)
118 gail_get_accessible_for_widget (GtkWidget *widget,
121 AtkObject *obj = NULL;
124 gnome_canvas = g_type_from_name ("GnomeCanvas");
130 if (GTK_IS_ENTRY (widget))
132 GtkWidget *other_widget = widget->parent;
133 if (GTK_IS_COMBO (other_widget))
135 gail_set_focus_widget (other_widget, widget);
136 widget = other_widget;
139 else if (GTK_IS_NOTEBOOK (widget))
141 GtkNotebook *notebook;
144 notebook = GTK_NOTEBOOK (widget);
146 * Report the currently focused tab rather than the currently selected tab
148 if (notebook->focus_tab)
150 page_num = g_list_index (notebook->children, notebook->focus_tab->data);
154 obj = gtk_widget_get_accessible (widget);
155 obj = atk_object_ref_accessible_child (obj, page_num);
156 g_object_unref (obj);
159 else if (GTK_CHECK_TYPE ((widget), gnome_canvas))
161 GObject *focused_item;
162 GValue value = {0, };
164 g_value_init (&value, G_TYPE_OBJECT);
165 g_object_get_property (G_OBJECT (widget), "focused_item", &value);
166 focused_item = g_value_get_object (&value);
172 obj = atk_gobject_accessible_for_object (G_OBJECT (focused_item));
173 tmp = g_object_get_qdata (G_OBJECT (obj), quark_focus_object);
178 else if (GTK_IS_TOGGLE_BUTTON (widget))
180 GtkWidget *other_widget = widget->parent;
181 if (GTK_IS_COMBO_BOX (other_widget))
183 gail_set_focus_widget (other_widget, widget);
184 widget = other_widget;
189 AtkObject *focus_object;
191 obj = gtk_widget_get_accessible (widget);
192 focus_object = g_object_get_qdata (G_OBJECT (obj), quark_focus_object);
194 * We check whether the object for this focus_object has been deleted.
195 * This can happen when navigating to an empty directory in nautilus.
198 if (ATK_IS_GOBJECT_ACCESSIBLE (focus_object))
200 if (!atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (focus_object)))
211 gail_focus_watcher (GSignalInvocationHint *ihint,
212 guint n_param_values,
213 const GValue *param_values,
220 object = g_value_get_object (param_values + 0);
221 g_return_val_if_fail (GTK_IS_WIDGET(object), FALSE);
223 event = g_value_get_boxed (param_values + 1);
224 widget = GTK_WIDGET (object);
226 if (event->type == GDK_FOCUS_CHANGE)
228 if (event->focus_change.in)
230 if (GTK_IS_WINDOW (widget))
234 window = GTK_WINDOW (widget);
235 if (window->focus_widget)
238 * If we already have a potential focus widget set this
239 * windows's focus widget to focus_before_menu so that
240 * it will be reported when menu item is unset.
242 if (next_focus_widget)
244 if (GTK_IS_MENU_ITEM (next_focus_widget) &&
247 void *vp_focus_before_menu = &focus_before_menu;
248 focus_before_menu = window->focus_widget;
249 g_object_add_weak_pointer (G_OBJECT (focus_before_menu), vp_focus_before_menu);
254 widget = window->focus_widget;
256 else if (window->type == GTK_WINDOW_POPUP)
258 if (GTK_IS_BIN (widget))
260 GtkWidget *child = gtk_bin_get_child (GTK_BIN (widget));
262 if (GTK_IS_WIDGET (child) && GTK_WIDGET_HAS_GRAB (child))
264 if (GTK_IS_MENU_SHELL (child))
266 if (GTK_MENU_SHELL (child)->active_menu_item)
269 * We have a menu which has a menu item selected
270 * so we do not report focus on the menu.
278 else /* popup window has no children; this edge case occurs in some custom code (OOo for instance) */
283 else /* Widget is a non-popup toplevel with no focus children;
284 don't emit for this case either, as it's useless */
292 if (next_focus_widget)
296 toplevel = gtk_widget_get_toplevel (next_focus_widget);
297 if (toplevel == widget)
298 next_focus_widget = NULL;
306 if (event->type == GDK_MOTION_NOTIFY && GTK_WIDGET_HAS_FOCUS (widget))
308 if (widget == focus_widget)
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 (widget)->plug_widget == NULL)
327 * The widget may not yet be visible on the screen so we wait until it is.
329 gail_focus_notify_when_idle (widget);
334 gail_select_watcher (GSignalInvocationHint *ihint,
335 guint n_param_values,
336 const GValue *param_values,
342 object = g_value_get_object (param_values + 0);
343 g_return_val_if_fail (GTK_IS_WIDGET(object), FALSE);
345 widget = GTK_WIDGET (object);
347 if (!GTK_WIDGET_MAPPED (widget))
349 g_signal_connect (widget, "map",
350 G_CALLBACK (gail_map_cb),
354 gail_finish_select (widget);
360 gail_finish_select (GtkWidget *widget)
362 if (GTK_IS_MENU_ITEM (widget))
364 GtkMenuItem* menu_item;
366 menu_item = GTK_MENU_ITEM (widget);
367 if (menu_item->submenu &&
368 !GTK_WIDGET_MAPPED (menu_item->submenu))
371 * If the submenu is not visble, wait until it is before
372 * reporting focus on the menu item.
376 handler_id = g_signal_handler_find (menu_item->submenu,
378 g_signal_lookup ("map",
382 (gpointer) gail_map_submenu_cb,
385 g_signal_connect (menu_item->submenu, "map",
386 G_CALLBACK (gail_map_submenu_cb),
392 * If we are waiting to report focus on a menubar or a menu item
393 * because of a previous deselect, cancel it.
396 focus_notify_handler &&
398 (GTK_IS_MENU_BAR (next_focus_widget) ||
399 GTK_IS_MENU_ITEM (next_focus_widget)))
401 void *vp_next_focus_widget = &next_focus_widget;
402 g_source_remove (focus_notify_handler);
403 g_object_remove_weak_pointer (G_OBJECT (next_focus_widget), vp_next_focus_widget);
404 next_focus_widget = NULL;
405 focus_notify_handler = 0;
406 was_deselect = FALSE;
410 * If previously focused widget is not a GtkMenuItem or a GtkMenu,
411 * keep track of it so we can return to it after menubar is deactivated
414 !GTK_IS_MENU_ITEM (focus_widget) &&
415 !GTK_IS_MENU (focus_widget))
417 void *vp_focus_before_menu = &focus_before_menu;
418 focus_before_menu = focus_widget;
419 g_object_add_weak_pointer (G_OBJECT (focus_before_menu), vp_focus_before_menu);
422 gail_focus_notify_when_idle (widget);
428 gail_map_cb (GtkWidget *widget)
430 gail_finish_select (widget);
434 gail_map_submenu_cb (GtkWidget *widget)
436 if (GTK_IS_MENU (widget))
438 if (GTK_MENU (widget)->parent_menu_item)
439 gail_finish_select (GTK_MENU (widget)->parent_menu_item);
445 gail_deselect_watcher (GSignalInvocationHint *ihint,
446 guint n_param_values,
447 const GValue *param_values,
452 GtkWidget *menu_shell;
454 object = g_value_get_object (param_values + 0);
455 g_return_val_if_fail (GTK_IS_WIDGET(object), FALSE);
457 widget = GTK_WIDGET (object);
459 if (!GTK_IS_MENU_ITEM (widget))
462 if (subsequent_focus_widget == widget)
463 subsequent_focus_widget = NULL;
465 menu_shell = gtk_widget_get_parent (widget);
466 if (GTK_IS_MENU_SHELL (menu_shell))
468 GtkWidget *parent_menu_shell;
470 parent_menu_shell = GTK_MENU_SHELL (menu_shell)->parent_menu_shell;
471 if (parent_menu_shell)
473 GtkWidget *active_menu_item;
475 active_menu_item = GTK_MENU_SHELL (parent_menu_shell)->active_menu_item;
476 if (active_menu_item)
478 gail_focus_notify_when_idle (active_menu_item);
483 if (!GTK_IS_MENU_BAR (menu_shell))
485 gail_focus_notify_when_idle (menu_shell);
494 gail_switch_page_watcher (GSignalInvocationHint *ihint,
495 guint n_param_values,
496 const GValue *param_values,
501 GtkNotebook *notebook;
503 object = g_value_get_object (param_values + 0);
504 g_return_val_if_fail (GTK_IS_WIDGET(object), FALSE);
506 widget = GTK_WIDGET (object);
508 if (!GTK_IS_NOTEBOOK (widget))
511 notebook = GTK_NOTEBOOK (widget);
512 if (!notebook->focus_tab)
515 gail_focus_notify_when_idle (widget);
520 gail_focus_idle_handler (gpointer data)
522 focus_notify_handler = 0;
524 * The widget which was to receive focus may have been removed
526 if (!next_focus_widget)
528 if (next_focus_widget != data)
533 void *vp_next_focus_widget = &next_focus_widget;
534 g_object_remove_weak_pointer (G_OBJECT (next_focus_widget), vp_next_focus_widget);
535 next_focus_widget = NULL;
538 gail_focus_notify (data);
544 gail_focus_notify (GtkWidget *widget)
549 if (widget != focus_widget)
553 void *vp_focus_widget = &focus_widget;
554 g_object_remove_weak_pointer (G_OBJECT (focus_widget), vp_focus_widget);
556 focus_widget = widget;
559 void *vp_focus_widget = &focus_widget;
560 g_object_add_weak_pointer (G_OBJECT (focus_widget), vp_focus_widget);
562 * The UI may not have been updated yet; e.g. in gtkhtml2
563 * html_view_layout() is called in a idle handler
565 if (focus_widget == focus_before_menu)
567 void *vp_focus_before_menu = &focus_before_menu;
568 g_object_remove_weak_pointer (G_OBJECT (focus_before_menu), vp_focus_before_menu);
569 focus_before_menu = NULL;
572 gail_focus_notify_when_idle (focus_widget);
577 atk_obj = gail_get_accessible_for_widget (focus_widget, &transient);
581 * Do not report focus on redundant object
584 (atk_object_get_role(atk_obj) != ATK_ROLE_REDUNDANT_OBJECT))
585 atk_focus_tracker_notify (atk_obj);
586 if (atk_obj && transient)
587 g_object_unref (atk_obj);
588 if (subsequent_focus_widget)
590 GtkWidget *tmp_widget = subsequent_focus_widget;
591 subsequent_focus_widget = NULL;
592 gail_focus_notify_when_idle (tmp_widget);
598 gail_focus_notify_when_idle (GtkWidget *widget)
600 if (focus_notify_handler)
605 * Ignore focus request when menu item is going to be focused.
608 if (GTK_IS_MENU_ITEM (next_focus_widget) && !GTK_IS_MENU_ITEM (widget))
611 if (next_focus_widget)
613 if (GTK_IS_MENU_ITEM (next_focus_widget) && GTK_IS_MENU_ITEM (widget))
615 if (gtk_menu_item_get_submenu (GTK_MENU_ITEM (next_focus_widget)) == gtk_widget_get_parent (widget))
617 if (subsequent_focus_widget)
618 g_assert_not_reached ();
619 subsequent_focus_widget = widget;
624 g_source_remove (focus_notify_handler);
625 if (next_focus_widget)
627 void *vp_next_focus_widget = &next_focus_widget;
628 g_object_remove_weak_pointer (G_OBJECT (next_focus_widget), vp_next_focus_widget);
629 next_focus_widget = NULL;
634 * Ignore if focus is being set to NULL and we are waiting to set focus
641 void *vp_next_focus_widget = &next_focus_widget;
642 next_focus_widget = widget;
643 g_object_add_weak_pointer (G_OBJECT (next_focus_widget), vp_next_focus_widget);
648 * We are about to report focus as NULL so remove the weak pointer
649 * for the widget we were waiting to report focus on.
651 if (next_focus_widget)
653 void *vp_next_focus_widget = &next_focus_widget;
654 g_object_remove_weak_pointer (G_OBJECT (next_focus_widget), vp_next_focus_widget);
655 next_focus_widget = NULL;
659 focus_notify_handler = gdk_threads_add_idle (gail_focus_idle_handler, widget);
663 gail_deactivate_watcher (GSignalInvocationHint *ihint,
664 guint n_param_values,
665 const GValue *param_values,
671 GtkWidget *focus = NULL;
673 object = g_value_get_object (param_values + 0);
674 g_return_val_if_fail (GTK_IS_WIDGET(object), FALSE);
675 widget = GTK_WIDGET (object);
677 g_return_val_if_fail (GTK_IS_MENU_SHELL(widget), TRUE);
678 shell = GTK_MENU_SHELL(widget);
679 if (!shell->parent_menu_shell)
680 focus = focus_before_menu;
683 * If we are waiting to report focus on a menubar or a menu item
684 * because of a previous deselect, cancel it.
687 focus_notify_handler &&
689 (GTK_IS_MENU_BAR (next_focus_widget) ||
690 GTK_IS_MENU_ITEM (next_focus_widget)))
692 void *vp_next_focus_widget = &next_focus_widget;
693 g_source_remove (focus_notify_handler);
694 g_object_remove_weak_pointer (G_OBJECT (next_focus_widget), vp_next_focus_widget);
695 next_focus_widget = NULL;
696 focus_notify_handler = 0;
697 was_deselect = FALSE;
699 gail_focus_notify_when_idle (focus);
705 gail_focus_tracker_init (void)
707 static gboolean emission_hooks_added = FALSE;
709 if (!emission_hooks_added)
712 * We cannot be sure that the classes exist so we make sure that they do.
714 gtk_type_class (GTK_TYPE_WIDGET);
715 gtk_type_class (GTK_TYPE_ITEM);
716 gtk_type_class (GTK_TYPE_MENU_SHELL);
717 gtk_type_class (GTK_TYPE_NOTEBOOK);
720 * We listen for event_after signal and then check that the
721 * event was a focus in event so we get called after the event.
723 g_signal_add_emission_hook (
724 g_signal_lookup ("event-after", GTK_TYPE_WIDGET), 0,
725 gail_focus_watcher, NULL, (GDestroyNotify) NULL);
727 * A "select" signal is emitted when arrow key is used to
728 * move to a list item in the popup window of a GtkCombo or
729 * a menu item in a menu.
731 g_signal_add_emission_hook (
732 g_signal_lookup ("select", GTK_TYPE_ITEM), 0,
733 gail_select_watcher, NULL, (GDestroyNotify) NULL);
736 * A "deselect" signal is emitted when arrow key is used to
737 * move from a menu item in a menu to the parent menu.
739 g_signal_add_emission_hook (
740 g_signal_lookup ("deselect", GTK_TYPE_ITEM), 0,
741 gail_deselect_watcher, NULL, (GDestroyNotify) NULL);
744 * We listen for deactivate signals on menushells to determine
745 * when the "focus" has left the menus.
747 g_signal_add_emission_hook (
748 g_signal_lookup ("deactivate", GTK_TYPE_MENU_SHELL), 0,
749 gail_deactivate_watcher, NULL, (GDestroyNotify) NULL);
752 * We listen for "switch-page" signal on a GtkNotebook to notify
753 * when page has changed because of clicking on a notebook tab.
755 g_signal_add_emission_hook (
756 g_signal_lookup ("switch-page", GTK_TYPE_NOTEBOOK), 0,
757 gail_switch_page_watcher, NULL, (GDestroyNotify) NULL);
758 emission_hooks_added = TRUE;
763 gail_focus_object_destroyed (gpointer data)
767 obj = G_OBJECT (data);
768 g_object_set_qdata (obj, quark_focus_object, NULL);
769 g_object_unref (obj);
773 gail_focus_tracker (AtkObject *focus_object)
776 * Do not report focus on redundant object
779 (atk_object_get_role(focus_object) != ATK_ROLE_REDUNDANT_OBJECT))
781 AtkObject *old_focus_object;
783 if (!GTK_IS_ACCESSIBLE (focus_object))
787 parent = focus_object;
790 parent = atk_object_get_parent (parent);
793 if (GTK_IS_ACCESSIBLE (parent))
799 gail_set_focus_object (focus_object, parent);
804 old_focus_object = g_object_get_qdata (G_OBJECT (focus_object), quark_focus_object);
805 if (old_focus_object)
807 g_object_weak_unref (G_OBJECT (old_focus_object),
808 (GWeakNotify) gail_focus_object_destroyed,
810 g_object_set_qdata (G_OBJECT (focus_object), quark_focus_object, NULL);
811 g_object_unref (G_OBJECT (focus_object));
818 gail_set_focus_widget (GtkWidget *focus_widget,
821 AtkObject *focus_obj;
824 focus_obj = gtk_widget_get_accessible (focus_widget);
825 obj = gtk_widget_get_accessible (widget);
826 gail_set_focus_object (focus_obj, obj);
830 gail_set_focus_object (AtkObject *focus_obj,
833 AtkObject *old_focus_obj;
835 old_focus_obj = g_object_get_qdata (G_OBJECT (obj), quark_focus_object);
836 if (old_focus_obj != obj)
839 g_object_weak_unref (G_OBJECT (old_focus_obj),
840 (GWeakNotify) gail_focus_object_destroyed,
844 * We call g_object_ref as if obj is destroyed
845 * while the weak reference exists then destroying the
846 * focus_obj would cause gail_focus_object_destroyed to be
847 * called when obj is not a valid GObject.
851 g_object_weak_ref (G_OBJECT (focus_obj),
852 (GWeakNotify) gail_focus_object_destroyed,
854 g_object_set_qdata (G_OBJECT (obj), quark_focus_object, focus_obj);
859 * These exported symbols are hooked by gnome-program
860 * to provide automatic module initialization and shutdown.
862 extern void gnome_accessibility_module_init (void);
863 extern void gnome_accessibility_module_shutdown (void);
865 static int gail_initialized = FALSE;
868 gail_accessibility_module_init (void)
870 const char *env_a_t_support;
871 gboolean a_t_support = FALSE;
873 if (gail_initialized)
877 gail_initialized = TRUE;
878 quark_focus_object = g_quark_from_static_string ("gail-focus-object");
880 env_a_t_support = g_getenv (GNOME_ACCESSIBILITY_ENV);
883 a_t_support = atoi (env_a_t_support);
885 fprintf (stderr, "GTK Accessibility Module initialized\n");
887 GAIL_WIDGET_SET_FACTORY (GTK_TYPE_WIDGET, gail_widget);
888 GAIL_WIDGET_SET_FACTORY (GTK_TYPE_CONTAINER, gail_container);
889 GAIL_WIDGET_SET_FACTORY (GTK_TYPE_BUTTON, gail_button);
890 GAIL_WIDGET_SET_FACTORY (GTK_TYPE_ITEM, gail_item);
891 GAIL_WIDGET_SET_FACTORY (GTK_TYPE_MENU_ITEM, gail_menu_item);
892 GAIL_WIDGET_SET_FACTORY (GTK_TYPE_TOGGLE_BUTTON, gail_toggle_button);
893 GAIL_WIDGET_SET_FACTORY (GTK_TYPE_IMAGE, gail_image);
894 GAIL_WIDGET_SET_FACTORY (GTK_TYPE_TEXT_VIEW, gail_text_view);
895 GAIL_WIDGET_SET_FACTORY (GTK_TYPE_COMBO, gail_combo);
896 GAIL_WIDGET_SET_FACTORY (GTK_TYPE_COMBO_BOX, gail_combo_box);
897 GAIL_WIDGET_SET_FACTORY (GTK_TYPE_ENTRY, gail_entry);
898 GAIL_WIDGET_SET_FACTORY (GTK_TYPE_MENU_BAR, gail_menu_shell);
899 GAIL_WIDGET_SET_FACTORY (GTK_TYPE_MENU, gail_menu);
900 GAIL_WIDGET_SET_FACTORY (GTK_TYPE_WINDOW, gail_window);
901 GAIL_WIDGET_SET_FACTORY (GTK_TYPE_RANGE, gail_range);
902 GAIL_WIDGET_SET_FACTORY (GTK_TYPE_SCALE, gail_scale);
903 GAIL_WIDGET_SET_FACTORY (GTK_TYPE_CLIST, gail_clist);
904 GAIL_WIDGET_SET_FACTORY (GTK_TYPE_LABEL, gail_label);
905 GAIL_WIDGET_SET_FACTORY (GTK_TYPE_STATUSBAR, gail_statusbar);
906 GAIL_WIDGET_SET_FACTORY (GTK_TYPE_NOTEBOOK, gail_notebook);
907 GAIL_WIDGET_SET_FACTORY (GTK_TYPE_CALENDAR, gail_calendar);
908 GAIL_WIDGET_SET_FACTORY (GTK_TYPE_PROGRESS_BAR, gail_progress_bar);
909 GAIL_WIDGET_SET_FACTORY (GTK_TYPE_SPIN_BUTTON, gail_spin_button);
910 GAIL_WIDGET_SET_FACTORY (GTK_TYPE_TREE_VIEW, gail_tree_view);
911 GAIL_WIDGET_SET_FACTORY (GTK_TYPE_FRAME, gail_frame);
912 GAIL_WIDGET_SET_FACTORY (GTK_TYPE_CELL_RENDERER_TEXT, gail_text_cell);
913 GAIL_WIDGET_SET_FACTORY (GTK_TYPE_CELL_RENDERER_TOGGLE, gail_boolean_cell);
914 GAIL_WIDGET_SET_FACTORY (GTK_TYPE_CELL_RENDERER_PIXBUF, gail_image_cell);
915 GAIL_WIDGET_SET_FACTORY (GTK_TYPE_CELL_RENDERER, gail_renderer_cell);
916 GAIL_WIDGET_SET_FACTORY (GTK_TYPE_RADIO_BUTTON, gail_radio_button);
917 GAIL_WIDGET_SET_FACTORY (GTK_TYPE_ARROW, gail_arrow);
918 GAIL_WIDGET_SET_FACTORY (GTK_TYPE_PIXMAP, gail_pixmap);
919 GAIL_WIDGET_SET_FACTORY (GTK_TYPE_SEPARATOR, gail_separator);
920 GAIL_WIDGET_SET_FACTORY (GTK_TYPE_BOX, gail_box);
921 GAIL_WIDGET_SET_FACTORY (GTK_TYPE_SCROLLED_WINDOW, gail_scrolled_window);
922 GAIL_WIDGET_SET_FACTORY (GTK_TYPE_LIST, gail_list);
923 GAIL_WIDGET_SET_FACTORY (GTK_TYPE_PANED, gail_paned);
924 GAIL_WIDGET_SET_FACTORY (GTK_TYPE_SCROLLBAR, gail_scrollbar);
925 GAIL_WIDGET_SET_FACTORY (GTK_TYPE_OPTION_MENU, gail_option_menu);
926 GAIL_WIDGET_SET_FACTORY (GTK_TYPE_CHECK_MENU_ITEM, gail_check_menu_item);
927 GAIL_WIDGET_SET_FACTORY (GTK_TYPE_RADIO_MENU_ITEM, gail_radio_menu_item);
928 GAIL_WIDGET_SET_FACTORY (GTK_TYPE_EXPANDER, gail_expander);
930 /* LIBGNOMECANVAS SUPPORT */
931 GAIL_WIDGET_SET_FACTORY (GTK_TYPE_OBJECT, gail_object);
933 atk_focus_tracker_init (gail_focus_tracker_init);
934 focus_tracker_id = atk_add_focus_tracker (gail_focus_tracker);
936 /* Initialize the GailUtility class */
937 g_type_class_unref (g_type_class_ref (GAIL_TYPE_UTIL));
938 g_type_class_unref (g_type_class_ref (GAIL_TYPE_MISC));
942 * gnome_accessibility_module_init:
945 * This method is invoked by name from libgnome's
946 * gnome-program.c to activate accessibility support.
949 gnome_accessibility_module_init (void)
951 gail_accessibility_module_init ();
955 * gnome_accessibility_module_shutdown:
958 * This method is invoked by name from libgnome's
959 * gnome-program.c to de-activate accessibility support.
962 gnome_accessibility_module_shutdown (void)
964 if (!gail_initialized)
968 gail_initialized = FALSE;
969 atk_remove_focus_tracker (focus_tracker_id);
971 fprintf (stderr, "GTK Accessibility Module shutdown\n");
973 /* FIXME: de-register the factory types so we can unload ? */
977 gtk_module_init (gint *argc, char** argv[])
979 gail_accessibility_module_init ();