diff --git a/ash/ash.gyp b/ash/ash.gyp
index a2bf778f2baaa..f78a02101f671 100644
--- a/ash/ash.gyp
+++ b/ash/ash.gyp
@@ -138,8 +138,6 @@
         'wm/shadow_types.h',
         'wm/shelf_layout_manager.cc',
         'wm/shelf_layout_manager.h',
-        'wm/show_state_controller.h',
-        'wm/show_state_controller.cc',
         'wm/stacking_controller.cc',
         'wm/stacking_controller.h',
         'wm/status_area_layout_manager.cc',
@@ -176,7 +174,6 @@
         'wm/workspace/workspace_layout_manager.h',
         'wm/workspace/workspace_manager.cc',
         'wm/workspace/workspace_manager.h',
-        'wm/workspace/workspace_observer.h',
       ],
     },
     {
@@ -238,7 +235,6 @@
         'wm/window_cycle_controller_unittest.cc',
         'wm/window_modality_controller_unittest.cc',
         'wm/workspace_controller_unittest.cc',
-        'wm/workspace/workspace_layout_manager_unittest.cc',
         'wm/workspace/workspace_manager_unittest.cc',
 
         '<(SHARED_INTERMEDIATE_DIR)/ui/gfx/gfx_resources.rc',
diff --git a/ash/shell/shell_main.cc b/ash/shell/shell_main.cc
index ea52da8493b2b..93029909995e5 100644
--- a/ash/shell/shell_main.cc
+++ b/ash/shell/shell_main.cc
@@ -157,7 +157,9 @@ class ShellDelegateImpl : public ash::ShellDelegate {
 
   virtual void LauncherItemClicked(
       const ash::LauncherItem& item) OVERRIDE {
-    ash::ActivateWindow(watcher_->GetWindowByID(item.id));
+    aura::Window* window = watcher_->GetWindowByID(item.id);
+    window->Show();
+    ash::ActivateWindow(window);
   }
 
   virtual int GetBrowserShortcutResourceId() OVERRIDE {
diff --git a/ash/wm/show_state_controller.cc b/ash/wm/show_state_controller.cc
deleted file mode 100644
index 9b670c784f2cc..0000000000000
--- a/ash/wm/show_state_controller.cc
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ash/wm/show_state_controller.h"
-
-#include "ash/wm/property_util.h"
-#include "ash/wm/workspace/workspace.h"
-#include "ash/wm/workspace/workspace_manager.h"
-#include "ui/aura/client/aura_constants.h"
-#include "ui/aura/window.h"
-#include "ui/base/ui_base_types.h"
-
-namespace ash {
-namespace internal {
-
-ShowStateController::ShowStateController(
-    WorkspaceManager* workspace_manager)
-    : workspace_manager_(workspace_manager) {
-}
-
-ShowStateController::~ShowStateController() {
-}
-
-void ShowStateController::OnWindowPropertyChanged(aura::Window* window,
-                                                  const char* name,
-                                                  void* old) {
-  if (name != aura::client::kShowStateKey)
-    return;
-  if (window->GetIntProperty(name) == ui::SHOW_STATE_NORMAL) {
-    // Restore the size of window first, then let Workspace layout the window.
-    const gfx::Rect* restore = GetRestoreBounds(window);
-    window->SetProperty(aura::client::kRestoreBoundsKey, NULL);
-    if (restore)
-      window->SetBounds(*restore);
-    delete restore;
-  } else if (old == reinterpret_cast<void*>(ui::SHOW_STATE_NORMAL)) {
-    // Store the restore bounds only if previous state is normal.
-    DCHECK(window->GetProperty(aura::client::kRestoreBoundsKey) == NULL);
-    SetRestoreBounds(window, window->GetTargetBounds());
-  }
-
-  workspace_manager_->FindBy(window)->Layout(window);
-}
-
-}  // namespace internal
-}  // namespace ash
diff --git a/ash/wm/show_state_controller.h b/ash/wm/show_state_controller.h
deleted file mode 100644
index 5b3191f578ca2..0000000000000
--- a/ash/wm/show_state_controller.h
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef ASH_WM_SHOW_STATE_CONTROLLER_H_
-#define ASH_WM_SHOW_STATE_CONTROLLER_H_
-#pragma once
-
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
-#include "ui/aura/window_observer.h"
-
-namespace aura {
-class Window;
-}
-
-namespace ash {
-namespace internal {
-
-class WorkspaceManager;
-
-// ShowStateController controls the window's bounds when
-// the window's show state property has changed.
-class ShowStateController : public aura::WindowObserver {
-public:
-  explicit ShowStateController(WorkspaceManager* layout_manager);
-  virtual ~ShowStateController();
-
-  // aura::WindowObserver overrides:
-  virtual void OnWindowPropertyChanged(aura::Window* window,
-                                       const char* name,
-                                       void* old) OVERRIDE;
-
- private:
-  // |workspace_maanger_| is owned by |WorkspaceController|.
-  WorkspaceManager* workspace_manager_;
-
-  DISALLOW_COPY_AND_ASSIGN(ShowStateController);
-};
-
-}  // namepsace internal
-}  // namepsace ash
-
-#endif  // ASH_WM_SHOW_STATE_CONTROLLER_H_
diff --git a/ash/wm/window_util.cc b/ash/wm/window_util.cc
index 25e84f6db8c2f..055244d490b89 100644
--- a/ash/wm/window_util.cc
+++ b/ash/wm/window_util.cc
@@ -14,6 +14,12 @@
 
 namespace ash {
 
+namespace {
+
+const char kOpenWindowSplitKey[] = "OpenWindowSplit";
+
+}  // namespace
+
 void ActivateWindow(aura::Window* window) {
   aura::client::GetActivationClient()->ActivateWindow(window);
 }
@@ -64,5 +70,13 @@ bool HasFullscreenWindow(const WindowSet& windows) {
   return false;
 }
 
+void SetOpenWindowSplit(aura::Window* window, bool value) {
+  window->SetIntProperty(kOpenWindowSplitKey, value ? 1 : 0);
+}
+
+bool GetOpenWindowSplit(aura::Window* window) {
+  return window->GetIntProperty(kOpenWindowSplitKey) == 1;
+}
+
 }  // namespace window_util
 }  // namespace ash
diff --git a/ash/wm/window_util.h b/ash/wm/window_util.h
index e43800721bb6a..f76b8aaf05727 100644
--- a/ash/wm/window_util.h
+++ b/ash/wm/window_util.h
@@ -49,6 +49,11 @@ ASH_EXPORT void RestoreWindow(aura::Window* window);
 typedef std::set<aura::Window*> WindowSet;
 ASH_EXPORT bool HasFullscreenWindow(const WindowSet& windows);
 
+// Sets whether the window should be open in a split mode. Only applicable when
+// workspaces are used.
+ASH_EXPORT void SetOpenWindowSplit(aura::Window* window, bool value);
+ASH_EXPORT bool GetOpenWindowSplit(aura::Window* window);
+
 }  // namespace window_util
 }  // namespace ash
 
diff --git a/ash/wm/workspace/workspace.cc b/ash/wm/workspace/workspace.cc
index 574662b50e96b..3f5ebbe873bc6 100644
--- a/ash/wm/workspace/workspace.cc
+++ b/ash/wm/workspace/workspace.cc
@@ -14,41 +14,13 @@
 #include "ui/aura/root_window.h"
 #include "ui/aura/window.h"
 #include "ui/base/ui_base_types.h"
