Prevents double-clicks on a tab close button from aslo maximizing the browser
[chromium-blink-merge.git] / ash / wm / system_modal_container_layout_manager.cc
blob7de575994b9a70f38d8d93476e06bab4cae68487
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.
5 #include "ash/wm/system_modal_container_layout_manager.h"
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/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"
30 namespace ash {
32 ////////////////////////////////////////////////////////////////////////////////
33 // SystemModalContainerLayoutManager, public:
35 SystemModalContainerLayoutManager::SystemModalContainerLayoutManager(
36 aura::Window* container)
37 : container_(container),
38 modal_background_(NULL) {
41 SystemModalContainerLayoutManager::~SystemModalContainerLayoutManager() {
44 ////////////////////////////////////////////////////////////////////////////////
45 // SystemModalContainerLayoutManager, aura::LayoutManager implementation:
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());
53 PositionDialogsAfterWorkAreaResize();
56 void 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());
65 child->AddObserver(this);
66 if (child->GetProperty(aura::client::kModalKey) != ui::MODAL_TYPE_NONE)
67 AddModalWindow(child);
70 void SystemModalContainerLayoutManager::OnWillRemoveWindowFromLayout(
71 aura::Window* child) {
72 child->RemoveObserver(this);
73 if (child->GetProperty(aura::client::kModalKey) != ui::MODAL_TYPE_NONE)
74 RemoveModalWindow(child);
77 void SystemModalContainerLayoutManager::OnWindowRemovedFromLayout(
78 aura::Window* child) {
81 void SystemModalContainerLayoutManager::OnChildWindowVisibilityChanged(
82 aura::Window* child,
83 bool visible) {
86 void SystemModalContainerLayoutManager::SetChildBounds(
87 aura::Window* child,
88 const gfx::Rect& requested_bounds) {
89 SetChildBoundsDirect(child, requested_bounds);
92 ////////////////////////////////////////////////////////////////////////////////
93 // SystemModalContainerLayoutManager, aura::WindowObserver implementation:
95 void SystemModalContainerLayoutManager::OnWindowPropertyChanged(
96 aura::Window* window,
97 const void* key,
98 intptr_t old) {
99 if (key != aura::client::kModalKey)
100 return;
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);
110 void SystemModalContainerLayoutManager::OnWindowDestroying(
111 aura::Window* window) {
112 if (modal_background_ && modal_background_->GetNativeView() == window)
113 modal_background_ = NULL;
116 ////////////////////////////////////////////////////////////////////////////////
117 // SystemModalContainerLayoutManager, Keyboard::KeybaordControllerObserver
118 // implementation:
120 void SystemModalContainerLayoutManager::OnKeyboardBoundsChanging(
121 const gfx::Rect& new_bounds) {
122 PositionDialogsAfterWorkAreaResize();
125 bool 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();
143 bool SystemModalContainerLayoutManager::ActivateNextModalWindow() {
144 if (modal_windows_.empty())
145 return false;
146 wm::ActivateWindow(modal_window());
147 return true;
150 void 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);
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());
180 void 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;
194 // static
195 bool 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;
208 ////////////////////////////////////////////////////////////////////////////////
209 // SystemModalContainerLayoutManager, private:
211 void 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();
217 modal_windows_.push_back(window);
218 Shell::GetInstance()->CreateModalBackground(window);
219 window->parent()->StackChildAtTop(window);
221 gfx::Rect target_bounds = window->bounds();
222 target_bounds.AdjustToFit(GetUsableDialogArea());
223 window->SetBounds(target_bounds);
226 void 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);
234 void SystemModalContainerLayoutManager::PositionDialogsAfterWorkAreaResize() {
235 gfx::Rect valid_bounds = GetUsableDialogArea();
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);
247 gfx::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());
263 return valid_bounds;
266 } // namespace ash