1 // Copyright (c) 2012 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 "ui/wm/core/window_modality_controller.h"
9 #include "ui/aura/client/aura_constants.h"
10 #include "ui/aura/client/capture_client.h"
11 #include "ui/aura/env.h"
12 #include "ui/aura/window.h"
13 #include "ui/aura/window_event_dispatcher.h"
14 #include "ui/aura/window_property.h"
15 #include "ui/base/ui_base_types.h"
16 #include "ui/events/event.h"
17 #include "ui/events/event_target.h"
18 #include "ui/events/gestures/gesture_recognizer.h"
19 #include "ui/wm/core/window_animations.h"
20 #include "ui/wm/core/window_util.h"
24 // Transient child's modal parent.
25 extern const aura::WindowProperty
<aura::Window
*>* const kModalParentKey
;
26 DEFINE_WINDOW_PROPERTY_KEY(aura::Window
*, kModalParentKey
, NULL
);
30 bool HasAncestor(aura::Window
* window
, aura::Window
* ancestor
) {
33 if (window
== ancestor
)
35 return HasAncestor(window
->parent(), ancestor
);
38 bool TransientChildIsWindowModal(aura::Window
* window
) {
39 return window
->GetProperty(aura::client::kModalKey
) == ui::MODAL_TYPE_WINDOW
;
42 bool TransientChildIsSystemModal(aura::Window
* window
) {
43 return window
->GetProperty(aura::client::kModalKey
) == ui::MODAL_TYPE_SYSTEM
;
46 bool TransientChildIsChildModal(aura::Window
* window
) {
47 return window
->GetProperty(aura::client::kModalKey
) == ui::MODAL_TYPE_CHILD
;
50 aura::Window
* GetModalParent(aura::Window
* window
) {
51 return window
->GetProperty(kModalParentKey
);
54 bool IsModalTransientChild(aura::Window
* transient
, aura::Window
* original
) {
55 return transient
->IsVisible() &&
56 (TransientChildIsWindowModal(transient
) ||
57 TransientChildIsSystemModal(transient
) ||
58 (TransientChildIsChildModal(transient
) &&
59 (HasAncestor(original
, GetModalParent(transient
)))));
62 aura::Window
* GetModalTransientChild(
63 aura::Window
* activatable
,
64 aura::Window
* original
) {
65 for (aura::Window::Windows::const_iterator it
=
66 GetTransientChildren(activatable
).begin();
67 it
!= GetTransientChildren(activatable
).end();
69 aura::Window
* transient
= *it
;
70 if (IsModalTransientChild(transient
, original
)) {
71 return GetTransientChildren(transient
).empty() ?
72 transient
: GetModalTransientChild(transient
, original
);
80 void SetModalParent(aura::Window
* child
, aura::Window
* parent
) {
81 child
->SetProperty(kModalParentKey
, parent
);
84 aura::Window
* GetModalTransient(aura::Window
* window
) {
88 // We always want to check the for the transient child of the toplevel window.
89 aura::Window
* toplevel
= GetToplevelWindow(window
);
93 return GetModalTransientChild(toplevel
, window
);
96 ////////////////////////////////////////////////////////////////////////////////
97 // WindowModalityController, public:
99 WindowModalityController::WindowModalityController(
100 ui::EventTarget
* event_target
)
101 : event_target_(event_target
) {
102 aura::Env::GetInstance()->AddObserver(this);
103 DCHECK(event_target
->IsPreTargetListEmpty());
104 event_target_
->AddPreTargetHandler(this);
107 WindowModalityController::~WindowModalityController() {
108 event_target_
->RemovePreTargetHandler(this);
109 aura::Env::GetInstance()->RemoveObserver(this);
110 for (size_t i
= 0; i
< windows_
.size(); ++i
)
111 windows_
[i
]->RemoveObserver(this);
114 ////////////////////////////////////////////////////////////////////////////////
115 // WindowModalityController, aura::EventFilter implementation:
117 void WindowModalityController::OnKeyEvent(ui::KeyEvent
* event
) {
118 aura::Window
* target
= static_cast<aura::Window
*>(event
->target());
119 if (GetModalTransient(target
))
123 void WindowModalityController::OnMouseEvent(ui::MouseEvent
* event
) {
124 aura::Window
* target
= static_cast<aura::Window
*>(event
->target());
125 if (ProcessLocatedEvent(target
, event
))
129 void WindowModalityController::OnTouchEvent(ui::TouchEvent
* event
) {
130 aura::Window
* target
= static_cast<aura::Window
*>(event
->target());
131 if (ProcessLocatedEvent(target
, event
))
135 ////////////////////////////////////////////////////////////////////////////////
136 // WindowModalityController, aura::EnvObserver implementation:
138 void WindowModalityController::OnWindowInitialized(aura::Window
* window
) {
139 windows_
.push_back(window
);
140 window
->AddObserver(this);
143 ////////////////////////////////////////////////////////////////////////////////
144 // WindowModalityController, aura::WindowObserver implementation:
146 void WindowModalityController::OnWindowPropertyChanged(aura::Window
* window
,
149 // In tests, we sometimes create the modality relationship after a window is
151 if (key
== aura::client::kModalKey
&&
152 window
->GetProperty(aura::client::kModalKey
) != ui::MODAL_TYPE_NONE
&&
153 window
->IsVisible()) {
154 ActivateWindow(window
);
155 ui::GestureRecognizer::Get()->TransferEventsTo(GetTransientParent(window
),
160 void WindowModalityController::OnWindowVisibilityChanged(
161 aura::Window
* window
,
163 if (visible
&& window
->GetProperty(aura::client::kModalKey
) !=
164 ui::MODAL_TYPE_NONE
) {
165 ui::GestureRecognizer::Get()->TransferEventsTo(GetTransientParent(window
),
167 // Make sure no other window has capture, otherwise |window| won't get mouse
169 aura::Window
* capture_window
= aura::client::GetCaptureWindow(window
);
171 capture_window
->ReleaseCapture();
175 void WindowModalityController::OnWindowDestroyed(aura::Window
* window
) {
176 windows_
.erase(std::find(windows_
.begin(), windows_
.end(), window
));
177 window
->RemoveObserver(this);
180 bool WindowModalityController::ProcessLocatedEvent(aura::Window
* target
,
181 ui::LocatedEvent
* event
) {
182 if (event
->handled())
184 aura::Window
* modal_transient_child
= GetModalTransient(target
);
185 if (modal_transient_child
&& (event
->type() == ui::ET_MOUSE_PRESSED
||
186 event
->type() == ui::ET_TOUCH_PRESSED
)) {
187 // Activate top window if transient child window is window modal.
188 if (TransientChildIsWindowModal(modal_transient_child
)) {
189 aura::Window
* toplevel
= GetToplevelWindow(target
);
191 ActivateWindow(toplevel
);
194 AnimateWindow(modal_transient_child
, WINDOW_ANIMATION_TYPE_BOUNCE
);
196 if (event
->type() == ui::ET_TOUCH_CANCELLED
)
198 return !!modal_transient_child
;