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