Home | History | Annotate | Download | only in wm
      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