1 // Copyright 2013 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/window_state.h" 6 7 #include "ash/ash_switches.h" 8 #include "ash/root_window_controller.h" 9 #include "ash/screen_ash.h" 10 #include "ash/shell_window_ids.h" 11 #include "ash/wm/window_properties.h" 12 #include "ash/wm/window_state_delegate.h" 13 #include "ash/wm/window_state_observer.h" 14 #include "ash/wm/window_util.h" 15 #include "ash/wm/wm_types.h" 16 #include "base/auto_reset.h" 17 #include "base/command_line.h" 18 #include "ui/aura/client/aura_constants.h" 19 #include "ui/aura/window.h" 20 #include "ui/aura/window_delegate.h" 21 #include "ui/gfx/display.h" 22 #include "ui/views/corewm/window_util.h" 23 24 namespace ash { 25 namespace wm { 26 27 // static 28 bool WindowState::IsMaximizedOrFullscreenState(ui::WindowShowState show_state) { 29 return show_state == ui::SHOW_STATE_FULLSCREEN || 30 show_state == ui::SHOW_STATE_MAXIMIZED; 31 } 32 33 WindowState::WindowState(aura::Window* window) 34 : window_(window), 35 window_position_managed_(false), 36 bounds_changed_by_user_(false), 37 panel_attached_(true), 38 continue_drag_after_reparent_(false), 39 ignored_by_shelf_(false), 40 can_consume_system_keys_(false), 41 top_row_keys_are_function_keys_(false), 42 window_resizer_(NULL), 43 always_restores_to_restore_bounds_(false), 44 hide_shelf_when_fullscreen_(true), 45 animate_to_fullscreen_(true), 46 minimum_visibility_(false), 47 in_set_window_show_type_(false), 48 window_show_type_(ToWindowShowType(GetShowState())) { 49 window_->AddObserver(this); 50 51 #if defined(OS_CHROMEOS) 52 // NOTE(pkotwicz): Animating to immersive fullscreen does not look good. When 53 // the kAshEnableImmersiveFullscreenForAllWindows flag is set most windows 54 // can be put into immersive fullscreen. It is not worth the added complexity 55 // to only animate to fullscreen if the window is put into immersive 56 // fullscreen. 57 animate_to_fullscreen_ = !CommandLine::ForCurrentProcess()->HasSwitch( 58 switches::kAshEnableImmersiveFullscreenForAllWindows); 59 #endif 60 } 61 62 WindowState::~WindowState() { 63 } 64 65 bool WindowState::HasDelegate() const { 66 return delegate_; 67 } 68 69 void WindowState::SetDelegate(scoped_ptr<WindowStateDelegate> delegate) { 70 DCHECK(!delegate_.get()); 71 delegate_ = delegate.Pass(); 72 } 73 74 ui::WindowShowState WindowState::GetShowState() const { 75 return window_->GetProperty(aura::client::kShowStateKey); 76 } 77 78 bool WindowState::IsMinimized() const { 79 return GetShowState() == ui::SHOW_STATE_MINIMIZED; 80 } 81 82 bool WindowState::IsMaximized() const { 83 return GetShowState() == ui::SHOW_STATE_MAXIMIZED; 84 } 85 86 bool WindowState::IsFullscreen() const { 87 return GetShowState() == ui::SHOW_STATE_FULLSCREEN; 88 } 89 90 bool WindowState::IsMaximizedOrFullscreen() const { 91 return IsMaximizedOrFullscreenState(GetShowState()); 92 } 93 94 bool WindowState::IsNormalShowState() const { 95 ui::WindowShowState state = window_->GetProperty(aura::client::kShowStateKey); 96 return state == ui::SHOW_STATE_NORMAL || state == ui::SHOW_STATE_DEFAULT; 97 } 98 99 bool WindowState::IsActive() const { 100 return IsActiveWindow(window_); 101 } 102 103 bool WindowState::IsDocked() const { 104 return window_->parent() && 105 window_->parent()->id() == internal::kShellWindowId_DockedContainer; 106 } 107 108 bool WindowState::IsSnapped() const { 109 return window_show_type_ == SHOW_TYPE_LEFT_SNAPPED || 110 window_show_type_ == SHOW_TYPE_RIGHT_SNAPPED; 111 } 112 113 bool WindowState::CanMaximize() const { 114 return window_->GetProperty(aura::client::kCanMaximizeKey); 115 } 116 117 bool WindowState::CanMinimize() const { 118 internal::RootWindowController* controller = 119 internal::RootWindowController::ForWindow(window_); 120 if (!controller) 121 return false; 122 aura::Window* lockscreen = controller->GetContainer( 123 internal::kShellWindowId_LockScreenContainersContainer); 124 if (lockscreen->Contains(window_)) 125 return false; 126 127 return true; 128 } 129 130 bool WindowState::CanResize() const { 131 return window_->GetProperty(aura::client::kCanResizeKey); 132 } 133 134 bool WindowState::CanActivate() const { 135 return views::corewm::CanActivateWindow(window_); 136 } 137 138 bool WindowState::CanSnap() const { 139 if (!CanResize() || 140 window_->type() == aura::client::WINDOW_TYPE_PANEL || 141 window_->transient_parent()) 142 return false; 143 // If a window has a maximum size defined, snapping may make it too big. 144 return window_->delegate() ? window_->delegate()->GetMaximumSize().IsEmpty() : 145 true; 146 } 147 148 bool WindowState::HasRestoreBounds() const { 149 return window_->GetProperty(aura::client::kRestoreBoundsKey) != NULL; 150 } 151 152 void WindowState::Maximize() { 153 window_->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MAXIMIZED); 154 } 155 156 void WindowState::SnapLeft(const gfx::Rect& bounds) { 157 SnapWindow(SHOW_TYPE_LEFT_SNAPPED, bounds); 158 } 159 160 void WindowState::SnapRight(const gfx::Rect& bounds) { 161 SnapWindow(SHOW_TYPE_RIGHT_SNAPPED, bounds); 162 } 163 164 void WindowState::Minimize() { 165 window_->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MINIMIZED); 166 } 167 168 void WindowState::Unminimize() { 169 window_->SetProperty( 170 aura::client::kShowStateKey, 171 window_->GetProperty(aura::client::kRestoreShowStateKey)); 172 window_->ClearProperty(aura::client::kRestoreShowStateKey); 173 } 174 175 void WindowState::Activate() { 176 ActivateWindow(window_); 177 } 178 179 void WindowState::Deactivate() { 180 DeactivateWindow(window_); 181 } 182 183 void WindowState::Restore() { 184 window_->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL); 185 } 186 187 void WindowState::ToggleMaximized() { 188 if (IsMaximized()) 189 Restore(); 190 else if (CanMaximize()) 191 Maximize(); 192 } 193 194 void WindowState::ToggleFullscreen() { 195 // Window which cannot be maximized should not be fullscreened. 196 // It can, however, be restored if it was fullscreened. 197 bool is_fullscreen = IsFullscreen(); 198 if (!is_fullscreen && !CanMaximize()) 199 return; 200 if (delegate_ && delegate_->ToggleFullscreen(this)) 201 return; 202 if (is_fullscreen) { 203 Restore(); 204 } else { 205 window_->SetProperty(aura::client::kShowStateKey, 206 ui::SHOW_STATE_FULLSCREEN); 207 } 208 } 209 210 void WindowState::SetBoundsInScreen( 211 const gfx::Rect& bounds_in_screen) { 212 gfx::Rect bounds_in_parent = 213 ScreenAsh::ConvertRectFromScreen(window_->parent(), 214 bounds_in_screen); 215 window_->SetBounds(bounds_in_parent); 216 } 217 218 void WindowState::SaveCurrentBoundsForRestore() { 219 gfx::Rect bounds_in_screen = 220 ScreenAsh::ConvertRectToScreen(window_->parent(), 221 window_->bounds()); 222 SetRestoreBoundsInScreen(bounds_in_screen); 223 } 224 225 gfx::Rect WindowState::GetRestoreBoundsInScreen() const { 226 return *window_->GetProperty(aura::client::kRestoreBoundsKey); 227 } 228 229 gfx::Rect WindowState::GetRestoreBoundsInParent() const { 230 return ScreenAsh::ConvertRectFromScreen(window_->parent(), 231 GetRestoreBoundsInScreen()); 232 } 233 234 void WindowState::SetRestoreBoundsInScreen(const gfx::Rect& bounds) { 235 window_->SetProperty(aura::client::kRestoreBoundsKey, new gfx::Rect(bounds)); 236 } 237 238 void WindowState::SetRestoreBoundsInParent(const gfx::Rect& bounds) { 239 SetRestoreBoundsInScreen( 240 ScreenAsh::ConvertRectToScreen(window_->parent(), bounds)); 241 } 242 243 void WindowState::ClearRestoreBounds() { 244 window_->ClearProperty(aura::client::kRestoreBoundsKey); 245 } 246 247 void WindowState::SetPreAutoManageWindowBounds( 248 const gfx::Rect& bounds) { 249 pre_auto_manage_window_bounds_.reset(new gfx::Rect(bounds)); 250 } 251 252 void WindowState::AddObserver(WindowStateObserver* observer) { 253 observer_list_.AddObserver(observer); 254 } 255 256 void WindowState::RemoveObserver(WindowStateObserver* observer) { 257 observer_list_.RemoveObserver(observer); 258 } 259 260 void WindowState::OnWindowPropertyChanged(aura::Window* window, 261 const void* key, 262 intptr_t old) { 263 DCHECK_EQ(window, window_); 264 if (key == aura::client::kShowStateKey) 265 SetWindowShowType(ToWindowShowType(GetShowState())); 266 } 267 268 void WindowState::SnapWindow(WindowShowType left_or_right, 269 const gfx::Rect& bounds) { 270 if (window_show_type_ == left_or_right) { 271 window_->SetBounds(bounds); 272 return; 273 } 274 275 // Compute the bounds that the window will restore to. If the window does not 276 // already have restore bounds, it will be restored (when un-snapped) to the 277 // last bounds that it had before getting snapped. 278 gfx::Rect restore_bounds_in_screen(HasRestoreBounds() ? 279 GetRestoreBoundsInScreen() : window_->GetBoundsInScreen()); 280 // Set the window's restore bounds so that WorkspaceLayoutManager knows 281 // which width to use when the snapped window is moved to the edge. 282 SetRestoreBoundsInParent(bounds); 283 284 bool was_maximized = IsMaximizedOrFullscreen(); 285 // Before we can set the bounds we need to restore the window. 286 // Restoring the window will set the window to its restored bounds set above. 287 // Restore will cause OnWindowPropertyChanged() so it needs to be done 288 // before notifying that the WindowShowType has changed to |left_or_right|. 289 if (was_maximized) 290 Restore(); 291 DCHECK(left_or_right == SHOW_TYPE_LEFT_SNAPPED || 292 left_or_right == SHOW_TYPE_RIGHT_SNAPPED); 293 SetWindowShowType(left_or_right); 294 // TODO(varkha): Ideally the bounds should be changed in a LayoutManager upon 295 // observing the WindowShowType change. 296 // If the window is a child of kShellWindowId_DockedContainer such as during 297 // a drag, the window's bounds are not set in 298 // WorkspaceLayoutManager::OnWindowShowTypeChanged(). Set them here. Skip 299 // setting the bounds otherwise to avoid stopping the slide animation which 300 // was started as a result of OnWindowShowTypeChanged(). 301 if (IsDocked()) 302 window_->SetBounds(bounds); 303 SetRestoreBoundsInScreen(restore_bounds_in_screen); 304 } 305 306 void WindowState::SetWindowShowType(WindowShowType new_window_show_type) { 307 if (in_set_window_show_type_) 308 return; 309 base::AutoReset<bool> resetter(&in_set_window_show_type_, true); 310 311 ui::WindowShowState new_window_state = 312 ToWindowShowState(new_window_show_type); 313 if (new_window_state != GetShowState()) 314 window_->SetProperty(aura::client::kShowStateKey, new_window_state); 315 WindowShowType old_window_show_type = window_show_type_; 316 window_show_type_ = new_window_show_type; 317 if (old_window_show_type != window_show_type_) { 318 FOR_EACH_OBSERVER(WindowStateObserver, observer_list_, 319 OnWindowShowTypeChanged(this, old_window_show_type)); 320 } 321 } 322 323 WindowState* GetActiveWindowState() { 324 aura::Window* active = GetActiveWindow(); 325 return active ? GetWindowState(active) : NULL; 326 } 327 328 WindowState* GetWindowState(aura::Window* window) { 329 if (!window) 330 return NULL; 331 WindowState* settings = window->GetProperty(internal::kWindowStateKey); 332 if(!settings) { 333 settings = new WindowState(window); 334 window->SetProperty(internal::kWindowStateKey, settings); 335 } 336 return settings; 337 } 338 339 const WindowState* GetWindowState(const aura::Window* window) { 340 return GetWindowState(const_cast<aura::Window*>(window)); 341 } 342 343 } // namespace wm 344 } // namespace ash 345