OLD | NEW |
---|---|
1 // Copyright (c) 2010 The Chromium OS Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium OS 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 "monitor_reconfig/monitor_reconfigure_main.h" | 5 #include "monitor_reconfig/monitor_reconfigure_main.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <cstdio> | 8 #include <cstdio> |
9 #include <cstdlib> | 9 #include <cstdlib> |
10 | 10 |
11 #include "base/command_line.h" | 11 #include "base/command_line.h" |
12 #include "base/logging.h" | 12 #include "base/logging.h" |
13 #include "base/string_util.h" | 13 #include "base/string_util.h" |
14 | 14 |
15 using std::map; | 15 using std::map; |
16 using std::sort; | 16 using std::sort; |
17 using std::string; | 17 using std::string; |
18 using std::vector; | 18 using std::vector; |
19 | 19 |
20 namespace monitor_reconfig { | 20 namespace monitor_reconfig { |
21 | 21 |
22 static const char kLcdOutputName[] = "LVDS1"; | 22 static const char kLcdOutputName[] = "LVDS1"; |
23 static const float kScreenDpi = 96.0; | |
24 static const float kInchInMm = 25.4; | |
23 | 25 |
24 MonitorReconfigureMain::MonitorReconfigureMain(Display* display, | 26 MonitorReconfigureMain::MonitorReconfigureMain(Display* display, |
27 Window window, | |
25 XRRScreenResources* screen_info) | 28 XRRScreenResources* screen_info) |
26 : display_(display), | 29 : display_(display), |
30 window_(window), | |
27 screen_info_(screen_info), | 31 screen_info_(screen_info), |
28 lcd_output_(NULL), | 32 lcd_output_(0), |
29 external_output_(NULL) { | 33 external_output_(0) { |
30 for (int i = 0; i < screen_info_->nmode; ++i) { | 34 for (int i = 0; i < screen_info_->nmode; ++i) { |
31 XRRModeInfo* current_mode = &screen_info_->modes[i]; | 35 XRRModeInfo* current_mode = &screen_info_->modes[i]; |
32 mode_map_[current_mode->id] = current_mode; | 36 mode_map_[current_mode->id] = current_mode; |
33 } | 37 } |
34 DetermineOutputs(); | 38 DetermineOutputs(); |
35 } | 39 } |
36 | 40 |
37 void MonitorReconfigureMain::Run() { | 41 void MonitorReconfigureMain::Run() { |
38 vector<ResolutionSelector::Mode> lcd_modes; | 42 vector<ResolutionSelector::Mode> lcd_modes; |
39 SortModesByResolution(*lcd_output_, &lcd_modes); | 43 SortModesByResolution(lcd_output_, &lcd_modes); |
40 DCHECK(!lcd_modes.empty()); | 44 DCHECK(!lcd_modes.empty()); |
41 | 45 |
42 vector<ResolutionSelector::Mode> external_modes; | 46 vector<ResolutionSelector::Mode> external_modes; |
43 if (IsExternalMonitorConnected()) { | 47 if (IsExternalMonitorConnected()) { |
44 SortModesByResolution(*external_output_, &external_modes); | 48 SortModesByResolution(external_output_, &external_modes); |
45 DCHECK(!external_modes.empty()); | 49 DCHECK(!external_modes.empty()); |
46 } | 50 } |
47 | 51 |
48 ResolutionSelector selector; | 52 ResolutionSelector selector; |
49 string lcd_resolution, external_resolution, screen_resolution; | 53 ResolutionSelector::Mode lcd_resolution, |
54 external_resolution, | |
Daniel Erat
2011/03/24 23:02:11
make each of these be declared in a separate state
| |
55 screen_resolution; | |
50 CHECK(selector.FindBestResolutions(lcd_modes, | 56 CHECK(selector.FindBestResolutions(lcd_modes, |
51 external_modes, | 57 external_modes, |
52 &lcd_resolution, | 58 &lcd_resolution, |
53 &external_resolution, | 59 &external_resolution, |
54 &screen_resolution)); | 60 &screen_resolution)); |
55 CHECK(!lcd_resolution.empty() || !external_resolution.empty()); | 61 CHECK(!lcd_resolution.name.empty() || !external_resolution.name.empty()); |
62 | |
63 // Grab the server during mode changes. | |
64 XGrabServer (display_); | |
Daniel Erat
2011/03/24 23:02:11
no spaces between function names and opening paren
| |
56 | 65 |
57 // Disable the LCD if we were told to do so (because we're using a higher | 66 // Disable the LCD if we were told to do so (because we're using a higher |
58 // resolution that'd be clipped on the LCD). | 67 // resolution that'd be clipped on the LCD). |
59 if (lcd_resolution.empty()) | 68 // Otherwise enable the LCD if appropriate. |
60 DisableDevice(lcd_output_->name); | 69 if (lcd_resolution.name.empty()) |
70 DisableDevice(lcd_output_, lcd_output_info_); | |
71 else | |
72 SetDeviceResolution(lcd_output_, lcd_output_info_, lcd_resolution); | |
61 | 73 |
62 // If there's no external output connected, disable the device before we try | 74 // If there's no external output connected, disable the device before we try |
63 // to set the screen resolution; otherwise xrandr will complain if we're | 75 // to set the screen resolution; otherwise xrandr will complain if we're |
64 // trying to set the screen to a smaller size than what the now-unplugged | 76 // trying to set the screen to a smaller size than what the now-unplugged |
65 // device was using. | 77 // device was using. |
66 if (external_resolution.empty()) | 78 // Otherwise enable the external device if appropriate. |
67 DisableDevice(external_output_->name); | 79 if (external_resolution.name.empty()) |
80 DisableDevice(external_output_, external_output_info_); | |
81 else | |
82 SetDeviceResolution(external_output_, external_output_info_, | |
83 external_resolution); | |
68 | 84 |
69 // Set the fb to try to avoid the driver's "crtc has no fb" message. | 85 // Set the fb resolution. |
70 // Doing this before enabling the display reduces the likelihood of a | |
71 // visible "snap" when returning to the panel. | |
72 SetScreenResolution(screen_resolution); | 86 SetScreenResolution(screen_resolution); |
73 | 87 |
74 // Enable the LCD if appropriate. | 88 if (!lcd_resolution.name.empty()) |
75 if (!lcd_resolution.empty()) | |
76 SetDeviceResolution(lcd_output_->name, lcd_resolution); | |
77 | 89 |
78 // Enable the external device if appropriate. | 90 if (!external_resolution.name.empty()) |
79 if (!external_resolution.empty()) | 91 |
80 SetDeviceResolution(external_output_->name, external_resolution); | 92 // Now let the server go and sync all changes. |
93 XUngrabServer (display_); | |
94 XSync (display_, False); | |
81 } | 95 } |
82 | 96 |
83 void MonitorReconfigureMain::DetermineOutputs() { | 97 void MonitorReconfigureMain::DetermineOutputs() { |
84 CHECK(screen_info_->noutput > 1) << "Expected at least two outputs"; | 98 CHECK(screen_info_->noutput > 1) << "Expected at least two outputs"; |
85 XRROutputInfo* first_output = | |
86 XRRGetOutputInfo(display_, screen_info_, screen_info_->outputs[0]); | |
87 XRROutputInfo* second_output = | |
88 XRRGetOutputInfo(display_, screen_info_, screen_info_->outputs[1]); | |
89 | 99 |
90 if (strcmp(first_output->name, kLcdOutputName) == 0) { | 100 RROutput first_output = screen_info_->outputs[0]; |
101 RROutput second_output = screen_info_->outputs[1]; | |
102 | |
103 XRROutputInfo* first_output_info = | |
104 XRRGetOutputInfo(display_, screen_info_, first_output); | |
105 XRROutputInfo* second_output_info = | |
106 XRRGetOutputInfo(display_, screen_info_, second_output); | |
107 | |
108 if (strcmp(first_output_info->name, kLcdOutputName) == 0) { | |
91 lcd_output_ = first_output; | 109 lcd_output_ = first_output; |
110 lcd_output_info_ = first_output_info; | |
92 external_output_ = second_output; | 111 external_output_ = second_output; |
112 external_output_info_ = second_output_info; | |
93 } else { | 113 } else { |
94 lcd_output_ = second_output; | 114 lcd_output_ = second_output; |
115 lcd_output_info_ = second_output_info; | |
95 external_output_ = first_output; | 116 external_output_ = first_output; |
117 external_output_info_ = first_output_info; | |
96 } | 118 } |
97 | 119 |
98 LOG(INFO) << "LCD name: " << lcd_output_->name; | 120 LOG(INFO) << "LCD name: " << lcd_output_info_->name << " (xid " |
99 for (int i = 0; i < lcd_output_->nmode; ++i) { | 121 << lcd_output_ << ")"; |
100 XRRModeInfo* mode = mode_map_[lcd_output_->modes[i]]; | 122 for (int i = 0; i < lcd_output_info_->nmode; ++i) { |
101 LOG(INFO) << " Mode: " << mode->width << "x" << mode->height; | 123 XRRModeInfo* mode = mode_map_[lcd_output_info_->modes[i]]; |
124 LOG(INFO) << " Mode: " << mode->width << "x" << mode->height | |
125 << " (xid " << mode->id << ")"; | |
102 } | 126 } |
103 | 127 |
104 LOG(INFO) << "External name: " << external_output_->name; | 128 LOG(INFO) << "External name: " << external_output_info_->name |
105 for (int i = 0; i < external_output_->nmode; ++i) { | 129 << " (xid " << external_output_ << ")"; |
106 XRRModeInfo* mode = mode_map_[external_output_->modes[i]]; | 130 for (int i = 0; i < external_output_info_->nmode; ++i) { |
107 LOG(INFO) << " Mode: " << mode->width << "x" << mode->height; | 131 XRRModeInfo* mode = mode_map_[external_output_info_->modes[i]]; |
132 LOG(INFO) << " Mode: " << mode->width << "x" << mode->height | |
133 << " (xid " << mode->id << ")"; | |
108 } | 134 } |
109 } | 135 } |
110 | 136 |
111 bool MonitorReconfigureMain::IsExternalMonitorConnected() { | 137 bool MonitorReconfigureMain::IsExternalMonitorConnected() { |
112 return (external_output_->connection == RR_Connected); | 138 return (external_output_info_->connection == RR_Connected); |
113 } | 139 } |
114 | 140 |
115 void MonitorReconfigureMain::SortModesByResolution( | 141 void MonitorReconfigureMain::SortModesByResolution( |
116 const XRROutputInfo& output_info, | 142 const RROutput output, |
117 vector<ResolutionSelector::Mode>* modes_out) { | 143 vector<ResolutionSelector::Mode>* modes_out) { |
118 modes_out->clear(); | 144 modes_out->clear(); |
119 | 145 |
120 for (int i = 0; i < output_info.nmode; ++i) { | 146 XRROutputInfo* output_info = XRRGetOutputInfo(display_, screen_info_, output); |
121 const XRRModeInfo* mode = mode_map_[output_info.modes[i]]; | 147 for (int i = 0; i < output_info->nmode; ++i) { |
148 const XRRModeInfo* mode = mode_map_[output_info->modes[i]]; | |
122 DCHECK(mode); | 149 DCHECK(mode); |
150 LOG(INFO) << "Adding mode " << mode->width << " " << mode->height | |
151 << " (xid " << mode->id << ")"; | |
123 modes_out->push_back( | 152 modes_out->push_back( |
124 ResolutionSelector::Mode(mode->width, mode->height, mode->name)); | 153 ResolutionSelector::Mode(mode->width, mode->height, mode->name, |
154 mode->id)); | |
125 } | 155 } |
126 | 156 |
127 sort(modes_out->begin(), modes_out->end(), | 157 sort(modes_out->begin(), modes_out->end(), |
128 ResolutionSelector::ModeResolutionComparator()); | 158 ResolutionSelector::ModeResolutionComparator()); |
129 } | 159 } |
130 | 160 |
131 bool MonitorReconfigureMain::SetDeviceResolution( | 161 bool MonitorReconfigureMain::SetDeviceResolution( |
132 const std::string& device_name, const std::string& resolution) { | 162 const RROutput output, const XRROutputInfo* output_info, |
133 string command = StringPrintf("xrandr --output %s --mode %s", | 163 const ResolutionSelector::Mode resolution) { |
134 device_name.c_str(), resolution.c_str()); | 164 RROutput o = output; |
Daniel Erat
2011/03/24 23:02:11
why do you need to make a copy here?
marcheu
2011/03/24 23:17:53
XRRSetCrtcConfig has a non-const RROutput* paramet
Daniel Erat
2011/03/24 23:39:46
How about const_cast?
| |
135 LOG(INFO) << "Running " << command.c_str(); | 165 Status s = XRRSetCrtcConfig (display_, screen_info_, output_info->crtcs[0], |
136 return system(command.c_str()) == 0; | 166 CurrentTime, 0, 0, resolution.id, RR_Rotate_0, |
167 &o, 1); | |
168 return (s == RRSetConfigSuccess); | |
137 } | 169 } |
138 | 170 |
139 bool MonitorReconfigureMain::SetScreenResolution( | 171 bool MonitorReconfigureMain::SetScreenResolution( |
140 const std::string& resolution) { | 172 const ResolutionSelector::Mode resolution) { |
141 string command = StringPrintf("xrandr --fb %s", resolution.c_str()); | 173 int screen = DefaultScreen(display_); |
142 LOG(INFO) << "Running " << command.c_str(); | 174 LOG(INFO) << "Setting resolution " << resolution.name.c_str() << " " |
143 return system(command.c_str()) == 0; | 175 << resolution.width << "x" << resolution.height; |
176 XRRSetScreenSize (display_, window_, | |
177 resolution.width, | |
178 resolution.height, | |
179 resolution.width * kInchInMm / kScreenDpi, | |
180 resolution.height * kInchInMm / kScreenDpi | |
181 ); | |
Daniel Erat
2011/03/24 23:02:11
move this to the end of the previous line
| |
182 | |
183 return true; | |
144 } | 184 } |
145 | 185 |
146 bool MonitorReconfigureMain::DisableDevice(const std::string& device_name) { | 186 bool MonitorReconfigureMain::DisableDevice(const RROutput output, |
147 string command = StringPrintf("xrandr --output %s --off", | 187 const XRROutputInfo* output_info) { |
148 device_name.c_str()); | 188 if (!output_info->crtc) |
149 LOG(INFO) << "Running " << command.c_str(); | 189 return true; |
150 return system(command.c_str()) == 0; | 190 LOG(INFO) << "Disabling output " << output_info->name; |
191 Status s = XRRSetCrtcConfig (display_, screen_info_, output_info->crtc, | |
192 CurrentTime, 0, 0, None, RR_Rotate_0, NULL, 0); | |
193 return (s == RRSetConfigSuccess); | |
151 } | 194 } |
152 | 195 |
153 } // end namespace monitor_reconfig | 196 } // end namespace monitor_reconfig |
154 | 197 |
155 int main(int argc, char** argv) { | 198 int main(int argc, char** argv) { |
156 CommandLine::Init(argc, argv); | 199 CommandLine::Init(argc, argv); |
157 logging::InitLogging(NULL, | 200 logging::InitLogging(NULL, |
158 logging::LOG_ONLY_TO_SYSTEM_DEBUG_LOG, | 201 logging::LOG_ONLY_TO_SYSTEM_DEBUG_LOG, |
159 logging::DONT_LOCK_LOG_FILE, | 202 logging::DONT_LOCK_LOG_FILE, |
160 logging::APPEND_TO_OLD_LOG_FILE); | 203 logging::APPEND_TO_OLD_LOG_FILE); |
161 Display* display = XOpenDisplay(NULL); | 204 Display* display = XOpenDisplay(NULL); |
162 CHECK(display) << "Could not open display"; | 205 CHECK(display) << "Could not open display"; |
163 | 206 |
164 Window window = RootWindow(display, DefaultScreen(display)); | 207 Window window = RootWindow(display, DefaultScreen(display)); |
165 XRRScreenResources* screen_info = XRRGetScreenResources(display, window); | 208 XRRScreenResources* screen_info = XRRGetScreenResources(display, window); |
166 monitor_reconfig::MonitorReconfigureMain main_app(display, screen_info); | 209 monitor_reconfig::MonitorReconfigureMain main_app(display, window, |
210 screen_info); | |
167 main_app.Run(); | 211 main_app.Run(); |
168 return 0; | 212 return 0; |
169 } | 213 } |
OLD | NEW |