| // 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 "ui/wm/core/window_animations.h" |
| |
| #include <math.h> |
| |
| #include <algorithm> |
| #include <vector> |
| |
| #include "base/command_line.h" |
| #include "base/compiler_specific.h" |
| #include "base/logging.h" |
| #include "base/message_loop/message_loop.h" |
| #include "base/stl_util.h" |
| #include "base/time/time.h" |
| #include "ui/aura/client/aura_constants.h" |
| #include "ui/aura/window.h" |
| #include "ui/aura/window_delegate.h" |
| #include "ui/aura/window_observer.h" |
| #include "ui/aura/window_property.h" |
| #include "ui/compositor/compositor_observer.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/layer_tree_owner.h" |
| #include "ui/compositor/scoped_animation_duration_scale_mode.h" |
| #include "ui/compositor/scoped_layer_animation_settings.h" |
| #include "ui/gfx/animation/animation.h" |
| #include "ui/gfx/geometry/rect_conversions.h" |
| #include "ui/gfx/geometry/vector2d.h" |
| #include "ui/gfx/geometry/vector3d_f.h" |
| #include "ui/gfx/interpolated_transform.h" |
| #include "ui/gfx/screen.h" |
| #include "ui/wm/core/window_util.h" |
| #include "ui/wm/core/wm_core_switches.h" |
| #include "ui/wm/public/animation_host.h" |
| |
| DECLARE_WINDOW_PROPERTY_TYPE(wm::WindowVisibilityAnimationType) |
| DECLARE_WINDOW_PROPERTY_TYPE(wm::WindowVisibilityAnimationTransition) |
| DECLARE_WINDOW_PROPERTY_TYPE(float) |
| |
| namespace wm { |
| namespace { |
| const float kWindowAnimation_Vertical_TranslateY = 15.f; |
| |
| // A base class for hiding animation observer which has two roles: |
| // 1) Notifies AnimationHost at the end of hiding animation. |
| // 2) Detaches the window's layers for hiding animation and deletes |
| // them upon completion of the animation. This is necessary to a) |
| // ensure that the animation continues in the event of the window being |
| // deleted, and b) to ensure that the animation is visible even if the |
| // window gets restacked below other windows when focus or activation |
| // changes. |
| // The subclass will determine when the animation is completed. |
| class HidingWindowAnimationObserverBase : public aura::WindowObserver { |
| public: |
| explicit HidingWindowAnimationObserverBase(aura::Window* window) |
| : window_(window) { |
| window_->AddObserver(this); |
| } |
| ~HidingWindowAnimationObserverBase() override { |
| if (window_) |
| window_->RemoveObserver(this); |
| } |
| |
| // aura::WindowObserver: |
| void OnWindowDestroying(aura::Window* window) override { |
| DCHECK_EQ(window, window_); |
| WindowInvalid(); |
| } |
| |
| void OnWindowDestroyed(aura::Window* window) override { |
| DCHECK_EQ(window, window_); |
| WindowInvalid(); |
| } |
| |
| // Detach the current layers and create new layers for |window_|. |
| // Stack the original layers above |window_| and its transient |
| // children. If the window has transient children, the original |
| // layers will be moved above the top most transient child so that |
| // activation change does not put the window above the animating |
| // layer. |
| void DetachAndRecreateLayers() { |
| layer_owner_ = RecreateLayers(window_); |
| if (window_->parent()) { |
| const aura::Window::Windows& transient_children = |
| GetTransientChildren(window_); |
| aura::Window::Windows::const_iterator iter = |
| std::find(window_->parent()->children().begin(), |
| window_->parent()->children().end(), |
| window_); |
| DCHECK(iter != window_->parent()->children().end()); |
| aura::Window* topmost_transient_child = NULL; |
| for (++iter; iter != window_->parent()->children().end(); ++iter) { |
| if (std::find(transient_children.begin(), |
| transient_children.end(), |
| *iter) != transient_children.end()) { |
| topmost_transient_child = *iter; |
| } |
| } |
| if (topmost_transient_child) { |
| window_->parent()->layer()->StackAbove( |
| layer_owner_->root(), topmost_transient_child->layer()); |
| } |
| } |
| } |
| |
| protected: |
| // Invoked when the hiding animation is completed. It will delete |
| // 'this', and no operation should be made on this object after this |
| // point. |
| void OnAnimationCompleted() { |
| // Window may have been destroyed by this point. |
| if (window_) { |
| aura::client::AnimationHost* animation_host = |
| aura::client::GetAnimationHost(window_); |
| if (animation_host) |
| animation_host->OnWindowHidingAnimationCompleted(); |
| window_->RemoveObserver(this); |
| } |
| delete this; |
| } |
| |
| private: |
| // Invoked when the window is destroyed (or destroying). |
| void WindowInvalid() { |
| layer_owner_->root()->SuppressPaint(); |
| |
| window_->RemoveObserver(this); |
| window_ = NULL; |
| } |
| |
| aura::Window* window_; |
| |
| // The owner of detached layers. |
| scoped_ptr<ui::LayerTreeOwner> layer_owner_; |
| |
| DISALLOW_COPY_AND_ASSIGN(HidingWindowAnimationObserverBase); |
| }; |
| |
| } // namespace |
| |
| DEFINE_WINDOW_PROPERTY_KEY(int, |
| kWindowVisibilityAnimationTypeKey, |
| WINDOW_VISIBILITY_ANIMATION_TYPE_DEFAULT); |
| DEFINE_WINDOW_PROPERTY_KEY(int, kWindowVisibilityAnimationDurationKey, 0); |
| DEFINE_WINDOW_PROPERTY_KEY(WindowVisibilityAnimationTransition, |
| kWindowVisibilityAnimationTransitionKey, |
| ANIMATE_BOTH); |
| DEFINE_WINDOW_PROPERTY_KEY(float, |
| kWindowVisibilityAnimationVerticalPositionKey, |
| kWindowAnimation_Vertical_TranslateY); |
| |
| // A HidingWindowAnimationObserver that deletes observer and detached |
| // layers upon the completion of the implicit animation. |
| class ImplicitHidingWindowAnimationObserver |
| : public HidingWindowAnimationObserverBase, |
| public ui::ImplicitAnimationObserver { |
| public: |
| ImplicitHidingWindowAnimationObserver( |
| aura::Window* window, |
| ui::ScopedLayerAnimationSettings* settings); |
| ~ImplicitHidingWindowAnimationObserver() override {} |
| |
| // ui::ImplicitAnimationObserver: |
| void OnImplicitAnimationsCompleted() override; |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(ImplicitHidingWindowAnimationObserver); |
| }; |
| |
| namespace { |
| |
| const int kDefaultAnimationDurationForMenuMS = 150; |
| |
| const float kWindowAnimation_HideOpacity = 0.f; |
| const float kWindowAnimation_ShowOpacity = 1.f; |
| const float kWindowAnimation_TranslateFactor = 0.5f; |
| const float kWindowAnimation_ScaleFactor = .95f; |
| |
| const int kWindowAnimation_Rotate_DurationMS = 180; |
| const int kWindowAnimation_Rotate_OpacityDurationPercent = 90; |
| const float kWindowAnimation_Rotate_TranslateY = -20.f; |
| const float kWindowAnimation_Rotate_PerspectiveDepth = 500.f; |
| const float kWindowAnimation_Rotate_DegreesX = 5.f; |
| const float kWindowAnimation_Rotate_ScaleFactor = .99f; |
| |
| const float kWindowAnimation_Bounce_Scale = 1.02f; |
| const int kWindowAnimation_Bounce_DurationMS = 180; |
| const int kWindowAnimation_Bounce_GrowShrinkDurationPercent = 40; |
| |
| base::TimeDelta GetWindowVisibilityAnimationDuration( |
| const aura::Window& window) { |
| int duration = |
| window.GetProperty(kWindowVisibilityAnimationDurationKey); |
| if (duration == 0 && window.type() == ui::wm::WINDOW_TYPE_MENU) { |
| return base::TimeDelta::FromMilliseconds( |
| kDefaultAnimationDurationForMenuMS); |
| } |
| return base::TimeDelta::FromInternalValue(duration); |
| } |
| |
| // Gets/sets the WindowVisibilityAnimationType associated with a window. |
| // TODO(beng): redundant/fold into method on public api? |
| int GetWindowVisibilityAnimationType(aura::Window* window) { |
| int type = window->GetProperty(kWindowVisibilityAnimationTypeKey); |
| if (type == WINDOW_VISIBILITY_ANIMATION_TYPE_DEFAULT) { |
| return (window->type() == ui::wm::WINDOW_TYPE_MENU || |
| window->type() == ui::wm::WINDOW_TYPE_TOOLTIP) |
| ? WINDOW_VISIBILITY_ANIMATION_TYPE_FADE |
| : WINDOW_VISIBILITY_ANIMATION_TYPE_DROP; |
| } |
| return type; |
| } |
| |
| void GetTransformRelativeToRoot(ui::Layer* layer, gfx::Transform* transform) { |
| const ui::Layer* root = layer; |
| while (root->parent()) |
| root = root->parent(); |
| layer->GetTargetTransformRelativeTo(root, transform); |
| } |
| |
| gfx::Rect GetLayerWorldBoundsAfterTransform(ui::Layer* layer, |
| const gfx::Transform& transform) { |
| gfx::Transform in_world = transform; |
| GetTransformRelativeToRoot(layer, &in_world); |
| |
| gfx::RectF transformed = layer->bounds(); |
| in_world.TransformRect(&transformed); |
| |
| return gfx::ToEnclosingRect(transformed); |
| } |
| |
| // Augment the host window so that the enclosing bounds of the full |
| // animation will fit inside of it. |
| void AugmentWindowSize(aura::Window* window, |
| const gfx::Transform& end_transform) { |
| aura::client::AnimationHost* animation_host = |
| aura::client::GetAnimationHost(window); |
| if (!animation_host) |
| return; |
| |
| const gfx::Rect& world_at_start = window->bounds(); |
| gfx::Rect world_at_end = |
| GetLayerWorldBoundsAfterTransform(window->layer(), end_transform); |
| gfx::Rect union_in_window_space = |
| gfx::UnionRects(world_at_start, world_at_end); |
| |
| // Calculate the top left and bottom right deltas to be added to the window |
| // bounds. |
| gfx::Vector2d top_left_delta(world_at_start.x() - union_in_window_space.x(), |
| world_at_start.y() - union_in_window_space.y()); |
| |
| gfx::Vector2d bottom_right_delta( |
| union_in_window_space.x() + union_in_window_space.width() - |
| (world_at_start.x() + world_at_start.width()), |
| union_in_window_space.y() + union_in_window_space.height() - |
| (world_at_start.y() + world_at_start.height())); |
| |
| DCHECK(top_left_delta.x() >= 0 && top_left_delta.y() >= 0 && |
| bottom_right_delta.x() >= 0 && bottom_right_delta.y() >= 0); |
| |
| animation_host->SetHostTransitionOffsets(top_left_delta, bottom_right_delta); |
| } |
| |
| // Shows a window using an animation, animating its opacity from 0.f to 1.f, |
| // its visibility to true, and its transform from |start_transform| to |
| // |end_transform|. |
| void AnimateShowWindowCommon(aura::Window* window, |
| const gfx::Transform& start_transform, |
| const gfx::Transform& end_transform) { |
| AugmentWindowSize(window, end_transform); |
| |
| window->layer()->SetOpacity(kWindowAnimation_HideOpacity); |
| window->layer()->SetTransform(start_transform); |
| window->layer()->SetVisible(true); |
| |
| { |
| // Property sets within this scope will be implicitly animated. |
| ui::ScopedLayerAnimationSettings settings(window->layer()->GetAnimator()); |
| base::TimeDelta duration = GetWindowVisibilityAnimationDuration(*window); |
| if (duration.ToInternalValue() > 0) |
| settings.SetTransitionDuration(duration); |
| |
| window->layer()->SetTransform(end_transform); |
| window->layer()->SetOpacity(kWindowAnimation_ShowOpacity); |
| } |
| } |
| |
| // Hides a window using an animation, animating its opacity from 1.f to 0.f, |
| // its visibility to false, and its transform to |end_transform|. |
| void AnimateHideWindowCommon(aura::Window* window, |
| const gfx::Transform& end_transform) { |
| AugmentWindowSize(window, end_transform); |
| |
| // Property sets within this scope will be implicitly animated. |
| ScopedHidingAnimationSettings hiding_settings(window); |
| base::TimeDelta duration = GetWindowVisibilityAnimationDuration(*window); |
| if (duration.ToInternalValue() > 0) |
| hiding_settings.layer_animation_settings()->SetTransitionDuration(duration); |
| |
| window->layer()->SetOpacity(kWindowAnimation_HideOpacity); |
| window->layer()->SetTransform(end_transform); |
| window->layer()->SetVisible(false); |
| } |
| |
| static gfx::Transform GetScaleForWindow(aura::Window* window) { |
| gfx::Rect bounds = window->bounds(); |
| gfx::Transform scale = gfx::GetScaleTransform( |
| gfx::Point(kWindowAnimation_TranslateFactor * bounds.width(), |
| kWindowAnimation_TranslateFactor * bounds.height()), |
| kWindowAnimation_ScaleFactor); |
| return scale; |
| } |
| |
| // Show/Hide windows using a shrink animation. |
| void AnimateShowWindow_Drop(aura::Window* window) { |
| AnimateShowWindowCommon(window, GetScaleForWindow(window), gfx::Transform()); |
| } |
| |
| void AnimateHideWindow_Drop(aura::Window* window) { |
| AnimateHideWindowCommon(window, GetScaleForWindow(window)); |
| } |
| |
| // Show/Hide windows using a vertical Glenimation. |
| void AnimateShowWindow_Vertical(aura::Window* window) { |
| gfx::Transform transform; |
| transform.Translate(0, window->GetProperty( |
| kWindowVisibilityAnimationVerticalPositionKey)); |
| AnimateShowWindowCommon(window, transform, gfx::Transform()); |
| } |
| |
| void AnimateHideWindow_Vertical(aura::Window* window) { |
| gfx::Transform transform; |
| transform.Translate(0, window->GetProperty( |
| kWindowVisibilityAnimationVerticalPositionKey)); |
| AnimateHideWindowCommon(window, transform); |
| } |
| |
| // Show/Hide windows using a fade. |
| void AnimateShowWindow_Fade(aura::Window* window) { |
| AnimateShowWindowCommon(window, gfx::Transform(), gfx::Transform()); |
| } |
| |
| void AnimateHideWindow_Fade(aura::Window* window) { |
| AnimateHideWindowCommon(window, gfx::Transform()); |
| } |
| |
| ui::LayerAnimationElement* CreateGrowShrinkElement( |
| aura::Window* window, bool grow) { |
| scoped_ptr<ui::InterpolatedTransform> scale(new ui::InterpolatedScale( |
| gfx::Point3F(kWindowAnimation_Bounce_Scale, |
| kWindowAnimation_Bounce_Scale, |
| 1), |
| gfx::Point3F(1, 1, 1))); |
| scoped_ptr<ui::InterpolatedTransform> scale_about_pivot( |
| new ui::InterpolatedTransformAboutPivot( |
| gfx::Point(window->bounds().width() * 0.5, |
| window->bounds().height() * 0.5), |
| scale.release())); |
| scale_about_pivot->SetReversed(grow); |
| scoped_ptr<ui::LayerAnimationElement> transition( |
| ui::LayerAnimationElement::CreateInterpolatedTransformElement( |
| scale_about_pivot.release(), |
| base::TimeDelta::FromMilliseconds( |
| kWindowAnimation_Bounce_DurationMS * |
| kWindowAnimation_Bounce_GrowShrinkDurationPercent / 100))); |
| transition->set_tween_type(grow ? gfx::Tween::EASE_OUT : gfx::Tween::EASE_IN); |
| return transition.release(); |
| } |
| |
| void AnimateBounce(aura::Window* window) { |
| ui::ScopedLayerAnimationSettings scoped_settings( |
| window->layer()->GetAnimator()); |
| scoped_settings.SetPreemptionStrategy( |
| ui::LayerAnimator::REPLACE_QUEUED_ANIMATIONS); |
| scoped_ptr<ui::LayerAnimationSequence> sequence( |
| new ui::LayerAnimationSequence); |
| sequence->AddElement(CreateGrowShrinkElement(window, true)); |
| sequence->AddElement(ui::LayerAnimationElement::CreatePauseElement( |
| ui::LayerAnimationElement::BOUNDS, |
| base::TimeDelta::FromMilliseconds( |
| kWindowAnimation_Bounce_DurationMS * |
| (100 - 2 * kWindowAnimation_Bounce_GrowShrinkDurationPercent) / |
| 100))); |
| sequence->AddElement(CreateGrowShrinkElement(window, false)); |
| window->layer()->GetAnimator()->StartAnimation(sequence.release()); |
| } |
| |
| // A HidingWindowAnimationObserver that deletes observer and detached |
| // layers when the last_sequence has been completed or aborted. |
| class RotateHidingWindowAnimationObserver |
| : public HidingWindowAnimationObserverBase, |
| public ui::LayerAnimationObserver { |
| public: |
| explicit RotateHidingWindowAnimationObserver(aura::Window* window) |
| : HidingWindowAnimationObserverBase(window) {} |
| ~RotateHidingWindowAnimationObserver() override {} |
| |
| // Destroys itself after |last_sequence| ends or is aborted. Does not take |
| // ownership of |last_sequence|, which should not be NULL. |
| void SetLastSequence(ui::LayerAnimationSequence* last_sequence) { |
| last_sequence->AddObserver(this); |
| } |
| |
| // ui::LayerAnimationObserver: |
| void OnLayerAnimationEnded(ui::LayerAnimationSequence* sequence) override { |
| OnAnimationCompleted(); |
| } |
| void OnLayerAnimationAborted(ui::LayerAnimationSequence* sequence) override { |
| OnAnimationCompleted(); |
| } |
| void OnLayerAnimationScheduled( |
| ui::LayerAnimationSequence* sequence) override {} |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(RotateHidingWindowAnimationObserver); |
| }; |
| |
| void AddLayerAnimationsForRotate(aura::Window* window, bool show) { |
| if (show) |
| window->layer()->SetOpacity(kWindowAnimation_HideOpacity); |
| |
| base::TimeDelta duration = base::TimeDelta::FromMilliseconds( |
| kWindowAnimation_Rotate_DurationMS); |
| |
| RotateHidingWindowAnimationObserver* observer = NULL; |
| |
| if (!show) { |
| observer = new RotateHidingWindowAnimationObserver(window); |
| window->layer()->GetAnimator()->SchedulePauseForProperties( |
| duration * (100 - kWindowAnimation_Rotate_OpacityDurationPercent) / 100, |
| ui::LayerAnimationElement::OPACITY); |
| } |
| scoped_ptr<ui::LayerAnimationElement> opacity( |
| ui::LayerAnimationElement::CreateOpacityElement( |
| show ? kWindowAnimation_ShowOpacity : kWindowAnimation_HideOpacity, |
| duration * kWindowAnimation_Rotate_OpacityDurationPercent / 100)); |
| opacity->set_tween_type(gfx::Tween::EASE_IN_OUT); |
| window->layer()->GetAnimator()->ScheduleAnimation( |
| new ui::LayerAnimationSequence(opacity.release())); |
| |
| float xcenter = window->bounds().width() * 0.5; |
| |
| gfx::Transform transform; |
| transform.Translate(xcenter, 0); |
| transform.ApplyPerspectiveDepth(kWindowAnimation_Rotate_PerspectiveDepth); |
| transform.Translate(-xcenter, 0); |
| scoped_ptr<ui::InterpolatedTransform> perspective( |
| new ui::InterpolatedConstantTransform(transform)); |
| |
| scoped_ptr<ui::InterpolatedTransform> scale( |
| new ui::InterpolatedScale(1, kWindowAnimation_Rotate_ScaleFactor)); |
| scoped_ptr<ui::InterpolatedTransform> scale_about_pivot( |
| new ui::InterpolatedTransformAboutPivot( |
| gfx::Point(xcenter, kWindowAnimation_Rotate_TranslateY), |
| scale.release())); |
| |
| scoped_ptr<ui::InterpolatedTransform> translation( |
| new ui::InterpolatedTranslation(gfx::Point(), gfx::Point( |
| 0, kWindowAnimation_Rotate_TranslateY))); |
| |
| scoped_ptr<ui::InterpolatedTransform> rotation( |
| new ui::InterpolatedAxisAngleRotation( |
| gfx::Vector3dF(1, 0, 0), 0, kWindowAnimation_Rotate_DegreesX)); |
| |
| scale_about_pivot->SetChild(perspective.release()); |
| translation->SetChild(scale_about_pivot.release()); |
| rotation->SetChild(translation.release()); |
| rotation->SetReversed(show); |
| |
| scoped_ptr<ui::LayerAnimationElement> transition( |
| ui::LayerAnimationElement::CreateInterpolatedTransformElement( |
| rotation.release(), duration)); |
| ui::LayerAnimationSequence* last_sequence = |
| new ui::LayerAnimationSequence(transition.release()); |
| window->layer()->GetAnimator()->ScheduleAnimation(last_sequence); |
| |
| if (observer) { |
| observer->SetLastSequence(last_sequence); |
| observer->DetachAndRecreateLayers(); |
| } |
| } |
| |
| void AnimateShowWindow_Rotate(aura::Window* window) { |
| AddLayerAnimationsForRotate(window, true); |
| } |
| |
| void AnimateHideWindow_Rotate(aura::Window* window) { |
| AddLayerAnimationsForRotate(window, false); |
| } |
| |
| bool AnimateShowWindow(aura::Window* window) { |
| if (!HasWindowVisibilityAnimationTransition(window, ANIMATE_SHOW)) { |
| if (HasWindowVisibilityAnimationTransition(window, ANIMATE_HIDE)) { |
| // Since hide animation may have changed opacity and transform, |
| // reset them to show the window. |
| window->layer()->SetOpacity(kWindowAnimation_ShowOpacity); |
| window->layer()->SetTransform(gfx::Transform()); |
| } |
| return false; |
| } |
| |
| switch (GetWindowVisibilityAnimationType(window)) { |
| case WINDOW_VISIBILITY_ANIMATION_TYPE_DROP: |
| AnimateShowWindow_Drop(window); |
| return true; |
| case WINDOW_VISIBILITY_ANIMATION_TYPE_VERTICAL: |
| AnimateShowWindow_Vertical(window); |
| return true; |
| case WINDOW_VISIBILITY_ANIMATION_TYPE_FADE: |
| AnimateShowWindow_Fade(window); |
| return true; |
| case WINDOW_VISIBILITY_ANIMATION_TYPE_ROTATE: |
| AnimateShowWindow_Rotate(window); |
| return true; |
| default: |
| return false; |
| } |
| } |
| |
| bool AnimateHideWindow(aura::Window* window) { |
| if (!HasWindowVisibilityAnimationTransition(window, ANIMATE_HIDE)) { |
| if (HasWindowVisibilityAnimationTransition(window, ANIMATE_SHOW)) { |
| // Since show animation may have changed opacity and transform, |
| // reset them, though the change should be hidden. |
| window->layer()->SetOpacity(kWindowAnimation_HideOpacity); |
| window->layer()->SetTransform(gfx::Transform()); |
| } |
| return false; |
| } |
| |
| switch (GetWindowVisibilityAnimationType(window)) { |
| case WINDOW_VISIBILITY_ANIMATION_TYPE_DROP: |
| AnimateHideWindow_Drop(window); |
| return true; |
| case WINDOW_VISIBILITY_ANIMATION_TYPE_VERTICAL: |
| AnimateHideWindow_Vertical(window); |
| return true; |
| case WINDOW_VISIBILITY_ANIMATION_TYPE_FADE: |
| AnimateHideWindow_Fade(window); |
| return true; |
| case WINDOW_VISIBILITY_ANIMATION_TYPE_ROTATE: |
| AnimateHideWindow_Rotate(window); |
| return true; |
| default: |
| return false; |
| } |
| } |
| |
| } // namespace |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // ImplicitHidingWindowAnimationObserver |
| |
| ImplicitHidingWindowAnimationObserver::ImplicitHidingWindowAnimationObserver( |
| aura::Window* window, |
| ui::ScopedLayerAnimationSettings* settings) |
| : HidingWindowAnimationObserverBase(window) { |
| settings->AddObserver(this); |
| } |
| |
| void ImplicitHidingWindowAnimationObserver::OnImplicitAnimationsCompleted() { |
| OnAnimationCompleted(); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // ScopedHidingAnimationSettings |
| |
| ScopedHidingAnimationSettings::ScopedHidingAnimationSettings( |
| aura::Window* window) |
| : layer_animation_settings_(window->layer()->GetAnimator()), |
| observer_(new ImplicitHidingWindowAnimationObserver( |
| window, |
| &layer_animation_settings_)) { |
| } |
| |
| ScopedHidingAnimationSettings::~ScopedHidingAnimationSettings() { |
| observer_->DetachAndRecreateLayers(); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // External interface |
| |
| void SetWindowVisibilityAnimationType(aura::Window* window, int type) { |
| window->SetProperty(kWindowVisibilityAnimationTypeKey, type); |
| } |
| |
| int GetWindowVisibilityAnimationType(aura::Window* window) { |
| return window->GetProperty(kWindowVisibilityAnimationTypeKey); |
| } |
| |
| void SetWindowVisibilityAnimationTransition( |
| aura::Window* window, |
| WindowVisibilityAnimationTransition transition) { |
| window->SetProperty(kWindowVisibilityAnimationTransitionKey, transition); |
| } |
| |
| bool HasWindowVisibilityAnimationTransition( |
| aura::Window* window, |
| WindowVisibilityAnimationTransition transition) { |
| WindowVisibilityAnimationTransition prop = window->GetProperty( |
| kWindowVisibilityAnimationTransitionKey); |
| return (prop & transition) != 0; |
| } |
| |
| void SetWindowVisibilityAnimationDuration(aura::Window* window, |
| const base::TimeDelta& duration) { |
| window->SetProperty(kWindowVisibilityAnimationDurationKey, |
| static_cast<int>(duration.ToInternalValue())); |
| } |
| |
| base::TimeDelta GetWindowVisibilityAnimationDuration( |
| const aura::Window& window) { |
| return base::TimeDelta::FromInternalValue( |
| window.GetProperty(kWindowVisibilityAnimationDurationKey)); |
| } |
| |
| void SetWindowVisibilityAnimationVerticalPosition(aura::Window* window, |
| float position) { |
| window->SetProperty(kWindowVisibilityAnimationVerticalPositionKey, position); |
| } |
| |
| bool AnimateOnChildWindowVisibilityChanged(aura::Window* window, bool visible) { |
| if (WindowAnimationsDisabled(window)) |
| return false; |
| if (visible) |
| return AnimateShowWindow(window); |
| // Don't start hiding the window again if it's already being hidden. |
| return window->layer()->GetTargetOpacity() != 0.0f && |
| AnimateHideWindow(window); |
| } |
| |
| bool AnimateWindow(aura::Window* window, WindowAnimationType type) { |
| switch (type) { |
| case WINDOW_ANIMATION_TYPE_BOUNCE: |
| AnimateBounce(window); |
| return true; |
| default: |
| NOTREACHED(); |
| return false; |
| } |
| } |
| |
| bool WindowAnimationsDisabled(aura::Window* window) { |
| // Individual windows can choose to skip animations. |
| if (window && window->GetProperty(aura::client::kAnimationsDisabledKey)) |
| return true; |
| |
| // Animations can be disabled globally for testing. |
| if (base::CommandLine::ForCurrentProcess()->HasSwitch( |
| switches::kWindowAnimationsDisabled)) |
| return true; |
| |
| // Tests of animations themselves should still run even if the machine is |
| // being accessed via Remote Desktop. |
| if (ui::ScopedAnimationDurationScaleMode::duration_scale_mode() == |
| ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION) |
| return false; |
| |
| // Let the user decide whether or not to play the animation. |
| return !gfx::Animation::ShouldRenderRichAnimation(); |
| } |
| |
| } // namespace wm |