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::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())) {
66 MaximizeAndTrackWindow(window
);
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));
74 WindowToState::iterator it
= window_state_map_
.find(window
);
75 DCHECK(it
!= window_state_map_
.end());
76 window_state_map_
.erase(it
);
79 void MaximizeModeWindowManager::OnOverviewModeStarting() {
80 if (backdrops_hidden_
)
83 EnableBackdropBehindTopWindowOnEachDisplay(false);
84 SetDeferBoundsUpdates(true);
85 backdrops_hidden_
= true;
88 void MaximizeModeWindowManager::OnOverviewModeEnded() {
89 if (!backdrops_hidden_
)
92 backdrops_hidden_
= false;
93 EnableBackdropBehindTopWindowOnEachDisplay(true);
94 SetDeferBoundsUpdates(false);
97 void MaximizeModeWindowManager::OnWindowDestroying(aura::Window
* window
) {
98 // If a known window gets destroyed we need to remove all knowledge about it.
99 if (!IsContainerWindow(window
))
100 ForgetWindow(window
);
103 void MaximizeModeWindowManager::OnWindowAdded(aura::Window
* window
) {
104 // A window can get removed and then re-added by a drag and drop operation.
105 if (IsContainerWindow(window
->parent()) &&
106 window_state_map_
.find(window
) == window_state_map_
.end()) {
107 MaximizeAndTrackWindow(window
);
108 // When the state got added, the "WM_EVENT_ADDED_TO_WORKSPACE" event got
109 // already sent and we have to notify our state again.
110 if (window_state_map_
.find(window
) != window_state_map_
.end()) {
111 wm::WMEvent
event(wm::WM_EVENT_ADDED_TO_WORKSPACE
);
112 wm::GetWindowState(window
)->OnWMEvent(&event
);
117 void MaximizeModeWindowManager::OnWindowBoundsChanged(
118 aura::Window
* window
,
119 const gfx::Rect
& old_bounds
,
120 const gfx::Rect
& new_bounds
) {
121 if (!IsContainerWindow(window
))
123 // Reposition all non maximizeable windows.
124 for (WindowToState::iterator it
= window_state_map_
.begin();
125 it
!= window_state_map_
.end();
127 it
->second
->UpdateWindowPosition(wm::GetWindowState(it
->first
), false);
131 void MaximizeModeWindowManager::OnDisplayAdded(const gfx::Display
& display
) {
132 DisplayConfigurationChanged();
135 void MaximizeModeWindowManager::OnDisplayRemoved(const gfx::Display
& display
) {
136 DisplayConfigurationChanged();
139 void MaximizeModeWindowManager::OnDisplayMetricsChanged(const gfx::Display
&,
141 // Nothing to do here.
144 void MaximizeModeWindowManager::OnTouchEvent(ui::TouchEvent
* event
) {
145 if (event
->type() != ui::ET_TOUCH_PRESSED
)
148 // Find the active window (from the primary screen) to un-fullscreen.
149 aura::Window
* window
= wm::GetActiveWindow();
153 wm::WindowState
* window_state
= wm::GetWindowState(window
);
154 if (!window_state
->IsFullscreen() || window_state
->in_immersive_fullscreen())
157 // Test that the touch happened in the top or bottom lines.
159 if (y
>= kLeaveFullScreenAreaHeightInPixel
&&
160 y
< (window
->bounds().height() - kLeaveFullScreenAreaHeightInPixel
)) {
164 // Leave full screen mode.
165 event
->StopPropagation();
166 wm::WMEvent
toggle_fullscreen(wm::WM_EVENT_TOGGLE_FULLSCREEN
);
167 window_state
->OnWMEvent(&toggle_fullscreen
);
170 MaximizeModeWindowManager::MaximizeModeWindowManager()
171 : backdrops_hidden_(false) {
172 // The overview mode needs to be ended before the maximize mode is started. To
173 // guarantee the proper order, it will be turned off from here.
176 MaximizeAllWindows();
177 AddWindowCreationObservers();
178 EnableBackdropBehindTopWindowOnEachDisplay(true);
179 Shell::GetScreen()->AddObserver(this);
180 Shell::GetInstance()->AddShellObserver(this);
181 Shell::GetInstance()->AddPreTargetHandler(this);
184 void MaximizeModeWindowManager::MaximizeAllWindows() {
185 MruWindowTracker::WindowList windows
= ash::Shell::GetInstance()->
186 mru_window_tracker()->BuildWindowListIgnoreModal();
187 // Add all existing Mru windows.
188 for (MruWindowTracker::WindowList::iterator window
= windows
.begin();
189 window
!= windows
.end(); ++window
) {
190 MaximizeAndTrackWindow(*window
);
194 void MaximizeModeWindowManager::RestoreAllWindows() {
195 while (window_state_map_
.size())
196 ForgetWindow(window_state_map_
.begin()->first
);
199 void MaximizeModeWindowManager::SetDeferBoundsUpdates(
200 bool defer_bounds_updates
) {
201 for (WindowToState::iterator it
= window_state_map_
.begin();
202 it
!= window_state_map_
.end();
204 it
->second
->SetDeferBoundsUpdates(defer_bounds_updates
);
208 void MaximizeModeWindowManager::MaximizeAndTrackWindow(
209 aura::Window
* window
) {
210 if (!ShouldHandleWindow(window
))
213 DCHECK(window_state_map_
.find(window
) == window_state_map_
.end());
214 window
->AddObserver(this);
216 // We create and remember a maximize mode state which will attach itself to
217 // the provided state object.
218 window_state_map_
[window
] = new MaximizeModeWindowState(window
, this);
221 void MaximizeModeWindowManager::ForgetWindow(aura::Window
* window
) {
222 WindowToState::iterator it
= window_state_map_
.find(window
);
224 // The following DCHECK could fail if our window state object was destroyed
225 // earlier by someone else. However - at this point there is no other client
226 // which replaces the state object and therefore this should not happen.
227 DCHECK(it
!= window_state_map_
.end());
228 window
->RemoveObserver(this);
230 // By telling the state object to revert, it will switch back the old
231 // State object and destroy itself, calling WindowStateDerstroyed().
232 it
->second
->LeaveMaximizeMode(wm::GetWindowState(it
->first
));
233 DCHECK(window_state_map_
.find(window
) == window_state_map_
.end());
236 bool MaximizeModeWindowManager::ShouldHandleWindow(aura::Window
* window
) {
238 return window
->type() == ui::wm::WINDOW_TYPE_NORMAL
;
241 void MaximizeModeWindowManager::AddWindowCreationObservers() {
242 DCHECK(observed_container_windows_
.empty());
243 // Observe window activations/creations in the default containers on all root
245 aura::Window::Windows root_windows
= Shell::GetAllRootWindows();
246 for (aura::Window::Windows::const_iterator iter
= root_windows
.begin();
247 iter
!= root_windows
.end(); ++iter
) {
248 aura::Window
* container
=
249 Shell::GetContainer(*iter
, kShellWindowId_DefaultContainer
);
250 DCHECK(observed_container_windows_
.find(container
) ==
251 observed_container_windows_
.end());
252 container
->AddObserver(this);
253 observed_container_windows_
.insert(container
);
257 void MaximizeModeWindowManager::RemoveWindowCreationObservers() {
258 for (std::set
<aura::Window
*>::iterator iter
=
259 observed_container_windows_
.begin();
260 iter
!= observed_container_windows_
.end(); ++iter
) {
261 (*iter
)->RemoveObserver(this);
263 observed_container_windows_
.clear();
266 void MaximizeModeWindowManager::DisplayConfigurationChanged() {
267 EnableBackdropBehindTopWindowOnEachDisplay(false);
268 RemoveWindowCreationObservers();
269 AddWindowCreationObservers();
270 EnableBackdropBehindTopWindowOnEachDisplay(true);
273 bool MaximizeModeWindowManager::IsContainerWindow(aura::Window
* window
) {
274 return observed_container_windows_
.find(window
) !=
275 observed_container_windows_
.end();
278 void MaximizeModeWindowManager::EnableBackdropBehindTopWindowOnEachDisplay(
280 if (backdrops_hidden_
)
282 // Inform the WorkspaceLayoutManager that we want to show a backdrop behind
283 // the topmost window of its container.
284 Shell::RootWindowControllerList controllers
=
285 Shell::GetAllRootWindowControllers();
286 for (Shell::RootWindowControllerList::iterator iter
= controllers
.begin();
287 iter
!= controllers
.end(); ++iter
) {
288 RootWindowController
* controller
= *iter
;
289 aura::Window
* container
= Shell::GetContainer(
290 controller
->GetRootWindow(), kShellWindowId_DefaultContainer
);
291 controller
->workspace_controller()->SetMaximizeBackdropDelegate(
292 scoped_ptr
<WorkspaceLayoutManagerDelegate
>(
293 enable
? new WorkspaceBackdropDelegate(container
) : NULL
));