| 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/window_selector.h" | 5 #include "ash/wm/overview/window_selector.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "ash/screen_ash.h" | 9 #include "ash/screen_ash.h" |
| 10 #include "ash/shell.h" | 10 #include "ash/shell.h" |
| 11 #include "ash/shell_window_ids.h" | 11 #include "ash/shell_window_ids.h" |
| 12 #include "ash/wm/window_selector_delegate.h" | 12 #include "ash/wm/overview/window_selector_delegate.h" |
| 13 #include "ash/wm/overview/window_selector_window.h" |
| 13 #include "ash/wm/window_util.h" | 14 #include "ash/wm/window_util.h" |
| 14 #include "base/memory/scoped_ptr.h" | 15 #include "base/memory/scoped_ptr.h" |
| 15 #include "third_party/skia/include/core/SkColor.h" | 16 #include "third_party/skia/include/core/SkColor.h" |
| 16 #include "ui/aura/client/aura_constants.h" | |
| 17 #include "ui/aura/client/screen_position_client.h" | |
| 18 #include "ui/aura/root_window.h" | 17 #include "ui/aura/root_window.h" |
| 19 #include "ui/aura/window.h" | 18 #include "ui/aura/window.h" |
| 20 #include "ui/base/events/event.h" | 19 #include "ui/base/events/event.h" |
| 21 #include "ui/compositor/layer_animation_observer.h" | |
| 22 #include "ui/compositor/scoped_layer_animation_settings.h" | 20 #include "ui/compositor/scoped_layer_animation_settings.h" |
| 23 #include "ui/gfx/display.h" | |
| 24 #include "ui/gfx/interpolated_transform.h" | |
| 25 #include "ui/gfx/transform_util.h" | |
| 26 #include "ui/views/corewm/shadow_types.h" | |
| 27 #include "ui/views/corewm/window_animations.h" | |
| 28 #include "ui/views/corewm/window_util.h" | |
| 29 #include "ui/views/widget/widget.h" | 21 #include "ui/views/widget/widget.h" |
| 30 | 22 |
| 31 namespace ash { | 23 namespace ash { |
| 32 | 24 |
| 33 namespace { | 25 namespace { |
| 34 | 26 |
| 35 const float kCardAspectRatio = 4.0f / 3.0f; | 27 const float kCardAspectRatio = 4.0f / 3.0f; |
| 36 const int kWindowMargin = 30; | 28 const int kWindowMargin = 30; |
| 37 const int kMinCardsMajor = 3; | 29 const int kMinCardsMajor = 3; |
| 38 const int kOverviewTransitionMilliseconds = 100; | 30 const int kOverviewSelectorTransitionMilliseconds = 100; |
| 39 const SkColor kWindowSelectorSelectionColor = SK_ColorBLACK; | 31 const SkColor kWindowSelectorSelectionColor = SK_ColorBLACK; |
| 40 const float kWindowSelectorSelectionOpacity = 0.5f; | 32 const float kWindowSelectorSelectionOpacity = 0.5f; |
| 41 const int kWindowSelectorSelectionPadding = 15; | 33 const int kWindowSelectorSelectionPadding = 15; |
| 42 | 34 |
| 43 // Creates a copy of |window| with |recreated_layer| in the |target_root|. | |
| 44 views::Widget* CreateCopyOfWindow(aura::RootWindow* target_root, | |
| 45 aura::Window* src_window, | |
| 46 ui::Layer* recreated_layer) { | |
| 47 views::Widget* widget = new views::Widget; | |
| 48 views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP); | |
| 49 params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; | |
| 50 params.parent = src_window->parent(); | |
| 51 params.can_activate = false; | |
| 52 params.keep_on_top = true; | |
| 53 widget->set_focus_on_creation(false); | |
| 54 widget->Init(params); | |
| 55 widget->SetVisibilityChangedAnimationsEnabled(false); | |
| 56 std::string name = src_window->name() + " (Copy)"; | |
| 57 widget->GetNativeWindow()->SetName(name); | |
| 58 views::corewm::SetShadowType(widget->GetNativeWindow(), | |
| 59 views::corewm::SHADOW_TYPE_RECTANGULAR); | |
| 60 | |
| 61 // Set the bounds in the target root window. | |
| 62 gfx::Display target_display = | |
| 63 Shell::GetScreen()->GetDisplayNearestWindow(target_root); | |
| 64 aura::client::ScreenPositionClient* screen_position_client = | |
| 65 aura::client::GetScreenPositionClient(src_window->GetRootWindow()); | |
| 66 if (screen_position_client && target_display.is_valid()) { | |
| 67 screen_position_client->SetBounds(widget->GetNativeWindow(), | |
| 68 src_window->GetBoundsInScreen(), target_display); | |
| 69 } else { | |
| 70 widget->SetBounds(src_window->GetBoundsInScreen()); | |
| 71 } | |
| 72 widget->StackAbove(src_window); | |
| 73 | |
| 74 // Move the |recreated_layer| to the newly created window. | |
| 75 recreated_layer->set_delegate(src_window->layer()->delegate()); | |
| 76 gfx::Rect layer_bounds = recreated_layer->bounds(); | |
| 77 layer_bounds.set_origin(gfx::Point(0, 0)); | |
| 78 recreated_layer->SetBounds(layer_bounds); | |
| 79 recreated_layer->SetVisible(false); | |
| 80 recreated_layer->parent()->Remove(recreated_layer); | |
| 81 | |
| 82 aura::Window* window = widget->GetNativeWindow(); | |
| 83 recreated_layer->SetVisible(true); | |
| 84 window->layer()->Add(recreated_layer); | |
| 85 window->layer()->StackAtTop(recreated_layer); | |
| 86 window->layer()->SetOpacity(1); | |
| 87 window->Show(); | |
| 88 return widget; | |
| 89 } | |
| 90 | |
| 91 // An observer which closes the widget and deletes the layer after an | |
| 92 // animation finishes. | |
| 93 class CleanupWidgetAfterAnimationObserver : public ui::LayerAnimationObserver { | |
| 94 public: | |
| 95 CleanupWidgetAfterAnimationObserver(views::Widget* widget, ui::Layer* layer); | |
| 96 | |
| 97 virtual void OnLayerAnimationEnded( | |
| 98 ui::LayerAnimationSequence* sequence) OVERRIDE; | |
| 99 virtual void OnLayerAnimationAborted( | |
| 100 ui::LayerAnimationSequence* sequence) OVERRIDE; | |
| 101 virtual void OnLayerAnimationScheduled( | |
| 102 ui::LayerAnimationSequence* sequence) OVERRIDE; | |
| 103 | |
| 104 protected: | |
| 105 virtual ~CleanupWidgetAfterAnimationObserver(); | |
| 106 | |
| 107 private: | |
| 108 views::Widget* widget_; | |
| 109 ui::Layer* layer_; | |
| 110 | |
| 111 DISALLOW_COPY_AND_ASSIGN(CleanupWidgetAfterAnimationObserver); | |
| 112 }; | |
| 113 | |
| 114 CleanupWidgetAfterAnimationObserver::CleanupWidgetAfterAnimationObserver( | |
| 115 views::Widget* widget, | |
| 116 ui::Layer* layer) | |
| 117 : widget_(widget), | |
| 118 layer_(layer) { | |
| 119 widget_->GetNativeWindow()->layer()->GetAnimator()->AddObserver(this); | |
| 120 } | |
| 121 | |
| 122 void CleanupWidgetAfterAnimationObserver::OnLayerAnimationEnded( | |
| 123 ui::LayerAnimationSequence* sequence) { | |
| 124 delete this; | |
| 125 } | |
| 126 | |
| 127 void CleanupWidgetAfterAnimationObserver::OnLayerAnimationAborted( | |
| 128 ui::LayerAnimationSequence* sequence) { | |
| 129 delete this; | |
| 130 } | |
| 131 | |
| 132 void CleanupWidgetAfterAnimationObserver::OnLayerAnimationScheduled( | |
| 133 ui::LayerAnimationSequence* sequence) { | |
| 134 } | |
| 135 | |
| 136 CleanupWidgetAfterAnimationObserver::~CleanupWidgetAfterAnimationObserver() { | |
| 137 widget_->GetNativeWindow()->layer()->GetAnimator()->RemoveObserver(this); | |
| 138 widget_->Close(); | |
| 139 widget_ = NULL; | |
| 140 if (layer_) { | |
| 141 views::corewm::DeepDeleteLayers(layer_); | |
| 142 layer_ = NULL; | |
| 143 } | |
| 144 } | |
| 145 | |
| 146 // The animation settings used for window selector animations. | |
| 147 class WindowSelectorAnimationSettings | |
| 148 : public ui::ScopedLayerAnimationSettings { | |
| 149 public: | |
| 150 WindowSelectorAnimationSettings(aura::Window* window) : | |
| 151 ui::ScopedLayerAnimationSettings(window->layer()->GetAnimator()) { | |
| 152 SetPreemptionStrategy( | |
| 153 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); | |
| 154 SetTransitionDuration( | |
| 155 base::TimeDelta::FromMilliseconds(kOverviewTransitionMilliseconds)); | |
| 156 } | |
| 157 | |
| 158 virtual ~WindowSelectorAnimationSettings() { | |
| 159 } | |
| 160 }; | |
| 161 | |
| 162 } // namespace | |
| 163 | |
| 164 // TODO(flackr): Split up into separate file under subdirectory in ash/wm. | |
| 165 class WindowSelectorWindow { | |
| 166 public: | |
| 167 explicit WindowSelectorWindow(aura::Window* window); | |
| 168 virtual ~WindowSelectorWindow(); | |
| 169 | |
| 170 aura::Window* window() { return window_; } | |
| 171 const aura::Window* window() const { return window_; } | |
| 172 | |
| 173 // Returns true if this window selector window contains the |target|. This is | |
| 174 // used to determine if an event targetted this window. | |
| 175 bool Contains(const aura::Window* target) const; | |
| 176 | |
| 177 // Restores this window on exit rather than returning it to a minimized state | |
| 178 // if it was minimized on entering overview mode. | |
| 179 void RestoreWindowOnExit(); | |
| 180 | |
| 181 // Informs the WindowSelectorWindow that the window being watched was | |
| 182 // destroyed. This resets the internal window pointer to avoid calling | |
| 183 // anything on the window at destruction time. | |
| 184 void OnWindowDestroyed(); | |
| 185 | |
| 186 // Applies a transform to the window to fit within |target_bounds| while | |
| 187 // maintaining its aspect ratio. | |
| 188 void TransformToFitBounds(aura::RootWindow* root_window, | |
| 189 const gfx::Rect& target_bounds); | |
| 190 | |
| 191 gfx::Rect bounds() { return fit_bounds_; } | |
| 192 | |
| 193 private: | |
| 194 // A weak pointer to the real window in the overview. | |
| 195 aura::Window* window_; | |
| 196 | |
| 197 // A copy of the window used to transition the window to another root. | |
| 198 views::Widget* window_copy_; | |
| 199 | |
| 200 // A weak pointer to a deep copy of the window's layers. | |
| 201 ui::Layer* layer_; | |
| 202 | |
| 203 // If true, the window was minimized and should be restored if the window | |
| 204 // was not selected. | |
| 205 bool minimized_; | |
| 206 | |
| 207 // The original transform of the window before entering overview mode. | |
| 208 gfx::Transform original_transform_; | |
| 209 | |
| 210 // The bounds this window is fit to. | |
| 211 gfx::Rect fit_bounds_; | |
| 212 | |
| 213 DISALLOW_COPY_AND_ASSIGN(WindowSelectorWindow); | |
| 214 }; | |
| 215 | |
| 216 WindowSelectorWindow::WindowSelectorWindow(aura::Window* window) | |
| 217 : window_(window), | |
| 218 window_copy_(NULL), | |
| 219 layer_(NULL), | |
| 220 minimized_(window->GetProperty(aura::client::kShowStateKey) == | |
| 221 ui::SHOW_STATE_MINIMIZED), | |
| 222 original_transform_(window->layer()->GetTargetTransform()) { | |
| 223 if (minimized_) | |
| 224 window_->Show(); | |
| 225 } | |
| 226 | |
| 227 WindowSelectorWindow::~WindowSelectorWindow() { | |
| 228 if (window_) { | |
| 229 WindowSelectorAnimationSettings animation_settings(window_); | |
| 230 gfx::Transform transform; | |
| 231 window_->SetTransform(original_transform_); | |
| 232 if (minimized_) { | |
| 233 // Setting opacity 0 and visible false ensures that the property change | |
| 234 // to SHOW_STATE_MINIMIZED will not animate the window from its original | |
| 235 // bounds to the minimized position. | |
| 236 window_->layer()->SetOpacity(0); | |
| 237 window_->layer()->SetVisible(false); | |
| 238 window_->SetProperty(aura::client::kShowStateKey, | |
| 239 ui::SHOW_STATE_MINIMIZED); | |
| 240 } | |
| 241 } | |
| 242 // If a copy of the window was created, clean it up. | |
| 243 if (window_copy_) { | |
| 244 if (window_) { | |
| 245 // If the initial window wasn't destroyed, the copy needs to be animated | |
| 246 // out. CleanupWidgetAfterAnimationObserver will destroy the widget and | |
| 247 // layer after the animation is complete. | |
| 248 new CleanupWidgetAfterAnimationObserver(window_copy_, layer_); | |
| 249 WindowSelectorAnimationSettings animation_settings( | |
| 250 window_copy_->GetNativeWindow()); | |
| 251 window_copy_->GetNativeWindow()->SetTransform(original_transform_); | |
| 252 } else { | |
| 253 window_copy_->Close(); | |
| 254 if (layer_) | |
| 255 views::corewm::DeepDeleteLayers(layer_); | |
| 256 } | |
| 257 window_copy_ = NULL; | |
| 258 layer_ = NULL; | |
| 259 } | |
| 260 } | |
| 261 | |
| 262 bool WindowSelectorWindow::Contains(const aura::Window* window) const { | |
| 263 if (window_copy_ && window_copy_->GetNativeWindow()->Contains(window)) | |
| 264 return true; | |
| 265 return window_->Contains(window); | |
| 266 } | |
| 267 | |
| 268 void WindowSelectorWindow::RestoreWindowOnExit() { | |
| 269 minimized_ = false; | |
| 270 original_transform_ = gfx::Transform(); | |
| 271 } | |
| 272 | |
| 273 void WindowSelectorWindow::OnWindowDestroyed() { | |
| 274 window_ = NULL; | |
| 275 } | |
| 276 | |
| 277 void WindowSelectorWindow::TransformToFitBounds( | |
| 278 aura::RootWindow* root_window, | |
| 279 const gfx::Rect& target_bounds) { | |
| 280 fit_bounds_ = target_bounds; | |
| 281 const gfx::Rect bounds = window_->GetBoundsInScreen(); | |
| 282 float scale = std::min(1.0f, | |
| 283 std::min(static_cast<float>(target_bounds.width()) / bounds.width(), | |
| 284 static_cast<float>(target_bounds.height()) / bounds.height())); | |
| 285 gfx::Transform transform; | |
| 286 gfx::Vector2d offset( | |
| 287 0.5 * (target_bounds.width() - scale * bounds.width()), | |
| 288 0.5 * (target_bounds.height() - scale * bounds.height())); | |
| 289 transform.Translate(target_bounds.x() - bounds.x() + offset.x(), | |
| 290 target_bounds.y() - bounds.y() + offset.y()); | |
| 291 transform.Scale(scale, scale); | |
| 292 if (root_window != window_->GetRootWindow()) { | |
| 293 if (!window_copy_) { | |
| 294 DCHECK(!layer_); | |
| 295 layer_ = views::corewm::RecreateWindowLayers(window_, true); | |
| 296 window_copy_ = CreateCopyOfWindow(root_window, window_, layer_); | |
| 297 } | |
| 298 WindowSelectorAnimationSettings animation_settings( | |
| 299 window_copy_->GetNativeWindow()); | |
| 300 window_copy_->GetNativeWindow()->SetTransform(transform); | |
| 301 } | |
| 302 WindowSelectorAnimationSettings animation_settings(window_); | |
| 303 window_->SetTransform(transform); | |
| 304 } | |
| 305 | |
| 306 // A comparator for locating a given target window. | 35 // A comparator for locating a given target window. |
| 307 struct WindowSelectorWindowComparator | 36 struct WindowSelectorWindowComparator |
| 308 : public std::unary_function<WindowSelectorWindow*, bool> { | 37 : public std::unary_function<WindowSelectorWindow*, bool> { |
| 309 explicit WindowSelectorWindowComparator(const aura::Window* target_window) | 38 explicit WindowSelectorWindowComparator(const aura::Window* target_window) |
| 310 : target(target_window) { | 39 : target(target_window) { |
| 311 } | 40 } |
| 312 | 41 |
| 313 bool operator()(const WindowSelectorWindow* window) const { | 42 bool operator()(const WindowSelectorWindow* window) const { |
| 314 return target == window->window(); | 43 return target == window->window(); |
| 315 } | 44 } |
| 316 | 45 |
| 317 const aura::Window* target; | 46 const aura::Window* target; |
| 318 }; | 47 }; |
| 319 | 48 |
| 49 } // namespace |
| 50 |
| 320 WindowSelector::WindowSelector(const WindowList& windows, | 51 WindowSelector::WindowSelector(const WindowList& windows, |
| 321 WindowSelector::Mode mode, | 52 WindowSelector::Mode mode, |
| 322 WindowSelectorDelegate* delegate) | 53 WindowSelectorDelegate* delegate) |
| 323 : mode_(mode), | 54 : mode_(mode), |
| 324 delegate_(delegate), | 55 delegate_(delegate), |
| 325 selected_window_(0), | 56 selected_window_(0), |
| 326 selection_root_(NULL) { | 57 selection_root_(NULL) { |
| 327 DCHECK(delegate_); | 58 DCHECK(delegate_); |
| 328 for (size_t i = 0; i < windows.size(); ++i) { | 59 for (size_t i = 0; i < windows.size(); ++i) { |
| 329 windows[i]->AddObserver(this); | 60 windows[i]->AddObserver(this); |
| (...skipping 202 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 532 kWindowSelectorSelectionOpacity); | 263 kWindowSelectorSelectionOpacity); |
| 533 } | 264 } |
| 534 | 265 |
| 535 void WindowSelector::UpdateSelectionLocation(bool animate) { | 266 void WindowSelector::UpdateSelectionLocation(bool animate) { |
| 536 if (!selection_widget_) | 267 if (!selection_widget_) |
| 537 return; | 268 return; |
| 538 gfx::Rect target_bounds = windows_[selected_window_]->bounds(); | 269 gfx::Rect target_bounds = windows_[selected_window_]->bounds(); |
| 539 target_bounds.Inset(-kWindowSelectorSelectionPadding, | 270 target_bounds.Inset(-kWindowSelectorSelectionPadding, |
| 540 -kWindowSelectorSelectionPadding); | 271 -kWindowSelectorSelectionPadding); |
| 541 if (animate) { | 272 if (animate) { |
| 542 WindowSelectorAnimationSettings animation_settings( | 273 ui::ScopedLayerAnimationSettings animation_settings( |
| 543 selection_widget_->GetNativeWindow()); | 274 selection_widget_->GetNativeWindow()->layer()->GetAnimator()); |
| 275 animation_settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds( |
| 276 kOverviewSelectorTransitionMilliseconds)); |
| 277 animation_settings.SetPreemptionStrategy( |
| 278 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); |
| 544 selection_widget_->SetBounds(target_bounds); | 279 selection_widget_->SetBounds(target_bounds); |
| 545 } else { | 280 } else { |
| 546 selection_widget_->SetBounds(target_bounds); | 281 selection_widget_->SetBounds(target_bounds); |
| 547 } | 282 } |
| 548 } | 283 } |
| 549 | 284 |
| 550 } // namespace ash | 285 } // namespace ash |
| OLD | NEW |