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);
34 DEFINE_OWNED_WINDOW_PROPERTY_KEY(ScreenManager::ContainerParams
,
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
>
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();
80 class AthenaFocusRules
: public wm::BaseFocusRules
{
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
{
95 // Check if containers of higher z-order than |window| have 'block_events'
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
))
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();
118 if (*i
!= ignore
&& CanActivateWindow(*i
))
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();
132 if ((*container_iter
)->Contains(ignore
)) {
133 starting_container_iter
= container_iter
;
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();
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()) {
150 next
= GetTopmostWindowToActivateInContainer(*container_iter
, ignore
);
156 DISALLOW_COPY_AND_ASSIGN(AthenaFocusRules
);
159 class AthenaScreenPositionClient
: public wm::DefaultScreenPositionClient
{
161 AthenaScreenPositionClient() {
163 ~AthenaScreenPositionClient() override
{}
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.
173 DISALLOW_COPY_AND_ASSIGN(AthenaScreenPositionClient
);
176 class AthenaWindowTargeter
: public aura::WindowTargeter
{
178 explicit AthenaWindowTargeter(aura::Window
* root_window
)
179 : root_window_(root_window
) {}
181 ~AthenaWindowTargeter() override
{}
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();
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
);
196 if ((*r_iter
)->Contains(window
))
197 return aura::WindowTargeter::SubtreeCanAcceptEvent(target
, event
);
198 if (r_iter
== containers
.rbegin())
204 virtual ui::EventTarget
* FindTargetForLocatedEvent(
205 ui::EventTarget
* root
,
206 ui::LocatedEvent
* event
) override
{
207 ui::EventTarget
* target
=
208 aura::WindowTargeter::FindTargetForLocatedEvent(root
, event
);
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;
219 aura::Window
* root_window_
;
221 DISALLOW_COPY_AND_ASSIGN(AthenaWindowTargeter
);
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_
);
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();
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
)
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
) ==
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(),
312 HigherPriorityFinder(params
.z_order_priority
));
313 if (iter
!= children
.end())
314 root_window_
->StackChildBelow(container
, *iter
);
320 aura::Window
* ScreenManagerImpl::GetContext() {
324 void ScreenManagerImpl::SetRotation(gfx::Display::Rotation rotation
) {
325 last_requested_rotation_
= rotation
;
326 if (rotation_locked_
|| rotation
==
327 gfx::Screen::GetNativeScreen()->GetPrimaryDisplay().rotation()) {
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
;
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
);
368 parent
= GetContainer(parent
);
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
);
379 ModalWindowController
* controller
= new ModalWindowController(priority
);
380 parent
= controller
->modal_container();
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
,
394 can_activate_children(false),
396 z_order_priority(priority
),
397 default_parent(false),
398 modal_container_priority(-1) {
402 ScreenManager
* ScreenManager::Create(aura::Window
* root_window
) {
403 (new ScreenManagerImpl(root_window
))->Init();
409 ScreenManager
* ScreenManager::Get() {
415 void ScreenManager::Shutdown() {
421 } // namespace athena