Chromium Code Reviews| 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 = 55; | |
| 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_in_screen|. No-op if |widget| | |
| 54 // is NULL. | |
| 55 void AnimateToBounds(views::Widget* widget, | |
| 56 const gfx::Rect& new_bounds_in_screen) { | |
| 57 if (!widget) | |
| 58 return; | |
| 59 | |
| 60 ui::Layer* layer = widget->GetNativeWindow()->layer(); | |
| 61 ui::ScopedLayerAnimationSettings scoped_setter( | |
| 62 layer->GetAnimator()); | |
| 63 scoped_setter.SetTweenType(gfx::Tween::EASE_IN); | |
| 64 scoped_setter.SetPreemptionStrategy( | |
| 65 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); | |
|
sky
2013/12/19 21:25:43
Why do you want strategy?
pkotwicz
2013/12/20 01:57:20
I think that IMMEDIATELY_ANIMATE_TO_NEW_TARGET sho
| |
| 66 scoped_setter.SetTransitionDuration( | |
| 67 base::TimeDelta::FromMilliseconds(kBoundsChangeAnimationDurationMs)); | |
| 68 widget->SetBounds(new_bounds_in_screen); | |
| 69 } | |
| 70 | |
| 71 // Starts a fade in or fade out animation of |widget|. No-op if |widget| is | |
| 72 // NULL. | |
| 73 void AnimateToVisibility(views::Widget* widget, bool new_visibility) { | |
|
sky
2013/12/19 21:25:43
Seems like this is the same as an AnimationType of
pkotwicz
2013/12/20 01:57:20
kChildWindowVisibilityChangesAnimatedKey is false
sky
2014/01/06 17:30:05
Can't you temporarily enable animations when you c
| |
| 74 if (!widget) | |
| 75 return; | |
| 76 | |
| 77 if (new_visibility) | |
| 78 widget->Show(); | |
| 79 | |
| 80 int animation_duration_ms = new_visibility ? | |
| 81 kShowAnimationDurationMs : kHideAnimationDurationMs; | |
| 82 | |
| 83 ui::Layer* layer = widget->GetNativeWindow()->layer(); | |
| 84 ui::ScopedLayerAnimationSettings scoped_setter(layer->GetAnimator()); | |
| 85 scoped_setter.SetPreemptionStrategy( | |
| 86 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); | |
| 87 scoped_setter.SetTransitionDuration(base::TimeDelta::FromMilliseconds( | |
| 88 animation_duration_ms)); | |
| 89 if (!new_visibility) | |
| 90 widget->Hide(); | |
|
pkotwicz
2013/12/18 19:16:47
Changed so that Hide() gets called before setting
Mr4D (OOO till 08-26)
2013/12/19 17:56:55
I just checked with sky and all you would need to
pkotwicz
2013/12/19 18:18:22
I am unsure if I understand. I need to call both u
| |
| 91 layer->SetOpacity(new_visibility ? 1.0f : 0.0f); | |
| 92 } | |
| 93 | |
| 26 // EdgePainter ---------------------------------------------------------------- | 94 // EdgePainter ---------------------------------------------------------------- |
| 27 | 95 |
| 28 namespace { | |
| 29 | |
| 30 // Paints the background of the phantom window for window snapping. | 96 // Paints the background of the phantom window for window snapping. |
| 31 class EdgePainter : public views::Painter { | 97 class EdgePainter : public views::Painter { |
| 32 public: | 98 public: |
| 33 EdgePainter(); | 99 EdgePainter(); |
| 34 virtual ~EdgePainter(); | 100 virtual ~EdgePainter(); |
| 35 | 101 |
| 36 // views::Painter: | 102 // views::Painter: |
| 37 virtual gfx::Size GetMinimumSize() const OVERRIDE; | 103 virtual gfx::Size GetMinimumSize() const OVERRIDE; |
| 38 virtual void Paint(gfx::Canvas* canvas, const gfx::Size& size) OVERRIDE; | 104 virtual void Paint(gfx::Canvas* canvas, const gfx::Size& size) OVERRIDE; |
| 39 | 105 |
| 40 private: | 106 private: |
| 41 DISALLOW_COPY_AND_ASSIGN(EdgePainter); | 107 DISALLOW_COPY_AND_ASSIGN(EdgePainter); |
| 42 }; | 108 }; |
| 43 | 109 |
| 44 } // namespace | |
| 45 | |
| 46 | |
| 47 EdgePainter::EdgePainter() { | 110 EdgePainter::EdgePainter() { |
| 48 } | 111 } |
| 49 | 112 |
| 50 EdgePainter::~EdgePainter() { | 113 EdgePainter::~EdgePainter() { |
| 51 } | 114 } |
| 52 | 115 |
| 53 gfx::Size EdgePainter::GetMinimumSize() const { | 116 gfx::Size EdgePainter::GetMinimumSize() const { |
| 54 return gfx::Size(); | 117 return gfx::Size(); |
| 55 } | 118 } |
| 56 | 119 |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 79 return; | 142 return; |
| 80 | 143 |
| 81 paint.setColor(SkColorSetARGB(200, 255, 255, 255)); | 144 paint.setColor(SkColorSetARGB(200, 255, 255, 255)); |
| 82 paint.setStyle(SkPaint::kStroke_Style); | 145 paint.setStyle(SkPaint::kStroke_Style); |
| 83 paint.setStrokeWidth(SkIntToScalar(2)); | 146 paint.setStrokeWidth(SkIntToScalar(2)); |
| 84 canvas->sk_canvas()->drawRoundRect( | 147 canvas->sk_canvas()->drawRoundRect( |
| 85 gfx::RectToSkRect(gfx::Rect(x, y, w, h)), SkIntToScalar(kRoundRectSize), | 148 gfx::RectToSkRect(gfx::Rect(x, y, w, h)), SkIntToScalar(kRoundRectSize), |
| 86 SkIntToScalar(kRoundRectSize), paint); | 149 SkIntToScalar(kRoundRectSize), paint); |
| 87 } | 150 } |
| 88 | 151 |
| 152 } // namespace | |
| 89 | 153 |
| 90 // PhantomWindowController ---------------------------------------------------- | 154 // PhantomWindowController ---------------------------------------------------- |
| 91 | 155 |
| 92 PhantomWindowController::PhantomWindowController(aura::Window* window) | 156 PhantomWindowController::PhantomWindowController(aura::Window* window) |
| 93 : window_(window), | 157 : window_(window), |
| 94 phantom_below_window_(NULL), | 158 phantom_below_window_(NULL), |
| 95 phantom_widget_(NULL), | 159 target_visibility_(false) { |
| 96 phantom_widget_start_(NULL) { | |
| 97 } | 160 } |
| 98 | 161 |
| 99 PhantomWindowController::~PhantomWindowController() { | 162 PhantomWindowController::~PhantomWindowController() { |
| 100 Hide(); | |
| 101 } | 163 } |
| 102 | 164 |
| 103 void PhantomWindowController::Show(const gfx::Rect& bounds_in_screen) { | 165 void PhantomWindowController::Show(const gfx::Rect& bounds_in_screen) { |
| 104 if (bounds_in_screen == bounds_in_screen_) | 166 if (GetBoundsWithShadow(bounds_in_screen) == target_bounds_in_screen_ && |
| 167 target_visibility_) { | |
| 105 return; | 168 return; |
| 106 bounds_in_screen_ = bounds_in_screen; | 169 } |
| 107 aura::Window* target_root = wm::GetRootWindowMatching(bounds_in_screen); | 170 if (target_phantom_widget_ && |
| 108 // Show the phantom at the current bounds of the window. We'll animate to the | 171 !target_phantom_widget_->GetNativeView()->layer()->IsDrawn()) { |
|
pkotwicz
2013/12/18 19:16:47
I made the phantom window start animating from |wi
| |
| 109 // target bounds. If phantom exists, update the start bounds. | 172 target_phantom_widget_.reset(); |
| 110 if (!phantom_widget_) | 173 start_phantom_widget_.reset(); |
| 111 start_bounds_ = window_->GetBoundsInScreen(); | 174 } |
| 175 StartFade(true); | |
| 176 | |
| 177 target_bounds_in_screen_ = GetBoundsWithShadow(bounds_in_screen); | |
| 178 gfx::Rect start_bounds; | |
| 179 if (!target_phantom_widget_) | |
| 180 start_bounds = GetBoundsWithShadow(window_->GetBoundsInScreen()); | |
|
pkotwicz
2013/12/18 19:16:47
Fixed when GetBoundsWithShadow() is called. In the
| |
| 112 else | 181 else |
| 113 start_bounds_ = phantom_widget_->GetWindowBoundsInScreen(); | 182 start_bounds = target_phantom_widget_->GetWindowBoundsInScreen(); |
| 114 if (phantom_widget_ && | 183 |
| 115 phantom_widget_->GetNativeWindow()->GetRootWindow() != target_root) { | 184 aura::Window* target_root = |
| 116 phantom_widget_->Close(); | 185 wm::GetRootWindowMatching(target_bounds_in_screen_); |
| 117 phantom_widget_ = NULL; | 186 if (!target_phantom_widget_ || |
| 187 target_phantom_widget_->GetNativeWindow()->GetRootWindow() != | |
| 188 target_root) { | |
| 189 target_phantom_widget_.reset( | |
| 190 CreatePhantomWidget(target_root, start_bounds)); | |
| 118 } | 191 } |
| 119 if (!phantom_widget_) | 192 AnimateToBounds(target_phantom_widget_.get(), target_bounds_in_screen_); |
| 120 phantom_widget_ = CreatePhantomWidget(target_root, start_bounds_); | |
| 121 | 193 |
| 122 // Create a secondary widget in a second screen if start_bounds_ lie at least | 194 // 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 | 195 // least partially in another screen. This allows animations to start or |
| 124 // in one root window and progress into another root. | 196 // restart in one root window and progress to another root. |
| 125 aura::Window* start_root = wm::GetRootWindowMatching(start_bounds_); | 197 aura::Window* start_root = wm::GetRootWindowMatching(start_bounds); |
| 126 if (start_root == target_root) { | 198 if (start_root == target_root) { |
| 127 aura::Window::Windows root_windows = Shell::GetAllRootWindows(); | 199 aura::Window::Windows root_windows = Shell::GetAllRootWindows(); |
| 128 for (size_t i = 0; i < root_windows.size(); ++i) { | 200 for (size_t i = 0; i < root_windows.size(); ++i) { |
| 129 if (root_windows[i] != target_root && | 201 if (root_windows[i] != target_root && |
| 130 root_windows[i]->GetBoundsInScreen().Intersects(start_bounds_)) { | 202 root_windows[i]->GetBoundsInScreen().Intersects(start_bounds)) { |
| 131 start_root = root_windows[i]; | 203 start_root = root_windows[i]; |
| 132 break; | 204 break; |
| 133 } | 205 } |
| 134 } | 206 } |
| 135 } | 207 } |
| 136 if (phantom_widget_start_ && | 208 if (start_root == target_root) { |
| 137 (phantom_widget_start_->GetNativeWindow()->GetRootWindow() != start_root | 209 start_phantom_widget_.reset(); |
| 138 || start_root == target_root)) { | 210 } else { |
| 139 phantom_widget_start_->Close(); | 211 if (!start_phantom_widget_ || |
| 140 phantom_widget_start_ = NULL; | 212 start_phantom_widget_->GetNativeWindow()->GetRootWindow() != |
| 213 start_root) { | |
| 214 start_phantom_widget_.reset( | |
| 215 CreatePhantomWidget(start_root, start_bounds)); | |
| 216 } | |
| 217 AnimateToBounds(start_phantom_widget_.get(), target_bounds_in_screen_); | |
| 141 } | 218 } |
| 142 if (!phantom_widget_start_ && start_root != target_root) | 219 } |
| 143 phantom_widget_start_ = CreatePhantomWidget(start_root, start_bounds_); | |
| 144 | 220 |
| 145 animation_.reset(new gfx::SlideAnimation(this)); | 221 void PhantomWindowController::StartFadeOut() { |
| 146 animation_->SetTweenType(gfx::Tween::EASE_IN); | 222 StartFade(false); |
| 147 const int kAnimationDurationMS = 200; | |
| 148 animation_->SetSlideDuration(kAnimationDurationMS); | |
| 149 animation_->Show(); | |
| 150 } | 223 } |
| 151 | 224 |
| 152 void PhantomWindowController::Hide() { | 225 void PhantomWindowController::Hide() { |
| 153 if (phantom_widget_) | 226 target_visibility_ = false; |
| 154 phantom_widget_->Close(); | 227 target_phantom_widget_.reset(); |
| 155 phantom_widget_ = NULL; | 228 start_phantom_widget_.reset(); |
| 156 if (phantom_widget_start_) | |
| 157 phantom_widget_start_->Close(); | |
| 158 phantom_widget_start_ = NULL; | |
| 159 } | 229 } |
| 160 | 230 |
| 161 bool PhantomWindowController::IsShowing() const { | 231 bool PhantomWindowController::IsShowing() const { |
| 162 return phantom_widget_ != NULL; | 232 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 } | 233 } |
| 173 | 234 |
| 174 views::Widget* PhantomWindowController::CreatePhantomWidget( | 235 views::Widget* PhantomWindowController::CreatePhantomWidget( |
| 175 aura::Window* root_window, | 236 aura::Window* root_window, |
| 176 const gfx::Rect& bounds_in_screen) { | 237 const gfx::Rect& bounds_in_screen) { |
| 177 views::Widget* phantom_widget = new views::Widget; | 238 views::Widget* phantom_widget = new views::Widget; |
| 178 views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP); | 239 views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP); |
| 179 params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; | 240 params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; |
| 180 // PhantomWindowController is used by FrameMaximizeButton to highlight the | 241 // PhantomWindowController is used by FrameMaximizeButton to highlight the |
| 181 // launcher button. Put the phantom in the same window as the launcher so that | 242 // launcher button. Put the phantom in the same window as the launcher so that |
| 182 // the phantom is visible. | 243 // the phantom is visible. |
| 183 params.parent = Shell::GetContainer(root_window, | 244 params.parent = Shell::GetContainer(root_window, |
| 184 kShellWindowId_ShelfContainer); | 245 kShellWindowId_ShelfContainer); |
| 185 params.can_activate = false; | 246 params.can_activate = false; |
| 186 params.keep_on_top = true; | 247 params.keep_on_top = true; |
| 248 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; | |
| 187 phantom_widget->set_focus_on_creation(false); | 249 phantom_widget->set_focus_on_creation(false); |
| 188 phantom_widget->Init(params); | 250 phantom_widget->Init(params); |
| 189 phantom_widget->SetVisibilityChangedAnimationsEnabled(false); | 251 phantom_widget->SetVisibilityChangedAnimationsEnabled(false); |
| 190 phantom_widget->GetNativeWindow()->SetName("PhantomWindow"); | 252 phantom_widget->GetNativeWindow()->SetName("PhantomWindow"); |
| 191 phantom_widget->GetNativeWindow()->set_id(kShellWindowId_PhantomWindow); | 253 phantom_widget->GetNativeWindow()->set_id(kShellWindowId_PhantomWindow); |
| 192 views::View* content_view = new views::View; | |
| 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); | 254 phantom_widget->SetBounds(bounds_in_screen); |
| 197 if (phantom_below_window_) | 255 if (phantom_below_window_) |
| 198 phantom_widget->StackBelow(phantom_below_window_); | 256 phantom_widget->StackBelow(phantom_below_window_); |
| 199 else | 257 else |
| 200 phantom_widget->StackAbove(window_); | 258 phantom_widget->StackAbove(window_); |
| 201 | 259 |
| 202 // Show the widget after all the setups. | 260 views::Painter* background_painter; |
| 203 phantom_widget->Show(); | 261 if (switches::UseAlternateFrameCaptionButtonStyle()) { |
| 262 const int kImages[] = IMAGE_GRID(IDR_AURA_PHANTOM_WINDOW); | |
| 263 background_painter = views::Painter::CreateImageGridPainter(kImages); | |
| 264 } else { | |
| 265 background_painter = new EdgePainter; | |
| 266 } | |
| 267 views::View* content_view = new views::View; | |
| 268 content_view->set_background( | |
| 269 views::Background::CreateBackgroundPainter(true, background_painter)); | |
| 270 phantom_widget->SetContentsView(content_view); | |
| 204 | 271 |
| 205 // Fade the window in. | 272 // Fade the window in. |
| 206 ui::Layer* widget_layer = phantom_widget->GetNativeWindow()->layer(); | 273 ui::Layer* widget_layer = phantom_widget->GetNativeWindow()->layer(); |
| 207 widget_layer->SetOpacity(0); | 274 widget_layer->SetOpacity(0); |
| 208 ui::ScopedLayerAnimationSettings scoped_setter(widget_layer->GetAnimator()); | 275 AnimateToVisibility(phantom_widget, true); |
| 209 widget_layer->SetOpacity(1); | |
| 210 return phantom_widget; | 276 return phantom_widget; |
| 211 } | 277 } |
| 212 | 278 |
| 279 void PhantomWindowController::StartFade(bool fade_in) { | |
| 280 if (target_visibility_ != fade_in) { | |
| 281 target_visibility_ = fade_in; | |
| 282 AnimateToVisibility(target_phantom_widget_.get(), target_visibility_); | |
| 283 AnimateToVisibility(start_phantom_widget_.get(), target_visibility_); | |
| 284 } | |
| 285 } | |
| 286 | |
| 213 } // namespace internal | 287 } // namespace internal |
| 214 } // namespace ash | 288 } // namespace ash |
| OLD | NEW |