Chromium Code Reviews| Index: ash/wm/default_state.cc |
| diff --git a/ash/wm/default_state.cc b/ash/wm/default_state.cc |
| index 3787f7f30f46aeaed6eb4579146baa5a6fe73e5c..382ede257f7fde97eb9452eea838805ece1aa09f 100644 |
| --- a/ash/wm/default_state.cc |
| +++ b/ash/wm/default_state.cc |
| @@ -4,10 +4,16 @@ |
| #include "ash/wm/default_state.h" |
| +#include "ash/display/display_controller.h" |
| #include "ash/screen_util.h" |
| #include "ash/shell.h" |
| #include "ash/wm/coordinate_conversion.h" |
| +#include "ash/wm/window_animations.h" |
| #include "ash/wm/window_state.h" |
| +#include "ash/wm/window_state_delegate.h" |
| +#include "ash/wm/window_util.h" |
| +#include "ash/wm/workspace/workspace_window_resizer.h" |
| +#include "ui/aura/client/aura_constants.h" |
| #include "ui/aura/window.h" |
| #include "ui/aura/window_delegate.h" |
| #include "ui/gfx/display.h" |
| @@ -15,12 +21,104 @@ |
| namespace ash { |
| namespace wm { |
| +namespace { |
| + |
| +gfx::Rect BoundsWithScreenEdgeVisible( |
| + aura::Window* window, |
| + const gfx::Rect& restore_bounds) { |
| + gfx::Rect max_bounds = |
| + ash::ScreenUtil::GetMaximizedWindowBoundsInParent(window); |
| + // If the restore_bounds are more than 1 grid step away from the size the |
| + // window would be when maximized, inset it. |
| + max_bounds.Inset(ash::internal::WorkspaceWindowResizer::kScreenEdgeInset, |
| + ash::internal::WorkspaceWindowResizer::kScreenEdgeInset); |
| + if (restore_bounds.Contains(max_bounds)) |
| + return max_bounds; |
| + return restore_bounds; |
| +} |
| + |
| +void MoveToDisplayForRestore(wm::WindowState* window_state) { |
| + if (!window_state->HasRestoreBounds()) |
| + return; |
| + const gfx::Rect& restore_bounds = window_state->GetRestoreBoundsInScreen(); |
| + |
| + // Move only if the restore bounds is outside of |
| + // the display. There is no information about in which |
| + // display it should be restored, so this is best guess. |
| + // TODO(oshima): Restore information should contain the |
| + // work area information like WindowResizer does for the |
| + // last window location. |
| + gfx::Rect display_area = Shell::GetScreen()->GetDisplayNearestWindow( |
| + window_state->window()).bounds(); |
| + |
| + if (!display_area.Intersects(restore_bounds)) { |
| + const gfx::Display& display = |
| + Shell::GetScreen()->GetDisplayMatching(restore_bounds); |
| + DisplayController* display_controller = |
| + Shell::GetInstance()->display_controller(); |
| + aura::Window* new_root = |
| + display_controller->GetRootWindowForDisplayId(display.id()); |
| + if (new_root != window_state->window()->GetRootWindow()) { |
| + aura::Window* new_container = |
| + Shell::GetContainer(new_root, window_state->window()->parent()->id()); |
| + new_container->AddChild(window_state->window()); |
| + } |
| + } |
| +} |
| + |
| +} // namespace; |
| DefaultState::DefaultState() {} |
| DefaultState::~DefaultState() {} |
| void DefaultState::OnWMEvent(WindowState* window_state, |
| WMEvent event) { |
| + if (ProcessCompoundEvents(window_state, event)) |
| + return; |
| + |
| + WindowShowType next_show_type; |
| + |
| + switch (event) { |
| + case NORMAL: |
| + next_show_type = SHOW_TYPE_NORMAL; |
| + break; |
| + case MAXIMIZE: |
| + next_show_type = SHOW_TYPE_MAXIMIZED; |
| + break; |
| + case MINIMIZE: |
| + next_show_type = SHOW_TYPE_MINIMIZED; |
| + break; |
| + case FULLSCREEN: |
| + next_show_type = SHOW_TYPE_FULLSCREEN; |
| + break; |
| + case SNAP_LEFT: |
| + next_show_type = SHOW_TYPE_LEFT_SNAPPED; |
| + break; |
| + case SNAP_RIGHT: |
| + next_show_type = SHOW_TYPE_RIGHT_SNAPPED; |
| + break; |
| + case TOGGLE_MAXIMIZE_CAPTION: |
| + case TOGGLE_MAXIMIZE: |
| + case TOGGLE_VERTICAL_MAXIMIZE: |
| + case TOGGLE_HORIZONTAL_MAXIMIZE: |
| + case TOGGLE_FULLSCREEN: |
| + NOTREACHED() << "Compound event should not reach here:" << event; |
| + return; |
| + } |
| + |
| + WindowShowType current = window_state->window_show_type(); |
| + if (current != next_show_type) { |
| + window_state->UpdateWindowShowType(next_show_type); |
| + window_state->NotifyPreShowTypeChange(current); |
| + if (!window_state->IsDocked()) |
| + UpdateBoundsFromShowType(window_state, current); |
| + window_state->NotifyPostShowTypeChange(current); |
| + } |
| +}; |
| + |
| +// static |
| +bool DefaultState::ProcessCompoundEvents(WindowState* window_state, |
| + WMEvent event) { |
| aura::Window* window = window_state->window(); |
| switch (event) { |
| @@ -34,8 +132,7 @@ void DefaultState::OnWMEvent(WindowState* window_state, |
| if (window_state->CanMaximize()) |
| window_state->Maximize(); |
| } |
| - break; |
| - |
| + return true; |
| case TOGGLE_MAXIMIZE: |
| if (window_state->IsFullscreen()) |
| window_state->ToggleFullscreen(); |
| @@ -43,8 +140,7 @@ void DefaultState::OnWMEvent(WindowState* window_state, |
| window_state->Restore(); |
| else if (window_state->CanMaximize()) |
| window_state->Maximize(); |
| - break; |
| - |
| + return true; |
| case TOGGLE_VERTICAL_MAXIMIZE: { |
| gfx::Rect work_area = |
| ScreenUtil::GetDisplayWorkAreaBoundsInParent(window); |
| @@ -56,7 +152,7 @@ void DefaultState::OnWMEvent(WindowState* window_state, |
| // restored bounds looks weird. |
| if (window->delegate()->GetMaximumSize().height() != 0 || |
| !window_state->IsNormalShowType()) { |
| - return; |
| + return true; |
| } |
| if (window_state->HasRestoreBounds() && |
| (window->bounds().height() == work_area.height() && |
| @@ -69,20 +165,18 @@ void DefaultState::OnWMEvent(WindowState* window_state, |
| window->bounds().width(), |
| work_area.height())); |
| } |
| - break; |
| + return true; |
| } |
| case TOGGLE_HORIZONTAL_MAXIMIZE: { |
| // Maximize horizontally if: |
| // - The window does not have a max width defined. |
| // - The window is snapped or has the normal show type. |
| if (window->delegate()->GetMaximumSize().width() != 0) |
| - return; |
| + return true; |
| if (!window_state->IsNormalShowType() && !window_state->IsSnapped()) |
| - return; |
| - |
| + return true; |
| gfx::Rect work_area = |
| ScreenUtil::GetDisplayWorkAreaBoundsInParent(window); |
| - |
| if (window_state->IsNormalShowType() && |
| window_state->HasRestoreBounds() && |
| (window->bounds().width() == work_area.width() && |
| @@ -107,9 +201,157 @@ void DefaultState::OnWMEvent(WindowState* window_state, |
| window_state->SetRestoreBoundsInParent(restore_bounds); |
| window->SetBounds(new_bounds); |
| } |
| + return true; |
| + } |
| + case TOGGLE_FULLSCREEN: { |
| + // Window which cannot be maximized should not be fullscreened. |
| + // It can, however, be restored if it was fullscreened. |
| + bool is_fullscreen = window_state->IsFullscreen(); |
| + if (!is_fullscreen && !window_state->CanMaximize()) |
| + return true; |
| + if (window_state->delegate() && |
| + window_state->delegate()->ToggleFullscreen(window_state)) { |
| + return true; |
| + } |
| + if (is_fullscreen) { |
| + window_state->Restore(); |
| + } else { |
| + // |
| + window_state->window()->SetProperty(aura::client::kShowStateKey, |
| + ui::SHOW_STATE_FULLSCREEN); |
| + } |
| + return true; |
| } |
| + case NORMAL: |
| + case MAXIMIZE: |
| + case MINIMIZE: |
| + case FULLSCREEN: |
| + case SNAP_LEFT: |
| + case SNAP_RIGHT: |
| + break; |
| } |
| -}; |
| + return false; |
| +} |
| + |
| +// static |
| +void DefaultState::UpdateBoundsFromShowType(wm::WindowState* window_state, |
|
oshima
2014/02/11 21:49:35
The code that updates window state in OnWindowShow
|
| + wm::WindowShowType old_show_type) { |
| + if (old_show_type != wm::SHOW_TYPE_MINIMIZED && |
| + !window_state->HasRestoreBounds() && |
| + window_state->IsMaximizedOrFullscreen() && |
| + !wm::IsMaximizedOrFullscreenWindowShowType(old_show_type)) { |
| + window_state->SaveCurrentBoundsForRestore(); |
| + } |
| + |
| + // When restoring from a minimized state, we want to restore to the previous |
| + // bounds. However, we want to maintain the restore bounds. (The restore |
| + // bounds are set if a user maximized the window in one axis by double |
| + // clicking the window border for example). |
| + gfx::Rect restore; |
| + if (old_show_type == wm::SHOW_TYPE_MINIMIZED && |
| + window_state->IsNormalShowState() && |
| + window_state->HasRestoreBounds() && |
| + !window_state->unminimize_to_restore_bounds()) { |
| + restore = window_state->GetRestoreBoundsInScreen(); |
| + window_state->SaveCurrentBoundsForRestore(); |
| + } |
| + |
| + aura::Window* window = window_state->window(); |
| + if (window_state->IsMaximizedOrFullscreen()) |
| + MoveToDisplayForRestore(window_state); |
| + |
| + gfx::Rect work_area_in_parent = |
| + ScreenUtil::GetDisplayWorkAreaBoundsInParent(window_state->window()); |
| + |
| + wm::WindowShowType show_type = window_state->window_show_type(); |
| + gfx::Rect bounds_in_parent; |
| + switch (show_type) { |
| + case wm::SHOW_TYPE_DEFAULT: |
| + case wm::SHOW_TYPE_NORMAL: |
| + case wm::SHOW_TYPE_LEFT_SNAPPED: |
| + case wm::SHOW_TYPE_RIGHT_SNAPPED: |
| + if (window_state->HasRestoreBounds()) |
| + bounds_in_parent = window_state->GetRestoreBoundsInParent(); |
| + else |
| + bounds_in_parent = window->bounds(); |
| + // Make sure that part of the window is always visible. |
| + wm::AdjustBoundsToEnsureMinimumWindowVisibility( |
| + work_area_in_parent, &bounds_in_parent); |
| + |
| + if (show_type == wm::SHOW_TYPE_LEFT_SNAPPED || |
| + show_type == wm::SHOW_TYPE_RIGHT_SNAPPED) { |
| + window_state->AdjustSnappedBounds(&bounds_in_parent); |
| + } else { |
| + bounds_in_parent = BoundsWithScreenEdgeVisible( |
| + window, |
| + bounds_in_parent); |
| + } |
| + break; |
| + |
| + case wm::SHOW_TYPE_MAXIMIZED: |
| + bounds_in_parent = ScreenUtil::GetMaximizedWindowBoundsInParent(window); |
| + break; |
| + |
| + case wm::SHOW_TYPE_FULLSCREEN: |
| + bounds_in_parent = ScreenUtil::GetDisplayBoundsInParent(window); |
| + break; |
| + |
| + case wm::SHOW_TYPE_MINIMIZED: |
| + break; |
| + case wm::SHOW_TYPE_INACTIVE: |
| + case wm::SHOW_TYPE_DETACHED: |
| + case wm::SHOW_TYPE_END: |
| + case wm::SHOW_TYPE_AUTO_POSITIONED: |
| + return; |
| + } |
| + |
| + if (show_type != wm::SHOW_TYPE_MINIMIZED) { |
| + if (old_show_type == wm::SHOW_TYPE_MINIMIZED || |
| + (window_state->IsFullscreen() && |
| + !window_state->animate_to_fullscreen())) { |
| + window_state->SetBoundsDirect(bounds_in_parent); |
| + } else if (window_state->IsMaximizedOrFullscreen() || |
| + IsMaximizedOrFullscreenWindowShowType(old_show_type)) { |
| + CrossFadeToBounds(window, bounds_in_parent); |
| + } else { |
| + window_state->SetBoundsDirectAnimated(bounds_in_parent); |
| + } |
| + } |
| + |
| + if (window_state->IsMinimized()) { |
| + if (old_show_type == wm::SHOW_TYPE_MINIMIZED) |
| + return; |
| + |
| + // Save the previous show state so that we can correctly restore it. |
| + window_state->window()->SetProperty(aura::client::kRestoreShowStateKey, |
| + wm::ToWindowShowState(old_show_type)); |
| + views::corewm::SetWindowVisibilityAnimationType( |
| + window_state->window(), WINDOW_VISIBILITY_ANIMATION_TYPE_MINIMIZE); |
| + |
| + // Hide the window. |
| + window_state->window()->Hide(); |
| + // Activate another window. |
| + if (window_state->IsActive()) |
| + window_state->Deactivate(); |
| + } else if ((window_state->window()->TargetVisibility() || |
| + old_show_type == wm::SHOW_TYPE_MINIMIZED) && |
| + !window_state->window()->layer()->visible()) { |
| + // The layer may be hidden if the window was previously minimized. Make |
| + // sure it's visible. |
| + window_state->window()->Show(); |
| + if (old_show_type == wm::SHOW_TYPE_MINIMIZED && |
| + !window_state->IsMaximizedOrFullscreen()) { |
| + window_state->set_unminimize_to_restore_bounds(false); |
| + } |
| + } |
| + |
| + if (window_state->IsNormalShowState()) |
| + window_state->ClearRestoreBounds(); |
| + |
| + // Set the restore rectangle to the previously set restore rectangle. |
| + if (!restore.IsEmpty()) |
| + window_state->SetRestoreBoundsInScreen(restore); |
| +} |
| } // namespace wm |
| } // namespace ash |