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 |