diff options
Diffstat (limited to 'chromium/ash/wm/overview/scoped_window_copy.cc')
-rw-r--r-- | chromium/ash/wm/overview/scoped_window_copy.cc | 178 |
1 files changed, 178 insertions, 0 deletions
diff --git a/chromium/ash/wm/overview/scoped_window_copy.cc b/chromium/ash/wm/overview/scoped_window_copy.cc new file mode 100644 index 00000000000..660b2845964 --- /dev/null +++ b/chromium/ash/wm/overview/scoped_window_copy.cc @@ -0,0 +1,178 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/wm/overview/scoped_window_copy.h" + +#include "ash/screen_ash.h" +#include "ash/shell.h" +#include "ui/aura/client/aura_constants.h" +#include "ui/aura/client/screen_position_client.h" +#include "ui/aura/root_window.h" +#include "ui/aura/window.h" +#include "ui/compositor/layer_animation_observer.h" +#include "ui/gfx/display.h" +#include "ui/views/corewm/shadow_types.h" +#include "ui/views/corewm/window_util.h" +#include "ui/views/widget/widget.h" + +namespace ash { + +namespace { + +// Creates a copy of |window| with |recreated_layer| in the |target_root|. +views::Widget* CreateCopyOfWindow(aura::Window* target_root, + aura::Window* src_window, + ui::Layer* recreated_layer) { + // Save and remove the transform from the layer to later reapply to both the + // source and newly created copy window. + gfx::Transform transform = recreated_layer->transform(); + recreated_layer->SetTransform(gfx::Transform()); + + src_window->SetTransform(transform); + views::Widget* widget = new views::Widget; + views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP); + params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; + params.parent = src_window->parent(); + params.can_activate = false; + params.keep_on_top = true; + widget->set_focus_on_creation(false); + widget->Init(params); + widget->SetVisibilityChangedAnimationsEnabled(false); + std::string name = src_window->name() + " (Copy)"; + widget->GetNativeWindow()->SetName(name); + views::corewm::SetShadowType(widget->GetNativeWindow(), + views::corewm::SHADOW_TYPE_RECTANGULAR); + + // Set the bounds in the target root window. + gfx::Display target_display = + Shell::GetScreen()->GetDisplayNearestWindow(target_root); + aura::client::ScreenPositionClient* screen_position_client = + aura::client::GetScreenPositionClient(src_window->GetRootWindow()); + if (screen_position_client && target_display.is_valid()) { + screen_position_client->SetBounds(widget->GetNativeWindow(), + src_window->GetBoundsInScreen(), target_display); + } else { + widget->SetBounds(src_window->GetBoundsInScreen()); + } + widget->StackAbove(src_window); + + // Move the |recreated_layer| to the newly created window. + recreated_layer->set_delegate(src_window->layer()->delegate()); + gfx::Rect layer_bounds = recreated_layer->bounds(); + layer_bounds.set_origin(gfx::Point(0, 0)); + recreated_layer->SetBounds(layer_bounds); + recreated_layer->SetVisible(false); + recreated_layer->parent()->Remove(recreated_layer); + + aura::Window* window = widget->GetNativeWindow(); + recreated_layer->SetVisible(true); + window->layer()->Add(recreated_layer); + window->layer()->StackAtTop(recreated_layer); + window->layer()->SetOpacity(1); + window->SetTransform(transform); + window->Show(); + return widget; +} + +} // namespace + +// An observer which closes the widget and deletes the layer after an +// animation finishes. +class CleanupWidgetAfterAnimationObserver : public ui::LayerAnimationObserver { + public: + CleanupWidgetAfterAnimationObserver(views::Widget* widget, ui::Layer* layer); + + // Takes ownership of the widget. At this point the class will delete itself + // and clean up the layer when there are no pending animations. + void TakeOwnershipOfWidget(); + + // ui::LayerAnimationObserver: + virtual void OnLayerAnimationEnded( + ui::LayerAnimationSequence* sequence) OVERRIDE; + virtual void OnLayerAnimationAborted( + ui::LayerAnimationSequence* sequence) OVERRIDE; + virtual void OnLayerAnimationScheduled( + ui::LayerAnimationSequence* sequence) OVERRIDE; + + private: + virtual ~CleanupWidgetAfterAnimationObserver(); + + // If the necessary conditions have been satisfied to destruct this + // class, deletes itself and cleans up the widget and layer. + void MaybeDestruct(); + + views::Widget* widget_; + ui::Layer* layer_; + bool owns_widget_; + int pending_animations_; + + DISALLOW_COPY_AND_ASSIGN(CleanupWidgetAfterAnimationObserver); +}; + +CleanupWidgetAfterAnimationObserver::CleanupWidgetAfterAnimationObserver( + views::Widget* widget, + ui::Layer* layer) + : widget_(widget), + layer_(layer), + owns_widget_(false), + pending_animations_(0) { + widget_->GetNativeWindow()->layer()->GetAnimator()->AddObserver(this); +} + +void CleanupWidgetAfterAnimationObserver::TakeOwnershipOfWidget() { + owns_widget_ = true; + MaybeDestruct(); +} + +void CleanupWidgetAfterAnimationObserver::OnLayerAnimationEnded( + ui::LayerAnimationSequence* sequence) { + pending_animations_--; + MaybeDestruct(); +} + +void CleanupWidgetAfterAnimationObserver::OnLayerAnimationAborted( + ui::LayerAnimationSequence* sequence) { + pending_animations_--; + MaybeDestruct(); +} + +void CleanupWidgetAfterAnimationObserver::OnLayerAnimationScheduled( + ui::LayerAnimationSequence* sequence) { + pending_animations_++; +} + +CleanupWidgetAfterAnimationObserver::~CleanupWidgetAfterAnimationObserver() { + widget_->GetNativeWindow()->layer()->GetAnimator()->RemoveObserver(this); + widget_->Close(); + widget_ = NULL; + if (layer_) { + views::corewm::DeepDeleteLayers(layer_); + layer_ = NULL; + } +} + +void CleanupWidgetAfterAnimationObserver::MaybeDestruct() { + if (pending_animations_ || !owns_widget_) + return; + delete this; +} + +ScopedWindowCopy::ScopedWindowCopy(aura::Window* target_root, + aura::Window* src_window) { + layer_ = views::corewm::RecreateWindowLayers(src_window, true); + widget_ = CreateCopyOfWindow(target_root, src_window, layer_); + cleanup_observer_ = new CleanupWidgetAfterAnimationObserver(widget_, layer_); +} + +ScopedWindowCopy::~ScopedWindowCopy() { + // The cleanup observer will delete itself and the window when any pending + // animations have completed. + cleanup_observer_->TakeOwnershipOfWidget(); +} + +aura::Window* ScopedWindowCopy::GetWindow() { + return widget_->GetNativeWindow(); +} + +} // namespace ash |