summaryrefslogtreecommitdiffstats
path: root/chrome/browser/gtk
diff options
context:
space:
mode:
Diffstat (limited to 'chrome/browser/gtk')
-rw-r--r--chrome/browser/gtk/accessibility_event_router_gtk.cc286
-rw-r--r--chrome/browser/gtk/accessibility_event_router_gtk.h130
-rw-r--r--chrome/browser/gtk/accessible_widget_helper_gtk.cc41
-rw-r--r--chrome/browser/gtk/accessible_widget_helper_gtk.h58
-rw-r--r--chrome/browser/gtk/location_bar_view_gtk.cc10
-rw-r--r--chrome/browser/gtk/options/advanced_contents_gtk.cc49
-rw-r--r--chrome/browser/gtk/options/content_page_gtk.h2
-rw-r--r--chrome/browser/gtk/options/general_page_gtk.cc4
-rw-r--r--chrome/browser/gtk/options/options_window_gtk.cc30
9 files changed, 606 insertions, 4 deletions
diff --git a/chrome/browser/gtk/accessibility_event_router_gtk.cc b/chrome/browser/gtk/accessibility_event_router_gtk.cc
new file mode 100644
index 0000000..c020721
--- /dev/null
+++ b/chrome/browser/gtk/accessibility_event_router_gtk.cc
@@ -0,0 +1,286 @@
+// 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/accessibility_event_router_gtk.h"
+
+#include "base/basictypes.h"
+#include "base/stl_util-inl.h"
+#include "chrome/browser/extensions/extension_accessibility_api.h"
+#include "chrome/browser/gtk/gtk_chrome_link_button.h"
+#include "chrome/browser/profile.h"
+#include "chrome/common/notification_type.h"
+
+namespace {
+
+//
+// Callbacks triggered by signals on gtk widgets.
+//
+
+gboolean OnWidgetFocused(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(
+ widget, NotificationType::ACCESSIBILITY_CONTROL_FOCUSED);
+ return true;
+}
+
+gboolean OnButtonClicked(GSignalInvocationHint *ihint,
+ guint n_param_values,
+ const GValue* param_values,
+ gpointer user_data) {
+ GtkWidget* widget = GTK_WIDGET(g_value_get_object(param_values));
+ // 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(
+ widget, NotificationType::ACCESSIBILITY_CONTROL_ACTION);
+ return true;
+}
+
+gboolean OnButtonToggled(GSignalInvocationHint *ihint,
+ guint n_param_values,
+ const GValue* param_values,
+ gpointer user_data) {
+ GtkWidget* widget = GTK_WIDGET(g_value_get_object(param_values));
+ bool checked = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
+ // Skip propagating an "uncheck" event for a radio button because it's
+ // redundant; there will always be a corresponding "check" event for
+ // a different radio button the group.
+ if (GTK_IS_RADIO_BUTTON(widget) && !checked)
+ return true;
+ 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) {
+ GtkWidget* widget = GTK_WIDGET(g_value_get_object(param_values));
+ reinterpret_cast<AccessibilityEventRouter *>(user_data)
+ ->DispatchAccessibilityNotification(
+ widget, NotificationType::ACCESSIBILITY_CONTROL_ACTION);
+ return true;
+}
+
+} // anonymous namespace
+
+AccessibilityEventRouter::AccessibilityEventRouter() {
+ // 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.
+ ExtensionAccessibilityEventRouter *accessibility_event_router =
+ ExtensionAccessibilityEventRouter::GetInstance();
+ accessibility_event_router->AddOnEnabledListener(
+ NewCallback(this,
+ &AccessibilityEventRouter::InstallEventListeners));
+ accessibility_event_router->AddOnDisabledListener(
+ NewCallback(this,
+ &AccessibilityEventRouter::RemoveEventListeners));
+ if (accessibility_event_router->IsAccessibilityEnabled()) {
+ InstallEventListeners();
+ }
+}
+
+// static
+AccessibilityEventRouter* AccessibilityEventRouter::GetInstance() {
+ return Singleton<AccessibilityEventRouter>::get();
+}
+
+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.
+ g_object_unref(g_object_ref_sink(gtk_notebook_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);
+}
+
+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_);
+}
+
+void AccessibilityEventRouter::AddRootWidget(
+ GtkWidget* root_widget, Profile* profile) {
+ root_widget_profile_map_[root_widget] = profile;
+}
+
+void AccessibilityEventRouter::RemoveRootWidget(GtkWidget* root_widget) {
+ DCHECK(root_widget_profile_map_.find(root_widget) !=
+ root_widget_profile_map_.end());
+ root_widget_profile_map_.erase(root_widget);
+}
+
+void AccessibilityEventRouter::IgnoreWidget(GtkWidget* widget) {
+ widget_info_map_[widget].ignore = true;
+}
+
+void AccessibilityEventRouter::SetWidgetName(
+ GtkWidget* widget, std::string name) {
+ widget_info_map_[widget].name = name;
+}
+
+void AccessibilityEventRouter::RemoveWidget(GtkWidget* widget) {
+ DCHECK(widget_info_map_.find(widget) != widget_info_map_.end());
+ widget_info_map_.erase(widget);
+}
+
+bool AccessibilityEventRouter::IsWidgetAccessible(
+ GtkWidget* widget, Profile** profile) {
+ // First see if it's a descendant of a root widget.
+ bool is_accessible = false;
+ for (base::hash_map<GtkWidget*, Profile*>::const_iterator iter =
+ root_widget_profile_map_.begin();
+ iter != root_widget_profile_map_.end();
+ ++iter) {
+ if (gtk_widget_is_ancestor(widget, iter->first)) {
+ is_accessible = true;
+ if (profile)
+ *profile = iter->second;
+ break;
+ }
+ }
+ if (!is_accessible)
+ return false;
+
+ // Now make sure it's not marked as a widget to be ignored.
+ base::hash_map<GtkWidget*, WidgetInfo>::const_iterator iter =
+ widget_info_map_.find(widget);
+ if (iter != widget_info_map_.end() && iter->second.ignore) {
+ is_accessible = false;
+ }
+
+ return is_accessible;
+}
+
+std::string AccessibilityEventRouter::GetWidgetName(GtkWidget* widget) {
+ base::hash_map<GtkWidget*, WidgetInfo>::const_iterator iter =
+ widget_info_map_.find(widget);
+ if (iter != widget_info_map_.end()) {
+ return iter->second.name;
+ } else {
+ return "";
+ }
+}
+
+void AccessibilityEventRouter::DispatchAccessibilityNotification(
+ GtkWidget* widget, NotificationType type) {
+ 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)) {
+ SendRadioButtonNotification(widget, type, profile);
+ } else if (GTK_IS_TOGGLE_BUTTON(widget)) {
+ SendCheckboxNotification(widget, type, profile);
+ } else if (GTK_IS_BUTTON(widget)) {
+ SendButtonNotification(widget, type, profile);
+ } else if (GTK_IS_ENTRY(widget)) {
+ SendTextBoxNotification(widget, type, profile);
+ } else if (GTK_IS_NOTEBOOK(widget)) {
+ SendTabNotification(widget, type, profile);
+ }
+}
+
+void AccessibilityEventRouter::SendRadioButtonNotification(
+ GtkWidget* widget, NotificationType type, Profile* profile) {
+ // Get the radio button name
+ std::string button_name = GetWidgetName(widget);
+ if (button_name.empty() && gtk_button_get_label(GTK_BUTTON(widget)))
+ button_name = gtk_button_get_label(GTK_BUTTON(widget));
+
+ // Get its state
+ bool checked = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
+
+ // Get the index of this radio button and the total number of
+ // radio buttons in the group.
+ int item_count = 0;
+ int item_index = -1;
+ for (GSList* group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(widget));
+ group;
+ group = group->next) {
+ if (group->data == widget) {
+ item_index = item_count;
+ }
+ item_count++;
+ }
+ item_index = item_count - 1 - item_index;
+
+ AccessibilityRadioButtonInfo info(
+ profile, button_name, checked, item_index, item_count);
+ SendAccessibilityNotification(type, &info);
+}
+
+void AccessibilityEventRouter::SendCheckboxNotification(
+ GtkWidget* widget, NotificationType type, Profile* profile) {
+ std::string button_name = GetWidgetName(widget);
+ if (button_name.empty() && gtk_button_get_label(GTK_BUTTON(widget)))
+ button_name = gtk_button_get_label(GTK_BUTTON(widget));
+ bool checked = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
+ AccessibilityCheckboxInfo info(profile, button_name, checked);
+ SendAccessibilityNotification(type, &info);
+}
+
+void AccessibilityEventRouter::SendButtonNotification(
+ GtkWidget* widget, NotificationType type, Profile* profile) {
+ std::string button_name = GetWidgetName(widget);
+ if (button_name.empty() && gtk_button_get_label(GTK_BUTTON(widget)))
+ button_name = gtk_button_get_label(GTK_BUTTON(widget));
+ AccessibilityButtonInfo info(profile, button_name);
+ SendAccessibilityNotification(type, &info);
+}
+
+void AccessibilityEventRouter::SendTextBoxNotification(
+ GtkWidget* widget, NotificationType type, Profile* profile) {
+ std::string name = GetWidgetName(widget);
+ std::string value = gtk_entry_get_text(GTK_ENTRY(widget));
+ gint start_pos;
+ gint end_pos;
+ gtk_editable_get_selection_bounds(GTK_EDITABLE(widget), &start_pos, &end_pos);
+ AccessibilityTextBoxInfo info(profile, name, false);
+ info.SetValue(value, start_pos, end_pos);
+ SendAccessibilityNotification(type, &info);
+}
+
+void AccessibilityEventRouter::SendTabNotification(
+ GtkWidget* widget, NotificationType type, Profile* profile) {
+ int index = gtk_notebook_get_current_page(GTK_NOTEBOOK(widget));
+ int page_count = gtk_notebook_get_n_pages(GTK_NOTEBOOK(widget));
+ GtkWidget* page = gtk_notebook_get_nth_page(GTK_NOTEBOOK(widget), index);
+ GtkWidget* label = gtk_notebook_get_tab_label(GTK_NOTEBOOK(widget), page);
+ std::string name = GetWidgetName(widget);
+ if (name.empty() && gtk_label_get_text(GTK_LABEL(label))) {
+ name = gtk_label_get_text(GTK_LABEL(label));
+ }
+ AccessibilityTabInfo info(profile, name, index, page_count);
+ SendAccessibilityNotification(type, &info);
+}
diff --git a/chrome/browser/gtk/accessibility_event_router_gtk.h b/chrome/browser/gtk/accessibility_event_router_gtk.h
new file mode 100644
index 0000000..d0fd99d
--- /dev/null
+++ b/chrome/browser/gtk/accessibility_event_router_gtk.h
@@ -0,0 +1,130 @@
+// 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.
+
+#ifndef CHROME_BROWSER_GTK_ACCESSIBILITY_EVENT_ROUTER_GTK_H_
+#define CHROME_BROWSER_GTK_ACCESSIBILITY_EVENT_ROUTER_GTK_H_
+
+#include <gtk/gtk.h>
+
+#include <string>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/hash_tables.h"
+#include "base/singleton.h"
+#include "chrome/common/accessibility_events.h"
+
+class Profile;
+
+// Allows us to use (GtkWidget*) in a hash_map with gcc.
+namespace __gnu_cxx {
+template<>
+struct hash<GtkWidget*> {
+ size_t operator()(GtkWidget* widget) const {
+ return reinterpret_cast<size_t>(widget);
+ }
+};
+} // namespace __gnu_cxx
+
+// 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.
+//
+// Gtk widgets are not accessible by default. When you register a root widget,
+// that widget and all of its descendants will start sending accessibility
+// event notifications. You can then override the default behavior for
+// specific descendants using other methods.
+//
+// You can use Profile::PauseAccessibilityEvents to prevent a flurry
+// of accessibility events when a window is being created or initialized.
+class AccessibilityEventRouter {
+ public:
+ // Internal information about a particular widget to override the
+ // information we get directly from gtk.
+ struct WidgetInfo {
+ // If nonempty, will use this name instead of the widget's label.
+ std::string name;
+
+ // If true, will ignore this widget and not send accessibility events.
+ bool ignore;
+ };
+
+ // Get the single instance of this class.
+ static AccessibilityEventRouter* GetInstance();
+
+ // Start sending accessibility events for this widget and all of its
+ // descendants. Notifications will go to the specified profile.
+ void AddRootWidget(GtkWidget* root_widget, Profile* profile);
+
+ // Stop sending accessibility events for this widget and all of its
+ // descendants.
+ void RemoveRootWidget(GtkWidget* root_widget);
+
+ // Don't send any events for this widget.
+ void IgnoreWidget(GtkWidget* widget);
+
+ // Use the following string as the name of this widget, instead of the
+ // gtk label associated with the widget.
+ void SetWidgetName(GtkWidget* widget, std::string name);
+
+ // Forget all information about this widget.
+ void RemoveWidget(GtkWidget* widget);
+
+ //
+ // The following methods are only for use by gtk signal handlers.
+ //
+
+ // Returns true if this widget is a descendant of one of our registered
+ // root widgets and not in the set of ignored widgets. If |profile| is
+ // not null, return the profile where notifications associated with this
+ // widget should be sent.
+ bool IsWidgetAccessible(GtkWidget* widget, Profile** profile);
+
+ // Return the name of a widget.
+ std::string GetWidgetName(GtkWidget* widget);
+
+ // Called by the signal handler. Checks the type of the widget and
+ // calls one of the more specific Send*Notification methods, below.
+ void DispatchAccessibilityNotification(
+ GtkWidget* widget, NotificationType type);
+
+ // Each of these methods constructs an AccessibilityControlInfo object
+ // and sends a notification of a specific accessibility event.
+ void SendRadioButtonNotification(
+ GtkWidget* widget, NotificationType type, Profile* profile);
+ void SendCheckboxNotification(
+ GtkWidget* widget, NotificationType type, Profile* profile);
+ void SendButtonNotification(
+ GtkWidget* widget, NotificationType type, Profile* profile);
+ void SendTextBoxNotification(
+ GtkWidget* widget, NotificationType type, Profile* profile);
+ void SendTabNotification(
+ GtkWidget* widget, NotificationType type, Profile* profile);
+
+ void InstallEventListeners();
+ void RemoveEventListeners();
+
+ private:
+ AccessibilityEventRouter();
+ virtual ~AccessibilityEventRouter() {}
+
+ friend struct DefaultSingletonTraits<AccessibilityEventRouter>;
+
+ // The set of all root widgets; only descendants of these will generate
+ // accessibility notifications.
+ base::hash_map<GtkWidget*, Profile*> root_widget_profile_map_;
+
+ // Extra information about specific widgets.
+ 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<gulong> event_listener_hook_ids_;
+};
+
+#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
new file mode 100644
index 0000000..64710b1
--- /dev/null
+++ b/chrome/browser/gtk/accessible_widget_helper_gtk.cc
@@ -0,0 +1,41 @@
+// 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/accessible_widget_helper_gtk.h"
+
+#include "app/l10n_util.h"
+#include "chrome/browser/profile.h"
+
+AccessibleWidgetHelper::AccessibleWidgetHelper(
+ GtkWidget* root_widget, Profile* profile)
+ : accessibility_event_router_(AccessibilityEventRouter::GetInstance()),
+ root_widget_(root_widget) {
+ accessibility_event_router_->AddRootWidget(root_widget_, profile);
+}
+
+AccessibleWidgetHelper::~AccessibleWidgetHelper() {
+ if (root_widget_)
+ accessibility_event_router_->RemoveRootWidget(root_widget_);
+ for (unsigned int i = 0; i < managed_widgets_.size(); i++) {
+ accessibility_event_router_->RemoveWidget(managed_widgets_[i]);
+ }
+}
+
+void AccessibleWidgetHelper::IgnoreWidget(GtkWidget* widget) {
+ accessibility_event_router_->IgnoreWidget(widget);
+ managed_widgets_.push_back(widget);
+}
+
+void AccessibleWidgetHelper::SetWidgetName(
+ GtkWidget* widget, std::string name) {
+ accessibility_event_router_->SetWidgetName(widget, name);
+ managed_widgets_.push_back(widget);
+}
+
+void AccessibleWidgetHelper::SetWidgetName(
+ GtkWidget* widget, int string_id) {
+ std::string name = l10n_util::GetStringUTF8(string_id);
+ accessibility_event_router_->SetWidgetName(widget, name);
+ 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
new file mode 100644
index 0000000..775b92e
--- /dev/null
+++ b/chrome/browser/gtk/accessible_widget_helper_gtk.h
@@ -0,0 +1,58 @@
+// 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.
+
+#ifndef CHROME_BROWSER_GTK_ACCESSIBLE_WIDGET_HELPER_GTK_H_
+#define CHROME_BROWSER_GTK_ACCESSIBLE_WIDGET_HELPER_GTK_H_
+
+#include <gtk/gtk.h>
+
+#include <string>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/singleton.h"
+#include "chrome/browser/gtk/accessibility_event_router_gtk.h"
+#include "chrome/common/accessibility_events.h"
+
+class Profile;
+
+// Helper class that helps to manage the accessibility information for all
+// of the widgets in a container. Create an instance of this class for
+// each container GtkWidget (like a dialog) that should send accessibility
+// events for all of its descendants.
+//
+// Most controls have default behavior for accessibility; when this needs
+// to be augmented, call one of the methods below to ignore a particular
+// widget or change its details.
+//
+// All of the information managed by this class is registered with the
+// (global) AccessibilityEventRouter and unregistered when this object is
+// destroyed.
+class AccessibleWidgetHelper {
+ public:
+ // Contruct an AccessibleWidgetHelper that makes the given root widget
+ // accessible for the lifetime of this object, sending accessibility
+ // notifications to the given profile.
+ AccessibleWidgetHelper(GtkWidget* root_widget, Profile* profile);
+
+ virtual ~AccessibleWidgetHelper();
+
+ // Do not send accessibility events for this widget
+ void IgnoreWidget(GtkWidget* widget);
+
+ // Use the following string as the name of this widget, instead of the
+ // gtk label associated with the widget.
+ void SetWidgetName(GtkWidget* widget, std::string name);
+
+ // Use the following string as the name of this widget, instead of the
+ // gtk label associated with the widget.
+ void SetWidgetName(GtkWidget* widget, int string_id);
+
+ private:
+ AccessibilityEventRouter* accessibility_event_router_;
+ GtkWidget* root_widget_;
+ std::vector<GtkWidget*> managed_widgets_;
+};
+
+#endif // CHROME_BROWSER_GTK_ACCESSIBLE_WIDGET_HELPER_GTK_H_
diff --git a/chrome/browser/gtk/location_bar_view_gtk.cc b/chrome/browser/gtk/location_bar_view_gtk.cc
index 2842fcd..a52105d 100644
--- a/chrome/browser/gtk/location_bar_view_gtk.cc
+++ b/chrome/browser/gtk/location_bar_view_gtk.cc
@@ -19,6 +19,7 @@
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/command_updater.h"
+#include "chrome/browser/extensions/extension_accessibility_api_constants.h"
#include "chrome/browser/extensions/extension_action_context_menu_model.h"
#include "chrome/browser/extensions/extension_browser_event_router.h"
#include "chrome/browser/extensions/extension_tabs_module.h"
@@ -32,6 +33,7 @@
#include "chrome/browser/search_engines/template_url.h"
#include "chrome/browser/search_engines/template_url_model.h"
#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/common/accessibility_events.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/extension_action.h"
#include "chrome/common/gtk_util.h"
@@ -449,6 +451,14 @@ void LocationBarViewGtk::OnKillFocus() {
}
void LocationBarViewGtk::OnSetFocus() {
+ AccessibilityTextBoxInfo info(
+ profile_,
+ l10n_util::GetStringUTF8(IDS_ACCNAME_LOCATION).c_str(),
+ false);
+ NotificationService::current()->Notify(
+ NotificationType::ACCESSIBILITY_CONTROL_FOCUSED,
+ Source<Profile>(profile_),
+ Details<AccessibilityTextBoxInfo>(&info));
}
SkBitmap LocationBarViewGtk::GetFavIcon() const {
diff --git a/chrome/browser/gtk/options/advanced_contents_gtk.cc b/chrome/browser/gtk/options/advanced_contents_gtk.cc
index d493a39..2ceb997 100644
--- a/chrome/browser/gtk/options/advanced_contents_gtk.cc
+++ b/chrome/browser/gtk/options/advanced_contents_gtk.cc
@@ -18,6 +18,7 @@
#include "chrome/browser/browser_process.h"
#include "chrome/browser/download/download_manager.h"
#include "chrome/browser/fonts_languages_window.h"
+#include "chrome/browser/gtk/accessible_widget_helper_gtk.h"
#include "chrome/browser/gtk/gtk_chrome_link_button.h"
#include "chrome/browser/gtk/options/cookies_view.h"
#include "chrome/browser/gtk/options/options_layout_gtk.h"
@@ -82,6 +83,7 @@ GtkWidget* AddCheckButtonWithWrappedLabel(int string_id,
GtkWidget* checkbox = CreateCheckButtonWithWrappedLabel(string_id);
gtk_box_pack_start(GTK_BOX(container), checkbox, FALSE, FALSE, 0);
g_signal_connect(checkbox, "toggled", handler, data);
+
return checkbox;
}
@@ -167,13 +169,19 @@ class DownloadSection : public OptionsPageBase {
// then turning around and saving them again.
bool pref_changing_;
+ scoped_ptr<AccessibleWidgetHelper> accessible_widget_helper_;
+
DISALLOW_COPY_AND_ASSIGN(DownloadSection);
};
DownloadSection::DownloadSection(Profile* profile)
- : OptionsPageBase(profile), pref_changing_(true) {
+ : OptionsPageBase(profile),
+ pref_changing_(true) {
page_ = gtk_vbox_new(FALSE, gtk_util::kControlSpacing);
+ accessible_widget_helper_.reset(new AccessibleWidgetHelper(
+ page_, profile));
+
// Download location options.
download_location_button_ = gtk_file_chooser_button_new(
l10n_util::GetStringUTF8(
@@ -212,6 +220,9 @@ DownloadSection::DownloadSection(Profile* profile)
FALSE, FALSE, 0);
g_signal_connect(download_ask_for_save_location_checkbox_, "clicked",
G_CALLBACK(OnDownloadAskForSaveLocationChanged), this);
+ accessible_widget_helper_->SetWidgetName(
+ download_ask_for_save_location_checkbox_,
+ IDS_OPTIONS_DOWNLOADLOCATION_ASKFORSAVELOCATION);
// Option for resetting file handlers.
reset_file_handlers_label_ = CreateWrappedLabel(
@@ -359,6 +370,7 @@ NetworkSection::NetworkSection(Profile* profile)
IDS_OPTIONS_PROXIES_CONFIGURE_BUTTON).c_str());
g_signal_connect(change_proxies_button, "clicked",
G_CALLBACK(OnChangeProxiesButtonClicked), this);
+
// Stick it in an hbox so it doesn't expand to the whole width.
GtkWidget* button_hbox = gtk_hbox_new(FALSE, 0);
gtk_box_pack_start(GTK_BOX(button_hbox),
@@ -526,6 +538,8 @@ class PrivacySection : public OptionsPageBase {
// then turning around and saving them again.
bool pref_changing_;
+ scoped_ptr<AccessibleWidgetHelper> accessible_widget_helper_;
+
DISALLOW_COPY_AND_ASSIGN(PrivacySection);
};
@@ -534,6 +548,9 @@ PrivacySection::PrivacySection(Profile* profile)
pref_changing_(true) {
page_ = gtk_vbox_new(FALSE, gtk_util::kControlSpacing);
+ accessible_widget_helper_.reset(new AccessibleWidgetHelper(
+ page_, profile));
+
GtkWidget* section_description_label = CreateWrappedLabel(
IDS_OPTIONS_DISABLE_SERVICES);
gtk_misc_set_alignment(GTK_MISC(section_description_label), 0, 0);
@@ -557,6 +574,8 @@ PrivacySection::PrivacySection(Profile* profile)
FALSE, FALSE, 0);
g_signal_connect(enable_link_doctor_checkbox_, "clicked",
G_CALLBACK(OnEnableLinkDoctorChange), this);
+ accessible_widget_helper_->SetWidgetName(
+ enable_link_doctor_checkbox_, IDS_OPTIONS_LINKDOCTOR_PREF);
enable_suggest_checkbox_ = CreateCheckButtonWithWrappedLabel(
IDS_OPTIONS_SUGGEST_PREF);
@@ -564,6 +583,8 @@ PrivacySection::PrivacySection(Profile* profile)
FALSE, FALSE, 0);
g_signal_connect(enable_suggest_checkbox_, "clicked",
G_CALLBACK(OnEnableSuggestChange), this);
+ accessible_widget_helper_->SetWidgetName(
+ enable_suggest_checkbox_, IDS_OPTIONS_SUGGEST_PREF);
enable_dns_prefetching_checkbox_ = CreateCheckButtonWithWrappedLabel(
IDS_NETWORK_DNS_PREFETCH_ENABLED_DESCRIPTION);
@@ -571,6 +592,9 @@ PrivacySection::PrivacySection(Profile* profile)
FALSE, FALSE, 0);
g_signal_connect(enable_dns_prefetching_checkbox_, "clicked",
G_CALLBACK(OnDNSPrefetchingChange), this);
+ accessible_widget_helper_->SetWidgetName(
+ enable_dns_prefetching_checkbox_,
+ IDS_NETWORK_DNS_PREFETCH_ENABLED_DESCRIPTION);
enable_safe_browsing_checkbox_ = CreateCheckButtonWithWrappedLabel(
IDS_OPTIONS_SAFEBROWSING_ENABLEPROTECTION);
@@ -578,6 +602,9 @@ PrivacySection::PrivacySection(Profile* profile)
FALSE, FALSE, 0);
g_signal_connect(enable_safe_browsing_checkbox_, "clicked",
G_CALLBACK(OnSafeBrowsingChange), this);
+ accessible_widget_helper_->SetWidgetName(
+ enable_safe_browsing_checkbox_,
+ IDS_OPTIONS_SAFEBROWSING_ENABLEPROTECTION);
#if defined(GOOGLE_CHROME_BUILD)
reporting_enabled_checkbox_ = CreateCheckButtonWithWrappedLabel(
@@ -586,6 +613,8 @@ PrivacySection::PrivacySection(Profile* profile)
FALSE, FALSE, 0);
g_signal_connect(reporting_enabled_checkbox_, "clicked",
G_CALLBACK(OnLoggingChange), this);
+ accessible_widget_helper_->SetWidgetName(
+ reporting_enabled_checkbox_, IDS_OPTIONS_ENABLE_LOGGING);
#endif
GtkWidget* cookie_description_label = gtk_label_new(
@@ -620,6 +649,7 @@ PrivacySection::PrivacySection(Profile* profile)
IDS_OPTIONS_COOKIES_SHOWCOOKIES_WEBSITE_PERMISSIONS).c_str());
g_signal_connect(show_cookies_button, "clicked",
G_CALLBACK(OnShowCookiesButtonClicked), this);
+
// Stick it in an hbox so it doesn't expand to the whole width.
GtkWidget* button_hbox = gtk_hbox_new(FALSE, 0);
gtk_box_pack_start(GTK_BOX(button_hbox), show_cookies_button,
@@ -876,13 +906,19 @@ class SecuritySection : public OptionsPageBase {
// then turning around and saving them again.
bool pref_changing_;
+ scoped_ptr<AccessibleWidgetHelper> accessible_widget_helper_;
+
DISALLOW_COPY_AND_ASSIGN(SecuritySection);
};
SecuritySection::SecuritySection(Profile* profile)
- : OptionsPageBase(profile), pref_changing_(true) {
+ : OptionsPageBase(profile),
+ pref_changing_(true) {
page_ = gtk_vbox_new(FALSE, gtk_util::kControlSpacing);
+ accessible_widget_helper_.reset(new AccessibleWidgetHelper(
+ page_, profile));
+
GtkWidget* manage_certificates_label = CreateWrappedLabel(
IDS_OPTIONS_CERTIFICATES_LABEL);
gtk_misc_set_alignment(GTK_MISC(manage_certificates_label), 0, 0);
@@ -909,13 +945,20 @@ SecuritySection::SecuritySection(Profile* profile)
rev_checking_enabled_checkbox_ = AddCheckButtonWithWrappedLabel(
IDS_OPTIONS_SSL_CHECKREVOCATION, page_,
G_CALLBACK(OnRevCheckingEnabledToggled), this);
+ accessible_widget_helper_->SetWidgetName(
+ rev_checking_enabled_checkbox_, IDS_OPTIONS_SSL_CHECKREVOCATION);
ssl2_enabled_checkbox_ = AddCheckButtonWithWrappedLabel(
IDS_OPTIONS_SSL_USESSL2, page_, G_CALLBACK(OnSSL2EnabledToggled), this);
+ accessible_widget_helper_->SetWidgetName(
+ ssl2_enabled_checkbox_, IDS_OPTIONS_SSL_USESSL2);
ssl3_enabled_checkbox_ = AddCheckButtonWithWrappedLabel(
IDS_OPTIONS_SSL_USESSL3, page_, G_CALLBACK(OnSSL3EnabledToggled), this);
+ accessible_widget_helper_->SetWidgetName(
+ ssl3_enabled_checkbox_, IDS_OPTIONS_SSL_USESSL3);
tls1_enabled_checkbox_ = AddCheckButtonWithWrappedLabel(
IDS_OPTIONS_SSL_USETLS1, page_, G_CALLBACK(OnTLS1EnabledToggled), this);
-
+ accessible_widget_helper_->SetWidgetName(
+ tls1_enabled_checkbox_, IDS_OPTIONS_SSL_USETLS1);
rev_checking_enabled_.Init(prefs::kCertRevocationCheckingEnabled,
profile->GetPrefs(), this);
diff --git a/chrome/browser/gtk/options/content_page_gtk.h b/chrome/browser/gtk/options/content_page_gtk.h
index ba70861..b5ed627a 100644
--- a/chrome/browser/gtk/options/content_page_gtk.h
+++ b/chrome/browser/gtk/options/content_page_gtk.h
@@ -7,9 +7,9 @@
#include <gtk/gtk.h>
-#include "chrome/browser/sync/profile_sync_service.h"
#include "chrome/browser/options_page_base.h"
#include "chrome/browser/profile.h"
+#include "chrome/browser/sync/profile_sync_service.h"
#include "chrome/common/pref_member.h"
class ContentPageGtk : public OptionsPageBase,
diff --git a/chrome/browser/gtk/options/general_page_gtk.cc b/chrome/browser/gtk/options/general_page_gtk.cc
index b491c629..d9ae203 100644
--- a/chrome/browser/gtk/options/general_page_gtk.cc
+++ b/chrome/browser/gtk/options/general_page_gtk.cc
@@ -17,6 +17,7 @@
#include "chrome/browser/session_startup_pref.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/gtk_util.h"
+#include "chrome/common/notification_service.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/pref_service.h"
#include "chrome/common/url_constants.h"
@@ -293,6 +294,7 @@ GtkWidget* GeneralPageGtk::InitHomepageGroup() {
G_CALLBACK(OnNewTabIsHomePageToggled), this);
gtk_box_pack_start(GTK_BOX(homepage_hbox), homepage_use_url_radio_,
FALSE, FALSE, 0);
+
homepage_use_url_entry_ = gtk_entry_new();
g_signal_connect(G_OBJECT(homepage_use_url_entry_), "changed",
G_CALLBACK(OnHomepageUseUrlEntryChanged), this);
@@ -361,6 +363,7 @@ GtkWidget* GeneralPageGtk::InitDefaultBrowserGroup() {
l10n_util::GetStringUTF16(IDS_PRODUCT_NAME)).c_str());
g_signal_connect(G_OBJECT(default_browser_use_as_default_button_), "clicked",
G_CALLBACK(OnBrowserUseAsDefaultClicked), this);
+
gtk_box_pack_start(GTK_BOX(vbox), default_browser_use_as_default_button_,
FALSE, FALSE, 0);
@@ -377,6 +380,7 @@ void GeneralPageGtk::OnStartupRadioToggled(GtkToggleButton* toggle_button,
GeneralPageGtk* general_page) {
if (general_page->initializing_)
return;
+
if (!gtk_toggle_button_get_active(toggle_button)) {
// When selecting a radio button, we get two signals (one for the old radio
// being toggled off, one for the new one being toggled on.) Ignore the
diff --git a/chrome/browser/gtk/options/options_window_gtk.cc b/chrome/browser/gtk/options/options_window_gtk.cc
index 2a12e12..709ee45 100644
--- a/chrome/browser/gtk/options/options_window_gtk.cc
+++ b/chrome/browser/gtk/options/options_window_gtk.cc
@@ -8,15 +8,19 @@
#include "app/l10n_util.h"
#include "base/message_loop.h"
+#include "base/scoped_ptr.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_window.h"
+#include "chrome/browser/gtk/accessible_widget_helper_gtk.h"
#include "chrome/browser/gtk/options/advanced_page_gtk.h"
#include "chrome/browser/gtk/options/content_page_gtk.h"
#include "chrome/browser/gtk/options/general_page_gtk.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/window_sizer.h"
+#include "chrome/common/accessibility_events.h"
#include "chrome/common/gtk_util.h"
+#include "chrome/common/notification_service.h"
#include "chrome/common/pref_member.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/pref_service.h"
@@ -68,6 +72,8 @@ 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_;
+
DISALLOW_COPY_AND_ASSIGN(OptionsWindowGtk);
};
@@ -85,6 +91,7 @@ OptionsWindowGtk::OptionsWindowGtk(Profile* profile)
general_page_(profile_),
content_page_(profile_),
advanced_page_(profile_) {
+
// We don't need to observe changes in this value.
last_selected_page_.Init(prefs::kOptionsWindowLastTabIndex,
g_browser_process->local_state(), NULL);
@@ -105,6 +112,9 @@ OptionsWindowGtk::OptionsWindowGtk(Profile* profile)
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)
@@ -248,10 +258,30 @@ void ShowOptionsWindow(OptionsPage page,
OptionsGroup highlight_group,
Profile* profile) {
DCHECK(profile);
+
// If there's already an existing options window, activate it and switch to
// the specified page.
if (!options_window) {
+ // Creating and initializing a bunch of controls generates a bunch of
+ // spurious events as control values change. Temporarily suppress
+ // accessibility events until the window is created.
+ profile->PauseAccessibilityEvents();
+
+ // Create the options window.
options_window = new OptionsWindowGtk(profile);
+
+ // Resume accessibility events.
+ 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));
}