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"
10 #include "ash/screen_util.h"
11 #include "ash/shell_window_ids.h"
12 #include "ash/wm/overview/scoped_overview_animation_settings.h"
13 #include "ash/wm/overview/window_selector_item.h"
14 #include "ash/wm/window_state.h"
15 #include "ash/wm/window_util.h"
16 #include "base/macros.h"
17 #include "ui/aura/client/aura_constants.h"
18 #include "ui/aura/client/screen_position_client.h"
19 #include "ui/aura/window.h"
20 #include "ui/compositor/scoped_layer_animation_settings.h"
21 #include "ui/gfx/animation/tween.h"
22 #include "ui/gfx/transform_util.h"
23 #include "ui/views/widget/widget.h"
24 #include "ui/wm/core/window_animations.h"
25 #include "ui/wm/core/window_util.h"
31 // The opacity level that windows will be set to when they are restored.
32 const float kRestoreWindowOpacity
= 1.0f
;
34 aura::Window
* GetTransientRoot(aura::Window
* window
) {
35 while (::wm::GetTransientParent(window
))
36 window
= ::wm::GetTransientParent(window
);
40 // An iterator class that traverses an aura::Window and all of it's transient
42 class TransientDescendantIterator
{
44 // Creates an empty iterator.
45 TransientDescendantIterator();
47 // Copy constructor required for iterator purposes.
48 TransientDescendantIterator(
49 const TransientDescendantIterator
& other
) = default;
51 // Iterates over |root_window| and all of its transient descendants.
52 // Note |root_window| must not have a transient parent.
53 explicit TransientDescendantIterator(aura::Window
* root_window
);
55 // Prefix increment operator. This assumes there are more items (i.e.
56 // *this != TransientDescendantIterator()).
57 const TransientDescendantIterator
& operator++();
59 // Comparison for STL-based loops.
60 bool operator!=(const TransientDescendantIterator
& other
) const;
62 // Dereference operator for STL-compatible iterators.
63 aura::Window
* operator*() const;
66 // The current window that |this| refers to. A NULL |current_window_| denotes
67 // an empty iterator and is used as the last possible value in the traversal.
68 aura::Window
* current_window_
;
70 // Explicit assignment operator defined because an explicit copy constructor
71 // is needed and therefore the DISALLOW_COPY_AND_ASSIGN macro cannot be used.
72 TransientDescendantIterator
& operator=(
73 const TransientDescendantIterator
& other
) = default;
76 // Provides a virtual container implementing begin() and end() for a sequence of
77 // TransientDescendantIterators. This can be used in range-based for loops.
78 class TransientDescendantIteratorRange
{
80 explicit TransientDescendantIteratorRange(
81 const TransientDescendantIterator
& begin
);
83 // Copy constructor required for iterator purposes.
84 TransientDescendantIteratorRange(
85 const TransientDescendantIteratorRange
& other
) = default;
87 const TransientDescendantIterator
& begin() const { return begin_
; }
88 const TransientDescendantIterator
& end() const { return end_
; }
91 TransientDescendantIterator begin_
;
92 TransientDescendantIterator end_
;
94 // Explicit assignment operator defined because an explicit copy constructor
95 // is needed and therefore the DISALLOW_COPY_AND_ASSIGN macro cannot be used.
96 TransientDescendantIteratorRange
& operator=(
97 const TransientDescendantIteratorRange
& other
) = default;
100 TransientDescendantIterator::TransientDescendantIterator()
101 : current_window_(nullptr) {
104 TransientDescendantIterator::TransientDescendantIterator(
105 aura::Window
* root_window
)
106 : current_window_(root_window
) {
107 DCHECK(!::wm::GetTransientParent(root_window
));
110 // Performs a pre-order traversal of the transient descendants.
111 const TransientDescendantIterator
&
112 TransientDescendantIterator::operator++() {
113 DCHECK(current_window_
);
115 const aura::Window::Windows
& transient_children
=
116 ::wm::GetTransientChildren(current_window_
);
118 if (transient_children
.size() > 0) {
119 current_window_
= transient_children
.front();
121 while (current_window_
) {
122 aura::Window
* parent
= ::wm::GetTransientParent(current_window_
);
124 current_window_
= nullptr;
127 const aura::Window::Windows
& transient_siblings
=
128 ::wm::GetTransientChildren(parent
);
129 aura::Window::Windows::const_iterator iter
= std::find(
130 transient_siblings
.begin(),
131 transient_siblings
.end(),
134 if (iter
!= transient_siblings
.end()) {
135 current_window_
= *iter
;
138 current_window_
= ::wm::GetTransientParent(current_window_
);
144 bool TransientDescendantIterator::operator!=(
145 const TransientDescendantIterator
& other
) const {
146 return current_window_
!= other
.current_window_
;
149 aura::Window
* TransientDescendantIterator::operator*() const {
150 return current_window_
;
153 TransientDescendantIteratorRange::TransientDescendantIteratorRange(
154 const TransientDescendantIterator
& begin
)
158 TransientDescendantIteratorRange
GetTransientTreeIterator(
159 aura::Window
* window
) {
160 return TransientDescendantIteratorRange(
161 TransientDescendantIterator(GetTransientRoot(window
)));
166 ScopedTransformOverviewWindow::ScopedTransformOverviewWindow(
167 aura::Window
* window
)
169 minimized_(window
->GetProperty(aura::client::kShowStateKey
) ==
170 ui::SHOW_STATE_MINIMIZED
),
171 ignored_by_shelf_(wm::GetWindowState(window
)->ignored_by_shelf()),
172 overview_started_(false),
173 original_transform_(window
->layer()->GetTargetTransform()),
174 original_opacity_(window
->layer()->GetTargetOpacity()) {
178 ScopedTransformOverviewWindow::~ScopedTransformOverviewWindow() {
181 void ScopedTransformOverviewWindow::RestoreWindow() {
182 ScopedAnimationSettings animation_settings_list
;
183 BeginScopedAnimation(
184 OverviewAnimationType::OVERVIEW_ANIMATION_RESTORE_WINDOW
,
185 &animation_settings_list
);
186 SetTransform(window()->GetRootWindow(), original_transform_
);
188 ScopedOverviewAnimationSettings
animation_settings(
189 OverviewAnimationType::OVERVIEW_ANIMATION_LAY_OUT_SELECTOR_ITEMS
,
191 gfx::Transform transform
;
192 if (minimized_
&& window_
->GetProperty(aura::client::kShowStateKey
) !=
193 ui::SHOW_STATE_MINIMIZED
) {
194 // Setting opacity 0 and visible false ensures that the property change
195 // to SHOW_STATE_MINIMIZED will not animate the window from its original
196 // bounds to the minimized position.
197 // Hiding the window needs to be done before the target opacity is 0,
198 // otherwise the layer's visibility will not be updated
199 // (See VisibilityController::UpdateLayerVisibility).
201 window_
->layer()->SetOpacity(0);
202 window_
->SetProperty(aura::client::kShowStateKey
, ui::SHOW_STATE_MINIMIZED
);
204 wm::GetWindowState(window_
)->set_ignored_by_shelf(ignored_by_shelf_
);
205 SetOpacity(original_opacity_
);
208 void ScopedTransformOverviewWindow::BeginScopedAnimation(
209 OverviewAnimationType animation_type
,
210 ScopedAnimationSettings
* animation_settings
) {
211 for (const auto& window
: GetTransientTreeIterator(window_
)) {
212 animation_settings
->push_back(
213 new ScopedOverviewAnimationSettings(animation_type
, window
));
217 bool ScopedTransformOverviewWindow::Contains(const aura::Window
* target
) const {
218 for (const auto& window
: GetTransientTreeIterator(window_
)) {
219 if (window
->Contains(target
))
225 gfx::Rect
ScopedTransformOverviewWindow::GetTargetBoundsInScreen() const {
227 for (const auto& window
: GetTransientTreeIterator(window_
)) {
228 bounds
.Union(ScreenUtil::ConvertRectToScreen(window
->parent(),
229 window
->GetTargetBounds()));
234 void ScopedTransformOverviewWindow::ShowWindowIfMinimized() {
235 if (minimized_
&& window_
->GetProperty(aura::client::kShowStateKey
) ==
236 ui::SHOW_STATE_MINIMIZED
) {
241 void ScopedTransformOverviewWindow::ShowWindowOnExit() {
244 original_transform_
= gfx::Transform();
245 original_opacity_
= kRestoreWindowOpacity
;
249 void ScopedTransformOverviewWindow::OnWindowDestroyed() {
253 gfx::Rect
ScopedTransformOverviewWindow::ShrinkRectToFitPreservingAspectRatio(
254 const gfx::Rect
& rect
,
255 const gfx::Rect
& bounds
) {
256 DCHECK(!rect
.IsEmpty());
257 DCHECK(!bounds
.IsEmpty());
258 float scale
= std::min(1.0f
,
259 std::min(static_cast<float>(bounds
.width()) / rect
.width(),
260 static_cast<float>(bounds
.height()) / rect
.height()));
261 return gfx::Rect(bounds
.x() + 0.5 * (bounds
.width() - scale
* rect
.width()),
262 bounds
.y() + 0.5 * (bounds
.height() - scale
* rect
.height()),
263 rect
.width() * scale
,
264 rect
.height() * scale
);
267 gfx::Transform
ScopedTransformOverviewWindow::GetTransformForRect(
268 const gfx::Rect
& src_rect
,
269 const gfx::Rect
& dst_rect
) {
270 DCHECK(!src_rect
.IsEmpty());
271 DCHECK(!dst_rect
.IsEmpty());
272 gfx::Transform transform
;
273 transform
.Translate(dst_rect
.x() - src_rect
.x(),
274 dst_rect
.y() - src_rect
.y());
275 transform
.Scale(static_cast<float>(dst_rect
.width()) / src_rect
.width(),
276 static_cast<float>(dst_rect
.height()) / src_rect
.height());
280 void ScopedTransformOverviewWindow::SetTransform(
281 aura::Window
* root_window
,
282 const gfx::Transform
& transform
) {
283 DCHECK(overview_started_
);
285 gfx::Point
target_origin(GetTargetBoundsInScreen().origin());
287 for (const auto& window
: GetTransientTreeIterator(window_
)) {
288 aura::Window
* parent_window
= window
->parent();
289 gfx::Point original_origin
= ScreenUtil::ConvertRectToScreen(
290 parent_window
, window
->GetTargetBounds()).origin();
291 gfx::Transform new_transform
= TransformAboutPivot(
292 gfx::Point(target_origin
.x() - original_origin
.x(),
293 target_origin
.y() - original_origin
.y()),
295 window
->SetTransform(new_transform
);
299 void ScopedTransformOverviewWindow::SetOpacity(float opacity
) {
300 for (const auto& window
: GetTransientTreeIterator(window_
)) {
301 window
->layer()->SetOpacity(opacity
);
305 void ScopedTransformOverviewWindow::Close() {
306 aura::Window
* window
= GetTransientRoot(window_
);
307 views::Widget::GetWidgetForNativeView(window
)->Close();
310 void ScopedTransformOverviewWindow::PrepareForOverview() {
311 DCHECK(!overview_started_
);
312 overview_started_
= true;
313 wm::GetWindowState(window_
)->set_ignored_by_shelf(true);
314 ShowWindowIfMinimized();