Home | History | Annotate | Download | only in overview
      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