OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "ash/wm/window_selector.h" | 5 #include "ash/wm/window_selector.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 | 8 |
9 #include "ash/screen_ash.h" | 9 #include "ash/screen_ash.h" |
10 #include "ash/shell.h" | 10 #include "ash/shell.h" |
11 #include "ash/shell_window_ids.h" | 11 #include "ash/shell_window_ids.h" |
12 #include "ash/wm/window_selector_delegate.h" | 12 #include "ash/wm/window_selector_delegate.h" |
13 #include "ash/wm/window_util.h" | 13 #include "ash/wm/window_util.h" |
14 #include "base/memory/scoped_ptr.h" | 14 #include "base/memory/scoped_ptr.h" |
15 #include "third_party/skia/include/core/SkColor.h" | |
16 #include "ui/aura/client/aura_constants.h" | 15 #include "ui/aura/client/aura_constants.h" |
17 #include "ui/aura/client/screen_position_client.h" | |
18 #include "ui/aura/root_window.h" | 16 #include "ui/aura/root_window.h" |
19 #include "ui/aura/window.h" | 17 #include "ui/aura/window.h" |
20 #include "ui/base/events/event.h" | 18 #include "ui/base/events/event.h" |
21 #include "ui/compositor/layer_animation_observer.h" | |
22 #include "ui/compositor/scoped_layer_animation_settings.h" | 19 #include "ui/compositor/scoped_layer_animation_settings.h" |
23 #include "ui/gfx/display.h" | |
24 #include "ui/gfx/interpolated_transform.h" | 20 #include "ui/gfx/interpolated_transform.h" |
25 #include "ui/gfx/transform_util.h" | 21 #include "ui/gfx/transform_util.h" |
26 #include "ui/views/corewm/shadow_types.h" | |
27 #include "ui/views/corewm/window_animations.h" | 22 #include "ui/views/corewm/window_animations.h" |
28 #include "ui/views/corewm/window_util.h" | |
29 #include "ui/views/widget/widget.h" | |
30 | 23 |
31 namespace ash { | 24 namespace ash { |
32 | 25 |
33 namespace { | 26 namespace { |
34 | 27 |
35 const float kCardAspectRatio = 4.0f / 3.0f; | 28 const float kCardAspectRatio = 4.0f / 3.0f; |
36 const int kWindowMargin = 30; | 29 const int kWindowMargin = 20; |
37 const int kMinCardsMajor = 3; | 30 const int kMinCardsMajor = 3; |
38 const int kOverviewTransitionMilliseconds = 100; | 31 const int kOverviewTransitionMilliseconds = 100; |
39 const SkColor kWindowSelectorSelectionColor = SK_ColorBLACK; | |
40 const float kWindowSelectorSelectionOpacity = 0.5f; | |
41 const int kWindowSelectorSelectionPadding = 15; | |
42 | 32 |
43 // Creates a copy of |window| with |recreated_layer| in the |target_root|. | 33 // Applies a transform to |window| to fit within |target_bounds| while |
44 views::Widget* CreateCopyOfWindow(aura::RootWindow* target_root, | 34 // maintaining its aspect ratio. |
45 aura::Window* src_window, | 35 void TransformWindowToFitBounds(aura::Window* window, |
46 ui::Layer* recreated_layer) { | 36 const gfx::Rect& target_bounds) { |
47 views::Widget* widget = new views::Widget; | 37 const gfx::Rect bounds = window->bounds(); |
48 views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP); | |
49 params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; | |
50 params.parent = src_window->parent(); | |
51 params.can_activate = false; | |
52 params.keep_on_top = true; | |
53 widget->set_focus_on_creation(false); | |
54 widget->Init(params); | |
55 widget->SetVisibilityChangedAnimationsEnabled(false); | |
56 std::string name = src_window->name() + " (Copy)"; | |
57 widget->GetNativeWindow()->SetName(name); | |
58 views::corewm::SetShadowType(widget->GetNativeWindow(), | |
59 views::corewm::SHADOW_TYPE_RECTANGULAR); | |
60 | |
61 // Set the bounds in the target root window. | |
62 gfx::Display target_display = | |
63 Shell::GetScreen()->GetDisplayNearestWindow(target_root); | |
64 aura::client::ScreenPositionClient* screen_position_client = | |
65 aura::client::GetScreenPositionClient(src_window->GetRootWindow()); | |
66 if (screen_position_client && target_display.is_valid()) { | |
67 screen_position_client->SetBounds(widget->GetNativeWindow(), | |
68 src_window->GetBoundsInScreen(), target_display); | |
69 } else { | |
70 widget->SetBounds(src_window->GetBoundsInScreen()); | |
71 } | |
72 widget->StackAbove(src_window); | |
73 | |
74 // Move the |recreated_layer| to the newly created window. | |
75 recreated_layer->set_delegate(src_window->layer()->delegate()); | |
76 gfx::Rect layer_bounds = recreated_layer->bounds(); | |
77 layer_bounds.set_origin(gfx::Point(0, 0)); | |
78 recreated_layer->SetBounds(layer_bounds); | |
79 recreated_layer->SetVisible(false); | |
80 recreated_layer->parent()->Remove(recreated_layer); | |
81 | |
82 aura::Window* window = widget->GetNativeWindow(); | |
83 recreated_layer->SetVisible(true); | |
84 window->layer()->Add(recreated_layer); | |
85 window->layer()->StackAtTop(recreated_layer); | |
86 window->layer()->SetOpacity(1); | |
87 window->Show(); | |
88 return widget; | |
89 } | |
90 | |
91 // An observer which closes the widget and deletes the layer after an | |
92 // animation finishes. | |
93 class CleanupWidgetAfterAnimationObserver : public ui::LayerAnimationObserver { | |
94 public: | |
95 CleanupWidgetAfterAnimationObserver(views::Widget* widget, ui::Layer* layer); | |
96 | |
97 virtual void OnLayerAnimationEnded( | |
98 ui::LayerAnimationSequence* sequence) OVERRIDE; | |
99 virtual void OnLayerAnimationAborted( | |
100 ui::LayerAnimationSequence* sequence) OVERRIDE; | |
101 virtual void OnLayerAnimationScheduled( | |
102 ui::LayerAnimationSequence* sequence) OVERRIDE; | |
103 | |
104 protected: | |
105 virtual ~CleanupWidgetAfterAnimationObserver(); | |
106 | |
107 private: | |
108 views::Widget* widget_; | |
109 ui::Layer* layer_; | |
110 | |
111 DISALLOW_COPY_AND_ASSIGN(CleanupWidgetAfterAnimationObserver); | |
112 }; | |
113 | |
114 CleanupWidgetAfterAnimationObserver::CleanupWidgetAfterAnimationObserver( | |
115 views::Widget* widget, | |
116 ui::Layer* layer) | |
117 : widget_(widget), | |
118 layer_(layer) { | |
119 widget_->GetNativeWindow()->layer()->GetAnimator()->AddObserver(this); | |
120 } | |
121 | |
122 void CleanupWidgetAfterAnimationObserver::OnLayerAnimationEnded( | |
123 ui::LayerAnimationSequence* sequence) { | |
124 delete this; | |
125 } | |
126 | |
127 void CleanupWidgetAfterAnimationObserver::OnLayerAnimationAborted( | |
128 ui::LayerAnimationSequence* sequence) { | |
129 delete this; | |
130 } | |
131 | |
132 void CleanupWidgetAfterAnimationObserver::OnLayerAnimationScheduled( | |
133 ui::LayerAnimationSequence* sequence) { | |
134 } | |
135 | |
136 CleanupWidgetAfterAnimationObserver::~CleanupWidgetAfterAnimationObserver() { | |
137 widget_->GetNativeWindow()->layer()->GetAnimator()->RemoveObserver(this); | |
138 widget_->Close(); | |
139 widget_ = NULL; | |
140 if (layer_) { | |
141 views::corewm::DeepDeleteLayers(layer_); | |
142 layer_ = NULL; | |
143 } | |
144 } | |
145 | |
146 // The animation settings used for window selector animations. | |
147 class WindowSelectorAnimationSettings | |
148 : public ui::ScopedLayerAnimationSettings { | |
149 public: | |
150 WindowSelectorAnimationSettings(aura::Window* window) : | |
151 ui::ScopedLayerAnimationSettings(window->layer()->GetAnimator()) { | |
152 SetPreemptionStrategy( | |
153 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); | |
154 SetTransitionDuration( | |
155 base::TimeDelta::FromMilliseconds(kOverviewTransitionMilliseconds)); | |
156 } | |
157 | |
158 virtual ~WindowSelectorAnimationSettings() { | |
159 } | |
160 }; | |
161 | |
162 } // namespace | |
163 | |
164 // TODO(flackr): Split up into separate file under subdirectory in ash/wm. | |
165 class WindowSelectorWindow { | |
166 public: | |
167 explicit WindowSelectorWindow(aura::Window* window); | |
168 virtual ~WindowSelectorWindow(); | |
169 | |
170 aura::Window* window() { return window_; } | |
171 const aura::Window* window() const { return window_; } | |
172 | |
173 // Returns true if this window selector window contains the |target|. This is | |
174 // used to determine if an event targetted this window. | |
175 bool Contains(const aura::Window* target) const; | |
176 | |
177 // Restores this window on exit rather than returning it to a minimized state | |
178 // if it was minimized on entering overview mode. | |
179 void RestoreWindowOnExit(); | |
180 | |
181 // Informs the WindowSelectorWindow that the window being watched was | |
182 // destroyed. This resets the internal window pointer to avoid calling | |
183 // anything on the window at destruction time. | |
184 void OnWindowDestroyed(); | |
185 | |
186 // Applies a transform to the window to fit within |target_bounds| while | |
187 // maintaining its aspect ratio. | |
188 void TransformToFitBounds(aura::RootWindow* root_window, | |
189 const gfx::Rect& target_bounds); | |
190 | |
191 gfx::Rect bounds() { return fit_bounds_; } | |
192 | |
193 private: | |
194 // A weak pointer to the real window in the overview. | |
195 aura::Window* window_; | |
196 | |
197 // A copy of the window used to transition the window to another root. | |
198 views::Widget* window_copy_; | |
199 | |
200 // A weak pointer to a deep copy of the window's layers. | |
201 ui::Layer* layer_; | |
202 | |
203 // If true, the window was minimized and should be restored if the window | |
204 // was not selected. | |
205 bool minimized_; | |
206 | |
207 // The original transform of the window before entering overview mode. | |
208 gfx::Transform original_transform_; | |
209 | |
210 // The bounds this window is fit to. | |
211 gfx::Rect fit_bounds_; | |
212 | |
213 DISALLOW_COPY_AND_ASSIGN(WindowSelectorWindow); | |
214 }; | |
215 | |
216 WindowSelectorWindow::WindowSelectorWindow(aura::Window* window) | |
217 : window_(window), | |
218 window_copy_(NULL), | |
219 layer_(NULL), | |
220 minimized_(window->GetProperty(aura::client::kShowStateKey) == | |
221 ui::SHOW_STATE_MINIMIZED), | |
222 original_transform_(window->layer()->transform()) { | |
223 if (minimized_) | |
224 window_->Show(); | |
225 } | |
226 | |
227 WindowSelectorWindow::~WindowSelectorWindow() { | |
228 if (window_) { | |
229 WindowSelectorAnimationSettings animation_settings(window_); | |
230 gfx::Transform transform; | |
231 window_->SetTransform(original_transform_); | |
232 if (minimized_) { | |
233 // Setting opacity 0 and visible false ensures that the property change | |
234 // to SHOW_STATE_MINIMIZED will not animate the window from its original | |
235 // bounds to the minimized position. | |
236 window_->layer()->SetOpacity(0); | |
237 window_->layer()->SetVisible(false); | |
238 window_->SetProperty(aura::client::kShowStateKey, | |
239 ui::SHOW_STATE_MINIMIZED); | |
240 } | |
241 } | |
242 // If a copy of the window was created, clean it up. | |
243 if (window_copy_) { | |
244 if (window_) { | |
245 // If the initial window wasn't destroyed, the copy needs to be animated | |
246 // out. CleanupWidgetAfterAnimationObserver will destroy the widget and | |
247 // layer after the animation is complete. | |
248 new CleanupWidgetAfterAnimationObserver(window_copy_, layer_); | |
249 WindowSelectorAnimationSettings animation_settings( | |
250 window_copy_->GetNativeWindow()); | |
251 window_copy_->GetNativeWindow()->SetTransform(original_transform_); | |
252 } else { | |
253 window_copy_->Close(); | |
254 if (layer_) | |
255 views::corewm::DeepDeleteLayers(layer_); | |
256 } | |
257 window_copy_ = NULL; | |
258 layer_ = NULL; | |
259 } | |
260 } | |
261 | |
262 bool WindowSelectorWindow::Contains(const aura::Window* window) const { | |
263 if (window_copy_ && window_copy_->GetNativeWindow()->Contains(window)) | |
264 return true; | |
265 return window_->Contains(window); | |
266 } | |
267 | |
268 void WindowSelectorWindow::RestoreWindowOnExit() { | |
269 minimized_ = false; | |
270 original_transform_ = gfx::Transform(); | |
271 } | |
272 | |
273 void WindowSelectorWindow::OnWindowDestroyed() { | |
274 window_ = NULL; | |
275 } | |
276 | |
277 void WindowSelectorWindow::TransformToFitBounds( | |
278 aura::RootWindow* root_window, | |
279 const gfx::Rect& target_bounds) { | |
280 fit_bounds_ = target_bounds; | |
281 const gfx::Rect bounds = window_->GetBoundsInScreen(); | |
282 float scale = std::min(1.0f, | 38 float scale = std::min(1.0f, |
283 std::min(static_cast<float>(target_bounds.width()) / bounds.width(), | 39 std::min(static_cast<float>(target_bounds.width()) / bounds.width(), |
284 static_cast<float>(target_bounds.height()) / bounds.height())); | 40 static_cast<float>(target_bounds.height()) / bounds.height())); |
285 gfx::Transform transform; | 41 gfx::Transform transform; |
286 gfx::Vector2d offset( | 42 gfx::Vector2d offset( |
287 0.5 * (target_bounds.width() - scale * bounds.width()), | 43 0.5 * (target_bounds.width() - scale * bounds.width()), |
288 0.5 * (target_bounds.height() - scale * bounds.height())); | 44 0.5 * (target_bounds.height() - scale * bounds.height())); |
289 transform.Translate(target_bounds.x() - bounds.x() + offset.x(), | 45 transform.Translate(target_bounds.x() - bounds.x() + offset.x(), |
290 target_bounds.y() - bounds.y() + offset.y()); | 46 target_bounds.y() - bounds.y() + offset.y()); |
291 transform.Scale(scale, scale); | 47 transform.Scale(scale, scale); |
292 if (root_window != window_->GetRootWindow()) { | 48 // TODO(flackr): The window bounds or transform could change during overview |
293 if (!window_copy_) { | 49 // mode. WindowSelector should create a copy of the window so that the |
294 DCHECK(!layer_); | 50 // displayed windows are not affected by changes happening in the background. |
295 layer_ = views::corewm::RecreateWindowLayers(window_, true); | 51 // This will be necessary for alt-tab cycling as well, as some windows will |
296 window_copy_ = CreateCopyOfWindow(root_window, window_, layer_); | 52 // be coming from other displays: http://crbug.com/263481. |
297 } | 53 window->SetTransform(transform); |
298 WindowSelectorAnimationSettings animation_settings( | |
299 window_copy_->GetNativeWindow()); | |
300 window_copy_->GetNativeWindow()->SetTransform(transform); | |
301 } | |
302 WindowSelectorAnimationSettings animation_settings(window_); | |
303 window_->SetTransform(transform); | |
304 } | 54 } |
305 | 55 |
306 // A comparator for locating a given target window. | 56 } // namespace |
307 struct WindowSelectorWindowComparator | |
308 : public std::unary_function<WindowSelectorWindow*, bool> { | |
309 explicit WindowSelectorWindowComparator(const aura::Window* target_window) | |
310 : target(target_window) { | |
311 } | |
312 | |
313 bool operator()(const WindowSelectorWindow* window) const { | |
314 return target == window->window(); | |
315 } | |
316 | |
317 const aura::Window* target; | |
318 }; | |
319 | 57 |
320 WindowSelector::WindowSelector(const WindowList& windows, | 58 WindowSelector::WindowSelector(const WindowList& windows, |
321 WindowSelector::Mode mode, | |
322 WindowSelectorDelegate* delegate) | 59 WindowSelectorDelegate* delegate) |
323 : mode_(mode), | 60 : delegate_(delegate) { |
324 delegate_(delegate), | |
325 selected_window_(0), | |
326 selection_root_(NULL) { | |
327 DCHECK(delegate_); | 61 DCHECK(delegate_); |
328 for (size_t i = 0; i < windows.size(); ++i) { | 62 for (size_t i = 0; i < windows.size(); ++i) { |
329 windows[i]->AddObserver(this); | 63 windows[i]->AddObserver(this); |
330 windows_.push_back(new WindowSelectorWindow(windows[i])); | 64 WindowDetails details; |
| 65 details.window = windows[i]; |
| 66 details.minimized = windows[i]->GetProperty(aura::client::kShowStateKey) == |
| 67 ui::SHOW_STATE_MINIMIZED; |
| 68 details.original_transform = windows[i]->layer()->transform(); |
| 69 if (details.minimized) { |
| 70 windows[i]->Show(); |
| 71 } |
| 72 windows_.push_back(details); |
331 } | 73 } |
332 if (mode == WindowSelector::CYCLE) | |
333 selection_root_ = ash::Shell::GetActiveRootWindow(); | |
334 PositionWindows(); | 74 PositionWindows(); |
335 ash::Shell::GetInstance()->AddPreTargetHandler(this); | 75 ash::Shell::GetInstance()->AddPreTargetHandler(this); |
336 } | 76 } |
337 | 77 |
338 WindowSelector::~WindowSelector() { | 78 WindowSelector::~WindowSelector() { |
339 for (size_t i = 0; i < windows_.size(); i++) { | 79 for (size_t i = 0; i < windows_.size(); i++) { |
340 windows_[i]->window()->RemoveObserver(this); | 80 ui::ScopedLayerAnimationSettings animation_settings( |
| 81 windows_[i].window->layer()->GetAnimator()); |
| 82 animation_settings.SetPreemptionStrategy( |
| 83 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); |
| 84 animation_settings.SetTransitionDuration( |
| 85 base::TimeDelta::FromMilliseconds(kOverviewTransitionMilliseconds)); |
| 86 windows_[i].window->RemoveObserver(this); |
| 87 gfx::Transform transform; |
| 88 windows_[i].window->SetTransform(windows_[i].original_transform); |
| 89 if (windows_[i].minimized) { |
| 90 // Setting opacity 0 and visible false ensures that the property change |
| 91 // to SHOW_STATE_MINIMIZED will not animate the window from its original |
| 92 // bounds to the minimized position. |
| 93 windows_[i].window->layer()->SetOpacity(0); |
| 94 windows_[i].window->layer()->SetVisible(false); |
| 95 windows_[i].window->SetProperty(aura::client::kShowStateKey, |
| 96 ui::SHOW_STATE_MINIMIZED); |
| 97 } |
341 } | 98 } |
342 ash::Shell::GetInstance()->RemovePreTargetHandler(this); | 99 ash::Shell::GetInstance()->RemovePreTargetHandler(this); |
343 } | 100 } |
344 | 101 |
345 void WindowSelector::Step(WindowSelector::Direction direction) { | |
346 DCHECK(windows_.size() > 0); | |
347 if (!selection_widget_) | |
348 InitializeSelectionWidget(); | |
349 selected_window_ = (selected_window_ + windows_.size() + | |
350 (direction == WindowSelector::FORWARD ? 1 : -1)) % windows_.size(); | |
351 UpdateSelectionLocation(true); | |
352 } | |
353 | |
354 void WindowSelector::SelectWindow() { | |
355 delegate_->OnWindowSelected(windows_[selected_window_]->window()); | |
356 } | |
357 | |
358 void WindowSelector::OnEvent(ui::Event* event) { | 102 void WindowSelector::OnEvent(ui::Event* event) { |
359 ui::EventHandler::OnEvent(event); | 103 // TODO(flackr): This will prevent anything else from working while overview |
360 | 104 // mode is active. This should only stop events from being sent to the windows |
361 // If the event is targetted at any of the windows in the overview, then | 105 // in the overview but still allow interaction with the launcher / tray and |
362 // prevent it from propagating. | 106 // hotkeys http://crbug.com/264289. |
363 aura::Window* target = static_cast<aura::Window*>(event->target()); | 107 EventHandler::OnEvent(event); |
364 for (size_t i = 0; i < windows_.size(); ++i) { | 108 event->StopPropagation(); |
365 if (windows_[i]->Contains(target)) { | |
366 event->StopPropagation(); | |
367 break; | |
368 } | |
369 } | |
370 } | 109 } |
371 | 110 |
372 void WindowSelector::OnMouseEvent(ui::MouseEvent* event) { | 111 void WindowSelector::OnMouseEvent(ui::MouseEvent* event) { |
373 if (event->type() != ui::ET_MOUSE_RELEASED) | 112 if (event->type() != ui::ET_MOUSE_RELEASED) |
374 return; | 113 return; |
375 WindowSelectorWindow* target = GetEventTarget(event); | 114 aura::Window* target = static_cast<aura::Window*>(event->target()); |
376 if (!target) | 115 if (!target->HitTest(event->location())) |
377 return; | 116 return; |
378 | 117 |
379 HandleSelectionEvent(target); | 118 HandleSelectionEvent(event); |
380 } | 119 } |
381 | 120 |
382 void WindowSelector::OnGestureEvent(ui::GestureEvent* event) { | 121 void WindowSelector::OnGestureEvent(ui::GestureEvent* event) { |
383 if (event->type() != ui::ET_GESTURE_TAP) | 122 if (event->type() != ui::ET_GESTURE_TAP) |
384 return; | 123 return; |
385 WindowSelectorWindow* target = GetEventTarget(event); | 124 HandleSelectionEvent(event); |
386 if (!target) | |
387 return; | |
388 | |
389 HandleSelectionEvent(target); | |
390 } | 125 } |
391 | 126 |
392 void WindowSelector::OnWindowDestroyed(aura::Window* window) { | 127 void WindowSelector::OnWindowDestroyed(aura::Window* window) { |
393 ScopedVector<WindowSelectorWindow>::iterator iter = | 128 std::vector<WindowDetails>::iterator iter = |
394 std::find_if(windows_.begin(), windows_.end(), | 129 std::find(windows_.begin(), windows_.end(), window); |
395 WindowSelectorWindowComparator(window)); | |
396 DCHECK(iter != windows_.end()); | 130 DCHECK(iter != windows_.end()); |
397 size_t deleted_index = iter - windows_.begin(); | |
398 (*iter)->OnWindowDestroyed(); | |
399 windows_.erase(iter); | 131 windows_.erase(iter); |
400 if (windows_.empty()) { | 132 if (windows_.empty()) { |
401 delegate_->OnSelectionCanceled(); | 133 delegate_->OnSelectionCanceled(); |
402 return; | 134 return; |
403 } | 135 } |
404 if (selected_window_ >= deleted_index) { | |
405 if (selected_window_ > deleted_index) | |
406 selected_window_--; | |
407 selected_window_ = selected_window_ % windows_.size(); | |
408 UpdateSelectionLocation(true); | |
409 } | |
410 | 136 |
411 PositionWindows(); | 137 PositionWindows(); |
412 } | 138 } |
413 | 139 |
414 WindowSelectorWindow* WindowSelector::GetEventTarget(ui::LocatedEvent* event) { | 140 void WindowSelector::HandleSelectionEvent(ui::Event* event) { |
415 aura::Window* target = static_cast<aura::Window*>(event->target()); | 141 aura::Window* target = static_cast<aura::Window*>(event->target()); |
416 // If the target window doesn't actually contain the event location (i.e. | |
417 // mouse down over the window and mouse up elsewhere) then do not select the | |
418 // window. | |
419 if (!target->HitTest(event->location())) | |
420 return NULL; | |
421 | 142 |
422 for (size_t i = 0; i < windows_.size(); i++) { | 143 for (size_t i = 0; i < windows_.size(); i++) { |
423 if (windows_[i]->Contains(target)) | 144 if (windows_[i].window->Contains(target)) { |
424 return windows_[i]; | 145 // The selected window should not be minimized when window selection is |
| 146 // ended. |
| 147 windows_[i].minimized = false; |
| 148 windows_[i].original_transform = gfx::Transform(); |
| 149 |
| 150 // The delegate may delete the WindowSelector, assume the object may no |
| 151 // longer valid after calling this. |
| 152 delegate_->OnWindowSelected(windows_[i].window); |
| 153 return; |
| 154 } |
425 } | 155 } |
426 return NULL; | |
427 } | |
428 | |
429 void WindowSelector::HandleSelectionEvent(WindowSelectorWindow* target) { | |
430 // The selected window should not be minimized when window selection is | |
431 // ended. | |
432 target->RestoreWindowOnExit(); | |
433 delegate_->OnWindowSelected(target->window()); | |
434 } | 156 } |
435 | 157 |
436 void WindowSelector::PositionWindows() { | 158 void WindowSelector::PositionWindows() { |
437 if (selection_root_) { | 159 Shell::RootWindowList root_window_list = Shell::GetAllRootWindows(); |
438 DCHECK_EQ(mode_, CYCLE); | 160 for (size_t i = 0; i < root_window_list.size(); ++i) { |
439 std::vector<WindowSelectorWindow*> windows; | 161 PositionWindowsOnRoot(root_window_list[i]); |
440 for (size_t i = 0; i < windows_.size(); ++i) | |
441 windows.push_back(windows_[i]); | |
442 PositionWindowsOnRoot(selection_root_, windows); | |
443 } else { | |
444 DCHECK_EQ(mode_, OVERVIEW); | |
445 Shell::RootWindowList root_window_list = Shell::GetAllRootWindows(); | |
446 for (size_t i = 0; i < root_window_list.size(); ++i) | |
447 PositionWindowsFromRoot(root_window_list[i]); | |
448 } | 162 } |
449 } | 163 } |
450 | 164 |
451 void WindowSelector::PositionWindowsFromRoot(aura::RootWindow* root_window) { | 165 void WindowSelector::PositionWindowsOnRoot(aura::RootWindow* root_window) { |
452 std::vector<WindowSelectorWindow*> windows; | 166 gfx::Size window_size; |
| 167 gfx::Rect total_bounds = ScreenAsh::GetDisplayWorkAreaBoundsInParent( |
| 168 Shell::GetContainer(root_window, |
| 169 internal::kShellWindowId_DefaultContainer)); |
| 170 |
| 171 std::vector<WindowDetails> windows; |
453 for (size_t i = 0; i < windows_.size(); ++i) { | 172 for (size_t i = 0; i < windows_.size(); ++i) { |
454 if (windows_[i]->window()->GetRootWindow() == root_window) | 173 if (windows_[i].window->GetRootWindow() == root_window) |
455 windows.push_back(windows_[i]); | 174 windows.push_back(windows_[i]); |
456 } | 175 } |
457 PositionWindowsOnRoot(root_window, windows); | |
458 } | |
459 | |
460 void WindowSelector::PositionWindowsOnRoot( | |
461 aura::RootWindow* root_window, | |
462 const std::vector<WindowSelectorWindow*>& windows) { | |
463 if (windows.empty()) | 176 if (windows.empty()) |
464 return; | 177 return; |
465 | 178 |
466 gfx::Size window_size; | |
467 gfx::Rect total_bounds = ScreenAsh::ConvertRectToScreen(root_window, | |
468 ScreenAsh::GetDisplayWorkAreaBoundsInParent( | |
469 Shell::GetContainer(root_window, | |
470 internal::kShellWindowId_DefaultContainer))); | |
471 | |
472 // Find the minimum number of windows per row that will fit all of the | 179 // Find the minimum number of windows per row that will fit all of the |
473 // windows on screen. | 180 // windows on screen. |
474 size_t columns = std::max( | 181 size_t columns = std::max( |
475 total_bounds.width() > total_bounds.height() ? kMinCardsMajor : 1, | 182 total_bounds.width() > total_bounds.height() ? kMinCardsMajor : 1, |
476 static_cast<int>(ceil(sqrt(total_bounds.width() * windows.size() / | 183 static_cast<int>(ceil(sqrt(total_bounds.width() * windows.size() / |
477 (kCardAspectRatio * total_bounds.height()))))); | 184 (kCardAspectRatio * total_bounds.height()))))); |
478 size_t rows = ((windows.size() + columns - 1) / columns); | 185 size_t rows = ((windows.size() + columns - 1) / columns); |
479 window_size.set_width(std::min( | 186 window_size.set_width(std::min( |
480 static_cast<int>(total_bounds.width() / columns), | 187 static_cast<int>(total_bounds.width() / columns), |
481 static_cast<int>(total_bounds.height() * kCardAspectRatio / rows))); | 188 static_cast<int>(total_bounds.height() * kCardAspectRatio / rows))); |
482 window_size.set_height(window_size.width() / kCardAspectRatio); | 189 window_size.set_height(window_size.width() / kCardAspectRatio); |
483 | 190 |
484 // Calculate the X and Y offsets necessary to center the grid. | 191 // Calculate the X and Y offsets necessary to center the grid. |
485 int x_offset = total_bounds.x() + ((windows.size() >= columns ? 0 : | 192 int x_offset = total_bounds.x() + ((windows.size() >= columns ? 0 : |
486 (columns - windows.size()) * window_size.width()) + | 193 (columns - windows.size()) * window_size.width()) + |
487 (total_bounds.width() - columns * window_size.width())) / 2; | 194 (total_bounds.width() - columns * window_size.width())) / 2; |
488 int y_offset = total_bounds.y() + (total_bounds.height() - | 195 int y_offset = total_bounds.y() + (total_bounds.height() - |
489 rows * window_size.height()) / 2; | 196 rows * window_size.height()) / 2; |
490 for (size_t i = 0; i < windows.size(); ++i) { | 197 for (size_t i = 0; i < windows.size(); ++i) { |
| 198 ui::ScopedLayerAnimationSettings animation_settings( |
| 199 windows[i].window->layer()->GetAnimator()); |
| 200 animation_settings.SetPreemptionStrategy( |
| 201 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); |
| 202 animation_settings.SetTransitionDuration( |
| 203 base::TimeDelta::FromMilliseconds(kOverviewTransitionMilliseconds)); |
491 gfx::Transform transform; | 204 gfx::Transform transform; |
492 int column = i % columns; | 205 int column = i % columns; |
493 int row = i / columns; | 206 int row = i / columns; |
494 gfx::Rect target_bounds(window_size.width() * column + x_offset, | 207 gfx::Rect target_bounds(window_size.width() * column + x_offset, |
495 window_size.height() * row + y_offset, | 208 window_size.height() * row + y_offset, |
496 window_size.width(), | 209 window_size.width(), |
497 window_size.height()); | 210 window_size.height()); |
498 target_bounds.Inset(kWindowMargin, kWindowMargin); | 211 target_bounds.Inset(kWindowMargin, kWindowMargin); |
499 windows[i]->TransformToFitBounds(root_window, target_bounds); | 212 TransformWindowToFitBounds(windows[i].window, target_bounds); |
500 } | |
501 } | |
502 | |
503 void WindowSelector::InitializeSelectionWidget() { | |
504 selection_widget_.reset(new views::Widget); | |
505 views::Widget::InitParams params; | |
506 params.type = views::Widget::InitParams::TYPE_POPUP; | |
507 params.can_activate = false; | |
508 params.keep_on_top = false; | |
509 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; | |
510 params.opacity = views::Widget::InitParams::OPAQUE_WINDOW; | |
511 params.parent = Shell::GetContainer( | |
512 selection_root_, | |
513 internal::kShellWindowId_DefaultContainer); | |
514 params.accept_events = false; | |
515 selection_widget_->set_focus_on_creation(false); | |
516 selection_widget_->Init(params); | |
517 views::View* content_view = new views::View; | |
518 content_view->set_background( | |
519 views::Background::CreateSolidBackground(kWindowSelectorSelectionColor)); | |
520 selection_widget_->SetContentsView(content_view); | |
521 UpdateSelectionLocation(false); | |
522 selection_widget_->GetNativeWindow()->parent()->StackChildAtBottom( | |
523 selection_widget_->GetNativeWindow()); | |
524 selection_widget_->Show(); | |
525 selection_widget_->GetNativeWindow()->layer()->SetOpacity( | |
526 kWindowSelectorSelectionOpacity); | |
527 } | |
528 | |
529 void WindowSelector::UpdateSelectionLocation(bool animate) { | |
530 if (!selection_widget_) | |
531 return; | |
532 gfx::Rect target_bounds = windows_[selected_window_]->bounds(); | |
533 target_bounds.Inset(-kWindowSelectorSelectionPadding, | |
534 -kWindowSelectorSelectionPadding); | |
535 if (animate) { | |
536 WindowSelectorAnimationSettings animation_settings( | |
537 selection_widget_->GetNativeWindow()); | |
538 selection_widget_->SetBounds(target_bounds); | |
539 } else { | |
540 selection_widget_->SetBounds(target_bounds); | |
541 } | 213 } |
542 } | 214 } |
543 | 215 |
544 } // namespace ash | 216 } // namespace ash |
OLD | NEW |