Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/workspace/workspace_window_resizer.h" | 5 #include "ash/wm/workspace/workspace_window_resizer.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <cmath> | 8 #include <cmath> |
| 9 | 9 |
| 10 #include "ash/display/display_controller.h" | 10 #include "ash/display/display_controller.h" |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 34 | 34 |
| 35 // Duration of the animation when snapping the window into place. | 35 // Duration of the animation when snapping the window into place. |
| 36 const int kSnapDurationMS = 100; | 36 const int kSnapDurationMS = 100; |
| 37 | 37 |
| 38 // Returns true if should snap to the edge. | 38 // Returns true if should snap to the edge. |
| 39 bool ShouldSnapToEdge(int distance_from_edge, int grid_size) { | 39 bool ShouldSnapToEdge(int distance_from_edge, int grid_size) { |
| 40 return distance_from_edge <= grid_size / 2 && | 40 return distance_from_edge <= grid_size / 2 && |
| 41 distance_from_edge > -grid_size * 2; | 41 distance_from_edge > -grid_size * 2; |
| 42 } | 42 } |
| 43 | 43 |
| 44 // Returns true if Ash has more than one root window. | |
| 45 bool HasSecondaryRootWindow() { | |
| 46 return Shell::GetAllRootWindows().size() > 1; | |
| 47 } | |
| 48 | |
| 49 // When there are two root windows, returns one of the root windows which is not | |
| 50 // |root_window|. Returns NULL if only one root window exists. | |
| 51 aura::RootWindow* GetAnotherRootWindow(aura::RootWindow* root_window) { | |
| 52 Shell::RootWindowList root_windows = Shell::GetAllRootWindows(); | |
| 53 if (root_windows.size() < 2) | |
| 54 return NULL; | |
| 55 DCHECK_EQ(2U, root_windows.size()); | |
|
sky
2012/08/07 03:28:05
Is there a limitation that we only ever support at
Yusuke Sato
2012/08/07 16:38:30
According to oshima, yes. Actually DisplayControll
oshima
2012/08/08 01:40:31
We only support to up 2 displays for now (in terms
| |
| 56 if (root_windows[0] == root_window) | |
| 57 return root_windows[1]; | |
| 58 return root_windows[0]; | |
| 59 } | |
| 60 | |
| 44 } // namespace | 61 } // namespace |
| 45 | 62 |
| 46 // static | 63 // static |
| 47 const int WorkspaceWindowResizer::kMinOnscreenSize = 20; | 64 const int WorkspaceWindowResizer::kMinOnscreenSize = 20; |
| 48 | 65 |
| 49 // static | 66 // static |
| 50 const int WorkspaceWindowResizer::kMinOnscreenHeight = 32; | 67 const int WorkspaceWindowResizer::kMinOnscreenHeight = 32; |
| 51 | 68 |
| 52 WorkspaceWindowResizer::~WorkspaceWindowResizer() { | 69 WorkspaceWindowResizer::~WorkspaceWindowResizer() { |
| 53 Shell* shell = Shell::GetInstance(); | 70 Shell* shell = Shell::GetInstance(); |
| 54 shell->display_controller()->set_dont_warp_mouse(false); | 71 shell->display_controller()->set_dont_warp_mouse(false); |
| 55 shell->cursor_manager()->UnlockCursor(); | 72 shell->cursor_manager()->UnlockCursor(); |
| 56 } | 73 } |
| 57 | 74 |
| 58 // static | 75 // static |
| 59 WorkspaceWindowResizer* WorkspaceWindowResizer::Create( | 76 WorkspaceWindowResizer* WorkspaceWindowResizer::Create( |
| 60 aura::Window* window, | 77 aura::Window* window, |
| 61 const gfx::Point& location_in_parent, | 78 const gfx::Point& location_in_parent, |
| 62 int window_component, | 79 int window_component, |
| 63 const std::vector<aura::Window*>& attached_windows) { | 80 const std::vector<aura::Window*>& attached_windows) { |
| 64 Details details(window, location_in_parent, window_component); | 81 Details details(window, location_in_parent, window_component); |
| 65 return details.is_resizable ? | 82 return details.is_resizable ? |
| 66 new WorkspaceWindowResizer(details, attached_windows) : NULL; | 83 new WorkspaceWindowResizer(details, attached_windows) : NULL; |
| 67 } | 84 } |
| 68 | 85 |
| 69 void WorkspaceWindowResizer::Drag(const gfx::Point& location, int event_flags) { | 86 void WorkspaceWindowResizer::Drag(const gfx::Point& location, int event_flags) { |
| 70 std::pair<aura::RootWindow*, gfx::Point> actual_location = | 87 std::pair<aura::RootWindow*, gfx::Point> actual_location = |
| 71 wm::GetRootWindowRelativeToWindow(window()->parent(), location); | 88 wm::GetRootWindowRelativeToWindow(window()->parent(), location); |
| 89 aura::RootWindow* current_root = actual_location.first; | |
| 90 gfx::Point location_in_original_root = actual_location.second; | |
| 91 aura::Window::ConvertPointToWindow(current_root, | |
| 92 window()->GetRootWindow(), | |
| 93 &location_in_original_root); | |
| 72 | 94 |
| 73 // TODO(yusukes): Implement dragging a window from one display to another. | 95 // Do not use |location| below this point, use |location_in_original_root| |
| 74 aura::RootWindow* current_root = actual_location.first; | 96 // instead. When the pointer is on |window()->GetRootWindow()|, |location| and |
| 75 if (current_root != window()->GetRootWindow()) | 97 // |location_in_original_root| have the same value and both of them are in |
| 76 return; | 98 // |window()->GetRootWindow()|'s coordinates, but once the pointer enters the |
| 99 // other root window, you will see an unexpected value on the former. See | |
| 100 // comments in wm::GetRootWindowRelativeToWindow() for details. | |
| 77 | 101 |
| 78 int grid_size = event_flags & ui::EF_CONTROL_DOWN ? | 102 int grid_size = event_flags & ui::EF_CONTROL_DOWN ? |
| 79 0 : ash::Shell::GetInstance()->GetGridSize(); | 103 0 : ash::Shell::GetInstance()->GetGridSize(); |
| 80 gfx::Rect bounds = CalculateBoundsForDrag(details_, location, grid_size); | 104 gfx::Rect bounds = // in |window()->GetRootWindow()|'s coordinates. |
| 105 CalculateBoundsForDrag(details_, location_in_original_root, grid_size); | |
|
sky
2012/08/07 03:28:05
I'm confused, CalculateBoundsForDrag should take c
Yusuke Sato
2012/08/07 16:38:30
The variable name and the comment were wrong. Sorr
| |
| 81 | 106 |
| 82 if (wm::IsWindowNormal(details_.window)) | 107 if (wm::IsWindowNormal(details_.window)) |
| 83 AdjustBoundsForMainWindow(&bounds, grid_size); | 108 AdjustBoundsForMainWindow(&bounds, grid_size); |
| 84 if (bounds != details_.window->bounds()) { | 109 if (bounds != details_.window->bounds()) { |
| 85 if (!did_move_or_resize_) | 110 if (!did_move_or_resize_) |
| 86 RestackWindows(); | 111 RestackWindows(); |
| 87 did_move_or_resize_ = true; | 112 did_move_or_resize_ = true; |
| 88 } | 113 } |
| 89 UpdatePhantomWindow(location, bounds, grid_size); | 114 |
| 115 const bool in_original_root = (window()->GetRootWindow() == current_root); | |
| 116 // Hide a phantom window for snapping if the cursor is in another root window. | |
| 117 if (in_original_root) | |
| 118 UpdatePhantomWindow(location_in_original_root, bounds, grid_size); | |
| 119 else | |
| 120 phantom_window_controller_.reset(); | |
| 121 | |
| 122 // Show a phantom window for dragging in another root window. | |
| 123 if (HasSecondaryRootWindow()) | |
| 124 UpdateDragPhantomWindow(bounds); | |
| 125 else | |
| 126 drag_phantom_window_controller_.reset(); | |
| 127 | |
| 90 if (!attached_windows_.empty()) | 128 if (!attached_windows_.empty()) |
| 91 LayoutAttachedWindows(bounds, grid_size); | 129 LayoutAttachedWindows(bounds, grid_size); |
| 92 if (bounds != details_.window->bounds()) | 130 if (bounds != details_.window->bounds()) |
| 93 details_.window->SetBounds(bounds); | 131 details_.window->SetBounds(bounds); |
| 94 // WARNING: we may have been deleted. | 132 // WARNING: we may have been deleted. |
| 95 } | 133 } |
| 96 | 134 |
| 97 void WorkspaceWindowResizer::CompleteDrag(int event_flags) { | 135 void WorkspaceWindowResizer::CompleteDrag(int event_flags) { |
| 136 drag_phantom_window_controller_.reset(); | |
| 98 phantom_window_controller_.reset(); | 137 phantom_window_controller_.reset(); |
| 99 if (!did_move_or_resize_ || details_.window_component != HTCAPTION) | 138 if (!did_move_or_resize_ || details_.window_component != HTCAPTION) |
| 100 return; | 139 return; |
| 101 | 140 |
| 102 if (snap_type_ == SNAP_LEFT_EDGE || snap_type_ == SNAP_RIGHT_EDGE) { | 141 if (snap_type_ == SNAP_LEFT_EDGE || snap_type_ == SNAP_RIGHT_EDGE) { |
| 103 if (!GetRestoreBoundsInScreen(details_.window)) | 142 if (!GetRestoreBoundsInScreen(details_.window)) |
| 104 SetRestoreBoundsInParent(details_.window, details_.initial_bounds); | 143 SetRestoreBoundsInParent(details_.window, details_.initial_bounds); |
| 105 details_.window->SetBounds(snap_sizer_->target_bounds()); | 144 details_.window->SetBounds(snap_sizer_->target_bounds()); |
| 106 return; | 145 return; |
| 107 } | 146 } |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 133 ui::ScopedLayerAnimationSettings scoped_setter( | 172 ui::ScopedLayerAnimationSettings scoped_setter( |
| 134 details_.window->layer()->GetAnimator()); | 173 details_.window->layer()->GetAnimator()); |
| 135 // Use a small duration since the grid is small. | 174 // Use a small duration since the grid is small. |
| 136 scoped_setter.SetTransitionDuration( | 175 scoped_setter.SetTransitionDuration( |
| 137 base::TimeDelta::FromMilliseconds(kSnapDurationMS)); | 176 base::TimeDelta::FromMilliseconds(kSnapDurationMS)); |
| 138 details_.window->SetBounds(bounds); | 177 details_.window->SetBounds(bounds); |
| 139 } | 178 } |
| 140 } | 179 } |
| 141 | 180 |
| 142 void WorkspaceWindowResizer::RevertDrag() { | 181 void WorkspaceWindowResizer::RevertDrag() { |
| 182 drag_phantom_window_controller_.reset(); | |
| 143 phantom_window_controller_.reset(); | 183 phantom_window_controller_.reset(); |
| 144 | 184 |
| 145 if (!did_move_or_resize_) | 185 if (!did_move_or_resize_) |
| 146 return; | 186 return; |
| 147 | 187 |
| 148 details_.window->SetBounds(details_.initial_bounds); | 188 details_.window->SetBounds(details_.initial_bounds); |
| 149 if (details_.window_component == HTRIGHT) { | 189 if (details_.window_component == HTRIGHT) { |
| 150 int last_x = details_.initial_bounds.right(); | 190 int last_x = details_.initial_bounds.right(); |
| 151 for (size_t i = 0; i < attached_windows_.size(); ++i) { | 191 for (size_t i = 0; i < attached_windows_.size(); ++i) { |
| 152 gfx::Rect bounds(attached_windows_[i]->bounds()); | 192 gfx::Rect bounds(attached_windows_[i]->bounds()); |
| (...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 305 if (i == attached_windows_.size()) | 345 if (i == attached_windows_.size()) |
| 306 size = end - current; | 346 size = end - current; |
| 307 current += size; | 347 current += size; |
| 308 sizes->push_back(size); | 348 sizes->push_back(size); |
| 309 } | 349 } |
| 310 } | 350 } |
| 311 } | 351 } |
| 312 | 352 |
| 313 void WorkspaceWindowResizer::AdjustBoundsForMainWindow( | 353 void WorkspaceWindowResizer::AdjustBoundsForMainWindow( |
| 314 gfx::Rect* bounds, int grid_size) const { | 354 gfx::Rect* bounds, int grid_size) const { |
| 315 // Always keep kMinOnscreenHeight on the bottom. | 355 // Always keep kMinOnscreenHeight on the bottom except when an extended |
| 356 // display is available and a window is being dragged. | |
|
sky
2012/08/07 03:28:05
Doesn't that only make sense if the extended displ
Yusuke Sato
2012/08/07 16:38:30
Yes.
| |
| 316 gfx::Rect work_area( | 357 gfx::Rect work_area( |
| 317 ScreenAsh::GetDisplayWorkAreaBoundsInParent(details_.window)); | 358 ScreenAsh::GetDisplayWorkAreaBoundsInParent(details_.window)); |
| 318 int max_y = AlignToGridRoundUp(work_area.bottom() - kMinOnscreenHeight, | 359 int max_y = AlignToGridRoundUp(work_area.bottom() - kMinOnscreenHeight, |
| 319 grid_size); | 360 grid_size); |
| 320 if (bounds->y() > max_y) | 361 if ((details_.window_component != HTCAPTION || !HasSecondaryRootWindow()) && |
| 362 bounds->y() > max_y) { | |
| 321 bounds->set_y(max_y); | 363 bounds->set_y(max_y); |
| 364 } | |
| 322 | 365 |
| 323 // Don't allow dragging above the top of the display. | 366 // Don't allow dragging above the top of the display except when an extended |
| 324 if (bounds->y() <= work_area.y()) | 367 // display is available and a window is being dragged. |
| 368 if ((details_.window_component != HTCAPTION || !HasSecondaryRootWindow()) && | |
| 369 bounds->y() <= work_area.y()) { | |
| 325 bounds->set_y(work_area.y()); | 370 bounds->set_y(work_area.y()); |
| 371 } | |
| 326 | 372 |
| 327 if (grid_size >= 0 && details_.window_component == HTCAPTION) | 373 if (grid_size >= 0 && details_.window_component == HTCAPTION) |
| 328 SnapToWorkAreaEdges(work_area, bounds, grid_size); | 374 SnapToWorkAreaEdges(work_area, bounds, grid_size); |
| 329 | 375 |
| 330 if (attached_windows_.empty()) | 376 if (attached_windows_.empty()) |
| 331 return; | 377 return; |
| 332 | 378 |
| 333 if (details_.window_component == HTRIGHT) { | 379 if (details_.window_component == HTRIGHT) { |
| 334 bounds->set_width(std::min(bounds->width(), | 380 bounds->set_width(std::min(bounds->width(), |
| 335 work_area.right() - total_min_ - bounds->x())); | 381 work_area.right() - total_min_ - bounds->x())); |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 384 case HTRIGHT: | 430 case HTRIGHT: |
| 385 return x; | 431 return x; |
| 386 case HTBOTTOM: | 432 case HTBOTTOM: |
| 387 return y; | 433 return y; |
| 388 default: | 434 default: |
| 389 NOTREACHED(); | 435 NOTREACHED(); |
| 390 } | 436 } |
| 391 return 0; | 437 return 0; |
| 392 } | 438 } |
| 393 | 439 |
| 440 void WorkspaceWindowResizer::UpdateDragPhantomWindow(const gfx::Rect& bounds) { | |
| 441 if (!did_move_or_resize_ || details_.window_component != HTCAPTION || | |
| 442 !ShouldAllowMouseWarp()) { | |
| 443 return; | |
| 444 } | |
| 445 | |
| 446 // It's available. Show a phantom window on the display if needed. | |
| 447 aura::RootWindow* another_root = | |
| 448 GetAnotherRootWindow(window()->GetRootWindow()); | |
| 449 const gfx::Rect root_bounds_in_screen(another_root->GetBoundsInScreen()); | |
| 450 const gfx::Rect bounds_in_screen = | |
| 451 ScreenAsh::ConvertRectToScreen(window()->GetRootWindow(), bounds); | |
| 452 const gfx::Rect phantom(root_bounds_in_screen.Intersect(bounds_in_screen)); | |
| 453 | |
| 454 if (!phantom.IsEmpty()) { | |
| 455 if (!drag_phantom_window_controller_.get()) { | |
| 456 drag_phantom_window_controller_.reset( | |
| 457 new PhantomWindowController(window())); | |
| 458 drag_phantom_window_controller_->Show(phantom); | |
| 459 } else { | |
| 460 drag_phantom_window_controller_->SetBounds(phantom); // no animation | |
| 461 } | |
| 462 } else { | |
| 463 drag_phantom_window_controller_.reset(); | |
| 464 } | |
| 465 } | |
| 466 | |
| 394 void WorkspaceWindowResizer::UpdatePhantomWindow(const gfx::Point& location, | 467 void WorkspaceWindowResizer::UpdatePhantomWindow(const gfx::Point& location, |
| 395 const gfx::Rect& bounds, | 468 const gfx::Rect& bounds, |
| 396 int grid_size) { | 469 int grid_size) { |
| 397 if (!did_move_or_resize_ || details_.window_component != HTCAPTION) | 470 if (!did_move_or_resize_ || details_.window_component != HTCAPTION) |
| 398 return; | 471 return; |
| 399 | 472 |
| 400 SnapType last_type = snap_type_; | 473 SnapType last_type = snap_type_; |
| 401 snap_type_ = GetSnapType(location); | 474 snap_type_ = GetSnapType(location); |
| 402 if (snap_type_ == SNAP_NONE || snap_type_ != last_type) { | 475 if (snap_type_ == SNAP_NONE || snap_type_ != last_type) { |
| 403 phantom_window_controller_.reset(); | 476 phantom_window_controller_.reset(); |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 465 } | 538 } |
| 466 | 539 |
| 467 bool WorkspaceWindowResizer::ShouldAllowMouseWarp() const { | 540 bool WorkspaceWindowResizer::ShouldAllowMouseWarp() const { |
| 468 return (details_.window_component == HTCAPTION) && | 541 return (details_.window_component == HTCAPTION) && |
| 469 (window()->GetProperty(aura::client::kModalKey) == ui::MODAL_TYPE_NONE) && | 542 (window()->GetProperty(aura::client::kModalKey) == ui::MODAL_TYPE_NONE) && |
| 470 (window()->type() == aura::client::WINDOW_TYPE_NORMAL); | 543 (window()->type() == aura::client::WINDOW_TYPE_NORMAL); |
| 471 } | 544 } |
| 472 | 545 |
| 473 } // namespace internal | 546 } // namespace internal |
| 474 } // namespace ash | 547 } // namespace ash |
| OLD | NEW |