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/update_display_configuration_task.h"
7 #include "ui/display/chromeos/configure_displays_task.h"
8 #include "ui/display/chromeos/display_util.h"
9 #include "ui/display/types/display_snapshot.h"
10 #include "ui/display/types/native_display_delegate.h"
14 UpdateDisplayConfigurationTask::UpdateDisplayConfigurationTask(
15 NativeDisplayDelegate
* delegate
,
16 DisplayConfigurator::DisplayLayoutManager
* layout_manager
,
17 MultipleDisplayState new_display_state
,
18 chromeos::DisplayPowerState new_power_state
,
20 uint32_t background_color_argb
,
22 const ResponseCallback
& callback
)
23 : delegate_(delegate
),
24 layout_manager_(layout_manager
),
25 new_display_state_(new_display_state
),
26 new_power_state_(new_power_state
),
27 power_flags_(power_flags
),
28 background_color_argb_(background_color_argb
),
29 force_configure_(force_configure
),
32 weak_ptr_factory_(this) {
33 delegate_
->GrabServer();
36 UpdateDisplayConfigurationTask::~UpdateDisplayConfigurationTask() {
37 delegate_
->UngrabServer();
40 void UpdateDisplayConfigurationTask::Run() {
41 delegate_
->GetDisplays(
42 base::Bind(&UpdateDisplayConfigurationTask::OnDisplaysUpdated
,
43 weak_ptr_factory_
.GetWeakPtr()));
46 void UpdateDisplayConfigurationTask::OnDisplaysUpdated(
47 const std::vector
<DisplaySnapshot
*>& displays
) {
48 cached_displays_
= displays
;
50 if (cached_displays_
.size() > 1 && background_color_argb_
)
51 delegate_
->SetBackgroundColor(background_color_argb_
);
53 // If the user hasn't requested a display state, update it using the requested
55 if (new_display_state_
== MULTIPLE_DISPLAY_STATE_INVALID
)
56 new_display_state_
= ChooseDisplayState();
58 VLOG(1) << "OnDisplaysUpdated: new_display_state="
59 << MultipleDisplayStateToString(new_display_state_
)
60 << " new_power_state=" << DisplayPowerStateToString(new_power_state_
)
61 << " flags=" << power_flags_
62 << " force_configure=" << force_configure_
63 << " display_count=" << cached_displays_
.size();
64 // If there has been any change in the requested power state and the displays
65 // aren't being turned off force a change in DPMS state.
66 force_dpms_
= ShouldForceDpms() && ShouldConfigure();
68 if (ShouldConfigure()) {
69 EnterState(base::Bind(&UpdateDisplayConfigurationTask::OnStateEntered
,
70 weak_ptr_factory_
.GetWeakPtr()));
72 // If we don't have to configure then we're sticking with the old
73 // configuration. Update it such that it reflects in the reported value.
74 new_power_state_
= layout_manager_
->GetPowerState();
75 FinishConfiguration(true);
79 void UpdateDisplayConfigurationTask::EnterState(
80 const ConfigureDisplaysTask::ResponseCallback
& callback
) {
81 VLOG(2) << "EnterState";
82 std::vector
<DisplayConfigureRequest
> requests
;
83 if (!layout_manager_
->GetDisplayLayout(cached_displays_
, new_display_state_
,
84 new_power_state_
, &requests
,
85 &framebuffer_size_
)) {
86 callback
.Run(ConfigureDisplaysTask::ERROR
);
89 if (!requests
.empty()) {
90 DCHECK(!framebuffer_size_
.IsEmpty());
91 delegate_
->CreateFrameBuffer(framebuffer_size_
);
92 configure_task_
.reset(
93 new ConfigureDisplaysTask(delegate_
, requests
, callback
));
94 configure_task_
->Run();
96 VLOG(2) << "No displays";
97 callback
.Run(ConfigureDisplaysTask::SUCCESS
);
101 void UpdateDisplayConfigurationTask::OnStateEntered(
102 ConfigureDisplaysTask::Status status
) {
103 bool success
= status
!= ConfigureDisplaysTask::ERROR
;
104 if (new_display_state_
== MULTIPLE_DISPLAY_STATE_DUAL_MIRROR
&&
105 status
== ConfigureDisplaysTask::PARTIAL_SUCCESS
)
108 if (layout_manager_
->GetSoftwareMirroringController()) {
109 bool enable_software_mirroring
= false;
110 if (!success
&& new_display_state_
== MULTIPLE_DISPLAY_STATE_DUAL_MIRROR
) {
111 if (layout_manager_
->GetDisplayState() !=
112 MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED
||
113 layout_manager_
->GetPowerState() != new_power_state_
) {
114 new_display_state_
= MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED
;
115 EnterState(base::Bind(
116 &UpdateDisplayConfigurationTask::OnEnableSoftwareMirroring
,
117 weak_ptr_factory_
.GetWeakPtr()));
121 success
= layout_manager_
->GetDisplayState() ==
122 MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED
;
123 enable_software_mirroring
= success
;
125 new_display_state_
= MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED
;
128 layout_manager_
->GetSoftwareMirroringController()->SetSoftwareMirroring(
129 enable_software_mirroring
);
132 FinishConfiguration(success
);
135 void UpdateDisplayConfigurationTask::OnEnableSoftwareMirroring(
136 ConfigureDisplaysTask::Status status
) {
137 bool success
= status
!= ConfigureDisplaysTask::ERROR
;
138 layout_manager_
->GetSoftwareMirroringController()->SetSoftwareMirroring(
140 FinishConfiguration(success
);
143 void UpdateDisplayConfigurationTask::FinishConfiguration(bool success
) {
144 if (success
&& force_dpms_
)
145 delegate_
->ForceDPMSOn();
147 callback_
.Run(success
, cached_displays_
, framebuffer_size_
,
148 new_display_state_
, new_power_state_
);
151 bool UpdateDisplayConfigurationTask::ShouldForceDpms() const {
152 return new_power_state_
!= chromeos::DISPLAY_POWER_ALL_OFF
&&
153 (layout_manager_
->GetPowerState() != new_power_state_
||
154 (power_flags_
& DisplayConfigurator::kSetDisplayPowerForceProbe
));
157 bool UpdateDisplayConfigurationTask::ShouldConfigure() const {
158 if (force_configure_
)
161 if (cached_displays_
.size() == 1 &&
162 cached_displays_
[0]->type() == DISPLAY_CONNECTION_TYPE_INTERNAL
)
166 DisplayConfigurator::kSetDisplayPowerOnlyIfSingleInternalDisplay
))
169 if (new_display_state_
!= layout_manager_
->GetDisplayState())
175 MultipleDisplayState
UpdateDisplayConfigurationTask::ChooseDisplayState()
177 int num_on_displays
=
178 GetDisplayPower(cached_displays_
, new_power_state_
, NULL
);
179 switch (cached_displays_
.size()) {
181 return MULTIPLE_DISPLAY_STATE_HEADLESS
;
183 return MULTIPLE_DISPLAY_STATE_SINGLE
;
185 if (num_on_displays
== 1) {
186 // If only one display is currently turned on, return the "single"
187 // state so that its native mode will be used.
188 return MULTIPLE_DISPLAY_STATE_SINGLE
;
190 if (num_on_displays
>= 3) {
191 return MULTIPLE_DISPLAY_STATE_MULTI_EXTENDED
;
192 } else if (cached_displays_
.size() == 2) {
193 if (!layout_manager_
->GetStateController())
194 return MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED
;
195 // With either both displays on or both displays off, use one of the
197 std::vector
<int64_t> display_ids
;
198 for (size_t i
= 0; i
< cached_displays_
.size(); ++i
)
199 display_ids
.push_back(cached_displays_
[i
]->display_id());
201 return layout_manager_
->GetStateController()->GetStateForDisplayIds(
207 return MULTIPLE_DISPLAY_STATE_INVALID
;