| // Copyright 2016 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/display/display_configuration_controller.h" |
| |
| #include "ash/display/display_animator.h" |
| #include "ash/display/display_util.h" |
| #include "ash/display/window_tree_host_manager.h" |
| #include "ash/public/cpp/shelf_types.h" |
| #include "ash/root_window_controller.h" |
| #include "ash/rotator/screen_rotation_animator.h" |
| #include "ash/shelf/shelf.h" |
| #include "ash/shell.h" |
| #include "ash/strings/grit/ash_strings.h" |
| #include "base/bind.h" |
| #include "base/time/time.h" |
| #include "chromeos/system/devicemode.h" |
| #include "ui/base/l10n/l10n_util.h" |
| #include "ui/display/display_layout.h" |
| #include "ui/display/manager/display_manager.h" |
| |
| namespace ash { |
| |
| namespace { |
| |
| // Specifies how long the display change should have been disabled |
| // after each display change operations. |
| // |kCycleDisplayThrottleTimeoutMs| is set to be longer to avoid |
| // changing the settings while the system is still configurating |
| // displays. It will be overriden by |kAfterDisplayChangeThrottleTimeoutMs| |
| // when the display change happens, so the actual timeout is much shorter. |
| const int64_t kAfterDisplayChangeThrottleTimeoutMs = 500; |
| const int64_t kCycleDisplayThrottleTimeoutMs = 4000; |
| const int64_t kSetPrimaryDisplayThrottleTimeoutMs = 500; |
| |
| bool g_disable_animator_for_test = false; |
| |
| display::DisplayPositionInUnifiedMatrix GetUnifiedModeShelfCellPosition() { |
| const ShelfAlignment alignment = |
| Shell::GetPrimaryRootWindowController()->shelf()->alignment(); |
| switch (alignment) { |
| case SHELF_ALIGNMENT_BOTTOM: |
| case SHELF_ALIGNMENT_BOTTOM_LOCKED: |
| return display::DisplayPositionInUnifiedMatrix::kBottomLeft; |
| |
| case SHELF_ALIGNMENT_LEFT: |
| return display::DisplayPositionInUnifiedMatrix::kTopLeft; |
| |
| case SHELF_ALIGNMENT_RIGHT: |
| return display::DisplayPositionInUnifiedMatrix::kTopRight; |
| } |
| |
| NOTREACHED(); |
| return display::DisplayPositionInUnifiedMatrix::kBottomLeft; |
| } |
| |
| } // namespace |
| |
| class DisplayConfigurationController::DisplayChangeLimiter { |
| public: |
| DisplayChangeLimiter() : throttle_timeout_(base::Time::Now()) {} |
| |
| void SetThrottleTimeout(int64_t throttle_ms) { |
| throttle_timeout_ = |
| base::Time::Now() + base::TimeDelta::FromMilliseconds(throttle_ms); |
| } |
| |
| bool IsThrottled() const { return base::Time::Now() < throttle_timeout_; } |
| |
| private: |
| base::Time throttle_timeout_; |
| |
| DISALLOW_COPY_AND_ASSIGN(DisplayChangeLimiter); |
| }; |
| |
| // static |
| void DisplayConfigurationController::DisableAnimatorForTest() { |
| g_disable_animator_for_test = true; |
| } |
| |
| DisplayConfigurationController::DisplayConfigurationController( |
| display::DisplayManager* display_manager, |
| WindowTreeHostManager* window_tree_host_manager) |
| : display_manager_(display_manager), |
| window_tree_host_manager_(window_tree_host_manager), |
| weak_ptr_factory_(this) { |
| window_tree_host_manager_->AddObserver(this); |
| if (chromeos::IsRunningAsSystemCompositor()) |
| limiter_.reset(new DisplayChangeLimiter); |
| if (!g_disable_animator_for_test) |
| display_animator_.reset(new DisplayAnimator()); |
| } |
| |
| DisplayConfigurationController::~DisplayConfigurationController() { |
| window_tree_host_manager_->RemoveObserver(this); |
| } |
| |
| void DisplayConfigurationController::SetDisplayLayout( |
| std::unique_ptr<display::DisplayLayout> layout) { |
| if (display_animator_) { |
| display_animator_->StartFadeOutAnimation( |
| base::Bind(&DisplayConfigurationController::SetDisplayLayoutImpl, |
| weak_ptr_factory_.GetWeakPtr(), base::Passed(&layout))); |
| } else { |
| SetDisplayLayoutImpl(std::move(layout)); |
| } |
| } |
| |
| void DisplayConfigurationController::SetUnifiedDesktopLayoutMatrix( |
| const display::UnifiedDesktopLayoutMatrix& matrix) { |
| DCHECK(display_manager_->IsInUnifiedMode()); |
| |
| if (display_animator_) { |
| display_animator_->StartFadeOutAnimation(base::Bind( |
| &DisplayConfigurationController::SetUnifiedDesktopLayoutMatrixImpl, |
| weak_ptr_factory_.GetWeakPtr(), matrix)); |
| } else { |
| SetUnifiedDesktopLayoutMatrixImpl(matrix); |
| } |
| } |
| |
| void DisplayConfigurationController::SetMirrorMode(bool mirror, bool throttle) { |
| if (display_manager_->num_connected_displays() <= 1 || |
| display_manager_->IsInMirrorMode() == mirror || |
| (throttle && IsLimited())) { |
| return; |
| } |
| SetThrottleTimeout(kCycleDisplayThrottleTimeoutMs); |
| if (display_animator_) { |
| display_animator_->StartFadeOutAnimation( |
| base::Bind(&DisplayConfigurationController::SetMirrorModeImpl, |
| weak_ptr_factory_.GetWeakPtr(), mirror)); |
| } else { |
| SetMirrorModeImpl(mirror); |
| } |
| } |
| |
| void DisplayConfigurationController::SetDisplayRotation( |
| int64_t display_id, |
| display::Display::Rotation rotation, |
| display::Display::RotationSource source, |
| DisplayConfigurationController::RotationAnimation mode) { |
| if (display_manager_->IsDisplayIdValid(display_id)) { |
| if (GetTargetRotation(display_id) == rotation) |
| return; |
| if (display_animator_) { |
| ScreenRotationAnimator* screen_rotation_animator = |
| GetScreenRotationAnimatorForDisplay(display_id); |
| screen_rotation_animator->Rotate(rotation, source, mode); |
| return; |
| } |
| } |
| // Invalid |display_id| or animator is disabled; call |
| // DisplayManager::SetDisplayRotation directly. |
| display_manager_->SetDisplayRotation(display_id, rotation, source); |
| } |
| |
| display::Display::Rotation DisplayConfigurationController::GetTargetRotation( |
| int64_t display_id) { |
| if (!display_manager_->IsDisplayIdValid(display_id)) |
| return display::Display::ROTATE_0; |
| |
| ScreenRotationAnimator* animator = |
| GetScreenRotationAnimatorForDisplay(display_id); |
| if (animator->IsRotating()) |
| return animator->GetTargetRotation(); |
| |
| return display_manager_->GetDisplayInfo(display_id).GetActiveRotation(); |
| } |
| |
| void DisplayConfigurationController::SetPrimaryDisplayId(int64_t display_id, |
| bool throttle) { |
| if (display_manager_->GetNumDisplays() <= 1 || (IsLimited() && throttle)) |
| return; |
| |
| SetThrottleTimeout(kSetPrimaryDisplayThrottleTimeoutMs); |
| if (display_animator_) { |
| display_animator_->StartFadeOutAnimation( |
| base::Bind(&DisplayConfigurationController::SetPrimaryDisplayIdImpl, |
| weak_ptr_factory_.GetWeakPtr(), display_id)); |
| } else { |
| SetPrimaryDisplayIdImpl(display_id); |
| } |
| } |
| |
| display::Display |
| DisplayConfigurationController::GetPrimaryMirroringDisplayForUnifiedDesktop() |
| const { |
| DCHECK(display_manager_->IsInUnifiedMode()); |
| |
| return display_manager_->GetMirroringDisplayForUnifiedDesktop( |
| GetUnifiedModeShelfCellPosition()); |
| } |
| |
| void DisplayConfigurationController::OnDisplayConfigurationChanged() { |
| // TODO(oshima): Stop all animations. |
| SetThrottleTimeout(kAfterDisplayChangeThrottleTimeoutMs); |
| } |
| |
| // Protected |
| |
| void DisplayConfigurationController::SetAnimatorForTest(bool enable) { |
| if (display_animator_ && !enable) |
| display_animator_.reset(); |
| else if (!display_animator_ && enable) |
| display_animator_.reset(new DisplayAnimator()); |
| } |
| |
| // Private |
| |
| void DisplayConfigurationController::SetThrottleTimeout(int64_t throttle_ms) { |
| if (limiter_) |
| limiter_->SetThrottleTimeout(throttle_ms); |
| } |
| |
| bool DisplayConfigurationController::IsLimited() { |
| return limiter_ && limiter_->IsThrottled(); |
| } |
| |
| void DisplayConfigurationController::SetDisplayLayoutImpl( |
| std::unique_ptr<display::DisplayLayout> layout) { |
| display_manager_->SetLayoutForCurrentDisplays(std::move(layout)); |
| if (display_animator_) |
| display_animator_->StartFadeInAnimation(); |
| } |
| |
| void DisplayConfigurationController::SetMirrorModeImpl(bool mirror) { |
| display_manager_->SetMirrorMode( |
| mirror ? display::MirrorMode::kNormal : display::MirrorMode::kOff, |
| base::nullopt); |
| if (display_animator_) |
| display_animator_->StartFadeInAnimation(); |
| } |
| |
| void DisplayConfigurationController::SetPrimaryDisplayIdImpl( |
| int64_t display_id) { |
| window_tree_host_manager_->SetPrimaryDisplayId(display_id); |
| if (display_animator_) |
| display_animator_->StartFadeInAnimation(); |
| } |
| |
| void DisplayConfigurationController::SetUnifiedDesktopLayoutMatrixImpl( |
| const display::UnifiedDesktopLayoutMatrix& matrix) { |
| display_manager_->SetUnifiedDesktopMatrix(matrix); |
| if (display_animator_) |
| display_animator_->StartFadeInAnimation(); |
| } |
| |
| ScreenRotationAnimator* |
| DisplayConfigurationController::GetScreenRotationAnimatorForDisplay( |
| int64_t display_id) { |
| aura::Window* root_window = Shell::GetRootWindowForDisplayId(display_id); |
| return ScreenRotationAnimator::GetForRootWindow(root_window); |
| } |
| |
| } // namespace ash |