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 "ash/wm/system_modal_container_layout_manager.h"
7 #include "ash/session_state_delegate.h"
9 #include "ash/shell_window_ids.h"
10 #include "ash/wm/system_modal_container_event_filter.h"
11 #include "ash/wm/window_animations.h"
12 #include "ash/wm/window_util.h"
13 #include "base/bind.h"
14 #include "ui/aura/client/aura_constants.h"
15 #include "ui/aura/client/capture_client.h"
16 #include "ui/aura/root_window.h"
17 #include "ui/aura/window.h"
18 #include "ui/base/events/event.h"
19 #include "ui/base/ui_base_switches_util.h"
20 #include "ui/compositor/layer.h"
21 #include "ui/compositor/layer_animator.h"
22 #include "ui/compositor/scoped_layer_animation_settings.h"
23 #include "ui/gfx/screen.h"
24 #include "ui/views/corewm/compound_event_filter.h"
25 #include "ui/views/view.h"
26 #include "ui/views/widget/widget.h"
31 ////////////////////////////////////////////////////////////////////////////////
32 // SystemModalContainerLayoutManager, public:
34 SystemModalContainerLayoutManager::SystemModalContainerLayoutManager(
35 aura::Window
* container
)
36 : container_(container
),
37 modal_background_(NULL
) {
40 SystemModalContainerLayoutManager::~SystemModalContainerLayoutManager() {
43 ////////////////////////////////////////////////////////////////////////////////
44 // SystemModalContainerLayoutManager, aura::LayoutManager implementation:
46 void SystemModalContainerLayoutManager::OnWindowResized() {
47 if (modal_background_
) {
48 // Note: we have to set the entire bounds with the screen offset.
49 modal_background_
->SetBounds(
50 Shell::GetScreen()->GetDisplayNearestWindow(container_
).bounds());
52 if (!modal_windows_
.empty()) {
53 aura::Window::Windows::iterator it
= modal_windows_
.begin();
54 for (it
= modal_windows_
.begin(); it
!= modal_windows_
.end(); ++it
) {
55 gfx::Rect bounds
= (*it
)->bounds();
56 bounds
.AdjustToFit(container_
->bounds());
57 (*it
)->SetBounds(bounds
);
62 void SystemModalContainerLayoutManager::OnWindowAddedToLayout(
63 aura::Window
* child
) {
64 DCHECK((modal_background_
&& child
== modal_background_
->GetNativeView()) ||
65 child
->type() == aura::client::WINDOW_TYPE_NORMAL
||
66 child
->type() == aura::client::WINDOW_TYPE_POPUP
);
68 container_
->id() != internal::kShellWindowId_LockSystemModalContainer
||
69 Shell::GetInstance()->session_state_delegate()->IsScreenLocked() ||
70 !Shell::GetInstance()->session_state_delegate()->
71 IsActiveUserSessionStarted());
73 child
->AddObserver(this);
74 if (child
->GetProperty(aura::client::kModalKey
) != ui::MODAL_TYPE_NONE
)
75 AddModalWindow(child
);
78 void SystemModalContainerLayoutManager::OnWillRemoveWindowFromLayout(
79 aura::Window
* child
) {
80 child
->RemoveObserver(this);
81 if (child
->GetProperty(aura::client::kModalKey
) != ui::MODAL_TYPE_NONE
)
82 RemoveModalWindow(child
);
85 void SystemModalContainerLayoutManager::OnWindowRemovedFromLayout(
86 aura::Window
* child
) {
89 void SystemModalContainerLayoutManager::OnChildWindowVisibilityChanged(
94 void SystemModalContainerLayoutManager::SetChildBounds(
96 const gfx::Rect
& requested_bounds
) {
97 SetChildBoundsDirect(child
, requested_bounds
);
100 ////////////////////////////////////////////////////////////////////////////////
101 // SystemModalContainerLayoutManager, aura::WindowObserver implementation:
103 void SystemModalContainerLayoutManager::OnWindowPropertyChanged(
104 aura::Window
* window
,
107 if (key
!= aura::client::kModalKey
)
110 if (window
->GetProperty(aura::client::kModalKey
) != ui::MODAL_TYPE_NONE
) {
111 AddModalWindow(window
);
112 } else if (static_cast<ui::ModalType
>(old
) != ui::MODAL_TYPE_NONE
) {
113 RemoveModalWindow(window
);
114 Shell::GetInstance()->OnModalWindowRemoved(window
);
118 void SystemModalContainerLayoutManager::OnWindowDestroying(
119 aura::Window
* window
) {
120 if (modal_background_
&& modal_background_
->GetNativeView() == window
)
121 modal_background_
= NULL
;
125 ////////////////////////////////////////////////////////////////////////////////
126 // SystemModalContainerLayoutManager,
127 // SystemModalContainerEventFilter::Delegate implementation:
129 bool SystemModalContainerLayoutManager::CanWindowReceiveEvents(
130 aura::Window
* window
) {
131 // We could get when we're at lock screen and there is modal window at
132 // system modal window layer which added event filter.
133 // Now this lock modal windows layer layout manager should not block events
134 // for windows at lock layer.
135 // See SystemModalContainerLayoutManagerTest.EventFocusContainers and
136 // http://crbug.com/157469
137 if (modal_windows_
.empty())
139 // This container can not handle events if the screen is locked and it is not
140 // above the lock screen layer (crbug.com/110920).
141 if (Shell::GetInstance()->session_state_delegate()->IsScreenLocked() &&
142 container_
->id() < ash::internal::kShellWindowId_LockScreenContainer
)
144 return wm::GetActivatableWindow(window
) == modal_window();
147 bool SystemModalContainerLayoutManager::ActivateNextModalWindow() {
148 if (modal_windows_
.empty())
150 wm::ActivateWindow(modal_window());
154 void SystemModalContainerLayoutManager::CreateModalBackground() {
155 if (!modal_background_
) {
156 modal_background_
= new views::Widget
;
157 views::Widget::InitParams
params(views::Widget::InitParams::TYPE_CONTROL
);
158 params
.parent
= container_
;
159 params
.bounds
= Shell::GetScreen()->GetDisplayNearestWindow(
160 container_
).bounds();
161 modal_background_
->Init(params
);
162 modal_background_
->GetNativeView()->SetName(
163 "SystemModalContainerLayoutManager.ModalBackground");
164 views::View
* contents_view
= new views::View();
165 contents_view
->set_background(views::Background::CreateSolidBackground(
166 switches::IsNewDialogStyleEnabled() ? SK_ColorWHITE
: SK_ColorBLACK
));
167 modal_background_
->SetContentsView(contents_view
);
168 modal_background_
->GetNativeView()->layer()->SetOpacity(0.0f
);
171 ui::ScopedLayerAnimationSettings
settings(
172 modal_background_
->GetNativeView()->layer()->GetAnimator());
173 modal_background_
->Show();
174 modal_background_
->GetNativeView()->layer()->SetOpacity(0.5f
);
175 container_
->StackChildAtTop(modal_background_
->GetNativeView());
178 void SystemModalContainerLayoutManager::DestroyModalBackground() {
179 // modal_background_ can be NULL when a root window is shutting down
180 // and OnWindowDestroying is called first.
181 if (modal_background_
) {
182 ui::ScopedLayerAnimationSettings
settings(
183 modal_background_
->GetNativeView()->layer()->GetAnimator());
184 modal_background_
->Close();
185 settings
.AddObserver(views::corewm::CreateHidingWindowAnimationObserver(
186 modal_background_
->GetNativeView()));
187 modal_background_
->GetNativeView()->layer()->SetOpacity(0.0f
);
188 modal_background_
= NULL
;
193 bool SystemModalContainerLayoutManager::IsModalBackground(
194 aura::Window
* window
) {
195 int id
= window
->parent()->id();
196 if (id
!= internal::kShellWindowId_SystemModalContainer
&&
197 id
!= internal::kShellWindowId_LockSystemModalContainer
)
199 SystemModalContainerLayoutManager
* layout_manager
=
200 static_cast<SystemModalContainerLayoutManager
*>(
201 window
->parent()->layout_manager());
202 return layout_manager
->modal_background_
&&
203 layout_manager
->modal_background_
->GetNativeWindow() == window
;
206 ////////////////////////////////////////////////////////////////////////////////
207 // SystemModalContainerLayoutManager, private:
209 void SystemModalContainerLayoutManager::AddModalWindow(aura::Window
* window
) {
210 if (modal_windows_
.empty()) {
211 aura::Window
* capture_window
= aura::client::GetCaptureWindow(container_
);
213 capture_window
->ReleaseCapture();
215 modal_windows_
.push_back(window
);
216 Shell::GetInstance()->CreateModalBackground(window
);
217 window
->parent()->StackChildAtTop(window
);
220 void SystemModalContainerLayoutManager::RemoveModalWindow(
221 aura::Window
* window
) {
222 aura::Window::Windows::iterator it
=
223 std::find(modal_windows_
.begin(), modal_windows_
.end(), window
);
224 if (it
!= modal_windows_
.end())
225 modal_windows_
.erase(it
);
228 } // namespace internal