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. 4 5 #include "ash/wm/base_layout_manager.h" 6 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" 24 25 namespace ash { 26 namespace internal { 27 28 ///////////////////////////////////////////////////////////////////////////// 29 // BaseLayoutManager, public: 30 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); 36 } 37 38 BaseLayoutManager::~BaseLayoutManager() { 39 if (root_window_) 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); 45 } 46 47 // static 48 gfx::Rect BaseLayoutManager::BoundsWithScreenEdgeVisible( 49 aura::Window* window, 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)) 58 return max_bounds; 59 return restore_bounds; 60 } 61 62 ///////////////////////////////////////////////////////////////////////////// 63 // BaseLayoutManager, LayoutManager overrides: 64 65 void BaseLayoutManager::OnWindowResized() { 66 } 67 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 72 // workspace area. 73 if (wm::IsWindowMaximized(child) || wm::IsWindowFullscreen(child)) 74 UpdateBoundsFromShowState(child); 75 } 76 77 void BaseLayoutManager::OnWillRemoveWindowFromLayout(aura::Window* child) { 78 windows_.erase(child); 79 child->RemoveObserver(this); 80 } 81 82 void BaseLayoutManager::OnWindowRemovedFromLayout(aura::Window* child) { 83 } 84 85 void BaseLayoutManager::OnChildWindowVisibilityChanged(aura::Window* child, 86 bool visible) { 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); 92 } 93 } 94 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); 104 } 105 106 ///////////////////////////////////////////////////////////////////////////// 107 // BaseLayoutManager, ash::ShellObserver overrides: 108 109 void BaseLayoutManager::OnDisplayWorkAreaInsetsChanged() { 110 AdjustAllWindowsBoundsForWorkAreaChange( 111 ADJUST_WINDOW_WORK_AREA_INSETS_CHANGED); 112 } 113 114 ///////////////////////////////////////////////////////////////////////////// 115 // BaseLayoutManager, WindowObserver overrides: 116 117 void BaseLayoutManager::OnWindowPropertyChanged(aura::Window* window, 118 const void* key, 119 intptr_t old) { 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()); 131 } 132 133 UpdateBoundsFromShowState(window); 134 ShowStateChanged(window, old_state); 135 } 136 } 137 138 void BaseLayoutManager::OnWindowDestroying(aura::Window* window) { 139 if (root_window_ == window) { 140 root_window_->RemoveObserver(this); 141 root_window_ = NULL; 142 } 143 } 144 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); 150 } 151 152 ////////////////////////////////////////////////////////////////////////////// 153 // BaseLayoutManager, aura::client::ActivationChangeObserver implementation: 154 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)); 162 } 163 } 164 } 165 166 ////////////////////////////////////////////////////////////////////////////// 167 // BaseLayoutManager, protected: 168 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); 176 177 // Hide the window. 178 window->Hide(); 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. 187 window->Show(); 188 if (last_show_state == ui::SHOW_STATE_MINIMIZED && 189 !wm::IsWindowMaximized(window) && 190 !wm::IsWindowFullscreen(window)) { 191 window->ClearProperty(internal::kWindowRestoresToRestoreBounds); 192 } 193 } 194 } 195 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()) 203 return; 204 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 208 // the host window. 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(); 212 ++it) { 213 AdjustWindowBoundsForWorkAreaChange(*it, reason); 214 } 215 } 216 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)); 226 } else { 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); 234 } 235 } 236 237 ////////////////////////////////////////////////////////////////////////////// 238 // BaseLayoutManager, private: 239 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); 245 if (restore) { 246 gfx::Rect bounds_in_parent = 247 ScreenAsh::ConvertRectFromScreen(window->parent(), *restore); 248 SetChildBoundsDirect(window, 249 BoundsWithScreenEdgeVisible(window, 250 bounds_in_parent)); 251 } 252 ClearRestoreBounds(window); 253 break; 254 } 255 256 case ui::SHOW_STATE_MAXIMIZED: 257 SetChildBoundsDirect(window, 258 ScreenAsh::GetMaximizedWindowBoundsInParent(window)); 259 break; 260 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)); 266 break; 267 268 default: 269 break; 270 } 271 } 272 273 } // namespace internal 274 } // namespace ash 275