| 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/shell.h" | 7 #include "ash/shell.h" |
| 8 #include "ash/shell_window_ids.h" | 8 #include "ash/shell_window_ids.h" |
| 9 #include "ash/wm/coordinate_conversion.h" | 9 #include "ash/wm/coordinate_conversion.h" |
| 10 #include "third_party/skia/include/core/SkCanvas.h" | 10 #include "third_party/skia/include/core/SkCanvas.h" |
| 11 #include "ui/aura/root_window.h" | 11 #include "ui/aura/root_window.h" |
| 12 #include "ui/aura/window.h" | 12 #include "ui/aura/window.h" |
| 13 #include "ui/compositor/layer.h" | 13 #include "ui/compositor/layer.h" |
| 14 #include "ui/compositor/scoped_layer_animation_settings.h" | 14 #include "ui/compositor/scoped_layer_animation_settings.h" |
| 15 #include "ui/gfx/animation/slide_animation.h" | |
| 16 #include "ui/gfx/canvas.h" | 15 #include "ui/gfx/canvas.h" |
| 17 #include "ui/gfx/skia_util.h" | 16 #include "ui/gfx/skia_util.h" |
| 18 #include "ui/views/background.h" | 17 #include "ui/views/background.h" |
| 19 #include "ui/views/painter.h" | 18 #include "ui/views/painter.h" |
| 20 #include "ui/views/view.h" | 19 #include "ui/views/view.h" |
| 21 #include "ui/views/widget/widget.h" | 20 #include "ui/views/widget/widget.h" |
| 22 | 21 |
| 23 namespace ash { | 22 namespace ash { |
| 24 namespace internal { | 23 namespace internal { |
| 25 | 24 |
| 25 namespace { |
| 26 |
| 27 // The duration of the show animation. |
| 28 const int kAnimationDurationMs = 200; |
| 29 |
| 30 // Starts an animation of |widget| to |new_bounds_in_screen|. No-op if |widget| |
| 31 // is NULL. |
| 32 void AnimateToBounds(views::Widget* widget, |
| 33 const gfx::Rect& new_bounds_in_screen) { |
| 34 if (!widget) |
| 35 return; |
| 36 |
| 37 ui::ScopedLayerAnimationSettings scoped_setter( |
| 38 widget->GetNativeWindow()->layer()->GetAnimator()); |
| 39 scoped_setter.SetTweenType(gfx::Tween::EASE_IN); |
| 40 scoped_setter.SetPreemptionStrategy( |
| 41 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); |
| 42 scoped_setter.SetTransitionDuration( |
| 43 base::TimeDelta::FromMilliseconds(kAnimationDurationMs)); |
| 44 widget->SetBounds(new_bounds_in_screen); |
| 45 } |
| 46 |
| 26 // EdgePainter ---------------------------------------------------------------- | 47 // EdgePainter ---------------------------------------------------------------- |
| 27 | 48 |
| 28 namespace { | |
| 29 | |
| 30 // Paints the background of the phantom window for window snapping. | 49 // Paints the background of the phantom window for window snapping. |
| 31 class EdgePainter : public views::Painter { | 50 class EdgePainter : public views::Painter { |
| 32 public: | 51 public: |
| 33 EdgePainter(); | 52 EdgePainter(); |
| 34 virtual ~EdgePainter(); | 53 virtual ~EdgePainter(); |
| 35 | 54 |
| 36 // views::Painter: | 55 // views::Painter: |
| 37 virtual gfx::Size GetMinimumSize() const OVERRIDE; | 56 virtual gfx::Size GetMinimumSize() const OVERRIDE; |
| 38 virtual void Paint(gfx::Canvas* canvas, const gfx::Size& size) OVERRIDE; | 57 virtual void Paint(gfx::Canvas* canvas, const gfx::Size& size) OVERRIDE; |
| 39 | 58 |
| 40 private: | 59 private: |
| 41 DISALLOW_COPY_AND_ASSIGN(EdgePainter); | 60 DISALLOW_COPY_AND_ASSIGN(EdgePainter); |
| 42 }; | 61 }; |
| 43 | 62 |
| 44 } // namespace | |
| 45 | |
| 46 | |
| 47 EdgePainter::EdgePainter() { | 63 EdgePainter::EdgePainter() { |
| 48 } | 64 } |
| 49 | 65 |
| 50 EdgePainter::~EdgePainter() { | 66 EdgePainter::~EdgePainter() { |
| 51 } | 67 } |
| 52 | 68 |
| 53 gfx::Size EdgePainter::GetMinimumSize() const { | 69 gfx::Size EdgePainter::GetMinimumSize() const { |
| 54 return gfx::Size(); | 70 return gfx::Size(); |
| 55 } | 71 } |
| 56 | 72 |
| (...skipping 22 matching lines...) Expand all Loading... |
| 79 return; | 95 return; |
| 80 | 96 |
| 81 paint.setColor(SkColorSetARGB(200, 255, 255, 255)); | 97 paint.setColor(SkColorSetARGB(200, 255, 255, 255)); |
| 82 paint.setStyle(SkPaint::kStroke_Style); | 98 paint.setStyle(SkPaint::kStroke_Style); |
| 83 paint.setStrokeWidth(SkIntToScalar(2)); | 99 paint.setStrokeWidth(SkIntToScalar(2)); |
| 84 canvas->sk_canvas()->drawRoundRect( | 100 canvas->sk_canvas()->drawRoundRect( |
| 85 gfx::RectToSkRect(gfx::Rect(x, y, w, h)), SkIntToScalar(kRoundRectSize), | 101 gfx::RectToSkRect(gfx::Rect(x, y, w, h)), SkIntToScalar(kRoundRectSize), |
| 86 SkIntToScalar(kRoundRectSize), paint); | 102 SkIntToScalar(kRoundRectSize), paint); |
| 87 } | 103 } |
| 88 | 104 |
| 105 } // namespace |
| 89 | 106 |
| 90 // PhantomWindowController ---------------------------------------------------- | 107 // PhantomWindowController ---------------------------------------------------- |
| 91 | 108 |
| 92 PhantomWindowController::PhantomWindowController(aura::Window* window) | 109 PhantomWindowController::PhantomWindowController(aura::Window* window) |
| 93 : window_(window), | 110 : window_(window), |
| 94 phantom_below_window_(NULL), | 111 phantom_below_window_(NULL) { |
| 95 phantom_widget_(NULL), | |
| 96 phantom_widget_start_(NULL) { | |
| 97 } | 112 } |
| 98 | 113 |
| 99 PhantomWindowController::~PhantomWindowController() { | 114 PhantomWindowController::~PhantomWindowController() { |
| 100 Hide(); | |
| 101 } | 115 } |
| 102 | 116 |
| 103 void PhantomWindowController::Show(const gfx::Rect& bounds_in_screen) { | 117 void PhantomWindowController::Show(const gfx::Rect& bounds_in_screen) { |
| 104 if (bounds_in_screen == bounds_in_screen_) | 118 if (bounds_in_screen == target_bounds_in_screen_) |
| 105 return; | 119 return; |
| 106 bounds_in_screen_ = bounds_in_screen; | 120 target_bounds_in_screen_ = bounds_in_screen; |
| 107 aura::Window* target_root = wm::GetRootWindowMatching(bounds_in_screen); | 121 |
| 108 // Show the phantom at the current bounds of the window. We'll animate to the | 122 gfx::Rect start_bounds_in_screen; |
| 109 // target bounds. If phantom exists, update the start bounds. | 123 if (!phantom_widget_in_target_root_) { |
| 110 if (!phantom_widget_) | 124 start_bounds_in_screen = window_->GetBoundsInScreen(); |
| 111 start_bounds_ = window_->GetBoundsInScreen(); | 125 } else { |
| 112 else | 126 start_bounds_in_screen = |
| 113 start_bounds_ = phantom_widget_->GetWindowBoundsInScreen(); | 127 phantom_widget_in_target_root_->GetWindowBoundsInScreen(); |
| 114 if (phantom_widget_ && | |
| 115 phantom_widget_->GetNativeWindow()->GetRootWindow() != target_root) { | |
| 116 phantom_widget_->Close(); | |
| 117 phantom_widget_ = NULL; | |
| 118 } | 128 } |
| 119 if (!phantom_widget_) | |
| 120 phantom_widget_ = CreatePhantomWidget(target_root, start_bounds_); | |
| 121 | 129 |
| 122 // Create a secondary widget in a second screen if start_bounds_ lie at least | 130 aura::Window* target_root = |
| 123 // partially in that other screen. This allows animations to start or restart | 131 wm::GetRootWindowMatching(target_bounds_in_screen_); |
| 124 // in one root window and progress into another root. | 132 if (!phantom_widget_in_target_root_ || |
| 125 aura::Window* start_root = wm::GetRootWindowMatching(start_bounds_); | 133 phantom_widget_in_target_root_->GetNativeWindow()->GetRootWindow() != |
| 134 target_root) { |
| 135 phantom_widget_in_target_root_ = |
| 136 CreatePhantomWidget(target_root, start_bounds_in_screen); |
| 137 } |
| 138 AnimateToBounds(phantom_widget_in_target_root_.get(), |
| 139 target_bounds_in_screen_); |
| 140 |
| 141 // Create a secondary widget in a second screen if |start_bounds_in_screen| |
| 142 // lies at least partially in another screen. This allows animations to start |
| 143 // or restart in one root window and progress to another root. |
| 144 aura::Window* start_root = wm::GetRootWindowMatching(start_bounds_in_screen); |
| 126 if (start_root == target_root) { | 145 if (start_root == target_root) { |
| 127 aura::Window::Windows root_windows = Shell::GetAllRootWindows(); | 146 aura::Window::Windows root_windows = Shell::GetAllRootWindows(); |
| 128 for (size_t i = 0; i < root_windows.size(); ++i) { | 147 for (size_t i = 0; i < root_windows.size(); ++i) { |
| 129 if (root_windows[i] != target_root && | 148 if (root_windows[i] != target_root && |
| 130 root_windows[i]->GetBoundsInScreen().Intersects(start_bounds_)) { | 149 root_windows[i]->GetBoundsInScreen().Intersects( |
| 150 start_bounds_in_screen)) { |
| 131 start_root = root_windows[i]; | 151 start_root = root_windows[i]; |
| 132 break; | 152 break; |
| 133 } | 153 } |
| 134 } | 154 } |
| 135 } | 155 } |
| 136 if (phantom_widget_start_ && | 156 if (start_root == target_root) { |
| 137 (phantom_widget_start_->GetNativeWindow()->GetRootWindow() != start_root | 157 phantom_widget_in_start_root_.reset(); |
| 138 || start_root == target_root)) { | 158 } else { |
| 139 phantom_widget_start_->Close(); | 159 if (!phantom_widget_in_start_root_ || |
| 140 phantom_widget_start_ = NULL; | 160 phantom_widget_in_start_root_->GetNativeWindow()->GetRootWindow() != |
| 161 start_root) { |
| 162 phantom_widget_in_start_root_ = |
| 163 CreatePhantomWidget(start_root, start_bounds_in_screen); |
| 164 } |
| 165 AnimateToBounds(phantom_widget_in_start_root_.get(), |
| 166 target_bounds_in_screen_); |
| 141 } | 167 } |
| 142 if (!phantom_widget_start_ && start_root != target_root) | |
| 143 phantom_widget_start_ = CreatePhantomWidget(start_root, start_bounds_); | |
| 144 | |
| 145 animation_.reset(new gfx::SlideAnimation(this)); | |
| 146 animation_->SetTweenType(gfx::Tween::EASE_IN); | |
| 147 const int kAnimationDurationMS = 200; | |
| 148 animation_->SetSlideDuration(kAnimationDurationMS); | |
| 149 animation_->Show(); | |
| 150 } | 168 } |
| 151 | 169 |
| 152 void PhantomWindowController::Hide() { | 170 scoped_ptr<views::Widget> PhantomWindowController::CreatePhantomWidget( |
| 153 if (phantom_widget_) | |
| 154 phantom_widget_->Close(); | |
| 155 phantom_widget_ = NULL; | |
| 156 if (phantom_widget_start_) | |
| 157 phantom_widget_start_->Close(); | |
| 158 phantom_widget_start_ = NULL; | |
| 159 } | |
| 160 | |
| 161 bool PhantomWindowController::IsShowing() const { | |
| 162 return phantom_widget_ != NULL; | |
| 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 } | |
| 173 | |
| 174 views::Widget* PhantomWindowController::CreatePhantomWidget( | |
| 175 aura::Window* root_window, | 171 aura::Window* root_window, |
| 176 const gfx::Rect& bounds_in_screen) { | 172 const gfx::Rect& bounds_in_screen) { |
| 177 views::Widget* phantom_widget = new views::Widget; | 173 scoped_ptr<views::Widget> phantom_widget(new views::Widget); |
| 178 views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP); | 174 views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP); |
| 179 params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; | 175 params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; |
| 180 // PhantomWindowController is used by FrameMaximizeButton to highlight the | 176 // PhantomWindowController is used by FrameMaximizeButton to highlight the |
| 181 // launcher button. Put the phantom in the same window as the launcher so that | 177 // launcher button. Put the phantom in the same window as the launcher so that |
| 182 // the phantom is visible. | 178 // the phantom is visible. |
| 183 params.parent = Shell::GetContainer(root_window, | 179 params.parent = Shell::GetContainer(root_window, |
| 184 kShellWindowId_ShelfContainer); | 180 kShellWindowId_ShelfContainer); |
| 185 params.can_activate = false; | 181 params.can_activate = false; |
| 186 params.keep_on_top = true; | 182 params.keep_on_top = true; |
| 183 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; |
| 187 phantom_widget->set_focus_on_creation(false); | 184 phantom_widget->set_focus_on_creation(false); |
| 188 phantom_widget->Init(params); | 185 phantom_widget->Init(params); |
| 189 phantom_widget->SetVisibilityChangedAnimationsEnabled(false); | 186 phantom_widget->SetVisibilityChangedAnimationsEnabled(false); |
| 190 phantom_widget->GetNativeWindow()->SetName("PhantomWindow"); | 187 phantom_widget->GetNativeWindow()->SetName("PhantomWindow"); |
| 191 phantom_widget->GetNativeWindow()->set_id(kShellWindowId_PhantomWindow); | 188 phantom_widget->GetNativeWindow()->set_id(kShellWindowId_PhantomWindow); |
| 192 views::View* content_view = new views::View; | 189 views::View* content_view = new views::View; |
| 193 content_view->set_background( | 190 content_view->set_background( |
| 194 views::Background::CreateBackgroundPainter(true, new EdgePainter)); | 191 views::Background::CreateBackgroundPainter(true, new EdgePainter)); |
| 195 phantom_widget->SetContentsView(content_view); | 192 phantom_widget->SetContentsView(content_view); |
| 196 phantom_widget->SetBounds(bounds_in_screen); | 193 phantom_widget->SetBounds(bounds_in_screen); |
| 197 if (phantom_below_window_) | 194 if (phantom_below_window_) |
| 198 phantom_widget->StackBelow(phantom_below_window_); | 195 phantom_widget->StackBelow(phantom_below_window_); |
| 199 else | 196 else |
| 200 phantom_widget->StackAbove(window_); | 197 phantom_widget->StackAbove(window_); |
| 201 | 198 |
| 202 // Show the widget after all the setups. | 199 // Show the widget after all the setups. |
| 203 phantom_widget->Show(); | 200 phantom_widget->Show(); |
| 204 | 201 |
| 205 // Fade the window in. | 202 // Fade the window in. |
| 206 ui::Layer* widget_layer = phantom_widget->GetNativeWindow()->layer(); | 203 ui::Layer* widget_layer = phantom_widget->GetNativeWindow()->layer(); |
| 207 widget_layer->SetOpacity(0); | 204 widget_layer->SetOpacity(0); |
| 208 ui::ScopedLayerAnimationSettings scoped_setter(widget_layer->GetAnimator()); | 205 ui::ScopedLayerAnimationSettings scoped_setter(widget_layer->GetAnimator()); |
| 206 scoped_setter.SetTransitionDuration( |
| 207 base::TimeDelta::FromMilliseconds(kAnimationDurationMs)); |
| 209 widget_layer->SetOpacity(1); | 208 widget_layer->SetOpacity(1); |
| 210 return phantom_widget; | 209 |
| 210 return phantom_widget.Pass(); |
| 211 } | 211 } |
| 212 | 212 |
| 213 } // namespace internal | 213 } // namespace internal |
| 214 } // namespace ash | 214 } // namespace ash |
| OLD | NEW |