system_modal_container_layout_manager.cc revision 2a99a7e74a7f215066514fe81d2bfa6639d9eddd
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/shell.h"
8#include "ash/shell_delegate.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 "base/command_line.h"
15#include "ui/aura/client/aura_constants.h"
16#include "ui/aura/client/capture_client.h"
17#include "ui/aura/root_window.h"
18#include "ui/views/corewm/compound_event_filter.h"
19#include "ui/aura/window.h"
20#include "ui/base/events/event.h"
21#include "ui/base/ui_base_switches.h"
22#include "ui/compositor/layer.h"
23#include "ui/compositor/layer_animator.h"
24#include "ui/compositor/scoped_layer_animation_settings.h"
25#include "ui/gfx/screen.h"
26#include "ui/views/view.h"
27#include "ui/views/widget/widget.h"
28
29namespace ash {
30namespace internal {
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  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
63void 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()->delegate()->IsScreenLocked() ||
71      !Shell::GetInstance()->delegate()->IsSessionStarted());
72
73  child->AddObserver(this);
74  if (child->GetProperty(aura::client::kModalKey) != ui::MODAL_TYPE_NONE)
75    AddModalWindow(child);
76}
77
78void SystemModalContainerLayoutManager::OnWillRemoveWindowFromLayout(
79    aura::Window* child) {
80  child->RemoveObserver(this);
81  if (child->GetProperty(aura::client::kModalKey) != ui::MODAL_TYPE_NONE)
82    RemoveModalWindow(child);
83}
84
85void SystemModalContainerLayoutManager::OnWindowRemovedFromLayout(
86    aura::Window* child) {
87}
88
89void SystemModalContainerLayoutManager::OnChildWindowVisibilityChanged(
90    aura::Window* child,
91    bool visible) {
92}
93
94void SystemModalContainerLayoutManager::SetChildBounds(
95    aura::Window* child,
96    const gfx::Rect& requested_bounds) {
97  SetChildBoundsDirect(child, requested_bounds);
98}
99
100////////////////////////////////////////////////////////////////////////////////
101// SystemModalContainerLayoutManager, aura::WindowObserver implementation:
102
103void SystemModalContainerLayoutManager::OnWindowPropertyChanged(
104    aura::Window* window,
105    const void* key,
106    intptr_t old) {
107  if (key != aura::client::kModalKey)
108    return;
109
110  if (window->GetProperty(aura::client::kModalKey) != ui::MODAL_TYPE_NONE) {
111    AddModalWindow(window);
112  } else if (static_cast<ui::ModalType>(old) != ui::MODAL_TYPE_NONE) {
113    RemoveModalWindow(window);
114    Shell::GetInstance()->OnModalWindowRemoved(window);
115  }
116}
117
118void SystemModalContainerLayoutManager::OnWindowDestroying(
119    aura::Window* window) {
120  if (modal_background_ && modal_background_->GetNativeView() == window)
121    modal_background_ = NULL;
122}
123
124
125////////////////////////////////////////////////////////////////////////////////
126// SystemModalContainerLayoutManager,
127//     SystemModalContainerEventFilter::Delegate implementation:
128
129bool SystemModalContainerLayoutManager::CanWindowReceiveEvents(
130    aura::Window* window) {
131  // We could get when we're at lock screen and there is modal window at
132  // system modal window layer which added event filter.
133  // Now this lock modal windows layer layout manager should not block events
134  // for windows at lock layer.
135  // See SystemModalContainerLayoutManagerTest.EventFocusContainers and
136  // http://crbug.com/157469
137  if (modal_windows_.empty())
138    return true;
139  // This container can not handle events if the screen is locked and it is not
140  // above the lock screen layer (crbug.com/110920).
141  if (ash::Shell::GetInstance()->IsScreenLocked() &&
142      container_->id() < ash::internal::kShellWindowId_LockScreenContainer)
143    return true;
144  return wm::GetActivatableWindow(window) == modal_window();
145}
146
147bool SystemModalContainerLayoutManager::ActivateNextModalWindow() {
148  if (modal_windows_.empty())
149    return false;
150  wm::ActivateWindow(modal_window());
151  return true;
152}
153
154void SystemModalContainerLayoutManager::CreateModalBackground() {
155  if (!modal_background_) {
156    modal_background_ = new views::Widget;
157    views::Widget::InitParams params(views::Widget::InitParams::TYPE_CONTROL);
158    params.parent = container_;
159    params.bounds = Shell::GetScreen()->GetDisplayNearestWindow(
160        container_).bounds();
161    modal_background_->Init(params);
162    modal_background_->GetNativeView()->SetName(
163        "SystemModalContainerLayoutManager.ModalBackground");
164    views::View* contents_view = new views::View();
165    contents_view->set_background(views::Background::CreateSolidBackground(
166        CommandLine::ForCurrentProcess()->HasSwitch(
167            switches::kEnableNewDialogStyle) ? SK_ColorWHITE : SK_ColorBLACK));
168    modal_background_->SetContentsView(contents_view);
169    modal_background_->GetNativeView()->layer()->SetOpacity(0.0f);
170  }
171
172  ui::ScopedLayerAnimationSettings settings(
173      modal_background_->GetNativeView()->layer()->GetAnimator());
174  modal_background_->Show();
175  modal_background_->GetNativeView()->layer()->SetOpacity(0.5f);
176  container_->StackChildAtTop(modal_background_->GetNativeView());
177}
178
179void SystemModalContainerLayoutManager::DestroyModalBackground() {
180  // modal_background_ can be NULL when a root window is shutting down
181  // and OnWindowDestroying is called first.
182  if (modal_background_) {
183    ui::ScopedLayerAnimationSettings settings(
184        modal_background_->GetNativeView()->layer()->GetAnimator());
185    modal_background_->Close();
186    settings.AddObserver(views::corewm::CreateHidingWindowAnimationObserver(
187        modal_background_->GetNativeView()));
188    modal_background_->GetNativeView()->layer()->SetOpacity(0.0f);
189    modal_background_ = NULL;
190  }
191}
192
193// static
194bool SystemModalContainerLayoutManager::IsModalBackground(
195    aura::Window* window) {
196  int id = window->parent()->id();
197  if (id != internal::kShellWindowId_SystemModalContainer &&
198      id != internal::kShellWindowId_LockSystemModalContainer)
199    return false;
200  SystemModalContainerLayoutManager* layout_manager =
201      static_cast<SystemModalContainerLayoutManager*>(
202          window->parent()->layout_manager());
203  return layout_manager->modal_background_ &&
204      layout_manager->modal_background_->GetNativeWindow() == window;
205}
206
207////////////////////////////////////////////////////////////////////////////////
208// SystemModalContainerLayoutManager, private:
209
210void SystemModalContainerLayoutManager::AddModalWindow(aura::Window* window) {
211  if (modal_windows_.empty()) {
212    aura::Window* capture_window = aura::client::GetCaptureWindow(container_);
213    if (capture_window)
214      capture_window->ReleaseCapture();
215  }
216  modal_windows_.push_back(window);
217  Shell::GetInstance()->CreateModalBackground(window);
218  window->parent()->StackChildAtTop(window);
219}
220
221void SystemModalContainerLayoutManager::RemoveModalWindow(
222    aura::Window* window) {
223  aura::Window::Windows::iterator it =
224      std::find(modal_windows_.begin(), modal_windows_.end(), window);
225  if (it != modal_windows_.end())
226    modal_windows_.erase(it);
227}
228
229}  // namespace internal
230}  // namespace ash
231