Index: src/platform/monitor_reconfig/monitor_reconfigure_main.cc |
diff --git a/src/platform/monitor_reconfig/monitor_reconfigure_main.cc b/src/platform/monitor_reconfig/monitor_reconfigure_main.cc |
index 52f30fa461e851b4d18e1573e5fb50396f910ff4..e0e07a3c2b51e3dbedd18297ab61436c7eff7249 100644 |
--- a/src/platform/monitor_reconfig/monitor_reconfigure_main.cc |
+++ b/src/platform/monitor_reconfig/monitor_reconfigure_main.cc |
@@ -4,19 +4,26 @@ |
#include "monitor_reconfig/monitor_reconfigure_main.h" |
+#include <algorithm> |
#include <cstdio> |
#include <cstdlib> |
#include "base/logging.h" |
+#include "base/string_util.h" |
using std::map; |
+using std::sort; |
+using std::string; |
+using std::vector; |
namespace monitor_reconfig { |
MonitorReconfigureMain::MonitorReconfigureMain(Display* display, |
XRRScreenResources* screen_info) |
: display_(display), |
- screen_info_(screen_info) { |
+ screen_info_(screen_info), |
+ lcd_output_(NULL), |
+ external_output_(NULL) { |
for (int i = 0; i < screen_info_->nmode; ++i) { |
XRRModeInfo* current_mode = &screen_info_->modes[i]; |
mode_map_[current_mode->id] = current_mode; |
@@ -30,126 +37,131 @@ void MonitorReconfigureMain::DetermineOutputs() { |
XRROutputInfo* second_output = |
XRRGetOutputInfo(display_, screen_info_, screen_info_->outputs[1]); |
- static const char* kNotebookOutputName = "LVDS1"; |
- if (strcmp(first_output->name, kNotebookOutputName) == 0) { |
- notebook_output_ = first_output; |
+ static const char* kLcdOutputName = "LVDS1"; |
+ if (strcmp(first_output->name, kLcdOutputName) == 0) { |
+ lcd_output_ = first_output; |
external_output_ = second_output; |
} else { |
- notebook_output_ = second_output; |
+ lcd_output_ = second_output; |
external_output_ = first_output; |
} |
- for (int i = 0; i < notebook_output_->nmode; ++i) { |
- XRRModeInfo* mode = mode_map_[notebook_output_->modes[i]]; |
- LOG(INFO) << "notebook mode: " << mode->width << "x" << mode->height; |
+ LOG(INFO) << "LCD name: " << lcd_output_->name; |
+ for (int i = 0; i < lcd_output_->nmode; ++i) { |
+ XRRModeInfo* mode = mode_map_[lcd_output_->modes[i]]; |
+ LOG(INFO) << " Mode: " << mode->width << "x" << mode->height; |
} |
+ |
+ LOG(INFO) << "External name: " << external_output_->name; |
for (int i = 0; i < external_output_->nmode; ++i) { |
XRRModeInfo* mode = mode_map_[external_output_->modes[i]]; |
- LOG(INFO) << "external mode: " << mode->width << "x" << mode->height; |
+ LOG(INFO) << " Mode: " << mode->width << "x" << mode->height; |
} |
} |
- |
-XRRModeInfo* MonitorReconfigureMain::FindMaxResolution(XRROutputInfo* output) { |
- XRRModeInfo* mode_return = NULL; |
- for (int i = 0; i < output->nmode; ++i) { |
- XRRModeInfo* current_mode = mode_map_[output->modes[i]]; |
- if (mode_return == NULL) { |
- mode_return = current_mode; |
- } else { |
- int n_size = mode_return->height * mode_return->width; |
- int c_size = current_mode->height * current_mode->width; |
- if (c_size > n_size) { |
- mode_return = current_mode; |
- } |
- } |
- } |
- return mode_return; |
-} |
- |
-bool MonitorReconfigureMain::IsEqual(XRRModeInfo* one, XRRModeInfo* two) { |
- return (one->height * one->width) == (two->height * two->width); |
+bool MonitorReconfigureMain::IsExternalMonitorConnected() { |
+ return (external_output_->connection == RR_Connected); |
} |
-bool MonitorReconfigureMain::IsBiggerOrEqual(XRRModeInfo* target, |
- XRRModeInfo* screen) { |
- return ((target->width >= screen->width) && |
- (target->height >= screen->height)); |
+void MonitorReconfigureMain::SortModesByResolution( |
+ const XRROutputInfo& output_info, vector<XRRModeInfo*>* modes_out) { |
+ modes_out->clear(); |
+ for (int i = 0; i < output_info.nmode; ++i) |
+ modes_out->push_back(mode_map_[output_info.modes[i]]); |
+ sort(modes_out->begin(), modes_out->end(), ModeResolutionComparator()); |
} |
-bool MonitorReconfigureMain::IsBetterMatching(XRRModeInfo* target, |
- XRRModeInfo* to_match, |
- XRRModeInfo* previous_best) { |
- if (IsEqual(previous_best, to_match)) |
- return false; |
- // If the current will have some of the display cut off |
- // and the new choice doesn't, choose the new one |
- if ((!IsBiggerOrEqual(previous_best, to_match)) && |
- (IsBiggerOrEqual(target, to_match))) { |
- return true; |
- // If the current one isn't cropped and the new one would |
- // get cropped |
- } else if (IsBiggerOrEqual(previous_best, to_match) && |
- !IsBiggerOrEqual(target, to_match)) { |
- return false; |
- // Case if the current is bigger than the matching but the new target falls |
- // between the current and the matching (so it's closer to the matching) |
- } else if (IsBiggerOrEqual(previous_best, to_match)) { |
- return !IsBiggerOrEqual(target, previous_best); |
+bool MonitorReconfigureMain::FindBestResolutions( |
+ string* lcd_resolution, |
+ string* external_resolution, |
+ string* screen_resolution) { |
+ DCHECK(lcd_resolution); |
+ DCHECK(external_resolution); |
+ DCHECK(screen_resolution); |
+ |
+ vector<XRRModeInfo*> lcd_modes, external_modes; |
+ SortModesByResolution(*lcd_output_, &lcd_modes); |
+ SortModesByResolution(*external_output_, &external_modes); |
+ DCHECK(!lcd_modes.empty()); |
+ DCHECK(!external_modes.empty()); |
+ |
+ if ((lcd_modes[0]->width * lcd_modes[0]->height) >= |
+ (external_modes[0]->width * external_modes[0]->height)) { |
+ return FindNearestResolutions( |
+ lcd_modes, external_modes, |
+ lcd_resolution, external_resolution, screen_resolution); |
} else { |
- // Final case, we know the current is smaller than the matching |
- // We just need to check if the new will bring us closer to the matching |
- return IsBiggerOrEqual(target, previous_best); |
+ return FindNearestResolutions( |
+ external_modes, lcd_modes, |
+ external_resolution, lcd_resolution, screen_resolution); |
} |
} |
-XRRModeInfo* MonitorReconfigureMain::FindBestMatchingResolution( |
- XRRModeInfo* matching_mode) { |
- // Need a min mode to increase from |
- XRRModeInfo min_mode; |
- min_mode.height = 0; |
- min_mode.width = 0; |
- XRRModeInfo* best_mode = &min_mode; |
- // Match horizontal if notebook is wider, o/w match vertical |
- for (int i = 0; i < external_output_->nmode; ++i) { |
- XRRModeInfo* current_mode = mode_map_[external_output_->modes[i]]; |
- if (IsBetterMatching(current_mode, matching_mode, best_mode)) |
- best_mode = current_mode; |
+bool MonitorReconfigureMain::FindNearestResolutions( |
+ const vector<XRRModeInfo*>& larger_device_modes, |
+ const vector<XRRModeInfo*>& smaller_device_modes, |
+ string* larger_resolution, |
+ string* smaller_resolution, |
+ string* screen_resolution) { |
+ DCHECK(larger_resolution); |
+ DCHECK(smaller_resolution); |
+ |
+ // Start with the best that the smaller device has to offer. |
+ smaller_resolution->assign(smaller_device_modes[0]->name); |
+ *screen_resolution = *smaller_resolution; |
+ int smaller_width = smaller_device_modes[0]->width; |
+ int smaller_height = smaller_device_modes[0]->height; |
+ |
+ for (vector<XRRModeInfo*>::const_reverse_iterator it = |
+ larger_device_modes.rbegin(); |
+ it != larger_device_modes.rend(); ++it) { |
+ if ((*it)->width >= smaller_width && (*it)->height >= smaller_height) { |
+ larger_resolution->assign((*it)->name); |
+ return true; |
+ } |
} |
- if (best_mode == &min_mode) |
- best_mode = NULL; |
- return best_mode; |
+ |
+ LOG(WARNING) << "Failed to find a resolution from larger device " |
+ << "exceeding chosen resolution from smaller device (" |
+ << *smaller_resolution << ")"; |
+ return false; |
} |
-void MonitorReconfigureMain::SetResolutions(XRRModeInfo* notebook_mode, |
- XRRModeInfo* external_mode, |
- XRRModeInfo* overall_screen_size) { |
- // We use xrandr script to set modes |
- char buffer[512]; |
- snprintf(buffer, sizeof(buffer), "xrandr --output %s --mode %s", |
- external_output_->name, external_mode->name); |
- system(buffer); |
- snprintf(buffer, sizeof(buffer), "xrandr --output %s --mode %s", |
- notebook_output_->name, notebook_mode->name); |
- system(buffer); |
- snprintf(buffer, sizeof(buffer), "xrandr --fb %s", overall_screen_size->name); |
- system(buffer); |
+bool MonitorReconfigureMain::SetDeviceResolution( |
+ const std::string& device_name, const std::string& resolution) { |
+ string command = StringPrintf("xrandr --output %s --mode %s", |
+ device_name.c_str(), resolution.c_str()); |
+ LOG(INFO) << "Running " << command.c_str(); |
+ return system(command.c_str()) == 0; |
+} |
+ |
+bool MonitorReconfigureMain::SetScreenResolution( |
+ const std::string& resolution) { |
+ string command = StringPrintf("xrandr --fb %s", resolution.c_str()); |
+ LOG(INFO) << "Running " << command.c_str(); |
+ return system(command.c_str()) == 0; |
} |
void MonitorReconfigureMain::Run() { |
- if (!IsExternalMonitorConnected()) |
+ // If there's no external monitor connected, just use the highest resolution |
+ // supported by the LCD. |
+ if (!IsExternalMonitorConnected()) { |
+ LOG(INFO) << "No external monitor connected; using max LCD resolution"; |
+ vector<XRRModeInfo*> lcd_modes; |
+ SortModesByResolution(*lcd_output_, &lcd_modes); |
+ CHECK(!lcd_modes.empty()); |
+ SetDeviceResolution(lcd_output_->name, lcd_modes[0]->name); |
+ SetScreenResolution(lcd_modes[0]->name); |
return; |
+ } |
- // Find the max resolution for the notebook |
- XRRModeInfo* notebook_mode = FindMaxResolution(notebook_output_); |
- // Find the best mode for external output relative to above mode |
- XRRModeInfo* external_mode = FindBestMatchingResolution(notebook_mode); |
- // Set the resolutions accordingly |
- SetResolutions(notebook_mode, external_mode, notebook_mode); |
-} |
- |
-bool MonitorReconfigureMain::IsExternalMonitorConnected() { |
- return (external_output_->connection == RR_Connected); |
+ string lcd_resolution, external_resolution, screen_resolution; |
+ CHECK(FindBestResolutions(&lcd_resolution, |
+ &external_resolution, |
+ &screen_resolution)); |
+ SetDeviceResolution(lcd_output_->name, lcd_resolution); |
+ SetDeviceResolution(external_output_->name, external_resolution); |
+ SetScreenResolution(screen_resolution); |
} |
} // end namespace monitor_reconfig |