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 lcd_output_info_(NULL), |
34 external_output_(0), | |
35 external_output_info_(NULL) { | |
30 for (int i = 0; i < screen_info_->nmode; ++i) { | 36 for (int i = 0; i < screen_info_->nmode; ++i) { |
31 XRRModeInfo* current_mode = &screen_info_->modes[i]; | 37 XRRModeInfo* current_mode = &screen_info_->modes[i]; |
32 mode_map_[current_mode->id] = current_mode; | 38 mode_map_[current_mode->id] = current_mode; |
33 } | 39 } |
34 DetermineOutputs(); | 40 DetermineOutputs(); |
35 } | 41 } |
36 | 42 |
37 void MonitorReconfigureMain::Run() { | 43 void MonitorReconfigureMain::Run() { |
38 vector<ResolutionSelector::Mode> lcd_modes; | 44 vector<ResolutionSelector::Mode> lcd_modes; |
39 SortModesByResolution(*lcd_output_, &lcd_modes); | 45 SortModesByResolution(lcd_output_, &lcd_modes); |
40 DCHECK(!lcd_modes.empty()); | 46 DCHECK(!lcd_modes.empty()); |
41 | 47 |
42 vector<ResolutionSelector::Mode> external_modes; | 48 vector<ResolutionSelector::Mode> external_modes; |
43 if (IsExternalMonitorConnected()) { | 49 if (IsExternalMonitorConnected()) { |
44 SortModesByResolution(*external_output_, &external_modes); | 50 SortModesByResolution(external_output_, &external_modes); |
45 DCHECK(!external_modes.empty()); | 51 DCHECK(!external_modes.empty()); |
46 } | 52 } |
47 | 53 |
48 ResolutionSelector selector; | 54 ResolutionSelector selector; |
49 string lcd_resolution, external_resolution, screen_resolution; | 55 ResolutionSelector::Mode lcd_resolution(0, 0, "", 0); |
Daniel Erat
2011/03/25 03:39:02
i think that it's okay to make an additional c'tor
marcheu
2011/03/25 17:39:42
Done.
| |
56 ResolutionSelector::Mode external_resolution(0, 0, "", 0); | |
57 ResolutionSelector::Mode screen_resolution(0, 0, "", 0); | |
58 | |
50 CHECK(selector.FindBestResolutions(lcd_modes, | 59 CHECK(selector.FindBestResolutions(lcd_modes, |
51 external_modes, | 60 external_modes, |
52 &lcd_resolution, | 61 &lcd_resolution, |
53 &external_resolution, | 62 &external_resolution, |
54 &screen_resolution)); | 63 &screen_resolution)); |
55 CHECK(!lcd_resolution.empty() || !external_resolution.empty()); | 64 CHECK(!lcd_resolution.name.empty() || !external_resolution.name.empty()); |
65 | |
66 // Grab the server during mode changes. | |
67 XGrabServer(display_); | |
56 | 68 |
57 // Disable the LCD if we were told to do so (because we're using a higher | 69 // 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). | 70 // resolution that'd be clipped on the LCD). |
59 if (lcd_resolution.empty()) | 71 // Otherwise enable the LCD if appropriate. |
60 DisableDevice(lcd_output_->name); | 72 if (lcd_resolution.name.empty()) |
73 DisableDevice(lcd_output_, lcd_output_info_); | |
74 else | |
75 SetDeviceResolution(lcd_output_, lcd_output_info_, lcd_resolution); | |
61 | 76 |
62 // If there's no external output connected, disable the device before we try | 77 // 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 | 78 // 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 | 79 // trying to set the screen to a smaller size than what the now-unplugged |
65 // device was using. | 80 // device was using. |
66 if (external_resolution.empty()) | 81 // Otherwise enable the external device if appropriate. |
67 DisableDevice(external_output_->name); | 82 if (external_resolution.name.empty()) |
83 DisableDevice(external_output_, external_output_info_); | |
84 else | |
85 SetDeviceResolution(external_output_, external_output_info_, | |
86 external_resolution); | |
68 | 87 |
69 // Set the fb to try to avoid the driver's "crtc has no fb" message. | 88 // 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); | 89 SetScreenResolution(screen_resolution); |
73 | 90 |
74 // Enable the LCD if appropriate. | 91 if (!lcd_resolution.name.empty()) |
Daniel Erat
2011/03/25 03:39:02
i think that something went horribly wrong here an
marcheu
2011/03/25 17:39:42
Indeed. Oops.
| |
75 if (!lcd_resolution.empty()) | |
76 SetDeviceResolution(lcd_output_->name, lcd_resolution); | |
77 | 92 |
78 // Enable the external device if appropriate. | 93 if (!external_resolution.name.empty()) |
79 if (!external_resolution.empty()) | 94 |
80 SetDeviceResolution(external_output_->name, external_resolution); | 95 // Now let the server go and sync all changes. |
96 XUngrabServer(display_); | |
97 XSync(display_, False); | |
81 } | 98 } |
82 | 99 |
83 void MonitorReconfigureMain::DetermineOutputs() { | 100 void MonitorReconfigureMain::DetermineOutputs() { |
84 CHECK(screen_info_->noutput > 1) << "Expected at least two outputs"; | 101 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 | 102 |
90 if (strcmp(first_output->name, kLcdOutputName) == 0) { | 103 RROutput first_output = screen_info_->outputs[0]; |
104 RROutput second_output = screen_info_->outputs[1]; | |
105 | |
106 XRROutputInfo* first_output_info = | |
107 XRRGetOutputInfo(display_, screen_info_, first_output); | |
108 XRROutputInfo* second_output_info = | |
109 XRRGetOutputInfo(display_, screen_info_, second_output); | |
110 | |
111 if (strcmp(first_output_info->name, kLcdOutputName) == 0) { | |
91 lcd_output_ = first_output; | 112 lcd_output_ = first_output; |
113 lcd_output_info_ = first_output_info; | |
92 external_output_ = second_output; | 114 external_output_ = second_output; |
115 external_output_info_ = second_output_info; | |
Daniel Erat
2011/03/25 03:39:02
can you add a check earlier in this method to make
marcheu
2011/03/25 17:39:42
Done.
| |
93 } else { | 116 } else { |
94 lcd_output_ = second_output; | 117 lcd_output_ = second_output; |
118 lcd_output_info_ = second_output_info; | |
95 external_output_ = first_output; | 119 external_output_ = first_output; |
120 external_output_info_ = first_output_info; | |
96 } | 121 } |
97 | 122 |
98 LOG(INFO) << "LCD name: " << lcd_output_->name; | 123 LOG(INFO) << "LCD name: " << lcd_output_info_->name << " (xid " |
99 for (int i = 0; i < lcd_output_->nmode; ++i) { | 124 << lcd_output_ << ")"; |
100 XRRModeInfo* mode = mode_map_[lcd_output_->modes[i]]; | 125 for (int i = 0; i < lcd_output_info_->nmode; ++i) { |
101 LOG(INFO) << " Mode: " << mode->width << "x" << mode->height; | 126 XRRModeInfo* mode = mode_map_[lcd_output_info_->modes[i]]; |
127 LOG(INFO) << " Mode: " << mode->width << "x" << mode->height | |
128 << " (xid " << mode->id << ")"; | |
102 } | 129 } |
103 | 130 |
104 LOG(INFO) << "External name: " << external_output_->name; | 131 LOG(INFO) << "External name: " << external_output_info_->name |
105 for (int i = 0; i < external_output_->nmode; ++i) { | 132 << " (xid " << external_output_ << ")"; |
106 XRRModeInfo* mode = mode_map_[external_output_->modes[i]]; | 133 for (int i = 0; i < external_output_info_->nmode; ++i) { |
107 LOG(INFO) << " Mode: " << mode->width << "x" << mode->height; | 134 XRRModeInfo* mode = mode_map_[external_output_info_->modes[i]]; |
135 LOG(INFO) << " Mode: " << mode->width << "x" << mode->height | |
136 << " (xid " << mode->id << ")"; | |
108 } | 137 } |
109 } | 138 } |
110 | 139 |
111 bool MonitorReconfigureMain::IsExternalMonitorConnected() { | 140 bool MonitorReconfigureMain::IsExternalMonitorConnected() { |
112 return (external_output_->connection == RR_Connected); | 141 return (external_output_info_->connection == RR_Connected); |
113 } | 142 } |
114 | 143 |
115 void MonitorReconfigureMain::SortModesByResolution( | 144 void MonitorReconfigureMain::SortModesByResolution( |
116 const XRROutputInfo& output_info, | 145 RROutput output, |
117 vector<ResolutionSelector::Mode>* modes_out) { | 146 vector<ResolutionSelector::Mode>* modes_out) { |
118 modes_out->clear(); | 147 modes_out->clear(); |
119 | 148 |
120 for (int i = 0; i < output_info.nmode; ++i) { | 149 XRROutputInfo* output_info = XRRGetOutputInfo(display_, screen_info_, output); |
121 const XRRModeInfo* mode = mode_map_[output_info.modes[i]]; | 150 for (int i = 0; i < output_info->nmode; ++i) { |
151 const XRRModeInfo* mode = mode_map_[output_info->modes[i]]; | |
122 DCHECK(mode); | 152 DCHECK(mode); |
153 LOG(INFO) << "Adding mode " << mode->width << " " << mode->height | |
154 << " (xid " << mode->id << ")"; | |
123 modes_out->push_back( | 155 modes_out->push_back( |
124 ResolutionSelector::Mode(mode->width, mode->height, mode->name)); | 156 ResolutionSelector::Mode(mode->width, mode->height, mode->name, |
157 mode->id)); | |
125 } | 158 } |
126 | 159 |
127 sort(modes_out->begin(), modes_out->end(), | 160 sort(modes_out->begin(), modes_out->end(), |
128 ResolutionSelector::ModeResolutionComparator()); | 161 ResolutionSelector::ModeResolutionComparator()); |
162 | |
163 XRRFreeOutputInfo(output_info); | |
129 } | 164 } |
130 | 165 |
131 bool MonitorReconfigureMain::SetDeviceResolution( | 166 bool MonitorReconfigureMain::SetDeviceResolution( |
132 const std::string& device_name, const std::string& resolution) { | 167 RROutput output, const XRROutputInfo* output_info, |
133 string command = StringPrintf("xrandr --output %s --mode %s", | 168 const ResolutionSelector::Mode& resolution) { |
134 device_name.c_str(), resolution.c_str()); | 169 Status s = XRRSetCrtcConfig(display_, screen_info_, output_info->crtcs[0], |
135 LOG(INFO) << "Running " << command.c_str(); | 170 CurrentTime, 0, 0, resolution.id, RR_Rotate_0, |
136 return system(command.c_str()) == 0; | 171 &output, 1); |
172 return (s == RRSetConfigSuccess); | |
137 } | 173 } |
138 | 174 |
139 bool MonitorReconfigureMain::SetScreenResolution( | 175 bool MonitorReconfigureMain::SetScreenResolution( |
140 const std::string& resolution) { | 176 const ResolutionSelector::Mode& resolution) { |
141 string command = StringPrintf("xrandr --fb %s", resolution.c_str()); | 177 int screen = DefaultScreen(display_); |
Daniel Erat
2011/03/25 03:39:02
this variable looks like it isn't being used
marcheu
2011/03/25 17:39:42
Done.
| |
142 LOG(INFO) << "Running " << command.c_str(); | 178 LOG(INFO) << "Setting resolution " << resolution.name.c_str() << " " |
143 return system(command.c_str()) == 0; | 179 << resolution.width << "x" << resolution.height; |
180 XRRSetScreenSize(display_, window_, | |
181 resolution.width, | |
182 resolution.height, | |
183 resolution.width * kInchInMm / kScreenDpi, | |
184 resolution.height * kInchInMm / kScreenDpi); | |
185 | |
186 return true; | |
144 } | 187 } |
145 | 188 |
146 bool MonitorReconfigureMain::DisableDevice(const std::string& device_name) { | 189 bool MonitorReconfigureMain::DisableDevice(RROutput output, |
147 string command = StringPrintf("xrandr --output %s --off", | 190 const XRROutputInfo* output_info) { |
148 device_name.c_str()); | 191 if (!output_info->crtc) |
149 LOG(INFO) << "Running " << command.c_str(); | 192 return true; |
150 return system(command.c_str()) == 0; | 193 LOG(INFO) << "Disabling output " << output_info->name; |
194 Status s = XRRSetCrtcConfig(display_, screen_info_, output_info->crtc, | |
195 CurrentTime, 0, 0, None, RR_Rotate_0, NULL, 0); | |
196 return (s == RRSetConfigSuccess); | |
151 } | 197 } |
152 | 198 |
153 } // end namespace monitor_reconfig | 199 } // end namespace monitor_reconfig |
154 | 200 |
155 int main(int argc, char** argv) { | 201 int main(int argc, char** argv) { |
156 CommandLine::Init(argc, argv); | 202 CommandLine::Init(argc, argv); |
157 logging::InitLogging(NULL, | 203 logging::InitLogging(NULL, |
158 logging::LOG_ONLY_TO_SYSTEM_DEBUG_LOG, | 204 logging::LOG_ONLY_TO_SYSTEM_DEBUG_LOG, |
159 logging::DONT_LOCK_LOG_FILE, | 205 logging::DONT_LOCK_LOG_FILE, |
160 logging::APPEND_TO_OLD_LOG_FILE); | 206 logging::APPEND_TO_OLD_LOG_FILE); |
161 Display* display = XOpenDisplay(NULL); | 207 Display* display = XOpenDisplay(NULL); |
162 CHECK(display) << "Could not open display"; | 208 CHECK(display) << "Could not open display"; |
163 | 209 |
164 Window window = RootWindow(display, DefaultScreen(display)); | 210 Window window = RootWindow(display, DefaultScreen(display)); |
165 XRRScreenResources* screen_info = XRRGetScreenResources(display, window); | 211 XRRScreenResources* screen_info = XRRGetScreenResources(display, window); |
166 monitor_reconfig::MonitorReconfigureMain main_app(display, screen_info); | 212 monitor_reconfig::MonitorReconfigureMain main_app(display, window, |
213 screen_info); | |
167 main_app.Run(); | 214 main_app.Run(); |
215 XRRFreeScreenResources(screen_info); | |
168 return 0; | 216 return 0; |
169 } | 217 } |
OLD | NEW |