Adds capture to the mojo window_manager.

This adds a CaptureController which manages capture, puts a checkbox
that makes a window have capture in the wm_flow demo, and ports the
relevant unit tests for FocusController.

BUG=442545
R=sky@chromium.org

Review URL: https://codereview.chromium.org/805123003
diff --git a/examples/wm_flow/wm/frame_controller.cc b/examples/wm_flow/wm/frame_controller.cc
index e391f42..acf608c 100644
--- a/examples/wm_flow/wm/frame_controller.cc
+++ b/examples/wm_flow/wm/frame_controller.cc
@@ -9,8 +9,10 @@
 #include "mojo/converters/geometry/geometry_type_converters.h"
 #include "mojo/services/view_manager/public/cpp/view.h"
 #include "mojo/views/native_widget_mojo.h"
+#include "services/window_manager/capture_controller.h"
 #include "services/window_manager/window_manager_app.h"
 #include "ui/views/background.h"
+#include "ui/views/controls/button/checkbox.h"
 #include "ui/views/controls/button/label_button.h"
 #include "ui/views/layout/layout_manager.h"
 #include "ui/views/widget/widget.h"
@@ -21,10 +23,14 @@
  public:
   explicit LayoutManager(FrameController* controller)
       : controller_(controller),
+        capture_checkbox_(
+            new views::Checkbox(base::ASCIIToUTF16("Capture"))),
         close_button_(
             new views::LabelButton(this, base::ASCIIToUTF16("Begone"))),
         maximize_button_(
-            new views::LabelButton(this, base::ASCIIToUTF16("Embiggen"))) {}
+            new views::LabelButton(this, base::ASCIIToUTF16("Embiggen"))) {
+    capture_checkbox_->set_listener(this);
+  }
   virtual ~LayoutManager() {}
 
  private:
@@ -34,11 +40,16 @@
 
   // Overridden from views::LayoutManager:
   virtual void Installed(views::View* host) override {
+    host->AddChildView(capture_checkbox_);
     host->AddChildView(close_button_);
     host->AddChildView(maximize_button_);
   }
   virtual void Layout(views::View* host) override {
-    gfx::Size ps = close_button_->GetPreferredSize();
+    gfx::Size ps = capture_checkbox_->GetPreferredSize();
+    capture_checkbox_->SetBounds(kButtonFrameMargin, kButtonFrameMargin,
+                                 ps.width(), ps.height());
+
+    ps = close_button_->GetPreferredSize();
     gfx::Rect bounds = host->GetLocalBounds();
     close_button_->SetBounds(bounds.right() - kButtonFrameMargin - ps.width(),
                              kButtonFrameMargin, ps.width(), ps.height());
@@ -64,9 +75,12 @@
       controller_->CloseWindow();
     else if (sender == maximize_button_)
       controller_->ToggleMaximize();
+    else if (sender == capture_checkbox_)
+      controller_->SetCapture(capture_checkbox_->checked());
   }
 
   FrameController* controller_;
+  views::Checkbox* capture_checkbox_;
   views::Button* close_button_;
   views::Button* maximize_button_;
 
@@ -146,6 +160,13 @@
   window_manager_app_->focus_controller()->ActivateView(view_);
 }
 
