Roll leveldb 3f7758:803d69 (v1.17 -> v1.18)
[chromium-blink-merge.git] / athena / screen / screen_manager_impl.cc
blob8f960eb442413207454b9e9b8d0d4e6c7ddad8e0
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.
5 #include "athena/screen/screen_manager_impl.h"
7 #include "athena/input/public/accelerator_manager.h"
8 #include "athena/screen/modal_window_controller.h"
9 #include "athena/screen/screen_accelerator_handler.h"
10 #include "athena/util/container_priorities.h"
11 #include "base/logging.h"
12 #include "base/memory/scoped_ptr.h"
13 #include "ui/aura/client/aura_constants.h"
14 #include "ui/aura/client/screen_position_client.h"
15 #include "ui/aura/test/test_screen.h"
16 #include "ui/aura/window.h"
17 #include "ui/aura/window_property.h"
18 #include "ui/aura/window_targeter.h"
19 #include "ui/aura/window_tree_host.h"
20 #include "ui/gfx/display.h"
21 #include "ui/gfx/screen.h"
22 #include "ui/wm/core/base_focus_rules.h"
23 #include "ui/wm/core/capture_controller.h"
24 #include "ui/wm/core/default_screen_position_client.h"
25 #include "ui/wm/core/focus_controller.h"
26 #include "ui/wm/core/window_util.h"
28 // This is to avoid creating type definitoin for kAlwaysOnTopKey.
29 DECLARE_EXPORTED_WINDOW_PROPERTY_TYPE(ATHENA_EXPORT, bool);
31 namespace athena {
32 namespace {
34 DEFINE_OWNED_WINDOW_PROPERTY_KEY(ScreenManager::ContainerParams,
35 kContainerParamsKey,
36 nullptr);
38 ScreenManagerImpl* instance = nullptr;
40 // A functor to find a container that has the higher priority.
41 struct HigherPriorityFinder {
42 HigherPriorityFinder(int p) : priority(p) {}
43 bool operator()(aura::Window* window) {
44 return window->GetProperty(kContainerParamsKey)->z_order_priority >
45 priority;
47 int priority;
50 bool BlockEvents(aura::Window* container) {
51 ScreenManager::ContainerParams* params =
52 container->GetProperty(kContainerParamsKey);
53 return params && params->block_events && container->IsVisible();
56 bool DefaultContainer(aura::Window* container) {
57 ScreenManager::ContainerParams* params =
58 container->GetProperty(kContainerParamsKey);
59 return params && params->default_parent;
62 bool HasModalContainerPriority(aura::Window* container) {
63 ScreenManager::ContainerParams* params =
64 container->GetProperty(kContainerParamsKey);
65 return params && params->modal_container_priority != -1;
68 bool IsSystemModal(aura::Window* window) {
69 return window->GetProperty(aura::client::kModalKey) == ui::MODAL_TYPE_SYSTEM;
72 // Returns the container which contains |window|.
73 aura::Window* GetContainer(aura::Window* window) {
74 aura::Window* container = window;
75 while (container && !container->GetProperty(kContainerParamsKey))
76 container = container->parent();
77 return container;
80 class AthenaFocusRules : public wm::BaseFocusRules {
81 public:
82 AthenaFocusRules() {}
83 ~AthenaFocusRules() override {}
85 // wm::BaseFocusRules:
86 virtual bool SupportsChildActivation(aura::Window* window) const override {
87 ScreenManager::ContainerParams* params =
88 window->GetProperty(kContainerParamsKey);
89 return params && params->can_activate_children;
91 virtual bool CanActivateWindow(aura::Window* window) const override {
92 if (!window)
93 return true;
95 // Check if containers of higher z-order than |window| have 'block_events'
96 // fields.
97 if (window->GetRootWindow()) {
98 const aura::Window::Windows& containers =
99 window->GetRootWindow()->children();
100 aura::Window::Windows::const_iterator iter =
101 std::find(containers.begin(), containers.end(), GetContainer(window));
102 DCHECK(iter != containers.end());
103 for (++iter; iter != containers.end(); ++iter) {
104 if (BlockEvents(*iter))
105 return false;
108 return BaseFocusRules::CanActivateWindow(window);
111 aura::Window* GetTopmostWindowToActivateInContainer(
112 aura::Window* container,
113 aura::Window* ignore) const {
114 for (aura::Window::Windows::const_reverse_iterator i =
115 container->children().rbegin();
116 i != container->children().rend();
117 ++i) {
118 if (*i != ignore && CanActivateWindow(*i))
119 return *i;
121 return NULL;
124 virtual aura::Window* GetNextActivatableWindow(
125 aura::Window* ignore) const override {
126 const aura::Window::Windows& containers =
127 ignore->GetRootWindow()->children();
128 auto starting_container_iter = containers.begin();
129 for (auto container_iter = containers.begin();
130 container_iter != containers.end();
131 container_iter++) {
132 if ((*container_iter)->Contains(ignore)) {
133 starting_container_iter = container_iter;
134 break;
138 // Find next window from the front containers.
139 aura::Window* next = nullptr;
140 for (auto container_iter = starting_container_iter;
141 !next && container_iter != containers.end();
142 container_iter++) {
143 next = GetTopmostWindowToActivateInContainer(*container_iter, ignore);
146 // Find next window from the back containers.
147 auto container_iter = starting_container_iter;
148 while (!next && container_iter != containers.begin()) {
149 container_iter--;
150 next = GetTopmostWindowToActivateInContainer(*container_iter, ignore);
152 return next;
155 private:
156 DISALLOW_COPY_AND_ASSIGN(AthenaFocusRules);
159 class AthenaScreenPositionClient : public wm::DefaultScreenPositionClient {
160 public:
161 AthenaScreenPositionClient() {
163 ~AthenaScreenPositionClient() override {}
165 private:
166 // aura::client::ScreenPositionClient:
167 void ConvertHostPointToScreen(aura::Window* window,
168 gfx::Point* point) override {
169 // TODO(oshima): Implement this when adding multiple display support.
170 NOTREACHED();
173 DISALLOW_COPY_AND_ASSIGN(AthenaScreenPositionClient);
176 class AthenaWindowTargeter : public aura::WindowTargeter {
177 public:
178 explicit AthenaWindowTargeter(aura::Window* root_window)
179 : root_window_(root_window) {}
181 ~AthenaWindowTargeter() override {}
183 private:
184 // aura::WindowTargeter:
185 virtual bool SubtreeCanAcceptEvent(
186 ui::EventTarget* target,
187 const ui::LocatedEvent& event) const override {
188 const aura::Window::Windows& containers = root_window_->children();
189 auto r_iter =
190 std::find_if(containers.rbegin(), containers.rend(), &BlockEvents);
191 if (r_iter == containers.rend())
192 return aura::WindowTargeter::SubtreeCanAcceptEvent(target, event);
194 aura::Window* window = static_cast<aura::Window*>(target);
195 for (;; --r_iter) {
196 if ((*r_iter)->Contains(window))
197 return aura::WindowTargeter::SubtreeCanAcceptEvent(target, event);
198 if (r_iter == containers.rbegin())
199 break;
201 return false;
204 virtual ui::EventTarget* FindTargetForLocatedEvent(
205 ui::EventTarget* root,
206 ui::LocatedEvent* event) override {
207 ui::EventTarget* target =
208 aura::WindowTargeter::FindTargetForLocatedEvent(root, event);
209 if (target)
210 return target;
211 // If the root target is blocking the event, return the container even if
212 // there is no target found so that windows behind it will not be searched.
213 const ScreenManager::ContainerParams* params =
214 static_cast<aura::Window*>(root)->GetProperty(kContainerParamsKey);
215 return (params && params->block_events) ? root : nullptr;
218 // Not owned.
219 aura::Window* root_window_;
221 DISALLOW_COPY_AND_ASSIGN(AthenaWindowTargeter);
224 } // namespace
226 ScreenManagerImpl::ScreenManagerImpl(aura::Window* root_window)
227 : root_window_(root_window),
228 last_requested_rotation_(gfx::Display::ROTATE_0),
229 rotation_locked_(false) {
230 DCHECK(root_window_);
231 DCHECK(!instance);
232 instance = this;
235 ScreenManagerImpl::~ScreenManagerImpl() {
236 aura::client::SetScreenPositionClient(root_window_, nullptr);
237 aura::client::SetWindowTreeClient(root_window_, nullptr);
238 wm::FocusController* focus_controller =
239 static_cast<wm::FocusController*>(focus_client_.get());
240 root_window_->RemovePreTargetHandler(focus_controller);
241 aura::client::SetActivationClient(root_window_, nullptr);
242 aura::client::SetFocusClient(root_window_, nullptr);
243 aura::Window::Windows children = root_window_->children();
244 // Close All children:
245 for (aura::Window::Windows::iterator iter = children.begin();
246 iter != children.end();
247 ++iter) {
248 delete *iter;
250 instance = nullptr;
253 void ScreenManagerImpl::Init() {
254 wm::FocusController* focus_controller =
255 new wm::FocusController(new AthenaFocusRules());
257 aura::client::SetFocusClient(root_window_, focus_controller);
258 root_window_->AddPreTargetHandler(focus_controller);
259 aura::client::SetActivationClient(root_window_, focus_controller);
260 focus_client_.reset(focus_controller);
262 capture_client_.reset(new ::wm::ScopedCaptureClient(root_window_));
263 accelerator_handler_.reset(new ScreenAcceleratorHandler());
265 aura::client::SetWindowTreeClient(root_window_, this);
267 screen_position_client_.reset(new AthenaScreenPositionClient());
268 aura::client::SetScreenPositionClient(root_window_,
269 screen_position_client_.get());
270 root_window_->SetEventTargeter(
271 make_scoped_ptr(new AthenaWindowTargeter(root_window_)));
274 aura::Window* ScreenManagerImpl::FindContainerByPriority(int priority) {
275 for (aura::Window* window : root_window_->children()) {
276 if (window->GetProperty(kContainerParamsKey)->z_order_priority == priority)
277 return window;
279 return nullptr;
282 aura::Window* ScreenManagerImpl::CreateContainer(
283 const ContainerParams& params) {
284 const aura::Window::Windows& children = root_window_->children();
286 if (params.default_parent) {
287 CHECK(std::find_if(children.begin(), children.end(), &DefaultContainer) ==
288 children.end());
290 // mmodal container's priority must be higher than the container's priority.
291 DCHECK(params.modal_container_priority == -1 ||
292 params.modal_container_priority > params.z_order_priority);
293 // Default parent must specify modal_container_priority.
294 DCHECK(!params.default_parent || params.modal_container_priority != -1);
296 aura::Window* container = new aura::Window(nullptr);
297 CHECK_GE(params.z_order_priority, 0);
298 container->Init(aura::WINDOW_LAYER_NOT_DRAWN);
299 container->SetName(params.name);
301 DCHECK(!FindContainerByPriority(params.z_order_priority))
302 << "The container with the priority " << params.z_order_priority
303 << " already exists.";
305 container->SetProperty(kContainerParamsKey, new ContainerParams(params));
307 root_window_->AddChild(container);
309 aura::Window::Windows::const_iterator iter =
310 std::find_if(children.begin(),
311 children.end(),
312 HigherPriorityFinder(params.z_order_priority));
313 if (iter != children.end())
314 root_window_->StackChildBelow(container, *iter);
316 container->Show();
317 return container;
320 aura::Window* ScreenManagerImpl::GetContext() {
321 return root_window_;
324 void ScreenManagerImpl::SetRotation(gfx::Display::Rotation rotation) {
325 last_requested_rotation_ = rotation;
326 if (rotation_locked_ || rotation ==
327 gfx::Screen::GetNativeScreen()->GetPrimaryDisplay().rotation()) {
328 return;
331 // TODO(flackr): Use display manager to update display rotation:
332 // http://crbug.com/401044.
333 static_cast<aura::TestScreen*>(gfx::Screen::GetNativeScreen())->
334 SetDisplayRotation(rotation);
337 void ScreenManagerImpl::SetRotationLocked(bool rotation_locked) {
338 rotation_locked_ = rotation_locked;
339 if (!rotation_locked_)
340 SetRotation(last_requested_rotation_);
343 int ScreenManagerImpl::GetModalContainerPriority(aura::Window* window,
344 aura::Window* parent) {
345 const aura::Window::Windows& children = root_window_->children();
346 if (window->GetProperty(aura::client::kAlwaysOnTopKey)) {
347 // Use top most modal container.
348 auto iter = std::find_if(
349 children.rbegin(), children.rend(), &HasModalContainerPriority);
350 DCHECK(iter != children.rend());
351 return (*iter)->GetProperty(kContainerParamsKey)->modal_container_priority;
352 } else {
353 // use the container closest to the parent which has modal
354 // container priority.
355 auto iter = std::find(children.rbegin(), children.rend(), parent);
356 DCHECK(iter != children.rend());
357 iter = std::find_if(iter, children.rend(), &HasModalContainerPriority);
358 DCHECK(iter != children.rend());
359 return (*iter)->GetProperty(kContainerParamsKey)->modal_container_priority;
363 aura::Window* ScreenManagerImpl::GetDefaultParent(aura::Window* context,
364 aura::Window* window,
365 const gfx::Rect& bounds) {
366 aura::Window* parent = wm::GetTransientParent(window);
367 if (parent)
368 parent = GetContainer(parent);
369 else
370 parent = GetDefaultContainer();
372 if (IsSystemModal(window)) {
373 DCHECK(window->type() == ui::wm::WINDOW_TYPE_NORMAL ||
374 window->type() == ui::wm::WINDOW_TYPE_POPUP);
375 int priority = GetModalContainerPriority(window, parent);
377 parent = FindContainerByPriority(priority);
378 if (!parent) {
379 ModalWindowController* controller = new ModalWindowController(priority);
380 parent = controller->modal_container();
383 return parent;
386 aura::Window* ScreenManagerImpl::GetDefaultContainer() {
387 const aura::Window::Windows& children = root_window_->children();
388 return *(std::find_if(children.begin(), children.end(), &DefaultContainer));
391 ScreenManager::ContainerParams::ContainerParams(const std::string& n,
392 int priority)
393 : name(n),
394 can_activate_children(false),
395 block_events(false),
396 z_order_priority(priority),
397 default_parent(false),
398 modal_container_priority(-1) {
401 // static
402 ScreenManager* ScreenManager::Create(aura::Window* root_window) {
403 (new ScreenManagerImpl(root_window))->Init();
404 DCHECK(instance);
405 return instance;
408 // static
409 ScreenManager* ScreenManager::Get() {
410 DCHECK(instance);
411 return instance;
414 // static
415 void ScreenManager::Shutdown() {
416 DCHECK(instance);
417 delete instance;
418 DCHECK(!instance);
421 } // namespace athena