| OLD | NEW |
| (Empty) |
| 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 <cmath> | |
| 8 | |
| 9 #include "ash/aura/wm_window_aura.h" | |
| 10 #include "ash/common/session/session_state_delegate.h" | |
| 11 #include "ash/common/shell_window_ids.h" | |
| 12 #include "ash/common/wm/window_dimmer.h" | |
| 13 #include "ash/common/wm_shell.h" | |
| 14 #include "ash/shell.h" | |
| 15 #include "ash/wm/window_util.h" | |
| 16 #include "base/stl_util.h" | |
| 17 #include "ui/aura/client/aura_constants.h" | |
| 18 #include "ui/aura/client/capture_client.h" | |
| 19 #include "ui/aura/window.h" | |
| 20 #include "ui/aura/window_property.h" | |
| 21 #include "ui/compositor/layer.h" | |
| 22 #include "ui/keyboard/keyboard_controller.h" | |
| 23 #include "ui/wm/core/window_util.h" | |
| 24 | |
| 25 namespace ash { | |
| 26 namespace { | |
| 27 | |
| 28 // The center point of the window can diverge this much from the center point | |
| 29 // If this is set to true, the window will get centered. | |
| 30 DEFINE_WINDOW_PROPERTY_KEY(bool, kCenteredKey, false); | |
| 31 | |
| 32 // The center point of the window can diverge this much from the center point | |
| 33 // of the container to be kept centered upon resizing operations. | |
| 34 const int kCenterPixelDelta = 32; | |
| 35 } | |
| 36 | |
| 37 //////////////////////////////////////////////////////////////////////////////// | |
| 38 // SystemModalContainerLayoutManager, public: | |
| 39 | |
| 40 SystemModalContainerLayoutManager::SystemModalContainerLayoutManager( | |
| 41 aura::Window* container) | |
| 42 : SnapToPixelLayoutManager(container), container_(container) {} | |
| 43 | |
| 44 SystemModalContainerLayoutManager::~SystemModalContainerLayoutManager() {} | |
| 45 | |
| 46 //////////////////////////////////////////////////////////////////////////////// | |
| 47 // SystemModalContainerLayoutManager, aura::LayoutManager implementation: | |
| 48 | |
| 49 void SystemModalContainerLayoutManager::OnWindowResized() { | |
| 50 PositionDialogsAfterWorkAreaResize(); | |
| 51 } | |
| 52 | |
| 53 void SystemModalContainerLayoutManager::OnWindowAddedToLayout( | |
| 54 aura::Window* child) { | |
| 55 DCHECK(child->type() == ui::wm::WINDOW_TYPE_NORMAL || | |
| 56 child->type() == ui::wm::WINDOW_TYPE_POPUP); | |
| 57 DCHECK( | |
| 58 container_->id() != kShellWindowId_LockSystemModalContainer || | |
| 59 WmShell::Get()->GetSessionStateDelegate()->IsUserSessionBlocked()); | |
| 60 // Since this is for SystemModal, there is no goodd reason to add | |
| 61 // these window other than MODAL_TYPE_NONE or MODAL_TYPE_SYSTEM. | |
| 62 // DCHECK to avoid simple mistake. | |
| 63 DCHECK_NE(child->GetProperty(aura::client::kModalKey), ui::MODAL_TYPE_CHILD); | |
| 64 DCHECK_NE(child->GetProperty(aura::client::kModalKey), ui::MODAL_TYPE_WINDOW); | |
| 65 | |
| 66 child->AddObserver(this); | |
| 67 if (child->GetProperty(aura::client::kModalKey) == ui::MODAL_TYPE_SYSTEM && | |
| 68 child->IsVisible()) { | |
| 69 AddModalWindow(child); | |
| 70 } | |
| 71 } | |
| 72 | |
| 73 void SystemModalContainerLayoutManager::OnWillRemoveWindowFromLayout( | |
| 74 aura::Window* child) { | |
| 75 child->RemoveObserver(this); | |
| 76 if (child->GetProperty(aura::client::kModalKey) == ui::MODAL_TYPE_SYSTEM) | |
| 77 RemoveModalWindow(child); | |
| 78 } | |
| 79 | |
| 80 void SystemModalContainerLayoutManager::SetChildBounds( | |
| 81 aura::Window* child, | |
| 82 const gfx::Rect& requested_bounds) { | |
| 83 SnapToPixelLayoutManager::SetChildBounds(child, requested_bounds); | |
| 84 child->SetProperty(kCenteredKey, DialogIsCentered(requested_bounds)); | |
| 85 } | |
| 86 | |
| 87 //////////////////////////////////////////////////////////////////////////////// | |
| 88 // SystemModalContainerLayoutManager, aura::WindowObserver implementation: | |
| 89 | |
| 90 void SystemModalContainerLayoutManager::OnWindowPropertyChanged( | |
| 91 aura::Window* window, | |
| 92 const void* key, | |
| 93 intptr_t old) { | |
| 94 if (key != aura::client::kModalKey || !window->IsVisible()) | |
| 95 return; | |
| 96 | |
| 97 ui::ModalType new_modal = window->GetProperty(aura::client::kModalKey); | |
| 98 if (static_cast<ui::ModalType>(old) == new_modal) | |
| 99 return; | |
| 100 | |
| 101 if (new_modal == ui::MODAL_TYPE_SYSTEM) { | |
| 102 AddModalWindow(window); | |
| 103 } else { | |
| 104 RemoveModalWindow(window); | |
| 105 Shell::GetInstance()->OnModalWindowRemoved(window); | |
| 106 } | |
| 107 } | |
| 108 | |
| 109 void SystemModalContainerLayoutManager::OnWindowVisibilityChanged( | |
| 110 aura::Window* window, | |
| 111 bool visible) { | |
| 112 if (window->GetProperty(aura::client::kModalKey) != ui::MODAL_TYPE_SYSTEM) | |
| 113 return; | |
| 114 if (window->IsVisible()) { | |
| 115 AddModalWindow(window); | |
| 116 } else { | |
| 117 RemoveModalWindow(window); | |
| 118 Shell::GetInstance()->OnModalWindowRemoved(window); | |
| 119 } | |
| 120 } | |
| 121 | |
| 122 //////////////////////////////////////////////////////////////////////////////// | |
| 123 // SystemModalContainerLayoutManager, Keyboard::KeybaordControllerObserver | |
| 124 // implementation: | |
| 125 | |
| 126 void SystemModalContainerLayoutManager::OnKeyboardBoundsChanging( | |
| 127 const gfx::Rect& new_bounds) { | |
| 128 PositionDialogsAfterWorkAreaResize(); | |
| 129 } | |
| 130 | |
| 131 bool SystemModalContainerLayoutManager::IsPartOfActiveModalWindow( | |
| 132 aura::Window* window) { | |
| 133 return modal_window() && | |
| 134 (modal_window()->Contains(window) || | |
| 135 ::wm::HasTransientAncestor(::wm::GetToplevelWindow(window), | |
| 136 modal_window())); | |
| 137 } | |
| 138 | |
| 139 bool SystemModalContainerLayoutManager::ActivateNextModalWindow() { | |
| 140 if (modal_windows_.empty()) | |
| 141 return false; | |
| 142 wm::ActivateWindow(modal_window()); | |
| 143 return true; | |
| 144 } | |
| 145 | |
| 146 void SystemModalContainerLayoutManager::CreateModalBackground() { | |
| 147 if (!window_dimmer_) { | |
| 148 window_dimmer_ = | |
| 149 base::MakeUnique<WindowDimmer>(WmWindowAura::Get(container_)); | |
| 150 window_dimmer_->window()->SetName( | |
| 151 "SystemModalContainerLayoutManager.ModalBackground"); | |
| 152 // There isn't always a keyboard controller. | |
| 153 if (keyboard::KeyboardController::GetInstance()) | |
| 154 keyboard::KeyboardController::GetInstance()->AddObserver(this); | |
| 155 } | |
| 156 window_dimmer_->window()->Show(); | |
| 157 } | |
| 158 | |
| 159 void SystemModalContainerLayoutManager::DestroyModalBackground() { | |
| 160 if (!window_dimmer_) | |
| 161 return; | |
| 162 | |
| 163 if (keyboard::KeyboardController::GetInstance()) | |
| 164 keyboard::KeyboardController::GetInstance()->RemoveObserver(this); | |
| 165 window_dimmer_.reset(); | |
| 166 } | |
| 167 | |
| 168 // static | |
| 169 bool SystemModalContainerLayoutManager::IsModalBackground( | |
| 170 aura::Window* window) { | |
| 171 int id = window->parent()->id(); | |
| 172 if (id != kShellWindowId_SystemModalContainer && | |
| 173 id != kShellWindowId_LockSystemModalContainer) | |
| 174 return false; | |
| 175 SystemModalContainerLayoutManager* layout_manager = | |
| 176 static_cast<SystemModalContainerLayoutManager*>( | |
| 177 window->parent()->layout_manager()); | |
| 178 return layout_manager->window_dimmer_ && | |
| 179 layout_manager->window_dimmer_->window() == WmWindowAura::Get(window); | |
| 180 } | |
| 181 | |
| 182 //////////////////////////////////////////////////////////////////////////////// | |
| 183 // SystemModalContainerLayoutManager, private: | |
| 184 | |
| 185 void SystemModalContainerLayoutManager::AddModalWindow(aura::Window* window) { | |
| 186 if (modal_windows_.empty()) { | |
| 187 aura::Window* capture_window = aura::client::GetCaptureWindow(container_); | |
| 188 if (capture_window) | |
| 189 capture_window->ReleaseCapture(); | |
| 190 } | |
| 191 DCHECK(window->IsVisible()); | |
| 192 DCHECK(!base::ContainsValue(modal_windows_, window)); | |
| 193 | |
| 194 modal_windows_.push_back(window); | |
| 195 Shell::GetInstance()->CreateModalBackground(window); | |
| 196 window->parent()->StackChildAtTop(window); | |
| 197 | |
| 198 gfx::Rect target_bounds = window->bounds(); | |
| 199 target_bounds.AdjustToFit(GetUsableDialogArea()); | |
| 200 window->SetBounds(target_bounds); | |
| 201 } | |
| 202 | |
| 203 void SystemModalContainerLayoutManager::RemoveModalWindow( | |
| 204 aura::Window* window) { | |
| 205 aura::Window::Windows::iterator it = | |
| 206 std::find(modal_windows_.begin(), modal_windows_.end(), window); | |
| 207 if (it != modal_windows_.end()) | |
| 208 modal_windows_.erase(it); | |
| 209 } | |
| 210 | |
| 211 void SystemModalContainerLayoutManager::PositionDialogsAfterWorkAreaResize() { | |
| 212 if (!modal_windows_.empty()) { | |
| 213 for (aura::Window::Windows::iterator it = modal_windows_.begin(); | |
| 214 it != modal_windows_.end(); ++it) { | |
| 215 (*it)->SetBounds(GetCenteredAndOrFittedBounds(*it)); | |
| 216 } | |
| 217 } | |
| 218 } | |
| 219 | |
| 220 gfx::Rect SystemModalContainerLayoutManager::GetUsableDialogArea() { | |
| 221 // Instead of resizing the system modal container, we move only the modal | |
| 222 // windows. This way we avoid flashing lines upon resize animation and if the | |
| 223 // keyboard will not fill left to right, the background is still covered. | |
| 224 gfx::Rect valid_bounds = container_->bounds(); | |
| 225 keyboard::KeyboardController* keyboard_controller = | |
| 226 keyboard::KeyboardController::GetInstance(); | |
| 227 if (keyboard_controller) { | |
| 228 gfx::Rect bounds = keyboard_controller->current_keyboard_bounds(); | |
| 229 if (!bounds.IsEmpty()) { | |
| 230 valid_bounds.set_height( | |
| 231 std::max(0, valid_bounds.height() - bounds.height())); | |
| 232 } | |
| 233 } | |
| 234 return valid_bounds; | |
| 235 } | |
| 236 | |
| 237 gfx::Rect SystemModalContainerLayoutManager::GetCenteredAndOrFittedBounds( | |
| 238 const aura::Window* window) { | |
| 239 gfx::Rect target_bounds; | |
| 240 gfx::Rect usable_area = GetUsableDialogArea(); | |
| 241 if (window->GetProperty(kCenteredKey)) { | |
| 242 // Keep the dialog centered if it was centered before. | |
| 243 target_bounds = usable_area; | |
| 244 target_bounds.ClampToCenteredSize(window->bounds().size()); | |
| 245 } else { | |
| 246 // Keep the dialog within the usable area. | |
| 247 target_bounds = window->bounds(); | |
| 248 target_bounds.AdjustToFit(usable_area); | |
| 249 } | |
| 250 if (usable_area != container_->bounds()) { | |
| 251 // Don't clamp the dialog for the keyboard. Keep the size as it is but make | |
| 252 // sure that the top remains visible. | |
| 253 // TODO(skuhne): M37 should add over scroll functionality to address this. | |
| 254 target_bounds.set_size(window->bounds().size()); | |
| 255 } | |
| 256 return target_bounds; | |
| 257 } | |
| 258 | |
| 259 bool SystemModalContainerLayoutManager::DialogIsCentered( | |
| 260 const gfx::Rect& window_bounds) { | |
| 261 gfx::Point window_center = window_bounds.CenterPoint(); | |
| 262 gfx::Point container_center = GetUsableDialogArea().CenterPoint(); | |
| 263 return std::abs(window_center.x() - container_center.x()) < | |
| 264 kCenterPixelDelta && | |
| 265 std::abs(window_center.y() - container_center.y()) < kCenterPixelDelta; | |
| 266 } | |
| 267 | |
| 268 } // namespace ash | |
| OLD | NEW |