1 // Copyright 2013 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/overview/scoped_window_copy.h" 6 7 #include "ash/screen_util.h" 8 #include "ash/shell.h" 9 #include "ui/aura/client/aura_constants.h" 10 #include "ui/aura/client/screen_position_client.h" 11 #include "ui/aura/window.h" 12 #include "ui/aura/window_event_dispatcher.h" 13 #include "ui/compositor/layer_animation_observer.h" 14 #include "ui/compositor/layer_tree_owner.h" 15 #include "ui/gfx/display.h" 16 #include "ui/views/widget/widget.h" 17 #include "ui/wm/core/shadow_types.h" 18 #include "ui/wm/core/window_util.h" 19 20 namespace ash { 21 22 namespace { 23 24 // Creates a copy of |window| with |recreated_layer| in the |target_root|. 25 views::Widget* CreateCopyOfWindow(aura::Window* target_root, 26 aura::Window* src_window, 27 ui::Layer* recreated_layer) { 28 // Save and remove the transform from the layer to later reapply to both the 29 // source and newly created copy window. 30 gfx::Transform transform = recreated_layer->transform(); 31 recreated_layer->SetTransform(gfx::Transform()); 32 33 src_window->SetTransform(transform); 34 views::Widget* widget = new views::Widget; 35 views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP); 36 params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; 37 params.parent = src_window->parent(); 38 params.keep_on_top = true; 39 widget->set_focus_on_creation(false); 40 widget->Init(params); 41 widget->SetVisibilityChangedAnimationsEnabled(false); 42 std::string name = src_window->name() + " (Copy)"; 43 widget->GetNativeWindow()->SetName(name); 44 ::wm::SetShadowType(widget->GetNativeWindow(), 45 ::wm::SHADOW_TYPE_RECTANGULAR); 46 47 // Set the bounds in the target root window. 48 gfx::Display target_display = 49 Shell::GetScreen()->GetDisplayNearestWindow(target_root); 50 aura::client::ScreenPositionClient* screen_position_client = 51 aura::client::GetScreenPositionClient(src_window->GetRootWindow()); 52 if (screen_position_client && target_display.is_valid()) { 53 screen_position_client->SetBounds(widget->GetNativeWindow(), 54 src_window->GetBoundsInScreen(), target_display); 55 } else { 56 widget->SetBounds(src_window->GetBoundsInScreen()); 57 } 58 widget->StackAbove(src_window); 59 60 // Move the |recreated_layer| to the newly created window. 61 recreated_layer->set_delegate(src_window->layer()->delegate()); 62 gfx::Rect layer_bounds = recreated_layer->bounds(); 63 layer_bounds.set_origin(gfx::Point(0, 0)); 64 recreated_layer->SetBounds(layer_bounds); 65 recreated_layer->SetVisible(false); 66 recreated_layer->parent()->Remove(recreated_layer); 67 68 aura::Window* window = widget->GetNativeWindow(); 69 recreated_layer->SetVisible(true); 70 window->layer()->Add(recreated_layer); 71 window->layer()->StackAtTop(recreated_layer); 72 window->layer()->SetOpacity(1); 73 window->SetTransform(transform); 74 window->Show(); 75 return widget; 76 } 77 78 } // namespace 79 80 // An observer which closes the widget and deletes the layer after an 81 // animation finishes. 82 class CleanupWidgetAfterAnimationObserver : public ui::LayerAnimationObserver { 83 public: 84 CleanupWidgetAfterAnimationObserver( 85 views::Widget* widget, 86 scoped_ptr<ui::LayerTreeOwner> layer_owner); 87 88 // Takes ownership of the widget. At this point the class will delete itself 89 // and clean up the layer when there are no pending animations. 90 void TakeOwnershipOfWidget(); 91 92 // ui::LayerAnimationObserver: 93 virtual void OnLayerAnimationEnded( 94 ui::LayerAnimationSequence* sequence) OVERRIDE; 95 virtual void OnLayerAnimationAborted( 96 ui::LayerAnimationSequence* sequence) OVERRIDE; 97 virtual void OnLayerAnimationScheduled( 98 ui::LayerAnimationSequence* sequence) OVERRIDE; 99 100 private: 101 virtual ~CleanupWidgetAfterAnimationObserver(); 102 103 // If the necessary conditions have been satisfied to destruct this 104 // class, deletes itself and cleans up the widget and layer. 105 void MaybeDestruct(); 106 107 views::Widget* widget_; 108 scoped_ptr<ui::LayerTreeOwner> layer_owner_; 109 bool owns_widget_; 110 int pending_animations_; 111 112 DISALLOW_COPY_AND_ASSIGN(CleanupWidgetAfterAnimationObserver); 113 }; 114 115 CleanupWidgetAfterAnimationObserver::CleanupWidgetAfterAnimationObserver( 116 views::Widget* widget, 117 scoped_ptr<ui::LayerTreeOwner> layer_owner) 118 : widget_(widget), 119 layer_owner_(layer_owner.Pass()), 120 owns_widget_(false), 121 pending_animations_(0) { 122 widget_->GetNativeWindow()->layer()->GetAnimator()->AddObserver(this); 123 } 124 125 void CleanupWidgetAfterAnimationObserver::TakeOwnershipOfWidget() { 126 owns_widget_ = true; 127 MaybeDestruct(); 128 } 129 130 void CleanupWidgetAfterAnimationObserver::OnLayerAnimationEnded( 131 ui::LayerAnimationSequence* sequence) { 132 pending_animations_--; 133 MaybeDestruct(); 134 } 135 136 void CleanupWidgetAfterAnimationObserver::OnLayerAnimationAborted( 137 ui::LayerAnimationSequence* sequence) { 138 pending_animations_--; 139 MaybeDestruct(); 140 } 141 142 void CleanupWidgetAfterAnimationObserver::OnLayerAnimationScheduled( 143 ui::LayerAnimationSequence* sequence) { 144 pending_animations_++; 145 } 146 147 CleanupWidgetAfterAnimationObserver::~CleanupWidgetAfterAnimationObserver() { 148 widget_->GetNativeWindow()->layer()->GetAnimator()->RemoveObserver(this); 149 widget_->Close(); 150 widget_ = NULL; 151 } 152 153 void CleanupWidgetAfterAnimationObserver::MaybeDestruct() { 154 if (pending_animations_ || !owns_widget_) 155 return; 156 delete this; 157 } 158 159 ScopedWindowCopy::ScopedWindowCopy(aura::Window* target_root, 160 aura::Window* src_window) { 161 scoped_ptr<ui::LayerTreeOwner> layer_owner = 162 ::wm::RecreateLayers(src_window); 163 widget_ = CreateCopyOfWindow(target_root, src_window, layer_owner->root()); 164 cleanup_observer_ = 165 new CleanupWidgetAfterAnimationObserver(widget_, layer_owner.Pass()); 166 } 167 168 ScopedWindowCopy::~ScopedWindowCopy() { 169 // The cleanup observer will delete itself and the window when any pending 170 // animations have completed. 171 cleanup_observer_->TakeOwnershipOfWidget(); 172 } 173 174 aura::Window* ScopedWindowCopy::GetWindow() { 175 return widget_->GetNativeWindow(); 176 } 177 178 } // namespace ash 179