| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "ash/wm/base_layout_manager.h" |
| |
| #include "ash/screen_ash.h" |
| #include "ash/session_state_delegate.h" |
| #include "ash/shelf/shelf_layout_manager.h" |
| #include "ash/shell.h" |
| #include "ash/wm/window_animations.h" |
| #include "ash/wm/window_properties.h" |
| #include "ash/wm/window_state.h" |
| #include "ash/wm/window_util.h" |
| #include "ash/wm/workspace/workspace_window_resizer.h" |
| #include "ui/aura/client/activation_client.h" |
| #include "ui/aura/client/aura_constants.h" |
| #include "ui/aura/window.h" |
| #include "ui/base/ui_base_types.h" |
| #include "ui/compositor/layer.h" |
| #include "ui/gfx/screen.h" |
| #include "ui/views/corewm/corewm_switches.h" |
| #include "ui/views/corewm/window_util.h" |
| |
| namespace ash { |
| namespace internal { |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| // BaseLayoutManager, public: |
| |
| BaseLayoutManager::BaseLayoutManager(aura::Window* root_window) |
| : root_window_(root_window) { |
| Shell::GetInstance()->activation_client()->AddObserver(this); |
| Shell::GetInstance()->AddShellObserver(this); |
| root_window_->AddObserver(this); |
| } |
| |
| BaseLayoutManager::~BaseLayoutManager() { |
| if (root_window_) |
| root_window_->RemoveObserver(this); |
| for (WindowSet::const_iterator i = windows_.begin(); i != windows_.end(); ++i) |
| (*i)->RemoveObserver(this); |
| Shell::GetInstance()->RemoveShellObserver(this); |
| Shell::GetInstance()->activation_client()->RemoveObserver(this); |
| } |
| |
| // static |
| gfx::Rect BaseLayoutManager::BoundsWithScreenEdgeVisible( |
| aura::Window* window, |
| const gfx::Rect& restore_bounds) { |
| gfx::Rect max_bounds = |
| ash::ScreenAsh::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; |
| } |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| // BaseLayoutManager, aura::LayoutManager overrides: |
| |
| void BaseLayoutManager::OnWindowResized() { |
| } |
| |
| void BaseLayoutManager::OnWindowAddedToLayout(aura::Window* child) { |
| windows_.insert(child); |
| child->AddObserver(this); |
| wm::WindowState* window_state = wm::GetWindowState(child); |
| window_state->AddObserver(this); |
| |
| // Only update the bounds if the window has a show state that depends on the |
| // workspace area. |
| if (window_state->IsMaximizedOrFullscreen()) |
| UpdateBoundsFromShowState(window_state); |
| } |
| |
| void BaseLayoutManager::OnWillRemoveWindowFromLayout(aura::Window* child) { |
| windows_.erase(child); |
| child->RemoveObserver(this); |
| wm::GetWindowState(child)->RemoveObserver(this); |
| } |
| |
| void BaseLayoutManager::OnWindowRemovedFromLayout(aura::Window* child) { |
| } |
| |
| void BaseLayoutManager::OnChildWindowVisibilityChanged(aura::Window* child, |
| bool visible) { |
| wm::WindowState* window_state = wm::GetWindowState(child); |
| // Attempting to show a minimized window. Unminimize it. |
| if (visible && window_state->IsMinimized()) |
| window_state->Unminimize(); |
| } |
| |
| void BaseLayoutManager::SetChildBounds(aura::Window* child, |
| const gfx::Rect& requested_bounds) { |
| gfx::Rect child_bounds(requested_bounds); |
| wm::WindowState* window_state = wm::GetWindowState(child); |
| // Some windows rely on this to set their initial bounds. |
| if (window_state->IsMaximized()) |
| child_bounds = ScreenAsh::GetMaximizedWindowBoundsInParent(child); |
| else if (window_state->IsFullscreen()) |
| child_bounds = ScreenAsh::GetDisplayBoundsInParent(child); |
| SetChildBoundsDirect(child, child_bounds); |
| } |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| // BaseLayoutManager, aura::WindowObserver overrides: |
| |
| void BaseLayoutManager::OnWindowDestroying(aura::Window* window) { |
| if (root_window_ == window) { |
| root_window_->RemoveObserver(this); |
| root_window_ = NULL; |
| } |
| } |
| |
| void BaseLayoutManager::OnWindowBoundsChanged(aura::Window* window, |
| const gfx::Rect& old_bounds, |
| const gfx::Rect& new_bounds) { |
| if (root_window_ == window) |
| AdjustAllWindowsBoundsForWorkAreaChange(ADJUST_WINDOW_DISPLAY_SIZE_CHANGED); |
| } |
| |
| ////////////////////////////////////////////////////////////////////////////// |
| // BaseLayoutManager, aura::client::ActivationChangeObserver implementation: |
| |
| void BaseLayoutManager::OnWindowActivated(aura::Window* gained_active, |
| aura::Window* lost_active) { |
| wm::WindowState* window_state = wm::GetWindowState(gained_active); |
| if (window_state && window_state->IsMinimized() && |
| !gained_active->IsVisible()) { |
| gained_active->Show(); |
| DCHECK(!window_state->IsMinimized()); |
| } |
| } |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| // BaseLayoutManager, ash::ShellObserver overrides: |
| |
| void BaseLayoutManager::OnDisplayWorkAreaInsetsChanged() { |
| AdjustAllWindowsBoundsForWorkAreaChange( |
| ADJUST_WINDOW_WORK_AREA_INSETS_CHANGED); |
| } |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| // BaseLayoutManager, ash::wm::WindowStateObserver overrides: |
| |
| void BaseLayoutManager::OnWindowShowTypeChanged(wm::WindowState* window_state, |
| wm::WindowShowType old_type) { |
| ui::WindowShowState old_state = ToWindowShowState(old_type); |
| ui::WindowShowState new_state = window_state->GetShowState(); |
| |
| if (old_state != new_state && old_state != ui::SHOW_STATE_MINIMIZED && |
| !window_state->HasRestoreBounds() && |
| ((new_state == ui::SHOW_STATE_MAXIMIZED && |
| old_state != ui::SHOW_STATE_FULLSCREEN) || |
| (new_state == ui::SHOW_STATE_FULLSCREEN && |
| old_state != ui::SHOW_STATE_MAXIMIZED))) { |
| window_state->SetRestoreBoundsInParent(window_state->window()->bounds()); |
| } |
| |
| UpdateBoundsFromShowState(window_state); |
| ShowStateChanged(window_state, old_state); |
| } |
| |
| ////////////////////////////////////////////////////////////////////////////// |
| // BaseLayoutManager, protected: |
| |
| void BaseLayoutManager::ShowStateChanged( |
| wm::WindowState* window_state, |
| ui::WindowShowState last_show_state) { |
| if (window_state->IsMinimized()) { |
| // Save the previous show state so that we can correctly restore it. |
| window_state->window()->SetProperty(aura::client::kRestoreShowStateKey, |
| last_show_state); |
| 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() || |
| last_show_state == ui::SHOW_STATE_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 (last_show_state == ui::SHOW_STATE_MINIMIZED && |
| !window_state->IsMaximizedOrFullscreen()) { |
| window_state->set_always_restores_to_restore_bounds(false); |
| } |
| } |
| } |
| |
| void BaseLayoutManager::AdjustAllWindowsBoundsForWorkAreaChange( |
| AdjustWindowReason reason) { |
| // Don't do any adjustments of the insets while we are in screen locked mode. |
| // This would happen if the launcher was auto hidden before the login screen |
| // was shown and then gets shown when the login screen gets presented. |
| if (reason == ADJUST_WINDOW_WORK_AREA_INSETS_CHANGED && |
| Shell::GetInstance()->session_state_delegate()->IsScreenLocked()) |
| return; |
| |
| // If a user plugs an external display into a laptop running Aura the |
| // display size will change. Maximized windows need to resize to match. |
| // We also do this when developers running Aura on a desktop manually resize |
| // the host window. |
| // We also need to do this when the work area insets changes. |
| for (WindowSet::const_iterator it = windows_.begin(); |
| it != windows_.end(); |
| ++it) { |
| AdjustWindowBoundsForWorkAreaChange(wm::GetWindowState(*it), reason); |
| } |
| } |
| |
| void BaseLayoutManager::AdjustWindowBoundsForWorkAreaChange( |
| wm::WindowState* window_state, |
| AdjustWindowReason reason) { |
| aura::Window* window = window_state->window(); |
| if (window_state->IsMaximized()) { |
| SetChildBoundsDirect( |
| window, ScreenAsh::GetMaximizedWindowBoundsInParent(window)); |
| } else if (window_state->IsFullscreen()) { |
| SetChildBoundsDirect( |
| window, ScreenAsh::GetDisplayBoundsInParent(window)); |
| } else { |
| // The work area may be smaller than the full screen. |
| gfx::Rect display_rect = |
| ScreenAsh::GetDisplayWorkAreaBoundsInParent(window); |
| // Put as much of the window as possible within the display area. |
| gfx::Rect bounds = window->bounds(); |
| bounds.AdjustToFit(display_rect); |
| window->SetBounds(bounds); |
| } |
| } |
| |
| ////////////////////////////////////////////////////////////////////////////// |
| // BaseLayoutManager, private: |
| |
| void BaseLayoutManager::UpdateBoundsFromShowState( |
| wm::WindowState* window_state) { |
| aura::Window* window = window_state->window(); |
| switch (window_state->GetShowState()) { |
| case ui::SHOW_STATE_DEFAULT: |
| case ui::SHOW_STATE_NORMAL: { |
| if (window_state->HasRestoreBounds()) { |
| gfx::Rect bounds_in_parent = window_state->GetRestoreBoundsInParent(); |
| SetChildBoundsDirect(window, |
| BoundsWithScreenEdgeVisible(window, |
| bounds_in_parent)); |
| } |
| window_state->ClearRestoreBounds(); |
| break; |
| } |
| |
| case ui::SHOW_STATE_MAXIMIZED: |
| SetChildBoundsDirect( |
| window, ScreenAsh::GetMaximizedWindowBoundsInParent(window)); |
| break; |
| |
| case ui::SHOW_STATE_FULLSCREEN: |
| // Don't animate the full-screen window transition. |
| // TODO(jamescook): Use animation here. Be sure the lock screen works. |
| SetChildBoundsDirect(window, |
| ScreenAsh::GetDisplayBoundsInParent(window)); |
| break; |
| |
| default: |
| break; |
| } |
| } |
| |
| } // namespace internal |
| } // namespace ash |