1 // Copyright (c) 2012 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/base_layout_manager.h"
7 #include "ash/screen_util.h"
8 #include "ash/session_state_delegate.h"
9 #include "ash/shelf/shelf_layout_manager.h"
10 #include "ash/shell.h"
11 #include "ash/wm/window_animations.h"
12 #include "ash/wm/window_properties.h"
13 #include "ash/wm/window_state.h"
14 #include "ash/wm/window_util.h"
15 #include "ash/wm/workspace/workspace_window_resizer.h"
16 #include "ui/aura/client/activation_client.h"
17 #include "ui/aura/client/aura_constants.h"
18 #include "ui/aura/window.h"
19 #include "ui/base/ui_base_types.h"
20 #include "ui/compositor/layer.h"
21 #include "ui/gfx/screen.h"
22 #include "ui/views/corewm/corewm_switches.h"
23 #include "ui/views/corewm/window_util.h"
28 /////////////////////////////////////////////////////////////////////////////
29 // BaseLayoutManager, public:
31 BaseLayoutManager::BaseLayoutManager(aura::Window* root_window)
32 : root_window_(root_window) {
33 Shell::GetInstance()->activation_client()->AddObserver(this);
34 Shell::GetInstance()->AddShellObserver(this);
35 root_window_->AddObserver(this);
38 BaseLayoutManager::~BaseLayoutManager() {
40 root_window_->RemoveObserver(this);
41 for (WindowSet::const_iterator i = windows_.begin(); i != windows_.end(); ++i)
42 (*i)->RemoveObserver(this);
43 Shell::GetInstance()->RemoveShellObserver(this);
44 Shell::GetInstance()->activation_client()->RemoveObserver(this);
48 gfx::Rect BaseLayoutManager::BoundsWithScreenEdgeVisible(
50 const gfx::Rect& restore_bounds) {
51 gfx::Rect max_bounds =
52 ash::ScreenUtil::GetMaximizedWindowBoundsInParent(window);
53 // If the restore_bounds are more than 1 grid step away from the size the
54 // window would be when maximized, inset it.
55 max_bounds.Inset(ash::internal::WorkspaceWindowResizer::kScreenEdgeInset,
56 ash::internal::WorkspaceWindowResizer::kScreenEdgeInset);
57 if (restore_bounds.Contains(max_bounds))
59 return restore_bounds;
62 /////////////////////////////////////////////////////////////////////////////
63 // BaseLayoutManager, aura::LayoutManager overrides:
65 void BaseLayoutManager::OnWindowResized() {
68 void BaseLayoutManager::OnWindowAddedToLayout(aura::Window* child) {
69 windows_.insert(child);
70 child->AddObserver(this);
71 wm::WindowState* window_state = wm::GetWindowState(child);
72 window_state->AddObserver(this);
74 // Only update the bounds if the window has a show state that depends on the
76 if (window_state->IsMaximizedOrFullscreen())
77 UpdateBoundsFromShowType(window_state);
80 void BaseLayoutManager::OnWillRemoveWindowFromLayout(aura::Window* child) {
81 windows_.erase(child);
82 child->RemoveObserver(this);
83 wm::GetWindowState(child)->RemoveObserver(this);
86 void BaseLayoutManager::OnWindowRemovedFromLayout(aura::Window* child) {
89 void BaseLayoutManager::OnChildWindowVisibilityChanged(aura::Window* child,
91 wm::WindowState* window_state = wm::GetWindowState(child);
92 // Attempting to show a minimized window. Unminimize it.
93 if (visible && window_state->IsMinimized())
94 window_state->Unminimize();
97 void BaseLayoutManager::SetChildBounds(aura::Window* child,
98 const gfx::Rect& requested_bounds) {
99 gfx::Rect child_bounds(requested_bounds);
100 wm::WindowState* window_state = wm::GetWindowState(child);
101 // Some windows rely on this to set their initial bounds.
102 if (window_state->IsMaximized())
103 child_bounds = ScreenUtil::GetMaximizedWindowBoundsInParent(child);
104 else if (window_state->IsFullscreen())
105 child_bounds = ScreenUtil::GetDisplayBoundsInParent(child);
106 SetChildBoundsDirect(child, child_bounds);
109 /////////////////////////////////////////////////////////////////////////////
110 // BaseLayoutManager, aura::WindowObserver overrides:
112 void BaseLayoutManager::OnWindowDestroying(aura::Window* window) {
113 if (root_window_ == window) {
114 root_window_->RemoveObserver(this);
119 void BaseLayoutManager::OnWindowBoundsChanged(aura::Window* window,
120 const gfx::Rect& old_bounds,
121 const gfx::Rect& new_bounds) {
122 if (root_window_ == window)
123 AdjustAllWindowsBoundsForWorkAreaChange(ADJUST_WINDOW_DISPLAY_SIZE_CHANGED);
126 //////////////////////////////////////////////////////////////////////////////
127 // BaseLayoutManager, aura::client::ActivationChangeObserver implementation:
129 void BaseLayoutManager::OnWindowActivated(aura::Window* gained_active,
130 aura::Window* lost_active) {
131 wm::WindowState* window_state = wm::GetWindowState(gained_active);
132 if (window_state && window_state->IsMinimized() &&
133 !gained_active->IsVisible()) {
134 window_state->Unminimize();
135 DCHECK(!window_state->IsMinimized());
139 /////////////////////////////////////////////////////////////////////////////
140 // BaseLayoutManager, ash::ShellObserver overrides:
142 void BaseLayoutManager::OnDisplayWorkAreaInsetsChanged() {
143 AdjustAllWindowsBoundsForWorkAreaChange(
144 ADJUST_WINDOW_WORK_AREA_INSETS_CHANGED);
147 /////////////////////////////////////////////////////////////////////////////
148 // BaseLayoutManager, ash::wm::WindowStateObserver overrides:
150 void BaseLayoutManager::OnWindowShowTypeChanged(wm::WindowState* window_state,
151 wm::WindowShowType old_type) {
152 if (old_type != wm::SHOW_TYPE_MINIMIZED &&
153 !window_state->HasRestoreBounds() &&
154 window_state->IsMaximizedOrFullscreen() &&
155 !wm::IsMaximizedOrFullscreenWindowShowType(old_type)) {
156 window_state->SetRestoreBoundsInParent(window_state->window()->bounds());
159 UpdateBoundsFromShowType(window_state);
160 ShowTypeChanged(window_state, old_type);
163 //////////////////////////////////////////////////////////////////////////////
164 // BaseLayoutManager, protected:
166 void BaseLayoutManager::ShowTypeChanged(
167 wm::WindowState* window_state,
168 wm::WindowShowType last_show_type) {
169 if (window_state->IsMinimized()) {
170 if (last_show_type == wm::SHOW_TYPE_MINIMIZED)
173 // Save the previous show state so that we can correctly restore it.
174 window_state->window()->SetProperty(aura::client::kRestoreShowStateKey,
175 wm::ToWindowShowState(last_show_type));
176 views::corewm::SetWindowVisibilityAnimationType(
177 window_state->window(), WINDOW_VISIBILITY_ANIMATION_TYPE_MINIMIZE);
180 window_state->window()->Hide();
181 // Activate another window.
182 if (window_state->IsActive())
183 window_state->Deactivate();
184 } else if ((window_state->window()->TargetVisibility() ||
185 last_show_type == wm::SHOW_TYPE_MINIMIZED) &&
186 !window_state->window()->layer()->visible()) {
187 // The layer may be hidden if the window was previously minimized. Make
188 // sure it's visible.
189 window_state->window()->Show();
190 if (last_show_type == wm::SHOW_TYPE_MINIMIZED &&
191 !window_state->IsMaximizedOrFullscreen()) {
192 window_state->set_always_restores_to_restore_bounds(false);
197 void BaseLayoutManager::AdjustAllWindowsBoundsForWorkAreaChange(
198 AdjustWindowReason reason) {
199 // Don't do any adjustments of the insets while we are in screen locked mode.
200 // This would happen if the launcher was auto hidden before the login screen
201 // was shown and then gets shown when the login screen gets presented.
202 if (reason == ADJUST_WINDOW_WORK_AREA_INSETS_CHANGED &&
203 Shell::GetInstance()->session_state_delegate()->IsScreenLocked())
206 // If a user plugs an external display into a laptop running Aura the
207 // display size will change. Maximized windows need to resize to match.
208 // We also do this when developers running Aura on a desktop manually resize
210 // We also need to do this when the work area insets changes.
211 for (WindowSet::const_iterator it = windows_.begin();
212 it != windows_.end();
214 AdjustWindowBoundsForWorkAreaChange(wm::GetWindowState(*it), reason);
218 void BaseLayoutManager::AdjustWindowBoundsForWorkAreaChange(
219 wm::WindowState* window_state,
220 AdjustWindowReason reason) {
221 aura::Window* window = window_state->window();
222 if (window_state->IsMaximized()) {
223 SetChildBoundsDirect(
224 window, ScreenUtil::GetMaximizedWindowBoundsInParent(window));
225 } else if (window_state->IsFullscreen()) {
226 SetChildBoundsDirect(
227 window, ScreenUtil::GetDisplayBoundsInParent(window));
229 // The work area may be smaller than the full screen.
230 gfx::Rect display_rect =
231 ScreenUtil::GetDisplayWorkAreaBoundsInParent(window);
232 // Put as much of the window as possible within the display area.
233 gfx::Rect bounds = window->bounds();
234 bounds.AdjustToFit(display_rect);
235 window->SetBounds(bounds);
239 //////////////////////////////////////////////////////////////////////////////
240 // BaseLayoutManager, private:
242 void BaseLayoutManager::UpdateBoundsFromShowType(
243 wm::WindowState* window_state) {
244 aura::Window* window = window_state->window();
245 switch (window_state->window_show_type()) {
246 case wm::SHOW_TYPE_DEFAULT:
247 case wm::SHOW_TYPE_NORMAL:
248 if (window_state->HasRestoreBounds()) {
249 gfx::Rect bounds_in_parent = window_state->GetRestoreBoundsInParent();
250 SetChildBoundsDirect(window,
251 BoundsWithScreenEdgeVisible(window,
254 window_state->ClearRestoreBounds();
257 case wm::SHOW_TYPE_LEFT_SNAPPED:
258 case wm::SHOW_TYPE_RIGHT_SNAPPED:
259 if (window_state->HasRestoreBounds())
260 SetChildBoundsDirect(window, window_state->GetRestoreBoundsInParent());
261 window_state->ClearRestoreBounds();
264 case wm::SHOW_TYPE_MAXIMIZED:
265 SetChildBoundsDirect(
266 window, ScreenUtil::GetMaximizedWindowBoundsInParent(window));
269 case wm::SHOW_TYPE_FULLSCREEN:
270 // Don't animate the full-screen window transition.
271 // TODO(jamescook): Use animation here. Be sure the lock screen works.
272 SetChildBoundsDirect(window,
273 ScreenUtil::GetDisplayBoundsInParent(window));
276 case wm::SHOW_TYPE_MINIMIZED:
277 case wm::SHOW_TYPE_INACTIVE:
278 case wm::SHOW_TYPE_DETACHED:
279 case wm::SHOW_TYPE_END:
280 case wm::SHOW_TYPE_AUTO_POSITIONED:
285 } // namespace internal