summaryrefslogtreecommitdiff
path: root/chromium/ash/wm/overview/scoped_window_copy.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/ash/wm/overview/scoped_window_copy.cc')
-rw-r--r--chromium/ash/wm/overview/scoped_window_copy.cc178
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