Home | History | Annotate | Download | only in maximize_mode
      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/maximize_mode/maximize_mode_window_manager.h"
      6 
      7 #include "ash/root_window_controller.h"
      8 #include "ash/shell.h"
      9 #include "ash/shell_window_ids.h"
     10 #include "ash/wm/maximize_mode/maximize_mode_window_state.h"
     11 #include "ash/wm/maximize_mode/workspace_backdrop_delegate.h"
     12 #include "ash/wm/mru_window_tracker.h"
     13 #include "ash/wm/overview/window_selector_controller.h"
     14 #include "ash/wm/window_state.h"
     15 #include "ash/wm/window_util.h"
     16 #include "ash/wm/wm_event.h"
     17 #include "ash/wm/workspace_controller.h"
     18 #include "ui/aura/window.h"
     19 #include "ui/gfx/screen.h"
     20 
     21 namespace ash {
     22 
     23 namespace {
     24 
     25 // The height of the area in which a touch operation leads to exiting the
     26 // full screen mode.
     27 const int kLeaveFullScreenAreaHeightInPixel = 2;
     28 
     29 // Exits overview mode if it is currently active.
     30 void CancelOverview() {
     31   WindowSelectorController* controller =
     32       Shell::GetInstance()->window_selector_controller();
     33   if (controller && controller->IsSelecting())
     34     controller->OnSelectionEnded();
     35 }
     36 
     37 }  // namespace
     38 
     39 MaximizeModeWindowManager::~MaximizeModeWindowManager() {
     40   // Overview mode needs to be ended before exiting maximize mode to prevent
     41   // transforming windows which are currently in
     42   // overview: http://crbug.com/366605
     43   CancelOverview();
     44 
     45   Shell::GetInstance()->RemovePreTargetHandler(this);
     46   Shell::GetInstance()->RemoveShellObserver(this);
     47   Shell::GetScreen()->RemoveObserver(this);
     48   EnableBackdropBehindTopWindowOnEachDisplay(false);
     49   RemoveWindowCreationObservers();
     50   RestoreAllWindows();
     51 }
     52 
     53 int MaximizeModeWindowManager::GetNumberOfManagedWindows() {
     54   return window_state_map_.size();
     55 }
     56 
     57 void MaximizeModeWindowManager::AddWindow(aura::Window* window) {
     58   // Only add the window if it is a direct dependent of a container window
     59   // and not yet tracked.
     60   if (!ShouldHandleWindow(window) ||
     61       window_state_map_.find(window) != window_state_map_.end() ||
     62       !IsContainerWindow(window->parent())) {
     63     return;
     64   }
     65 
     66   MaximizeAndTrackWindow(window);
     67 }
     68 
     69 void MaximizeModeWindowManager::WindowStateDestroyed(aura::Window* window) {
     70   // At this time ForgetWindow() should already have been called. If not,
     71   // someone else must have replaced the "window manager's state object".
     72   DCHECK(!window->HasObserver(this));
     73 
     74   WindowToState::iterator it = window_state_map_.find(window);
     75   DCHECK(it != window_state_map_.end());
     76   window_state_map_.erase(it);
     77 }
     78 
     79 void MaximizeModeWindowManager::OnOverviewModeStarting() {
     80   if (backdrops_hidden_)
     81     return;
     82 
     83   EnableBackdropBehindTopWindowOnEachDisplay(false);
     84   backdrops_hidden_ = true;
     85 }
     86 
     87 void MaximizeModeWindowManager::OnOverviewModeEnding() {
     88   if (!backdrops_hidden_)
     89     return;
     90 
     91   backdrops_hidden_ = false;
     92   EnableBackdropBehindTopWindowOnEachDisplay(true);
     93 }
     94 
     95 void MaximizeModeWindowManager::OnWindowDestroying(aura::Window* window) {
     96   // If a known window gets destroyed we need to remove all knowledge about it.
     97   if (!IsContainerWindow(window))
     98     ForgetWindow(window);
     99 }
    100 
    101 void MaximizeModeWindowManager::OnWindowAdded(aura::Window* window) {
    102   // A window can get removed and then re-added by a drag and drop operation.
    103   if (IsContainerWindow(window->parent()) &&
    104       window_state_map_.find(window) == window_state_map_.end()) {
    105     MaximizeAndTrackWindow(window);
    106     // When the state got added, the "WM_EVENT_ADDED_TO_WORKSPACE" event got
    107     // already sent and we have to notify our state again.
    108     if (window_state_map_.find(window) != window_state_map_.end()) {
    109       wm::WMEvent event(wm::WM_EVENT_ADDED_TO_WORKSPACE);
    110       wm::GetWindowState(window)->OnWMEvent(&event);
    111     }
    112   }
    113 }
    114 
    115 void MaximizeModeWindowManager::OnWindowBoundsChanged(
    116     aura::Window* window,
    117     const gfx::Rect& old_bounds,
    118     const gfx::Rect& new_bounds) {
    119   if (!IsContainerWindow(window))
    120     return;
    121   // Reposition all non maximizeable windows.
    122   for (WindowToState::iterator it = window_state_map_.begin();
    123        it != window_state_map_.end();
    124        ++it) {
    125     it->second->UpdateWindowPosition(wm::GetWindowState(it->first), false);
    126   }
    127 }
    128 
    129 void MaximizeModeWindowManager::OnDisplayAdded(const gfx::Display& display) {
    130   DisplayConfigurationChanged();
    131 }
    132 
    133 void MaximizeModeWindowManager::OnDisplayRemoved(const gfx::Display& display) {
    134   DisplayConfigurationChanged();
    135 }
    136 
    137 void MaximizeModeWindowManager::OnDisplayMetricsChanged(const gfx::Display&,
    138                                                         uint32_t) {
    139   // Nothing to do here.
    140 }
    141 
    142 void MaximizeModeWindowManager::OnTouchEvent(ui::TouchEvent* event) {
    143   if (event->type() != ui::ET_TOUCH_PRESSED)
    144     return;
    145 
    146   // Find the active window (from the primary screen) to un-fullscreen.
    147   aura::Window* window = wm::GetActiveWindow();
    148   if (!window)
    149     return;
    150 
    151   wm::WindowState* window_state = wm::GetWindowState(window);
    152   if (!window_state->IsFullscreen() || window_state->in_immersive_fullscreen())
    153     return;
    154 
    155   // Test that the touch happened in the top or bottom lines.
    156   int y = event->y();
    157   if (y >= kLeaveFullScreenAreaHeightInPixel &&
    158       y < (window->bounds().height() - kLeaveFullScreenAreaHeightInPixel)) {
    159     return;
    160   }
    161 
    162   // Leave full screen mode.
    163   event->StopPropagation();
    164   wm::WMEvent toggle_fullscreen(wm::WM_EVENT_TOGGLE_FULLSCREEN);
    165   window_state->OnWMEvent(&toggle_fullscreen);
    166 }
    167 
    168 MaximizeModeWindowManager::MaximizeModeWindowManager()
    169       : backdrops_hidden_(false) {
    170   // The overview mode needs to be ended before the maximize mode is started. To
    171   // guarantee the proper order, it will be turned off from here.
    172   CancelOverview();
    173 
    174   MaximizeAllWindows();
    175   AddWindowCreationObservers();
    176   EnableBackdropBehindTopWindowOnEachDisplay(true);
    177   Shell::GetScreen()->AddObserver(this);
    178   Shell::GetInstance()->AddShellObserver(this);
    179   Shell::GetInstance()->AddPreTargetHandler(this);
    180 }
    181 
    182 void MaximizeModeWindowManager::MaximizeAllWindows() {
    183   MruWindowTracker::WindowList windows =
    184       MruWindowTracker::BuildWindowList(false);
    185   // Add all existing Mru windows.
    186   for (MruWindowTracker::WindowList::iterator window = windows.begin();
    187       window != windows.end(); ++window) {
    188     MaximizeAndTrackWindow(*window);
    189   }
    190 }
    191 
    192 void MaximizeModeWindowManager::RestoreAllWindows() {
    193   while (window_state_map_.size())
    194     ForgetWindow(window_state_map_.begin()->first);
    195 }
    196 
    197 void MaximizeModeWindowManager::MaximizeAndTrackWindow(
    198     aura::Window* window) {
    199   if (!ShouldHandleWindow(window))
    200     return;
    201 
    202   DCHECK(window_state_map_.find(window) == window_state_map_.end());
    203   window->AddObserver(this);
    204 
    205   // We create and remember a maximize mode state which will attach itself to
    206   // the provided state object.
    207   window_state_map_[window] = new MaximizeModeWindowState(window, this);
    208 }
    209 
    210 void MaximizeModeWindowManager::ForgetWindow(aura::Window* window) {
    211   WindowToState::iterator it = window_state_map_.find(window);
    212 
    213   // The following DCHECK could fail if our window state object was destroyed
    214   // earlier by someone else. However - at this point there is no other client
    215   // which replaces the state object and therefore this should not happen.
    216   DCHECK(it != window_state_map_.end());
    217   window->RemoveObserver(this);
    218 
    219   // By telling the state object to revert, it will switch back the old
    220   // State object and destroy itself, calling WindowStateDerstroyed().
    221   it->second->LeaveMaximizeMode(wm::GetWindowState(it->first));
    222   DCHECK(window_state_map_.find(window) == window_state_map_.end());
    223 }
    224 
    225 bool MaximizeModeWindowManager::ShouldHandleWindow(aura::Window* window) {
    226   DCHECK(window);
    227   return window->type() == ui::wm::WINDOW_TYPE_NORMAL;
    228 }
    229 
    230 void MaximizeModeWindowManager::AddWindowCreationObservers() {
    231   DCHECK(observed_container_windows_.empty());
    232   // Observe window activations/creations in the default containers on all root
    233   // windows.
    234   aura::Window::Windows root_windows = Shell::GetAllRootWindows();
    235   for (aura::Window::Windows::const_iterator iter = root_windows.begin();
    236        iter != root_windows.end(); ++iter) {
    237     aura::Window* container =
    238         Shell::GetContainer(*iter, kShellWindowId_DefaultContainer);
    239     DCHECK(observed_container_windows_.find(container) ==
    240               observed_container_windows_.end());
    241     container->AddObserver(this);
    242     observed_container_windows_.insert(container);
    243   }
    244 }
    245 
    246 void MaximizeModeWindowManager::RemoveWindowCreationObservers() {
    247   for (std::set<aura::Window*>::iterator iter =
    248            observed_container_windows_.begin();
    249        iter != observed_container_windows_.end(); ++iter) {
    250     (*iter)->RemoveObserver(this);
    251   }
    252   observed_container_windows_.clear();
    253 }
    254 
    255 void MaximizeModeWindowManager::DisplayConfigurationChanged() {
    256   EnableBackdropBehindTopWindowOnEachDisplay(false);
    257   RemoveWindowCreationObservers();
    258   AddWindowCreationObservers();
    259   EnableBackdropBehindTopWindowOnEachDisplay(true);
    260 }
    261 
    262 bool MaximizeModeWindowManager::IsContainerWindow(aura::Window* window) {
    263   return observed_container_windows_.find(window) !=
    264              observed_container_windows_.end();
    265 }
    266 
    267 void MaximizeModeWindowManager::EnableBackdropBehindTopWindowOnEachDisplay(
    268     bool enable) {
    269   if (backdrops_hidden_)
    270     return;
    271   // Inform the WorkspaceLayoutManager that we want to show a backdrop behind
    272   // the topmost window of its container.
    273   Shell::RootWindowControllerList controllers =
    274       Shell::GetAllRootWindowControllers();
    275   for (Shell::RootWindowControllerList::iterator iter = controllers.begin();
    276        iter != controllers.end(); ++iter) {
    277     RootWindowController* controller = *iter;
    278     aura::Window* container = Shell::GetContainer(
    279         controller->GetRootWindow(), kShellWindowId_DefaultContainer);
    280     controller->workspace_controller()->SetMaximizeBackdropDelegate(
    281         scoped_ptr<WorkspaceLayoutManagerDelegate>(
    282             enable ? new WorkspaceBackdropDelegate(container) : NULL));
    283   }
    284 }
    285 
    286 }  // namespace ash
    287