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