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/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" 27 28 namespace ash { 29 namespace internal { 30 31 //////////////////////////////////////////////////////////////////////////////// 32 // SystemModalContainerLayoutManager, public: 33 34 SystemModalContainerLayoutManager::SystemModalContainerLayoutManager( 35 aura::Window* container) 36 : container_(container), 37 modal_background_(NULL) { 38 } 39 40 SystemModalContainerLayoutManager::~SystemModalContainerLayoutManager() { 41 } 42 43 //////////////////////////////////////////////////////////////////////////////// 44 // SystemModalContainerLayoutManager, aura::LayoutManager implementation: 45 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()); 51 } 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); 58 } 59 } 60 } 61 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); 67 DCHECK( 68 container_->id() != internal::kShellWindowId_LockSystemModalContainer || 69 Shell::GetInstance()->session_state_delegate()->IsUserSessionBlocked()); 70 71 child->AddObserver(this); 72 if (child->GetProperty(aura::client::kModalKey) != ui::MODAL_TYPE_NONE) 73 AddModalWindow(child); 74 } 75 76 void SystemModalContainerLayoutManager::OnWillRemoveWindowFromLayout( 77 aura::Window* child) { 78 child->RemoveObserver(this); 79 if (child->GetProperty(aura::client::kModalKey) != ui::MODAL_TYPE_NONE) 80 RemoveModalWindow(child); 81 } 82 83 void SystemModalContainerLayoutManager::OnWindowRemovedFromLayout( 84 aura::Window* child) { 85 } 86 87 void SystemModalContainerLayoutManager::OnChildWindowVisibilityChanged( 88 aura::Window* child, 89 bool visible) { 90 } 91 92 void SystemModalContainerLayoutManager::SetChildBounds( 93 aura::Window* child, 94 const gfx::Rect& requested_bounds) { 95 SetChildBoundsDirect(child, requested_bounds); 96 } 97 98 //////////////////////////////////////////////////////////////////////////////// 99 // SystemModalContainerLayoutManager, aura::WindowObserver implementation: 100 101 void SystemModalContainerLayoutManager::OnWindowPropertyChanged( 102 aura::Window* window, 103 const void* key, 104 intptr_t old) { 105 if (key != aura::client::kModalKey) 106 return; 107 108 if (window->GetProperty(aura::client::kModalKey) != ui::MODAL_TYPE_NONE) { 109 AddModalWindow(window); 110 } else if (static_cast<ui::ModalType>(old) != ui::MODAL_TYPE_NONE) { 111 RemoveModalWindow(window); 112 Shell::GetInstance()->OnModalWindowRemoved(window); 113 } 114 } 115 116 void SystemModalContainerLayoutManager::OnWindowDestroying( 117 aura::Window* window) { 118 if (modal_background_ && modal_background_->GetNativeView() == window) 119 modal_background_ = NULL; 120 } 121 122 bool SystemModalContainerLayoutManager::CanWindowReceiveEvents( 123 aura::Window* window) { 124 // We could get when we're at lock screen and there is modal window at 125 // system modal window layer which added event filter. 126 // Now this lock modal windows layer layout manager should not block events 127 // for windows at lock layer. 128 // See SystemModalContainerLayoutManagerTest.EventFocusContainers and 129 // http://crbug.com/157469 130 if (modal_windows_.empty()) 131 return true; 132 // This container can not handle events if the screen is locked and it is not 133 // above the lock screen layer (crbug.com/110920). 134 if (Shell::GetInstance()->session_state_delegate()->IsUserSessionBlocked() && 135 container_->id() < ash::internal::kShellWindowId_LockScreenContainer) 136 return true; 137 return wm::GetActivatableWindow(window) == modal_window(); 138 } 139 140 bool SystemModalContainerLayoutManager::ActivateNextModalWindow() { 141 if (modal_windows_.empty()) 142 return false; 143 wm::ActivateWindow(modal_window()); 144 return true; 145 } 146 147 void SystemModalContainerLayoutManager::CreateModalBackground() { 148 if (!modal_background_) { 149 modal_background_ = new views::Widget; 150 views::Widget::InitParams params(views::Widget::InitParams::TYPE_CONTROL); 151 params.parent = container_; 152 params.bounds = Shell::GetScreen()->GetDisplayNearestWindow( 153 container_).bounds(); 154 modal_background_->Init(params); 155 modal_background_->GetNativeView()->SetName( 156 "SystemModalContainerLayoutManager.ModalBackground"); 157 views::View* contents_view = new views::View(); 158 // TODO(jamescook): This could also be SK_ColorWHITE if using the new 159 // dialog style via switches::IsNewDialogStyleEnabled(). 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