| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/workspace/phantom_window_controller.h" | 5 #include "ash/wm/workspace/phantom_window_controller.h" |
| 6 | 6 |
| 7 #include "ash/ash_switches.h" |
| 7 #include "ash/shell.h" | 8 #include "ash/shell.h" |
| 8 #include "ash/shell_window_ids.h" | 9 #include "ash/shell_window_ids.h" |
| 9 #include "ash/wm/coordinate_conversion.h" | 10 #include "ash/wm/coordinate_conversion.h" |
| 11 #include "grit/ash_resources.h" |
| 10 #include "third_party/skia/include/core/SkCanvas.h" | 12 #include "third_party/skia/include/core/SkCanvas.h" |
| 11 #include "ui/aura/root_window.h" | 13 #include "ui/aura/root_window.h" |
| 12 #include "ui/aura/window.h" | 14 #include "ui/aura/window.h" |
| 13 #include "ui/compositor/layer.h" | 15 #include "ui/compositor/layer.h" |
| 14 #include "ui/compositor/scoped_layer_animation_settings.h" | 16 #include "ui/compositor/scoped_layer_animation_settings.h" |
| 15 #include "ui/gfx/animation/slide_animation.h" | |
| 16 #include "ui/gfx/canvas.h" | 17 #include "ui/gfx/canvas.h" |
| 17 #include "ui/gfx/skia_util.h" | 18 #include "ui/gfx/skia_util.h" |
| 18 #include "ui/views/background.h" | 19 #include "ui/views/background.h" |
| 19 #include "ui/views/painter.h" | 20 #include "ui/views/painter.h" |
| 20 #include "ui/views/view.h" | 21 #include "ui/views/view.h" |
| 21 #include "ui/views/widget/widget.h" | 22 #include "ui/views/widget/widget.h" |
| 22 | 23 |
| 23 namespace ash { | 24 namespace ash { |
| 24 namespace internal { | 25 namespace internal { |
| 25 | 26 |
| 27 namespace { |
| 28 |
| 29 // The duration of the bounds change animation. |
| 30 const int kBoundsChangeAnimationDurationMs = 200; |
| 31 |
| 32 // The duration of the fade in animation to show the phantom window. |
| 33 const int kShowAnimationDurationMs = 200; |
| 34 |
| 35 // The duration of the fade out animation to hide the phantom window. |
| 36 const int kHideAnimationDurationMs = 100; |
| 37 |
| 38 // The amount of pixels that the shadow should extend past the window bounds |
| 39 // when using the alternate caption button style. |
| 40 const int kShadowThickness = 52; |
| 41 |
| 42 // Converts the bounds of a phantom window without a shadow to those of a |
| 43 // phantom window with a shadow. |
| 44 gfx::Rect GetBoundsWithShadow(const gfx::Rect& bounds) { |
| 45 gfx::Rect bounds_with_shadow(bounds); |
| 46 // Phantom windows have a shadow solely when using the alternate caption |
| 47 // button style. |
| 48 if (switches::UseAlternateFrameCaptionButtonStyle()) |
| 49 bounds_with_shadow.Inset(-kShadowThickness, -kShadowThickness); |
| 50 return bounds_with_shadow; |
| 51 } |
| 52 |
| 53 // Starts an animation of |widget| to |new_bounds|. No-op if |widget| is NULL. |
| 54 void AnimateToBounds(views::Widget* widget, const gfx::Rect& new_bounds) { |
| 55 if (!widget) |
| 56 return; |
| 57 |
| 58 aura::Window* window = widget->GetNativeWindow(); |
| 59 ui::ScopedLayerAnimationSettings scoped_setter( |
| 60 window->layer()->GetAnimator()); |
| 61 scoped_setter.SetTweenType(gfx::Tween::EASE_IN); |
| 62 scoped_setter.SetPreemptionStrategy( |
| 63 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); |
| 64 scoped_setter.SetTransitionDuration( |
| 65 base::TimeDelta::FromMilliseconds(kBoundsChangeAnimationDurationMs)); |
| 66 window->SetBounds(GetBoundsWithShadow(new_bounds)); |
| 67 } |
| 68 |
| 69 // Starts a fade in or fade out animation of |widget|. No-op if |widget| is |
| 70 // NULL. |
| 71 void AnimateToVisibility(views::Widget* widget, bool new_visibility) { |
| 72 if (!widget) |
| 73 return; |
| 74 |
| 75 if (new_visibility) |
| 76 widget->Show(); |
| 77 |
| 78 int animation_duration_ms = new_visibility ? |
| 79 kShowAnimationDurationMs : kHideAnimationDurationMs; |
| 80 |
| 81 ui::Layer* layer = widget->GetNativeWindow()->layer(); |
| 82 ui::ScopedLayerAnimationSettings scoped_setter(layer->GetAnimator()); |
| 83 scoped_setter.SetPreemptionStrategy( |
| 84 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); |
| 85 scoped_setter.SetTransitionDuration(base::TimeDelta::FromMilliseconds( |
| 86 animation_duration_ms)); |
| 87 layer->SetOpacity(new_visibility ? 1.0f : 0.0f); |
| 88 if (!new_visibility) |
| 89 widget->Hide(); |
| 90 } |
| 91 |
| 26 // EdgePainter ---------------------------------------------------------------- | 92 // EdgePainter ---------------------------------------------------------------- |
| 27 | 93 |
| 28 namespace { | |
| 29 | |
| 30 // Paints the background of the phantom window for window snapping. | 94 // Paints the background of the phantom window for window snapping. |
| 31 class EdgePainter : public views::Painter { | 95 class EdgePainter : public views::Painter { |
| 32 public: | 96 public: |
| 33 EdgePainter(); | 97 EdgePainter(); |
| 34 virtual ~EdgePainter(); | 98 virtual ~EdgePainter(); |
| 35 | 99 |
| 36 // views::Painter: | 100 // views::Painter: |
| 37 virtual gfx::Size GetMinimumSize() const OVERRIDE; | 101 virtual gfx::Size GetMinimumSize() const OVERRIDE; |
| 38 virtual void Paint(gfx::Canvas* canvas, const gfx::Size& size) OVERRIDE; | 102 virtual void Paint(gfx::Canvas* canvas, const gfx::Size& size) OVERRIDE; |
| 39 | 103 |
| 40 private: | 104 private: |
| 41 DISALLOW_COPY_AND_ASSIGN(EdgePainter); | 105 DISALLOW_COPY_AND_ASSIGN(EdgePainter); |
| 42 }; | 106 }; |
| 43 | 107 |
| 44 } // namespace | |
| 45 | |
| 46 | |
| 47 EdgePainter::EdgePainter() { | 108 EdgePainter::EdgePainter() { |
| 48 } | 109 } |
| 49 | 110 |
| 50 EdgePainter::~EdgePainter() { | 111 EdgePainter::~EdgePainter() { |
| 51 } | 112 } |
| 52 | 113 |
| 53 gfx::Size EdgePainter::GetMinimumSize() const { | 114 gfx::Size EdgePainter::GetMinimumSize() const { |
| 54 return gfx::Size(); | 115 return gfx::Size(); |
| 55 } | 116 } |
| 56 | 117 |
| (...skipping 22 matching lines...) Expand all Loading... |
| 79 return; | 140 return; |
| 80 | 141 |
| 81 paint.setColor(SkColorSetARGB(200, 255, 255, 255)); | 142 paint.setColor(SkColorSetARGB(200, 255, 255, 255)); |
| 82 paint.setStyle(SkPaint::kStroke_Style); | 143 paint.setStyle(SkPaint::kStroke_Style); |
| 83 paint.setStrokeWidth(SkIntToScalar(2)); | 144 paint.setStrokeWidth(SkIntToScalar(2)); |
| 84 canvas->sk_canvas()->drawRoundRect( | 145 canvas->sk_canvas()->drawRoundRect( |
| 85 gfx::RectToSkRect(gfx::Rect(x, y, w, h)), SkIntToScalar(kRoundRectSize), | 146 gfx::RectToSkRect(gfx::Rect(x, y, w, h)), SkIntToScalar(kRoundRectSize), |
| 86 SkIntToScalar(kRoundRectSize), paint); | 147 SkIntToScalar(kRoundRectSize), paint); |
| 87 } | 148 } |
| 88 | 149 |
| 150 } // namespace |
| 89 | 151 |
| 90 // PhantomWindowController ---------------------------------------------------- | 152 // PhantomWindowController ---------------------------------------------------- |
| 91 | 153 |
| 92 PhantomWindowController::PhantomWindowController(aura::Window* window) | 154 PhantomWindowController::PhantomWindowController(aura::Window* window) |
| 93 : window_(window), | 155 : window_(window), |
| 94 phantom_below_window_(NULL), | 156 phantom_below_window_(NULL), |
| 95 phantom_widget_(NULL), | 157 target_visibility_(false) { |
| 96 phantom_widget_start_(NULL) { | |
| 97 } | 158 } |
| 98 | 159 |
| 99 PhantomWindowController::~PhantomWindowController() { | 160 PhantomWindowController::~PhantomWindowController() { |
| 100 Hide(); | |
| 101 } | 161 } |
| 102 | 162 |
| 103 void PhantomWindowController::Show(const gfx::Rect& bounds_in_screen) { | 163 void PhantomWindowController::Show(const gfx::Rect& bounds_in_screen) { |
| 104 if (bounds_in_screen == bounds_in_screen_) | 164 StartFade(true); |
| 165 |
| 166 if (bounds_in_screen == target_bounds_in_screen_) |
| 105 return; | 167 return; |
| 106 bounds_in_screen_ = bounds_in_screen; | 168 |
| 107 aura::Window* target_root = wm::GetRootWindowMatching(bounds_in_screen); | 169 target_bounds_in_screen_ = bounds_in_screen; |
| 108 // Show the phantom at the current bounds of the window. We'll animate to the | 170 gfx::Rect start_bounds; |
| 109 // target bounds. If phantom exists, update the start bounds. | |
| 110 if (!phantom_widget_) | 171 if (!phantom_widget_) |
| 111 start_bounds_ = window_->GetBoundsInScreen(); | 172 start_bounds = window_->GetBoundsInScreen(); |
| 112 else | 173 else |
| 113 start_bounds_ = phantom_widget_->GetWindowBoundsInScreen(); | 174 start_bounds = phantom_widget_->GetWindowBoundsInScreen(); |
| 114 if (phantom_widget_ && | 175 |
| 176 aura::Window* target_root = |
| 177 wm::GetRootWindowMatching(target_bounds_in_screen_); |
| 178 if (!phantom_widget_ || |
| 115 phantom_widget_->GetNativeWindow()->GetRootWindow() != target_root) { | 179 phantom_widget_->GetNativeWindow()->GetRootWindow() != target_root) { |
| 116 phantom_widget_->Close(); | 180 phantom_widget_.reset(CreatePhantomWidget(target_root, start_bounds)); |
| 117 phantom_widget_ = NULL; | |
| 118 } | 181 } |
| 119 if (!phantom_widget_) | 182 AnimateToBounds(phantom_widget_.get(), target_bounds_in_screen_); |
| 120 phantom_widget_ = CreatePhantomWidget(target_root, start_bounds_); | |
| 121 | 183 |
| 122 // Create a secondary widget in a second screen if start_bounds_ lie at least | 184 // Create a secondary widget in a second screen if |start_bounds| lies at |
| 123 // partially in that other screen. This allows animations to start or restart | 185 // least partially in another screen. This allows animations to start or |
| 124 // in one root window and progress into another root. | 186 // restart in one root window and progress to another root. |
| 125 aura::Window* start_root = wm::GetRootWindowMatching(start_bounds_); | 187 aura::Window* start_root = wm::GetRootWindowMatching(start_bounds); |
| 126 if (start_root == target_root) { | 188 if (start_root == target_root) { |
| 127 aura::Window::Windows root_windows = Shell::GetAllRootWindows(); | 189 aura::Window::Windows root_windows = Shell::GetAllRootWindows(); |
| 128 for (size_t i = 0; i < root_windows.size(); ++i) { | 190 for (size_t i = 0; i < root_windows.size(); ++i) { |
| 129 if (root_windows[i] != target_root && | 191 if (root_windows[i] != target_root && |
| 130 root_windows[i]->GetBoundsInScreen().Intersects(start_bounds_)) { | 192 root_windows[i]->GetBoundsInScreen().Intersects(start_bounds)) { |
| 131 start_root = root_windows[i]; | 193 start_root = root_windows[i]; |
| 132 break; | 194 break; |
| 133 } | 195 } |
| 134 } | 196 } |
| 135 } | 197 } |
| 136 if (phantom_widget_start_ && | 198 if (start_root == target_root) { |
| 137 (phantom_widget_start_->GetNativeWindow()->GetRootWindow() != start_root | 199 phantom_widget_start_.reset(); |
| 138 || start_root == target_root)) { | 200 } else { |
| 139 phantom_widget_start_->Close(); | 201 if (!phantom_widget_start_ || |
| 140 phantom_widget_start_ = NULL; | 202 phantom_widget_start_->GetNativeWindow()->GetRootWindow() != |
| 203 start_root) { |
| 204 phantom_widget_start_.reset( |
| 205 CreatePhantomWidget(start_root, start_bounds)); |
| 206 } |
| 207 AnimateToBounds(phantom_widget_start_.get(), target_bounds_in_screen_); |
| 141 } | 208 } |
| 142 if (!phantom_widget_start_ && start_root != target_root) | 209 } |
| 143 phantom_widget_start_ = CreatePhantomWidget(start_root, start_bounds_); | |
| 144 | 210 |
| 145 animation_.reset(new gfx::SlideAnimation(this)); | 211 void PhantomWindowController::StartFadeOut() { |
| 146 animation_->SetTweenType(gfx::Tween::EASE_IN); | 212 StartFade(false); |
| 147 const int kAnimationDurationMS = 200; | |
| 148 animation_->SetSlideDuration(kAnimationDurationMS); | |
| 149 animation_->Show(); | |
| 150 } | 213 } |
| 151 | 214 |
| 152 void PhantomWindowController::Hide() { | 215 void PhantomWindowController::Hide() { |
| 153 if (phantom_widget_) | 216 target_visibility_ = false; |
| 154 phantom_widget_->Close(); | 217 phantom_widget_.reset(); |
| 155 phantom_widget_ = NULL; | 218 phantom_widget_start_.reset(); |
| 156 if (phantom_widget_start_) | |
| 157 phantom_widget_start_->Close(); | |
| 158 phantom_widget_start_ = NULL; | |
| 159 } | 219 } |
| 160 | 220 |
| 161 bool PhantomWindowController::IsShowing() const { | 221 bool PhantomWindowController::IsShowing() const { |
| 162 return phantom_widget_ != NULL; | 222 return target_visibility_; |
| 163 } | |
| 164 | |
| 165 void PhantomWindowController::AnimationProgressed( | |
| 166 const gfx::Animation* animation) { | |
| 167 const gfx::Rect current_bounds = | |
| 168 animation->CurrentValueBetween(start_bounds_, bounds_in_screen_); | |
| 169 if (phantom_widget_start_) | |
| 170 phantom_widget_start_->SetBounds(current_bounds); | |
| 171 phantom_widget_->SetBounds(current_bounds); | |
| 172 } | 223 } |
| 173 | 224 |
| 174 views::Widget* PhantomWindowController::CreatePhantomWidget( | 225 views::Widget* PhantomWindowController::CreatePhantomWidget( |
| 175 aura::Window* root_window, | 226 aura::Window* root_window, |
| 176 const gfx::Rect& bounds_in_screen) { | 227 const gfx::Rect& bounds_in_screen) { |
| 177 views::Widget* phantom_widget = new views::Widget; | 228 views::Widget* phantom_widget = new views::Widget; |
| 178 views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP); | 229 views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP); |
| 179 params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; | 230 params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; |
| 180 // PhantomWindowController is used by FrameMaximizeButton to highlight the | 231 // PhantomWindowController is used by FrameMaximizeButton to highlight the |
| 181 // launcher button. Put the phantom in the same window as the launcher so that | 232 // launcher button. Put the phantom in the same window as the launcher so that |
| 182 // the phantom is visible. | 233 // the phantom is visible. |
| 183 params.parent = Shell::GetContainer(root_window, | 234 params.parent = Shell::GetContainer(root_window, |
| 184 kShellWindowId_ShelfContainer); | 235 kShellWindowId_ShelfContainer); |
| 185 params.can_activate = false; | 236 params.can_activate = false; |
| 186 params.keep_on_top = true; | 237 params.keep_on_top = true; |
| 238 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; |
| 187 phantom_widget->set_focus_on_creation(false); | 239 phantom_widget->set_focus_on_creation(false); |
| 188 phantom_widget->Init(params); | 240 phantom_widget->Init(params); |
| 189 phantom_widget->SetVisibilityChangedAnimationsEnabled(false); | 241 phantom_widget->SetVisibilityChangedAnimationsEnabled(false); |
| 190 phantom_widget->GetNativeWindow()->SetName("PhantomWindow"); | 242 phantom_widget->GetNativeWindow()->SetName("PhantomWindow"); |
| 191 phantom_widget->GetNativeWindow()->set_id(kShellWindowId_PhantomWindow); | 243 phantom_widget->GetNativeWindow()->set_id(kShellWindowId_PhantomWindow); |
| 192 views::View* content_view = new views::View; | 244 phantom_widget->SetBounds(GetBoundsWithShadow(bounds_in_screen)); |
| 193 content_view->set_background( | |
| 194 views::Background::CreateBackgroundPainter(true, new EdgePainter)); | |
| 195 phantom_widget->SetContentsView(content_view); | |
| 196 phantom_widget->SetBounds(bounds_in_screen); | |
| 197 if (phantom_below_window_) | 245 if (phantom_below_window_) |
| 198 phantom_widget->StackBelow(phantom_below_window_); | 246 phantom_widget->StackBelow(phantom_below_window_); |
| 199 else | 247 else |
| 200 phantom_widget->StackAbove(window_); | 248 phantom_widget->StackAbove(window_); |
| 201 | 249 |
| 202 // Show the widget after all the setups. | 250 views::Painter* background_painter; |
| 203 phantom_widget->Show(); | 251 if (switches::UseAlternateFrameCaptionButtonStyle()) { |
| 252 const int kImages[] = IMAGE_GRID(IDR_AURA_PHANTOM_WINDOW); |
| 253 background_painter = views::Painter::CreateImageGridPainter(kImages); |
| 254 } else { |
| 255 background_painter = new EdgePainter; |
| 256 } |
| 257 views::View* content_view = new views::View; |
| 258 content_view->set_background( |
| 259 views::Background::CreateBackgroundPainter(true, background_painter)); |
| 260 phantom_widget->SetContentsView(content_view); |
| 204 | 261 |
| 205 // Fade the window in. | 262 // Fade the window in. |
| 206 ui::Layer* widget_layer = phantom_widget->GetNativeWindow()->layer(); | 263 ui::Layer* widget_layer = phantom_widget->GetNativeWindow()->layer(); |
| 207 widget_layer->SetOpacity(0); | 264 widget_layer->SetOpacity(0); |
| 208 ui::ScopedLayerAnimationSettings scoped_setter(widget_layer->GetAnimator()); | 265 AnimateToVisibility(phantom_widget, true); |
| 209 widget_layer->SetOpacity(1); | |
| 210 return phantom_widget; | 266 return phantom_widget; |
| 211 } | 267 } |
| 212 | 268 |
| 269 void PhantomWindowController::StartFade(bool fade_in) { |
| 270 if (target_visibility_ != fade_in) { |
| 271 target_visibility_ = fade_in; |
| 272 AnimateToVisibility(phantom_widget_.get(), target_visibility_); |
| 273 AnimateToVisibility(phantom_widget_start_.get(), target_visibility_); |
| 274 } |
| 275 } |
| 276 |
| 213 } // namespace internal | 277 } // namespace internal |
| 214 } // namespace ash | 278 } // namespace ash |
| OLD | NEW |