• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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|.
CreateCopyOfWindow(aura::Window * target_root,aura::Window * src_window,ui::Layer * recreated_layer)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 
CleanupWidgetAfterAnimationObserver(views::Widget * widget,scoped_ptr<ui::LayerTreeOwner> layer_owner)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 
TakeOwnershipOfWidget()125 void CleanupWidgetAfterAnimationObserver::TakeOwnershipOfWidget() {
126   owns_widget_ = true;
127   MaybeDestruct();
128 }
129 
OnLayerAnimationEnded(ui::LayerAnimationSequence * sequence)130 void CleanupWidgetAfterAnimationObserver::OnLayerAnimationEnded(
131     ui::LayerAnimationSequence* sequence) {
132   pending_animations_--;
133   MaybeDestruct();
134 }
135 
OnLayerAnimationAborted(ui::LayerAnimationSequence * sequence)136 void CleanupWidgetAfterAnimationObserver::OnLayerAnimationAborted(
137     ui::LayerAnimationSequence* sequence) {
138   pending_animations_--;
139   MaybeDestruct();
140 }
141 
OnLayerAnimationScheduled(ui::LayerAnimationSequence * sequence)142 void CleanupWidgetAfterAnimationObserver::OnLayerAnimationScheduled(
143     ui::LayerAnimationSequence* sequence) {
144   pending_animations_++;
145 }
146 
~CleanupWidgetAfterAnimationObserver()147 CleanupWidgetAfterAnimationObserver::~CleanupWidgetAfterAnimationObserver() {
148   widget_->GetNativeWindow()->layer()->GetAnimator()->RemoveObserver(this);
149   widget_->Close();
150   widget_ = NULL;
151 }
152 
MaybeDestruct()153 void CleanupWidgetAfterAnimationObserver::MaybeDestruct() {
154   if (pending_animations_ || !owns_widget_)
155     return;
156   delete this;
157 }
158 
ScopedWindowCopy(aura::Window * target_root,aura::Window * src_window)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 
~ScopedWindowCopy()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 
GetWindow()174 aura::Window* ScopedWindowCopy::GetWindow() {
175   return widget_->GetNativeWindow();
176 }
177 
178 }  // namespace ash
179