workspace_backdrop_delegate.cc revision a1401311d1ab56c4ed0a474bd38c108f75cb0cd9
1// Copyright 2014 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/maximize_mode/workspace_backdrop_delegate.h"
6
7#include "ash/wm/window_animations.h"
8#include "ash/wm/window_util.h"
9#include "base/auto_reset.h"
10#include "ui/aura/window.h"
11#include "ui/compositor/layer.h"
12#include "ui/compositor/scoped_layer_animation_settings.h"
13#include "ui/views/background.h"
14#include "ui/views/widget/widget.h"
15#include "ui/wm/core/window_util.h"
16
17namespace ash {
18
19namespace internal {
20
21namespace {
22
23// The opacity of the backdrop.
24const float kBackdropOpacity = 0.5f;
25
26}  // namespace
27
28WorkspaceBackdropDelegate::WorkspaceBackdropDelegate(aura::Window* container)
29    : background_(NULL),
30      container_(container),
31      in_restacking_(false) {
32  background_ = new views::Widget;
33  views::Widget::InitParams params(
34      views::Widget::InitParams::TYPE_WINDOW_FRAMELESS);
35  params.parent = container_;
36  params.bounds = container_->bounds();
37  params.layer_type = aura::WINDOW_LAYER_SOLID_COLOR;
38  // To disallow the MRU list from picking this window up it should not be
39  // activateable.
40  params.can_activate = false;
41  background_->Init(params);
42  background_->GetNativeView()->SetName("WorkspaceBackdropDelegate");
43  background_->GetNativeView()->layer()->SetColor(SK_ColorBLACK);
44  Show();
45  RestackBackdrop();
46  container_->AddObserver(this);
47}
48
49WorkspaceBackdropDelegate::~WorkspaceBackdropDelegate() {
50  container_->RemoveObserver(this);
51  ui::ScopedLayerAnimationSettings settings(
52      background_->GetNativeView()->layer()->GetAnimator());
53  background_->Close();
54  settings.AddObserver(::wm::CreateHidingWindowAnimationObserver(
55      background_->GetNativeView()));
56  background_->GetNativeView()->layer()->SetOpacity(0.0f);
57}
58
59void WorkspaceBackdropDelegate::OnWindowBoundsChanged(
60    aura::Window* window,
61    const gfx::Rect& old_bounds,
62    const gfx::Rect& new_bounds) {
63  // The container size has changed and the layer needs to be adapt to it.
64  AdjustToContainerBounds();
65}
66
67void WorkspaceBackdropDelegate::OnWindowAddedToLayout(aura::Window* child) {
68  RestackBackdrop();
69}
70
71void WorkspaceBackdropDelegate::OnWindowRemovedFromLayout(aura::Window* child) {
72  RestackBackdrop();
73}
74
75void WorkspaceBackdropDelegate::OnChildWindowVisibilityChanged(
76    aura::Window* child,
77    bool visible) {
78  RestackBackdrop();
79}
80
81void WorkspaceBackdropDelegate::OnWindowStackingChanged(aura::Window* window) {
82  RestackBackdrop();
83}
84
85void WorkspaceBackdropDelegate::OnPostWindowStateTypeChange(
86    wm::WindowState* window_state,
87    wm::WindowStateType old_type) {
88  RestackBackdrop();
89}
90
91void WorkspaceBackdropDelegate::RestackBackdrop() {
92  // Avoid recursive calls.
93  if (in_restacking_)
94    return;
95
96  aura::Window* window = GetCurrentTopWindow();
97  if (!window) {
98    // Hide backdrop since no suitable window was found.
99    background_->Hide();
100    return;
101  }
102  if (window == background_->GetNativeWindow() &&
103      background_->IsVisible()) {
104    return;
105  }
106  // We are changing the order of windows which will cause recursion.
107  base::AutoReset<bool> lock(&in_restacking_, true);
108  if (!background_->IsVisible())
109    Show();
110  // Since the backdrop needs to be immediately behind the window and the
111  // stacking functions only guarantee a "it's above or below", we need
112  // to re-arrange the two windows twice.
113  container_->StackChildAbove(background_->GetNativeView(), window);
114  container_->StackChildAbove(window, background_->GetNativeView());
115}
116
117aura::Window* WorkspaceBackdropDelegate::GetCurrentTopWindow() {
118  const aura::Window::Windows& windows = container_->children();
119  for (aura::Window::Windows::const_reverse_iterator window_iter =
120           windows.rbegin();
121       window_iter != windows.rend(); ++window_iter) {
122    aura::Window* window = *window_iter;
123    if (window->TargetVisibility() &&
124        window->type() == ui::wm::WINDOW_TYPE_NORMAL &&
125        ash::wm::CanActivateWindow(window))
126      return window;
127  }
128  return NULL;
129}
130
131void WorkspaceBackdropDelegate::AdjustToContainerBounds() {
132  // Cover the entire container window.
133  gfx::Rect target_rect(gfx::Point(0, 0), container_->bounds().size());
134  if (target_rect != background_->GetNativeWindow()->bounds()) {
135    // This needs to be instant.
136    ui::ScopedLayerAnimationSettings settings(
137        background_->GetNativeView()->layer()->GetAnimator());
138    settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds(0));
139    background_->GetNativeWindow()->SetBounds(target_rect);
140    if (!background_->IsVisible())
141      background_->GetNativeView()->layer()->SetOpacity(kBackdropOpacity);
142  }
143}
144
145void WorkspaceBackdropDelegate::Show() {
146  background_->GetNativeView()->layer()->SetOpacity(0.0f);
147  background_->Show();
148  ui::ScopedLayerAnimationSettings settings(
149      background_->GetNativeView()->layer()->GetAnimator());
150  background_->GetNativeView()->layer()->SetOpacity(kBackdropOpacity);
151}
152
153}  // namespace internal
154}  // namespace ash
155