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
3 // found in the LICENSE file.
5 #include "ui/display/chromeos/display_configurator.h"
8 #include "base/command_line.h"
9 #include "base/logging.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "base/strings/stringprintf.h"
12 #include "base/sys_info.h"
13 #include "base/time/time.h"
14 #include "ui/display/display_switches.h"
15 #include "ui/display/types/display_mode.h"
16 #include "ui/display/types/display_snapshot.h"
17 #include "ui/display/types/native_display_delegate.h"
23 typedef std::vector
<const DisplayMode
*> DisplayModeList
;
25 // The delay to perform configuration after RRNotify. See the comment for
26 // |configure_timer_|.
27 const int kConfigureDelayMs
= 500;
29 // The delay spent before reading the display configuration after coming out of
30 // suspend. While coming out of suspend the display state may be updating. This
31 // is used to wait until the hardware had a chance to update the display state
32 // such that we read an up to date state.
33 const int kResumeDelayMs
= 500;
35 // Returns a string describing |state|.
36 std::string
DisplayPowerStateToString(chromeos::DisplayPowerState state
) {
38 case chromeos::DISPLAY_POWER_ALL_ON
:
40 case chromeos::DISPLAY_POWER_ALL_OFF
:
42 case chromeos::DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON
:
43 return "INTERNAL_OFF_EXTERNAL_ON";
44 case chromeos::DISPLAY_POWER_INTERNAL_ON_EXTERNAL_OFF
:
45 return "INTERNAL_ON_EXTERNAL_OFF";
47 return "unknown (" + base::IntToString(state
) + ")";
51 // Returns a string describing |state|.
52 std::string
DisplayStateToString(MultipleDisplayState state
) {
54 case MULTIPLE_DISPLAY_STATE_INVALID
:
56 case MULTIPLE_DISPLAY_STATE_HEADLESS
:
58 case MULTIPLE_DISPLAY_STATE_SINGLE
:
60 case MULTIPLE_DISPLAY_STATE_DUAL_MIRROR
:
62 case MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED
:
63 return "DUAL_EXTENDED";
65 NOTREACHED() << "Unknown state " << state
;
69 // Returns the number of displays in |displays| that should be turned on, per
70 // |state|. If |display_power| is non-NULL, it is updated to contain the
71 // on/off state of each corresponding entry in |displays|.
73 const std::vector
<DisplayConfigurator::DisplayState
>& display_states
,
74 chromeos::DisplayPowerState state
,
75 std::vector
<bool>* display_power
) {
76 int num_on_displays
= 0;
78 display_power
->resize(display_states
.size());
80 for (size_t i
= 0; i
< display_states
.size(); ++i
) {
82 display_states
[i
].display
->type() == DISPLAY_CONNECTION_TYPE_INTERNAL
;
84 state
== chromeos::DISPLAY_POWER_ALL_ON
||
85 (state
== chromeos::DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON
&&
87 (state
== chromeos::DISPLAY_POWER_INTERNAL_ON_EXTERNAL_OFF
&& internal
);
89 (*display_power
)[i
] = on
;
93 return num_on_displays
;
99 const int DisplayConfigurator::kSetDisplayPowerNoFlags
= 0;
100 const int DisplayConfigurator::kSetDisplayPowerForceProbe
= 1 << 0;
102 DisplayConfigurator::kSetDisplayPowerOnlyIfSingleInternalDisplay
= 1 << 1;
104 DisplayConfigurator::DisplayState::DisplayState()
109 bool DisplayConfigurator::TestApi::TriggerConfigureTimeout() {
110 if (configurator_
->configure_timer_
.IsRunning()) {
111 configurator_
->configure_timer_
.user_task().Run();
112 configurator_
->configure_timer_
.Stop();
120 const DisplayMode
* DisplayConfigurator::FindDisplayModeMatchingSize(
121 const DisplaySnapshot
& display
,
122 const gfx::Size
& size
) {
123 const DisplayMode
* best_mode
= NULL
;
124 for (DisplayModeList::const_iterator it
= display
.modes().begin();
125 it
!= display
.modes().end();
127 const DisplayMode
* mode
= *it
;
129 if (mode
->size() != size
)
132 if (mode
== display
.native_mode()) {
142 if (mode
->is_interlaced()) {
143 if (!best_mode
->is_interlaced())
146 // Reset the best rate if the non interlaced is
147 // found the first time.
148 if (best_mode
->is_interlaced()) {
153 if (mode
->refresh_rate() < best_mode
->refresh_rate())
162 DisplayConfigurator::DisplayConfigurator()
163 : state_controller_(NULL
),
164 mirroring_controller_(NULL
),
165 is_panel_fitting_enabled_(false),
166 configure_display_(base::SysInfo::IsRunningOnChromeOS()),
167 display_state_(MULTIPLE_DISPLAY_STATE_INVALID
),
168 requested_power_state_(chromeos::DISPLAY_POWER_ALL_ON
),
169 current_power_state_(chromeos::DISPLAY_POWER_ALL_ON
),
170 next_display_protection_client_id_(1) {}
172 DisplayConfigurator::~DisplayConfigurator() {
173 if (native_display_delegate_
)
174 native_display_delegate_
->RemoveObserver(this);
177 void DisplayConfigurator::SetDelegateForTesting(
178 scoped_ptr
<NativeDisplayDelegate
> display_delegate
) {
179 DCHECK(!native_display_delegate_
);
181 native_display_delegate_
= display_delegate
.Pass();
182 configure_display_
= true;
185 void DisplayConfigurator::SetInitialDisplayPower(
186 chromeos::DisplayPowerState power_state
) {
187 DCHECK_EQ(display_state_
, MULTIPLE_DISPLAY_STATE_INVALID
);
188 requested_power_state_
= current_power_state_
= power_state
;
191 void DisplayConfigurator::Init(bool is_panel_fitting_enabled
) {
192 is_panel_fitting_enabled_
= is_panel_fitting_enabled
;
193 if (!configure_display_
)
196 // If the delegate is already initialized don't update it (For example, tests
197 // set their own delegates).
198 if (!native_display_delegate_
) {
199 native_display_delegate_
= CreatePlatformNativeDisplayDelegate();
200 native_display_delegate_
->AddObserver(this);
204 void DisplayConfigurator::ForceInitialConfigure(
205 uint32_t background_color_argb
) {
206 if (!configure_display_
)
209 native_display_delegate_
->GrabServer();
210 native_display_delegate_
->Initialize();
212 UpdateCachedDisplays();
213 if (cached_displays_
.size() > 1 && background_color_argb
)
214 native_display_delegate_
->SetBackgroundColor(background_color_argb
);
215 const MultipleDisplayState new_state
= ChooseDisplayState(
216 requested_power_state_
);
217 const bool success
= EnterStateOrFallBackToSoftwareMirroring(
218 new_state
, requested_power_state_
);
220 // Force the DPMS on chrome startup as the driver doesn't always detect
221 // that all displays are on when signing out.
222 native_display_delegate_
->ForceDPMSOn();
223 native_display_delegate_
->UngrabServer();
224 NotifyObservers(success
, new_state
);
227 bool DisplayConfigurator::IsMirroring() const {
228 return display_state_
== MULTIPLE_DISPLAY_STATE_DUAL_MIRROR
||
229 (mirroring_controller_
&&
230 mirroring_controller_
->SoftwareMirroringEnabled());
233 bool DisplayConfigurator::ApplyProtections(const ContentProtections
& requests
) {
234 for (DisplayStateList::const_iterator it
= cached_displays_
.begin();
235 it
!= cached_displays_
.end();
237 uint32_t all_desired
= 0;
239 // In mirror mode, protection request of all displays need to be fulfilled.
240 // In non-mirror mode, only request of client's display needs to be
242 ContentProtections::const_iterator request_it
;
244 for (request_it
= requests
.begin();
245 request_it
!= requests
.end();
247 all_desired
|= request_it
->second
;
249 request_it
= requests
.find(it
->display
->display_id());
250 if (request_it
!= requests
.end())
251 all_desired
= request_it
->second
;
254 switch (it
->display
->type()) {
255 case DISPLAY_CONNECTION_TYPE_UNKNOWN
:
257 // DisplayPort, DVI, and HDMI all support HDCP.
258 case DISPLAY_CONNECTION_TYPE_DISPLAYPORT
:
259 case DISPLAY_CONNECTION_TYPE_DVI
:
260 case DISPLAY_CONNECTION_TYPE_HDMI
: {
261 HDCPState current_state
;
262 // Need to poll the driver for updates since other applications may
263 // have updated the state.
264 if (!native_display_delegate_
->GetHDCPState(*it
->display
,
267 bool current_desired
= (current_state
!= HDCP_STATE_UNDESIRED
);
268 bool new_desired
= (all_desired
& CONTENT_PROTECTION_METHOD_HDCP
);
269 // Don't enable again if HDCP is already active. Some buggy drivers
270 // may disable and enable if setting "desired" in active state.
271 if (current_desired
!= new_desired
) {
272 HDCPState new_state
=
273 new_desired
? HDCP_STATE_DESIRED
: HDCP_STATE_UNDESIRED
;
274 if (!native_display_delegate_
->SetHDCPState(*it
->display
, new_state
))
279 case DISPLAY_CONNECTION_TYPE_INTERNAL
:
280 case DISPLAY_CONNECTION_TYPE_VGA
:
281 case DISPLAY_CONNECTION_TYPE_NETWORK
:
282 // No protections for these types. Do nothing.
284 case DISPLAY_CONNECTION_TYPE_NONE
:
293 DisplayConfigurator::ContentProtectionClientId
294 DisplayConfigurator::RegisterContentProtectionClient() {
295 if (!configure_display_
)
296 return kInvalidClientId
;
298 return next_display_protection_client_id_
++;
301 void DisplayConfigurator::UnregisterContentProtectionClient(
302 ContentProtectionClientId client_id
) {
303 client_protection_requests_
.erase(client_id
);
305 ContentProtections protections
;
306 for (ProtectionRequests::const_iterator it
=
307 client_protection_requests_
.begin();
308 it
!= client_protection_requests_
.end();
310 for (ContentProtections::const_iterator it2
= it
->second
.begin();
311 it2
!= it
->second
.end();
313 protections
[it2
->first
] |= it2
->second
;
317 ApplyProtections(protections
);
320 bool DisplayConfigurator::QueryContentProtectionStatus(
321 ContentProtectionClientId client_id
,
324 uint32_t* protection_mask
) {
325 if (!configure_display_
)
328 uint32_t enabled
= 0;
329 uint32_t unfulfilled
= 0;
331 for (DisplayStateList::const_iterator it
= cached_displays_
.begin();
332 it
!= cached_displays_
.end();
334 // Query display if it is in mirror mode or client on the same display.
335 if (!IsMirroring() && it
->display
->display_id() != display_id
)
338 *link_mask
|= it
->display
->type();
339 switch (it
->display
->type()) {
340 case DISPLAY_CONNECTION_TYPE_UNKNOWN
:
342 // DisplayPort, DVI, and HDMI all support HDCP.
343 case DISPLAY_CONNECTION_TYPE_DISPLAYPORT
:
344 case DISPLAY_CONNECTION_TYPE_DVI
:
345 case DISPLAY_CONNECTION_TYPE_HDMI
: {
347 if (!native_display_delegate_
->GetHDCPState(*it
->display
, &state
))
349 if (state
== HDCP_STATE_ENABLED
)
350 enabled
|= CONTENT_PROTECTION_METHOD_HDCP
;
352 unfulfilled
|= CONTENT_PROTECTION_METHOD_HDCP
;
355 case DISPLAY_CONNECTION_TYPE_INTERNAL
:
356 case DISPLAY_CONNECTION_TYPE_VGA
:
357 case DISPLAY_CONNECTION_TYPE_NETWORK
:
358 // No protections for these types. Do nothing.
360 case DISPLAY_CONNECTION_TYPE_NONE
:
366 // Don't reveal protections requested by other clients.
367 ProtectionRequests::iterator it
= client_protection_requests_
.find(client_id
);
368 if (it
!= client_protection_requests_
.end()) {
369 uint32_t requested_mask
= 0;
370 if (it
->second
.find(display_id
) != it
->second
.end())
371 requested_mask
= it
->second
[display_id
];
372 *protection_mask
= enabled
& ~unfulfilled
& requested_mask
;
374 *protection_mask
= 0;
379 bool DisplayConfigurator::EnableContentProtection(
380 ContentProtectionClientId client_id
,
382 uint32_t desired_method_mask
) {
383 if (!configure_display_
)
386 ContentProtections protections
;
387 for (ProtectionRequests::const_iterator it
=
388 client_protection_requests_
.begin();
389 it
!= client_protection_requests_
.end();
391 for (ContentProtections::const_iterator it2
= it
->second
.begin();
392 it2
!= it
->second
.end();
394 if (it
->first
== client_id
&& it2
->first
== display_id
)
396 protections
[it2
->first
] |= it2
->second
;
399 protections
[display_id
] |= desired_method_mask
;
401 if (!ApplyProtections(protections
))
404 if (desired_method_mask
== CONTENT_PROTECTION_METHOD_NONE
) {
405 if (client_protection_requests_
.find(client_id
) !=
406 client_protection_requests_
.end()) {
407 client_protection_requests_
[client_id
].erase(display_id
);
408 if (client_protection_requests_
[client_id
].size() == 0)
409 client_protection_requests_
.erase(client_id
);
412 client_protection_requests_
[client_id
][display_id
] = desired_method_mask
;
418 std::vector
<ui::ColorCalibrationProfile
>
419 DisplayConfigurator::GetAvailableColorCalibrationProfiles(int64_t display_id
) {
420 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
421 switches::kDisableDisplayColorCalibration
)) {
422 for (size_t i
= 0; i
< cached_displays_
.size(); ++i
) {
423 if (cached_displays_
[i
].display
&&
424 cached_displays_
[i
].display
->display_id() == display_id
) {
425 return native_display_delegate_
->GetAvailableColorCalibrationProfiles(
426 *cached_displays_
[i
].display
);
431 return std::vector
<ui::ColorCalibrationProfile
>();
434 bool DisplayConfigurator::SetColorCalibrationProfile(
436 ui::ColorCalibrationProfile new_profile
) {
437 for (size_t i
= 0; i
< cached_displays_
.size(); ++i
) {
438 if (cached_displays_
[i
].display
&&
439 cached_displays_
[i
].display
->display_id() == display_id
) {
440 return native_display_delegate_
->SetColorCalibrationProfile(
441 *cached_displays_
[i
].display
, new_profile
);
448 void DisplayConfigurator::PrepareForExit() {
449 configure_display_
= false;
452 bool DisplayConfigurator::SetDisplayPower(
453 chromeos::DisplayPowerState power_state
,
455 if (!configure_display_
)
458 VLOG(1) << "SetDisplayPower: power_state="
459 << DisplayPowerStateToString(power_state
) << " flags=" << flags
460 << ", configure timer="
461 << (configure_timer_
.IsRunning() ? "Running" : "Stopped");
462 if (power_state
== current_power_state_
&&
463 !(flags
& kSetDisplayPowerForceProbe
))
466 native_display_delegate_
->GrabServer();
467 UpdateCachedDisplays();
469 const MultipleDisplayState new_state
= ChooseDisplayState(power_state
);
470 bool attempted_change
= false;
471 bool success
= false;
473 bool only_if_single_internal_display
=
474 flags
& kSetDisplayPowerOnlyIfSingleInternalDisplay
;
475 bool single_internal_display
=
476 cached_displays_
.size() == 1 &&
477 cached_displays_
[0].display
->type() == DISPLAY_CONNECTION_TYPE_INTERNAL
;
478 if (single_internal_display
|| !only_if_single_internal_display
) {
479 success
= EnterStateOrFallBackToSoftwareMirroring(new_state
, power_state
);
480 attempted_change
= true;
482 // Force the DPMS on since the driver doesn't always detect that it
483 // should turn on. This is needed when coming back from idle suspend.
484 if (success
&& power_state
!= chromeos::DISPLAY_POWER_ALL_OFF
)
485 native_display_delegate_
->ForceDPMSOn();
488 native_display_delegate_
->UngrabServer();
489 if (attempted_change
)
490 NotifyObservers(success
, new_state
);
494 bool DisplayConfigurator::SetDisplayMode(MultipleDisplayState new_state
) {
495 if (!configure_display_
)
498 VLOG(1) << "SetDisplayMode: state=" << DisplayStateToString(new_state
);
499 if (display_state_
== new_state
) {
500 // Cancel software mirroring if the state is moving from
501 // MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED to
502 // MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED.
503 if (mirroring_controller_
&&
504 new_state
== MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED
)
505 mirroring_controller_
->SetSoftwareMirroring(false);
506 NotifyObservers(true, new_state
);
510 native_display_delegate_
->GrabServer();
511 UpdateCachedDisplays();
512 const bool success
= EnterStateOrFallBackToSoftwareMirroring(
513 new_state
, requested_power_state_
);
514 native_display_delegate_
->UngrabServer();
516 NotifyObservers(success
, new_state
);
520 void DisplayConfigurator::OnConfigurationChanged() {
521 // Configure displays with |kConfigureDelayMs| delay,
522 // so that time-consuming ConfigureDisplays() won't be called multiple times.
523 if (configure_timer_
.IsRunning()) {
524 // Note: when the timer is running it is possible that a different task
525 // (RestoreRequestedPowerStateAfterResume()) is scheduled. In these cases,
526 // prefer the already scheduled task to ConfigureDisplays() since
527 // ConfigureDisplays() performs only basic configuration while
528 // RestoreRequestedPowerStateAfterResume() will perform additional
530 configure_timer_
.Reset();
532 configure_timer_
.Start(
534 base::TimeDelta::FromMilliseconds(kConfigureDelayMs
),
536 &DisplayConfigurator::ConfigureDisplays
);
540 void DisplayConfigurator::AddObserver(Observer
* observer
) {
541 observers_
.AddObserver(observer
);
544 void DisplayConfigurator::RemoveObserver(Observer
* observer
) {
545 observers_
.RemoveObserver(observer
);
548 void DisplayConfigurator::SuspendDisplays() {
549 // If the display is off due to user inactivity and there's only a single
550 // internal display connected, switch to the all-on state before
551 // suspending. This shouldn't be very noticeable to the user since the
552 // backlight is off at this point, and doing this lets us resume directly
553 // into the "on" state, which greatly reduces resume times.
554 if (requested_power_state_
== chromeos::DISPLAY_POWER_ALL_OFF
) {
555 SetDisplayPower(chromeos::DISPLAY_POWER_ALL_ON
,
556 kSetDisplayPowerOnlyIfSingleInternalDisplay
);
558 // We need to make sure that the monitor configuration we just did actually
559 // completes before we return, because otherwise the X message could be
560 // racing with the HandleSuspendReadiness message.
561 native_display_delegate_
->SyncWithServer();
565 void DisplayConfigurator::ResumeDisplays() {
566 configure_timer_
.Start(
568 base::TimeDelta::FromMilliseconds(kResumeDelayMs
),
569 base::Bind(&DisplayConfigurator::RestoreRequestedPowerStateAfterResume
,
570 base::Unretained(this)));
573 void DisplayConfigurator::UpdateCachedDisplays() {
574 std::vector
<DisplaySnapshot
*> snapshots
=
575 native_display_delegate_
->GetDisplays();
577 cached_displays_
.clear();
578 for (size_t i
= 0; i
< snapshots
.size(); ++i
) {
579 DisplayState display_state
;
580 display_state
.display
= snapshots
[i
];
581 cached_displays_
.push_back(display_state
);
584 // Set |selected_mode| fields.
585 for (size_t i
= 0; i
< cached_displays_
.size(); ++i
) {
586 DisplayState
* display_state
= &cached_displays_
[i
];
588 if (state_controller_
&&
589 state_controller_
->GetResolutionForDisplayId(
590 display_state
->display
->display_id(), &size
)) {
591 display_state
->selected_mode
=
592 FindDisplayModeMatchingSize(*display_state
->display
, size
);
595 // Fall back to native mode.
596 if (!display_state
->selected_mode
)
597 display_state
->selected_mode
= display_state
->display
->native_mode();
600 // Set |mirror_mode| fields.
601 if (cached_displays_
.size() == 2) {
602 bool one_is_internal
=
603 cached_displays_
[0].display
->type() == DISPLAY_CONNECTION_TYPE_INTERNAL
;
604 bool two_is_internal
=
605 cached_displays_
[1].display
->type() == DISPLAY_CONNECTION_TYPE_INTERNAL
;
606 int internal_displays
=
607 (one_is_internal
? 1 : 0) + (two_is_internal
? 1 : 0);
608 DCHECK_LT(internal_displays
, 2);
609 LOG_IF(WARNING
, internal_displays
== 2)
610 << "Two internal displays detected.";
612 bool can_mirror
= false;
613 for (int attempt
= 0; !can_mirror
&& attempt
< 2; ++attempt
) {
614 // Try preserving external display's aspect ratio on the first attempt.
615 // If that fails, fall back to the highest matching resolution.
616 bool preserve_aspect
= attempt
== 0;
618 if (internal_displays
== 1) {
619 if (one_is_internal
) {
620 can_mirror
= FindMirrorMode(&cached_displays_
[0],
621 &cached_displays_
[1],
622 is_panel_fitting_enabled_
,
625 DCHECK(two_is_internal
);
626 can_mirror
= FindMirrorMode(&cached_displays_
[1],
627 &cached_displays_
[0],
628 is_panel_fitting_enabled_
,
631 } else { // if (internal_displays == 0)
632 // No panel fitting for external displays, so fall back to exact match.
633 can_mirror
= FindMirrorMode(
634 &cached_displays_
[0], &cached_displays_
[1], false, preserve_aspect
);
635 if (!can_mirror
&& preserve_aspect
) {
636 // FindMirrorMode() will try to preserve aspect ratio of what it
637 // thinks is external display, so if it didn't succeed with one, maybe
638 // it will succeed with the other. This way we will have the correct
639 // aspect ratio on at least one of them.
640 can_mirror
= FindMirrorMode(&cached_displays_
[1],
641 &cached_displays_
[0],
650 bool DisplayConfigurator::FindMirrorMode(DisplayState
* internal_display
,
651 DisplayState
* external_display
,
652 bool try_panel_fitting
,
653 bool preserve_aspect
) {
654 const DisplayMode
* internal_native_info
=
655 internal_display
->display
->native_mode();
656 const DisplayMode
* external_native_info
=
657 external_display
->display
->native_mode();
658 if (!internal_native_info
|| !external_native_info
)
661 // Check if some external display resolution can be mirrored on internal.
662 // Prefer the modes in the order they're present in DisplaySnapshot, assuming
663 // this is the order in which they look better on the monitor.
664 for (DisplayModeList::const_iterator external_it
=
665 external_display
->display
->modes().begin();
666 external_it
!= external_display
->display
->modes().end();
668 const DisplayMode
& external_info
= **external_it
;
669 bool is_native_aspect_ratio
=
670 external_native_info
->size().width() * external_info
.size().height() ==
671 external_native_info
->size().height() * external_info
.size().width();
672 if (preserve_aspect
&& !is_native_aspect_ratio
)
673 continue; // Allow only aspect ratio preserving modes for mirroring.
675 // Try finding an exact match.
676 for (DisplayModeList::const_iterator internal_it
=
677 internal_display
->display
->modes().begin();
678 internal_it
!= internal_display
->display
->modes().end();
680 const DisplayMode
& internal_info
= **internal_it
;
681 if (internal_info
.size().width() == external_info
.size().width() &&
682 internal_info
.size().height() == external_info
.size().height() &&
683 internal_info
.is_interlaced() == external_info
.is_interlaced()) {
684 internal_display
->mirror_mode
= *internal_it
;
685 external_display
->mirror_mode
= *external_it
;
686 return true; // Mirror mode found.
690 // Try to create a matching internal display mode by panel fitting.
691 if (try_panel_fitting
) {
692 // We can downscale by 1.125, and upscale indefinitely. Downscaling looks
693 // ugly, so, can fit == can upscale. Also, internal panels don't support
694 // fitting interlaced modes.
695 bool can_fit
= internal_native_info
->size().width() >=
696 external_info
.size().width() &&
697 internal_native_info
->size().height() >=
698 external_info
.size().height() &&
699 !external_info
.is_interlaced();
701 native_display_delegate_
->AddMode(*internal_display
->display
,
703 internal_display
->display
->add_mode(*external_it
);
704 internal_display
->mirror_mode
= *external_it
;
705 external_display
->mirror_mode
= *external_it
;
706 return true; // Mirror mode created.
714 void DisplayConfigurator::ConfigureDisplays() {
715 if (!configure_display_
)
718 native_display_delegate_
->GrabServer();
719 UpdateCachedDisplays();
720 const MultipleDisplayState new_state
= ChooseDisplayState(
721 requested_power_state_
);
722 const bool success
= EnterStateOrFallBackToSoftwareMirroring(
723 new_state
, requested_power_state_
);
724 native_display_delegate_
->UngrabServer();
726 NotifyObservers(success
, new_state
);
729 void DisplayConfigurator::RestoreRequestedPowerStateAfterResume() {
730 // Force probing to ensure that we pick up any changes that were made while
731 // the system was suspended.
732 SetDisplayPower(requested_power_state_
, kSetDisplayPowerForceProbe
);
735 void DisplayConfigurator::NotifyObservers(
737 MultipleDisplayState attempted_state
) {
740 Observer
, observers_
, OnDisplayModeChanged(cached_displays_
));
743 Observer
, observers_
, OnDisplayModeChangeFailed(attempted_state
));
747 bool DisplayConfigurator::EnterStateOrFallBackToSoftwareMirroring(
748 MultipleDisplayState display_state
,
749 chromeos::DisplayPowerState power_state
) {
750 bool success
= EnterState(display_state
, power_state
);
751 if (mirroring_controller_
) {
752 bool enable_software_mirroring
= false;
753 if (!success
&& display_state
== MULTIPLE_DISPLAY_STATE_DUAL_MIRROR
) {
754 if (display_state_
!= MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED
||
755 current_power_state_
!= power_state
)
756 EnterState(MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED
, power_state
);
757 enable_software_mirroring
= success
=
758 display_state_
== MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED
;
760 mirroring_controller_
->SetSoftwareMirroring(enable_software_mirroring
);
765 bool DisplayConfigurator::EnterState(MultipleDisplayState display_state
,
766 chromeos::DisplayPowerState power_state
) {
767 std::vector
<bool> display_power
;
768 int num_on_displays
=
769 GetDisplayPower(cached_displays_
, power_state
, &display_power
);
770 VLOG(1) << "EnterState: display=" << DisplayStateToString(display_state
)
771 << " power=" << DisplayPowerStateToString(power_state
);
773 // Save the requested state so we'll try to use it next time even if we fail.
774 requested_power_state_
= power_state
;
776 // Framebuffer dimensions.
779 std::vector
<gfx::Point
> new_origins(cached_displays_
.size(), gfx::Point());
780 std::vector
<const DisplayMode
*> new_mode
;
781 for (size_t i
= 0; i
< cached_displays_
.size(); ++i
)
782 new_mode
.push_back(cached_displays_
[i
].display
->current_mode());
784 switch (display_state
) {
785 case MULTIPLE_DISPLAY_STATE_INVALID
:
786 NOTREACHED() << "Ignoring request to enter invalid state with "
787 << cached_displays_
.size() << " connected display(s)";
789 case MULTIPLE_DISPLAY_STATE_HEADLESS
:
790 if (cached_displays_
.size() != 0) {
791 LOG(WARNING
) << "Ignoring request to enter headless mode with "
792 << cached_displays_
.size() << " connected display(s)";
796 case MULTIPLE_DISPLAY_STATE_SINGLE
: {
797 // If there are multiple displays connected, only one should be turned on.
798 if (cached_displays_
.size() != 1 && num_on_displays
!= 1) {
799 LOG(WARNING
) << "Ignoring request to enter single mode with "
800 << cached_displays_
.size() << " connected displays and "
801 << num_on_displays
<< " turned on";
805 for (size_t i
= 0; i
< cached_displays_
.size(); ++i
) {
806 DisplayState
* state
= &cached_displays_
[i
];
807 new_mode
[i
] = display_power
[i
] ? state
->selected_mode
: NULL
;
809 if (display_power
[i
] || cached_displays_
.size() == 1) {
810 const DisplayMode
* mode_info
= state
->selected_mode
;
812 LOG(WARNING
) << "No selected mode when configuring display: "
813 << state
->display
->ToString();
816 if (mode_info
->size() == gfx::Size(1024, 768)) {
817 VLOG(1) << "Potentially misdetecting display(1024x768):"
818 << " displays size=" << cached_displays_
.size()
819 << ", num_on_displays=" << num_on_displays
820 << ", current size:" << size
.width() << "x" << size
.height()
821 << ", i=" << i
<< ", display=" << state
->display
->ToString()
822 << ", display_mode=" << mode_info
->ToString();
824 size
= mode_info
->size();
829 case MULTIPLE_DISPLAY_STATE_DUAL_MIRROR
: {
830 if (cached_displays_
.size() != 2 ||
831 (num_on_displays
!= 0 && num_on_displays
!= 2)) {
832 LOG(WARNING
) << "Ignoring request to enter mirrored mode with "
833 << cached_displays_
.size() << " connected display(s) and "
834 << num_on_displays
<< " turned on";
838 const DisplayMode
* mode_info
= cached_displays_
[0].mirror_mode
;
840 LOG(WARNING
) << "No mirror mode when configuring display: "
841 << cached_displays_
[0].display
->ToString();
844 size
= mode_info
->size();
846 for (size_t i
= 0; i
< cached_displays_
.size(); ++i
) {
847 DisplayState
* state
= &cached_displays_
[i
];
848 new_mode
[i
] = display_power
[i
] ? state
->mirror_mode
: NULL
;
852 case MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED
: {
853 if (cached_displays_
.size() != 2 ||
854 (num_on_displays
!= 0 && num_on_displays
!= 2)) {
855 LOG(WARNING
) << "Ignoring request to enter extended mode with "
856 << cached_displays_
.size() << " connected display(s) and "
857 << num_on_displays
<< " turned on";
861 for (size_t i
= 0; i
< cached_displays_
.size(); ++i
) {
862 DisplayState
* state
= &cached_displays_
[i
];
863 new_origins
[i
].set_y(size
.height() ? size
.height() + kVerticalGap
: 0);
864 new_mode
[i
] = display_power
[i
] ? state
->selected_mode
: NULL
;
866 // Retain the full screen size even if all displays are off so the
867 // same desktop configuration can be restored when the displays are
869 const DisplayMode
* mode_info
= cached_displays_
[i
].selected_mode
;
871 LOG(WARNING
) << "No selected mode when configuring display: "
872 << state
->display
->ToString();
876 size
.set_width(std::max
<int>(size
.width(), mode_info
->size().width()));
877 size
.set_height(size
.height() + (size
.height() ? kVerticalGap
: 0) +
878 mode_info
->size().height());
884 // Finally, apply the desired changes.
885 bool all_succeeded
= true;
886 if (!cached_displays_
.empty()) {
887 native_display_delegate_
->CreateFrameBuffer(size
);
888 for (size_t i
= 0; i
< cached_displays_
.size(); ++i
) {
889 const DisplayState
& state
= cached_displays_
[i
];
890 bool configure_succeeded
= false;
893 if (native_display_delegate_
->Configure(
894 *state
.display
, new_mode
[i
], new_origins
[i
])) {
895 state
.display
->set_current_mode(new_mode
[i
]);
896 state
.display
->set_origin(new_origins
[i
]);
898 configure_succeeded
= true;
902 const DisplayMode
* mode_info
= new_mode
[i
];
906 // Find the mode with the next-best resolution and see if that can
908 int best_mode_pixels
= 0;
910 int current_mode_pixels
= mode_info
->size().GetArea();
911 for (DisplayModeList::const_iterator it
=
912 state
.display
->modes().begin();
913 it
!= state
.display
->modes().end();
915 int pixel_count
= (*it
)->size().GetArea();
916 if ((pixel_count
< current_mode_pixels
) &&
917 (pixel_count
> best_mode_pixels
)) {
919 best_mode_pixels
= pixel_count
;
923 if (best_mode_pixels
== 0)
927 if (!configure_succeeded
)
928 all_succeeded
= false;
930 // If we are trying to set mirror mode and one of the modesets fails,
931 // then the two monitors will be mis-matched. In this case, return
932 // false to let the observers be aware.
933 if (display_state
== MULTIPLE_DISPLAY_STATE_DUAL_MIRROR
&&
935 state
.display
->current_mode() != state
.mirror_mode
)
936 all_succeeded
= false;
941 display_state_
= display_state
;
942 current_power_state_
= power_state
;
943 framebuffer_size_
= size
;
945 return all_succeeded
;
948 MultipleDisplayState
DisplayConfigurator::ChooseDisplayState(
949 chromeos::DisplayPowerState power_state
) const {
950 int num_on_displays
= GetDisplayPower(cached_displays_
, power_state
, NULL
);
951 switch (cached_displays_
.size()) {
953 return MULTIPLE_DISPLAY_STATE_HEADLESS
;
955 return MULTIPLE_DISPLAY_STATE_SINGLE
;
957 if (num_on_displays
== 1) {
958 // If only one display is currently turned on, return the "single"
959 // state so that its native mode will be used.
960 return MULTIPLE_DISPLAY_STATE_SINGLE
;
962 if (!state_controller_
)
963 return MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED
;
964 // With either both displays on or both displays off, use one of the
966 std::vector
<int64_t> display_ids
;
967 for (size_t i
= 0; i
< cached_displays_
.size(); ++i
)
968 display_ids
.push_back(cached_displays_
[i
].display
->display_id());
970 return state_controller_
->GetStateForDisplayIds(display_ids
);
976 return MULTIPLE_DISPLAY_STATE_INVALID
;