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.
5 #include "ash/wm/overview/scoped_transform_overview_window.h"
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"
26 // The animation settings used for window selector animations.
27 class WindowSelectorAnimationSettings
28 : public ui::ScopedLayerAnimationSettings
{
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
);
39 virtual ~WindowSelectorAnimationSettings() {
43 void SetTransformOnWindow(aura::Window
* window
,
44 const gfx::Transform
& transform
,
47 WindowSelectorAnimationSettings
animation_settings(window
);
48 window
->SetTransform(transform
);
50 window
->SetTransform(transform
);
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());
63 void SetTransformOnWindowAndAllTransientChildren(
65 const gfx::Transform
& transform
,
67 SetTransformOnWindow(window
, transform
, animate
);
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(),
79 SetTransformOnWindow(transient_child
, transient_window_transform
, animate
);
83 aura::Window
* GetModalTransientParent(aura::Window
* window
) {
84 if (window
->GetProperty(aura::client::kModalKey
) == ui::MODAL_TYPE_WINDOW
)
85 return ::wm::GetTransientParent(window
);
91 const int ScopedTransformOverviewWindow::kTransitionMilliseconds
= 200;
93 ScopedTransformOverviewWindow::ScopedTransformOverviewWindow(
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()) {
104 ScopedTransformOverviewWindow::~ScopedTransformOverviewWindow() {
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).
118 window_
->layer()->SetOpacity(0);
119 window_
->SetProperty(aura::client::kShowStateKey
,
120 ui::SHOW_STATE_MINIMIZED
);
122 ash::wm::GetWindowState(window_
)->set_ignored_by_shelf(ignored_by_shelf_
);
123 window_
->layer()->SetOpacity(opacity_
);
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
))
133 aura::Window
* window
= window_
;
135 if (window
->Contains(target
))
137 window
= GetModalTransientParent(window
);
142 gfx::Rect
ScopedTransformOverviewWindow::GetBoundsInScreen() const {
144 aura::Window
* window
= window_
;
146 bounds
.Union(ScreenUtil::ConvertRectToScreen(window
->parent(),
147 window
->GetTargetBounds()));
148 window
= GetModalTransientParent(window
);
153 void ScopedTransformOverviewWindow::RestoreWindow() {
154 if (minimized_
&& window_
->GetProperty(aura::client::kShowStateKey
) ==
155 ui::SHOW_STATE_MINIMIZED
) {
160 void ScopedTransformOverviewWindow::RestoreWindowOnExit() {
162 original_transform_
= gfx::Transform();
166 void ScopedTransformOverviewWindow::OnWindowDestroyed() {
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
);
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());
197 void ScopedTransformOverviewWindow::SetTransform(
198 aura::Window
* root_window
,
199 const gfx::Transform
& transform
,
201 DCHECK(overview_started_
);
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
)) {
212 bounds_or_hierarchy_changed
= true;
213 } else if ((*iter
)->GetWindow()->GetBoundsInScreen() !=
214 window
->GetBoundsInScreen()) {
215 bounds_or_hierarchy_changed
= true;
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();
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_
);
230 SetTransformOnWindowAndTransientChildren(transform
, animate
);
233 void ScopedTransformOverviewWindow::CopyWindowAndTransientParents(
234 aura::Window
* target_root
,
235 aura::Window
* window
) {
236 aura::Window
* modal_parent
= GetModalTransientParent(window
);
238 CopyWindowAndTransientParents(target_root
, modal_parent
);
239 window_copies_
.push_back(new ScopedWindowCopy(target_root
, window
));
242 void ScopedTransformOverviewWindow::SetTransformOnWindowAndTransientChildren(
243 const gfx::Transform
& transform
,
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
,
259 SetTransformOnWindowAndAllTransientChildren(
261 TranslateTransformOrigin(ScreenUtil::ConvertRectToScreen(
262 window
->parent(), window
->GetTargetBounds()).origin() - origin
,
267 void ScopedTransformOverviewWindow::PrepareForOverview() {
268 DCHECK(!overview_started_
);
269 overview_started_
= true;
270 ash::wm::GetWindowState(window_
)->set_ignored_by_shelf(true);