diff options
-rw-r--r-- | ash/display/display_controller.cc | 148 | ||||
-rw-r--r-- | ash/display/display_controller.h | 60 | ||||
-rw-r--r-- | ash/display/display_controller_unittest.cc | 20 | ||||
-rw-r--r-- | ash/display/mouse_cursor_event_filter.cc | 22 | ||||
-rw-r--r-- | ash/display/mouse_cursor_event_filter.h | 3 | ||||
-rw-r--r-- | ash/display/mouse_cursor_event_filter_unittest.cc | 42 | ||||
-rw-r--r-- | ash/extended_desktop_unittest.cc | 17 | ||||
-rw-r--r-- | ash/shell.cc | 2 | ||||
-rw-r--r-- | ash/shell.h | 6 | ||||
-rw-r--r-- | chrome/browser/chromeos/display/OWNERS | 2 | ||||
-rw-r--r-- | chrome/browser/chromeos/display/display_preferences.cc | 123 | ||||
-rw-r--r-- | chrome/browser/chromeos/display/display_preferences.h | 30 | ||||
-rw-r--r-- | chrome/browser/chromeos/preferences.cc | 36 | ||||
-rw-r--r-- | chrome/browser/chromeos/preferences.h | 3 | ||||
-rw-r--r-- | chrome/browser/ui/webui/options/chromeos/display_options_handler.cc | 38 | ||||
-rw-r--r-- | chrome/chrome_browser_chromeos.gypi | 2 | ||||
-rw-r--r-- | chrome/common/pref_names.cc | 5 | ||||
-rw-r--r-- | chrome/common/pref_names.h | 1 |
18 files changed, 427 insertions, 133 deletions
diff --git a/ash/display/display_controller.cc b/ash/display/display_controller.cc index 1a2ed63..16ee88c 100644 --- a/ash/display/display_controller.cc +++ b/ash/display/display_controller.cc @@ -15,6 +15,9 @@ #include "ash/wm/property_util.h" #include "ash/wm/window_util.h" #include "base/command_line.h" +#include "base/json/json_value_converter.h" +#include "base/string_piece.h" +#include "base/values.h" #include "ui/aura/client/screen_position_client.h" #include "ui/aura/env.h" #include "ui/aura/root_window.h" @@ -28,18 +31,102 @@ #endif namespace ash { -namespace internal { namespace { +// The maximum value for 'offset' in DisplayLayout in case of outliers. Need +// to change this value in case to support even larger displays. +const int kMaxValidOffset = 10000; + // The number of pixels to overlap between the primary and secondary displays, // in case that the offset value is too large. const int kMinimumOverlapForInvalidOffset = 50; +bool GetPositionFromString(const base::StringPiece& position, + DisplayLayout::Position* field) { + if (position == "top") { + *field = DisplayLayout::TOP; + return true; + } else if (position == "bottom") { + *field = DisplayLayout::BOTTOM; + return true; + } else if (position == "right") { + *field = DisplayLayout::RIGHT; + return true; + } else if (position == "left") { + *field = DisplayLayout::LEFT; + return true; + } + LOG(ERROR) << "Invalid position value: " << position; + + return false; +} + +} // namespace + +DisplayLayout::DisplayLayout() + : position(RIGHT), + offset(0) {} + +DisplayLayout::DisplayLayout(DisplayLayout::Position position, int offset) + : position(position), + offset(offset) { + DCHECK_LE(TOP, position); + DCHECK_GE(LEFT, position); + + // Set the default value to |position| in case position is invalid. DCHECKs + // above doesn't stop in Release builds. + if (TOP > position || LEFT < position) + this->position = RIGHT; + + DCHECK_GE(kMaxValidOffset, abs(offset)); +} + +// static +bool DisplayLayout::ConvertFromValue(const base::Value& value, + DisplayLayout* layout) { + base::JSONValueConverter<DisplayLayout> converter; + return converter.Convert(value, layout); +} + +// static +bool DisplayLayout::ConvertToValue(const DisplayLayout& layout, + base::Value* value) { + base::DictionaryValue* dict_value = NULL; + if (!value->GetAsDictionary(&dict_value) || dict_value == NULL) + return false; + + std::string position_value; + switch (layout.position) { + case TOP: + position_value = "top"; + break; + case BOTTOM: + position_value = "bottom"; + break; + case RIGHT: + position_value = "right"; + break; + case LEFT: + position_value = "left"; + break; + default: + return false; + } + + dict_value->SetString("position", position_value); + dict_value->SetInteger("offset", layout.offset); + return true; +} + +// static +void DisplayLayout::RegisterJSONConverter( + base::JSONValueConverter<DisplayLayout>* converter) { + converter->RegisterCustomField<Position>( + "position", &DisplayLayout::position, &GetPositionFromString); + converter->RegisterIntField("offset", &DisplayLayout::offset); } -DisplayController::DisplayController() - : secondary_display_layout_(RIGHT), - secondary_display_offset_(0) { +DisplayController::DisplayController() { aura::Env::GetInstance()->display_manager()->AddObserver(this); } @@ -80,14 +167,14 @@ void DisplayController::InitSecondaryDisplays() { int offset; if (sscanf(value.c_str(), "%c,%d", &layout, &offset) == 2) { if (layout == 't') - secondary_display_layout_ = TOP; + default_display_layout_.position = DisplayLayout::TOP; else if (layout == 'b') - secondary_display_layout_ = BOTTOM; + default_display_layout_.position = DisplayLayout::BOTTOM; else if (layout == 'r') - secondary_display_layout_ = RIGHT; + default_display_layout_.position = DisplayLayout::RIGHT; else if (layout == 'l') - secondary_display_layout_ = LEFT; - secondary_display_offset_ = offset; + default_display_layout_.position = DisplayLayout::LEFT; + default_display_layout_.offset = offset; } } UpdateDisplayBoundsForLayout(); @@ -145,17 +232,26 @@ DisplayController::GetAllRootWindowControllers() { return controllers; } -void DisplayController::SetSecondaryDisplayLayout( - SecondaryDisplayLayout layout) { - secondary_display_layout_ = layout; +void DisplayController::SetDefaultDisplayLayout(const DisplayLayout& layout) { + default_display_layout_ = layout; UpdateDisplayBoundsForLayout(); } -void DisplayController::SetSecondaryDisplayOffset(int offset) { - secondary_display_offset_ = offset; +void DisplayController::SetLayoutForDisplayName(const std::string& name, + const DisplayLayout& layout) { + secondary_layouts_[name] = layout; UpdateDisplayBoundsForLayout(); } +const DisplayLayout& DisplayController::GetLayoutForDisplayName( + const std::string& name) { + std::map<std::string, DisplayLayout>::const_iterator it = + secondary_layouts_.find(name); + + if (it != secondary_layouts_.end()) + return it->second; + return default_display_layout_; +} void DisplayController::OnDisplayBoundsChanged(const gfx::Display& display) { root_windows_[display.id()]->SetHostBounds(display.bounds_in_pixel()); @@ -215,13 +311,22 @@ void DisplayController::UpdateDisplayBoundsForLayout() { aura::Env::GetInstance()->display_manager(); const gfx::Rect& primary_bounds = display_manager->GetDisplayAt(0)->bounds(); gfx::Display* secondary_display = display_manager->GetDisplayAt(1); + const std::string& secondary_name = display_manager->GetDisplayNameAt(1); const gfx::Rect& secondary_bounds = secondary_display->bounds(); gfx::Point new_secondary_origin = primary_bounds.origin(); + const DisplayLayout* layout = &default_display_layout_; + std::map<std::string, DisplayLayout>::const_iterator iter = + secondary_layouts_.find(secondary_name); + if (iter != secondary_layouts_.end()) + layout = &iter->second; + + DisplayLayout::Position position = layout->position; + // Ignore the offset in case the secondary display doesn't share edges with // the primary display. - int offset = secondary_display_offset_; - if (secondary_display_layout_ == TOP || secondary_display_layout_ == BOTTOM) { + int offset = layout->offset; + if (position == DisplayLayout::TOP || position == DisplayLayout::BOTTOM) { offset = std::min( offset, primary_bounds.width() - kMinimumOverlapForInvalidOffset); offset = std::max( @@ -232,17 +337,17 @@ void DisplayController::UpdateDisplayBoundsForLayout() { offset = std::max( offset, -secondary_bounds.height() + kMinimumOverlapForInvalidOffset); } - switch (secondary_display_layout_) { - case TOP: + switch (position) { + case DisplayLayout::TOP: new_secondary_origin.Offset(offset, -secondary_bounds.height()); break; - case RIGHT: + case DisplayLayout::RIGHT: new_secondary_origin.Offset(primary_bounds.width(), offset); break; - case BOTTOM: + case DisplayLayout::BOTTOM: new_secondary_origin.Offset(offset, primary_bounds.height()); break; - case LEFT: + case DisplayLayout::LEFT: new_secondary_origin.Offset(-secondary_bounds.width(), offset); break; } @@ -252,5 +357,4 @@ void DisplayController::UpdateDisplayBoundsForLayout() { secondary_display->UpdateWorkAreaFromInsets(insets); } -} // namespace internal } // namespace ash diff --git a/ash/display/display_controller.h b/ash/display/display_controller.h index 324214f..d6e122e 100644 --- a/ash/display/display_controller.h +++ b/ash/display/display_controller.h @@ -19,22 +19,48 @@ class Display; class RootWindow; } +namespace base { +class Value; +template <typename T> class JSONValueConverter; +} + namespace ash { namespace internal { class RootWindowController; +} -// DisplayController owns and maintains RootWindows for each attached -// display, keeping them in sync with display configuration changes. -class ASH_EXPORT DisplayController : public aura::DisplayObserver { - public: +struct ASH_EXPORT DisplayLayout { // Layout options where the secondary display should be positioned. - enum SecondaryDisplayLayout { + enum Position { TOP, RIGHT, BOTTOM, LEFT }; + DisplayLayout(); + DisplayLayout(Position position, int offset); + + // Converter functions to/from base::Value. + static bool ConvertFromValue(const base::Value& value, DisplayLayout* layout); + static bool ConvertToValue(const DisplayLayout& layout, base::Value* value); + + // This method is used by base::JSONValueConverter, you don't need to call + // this directly. Instead consider using converter functions above. + static void RegisterJSONConverter( + base::JSONValueConverter<DisplayLayout>* converter); + + Position position; + + // The offset of the position of the secondary display. The offset is + // based on the top/left edge of the primary display. + int offset; +}; + +// DisplayController owns and maintains RootWindows for each attached +// display, keeping them in sync with display configuration changes. +class ASH_EXPORT DisplayController : public aura::DisplayObserver { + public: DisplayController(); virtual ~DisplayController(); @@ -61,15 +87,16 @@ class ASH_EXPORT DisplayController : public aura::DisplayObserver { // mode, this return a RootWindowController for the primary root window only. std::vector<internal::RootWindowController*> GetAllRootWindowControllers(); - SecondaryDisplayLayout secondary_display_layout() const { - return secondary_display_layout_; + const DisplayLayout& default_display_layout() const { + return default_display_layout_; } - void SetSecondaryDisplayLayout(SecondaryDisplayLayout layout); + void SetDefaultDisplayLayout(const DisplayLayout& layout); - int secondary_display_offset() const { - return secondary_display_offset_; - } - void SetSecondaryDisplayOffset(int offset); + // Sets/gets the display layout for the specified display name. Getter + // returns the default value in case it doesn't have its own layout yet. + void SetLayoutForDisplayName(const std::string& name, + const DisplayLayout& layout); + const DisplayLayout& GetLayoutForDisplayName(const std::string& name); // aura::DisplayObserver overrides: virtual void OnDisplayBoundsChanged( @@ -87,16 +114,15 @@ class ASH_EXPORT DisplayController : public aura::DisplayObserver { // The mapping from display ID to its root window. std::map<int64, aura::RootWindow*> root_windows_; - SecondaryDisplayLayout secondary_display_layout_; + // The default display layout. + DisplayLayout default_display_layout_; - // The offset of the position of the secondary display. The offset is - // based on the top/left edge of the primary display. - int secondary_display_offset_; + // Per-device display layout. + std::map<std::string, DisplayLayout> secondary_layouts_; DISALLOW_COPY_AND_ASSIGN(DisplayController); }; -} // namespace internal } // namespace ash #endif // ASH_DISPLAY_DISPLAY_CONTROLLER_H_ diff --git a/ash/display/display_controller_unittest.cc b/ash/display/display_controller_unittest.cc index 7f2d461..9915753 100644 --- a/ash/display/display_controller_unittest.cc +++ b/ash/display/display_controller_unittest.cc @@ -26,6 +26,14 @@ gfx::Display GetSecondaryDisplay() { Shell::GetAllRootWindows()[1]); } +void SetSecondaryDisplayLayout(DisplayLayout::Position position) { + DisplayController* display_controller = + Shell::GetInstance()->display_controller(); + DisplayLayout layout = display_controller->default_display_layout(); + layout.position = position; + display_controller->SetDefaultDisplayLayout(layout); +} + } // namespace typedef test::AshTestBase DisplayControllerTest; @@ -51,22 +59,19 @@ TEST_F(DisplayControllerTest, MAYBE_SecondaryDisplayLayout) { EXPECT_EQ("505,5 390x390", GetSecondaryDisplay().work_area().ToString()); // Layout the secondary display to the bottom of the primary. - Shell::GetInstance()->display_controller()->SetSecondaryDisplayLayout( - internal::DisplayController::BOTTOM); + SetSecondaryDisplayLayout(DisplayLayout::BOTTOM); EXPECT_EQ("0,0 500x500", GetPrimaryDisplay().bounds().ToString()); EXPECT_EQ("0,500 400x400", GetSecondaryDisplay().bounds().ToString()); EXPECT_EQ("5,505 390x390", GetSecondaryDisplay().work_area().ToString()); // Layout the secondary display to the left of the primary. - Shell::GetInstance()->display_controller()->SetSecondaryDisplayLayout( - internal::DisplayController::LEFT); + SetSecondaryDisplayLayout(DisplayLayout::LEFT); EXPECT_EQ("0,0 500x500", GetPrimaryDisplay().bounds().ToString()); EXPECT_EQ("-400,0 400x400", GetSecondaryDisplay().bounds().ToString()); EXPECT_EQ("-395,5 390x390", GetSecondaryDisplay().work_area().ToString()); // Layout the secondary display to the top of the primary. - Shell::GetInstance()->display_controller()->SetSecondaryDisplayLayout( - internal::DisplayController::TOP); + SetSecondaryDisplayLayout(DisplayLayout::TOP); EXPECT_EQ("0,0 500x500", GetPrimaryDisplay().bounds().ToString()); EXPECT_EQ("0,-400 400x400", GetSecondaryDisplay().bounds().ToString()); EXPECT_EQ("5,-395 390x390", GetSecondaryDisplay().work_area().ToString()); @@ -77,8 +82,7 @@ TEST_F(DisplayControllerTest, MAYBE_SecondaryDisplayLayout) { // always been incorrect, but is now visibly broken now that we're processing // X11 configuration events while waiting for the MapNotify. TEST_F(DisplayControllerTest, DISABLED_BoundsUpdated) { - Shell::GetInstance()->display_controller()->SetSecondaryDisplayLayout( - internal::DisplayController::BOTTOM); + SetSecondaryDisplayLayout(DisplayLayout::BOTTOM); UpdateDisplay("500x500,400x400"); gfx::Display* secondary_display = aura::Env::GetInstance()->display_manager()->GetDisplayAt(1); diff --git a/ash/display/mouse_cursor_event_filter.cc b/ash/display/mouse_cursor_event_filter.cc index d2ad3e4..b84986e 100644 --- a/ash/display/mouse_cursor_event_filter.cc +++ b/ash/display/mouse_cursor_event_filter.cc @@ -55,9 +55,9 @@ void MouseCursorEventFilter::ShowSharedEdgeIndicator( } drag_source_root_ = from; - DisplayController::SecondaryDisplayLayout layout = - Shell::GetInstance()->display_controller()->secondary_display_layout(); - if (layout == DisplayController::TOP || layout == DisplayController::BOTTOM) + DisplayLayout::Position position = Shell::GetInstance()-> + display_controller()->default_display_layout().position; + if (position == DisplayLayout::TOP || position == DisplayLayout::BOTTOM) UpdateHorizontalIndicatorWindowBounds(); else UpdateVerticalIndicatorWindowBounds(); @@ -165,8 +165,8 @@ void MouseCursorEventFilter::UpdateHorizontalIndicatorWindowBounds() { const gfx::Rect& primary_bounds = display_manager->GetDisplayAt(0)->bounds(); const gfx::Rect& secondary_bounds = display_manager->GetDisplayAt(1)->bounds(); - DisplayController::SecondaryDisplayLayout layout = - Shell::GetInstance()->display_controller()->secondary_display_layout(); + DisplayLayout::Position position = Shell::GetInstance()-> + display_controller()->default_display_layout().position; src_indicator_bounds_.set_x( std::max(primary_bounds.x(), secondary_bounds.x())); @@ -175,14 +175,14 @@ void MouseCursorEventFilter::UpdateHorizontalIndicatorWindowBounds() { src_indicator_bounds_.x()); src_indicator_bounds_.set_height(kIndicatorThickness); src_indicator_bounds_.set_y( - layout == DisplayController::TOP ? + position == DisplayLayout::TOP ? primary_bounds.y() - (from_primary ? 0 : kIndicatorThickness) : primary_bounds.bottom() - (from_primary ? kIndicatorThickness : 0)); dst_indicator_bounds_ = src_indicator_bounds_; dst_indicator_bounds_.set_height(kIndicatorThickness); dst_indicator_bounds_.set_y( - layout == DisplayController::TOP ? + position == DisplayLayout::TOP ? primary_bounds.y() - (from_primary ? kIndicatorThickness : 0) : primary_bounds.bottom() - (from_primary ? 0 : kIndicatorThickness)); } @@ -194,15 +194,15 @@ void MouseCursorEventFilter::UpdateVerticalIndicatorWindowBounds() { const gfx::Rect& primary_bounds = display_manager->GetDisplayAt(0)->bounds(); const gfx::Rect& secondary_bounds = display_manager->GetDisplayAt(1)->bounds(); - DisplayController::SecondaryDisplayLayout layout = - Shell::GetInstance()->display_controller()->secondary_display_layout(); + DisplayLayout::Position position = Shell::GetInstance()-> + display_controller()->default_display_layout().position; int upper_shared_y = std::max(primary_bounds.y(), secondary_bounds.y()); int lower_shared_y = std::min(primary_bounds.bottom(), secondary_bounds.bottom()); int shared_height = lower_shared_y - upper_shared_y; - int dst_x = layout == DisplayController::LEFT ? + int dst_x = position == DisplayLayout::LEFT ? primary_bounds.x() - (in_primary ? kIndicatorThickness : 0) : primary_bounds.right() - (in_primary ? 0 : kIndicatorThickness); dst_indicator_bounds_.SetRect( @@ -211,7 +211,7 @@ void MouseCursorEventFilter::UpdateVerticalIndicatorWindowBounds() { // The indicator on the source display. src_indicator_bounds_.set_width(kIndicatorThickness); src_indicator_bounds_.set_x( - layout == DisplayController::LEFT ? + position == DisplayLayout::LEFT ? primary_bounds.x() - (in_primary ? 0 : kIndicatorThickness) : primary_bounds.right() - (in_primary ? kIndicatorThickness : 0)); diff --git a/ash/display/mouse_cursor_event_filter.h b/ash/display/mouse_cursor_event_filter.h index 03e67bc..b6113fb 100644 --- a/ash/display/mouse_cursor_event_filter.h +++ b/ash/display/mouse_cursor_event_filter.h @@ -17,8 +17,9 @@ class RootWindow; } namespace ash { -namespace internal { class DisplayController; + +namespace internal { class SharedDisplayEdgeIndicator; // An event filter that controls mouse location in extended desktop diff --git a/ash/display/mouse_cursor_event_filter_unittest.cc b/ash/display/mouse_cursor_event_filter_unittest.cc index b7421e1..aca0a1b 100644 --- a/ash/display/mouse_cursor_event_filter_unittest.cc +++ b/ash/display/mouse_cursor_event_filter_unittest.cc @@ -38,8 +38,9 @@ TEST_F(MouseCursorEventFilterTest, WarpMouse) { MouseCursorEventFilter* event_filter = Shell::GetInstance()->mouse_cursor_filter(); ASSERT_EQ( - DisplayController::RIGHT, - Shell::GetInstance()->display_controller()->secondary_display_layout()); + DisplayLayout::RIGHT, + Shell::GetInstance()-> + display_controller()->default_display_layout().position); Shell::RootWindowList root_windows = Shell::GetAllRootWindows(); bool is_warped = event_filter->WarpMouseCursorIfNecessary(root_windows[0], @@ -97,8 +98,9 @@ TEST_F(MouseCursorEventFilterTest, WarpMouseDifferentSizeDisplays) { MouseCursorEventFilter* event_filter = Shell::GetInstance()->mouse_cursor_filter(); ASSERT_EQ( - DisplayController::RIGHT, - Shell::GetInstance()->display_controller()->secondary_display_layout()); + DisplayLayout::RIGHT, + Shell::GetInstance()-> + display_controller()->default_display_layout().position); Shell::RootWindowList root_windows = Shell::GetAllRootWindows(); aura::Env::GetInstance()->SetLastMouseLocation(*root_windows[1], @@ -154,8 +156,8 @@ TEST_F(MouseCursorEventFilterTest, IndicatorBoundsTestOnRight) { DisplayController* controller = Shell::GetInstance()->display_controller(); - controller->SetSecondaryDisplayLayout(DisplayController::RIGHT); - controller->SetSecondaryDisplayOffset(0); + DisplayLayout default_layout(DisplayLayout::RIGHT, 0); + controller->SetDefaultDisplayLayout(default_layout); ash::internal::MouseCursorEventFilter* event_filter = Shell::GetInstance()->mouse_cursor_filter(); event_filter->ShowSharedEdgeIndicator(root_windows[0] /* primary */); @@ -166,7 +168,8 @@ TEST_F(MouseCursorEventFilterTest, IndicatorBoundsTestOnRight) { EXPECT_EQ("350,0 10x360", event_filter->dst_indicator_bounds_.ToString()); // Move 2nd display downwards a bit. - controller->SetSecondaryDisplayOffset(50); + default_layout.offset = 50; + controller->SetDefaultDisplayLayout(default_layout); event_filter->ShowSharedEdgeIndicator(root_windows[0] /* primary */); // This is same as before because the 2nd display's y is above // the warp hole's x. @@ -178,7 +181,8 @@ TEST_F(MouseCursorEventFilterTest, IndicatorBoundsTestOnRight) { // Move it down further so that the shared edge is shorter than // minimum hole size (160). - controller->SetSecondaryDisplayOffset(200); + default_layout.offset = 200; + controller->SetDefaultDisplayLayout(default_layout); event_filter->ShowSharedEdgeIndicator(root_windows[0] /* primary */); EXPECT_EQ("350,200 10x160", event_filter->src_indicator_bounds_.ToString()); EXPECT_EQ("360,200 10x160", event_filter->dst_indicator_bounds_.ToString()); @@ -187,7 +191,8 @@ TEST_F(MouseCursorEventFilterTest, IndicatorBoundsTestOnRight) { EXPECT_EQ("350,200 10x160", event_filter->dst_indicator_bounds_.ToString()); // Now move 2nd display upwards - controller->SetSecondaryDisplayOffset(-80); + default_layout.offset = -80; + controller->SetDefaultDisplayLayout(default_layout); event_filter->ShowSharedEdgeIndicator(root_windows[0] /* primary */); EXPECT_EQ("350,80 10x200", event_filter->src_indicator_bounds_.ToString()); EXPECT_EQ("360,0 10x360", event_filter->dst_indicator_bounds_.ToString()); @@ -206,8 +211,8 @@ TEST_F(MouseCursorEventFilterTest, IndicatorBoundsTestOnLeft) { DisplayController* controller = Shell::GetInstance()->display_controller(); - controller->SetSecondaryDisplayLayout(DisplayController::LEFT); - controller->SetSecondaryDisplayOffset(0); + DisplayLayout default_layout(DisplayLayout::LEFT, 0); + controller->SetDefaultDisplayLayout(default_layout); ash::internal::MouseCursorEventFilter* event_filter = Shell::GetInstance()->mouse_cursor_filter(); event_filter->ShowSharedEdgeIndicator(root_windows[0] /* primary */); @@ -217,7 +222,8 @@ TEST_F(MouseCursorEventFilterTest, IndicatorBoundsTestOnLeft) { EXPECT_EQ("-10,100 10x260", event_filter->src_indicator_bounds_.ToString()); EXPECT_EQ("0,0 10x360", event_filter->dst_indicator_bounds_.ToString()); - controller->SetSecondaryDisplayOffset(300); + default_layout.offset = 300; + controller->SetDefaultDisplayLayout(default_layout); event_filter->ShowSharedEdgeIndicator(root_windows[0] /* primary */); EXPECT_EQ("0,300 10x60", event_filter->src_indicator_bounds_.ToString()); EXPECT_EQ("-10,300 10x60", event_filter->dst_indicator_bounds_.ToString()); @@ -233,8 +239,8 @@ TEST_F(MouseCursorEventFilterTest, IndicatorBoundsTestOnTopBottom) { DisplayController* controller = Shell::GetInstance()->display_controller(); - controller->SetSecondaryDisplayLayout(DisplayController::TOP); - controller->SetSecondaryDisplayOffset(0); + DisplayLayout default_layout(DisplayLayout::TOP, 0); + controller->SetDefaultDisplayLayout(default_layout); ash::internal::MouseCursorEventFilter* event_filter = Shell::GetInstance()->mouse_cursor_filter(); event_filter->ShowSharedEdgeIndicator(root_windows[0] /* primary */); @@ -244,7 +250,8 @@ TEST_F(MouseCursorEventFilterTest, IndicatorBoundsTestOnTopBottom) { EXPECT_EQ("0,-10 360x10", event_filter->src_indicator_bounds_.ToString()); EXPECT_EQ("0,0 360x10", event_filter->dst_indicator_bounds_.ToString()); - controller->SetSecondaryDisplayOffset(300); + default_layout.offset = 300; + controller->SetDefaultDisplayLayout(default_layout); event_filter->ShowSharedEdgeIndicator(root_windows[0] /* primary */); EXPECT_EQ("300,0 60x10", event_filter->src_indicator_bounds_.ToString()); EXPECT_EQ("300,-10 60x10", event_filter->dst_indicator_bounds_.ToString()); @@ -252,8 +259,9 @@ TEST_F(MouseCursorEventFilterTest, IndicatorBoundsTestOnTopBottom) { EXPECT_EQ("300,-10 60x10", event_filter->src_indicator_bounds_.ToString()); EXPECT_EQ("300,0 60x10", event_filter->dst_indicator_bounds_.ToString()); - controller->SetSecondaryDisplayLayout(DisplayController::BOTTOM); - controller->SetSecondaryDisplayOffset(0); + default_layout.position = DisplayLayout::BOTTOM; + default_layout.offset = 0; + controller->SetDefaultDisplayLayout(default_layout); event_filter->ShowSharedEdgeIndicator(root_windows[0] /* primary */); EXPECT_EQ("0,350 360x10", event_filter->src_indicator_bounds_.ToString()); EXPECT_EQ("0,360 360x10", event_filter->dst_indicator_bounds_.ToString()); diff --git a/ash/extended_desktop_unittest.cc b/ash/extended_desktop_unittest.cc index 572bb68..5b65afe 100644 --- a/ash/extended_desktop_unittest.cc +++ b/ash/extended_desktop_unittest.cc @@ -44,6 +44,14 @@ views::Widget* CreateTestWidget(const gfx::Rect& bounds) { return CreateTestWidgetWithParent(NULL, bounds, false); } +void SetSecondaryDisplayLayout(DisplayLayout::Position position) { + DisplayController* display_controller = + Shell::GetInstance()->display_controller(); + DisplayLayout layout = display_controller->default_display_layout(); + layout.position = position; + display_controller->SetDefaultDisplayLayout(layout); +} + class ModalWidgetDelegate : public views::WidgetDelegateView { public: ModalWidgetDelegate() {} @@ -242,8 +250,7 @@ TEST_F(ExtendedDesktopTest, CycleWindows) { TEST_F(ExtendedDesktopTest, GetRootWindowAt) { UpdateDisplay("700x500,500x500"); - Shell::GetInstance()->display_controller()->SetSecondaryDisplayLayout( - internal::DisplayController::LEFT); + SetSecondaryDisplayLayout(DisplayLayout::LEFT); Shell::RootWindowList root_windows = Shell::GetAllRootWindows(); EXPECT_EQ(root_windows[1], wm::GetRootWindowAt(gfx::Point(-400, 100))); @@ -261,8 +268,7 @@ TEST_F(ExtendedDesktopTest, GetRootWindowAt) { TEST_F(ExtendedDesktopTest, GetRootWindowMatching) { UpdateDisplay("700x500,500x500"); - Shell::GetInstance()->display_controller()->SetSecondaryDisplayLayout( - internal::DisplayController::LEFT); + SetSecondaryDisplayLayout(DisplayLayout::LEFT); Shell::RootWindowList root_windows = Shell::GetAllRootWindows(); @@ -504,8 +510,7 @@ TEST_F(ExtendedDesktopTest, ConvertPoint) { EXPECT_EQ("-1010,-10", p.ToString()); // Move the 2nd display to the bottom and test again. - Shell::GetInstance()->display_controller()->SetSecondaryDisplayLayout( - internal::DisplayController::BOTTOM); + SetSecondaryDisplayLayout(DisplayLayout::BOTTOM); display_2 = GetDisplayManager()->FindDisplayForRootWindow(root_windows[1]); EXPECT_EQ("0,600", display_2.bounds().origin().ToString()); diff --git a/ash/shell.cc b/ash/shell.cc index 19a612e..f43a1e35 100644 --- a/ash/shell.cc +++ b/ash/shell.cc @@ -367,7 +367,7 @@ void Shell::Init() { new internal::ActivationController(focus_manager_.get())); screen_position_controller_.reset(new internal::ScreenPositionController); - display_controller_.reset(new internal::DisplayController); + display_controller_.reset(new DisplayController); display_controller_->InitPrimaryDisplay(); aura::RootWindow* root_window = display_controller_->GetPrimaryRootWindow(); active_root_window_ = root_window; diff --git a/ash/shell.h b/ash/shell.h index 8427e27..e0c0cae 100644 --- a/ash/shell.h +++ b/ash/shell.h @@ -61,6 +61,7 @@ namespace ash { class AcceleratorController; class CapsLockDelegate; class DesktopBackgroundController; +class DisplayController; class HighContrastController; class Launcher; class NestedDispatcherController; @@ -80,7 +81,6 @@ class AcceleratorFilter; class ActivationController; class AppListController; class CaptureController; -class DisplayController; class DragDropController; class EventRewriterEventFilter; class FocusCycler; @@ -274,7 +274,7 @@ class ASH_EXPORT Shell : ash::CursorDelegate { internal::FocusCycler* focus_cycler() { return focus_cycler_.get(); } - internal::DisplayController* display_controller() { + DisplayController* display_controller() { return display_controller_.get(); } internal::MouseCursorEventFilter* mouse_cursor_filter() { @@ -436,7 +436,7 @@ class ASH_EXPORT Shell : ash::CursorDelegate { scoped_ptr<VideoDetector> video_detector_; scoped_ptr<WindowCycleController> window_cycle_controller_; scoped_ptr<internal::FocusCycler> focus_cycler_; - scoped_ptr<internal::DisplayController> display_controller_; + scoped_ptr<DisplayController> display_controller_; scoped_ptr<HighContrastController> high_contrast_controller_; scoped_ptr<internal::MagnificationController> magnification_controller_; scoped_ptr<aura::FocusManager> focus_manager_; diff --git a/chrome/browser/chromeos/display/OWNERS b/chrome/browser/chromeos/display/OWNERS new file mode 100644 index 0000000..cbb83f9 --- /dev/null +++ b/chrome/browser/chromeos/display/OWNERS @@ -0,0 +1,2 @@ +oshima@chromium.org +mukai@chromium.org diff --git a/chrome/browser/chromeos/display/display_preferences.cc b/chrome/browser/chromeos/display/display_preferences.cc new file mode 100644 index 0000000..6275f3f --- /dev/null +++ b/chrome/browser/chromeos/display/display_preferences.cc @@ -0,0 +1,123 @@ +// Copyright (c) 2012 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 "chrome/browser/chromeos/display/display_preferences.h" + +#include "ash/display/display_controller.h" +#include "ash/shell.h" +#include "base/string16.h" +#include "base/string_util.h" +#include "base/values.h" +#include "chrome/browser/prefs/pref_service.h" +#include "chrome/browser/prefs/scoped_user_pref_update.h" +#include "chrome/common/pref_names.h" +#include "googleurl/src/url_canon.h" +#include "googleurl/src/url_util.h" +#include "ui/aura/display_manager.h" +#include "ui/aura/env.h" +#include "ui/gfx/display.h" + +namespace chromeos { + +namespace { +// Replaces dot "." by "%2E" since it's the path separater of base::Value. Also +// replaces "%" by "%25" for unescaping. +void EscapeDisplayName(const std::string& name, std::string* escaped) { + DCHECK(escaped); + std::string middle; + ReplaceChars(name, "%", "%25", &middle); + ReplaceChars(middle, ".", "%2E", escaped); +} + +// Unescape %-encoded characters. +std::string UnescapeDisplayName(const std::string& name) { + url_canon::RawCanonOutputT<char16> decoded; + url_util::DecodeURLEscapeSequences(name.data(), name.size(), &decoded); + // Display names are ASCII-only. + return UTF16ToASCII(string16(decoded.data(), decoded.length())); +} + +} // namespace + +void RegisterDisplayPrefs(PrefService* pref_service) { + // The default secondary display layout. + pref_service->RegisterIntegerPref(prefs::kSecondaryDisplayLayout, + static_cast<int>(ash::DisplayLayout::RIGHT), + PrefService::UNSYNCABLE_PREF); + // The default offset of the secondary display position from the primary + // display. + pref_service->RegisterIntegerPref(prefs::kSecondaryDisplayOffset, + 0, + PrefService::UNSYNCABLE_PREF); + // Per-display preference. + pref_service->RegisterDictionaryPref(prefs::kSecondaryDisplays, + PrefService::UNSYNCABLE_PREF); +} + +void SetDisplayLayoutPref(PrefService* pref_service, + const gfx::Display& display, + int layout, + int offset) { + { + DictionaryPrefUpdate update(pref_service, prefs::kSecondaryDisplays); + ash::DisplayLayout display_layout( + static_cast<ash::DisplayLayout::Position>(layout), offset); + + aura::DisplayManager* display_manager = + aura::Env::GetInstance()->display_manager(); + std::string name; + for (size_t i = 0; i < display_manager->GetNumDisplays(); ++i) { + if (display_manager->GetDisplayAt(i)->id() == display.id()) { + EscapeDisplayName(display_manager->GetDisplayNameAt(i), &name); + break; + } + } + + DCHECK(!name.empty()); + + base::DictionaryValue* pref_data = update.Get(); + scoped_ptr<base::Value>layout_value(new base::DictionaryValue()); + if (pref_data->HasKey(name)) { + base::Value* value = NULL; + if (pref_data->Get(name, &value) && value != NULL) + layout_value.reset(value->DeepCopy()); + } + if (ash::DisplayLayout::ConvertToValue(display_layout, layout_value.get())) + pref_data->Set(name, layout_value.release()); + } + + pref_service->SetInteger(prefs::kSecondaryDisplayLayout, layout); + pref_service->SetInteger(prefs::kSecondaryDisplayOffset, offset); + + NotifyDisplayPrefChanged(pref_service); +} + +void NotifyDisplayPrefChanged(PrefService* pref_service) { + ash::DisplayController* display_controller = + ash::Shell::GetInstance()->display_controller(); + + ash::DisplayLayout default_layout( + static_cast<ash::DisplayLayout::Position>(pref_service->GetInteger( + prefs::kSecondaryDisplayLayout)), + pref_service->GetInteger(prefs::kSecondaryDisplayOffset)); + display_controller->SetDefaultDisplayLayout(default_layout); + + const base::DictionaryValue* layouts = pref_service->GetDictionary( + prefs::kSecondaryDisplays); + for (base::DictionaryValue::key_iterator it = layouts->begin_keys(); + it != layouts->end_keys(); ++it) { + const base::Value* value = NULL; + if (!layouts->Get(*it, &value) || value == NULL) + continue; + + ash::DisplayLayout layout; + if (!ash::DisplayLayout::ConvertFromValue(*value, &layout)) + continue; + + display_controller->SetLayoutForDisplayName( + UnescapeDisplayName(*it), layout); + } +} + +} // namespace chromeos diff --git a/chrome/browser/chromeos/display/display_preferences.h b/chrome/browser/chromeos/display/display_preferences.h new file mode 100644 index 0000000..cbc8df0 --- /dev/null +++ b/chrome/browser/chromeos/display/display_preferences.h @@ -0,0 +1,30 @@ +// Copyright (c) 2012 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 CHROME_BROWSER_CHROMEOS_DISPLAY_DISPLAY_PREFERENCES_H_ +#define CHROME_BROWSER_CHROMEOS_DISPLAY_DISPLAY_PREFERENCES_H_ + +class PrefService; +namespace gfx { +class Display; +} + +namespace chromeos { + +// Registers the prefs associated with display settings. +void RegisterDisplayPrefs(PrefService* pref_service); + +// Sets or updates the display layout data to the specified |display| and +// |pref_service|. +void SetDisplayLayoutPref(PrefService* pref_service, + const gfx::Display& display, + int layout, + int offset); + +// Checks the current display settings values and notifies them to the system. +void NotifyDisplayPrefChanged(PrefService* pref_service); + +} // namespace chromeos + +#endif // CHROME_BROWSER_CHROMEOS_DISPLAY_DISPLAY_PREFERENCES_H_ diff --git a/chrome/browser/chromeos/preferences.cc b/chrome/browser/chromeos/preferences.cc index 5f99403..92b09bed 100644 --- a/chrome/browser/chromeos/preferences.cc +++ b/chrome/browser/chromeos/preferences.cc @@ -4,8 +4,6 @@ #include "chrome/browser/chromeos/preferences.h" -#include "ash/display/display_controller.h" -#include "ash/shell.h" #include "base/chromeos/chromeos_version.h" #include "base/command_line.h" #include "base/i18n/time_formatting.h" @@ -15,6 +13,7 @@ #include "base/utf_string_conversions.h" #include "chrome/browser/api/prefs/pref_member.h" #include "chrome/browser/browser_process.h" +#include "chrome/browser/chromeos/display/display_preferences.h" #include "chrome/browser/chromeos/gdata/gdata_util.h" #include "chrome/browser/chromeos/input_method/input_method_manager.h" #include "chrome/browser/chromeos/input_method/input_method_util.h" @@ -49,8 +48,6 @@ bool IsLumpy() { } // namespace -using ash::internal::DisplayController; - static const char kFallbackInputMethodLocale[] = "en-US"; Preferences::Preferences() @@ -248,15 +245,6 @@ void Preferences::RegisterUserPrefs(PrefService* prefs) { false, PrefService::SYNCABLE_PREF); - // Secondary display layout. - prefs->RegisterIntegerPref(prefs::kSecondaryDisplayLayout, - static_cast<int>(DisplayController::RIGHT), - PrefService::UNSYNCABLE_PREF); - // The offset of the secondary display position from the primary display. - prefs->RegisterIntegerPref(prefs::kSecondaryDisplayOffset, - 0, - PrefService::UNSYNCABLE_PREF); - // Mobile plan notifications default to on. prefs->RegisterBooleanPref(prefs::kShowPlanNotifications, true, @@ -290,6 +278,8 @@ void Preferences::RegisterUserPrefs(PrefService* prefs) { prefs->RegisterBooleanPref(prefs::kExternalStorageDisabled, false, PrefService::UNSYNCABLE_PREF); + + RegisterDisplayPrefs(prefs); } void Preferences::InitUserPrefs(PrefService* prefs) { @@ -364,9 +354,6 @@ void Preferences::InitUserPrefs(PrefService* prefs) { enable_screen_lock_.Init(prefs::kEnableScreenLock, prefs, this); - secondary_display_layout_.Init(prefs::kSecondaryDisplayLayout, prefs, this); - secondary_display_offset_.Init(prefs::kSecondaryDisplayOffset, prefs, this); - enable_drm_.Init(prefs::kEnableCrosDRM, prefs, this); } @@ -381,6 +368,8 @@ void Preferences::Init(PrefService* prefs) { if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kGuestSession)) { LoginUtils::Get()->SetFirstLoginPrefs(prefs); } + + NotifyDisplayPrefChanged(prefs); } void Preferences::InitUserPrefsForTesting(PrefService* prefs) { @@ -584,21 +573,6 @@ void Preferences::NotifyPrefChanged(const std::string* pref_name) { enable_screen_lock_.GetValue()); } - if (!pref_name || *pref_name == prefs::kSecondaryDisplayLayout) { - int layout = secondary_display_layout_.GetValue(); - if (static_cast<int>(DisplayController::TOP) <= layout && - layout <= static_cast<int>(DisplayController::LEFT)) { - ash::Shell::GetInstance()->display_controller()-> - SetSecondaryDisplayLayout( - static_cast<DisplayController::SecondaryDisplayLayout>(layout)); - } - } - - if (!pref_name || *pref_name == prefs::kSecondaryDisplayOffset) { - ash::Shell::GetInstance()->display_controller()-> - SetSecondaryDisplayOffset(secondary_display_offset_.GetValue()); - } - // Init or update protected content (DRM) support. if (!pref_name || *pref_name == prefs::kEnableCrosDRM) { system::ToggleDrm(enable_drm_.GetValue()); diff --git a/chrome/browser/chromeos/preferences.h b/chrome/browser/chromeos/preferences.h index 6f047c1..229dfc1 100644 --- a/chrome/browser/chromeos/preferences.h +++ b/chrome/browser/chromeos/preferences.h @@ -144,9 +144,6 @@ class Preferences : public content::NotificationObserver { BooleanPrefMember enable_screen_lock_; - IntegerPrefMember secondary_display_layout_; - IntegerPrefMember secondary_display_offset_; - BooleanPrefMember enable_drm_; DISALLOW_COPY_AND_ASSIGN(Preferences); diff --git a/chrome/browser/ui/webui/options/chromeos/display_options_handler.cc b/chrome/browser/ui/webui/options/chromeos/display_options_handler.cc index 7893d1e..ec2ae22 100644 --- a/chrome/browser/ui/webui/options/chromeos/display_options_handler.cc +++ b/chrome/browser/ui/webui/options/chromeos/display_options_handler.cc @@ -14,7 +14,7 @@ #include "base/logging.h" #include "base/stringprintf.h" #include "base/values.h" -#include "chrome/browser/prefs/pref_service.h" +#include "chrome/browser/chromeos/display/display_preferences.h" #include "chrome/browser/profiles/profile.h" #include "chrome/common/pref_names.h" #include "chromeos/display/output_configurator.h" @@ -29,8 +29,6 @@ namespace chromeos { namespace options { -using ash::internal::DisplayController; - DisplayOptionsHandler::DisplayOptionsHandler() { aura::Env::GetInstance()->display_manager()->AddObserver(this); } @@ -103,6 +101,8 @@ void DisplayOptionsHandler::UpdateDisplaySectionVisibility() { void DisplayOptionsHandler::SendDisplayInfo() { aura::DisplayManager* display_manager = aura::Env::GetInstance()->display_manager(); + ash::DisplayController* display_controller = + ash::Shell::GetInstance()->display_controller(); chromeos::OutputConfigurator* output_configurator = ash::Shell::GetInstance()->output_configurator(); base::FundamentalValue mirroring( @@ -122,15 +122,20 @@ void DisplayOptionsHandler::SendDisplayInfo() { displays.Set(i, js_display); } - PrefService* pref_service = Profile::FromWebUI(web_ui())->GetPrefs(); - base::FundamentalValue layout( - pref_service->GetInteger(prefs::kSecondaryDisplayLayout)); - base::FundamentalValue offset( - pref_service->GetInteger(prefs::kSecondaryDisplayOffset)); + scoped_ptr<base::Value> layout_value(base::Value::CreateNullValue()); + scoped_ptr<base::Value> offset_value(base::Value::CreateNullValue()); + if (display_manager->GetNumDisplays() > 1) { + const std::string& secondary_display_name = + display_manager->GetDisplayNameAt(1); + const ash::DisplayLayout& layout = + display_controller->GetLayoutForDisplayName(secondary_display_name); + layout_value.reset(new base::FundamentalValue(layout.position)); + offset_value.reset(new base::FundamentalValue(layout.offset)); + } web_ui()->CallJavascriptFunction( "options.DisplayOptions.setDisplayInfo", - mirroring, displays, layout, offset); + mirroring, displays, *layout_value.get(), *offset_value.get()); } void DisplayOptionsHandler::FadeOutForMirroringFinished(bool is_mirroring) { @@ -146,8 +151,15 @@ void DisplayOptionsHandler::FadeOutForMirroringFinished(bool is_mirroring) { void DisplayOptionsHandler::FadeOutForDisplayLayoutFinished( int layout, int offset) { PrefService* pref_service = Profile::FromWebUI(web_ui())->GetPrefs(); - pref_service->SetInteger(prefs::kSecondaryDisplayLayout, layout); - pref_service->SetInteger(prefs::kSecondaryDisplayOffset, offset); + aura::DisplayManager* display_manager = + aura::Env::GetInstance()->display_manager(); + // Assumes that there are two displays at most and the second item is the + // secondary display. + if (display_manager->GetNumDisplays() > 1) { + gfx::Display* display = display_manager->GetDisplayAt(1); + SetDisplayLayoutPref(pref_service, *display, layout, offset); + } + SendDisplayInfo(); ash::Shell::GetInstance()->output_configurator_animation()-> StartFadeInAnimation(); @@ -177,8 +189,8 @@ void DisplayOptionsHandler::HandleDisplayLayout(const base::ListValue* args) { SendDisplayInfo(); return; } - DCHECK_LE(DisplayController::TOP, layout); - DCHECK_GE(DisplayController::LEFT, layout); + DCHECK_LE(ash::DisplayLayout::TOP, layout); + DCHECK_GE(ash::DisplayLayout::LEFT, layout); ash::Shell::GetInstance()->output_configurator_animation()-> StartFadeOutAnimation(base::Bind( &DisplayOptionsHandler::FadeOutForDisplayLayoutFinished, diff --git a/chrome/chrome_browser_chromeos.gypi b/chrome/chrome_browser_chromeos.gypi index a80a01e..7ed9dde 100644 --- a/chrome/chrome_browser_chromeos.gypi +++ b/chrome/chrome_browser_chromeos.gypi @@ -191,6 +191,8 @@ 'browser/chromeos/cros/sms_watcher.h', 'browser/chromeos/customization_document.cc', 'browser/chromeos/customization_document.h', + 'browser/chromeos/display/display_preferences.cc', + 'browser/chromeos/display/display_preferences.h', 'browser/chromeos/dbus/cros_dbus_service.cc', 'browser/chromeos/dbus/cros_dbus_service.h', 'browser/chromeos/dbus/proxy_resolution_service_provider.cc', diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc index fe38006..360e5fa 100644 --- a/chrome/common/pref_names.cc +++ b/chrome/common/pref_names.cc @@ -741,6 +741,11 @@ const char kSecondaryDisplayLayout[] = "settings.display.secondary_layout"; // An integer pref that specifies how far the secondary display is positioned // from the edge of the primary display. const char kSecondaryDisplayOffset[] = "settings.display.secondary_offset"; + +// A dictionary pref that specifies per-display layout/offset information. +// Its key is the ID of the display and its value is a dictionary for the +// layout/offset information. +const char kSecondaryDisplays[] = "settings.display.secondary_displays"; #endif // defined(OS_CHROMEOS) // The disabled messages in IPC logging. diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h index bd0fcde..b4cabce 100644 --- a/chrome/common/pref_names.h +++ b/chrome/common/pref_names.h @@ -267,6 +267,7 @@ extern const char kOAuth1Secret[]; extern const char kEnableCrosDRM[]; extern const char kSecondaryDisplayLayout[]; extern const char kSecondaryDisplayOffset[]; +extern const char kSecondaryDisplays[]; #endif // defined(OS_CHROMEOS) extern const char kIpcDisabledMessages[]; extern const char kShowHomeButton[]; |