OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "ui/display/chromeos/display_configurator.h" | 5 #include "ui/display/chromeos/display_configurator.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/command_line.h" | 8 #include "base/command_line.h" |
9 #include "base/logging.h" | 9 #include "base/logging.h" |
10 #include "base/sys_info.h" | 10 #include "base/sys_info.h" |
11 #include "base/time/time.h" | 11 #include "base/time/time.h" |
12 #include "ui/display/chromeos/display_util.h" | 12 #include "ui/display/chromeos/display_util.h" |
| 13 #include "ui/display/chromeos/update_display_configuration_task.h" |
13 #include "ui/display/display_switches.h" | 14 #include "ui/display/display_switches.h" |
14 #include "ui/display/types/display_mode.h" | 15 #include "ui/display/types/display_mode.h" |
15 #include "ui/display/types/display_snapshot.h" | 16 #include "ui/display/types/display_snapshot.h" |
16 #include "ui/display/types/native_display_delegate.h" | 17 #include "ui/display/types/native_display_delegate.h" |
17 | 18 |
18 namespace ui { | 19 namespace ui { |
19 | 20 |
20 namespace { | 21 namespace { |
21 | 22 |
22 typedef std::vector<const DisplayMode*> DisplayModeList; | 23 typedef std::vector<const DisplayMode*> DisplayModeList; |
(...skipping 24 matching lines...) Expand all Loading... |
47 bool DisplayConfigurator::TestApi::TriggerConfigureTimeout() { | 48 bool DisplayConfigurator::TestApi::TriggerConfigureTimeout() { |
48 if (configurator_->configure_timer_.IsRunning()) { | 49 if (configurator_->configure_timer_.IsRunning()) { |
49 configurator_->configure_timer_.user_task().Run(); | 50 configurator_->configure_timer_.user_task().Run(); |
50 configurator_->configure_timer_.Stop(); | 51 configurator_->configure_timer_.Stop(); |
51 return true; | 52 return true; |
52 } else { | 53 } else { |
53 return false; | 54 return false; |
54 } | 55 } |
55 } | 56 } |
56 | 57 |
| 58 //////////////////////////////////////////////////////////////////////////////// |
| 59 // DisplayConfigurator::DisplayLayoutManagerImpl implementation |
| 60 |
| 61 class DisplayConfigurator::DisplayLayoutManagerImpl |
| 62 : public DisplayLayoutManager { |
| 63 public: |
| 64 DisplayLayoutManagerImpl(DisplayConfigurator* configurator); |
| 65 ~DisplayLayoutManagerImpl() override; |
| 66 |
| 67 // DisplayConfigurator::DisplayLayoutManager: |
| 68 SoftwareMirroringController* GetSoftwareMirroringController() const override; |
| 69 StateController* GetStateController() const override; |
| 70 MultipleDisplayState GetDisplayState() const override; |
| 71 chromeos::DisplayPowerState GetPowerState() const override; |
| 72 std::vector<DisplayState> ParseDisplays( |
| 73 const std::vector<DisplaySnapshot*>& displays) const override; |
| 74 bool GetDisplayLayout(const std::vector<DisplayState>& displays, |
| 75 MultipleDisplayState new_display_state, |
| 76 chromeos::DisplayPowerState new_power_state, |
| 77 std::vector<DisplayConfigureRequest>* requests, |
| 78 gfx::Size* framebuffer_size) const override; |
| 79 |
| 80 private: |
| 81 // Helper method for ParseDisplays() that initializes the passed-in |
| 82 // displays' |mirror_mode| fields by looking for a mode in |internal_display| |
| 83 // and |external_display| having the same resolution. Returns false if a |
| 84 // shared mode wasn't found or created. |
| 85 // |
| 86 // |try_panel_fitting| allows creating a panel-fitting mode for |
| 87 // |internal_display| instead of only searching for a matching mode (note that |
| 88 // it may lead to a crash if |internal_display| is not capable of panel |
| 89 // fitting). |
| 90 // |
| 91 // |preserve_aspect| limits the search/creation only to the modes having the |
| 92 // native aspect ratio of |external_display|. |
| 93 bool FindMirrorMode(DisplayState* internal_display, |
| 94 DisplayState* external_display, |
| 95 bool try_panel_fitting, |
| 96 bool preserve_aspect) const; |
| 97 |
| 98 DisplayConfigurator* configurator_; // Not owned. |
| 99 |
| 100 DISALLOW_COPY_AND_ASSIGN(DisplayLayoutManagerImpl); |
| 101 }; |
| 102 |
| 103 DisplayConfigurator::DisplayLayoutManagerImpl::DisplayLayoutManagerImpl( |
| 104 DisplayConfigurator* configurator) |
| 105 : configurator_(configurator) { |
| 106 } |
| 107 |
| 108 DisplayConfigurator::DisplayLayoutManagerImpl::~DisplayLayoutManagerImpl() { |
| 109 } |
| 110 |
| 111 DisplayConfigurator::SoftwareMirroringController* |
| 112 DisplayConfigurator::DisplayLayoutManagerImpl::GetSoftwareMirroringController() |
| 113 const { |
| 114 return configurator_->mirroring_controller_; |
| 115 } |
| 116 |
| 117 DisplayConfigurator::StateController* |
| 118 DisplayConfigurator::DisplayLayoutManagerImpl::GetStateController() const { |
| 119 return configurator_->state_controller_; |
| 120 } |
| 121 |
| 122 MultipleDisplayState |
| 123 DisplayConfigurator::DisplayLayoutManagerImpl::GetDisplayState() const { |
| 124 return configurator_->current_display_state_; |
| 125 } |
| 126 |
| 127 chromeos::DisplayPowerState |
| 128 DisplayConfigurator::DisplayLayoutManagerImpl::GetPowerState() const { |
| 129 return configurator_->current_power_state_; |
| 130 } |
| 131 |
| 132 std::vector<DisplayConfigurator::DisplayState> |
| 133 DisplayConfigurator::DisplayLayoutManagerImpl::ParseDisplays( |
| 134 const std::vector<DisplaySnapshot*>& snapshots) const { |
| 135 std::vector<DisplayState> cached_displays; |
| 136 for (auto snapshot : snapshots) { |
| 137 DisplayState display_state; |
| 138 display_state.display = snapshot; |
| 139 cached_displays.push_back(display_state); |
| 140 } |
| 141 |
| 142 // Set |selected_mode| fields. |
| 143 for (size_t i = 0; i < cached_displays.size(); ++i) { |
| 144 DisplayState* display_state = &cached_displays[i]; |
| 145 gfx::Size size; |
| 146 if (GetStateController() && |
| 147 GetStateController()->GetResolutionForDisplayId( |
| 148 display_state->display->display_id(), &size)) { |
| 149 display_state->selected_mode = |
| 150 FindDisplayModeMatchingSize(*display_state->display, size); |
| 151 } |
| 152 |
| 153 // Fall back to native mode. |
| 154 if (!display_state->selected_mode) |
| 155 display_state->selected_mode = display_state->display->native_mode(); |
| 156 } |
| 157 |
| 158 // Set |mirror_mode| fields. |
| 159 if (cached_displays.size() == 2) { |
| 160 bool one_is_internal = |
| 161 cached_displays[0].display->type() == DISPLAY_CONNECTION_TYPE_INTERNAL; |
| 162 bool two_is_internal = |
| 163 cached_displays[1].display->type() == DISPLAY_CONNECTION_TYPE_INTERNAL; |
| 164 int internal_displays = |
| 165 (one_is_internal ? 1 : 0) + (two_is_internal ? 1 : 0); |
| 166 DCHECK_LT(internal_displays, 2); |
| 167 LOG_IF(WARNING, internal_displays >= 2) |
| 168 << "At least two internal displays detected."; |
| 169 |
| 170 bool can_mirror = false; |
| 171 for (int attempt = 0; !can_mirror && attempt < 2; ++attempt) { |
| 172 // Try preserving external display's aspect ratio on the first attempt. |
| 173 // If that fails, fall back to the highest matching resolution. |
| 174 bool preserve_aspect = attempt == 0; |
| 175 |
| 176 if (internal_displays == 1) { |
| 177 can_mirror = FindMirrorMode(&cached_displays[one_is_internal ? 0 : 1], |
| 178 &cached_displays[one_is_internal ? 1 : 0], |
| 179 configurator_->is_panel_fitting_enabled_, |
| 180 preserve_aspect); |
| 181 } else { // if (internal_displays == 0) |
| 182 // No panel fitting for external displays, so fall back to exact match. |
| 183 can_mirror = FindMirrorMode(&cached_displays[0], &cached_displays[1], |
| 184 false, preserve_aspect); |
| 185 if (!can_mirror && preserve_aspect) { |
| 186 // FindMirrorMode() will try to preserve aspect ratio of what it |
| 187 // thinks is external display, so if it didn't succeed with one, maybe |
| 188 // it will succeed with the other. This way we will have the correct |
| 189 // aspect ratio on at least one of them. |
| 190 can_mirror = FindMirrorMode(&cached_displays[1], &cached_displays[0], |
| 191 false, preserve_aspect); |
| 192 } |
| 193 } |
| 194 } |
| 195 } |
| 196 |
| 197 return cached_displays; |
| 198 } |
| 199 |
| 200 bool DisplayConfigurator::DisplayLayoutManagerImpl::GetDisplayLayout( |
| 201 const std::vector<DisplayState>& displays, |
| 202 MultipleDisplayState new_display_state, |
| 203 chromeos::DisplayPowerState new_power_state, |
| 204 std::vector<DisplayConfigureRequest>* requests, |
| 205 gfx::Size* framebuffer_size) const { |
| 206 std::vector<bool> display_power; |
| 207 int num_on_displays = |
| 208 GetDisplayPower(displays, new_power_state, &display_power); |
| 209 VLOG(1) << "EnterState: display=" |
| 210 << MultipleDisplayStateToString(new_display_state) |
| 211 << " power=" << DisplayPowerStateToString(new_power_state); |
| 212 |
| 213 // Framebuffer dimensions. |
| 214 gfx::Size size; |
| 215 |
| 216 for (size_t i = 0; i < displays.size(); ++i) { |
| 217 requests->push_back(DisplayConfigureRequest( |
| 218 displays[i].display, displays[i].display->current_mode(), |
| 219 gfx::Point())); |
| 220 } |
| 221 |
| 222 switch (new_display_state) { |
| 223 case MULTIPLE_DISPLAY_STATE_INVALID: |
| 224 NOTREACHED() << "Ignoring request to enter invalid state with " |
| 225 << displays.size() << " connected display(s)"; |
| 226 return false; |
| 227 case MULTIPLE_DISPLAY_STATE_HEADLESS: |
| 228 if (displays.size() != 0) { |
| 229 LOG(WARNING) << "Ignoring request to enter headless mode with " |
| 230 << displays.size() << " connected display(s)"; |
| 231 return false; |
| 232 } |
| 233 break; |
| 234 case MULTIPLE_DISPLAY_STATE_SINGLE: { |
| 235 // If there are multiple displays connected, only one should be turned on. |
| 236 if (displays.size() != 1 && num_on_displays != 1) { |
| 237 LOG(WARNING) << "Ignoring request to enter single mode with " |
| 238 << displays.size() << " connected displays and " |
| 239 << num_on_displays << " turned on"; |
| 240 return false; |
| 241 } |
| 242 |
| 243 for (size_t i = 0; i < displays.size(); ++i) { |
| 244 const DisplayConfigurator::DisplayState* state = &displays[i]; |
| 245 (*requests)[i].mode = display_power[i] ? state->selected_mode : NULL; |
| 246 |
| 247 if (display_power[i] || displays.size() == 1) { |
| 248 const DisplayMode* mode_info = state->selected_mode; |
| 249 if (!mode_info) { |
| 250 LOG(WARNING) << "No selected mode when configuring display: " |
| 251 << state->display->ToString(); |
| 252 return false; |
| 253 } |
| 254 if (mode_info->size() == gfx::Size(1024, 768)) { |
| 255 VLOG(1) << "Potentially misdetecting display(1024x768):" |
| 256 << " displays size=" << displays.size() |
| 257 << ", num_on_displays=" << num_on_displays |
| 258 << ", current size:" << size.width() << "x" << size.height() |
| 259 << ", i=" << i << ", display=" << state->display->ToString() |
| 260 << ", display_mode=" << mode_info->ToString(); |
| 261 } |
| 262 size = mode_info->size(); |
| 263 } |
| 264 } |
| 265 break; |
| 266 } |
| 267 case MULTIPLE_DISPLAY_STATE_DUAL_MIRROR: { |
| 268 if (displays.size() != 2 || |
| 269 (num_on_displays != 0 && num_on_displays != 2)) { |
| 270 LOG(WARNING) << "Ignoring request to enter mirrored mode with " |
| 271 << displays.size() << " connected display(s) and " |
| 272 << num_on_displays << " turned on"; |
| 273 return false; |
| 274 } |
| 275 |
| 276 const DisplayMode* mode_info = displays[0].mirror_mode; |
| 277 if (!mode_info) { |
| 278 LOG(WARNING) << "No mirror mode when configuring display: " |
| 279 << displays[0].display->ToString(); |
| 280 return false; |
| 281 } |
| 282 size = mode_info->size(); |
| 283 |
| 284 for (size_t i = 0; i < displays.size(); ++i) { |
| 285 const DisplayConfigurator::DisplayState* state = &displays[i]; |
| 286 (*requests)[i].mode = display_power[i] ? state->mirror_mode : NULL; |
| 287 } |
| 288 break; |
| 289 } |
| 290 case MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED: |
| 291 case MULTIPLE_DISPLAY_STATE_MULTI_EXTENDED: { |
| 292 if ((new_display_state == MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED && |
| 293 displays.size() != 2) || |
| 294 (new_display_state == MULTIPLE_DISPLAY_STATE_MULTI_EXTENDED && |
| 295 displays.size() <= 2) || |
| 296 (num_on_displays != 0 && |
| 297 num_on_displays != static_cast<int>(displays.size()))) { |
| 298 LOG(WARNING) << "Ignoring request to enter extended mode with " |
| 299 << displays.size() << " connected display(s) and " |
| 300 << num_on_displays << " turned on"; |
| 301 return false; |
| 302 } |
| 303 |
| 304 for (size_t i = 0; i < displays.size(); ++i) { |
| 305 const DisplayConfigurator::DisplayState* state = &displays[i]; |
| 306 (*requests)[i].origin.set_y(size.height() ? size.height() + kVerticalGap |
| 307 : 0); |
| 308 (*requests)[i].mode = display_power[i] ? state->selected_mode : NULL; |
| 309 |
| 310 // Retain the full screen size even if all displays are off so the |
| 311 // same desktop configuration can be restored when the displays are |
| 312 // turned back on. |
| 313 const DisplayMode* mode_info = displays[i].selected_mode; |
| 314 if (!mode_info) { |
| 315 LOG(WARNING) << "No selected mode when configuring display: " |
| 316 << state->display->ToString(); |
| 317 return false; |
| 318 } |
| 319 |
| 320 size.set_width(std::max<int>(size.width(), mode_info->size().width())); |
| 321 size.set_height(size.height() + (size.height() ? kVerticalGap : 0) + |
| 322 mode_info->size().height()); |
| 323 } |
| 324 break; |
| 325 } |
| 326 } |
| 327 |
| 328 *framebuffer_size = size; |
| 329 return true; |
| 330 } |
| 331 |
| 332 bool DisplayConfigurator::DisplayLayoutManagerImpl::FindMirrorMode( |
| 333 DisplayState* internal_display, |
| 334 DisplayState* external_display, |
| 335 bool try_panel_fitting, |
| 336 bool preserve_aspect) const { |
| 337 const DisplayMode* internal_native_info = |
| 338 internal_display->display->native_mode(); |
| 339 const DisplayMode* external_native_info = |
| 340 external_display->display->native_mode(); |
| 341 if (!internal_native_info || !external_native_info) |
| 342 return false; |
| 343 |
| 344 // Check if some external display resolution can be mirrored on internal. |
| 345 // Prefer the modes in the order they're present in DisplaySnapshot, assuming |
| 346 // this is the order in which they look better on the monitor. |
| 347 for (DisplayModeList::const_iterator external_it = |
| 348 external_display->display->modes().begin(); |
| 349 external_it != external_display->display->modes().end(); ++external_it) { |
| 350 const DisplayMode& external_info = **external_it; |
| 351 bool is_native_aspect_ratio = |
| 352 external_native_info->size().width() * external_info.size().height() == |
| 353 external_native_info->size().height() * external_info.size().width(); |
| 354 if (preserve_aspect && !is_native_aspect_ratio) |
| 355 continue; // Allow only aspect ratio preserving modes for mirroring. |
| 356 |
| 357 // Try finding an exact match. |
| 358 for (DisplayModeList::const_iterator internal_it = |
| 359 internal_display->display->modes().begin(); |
| 360 internal_it != internal_display->display->modes().end(); |
| 361 ++internal_it) { |
| 362 const DisplayMode& internal_info = **internal_it; |
| 363 if (internal_info.size().width() == external_info.size().width() && |
| 364 internal_info.size().height() == external_info.size().height() && |
| 365 internal_info.is_interlaced() == external_info.is_interlaced()) { |
| 366 internal_display->mirror_mode = *internal_it; |
| 367 external_display->mirror_mode = *external_it; |
| 368 return true; // Mirror mode found. |
| 369 } |
| 370 } |
| 371 |
| 372 // Try to create a matching internal display mode by panel fitting. |
| 373 if (try_panel_fitting) { |
| 374 // We can downscale by 1.125, and upscale indefinitely. Downscaling looks |
| 375 // ugly, so, can fit == can upscale. Also, internal panels don't support |
| 376 // fitting interlaced modes. |
| 377 bool can_fit = internal_native_info->size().width() >= |
| 378 external_info.size().width() && |
| 379 internal_native_info->size().height() >= |
| 380 external_info.size().height() && |
| 381 !external_info.is_interlaced(); |
| 382 if (can_fit) { |
| 383 configurator_->native_display_delegate_->AddMode( |
| 384 *internal_display->display, *external_it); |
| 385 internal_display->display->add_mode(*external_it); |
| 386 internal_display->mirror_mode = *external_it; |
| 387 external_display->mirror_mode = *external_it; |
| 388 return true; // Mirror mode created. |
| 389 } |
| 390 } |
| 391 } |
| 392 |
| 393 return false; |
| 394 } |
| 395 |
| 396 //////////////////////////////////////////////////////////////////////////////// |
| 397 // DisplayConfigurator implementation |
| 398 |
57 // static | 399 // static |
58 const DisplayMode* DisplayConfigurator::FindDisplayModeMatchingSize( | 400 const DisplayMode* DisplayConfigurator::FindDisplayModeMatchingSize( |
59 const DisplaySnapshot& display, | 401 const DisplaySnapshot& display, |
60 const gfx::Size& size) { | 402 const gfx::Size& size) { |
61 const DisplayMode* best_mode = NULL; | 403 const DisplayMode* best_mode = NULL; |
62 for (DisplayModeList::const_iterator it = display.modes().begin(); | 404 for (DisplayModeList::const_iterator it = display.modes().begin(); |
63 it != display.modes().end(); | 405 it != display.modes().end(); |
64 ++it) { | 406 ++it) { |
65 const DisplayMode* mode = *it; | 407 const DisplayMode* mode = *it; |
66 | 408 |
(...skipping 28 matching lines...) Expand all Loading... |
95 } | 437 } |
96 | 438 |
97 return best_mode; | 439 return best_mode; |
98 } | 440 } |
99 | 441 |
100 DisplayConfigurator::DisplayConfigurator() | 442 DisplayConfigurator::DisplayConfigurator() |
101 : state_controller_(NULL), | 443 : state_controller_(NULL), |
102 mirroring_controller_(NULL), | 444 mirroring_controller_(NULL), |
103 is_panel_fitting_enabled_(false), | 445 is_panel_fitting_enabled_(false), |
104 configure_display_(base::SysInfo::IsRunningOnChromeOS()), | 446 configure_display_(base::SysInfo::IsRunningOnChromeOS()), |
105 display_state_(MULTIPLE_DISPLAY_STATE_INVALID), | 447 current_display_state_(MULTIPLE_DISPLAY_STATE_INVALID), |
| 448 current_power_state_(chromeos::DISPLAY_POWER_ALL_ON), |
| 449 requested_display_state_(MULTIPLE_DISPLAY_STATE_INVALID), |
106 requested_power_state_(chromeos::DISPLAY_POWER_ALL_ON), | 450 requested_power_state_(chromeos::DISPLAY_POWER_ALL_ON), |
107 current_power_state_(chromeos::DISPLAY_POWER_ALL_ON), | 451 requested_power_state_change_(false), |
| 452 requested_power_flags_(kSetDisplayPowerNoFlags), |
| 453 force_configure_(false), |
108 next_display_protection_client_id_(1), | 454 next_display_protection_client_id_(1), |
109 display_externally_controlled_(false) { | 455 display_externally_controlled_(false), |
| 456 layout_manager_(new DisplayLayoutManagerImpl(this)), |
| 457 weak_ptr_factory_(this) { |
110 } | 458 } |
111 | 459 |
112 DisplayConfigurator::~DisplayConfigurator() { | 460 DisplayConfigurator::~DisplayConfigurator() { |
113 if (native_display_delegate_) | 461 if (native_display_delegate_) |
114 native_display_delegate_->RemoveObserver(this); | 462 native_display_delegate_->RemoveObserver(this); |
115 } | 463 } |
116 | 464 |
117 void DisplayConfigurator::SetDelegateForTesting( | 465 void DisplayConfigurator::SetDelegateForTesting( |
118 scoped_ptr<NativeDisplayDelegate> display_delegate) { | 466 scoped_ptr<NativeDisplayDelegate> display_delegate) { |
119 DCHECK(!native_display_delegate_); | 467 DCHECK(!native_display_delegate_); |
120 | 468 |
121 native_display_delegate_ = display_delegate.Pass(); | 469 native_display_delegate_ = display_delegate.Pass(); |
122 configure_display_ = true; | 470 configure_display_ = true; |
123 } | 471 } |
124 | 472 |
125 void DisplayConfigurator::SetInitialDisplayPower( | 473 void DisplayConfigurator::SetInitialDisplayPower( |
126 chromeos::DisplayPowerState power_state) { | 474 chromeos::DisplayPowerState power_state) { |
127 DCHECK_EQ(display_state_, MULTIPLE_DISPLAY_STATE_INVALID); | 475 DCHECK_EQ(current_display_state_, MULTIPLE_DISPLAY_STATE_INVALID); |
128 requested_power_state_ = current_power_state_ = power_state; | 476 requested_power_state_ = current_power_state_ = power_state; |
129 } | 477 } |
130 | 478 |
131 void DisplayConfigurator::Init(bool is_panel_fitting_enabled) { | 479 void DisplayConfigurator::Init(bool is_panel_fitting_enabled) { |
132 is_panel_fitting_enabled_ = is_panel_fitting_enabled; | 480 is_panel_fitting_enabled_ = is_panel_fitting_enabled; |
133 if (!configure_display_ || display_externally_controlled_) | 481 if (!configure_display_ || display_externally_controlled_) |
134 return; | 482 return; |
135 | 483 |
136 // If the delegate is already initialized don't update it (For example, tests | 484 // If the delegate is already initialized don't update it (For example, tests |
137 // set their own delegates). | 485 // set their own delegates). |
(...skipping 28 matching lines...) Expand all Loading... |
166 | 514 |
167 display_externally_controlled_ = true; | 515 display_externally_controlled_ = true; |
168 native_display_delegate_->RelinquishDisplayControl(); | 516 native_display_delegate_->RelinquishDisplayControl(); |
169 } | 517 } |
170 | 518 |
171 void DisplayConfigurator::ForceInitialConfigure( | 519 void DisplayConfigurator::ForceInitialConfigure( |
172 uint32_t background_color_argb) { | 520 uint32_t background_color_argb) { |
173 if (!configure_display_ || display_externally_controlled_) | 521 if (!configure_display_ || display_externally_controlled_) |
174 return; | 522 return; |
175 | 523 |
176 native_display_delegate_->GrabServer(); | |
177 native_display_delegate_->Initialize(); | 524 native_display_delegate_->Initialize(); |
178 | 525 |
179 UpdateCachedDisplays(); | 526 // ForceInitialConfigure should be the first configuration so there shouldn't |
180 if (cached_displays_.size() > 1 && background_color_argb) | 527 // be anything scheduled. |
181 native_display_delegate_->SetBackgroundColor(background_color_argb); | 528 DCHECK(!configuration_task_); |
182 const MultipleDisplayState new_state = ChooseDisplayState( | |
183 requested_power_state_); | |
184 const bool success = EnterStateOrFallBackToSoftwareMirroring( | |
185 new_state, requested_power_state_); | |
186 | 529 |
187 // Force the DPMS on chrome startup as the driver doesn't always detect | 530 configuration_task_.reset(new UpdateDisplayConfigurationTask( |
188 // that all displays are on when signing out. | 531 native_display_delegate_.get(), layout_manager_.get(), |
189 native_display_delegate_->ForceDPMSOn(); | 532 requested_display_state_, requested_power_state_, |
190 native_display_delegate_->UngrabServer(); | 533 kSetDisplayPowerForceProbe, background_color_argb, true, |
191 NotifyObservers(success, new_state); | 534 base::Bind(&DisplayConfigurator::OnConfigured, |
| 535 weak_ptr_factory_.GetWeakPtr()))); |
| 536 configuration_task_->Run(); |
192 } | 537 } |
193 | 538 |
194 bool DisplayConfigurator::IsMirroring() const { | 539 bool DisplayConfigurator::IsMirroring() const { |
195 return display_state_ == MULTIPLE_DISPLAY_STATE_DUAL_MIRROR || | 540 return current_display_state_ == MULTIPLE_DISPLAY_STATE_DUAL_MIRROR || |
196 (mirroring_controller_ && | 541 (mirroring_controller_ && |
197 mirroring_controller_->SoftwareMirroringEnabled()); | 542 mirroring_controller_->SoftwareMirroringEnabled()); |
198 } | 543 } |
199 | 544 |
200 bool DisplayConfigurator::ApplyProtections(const ContentProtections& requests) { | 545 bool DisplayConfigurator::ApplyProtections(const ContentProtections& requests) { |
201 for (DisplayStateList::const_iterator it = cached_displays_.begin(); | 546 for (DisplayStateList::const_iterator it = cached_displays_.begin(); |
202 it != cached_displays_.end(); | 547 it != cached_displays_.end(); |
203 ++it) { | 548 ++it) { |
204 uint32_t all_desired = 0; | 549 uint32_t all_desired = 0; |
205 | 550 |
206 // In mirror mode, protection request of all displays need to be fulfilled. | 551 // In mirror mode, protection request of all displays need to be fulfilled. |
207 // In non-mirror mode, only request of client's display needs to be | 552 // In non-mirror mode, only request of client's display needs to be |
(...skipping 201 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
409 } | 754 } |
410 } | 755 } |
411 | 756 |
412 return false; | 757 return false; |
413 } | 758 } |
414 | 759 |
415 void DisplayConfigurator::PrepareForExit() { | 760 void DisplayConfigurator::PrepareForExit() { |
416 configure_display_ = false; | 761 configure_display_ = false; |
417 } | 762 } |
418 | 763 |
419 bool DisplayConfigurator::SetDisplayPower( | 764 void DisplayConfigurator::SetDisplayPower( |
420 chromeos::DisplayPowerState power_state, | 765 chromeos::DisplayPowerState power_state, |
421 int flags) { | 766 int flags) { |
422 if (!configure_display_ || display_externally_controlled_) | 767 if (!configure_display_ || display_externally_controlled_) |
423 return false; | 768 return; |
424 | 769 |
425 VLOG(1) << "SetDisplayPower: power_state=" | 770 VLOG(1) << "SetDisplayPower: power_state=" |
426 << DisplayPowerStateToString(power_state) << " flags=" << flags | 771 << DisplayPowerStateToString(power_state) << " flags=" << flags |
427 << ", configure timer=" | 772 << ", configure timer=" |
428 << (configure_timer_.IsRunning() ? "Running" : "Stopped"); | 773 << (configure_timer_.IsRunning() ? "Running" : "Stopped"); |
429 if (power_state == current_power_state_ && | 774 if (power_state == requested_power_state_ && |
430 !(flags & kSetDisplayPowerForceProbe)) | 775 !(flags & kSetDisplayPowerForceProbe)) |
431 return true; | 776 return; |
432 | 777 |
433 native_display_delegate_->GrabServer(); | 778 requested_power_state_ = power_state; |
434 UpdateCachedDisplays(); | 779 requested_power_state_change_ = true; |
| 780 requested_power_flags_ = flags; |
435 | 781 |
436 const MultipleDisplayState new_state = ChooseDisplayState(power_state); | 782 RunPendingConfiguration(); |
437 bool attempted_change = false; | |
438 bool success = false; | |
439 | |
440 bool only_if_single_internal_display = | |
441 flags & kSetDisplayPowerOnlyIfSingleInternalDisplay; | |
442 bool single_internal_display = | |
443 cached_displays_.size() == 1 && | |
444 cached_displays_[0].display->type() == DISPLAY_CONNECTION_TYPE_INTERNAL; | |
445 if (single_internal_display || !only_if_single_internal_display) { | |
446 success = EnterStateOrFallBackToSoftwareMirroring(new_state, power_state); | |
447 attempted_change = true; | |
448 | |
449 // Force the DPMS on since the driver doesn't always detect that it | |
450 // should turn on. This is needed when coming back from idle suspend. | |
451 if (success && power_state != chromeos::DISPLAY_POWER_ALL_OFF) | |
452 native_display_delegate_->ForceDPMSOn(); | |
453 } | |
454 | |
455 native_display_delegate_->UngrabServer(); | |
456 if (attempted_change) | |
457 NotifyObservers(success, new_state); | |
458 return success; | |
459 } | 783 } |
460 | 784 |
461 bool DisplayConfigurator::SetDisplayMode(MultipleDisplayState new_state) { | 785 void DisplayConfigurator::SetDisplayMode(MultipleDisplayState new_state) { |
462 if (!configure_display_ || display_externally_controlled_) | 786 if (!configure_display_ || display_externally_controlled_) |
463 return false; | 787 return; |
464 | 788 |
465 VLOG(1) << "SetDisplayMode: state=" | 789 VLOG(1) << "SetDisplayMode: state=" |
466 << MultipleDisplayStateToString(new_state); | 790 << MultipleDisplayStateToString(new_state); |
467 if (display_state_ == new_state) { | 791 if (current_display_state_ == new_state) { |
468 // Cancel software mirroring if the state is moving from | 792 // Cancel software mirroring if the state is moving from |
469 // MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED to | 793 // MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED to |
470 // MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED. | 794 // MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED. |
471 if (mirroring_controller_ && | 795 if (mirroring_controller_ && |
472 new_state == MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED) | 796 new_state == MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED) |
473 mirroring_controller_->SetSoftwareMirroring(false); | 797 mirroring_controller_->SetSoftwareMirroring(false); |
474 NotifyObservers(true, new_state); | 798 NotifyObservers(true, new_state); |
475 return true; | 799 return; |
476 } | 800 } |
477 | 801 |
478 native_display_delegate_->GrabServer(); | 802 requested_display_state_ = new_state; |
479 UpdateCachedDisplays(); | |
480 const bool success = EnterStateOrFallBackToSoftwareMirroring( | |
481 new_state, requested_power_state_); | |
482 native_display_delegate_->UngrabServer(); | |
483 | 803 |
484 NotifyObservers(success, new_state); | 804 RunPendingConfiguration(); |
485 return success; | |
486 } | 805 } |
487 | 806 |
488 void DisplayConfigurator::OnConfigurationChanged() { | 807 void DisplayConfigurator::OnConfigurationChanged() { |
489 // Configure displays with |kConfigureDelayMs| delay, | 808 // Configure displays with |kConfigureDelayMs| delay, |
490 // so that time-consuming ConfigureDisplays() won't be called multiple times. | 809 // so that time-consuming ConfigureDisplays() won't be called multiple times. |
491 if (configure_timer_.IsRunning()) { | 810 if (configure_timer_.IsRunning()) { |
492 // Note: when the timer is running it is possible that a different task | 811 // Note: when the timer is running it is possible that a different task |
493 // (RestoreRequestedPowerStateAfterResume()) is scheduled. In these cases, | 812 // (RestoreRequestedPowerStateAfterResume()) is scheduled. In these cases, |
494 // prefer the already scheduled task to ConfigureDisplays() since | 813 // prefer the already scheduled task to ConfigureDisplays() since |
495 // ConfigureDisplays() performs only basic configuration while | 814 // ConfigureDisplays() performs only basic configuration while |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
531 } | 850 } |
532 | 851 |
533 void DisplayConfigurator::ResumeDisplays() { | 852 void DisplayConfigurator::ResumeDisplays() { |
534 configure_timer_.Start( | 853 configure_timer_.Start( |
535 FROM_HERE, | 854 FROM_HERE, |
536 base::TimeDelta::FromMilliseconds(kResumeDelayMs), | 855 base::TimeDelta::FromMilliseconds(kResumeDelayMs), |
537 base::Bind(&DisplayConfigurator::RestoreRequestedPowerStateAfterResume, | 856 base::Bind(&DisplayConfigurator::RestoreRequestedPowerStateAfterResume, |
538 base::Unretained(this))); | 857 base::Unretained(this))); |
539 } | 858 } |
540 | 859 |
541 void DisplayConfigurator::UpdateCachedDisplays() { | |
542 std::vector<DisplaySnapshot*> snapshots = | |
543 native_display_delegate_->GetDisplays(); | |
544 | |
545 cached_displays_.clear(); | |
546 for (size_t i = 0; i < snapshots.size(); ++i) { | |
547 DisplayState display_state; | |
548 display_state.display = snapshots[i]; | |
549 cached_displays_.push_back(display_state); | |
550 } | |
551 | |
552 // Set |selected_mode| fields. | |
553 for (size_t i = 0; i < cached_displays_.size(); ++i) { | |
554 DisplayState* display_state = &cached_displays_[i]; | |
555 gfx::Size size; | |
556 if (state_controller_ && | |
557 state_controller_->GetResolutionForDisplayId( | |
558 display_state->display->display_id(), &size)) { | |
559 display_state->selected_mode = | |
560 FindDisplayModeMatchingSize(*display_state->display, size); | |
561 } | |
562 | |
563 // Fall back to native mode. | |
564 if (!display_state->selected_mode) | |
565 display_state->selected_mode = display_state->display->native_mode(); | |
566 } | |
567 | |
568 // Set |mirror_mode| fields. | |
569 if (cached_displays_.size() == 2) { | |
570 bool one_is_internal = | |
571 cached_displays_[0].display->type() == DISPLAY_CONNECTION_TYPE_INTERNAL; | |
572 bool two_is_internal = | |
573 cached_displays_[1].display->type() == DISPLAY_CONNECTION_TYPE_INTERNAL; | |
574 int internal_displays = | |
575 (one_is_internal ? 1 : 0) + (two_is_internal ? 1 : 0); | |
576 DCHECK_LT(internal_displays, 2); | |
577 LOG_IF(WARNING, internal_displays == 2) | |
578 << "Two internal displays detected."; | |
579 | |
580 bool can_mirror = false; | |
581 for (int attempt = 0; !can_mirror && attempt < 2; ++attempt) { | |
582 // Try preserving external display's aspect ratio on the first attempt. | |
583 // If that fails, fall back to the highest matching resolution. | |
584 bool preserve_aspect = attempt == 0; | |
585 | |
586 if (internal_displays == 1) { | |
587 if (one_is_internal) { | |
588 can_mirror = FindMirrorMode(&cached_displays_[0], | |
589 &cached_displays_[1], | |
590 is_panel_fitting_enabled_, | |
591 preserve_aspect); | |
592 } else { | |
593 DCHECK(two_is_internal); | |
594 can_mirror = FindMirrorMode(&cached_displays_[1], | |
595 &cached_displays_[0], | |
596 is_panel_fitting_enabled_, | |
597 preserve_aspect); | |
598 } | |
599 } else { // if (internal_displays == 0) | |
600 // No panel fitting for external displays, so fall back to exact match. | |
601 can_mirror = FindMirrorMode( | |
602 &cached_displays_[0], &cached_displays_[1], false, preserve_aspect); | |
603 if (!can_mirror && preserve_aspect) { | |
604 // FindMirrorMode() will try to preserve aspect ratio of what it | |
605 // thinks is external display, so if it didn't succeed with one, maybe | |
606 // it will succeed with the other. This way we will have the correct | |
607 // aspect ratio on at least one of them. | |
608 can_mirror = FindMirrorMode(&cached_displays_[1], | |
609 &cached_displays_[0], | |
610 false, | |
611 preserve_aspect); | |
612 } | |
613 } | |
614 } | |
615 } | |
616 } | |
617 | |
618 bool DisplayConfigurator::FindMirrorMode(DisplayState* internal_display, | |
619 DisplayState* external_display, | |
620 bool try_panel_fitting, | |
621 bool preserve_aspect) { | |
622 const DisplayMode* internal_native_info = | |
623 internal_display->display->native_mode(); | |
624 const DisplayMode* external_native_info = | |
625 external_display->display->native_mode(); | |
626 if (!internal_native_info || !external_native_info) | |
627 return false; | |
628 | |
629 // Check if some external display resolution can be mirrored on internal. | |
630 // Prefer the modes in the order they're present in DisplaySnapshot, assuming | |
631 // this is the order in which they look better on the monitor. | |
632 for (DisplayModeList::const_iterator external_it = | |
633 external_display->display->modes().begin(); | |
634 external_it != external_display->display->modes().end(); | |
635 ++external_it) { | |
636 const DisplayMode& external_info = **external_it; | |
637 bool is_native_aspect_ratio = | |
638 external_native_info->size().width() * external_info.size().height() == | |
639 external_native_info->size().height() * external_info.size().width(); | |
640 if (preserve_aspect && !is_native_aspect_ratio) | |
641 continue; // Allow only aspect ratio preserving modes for mirroring. | |
642 | |
643 // Try finding an exact match. | |
644 for (DisplayModeList::const_iterator internal_it = | |
645 internal_display->display->modes().begin(); | |
646 internal_it != internal_display->display->modes().end(); | |
647 ++internal_it) { | |
648 const DisplayMode& internal_info = **internal_it; | |
649 if (internal_info.size().width() == external_info.size().width() && | |
650 internal_info.size().height() == external_info.size().height() && | |
651 internal_info.is_interlaced() == external_info.is_interlaced()) { | |
652 internal_display->mirror_mode = *internal_it; | |
653 external_display->mirror_mode = *external_it; | |
654 return true; // Mirror mode found. | |
655 } | |
656 } | |
657 | |
658 // Try to create a matching internal display mode by panel fitting. | |
659 if (try_panel_fitting) { | |
660 // We can downscale by 1.125, and upscale indefinitely. Downscaling looks | |
661 // ugly, so, can fit == can upscale. Also, internal panels don't support | |
662 // fitting interlaced modes. | |
663 bool can_fit = internal_native_info->size().width() >= | |
664 external_info.size().width() && | |
665 internal_native_info->size().height() >= | |
666 external_info.size().height() && | |
667 !external_info.is_interlaced(); | |
668 if (can_fit) { | |
669 native_display_delegate_->AddMode(*internal_display->display, | |
670 *external_it); | |
671 internal_display->display->add_mode(*external_it); | |
672 internal_display->mirror_mode = *external_it; | |
673 external_display->mirror_mode = *external_it; | |
674 return true; // Mirror mode created. | |
675 } | |
676 } | |
677 } | |
678 | |
679 return false; | |
680 } | |
681 | |
682 void DisplayConfigurator::ConfigureDisplays() { | 860 void DisplayConfigurator::ConfigureDisplays() { |
683 if (!configure_display_ || display_externally_controlled_) | 861 if (!configure_display_ || display_externally_controlled_) |
684 return; | 862 return; |
685 | 863 |
686 native_display_delegate_->GrabServer(); | 864 force_configure_ = true; |
687 UpdateCachedDisplays(); | 865 RunPendingConfiguration(); |
688 const MultipleDisplayState new_state = ChooseDisplayState( | 866 } |
689 requested_power_state_); | |
690 const bool success = EnterStateOrFallBackToSoftwareMirroring( | |
691 new_state, requested_power_state_); | |
692 native_display_delegate_->UngrabServer(); | |
693 | 867 |
694 NotifyObservers(success, new_state); | 868 void DisplayConfigurator::RunPendingConfiguration() { |
| 869 // Configuration task is currently running. Do not start a second |
| 870 // configuration. |
| 871 if (configuration_task_) |
| 872 return; |
| 873 |
| 874 if (!ShouldRunConfigurationTask()) { |
| 875 LOG(ERROR) << "Called RunPendingConfiguration without any changes" |
| 876 " requested"; |
| 877 return; |
| 878 } |
| 879 |
| 880 configuration_task_.reset(new UpdateDisplayConfigurationTask( |
| 881 native_display_delegate_.get(), layout_manager_.get(), |
| 882 requested_display_state_, requested_power_state_, requested_power_flags_, |
| 883 0, force_configure_, base::Bind(&DisplayConfigurator::OnConfigured, |
| 884 weak_ptr_factory_.GetWeakPtr()))); |
| 885 |
| 886 // Reset the flags before running the task; otherwise it may end up scheduling |
| 887 // another configuration. |
| 888 force_configure_ = false; |
| 889 requested_power_flags_ = kSetDisplayPowerNoFlags; |
| 890 requested_power_state_change_ = false; |
| 891 requested_display_state_ = MULTIPLE_DISPLAY_STATE_INVALID; |
| 892 |
| 893 configuration_task_->Run(); |
| 894 } |
| 895 |
| 896 void DisplayConfigurator::OnConfigured( |
| 897 bool success, |
| 898 const std::vector<DisplayState>& displays, |
| 899 const gfx::Size& framebuffer_size, |
| 900 MultipleDisplayState new_display_state, |
| 901 chromeos::DisplayPowerState new_power_state) { |
| 902 VLOG(1) << "OnConfigured: success=" << success << " new_display_state=" |
| 903 << MultipleDisplayStateToString(new_display_state) |
| 904 << " new_power_state=" << DisplayPowerStateToString(new_power_state); |
| 905 |
| 906 cached_displays_ = displays; |
| 907 if (success) { |
| 908 current_display_state_ = new_display_state; |
| 909 current_power_state_ = new_power_state; |
| 910 framebuffer_size_ = framebuffer_size; |
| 911 // If the requested power state hasn't changed then make sure that value |
| 912 // gets updated as well since the last requested value may have been |
| 913 // dependent on certain conditions (ie: if only the internal monitor was |
| 914 // present). |
| 915 if (!requested_power_state_change_) |
| 916 requested_power_state_ = new_power_state; |
| 917 } |
| 918 |
| 919 configuration_task_.reset(); |
| 920 NotifyObservers(success, new_display_state); |
| 921 |
| 922 if (success && !configure_timer_.IsRunning() && |
| 923 ShouldRunConfigurationTask()) { |
| 924 configure_timer_.Start(FROM_HERE, |
| 925 base::TimeDelta::FromMilliseconds(kConfigureDelayMs), |
| 926 this, &DisplayConfigurator::RunPendingConfiguration); |
| 927 } |
| 928 } |
| 929 |
| 930 bool DisplayConfigurator::ShouldRunConfigurationTask() const { |
| 931 if (force_configure_) |
| 932 return true; |
| 933 |
| 934 // Schedule if there is a request to change the display state. |
| 935 if (requested_display_state_ != current_display_state_ && |
| 936 requested_display_state_ != MULTIPLE_DISPLAY_STATE_INVALID) |
| 937 return true; |
| 938 |
| 939 // Schedule if there is a request to change the power state. |
| 940 if (requested_power_state_change_) |
| 941 return true; |
| 942 |
| 943 return false; |
695 } | 944 } |
696 | 945 |
697 void DisplayConfigurator::RestoreRequestedPowerStateAfterResume() { | 946 void DisplayConfigurator::RestoreRequestedPowerStateAfterResume() { |
698 // Force probing to ensure that we pick up any changes that were made while | 947 // Force probing to ensure that we pick up any changes that were made while |
699 // the system was suspended. | 948 // the system was suspended. |
700 SetDisplayPower(requested_power_state_, kSetDisplayPowerForceProbe); | 949 SetDisplayPower(requested_power_state_, kSetDisplayPowerForceProbe); |
701 } | 950 } |
702 | 951 |
703 void DisplayConfigurator::NotifyObservers( | 952 void DisplayConfigurator::NotifyObservers( |
704 bool success, | 953 bool success, |
705 MultipleDisplayState attempted_state) { | 954 MultipleDisplayState attempted_state) { |
706 if (success) { | 955 if (success) { |
707 FOR_EACH_OBSERVER( | 956 FOR_EACH_OBSERVER( |
708 Observer, observers_, OnDisplayModeChanged(cached_displays_)); | 957 Observer, observers_, OnDisplayModeChanged(cached_displays_)); |
709 } else { | 958 } else { |
710 FOR_EACH_OBSERVER( | 959 FOR_EACH_OBSERVER( |
711 Observer, observers_, OnDisplayModeChangeFailed(attempted_state)); | 960 Observer, observers_, OnDisplayModeChangeFailed(attempted_state)); |
712 } | 961 } |
713 } | 962 } |
714 | 963 |
715 bool DisplayConfigurator::EnterStateOrFallBackToSoftwareMirroring( | |
716 MultipleDisplayState display_state, | |
717 chromeos::DisplayPowerState power_state) { | |
718 bool success = EnterState(display_state, power_state); | |
719 if (mirroring_controller_) { | |
720 bool enable_software_mirroring = false; | |
721 if (!success && display_state == MULTIPLE_DISPLAY_STATE_DUAL_MIRROR) { | |
722 if (display_state_ != MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED || | |
723 current_power_state_ != power_state) | |
724 EnterState(MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED, power_state); | |
725 enable_software_mirroring = success = | |
726 display_state_ == MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED; | |
727 } | |
728 mirroring_controller_->SetSoftwareMirroring(enable_software_mirroring); | |
729 } | |
730 return success; | |
731 } | |
732 | |
733 bool DisplayConfigurator::EnterState(MultipleDisplayState display_state, | |
734 chromeos::DisplayPowerState power_state) { | |
735 std::vector<bool> display_power; | |
736 int num_on_displays = | |
737 GetDisplayPower(cached_displays_, power_state, &display_power); | |
738 VLOG(1) << "EnterState: display=" | |
739 << MultipleDisplayStateToString(display_state) | |
740 << " power=" << DisplayPowerStateToString(power_state); | |
741 | |
742 // Save the requested state so we'll try to use it next time even if we fail. | |
743 requested_power_state_ = power_state; | |
744 | |
745 // Framebuffer dimensions. | |
746 gfx::Size size; | |
747 | |
748 std::vector<gfx::Point> new_origins(cached_displays_.size(), gfx::Point()); | |
749 std::vector<const DisplayMode*> new_mode; | |
750 for (size_t i = 0; i < cached_displays_.size(); ++i) | |
751 new_mode.push_back(cached_displays_[i].display->current_mode()); | |
752 | |
753 switch (display_state) { | |
754 case MULTIPLE_DISPLAY_STATE_INVALID: | |
755 NOTREACHED() << "Ignoring request to enter invalid state with " | |
756 << cached_displays_.size() << " connected display(s)"; | |
757 return false; | |
758 case MULTIPLE_DISPLAY_STATE_HEADLESS: | |
759 if (cached_displays_.size() != 0) { | |
760 LOG(WARNING) << "Ignoring request to enter headless mode with " | |
761 << cached_displays_.size() << " connected display(s)"; | |
762 return false; | |
763 } | |
764 break; | |
765 case MULTIPLE_DISPLAY_STATE_SINGLE: { | |
766 // If there are multiple displays connected, only one should be turned on. | |
767 if (cached_displays_.size() != 1 && num_on_displays != 1) { | |
768 LOG(WARNING) << "Ignoring request to enter single mode with " | |
769 << cached_displays_.size() << " connected displays and " | |
770 << num_on_displays << " turned on"; | |
771 return false; | |
772 } | |
773 | |
774 for (size_t i = 0; i < cached_displays_.size(); ++i) { | |
775 DisplayState* state = &cached_displays_[i]; | |
776 new_mode[i] = display_power[i] ? state->selected_mode : NULL; | |
777 | |
778 if (display_power[i] || cached_displays_.size() == 1) { | |
779 const DisplayMode* mode_info = state->selected_mode; | |
780 if (!mode_info) { | |
781 LOG(WARNING) << "No selected mode when configuring display: " | |
782 << state->display->ToString(); | |
783 return false; | |
784 } | |
785 if (mode_info->size() == gfx::Size(1024, 768)) { | |
786 VLOG(1) << "Potentially misdetecting display(1024x768):" | |
787 << " displays size=" << cached_displays_.size() | |
788 << ", num_on_displays=" << num_on_displays | |
789 << ", current size:" << size.width() << "x" << size.height() | |
790 << ", i=" << i << ", display=" << state->display->ToString() | |
791 << ", display_mode=" << mode_info->ToString(); | |
792 } | |
793 size = mode_info->size(); | |
794 } | |
795 } | |
796 break; | |
797 } | |
798 case MULTIPLE_DISPLAY_STATE_DUAL_MIRROR: { | |
799 if (cached_displays_.size() != 2 || | |
800 (num_on_displays != 0 && num_on_displays != 2)) { | |
801 LOG(WARNING) << "Ignoring request to enter mirrored mode with " | |
802 << cached_displays_.size() << " connected display(s) and " | |
803 << num_on_displays << " turned on"; | |
804 return false; | |
805 } | |
806 | |
807 const DisplayMode* mode_info = cached_displays_[0].mirror_mode; | |
808 if (!mode_info) { | |
809 LOG(WARNING) << "No mirror mode when configuring display: " | |
810 << cached_displays_[0].display->ToString(); | |
811 return false; | |
812 } | |
813 size = mode_info->size(); | |
814 | |
815 for (size_t i = 0; i < cached_displays_.size(); ++i) { | |
816 DisplayState* state = &cached_displays_[i]; | |
817 new_mode[i] = display_power[i] ? state->mirror_mode : NULL; | |
818 } | |
819 break; | |
820 } | |
821 case MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED: | |
822 case MULTIPLE_DISPLAY_STATE_MULTI_EXTENDED: { | |
823 if ((display_state == MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED && | |
824 cached_displays_.size() != 2) || | |
825 (display_state == MULTIPLE_DISPLAY_STATE_MULTI_EXTENDED && | |
826 cached_displays_.size() <= 2) || | |
827 (num_on_displays != 0 && | |
828 num_on_displays != static_cast<int>(cached_displays_.size()))) { | |
829 LOG(WARNING) << "Ignoring request to enter extended mode with " | |
830 << cached_displays_.size() << " connected display(s) and " | |
831 << num_on_displays << " turned on"; | |
832 return false; | |
833 } | |
834 | |
835 for (size_t i = 0; i < cached_displays_.size(); ++i) { | |
836 DisplayState* state = &cached_displays_[i]; | |
837 new_origins[i].set_y(size.height() ? size.height() + kVerticalGap : 0); | |
838 new_mode[i] = display_power[i] ? state->selected_mode : NULL; | |
839 | |
840 // Retain the full screen size even if all displays are off so the | |
841 // same desktop configuration can be restored when the displays are | |
842 // turned back on. | |
843 const DisplayMode* mode_info = cached_displays_[i].selected_mode; | |
844 if (!mode_info) { | |
845 LOG(WARNING) << "No selected mode when configuring display: " | |
846 << state->display->ToString(); | |
847 return false; | |
848 } | |
849 | |
850 size.set_width(std::max<int>(size.width(), mode_info->size().width())); | |
851 size.set_height(size.height() + (size.height() ? kVerticalGap : 0) + | |
852 mode_info->size().height()); | |
853 } | |
854 break; | |
855 } | |
856 } | |
857 | |
858 // Finally, apply the desired changes. | |
859 bool all_succeeded = true; | |
860 if (!cached_displays_.empty()) { | |
861 native_display_delegate_->CreateFrameBuffer(size); | |
862 for (size_t i = 0; i < cached_displays_.size(); ++i) { | |
863 const DisplayState& state = cached_displays_[i]; | |
864 bool configure_succeeded = false; | |
865 | |
866 while (true) { | |
867 if (native_display_delegate_->Configure( | |
868 *state.display, new_mode[i], new_origins[i])) { | |
869 state.display->set_current_mode(new_mode[i]); | |
870 state.display->set_origin(new_origins[i]); | |
871 | |
872 configure_succeeded = true; | |
873 break; | |
874 } | |
875 | |
876 const DisplayMode* mode_info = new_mode[i]; | |
877 if (!mode_info) | |
878 break; | |
879 | |
880 // Find the mode with the next-best resolution and see if that can | |
881 // be set. | |
882 int best_mode_pixels = 0; | |
883 | |
884 int current_mode_pixels = mode_info->size().GetArea(); | |
885 for (DisplayModeList::const_iterator it = | |
886 state.display->modes().begin(); | |
887 it != state.display->modes().end(); | |
888 it++) { | |
889 int pixel_count = (*it)->size().GetArea(); | |
890 if ((pixel_count < current_mode_pixels) && | |
891 (pixel_count > best_mode_pixels)) { | |
892 new_mode[i] = *it; | |
893 best_mode_pixels = pixel_count; | |
894 } | |
895 } | |
896 | |
897 if (best_mode_pixels == 0) | |
898 break; | |
899 } | |
900 | |
901 if (!configure_succeeded) | |
902 all_succeeded = false; | |
903 | |
904 // If we are trying to set mirror mode and one of the modesets fails, | |
905 // then the two monitors will be mis-matched. In this case, return | |
906 // false to let the observers be aware. | |
907 if (display_state == MULTIPLE_DISPLAY_STATE_DUAL_MIRROR && | |
908 display_power[i] && | |
909 state.display->current_mode() != state.mirror_mode) | |
910 all_succeeded = false; | |
911 } | |
912 } | |
913 | |
914 if (all_succeeded) { | |
915 display_state_ = display_state; | |
916 current_power_state_ = power_state; | |
917 framebuffer_size_ = size; | |
918 } | |
919 return all_succeeded; | |
920 } | |
921 | |
922 MultipleDisplayState DisplayConfigurator::ChooseDisplayState( | |
923 chromeos::DisplayPowerState power_state) const { | |
924 int num_on_displays = GetDisplayPower(cached_displays_, power_state, NULL); | |
925 switch (cached_displays_.size()) { | |
926 case 0: | |
927 return MULTIPLE_DISPLAY_STATE_HEADLESS; | |
928 case 1: | |
929 return MULTIPLE_DISPLAY_STATE_SINGLE; | |
930 default: { | |
931 if (num_on_displays == 1) { | |
932 // If only one display is currently turned on, return the "single" | |
933 // state so that its native mode will be used. | |
934 return MULTIPLE_DISPLAY_STATE_SINGLE; | |
935 } if (num_on_displays >= 3) { | |
936 return MULTIPLE_DISPLAY_STATE_MULTI_EXTENDED; | |
937 } else if (cached_displays_.size() == 2) { | |
938 if (!state_controller_) | |
939 return MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED; | |
940 // With either both displays on or both displays off, use one of the | |
941 // dual modes. | |
942 std::vector<int64_t> display_ids; | |
943 for (size_t i = 0; i < cached_displays_.size(); ++i) | |
944 display_ids.push_back(cached_displays_[i].display->display_id()); | |
945 | |
946 return state_controller_->GetStateForDisplayIds(display_ids); | |
947 } | |
948 NOTREACHED(); | |
949 } | |
950 } | |
951 return MULTIPLE_DISPLAY_STATE_INVALID; | |
952 } | |
953 | |
954 } // namespace ui | 964 } // namespace ui |
OLD | NEW |