+void FrameController::SetCapture(bool frame_has_capture) {
+  if (frame_has_capture)
+    window_manager_app_->capture_controller()->SetCapture(view_);
+  else
+    window_manager_app_->capture_controller()->ReleaseCapture(view_);
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // FrameController, mojo::ViewObserver implementation:
 
diff --git a/examples/wm_flow/wm/frame_controller.h b/examples/wm_flow/wm/frame_controller.h
index 440761d..5d6bdf4 100644
--- a/examples/wm_flow/wm/frame_controller.h
+++ b/examples/wm_flow/wm/frame_controller.h
@@ -41,6 +41,8 @@
 
   void ActivateWindow();
 
+  void SetCapture(bool frame_has_capture);
+
  private:
   class LayoutManager;
   friend class LayoutManager;
diff --git a/mojo/services/view_manager/public/cpp/lib/view_manager_client_impl.cc b/mojo/services/view_manager/public/cpp/lib/view_manager_client_impl.cc
index 3ebb4c7..a51e234 100644
--- a/mojo/services/view_manager/public/cpp/lib/view_manager_client_impl.cc
+++ b/mojo/services/view_manager/public/cpp/lib/view_manager_client_impl.cc
@@ -100,6 +100,7 @@
       next_id_(1),
       delegate_(delegate),
       root_(nullptr),
+      capture_view_(nullptr),
       focused_view_(nullptr),
       activated_view_(nullptr),
       binding_(this, handle.Pass()),
@@ -381,7 +382,21 @@
 // ViewManagerClientImpl, WindowManagerClient implementation:
 
 void ViewManagerClientImpl::OnCaptureChanged(Id old_capture_view_id,
-                                             Id new_capture_view_id) {}
+                                             Id new_capture_view_id) {
+  View* gained_capture = GetViewById(new_capture_view_id);
+  View* lost_capture = GetViewById(old_capture_view_id);
+  if (lost_capture) {
+    FOR_EACH_OBSERVER(ViewObserver,
+                      *ViewPrivate(lost_capture).observers(),
+                      OnViewFocusChanged(gained_capture, lost_capture));
+  }
+  capture_view_ = gained_capture;
+  if (gained_capture) {
+    FOR_EACH_OBSERVER(ViewObserver,
+                      *ViewPrivate(gained_capture).observers(),
+                      OnViewFocusChanged(gained_capture, lost_capture));
+  }
+}
 
 void ViewManagerClientImpl::OnFocusChanged(Id old_focused_view_id,
                                            Id new_focused_view_id) {
diff --git a/mojo/services/view_manager/public/cpp/lib/view_manager_client_impl.h b/mojo/services/view_manager/public/cpp/lib/view_manager_client_impl.h
index 2ed83f8..91e4358 100644
--- a/mojo/services/view_manager/public/cpp/lib/view_manager_client_impl.h
+++ b/mojo/services/view_manager/public/cpp/lib/view_manager_client_impl.h
@@ -152,6 +152,7 @@
 
   IdToViewMap views_;
 
+  View* capture_view_;
   View* focused_view_;
   View* activated_view_;
 
diff --git a/mojo/services/view_manager/public/cpp/view.h b/mojo/services/view_manager/public/cpp/view.h
index 8569616..d3c6292 100644
--- a/mojo/services/view_manager/public/cpp/view.h
+++ b/mojo/services/view_manager/public/cpp/view.h
@@ -103,6 +103,9 @@
   View* parent() { return parent_; }
   const View* parent() const { return parent_; }
   const Children& children() const { return children_; }
+  View* GetRoot() {
+    return const_cast<View*>(const_cast<const View*>(this)->GetRoot());
+  }
   const View* GetRoot() const;
 
   void AddChild(View* child);
diff --git a/mojo/services/view_manager/public/cpp/view_observer.h b/mojo/services/view_manager/public/cpp/view_observer.h
index b6b1a70..4f49fbd 100644
--- a/mojo/services/view_manager/public/cpp/view_observer.h
+++ b/mojo/services/view_manager/public/cpp/view_observer.h
@@ -56,6 +56,7 @@
                                    const Rect& old_bounds,
                                    const Rect& new_bounds) {}
 
+  virtual void OnCaptureChanged(View* gained_capture, View* lost_capture) {}
   virtual void OnViewFocusChanged(View* gained_focus, View* lost_focus) {}
   virtual void OnViewActivationChanged(View* gained_active, View* lost_active) {
   }
