| // 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_manager.h" |
| #include "ash/display/display_util.h" |
| #include "ash/rotator/screen_rotation_animator.h" |
| #include "ash/screen_util.h" |
| #include "base/time/time.h" |
| #include "ui/display/manager/display_layout.h" |
| |
| #if defined(OS_CHROMEOS) |
| #include "ash/display/display_animator_chromeos.h" |
| #include "base/sys_info.h" |
| #include "grit/ash_strings.h" |
| #endif |
| |
| 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; |
| |
| } // namespace |
| |
| namespace ash { |
| |
| 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); |
| }; |
| |
| DisplayConfigurationController::DisplayConfigurationController( |
| 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 defined(OS_CHROMEOS) |
| if (base::SysInfo::IsRunningOnChromeOS()) |
| limiter_.reset(new DisplayChangeLimiter); |
| display_animator_.reset(new DisplayAnimatorChromeOS()); |
| #endif |
| } |
| |
| DisplayConfigurationController::~DisplayConfigurationController() { |
| window_tree_host_manager_->RemoveObserver(this); |
| } |
| |
| void DisplayConfigurationController::SetDisplayLayout( |
| std::unique_ptr<display::DisplayLayout> layout, |
| bool user_action) { |
| if (user_action && display_animator_) { |
| display_animator_->StartFadeOutAnimation( |
| base::Bind(&DisplayConfigurationController::SetDisplayLayoutImpl, |
| weak_ptr_factory_.GetWeakPtr(), base::Passed(&layout))); |
| } else { |
| SetDisplayLayoutImpl(std::move(layout)); |
| } |
| } |
| |
| void DisplayConfigurationController::SetMirrorMode(bool mirror, |
| bool user_action) { |
| if (display_manager_->num_connected_displays() > 2) { |
| #if defined(OS_CHROMEOS) |
| if (user_action) |
| ShowDisplayErrorNotification(IDS_ASH_DISPLAY_MIRRORING_NOT_SUPPORTED); |
| #endif |
| return; |
| } |
| if (display_manager_->num_connected_displays() <= 1 || |
| display_manager_->IsInMirrorMode() == mirror || IsLimited()) { |
| return; |
| } |
| SetThrottleTimeout(kCycleDisplayThrottleTimeoutMs); |
| if (user_action && 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, |
| bool user_action) { |
| ash::ScreenRotationAnimator screen_rotation_animator(display_id); |
| if (user_action && screen_rotation_animator.CanAnimate()) |
| screen_rotation_animator.Rotate(rotation, source); |
| else |
| display_manager_->SetDisplayRotation(display_id, rotation, source); |
| } |
| |
| void DisplayConfigurationController::SetPrimaryDisplayId(int64_t display_id, |
| bool user_action) { |
| if (display_manager_->GetNumDisplays() <= 1 || IsLimited()) |
| return; |
| |
| SetThrottleTimeout(kSetPrimaryDisplayThrottleTimeoutMs); |
| if (user_action && display_animator_) { |
| display_animator_->StartFadeOutAnimation( |
| base::Bind(&DisplayConfigurationController::SetPrimaryDisplayIdImpl, |
| weak_ptr_factory_.GetWeakPtr(), display_id)); |
| } else { |
| SetPrimaryDisplayIdImpl(display_id); |
| } |
| } |
| |
| void DisplayConfigurationController::OnDisplayConfigurationChanged() { |
| // TODO(oshima): Stop all animations. |
| SetThrottleTimeout(kAfterDisplayChangeThrottleTimeoutMs); |
| } |
| |
| // Protected |
| |
| void DisplayConfigurationController::ResetAnimatorForTest() { |
| if (!display_animator_) |
| return; |
| display_animator_.reset(); |
| } |
| |
| // 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) { |
| // TODO(oshima/stevenjb): Add support for 3+ displays. |
| display_manager_->SetLayoutForCurrentDisplays(std::move(layout)); |
| if (display_animator_) |
| display_animator_->StartFadeInAnimation(); |
| } |
| |
| void DisplayConfigurationController::SetMirrorModeImpl(bool mirror) { |
| display_manager_->SetMirrorMode(mirror); |
| 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(); |
| } |
| |
| } // namespace ash |