Home | History | Annotate | Download | only in wm
      1 // Copyright 2013 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/mru_window_tracker.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/activation_controller.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 // List of containers whose children we will allow switching to.
     25 const int kContainerIds[] = {
     26   internal::kShellWindowId_DefaultContainer,
     27   internal::kShellWindowId_AlwaysOnTopContainer
     28 };
     29 
     30 // Adds the windows that can be cycled through for the specified window id to
     31 // |windows|.
     32 void AddTrackedWindows(aura::RootWindow* root,
     33                      int container_id,
     34                      MruWindowTracker::WindowList* windows) {
     35   aura::Window* container = Shell::GetContainer(root, container_id);
     36   const MruWindowTracker::WindowList& children(container->children());
     37   windows->insert(windows->end(), children.begin(), children.end());
     38 }
     39 
     40 // Returns a list of windows ordered by their stacking order.
     41 // If |mru_windows| is passed, these windows are moved to the front of the list.
     42 // If |top_most_at_end|, the list is returned in descending (bottom-most / least
     43 // recently used) order.
     44 MruWindowTracker::WindowList BuildWindowListInternal(
     45     const std::list<aura::Window*>* mru_windows,
     46     bool top_most_at_end) {
     47   MruWindowTracker::WindowList windows;
     48   Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
     49 
     50   aura::RootWindow* active_root = Shell::GetActiveRootWindow();
     51   for (Shell::RootWindowList::const_iterator iter = root_windows.begin();
     52        iter != root_windows.end(); ++iter) {
     53     if (*iter == active_root)
     54       continue;
     55     for (size_t i = 0; i < arraysize(kContainerIds); ++i)
     56       AddTrackedWindows(*iter, kContainerIds[i], &windows);
     57   }
     58 
     59   // Add windows in the active root windows last so that the topmost window
     60   // in the active root window becomes the front of the list.
     61   for (size_t i = 0; i < arraysize(kContainerIds); ++i)
     62     AddTrackedWindows(active_root, kContainerIds[i], &windows);
     63 
     64   // Removes unfocusable windows.
     65   MruWindowTracker::WindowList::iterator last =
     66       std::remove_if(
     67           windows.begin(),
     68           windows.end(),
     69           std::not1(std::ptr_fun(ash::wm::CanActivateWindow)));
     70   windows.erase(last, windows.end());
     71 
     72   // Put the windows in the mru_windows list at the head, if it's available.
     73   if (mru_windows) {
     74     // Iterate through the list backwards, so that we can move each window to
     75     // the front of the windows list as we find them.
     76     for (std::list<aura::Window*>::const_reverse_iterator ix =
     77          mru_windows->rbegin();
     78          ix != mru_windows->rend(); ++ix) {
     79       MruWindowTracker::WindowList::iterator window =
     80           std::find(windows.begin(), windows.end(), *ix);
     81       if (window != windows.end()) {
     82         windows.erase(window);
     83         windows.push_back(*ix);
     84       }
     85     }
     86   }
     87 
     88   // Window cycling expects the topmost window at the front of the list.
     89   if (!top_most_at_end)
     90     std::reverse(windows.begin(), windows.end());
     91 
     92   return windows;
     93 }
     94 
     95 }  // namespace
     96 
     97 //////////////////////////////////////////////////////////////////////////////
     98 // MruWindowTracker, public:
     99 
    100 MruWindowTracker::MruWindowTracker(
    101     aura::client::ActivationClient* activation_client)
    102     : activation_client_(activation_client),
    103       ignore_window_activations_(false) {
    104   activation_client_->AddObserver(this);
    105 }
    106 
    107 MruWindowTracker::~MruWindowTracker() {
    108   Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
    109   for (Shell::RootWindowList::const_iterator iter = root_windows.begin();
    110        iter != root_windows.end(); ++iter) {
    111     for (size_t i = 0; i < arraysize(kContainerIds); ++i) {
    112       aura::Window* container = Shell::GetContainer(*iter, kContainerIds[i]);
    113       if (container)
    114         container->RemoveObserver(this);
    115     }
    116   }
    117 
    118   activation_client_->RemoveObserver(this);
    119 }
    120 
    121 // static
    122 MruWindowTracker::WindowList MruWindowTracker::BuildWindowList(
    123     bool top_most_at_end) {
    124   return BuildWindowListInternal(NULL, top_most_at_end);
    125 }
    126 
    127 MruWindowTracker::WindowList MruWindowTracker::BuildMruWindowList() {
    128   return BuildWindowListInternal(&mru_windows_, false);
    129 }
    130 
    131 void MruWindowTracker::OnRootWindowAdded(aura::RootWindow* root_window) {
    132   for (size_t i = 0; i < arraysize(kContainerIds); ++i) {
    133     aura::Window* container =
    134         Shell::GetContainer(root_window, kContainerIds[i]);
    135     container->AddObserver(this);
    136   }
    137 }
    138 
    139 void MruWindowTracker::SetIgnoreActivations(bool ignore) {
    140   ignore_window_activations_ = ignore;
    141 
    142   // If no longer ignoring window activations, move currently active window
    143   // to front.
    144   if (!ignore) {
    145     aura::Window* active_window = wm::GetActiveWindow();
    146     mru_windows_.remove(active_window);
    147     mru_windows_.push_front(active_window);
    148   }
    149 }
    150 
    151 //////////////////////////////////////////////////////////////////////////////
    152 // MruWindowTracker, private:
    153 
    154 // static
    155 bool MruWindowTracker::IsTrackedContainer(aura::Window* window) {
    156   if (!window)
    157     return false;
    158   for (size_t i = 0; i < arraysize(kContainerIds); ++i) {
    159     if (window->id() == kContainerIds[i])
    160       return true;
    161   }
    162   return false;
    163 }
    164 
    165 void MruWindowTracker::OnWindowActivated(aura::Window* gained_active,
    166                                          aura::Window* lost_active) {
    167   if (gained_active && !ignore_window_activations_ &&
    168       IsTrackedContainer(gained_active->parent())) {
    169     mru_windows_.remove(gained_active);
    170     mru_windows_.push_front(gained_active);
    171   }
    172 }
    173 
    174 void MruWindowTracker::OnWillRemoveWindow(aura::Window* window) {
    175   mru_windows_.remove(window);
    176 }
    177 
    178 void MruWindowTracker::OnWindowDestroying(aura::Window* window) {
    179   window->RemoveObserver(this);
    180 }
    181 
    182 }  // namespace ash
    183