1// Copyright 2014 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 "ash/wm/window_cycle_controller.h"
6
7#include "ash/session/session_state_delegate.h"
8#include "ash/shell.h"
9#include "ash/wm/mru_window_tracker.h"
10#include "ash/wm/window_cycle_list.h"
11#include "base/metrics/histogram.h"
12#include "ui/events/event.h"
13#include "ui/events/event_handler.h"
14
15namespace ash {
16
17namespace {
18
19// Filter to watch for the termination of a keyboard gesture to cycle through
20// multiple windows.
21class WindowCycleEventFilter : public ui::EventHandler {
22 public:
23  WindowCycleEventFilter();
24  virtual ~WindowCycleEventFilter();
25
26  // Overridden from ui::EventHandler:
27  virtual void OnKeyEvent(ui::KeyEvent* event) OVERRIDE;
28
29 private:
30  DISALLOW_COPY_AND_ASSIGN(WindowCycleEventFilter);
31};
32
33WindowCycleEventFilter::WindowCycleEventFilter() {
34  Shell::GetInstance()->AddPreTargetHandler(this);
35}
36
37WindowCycleEventFilter::~WindowCycleEventFilter() {
38  Shell::GetInstance()->RemovePreTargetHandler(this);
39}
40
41void WindowCycleEventFilter::OnKeyEvent(ui::KeyEvent* event) {
42  // Views uses VKEY_MENU for both left and right Alt keys.
43  if (event->key_code() == ui::VKEY_MENU &&
44      event->type() == ui::ET_KEY_RELEASED) {
45    Shell::GetInstance()->window_cycle_controller()->StopCycling();
46    // Warning: |this| will be deleted from here on.
47  }
48}
49
50}  // namespace
51
52//////////////////////////////////////////////////////////////////////////////
53// WindowCycleController, public:
54
55WindowCycleController::WindowCycleController() {
56}
57
58WindowCycleController::~WindowCycleController() {
59}
60
61// static
62bool WindowCycleController::CanCycle() {
63  // Don't allow window cycling if the screen is locked or a modal dialog is
64  // open.
65  return !Shell::GetInstance()->session_state_delegate()->IsScreenLocked() &&
66         !Shell::GetInstance()->IsSystemModalWindowOpen();
67}
68
69void WindowCycleController::HandleCycleWindow(Direction direction) {
70  if (!CanCycle())
71    return;
72
73  if (!IsCycling())
74    StartCycling();
75
76  Step(direction);
77}
78
79void WindowCycleController::StartCycling() {
80  window_cycle_list_.reset(new WindowCycleList(ash::Shell::GetInstance()->
81      mru_window_tracker()->BuildMruWindowList()));
82  event_handler_.reset(new WindowCycleEventFilter());
83  cycle_start_time_ = base::Time::Now();
84  Shell::GetInstance()->metrics()->RecordUserMetricsAction(UMA_WINDOW_CYCLE);
85}
86
87//////////////////////////////////////////////////////////////////////////////
88// WindowCycleController, private:
89
90void WindowCycleController::Step(Direction direction) {
91  DCHECK(window_cycle_list_.get());
92  window_cycle_list_->Step(direction);
93}
94
95void WindowCycleController::StopCycling() {
96  window_cycle_list_.reset();
97  // Remove our key event filter.
98  event_handler_.reset();
99  UMA_HISTOGRAM_MEDIUM_TIMES("Ash.WindowCycleController.CycleTime",
100                             base::Time::Now() - cycle_start_time_);
101}
102
103}  // namespace ash
104