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 "athena/screen/public/screen_manager.h"
6
7 #include "athena/input/public/accelerator_manager.h"
8 #include "athena/screen/screen_accelerator_handler.h"
9 #include "athena/util/container_priorities.h"
10 #include "athena/util/fill_layout_manager.h"
11 #include "base/logging.h"
12 #include "base/memory/scoped_ptr.h"
13 #include "ui/aura/client/screen_position_client.h"
14 #include "ui/aura/client/window_tree_client.h"
15 #include "ui/aura/layout_manager.h"
16 #include "ui/aura/test/test_screen.h"
17 #include "ui/aura/window.h"
18 #include "ui/aura/window_property.h"
19 #include "ui/aura/window_targeter.h"
20 #include "ui/aura/window_tree_host.h"
21 #include "ui/compositor/layer.h"
22 #include "ui/gfx/display.h"
23 #include "ui/gfx/screen.h"
24 #include "ui/wm/core/base_focus_rules.h"
25 #include "ui/wm/core/capture_controller.h"
26 #include "ui/wm/core/focus_controller.h"
27 #include "ui/wm/core/window_util.h"
28
29 namespace athena {
30 namespace {
31
32 DEFINE_OWNED_WINDOW_PROPERTY_KEY(ScreenManager::ContainerParams,
33 kContainerParamsKey,
34 NULL);
35
36 ScreenManager* instance = NULL;
37
GrabsInput(aura::Window * container)38 bool GrabsInput(aura::Window* container) {
39 ScreenManager::ContainerParams* params =
40 container->GetProperty(kContainerParamsKey);
41 return params && params->grab_inputs;
42 }
43
44 // Returns the container which contains |window|.
GetContainer(aura::Window * window)45 aura::Window* GetContainer(aura::Window* window) {
46 aura::Window* container = window;
47 while (container && !container->GetProperty(kContainerParamsKey))
48 container = container->parent();
49 return container;
50 }
51
52 class AthenaFocusRules : public wm::BaseFocusRules {
53 public:
AthenaFocusRules()54 AthenaFocusRules() {}
~AthenaFocusRules()55 virtual ~AthenaFocusRules() {}
56
57 // wm::BaseFocusRules:
SupportsChildActivation(aura::Window * window) const58 virtual bool SupportsChildActivation(aura::Window* window) const OVERRIDE {
59 ScreenManager::ContainerParams* params =
60 window->GetProperty(kContainerParamsKey);
61 return params && params->can_activate_children;
62 }
CanActivateWindow(aura::Window * window) const63 virtual bool CanActivateWindow(aura::Window* window) const OVERRIDE {
64 // Check if containers of higher z-order than |window| have 'grab_inputs'
65 // fields.
66 if (window) {
67 const aura::Window::Windows& containers =
68 window->GetRootWindow()->children();
69 aura::Window::Windows::const_iterator iter =
70 std::find(containers.begin(), containers.end(), GetContainer(window));
71 DCHECK(iter != containers.end());
72 for (++iter; iter != containers.end(); ++iter) {
73 if (GrabsInput(*iter))
74 return false;
75 }
76 }
77 return BaseFocusRules::CanActivateWindow(window);
78 }
79
80 private:
81 DISALLOW_COPY_AND_ASSIGN(AthenaFocusRules);
82 };
83
84 class AthenaWindowTreeClient : public aura::client::WindowTreeClient {
85 public:
AthenaWindowTreeClient(aura::Window * container)86 explicit AthenaWindowTreeClient(aura::Window* container)
87 : container_(container) {}
88
89 private:
~AthenaWindowTreeClient()90 virtual ~AthenaWindowTreeClient() {}
91
92 // aura::client::WindowTreeClient:
GetDefaultParent(aura::Window * context,aura::Window * window,const gfx::Rect & bounds)93 virtual aura::Window* GetDefaultParent(aura::Window* context,
94 aura::Window* window,
95 const gfx::Rect& bounds) OVERRIDE {
96 aura::Window* transient_parent = wm::GetTransientParent(window);
97 if (transient_parent)
98 return GetContainer(transient_parent);
99 return container_;
100 }
101
102 aura::Window* container_;
103
104 DISALLOW_COPY_AND_ASSIGN(AthenaWindowTreeClient);
105 };
106
107 class AthenaScreenPositionClient : public aura::client::ScreenPositionClient {
108 public:
AthenaScreenPositionClient()109 AthenaScreenPositionClient() {
110 }
~AthenaScreenPositionClient()111 virtual ~AthenaScreenPositionClient() {
112 }
113
114 private:
115 // aura::client::ScreenPositionClient:
ConvertPointToScreen(const aura::Window * window,gfx::Point * point)116 virtual void ConvertPointToScreen(const aura::Window* window,
117 gfx::Point* point) OVERRIDE {
118 const aura::Window* root = window->GetRootWindow();
119 aura::Window::ConvertPointToTarget(window, root, point);
120 }
121
ConvertPointFromScreen(const aura::Window * window,gfx::Point * point)122 virtual void ConvertPointFromScreen(const aura::Window* window,
123 gfx::Point* point) OVERRIDE {
124 const aura::Window* root = window->GetRootWindow();
125 aura::Window::ConvertPointToTarget(root, window, point);
126 }
127
ConvertHostPointToScreen(aura::Window * window,gfx::Point * point)128 virtual void ConvertHostPointToScreen(aura::Window* window,
129 gfx::Point* point) OVERRIDE {
130 // TODO(oshima): Implement this when adding multiple display support.
131 NOTREACHED();
132 }
133
SetBounds(aura::Window * window,const gfx::Rect & bounds,const gfx::Display & display)134 virtual void SetBounds(aura::Window* window,
135 const gfx::Rect& bounds,
136 const gfx::Display& display) OVERRIDE {
137 window->SetBounds(bounds);
138 }
139
140 DISALLOW_COPY_AND_ASSIGN(AthenaScreenPositionClient);
141 };
142
143 class AthenaEventTargeter : public aura::WindowTargeter,
144 public aura::WindowObserver {
145 public:
AthenaEventTargeter(aura::Window * container)146 explicit AthenaEventTargeter(aura::Window* container)
147 : container_(container) {
148 container_->AddObserver(this);
149 }
150
~AthenaEventTargeter()151 virtual ~AthenaEventTargeter() {
152 // Removed before the container is removed.
153 if (container_)
154 container_->RemoveObserver(this);
155 }
156
157 private:
158 // aura::WindowTargeter:
SubtreeCanAcceptEvent(ui::EventTarget * target,const ui::LocatedEvent & event) const159 virtual bool SubtreeCanAcceptEvent(
160 ui::EventTarget* target,
161 const ui::LocatedEvent& event) const OVERRIDE {
162 aura::Window* window = static_cast<aura::Window*>(target);
163 const aura::Window::Windows& containers =
164 container_->GetRootWindow()->children();
165 aura::Window::Windows::const_iterator iter =
166 std::find(containers.begin(), containers.end(), container_);
167 DCHECK(iter != containers.end());
168 for (; iter != containers.end(); ++iter) {
169 if ((*iter)->Contains(window))
170 return true;
171 }
172 return false;
173 }
174
175 // aura::WindowObserver:
OnWindowDestroying(aura::Window * window)176 virtual void OnWindowDestroying(aura::Window* window) OVERRIDE {
177 aura::Window* root_window = container_->GetRootWindow();
178 DCHECK_EQ(window, container_);
179 DCHECK_EQ(
180 this, static_cast<ui::EventTarget*>(root_window)->GetEventTargeter());
181
182 container_->RemoveObserver(this);
183 container_ = NULL;
184
185 // This will remove myself.
186 root_window->SetEventTargeter(scoped_ptr<ui::EventTargeter>());
187 }
188
189 aura::Window* container_;
190
191 DISALLOW_COPY_AND_ASSIGN(AthenaEventTargeter);
192 };
193
194 class ScreenManagerImpl : public ScreenManager {
195 public:
196 explicit ScreenManagerImpl(aura::Window* root_window);
197 virtual ~ScreenManagerImpl();
198
199 void Init();
200
201 private:
202 // ScreenManager:
203 virtual aura::Window* CreateDefaultContainer(
204 const ContainerParams& params) OVERRIDE;
205 virtual aura::Window* CreateContainer(const ContainerParams& params) OVERRIDE;
GetContext()206 virtual aura::Window* GetContext() OVERRIDE { return root_window_; }
207 virtual void SetRotation(gfx::Display::Rotation rotation) OVERRIDE;
208 virtual void SetRotationLocked(bool rotation_locked) OVERRIDE;
209
210 // Not owned.
211 aura::Window* root_window_;
212
213 scoped_ptr<aura::client::FocusClient> focus_client_;
214 scoped_ptr<aura::client::WindowTreeClient> window_tree_client_;
215 scoped_ptr<AcceleratorHandler> accelerator_handler_;
216 scoped_ptr< ::wm::ScopedCaptureClient> capture_client_;
217 scoped_ptr<aura::client::ScreenPositionClient> screen_position_client_;
218
219 gfx::Display::Rotation last_requested_rotation_;
220 bool rotation_locked_;
221
222 DISALLOW_COPY_AND_ASSIGN(ScreenManagerImpl);
223 };
224
ScreenManagerImpl(aura::Window * root_window)225 ScreenManagerImpl::ScreenManagerImpl(aura::Window* root_window)
226 : root_window_(root_window),
227 last_requested_rotation_(gfx::Display::ROTATE_0),
228 rotation_locked_(false) {
229 DCHECK(root_window_);
230 DCHECK(!instance);
231 instance = this;
232 }
233
~ScreenManagerImpl()234 ScreenManagerImpl::~ScreenManagerImpl() {
235 aura::client::SetScreenPositionClient(root_window_, NULL);
236 aura::client::SetWindowTreeClient(root_window_, NULL);
237 wm::FocusController* focus_controller =
238 static_cast<wm::FocusController*>(focus_client_.get());
239 root_window_->RemovePreTargetHandler(focus_controller);
240 aura::client::SetActivationClient(root_window_, NULL);
241 aura::client::SetFocusClient(root_window_, NULL);
242 aura::Window::Windows children = root_window_->children();
243 // Close All children:
244 for (aura::Window::Windows::iterator iter = children.begin();
245 iter != children.end();
246 ++iter) {
247 delete *iter;
248 }
249 instance = NULL;
250 }
251
Init()252 void ScreenManagerImpl::Init() {
253 wm::FocusController* focus_controller =
254 new wm::FocusController(new AthenaFocusRules());
255
256 aura::client::SetFocusClient(root_window_, focus_controller);
257 root_window_->AddPreTargetHandler(focus_controller);
258 aura::client::SetActivationClient(root_window_, focus_controller);
259 focus_client_.reset(focus_controller);
260
261 root_window_->SetLayoutManager(new FillLayoutManager(root_window_));
262 capture_client_.reset(new ::wm::ScopedCaptureClient(root_window_));
263 accelerator_handler_.reset(new ScreenAcceleratorHandler(root_window_));
264 }
265
CreateDefaultContainer(const ContainerParams & params)266 aura::Window* ScreenManagerImpl::CreateDefaultContainer(
267 const ContainerParams& params) {
268 aura::Window* container = CreateContainer(params);
269 window_tree_client_.reset(new AthenaWindowTreeClient(container));
270 aura::client::SetWindowTreeClient(root_window_, window_tree_client_.get());
271
272 screen_position_client_.reset(new AthenaScreenPositionClient());
273 aura::client::SetScreenPositionClient(root_window_,
274 screen_position_client_.get());
275
276 return container;
277 }
278
279 // A functor to find a container that has the higher priority.
280 struct HigherPriorityFinder {
HigherPriorityFinderathena::__anonf43701900111::HigherPriorityFinder281 HigherPriorityFinder(int p) : priority(p) {}
operator ()athena::__anonf43701900111::HigherPriorityFinder282 bool operator()(aura::Window* window) {
283 return window->GetProperty(kContainerParamsKey)->z_order_priority >
284 priority;
285 }
286 int priority;
287 };
288
289 #if !defined(NDEBUG)
290 struct PriorityMatcher {
PriorityMatcherathena::__anonf43701900111::PriorityMatcher291 PriorityMatcher(int p) : priority(p) {}
operator ()athena::__anonf43701900111::PriorityMatcher292 bool operator()(aura::Window* window) {
293 return window->GetProperty(kContainerParamsKey)->z_order_priority ==
294 priority;
295 }
296 int priority;
297 };
298 #endif
299
CreateContainer(const ContainerParams & params)300 aura::Window* ScreenManagerImpl::CreateContainer(
301 const ContainerParams& params) {
302 aura::Window* container = new aura::Window(NULL);
303 CHECK_GE(params.z_order_priority, 0);
304 container->Init(aura::WINDOW_LAYER_NOT_DRAWN);
305 container->SetName(params.name);
306
307 const aura::Window::Windows& children = root_window_->children();
308
309 #if !defined(NDEBUG)
310 DCHECK(std::find_if(children.begin(),
311 children.end(),
312 PriorityMatcher(params.z_order_priority))
313 == children.end())
314 << "The container with the priority "
315 << params.z_order_priority << " already exists.";
316 #endif
317
318 container->SetProperty(kContainerParamsKey, new ContainerParams(params));
319
320 // If another container is already grabbing the input, SetEventTargeter
321 // implicitly release the grabbing and remove the EventTargeter instance.
322 // TODO(mukai|oshima): think about the ideal behavior of multiple grabbing
323 // and implement it.
324 if (params.grab_inputs) {
325 DCHECK(std::find_if(children.begin(), children.end(), &GrabsInput)
326 == children.end())
327 << "input has already been grabbed by another container";
328 root_window_->SetEventTargeter(
329 scoped_ptr<ui::EventTargeter>(new AthenaEventTargeter(container)));
330 }
331
332 root_window_->AddChild(container);
333
334 aura::Window::Windows::const_iterator iter =
335 std::find_if(children.begin(),
336 children.end(),
337 HigherPriorityFinder(params.z_order_priority));
338 if (iter != children.end())
339 root_window_->StackChildBelow(container, *iter);
340
341 container->Show();
342 return container;
343 }
344
SetRotation(gfx::Display::Rotation rotation)345 void ScreenManagerImpl::SetRotation(gfx::Display::Rotation rotation) {
346 last_requested_rotation_ = rotation;
347 if (rotation_locked_ || rotation ==
348 gfx::Screen::GetNativeScreen()->GetPrimaryDisplay().rotation()) {
349 return;
350 }
351
352 // TODO(flackr): Use display manager to update display rotation:
353 // http://crbug.com/401044.
354 static_cast<aura::TestScreen*>(gfx::Screen::GetNativeScreen())->
355 SetDisplayRotation(rotation);
356 }
357
SetRotationLocked(bool rotation_locked)358 void ScreenManagerImpl::SetRotationLocked(bool rotation_locked) {
359 rotation_locked_ = rotation_locked;
360 if (!rotation_locked_)
361 SetRotation(last_requested_rotation_);
362 }
363
364 } // namespace
365
ContainerParams(const std::string & n,int priority)366 ScreenManager::ContainerParams::ContainerParams(const std::string& n,
367 int priority)
368 : name(n),
369 can_activate_children(false),
370 grab_inputs(false),
371 z_order_priority(priority) {
372 }
373
374 // static
Create(aura::Window * root_window)375 ScreenManager* ScreenManager::Create(aura::Window* root_window) {
376 (new ScreenManagerImpl(root_window))->Init();
377 DCHECK(instance);
378 return instance;
379 }
380
381 // static
Get()382 ScreenManager* ScreenManager::Get() {
383 DCHECK(instance);
384 return instance;
385 }
386
387 // static
Shutdown()388 void ScreenManager::Shutdown() {
389 DCHECK(instance);
390 delete instance;
391 DCHECK(!instance);
392 }
393
394 } // namespace athena
395