diff options
author | oshima@chromium.org <oshima@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-02-28 23:58:32 +0000 |
---|---|---|
committer | oshima@chromium.org <oshima@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-02-28 23:58:32 +0000 |
commit | 7bb8f443297e0ef3e09c298a58adc6aebdf8a53f (patch) | |
tree | 45fcc9719addee55adb3f3bffffe6fcaa481f99e | |
parent | b969b0a804a1278bcb1828b94809b74e2b6f34d4 (diff) | |
download | chromium_src-7bb8f443297e0ef3e09c298a58adc6aebdf8a53f.zip chromium_src-7bb8f443297e0ef3e09c298a58adc6aebdf8a53f.tar.gz chromium_src-7bb8f443297e0ef3e09c298a58adc6aebdf8a53f.tar.bz2 |
Refactor DisplayInfo/Display - 3rd try
This is a first step to fix overscan issue and implement
screen rotation.
* remove bounds_in_pixel from gfx::Display
* promote DisplayInfo to separate class/file
* All display information is now generated in display_change_observer_x11.cc.
almost no X11 depenency in display_manager.cc
(I'll move FindInternalDisplayID out from display_manager.cc once https://codereview.chromium.org/12217120/ is landed)
This makes testing more consistent with real environment.
* Add DisplayManager::ClearCustomOverscanInsets so that
you can reset the insets to default value.
* Removed obsolete AshTestBase::ChangeDisplayConfig
BUG=174721,119268
TEST=covered by test
Committed: https://src.chromium.org/viewvc/chrome?view=rev&revision=185178
Committed: https://src.chromium.org/viewvc/chrome?view=rev&revision=185230
Review URL: https://chromiumcodereview.appspot.com/12218045
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@185367 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | ash/accelerators/accelerator_controller_unittest.cc | 5 | ||||
-rw-r--r-- | ash/ash.gyp | 2 | ||||
-rw-r--r-- | ash/dip_unittest.cc | 14 | ||||
-rw-r--r-- | ash/display/display_change_observer_x11.cc | 66 | ||||
-rw-r--r-- | ash/display/display_controller.cc | 44 | ||||
-rw-r--r-- | ash/display/display_controller.h | 3 | ||||
-rw-r--r-- | ash/display/display_controller_unittest.cc | 35 | ||||
-rw-r--r-- | ash/display/display_info.cc | 143 | ||||
-rw-r--r-- | ash/display/display_info.h | 130 | ||||
-rw-r--r-- | ash/display/display_manager.cc | 393 | ||||
-rw-r--r-- | ash/display/display_manager.h | 75 | ||||
-rw-r--r-- | ash/display/display_manager_unittest.cc | 221 | ||||
-rw-r--r-- | ash/test/ash_test_base.cc | 10 | ||||
-rw-r--r-- | ash/test/ash_test_base.h | 4 | ||||
-rw-r--r-- | ash/test/display_manager_test_api.cc | 49 | ||||
-rw-r--r-- | ash/test/display_manager_test_api.h | 4 | ||||
-rw-r--r-- | ash/wm/system_gesture_event_filter_unittest.cc | 5 | ||||
-rw-r--r-- | ui/aura/root_window.cc | 1 | ||||
-rw-r--r-- | ui/base/x/events_x.cc | 8 | ||||
-rw-r--r-- | ui/base/x/x11_util.cc | 10 | ||||
-rw-r--r-- | ui/base/x/x11_util.h | 8 | ||||
-rw-r--r-- | ui/gfx/display.cc | 14 | ||||
-rw-r--r-- | ui/gfx/display.h | 10 |
23 files changed, 755 insertions, 499 deletions
diff --git a/ash/accelerators/accelerator_controller_unittest.cc b/ash/accelerators/accelerator_controller_unittest.cc index ccc574d..62b52c2 100644 --- a/ash/accelerators/accelerator_controller_unittest.cc +++ b/ash/accelerators/accelerator_controller_unittest.cc @@ -14,6 +14,7 @@ #include "ash/system/keyboard_brightness/keyboard_brightness_control_delegate.h" #include "ash/system/tray/system_tray_delegate.h" #include "ash/test/ash_test_base.h" +#include "ash/test/display_manager_test_api.h" #include "ash/test/test_shell_delegate.h" #include "ash/volume_control_delegate.h" #include "ash/wm/window_util.h" @@ -313,8 +314,8 @@ class AcceleratorControllerTest : public test::AshTestBase { protected: void EnableInternalDisplay() { - Shell::GetInstance()->display_manager()-> - SetFirstDisplayAsInternalDisplayForTest(); + test::DisplayManagerTestApi(Shell::GetInstance()->display_manager()). + SetFirstDisplayAsInternalDisplay(); } static AcceleratorController* GetController(); diff --git a/ash/ash.gyp b/ash/ash.gyp index a4c6f7c..ec824a4 100644 --- a/ash/ash.gyp +++ b/ash/ash.gyp @@ -81,6 +81,8 @@ 'display/display_controller.h', 'display/display_error_dialog.cc', 'display/display_error_dialog.h', + 'display/display_info.h', + 'display/display_info.cc', 'display/display_manager.cc', 'display/display_manager.h', 'display/event_transformation_handler.cc', diff --git a/ash/dip_unittest.cc b/ash/dip_unittest.cc index 1df1ec7..2c00d71a 100644 --- a/ash/dip_unittest.cc +++ b/ash/dip_unittest.cc @@ -5,6 +5,7 @@ #include <algorithm> #include <vector> +#include "ash/display/display_manager.h" #include "ash/launcher/launcher.h" #include "ash/shell.h" #include "ash/test/ash_test_base.h" @@ -29,7 +30,7 @@ typedef ash::test::AshTestBase DIPTest; // Test if the WM sets correct work area under different density. TEST_F(DIPTest, WorkArea) { - ChangeDisplayConfig(1.0f, gfx::Rect(0, 0, 1000, 900)); + UpdateDisplay("1000x900*1.0f"); aura::RootWindow* root = Shell::GetPrimaryRootWindow(); const gfx::Display display = @@ -40,13 +41,16 @@ TEST_F(DIPTest, WorkArea) { EXPECT_EQ("0,0 1000x852", work_area.ToString()); EXPECT_EQ("0,0,48,0", display.bounds().InsetsFrom(work_area).ToString()); - ChangeDisplayConfig(2.0f, gfx::Rect(0, 0, 2000, 1800)); + UpdateDisplay("2000x1800*2.0f"); + gfx::Screen* screen = Shell::GetScreen(); - const gfx::Display display_2x = - Shell::GetScreen()->GetDisplayNearestWindow(root); + const gfx::Display display_2x = screen->GetDisplayNearestWindow(root); + const internal::DisplayInfo display_info_2x = + Shell::GetInstance()->display_manager()->GetDisplayInfo(display_2x); // The |bounds_in_pixel()| should report bounds in pixel coordinate. - EXPECT_EQ("0,0 2000x1800", display_2x.bounds_in_pixel().ToString()); + EXPECT_EQ("1,1 2000x1800", + display_info_2x.bounds_in_pixel().ToString()); // Aura and views coordinates are in DIP, so they their bounds do not change. EXPECT_EQ("0,0 1000x900", display_2x.bounds().ToString()); diff --git a/ash/display/display_change_observer_x11.cc b/ash/display/display_change_observer_x11.cc index b7114ce..073b515 100644 --- a/ash/display/display_change_observer_x11.cc +++ b/ash/display/display_change_observer_x11.cc @@ -11,9 +11,12 @@ #include <X11/extensions/Xrandr.h> +#include "ash/display/display_info.h" #include "ash/display/display_manager.h" #include "ash/shell.h" #include "base/message_pump_aurax11.h" +#include "grit/ash_strings.h" +#include "ui/base/l10n/l10n_util.h" #include "ui/base/x/x11_util.h" #include "ui/compositor/dip_util.h" #include "ui/gfx/display.h" @@ -45,7 +48,7 @@ XRRModeInfo* FindMode(XRRScreenResources* screen_resources, XID current_mode) { return NULL; } -bool CompareDisplayY(const gfx::Display& lhs, const gfx::Display& rhs) { +bool CompareDisplayY(const DisplayInfo& lhs, const DisplayInfo& rhs) { return lhs.bounds_in_pixel().y() < rhs.bounds_in_pixel().y(); } @@ -76,6 +79,12 @@ bool ShouldIgnoreSize(XRROutputInfo *output_info) { return false; } +std::string GetDisplayName(XID output_id) { + std::string display_name; + ui::GetOutputDeviceData(output_id, NULL, NULL, &display_name); + return display_name; +} + } // namespace DisplayChangeObserverX11::DisplayChangeObserverX11() @@ -101,15 +110,14 @@ void DisplayChangeObserverX11::OnDisplayModeChanged() { crtc_info_map[crtc_id] = crtc_info; } - std::vector<gfx::Display> displays; + std::vector<DisplayInfo> displays; std::set<int> y_coords; std::set<int64> ids; for (int output_index = 0; output_index < screen_resources->noutput; output_index++) { + XID output = screen_resources->outputs[output_index]; XRROutputInfo *output_info = - XRRGetOutputInfo(xdisplay_, - screen_resources, - screen_resources->outputs[output_index]); + XRRGetOutputInfo(xdisplay_, screen_resources, output); if (output_info->connection != RR_Connected) { XRRFreeOutputInfo(output_info); continue; @@ -129,7 +137,6 @@ void DisplayChangeObserverX11::OnDisplayModeChanged() { // Mirrored monitors have the same y coordinates. if (y_coords.find(crtc_info->y) != y_coords.end()) continue; - displays.push_back(gfx::Display()); float device_scale_factor = 1.0f; if (!ShouldIgnoreSize(output_info) && @@ -137,27 +144,45 @@ void DisplayChangeObserverX11::OnDisplayModeChanged() { kHighDensityDPIThreshold) { device_scale_factor = 2.0f; } - displays.back().SetScaleAndBounds( - device_scale_factor, - gfx::Rect(crtc_info->x, crtc_info->y, mode->width, mode->height)); + gfx::Rect display_bounds( + crtc_info->x, crtc_info->y, mode->width, mode->height); + + bool is_internal = chromeos::OutputConfigurator::IsInternalOutputName( + std::string(output_info->name)); + XRRFreeOutputInfo(output_info); + + std::string name = is_internal ? + l10n_util::GetStringUTF8(IDS_ASH_INTERNAL_DISPLAY_NAME) : + GetDisplayName(output); + if (name.empty()) + name = l10n_util::GetStringUTF8(IDS_ASH_STATUS_TRAY_UNKNOWN_DISPLAY_NAME); + + bool has_overscan = false; + ui::GetOutputOverscanFlag(output, &has_overscan); uint16 manufacturer_id = 0; uint16 product_code = 0; - if (ui::GetOutputDeviceData(screen_resources->outputs[output_index], - &manufacturer_id, &product_code, NULL) && + int64 id = gfx::Display::kInvalidDisplayID; + + if (ui::GetOutputDeviceData( + output, &manufacturer_id, &product_code, NULL) && manufacturer_id != 0) { // An ID based on display's index will be assigned later if this call // fails. int64 new_id = gfx::Display::GetID( manufacturer_id, product_code, output_index); - if (ids.find(new_id) == ids.end()) { - displays.back().set_id(new_id); - ids.insert(new_id); - } + if (ids.find(new_id) == ids.end()) + id = new_id; } + if (id == gfx::Display::kInvalidDisplayID) + id = output_index; + ids.insert(id); + + displays.push_back(DisplayInfo(id, name, has_overscan)); + displays.back().set_device_scale_factor(device_scale_factor); + displays.back().SetBounds(display_bounds); y_coords.insert(crtc_info->y); - XRRFreeOutputInfo(output_info); } // Free all allocated resources. @@ -170,14 +195,7 @@ void DisplayChangeObserverX11::OnDisplayModeChanged() { // PowerManager lays out the outputs vertically. Sort them by Y // coordinates. std::sort(displays.begin(), displays.end(), CompareDisplayY); - int64 id = 0; - for (std::vector<gfx::Display>::iterator iter = displays.begin(); - iter != displays.end(); ++iter) { - if (iter->id() == gfx::Display::kInvalidDisplayID) { - iter->set_id(id); - ++id; - } - } + // DisplayManager can be null during the boot. Shell::GetInstance()->display_manager()->OnNativeDisplaysChanged(displays); } diff --git a/ash/display/display_controller.cc b/ash/display/display_controller.cc index 2d645a1..29987d5 100644 --- a/ash/display/display_controller.cc +++ b/ash/display/display_controller.cc @@ -296,26 +296,8 @@ bool DisplayController::HasPrimaryDisplay() { } void DisplayController::InitPrimaryDisplay() { - const gfx::Display* primary_candidate = GetDisplayManager()->GetDisplayAt(0); -#if defined(OS_CHROMEOS) - if (base::chromeos::IsRunningOnChromeOS()) { - internal::DisplayManager* display_manager = GetDisplayManager(); - // On ChromeOS device, root windows are stacked vertically, and - // default primary is the one on top. - int count = display_manager->GetNumDisplays(); - int y = primary_candidate->bounds_in_pixel().y(); - for (int i = 1; i < count; ++i) { - const gfx::Display* display = display_manager->GetDisplayAt(i); - if (display->IsInternal()) { - primary_candidate = display; - break; - } else if (display->bounds_in_pixel().y() < y) { - primary_candidate = display; - y = display->bounds_in_pixel().y(); - } - } - } -#endif + const gfx::Display* primary_candidate = + GetDisplayManager()->GetPrimaryDisplayCandidate(); primary_display_id = primary_candidate->id(); AddRootWindowForDisplay(*primary_candidate); UpdateDisplayBoundsForLayout(); @@ -405,6 +387,10 @@ void DisplayController::SetOverscanInsets(int64 display_id, GetDisplayManager()->SetOverscanInsets(display_id, insets_in_dip); } +void DisplayController::ClearCustomOverscanInsets(int64 display_id) { + GetDisplayManager()->ClearCustomOverscanInsets(display_id); +} + std::vector<internal::RootWindowController*> DisplayController::GetAllRootWindowControllers() { std::vector<internal::RootWindowController*> controllers; @@ -559,11 +545,13 @@ void DisplayController::SetPrimaryDisplay( GetLayoutForDisplay(new_primary_display).Invert()); // Update the dispay manager with new display info. - std::vector<gfx::Display> displays; - displays.push_back(display_manager->GetDisplayForId(primary_display_id)); - displays.push_back(*GetSecondaryDisplay()); + std::vector<internal::DisplayInfo> display_info_list; + display_info_list.push_back(display_manager->GetDisplayInfo( + display_manager->GetDisplayForId(primary_display_id))); + display_info_list.push_back(display_manager->GetDisplayInfo( + *GetSecondaryDisplay())); GetDisplayManager()->set_force_bounds_changed(true); - GetDisplayManager()->UpdateDisplays(displays); + GetDisplayManager()->UpdateDisplays(display_info_list); GetDisplayManager()->set_force_bounds_changed(false); } @@ -577,12 +565,15 @@ gfx::Display* DisplayController::GetSecondaryDisplay() { void DisplayController::OnDisplayBoundsChanged(const gfx::Display& display) { if (limiter_.get()) limiter_->SetThrottleTimeout(kAfterDisplayChangeThrottleTimeoutMs); + DCHECK(!GetDisplayManager()->GetDisplayInfo(display). + bounds_in_pixel().IsEmpty()); NotifyDisplayConfigurationChanging(); UpdateDisplayBoundsForLayout(); aura::RootWindow* root = root_windows_[display.id()]; SetDisplayPropertiesOnHostWindow(root, display); - root->SetHostBounds(display.bounds_in_pixel()); + root->SetHostBounds( + GetDisplayManager()->GetDisplayInfo(display).bounds_in_pixel()); } void DisplayController::OnDisplayAdded(const gfx::Display& display) { @@ -598,7 +589,8 @@ void DisplayController::OnDisplayAdded(const gfx::Display& display) { internal::kDisplayIdKey, display.id()); primary_root_window_for_replace_ = NULL; UpdateDisplayBoundsForLayout(); - root_windows_[display.id()]->SetHostBounds(display.bounds_in_pixel()); + root_windows_[display.id()]->SetHostBounds( + GetDisplayManager()->GetDisplayInfo(display).bounds_in_pixel()); } else { DCHECK(!root_windows_.empty()); aura::RootWindow* root = AddRootWindowForDisplay(display); diff --git a/ash/display/display_controller.h b/ash/display/display_controller.h index 2674483..65b4570 100644 --- a/ash/display/display_controller.h +++ b/ash/display/display_controller.h @@ -141,10 +141,11 @@ class ASH_EXPORT DisplayController : public gfx::DisplayObserver { // mode, this return a RootWindowController for the primary root window only. std::vector<internal::RootWindowController*> GetAllRootWindowControllers(); - // Gets/Sets the overscan insets for the specified |display_id|. See + // Gets/Sets/Clears the overscan insets for the specified |display_id|. See // display_manager.h for the details. gfx::Insets GetOverscanInsets(int64 display_id) const; void SetOverscanInsets(int64 display_id, const gfx::Insets& insets_in_dip); + void ClearCustomOverscanInsets(int64 display_id); const DisplayLayout& default_display_layout() const { return default_display_layout_; diff --git a/ash/display/display_controller_unittest.cc b/ash/display/display_controller_unittest.cc index a507062..c07a9b7 100644 --- a/ash/display/display_controller_unittest.cc +++ b/ash/display/display_controller_unittest.cc @@ -395,14 +395,15 @@ TEST_F(DisplayControllerTest, SwapPrimaryById) { EXPECT_FALSE(tracker.Contains(secondary_root)); EXPECT_TRUE(primary_root->Contains(launcher_window)); - // Adding 2nd display with the same ID. The 2nd display should become primary - // since secondary id is still stored as desirable_primary_id. - std::vector<gfx::Display> displays; - displays.push_back(primary_display); - displays.push_back(secondary_display); internal::DisplayManager* display_manager = Shell::GetInstance()->display_manager(); - display_manager->OnNativeDisplaysChanged(displays); + // Adding 2nd display with the same ID. The 2nd display should become primary + // since secondary id is still stored as desirable_primary_id. + std::vector<internal::DisplayInfo> display_info_list; + display_info_list.push_back(display_manager->GetDisplayInfo(primary_display)); + display_info_list.push_back( + display_manager->GetDisplayInfo(secondary_display)); + display_manager->OnNativeDisplaysChanged(display_info_list); EXPECT_EQ(2, Shell::GetScreen()->GetNumDisplays()); EXPECT_EQ(secondary_display.id(), @@ -419,23 +420,27 @@ TEST_F(DisplayControllerTest, SwapPrimaryById) { // Deleting 2nd display and adding 2nd display with a different ID. The 2nd // display shouldn't become primary. UpdateDisplay("200x200"); - std::vector<gfx::Display> displays2; - gfx::Display third_display( - secondary_display.id() + 1, secondary_display.bounds()); - ASSERT_NE(primary_display.id(), third_display.id()); - displays2.push_back(primary_display); - displays2.push_back(third_display); - display_manager->OnNativeDisplaysChanged(displays2); + internal::DisplayInfo third_display_info( + secondary_display.id() + 1, std::string(), false); + third_display_info.SetBounds(secondary_display.bounds()); + ASSERT_NE(primary_display.id(), third_display_info.id()); + + const internal::DisplayInfo& primary_display_info = + display_manager->GetDisplayInfo(primary_display); + std::vector<internal::DisplayInfo> display_info_list2; + display_info_list2.push_back(primary_display_info); + display_info_list2.push_back(third_display_info); + display_manager->OnNativeDisplaysChanged(display_info_list2); EXPECT_EQ(2, Shell::GetScreen()->GetNumDisplays()); EXPECT_EQ(primary_display.id(), Shell::GetScreen()->GetPrimaryDisplay().id()); - EXPECT_EQ(third_display.id(), ScreenAsh::GetSecondaryDisplay().id()); + EXPECT_EQ(third_display_info.id(), ScreenAsh::GetSecondaryDisplay().id()); EXPECT_EQ( primary_root, display_controller->GetRootWindowForDisplayId(primary_display.id())); EXPECT_NE( primary_root, - display_controller->GetRootWindowForDisplayId(third_display.id())); + display_controller->GetRootWindowForDisplayId(third_display_info.id())); EXPECT_TRUE(primary_root->Contains(launcher_window)); } diff --git a/ash/display/display_info.cc b/ash/display/display_info.cc new file mode 100644 index 0000000..e94ea9e --- /dev/null +++ b/ash/display/display_info.cc @@ -0,0 +1,143 @@ +// Copyright (c) 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 <stdio.h> + +#include "ash/display/display_info.h" +#include "base/logging.h" +#include "base/stringprintf.h" +#include "ui/gfx/display.h" + +#if defined(OS_WIN) +#include "ui/aura/root_window_host.h" +#endif + +namespace ash { +namespace internal { + +// satic +DisplayInfo DisplayInfo::CreateFromSpec(const std::string& spec) { + return CreateFromSpecWithID(spec, gfx::Display::kInvalidDisplayID); +} + +// static +DisplayInfo DisplayInfo::CreateFromSpecWithID(const std::string& spec, + int64 id) { + // Default bounds for a display. + const int kDefaultHostWindowX = 200; + const int kDefaultHostWindowY = 200; + const int kDefaultHostWindowWidth = 1280; + const int kDefaultHostWindowHeight = 1024; + + static int64 synthesized_display_id = 1000; + +#if defined(OS_WIN) + gfx::Rect bounds(aura::RootWindowHost::GetNativeScreenSize()); +#else + gfx::Rect bounds(kDefaultHostWindowX, kDefaultHostWindowY, + kDefaultHostWindowWidth, kDefaultHostWindowHeight); +#endif + + int x = 0, y = 0, width, height; + float scale = 1.0f; + if (sscanf(spec.c_str(), "%dx%d*%f", &width, &height, &scale) >= 2 || + sscanf(spec.c_str(), "%d+%d-%dx%d*%f", &x, &y, &width, &height, + &scale) >= 4) { + bounds.SetRect(x, y, width, height); + } + if (id == gfx::Display::kInvalidDisplayID) + id = synthesized_display_id++; + DisplayInfo display_info( + id, base::StringPrintf("Display-%d", static_cast<int>(id)), false); + display_info.set_device_scale_factor(scale); + display_info.SetBounds(bounds); + DVLOG(1) << "DisplayInfoFromSpec info=" << display_info.ToString() + << ", spec=" << spec; + return display_info; +} + +DisplayInfo::DisplayInfo() + : id_(gfx::Display::kInvalidDisplayID), + has_overscan_(false), + device_scale_factor_(1.0f), + overscan_insets_in_dip_(-1, -1, -1, -1), + has_custom_overscan_insets_(false) { +} + +DisplayInfo::DisplayInfo(int64 id, + const std::string& name, + bool has_overscan) + : id_(id), + name_(name), + has_overscan_(has_overscan), + device_scale_factor_(1.0f), + overscan_insets_in_dip_(-1, -1, -1, -1), + has_custom_overscan_insets_(false) { +} + +DisplayInfo::~DisplayInfo() { +} + +void DisplayInfo::CopyFromNative(const DisplayInfo& native_info) { + DCHECK(id_ == native_info.id_); + name_ = native_info.name_; + has_overscan_ = native_info.has_overscan_; + + DCHECK(!native_info.original_bounds_in_pixel_.IsEmpty()); + original_bounds_in_pixel_ = native_info.original_bounds_in_pixel_; + bounds_in_pixel_ = native_info.bounds_in_pixel_; + device_scale_factor_ = native_info.device_scale_factor_; +} + +void DisplayInfo::SetBounds(const gfx::Rect& new_original_bounds) { + original_bounds_in_pixel_ = bounds_in_pixel_ = new_original_bounds; +} + +void DisplayInfo::UpdateBounds(const gfx::Rect& new_original_bounds) { + bool overscan = original_bounds_in_pixel_ != bounds_in_pixel_; + original_bounds_in_pixel_ = bounds_in_pixel_ = new_original_bounds; + if (overscan) { + original_bounds_in_pixel_.Inset( + overscan_insets_in_dip_.Scale(-device_scale_factor_)); + } +} + +void DisplayInfo::UpdateOverscanInfo(bool can_overscan) { + bounds_in_pixel_ = original_bounds_in_pixel_; + if (can_overscan) { + if (has_custom_overscan_insets_) { + bounds_in_pixel_.Inset( + overscan_insets_in_dip_.Scale(device_scale_factor_)); + } else if (has_overscan_) { + // Currently we assume 5% overscan and hope for the best if TV claims it + // overscan, but doesn't expose how much. + int width = bounds_in_pixel_.width() / 40; + int height = bounds_in_pixel_.height() / 40; + gfx::Insets insets_in_pixel(height, width, height, width); + overscan_insets_in_dip_ = + insets_in_pixel.Scale(1.0 / device_scale_factor_); + bounds_in_pixel_.Inset( + overscan_insets_in_dip_.Scale(device_scale_factor_)); + } + } +} + +void DisplayInfo::SetOverscanInsets(bool custom, + const gfx::Insets& insets_in_dip) { + has_custom_overscan_insets_ = custom; + overscan_insets_in_dip_ = insets_in_dip; +} + +std::string DisplayInfo::ToString() const { + return base::StringPrintf( + "DisplayInfo[%lld] bounds=%s, original=%s, scale=%f, overscan=%s", + static_cast<long long int>(id_), + bounds_in_pixel_.ToString().c_str(), + original_bounds_in_pixel_.ToString().c_str(), + device_scale_factor_, + overscan_insets_in_dip_.ToString().c_str()); +} + +} // namespace internal +} // namespace ash diff --git a/ash/display/display_info.h b/ash/display/display_info.h new file mode 100644 index 0000000..94adf1d --- /dev/null +++ b/ash/display/display_info.h @@ -0,0 +1,130 @@ +// Copyright (c) 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_INFO_H_ +#define ASH_DISPLAY_DISPLAY_INFO_H_ + +#include <string> + +#include "ash/ash_export.h" +#include "base/gtest_prod_util.h" +#include "ui/gfx/insets.h" +#include "ui/gfx/rect.h" + +namespace gfx { +class Display; +} + +namespace ash { +namespace internal { + +// 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. +// This class is intentionally made copiable. +class ASH_EXPORT DisplayInfo { + public: + // Creates a DisplayInfo from string spec. 100+200-1440x800 creates display + // whose size is 1440x800 at the location (100, 200) in screen's coordinates. + // The location can be omitted and be just "1440x800", which creates + // display at the origin of the screen. An empty string creates + // the display with default size. + // The device scale factor can be specified by "*", like "1280x780*2", + // or will use the value of |gfx::Display::GetForcedDeviceScaleFactor()| if + // --force-device-scale-factor is specified. + static DisplayInfo CreateFromSpec(const std::string& spec); + + // Creates a DisplayInfo from string spec using given |id|. + static DisplayInfo CreateFromSpecWithID(const std::string& spec, + int64 id); + + DisplayInfo(); + DisplayInfo(int64 id, const std::string& name, bool has_overscan); + ~DisplayInfo(); + + int64 id() const { return id_; } + + // The name of the display. + const std::string& name() const { return name_; } + + // True if the display has overscan. + bool has_overscan() const { return has_overscan_; } + + // Gets/Sets the device scale factor of the display. + float device_scale_factor() const { return device_scale_factor_; } + void set_device_scale_factor(float scale) { device_scale_factor_ = scale; } + + // The original bounds_in_pixel for the display. This can be different from + // the |bounds_in_pixel| in case of overscan insets. + const gfx::Rect original_bounds_in_pixel() const { + return original_bounds_in_pixel_; + } + + // The bounds for the display in pixels. + const gfx::Rect bounds_in_pixel() const { return bounds_in_pixel_; } + + // The overscan insets for the display in DIP. The default value is + // (-1, -1, -1, -1), which indicates that no overscan should be applied. + const gfx::Insets& overscan_insets_in_dip() const { + return overscan_insets_in_dip_; + } + + // Copy the display info except for two fields that can be modified by a user + // (|has_custom_overscan_insets_| and |custom_overscan_insets_in_dip_|). + void CopyFromNative(const DisplayInfo& native_info); + + // Set the |original_bounds_in_pixel| and |bounds_in_pixel| to + // given |bounds|. + void SetBounds(const gfx::Rect& bounds_in_pixel); + + // Sets the |bounds_in_pixel| and updates original bounds based on + // current overscan configuration. + void UpdateBounds(const gfx::Rect& bounds_in_pixel); + + // Update the |bounds_in_pixel| according to the current overscan + // settings. + // 1) If can_overscan is false, then |bounds_in_pixel| is equal to + // |original_bounds_in_pixel|. + // 2) If this has custom overscan insets + // (i.e. |has_custom_overscan_insets_| is true), it simply applies + // the existing |overscan_insets_in_dip_|. + // 3) If this doesn't have custom overscan insets, then this updates + // |overscan_insets_in_dip_| to default value (5% of the display size) + // and apply the insets. + void UpdateOverscanInfo(bool can_overscan); + + // Sets/Clears the overscan insets. + void SetOverscanInsets(bool custom, + const gfx::Insets& insets_in_dip); + void clear_has_custom_overscan_insets() { + has_custom_overscan_insets_ = false; + } + + // Returns a string representation of the DisplayInfo; + std::string ToString() const; + + private: + FRIEND_TEST_ALL_PREFIXES(DisplayManagerTest, AutomaticOverscanInsets); + // Set the overscan flag. Used for test. + void set_has_overscan_for_test(bool has_overscan) { + has_overscan_ = has_overscan; + } + + int64 id_; + std::string name_; + bool has_overscan_; + float device_scale_factor_; + gfx::Rect original_bounds_in_pixel_; + gfx::Rect bounds_in_pixel_; + gfx::Insets overscan_insets_in_dip_; + + // True if the |overscan_insets_in_dip| is specified by a user. This + // is used not to override the insets by native insets. + bool has_custom_overscan_insets_; +}; + +} // namespace internal +} // namespace ash + +#endif // ASH_DISPLAY_DISPLAY_INFO_H_ diff --git a/ash/display/display_manager.cc b/ash/display/display_manager.cc index 170b340..6aef6f4 100644 --- a/ash/display/display_manager.cc +++ b/ash/display/display_manager.cc @@ -46,10 +46,12 @@ #endif DECLARE_WINDOW_PROPERTY_TYPE(int64); -typedef std::vector<gfx::Display> DisplayList; namespace ash { namespace internal { +typedef std::vector<gfx::Display> DisplayList; +typedef std::vector<DisplayInfo> DisplayInfoList; + namespace { // Default bounds for a display. @@ -64,29 +66,38 @@ struct DisplaySortFunctor { } }; +struct DisplayInfoSortFunctor { + bool operator()(const DisplayInfo& a, const DisplayInfo& b) { + return a.id() < b.id(); + } +}; + gfx::Display& GetInvalidDisplay() { static gfx::Display* invalid_display = new gfx::Display(); return *invalid_display; } #if defined(OS_CHROMEOS) -int64 GetDisplayIdForOutput(XID output, int output_index) { - uint16 manufacturer_id = 0; - uint16 product_code = 0; - ui::GetOutputDeviceData( - output, &manufacturer_id, &product_code, NULL); - return gfx::Display::GetID(manufacturer_id, product_code, output_index); -} -#endif -gfx::Insets GetDefaultDisplayOverscan(const gfx::Display& display) { - // Currently we assume 5% overscan and hope for the best if TV claims it - // overscan, but doesn't expose how much. - int width = display.bounds().width() / 40; - int height = display.bounds().height() / 40; - return gfx::Insets(height, width, height, width); +int64 FindInternalDisplayID() { + std::vector<XID> outputs; + ui::GetOutputDeviceHandles(&outputs); + std::vector<std::string> output_names = ui::GetOutputNames(outputs); + for (size_t i = 0; i < output_names.size(); ++i) { + if (chromeos::OutputConfigurator::IsInternalOutputName( + output_names[i])) { + uint16 manufacturer_id = 0; + uint16 product_code = 0; + ui::GetOutputDeviceData( + outputs[i], &manufacturer_id, &product_code, NULL); + return gfx::Display::GetID(manufacturer_id, product_code, i); + } + } + return gfx::Display::kInvalidDisplayID; } +#endif + } // namespace using aura::RootWindow; @@ -159,24 +170,34 @@ const gfx::Display& DisplayManager::FindDisplayContainingPoint( void DisplayManager::SetOverscanInsets(int64 display_id, const gfx::Insets& insets_in_dip) { - display_info_[display_id].overscan_insets_in_dip = insets_in_dip; - display_info_[display_id].has_custom_overscan_insets = true; + display_info_[display_id].SetOverscanInsets(true, insets_in_dip); + DisplayInfoList display_info_list; + for (DisplayList::const_iterator iter = displays_.begin(); + iter != displays_.end(); ++iter) { + display_info_list.push_back(GetDisplayInfo(*iter)); + } + UpdateDisplays(display_info_list); +} - // Copies the |displays_| because UpdateDisplays() compares the passed - // displays and its internal |displays_|. - DisplayList displays = displays_; - UpdateDisplays(displays); +void DisplayManager::ClearCustomOverscanInsets(int64 display_id) { + display_info_[display_id].clear_has_custom_overscan_insets(); + DisplayInfoList display_info_list; + for (DisplayList::const_iterator iter = displays_.begin(); + iter != displays_.end(); ++iter) { + display_info_list.push_back(GetDisplayInfo(*iter)); + } + UpdateDisplays(display_info_list); } gfx::Insets DisplayManager::GetOverscanInsets(int64 display_id) const { std::map<int64, DisplayInfo>::const_iterator it = display_info_.find(display_id); return (it != display_info_.end()) ? - it->second.overscan_insets_in_dip : gfx::Insets(); + it->second.overscan_insets_in_dip() : gfx::Insets(); } void DisplayManager::OnNativeDisplaysChanged( - const std::vector<gfx::Display>& updated_displays) { + const std::vector<DisplayInfo>& updated_displays) { if (updated_displays.empty()) { // Don't update the displays when all displays are disconnected. // This happens when: @@ -190,55 +211,34 @@ void DisplayManager::OnNativeDisplaysChanged( // display list will be updated correctly. return; } - DisplayList new_displays = updated_displays; - if (HasInternalDisplay()) { - bool internal_display_connected = false; - for (DisplayList::const_iterator iter = updated_displays.begin(); - iter != updated_displays.end(); ++iter) { - if ((*iter).IsInternal()) { - internal_display_connected = true; - // Update the internal display cache. - internal_display_.reset(new gfx::Display); - *internal_display_.get() = *iter; - break; - } - } - // If the internal display wasn't connected, use the cached value. - if (!internal_display_connected) { - // Internal display may be reported as disconnect during startup time. - if (!internal_display_.get()) { - internal_display_.reset( - new gfx::Display(gfx::Display::InternalDisplayId(), - gfx::Rect(800, 600))); - } - new_displays.push_back(*internal_display_.get()); - } - } else { - new_displays = updated_displays; - } - - RefreshDisplayInfo(); - for (DisplayList::const_iterator iter = new_displays.begin(); - iter != new_displays.end(); ++iter) { - std::map<int64, DisplayInfo>::iterator info = - display_info_.find(iter->id()); - if (info != display_info_.end()) { - info->second.original_bounds_in_pixel = iter->bounds_in_pixel(); - if (info->second.has_overscan && !info->second.has_custom_overscan_insets) - info->second.overscan_insets_in_dip = GetDefaultDisplayOverscan(*iter); - } else { - display_info_[iter->id()].original_bounds_in_pixel = - iter->bounds_in_pixel(); + bool internal_display_connected = false; + for (DisplayInfoList::const_iterator iter = updated_displays.begin(); + iter != updated_displays.end() && !internal_display_connected; + ++iter) { + internal_display_connected = IsInternalDisplayId(iter->id()); + if (internal_display_connected) + internal_display_info_.reset(new DisplayInfo(*iter)); + } + DisplayInfoList new_display_info_list = updated_displays; + + if (HasInternalDisplay() && !internal_display_connected) { + if (!internal_display_info_.get()) { + // TODO(oshima): Get has_custom value. + internal_display_info_.reset(new DisplayInfo( + gfx::Display::InternalDisplayId(), + l10n_util::GetStringUTF8(IDS_ASH_INTERNAL_DISPLAY_NAME), + false)); + internal_display_info_->SetBounds(gfx::Rect(0, 0, 800, 600)); } + new_display_info_list.push_back(*internal_display_info_.get()); } - UpdateDisplays(new_displays); + UpdateDisplays(new_display_info_list); } void DisplayManager::UpdateDisplays( - const std::vector<gfx::Display>& updated_displays) { - DisplayList new_displays = updated_displays; + const std::vector<DisplayInfo>& updated_display_info_list) { #if defined(OS_CHROMEOS) // Overscan is always enabled when not running on the device // in order for unit tests to work. @@ -246,26 +246,15 @@ void DisplayManager::UpdateDisplays( !base::chromeos::IsRunningOnChromeOS() || (Shell::GetInstance()->output_configurator()->output_state() != chromeos::STATE_DUAL_MIRROR && - updated_displays.size() == 1); + updated_display_info_list.size() == 1); #else bool can_overscan = true; #endif - if (can_overscan) { - for (DisplayList::iterator iter = new_displays.begin(); - iter != new_displays.end(); ++iter) { - std::map<int64, DisplayInfo>::const_iterator info = - display_info_.find(iter->id()); - if (info != display_info_.end()) { - gfx::Rect bounds = info->second.original_bounds_in_pixel; - bounds.Inset(info->second.overscan_insets_in_dip.Scale( - iter->device_scale_factor())); - iter->SetScaleAndBounds(iter->device_scale_factor(), bounds); - } - } - } - + DisplayInfoList new_display_info_list = updated_display_info_list; std::sort(displays_.begin(), displays_.end(), DisplaySortFunctor()); - std::sort(new_displays.begin(), new_displays.end(), DisplaySortFunctor()); + std::sort(new_display_info_list.begin(), + new_display_info_list.end(), + DisplayInfoSortFunctor()); DisplayList removed_displays; std::vector<size_t> changed_display_indices; std::vector<size_t> added_display_indices; @@ -273,44 +262,54 @@ void DisplayManager::UpdateDisplays( if (DisplayController::HasPrimaryDisplay()) current_primary = DisplayController::GetPrimaryDisplay(); - for (DisplayList::iterator curr_iter = displays_.begin(), - new_iter = new_displays.begin(); - curr_iter != displays_.end() || new_iter != new_displays.end();) { + DisplayList::iterator curr_iter = displays_.begin(); + DisplayInfoList::const_iterator new_info_iter = new_display_info_list.begin(); + + DisplayList new_displays; + while (curr_iter != displays_.end() || + new_info_iter != new_display_info_list.end()) { if (curr_iter == displays_.end()) { // more displays in new list. - added_display_indices.push_back(new_iter - new_displays.begin()); - ++new_iter; - } else if (new_iter == new_displays.end()) { + added_display_indices.push_back(new_displays.size()); + InsertAndUpdateDisplayInfo(*new_info_iter, can_overscan); + new_displays.push_back( + CreateDisplayFromDisplayInfoById(new_info_iter->id())); + ++new_info_iter; + } else if (new_info_iter == new_display_info_list.end()) { // more displays in current list. removed_displays.push_back(*curr_iter); ++curr_iter; - } else if ((*curr_iter).id() == (*new_iter).id()) { + } else if (curr_iter->id() == new_info_iter->id()) { const gfx::Display& current_display = *curr_iter; - gfx::Display& new_display = *new_iter; + // Copy the info because |CreateDisplayFromInfo| updates the instance. + const DisplayInfo current_display_info = GetDisplayInfo(current_display); + InsertAndUpdateDisplayInfo(*new_info_iter, can_overscan); + gfx::Display new_display = + CreateDisplayFromDisplayInfoById(new_info_iter->id()); + const DisplayInfo& new_display_info = GetDisplayInfo(new_display); if (force_bounds_changed_ || - current_display.bounds_in_pixel() != new_display.bounds_in_pixel() || - current_display.device_scale_factor() != - new_display.device_scale_factor()) { - changed_display_indices.push_back(new_iter - new_displays.begin()); + (current_display_info.bounds_in_pixel() != + new_display_info.bounds_in_pixel()) || + (current_display.device_scale_factor() != + new_display.device_scale_factor())) { + changed_display_indices.push_back(new_displays.size()); } - // If the display is primary, then simpy set the origin to (0,0). - // The secondary display's bounds will be updated by - // |DisplayController::UpdateDisplayBoundsForLayout|, so no need - // to change there. - if ((*new_iter).id() == current_primary.id()) - new_display.set_bounds(gfx::Rect(new_display.bounds().size())); new_display.UpdateWorkAreaFromInsets(current_display.GetWorkAreaInsets()); + new_displays.push_back(new_display); ++curr_iter; - ++new_iter; - } else if ((*curr_iter).id() < (*new_iter).id()) { + ++new_info_iter; + } else if (curr_iter->id() < new_info_iter->id()) { // more displays in current list between ids, which means it is deleted. removed_displays.push_back(*curr_iter); ++curr_iter; } else { // more displays in new list between ids, which means it is added. - added_display_indices.push_back(new_iter - new_displays.begin()); - ++new_iter; + added_display_indices.push_back(new_displays.size()); + InsertAndUpdateDisplayInfo(*new_info_iter, can_overscan); + new_displays.push_back( + CreateDisplayFromDisplayInfoById(new_info_iter->id())); + ++new_info_iter; } } @@ -352,10 +351,10 @@ void DisplayManager::UpdateDisplays( RootWindow* DisplayManager::CreateRootWindowForDisplay( const gfx::Display& display) { static int root_window_count = 0; - - RootWindow::CreateParams params(display.bounds_in_pixel()); + const gfx::Rect& bounds_in_pixel = GetDisplayInfo(display).bounds_in_pixel(); + RootWindow::CreateParams params(bounds_in_pixel); params.host = Shell::GetInstance()->root_window_host_factory()-> - CreateRootWindowHost(display.bounds_in_pixel()); + CreateRootWindowHost(bounds_in_pixel); aura::RootWindow* root_window = new aura::RootWindow(params); root_window->SetName(StringPrintf("RootWindow-%d", root_window_count++)); @@ -371,6 +370,30 @@ gfx::Display* DisplayManager::GetDisplayAt(size_t index) { return index < displays_.size() ? &displays_[index] : NULL; } +const gfx::Display* DisplayManager::GetPrimaryDisplayCandidate() const { + const gfx::Display* primary_candidate = &displays_[0]; +#if defined(OS_CHROMEOS) + if (base::chromeos::IsRunningOnChromeOS()) { + // On ChromeOS device, root windows are stacked vertically, and + // default primary is the one on top. + int count = GetNumDisplays(); + int y = GetDisplayInfo(*primary_candidate).bounds_in_pixel().y(); + for (int i = 1; i < count; ++i) { + const gfx::Display* display = &displays_[i]; + const DisplayInfo& display_info = GetDisplayInfo(*display); + if (display->IsInternal()) { + primary_candidate = display; + break; + } else if (display_info.bounds_in_pixel().y() < y) { + primary_candidate = display; + y = display_info.bounds_in_pixel().y(); + } + } + } +#endif + return primary_candidate; +} + size_t DisplayManager::GetNumDisplays() const { return displays_.size(); } @@ -415,6 +438,14 @@ const gfx::Display& DisplayManager::GetDisplayMatching( return matching ? *matching : DisplayController::GetPrimaryDisplay(); } +const DisplayInfo& DisplayManager::GetDisplayInfo( + const gfx::Display& display) const { + std::map<int64, DisplayInfo>::const_iterator iter = + display_info_.find(display.id()); + CHECK(iter != display_info_.end()); + return iter->second; +} + std::string DisplayManager::GetDisplayNameFor( const gfx::Display& display) { if (!display.is_valid()) @@ -422,8 +453,8 @@ std::string DisplayManager::GetDisplayNameFor( std::map<int64, DisplayInfo>::const_iterator iter = display_info_.find(display.id()); - if (iter != display_info_.end() && !iter->second.name.empty()) - return iter->second.name; + if (iter != display_info_.end() && !iter->second.name().empty()) + return iter->second.name(); return base::StringPrintf("Display %d", static_cast<int>(display.id())); } @@ -438,6 +469,8 @@ void DisplayManager::OnRootWindowResized(const aura::RootWindow* root, gfx::Display& display = FindDisplayForRootWindow(root); if (display.size() != root->GetHostSize()) { display.SetSize(root->GetHostSize()); + display_info_[display.id()].UpdateBounds( + gfx::Rect(root->GetHostOrigin(), root->GetHostSize())); Shell::GetInstance()->screen()->NotifyBoundsChanged(display); } } @@ -445,23 +478,10 @@ void DisplayManager::OnRootWindowResized(const aura::RootWindow* root, void DisplayManager::Init() { #if defined(OS_CHROMEOS) - if (base::chromeos::IsRunningOnChromeOS()) { - std::vector<XID> outputs; - ui::GetOutputDeviceHandles(&outputs); - std::vector<std::string> output_names = ui::GetOutputNames(outputs); - for (size_t i = 0; i < output_names.size(); ++i) { - if (chromeos::OutputConfigurator::IsInternalOutputName( - output_names[i])) { - gfx::Display::SetInternalDisplayId( - GetDisplayIdForOutput(outputs[i], i)); - break; - } - } - } + if (base::chromeos::IsRunningOnChromeOS()) + gfx::Display::SetInternalDisplayId(FindInternalDisplayID()); #endif - RefreshDisplayInfo(); - // TODO(oshima): Move this logic to DisplayChangeObserver. const string size_str = CommandLine::ForCurrentProcess()->GetSwitchValueASCII( switches::kAshHostWindowBounds); @@ -477,34 +497,32 @@ void DisplayManager::Init() { void DisplayManager::CycleDisplayImpl() { DCHECK(!displays_.empty()); - std::vector<gfx::Display> new_displays; - new_displays.push_back(DisplayController::GetPrimaryDisplay()); + std::vector<DisplayInfo> new_display_info_list; + new_display_info_list.push_back( + GetDisplayInfo(DisplayController::GetPrimaryDisplay())); // Add if there is only one display. if (displays_.size() == 1) { // Layout the 2nd display below the primary as with the real device. aura::RootWindow* primary = Shell::GetPrimaryRootWindow(); gfx::Rect host_bounds = gfx::Rect(primary->GetHostOrigin(), primary->GetHostSize()); - new_displays.push_back(CreateDisplayFromSpec( + new_display_info_list.push_back(DisplayInfo::CreateFromSpec( StringPrintf("%d+%d-500x400", host_bounds.x(), host_bounds.bottom()))); } - OnNativeDisplaysChanged(new_displays); + OnNativeDisplaysChanged(new_display_info_list); } void DisplayManager::ScaleDisplayImpl() { DCHECK(!displays_.empty()); - std::vector<gfx::Display> new_displays; + std::vector<DisplayInfo> new_display_info_list; for (DisplayList::const_iterator iter = displays_.begin(); iter != displays_.end(); ++iter) { - gfx::Display display = *iter; - float factor = display.device_scale_factor() == 1.0f ? 2.0f : 1.0f; - gfx::Point display_origin = display.bounds_in_pixel().origin(); - gfx::Size display_size = gfx::ToFlooredSize( - gfx::ScaleSize(display.size(), factor)); - display.SetScaleAndBounds(factor, gfx::Rect(display_origin, display_size)); - new_displays.push_back(display); + DisplayInfo display_info = GetDisplayInfo(*iter); + display_info.set_device_scale_factor( + display_info.device_scale_factor() == 1.0f ? 2.0f : 1.0f); + new_display_info_list.push_back(display_info); } - OnNativeDisplaysChanged(new_displays); + OnNativeDisplaysChanged(new_display_info_list); } gfx::Display& DisplayManager::FindDisplayForRootWindow( @@ -528,22 +546,12 @@ gfx::Display& DisplayManager::FindDisplayForId(int64 id) { } void DisplayManager::AddDisplayFromSpec(const std::string& spec) { - gfx::Display display = CreateDisplayFromSpec(spec); - - const gfx::Insets insets = display.GetWorkAreaInsets(); - const gfx::Rect& native_bounds = display.bounds_in_pixel(); - display.SetScaleAndBounds(display.device_scale_factor(), native_bounds); - display.UpdateWorkAreaFromInsets(insets); + DisplayInfo display_info = DisplayInfo::CreateFromSpec(spec); + InsertAndUpdateDisplayInfo(display_info, false); + gfx::Display display = CreateDisplayFromDisplayInfoById(display_info.id()); displays_.push_back(display); } -int64 DisplayManager::SetFirstDisplayAsInternalDisplayForTest() { - gfx::Display::SetInternalDisplayId(displays_[0].id()); - internal_display_.reset(new gfx::Display); - *internal_display_ = displays_[0]; - return gfx::Display::InternalDisplayId(); -} - void DisplayManager::EnsurePointerInDisplays() { // Don't try to move the pointer during the boot/startup. if (!DisplayController::HasPrimaryDisplay()) @@ -582,76 +590,35 @@ void DisplayManager::EnsurePointerInDisplays() { root_window->MoveCursorTo(target_location); } -DisplayManager::DisplayInfo::DisplayInfo() - : has_overscan(false), - has_custom_overscan_insets(false) { -} - -void DisplayManager::RefreshDisplayInfo() { -#if defined(OS_CHROMEOS) - if (!base::chromeos::IsRunningOnChromeOS()) - return; -#endif - -#if defined(USE_X11) - std::vector<XID> outputs; - if (!ui::GetOutputDeviceHandles(&outputs)) - return; - - for (size_t output_index = 0; output_index < outputs.size(); ++output_index) { - uint16 manufacturer_id = 0; - uint16 product_code = 0; - std::string name; - ui::GetOutputDeviceData( - outputs[output_index], &manufacturer_id, &product_code, &name); - int64 id = gfx::Display::GetID(manufacturer_id, product_code, output_index); - if (IsInternalDisplayId(id)) { - display_info_[id].name = - l10n_util::GetStringUTF8(IDS_ASH_INTERNAL_DISPLAY_NAME); - } else if (!name.empty()) { - display_info_[id].name = name; - } - - ui::GetOutputOverscanFlag( - outputs[output_index], &display_info_[id].has_overscan); - } -#endif -} +void DisplayManager::InsertAndUpdateDisplayInfo(const DisplayInfo& new_info, + bool can_overscan) { + std::map<int64, DisplayInfo>::iterator info = + display_info_.find(new_info.id()); + if (info != display_info_.end()) + info->second.CopyFromNative(new_info); + else + display_info_[new_info.id()] = new_info; -void DisplayManager::SetDisplayIdsForTest(DisplayList* to_update) const { - DisplayList::iterator iter_to_update = to_update->begin(); - DisplayList::const_iterator iter = displays_.begin(); - for (; iter != displays_.end() && iter_to_update != to_update->end(); - ++iter, ++iter_to_update) { - (*iter_to_update).set_id((*iter).id()); - } + display_info_[new_info.id()].UpdateOverscanInfo(can_overscan); } -void DisplayManager::SetHasOverscanFlagForTest(int64 id, bool has_overscan) { - display_info_[id].has_overscan = has_overscan; -} +gfx::Display DisplayManager::CreateDisplayFromDisplayInfoById(int64 id) { + DCHECK(display_info_.find(id) != display_info_.end()); + const DisplayInfo& display_info = display_info_[id]; -gfx::Display CreateDisplayFromSpec(const std::string& spec) { - static int64 synthesized_display_id = 1000; + gfx::Display new_display(display_info.id()); + new_display.SetScaleAndBounds( + display_info.device_scale_factor(), display_info.bounds_in_pixel()); -#if defined(OS_WIN) - gfx::Rect bounds(aura::RootWindowHost::GetNativeScreenSize()); -#else - gfx::Rect bounds(kDefaultHostWindowX, kDefaultHostWindowY, - kDefaultHostWindowWidth, kDefaultHostWindowHeight); -#endif - int x = 0, y = 0, width, height; - float scale = 1.0f; - if (sscanf(spec.c_str(), "%dx%d*%f", &width, &height, &scale) >= 2 || - sscanf(spec.c_str(), "%d+%d-%dx%d*%f", &x, &y, &width, &height, - &scale) >= 4) { - bounds.SetRect(x, y, width, height); + // If the display is primary, then simply set the origin to (0,0). + // The secondary display's bounds will be updated by + // |DisplayController::UpdateDisplayBoundsForLayout|, so no need + // to change there. + if (DisplayController::HasPrimaryDisplay() && + display_info.id() == DisplayController::GetPrimaryDisplay().id()) { + new_display.set_bounds(gfx::Rect(new_display.bounds().size())); } - - gfx::Display display(synthesized_display_id++); - display.SetScaleAndBounds(scale, bounds); - DVLOG(1) << "Display bounds=" << bounds.ToString() << ", scale=" << scale; - return display; + return new_display; } } // namespace internal diff --git a/ash/display/display_manager.h b/ash/display/display_manager.h index 25be7c1..541ea4b 100644 --- a/ash/display/display_manager.h +++ b/ash/display/display_manager.h @@ -9,6 +9,7 @@ #include <vector> #include "ash/ash_export.h" +#include "ash/display/display_info.h" #include "base/compiler_specific.h" #include "base/gtest_prod_util.h" #include "ui/aura/root_window_observer.h" @@ -76,6 +77,9 @@ class ASH_EXPORT DisplayManager : public aura::RootWindowObserver { // display's bounds change. void SetOverscanInsets(int64 display_id, const gfx::Insets& insets_in_dip); + // Clears the overscan insets + void ClearCustomOverscanInsets(int64 display_id); + // Returns the current overscan insets for the specified |display_id|. // Returns an empty insets (0, 0, 0, 0) if no insets are specified for // the display. @@ -84,10 +88,11 @@ class ASH_EXPORT DisplayManager : public aura::RootWindowObserver { // Called when display configuration has changed. The new display // configurations is passed as a vector of Display object, which // contains each display's new infomration. - void OnNativeDisplaysChanged(const std::vector<gfx::Display>& displays); + void OnNativeDisplaysChanged( + const std::vector<DisplayInfo>& display_info_list); // Updates the internal display data and notifies observers about the changes. - void UpdateDisplays(const std::vector<gfx::Display>& displays); + void UpdateDisplays(const std::vector<DisplayInfo>& display_info_list); // Create a root window for given |display|. aura::RootWindow* CreateRootWindowForDisplay(const gfx::Display& display); @@ -97,6 +102,8 @@ class ASH_EXPORT DisplayManager : public aura::RootWindowObserver { // no longer considered "primary". gfx::Display* GetDisplayAt(size_t index); + const gfx::Display* GetPrimaryDisplayCandidate() const; + size_t GetNumDisplays() const; // Returns the display object nearest given |window|. @@ -111,6 +118,9 @@ class ASH_EXPORT DisplayManager : public aura::RootWindowObserver { const gfx::Display& GetDisplayMatching( const gfx::Rect& match_rect)const; + // Retuns the display info associated with |display|. + const DisplayInfo& GetDisplayInfo(const gfx::Display& display) const; + // Returns the human-readable name for the display specified by |display|. std::string GetDisplayNameFor(const gfx::Display& display); @@ -131,29 +141,6 @@ class ASH_EXPORT DisplayManager : public aura::RootWindowObserver { typedef std::vector<gfx::Display> DisplayList; - // Metadata for each display. - struct DisplayInfo { - DisplayInfo(); - - // The cached name of the display. - std::string name; - - // The original bounds_in_pixel for the display. This can be different from - // the current one in case of overscan insets. - gfx::Rect original_bounds_in_pixel; - - // The overscan insets for the display. - gfx::Insets overscan_insets_in_dip; - - // True if we detect that the display has overscan area. False if the - // display doesn't have it, or failed to detect it. - bool has_overscan; - - // True if the |overscan_insets_in_dip| is specified. This is set because - // the user may specify an empty inset intentionally. - bool has_custom_overscan_insets; - }; - void Init(); void CycleDisplayImpl(); void ScaleDisplayImpl(); @@ -164,30 +151,26 @@ class ASH_EXPORT DisplayManager : public aura::RootWindowObserver { // Refer to |CreateDisplayFromSpec| API for the format of |spec|. void AddDisplayFromSpec(const std::string& spec); - // Set the 1st display as an internal display and returns the display Id for - // the internal display. - int64 SetFirstDisplayAsInternalDisplayForTest(); - // Checks if the mouse pointer is on one of displays, and moves to // the center of the nearest display if it's outside of all displays. void EnsurePointerInDisplays(); - // Updates |display_info_| by calling platform-dependent functions. - void RefreshDisplayInfo(); - - // Update the display's id in the |display_list| to match the ones - // stored in this display manager's |displays_|. This is used to - // emulate display change behavior during the test byn creating the - // display list with the same display ids but with different bounds - void SetDisplayIdsForTest(DisplayList* display_list) const; + // Inserts and update the DisplayInfo according to the overscan + // state. Note that The DisplayInfo stored in the |internal_display_info_| + // can be different from |new_info| (due to overscan state), so + // you must use |GetDisplayInfo| to get the correct DisplayInfo for + // a display. + void InsertAndUpdateDisplayInfo(const DisplayInfo& new_info, + bool can_overscan); - // Forcibly specify 'has_overscan' flag of the DisplayInfo for specified |id|. - void SetHasOverscanFlagForTest(int64 id, bool has_overscan); + // Creates a display object from the DisplayInfo for |display_id|. + gfx::Display CreateDisplayFromDisplayInfoById(int64 display_id); DisplayList displays_; - // An internal display cache used when the internal display is disconnectd. - scoped_ptr<gfx::Display> internal_display_; + // An internal display info cache used when the internal display is + // disconnectd. + scoped_ptr<DisplayInfo> internal_display_info_; bool force_bounds_changed_; @@ -197,16 +180,6 @@ class ASH_EXPORT DisplayManager : public aura::RootWindowObserver { DISALLOW_COPY_AND_ASSIGN(DisplayManager); }; -// Creates a display from string spec. 100+200-1440x800 creates display -// whose size is 1440x800 at the location (100, 200) in screen's coordinates. -// The location can be omitted and be just "1440x800", which creates -// display at the origin of the screen. An empty string creates -// the display with default size. -// The device scale factor can be specified by "*", like "1280x780*2", -// or will use the value of |gfx::Display::GetForcedDeviceScaleFactor()| if -// --force-device-scale-factor is specified. -ASH_EXPORT gfx::Display CreateDisplayFromSpec(const std::string& str); - extern const aura::WindowProperty<int64>* const kDisplayIdKey; } // namespace internal diff --git a/ash/display/display_manager_unittest.cc b/ash/display/display_manager_unittest.cc index 43e2593..b3bba2c 100644 --- a/ash/display/display_manager_unittest.cc +++ b/ash/display/display_manager_unittest.cc @@ -8,6 +8,7 @@ #include "ash/screen_ash.h" #include "ash/shell.h" #include "ash/test/ash_test_base.h" +#include "ash/test/display_manager_test_api.h" #include "base/format_macros.h" #include "base/stringprintf.h" #include "ui/aura/env.h" @@ -65,10 +66,22 @@ class DisplayManagerTest : public test::AshTestBase, return root_window_destroyed_; } + const DisplayInfo& GetDisplayInfo(const gfx::Display& display) { + return display_manager()->GetDisplayInfo(display); + } + + const DisplayInfo& GetDisplayInfoAt(int index) { + return GetDisplayInfo(*display_manager()->GetDisplayAt(index)); + } + const gfx::Display& FindDisplayForId(int64 id) { return display_manager()->FindDisplayForId(id); } + const DisplayInfo& FindDisplayInfoForId(int64 id) { + return GetDisplayInfo(display_manager()->FindDisplayForId(id)); + } + // aura::DisplayObserver overrides: virtual void OnDisplayBoundsChanged(const gfx::Display& display) OVERRIDE { changed_.push_back(display); @@ -110,7 +123,8 @@ TEST_F(DisplayManagerTest, NativeDisplayTest) { EXPECT_EQ("0,0 500x500", changed()[0].bounds().ToString()); // Secondary display is on right. EXPECT_EQ("500,0 400x400", added()[0].bounds().ToString()); - EXPECT_EQ("0,501 400x400", added()[0].bounds_in_pixel().ToString()); + EXPECT_EQ("0,501 400x400", + GetDisplayInfo(added()[0]).bounds_in_pixel().ToString()); reset(); // Delete secondary. @@ -132,7 +146,8 @@ TEST_F(DisplayManagerTest, NativeDisplayTest) { EXPECT_EQ(display_manager()->GetDisplayAt(1)->id(), added()[0].id()); // Secondary display is on right. EXPECT_EQ("1000,0 600x400", added()[0].bounds().ToString()); - EXPECT_EQ("1002,0 600x400", added()[0].bounds_in_pixel().ToString()); + EXPECT_EQ("1002,0 600x400", + GetDisplayInfo(added()[0]).bounds_in_pixel().ToString()); reset(); // Secondary removed, primary changed. @@ -144,7 +159,7 @@ TEST_F(DisplayManagerTest, NativeDisplayTest) { reset(); // # of display can go to zero when screen is off. - const vector<gfx::Display> empty; + const vector<DisplayInfo> empty; display_manager()->OnNativeDisplaysChanged(empty); EXPECT_EQ(1U, display_manager()->GetNumDisplays()); EXPECT_EQ("0 0 0", GetCountSummary()); @@ -160,7 +175,8 @@ TEST_F(DisplayManagerTest, NativeDisplayTest) { EXPECT_EQ("1 0 0", GetCountSummary()); EXPECT_FALSE(root_window_destroyed()); EXPECT_EQ("0,0 500x400", changed()[0].bounds().ToString()); - EXPECT_EQ("100,100 500x400", changed()[0].bounds_in_pixel().ToString()); + EXPECT_EQ("100,100 500x400", + GetDisplayInfo(changed()[0]).bounds_in_pixel().ToString()); reset(); // Go back to zero and wake up with multiple displays. @@ -178,7 +194,7 @@ TEST_F(DisplayManagerTest, NativeDisplayTest) { EXPECT_EQ("1000,0 600x400", display_manager()->GetDisplayAt(1)->bounds().ToString()); EXPECT_EQ("1000,1000 600x400", - display_manager()->GetDisplayAt(1)->bounds_in_pixel().ToString()); + GetDisplayInfoAt(1).bounds_in_pixel().ToString()); reset(); } @@ -207,74 +223,75 @@ TEST_F(DisplayManagerTest, OverscanInsetsTest) { UpdateDisplay("0+0-500x500,0+501-400x400"); reset(); ASSERT_EQ(2u, display_manager()->GetNumDisplays()); - gfx::Display display1(*display_manager()->GetDisplayAt(0)); - gfx::Display display2(*display_manager()->GetDisplayAt(1)); - + const DisplayInfo& display_info1 = GetDisplayInfoAt(0); + const DisplayInfo& display_info2 = GetDisplayInfoAt(1); display_manager()->SetOverscanInsets( - display2.id(), gfx::Insets(13, 12, 11, 10)); + display_info2.id(), gfx::Insets(13, 12, 11, 10)); + std::vector<gfx::Display> changed_displays = changed(); EXPECT_EQ(1u, changed_displays.size()); - EXPECT_EQ(display2.id(), changed_displays[0].id()); + EXPECT_EQ(display_info2.id(), changed_displays[0].id()); EXPECT_EQ("0,0 500x500", - display_manager()->GetDisplayAt(0)->bounds_in_pixel().ToString()); + GetDisplayInfoAt(0).bounds_in_pixel().ToString()); EXPECT_EQ("12,514 378x376", - display_manager()->GetDisplayAt(1)->bounds_in_pixel().ToString()); + GetDisplayInfoAt(1).bounds_in_pixel().ToString()); // Make sure that SetOverscanInsets() is idempotent. - display_manager()->SetOverscanInsets(display1.id(), gfx::Insets()); + display_manager()->SetOverscanInsets(display_info1.id(), gfx::Insets()); display_manager()->SetOverscanInsets( - display2.id(), gfx::Insets(13, 12, 11, 10)); + display_info2.id(), gfx::Insets(13, 12, 11, 10)); EXPECT_EQ("0,0 500x500", - display_manager()->GetDisplayAt(0)->bounds_in_pixel().ToString()); + GetDisplayInfoAt(0).bounds_in_pixel().ToString()); EXPECT_EQ("12,514 378x376", - display_manager()->GetDisplayAt(1)->bounds_in_pixel().ToString()); + GetDisplayInfoAt(1).bounds_in_pixel().ToString()); display_manager()->SetOverscanInsets( - display2.id(), gfx::Insets(10, 11, 12, 13)); + display_info2.id(), gfx::Insets(10, 11, 12, 13)); EXPECT_EQ("0,0 500x500", - display_manager()->GetDisplayAt(0)->bounds_in_pixel().ToString()); + GetDisplayInfoAt(0).bounds_in_pixel().ToString()); EXPECT_EQ("11,511 376x378", - display_manager()->GetDisplayAt(1)->bounds_in_pixel().ToString()); + GetDisplayInfoAt(1).bounds_in_pixel().ToString()); // Recreate a new 2nd display. It won't apply the overscan inset because the // new display has a different ID. UpdateDisplay("0+0-500x500"); UpdateDisplay("0+0-500x500,0+501-400x400"); EXPECT_EQ("0,0 500x500", - display_manager()->GetDisplayAt(0)->bounds_in_pixel().ToString()); + GetDisplayInfoAt(0).bounds_in_pixel().ToString()); EXPECT_EQ("0,501 400x400", - display_manager()->GetDisplayAt(1)->bounds_in_pixel().ToString()); + GetDisplayInfoAt(1).bounds_in_pixel().ToString()); // Recreate the displays with the same ID. It should apply the overscan // inset. UpdateDisplay("0+0-500x500"); - std::vector<gfx::Display> displays; - displays.push_back(display1); - displays.push_back(display2); - display_manager()->OnNativeDisplaysChanged(displays); - EXPECT_EQ("0,0 500x500", - display_manager()->GetDisplayAt(0)->bounds_in_pixel().ToString()); + std::vector<DisplayInfo> display_info_list; + display_info_list.push_back(display_info1); + display_info_list.push_back(display_info2); + display_manager()->OnNativeDisplaysChanged(display_info_list); + EXPECT_EQ("1,1 500x500", + GetDisplayInfoAt(0).bounds_in_pixel().ToString()); EXPECT_EQ("11,511 376x378", - display_manager()->GetDisplayAt(1)->bounds_in_pixel().ToString()); + GetDisplayInfoAt(1).bounds_in_pixel().ToString()); // HiDPI but overscan display. The specified insets size should be doubled. - UpdateDisplay("0+0-500x500"); UpdateDisplay("0+0-500x500,0+501-400x400*2"); display_manager()->SetOverscanInsets( display_manager()->GetDisplayAt(1)->id(), gfx::Insets(4, 5, 6, 7)); EXPECT_EQ("0,0 500x500", - display_manager()->GetDisplayAt(0)->bounds_in_pixel().ToString()); + GetDisplayInfoAt(0).bounds_in_pixel().ToString()); EXPECT_EQ("10,509 376x380", - display_manager()->GetDisplayAt(1)->bounds_in_pixel().ToString()); + GetDisplayInfoAt(1).bounds_in_pixel().ToString()); EXPECT_EQ("188x190", display_manager()->GetDisplayAt(1)->size().ToString()); // Make sure switching primary display applies the overscan offset only once. ash::Shell::GetInstance()->display_controller()->SetPrimaryDisplay( ScreenAsh::GetSecondaryDisplay()); EXPECT_EQ("0,0 500x500", - ScreenAsh::GetSecondaryDisplay().bounds_in_pixel().ToString()); - EXPECT_EQ("10,509 376x380", gfx::Screen::GetNativeScreen()-> - GetPrimaryDisplay().bounds_in_pixel().ToString()); + GetDisplayInfo(ScreenAsh::GetSecondaryDisplay()). + bounds_in_pixel().ToString()); + EXPECT_EQ("10,509 376x380", + GetDisplayInfo(gfx::Screen::GetNativeScreen()->GetPrimaryDisplay()). + bounds_in_pixel().ToString()); } TEST_F(DisplayManagerTest, ZeroOverscanInsets) { @@ -311,84 +328,93 @@ TEST_F(DisplayManagerTest, TestDeviceScaleOnlyChange) { Shell::GetPrimaryRootWindow()->bounds().size().ToString()); } +DisplayInfo CreateDisplayInfo(int64 id, const gfx::Rect& bounds) { + DisplayInfo info(id, std::string(), false); + info.SetBounds(bounds); + return info; +} + TEST_F(DisplayManagerTest, TestNativeDisplaysChanged) { const int64 internal_display_id = - display_manager()->SetFirstDisplayAsInternalDisplayForTest(); - const gfx::Display native_display(internal_display_id, - gfx::Rect(0, 0, 500, 500)); - const gfx::Display external_display(10, gfx::Rect(1, 1, 100, 100)); + test::DisplayManagerTestApi(display_manager()). + SetFirstDisplayAsInternalDisplay(); + const DisplayInfo native_display_info = + CreateDisplayInfo(internal_display_id, gfx::Rect(0, 0, 500, 500)); + const DisplayInfo external_display_info = + CreateDisplayInfo(10, gfx::Rect(1, 1, 100, 100)); EXPECT_EQ(1U, display_manager()->GetNumDisplays()); std::string default_bounds = display_manager()->GetDisplayAt(0)->bounds().ToString(); - std::vector<gfx::Display> displays; + std::vector<DisplayInfo> display_info_list; // Primary disconnected. - display_manager()->OnNativeDisplaysChanged(displays); + display_manager()->OnNativeDisplaysChanged(display_info_list); EXPECT_EQ(1U, display_manager()->GetNumDisplays()); EXPECT_EQ(default_bounds, display_manager()->GetDisplayAt(0)->bounds().ToString()); // External connected while primary was disconnected. - displays.push_back(external_display); - display_manager()->OnNativeDisplaysChanged(displays); + display_info_list.push_back(external_display_info); + display_manager()->OnNativeDisplaysChanged(display_info_list); EXPECT_EQ(2U, display_manager()->GetNumDisplays()); + EXPECT_EQ(default_bounds, FindDisplayForId(internal_display_id).bounds().ToString()); EXPECT_EQ("1,1 100x100", - FindDisplayForId(10).bounds_in_pixel().ToString()); + FindDisplayInfoForId(10).bounds_in_pixel().ToString()); // Primary connected, with different bounds. - displays.clear(); - displays.push_back(native_display); - displays.push_back(external_display); - display_manager()->OnNativeDisplaysChanged(displays); + display_info_list.clear(); + display_info_list.push_back(native_display_info); + display_info_list.push_back(external_display_info); + display_manager()->OnNativeDisplaysChanged(display_info_list); EXPECT_EQ(2U, display_manager()->GetNumDisplays()); EXPECT_EQ("0,0 500x500", FindDisplayForId(internal_display_id).bounds().ToString()); EXPECT_EQ("1,1 100x100", - FindDisplayForId(10).bounds_in_pixel().ToString()); + FindDisplayInfoForId(10).bounds_in_pixel().ToString()); // Turn off primary. - displays.clear(); - displays.push_back(external_display); - display_manager()->OnNativeDisplaysChanged(displays); + display_info_list.clear(); + display_info_list.push_back(external_display_info); + display_manager()->OnNativeDisplaysChanged(display_info_list); EXPECT_EQ(2U, display_manager()->GetNumDisplays()); EXPECT_EQ("0,0 500x500", FindDisplayForId(internal_display_id).bounds().ToString()); EXPECT_EQ("1,1 100x100", - FindDisplayForId(10).bounds_in_pixel().ToString()); + FindDisplayInfoForId(10).bounds_in_pixel().ToString()); // Emulate suspend. - displays.clear(); - display_manager()->OnNativeDisplaysChanged(displays); + display_info_list.clear(); + display_manager()->OnNativeDisplaysChanged(display_info_list); EXPECT_EQ(2U, display_manager()->GetNumDisplays()); EXPECT_EQ("0,0 500x500", FindDisplayForId(internal_display_id).bounds().ToString()); EXPECT_EQ("1,1 100x100", - FindDisplayForId(10).bounds_in_pixel().ToString()); + FindDisplayInfoForId(10).bounds_in_pixel().ToString()); // External display has disconnected then resumed. - displays.push_back(native_display); - display_manager()->OnNativeDisplaysChanged(displays); + display_info_list.push_back(native_display_info); + display_manager()->OnNativeDisplaysChanged(display_info_list); EXPECT_EQ(1U, display_manager()->GetNumDisplays()); EXPECT_EQ("0,0 500x500", FindDisplayForId(internal_display_id).bounds().ToString()); // External display was changed during suspend. - displays.push_back(external_display); - display_manager()->OnNativeDisplaysChanged(displays); + display_info_list.push_back(external_display_info); + display_manager()->OnNativeDisplaysChanged(display_info_list); EXPECT_EQ(2U, display_manager()->GetNumDisplays()); // suspend... - displays.clear(); - display_manager()->OnNativeDisplaysChanged(displays); + display_info_list.clear(); + display_manager()->OnNativeDisplaysChanged(display_info_list); EXPECT_EQ(2U, display_manager()->GetNumDisplays()); // and resume with different external display. - displays.push_back(native_display); - displays.push_back(gfx::Display(11, gfx::Rect(1, 1, 100, 100))); - display_manager()->OnNativeDisplaysChanged(displays); + display_info_list.push_back(native_display_info); + display_info_list.push_back(CreateDisplayInfo(11, gfx::Rect(1, 1, 100, 100))); + display_manager()->OnNativeDisplaysChanged(display_info_list); EXPECT_EQ(2U, display_manager()->GetNumDisplays()); } @@ -406,17 +432,18 @@ TEST_F(DisplayManagerTest, MAYBE_TestNativeDisplaysChangedNoInternal) { EXPECT_EQ(1U, display_manager()->GetNumDisplays()); // Don't change the display info if all displays are disconnected. - std::vector<gfx::Display> displays; - display_manager()->OnNativeDisplaysChanged(displays); + std::vector<DisplayInfo> display_info_list; + display_manager()->OnNativeDisplaysChanged(display_info_list); EXPECT_EQ(1U, display_manager()->GetNumDisplays()); // Connect another display which will become primary. - const gfx::Display external_display(10, gfx::Rect(1, 1, 100, 100)); - displays.push_back(external_display); - display_manager()->OnNativeDisplaysChanged(displays); + const DisplayInfo external_display_info = + CreateDisplayInfo(10, gfx::Rect(1, 1, 100, 100)); + display_info_list.push_back(external_display_info); + display_manager()->OnNativeDisplaysChanged(display_info_list); EXPECT_EQ(1U, display_manager()->GetNumDisplays()); EXPECT_EQ("1,1 100x100", - FindDisplayForId(10).bounds_in_pixel().ToString()); + FindDisplayInfoForId(10).bounds_in_pixel().ToString()); EXPECT_EQ("100x100", ash::Shell::GetPrimaryRootWindow()->GetHostSize().ToString()); } @@ -496,29 +523,31 @@ TEST_F(DisplayManagerTest, EnsurePointerInDisplays_2ndOnLeft) { TEST_F(DisplayManagerTest, NativeDisplaysChangedAfterPrimaryChange) { const int64 internal_display_id = - display_manager()->SetFirstDisplayAsInternalDisplayForTest(); - const gfx::Display native_display(internal_display_id, - gfx::Rect(0, 0, 500, 500)); - const gfx::Display secondary_display(10, gfx::Rect(1, 1, 100, 100)); - - std::vector<gfx::Display> displays; - displays.push_back(native_display); - displays.push_back(secondary_display); - display_manager()->OnNativeDisplaysChanged(displays); + test::DisplayManagerTestApi(display_manager()). + SetFirstDisplayAsInternalDisplay(); + const DisplayInfo native_display_info = + CreateDisplayInfo(internal_display_id, gfx::Rect(0, 0, 500, 500)); + const DisplayInfo secondary_display_info = + CreateDisplayInfo(10, gfx::Rect(1, 1, 100, 100)); + + std::vector<DisplayInfo> display_info_list; + display_info_list.push_back(native_display_info); + display_info_list.push_back(secondary_display_info); + display_manager()->OnNativeDisplaysChanged(display_info_list); EXPECT_EQ(2U, display_manager()->GetNumDisplays()); EXPECT_EQ("0,0 500x500", FindDisplayForId(internal_display_id).bounds().ToString()); EXPECT_EQ("500,0 100x100", FindDisplayForId(10).bounds().ToString()); ash::Shell::GetInstance()->display_controller()->SetPrimaryDisplay( - secondary_display); + FindDisplayForId(secondary_display_info.id())); EXPECT_EQ("-500,0 500x500", FindDisplayForId(internal_display_id).bounds().ToString()); EXPECT_EQ("0,0 100x100", FindDisplayForId(10).bounds().ToString()); // OnNativeDisplaysChanged may change the display bounds. Here makes sure // nothing changed if the exactly same displays are specified. - display_manager()->OnNativeDisplaysChanged(displays); + display_manager()->OnNativeDisplaysChanged(display_info_list); EXPECT_EQ("-500,0 500x500", FindDisplayForId(internal_display_id).bounds().ToString()); EXPECT_EQ("0,0 100x100", FindDisplayForId(10).bounds().ToString()); @@ -527,29 +556,35 @@ TEST_F(DisplayManagerTest, NativeDisplaysChangedAfterPrimaryChange) { TEST_F(DisplayManagerTest, AutomaticOverscanInsets) { UpdateDisplay("200x200,400x400"); - std::vector<gfx::Display> displays; - displays.push_back(*display_manager()->GetDisplayAt(0)); - displays.push_back(*display_manager()->GetDisplayAt(1)); - int64 id = displays[1].id(); - display_manager()->SetHasOverscanFlagForTest(id, true); - - display_manager()->OnNativeDisplaysChanged(displays); + std::vector<DisplayInfo> display_info_list; + display_info_list.push_back(GetDisplayInfoAt(0)); + display_info_list.push_back(GetDisplayInfoAt(1)); + display_info_list[1].set_has_overscan_for_test(true); + int64 id = display_info_list[1].id(); + // SetDefaultOverscanInsets(&display_info_list[1]); + display_manager()->OnNativeDisplaysChanged(display_info_list); // It has overscan insets, although SetOverscanInsets() isn't called. EXPECT_EQ("11,211 380x380", - display_manager()->GetDisplayAt(1)->bounds_in_pixel().ToString()); + GetDisplayInfoAt(1).bounds_in_pixel().ToString()); // If custom overscan insets is specified, the specified value is used. display_manager()->SetOverscanInsets(id, gfx::Insets(5, 6, 7, 8)); - display_manager()->OnNativeDisplaysChanged(displays); + display_manager()->OnNativeDisplaysChanged(display_info_list); EXPECT_EQ("7,206 386x388", - display_manager()->GetDisplayAt(1)->bounds_in_pixel().ToString()); + GetDisplayInfoAt(1).bounds_in_pixel().ToString()); // Do not overscan even though it has 'has_overscan' flag, if the custom // insets is empty. display_manager()->SetOverscanInsets(id, gfx::Insets()); - display_manager()->OnNativeDisplaysChanged(displays); + display_manager()->OnNativeDisplaysChanged(display_info_list); EXPECT_EQ("1,201 400x400", - display_manager()->GetDisplayAt(1)->bounds_in_pixel().ToString()); + GetDisplayInfoAt(1).bounds_in_pixel().ToString()); + + // Clearing the custom overscan should set the bounds to + // original. + display_manager()->ClearCustomOverscanInsets(id); + EXPECT_EQ("11,211 380x380", + GetDisplayInfoAt(1).bounds_in_pixel().ToString()); } } // namespace internal diff --git a/ash/test/ash_test_base.cc b/ash/test/ash_test_base.cc index 980777e..853cdff 100644 --- a/ash/test/ash_test_base.cc +++ b/ash/test/ash_test_base.cc @@ -161,16 +161,6 @@ aura::test::EventGenerator& AshTestBase::GetEventGenerator() { return *event_generator_.get(); } -void AshTestBase::ChangeDisplayConfig(float scale, - const gfx::Rect& bounds_in_pixel) { - gfx::Display display = - gfx::Display(Shell::GetScreen()->GetPrimaryDisplay().id()); - display.SetScaleAndBounds(scale, bounds_in_pixel); - std::vector<gfx::Display> displays; - displays.push_back(display); - Shell::GetInstance()->display_manager()->OnNativeDisplaysChanged(displays); -} - void AshTestBase::UpdateDisplay(const std::string& display_specs) { DisplayManagerTestApi display_manager_test_api( Shell::GetInstance()->display_manager()); diff --git a/ash/test/ash_test_base.h b/ash/test/ash_test_base.h index 2541c15..3b4bd1d 100644 --- a/ash/test/ash_test_base.h +++ b/ash/test/ash_test_base.h @@ -57,10 +57,6 @@ class AshTestBase : public testing::Test { virtual void SetUp() OVERRIDE; virtual void TearDown() OVERRIDE; - // Change the primary display's configuration to use |bounds| - // and |scale|. - void ChangeDisplayConfig(float scale, const gfx::Rect& bounds); - // Update the display configuration as given in |display_specs|. // See ash::test::DisplayManagerTestApi::UpdateDisplay for more details. void UpdateDisplay(const std::string& display_specs); diff --git a/ash/test/display_manager_test_api.cc b/ash/test/display_manager_test_api.cc index dbfb8495..067bbc6 100644 --- a/ash/test/display_manager_test_api.cc +++ b/ash/test/display_manager_test_api.cc @@ -6,6 +6,7 @@ #include <vector> +#include "ash/display/display_info.h" #include "ash/display/display_manager.h" #include "ash/shell.h" #include "base/string_split.h" @@ -14,18 +15,27 @@ namespace ash { namespace test { +typedef std::vector<gfx::Display> DisplayList; +typedef internal::DisplayInfo DisplayInfo; +typedef std::vector<DisplayInfo> DisplayInfoList; + namespace { -std::vector<gfx::Display> CreateDisplaysFromString( - const std::string specs) { - std::vector<gfx::Display> displays; +std::vector<DisplayInfo> CreateDisplayInfoListFromString( + const std::string specs, + internal::DisplayManager* display_manager) { + std::vector<DisplayInfo> display_info_list; std::vector<std::string> parts; base::SplitString(specs, ',', &parts); + int index = 0; for (std::vector<std::string>::const_iterator iter = parts.begin(); - iter != parts.end(); ++iter) { - displays.push_back(internal::CreateDisplayFromSpec(*iter)); + iter != parts.end(); ++iter, ++index) { + gfx::Display* display = display_manager->GetDisplayAt(index); + int64 id = display ? display->id() : gfx::Display::kInvalidDisplayID; + display_info_list.push_back( + DisplayInfo::CreateFromSpecWithID(*iter, id)); } - return displays; + return display_info_list; } } // namespace @@ -39,10 +49,12 @@ DisplayManagerTestApi::~DisplayManagerTestApi() {} void DisplayManagerTestApi::UpdateDisplay( const std::string& display_specs) { - std::vector<gfx::Display> displays = CreateDisplaysFromString(display_specs); + std::vector<DisplayInfo> display_info_list = + CreateDisplayInfoListFromString(display_specs, display_manager_); bool is_host_origin_set = false; - for (size_t i = 0; i < displays.size(); ++i) { - if (displays[i].bounds_in_pixel().origin() != gfx::Point(0, 0)) { + for (size_t i = 0; i < display_info_list.size(); ++i) { + const DisplayInfo& display_info = display_info_list[i]; + if (display_info.bounds_in_pixel().origin() != gfx::Point(0, 0)) { is_host_origin_set = true; break; } @@ -56,18 +68,25 @@ void DisplayManagerTestApi::UpdateDisplay( // Sart from (1,1) so that windows won't overlap with native mouse cursor. // See |AshTestBase::SetUp()|. int next_y = 1; - for (std::vector<gfx::Display>::iterator iter = displays.begin(); - iter != displays.end(); ++iter) { - gfx::Rect bounds(iter->GetSizeInPixel()); + for (std::vector<DisplayInfo>::iterator iter = display_info_list.begin(); + iter != display_info_list.end(); ++iter) { + gfx::Rect bounds(iter->bounds_in_pixel().size()); bounds.set_x(1); bounds.set_y(next_y); next_y += bounds.height(); - iter->SetScaleAndBounds(iter->device_scale_factor(), bounds); + iter->SetBounds(bounds); } } - display_manager_->SetDisplayIdsForTest(&displays); - display_manager_->OnNativeDisplaysChanged(displays); + display_manager_->OnNativeDisplaysChanged(display_info_list); +} + +int64 DisplayManagerTestApi::SetFirstDisplayAsInternalDisplay() { + const gfx::Display& internal = display_manager_->displays_[0]; + gfx::Display::SetInternalDisplayId(internal.id()); + display_manager_->internal_display_info_.reset(new DisplayInfo( + display_manager_->GetDisplayInfo(internal))); + return gfx::Display::InternalDisplayId(); } } // namespace test diff --git a/ash/test/display_manager_test_api.h b/ash/test/display_manager_test_api.h index 57e961d..e6a83708 100644 --- a/ash/test/display_manager_test_api.h +++ b/ash/test/display_manager_test_api.h @@ -27,6 +27,10 @@ class DisplayManagerTestApi { // the format of the display spec. void UpdateDisplay(const std::string& display_specs); + // Set the 1st display as an internal display and returns the display Id for + // the internal display. + int64 SetFirstDisplayAsInternalDisplay(); + private: internal::DisplayManager* display_manager_; // not owned diff --git a/ash/wm/system_gesture_event_filter_unittest.cc b/ash/wm/system_gesture_event_filter_unittest.cc index a5d345c..391cfbf 100644 --- a/ash/wm/system_gesture_event_filter_unittest.cc +++ b/ash/wm/system_gesture_event_filter_unittest.cc @@ -13,6 +13,7 @@ #include "ash/system/brightness/brightness_control_delegate.h" #include "ash/system/tray/system_tray_delegate.h" #include "ash/test/ash_test_base.h" +#include "ash/test/display_manager_test_api.h" #include "ash/test/shell_test_api.h" #include "ash/test/test_launcher_delegate.h" #include "ash/volume_control_delegate.h" @@ -216,8 +217,8 @@ class SystemGestureEventFilterTest : public AshTestBase { ::switches::kEnableBezelTouch); test::AshTestBase::SetUp(); // Enable brightness key. - Shell::GetInstance()->display_manager()-> - SetFirstDisplayAsInternalDisplayForTest(); + test::DisplayManagerTestApi(Shell::GetInstance()->display_manager()). + SetFirstDisplayAsInternalDisplay(); } private: diff --git a/ui/aura/root_window.cc b/ui/aura/root_window.cc index 7305ca7..7ff474f 100644 --- a/ui/aura/root_window.cc +++ b/ui/aura/root_window.cc @@ -196,6 +196,7 @@ gfx::Size RootWindow::GetHostSize() const { } void RootWindow::SetHostBounds(const gfx::Rect& bounds_in_pixel) { + DCHECK(!bounds_in_pixel.IsEmpty()); DispatchHeldMouseMove(); host_->SetBounds(bounds_in_pixel); synthesize_mouse_move_ = false; diff --git a/ui/base/x/events_x.cc b/ui/base/x/events_x.cc index 3fba257f0..e4ca121 100644 --- a/ui/base/x/events_x.cc +++ b/ui/base/x/events_x.cc @@ -718,10 +718,10 @@ gfx::Point CalibrateTouchCoordinates( !top_border_touch_calibration && !bottom_border_touch_calibration) return gfx::Point(x, y); - gfx::Rect bounds = - gfx::Screen::GetNativeScreen()->GetPrimaryDisplay().bounds_in_pixel(); - const int resolution_x = bounds.width(); - const int resolution_y = bounds.height(); + gfx::Display display = gfx::Screen::GetNativeScreen()->GetPrimaryDisplay(); + gfx::Rect bounds = display.bounds(); + const int resolution_x = bounds.width() * display.device_scale_factor(); + const int resolution_y = bounds.height() * display.device_scale_factor(); // The "grace area" (10% in this case) is to make it easier for the user to // navigate to the corner. const double kGraceAreaFraction = 0.1; diff --git a/ui/base/x/x11_util.cc b/ui/base/x/x11_util.cc index cb57e09..ad59097 100644 --- a/ui/base/x/x11_util.cc +++ b/ui/base/x/x11_util.cc @@ -1488,16 +1488,6 @@ bool ParseOutputOverscanFlag(const unsigned char* prop, return false; } -std::vector<std::string> GetDisplayNames(const std::vector<XID>& output_ids) { - std::vector<std::string> names; - for (size_t i = 0; i < output_ids.size(); ++i) { - std::string display_name; - if (GetOutputDeviceData(output_ids[i], NULL, NULL, &display_name)) - names.push_back(display_name); - } - return names; -} - std::vector<std::string> GetOutputNames(const std::vector<XID>& output_ids) { std::vector<std::string> names; Display* display = GetXDisplay(); diff --git a/ui/base/x/x11_util.h b/ui/base/x/x11_util.h index 377dd41..1169f87 100644 --- a/ui/base/x/x11_util.h +++ b/ui/base/x/x11_util.h @@ -303,13 +303,9 @@ UI_EXPORT bool ParseOutputOverscanFlag(const unsigned char* prop, unsigned long nitems, bool* flag); -// Gets the names of the all displays physically connected to the system. -UI_EXPORT std::vector<std::string> GetDisplayNames( - const std::vector<XID>& output_id); - -// Gets the name of outputs given by |output_id|. +// Gets the name of outputs given by |output_ids|. UI_EXPORT std::vector<std::string> GetOutputNames( - const std::vector<XID>& output_id); + const std::vector<XID>& output_ids); enum WindowManagerName { WM_UNKNOWN, diff --git a/ui/gfx/display.cc b/ui/gfx/display.cc index 7aa1241..73f33b3 100644 --- a/ui/gfx/display.cc +++ b/ui/gfx/display.cc @@ -11,6 +11,7 @@ #include "ui/base/ui_base_switches.h" #include "ui/base/win/dpi.h" #include "ui/gfx/insets.h" +#include "ui/gfx/point_f.h" #include "ui/gfx/size_conversions.h" namespace gfx { @@ -103,22 +104,19 @@ void Display::SetScaleAndBounds( device_scale_factor_ = device_scale_factor; } device_scale_factor_ = std::max(1.0f, device_scale_factor_); -#if defined(USE_AURA) - bounds_in_pixel_ = bounds_in_pixel; -#endif bounds_ = gfx::Rect(gfx::ToFlooredSize( gfx::ScaleSize(bounds_in_pixel.size(), 1.0f / device_scale_factor_))); UpdateWorkAreaFromInsets(insets); } void Display::SetSize(const gfx::Size& size_in_pixel) { - SetScaleAndBounds( - device_scale_factor_, + gfx::Point origin = bounds_.origin(); #if defined(USE_AURA) - gfx::Rect(bounds_in_pixel_.origin(), size_in_pixel)); -#else - gfx::Rect(bounds_.origin(), size_in_pixel)); + gfx::PointF origin_f = origin; + origin_f.Scale(device_scale_factor_); + origin.SetPoint(origin_f.x(), origin_f.y()); #endif + SetScaleAndBounds(device_scale_factor_, gfx::Rect(origin, size_in_pixel)); } void Display::UpdateWorkAreaFromInsets(const gfx::Insets& insets) { diff --git a/ui/gfx/display.h b/ui/gfx/display.h index 4df69b7..81963f2 100644 --- a/ui/gfx/display.h +++ b/ui/gfx/display.h @@ -88,13 +88,6 @@ class UI_EXPORT Display { // Returns the display's size in pixel coordinates. gfx::Size GetSizeInPixel() const; -#if defined(USE_AURA) - // TODO(oshima|skuhne): Eliminate the use of bounds_in_pixel in events_x.cc - // and remove bounds_in_pixel from gfx::Display. - // Returns the display's bounds in pixel coordinates. - const Rect& bounds_in_pixel() const { return bounds_in_pixel_; } -#endif - // Returns a string representation of the display; std::string ToString() const; @@ -114,9 +107,6 @@ class UI_EXPORT Display { int64 id_; Rect bounds_; Rect work_area_; -#if defined(USE_AURA) - Rect bounds_in_pixel_; -#endif float device_scale_factor_; }; |