Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(143)

Side by Side Diff: chromeos/display/output_configurator.cc

Issue 13006006: chromeos: Support turning displays off in extended mode. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: reupload Created 7 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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 <cmath> 7 #include <cmath>
8 8
9 #include <X11/Xatom.h> 9 #include <X11/Xatom.h>
10 #include <X11/Xlib.h> 10 #include <X11/Xlib.h>
(...skipping 579 matching lines...) Expand 10 before | Expand all | Expand 10 after
590 590
591 chromeos::DBusThreadManager::Get()->GetPowerManagerClient()-> 591 chromeos::DBusThreadManager::Get()->GetPowerManagerClient()->
592 SetIsProjecting(is_projecting); 592 SetIsProjecting(is_projecting);
593 } 593 }
594 594
595 void OutputConfigurator::Stop() { 595 void OutputConfigurator::Stop() {
596 configure_display_ = false; 596 configure_display_ = false;
597 } 597 }
598 598
599 bool OutputConfigurator::SetDisplayPower(DisplayPowerState power_state, 599 bool OutputConfigurator::SetDisplayPower(DisplayPowerState power_state,
600 bool force_probe) { 600 bool force_probe,
601 bool only_if_single_internal_display) {
601 TRACE_EVENT0("chromeos", "OutputConfigurator::SetDisplayPower"); 602 TRACE_EVENT0("chromeos", "OutputConfigurator::SetDisplayPower");
602 VLOG(1) << "OutputConfigurator::SetDisplayPower: power_state=" << power_state 603 VLOG(1) << "OutputConfigurator::SetDisplayPower: power_state=" << power_state
603 << " force_probe=" << force_probe; 604 << " force_probe=" << force_probe
605 << " only_if_single_internal_display="
606 << only_if_single_internal_display;
604 607
605 if (!configure_display_) 608 if (!configure_display_)
606 return false; 609 return false;
607 if (power_state == power_state_ && !force_probe) 610 if (power_state == power_state_ && !force_probe)
608 return true; 611 return true;
609 612
610 Display* display = base::MessagePumpAuraX11::GetDefaultXDisplay(); 613 Display* display = base::MessagePumpAuraX11::GetDefaultXDisplay();
611 CHECK(display); 614 CHECK(display);
612 XGrabServer(display); 615 XGrabServer(display);
613 Window window = DefaultRootWindow(display); 616 Window window = DefaultRootWindow(display);
614 XRRScreenResources* screen = GetScreenResourcesAndRecordUMA(display, window); 617 XRRScreenResources* screen = GetScreenResourcesAndRecordUMA(display, window);
615 CHECK(screen); 618 CHECK(screen);
616 std::vector<OutputSnapshot> outputs = GetDualOutputs(display, screen); 619 std::vector<OutputSnapshot> outputs = GetDualOutputs(display, screen);
617 connected_output_count_ = outputs.size(); 620 connected_output_count_ = outputs.size();
618 621
619 if (EnterState(display, screen, window, output_state_, power_state, 622 bool single_internal_display = outputs.size() == 1 && outputs[0].is_internal;
623 if ((single_internal_display || !only_if_single_internal_display) &&
624 EnterState(display, screen, window, output_state_, power_state,
620 outputs)) { 625 outputs)) {
621 power_state_ = power_state; 626 power_state_ = power_state;
622 if (power_state != DISPLAY_POWER_ALL_OFF) { 627 if (power_state != DISPLAY_POWER_ALL_OFF) {
623 // Force the DPMS on since the driver doesn't always detect that it 628 // Force the DPMS on since the driver doesn't always detect that it
624 // should turn on. This is needed when coming back from idle suspend. 629 // should turn on. This is needed when coming back from idle suspend.
625 CHECK(DPMSEnable(display)); 630 CHECK(DPMSEnable(display));
626 CHECK(DPMSForceLevel(display, DPMSModeOn)); 631 CHECK(DPMSForceLevel(display, DPMSModeOn));
627 } 632 }
628 } 633 }
629 634
630 XRRFreeScreenResources(screen); 635 XRRFreeScreenResources(screen);
631 XUngrabServer(display); 636 XUngrabServer(display);
632
633 return true; 637 return true;
634 } 638 }
635 639
636 bool OutputConfigurator::SetDisplayMode(OutputState new_state) { 640 bool OutputConfigurator::SetDisplayMode(OutputState new_state) {
637 TRACE_EVENT0("chromeos", "OutputConfigurator::SetDisplayMode"); 641 TRACE_EVENT0("chromeos", "OutputConfigurator::SetDisplayMode");
638 if (output_state_ == STATE_INVALID || 642 if (output_state_ == STATE_INVALID ||
639 output_state_ == STATE_HEADLESS || 643 output_state_ == STATE_HEADLESS ||
640 output_state_ == STATE_SINGLE) 644 output_state_ == STATE_SINGLE)
641 return false; 645 return false;
642 646
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after
750 void OutputConfigurator::RemoveObserver(Observer* observer) { 754 void OutputConfigurator::RemoveObserver(Observer* observer) {
751 observers_.RemoveObserver(observer); 755 observers_.RemoveObserver(observer);
752 } 756 }
753 757
754 // static 758 // static
755 bool OutputConfigurator::IsInternalOutputName(const std::string& name) { 759 bool OutputConfigurator::IsInternalOutputName(const std::string& name) {
756 return name.find(kInternal_LVDS) == 0 || name.find(kInternal_eDP) == 0; 760 return name.find(kInternal_LVDS) == 0 || name.find(kInternal_eDP) == 0;
757 } 761 }
758 762
759 void OutputConfigurator::SuspendDisplays() { 763 void OutputConfigurator::SuspendDisplays() {
760 // Turn internal displays on before suspend. At this point, the backlight 764 // If the display is off due to user inactivity and there's only a single
761 // is off, so we turn on the internal display so that we can resume 765 // internal display connected, switch to the all-on state before
762 // directly into "on" state. This greatly reduces resume times. 766 // suspending. This shouldn't be very noticeable to the user since the
763 SetDisplayPower(DISPLAY_POWER_INTERNAL_ON_EXTERNAL_OFF, false); 767 // backlight is off at this point, and doing this lets us resume directly
768 // into the "on" state, which greatly reduces resume times.
769 if (power_state_ == DISPLAY_POWER_ALL_OFF) {
770 SetDisplayPower(DISPLAY_POWER_ALL_ON, false,
771 true /* only_if_single_internal_display */);
Daniel Erat 2013/03/27 23:15:19 I think that we can only do this safely when there
772 }
764 773
765 // We need to make sure that the monitor configuration we just did actually 774 // We need to make sure that the monitor configuration we just did actually
766 // completes before we return, because otherwise the X message could be 775 // completes before we return, because otherwise the X message could be
767 // racing with the HandleSuspendReadiness message. 776 // racing with the HandleSuspendReadiness message.
768 XSync(base::MessagePumpAuraX11::GetDefaultXDisplay(), 0); 777 XSync(base::MessagePumpAuraX11::GetDefaultXDisplay(), 0);
769 } 778 }
770 779
771 void OutputConfigurator::ResumeDisplays() { 780 void OutputConfigurator::ResumeDisplays() {
772 // Force probing to ensure that we pick up any changes that were made 781 // Force probing to ensure that we pick up any changes that were made
773 // while the system was suspended. 782 // while the system was suspended.
774 SetDisplayPower(DISPLAY_POWER_ALL_ON, true); 783 SetDisplayPower(power_state_, true /* force_probe */, false);
775 } 784 }
776 785
777 void OutputConfigurator::NotifyOnDisplayChanged() { 786 void OutputConfigurator::NotifyOnDisplayChanged() {
778 TRACE_EVENT0("chromeos", "OutputConfigurator::NotifyOnDisplayChanged"); 787 TRACE_EVENT0("chromeos", "OutputConfigurator::NotifyOnDisplayChanged");
779 FOR_EACH_OBSERVER(Observer, observers_, OnDisplayModeChanged()); 788 FOR_EACH_OBSERVER(Observer, observers_, OnDisplayModeChanged());
780 } 789 }
781 790
782 std::vector<OutputSnapshot> OutputConfigurator::GetDualOutputs( 791 std::vector<OutputSnapshot> OutputConfigurator::GetDualOutputs(
783 Display* display, 792 Display* display,
784 XRRScreenResources* screen) { 793 XRRScreenResources* screen) {
(...skipping 310 matching lines...) Expand 10 before | Expand all | Expand 10 after
1095 } 1104 }
1096 1105
1097 bool OutputConfigurator::EnterState( 1106 bool OutputConfigurator::EnterState(
1098 Display* display, 1107 Display* display,
1099 XRRScreenResources* screen, 1108 XRRScreenResources* screen,
1100 Window window, 1109 Window window,
1101 OutputState output_state, 1110 OutputState output_state,
1102 DisplayPowerState power_state, 1111 DisplayPowerState power_state,
1103 const std::vector<OutputSnapshot>& outputs) { 1112 const std::vector<OutputSnapshot>& outputs) {
1104 TRACE_EVENT0("chromeos", "OutputConfigurator::EnterState"); 1113 TRACE_EVENT0("chromeos", "OutputConfigurator::EnterState");
1114
1115 std::vector<RRCrtc> crtcs(outputs.size());
1116 std::vector<bool> output_power(outputs.size());
1117 bool all_outputs_off = true;
1118
1119 RRCrtc prev_crtc = None;
1120 for (size_t i = 0; i < outputs.size(); prev_crtc = crtcs[i], ++i) {
1121 crtcs[i] = GetNextCrtcAfter(display, screen, outputs[i].output, prev_crtc);
1122 output_power[i] = power_state == DISPLAY_POWER_ALL_ON ||
1123 (power_state == DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON &&
1124 !outputs[i].is_internal) ||
1125 (power_state == DISPLAY_POWER_INTERNAL_ON_EXTERNAL_OFF &&
1126 outputs[i].is_internal);
1127 if (output_power[i])
1128 all_outputs_off = false;
1129 }
1130
1105 switch (outputs.size()) { 1131 switch (outputs.size()) {
1106 case 0: 1132 case 0:
1107 // Do nothing as no 0-display states are supported. 1133 // Do nothing as no 0-display states are supported.
1108 break; 1134 break;
1109 case 1: { 1135 case 1: {
1110 // Re-allocate the framebuffer to fit. 1136 // Re-allocate the framebuffer to fit.
1111 XRRModeInfo* mode_info = ModeInfoForID(screen, outputs[0].native_mode); 1137 XRRModeInfo* mode_info = ModeInfoForID(screen, outputs[0].native_mode);
1112 if (mode_info == NULL) { 1138 if (!mode_info) {
1113 UMA_HISTOGRAM_COUNTS("Display.EnterState.single_failures", 1); 1139 UMA_HISTOGRAM_COUNTS("Display.EnterState.single_failures", 1);
1114 return false; 1140 return false;
1115 } 1141 }
1116 1142
1117 bool power_on = power_state == DISPLAY_POWER_ALL_ON || 1143 CrtcConfig config(crtcs[0], 0, 0,
1118 (power_state == DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON && 1144 output_power[0] ? outputs[0].native_mode : None,
1119 !outputs[0].is_internal) || 1145 outputs[0].output);
1120 (power_state == DISPLAY_POWER_INTERNAL_ON_EXTERNAL_OFF &&
1121 outputs[0].is_internal);
1122 CrtcConfig config(
1123 GetNextCrtcAfter(display, screen, outputs[0].output, None),
1124 0, 0, power_on ? outputs[0].native_mode : None, outputs[0].output);
1125
1126 CreateFrameBuffer(display, screen, window, mode_info->width, 1146 CreateFrameBuffer(display, screen, window, mode_info->width,
1127 mode_info->height, &config, NULL); 1147 mode_info->height, &config, NULL);
1128
1129 ConfigureCrtc(display, screen, &config); 1148 ConfigureCrtc(display, screen, &config);
1130 1149 if (outputs[0].touch_device_id) {
1131 // Restore identity transformation for single monitor in native mode. 1150 // Restore identity transformation for single monitor in native mode.
1132 if (outputs[0].touch_device_id != None) { 1151 ConfigureCTM(display, outputs[0].touch_device_id,
1133 CoordinateTransformation ctm; // Defaults to identity 1152 CoordinateTransformation());
1134 ConfigureCTM(display, outputs[0].touch_device_id, ctm);
1135 } 1153 }
1136 break; 1154 break;
1137 } 1155 }
1138 case 2: { 1156 case 2: {
1139 RRCrtc primary_crtc =
1140 GetNextCrtcAfter(display, screen, outputs[0].output, None);
1141 RRCrtc secondary_crtc =
1142 GetNextCrtcAfter(display, screen, outputs[1].output, primary_crtc);
1143
1144 // Workaround for crbug.com/148365: leave internal display on for
1145 // internal-off, external-on so user can move cursor (and hence
1146 // windows) onto internal display even when it's off.
1147 bool primary_power_on = power_state == DISPLAY_POWER_ALL_ON ||
1148 (power_state == DISPLAY_POWER_INTERNAL_ON_EXTERNAL_OFF &&
1149 outputs[0].is_internal);
1150 bool secondary_power_on = power_state == DISPLAY_POWER_ALL_ON ||
1151 (power_state == DISPLAY_POWER_INTERNAL_ON_EXTERNAL_OFF &&
1152 outputs[1].is_internal);
1153
1154 if (output_state == STATE_DUAL_MIRROR) { 1157 if (output_state == STATE_DUAL_MIRROR) {
1155 XRRModeInfo* mode_info = ModeInfoForID(screen, outputs[0].mirror_mode); 1158 XRRModeInfo* mode_info = ModeInfoForID(screen, outputs[0].mirror_mode);
1156 if (mode_info == NULL) { 1159 if (!mode_info) {
1157 UMA_HISTOGRAM_COUNTS("Display.EnterState.mirror_failures", 1); 1160 UMA_HISTOGRAM_COUNTS("Display.EnterState.mirror_failures", 1);
1158 return false; 1161 return false;
1159 } 1162 }
1160 1163
1161 CrtcConfig config1(primary_crtc, 0, 0, 1164 std::vector<CrtcConfig> configs(outputs.size());
1162 primary_power_on ? outputs[0].mirror_mode : None, 1165 for (size_t i = 0; i < outputs.size(); ++i) {
1163 outputs[0].output); 1166 configs[i] = CrtcConfig(
1164 CrtcConfig config2(secondary_crtc, 0, 0, 1167 crtcs[i], 0, 0,
1165 secondary_power_on ? outputs[1].mirror_mode : None, 1168 output_power[i] ? outputs[i].mirror_mode : None,
1166 outputs[1].output); 1169 outputs[i].output);
1170 }
1167 1171
1168 CreateFrameBuffer(display, screen, window, mode_info->width, 1172 CreateFrameBuffer(display, screen, window, mode_info->width,
1169 mode_info->height, &config1, &config2); 1173 mode_info->height, &configs[0], &configs[1]);
1170 1174
1171 ConfigureCrtc(display, screen, &config1); 1175 for (size_t i = 0; i < outputs.size(); ++i) {
1172 ConfigureCrtc(display, screen, &config2); 1176 ConfigureCrtc(display, screen, &configs[i]);
1177 if (outputs[i].touch_device_id) {
1178 CoordinateTransformation ctm;
1179 // CTM needs to be calculated if aspect preserving scaling is used.
1180 // Otherwise, assume it is full screen, and use identity CTM.
1181 if (outputs[i].mirror_mode != outputs[i].native_mode &&
1182 outputs[i].is_aspect_preserving_scaling) {
1183 ctm = GetMirrorModeCTM(screen, &outputs[i]);
1184 }
1185 ConfigureCTM(display, outputs[i].touch_device_id, ctm);
1186 }
1187 }
1188 } else { // STATE_DUAL_EXTENDED
1189 std::vector<XRRModeInfo*> mode_infos(outputs.size());
1190 std::vector<CrtcConfig> configs(outputs.size());
1191 int width = 0, height = 0;
1173 1192
1174 for (size_t i = 0; i < outputs.size(); i++) { 1193 for (size_t i = 0; i < outputs.size(); ++i) {
1175 if (outputs[i].touch_device_id == None) 1194 mode_infos[i] = ModeInfoForID(screen, outputs[i].native_mode);
1176 continue; 1195 if (!mode_infos[i]) {
1196 UMA_HISTOGRAM_COUNTS("Display.EnterState.dual_failures", 1);
1197 return false;
1198 }
1177 1199
1178 CoordinateTransformation ctm; 1200 configs[i] = CrtcConfig(
1179 // CTM needs to be calculated if aspect preserving scaling is used. 1201 crtcs[i], 0, height,
1180 // Otherwise, assume it is full screen, and use identity CTM. 1202 output_power[i] ? outputs[i].native_mode : None,
1181 if (outputs[i].mirror_mode != outputs[i].native_mode && 1203 outputs[i].output);
1182 outputs[i].is_aspect_preserving_scaling) { 1204
1183 ctm = GetMirrorModeCTM(screen, &outputs[i]); 1205 // Retain the full screen size if all outputs are off so the same
1206 // desktop configuration can be restored when the outputs are
1207 // turned back on.
1208 if (output_power[i] || all_outputs_off) {
1209 width = std::max<int>(width, mode_infos[i]->width);
1210 height += (height ? kVerticalGap : 0) + mode_infos[i]->height;
1184 } 1211 }
1185 ConfigureCTM(display, outputs[i].touch_device_id, ctm);
1186 }
1187 } else {
1188 XRRModeInfo* primary_mode_info =
1189 ModeInfoForID(screen, outputs[0].native_mode);
1190 XRRModeInfo* secondary_mode_info =
1191 ModeInfoForID(screen, outputs[1].native_mode);
1192 if (primary_mode_info == NULL || secondary_mode_info == NULL) {
1193 UMA_HISTOGRAM_COUNTS("Display.EnterState.dual_failures", 1);
1194 return false;
1195 } 1212 }
1196 1213
1197 int primary_height = primary_mode_info->height; 1214 CreateFrameBuffer(display, screen, window, width, height,
1198 int secondary_height = secondary_mode_info->height; 1215 &configs[0], &configs[1]);
1199 CrtcConfig config1(primary_crtc, 0, 0,
1200 primary_power_on ? outputs[0].native_mode : None,
1201 outputs[0].output);
1202 CrtcConfig config2(secondary_crtc, 0, 0,
1203 secondary_power_on ? outputs[1].native_mode : None,
1204 outputs[1].output);
1205 1216
1206 if (output_state == STATE_DUAL_EXTENDED) 1217 for (size_t i = 0; i < outputs.size(); ++i) {
1207 config2.y = primary_height + kVerticalGap; 1218 ConfigureCrtc(display, screen, &configs[i]);
1208 else 1219 if (outputs[i].touch_device_id) {
1209 config1.y = secondary_height + kVerticalGap; 1220 CoordinateTransformation ctm;
1210 1221 ctm.x_scale = static_cast<float>(mode_infos[i]->width) / width;
1211 int width = std::max<int>( 1222 ctm.x_offset = static_cast<float>(configs[i].x) / width;
1212 primary_mode_info->width, secondary_mode_info->width); 1223 ctm.y_scale = static_cast<float>(mode_infos[i]->height) / height;
1213 int height = primary_height + secondary_height + kVerticalGap; 1224 ctm.y_offset = static_cast<float>(configs[i].y) / height;
1214 1225 ConfigureCTM(display, outputs[i].touch_device_id, ctm);
1215 CreateFrameBuffer(display, screen, window, width, height, &config1, 1226 }
1216 &config2);
1217
1218 ConfigureCrtc(display, screen, &config1);
1219 ConfigureCrtc(display, screen, &config2);
1220
1221 if (outputs[0].touch_device_id != None) {
1222 CoordinateTransformation ctm;
1223 ctm.x_scale = static_cast<float>(primary_mode_info->width) / width;
1224 ctm.x_offset = static_cast<float>(config1.x) / width;
1225 ctm.y_scale = static_cast<float>(primary_height) / height;
1226 ctm.y_offset = static_cast<float>(config1.y) / height;
1227 ConfigureCTM(display, outputs[0].touch_device_id, ctm);
1228 }
1229 if (outputs[1].touch_device_id != None) {
1230 CoordinateTransformation ctm;
1231 ctm.x_scale = static_cast<float>(secondary_mode_info->width) /
1232 width;
1233 ctm.x_offset = static_cast<float>(config2.x) / width;
1234 ctm.y_scale = static_cast<float>(secondary_height) / height;
1235 ctm.y_offset = static_cast<float>(config2.y) / height;
1236 ConfigureCTM(display, outputs[1].touch_device_id, ctm);
1237 } 1227 }
1238 } 1228 }
1239 break; 1229 break;
1240 } 1230 }
1241 default: 1231 default:
1242 CHECK(false); 1232 NOTREACHED() << "Got " << outputs.size() << " outputs";
1243 } 1233 }
1244 1234
1245 RecordPreviousStateUMA(); 1235 RecordPreviousStateUMA();
1246
1247 return true; 1236 return true;
1248 } 1237 }
1249 1238
1250 void OutputConfigurator::RecordPreviousStateUMA() { 1239 void OutputConfigurator::RecordPreviousStateUMA() {
1251 base::TimeDelta duration = base::TimeTicks::Now() - last_enter_state_time_; 1240 base::TimeDelta duration = base::TimeTicks::Now() - last_enter_state_time_;
1252 1241
1253 // |output_state_| can be used for the state being left, 1242 // |output_state_| can be used for the state being left,
1254 // since RecordPreviousStateUMA is called from EnterState, 1243 // since RecordPreviousStateUMA is called from EnterState,
1255 // and |output_state_| is always updated after EnterState is called. 1244 // and |output_state_| is always updated after EnterState is called.
1256 switch (output_state_) { 1245 switch (output_state_) {
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
1332 // static 1321 // static
1333 RRMode OutputConfigurator::GetOutputNativeMode( 1322 RRMode OutputConfigurator::GetOutputNativeMode(
1334 const XRROutputInfo* output_info) { 1323 const XRROutputInfo* output_info) {
1335 if (output_info->nmode <= 0) 1324 if (output_info->nmode <= 0)
1336 return None; 1325 return None;
1337 1326
1338 return output_info->modes[0]; 1327 return output_info->modes[0];
1339 } 1328 }
1340 1329
1341 } // namespace chromeos 1330 } // namespace chromeos
OLDNEW
« chromeos/display/output_configurator.h ('K') | « chromeos/display/output_configurator.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698