diff --git a/services/window_manager/BUILD.gn b/services/window_manager/BUILD.gn
index afc86f3..1affe54 100644
--- a/services/window_manager/BUILD.gn
+++ b/services/window_manager/BUILD.gn
@@ -26,6 +26,9 @@
   sources = [
     "basic_focus_rules.cc",
     "basic_focus_rules.h",
+    "capture_controller.cc",
+    "capture_controller.h",
+    "capture_controller_observer.h",
     "focus_controller.cc",
     "focus_controller.h",
     "focus_controller_observer.h",
diff --git a/services/window_manager/capture_controller.cc b/services/window_manager/capture_controller.cc
new file mode 100644
index 0000000..227d92f
--- /dev/null
+++ b/services/window_manager/capture_controller.cc
@@ -0,0 +1,105 @@
+// Copyright 2014 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 "services/window_manager/capture_controller.h"
+
+#include "mojo/services/view_manager/public/cpp/view_property.h"
+#include "mojo/services/view_manager/public/cpp/view_tracker.h"
+#include "services/window_manager/capture_controller_observer.h"
+
+DECLARE_VIEW_PROPERTY_TYPE(window_manager::CaptureController*);
+
+namespace window_manager {
+
+namespace {
+DEFINE_VIEW_PROPERTY_KEY(CaptureController*,
+                         kRootViewCaptureController,
+                         nullptr);
+}  // namespace
+
+CaptureController::CaptureController()
+    : capture_view_(nullptr) {}
+
+CaptureController::~CaptureController() {}
+
+void CaptureController::AddObserver(CaptureControllerObserver* observer) {
+  capture_controller_observers_.AddObserver(observer);
+}
+
+void CaptureController::RemoveObserver(CaptureControllerObserver* observer) {
+  capture_controller_observers_.RemoveObserver(observer);
+}
+
+void CaptureController::SetCapture(mojo::View* view) {
+  if (capture_view_ == view)
+    return;
+
+  if (capture_view_)
+    capture_view_->RemoveObserver(this);
+
+  mojo::View* old_capture_view = capture_view_;
+  capture_view_ = view;
+
+  if (capture_view_)
+    capture_view_->AddObserver(this);
+
+  NotifyCaptureChange(capture_view_, old_capture_view);
+}
+
+void CaptureController::ReleaseCapture(mojo::View* view) {
+  if (capture_view_ != view)
+    return;
+  SetCapture(nullptr);
+}
+
+mojo::View* CaptureController::GetCapture() {
+  return capture_view_;
+}
+
+void CaptureController::NotifyCaptureChange(mojo::View* new_capture,
+                                            mojo::View* old_capture) {
+  mojo::ViewTracker view_tracker;
+  if (new_capture)
+    view_tracker.Add(new_capture);
+  if (old_capture)
+    view_tracker.Add(old_capture);
+
+  FOR_EACH_OBSERVER(
+      CaptureControllerObserver,
+      capture_controller_observers_,
+      OnCaptureChanged(
+          view_tracker.Contains(new_capture) ? new_capture : nullptr,
+          view_tracker.Contains(old_capture) ? old_capture : nullptr));
+}
+
+void CaptureController::OnViewDestroying(mojo::View* view) {
+  if (view == capture_view_) {
+    view->RemoveObserver(this);
+    NotifyCaptureChange(nullptr, view);
+    capture_view_ = nullptr;
+  }
+}
+
+void SetCaptureController(mojo::View* root_view,
+                          CaptureController* capture_controller) {
+  DCHECK_EQ(root_view->GetRoot(), root_view);
+  root_view->SetLocalProperty(kRootViewCaptureController, capture_controller);
+}
+
+CaptureController* GetCaptureController(mojo::View* root_view) {
+  if (root_view)
+    DCHECK_EQ(root_view->GetRoot(), root_view);
+  return root_view ?
+      root_view->GetLocalProperty(kRootViewCaptureController) : nullptr;
+}
+
+mojo::View* GetCaptureView(mojo::View* view) {
+  mojo::View* root = view->GetRoot();
+  if (!root)
+    return nullptr;
+  CaptureController* controller = GetCaptureController(root);
+  return controller ? controller->GetCapture() : nullptr;
+}
+
+}  // namespace window_manager
diff --git a/services/window_manager/capture_controller.h b/services/window_manager/capture_controller.h
new file mode 100644
index 0000000..dc495f5
--- /dev/null
+++ b/services/window_manager/capture_controller.h
@@ -0,0 +1,49 @@
+// Copyright 2014 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 SERVICES_WINDOW_MANAGER_CAPTURE_CONTROLLER_H_
+#define SERVICES_WINDOW_MANAGER_CAPTURE_CONTROLLER_H_
+
+#include "base/observer_list.h"
+#include "mojo/services/view_manager/public/cpp/view_observer.h"
+
+namespace window_manager {
+
+class CaptureControllerObserver;
+
+// Manages input capture. A view which has capture will take all input events.
+class CaptureController : public mojo::ViewObserver {
+ public:
+  CaptureController();
+  ~CaptureController() override;
+
+  void AddObserver(CaptureControllerObserver* observer);
+  void RemoveObserver(CaptureControllerObserver* observer);
+
+  void SetCapture(mojo::View* view);
+  void ReleaseCapture(mojo::View* view);
+  mojo::View* GetCapture();
+
+ private:
+  void NotifyCaptureChange(mojo::View* new_capture, mojo::View* old_capture);
+
+  // Overridden from ViewObserver:
+  void OnViewDestroying(mojo::View* view) override;
+
+  // The current capture view. Null if there is no capture view.
+  mojo::View* capture_view_;
+
+  ObserverList<CaptureControllerObserver> capture_controller_observers_;
+
+  DISALLOW_COPY_AND_ASSIGN(CaptureController);
+};
+
+void SetCaptureController(mojo::View* view,
+                          CaptureController* capture_controller);
+CaptureController* GetCaptureController(mojo::View* view);
+mojo::View* GetCaptureView(mojo::View* view);
+
+}  // namespace window_manager
+
+#endif  // SERVICES_WINDOW_MANAGER_CAPTURE_CONTROLLER_H_
diff --git a/services/window_manager/capture_controller_observer.h b/services/window_manager/capture_controller_observer.h
new file mode 100644
index 0000000..ba3ec3b
--- /dev/null
+++ b/services/window_manager/capture_controller_observer.h
@@ -0,0 +1,21 @@
+// Copyright 2014 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 SERVICES_WINDOW_MANAGER_CAPTURE_CONTROLLER_OBSERVER_H_
+#define SERVICES_WINDOW_MANAGER_CAPTURE_CONTROLLER_OBSERVER_H_
+
+namespace window_manager {
+
+class CaptureControllerObserver {
+ public:
+  virtual void OnCaptureChanged(mojo::View* gained_capture,
+                                mojo::View* lost_capture) = 0;
+
+ protected:
+  virtual ~CaptureControllerObserver() {}
+};
+
+}  // namespace window_manager
+
+#endif // SERVICES_WINDOW_MANAGER_CAPTURE_CONTROLLER_OBSERVER_H_
diff --git a/services/window_manager/focus_controller.cc b/services/window_manager/focus_controller.cc
index ba6454a..e58dca8 100644
--- a/services/window_manager/focus_controller.cc
+++ b/services/window_manager/focus_controller.cc
@@ -74,9 +74,6 @@
     return;
   }
 
