| 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/overview/window_selector.h" | 5 #include "ash/wm/overview/window_selector.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "ash/accessibility_delegate.h" | 9 #include "ash/accessibility_delegate.h" |
| 10 #include "ash/ash_switches.h" | 10 #include "ash/ash_switches.h" |
| 11 #include "ash/metrics/user_metrics_recorder.h" | 11 #include "ash/metrics/user_metrics_recorder.h" |
| 12 #include "ash/root_window_controller.h" | 12 #include "ash/root_window_controller.h" |
| 13 #include "ash/screen_util.h" | |
| 14 #include "ash/shell.h" | 13 #include "ash/shell.h" |
| 15 #include "ash/shell_window_ids.h" | 14 #include "ash/shell_window_ids.h" |
| 16 #include "ash/switchable_windows.h" | 15 #include "ash/switchable_windows.h" |
| 17 #include "ash/wm/overview/scoped_transform_overview_window.h" | 16 #include "ash/wm/overview/scoped_transform_overview_window.h" |
| 17 #include "ash/wm/overview/window_grid.h" |
| 18 #include "ash/wm/overview/window_selector_delegate.h" | 18 #include "ash/wm/overview/window_selector_delegate.h" |
| 19 #include "ash/wm/overview/window_selector_item.h" | 19 #include "ash/wm/overview/window_selector_item.h" |
| 20 #include "ash/wm/overview/window_selector_panels.h" | |
| 21 #include "ash/wm/overview/window_selector_window.h" | |
| 22 #include "ash/wm/window_state.h" | 20 #include "ash/wm/window_state.h" |
| 23 #include "base/auto_reset.h" | 21 #include "base/auto_reset.h" |
| 24 #include "base/command_line.h" | |
| 25 #include "base/metrics/histogram.h" | 22 #include "base/metrics/histogram.h" |
| 26 #include "base/strings/string_number_conversions.h" | |
| 27 #include "third_party/skia/include/core/SkColor.h" | |
| 28 #include "ui/aura/client/focus_client.h" | 23 #include "ui/aura/client/focus_client.h" |
| 29 #include "ui/aura/window.h" | 24 #include "ui/aura/window.h" |
| 30 #include "ui/aura/window_event_dispatcher.h" | 25 #include "ui/aura/window_event_dispatcher.h" |
| 31 #include "ui/aura/window_observer.h" | 26 #include "ui/aura/window_observer.h" |
| 32 #include "ui/compositor/layer_animation_observer.h" | |
| 33 #include "ui/compositor/scoped_layer_animation_settings.h" | 27 #include "ui/compositor/scoped_layer_animation_settings.h" |
| 34 #include "ui/events/event.h" | 28 #include "ui/events/event.h" |
| 35 #include "ui/gfx/screen.h" | 29 #include "ui/gfx/screen.h" |
| 36 #include "ui/views/background.h" | |
| 37 #include "ui/views/widget/widget.h" | |
| 38 #include "ui/wm/core/window_util.h" | 30 #include "ui/wm/core/window_util.h" |
| 39 #include "ui/wm/public/activation_client.h" | 31 #include "ui/wm/public/activation_client.h" |
| 40 | 32 |
| 41 namespace ash { | 33 namespace ash { |
| 42 | 34 |
| 43 namespace { | 35 namespace { |
| 44 | 36 |
| 45 // Conceptually the window overview is a table or grid of cells having this | 37 // A comparator for locating a grid with a given root window. |
| 46 // fixed aspect ratio. The number of columns is determined by maximizing the | 38 struct RootWindowGridComparator |
| 47 // area of them based on the number of windows. | 39 : public std::unary_function<WindowGrid*, bool> { |
| 48 const float kCardAspectRatio = 4.0f / 3.0f; | 40 explicit RootWindowGridComparator(const aura::Window* root_window) |
| 49 | 41 : root_window_(root_window) { |
| 50 // The minimum number of cards along the major axis (i.e. horizontally on a | |
| 51 // landscape orientation). | |
| 52 const int kMinCardsMajor = 3; | |
| 53 | |
| 54 // A comparator for locating a given target window. | |
| 55 struct WindowSelectorItemComparator | |
| 56 : public std::unary_function<WindowSelectorItem*, bool> { | |
| 57 explicit WindowSelectorItemComparator(const aura::Window* target_window) | |
| 58 : target(target_window) { | |
| 59 } | 42 } |
| 60 | 43 |
| 61 bool operator()(WindowSelectorItem* window) const { | 44 bool operator()(WindowGrid* grid) const { |
| 62 return window->HasSelectableWindow(target); | 45 return (grid->root_window() == root_window_); |
| 63 } | 46 } |
| 64 | 47 |
| 65 const aura::Window* target; | 48 const aura::Window* root_window_; |
| 66 }; | 49 }; |
| 67 | 50 |
| 68 // An observer which holds onto the passed widget until the animation is | |
| 69 // complete. | |
| 70 class CleanupWidgetAfterAnimationObserver : public ui::LayerAnimationObserver { | |
| 71 public: | |
| 72 explicit CleanupWidgetAfterAnimationObserver( | |
| 73 scoped_ptr<views::Widget> widget); | |
| 74 | |
| 75 // ui::LayerAnimationObserver: | |
| 76 virtual void OnLayerAnimationEnded( | |
| 77 ui::LayerAnimationSequence* sequence) OVERRIDE; | |
| 78 virtual void OnLayerAnimationAborted( | |
| 79 ui::LayerAnimationSequence* sequence) OVERRIDE; | |
| 80 virtual void OnLayerAnimationScheduled( | |
| 81 ui::LayerAnimationSequence* sequence) OVERRIDE; | |
| 82 | |
| 83 private: | |
| 84 virtual ~CleanupWidgetAfterAnimationObserver(); | |
| 85 | |
| 86 scoped_ptr<views::Widget> widget_; | |
| 87 | |
| 88 DISALLOW_COPY_AND_ASSIGN(CleanupWidgetAfterAnimationObserver); | |
| 89 }; | |
| 90 | |
| 91 CleanupWidgetAfterAnimationObserver::CleanupWidgetAfterAnimationObserver( | |
| 92 scoped_ptr<views::Widget> widget) | |
| 93 : widget_(widget.Pass()) { | |
| 94 widget_->GetNativeWindow()->layer()->GetAnimator()->AddObserver(this); | |
| 95 } | |
| 96 | |
| 97 CleanupWidgetAfterAnimationObserver::~CleanupWidgetAfterAnimationObserver() { | |
| 98 widget_->GetNativeWindow()->layer()->GetAnimator()->RemoveObserver(this); | |
| 99 } | |
| 100 | |
| 101 void CleanupWidgetAfterAnimationObserver::OnLayerAnimationEnded( | |
| 102 ui::LayerAnimationSequence* sequence) { | |
| 103 delete this; | |
| 104 } | |
| 105 | |
| 106 void CleanupWidgetAfterAnimationObserver::OnLayerAnimationAborted( | |
| 107 ui::LayerAnimationSequence* sequence) { | |
| 108 delete this; | |
| 109 } | |
| 110 | |
| 111 void CleanupWidgetAfterAnimationObserver::OnLayerAnimationScheduled( | |
| 112 ui::LayerAnimationSequence* sequence) { | |
| 113 } | |
| 114 | |
| 115 // A comparator for locating a selectable window given a targeted window. | 51 // A comparator for locating a selectable window given a targeted window. |
| 116 struct WindowSelectorItemTargetComparator | 52 struct WindowSelectorItemTargetComparator |
| 117 : public std::unary_function<WindowSelectorItem*, bool> { | 53 : public std::unary_function<WindowSelectorItem*, bool> { |
| 118 explicit WindowSelectorItemTargetComparator(const aura::Window* target_window) | 54 explicit WindowSelectorItemTargetComparator(const aura::Window* target_window) |
| 119 : target(target_window) { | 55 : target(target_window) { |
| 120 } | 56 } |
| 121 | 57 |
| 122 bool operator()(WindowSelectorItem* window) const { | 58 bool operator()(WindowSelectorItem* window) const { |
| 123 return window->Contains(target); | 59 return window->Contains(target); |
| 124 } | 60 } |
| (...skipping 26 matching lines...) Expand all Loading... |
| 151 } | 87 } |
| 152 } | 88 } |
| 153 | 89 |
| 154 } // namespace | 90 } // namespace |
| 155 | 91 |
| 156 WindowSelector::WindowSelector(const WindowList& windows, | 92 WindowSelector::WindowSelector(const WindowList& windows, |
| 157 WindowSelectorDelegate* delegate) | 93 WindowSelectorDelegate* delegate) |
| 158 : delegate_(delegate), | 94 : delegate_(delegate), |
| 159 restore_focus_window_(aura::client::GetFocusClient( | 95 restore_focus_window_(aura::client::GetFocusClient( |
| 160 Shell::GetPrimaryRootWindow())->GetFocusedWindow()), | 96 Shell::GetPrimaryRootWindow())->GetFocusedWindow()), |
| 161 ignore_activations_(false) { | 97 ignore_activations_(false), |
| 98 selected_grid_index_(0) { |
| 162 DCHECK(delegate_); | 99 DCHECK(delegate_); |
| 100 Shell* shell = Shell::GetInstance(); |
| 101 shell->OnOverviewModeStarting(); |
| 163 | 102 |
| 164 if (restore_focus_window_) | 103 if (restore_focus_window_) |
| 165 restore_focus_window_->AddObserver(this); | 104 restore_focus_window_->AddObserver(this); |
| 166 | 105 |
| 167 std::vector<WindowSelectorPanels*> panels_items; | 106 const aura::Window::Windows root_windows = Shell::GetAllRootWindows(); |
| 168 for (size_t i = 0; i < windows.size(); ++i) { | 107 size_t items = 0; |
| 169 WindowSelectorItem* item = NULL; | |
| 170 if (windows[i] != restore_focus_window_) | |
| 171 windows[i]->AddObserver(this); | |
| 172 observed_windows_.insert(windows[i]); | |
| 173 | |
| 174 if (windows[i]->type() == ui::wm::WINDOW_TYPE_PANEL && | |
| 175 wm::GetWindowState(windows[i])->panel_attached()) { | |
| 176 // Attached panel windows are grouped into a single overview item per | |
| 177 // root window (display). | |
| 178 std::vector<WindowSelectorPanels*>::iterator iter = | |
| 179 std::find_if(panels_items.begin(), panels_items.end(), | |
| 180 WindowSelectorItemForRoot(windows[i]->GetRootWindow())); | |
| 181 WindowSelectorPanels* panels_item = NULL; | |
| 182 if (iter == panels_items.end()) { | |
| 183 panels_item = new WindowSelectorPanels(); | |
| 184 panels_items.push_back(panels_item); | |
| 185 windows_.push_back(panels_item); | |
| 186 } else { | |
| 187 panels_item = *iter; | |
| 188 } | |
| 189 panels_item->AddWindow(windows[i]); | |
| 190 item = panels_item; | |
| 191 } else { | |
| 192 item = new WindowSelectorWindow(windows[i]); | |
| 193 windows_.push_back(item); | |
| 194 } | |
| 195 // Verify that the window has been added to an item in overview. | |
| 196 CHECK(item->Contains(windows[i])); | |
| 197 } | |
| 198 UMA_HISTOGRAM_COUNTS_100("Ash.WindowSelector.Items", windows_.size()); | |
| 199 | |
| 200 // Observe window activations and switchable containers on all root windows | |
| 201 // for newly created windows during overview. | |
| 202 Shell::GetInstance()->activation_client()->AddObserver(this); | |
| 203 aura::Window::Windows root_windows = Shell::GetAllRootWindows(); | |
| 204 for (aura::Window::Windows::const_iterator iter = root_windows.begin(); | 108 for (aura::Window::Windows::const_iterator iter = root_windows.begin(); |
| 205 iter != root_windows.end(); ++iter) { | 109 iter != root_windows.end(); iter++) { |
| 110 // Observed switchable containers for newly created windows on all root |
| 111 // windows. |
| 206 for (size_t i = 0; i < kSwitchableWindowContainerIdsLength; ++i) { | 112 for (size_t i = 0; i < kSwitchableWindowContainerIdsLength; ++i) { |
| 207 aura::Window* container = Shell::GetContainer(*iter, | 113 aura::Window* container = Shell::GetContainer(*iter, |
| 208 kSwitchableWindowContainerIds[i]); | 114 kSwitchableWindowContainerIds[i]); |
| 209 container->AddObserver(this); | 115 container->AddObserver(this); |
| 210 observed_windows_.insert(container); | 116 observed_windows_.insert(container); |
| 211 } | 117 } |
| 118 scoped_ptr<WindowGrid> grid(new WindowGrid(*iter, windows, this)); |
| 119 if (grid->empty()) |
| 120 continue; |
| 121 grid_list_.push_back(grid.release()); |
| 122 items += grid_list_.size(); |
| 212 } | 123 } |
| 213 | 124 |
| 214 StartOverview(); | 125 DCHECK(!grid_list_.empty()); |
| 126 UMA_HISTOGRAM_COUNTS_100("Ash.WindowSelector.Items", items); |
| 127 |
| 128 shell->activation_client()->AddObserver(this); |
| 129 |
| 130 // Remove focus from active window before entering overview. |
| 131 aura::client::GetFocusClient( |
| 132 Shell::GetPrimaryRootWindow())->FocusWindow(NULL); |
| 133 |
| 134 shell->PrependPreTargetHandler(this); |
| 135 shell->GetScreen()->AddObserver(this); |
| 136 shell->metrics()->RecordUserMetricsAction(UMA_WINDOW_OVERVIEW); |
| 137 HideAndTrackNonOverviewWindows(); |
| 138 // Send an a11y alert. |
| 139 shell->accessibility_delegate()->TriggerAccessibilityAlert( |
| 140 A11Y_ALERT_WINDOW_OVERVIEW_MODE_ENTERED); |
| 141 |
| 142 UpdateShelfVisibility(); |
| 215 } | 143 } |
| 216 | 144 |
| 217 WindowSelector::~WindowSelector() { | 145 WindowSelector::~WindowSelector() { |
| 218 ash::Shell* shell = ash::Shell::GetInstance(); | 146 ash::Shell* shell = ash::Shell::GetInstance(); |
| 219 | 147 |
| 220 ResetFocusRestoreWindow(true); | 148 ResetFocusRestoreWindow(true); |
| 221 for (std::set<aura::Window*>::iterator iter = observed_windows_.begin(); | 149 for (std::set<aura::Window*>::iterator iter = observed_windows_.begin(); |
| 222 iter != observed_windows_.end(); ++iter) { | 150 iter != observed_windows_.end(); ++iter) { |
| 223 (*iter)->RemoveObserver(this); | 151 (*iter)->RemoveObserver(this); |
| 224 } | 152 } |
| (...skipping 17 matching lines...) Expand all Loading... |
| 242 shell->GetScreen()->RemoveObserver(this); | 170 shell->GetScreen()->RemoveObserver(this); |
| 243 UMA_HISTOGRAM_MEDIUM_TIMES( | 171 UMA_HISTOGRAM_MEDIUM_TIMES( |
| 244 "Ash.WindowSelector.TimeInOverview", | 172 "Ash.WindowSelector.TimeInOverview", |
| 245 base::Time::Now() - overview_start_time_); | 173 base::Time::Now() - overview_start_time_); |
| 246 | 174 |
| 247 // TODO(nsatragno): Change this to OnOverviewModeEnded and move it to when | 175 // TODO(nsatragno): Change this to OnOverviewModeEnded and move it to when |
| 248 // everything is done. | 176 // everything is done. |
| 249 shell->OnOverviewModeEnding(); | 177 shell->OnOverviewModeEnding(); |
| 250 | 178 |
| 251 // Clearing the window list resets the ignored_by_shelf flag on the windows. | 179 // Clearing the window list resets the ignored_by_shelf flag on the windows. |
| 252 windows_.clear(); | 180 grid_list_.clear(); |
| 253 UpdateShelfVisibility(); | 181 UpdateShelfVisibility(); |
| 254 } | 182 } |
| 255 | 183 |
| 256 void WindowSelector::CancelSelection() { | 184 void WindowSelector::CancelSelection() { |
| 257 delegate_->OnSelectionEnded(); | 185 delegate_->OnSelectionEnded(); |
| 258 } | 186 } |
| 259 | 187 |
| 188 void WindowSelector::OnGridEmpty(WindowGrid* grid) { |
| 189 ScopedVector<WindowGrid>::iterator iter = |
| 190 std::find(grid_list_.begin(), grid_list_.end(), grid); |
| 191 DCHECK(iter != grid_list_.end()); |
| 192 grid_list_.erase(iter); |
| 193 // TODO(nsatragno): Use the previous index for more than two displays. |
| 194 selected_grid_index_ = 0; |
| 195 if (grid_list_.empty()) |
| 196 CancelSelection(); |
| 197 } |
| 198 |
| 260 void WindowSelector::OnKeyEvent(ui::KeyEvent* event) { | 199 void WindowSelector::OnKeyEvent(ui::KeyEvent* event) { |
| 261 if (event->type() != ui::ET_KEY_PRESSED) | 200 if (event->type() != ui::ET_KEY_PRESSED) |
| 262 return; | 201 return; |
| 263 | 202 |
| 264 if (event->key_code() == ui::VKEY_ESCAPE) { | 203 bool handled = true; |
| 265 CancelSelection(); | 204 switch (event->key_code()) { |
| 205 case ui::VKEY_ESCAPE: |
| 206 CancelSelection(); |
| 207 break; |
| 208 case ui::VKEY_UP: |
| 209 Move(WindowSelector::UP); |
| 210 break; |
| 211 case ui::VKEY_DOWN: |
| 212 Move(WindowSelector::DOWN); |
| 213 break; |
| 214 case ui::VKEY_RIGHT: |
| 215 Move(WindowSelector::RIGHT); |
| 216 break; |
| 217 case ui::VKEY_LEFT: |
| 218 Move(WindowSelector::LEFT); |
| 219 break; |
| 220 case ui::VKEY_RETURN: |
| 221 wm::GetWindowState( |
| 222 grid_list_[selected_grid_index_]-> |
| 223 SelectedWindow()->SelectionWindow())->Activate(); |
| 224 break; |
| 225 default: |
| 226 // Not a key we are interested in. |
| 227 handled = false; |
| 228 break; |
| 229 } |
| 230 if (handled) |
| 266 event->SetHandled(); | 231 event->SetHandled(); |
| 267 } | |
| 268 } | 232 } |
| 269 | 233 |
| 270 void WindowSelector::OnDisplayAdded(const gfx::Display& display) { | 234 void WindowSelector::OnDisplayAdded(const gfx::Display& display) { |
| 271 } | 235 } |
| 272 | 236 |
| 273 void WindowSelector::OnDisplayRemoved(const gfx::Display& display) { | 237 void WindowSelector::OnDisplayRemoved(const gfx::Display& display) { |
| 238 // TODO(nsatragno): Keep window selection active on remaining displays. |
| 239 CancelSelection(); |
| 274 } | 240 } |
| 275 | 241 |
| 276 void WindowSelector::OnDisplayMetricsChanged(const gfx::Display& display, | 242 void WindowSelector::OnDisplayMetricsChanged(const gfx::Display& display, |
| 277 uint32_t metrics) { | 243 uint32_t metrics) { |
| 278 PositionWindows(/* animate */ false); | 244 PositionWindows(/* animate */ false); |
| 279 } | 245 } |
| 280 | 246 |
| 281 void WindowSelector::OnWindowAdded(aura::Window* new_window) { | 247 void WindowSelector::OnWindowAdded(aura::Window* new_window) { |
| 282 if (new_window->type() != ui::wm::WINDOW_TYPE_NORMAL && | 248 if (new_window->type() != ui::wm::WINDOW_TYPE_NORMAL && |
| 283 new_window->type() != ui::wm::WINDOW_TYPE_PANEL) { | 249 new_window->type() != ui::wm::WINDOW_TYPE_PANEL) { |
| 284 return; | 250 return; |
| 285 } | 251 } |
| 286 | 252 |
| 287 for (size_t i = 0; i < kSwitchableWindowContainerIdsLength; ++i) { | 253 for (size_t i = 0; i < kSwitchableWindowContainerIdsLength; ++i) { |
| 288 if (new_window->parent()->id() == kSwitchableWindowContainerIds[i] && | 254 if (new_window->parent()->id() == kSwitchableWindowContainerIds[i] && |
| 289 !::wm::GetTransientParent(new_window)) { | 255 !::wm::GetTransientParent(new_window)) { |
| 290 // The new window is in one of the switchable containers, abort overview. | 256 // The new window is in one of the switchable containers, abort overview. |
| 291 CancelSelection(); | 257 CancelSelection(); |
| 292 return; | 258 return; |
| 293 } | 259 } |
| 294 } | 260 } |
| 295 } | 261 } |
| 296 | 262 |
| 297 void WindowSelector::OnWindowDestroying(aura::Window* window) { | 263 void WindowSelector::OnWindowDestroying(aura::Window* window) { |
| 298 // window is one of a container, the restore_focus_window and/or | |
| 299 // one of the selectable windows in overview. | |
| 300 ScopedVector<WindowSelectorItem>::iterator iter = | |
| 301 std::find_if(windows_.begin(), windows_.end(), | |
| 302 WindowSelectorItemComparator(window)); | |
| 303 window->RemoveObserver(this); | 264 window->RemoveObserver(this); |
| 304 observed_windows_.erase(window); | 265 observed_windows_.erase(window); |
| 305 if (window == restore_focus_window_) | 266 if (window == restore_focus_window_) |
| 306 restore_focus_window_ = NULL; | 267 restore_focus_window_ = NULL; |
| 307 if (iter == windows_.end()) | |
| 308 return; | |
| 309 | |
| 310 (*iter)->RemoveWindow(window); | |
| 311 // If there are still windows in this selector entry then the overview is | |
| 312 // still active and the active selection remains the same. | |
| 313 if (!(*iter)->empty()) | |
| 314 return; | |
| 315 | |
| 316 windows_.erase(iter); | |
| 317 if (windows_.empty()) { | |
| 318 CancelSelection(); | |
| 319 return; | |
| 320 } | |
| 321 PositionWindows(true); | |
| 322 } | |
| 323 | |
| 324 void WindowSelector::OnWindowBoundsChanged(aura::Window* window, | |
| 325 const gfx::Rect& old_bounds, | |
| 326 const gfx::Rect& new_bounds) { | |
| 327 ScopedVector<WindowSelectorItem>::iterator iter = | |
| 328 std::find_if(windows_.begin(), windows_.end(), | |
| 329 WindowSelectorItemTargetComparator(window)); | |
| 330 if (iter == windows_.end()) | |
| 331 return; | |
| 332 | |
| 333 // Immediately finish any active bounds animation. | |
| 334 window->layer()->GetAnimator()->StopAnimatingProperty( | |
| 335 ui::LayerAnimationElement::BOUNDS); | |
| 336 | |
| 337 // Recompute the transform for the window. | |
| 338 (*iter)->RecomputeWindowTransforms(); | |
| 339 } | 268 } |
| 340 | 269 |
| 341 void WindowSelector::OnWindowActivated(aura::Window* gained_active, | 270 void WindowSelector::OnWindowActivated(aura::Window* gained_active, |
| 342 aura::Window* lost_active) { | 271 aura::Window* lost_active) { |
| 343 if (ignore_activations_ || !gained_active) | 272 if (ignore_activations_ || !gained_active) |
| 344 return; | 273 return; |
| 345 | 274 |
| 346 ScopedVector<WindowSelectorItem>::iterator iter = std::find_if( | 275 ScopedVector<WindowGrid>::iterator grid = |
| 347 windows_.begin(), windows_.end(), | 276 std::find_if(grid_list_.begin(), grid_list_.end(), |
| 348 WindowSelectorItemComparator(gained_active)); | 277 RootWindowGridComparator(gained_active->GetRootWindow())); |
| 278 if (grid == grid_list_.end()) |
| 279 return; |
| 280 const std::vector<WindowSelectorItem*> windows = (*grid)->window_list(); |
| 349 | 281 |
| 350 if (iter != windows_.end()) | 282 ScopedVector<WindowSelectorItem>::const_iterator iter = std::find_if( |
| 283 windows.begin(), windows.end(), |
| 284 WindowSelectorItemTargetComparator(gained_active)); |
| 285 |
| 286 if (iter != windows.end()) |
| 351 (*iter)->RestoreWindowOnExit(gained_active); | 287 (*iter)->RestoreWindowOnExit(gained_active); |
| 352 | 288 |
| 353 // Don't restore focus on exit if a window was just activated. | 289 // Don't restore focus on exit if a window was just activated. |
| 354 ResetFocusRestoreWindow(false); | 290 ResetFocusRestoreWindow(false); |
| 355 CancelSelection(); | 291 CancelSelection(); |
| 356 } | 292 } |
| 357 | 293 |
| 358 void WindowSelector::OnAttemptToReactivateWindow(aura::Window* request_active, | 294 void WindowSelector::OnAttemptToReactivateWindow(aura::Window* request_active, |
| 359 aura::Window* actual_active) { | 295 aura::Window* actual_active) { |
| 360 OnWindowActivated(request_active, actual_active); | 296 OnWindowActivated(request_active, actual_active); |
| 361 } | 297 } |
| 362 | 298 |
| 363 void WindowSelector::StartOverview() { | |
| 364 // Remove focus from active window before entering overview. | |
| 365 aura::client::GetFocusClient( | |
| 366 Shell::GetPrimaryRootWindow())->FocusWindow(NULL); | |
| 367 | |
| 368 Shell* shell = Shell::GetInstance(); | |
| 369 shell->OnOverviewModeStarting(); | |
| 370 | |
| 371 for (WindowSelectorItemList::iterator iter = windows_.begin(); | |
| 372 iter != windows_.end(); ++iter) { | |
| 373 (*iter)->PrepareForOverview(); | |
| 374 } | |
| 375 PositionWindows(/* animate */ true); | |
| 376 DCHECK(!windows_.empty()); | |
| 377 shell->PrependPreTargetHandler(this); | |
| 378 shell->GetScreen()->AddObserver(this); | |
| 379 shell->metrics()->RecordUserMetricsAction(UMA_WINDOW_OVERVIEW); | |
| 380 HideAndTrackNonOverviewWindows(); | |
| 381 // Send an a11y alert. | |
| 382 shell->accessibility_delegate()->TriggerAccessibilityAlert( | |
| 383 A11Y_ALERT_WINDOW_OVERVIEW_MODE_ENTERED); | |
| 384 | |
| 385 UpdateShelfVisibility(); | |
| 386 } | |
| 387 | |
| 388 bool WindowSelector::Contains(const aura::Window* window) { | |
| 389 for (WindowSelectorItemList::iterator iter = windows_.begin(); | |
| 390 iter != windows_.end(); ++iter) { | |
| 391 if ((*iter)->Contains(window)) | |
| 392 return true; | |
| 393 } | |
| 394 return false; | |
| 395 } | |
| 396 | |
| 397 void WindowSelector::PositionWindows(bool animate) { | 299 void WindowSelector::PositionWindows(bool animate) { |
| 398 aura::Window::Windows root_window_list = Shell::GetAllRootWindows(); | 300 for (ScopedVector<WindowGrid>::iterator iter = grid_list_.begin(); |
| 399 for (size_t i = 0; i < root_window_list.size(); ++i) | 301 iter != grid_list_.end(); iter++) { |
| 400 PositionWindowsFromRoot(root_window_list[i], animate); | 302 (*iter)->PositionWindows(animate); |
| 401 } | |
| 402 | |
| 403 void WindowSelector::PositionWindowsFromRoot(aura::Window* root_window, | |
| 404 bool animate) { | |
| 405 std::vector<WindowSelectorItem*> windows; | |
| 406 for (WindowSelectorItemList::iterator iter = windows_.begin(); | |
| 407 iter != windows_.end(); ++iter) { | |
| 408 if ((*iter)->GetRootWindow() == root_window) | |
| 409 windows.push_back(*iter); | |
| 410 } | |
| 411 | |
| 412 if (windows.empty()) | |
| 413 return; | |
| 414 | |
| 415 gfx::Size window_size; | |
| 416 gfx::Rect total_bounds = ScreenUtil::ConvertRectToScreen( | |
| 417 root_window, | |
| 418 ScreenUtil::GetDisplayWorkAreaBoundsInParent( | |
| 419 Shell::GetContainer(root_window, kShellWindowId_DefaultContainer))); | |
| 420 | |
| 421 // Find the minimum number of windows per row that will fit all of the | |
| 422 // windows on screen. | |
| 423 size_t columns = std::max( | |
| 424 total_bounds.width() > total_bounds.height() ? kMinCardsMajor : 1, | |
| 425 static_cast<int>(ceil(sqrt(total_bounds.width() * windows.size() / | |
| 426 (kCardAspectRatio * total_bounds.height()))))); | |
| 427 size_t rows = ((windows.size() + columns - 1) / columns); | |
| 428 window_size.set_width(std::min( | |
| 429 static_cast<int>(total_bounds.width() / columns), | |
| 430 static_cast<int>(total_bounds.height() * kCardAspectRatio / rows))); | |
| 431 window_size.set_height(window_size.width() / kCardAspectRatio); | |
| 432 | |
| 433 // Calculate the X and Y offsets necessary to center the grid. | |
| 434 int x_offset = total_bounds.x() + ((windows.size() >= columns ? 0 : | |
| 435 (columns - windows.size()) * window_size.width()) + | |
| 436 (total_bounds.width() - columns * window_size.width())) / 2; | |
| 437 int y_offset = total_bounds.y() + (total_bounds.height() - | |
| 438 rows * window_size.height()) / 2; | |
| 439 for (size_t i = 0; i < windows.size(); ++i) { | |
| 440 gfx::Transform transform; | |
| 441 int column = i % columns; | |
| 442 int row = i / columns; | |
| 443 gfx::Rect target_bounds(window_size.width() * column + x_offset, | |
| 444 window_size.height() * row + y_offset, | |
| 445 window_size.width(), | |
| 446 window_size.height()); | |
| 447 windows[i]->SetBounds(root_window, target_bounds, animate); | |
| 448 } | 303 } |
| 449 } | 304 } |
| 450 | 305 |
| 451 void WindowSelector::HideAndTrackNonOverviewWindows() { | 306 void WindowSelector::HideAndTrackNonOverviewWindows() { |
| 452 // Add the windows to hidden_windows first so that if any are destroyed | 307 // Add the windows to hidden_windows first so that if any are destroyed |
| 453 // while hiding them they are tracked. | 308 // while hiding them they are tracked. |
| 454 aura::Window::Windows root_windows = Shell::GetAllRootWindows(); | 309 for (ScopedVector<WindowGrid>::iterator grid_iter = grid_list_.begin(); |
| 455 for (aura::Window::Windows::const_iterator root_iter = root_windows.begin(); | 310 grid_iter != grid_list_.end(); ++grid_iter) { |
| 456 root_iter != root_windows.end(); ++root_iter) { | |
| 457 for (size_t i = 0; i < kSwitchableWindowContainerIdsLength; ++i) { | 311 for (size_t i = 0; i < kSwitchableWindowContainerIdsLength; ++i) { |
| 458 aura::Window* container = Shell::GetContainer(*root_iter, | 312 const aura::Window* container = |
| 459 kSwitchableWindowContainerIds[i]); | 313 Shell::GetContainer((*grid_iter)->root_window(), |
| 314 kSwitchableWindowContainerIds[i]); |
| 460 for (aura::Window::Windows::const_iterator iter = | 315 for (aura::Window::Windows::const_iterator iter = |
| 461 container->children().begin(); iter != container->children().end(); | 316 container->children().begin(); iter != container->children().end(); |
| 462 ++iter) { | 317 ++iter) { |
| 463 if (Contains(*iter) || !(*iter)->IsVisible()) | 318 if (!(*iter)->IsVisible() || (*grid_iter)->Contains(*iter)) |
| 464 continue; | 319 continue; |
| 465 hidden_windows_.Add(*iter); | 320 hidden_windows_.Add(*iter); |
| 466 } | 321 } |
| 467 } | 322 } |
| 468 } | 323 } |
| 469 | 324 |
| 470 // Copy the window list as it can change during iteration. | 325 // Copy the window list as it can change during iteration. |
| 471 const aura::WindowTracker::Windows hidden_windows(hidden_windows_.windows()); | 326 const aura::WindowTracker::Windows hidden_windows(hidden_windows_.windows()); |
| 472 for (aura::WindowTracker::Windows::const_iterator iter = | 327 for (aura::WindowTracker::Windows::const_iterator iter = |
| 473 hidden_windows.begin(); iter != hidden_windows.end(); ++iter) { | 328 hidden_windows.begin(); iter != hidden_windows.end(); ++iter) { |
| (...skipping 22 matching lines...) Expand all Loading... |
| 496 } | 351 } |
| 497 // If the window is in the observed_windows_ list it needs to continue to be | 352 // If the window is in the observed_windows_ list it needs to continue to be |
| 498 // observed. | 353 // observed. |
| 499 if (observed_windows_.find(restore_focus_window_) == | 354 if (observed_windows_.find(restore_focus_window_) == |
| 500 observed_windows_.end()) { | 355 observed_windows_.end()) { |
| 501 restore_focus_window_->RemoveObserver(this); | 356 restore_focus_window_->RemoveObserver(this); |
| 502 } | 357 } |
| 503 restore_focus_window_ = NULL; | 358 restore_focus_window_ = NULL; |
| 504 } | 359 } |
| 505 | 360 |
| 361 void WindowSelector::Move(Direction direction) { |
| 362 bool overflowed = grid_list_[selected_grid_index_]->Move(direction); |
| 363 if (overflowed) { |
| 364 // The grid reported that the movement command corresponds to the next |
| 365 // root window, identify it and call Move() on it to initialize the |
| 366 // selection widget. |
| 367 // TODO(nsatragno): If there are more than two monitors, move between grids |
| 368 // in the requested direction. |
| 369 selected_grid_index_ = (selected_grid_index_ + 1) % grid_list_.size(); |
| 370 grid_list_[selected_grid_index_]->Move(direction); |
| 371 } |
| 372 } |
| 373 |
| 506 } // namespace ash | 374 } // namespace ash |
| OLD | NEW |