| Index: ui/views/corewm/window_animations.cc
|
| diff --git a/ui/views/corewm/window_animations.cc b/ui/views/corewm/window_animations.cc
|
| index 42b26413129abdd166b339cd15de902c2393946e..f2da98a837d592da262b9223caeade9094008419 100644
|
| --- a/ui/views/corewm/window_animations.cc
|
| +++ b/ui/views/corewm/window_animations.cc
|
| @@ -107,31 +107,22 @@ int GetWindowVisibilityAnimationType(aura::Window* window) {
|
| return type;
|
| }
|
|
|
| -// Observes a hide animation.
|
| -// A window can be hidden for a variety of reasons. Sometimes, Hide() will be
|
| -// called and life is simple. Sometimes, the window is actually bound to a
|
| -// views::Widget and that Widget is closed, and life is a little more
|
| -// complicated. When a Widget is closed the aura::Window* is actually not
|
| -// destroyed immediately - it is actually just immediately hidden and then
|
| -// destroyed when the stack unwinds. To handle this case, we start the hide
|
| -// animation immediately when the window is hidden, then when the window is
|
| -// subsequently destroyed this object acquires ownership of the window's layer,
|
| -// so that it can continue animating it until the animation completes.
|
| -// Regardless of whether or not the window is destroyed, this object deletes
|
| -// itself when the animation completes.
|
| +// A base class for hiding animation observer. This calls
|
| +// AnimationHost::OnWindowHidingAnimationCompleted upon completion.
|
| class HidingWindowAnimationObserver : public ui::ImplicitAnimationObserver,
|
| public aura::WindowObserver {
|
| public:
|
| - explicit HidingWindowAnimationObserver(aura::Window* window)
|
| + HidingWindowAnimationObserver(aura::Window* window,
|
| + ui::ScopedLayerAnimationSettings* settings)
|
| : window_(window) {
|
| - window_->AddObserver(this);
|
| + window->AddObserver(this);
|
| + if (settings)
|
| + settings->AddObserver(this);
|
| }
|
| +
|
| virtual ~HidingWindowAnimationObserver() {
|
| - STLDeleteElements(&layers_);
|
| }
|
|
|
| - private:
|
| - // Overridden from ui::ImplicitAnimationObserver:
|
| virtual void OnImplicitAnimationsCompleted() OVERRIDE {
|
| // Window may have been destroyed by this point.
|
| if (window_) {
|
| @@ -144,30 +135,122 @@ class HidingWindowAnimationObserver : public ui::ImplicitAnimationObserver,
|
| delete this;
|
| }
|
|
|
| + virtual void OnWindowDestroying(aura::Window* window) OVERRIDE {
|
| + DCHECK_EQ(window, window_);
|
| + window_->RemoveObserver(this);
|
| + window_ = NULL;
|
| + }
|
| +
|
| + protected:
|
| + aura::Window* window_;
|
| +
|
| + private:
|
| + DISALLOW_COPY_AND_ASSIGN(HidingWindowAnimationObserver);
|
| +};
|
| +
|
| +// A window can be hidden for a variety of reasons. Sometimes, Hide() will be
|
| +// called and life is simple. Sometimes, the window is actually bound to a
|
| +// views::Widget and that Widget is closed, and life is a little more
|
| +// complicated. When a Widget is closed the aura::Window* is actually not
|
| +// destroyed immediately - it is actually just immediately hidden and then
|
| +// destroyed when the stack unwinds. To handle this case, we start the hide
|
| +// animation immediately when the window is hidden, then when the window is
|
| +// subsequently destroyed this object acquires ownership of the window's layer,
|
| +// so that it can continue animating it until the animation completes.
|
| +// Regardless of whether or not the window is destroyed, this object deletes
|
| +// itself when the animation completes.
|
| +class DetachLayersWhenDestroyedAnimationObserver
|
| + : public HidingWindowAnimationObserver {
|
| + public:
|
| + DetachLayersWhenDestroyedAnimationObserver(
|
| + aura::Window* window,
|
| + ui::ScopedLayerAnimationSettings* settings)
|
| + : HidingWindowAnimationObserver(window, settings) {
|
| + }
|
| +
|
| + virtual ~DetachLayersWhenDestroyedAnimationObserver() {
|
| + STLDeleteElements(&layers_);
|
| + }
|
| +
|
| + private:
|
| // Overridden from aura::WindowObserver:
|
| virtual void OnWindowDestroying(aura::Window* window) OVERRIDE {
|
| DCHECK_EQ(window, window_);
|
| DCHECK(layers_.empty());
|
| AcquireAllLayers(window_->layer());
|
| - window_->RemoveObserver(this);
|
| - window_ = NULL;
|
| + HidingWindowAnimationObserver::OnWindowDestroying(window);
|
| }
|
|
|
| void AcquireAllLayers(ui::Layer* layer) {
|
| if (layer->owner()) {
|
| ui::Layer* released = layer->owner()->AcquireLayer();
|
| - DCHECK_EQ(layer, released);
|
| + CHECK_EQ(layer, released);
|
| layers_.push_back(released);
|
| }
|
| - std::vector<Layer*>::const_iterator it = layer->children().begin();
|
| + std::vector<ui::Layer*>::const_iterator it = layer->children().begin();
|
| for (; it != layer->children().end(); ++it)
|
| AcquireAllLayers(*it);
|
| }
|
|
|
| - aura::Window* window_;
|
| std::vector<ui::Layer*> layers_;
|
|
|
| - DISALLOW_COPY_AND_ASSIGN(HidingWindowAnimationObserver);
|
| + DISALLOW_COPY_AND_ASSIGN(DetachLayersWhenDestroyedAnimationObserver);
|
| +};
|
| +
|
| +// When hiding an active window, the animating layer can be hidden by
|
| +// new active window's layer. This class detaches the layers for
|
| +// hiding animation, creates new layers for the window and stacks them
|
| +// above the window and its transient children so that the layer for
|
| +// new active window will not hide the hiding animation.
|
| +class DetachAndRecreateLayersAnimationObserver
|
| + : HidingWindowAnimationObserver {
|
| + public:
|
| + DetachAndRecreateLayersAnimationObserver(
|
| + aura::Window* window,
|
| + ui::ScopedLayerAnimationSettings* settings)
|
| + : HidingWindowAnimationObserver(window, settings) {
|
| + }
|
| +
|
| + virtual ~DetachAndRecreateLayersAnimationObserver() {
|
| + DeepDeleteLayers(layer_);
|
| + }
|
| +
|
| + void DetachAndRecreateLayers() {
|
| + layer_ = RecreateWindowLayers(window_, true);
|
| + // If the window has transient children, move above the top most
|
| + // transient child so that activation change does not put the
|
| + // window above the animating layer.
|
| + 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_, topmost_transient_child->layer());
|
| + }
|
| + }
|
| + // Make the new layer invisible immediately.
|
| + window_->layer()->SetVisible(false);
|
| + window_->layer()->SetOpacity(0);
|
| + }
|
| +
|
| + private:
|
| + ui::Layer* layer_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(DetachAndRecreateLayersAnimationObserver);
|
| };
|
|
|
| void GetTransformRelativeToRoot(ui::Layer* layer, gfx::Transform* transform) {
|
| @@ -255,7 +338,8 @@ void AnimateHideWindowCommon(aura::Window* window,
|
|
|
| // Property sets within this scope will be implicitly animated.
|
| ui::ScopedLayerAnimationSettings settings(window->layer()->GetAnimator());
|
| - settings.AddObserver(new HidingWindowAnimationObserver(window));
|
| + scoped_ptr<LayerDetacherForHidingAnimation> detacher =
|
| + DetachAndRecreateLayersForHidingAnimation(window, &settings);
|
|
|
| base::TimeDelta duration = GetWindowVisibilityAnimationDuration(*window);
|
| if (duration.ToInternalValue() > 0)
|
| @@ -358,8 +442,11 @@ void AddLayerAnimationsForRotate(aura::Window* window, bool show) {
|
| base::TimeDelta duration = base::TimeDelta::FromMilliseconds(
|
| kWindowAnimation_Rotate_DurationMS);
|
|
|
| + scoped_ptr<LayerDetacherForHidingAnimation> layer_detacher;
|
| if (!show) {
|
| - new HidingWindowAnimationObserver(window);
|
| + // TODO(oshima): Fix observer leak.
|
| + layer_detacher =
|
| + DetachAndRecreateLayersForHidingAnimation(window, NULL).Pass();
|
| window->layer()->GetAnimator()->SchedulePauseForProperties(
|
| duration * (100 - kWindowAnimation_Rotate_OpacityDurationPercent) / 100,
|
| ui::LayerAnimationElement::OPACITY);
|
| @@ -477,6 +564,28 @@ bool AnimateHideWindow(aura::Window* window) {
|
| }
|
| }
|
|
|
| +// Refer to the description of LayerDetacherForHidingAnimation in
|
| +// window_animations.h for details.
|
| +class LayerDetacherForHidingAnimationImpl
|
| + : public LayerDetacherForHidingAnimation {
|
| + public:
|
| + LayerDetacherForHidingAnimationImpl(
|
| + aura::Window* window,
|
| + ui::ScopedLayerAnimationSettings* settings)
|
| + : observer_(
|
| + new DetachAndRecreateLayersAnimationObserver(window, settings)) {
|
| + }
|
| +
|
| + virtual ~LayerDetacherForHidingAnimationImpl() {
|
| + observer_->DetachAndRecreateLayers();
|
| + }
|
| +
|
| + private:
|
| + DetachAndRecreateLayersAnimationObserver* observer_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(LayerDetacherForHidingAnimationImpl);
|
| +};
|
| +
|
| } // namespace
|
|
|
| ////////////////////////////////////////////////////////////////////////////////
|
| @@ -521,9 +630,18 @@ void SetWindowVisibilityAnimationVerticalPosition(aura::Window* window,
|
| window->SetProperty(kWindowVisibilityAnimationVerticalPositionKey, position);
|
| }
|
|
|
| -ui::ImplicitAnimationObserver* CreateHidingWindowAnimationObserver(
|
| - aura::Window* window) {
|
| - return new HidingWindowAnimationObserver(window);
|
| +scoped_ptr<LayerDetacherForHidingAnimation>
|
| +DetachAndRecreateLayersForHidingAnimation(
|
| + aura::Window* window,
|
| + ui::ScopedLayerAnimationSettings* settings) {
|
| + return scoped_ptr<LayerDetacherForHidingAnimation>(
|
| + new LayerDetacherForHidingAnimationImpl(window, settings)).Pass();
|
| +}
|
| +
|
| +void DetachLayersForHidingAnimationWhenDestroyed(
|
| + aura::Window* window,
|
| + ui::ScopedLayerAnimationSettings* settings) {
|
| + new DetachLayersWhenDestroyedAnimationObserver(window, settings);
|
| }
|
|
|
| bool AnimateOnChildWindowVisibilityChanged(aura::Window* window, bool visible) {
|
|
|