-  // TODO(erg): We need to early abort in the of a view having
-  // capture. However, we currently don't have a capture client here.
-
   // Focusing a window also activates its containing activatable window. Note
   // that the rules could redirect activation activation and/or focus.
   View* focusable = rules_->GetFocusableView(view);
diff --git a/services/window_manager/focus_controller.h b/services/window_manager/focus_controller.h
index f212123..20f966e 100644
--- a/services/window_manager/focus_controller.h
+++ b/services/window_manager/focus_controller.h
@@ -93,7 +93,7 @@
   DISALLOW_COPY_AND_ASSIGN(FocusController);
 };
 
-// Sets/Gets the focus controller for a root view.
+// Sets/Gets the focus controller for a view.
 void SetFocusController(mojo::View* view, FocusController* focus_controller);
 FocusController* GetFocusController(mojo::View* view);
 
diff --git a/services/window_manager/focus_controller_unittest.cc b/services/window_manager/focus_controller_unittest.cc
index 13e841d..7dacf03 100644
--- a/services/window_manager/focus_controller_unittest.cc
+++ b/services/window_manager/focus_controller_unittest.cc
@@ -6,6 +6,7 @@
 
 #include "mojo/converters/geometry/geometry_type_converters.h"
 #include "services/window_manager/basic_focus_rules.h"
+#include "services/window_manager/capture_controller.h"
 #include "services/window_manager/focus_controller_observer.h"
 #include "services/window_manager/view_event_dispatcher.h"
 #include "services/window_manager/view_targeter.h"
@@ -347,6 +348,10 @@
     test_focus_rules_ = new TestFocusRules(root_view());
     focus_controller_.reset(
         new FocusController(scoped_ptr<FocusRules>(test_focus_rules_)));
+    SetFocusController(root_view(), focus_controller_.get());
+
+    capture_controller_.reset(new CaptureController);
+    SetCaptureController(root_view(), capture_controller_.get());
 
     ViewTarget* root_target = root_view_->target();
     root_target->SetEventTargeter(scoped_ptr<ViewTargeter>(new ViewTargeter()));
