Extend the suppression for issue 379943
[chromium-blink-merge.git] / ui / views / focus / focus_manager.cc
blob8dec8eaafb6097ed30e21e371689164b24dc7bb0
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "ui/views/focus/focus_manager.h"
7 #include <algorithm>
8 #include <vector>
10 #include "base/auto_reset.h"
11 #include "base/logging.h"
12 #include "build/build_config.h"
13 #include "ui/base/accelerators/accelerator.h"
14 #include "ui/base/ime/input_method.h"
15 #include "ui/base/ime/text_input_client.h"
16 #include "ui/base/ime/text_input_focus_manager.h"
17 #include "ui/base/ui_base_switches_util.h"
18 #include "ui/events/event.h"
19 #include "ui/events/keycodes/keyboard_codes.h"
20 #include "ui/views/focus/focus_manager_delegate.h"
21 #include "ui/views/focus/focus_search.h"
22 #include "ui/views/focus/view_storage.h"
23 #include "ui/views/focus/widget_focus_manager.h"
24 #include "ui/views/view.h"
25 #include "ui/views/widget/root_view.h"
26 #include "ui/views/widget/widget.h"
27 #include "ui/views/widget/widget_delegate.h"
29 namespace views {
31 namespace {
33 } // namespace
35 bool FocusManager::shortcut_handling_suspended_ = false;
36 bool FocusManager::arrow_key_traversal_enabled_ = false;
38 FocusManager::FocusManager(Widget* widget, FocusManagerDelegate* delegate)
39 : widget_(widget),
40 delegate_(delegate),
41 focused_view_(NULL),
42 accelerator_manager_(new ui::AcceleratorManager),
43 focus_change_reason_(kReasonDirectFocusChange),
44 is_changing_focus_(false) {
45 DCHECK(widget_);
46 stored_focused_view_storage_id_ =
47 ViewStorage::GetInstance()->CreateStorageID();
50 FocusManager::~FocusManager() {
53 bool FocusManager::OnKeyEvent(const ui::KeyEvent& event) {
54 const int key_code = event.key_code();
56 if (event.type() != ui::ET_KEY_PRESSED && event.type() != ui::ET_KEY_RELEASED)
57 return false;
59 if (shortcut_handling_suspended())
60 return true;
62 int modifiers = ui::EF_NONE;
63 if (event.IsShiftDown())
64 modifiers |= ui::EF_SHIFT_DOWN;
65 if (event.IsControlDown())
66 modifiers |= ui::EF_CONTROL_DOWN;
67 if (event.IsAltDown())
68 modifiers |= ui::EF_ALT_DOWN;
69 #if defined(OS_MACOSX) || defined(OS_CHROMEOS)
70 if (event.IsCommandDown())
71 modifiers |= ui::EF_COMMAND_DOWN;
72 #endif
73 ui::Accelerator accelerator(event.key_code(), modifiers);
74 accelerator.set_type(event.type());
75 accelerator.set_is_repeat(event.IsRepeat());
77 if (event.type() == ui::ET_KEY_PRESSED) {
78 // If the focused view wants to process the key event as is, let it be.
79 if (focused_view_ && focused_view_->SkipDefaultKeyEventProcessing(event) &&
80 !accelerator_manager_->HasPriorityHandler(accelerator))
81 return true;
83 // Intercept Tab related messages for focus traversal.
84 // Note that we don't do focus traversal if the root window is not part of
85 // the active window hierarchy as this would mean we have no focused view
86 // and would focus the first focusable view.
87 if (IsTabTraversalKeyEvent(event)) {
88 AdvanceFocus(event.IsShiftDown());
89 return false;
92 if (arrow_key_traversal_enabled_ && ProcessArrowKeyTraversal(event))
93 return false;
95 // Intercept arrow key messages to switch between grouped views.
96 if (focused_view_ && focused_view_->GetGroup() != -1 &&
97 (key_code == ui::VKEY_UP || key_code == ui::VKEY_DOWN ||
98 key_code == ui::VKEY_LEFT || key_code == ui::VKEY_RIGHT)) {
99 bool next = (key_code == ui::VKEY_RIGHT || key_code == ui::VKEY_DOWN);
100 View::Views views;
101 focused_view_->parent()->GetViewsInGroup(focused_view_->GetGroup(),
102 &views);
103 View::Views::const_iterator i(
104 std::find(views.begin(), views.end(), focused_view_));
105 DCHECK(i != views.end());
106 int index = static_cast<int>(i - views.begin());
107 index += next ? 1 : -1;
108 if (index < 0) {
109 index = static_cast<int>(views.size()) - 1;
110 } else if (index >= static_cast<int>(views.size())) {
111 index = 0;
113 SetFocusedViewWithReason(views[index], kReasonFocusTraversal);
114 return false;
118 // Process keyboard accelerators.
119 // If the key combination matches an accelerator, the accelerator is
120 // triggered, otherwise the key event is processed as usual.
121 if (ProcessAccelerator(accelerator)) {
122 // If a shortcut was activated for this keydown message, do not propagate
123 // the event further.
124 return false;
126 return true;
129 void FocusManager::ValidateFocusedView() {
130 if (focused_view_ && !ContainsView(focused_view_))
131 ClearFocus();
134 // Tests whether a view is valid, whether it still belongs to the window
135 // hierarchy of the FocusManager.
136 bool FocusManager::ContainsView(View* view) {
137 Widget* widget = view->GetWidget();
138 return widget ? widget->GetFocusManager() == this : false;
141 void FocusManager::AdvanceFocus(bool reverse) {
142 View* v = GetNextFocusableView(focused_view_, NULL, reverse, false);
143 // Note: Do not skip this next block when v == focused_view_. If the user
144 // tabs past the last focusable element in a webpage, we'll get here, and if
145 // the TabContentsContainerView is the only focusable view (possible in
146 // fullscreen mode), we need to run this block in order to cycle around to the
147 // first element on the page.
148 if (v) {
149 views::View* focused_view = focused_view_;
150 v->AboutToRequestFocusFromTabTraversal(reverse);
151 // AboutToRequestFocusFromTabTraversal() may have changed focus. If it did,
152 // don't change focus again.
153 if (focused_view == focused_view_)
154 SetFocusedViewWithReason(v, kReasonFocusTraversal);
158 void FocusManager::ClearNativeFocus() {
159 // Keep the top root window focused so we get keyboard events.
160 widget_->ClearNativeFocus();
163 bool FocusManager::RotatePaneFocus(Direction direction,
164 FocusCycleWrappingBehavior wrap) {
165 // Get the list of all accessible panes.
166 std::vector<View*> panes;
167 widget_->widget_delegate()->GetAccessiblePanes(&panes);
169 // Count the number of panes and set the default index if no pane
170 // is initially focused.
171 int count = static_cast<int>(panes.size());
172 if (count == 0)
173 return false;
175 // Initialize |index| to an appropriate starting index if nothing is
176 // focused initially.
177 int index = direction == kBackward ? 0 : count - 1;
179 // Check to see if a pane already has focus and update the index accordingly.
180 const views::View* focused_view = GetFocusedView();
181 if (focused_view) {
182 for (int i = 0; i < count; i++) {
183 if (panes[i] && panes[i]->Contains(focused_view)) {
184 index = i;
185 break;
190 // Rotate focus.
191 int start_index = index;
192 for (;;) {
193 if (direction == kBackward)
194 index--;
195 else
196 index++;
198 if (wrap == kNoWrap && (index >= count || index < 0))
199 return false;
200 index = (index + count) % count;
202 // Ensure that we don't loop more than once.
203 if (index == start_index)
204 break;
206 views::View* pane = panes[index];
207 DCHECK(pane);
209 if (!pane->visible())
210 continue;
212 pane->RequestFocus();
213 focused_view = GetFocusedView();
214 if (pane == focused_view || pane->Contains(focused_view))
215 return true;
218 return false;
221 View* FocusManager::GetNextFocusableView(View* original_starting_view,
222 Widget* starting_widget,
223 bool reverse,
224 bool dont_loop) {
225 FocusTraversable* focus_traversable = NULL;
227 // Let's revalidate the focused view.
228 ValidateFocusedView();
230 View* starting_view = NULL;
231 if (original_starting_view) {
232 // Search up the containment hierarchy to see if a view is acting as
233 // a pane, and wants to implement its own focus traversable to keep
234 // the focus trapped within that pane.
235 View* pane_search = original_starting_view;
236 while (pane_search) {
237 focus_traversable = pane_search->GetPaneFocusTraversable();
238 if (focus_traversable) {
239 starting_view = original_starting_view;
240 break;
242 pane_search = pane_search->parent();
245 if (!focus_traversable) {
246 if (!reverse) {
247 // If the starting view has a focus traversable, use it.
248 // This is the case with NativeWidgetWins for example.
249 focus_traversable = original_starting_view->GetFocusTraversable();
251 // Otherwise default to the root view.
252 if (!focus_traversable) {
253 focus_traversable =
254 original_starting_view->GetWidget()->GetFocusTraversable();
255 starting_view = original_starting_view;
257 } else {
258 // When you are going back, starting view's FocusTraversable
259 // should not be used.
260 focus_traversable =
261 original_starting_view->GetWidget()->GetFocusTraversable();
262 starting_view = original_starting_view;
265 } else {
266 Widget* widget = starting_widget ? starting_widget : widget_;
267 focus_traversable = widget->GetFocusTraversable();
270 // Traverse the FocusTraversable tree down to find the focusable view.
271 View* v = FindFocusableView(focus_traversable, starting_view, reverse);
272 if (v) {
273 return v;
274 } else {
275 // Let's go up in the FocusTraversable tree.
276 FocusTraversable* parent_focus_traversable =
277 focus_traversable->GetFocusTraversableParent();
278 starting_view = focus_traversable->GetFocusTraversableParentView();
279 while (parent_focus_traversable) {
280 FocusTraversable* new_focus_traversable = NULL;
281 View* new_starting_view = NULL;
282 // When we are going backward, the parent view might gain the next focus.
283 bool check_starting_view = reverse;
284 v = parent_focus_traversable->GetFocusSearch()->FindNextFocusableView(
285 starting_view, reverse, FocusSearch::UP,
286 check_starting_view, &new_focus_traversable, &new_starting_view);
288 if (new_focus_traversable) {
289 DCHECK(!v);
291 // There is a FocusTraversable, traverse it down.
292 v = FindFocusableView(new_focus_traversable, NULL, reverse);
295 if (v)
296 return v;
298 starting_view = focus_traversable->GetFocusTraversableParentView();
299 parent_focus_traversable =
300 parent_focus_traversable->GetFocusTraversableParent();
303 // If we get here, we have reached the end of the focus hierarchy, let's
304 // loop. Make sure there was at least a view to start with, to prevent
305 // infinitely looping in empty windows.
306 if (!dont_loop && original_starting_view) {
307 // Easy, just clear the selection and press tab again.
308 // By calling with NULL as the starting view, we'll start from either
309 // the starting views widget or |widget_|.
310 Widget* widget = original_starting_view->GetWidget();
311 if (widget->widget_delegate()->ShouldAdvanceFocusToTopLevelWidget())
312 widget = widget_;
313 return GetNextFocusableView(NULL, widget, reverse, true);
316 return NULL;
319 void FocusManager::SetFocusedViewWithReason(
320 View* view, FocusChangeReason reason) {
321 if (focused_view_ == view) {
322 // In the case that the widget lost the focus and gained it back without
323 // changing the focused view, we have to make the text input client focused.
324 // TODO(yukishiino): Remove this hack once we fix http://crbug.com/383236
325 FocusTextInputClient(focused_view_);
326 return;
329 base::AutoReset<bool> auto_changing_focus(&is_changing_focus_, true);
330 // Update the reason for the focus change (since this is checked by
331 // some listeners), then notify all listeners.
332 focus_change_reason_ = reason;
333 FOR_EACH_OBSERVER(FocusChangeListener, focus_change_listeners_,
334 OnWillChangeFocus(focused_view_, view));
336 View* old_focused_view = focused_view_;
337 focused_view_ = view;
338 if (old_focused_view) {
339 old_focused_view->Blur();
340 BlurTextInputClient(old_focused_view);
342 // Also make |focused_view_| the stored focus view. This way the stored focus
343 // view is remembered if focus changes are requested prior to a show or while
344 // hidden.
345 SetStoredFocusView(focused_view_);
346 if (focused_view_) {
347 FocusTextInputClient(focused_view_);
348 focused_view_->Focus();
351 FOR_EACH_OBSERVER(FocusChangeListener, focus_change_listeners_,
352 OnDidChangeFocus(old_focused_view, focused_view_));
355 void FocusManager::ClearFocus() {
356 // SetFocusedView(NULL) is going to clear out the stored view to. We need to
357 // persist it in this case.
358 views::View* focused_view = GetStoredFocusView();
359 SetFocusedView(NULL);
360 ClearNativeFocus();
361 SetStoredFocusView(focused_view);
364 void FocusManager::AdvanceFocusIfNecessary() {
365 // If widget is inactive, there is no focused view to check. The stored view
366 // will also be checked for focusability when it is being restored.
367 if (!widget_->IsActive())
368 return;
370 // If widget is active and focused view is not focusable, advance focus or,
371 // if not possible, clear focus.
372 if (focused_view_ && !focused_view_->IsAccessibilityFocusable()) {
373 AdvanceFocus(false);
374 if (focused_view_ && !focused_view_->IsAccessibilityFocusable())
375 ClearFocus();
379 void FocusManager::StoreFocusedView(bool clear_native_focus) {
380 View* focused_view = focused_view_;
381 // Don't do anything if no focused view. Storing the view (which is NULL), in
382 // this case, would clobber the view that was previously saved.
383 if (!focused_view_)
384 return;
386 View* v = focused_view_;
388 if (clear_native_focus) {
389 // Temporarily disable notification. ClearFocus() will set the focus to the
390 // main browser window. This extra focus bounce which happens during
391 // deactivation can confuse registered WidgetFocusListeners, as the focus
392 // is not changing due to a user-initiated event.
393 AutoNativeNotificationDisabler local_notification_disabler;
394 // ClearFocus() also stores the focused view.
395 ClearFocus();
396 } else {
397 SetFocusedView(NULL);
398 SetStoredFocusView(focused_view);
401 if (v)
402 v->SchedulePaint(); // Remove focus border.
405 bool FocusManager::RestoreFocusedView() {
406 View* view = GetStoredFocusView();
407 if (view) {
408 if (ContainsView(view)) {
409 if (!view->IsFocusable() && view->IsAccessibilityFocusable()) {
410 // RequestFocus would fail, but we want to restore focus to controls
411 // that had focus in accessibility mode.
412 SetFocusedViewWithReason(view, kReasonFocusRestore);
413 } else {
414 // This usually just sets the focus if this view is focusable, but
415 // let the view override RequestFocus if necessary.
416 view->RequestFocus();
418 // If it succeeded, the reason would be incorrect; set it to
419 // focus restore.
420 if (focused_view_ == view)
421 focus_change_reason_ = kReasonFocusRestore;
424 return true;
426 return false;
429 void FocusManager::SetStoredFocusView(View* focus_view) {
430 ViewStorage* view_storage = ViewStorage::GetInstance();
431 if (!view_storage) {
432 // This should never happen but bug 981648 seems to indicate it could.
433 NOTREACHED();
434 return;
437 // TODO(jcivelli): when a TabContents containing a popup is closed, the focus
438 // is stored twice causing an assert. We should find a better alternative than
439 // removing the view from the storage explicitly.
440 view_storage->RemoveView(stored_focused_view_storage_id_);
442 if (!focus_view)
443 return;
445 view_storage->StoreView(stored_focused_view_storage_id_, focus_view);
448 View* FocusManager::GetStoredFocusView() {
449 ViewStorage* view_storage = ViewStorage::GetInstance();
450 if (!view_storage) {
451 // This should never happen but bug 981648 seems to indicate it could.
452 NOTREACHED();
453 return NULL;
456 return view_storage->RetrieveView(stored_focused_view_storage_id_);
459 void FocusManager::ClearStoredFocusedView() {
460 SetStoredFocusView(NULL);
463 void FocusManager::OnTextInputClientChanged(View* view) {
464 if (view == focused_view_)
465 FocusTextInputClient(view);
468 void FocusManager::FocusTextInputClient(View* view) {
469 if (!switches::IsTextInputFocusManagerEnabled())
470 return;
472 // If the widget is not active, do not steal the text input focus.
473 if (!widget_->IsActive())
474 return;
476 ui::TextInputClient* text_input_client =
477 view ? view->GetTextInputClient() : NULL;
478 ui::TextInputFocusManager::GetInstance()->
479 FocusTextInputClient(text_input_client);
480 ui::InputMethod* input_method = widget_->GetHostInputMethod();
481 if (input_method) {
482 input_method->OnTextInputTypeChanged(text_input_client);
483 input_method->OnCaretBoundsChanged(text_input_client);
487 void FocusManager::BlurTextInputClient(View* view) {
488 if (!switches::IsTextInputFocusManagerEnabled())
489 return;
491 ui::TextInputClient* text_input_client =
492 view ? view->GetTextInputClient() : NULL;
493 if (text_input_client && text_input_client->HasCompositionText()) {
494 text_input_client->ConfirmCompositionText();
495 ui::InputMethod* input_method = widget_->GetHostInputMethod();
496 if (input_method && input_method->GetTextInputClient() == text_input_client)
497 input_method->CancelComposition(text_input_client);
499 ui::TextInputFocusManager::GetInstance()->
500 BlurTextInputClient(text_input_client);
503 // Find the next (previous if reverse is true) focusable view for the specified
504 // FocusTraversable, starting at the specified view, traversing down the
505 // FocusTraversable hierarchy.
506 View* FocusManager::FindFocusableView(FocusTraversable* focus_traversable,
507 View* starting_view,
508 bool reverse) {
509 FocusTraversable* new_focus_traversable = NULL;
510 View* new_starting_view = NULL;
511 View* v = focus_traversable->GetFocusSearch()->FindNextFocusableView(
512 starting_view,
513 reverse,
514 FocusSearch::DOWN,
515 false,
516 &new_focus_traversable,
517 &new_starting_view);
519 // Let's go down the FocusTraversable tree as much as we can.
520 while (new_focus_traversable) {
521 DCHECK(!v);
522 focus_traversable = new_focus_traversable;
523 new_focus_traversable = NULL;
524 starting_view = NULL;
525 v = focus_traversable->GetFocusSearch()->FindNextFocusableView(
526 starting_view,
527 reverse,
528 FocusSearch::DOWN,
529 false,
530 &new_focus_traversable,
531 &new_starting_view);
533 return v;
536 void FocusManager::RegisterAccelerator(
537 const ui::Accelerator& accelerator,
538 ui::AcceleratorManager::HandlerPriority priority,
539 ui::AcceleratorTarget* target) {
540 accelerator_manager_->Register(accelerator, priority, target);
543 void FocusManager::UnregisterAccelerator(const ui::Accelerator& accelerator,
544 ui::AcceleratorTarget* target) {
545 accelerator_manager_->Unregister(accelerator, target);
548 void FocusManager::UnregisterAccelerators(ui::AcceleratorTarget* target) {
549 accelerator_manager_->UnregisterAll(target);
552 bool FocusManager::ProcessAccelerator(const ui::Accelerator& accelerator) {
553 if (accelerator_manager_->Process(accelerator))
554 return true;
555 if (delegate_.get())
556 return delegate_->ProcessAccelerator(accelerator);
557 return false;
560 ui::AcceleratorTarget* FocusManager::GetCurrentTargetForAccelerator(
561 const ui::Accelerator& accelerator) const {
562 ui::AcceleratorTarget* target =
563 accelerator_manager_->GetCurrentTarget(accelerator);
564 if (!target && delegate_.get())
565 target = delegate_->GetCurrentTargetForAccelerator(accelerator);
566 return target;
569 bool FocusManager::HasPriorityHandler(
570 const ui::Accelerator& accelerator) const {
571 return accelerator_manager_->HasPriorityHandler(accelerator);
574 // static
575 bool FocusManager::IsTabTraversalKeyEvent(const ui::KeyEvent& key_event) {
576 return key_event.key_code() == ui::VKEY_TAB && !key_event.IsControlDown();
579 void FocusManager::ViewRemoved(View* removed) {
580 // If the view being removed contains (or is) the focused view,
581 // clear the focus. However, it's not safe to call ClearFocus()
582 // (and in turn ClearNativeFocus()) here because ViewRemoved() can
583 // be called while the top level widget is being destroyed.
584 if (focused_view_ && removed->Contains(focused_view_))
585 SetFocusedView(NULL);
588 void FocusManager::AddFocusChangeListener(FocusChangeListener* listener) {
589 focus_change_listeners_.AddObserver(listener);
592 void FocusManager::RemoveFocusChangeListener(FocusChangeListener* listener) {
593 focus_change_listeners_.RemoveObserver(listener);
596 bool FocusManager::ProcessArrowKeyTraversal(const ui::KeyEvent& event) {
597 if (event.IsShiftDown() || event.IsControlDown() || event.IsAltDown())
598 return false;
600 const int key_code = event.key_code();
601 if (key_code == ui::VKEY_LEFT || key_code == ui::VKEY_UP) {
602 AdvanceFocus(true);
603 return true;
605 if (key_code == ui::VKEY_RIGHT || key_code == ui::VKEY_DOWN) {
606 AdvanceFocus(false);
607 return true;
610 return false;
613 } // namespace views