diff options
10 files changed, 112 insertions, 20 deletions
diff --git a/chrome/browser/autocomplete/autocomplete_edit_view_gtk.h b/chrome/browser/autocomplete/autocomplete_edit_view_gtk.h index e524820..83aa77a 100644 --- a/chrome/browser/autocomplete/autocomplete_edit_view_gtk.h +++ b/chrome/browser/autocomplete/autocomplete_edit_view_gtk.h @@ -138,6 +138,10 @@ class AutocompleteEditViewGtk : public AutocompleteEditView, enable_tab_to_search_ = enable; } + GtkWidget* text_view() { + return text_view_; + } + private: CHROMEG_CALLBACK_0(AutocompleteEditViewGtk, void, HandleBeginUserAction, GtkTextBuffer*); diff --git a/chrome/browser/gtk/accessibility_event_router_gtk.cc b/chrome/browser/gtk/accessibility_event_router_gtk.cc index e0714de..606fd40 100644 --- a/chrome/browser/gtk/accessibility_event_router_gtk.cc +++ b/chrome/browser/gtk/accessibility_event_router_gtk.cc @@ -117,6 +117,34 @@ gboolean OnEntryChanged(GSignalInvocationHint *ihint, return TRUE; } +gboolean OnTextBufferChanged(GSignalInvocationHint *ihint, + guint n_param_values, + const GValue* param_values, + gpointer user_data) { + // The text hasn't changed yet, so defer calling + // DispatchAccessibilityNotification. + reinterpret_cast<AccessibilityEventRouterGtk*>(user_data)-> + PostDispatchAccessibilityNotification( + NULL, NotificationType::ACCESSIBILITY_TEXT_CHANGED); + return TRUE; +} + +gboolean OnTextViewChanged(GSignalInvocationHint *ihint, + guint n_param_values, + const GValue* param_values, + gpointer user_data) { + GtkWidget* widget = GTK_WIDGET(g_value_get_object(param_values)); + if (!GTK_IS_TEXT_VIEW(widget)) { + return TRUE; + } + // The text hasn't changed yet, so defer calling + // DispatchAccessibilityNotification. + reinterpret_cast<AccessibilityEventRouterGtk*>(user_data)-> + PostDispatchAccessibilityNotification( + widget, NotificationType::ACCESSIBILITY_TEXT_CHANGED); + return TRUE; +} + gboolean OnMenuMoveCurrent(GSignalInvocationHint *ihint, guint n_param_values, const GValue* param_values, @@ -145,6 +173,7 @@ gboolean OnMenuMoveCurrent(GSignalInvocationHint *ihint, AccessibilityEventRouterGtk::AccessibilityEventRouterGtk() : listening_(false), most_recent_profile_(NULL), + most_recent_widget_(NULL), method_factory_(this) { // We don't want our event listeners to be installed if accessibility is // disabled. Install listeners so we can install and uninstall them as @@ -190,6 +219,8 @@ void AccessibilityEventRouterGtk::InstallEventListeners() { g_object_unref(g_object_ref_sink(gtk_notebook_new())); g_object_unref(g_object_ref_sink(gtk_toggle_button_new())); g_object_unref(g_object_ref_sink(gtk_tree_view_new())); + g_object_unref(g_object_ref_sink(gtk_text_view_new())); + g_object_unref(g_object_ref_sink(gtk_text_buffer_new(NULL))); // Add signal emission hooks for the events we're interested in. InstallEventListener("clicked", GTK_TYPE_BUTTON, OnButtonClicked); @@ -204,6 +235,8 @@ void AccessibilityEventRouterGtk::InstallEventListeners() { InstallEventListener("switch-page", GTK_TYPE_NOTEBOOK, OnPageSwitched); InstallEventListener("toggled", GTK_TYPE_TOGGLE_BUTTON, OnButtonToggled); InstallEventListener("move-current", GTK_TYPE_MENU, OnMenuMoveCurrent); + InstallEventListener("changed", GTK_TYPE_TEXT_BUFFER, OnTextBufferChanged); + InstallEventListener("move-cursor", GTK_TYPE_TEXT_VIEW, OnTextViewChanged); listening_ = true; } @@ -297,6 +330,21 @@ void AccessibilityEventRouterGtk::DispatchAccessibilityNotification( Profile* profile = NULL; bool is_accessible; + + // Special case: when we get ACCESSIBILITY_TEXT_CHANGED, we don't get + // a pointer to the widget, so we try to retrieve it from the most recent + // widget. + if (widget == NULL && + type == NotificationType::ACCESSIBILITY_TEXT_CHANGED && + most_recent_widget_ && + GTK_IS_TEXT_VIEW(most_recent_widget_)) { + widget = most_recent_widget_; + } + + if (!widget) + return; + + most_recent_widget_ = widget; FindWidget(widget, &profile, &is_accessible); if (profile) most_recent_profile_ = profile; @@ -331,7 +379,9 @@ void AccessibilityEventRouterGtk::DispatchAccessibilityNotification( } else if (GTK_IS_BUTTON(widget)) { SendButtonNotification(widget, type, profile); } else if (GTK_IS_ENTRY(widget)) { - SendTextBoxNotification(widget, type, profile); + SendEntryNotification(widget, type, profile); + } else if (GTK_IS_TEXT_VIEW(widget)) { + SendTextViewNotification(widget, type, profile); } else if (GTK_IS_NOTEBOOK(widget)) { SendTabNotification(widget, type, profile); } else if (GTK_IS_TREE_VIEW(widget)) { @@ -410,7 +460,7 @@ void AccessibilityEventRouterGtk::SendButtonNotification( SendAccessibilityNotification(type, &info); } -void AccessibilityEventRouterGtk::SendTextBoxNotification( +void AccessibilityEventRouterGtk::SendEntryNotification( GtkWidget* widget, NotificationType type, Profile* profile) { std::string name = GetWidgetName(widget); std::string value = gtk_entry_get_text(GTK_ENTRY(widget)); @@ -422,6 +472,24 @@ void AccessibilityEventRouterGtk::SendTextBoxNotification( SendAccessibilityNotification(type, &info); } +void AccessibilityEventRouterGtk::SendTextViewNotification( + GtkWidget* widget, NotificationType type, Profile* profile) { + std::string name = GetWidgetName(widget); + GtkTextBuffer* buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(widget)); + GtkTextIter start, end; + gtk_text_buffer_get_bounds(buffer, &start, &end); + gchar* text = gtk_text_buffer_get_text(buffer, &start, &end, false); + std::string value = text; + g_free(text); + GtkTextIter sel_start, sel_end; + gtk_text_buffer_get_selection_bounds(buffer, &sel_start, &sel_end); + int start_pos = gtk_text_iter_get_offset(&sel_start); + int end_pos = gtk_text_iter_get_offset(&sel_end); + AccessibilityTextBoxInfo info(profile, name, false); + info.SetValue(value, start_pos, end_pos); + SendAccessibilityNotification(type, &info); +} + void AccessibilityEventRouterGtk::SendTabNotification( GtkWidget* widget, NotificationType type, Profile* profile) { int index = gtk_notebook_get_current_page(GTK_NOTEBOOK(widget)); diff --git a/chrome/browser/gtk/accessibility_event_router_gtk.h b/chrome/browser/gtk/accessibility_event_router_gtk.h index 662e783..ecb9b78 100644 --- a/chrome/browser/gtk/accessibility_event_router_gtk.h +++ b/chrome/browser/gtk/accessibility_event_router_gtk.h @@ -127,7 +127,9 @@ class AccessibilityEventRouterGtk { GtkWidget* widget, NotificationType type, Profile* profile); void SendTabNotification( GtkWidget* widget, NotificationType type, Profile* profile); - void SendTextBoxNotification( + void SendEntryNotification( + GtkWidget* widget, NotificationType type, Profile* profile); + void SendTextViewNotification( GtkWidget* widget, NotificationType type, Profile* profile); void InstallEventListeners(); @@ -165,6 +167,9 @@ class AccessibilityEventRouterGtk { // to a window with a profile (like menu events). Profile* most_recent_profile_; + // The most recent focused widget. + GtkWidget* most_recent_widget_; + // Used to schedule invocations of StartListening() and to defer handling // of some events until the next time through the event loop. ScopedRunnableMethodFactory<AccessibilityEventRouterGtk> method_factory_; diff --git a/chrome/browser/gtk/accessible_widget_helper_gtk.cc b/chrome/browser/gtk/accessible_widget_helper_gtk.cc index 50bc107..ede764f 100644 --- a/chrome/browser/gtk/accessible_widget_helper_gtk.cc +++ b/chrome/browser/gtk/accessible_widget_helper_gtk.cc @@ -14,7 +14,8 @@ AccessibleWidgetHelper::AccessibleWidgetHelper( : accessibility_event_router_(AccessibilityEventRouterGtk::GetInstance()), profile_(profile), root_widget_(root_widget) { - accessibility_event_router_->AddRootWidget(root_widget_, profile); + CHECK(profile_); + accessibility_event_router_->AddRootWidget(root_widget_, profile_); } AccessibleWidgetHelper::~AccessibleWidgetHelper() { diff --git a/chrome/browser/views/accessible_view_helper.cc b/chrome/browser/views/accessible_view_helper.cc index 8a42515..f173761 100644 --- a/chrome/browser/views/accessible_view_helper.cc +++ b/chrome/browser/views/accessible_view_helper.cc @@ -8,6 +8,7 @@ #include "chrome/browser/accessibility_events.h" #include "chrome/browser/profile.h" #include "chrome/common/notification_service.h" +#include "views/widget/widget.h" using views::View; @@ -18,6 +19,11 @@ AccessibleViewHelper::AccessibleViewHelper( view_tree_(view_tree) { if (!accessibility_event_router_->AddViewTree(view_tree_, profile)) view_tree_ = NULL; + +#if defined(OS_LINUX) + GtkWidget* widget = view_tree->GetWidget()->GetNativeView(); + widget_helper_.reset(new AccessibleWidgetHelper(widget, profile)); +#endif } AccessibleViewHelper::~AccessibleViewHelper() { diff --git a/chrome/browser/views/accessible_view_helper.h b/chrome/browser/views/accessible_view_helper.h index c5c1e15..2d01238 100644 --- a/chrome/browser/views/accessible_view_helper.h +++ b/chrome/browser/views/accessible_view_helper.h @@ -9,10 +9,15 @@ #include <vector> #include "base/basictypes.h" +#include "base/scoped_ptr.h" #include "base/singleton.h" #include "chrome/browser/accessibility_events.h" #include "chrome/browser/views/accessibility_event_router_views.h" +#if defined(OS_LINUX) +#include "chrome/browser/gtk/accessible_widget_helper_gtk.h" +#endif + class Profile; // NOTE: This class is part of the Accessibility Extension API, which lets @@ -63,6 +68,10 @@ class AccessibleViewHelper { std::string window_title_; std::vector<views::View*> managed_views_; +#if defined(OS_LINUX) + scoped_ptr<AccessibleWidgetHelper> widget_helper_; +#endif + DISALLOW_COPY_AND_ASSIGN(AccessibleViewHelper); }; diff --git a/chrome/browser/views/frame/browser_view.cc b/chrome/browser/views/frame/browser_view.cc index 4e7b411..2686a61 100644 --- a/chrome/browser/views/frame/browser_view.cc +++ b/chrome/browser/views/frame/browser_view.cc @@ -69,7 +69,6 @@ #include "chrome/browser/aeropeek_manager.h" #include "chrome/browser/jumplist_win.h" #elif defined(OS_LINUX) -#include "chrome/browser/gtk/accessible_widget_helper_gtk.h" #include "chrome/browser/views/accelerator_table_gtk.h" #include "views/window/hit_test.h" #endif @@ -664,16 +663,6 @@ bool BrowserView::IsPositionInWindowCaption(const gfx::Point& point) { // BrowserView, BrowserWindow implementation: void BrowserView::Show() { - accessible_view_helper_.reset(new AccessibleViewHelper( - this, browser_->profile())); - -#if defined(OS_LINUX) - if (!accessible_widget_helper_.get()) { - accessible_widget_helper_.reset(new AccessibleWidgetHelper( - GTK_WIDGET(GetWindow()->GetNativeWindow()), browser_->profile())); - } -#endif - // If the window is already visible, just activate it. if (frame_->GetWindow()->IsVisible()) { frame_->GetWindow()->Activate(); @@ -1754,6 +1743,9 @@ void BrowserView::InitTabStrip(TabStripModel* model) { // BrowserView, private: void BrowserView::Init() { + accessible_view_helper_.reset(new AccessibleViewHelper( + this, browser_->profile())); + SetLayoutManager(CreateLayoutManager()); // Stow a pointer to this object onto the window handle so that we can get // at it later when all we have is a native view. diff --git a/chrome/browser/views/frame/browser_view.h b/chrome/browser/views/frame/browser_view.h index 96a6f86..ab89256 100644 --- a/chrome/browser/views/frame/browser_view.h +++ b/chrome/browser/views/frame/browser_view.h @@ -62,8 +62,6 @@ class ZoomMenuModel; #if defined(OS_WIN) class AeroPeekManager; class JumpList; -#elif defined(OS_LINUX) -class AccessibleWidgetHelper; #endif namespace views { @@ -609,9 +607,6 @@ class BrowserView : public BrowserBubbleHost, UnhandledKeyboardEventHandler unhandled_keyboard_event_handler_; scoped_ptr<AccessibleViewHelper> accessible_view_helper_; -#if defined(OS_LINUX) - scoped_ptr<AccessibleWidgetHelper> accessible_widget_helper_; -#endif // Loads extension_app_icon_ asynchronously on the file thread. ImageLoadingTracker extension_app_icon_loader_; diff --git a/chrome/browser/views/location_bar/location_bar_view.cc b/chrome/browser/views/location_bar/location_bar_view.cc index a1c84fb..781d082 100644 --- a/chrome/browser/views/location_bar/location_bar_view.cc +++ b/chrome/browser/views/location_bar/location_bar_view.cc @@ -154,6 +154,13 @@ void LocationBarView::Init() { // Hide the widget. NativeViewHostGtk will make it visible again as // necessary. gtk_widget_hide(location_entry_->GetNativeView()); + + // Associate an accessible name with the location entry. + accessible_widget_helper_.reset(new AccessibleWidgetHelper( + location_entry_->text_view(), profile_)); + accessible_widget_helper_->SetWidgetName( + location_entry_->text_view(), + l10n_util::GetStringUTF8(IDS_ACCNAME_LOCATION)); #endif location_entry_view_ = new views::NativeViewHost; location_entry_view_->SetID(VIEW_ID_AUTOCOMPLETE); diff --git a/chrome/browser/views/location_bar/location_bar_view.h b/chrome/browser/views/location_bar/location_bar_view.h index 538f1ba..84270dd 100644 --- a/chrome/browser/views/location_bar/location_bar_view.h +++ b/chrome/browser/views/location_bar/location_bar_view.h @@ -26,6 +26,7 @@ #include "chrome/browser/autocomplete/autocomplete_edit_view_win.h" #else #include "chrome/browser/autocomplete/autocomplete_edit_view_gtk.h" +#include "chrome/browser/gtk/accessible_widget_helper_gtk.h" #endif class Browser; @@ -356,6 +357,10 @@ class LocationBarView : public LocationBar, // focused. Used when the toolbar is in full keyboard accessibility mode. bool show_focus_rect_; +#if defined(OS_LINUX) + scoped_ptr<AccessibleWidgetHelper> accessible_widget_helper_; +#endif + // Used to schedule a task for the first run info bubble. ScopedRunnableMethodFactory<LocationBarView> first_run_bubble_; |