@@ -362,6 +367,7 @@
 
     root_view_->Destroy();
 
+    capture_controller_.reset();
     test_focus_rules_ = nullptr;  // Owned by FocusController.
     focus_controller_.reset();
 
@@ -410,6 +416,7 @@
   View* root_view() { return root_view_; }
   TestFocusRules* test_focus_rules() { return test_focus_rules_; }
   FocusController* focus_controller() { return focus_controller_.get(); }
+  CaptureController* capture_controller() { return capture_controller_.get(); }
 
   // Test functions.
   virtual void BasicFocus() = 0;
@@ -427,9 +434,7 @@
   virtual void ShiftFocusOnActivation() {}
   virtual void ShiftFocusOnActivationDueToHide() {}
   virtual void NoShiftActiveOnActivation() {}
-  // TODO(erg): void NoFocusChangeOnClickOnCaptureWindow() once we have a
-  // system of capture.
-  // TODO(erg): Also, void ChangeFocusWhenNothingFocusedAndCaptured().
+  virtual void ChangeFocusWhenNothingFocusedAndCaptured() {}
   virtual void DontPassDestroyedView() {}
   // TODO(erg): Also, void FocusedTextInputClient() once we build the IME.
 
@@ -437,6 +442,7 @@
   TestView* root_view_;
   scoped_ptr<FocusController> focus_controller_;
   TestFocusRules* test_focus_rules_;
+  scoped_ptr<CaptureController> capture_controller_;
   // TODO(erg): The aura version of this class also keeps track of WMState. Do
   // we need something analogous here?
 
@@ -723,7 +729,21 @@
     // from being made in response to an activation change notification.
   }
 
-  // TODO(erg): Port the capture tests here, once we have a capture mechanism.
+  // Verifies focus change is honored while capture held.
+  void ChangeFocusWhenNothingFocusedAndCaptured() override {
+    View* v1 = root_view()->GetChildById(1);
+    capture_controller()->SetCapture(v1);
+
+    EXPECT_EQ(-1, GetActiveViewId());
+    EXPECT_EQ(-1, GetFocusedViewId());
+
+    FocusViewById(1);
+
+    EXPECT_EQ(1, GetActiveViewId());
+    EXPECT_EQ(1, GetFocusedViewId());
+
+    capture_controller()->ReleaseCapture(v1);
+  }
 
   // Verifies if a view that loses activation or focus is destroyed during
   // observer notification we don't pass the destroyed view to other observers.
@@ -1122,7 +1142,8 @@
 DIRECT_FOCUS_CHANGE_TESTS(ShiftFocusOnActivationDueToHide);
 DIRECT_FOCUS_CHANGE_TESTS(NoShiftActiveOnActivation);
 
-// TODO(erg): Add the capture tests here.
+FOCUS_CONTROLLER_TEST(FocusControllerApiTest,
+                      ChangeFocusWhenNothingFocusedAndCaptured);
 
 // See description above DontPassDestroyedView() for details.
 FOCUS_CONTROLLER_TEST(FocusControllerApiTest, DontPassDestroyedView);
diff --git a/services/window_manager/view_targeter.cc b/services/window_manager/view_targeter.cc
index ab822ff..5a2de7b 100644
--- a/services/window_manager/view_targeter.cc
+++ b/services/window_manager/view_targeter.cc
@@ -4,6 +4,7 @@
 
 #include "services/window_manager/view_targeter.h"
 
+#include "services/window_manager/capture_controller.h"
 #include "services/window_manager/focus_controller.h"
 #include "services/window_manager/view_target.h"
 
@@ -85,8 +86,12 @@
   // mouse_pressed_handler() in the aura version. This is what makes sure
   // that a view gets both the mouse down and up.
 
-  // TODO(erg): We redirect to a currently active capture window here. Add this
-  // when we have capture working.
+  CaptureController* capture_controller =
+      GetCaptureController(root_view->view());
+  DCHECK(capture_controller);
+  mojo::View* capture_view = capture_controller->GetCapture();
+  if (capture_view)
+    return ViewTarget::TargetFromView(capture_view);
 
   // TODO(erg): There's a whole bunch of junk about handling touch events
   // here. Handle later.
