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 |