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