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 3 // found in the LICENSE file. 4 5 #include "ash/wm/workspace/phantom_window_controller.h" 6 7 #include "ash/shell.h" 8 #include "ash/shell_window_ids.h" 9 #include "ash/wm/coordinate_conversion.h" 10 #include "third_party/skia/include/core/SkCanvas.h" 11 #include "ui/aura/window.h" 12 #include "ui/base/animation/slide_animation.h" 13 #include "ui/compositor/layer.h" 14 #include "ui/compositor/scoped_layer_animation_settings.h" 15 #include "ui/gfx/canvas.h" 16 #include "ui/gfx/skia_util.h" 17 #include "ui/views/painter.h" 18 #include "ui/views/view.h" 19 #include "ui/views/widget/widget.h" 20 21 22 namespace ash { 23 namespace internal { 24 25 // EdgePainter ---------------------------------------------------------------- 26 27 namespace { 28 29 // Paints the background of the phantom window for window snapping. 30 class EdgePainter : public views::Painter { 31 public: 32 EdgePainter(); 33 virtual ~EdgePainter(); 34 35 // views::Painter: 36 virtual gfx::Size GetMinimumSize() const OVERRIDE; 37 virtual void Paint(gfx::Canvas* canvas, const gfx::Size& size) OVERRIDE; 38 39 private: 40 DISALLOW_COPY_AND_ASSIGN(EdgePainter); 41 }; 42 43 } // namespace 44 45 46 EdgePainter::EdgePainter() { 47 } 48 49 EdgePainter::~EdgePainter() { 50 } 51 52 gfx::Size EdgePainter::GetMinimumSize() const { 53 return gfx::Size(); 54 } 55 56 void EdgePainter::Paint(gfx::Canvas* canvas, const gfx::Size& size) { 57 const int kInsetSize = 4; 58 int x = kInsetSize; 59 int y = kInsetSize; 60 int w = size.width() - kInsetSize * 2; 61 int h = size.height() - kInsetSize * 2; 62 bool inset = (w > 0 && h > 0); 63 if (!inset) { 64 x = 0; 65 y = 0; 66 w = size.width(); 67 h = size.height(); 68 } 69 SkPaint paint; 70 paint.setColor(SkColorSetARGB(100, 0, 0, 0)); 71 paint.setStyle(SkPaint::kFill_Style); 72 paint.setAntiAlias(true); 73 const int kRoundRectSize = 4; 74 canvas->sk_canvas()->drawRoundRect( 75 gfx::RectToSkRect(gfx::Rect(x, y, w, h)), 76 SkIntToScalar(kRoundRectSize), SkIntToScalar(kRoundRectSize), paint); 77 if (!inset) 78 return; 79 80 paint.setColor(SkColorSetARGB(200, 255, 255, 255)); 81 paint.setStyle(SkPaint::kStroke_Style); 82 paint.setStrokeWidth(SkIntToScalar(2)); 83 canvas->sk_canvas()->drawRoundRect( 84 gfx::RectToSkRect(gfx::Rect(x, y, w, h)), SkIntToScalar(kRoundRectSize), 85 SkIntToScalar(kRoundRectSize), paint); 86 } 87 88 89 // PhantomWindowController ---------------------------------------------------- 90 91 PhantomWindowController::PhantomWindowController(aura::Window* window) 92 : window_(window), 93 phantom_below_window_(NULL), 94 phantom_widget_(NULL) { 95 } 96 97 PhantomWindowController::~PhantomWindowController() { 98 Hide(); 99 } 100 101 void PhantomWindowController::Show(const gfx::Rect& bounds) { 102 if (bounds == bounds_) 103 return; 104 bounds_ = bounds; 105 if (!phantom_widget_) { 106 // Show the phantom at the bounds of the window. We'll animate to the target 107 // bounds. 108 start_bounds_ = window_->GetBoundsInScreen(); 109 CreatePhantomWidget(start_bounds_); 110 } else { 111 start_bounds_ = phantom_widget_->GetWindowBoundsInScreen(); 112 } 113 animation_.reset(new ui::SlideAnimation(this)); 114 animation_->SetTweenType(ui::Tween::EASE_IN); 115 const int kAnimationDurationMS = 200; 116 animation_->SetSlideDuration(kAnimationDurationMS); 117 animation_->Show(); 118 } 119 120 void PhantomWindowController::Hide() { 121 if (phantom_widget_) 122 phantom_widget_->Close(); 123 phantom_widget_ = NULL; 124 } 125 126 bool PhantomWindowController::IsShowing() const { 127 return phantom_widget_ != NULL; 128 } 129 130 void PhantomWindowController::AnimationProgressed( 131 const ui::Animation* animation) { 132 phantom_widget_->SetBounds( 133 animation->CurrentValueBetween(start_bounds_, bounds_)); 134 } 135 136 void PhantomWindowController::CreatePhantomWidget(const gfx::Rect& bounds) { 137 DCHECK(!phantom_widget_); 138 phantom_widget_ = new views::Widget; 139 views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP); 140 params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; 141 // PhantomWindowController is used by FrameMaximizeButton to highlight the 142 // launcher button. Put the phantom in the same window as the launcher so that 143 // the phantom is visible. 144 params.parent = Shell::GetContainer(wm::GetRootWindowMatching(bounds), 145 kShellWindowId_ShelfContainer); 146 params.can_activate = false; 147 params.keep_on_top = true; 148 phantom_widget_->set_focus_on_creation(false); 149 phantom_widget_->Init(params); 150 phantom_widget_->SetVisibilityChangedAnimationsEnabled(false); 151 phantom_widget_->GetNativeWindow()->SetName("PhantomWindow"); 152 phantom_widget_->GetNativeWindow()->set_id(kShellWindowId_PhantomWindow); 153 views::View* content_view = new views::View; 154 content_view->set_background( 155 views::Background::CreateBackgroundPainter(true, new EdgePainter)); 156 phantom_widget_->SetContentsView(content_view); 157 phantom_widget_->SetBounds(bounds); 158 if (phantom_below_window_) 159 phantom_widget_->StackBelow(phantom_below_window_); 160 else 161 phantom_widget_->StackAbove(window_); 162 163 // Show the widget after all the setups. 164 phantom_widget_->Show(); 165 166 // Fade the window in. 167 ui::Layer* widget_layer = phantom_widget_->GetNativeWindow()->layer(); 168 widget_layer->SetOpacity(0); 169 ui::ScopedLayerAnimationSettings scoped_setter(widget_layer->GetAnimator()); 170 widget_layer->SetOpacity(1); 171 } 172 173 } // namespace internal 174 } // namespace ash 175