• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include "ash/wm/system_modal_container_layout_manager.h"
6 
7 #include "ash/session_state_delegate.h"
8 #include "ash/shell.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/ui_base_switches_util.h"
19 #include "ui/compositor/layer.h"
20 #include "ui/compositor/layer_animator.h"
21 #include "ui/compositor/scoped_layer_animation_settings.h"
22 #include "ui/events/event.h"
23 #include "ui/gfx/screen.h"
24 #include "ui/views/background.h"
25 #include "ui/views/corewm/compound_event_filter.h"
26 #include "ui/views/view.h"
27 #include "ui/views/widget/widget.h"
28 
29 namespace ash {
30 namespace internal {
31 
32 ////////////////////////////////////////////////////////////////////////////////
33 // SystemModalContainerLayoutManager, public:
34 
SystemModalContainerLayoutManager(aura::Window * container)35 SystemModalContainerLayoutManager::SystemModalContainerLayoutManager(
36     aura::Window* container)
37     : container_(container),
38       modal_background_(NULL) {
39 }
40 
~SystemModalContainerLayoutManager()41 SystemModalContainerLayoutManager::~SystemModalContainerLayoutManager() {
42 }
43 
44 ////////////////////////////////////////////////////////////////////////////////
45 // SystemModalContainerLayoutManager, aura::LayoutManager implementation:
46 
OnWindowResized()47 void SystemModalContainerLayoutManager::OnWindowResized() {
48   if (modal_background_) {
49     // Note: we have to set the entire bounds with the screen offset.
50     modal_background_->SetBounds(
51         Shell::GetScreen()->GetDisplayNearestWindow(container_).bounds());
52   }
53   if (!modal_windows_.empty()) {
54     aura::Window::Windows::iterator it = modal_windows_.begin();
55     for (it = modal_windows_.begin(); it != modal_windows_.end(); ++it) {
56       gfx::Rect bounds = (*it)->bounds();
57       bounds.AdjustToFit(container_->bounds());
58       (*it)->SetBounds(bounds);
59     }
60   }
61 }
62 
OnWindowAddedToLayout(aura::Window * child)63 void SystemModalContainerLayoutManager::OnWindowAddedToLayout(
64     aura::Window* child) {
65   DCHECK((modal_background_ && child == modal_background_->GetNativeView()) ||
66          child->type() == aura::client::WINDOW_TYPE_NORMAL ||
67          child->type() == aura::client::WINDOW_TYPE_POPUP);
68   DCHECK(
69       container_->id() != internal::kShellWindowId_LockSystemModalContainer ||
70       Shell::GetInstance()->session_state_delegate()->IsUserSessionBlocked());
71 
72   child->AddObserver(this);
73   if (child->GetProperty(aura::client::kModalKey) != ui::MODAL_TYPE_NONE)
74     AddModalWindow(child);
75 }
76 
OnWillRemoveWindowFromLayout(aura::Window * child)77 void SystemModalContainerLayoutManager::OnWillRemoveWindowFromLayout(
78     aura::Window* child) {
79   child->RemoveObserver(this);
80   if (child->GetProperty(aura::client::kModalKey) != ui::MODAL_TYPE_NONE)
81     RemoveModalWindow(child);
82 }
83 
OnWindowRemovedFromLayout(aura::Window * child)84 void SystemModalContainerLayoutManager::OnWindowRemovedFromLayout(
85     aura::Window* child) {
86 }
87 
OnChildWindowVisibilityChanged(aura::Window * child,bool visible)88 void SystemModalContainerLayoutManager::OnChildWindowVisibilityChanged(
89     aura::Window* child,
90     bool visible) {
91 }
92 
SetChildBounds(aura::Window * child,const gfx::Rect & requested_bounds)93 void SystemModalContainerLayoutManager::SetChildBounds(
94     aura::Window* child,
95     const gfx::Rect& requested_bounds) {
96   SetChildBoundsDirect(child, requested_bounds);
97 }
98 
99 ////////////////////////////////////////////////////////////////////////////////
100 // SystemModalContainerLayoutManager, aura::WindowObserver implementation:
101 
OnWindowPropertyChanged(aura::Window * window,const void * key,intptr_t old)102 void SystemModalContainerLayoutManager::OnWindowPropertyChanged(
103     aura::Window* window,
104     const void* key,
105     intptr_t old) {
106   if (key != aura::client::kModalKey)
107     return;
108 
109   if (window->GetProperty(aura::client::kModalKey) != ui::MODAL_TYPE_NONE) {
110     AddModalWindow(window);
111   } else if (static_cast<ui::ModalType>(old) != ui::MODAL_TYPE_NONE) {
112     RemoveModalWindow(window);
113     Shell::GetInstance()->OnModalWindowRemoved(window);
114   }
115 }
116 
OnWindowDestroying(aura::Window * window)117 void SystemModalContainerLayoutManager::OnWindowDestroying(
118     aura::Window* window) {
119   if (modal_background_ && modal_background_->GetNativeView() == window)
120     modal_background_ = NULL;
121 }
122 
CanWindowReceiveEvents(aura::Window * window)123 bool SystemModalContainerLayoutManager::CanWindowReceiveEvents(
124     aura::Window* window) {
125   // We could get when we're at lock screen and there is modal window at
126   // system modal window layer which added event filter.
127   // Now this lock modal windows layer layout manager should not block events
128   // for windows at lock layer.
129   // See SystemModalContainerLayoutManagerTest.EventFocusContainers and
130   // http://crbug.com/157469
131   if (modal_windows_.empty())
132     return true;
133   // This container can not handle events if the screen is locked and it is not
134   // above the lock screen layer (crbug.com/110920).
135   if (Shell::GetInstance()->session_state_delegate()->IsUserSessionBlocked() &&
136       container_->id() < ash::internal::kShellWindowId_LockScreenContainer)
137     return true;
138   return wm::GetActivatableWindow(window) == modal_window();
139 }
140 
ActivateNextModalWindow()141 bool SystemModalContainerLayoutManager::ActivateNextModalWindow() {
142   if (modal_windows_.empty())
143     return false;
144   wm::ActivateWindow(modal_window());
145   return true;
146 }
147 
CreateModalBackground()148 void SystemModalContainerLayoutManager::CreateModalBackground() {
149   if (!modal_background_) {
150     modal_background_ = new views::Widget;
151     views::Widget::InitParams params(views::Widget::InitParams::TYPE_CONTROL);
152     params.parent = container_;
153     params.bounds = Shell::GetScreen()->GetDisplayNearestWindow(
154         container_).bounds();
155     modal_background_->Init(params);
156     modal_background_->GetNativeView()->SetName(
157         "SystemModalContainerLayoutManager.ModalBackground");
158     views::View* contents_view = new views::View();
159     // TODO(jamescook): This could be SK_ColorWHITE for the new dialog style.
160     contents_view->set_background(
161         views::Background::CreateSolidBackground(SK_ColorBLACK));
162     modal_background_->SetContentsView(contents_view);
163     modal_background_->GetNativeView()->layer()->SetOpacity(0.0f);
164   }
165 
166   ui::ScopedLayerAnimationSettings settings(
167       modal_background_->GetNativeView()->layer()->GetAnimator());
168   modal_background_->Show();
169   modal_background_->GetNativeView()->layer()->SetOpacity(0.5f);
170   container_->StackChildAtTop(modal_background_->GetNativeView());
171 }
172 
DestroyModalBackground()173 void SystemModalContainerLayoutManager::DestroyModalBackground() {
174   // modal_background_ can be NULL when a root window is shutting down
175   // and OnWindowDestroying is called first.
176   if (modal_background_) {
177     ui::ScopedLayerAnimationSettings settings(
178         modal_background_->GetNativeView()->layer()->GetAnimator());
179     modal_background_->Close();
180     settings.AddObserver(views::corewm::CreateHidingWindowAnimationObserver(
181         modal_background_->GetNativeView()));
182     modal_background_->GetNativeView()->layer()->SetOpacity(0.0f);
183     modal_background_ = NULL;
184   }
185 }
186 
187 // static
IsModalBackground(aura::Window * window)188 bool SystemModalContainerLayoutManager::IsModalBackground(
189     aura::Window* window) {
190   int id = window->parent()->id();
191   if (id != internal::kShellWindowId_SystemModalContainer &&
192       id != internal::kShellWindowId_LockSystemModalContainer)
193     return false;
194   SystemModalContainerLayoutManager* layout_manager =
195       static_cast<SystemModalContainerLayoutManager*>(
196           window->parent()->layout_manager());
197   return layout_manager->modal_background_ &&
198       layout_manager->modal_background_->GetNativeWindow() == window;
199 }
200 
201 ////////////////////////////////////////////////////////////////////////////////
202 // SystemModalContainerLayoutManager, private:
203 
AddModalWindow(aura::Window * window)204 void SystemModalContainerLayoutManager::AddModalWindow(aura::Window* window) {
205   if (modal_windows_.empty()) {
206     aura::Window* capture_window = aura::client::GetCaptureWindow(container_);
207     if (capture_window)
208       capture_window->ReleaseCapture();
209   }
210   modal_windows_.push_back(window);
211   Shell::GetInstance()->CreateModalBackground(window);
212   window->parent()->StackChildAtTop(window);
213 }
214 
RemoveModalWindow(aura::Window * window)215 void SystemModalContainerLayoutManager::RemoveModalWindow(
216     aura::Window* window) {
217   aura::Window::Windows::iterator it =
218       std::find(modal_windows_.begin(), modal_windows_.end(), window);
219   if (it != modal_windows_.end())
220     modal_windows_.erase(it);
221 }
222 
223 }  // namespace internal
224 }  // namespace ash
225