default_state.cc revision 5c02ac1a9c1b504631c0a3d2b6e737b5d738bae1
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/default_state.h" 6 7#include "ash/display/display_controller.h" 8#include "ash/screen_util.h" 9#include "ash/shell.h" 10#include "ash/shell_window_ids.h" 11#include "ash/wm/coordinate_conversion.h" 12#include "ash/wm/window_animations.h" 13#include "ash/wm/window_state.h" 14#include "ash/wm/window_state_delegate.h" 15#include "ash/wm/window_state_util.h" 16#include "ash/wm/window_util.h" 17#include "ash/wm/wm_event.h" 18#include "ash/wm/workspace/workspace_window_resizer.h" 19#include "ui/aura/client/aura_constants.h" 20#include "ui/aura/window.h" 21#include "ui/aura/window_delegate.h" 22#include "ui/gfx/display.h" 23#include "ui/gfx/rect.h" 24 25namespace ash { 26namespace wm { 27namespace { 28 29// This specifies how much percent (30%) of a window rect 30// must be visible when the window is added to the workspace. 31const float kMinimumPercentOnScreenArea = 0.3f; 32 33bool IsPanel(aura::Window* window) { 34 return window->parent() && 35 window->parent()->id() == kShellWindowId_PanelContainer; 36} 37 38void MoveToDisplayForRestore(WindowState* window_state) { 39 if (!window_state->HasRestoreBounds()) 40 return; 41 const gfx::Rect& restore_bounds = window_state->GetRestoreBoundsInScreen(); 42 43 // Move only if the restore bounds is outside of 44 // the display. There is no information about in which 45 // display it should be restored, so this is best guess. 46 // TODO(oshima): Restore information should contain the 47 // work area information like WindowResizer does for the 48 // last window location. 49 gfx::Rect display_area = Shell::GetScreen()->GetDisplayNearestWindow( 50 window_state->window()).bounds(); 51 52 if (!display_area.Intersects(restore_bounds)) { 53 const gfx::Display& display = 54 Shell::GetScreen()->GetDisplayMatching(restore_bounds); 55 DisplayController* display_controller = 56 Shell::GetInstance()->display_controller(); 57 aura::Window* new_root = 58 display_controller->GetRootWindowForDisplayId(display.id()); 59 if (new_root != window_state->window()->GetRootWindow()) { 60 aura::Window* new_container = 61 Shell::GetContainer(new_root, window_state->window()->parent()->id()); 62 new_container->AddChild(window_state->window()); 63 } 64 } 65} 66 67} // namespace; 68 69DefaultState::DefaultState(WindowStateType initial_state_type) 70 : state_type_(initial_state_type) {} 71DefaultState::~DefaultState() {} 72 73void DefaultState::OnWMEvent(WindowState* window_state, 74 const WMEvent* event) { 75 if (ProcessWorkspaceEvents(window_state, event)) 76 return; 77 78 if (ProcessCompoundEvents(window_state, event)) 79 return; 80 81 WindowStateType next_state_type = WINDOW_STATE_TYPE_NORMAL; 82 switch (event->type()) { 83 case WM_EVENT_NORMAL: 84 next_state_type = WINDOW_STATE_TYPE_NORMAL; 85 break; 86 case WM_EVENT_MAXIMIZE: 87 next_state_type = WINDOW_STATE_TYPE_MAXIMIZED; 88 break; 89 case WM_EVENT_MINIMIZE: 90 next_state_type = WINDOW_STATE_TYPE_MINIMIZED; 91 break; 92 case WM_EVENT_FULLSCREEN: 93 next_state_type = WINDOW_STATE_TYPE_FULLSCREEN; 94 break; 95 case WM_EVENT_SNAP_LEFT: 96 next_state_type = WINDOW_STATE_TYPE_LEFT_SNAPPED; 97 break; 98 case WM_EVENT_SNAP_RIGHT: 99 next_state_type = WINDOW_STATE_TYPE_RIGHT_SNAPPED; 100 break; 101 case WM_EVENT_SET_BOUNDS: 102 SetBounds(window_state, static_cast<const SetBoundsEvent*>(event)); 103 return; 104 case WM_EVENT_SHOW_INACTIVE: 105 next_state_type = WINDOW_STATE_TYPE_INACTIVE; 106 break; 107 case WM_EVENT_TOGGLE_MAXIMIZE_CAPTION: 108 case WM_EVENT_TOGGLE_MAXIMIZE: 109 case WM_EVENT_TOGGLE_VERTICAL_MAXIMIZE: 110 case WM_EVENT_TOGGLE_HORIZONTAL_MAXIMIZE: 111 case WM_EVENT_TOGGLE_FULLSCREEN: 112 case WM_EVENT_CENTER: 113 NOTREACHED() << "Compound event should not reach here:" << event; 114 return; 115 case WM_EVENT_ADDED_TO_WORKSPACE: 116 case WM_EVENT_WORKAREA_BOUNDS_CHANGED: 117 case WM_EVENT_DISPLAY_BOUNDS_CHANGED: 118 NOTREACHED() << "Workspace event should not reach here:" << event; 119 return; 120 } 121 122 WindowStateType current = window_state->GetStateType(); 123 124 if (next_state_type == current && window_state->IsSnapped()) { 125 gfx::Rect snapped_bounds = event->type() == WM_EVENT_SNAP_LEFT ? 126 GetDefaultLeftSnappedWindowBoundsInParent(window_state->window()) : 127 GetDefaultRightSnappedWindowBoundsInParent(window_state->window()); 128 window_state->SetBoundsDirectAnimated(snapped_bounds); 129 return; 130 } 131 132 EnterToNextState(window_state, next_state_type); 133} 134 135WindowStateType DefaultState::GetType() const { 136 return state_type_; 137} 138 139void DefaultState::AttachState( 140 WindowState* window_state, 141 WindowState::State* state_in_previous_mode) { 142 DCHECK_EQ(stored_window_state_, window_state); 143 144 ReenterToCurrentState(window_state, state_in_previous_mode); 145 146 // If the display has changed while in the another mode, 147 // we need to let windows know the change. 148 gfx::Display current_display = Shell::GetScreen()-> 149 GetDisplayNearestWindow(window_state->window()); 150 if (stored_display_state_.bounds() != current_display.bounds()) { 151 const WMEvent event(wm::WM_EVENT_DISPLAY_BOUNDS_CHANGED); 152 window_state->OnWMEvent(&event); 153 } else if (stored_display_state_.work_area() != current_display.work_area()) { 154 const WMEvent event(wm::WM_EVENT_WORKAREA_BOUNDS_CHANGED); 155 window_state->OnWMEvent(&event); 156 } 157} 158 159void DefaultState::DetachState(WindowState* window_state) { 160 stored_window_state_ = window_state; 161 aura::Window* window = window_state->window(); 162 stored_bounds_ = window->bounds(); 163 stored_restore_bounds_ = window_state->HasRestoreBounds() ? 164 window_state->GetRestoreBoundsInParent() : gfx::Rect(); 165 // Remember the display state so that in case of the display change 166 // while in the other mode, we can perform necessary action to 167 // restore the window state to the proper state for the current 168 // display. 169 stored_display_state_ = Shell::GetScreen()-> 170 GetDisplayNearestWindow(window_state->window()); 171} 172 173// static 174bool DefaultState::ProcessCompoundEvents(WindowState* window_state, 175 const WMEvent* event) { 176 aura::Window* window = window_state->window(); 177 178 switch (event->type()) { 179 case WM_EVENT_TOGGLE_MAXIMIZE_CAPTION: 180 if (window_state->IsFullscreen()) { 181 const wm::WMEvent event(wm::WM_EVENT_TOGGLE_FULLSCREEN); 182 window_state->OnWMEvent(&event); 183 } else if (window_state->IsMaximized()) { 184 window_state->Restore(); 185 } else if (window_state->IsNormalOrSnapped()) { 186 if (window_state->CanMaximize()) 187 window_state->Maximize(); 188 } 189 return true; 190 case WM_EVENT_TOGGLE_MAXIMIZE: 191 if (window_state->IsFullscreen()) { 192 const wm::WMEvent event(wm::WM_EVENT_TOGGLE_FULLSCREEN); 193 window_state->OnWMEvent(&event); 194 } else if (window_state->IsMaximized()) { 195 window_state->Restore(); 196 } else if (window_state->CanMaximize()) { 197 window_state->Maximize(); 198 } 199 return true; 200 case WM_EVENT_TOGGLE_VERTICAL_MAXIMIZE: { 201 gfx::Rect work_area = 202 ScreenUtil::GetDisplayWorkAreaBoundsInParent(window); 203 204 // Maximize vertically if: 205 // - The window does not have a max height defined. 206 // - The window has the normal state type. Snapped windows are excluded 207 // because they are already maximized vertically and reverting to the 208 // restored bounds looks weird. 209 if (window->delegate()->GetMaximumSize().height() != 0 || 210 !window_state->IsNormalStateType()) { 211 return true; 212 } 213 if (window_state->HasRestoreBounds() && 214 (window->bounds().height() == work_area.height() && 215 window->bounds().y() == work_area.y())) { 216 window_state->SetAndClearRestoreBounds(); 217 } else { 218 window_state->SaveCurrentBoundsForRestore(); 219 window->SetBounds(gfx::Rect(window->bounds().x(), 220 work_area.y(), 221 window->bounds().width(), 222 work_area.height())); 223 } 224 return true; 225 } 226 case WM_EVENT_TOGGLE_HORIZONTAL_MAXIMIZE: { 227 // Maximize horizontally if: 228 // - The window does not have a max width defined. 229 // - The window is snapped or has the normal state type. 230 if (window->delegate()->GetMaximumSize().width() != 0) 231 return true; 232 if (!window_state->IsNormalOrSnapped()) 233 return true; 234 gfx::Rect work_area = 235 ScreenUtil::GetDisplayWorkAreaBoundsInParent(window); 236 if (window_state->IsNormalStateType() && 237 window_state->HasRestoreBounds() && 238 (window->bounds().width() == work_area.width() && 239 window->bounds().x() == work_area.x())) { 240 window_state->SetAndClearRestoreBounds(); 241 } else { 242 gfx::Rect new_bounds(work_area.x(), 243 window->bounds().y(), 244 work_area.width(), 245 window->bounds().height()); 246 247 gfx::Rect restore_bounds = window->bounds(); 248 if (window_state->IsSnapped()) { 249 window_state->SetRestoreBoundsInParent(new_bounds); 250 window_state->Restore(); 251 252 // The restore logic prevents a window from being restored to bounds 253 // which match the workspace bounds exactly so it is necessary to set 254 // the bounds again below. 255 } 256 257 window_state->SetRestoreBoundsInParent(restore_bounds); 258 window->SetBounds(new_bounds); 259 } 260 return true; 261 } 262 case WM_EVENT_TOGGLE_FULLSCREEN: 263 ToggleFullScreen(window_state, window_state->delegate()); 264 return true; 265 case WM_EVENT_CENTER: 266 CenterWindow(window_state); 267 return true; 268 case WM_EVENT_NORMAL: 269 case WM_EVENT_MAXIMIZE: 270 case WM_EVENT_MINIMIZE: 271 case WM_EVENT_FULLSCREEN: 272 case WM_EVENT_SNAP_LEFT: 273 case WM_EVENT_SNAP_RIGHT: 274 case WM_EVENT_SET_BOUNDS: 275 case WM_EVENT_SHOW_INACTIVE: 276 break; 277 case WM_EVENT_ADDED_TO_WORKSPACE: 278 case WM_EVENT_WORKAREA_BOUNDS_CHANGED: 279 case WM_EVENT_DISPLAY_BOUNDS_CHANGED: 280 NOTREACHED() << "Workspace event should not reach here:" << event; 281 break; 282 } 283 return false; 284} 285 286bool DefaultState::ProcessWorkspaceEvents(WindowState* window_state, 287 const WMEvent* event) { 288 switch (event->type()) { 289 case WM_EVENT_ADDED_TO_WORKSPACE: { 290 // When a window is dragged and dropped onto a different 291 // root window, the bounds will be updated after they are added 292 // to the root window. 293 // If a window is opened as maximized or fullscreen, its bounds may be 294 // empty, so update the bounds now before checking empty. 295 if (window_state->is_dragged() || 296 SetMaximizedOrFullscreenBounds(window_state)) { 297 return true; 298 } 299 300 aura::Window* window = window_state->window(); 301 gfx::Rect bounds = window->bounds(); 302 303 // Don't adjust window bounds if the bounds are empty as this 304 // happens when a new views::Widget is created. 305 if (bounds.IsEmpty()) 306 return true; 307 308 // Use entire display instead of workarea because the workarea can 309 // be further shrunk by the docked area. The logic ensures 30% 310 // visibility which should be enough to see where the window gets 311 // moved. 312 gfx::Rect display_area = ScreenUtil::GetDisplayBoundsInParent(window); 313 int min_width = bounds.width() * kMinimumPercentOnScreenArea; 314 int min_height = bounds.height() * kMinimumPercentOnScreenArea; 315 AdjustBoundsToEnsureWindowVisibility( 316 display_area, min_width, min_height, &bounds); 317 window_state->AdjustSnappedBounds(&bounds); 318 if (window->bounds() != bounds) 319 window_state->SetBoundsConstrained(bounds); 320 return true; 321 } 322 case WM_EVENT_DISPLAY_BOUNDS_CHANGED: { 323 if (window_state->is_dragged() || 324 SetMaximizedOrFullscreenBounds(window_state)) { 325 return true; 326 } 327 gfx::Rect work_area_in_parent = 328 ScreenUtil::GetDisplayWorkAreaBoundsInParent(window_state->window()); 329 gfx::Rect bounds = window_state->window()->bounds(); 330 // When display bounds has changed, make sure the entire window is fully 331 // visible. 332 bounds.AdjustToFit(work_area_in_parent); 333 window_state->AdjustSnappedBounds(&bounds); 334 if (window_state->window()->bounds() != bounds) 335 window_state->SetBoundsDirectAnimated(bounds); 336 return true; 337 } 338 case WM_EVENT_WORKAREA_BOUNDS_CHANGED: { 339 if (window_state->is_dragged() || 340 SetMaximizedOrFullscreenBounds(window_state)) { 341 return true; 342 } 343 gfx::Rect work_area_in_parent = 344 ScreenUtil::GetDisplayWorkAreaBoundsInParent(window_state->window()); 345 gfx::Rect bounds = window_state->window()->bounds(); 346 AdjustBoundsToEnsureMinimumWindowVisibility(work_area_in_parent, &bounds); 347 window_state->AdjustSnappedBounds(&bounds); 348 if (window_state->window()->bounds() != bounds) 349 window_state->SetBoundsDirectAnimated(bounds); 350 return true; 351 } 352 case WM_EVENT_TOGGLE_MAXIMIZE_CAPTION: 353 case WM_EVENT_TOGGLE_MAXIMIZE: 354 case WM_EVENT_TOGGLE_VERTICAL_MAXIMIZE: 355 case WM_EVENT_TOGGLE_HORIZONTAL_MAXIMIZE: 356 case WM_EVENT_TOGGLE_FULLSCREEN: 357 case WM_EVENT_CENTER: 358 case WM_EVENT_NORMAL: 359 case WM_EVENT_MAXIMIZE: 360 case WM_EVENT_MINIMIZE: 361 case WM_EVENT_FULLSCREEN: 362 case WM_EVENT_SNAP_LEFT: 363 case WM_EVENT_SNAP_RIGHT: 364 case WM_EVENT_SET_BOUNDS: 365 case WM_EVENT_SHOW_INACTIVE: 366 break; 367 } 368 return false; 369} 370 371// static 372bool DefaultState::SetMaximizedOrFullscreenBounds(WindowState* window_state) { 373 DCHECK(!window_state->is_dragged()); 374 if (window_state->IsMaximized()) { 375 window_state->SetBoundsDirect( 376 ScreenUtil::GetMaximizedWindowBoundsInParent(window_state->window())); 377 return true; 378 } 379 if (window_state->IsFullscreen()) { 380 window_state->SetBoundsDirect( 381 ScreenUtil::GetDisplayBoundsInParent(window_state->window())); 382 return true; 383 } 384 return false; 385} 386 387// static 388void DefaultState::SetBounds(WindowState* window_state, 389 const SetBoundsEvent* event) { 390 if (window_state->is_dragged()) { 391 window_state->SetBoundsDirect(event->requested_bounds()); 392 } else if (window_state->IsSnapped()) { 393 gfx::Rect work_area_in_parent = 394 ScreenUtil::GetDisplayWorkAreaBoundsInParent(window_state->window()); 395 gfx::Rect child_bounds(event->requested_bounds()); 396 AdjustBoundsSmallerThan(work_area_in_parent.size(), &child_bounds); 397 window_state->AdjustSnappedBounds(&child_bounds); 398 window_state->SetBoundsDirect(child_bounds); 399 } else if (!SetMaximizedOrFullscreenBounds(window_state)) { 400 window_state->SetBoundsConstrained(event->requested_bounds()); 401 } 402} 403 404void DefaultState::EnterToNextState(WindowState* window_state, 405 WindowStateType next_state_type) { 406 // Do nothing if we're already in the same state. 407 if (state_type_ == next_state_type) 408 return; 409 410 WindowStateType previous_state_type = state_type_; 411 state_type_ = next_state_type; 412 413 window_state->UpdateWindowShowStateFromStateType(); 414 window_state->NotifyPreStateTypeChange(previous_state_type); 415 416 // This Docked/Snapped hack is due to the issue that IsDocked returns 417 // true for dragging window. TODO(oshima): Make docked window a state 418 // and remove this hack. 419 if (window_state->window()->parent() && 420 (window_state->IsSnapped() || 421 (!window_state->IsDocked() && !IsPanel(window_state->window())))) { 422 if (!window_state->HasRestoreBounds() && 423 (previous_state_type == WINDOW_STATE_TYPE_DEFAULT || 424 previous_state_type == WINDOW_STATE_TYPE_NORMAL) && 425 !window_state->IsMinimized() && 426 !window_state->IsNormalStateType()) { 427 window_state->SaveCurrentBoundsForRestore(); 428 } 429 430 // When restoring from a minimized state, we want to restore to the previous 431 // bounds. However, we want to maintain the restore bounds. (The restore 432 // bounds are set if a user maximized the window in one axis by double 433 // clicking the window border for example). 434 gfx::Rect restore_bounds_in_screen; 435 if (previous_state_type == WINDOW_STATE_TYPE_MINIMIZED && 436 window_state->IsNormalStateType() && 437 window_state->HasRestoreBounds() && 438 !window_state->unminimize_to_restore_bounds()) { 439 restore_bounds_in_screen = window_state->GetRestoreBoundsInScreen(); 440 window_state->SaveCurrentBoundsForRestore(); 441 } 442 443 if (window_state->IsMaximizedOrFullscreen()) 444 MoveToDisplayForRestore(window_state); 445 446 UpdateBoundsFromState(window_state, previous_state_type); 447 448 // Normal state should have no restore bounds unless it's 449 // unminimzied. 450 if (!restore_bounds_in_screen.IsEmpty()) 451 window_state->SetRestoreBoundsInScreen(restore_bounds_in_screen); 452 else if (window_state->IsNormalStateType()) 453 window_state->ClearRestoreBounds(); 454 } 455 window_state->NotifyPostStateTypeChange(previous_state_type); 456} 457 458void DefaultState::ReenterToCurrentState( 459 WindowState* window_state, 460 WindowState::State* state_in_previous_mode) { 461 WindowStateType previous_state_type = state_in_previous_mode->GetType(); 462 window_state->UpdateWindowShowStateFromStateType(); 463 window_state->NotifyPreStateTypeChange(previous_state_type); 464 465 if ((state_type_ == wm::WINDOW_STATE_TYPE_NORMAL || 466 state_type_ == wm::WINDOW_STATE_TYPE_DEFAULT) && 467 !stored_bounds_.IsEmpty()) { 468 // Use the restore mechanism to set the bounds for 469 // the window in normal state. This also covers unminimize case. 470 window_state->SetRestoreBoundsInParent(stored_bounds_); 471 } 472 473 UpdateBoundsFromState(window_state, state_in_previous_mode->GetType()); 474 475 // Then restore the restore bounds to their previous value. 476 if (!stored_restore_bounds_.IsEmpty()) 477 window_state->SetRestoreBoundsInParent(stored_restore_bounds_); 478 else 479 window_state->ClearRestoreBounds(); 480 481 window_state->NotifyPostStateTypeChange(previous_state_type); 482} 483 484void DefaultState::UpdateBoundsFromState(WindowState* window_state, 485 WindowStateType previous_state_type) { 486 aura::Window* window = window_state->window(); 487 gfx::Rect bounds_in_parent; 488 switch (state_type_) { 489 case WINDOW_STATE_TYPE_LEFT_SNAPPED: 490 case WINDOW_STATE_TYPE_RIGHT_SNAPPED: 491 bounds_in_parent = state_type_ == WINDOW_STATE_TYPE_LEFT_SNAPPED ? 492 GetDefaultLeftSnappedWindowBoundsInParent(window_state->window()) : 493 GetDefaultRightSnappedWindowBoundsInParent(window_state->window()); 494 break; 495 case WINDOW_STATE_TYPE_DEFAULT: 496 case WINDOW_STATE_TYPE_NORMAL: { 497 gfx::Rect work_area_in_parent = 498 ScreenUtil::GetDisplayWorkAreaBoundsInParent(window_state->window()); 499 if (window_state->HasRestoreBounds()) 500 bounds_in_parent = window_state->GetRestoreBoundsInParent(); 501 else 502 bounds_in_parent = window->bounds(); 503 // Make sure that part of the window is always visible. 504 AdjustBoundsToEnsureMinimumWindowVisibility( 505 work_area_in_parent, &bounds_in_parent); 506 break; 507 } 508 case WINDOW_STATE_TYPE_MAXIMIZED: 509 bounds_in_parent = ScreenUtil::GetMaximizedWindowBoundsInParent(window); 510 break; 511 512 case WINDOW_STATE_TYPE_FULLSCREEN: 513 bounds_in_parent = ScreenUtil::GetDisplayBoundsInParent(window); 514 break; 515 516 case WINDOW_STATE_TYPE_MINIMIZED: 517 break; 518 case WINDOW_STATE_TYPE_INACTIVE: 519 case WINDOW_STATE_TYPE_DETACHED: 520 case WINDOW_STATE_TYPE_END: 521 case WINDOW_STATE_TYPE_AUTO_POSITIONED: 522 return; 523 } 524 525 if (state_type_ != WINDOW_STATE_TYPE_MINIMIZED) { 526 if (previous_state_type == WINDOW_STATE_TYPE_MINIMIZED || 527 window_state->IsFullscreen()) { 528 window_state->SetBoundsDirect(bounds_in_parent); 529 } else if (window_state->IsMaximized() || 530 IsMaximizedOrFullscreenWindowStateType(previous_state_type)) { 531 window_state->SetBoundsDirectCrossFade(bounds_in_parent); 532 } else if (window_state->is_dragged()) { 533 // SetBoundsDirectAnimated does not work when the window gets reparented. 534 // TODO(oshima): Consider fixing it and reenable the animation. 535 window_state->SetBoundsDirect(bounds_in_parent); 536 } else { 537 window_state->SetBoundsDirectAnimated(bounds_in_parent); 538 } 539 } 540 541 if (window_state->IsMinimized()) { 542 // Save the previous show state so that we can correctly restore it. 543 window_state->window()->SetProperty(aura::client::kRestoreShowStateKey, 544 ToWindowShowState(previous_state_type)); 545 ::wm::SetWindowVisibilityAnimationType( 546 window_state->window(), WINDOW_VISIBILITY_ANIMATION_TYPE_MINIMIZE); 547 548 // Hide the window. 549 window_state->window()->Hide(); 550 // Activate another window. 551 if (window_state->IsActive()) 552 window_state->Deactivate(); 553 } else if ((window_state->window()->TargetVisibility() || 554 previous_state_type == WINDOW_STATE_TYPE_MINIMIZED) && 555 !window_state->window()->layer()->visible()) { 556 // The layer may be hidden if the window was previously minimized. Make 557 // sure it's visible. 558 window_state->window()->Show(); 559 if (previous_state_type == WINDOW_STATE_TYPE_MINIMIZED && 560 !window_state->IsMaximizedOrFullscreen()) { 561 window_state->set_unminimize_to_restore_bounds(false); 562 } 563 } 564} 565 566// static 567void DefaultState::CenterWindow(WindowState* window_state) { 568 if (!window_state->IsNormalOrSnapped()) 569 return; 570 aura::Window* window = window_state->window(); 571 if (window_state->IsSnapped()) { 572 gfx::Rect center_in_screen = 573 Shell::GetScreen()->GetDisplayNearestWindow(window).work_area(); 574 gfx::Size size = window_state->HasRestoreBounds() ? 575 window_state->GetRestoreBoundsInScreen().size() : 576 window->bounds().size(); 577 center_in_screen.ClampToCenteredSize(size); 578 window_state->SetRestoreBoundsInScreen(center_in_screen); 579 window_state->Restore(); 580 } else { 581 gfx::Rect center_in_parent = 582 ScreenUtil::GetDisplayWorkAreaBoundsInParent(window); 583 center_in_parent.ClampToCenteredSize(window->bounds().size()); 584 window_state->SetBoundsDirectAnimated(center_in_parent); 585 } 586 // Centering window is treated as if a user moved and resized the window. 587 window_state->set_bounds_changed_by_user(true); 588} 589 590} // namespace wm 591} // namespace ash 592