OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 "chromeos/display/output_configurator.h" | 5 #include "chromeos/display/output_configurator.h" |
6 | 6 |
7 #include <X11/Xlib.h> | 7 #include <X11/Xlib.h> |
8 #include <X11/extensions/Xrandr.h> | 8 #include <X11/extensions/Xrandr.h> |
9 | 9 |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
11 #include "base/chromeos/chromeos_version.h" | 11 #include "base/chromeos/chromeos_version.h" |
12 #include "base/logging.h" | 12 #include "base/logging.h" |
13 #include "base/strings/string_number_conversions.h" | 13 #include "base/strings/string_number_conversions.h" |
14 #include "base/time.h" | 14 #include "base/time.h" |
15 #include "chromeos/dbus/dbus_thread_manager.h" | |
16 #include "chromeos/dbus/power_manager_client.h" | |
17 #include "chromeos/display/real_output_configurator_delegate.h" | 15 #include "chromeos/display/real_output_configurator_delegate.h" |
18 | 16 |
19 namespace chromeos { | 17 namespace chromeos { |
20 | 18 |
21 namespace { | 19 namespace { |
22 | 20 |
23 // Prefixes for the built-in displays. | 21 // Prefixes for the built-in displays. |
24 const char kInternal_LVDS[] = "LVDS"; | 22 const char kInternal_LVDS[] = "LVDS"; |
25 const char kInternal_eDP[] = "eDP"; | 23 const char kInternal_eDP[] = "eDP"; |
26 | 24 |
27 // The delay to perform configuration after RRNotify. See the comment | 25 // The delay to perform configuration after RRNotify. See the comment |
28 // in |Dispatch()|. | 26 // in |Dispatch()|. |
29 const int64 kConfigureDelayMs = 500; | 27 const int64 kConfigureDelayMs = 500; |
30 | 28 |
31 // Gap between screens so cursor at bottom of active display doesn't partially | |
32 // appear on top of inactive display. Higher numbers guard against larger | |
33 // cursors, but also waste more memory. | |
34 // For simplicity, this is hard-coded to 60 to avoid the complexity of always | |
35 // determining the DPI of the screen and rationalizing which screen we need to | |
36 // use for the DPI calculation. | |
37 // See crbug.com/130188 for initial discussion. | |
38 const int kVerticalGap = 60; | |
39 | |
40 // Returns a string describing |state|. | 29 // Returns a string describing |state|. |
41 std::string DisplayPowerStateToString(DisplayPowerState state) { | 30 std::string DisplayPowerStateToString(DisplayPowerState state) { |
42 switch (state) { | 31 switch (state) { |
43 case DISPLAY_POWER_ALL_ON: | 32 case DISPLAY_POWER_ALL_ON: |
44 return "ALL_ON"; | 33 return "ALL_ON"; |
45 case DISPLAY_POWER_ALL_OFF: | 34 case DISPLAY_POWER_ALL_OFF: |
46 return "ALL_OFF"; | 35 return "ALL_OFF"; |
47 case DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON: | 36 case DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON: |
48 return "INTERNAL_OFF_EXTERNAL_ON"; | 37 return "INTERNAL_OFF_EXTERNAL_ON"; |
49 case DISPLAY_POWER_INTERNAL_ON_EXTERNAL_OFF: | 38 case DISPLAY_POWER_INTERNAL_ON_EXTERNAL_OFF: |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
88 // At this point, we expect both displays to be in native mode and tiled | 77 // At this point, we expect both displays to be in native mode and tiled |
89 // such that one is primary and another is correctly positioned as | 78 // such that one is primary and another is correctly positioned as |
90 // secondary. If any of these assumptions are false, this is an unknown | 79 // secondary. If any of these assumptions are false, this is an unknown |
91 // configuration. | 80 // configuration. |
92 bool primary_native = (primary_mode == outputs[0].native_mode) || | 81 bool primary_native = (primary_mode == outputs[0].native_mode) || |
93 (primary_mode == None); | 82 (primary_mode == None); |
94 bool secondary_native = (secondary_mode == outputs[1].native_mode) || | 83 bool secondary_native = (secondary_mode == outputs[1].native_mode) || |
95 (secondary_mode == None); | 84 (secondary_mode == None); |
96 if (primary_native && secondary_native) { | 85 if (primary_native && secondary_native) { |
97 // Just check the relative locations. | 86 // Just check the relative locations. |
98 int secondary_offset = outputs[0].height + kVerticalGap; | 87 int secondary_offset = outputs[0].height + |
88 OutputConfigurator::kVerticalGap; | |
99 if (outputs[0].y == 0 && outputs[1].y == secondary_offset) { | 89 if (outputs[0].y == 0 && outputs[1].y == secondary_offset) { |
100 state = STATE_DUAL_EXTENDED; | 90 state = STATE_DUAL_EXTENDED; |
101 } else { | 91 } else { |
102 // Unexpected locations. | 92 // Unexpected locations. |
103 state = STATE_DUAL_UNKNOWN; | 93 state = STATE_DUAL_UNKNOWN; |
104 } | 94 } |
105 } else { | 95 } else { |
106 // Mode assumptions don't hold. | 96 // Mode assumptions don't hold. |
107 state = STATE_DUAL_UNKNOWN; | 97 state = STATE_DUAL_UNKNOWN; |
108 } | 98 } |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
159 OutputConfigurator::CrtcConfig::CrtcConfig(RRCrtc crtc, | 149 OutputConfigurator::CrtcConfig::CrtcConfig(RRCrtc crtc, |
160 int x, int y, | 150 int x, int y, |
161 RRMode mode, | 151 RRMode mode, |
162 RROutput output) | 152 RROutput output) |
163 : crtc(crtc), | 153 : crtc(crtc), |
164 x(x), | 154 x(x), |
165 y(y), | 155 y(y), |
166 mode(mode), | 156 mode(mode), |
167 output(output) {} | 157 output(output) {} |
168 | 158 |
159 bool OutputConfigurator::TestApi::SendOutputChangeEvents(bool connected) { | |
160 XRRScreenChangeNotifyEvent screen_event; | |
161 memset(&screen_event, 0, sizeof(screen_event)); | |
162 screen_event.type = xrandr_event_base_ + RRScreenChangeNotify; | |
163 configurator_->Dispatch( | |
164 reinterpret_cast<const base::NativeEvent>(&screen_event)); | |
165 | |
166 XRROutputChangeNotifyEvent notify_event; | |
167 memset(¬ify_event, 0, sizeof(notify_event)); | |
168 notify_event.type = xrandr_event_base_ + RRNotify; | |
169 notify_event.subtype = RRNotify_OutputChange; | |
170 notify_event.connection = connected ? RR_Connected : RR_Disconnected; | |
171 configurator_->Dispatch( | |
172 reinterpret_cast<const base::NativeEvent>(¬ify_event)); | |
173 | |
174 if (!configurator_->configure_timer_->IsRunning()) { | |
175 LOG(ERROR) << "ConfigureOutputs() timer not running"; | |
176 return false; | |
177 } | |
178 | |
179 configurator_->ConfigureOutputs(); | |
180 return true; | |
181 } | |
182 | |
169 // static | 183 // static |
170 bool OutputConfigurator::IsInternalOutputName(const std::string& name) { | 184 bool OutputConfigurator::IsInternalOutputName(const std::string& name) { |
171 return name.find(kInternal_LVDS) == 0 || name.find(kInternal_eDP) == 0; | 185 return name.find(kInternal_LVDS) == 0 || name.find(kInternal_eDP) == 0; |
172 } | 186 } |
173 | 187 |
174 OutputConfigurator::OutputConfigurator() | 188 OutputConfigurator::OutputConfigurator() |
175 : state_controller_(NULL), | 189 : state_controller_(NULL), |
176 delegate_(new RealOutputConfiguratorDelegate()), | |
177 configure_display_(base::chromeos::IsRunningOnChromeOS()), | 190 configure_display_(base::chromeos::IsRunningOnChromeOS()), |
178 connected_output_count_(0), | 191 connected_output_count_(0), |
179 xrandr_event_base_(0), | 192 xrandr_event_base_(0), |
180 output_state_(STATE_INVALID), | 193 output_state_(STATE_INVALID), |
181 power_state_(DISPLAY_POWER_ALL_ON) { | 194 power_state_(DISPLAY_POWER_ALL_ON) { |
182 } | 195 } |
183 | 196 |
184 OutputConfigurator::~OutputConfigurator() {} | 197 OutputConfigurator::~OutputConfigurator() {} |
185 | 198 |
199 void OutputConfigurator::SetDelegateForTesting( | |
200 scoped_ptr<Delegate> delegate) { | |
201 delegate_.swap(delegate); | |
oshima
2013/04/08 17:29:15
delegate_ = delegate.Pass();
is more common nowad
Daniel Erat
2013/04/08 21:47:53
Done.
| |
202 configure_display_ = true; | |
203 } | |
204 | |
186 void OutputConfigurator::Init(bool is_panel_fitting_enabled, | 205 void OutputConfigurator::Init(bool is_panel_fitting_enabled, |
187 uint32 background_color_argb) { | 206 uint32 background_color_argb) { |
188 if (!configure_display_) | 207 if (!configure_display_) |
189 return; | 208 return; |
190 | 209 |
210 if (!delegate_) | |
211 delegate_.reset(new RealOutputConfiguratorDelegate()); | |
212 | |
191 // Cache the initial output state. | 213 // Cache the initial output state. |
192 delegate_->SetPanelFittingEnabled(is_panel_fitting_enabled); | 214 delegate_->SetPanelFittingEnabled(is_panel_fitting_enabled); |
193 delegate_->GrabServer(); | 215 delegate_->GrabServer(); |
194 std::vector<OutputSnapshot> outputs = delegate_->GetOutputs(); | 216 std::vector<OutputSnapshot> outputs = delegate_->GetOutputs(); |
195 if (outputs.size() > 1 && background_color_argb) | 217 if (outputs.size() > 1 && background_color_argb) |
196 delegate_->SetBackgroundColor(background_color_argb); | 218 delegate_->SetBackgroundColor(background_color_argb); |
197 delegate_->UngrabServer(); | 219 delegate_->UngrabServer(); |
198 } | 220 } |
199 | 221 |
200 void OutputConfigurator::Start() { | 222 void OutputConfigurator::Start() { |
223 if (!configure_display_) | |
224 return; | |
225 | |
201 delegate_->GrabServer(); | 226 delegate_->GrabServer(); |
202 // Detect our initial state. | |
203 std::vector<OutputSnapshot> outputs = delegate_->GetOutputs(); | 227 std::vector<OutputSnapshot> outputs = delegate_->GetOutputs(); |
204 connected_output_count_ = outputs.size(); | 228 connected_output_count_ = outputs.size(); |
205 | 229 |
206 output_state_ = InferCurrentState(outputs); | 230 output_state_ = InferCurrentState(outputs); |
207 // Ensure that we are in a supported state with all connected displays powered | 231 // Ensure that we are in a supported state with all connected displays powered |
208 // on. | 232 // on. |
209 OutputState starting_state = GetNextState(outputs); | 233 OutputState starting_state = GetNextState(outputs); |
210 if (output_state_ != starting_state && | 234 if (output_state_ != starting_state && |
211 EnterState(starting_state, power_state_, outputs)) { | 235 EnterState(starting_state, power_state_, outputs)) { |
212 output_state_ = starting_state; | 236 output_state_ = starting_state; |
213 } | 237 } |
214 bool is_projecting = IsProjecting(outputs); | 238 bool is_projecting = IsProjecting(outputs); |
215 | 239 |
216 delegate_->InitXRandRExtension(&xrandr_event_base_); | 240 delegate_->InitXRandRExtension(&xrandr_event_base_); |
217 | 241 |
218 // Force the DPMS on chrome startup as the driver doesn't always detect | 242 // Force the DPMS on chrome startup as the driver doesn't always detect |
219 // that all displays are on when signing out. | 243 // that all displays are on when signing out. |
220 delegate_->ForceDPMSOn(); | 244 delegate_->ForceDPMSOn(); |
221 | |
222 // Relinquish X resources. | |
223 delegate_->UngrabServer(); | 245 delegate_->UngrabServer(); |
224 | 246 delegate_->SendProjectingStateToPowerManager(is_projecting); |
225 chromeos::DBusThreadManager::Get()->GetPowerManagerClient()-> | |
226 SetIsProjecting(is_projecting); | |
227 } | 247 } |
228 | 248 |
229 void OutputConfigurator::Stop() { | 249 void OutputConfigurator::Stop() { |
230 configure_display_ = false; | 250 configure_display_ = false; |
231 } | 251 } |
232 | 252 |
233 bool OutputConfigurator::SetDisplayPower(DisplayPowerState power_state, | 253 bool OutputConfigurator::SetDisplayPower(DisplayPowerState power_state, |
234 int flags) { | 254 int flags) { |
255 if (!configure_display_) | |
256 return false; | |
257 | |
235 VLOG(1) << "SetDisplayPower: power_state=" | 258 VLOG(1) << "SetDisplayPower: power_state=" |
236 << DisplayPowerStateToString(power_state) << " flags=" << flags; | 259 << DisplayPowerStateToString(power_state) << " flags=" << flags; |
237 | |
238 if (!configure_display_) | |
239 return false; | |
240 if (power_state == power_state_ && !(flags & kSetDisplayPowerForceProbe)) | 260 if (power_state == power_state_ && !(flags & kSetDisplayPowerForceProbe)) |
241 return true; | 261 return true; |
242 | 262 |
243 delegate_->GrabServer(); | 263 delegate_->GrabServer(); |
244 std::vector<OutputSnapshot> outputs = delegate_->GetOutputs(); | 264 std::vector<OutputSnapshot> outputs = delegate_->GetOutputs(); |
245 connected_output_count_ = outputs.size(); | 265 connected_output_count_ = outputs.size(); |
246 | 266 |
247 bool only_if_single_internal_display = | 267 bool only_if_single_internal_display = |
248 flags & kSetDisplayPowerOnlyIfSingleInternalDisplay; | 268 flags & kSetDisplayPowerOnlyIfSingleInternalDisplay; |
249 bool single_internal_display = outputs.size() == 1 && outputs[0].is_internal; | 269 bool single_internal_display = outputs.size() == 1 && outputs[0].is_internal; |
250 if ((single_internal_display || !only_if_single_internal_display) && | 270 if ((single_internal_display || !only_if_single_internal_display) && |
251 EnterState(output_state_, power_state, outputs)) { | 271 EnterState(output_state_, power_state, outputs)) { |
252 power_state_ = power_state; | 272 power_state_ = power_state; |
253 if (power_state != DISPLAY_POWER_ALL_OFF) { | 273 if (power_state != DISPLAY_POWER_ALL_OFF) { |
254 // Force the DPMS on since the driver doesn't always detect that it | 274 // Force the DPMS on since the driver doesn't always detect that it |
255 // should turn on. This is needed when coming back from idle suspend. | 275 // should turn on. This is needed when coming back from idle suspend. |
256 delegate_->ForceDPMSOn(); | 276 delegate_->ForceDPMSOn(); |
257 } | 277 } |
258 } | 278 } |
259 | 279 |
260 delegate_->UngrabServer(); | 280 delegate_->UngrabServer(); |
261 return true; | 281 return true; |
262 } | 282 } |
263 | 283 |
264 bool OutputConfigurator::SetDisplayMode(OutputState new_state) { | 284 bool OutputConfigurator::SetDisplayMode(OutputState new_state) { |
285 if (!configure_display_) | |
286 return false; | |
287 | |
265 if (output_state_ == STATE_INVALID || | 288 if (output_state_ == STATE_INVALID || |
266 output_state_ == STATE_HEADLESS || | 289 output_state_ == STATE_HEADLESS || |
267 output_state_ == STATE_SINGLE) | 290 output_state_ == STATE_SINGLE) |
268 return false; | 291 return false; |
269 | 292 |
270 if (output_state_ == new_state) | 293 if (output_state_ == new_state) |
271 return true; | 294 return true; |
272 | 295 |
273 delegate_->GrabServer(); | 296 delegate_->GrabServer(); |
274 std::vector<OutputSnapshot> outputs = delegate_->GetOutputs(); | 297 std::vector<OutputSnapshot> outputs = delegate_->GetOutputs(); |
275 connected_output_count_ = outputs.size(); | 298 connected_output_count_ = outputs.size(); |
276 if (EnterState(new_state, power_state_, outputs)) | 299 if (EnterState(new_state, power_state_, outputs)) |
277 output_state_ = new_state; | 300 output_state_ = new_state; |
278 delegate_->UngrabServer(); | 301 delegate_->UngrabServer(); |
279 | 302 |
280 if (output_state_ == new_state) { | 303 if (output_state_ == new_state) { |
281 NotifyOnDisplayChanged(); | 304 NotifyOnDisplayChanged(); |
282 } else { | 305 } else { |
283 FOR_EACH_OBSERVER( | 306 FOR_EACH_OBSERVER( |
284 Observer, observers_, OnDisplayModeChangeFailed(new_state)); | 307 Observer, observers_, OnDisplayModeChangeFailed(new_state)); |
285 } | 308 } |
286 return true; | 309 return true; |
287 } | 310 } |
288 | 311 |
289 bool OutputConfigurator::Dispatch(const base::NativeEvent& event) { | 312 bool OutputConfigurator::Dispatch(const base::NativeEvent& event) { |
290 if (event->type - xrandr_event_base_ == RRScreenChangeNotify) | 313 if (event->type - xrandr_event_base_ == RRScreenChangeNotify) { |
291 delegate_->UpdateXRandRConfiguration(event); | 314 if (delegate_) |
oshima
2013/04/08 17:29:15
This is only place you check if it's NULL. How thi
Daniel Erat
2013/04/08 21:47:53
All of the other members return early on !configur
oshima
2013/04/08 23:21:44
I see. I think it's safe to move after configure_d
Daniel Erat
2013/04/09 00:21:34
Done.
| |
292 // Ignore this event if the Xrandr extension isn't supported, or | 315 delegate_->UpdateXRandRConfiguration(event); |
293 // the device is being shutdown. | |
294 if (!configure_display_ || | |
295 (event->type - xrandr_event_base_ != RRNotify)) { | |
296 return true; | 316 return true; |
297 } | 317 } |
318 | |
319 if (!configure_display_ || event->type - xrandr_event_base_ != RRNotify) | |
320 return true; | |
321 | |
298 XEvent* xevent = static_cast<XEvent*>(event); | 322 XEvent* xevent = static_cast<XEvent*>(event); |
299 XRRNotifyEvent* notify_event = | 323 XRRNotifyEvent* notify_event = |
300 reinterpret_cast<XRRNotifyEvent*>(xevent); | 324 reinterpret_cast<XRRNotifyEvent*>(xevent); |
301 if (notify_event->subtype == RRNotify_OutputChange) { | 325 if (notify_event->subtype == RRNotify_OutputChange) { |
302 XRROutputChangeNotifyEvent* output_change_event = | 326 XRROutputChangeNotifyEvent* output_change_event = |
303 reinterpret_cast<XRROutputChangeNotifyEvent*>(xevent); | 327 reinterpret_cast<XRROutputChangeNotifyEvent*>(xevent); |
304 if ((output_change_event->connection == RR_Connected) || | 328 if ((output_change_event->connection == RR_Connected) || |
305 (output_change_event->connection == RR_Disconnected)) { | 329 (output_change_event->connection == RR_Disconnected)) { |
306 // Connecting/Disconnecting display may generate multiple | 330 // Connecting/Disconnecting display may generate multiple |
307 // RRNotify. Defer configuring outputs to avoid | 331 // RRNotify. Defer configuring outputs to avoid |
308 // grabbing X and configuring displays multiple times. | 332 // grabbing X and configuring displays multiple times. |
309 if (configure_timer_.get()) { | 333 if (configure_timer_.get()) { |
310 configure_timer_->Reset(); | 334 configure_timer_->Reset(); |
311 } else { | 335 } else { |
312 configure_timer_.reset(new base::OneShotTimer<OutputConfigurator>()); | 336 configure_timer_.reset(new base::OneShotTimer<OutputConfigurator>()); |
313 configure_timer_->Start( | 337 configure_timer_->Start( |
314 FROM_HERE, | 338 FROM_HERE, |
315 base::TimeDelta::FromMilliseconds(kConfigureDelayMs), | 339 base::TimeDelta::FromMilliseconds(kConfigureDelayMs), |
316 this, | 340 this, |
317 &OutputConfigurator::ConfigureOutputs); | 341 &OutputConfigurator::ConfigureOutputs); |
318 } | 342 } |
319 } | 343 } |
320 } | 344 } |
321 | 345 |
322 // Ignore the case of RR_UnknownConnection. | 346 // Ignore the case of RR_UnknownConnection. |
323 return true; | 347 return true; |
324 } | 348 } |
325 | 349 |
326 void OutputConfigurator::ConfigureOutputs() { | |
327 configure_timer_.reset(); | |
328 | |
329 delegate_->GrabServer(); | |
330 std::vector<OutputSnapshot> outputs = delegate_->GetOutputs(); | |
331 int new_output_count = outputs.size(); | |
332 // Don't skip even if the output counts didn't change because | |
333 // a display might have been swapped during the suspend. | |
334 connected_output_count_ = new_output_count; | |
335 OutputState new_state = GetNextState(outputs); | |
336 // When a display was swapped, the state moves from | |
337 // STATE_DUAL_EXTENDED to STATE_DUAL_EXTENDED, so don't rely on | |
338 // the state chagne to tell if it was successful. | |
339 bool success = EnterState(new_state, power_state_, outputs); | |
340 bool is_projecting = IsProjecting(outputs); | |
341 delegate_->UngrabServer(); | |
342 | |
343 if (success) { | |
344 output_state_ = new_state; | |
345 NotifyOnDisplayChanged(); | |
346 } else { | |
347 FOR_EACH_OBSERVER( | |
348 Observer, observers_, OnDisplayModeChangeFailed(new_state)); | |
349 } | |
350 chromeos::DBusThreadManager::Get()->GetPowerManagerClient()-> | |
351 SetIsProjecting(is_projecting); | |
352 } | |
353 | |
354 void OutputConfigurator::AddObserver(Observer* observer) { | 350 void OutputConfigurator::AddObserver(Observer* observer) { |
355 observers_.AddObserver(observer); | 351 observers_.AddObserver(observer); |
356 } | 352 } |
357 | 353 |
358 void OutputConfigurator::RemoveObserver(Observer* observer) { | 354 void OutputConfigurator::RemoveObserver(Observer* observer) { |
359 observers_.RemoveObserver(observer); | 355 observers_.RemoveObserver(observer); |
360 } | 356 } |
361 | 357 |
362 void OutputConfigurator::SuspendDisplays() { | 358 void OutputConfigurator::SuspendDisplays() { |
363 // If the display is off due to user inactivity and there's only a single | 359 // If the display is off due to user inactivity and there's only a single |
(...skipping 11 matching lines...) Expand all Loading... | |
375 // racing with the HandleSuspendReadiness message. | 371 // racing with the HandleSuspendReadiness message. |
376 delegate_->SyncWithServer(); | 372 delegate_->SyncWithServer(); |
377 } | 373 } |
378 | 374 |
379 void OutputConfigurator::ResumeDisplays() { | 375 void OutputConfigurator::ResumeDisplays() { |
380 // Force probing to ensure that we pick up any changes that were made | 376 // Force probing to ensure that we pick up any changes that were made |
381 // while the system was suspended. | 377 // while the system was suspended. |
382 SetDisplayPower(power_state_, kSetDisplayPowerForceProbe); | 378 SetDisplayPower(power_state_, kSetDisplayPowerForceProbe); |
383 } | 379 } |
384 | 380 |
381 void OutputConfigurator::ConfigureOutputs() { | |
382 configure_timer_.reset(); | |
383 | |
384 delegate_->GrabServer(); | |
385 std::vector<OutputSnapshot> outputs = delegate_->GetOutputs(); | |
386 int new_output_count = outputs.size(); | |
387 // Don't skip even if the output counts didn't change because | |
388 // a display might have been swapped during the suspend. | |
389 connected_output_count_ = new_output_count; | |
390 OutputState new_state = GetNextState(outputs); | |
391 // When a display was swapped, the state moves from | |
392 // STATE_DUAL_EXTENDED to STATE_DUAL_EXTENDED, so don't rely on | |
393 // the state chagne to tell if it was successful. | |
394 bool success = EnterState(new_state, power_state_, outputs); | |
395 bool is_projecting = IsProjecting(outputs); | |
396 delegate_->UngrabServer(); | |
397 | |
398 if (success) { | |
399 output_state_ = new_state; | |
400 NotifyOnDisplayChanged(); | |
401 } else { | |
402 FOR_EACH_OBSERVER( | |
403 Observer, observers_, OnDisplayModeChangeFailed(new_state)); | |
404 } | |
405 delegate_->SendProjectingStateToPowerManager(is_projecting); | |
406 } | |
407 | |
385 void OutputConfigurator::NotifyOnDisplayChanged() { | 408 void OutputConfigurator::NotifyOnDisplayChanged() { |
386 FOR_EACH_OBSERVER(Observer, observers_, OnDisplayModeChanged()); | 409 FOR_EACH_OBSERVER(Observer, observers_, OnDisplayModeChanged()); |
387 } | 410 } |
388 | 411 |
389 bool OutputConfigurator::EnterState( | 412 bool OutputConfigurator::EnterState( |
390 OutputState output_state, | 413 OutputState output_state, |
391 DisplayPowerState power_state, | 414 DisplayPowerState power_state, |
392 const std::vector<OutputSnapshot>& outputs) { | 415 const std::vector<OutputSnapshot>& outputs) { |
393 std::vector<bool> output_power(outputs.size()); | 416 std::vector<bool> output_power(outputs.size()); |
394 bool all_outputs_off = true; | 417 bool all_outputs_off = true; |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
464 std::vector<CrtcConfig> configs(outputs.size()); | 487 std::vector<CrtcConfig> configs(outputs.size()); |
465 int width = 0, height = 0; | 488 int width = 0, height = 0; |
466 | 489 |
467 for (size_t i = 0; i < outputs.size(); ++i) { | 490 for (size_t i = 0; i < outputs.size(); ++i) { |
468 if (!delegate_->GetModeDetails(outputs[i].native_mode, | 491 if (!delegate_->GetModeDetails(outputs[i].native_mode, |
469 &(mode_sizes[i].first), &(mode_sizes[i].second), NULL)) { | 492 &(mode_sizes[i].first), &(mode_sizes[i].second), NULL)) { |
470 return false; | 493 return false; |
471 } | 494 } |
472 | 495 |
473 configs[i] = CrtcConfig( | 496 configs[i] = CrtcConfig( |
474 outputs[i].crtc, 0, height, | 497 outputs[i].crtc, 0, (height ? height + kVerticalGap : 0), |
475 output_power[i] ? outputs[i].native_mode : None, | 498 output_power[i] ? outputs[i].native_mode : None, |
476 outputs[i].output); | 499 outputs[i].output); |
477 | 500 |
478 // Retain the full screen size if all outputs are off so the same | 501 // Retain the full screen size if all outputs are off so the same |
479 // desktop configuration can be restored when the outputs are | 502 // desktop configuration can be restored when the outputs are |
480 // turned back on. | 503 // turned back on. |
481 if (output_power[i] || all_outputs_off) { | 504 if (output_power[i] || all_outputs_off) { |
482 width = std::max<int>(width, mode_sizes[i].first); | 505 width = std::max<int>(width, mode_sizes[i].first); |
483 height += (height ? kVerticalGap : 0) + mode_sizes[i].second; | 506 height += (height ? kVerticalGap : 0) + mode_sizes[i].second; |
484 } | 507 } |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
562 ctm.y_offset = 0.0; | 585 ctm.y_offset = 0.0; |
563 ctm.x_scale = native_mode_ar / mirror_mode_ar; | 586 ctm.x_scale = native_mode_ar / mirror_mode_ar; |
564 ctm.x_offset = (mirror_mode_ar / native_mode_ar - 1.0) * 0.5; | 587 ctm.x_offset = (mirror_mode_ar / native_mode_ar - 1.0) * 0.5; |
565 return ctm; | 588 return ctm; |
566 } | 589 } |
567 | 590 |
568 return ctm; // Same aspect ratio - return identity | 591 return ctm; // Same aspect ratio - return identity |
569 } | 592 } |
570 | 593 |
571 } // namespace chromeos | 594 } // namespace chromeos |
OLD | NEW |