[Cleanup]
* Remove aura from DisplayManager
 -Introduced DislayManager::Delegate to decouple DisplayController
 - Moved methods that requires aura to DisplayController
 - Changed to use DisplayInfo to get native bounds instead of 
RootWindow.

* Moved mirror_window_controller_ from Shell to DisplayControlller.
  This should belong to DC rather than Shell.


BUG=253991

Review URL: https://chromiumcodereview.appspot.com/19038002

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@211357 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/ash/display/display_controller.cc b/ash/display/display_controller.cc
index 6056e07a..e42b6ba 100644
--- a/ash/display/display_controller.cc
+++ b/ash/display/display_controller.cc
@@ -11,6 +11,7 @@
 #include "ash/ash_switches.h"
 #include "ash/display/display_layout_store.h"
 #include "ash/display/display_manager.h"
+#include "ash/display/mirror_window_controller.h"
 #include "ash/display/root_window_transformers.h"
 #include "ash/host/root_window_host_factory.h"
 #include "ash/root_window_controller.h"
@@ -18,6 +19,7 @@
 #include "ash/shell.h"
 #include "ash/wm/coordinate_conversion.h"
 #include "ash/wm/property_util.h"
+#include "ash/wm/window_properties.h"
 #include "ash/wm/window_util.h"
 #include "base/command_line.h"
 #include "base/strings/stringprintf.h"
@@ -52,6 +54,8 @@
 #endif  // defined(USE_X11)
 #endif  // defined(OS_CHROMEOS)
 
