Index: ash/display/output_configurator_animation.cc |
diff --git a/ash/display/output_configurator_animation.cc b/ash/display/output_configurator_animation.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..bc175b37e306681668e5a42ccd5d595c490d5518 |
--- /dev/null |
+++ b/ash/display/output_configurator_animation.cc |
@@ -0,0 +1,160 @@ |
+// Copyright (c) 2012 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/display/output_configurator_animation.h" |
+ |
+#include "ash/shell.h" |
+#include "ash/shell_window_ids.h" |
+#include "base/bind.h" |
+#include "base/stl_util.h" |
+#include "base/time.h" |
+#include "ui/aura/root_window.h" |
+#include "ui/aura/window.h" |
+#include "ui/compositor/layer.h" |
+#include "ui/compositor/layer_animation_observer.h" |
+#include "ui/compositor/layer_animation_sequence.h" |
+#include "ui/compositor/layer_animator.h" |
+#include "ui/compositor/scoped_layer_animation_settings.h" |
+ |
+namespace ash { |
+namespace internal { |
+namespace { |
+ |
+const int kFadingAnimationDurationInMS = 200; |
+ |
+// CallbackRunningObserver accepts several layer animations and |
+// runs the specified |callback| when all of the animations have finished. |
+class CallbackRunningObserver { |
+ public: |
+ CallbackRunningObserver(base::Closure callback) |
+ : completed_counter_(0), |
+ callback_(callback) {} |
+ |
+ void AddNewAnimator(ui::ScopedLayerAnimationSettings *settings) { |
+ Observer* observer = new Observer(this); |
+ settings->AddObserver(observer); |
+ observer_list_.push_back(observer); |
+ } |
+ |
+ private: |
+ void OnSingleTaskCompleted() { |
+ completed_counter_++; |
+ if (completed_counter_ >= observer_list_.size()) { |
+ callback_.Run(); |
+ MessageLoopForUI::current()->DeleteSoon(FROM_HERE, this); |
+ } |
+ } |
+ |
+ // The actual observer to listen each animation completion. |
+ class Observer : public ui::ImplicitAnimationObserver { |
+ public: |
+ Observer(CallbackRunningObserver* observer) |
+ : observer_(observer) {} |
+ |
+ virtual void OnImplicitAnimationsCompleted() OVERRIDE { |
+ observer_->OnSingleTaskCompleted(); |
+ } |
+ |
+ private: |
+ CallbackRunningObserver* observer_; |
+ }; |
+ |
+ size_t completed_counter_; |
+ ScopedVector<Observer> observer_list_; |
+ base::Closure callback_; |
+}; |
+ |
+} // namespace |
+ |
+OutputConfiguratorAnimation::OutputConfiguratorAnimation() { |
+} |
+ |
+OutputConfiguratorAnimation::~OutputConfiguratorAnimation() { |
+ ClearHidingLayers(); |
+} |
+ |
+void OutputConfiguratorAnimation::WillDisplayModeChange( |
+ base::Closure callback) { |
+ CallbackRunningObserver *observer = new CallbackRunningObserver(callback); |
+ ClearHidingLayers(); |
+ |
+ // Make the fade-out animation for all root windows. Instead of actually |
+ // hiding the root windows, we put a black layer over a root window for |
+ // safety. |
+ Shell::RootWindowList root_windows = |
+ Shell::GetInstance()->GetAllRootWindows(); |
+ for (Shell::RootWindowList::const_iterator it = root_windows.begin(); |
+ it != root_windows.end(); ++it) { |
+ aura::RootWindow* root_window = *it; |
+ ui::Layer* hiding_layer = new ui::Layer(ui::LAYER_SOLID_COLOR); |
+ hiding_layer->SetColor(SK_ColorBLACK); |
+ hiding_layer->SetBounds(root_window->bounds()); |
+ ui::Layer* parent = ash::Shell::GetContainer( |
+ root_window, |
+ ash::internal::kShellWindowId_OverlayContainer)->layer(); |
+ parent->Add(hiding_layer); |
+ |
+ hiding_layer->SetOpacity(0.0); |
+ |
+ ui::ScopedLayerAnimationSettings settings(hiding_layer->GetAnimator()); |
+ settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds( |
+ kFadingAnimationDurationInMS)); |
+ observer->AddNewAnimator(&settings); |
+ hiding_layer->SetOpacity(1.0f); |
+ hiding_layer->SetVisible(true); |
+ hiding_layers_[root_window] = hiding_layer; |
+ } |
+} |
+ |
+void OutputConfiguratorAnimation::OnDisplayModeChanged() { |
+ // We want to make sure clearing all of hiding layers after the animation |
+ // finished. |
+ CallbackRunningObserver *observer = new CallbackRunningObserver( |
+ base::Bind(&OutputConfiguratorAnimation::ClearHidingLayers, |
+ base::Unretained(this))); |
+ |
+ // Schedules the fade-in effect for all root windows. Because we put the |
+ // black layers for fade-out, here we actually turn those black layers |
+ // invisible. |
+ Shell::RootWindowList root_windows = |
+ Shell::GetInstance()->GetAllRootWindows(); |
+ for (Shell::RootWindowList::const_iterator it = root_windows.begin(); |
+ it != root_windows.end(); ++it) { |
+ aura::RootWindow* root_window = *it; |
+ ui::Layer* hiding_layer = NULL; |
+ if (hiding_layers_.find(root_window) == hiding_layers_.end()) { |
+ // In case of the transition from mirroring->non-mirroring, new root |
+ // windows appear and we do not have the black layers for them. Thus |
+ // we need to create the layer and make it visible. |
+ hiding_layer = new ui::Layer(ui::LAYER_SOLID_COLOR); |
+ hiding_layer->SetColor(SK_ColorBLACK); |
+ hiding_layer->SetBounds(root_window->bounds()); |
+ ui::Layer* parent = ash::Shell::GetContainer( |
+ root_window, |
+ ash::internal::kShellWindowId_OverlayContainer)->layer(); |
+ parent->Add(hiding_layer); |
+ hiding_layer->SetOpacity(1.0f); |
+ hiding_layer->SetVisible(true); |
+ hiding_layers_[root_window] = hiding_layer; |
+ } else { |
+ hiding_layer = hiding_layers_[root_window]; |
+ } |
+ |
+ ui::ScopedLayerAnimationSettings settings(hiding_layer->GetAnimator()); |
+ settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds( |
+ kFadingAnimationDurationInMS)); |
+ observer->AddNewAnimator(&settings); |
+ hiding_layer->SetOpacity(0.0f); |
+ hiding_layer->SetVisible(false); |
+ } |
+} |
+ |
+void OutputConfiguratorAnimation::ClearHidingLayers() { |
+ STLDeleteContainerPairSecondPointers( |
+ hiding_layers_.begin(), hiding_layers_.end()); |
+ hiding_layers_.clear(); |
+} |
+ |
+} // namespace internal |
+} // namespace ash |