| 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
|
|
|