Chromium Code Reviews| 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 |