Home | History | Annotate | Download | only in overview
      1 // Copyright 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "ash/wm/overview/scoped_transform_overview_window.h"
      6 
      7 #include "ash/screen_util.h"
      8 #include "ash/shell_window_ids.h"
      9 #include "ash/wm/overview/scoped_window_copy.h"
     10 #include "ash/wm/overview/window_selector_item.h"
     11 #include "ash/wm/window_state.h"
     12 #include "ash/wm/window_util.h"
     13 #include "ui/aura/client/aura_constants.h"
     14 #include "ui/aura/client/screen_position_client.h"
     15 #include "ui/aura/window.h"
     16 #include "ui/compositor/scoped_layer_animation_settings.h"
     17 #include "ui/gfx/animation/tween.h"
     18 #include "ui/views/widget/widget.h"
     19 #include "ui/wm/core/window_animations.h"
     20 #include "ui/wm/core/window_util.h"
     21 
     22 namespace ash {
     23 
     24 namespace {
     25 
     26 // The animation settings used for window selector animations.
     27 class WindowSelectorAnimationSettings
     28     : public ui::ScopedLayerAnimationSettings {
     29  public:
     30   WindowSelectorAnimationSettings(aura::Window* window) :
     31       ui::ScopedLayerAnimationSettings(window->layer()->GetAnimator()) {
     32     SetPreemptionStrategy(
     33         ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
     34     SetTransitionDuration(base::TimeDelta::FromMilliseconds(
     35         ScopedTransformOverviewWindow::kTransitionMilliseconds));
     36     SetTweenType(gfx::Tween::FAST_OUT_SLOW_IN);
     37   }
     38 
     39   virtual ~WindowSelectorAnimationSettings() {
     40   }
     41 };
     42 
     43 void SetTransformOnWindow(aura::Window* window,
     44                           const gfx::Transform& transform,
     45                           bool animate) {
     46   if (animate) {
     47     WindowSelectorAnimationSettings animation_settings(window);
     48     window->SetTransform(transform);
     49   } else {
     50     window->SetTransform(transform);
     51   }
     52 }
     53 
     54 gfx::Transform TranslateTransformOrigin(const gfx::Vector2d& new_origin,
     55                                         const gfx::Transform& transform) {
     56   gfx::Transform result;
     57   result.Translate(-new_origin.x(), -new_origin.y());
     58   result.PreconcatTransform(transform);
     59   result.Translate(new_origin.x(), new_origin.y());
     60   return result;
     61 }
     62 
     63 void SetTransformOnWindowAndAllTransientChildren(
     64     aura::Window* window,
     65     const gfx::Transform& transform,
     66     bool animate) {
     67   SetTransformOnWindow(window, transform, animate);
     68 
     69   aura::Window::Windows transient_children =
     70       ::wm::GetTransientChildren(window);
     71   for (aura::Window::Windows::iterator iter = transient_children.begin();
     72        iter != transient_children.end(); ++iter) {
     73     aura::Window* transient_child = *iter;
     74     gfx::Rect window_bounds = window->bounds();
     75     gfx::Rect child_bounds = transient_child->bounds();
     76     gfx::Transform transient_window_transform(
     77         TranslateTransformOrigin(child_bounds.origin() - window_bounds.origin(),
     78                                  transform));
     79     SetTransformOnWindow(transient_child, transient_window_transform, animate);
     80   }
     81 }
     82 
     83 aura::Window* GetModalTransientParent(aura::Window* window) {
     84   if (window->GetProperty(aura::client::kModalKey) == ui::MODAL_TYPE_WINDOW)
     85     return ::wm::GetTransientParent(window);
     86   return NULL;
     87 }
     88 
     89 }  // namespace
     90 
     91 const int ScopedTransformOverviewWindow::kTransitionMilliseconds = 200;
     92 
     93 ScopedTransformOverviewWindow::ScopedTransformOverviewWindow(
     94         aura::Window* window)
     95     : window_(window),
     96       minimized_(window->GetProperty(aura::client::kShowStateKey) ==
     97                  ui::SHOW_STATE_MINIMIZED),
     98       ignored_by_shelf_(ash::wm::GetWindowState(window)->ignored_by_shelf()),
     99       overview_started_(false),
    100       original_transform_(window->layer()->GetTargetTransform()),
    101       opacity_(window->layer()->GetTargetOpacity()) {
    102 }
    103 
    104 ScopedTransformOverviewWindow::~ScopedTransformOverviewWindow() {
    105   if (window_) {
    106     WindowSelectorAnimationSettings animation_settings(window_);
    107     gfx::Transform transform;
    108     SetTransformOnWindowAndTransientChildren(original_transform_, true);
    109     if (minimized_ && window_->GetProperty(aura::client::kShowStateKey) !=
    110         ui::SHOW_STATE_MINIMIZED) {
    111       // Setting opacity 0 and visible false ensures that the property change
    112       // to SHOW_STATE_MINIMIZED will not animate the window from its original
    113       // bounds to the minimized position.
    114       // Hiding the window needs to be done before the target opacity is 0,
    115       // otherwise the layer's visibility will not be updated
    116       // (See VisibilityController::UpdateLayerVisibility).
    117       window_->Hide();
    118       window_->layer()->SetOpacity(0);
    119       window_->SetProperty(aura::client::kShowStateKey,
    120                            ui::SHOW_STATE_MINIMIZED);
    121     }
    122     ash::wm::GetWindowState(window_)->set_ignored_by_shelf(ignored_by_shelf_);
    123     window_->layer()->SetOpacity(opacity_);
    124   }
    125 }
    126 
    127 bool ScopedTransformOverviewWindow::Contains(const aura::Window* target) const {
    128   for (ScopedVector<ScopedWindowCopy>::const_iterator iter =
    129       window_copies_.begin(); iter != window_copies_.end(); ++iter) {
    130     if ((*iter)->GetWindow()->Contains(target))
    131       return true;
    132   }
    133   aura::Window* window = window_;
    134   while (window) {
    135     if (window->Contains(target))
    136       return true;
    137     window = GetModalTransientParent(window);
    138   }
    139   return false;
    140 }
    141 
    142 gfx::Rect ScopedTransformOverviewWindow::GetBoundsInScreen() const {
    143   gfx::Rect bounds;
    144   aura::Window* window = window_;
    145   while (window) {
    146     bounds.Union(ScreenUtil::ConvertRectToScreen(window->parent(),
    147                                                 window->GetTargetBounds()));
    148     window = GetModalTransientParent(window);
    149   }
    150   return bounds;
    151 }
    152 
    153 void ScopedTransformOverviewWindow::RestoreWindow() {
    154   if (minimized_ && window_->GetProperty(aura::client::kShowStateKey) ==
    155       ui::SHOW_STATE_MINIMIZED) {
    156     window_->Show();
    157   }
    158 }
    159 
    160 void ScopedTransformOverviewWindow::RestoreWindowOnExit() {
    161   minimized_ = false;
    162   original_transform_ = gfx::Transform();
    163   opacity_ = 1;
    164 }
    165 
    166 void ScopedTransformOverviewWindow::OnWindowDestroyed() {
    167   window_ = NULL;
    168 }
    169 
    170 gfx::Rect ScopedTransformOverviewWindow::ShrinkRectToFitPreservingAspectRatio(
    171     const gfx::Rect& rect,
    172     const gfx::Rect& bounds) {
    173   DCHECK(!rect.IsEmpty());
    174   DCHECK(!bounds.IsEmpty());
    175   float scale = std::min(1.0f,
    176       std::min(static_cast<float>(bounds.width()) / rect.width(),
    177                static_cast<float>(bounds.height()) / rect.height()));
    178   return gfx::Rect(bounds.x() + 0.5 * (bounds.width() - scale * rect.width()),
    179                    bounds.y() + 0.5 * (bounds.height() - scale * rect.height()),
    180                    rect.width() * scale,
    181                    rect.height() * scale);
    182 }
    183 
    184 gfx::Transform ScopedTransformOverviewWindow::GetTransformForRect(
    185     const gfx::Rect& src_rect,
    186     const gfx::Rect& dst_rect) {
    187   DCHECK(!src_rect.IsEmpty());
    188   DCHECK(!dst_rect.IsEmpty());
    189   gfx::Transform transform;
    190   transform.Translate(dst_rect.x() - src_rect.x(),
    191                       dst_rect.y() - src_rect.y());
    192   transform.Scale(static_cast<float>(dst_rect.width()) / src_rect.width(),
    193                   static_cast<float>(dst_rect.height()) / src_rect.height());
    194   return transform;
    195 }
    196 
    197 void ScopedTransformOverviewWindow::SetTransform(
    198     aura::Window* root_window,
    199     const gfx::Transform& transform,
    200     bool animate) {
    201   DCHECK(overview_started_);
    202 
    203   if (root_window != window_->GetRootWindow()) {
    204     if (!window_copies_.empty()) {
    205       bool bounds_or_hierarchy_changed = false;
    206       aura::Window* window = window_;
    207       for (ScopedVector<ScopedWindowCopy>::reverse_iterator iter =
    208                window_copies_.rbegin();
    209            !bounds_or_hierarchy_changed && iter != window_copies_.rend();
    210            ++iter, window = GetModalTransientParent(window)) {
    211         if (!window) {
    212           bounds_or_hierarchy_changed = true;
    213         } else if ((*iter)->GetWindow()->GetBoundsInScreen() !=
    214                 window->GetBoundsInScreen()) {
    215           bounds_or_hierarchy_changed = true;
    216         }
    217       }
    218       // Clearing the window copies array will force it to be recreated.
    219       // TODO(flackr): If only the position changed and not the size,
    220       // update the existing window copy's position and continue to use it.
    221       if (bounds_or_hierarchy_changed)
    222         window_copies_.clear();
    223     }
    224     if (window_copies_.empty()) {
    225       // TODO(flackr): Create copies of the transient children windows as well.
    226       // Currently they will only be visible on the window's initial display.
    227       CopyWindowAndTransientParents(root_window, window_);
    228     }
    229   }
    230   SetTransformOnWindowAndTransientChildren(transform, animate);
    231 }
    232 
    233 void ScopedTransformOverviewWindow::CopyWindowAndTransientParents(
    234     aura::Window* target_root,
    235     aura::Window* window) {
    236   aura::Window* modal_parent = GetModalTransientParent(window);
    237   if (modal_parent)
    238     CopyWindowAndTransientParents(target_root, modal_parent);
    239   window_copies_.push_back(new ScopedWindowCopy(target_root, window));
    240 }
    241 
    242 void ScopedTransformOverviewWindow::SetTransformOnWindowAndTransientChildren(
    243     const gfx::Transform& transform,
    244     bool animate) {
    245   gfx::Point origin(GetBoundsInScreen().origin());
    246   aura::Window* window = window_;
    247   while (::wm::GetTransientParent(window))
    248     window = ::wm::GetTransientParent(window);
    249   for (ScopedVector<ScopedWindowCopy>::const_iterator iter =
    250       window_copies_.begin(); iter != window_copies_.end(); ++iter) {
    251     SetTransformOnWindow(
    252         (*iter)->GetWindow(),
    253         TranslateTransformOrigin(ScreenUtil::ConvertRectToScreen(
    254             (*iter)->GetWindow()->parent(),
    255             (*iter)->GetWindow()->GetTargetBounds()).origin() - origin,
    256             transform),
    257         animate);
    258   }
    259   SetTransformOnWindowAndAllTransientChildren(
    260       window,
    261       TranslateTransformOrigin(ScreenUtil::ConvertRectToScreen(
    262           window->parent(), window->GetTargetBounds()).origin() - origin,
    263           transform),
    264       animate);
    265 }
    266 
    267 void ScopedTransformOverviewWindow::PrepareForOverview() {
    268   DCHECK(!overview_started_);
    269   overview_started_ = true;
    270   ash::wm::GetWindowState(window_)->set_ignored_by_shelf(true);
    271   RestoreWindow();
    272 }
    273 
    274 }  // namespace ash
    275