| OLD | NEW |
| (Empty) | |
| 1 |
| 2 // Copyright 2013 The Chromium Authors. All rights reserved. |
| 3 // Use of this source code is governed by a BSD-style license that can be |
| 4 // found in the LICENSE file. |
| 5 |
| 6 #include "ash/wm/overview/window_selector_window.h" |
| 7 |
| 8 #include "ash/shell.h" |
| 9 #include "ui/aura/client/aura_constants.h" |
| 10 #include "ui/aura/client/screen_position_client.h" |
| 11 #include "ui/aura/root_window.h" |
| 12 #include "ui/aura/window.h" |
| 13 #include "ui/compositor/layer_animation_observer.h" |
| 14 #include "ui/compositor/scoped_layer_animation_settings.h" |
| 15 #include "ui/gfx/display.h" |
| 16 #include "ui/gfx/interpolated_transform.h" |
| 17 #include "ui/gfx/transform_util.h" |
| 18 #include "ui/views/corewm/shadow_types.h" |
| 19 #include "ui/views/corewm/window_animations.h" |
| 20 #include "ui/views/corewm/window_util.h" |
| 21 #include "ui/views/widget/widget.h" |
| 22 |
| 23 namespace ash { |
| 24 |
| 25 namespace { |
| 26 |
| 27 const int kOverviewWindowTransitionMilliseconds = 100; |
| 28 |
| 29 // Creates a copy of |window| with |recreated_layer| in the |target_root|. |
| 30 views::Widget* CreateCopyOfWindow(aura::RootWindow* target_root, |
| 31 aura::Window* src_window, |
| 32 ui::Layer* recreated_layer) { |
| 33 views::Widget* widget = new views::Widget; |
| 34 views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP); |
| 35 params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; |
| 36 params.parent = src_window->parent(); |
| 37 params.can_activate = false; |
| 38 params.keep_on_top = true; |
| 39 widget->set_focus_on_creation(false); |
| 40 widget->Init(params); |
| 41 widget->SetVisibilityChangedAnimationsEnabled(false); |
| 42 std::string name = src_window->name() + " (Copy)"; |
| 43 widget->GetNativeWindow()->SetName(name); |
| 44 views::corewm::SetShadowType(widget->GetNativeWindow(), |
| 45 views::corewm::SHADOW_TYPE_RECTANGULAR); |
| 46 |
| 47 // Set the bounds in the target root window. |
| 48 gfx::Display target_display = |
| 49 Shell::GetScreen()->GetDisplayNearestWindow(target_root); |
| 50 aura::client::ScreenPositionClient* screen_position_client = |
| 51 aura::client::GetScreenPositionClient(src_window->GetRootWindow()); |
| 52 if (screen_position_client && target_display.is_valid()) { |
| 53 screen_position_client->SetBounds(widget->GetNativeWindow(), |
| 54 src_window->GetBoundsInScreen(), target_display); |
| 55 } else { |
| 56 widget->SetBounds(src_window->GetBoundsInScreen()); |
| 57 } |
| 58 widget->StackAbove(src_window); |
| 59 |
| 60 // Move the |recreated_layer| to the newly created window. |
| 61 recreated_layer->set_delegate(src_window->layer()->delegate()); |
| 62 gfx::Rect layer_bounds = recreated_layer->bounds(); |
| 63 layer_bounds.set_origin(gfx::Point(0, 0)); |
| 64 recreated_layer->SetBounds(layer_bounds); |
| 65 recreated_layer->SetVisible(false); |
| 66 recreated_layer->parent()->Remove(recreated_layer); |
| 67 |
| 68 aura::Window* window = widget->GetNativeWindow(); |
| 69 recreated_layer->SetVisible(true); |
| 70 window->layer()->Add(recreated_layer); |
| 71 window->layer()->StackAtTop(recreated_layer); |
| 72 window->layer()->SetOpacity(1); |
| 73 window->Show(); |
| 74 return widget; |
| 75 } |
| 76 |
| 77 // An observer which closes the widget and deletes the layer after an |
| 78 // animation finishes. |
| 79 class CleanupWidgetAfterAnimationObserver : public ui::LayerAnimationObserver { |
| 80 public: |
| 81 CleanupWidgetAfterAnimationObserver(views::Widget* widget, ui::Layer* layer); |
| 82 |
| 83 virtual void OnLayerAnimationEnded( |
| 84 ui::LayerAnimationSequence* sequence) OVERRIDE; |
| 85 virtual void OnLayerAnimationAborted( |
| 86 ui::LayerAnimationSequence* sequence) OVERRIDE; |
| 87 virtual void OnLayerAnimationScheduled( |
| 88 ui::LayerAnimationSequence* sequence) OVERRIDE; |
| 89 |
| 90 protected: |
| 91 virtual ~CleanupWidgetAfterAnimationObserver(); |
| 92 |
| 93 private: |
| 94 views::Widget* widget_; |
| 95 ui::Layer* layer_; |
| 96 |
| 97 DISALLOW_COPY_AND_ASSIGN(CleanupWidgetAfterAnimationObserver); |
| 98 }; |
| 99 |
| 100 CleanupWidgetAfterAnimationObserver::CleanupWidgetAfterAnimationObserver( |
| 101 views::Widget* widget, |
| 102 ui::Layer* layer) |
| 103 : widget_(widget), |
| 104 layer_(layer) { |
| 105 widget_->GetNativeWindow()->layer()->GetAnimator()->AddObserver(this); |
| 106 } |
| 107 |
| 108 void CleanupWidgetAfterAnimationObserver::OnLayerAnimationEnded( |
| 109 ui::LayerAnimationSequence* sequence) { |
| 110 delete this; |
| 111 } |
| 112 |
| 113 void CleanupWidgetAfterAnimationObserver::OnLayerAnimationAborted( |
| 114 ui::LayerAnimationSequence* sequence) { |
| 115 delete this; |
| 116 } |
| 117 |
| 118 void CleanupWidgetAfterAnimationObserver::OnLayerAnimationScheduled( |
| 119 ui::LayerAnimationSequence* sequence) { |
| 120 } |
| 121 |
| 122 CleanupWidgetAfterAnimationObserver::~CleanupWidgetAfterAnimationObserver() { |
| 123 widget_->GetNativeWindow()->layer()->GetAnimator()->RemoveObserver(this); |
| 124 widget_->Close(); |
| 125 widget_ = NULL; |
| 126 if (layer_) { |
| 127 views::corewm::DeepDeleteLayers(layer_); |
| 128 layer_ = NULL; |
| 129 } |
| 130 } |
| 131 |
| 132 // The animation settings used for window selector animations. |
| 133 class WindowSelectorAnimationSettings |
| 134 : public ui::ScopedLayerAnimationSettings { |
| 135 public: |
| 136 WindowSelectorAnimationSettings(aura::Window* window) : |
| 137 ui::ScopedLayerAnimationSettings(window->layer()->GetAnimator()) { |
| 138 SetPreemptionStrategy( |
| 139 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); |
| 140 SetTransitionDuration(base::TimeDelta::FromMilliseconds( |
| 141 kOverviewWindowTransitionMilliseconds)); |
| 142 } |
| 143 |
| 144 virtual ~WindowSelectorAnimationSettings() { |
| 145 } |
| 146 }; |
| 147 |
| 148 } // namespace |
| 149 |
| 150 WindowSelectorWindow::WindowSelectorWindow(aura::Window* window) |
| 151 : window_(window), |
| 152 window_copy_(NULL), |
| 153 layer_(NULL), |
| 154 minimized_(window->GetProperty(aura::client::kShowStateKey) == |
| 155 ui::SHOW_STATE_MINIMIZED), |
| 156 original_transform_(window->layer()->GetTargetTransform()) { |
| 157 if (minimized_) |
| 158 window_->Show(); |
| 159 } |
| 160 |
| 161 WindowSelectorWindow::~WindowSelectorWindow() { |
| 162 if (window_) { |
| 163 WindowSelectorAnimationSettings animation_settings(window_); |
| 164 gfx::Transform transform; |
| 165 window_->SetTransform(original_transform_); |
| 166 if (minimized_) { |
| 167 // Setting opacity 0 and visible false ensures that the property change |
| 168 // to SHOW_STATE_MINIMIZED will not animate the window from its original |
| 169 // bounds to the minimized position. |
| 170 window_->layer()->SetOpacity(0); |
| 171 window_->layer()->SetVisible(false); |
| 172 window_->SetProperty(aura::client::kShowStateKey, |
| 173 ui::SHOW_STATE_MINIMIZED); |
| 174 } |
| 175 } |
| 176 // If a copy of the window was created, clean it up. |
| 177 if (window_copy_) { |
| 178 if (window_) { |
| 179 // If the initial window wasn't destroyed, the copy needs to be animated |
| 180 // out. CleanupWidgetAfterAnimationObserver will destroy the widget and |
| 181 // layer after the animation is complete. |
| 182 new CleanupWidgetAfterAnimationObserver(window_copy_, layer_); |
| 183 WindowSelectorAnimationSettings animation_settings( |
| 184 window_copy_->GetNativeWindow()); |
| 185 window_copy_->GetNativeWindow()->SetTransform(original_transform_); |
| 186 } else { |
| 187 window_copy_->Close(); |
| 188 if (layer_) |
| 189 views::corewm::DeepDeleteLayers(layer_); |
| 190 } |
| 191 window_copy_ = NULL; |
| 192 layer_ = NULL; |
| 193 } |
| 194 } |
| 195 |
| 196 bool WindowSelectorWindow::Contains(const aura::Window* window) const { |
| 197 if (window_copy_ && window_copy_->GetNativeWindow()->Contains(window)) |
| 198 return true; |
| 199 return window_->Contains(window); |
| 200 } |
| 201 |
| 202 void WindowSelectorWindow::RestoreWindowOnExit() { |
| 203 minimized_ = false; |
| 204 original_transform_ = gfx::Transform(); |
| 205 } |
| 206 |
| 207 void WindowSelectorWindow::OnWindowDestroyed() { |
| 208 window_ = NULL; |
| 209 } |
| 210 |
| 211 void WindowSelectorWindow::TransformToFitBounds( |
| 212 aura::RootWindow* root_window, |
| 213 const gfx::Rect& target_bounds) { |
| 214 fit_bounds_ = target_bounds; |
| 215 const gfx::Rect bounds = window_->GetBoundsInScreen(); |
| 216 float scale = std::min(1.0f, |
| 217 std::min(static_cast<float>(target_bounds.width()) / bounds.width(), |
| 218 static_cast<float>(target_bounds.height()) / bounds.height())); |
| 219 gfx::Transform transform; |
| 220 gfx::Vector2d offset( |
| 221 0.5 * (target_bounds.width() - scale * bounds.width()), |
| 222 0.5 * (target_bounds.height() - scale * bounds.height())); |
| 223 transform.Translate(target_bounds.x() - bounds.x() + offset.x(), |
| 224 target_bounds.y() - bounds.y() + offset.y()); |
| 225 transform.Scale(scale, scale); |
| 226 if (root_window != window_->GetRootWindow()) { |
| 227 if (!window_copy_) { |
| 228 DCHECK(!layer_); |
| 229 layer_ = views::corewm::RecreateWindowLayers(window_, true); |
| 230 window_copy_ = CreateCopyOfWindow(root_window, window_, layer_); |
| 231 } |
| 232 WindowSelectorAnimationSettings animation_settings( |
| 233 window_copy_->GetNativeWindow()); |
| 234 window_copy_->GetNativeWindow()->SetTransform(transform); |
| 235 } |
| 236 WindowSelectorAnimationSettings animation_settings(window_); |
| 237 window_->SetTransform(transform); |
| 238 } |
| 239 |
| 240 } // namespace ash |
| OLD | NEW |