OLD | NEW |
| (Empty) |
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/screen_manager_impl.h" | |
6 | |
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" | |
27 | |
28 DECLARE_WINDOW_PROPERTY_TYPE(athena::ScreenManager::ContainerParams*); | |
29 | |
30 namespace athena { | |
31 namespace { | |
32 | |
33 DEFINE_OWNED_WINDOW_PROPERTY_KEY(ScreenManager::ContainerParams, | |
34 kContainerParamsKey, | |
35 nullptr); | |
36 | |
37 ScreenManagerImpl* instance = nullptr; | |
38 | |
39 // A functor to find a container that has the higher priority. | |
40 struct HigherPriorityFinder { | |
41 HigherPriorityFinder(int p) : priority(p) {} | |
42 bool operator()(aura::Window* window) { | |
43 return window->GetProperty(kContainerParamsKey)->z_order_priority > | |
44 priority; | |
45 } | |
46 int priority; | |
47 }; | |
48 | |
49 bool BlockEvents(aura::Window* container) { | |
50 ScreenManager::ContainerParams* params = | |
51 container->GetProperty(kContainerParamsKey); | |
52 return params && params->block_events && container->IsVisible(); | |
53 } | |
54 | |
55 bool DefaultContainer(aura::Window* container) { | |
56 ScreenManager::ContainerParams* params = | |
57 container->GetProperty(kContainerParamsKey); | |
58 return params && params->default_parent; | |
59 } | |
60 | |
61 bool HasModalContainerPriority(aura::Window* container) { | |
62 ScreenManager::ContainerParams* params = | |
63 container->GetProperty(kContainerParamsKey); | |
64 return params && params->modal_container_priority != -1; | |
65 } | |
66 | |
67 bool IsSystemModal(aura::Window* window) { | |
68 return window->GetProperty(aura::client::kModalKey) == ui::MODAL_TYPE_SYSTEM; | |
69 } | |
70 | |
71 // Returns the container which contains |window|. | |
72 aura::Window* GetContainer(aura::Window* window) { | |
73 aura::Window* container = window; | |
74 while (container && !container->GetProperty(kContainerParamsKey)) | |
75 container = container->parent(); | |
76 return container; | |
77 } | |
78 | |
79 class AthenaFocusRules : public wm::BaseFocusRules { | |
80 public: | |
81 AthenaFocusRules() {} | |
82 ~AthenaFocusRules() override {} | |
83 | |
84 // wm::BaseFocusRules: | |
85 virtual bool SupportsChildActivation(aura::Window* window) const override { | |
86 ScreenManager::ContainerParams* params = | |
87 window->GetProperty(kContainerParamsKey); | |
88 return params && params->can_activate_children; | |
89 } | |
90 virtual bool CanActivateWindow(aura::Window* window) const override { | |
91 if (!window) | |
92 return true; | |
93 | |
94 // Check if containers of higher z-order than |window| have 'block_events' | |
95 // fields. | |
96 if (window->GetRootWindow()) { | |
97 const aura::Window::Windows& containers = | |
98 window->GetRootWindow()->children(); | |
99 aura::Window::Windows::const_iterator iter = | |
100 std::find(containers.begin(), containers.end(), GetContainer(window)); | |
101 DCHECK(iter != containers.end()); | |
102 for (++iter; iter != containers.end(); ++iter) { | |
103 if (BlockEvents(*iter)) | |
104 return false; | |
105 } | |
106 } | |
107 return BaseFocusRules::CanActivateWindow(window); | |
108 } | |
109 | |
110 aura::Window* GetTopmostWindowToActivateInContainer( | |
111 aura::Window* container, | |
112 aura::Window* ignore) const { | |
113 for (aura::Window::Windows::const_reverse_iterator i = | |
114 container->children().rbegin(); | |
115 i != container->children().rend(); | |
116 ++i) { | |
117 if (*i != ignore && CanActivateWindow(*i)) | |
118 return *i; | |
119 } | |
120 return NULL; | |
121 } | |
122 | |
123 virtual aura::Window* GetNextActivatableWindow( | |
124 aura::Window* ignore) const override { | |
125 const aura::Window::Windows& containers = | |
126 ignore->GetRootWindow()->children(); | |
127 auto starting_container_iter = containers.begin(); | |
128 for (auto container_iter = containers.begin(); | |
129 container_iter != containers.end(); | |
130 container_iter++) { | |
131 if ((*container_iter)->Contains(ignore)) { | |
132 starting_container_iter = container_iter; | |
133 break; | |
134 } | |
135 } | |
136 | |
137 // Find next window from the front containers. | |
138 aura::Window* next = nullptr; | |
139 for (auto container_iter = starting_container_iter; | |
140 !next && container_iter != containers.end(); | |
141 container_iter++) { | |
142 next = GetTopmostWindowToActivateInContainer(*container_iter, ignore); | |
143 } | |
144 | |
145 // Find next window from the back containers. | |
146 auto container_iter = starting_container_iter; | |
147 while (!next && container_iter != containers.begin()) { | |
148 container_iter--; | |
149 next = GetTopmostWindowToActivateInContainer(*container_iter, ignore); | |
150 } | |
151 return next; | |
152 } | |
153 | |
154 private: | |
155 DISALLOW_COPY_AND_ASSIGN(AthenaFocusRules); | |
156 }; | |
157 | |
158 class AthenaScreenPositionClient : public wm::DefaultScreenPositionClient { | |
159 public: | |
160 AthenaScreenPositionClient() { | |
161 } | |
162 ~AthenaScreenPositionClient() override {} | |
163 | |
164 private: | |
165 // aura::client::ScreenPositionClient: | |
166 void ConvertHostPointToScreen(aura::Window* window, | |
167 gfx::Point* point) override { | |
168 // TODO(oshima): Implement this when adding multiple display support. | |
169 NOTREACHED(); | |
170 } | |
171 | |
172 DISALLOW_COPY_AND_ASSIGN(AthenaScreenPositionClient); | |
173 }; | |
174 | |
175 class AthenaWindowTargeter : public aura::WindowTargeter { | |
176 public: | |
177 explicit AthenaWindowTargeter(aura::Window* root_window) | |
178 : root_window_(root_window) {} | |
179 | |
180 ~AthenaWindowTargeter() override {} | |
181 | |
182 private: | |
183 // aura::WindowTargeter: | |
184 virtual bool SubtreeCanAcceptEvent( | |
185 ui::EventTarget* target, | |
186 const ui::LocatedEvent& event) const override { | |
187 const aura::Window::Windows& containers = root_window_->children(); | |
188 auto r_iter = | |
189 std::find_if(containers.rbegin(), containers.rend(), &BlockEvents); | |
190 if (r_iter == containers.rend()) | |
191 return aura::WindowTargeter::SubtreeCanAcceptEvent(target, event); | |
192 | |
193 aura::Window* window = static_cast<aura::Window*>(target); | |
194 for (;; --r_iter) { | |
195 if ((*r_iter)->Contains(window)) | |
196 return aura::WindowTargeter::SubtreeCanAcceptEvent(target, event); | |
197 if (r_iter == containers.rbegin()) | |
198 break; | |
199 } | |
200 return false; | |
201 } | |
202 | |
203 virtual ui::EventTarget* FindTargetForLocatedEvent( | |
204 ui::EventTarget* root, | |
205 ui::LocatedEvent* event) override { | |
206 ui::EventTarget* target = | |
207 aura::WindowTargeter::FindTargetForLocatedEvent(root, event); | |
208 if (target) | |
209 return target; | |
210 // If the root target is blocking the event, return the container even if | |
211 // there is no target found so that windows behind it will not be searched. | |
212 const ScreenManager::ContainerParams* params = | |
213 static_cast<aura::Window*>(root)->GetProperty(kContainerParamsKey); | |
214 return (params && params->block_events) ? root : nullptr; | |
215 } | |
216 | |
217 // Not owned. | |
218 aura::Window* root_window_; | |
219 | |
220 DISALLOW_COPY_AND_ASSIGN(AthenaWindowTargeter); | |
221 }; | |
222 | |
223 } // namespace | |
224 | |
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 | |
234 ScreenManagerImpl::~ScreenManagerImpl() { | |
235 aura::client::SetScreenPositionClient(root_window_, nullptr); | |
236 aura::client::SetWindowTreeClient(root_window_, nullptr); | |
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_, nullptr); | |
241 aura::client::SetFocusClient(root_window_, nullptr); | |
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 = nullptr; | |
250 } | |
251 | |
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 capture_client_.reset(new ::wm::ScopedCaptureClient(root_window_)); | |
262 accelerator_handler_.reset(new ScreenAcceleratorHandler()); | |
263 | |
264 aura::client::SetWindowTreeClient(root_window_, this); | |
265 | |
266 screen_position_client_.reset(new AthenaScreenPositionClient()); | |
267 aura::client::SetScreenPositionClient(root_window_, | |
268 screen_position_client_.get()); | |
269 root_window_->SetEventTargeter( | |
270 make_scoped_ptr(new AthenaWindowTargeter(root_window_))); | |
271 } | |
272 | |
273 aura::Window* ScreenManagerImpl::FindContainerByPriority(int priority) { | |
274 for (aura::Window* window : root_window_->children()) { | |
275 if (window->GetProperty(kContainerParamsKey)->z_order_priority == priority) | |
276 return window; | |
277 } | |
278 return nullptr; | |
279 } | |
280 | |
281 aura::Window* ScreenManagerImpl::CreateContainer( | |
282 const ContainerParams& params) { | |
283 const aura::Window::Windows& children = root_window_->children(); | |
284 | |
285 if (params.default_parent) { | |
286 CHECK(std::find_if(children.begin(), children.end(), &DefaultContainer) == | |
287 children.end()); | |
288 } | |
289 // mmodal container's priority must be higher than the container's priority. | |
290 DCHECK(params.modal_container_priority == -1 || | |
291 params.modal_container_priority > params.z_order_priority); | |
292 // Default parent must specify modal_container_priority. | |
293 DCHECK(!params.default_parent || params.modal_container_priority != -1); | |
294 | |
295 aura::Window* container = new aura::Window(nullptr); | |
296 CHECK_GE(params.z_order_priority, 0); | |
297 container->Init(aura::WINDOW_LAYER_NOT_DRAWN); | |
298 container->SetName(params.name); | |
299 | |
300 DCHECK(!FindContainerByPriority(params.z_order_priority)) | |
301 << "The container with the priority " << params.z_order_priority | |
302 << " already exists."; | |
303 | |
304 container->SetProperty(kContainerParamsKey, new ContainerParams(params)); | |
305 | |
306 root_window_->AddChild(container); | |
307 | |
308 aura::Window::Windows::const_iterator iter = | |
309 std::find_if(children.begin(), | |
310 children.end(), | |
311 HigherPriorityFinder(params.z_order_priority)); | |
312 if (iter != children.end()) | |
313 root_window_->StackChildBelow(container, *iter); | |
314 | |
315 container->Show(); | |
316 return container; | |
317 } | |
318 | |
319 aura::Window* ScreenManagerImpl::GetContext() { | |
320 return root_window_; | |
321 } | |
322 | |
323 void ScreenManagerImpl::SetRotation(gfx::Display::Rotation rotation) { | |
324 last_requested_rotation_ = rotation; | |
325 if (rotation_locked_ || rotation == | |
326 gfx::Screen::GetNativeScreen()->GetPrimaryDisplay().rotation()) { | |
327 return; | |
328 } | |
329 | |
330 // TODO(flackr): Use display manager to update display rotation: | |
331 // http://crbug.com/401044. | |
332 static_cast<aura::TestScreen*>(gfx::Screen::GetNativeScreen())-> | |
333 SetDisplayRotation(rotation); | |
334 } | |
335 | |
336 void ScreenManagerImpl::SetRotationLocked(bool rotation_locked) { | |
337 rotation_locked_ = rotation_locked; | |
338 if (!rotation_locked_) | |
339 SetRotation(last_requested_rotation_); | |
340 } | |
341 | |
342 int ScreenManagerImpl::GetModalContainerPriority(aura::Window* window, | |
343 aura::Window* parent) { | |
344 const aura::Window::Windows& children = root_window_->children(); | |
345 if (window->GetProperty(aura::client::kAlwaysOnTopKey)) { | |
346 // Use top most modal container. | |
347 auto iter = std::find_if( | |
348 children.rbegin(), children.rend(), &HasModalContainerPriority); | |
349 DCHECK(iter != children.rend()); | |
350 return (*iter)->GetProperty(kContainerParamsKey)->modal_container_priority; | |
351 } else { | |
352 // use the container closest to the parent which has modal | |
353 // container priority. | |
354 auto iter = std::find(children.rbegin(), children.rend(), parent); | |
355 DCHECK(iter != children.rend()); | |
356 iter = std::find_if(iter, children.rend(), &HasModalContainerPriority); | |
357 DCHECK(iter != children.rend()); | |
358 return (*iter)->GetProperty(kContainerParamsKey)->modal_container_priority; | |
359 } | |
360 } | |
361 | |
362 aura::Window* ScreenManagerImpl::GetDefaultParent(aura::Window* context, | |
363 aura::Window* window, | |
364 const gfx::Rect& bounds) { | |
365 aura::Window* parent = wm::GetTransientParent(window); | |
366 if (parent) | |
367 parent = GetContainer(parent); | |
368 else | |
369 parent = GetDefaultContainer(); | |
370 | |
371 if (IsSystemModal(window)) { | |
372 DCHECK(window->type() == ui::wm::WINDOW_TYPE_NORMAL || | |
373 window->type() == ui::wm::WINDOW_TYPE_POPUP); | |
374 int priority = GetModalContainerPriority(window, parent); | |
375 | |
376 parent = FindContainerByPriority(priority); | |
377 if (!parent) { | |
378 ModalWindowController* controller = new ModalWindowController(priority); | |
379 parent = controller->modal_container(); | |
380 } | |
381 } | |
382 return parent; | |
383 } | |
384 | |
385 aura::Window* ScreenManagerImpl::GetDefaultContainer() { | |
386 const aura::Window::Windows& children = root_window_->children(); | |
387 return *(std::find_if(children.begin(), children.end(), &DefaultContainer)); | |
388 } | |
389 | |
390 ScreenManager::ContainerParams::ContainerParams(const std::string& n, | |
391 int priority) | |
392 : name(n), | |
393 can_activate_children(false), | |
394 block_events(false), | |
395 z_order_priority(priority), | |
396 default_parent(false), | |
397 modal_container_priority(-1) { | |
398 } | |
399 | |
400 // static | |
401 ScreenManager* ScreenManager::Create(aura::Window* root_window) { | |
402 (new ScreenManagerImpl(root_window))->Init(); | |
403 DCHECK(instance); | |
404 return instance; | |
405 } | |
406 | |
407 // static | |
408 ScreenManager* ScreenManager::Get() { | |
409 DCHECK(instance); | |
410 return instance; | |
411 } | |
412 | |
413 // static | |
414 void ScreenManager::Shutdown() { | |
415 DCHECK(instance); | |
416 delete instance; | |
417 DCHECK(!instance); | |
418 } | |
419 | |
420 } // namespace athena | |
OLD | NEW |