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_ash.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_util.h"
14 #include "ash/wm/workspace/workspace_window_resizer.h"
15 #include "ui/aura/client/activation_client.h"
16 #include "ui/aura/client/aura_constants.h"
17 #include "ui/aura/root_window.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::RootWindow
* 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::ScreenAsh::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, LayoutManager overrides:
65 void BaseLayoutManager::OnWindowResized() {
68 void BaseLayoutManager::OnWindowAddedToLayout(aura::Window
* child
) {
69 windows_
.insert(child
);
70 child
->AddObserver(this);
71 // Only update the bounds if the window has a show state that depends on the
73 if (wm::IsWindowMaximized(child
) || wm::IsWindowFullscreen(child
))
74 UpdateBoundsFromShowState(child
);
77 void BaseLayoutManager::OnWillRemoveWindowFromLayout(aura::Window
* child
) {
78 windows_
.erase(child
);
79 child
->RemoveObserver(this);
82 void BaseLayoutManager::OnWindowRemovedFromLayout(aura::Window
* child
) {
85 void BaseLayoutManager::OnChildWindowVisibilityChanged(aura::Window
* child
,
87 if (visible
&& wm::IsWindowMinimized(child
)) {
88 // Attempting to show a minimized window. Unminimize it.
89 child
->SetProperty(aura::client::kShowStateKey
,
90 child
->GetProperty(aura::client::kRestoreShowStateKey
));
91 child
->ClearProperty(aura::client::kRestoreShowStateKey
);
95 void BaseLayoutManager::SetChildBounds(aura::Window
* child
,
96 const gfx::Rect
& requested_bounds
) {
97 gfx::Rect
child_bounds(requested_bounds
);
98 // Some windows rely on this to set their initial bounds.
99 if (wm::IsWindowMaximized(child
))
100 child_bounds
= ScreenAsh::GetMaximizedWindowBoundsInParent(child
);
101 else if (wm::IsWindowFullscreen(child
))
102 child_bounds
= ScreenAsh::GetDisplayBoundsInParent(child
);
103 SetChildBoundsDirect(child
, child_bounds
);
106 /////////////////////////////////////////////////////////////////////////////
107 // BaseLayoutManager, ash::ShellObserver overrides:
109 void BaseLayoutManager::OnDisplayWorkAreaInsetsChanged() {
110 AdjustAllWindowsBoundsForWorkAreaChange(
111 ADJUST_WINDOW_WORK_AREA_INSETS_CHANGED
);
114 /////////////////////////////////////////////////////////////////////////////
115 // BaseLayoutManager, WindowObserver overrides:
117 void BaseLayoutManager::OnWindowPropertyChanged(aura::Window
* window
,
120 if (key
== aura::client::kShowStateKey
) {
121 ui::WindowShowState old_state
= static_cast<ui::WindowShowState
>(old
);
122 ui::WindowShowState new_state
=
123 window
->GetProperty(aura::client::kShowStateKey
);
124 if (old_state
!= new_state
&& old_state
!= ui::SHOW_STATE_MINIMIZED
&&
125 !GetRestoreBoundsInScreen(window
) &&
126 ((new_state
== ui::SHOW_STATE_MAXIMIZED
&&
127 old_state
!= ui::SHOW_STATE_FULLSCREEN
) ||
128 (new_state
== ui::SHOW_STATE_FULLSCREEN
&&
129 old_state
!= ui::SHOW_STATE_MAXIMIZED
))) {
130 SetRestoreBoundsInParent(window
, window
->bounds());
133 UpdateBoundsFromShowState(window
);
134 ShowStateChanged(window
, old_state
);
138 void BaseLayoutManager::OnWindowDestroying(aura::Window
* window
) {
139 if (root_window_
== window
) {
140 root_window_
->RemoveObserver(this);
145 void BaseLayoutManager::OnWindowBoundsChanged(aura::Window
* window
,
146 const gfx::Rect
& old_bounds
,
147 const gfx::Rect
& new_bounds
) {
148 if (root_window_
== window
)
149 AdjustAllWindowsBoundsForWorkAreaChange(ADJUST_WINDOW_DISPLAY_SIZE_CHANGED
);
152 //////////////////////////////////////////////////////////////////////////////
153 // BaseLayoutManager, aura::client::ActivationChangeObserver implementation:
155 void BaseLayoutManager::OnWindowActivated(aura::Window
* gained_active
,
156 aura::Window
* lost_active
) {
157 if (views::corewm::UseFocusController()) {
158 if (gained_active
&& wm::IsWindowMinimized(gained_active
) &&
159 !gained_active
->IsVisible()) {
160 gained_active
->Show();
161 DCHECK(!wm::IsWindowMinimized(gained_active
));
166 //////////////////////////////////////////////////////////////////////////////
167 // BaseLayoutManager, protected:
169 void BaseLayoutManager::ShowStateChanged(aura::Window
* window
,
170 ui::WindowShowState last_show_state
) {
171 if (wm::IsWindowMinimized(window
)) {
172 // Save the previous show state so that we can correctly restore it.
173 window
->SetProperty(aura::client::kRestoreShowStateKey
, last_show_state
);
174 views::corewm::SetWindowVisibilityAnimationType(
175 window
, WINDOW_VISIBILITY_ANIMATION_TYPE_MINIMIZE
);
179 // Activate another window.
180 if (wm::IsActiveWindow(window
))
181 wm::DeactivateWindow(window
);
182 } else if ((window
->TargetVisibility() ||
183 last_show_state
== ui::SHOW_STATE_MINIMIZED
) &&
184 !window
->layer()->visible()) {
185 // The layer may be hidden if the window was previously minimized. Make
186 // sure it's visible.
188 if (last_show_state
== ui::SHOW_STATE_MINIMIZED
&&
189 !wm::IsWindowMaximized(window
) &&
190 !wm::IsWindowFullscreen(window
)) {
191 window
->ClearProperty(internal::kWindowRestoresToRestoreBounds
);
196 void BaseLayoutManager::AdjustAllWindowsBoundsForWorkAreaChange(
197 AdjustWindowReason reason
) {
198 // Don't do any adjustments of the insets while we are in screen locked mode.
199 // This would happen if the launcher was auto hidden before the login screen
200 // was shown and then gets shown when the login screen gets presented.
201 if (reason
== ADJUST_WINDOW_WORK_AREA_INSETS_CHANGED
&&
202 Shell::GetInstance()->session_state_delegate()->IsScreenLocked())
205 // If a user plugs an external display into a laptop running Aura the
206 // display size will change. Maximized windows need to resize to match.
207 // We also do this when developers running Aura on a desktop manually resize
209 // We also need to do this when the work area insets changes.
210 for (WindowSet::const_iterator it
= windows_
.begin();
211 it
!= windows_
.end();
213 AdjustWindowBoundsForWorkAreaChange(*it
, reason
);
217 void BaseLayoutManager::AdjustWindowBoundsForWorkAreaChange(
218 aura::Window
* window
,
219 AdjustWindowReason reason
) {
220 if (wm::IsWindowMaximized(window
)) {
221 SetChildBoundsDirect(
222 window
, ScreenAsh::GetMaximizedWindowBoundsInParent(window
));
223 } else if (wm::IsWindowFullscreen(window
)) {
224 SetChildBoundsDirect(
225 window
, ScreenAsh::GetDisplayBoundsInParent(window
));
227 // The work area may be smaller than the full screen.
228 gfx::Rect display_rect
=
229 ScreenAsh::GetDisplayWorkAreaBoundsInParent(window
);
230 // Put as much of the window as possible within the display area.
231 gfx::Rect bounds
= window
->bounds();
232 bounds
.AdjustToFit(display_rect
);
233 window
->SetBounds(bounds
);
237 //////////////////////////////////////////////////////////////////////////////
238 // BaseLayoutManager, private:
240 void BaseLayoutManager::UpdateBoundsFromShowState(aura::Window
* window
) {
241 switch (window
->GetProperty(aura::client::kShowStateKey
)) {
242 case ui::SHOW_STATE_DEFAULT
:
243 case ui::SHOW_STATE_NORMAL
: {
244 const gfx::Rect
* restore
= GetRestoreBoundsInScreen(window
);
246 gfx::Rect bounds_in_parent
=
247 ScreenAsh::ConvertRectFromScreen(window
->parent(), *restore
);
248 SetChildBoundsDirect(window
,
249 BoundsWithScreenEdgeVisible(window
,
252 ClearRestoreBounds(window
);
256 case ui::SHOW_STATE_MAXIMIZED
:
257 SetChildBoundsDirect(window
,
258 ScreenAsh::GetMaximizedWindowBoundsInParent(window
));
261 case ui::SHOW_STATE_FULLSCREEN
:
262 // Don't animate the full-screen window transition.
263 // TODO(jamescook): Use animation here. Be sure the lock screen works.
264 SetChildBoundsDirect(
265 window
, ScreenAsh::GetDisplayBoundsInParent(window
));
273 } // namespace internal