| Index: chrome/browser/gtk/accessibility_event_router_gtk.cc
|
| ===================================================================
|
| --- chrome/browser/gtk/accessibility_event_router_gtk.cc (revision 71352)
|
| +++ chrome/browser/gtk/accessibility_event_router_gtk.cc (working copy)
|
| @@ -1,658 +0,0 @@
|
| -// 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/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"
|
| -#include "chrome/browser/profiles/profile.h"
|
| -#include "chrome/common/notification_type.h"
|
| -
|
| -#if defined(TOOLKIT_VIEWS)
|
| -#include "views/controls/textfield/gtk_views_textview.h"
|
| -#include "views/controls/textfield/gtk_views_entry.h"
|
| -#include "views/controls/textfield/native_textfield_gtk.h"
|
| -#endif
|
| -
|
| -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<AccessibilityEventRouterGtk*>(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<AccessibilityEventRouterGtk*>(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<AccessibilityEventRouterGtk*>(user_data)->
|
| - DispatchAccessibilityNotification(
|
| - widget, NotificationType::ACCESSIBILITY_CONTROL_ACTION);
|
| - return TRUE;
|
| -}
|
| -
|
| -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));
|
| - // The page hasn't switched yet, so defer calling
|
| - // DispatchAccessibilityNotification.
|
| - reinterpret_cast<AccessibilityEventRouterGtk*>(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<AccessibilityEventRouterGtk*>(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<AccessibilityEventRouterGtk*>(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<AccessibilityEventRouterGtk*>(user_data)->
|
| - PostDispatchAccessibilityNotification(
|
| - widget, NotificationType::ACCESSIBILITY_TEXT_CHANGED);
|
| - return TRUE;
|
| -}
|
| -
|
| -gboolean OnTextBufferChanged(GSignalInvocationHint *ihint,
|
| - guint n_param_values,
|
| - const GValue* param_values,
|
| - gpointer user_data) {
|
| - // The text hasn't changed yet, so defer calling
|
| - // DispatchAccessibilityNotification.
|
| - reinterpret_cast<AccessibilityEventRouterGtk*>(user_data)->
|
| - PostDispatchAccessibilityNotification(
|
| - NULL, NotificationType::ACCESSIBILITY_TEXT_CHANGED);
|
| - return TRUE;
|
| -}
|
| -
|
| -gboolean OnTextViewChanged(GSignalInvocationHint *ihint,
|
| - guint n_param_values,
|
| - const GValue* param_values,
|
| - gpointer user_data) {
|
| - GtkWidget* widget = GTK_WIDGET(g_value_get_object(param_values));
|
| - if (!GTK_IS_TEXT_VIEW(widget)) {
|
| - return TRUE;
|
| - }
|
| - // The text hasn't changed yet, so defer calling
|
| - // DispatchAccessibilityNotification.
|
| - reinterpret_cast<AccessibilityEventRouterGtk*>(user_data)->
|
| - PostDispatchAccessibilityNotification(
|
| - widget, NotificationType::ACCESSIBILITY_TEXT_CHANGED);
|
| - return TRUE;
|
| -}
|
| -
|
| -gboolean OnMenuMoveCurrent(GSignalInvocationHint *ihint,
|
| - guint n_param_values,
|
| - const GValue* param_values,
|
| - gpointer user_data) {
|
| - // Get the widget (the GtkMenu).
|
| - GtkWidget* widget = GTK_WIDGET(g_value_get_object(param_values));
|
| -
|
| - // Moving may move us into or out of a submenu, so after the menu
|
| - // item moves, |widget| may not be valid anymore. To be safe, then,
|
| - // find the topmost ancestor of this menu and post the notification
|
| - // dispatch on that menu. Then the dispatcher will recurse into submenus
|
| - // as necessary to figure out which item is focused.
|
| - while (GTK_MENU_SHELL(widget)->parent_menu_shell)
|
| - widget = GTK_MENU_SHELL(widget)->parent_menu_shell;
|
| -
|
| - // The menu item hasn't moved yet, so we want to defer calling
|
| - // DispatchAccessibilityNotification until after it does.
|
| - reinterpret_cast<AccessibilityEventRouterGtk*>(user_data)->
|
| - PostDispatchAccessibilityNotification(
|
| - widget, NotificationType::ACCESSIBILITY_CONTROL_FOCUSED);
|
| - return TRUE;
|
| -}
|
| -
|
| -} // anonymous namespace
|
| -
|
| -AccessibilityEventRouterGtk::AccessibilityEventRouterGtk()
|
| - : listening_(false),
|
| - most_recent_profile_(NULL),
|
| - most_recent_widget_(NULL),
|
| - method_factory_(this) {
|
| - // We don't want our event listeners to be installed if accessibility is
|
| - // disabled. Install listeners so we can install and uninstall them as
|
| - // needed, then install them now if it's currently enabled.
|
| - ExtensionAccessibilityEventRouter *extension_event_router =
|
| - ExtensionAccessibilityEventRouter::GetInstance();
|
| - extension_event_router->AddOnEnabledListener(
|
| - NewCallback(this,
|
| - &AccessibilityEventRouterGtk::InstallEventListeners));
|
| - extension_event_router->AddOnDisabledListener(
|
| - NewCallback(this,
|
| - &AccessibilityEventRouterGtk::RemoveEventListeners));
|
| - if (extension_event_router->IsAccessibilityEnabled()) {
|
| - InstallEventListeners();
|
| - }
|
| -}
|
| -
|
| -AccessibilityEventRouterGtk::~AccessibilityEventRouterGtk() {
|
| - RemoveEventListeners();
|
| -}
|
| -
|
| -// static
|
| -AccessibilityEventRouterGtk* AccessibilityEventRouterGtk::GetInstance() {
|
| - return Singleton<AccessibilityEventRouterGtk>::get();
|
| -}
|
| -
|
| -void AccessibilityEventRouterGtk::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));
|
| -}
|
| -
|
| -bool AccessibilityEventRouterGtk::IsPassword(GtkWidget* widget) {
|
| - bool is_password = false;
|
| -#if defined (TOOLKIT_VIEWS)
|
| - is_password = (GTK_IS_VIEWS_ENTRY(widget) &&
|
| - GTK_VIEWS_ENTRY(widget)->host != NULL &&
|
| - GTK_VIEWS_ENTRY(widget)->host->IsPassword()) ||
|
| - (GTK_IS_VIEWS_TEXTVIEW(widget) &&
|
| - GTK_VIEWS_TEXTVIEW(widget)->host != NULL &&
|
| - GTK_VIEWS_TEXTVIEW(widget)->host->IsPassword());
|
| -#endif
|
| - return is_password;
|
| -}
|
| -
|
| -
|
| -void AccessibilityEventRouterGtk::InstallEventListeners() {
|
| - // 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()));
|
| - g_object_unref(g_object_ref_sink(gtk_text_view_new()));
|
| - g_object_unref(g_object_ref_sink(gtk_text_buffer_new(NULL)));
|
| -
|
| - // Add signal emission hooks for the events we're interested in.
|
| - InstallEventListener("clicked", GTK_TYPE_BUTTON, OnButtonClicked);
|
| - 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);
|
| - InstallEventListener("move-current", GTK_TYPE_MENU, OnMenuMoveCurrent);
|
| - InstallEventListener("changed", GTK_TYPE_TEXT_BUFFER, OnTextBufferChanged);
|
| - InstallEventListener("move-cursor", GTK_TYPE_TEXT_VIEW, OnTextViewChanged);
|
| -
|
| - listening_ = true;
|
| -}
|
| -
|
| -void AccessibilityEventRouterGtk::RemoveEventListeners() {
|
| - 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 AccessibilityEventRouterGtk::AddRootWidget(
|
| - GtkWidget* root_widget, Profile* profile) {
|
| - root_widget_info_map_[root_widget].refcount++;
|
| - root_widget_info_map_[root_widget].profile = profile;
|
| -}
|
| -
|
| -void AccessibilityEventRouterGtk::RemoveRootWidget(GtkWidget* root_widget) {
|
| - DCHECK(root_widget_info_map_.find(root_widget) !=
|
| - root_widget_info_map_.end());
|
| - root_widget_info_map_[root_widget].refcount--;
|
| - if (root_widget_info_map_[root_widget].refcount == 0) {
|
| - root_widget_info_map_.erase(root_widget);
|
| - }
|
| -}
|
| -
|
| -void AccessibilityEventRouterGtk::AddWidgetNameOverride(
|
| - GtkWidget* widget, std::string name) {
|
| - widget_info_map_[widget].name = name;
|
| - widget_info_map_[widget].refcount++;
|
| -}
|
| -
|
| -void AccessibilityEventRouterGtk::RemoveWidgetNameOverride(GtkWidget* widget) {
|
| - DCHECK(widget_info_map_.find(widget) != widget_info_map_.end());
|
| - widget_info_map_[widget].refcount--;
|
| - if (widget_info_map_[widget].refcount == 0) {
|
| - widget_info_map_.erase(widget);
|
| - }
|
| -}
|
| -
|
| -void AccessibilityEventRouterGtk::FindWidget(
|
| - GtkWidget* widget, Profile** profile, bool* is_accessible) {
|
| - *is_accessible = false;
|
| -
|
| - for (base::hash_map<GtkWidget*, RootWidgetInfo>::const_iterator iter =
|
| - root_widget_info_map_.begin();
|
| - iter != root_widget_info_map_.end();
|
| - ++iter) {
|
| - if (widget == iter->first || gtk_widget_is_ancestor(widget, iter->first)) {
|
| - *is_accessible = true;
|
| - if (profile)
|
| - *profile = iter->second.profile;
|
| - break;
|
| - }
|
| - }
|
| -}
|
| -
|
| -std::string AccessibilityEventRouterGtk::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 AccessibilityEventRouterGtk::StartListening() {
|
| - listening_ = true;
|
| -}
|
| -
|
| -void AccessibilityEventRouterGtk::StopListening() {
|
| - listening_ = false;
|
| -}
|
| -
|
| -void AccessibilityEventRouterGtk::DispatchAccessibilityNotification(
|
| - GtkWidget* widget, NotificationType type) {
|
| - // If there's no message loop, we must be about to shutdown or we're
|
| - // running inside a test; either way, there's no reason to do any
|
| - // further processing.
|
| - if (!MessageLoop::current())
|
| - return;
|
| -
|
| - if (!listening_)
|
| - return;
|
| -
|
| - Profile* profile = NULL;
|
| - bool is_accessible;
|
| -
|
| - // Special case: when we get ACCESSIBILITY_TEXT_CHANGED, we don't get
|
| - // a pointer to the widget, so we try to retrieve it from the most recent
|
| - // widget.
|
| - if (widget == NULL &&
|
| - type == NotificationType::ACCESSIBILITY_TEXT_CHANGED &&
|
| - most_recent_widget_ &&
|
| - GTK_IS_TEXT_VIEW(most_recent_widget_)) {
|
| - widget = most_recent_widget_;
|
| - }
|
| -
|
| - if (!widget)
|
| - return;
|
| -
|
| - most_recent_widget_ = widget;
|
| - FindWidget(widget, &profile, &is_accessible);
|
| - if (profile)
|
| - most_recent_profile_ = profile;
|
| -
|
| - // Special case: a GtkMenu isn't associated with any particular
|
| - // toplevel window, so menu events get routed to the profile of
|
| - // the most recent event that was associated with a window.
|
| - if (GTK_IS_MENU_SHELL(widget) && most_recent_profile_) {
|
| - SendMenuItemNotification(widget, type, most_recent_profile_);
|
| - return;
|
| - }
|
| -
|
| - // In all other cases, return if this widget wasn't marked as accessible.
|
| - if (!is_accessible)
|
| - return;
|
| -
|
| - // The order of these checks matters, because, for example, a radio button
|
| - // 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);
|
| - } else if (GTK_IS_BUTTON(widget)) {
|
| - SendButtonNotification(widget, type, profile);
|
| - } else if (GTK_IS_ENTRY(widget)) {
|
| - SendEntryNotification(widget, type, profile);
|
| - } else if (GTK_IS_TEXT_VIEW(widget)) {
|
| - SendTextViewNotification(widget, type, profile);
|
| - } else if (GTK_IS_NOTEBOOK(widget)) {
|
| - SendTabNotification(widget, type, profile);
|
| - } else if (GTK_IS_TREE_VIEW(widget)) {
|
| - 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(
|
| - &AccessibilityEventRouterGtk::StartListening));
|
| -}
|
| -
|
| -void AccessibilityEventRouterGtk::PostDispatchAccessibilityNotification(
|
| - GtkWidget* widget, NotificationType type) {
|
| - if (!MessageLoop::current())
|
| - return;
|
| -
|
| - MessageLoop::current()->PostTask(
|
| - FROM_HERE, method_factory_.NewRunnableMethod(
|
| - &AccessibilityEventRouterGtk::DispatchAccessibilityNotification,
|
| - widget,
|
| - type));
|
| -}
|
| -
|
| -void AccessibilityEventRouterGtk::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 AccessibilityEventRouterGtk::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 AccessibilityEventRouterGtk::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 AccessibilityEventRouterGtk::SendEntryNotification(
|
| - 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, IsPassword(widget));
|
| - info.SetValue(value, start_pos, end_pos);
|
| - SendAccessibilityNotification(type, &info);
|
| -}
|
| -
|
| -void AccessibilityEventRouterGtk::SendTextViewNotification(
|
| - GtkWidget* widget, NotificationType type, Profile* profile) {
|
| - std::string name = GetWidgetName(widget);
|
| - GtkTextBuffer* buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(widget));
|
| - GtkTextIter start, end;
|
| - gtk_text_buffer_get_bounds(buffer, &start, &end);
|
| - gchar* text = gtk_text_buffer_get_text(buffer, &start, &end, false);
|
| - std::string value = text;
|
| - g_free(text);
|
| - GtkTextIter sel_start, sel_end;
|
| - gtk_text_buffer_get_selection_bounds(buffer, &sel_start, &sel_end);
|
| - int start_pos = gtk_text_iter_get_offset(&sel_start);
|
| - int end_pos = gtk_text_iter_get_offset(&sel_end);
|
| - AccessibilityTextBoxInfo info(profile, name, IsPassword(widget));
|
| - info.SetValue(value, start_pos, end_pos);
|
| - SendAccessibilityNotification(type, &info);
|
| -}
|
| -
|
| -void AccessibilityEventRouterGtk::SendTabNotification(
|
| - GtkWidget* widget, NotificationType type, Profile* profile) {
|
| - int index = gtk_notebook_get_current_page(GTK_NOTEBOOK(widget));
|
| - 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);
|
| -}
|
| -
|
| -void AccessibilityEventRouterGtk::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 AccessibilityEventRouterGtk::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);
|
| -}
|
| -
|
| -void AccessibilityEventRouterGtk::SendMenuItemNotification(
|
| - GtkWidget* menu, NotificationType type, Profile* profile) {
|
| - // Find the focused menu item, recursing into submenus as needed.
|
| - 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
|
| -
|
| - // Send the event.
|
| - AccessibilityMenuItemInfo info(profile, name, submenu != NULL, index, count);
|
| - SendAccessibilityNotification(type, &info);
|
| -}
|
|
|