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