Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1404)

Unified Diff: ui/display/chromeos/display_configurator.cc

Issue 797383002: Revert of Update DisplayConfigurator to use the asynchronous tasks (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@async-refactor4
Patch Set: Created 6 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « ui/display/chromeos/display_configurator.h ('k') | ui/display/chromeos/display_configurator_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: ui/display/chromeos/display_configurator.cc
diff --git a/ui/display/chromeos/display_configurator.cc b/ui/display/chromeos/display_configurator.cc
index 01f47fabb038179be68ec56719d92d215caafb95..f912a60a8586d41635e24b33c526ce28e2b3e7a3 100644
--- a/ui/display/chromeos/display_configurator.cc
+++ b/ui/display/chromeos/display_configurator.cc
@@ -10,7 +10,6 @@
#include "base/sys_info.h"
#include "base/time/time.h"
#include "ui/display/chromeos/display_util.h"
-#include "ui/display/chromeos/update_display_configuration_task.h"
#include "ui/display/display_switches.h"
#include "ui/display/types/display_mode.h"
#include "ui/display/types/display_snapshot.h"
@@ -54,347 +53,6 @@
return false;
}
}
-
-////////////////////////////////////////////////////////////////////////////////
-// DisplayConfigurator::DisplayLayoutManagerImpl implementation
-
-class DisplayConfigurator::DisplayLayoutManagerImpl
- : public DisplayLayoutManager {
- public:
- DisplayLayoutManagerImpl(DisplayConfigurator* configurator);
- ~DisplayLayoutManagerImpl() override;
-
- // DisplayConfigurator::DisplayLayoutManager:
- SoftwareMirroringController* GetSoftwareMirroringController() const override;
- StateController* GetStateController() const override;
- MultipleDisplayState GetDisplayState() const override;
- chromeos::DisplayPowerState GetPowerState() const override;
- std::vector<DisplayState> ParseDisplays(
- const std::vector<DisplaySnapshot*>& displays) const override;
- bool GetDisplayLayout(const std::vector<DisplayState>& displays,
- MultipleDisplayState new_display_state,
- chromeos::DisplayPowerState new_power_state,
- std::vector<DisplayConfigureRequest>* requests,
- gfx::Size* framebuffer_size) const override;
-
- private:
- // Helper method for ParseDisplays() that initializes the passed-in
- // displays' |mirror_mode| fields by looking for a mode in |internal_display|
- // and |external_display| having the same resolution. Returns false if a
- // shared mode wasn't found or created.
- //
- // |try_panel_fitting| allows creating a panel-fitting mode for
- // |internal_display| instead of only searching for a matching mode (note that
- // it may lead to a crash if |internal_display| is not capable of panel
- // fitting).
- //
- // |preserve_aspect| limits the search/creation only to the modes having the
- // native aspect ratio of |external_display|.
- bool FindMirrorMode(DisplayState* internal_display,
- DisplayState* external_display,
- bool try_panel_fitting,
- bool preserve_aspect) const;
-
- DisplayConfigurator* configurator_; // Not owned.
-
- DISALLOW_COPY_AND_ASSIGN(DisplayLayoutManagerImpl);
-};
-
-DisplayConfigurator::DisplayLayoutManagerImpl::DisplayLayoutManagerImpl(
- DisplayConfigurator* configurator)
- : configurator_(configurator) {
-}
-
-DisplayConfigurator::DisplayLayoutManagerImpl::~DisplayLayoutManagerImpl() {
-}
-
-DisplayConfigurator::SoftwareMirroringController*
-DisplayConfigurator::DisplayLayoutManagerImpl::GetSoftwareMirroringController()
- const {
- return configurator_->mirroring_controller_;
-}
-
-DisplayConfigurator::StateController*
-DisplayConfigurator::DisplayLayoutManagerImpl::GetStateController() const {
- return configurator_->state_controller_;
-}
-
-MultipleDisplayState
-DisplayConfigurator::DisplayLayoutManagerImpl::GetDisplayState() const {
- return configurator_->current_display_state_;
-}
-
-chromeos::DisplayPowerState
-DisplayConfigurator::DisplayLayoutManagerImpl::GetPowerState() const {
- return configurator_->current_power_state_;
-}
-
-std::vector<DisplayConfigurator::DisplayState>
-DisplayConfigurator::DisplayLayoutManagerImpl::ParseDisplays(
- const std::vector<DisplaySnapshot*>& snapshots) const {
- std::vector<DisplayState> cached_displays;
- for (auto snapshot : snapshots) {
- DisplayState display_state;
- display_state.display = snapshot;
- cached_displays.push_back(display_state);
- }
-
- // Set |selected_mode| fields.
- for (size_t i = 0; i < cached_displays.size(); ++i) {
- DisplayState* display_state = &cached_displays[i];
- gfx::Size size;
- if (GetStateController() &&
- GetStateController()->GetResolutionForDisplayId(
- display_state->display->display_id(), &size)) {
- display_state->selected_mode =
- FindDisplayModeMatchingSize(*display_state->display, size);
- }
-
- // Fall back to native mode.
- if (!display_state->selected_mode)
- display_state->selected_mode = display_state->display->native_mode();
- }
-
- // Set |mirror_mode| fields.
- if (cached_displays.size() == 2) {
- bool one_is_internal =
- cached_displays[0].display->type() == DISPLAY_CONNECTION_TYPE_INTERNAL;
- bool two_is_internal =
- cached_displays[1].display->type() == DISPLAY_CONNECTION_TYPE_INTERNAL;
- int internal_displays =
- (one_is_internal ? 1 : 0) + (two_is_internal ? 1 : 0);
- DCHECK_LT(internal_displays, 2);
- LOG_IF(WARNING, internal_displays >= 2)
- << "At least two internal displays detected.";
-
- bool can_mirror = false;
- for (int attempt = 0; !can_mirror && attempt < 2; ++attempt) {
- // Try preserving external display's aspect ratio on the first attempt.
- // If that fails, fall back to the highest matching resolution.
- bool preserve_aspect = attempt == 0;
-
- if (internal_displays == 1) {
- can_mirror = FindMirrorMode(&cached_displays[one_is_internal ? 0 : 1],
- &cached_displays[one_is_internal ? 1 : 0],
- configurator_->is_panel_fitting_enabled_,
- preserve_aspect);
- } else { // if (internal_displays == 0)
- // No panel fitting for external displays, so fall back to exact match.
- can_mirror = FindMirrorMode(&cached_displays[0], &cached_displays[1],
- false, preserve_aspect);
- if (!can_mirror && preserve_aspect) {
- // FindMirrorMode() will try to preserve aspect ratio of what it
- // thinks is external display, so if it didn't succeed with one, maybe
- // it will succeed with the other. This way we will have the correct
- // aspect ratio on at least one of them.
- can_mirror = FindMirrorMode(&cached_displays[1], &cached_displays[0],
- false, preserve_aspect);
- }
- }
- }
- }
-
- return cached_displays;
-}
-
-bool DisplayConfigurator::DisplayLayoutManagerImpl::GetDisplayLayout(
- const std::vector<DisplayState>& displays,
- MultipleDisplayState new_display_state,
- chromeos::DisplayPowerState new_power_state,
- std::vector<DisplayConfigureRequest>* requests,
- gfx::Size* framebuffer_size) const {
- std::vector<bool> display_power;
- int num_on_displays =
- GetDisplayPower(displays, new_power_state, &display_power);
- VLOG(1) << "EnterState: display="
- << MultipleDisplayStateToString(new_display_state)
- << " power=" << DisplayPowerStateToString(new_power_state);
-
- // Framebuffer dimensions.
- gfx::Size size;
-
- for (size_t i = 0; i < displays.size(); ++i) {
- requests->push_back(DisplayConfigureRequest(
- displays[i].display, displays[i].display->current_mode(),
- gfx::Point()));
- }
-
- switch (new_display_state) {
- case MULTIPLE_DISPLAY_STATE_INVALID:
- NOTREACHED() << "Ignoring request to enter invalid state with "
- << displays.size() << " connected display(s)";
- return false;
- case MULTIPLE_DISPLAY_STATE_HEADLESS:
- if (displays.size() != 0) {
- LOG(WARNING) << "Ignoring request to enter headless mode with "
- << displays.size() << " connected display(s)";
- return false;
- }
- break;
- case MULTIPLE_DISPLAY_STATE_SINGLE: {
- // If there are multiple displays connected, only one should be turned on.
- if (displays.size() != 1 && num_on_displays != 1) {
- LOG(WARNING) << "Ignoring request to enter single mode with "
- << displays.size() << " connected displays and "
- << num_on_displays << " turned on";
- return false;
- }
-
- for (size_t i = 0; i < displays.size(); ++i) {
- const DisplayConfigurator::DisplayState* state = &displays[i];
- (*requests)[i].mode = display_power[i] ? state->selected_mode : NULL;
-
- if (display_power[i] || displays.size() == 1) {
- const DisplayMode* mode_info = state->selected_mode;
- if (!mode_info) {
- LOG(WARNING) << "No selected mode when configuring display: "
- << state->display->ToString();
- return false;
- }
- if (mode_info->size() == gfx::Size(1024, 768)) {
- VLOG(1) << "Potentially misdetecting display(1024x768):"
- << " displays size=" << displays.size()
- << ", num_on_displays=" << num_on_displays
- << ", current size:" << size.width() << "x" << size.height()
- << ", i=" << i << ", display=" << state->display->ToString()
- << ", display_mode=" << mode_info->ToString();
- }
- size = mode_info->size();
- }
- }
- break;
- }
- case MULTIPLE_DISPLAY_STATE_DUAL_MIRROR: {
- if (displays.size() != 2 ||
- (num_on_displays != 0 && num_on_displays != 2)) {
- LOG(WARNING) << "Ignoring request to enter mirrored mode with "
- << displays.size() << " connected display(s) and "
- << num_on_displays << " turned on";
- return false;
- }
-
- const DisplayMode* mode_info = displays[0].mirror_mode;
- if (!mode_info) {
- LOG(WARNING) << "No mirror mode when configuring display: "
- << displays[0].display->ToString();
- return false;
- }
- size = mode_info->size();
-
- for (size_t i = 0; i < displays.size(); ++i) {
- const DisplayConfigurator::DisplayState* state = &displays[i];
- (*requests)[i].mode = display_power[i] ? state->mirror_mode : NULL;
- }
- break;
- }
- case MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED:
- case MULTIPLE_DISPLAY_STATE_MULTI_EXTENDED: {
- if ((new_display_state == MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED &&
- displays.size() != 2) ||
- (new_display_state == MULTIPLE_DISPLAY_STATE_MULTI_EXTENDED &&
- displays.size() <= 2) ||
- (num_on_displays != 0 &&
- num_on_displays != static_cast<int>(displays.size()))) {
- LOG(WARNING) << "Ignoring request to enter extended mode with "
- << displays.size() << " connected display(s) and "
- << num_on_displays << " turned on";
- return false;
- }
-
- for (size_t i = 0; i < displays.size(); ++i) {
- const DisplayConfigurator::DisplayState* state = &displays[i];
- (*requests)[i].origin.set_y(size.height() ? size.height() + kVerticalGap
- : 0);
- (*requests)[i].mode = display_power[i] ? state->selected_mode : NULL;
-
- // Retain the full screen size even if all displays are off so the
- // same desktop configuration can be restored when the displays are
- // turned back on.
- const DisplayMode* mode_info = displays[i].selected_mode;
- if (!mode_info) {
- LOG(WARNING) << "No selected mode when configuring display: "
- << state->display->ToString();
- return false;
- }
-
- size.set_width(std::max<int>(size.width(), mode_info->size().width()));
- size.set_height(size.height() + (size.height() ? kVerticalGap : 0) +
- mode_info->size().height());
- }
- break;
- }
- }
-
- *framebuffer_size = size;
- return true;
-}
-
-bool DisplayConfigurator::DisplayLayoutManagerImpl::FindMirrorMode(
- DisplayState* internal_display,
- DisplayState* external_display,
- bool try_panel_fitting,
- bool preserve_aspect) const {
- const DisplayMode* internal_native_info =
- internal_display->display->native_mode();
- const DisplayMode* external_native_info =
- external_display->display->native_mode();
- if (!internal_native_info || !external_native_info)
- return false;
-
- // Check if some external display resolution can be mirrored on internal.
- // Prefer the modes in the order they're present in DisplaySnapshot, assuming
- // this is the order in which they look better on the monitor.
- for (DisplayModeList::const_iterator external_it =
- external_display->display->modes().begin();
- external_it != external_display->display->modes().end(); ++external_it) {
- const DisplayMode& external_info = **external_it;
- bool is_native_aspect_ratio =
- external_native_info->size().width() * external_info.size().height() ==
- external_native_info->size().height() * external_info.size().width();
- if (preserve_aspect && !is_native_aspect_ratio)
- continue; // Allow only aspect ratio preserving modes for mirroring.
-
- // Try finding an exact match.
- for (DisplayModeList::const_iterator internal_it =
- internal_display->display->modes().begin();
- internal_it != internal_display->display->modes().end();
- ++internal_it) {
- const DisplayMode& internal_info = **internal_it;
- if (internal_info.size().width() == external_info.size().width() &&
- internal_info.size().height() == external_info.size().height() &&
- internal_info.is_interlaced() == external_info.is_interlaced()) {
- internal_display->mirror_mode = *internal_it;
- external_display->mirror_mode = *external_it;
- return true; // Mirror mode found.
- }
- }
-
- // Try to create a matching internal display mode by panel fitting.
- if (try_panel_fitting) {
- // We can downscale by 1.125, and upscale indefinitely. Downscaling looks
- // ugly, so, can fit == can upscale. Also, internal panels don't support
- // fitting interlaced modes.
- bool can_fit = internal_native_info->size().width() >=
- external_info.size().width() &&
- internal_native_info->size().height() >=
- external_info.size().height() &&
- !external_info.is_interlaced();
- if (can_fit) {
- configurator_->native_display_delegate_->AddMode(
- *internal_display->display, *external_it);
- internal_display->display->add_mode(*external_it);
- internal_display->mirror_mode = *external_it;
- external_display->mirror_mode = *external_it;
- return true; // Mirror mode created.
- }
- }
- }
-
- return false;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// DisplayConfigurator implementation
// static
const DisplayMode* DisplayConfigurator::FindDisplayModeMatchingSize(
@@ -444,17 +102,11 @@
mirroring_controller_(NULL),
is_panel_fitting_enabled_(false),
configure_display_(base::SysInfo::IsRunningOnChromeOS()),
- current_display_state_(MULTIPLE_DISPLAY_STATE_INVALID),
+ display_state_(MULTIPLE_DISPLAY_STATE_INVALID),
+ requested_power_state_(chromeos::DISPLAY_POWER_ALL_ON),
current_power_state_(chromeos::DISPLAY_POWER_ALL_ON),
- requested_display_state_(MULTIPLE_DISPLAY_STATE_INVALID),
- requested_power_state_(chromeos::DISPLAY_POWER_ALL_ON),
- requested_power_state_change_(false),
- requested_power_flags_(kSetDisplayPowerNoFlags),
- force_configure_(false),
next_display_protection_client_id_(1),
- display_externally_controlled_(false),
- layout_manager_(new DisplayLayoutManagerImpl(this)),
- weak_ptr_factory_(this) {
+ display_externally_controlled_(false) {
}
DisplayConfigurator::~DisplayConfigurator() {
@@ -472,7 +124,7 @@
void DisplayConfigurator::SetInitialDisplayPower(
chromeos::DisplayPowerState power_state) {
- DCHECK_EQ(current_display_state_, MULTIPLE_DISPLAY_STATE_INVALID);
+ DCHECK_EQ(display_state_, MULTIPLE_DISPLAY_STATE_INVALID);
requested_power_state_ = current_power_state_ = power_state;
}
@@ -521,25 +173,28 @@
if (!configure_display_ || display_externally_controlled_)
return;
+ native_display_delegate_->GrabServer();
native_display_delegate_->Initialize();
- // ForceInitialConfigure should be the first configuration so there shouldn't
- // be anything scheduled.
- DCHECK(!configuration_task_);
-
- configuration_task_.reset(new UpdateDisplayConfigurationTask(
- native_display_delegate_.get(), layout_manager_.get(),
- requested_display_state_, requested_power_state_,
- kSetDisplayPowerForceProbe, background_color_argb, true,
- base::Bind(&DisplayConfigurator::OnConfigured,
- weak_ptr_factory_.GetWeakPtr())));
- configuration_task_->Run();
+ UpdateCachedDisplays();
+ if (cached_displays_.size() > 1 && background_color_argb)
+ native_display_delegate_->SetBackgroundColor(background_color_argb);
+ const MultipleDisplayState new_state = ChooseDisplayState(
+ requested_power_state_);
+ const bool success = EnterStateOrFallBackToSoftwareMirroring(
+ new_state, requested_power_state_);
+
+ // Force the DPMS on chrome startup as the driver doesn't always detect
+ // that all displays are on when signing out.
+ native_display_delegate_->ForceDPMSOn();
+ native_display_delegate_->UngrabServer();
+ NotifyObservers(success, new_state);
}
bool DisplayConfigurator::IsMirroring() const {
- return current_display_state_ == MULTIPLE_DISPLAY_STATE_DUAL_MIRROR ||
- (mirroring_controller_ &&
- mirroring_controller_->SoftwareMirroringEnabled());
+ return display_state_ == MULTIPLE_DISPLAY_STATE_DUAL_MIRROR ||
+ (mirroring_controller_ &&
+ mirroring_controller_->SoftwareMirroringEnabled());
}
bool DisplayConfigurator::ApplyProtections(const ContentProtections& requests) {
@@ -761,34 +416,55 @@
configure_display_ = false;
}
-void DisplayConfigurator::SetDisplayPower(
+bool DisplayConfigurator::SetDisplayPower(
chromeos::DisplayPowerState power_state,
int flags) {
if (!configure_display_ || display_externally_controlled_)
- return;
+ return false;
VLOG(1) << "SetDisplayPower: power_state="
<< DisplayPowerStateToString(power_state) << " flags=" << flags
<< ", configure timer="
<< (configure_timer_.IsRunning() ? "Running" : "Stopped");
- if (power_state == requested_power_state_ &&
+ if (power_state == current_power_state_ &&
!(flags & kSetDisplayPowerForceProbe))
- return;
-
- requested_power_state_ = power_state;
- requested_power_state_change_ = true;
- requested_power_flags_ = flags;
-
- RunPendingConfiguration();
-}
-
-void DisplayConfigurator::SetDisplayMode(MultipleDisplayState new_state) {
+ return true;
+
+ native_display_delegate_->GrabServer();
+ UpdateCachedDisplays();
+
+ const MultipleDisplayState new_state = ChooseDisplayState(power_state);
+ bool attempted_change = false;
+ bool success = false;
+
+ bool only_if_single_internal_display =
+ flags & kSetDisplayPowerOnlyIfSingleInternalDisplay;
+ bool single_internal_display =
+ cached_displays_.size() == 1 &&
+ cached_displays_[0].display->type() == DISPLAY_CONNECTION_TYPE_INTERNAL;
+ if (single_internal_display || !only_if_single_internal_display) {
+ success = EnterStateOrFallBackToSoftwareMirroring(new_state, power_state);
+ attempted_change = true;
+
+ // Force the DPMS on since the driver doesn't always detect that it
+ // should turn on. This is needed when coming back from idle suspend.
+ if (success && power_state != chromeos::DISPLAY_POWER_ALL_OFF)
+ native_display_delegate_->ForceDPMSOn();
+ }
+
+ native_display_delegate_->UngrabServer();
+ if (attempted_change)
+ NotifyObservers(success, new_state);
+ return success;
+}
+
+bool DisplayConfigurator::SetDisplayMode(MultipleDisplayState new_state) {
if (!configure_display_ || display_externally_controlled_)
- return;
+ return false;
VLOG(1) << "SetDisplayMode: state="
<< MultipleDisplayStateToString(new_state);
- if (current_display_state_ == new_state) {
+ if (display_state_ == new_state) {
// Cancel software mirroring if the state is moving from
// MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED to
// MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED.
@@ -796,12 +472,17 @@
new_state == MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED)
mirroring_controller_->SetSoftwareMirroring(false);
NotifyObservers(true, new_state);
- return;
- }
-
- requested_display_state_ = new_state;
-
- RunPendingConfiguration();
+ return true;
+ }
+
+ native_display_delegate_->GrabServer();
+ UpdateCachedDisplays();
+ const bool success = EnterStateOrFallBackToSoftwareMirroring(
+ new_state, requested_power_state_);
+ native_display_delegate_->UngrabServer();
+
+ NotifyObservers(success, new_state);
+ return success;
}
void DisplayConfigurator::OnConfigurationChanged() {
@@ -857,90 +538,160 @@
base::Unretained(this)));
}
+void DisplayConfigurator::UpdateCachedDisplays() {
+ std::vector<DisplaySnapshot*> snapshots =
+ native_display_delegate_->GetDisplays();
+
+ cached_displays_.clear();
+ for (size_t i = 0; i < snapshots.size(); ++i) {
+ DisplayState display_state;
+ display_state.display = snapshots[i];
+ cached_displays_.push_back(display_state);
+ }
+
+ // Set |selected_mode| fields.
+ for (size_t i = 0; i < cached_displays_.size(); ++i) {
+ DisplayState* display_state = &cached_displays_[i];
+ gfx::Size size;
+ if (state_controller_ &&
+ state_controller_->GetResolutionForDisplayId(
+ display_state->display->display_id(), &size)) {
+ display_state->selected_mode =
+ FindDisplayModeMatchingSize(*display_state->display, size);
+ }
+
+ // Fall back to native mode.
+ if (!display_state->selected_mode)
+ display_state->selected_mode = display_state->display->native_mode();
+ }
+
+ // Set |mirror_mode| fields.
+ if (cached_displays_.size() == 2) {
+ bool one_is_internal =
+ cached_displays_[0].display->type() == DISPLAY_CONNECTION_TYPE_INTERNAL;
+ bool two_is_internal =
+ cached_displays_[1].display->type() == DISPLAY_CONNECTION_TYPE_INTERNAL;
+ int internal_displays =
+ (one_is_internal ? 1 : 0) + (two_is_internal ? 1 : 0);
+ DCHECK_LT(internal_displays, 2);
+ LOG_IF(WARNING, internal_displays == 2)
+ << "Two internal displays detected.";
+
+ bool can_mirror = false;
+ for (int attempt = 0; !can_mirror && attempt < 2; ++attempt) {
+ // Try preserving external display's aspect ratio on the first attempt.
+ // If that fails, fall back to the highest matching resolution.
+ bool preserve_aspect = attempt == 0;
+
+ if (internal_displays == 1) {
+ if (one_is_internal) {
+ can_mirror = FindMirrorMode(&cached_displays_[0],
+ &cached_displays_[1],
+ is_panel_fitting_enabled_,
+ preserve_aspect);
+ } else {
+ DCHECK(two_is_internal);
+ can_mirror = FindMirrorMode(&cached_displays_[1],
+ &cached_displays_[0],
+ is_panel_fitting_enabled_,
+ preserve_aspect);
+ }
+ } else { // if (internal_displays == 0)
+ // No panel fitting for external displays, so fall back to exact match.
+ can_mirror = FindMirrorMode(
+ &cached_displays_[0], &cached_displays_[1], false, preserve_aspect);
+ if (!can_mirror && preserve_aspect) {
+ // FindMirrorMode() will try to preserve aspect ratio of what it
+ // thinks is external display, so if it didn't succeed with one, maybe
+ // it will succeed with the other. This way we will have the correct
+ // aspect ratio on at least one of them.
+ can_mirror = FindMirrorMode(&cached_displays_[1],
+ &cached_displays_[0],
+ false,
+ preserve_aspect);
+ }
+ }
+ }
+ }
+}
+
+bool DisplayConfigurator::FindMirrorMode(DisplayState* internal_display,
+ DisplayState* external_display,
+ bool try_panel_fitting,
+ bool preserve_aspect) {
+ const DisplayMode* internal_native_info =
+ internal_display->display->native_mode();
+ const DisplayMode* external_native_info =
+ external_display->display->native_mode();
+ if (!internal_native_info || !external_native_info)
+ return false;
+
+ // Check if some external display resolution can be mirrored on internal.
+ // Prefer the modes in the order they're present in DisplaySnapshot, assuming
+ // this is the order in which they look better on the monitor.
+ for (DisplayModeList::const_iterator external_it =
+ external_display->display->modes().begin();
+ external_it != external_display->display->modes().end();
+ ++external_it) {
+ const DisplayMode& external_info = **external_it;
+ bool is_native_aspect_ratio =
+ external_native_info->size().width() * external_info.size().height() ==
+ external_native_info->size().height() * external_info.size().width();
+ if (preserve_aspect && !is_native_aspect_ratio)
+ continue; // Allow only aspect ratio preserving modes for mirroring.
+
+ // Try finding an exact match.
+ for (DisplayModeList::const_iterator internal_it =
+ internal_display->display->modes().begin();
+ internal_it != internal_display->display->modes().end();
+ ++internal_it) {
+ const DisplayMode& internal_info = **internal_it;
+ if (internal_info.size().width() == external_info.size().width() &&
+ internal_info.size().height() == external_info.size().height() &&
+ internal_info.is_interlaced() == external_info.is_interlaced()) {
+ internal_display->mirror_mode = *internal_it;
+ external_display->mirror_mode = *external_it;
+ return true; // Mirror mode found.
+ }
+ }
+
+ // Try to create a matching internal display mode by panel fitting.
+ if (try_panel_fitting) {
+ // We can downscale by 1.125, and upscale indefinitely. Downscaling looks
+ // ugly, so, can fit == can upscale. Also, internal panels don't support
+ // fitting interlaced modes.
+ bool can_fit = internal_native_info->size().width() >=
+ external_info.size().width() &&
+ internal_native_info->size().height() >=
+ external_info.size().height() &&
+ !external_info.is_interlaced();
+ if (can_fit) {
+ native_display_delegate_->AddMode(*internal_display->display,
+ *external_it);
+ internal_display->display->add_mode(*external_it);
+ internal_display->mirror_mode = *external_it;
+ external_display->mirror_mode = *external_it;
+ return true; // Mirror mode created.
+ }
+ }
+ }
+
+ return false;
+}
+
void DisplayConfigurator::ConfigureDisplays() {
if (!configure_display_ || display_externally_controlled_)
return;
- force_configure_ = true;
- RunPendingConfiguration();
-}
-
-void DisplayConfigurator::RunPendingConfiguration() {
- // Configuration task is currently running. Do not start a second
- // configuration.
- if (configuration_task_)
- return;
-
- if (!ShouldRunConfigurationTask()) {
- LOG(ERROR) << "Called RunPendingConfiguration without any changes"
- " requested";
- return;
- }
-
- configuration_task_.reset(new UpdateDisplayConfigurationTask(
- native_display_delegate_.get(), layout_manager_.get(),
- requested_display_state_, requested_power_state_, requested_power_flags_,
- 0, force_configure_, base::Bind(&DisplayConfigurator::OnConfigured,
- weak_ptr_factory_.GetWeakPtr())));
-
- // Reset the flags before running the task; otherwise it may end up scheduling
- // another configuration.
- force_configure_ = false;
- requested_power_flags_ = kSetDisplayPowerNoFlags;
- requested_power_state_change_ = false;
- requested_display_state_ = MULTIPLE_DISPLAY_STATE_INVALID;
-
- configuration_task_->Run();
-}
-
-void DisplayConfigurator::OnConfigured(
- bool success,
- const std::vector<DisplayState>& displays,
- const gfx::Size& framebuffer_size,
- MultipleDisplayState new_display_state,
- chromeos::DisplayPowerState new_power_state) {
- VLOG(1) << "OnConfigured: success=" << success << " new_display_state="
- << MultipleDisplayStateToString(new_display_state)
- << " new_power_state=" << DisplayPowerStateToString(new_power_state);
-
- cached_displays_ = displays;
- if (success) {
- current_display_state_ = new_display_state;
- current_power_state_ = new_power_state;
- framebuffer_size_ = framebuffer_size;
- // If the requested power state hasn't changed then make sure that value
- // gets updated as well since the last requested value may have been
- // dependent on certain conditions (ie: if only the internal monitor was
- // present).
- if (!requested_power_state_change_)
- requested_power_state_ = new_power_state;
- }
-
- configuration_task_.reset();
- NotifyObservers(success, new_display_state);
-
- if (success && !configure_timer_.IsRunning() &&
- ShouldRunConfigurationTask()) {
- configure_timer_.Start(FROM_HERE,
- base::TimeDelta::FromMilliseconds(kConfigureDelayMs),
- this, &DisplayConfigurator::RunPendingConfiguration);
- }
-}
-
-bool DisplayConfigurator::ShouldRunConfigurationTask() const {
- if (force_configure_)
- return true;
-
- // Schedule if there is a request to change the display state.
- if (requested_display_state_ != current_display_state_ &&
- requested_display_state_ != MULTIPLE_DISPLAY_STATE_INVALID)
- return true;
-
- // Schedule if there is a request to change the power state.
- if (requested_power_state_change_)
- return true;
-
- return false;
+ native_display_delegate_->GrabServer();
+ UpdateCachedDisplays();
+ const MultipleDisplayState new_state = ChooseDisplayState(
+ requested_power_state_);
+ const bool success = EnterStateOrFallBackToSoftwareMirroring(
+ new_state, requested_power_state_);
+ native_display_delegate_->UngrabServer();
+
+ NotifyObservers(success, new_state);
}
void DisplayConfigurator::RestoreRequestedPowerStateAfterResume() {
@@ -961,4 +712,243 @@
}
}
+bool DisplayConfigurator::EnterStateOrFallBackToSoftwareMirroring(
+ MultipleDisplayState display_state,
+ chromeos::DisplayPowerState power_state) {
+ bool success = EnterState(display_state, power_state);
+ if (mirroring_controller_) {
+ bool enable_software_mirroring = false;
+ if (!success && display_state == MULTIPLE_DISPLAY_STATE_DUAL_MIRROR) {
+ if (display_state_ != MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED ||
+ current_power_state_ != power_state)
+ EnterState(MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED, power_state);
+ enable_software_mirroring = success =
+ display_state_ == MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED;
+ }
+ mirroring_controller_->SetSoftwareMirroring(enable_software_mirroring);
+ }
+ return success;
+}
+
+bool DisplayConfigurator::EnterState(MultipleDisplayState display_state,
+ chromeos::DisplayPowerState power_state) {
+ std::vector<bool> display_power;
+ int num_on_displays =
+ GetDisplayPower(cached_displays_, power_state, &display_power);
+ VLOG(1) << "EnterState: display="
+ << MultipleDisplayStateToString(display_state)
+ << " power=" << DisplayPowerStateToString(power_state);
+
+ // Save the requested state so we'll try to use it next time even if we fail.
+ requested_power_state_ = power_state;
+
+ // Framebuffer dimensions.
+ gfx::Size size;
+
+ std::vector<gfx::Point> new_origins(cached_displays_.size(), gfx::Point());
+ std::vector<const DisplayMode*> new_mode;
+ for (size_t i = 0; i < cached_displays_.size(); ++i)
+ new_mode.push_back(cached_displays_[i].display->current_mode());
+
+ switch (display_state) {
+ case MULTIPLE_DISPLAY_STATE_INVALID:
+ NOTREACHED() << "Ignoring request to enter invalid state with "
+ << cached_displays_.size() << " connected display(s)";
+ return false;
+ case MULTIPLE_DISPLAY_STATE_HEADLESS:
+ if (cached_displays_.size() != 0) {
+ LOG(WARNING) << "Ignoring request to enter headless mode with "
+ << cached_displays_.size() << " connected display(s)";
+ return false;
+ }
+ break;
+ case MULTIPLE_DISPLAY_STATE_SINGLE: {
+ // If there are multiple displays connected, only one should be turned on.
+ if (cached_displays_.size() != 1 && num_on_displays != 1) {
+ LOG(WARNING) << "Ignoring request to enter single mode with "
+ << cached_displays_.size() << " connected displays and "
+ << num_on_displays << " turned on";
+ return false;
+ }
+
+ for (size_t i = 0; i < cached_displays_.size(); ++i) {
+ DisplayState* state = &cached_displays_[i];
+ new_mode[i] = display_power[i] ? state->selected_mode : NULL;
+
+ if (display_power[i] || cached_displays_.size() == 1) {
+ const DisplayMode* mode_info = state->selected_mode;
+ if (!mode_info) {
+ LOG(WARNING) << "No selected mode when configuring display: "
+ << state->display->ToString();
+ return false;
+ }
+ if (mode_info->size() == gfx::Size(1024, 768)) {
+ VLOG(1) << "Potentially misdetecting display(1024x768):"
+ << " displays size=" << cached_displays_.size()
+ << ", num_on_displays=" << num_on_displays
+ << ", current size:" << size.width() << "x" << size.height()
+ << ", i=" << i << ", display=" << state->display->ToString()
+ << ", display_mode=" << mode_info->ToString();
+ }
+ size = mode_info->size();
+ }
+ }
+ break;
+ }
+ case MULTIPLE_DISPLAY_STATE_DUAL_MIRROR: {
+ if (cached_displays_.size() != 2 ||
+ (num_on_displays != 0 && num_on_displays != 2)) {
+ LOG(WARNING) << "Ignoring request to enter mirrored mode with "
+ << cached_displays_.size() << " connected display(s) and "
+ << num_on_displays << " turned on";
+ return false;
+ }
+
+ const DisplayMode* mode_info = cached_displays_[0].mirror_mode;
+ if (!mode_info) {
+ LOG(WARNING) << "No mirror mode when configuring display: "
+ << cached_displays_[0].display->ToString();
+ return false;
+ }
+ size = mode_info->size();
+
+ for (size_t i = 0; i < cached_displays_.size(); ++i) {
+ DisplayState* state = &cached_displays_[i];
+ new_mode[i] = display_power[i] ? state->mirror_mode : NULL;
+ }
+ break;
+ }
+ case MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED:
+ case MULTIPLE_DISPLAY_STATE_MULTI_EXTENDED: {
+ if ((display_state == MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED &&
+ cached_displays_.size() != 2) ||
+ (display_state == MULTIPLE_DISPLAY_STATE_MULTI_EXTENDED &&
+ cached_displays_.size() <= 2) ||
+ (num_on_displays != 0 &&
+ num_on_displays != static_cast<int>(cached_displays_.size()))) {
+ LOG(WARNING) << "Ignoring request to enter extended mode with "
+ << cached_displays_.size() << " connected display(s) and "
+ << num_on_displays << " turned on";
+ return false;
+ }
+
+ for (size_t i = 0; i < cached_displays_.size(); ++i) {
+ DisplayState* state = &cached_displays_[i];
+ new_origins[i].set_y(size.height() ? size.height() + kVerticalGap : 0);
+ new_mode[i] = display_power[i] ? state->selected_mode : NULL;
+
+ // Retain the full screen size even if all displays are off so the
+ // same desktop configuration can be restored when the displays are
+ // turned back on.
+ const DisplayMode* mode_info = cached_displays_[i].selected_mode;
+ if (!mode_info) {
+ LOG(WARNING) << "No selected mode when configuring display: "
+ << state->display->ToString();
+ return false;
+ }
+
+ size.set_width(std::max<int>(size.width(), mode_info->size().width()));
+ size.set_height(size.height() + (size.height() ? kVerticalGap : 0) +
+ mode_info->size().height());
+ }
+ break;
+ }
+ }
+
+ // Finally, apply the desired changes.
+ bool all_succeeded = true;
+ if (!cached_displays_.empty()) {
+ native_display_delegate_->CreateFrameBuffer(size);
+ for (size_t i = 0; i < cached_displays_.size(); ++i) {
+ const DisplayState& state = cached_displays_[i];
+ bool configure_succeeded = false;
+
+ while (true) {
+ if (native_display_delegate_->Configure(
+ *state.display, new_mode[i], new_origins[i])) {
+ state.display->set_current_mode(new_mode[i]);
+ state.display->set_origin(new_origins[i]);
+
+ configure_succeeded = true;
+ break;
+ }
+
+ const DisplayMode* mode_info = new_mode[i];
+ if (!mode_info)
+ break;
+
+ // Find the mode with the next-best resolution and see if that can
+ // be set.
+ int best_mode_pixels = 0;
+
+ int current_mode_pixels = mode_info->size().GetArea();
+ for (DisplayModeList::const_iterator it =
+ state.display->modes().begin();
+ it != state.display->modes().end();
+ it++) {
+ int pixel_count = (*it)->size().GetArea();
+ if ((pixel_count < current_mode_pixels) &&
+ (pixel_count > best_mode_pixels)) {
+ new_mode[i] = *it;
+ best_mode_pixels = pixel_count;
+ }
+ }
+
+ if (best_mode_pixels == 0)
+ break;
+ }
+
+ if (!configure_succeeded)
+ all_succeeded = false;
+
+ // If we are trying to set mirror mode and one of the modesets fails,
+ // then the two monitors will be mis-matched. In this case, return
+ // false to let the observers be aware.
+ if (display_state == MULTIPLE_DISPLAY_STATE_DUAL_MIRROR &&
+ display_power[i] &&
+ state.display->current_mode() != state.mirror_mode)
+ all_succeeded = false;
+ }
+ }
+
+ if (all_succeeded) {
+ display_state_ = display_state;
+ current_power_state_ = power_state;
+ framebuffer_size_ = size;
+ }
+ return all_succeeded;
+}
+
+MultipleDisplayState DisplayConfigurator::ChooseDisplayState(
+ chromeos::DisplayPowerState power_state) const {
+ int num_on_displays = GetDisplayPower(cached_displays_, power_state, NULL);
+ switch (cached_displays_.size()) {
+ case 0:
+ return MULTIPLE_DISPLAY_STATE_HEADLESS;
+ case 1:
+ return MULTIPLE_DISPLAY_STATE_SINGLE;
+ default: {
+ if (num_on_displays == 1) {
+ // If only one display is currently turned on, return the "single"
+ // state so that its native mode will be used.
+ return MULTIPLE_DISPLAY_STATE_SINGLE;
+ } if (num_on_displays >= 3) {
+ return MULTIPLE_DISPLAY_STATE_MULTI_EXTENDED;
+ } else if (cached_displays_.size() == 2) {
+ if (!state_controller_)
+ return MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED;
+ // With either both displays on or both displays off, use one of the
+ // dual modes.
+ std::vector<int64_t> display_ids;
+ for (size_t i = 0; i < cached_displays_.size(); ++i)
+ display_ids.push_back(cached_displays_[i].display->display_id());
+
+ return state_controller_->GetStateForDisplayIds(display_ids);
+ }
+ NOTREACHED();
+ }
+ }
+ return MULTIPLE_DISPLAY_STATE_INVALID;
+}
+
} // namespace ui
« no previous file with comments | « ui/display/chromeos/display_configurator.h ('k') | ui/display/chromeos/display_configurator_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698