diff options
author | dmazzoni@chromium.org <dmazzoni@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-03-05 21:46:47 +0000 |
---|---|---|
committer | dmazzoni@chromium.org <dmazzoni@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-03-05 21:46:47 +0000 |
commit | cabbf6ea708c05b099fe77ca6e7533abfb6a035c (patch) | |
tree | 46d859022039379bf97cecb0571a5c3bc1d86c63 | |
parent | 8f9eb9f902cde0195f2473eedaafacaa3241d9dd (diff) | |
download | chromium_src-cabbf6ea708c05b099fe77ca6e7533abfb6a035c.zip chromium_src-cabbf6ea708c05b099fe77ca6e7533abfb6a035c.tar.gz chromium_src-cabbf6ea708c05b099fe77ca6e7533abfb6a035c.tar.bz2 |
Send accessibility events from GTK implementations of views.
BUG=none
TEST=manual testing on Chrome OS
Review URL: http://codereview.chromium.org/6538090
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@77054 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/browser/autocomplete/autocomplete_edit_view_gtk.cc | 13 | ||||
-rw-r--r-- | chrome/browser/autocomplete/autocomplete_edit_view_gtk.h | 8 | ||||
-rw-r--r-- | views/controls/button/native_button_gtk.cc | 2 | ||||
-rw-r--r-- | views/controls/button/text_button.h | 2 | ||||
-rw-r--r-- | views/controls/combobox/combobox.cc | 1 | ||||
-rw-r--r-- | views/controls/combobox/native_combobox_gtk.cc | 70 | ||||
-rw-r--r-- | views/controls/combobox/native_combobox_gtk.h | 7 | ||||
-rw-r--r-- | views/controls/menu/native_menu_gtk.cc | 57 | ||||
-rw-r--r-- | views/controls/menu/native_menu_gtk.h | 5 | ||||
-rw-r--r-- | views/controls/native/native_view_host.cc | 1 | ||||
-rw-r--r-- | views/controls/textfield/native_textfield_gtk.cc | 39 | ||||
-rw-r--r-- | views/controls/textfield/native_textfield_gtk.h | 12 | ||||
-rw-r--r-- | views/controls/textfield/textfield.cc | 16 | ||||
-rw-r--r-- | views/controls/textfield/textfield.h | 4 |
14 files changed, 222 insertions, 15 deletions
diff --git a/chrome/browser/autocomplete/autocomplete_edit_view_gtk.cc b/chrome/browser/autocomplete/autocomplete_edit_view_gtk.cc index ef7d49d..e304418 100644 --- a/chrome/browser/autocomplete/autocomplete_edit_view_gtk.cc +++ b/chrome/browser/autocomplete/autocomplete_edit_view_gtk.cc @@ -157,7 +157,7 @@ AutocompleteEditViewGtk::AutocompleteEditViewGtk( CommandUpdater* command_updater, bool popup_window_mode, #if defined(TOOLKIT_VIEWS) - const views::View* location_bar) + views::View* location_bar) #else GtkWidget* location_bar) #endif @@ -183,7 +183,9 @@ AutocompleteEditViewGtk::AutocompleteEditViewGtk( text_selected_during_click_(false), text_view_focused_before_button_press_(false), #endif -#if !defined(TOOLKIT_VIEWS) +#if defined(TOOLKIT_VIEWS) + location_bar_view_(location_bar), +#else theme_provider_(GtkThemeProvider::GetFrom(profile)), #endif enter_was_pressed_(false), @@ -882,7 +884,7 @@ AutocompleteEditView* AutocompleteEditViewGtk::Create( Profile* profile, CommandUpdater* command_updater, bool popup_window_mode, - const views::View* location_bar) { + views::View* location_bar) { if (views::NativeTextfieldViews::IsTextfieldViewsEnabled()) { AutocompleteEditViewViews* autocomplete = new AutocompleteEditViewViews(controller, @@ -1222,6 +1224,11 @@ gboolean AutocompleteEditViewGtk::HandleKeyPress(GtkWidget* widget, g_signal_stop_emission(widget, signal_id, 0); } +#if defined(TOOLKIT_VIEWS) + location_bar_view_->NotifyAccessibilityEvent( + AccessibilityTypes::EVENT_TEXT_CHANGED); +#endif + return result; } diff --git a/chrome/browser/autocomplete/autocomplete_edit_view_gtk.h b/chrome/browser/autocomplete/autocomplete_edit_view_gtk.h index d101fe9..23738e2 100644 --- a/chrome/browser/autocomplete/autocomplete_edit_view_gtk.h +++ b/chrome/browser/autocomplete/autocomplete_edit_view_gtk.h @@ -74,7 +74,7 @@ class AutocompleteEditViewGtk : public AutocompleteEditView, CommandUpdater* command_updater, bool popup_window_mode, #if defined(TOOLKIT_VIEWS) - const views::View* location_bar + views::View* location_bar #else GtkWidget* location_bar #endif @@ -157,7 +157,7 @@ class AutocompleteEditViewGtk : public AutocompleteEditView, Profile* profile, CommandUpdater* command_updater, bool popup_window_mode, - const views::View* location_bar); + views::View* location_bar); #endif // Overridden from NotificationObserver: @@ -460,7 +460,9 @@ class AutocompleteEditViewGtk : public AutocompleteEditView, bool text_view_focused_before_button_press_; #endif -#if !defined(TOOLKIT_VIEWS) +#if defined(TOOLKIT_VIEWS) + views::View* location_bar_view_; +#else // Supplies colors, et cetera. GtkThemeProvider* theme_provider_; diff --git a/views/controls/button/native_button_gtk.cc b/views/controls/button/native_button_gtk.cc index 9ae7d96..a217249 100644 --- a/views/controls/button/native_button_gtk.cc +++ b/views/controls/button/native_button_gtk.cc @@ -158,6 +158,8 @@ void NativeCheckboxGtk::OnClicked() { if (deliver_click_event_) { SyncCheckState(); NativeButtonGtk::OnClicked(); + checkbox()->NotifyAccessibilityEvent( + AccessibilityTypes::EVENT_VALUE_CHANGED); } } diff --git a/views/controls/button/text_button.h b/views/controls/button/text_button.h index fa4d4be..f8ab377 100644 --- a/views/controls/button/text_button.h +++ b/views/controls/button/text_button.h @@ -185,7 +185,6 @@ class TextButton : public CustomButton { // states change. virtual void UpdateColor(); - private: // Updates text_size_ and max_text_size_ from the current text/font. This is // invoked when the font or text changes. void UpdateTextSize(); @@ -193,6 +192,7 @@ class TextButton : public CustomButton { // The text string that is displayed in the button. string16 text_; + private: // The size of the text string. gfx::Size text_size_; diff --git a/views/controls/combobox/combobox.cc b/views/controls/combobox/combobox.cc index be7d719..552c69b 100644 --- a/views/controls/combobox/combobox.cc +++ b/views/controls/combobox/combobox.cc @@ -50,6 +50,7 @@ void Combobox::SelectionChanged() { selected_item_ = native_wrapper_->GetSelectedItem(); if (listener_) listener_->ItemChanged(this, prev_selected_item, selected_item_); + NotifyAccessibilityEvent(AccessibilityTypes::EVENT_VALUE_CHANGED, false); } //////////////////////////////////////////////////////////////////////////////// diff --git a/views/controls/combobox/native_combobox_gtk.cc b/views/controls/combobox/native_combobox_gtk.cc index cfa2dc9..00552d8 100644 --- a/views/controls/combobox/native_combobox_gtk.cc +++ b/views/controls/combobox/native_combobox_gtk.cc @@ -8,9 +8,11 @@ #include <algorithm> +#include "base/message_loop.h" #include "base/utf_string_conversions.h" #include "ui/base/models/combobox_model.h" #include "views/controls/combobox/combobox.h" +#include "views/views_delegate.h" using ui::ComboboxModel; // TODO(beng): remove @@ -20,7 +22,8 @@ namespace views { // NativeComboboxGtk, public: NativeComboboxGtk::NativeComboboxGtk(Combobox* combobox) - : combobox_(combobox) { + : combobox_(combobox), + menu_(NULL) { set_focus_view(combobox); } @@ -115,6 +118,16 @@ void NativeComboboxGtk::CreateNativeControl() { GTK_CELL_LAYOUT(widget), cell, "text", 0, NULL); g_signal_connect(widget, "changed", G_CALLBACK(CallChangedThunk), this); + g_signal_connect_after(widget, "popup", + G_CALLBACK(CallPopUpThunk), this); + + // Get the menu associated with the combo box and listen to events on it. + GList* menu_list = gtk_menu_get_for_attach_widget(widget); + if (menu_list) { + menu_ = reinterpret_cast<GtkMenu*>(menu_list->data); + g_signal_connect_after(menu_, "move-current", + G_CALLBACK(CallMenuMoveCurrentThunk), this); + } NativeControlCreated(widget); } @@ -133,10 +146,65 @@ void NativeComboboxGtk::SelectionChanged() { combobox_->SelectionChanged(); } +void NativeComboboxGtk::FocusedMenuItemChanged() { + DCHECK(menu_); + GtkWidget* menu_item = GTK_MENU_SHELL(menu_)->active_menu_item; + if (!menu_item) + return; + + // Figure out the item index and total number of items. + GList* items = gtk_container_get_children(GTK_CONTAINER(menu_)); + guint count = g_list_length(items); + int index = g_list_index(items, static_cast<gconstpointer>(menu_item)); + + // Get the menu item's label. + std::string name; + GList* children = gtk_container_get_children(GTK_CONTAINER(menu_item)); + for (GList* l = g_list_first(children); l != NULL; l = g_list_next(l)) { + GtkWidget* child = static_cast<GtkWidget*>(l->data); + if (GTK_IS_CELL_VIEW(child)) { + GtkCellView* cell_view = GTK_CELL_VIEW(child); + GtkTreePath* path = gtk_cell_view_get_displayed_row(cell_view); + GtkTreeModel* model = NULL; +#if GTK_CHECK_VERSION(2, 16, 0) + model = gtk_cell_view_get_model(cell_view); +#else + g_object_get(cell_view, "model", &model, NULL); +#endif + GtkTreeIter iter; + if (model && gtk_tree_model_get_iter(model, &iter, path)) { + GValue value = { 0 }; + gtk_tree_model_get_value(model, &iter, 0, &value); + name = g_value_get_string(&value); + break; + } + } + } + + if (ViewsDelegate::views_delegate) { + ViewsDelegate::views_delegate->NotifyMenuItemFocused( + L"", + UTF8ToWide(name), + index, + count, + false); + } +} + void NativeComboboxGtk::CallChanged(GtkWidget* widget) { SelectionChanged(); } +gboolean NativeComboboxGtk::CallPopUp(GtkWidget* widget) { + FocusedMenuItemChanged(); + return false; +} + +void NativeComboboxGtk::CallMenuMoveCurrent( + GtkWidget* menu, GtkMenuDirectionType focus_direction) { + FocusedMenuItemChanged(); +} + //////////////////////////////////////////////////////////////////////////////// // NativeComboboxWrapper, public: diff --git a/views/controls/combobox/native_combobox_gtk.h b/views/controls/combobox/native_combobox_gtk.h index 7d5f30a..9a0e8de 100644 --- a/views/controls/combobox/native_combobox_gtk.h +++ b/views/controls/combobox/native_combobox_gtk.h @@ -36,12 +36,19 @@ class NativeComboboxGtk : public NativeControlGtk, private: void SelectionChanged(); + void FocusedMenuItemChanged(); CHROMEGTK_CALLBACK_0(NativeComboboxGtk, void, CallChanged); + CHROMEGTK_CALLBACK_0(NativeComboboxGtk, gboolean, CallPopUp); + CHROMEGTK_CALLBACK_1(NativeComboboxGtk, void, CallMenuMoveCurrent, + GtkMenuDirectionType); // The combobox we are bound to. Combobox* combobox_; + // The combo box's pop-up menu. + GtkMenu* menu_; + // The preferred size from the last size_request. See // NativeButtonGtk::preferred_size_ for more detail why we need this. gfx::Size preferred_size_; diff --git a/views/controls/menu/native_menu_gtk.cc b/views/controls/menu/native_menu_gtk.cc index 2dd5fd4..bb5a531 100644 --- a/views/controls/menu/native_menu_gtk.cc +++ b/views/controls/menu/native_menu_gtk.cc @@ -21,6 +21,7 @@ #include "views/accelerator.h" #include "views/controls/menu/menu_2.h" #include "views/controls/menu/nested_dispatcher_gtk.h" +#include "views/views_delegate.h" namespace { @@ -118,6 +119,9 @@ void NativeMenuGtk::RunMenuAt(const gfx::Point& point, int alignment) { gint move_handle_id = g_signal_connect(menu_, "move-current", G_CALLBACK(OnMenuMoveCurrentThunk), this); + gint after_move_handle_id = + g_signal_connect_after(menu_, "move-current", + G_CALLBACK(AfterMenuMoveCurrentThunk), this); // Block until menu is no longer shown by running a nested message loop. nested_dispatcher_ = new NestedDispatcherGtk(this, true); @@ -137,6 +141,7 @@ void NativeMenuGtk::RunMenuAt(const gfx::Point& point, int alignment) { g_signal_handler_disconnect(G_OBJECT(menu_), hide_handle_id); g_signal_handler_disconnect(G_OBJECT(menu_), move_handle_id); + g_signal_handler_disconnect(G_OBJECT(menu_), after_move_handle_id); if (activated_menu_) { MessageLoop::current()->PostTask(FROM_HERE, @@ -310,6 +315,11 @@ void NativeMenuGtk::OnMenuMoveCurrent(GtkWidget* menu_widget, } } +void NativeMenuGtk::AfterMenuMoveCurrent(GtkWidget* menu_widget, + GtkMenuDirectionType focus_direction) { + SendAccessibilityEvent(); +} + void NativeMenuGtk::AddSeparatorAt(int index) { GtkWidget* separator = gtk_separator_menu_item_new(); gtk_widget_show(separator); @@ -380,6 +390,8 @@ GtkWidget* NativeMenuGtk::AddMenuItemAt(int index, g_object_set_data(G_OBJECT(menu_item), "submenu", submenu); gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item), submenu->GetNativeMenu()); + g_signal_connect(submenu->GetNativeMenu(), "move-current", + G_CALLBACK(OnMenuMoveCurrentThunk), this); } views::Accelerator accelerator(ui::VKEY_UNKNOWN, false, false, false); @@ -537,6 +549,51 @@ void NativeMenuGtk::Activate() { } } +void NativeMenuGtk::SendAccessibilityEvent() { + // Find the focused menu item, recursing into submenus as needed. + GtkWidget* menu = menu_; + GtkWidget* menu_item = GTK_MENU_SHELL(menu_)->active_menu_item; + if (!menu_item) + return; + GtkWidget* submenu = gtk_menu_item_get_submenu(GTK_MENU_ITEM(menu_item)); + while (submenu && GTK_MENU_SHELL(submenu)->active_menu_item) { + menu = submenu; + menu_item = GTK_MENU_SHELL(menu)->active_menu_item; + if (!menu_item) + return; + submenu = gtk_menu_item_get_submenu(GTK_MENU_ITEM(menu_item)); + } + + // Figure out the item index and total number of items. + GList* items = gtk_container_get_children(GTK_CONTAINER(menu)); + guint count = g_list_length(items); + int index = g_list_index(items, static_cast<gconstpointer>(menu_item)); + + // Get the menu item's label. + std::string name; +#if GTK_CHECK_VERSION(2, 16, 0) + name = gtk_menu_item_get_label(GTK_MENU_ITEM(menu_item)); +#else + GList* children = gtk_container_get_children(GTK_CONTAINER(menu_item)); + for (GList* l = g_list_first(children); l != NULL; l = g_list_next(l)) { + GtkWidget* child = static_cast<GtkWidget*>(l->data); + if (GTK_IS_LABEL(child)) { + name = gtk_label_get_label(GTK_LABEL(child)); + break; + } + } +#endif + + if (ViewsDelegate::views_delegate) { + ViewsDelegate::views_delegate->NotifyMenuItemFocused( + L"", + UTF8ToWide(name), + index, + count, + submenu != NULL); + } +} + // static void NativeMenuGtk::MenuDestroyed(GtkWidget* widget, Menu2* menu2) { NativeMenuGtk* native_menu = diff --git a/views/controls/menu/native_menu_gtk.h b/views/controls/menu/native_menu_gtk.h index ea9791d..4c1d21b 100644 --- a/views/controls/menu/native_menu_gtk.h +++ b/views/controls/menu/native_menu_gtk.h @@ -11,7 +11,6 @@ #include <vector> #include "base/message_loop.h" -#include "base/task.h" #include "ui/base/gtk/gtk_signal.h" #include "views/controls/menu/menu_wrapper.h" @@ -56,6 +55,8 @@ class NativeMenuGtk : public MenuWrapper, CHROMEGTK_CALLBACK_0(NativeMenuGtk, void, OnMenuHidden); CHROMEGTK_CALLBACK_1(NativeMenuGtk, void, OnMenuMoveCurrent, GtkMenuDirectionType); + CHROMEGTK_CALLBACK_1(NativeMenuGtk, void, AfterMenuMoveCurrent, + GtkMenuDirectionType); void AddSeparatorAt(int index); GtkWidget* AddMenuItemAt(int index, GtkRadioMenuItem* radio_group, @@ -91,6 +92,8 @@ class NativeMenuGtk : public MenuWrapper, // Notifies the model the user selected an item. void Activate(); + void SendAccessibilityEvent(); + // A callback to delete menu2 object when the native widget is // destroyed first. static void MenuDestroyed(GtkWidget* widget, Menu2* menu2); diff --git a/views/controls/native/native_view_host.cc b/views/controls/native/native_view_host.cc index 162b1f6..73ecb64 100644 --- a/views/controls/native/native_view_host.cc +++ b/views/controls/native/native_view_host.cc @@ -180,6 +180,7 @@ std::string NativeViewHost::GetClassName() const { void NativeViewHost::OnFocus() { native_wrapper_->SetFocus(); + NotifyAccessibilityEvent(AccessibilityTypes::EVENT_FOCUS); } bool NativeViewHost::ContainsNativeView(gfx::NativeView native_view) const { diff --git a/views/controls/textfield/native_textfield_gtk.cc b/views/controls/textfield/native_textfield_gtk.cc index f3b1ff5..4e0b4cc 100644 --- a/views/controls/textfield/native_textfield_gtk.cc +++ b/views/controls/textfield/native_textfield_gtk.cc @@ -344,7 +344,11 @@ bool NativeTextfieldGtk::IsIMEComposing() const { } void NativeTextfieldGtk::GetSelectedRange(TextRange* range) const { - NOTREACHED(); + gint start_pos; + gint end_pos; + gtk_editable_get_selection_bounds( + GTK_EDITABLE(native_view()), &start_pos, &end_pos); + range->SetRange(start_pos, end_pos); } void NativeTextfieldGtk::SelectRange(const TextRange& range) { @@ -427,6 +431,35 @@ gboolean NativeTextfieldGtk::OnChanged() { Textfield::Controller* controller = textfield_->GetController(); if (controller) controller->ContentsChanged(textfield_, GetText()); + textfield_->NotifyAccessibilityEvent(AccessibilityTypes::EVENT_TEXT_CHANGED); + return false; +} + +// static +gboolean NativeTextfieldGtk::OnMoveCursorHandler( + GtkWidget* widget, + GtkMovementStep step, + gint count, + gboolean extend_selection, + NativeTextfieldGtk* textfield) { + return textfield->OnMoveCursor(); +} + +gboolean NativeTextfieldGtk::OnMoveCursor() { + textfield_->NotifyAccessibilityEvent(AccessibilityTypes::EVENT_TEXT_CHANGED); + return false; +} + +// static +gboolean NativeTextfieldGtk::OnMouseUpHandler( + GtkWidget* widget, + GdkEvent* event, + NativeTextfieldGtk* textfield) { + return textfield->OnMouseUp(); +} + +gboolean NativeTextfieldGtk::OnMouseUp() { + textfield_->NotifyAccessibilityEvent(AccessibilityTypes::EVENT_TEXT_CHANGED); return false; } @@ -462,6 +495,10 @@ void NativeTextfieldGtk::NativeControlCreated(GtkWidget* widget) { g_signal_connect(widget, "changed", G_CALLBACK(OnChangedHandler), this); } + g_signal_connect_after(widget, "move-cursor", + G_CALLBACK(OnMoveCursorHandler), this); + g_signal_connect_after(widget, "button-release-event", + G_CALLBACK(OnMouseUpHandler), this); g_signal_connect_after(widget, "key-press-event", G_CALLBACK(OnKeyPressEventHandler), this); // In order to properly trigger Accelerators bound to VKEY_RETURN, we need to diff --git a/views/controls/textfield/native_textfield_gtk.h b/views/controls/textfield/native_textfield_gtk.h index bfbc839..6f211ad 100644 --- a/views/controls/textfield/native_textfield_gtk.h +++ b/views/controls/textfield/native_textfield_gtk.h @@ -80,6 +80,18 @@ class NativeTextfieldGtk : public NativeControlGtk, GtkWidget* entry, NativeTextfieldGtk* textfield); gboolean OnChanged(); + static gboolean OnMoveCursorHandler( + GtkWidget* entry, + GtkMovementStep step, + gint count, + gboolean extend_selection, + NativeTextfieldGtk* textfield); + gboolean OnMoveCursor(); + static gboolean OnMouseUpHandler( + GtkWidget* entry, + GdkEvent* event, + NativeTextfieldGtk* textfield); + gboolean OnMouseUp(); DISALLOW_COPY_AND_ASSIGN(NativeTextfieldGtk); }; diff --git a/views/controls/textfield/textfield.cc b/views/controls/textfield/textfield.cc index 2a72712..8c1003b 100644 --- a/views/controls/textfield/textfield.cc +++ b/views/controls/textfield/textfield.cc @@ -265,19 +265,17 @@ bool Textfield::IsIMEComposing() const { void Textfield::GetSelectedRange(TextRange* range) const { DCHECK(native_wrapper_); - if (native_wrapper_) - native_wrapper_->GetSelectedRange(range); + native_wrapper_->GetSelectedRange(range); } void Textfield::SelectRange(const TextRange& range) { DCHECK(native_wrapper_); - if (native_wrapper_) - native_wrapper_->SelectRange(range); + native_wrapper_->SelectRange(range); } size_t Textfield::GetCursorPosition() const { DCHECK(native_wrapper_); - return native_wrapper_ ? native_wrapper_->GetCursorPosition() : 0; + return native_wrapper_->GetCursorPosition(); } //////////////////////////////////////////////////////////////////////////////// @@ -373,6 +371,14 @@ AccessibilityTypes::State Textfield::GetAccessibleState() { return state; } +void Textfield::GetSelectionBounds(int* start_index, int* end_index) { + DCHECK(native_wrapper_); + TextRange range; + native_wrapper_->GetSelectedRange(&range); + *start_index = range.start(); + *end_index = range.end(); +} + string16 Textfield::GetAccessibleValue() { if (!text_.empty()) return text_; diff --git a/views/controls/textfield/textfield.h b/views/controls/textfield/textfield.h index c8484d5..a4f2aec 100644 --- a/views/controls/textfield/textfield.h +++ b/views/controls/textfield/textfield.h @@ -273,6 +273,10 @@ class Textfield : public View { virtual AccessibilityTypes::State GetAccessibleState() OVERRIDE; virtual string16 GetAccessibleValue() OVERRIDE; + // TODO(dmazzoni): Remove this when refactoring views accessibility code. + // http://crbug.com/74988 + void GetSelectionBounds(int* start_index, int* end_index); + protected: virtual void ViewHierarchyChanged(bool is_add, View* parent, View* child) OVERRIDE; |