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.
4
5#include "ui/views/focus/focus_manager.h"
6
7#include <algorithm>
8#include <vector>
9
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"
28
29namespace views {
30
31namespace {
32
33}  // namespace
34
35bool FocusManager::shortcut_handling_suspended_ = false;
36bool FocusManager::arrow_key_traversal_enabled_ = false;
37
38FocusManager::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();
48}
49
50FocusManager::~FocusManager() {
51}
52
53bool FocusManager::OnKeyEvent(const ui::KeyEvent& event) {
54  const int key_code = event.key_code();
55
56  if (event.type() != ui::ET_KEY_PRESSED && event.type() != ui::ET_KEY_RELEASED)
57    return false;
58
59  if (shortcut_handling_suspended())
60    return true;
61
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  ui::Accelerator accelerator(event.key_code(), modifiers);
70  accelerator.set_type(event.type());
71  accelerator.set_is_repeat(event.IsRepeat());
72
73  if (event.type() == ui::ET_KEY_PRESSED) {
74    // If the focused view wants to process the key event as is, let it be.
75    if (focused_view_ && focused_view_->SkipDefaultKeyEventProcessing(event) &&
76        !accelerator_manager_->HasPriorityHandler(accelerator))
77      return true;
78
79    // Intercept Tab related messages for focus traversal.
80    // Note that we don't do focus traversal if the root window is not part of
81    // the active window hierarchy as this would mean we have no focused view
82    // and would focus the first focusable view.
83    if (IsTabTraversalKeyEvent(event)) {
84      AdvanceFocus(event.IsShiftDown());
85      return false;
86    }
87
88    if (arrow_key_traversal_enabled_ && ProcessArrowKeyTraversal(event))
89      return false;
90
91    // Intercept arrow key messages to switch between grouped views.
92    if (focused_view_ && focused_view_->GetGroup() != -1 &&
93        (key_code == ui::VKEY_UP || key_code == ui::VKEY_DOWN ||
94         key_code == ui::VKEY_LEFT || key_code == ui::VKEY_RIGHT)) {
95      bool next = (key_code == ui::VKEY_RIGHT || key_code == ui::VKEY_DOWN);
96      View::Views views;
97      focused_view_->parent()->GetViewsInGroup(focused_view_->GetGroup(),
98                                               &views);
99      View::Views::const_iterator i(
100          std::find(views.begin(), views.end(), focused_view_));
101      DCHECK(i != views.end());
102      int index = static_cast<int>(i - views.begin());
103      index += next ? 1 : -1;
104      if (index < 0) {
105        index = static_cast<int>(views.size()) - 1;
106      } else if (index >= static_cast<int>(views.size())) {
107        index = 0;
108      }
109      SetFocusedViewWithReason(views[index], kReasonFocusTraversal);
110      return false;
111    }
112  }
113
114  // Process keyboard accelerators.
115  // If the key combination matches an accelerator, the accelerator is
116  // triggered, otherwise the key event is processed as usual.
117  if (ProcessAccelerator(accelerator)) {
118    // If a shortcut was activated for this keydown message, do not propagate
119    // the event further.
120    return false;
121  }
122  return true;
123}
124
125void FocusManager::ValidateFocusedView() {
126  if (focused_view_ && !ContainsView(focused_view_))
127    ClearFocus();
128}
129
130// Tests whether a view is valid, whether it still belongs to the window
131// hierarchy of the FocusManager.
132bool FocusManager::ContainsView(View* view) {
133  Widget* widget = view->GetWidget();
134  return widget ? widget->GetFocusManager() == this : false;
135}
136
137void FocusManager::AdvanceFocus(bool reverse) {
138  View* v = GetNextFocusableView(focused_view_, NULL, reverse, false);
139  // Note: Do not skip this next block when v == focused_view_.  If the user
140  // tabs past the last focusable element in a webpage, we'll get here, and if
141  // the TabContentsContainerView is the only focusable view (possible in
142  // fullscreen mode), we need to run this block in order to cycle around to the
143  // first element on the page.
144  if (v) {
145    views::View* focused_view = focused_view_;
146    v->AboutToRequestFocusFromTabTraversal(reverse);
147    // AboutToRequestFocusFromTabTraversal() may have changed focus. If it did,
148    // don't change focus again.
149    if (focused_view == focused_view_)
150      SetFocusedViewWithReason(v, kReasonFocusTraversal);
151  }
152}
153
154void FocusManager::ClearNativeFocus() {
155  // Keep the top root window focused so we get keyboard events.
156  widget_->ClearNativeFocus();
157}
158
159bool FocusManager::RotatePaneFocus(Direction direction,
160                                   FocusCycleWrappingBehavior wrap) {
161  // Get the list of all accessible panes.
162  std::vector<View*> panes;
163  widget_->widget_delegate()->GetAccessiblePanes(&panes);
164
165  // Count the number of panes and set the default index if no pane
166  // is initially focused.
167  int count = static_cast<int>(panes.size());
168  if (count == 0)
169    return false;
170
171  // Initialize |index| to an appropriate starting index if nothing is
172  // focused initially.
173  int index = direction == kBackward ? 0 : count - 1;
174
175  // Check to see if a pane already has focus and update the index accordingly.
176  const views::View* focused_view = GetFocusedView();
177  if (focused_view) {
178    for (int i = 0; i < count; i++) {
179      if (panes[i] && panes[i]->Contains(focused_view)) {
180        index = i;
181        break;
182      }
183    }
184  }
185
186  // Rotate focus.
187  int start_index = index;
188  for (;;) {
189    if (direction == kBackward)
190      index--;
191    else
192      index++;
193
194    if (wrap == kNoWrap && (index >= count || index < 0))
195      return false;
196    index = (index + count) % count;
197
198    // Ensure that we don't loop more than once.
199    if (index == start_index)
200      break;
201
202    views::View* pane = panes[index];
203    DCHECK(pane);
204
205    if (!pane->visible())
206      continue;
207
208    pane->RequestFocus();
209    focused_view = GetFocusedView();
210    if (pane == focused_view || pane->Contains(focused_view))
211      return true;
212  }
213
214  return false;
215}
216
217View* FocusManager::GetNextFocusableView(View* original_starting_view,
218                                         Widget* starting_widget,
219                                         bool reverse,
220                                         bool dont_loop) {
221  FocusTraversable* focus_traversable = NULL;
222
223  // Let's revalidate the focused view.
224  ValidateFocusedView();
225
226  View* starting_view = NULL;
227  if (original_starting_view) {
228    // Search up the containment hierarchy to see if a view is acting as
229    // a pane, and wants to implement its own focus traversable to keep
230    // the focus trapped within that pane.
231    View* pane_search = original_starting_view;
232    while (pane_search) {
233      focus_traversable = pane_search->GetPaneFocusTraversable();
234      if (focus_traversable) {
235        starting_view = original_starting_view;
236        break;
237      }
238      pane_search = pane_search->parent();
239    }
240
241    if (!focus_traversable) {
242      if (!reverse) {
243        // If the starting view has a focus traversable, use it.
244        // This is the case with NativeWidgetWins for example.
245        focus_traversable = original_starting_view->GetFocusTraversable();
246
247        // Otherwise default to the root view.
248        if (!focus_traversable) {
249          focus_traversable =
250              original_starting_view->GetWidget()->GetFocusTraversable();
251          starting_view = original_starting_view;
252        }
253      } else {
254        // When you are going back, starting view's FocusTraversable
255        // should not be used.
256        focus_traversable =
257            original_starting_view->GetWidget()->GetFocusTraversable();
258        starting_view = original_starting_view;
259      }
260    }
261  } else {
262    Widget* widget = starting_widget ? starting_widget : widget_;
263    focus_traversable = widget->GetFocusTraversable();
264  }
265
266  // Traverse the FocusTraversable tree down to find the focusable view.
267  View* v = FindFocusableView(focus_traversable, starting_view, reverse);
268  if (v) {
269    return v;
270  } else {
271    // Let's go up in the FocusTraversable tree.
272    FocusTraversable* parent_focus_traversable =
273        focus_traversable->GetFocusTraversableParent();
274    starting_view = focus_traversable->GetFocusTraversableParentView();
275    while (parent_focus_traversable) {
276      FocusTraversable* new_focus_traversable = NULL;
277      View* new_starting_view = NULL;
278      // When we are going backward, the parent view might gain the next focus.
279      bool check_starting_view = reverse;
280      v = parent_focus_traversable->GetFocusSearch()->FindNextFocusableView(
281          starting_view, reverse, FocusSearch::UP,
282          check_starting_view, &new_focus_traversable, &new_starting_view);
283
284      if (new_focus_traversable) {
285        DCHECK(!v);
286
287        // There is a FocusTraversable, traverse it down.
288        v = FindFocusableView(new_focus_traversable, NULL, reverse);
289      }
290
291      if (v)
292        return v;
293
294      starting_view = focus_traversable->GetFocusTraversableParentView();
295      parent_focus_traversable =
296          parent_focus_traversable->GetFocusTraversableParent();
297    }
298
299    // If we get here, we have reached the end of the focus hierarchy, let's
300    // loop. Make sure there was at least a view to start with, to prevent
301    // infinitely looping in empty windows.
302    if (!dont_loop && original_starting_view) {
303      // Easy, just clear the selection and press tab again.
304      // By calling with NULL as the starting view, we'll start from either
305      // the starting views widget or |widget_|.
306      Widget* widget = original_starting_view->GetWidget();
307      if (widget->widget_delegate()->ShouldAdvanceFocusToTopLevelWidget())
308        widget = widget_;
309      return GetNextFocusableView(NULL, widget, reverse, true);
310    }
311  }
312  return NULL;
313}
314
315void FocusManager::SetFocusedViewWithReason(
316    View* view, FocusChangeReason reason) {
317  if (focused_view_ == view) {
318    // In the case that the widget lost the focus and gained it back without
319    // changing the focused view, we have to make the text input client focused.
320    // TODO(yukishiino): Remove this hack once we fix http://crbug.com/383236
321    FocusTextInputClient(focused_view_);
322    return;
323  }
324
325  base::AutoReset<bool> auto_changing_focus(&is_changing_focus_, true);
326  // Update the reason for the focus change (since this is checked by
327  // some listeners), then notify all listeners.
328  focus_change_reason_ = reason;
329  FOR_EACH_OBSERVER(FocusChangeListener, focus_change_listeners_,
330                    OnWillChangeFocus(focused_view_, view));
331
332  View* old_focused_view = focused_view_;
333  focused_view_ = view;
334  if (old_focused_view) {
335    old_focused_view->Blur();
336    BlurTextInputClient(old_focused_view);
337  }
338  // Also make |focused_view_| the stored focus view. This way the stored focus
339  // view is remembered if focus changes are requested prior to a show or while
340  // hidden.
341  SetStoredFocusView(focused_view_);
342  if (focused_view_) {
343    FocusTextInputClient(focused_view_);
344    focused_view_->Focus();
345  }
346
347  FOR_EACH_OBSERVER(FocusChangeListener, focus_change_listeners_,
348                    OnDidChangeFocus(old_focused_view, focused_view_));
349}
350
351void FocusManager::ClearFocus() {
352  // SetFocusedView(NULL) is going to clear out the stored view to. We need to
353  // persist it in this case.
354  views::View* focused_view = GetStoredFocusView();
355  SetFocusedView(NULL);
356  ClearNativeFocus();
357  SetStoredFocusView(focused_view);
358}
359
360void FocusManager::StoreFocusedView(bool clear_native_focus) {
361  View* focused_view = focused_view_;
362  // Don't do anything if no focused view. Storing the view (which is NULL), in
363  // this case, would clobber the view that was previously saved.
364  if (!focused_view_)
365    return;
366
367  View* v = focused_view_;
368
369  if (clear_native_focus) {
370    // Temporarily disable notification.  ClearFocus() will set the focus to the
371    // main browser window.  This extra focus bounce which happens during
372    // deactivation can confuse registered WidgetFocusListeners, as the focus
373    // is not changing due to a user-initiated event.
374    AutoNativeNotificationDisabler local_notification_disabler;
375    // ClearFocus() also stores the focused view.
376    ClearFocus();
377  } else {
378    SetFocusedView(NULL);
379    SetStoredFocusView(focused_view);
380  }
381
382  if (v)
383    v->SchedulePaint();  // Remove focus border.
384}
385
386bool FocusManager::RestoreFocusedView() {
387  View* view = GetStoredFocusView();
388  if (view) {
389    if (ContainsView(view)) {
390      if (!view->IsFocusable() && view->IsAccessibilityFocusable()) {
391        // RequestFocus would fail, but we want to restore focus to controls
392        // that had focus in accessibility mode.
393        SetFocusedViewWithReason(view, kReasonFocusRestore);
394      } else {
395        // This usually just sets the focus if this view is focusable, but
396        // let the view override RequestFocus if necessary.
397        view->RequestFocus();
398
399        // If it succeeded, the reason would be incorrect; set it to
400        // focus restore.
401        if (focused_view_ == view)
402          focus_change_reason_ = kReasonFocusRestore;
403      }
404    }
405    return true;
406  }
407  return false;
408}
409
410void FocusManager::SetStoredFocusView(View* focus_view) {
411  ViewStorage* view_storage = ViewStorage::GetInstance();
412  if (!view_storage) {
413    // This should never happen but bug 981648 seems to indicate it could.
414    NOTREACHED();
415    return;
416  }
417
418  // TODO(jcivelli): when a TabContents containing a popup is closed, the focus
419  // is stored twice causing an assert. We should find a better alternative than
420  // removing the view from the storage explicitly.
421  view_storage->RemoveView(stored_focused_view_storage_id_);
422
423  if (!focus_view)
424    return;
425
426  view_storage->StoreView(stored_focused_view_storage_id_, focus_view);
427}
428
429View* FocusManager::GetStoredFocusView() {
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 NULL;
435  }
436
437  return view_storage->RetrieveView(stored_focused_view_storage_id_);
438}
439
440void FocusManager::ClearStoredFocusedView() {
441  SetStoredFocusView(NULL);
442}
443
444void FocusManager::OnTextInputClientChanged(View* view) {
445  if (view == focused_view_)
446    FocusTextInputClient(view);
447}
448
449void FocusManager::FocusTextInputClient(View* view) {
450  if (!switches::IsTextInputFocusManagerEnabled())
451    return;
452
453  // If the widget is not active, do not steal the text input focus.
454  if (!widget_->IsActive())
455    return;
456
457  ui::TextInputClient* text_input_client =
458      view ? view->GetTextInputClient() : NULL;
459  ui::TextInputFocusManager::GetInstance()->
460      FocusTextInputClient(text_input_client);
461  ui::InputMethod* input_method = widget_->GetHostInputMethod();
462  if (input_method) {
463    input_method->OnTextInputTypeChanged(text_input_client);
464    input_method->OnCaretBoundsChanged(text_input_client);
465  }
466}
467
468void FocusManager::BlurTextInputClient(View* view) {
469  if (!switches::IsTextInputFocusManagerEnabled())
470    return;
471
472  ui::TextInputClient* text_input_client =
473      view ? view->GetTextInputClient() : NULL;
474  if (text_input_client && text_input_client->HasCompositionText()) {
475    text_input_client->ConfirmCompositionText();
476    ui::InputMethod* input_method = widget_->GetHostInputMethod();
477    if (input_method && input_method->GetTextInputClient() == text_input_client)
478      input_method->CancelComposition(text_input_client);
479  }
480  ui::TextInputFocusManager::GetInstance()->
481      BlurTextInputClient(text_input_client);
482}
483
484// Find the next (previous if reverse is true) focusable view for the specified
485// FocusTraversable, starting at the specified view, traversing down the
486// FocusTraversable hierarchy.
487View* FocusManager::FindFocusableView(FocusTraversable* focus_traversable,
488                                      View* starting_view,
489                                      bool reverse) {
490  FocusTraversable* new_focus_traversable = NULL;
491  View* new_starting_view = NULL;
492  View* v = focus_traversable->GetFocusSearch()->FindNextFocusableView(
493      starting_view,
494      reverse,
495      FocusSearch::DOWN,
496      false,
497      &new_focus_traversable,
498      &new_starting_view);
499
500  // Let's go down the FocusTraversable tree as much as we can.
501  while (new_focus_traversable) {
502    DCHECK(!v);
503    focus_traversable = new_focus_traversable;
504    new_focus_traversable = NULL;
505    starting_view = NULL;
506    v = focus_traversable->GetFocusSearch()->FindNextFocusableView(
507        starting_view,
508        reverse,
509        FocusSearch::DOWN,
510        false,
511        &new_focus_traversable,
512        &new_starting_view);
513  }
514  return v;
515}
516
517void FocusManager::RegisterAccelerator(
518    const ui::Accelerator& accelerator,
519    ui::AcceleratorManager::HandlerPriority priority,
520    ui::AcceleratorTarget* target) {
521  accelerator_manager_->Register(accelerator, priority, target);
522}
523
524void FocusManager::UnregisterAccelerator(const ui::Accelerator& accelerator,
525                                         ui::AcceleratorTarget* target) {
526  accelerator_manager_->Unregister(accelerator, target);
527}
528
529void FocusManager::UnregisterAccelerators(ui::AcceleratorTarget* target) {
530  accelerator_manager_->UnregisterAll(target);
531}
532
533bool FocusManager::ProcessAccelerator(const ui::Accelerator& accelerator) {
534  if (accelerator_manager_->Process(accelerator))
535    return true;
536  if (delegate_.get())
537    return delegate_->ProcessAccelerator(accelerator);
538  return false;
539}
540
541ui::AcceleratorTarget* FocusManager::GetCurrentTargetForAccelerator(
542    const ui::Accelerator& accelerator) const {
543  ui::AcceleratorTarget* target =
544      accelerator_manager_->GetCurrentTarget(accelerator);
545  if (!target && delegate_.get())
546    target = delegate_->GetCurrentTargetForAccelerator(accelerator);
547  return target;
548}
549
550bool FocusManager::HasPriorityHandler(
551    const ui::Accelerator& accelerator) const {
552  return accelerator_manager_->HasPriorityHandler(accelerator);
553}
554
555// static
556bool FocusManager::IsTabTraversalKeyEvent(const ui::KeyEvent& key_event) {
557  return key_event.key_code() == ui::VKEY_TAB && !key_event.IsControlDown();
558}
559
560void FocusManager::ViewRemoved(View* removed) {
561  // If the view being removed contains (or is) the focused view,
562  // clear the focus.  However, it's not safe to call ClearFocus()
563  // (and in turn ClearNativeFocus()) here because ViewRemoved() can
564  // be called while the top level widget is being destroyed.
565  if (focused_view_ && removed->Contains(focused_view_))
566    SetFocusedView(NULL);
567}
568
569void FocusManager::AddFocusChangeListener(FocusChangeListener* listener) {
570  focus_change_listeners_.AddObserver(listener);
571}
572
573void FocusManager::RemoveFocusChangeListener(FocusChangeListener* listener) {
574  focus_change_listeners_.RemoveObserver(listener);
575}
576
577bool FocusManager::ProcessArrowKeyTraversal(const ui::KeyEvent& event) {
578  if (event.IsShiftDown() || event.IsControlDown() || event.IsAltDown())
579    return false;
580
581  const int key_code = event.key_code();
582  if (key_code == ui::VKEY_LEFT || key_code == ui::VKEY_UP) {
583    AdvanceFocus(true);
584    return true;
585  }
586  if (key_code == ui::VKEY_RIGHT || key_code == ui::VKEY_DOWN) {
587    AdvanceFocus(false);
588    return true;
589  }
590
591  return false;
592}
593
594}  // namespace views
595