summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ash/display/display_controller.cc148
-rw-r--r--ash/display/display_controller.h60
-rw-r--r--ash/display/display_controller_unittest.cc20
-rw-r--r--ash/display/mouse_cursor_event_filter.cc22
-rw-r--r--ash/display/mouse_cursor_event_filter.h3
-rw-r--r--ash/display/mouse_cursor_event_filter_unittest.cc42
-rw-r--r--ash/extended_desktop_unittest.cc17
-rw-r--r--ash/shell.cc2
-rw-r--r--ash/shell.h6
-rw-r--r--chrome/browser/chromeos/display/OWNERS2
-rw-r--r--chrome/browser/chromeos/display/display_preferences.cc123
-rw-r--r--chrome/browser/chromeos/display/display_preferences.h30
-rw-r--r--chrome/browser/chromeos/preferences.cc36
-rw-r--r--chrome/browser/chromeos/preferences.h3
-rw-r--r--chrome/browser/ui/webui/options/chromeos/display_options_handler.cc38
-rw-r--r--chrome/chrome_browser_chromeos.gypi2
-rw-r--r--chrome/common/pref_names.cc5
-rw-r--r--chrome/common/pref_names.h1
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[];