| 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; | 
|  | 56   ResolutionSelector::Mode external_resolution; | 
|  | 57   ResolutionSelector::Mode screen_resolution; | 
|  | 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   // Now let the server go and sync all changes. | 
| 75   if (!lcd_resolution.empty()) | 92   XUngrabServer(display_); | 
| 76     SetDeviceResolution(lcd_output_->name, lcd_resolution); | 93   XSync(display_, False); | 
| 77 |  | 
| 78   // Enable the external device if appropriate. |  | 
| 79   if (!external_resolution.empty()) |  | 
| 80     SetDeviceResolution(external_output_->name, external_resolution); |  | 
| 81 } | 94 } | 
| 82 | 95 | 
| 83 void MonitorReconfigureMain::DetermineOutputs() { | 96 void MonitorReconfigureMain::DetermineOutputs() { | 
| 84   CHECK(screen_info_->noutput > 1) << "Expected at least two outputs"; | 97   CHECK(screen_info_->noutput > 1) << "Expected at least two outputs"; | 
| 85   XRROutputInfo* first_output = | 98   CHECK(!lcd_output_info_); | 
| 86       XRRGetOutputInfo(display_, screen_info_, screen_info_->outputs[0]); | 99   CHECK(!external_output_info_); | 
| 87   XRROutputInfo* second_output = |  | 
| 88       XRRGetOutputInfo(display_, screen_info_, screen_info_->outputs[1]); |  | 
| 89 | 100 | 
| 90   if (strcmp(first_output->name, kLcdOutputName) == 0) { | 101   RROutput first_output = screen_info_->outputs[0]; | 
|  | 102   RROutput second_output = screen_info_->outputs[1]; | 
|  | 103 | 
|  | 104   XRROutputInfo* first_output_info = | 
|  | 105       XRRGetOutputInfo(display_, screen_info_, first_output); | 
|  | 106   XRROutputInfo* second_output_info = | 
|  | 107       XRRGetOutputInfo(display_, screen_info_, second_output); | 
|  | 108 | 
|  | 109   if (strcmp(first_output_info->name, kLcdOutputName) == 0) { | 
| 91     lcd_output_ = first_output; | 110     lcd_output_ = first_output; | 
|  | 111     lcd_output_info_ = first_output_info; | 
| 92     external_output_ = second_output; | 112     external_output_ = second_output; | 
|  | 113     external_output_info_ = second_output_info; | 
| 93   } else { | 114   } else { | 
| 94     lcd_output_ = second_output; | 115     lcd_output_ = second_output; | 
|  | 116     lcd_output_info_ = second_output_info; | 
| 95     external_output_ = first_output; | 117     external_output_ = first_output; | 
|  | 118     external_output_info_ = first_output_info; | 
| 96   } | 119   } | 
| 97 | 120 | 
| 98   LOG(INFO) << "LCD name: " << lcd_output_->name; | 121   LOG(INFO) << "LCD name: " << lcd_output_info_->name << " (xid " | 
| 99   for (int i = 0; i < lcd_output_->nmode; ++i) { | 122             << lcd_output_ << ")"; | 
| 100     XRRModeInfo* mode = mode_map_[lcd_output_->modes[i]]; | 123   for (int i = 0; i < lcd_output_info_->nmode; ++i) { | 
| 101     LOG(INFO) << "  Mode: " << mode->width << "x" << mode->height; | 124     XRRModeInfo* mode = mode_map_[lcd_output_info_->modes[i]]; | 
|  | 125     LOG(INFO) << "  Mode: " << mode->width << "x" << mode->height | 
|  | 126               << " (xid " << mode->id << ")"; | 
| 102   } | 127   } | 
| 103 | 128 | 
| 104   LOG(INFO) << "External name: " << external_output_->name; | 129   LOG(INFO) << "External name: " << external_output_info_->name | 
| 105   for (int i = 0; i < external_output_->nmode; ++i) { | 130             << " (xid " << external_output_ << ")"; | 
| 106     XRRModeInfo* mode = mode_map_[external_output_->modes[i]]; | 131   for (int i = 0; i < external_output_info_->nmode; ++i) { | 
| 107     LOG(INFO) << "  Mode: " << mode->width << "x" << mode->height; | 132     XRRModeInfo* mode = mode_map_[external_output_info_->modes[i]]; | 
|  | 133     LOG(INFO) << "  Mode: " << mode->width << "x" << mode->height | 
|  | 134               << " (xid " << mode->id << ")"; | 
| 108   } | 135   } | 
| 109 } | 136 } | 
| 110 | 137 | 
| 111 bool MonitorReconfigureMain::IsExternalMonitorConnected() { | 138 bool MonitorReconfigureMain::IsExternalMonitorConnected() { | 
| 112   return (external_output_->connection == RR_Connected); | 139   return (external_output_info_->connection == RR_Connected); | 
| 113 } | 140 } | 
| 114 | 141 | 
| 115 void MonitorReconfigureMain::SortModesByResolution( | 142 void MonitorReconfigureMain::SortModesByResolution( | 
| 116     const XRROutputInfo& output_info, | 143     RROutput output, | 
| 117     vector<ResolutionSelector::Mode>* modes_out) { | 144     vector<ResolutionSelector::Mode>* modes_out) { | 
| 118   modes_out->clear(); | 145   modes_out->clear(); | 
| 119 | 146 | 
| 120   for (int i = 0; i < output_info.nmode; ++i) { | 147   XRROutputInfo* output_info = XRRGetOutputInfo(display_, screen_info_, output); | 
| 121     const XRRModeInfo* mode = mode_map_[output_info.modes[i]]; | 148   for (int i = 0; i < output_info->nmode; ++i) { | 
|  | 149     const XRRModeInfo* mode = mode_map_[output_info->modes[i]]; | 
| 122     DCHECK(mode); | 150     DCHECK(mode); | 
|  | 151     LOG(INFO) << "Adding mode " << mode->width << " " << mode->height | 
|  | 152               << " (xid " << mode->id << ")"; | 
| 123     modes_out->push_back( | 153     modes_out->push_back( | 
| 124         ResolutionSelector::Mode(mode->width, mode->height, mode->name)); | 154         ResolutionSelector::Mode(mode->width, mode->height, mode->name, | 
|  | 155                                  mode->id)); | 
| 125   } | 156   } | 
| 126 | 157 | 
| 127   sort(modes_out->begin(), modes_out->end(), | 158   sort(modes_out->begin(), modes_out->end(), | 
| 128        ResolutionSelector::ModeResolutionComparator()); | 159        ResolutionSelector::ModeResolutionComparator()); | 
|  | 160 | 
|  | 161   XRRFreeOutputInfo(output_info); | 
| 129 } | 162 } | 
| 130 | 163 | 
| 131 bool MonitorReconfigureMain::SetDeviceResolution( | 164 bool MonitorReconfigureMain::SetDeviceResolution( | 
| 132     const std::string& device_name, const std::string& resolution) { | 165     RROutput output, const XRROutputInfo* output_info, | 
| 133   string command = StringPrintf("xrandr --output %s --mode %s", | 166     const ResolutionSelector::Mode& resolution) { | 
| 134                                 device_name.c_str(), resolution.c_str()); | 167   Status s = XRRSetCrtcConfig(display_, screen_info_, output_info->crtcs[0], | 
| 135   LOG(INFO) << "Running " << command.c_str(); | 168                               CurrentTime, 0, 0, resolution.id, RR_Rotate_0, | 
| 136   return system(command.c_str()) == 0; | 169                               &output, 1); | 
|  | 170   return (s == RRSetConfigSuccess); | 
| 137 } | 171 } | 
| 138 | 172 | 
| 139 bool MonitorReconfigureMain::SetScreenResolution( | 173 bool MonitorReconfigureMain::SetScreenResolution( | 
| 140     const std::string& resolution) { | 174     const ResolutionSelector::Mode& resolution) { | 
| 141   string command = StringPrintf("xrandr --fb %s", resolution.c_str()); | 175   LOG(INFO) << "Setting resolution " << resolution.name.c_str() << " " | 
| 142   LOG(INFO) << "Running " << command.c_str(); | 176             << resolution.width << "x" << resolution.height; | 
| 143   return system(command.c_str()) == 0; | 177   XRRSetScreenSize(display_, window_, | 
|  | 178                    resolution.width, | 
|  | 179                    resolution.height, | 
|  | 180                    resolution.width * kInchInMm / kScreenDpi, | 
|  | 181                    resolution.height * kInchInMm / kScreenDpi); | 
|  | 182 | 
|  | 183   return true; | 
| 144 } | 184 } | 
| 145 | 185 | 
| 146 bool MonitorReconfigureMain::DisableDevice(const std::string& device_name) { | 186 bool MonitorReconfigureMain::DisableDevice(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(); | 
|  | 212   XRRFreeScreenResources(screen_info); | 
| 168   return 0; | 213   return 0; | 
| 169 } | 214 } | 
| OLD | NEW | 
|---|