Upstream version 9.37.195.0
[platform/framework/web/crosswalk.git] / src / ash / wm / maximize_mode / maximize_mode_window_manager.cc
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