Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / ash / wm / default_state.cc
bloba6e0ee291bf6b81ef6533a8f00f14425ee2d05f4
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.
5 #include "ash/wm/default_state.h"
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"
25 namespace ash {
26 namespace wm {
27 namespace {
29 // This specifies how much percent (30%) of a window rect
30 // must be visible when the window is added to the workspace.
31 const float kMinimumPercentOnScreenArea = 0.3f;
33 bool IsPanel(aura::Window* window) {
34 return window->parent() &&
35 window->parent()->id() == kShellWindowId_PanelContainer;
38 void MoveToDisplayForRestore(WindowState* window_state) {
39 if (!window_state->HasRestoreBounds())
40 return;
41 const gfx::Rect& restore_bounds = window_state->GetRestoreBoundsInScreen();
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();
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());
67 } // namespace;
69 DefaultState::DefaultState(WindowStateType initial_state_type)
70 : state_type_(initial_state_type) {}
71 DefaultState::~DefaultState() {}
73 void DefaultState::OnWMEvent(WindowState* window_state,
74 const WMEvent* event) {
75 if (ProcessWorkspaceEvents(window_state, event))
76 return;
78 if (ProcessCompoundEvents(window_state, event))
79 return;
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;
122 WindowStateType current = window_state->GetStateType();
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;
132 EnterToNextState(window_state, next_state_type);
135 WindowStateType DefaultState::GetType() const {
136 return state_type_;
139 void DefaultState::AttachState(
140 WindowState* window_state,
141 WindowState::State* state_in_previous_mode) {
142 DCHECK_EQ(stored_window_state_, window_state);
144 ReenterToCurrentState(window_state, state_in_previous_mode);
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);
159 void 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());
173 // static
174 bool DefaultState::ProcessCompoundEvents(WindowState* window_state,
175 const WMEvent* event) {
176 aura::Window* window = window_state->window();
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();
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();
199 return true;
200 case WM_EVENT_TOGGLE_VERTICAL_MAXIMIZE: {
201 gfx::Rect work_area =
202 ScreenUtil::GetDisplayWorkAreaBoundsInParent(window);
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;
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()));
224 return true;
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());
247 gfx::Rect restore_bounds = window->bounds();
248 if (window_state->IsSnapped()) {
249 window_state->SetRestoreBoundsInParent(new_bounds);
250 window_state->Restore();
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.
257 window_state->SetRestoreBoundsInParent(restore_bounds);
258 window->SetBounds(new_bounds);
260 return true;
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;
283 return false;
286 bool 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;
300 aura::Window* window = window_state->window();
301 gfx::Rect bounds = window->bounds();
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;
308 // Only windows of type WINDOW_TYPE_NORMAL or WINDOW_TYPE_PANEL need to be
309 // adjusted to have minimum visibility, because they are positioned by the
310 // user and user should always be able to interact with them. Other
311 // windows are positioned programmatically.
312 if (window_state->window()->type() != ui::wm::WINDOW_TYPE_NORMAL &&
313 window_state->window()->type() != ui::wm::WINDOW_TYPE_PANEL) {
314 return true;
317 // Use entire display instead of workarea because the workarea can
318 // be further shrunk by the docked area. The logic ensures 30%
319 // visibility which should be enough to see where the window gets
320 // moved.
321 gfx::Rect display_area = ScreenUtil::GetDisplayBoundsInParent(window);
322 int min_width = bounds.width() * kMinimumPercentOnScreenArea;
323 int min_height = bounds.height() * kMinimumPercentOnScreenArea;
324 AdjustBoundsToEnsureWindowVisibility(
325 display_area, min_width, min_height, &bounds);
326 window_state->AdjustSnappedBounds(&bounds);
327 if (window->bounds() != bounds)
328 window_state->SetBoundsConstrained(bounds);
329 return true;
331 case WM_EVENT_DISPLAY_BOUNDS_CHANGED: {
332 if (window_state->is_dragged() ||
333 SetMaximizedOrFullscreenBounds(window_state)) {
334 return true;
336 gfx::Rect work_area_in_parent =
337 ScreenUtil::GetDisplayWorkAreaBoundsInParent(window_state->window());
338 gfx::Rect bounds = window_state->window()->bounds();
339 // When display bounds has changed, make sure the entire window is fully
340 // visible.
341 bounds.AdjustToFit(work_area_in_parent);
342 window_state->AdjustSnappedBounds(&bounds);
343 if (window_state->window()->bounds() != bounds)
344 window_state->SetBoundsDirectAnimated(bounds);
345 return true;
347 case WM_EVENT_WORKAREA_BOUNDS_CHANGED: {
348 if (window_state->is_dragged() ||
349 SetMaximizedOrFullscreenBounds(window_state)) {
350 return true;
352 gfx::Rect work_area_in_parent =
353 ScreenUtil::GetDisplayWorkAreaBoundsInParent(window_state->window());
354 gfx::Rect bounds = window_state->window()->bounds();
355 AdjustBoundsToEnsureMinimumWindowVisibility(work_area_in_parent, &bounds);
356 window_state->AdjustSnappedBounds(&bounds);
357 if (window_state->window()->bounds() != bounds)
358 window_state->SetBoundsDirectAnimated(bounds);
359 return true;
361 case WM_EVENT_TOGGLE_MAXIMIZE_CAPTION:
362 case WM_EVENT_TOGGLE_MAXIMIZE:
363 case WM_EVENT_TOGGLE_VERTICAL_MAXIMIZE:
364 case WM_EVENT_TOGGLE_HORIZONTAL_MAXIMIZE:
365 case WM_EVENT_TOGGLE_FULLSCREEN:
366 case WM_EVENT_CENTER:
367 case WM_EVENT_NORMAL:
368 case WM_EVENT_MAXIMIZE:
369 case WM_EVENT_MINIMIZE:
370 case WM_EVENT_FULLSCREEN:
371 case WM_EVENT_SNAP_LEFT:
372 case WM_EVENT_SNAP_RIGHT:
373 case WM_EVENT_SET_BOUNDS:
374 case WM_EVENT_SHOW_INACTIVE:
375 break;
377 return false;
380 // static
381 bool DefaultState::SetMaximizedOrFullscreenBounds(WindowState* window_state) {
382 DCHECK(!window_state->is_dragged());
383 if (window_state->IsMaximized()) {
384 window_state->SetBoundsDirect(
385 ScreenUtil::GetMaximizedWindowBoundsInParent(window_state->window()));
386 return true;
388 if (window_state->IsFullscreen()) {
389 window_state->SetBoundsDirect(
390 ScreenUtil::GetDisplayBoundsInParent(window_state->window()));
391 return true;
393 return false;
396 // static
397 void DefaultState::SetBounds(WindowState* window_state,
398 const SetBoundsEvent* event) {
399 if (window_state->is_dragged()) {
400 window_state->SetBoundsDirect(event->requested_bounds());
401 } else if (window_state->IsSnapped()) {
402 gfx::Rect work_area_in_parent =
403 ScreenUtil::GetDisplayWorkAreaBoundsInParent(window_state->window());
404 gfx::Rect child_bounds(event->requested_bounds());
405 AdjustBoundsSmallerThan(work_area_in_parent.size(), &child_bounds);
406 window_state->AdjustSnappedBounds(&child_bounds);
407 window_state->SetBoundsDirect(child_bounds);
408 } else if (!SetMaximizedOrFullscreenBounds(window_state)) {
409 window_state->SetBoundsConstrained(event->requested_bounds());
413 void DefaultState::EnterToNextState(WindowState* window_state,
414 WindowStateType next_state_type) {
415 // Do nothing if we're already in the same state.
416 if (state_type_ == next_state_type)
417 return;
419 WindowStateType previous_state_type = state_type_;
420 state_type_ = next_state_type;
422 window_state->UpdateWindowShowStateFromStateType();
423 window_state->NotifyPreStateTypeChange(previous_state_type);
425 // This Docked/Snapped hack is due to the issue that IsDocked returns
426 // true for dragging window. TODO(oshima): Make docked window a state
427 // and remove this hack.
428 if (window_state->window()->parent() &&
429 (window_state->IsSnapped() ||
430 (!window_state->IsDocked() && !IsPanel(window_state->window())))) {
431 if (!window_state->HasRestoreBounds() &&
432 (previous_state_type == WINDOW_STATE_TYPE_DEFAULT ||
433 previous_state_type == WINDOW_STATE_TYPE_NORMAL) &&
434 !window_state->IsMinimized() &&
435 !window_state->IsNormalStateType()) {
436 window_state->SaveCurrentBoundsForRestore();
439 // When restoring from a minimized state, we want to restore to the previous
440 // bounds. However, we want to maintain the restore bounds. (The restore
441 // bounds are set if a user maximized the window in one axis by double
442 // clicking the window border for example).
443 gfx::Rect restore_bounds_in_screen;
444 if (previous_state_type == WINDOW_STATE_TYPE_MINIMIZED &&
445 window_state->IsNormalStateType() &&
446 window_state->HasRestoreBounds() &&
447 !window_state->unminimize_to_restore_bounds()) {
448 restore_bounds_in_screen = window_state->GetRestoreBoundsInScreen();
449 window_state->SaveCurrentBoundsForRestore();
452 if (window_state->IsMaximizedOrFullscreen())
453 MoveToDisplayForRestore(window_state);
455 UpdateBoundsFromState(window_state, previous_state_type);
457 // Normal state should have no restore bounds unless it's
458 // unminimzied.
459 if (!restore_bounds_in_screen.IsEmpty())
460 window_state->SetRestoreBoundsInScreen(restore_bounds_in_screen);
461 else if (window_state->IsNormalStateType())
462 window_state->ClearRestoreBounds();
464 window_state->NotifyPostStateTypeChange(previous_state_type);
467 void DefaultState::ReenterToCurrentState(
468 WindowState* window_state,
469 WindowState::State* state_in_previous_mode) {
470 WindowStateType previous_state_type = state_in_previous_mode->GetType();
471 if (previous_state_type == wm::WINDOW_STATE_TYPE_FULLSCREEN) {
472 // A state change should not move a window out of full screen since full
473 // screen is a "special mode" the user wanted to be in and should be
474 // respected as such.
475 state_type_ = wm::WINDOW_STATE_TYPE_FULLSCREEN;
477 window_state->UpdateWindowShowStateFromStateType();
478 window_state->NotifyPreStateTypeChange(previous_state_type);
480 if ((state_type_ == wm::WINDOW_STATE_TYPE_NORMAL ||
481 state_type_ == wm::WINDOW_STATE_TYPE_DEFAULT) &&
482 !stored_bounds_.IsEmpty()) {
483 // Use the restore mechanism to set the bounds for
484 // the window in normal state. This also covers unminimize case.
485 window_state->SetRestoreBoundsInParent(stored_bounds_);
488 UpdateBoundsFromState(window_state, state_in_previous_mode->GetType());
490 // Then restore the restore bounds to their previous value.
491 if (!stored_restore_bounds_.IsEmpty())
492 window_state->SetRestoreBoundsInParent(stored_restore_bounds_);
493 else
494 window_state->ClearRestoreBounds();
496 window_state->NotifyPostStateTypeChange(previous_state_type);
499 void DefaultState::UpdateBoundsFromState(WindowState* window_state,
500 WindowStateType previous_state_type) {
501 aura::Window* window = window_state->window();
502 gfx::Rect bounds_in_parent;
503 switch (state_type_) {
504 case WINDOW_STATE_TYPE_LEFT_SNAPPED:
505 case WINDOW_STATE_TYPE_RIGHT_SNAPPED:
506 bounds_in_parent = state_type_ == WINDOW_STATE_TYPE_LEFT_SNAPPED ?
507 GetDefaultLeftSnappedWindowBoundsInParent(window_state->window()) :
508 GetDefaultRightSnappedWindowBoundsInParent(window_state->window());
509 break;
510 case WINDOW_STATE_TYPE_DEFAULT:
511 case WINDOW_STATE_TYPE_NORMAL: {
512 gfx::Rect work_area_in_parent =
513 ScreenUtil::GetDisplayWorkAreaBoundsInParent(window_state->window());
514 if (window_state->HasRestoreBounds()) {
515 bounds_in_parent = window_state->GetRestoreBoundsInParent();
516 // Check if the |window|'s restored size is bigger than the working area
517 // This may happen if a window was resized to maximized bounds or if the
518 // display resolution changed while the window was maximized.
519 if (previous_state_type == WINDOW_STATE_TYPE_MAXIMIZED &&
520 bounds_in_parent.width() >= work_area_in_parent.width() &&
521 bounds_in_parent.height() >= work_area_in_parent.height()) {
522 // Inset the bounds slightly so that they are not exactly same as
523 // the work area bounds and it is easier to resize the window.
524 bounds_in_parent = work_area_in_parent;
525 bounds_in_parent.Inset(10, 10, 10, 10);
527 } else {
528 bounds_in_parent = window->bounds();
530 // Make sure that part of the window is always visible.
531 AdjustBoundsToEnsureMinimumWindowVisibility(
532 work_area_in_parent, &bounds_in_parent);
533 break;
535 case WINDOW_STATE_TYPE_MAXIMIZED:
536 bounds_in_parent = ScreenUtil::GetMaximizedWindowBoundsInParent(window);
537 break;
539 case WINDOW_STATE_TYPE_FULLSCREEN:
540 bounds_in_parent = ScreenUtil::GetDisplayBoundsInParent(window);
541 break;
543 case WINDOW_STATE_TYPE_MINIMIZED:
544 break;
545 case WINDOW_STATE_TYPE_INACTIVE:
546 case WINDOW_STATE_TYPE_END:
547 case WINDOW_STATE_TYPE_AUTO_POSITIONED:
548 return;
551 if (state_type_ != WINDOW_STATE_TYPE_MINIMIZED) {
552 if (previous_state_type == WINDOW_STATE_TYPE_MINIMIZED ||
553 window_state->IsFullscreen()) {
554 window_state->SetBoundsDirect(bounds_in_parent);
555 } else if (window_state->IsMaximized() ||
556 IsMaximizedOrFullscreenWindowStateType(previous_state_type)) {
557 window_state->SetBoundsDirectCrossFade(bounds_in_parent);
558 } else if (window_state->is_dragged()) {
559 // SetBoundsDirectAnimated does not work when the window gets reparented.
560 // TODO(oshima): Consider fixing it and reenable the animation.
561 window_state->SetBoundsDirect(bounds_in_parent);
562 } else {
563 window_state->SetBoundsDirectAnimated(bounds_in_parent);
567 if (window_state->IsMinimized()) {
568 // Save the previous show state so that we can correctly restore it.
569 window_state->window()->SetProperty(aura::client::kRestoreShowStateKey,
570 ToWindowShowState(previous_state_type));
571 ::wm::SetWindowVisibilityAnimationType(
572 window_state->window(), WINDOW_VISIBILITY_ANIMATION_TYPE_MINIMIZE);
574 // Hide the window.
575 window_state->window()->Hide();
576 // Activate another window.
577 if (window_state->IsActive())
578 window_state->Deactivate();
579 } else if ((window_state->window()->TargetVisibility() ||
580 previous_state_type == WINDOW_STATE_TYPE_MINIMIZED) &&
581 !window_state->window()->layer()->visible()) {
582 // The layer may be hidden if the window was previously minimized. Make
583 // sure it's visible.
584 window_state->window()->Show();
585 if (previous_state_type == WINDOW_STATE_TYPE_MINIMIZED &&
586 !window_state->IsMaximizedOrFullscreen()) {
587 window_state->set_unminimize_to_restore_bounds(false);
592 // static
593 void DefaultState::CenterWindow(WindowState* window_state) {
594 if (!window_state->IsNormalOrSnapped())
595 return;
596 aura::Window* window = window_state->window();
597 if (window_state->IsSnapped()) {
598 gfx::Rect center_in_screen =
599 Shell::GetScreen()->GetDisplayNearestWindow(window).work_area();
600 gfx::Size size = window_state->HasRestoreBounds() ?
601 window_state->GetRestoreBoundsInScreen().size() :
602 window->bounds().size();
603 center_in_screen.ClampToCenteredSize(size);
604 window_state->SetRestoreBoundsInScreen(center_in_screen);
605 window_state->Restore();
606 } else {
607 gfx::Rect center_in_parent =
608 ScreenUtil::GetDisplayWorkAreaBoundsInParent(window);
609 center_in_parent.ClampToCenteredSize(window->bounds().size());
610 window_state->SetBoundsDirectAnimated(center_in_parent);
612 // Centering window is treated as if a user moved and resized the window.
613 window_state->set_bounds_changed_by_user(true);
616 } // namespace wm
617 } // namespace ash