| 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 <math.h> | 7 #include <math.h> |
| 8 | 8 |
| 9 #include "ash/ash_switches.h" | |
| 10 #include "ash/shell.h" | 9 #include "ash/shell.h" |
| 11 #include "ash/shell_window_ids.h" | 10 #include "ash/shell_window_ids.h" |
| 12 #include "ash/wm/coordinate_conversion.h" | 11 #include "ash/wm/coordinate_conversion.h" |
| 13 #include "grit/ash_resources.h" | 12 #include "grit/ash_resources.h" |
| 14 #include "third_party/skia/include/core/SkCanvas.h" | |
| 15 #include "ui/aura/window.h" | 13 #include "ui/aura/window.h" |
| 16 #include "ui/aura/window_event_dispatcher.h" | |
| 17 #include "ui/compositor/layer.h" | 14 #include "ui/compositor/layer.h" |
| 18 #include "ui/compositor/scoped_layer_animation_settings.h" | 15 #include "ui/compositor/scoped_layer_animation_settings.h" |
| 19 #include "ui/gfx/canvas.h" | |
| 20 #include "ui/gfx/skia_util.h" | |
| 21 #include "ui/views/background.h" | 16 #include "ui/views/background.h" |
| 22 #include "ui/views/painter.h" | 17 #include "ui/views/painter.h" |
| 23 #include "ui/views/view.h" | 18 #include "ui/views/view.h" |
| 24 #include "ui/views/widget/widget.h" | 19 #include "ui/views/widget/widget.h" |
| 25 | 20 |
| 26 namespace ash { | 21 namespace ash { |
| 27 namespace { | 22 namespace { |
| 28 | 23 |
| 29 // The duration of the show animation. | 24 // The duration of the show animation. |
| 30 const int kAnimationDurationMs = 200; | 25 const int kAnimationDurationMs = 200; |
| 31 | 26 |
| 32 // The size of the phantom window at the beginning of the show animation in | 27 // The size of the phantom window at the beginning of the show animation in |
| 33 // relation to the size of the phantom window at the end of the animation when | 28 // relation to the size of the phantom window at the end of the animation. |
| 34 // using the alternate caption button style. | 29 const float kStartBoundsRatio = 0.85f; |
| 35 const float kAlternateStyleStartBoundsRatio = 0.85f; | |
| 36 | 30 |
| 37 // The amount of pixels that the phantom window's shadow should extend past | 31 // The amount of pixels that the phantom window's shadow should extend past |
| 38 // the bounds passed into Show(). There is no shadow when not using the | 32 // the bounds passed into Show(). |
| 39 // alternate caption button style. | 33 const int kShadowThickness = 15; |
| 40 const int kAlternateStyleShadowThickness = 15; | |
| 41 | 34 |
| 42 // The minimum size of a phantom window including the shadow when using the | 35 // The minimum size of a phantom window including the shadow. The minimum size |
| 43 // alternate caption button style. The minimum size is derived from the size of | 36 // is derived from the size of the IDR_AURA_PHANTOM_WINDOW image assets. |
| 44 // the IDR_AURA_PHANTOM_WINDOW image assets. | 37 const int kMinSizeWithShadow = 100; |
| 45 const int kAlternateStyleMinSizeWithShadow = 100; | |
| 46 | 38 |
| 47 // Adjusts the phantom window's bounds so that the bounds: | 39 // Adjusts the phantom window's bounds so that the bounds: |
| 48 // - Include the size of the shadow. | 40 // - Include the size of the shadow. |
| 49 // - Have a size equal to or larger than the minimize phantom window size. | 41 // - Have a size equal to or larger than the minimum phantom window size. |
| 50 gfx::Rect GetAdjustedBoundsForAlternateStyle(const gfx::Rect& bounds) { | 42 gfx::Rect GetAdjustedBounds(const gfx::Rect& bounds) { |
| 51 int x_inset = std::max( | 43 int x_inset = std::max( |
| 52 static_cast<int>( | 44 static_cast<int>(ceil((kMinSizeWithShadow - bounds.width()) / 2.0f)), |
| 53 ceil((kAlternateStyleMinSizeWithShadow - bounds.width()) / 2.0f)), | 45 kShadowThickness); |
| 54 kAlternateStyleShadowThickness); | |
| 55 int y_inset = std::max( | 46 int y_inset = std::max( |
| 56 static_cast<int>( | 47 static_cast<int>(ceil((kMinSizeWithShadow - bounds.height()) / 2.0f)), |
| 57 ceil((kAlternateStyleMinSizeWithShadow - bounds.height()) / 2.0f)), | 48 kShadowThickness); |
| 58 kAlternateStyleShadowThickness); | |
| 59 | 49 |
| 60 gfx::Rect adjusted_bounds(bounds); | 50 gfx::Rect adjusted_bounds(bounds); |
| 61 adjusted_bounds.Inset(-x_inset, -y_inset); | 51 adjusted_bounds.Inset(-x_inset, -y_inset); |
| 62 return adjusted_bounds; | 52 return adjusted_bounds; |
| 63 } | 53 } |
| 64 | 54 |
| 65 // Starts an animation of |widget| to |new_bounds_in_screen|. No-op if |widget| | 55 // Starts an animation of |widget| to |new_bounds_in_screen|. No-op if |widget| |
| 66 // is NULL. | 56 // is NULL. |
| 67 void AnimateToBounds(views::Widget* widget, | 57 void AnimateToBounds(views::Widget* widget, |
| 68 const gfx::Rect& new_bounds_in_screen) { | 58 const gfx::Rect& new_bounds_in_screen) { |
| 69 if (!widget) | 59 if (!widget) |
| 70 return; | 60 return; |
| 71 | 61 |
| 72 ui::ScopedLayerAnimationSettings scoped_setter( | 62 ui::ScopedLayerAnimationSettings scoped_setter( |
| 73 widget->GetNativeWindow()->layer()->GetAnimator()); | 63 widget->GetNativeWindow()->layer()->GetAnimator()); |
| 74 scoped_setter.SetTweenType(gfx::Tween::EASE_IN); | 64 scoped_setter.SetTweenType(gfx::Tween::EASE_IN); |
| 75 scoped_setter.SetPreemptionStrategy( | 65 scoped_setter.SetPreemptionStrategy( |
| 76 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); | 66 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); |
| 77 scoped_setter.SetTransitionDuration( | 67 scoped_setter.SetTransitionDuration( |
| 78 base::TimeDelta::FromMilliseconds(kAnimationDurationMs)); | 68 base::TimeDelta::FromMilliseconds(kAnimationDurationMs)); |
| 79 widget->SetBounds(new_bounds_in_screen); | 69 widget->SetBounds(new_bounds_in_screen); |
| 80 } | 70 } |
| 81 | 71 |
| 82 // EdgePainter ---------------------------------------------------------------- | |
| 83 | |
| 84 // Paints the background of the phantom window for window snapping. | |
| 85 class EdgePainter : public views::Painter { | |
| 86 public: | |
| 87 EdgePainter(); | |
| 88 virtual ~EdgePainter(); | |
| 89 | |
| 90 // views::Painter: | |
| 91 virtual gfx::Size GetMinimumSize() const OVERRIDE; | |
| 92 virtual void Paint(gfx::Canvas* canvas, const gfx::Size& size) OVERRIDE; | |
| 93 | |
| 94 private: | |
| 95 DISALLOW_COPY_AND_ASSIGN(EdgePainter); | |
| 96 }; | |
| 97 | |
| 98 EdgePainter::EdgePainter() { | |
| 99 } | |
| 100 | |
| 101 EdgePainter::~EdgePainter() { | |
| 102 } | |
| 103 | |
| 104 gfx::Size EdgePainter::GetMinimumSize() const { | |
| 105 return gfx::Size(); | |
| 106 } | |
| 107 | |
| 108 void EdgePainter::Paint(gfx::Canvas* canvas, const gfx::Size& size) { | |
| 109 const int kInsetSize = 4; | |
| 110 int x = kInsetSize; | |
| 111 int y = kInsetSize; | |
| 112 int w = size.width() - kInsetSize * 2; | |
| 113 int h = size.height() - kInsetSize * 2; | |
| 114 bool inset = (w > 0 && h > 0); | |
| 115 if (!inset) { | |
| 116 x = 0; | |
| 117 y = 0; | |
| 118 w = size.width(); | |
| 119 h = size.height(); | |
| 120 } | |
| 121 SkPaint paint; | |
| 122 paint.setColor(SkColorSetARGB(100, 0, 0, 0)); | |
| 123 paint.setStyle(SkPaint::kFill_Style); | |
| 124 paint.setAntiAlias(true); | |
| 125 const int kRoundRectSize = 4; | |
| 126 canvas->sk_canvas()->drawRoundRect( | |
| 127 gfx::RectToSkRect(gfx::Rect(x, y, w, h)), | |
| 128 SkIntToScalar(kRoundRectSize), SkIntToScalar(kRoundRectSize), paint); | |
| 129 if (!inset) | |
| 130 return; | |
| 131 | |
| 132 paint.setColor(SkColorSetARGB(200, 255, 255, 255)); | |
| 133 paint.setStyle(SkPaint::kStroke_Style); | |
| 134 paint.setStrokeWidth(SkIntToScalar(2)); | |
| 135 canvas->sk_canvas()->drawRoundRect( | |
| 136 gfx::RectToSkRect(gfx::Rect(x, y, w, h)), SkIntToScalar(kRoundRectSize), | |
| 137 SkIntToScalar(kRoundRectSize), paint); | |
| 138 } | |
| 139 | |
| 140 } // namespace | 72 } // namespace |
| 141 | 73 |
| 142 // PhantomWindowController ---------------------------------------------------- | 74 // PhantomWindowController ---------------------------------------------------- |
| 143 | 75 |
| 144 PhantomWindowController::PhantomWindowController(aura::Window* window) | 76 PhantomWindowController::PhantomWindowController(aura::Window* window) |
| 145 : window_(window), | 77 : window_(window) { |
| 146 phantom_below_window_(NULL) { | |
| 147 } | 78 } |
| 148 | 79 |
| 149 PhantomWindowController::~PhantomWindowController() { | 80 PhantomWindowController::~PhantomWindowController() { |
| 150 } | 81 } |
| 151 | 82 |
| 152 void PhantomWindowController::Show(const gfx::Rect& bounds_in_screen) { | 83 void PhantomWindowController::Show(const gfx::Rect& bounds_in_screen) { |
| 153 if (switches::UseAlternateFrameCaptionButtonStyle()) | 84 gfx::Rect adjusted_bounds_in_screen = GetAdjustedBounds(bounds_in_screen); |
| 154 ShowAlternate(bounds_in_screen); | |
| 155 else | |
| 156 ShowLegacy(bounds_in_screen); | |
| 157 } | |
| 158 | |
| 159 void PhantomWindowController::ShowAlternate(const gfx::Rect& bounds_in_screen) { | |
| 160 gfx::Rect adjusted_bounds_in_screen = | |
| 161 GetAdjustedBoundsForAlternateStyle(bounds_in_screen); | |
| 162 if (adjusted_bounds_in_screen == target_bounds_in_screen_) | 85 if (adjusted_bounds_in_screen == target_bounds_in_screen_) |
| 163 return; | 86 return; |
| 164 target_bounds_in_screen_ = adjusted_bounds_in_screen; | 87 target_bounds_in_screen_ = adjusted_bounds_in_screen; |
| 165 | 88 |
| 166 gfx::Rect start_bounds_in_screen = target_bounds_in_screen_; | 89 gfx::Rect start_bounds_in_screen = target_bounds_in_screen_; |
| 167 int start_width = std::max( | 90 int start_width = std::max( |
| 168 kAlternateStyleMinSizeWithShadow, | 91 kMinSizeWithShadow, |
| 169 static_cast<int>( | 92 static_cast<int>(start_bounds_in_screen.width() * kStartBoundsRatio)); |
| 170 start_bounds_in_screen.width() * kAlternateStyleStartBoundsRatio)); | |
| 171 int start_height = std::max( | 93 int start_height = std::max( |
| 172 kAlternateStyleMinSizeWithShadow, | 94 kMinSizeWithShadow, |
| 173 static_cast<int>( | 95 static_cast<int>(start_bounds_in_screen.height() * kStartBoundsRatio)); |
| 174 start_bounds_in_screen.height() * kAlternateStyleStartBoundsRatio)); | |
| 175 start_bounds_in_screen.Inset( | 96 start_bounds_in_screen.Inset( |
| 176 floor((start_bounds_in_screen.width() - start_width) / 2.0f), | 97 floor((start_bounds_in_screen.width() - start_width) / 2.0f), |
| 177 floor((start_bounds_in_screen.height() - start_height) / 2.0f)); | 98 floor((start_bounds_in_screen.height() - start_height) / 2.0f)); |
| 178 phantom_widget_in_target_root_ = CreatePhantomWidget( | 99 phantom_widget_ = CreatePhantomWidget( |
| 179 wm::GetRootWindowMatching(target_bounds_in_screen_), | 100 wm::GetRootWindowMatching(target_bounds_in_screen_), |
| 180 start_bounds_in_screen); | 101 start_bounds_in_screen); |
| 181 | 102 |
| 182 AnimateToBounds(phantom_widget_in_target_root_.get(), | 103 AnimateToBounds(phantom_widget_.get(), target_bounds_in_screen_); |
| 183 target_bounds_in_screen_); | |
| 184 } | |
| 185 | |
| 186 void PhantomWindowController::ShowLegacy(const gfx::Rect& bounds_in_screen) { | |
| 187 if (bounds_in_screen == target_bounds_in_screen_) | |
| 188 return; | |
| 189 target_bounds_in_screen_ = bounds_in_screen; | |
| 190 | |
| 191 gfx::Rect start_bounds_in_screen; | |
| 192 if (!phantom_widget_in_target_root_) { | |
| 193 start_bounds_in_screen = window_->GetBoundsInScreen(); | |
| 194 } else { | |
| 195 start_bounds_in_screen = | |
| 196 phantom_widget_in_target_root_->GetWindowBoundsInScreen(); | |
| 197 } | |
| 198 | |
| 199 aura::Window* target_root = | |
| 200 wm::GetRootWindowMatching(target_bounds_in_screen_); | |
| 201 if (!phantom_widget_in_target_root_ || | |
| 202 phantom_widget_in_target_root_->GetNativeWindow()->GetRootWindow() != | |
| 203 target_root) { | |
| 204 phantom_widget_in_target_root_ = | |
| 205 CreatePhantomWidget(target_root, start_bounds_in_screen); | |
| 206 } | |
| 207 AnimateToBounds(phantom_widget_in_target_root_.get(), | |
| 208 target_bounds_in_screen_); | |
| 209 | |
| 210 // Create a secondary widget in a second screen if |start_bounds_in_screen| | |
| 211 // lies at least partially in another screen. This allows animations to start | |
| 212 // or restart in one root window and progress to another root. | |
| 213 aura::Window* start_root = wm::GetRootWindowMatching(start_bounds_in_screen); | |
| 214 if (start_root == target_root) { | |
| 215 aura::Window::Windows root_windows = Shell::GetAllRootWindows(); | |
| 216 for (size_t i = 0; i < root_windows.size(); ++i) { | |
| 217 if (root_windows[i] != target_root && | |
| 218 root_windows[i]->GetBoundsInScreen().Intersects( | |
| 219 start_bounds_in_screen)) { | |
| 220 start_root = root_windows[i]; | |
| 221 break; | |
| 222 } | |
| 223 } | |
| 224 } | |
| 225 if (start_root == target_root) { | |
| 226 phantom_widget_in_start_root_.reset(); | |
| 227 } else { | |
| 228 if (!phantom_widget_in_start_root_ || | |
| 229 phantom_widget_in_start_root_->GetNativeWindow()->GetRootWindow() != | |
| 230 start_root) { | |
| 231 phantom_widget_in_start_root_ = | |
| 232 CreatePhantomWidget(start_root, start_bounds_in_screen); | |
| 233 } | |
| 234 AnimateToBounds(phantom_widget_in_start_root_.get(), | |
| 235 target_bounds_in_screen_); | |
| 236 } | |
| 237 } | 104 } |
| 238 | 105 |
| 239 scoped_ptr<views::Widget> PhantomWindowController::CreatePhantomWidget( | 106 scoped_ptr<views::Widget> PhantomWindowController::CreatePhantomWidget( |
| 240 aura::Window* root_window, | 107 aura::Window* root_window, |
| 241 const gfx::Rect& bounds_in_screen) { | 108 const gfx::Rect& bounds_in_screen) { |
| 242 scoped_ptr<views::Widget> phantom_widget(new views::Widget); | 109 scoped_ptr<views::Widget> phantom_widget(new views::Widget); |
| 243 views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP); | 110 views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP); |
| 244 params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; | 111 params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; |
| 245 // PhantomWindowController is used by FrameMaximizeButton to highlight the | 112 // PhantomWindowController is used by FrameMaximizeButton to highlight the |
| 246 // launcher button. Put the phantom in the same window as the launcher so that | 113 // launcher button. Put the phantom in the same window as the launcher so that |
| 247 // the phantom is visible. | 114 // the phantom is visible. |
| 248 params.parent = Shell::GetContainer(root_window, | 115 params.parent = Shell::GetContainer(root_window, |
| 249 kShellWindowId_ShelfContainer); | 116 kShellWindowId_ShelfContainer); |
| 250 params.can_activate = false; | 117 params.can_activate = false; |
| 251 params.keep_on_top = true; | 118 params.keep_on_top = true; |
| 252 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; | 119 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; |
| 253 phantom_widget->set_focus_on_creation(false); | 120 phantom_widget->set_focus_on_creation(false); |
| 254 phantom_widget->Init(params); | 121 phantom_widget->Init(params); |
| 255 phantom_widget->SetVisibilityChangedAnimationsEnabled(false); | 122 phantom_widget->SetVisibilityChangedAnimationsEnabled(false); |
| 256 phantom_widget->GetNativeWindow()->SetName("PhantomWindow"); | 123 phantom_widget->GetNativeWindow()->SetName("PhantomWindow"); |
| 257 phantom_widget->GetNativeWindow()->set_id(kShellWindowId_PhantomWindow); | 124 phantom_widget->GetNativeWindow()->set_id(kShellWindowId_PhantomWindow); |
| 258 phantom_widget->SetBounds(bounds_in_screen); | 125 phantom_widget->SetBounds(bounds_in_screen); |
| 259 if (phantom_below_window_) | 126 phantom_widget->StackAbove(window_); |
| 260 phantom_widget->StackBelow(phantom_below_window_); | |
| 261 else | |
| 262 phantom_widget->StackAbove(window_); | |
| 263 | 127 |
| 264 views::Painter* background_painter = NULL; | 128 const int kImages[] = IMAGE_GRID(IDR_AURA_PHANTOM_WINDOW); |
| 265 if (switches::UseAlternateFrameCaptionButtonStyle()) { | 129 views::Painter* background_painter = |
| 266 const int kImages[] = IMAGE_GRID(IDR_AURA_PHANTOM_WINDOW); | 130 views::Painter::CreateImageGridPainter(kImages); |
| 267 background_painter = views::Painter::CreateImageGridPainter(kImages); | |
| 268 } else { | |
| 269 background_painter = new EdgePainter; | |
| 270 } | |
| 271 views::View* content_view = new views::View; | 131 views::View* content_view = new views::View; |
| 272 content_view->set_background( | 132 content_view->set_background( |
| 273 views::Background::CreateBackgroundPainter(true, background_painter)); | 133 views::Background::CreateBackgroundPainter(true, background_painter)); |
| 274 phantom_widget->SetContentsView(content_view); | 134 phantom_widget->SetContentsView(content_view); |
| 275 | 135 |
| 276 // Show the widget after all the setups. | 136 // Show the widget after all the setups. |
| 277 phantom_widget->Show(); | 137 phantom_widget->Show(); |
| 278 | 138 |
| 279 // Fade the window in. | 139 // Fade the window in. |
| 280 ui::Layer* widget_layer = phantom_widget->GetNativeWindow()->layer(); | 140 ui::Layer* widget_layer = phantom_widget->GetNativeWindow()->layer(); |
| 281 widget_layer->SetOpacity(0); | 141 widget_layer->SetOpacity(0); |
| 282 ui::ScopedLayerAnimationSettings scoped_setter(widget_layer->GetAnimator()); | 142 ui::ScopedLayerAnimationSettings scoped_setter(widget_layer->GetAnimator()); |
| 283 scoped_setter.SetTransitionDuration( | 143 scoped_setter.SetTransitionDuration( |
| 284 base::TimeDelta::FromMilliseconds(kAnimationDurationMs)); | 144 base::TimeDelta::FromMilliseconds(kAnimationDurationMs)); |
| 285 widget_layer->SetOpacity(1); | 145 widget_layer->SetOpacity(1); |
| 286 | 146 |
| 287 return phantom_widget.Pass(); | 147 return phantom_widget.Pass(); |
| 288 } | 148 } |
| 289 | 149 |
| 290 } // namespace ash | 150 } // namespace ash |
| OLD | NEW |