+DECLARE_WINDOW_PROPERTY_TYPE(int64);
+
 namespace ash {
 namespace {
 
@@ -129,6 +133,9 @@
 
 namespace internal {
 
+DEFINE_WINDOW_PROPERTY_KEY(int64, kDisplayIdKey,
+                           gfx::Display::kInvalidDisplayID);
+
 // A utility class to store/restore focused/active window
 // when the display configuration has changed.
 class FocusActivationStore {
@@ -216,8 +223,8 @@
 
 DisplayController::DisplayController()
     : primary_root_window_for_replace_(NULL),
-      in_bootstrap_(true),
-      focus_activation_store_(new internal::FocusActivationStore()) {
+      focus_activation_store_(new internal::FocusActivationStore()),
+      mirror_window_controller_(new internal::MirrorWindowController) {
   CommandLine* command_line = CommandLine::ForCurrentProcess();
 #if defined(OS_CHROMEOS)
   if (!command_line->HasSwitch(switches::kAshDisableDisplayChangeLimiter) &&
@@ -238,10 +245,16 @@
 
 void DisplayController::Start() {
   Shell::GetScreen()->AddObserver(this);
-  in_bootstrap_ = false;
+  Shell::GetInstance()->display_manager()->set_delegate(this);
 }
 
 void DisplayController::Shutdown() {
+  // Unset the display manager's delegate here because
+  // DisplayManager outlives DisplayController.
+  Shell::GetInstance()->display_manager()->set_delegate(NULL);
+
+  mirror_window_controller_.reset();
+
   DCHECK(!primary_display_for_shutdown);
   primary_display_for_shutdown = new gfx::Display(
       GetDisplayManager()->GetDisplayForId(primary_display_id));
@@ -388,10 +401,10 @@
     to_set.primary_id = primary.id();
     layout_store->RegisterLayoutForDisplayIdPair(
         pair.first, pair.second, to_set);
-    NotifyDisplayConfigurationChanging();
+    PreDisplayConfigurationChange();
     // TODO(oshima): Call UpdateDisplays instead.
     UpdateDisplayBoundsForLayout();
-    NotifyDisplayConfigurationChanged();
+    PostDisplayConfigurationChange();
   }
 }
 
@@ -527,9 +540,9 @@
   GetDisplayManager()->layout_store()->UpdatePrimaryDisplayId(
       GetCurrentDisplayIdPair(), primary_display_id);
 
-  display_manager->UpdateWorkAreaOfDisplayNearestWindow(
+  UpdateWorkAreaOfDisplayNearestWindow(
       primary_root, old_primary_display.GetWorkAreaInsets());
-  display_manager->UpdateWorkAreaOfDisplayNearestWindow(
+  UpdateWorkAreaOfDisplayNearestWindow(
       non_primary_root, new_primary_display.GetWorkAreaInsets());
 
   // Update the dispay manager with new display info.
@@ -596,6 +609,66 @@
   dst_root_window->MoveCursorTo(target_location_in_native);
 }
 
+bool DisplayController::UpdateWorkAreaOfDisplayNearestWindow(
+    const aura::Window* window,
+    const gfx::Insets& insets) {
+  const aura::RootWindow* root = window->GetRootWindow();
+  gfx::Display* display = FindDisplayForRootWindow(root);
+  gfx::Rect old_work_area = display->work_area();
+  display->UpdateWorkAreaFromInsets(insets);
+  return old_work_area != display->work_area();
+}
+
+const gfx::Display& DisplayController::GetDisplayNearestWindow(
+    const aura::Window* window) const {
+  if (!window)
+    return GetPrimaryDisplay();
+  const aura::RootWindow* root_window = window->GetRootWindow();
+  if (!root_window)
+    return GetPrimaryDisplay();
+  int64 id = root_window->GetProperty(internal::kDisplayIdKey);
+  // if id is |kInvaildDisplayID|, it's being deleted.
+  DCHECK(id != gfx::Display::kInvalidDisplayID);
+
+  internal::DisplayManager* display_manager = GetDisplayManager();
+  // RootWindow needs Display to determine its device scale factor.
+  // TODO(oshima): We don't need full display info for mirror
+  // window. Refactor so that RootWindow doesn't use it.
+  if (display_manager->mirrored_display().id() == id)
+    return display_manager->mirrored_display();
+
+  return display_manager->FindDisplayForId(id);
+}
+
+const gfx::Display& DisplayController::GetDisplayNearestPoint(
+    const gfx::Point& point) const {
+  // Fallback to the primary display if there is no root display containing
+  // the |point|.
+  const gfx::Display& display =
+      GetDisplayManager()->FindDisplayContainingPoint(point);
+  return display.is_valid() ? display : GetPrimaryDisplay();
+}
+
+const gfx::Display& DisplayController::GetDisplayMatching(
+    const gfx::Rect& rect) const {
+  if (rect.IsEmpty())
+    return GetDisplayNearestPoint(rect.origin());
+
+  int max_area = 0;
+  const gfx::Display* matching = NULL;
+  for (size_t i = 0; i < GetDisplayManager()->GetNumDisplays(); ++i) {
+    gfx::Display* display = GetDisplayManager()->GetDisplayAt(i);
+    gfx::Rect intersect = gfx::IntersectRects(display->bounds(), rect);
+    int area = intersect.width() * intersect.height();
+    if (area > max_area) {
+      max_area = area;
+      matching = display;
+    }
+  }
+  // Fallback to the primary display if there is no matching display.
+  return matching ? *matching : GetPrimaryDisplay();
+}
+
 void DisplayController::OnDisplayBoundsChanged(const gfx::Display& display) {
   const internal::DisplayInfo& display_info =
       GetDisplayManager()->GetDisplayInfo(display.id());
@@ -669,53 +742,26 @@
   base::MessageLoop::current()->DeleteSoon(FROM_HERE, controller);
 }
 
-aura::RootWindow* DisplayController::AddRootWindowForDisplay(
-    const gfx::Display& display) {
-  static int root_window_count = 0;
-  const internal::DisplayInfo& display_info =
-      GetDisplayManager()->GetDisplayInfo(display.id());
-  const gfx::Rect& bounds_in_pixel = display_info.bounds_in_pixel();
-  aura::RootWindow::CreateParams params(bounds_in_pixel);
-  params.host = Shell::GetInstance()->root_window_host_factory()->
-      CreateRootWindowHost(bounds_in_pixel);
-  aura::RootWindow* root_window = new aura::RootWindow(params);
-  root_window->SetName(
-      base::StringPrintf("RootWindow-%d", root_window_count++));
-  root_window->compositor()->SetBackgroundColor(SK_ColorBLACK);
-  // No need to remove RootWindowObserver because
-  // the DisplayManager object outlives RootWindow objects.
-  root_window->AddRootWindowObserver(GetDisplayManager());
-  root_window->SetProperty(internal::kDisplayIdKey, display.id());
-  root_window->Init();
-
-  root_windows_[display.id()] = root_window;
-  SetDisplayPropertiesOnHostWindow(root_window, display);
-
-#if defined(OS_CHROMEOS)
-  static bool force_constrain_pointer_to_root =
-      CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kAshConstrainPointerToRoot);
-  if (base::chromeos::IsRunningOnChromeOS() || force_constrain_pointer_to_root)
-    root_window->ConfineCursorToWindow();
-#endif
-  return root_window;
-}
-
-void DisplayController::UpdateDisplayBoundsForLayout() {
-  if (Shell::GetScreen()->GetNumDisplays() < 2 ||
-      GetDisplayManager()->num_connected_displays() < 2) {
-    return;
+void DisplayController::OnRootWindowHostResized(const aura::RootWindow* root) {
+  internal::DisplayManager* display_manager = GetDisplayManager();
+  gfx::Display display = GetDisplayNearestWindow(root);
+  if (display_manager->UpdateDisplayBounds(
+          display.id(),
+          gfx::Rect(root->GetHostOrigin(), root->GetHostSize()))) {
+    mirror_window_controller_->UpdateWindow();
   }
-  DCHECK_EQ(2, Shell::GetScreen()->GetNumDisplays());
-
-  const DisplayLayout layout = GetCurrentDisplayLayout();
-  Shell::GetInstance()->display_manager()->UpdateDisplayBoundsForLayout(
-      layout, GetPrimaryDisplay(), GetSecondaryDisplay());
 }
 
-void DisplayController::NotifyDisplayConfigurationChanging() {
-  if (in_bootstrap())
-    return;
+void DisplayController::CreateOrUpdateMirrorWindow(
+    const internal::DisplayInfo& info) {
+  mirror_window_controller_->UpdateWindow(info);
+}
+
+void DisplayController::CloseMirrorWindow() {
+  mirror_window_controller_->Close();
+}
+
+void DisplayController::PreDisplayConfigurationChange() {
   FOR_EACH_OBSERVER(Observer, observers_, OnDisplayConfigurationChanging());
   focus_activation_store_->Store();
 
@@ -731,10 +777,7 @@
   cursor_location_in_native_coords_for_restore_ = point_in_screen;
 }
 
-void DisplayController::NotifyDisplayConfigurationChanged() {
-  if (in_bootstrap())
-    return;
-
+void DisplayController::PostDisplayConfigurationChange() {
   if (limiter_)
     limiter_->SetThrottleTimeout(kAfterDisplayChangeThrottleTimeoutMs);
 
@@ -764,6 +807,60 @@
   EnsurePointerInDisplays();
 }
 
+gfx::Display* DisplayController::FindDisplayForRootWindow(
+    const aura::RootWindow* root_window) {
+  int64 id = root_window->GetProperty(internal::kDisplayIdKey);
+  // if id is |kInvaildDisplayID|, it's being deleted.
+  DCHECK(id != gfx::Display::kInvalidDisplayID);
+  gfx::Display& display = GetDisplayManager()->FindDisplayForId(id);
+  DCHECK(display.is_valid());
+  return display.is_valid() ? &display : NULL;
+}
+
+aura::RootWindow* DisplayController::AddRootWindowForDisplay(
+    const gfx::Display& display) {
+  static int root_window_count = 0;
+  const internal::DisplayInfo& display_info =
+      GetDisplayManager()->GetDisplayInfo(display.id());
+  const gfx::Rect& bounds_in_pixel = display_info.bounds_in_pixel();
+  aura::RootWindow::CreateParams params(bounds_in_pixel);
+  params.host = Shell::GetInstance()->root_window_host_factory()->
+      CreateRootWindowHost(bounds_in_pixel);
+  aura::RootWindow* root_window = new aura::RootWindow(params);
+  root_window->SetName(
+      base::StringPrintf("RootWindow-%d", root_window_count++));
+  root_window->compositor()->SetBackgroundColor(SK_ColorBLACK);
+  // No need to remove RootWindowObserver because
+  // the DisplayController object outlives RootWindow objects.
+  root_window->AddRootWindowObserver(this);
+  root_window->SetProperty(internal::kDisplayIdKey, display.id());
+  root_window->Init();
+
+  root_windows_[display.id()] = root_window;
+  SetDisplayPropertiesOnHostWindow(root_window, display);
+
+#if defined(OS_CHROMEOS)
+  static bool force_constrain_pointer_to_root =
+      CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kAshConstrainPointerToRoot);
+  if (base::chromeos::IsRunningOnChromeOS() || force_constrain_pointer_to_root)
+    root_window->ConfineCursorToWindow();
+#endif
+  return root_window;
+}
+
+void DisplayController::UpdateDisplayBoundsForLayout() {
+  if (Shell::GetScreen()->GetNumDisplays() < 2 ||
+      GetDisplayManager()->num_connected_displays() < 2) {
+    return;
+  }
+  DCHECK_EQ(2, Shell::GetScreen()->GetNumDisplays());
+
+  const DisplayLayout layout = GetCurrentDisplayLayout();
+  Shell::GetInstance()->display_manager()->UpdateDisplayBoundsForLayout(
+      layout, GetPrimaryDisplay(), GetSecondaryDisplay());
+}
+
 void DisplayController::OnFadeOutForSwapDisplayFinished() {
 #if defined(OS_CHROMEOS) && defined(USE_X11)
   SetPrimaryDisplay(ScreenAsh::GetSecondaryDisplay());
diff --git a/ash/display/display_controller.h b/ash/display/display_controller.h
index a0b1477..f313ba8 100644
--- a/ash/display/display_controller.h
+++ b/ash/display/display_controller.h
@@ -10,12 +10,13 @@
 
 #include "ash/ash_export.h"
 #include "ash/display/display_layout.h"
+#include "ash/display/display_manager.h"
 #include "base/basictypes.h"
 #include "base/compiler_specific.h"
-#include "base/gtest_prod_util.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/observer_list.h"
 #include "base/time/time.h"
+#include "ui/aura/root_window_observer.h"
 #include "ui/gfx/display_observer.h"
 #include "ui/gfx/point.h"
 
@@ -36,6 +37,7 @@
 
 namespace ash {
 namespace internal {
+class DisplayInfo;
 class DisplayManager;
 class FocusActivationStore;
 class MirrorWindowController;
@@ -44,8 +46,9 @@
 
 // DisplayController owns and maintains RootWindows for each attached
 // display, keeping them in sync with display configuration changes.
-// TODO(oshima): Factor out the layout registration class.
-class ASH_EXPORT DisplayController : public gfx::DisplayObserver {
+class ASH_EXPORT DisplayController : public gfx::DisplayObserver,
+                                     public aura::RootWindowObserver,
+                                     public internal::DisplayManager::Delegate {
  public:
   class ASH_EXPORT Observer {
    public:
@@ -75,6 +78,10 @@
   // ash::Shell is deleted.
   static int GetNumDisplays();
 
+  internal::MirrorWindowController* mirror_window_controller() {
+    return mirror_window_controller_.get();
+  }
+
   // Initializes primary display.
   void InitPrimaryDisplay();
 
@@ -138,25 +145,53 @@
   // the center of the nearest display if it's outside of all displays.
   void EnsurePointerInDisplays();
 
+  // Sets the work area's |insets| to the display assigned to |window|.
+  bool UpdateWorkAreaOfDisplayNearestWindow(const aura::Window* window,
+                                            const gfx::Insets& insets);
+
+  // Returns the display object nearest given |point|.
+  const gfx::Display& GetDisplayNearestPoint(
+      const gfx::Point& point) const;
+
+  // Returns the display object nearest given |window|.
+  const gfx::Display& GetDisplayNearestWindow(
+      const aura::Window* window) const;
+
+  // Returns the display that most closely intersects |match_rect|.
+  const gfx::Display& GetDisplayMatching(
+      const gfx::Rect& match_rect)const;
+
   // aura::DisplayObserver overrides:
   virtual void OnDisplayBoundsChanged(
       const gfx::Display& display) OVERRIDE;
   virtual void OnDisplayAdded(const gfx::Display& display) OVERRIDE;
   virtual void OnDisplayRemoved(const gfx::Display& display) OVERRIDE;
 
+  // RootWindowObserver overrides:
+  virtual void OnRootWindowHostResized(const aura::RootWindow* root) OVERRIDE;
+
+  // aura::DisplayManager::Delegate overrides:
+  virtual void CreateOrUpdateMirrorWindow(
+      const internal::DisplayInfo& info) OVERRIDE;
+  virtual void CloseMirrorWindow() OVERRIDE;
+  virtual void PreDisplayConfigurationChange() OVERRIDE;
+  virtual void PostDisplayConfigurationChange() OVERRIDE;
+
  private:
   friend class internal::DisplayManager;
   friend class internal::MirrorWindowController;
 
+  // Returns a display the |root| is assigned to for modification.
+  // Returns NULL if the no display is assigned, or the root window is
+  // for mirroring.
+  gfx::Display* FindDisplayForRootWindow(const aura::RootWindow* root);
+
   // Creates a root window for |display| and stores it in the |root_windows_|
   // map.
   aura::RootWindow* AddRootWindowForDisplay(const gfx::Display& display);
 
   void UpdateDisplayBoundsForLayout();
 
-  void NotifyDisplayConfigurationChanging();
-  void NotifyDisplayConfigurationChanged();
-
   void SetLayoutForDisplayIdPair(const DisplayIdPair& display_pair,
                                  const DisplayLayout& layout);
 
@@ -164,8 +199,6 @@
 
   void UpdateHostWindowNames();
 
-  bool in_bootstrap() const { return in_bootstrap_; }
-
   class DisplayChangeLimiter {
    public:
     DisplayChangeLimiter();
@@ -195,10 +228,11 @@
   // display.
   aura::RootWindow* primary_root_window_for_replace_;
 
-  bool in_bootstrap_;
-
   scoped_ptr<internal::FocusActivationStore> focus_activation_store_;
 
+
+  scoped_ptr<internal::MirrorWindowController> mirror_window_controller_;
+
   // Stores the curent cursor location (in native coordinates) used to
   // restore the cursor location when display configuration
   // changed.
diff --git a/ash/display/display_manager.cc b/ash/display/display_manager.cc
index d773147e..b4d9580 100644
--- a/ash/display/display_manager.cc
+++ b/ash/display/display_manager.cc
@@ -10,9 +10,7 @@
 #include <vector>
 
 #include "ash/ash_switches.h"
-#include "ash/display/display_controller.h"
 #include "ash/display/display_layout_store.h"
-#include "ash/display/mirror_window_controller.h"
 #include "ash/screen_ash.h"
 #include "ash/shell.h"
 #include "base/auto_reset.h"
@@ -23,9 +21,6 @@
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "grit/ash_strings.h"
-#include "ui/aura/client/screen_position_client.h"
-#include "ui/aura/root_window.h"
-#include "ui/aura/window_property.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/gfx/display.h"
 #include "ui/gfx/rect.h"
@@ -46,8 +41,6 @@
 #include "base/win/windows_version.h"
 #endif
 
-DECLARE_WINDOW_PROPERTY_TYPE(int64);
-
 namespace ash {
 namespace internal {
 typedef std::vector<gfx::Display> DisplayList;
@@ -98,43 +91,47 @@
 // at specific timing.
 class MirrorWindowCreator {
  public:
-  explicit MirrorWindowCreator(const DisplayInfo& display_info)
-      : display_info_(display_info) {
+  MirrorWindowCreator(DisplayManager::Delegate* delegate,
+                      const DisplayInfo& display_info)
+      : delegate_(delegate),
+        display_info_(display_info) {
   }
 
   virtual ~MirrorWindowCreator() {
-    Shell::GetInstance()->mirror_window_controller()->
-        UpdateWindow(display_info_);
+    if (delegate_)
+      delegate_->CreateOrUpdateMirrorWindow(display_info_);
   }
 
  private:
+  DisplayManager::Delegate* delegate_;
   const DisplayInfo display_info_;
   DISALLOW_COPY_AND_ASSIGN(MirrorWindowCreator);
 };
 
 class MirrorWindowCloser {
  public:
-  MirrorWindowCloser() {}
+  explicit MirrorWindowCloser(DisplayManager::Delegate* delegate)
+      : delegate_(delegate)  {}
+
   virtual ~MirrorWindowCloser() {
-    Shell::GetInstance()->mirror_window_controller()->Close();
+    if (delegate_)
+      delegate_->CloseMirrorWindow();
   }
 
  private:
+  DisplayManager::Delegate* delegate_;
+
   DISALLOW_COPY_AND_ASSIGN(MirrorWindowCloser);
 };
 
 }  // namespace
 
-using aura::RootWindow;
-using aura::Window;
 using std::string;
 using std::vector;
 
-DEFINE_WINDOW_PROPERTY_KEY(int64, kDisplayIdKey,
-                           gfx::Display::kInvalidDisplayID);
-
 DisplayManager::DisplayManager()
-    : layout_store_(new DisplayLayoutStore),
+    : delegate_(NULL),
+      layout_store_(new DisplayLayoutStore),
       first_display_id_(gfx::Display::kInvalidDisplayID),
       num_connected_displays_(0),
       force_bounds_changed_(false),
@@ -277,16 +274,6 @@
   return gfx::Display::InternalDisplayId() == id;
 }
 
-bool DisplayManager::UpdateWorkAreaOfDisplayNearestWindow(
-    const aura::Window* window,
-    const gfx::Insets& insets) {
-  const RootWindow* root = window->GetRootWindow();
-  gfx::Display& display = FindDisplayForRootWindow(root);
-  gfx::Rect old_work_area = display.work_area();
-  display.UpdateWorkAreaFromInsets(insets);
-  return old_work_area != display.work_area();
-}
-
 const gfx::Display& DisplayManager::GetDisplayForId(int64 id) const {
   return const_cast<DisplayManager*>(this)->FindDisplayForId(id);
 }
@@ -512,8 +499,8 @@
       InsertAndUpdateDisplayInfo(info);
 
       mirrored_display_ = CreateDisplayFromDisplayInfoById(new_info_iter->id());
-      mirror_window_creater.reset(
-          new MirrorWindowCreator(display_info_[new_info_iter->id()]));
+      mirror_window_creater.reset(new MirrorWindowCreator(
+          delegate_, display_info_[new_info_iter->id()]));
       ++new_info_iter;
       // Remove existing external dispaly if it is going to be mirrored.
       if (curr_iter != displays_.end() &&
@@ -581,7 +568,7 @@
   scoped_ptr<MirrorWindowCloser> mirror_window_closer;
   // Try to close mirror window unless mirror window is necessary.
   if (!mirror_window_creater.get())
-    mirror_window_closer.reset(new MirrorWindowCloser);
+    mirror_window_closer.reset(new MirrorWindowCloser(delegate_));
 
   // Do not update |displays_| if there's nothing to be updated. Without this,
   // it will not update the display layout, which causes the bug
@@ -590,10 +577,8 @@
       removed_displays.empty()) {
     return;
   }
-
-  DisplayController* display_controller =
-      Shell::GetInstance()->display_controller();
-  display_controller->NotifyDisplayConfigurationChanging();
+  if (delegate_)
+    delegate_->PreDisplayConfigurationChange();
 
   size_t updated_index;
   if (UpdateSecondaryDisplayBoundsForLayout(&new_displays, &updated_index) &&
@@ -635,7 +620,8 @@
        iter != changed_display_indices.end(); ++iter) {
     Shell::GetInstance()->screen()->NotifyBoundsChanged(displays_[*iter]);
   }
-  display_controller->NotifyDisplayConfigurationChanged();
+  if (delegate_)
+    delegate_->PostDisplayConfigurationChange();
 
 #if defined(USE_X11) && defined(OS_CHROMEOS)
   if (!changed_display_indices.empty() && base::chromeos::IsRunningOnChromeOS())
@@ -679,46 +665,6 @@
   return mirrored_display_.id() != gfx::Display::kInvalidDisplayID;
 }
 
-const gfx::Display& DisplayManager::GetDisplayNearestWindow(
-    const Window* window) const {
-  if (!window)
-    return DisplayController::GetPrimaryDisplay();
-  const RootWindow* root = window->GetRootWindow();
-  DisplayManager* manager = const_cast<DisplayManager*>(this);
-  return root ?
-      manager->FindDisplayForRootWindow(root) :
-      DisplayController::GetPrimaryDisplay();
-}
-
-const gfx::Display& DisplayManager::GetDisplayNearestPoint(
-    const gfx::Point& point) const {
-  // Fallback to the primary display if there is no root display containing
-  // the |point|.
-  const gfx::Display& display = FindDisplayContainingPoint(point);
-  return display.is_valid() ? display : DisplayController::GetPrimaryDisplay();
-}
-
-const gfx::Display& DisplayManager::GetDisplayMatching(
-    const gfx::Rect& rect) const {
-  if (rect.IsEmpty())
-    return GetDisplayNearestPoint(rect.origin());
-
-  int max = 0;
-  const gfx::Display* matching = 0;
-  for (std::vector<gfx::Display>::const_iterator iter = displays_.begin();
-       iter != displays_.end(); ++iter) {
-    const gfx::Display& display = *iter;
-    gfx::Rect intersect = gfx::IntersectRects(display.bounds(), rect);
-    int area = intersect.width() * intersect.height();
-    if (area > max) {
-      max = area;
-      matching = &(*iter);
-    }
-  }
-  // Fallback to the primary display if there is no matching display.
-  return matching ? *matching : DisplayController::GetPrimaryDisplay();
-}
-
 const DisplayInfo& DisplayManager::GetDisplayInfo(int64 display_id) const {
   std::map<int64, DisplayInfo>::const_iterator iter =
       display_info_.find(display_id);
@@ -778,14 +724,12 @@
 void DisplayManager::AddRemoveDisplay() {
   DCHECK(!displays_.empty());
   std::vector<DisplayInfo> new_display_info_list;
-  new_display_info_list.push_back(
-      GetDisplayInfo(DisplayController::GetPrimaryDisplay().id()));
+  DisplayInfo first_display = GetDisplayInfo(displays_[0].id());
+  new_display_info_list.push_back(first_display);
   // Add if there is only one display connected.
   if (num_connected_displays() == 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());
+    gfx::Rect host_bounds = first_display.bounds_in_pixel();
     new_display_info_list.push_back(DisplayInfo::CreateFromSpec(
         base::StringPrintf(
             "%d+%d-500x400", host_bounds.x(), host_bounds.bottom())));
@@ -809,42 +753,11 @@
   UpdateDisplays(new_display_info_list);
 }
 
-void DisplayManager::OnRootWindowHostResized(const aura::RootWindow* root) {
-  if (change_display_upon_host_resize_) {
-    gfx::Display& display = FindDisplayForRootWindow(root);
-    gfx::Size old_display_size_in_pixel = display.GetSizeInPixel();
-    display_info_[display.id()].SetBounds(
-        gfx::Rect(root->GetHostOrigin(), root->GetHostSize()));
-    // It's tricky to support resizing mirror window on desktop.
-    if (software_mirroring_enabled_ && mirrored_display_.id() == display.id())
-      return;
-    display.SetSize(display_info_[display.id()].size_in_pixel());
-    Shell::GetInstance()->screen()->NotifyBoundsChanged(display);
-    Shell::GetInstance()->mirror_window_controller()->UpdateWindow();
-  }
-}
-
 void DisplayManager::SetSoftwareMirroring(bool enabled) {
   software_mirroring_enabled_ = enabled;
   mirrored_display_ = gfx::Display();
 }
 
-gfx::Display& DisplayManager::FindDisplayForRootWindow(
-    const aura::RootWindow* root_window) {
-  int64 id = root_window->GetProperty(kDisplayIdKey);
-  // RootWindow needs Display to determine it's device scale factor.
-  // TODO(oshima): We don't need full display info for mirror
-  // window. Refactor so that RootWindow doesn't use it.
-  if (mirrored_display_.id() == id)
-    return mirrored_display_;
-
-  // if id is |kInvaildDisplayID|, it's being deleted.
-  DCHECK(id != gfx::Display::kInvalidDisplayID);
-  gfx::Display& display = FindDisplayForId(id);
-  DCHECK(display.is_valid());
-  return display;
-}
-
 gfx::Display& DisplayManager::FindDisplayForId(int64 id) {
   for (DisplayList::iterator iter = displays_.begin();
        iter != displays_.end(); ++iter) {
@@ -855,6 +768,21 @@
   return GetInvalidDisplay();
 }
 
+bool DisplayManager::UpdateDisplayBounds(int64 display_id,
+                                         const gfx::Rect& new_bounds) {
+  if (change_display_upon_host_resize_) {
+    display_info_[display_id].SetBounds(new_bounds);
+    // Don't notify observers if the mirrored window has changed.
+    if (software_mirroring_enabled_ && mirrored_display_.id() == display_id)
+      return false;
+    gfx::Display& display = FindDisplayForId(display_id);
+    display.SetSize(display_info_[display_id].size_in_pixel());
+    Shell::GetInstance()->screen()->NotifyBoundsChanged(display);
+    return true;
+  }
+  return false;
+}
+
 void DisplayManager::AddMirrorDisplayInfoIfAny(
     std::vector<DisplayInfo>* display_info_list) {
   if (software_mirroring_enabled_ && mirrored_display_.is_valid())
diff --git a/ash/display/display_manager.h b/ash/display/display_manager.h
index 2d99e04..fb4288e 100644
--- a/ash/display/display_manager.h
+++ b/ash/display/display_manager.h
@@ -13,8 +13,7 @@
 #include "ash/display/display_layout.h"
 #include "base/compiler_specific.h"
 #include "base/gtest_prod_util.h"
-#include "ui/aura/root_window_observer.h"
-#include "ui/aura/window.h"
+#include "base/memory/scoped_ptr.h"
 #include "ui/gfx/display.h"
 
 #if defined(OS_CHROMEOS)
@@ -29,6 +28,8 @@
 
 namespace ash {
 class AcceleratorControllerTest;
+class DisplayController;
+
 namespace test {
 class DisplayManagerTestApi;
 class SystemGestureEventFilterTest;
@@ -38,17 +39,29 @@
 
 // DisplayManager maintains the current display configurations,
 // and notifies observers when configuration changes.
-// This is exported for unittest.
 //
 // TODO(oshima): Make this non internal.
-class ASH_EXPORT DisplayManager :
+class ASH_EXPORT DisplayManager
 #if defined(OS_CHROMEOS)
-      public chromeos::OutputConfigurator::SoftwareMirroringController,
+    : public chromeos::OutputConfigurator::SoftwareMirroringController
 #endif
-      public aura::RootWindowObserver {
+      {
  public:
-  DisplayManager();
-  virtual ~DisplayManager();
+  class ASH_EXPORT Delegate {
+   public:
+    virtual ~Delegate() {}
+
+    // Create or updates the mirror window with |display_info|.
+    virtual void CreateOrUpdateMirrorWindow(
+        const DisplayInfo& display_info) = 0;
+
+    // Closes the mirror window if exists.
+    virtual void CloseMirrorWindow() = 0;
+
+    // Called before and after the display configuration changes.
+    virtual void PreDisplayConfigurationChange() = 0;
+    virtual void PostDisplayConfigurationChange() = 0;
+  };
 
   // Returns the list of possible UI scales for the display.
   static std::vector<float> GetScalesForDisplay(const DisplayInfo& info);
@@ -62,10 +75,15 @@
       const gfx::Display& primary_display,
       gfx::Display* secondary_display);
 
+  DisplayManager();
+  virtual ~DisplayManager();
+
   DisplayLayoutStore* layout_store() {
     return layout_store_.get();
   }
 
+  void set_delegate(Delegate* delegate) { delegate_ = delegate; }
+
   // When set to true, the MonitorManager calls OnDisplayBoundsChanged
   // even if the display's bounds didn't change. Used to swap primary
   // display.
@@ -88,9 +106,6 @@
 
   bool IsInternalDisplayId(int64 id) const;
 
-  bool UpdateWorkAreaOfDisplayNearestWindow(const aura::Window* window,
-                                            const gfx::Insets& insets);
-
   // Returns display for given |id|;
   const gfx::Display& GetDisplayForId(int64 id) const;
 
@@ -158,18 +173,6 @@
   bool IsMirrored() const;
   const gfx::Display& mirrored_display() const { return mirrored_display_; }
 
-  // Returns the display object nearest given |window|.
-  const gfx::Display& GetDisplayNearestPoint(
-      const gfx::Point& point) const;
-
-  // Returns the display object nearest given |point|.
-  const gfx::Display& GetDisplayNearestWindow(
-      const aura::Window* window) const;
-
-  // Returns the display that most closely intersects |match_rect|.
-  const gfx::Display& GetDisplayMatching(
-      const gfx::Rect& match_rect)const;
-
   // Retuns the display info associated with |display_id|.
   const DisplayInfo& GetDisplayInfo(int64 display_id) const;
 
@@ -190,9 +193,6 @@
   void AddRemoveDisplay();
   void ToggleDisplayScaleFactor();
 
-  // RootWindowObserver overrides:
-  virtual void OnRootWindowHostResized(const aura::RootWindow* root) OVERRIDE;
-
   // SoftwareMirroringController override:
 #if defined(OS_CHROMEOS)
   virtual void SetSoftwareMirroring(bool enabled) OVERRIDE;
@@ -208,8 +208,12 @@
   FRIEND_TEST_ALL_PREFIXES(DisplayManagerTest, AutomaticOverscanInsets);
   friend class ash::AcceleratorControllerTest;
   friend class test::DisplayManagerTestApi;
-  friend class DisplayManagerTest;
   friend class test::SystemGestureEventFilterTest;
+  friend class DisplayManagerTest;
+  // This is to allow DisplayController to modify the state of
+  // DisplayManager.  TODO(oshima): consider provide separate
+  // interface to modify the state.
+  friend class ash::DisplayController;
 
   typedef std::vector<gfx::Display> DisplayList;
 
@@ -217,9 +221,11 @@
     change_display_upon_host_resize_ = value;
   }
 
-  gfx::Display& FindDisplayForRootWindow(const aura::RootWindow* root);
   gfx::Display& FindDisplayForId(int64 id);
 
+  // Updates the bounds of the display given by |display_id|.
+  bool UpdateDisplayBounds(int64 display_id, const gfx::Rect& new_bounds);
+
   // Add the mirror display's display info if the software based
   // mirroring is in use.
   void AddMirrorDisplayInfoIfAny(std::vector<DisplayInfo>* display_info_list);
@@ -242,6 +248,9 @@
   bool UpdateSecondaryDisplayBoundsForLayout(DisplayList* display_list,
                                              size_t* updated_index) const;
 
+
+  Delegate* delegate_;  // not owned.
+
   scoped_ptr<DisplayLayoutStore> layout_store_;
 
   int64 first_display_id_;
@@ -270,8 +279,6 @@
   DISALLOW_COPY_AND_ASSIGN(DisplayManager);
 };
 
-extern const aura::WindowProperty<int64>* const kDisplayIdKey;
-
 }  // namespace internal
 }  // namespace ash
 
diff --git a/ash/display/display_manager_unittest.cc b/ash/display/display_manager_unittest.cc
index de22618..e3e460d 100644
--- a/ash/display/display_manager_unittest.cc
+++ b/ash/display/display_manager_unittest.cc
@@ -97,9 +97,7 @@
   }
 
   const gfx::Display GetMirroredDisplay() {
-    test::MirrorWindowTestApi test_api;
-    return Shell::GetInstance()->display_manager()->
-        FindDisplayForRootWindow(test_api.GetRootWindow());
+    return Shell::GetInstance()->display_manager()->mirrored_display();
   }
 
   // aura::DisplayObserver overrides:
diff --git a/ash/display/mirror_window_controller.cc b/ash/display/mirror_window_controller.cc
index a2b9d09..508eb9a 100644
--- a/ash/display/mirror_window_controller.cc
+++ b/ash/display/mirror_window_controller.cc
@@ -17,6 +17,7 @@
 #include "ash/display/root_window_transformers.h"
 #include "ash/host/root_window_host_factory.h"
 #include "ash/shell.h"
+#include "ash/wm/window_properties.h"
 #include "base/strings/stringprintf.h"
 #include "ui/aura/client/capture_client.h"
 #include "ui/aura/env.h"
@@ -156,11 +157,7 @@
 }
 
 void MirrorWindowController::UpdateWindow(const DisplayInfo& display_info) {
-  if (Shell::GetInstance()->display_controller()->in_bootstrap())
-    return;
-
   static int mirror_root_window_count = 0;
-  DisplayManager* display_manager = Shell::GetInstance()->display_manager();
 
   if (!root_window_.get()) {
     const gfx::Rect& bounds_in_pixel = display_info.bounds_in_pixel();
@@ -172,8 +169,9 @@
         base::StringPrintf("MirrorRootWindow-%d", mirror_root_window_count++));
     root_window_->compositor()->SetBackgroundColor(SK_ColorBLACK);
     // No need to remove RootWindowObserver because
-    // the DisplayManager object outlives RootWindow objects.
-    root_window_->AddRootWindowObserver(display_manager);
+    // the DisplayController object outlives RootWindow objects.
+    root_window_->AddRootWindowObserver(
+        Shell::GetInstance()->display_controller());
     root_window_->AddRootWindowObserver(this);
     // TODO(oshima): TouchHUD is using idkey.
     root_window_->SetProperty(internal::kDisplayIdKey, display_info.id());
@@ -205,6 +203,7 @@
     root_window_->SetHostBounds(display_info.bounds_in_pixel());
   }
 
+  DisplayManager* display_manager = Shell::GetInstance()->display_manager();
   const DisplayInfo& source_display_info = display_manager->GetDisplayInfo(
       Shell::GetScreen()->GetPrimaryDisplay().id());
   DCHECK(display_manager->mirrored_display().is_valid());
@@ -235,7 +234,7 @@
     delete capture_client;
 
     root_window_->RemoveRootWindowObserver(
-        Shell::GetInstance()->display_manager());
+        Shell::GetInstance()->display_controller());
     root_window_->RemoveRootWindowObserver(this);
     root_window_.reset();
     cursor_window_ = NULL;
diff --git a/ash/display/mouse_cursor_event_filter.cc b/ash/display/mouse_cursor_event_filter.cc
index 3509f7f..419ea78 100644
--- a/ash/display/mouse_cursor_event_filter.cc
+++ b/ash/display/mouse_cursor_event_filter.cc
@@ -79,7 +79,8 @@
       event->type() != ui::ET_MOUSE_DRAGGED) {
       return;
   }
-  Shell::GetInstance()->mirror_window_controller()->UpdateCursorLocation();
+  Shell::GetInstance()->display_controller()->
+      mirror_window_controller()->UpdateCursorLocation();
 
   gfx::Point point_in_screen(event->location());
   aura::Window* target = static_cast<aura::Window*>(event->target());
diff --git a/ash/extended_desktop_unittest.cc b/ash/extended_desktop_unittest.cc
index 4115523..36161e04 100644
--- a/ash/extended_desktop_unittest.cc
+++ b/ash/extended_desktop_unittest.cc
@@ -43,6 +43,10 @@
   display_controller->SetLayoutForCurrentDisplays(layout);
 }
 
+internal::DisplayManager* GetDisplayManager() {
+  return Shell::GetInstance()->display_manager();
+}
+
 class ModalWidgetDelegate : public views::WidgetDelegateView {
  public:
   ModalWidgetDelegate() {}
@@ -60,10 +64,6 @@
   DISALLOW_COPY_AND_ASSIGN(ModalWidgetDelegate);
 };
 
-internal::DisplayManager* GetDisplayManager() {
-  return Shell::GetInstance()->display_manager();
-}
-
 // An event handler which moves the target window to the secondary root window
 // at pre-handle phase of a mouse release event.
 class MoveWindowByClickEventHandler : public ui::EventHandler {
@@ -608,20 +608,17 @@
             w1_t1->GetWindowBoundsInScreen().ToString());
 }
 
-namespace internal {
 // Test if the Window::ConvertPointToTarget works across root windows.
 // TODO(oshima): Move multiple display suport and this test to aura.
 TEST_F(ExtendedDesktopTest, ConvertPoint) {
   if (!SupportsMultipleDisplays())
     return;
-
+  gfx::Screen* screen = Shell::GetInstance()->screen();
   UpdateDisplay("1000x600,600x400");
   Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
-  gfx::Display& display_1 =
-      GetDisplayManager()->FindDisplayForRootWindow(root_windows[0]);
+  gfx::Display display_1 = screen->GetDisplayNearestWindow(root_windows[0]);
   EXPECT_EQ("0,0", display_1.bounds().origin().ToString());
-  gfx::Display& display_2 =
-      GetDisplayManager()->FindDisplayForRootWindow(root_windows[1]);
+  gfx::Display display_2 = screen->GetDisplayNearestWindow(root_windows[1]);
   EXPECT_EQ("1000,0", display_2.bounds().origin().ToString());
 
   aura::Window* d1 =
@@ -650,7 +647,7 @@
   // Move the 2nd display to the bottom and test again.
   SetSecondaryDisplayLayout(DisplayLayout::BOTTOM);
 
-  display_2 = GetDisplayManager()->FindDisplayForRootWindow(root_windows[1]);
+  display_2 = screen->GetDisplayNearestWindow(root_windows[1]);
   EXPECT_EQ("0,600", display_2.bounds().origin().ToString());
 
   // Convert point in Root2's window to Root1's window Coord.
@@ -730,7 +727,7 @@
   // not move to another root window regardles of the bounds specified.
   aura::Window* settings_bubble_container =
       Shell::GetPrimaryRootWindowController()->GetContainer(
-          kShellWindowId_SettingBubbleContainer);
+          internal::kShellWindowId_SettingBubbleContainer);
   aura::Window* window = aura::test::CreateTestWindowWithId(
       100, settings_bubble_container);
   window->SetBoundsInScreen(gfx::Rect(150, 10, 50, 50),
@@ -739,7 +736,7 @@
 
   aura::Window* status_container =
       Shell::GetPrimaryRootWindowController()->GetContainer(
-          kShellWindowId_StatusContainer);
+          internal::kShellWindowId_StatusContainer);
   window = aura::test::CreateTestWindowWithId(100, status_container);
   window->SetBoundsInScreen(gfx::Rect(150, 10, 50, 50),
                             ScreenAsh::GetSecondaryDisplay());
@@ -850,5 +847,4 @@
   ash::Shell::GetInstance()->RemovePreTargetHandler(&event_handler);
 }
 
-}  // namespace internal
 }  // namespace ash
diff --git a/ash/screen_ash.cc b/ash/screen_ash.cc
index 6155d54b..d47278d 100644
--- a/ash/screen_ash.cc
+++ b/ash/screen_ash.cc
@@ -25,6 +25,10 @@
 internal::DisplayManager* GetDisplayManager() {
   return Shell::GetInstance()->display_manager();
 }
+
+DisplayController* GetDisplayController() {
+  return Shell::GetInstance()->display_controller();
+}
 }  // namespace
 
 ScreenAsh::ScreenAsh() {
@@ -120,15 +124,15 @@
 }
 
 gfx::Display ScreenAsh::GetDisplayNearestWindow(gfx::NativeView window) const {
-  return GetDisplayManager()->GetDisplayNearestWindow(window);
+  return GetDisplayController()->GetDisplayNearestWindow(window);
 }
 
 gfx::Display ScreenAsh::GetDisplayNearestPoint(const gfx::Point& point) const {
-  return GetDisplayManager()->GetDisplayNearestPoint(point);
+  return GetDisplayController()->GetDisplayNearestPoint(point);
 }
 
 gfx::Display ScreenAsh::GetDisplayMatching(const gfx::Rect& match_rect) const {
-  return GetDisplayManager()->GetDisplayMatching(match_rect);
+  return GetDisplayController()->GetDisplayMatching(match_rect);
 }
 
 gfx::Display ScreenAsh::GetPrimaryDisplay() const {
diff --git a/ash/screen_ash.h b/ash/screen_ash.h
index 7e1d108..649c3d9f 100644
--- a/ash/screen_ash.h
+++ b/ash/screen_ash.h
@@ -62,7 +62,7 @@
   void NotifyDisplayRemoved(const gfx::Display& display);
 
  protected:
-  // Implementation of gfx::Screen:
+  // gfx::Screen overrides:
   virtual bool IsDIPEnabled() OVERRIDE;
   virtual gfx::Point GetCursorScreenPoint() OVERRIDE;
   virtual gfx::NativeWindow GetWindowAtCursorScreenPoint() OVERRIDE;
diff --git a/ash/shelf/shelf_layout_manager_unittest.cc b/ash/shelf/shelf_layout_manager_unittest.cc
index e065bda1..c778f08 100644
--- a/ash/shelf/shelf_layout_manager_unittest.cc
+++ b/ash/shelf/shelf_layout_manager_unittest.cc
@@ -593,13 +593,12 @@
   gfx::Rect launcher_bounds(
       shelf->GetWindowBoundsInScreen());
   int shelf_height = manager->GetIdealBounds().height();
-
-  const gfx::Display& display = Shell::GetInstance()->display_manager()->
-      GetDisplayNearestWindow(Shell::GetPrimaryRootWindow());
+  gfx::Screen* screen = Shell::GetScreen();
+  gfx::Display display = screen->GetDisplayNearestWindow(
+      Shell::GetPrimaryRootWindow());
   ASSERT_NE(-1, display.id());
   // Bottom inset should be the max of widget heights.
-  EXPECT_EQ(shelf_height,
-            display.bounds().bottom() - display.work_area().bottom());
+  EXPECT_EQ(shelf_height, display.GetWorkAreaInsets().bottom());
 
   // Hide the shelf.
   SetState(manager, SHELF_HIDDEN);
@@ -607,14 +606,16 @@
   StepWidgetLayerAnimatorToEnd(shelf);
   StepWidgetLayerAnimatorToEnd(shelf->status_area_widget());
   EXPECT_EQ(SHELF_HIDDEN, manager->visibility_state());
-  EXPECT_EQ(0,
-            display.bounds().bottom() - display.work_area().bottom());
+  display = screen->GetDisplayNearestWindow(
+      Shell::GetPrimaryRootWindow());
+
+  EXPECT_EQ(0, display.GetWorkAreaInsets().bottom());
 
   // Make sure the bounds of the two widgets changed.
   EXPECT_GE(shelf->GetNativeView()->bounds().y(),
-            Shell::GetScreen()->GetPrimaryDisplay().bounds().bottom());
+            screen->GetPrimaryDisplay().bounds().bottom());
   EXPECT_GE(shelf->status_area_widget()->GetNativeView()->bounds().y(),
-            Shell::GetScreen()->GetPrimaryDisplay().bounds().bottom());
+            screen->GetPrimaryDisplay().bounds().bottom());
 
   // And show it again.
   SetState(manager, SHELF_VISIBLE);
@@ -622,13 +623,14 @@
   StepWidgetLayerAnimatorToEnd(shelf);
   StepWidgetLayerAnimatorToEnd(shelf->status_area_widget());
   EXPECT_EQ(SHELF_VISIBLE, manager->visibility_state());
-  EXPECT_EQ(shelf_height,
-            display.bounds().bottom() - display.work_area().bottom());
+  display = screen->GetDisplayNearestWindow(
+      Shell::GetPrimaryRootWindow());
+  EXPECT_EQ(shelf_height, display.GetWorkAreaInsets().bottom());
 
   // Make sure the bounds of the two widgets changed.
   launcher_bounds = shelf->GetNativeView()->bounds();
   int bottom =
-      Shell::GetScreen()->GetPrimaryDisplay().bounds().bottom() - shelf_height;
+      screen->GetPrimaryDisplay().bounds().bottom() - shelf_height;
   EXPECT_EQ(launcher_bounds.y(),
             bottom + (manager->GetIdealBounds().height() -
                       launcher_bounds.height()) / 2);
@@ -644,14 +646,13 @@
   shelf->shelf_layout_manager()->LayoutShelf();
   EXPECT_EQ(SHELF_VISIBLE, shelf->shelf_layout_manager()->visibility_state());
 
-  const gfx::Display& display = Shell::GetInstance()->display_manager()->
-      GetDisplayNearestWindow(Shell::GetPrimaryRootWindow());
-
   // Hide the shelf.
   SetState(shelf->shelf_layout_manager(), SHELF_HIDDEN);
   shelf->shelf_layout_manager()->LayoutShelf();
   EXPECT_EQ(SHELF_HIDDEN, shelf->shelf_layout_manager()->visibility_state());
-  EXPECT_EQ(0, display.bounds().bottom() - display.work_area().bottom());
+  gfx::Display display = Shell::GetScreen()->GetDisplayNearestWindow(
+      Shell::GetPrimaryRootWindow());
+  EXPECT_EQ(0, display.GetWorkAreaInsets().bottom());
 
   // Make sure the bounds of the two widgets changed.
   EXPECT_GE(shelf->GetNativeView()->bounds().y(),
@@ -1163,10 +1164,9 @@
   shelf->SetAlignment(SHELF_ALIGNMENT_LEFT);
   gfx::Rect launcher_bounds(
       GetShelfWidget()->GetWindowBoundsInScreen());
-  const internal::DisplayManager* manager =
-      Shell::GetInstance()->display_manager();
+  const gfx::Screen* screen = Shell::GetScreen();
   gfx::Display display =
-      manager->GetDisplayNearestWindow(Shell::GetPrimaryRootWindow());
+      screen->GetDisplayNearestWindow(Shell::GetPrimaryRootWindow());
   ASSERT_NE(-1, display.id());
   EXPECT_EQ(shelf->GetIdealBounds().width(),
             display.GetWorkAreaInsets().left());
@@ -1187,16 +1187,16 @@
   EXPECT_EQ(display.bounds().y(), launcher_bounds.y());
   EXPECT_EQ(display.bounds().height(), launcher_bounds.height());
   shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS);
-  display = manager->GetDisplayNearestWindow(Shell::GetPrimaryRootWindow());
+  display = screen->GetDisplayNearestWindow(Shell::GetPrimaryRootWindow());
   EXPECT_EQ(ShelfLayoutManager::kAutoHideSize,
       display.GetWorkAreaInsets().left());
   EXPECT_EQ(ShelfLayoutManager::kAutoHideSize, display.work_area().x());
 
   shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_NEVER);
   shelf->SetAlignment(SHELF_ALIGNMENT_RIGHT);
-  display = manager->GetDisplayNearestWindow(Shell::GetPrimaryRootWindow());
+  display = screen->GetDisplayNearestWindow(Shell::GetPrimaryRootWindow());
   launcher_bounds = GetShelfWidget()->GetWindowBoundsInScreen();
-  display = manager->GetDisplayNearestWindow(Shell::GetPrimaryRootWindow());
+  display = screen->GetDisplayNearestWindow(Shell::GetPrimaryRootWindow());
   ASSERT_NE(-1, display.id());
   EXPECT_EQ(shelf->GetIdealBounds().width(),
             display.GetWorkAreaInsets().right());
@@ -1215,7 +1215,7 @@
   EXPECT_EQ(display.bounds().y(), launcher_bounds.y());
   EXPECT_EQ(display.bounds().height(), launcher_bounds.height());
   shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS);
-  display = manager->GetDisplayNearestWindow(Shell::GetPrimaryRootWindow());
+  display = screen->GetDisplayNearestWindow(Shell::GetPrimaryRootWindow());
   EXPECT_EQ(ShelfLayoutManager::kAutoHideSize,
       display.GetWorkAreaInsets().right());
   EXPECT_EQ(ShelfLayoutManager::kAutoHideSize,
@@ -1223,9 +1223,9 @@
 
   shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_NEVER);
   shelf->SetAlignment(SHELF_ALIGNMENT_TOP);
-  display = manager->GetDisplayNearestWindow(Shell::GetPrimaryRootWindow());
+  display = screen->GetDisplayNearestWindow(Shell::GetPrimaryRootWindow());
   launcher_bounds = GetShelfWidget()->GetWindowBoundsInScreen();
-  display = manager->GetDisplayNearestWindow(Shell::GetPrimaryRootWindow());
+  display = screen->GetDisplayNearestWindow(Shell::GetPrimaryRootWindow());
   ASSERT_NE(-1, display.id());
   EXPECT_EQ(shelf->GetIdealBounds().height(),
             display.GetWorkAreaInsets().top());
@@ -1244,7 +1244,7 @@
   EXPECT_EQ(display.bounds().x(), launcher_bounds.x());
   EXPECT_EQ(display.bounds().width(), launcher_bounds.width());
   shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS);
-  display = manager->GetDisplayNearestWindow(Shell::GetPrimaryRootWindow());
+  display = screen->GetDisplayNearestWindow(Shell::GetPrimaryRootWindow());
   EXPECT_EQ(ShelfLayoutManager::kAutoHideSize,
       display.GetWorkAreaInsets().top());
   EXPECT_EQ(ShelfLayoutManager::kAutoHideSize,
diff --git a/ash/shell.cc b/ash/shell.cc
index 97450b8f..b55cb3f 100644
--- a/ash/shell.cc
+++ b/ash/shell.cc
@@ -16,7 +16,6 @@
 #include "ash/display/display_controller.h"
 #include "ash/display/display_manager.h"
 #include "ash/display/event_transformation_handler.h"
-#include "ash/display/mirror_window_controller.h"
 #include "ash/display/mouse_cursor_event_filter.h"
 #include "ash/display/screen_position_controller.h"
 #include "ash/drag_drop/drag_drop_controller.h"
@@ -214,7 +213,6 @@
       is_touch_hud_projection_enabled_(false) {
   DCHECK(delegate_.get());
   display_manager_.reset(new internal::DisplayManager);
-  mirror_window_controller_.reset(new internal::MirrorWindowController);
 
   ANNOTATE_LEAKING_OBJECT_PTR(screen_);  // see crbug.com/156466
   gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_ALTERNATE, screen_);
@@ -307,8 +305,6 @@
   power_button_controller_.reset();
   lock_state_controller_.reset();
 
-  mirror_window_controller_.reset();
-
   // This also deletes all RootWindows. Note that we invoke Shutdown() on
   // DisplayController before resetting |display_controller_|, since destruction
   // of its owned RootWindowControllers relies on the value.
@@ -711,8 +707,10 @@
 
 void Shell::SetDisplayWorkAreaInsets(Window* contains,
                                      const gfx::Insets& insets) {
-  if (!display_manager_->UpdateWorkAreaOfDisplayNearestWindow(contains, insets))
+  if (!display_controller_->UpdateWorkAreaOfDisplayNearestWindow(
+          contains, insets)) {
     return;
+  }
   FOR_EACH_OBSERVER(ShellObserver, observers_,
                     OnDisplayWorkAreaInsetsChanged());
 }
diff --git a/ash/shell.h b/ash/shell.h
index a602cdf3..69b8970e 100644
--- a/ash/shell.h
+++ b/ash/shell.h
@@ -111,7 +111,6 @@
 class EventRewriterEventFilter;
 class EventTransformationHandler;
 class FocusCycler;
-class MirrorWindowController;
 class MouseCursorEventFilter;
 class OutputConfiguratorAnimation;
 class OverlayEventFilter;
@@ -287,9 +286,6 @@
   internal::DisplayManager* display_manager() {
     return display_manager_.get();
   }
-  internal::MirrorWindowController* mirror_window_controller() {
-    return mirror_window_controller_.get();
-  }
   views::corewm::InputMethodEventFilter* input_method_filter() {
     return input_method_filter_.get();
   }
@@ -586,7 +582,6 @@
   scoped_ptr<views::corewm::InputMethodEventFilter> input_method_filter_;
 
   scoped_ptr<internal::DisplayManager> display_manager_;
-  scoped_ptr<internal::MirrorWindowController> mirror_window_controller_;
 
 #if defined(OS_CHROMEOS) && defined(USE_X11)
   // Controls video output device state.
diff --git a/ash/shell/toplevel_window.cc b/ash/shell/toplevel_window.cc
index a65787a..4165b398 100644
--- a/ash/shell/toplevel_window.cc
+++ b/ash/shell/toplevel_window.cc
@@ -5,7 +5,7 @@
 #include "ash/shell/toplevel_window.h"
 
 #include "ash/display/display_controller.h"
-#include "ash/display/display_manager.h"
+#include "ash/screen_ash.h"
 #include "ash/shell.h"
 #include "ash/wm/property_util.h"
 #include "base/strings/utf_string_conversions.h"
@@ -31,7 +31,7 @@
 
   gfx::Rect bounds(x, 150, 300, 300);
   gfx::Display display =
-      ash::Shell::GetInstance()->display_manager()->GetDisplayMatching(bounds);
+      ash::Shell::GetScreen()->GetDisplayMatching(bounds);
   aura::RootWindow* root = ash::Shell::GetInstance()->display_controller()->
       GetRootWindowForDisplayId(display.id());
   views::Widget* widget = views::Widget::CreateWindowWithContextAndBounds(
diff --git a/ash/test/ash_test_base.cc b/ash/test/ash_test_base.cc
index 95b8d99..6917e0e 100644
--- a/ash/test/ash_test_base.cc
+++ b/ash/test/ash_test_base.cc
@@ -9,7 +9,7 @@
 
 #include "ash/ash_switches.h"
 #include "ash/display/display_controller.h"
-#include "ash/display/display_manager.h"
+#include "ash/screen_ash.h"
 #include "ash/shell.h"
 #include "ash/test/ash_test_helper.h"
 #include "ash/test/display_manager_test_api.h"
@@ -253,7 +253,7 @@
     SetDefaultParentByPrimaryRootWindow(window);
   } else {
     gfx::Display display =
-      ash::Shell::GetInstance()->display_manager()->GetDisplayMatching(bounds);
+        Shell::GetScreen()->GetDisplayMatching(bounds);
     aura::RootWindow* root = ash::Shell::GetInstance()->display_controller()->
         GetRootWindowForDisplayId(display.id());
     gfx::Point origin = bounds.origin();
diff --git a/ash/test/mirror_window_test_api.cc b/ash/test/mirror_window_test_api.cc
index 270c200b..d8c7705 100644
--- a/ash/test/mirror_window_test_api.cc
+++ b/ash/test/mirror_window_test_api.cc
@@ -4,6 +4,7 @@
 
 #include "ash/test/mirror_window_test_api.h"
 
+#include "ash/display/display_controller.h"
 #include "ash/display/mirror_window_controller.h"
 #include "ash/shell.h"
 #include "ui/aura/root_window_transformer.h"
@@ -13,25 +14,29 @@
 namespace test {
 
 const aura::RootWindow* MirrorWindowTestApi::GetRootWindow() const {
-  return Shell::GetInstance()->mirror_window_controller()->root_window_.get();
+  return Shell::GetInstance()->display_controller()->
+      mirror_window_controller()->root_window_.get();
 }
 
 int MirrorWindowTestApi::GetCurrentCursorType() const {
-  return Shell::GetInstance()->mirror_window_controller()->current_cursor_type_;
+  return Shell::GetInstance()->display_controller()->
+      mirror_window_controller()->current_cursor_type_;
 }
 
 const gfx::Point& MirrorWindowTestApi::GetCursorHotPoint() const {
-  return Shell::GetInstance()->mirror_window_controller()->hot_point_;
+  return Shell::GetInstance()->display_controller()->
+      mirror_window_controller()->hot_point_;
 }
 
 const aura::Window* MirrorWindowTestApi::GetCursorWindow() const {
-  return Shell::GetInstance()->mirror_window_controller()->cursor_window_;
+  return Shell::GetInstance()->display_controller()->
+      mirror_window_controller()->cursor_window_;
 }
 
 scoped_ptr<aura::RootWindowTransformer>
 MirrorWindowTestApi::CreateCurrentRootWindowTransformer() const {
-  return Shell::GetInstance()->mirror_window_controller()->
-      CreateRootWindowTransformer();
+  return Shell::GetInstance()->display_controller()->
+      mirror_window_controller()->CreateRootWindowTransformer();
 }
 
 }  // namespace test
diff --git a/ash/touch/touch_observer_hud.cc b/ash/touch/touch_observer_hud.cc
index ceb87fd..3daeba6 100644
--- a/ash/touch/touch_observer_hud.cc
+++ b/ash/touch/touch_observer_hud.cc
@@ -4,11 +4,11 @@
 
 #include "ash/touch/touch_observer_hud.h"
 
-#include "ash/display/display_manager.h"
 #include "ash/root_window_controller.h"
 #include "ash/shell.h"
 #include "ash/shell_window_ids.h"
 #include "ash/wm/property_util.h"
+#include "ash/wm/window_properties.h"
 #include "ui/aura/root_window.h"
 #include "ui/gfx/display.h"
 #include "ui/gfx/rect.h"
diff --git a/ash/touch/touch_observer_hud_unittest.cc b/ash/touch/touch_observer_hud_unittest.cc
index 0399407..3c60543 100644
--- a/ash/touch/touch_observer_hud_unittest.cc
+++ b/ash/touch/touch_observer_hud_unittest.cc
@@ -15,6 +15,7 @@
 #include "base/command_line.h"
 #include "base/format_macros.h"
 #include "base/strings/stringprintf.h"
+#include "ui/aura/window.h"
 
 namespace ash {
 namespace internal {
diff --git a/ash/wm/ash_native_cursor_manager.cc b/ash/wm/ash_native_cursor_manager.cc
index 4f2f39e5..28e0785 100644
--- a/ash/wm/ash_native_cursor_manager.cc
+++ b/ash/wm/ash_native_cursor_manager.cc
@@ -4,6 +4,7 @@
 
 #include "ash/wm/ash_native_cursor_manager.h"
 
+#include "ash/display/display_controller.h"
 #include "ash/display/mirror_window_controller.h"
 #include "ash/shell.h"
 #include "ash/wm/image_cursors.h"
@@ -22,7 +23,8 @@
        iter != root_windows.end(); ++iter)
     (*iter)->SetCursor(cursor);
 #if defined(OS_CHROMEOS)
-  Shell::GetInstance()->mirror_window_controller()->SetMirroredCursor(cursor);
+  Shell::GetInstance()->display_controller()->
+      mirror_window_controller()->SetMirroredCursor(cursor);
 #endif
 }
 
@@ -33,7 +35,7 @@
        iter != root_windows.end(); ++iter)
     (*iter)->OnCursorVisibilityChanged(visible);
 #if defined(OS_CHROMEOS)
-  Shell::GetInstance()->mirror_window_controller()->
+  Shell::GetInstance()->display_controller()->mirror_window_controller()->
       SetMirroredCursorVisibility(visible);
 #endif
 }
diff --git a/ash/wm/window_properties.h b/ash/wm/window_properties.h
index c5bba1f..50fb93ba 100644
--- a/ash/wm/window_properties.h
+++ b/ash/wm/window_properties.h
@@ -32,6 +32,9 @@
 ASH_EXPORT extern const aura::WindowProperty<bool>* const
     kCyclingThroughWorkspacesKey;
 
+// A property key to store display_id an aura::RootWindow is mapped to.
+extern const aura::WindowProperty<int64>* const kDisplayIdKey;
+
 // A property key to indicate whether there is any chrome at all that cannot be
 // hidden when the window is fullscreen. This is unrelated to whether the full
 // chrome can be revealed by hovering the mouse at the top of the screen.