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