Correct blacklist entry message
[chromium-blink-merge.git] / ui / views / focus / focus_manager.cc
blob5952525fd0ef2f4fec7340ffae94c811c2ad9791
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/events/event.h"
15 #include "ui/events/keycodes/keyboard_codes.h"
16 #include "ui/views/focus/focus_manager_delegate.h"
17 #include "ui/views/focus/focus_search.h"
18 #include "ui/views/focus/view_storage.h"
19 #include "ui/views/focus/widget_focus_manager.h"
20 #include "ui/views/view.h"
21 #include "ui/views/widget/root_view.h"
22 #include "ui/views/widget/widget.h"
23 #include "ui/views/widget/widget_delegate.h"
25 namespace views {
27 namespace {
29 class FocusManagerEventHandler : public ui::EventHandler {
30 public:
31 FocusManagerEventHandler(FocusManager* parent) : focus_manager_(parent) {}
33 // Implementation of ui::EventHandler:
34 virtual void OnKeyEvent(ui::KeyEvent* event) OVERRIDE {
35 if (!focus_manager_->OnKeyEvent(*event))
36 event->SetHandled();
39 private:
40 FocusManager* focus_manager_;
43 } // namespace
45 bool FocusManager::shortcut_handling_suspended_ = false;
46 bool FocusManager::arrow_key_traversal_enabled_ = false;
48 FocusManager::FocusManager(Widget* widget, FocusManagerDelegate* delegate)
49 : widget_(widget),
50 delegate_(delegate),
51 focused_view_(NULL),
52 accelerator_manager_(new ui::AcceleratorManager),
53 focus_change_reason_(kReasonDirectFocusChange),
54 is_changing_focus_(false) {
55 DCHECK(widget_);
56 stored_focused_view_storage_id_ =
57 ViewStorage::GetInstance()->CreateStorageID();
60 FocusManager::~FocusManager() {
63 bool FocusManager::OnKeyEvent(const ui::KeyEvent& event) {
64 const int key_code = event.key_code();
66 if (event.type() != ui::ET_KEY_PRESSED && event.type() != ui::ET_KEY_RELEASED)
67 return false;
69 if (shortcut_handling_suspended())
70 return true;
72 int modifiers = ui::EF_NONE;
73 if (event.IsShiftDown())
74 modifiers |= ui::EF_SHIFT_DOWN;
75 if (event.IsControlDown())
76 modifiers |= ui::EF_CONTROL_DOWN;
77 if (event.IsAltDown())
78 modifiers |= ui::EF_ALT_DOWN;
79 ui::Accelerator accelerator(event.key_code(), modifiers);
80 accelerator.set_type(event.type());
82 if (event.type() == ui::ET_KEY_PRESSED) {
83 // If the focused view wants to process the key event as is, let it be.
84 if (focused_view_ && focused_view_->SkipDefaultKeyEventProcessing(event) &&
85 !accelerator_manager_->HasPriorityHandler(accelerator))
86 return true;
88 // Intercept Tab related messages for focus traversal.
89 // Note that we don't do focus traversal if the root window is not part of
90 // the active window hierarchy as this would mean we have no focused view
91 // and would focus the first focusable view.
92 #if defined(OS_WIN) && !defined(USE_AURA)
93 HWND top_window = widget_->GetNativeView();
94 HWND active_window = ::GetActiveWindow();
95 if ((active_window == top_window || ::IsChild(active_window, top_window)) &&
96 IsTabTraversalKeyEvent(event)) {
97 AdvanceFocus(event.IsShiftDown());
98 return false;
100 #else
101 if (IsTabTraversalKeyEvent(event)) {
102 AdvanceFocus(event.IsShiftDown());
103 return false;
105 #endif
107 if (arrow_key_traversal_enabled_ && ProcessArrowKeyTraversal(event))
108 return false;
110 // Intercept arrow key messages to switch between grouped views.
111 if (focused_view_ && focused_view_->GetGroup() != -1 &&
112 (key_code == ui::VKEY_UP || key_code == ui::VKEY_DOWN ||
113 key_code == ui::VKEY_LEFT || key_code == ui::VKEY_RIGHT)) {
114 bool next = (key_code == ui::VKEY_RIGHT || key_code == ui::VKEY_DOWN);
115 View::Views views;
116 focused_view_->parent()->GetViewsInGroup(focused_view_->GetGroup(),
117 &views);
118 View::Views::const_iterator i(
119 std::find(views.begin(), views.end(), focused_view_));
120 DCHECK(i != views.end());
121 int index = static_cast<int>(i - views.begin());
122 index += next ? 1 : -1;
123 if (index < 0) {
124 index = static_cast<int>(views.size()) - 1;
125 } else if (index >= static_cast<int>(views.size())) {
126 index = 0;
128 SetFocusedViewWithReason(views[index], kReasonFocusTraversal);
129 return false;
133 // Process keyboard accelerators.
134 // If the key combination matches an accelerator, the accelerator is
135 // triggered, otherwise the key event is processed as usual.
136 if (ProcessAccelerator(accelerator)) {
137 // If a shortcut was activated for this keydown message, do not propagate
138 // the event further.
139 return false;
141 return true;
144 void FocusManager::ValidateFocusedView() {
145 if (focused_view_ && !ContainsView(focused_view_))
146 ClearFocus();
149 // Tests whether a view is valid, whether it still belongs to the window
150 // hierarchy of the FocusManager.
151 bool FocusManager::ContainsView(View* view) {
152 Widget* widget = view->GetWidget();
153 return widget ? widget->GetFocusManager() == this : false;
156 void FocusManager::AdvanceFocus(bool reverse) {
157 View* v = GetNextFocusableView(focused_view_, NULL, reverse, false);
158 // Note: Do not skip this next block when v == focused_view_. If the user
159 // tabs past the last focusable element in a webpage, we'll get here, and if
160 // the TabContentsContainerView is the only focusable view (possible in
161 // fullscreen mode), we need to run this block in order to cycle around to the
162 // first element on the page.
163 if (v) {
164 views::View* focused_view = focused_view_;
165 v->AboutToRequestFocusFromTabTraversal(reverse);
166 // AboutToRequestFocusFromTabTraversal() may have changed focus. If it did,
167 // don't change focus again.
168 if (focused_view == focused_view_)
169 SetFocusedViewWithReason(v, kReasonFocusTraversal);
173 void FocusManager::ClearNativeFocus() {
174 // Keep the top root window focused so we get keyboard events.
175 widget_->ClearNativeFocus();
178 bool FocusManager::RotatePaneFocus(Direction direction,
179 FocusCycleWrappingBehavior wrap) {
180 // Get the list of all accessible panes.
181 std::vector<View*> panes;
182 widget_->widget_delegate()->GetAccessiblePanes(&panes);
184 // Count the number of panes and set the default index if no pane
185 // is initially focused.
186 int count = static_cast<int>(panes.size());
187 if (count == 0)
188 return false;
190 // Initialize |index| to an appropriate starting index if nothing is
191 // focused initially.
192 int index = direction == kBackward ? 0 : count - 1;
194 // Check to see if a pane already has focus and update the index accordingly.
195 const views::View* focused_view = GetFocusedView();
196 if (focused_view) {
197 for (int i = 0; i < count; i++) {
198 if (panes[i] && panes[i]->Contains(focused_view)) {
199 index = i;
200 break;
205 // Rotate focus.
206 int start_index = index;
207 for (;;) {
208 if (direction == kBackward)
209 index--;
210 else
211 index++;
213 if (wrap == kNoWrap && (index >= count || index < 0))
214 return false;
215 index = (index + count) % count;
217 // Ensure that we don't loop more than once.
218 if (index == start_index)
219 break;
221 views::View* pane = panes[index];
222 DCHECK(pane);
224 if (!pane->visible())
225 continue;
227 pane->RequestFocus();
228 focused_view = GetFocusedView();
229 if (pane == focused_view || pane->Contains(focused_view))
230 return true;
233 return false;
236 View* FocusManager::GetNextFocusableView(View* original_starting_view,
237 Widget* starting_widget,
238 bool reverse,
239 bool dont_loop) {
240 FocusTraversable* focus_traversable = NULL;
242 // Let's revalidate the focused view.
243 ValidateFocusedView();
245 View* starting_view = NULL;
246 if (original_starting_view) {
247 // Search up the containment hierarchy to see if a view is acting as
248 // a pane, and wants to implement its own focus traversable to keep
249 // the focus trapped within that pane.
250 View* pane_search = original_starting_view;
251 while (pane_search) {
252 focus_traversable = pane_search->GetPaneFocusTraversable();
253 if (focus_traversable) {
254 starting_view = original_starting_view;
255 break;
257 pane_search = pane_search->parent();
260 if (!focus_traversable) {
261 if (!reverse) {
262 // If the starting view has a focus traversable, use it.
263 // This is the case with NativeWidgetWins for example.
264 focus_traversable = original_starting_view->GetFocusTraversable();
266 // Otherwise default to the root view.
267 if (!focus_traversable) {
268 focus_traversable =
269 original_starting_view->GetWidget()->GetFocusTraversable();
270 starting_view = original_starting_view;
272 } else {
273 // When you are going back, starting view's FocusTraversable
274 // should not be used.
275 focus_traversable =
276 original_starting_view->GetWidget()->GetFocusTraversable();
277 starting_view = original_starting_view;
280 } else {
281 Widget* widget = starting_widget ? starting_widget : widget_;
282 focus_traversable = widget->GetFocusTraversable();
285 // Traverse the FocusTraversable tree down to find the focusable view.
286 View* v = FindFocusableView(focus_traversable, starting_view, reverse);
287 if (v) {
288 return v;
289 } else {
290 // Let's go up in the FocusTraversable tree.
291 FocusTraversable* parent_focus_traversable =
292 focus_traversable->GetFocusTraversableParent();
293 starting_view = focus_traversable->GetFocusTraversableParentView();
294 while (parent_focus_traversable) {
295 FocusTraversable* new_focus_traversable = NULL;
296 View* new_starting_view = NULL;
297 // When we are going backward, the parent view might gain the next focus.
298 bool check_starting_view = reverse;
299 v = parent_focus_traversable->GetFocusSearch()->FindNextFocusableView(
300 starting_view, reverse, FocusSearch::UP,
301 check_starting_view, &new_focus_traversable, &new_starting_view);
303 if (new_focus_traversable) {
304 DCHECK(!v);
306 // There is a FocusTraversable, traverse it down.
307 v = FindFocusableView(new_focus_traversable, NULL, reverse);
310 if (v)
311 return v;
313 starting_view = focus_traversable->GetFocusTraversableParentView();
314 parent_focus_traversable =
315 parent_focus_traversable->GetFocusTraversableParent();
318 // If we get here, we have reached the end of the focus hierarchy, let's
319 // loop. Make sure there was at least a view to start with, to prevent
320 // infinitely looping in empty windows.
321 if (!dont_loop && original_starting_view) {
322 // Easy, just clear the selection and press tab again.
323 // By calling with NULL as the starting view, we'll start from either
324 // the starting views widget or |widget_|.
325 Widget* widget = original_starting_view->GetWidget();
326 if (widget->widget_delegate()->ShouldAdvanceFocusToTopLevelWidget())
327 widget = widget_;
328 return GetNextFocusableView(NULL, widget, reverse, true);
331 return NULL;
334 void FocusManager::SetFocusedViewWithReason(
335 View* view, FocusChangeReason reason) {
336 if (focused_view_ == view)
337 return;
339 base::AutoReset<bool> auto_changing_focus(&is_changing_focus_, true);
340 // Update the reason for the focus change (since this is checked by
341 // some listeners), then notify all listeners.
342 focus_change_reason_ = reason;
343 FOR_EACH_OBSERVER(FocusChangeListener, focus_change_listeners_,
344 OnWillChangeFocus(focused_view_, view));
346 View* old_focused_view = focused_view_;
347 focused_view_ = view;
348 if (old_focused_view)
349 old_focused_view->Blur();
350 // Also make |focused_view_| the stored focus view. This way the stored focus
351 // view is remembered if focus changes are requested prior to a show or while
352 // hidden.
353 SetStoredFocusView(focused_view_);
354 if (focused_view_)
355 focused_view_->Focus();
357 FOR_EACH_OBSERVER(FocusChangeListener, focus_change_listeners_,
358 OnDidChangeFocus(old_focused_view, focused_view_));
361 void FocusManager::ClearFocus() {
362 // SetFocusedView(NULL) is going to clear out the stored view to. We need to
363 // persist it in this case.
364 views::View* focused_view = GetStoredFocusView();
365 SetFocusedView(NULL);
366 ClearNativeFocus();
367 SetStoredFocusView(focused_view);
370 void FocusManager::StoreFocusedView(bool clear_native_focus) {
371 View* focused_view = focused_view_;
372 // Don't do anything if no focused view. Storing the view (which is NULL), in
373 // this case, would clobber the view that was previously saved.
374 if (!focused_view_)
375 return;
377 View* v = focused_view_;
379 if (clear_native_focus) {
380 // Temporarily disable notification. ClearFocus() will set the focus to the
381 // main browser window. This extra focus bounce which happens during
382 // deactivation can confuse registered WidgetFocusListeners, as the focus
383 // is not changing due to a user-initiated event.
384 AutoNativeNotificationDisabler local_notification_disabler;
385 // ClearFocus() also stores the focused view.
386 ClearFocus();
387 } else {
388 SetFocusedView(NULL);
389 SetStoredFocusView(focused_view);
392 if (v)
393 v->SchedulePaint(); // Remove focus border.
396 bool FocusManager::RestoreFocusedView() {
397 View* view = GetStoredFocusView();
398 if (view) {
399 if (ContainsView(view)) {
400 if (!view->IsFocusable() && view->IsAccessibilityFocusable()) {
401 // RequestFocus would fail, but we want to restore focus to controls
402 // that had focus in accessibility mode.
403 SetFocusedViewWithReason(view, kReasonFocusRestore);
404 } else {
405 // This usually just sets the focus if this view is focusable, but
406 // let the view override RequestFocus if necessary.
407 view->RequestFocus();
409 // If it succeeded, the reason would be incorrect; set it to
410 // focus restore.
411 if (focused_view_ == view)
412 focus_change_reason_ = kReasonFocusRestore;
415 return true;
417 return false;
420 void FocusManager::SetStoredFocusView(View* focus_view) {
421 ViewStorage* view_storage = ViewStorage::GetInstance();
422 if (!view_storage) {
423 // This should never happen but bug 981648 seems to indicate it could.
424 NOTREACHED();
425 return;
428 // TODO(jcivelli): when a TabContents containing a popup is closed, the focus
429 // is stored twice causing an assert. We should find a better alternative than
430 // removing the view from the storage explicitly.
431 view_storage->RemoveView(stored_focused_view_storage_id_);
433 if (!focus_view)
434 return;
436 view_storage->StoreView(stored_focused_view_storage_id_, focus_view);
439 View* FocusManager::GetStoredFocusView() {
440 ViewStorage* view_storage = ViewStorage::GetInstance();
441 if (!view_storage) {
442 // This should never happen but bug 981648 seems to indicate it could.
443 NOTREACHED();
444 return NULL;
447 return view_storage->RetrieveView(stored_focused_view_storage_id_);
450 void FocusManager::ClearStoredFocusedView() {
451 SetStoredFocusView(NULL);
454 // Find the next (previous if reverse is true) focusable view for the specified
455 // FocusTraversable, starting at the specified view, traversing down the
456 // FocusTraversable hierarchy.
457 View* FocusManager::FindFocusableView(FocusTraversable* focus_traversable,
458 View* starting_view,
459 bool reverse) {
460 FocusTraversable* new_focus_traversable = NULL;
461 View* new_starting_view = NULL;
462 View* v = focus_traversable->GetFocusSearch()->FindNextFocusableView(
463 starting_view,
464 reverse,
465 FocusSearch::DOWN,
466 false,
467 &new_focus_traversable,
468 &new_starting_view);
470 // Let's go down the FocusTraversable tree as much as we can.
471 while (new_focus_traversable) {
472 DCHECK(!v);
473 focus_traversable = new_focus_traversable;
474 new_focus_traversable = NULL;
475 starting_view = NULL;
476 v = focus_traversable->GetFocusSearch()->FindNextFocusableView(
477 starting_view,
478 reverse,
479 FocusSearch::DOWN,
480 false,
481 &new_focus_traversable,
482 &new_starting_view);
484 return v;
487 void FocusManager::RegisterAccelerator(
488 const ui::Accelerator& accelerator,
489 ui::AcceleratorManager::HandlerPriority priority,
490 ui::AcceleratorTarget* target) {
491 accelerator_manager_->Register(accelerator, priority, target);
494 void FocusManager::UnregisterAccelerator(const ui::Accelerator& accelerator,
495 ui::AcceleratorTarget* target) {
496 accelerator_manager_->Unregister(accelerator, target);
499 void FocusManager::UnregisterAccelerators(ui::AcceleratorTarget* target) {
500 accelerator_manager_->UnregisterAll(target);
503 bool FocusManager::ProcessAccelerator(const ui::Accelerator& accelerator) {
504 if (accelerator_manager_->Process(accelerator))
505 return true;
506 if (delegate_.get())
507 return delegate_->ProcessAccelerator(accelerator);
508 return false;
511 ui::AcceleratorTarget* FocusManager::GetCurrentTargetForAccelerator(
512 const ui::Accelerator& accelerator) const {
513 ui::AcceleratorTarget* target =
514 accelerator_manager_->GetCurrentTarget(accelerator);
515 if (!target && delegate_.get())
516 target = delegate_->GetCurrentTargetForAccelerator(accelerator);
517 return target;
520 bool FocusManager::HasPriorityHandler(
521 const ui::Accelerator& accelerator) const {
522 return accelerator_manager_->HasPriorityHandler(accelerator);
525 // static
526 bool FocusManager::IsTabTraversalKeyEvent(const ui::KeyEvent& key_event) {
527 return key_event.key_code() == ui::VKEY_TAB && !key_event.IsControlDown();
530 ui::EventHandler* FocusManager::GetEventHandler() {
531 if (!event_handler_)
532 event_handler_.reset(new FocusManagerEventHandler(this));
533 return event_handler_.get();
536 void FocusManager::ViewRemoved(View* removed) {
537 // If the view being removed contains (or is) the focused view,
538 // clear the focus. However, it's not safe to call ClearFocus()
539 // (and in turn ClearNativeFocus()) here because ViewRemoved() can
540 // be called while the top level widget is being destroyed.
541 if (focused_view_ && removed->Contains(focused_view_))
542 SetFocusedView(NULL);
545 void FocusManager::AddFocusChangeListener(FocusChangeListener* listener) {
546 focus_change_listeners_.AddObserver(listener);
549 void FocusManager::RemoveFocusChangeListener(FocusChangeListener* listener) {
550 focus_change_listeners_.RemoveObserver(listener);
553 bool FocusManager::ProcessArrowKeyTraversal(const ui::KeyEvent& event) {
554 if (event.IsShiftDown() || event.IsControlDown() || event.IsAltDown())
555 return false;
557 const int key_code = event.key_code();
558 if (key_code == ui::VKEY_LEFT || key_code == ui::VKEY_UP) {
559 AdvanceFocus(true);
560 return true;
562 if (key_code == ui::VKEY_RIGHT || key_code == ui::VKEY_DOWN) {
563 AdvanceFocus(false);
564 return true;
567 return false;
570 } // namespace views