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_ash.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/root_window.h"
     12 #include "ui/aura/window.h"
     13 #include "ui/compositor/layer_animation_observer.h"
     14 #include "ui/gfx/display.h"
     15 #include "ui/views/corewm/shadow_types.h"
     16 #include "ui/views/corewm/window_util.h"
     17 #include "ui/views/widget/widget.h"
     18 
     19 namespace ash {
     20 
     21 namespace {
     22 
     23 // Creates a copy of |window| with |recreated_layer| in the |target_root|.
     24 views::Widget* CreateCopyOfWindow(aura::Window* target_root,
     25                                   aura::Window* src_window,
     26                                   ui::Layer* recreated_layer) {
     27   // Save and remove the transform from the layer to later reapply to both the
     28   // source and newly created copy window.
     29   gfx::Transform transform = recreated_layer->transform();
     30   recreated_layer->SetTransform(gfx::Transform());
     31 
     32   src_window->SetTransform(transform);
     33   views::Widget* widget = new views::Widget;
     34   views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP);
     35   params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
     36   params.parent = src_window->parent();
     37   params.can_activate = false;
     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   views::corewm::SetShadowType(widget->GetNativeWindow(),
     45                                views::corewm::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(views::Widget* widget, ui::Layer* layer);
     85 
     86   // Takes ownership of the widget. At this point the class will delete itself
     87   // and clean up the layer when there are no pending animations.
     88   void TakeOwnershipOfWidget();
     89 
     90   // ui::LayerAnimationObserver:
     91   virtual void OnLayerAnimationEnded(
     92       ui::LayerAnimationSequence* sequence) OVERRIDE;
     93   virtual void OnLayerAnimationAborted(
     94       ui::LayerAnimationSequence* sequence) OVERRIDE;
     95   virtual void OnLayerAnimationScheduled(
     96       ui::LayerAnimationSequence* sequence) OVERRIDE;
     97 
     98  private:
     99   virtual ~CleanupWidgetAfterAnimationObserver();
    100 
    101   // If the necessary conditions have been satisfied to destruct this
    102   // class, deletes itself and cleans up the widget and layer.
    103   void MaybeDestruct();
    104 
    105   views::Widget* widget_;
    106   ui::Layer* layer_;
    107   bool owns_widget_;
    108   int pending_animations_;
    109 
    110   DISALLOW_COPY_AND_ASSIGN(CleanupWidgetAfterAnimationObserver);
    111 };
    112 
    113 CleanupWidgetAfterAnimationObserver::CleanupWidgetAfterAnimationObserver(
    114         views::Widget* widget,
    115         ui::Layer* layer)
    116     : widget_(widget),
    117       layer_(layer),
    118       owns_widget_(false),
    119       pending_animations_(0) {
    120   widget_->GetNativeWindow()->layer()->GetAnimator()->AddObserver(this);
    121 }
    122 
    123 void CleanupWidgetAfterAnimationObserver::TakeOwnershipOfWidget() {
    124   owns_widget_ = true;
    125   MaybeDestruct();
    126 }
    127 
    128 void CleanupWidgetAfterAnimationObserver::OnLayerAnimationEnded(
    129     ui::LayerAnimationSequence* sequence) {
    130   pending_animations_--;
    131   MaybeDestruct();
    132 }
    133 
    134 void CleanupWidgetAfterAnimationObserver::OnLayerAnimationAborted(
    135     ui::LayerAnimationSequence* sequence) {
    136   pending_animations_--;
    137   MaybeDestruct();
    138 }
    139 
    140 void CleanupWidgetAfterAnimationObserver::OnLayerAnimationScheduled(
    141     ui::LayerAnimationSequence* sequence) {
    142   pending_animations_++;
    143 }
    144 
    145 CleanupWidgetAfterAnimationObserver::~CleanupWidgetAfterAnimationObserver() {
    146   widget_->GetNativeWindow()->layer()->GetAnimator()->RemoveObserver(this);
    147   widget_->Close();
    148   widget_ = NULL;
    149   if (layer_) {
    150     views::corewm::DeepDeleteLayers(layer_);
    151     layer_ = NULL;
    152   }
    153 }
    154 
    155 void CleanupWidgetAfterAnimationObserver::MaybeDestruct() {
    156   if (pending_animations_ || !owns_widget_)
    157     return;
    158   delete this;
    159 }
    160 
    161 ScopedWindowCopy::ScopedWindowCopy(aura::Window* target_root,
    162                                    aura::Window* src_window) {
    163   layer_ = views::corewm::RecreateWindowLayers(src_window, true);
    164   widget_ = CreateCopyOfWindow(target_root, src_window, layer_);
    165   cleanup_observer_ = new CleanupWidgetAfterAnimationObserver(widget_, layer_);
    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