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 | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |