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 35 SystemModalContainerLayoutManager::SystemModalContainerLayoutManager( 36 aura::Window* container) 37 : container_(container), 38 modal_background_(NULL) { 39 } 40 41 SystemModalContainerLayoutManager::~SystemModalContainerLayoutManager() { 42 } 43 44 //////////////////////////////////////////////////////////////////////////////// 45 // SystemModalContainerLayoutManager, aura::LayoutManager implementation: 46 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 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 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 84 void SystemModalContainerLayoutManager::OnWindowRemovedFromLayout( 85 aura::Window* child) { 86 } 87 88 void SystemModalContainerLayoutManager::OnChildWindowVisibilityChanged( 89 aura::Window* child, 90 bool visible) { 91 } 92 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 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 117 void SystemModalContainerLayoutManager::OnWindowDestroying( 118 aura::Window* window) { 119 if (modal_background_ && modal_background_->GetNativeView() == window) 120 modal_background_ = NULL; 121 } 122 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 141 bool SystemModalContainerLayoutManager::ActivateNextModalWindow() { 142 if (modal_windows_.empty()) 143 return false; 144 wm::ActivateWindow(modal_window()); 145 return true; 146 } 147 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 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 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 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 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