window_manager_app.cc revision 1320f92c476a1ad9d19dba2a48c72b75566198e9
1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "mojo/services/window_manager/window_manager_app.h"
6
7#include "base/message_loop/message_loop.h"
8#include "base/stl_util.h"
9#include "mojo/aura/aura_init.h"
10#include "mojo/public/cpp/application/application_connection.h"
11#include "mojo/public/cpp/application/application_impl.h"
12#include "mojo/services/public/cpp/input_events/input_events_type_converters.h"
13#include "mojo/services/public/cpp/view_manager/view.h"
14#include "mojo/services/public/cpp/view_manager/view_manager.h"
15#include "ui/aura/window.h"
16#include "ui/aura/window_delegate.h"
17#include "ui/aura/window_property.h"
18#include "ui/base/hit_test.h"
19#include "ui/wm/core/capture_controller.h"
20#include "ui/wm/core/focus_controller.h"
21#include "ui/wm/core/focus_rules.h"
22#include "ui/wm/public/activation_client.h"
23
24DECLARE_WINDOW_PROPERTY_TYPE(mojo::View*);
25
26namespace mojo {
27
28// The aura::Windows we use to track Views don't render, so we don't actually
29// need to supply a fully functional WindowDelegate. We do need to provide _a_
30// delegate however, otherwise the event dispatcher won't dispatch events to
31// these windows. (The aura WindowTargeter won't allow a delegate-less window
32// to be the target of an event, since the window delegate is considered the
33// "target handler").
34class DummyDelegate : public aura::WindowDelegate {
35 public:
36  DummyDelegate() {}
37  virtual ~DummyDelegate() {}
38
39 private:
40  // WindowDelegate overrides:
41  virtual gfx::Size GetMinimumSize() const OVERRIDE { return gfx::Size(); }
42  virtual gfx::Size GetMaximumSize() const OVERRIDE { return gfx::Size(); }
43  virtual void OnBoundsChanged(const gfx::Rect& old_bounds,
44                               const gfx::Rect& new_bounds) OVERRIDE {}
45  virtual gfx::NativeCursor GetCursor(const gfx::Point& point) OVERRIDE {
46    return gfx::kNullCursor;
47  }
48  virtual int GetNonClientComponent(const gfx::Point& point) const OVERRIDE {
49    return HTCAPTION;
50  }
51  virtual bool ShouldDescendIntoChildForEventHandling(
52      aura::Window* child,
53      const gfx::Point& location) OVERRIDE { return true; }
54  virtual bool CanFocus() OVERRIDE { return true; }
55  virtual void OnCaptureLost() OVERRIDE {}
56  virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE {}
57  virtual void OnDeviceScaleFactorChanged(float device_scale_factor) OVERRIDE {}
58  virtual void OnWindowDestroying(aura::Window* window) OVERRIDE {}
59  virtual void OnWindowDestroyed(aura::Window* window) OVERRIDE {}
60  virtual void OnWindowTargetVisibilityChanged(bool visible) OVERRIDE {}
61  virtual bool HasHitTestMask() const OVERRIDE { return false; }
62  virtual void GetHitTestMask(gfx::Path* mask) const OVERRIDE {}
63
64  DISALLOW_COPY_AND_ASSIGN(DummyDelegate);
65};
66
67namespace {
68
69DEFINE_WINDOW_PROPERTY_KEY(View*, kViewKey, NULL);
70
71Id GetIdForWindow(aura::Window* window) {
72  return window ? WindowManagerApp::GetViewForWindow(window)->id() : 0;
73}
74
75class WMFocusRules : public wm::FocusRules {
76 public:
77  WMFocusRules() {}
78  virtual ~WMFocusRules() {}
79
80 private:
81  // Overridden from wm::FocusRules:
82  virtual bool IsToplevelWindow(aura::Window* window) const MOJO_OVERRIDE {
83    return true;
84  }
85  virtual bool CanActivateWindow(aura::Window* window) const MOJO_OVERRIDE {
86    return true;
87  }
88  virtual bool CanFocusWindow(aura::Window* window) const MOJO_OVERRIDE {
89    return true;
90  }
91  virtual aura::Window* GetToplevelWindow(
92      aura::Window* window) const MOJO_OVERRIDE {
93    return window;
94  }
95  virtual aura::Window* GetActivatableWindow(
96      aura::Window* window) const MOJO_OVERRIDE {
97    return window;
98  }
99  virtual aura::Window* GetFocusableWindow(
100      aura::Window* window) const MOJO_OVERRIDE {
101    return window;
102  }
103  virtual aura::Window* GetNextActivatableWindow(
104      aura::Window* ignore) const MOJO_OVERRIDE {
105    return NULL;
106  }
107
108  DISALLOW_COPY_AND_ASSIGN(WMFocusRules);
109};
110
111}  // namespace
112
113////////////////////////////////////////////////////////////////////////////////
114// WindowManagerApp, public:
115
116WindowManagerApp::WindowManagerApp(
117    ViewManagerDelegate* view_manager_delegate,
118    WindowManagerDelegate* window_manager_delegate)
119    : window_manager_service_factory_(this),
120      wrapped_view_manager_delegate_(view_manager_delegate),
121      wrapped_window_manager_delegate_(window_manager_delegate),
122      view_manager_(NULL),
123      root_(NULL),
124      dummy_delegate_(new DummyDelegate) {
125}
126
127WindowManagerApp::~WindowManagerApp() {}
128
129// static
130View* WindowManagerApp::GetViewForWindow(aura::Window* window) {
131  return window->GetProperty(kViewKey);
132}
133
134void WindowManagerApp::AddConnection(WindowManagerServiceImpl* connection) {
135  DCHECK(connections_.find(connection) == connections_.end());
136  connections_.insert(connection);
137}
138
139void WindowManagerApp::RemoveConnection(WindowManagerServiceImpl* connection) {
140  DCHECK(connections_.find(connection) != connections_.end());
141  connections_.erase(connection);
142}
143
144void WindowManagerApp::SetCapture(Id view) {
145  capture_client_->capture_client()->SetCapture(GetWindowForViewId(view));
146  // TODO(beng): notify connected clients that capture has changed, probably
147  //             by implementing some capture-client observer.
148}
149
150void WindowManagerApp::FocusWindow(Id view) {
151  aura::Window* window = GetWindowForViewId(view);
152  DCHECK(window);
153  focus_client_->FocusWindow(window);
154}
155
156void WindowManagerApp::ActivateWindow(Id view) {
157  aura::Window* window = GetWindowForViewId(view);
158  DCHECK(window);
159  activation_client_->ActivateWindow(window);
160}
161
162bool WindowManagerApp::IsReady() const {
163  return view_manager_ && root_;
164}
165
166////////////////////////////////////////////////////////////////////////////////
167// WindowManagerApp, ApplicationDelegate implementation:
168
169void WindowManagerApp::Initialize(ApplicationImpl* impl) {
170  aura_init_.reset(new AuraInit);
171  view_manager_client_factory_.reset(
172      new ViewManagerClientFactory(impl->shell(), this));
173}
174
175bool WindowManagerApp::ConfigureIncomingConnection(
176    ApplicationConnection* connection) {
177  connection->AddService(&window_manager_service_factory_);
178  connection->AddService(view_manager_client_factory_.get());
179  return true;
180}
181
182////////////////////////////////////////////////////////////////////////////////
183// WindowManagerApp, ViewManagerDelegate implementation:
184
185void WindowManagerApp::OnEmbed(ViewManager* view_manager,
186                               View* root,
187                               ServiceProviderImpl* exported_services,
188                               scoped_ptr<ServiceProvider> imported_services) {
189  DCHECK(!view_manager_ && !root_);
190  view_manager_ = view_manager;
191  view_manager_->SetWindowManagerDelegate(this);
192  root_ = root;
193
194  window_tree_host_.reset(new WindowTreeHostMojo(root_, this));
195  window_tree_host_->window()->SetBounds(root->bounds());
196  window_tree_host_->window()->Show();
197
198  RegisterSubtree(root_, window_tree_host_->window());
199
200  capture_client_.reset(
201      new wm::ScopedCaptureClient(window_tree_host_->window()));
202  wm::FocusController* focus_controller =
203      new wm::FocusController(new WMFocusRules);
204  activation_client_ = focus_controller;
205  focus_client_.reset(focus_controller);
206  aura::client::SetFocusClient(window_tree_host_->window(), focus_controller);
207
208  focus_client_->AddObserver(this);
209  activation_client_->AddObserver(this);
210
211  if (wrapped_view_manager_delegate_) {
212    wrapped_view_manager_delegate_->OnEmbed(
213        view_manager, root, exported_services, imported_services.Pass());
214  }
215
216  for (Connections::const_iterator it = connections_.begin();
217       it != connections_.end(); ++it) {
218    (*it)->NotifyReady();
219  }
220}
221
222void WindowManagerApp::OnViewManagerDisconnected(
223    ViewManager* view_manager) {
224  DCHECK_EQ(view_manager_, view_manager);
225  if (wrapped_view_manager_delegate_)
226    wrapped_view_manager_delegate_->OnViewManagerDisconnected(view_manager);
227  view_manager_ = NULL;
228  base::MessageLoop::current()->Quit();
229}
230
231////////////////////////////////////////////////////////////////////////////////
232// WindowManagerApp, WindowManagerDelegate implementation:
233
234void WindowManagerApp::Embed(
235    const String& url,
236    InterfaceRequest<ServiceProvider> service_provider) {
237  if (wrapped_window_manager_delegate_)
238    wrapped_window_manager_delegate_->Embed(url, service_provider.Pass());
239}
240
241void WindowManagerApp::DispatchEvent(EventPtr event) {
242  scoped_ptr<ui::Event> ui_event = event.To<scoped_ptr<ui::Event> >();
243  if (ui_event)
244    window_tree_host_->SendEventToProcessor(ui_event.get());
245}
246
247////////////////////////////////////////////////////////////////////////////////
248// WindowManagerApp, ViewObserver implementation:
249
250void WindowManagerApp::OnTreeChanged(
251    const ViewObserver::TreeChangeParams& params) {
252  if (params.receiver != root_)
253    return;
254  DCHECK(params.old_parent || params.new_parent);
255  if (!params.target)
256    return;
257
258  if (params.new_parent) {
259    if (view_id_to_window_map_.find(params.target->id()) ==
260        view_id_to_window_map_.end()) {
261      ViewIdToWindowMap::const_iterator it =
262          view_id_to_window_map_.find(params.new_parent->id());
263      DCHECK(it != view_id_to_window_map_.end());
264      RegisterSubtree(params.target, it->second);
265    }
266  } else if (params.old_parent) {
267    UnregisterSubtree(params.target);
268  }
269}
270
271void WindowManagerApp::OnViewDestroyed(View* view) {
272  if (view != root_)
273    return;
274  aura::Window* window = GetWindowForViewId(view->id());
275  window->RemovePreTargetHandler(this);
276  root_ = NULL;
277  STLDeleteValues(&view_id_to_window_map_);
278  if (focus_client_.get())
279    focus_client_->RemoveObserver(this);
280  if (activation_client_)
281    activation_client_->RemoveObserver(this);
282  window_tree_host_.reset();
283}
284
285void WindowManagerApp::OnViewBoundsChanged(View* view,
286                                           const gfx::Rect& old_bounds,
287                                           const gfx::Rect& new_bounds) {
288  aura::Window* window = GetWindowForViewId(view->id());
289  window->SetBounds(new_bounds);
290}
291
292////////////////////////////////////////////////////////////////////////////////
293// WindowManagerApp, WindowTreeHostMojoDelegate implementation:
294
295void WindowManagerApp::CompositorContentsChanged(const SkBitmap& bitmap) {
296  // We draw nothing.
297  NOTREACHED();
298}
299
300////////////////////////////////////////////////////////////////////////////////
301// WindowManagerApp, ui::EventHandler implementation:
302
303void WindowManagerApp::OnEvent(ui::Event* event) {
304  aura::Window* window = static_cast<aura::Window*>(event->target());
305  view_manager_->DispatchEvent(GetViewForWindow(window), Event::From(*event));
306}
307
308////////////////////////////////////////////////////////////////////////////////
309// WindowManagerApp, aura::client::FocusChangeObserver implementation:
310
311void WindowManagerApp::OnWindowFocused(aura::Window* gained_focus,
312                                       aura::Window* lost_focus) {
313  for (Connections::const_iterator it = connections_.begin();
314       it != connections_.end(); ++it) {
315    (*it)->NotifyViewFocused(GetIdForWindow(gained_focus),
316                             GetIdForWindow(lost_focus));
317  }
318}
319
320////////////////////////////////////////////////////////////////////////////////
321// WindowManagerApp, aura::client::ActivationChangeObserver implementation:
322
323void WindowManagerApp::OnWindowActivated(aura::Window* gained_active,
324                                         aura::Window* lost_active) {
325  for (Connections::const_iterator it = connections_.begin();
326       it != connections_.end(); ++it) {
327    (*it)->NotifyWindowActivated(GetIdForWindow(gained_active),
328                                 GetIdForWindow(lost_active));
329  }
330}
331
332////////////////////////////////////////////////////////////////////////////////
333// WindowManagerApp, private:
334
335aura::Window* WindowManagerApp::GetWindowForViewId(Id view) const {
336  ViewIdToWindowMap::const_iterator it = view_id_to_window_map_.find(view);
337  return it != view_id_to_window_map_.end() ? it->second : NULL;
338}
339
340void WindowManagerApp::RegisterSubtree(View* view, aura::Window* parent) {
341  view->AddObserver(this);
342  DCHECK(view_id_to_window_map_.find(view->id()) ==
343         view_id_to_window_map_.end());
344  aura::Window* window = new aura::Window(dummy_delegate_.get());
345  window->set_id(view->id());
346  window->SetProperty(kViewKey, view);
347  // All events pass through the root during dispatch, so we only need a handler
348  // installed there.
349  if (view == root_)
350    window->AddPreTargetHandler(this);
351  parent->AddChild(window);
352  window->SetBounds(view->bounds());
353  window->Show();
354  view_id_to_window_map_[view->id()] = window;
355  View::Children::const_iterator it = view->children().begin();
356  for (; it != view->children().end(); ++it)
357    RegisterSubtree(*it, window);
358}
359
360void WindowManagerApp::UnregisterSubtree(View* view) {
361  view->RemoveObserver(this);
362  ViewIdToWindowMap::iterator it = view_id_to_window_map_.find(view->id());
363  DCHECK(it != view_id_to_window_map_.end());
364  scoped_ptr<aura::Window> window(it->second);
365  view_id_to_window_map_.erase(it);
366  View::Children::const_iterator child = view->children().begin();
367  for (; child != view->children().end(); ++child)
368    UnregisterSubtree(*child);
369}
370
371}  // namespace mojo
372