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

Side by Side Diff: ui/display/chromeos/display_configurator.cc

Issue 801493002: Update DisplayConfigurator to use the asynchronous tasks (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@async-refactor4
Patch Set: Updated 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 unified diff | Download patch
OLDNEW
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
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
85 // mode wasn't found or created.
Daniel Erat 2014/12/12 16:25:28 nit: fix wrapping
dnicoara 2014/12/12 17:45:09 Done.
86 //
87 // |try_panel_fitting| allows creating a panel-fitting mode for
88 // |internal_display| instead of only searching for a matching mode (note that
89 // it may lead to a crash if |internal_info| is not capable of panel fitting).
Daniel Erat 2014/12/12 16:25:28 s/internal_info/internal_display/ ?
dnicoara 2014/12/12 17:45:09 Done.
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 (size_t i = 0; i < snapshots.size(); ++i) {
Daniel Erat 2014/12/12 16:25:29 nit: for (auto snapshot : snapshots) ?
dnicoara 2014/12/12 17:45:09 Done.
137 DisplayState display_state;
138 display_state.display = snapshots[i];
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)
Daniel Erat 2014/12/12 16:25:28 nit: >= 2 ?
dnicoara 2014/12/12 17:45:09 Done.
168 << "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 if (one_is_internal) {
Daniel Erat 2014/12/12 16:25:29 nit: to remove duplication, maybe rewrite as: c
dnicoara 2014/12/12 17:45:09 Done.
178 can_mirror = FindMirrorMode(&cached_displays[0], &cached_displays[1],
179 configurator_->is_panel_fitting_enabled_,
180 preserve_aspect);
181 } else {
182 DCHECK(two_is_internal);
183 can_mirror = FindMirrorMode(&cached_displays[1], &cached_displays[0],
184 configurator_->is_panel_fitting_enabled_,
185 preserve_aspect);
186 }
187 } else { // if (internal_displays == 0)
188 // No panel fitting for external displays, so fall back to exact match.
189 can_mirror = FindMirrorMode(&cached_displays[0], &cached_displays[1],
190 false, preserve_aspect);
191 if (!can_mirror && preserve_aspect) {
192 // FindMirrorMode() will try to preserve aspect ratio of what it
193 // thinks is external display, so if it didn't succeed with one, maybe
194 // it will succeed with the other. This way we will have the correct
195 // aspect ratio on at least one of them.
196 can_mirror = FindMirrorMode(&cached_displays[1], &cached_displays[0],
197 false, preserve_aspect);
198 }
199 }
200 }
201 }
202
203 return cached_displays;
204 }
205
206 bool DisplayConfigurator::DisplayLayoutManagerImpl::GetDisplayLayout(
207 const std::vector<DisplayState>& displays,
208 MultipleDisplayState new_display_state,
209 chromeos::DisplayPowerState new_power_state,
210 std::vector<DisplayConfigureRequest>* requests,
211 gfx::Size* framebuffer_size) const {
212 std::vector<bool> display_power;
213 int num_on_displays =
214 GetDisplayPower(displays, new_power_state, &display_power);
215 VLOG(1) << "EnterState: display="
216 << MultipleDisplayStateToString(new_display_state)
217 << " power=" << DisplayPowerStateToString(new_power_state);
218
219 // Framebuffer dimensions.
220 gfx::Size size;
221
222 for (size_t i = 0; i < displays.size(); ++i) {
223 requests->push_back(DisplayConfigureRequest(
224 displays[i].display, displays[i].display->current_mode(),
225 gfx::Point()));
226 }
227
228 switch (new_display_state) {
229 case MULTIPLE_DISPLAY_STATE_INVALID:
230 NOTREACHED() << "Ignoring request to enter invalid state with "
231 << displays.size() << " connected display(s)";
232 return false;
233 case MULTIPLE_DISPLAY_STATE_HEADLESS:
234 if (displays.size() != 0) {
235 LOG(WARNING) << "Ignoring request to enter headless mode with "
236 << displays.size() << " connected display(s)";
237 return false;
238 }
239 break;
240 case MULTIPLE_DISPLAY_STATE_SINGLE: {
241 // If there are multiple displays connected, only one should be turned on.
242 if (displays.size() != 1 && num_on_displays != 1) {
243 LOG(WARNING) << "Ignoring request to enter single mode with "
244 << displays.size() << " connected displays and "
245 << num_on_displays << " turned on";
246 return false;
247 }
248
249 for (size_t i = 0; i < displays.size(); ++i) {
250 const DisplayConfigurator::DisplayState* state = &displays[i];
251 (*requests)[i].mode = display_power[i] ? state->selected_mode : NULL;
252
253 if (display_power[i] || displays.size() == 1) {
254 const DisplayMode* mode_info = state->selected_mode;
255 if (!mode_info) {
256 LOG(WARNING) << "No selected mode when configuring display: "
257 << state->display->ToString();
258 return false;
259 }
260 if (mode_info->size() == gfx::Size(1024, 768)) {
261 VLOG(1) << "Potentially misdetecting display(1024x768):"
262 << " displays size=" << displays.size()
263 << ", num_on_displays=" << num_on_displays
264 << ", current size:" << size.width() << "x" << size.height()
265 << ", i=" << i << ", display=" << state->display->ToString()
266 << ", display_mode=" << mode_info->ToString();
267 }
268 size = mode_info->size();
269 }
270 }
271 break;
272 }
273 case MULTIPLE_DISPLAY_STATE_DUAL_MIRROR: {
274 if (displays.size() != 2 ||
275 (num_on_displays != 0 && num_on_displays != 2)) {
276 LOG(WARNING) << "Ignoring request to enter mirrored mode with "
277 << displays.size() << " connected display(s) and "
278 << num_on_displays << " turned on";
279 return false;
280 }
281
282 const DisplayMode* mode_info = displays[0].mirror_mode;
283 if (!mode_info) {
284 LOG(WARNING) << "No mirror mode when configuring display: "
285 << displays[0].display->ToString();
286 return false;
287 }
288 size = mode_info->size();
289
290 for (size_t i = 0; i < displays.size(); ++i) {
291 const DisplayConfigurator::DisplayState* state = &displays[i];
292 (*requests)[i].mode = display_power[i] ? state->mirror_mode : NULL;
293 }
294 break;
295 }
296 case MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED:
297 case MULTIPLE_DISPLAY_STATE_MULTI_EXTENDED: {
298 if ((new_display_state == MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED &&
299 displays.size() != 2) ||
300 (new_display_state == MULTIPLE_DISPLAY_STATE_MULTI_EXTENDED &&
301 displays.size() <= 2) ||
302 (num_on_displays != 0 &&
303 num_on_displays != static_cast<int>(displays.size()))) {
304 LOG(WARNING) << "Ignoring request to enter extended mode with "
305 << displays.size() << " connected display(s) and "
306 << num_on_displays << " turned on";
307 return false;
308 }
309
310 for (size_t i = 0; i < displays.size(); ++i) {
311 const DisplayConfigurator::DisplayState* state = &displays[i];
312 (*requests)[i].origin.set_y(size.height() ? size.height() + kVerticalGap
313 : 0);
314 (*requests)[i].mode = display_power[i] ? state->selected_mode : NULL;
315
316 // Retain the full screen size even if all displays are off so the
317 // same desktop configuration can be restored when the displays are
318 // turned back on.
319 const DisplayMode* mode_info = displays[i].selected_mode;
320 if (!mode_info) {
321 LOG(WARNING) << "No selected mode when configuring display: "
322 << state->display->ToString();
323 return false;
324 }
325
326 size.set_width(std::max<int>(size.width(), mode_info->size().width()));
327 size.set_height(size.height() + (size.height() ? kVerticalGap : 0) +
328 mode_info->size().height());
329 }
330 break;
331 }
332 }
333
334 *framebuffer_size = size;
335 return true;
336 }
337
338 bool DisplayConfigurator::DisplayLayoutManagerImpl::FindMirrorMode(
339 DisplayState* internal_display,
340 DisplayState* external_display,
341 bool try_panel_fitting,
342 bool preserve_aspect) const {
343 const DisplayMode* internal_native_info =
344 internal_display->display->native_mode();
345 const DisplayMode* external_native_info =
346 external_display->display->native_mode();
347 if (!internal_native_info || !external_native_info)
348 return false;
349
350 // Check if some external display resolution can be mirrored on internal.
351 // Prefer the modes in the order they're present in DisplaySnapshot, assuming
352 // this is the order in which they look better on the monitor.
353 for (DisplayModeList::const_iterator external_it =
354 external_display->display->modes().begin();
355 external_it != external_display->display->modes().end(); ++external_it) {
356 const DisplayMode& external_info = **external_it;
357 bool is_native_aspect_ratio =
358 external_native_info->size().width() * external_info.size().height() ==
359 external_native_info->size().height() * external_info.size().width();
360 if (preserve_aspect && !is_native_aspect_ratio)
361 continue; // Allow only aspect ratio preserving modes for mirroring.
362
363 // Try finding an exact match.
364 for (DisplayModeList::const_iterator internal_it =
365 internal_display->display->modes().begin();
366 internal_it != internal_display->display->modes().end();
367 ++internal_it) {
368 const DisplayMode& internal_info = **internal_it;
369 if (internal_info.size().width() == external_info.size().width() &&
370 internal_info.size().height() == external_info.size().height() &&
371 internal_info.is_interlaced() == external_info.is_interlaced()) {
372 internal_display->mirror_mode = *internal_it;
373 external_display->mirror_mode = *external_it;
374 return true; // Mirror mode found.
375 }
376 }
377
378 // Try to create a matching internal display mode by panel fitting.
379 if (try_panel_fitting) {
380 // We can downscale by 1.125, and upscale indefinitely. Downscaling looks
381 // ugly, so, can fit == can upscale. Also, internal panels don't support
382 // fitting interlaced modes.
383 bool can_fit = internal_native_info->size().width() >=
384 external_info.size().width() &&
385 internal_native_info->size().height() >=
386 external_info.size().height() &&
387 !external_info.is_interlaced();
388 if (can_fit) {
389 configurator_->native_display_delegate_->AddMode(
390 *internal_display->display, *external_it);
391 internal_display->display->add_mode(*external_it);
392 internal_display->mirror_mode = *external_it;
393 external_display->mirror_mode = *external_it;
394 return true; // Mirror mode created.
395 }
396 }
397 }
398
399 return false;
400 }
401
402 ////////////////////////////////////////////////////////////////////////////////
403 // DisplayConfigurator implementation
404
57 // static 405 // static
58 const DisplayMode* DisplayConfigurator::FindDisplayModeMatchingSize( 406 const DisplayMode* DisplayConfigurator::FindDisplayModeMatchingSize(
59 const DisplaySnapshot& display, 407 const DisplaySnapshot& display,
60 const gfx::Size& size) { 408 const gfx::Size& size) {
61 const DisplayMode* best_mode = NULL; 409 const DisplayMode* best_mode = NULL;
62 for (DisplayModeList::const_iterator it = display.modes().begin(); 410 for (DisplayModeList::const_iterator it = display.modes().begin();
63 it != display.modes().end(); 411 it != display.modes().end();
64 ++it) { 412 ++it) {
65 const DisplayMode* mode = *it; 413 const DisplayMode* mode = *it;
66 414
(...skipping 28 matching lines...) Expand all
95 } 443 }
96 444
97 return best_mode; 445 return best_mode;
98 } 446 }
99 447
100 DisplayConfigurator::DisplayConfigurator() 448 DisplayConfigurator::DisplayConfigurator()
101 : state_controller_(NULL), 449 : state_controller_(NULL),
102 mirroring_controller_(NULL), 450 mirroring_controller_(NULL),
103 is_panel_fitting_enabled_(false), 451 is_panel_fitting_enabled_(false),
104 configure_display_(base::SysInfo::IsRunningOnChromeOS()), 452 configure_display_(base::SysInfo::IsRunningOnChromeOS()),
105 display_state_(MULTIPLE_DISPLAY_STATE_INVALID), 453 current_display_state_(MULTIPLE_DISPLAY_STATE_INVALID),
454 current_power_state_(chromeos::DISPLAY_POWER_ALL_ON),
455 requested_display_state_(MULTIPLE_DISPLAY_STATE_INVALID),
106 requested_power_state_(chromeos::DISPLAY_POWER_ALL_ON), 456 requested_power_state_(chromeos::DISPLAY_POWER_ALL_ON),
107 current_power_state_(chromeos::DISPLAY_POWER_ALL_ON), 457 requested_power_state_change_(false),
458 requested_power_flags_(kSetDisplayPowerNoFlags),
459 force_configure_(false),
108 next_display_protection_client_id_(1), 460 next_display_protection_client_id_(1),
109 display_externally_controlled_(false) { 461 display_externally_controlled_(false),
462 layout_manager_(new DisplayLayoutManagerImpl(this)),
463 weak_ptr_factory_(this) {
110 } 464 }
111 465
112 DisplayConfigurator::~DisplayConfigurator() { 466 DisplayConfigurator::~DisplayConfigurator() {
113 if (native_display_delegate_) 467 if (native_display_delegate_)
114 native_display_delegate_->RemoveObserver(this); 468 native_display_delegate_->RemoveObserver(this);
115 } 469 }
116 470
117 void DisplayConfigurator::SetDelegateForTesting( 471 void DisplayConfigurator::SetDelegateForTesting(
118 scoped_ptr<NativeDisplayDelegate> display_delegate) { 472 scoped_ptr<NativeDisplayDelegate> display_delegate) {
119 DCHECK(!native_display_delegate_); 473 DCHECK(!native_display_delegate_);
120 474
121 native_display_delegate_ = display_delegate.Pass(); 475 native_display_delegate_ = display_delegate.Pass();
122 configure_display_ = true; 476 configure_display_ = true;
123 } 477 }
124 478
125 void DisplayConfigurator::SetInitialDisplayPower( 479 void DisplayConfigurator::SetInitialDisplayPower(
126 chromeos::DisplayPowerState power_state) { 480 chromeos::DisplayPowerState power_state) {
127 DCHECK_EQ(display_state_, MULTIPLE_DISPLAY_STATE_INVALID); 481 DCHECK_EQ(current_display_state_, MULTIPLE_DISPLAY_STATE_INVALID);
128 requested_power_state_ = current_power_state_ = power_state; 482 requested_power_state_ = current_power_state_ = power_state;
129 } 483 }
130 484
131 void DisplayConfigurator::Init(bool is_panel_fitting_enabled) { 485 void DisplayConfigurator::Init(bool is_panel_fitting_enabled) {
132 is_panel_fitting_enabled_ = is_panel_fitting_enabled; 486 is_panel_fitting_enabled_ = is_panel_fitting_enabled;
133 if (!configure_display_ || display_externally_controlled_) 487 if (!configure_display_ || display_externally_controlled_)
134 return; 488 return;
135 489
136 // If the delegate is already initialized don't update it (For example, tests 490 // If the delegate is already initialized don't update it (For example, tests
137 // set their own delegates). 491 // set their own delegates).
(...skipping 28 matching lines...) Expand all
166 520
167 display_externally_controlled_ = true; 521 display_externally_controlled_ = true;
168 native_display_delegate_->RelinquishDisplayControl(); 522 native_display_delegate_->RelinquishDisplayControl();
169 } 523 }
170 524
171 void DisplayConfigurator::ForceInitialConfigure( 525 void DisplayConfigurator::ForceInitialConfigure(
172 uint32_t background_color_argb) { 526 uint32_t background_color_argb) {
173 if (!configure_display_ || display_externally_controlled_) 527 if (!configure_display_ || display_externally_controlled_)
174 return; 528 return;
175 529
176 native_display_delegate_->GrabServer();
177 native_display_delegate_->Initialize(); 530 native_display_delegate_->Initialize();
178 531
179 UpdateCachedDisplays(); 532 // ForceInitialConfigure should be the first configuration so there shouldn't
180 if (cached_displays_.size() > 1 && background_color_argb) 533 // be anything scheduled.
181 native_display_delegate_->SetBackgroundColor(background_color_argb); 534 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 535
187 // Force the DPMS on chrome startup as the driver doesn't always detect 536 configuration_task_.reset(new UpdateDisplayConfigurationTask(
188 // that all displays are on when signing out. 537 native_display_delegate_.get(), layout_manager_.get(),
189 native_display_delegate_->ForceDPMSOn(); 538 requested_display_state_, requested_power_state_,
190 native_display_delegate_->UngrabServer(); 539 kSetDisplayPowerForceProbe, background_color_argb, true,
191 NotifyObservers(success, new_state); 540 base::Bind(&DisplayConfigurator::OnConfigured,
541 weak_ptr_factory_.GetWeakPtr())));
542 configuration_task_->Run();
192 } 543 }
193 544
194 bool DisplayConfigurator::IsMirroring() const { 545 bool DisplayConfigurator::IsMirroring() const {
195 return display_state_ == MULTIPLE_DISPLAY_STATE_DUAL_MIRROR || 546 return current_display_state_ == MULTIPLE_DISPLAY_STATE_DUAL_MIRROR ||
196 (mirroring_controller_ && 547 (mirroring_controller_ &&
197 mirroring_controller_->SoftwareMirroringEnabled()); 548 mirroring_controller_->SoftwareMirroringEnabled());
198 } 549 }
199 550
200 bool DisplayConfigurator::ApplyProtections(const ContentProtections& requests) { 551 bool DisplayConfigurator::ApplyProtections(const ContentProtections& requests) {
201 for (DisplayStateList::const_iterator it = cached_displays_.begin(); 552 for (DisplayStateList::const_iterator it = cached_displays_.begin();
202 it != cached_displays_.end(); 553 it != cached_displays_.end();
203 ++it) { 554 ++it) {
204 uint32_t all_desired = 0; 555 uint32_t all_desired = 0;
205 556
206 // In mirror mode, protection request of all displays need to be fulfilled. 557 // 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 558 // 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
409 } 760 }
410 } 761 }
411 762
412 return false; 763 return false;
413 } 764 }
414 765
415 void DisplayConfigurator::PrepareForExit() { 766 void DisplayConfigurator::PrepareForExit() {
416 configure_display_ = false; 767 configure_display_ = false;
417 } 768 }
418 769
419 bool DisplayConfigurator::SetDisplayPower( 770 void DisplayConfigurator::SetDisplayPower(
420 chromeos::DisplayPowerState power_state, 771 chromeos::DisplayPowerState power_state,
421 int flags) { 772 int flags) {
422 if (!configure_display_ || display_externally_controlled_) 773 if (!configure_display_ || display_externally_controlled_)
423 return false; 774 return;
424 775
425 VLOG(1) << "SetDisplayPower: power_state=" 776 VLOG(1) << "SetDisplayPower: power_state="
426 << DisplayPowerStateToString(power_state) << " flags=" << flags 777 << DisplayPowerStateToString(power_state) << " flags=" << flags
427 << ", configure timer=" 778 << ", configure timer="
428 << (configure_timer_.IsRunning() ? "Running" : "Stopped"); 779 << (configure_timer_.IsRunning() ? "Running" : "Stopped");
429 if (power_state == current_power_state_ && 780 if (power_state == requested_power_state_ &&
430 !(flags & kSetDisplayPowerForceProbe)) 781 !(flags & kSetDisplayPowerForceProbe))
431 return true; 782 return;
432 783
433 native_display_delegate_->GrabServer(); 784 requested_power_state_ = power_state;
434 UpdateCachedDisplays(); 785 requested_power_state_change_ = true;
786 requested_power_flags_ = flags;
435 787
436 const MultipleDisplayState new_state = ChooseDisplayState(power_state); 788 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 } 789 }
460 790
461 bool DisplayConfigurator::SetDisplayMode(MultipleDisplayState new_state) { 791 void DisplayConfigurator::SetDisplayMode(MultipleDisplayState new_state) {
462 if (!configure_display_ || display_externally_controlled_) 792 if (!configure_display_ || display_externally_controlled_)
463 return false; 793 return;
464 794
465 VLOG(1) << "SetDisplayMode: state=" 795 VLOG(1) << "SetDisplayMode: state="
466 << MultipleDisplayStateToString(new_state); 796 << MultipleDisplayStateToString(new_state);
467 if (display_state_ == new_state) { 797 if (current_display_state_ == new_state) {
468 // Cancel software mirroring if the state is moving from 798 // Cancel software mirroring if the state is moving from
469 // MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED to 799 // MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED to
470 // MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED. 800 // MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED.
471 if (mirroring_controller_ && 801 if (mirroring_controller_ &&
472 new_state == MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED) 802 new_state == MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED)
473 mirroring_controller_->SetSoftwareMirroring(false); 803 mirroring_controller_->SetSoftwareMirroring(false);
474 NotifyObservers(true, new_state); 804 NotifyObservers(true, new_state);
475 return true; 805 return;
476 } 806 }
477 807
478 native_display_delegate_->GrabServer(); 808 requested_display_state_ = new_state;
479 UpdateCachedDisplays();
480 const bool success = EnterStateOrFallBackToSoftwareMirroring(
481 new_state, requested_power_state_);
482 native_display_delegate_->UngrabServer();
483 809
484 NotifyObservers(success, new_state); 810 RunPendingConfiguration();
485 return success;
486 } 811 }
487 812
488 void DisplayConfigurator::OnConfigurationChanged() { 813 void DisplayConfigurator::OnConfigurationChanged() {
489 // Configure displays with |kConfigureDelayMs| delay, 814 // Configure displays with |kConfigureDelayMs| delay,
490 // so that time-consuming ConfigureDisplays() won't be called multiple times. 815 // so that time-consuming ConfigureDisplays() won't be called multiple times.
491 if (configure_timer_.IsRunning()) { 816 if (configure_timer_.IsRunning()) {
492 // Note: when the timer is running it is possible that a different task 817 // Note: when the timer is running it is possible that a different task
493 // (RestoreRequestedPowerStateAfterResume()) is scheduled. In these cases, 818 // (RestoreRequestedPowerStateAfterResume()) is scheduled. In these cases,
494 // prefer the already scheduled task to ConfigureDisplays() since 819 // prefer the already scheduled task to ConfigureDisplays() since
495 // ConfigureDisplays() performs only basic configuration while 820 // ConfigureDisplays() performs only basic configuration while
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
531 } 856 }
532 857
533 void DisplayConfigurator::ResumeDisplays() { 858 void DisplayConfigurator::ResumeDisplays() {
534 configure_timer_.Start( 859 configure_timer_.Start(
535 FROM_HERE, 860 FROM_HERE,
536 base::TimeDelta::FromMilliseconds(kResumeDelayMs), 861 base::TimeDelta::FromMilliseconds(kResumeDelayMs),
537 base::Bind(&DisplayConfigurator::RestoreRequestedPowerStateAfterResume, 862 base::Bind(&DisplayConfigurator::RestoreRequestedPowerStateAfterResume,
538 base::Unretained(this))); 863 base::Unretained(this)));
539 } 864 }
540 865
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() { 866 void DisplayConfigurator::ConfigureDisplays() {
683 if (!configure_display_ || display_externally_controlled_) 867 if (!configure_display_ || display_externally_controlled_)
684 return; 868 return;
685 869
686 native_display_delegate_->GrabServer(); 870 force_configure_ = true;
687 UpdateCachedDisplays(); 871 RunPendingConfiguration();
688 const MultipleDisplayState new_state = ChooseDisplayState( 872 }
689 requested_power_state_);
690 const bool success = EnterStateOrFallBackToSoftwareMirroring(
691 new_state, requested_power_state_);
692 native_display_delegate_->UngrabServer();
693 873
694 NotifyObservers(success, new_state); 874 void DisplayConfigurator::RunPendingConfiguration() {
875 // Configuration task is currently running. Do not start a second
876 // configuration.
877 if (configuration_task_)
878 return;
879
Daniel Erat 2014/12/12 16:25:29 nit: check that the requested_ fields don't have t
dnicoara 2014/12/12 17:45:09 I've slightly changed ShouldRunConfigurationTask()
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
Daniel Erat 2014/12/12 16:25:29 nit: "... before running the task; otherwise ..."
dnicoara 2014/12/12 17:45:09 Done.
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 && ShouldScheduleConfigurationTask()) {
923 configure_timer_.Start(FROM_HERE,
924 base::TimeDelta::FromMilliseconds(kConfigureDelayMs),
925 this, &DisplayConfigurator::RunPendingConfiguration);
926 }
927 }
928
929 bool DisplayConfigurator::ShouldScheduleConfigurationTask() const {
930 // A task is already scheduled, no need to schedule again.
931 if (configure_timer_.IsRunning())
932 return false;
933
934 if (force_configure_)
935 return true;
936
937 // Schedule if there is a request to change the display state.
938 if (requested_display_state_ != current_display_state_ &&
939 requested_display_state_ != MULTIPLE_DISPLAY_STATE_INVALID)
940 return true;
941
942 // Schedule if there is a request to change the power state.
943 if (current_power_state_ != requested_power_state_)
944 return true;
945
946 return false;
695 } 947 }
696 948
697 void DisplayConfigurator::RestoreRequestedPowerStateAfterResume() { 949 void DisplayConfigurator::RestoreRequestedPowerStateAfterResume() {
698 // Force probing to ensure that we pick up any changes that were made while 950 // Force probing to ensure that we pick up any changes that were made while
699 // the system was suspended. 951 // the system was suspended.
700 SetDisplayPower(requested_power_state_, kSetDisplayPowerForceProbe); 952 SetDisplayPower(requested_power_state_, kSetDisplayPowerForceProbe);
701 } 953 }
702 954
703 void DisplayConfigurator::NotifyObservers( 955 void DisplayConfigurator::NotifyObservers(
704 bool success, 956 bool success,
705 MultipleDisplayState attempted_state) { 957 MultipleDisplayState attempted_state) {
706 if (success) { 958 if (success) {
707 FOR_EACH_OBSERVER( 959 FOR_EACH_OBSERVER(
708 Observer, observers_, OnDisplayModeChanged(cached_displays_)); 960 Observer, observers_, OnDisplayModeChanged(cached_displays_));
709 } else { 961 } else {
710 FOR_EACH_OBSERVER( 962 FOR_EACH_OBSERVER(
711 Observer, observers_, OnDisplayModeChangeFailed(attempted_state)); 963 Observer, observers_, OnDisplayModeChangeFailed(attempted_state));
712 } 964 }
713 } 965 }
714 966
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 967 } // namespace ui
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698