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"
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"
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())
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());
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
))
78 if (ProcessCompoundEvents(window_state
, event
))
81 WindowStateType next_state_type
= WINDOW_STATE_TYPE_NORMAL
;
82 switch (event
->type()) {
84 next_state_type
= WINDOW_STATE_TYPE_NORMAL
;
86 case WM_EVENT_MAXIMIZE
:
87 next_state_type
= WINDOW_STATE_TYPE_MAXIMIZED
;
89 case WM_EVENT_MINIMIZE
:
90 next_state_type
= WINDOW_STATE_TYPE_MINIMIZED
;
92 case WM_EVENT_FULLSCREEN
:
93 next_state_type
= WINDOW_STATE_TYPE_FULLSCREEN
;
95 case WM_EVENT_SNAP_LEFT
:
96 next_state_type
= WINDOW_STATE_TYPE_LEFT_SNAPPED
;
98 case WM_EVENT_SNAP_RIGHT
:
99 next_state_type
= WINDOW_STATE_TYPE_RIGHT_SNAPPED
;
101 case WM_EVENT_SET_BOUNDS
:
102 SetBounds(window_state
, static_cast<const SetBoundsEvent
*>(event
));
104 case WM_EVENT_SHOW_INACTIVE
:
105 next_state_type
= WINDOW_STATE_TYPE_INACTIVE
;
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
;
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
;
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
);
132 EnterToNextState(window_state
, next_state_type
);
135 WindowStateType
DefaultState::GetType() const {
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
169 stored_display_state_
= Shell::GetScreen()->
170 GetDisplayNearestWindow(window_state
->window());
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();
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();
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()) {
213 if (window_state
->HasRestoreBounds() &&
214 (window
->bounds().height() == work_area
.height() &&
215 window
->bounds().y() == work_area
.y())) {
216 window_state
->SetAndClearRestoreBounds();
218 window_state
->SaveCurrentBoundsForRestore();
219 window
->SetBounds(gfx::Rect(window
->bounds().x(),
221 window
->bounds().width(),
222 work_area
.height()));
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)
232 if (!window_state
->IsNormalOrSnapped())
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();
242 gfx::Rect
new_bounds(work_area
.x(),
243 window
->bounds().y(),
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
);
262 case WM_EVENT_TOGGLE_FULLSCREEN
:
263 ToggleFullScreen(window_state
, window_state
->delegate());
265 case WM_EVENT_CENTER
:
266 CenterWindow(window_state
);
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
:
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
;
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
)) {
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())
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
) {
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
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
);
331 case WM_EVENT_DISPLAY_BOUNDS_CHANGED
: {
332 if (window_state
->is_dragged() ||
333 SetMaximizedOrFullscreenBounds(window_state
)) {
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
341 bounds
.AdjustToFit(work_area_in_parent
);
342 window_state
->AdjustSnappedBounds(&bounds
);
343 if (window_state
->window()->bounds() != bounds
)
344 window_state
->SetBoundsDirectAnimated(bounds
);
347 case WM_EVENT_WORKAREA_BOUNDS_CHANGED
: {
348 if (window_state
->is_dragged() ||
349 SetMaximizedOrFullscreenBounds(window_state
)) {
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
);
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
:
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()));
388 if (window_state
->IsFullscreen()) {
389 window_state
->SetBoundsDirect(
390 ScreenUtil::GetDisplayBoundsInParent(window_state
->window()));
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
)
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
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_
);
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());
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);
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
);
535 case WINDOW_STATE_TYPE_MAXIMIZED
:
536 bounds_in_parent
= ScreenUtil::GetMaximizedWindowBoundsInParent(window
);
539 case WINDOW_STATE_TYPE_FULLSCREEN
:
540 bounds_in_parent
= ScreenUtil::GetDisplayBoundsInParent(window
);
543 case WINDOW_STATE_TYPE_MINIMIZED
:
545 case WINDOW_STATE_TYPE_INACTIVE
:
546 case WINDOW_STATE_TYPE_END
:
547 case WINDOW_STATE_TYPE_AUTO_POSITIONED
:
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
);
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
);
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);
593 void DefaultState::CenterWindow(WindowState
* window_state
) {
594 if (!window_state
->IsNormalOrSnapped())
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();
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);