Home | History | Annotate | Download | only in wm
      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 "ash/wm/window_cycle_controller.h"
      6 
      7 #include <algorithm>
      8 
      9 #include "ash/session_state_delegate.h"
     10 #include "ash/shell.h"
     11 #include "ash/shell_window_ids.h"
     12 #include "ash/wm/mru_window_tracker.h"
     13 #include "ash/wm/window_cycle_list.h"
     14 #include "ash/wm/window_util.h"
     15 #include "ash/wm/workspace_controller.h"
     16 #include "ui/aura/root_window.h"
     17 #include "ui/base/events/event.h"
     18 #include "ui/base/events/event_handler.h"
     19 
     20 namespace ash {
     21 
     22 namespace {
     23 
     24 // Filter to watch for the termination of a keyboard gesture to cycle through
     25 // multiple windows.
     26 class WindowCycleEventFilter : public ui::EventHandler {
     27  public:
     28   WindowCycleEventFilter();
     29   virtual ~WindowCycleEventFilter();
     30 
     31   // Overridden from ui::EventHandler:
     32   virtual void OnKeyEvent(ui::KeyEvent* event) OVERRIDE;
     33  private:
     34   DISALLOW_COPY_AND_ASSIGN(WindowCycleEventFilter);
     35 };
     36 
     37 // Watch for all keyboard events by filtering the root window.
     38 WindowCycleEventFilter::WindowCycleEventFilter() {
     39 }
     40 
     41 WindowCycleEventFilter::~WindowCycleEventFilter() {
     42 }
     43 
     44 void WindowCycleEventFilter::OnKeyEvent(ui::KeyEvent* event) {
     45   // Views uses VKEY_MENU for both left and right Alt keys.
     46   if (event->key_code() == ui::VKEY_MENU &&
     47       event->type() == ui::ET_KEY_RELEASED) {
     48     Shell::GetInstance()->window_cycle_controller()->AltKeyReleased();
     49     // Warning: |this| will be deleted from here on.
     50   }
     51 }
     52 
     53 }  // namespace
     54 
     55 //////////////////////////////////////////////////////////////////////////////
     56 // WindowCycleController, public:
     57 
     58 WindowCycleController::WindowCycleController() {
     59 }
     60 
     61 WindowCycleController::~WindowCycleController() {
     62   StopCycling();
     63 }
     64 
     65 // static
     66 bool WindowCycleController::CanCycle() {
     67   // Don't allow window cycling if the screen is locked or a modal dialog is
     68   // open.
     69   return !Shell::GetInstance()->session_state_delegate()->IsScreenLocked() &&
     70          !Shell::GetInstance()->IsSystemModalWindowOpen();
     71 }
     72 
     73 void WindowCycleController::HandleCycleWindow(Direction direction,
     74                                               bool is_alt_down) {
     75   if (!CanCycle())
     76     return;
     77 
     78   if (is_alt_down) {
     79     if (!IsCycling()) {
     80       // This is the start of an alt-tab cycle through multiple windows, so
     81       // listen for the alt key being released to stop cycling.
     82       StartCycling();
     83       Step(direction);
     84       InstallEventFilter();
     85     } else {
     86       // We're in the middle of an alt-tab cycle, just step forward.
     87       Step(direction);
     88     }
     89   } else {
     90     // This is a simple, single-step window cycle.
     91     StartCycling();
     92     Step(direction);
     93     StopCycling();
     94   }
     95 }
     96 
     97 void WindowCycleController::HandleLinearCycleWindow() {
     98   if (!CanCycle() || IsCycling())
     99     return;
    100 
    101   // Use the reversed list of windows to prevent a 2-cycle of the most recent
    102   // windows occurring.
    103   WindowCycleList cycle_list(MruWindowTracker::BuildWindowList(true));
    104   cycle_list.Step(WindowCycleList::FORWARD);
    105 }
    106 
    107 void WindowCycleController::AltKeyReleased() {
    108   StopCycling();
    109 }
    110 
    111 //////////////////////////////////////////////////////////////////////////////
    112 // WindowCycleController, private:
    113 
    114 void WindowCycleController::StartCycling() {
    115   windows_.reset(new WindowCycleList(ash::Shell::GetInstance()->
    116       mru_window_tracker()->BuildMruWindowList()));
    117 }
    118 
    119 void WindowCycleController::Step(Direction direction) {
    120   DCHECK(windows_.get());
    121   windows_->Step(direction == FORWARD ? WindowCycleList::FORWARD :
    122                  WindowCycleList::BACKWARD);
    123 }
    124 
    125 void WindowCycleController::StopCycling() {
    126   windows_.reset();
    127   // Remove our key event filter.
    128   if (event_handler_) {
    129     Shell::GetInstance()->RemovePreTargetHandler(event_handler_.get());
    130     event_handler_.reset();
    131   }
    132 }
    133 
    134 void WindowCycleController::InstallEventFilter() {
    135   event_handler_.reset(new WindowCycleEventFilter());
    136   Shell::GetInstance()->AddPreTargetHandler(event_handler_.get());
    137 }
    138 
    139 }  // namespace ash
    140