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/window_selector_panels.h"
6
7 #include "ash/screen_util.h"
8 #include "ash/shell.h"
9 #include "ash/shell_window_ids.h"
10 #include "ash/wm/overview/scoped_transform_overview_window.h"
11 #include "ash/wm/overview/transparent_activate_window_button.h"
12 #include "ash/wm/panels/panel_layout_manager.h"
13 #include "ash/wm/window_util.h"
14 #include "ui/aura/window.h"
15 #include "ui/compositor/layer.h"
16 #include "ui/compositor/layer_animation_observer.h"
17 #include "ui/compositor/layer_animation_sequence.h"
18 #include "ui/views/controls/button/button.h"
19
20 namespace ash {
21
22 namespace {
23
24 // This class extends ScopedTransformOverviewMode to hide and show the callout
25 // widget for a panel window when entering / leaving overview mode, as well as
26 // to add a transparent button for each panel window.
27 class ScopedTransformPanelWindow : public ScopedTransformOverviewWindow {
28 public:
29 explicit ScopedTransformPanelWindow(aura::Window* window);
30 virtual ~ScopedTransformPanelWindow();
31
32 // ScopedTransformOverviewWindow overrides:
33 virtual void PrepareForOverview() OVERRIDE;
34
35 virtual void SetTransform(
36 aura::Window* root_window,
37 const gfx::Transform& transform,
38 bool animate) OVERRIDE;
39
40 private:
41 // Returns the panel window bounds after the transformation.
42 gfx::Rect GetTransformedBounds();
43
44 scoped_ptr<TransparentActivateWindowButton> window_button_;
45
46 DISALLOW_COPY_AND_ASSIGN(ScopedTransformPanelWindow);
47 };
48
ScopedTransformPanelWindow(aura::Window * window)49 ScopedTransformPanelWindow::ScopedTransformPanelWindow(aura::Window* window)
50 : ScopedTransformOverviewWindow(window) {
51 }
52
~ScopedTransformPanelWindow()53 ScopedTransformPanelWindow::~ScopedTransformPanelWindow() {
54 }
55
PrepareForOverview()56 void ScopedTransformPanelWindow::PrepareForOverview() {
57 ScopedTransformOverviewWindow::PrepareForOverview();
58 window_button_.reset(new TransparentActivateWindowButton(window()));
59 }
60
SetTransform(aura::Window * root_window,const gfx::Transform & transform,bool animate)61 void ScopedTransformPanelWindow::SetTransform(
62 aura::Window* root_window,
63 const gfx::Transform& transform,
64 bool animate) {
65 ScopedTransformOverviewWindow::SetTransform(root_window, transform, animate);
66 window_button_->SetBounds(GetTransformedBounds());
67 }
68
GetTransformedBounds()69 gfx::Rect ScopedTransformPanelWindow::GetTransformedBounds() {
70 gfx::RectF bounds(ScreenUtil::ConvertRectToScreen(
71 window()->GetRootWindow(), window()->layer()->bounds()));
72 gfx::Transform new_transform;
73 new_transform.Translate(bounds.x(),
74 bounds.y());
75 new_transform.PreconcatTransform(window()->layer()->GetTargetTransform());
76 new_transform.Translate(-bounds.x(),
77 -bounds.y());
78 new_transform.TransformRect(&bounds);
79 return ToEnclosingRect(bounds);
80 }
81
82 } // namespace
83
WindowSelectorPanels(aura::Window * panels_root_window)84 WindowSelectorPanels::WindowSelectorPanels(aura::Window* panels_root_window)
85 : panels_root_window_(panels_root_window) {
86 static_cast<PanelLayoutManager*>(
87 Shell::GetContainer(panels_root_window_, kShellWindowId_PanelContainer)->
88 layout_manager())->SetShowCalloutWidgets(false);
89 }
90
~WindowSelectorPanels()91 WindowSelectorPanels::~WindowSelectorPanels() {
92 static_cast<PanelLayoutManager*>(
93 Shell::GetContainer(panels_root_window_, kShellWindowId_PanelContainer)->
94 layout_manager())->SetShowCalloutWidgets(true);
95 }
96
AddWindow(aura::Window * window)97 void WindowSelectorPanels::AddWindow(aura::Window* window) {
98 DCHECK(window->GetRootWindow() == panels_root_window_);
99 transform_windows_.push_back(new ScopedTransformPanelWindow(window));
100 }
101
GetRootWindow()102 aura::Window* WindowSelectorPanels::GetRootWindow() {
103 return transform_windows_.front()->window()->GetRootWindow();
104 }
105
HasSelectableWindow(const aura::Window * window)106 bool WindowSelectorPanels::HasSelectableWindow(const aura::Window* window) {
107 for (WindowList::const_iterator iter = transform_windows_.begin();
108 iter != transform_windows_.end(); ++iter) {
109 if ((*iter)->window() == window)
110 return true;
111 }
112 return false;
113 }
114
Contains(const aura::Window * target)115 bool WindowSelectorPanels::Contains(const aura::Window* target) {
116 for (WindowList::const_iterator iter = transform_windows_.begin();
117 iter != transform_windows_.end(); ++iter) {
118 if ((*iter)->Contains(target))
119 return true;
120 }
121 return false;
122 }
123
RestoreWindowOnExit(aura::Window * window)124 void WindowSelectorPanels::RestoreWindowOnExit(aura::Window* window) {
125 for (WindowList::iterator iter = transform_windows_.begin();
126 iter != transform_windows_.end(); ++iter) {
127 if ((*iter)->Contains(window)) {
128 (*iter)->RestoreWindowOnExit();
129 break;
130 }
131 }
132 }
133
SelectionWindow()134 aura::Window* WindowSelectorPanels::SelectionWindow() {
135 return transform_windows_.front()->window();
136 }
137
RemoveWindow(const aura::Window * window)138 void WindowSelectorPanels::RemoveWindow(const aura::Window* window) {
139 for (WindowList::iterator iter = transform_windows_.begin();
140 iter != transform_windows_.end(); ++iter) {
141 if ((*iter)->window() == window) {
142 (*iter)->OnWindowDestroyed();
143 transform_windows_.erase(iter);
144 break;
145 }
146 }
147 WindowSelectorItem::RemoveWindow(window);
148 }
149
empty() const150 bool WindowSelectorPanels::empty() const {
151 return transform_windows_.empty();
152 }
153
PrepareForOverview()154 void WindowSelectorPanels::PrepareForOverview() {
155 // |panel_windows| will hold all the windows in the panel container, sorted
156 // according to their stacking order.
157 const aura::Window::Windows panels =
158 transform_windows_[0]->window()->parent()->children();
159
160 // Call PrepareForOverview() in the reverse stacking order so that the
161 // transparent windows that handle the events are in the correct stacking
162 // order.
163 size_t transformed_windows = 0;
164 for (aura::Window::Windows::const_reverse_iterator iter = panels.rbegin();
165 iter != panels.rend(); iter++) {
166 for (size_t j = 0; j < transform_windows_.size(); ++j) {
167 if (transform_windows_[j]->window() == (*iter)) {
168 transform_windows_[j]->PrepareForOverview();
169 transformed_windows++;
170 }
171 }
172 }
173 DCHECK(transformed_windows == transform_windows_.size());
174 }
175
SetItemBounds(aura::Window * root_window,const gfx::Rect & target_bounds,bool animate)176 void WindowSelectorPanels::SetItemBounds(aura::Window* root_window,
177 const gfx::Rect& target_bounds,
178 bool animate) {
179 gfx::Rect bounding_rect;
180 for (WindowList::iterator iter = transform_windows_.begin();
181 iter != transform_windows_.end(); ++iter) {
182 bounding_rect.Union((*iter)->GetBoundsInScreen());
183 }
184 set_bounds(ScopedTransformOverviewWindow::
185 ShrinkRectToFitPreservingAspectRatio(bounding_rect, target_bounds));
186 gfx::Transform bounding_transform =
187 ScopedTransformOverviewWindow::GetTransformForRect(bounding_rect,
188 bounds());
189 for (WindowList::iterator iter = transform_windows_.begin();
190 iter != transform_windows_.end(); ++iter) {
191 gfx::Transform transform;
192 gfx::Rect bounds = (*iter)->GetBoundsInScreen();
193 transform.Translate(bounding_rect.x() - bounds.x(),
194 bounding_rect.y() - bounds.y());
195 transform.PreconcatTransform(bounding_transform);
196 transform.Translate(bounds.x() - bounding_rect.x(),
197 bounds.y() - bounding_rect.y());
198 (*iter)->SetTransform(root_window, transform, animate);
199 }
200 }
201
202 } // namespace ash
203