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/scoped_window_copy.h"
14 #include "ash/wm/overview/window_selector_item.h"
15 #include "ash/wm/window_state.h"
16 #include "ash/wm/window_util.h"
17 #include "base/macros.h"
18 #include "ui/aura/client/aura_constants.h"
19 #include "ui/aura/client/screen_position_client.h"
20 #include "ui/aura/window.h"
21 #include "ui/compositor/scoped_layer_animation_settings.h"
22 #include "ui/gfx/animation/tween.h"
23 #include "ui/gfx/transform_util.h"
24 #include "ui/views/widget/widget.h"
25 #include "ui/wm/core/window_animations.h"
26 #include "ui/wm/core/window_util.h"
32 // The opacity level that windows will be set to when they are restored.
33 const float kRestoreWindowOpacity
= 1.0f
;
35 aura::Window
* GetTransientRoot(aura::Window
* window
) {
36 while (::wm::GetTransientParent(window
))
37 window
= ::wm::GetTransientParent(window
);
41 // An iterator class that traverses an aura::Window and all of it's transient
43 class TransientDescendantIterator
{
45 // Creates an empty iterator.
46 TransientDescendantIterator();
48 // Copy constructor required for iterator purposes.
49 TransientDescendantIterator(
50 const TransientDescendantIterator
& other
) = default;
52 // Iterates over |root_window| and all of its transient descendants.
53 // Note |root_window| must not have a transient parent.
54 explicit TransientDescendantIterator(aura::Window
* root_window
);
56 // Prefix increment operator. This assumes there are more items (i.e.
57 // *this != TransientDescendantIterator()).
58 const TransientDescendantIterator
& operator++();
60 // Comparison for STL-based loops.
61 bool operator!=(const TransientDescendantIterator
& other
) const;
63 // Dereference operator for STL-compatible iterators.
64 aura::Window
* operator*() const;
67 // The current window that |this| refers to. A NULL |current_window_| denotes
68 // an empty iterator and is used as the last possible value in the traversal.
69 aura::Window
* current_window_
;
71 // Explicit assignment operator defined because an explicit copy constructor
72 // is needed and therefore the DISALLOW_COPY_AND_ASSIGN macro cannot be used.
73 TransientDescendantIterator
& operator=(
74 const TransientDescendantIterator
& other
) = default;
77 // Provides a virtual container implementing begin() and end() for a sequence of
78 // TransientDescendantIterators. This can be used in range-based for loops.
79 class TransientDescendantIteratorRange
{
81 explicit TransientDescendantIteratorRange(
82 const TransientDescendantIterator
& begin
);
84 // Copy constructor required for iterator purposes.
85 TransientDescendantIteratorRange(
86 const TransientDescendantIteratorRange
& other
) = default;
88 const TransientDescendantIterator
& begin() const { return begin_
; }
89 const TransientDescendantIterator
& end() const { return end_
; }
92 TransientDescendantIterator begin_
;
93 TransientDescendantIterator end_
;
95 // Explicit assignment operator defined because an explicit copy constructor
96 // is needed and therefore the DISALLOW_COPY_AND_ASSIGN macro cannot be used.
97 TransientDescendantIteratorRange
& operator=(
98 const TransientDescendantIteratorRange
& other
) = default;
101 TransientDescendantIterator::TransientDescendantIterator()
102 : current_window_(nullptr) {
105 TransientDescendantIterator::TransientDescendantIterator(
106 aura::Window
* root_window
)
107 : current_window_(root_window
) {
108 DCHECK(!::wm::GetTransientParent(root_window
));
111 // Performs a pre-order traversal of the transient descendants.
112 const TransientDescendantIterator
&
113 TransientDescendantIterator::operator++() {
114 DCHECK(current_window_
);
116 const aura::Window::Windows
& transient_children
=
117 ::wm::GetTransientChildren(current_window_
);
119 if (transient_children
.size() > 0) {
120 current_window_
= transient_children
.front();
122 while (current_window_
) {
123 aura::Window
* parent
= ::wm::GetTransientParent(current_window_
);
125 current_window_
= nullptr;
128 const aura::Window::Windows
& transient_siblings
=
129 ::wm::GetTransientChildren(parent
);
130 aura::Window::Windows::const_iterator iter
= std::find(
131 transient_siblings
.begin(),
132 transient_siblings
.end(),
135 if (iter
!= transient_siblings
.end()) {
136 current_window_
= *iter
;
139 current_window_
= ::wm::GetTransientParent(current_window_
);
145 bool TransientDescendantIterator::operator!=(
146 const TransientDescendantIterator
& other
) const {
147 return current_window_
!= other
.current_window_
;
150 aura::Window
* TransientDescendantIterator::operator*() const {
151 return current_window_
;
154 TransientDescendantIteratorRange::TransientDescendantIteratorRange(
155 const TransientDescendantIterator
& begin
)
159 TransientDescendantIteratorRange
GetTransientTreeIterator(
160 aura::Window
* window
) {
161 return TransientDescendantIteratorRange(
162 TransientDescendantIterator(GetTransientRoot(window
)));
167 ScopedTransformOverviewWindow::ScopedTransformOverviewWindow(
168 aura::Window
* window
)
170 activate_button_(new TransparentActivateWindowButton(
171 window_
->GetRootWindow(), this)),
172 minimized_(window
->GetProperty(aura::client::kShowStateKey
) ==
173 ui::SHOW_STATE_MINIMIZED
),
174 ignored_by_shelf_(wm::GetWindowState(window
)->ignored_by_shelf()),
175 overview_started_(false),
176 original_transform_(window
->layer()->GetTargetTransform()),
177 original_opacity_(window
->layer()->GetTargetOpacity()) {
180 ScopedTransformOverviewWindow::~ScopedTransformOverviewWindow() {
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
,
203 ui::SHOW_STATE_MINIMIZED
);
205 wm::GetWindowState(window_
)->set_ignored_by_shelf(ignored_by_shelf_
);
206 SetOpacity(original_opacity_
);
210 void ScopedTransformOverviewWindow::BeginScopedAnimation(
211 OverviewAnimationType animation_type
,
212 ScopedAnimationSettings
* animation_settings
) {
213 for (const auto& window
: GetTransientTreeIterator(window_
)) {
214 animation_settings
->push_back(
215 new ScopedOverviewAnimationSettings(animation_type
, window
));
219 bool ScopedTransformOverviewWindow::Contains(const aura::Window
* target
) const {
220 for (const auto& window
: GetTransientTreeIterator(window_
)) {
221 if (window
->Contains(target
))
227 gfx::Rect
ScopedTransformOverviewWindow::GetTargetBoundsInScreen() const {
229 for (const auto& window
: GetTransientTreeIterator(window_
)) {
230 bounds
.Union(ScreenUtil::ConvertRectToScreen(window
->parent(),
231 window
->GetTargetBounds()));
236 void ScopedTransformOverviewWindow::RestoreWindow() {
237 if (minimized_
&& window_
->GetProperty(aura::client::kShowStateKey
) ==
238 ui::SHOW_STATE_MINIMIZED
) {
243 void ScopedTransformOverviewWindow::RestoreWindowOnExit() {
245 original_transform_
= gfx::Transform();
246 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::Select() {
306 wm::GetWindowState(window_
)->Activate();
309 void ScopedTransformOverviewWindow::Close() {
310 aura::Window
* window
= GetTransientRoot(window_
);
311 views::Widget::GetWidgetForNativeView(window
)->Close();
314 void ScopedTransformOverviewWindow::PrepareForOverview() {
315 DCHECK(!overview_started_
);
316 overview_started_
= true;
317 wm::GetWindowState(window_
)->set_ignored_by_shelf(true);