system_modal_container_layout_manager.cc revision 5c02ac1a9c1b504631c0a3d2b6e737b5d738bae1
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/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/window.h" 17#include "ui/aura/window_event_dispatcher.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/keyboard/keyboard_controller.h" 25#include "ui/views/background.h" 26#include "ui/views/view.h" 27#include "ui/views/widget/widget.h" 28#include "ui/wm/core/compound_event_filter.h" 29 30namespace ash { 31 32//////////////////////////////////////////////////////////////////////////////// 33// SystemModalContainerLayoutManager, public: 34 35SystemModalContainerLayoutManager::SystemModalContainerLayoutManager( 36 aura::Window* container) 37 : container_(container), 38 modal_background_(NULL) { 39} 40 41SystemModalContainerLayoutManager::~SystemModalContainerLayoutManager() { 42} 43 44//////////////////////////////////////////////////////////////////////////////// 45// SystemModalContainerLayoutManager, aura::LayoutManager implementation: 46 47void 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 PositionDialogsAfterWorkAreaResize(); 54} 55 56void SystemModalContainerLayoutManager::OnWindowAddedToLayout( 57 aura::Window* child) { 58 DCHECK((modal_background_ && child == modal_background_->GetNativeView()) || 59 child->type() == ui::wm::WINDOW_TYPE_NORMAL || 60 child->type() == ui::wm::WINDOW_TYPE_POPUP); 61 DCHECK( 62 container_->id() != kShellWindowId_LockSystemModalContainer || 63 Shell::GetInstance()->session_state_delegate()->IsUserSessionBlocked()); 64 65 child->AddObserver(this); 66 if (child->GetProperty(aura::client::kModalKey) != ui::MODAL_TYPE_NONE) 67 AddModalWindow(child); 68} 69 70void SystemModalContainerLayoutManager::OnWillRemoveWindowFromLayout( 71 aura::Window* child) { 72 child->RemoveObserver(this); 73 if (child->GetProperty(aura::client::kModalKey) != ui::MODAL_TYPE_NONE) 74 RemoveModalWindow(child); 75} 76 77void SystemModalContainerLayoutManager::OnWindowRemovedFromLayout( 78 aura::Window* child) { 79} 80 81void SystemModalContainerLayoutManager::OnChildWindowVisibilityChanged( 82 aura::Window* child, 83 bool visible) { 84} 85 86void SystemModalContainerLayoutManager::SetChildBounds( 87 aura::Window* child, 88 const gfx::Rect& requested_bounds) { 89 SetChildBoundsDirect(child, requested_bounds); 90} 91 92//////////////////////////////////////////////////////////////////////////////// 93// SystemModalContainerLayoutManager, aura::WindowObserver implementation: 94 95void SystemModalContainerLayoutManager::OnWindowPropertyChanged( 96 aura::Window* window, 97 const void* key, 98 intptr_t old) { 99 if (key != aura::client::kModalKey) 100 return; 101 102 if (window->GetProperty(aura::client::kModalKey) != ui::MODAL_TYPE_NONE) { 103 AddModalWindow(window); 104 } else if (static_cast<ui::ModalType>(old) != ui::MODAL_TYPE_NONE) { 105 RemoveModalWindow(window); 106 Shell::GetInstance()->OnModalWindowRemoved(window); 107 } 108} 109 110void SystemModalContainerLayoutManager::OnWindowDestroying( 111 aura::Window* window) { 112 if (modal_background_ && modal_background_->GetNativeView() == window) 113 modal_background_ = NULL; 114} 115 116//////////////////////////////////////////////////////////////////////////////// 117// SystemModalContainerLayoutManager, Keyboard::KeybaordControllerObserver 118// implementation: 119 120void SystemModalContainerLayoutManager::OnKeyboardBoundsChanging( 121 const gfx::Rect& new_bounds) { 122 PositionDialogsAfterWorkAreaResize(); 123} 124 125bool SystemModalContainerLayoutManager::CanWindowReceiveEvents( 126 aura::Window* window) { 127 // We could get when we're at lock screen and there is modal window at 128 // system modal window layer which added event filter. 129 // Now this lock modal windows layer layout manager should not block events 130 // for windows at lock layer. 131 // See SystemModalContainerLayoutManagerTest.EventFocusContainers and 132 // http://crbug.com/157469 133 if (modal_windows_.empty()) 134 return true; 135 // This container can not handle events if the screen is locked and it is not 136 // above the lock screen layer (crbug.com/110920). 137 if (Shell::GetInstance()->session_state_delegate()->IsUserSessionBlocked() && 138 container_->id() < ash::kShellWindowId_LockScreenContainer) 139 return true; 140 return wm::GetActivatableWindow(window) == modal_window(); 141} 142 143bool SystemModalContainerLayoutManager::ActivateNextModalWindow() { 144 if (modal_windows_.empty()) 145 return false; 146 wm::ActivateWindow(modal_window()); 147 return true; 148} 149 150void SystemModalContainerLayoutManager::CreateModalBackground() { 151 if (!modal_background_) { 152 modal_background_ = new views::Widget; 153 views::Widget::InitParams params(views::Widget::InitParams::TYPE_CONTROL); 154 params.parent = container_; 155 params.bounds = Shell::GetScreen()->GetDisplayNearestWindow( 156 container_).bounds(); 157 modal_background_->Init(params); 158 modal_background_->GetNativeView()->SetName( 159 "SystemModalContainerLayoutManager.ModalBackground"); 160 views::View* contents_view = new views::View(); 161 // TODO(jamescook): This could be SK_ColorWHITE for the new dialog style. 162 contents_view->set_background( 163 views::Background::CreateSolidBackground(SK_ColorBLACK)); 164 modal_background_->SetContentsView(contents_view); 165 modal_background_->GetNativeView()->layer()->SetOpacity(0.0f); 166 // There isn't always a keyboard controller. 167 if (keyboard::KeyboardController::GetInstance()) 168 keyboard::KeyboardController::GetInstance()->AddObserver(this); 169 } 170 171 ui::ScopedLayerAnimationSettings settings( 172 modal_background_->GetNativeView()->layer()->GetAnimator()); 173 // Show should not be called with a target opacity of 0. We therefore start 174 // the fade to show animation before Show() is called. 175 modal_background_->GetNativeView()->layer()->SetOpacity(0.5f); 176 modal_background_->Show(); 177 container_->StackChildAtTop(modal_background_->GetNativeView()); 178} 179 180void SystemModalContainerLayoutManager::DestroyModalBackground() { 181 // modal_background_ can be NULL when a root window is shutting down 182 // and OnWindowDestroying is called first. 183 if (modal_background_) { 184 if (keyboard::KeyboardController::GetInstance()) 185 keyboard::KeyboardController::GetInstance()->RemoveObserver(this); 186 ::wm::ScopedHidingAnimationSettings settings( 187 modal_background_->GetNativeView()); 188 modal_background_->Close(); 189 modal_background_->GetNativeView()->layer()->SetOpacity(0.0f); 190 modal_background_ = NULL; 191 } 192} 193 194// static 195bool SystemModalContainerLayoutManager::IsModalBackground( 196 aura::Window* window) { 197 int id = window->parent()->id(); 198 if (id != kShellWindowId_SystemModalContainer && 199 id != kShellWindowId_LockSystemModalContainer) 200 return false; 201 SystemModalContainerLayoutManager* layout_manager = 202 static_cast<SystemModalContainerLayoutManager*>( 203 window->parent()->layout_manager()); 204 return layout_manager->modal_background_ && 205 layout_manager->modal_background_->GetNativeWindow() == window; 206} 207 208//////////////////////////////////////////////////////////////////////////////// 209// SystemModalContainerLayoutManager, private: 210 211void SystemModalContainerLayoutManager::AddModalWindow(aura::Window* window) { 212 if (modal_windows_.empty()) { 213 aura::Window* capture_window = aura::client::GetCaptureWindow(container_); 214 if (capture_window) 215 capture_window->ReleaseCapture(); 216 } 217 modal_windows_.push_back(window); 218 Shell::GetInstance()->CreateModalBackground(window); 219 window->parent()->StackChildAtTop(window); 220 221 gfx::Rect target_bounds = window->bounds(); 222 target_bounds.AdjustToFit(GetUsableDialogArea()); 223 window->SetBounds(target_bounds); 224} 225 226void SystemModalContainerLayoutManager::RemoveModalWindow( 227 aura::Window* window) { 228 aura::Window::Windows::iterator it = 229 std::find(modal_windows_.begin(), modal_windows_.end(), window); 230 if (it != modal_windows_.end()) 231 modal_windows_.erase(it); 232} 233 234void SystemModalContainerLayoutManager::PositionDialogsAfterWorkAreaResize() { 235 gfx::Rect valid_bounds = GetUsableDialogArea(); 236 237 if (!modal_windows_.empty()) { 238 for (aura::Window::Windows::iterator it = modal_windows_.begin(); 239 it != modal_windows_.end(); ++it) { 240 gfx::Rect bounds = (*it)->bounds(); 241 bounds.AdjustToFit(valid_bounds); 242 (*it)->SetBounds(bounds); 243 } 244 } 245} 246 247gfx::Rect SystemModalContainerLayoutManager::GetUsableDialogArea() { 248 // Instead of resizing the system modal container, we move only the modal 249 // windows. This way we avoid flashing lines upon resize animation and if the 250 // keyboard will not fill left to right, the background is still covered. 251 gfx::Rect valid_bounds = container_->bounds(); 252 keyboard::KeyboardController* keyboard_controller = 253 keyboard::KeyboardController::GetInstance(); 254 if (keyboard_controller) { 255 gfx::Rect bounds = keyboard_controller->current_keyboard_bounds(); 256 if (!bounds.IsEmpty()) { 257 DCHECK_EQ(valid_bounds.x(), bounds.x()); 258 DCHECK_EQ(valid_bounds.right(), bounds.right()); 259 DCHECK_LT(valid_bounds.y(), bounds.y()); 260 valid_bounds.set_height(bounds.y() - valid_bounds.y()); 261 } 262 } 263 return valid_bounds; 264} 265 266} // namespace ash 267