From a5792d34938e1fd07110930477a67b42758cf86a Mon Sep 17 00:00:00 2001 From: "oshima@chromium.org" Date: Thu, 1 Aug 2013 11:18:21 +0000 Subject: [PATCH] Add ability to set resolution on external display * OutputConfigurator gets selected resolution via StateController::GetResolutionForDisplay * It only shows one selection per one resolution. Non interlaced takes precedence and best refresh rate is chosen. * Resolution list is added to DisplayInfo. UI can use this to present options to users. * Created separate display_util_x11 for utility functions that depends on xrandr. BUG=230733 TEST=covered by tests. more to come. manual test should be possible after UI is added. (crbug.com/266097) Review URL: https://chromiumcodereview.appspot.com/21297003 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@214997 0039d316-1c4b-4281-b951-d872f2087c98 --- ash/ash.gyp | 4 +- ash/display/display_change_observer_x11.cc | 69 ++++-------- ash/display/display_change_observer_x11.h | 9 +- .../display_change_observer_x11_unittest.cc | 31 ------ ash/display/display_info.cc | 19 ++++ ash/display/display_info.h | 27 ++++- ash/display/display_manager.cc | 28 ++++- ash/display/display_manager.h | 13 ++- ash/display/display_util_x11.cc | 97 ++++++++++++++++ ash/display/display_util_x11.h | 36 ++++++ ash/display/display_util_x11_unittest.cc | 104 ++++++++++++++++++ .../chromeos/display/display_preferences.cc | 19 +++- .../display/display_preferences_unittest.cc | 53 ++++++++- chromeos/display/output_configurator.cc | 48 ++++---- chromeos/display/output_configurator.h | 18 ++- .../display/output_configurator_unittest.cc | 13 ++- chromeos/display/output_util.cc | 81 ++++++++++++++ chromeos/display/output_util.h | 33 ++++++ chromeos/display/output_util_unittest.cc | 90 +++++++++++++++ .../real_output_configurator_delegate.cc | 17 ++- .../real_output_configurator_delegate.h | 3 +- 21 files changed, 691 insertions(+), 121 deletions(-) delete mode 100644 ash/display/display_change_observer_x11_unittest.cc create mode 100644 ash/display/display_util_x11.cc create mode 100644 ash/display/display_util_x11.h create mode 100644 ash/display/display_util_x11_unittest.cc diff --git a/ash/ash.gyp b/ash/ash.gyp index 5c9d6eea90cf..29a3c389f531 100644 --- a/ash/ash.gyp +++ b/ash/ash.gyp @@ -98,6 +98,8 @@ 'display/display_manager.cc', 'display/display_manager.h', 'display/display_pref_util.h', + 'display/display_util_x11.cc', + 'display/display_util_x11.h', 'display/event_transformation_handler.cc', 'display/event_transformation_handler.h', 'display/mirror_window_controller.cc', @@ -791,7 +793,7 @@ }], ['use_x11==1', { 'sources': [ - 'display/display_change_observer_x11_unittest.cc' + 'display/display_util_x11_unittest.cc' ], }], ['chromeos!=1', { diff --git a/ash/display/display_change_observer_x11.cc b/ash/display/display_change_observer_x11.cc index 8fa1730143e6..860a5ea49969 100644 --- a/ash/display/display_change_observer_x11.cc +++ b/ash/display/display_change_observer_x11.cc @@ -15,6 +15,7 @@ #include "ash/display/display_info.h" #include "ash/display/display_layout_store.h" #include "ash/display/display_manager.h" +#include "ash/display/display_util_x11.h" #include "ash/shell.h" #include "base/command_line.h" #include "base/message_loop/message_pump_aurax11.h" @@ -26,40 +27,15 @@ namespace ash { namespace internal { - namespace { // The DPI threshold to detect high density screen. // Higher DPI than this will use device_scale_factor=2. -// Note: This value has to be kept in sync with the mouse/touchpad driver -// which controls mouse pointer acceleration. If you need to update this value, -// please update the bug (crosbug.com/31628) first and make sure that the -// driver will use the same value. -// This value also has to be kept in sync with the value in -// chromeos/display/output_configurator.cc. See crbug.com/130188 const unsigned int kHighDensityDPIThreshold = 160; // 1 inch in mm. const float kInchInMm = 25.4f; -XRRModeInfo* FindMode(XRRScreenResources* screen_resources, XID current_mode) { - for (int m = 0; m < screen_resources->nmode; m++) { - XRRModeInfo *mode = &screen_resources->modes[m]; - if (mode->id == current_mode) - return mode; - } - return NULL; -} - -// A list of bogus sizes in mm that X detects and should be ignored. -// See crbug.com/136533. -const unsigned long kInvalidDisplaySizeList[][2] = { - {40, 30}, - {50, 40}, - {160, 90}, - {160, 100}, -}; - int64 GetDisplayId(XID output, size_t output_index) { int64 display_id; if (chromeos::GetDisplayId(output, output_index, &display_id)) @@ -69,24 +45,6 @@ int64 GetDisplayId(XID output, size_t output_index) { } // namespace -bool ShouldIgnoreSize(unsigned long mm_width, unsigned long mm_height) { - // Ignore if the reported display is smaller than minimum size. - if (mm_width <= kInvalidDisplaySizeList[0][0] || - mm_height <= kInvalidDisplaySizeList[0][1]) { - LOG(WARNING) << "Smaller than minimum display size"; - return true; - } - for (unsigned long i = 1 ; i < arraysize(kInvalidDisplaySizeList); ++i) { - const unsigned long* size = kInvalidDisplaySizeList[i]; - if (mm_width == size[0] && mm_height == size[1]) { - LOG(WARNING) << "Black listed display size detected:" - << size[0] << "x" << size[1]; - return true; - } - } - return false; -} - DisplayChangeObserverX11::DisplayChangeObserverX11() : xdisplay_(base::MessagePumpAuraX11::GetDefaultXDisplay()), x_root_window_(DefaultRootWindow(xdisplay_)), @@ -116,6 +74,21 @@ chromeos::OutputState DisplayChangeObserverX11::GetStateForDisplayIds( chromeos::STATE_DUAL_MIRROR : chromeos::STATE_DUAL_EXTENDED; } +bool DisplayChangeObserverX11::GetResolutionForDisplayId(int64 display_id, + int* width, + int* height) const { + + gfx::Size resolution; + if (!Shell::GetInstance()->display_manager()-> + GetSelectedResolutionForDisplayId(display_id, &resolution)) { + return false; + } + + *width = resolution.width(); + *height = resolution.height(); + return true; +} + void DisplayChangeObserverX11::OnDisplayModeChanged() { XRRScreenResources* screen_resources = XRRGetScreenResources(xdisplay_, x_root_window_); @@ -151,13 +124,14 @@ void DisplayChangeObserverX11::OnDisplayModeChanged() { XRRFreeOutputInfo(output_info); continue; } - XRRCrtcInfo* crtc_info = crtc_info_map[output_info->crtc]; + const XRRCrtcInfo* crtc_info = crtc_info_map[output_info->crtc]; if (!crtc_info) { LOG(WARNING) << "Crtc not found for output: output_index=" << output_index; continue; } - XRRModeInfo* mode = FindMode(screen_resources, crtc_info->mode); + const XRRModeInfo* mode = + chromeos::FindModeInfo(screen_resources, crtc_info->mode); if (!mode) { LOG(WARNING) << "Could not find a mode for the output: output_index=" << output_index; @@ -173,6 +147,10 @@ void DisplayChangeObserverX11::OnDisplayModeChanged() { gfx::Rect display_bounds( crtc_info->x, crtc_info->y, mode->width, mode->height); + std::vector resolutions; + if (!is_internal) + resolutions = GetResolutionList(screen_resources, output_info); + XRRFreeOutputInfo(output_info); std::string name = is_internal ? @@ -195,6 +173,7 @@ void DisplayChangeObserverX11::OnDisplayModeChanged() { displays.back().set_device_scale_factor(device_scale_factor); displays.back().SetBounds(display_bounds); displays.back().set_native(true); + displays.back().set_resolutions(resolutions); } // Free all allocated resources. diff --git a/ash/display/display_change_observer_x11.h b/ash/display/display_change_observer_x11.h index 3d13e0d0147c..67811515b19a 100644 --- a/ash/display/display_change_observer_x11.h +++ b/ash/display/display_change_observer_x11.h @@ -31,6 +31,9 @@ class DisplayChangeObserverX11 // chromeos::OutputConfigurator::StateController overrides: virtual chromeos::OutputState GetStateForDisplayIds( const std::vector& outputs) const OVERRIDE; + virtual bool GetResolutionForDisplayId(int64 display_id, + int* width, + int* height) const OVERRIDE; // Overriden from chromeos::OutputConfigurator::Observer: virtual void OnDisplayModeChanged() OVERRIDE; @@ -48,12 +51,6 @@ class DisplayChangeObserverX11 DISALLOW_COPY_AND_ASSIGN(DisplayChangeObserverX11); }; -// Returns true if the size info in the output_info isn't valid -// and should be ignored. This is exposed for testing. -// |mm_width| and |mm_height| are given in millimeters. -ASH_EXPORT bool ShouldIgnoreSize(unsigned long mm_width, - unsigned long mm_height); - } // namespace internal } // namespace ash diff --git a/ash/display/display_change_observer_x11_unittest.cc b/ash/display/display_change_observer_x11_unittest.cc deleted file mode 100644 index 8f81297a15c6..000000000000 --- a/ash/display/display_change_observer_x11_unittest.cc +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/display/display_change_observer_x11.h" - -// Undefine X's macros used in gtest. -#undef Bool -#undef None - -#include "testing/gtest/include/gtest/gtest.h" - -typedef testing::Test DisplayChangeObserverX11Test; - -namespace ash { -namespace internal { - -TEST_F(DisplayChangeObserverX11Test, TestBlackListedDisplay) { - EXPECT_TRUE(ShouldIgnoreSize(10, 10)); - EXPECT_TRUE(ShouldIgnoreSize(40, 30)); - EXPECT_TRUE(ShouldIgnoreSize(50, 40)); - EXPECT_TRUE(ShouldIgnoreSize(160, 90)); - EXPECT_TRUE(ShouldIgnoreSize(160, 100)); - - EXPECT_FALSE(ShouldIgnoreSize(50, 60)); - EXPECT_FALSE(ShouldIgnoreSize(100, 70)); - EXPECT_FALSE(ShouldIgnoreSize(272, 181)); -} - -} // namespace internal -} // namespace ash diff --git a/ash/display/display_info.cc b/ash/display/display_info.cc index d886a5962a19..8f71e6d0c801 100644 --- a/ash/display/display_info.cc +++ b/ash/display/display_info.cc @@ -22,6 +22,11 @@ namespace ash { namespace internal { +Resolution::Resolution(const gfx::Size& size, bool interlaced) + : size(size), + interlaced(interlaced) { +} + // satic DisplayInfo DisplayInfo::CreateFromSpec(const std::string& spec) { return CreateFromSpecWithID(spec, gfx::Display::kInvalidDisplayID); @@ -148,6 +153,7 @@ void DisplayInfo::Copy(const DisplayInfo& native_info) { bounds_in_pixel_ = native_info.bounds_in_pixel_; size_in_pixel_ = native_info.size_in_pixel_; device_scale_factor_ = native_info.device_scale_factor_; + resolutions_ = native_info.resolutions_; // Copy overscan_insets_in_dip_ if it's not empty. This is for test // cases which use "/o" annotation which sets the overscan inset @@ -214,5 +220,18 @@ std::string DisplayInfo::ToString() const { ui_scale_); } +std::string DisplayInfo::ToFullString() const { + std::string resolutions_str; + std::vector::const_iterator iter = resolutions_.begin(); + for (; iter != resolutions_.end(); ++iter) { + if (!resolutions_str.empty()) + resolutions_str += ","; + resolutions_str += iter->size.ToString(); + if (iter->interlaced) + resolutions_str += "(i)"; + } + return ToString() + ", resolutions=" + resolutions_str; +} + } // namespace internal } // namespace ash diff --git a/ash/display/display_info.h b/ash/display/display_info.h index a679a73807bf..899dd1541a2c 100644 --- a/ash/display/display_info.h +++ b/ash/display/display_info.h @@ -6,6 +6,7 @@ #define ASH_DISPLAY_DISPLAY_INFO_H_ #include +#include #include "ash/ash_export.h" #include "base/gtest_prod_util.h" @@ -16,6 +17,15 @@ namespace ash { namespace internal { +// A struct that represents the display's resolution and +// interlaced info. +struct ASH_EXPORT Resolution { + Resolution(const gfx::Size& size, bool interlaced); + + gfx::Size size; + bool interlaced; +}; + // DisplayInfo contains metadata for each display. This is used to // create |gfx::Display| as well as to maintain extra infomation // to manage displays in ash environment. @@ -114,9 +124,21 @@ class ASH_EXPORT DisplayInfo { void set_native(bool native) { native_ = native; } bool native() const { return native_; } - // Returns a string representation of the DisplayInfo; + const std::vector& resolutions() const { + return resolutions_; + } + void set_resolutions(std::vector& resolution) { + resolutions_.swap(resolution); + } + + // Returns a string representation of the DisplayInfo + // excluding resolutions. std::string ToString() const; + // Returns a string representation of the DisplayInfo + // including resolutions. + std::string ToFullString() const; + private: int64 id_; std::string name_; @@ -134,6 +156,9 @@ class ASH_EXPORT DisplayInfo { // True if this comes from native platform (DisplayChangeObserverX11). bool native_; + + // The list of resolutions supported by this display. + std::vector resolutions_; }; } // namespace internal diff --git a/ash/display/display_manager.cc b/ash/display/display_manager.cc index 48fb914d0f9d..5943f99b1896 100644 --- a/ash/display/display_manager.cc +++ b/ash/display/display_manager.cc @@ -321,11 +321,24 @@ void DisplayManager::SetDisplayUIScale(int64 display_id, UpdateDisplays(display_info_list); } +void DisplayManager::SetDisplayResolution(int64 display_id, + const gfx::Size& resolution) { + DCHECK_NE(gfx::Display::InternalDisplayId(), display_id); + if (gfx::Display::InternalDisplayId() == display_id) + return; + resolutions_[display_id] = resolution; +#if defined(OS_CHROMEOS) && defined(USE_X11) + if (base::chromeos::IsRunningOnChromeOS()) + Shell::GetInstance()->output_configurator()->ScheduleConfigureOutputs(); +#endif +} + void DisplayManager::RegisterDisplayProperty( int64 display_id, gfx::Display::Rotation rotation, float ui_scale, - const gfx::Insets* overscan_insets) { + const gfx::Insets* overscan_insets, + const gfx::Size& resolution_in_pixels) { if (display_info_.find(display_id) == display_info_.end()) { display_info_[display_id] = DisplayInfo(display_id, std::string(""), false); @@ -337,6 +350,19 @@ void DisplayManager::RegisterDisplayProperty( display_info_[display_id].set_ui_scale(ui_scale); if (overscan_insets) display_info_[display_id].SetOverscanInsets(*overscan_insets); + if (!resolution_in_pixels.IsEmpty()) + resolutions_[display_id] = resolution_in_pixels; +} + +bool DisplayManager::GetSelectedResolutionForDisplayId( + int64 id, + gfx::Size* resolution_out) const { + std::map::const_iterator iter = + resolutions_.find(id); + if (iter == resolutions_.end()) + return false; + *resolution_out = iter->second; + return true; } bool DisplayManager::IsDisplayRotationEnabled() const { diff --git a/ash/display/display_manager.h b/ash/display/display_manager.h index bfecbdc3426a..24303e1909b1 100644 --- a/ash/display/display_manager.h +++ b/ash/display/display_manager.h @@ -130,12 +130,20 @@ class ASH_EXPORT DisplayManager // Sets the display's ui scale. void SetDisplayUIScale(int64 display_id, float ui_scale); + // Sets the display's resolution. + void SetDisplayResolution(int64 display_id, const gfx::Size& resolution); + // Register per display properties. |overscan_insets| is NULL if // the display has no custom overscan insets. void RegisterDisplayProperty(int64 display_id, gfx::Display::Rotation rotation, float ui_scale, - const gfx::Insets* overscan_insets); + const gfx::Insets* overscan_insets, + const gfx::Size& resolution_in_pixels); + + // Returns the display's selected resolution. + bool GetSelectedResolutionForDisplayId(int64 display_id, + gfx::Size* resolution_out) const; // Tells if display rotation/ui scaling features are enabled. bool IsDisplayRotationEnabled() const; @@ -270,6 +278,9 @@ class ASH_EXPORT DisplayManager // The mapping from the display ID to its internal data. std::map display_info_; + // Selected resolutions for displays. Key is the displays' ID. + std::map resolutions_; + // When set to true, the host window's resize event updates // the display's size. This is set to true when running on // desktop environment (for debugging) so that resizing the host diff --git a/ash/display/display_util_x11.cc b/ash/display/display_util_x11.cc new file mode 100644 index 000000000000..e662ce237427 --- /dev/null +++ b/ash/display/display_util_x11.cc @@ -0,0 +1,97 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/display/display_util_x11.h" + +#include +#include +#include + +#include "ash/display/display_info.h" +#include "base/logging.h" +#include "chromeos/display/output_util.h" + +namespace ash { +namespace internal { +namespace { + +// A list of bogus sizes in mm that X detects that should be ignored. +// See crbug.com/136533. The first element maintains the minimum +// size required to be valid size. +const unsigned long kInvalidDisplaySizeList[][2] = { + {40, 30}, + {50, 40}, + {160, 90}, + {160, 100}, +}; + +// Resolution list are sorted by the area in pixels and the larger +// one comes first. +struct ResolutionSorter { + bool operator()(const Resolution& a, const Resolution& b) { + return a.size.width() * a.size.height() > b.size.width() * b.size.height(); + } +}; + +} // namespace + +bool ShouldIgnoreSize(unsigned long mm_width, unsigned long mm_height) { + // Ignore if the reported display is smaller than minimum size. + if (mm_width <= kInvalidDisplaySizeList[0][0] || + mm_height <= kInvalidDisplaySizeList[0][1]) { + LOG(WARNING) << "Smaller than minimum display size"; + return true; + } + for (unsigned long i = 1 ; i < arraysize(kInvalidDisplaySizeList); ++i) { + const unsigned long* size = kInvalidDisplaySizeList[i]; + if (mm_width == size[0] && mm_height == size[1]) { + LOG(WARNING) << "Black listed display size detected:" + << size[0] << "x" << size[1]; + return true; + } + } + return false; +} + +std::vector GetResolutionList( + XRRScreenResources* screen_resources, + XRROutputInfo* output_info) { + typedef std::map, Resolution> ResolutionMap; + + ResolutionMap resolution_map; + + for (int i = 0; i < output_info->nmode; i++) { + RRMode mode = output_info->modes[i]; + const XRRModeInfo* info = chromeos::FindModeInfo(screen_resources, mode); + DCHECK(info); + // Just ignore bad entry on Release build. + if (!info) + continue; + ResolutionMap::key_type size = std::make_pair(info->width, info->height); + bool interlaced = (info->modeFlags & RR_Interlace) != 0; + + ResolutionMap::iterator iter = resolution_map.find(size); + + // Add new resolution if it's new size or override interlaced mode. + if (iter == resolution_map.end()) { + resolution_map.insert(ResolutionMap::value_type( + size, + Resolution(gfx::Size(info->width, info->height), interlaced))); + } else if (iter->second.interlaced && !interlaced) { + iter->second.interlaced = false; + } + } + + std::vector resolution_list; + for (ResolutionMap::const_iterator iter = resolution_map.begin(); + iter != resolution_map.end(); + ++iter) { + resolution_list.push_back(iter->second); + } + std::sort(resolution_list.begin(), resolution_list.end(), ResolutionSorter()); + return resolution_list; +} + +} // namespace internal +} // namespace ash diff --git a/ash/display/display_util_x11.h b/ash/display/display_util_x11.h new file mode 100644 index 000000000000..6647688ce1c7 --- /dev/null +++ b/ash/display/display_util_x11.h @@ -0,0 +1,36 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_DISPLAY_DISPLAY_UTIL_X11_H_ +#define ASH_DISPLAY_DISPLAY_UTIL_X11_H_ + +#include + +#include "ash/ash_export.h" +#include "ash/display/display_info.h" + +struct _XRRScreenResources; +typedef _XRRScreenResources XRRScreenResources; +struct _XRROutputInfo; +typedef _XRROutputInfo XRROutputInfo; + +namespace ash { +namespace internal { +struct Resolution; + +// Returns true if the size info in the output_info isn't valid +// and should be ignored. This is exposed for testing. +// |mm_width| and |mm_height| are given in millimeters. +ASH_EXPORT bool ShouldIgnoreSize(unsigned long mm_width, + unsigned long mm_height); + +// Returns the resolution list. +ASH_EXPORT std::vector GetResolutionList( + XRRScreenResources* screen_resources, + XRROutputInfo* output_info); + +} // namespace internal +} // namespace ash + +#endif // ASH_DISPLAY_DISPLAY_UTIL_X11_H_ diff --git a/ash/display/display_util_x11_unittest.cc b/ash/display/display_util_x11_unittest.cc new file mode 100644 index 000000000000..f534a28dcbbb --- /dev/null +++ b/ash/display/display_util_x11_unittest.cc @@ -0,0 +1,104 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/display/display_util_x11.h" + +#include + +// Undefine X's macros used in gtest. +#undef Bool +#undef None + +#include "chromeos/display/output_util.h" +#include "testing/gtest/include/gtest/gtest.h" + +typedef testing::Test DisplayUtilX11Test; + +namespace ash { +namespace internal { + +TEST_F(DisplayUtilX11Test, TestBlackListedDisplay) { + EXPECT_TRUE(ShouldIgnoreSize(10, 10)); + EXPECT_TRUE(ShouldIgnoreSize(40, 30)); + EXPECT_TRUE(ShouldIgnoreSize(50, 40)); + EXPECT_TRUE(ShouldIgnoreSize(160, 90)); + EXPECT_TRUE(ShouldIgnoreSize(160, 100)); + + EXPECT_FALSE(ShouldIgnoreSize(50, 60)); + EXPECT_FALSE(ShouldIgnoreSize(100, 70)); + EXPECT_FALSE(ShouldIgnoreSize(272, 181)); +} + +TEST_F(DisplayUtilX11Test, GetResolutionList) { + XRRScreenResources resources = {0}; + RROutput outputs[] = {1}; + resources.noutput = arraysize(outputs); + resources.outputs = outputs; + XRRModeInfo modes[] = { + // id, width, height, interlaced, refresh rate + chromeos::test::CreateModeInfo(11, 1920, 1200, false, 60.0f), + + // different rates + chromeos::test::CreateModeInfo(12, 1920, 1080, false, 30.0f), + chromeos::test::CreateModeInfo(13, 1920, 1080, false, 50.0f), + chromeos::test::CreateModeInfo(14, 1920, 1080, false, 40.0f), + + // interlace vs non interlace + chromeos::test::CreateModeInfo(15, 1280, 720, true, 60.0f), + chromeos::test::CreateModeInfo(16, 1280, 720, false, 40.0f), + + // interlace only + chromeos::test::CreateModeInfo(17, 1024, 768, true, 40.0f), + chromeos::test::CreateModeInfo(18, 1024, 768, true, 60.0f), + + // mixed + chromeos::test::CreateModeInfo(19, 1024, 600, true, 60.0f), + chromeos::test::CreateModeInfo(20, 1024, 600, false, 40.0f), + chromeos::test::CreateModeInfo(21, 1024, 600, false, 50.0f), + + // just one interlaced mode + chromeos::test::CreateModeInfo(22, 640, 480, true, 60.0f), + }; + resources.nmode = arraysize(modes); + resources.modes = modes; + + XRROutputInfo output_info = {0}; + RRMode output_modes[] = { + 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22 + }; + output_info.nmode = arraysize(output_modes); + output_info.modes = output_modes; + + std::vector resolutions = + GetResolutionList(&resources, &output_info); + EXPECT_EQ(6u, resolutions.size()); + EXPECT_EQ("1920x1200", resolutions[0].size.ToString()); + EXPECT_FALSE(resolutions[0].interlaced); + + EXPECT_EQ("1920x1080", resolutions[1].size.ToString()); + EXPECT_FALSE(resolutions[1].interlaced); + + EXPECT_EQ("1280x720", resolutions[2].size.ToString()); + EXPECT_FALSE(resolutions[2].interlaced); + + EXPECT_EQ("1024x768", resolutions[3].size.ToString()); + EXPECT_TRUE(resolutions[3].interlaced); + + EXPECT_EQ("1024x600", resolutions[4].size.ToString()); + EXPECT_FALSE(resolutions[4].interlaced); + + EXPECT_EQ("640x480", resolutions[5].size.ToString()); + EXPECT_TRUE(resolutions[5].interlaced); + + // Empty output shouldn't crash. + RRMode empty_output_modes[] = {}; + output_info.nmode = 0; + output_info.modes = empty_output_modes; + + resolutions = GetResolutionList(&resources, &output_info); + EXPECT_EQ(0u, resolutions.size()); +} + +} // namespace internal +} // namespace ash diff --git a/chrome/browser/chromeos/display/display_preferences.cc b/chrome/browser/chromeos/display/display_preferences.cc index a6a6b89f88cd..168404ce39e3 100644 --- a/chrome/browser/chromeos/display/display_preferences.cc +++ b/chrome/browser/chromeos/display/display_preferences.cc @@ -135,13 +135,20 @@ void LoadDisplayProperties() { int ui_scale_value = 0; if (dict_value->GetInteger("ui-scale", &ui_scale_value)) ui_scale = static_cast(ui_scale_value) / 1000.0f; + + int width = 0, height = 0; + dict_value->GetInteger("width", &width); + dict_value->GetInteger("height", &height); + gfx::Size resolution_in_pixels(width, height); + gfx::Insets insets; if (ValueToInsets(*dict_value, &insets)) insets_to_set = &insets; GetDisplayManager()->RegisterDisplayProperty(id, rotation, ui_scale, - insets_to_set); + insets_to_set, + resolution_in_pixels); } } @@ -182,7 +189,8 @@ void StoreCurrentDisplayProperties() { size_t num = display_manager->GetNumDisplays(); for (size_t i = 0; i < num; ++i) { - int64 id = display_manager->GetDisplayAt(i).id(); + const gfx::Display& display = display_manager->GetDisplayAt(i); + int64 id = display.id(); ash::internal::DisplayInfo info = display_manager->GetDisplayInfo(id); scoped_ptr property_value( @@ -190,6 +198,13 @@ void StoreCurrentDisplayProperties() { property_value->SetInteger("rotation", static_cast(info.rotation())); property_value->SetInteger("ui-scale", static_cast(info.ui_scale() * 1000)); + gfx::Size resolution; + if (!display.IsInternal() && + display_manager->GetSelectedResolutionForDisplayId(id, &resolution)) { + property_value->SetInteger("width", resolution.width()); + property_value->SetInteger("height", resolution.height()); + } + if (!info.overscan_insets_in_dip().empty()) InsetsToValue(info.overscan_insets_in_dip(), property_value.get()); pref_data->Set(base::Int64ToString(id), property_value.release()); diff --git a/chrome/browser/chromeos/display/display_preferences_unittest.cc b/chrome/browser/chromeos/display/display_preferences_unittest.cc index 023cfdf34bb6..a319c5b307d5 100644 --- a/chrome/browser/chromeos/display/display_preferences_unittest.cc +++ b/chrome/browser/chromeos/display/display_preferences_unittest.cc @@ -183,7 +183,7 @@ TEST_F(DisplayPreferencesTest, BasicStores) { ash::internal::DisplayManager* display_manager = ash::Shell::GetInstance()->display_manager(); - UpdateDisplay("200x200*2,200x200"); + UpdateDisplay("200x200*2,400x300"); int64 id1 = gfx::Screen::GetNativeScreen()->GetPrimaryDisplay().id(); gfx::Display::SetInternalDisplayId(id1); int64 id2 = ash::ScreenAsh::GetSecondaryDisplay().id(); @@ -231,6 +231,11 @@ TEST_F(DisplayPreferencesTest, BasicStores) { EXPECT_EQ(1, rotation); EXPECT_EQ(1250, ui_scale); + // Internal display never registere the resolution. + int width = 0, height = 0; + EXPECT_FALSE(property->GetInteger("width", &width)); + EXPECT_FALSE(property->GetInteger("height", &height)); + int top = 0, left = 0, bottom = 0, right = 0; EXPECT_TRUE(property->GetInteger("insets_top", &top)); EXPECT_TRUE(property->GetInteger("insets_left", &left)); @@ -252,8 +257,31 @@ TEST_F(DisplayPreferencesTest, BasicStores) { EXPECT_FALSE(property->GetInteger("insets_bottom", &bottom)); EXPECT_FALSE(property->GetInteger("insets_right", &right)); + // Resolution is saved only when the resolution is set + // by DisplayManager::SetDisplayResolution + width = 0; + height = 0; + EXPECT_FALSE(property->GetInteger("width", &width)); + EXPECT_FALSE(property->GetInteger("height", &height)); + + display_manager->SetDisplayResolution(id2, gfx::Size(400, 300)); + display_controller->SetPrimaryDisplayId(id2); + EXPECT_TRUE(properties->GetDictionary(base::Int64ToString(id1), &property)); + width = 0; + height = 0; + // Internal dispaly shouldn't store its resolution. + EXPECT_FALSE(property->GetInteger("width", &width)); + EXPECT_FALSE(property->GetInteger("height", &height)); + + // External dispaly's resolution must be stored this time. + EXPECT_TRUE(properties->GetDictionary(base::Int64ToString(id2), &property)); + EXPECT_TRUE(property->GetInteger("width", &width)); + EXPECT_TRUE(property->GetInteger("height", &height)); + EXPECT_EQ(400, width); + EXPECT_EQ(300, height); + // The layout remains the same. EXPECT_TRUE(displays->GetDictionary(key, &layout_value)); EXPECT_TRUE(ash::DisplayLayout::ConvertFromValue(*layout_value, @@ -287,7 +315,21 @@ TEST_F(DisplayPreferencesTest, BasicStores) { EXPECT_TRUE(layout_value->GetString(kPrimaryIdKey, &primary_id_str)); EXPECT_EQ(base::Int64ToString(id2), primary_id_str); - UpdateDisplay("200x200*2,200x200"); + EXPECT_TRUE(properties->GetDictionary(base::Int64ToString(id1), &property)); + EXPECT_FALSE(property->GetInteger("width", &width)); + EXPECT_FALSE(property->GetInteger("height", &height)); + + // External dispaly's selected resolution must not change + // by mirroring. + EXPECT_TRUE(properties->GetDictionary(base::Int64ToString(id2), &property)); + EXPECT_TRUE(property->GetInteger("width", &width)); + EXPECT_TRUE(property->GetInteger("height", &height)); + EXPECT_EQ(400, width); + EXPECT_EQ(300, height); + + // Set new display's selected resolution. + display_manager->SetDisplayResolution(id2 + 1, gfx::Size(500, 400)); + UpdateDisplay("200x200*2,500x400"); // Update key as the 2nd display gets new id. id2 = ash::ScreenAsh::GetSecondaryDisplay().id(); key = base::Int64ToString(id1) + "," + base::Int64ToString(id2); @@ -301,6 +343,13 @@ TEST_F(DisplayPreferencesTest, BasicStores) { EXPECT_FALSE(mirrored); EXPECT_TRUE(layout_value->GetString(kPrimaryIdKey, &primary_id_str)); EXPECT_EQ(base::Int64ToString(id1), primary_id_str); + + // External dispaly's selected resolution must be updated. + EXPECT_TRUE(properties->GetDictionary(base::Int64ToString(id2), &property)); + EXPECT_TRUE(property->GetInteger("width", &width)); + EXPECT_TRUE(property->GetInteger("height", &height)); + EXPECT_EQ(500, width); + EXPECT_EQ(400, height); } TEST_F(DisplayPreferencesTest, StoreForSwappedDisplay) { diff --git a/chromeos/display/output_configurator.cc b/chromeos/display/output_configurator.cc index 2a51228b9aad..c1d2b30a654b 100644 --- a/chromeos/display/output_configurator.cc +++ b/chromeos/display/output_configurator.cc @@ -104,6 +104,7 @@ OutputConfigurator::OutputSnapshot::OutputSnapshot() current_mode(None), native_mode(None), mirror_mode(None), + selected_mode(None), y(0), height(0), is_internal(false), @@ -196,7 +197,8 @@ void OutputConfigurator::Start(uint32 background_color_argb) { delegate_->GrabServer(); delegate_->InitXRandRExtension(&xrandr_event_base_); - std::vector outputs = delegate_->GetOutputs(); + std::vector outputs = + delegate_->GetOutputs(state_controller_); if (outputs.size() > 1 && background_color_argb) delegate_->SetBackgroundColor(background_color_argb); EnterStateOrFallBackToSoftwareMirroring( @@ -225,7 +227,8 @@ bool OutputConfigurator::SetDisplayPower(DisplayPowerState power_state, return true; delegate_->GrabServer(); - std::vector outputs = delegate_->GetOutputs(); + std::vector outputs = + delegate_->GetOutputs(state_controller_); bool only_if_single_internal_display = flags & kSetDisplayPowerOnlyIfSingleInternalDisplay; @@ -259,7 +262,8 @@ bool OutputConfigurator::SetDisplayMode(OutputState new_state) { } delegate_->GrabServer(); - std::vector outputs = delegate_->GetOutputs(); + std::vector outputs = + delegate_->GetOutputs(state_controller_); bool success = EnterStateOrFallBackToSoftwareMirroring( new_state, power_state_, outputs); delegate_->UngrabServer(); @@ -351,11 +355,25 @@ void OutputConfigurator::ResumeDisplays() { SetDisplayPower(power_state_, kSetDisplayPowerForceProbe); } +void OutputConfigurator::ScheduleConfigureOutputs() { + if (configure_timer_.get()) { + configure_timer_->Reset(); + } else { + configure_timer_.reset(new base::OneShotTimer()); + configure_timer_->Start( + FROM_HERE, + base::TimeDelta::FromMilliseconds(kConfigureDelayMs), + this, + &OutputConfigurator::ConfigureOutputs); + } +} + void OutputConfigurator::ConfigureOutputs() { configure_timer_.reset(); delegate_->GrabServer(); - std::vector outputs = delegate_->GetOutputs(); + std::vector outputs = + delegate_->GetOutputs(state_controller_); OutputState new_state = GetOutputState(outputs, power_state_); bool success = EnterStateOrFallBackToSoftwareMirroring( new_state, power_state_, outputs); @@ -370,19 +388,6 @@ void OutputConfigurator::ConfigureOutputs() { delegate_->SendProjectingStateToPowerManager(IsProjecting(outputs)); } -void OutputConfigurator::ScheduleConfigureOutputs() { - if (configure_timer_.get()) { - configure_timer_->Reset(); - } else { - configure_timer_.reset(new base::OneShotTimer()); - configure_timer_->Start( - FROM_HERE, - base::TimeDelta::FromMilliseconds(kConfigureDelayMs), - this, - &OutputConfigurator::ConfigureOutputs); - } -} - void OutputConfigurator::NotifyOnDisplayChanged() { FOR_EACH_OBSERVER(Observer, observers_, OnDisplayModeChanged()); } @@ -434,14 +439,15 @@ bool OutputConfigurator::EnterState( const OutputSnapshot& output = outputs.size() == 1 ? outputs[0] : (output_power[0] ? outputs[0] : outputs[1]); int width = 0, height = 0; - if (!delegate_->GetModeDetails(output.native_mode, &width, &height, NULL)) + if (!delegate_->GetModeDetails( + output.selected_mode, &width, &height, NULL)) return false; std::vector configs(outputs.size()); for (size_t i = 0; i < outputs.size(); ++i) { configs[i] = CrtcConfig( outputs[i].crtc, 0, 0, - output_power[i] ? outputs[i].native_mode : None, + output_power[i] ? outputs[i].selected_mode : None, outputs[i].output); } delegate_->CreateFrameBuffer(width, height, configs); @@ -509,14 +515,14 @@ bool OutputConfigurator::EnterState( int width = 0, height = 0; for (size_t i = 0; i < outputs.size(); ++i) { - if (!delegate_->GetModeDetails(outputs[i].native_mode, + if (!delegate_->GetModeDetails(outputs[i].selected_mode, &(mode_sizes[i].first), &(mode_sizes[i].second), NULL)) { return false; } configs[i] = CrtcConfig( outputs[i].crtc, 0, (height ? height + kVerticalGap : 0), - output_power[i] ? outputs[i].native_mode : None, + output_power[i] ? outputs[i].selected_mode : None, outputs[i].output); // Retain the full screen size even if all outputs are off so the diff --git a/chromeos/display/output_configurator.h b/chromeos/display/output_configurator.h index 5385b71f4922..a308a4547883 100644 --- a/chromeos/display/output_configurator.h +++ b/chromeos/display/output_configurator.h @@ -55,6 +55,7 @@ class CHROMEOS_EXPORT OutputConfigurator RRMode current_mode; RRMode native_mode; RRMode mirror_mode; + RRMode selected_mode; int y; int height; @@ -114,6 +115,12 @@ class CHROMEOS_EXPORT OutputConfigurator // Called when displays are detected. virtual OutputState GetStateForDisplayIds( const std::vector& display_ids) const = 0; + + // Queries the resolution (|width|x|height|) in pixels + // to select output mode for the given display id. + virtual bool GetResolutionForDisplayId(int64 display_id, + int* width, + int* height) const = 0; }; // Interface for classes that implement software based mirroring. @@ -159,7 +166,8 @@ class CHROMEOS_EXPORT OutputConfigurator // Returns information about the current outputs. // This method may block for 60 milliseconds or more. - virtual std::vector GetOutputs() = 0; + virtual std::vector GetOutputs( + const StateController* state_controller) = 0; // Gets details corresponding to |mode|. Parameters may be NULL. // Returns true on success. @@ -303,14 +311,14 @@ class CHROMEOS_EXPORT OutputConfigurator return mirrored_display_area_ratio_map_; } - private: - // Configure outputs. - void ConfigureOutputs(); - // Configure outputs with |kConfigureDelayMs| delay, // so that time-consuming ConfigureOutputs() won't be called multiple times. void ScheduleConfigureOutputs(); + private: + // Configure outputs. + void ConfigureOutputs(); + // Fires OnDisplayModeChanged() event to the observers. void NotifyOnDisplayChanged(); diff --git a/chromeos/display/output_configurator_unittest.cc b/chromeos/display/output_configurator_unittest.cc index d0308a853848..246a436f3be8 100644 --- a/chromeos/display/output_configurator_unittest.cc +++ b/chromeos/display/output_configurator_unittest.cc @@ -127,8 +127,8 @@ class TestDelegate : public OutputConfigurator::Delegate { AppendAction(GetBackgroundAction(color_argb)); } virtual void ForceDPMSOn() OVERRIDE { AppendAction(kForceDPMS); } - virtual std::vector GetOutputs() - OVERRIDE { + virtual std::vector GetOutputs( + const OutputConfigurator::StateController* controller) OVERRIDE { return outputs_; } virtual bool GetModeDetails( @@ -210,6 +210,12 @@ class TestStateController : public OutputConfigurator::StateController { // OutputConfigurator::StateController overrides: virtual OutputState GetStateForDisplayIds( const std::vector& outputs) const OVERRIDE { return state_; } + virtual bool GetResolutionForDisplayId( + int64 display_id, + int *width, + int *height) const OVERRIDE { + return false; + } private: OutputState state_; @@ -255,6 +261,7 @@ class OutputConfiguratorTest : public testing::Test { o->crtc = 10; o->current_mode = kSmallModeId; o->native_mode = kSmallModeId; + o->selected_mode = kSmallModeId; o->mirror_mode = kSmallModeId; o->y = 0; o->height = kSmallModeHeight; @@ -268,6 +275,7 @@ class OutputConfiguratorTest : public testing::Test { o->crtc = 11; o->current_mode = kBigModeId; o->native_mode = kBigModeId; + o->selected_mode = kBigModeId; o->mirror_mode = kSmallModeId; o->y = 0; o->height = kBigModeHeight; @@ -681,6 +689,7 @@ TEST_F(OutputConfiguratorTest, Headless) { // Connect an external display and check that it's configured correctly. outputs_[0].is_internal = false; outputs_[0].native_mode = kBigModeId; + outputs_[0].selected_mode = kBigModeId; UpdateOutputs(1); EXPECT_TRUE(test_api_.SendOutputChangeEvents(true)); EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab, diff --git a/chromeos/display/output_util.cc b/chromeos/display/output_util.cc index ba26684b565d..d9d291319d54 100644 --- a/chromeos/display/output_util.cc +++ b/chromeos/display/output_util.cc @@ -111,6 +111,16 @@ bool GetOutputDeviceData(XID output, return result; } +float GetRefreshRate(const XRRModeInfo* mode_info) { + if (mode_info->hTotal && mode_info->vTotal) { + return static_cast(mode_info->dotClock) / + (static_cast(mode_info->hTotal) * + static_cast(mode_info->vTotal)); + } else { + return 0.0f; + } +} + } // namespace std::string GetDisplayName(XID output_id) { @@ -321,4 +331,75 @@ bool IsInternalOutputName(const std::string& name) { name.find(kInternal_DSI) == 0; } +const XRRModeInfo* FindModeInfo(const XRRScreenResources* screen_resources, + XID current_mode) { + for (int m = 0; m < screen_resources->nmode; m++) { + XRRModeInfo *mode = &screen_resources->modes[m]; + if (mode->id == current_mode) + return mode; + } + return NULL; +} + +// Find a mode that matches the given size with highest +// reflesh rate. +RRMode FindOutputModeMatchingSize( + const XRRScreenResources* screen_resources, + const XRROutputInfo* output_info, + size_t width, + size_t height) { + RRMode found = None; + float best_rate = 0; + bool non_interlaced_found = false; + for (int i = 0; i < output_info->nmode; ++i) { + RRMode mode = output_info->modes[i]; + const XRRModeInfo* info = FindModeInfo(screen_resources, mode); + + if (info->width == width && info->height == height) { + float rate = GetRefreshRate(info); + + if (info->modeFlags & RR_Interlace) { + if (non_interlaced_found) + continue; + } else { + // Reset the best rate if the non interlaced is + // found the first time. + if (!non_interlaced_found) { + best_rate = rate; + } + non_interlaced_found = true; + } + if (rate < best_rate) + continue; + + found = mode; + best_rate = rate; + } + } + return found; +} + +namespace test { + +XRRModeInfo CreateModeInfo(int id, + int width, + int height, + bool interlaced, + float refresh_rate) { + XRRModeInfo mode_info = {0}; + mode_info.id = id; + mode_info.width = width; + mode_info.height = height; + if (interlaced) + mode_info.modeFlags = RR_Interlace; + if (refresh_rate != 0.0f) { + mode_info.hTotal = 1; + mode_info.vTotal = 1; + mode_info.dotClock = refresh_rate; + } + return mode_info; +} + +} // namespace test + } // namespace chromeos diff --git a/chromeos/display/output_util.h b/chromeos/display/output_util.h index 345759df927f..d464ba6241d8 100644 --- a/chromeos/display/output_util.h +++ b/chromeos/display/output_util.h @@ -13,6 +13,13 @@ // Forward declarations for Xlib and Xrandr. // This is so unused X definitions don't pollute the namespace. typedef unsigned long XID; +typedef XID RRMode; +struct _XRRModeInfo; +typedef _XRRModeInfo XRRModeInfo; +struct _XRRScreenResources; +typedef _XRRScreenResources XRRScreenResources; +struct _XRROutputInfo; +typedef _XRROutputInfo XRROutputInfo; namespace chromeos { @@ -57,6 +64,32 @@ CHROMEOS_EXPORT bool ParseOutputOverscanFlag(const unsigned char* prop, // Returns true if an output named |name| is an internal display. CHROMEOS_EXPORT bool IsInternalOutputName(const std::string& name); +// Find a XRRModeInfo that matches |mode|. +CHROMEOS_EXPORT const XRRModeInfo* FindModeInfo( + const XRRScreenResources* screen_resources, + XID mode); + +// Find a mode that matches the given size with highest refresh +// rate. Non-interlaced mode takes precedence, so non-interlaced mode +// with a lower refresh rate will be used even if there is an interlaced +// mode with a higher refresh rate. +CHROMEOS_EXPORT RRMode FindOutputModeMatchingSize( + const XRRScreenResources* screen_resources, + const XRROutputInfo* output_info, + size_t width, + size_t height); + +namespace test { + +// Creates XRRModeInfo for unit tests. +CHROMEOS_EXPORT XRRModeInfo CreateModeInfo(int id, + int width, + int height, + bool interlaced, + float refresh_rate); + +} // namespace test + } // namespace chromeos #endif // CHROMEOS_DISPLAY_OUTPUT_UTIL_H_ diff --git a/chromeos/display/output_util_unittest.cc b/chromeos/display/output_util_unittest.cc index efd02d367d05..3550c248b4c3 100644 --- a/chromeos/display/output_util_unittest.cc +++ b/chromeos/display/output_util_unittest.cc @@ -7,6 +7,8 @@ #include "base/memory/scoped_ptr.h" #include "testing/gtest/include/gtest/gtest.h" +#include + namespace chromeos { namespace { @@ -244,4 +246,92 @@ TEST(OutputUtilTest, GetDisplayIdFailure) { EXPECT_EQ(-1, id); } +TEST(OutputUtilTest, FindOutputModeMatchingSize) { + XRRScreenResources resources = {0}; + RROutput outputs[] = {1}; + resources.noutput = arraysize(outputs); + resources.outputs = outputs; + XRRModeInfo modes[] = { + // id, width, height, interlaced, refresh rate + test::CreateModeInfo(11, 1920, 1200, false, 60.0f), + + // different rates + test::CreateModeInfo(12, 1920, 1080, false, 30.0f), + test::CreateModeInfo(13, 1920, 1080, false, 50.0f), + test::CreateModeInfo(14, 1920, 1080, false, 40.0f), + test::CreateModeInfo(15, 1920, 1080, false, 0.0f), + + // interlace vs non interlace + test::CreateModeInfo(16, 1280, 720, true, 60.0f), + test::CreateModeInfo(17, 1280, 720, false, 40.0f), + + // interlace only + test::CreateModeInfo(18, 1024, 768, true, 0.0f), + test::CreateModeInfo(19, 1024, 768, true, 40.0f), + test::CreateModeInfo(20, 1024, 768, true, 60.0f), + + // mixed + test::CreateModeInfo(21, 1024, 600, true, 60.0f), + test::CreateModeInfo(22, 1024, 600, false, 40.0f), + test::CreateModeInfo(23, 1024, 600, false, 50.0f), + + // just one interlaced mode + test::CreateModeInfo(24, 640, 480, true, 60.0f), + + // refresh rate not available. + test::CreateModeInfo(25, 320, 200, false, 0.0f), + }; + resources.nmode = arraysize(modes); + resources.modes = modes; + + XRROutputInfo output_info = {0}; + RRMode output_modes[] = { + 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25 + }; + output_info.nmode = arraysize(output_modes); + output_info.modes = output_modes; + + EXPECT_EQ(11u, FindOutputModeMatchingSize(&resources, + &output_info, + 1920, 1200)); + + // Should pick highest refresh rate. + EXPECT_EQ(13u, FindOutputModeMatchingSize(&resources, + &output_info, + 1920, 1080)); + + // Should pick non interlaced mode. + EXPECT_EQ(17u, FindOutputModeMatchingSize(&resources, + &output_info, + 1280, 720)); + + // Interlaced only. Should pick one with the highest refresh rate in + // interlaced mode. + EXPECT_EQ(20u, FindOutputModeMatchingSize(&resources, + &output_info, + 1024, 768)); + + // Mixed: Should pick one with the highest refresh rate in + // interlaced mode. + EXPECT_EQ(23u, FindOutputModeMatchingSize(&resources, + &output_info, + 1024, 600)); + + // Just one interlaced mode. + EXPECT_EQ(24u, FindOutputModeMatchingSize(&resources, + &output_info, + 640, 480)); + + // Refresh rate not available. + EXPECT_EQ(25u, FindOutputModeMatchingSize(&resources, + &output_info, + 320, 200)); + + // No mode found. + EXPECT_EQ(static_cast(None), + FindOutputModeMatchingSize(&resources, + &output_info, + 1440, 900)); +} + } // namespace chromeos diff --git a/chromeos/display/real_output_configurator_delegate.cc b/chromeos/display/real_output_configurator_delegate.cc index 5b0804a7e9e5..0ed04378b766 100644 --- a/chromeos/display/real_output_configurator_delegate.cc +++ b/chromeos/display/real_output_configurator_delegate.cc @@ -105,7 +105,8 @@ void RealOutputConfiguratorDelegate::ForceDPMSOn() { } std::vector -RealOutputConfiguratorDelegate::GetOutputs() { +RealOutputConfiguratorDelegate::GetOutputs( + const OutputConfigurator::StateController* state_controller) { CHECK(screen_) << "Server not grabbed"; std::vector outputs; @@ -150,8 +151,20 @@ RealOutputConfiguratorDelegate::GetOutputs() { break; } } - to_populate.native_mode = GetOutputNativeMode(output_info); + if (to_populate.has_display_id) { + int width = 0, height = 0; + if (state_controller && + state_controller->GetResolutionForDisplayId( + to_populate.display_id, &width, &height)) { + to_populate.selected_mode = + FindOutputModeMatchingSize(screen_, output_info, width, height); + } + } + // Fallback to native mode. + if (to_populate.selected_mode == None) + to_populate.selected_mode = to_populate.native_mode; + to_populate.is_aspect_preserving_scaling = IsOutputAspectPreservingScaling(this_id); to_populate.touch_device_id = None; diff --git a/chromeos/display/real_output_configurator_delegate.h b/chromeos/display/real_output_configurator_delegate.h index ba0b248b6d2c..eeec2ab75b8f 100644 --- a/chromeos/display/real_output_configurator_delegate.h +++ b/chromeos/display/real_output_configurator_delegate.h @@ -37,7 +37,8 @@ class RealOutputConfiguratorDelegate : public OutputConfigurator::Delegate { virtual void SyncWithServer() OVERRIDE; virtual void SetBackgroundColor(uint32 color_argb) OVERRIDE; virtual void ForceDPMSOn() OVERRIDE; - virtual std::vector GetOutputs() OVERRIDE; + virtual std::vector GetOutputs( + const OutputConfigurator::StateController* state_controller) OVERRIDE; virtual bool GetModeDetails( RRMode mode, int* width,