| Index: chromeos/display/output_configurator.cc
|
| diff --git a/chromeos/display/output_configurator.cc b/chromeos/display/output_configurator.cc
|
| index c460114699a15093dfb11e3d4149b48f833c0531..cb8210fd828028b2e200b618562fc052bb0234b0 100644
|
| --- a/chromeos/display/output_configurator.cc
|
| +++ b/chromeos/display/output_configurator.cc
|
| @@ -538,6 +538,7 @@ OutputConfigurator::OutputConfigurator()
|
| connected_output_count_(0),
|
| xrandr_event_base_(0),
|
| output_state_(STATE_INVALID),
|
| + power_state_(DISPLAY_POWER_ALL_ON),
|
| mirror_mode_will_preserve_aspect_(false),
|
| mirror_mode_preserved_aspect_(false),
|
| last_enter_state_time_() {
|
| @@ -594,10 +595,7 @@ void OutputConfigurator::Init(bool is_panel_fitting_enabled,
|
| STATE_INVALID,
|
| outputs);
|
| if (output_state_ != starting_state &&
|
| - EnterState(display,
|
| - screen,
|
| - window,
|
| - starting_state,
|
| + EnterState(display, screen, window, starting_state, power_state_,
|
| outputs)) {
|
| output_state_ = starting_state;
|
| }
|
| @@ -643,7 +641,7 @@ bool OutputConfigurator::CycleDisplayMode() {
|
| OutputState original = InferCurrentState(display, screen, outputs);
|
| OutputState next_state = GetNextState(display, screen, original, outputs);
|
| if (original != next_state &&
|
| - EnterState(display, screen, window, next_state, outputs)) {
|
| + EnterState(display, screen, window, next_state, power_state_, outputs)) {
|
| did_change = true;
|
| }
|
| // We have seen cases where the XRandR data can get out of sync with our own
|
| @@ -663,77 +661,41 @@ bool OutputConfigurator::CycleDisplayMode() {
|
| return did_change;
|
| }
|
|
|
| -bool OutputConfigurator::ScreenPowerSet(bool power_on, bool all_displays) {
|
| - TRACE_EVENT0("chromeos", "OutputConfigurator::ScreenPowerSet");
|
| - VLOG(1) << "OutputConfigurator::SetScreensOn " << power_on
|
| - << " all displays " << all_displays;
|
| +bool OutputConfigurator::SetDisplayPower(DisplayPowerState power_state,
|
| + bool force_probe) {
|
| + TRACE_EVENT0("chromeos", "OutputConfigurator::SetDisplayPower");
|
| + VLOG(1) << "OutputConfigurator::SetDisplayPower: power_state=" << power_state
|
| + << " force_probe=" << force_probe;
|
| +
|
| if (!configure_display_)
|
| return false;
|
| + if (power_state == power_state_ && !force_probe)
|
| + return true;
|
|
|
| - bool success = false;
|
| Display* display = base::MessagePumpAuraX11::GetDefaultXDisplay();
|
| - CHECK(display != NULL);
|
| + CHECK(display);
|
| XGrabServer(display);
|
| Window window = DefaultRootWindow(display);
|
| XRRScreenResources* screen = GetScreenResourcesAndRecordUMA(display, window);
|
| - CHECK(screen != NULL);
|
| -
|
| + CHECK(screen);
|
| std::vector<OutputSnapshot> outputs = GetDualOutputs(display, screen);
|
| connected_output_count_ = outputs.size();
|
|
|
| - if (all_displays && power_on) {
|
| - // Resume all displays using the current state.
|
| - if (EnterState(display, screen, window, output_state_, outputs)) {
|
| - // Force the DPMS on since the driver doesn't always detect that it should
|
| - // turn on. This is needed when coming back from idle suspend.
|
| + if (EnterState(display, screen, window, output_state_, power_state,
|
| + outputs)) {
|
| + power_state_ = power_state;
|
| + if (power_state != DISPLAY_POWER_ALL_OFF) {
|
| + // Force the DPMS on since the driver doesn't always detect that it
|
| + // should turn on. This is needed when coming back from idle suspend.
|
| CHECK(DPMSEnable(display));
|
| CHECK(DPMSForceLevel(display, DPMSModeOn));
|
| -
|
| - XRRFreeScreenResources(screen);
|
| - XUngrabServer(display);
|
| - return true;
|
| }
|
| }
|
|
|
| - CrtcConfig config;
|
| - config.crtc = None;
|
| - // Set the CRTCs based on whether we want to turn the power on or off and
|
| - // select the outputs to operate on by name or all_displays.
|
| - for (int i = 0; i < connected_output_count_; ++i) {
|
| - if (all_displays || outputs[i].is_internal || power_on) {
|
| - config.x = 0;
|
| - config.y = outputs[i].y;
|
| - config.output = outputs[i].output;
|
| - config.mode = None;
|
| - if (power_on) {
|
| - config.mode = (output_state_ == STATE_DUAL_MIRROR) ?
|
| - outputs[i].mirror_mode : outputs[i].native_mode;
|
| - } else if (connected_output_count_ > 1 && !all_displays &&
|
| - outputs[i].is_internal) {
|
| - // Workaround for crbug.com/148365: leave internal display in native
|
| - // mode so user can move cursor (and hence windows) onto internal
|
| - // display even when dimmed
|
| - config.mode = outputs[i].native_mode;
|
| - }
|
| - config.crtc = GetNextCrtcAfter(display, screen, config.output,
|
| - config.crtc);
|
| -
|
| - ConfigureCrtc(display, screen, &config);
|
| - success = true;
|
| - }
|
| - }
|
| -
|
| - // Force the DPMS on since the driver doesn't always detect that it should
|
| - // turn on. This is needed when coming back from idle suspend.
|
| - if (power_on) {
|
| - CHECK(DPMSEnable(display));
|
| - CHECK(DPMSForceLevel(display, DPMSModeOn));
|
| - }
|
| -
|
| XRRFreeScreenResources(screen);
|
| XUngrabServer(display);
|
|
|
| - return success;
|
| + return true;
|
| }
|
|
|
| bool OutputConfigurator::SetDisplayMode(OutputState new_state) {
|
| @@ -755,7 +717,7 @@ bool OutputConfigurator::SetDisplayMode(OutputState new_state) {
|
|
|
| std::vector<OutputSnapshot> outputs = GetDualOutputs(display, screen);
|
| connected_output_count_ = outputs.size();
|
| - if (EnterState(display, screen, window, new_state, outputs))
|
| + if (EnterState(display, screen, window, new_state, power_state_, outputs))
|
| output_state_ = new_state;
|
|
|
| XRRFreeScreenResources(screen);
|
| @@ -829,7 +791,8 @@ void OutputConfigurator::ConfigureOutputs() {
|
| // When a display was swapped, the state moves from
|
| // STATE_DUAL_EXTENDED to STATE_DUAL_EXTENDED, so don't rely on
|
| // the state chagne to tell if it was successful.
|
| - bool success = EnterState(display, screen, window, new_state, outputs);
|
| + bool success =
|
| + EnterState(display, screen, window, new_state, power_state_, outputs);
|
| bool is_projecting = IsProjecting(outputs);
|
| XRRFreeScreenResources(screen);
|
| XUngrabServer(display);
|
| @@ -859,16 +822,23 @@ bool OutputConfigurator::IsInternalOutputName(const std::string& name) {
|
| }
|
|
|
| void OutputConfigurator::SuspendDisplays() {
|
| - // Turn displays on before suspend. At this point, the backlight is off,
|
| - // so we turn on the internal display so that we can resume directly into
|
| - // "on" state. This greatly reduces resume times.
|
| - ScreenPowerSet(true, true);
|
| + // Turn internal displays on before suspend. At this point, the backlight
|
| + // is off, so we turn on the internal display so that we can resume
|
| + // directly into "on" state. This greatly reduces resume times.
|
| + SetDisplayPower(DISPLAY_POWER_INTERNAL_ON_EXTERNAL_OFF, false);
|
| +
|
| // We need to make sure that the monitor configuration we just did actually
|
| // completes before we return, because otherwise the X message could be
|
| // racing with the HandleSuspendReadiness message.
|
| XSync(base::MessagePumpAuraX11::GetDefaultXDisplay(), 0);
|
| }
|
|
|
| +void OutputConfigurator::ResumeDisplays() {
|
| + // Force probing to ensure that we pick up any changes that were made
|
| + // while the system was suspended.
|
| + SetDisplayPower(DISPLAY_POWER_ALL_ON, true);
|
| +}
|
| +
|
| void OutputConfigurator::NotifyOnDisplayChanged() {
|
| TRACE_EVENT0("chromeos", "OutputConfigurator::NotifyOnDisplayChanged");
|
| FOR_EACH_OBSERVER(Observer, observers_, OnDisplayModeChanged());
|
| @@ -1192,7 +1162,8 @@ bool OutputConfigurator::EnterState(
|
| Display* display,
|
| XRRScreenResources* screen,
|
| Window window,
|
| - OutputState new_state,
|
| + OutputState output_state,
|
| + DisplayPowerState power_state,
|
| const std::vector<OutputSnapshot>& outputs) {
|
| TRACE_EVENT0("chromeos", "OutputConfigurator::EnterState");
|
| switch (outputs.size()) {
|
| @@ -1207,16 +1178,20 @@ bool OutputConfigurator::EnterState(
|
| return false;
|
| }
|
|
|
| + bool power_on = power_state == DISPLAY_POWER_ALL_ON ||
|
| + (power_state == DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON &&
|
| + !outputs[0].is_internal) ||
|
| + (power_state == DISPLAY_POWER_INTERNAL_ON_EXTERNAL_OFF &&
|
| + outputs[0].is_internal);
|
| CrtcConfig config(
|
| GetNextCrtcAfter(display, screen, outputs[0].output, None),
|
| - 0, 0, outputs[0].native_mode, outputs[0].output);
|
| + 0, 0, power_on ? outputs[0].native_mode : None, outputs[0].output);
|
|
|
| - int width = mode_info->width;
|
| - int height = mode_info->height;
|
| - CreateFrameBuffer(display, screen, window, width, height, &config, NULL);
|
| + CreateFrameBuffer(display, screen, window, mode_info->width,
|
| + mode_info->height, &config, NULL);
|
|
|
| - // Re-attach native mode for the CRTC.
|
| ConfigureCrtc(display, screen, &config);
|
| +
|
| // Restore identity transformation for single monitor in native mode.
|
| if (outputs[0].touch_device_id != None) {
|
| CoordinateTransformation ctm; // Defaults to identity
|
| @@ -1230,25 +1205,36 @@ bool OutputConfigurator::EnterState(
|
| RRCrtc secondary_crtc =
|
| GetNextCrtcAfter(display, screen, outputs[1].output, primary_crtc);
|
|
|
| - if (new_state == STATE_DUAL_MIRROR) {
|
| + // Workaround for crbug.com/148365: leave internal display on for
|
| + // internal-off, external-on so user can move cursor (and hence
|
| + // windows) onto internal display even when it's off.
|
| + bool primary_power_on = power_state == DISPLAY_POWER_ALL_ON ||
|
| + (power_state == DISPLAY_POWER_INTERNAL_ON_EXTERNAL_OFF &&
|
| + outputs[0].is_internal);
|
| + bool secondary_power_on = power_state == DISPLAY_POWER_ALL_ON ||
|
| + (power_state == DISPLAY_POWER_INTERNAL_ON_EXTERNAL_OFF &&
|
| + outputs[1].is_internal);
|
| +
|
| + if (output_state == STATE_DUAL_MIRROR) {
|
| XRRModeInfo* mode_info = ModeInfoForID(screen, outputs[0].mirror_mode);
|
| if (mode_info == NULL) {
|
| UMA_HISTOGRAM_COUNTS("Display.EnterState.mirror_failures", 1);
|
| return false;
|
| }
|
|
|
| - CrtcConfig config1(primary_crtc, 0, 0, outputs[0].mirror_mode,
|
| + CrtcConfig config1(primary_crtc, 0, 0,
|
| + primary_power_on ? outputs[0].mirror_mode : None,
|
| outputs[0].output);
|
| - CrtcConfig config2(secondary_crtc, 0, 0, outputs[1].mirror_mode,
|
| + CrtcConfig config2(secondary_crtc, 0, 0,
|
| + secondary_power_on ? outputs[1].mirror_mode : None,
|
| outputs[1].output);
|
|
|
| - int width = mode_info->width;
|
| - int height = mode_info->height;
|
| - CreateFrameBuffer(display, screen, window, width, height,
|
| - &config1, &config2);
|
| + CreateFrameBuffer(display, screen, window, mode_info->width,
|
| + mode_info->height, &config1, &config2);
|
|
|
| ConfigureCrtc(display, screen, &config1);
|
| ConfigureCrtc(display, screen, &config2);
|
| +
|
| for (size_t i = 0; i < outputs.size(); i++) {
|
| if (outputs[i].touch_device_id == None)
|
| continue;
|
| @@ -1274,19 +1260,20 @@ bool OutputConfigurator::EnterState(
|
|
|
| int primary_height = primary_mode_info->height;
|
| int secondary_height = secondary_mode_info->height;
|
| - CrtcConfig config1(primary_crtc, 0, 0, outputs[0].native_mode,
|
| + CrtcConfig config1(primary_crtc, 0, 0,
|
| + primary_power_on ? outputs[0].native_mode : None,
|
| outputs[0].output);
|
| - CrtcConfig config2(secondary_crtc, 0, 0, outputs[1].native_mode,
|
| + CrtcConfig config2(secondary_crtc, 0, 0,
|
| + secondary_power_on ? outputs[1].native_mode : None,
|
| outputs[1].output);
|
|
|
| - if (new_state == STATE_DUAL_EXTENDED)
|
| + if (output_state == STATE_DUAL_EXTENDED)
|
| config2.y = primary_height + kVerticalGap;
|
| else
|
| config1.y = secondary_height + kVerticalGap;
|
|
|
| -
|
| - int width =
|
| - std::max<int>(primary_mode_info->width, secondary_mode_info->width);
|
| + int width = std::max<int>(
|
| + primary_mode_info->width, secondary_mode_info->width);
|
| int height = primary_height + secondary_height + kVerticalGap;
|
|
|
| CreateFrameBuffer(display, screen, window, width, height, &config1,
|
| @@ -1305,7 +1292,8 @@ bool OutputConfigurator::EnterState(
|
| }
|
| if (outputs[1].touch_device_id != None) {
|
| CoordinateTransformation ctm;
|
| - ctm.x_scale = static_cast<float>(secondary_mode_info->width) / width;
|
| + ctm.x_scale = static_cast<float>(secondary_mode_info->width) /
|
| + width;
|
| ctm.x_offset = static_cast<float>(config2.x) / width;
|
| ctm.y_scale = static_cast<float>(secondary_height) / height;
|
| ctm.y_offset = static_cast<float>(config2.y) / height;
|
|
|