-#include "ui/gfx/compositor/layer.h"
-#include "ui/gfx/compositor/layer_animator.h"
-#include "ui/gfx/compositor/scoped_layer_animation_settings.h"
-
-namespace {
-// Horizontal margin between windows.
-const int kWindowHorizontalMargin = 10;
-
-// Maximum number of windows a workspace can have.
-size_t g_max_windows_per_workspace = 2;
-
-// Returns the bounds of the window that should be used to calculate
-// the layout. It uses the restore bounds if exits, or
-// the target bounds of the window. The target bounds is the
-// final destination of |window| if the window's layer is animating,
-// or the current bounds of the window of no animation is currently
-// in progress.
-gfx::Rect GetLayoutBounds(aura::Window* window) {
-  const gfx::Rect* restore_bounds = ash::GetRestoreBounds(window);
-  return restore_bounds ? *restore_bounds : window->GetTargetBounds();
-}
-
-// Returns the width of the window that should be used to calculate
-// the layout. See |GetLayoutBounds| for more details.
-int GetLayoutWidth(aura::Window* window) {
-  return GetLayoutBounds(window).width();
-}
-
-}  // namespace
 
 namespace ash {
 namespace internal {
 
 Workspace::Workspace(WorkspaceManager* manager)
-    : workspace_manager_(manager) {
+    : type_(TYPE_NORMAL),
+      workspace_manager_(manager) {
   workspace_manager_->AddWorkspace(this);
 }
 
@@ -56,15 +28,34 @@ Workspace::~Workspace() {
   workspace_manager_->RemoveWorkspace(this);
 }
 
-void Workspace::SetBounds(const gfx::Rect& bounds) {
-  bool bounds_changed = bounds_ != bounds;
-  bounds_ = bounds;
-  if (bounds_changed)
-    Layout(NULL);
+// static
+Workspace::Type Workspace::TypeForWindow(aura::Window* window) {
+  if (window_util::GetOpenWindowSplit(window))
+    return TYPE_SPLIT;
+  if (window_util::IsWindowMaximized(window) ||
+      window_util::IsWindowFullscreen(window)) {
+    return TYPE_MAXIMIZED;
+  }
+  return TYPE_NORMAL;
+}
+
+void Workspace::SetType(Type type) {
+  // Can only change the type when there are no windows, or the type of window
+  // matches the type changing to. We need only check the first window as CanAdd
+  // only allows new windows if the type matches.
+  DCHECK(windows_.empty() || TypeForWindow(windows_[0]) == type);
+  type_ = type;
+}
+
+void Workspace::WorkspaceSizeChanged() {
+  if (!windows_.empty()) {
+    // TODO: need to handle size changing.
+    NOTIMPLEMENTED();
+  }
 }
 
 gfx::Rect Workspace::GetWorkAreaBounds() const {
-  return workspace_manager_->GetWorkAreaBounds(bounds_);
+  return workspace_manager_->GetWorkAreaBounds();
 }
 
 bool Workspace::AddWindowAfter(aura::Window* window, aura::Window* after) {
@@ -72,15 +63,19 @@ bool Workspace::AddWindowAfter(aura::Window* window, aura::Window* after) {
     return false;
   DCHECK(!Contains(window));
 
-  if (!after) {  // insert at the end.
+  aura::Window::Windows::iterator i =
+      std::find(windows_.begin(), windows_.end(), after);
+  if (!after || i == windows_.end())
     windows_.push_back(window);
-  } else {
-    DCHECK(Contains(after));
-    aura::Window::Windows::iterator i =
-        std::find(windows_.begin(), windows_.end(), after);
+  else
     windows_.insert(++i, window);
+
+  if (type_ == TYPE_MAXIMIZED) {
+    workspace_manager_->SetWindowBounds(window, GetWorkAreaBounds());
+  } else if (type_ == TYPE_SPLIT) {
+    // TODO: this needs to adjust bounds appropriately.
+    workspace_manager_->SetWindowBounds(window, GetWorkAreaBounds());
   }
-  Layout(window);
 
   return true;
 }
@@ -88,138 +83,17 @@ bool Workspace::AddWindowAfter(aura::Window* window, aura::Window* after) {
 void Workspace::RemoveWindow(aura::Window* window) {
   DCHECK(Contains(window));
   windows_.erase(std::find(windows_.begin(), windows_.end(), window));
-  Layout(NULL);
+  // TODO: this needs to adjust things.
 }
 
 bool Workspace::Contains(aura::Window* window) const {
   return std::find(windows_.begin(), windows_.end(), window) != windows_.end();
 }
 
-aura::Window* Workspace::FindRotateWindowForLocation(
-    const gfx::Point& position) {
-  aura::Window* active = ash::GetActiveWindow();
-  if (GetTotalWindowsWidth() < bounds_.width()) {
-    // If all windows fit to the width of the workspace, it returns the
-    // window which contains |position|'s x coordinate.
-    for (aura::Window::Windows::const_iterator i = windows_.begin();
-         i != windows_.end();
-         ++i) {
-      if (active == *i)
-        continue;
-      gfx::Rect bounds = (*i)->GetTargetBounds();
-      if (bounds.x() < position.x() && position.x() < bounds.right())
-        return *i;
-    }
-  } else if (bounds_.x() < position.x() && position.x() < bounds_.right()) {
-    // If windows are overlapping, it divides the workspace into
-    // regions with the same width, and returns the Nth window that
-    // corresponds to the region that contains the |position|.
-    int width = bounds_.width() / windows_.size();
-    size_t index = (position.x() - bounds_.x()) / width;
-    DCHECK(index < windows_.size());
-    aura::Window* window = windows_[index];
-    if (window != active)
-      return window;
-  }
-  return NULL;
-}
-
-void Workspace::RotateWindows(aura::Window* source, aura::Window* target) {
-  DCHECK(Contains(source));
-  DCHECK(Contains(target));
-  aura::Window::Windows::iterator source_iter =
-      std::find(windows_.begin(), windows_.end(), source);
-  aura::Window::Windows::iterator target_iter =
-      std::find(windows_.begin(), windows_.end(), target);
-  DCHECK(source_iter != target_iter);
-  if (source_iter < target_iter)
-    std::rotate(source_iter, source_iter + 1, target_iter + 1);
-  else
-    std::rotate(target_iter, source_iter, source_iter + 1);
-  Layout(NULL);
-}
-
-aura::Window* Workspace::ShiftWindows(aura::Window* insert,
-                                      aura::Window* until,
-                                      aura::Window* target,
-                                      ShiftDirection direction) {
-  DCHECK(until);
-  DCHECK(!Contains(insert));
-
-  bool shift_reached_until = GetIndexOf(until) >= 0;
-  if (shift_reached_until) {
-    // Calling RemoveWindow here causes the animation set in Layout below
-    // to be ignored.  See crbug.com/102413.
-    windows_.erase(std::find(windows_.begin(), windows_.end(), until));
-  }
-  aura::Window* pushed = NULL;
-  if (direction == SHIFT_TO_RIGHT) {
-    aura::Window::Windows::iterator iter =
-        std::find(windows_.begin(), windows_.end(), target);
-    // Insert at |target| position, or at the begining.
-    if (iter == windows_.end())
-      iter = windows_.begin();
-    windows_.insert(iter, insert);
-    if (!shift_reached_until) {
-      pushed = windows_.back();
-      windows_.erase(--windows_.end());
-    }
-  } else {
-    aura::Window::Windows::iterator iter =
-        std::find(windows_.begin(), windows_.end(), target);
-    // Insert after |target|, or at the end.
-    if (iter != windows_.end())
-      ++iter;
-    windows_.insert(iter, insert);
-    if (!shift_reached_until) {
-      pushed = windows_.front();
-      windows_.erase(windows_.begin());
-    }
-  }
-  Layout(NULL);
-  return pushed;
-}
-
 void Workspace::Activate() {
   workspace_manager_->SetActiveWorkspace(this);
 }
 
-void Workspace::Layout(aura::Window* no_animation) {
-  aura::Window* ignore = workspace_manager_->ignored_window();
-  workspace_manager_->set_layout_in_progress(true);
-  gfx::Rect work_area = workspace_manager_->GetWorkAreaBounds(bounds_);
-  int total_width = GetTotalWindowsWidth();
-  if (total_width < work_area.width()) {
-    int dx = (work_area.width() - total_width) / 2;
-    for (aura::Window::Windows::iterator i = windows_.begin();
-         i != windows_.end();
-         ++i) {
-      if (*i != ignore) {
-        MoveWindowTo(*i,
-                     gfx::Point(work_area.x() + dx, work_area.y()),
-                     no_animation != *i);
-      }
-      dx += GetLayoutWidth(*i) + kWindowHorizontalMargin;
-    }
-  } else {
-    DCHECK_LT(windows_.size(), 3U);
-    // TODO(oshima): This is messy. Figure out general algorithm to
-    // layout more than 2 windows.
-    if (windows_[0] != ignore) {
-      MoveWindowTo(windows_[0],
-                   work_area.origin(),
-                   no_animation != windows_[0]);
-    }
-    if (windows_.size() == 2 && windows_[1] != ignore) {
-      MoveWindowTo(windows_[1],
-                   gfx::Point(work_area.right() - GetLayoutWidth(windows_[1]),
-                              work_area.y()),
-                   no_animation != windows_[1]);
-    }
-  }
-  workspace_manager_->set_layout_in_progress(false);
-}
-
 bool Workspace::ContainsFullscreenWindow() const {
   for (aura::Window::Windows::const_iterator i = windows_.begin();
        i != windows_.end();
@@ -240,47 +114,7 @@ int Workspace::GetIndexOf(aura::Window* window) const {
 }
 
 bool Workspace::CanAdd(aura::Window* window) const {
-  // TODO(oshima): This should be based on available space and the
-  // size of the |window|.
-  //NOTIMPLEMENTED();
-  return windows_.size() < g_max_windows_per_workspace;
-}
-
-void Workspace::MoveWindowTo(
-    aura::Window* window,
-    const gfx::Point& origin,
-    bool animate) {
-  gfx::Rect bounds = GetLayoutBounds(window);
-  gfx::Rect work_area = GetWorkAreaBounds();
-  // Make sure the window isn't bigger than the workspace size.
-  bounds.SetRect(origin.x(), origin.y(),
-                 std::min(work_area.width(), bounds.width()),
-                 std::min(work_area.height(), bounds.height()));
-  if (animate) {
-    ui::ScopedLayerAnimationSettings settings(window->layer()->GetAnimator());
-    window->SetBounds(bounds);
-  } else {
-    window->SetBounds(bounds);
-  }
-}
-
-int Workspace::GetTotalWindowsWidth() const {
-  int total_width = 0;
-  for (aura::Window::Windows::const_iterator i = windows_.begin();
-       i != windows_.end();
-       ++i) {
-    if (total_width)
-      total_width += kWindowHorizontalMargin;
-    total_width += GetLayoutWidth(*i);
-  }
-  return total_width;
-}
-
-// static
-size_t Workspace::SetMaxWindowsCount(size_t max) {
-  int old = g_max_windows_per_workspace;
-  g_max_windows_per_workspace = max;
-  return old;
+  return TypeForWindow(window) == type_;
 }
 
 }  // namespace internal
diff --git a/ash/wm/workspace/workspace.h b/ash/wm/workspace/workspace.h
index 999df8493ef87..5441d5b8fc442 100644
--- a/ash/wm/workspace/workspace.h
+++ b/ash/wm/workspace/workspace.h
@@ -22,17 +22,24 @@ namespace internal {
 class WorkspaceManager;
 class WorkspaceTest;
 
-// A workspace is a partial area of the entire desktop (viewport) that
-// is visible to the user at a given time. The size of the workspace is
-// generally the same as the size of the monitor, and the desktop can
-// have multiple workspaces.
-// A workspace contains a limited number of windows and the workspace
-// manager may create a new workspace if there is not enough room for
-// a new window.
+// A workspace contains a number of windows. The number of windows a Workspace
+// may contain is dictated by the type. Typically only one workspace is visible
+// at a time. The exception to that is when overview mode is active.
 class ASH_EXPORT Workspace {
  public:
-  explicit Workspace(WorkspaceManager* manager);
-  virtual ~Workspace();
+  // Type of workspace. The type of workspace dictates the types of windows the
+  // workspace can contain.
+  enum Type {
+    // The workspace holds a single maximized or full screen window.
+    TYPE_MAXIMIZED,
+
+    // Workspace contains multiple windows that are split (also known as
+    // co-maximized).
+    TYPE_SPLIT,
+
+    // Workspace contains non-maximized windows that can be moved in anyway.
+    TYPE_NORMAL,
+  };
 
   // Specifies the direction to shift windows in |ShiftWindows()|.
   enum ShiftDirection {
@@ -40,15 +47,25 @@ class ASH_EXPORT Workspace {
     SHIFT_TO_LEFT
   };
 
-  //  Returns true if this workspace has no windows.
+  explicit Workspace(WorkspaceManager* manager);
+  virtual ~Workspace();
+
+  // Returns the type of workspace that can contain |window|.
+  static Type TypeForWindow(aura::Window* window);
+
+  // The type of this Workspace.
+  void SetType(Type type);
+  Type type() const { return type_; }
+
+  // Returns true if this workspace has no windows.
   bool is_empty() const { return windows_.empty(); }
+  size_t num_windows() const { return windows_.size(); }
+  const std::vector<aura::Window*>& windows() const { return windows_; }
 
-  // Sets/gets bounds of this workspace.
-  const gfx::Rect& bounds() { return bounds_; }
-  void SetBounds(const gfx::Rect& bounds);
+  // Invoked when the size of the workspace changes.
+  void WorkspaceSizeChanged();
 
-  // Returns the work area bounds of this workspace in viewport
-  // coordinates.
+  // Returns the work area bounds of this workspace in viewport coordinates.
   gfx::Rect GetWorkAreaBounds() const;
 
   // Adds the |window| at the position after the window |after|.  It
@@ -63,35 +80,9 @@ class ASH_EXPORT Workspace {
   // Return true if this workspace has |window|.
   bool Contains(aura::Window* window) const;
 
-  // Returns a window to rotate to based on |position|.
-  aura::Window* FindRotateWindowForLocation(const gfx::Point& position);
-
-  // Rotates the windows by removing |source| and inserting it to the
-  // position that |target| was in. It re-layouts windows except for |source|.
-  void RotateWindows(aura::Window* source, aura::Window* target);
-
-  // Shift the windows in the workspace by inserting |window| until it
-  // reaches |until|. If |direction| is |SHIFT_TO_RIGHT|, |insert| is
-  // inserted at the position of |target| or at the beginning if
-  // |target| is NULL. If |direction| is |SHIFT_TO_LEFT|, |insert| is
-  // inserted after the position of |target|, or at the end if
-  // |target| is NULL.  It returns the window that is overflowed by
-  // shifting, or NULL if shifting stopped at |until|.
-  aura::Window* ShiftWindows(aura::Window* insert,
-                             aura::Window* until,
-                             aura::Window* target,
-                             ShiftDirection direction);
-
   // Activates this workspace.
   void Activate();
 
-  // Layout windows. The workspace doesn't set bounds on
-  // |WorkspaceManager::ignored_window| if it's set. It still uses the window's
-  // bounds to calculate bounds for other windows. Moving animation is
-  // applied to all windows except for the window specified by |no_animation|
-  // and |ignore|.
-  void Layout(aura::Window* no_animation);
-
   // Returns true if the workspace contains a fullscreen window.
   bool ContainsFullscreenWindow() const;
 
@@ -108,24 +99,10 @@ class ASH_EXPORT Workspace {
   // Returns true if the given |window| can be added to this workspace.
   bool CanAdd(aura::Window* window) const;
 
-  // Moves |window| to the given point. It performs animation when
-  // |animate| is true.
-  void MoveWindowTo(aura::Window* window,
-                    const gfx::Point& origin,
-                    bool animate);
-
-  // Returns the sum of all window's width.
-  int GetTotalWindowsWidth() const;
-
-  // Test only: Changes how may windows workspace can have.
-  // Returns the current value so that it can be reverted back to
-  // original value.
-  static size_t SetMaxWindowsCount(size_t max);
+  Type type_;
 
   WorkspaceManager* workspace_manager_;
 
-  gfx::Rect bounds_;
-
   // Windows in the workspace in layout order.
   std::vector<aura::Window*> windows_;
 
diff --git a/ash/wm/workspace/workspace_event_filter.cc b/ash/wm/workspace/workspace_event_filter.cc
index 66aecb491bf3f..0988e2bee61f2 100644
--- a/ash/wm/workspace/workspace_event_filter.cc
+++ b/ash/wm/workspace/workspace_event_filter.cc
@@ -38,6 +38,8 @@ WorkspaceEventFilter::WorkspaceEventFilter(aura::Window* owner)
 }
 
 WorkspaceEventFilter::~WorkspaceEventFilter() {
+  if (hovered_window_)
+    hovered_window_->RemoveObserver(this);
 }
 
 bool WorkspaceEventFilter::PreHandleMouseEvent(aura::Window* target,
@@ -95,6 +97,12 @@ bool WorkspaceEventFilter::PreHandleMouseEvent(aura::Window* target,
   return handled;
 }
 
+void WorkspaceEventFilter::OnWindowDestroyed(aura::Window* window) {
+  DCHECK_EQ(hovered_window_, window);
+  hovered_window_->RemoveObserver(this);
+  hovered_window_ = NULL;
+}
+
 bool WorkspaceEventFilter::UpdateDragState() {
   DCHECK_EQ(DRAG_NONE, drag_state_);
   switch (window_component()) {
@@ -122,9 +130,13 @@ void WorkspaceEventFilter::UpdateHoveredWindow(
     aura::Window* toplevel_window) {
   if (toplevel_window == hovered_window_)
     return;
+  if (hovered_window_)
+    hovered_window_->RemoveObserver(this);
   WindowHoverChanged(hovered_window_, false);
   hovered_window_ = toplevel_window;
   WindowHoverChanged(hovered_window_, true);
+  if (hovered_window_)
+    hovered_window_->AddObserver(this);
 }
 
 }  // namespace internal
diff --git a/ash/wm/workspace/workspace_event_filter.h b/ash/wm/workspace/workspace_event_filter.h
index d6765fa38b54c..6224c1099b5b9 100644
--- a/ash/wm/workspace/workspace_event_filter.h
+++ b/ash/wm/workspace/workspace_event_filter.h
@@ -7,6 +7,7 @@
 #pragma once
 
 #include "ash/wm/toplevel_window_event_filter.h"
+#include "ui/aura/window_observer.h"
 
 namespace aura {
 class MouseEvent;
@@ -16,7 +17,8 @@ class Window;
 namespace ash {
 namespace internal {
 
-class WorkspaceEventFilter : public ToplevelWindowEventFilter {
+class WorkspaceEventFilter : public ToplevelWindowEventFilter,
+                             public aura::WindowObserver {
  public:
   explicit WorkspaceEventFilter(aura::Window* owner);
   virtual ~WorkspaceEventFilter();
@@ -25,6 +27,9 @@ class WorkspaceEventFilter : public ToplevelWindowEventFilter {
   virtual bool PreHandleMouseEvent(aura::Window* target,
                                    aura::MouseEvent* event) OVERRIDE;
 
+  // Overriden from WindowObserver:
+  virtual void OnWindowDestroyed(aura::Window* window) OVERRIDE;
+
  private:
   enum DragState {
     DRAG_NONE,
diff --git a/ash/wm/workspace/workspace_layout_manager.cc b/ash/wm/workspace/workspace_layout_manager.cc
index a4b95d43a23f9..99409e77ec8dc 100644
--- a/ash/wm/workspace/workspace_layout_manager.cc
+++ b/ash/wm/workspace/workspace_layout_manager.cc
@@ -5,7 +5,6 @@
 #include "ash/wm/workspace/workspace_layout_manager.h"
 
 #include "ash/wm/property_util.h"
-#include "ash/wm/show_state_controller.h"
 #include "ash/wm/window_util.h"
 #include "ash/wm/workspace/workspace.h"
 #include "ash/wm/workspace/workspace_manager.h"
@@ -27,8 +26,7 @@ namespace internal {
 
 WorkspaceLayoutManager::WorkspaceLayoutManager(
     WorkspaceManager* workspace_manager)
-    : workspace_manager_(workspace_manager),
-      show_state_controller_(new ShowStateController(workspace_manager)) {
+    : workspace_manager_(workspace_manager) {
 }
 
 WorkspaceLayoutManager::~WorkspaceLayoutManager() {}
@@ -48,43 +46,22 @@ void WorkspaceLayoutManager::CancelMoveOrResize(
 void WorkspaceLayoutManager::ProcessMove(
     aura::Window* drag,
     aura::MouseEvent* event) {
-  // TODO(oshima): Just zooming out may (and will) move/swap window without
-  // a users's intent. We probably should scroll viewport, but that may not
-  // be enough. See crbug.com/101826 for more discussion.
-  workspace_manager_->SetOverview(true);
-
-  gfx::Point point_in_owner = event->location();
-  aura::Window::ConvertPointToWindow(
-      drag,
-      workspace_manager_->contents_view(),
-      &point_in_owner);
-  // TODO(oshima): We should support simply moving to another
-  // workspace when the destination workspace has enough room to accomodate.
-  aura::Window* rotate_target =
-      workspace_manager_->FindRotateWindowForLocation(point_in_owner);
-  if (rotate_target)
-    workspace_manager_->RotateWindows(drag, rotate_target);
+  // TODO: needs implementation for TYPE_SPLIT. For TYPE_SPLIT I want to
+  // disallow eventfilter from moving and instead deal with it here.
 }
 
 void WorkspaceLayoutManager::EndMove(
     aura::Window* drag,
     aura::MouseEvent* evnet) {
-  // TODO(oshima): finish moving window between workspaces.
+  // TODO: see comment in ProcessMove.
   workspace_manager_->set_ignored_window(NULL);
-  Workspace* workspace = workspace_manager_->FindBy(drag);
-  workspace->Layout(NULL);
-  workspace->Activate();
-  workspace_manager_->SetOverview(false);
 }
 
 void WorkspaceLayoutManager::EndResize(
     aura::Window* drag,
     aura::MouseEvent* evnet) {
+  // TODO: see comment in ProcessMove.
   workspace_manager_->set_ignored_window(NULL);
-  Workspace* workspace = workspace_manager_->GetActiveWorkspace();
-  if (workspace)
-    workspace->Layout(NULL);
-  workspace_manager_->SetOverview(false);
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -95,95 +72,41 @@ void WorkspaceLayoutManager::OnWindowResized() {
 }
 
 void WorkspaceLayoutManager::OnWindowAddedToLayout(aura::Window* child) {
-  if (child->type() != aura::client::WINDOW_TYPE_NORMAL ||
-      child->transient_parent()) {
+  if (!workspace_manager_->IsManagedWindow(child))
     return;
-  }
 
-  if (!child->GetProperty(aura::client::kShowStateKey))
-    child->SetIntProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL);
-
-  child->AddObserver(show_state_controller_.get());
-
-  Workspace* workspace = workspace_manager_->GetActiveWorkspace();
-  if (workspace) {
-    aura::Window* active = ash::GetActiveWindow();
-    // Active window may not be in the default container layer.
-    if (!workspace->Contains(active))
-      active = NULL;
-    if (workspace->AddWindowAfter(child, active))
-      return;
-  }
-  // Create new workspace if new |child| doesn't fit to current workspace.
-  Workspace* new_workspace = workspace_manager_->CreateWorkspace();
-  new_workspace->AddWindowAfter(child, NULL);
-  new_workspace->Activate();
+  if (child->IsVisible())
+    workspace_manager_->AddWindow(child);
 }
 
 void WorkspaceLayoutManager::OnWillRemoveWindowFromLayout(
     aura::Window* child) {
-  child->RemoveObserver(show_state_controller_.get());
   ClearRestoreBounds(child);
-
-  Workspace* workspace = workspace_manager_->FindBy(child);
-  if (!workspace)
-    return;
-  workspace->RemoveWindow(child);
-  if (workspace->is_empty())
-    delete workspace;
+  workspace_manager_->RemoveWindow(child);
 }
 
 void WorkspaceLayoutManager::OnChildWindowVisibilityChanged(
     aura::Window* child,
     bool visible) {
-  NOTIMPLEMENTED();
+  if (!workspace_manager_->IsManagedWindow(child))
+    return;
+  if (visible)
+    workspace_manager_->AddWindow(child);
+  else
+    workspace_manager_->RemoveWindow(child);
 }
 
 void WorkspaceLayoutManager::SetChildBounds(
     aura::Window* child,
     const gfx::Rect& requested_bounds) {
-  gfx::Rect adjusted_bounds = requested_bounds;
-
-  // First, calculate the adjusted bounds.
-  if (child->type() != aura::client::WINDOW_TYPE_NORMAL ||
-      workspace_manager_->layout_in_progress() ||
-      child->transient_parent()) {
-    // Use the requested bounds as is.
-  } else if (child == workspace_manager_->ignored_window()) {
-    // If a drag window is requesting bounds, make sure its attached to
-    // the workarea's top and fits within the total drag area.
-    gfx::Rect drag_area =  workspace_manager_->GetDragAreaBounds();
-    adjusted_bounds.set_y(drag_area.y());
-    adjusted_bounds = adjusted_bounds.AdjustToFit(drag_area);
-  } else {
-    Workspace* workspace = workspace_manager_->FindBy(child);
-    gfx::Rect work_area = workspace->GetWorkAreaBounds();
-    adjusted_bounds.set_origin(
-        gfx::Point(child->GetTargetBounds().x(), work_area.y()));
-    adjusted_bounds = adjusted_bounds.AdjustToFit(work_area);
+  // Allow setting the bounds for any window we don't care about, isn't visible,
+  // or we're setting the bounds of. All other request are dropped on the floor.
+  if (child == workspace_manager_->ignored_window() ||
+      !workspace_manager_->IsManagedWindow(child) || !child->IsVisible() ||
+      (!window_util::IsWindowMaximized(child) &&
+       !window_util::IsWindowFullscreen(child))) {
+    SetChildBoundsDirect(child, requested_bounds);
   }
-
-  ui::WindowShowState show_state = static_cast<ui::WindowShowState>(
-      child->GetIntProperty(aura::client::kShowStateKey));
-
-  // Second, check if the window is either maximized or in fullscreen mode.
-  if (show_state == ui::SHOW_STATE_MAXIMIZED ||
-      show_state == ui::SHOW_STATE_FULLSCREEN) {
-    // If the request is not from workspace manager,
-    // remember the requested bounds.
-    if (!workspace_manager_->layout_in_progress())
-      SetRestoreBounds(child, adjusted_bounds);
-
-    Workspace* workspace = workspace_manager_->FindBy(child);
-    if (show_state == ui::SHOW_STATE_MAXIMIZED)
-      adjusted_bounds = workspace->GetWorkAreaBounds();
-    else
-      adjusted_bounds = workspace->bounds();
-    // Don't
-    if (child->GetTargetBounds() == adjusted_bounds)
-      return;
-  }
-  SetChildBoundsDirect(child, adjusted_bounds);
 }
 
 }  // namespace internal
diff --git a/ash/wm/workspace/workspace_layout_manager.h b/ash/wm/workspace/workspace_layout_manager.h
index 3fdceb8151ad6..4a1ca87929e61 100644
--- a/ash/wm/workspace/workspace_layout_manager.h
+++ b/ash/wm/workspace/workspace_layout_manager.h
@@ -6,11 +6,10 @@
 #define ASH_WM_WORKSPACE_WORKSPACE_LAYOUT_MANAGER_H_
 #pragma once
 
+#include "ash/ash_export.h"
 #include "base/basictypes.h"
 #include "base/compiler_specific.h"
-#include "base/memory/scoped_ptr.h"
 #include "ui/aura/layout_manager.h"
-#include "ash/ash_export.h"
 
 namespace aura {
 class MouseEvent;
@@ -24,10 +23,9 @@ class Rect;
 namespace ash {
 namespace internal {
 
-class ShowStateController;
 class WorkspaceManager;
 
-// LayoutManager for the default window container.
+// LayoutManager for top level windows when WorkspaceManager is enabled.
 class ASH_EXPORT WorkspaceLayoutManager : public aura::LayoutManager {
  public:
   explicit WorkspaceLayoutManager(WorkspaceManager* workspace_manager);
@@ -61,12 +59,11 @@ class ASH_EXPORT WorkspaceLayoutManager : public aura::LayoutManager {
                                               bool visibile) OVERRIDE;
   virtual void SetChildBounds(aura::Window* child,
                               const gfx::Rect& requested_bounds) OVERRIDE;
+
  private:
   // Owned by WorkspaceController.
   WorkspaceManager* workspace_manager_;
 
-  scoped_ptr<ShowStateController> show_state_controller_;
-
   DISALLOW_COPY_AND_ASSIGN(WorkspaceLayoutManager);
 };
 
diff --git a/ash/wm/workspace/workspace_layout_manager_unittest.cc b/ash/wm/workspace/workspace_layout_manager_unittest.cc
deleted file mode 100644
index ac2504e550f67..0000000000000
--- a/ash/wm/workspace/workspace_layout_manager_unittest.cc
+++ /dev/null
@@ -1,341 +0,0 @@
-// 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 "ash/wm/workspace/workspace_layout_manager.h"
-
-#include "ash/wm/workspace/workspace.h"
-#include "ash/wm/workspace/workspace_manager.h"
-#include "ash/wm/workspace_controller.h"
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
-#include "base/memory/scoped_vector.h"
-#include "ui/aura/client/aura_constants.h"
-#include "ui/aura/root_window.h"
-#include "ui/aura/screen_aura.h"
-#include "ui/aura/test/aura_test_base.h"
-#include "ui/aura/window.h"
-#include "ui/base/ui_base_types.h"
-#include "ui/views/widget/native_widget_aura.h"
-
-namespace ash {
-namespace test {
-
-namespace {
-
-using views::Widget;
-using ash::internal::WorkspaceLayoutManager;
-
-class WorkspaceLayoutManagerTest : public aura::test::AuraTestBase {
- public:
-  WorkspaceLayoutManagerTest() : layout_manager_(NULL) {}
-  virtual ~WorkspaceLayoutManagerTest() {}
-
-  virtual void SetUp() OVERRIDE {
-    aura::test::AuraTestBase::SetUp();
-    aura::RootWindow* root_window = aura::RootWindow::GetInstance();
-    container_.reset(
-        CreateTestWindow(gfx::Rect(0, 0, 500, 400), root_window));
-    workspace_controller_.reset(
-        new ash::internal::WorkspaceController(container_.get()));
-    layout_manager_ = new WorkspaceLayoutManager(
-        workspace_controller_->workspace_manager());
-    container_->SetLayoutManager(layout_manager_);
-
-    root_window->SetHostSize(gfx::Size(500, 400));
-  }
-
-  aura::Window* CreateTestWindowWithType(const gfx::Rect& bounds,
-                                         aura::Window* parent,
-                                         aura::client::WindowType type) {
-    aura::Window* window = new aura::Window(NULL);
-    window->SetType(type);
-    window->Init(ui::Layer::LAYER_HAS_NO_TEXTURE);
-    window->SetBounds(bounds);
-    window->Show();
-    window->SetParent(parent);
-    return window;
-  }
-
-  aura::Window* CreateTestWindow(const gfx::Rect& bounds,
-                                 aura::Window* parent) {
-    return CreateTestWindowWithType(bounds,
-                                    parent,
-                                    aura::client::WINDOW_TYPE_NORMAL);
-  }
-
-  aura::Window* container() { return container_.get(); }
-
-  WorkspaceLayoutManager* default_container_layout_manager() {
-    return layout_manager_;
-  }
-
- protected:
-  ash::internal::WorkspaceManager* workspace_manager() {
-    return workspace_controller_->workspace_manager();
-  }
-
- private:
-  scoped_ptr<aura::Window> container_;
-  scoped_ptr<ash::internal::WorkspaceController> workspace_controller_;
-  // LayoutManager is owned by |container|.
-  ash::internal::WorkspaceLayoutManager* layout_manager_;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(WorkspaceLayoutManagerTest);
-};
-
-// Utility functions to set and get show state on |window|.
-void Maximize(aura::Window* window) {
-  window->SetIntProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MAXIMIZED);
-}
-
-void Fullscreen(aura::Window* window) {
-  window->SetIntProperty(aura::client::kShowStateKey,
-                         ui::SHOW_STATE_FULLSCREEN);
-}
-
-void Restore(aura::Window* window) {
-  window->SetIntProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL);
-}
-
-ui::WindowShowState GetShowState(aura::Window* window) {
-  return static_cast<ui::WindowShowState>(
-      window->GetIntProperty(aura::client::kShowStateKey));
-}
-
-}  // namespace
-
-TEST_F(WorkspaceLayoutManagerTest, SetBounds) {
-  // Layout Manager moves the window to (0,0) to fit to draggable area.
-  scoped_ptr<aura::Window> child(
-      CreateTestWindow(gfx::Rect(0, -1000, 100, 100), container()));
-  // Window is centered in workspace.
-  EXPECT_EQ("200,0 100x100", child->bounds().ToString());
-
-  // DCLM enforces the window height can't be taller than its owner's height.
-  child->SetBounds(gfx::Rect(0, 0, 100, 500));
-  EXPECT_EQ("200,0 100x400", child->bounds().ToString());
-
-  // DCLM enforces the window width can't be wider than its owner's width.
-  child->SetBounds(gfx::Rect(0, 0, 900, 500));
-  EXPECT_EQ("0,0 500x400", child->bounds().ToString());
-
-  // Y origin must always be the top of drag area.
-  child->SetBounds(gfx::Rect(0, 500, 900, 500));
-  EXPECT_EQ("0,0 500x400", child->bounds().ToString());
-  child->SetBounds(gfx::Rect(0, -500, 900, 500));
-  EXPECT_EQ("0,0 500x400", child->bounds().ToString());
-}
-
-TEST_F(WorkspaceLayoutManagerTest, DragWindow) {
-  scoped_ptr<aura::Window> child(
-      CreateTestWindow(gfx::Rect(0, -1000, 50, 50), container()));
-  gfx::Rect original_bounds = child->bounds();
-
-  default_container_layout_manager()->PrepareForMoveOrResize(
-      child.get(), NULL);
-  // X origin must fit within viewport.
-  child->SetBounds(gfx::Rect(-100, 500, 50, 50));
-  EXPECT_EQ("0,0 50x50", child->GetTargetBounds().ToString());
-  child->SetBounds(gfx::Rect(1000, 500, 50, 50));
-  EXPECT_EQ("450,0 50x50", child->GetTargetBounds().ToString());
-  default_container_layout_manager()->EndMove(child.get(), NULL);
-  EXPECT_EQ(original_bounds.ToString(), child->GetTargetBounds().ToString());
-}
-
-TEST_F(WorkspaceLayoutManagerTest, Popup) {
-  scoped_ptr<aura::Window> popup(
-      CreateTestWindowWithType(gfx::Rect(0, -1000, 100, 100),
-                               container(),
-                               aura::client::WINDOW_TYPE_POPUP));
-  // A popup window can be placed outside of draggable area.
-  EXPECT_EQ("0,-1000 100x100", popup->bounds().ToString());
-
-  // A popup window can be moved to outside of draggable area.
-  popup->SetBounds(gfx::Rect(-100, 0, 100, 100));
-  EXPECT_EQ("-100,0 100x100", popup->bounds().ToString());
-
-  // A popup window can be resized to the size bigger than draggable area.
-  popup->SetBounds(gfx::Rect(0, 0, 1000, 1000));
-  EXPECT_EQ("0,0 1000x1000", popup->bounds().ToString());
-}
-
-// Make sure a window with a transient parent isn't resized by the layout
-// manager.
-TEST_F(WorkspaceLayoutManagerTest, IgnoreTransient) {
-  scoped_ptr<aura::Window> window(new aura::Window(NULL));
-  window->SetType(aura::client::WINDOW_TYPE_NORMAL);
-  window->Init(ui::Layer::LAYER_HAS_NO_TEXTURE);
-  aura::RootWindow::GetInstance()->AddTransientChild(window.get());
-  window->SetBounds(gfx::Rect(0, 0, 200, 200));
-  window->Show();
-  window->SetParent(container());
-
-  EXPECT_EQ("0,0 200x200", window->bounds().ToString());
-}
-
-TEST_F(WorkspaceLayoutManagerTest, Fullscreen) {
-  scoped_ptr<aura::Window> w(
-      CreateTestWindow(gfx::Rect(0, 0, 100, 100), container()));
-  gfx::Rect fullscreen_bounds =
-      workspace_manager()->FindBy(w.get())->bounds();
-  gfx::Rect original_bounds = w->GetTargetBounds();
-
-  // Restoreing the restored window.
-  Restore(w.get());
-  EXPECT_EQ(ui::SHOW_STATE_NORMAL, GetShowState(w.get()));
-  EXPECT_EQ(original_bounds.ToString(), w->bounds().ToString());
-
-  // Fullscreen
-  Fullscreen(w.get());
-  EXPECT_EQ(ui::SHOW_STATE_FULLSCREEN, GetShowState(w.get()));
-  EXPECT_EQ(fullscreen_bounds.ToString(), w->bounds().ToString());
-  w->SetIntProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL);
-  EXPECT_EQ(ui::SHOW_STATE_NORMAL, GetShowState(w.get()));
-  EXPECT_EQ(original_bounds.ToString(), w->bounds().ToString());
-
-  Fullscreen(w.get());
-  // Setting |ui::SHOW_STATE_FULLSCREEN| should have no additional effect.
-  Fullscreen(w.get());
-  EXPECT_EQ(fullscreen_bounds, w->bounds());
-  Restore(w.get());
-  EXPECT_EQ(ui::SHOW_STATE_NORMAL, GetShowState(w.get()));
-  EXPECT_EQ(original_bounds.ToString(), w->bounds().ToString());
-
-  // Calling SetBounds() in fullscreen mode should only update the
-  // restore bounds not change the bounds of the window.
-  gfx::Rect new_bounds(50, 50, 50, 50);
-  Fullscreen(w.get());
-  w->SetBounds(new_bounds);
-  EXPECT_EQ(fullscreen_bounds.ToString(), w->bounds().ToString());
-  EXPECT_EQ(ui::SHOW_STATE_FULLSCREEN, GetShowState(w.get()));
-  Restore(w.get());
-  EXPECT_EQ(ui::SHOW_STATE_NORMAL, GetShowState(w.get()));
-  EXPECT_EQ(50, w->bounds().height());
-}
-
-TEST_F(WorkspaceLayoutManagerTest, Maximized) {
-  scoped_ptr<aura::Window> w(
-      CreateTestWindow(gfx::Rect(0, 0, 100, 100), container()));
-  gfx::Rect original_bounds = w->GetTargetBounds();
-  gfx::Rect fullscreen_bounds =
-      workspace_manager()->FindBy(w.get())->bounds();
-  gfx::Rect work_area_bounds =
-      workspace_manager()->FindBy(w.get())->GetWorkAreaBounds();
-
-  // Maximized
-  Maximize(w.get());
-  EXPECT_EQ(ui::SHOW_STATE_MAXIMIZED, GetShowState(w.get()));
-  EXPECT_EQ(work_area_bounds.ToString(), w->bounds().ToString());
-  Restore(w.get());
-  EXPECT_EQ(ui::SHOW_STATE_NORMAL, GetShowState(w.get()));
-  EXPECT_EQ(original_bounds.ToString(), w->bounds().ToString());
-
-  // Maximize twice
-  Maximize(w.get());
-  Maximize(w.get());
-  EXPECT_EQ(ui::SHOW_STATE_MAXIMIZED, GetShowState(w.get()));
-  EXPECT_EQ(work_area_bounds.ToString(), w->bounds().ToString());
-  Restore(w.get());
-  EXPECT_EQ(ui::SHOW_STATE_NORMAL, GetShowState(w.get()));
-  EXPECT_EQ(original_bounds.ToString(), w->bounds().ToString());
-
-  // Maximized -> Fullscreen -> Maximized -> Normal
-  Maximize(w.get());
-  EXPECT_EQ(ui::SHOW_STATE_MAXIMIZED, GetShowState(w.get()));
-  EXPECT_EQ(work_area_bounds.ToString(), w->bounds().ToString());
-  Fullscreen(w.get());
-  EXPECT_EQ(ui::SHOW_STATE_FULLSCREEN, GetShowState(w.get()));
-  EXPECT_EQ(fullscreen_bounds.ToString(), w->bounds().ToString());
-  Maximize(w.get());
-  EXPECT_EQ(ui::SHOW_STATE_MAXIMIZED, GetShowState(w.get()));
-  EXPECT_EQ(work_area_bounds.ToString(), w->bounds().ToString());
-  Restore(w.get());
-  EXPECT_EQ(ui::SHOW_STATE_NORMAL, GetShowState(w.get()));
-  EXPECT_EQ(original_bounds.ToString(), w->bounds().ToString());
-
-  // Calling SetBounds() in maximized mode mode should only update the
-  // restore bounds not change the bounds of the window.
-  gfx::Rect new_bounds(50, 50, 50, 50);
-  Maximize(w.get());
-  w->SetBounds(new_bounds);
-  EXPECT_EQ(work_area_bounds.ToString(), w->bounds().ToString());
-  Restore(w.get());
-  EXPECT_EQ(ui::SHOW_STATE_NORMAL, GetShowState(w.get()));
-  EXPECT_EQ(50, w->bounds().height());
-}
-
-// Tests that fullscreen windows get resized after root window is resized.
-TEST_F(WorkspaceLayoutManagerTest, FullscreenAfterRootWindowResize) {
-  scoped_ptr<aura::Window> w1(CreateTestWindow(gfx::Rect(300, 400),
-                                               container()));
-  gfx::Rect window_bounds = w1->GetTargetBounds();
-  gfx::Rect fullscreen_bounds =
-      workspace_manager()->FindBy(w1.get())->bounds();
-
-  w1->Show();
-  EXPECT_EQ(window_bounds.ToString(), w1->bounds().ToString());
-
-  Fullscreen(w1.get());
-  EXPECT_EQ(fullscreen_bounds.ToString(), w1->bounds().ToString());
-
-  // Resize the root window.
-  aura::RootWindow* root_window = aura::RootWindow::GetInstance();
-  gfx::Size new_root_window_size = root_window->GetHostSize();
-  new_root_window_size.Enlarge(100, 200);
-  root_window->OnHostResized(new_root_window_size);
-
-  gfx::Rect new_fullscreen_bounds =
-      workspace_manager()->FindBy(w1.get())->bounds();
-  EXPECT_NE(fullscreen_bounds.size().ToString(),
-            new_fullscreen_bounds.size().ToString());
-
-  EXPECT_EQ(new_fullscreen_bounds.ToString(),
-            w1->GetTargetBounds().ToString());
-
-  Restore(w1.get());
-
-  // The following test does not pass due to crbug.com/102413.
-  // TODO(oshima): Re-enable this once the bug is fixed.
-  // EXPECT_EQ(window_bounds.size().ToString(),
-  //           w1->GetTargetBounds().size().ToString());
-}
-
-// Tests that maximized windows get resized after root_window is resized.
-TEST_F(WorkspaceLayoutManagerTest, MaximizeAfterRootWindowResize) {
-  scoped_ptr<aura::Window> w1(CreateTestWindow(gfx::Rect(300, 400),
-                                               container()));
-  gfx::Rect window_bounds = w1->GetTargetBounds();
-  gfx::Rect work_area_bounds =
-      workspace_manager()->FindBy(w1.get())->GetWorkAreaBounds();
-
-  w1->Show();
-  EXPECT_EQ(window_bounds.ToString(), w1->bounds().ToString());
-
-  Maximize(w1.get());
-  EXPECT_EQ(work_area_bounds.ToString(), w1->bounds().ToString());
-
-  // Resize the root window.
-  aura::RootWindow* root_window = aura::RootWindow::GetInstance();
-  gfx::Size new_root_window_size = root_window->GetHostSize();
-  new_root_window_size.Enlarge(100, 200);
-  root_window->OnHostResized(new_root_window_size);
-
-  gfx::Rect new_work_area_bounds =
-      workspace_manager()->FindBy(w1.get())->bounds();
-  EXPECT_NE(work_area_bounds.size().ToString(),
-            new_work_area_bounds.size().ToString());
-
-  EXPECT_EQ(new_work_area_bounds.ToString(),
-            w1->GetTargetBounds().ToString());
-
-  Restore(w1.get());
-  // The following test does not pass due to crbug.com/102413.
-  // TODO(oshima): Re-enable this once the bug is fixed.
-  // EXPECT_EQ(window_bounds.size().ToString(),
-  //           w1->GetTargetBounds().size().ToString());
-}
-
-}  // namespace test
-}  // namespace ash
diff --git a/ash/wm/workspace/workspace_manager.cc b/ash/wm/workspace/workspace_manager.cc
index a9884b3bf677c..9fc41e9d0a262 100644
--- a/ash/wm/workspace/workspace_manager.cc
+++ b/ash/wm/workspace/workspace_manager.cc
@@ -6,14 +6,17 @@
 
 #include <algorithm>
 
+#include "ash/wm/property_util.h"
+#include "ash/wm/window_util.h"
 #include "ash/wm/workspace/workspace.h"
-#include "ash/wm/workspace/workspace_observer.h"
 #include "base/auto_reset.h"
 #include "base/logging.h"
 #include "base/stl_util.h"
+#include "ui/aura/client/aura_constants.h"
 #include "ui/aura/root_window.h"
 #include "ui/aura/screen_aura.h"
 #include "ui/aura/window.h"
+#include "ui/base/ui_base_types.h"
 #include "ui/gfx/compositor/layer.h"
 #include "ui/gfx/compositor/layer_animator.h"
 #include "ui/gfx/compositor/scoped_layer_animation_settings.h"
@@ -29,6 +32,20 @@ const int kWorkspaceHorizontalMargin = 50;
 const float kMaxOverviewScale = 0.9f;
 const float kMinOverviewScale = 0.3f;
 
+// Sets the visibility of the layer of each window in |windows| to |value|. We
+// set the visibility of the layer rather than the Window so that views doesn't
+// see the visibility change.
+// TODO: revisit this. Ideally the Window would think it's still visibile after
+// this. May be possible after Ben lands his changes.
+void SetWindowLayerVisibility(const std::vector<aura::Window*>& windows,
+                              bool value) {
+  for (size_t i = 0; i < windows.size(); ++i){
+    if (windows[i]->layer())
+      windows[i]->layer()->SetVisible(value);
+    SetWindowLayerVisibility(windows[i]->transient_children(), value);
+  }
+}
+
 }
 
 namespace ash {
@@ -43,20 +60,173 @@ WorkspaceManager::WorkspaceManager(aura::Window* contents_view)
       workspace_size_(
           gfx::Screen::GetMonitorAreaNearestWindow(contents_view_).size()),
       is_overview_(false),
-      layout_in_progress_(false),
       ignored_window_(NULL) {
   DCHECK(contents_view);
 }
 
 WorkspaceManager::~WorkspaceManager() {
+  for (size_t i = 0; i < workspaces_.size(); ++i) {
+    Workspace* workspace = workspaces_[i];
+    for (size_t j = 0; j < workspace->windows().size(); ++j)
+      workspace->windows()[j]->RemoveObserver(this);
+  }
   std::vector<Workspace*> copy_to_delete(workspaces_);
   STLDeleteElements(&copy_to_delete);
 }
 
-Workspace* WorkspaceManager::CreateWorkspace() {
-  Workspace* workspace = new Workspace(this);
-  LayoutWorkspaces();
-  return workspace;
+bool WorkspaceManager::IsManagedWindow(aura::Window* window) const {
+  return window->type() == aura::client::WINDOW_TYPE_NORMAL &&
+         !window->transient_parent();
+}
+
+void WorkspaceManager::AddWindow(aura::Window* window) {
+  DCHECK(IsManagedWindow(window));
+
+  if (FindBy(window))
+    return;  // Already know about this window.
+
+  window->AddObserver(this);
+
+  if (!window->GetProperty(aura::client::kShowStateKey)) {
+    // TODO: set maximized if width < x.
+    window->SetIntProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL);
+  }
+
+  // TODO: handle fullscreen.
+  if (window_util::IsWindowMaximized(window)) {
+    if (!GetRestoreBounds(window))
+      SetRestoreBounds(window, window->GetTargetBounds());
+    else
+      SetWindowBounds(window, GetWorkAreaBounds());
+  }
+
+  Workspace* workspace = NULL;
+  Workspace::Type type_for_window = Workspace::TypeForWindow(window);
+  switch (type_for_window) {
+    case Workspace::TYPE_SPLIT:
+      // Splits either go in current workspace (if maximized or split). If the
+      // current workspace isn't split/maximized, then create a maximized
+      // workspace.
+      workspace = GetActiveWorkspace();
+      if (workspace &&
+          (workspace->type() == Workspace::TYPE_SPLIT ||
+           workspace->type() == Workspace::TYPE_MAXIMIZED)) {
+        // TODO: this needs to reset bounds of any existing windows in
+        // workspace.
+        workspace->SetType(Workspace::TYPE_SPLIT);
+      } else {
+        type_for_window = Workspace::TYPE_MAXIMIZED;
+        workspace = NULL;
+      }
+      break;
+
+    case Workspace::TYPE_NORMAL:
+      // All normal windows go in the same workspace.
+      workspace = GetNormalWorkspace();
+      break;
+
+    case Workspace::TYPE_MAXIMIZED:
+      // All maximized windows go in their own workspace.
+      break;
+
+    default:
+      NOTREACHED();
+      break;
+  }
+
+  if (!workspace) {
+    workspace = new Workspace(this);
+    workspace->SetType(type_for_window);
+  }
+  workspace->AddWindowAfter(window, NULL);
+  workspace->Activate();
+}
+
+void WorkspaceManager::RemoveWindow(aura::Window* window) {
+  Workspace* workspace = FindBy(window);
+  if (!workspace)
+    return;
+  window->RemoveObserver(this);
+  workspace->RemoveWindow(window);
+  if (workspace->is_empty())
+    delete workspace;
+}
+
+void WorkspaceManager::SetActiveWorkspaceByWindow(aura::Window* window) {
+  Workspace* workspace = FindBy(window);
+  if (workspace)
+    workspace->Activate();
+}
+
+gfx::Rect WorkspaceManager::GetDragAreaBounds() {
+  return GetWorkAreaBounds();
+}
+
+void WorkspaceManager::SetOverview(bool overview) {
+  if (is_overview_ == overview)
+    return;
+  NOTIMPLEMENTED();
+}
+
+void WorkspaceManager::SetWorkspaceSize(const gfx::Size& workspace_size) {
+  if (workspace_size == workspace_size_)
+    return;
+  workspace_size_ = workspace_size;
+  for (Workspaces::const_iterator i = workspaces_.begin();
+       i != workspaces_.end(); ++i) {
+    (*i)->WorkspaceSizeChanged();
+  }
+}
+
+void WorkspaceManager::OnWindowPropertyChanged(aura::Window* window,
+                                               const char* name,
+                                               void* old) {
+  if (!IsManagedWindow(window))
+    return;
+
+  if (name != aura::client::kShowStateKey)
+    return;
+  // TODO: handle fullscreen.
+  bool is_maximized = window->GetIntProperty(name) == ui::SHOW_STATE_MAXIMIZED;
+  bool was_maximized =
+      (old == reinterpret_cast<void*>(ui::SHOW_STATE_MAXIMIZED));
+  if (is_maximized == was_maximized)
+    return;
+
+  MaximizedStateChanged(window);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// WorkspaceManager, private:
+
+void WorkspaceManager::AddWorkspace(Workspace* workspace) {
+  DCHECK(std::find(workspaces_.begin(), workspaces_.end(),
+                   workspace) == workspaces_.end());
+  if (active_workspace_) {
+    // New workspaces go right after current workspace.
+    Workspaces::iterator i = std::find(workspaces_.begin(), workspaces_.end(),
+                                       active_workspace_);
+    workspaces_.insert(++i, workspace);
+  } else {
+    workspaces_.push_back(workspace);
+  }
+}
+
+void WorkspaceManager::RemoveWorkspace(Workspace* workspace) {
+  Workspaces::iterator i = std::find(workspaces_.begin(),
+                                     workspaces_.end(),
+                                     workspace);
+  DCHECK(i != workspaces_.end());
+  i = workspaces_.erase(i);
+  if (active_workspace_ == workspace) {
+    // TODO: need mru order.
+    if (i != workspaces_.end())
+      SetActiveWorkspace(*i);
+    else if (!workspaces_.empty())
+      SetActiveWorkspace(workspaces_.back());
+    else
+      active_workspace_ = NULL;
+  }
 }
 
 Workspace* WorkspaceManager::GetActiveWorkspace() const {
@@ -68,176 +238,22 @@ Workspace* WorkspaceManager::FindBy(aura::Window* window) const {
   return index < 0 ? NULL : workspaces_[index];
 }
 
-aura::Window* WorkspaceManager::FindRotateWindowForLocation(
-    const gfx::Point& point) {
-  for (Workspaces::const_iterator i = workspaces_.begin();
-       i != workspaces_.end();
-       ++i) {
-    aura::Window* window = (*i)->FindRotateWindowForLocation(point);
-    if (window)
-      return window;
-  }
-  return NULL;
-}
-
-void WorkspaceManager::LayoutWorkspaces() {
-  UpdateContentsView();
-
-  gfx::Rect bounds(workspace_size_);
-  int x = 0;
-  for (Workspaces::const_iterator i = workspaces_.begin();
-       i != workspaces_.end();
-       ++i) {
-    Workspace* workspace = *i;
-    bounds.set_x(x);
-    workspace->SetBounds(bounds);
-    x += bounds.width() + kWorkspaceHorizontalMargin;
-  }
-}
-
-gfx::Rect WorkspaceManager::GetDragAreaBounds() {
-  return GetWorkAreaBounds(gfx::Rect(contents_view_->bounds().size()));
-}
-
-void WorkspaceManager::SetOverview(bool overview) {
-  if (is_overview_ == overview)
-    return;
-  is_overview_ = overview;
-
-  ui::Transform transform;
-  if (is_overview_) {
-    // TODO(oshima|sky): We limit the how small windows can be shrinked
-    // in overview mode, thus part of the contents_view may not be visible.
-    // We need to add capability to scroll/move contents_view in overview mode.
-    float scale = std::min(
-        kMaxOverviewScale,
-        workspace_size_.width() /
-        static_cast<float>(contents_view_->bounds().width()));
-    scale = std::max(kMinOverviewScale, scale);
-
-    transform.SetScale(scale, scale);
-
-    int overview_width = contents_view_->bounds().width() * scale;
-    int dx = 0;
-    if (overview_width < workspace_size_.width()) {
-      dx = (workspace_size_.width() - overview_width) / 2;
-    } else if (active_workspace_) {
-      // Center the active workspace.
-      int active_workspace_mid_x = (active_workspace_->bounds().x() +
-          active_workspace_->bounds().width() / 2) * scale;
-      dx = workspace_size_.width() / 2 - active_workspace_mid_x;
-      dx = std::min(0, std::max(dx, workspace_size_.width() - overview_width));
-    }
-
-    transform.SetTranslateX(dx);
-    transform.SetTranslateY(workspace_size_.height() *  (1.0f - scale) / 2);
-  } else if (active_workspace_) {
-    transform.SetTranslateX(-active_workspace_->bounds().x());
-  }
-
-  ui::ScopedLayerAnimationSettings settings(
-      contents_view_->layer()->GetAnimator());
-  contents_view_->layer()->SetTransform(transform);
-}
-
-void WorkspaceManager::RotateWindows(aura::Window* source,
-                                     aura::Window* target) {
-  DCHECK(source);
-  DCHECK(target);
-  int source_ws_index = GetWorkspaceIndexContaining(source);
-  int target_ws_index = GetWorkspaceIndexContaining(target);
-  DCHECK(source_ws_index >= 0);
-  DCHECK(target_ws_index >= 0);
-  if (source_ws_index == target_ws_index) {
-    workspaces_[source_ws_index]->RotateWindows(source, target);
-  } else {
-    aura::Window* insert = source;
-    aura::Window* target_to_insert = target;
-    if (source_ws_index < target_ws_index) {
-      for (int i = target_ws_index; i >= source_ws_index; --i) {
-        insert = workspaces_[i]->ShiftWindows(
-            insert, source, target_to_insert, Workspace::SHIFT_TO_LEFT);
-        // |target| can only be in the 1st workspace.
-        target_to_insert = NULL;
-      }
-    } else {
-      for (int i = target_ws_index; i <= source_ws_index; ++i) {
-        insert = workspaces_[i]->ShiftWindows(
-            insert, source, target_to_insert, Workspace::SHIFT_TO_RIGHT);
-        // |target| can only be in the 1st workspace.
-        target_to_insert = NULL;
-      }
-    }
-  }
-  FOR_EACH_OBSERVER(WorkspaceObserver, observers_,
-                    WindowMoved(this, source, target));
-  workspaces_[target_ws_index]->Activate();
-}
-
-void WorkspaceManager::SetWorkspaceSize(const gfx::Size& workspace_size) {
-  if (workspace_size == workspace_size_)
-    return;
-  workspace_size_ = workspace_size;
-  LayoutWorkspaces();
-}
-
-void WorkspaceManager::AddObserver(WorkspaceObserver* observer) {
-  observers_.AddObserver(observer);
-}
-
-void WorkspaceManager::RemoveObserver(WorkspaceObserver* observer) {
-  observers_.RemoveObserver(observer);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// WorkspaceManager, private:
-
-void WorkspaceManager::AddWorkspace(Workspace* workspace) {
-  Workspaces::iterator i = std::find(workspaces_.begin(),
-                                     workspaces_.end(),
-                                     workspace);
-  DCHECK(i == workspaces_.end());
-  workspaces_.push_back(workspace);
-}
-
-void WorkspaceManager::RemoveWorkspace(Workspace* workspace) {
-  Workspaces::iterator i = std::find(workspaces_.begin(),
-                                     workspaces_.end(),
-                                     workspace);
-  DCHECK(i != workspaces_.end());
-  Workspace* old = NULL;
-
-  if (workspace == active_workspace_) {
-    old = active_workspace_;
-    active_workspace_ = NULL;
-  }
-  workspaces_.erase(i);
-  LayoutWorkspaces();
-
-  if (old) {
-    FOR_EACH_OBSERVER(WorkspaceObserver, observers_,
-                      ActiveWorkspaceChanged(this, old));
-  }
-}
-
 void WorkspaceManager::SetActiveWorkspace(Workspace* workspace) {
   if (active_workspace_ == workspace)
     return;
   DCHECK(std::find(workspaces_.begin(), workspaces_.end(),
                    workspace) != workspaces_.end());
-  Workspace* old = active_workspace_;
+  if (active_workspace_)
+    SetWindowLayerVisibility(active_workspace_->windows(), false);
   active_workspace_ = workspace;
+  if (active_workspace_)
+    SetWindowLayerVisibility(active_workspace_->windows(), true);
 
   is_overview_ = false;
-  UpdateContentsView();
-
-  FOR_EACH_OBSERVER(WorkspaceObserver, observers_,
-                    ActiveWorkspaceChanged(this, old));
 }
 
-gfx::Rect WorkspaceManager::GetWorkAreaBounds(
-    const gfx::Rect& workspace_bounds) {
-  gfx::Rect bounds = workspace_bounds;
+gfx::Rect WorkspaceManager::GetWorkAreaBounds() {
+  gfx::Rect bounds(workspace_size_);
   bounds.Inset(
       aura::RootWindow::GetInstance()->screen()->work_area_insets());
   return bounds;
@@ -254,23 +270,75 @@ int WorkspaceManager::GetWorkspaceIndexContaining(aura::Window* window) const {
   return -1;
 }
 
-void WorkspaceManager::UpdateContentsView() {
-  int num_workspaces = std::max(1, static_cast<int>(workspaces_.size()));
-  int total_width = workspace_size_.width() * num_workspaces +
-      kWorkspaceHorizontalMargin * (num_workspaces - 1);
-  gfx::Rect bounds(0, 0, total_width, workspace_size_.height());
+void WorkspaceManager::SetWindowBounds(aura::Window* window,
+                                       const gfx::Rect& bounds) {
+  // TODO: I suspect it's possible for this to be invoked when ignored_window_
+  // is non-NULL.
+  ignored_window_ = window;
+  window->SetBounds(bounds);
+  ignored_window_ = NULL;
+}
 
-  if (contents_view_->GetTargetBounds() != bounds)
-    contents_view_->SetBounds(bounds);
-
-  // Move to active workspace.
-  if (active_workspace_) {
-    ui::Transform transform;
-    transform.SetTranslateX(-active_workspace_->bounds().x());
-    ui::ScopedLayerAnimationSettings settings(
-        contents_view_->layer()->GetAnimator());
-    contents_view_->SetTransform(transform);
+void WorkspaceManager::SetWindowBoundsFromRestoreBounds(aura::Window* window) {
+  Workspace* workspace = FindBy(window);
+  DCHECK(workspace);
+  const gfx::Rect* restore = GetRestoreBounds(window);
+  if (restore) {
+    SetWindowBounds(window,
+                    restore->AdjustToFit(workspace->GetWorkAreaBounds()));
+  } else {
+    SetWindowBounds(window, window->bounds().AdjustToFit(
+                        workspace->GetWorkAreaBounds()));
   }
+  ash::ClearRestoreBounds(window);
+}
+
+void WorkspaceManager::MaximizedStateChanged(aura::Window* window) {
+  DCHECK(IsManagedWindow(window));
+  bool is_maximized = window_util::IsWindowMaximized(window);
+  Workspace* current_workspace = FindBy(window);
+  DCHECK(current_workspace);
+  if (is_maximized) {
+    // Unmaximized -> maximized; create a new workspace (unless current only has
+    // one window).
+    SetRestoreBounds(window, window->GetTargetBounds());
+    if (current_workspace->num_windows() != 1) {
+      current_workspace->RemoveWindow(window);
+      Workspace* workspace = new Workspace(this);
+      workspace->SetType(Workspace::TYPE_MAXIMIZED);
+      workspace->AddWindowAfter(window, NULL);
+      current_workspace = workspace;
+    } else {
+      current_workspace->SetType(Workspace::TYPE_MAXIMIZED);
+    }
+    SetWindowBounds(window, GetWorkAreaBounds());
+  } else {
+    // Maximized -> unmaximized; move window to unmaximized workspace (or reuse
+    // current if there isn't one).
+    window_util::SetOpenWindowSplit(window, false);
+    Workspace* workspace = GetNormalWorkspace();
+    if (workspace) {
+      current_workspace->RemoveWindow(window);
+      DCHECK(current_workspace->is_empty());
+      workspace->AddWindowAfter(window, NULL);
+      delete current_workspace;
+      current_workspace = workspace;
+    } else {
+      current_workspace->SetType(Workspace::TYPE_NORMAL);
+    }
+
+    SetWindowBoundsFromRestoreBounds(window);
+  }
+
+  SetActiveWorkspace(current_workspace);
+}
+
+Workspace* WorkspaceManager::GetNormalWorkspace() {
+  for (size_t i = 0; i < workspaces_.size(); ++i) {
+    if (workspaces_[i]->type() == Workspace::TYPE_NORMAL)
+      return workspaces_[i];
+  }
+  return NULL;
 }
 
 }  // namespace internal
diff --git a/ash/wm/workspace/workspace_manager.h b/ash/wm/workspace/workspace_manager.h
index 99560e94643da..055893e1f0095 100644
--- a/ash/wm/workspace/workspace_manager.h
+++ b/ash/wm/workspace/workspace_manager.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// 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.
 
@@ -9,8 +9,8 @@
 
 #include "base/basictypes.h"
 #include "base/compiler_specific.h"
-#include "base/observer_list.h"
 #include "ash/ash_export.h"
+#include "ui/aura/window_observer.h"
 #include "ui/gfx/insets.h"
 #include "ui/gfx/size.h"
 
@@ -26,34 +26,32 @@ class Rect;
 namespace ash {
 namespace internal {
 class Workspace;
-class WorkspaceObserver;
+class WorkspaceManagerTest;
 
 // WorkspaceManager manages multiple workspaces in the desktop.
-class ASH_EXPORT WorkspaceManager {
+class ASH_EXPORT WorkspaceManager : public aura::WindowObserver{
  public:
   explicit WorkspaceManager(aura::Window* viewport);
   virtual ~WorkspaceManager();
 
+  // Returns true if |window| should be managed by the WorkspaceManager.
+  bool IsManagedWindow(aura::Window* window) const;
+
+  // Adds/removes a window creating/destroying workspace as necessary.
+  void AddWindow(aura::Window* window);
+  void RemoveWindow(aura::Window* window);
+
+  // Activates the workspace containing |window|. Does nothing if |window| is
+  // NULL or not contained in a workspace.
+  void SetActiveWorkspaceByWindow(aura::Window* window);
+
   // Returns the Window this WorkspaceManager controls.
   aura::Window* contents_view() { return contents_view_; }
 
-  // Create new workspace. Workspace objects are managed by
-  // this WorkspaceManager. Deleting workspace will automatically
-  // remove the workspace from the workspace_manager.
-  Workspace* CreateWorkspace();
-
-  // Returns the active workspace.
-  Workspace* GetActiveWorkspace() const;
-
-  // Returns the workspace that contanis the |window|.
-  Workspace* FindBy(aura::Window* window) const;
-
   // Returns the window for rotate operation based on the |location|.
+  // TODO: this isn't currently used; remove if we do away with overview.
   aura::Window* FindRotateWindowForLocation(const gfx::Point& location);
 
-  // Sets the bounds of all workspaces.
-  void LayoutWorkspaces();
-
   // Returns the bounds in which a window can be moved/resized.
   gfx::Rect GetDragAreaBounds();
 
@@ -61,25 +59,9 @@ class ASH_EXPORT WorkspaceManager {
   void SetOverview(bool overview);
   bool is_overview() const { return is_overview_; }
 
-  // Rotate windows by moving |source| window to the position of |target|.
-  void RotateWindows(aura::Window* source, aura::Window* target);
-
   // Sets the size of a single workspace (all workspaces have the same size).
   void SetWorkspaceSize(const gfx::Size& workspace_size);
 
-  // Adds/Removes workspace observer.
-  void AddObserver(WorkspaceObserver* observer);
-  void RemoveObserver(WorkspaceObserver* observer);
-
-  // Returns true if this workspace manager is laying out windows.
-  // When true, LayoutManager must give windows their requested bounds.
-  bool layout_in_progress() const { return layout_in_progress_; }
-
-  // Sets the |layout_in_progress_| flag.
-  void set_layout_in_progress(bool layout_in_progress) {
-    layout_in_progress_ = layout_in_progress;
-  }
-
   // Sets/Returns the ignored window that the workspace manager does not
   // set bounds on.
   void set_ignored_window(aura::Window* ignored_window) {
@@ -87,23 +69,47 @@ class ASH_EXPORT WorkspaceManager {
   }
   aura::Window* ignored_window() { return ignored_window_; }
 
+  // Overriden from aura::WindowObserver:
+  virtual void OnWindowPropertyChanged(aura::Window* window,
+                                       const char* name,
+                                       void* old) OVERRIDE;
+
  private:
   friend class Workspace;
+  friend class WorkspaceManagerTest;
 
   void AddWorkspace(Workspace* workspace);
   void RemoveWorkspace(Workspace* workspace);
 
+  // Returns the active workspace.
+  Workspace* GetActiveWorkspace() const;
+
+  // Returns the workspace that contanis the |window|.
+  Workspace* FindBy(aura::Window* window) const;
+
   // Sets the active workspace.
   void SetActiveWorkspace(Workspace* workspace);
 
-  // Returns the bounds of the work are given |workspace_bounds|.
-  gfx::Rect GetWorkAreaBounds(const gfx::Rect& workspace_bounds);
+  // Returns the bounds of the work area.
+  gfx::Rect GetWorkAreaBounds();
 
   // Returns the index of the workspace that contains the |window|.
   int GetWorkspaceIndexContaining(aura::Window* window) const;
 
-  // Update contents_view size and move the viewport to the active workspace.
-  void UpdateContentsView();
+  // Sets the bounds of |window|. This sets |ignored_window_| to |window| so
+  // that the bounds change is allowed through.
+  void SetWindowBounds(aura::Window* window, const gfx::Rect& bounds);
+
+  // Resets the bounds of |window| to its restored bounds (if set), ensuring
+  // it fits in the the windows current workspace.
+  void SetWindowBoundsFromRestoreBounds(aura::Window* window);
+
+  // Invoked when the maximized state of |window| changes.
+  void MaximizedStateChanged(aura::Window* window);
+
+  // Returns the Workspace whose type is TYPE_NORMAL, or NULL if there isn't
+  // one.
+  Workspace* GetNormalWorkspace();
 
   aura::Window* contents_view_;
 
@@ -118,14 +124,9 @@ class ASH_EXPORT WorkspaceManager {
   // True if the workspace manager is in overview mode.
   bool is_overview_;
 
-  // True if this layout manager is laying out windows.
-  bool layout_in_progress_;
-
   // The window that WorkspaceManager does not set the bounds on.
   aura::Window* ignored_window_;
 
-  ObserverList<WorkspaceObserver> observers_;
-
   DISALLOW_COPY_AND_ASSIGN(WorkspaceManager);
 };
 
diff --git a/ash/wm/workspace/workspace_manager_unittest.cc b/ash/wm/workspace/workspace_manager_unittest.cc
index 51df1943d22d5..c8753f056dc3f 100644
--- a/ash/wm/workspace/workspace_manager_unittest.cc
+++ b/ash/wm/workspace/workspace_manager_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// 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.
 
@@ -7,7 +7,7 @@
 #include "ash/shell_window_ids.h"
 #include "ash/wm/activation_controller.h"
 #include "ash/wm/workspace/workspace.h"
-#include "ash/wm/workspace/workspace_observer.h"
+#include "ash/wm/workspace/workspace_layout_manager.h"
 #include "ui/aura/client/aura_constants.h"
 #include "ui/aura/root_window.h"
 #include "ui/aura/screen_aura.h"
@@ -15,81 +15,27 @@
 #include "ui/aura/window.h"
 #include "ui/base/ui_base_types.h"
 
-namespace {
-using ash::internal::Workspace;
-using ash::internal::WorkspaceManager;
 using aura::Window;
 
-class TestWorkspaceObserver : public ash::internal::WorkspaceObserver {
- public:
-  explicit TestWorkspaceObserver(WorkspaceManager* manager)
-      : manager_(manager),
-        move_source_(NULL),
-        move_target_(NULL),
-        active_workspace_(NULL),
-        old_active_workspace_(NULL) {
-    manager_->AddObserver(this);
-  }
-
-  virtual ~TestWorkspaceObserver() {
-    manager_->RemoveObserver(this);
-  }
-
-  Window* move_source() { return move_source_; }
-  Window* move_target() { return move_target_; }
-  Workspace* active_workspace() { return active_workspace_; }
-  Workspace* old_active_workspace() { return old_active_workspace_; }
-
-  // Resets the observer states.
-  void reset() {
-    active_workspace_ = NULL;
-    old_active_workspace_ = NULL;
-    move_source_ = NULL;
-    move_target_ = NULL;
-  }
-
-  // Overridden from WorkspaceObserver:
-  virtual void WindowMoved(WorkspaceManager* manager,
-                           Window* source,
-                           Window* target) {
-    move_source_ = source;
-    move_target_ = target;
-  }
-  virtual void ActiveWorkspaceChanged(WorkspaceManager* manager,
-                                      Workspace* old) {
-    old_active_workspace_ = old;
-    active_workspace_ = manager->GetActiveWorkspace();
-  }
-
- private:
-  WorkspaceManager* manager_;
-  Window* move_source_;
-  Window* move_target_;
-  Workspace* active_workspace_;
-  Workspace* old_active_workspace_;
-
-  DISALLOW_COPY_AND_ASSIGN(TestWorkspaceObserver);
-};
-
-}  // namespace
-
 namespace ash {
 namespace internal {
 
-class WorkspaceManagerTestBase : public aura::test::AuraTestBase {
+class WorkspaceManagerTest : public aura::test::AuraTestBase {
  public:
-  WorkspaceManagerTestBase() {
+  WorkspaceManagerTest() : layout_manager_(NULL) {
     aura::RootWindow::GetInstance()->set_id(
         internal::kShellWindowId_DefaultContainer);
     activation_controller_.reset(new internal::ActivationController);
     activation_controller_->set_default_container_for_test(
         aura::RootWindow::GetInstance());
   }
-  virtual ~WorkspaceManagerTestBase() {}
+  virtual ~WorkspaceManagerTest() {}
 
   virtual void SetUp() OVERRIDE {
     aura::test::AuraTestBase::SetUp();
     manager_.reset(new WorkspaceManager(viewport()));
+    layout_manager_ = new WorkspaceLayoutManager(manager_.get());
+    viewport()->SetLayoutManager(layout_manager_);
   }
 
   virtual void TearDown() OVERRIDE {
@@ -99,468 +45,243 @@ class WorkspaceManagerTestBase : public aura::test::AuraTestBase {
 
   aura::Window* CreateTestWindow() {
     aura::Window* window = new aura::Window(NULL);
-    window->Init(ui::Layer::LAYER_HAS_NO_TEXTURE);
+    window->SetType(aura::client::WINDOW_TYPE_NORMAL);
+    window->Init(ui::Layer::LAYER_HAS_TEXTURE);
+    window->SetParent(viewport());
     return window;
   }
 
   aura::Window* viewport() {
     return aura::RootWindow::GetInstance();
   }
+
+  const std::vector<Workspace*>& workspaces() const {
+    return manager_->workspaces_;
+  }
+
+  gfx::Rect GetWorkAreaBounds() {
+    return manager_->GetWorkAreaBounds();
+  }
+
+  Workspace* active_workspace() {
+    return manager_->active_workspace_;
+  }
+
+  Workspace* FindBy(aura::Window* window) const {
+    return manager_->FindBy(window);
+  }
+
   scoped_ptr<WorkspaceManager> manager_;
 
+  // Owned by viewport().
+  WorkspaceLayoutManager* layout_manager_;
+
  private:
   scoped_ptr<internal::ActivationController> activation_controller_;
 
-  DISALLOW_COPY_AND_ASSIGN(WorkspaceManagerTestBase);
+  DISALLOW_COPY_AND_ASSIGN(WorkspaceManagerTest);
 };
 
-class WorkspaceManagerTest : public WorkspaceManagerTestBase {
-};
-
-TEST_F(WorkspaceManagerTest, WorkspaceManagerCreateAddFind) {
+// Assertions around adding a normal window.
+TEST_F(WorkspaceManagerTest, AddNormalWindowWhenEmpty) {
   scoped_ptr<Window> w1(CreateTestWindow());
-  scoped_ptr<Window> w2(CreateTestWindow());
+  w1->SetBounds(gfx::Rect(0, 0, 250, 251));
 
-  Workspace* ws1 = manager_->CreateWorkspace();
-  ws1->AddWindowAfter(w1.get(), NULL);
-  // w2 is not a part of any workspace yet.
-  EXPECT_EQ(NULL, manager_->FindBy(w2.get()));
+  ASSERT_TRUE(manager_->IsManagedWindow(w1.get()));
+  EXPECT_FALSE(FindBy(w1.get()));
 
-  // w2 is in ws2 workspace.
-  Workspace* ws2 = manager_->CreateWorkspace();
-  ws2->AddWindowAfter(w2.get(), NULL);
-  EXPECT_EQ(ws2, manager_->FindBy(w2.get()));
-
-  // Make sure |FindBy(w1.get())| still returns
-  // correct workspace.
-  EXPECT_EQ(ws1, manager_->FindBy(w1.get()));
-
-  // once workspace is gone, w2 shouldn't match
-  // any workspace.
-  delete ws2;
-  EXPECT_EQ(NULL, manager_->FindBy(w2.get()));
-
-  // Reset now before windows are destroyed.
-  manager_.reset();
-}
-
-TEST_F(WorkspaceManagerTest, LayoutWorkspaces) {
-  manager_->SetWorkspaceSize(gfx::Size(100, 100));
-  EXPECT_EQ("0,0 100x100", viewport()->bounds().ToString());
-
-  Workspace* ws1 = manager_->CreateWorkspace();
-  manager_->LayoutWorkspaces();
-
-  // ws1 is laied out in left most position.
-  EXPECT_EQ(100, viewport()->bounds().width());
-  EXPECT_EQ("0,0 100x100", ws1->bounds().ToString());
-
-  // ws2 is laied out next to ws1, with 50 margin.
-  Workspace* ws2 = manager_->CreateWorkspace();
-  manager_->LayoutWorkspaces();
-
-  EXPECT_EQ(250, viewport()->bounds().width());
-  EXPECT_EQ("0,0 100x100", ws1->bounds().ToString());
-  EXPECT_EQ("150,0 100x100", ws2->bounds().ToString());
-}
-
-// Makes sure the bounds of window are resized if the workspace size shrinks.
-TEST_F(WorkspaceManagerTest, ResizeDuringLayout) {
-  manager_->SetWorkspaceSize(gfx::Size(100, 100));
-  EXPECT_EQ("0,0 100x100", viewport()->bounds().ToString());
-
-  Workspace* ws1 = manager_->CreateWorkspace();
-  scoped_ptr<Window> w1(CreateTestWindow());
-  w1->SetBounds(gfx::Rect(0, 0, 100, 100));
-  viewport()->AddChild(w1.get());
-  EXPECT_TRUE(ws1->AddWindowAfter(w1.get(), NULL));
-  manager_->SetWorkspaceSize(gfx::Size(50, 50));
-
-  // ws1 is laied out in left most position.
-  EXPECT_EQ("0,0 50x50", ws1->bounds().ToString());
-  EXPECT_EQ("0,0 50x50", w1->layer()->GetTargetBounds().ToString());
-}
-
-TEST_F(WorkspaceManagerTest, WorkspaceManagerDragArea) {
-  aura::RootWindow::GetInstance()->screen()->set_work_area_insets(
-      gfx::Insets(10, 10, 10, 10));
-  viewport()->SetBounds(gfx::Rect(0, 0, 200, 200));
-  EXPECT_EQ("10,10 180x180", manager_->GetDragAreaBounds().ToString());
-}
-
-TEST_F(WorkspaceManagerTest, WorkspaceManagerActivate) {
-  TestWorkspaceObserver observer(manager_.get());
-  Workspace* ws1 = manager_->CreateWorkspace();
-  Workspace* ws2 = manager_->CreateWorkspace();
-  EXPECT_EQ(NULL, manager_->GetActiveWorkspace());
-
-  // Activate ws1.
-  ws1->Activate();
-  EXPECT_EQ(ws1, manager_->GetActiveWorkspace());
-  EXPECT_EQ(NULL, observer.old_active_workspace());
-  EXPECT_EQ(ws1, observer.active_workspace());
-  observer.reset();
-
-  // Activate ws2.
-  ws2->Activate();
-  EXPECT_EQ(ws2, manager_->GetActiveWorkspace());
-  EXPECT_EQ(ws1, observer.old_active_workspace());
-  EXPECT_EQ(ws2, observer.active_workspace());
-  observer.reset();
-
-  // Deleting active workspace sets active workspace to NULL.
-  delete ws2;
-  EXPECT_EQ(NULL, manager_->GetActiveWorkspace());
-  EXPECT_EQ(ws2, observer.old_active_workspace());
-  EXPECT_EQ(NULL, observer.active_workspace());
-}
-
-TEST_F(WorkspaceManagerTest, FindRotateWindow) {
-  manager_->SetWorkspaceSize(gfx::Size(500, 300));
-
-  Workspace* ws1 = manager_->CreateWorkspace();
-  scoped_ptr<Window> w11(CreateTestWindow());
-  w11->SetBounds(gfx::Rect(0, 0, 100, 100));
-  ws1->AddWindowAfter(w11.get(), NULL);
-
-  scoped_ptr<Window> w12(CreateTestWindow());
-  w12->SetBounds(gfx::Rect(0, 0, 100, 100));
-  ws1->AddWindowAfter(w12.get(), NULL);
-  manager_->LayoutWorkspaces();
-
-  // Workspaces are 0-<lmgn>-145-<w11>-245-<wmng>-255-<w12>-355-<rmgn>-500.
-  EXPECT_EQ(NULL, manager_->FindRotateWindowForLocation(gfx::Point(0, 0)));
-  EXPECT_EQ(NULL, manager_->FindRotateWindowForLocation(gfx::Point(100, 0)));
-  EXPECT_EQ(w11.get(),
-            manager_->FindRotateWindowForLocation(gfx::Point(150, 0)));
-  EXPECT_EQ(w12.get(),
-            manager_->FindRotateWindowForLocation(gfx::Point(300, 0)));
-  EXPECT_EQ(NULL, manager_->FindRotateWindowForLocation(gfx::Point(400, 0)));
-
-  w11->SetBounds(gfx::Rect(0, 0, 400, 100));
-  w12->SetBounds(gfx::Rect(0, 0, 200, 100));
-  manager_->FindBy(w11.get())->Layout(NULL);
-  EXPECT_EQ(w11.get(),
-            manager_->FindRotateWindowForLocation(gfx::Point(10, 0)));
-  EXPECT_EQ(w11.get(),
-            manager_->FindRotateWindowForLocation(gfx::Point(240, 0)));
-  EXPECT_EQ(w12.get(),
-            manager_->FindRotateWindowForLocation(gfx::Point(260, 0)));
-  EXPECT_EQ(w12.get(),
-            manager_->FindRotateWindowForLocation(gfx::Point(490, 0)));
-
-  Workspace* ws2 = manager_->CreateWorkspace();
-  scoped_ptr<Window> w21(CreateTestWindow());
-  w21->SetBounds(gfx::Rect(0, 0, 100, 100));
-  ws2->AddWindowAfter(w21.get(), NULL);
-  manager_->LayoutWorkspaces();
-
-  // 2nd workspace starts from 500+50 and the window is centered 750-850.
-  EXPECT_EQ(NULL, manager_->FindRotateWindowForLocation(gfx::Point(600, 0)));
-  EXPECT_EQ(NULL, manager_->FindRotateWindowForLocation(gfx::Point(740, 0)));
-  EXPECT_EQ(w21.get(),
-            manager_->FindRotateWindowForLocation(gfx::Point(760, 0)));
-  EXPECT_EQ(w21.get(),
-            manager_->FindRotateWindowForLocation(gfx::Point(840, 0)));
-  EXPECT_EQ(NULL, manager_->FindRotateWindowForLocation(gfx::Point(860, 0)));
-
-  // Reset now before windows are destroyed.
-  manager_.reset();
-}
-
-TEST_F(WorkspaceManagerTest, RotateWindows) {
-  scoped_ptr<TestWorkspaceObserver> observer(
-      new TestWorkspaceObserver(manager_.get()));
-  Workspace* ws1 = manager_->CreateWorkspace();
-  Workspace* ws2 = manager_->CreateWorkspace();
-
-  scoped_ptr<Window> w11(CreateTestWindow());
-  ws1->AddWindowAfter(w11.get(), NULL);
-
-  scoped_ptr<Window> w21(CreateTestWindow());
-  scoped_ptr<Window> w22(CreateTestWindow());
-  ws2->AddWindowAfter(w21.get(), NULL);
-  ws2->AddWindowAfter(w22.get(), NULL);
-
-  EXPECT_EQ(0, ws1->GetIndexOf(w11.get()));
-  EXPECT_EQ(0, ws2->GetIndexOf(w21.get()));
-  EXPECT_EQ(1, ws2->GetIndexOf(w22.get()));
-
-  // Rotate right most to left most.
-  manager_->RotateWindows(w22.get(), w11.get());
-  EXPECT_EQ(w22.get(), observer->move_source());
-  EXPECT_EQ(w11.get(), observer->move_target());
-
-  EXPECT_EQ(0, ws1->GetIndexOf(w22.get()));
-  EXPECT_EQ(0, ws2->GetIndexOf(w11.get()));
-  EXPECT_EQ(1, ws2->GetIndexOf(w21.get()));
-
-  // Rotate left most to right most.
-  manager_->RotateWindows(w22.get(), w21.get());
-  EXPECT_EQ(0, ws1->GetIndexOf(w11.get()));
-  EXPECT_EQ(0, ws2->GetIndexOf(w21.get()));
-  EXPECT_EQ(1, ws2->GetIndexOf(w22.get()));
-  EXPECT_EQ(w22.get(), observer->move_source());
-  EXPECT_EQ(w21.get(), observer->move_target());
-
-  // Rotate left most to 1st element in 2nd workspace.
-  manager_->RotateWindows(w11.get(), w21.get());
-  EXPECT_EQ(0, ws1->GetIndexOf(w21.get()));
-  EXPECT_EQ(0, ws2->GetIndexOf(w11.get()));
-  EXPECT_EQ(1, ws2->GetIndexOf(w22.get()));
-  EXPECT_EQ(w11.get(), observer->move_source());
-  EXPECT_EQ(w21.get(), observer->move_target());
-
-  // Rotate middle to right most.
-  manager_->RotateWindows(w11.get(), w22.get());
-  EXPECT_EQ(0, ws1->GetIndexOf(w21.get()));
-  EXPECT_EQ(0, ws2->GetIndexOf(w22.get()));
-  EXPECT_EQ(1, ws2->GetIndexOf(w11.get()));
-  EXPECT_EQ(w11.get(), observer->move_source());
-  EXPECT_EQ(w22.get(), observer->move_target());
-
-  // Rotate middle to left most.
-  manager_->RotateWindows(w22.get(), w21.get());
-  EXPECT_EQ(0, ws1->GetIndexOf(w22.get()));
-  EXPECT_EQ(0, ws2->GetIndexOf(w21.get()));
-  EXPECT_EQ(1, ws2->GetIndexOf(w11.get()));
-  EXPECT_EQ(w22.get(), observer->move_source());
-  EXPECT_EQ(w21.get(), observer->move_target());
-
-  // Reset now before windows are destroyed.
-  observer.reset();
-  manager_.reset();
-}
-
-class WorkspaceTest : public WorkspaceManagerTestBase {
-};
-
-TEST_F(WorkspaceTest, WorkspaceBasic) {
-  Workspace* ws = manager_->CreateWorkspace();
-  // Sanity check
-  EXPECT_TRUE(ws->is_empty());
-
-  scoped_ptr<Window> w1(CreateTestWindow());
-  scoped_ptr<Window> w2(CreateTestWindow());
-  scoped_ptr<Window> w3(CreateTestWindow());
-  // ws is empty and can accomodate new window.
-  EXPECT_TRUE(ws->CanAdd(w1.get()));
-
-  // Add w1.
-  EXPECT_TRUE(ws->AddWindowAfter(w1.get(), NULL));
-  EXPECT_TRUE(ws->Contains(w1.get()));
-  EXPECT_FALSE(ws->is_empty());
-
-  // The workspac still has room for next window.
-  EXPECT_TRUE(ws->CanAdd(w2.get()));
-  EXPECT_TRUE(ws->AddWindowAfter(w2.get(), NULL));
-  EXPECT_TRUE(ws->Contains(w2.get()));
-
-  // The workspace no longer accepts new window.
-  EXPECT_FALSE(ws->CanAdd(w3.get()));
-  EXPECT_FALSE(ws->AddWindowAfter(w3.get(), NULL));
-  EXPECT_FALSE(ws->Contains(w3.get()));
-
-  // Check if the window has correct layout index.
-  EXPECT_EQ(0, ws->GetIndexOf(w1.get()));
-  EXPECT_EQ(1, ws->GetIndexOf(w2.get()));
-  EXPECT_EQ(-1, ws->GetIndexOf(w3.get()));
-
-  // w1 is gone, so no index for w2.
-  ws->RemoveWindow(w1.get());
-  EXPECT_EQ(-1, ws->GetIndexOf(w1.get()));
-  EXPECT_EQ(0, ws->GetIndexOf(w2.get()));
-  EXPECT_FALSE(ws->Contains(w1.get()));
-
-  // Add w1 back. w1 now has index = 1.
-  EXPECT_TRUE(ws->AddWindowAfter(w1.get(), w2.get()));
-  EXPECT_EQ(0, ws->GetIndexOf(w2.get()));
-  EXPECT_EQ(1, ws->GetIndexOf(w1.get()));
-
-  // Reset now before windows are destroyed.
-  manager_.reset();
-}
-
-TEST_F(WorkspaceTest, RotateWindows) {
-  size_t orig_max = Workspace::SetMaxWindowsCount(3);
-  Workspace* ws = manager_->CreateWorkspace();
-  scoped_ptr<Window> w1(CreateTestWindow());
-  scoped_ptr<Window> w2(CreateTestWindow());
-  scoped_ptr<Window> w3(CreateTestWindow());
-  ws->AddWindowAfter(w1.get(), NULL);
-  ws->AddWindowAfter(w2.get(), NULL);
-  ws->AddWindowAfter(w3.get(), NULL);
-
-  EXPECT_EQ(0, ws->GetIndexOf(w1.get()));
-  EXPECT_EQ(1, ws->GetIndexOf(w2.get()));
-  EXPECT_EQ(2, ws->GetIndexOf(w3.get()));
-
-  // Rotate to left.
-  ws->RotateWindows(w1.get(), w3.get());
-  EXPECT_EQ(0, ws->GetIndexOf(w2.get()));
-  EXPECT_EQ(1, ws->GetIndexOf(w3.get()));
-  EXPECT_EQ(2, ws->GetIndexOf(w1.get()));
-
-  // Rotate to right.
-  ws->RotateWindows(w1.get(), w2.get());
-  EXPECT_EQ(0, ws->GetIndexOf(w1.get()));
-  EXPECT_EQ(1, ws->GetIndexOf(w2.get()));
-  EXPECT_EQ(2, ws->GetIndexOf(w3.get()));
-
-  // Rotating to the middle from left.
-  ws->RotateWindows(w1.get(), w2.get());
-  EXPECT_EQ(0, ws->GetIndexOf(w2.get()));
-  EXPECT_EQ(1, ws->GetIndexOf(w1.get()));
-  EXPECT_EQ(2, ws->GetIndexOf(w3.get()));
-
-  // Rotating to the middle from right.
-  ws->RotateWindows(w3.get(), w1.get());
-  EXPECT_EQ(0, ws->GetIndexOf(w2.get()));
-  EXPECT_EQ(1, ws->GetIndexOf(w3.get()));
-  EXPECT_EQ(2, ws->GetIndexOf(w1.get()));
-
-  // Reset now before windows are destroyed.
-  manager_.reset();
-  Workspace::SetMaxWindowsCount(orig_max);
-}
-
-TEST_F(WorkspaceTest, ShiftWindowsSingle) {
-  Workspace* ws = manager_->CreateWorkspace();
-  // Single window in a workspace case.
-  scoped_ptr<Window> w1(CreateTestWindow());
-  ws->AddWindowAfter(w1.get(), NULL);
-
-  scoped_ptr<Window> w2(CreateTestWindow());
-
-  // Sanity check.
-  EXPECT_EQ(0, ws->GetIndexOf(w1.get()));
-  EXPECT_EQ(-1, ws->GetIndexOf(w2.get()));
-
-  // Insert |w2| at the beginning and shift.
-  aura::Window* overflow =
-      ws->ShiftWindows(
-          w2.get(), w2.get(), NULL, Workspace::SHIFT_TO_RIGHT);
-  EXPECT_EQ(w1.get(), overflow);
-  EXPECT_EQ(-1, ws->GetIndexOf(w1.get()));
-  EXPECT_EQ(0, ws->GetIndexOf(w2.get()));
-
-  // Insert |w1| at the end and shift.
-  overflow = ws->ShiftWindows(
-      w1.get(), w1.get(), NULL, Workspace::SHIFT_TO_LEFT);
-  EXPECT_EQ(w2.get(), overflow);
-  EXPECT_EQ(-1, ws->GetIndexOf(w2.get()));
-  EXPECT_EQ(0, ws->GetIndexOf(w1.get()));
-
-  // Insert |w2| at the begining and shift up to the w1.
-  overflow = ws->ShiftWindows(
-      w2.get(), w1.get(), NULL, Workspace::SHIFT_TO_RIGHT);
-  EXPECT_EQ(NULL, overflow);
-  EXPECT_EQ(-1, ws->GetIndexOf(w1.get()));
-  EXPECT_EQ(0, ws->GetIndexOf(w2.get()));
-
-  // Insert |w1| at the end and shift up to the w2.
-  overflow = ws->ShiftWindows(
-      w1.get(), w2.get(), NULL, Workspace::SHIFT_TO_LEFT);
-  EXPECT_EQ(NULL, overflow);
-  EXPECT_EQ(-1, ws->GetIndexOf(w2.get()));
-  EXPECT_EQ(0, ws->GetIndexOf(w1.get()));
-
-  // Reset now before windows are destroyed.
-  manager_.reset();
-}
-
-TEST_F(WorkspaceTest, ShiftWindowsMultiple) {
-  Workspace* ws = manager_->CreateWorkspace();
-  // Single window in a workspace case.
-  scoped_ptr<Window> w1(CreateTestWindow());
-  scoped_ptr<Window> w2(CreateTestWindow());
-  ws->AddWindowAfter(w1.get(), NULL);
-  ws->AddWindowAfter(w2.get(), NULL);
-
-  scoped_ptr<Window> w3(CreateTestWindow());
-
-  // Sanity check.
-  EXPECT_EQ(0, ws->GetIndexOf(w1.get()));
-  EXPECT_EQ(1, ws->GetIndexOf(w2.get()));
-  EXPECT_EQ(-1, ws->GetIndexOf(w3.get()));
-
-  // Insert |w3| at the beginning and shift.
-  aura::Window* overflow =
-      ws->ShiftWindows(w3.get(), w3.get(), NULL,
-                       Workspace::SHIFT_TO_RIGHT);
-  EXPECT_EQ(w2.get(), overflow);
-  EXPECT_EQ(-1, ws->GetIndexOf(w2.get()));
-  EXPECT_EQ(0, ws->GetIndexOf(w3.get()));
-  EXPECT_EQ(1, ws->GetIndexOf(w1.get()));
-
-  // Insert |w3| at the end and shift.
-  overflow = ws->ShiftWindows(w2.get(), w2.get(), NULL,
-                              Workspace::SHIFT_TO_LEFT);
-  EXPECT_EQ(w3.get(), overflow);
-  EXPECT_EQ(-1, ws->GetIndexOf(w3.get()));
-  EXPECT_EQ(0, ws->GetIndexOf(w1.get()));
-  EXPECT_EQ(1, ws->GetIndexOf(w2.get()));
-
-  // Insert |w3| at the begining and shift up to the w1.
-  overflow = ws->ShiftWindows(w3.get(), w1.get(), NULL,
-                              Workspace::SHIFT_TO_RIGHT);
-  EXPECT_EQ(NULL, overflow);
-  EXPECT_EQ(-1, ws->GetIndexOf(w1.get()));
-  EXPECT_EQ(0, ws->GetIndexOf(w3.get()));
-  EXPECT_EQ(1, ws->GetIndexOf(w2.get()));
-
-  // Insert |w1| at the end and shift up to the w2.
-  overflow = ws->ShiftWindows(w1.get(), w2.get(), NULL,
-                              Workspace::SHIFT_TO_LEFT);
-  EXPECT_EQ(NULL, overflow);
-  EXPECT_EQ(-1, ws->GetIndexOf(w2.get()));
-  EXPECT_EQ(0, ws->GetIndexOf(w3.get()));
-  EXPECT_EQ(1, ws->GetIndexOf(w1.get()));
-
-  scoped_ptr<Window> unused(CreateTestWindow());
-
-  // Insert |w2| at the |w3| and shift to right.
-  overflow = ws->ShiftWindows(w2.get(), unused.get(), w3.get(),
-                              Workspace::SHIFT_TO_RIGHT);
-  EXPECT_EQ(w1.get(), overflow);
-  EXPECT_EQ(-1, ws->GetIndexOf(w1.get()));
-  EXPECT_EQ(0, ws->GetIndexOf(w2.get()));
-  EXPECT_EQ(1, ws->GetIndexOf(w3.get()));
-
-  // Insert |w1| at the |w2| and shift to left.
-  overflow = ws->ShiftWindows(w1.get(), unused.get(), w2.get(),
-                              Workspace::SHIFT_TO_LEFT);
-  EXPECT_EQ(w2.get(), overflow);
-  EXPECT_EQ(-1, ws->GetIndexOf(w2.get()));
-  EXPECT_EQ(0, ws->GetIndexOf(w1.get()));
-  EXPECT_EQ(1, ws->GetIndexOf(w3.get()));
-
-  // Reset now before windows are destroyed.
-  manager_.reset();
-}
-
-TEST_F(WorkspaceTest, ContainsFullscreenWindow) {
-  Workspace* ws = manager_->CreateWorkspace();
-  scoped_ptr<Window> w1(CreateTestWindow());
-  scoped_ptr<Window> w2(CreateTestWindow());
-  ws->AddWindowAfter(w1.get(), NULL);
-  ws->AddWindowAfter(w2.get(), NULL);
   w1->Show();
+
+  ASSERT_TRUE(w1->layer() != NULL);
+  EXPECT_TRUE(w1->layer()->visible());
+
+  EXPECT_EQ(250, w1->bounds().width());
+  EXPECT_EQ(251, w1->bounds().height());
+
+  // Should be 1 workspace, TYPE_NORNMAL with w1.
+  ASSERT_EQ(1u, workspaces().size());
+  EXPECT_EQ(Workspace::TYPE_NORMAL, workspaces()[0]->type());
+  ASSERT_EQ(1u, workspaces()[0]->windows().size());
+  EXPECT_EQ(w1.get(), workspaces()[0]->windows()[0]);
+}
+
+// Assertions around maximizing/unmaximizing.
+TEST_F(WorkspaceManagerTest, SingleMaximizeWindow) {
+  scoped_ptr<Window> w1(CreateTestWindow());
+  w1->SetBounds(gfx::Rect(0, 0, 250, 251));
+
+  ASSERT_TRUE(manager_->IsManagedWindow(w1.get()));
+
+  w1->Show();
+
+  ASSERT_TRUE(w1->layer() != NULL);
+  EXPECT_TRUE(w1->layer()->visible());
+
+  EXPECT_EQ(250, w1->bounds().width());
+  EXPECT_EQ(251, w1->bounds().height());
+
+  // Maximize the window.
+  w1->SetIntProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MAXIMIZED);
+
+  // Should be 1 workspace, TYPE_MAXIMIZED with w1.
+  ASSERT_EQ(1u, workspaces().size());
+  EXPECT_EQ(Workspace::TYPE_MAXIMIZED, workspaces()[0]->type());
+  ASSERT_EQ(1u, workspaces()[0]->windows().size());
+  EXPECT_EQ(w1.get(), workspaces()[0]->windows()[0]);
+  EXPECT_EQ(GetWorkAreaBounds().width(), w1->bounds().width());
+  EXPECT_EQ(GetWorkAreaBounds().height(), w1->bounds().height());
+
+  // Restore the window.
+  w1->SetIntProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL);
+
+  // Should be 1 workspace, TYPE_NORMAL with w1.
+  ASSERT_EQ(1u, workspaces().size());
+  EXPECT_EQ(Workspace::TYPE_NORMAL, workspaces()[0]->type());
+  ASSERT_EQ(1u, workspaces()[0]->windows().size());
+  EXPECT_EQ(w1.get(), workspaces()[0]->windows()[0]);
+  EXPECT_EQ(250, w1->bounds().width());
+  EXPECT_EQ(251, w1->bounds().height());
+}
+
+// Assertions around closing the last window in a workspace.
+TEST_F(WorkspaceManagerTest, CloseLastWindowInWorkspace) {
+  scoped_ptr<Window> w1(CreateTestWindow());
+  scoped_ptr<Window> w2(CreateTestWindow());
+  w1->SetBounds(gfx::Rect(0, 0, 250, 251));
+  w1->Show();
+  w2->SetIntProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MAXIMIZED);
   w2->Show();
 
-  EXPECT_FALSE(ws->ContainsFullscreenWindow());
+  // Should be 2 workspaces, TYPE_NORMAL with w1, and TYPE_MAXIMIZED with w2.
+  ASSERT_EQ(2u, workspaces().size());
+  EXPECT_EQ(Workspace::TYPE_NORMAL, workspaces()[0]->type());
+  ASSERT_EQ(1u, workspaces()[0]->windows().size());
+  EXPECT_EQ(w1.get(), workspaces()[0]->windows()[0]);
+  EXPECT_EQ(Workspace::TYPE_MAXIMIZED, workspaces()[1]->type());
+  ASSERT_EQ(1u, workspaces()[1]->windows().size());
+  EXPECT_EQ(w2.get(), workspaces()[1]->windows()[0]);
+  EXPECT_FALSE(w1->layer()->visible());
+  EXPECT_TRUE(w2->layer()->visible());
+  // TYPE_MAXIMIZED workspace should be active.
+  EXPECT_EQ(workspaces()[1], active_workspace());
 
-  w1->SetIntProperty(aura::client::kShowStateKey, ui::SHOW_STATE_FULLSCREEN);
-  EXPECT_TRUE(ws->ContainsFullscreenWindow());
+  // Close w2.
+  w2.reset();
 
-  w1->SetIntProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL);
-  EXPECT_FALSE(ws->ContainsFullscreenWindow());
+  // Should have one workspace, TYPE_NORMAL with w1.
+  ASSERT_EQ(1u, workspaces().size());
+  EXPECT_EQ(Workspace::TYPE_NORMAL, workspaces()[0]->type());
+  ASSERT_EQ(1u, workspaces()[0]->windows().size());
+  EXPECT_EQ(w1.get(), workspaces()[0]->windows()[0]);
+  EXPECT_TRUE(w1->layer()->visible());
+  EXPECT_EQ(workspaces()[0], active_workspace());
+}
 
-  w2->SetIntProperty(aura::client::kShowStateKey, ui::SHOW_STATE_FULLSCREEN);
-  EXPECT_TRUE(ws->ContainsFullscreenWindow());
+// Assertions around adding a maximized window when empty.
+TEST_F(WorkspaceManagerTest, AddMaximizedWindowWhenEmpty) {
+  scoped_ptr<Window> w1(CreateTestWindow());
+  w1->SetBounds(gfx::Rect(0, 0, 250, 251));
+  w1->SetIntProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MAXIMIZED);
+  w1->Show();
 
-  w2->Hide();
-  EXPECT_FALSE(ws->ContainsFullscreenWindow());
+  ASSERT_TRUE(w1->layer() != NULL);
+  EXPECT_TRUE(w1->layer()->visible());
+  gfx::Rect work_area(
+      gfx::Screen::GetMonitorWorkAreaNearestWindow(w1.get()));
+  EXPECT_EQ(work_area.width(), w1->bounds().width());
+  EXPECT_EQ(work_area.height(), w1->bounds().height());
+
+  // Should be 1 workspace, TYPE_NORNMAL with w1.
+  ASSERT_EQ(1u, workspaces().size());
+  EXPECT_EQ(Workspace::TYPE_MAXIMIZED, workspaces()[0]->type());
+  ASSERT_EQ(1u, workspaces()[0]->windows().size());
+  EXPECT_EQ(w1.get(), workspaces()[0]->windows()[0]);
+}
+
+// Assertions around two windows and toggling one to be maximized.
+TEST_F(WorkspaceManagerTest, MaximizeWithNormalWindow) {
+  scoped_ptr<Window> w1(CreateTestWindow());
+  scoped_ptr<Window> w2(CreateTestWindow());
+  w1->SetBounds(gfx::Rect(0, 0, 250, 251));
+  w1->Show();
+
+  ASSERT_TRUE(w1->layer() != NULL);
+  EXPECT_TRUE(w1->layer()->visible());
+
+  w2->SetBounds(gfx::Rect(0, 0, 50, 51));
+  w2->SetIntProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MAXIMIZED);
+  w2->Show();
+
+  // Should now be two workspaces.
+  ASSERT_EQ(2u, workspaces().size());
+  EXPECT_EQ(Workspace::TYPE_NORMAL, workspaces()[0]->type());
+  ASSERT_EQ(1u, workspaces()[0]->windows().size());
+  EXPECT_EQ(w1.get(), workspaces()[0]->windows()[0]);
+  EXPECT_EQ(Workspace::TYPE_MAXIMIZED, workspaces()[1]->type());
+  ASSERT_EQ(1u, workspaces()[1]->windows().size());
+  EXPECT_EQ(w2.get(), workspaces()[1]->windows()[0]);
+  ASSERT_TRUE(w1->layer() != NULL);
+  EXPECT_FALSE(w1->layer()->visible());
+  ASSERT_TRUE(w2->layer() != NULL);
+  EXPECT_TRUE(w2->layer()->visible());
+
+  gfx::Rect work_area(
+      gfx::Screen::GetMonitorWorkAreaNearestWindow(w1.get()));
+  EXPECT_EQ(work_area.width(), w2->bounds().width());
+  EXPECT_EQ(work_area.height(), w2->bounds().height());
+
+  // Restore w2, which should then go back to one workspace.
+  w2->SetIntProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL);
+  ASSERT_EQ(1u, workspaces().size());
+  EXPECT_EQ(Workspace::TYPE_NORMAL, workspaces()[0]->type());
+  ASSERT_EQ(2u, workspaces()[0]->windows().size());
+  EXPECT_EQ(w1.get(), workspaces()[0]->windows()[0]);
+  EXPECT_EQ(w2.get(), workspaces()[0]->windows()[1]);
+  EXPECT_EQ(50, w2->bounds().width());
+  EXPECT_EQ(51, w2->bounds().height());
+  ASSERT_TRUE(w1->layer() != NULL);
+  EXPECT_TRUE(w1->layer()->visible());
+  ASSERT_TRUE(w2->layer() != NULL);
+  EXPECT_TRUE(w2->layer()->visible());
+}
+
+// Assertions around two maximized windows.
+TEST_F(WorkspaceManagerTest, TwoMaximized) {
+  scoped_ptr<Window> w1(CreateTestWindow());
+  scoped_ptr<Window> w2(CreateTestWindow());
+  w1->SetBounds(gfx::Rect(0, 0, 250, 251));
+  w1->Show();
+  w1->SetIntProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MAXIMIZED);
+
+  w2->SetBounds(gfx::Rect(0, 0, 50, 51));
+  w2->SetIntProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MAXIMIZED);
+  w2->Show();
+
+  // Should now be two workspaces.
+  ASSERT_EQ(2u, workspaces().size());
+  EXPECT_EQ(Workspace::TYPE_MAXIMIZED, workspaces()[0]->type());
+  ASSERT_EQ(1u, workspaces()[0]->windows().size());
+  EXPECT_EQ(w1.get(), workspaces()[0]->windows()[0]);
+  EXPECT_EQ(Workspace::TYPE_MAXIMIZED, workspaces()[1]->type());
+  ASSERT_EQ(1u, workspaces()[1]->windows().size());
+  EXPECT_EQ(w2.get(), workspaces()[1]->windows()[0]);
+  ASSERT_TRUE(w1->layer() != NULL);
+  EXPECT_FALSE(w1->layer()->visible());
+  ASSERT_TRUE(w2->layer() != NULL);
+  EXPECT_TRUE(w2->layer()->visible());
+}
+
+// Makes sure requests to change the bounds of a normal window go through.
+TEST_F(WorkspaceManagerTest, ChangeBoundsOfNormalWindow) {
+  scoped_ptr<Window> w1(CreateTestWindow());
+  w1->Show();
+
+  EXPECT_TRUE(manager_->IsManagedWindow(w1.get()));
+  // Setting the bounds should go through since the window is in the normal
+  // workspace.
+  w1->SetBounds(gfx::Rect(0, 0, 200, 500));
+  EXPECT_EQ(200, w1->bounds().width());
+  EXPECT_EQ(500, w1->bounds().height());
 }
 
 }  // namespace internal
diff --git a/ash/wm/workspace/workspace_observer.h b/ash/wm/workspace/workspace_observer.h
deleted file mode 100644
index c6e055bffae37..0000000000000
--- a/ash/wm/workspace/workspace_observer.h
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef ASH_WM_WORKSPACE_WORKSPACE_OBSERVER_H_
-#define ASH_WM_WORKSPACE_WORKSPACE_OBSERVER_H_
-#pragma once
-
-#include "ash/ash_export.h"
-
-namespace aura {
-class Window;
-}
-
-namespace ash {
-namespace internal {
-class Workspace;
-class WorkspaceManager;
-
-// A class to observe changes in workspace state.
-class ASH_EXPORT WorkspaceObserver {
- public:
-  // Invoked when |start| window is moved and inserted
-  // at the |target| window's position by |WorkspaceManager::RotateWindow|.
-  virtual void WindowMoved(WorkspaceManager* manager,
-                           aura::Window* source,
-                           aura::Window* target) = 0;
-
-  // Invoked when the active workspace changes. |old| is
-  // the old active workspace and can be NULL.
-  virtual void ActiveWorkspaceChanged(WorkspaceManager* manager,
-                                      Workspace* old) = 0;
- protected:
-  virtual ~WorkspaceObserver() {}
-};
-
-}  // namespace internal
-}  // namespace ash
-
-#endif  // ASH_WM_WORKSPACE_WORKSPACE_OBSERVER_H_
diff --git a/ash/wm/workspace_controller.cc b/ash/wm/workspace_controller.cc
index c12f8c95a1bc8..8f9d7cf614331 100644
--- a/ash/wm/workspace_controller.cc
+++ b/ash/wm/workspace_controller.cc
@@ -8,7 +8,6 @@
 #include "ash/launcher/launcher_model.h"
 #include "ash/shell.h"
 #include "ash/wm/window_util.h"
-#include "ash/wm/workspace/workspace.h"
 #include "ash/wm/workspace/workspace_layout_manager.h"
 #include "ash/wm/workspace/workspace_manager.h"
 #include "ui/aura/client/activation_client.h"
@@ -23,13 +22,11 @@ WorkspaceController::WorkspaceController(aura::Window* viewport)
     : workspace_manager_(new WorkspaceManager(viewport)),
       launcher_model_(NULL),
       ignore_move_event_(false) {
-  workspace_manager_->AddObserver(this);
   aura::RootWindow::GetInstance()->AddRootWindowObserver(this);
   aura::RootWindow::GetInstance()->AddObserver(this);
 }
 
 WorkspaceController::~WorkspaceController() {
-  workspace_manager_->RemoveObserver(this);
   if (launcher_model_)
     launcher_model_->RemoveObserver(this);
   aura::RootWindow::GetInstance()->RemoveObserver(this);
@@ -59,32 +56,8 @@ void WorkspaceController::OnRootWindowResized(const gfx::Size& new_size) {
 void WorkspaceController::OnWindowPropertyChanged(aura::Window* window,
                                                   const char* key,
                                                   void* old) {
-  if (key == aura::client::kRootWindowActiveWindow) {
-    // FindBy handles NULL.
-    Workspace* workspace = workspace_manager_->FindBy(GetActiveWindow());
-    if (workspace)
-      workspace->Activate();
-  }
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// WorkspaceController, ash::internal::WorkspaceObserver overrides:
-
-void WorkspaceController::WindowMoved(WorkspaceManager* manager,
-                                      aura::Window* source,
-                                      aura::Window* target) {
-  if (ignore_move_event_ || !launcher_model_)
-    return;
-  // TODO: there is no longer a 1-1 mapping between the launcher and windows;
-  // decide how we want to handle it.
-  NOTIMPLEMENTED();
-}
-
-void WorkspaceController::ActiveWorkspaceChanged(WorkspaceManager* manager,
-                                                 Workspace* old) {
-  // TODO(oshima): Update Launcher and Status area state when the active
-  // workspace's fullscreen state changes.
-  //NOTIMPLEMENTED();
+  if (key == aura::client::kRootWindowActiveWindow)
+    workspace_manager_->SetActiveWorkspaceByWindow(GetActiveWindow());
 }
 
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/ash/wm/workspace_controller.h b/ash/wm/workspace_controller.h
index 2d65e4238d716..9e541d984f457 100644
--- a/ash/wm/workspace_controller.h
+++ b/ash/wm/workspace_controller.h
@@ -7,7 +7,6 @@
 #pragma once
 
 #include "ash/launcher/launcher_model_observer.h"
-#include "ash/wm/workspace/workspace_observer.h"
 #include "base/basictypes.h"
 #include "base/memory/scoped_ptr.h"
 #include "ui/aura/root_window_observer.h"
@@ -35,7 +34,6 @@ class WorkspaceManager;
 class ASH_EXPORT WorkspaceController :
       public aura::RootWindowObserver,
       public aura::WindowObserver,
-      public ash::internal::WorkspaceObserver,
       public ash::LauncherModelObserver {
  public:
   explicit WorkspaceController(aura::Window* workspace_viewport);
@@ -58,13 +56,6 @@ class ASH_EXPORT WorkspaceController :
                                        const char* key,
                                        void* old) OVERRIDE;
 
-  // WorkspaceObserver overrides:
-  virtual void WindowMoved(WorkspaceManager* manager,
-                           aura::Window* source,
-                           aura::Window* target) OVERRIDE;
-  virtual void ActiveWorkspaceChanged(WorkspaceManager* manager,
-                                      Workspace* old) OVERRIDE;
-
   // Invoked after an item has been added to the model.
   virtual void LauncherItemAdded(int index) OVERRIDE;
   virtual void LauncherItemRemoved(int index) OVERRIDE;
diff --git a/ash/wm/workspace_controller_unittest.cc b/ash/wm/workspace_controller_unittest.cc
index 5438a6ff715a7..5bd2ac46e70fc 100644
--- a/ash/wm/workspace_controller_unittest.cc
+++ b/ash/wm/workspace_controller_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// 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.
 
@@ -67,53 +67,5 @@ class WorkspaceControllerTest : public aura::test::AuraTestBase {
   DISALLOW_COPY_AND_ASSIGN(WorkspaceControllerTest);
 };
 
-TEST_F(WorkspaceControllerTest, Overview) {
-  workspace_manager()->SetWorkspaceSize(gfx::Size(500, 300));
-
-  // Creating two workspaces, ws1 which contains window w1,
-  // and ws2 which contains window w2.
-  Workspace* ws1 = workspace_manager()->CreateWorkspace();
-  scoped_ptr<Window> w1(CreateTestWindow());
-  EXPECT_TRUE(ws1->AddWindowAfter(w1.get(), NULL));
-
-  Workspace* ws2 = workspace_manager()->CreateWorkspace();
-  scoped_ptr<Window> w2(CreateTestWindow());
-  EXPECT_TRUE(ws2->AddWindowAfter(w2.get(), NULL));
-
-  // Activating a window switches the active workspace.
-  ash::ActivateWindow(w2.get());
-  EXPECT_EQ(ws2, workspace_manager()->GetActiveWorkspace());
-
-  // The size of contents_view() is now ws1(500) + ws2(500) + margin(50).
-  EXPECT_EQ("0,0 1050x300", contents_view()->bounds().ToString());
-  EXPECT_FALSE(workspace_manager()->is_overview());
-  workspace_manager()->SetOverview(true);
-  EXPECT_TRUE(workspace_manager()->is_overview());
-
-  // Switching overview mode doesn't change the active workspace.
-  EXPECT_EQ(ws2, workspace_manager()->GetActiveWorkspace());
-
-  // Activating window w1 switches the active window and
-  // the mode back to normal mode.
-  ash::ActivateWindow(w1.get());
-  EXPECT_EQ(ws1, workspace_manager()->GetActiveWorkspace());
-  EXPECT_FALSE(workspace_manager()->is_overview());
-
-  // Deleting w1 without StackingClient resets the active workspace
-  ws1->RemoveWindow(w1.get());
-  delete ws1;
-  w1.reset();
-  EXPECT_EQ(ws2, workspace_manager()->GetActiveWorkspace());
-  EXPECT_EQ("0,0 500x300", contents_view()->bounds().ToString());
-  ws2->RemoveWindow(w2.get());
-  delete ws2;
-  // The size of contents_view() for no workspace case must be
-  // same as one contents_view() case.
-  EXPECT_EQ("0,0 500x300", contents_view()->bounds().ToString());
-
-  // Reset now before windows are destroyed.
-  controller_.reset();
-}
-
 }  // namespace internal
 }  // namespace ash
diff --git a/chrome/browser/ui/views/aura/launcher_icon_updater.cc b/chrome/browser/ui/views/aura/launcher_icon_updater.cc
index 94e8cd4f3e0d2..a79c5e59fe4c7 100644
--- a/chrome/browser/ui/views/aura/launcher_icon_updater.cc
+++ b/chrome/browser/ui/views/aura/launcher_icon_updater.cc
@@ -112,6 +112,7 @@ void LauncherIconUpdater::ActivateByID(ash::LauncherID id) {
     NOTREACHED();
     return;
   }
+  updater->window_->Show();
   ash::ActivateWindow(updater->window_);
   if (tab) {
     updater->tab_model_->ActivateTabAt(