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.
5 #include "ash/wm/maximize_mode/maximize_mode_window_manager.h"
7 #include "ash/root_window_controller.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"
25 // The height of the area in which a touch operation leads to exiting the
27 const int kLeaveFullScreenAreaHeightInPixel = 2;
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();
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
45 Shell::GetInstance()->RemovePreTargetHandler(this);
46 Shell::GetInstance()->RemoveShellObserver(this);
47 Shell::GetScreen()->RemoveObserver(this);
48 EnableBackdropBehindTopWindowOnEachDisplay(false);
49 RemoveWindowCreationObservers();
53 int MaximizeModeWindowManager::GetNumberOfManagedWindows() {
54 return window_state_map_.size();
57 void MaximizeModeWindowManager::WindowStateDestroyed(aura::Window* window) {
58 // At this time ForgetWindow() should already have been called. If not,
59 // someone else must have replaced the "window manager's state object".
60 DCHECK(!window->HasObserver(this));
62 WindowToState::iterator it = window_state_map_.find(window);
63 DCHECK(it != window_state_map_.end());
64 window_state_map_.erase(it);
67 void MaximizeModeWindowManager::OnOverviewModeStarting() {
68 if (backdrops_hidden_)
71 EnableBackdropBehindTopWindowOnEachDisplay(false);
72 backdrops_hidden_ = true;
75 void MaximizeModeWindowManager::OnOverviewModeEnding() {
76 if (!backdrops_hidden_)
79 backdrops_hidden_ = false;
80 EnableBackdropBehindTopWindowOnEachDisplay(true);
83 void MaximizeModeWindowManager::OnWindowDestroying(aura::Window* window) {
84 // If a known window gets destroyed we need to remove all knowledge about it.
85 if (!IsContainerWindow(window))
89 void MaximizeModeWindowManager::OnWindowAdded(aura::Window* window) {
90 // A window can get removed and then re-added by a drag and drop operation.
91 if (IsContainerWindow(window->parent()) &&
92 window_state_map_.find(window) == window_state_map_.end()) {
93 MaximizeAndTrackWindow(window);
94 // When the state got added, the "WM_EVENT_ADDED_TO_WORKSPACE" event got
95 // already sent and we have to notify our state again.
96 if (window_state_map_.find(window) != window_state_map_.end()) {
97 wm::WMEvent event(wm::WM_EVENT_ADDED_TO_WORKSPACE);
98 wm::GetWindowState(window)->OnWMEvent(&event);
103 void MaximizeModeWindowManager::OnWindowBoundsChanged(
104 aura::Window* window,
105 const gfx::Rect& old_bounds,
106 const gfx::Rect& new_bounds) {
107 if (!IsContainerWindow(window))
109 // Reposition all non maximizeable windows.
110 for (WindowToState::iterator it = window_state_map_.begin();
111 it != window_state_map_.end();
113 it->second->UpdateWindowPosition(wm::GetWindowState(it->first), false);
117 void MaximizeModeWindowManager::OnDisplayAdded(const gfx::Display& display) {
118 DisplayConfigurationChanged();
121 void MaximizeModeWindowManager::OnDisplayRemoved(const gfx::Display& display) {
122 DisplayConfigurationChanged();
125 void MaximizeModeWindowManager::OnDisplayMetricsChanged(const gfx::Display&,
127 // Nothing to do here.
130 void MaximizeModeWindowManager::OnTouchEvent(ui::TouchEvent* event) {
131 if (event->type() != ui::ET_TOUCH_PRESSED)
134 // Find the active window (from the primary screen) to un-fullscreen.
135 aura::Window* window = wm::GetActiveWindow();
139 wm::WindowState* window_state = wm::GetWindowState(window);
140 if (!window_state->IsFullscreen() || window_state->in_immersive_fullscreen())
143 // Test that the touch happened in the top or bottom lines.
145 if (y >= kLeaveFullScreenAreaHeightInPixel &&
146 y < (window->bounds().height() - kLeaveFullScreenAreaHeightInPixel)) {
150 // Leave full screen mode.
151 event->StopPropagation();
152 wm::WMEvent toggle_fullscreen(wm::WM_EVENT_TOGGLE_FULLSCREEN);
153 window_state->OnWMEvent(&toggle_fullscreen);
156 MaximizeModeWindowManager::MaximizeModeWindowManager()
157 : backdrops_hidden_(false) {
158 // The overview mode needs to be ended before the maximize mode is started. To
159 // guarantee the proper order, it will be turned off from here.
162 MaximizeAllWindows();
163 AddWindowCreationObservers();
164 EnableBackdropBehindTopWindowOnEachDisplay(true);
165 Shell::GetScreen()->AddObserver(this);
166 Shell::GetInstance()->AddShellObserver(this);
167 Shell::GetInstance()->AddPreTargetHandler(this);
170 void MaximizeModeWindowManager::MaximizeAllWindows() {
171 MruWindowTracker::WindowList windows =
172 MruWindowTracker::BuildWindowList(false);
173 // Add all existing Mru windows.
174 for (MruWindowTracker::WindowList::iterator window = windows.begin();
175 window != windows.end(); ++window) {
176 MaximizeAndTrackWindow(*window);
180 void MaximizeModeWindowManager::RestoreAllWindows() {
181 while (window_state_map_.size())
182 ForgetWindow(window_state_map_.begin()->first);
185 void MaximizeModeWindowManager::MaximizeAndTrackWindow(
186 aura::Window* window) {
187 if (!ShouldHandleWindow(window))
190 DCHECK(window_state_map_.find(window) == window_state_map_.end());
191 window->AddObserver(this);
193 // We create and remember a maximize mode state which will attach itself to
194 // the provided state object.
195 window_state_map_[window] = new MaximizeModeWindowState(window, this);
198 void MaximizeModeWindowManager::ForgetWindow(aura::Window* window) {
199 WindowToState::iterator it = window_state_map_.find(window);
201 // The following DCHECK could fail if our window state object was destroyed
202 // earlier by someone else. However - at this point there is no other client
203 // which replaces the state object and therefore this should not happen.
204 DCHECK(it != window_state_map_.end());
205 window->RemoveObserver(this);
207 // By telling the state object to revert, it will switch back the old
208 // State object and destroy itself, calling WindowStateDerstroyed().
209 it->second->LeaveMaximizeMode(wm::GetWindowState(it->first));
210 DCHECK(window_state_map_.find(window) == window_state_map_.end());
213 bool MaximizeModeWindowManager::ShouldHandleWindow(aura::Window* window) {
215 return window->type() == ui::wm::WINDOW_TYPE_NORMAL;
218 void MaximizeModeWindowManager::AddWindowCreationObservers() {
219 DCHECK(observed_container_windows_.empty());
220 // Observe window activations/creations in the default containers on all root
222 aura::Window::Windows root_windows = Shell::GetAllRootWindows();
223 for (aura::Window::Windows::const_iterator iter = root_windows.begin();
224 iter != root_windows.end(); ++iter) {
225 aura::Window* container =
226 Shell::GetContainer(*iter, kShellWindowId_DefaultContainer);
227 DCHECK(observed_container_windows_.find(container) ==
228 observed_container_windows_.end());
229 container->AddObserver(this);
230 observed_container_windows_.insert(container);
234 void MaximizeModeWindowManager::RemoveWindowCreationObservers() {
235 for (std::set<aura::Window*>::iterator iter =
236 observed_container_windows_.begin();
237 iter != observed_container_windows_.end(); ++iter) {
238 (*iter)->RemoveObserver(this);
240 observed_container_windows_.clear();
243 void MaximizeModeWindowManager::DisplayConfigurationChanged() {
244 EnableBackdropBehindTopWindowOnEachDisplay(false);
245 RemoveWindowCreationObservers();
246 AddWindowCreationObservers();
247 EnableBackdropBehindTopWindowOnEachDisplay(true);
250 bool MaximizeModeWindowManager::IsContainerWindow(aura::Window* window) {
251 return observed_container_windows_.find(window) !=
252 observed_container_windows_.end();
255 void MaximizeModeWindowManager::EnableBackdropBehindTopWindowOnEachDisplay(
257 if (backdrops_hidden_)
259 // Inform the WorkspaceLayoutManager that we want to show a backdrop behind
260 // the topmost window of its container.
261 Shell::RootWindowControllerList controllers =
262 Shell::GetAllRootWindowControllers();
263 for (Shell::RootWindowControllerList::iterator iter = controllers.begin();
264 iter != controllers.end(); ++iter) {
265 RootWindowController* controller = *iter;
266 aura::Window* container = Shell::GetContainer(
267 controller->GetRootWindow(), kShellWindowId_DefaultContainer);
268 controller->workspace_controller()->SetMaximizeBackdropDelegate(
269 scoped_ptr<WorkspaceLayoutManagerDelegate>(
270 enable ? new WorkspaceBackdropDelegate(container) : NULL));