diff --git a/services/window_manager/view_targeter_unittest.cc b/services/window_manager/view_targeter_unittest.cc
index a55ef75..298ce27 100644
--- a/services/window_manager/view_targeter_unittest.cc
+++ b/services/window_manager/view_targeter_unittest.cc
@@ -5,6 +5,7 @@
 #include "services/window_manager/view_targeter.h"
 
 #include "services/window_manager/basic_focus_rules.h"
+#include "services/window_manager/capture_controller.h"
 #include "services/window_manager/focus_controller.h"
 #include "services/window_manager/view_event_dispatcher.h"
 #include "services/window_manager/window_manager_test_util.h"
@@ -41,6 +42,9 @@
   root_target->SetEventTargeter(scoped_ptr<ViewTargeter>(new ViewTargeter()));
   view_event_dispatcher_->SetRootViewTarget(root_target);
 
+  CaptureController capture_controller;
+  SetCaptureController(&root, &capture_controller);
+
   TestView one(2, gfx::Rect(0, 0, 500, 100));
   TestView two(3, gfx::Rect(501, 0, 500, 1000));
 
@@ -68,6 +72,9 @@
   root_target->SetEventTargeter(scoped_ptr<ViewTargeter>(new ViewTargeter()));
   view_event_dispatcher_->SetRootViewTarget(root_target);
 
+  CaptureController capture_controller;
+  SetCaptureController(&root, &capture_controller);
+
   TestView one(2, gfx::Rect(0, 0, 500, 100));
   TestView two(3, gfx::Rect(501, 0, 500, 1000));
 
diff --git a/services/window_manager/window_manager_app.cc b/services/window_manager/window_manager_app.cc
index 023af5f..2c25e2b 100644
--- a/services/window_manager/window_manager_app.cc
+++ b/services/window_manager/window_manager_app.cc
@@ -13,6 +13,7 @@
 #include "mojo/public/interfaces/application/shell.mojom.h"
 #include "mojo/services/view_manager/public/cpp/view.h"
 #include "mojo/services/view_manager/public/cpp/view_manager.h"
+#include "services/window_manager/capture_controller.h"
 #include "services/window_manager/focus_controller.h"
 #include "services/window_manager/focus_rules.h"
 #include "services/window_manager/view_event_dispatcher.h"
@@ -72,13 +73,10 @@
   connections_.erase(connection);
 }
 
