diff options
author | dmazzoni@chromium.org <dmazzoni@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-02-23 17:04:35 +0000 |
---|---|---|
committer | dmazzoni@chromium.org <dmazzoni@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-02-23 17:04:35 +0000 |
commit | 2b8002791e925dcdab88ebe1b74eb416f3b2d585 (patch) | |
tree | 3a7cdaad36988199d0499e12d7b561b31806ed87 /chrome/browser | |
parent | bf767417d66c4d54761dd619cfb93838bdc2353a (diff) | |
download | chromium_src-2b8002791e925dcdab88ebe1b74eb416f3b2d585.zip chromium_src-2b8002791e925dcdab88ebe1b74eb416f3b2d585.tar.gz chromium_src-2b8002791e925dcdab88ebe1b74eb416f3b2d585.tar.bz2 |
Add support for more types of controls and events to GTK implementation of
accessibility extension API. Enable accessibility API for all subdialogs
of the main Options dialog.
BUG=none
TEST=none
Review URL: http://codereview.chromium.org/651037
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@39738 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
26 files changed, 518 insertions, 111 deletions
diff --git a/chrome/browser/accessibility_events.cc b/chrome/browser/accessibility_events.cc index fa1820a..b300183 100644 --- a/chrome/browser/accessibility_events.cc +++ b/chrome/browser/accessibility_events.cc @@ -79,3 +79,11 @@ void AccessibilityTextBoxInfo::SerializeToDict(DictionaryValue *dict) const { dict->SetInteger(keys::kSelectionStartKey, selection_start_); dict->SetInteger(keys::kSelectionEndKey, selection_end_); } + +void AccessibilityListBoxInfo::SerializeToDict(DictionaryValue *dict) const { + AccessibilityControlInfo::SerializeToDict(dict); + dict->SetString(keys::kTypeKey, keys::kTypeListBox); + dict->SetString(keys::kValueKey, value_); + dict->SetInteger(keys::kItemIndexKey, item_index_); + dict->SetInteger(keys::kItemCountKey, item_count_); +} diff --git a/chrome/browser/accessibility_events.h b/chrome/browser/accessibility_events.h index 2ef7535..da9189c 100644 --- a/chrome/browser/accessibility_events.h +++ b/chrome/browser/accessibility_events.h @@ -88,7 +88,8 @@ class AccessibilityRadioButtonInfo : public AccessibilityControlInfo { : AccessibilityControlInfo(profile, name), checked_(checked), item_index_(item_index), - item_count_(item_count) { } + item_count_(item_count) { + } virtual void SerializeToDict(DictionaryValue *dict) const; @@ -109,7 +110,8 @@ class AccessibilityCheckboxInfo : public AccessibilityControlInfo { std::string name, bool checked) : AccessibilityControlInfo(profile, name), - checked_(checked) { } + checked_(checked) { + } virtual void SerializeToDict(DictionaryValue *dict) const; @@ -129,7 +131,8 @@ class AccessibilityTabInfo : public AccessibilityControlInfo { int tab_count) : AccessibilityControlInfo(profile, tab_name), tab_index_(tab_index), - tab_count_(tab_count) { } + tab_count_(tab_count) { + } virtual void SerializeToDict(DictionaryValue *dict) const; @@ -156,7 +159,8 @@ class AccessibilityComboBoxInfo : public AccessibilityControlInfo { : AccessibilityControlInfo(profile, name), value_(value), item_index_(item_index), - item_count_(item_count) { } + item_count_(item_count) { + } virtual void SerializeToDict(DictionaryValue *dict) const; @@ -168,7 +172,7 @@ class AccessibilityComboBoxInfo : public AccessibilityControlInfo { private: std::string value_; // The 0-based index of the current item and the number of total items. - // If the value is not one of the drop-down options, item_index_ should + // If the value is not one of the drop-down options, |item_index_| should // be -1. int item_index_; int item_count_; @@ -185,7 +189,8 @@ class AccessibilityTextBoxInfo : public AccessibilityControlInfo { value_(""), password_(password), selection_start_(0), - selection_end_(0) { } + selection_end_(0) { + } virtual void SerializeToDict(DictionaryValue *dict) const; @@ -202,4 +207,35 @@ class AccessibilityTextBoxInfo : public AccessibilityControlInfo { int selection_end_; }; +// Accessibility information about a combo box passed to onControlFocused +// and onControlAction event listeners. +class AccessibilityListBoxInfo : public AccessibilityControlInfo { + public: + AccessibilityListBoxInfo(Profile* profile, + std::string name, + std::string value, + int item_index, + int item_count) + : AccessibilityControlInfo(profile, name), + value_(value), + item_index_(item_index), + item_count_(item_count) { + } + + virtual void SerializeToDict(DictionaryValue *dict) const; + + void SetValue(int item_index, std::string value) { + item_index_ = item_index; + value_ = value; + } + + private: + std::string value_; + // The 0-based index of the current item and the number of total items. + // If the value is not one of the drop-down options, |item_index_| should + // be -1. + int item_index_; + int item_count_; +}; + #endif // CHROME_BROWSER_ACCESSIBILITY_EVENTS_H_ diff --git a/chrome/browser/extensions/extension_accessibility_api.cc b/chrome/browser/extensions/extension_accessibility_api.cc index 24428af..2ea3775 100644 --- a/chrome/browser/extensions/extension_accessibility_api.cc +++ b/chrome/browser/extensions/extension_accessibility_api.cc @@ -5,6 +5,7 @@ #include "chrome/browser/extensions/extension_tabs_module.h" #include "base/json/json_writer.h" +#include "base/stl_util-inl.h" #include "base/string_util.h" #include "base/values.h" #include "chrome/browser/browser.h" @@ -38,6 +39,11 @@ ExtensionAccessibilityEventRouter* return Singleton<ExtensionAccessibilityEventRouter>::get(); } +ExtensionAccessibilityEventRouter::~ExtensionAccessibilityEventRouter() { + STLDeleteElements(&on_enabled_listeners_); + STLDeleteElements(&on_disabled_listeners_); +} + void ExtensionAccessibilityEventRouter::ObserveProfile(Profile* profile) { last_focused_control_dict_.Clear(); diff --git a/chrome/browser/extensions/extension_accessibility_api.h b/chrome/browser/extensions/extension_accessibility_api.h index fb3cb8d..9325dfb 100644 --- a/chrome/browser/extensions/extension_accessibility_api.h +++ b/chrome/browser/extensions/extension_accessibility_api.h @@ -47,7 +47,7 @@ class ExtensionAccessibilityEventRouter : public NotificationObserver { ExtensionAccessibilityEventRouter() : enabled_(false) {} - virtual ~ExtensionAccessibilityEventRouter() {} + virtual ~ExtensionAccessibilityEventRouter(); // NotificationObserver::Observe. virtual void Observe(NotificationType type, diff --git a/chrome/browser/extensions/extension_accessibility_api_constants.cc b/chrome/browser/extensions/extension_accessibility_api_constants.cc index 72d6138..8f52e14 100644 --- a/chrome/browser/extensions/extension_accessibility_api_constants.cc +++ b/chrome/browser/extensions/extension_accessibility_api_constants.cc @@ -30,6 +30,7 @@ extern const char kTypeButton[] = "button"; extern const char kTypeCheckbox[] = "checkbox"; extern const char kTypeComboBox[] = "combobox"; extern const char kTypeLink[] = "link"; +extern const char kTypeListBox[] = "listbox"; extern const char kTypeRadioButton[] = "radiobutton"; extern const char kTypeTab[] = "tab"; extern const char kTypeTextBox[] = "textbox"; diff --git a/chrome/browser/extensions/extension_accessibility_api_constants.h b/chrome/browser/extensions/extension_accessibility_api_constants.h index 2020ec8..37a7210 100644 --- a/chrome/browser/extensions/extension_accessibility_api_constants.h +++ b/chrome/browser/extensions/extension_accessibility_api_constants.h @@ -33,6 +33,7 @@ extern const char kTypeButton[]; extern const char kTypeCheckbox[]; extern const char kTypeComboBox[]; extern const char kTypeLink[]; +extern const char kTypeListBox[]; extern const char kTypeRadioButton[]; extern const char kTypeTab[]; extern const char kTypeTextBox[]; diff --git a/chrome/browser/gtk/accessibility_event_router_gtk.cc b/chrome/browser/gtk/accessibility_event_router_gtk.cc index f912fa7..833a47d 100644 --- a/chrome/browser/gtk/accessibility_event_router_gtk.cc +++ b/chrome/browser/gtk/accessibility_event_router_gtk.cc @@ -6,6 +6,7 @@ #include "base/basictypes.h" #include "base/callback.h" +#include "base/message_loop.h" #include "base/stl_util-inl.h" #include "chrome/browser/extensions/extension_accessibility_api.h" #include "chrome/browser/gtk/gtk_chrome_link_button.h" @@ -23,8 +24,8 @@ gboolean OnWidgetFocused(GSignalInvocationHint *ihint, const GValue* param_values, gpointer user_data) { GtkWidget* widget = GTK_WIDGET(g_value_get_object(param_values)); - reinterpret_cast<AccessibilityEventRouter *>(user_data) - ->DispatchAccessibilityNotification( + reinterpret_cast<AccessibilityEventRouter *>(user_data)-> + DispatchAccessibilityNotification( widget, NotificationType::ACCESSIBILITY_CONTROL_FOCUSED); return true; } @@ -37,8 +38,8 @@ gboolean OnButtonClicked(GSignalInvocationHint *ihint, // Skip toggle buttons because we're also listening on "toggle" events. if (GTK_IS_TOGGLE_BUTTON(widget)) return true; - reinterpret_cast<AccessibilityEventRouter *>(user_data) - ->DispatchAccessibilityNotification( + reinterpret_cast<AccessibilityEventRouter *>(user_data)-> + DispatchAccessibilityNotification( widget, NotificationType::ACCESSIBILITY_CONTROL_ACTION); return true; } @@ -54,26 +55,72 @@ gboolean OnButtonToggled(GSignalInvocationHint *ihint, // a different radio button the group. if (GTK_IS_RADIO_BUTTON(widget) && !checked) return true; - reinterpret_cast<AccessibilityEventRouter *>(user_data) - ->DispatchAccessibilityNotification( + reinterpret_cast<AccessibilityEventRouter *>(user_data)-> + DispatchAccessibilityNotification( widget, NotificationType::ACCESSIBILITY_CONTROL_ACTION); return true; } -gboolean OnSwitchPage(GSignalInvocationHint *ihint, - guint n_param_values, - const GValue* param_values, - gpointer user_data) { +gboolean OnPageSwitched(GSignalInvocationHint *ihint, + guint n_param_values, + const GValue* param_values, + gpointer user_data) { GtkWidget* widget = GTK_WIDGET(g_value_get_object(param_values)); - reinterpret_cast<AccessibilityEventRouter *>(user_data) - ->DispatchAccessibilityNotification( + // The page hasn't switched yet, so defer calling + // DispatchAccessibilityNotification. + reinterpret_cast<AccessibilityEventRouter *>(user_data)-> + PostDispatchAccessibilityNotification( widget, NotificationType::ACCESSIBILITY_CONTROL_ACTION); return true; } +gboolean OnComboBoxChanged(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_COMBO_BOX(widget)) + return true; + reinterpret_cast<AccessibilityEventRouter *>(user_data)-> + DispatchAccessibilityNotification( + widget, NotificationType::ACCESSIBILITY_CONTROL_ACTION); + return true; +} + +gboolean OnTreeViewCursorChanged(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_TREE_VIEW(widget)) { + return true; + } + reinterpret_cast<AccessibilityEventRouter *>(user_data)-> + DispatchAccessibilityNotification( + widget, NotificationType::ACCESSIBILITY_CONTROL_ACTION); + return true; +} + +gboolean OnEntryChanged(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_ENTRY(widget)) { + return true; + } + // The text hasn't changed yet, so defer calling + // DispatchAccessibilityNotification. + reinterpret_cast<AccessibilityEventRouter *>(user_data)-> + PostDispatchAccessibilityNotification( + widget, NotificationType::ACCESSIBILITY_TEXT_CHANGED); + return true; +} + } // anonymous namespace -AccessibilityEventRouter::AccessibilityEventRouter() { +AccessibilityEventRouter::AccessibilityEventRouter() + : 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 // needed, then install them now if it's currently enabled. @@ -90,41 +137,60 @@ AccessibilityEventRouter::AccessibilityEventRouter() { } } +AccessibilityEventRouter::~AccessibilityEventRouter() { + RemoveEventListeners(); +} + // static AccessibilityEventRouter* AccessibilityEventRouter::GetInstance() { return Singleton<AccessibilityEventRouter>::get(); } +void AccessibilityEventRouter::InstallEventListener( + const char* signal_name, + GType widget_type, + GSignalEmissionHook hook_func) { + guint signal_id = g_signal_lookup(signal_name, widget_type); + gulong hook_id = g_signal_add_emission_hook( + signal_id, 0, hook_func, reinterpret_cast<gpointer>(this), NULL); + installed_hooks_.push_back(InstalledHook(signal_id, hook_id)); +} + void AccessibilityEventRouter::InstallEventListeners() { - // Create and destroy a GtkNotebook to ensure this module is loaded, - // otherwise we can't lookup its signals. All of the other modules we - // need will already be loaded by the time we get here. + // Create and destroy each type of widget we need signals for, + // to ensure their modules are loaded, otherwise g_signal_lookup + // might fail. + g_object_unref(g_object_ref_sink(gtk_combo_box_new())); + g_object_unref(g_object_ref_sink(gtk_entry_new())); 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())); // Add signal emission hooks for the events we're interested in. - focus_hook_ = g_signal_add_emission_hook( - g_signal_lookup("focus-in-event", GTK_TYPE_WIDGET), - 0, OnWidgetFocused, (gpointer)this, NULL); - click_hook_ = g_signal_add_emission_hook( - g_signal_lookup("clicked", GTK_TYPE_BUTTON), - 0, OnButtonClicked, (gpointer)this, NULL); - toggle_hook_ = g_signal_add_emission_hook( - g_signal_lookup("toggled", GTK_TYPE_TOGGLE_BUTTON), - 0, OnButtonToggled, (gpointer)this, NULL); - switch_page_hook_ = g_signal_add_emission_hook( - g_signal_lookup("switch-page", GTK_TYPE_NOTEBOOK), - 0, OnSwitchPage, (gpointer)this, NULL); + InstallEventListener("clicked", GTK_TYPE_BUTTON, OnButtonClicked); + InstallEventListener("changed", GTK_TYPE_COMBO_BOX, OnComboBoxChanged); + InstallEventListener("cursor-changed", GTK_TYPE_TREE_VIEW, + OnTreeViewCursorChanged); + InstallEventListener("changed", GTK_TYPE_ENTRY, OnEntryChanged); + InstallEventListener("insert-text", GTK_TYPE_ENTRY, OnEntryChanged); + InstallEventListener("delete-text", GTK_TYPE_ENTRY, OnEntryChanged); + InstallEventListener("move-cursor", GTK_TYPE_ENTRY, OnEntryChanged); + InstallEventListener("focus-in-event", GTK_TYPE_WIDGET, OnWidgetFocused); + InstallEventListener("switch-page", GTK_TYPE_NOTEBOOK, OnPageSwitched); + InstallEventListener("toggled", GTK_TYPE_TOGGLE_BUTTON, OnButtonToggled); + + listening_ = true; } void AccessibilityEventRouter::RemoveEventListeners() { - g_signal_remove_emission_hook( - g_signal_lookup("focus-in-event", GTK_TYPE_WIDGET), focus_hook_); - g_signal_remove_emission_hook( - g_signal_lookup("clicked", GTK_TYPE_BUTTON), click_hook_); - g_signal_remove_emission_hook( - g_signal_lookup("toggled", GTK_TYPE_TOGGLE_BUTTON), toggle_hook_); - g_signal_remove_emission_hook( - g_signal_lookup("switch-page", GTK_TYPE_NOTEBOOK), switch_page_hook_); + for (size_t i = 0; i < installed_hooks_.size(); i++) { + g_signal_remove_emission_hook( + installed_hooks_[i].signal_id, + installed_hooks_[i].hook_id); + } + installed_hooks_.clear(); + + listening_ = false; } void AccessibilityEventRouter::AddRootWidget( @@ -190,16 +256,34 @@ std::string AccessibilityEventRouter::GetWidgetName(GtkWidget* widget) { } } +void AccessibilityEventRouter::StartListening() { + listening_ = true; +} + +void AccessibilityEventRouter::StopListening() { + listening_ = false; +} + void AccessibilityEventRouter::DispatchAccessibilityNotification( GtkWidget* widget, NotificationType type) { + if (!listening_) + return; Profile *profile; if (!IsWidgetAccessible(widget, &profile)) return; // The order of these checks matters, because, for example, a radio button - // is a subclass of button. We need to catch the most specific type that - // we can handle for each object. - if (GTK_IS_RADIO_BUTTON(widget)) { + // is a subclass of button, and a combo box is a composite control where + // the focus event goes to the button that's a child of the combo box. + GtkWidget* parent = gtk_widget_get_parent(widget); + if (parent && GTK_IS_BUTTON(widget) && GTK_IS_TREE_VIEW(parent)) { + // This is a list box column header. Currently not supported. + return; + } else if (GTK_IS_COMBO_BOX(widget)) { + SendComboBoxNotification(widget, type, profile); + } else if (parent && GTK_IS_COMBO_BOX(parent)) { + SendComboBoxNotification(parent, type, profile); + } else if (GTK_IS_RADIO_BUTTON(widget)) { SendRadioButtonNotification(widget, type, profile); } else if (GTK_IS_TOGGLE_BUTTON(widget)) { SendCheckboxNotification(widget, type, profile); @@ -209,7 +293,32 @@ void AccessibilityEventRouter::DispatchAccessibilityNotification( SendTextBoxNotification(widget, type, profile); } else if (GTK_IS_NOTEBOOK(widget)) { SendTabNotification(widget, type, profile); + } else if (GTK_IS_TREE_VIEW(widget)) { + SendListBoxNotification(widget, type, profile); + } else { + // If we have no idea what this control is, return and skip the + // temporary pause in event listening. + return; } + + // After this method returns, additional signal handlers will run, + // which will sometimes generate additional signals. To avoid + // generating redundant accessibility notifications for the same + // initial event, stop listening to all signals generated from now + // until this posted task runs. + StopListening(); + MessageLoop::current()->PostTask( + FROM_HERE, method_factory_.NewRunnableMethod( + &AccessibilityEventRouter::StartListening)); +} + +void AccessibilityEventRouter::PostDispatchAccessibilityNotification( + GtkWidget* widget, NotificationType type) { + MessageLoop::current()->PostTask( + FROM_HERE, method_factory_.NewRunnableMethod( + &AccessibilityEventRouter::DispatchAccessibilityNotification, + widget, + type)); } void AccessibilityEventRouter::SendRadioButtonNotification( @@ -285,3 +394,94 @@ void AccessibilityEventRouter::SendTabNotification( AccessibilityTabInfo info(profile, name, index, page_count); SendAccessibilityNotification(type, &info); } + +void AccessibilityEventRouter::SendComboBoxNotification( + GtkWidget* widget, NotificationType type, Profile* profile) { + // Get the index of the selected item. Will return -1 if no item is + // active, which matches the semantics of the extension API. + int index = gtk_combo_box_get_active(GTK_COMBO_BOX(widget)); + + // Get the number of items. + GtkTreeModel* model = gtk_combo_box_get_model(GTK_COMBO_BOX(widget)); + int count = gtk_tree_model_iter_n_children(model, NULL); + + // Get the value of the current item, if possible. Note that the + // model behind the combo box could be arbitrarily complex in theory, + // but this code just handles flat lists where the first string column + // contains the display value. + std::string value; + int string_column_index = -1; + for (int i = 0; i < gtk_tree_model_get_n_columns(model); i++) { + if (gtk_tree_model_get_column_type(model, i) == G_TYPE_STRING) { + string_column_index = i; + break; + } + } + if (string_column_index) { + GtkTreeIter iter; + if (gtk_combo_box_get_active_iter(GTK_COMBO_BOX(widget), &iter)) { + GValue gvalue = { 0 }; + gtk_tree_model_get_value(model, &iter, string_column_index, &gvalue); + const char* string_value = g_value_get_string(&gvalue); + if (string_value) { + value = string_value; + } + g_value_unset(&gvalue); + } + } else { + // Otherwise this must be a gtk_combo_box_text, in which case this + // function will return the value of the current item, instead. + value = gtk_combo_box_get_active_text(GTK_COMBO_BOX(widget)); + } + + // Get the name of this combo box. + std::string name = GetWidgetName(widget); + + // Send the notification. + AccessibilityComboBoxInfo info(profile, name, value, index, count); + SendAccessibilityNotification(type, &info); +} + +void AccessibilityEventRouter::SendListBoxNotification( + GtkWidget* widget, NotificationType type, Profile* profile) { + // Get the number of items. + GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(widget)); + int count = gtk_tree_model_iter_n_children(model, NULL); + + // Get the current selected index and its value. + int index = -1; + std::string value; + GtkTreePath* path; + gtk_tree_view_get_cursor(GTK_TREE_VIEW(widget), &path, NULL); + if (path != NULL) { + gint* indices = gtk_tree_path_get_indices(path); + if (indices) + index = indices[0]; + + GtkTreeIter iter; + if (gtk_tree_model_get_iter(model, &iter, path)) { + for (int i = 0; i < gtk_tree_model_get_n_columns(model); i++) { + if (gtk_tree_model_get_column_type(model, i) == G_TYPE_STRING) { + GValue gvalue = { 0 }; + gtk_tree_model_get_value(model, &iter, i, &gvalue); + const char* string_value = g_value_get_string(&gvalue); + if (string_value) { + if (!value.empty()) + value += " "; + value += string_value; + } + g_value_unset(&gvalue); + } + } + } + + gtk_tree_path_free(path); + } + + // Get the name of this control. + std::string name = GetWidgetName(widget); + + // Send the notification. + AccessibilityListBoxInfo info(profile, name, value, index, count); + SendAccessibilityNotification(type, &info); +} diff --git a/chrome/browser/gtk/accessibility_event_router_gtk.h b/chrome/browser/gtk/accessibility_event_router_gtk.h index 7943ea4..57c65d9 100644 --- a/chrome/browser/gtk/accessibility_event_router_gtk.h +++ b/chrome/browser/gtk/accessibility_event_router_gtk.h @@ -13,6 +13,7 @@ #include "base/basictypes.h" #include "base/hash_tables.h" #include "base/singleton.h" +#include "base/task.h" #include "chrome/browser/accessibility_events.h" class Profile; @@ -27,6 +28,14 @@ struct hash<GtkWidget*> { }; } // namespace __gnu_cxx +// Struct to keep track of event listener hook ids to remove them later. +struct InstalledHook { + InstalledHook(guint _signal_id, gulong _hook_id) + : signal_id(_signal_id), hook_id(_hook_id) { } + guint signal_id; + gulong hook_id; +}; + // Singleton class that adds a signal emission hook to many gtk events, and // then sends an accessibility notification whenever a relevant event is // sent to an accessible control. @@ -43,6 +52,8 @@ class AccessibilityEventRouter { // Internal information about a particular widget to override the // information we get directly from gtk. struct WidgetInfo { + WidgetInfo() : ignore(false) { } + // If nonempty, will use this name instead of the widget's label. std::string name; @@ -89,25 +100,46 @@ class AccessibilityEventRouter { void DispatchAccessibilityNotification( GtkWidget* widget, NotificationType type); + // Post a task to call DispatchAccessibilityNotification the next time + // through the event loop. + void PostDispatchAccessibilityNotification( + GtkWidget* widget, NotificationType type); + // Each of these methods constructs an AccessibilityControlInfo object // and sends a notification of a specific accessibility event. - void SendRadioButtonNotification( + void SendButtonNotification( GtkWidget* widget, NotificationType type, Profile* profile); void SendCheckboxNotification( GtkWidget* widget, NotificationType type, Profile* profile); - void SendButtonNotification( + void SendComboBoxNotification( GtkWidget* widget, NotificationType type, Profile* profile); - void SendTextBoxNotification( + void SendListBoxNotification( + GtkWidget* widget, NotificationType type, Profile* profile); + void SendRadioButtonNotification( GtkWidget* widget, NotificationType type, Profile* profile); void SendTabNotification( GtkWidget* widget, NotificationType type, Profile* profile); + void SendTextBoxNotification( + GtkWidget* widget, NotificationType type, Profile* profile); void InstallEventListeners(); void RemoveEventListeners(); + // Start and stop listening to signals. + void StartListening(); + void StopListening(); + private: AccessibilityEventRouter(); - virtual ~AccessibilityEventRouter() {} + virtual ~AccessibilityEventRouter(); + + // Add a signal emission hook for one particular signal name and + // widget type, and save the hook_id in installed_hooks so we can + // remove it later. + void InstallEventListener( + const char *signal_name, + GType widget_type, + GSignalEmissionHook hook_func); friend struct DefaultSingletonTraits<AccessibilityEventRouter>; @@ -119,12 +151,13 @@ class AccessibilityEventRouter { base::hash_map<GtkWidget*, WidgetInfo> widget_info_map_; // Installed event listener hook ids so we can remove them later. - gulong focus_hook_; - gulong click_hook_; - gulong toggle_hook_; - gulong switch_page_hook_; + std::vector<InstalledHook> installed_hooks_; + + // True if we are currently listening to signals. + bool listening_; - std::vector<gulong> event_listener_hook_ids_; + // Used to schedule invocations of StartListening(). + ScopedRunnableMethodFactory<AccessibilityEventRouter> method_factory_; }; #endif // CHROME_BROWSER_GTK_ACCESSIBILITY_EVENT_ROUTER_GTK_H_ diff --git a/chrome/browser/gtk/accessible_widget_helper_gtk.cc b/chrome/browser/gtk/accessible_widget_helper_gtk.cc index 64710b1..e54c6ff 100644 --- a/chrome/browser/gtk/accessible_widget_helper_gtk.cc +++ b/chrome/browser/gtk/accessible_widget_helper_gtk.cc @@ -5,16 +5,27 @@ #include "chrome/browser/gtk/accessible_widget_helper_gtk.h" #include "app/l10n_util.h" +#include "chrome/browser/accessibility_events.h" #include "chrome/browser/profile.h" +#include "chrome/common/notification_service.h" AccessibleWidgetHelper::AccessibleWidgetHelper( GtkWidget* root_widget, Profile* profile) : accessibility_event_router_(AccessibilityEventRouter::GetInstance()), + profile_(profile), root_widget_(root_widget) { accessibility_event_router_->AddRootWidget(root_widget_, profile); } AccessibleWidgetHelper::~AccessibleWidgetHelper() { + if (!window_title_.empty()) { + AccessibilityWindowInfo info(profile_, window_title_); + NotificationService::current()->Notify( + NotificationType::ACCESSIBILITY_WINDOW_CLOSED, + Source<Profile>(profile_), + Details<AccessibilityWindowInfo>(&info)); + } + if (root_widget_) accessibility_event_router_->RemoveRootWidget(root_widget_); for (unsigned int i = 0; i < managed_widgets_.size(); i++) { @@ -22,6 +33,16 @@ AccessibleWidgetHelper::~AccessibleWidgetHelper() { } } +void AccessibleWidgetHelper::SendOpenWindowNotification( + const std::string& window_title) { + window_title_ = window_title; + AccessibilityWindowInfo info(profile_, window_title); + NotificationService::current()->Notify( + NotificationType::ACCESSIBILITY_WINDOW_OPENED, + Source<Profile>(profile_), + Details<AccessibilityWindowInfo>(&info)); +} + void AccessibleWidgetHelper::IgnoreWidget(GtkWidget* widget) { accessibility_event_router_->IgnoreWidget(widget); managed_widgets_.push_back(widget); diff --git a/chrome/browser/gtk/accessible_widget_helper_gtk.h b/chrome/browser/gtk/accessible_widget_helper_gtk.h index 94e9140..b677c39 100644 --- a/chrome/browser/gtk/accessible_widget_helper_gtk.h +++ b/chrome/browser/gtk/accessible_widget_helper_gtk.h @@ -38,6 +38,11 @@ class AccessibleWidgetHelper { virtual ~AccessibleWidgetHelper(); + // Send a notification that a new window was opened now, and a + // corresponding close window notification when this object + // goes out of scope. + void SendOpenWindowNotification(const std::string& window_title); + // Do not send accessibility events for this widget void IgnoreWidget(GtkWidget* widget); @@ -51,7 +56,9 @@ class AccessibleWidgetHelper { private: AccessibilityEventRouter* accessibility_event_router_; + Profile* profile_; GtkWidget* root_widget_; + std::string window_title_; std::vector<GtkWidget*> managed_widgets_; }; diff --git a/chrome/browser/gtk/clear_browsing_data_dialog_gtk.cc b/chrome/browser/gtk/clear_browsing_data_dialog_gtk.cc index 1e2e533..183f641 100644 --- a/chrome/browser/gtk/clear_browsing_data_dialog_gtk.cc +++ b/chrome/browser/gtk/clear_browsing_data_dialog_gtk.cc @@ -4,10 +4,13 @@ #include "chrome/browser/gtk/clear_browsing_data_dialog_gtk.h" +#include <string> + #include "app/l10n_util.h" #include "app/resource_bundle.h" #include "chrome/browser/browser.h" #include "chrome/browser/browsing_data_remover.h" +#include "chrome/browser/gtk/accessible_widget_helper_gtk.h" #include "chrome/browser/gtk/browser_window_gtk.h" #include "chrome/browser/gtk/gtk_chrome_link_button.h" #include "chrome/browser/pref_service.h" @@ -26,13 +29,19 @@ ClearBrowsingDataDialogGtk::ClearBrowsingDataDialogGtk(GtkWindow* parent, Profile* profile) : profile_(profile), remover_(NULL) { // Build the dialog. + std::string dialog_name = l10n_util::GetStringUTF8( + IDS_CLEAR_BROWSING_DATA_TITLE); GtkWidget* dialog = gtk_dialog_new_with_buttons( - l10n_util::GetStringUTF8(IDS_CLEAR_BROWSING_DATA_TITLE).c_str(), + dialog_name.c_str(), parent, (GtkDialogFlags) (GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR), GTK_STOCK_CLOSE, GTK_RESPONSE_REJECT, NULL); + + accessible_widget_helper_.reset(new AccessibleWidgetHelper(dialog, profile)); + accessible_widget_helper_->SendOpenWindowNotification(dialog_name); + gtk_widget_realize(dialog); gtk_util::SetWindowSizeFromResources(GTK_WINDOW(dialog), IDS_CLEARDATA_DIALOG_WIDTH_CHARS, @@ -164,6 +173,9 @@ ClearBrowsingDataDialogGtk::ClearBrowsingDataDialogGtk(GtkWindow* parent, gtk_widget_show_all(dialog); } +ClearBrowsingDataDialogGtk::~ClearBrowsingDataDialogGtk() { +} + void ClearBrowsingDataDialogGtk::OnDialogResponse(GtkWidget* widget, int response) { if (response == GTK_RESPONSE_ACCEPT) { diff --git a/chrome/browser/gtk/clear_browsing_data_dialog_gtk.h b/chrome/browser/gtk/clear_browsing_data_dialog_gtk.h index 896119e..ce452f6 100644 --- a/chrome/browser/gtk/clear_browsing_data_dialog_gtk.h +++ b/chrome/browser/gtk/clear_browsing_data_dialog_gtk.h @@ -6,10 +6,12 @@ #define CHROME_BROWSER_GTK_CLEAR_BROWSING_DATA_DIALOG_GTK_H_ #include "base/basictypes.h" +#include "base/scoped_ptr.h" typedef struct _GtkWidget GtkWidget; typedef struct _GtkWindow GtkWindow; +class AccessibleWidgetHelper; class BrowsingDataRemover; class Profile; @@ -20,7 +22,7 @@ class ClearBrowsingDataDialogGtk { private: ClearBrowsingDataDialogGtk(GtkWindow* parent, Profile* profile); - ~ClearBrowsingDataDialogGtk() { } + ~ClearBrowsingDataDialogGtk(); // Handler to respond to Ok and Cancel responses from the dialog. static void HandleOnResponseDialog(GtkWidget* widget, @@ -59,6 +61,9 @@ class ClearBrowsingDataDialogGtk { // of deleting itself when done. BrowsingDataRemover* remover_; + // Helper object to manage accessibility metadata. + scoped_ptr<AccessibleWidgetHelper> accessible_widget_helper_; + DISALLOW_COPY_AND_ASSIGN(ClearBrowsingDataDialogGtk); }; diff --git a/chrome/browser/gtk/edit_search_engine_dialog.cc b/chrome/browser/gtk/edit_search_engine_dialog.cc index 1aa3576..6830b63 100644 --- a/chrome/browser/gtk/edit_search_engine_dialog.cc +++ b/chrome/browser/gtk/edit_search_engine_dialog.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Copyright (c) 2010 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -10,6 +10,7 @@ #include "app/resource_bundle.h" #include "base/message_loop.h" #include "base/string_util.h" +#include "chrome/browser/gtk/accessible_widget_helper_gtk.h" #include "chrome/browser/net/url_fixer_upper.h" #include "chrome/browser/profile.h" #include "chrome/browser/search_engines/edit_search_engine_controller.h" @@ -63,21 +64,27 @@ EditSearchEngineDialog::EditSearchEngineDialog( Profile* profile) : controller_(new EditSearchEngineController(template_url, delegate, profile)) { - Init(parent_window); + Init(parent_window, profile); } -void EditSearchEngineDialog::Init(GtkWindow* parent_window) { +void EditSearchEngineDialog::Init(GtkWindow* parent_window, Profile* profile) { + std::string dialog_name = l10n_util::GetStringUTF8( + controller_->template_url() ? + IDS_SEARCH_ENGINES_EDITOR_EDIT_WINDOW_TITLE : + IDS_SEARCH_ENGINES_EDITOR_NEW_WINDOW_TITLE); + dialog_ = gtk_dialog_new_with_buttons( - l10n_util::GetStringUTF8( - controller_->template_url() ? - IDS_SEARCH_ENGINES_EDITOR_EDIT_WINDOW_TITLE : - IDS_SEARCH_ENGINES_EDITOR_NEW_WINDOW_TITLE).c_str(), + dialog_name.c_str(), parent_window, static_cast<GtkDialogFlags>(GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, NULL); + accessible_widget_helper_.reset(new AccessibleWidgetHelper( + dialog_, profile)); + accessible_widget_helper_->SendOpenWindowNotification(dialog_name); + ok_button_ = gtk_dialog_add_button(GTK_DIALOG(dialog_), controller_->template_url() ? GTK_STOCK_SAVE : @@ -110,6 +117,9 @@ void EditSearchEngineDialog::Init(GtkWindow* parent_window) { gtk_entry_set_activates_default(GTK_ENTRY(title_entry_), TRUE); g_signal_connect(title_entry_, "changed", G_CALLBACK(OnEntryChanged), this); + accessible_widget_helper_->SetWidgetName( + title_entry_, + IDS_SEARCH_ENGINES_EDITOR_DESCRIPTION_LABEL); keyword_entry_ = gtk_entry_new(); gtk_entry_set_activates_default(GTK_ENTRY(keyword_entry_), TRUE); @@ -117,11 +127,17 @@ void EditSearchEngineDialog::Init(GtkWindow* parent_window) { G_CALLBACK(OnEntryChanged), this); g_signal_connect(keyword_entry_, "insert-text", G_CALLBACK(LowercaseInsertTextHandler), NULL); + accessible_widget_helper_->SetWidgetName( + keyword_entry_, + IDS_SEARCH_ENGINES_EDITOR_KEYWORD_LABEL); url_entry_ = gtk_entry_new(); gtk_entry_set_activates_default(GTK_ENTRY(url_entry_), TRUE); g_signal_connect(url_entry_, "changed", G_CALLBACK(OnEntryChanged), this); + accessible_widget_helper_->SetWidgetName( + url_entry_, + IDS_SEARCH_ENGINES_EDITOR_URL_LABEL); title_image_ = gtk_image_new_from_pixbuf(NULL); keyword_image_ = gtk_image_new_from_pixbuf(NULL); diff --git a/chrome/browser/gtk/edit_search_engine_dialog.h b/chrome/browser/gtk/edit_search_engine_dialog.h index 9635d9f..790a94d 100644 --- a/chrome/browser/gtk/edit_search_engine_dialog.h +++ b/chrome/browser/gtk/edit_search_engine_dialog.h @@ -1,4 +1,4 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Copyright (c) 2010 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -11,6 +11,7 @@ #include "base/basictypes.h" #include "base/scoped_ptr.h" +class AccessibleWidgetHelper; class EditSearchEngineController; class EditSearchEngineControllerDelegate; class Profile; @@ -25,7 +26,7 @@ class EditSearchEngineDialog { private: // Create and show the window. - void Init(GtkWindow* parent_window); + void Init(GtkWindow* parent_window, Profile* profile); // Retrieve the user input in the various fields. std::wstring GetTitleInput() const; @@ -71,6 +72,9 @@ class EditSearchEngineDialog { scoped_ptr<EditSearchEngineController> controller_; + // Helper object to manage accessibility metadata. + scoped_ptr<AccessibleWidgetHelper> accessible_widget_helper_; + DISALLOW_COPY_AND_ASSIGN(EditSearchEngineDialog); }; diff --git a/chrome/browser/gtk/import_dialog_gtk.cc b/chrome/browser/gtk/import_dialog_gtk.cc index 71546b2..fb3d92d 100644 --- a/chrome/browser/gtk/import_dialog_gtk.cc +++ b/chrome/browser/gtk/import_dialog_gtk.cc @@ -1,11 +1,14 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Copyright (c) 2010 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "chrome/browser/gtk/import_dialog_gtk.h" +#include <string> + #include "app/l10n_util.h" #include "app/resource_bundle.h" +#include "chrome/browser/gtk/accessible_widget_helper_gtk.h" #include "chrome/common/gtk_util.h" #include "grit/generated_resources.h" #include "grit/locale_settings.h" @@ -34,13 +37,20 @@ ImportDialogGtk::ImportDialogGtk(GtkWindow* parent, Profile* profile, importer_host_(new ImporterHost()), initial_state_(initial_state) { // Build the dialog. + std::string dialog_name = l10n_util::GetStringUTF8( + IDS_IMPORT_SETTINGS_TITLE); dialog_ = gtk_dialog_new_with_buttons( - l10n_util::GetStringUTF8(IDS_IMPORT_SETTINGS_TITLE).c_str(), + dialog_name.c_str(), parent, (GtkDialogFlags) (GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR), GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, NULL); + + accessible_widget_helper_.reset(new AccessibleWidgetHelper( + dialog_, profile)); + accessible_widget_helper_->SendOpenWindowNotification(dialog_name); + gtk_widget_realize(dialog_); gtk_util::SetWindowSizeFromResources(GTK_WINDOW(dialog_), IDS_IMPORT_DIALOG_WIDTH_CHARS, @@ -128,6 +138,9 @@ ImportDialogGtk::ImportDialogGtk(GtkWindow* parent, Profile* profile, gtk_widget_show_all(dialog_); } +ImportDialogGtk::~ImportDialogGtk() { +} + void ImportDialogGtk::OnDialogResponse(GtkWidget* widget, int response) { gtk_widget_hide_all(dialog_); if (response == GTK_RESPONSE_ACCEPT) { diff --git a/chrome/browser/gtk/import_dialog_gtk.h b/chrome/browser/gtk/import_dialog_gtk.h index 8be3dd0..1d3f5e5 100644 --- a/chrome/browser/gtk/import_dialog_gtk.h +++ b/chrome/browser/gtk/import_dialog_gtk.h @@ -1,4 +1,4 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Copyright (c) 2010 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,6 +7,7 @@ #include "chrome/browser/importer/importer.h" +class AccessibleWidgetHelper; class Profile; class ImportDialogGtk : public ImportObserver { @@ -22,7 +23,7 @@ class ImportDialogGtk : public ImportObserver { private: ImportDialogGtk(GtkWindow* parent, Profile* profile, int initial_state); - ~ImportDialogGtk() { } + ~ImportDialogGtk(); static void HandleOnResponseDialog(GtkWidget* widget, int response, @@ -60,6 +61,9 @@ class ImportDialogGtk : public ImportObserver { int initial_state_; + // Helper object to manage accessibility metadata. + scoped_ptr<AccessibleWidgetHelper> accessible_widget_helper_; + DISALLOW_COPY_AND_ASSIGN(ImportDialogGtk); }; diff --git a/chrome/browser/gtk/keyword_editor_view.cc b/chrome/browser/gtk/keyword_editor_view.cc index 4482216..f88409b 100644 --- a/chrome/browser/gtk/keyword_editor_view.cc +++ b/chrome/browser/gtk/keyword_editor_view.cc @@ -1,12 +1,15 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Copyright (c) 2010 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "chrome/browser/gtk/keyword_editor_view.h" +#include <string> + #include "app/gfx/gtk_util.h" #include "app/l10n_util.h" #include "base/message_loop.h" +#include "chrome/browser/gtk/accessible_widget_helper_gtk.h" #include "chrome/browser/gtk/edit_search_engine_dialog.h" #include "chrome/browser/profile.h" #include "chrome/browser/metrics/user_metrics.h" @@ -75,8 +78,10 @@ KeywordEditorView::KeywordEditorView(Profile* profile) } void KeywordEditorView::Init() { + std::string dialog_name = + l10n_util::GetStringUTF8(IDS_SEARCH_ENGINES_EDITOR_WINDOW_TITLE); dialog_ = gtk_dialog_new_with_buttons( - l10n_util::GetStringUTF8(IDS_SEARCH_ENGINES_EDITOR_WINDOW_TITLE).c_str(), + dialog_name.c_str(), NULL, // Non-modal. GTK_DIALOG_NO_SEPARATOR, @@ -84,6 +89,10 @@ void KeywordEditorView::Init() { GTK_RESPONSE_CLOSE, NULL); + accessible_widget_helper_.reset(new AccessibleWidgetHelper( + dialog_, profile_)); + accessible_widget_helper_->SendOpenWindowNotification(dialog_name); + gtk_box_set_spacing(GTK_BOX(GTK_DIALOG(dialog_)->vbox), gtk_util::kContentAreaSpacing); @@ -368,7 +377,7 @@ void KeywordEditorView::OnItemsRemoved(int start, int length) { // This is quite likely not correct with removing multiple in one call, but // that shouldn't happen since we only can select and modify/remove one at a // time. - DCHECK(length == 1); + DCHECK_EQ(length, 1); for (int i = 0; i < length; ++i) { int row = GetListStoreRowForModelRow(start + i); GtkTreeIter iter; diff --git a/chrome/browser/gtk/keyword_editor_view.h b/chrome/browser/gtk/keyword_editor_view.h index 75a8db9..8651fa80 100644 --- a/chrome/browser/gtk/keyword_editor_view.h +++ b/chrome/browser/gtk/keyword_editor_view.h @@ -1,4 +1,4 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Copyright (c) 2010 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -13,6 +13,7 @@ #include "chrome/browser/search_engines/template_url_model.h" #include "testing/gtest/include/gtest/gtest_prod.h" +class AccessibleWidgetHelper; class KeywordEditorController; class Profile; class TemplateURLTableModel; @@ -147,6 +148,9 @@ class KeywordEditorView : public TableModelObserver, // |list_store_|. int model_second_group_index_; + // Helper object to manage accessibility metadata. + scoped_ptr<AccessibleWidgetHelper> accessible_widget_helper_; + friend class KeywordEditorViewTest; FRIEND_TEST(KeywordEditorViewTest, Empty); FRIEND_TEST(KeywordEditorViewTest, Add); diff --git a/chrome/browser/gtk/options/content_settings_window_gtk.cc b/chrome/browser/gtk/options/content_settings_window_gtk.cc index eeaecd5..8334a9f 100644 --- a/chrome/browser/gtk/options/content_settings_window_gtk.cc +++ b/chrome/browser/gtk/options/content_settings_window_gtk.cc @@ -4,10 +4,13 @@ #include "chrome/browser/gtk/options/content_settings_window_gtk.h" +#include <string> + #include "app/l10n_util.h" #include "chrome/browser/browser.h" #include "chrome/browser/browser_list.h" #include "chrome/browser/browser_process.h" +#include "chrome/browser/gtk/accessible_widget_helper_gtk.h" #include "chrome/browser/gtk/browser_window_gtk.h" #include "chrome/browser/pref_service.h" #include "chrome/browser/profile.h" @@ -45,15 +48,6 @@ void ContentSettingsWindowGtk::Show(GtkWindow* parent, profile->ResumeAccessibilityEvents(); } settings_window->ShowContentSettingsTab(page); - - std::string name = l10n_util::GetStringUTF8( - IDS_CONTENT_SETTINGS_TITLE); - AccessibilityWindowInfo info(profile, name); - - NotificationService::current()->Notify( - NotificationType::ACCESSIBILITY_WINDOW_OPENED, - Source<Profile>(profile), - Details<AccessibilityWindowInfo>(&info)); } ContentSettingsWindowGtk::ContentSettingsWindowGtk(GtkWindow* parent, @@ -68,13 +62,20 @@ ContentSettingsWindowGtk::ContentSettingsWindowGtk(GtkWindow* parent, last_selected_page_.Init(prefs::kContentSettingsWindowLastTabIndex, profile->GetPrefs(), NULL); + std::string dialog_name = l10n_util::GetStringUTF8( + IDS_CONTENT_SETTINGS_TITLE); dialog_ = gtk_dialog_new_with_buttons( - l10n_util::GetStringUTF8(IDS_CONTENT_SETTINGS_TITLE).c_str(), + dialog_name.c_str(), parent, static_cast<GtkDialogFlags>(GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR), GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE, NULL); + + accessible_widget_helper_.reset(new AccessibleWidgetHelper( + dialog_, profile_)); + accessible_widget_helper_->SendOpenWindowNotification(dialog_name); + gtk_window_set_default_size(GTK_WINDOW(dialog_), 500, -1); // Allow browser windows to go in front of the options dialog in metacity. gtk_window_set_type_hint(GTK_WINDOW(dialog_), GDK_WINDOW_TYPE_HINT_NORMAL); @@ -82,9 +83,6 @@ ContentSettingsWindowGtk::ContentSettingsWindowGtk(GtkWindow* parent, gtk_util::kContentAreaSpacing); gtk_util::SetWindowIcon(GTK_WINDOW(dialog_)); - accessibility_widget_helper_.reset(new AccessibleWidgetHelper( - dialog_, profile)); - notebook_ = gtk_notebook_new(); gtk_notebook_append_page( diff --git a/chrome/browser/gtk/options/content_settings_window_gtk.h b/chrome/browser/gtk/options/content_settings_window_gtk.h index d6a1b91..554aef5 100644 --- a/chrome/browser/gtk/options/content_settings_window_gtk.h +++ b/chrome/browser/gtk/options/content_settings_window_gtk.h @@ -8,7 +8,6 @@ #include <gtk/gtk.h> #include "base/scoped_ptr.h" -#include "chrome/browser/gtk/accessible_widget_helper_gtk.h" #include "chrome/browser/gtk/options/cookie_filter_page_gtk.h" #include "chrome/browser/gtk/options/content_filter_page_gtk.h" #include "chrome/browser/pref_member.h" @@ -60,7 +59,8 @@ class ContentSettingsWindowGtk { ContentFilterPageGtk plugin_page_; ContentFilterPageGtk popup_page_; - scoped_ptr<AccessibleWidgetHelper> accessibility_widget_helper_; + // Helper object to manage accessibility metadata. + scoped_ptr<AccessibleWidgetHelper> accessible_widget_helper_; DISALLOW_COPY_AND_ASSIGN(ContentSettingsWindowGtk); }; diff --git a/chrome/browser/gtk/options/general_page_gtk.cc b/chrome/browser/gtk/options/general_page_gtk.cc index 78aa693..8fed28c 100644 --- a/chrome/browser/gtk/options/general_page_gtk.cc +++ b/chrome/browser/gtk/options/general_page_gtk.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved. +// Copyright (c) 2010 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -8,6 +8,7 @@ #include "base/callback.h" #include "chrome/browser/browser.h" #include "chrome/browser/browser_list.h" +#include "chrome/browser/gtk/accessible_widget_helper_gtk.h" #include "chrome/browser/gtk/keyword_editor_view.h" #include "chrome/browser/gtk/list_store_favicon_loader.h" #include "chrome/browser/gtk/options/options_layout_gtk.h" @@ -64,6 +65,10 @@ GeneralPageGtk::GeneralPageGtk(Profile* profile) default_browser_worker_( new ShellIntegration::DefaultBrowserWorker(this)) { OptionsLayoutBuilderGtk options_builder; + page_ = options_builder.get_page_widget(); + accessible_widget_helper_.reset(new AccessibleWidgetHelper( + page_, profile)); + options_builder.AddOptionGroup( l10n_util::GetStringUTF8(IDS_OPTIONS_STARTUP_GROUP_NAME), InitStartupGroup(), true); @@ -78,7 +83,6 @@ GeneralPageGtk::GeneralPageGtk(Profile* profile) l10n_util::GetStringUTF8(IDS_OPTIONS_DEFAULTBROWSER_GROUP_NAME), InitDefaultBrowserGroup(), false); #endif - page_ = options_builder.get_page_widget(); profile->GetPrefs()->AddPrefObserver(prefs::kRestoreOnStartup, this); profile->GetPrefs()->AddPrefObserver(prefs::kURLsToRestoreOnStartup, this); @@ -323,6 +327,8 @@ GtkWidget* GeneralPageGtk::InitDefaultSearchGroup() { g_signal_connect(default_search_engine_combobox_, "changed", G_CALLBACK(OnDefaultSearchEngineChanged), this); gtk_container_add(GTK_CONTAINER(hbox), default_search_engine_combobox_); + accessible_widget_helper_->SetWidgetName( + default_search_engine_combobox_, IDS_OPTIONS_DEFAULTSEARCH_GROUP_NAME); GtkCellRenderer* renderer = gtk_cell_renderer_text_new(); gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(default_search_engine_combobox_), diff --git a/chrome/browser/gtk/options/general_page_gtk.h b/chrome/browser/gtk/options/general_page_gtk.h index b394e6f..fcb87b2 100644 --- a/chrome/browser/gtk/options/general_page_gtk.h +++ b/chrome/browser/gtk/options/general_page_gtk.h @@ -17,6 +17,7 @@ #include "chrome/browser/shell_integration.h" #include "googleurl/src/gurl.h" +class AccessibleWidgetHelper; class Profile; class ListStoreFavIconLoader; @@ -181,6 +182,9 @@ class GeneralPageGtk : public OptionsPageBase, // The helper object that performs default browser set/check tasks. scoped_refptr<ShellIntegration::DefaultBrowserWorker> default_browser_worker_; + // Helper object to manage accessibility metadata. + scoped_ptr<AccessibleWidgetHelper> accessible_widget_helper_; + DISALLOW_COPY_AND_ASSIGN(GeneralPageGtk); }; diff --git a/chrome/browser/gtk/options/options_window_gtk.cc b/chrome/browser/gtk/options/options_window_gtk.cc index b459f46..58498a2 100644 --- a/chrome/browser/gtk/options/options_window_gtk.cc +++ b/chrome/browser/gtk/options/options_window_gtk.cc @@ -72,7 +72,7 @@ class OptionsWindowGtk { // The last page the user was on when they opened the Options window. IntegerPrefMember last_selected_page_; - scoped_ptr<AccessibleWidgetHelper> accessibility_widget_helper_; + scoped_ptr<AccessibleWidgetHelper> accessible_widget_helper_; DISALLOW_COPY_AND_ASSIGN(OptionsWindowGtk); }; @@ -96,9 +96,12 @@ OptionsWindowGtk::OptionsWindowGtk(Profile* profile) last_selected_page_.Init(prefs::kOptionsWindowLastTabIndex, g_browser_process->local_state(), NULL); + std::string dialog_name = + l10n_util::GetStringFUTF8( + IDS_OPTIONS_DIALOG_TITLE, + WideToUTF16(l10n_util::GetString(IDS_PRODUCT_NAME))); dialog_ = gtk_dialog_new_with_buttons( - l10n_util::GetStringFUTF8(IDS_OPTIONS_DIALOG_TITLE, - WideToUTF16(l10n_util::GetString(IDS_PRODUCT_NAME))).c_str(), + dialog_name.c_str(), // Prefs window is shared between all browser windows. NULL, // Non-modal. @@ -106,15 +109,17 @@ OptionsWindowGtk::OptionsWindowGtk(Profile* profile) GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE, NULL); + + accessible_widget_helper_.reset(new AccessibleWidgetHelper( + dialog_, profile)); + accessible_widget_helper_->SendOpenWindowNotification(dialog_name); + gtk_window_set_default_size(GTK_WINDOW(dialog_), 500, -1); // Allow browser windows to go in front of the options dialog in metacity. gtk_window_set_type_hint(GTK_WINDOW(dialog_), GDK_WINDOW_TYPE_HINT_NORMAL); gtk_box_set_spacing(GTK_BOX(GTK_DIALOG(dialog_)->vbox), gtk_util::kContentAreaSpacing); - accessibility_widget_helper_.reset(new AccessibleWidgetHelper( - dialog_, profile)); - notebook_ = gtk_notebook_new(); #if defined(OS_CHROMEOS) @@ -250,14 +255,4 @@ void ShowOptionsWindow(OptionsPage page, profile->ResumeAccessibilityEvents(); } options_window->ShowOptionsPage(page, highlight_group); - - std::string name = l10n_util::GetStringFUTF8( - IDS_OPTIONS_DIALOG_TITLE, - WideToUTF16(l10n_util::GetString(IDS_PRODUCT_NAME))); - AccessibilityWindowInfo info(profile, name); - - NotificationService::current()->Notify( - NotificationType::ACCESSIBILITY_WINDOW_OPENED, - Source<Profile>(profile), - Details<AccessibilityWindowInfo>(&info)); } diff --git a/chrome/browser/gtk/options/passwords_exceptions_window_gtk.cc b/chrome/browser/gtk/options/passwords_exceptions_window_gtk.cc index 260a934..fc93954 100644 --- a/chrome/browser/gtk/options/passwords_exceptions_window_gtk.cc +++ b/chrome/browser/gtk/options/passwords_exceptions_window_gtk.cc @@ -6,9 +6,12 @@ #include <gtk/gtk.h> +#include <string> + #include "app/l10n_util.h" #include "base/message_loop.h" #include "chrome/browser/browser_process.h" +#include "chrome/browser/gtk/accessible_widget_helper_gtk.h" #include "chrome/browser/gtk/options/passwords_exceptions_page_gtk.h" #include "chrome/browser/gtk/options/passwords_page_gtk.h" #include "chrome/browser/options_window.h" @@ -49,6 +52,9 @@ class PasswordsExceptionsWindowGtk { // The exceptions page. PasswordsExceptionsPageGtk exceptions_page_; + // Helper object to manage accessibility metadata. + scoped_ptr<AccessibleWidgetHelper> accessible_widget_helper_; + DISALLOW_COPY_AND_ASSIGN(PasswordsExceptionsWindowGtk); }; @@ -62,8 +68,10 @@ PasswordsExceptionsWindowGtk::PasswordsExceptionsWindowGtk(Profile* profile) : profile_(profile), passwords_page_(profile_), exceptions_page_(profile_) { + std::string dialog_name = l10n_util::GetStringUTF8( + IDS_PASSWORDS_EXCEPTIONS_WINDOW_TITLE); dialog_ = gtk_dialog_new_with_buttons( - l10n_util::GetStringUTF8(IDS_PASSWORDS_EXCEPTIONS_WINDOW_TITLE).c_str(), + dialog_name.c_str(), // Passwords and exceptions window is shared between all browser windows. NULL, // Non-modal. @@ -74,6 +82,10 @@ PasswordsExceptionsWindowGtk::PasswordsExceptionsWindowGtk(Profile* profile) gtk_box_set_spacing(GTK_BOX(GTK_DIALOG(dialog_)->vbox), gtk_util::kContentAreaSpacing); + accessible_widget_helper_.reset(new AccessibleWidgetHelper( + dialog_, profile)); + accessible_widget_helper_->SendOpenWindowNotification(dialog_name); + notebook_ = gtk_notebook_new(); gtk_notebook_append_page( diff --git a/chrome/browser/gtk/options/url_picker_dialog_gtk.cc b/chrome/browser/gtk/options/url_picker_dialog_gtk.cc index b08eef7..49e0f0b 100644 --- a/chrome/browser/gtk/options/url_picker_dialog_gtk.cc +++ b/chrome/browser/gtk/options/url_picker_dialog_gtk.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Copyright (c) 2010 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,6 +7,7 @@ #include "app/gfx/gtk_util.h" #include "app/l10n_util.h" #include "base/message_loop.h" +#include "chrome/browser/gtk/accessible_widget_helper_gtk.h" #include "chrome/browser/gtk/options/url_picker_dialog_gtk.h" #include "chrome/browser/net/url_fixer_upper.h" #include "chrome/browser/possible_url_model.h" @@ -41,13 +42,17 @@ UrlPickerDialogGtk::UrlPickerDialogGtk(UrlPickerCallback* callback, GtkWindow* parent) : profile_(profile), callback_(callback) { + std::string dialog_name = l10n_util::GetStringUTF8(IDS_ASI_ADD_TITLE); dialog_ = gtk_dialog_new_with_buttons( - l10n_util::GetStringUTF8(IDS_ASI_ADD_TITLE).c_str(), + dialog_name.c_str(), parent, static_cast<GtkDialogFlags>(GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, NULL); + accessible_widget_helper_.reset(new AccessibleWidgetHelper( + dialog_, profile)); + accessible_widget_helper_->SendOpenWindowNotification(dialog_name); add_button_ = gtk_dialog_add_button(GTK_DIALOG(dialog_), GTK_STOCK_ADD, GTK_RESPONSE_OK); @@ -62,6 +67,7 @@ UrlPickerDialogGtk::UrlPickerDialogGtk(UrlPickerCallback* callback, gtk_box_pack_start(GTK_BOX(url_hbox), url_label, FALSE, FALSE, 0); url_entry_ = gtk_entry_new(); + accessible_widget_helper_->SetWidgetName(url_entry_, IDS_ASI_URL); gtk_entry_set_activates_default(GTK_ENTRY(url_entry_), TRUE); g_signal_connect(url_entry_, "changed", G_CALLBACK(OnUrlEntryChanged), this); @@ -103,6 +109,8 @@ UrlPickerDialogGtk::UrlPickerDialogGtk(UrlPickerCallback* callback, gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(history_list_sort_), COL_DISPLAY_URL, CompareURL, this, NULL); history_tree_ = gtk_tree_view_new_with_model(history_list_sort_); + accessible_widget_helper_->SetWidgetName( + history_tree_, IDS_ASI_DESCRIPTION); g_object_unref(history_list_store_); g_object_unref(history_list_sort_); gtk_container_add(GTK_CONTAINER(scroll_window), history_tree_); diff --git a/chrome/browser/gtk/options/url_picker_dialog_gtk.h b/chrome/browser/gtk/options/url_picker_dialog_gtk.h index 7d21359..8da397d 100644 --- a/chrome/browser/gtk/options/url_picker_dialog_gtk.h +++ b/chrome/browser/gtk/options/url_picker_dialog_gtk.h @@ -1,4 +1,4 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Copyright (c) 2010 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -12,6 +12,7 @@ #include "chrome/browser/history/history.h" #include "chrome/common/gtk_tree.h" +class AccessibleWidgetHelper; class GURL; class Profile; class PossibleURLModel; @@ -92,6 +93,9 @@ class UrlPickerDialogGtk : public gtk_tree::TableAdapter::Delegate { // Called if the user selects an url. UrlPickerCallback* callback_; + // Helper object to manage accessibility metadata. + scoped_ptr<AccessibleWidgetHelper> accessible_widget_helper_; + DISALLOW_COPY_AND_ASSIGN(UrlPickerDialogGtk); }; |