Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(759)

Side by Side Diff: chrome/browser/gtk/accessibility_event_router_gtk.cc

Issue 1585011: Add menu and menu item events to the accessibility extension api, and... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 10 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/gtk/accessibility_event_router_gtk.h" 5 #include "chrome/browser/gtk/accessibility_event_router_gtk.h"
6 6
7 #include "base/basictypes.h" 7 #include "base/basictypes.h"
8 #include "base/callback.h" 8 #include "base/callback.h"
9 #include "base/message_loop.h" 9 #include "base/message_loop.h"
10 #include "base/stl_util-inl.h" 10 #include "base/stl_util-inl.h"
11 #include "chrome/browser/extensions/extension_accessibility_api.h" 11 #include "chrome/browser/extensions/extension_accessibility_api.h"
12 #include "chrome/browser/gtk/gtk_chrome_link_button.h" 12 #include "chrome/browser/gtk/gtk_chrome_link_button.h"
13 #include "chrome/browser/profile.h" 13 #include "chrome/browser/profile.h"
14 #include "chrome/common/notification_type.h" 14 #include "chrome/common/notification_type.h"
15 15
16 namespace { 16 namespace {
17 17
18 // 18 //
19 // Callbacks triggered by signals on gtk widgets. 19 // Callbacks triggered by signals on gtk widgets.
20 // 20 //
21 21
22 gboolean OnWidgetFocused(GSignalInvocationHint *ihint, 22 gboolean OnWidgetFocused(GSignalInvocationHint *ihint,
23 guint n_param_values, 23 guint n_param_values,
24 const GValue* param_values, 24 const GValue* param_values,
25 gpointer user_data) { 25 gpointer user_data) {
26 GtkWidget* widget = GTK_WIDGET(g_value_get_object(param_values)); 26 GtkWidget* widget = GTK_WIDGET(g_value_get_object(param_values));
27 reinterpret_cast<AccessibilityEventRouter *>(user_data)-> 27 reinterpret_cast<AccessibilityEventRouterGtk*>(user_data)->
28 DispatchAccessibilityNotification( 28 DispatchAccessibilityNotification(
29 widget, NotificationType::ACCESSIBILITY_CONTROL_FOCUSED); 29 widget, NotificationType::ACCESSIBILITY_CONTROL_FOCUSED);
30 return true; 30 return TRUE;
31 } 31 }
32 32
33 gboolean OnButtonClicked(GSignalInvocationHint *ihint, 33 gboolean OnButtonClicked(GSignalInvocationHint *ihint,
34 guint n_param_values, 34 guint n_param_values,
35 const GValue* param_values, 35 const GValue* param_values,
36 gpointer user_data) { 36 gpointer user_data) {
37 GtkWidget* widget = GTK_WIDGET(g_value_get_object(param_values)); 37 GtkWidget* widget = GTK_WIDGET(g_value_get_object(param_values));
38 // Skip toggle buttons because we're also listening on "toggle" events. 38 // Skip toggle buttons because we're also listening on "toggle" events.
39 if (GTK_IS_TOGGLE_BUTTON(widget)) 39 if (GTK_IS_TOGGLE_BUTTON(widget))
40 return true; 40 return true;
41 reinterpret_cast<AccessibilityEventRouter *>(user_data)-> 41 reinterpret_cast<AccessibilityEventRouterGtk*>(user_data)->
42 DispatchAccessibilityNotification( 42 DispatchAccessibilityNotification(
43 widget, NotificationType::ACCESSIBILITY_CONTROL_ACTION); 43 widget, NotificationType::ACCESSIBILITY_CONTROL_ACTION);
44 return true; 44 return TRUE;
45 } 45 }
46 46
47 gboolean OnButtonToggled(GSignalInvocationHint *ihint, 47 gboolean OnButtonToggled(GSignalInvocationHint *ihint,
48 guint n_param_values, 48 guint n_param_values,
49 const GValue* param_values, 49 const GValue* param_values,
50 gpointer user_data) { 50 gpointer user_data) {
51 GtkWidget* widget = GTK_WIDGET(g_value_get_object(param_values)); 51 GtkWidget* widget = GTK_WIDGET(g_value_get_object(param_values));
52 bool checked = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)); 52 bool checked = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
53 // Skip propagating an "uncheck" event for a radio button because it's 53 // Skip propagating an "uncheck" event for a radio button because it's
54 // redundant; there will always be a corresponding "check" event for 54 // redundant; there will always be a corresponding "check" event for
55 // a different radio button the group. 55 // a different radio button the group.
56 if (GTK_IS_RADIO_BUTTON(widget) && !checked) 56 if (GTK_IS_RADIO_BUTTON(widget) && !checked)
57 return true; 57 return true;
58 reinterpret_cast<AccessibilityEventRouter *>(user_data)-> 58 reinterpret_cast<AccessibilityEventRouterGtk*>(user_data)->
59 DispatchAccessibilityNotification( 59 DispatchAccessibilityNotification(
60 widget, NotificationType::ACCESSIBILITY_CONTROL_ACTION); 60 widget, NotificationType::ACCESSIBILITY_CONTROL_ACTION);
61 return true; 61 return TRUE;
62 } 62 }
63 63
64 gboolean OnPageSwitched(GSignalInvocationHint *ihint, 64 gboolean OnPageSwitched(GSignalInvocationHint *ihint,
65 guint n_param_values, 65 guint n_param_values,
66 const GValue* param_values, 66 const GValue* param_values,
67 gpointer user_data) { 67 gpointer user_data) {
68 GtkWidget* widget = GTK_WIDGET(g_value_get_object(param_values)); 68 GtkWidget* widget = GTK_WIDGET(g_value_get_object(param_values));
69 // The page hasn't switched yet, so defer calling 69 // The page hasn't switched yet, so defer calling
70 // DispatchAccessibilityNotification. 70 // DispatchAccessibilityNotification.
71 reinterpret_cast<AccessibilityEventRouter *>(user_data)-> 71 reinterpret_cast<AccessibilityEventRouterGtk*>(user_data)->
72 PostDispatchAccessibilityNotification( 72 PostDispatchAccessibilityNotification(
73 widget, NotificationType::ACCESSIBILITY_CONTROL_ACTION); 73 widget, NotificationType::ACCESSIBILITY_CONTROL_ACTION);
74 return true; 74 return TRUE;
75 } 75 }
76 76
77 gboolean OnComboBoxChanged(GSignalInvocationHint *ihint, 77 gboolean OnComboBoxChanged(GSignalInvocationHint *ihint,
78 guint n_param_values, 78 guint n_param_values,
79 const GValue* param_values, 79 const GValue* param_values,
80 gpointer user_data) { 80 gpointer user_data) {
81 GtkWidget* widget = GTK_WIDGET(g_value_get_object(param_values)); 81 GtkWidget* widget = GTK_WIDGET(g_value_get_object(param_values));
82 if (!GTK_IS_COMBO_BOX(widget)) 82 if (!GTK_IS_COMBO_BOX(widget))
83 return true; 83 return true;
84 reinterpret_cast<AccessibilityEventRouter *>(user_data)-> 84 reinterpret_cast<AccessibilityEventRouterGtk*>(user_data)->
85 DispatchAccessibilityNotification( 85 DispatchAccessibilityNotification(
86 widget, NotificationType::ACCESSIBILITY_CONTROL_ACTION); 86 widget, NotificationType::ACCESSIBILITY_CONTROL_ACTION);
87 return true; 87 return TRUE;
88 } 88 }
89 89
90 gboolean OnTreeViewCursorChanged(GSignalInvocationHint *ihint, 90 gboolean OnTreeViewCursorChanged(GSignalInvocationHint *ihint,
91 guint n_param_values, 91 guint n_param_values,
92 const GValue* param_values, 92 const GValue* param_values,
93 gpointer user_data) { 93 gpointer user_data) {
94 GtkWidget* widget = GTK_WIDGET(g_value_get_object(param_values)); 94 GtkWidget* widget = GTK_WIDGET(g_value_get_object(param_values));
95 if (!GTK_IS_TREE_VIEW(widget)) { 95 if (!GTK_IS_TREE_VIEW(widget)) {
96 return true; 96 return true;
97 } 97 }
98 reinterpret_cast<AccessibilityEventRouter *>(user_data)-> 98 reinterpret_cast<AccessibilityEventRouterGtk*>(user_data)->
99 DispatchAccessibilityNotification( 99 DispatchAccessibilityNotification(
100 widget, NotificationType::ACCESSIBILITY_CONTROL_ACTION); 100 widget, NotificationType::ACCESSIBILITY_CONTROL_ACTION);
101 return true; 101 return TRUE;
102 } 102 }
103 103
104 gboolean OnEntryChanged(GSignalInvocationHint *ihint, 104 gboolean OnEntryChanged(GSignalInvocationHint *ihint,
105 guint n_param_values, 105 guint n_param_values,
106 const GValue* param_values, 106 const GValue* param_values,
107 gpointer user_data) { 107 gpointer user_data) {
108 GtkWidget* widget = GTK_WIDGET(g_value_get_object(param_values)); 108 GtkWidget* widget = GTK_WIDGET(g_value_get_object(param_values));
109 if (!GTK_IS_ENTRY(widget)) { 109 if (!GTK_IS_ENTRY(widget)) {
110 return true; 110 return TRUE;
111 } 111 }
112 // The text hasn't changed yet, so defer calling 112 // The text hasn't changed yet, so defer calling
113 // DispatchAccessibilityNotification. 113 // DispatchAccessibilityNotification.
114 reinterpret_cast<AccessibilityEventRouter *>(user_data)-> 114 reinterpret_cast<AccessibilityEventRouterGtk*>(user_data)->
115 PostDispatchAccessibilityNotification( 115 PostDispatchAccessibilityNotification(
116 widget, NotificationType::ACCESSIBILITY_TEXT_CHANGED); 116 widget, NotificationType::ACCESSIBILITY_TEXT_CHANGED);
117 return true; 117 return TRUE;
118 }
119
120 gboolean OnMenuMoveCurrent(GSignalInvocationHint *ihint,
121 guint n_param_values,
122 const GValue* param_values,
123 gpointer user_data) {
124 // Get the widget (the GtkMenu).
125 GtkWidget* widget = GTK_WIDGET(g_value_get_object(param_values));
126
127 // Moving may move us into or out of a submenu, so after the menu
128 // item moves, |widget| may not be valid anymore. To be safe, then,
129 // find the topmost ancestor of this menu and post the notification
130 // dispatch on that menu. Then the dispatcher will recurse into submenus
131 // as necessary to figure out which item is focused.
132 while (GTK_MENU_SHELL(widget)->parent_menu_shell)
133 widget = GTK_MENU_SHELL(widget)->parent_menu_shell;
134
135 // The menu item hasn't moved yet, so we want to defer calling
136 // DispatchAccessibilityNotification until after it does.
137 reinterpret_cast<AccessibilityEventRouterGtk*>(user_data)->
138 PostDispatchAccessibilityNotification(
139 widget, NotificationType::ACCESSIBILITY_CONTROL_FOCUSED);
140 return TRUE;
118 } 141 }
119 142
120 } // anonymous namespace 143 } // anonymous namespace
121 144
122 AccessibilityEventRouter::AccessibilityEventRouter() 145 AccessibilityEventRouterGtk::AccessibilityEventRouterGtk()
123 : method_factory_(this) { 146 : listening_(false),
147 most_recent_profile_(NULL),
148 method_factory_(this) {
124 // We don't want our event listeners to be installed if accessibility is 149 // We don't want our event listeners to be installed if accessibility is
125 // disabled. Install listeners so we can install and uninstall them as 150 // disabled. Install listeners so we can install and uninstall them as
126 // needed, then install them now if it's currently enabled. 151 // needed, then install them now if it's currently enabled.
127 ExtensionAccessibilityEventRouter *accessibility_event_router = 152 ExtensionAccessibilityEventRouter *extension_event_router =
128 ExtensionAccessibilityEventRouter::GetInstance(); 153 ExtensionAccessibilityEventRouter::GetInstance();
129 accessibility_event_router->AddOnEnabledListener( 154 extension_event_router->AddOnEnabledListener(
130 NewCallback(this, 155 NewCallback(this,
131 &AccessibilityEventRouter::InstallEventListeners)); 156 &AccessibilityEventRouterGtk::InstallEventListeners));
132 accessibility_event_router->AddOnDisabledListener( 157 extension_event_router->AddOnDisabledListener(
133 NewCallback(this, 158 NewCallback(this,
134 &AccessibilityEventRouter::RemoveEventListeners)); 159 &AccessibilityEventRouterGtk::RemoveEventListeners));
135 if (accessibility_event_router->IsAccessibilityEnabled()) { 160 if (extension_event_router->IsAccessibilityEnabled()) {
136 InstallEventListeners(); 161 InstallEventListeners();
137 } 162 }
138 } 163 }
139 164
140 AccessibilityEventRouter::~AccessibilityEventRouter() { 165 AccessibilityEventRouterGtk::~AccessibilityEventRouterGtk() {
141 RemoveEventListeners(); 166 RemoveEventListeners();
142 } 167 }
143 168
144 // static 169 // static
145 AccessibilityEventRouter* AccessibilityEventRouter::GetInstance() { 170 AccessibilityEventRouterGtk* AccessibilityEventRouterGtk::GetInstance() {
146 return Singleton<AccessibilityEventRouter>::get(); 171 return Singleton<AccessibilityEventRouterGtk>::get();
147 } 172 }
148 173
149 void AccessibilityEventRouter::InstallEventListener( 174 void AccessibilityEventRouterGtk::InstallEventListener(
150 const char* signal_name, 175 const char* signal_name,
151 GType widget_type, 176 GType widget_type,
152 GSignalEmissionHook hook_func) { 177 GSignalEmissionHook hook_func) {
153 guint signal_id = g_signal_lookup(signal_name, widget_type); 178 guint signal_id = g_signal_lookup(signal_name, widget_type);
154 gulong hook_id = g_signal_add_emission_hook( 179 gulong hook_id = g_signal_add_emission_hook(
155 signal_id, 0, hook_func, reinterpret_cast<gpointer>(this), NULL); 180 signal_id, 0, hook_func, reinterpret_cast<gpointer>(this), NULL);
156 installed_hooks_.push_back(InstalledHook(signal_id, hook_id)); 181 installed_hooks_.push_back(InstalledHook(signal_id, hook_id));
157 } 182 }
158 183
159 void AccessibilityEventRouter::InstallEventListeners() { 184 void AccessibilityEventRouterGtk::InstallEventListeners() {
160 // Create and destroy each type of widget we need signals for, 185 // Create and destroy each type of widget we need signals for,
161 // to ensure their modules are loaded, otherwise g_signal_lookup 186 // to ensure their modules are loaded, otherwise g_signal_lookup
162 // might fail. 187 // might fail.
163 g_object_unref(g_object_ref_sink(gtk_combo_box_new())); 188 g_object_unref(g_object_ref_sink(gtk_combo_box_new()));
164 g_object_unref(g_object_ref_sink(gtk_entry_new())); 189 g_object_unref(g_object_ref_sink(gtk_entry_new()));
165 g_object_unref(g_object_ref_sink(gtk_notebook_new())); 190 g_object_unref(g_object_ref_sink(gtk_notebook_new()));
166 g_object_unref(g_object_ref_sink(gtk_toggle_button_new())); 191 g_object_unref(g_object_ref_sink(gtk_toggle_button_new()));
167 g_object_unref(g_object_ref_sink(gtk_tree_view_new())); 192 g_object_unref(g_object_ref_sink(gtk_tree_view_new()));
168 193
169 // Add signal emission hooks for the events we're interested in. 194 // Add signal emission hooks for the events we're interested in.
170 InstallEventListener("clicked", GTK_TYPE_BUTTON, OnButtonClicked); 195 InstallEventListener("clicked", GTK_TYPE_BUTTON, OnButtonClicked);
171 InstallEventListener("changed", GTK_TYPE_COMBO_BOX, OnComboBoxChanged); 196 InstallEventListener("changed", GTK_TYPE_COMBO_BOX, OnComboBoxChanged);
172 InstallEventListener("cursor-changed", GTK_TYPE_TREE_VIEW, 197 InstallEventListener("cursor-changed", GTK_TYPE_TREE_VIEW,
173 OnTreeViewCursorChanged); 198 OnTreeViewCursorChanged);
174 InstallEventListener("changed", GTK_TYPE_ENTRY, OnEntryChanged); 199 InstallEventListener("changed", GTK_TYPE_ENTRY, OnEntryChanged);
175 InstallEventListener("insert-text", GTK_TYPE_ENTRY, OnEntryChanged); 200 InstallEventListener("insert-text", GTK_TYPE_ENTRY, OnEntryChanged);
176 InstallEventListener("delete-text", GTK_TYPE_ENTRY, OnEntryChanged); 201 InstallEventListener("delete-text", GTK_TYPE_ENTRY, OnEntryChanged);
177 InstallEventListener("move-cursor", GTK_TYPE_ENTRY, OnEntryChanged); 202 InstallEventListener("move-cursor", GTK_TYPE_ENTRY, OnEntryChanged);
178 InstallEventListener("focus-in-event", GTK_TYPE_WIDGET, OnWidgetFocused); 203 InstallEventListener("focus-in-event", GTK_TYPE_WIDGET, OnWidgetFocused);
179 InstallEventListener("switch-page", GTK_TYPE_NOTEBOOK, OnPageSwitched); 204 InstallEventListener("switch-page", GTK_TYPE_NOTEBOOK, OnPageSwitched);
180 InstallEventListener("toggled", GTK_TYPE_TOGGLE_BUTTON, OnButtonToggled); 205 InstallEventListener("toggled", GTK_TYPE_TOGGLE_BUTTON, OnButtonToggled);
206 InstallEventListener("move-current", GTK_TYPE_MENU, OnMenuMoveCurrent);
181 207
182 listening_ = true; 208 listening_ = true;
183 } 209 }
184 210
185 void AccessibilityEventRouter::RemoveEventListeners() { 211 void AccessibilityEventRouterGtk::RemoveEventListeners() {
186 for (size_t i = 0; i < installed_hooks_.size(); i++) { 212 for (size_t i = 0; i < installed_hooks_.size(); i++) {
187 g_signal_remove_emission_hook( 213 g_signal_remove_emission_hook(
188 installed_hooks_[i].signal_id, 214 installed_hooks_[i].signal_id,
189 installed_hooks_[i].hook_id); 215 installed_hooks_[i].hook_id);
190 } 216 }
191 installed_hooks_.clear(); 217 installed_hooks_.clear();
192 218
193 listening_ = false; 219 listening_ = false;
194 } 220 }
195 221
196 void AccessibilityEventRouter::AddRootWidget( 222 void AccessibilityEventRouterGtk::AddRootWidget(
197 GtkWidget* root_widget, Profile* profile) { 223 GtkWidget* root_widget, Profile* profile) {
198 root_widget_profile_map_[root_widget] = profile; 224 root_widget_profile_map_[root_widget] = profile;
199 } 225 }
200 226
201 void AccessibilityEventRouter::RemoveRootWidget(GtkWidget* root_widget) { 227 void AccessibilityEventRouterGtk::RemoveRootWidget(GtkWidget* root_widget) {
202 DCHECK(root_widget_profile_map_.find(root_widget) != 228 DCHECK(root_widget_profile_map_.find(root_widget) !=
203 root_widget_profile_map_.end()); 229 root_widget_profile_map_.end());
204 root_widget_profile_map_.erase(root_widget); 230 root_widget_profile_map_.erase(root_widget);
205 } 231 }
206 232
207 void AccessibilityEventRouter::IgnoreWidget(GtkWidget* widget) { 233 void AccessibilityEventRouterGtk::IgnoreWidget(GtkWidget* widget) {
208 widget_info_map_[widget].ignore = true; 234 widget_info_map_[widget].ignore = true;
209 } 235 }
210 236
211 void AccessibilityEventRouter::SetWidgetName( 237 void AccessibilityEventRouterGtk::SetWidgetName(
212 GtkWidget* widget, std::string name) { 238 GtkWidget* widget, std::string name) {
213 widget_info_map_[widget].name = name; 239 widget_info_map_[widget].name = name;
214 } 240 }
215 241
216 void AccessibilityEventRouter::RemoveWidget(GtkWidget* widget) { 242 void AccessibilityEventRouterGtk::RemoveWidget(GtkWidget* widget) {
217 DCHECK(widget_info_map_.find(widget) != widget_info_map_.end()); 243 DCHECK(widget_info_map_.find(widget) != widget_info_map_.end());
218 widget_info_map_.erase(widget); 244 widget_info_map_.erase(widget);
219 } 245 }
220 246
221 bool AccessibilityEventRouter::IsWidgetAccessible( 247 void AccessibilityEventRouterGtk::FindWidget(
222 GtkWidget* widget, Profile** profile) { 248 GtkWidget* widget, Profile** profile, bool* is_accessible) {
249 *is_accessible = false;
250
223 // First see if it's a descendant of a root widget. 251 // First see if it's a descendant of a root widget.
224 bool is_accessible = false;
225 for (base::hash_map<GtkWidget*, Profile*>::const_iterator iter = 252 for (base::hash_map<GtkWidget*, Profile*>::const_iterator iter =
226 root_widget_profile_map_.begin(); 253 root_widget_profile_map_.begin();
227 iter != root_widget_profile_map_.end(); 254 iter != root_widget_profile_map_.end();
228 ++iter) { 255 ++iter) {
229 if (gtk_widget_is_ancestor(widget, iter->first)) { 256 if (gtk_widget_is_ancestor(widget, iter->first)) {
230 is_accessible = true; 257 *is_accessible = true;
231 if (profile) 258 if (profile)
232 *profile = iter->second; 259 *profile = iter->second;
233 break; 260 break;
234 } 261 }
235 } 262 }
236 if (!is_accessible) 263 if (!*is_accessible)
237 return false; 264 return;
238 265
239 // Now make sure it's not marked as a widget to be ignored. 266 // Now make sure it's not marked as a widget to be ignored.
240 base::hash_map<GtkWidget*, WidgetInfo>::const_iterator iter = 267 base::hash_map<GtkWidget*, WidgetInfo>::const_iterator iter =
241 widget_info_map_.find(widget); 268 widget_info_map_.find(widget);
242 if (iter != widget_info_map_.end() && iter->second.ignore) { 269 if (iter != widget_info_map_.end() && iter->second.ignore) {
243 is_accessible = false; 270 *is_accessible = false;
271 return;
244 } 272 }
245
246 return is_accessible;
247 } 273 }
248 274
249 std::string AccessibilityEventRouter::GetWidgetName(GtkWidget* widget) { 275 std::string AccessibilityEventRouterGtk::GetWidgetName(GtkWidget* widget) {
250 base::hash_map<GtkWidget*, WidgetInfo>::const_iterator iter = 276 base::hash_map<GtkWidget*, WidgetInfo>::const_iterator iter =
251 widget_info_map_.find(widget); 277 widget_info_map_.find(widget);
252 if (iter != widget_info_map_.end()) { 278 if (iter != widget_info_map_.end()) {
253 return iter->second.name; 279 return iter->second.name;
254 } else { 280 } else {
255 return ""; 281 return "";
256 } 282 }
257 } 283 }
258 284
259 void AccessibilityEventRouter::StartListening() { 285 void AccessibilityEventRouterGtk::StartListening() {
260 listening_ = true; 286 listening_ = true;
261 } 287 }
262 288
263 void AccessibilityEventRouter::StopListening() { 289 void AccessibilityEventRouterGtk::StopListening() {
264 listening_ = false; 290 listening_ = false;
265 } 291 }
266 292
267 void AccessibilityEventRouter::DispatchAccessibilityNotification( 293 void AccessibilityEventRouterGtk::DispatchAccessibilityNotification(
268 GtkWidget* widget, NotificationType type) { 294 GtkWidget* widget, NotificationType type) {
269 if (!listening_) 295 if (!listening_)
270 return; 296 return;
271 Profile *profile; 297
272 if (!IsWidgetAccessible(widget, &profile)) 298 Profile* profile = NULL;
299 bool is_accessible;
300 FindWidget(widget, &profile, &is_accessible);
301 if (profile)
302 most_recent_profile_ = profile;
303
304 // Special case: a GtkMenu isn't associated with any particular
305 // toplevel window, so menu events get routed to the profile of
306 // the most recent event that was associated with a window.
307 if (GTK_IS_MENU_SHELL(widget) && most_recent_profile_) {
308 SendMenuItemNotification(widget, type, most_recent_profile_);
309 return;
310 }
311
312 // In all other cases, return if this widget wasn't marked as accessible.
313 if (!is_accessible)
273 return; 314 return;
274 315
275 // The order of these checks matters, because, for example, a radio button 316 // The order of these checks matters, because, for example, a radio button
276 // is a subclass of button, and a combo box is a composite control where 317 // is a subclass of button, and a combo box is a composite control where
277 // the focus event goes to the button that's a child of the combo box. 318 // the focus event goes to the button that's a child of the combo box.
278 GtkWidget* parent = gtk_widget_get_parent(widget); 319 GtkWidget* parent = gtk_widget_get_parent(widget);
279 if (parent && GTK_IS_BUTTON(widget) && GTK_IS_TREE_VIEW(parent)) { 320 if (parent && GTK_IS_BUTTON(widget) && GTK_IS_TREE_VIEW(parent)) {
280 // This is a list box column header. Currently not supported. 321 // This is a list box column header. Currently not supported.
281 return; 322 return;
282 } else if (GTK_IS_COMBO_BOX(widget)) { 323 } else if (GTK_IS_COMBO_BOX(widget)) {
(...skipping 19 matching lines...) Expand all
302 } 343 }
303 344
304 // After this method returns, additional signal handlers will run, 345 // After this method returns, additional signal handlers will run,
305 // which will sometimes generate additional signals. To avoid 346 // which will sometimes generate additional signals. To avoid
306 // generating redundant accessibility notifications for the same 347 // generating redundant accessibility notifications for the same
307 // initial event, stop listening to all signals generated from now 348 // initial event, stop listening to all signals generated from now
308 // until this posted task runs. 349 // until this posted task runs.
309 StopListening(); 350 StopListening();
310 MessageLoop::current()->PostTask( 351 MessageLoop::current()->PostTask(
311 FROM_HERE, method_factory_.NewRunnableMethod( 352 FROM_HERE, method_factory_.NewRunnableMethod(
312 &AccessibilityEventRouter::StartListening)); 353 &AccessibilityEventRouterGtk::StartListening));
313 } 354 }
314 355
315 void AccessibilityEventRouter::PostDispatchAccessibilityNotification( 356 void AccessibilityEventRouterGtk::PostDispatchAccessibilityNotification(
316 GtkWidget* widget, NotificationType type) { 357 GtkWidget* widget, NotificationType type) {
317 MessageLoop::current()->PostTask( 358 MessageLoop::current()->PostTask(
318 FROM_HERE, method_factory_.NewRunnableMethod( 359 FROM_HERE, method_factory_.NewRunnableMethod(
319 &AccessibilityEventRouter::DispatchAccessibilityNotification, 360 &AccessibilityEventRouterGtk::DispatchAccessibilityNotification,
320 widget, 361 widget,
321 type)); 362 type));
322 } 363 }
323 364
324 void AccessibilityEventRouter::SendRadioButtonNotification( 365 void AccessibilityEventRouterGtk::SendRadioButtonNotification(
325 GtkWidget* widget, NotificationType type, Profile* profile) { 366 GtkWidget* widget, NotificationType type, Profile* profile) {
326 // Get the radio button name 367 // Get the radio button name
327 std::string button_name = GetWidgetName(widget); 368 std::string button_name = GetWidgetName(widget);
328 if (button_name.empty() && gtk_button_get_label(GTK_BUTTON(widget))) 369 if (button_name.empty() && gtk_button_get_label(GTK_BUTTON(widget)))
329 button_name = gtk_button_get_label(GTK_BUTTON(widget)); 370 button_name = gtk_button_get_label(GTK_BUTTON(widget));
330 371
331 // Get its state 372 // Get its state
332 bool checked = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)); 373 bool checked = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
333 374
334 // Get the index of this radio button and the total number of 375 // Get the index of this radio button and the total number of
335 // radio buttons in the group. 376 // radio buttons in the group.
336 int item_count = 0; 377 int item_count = 0;
337 int item_index = -1; 378 int item_index = -1;
338 for (GSList* group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(widget)); 379 for (GSList* group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(widget));
339 group; 380 group;
340 group = group->next) { 381 group = group->next) {
341 if (group->data == widget) { 382 if (group->data == widget) {
342 item_index = item_count; 383 item_index = item_count;
343 } 384 }
344 item_count++; 385 item_count++;
345 } 386 }
346 item_index = item_count - 1 - item_index; 387 item_index = item_count - 1 - item_index;
347 388
348 AccessibilityRadioButtonInfo info( 389 AccessibilityRadioButtonInfo info(
349 profile, button_name, checked, item_index, item_count); 390 profile, button_name, checked, item_index, item_count);
350 SendAccessibilityNotification(type, &info); 391 SendAccessibilityNotification(type, &info);
351 } 392 }
352 393
353 void AccessibilityEventRouter::SendCheckboxNotification( 394 void AccessibilityEventRouterGtk::SendCheckboxNotification(
354 GtkWidget* widget, NotificationType type, Profile* profile) { 395 GtkWidget* widget, NotificationType type, Profile* profile) {
355 std::string button_name = GetWidgetName(widget); 396 std::string button_name = GetWidgetName(widget);
356 if (button_name.empty() && gtk_button_get_label(GTK_BUTTON(widget))) 397 if (button_name.empty() && gtk_button_get_label(GTK_BUTTON(widget)))
357 button_name = gtk_button_get_label(GTK_BUTTON(widget)); 398 button_name = gtk_button_get_label(GTK_BUTTON(widget));
358 bool checked = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)); 399 bool checked = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
359 AccessibilityCheckboxInfo info(profile, button_name, checked); 400 AccessibilityCheckboxInfo info(profile, button_name, checked);
360 SendAccessibilityNotification(type, &info); 401 SendAccessibilityNotification(type, &info);
361 } 402 }
362 403
363 void AccessibilityEventRouter::SendButtonNotification( 404 void AccessibilityEventRouterGtk::SendButtonNotification(
364 GtkWidget* widget, NotificationType type, Profile* profile) { 405 GtkWidget* widget, NotificationType type, Profile* profile) {
365 std::string button_name = GetWidgetName(widget); 406 std::string button_name = GetWidgetName(widget);
366 if (button_name.empty() && gtk_button_get_label(GTK_BUTTON(widget))) 407 if (button_name.empty() && gtk_button_get_label(GTK_BUTTON(widget)))
367 button_name = gtk_button_get_label(GTK_BUTTON(widget)); 408 button_name = gtk_button_get_label(GTK_BUTTON(widget));
368 AccessibilityButtonInfo info(profile, button_name); 409 AccessibilityButtonInfo info(profile, button_name);
369 SendAccessibilityNotification(type, &info); 410 SendAccessibilityNotification(type, &info);
370 } 411 }
371 412
372 void AccessibilityEventRouter::SendTextBoxNotification( 413 void AccessibilityEventRouterGtk::SendTextBoxNotification(
373 GtkWidget* widget, NotificationType type, Profile* profile) { 414 GtkWidget* widget, NotificationType type, Profile* profile) {
374 std::string name = GetWidgetName(widget); 415 std::string name = GetWidgetName(widget);
375 std::string value = gtk_entry_get_text(GTK_ENTRY(widget)); 416 std::string value = gtk_entry_get_text(GTK_ENTRY(widget));
376 gint start_pos; 417 gint start_pos;
377 gint end_pos; 418 gint end_pos;
378 gtk_editable_get_selection_bounds(GTK_EDITABLE(widget), &start_pos, &end_pos); 419 gtk_editable_get_selection_bounds(GTK_EDITABLE(widget), &start_pos, &end_pos);
379 AccessibilityTextBoxInfo info(profile, name, false); 420 AccessibilityTextBoxInfo info(profile, name, false);
380 info.SetValue(value, start_pos, end_pos); 421 info.SetValue(value, start_pos, end_pos);
381 SendAccessibilityNotification(type, &info); 422 SendAccessibilityNotification(type, &info);
382 } 423 }
383 424
384 void AccessibilityEventRouter::SendTabNotification( 425 void AccessibilityEventRouterGtk::SendTabNotification(
385 GtkWidget* widget, NotificationType type, Profile* profile) { 426 GtkWidget* widget, NotificationType type, Profile* profile) {
386 int index = gtk_notebook_get_current_page(GTK_NOTEBOOK(widget)); 427 int index = gtk_notebook_get_current_page(GTK_NOTEBOOK(widget));
387 int page_count = gtk_notebook_get_n_pages(GTK_NOTEBOOK(widget)); 428 int page_count = gtk_notebook_get_n_pages(GTK_NOTEBOOK(widget));
388 GtkWidget* page = gtk_notebook_get_nth_page(GTK_NOTEBOOK(widget), index); 429 GtkWidget* page = gtk_notebook_get_nth_page(GTK_NOTEBOOK(widget), index);
389 GtkWidget* label = gtk_notebook_get_tab_label(GTK_NOTEBOOK(widget), page); 430 GtkWidget* label = gtk_notebook_get_tab_label(GTK_NOTEBOOK(widget), page);
390 std::string name = GetWidgetName(widget); 431 std::string name = GetWidgetName(widget);
391 if (name.empty() && gtk_label_get_text(GTK_LABEL(label))) { 432 if (name.empty() && gtk_label_get_text(GTK_LABEL(label))) {
392 name = gtk_label_get_text(GTK_LABEL(label)); 433 name = gtk_label_get_text(GTK_LABEL(label));
393 } 434 }
394 AccessibilityTabInfo info(profile, name, index, page_count); 435 AccessibilityTabInfo info(profile, name, index, page_count);
395 SendAccessibilityNotification(type, &info); 436 SendAccessibilityNotification(type, &info);
396 } 437 }
397 438
398 void AccessibilityEventRouter::SendComboBoxNotification( 439 void AccessibilityEventRouterGtk::SendComboBoxNotification(
399 GtkWidget* widget, NotificationType type, Profile* profile) { 440 GtkWidget* widget, NotificationType type, Profile* profile) {
400 // Get the index of the selected item. Will return -1 if no item is 441 // Get the index of the selected item. Will return -1 if no item is
401 // active, which matches the semantics of the extension API. 442 // active, which matches the semantics of the extension API.
402 int index = gtk_combo_box_get_active(GTK_COMBO_BOX(widget)); 443 int index = gtk_combo_box_get_active(GTK_COMBO_BOX(widget));
403 444
404 // Get the number of items. 445 // Get the number of items.
405 GtkTreeModel* model = gtk_combo_box_get_model(GTK_COMBO_BOX(widget)); 446 GtkTreeModel* model = gtk_combo_box_get_model(GTK_COMBO_BOX(widget));
406 int count = gtk_tree_model_iter_n_children(model, NULL); 447 int count = gtk_tree_model_iter_n_children(model, NULL);
407 448
408 // Get the value of the current item, if possible. Note that the 449 // Get the value of the current item, if possible. Note that the
(...skipping 26 matching lines...) Expand all
435 } 476 }
436 477
437 // Get the name of this combo box. 478 // Get the name of this combo box.
438 std::string name = GetWidgetName(widget); 479 std::string name = GetWidgetName(widget);
439 480
440 // Send the notification. 481 // Send the notification.
441 AccessibilityComboBoxInfo info(profile, name, value, index, count); 482 AccessibilityComboBoxInfo info(profile, name, value, index, count);
442 SendAccessibilityNotification(type, &info); 483 SendAccessibilityNotification(type, &info);
443 } 484 }
444 485
445 void AccessibilityEventRouter::SendListBoxNotification( 486 void AccessibilityEventRouterGtk::SendListBoxNotification(
446 GtkWidget* widget, NotificationType type, Profile* profile) { 487 GtkWidget* widget, NotificationType type, Profile* profile) {
447 // Get the number of items. 488 // Get the number of items.
448 GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(widget)); 489 GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
449 int count = gtk_tree_model_iter_n_children(model, NULL); 490 int count = gtk_tree_model_iter_n_children(model, NULL);
450 491
451 // Get the current selected index and its value. 492 // Get the current selected index and its value.
452 int index = -1; 493 int index = -1;
453 std::string value; 494 std::string value;
454 GtkTreePath* path; 495 GtkTreePath* path;
455 gtk_tree_view_get_cursor(GTK_TREE_VIEW(widget), &path, NULL); 496 gtk_tree_view_get_cursor(GTK_TREE_VIEW(widget), &path, NULL);
(...skipping 22 matching lines...) Expand all
478 gtk_tree_path_free(path); 519 gtk_tree_path_free(path);
479 } 520 }
480 521
481 // Get the name of this control. 522 // Get the name of this control.
482 std::string name = GetWidgetName(widget); 523 std::string name = GetWidgetName(widget);
483 524
484 // Send the notification. 525 // Send the notification.
485 AccessibilityListBoxInfo info(profile, name, value, index, count); 526 AccessibilityListBoxInfo info(profile, name, value, index, count);
486 SendAccessibilityNotification(type, &info); 527 SendAccessibilityNotification(type, &info);
487 } 528 }
529
530 void AccessibilityEventRouterGtk::SendMenuItemNotification(
531 GtkWidget* menu, NotificationType type, Profile* profile) {
532 // Find the focused menu item, recursing into submenus as needed.
533 GtkWidget* menu_item = GTK_MENU_SHELL(menu)->active_menu_item;
534 if (!menu_item)
535 return;
536 GtkWidget* submenu = gtk_menu_item_get_submenu(GTK_MENU_ITEM(menu_item));
537 while (submenu && GTK_MENU_SHELL(submenu)->active_menu_item) {
538 menu = submenu;
539 menu_item = GTK_MENU_SHELL(menu)->active_menu_item;
540 if (!menu_item)
541 return;
542 submenu = gtk_menu_item_get_submenu(GTK_MENU_ITEM(menu_item));
543 }
544
545 // Figure out the item index and total number of items.
546 GList* items = gtk_container_get_children(GTK_CONTAINER(menu));
547 guint count = g_list_length(items);
548 int index = g_list_index(items, static_cast<gconstpointer>(menu_item));
549
550 // Get the menu item's label.
551 std::string name;
552 #if GTK_CHECK_VERSION(2, 16, 0)
553 name = gtk_menu_item_get_label(GTK_MENU_ITEM(menu_item));
554 #else
555 GList* children = gtk_container_get_children(GTK_CONTAINER(menu_item));
556 for (GList* l = g_list_first(children); l != NULL; l = g_list_next(l)) {
557 GtkWidget* child = static_cast<GtkWidget*>(l->data);
558 if (GTK_IS_LABEL(child)) {
559 name = gtk_label_get_label(GTK_LABEL(child));
560 break;
561 }
562 }
563 #endif
564
565 // Send the event.
566 AccessibilityMenuItemInfo info(profile, name, submenu != NULL, index, count);
567 SendAccessibilityNotification(type, &info);
568 }
OLDNEW
« no previous file with comments | « chrome/browser/gtk/accessibility_event_router_gtk.h ('k') | chrome/browser/gtk/accessible_widget_helper_gtk.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698