-void WindowManagerApp::SetCapture(Id view) {
-  // TODO(erg): Capture. Another pile of worms that is mixed in here.
-
-  // capture_client_->capture_client()->SetCapture(GetWindowForViewId(view));
-
-  // TODO(beng): notify connected clients that capture has changed, probably
-  //             by implementing some capture-client observer.
+void WindowManagerApp::SetCapture(Id view_id) {
+  View* view = view_manager_->GetViewById(view_id);
+  DCHECK(view);
+  capture_controller_->SetCapture(view);
 }
 
 void WindowManagerApp::FocusWindow(Id view_id) {
@@ -98,11 +96,15 @@
 }
 
 void WindowManagerApp::InitFocus(scoped_ptr<FocusRules> rules) {
+  DCHECK(root_);
+
   focus_controller_.reset(new FocusController(rules.Pass()));
   focus_controller_->AddObserver(this);
-
-  DCHECK(root_);
   SetFocusController(root_, focus_controller_.get());
+
+  capture_controller_.reset(new CaptureController);
+  capture_controller_->AddObserver(this);
+  SetCaptureController(root_, capture_controller_.get());
 }
 
 void WindowManagerApp::Embed(
@@ -147,11 +149,6 @@
 
   RegisterSubtree(root_);
 
-  // TODO(erg): Also move the capture client over.
-  //
-  // capture_client_.reset(
-  //     new wm::ScopedCaptureClient(window_tree_host_->window()));
-
   if (wrapped_view_manager_delegate_) {
     wrapped_view_manager_delegate_->OnEmbed(
         view_manager, root, exported_services, imported_services.Pass());
@@ -203,6 +200,8 @@
   root_ = nullptr;
   if (focus_controller_)
     focus_controller_->RemoveObserver(this);
+  if (capture_controller_)
+    capture_controller_->RemoveObserver(this);
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -247,6 +246,20 @@
 }
 
 ////////////////////////////////////////////////////////////////////////////////
+// WindowManagerApp, mojo::CaptureControllerObserver implementation:
+
+void WindowManagerApp::OnCaptureChanged(View* gained_capture,
+                                        View* lost_capture) {
+  for (Connections::const_iterator it = connections_.begin();
+       it != connections_.end(); ++it) {
+    (*it)->NotifyCaptureChanged(GetIdForView(gained_capture),
+                                GetIdForView(lost_capture));
+  }
+  if (gained_capture)
+    gained_capture->MoveToFront();
+}
+
+////////////////////////////////////////////////////////////////////////////////
 // WindowManagerApp, private:
 
 void WindowManagerApp::RegisterSubtree(View* view) {
diff --git a/services/window_manager/window_manager_app.h b/services/window_manager/window_manager_app.h
index 5a97037..e866c38 100644
--- a/services/window_manager/window_manager_app.h
+++ b/services/window_manager/window_manager_app.h
@@ -18,6 +18,7 @@
 #include "mojo/services/view_manager/public/cpp/view_manager_delegate.h"
 #include "mojo/services/view_manager/public/cpp/view_observer.h"
 #include "mojo/services/window_manager/public/interfaces/window_manager_internal.mojom.h"
+#include "services/window_manager/capture_controller_observer.h"
 #include "services/window_manager/focus_controller_observer.h"
 #include "services/window_manager/native_viewport_event_dispatcher_impl.h"
 #include "services/window_manager/view_target.h"
@@ -30,6 +31,7 @@
 
 namespace window_manager {
 
+class CaptureController;
 class FocusController;
 class FocusRules;
 class ViewEventDispatcher;
@@ -51,6 +53,7 @@
       public mojo::ViewObserver,
       public ui::EventHandler,
       public FocusControllerObserver,
+      public CaptureControllerObserver,
       public mojo::InterfaceFactory<mojo::WindowManager>,
       public mojo::InterfaceFactory<mojo::WindowManagerInternal>,
       public mojo::WindowManagerInternal {
@@ -78,6 +81,7 @@
   bool IsReady() const;
 
   FocusController* focus_controller() { return focus_controller_.get(); }
+  CaptureController* capture_controller() { return capture_controller_.get(); }
 
   void InitFocus(scoped_ptr<FocusRules> rules);
 
@@ -132,6 +136,10 @@
   void OnViewActivated(mojo::View* gained_active,
                        mojo::View* lost_active) override;
 
+  // Overridden from mojo::CaptureControllerObserver:
+  void OnCaptureChanged(mojo::View* gained_capture,
+                        mojo::View* lost_capture) override;
+
   // Creates the connection to the ViewManager.
   void LaunchViewManager(mojo::ApplicationImpl* app);
 
@@ -163,6 +171,7 @@
   mojo::View* root_;
 
   scoped_ptr<FocusController> focus_controller_;
+  scoped_ptr<CaptureController> capture_controller_;
 
   Connections connections_;
   RegisteredViewIdSet registered_view_id_set_;
diff --git a/services/window_manager/window_manager_impl.cc b/services/window_manager/window_manager_impl.cc
index 2af9ffe..1cba820 100644
--- a/services/window_manager/window_manager_impl.cc
+++ b/services/window_manager/window_manager_impl.cc
@@ -41,6 +41,12 @@
     client()->OnActiveWindowChanged(old_active_id, new_active_id);
 }
 
+void WindowManagerImpl::NotifyCaptureChanged(Id new_capture_id,
+                                             Id old_capture_id) {
+  if (from_vm_)
+    client()->OnCaptureChanged(old_capture_id, new_capture_id);
+}
+
 void WindowManagerImpl::Embed(
     const mojo::String& url,
     mojo::InterfaceRequest<mojo::ServiceProvider> service_provider) {
diff --git a/services/window_manager/window_manager_impl.h b/services/window_manager/window_manager_impl.h
index 3b010cc..f433378 100644
--- a/services/window_manager/window_manager_impl.h
+++ b/services/window_manager/window_manager_impl.h
@@ -29,6 +29,7 @@
 
   void NotifyViewFocused(mojo::Id new_focused_id, mojo::Id old_focused_id);
   void NotifyWindowActivated(mojo::Id new_active_id, mojo::Id old_active_id);
+  void NotifyCaptureChanged(mojo::Id new_capture_id, mojo::Id old_capture_id);
 
  private:
   mojo::WindowManagerClient* client() {