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 22 matching lines...) Expand all Loading... | |
| 33 | 33 |
| 34 // Duration of the animation when snapping the window into place. | 34 // Duration of the animation when snapping the window into place. |
| 35 const int kSnapDurationMS = 100; | 35 const int kSnapDurationMS = 100; |
| 36 | 36 |
| 37 // Returns true if should snap to the edge. | 37 // Returns true if should snap to the edge. |
| 38 bool ShouldSnapToEdge(int distance_from_edge, int grid_size) { | 38 bool ShouldSnapToEdge(int distance_from_edge, int grid_size) { |
| 39 return distance_from_edge <= grid_size / 2 && | 39 return distance_from_edge <= grid_size / 2 && |
| 40 distance_from_edge > -grid_size * 2; | 40 distance_from_edge > -grid_size * 2; |
| 41 } | 41 } |
| 42 | 42 |
| 43 bool HasSecondaryRootWindow() { | |
| 44 return Shell::GetAllRootWindows().size() > 1; | |
| 45 } | |
| 46 | |
| 47 aura::RootWindow* GetAnotherRootWindow(aura::RootWindow* root_window) { | |
| 48 Shell::RootWindowList root_windows = Shell::GetAllRootWindows(); | |
| 49 if (root_windows.size() < 2) | |
| 50 return NULL; // an extended display is not connected. | |
| 51 DCHECK_EQ(2U, root_windows.size()); | |
| 52 if (root_windows[0] == root_window) | |
| 53 return root_windows[1]; | |
| 54 return root_windows[0]; | |
| 55 } | |
| 56 | |
| 43 } // namespace | 57 } // namespace |
| 44 | 58 |
| 45 // static | 59 // static |
| 46 const int WorkspaceWindowResizer::kMinOnscreenSize = 20; | 60 const int WorkspaceWindowResizer::kMinOnscreenSize = 20; |
| 47 | 61 |
| 48 // static | 62 // static |
| 49 const int WorkspaceWindowResizer::kMinOnscreenHeight = 32; | 63 const int WorkspaceWindowResizer::kMinOnscreenHeight = 32; |
| 50 | 64 |
| 51 WorkspaceWindowResizer::~WorkspaceWindowResizer() { | 65 WorkspaceWindowResizer::~WorkspaceWindowResizer() { |
| 52 Shell* shell = Shell::GetInstance(); | 66 Shell* shell = Shell::GetInstance(); |
| 53 if (details_.window_component == HTCAPTION) | 67 if (details_.window_component == HTCAPTION) |
| 54 shell->display_controller()->set_allow_warp_during_lock(false); | 68 shell->display_controller()->set_allow_warp_during_lock(false); |
| 55 shell->cursor_manager()->UnlockCursor(); | 69 shell->cursor_manager()->UnlockCursor(); |
| 56 } | 70 } |
| 57 | 71 |
| 58 // static | 72 // static |
| 59 WorkspaceWindowResizer* WorkspaceWindowResizer::Create( | 73 WorkspaceWindowResizer* WorkspaceWindowResizer::Create( |
| 60 aura::Window* window, | 74 aura::Window* window, |
| 61 const gfx::Point& location_in_parent, | 75 const gfx::Point& location_in_parent, |
| 62 int window_component, | 76 int window_component, |
| 63 const std::vector<aura::Window*>& attached_windows) { | 77 const std::vector<aura::Window*>& attached_windows) { |
| 64 Details details(window, location_in_parent, window_component); | 78 Details details(window, location_in_parent, window_component); |
| 65 return details.is_resizable ? | 79 return details.is_resizable ? |
| 66 new WorkspaceWindowResizer(details, attached_windows) : NULL; | 80 new WorkspaceWindowResizer(details, attached_windows) : NULL; |
| 67 } | 81 } |
| 68 | 82 |
| 69 void WorkspaceWindowResizer::Drag(const gfx::Point& location_in_screen, | 83 void WorkspaceWindowResizer::Drag(const gfx::Point& location_in_screen, |
| 70 int event_flags) { | 84 int event_flags) { |
| 71 // TODO(yusukes): Implement dragging a window from one display to another. | |
| 72 aura::RootWindow* current_root = Shell::GetRootWindowAt(location_in_screen); | 85 aura::RootWindow* current_root = Shell::GetRootWindowAt(location_in_screen); |
| 73 if (current_root != window()->GetRootWindow()) | 86 const bool in_original_root = (window()->GetRootWindow() == current_root); |
| 74 return; | |
| 75 | 87 |
| 76 gfx::Point location_in_root = location_in_screen; | 88 gfx::Point location_in_root = location_in_screen; |
| 77 aura::client::GetScreenPositionClient(current_root)-> | 89 aura::client::GetScreenPositionClient(current_root)-> |
| 78 ConvertPointFromScreen(current_root, &location_in_root); | 90 ConvertPointFromScreen(current_root, &location_in_root); |
| 79 | 91 |
| 80 int grid_size = event_flags & ui::EF_CONTROL_DOWN ? | 92 int grid_size = event_flags & ui::EF_CONTROL_DOWN ? |
| 81 0 : ash::Shell::GetInstance()->GetGridSize(); | 93 0 : ash::Shell::GetInstance()->GetGridSize(); |
| 82 gfx::Rect bounds = | 94 gfx::Rect bounds = // in |window()->GetRootWindow()|'s coordinates. |
| 83 CalculateBoundsForDrag(details_, location_in_root, grid_size); | 95 CalculateBoundsForDrag(details_, location_in_screen, grid_size); |
| 84 | 96 |
| 85 if (wm::IsWindowNormal(details_.window)) | 97 if (wm::IsWindowNormal(details_.window)) |
| 86 AdjustBoundsForMainWindow(&bounds, grid_size); | 98 AdjustBoundsForMainWindow(&bounds, grid_size); |
| 87 if (bounds != details_.window->bounds()) { | 99 if (bounds != details_.window->bounds()) { |
| 88 if (!did_move_or_resize_) | 100 if (!did_move_or_resize_) |
| 89 RestackWindows(); | 101 RestackWindows(); |
| 90 did_move_or_resize_ = true; | 102 did_move_or_resize_ = true; |
| 91 } | 103 } |
| 92 UpdatePhantomWindow(location_in_root, bounds, grid_size); | 104 |
| 105 // Hide a phantom window for snapping if the cursor is in another root window. | |
| 106 if (in_original_root) | |
| 107 UpdatePhantomWindow(location_in_root, bounds, grid_size); | |
| 108 else | |
| 109 phantom_window_controller_.reset(); | |
| 110 | |
| 111 // Show a phantom window for dragging in another root window. | |
| 112 aura::RootWindow* another_root = | |
| 113 GetAnotherRootWindow(window()->GetRootWindow()); | |
| 114 gfx::Rect bounds_in_screen = | |
| 115 ScreenAsh::ConvertRectToScreen(window()->GetRootWindow(), bounds); | |
| 116 UpdateDragPhantomWindow(another_root, bounds_in_screen); | |
| 117 | |
| 93 if (!attached_windows_.empty()) | 118 if (!attached_windows_.empty()) |
| 94 LayoutAttachedWindows(bounds, grid_size); | 119 LayoutAttachedWindows(bounds, grid_size); |
| 95 if (bounds != details_.window->bounds()) | 120 if (bounds != details_.window->bounds()) |
| 96 details_.window->SetBounds(bounds); | 121 details_.window->SetBounds(bounds); |
| 97 // WARNING: we may have been deleted. | 122 // WARNING: we may have been deleted. |
| 98 } | 123 } |
| 99 | 124 |
| 100 void WorkspaceWindowResizer::CompleteDrag(int event_flags) { | 125 void WorkspaceWindowResizer::CompleteDrag(int event_flags) { |
| 126 drag_phantom_window_controller_.reset(); | |
| 101 phantom_window_controller_.reset(); | 127 phantom_window_controller_.reset(); |
| 102 if (!did_move_or_resize_ || details_.window_component != HTCAPTION) | 128 if (!did_move_or_resize_ || details_.window_component != HTCAPTION) |
| 103 return; | 129 return; |
| 104 | 130 |
| 105 if (snap_type_ == SNAP_LEFT_EDGE || snap_type_ == SNAP_RIGHT_EDGE) { | 131 if (snap_type_ == SNAP_LEFT_EDGE || snap_type_ == SNAP_RIGHT_EDGE) { |
| 106 if (!GetRestoreBoundsInScreen(details_.window)) | 132 if (!GetRestoreBoundsInScreen(details_.window)) |
| 107 SetRestoreBoundsInParent(details_.window, details_.initial_bounds); | 133 SetRestoreBoundsInParent(details_.window, details_.initial_bounds); |
| 108 details_.window->SetBounds(snap_sizer_->target_bounds()); | 134 details_.window->SetBounds(snap_sizer_->target_bounds()); |
| 109 return; | 135 return; |
| 110 } | 136 } |
| 111 | 137 |
| 112 int grid_size = event_flags & ui::EF_CONTROL_DOWN ? | 138 int grid_size = event_flags & ui::EF_CONTROL_DOWN ? |
| 113 0 : ash::Shell::GetInstance()->GetGridSize(); | 139 0 : ash::Shell::GetInstance()->GetGridSize(); |
| 114 if (grid_size <= 1) | 140 if (grid_size <= 1) |
| 115 return; | 141 return; |
| 116 | 142 |
| 117 gfx::Rect bounds(GetFinalBounds(details_.window->bounds(), grid_size)); | 143 gfx::Rect bounds(GetFinalBounds(details_.window->bounds(), grid_size)); |
| 118 if (bounds == details_.window->bounds()) | 144 if (bounds == details_.window->bounds()) |
| 119 return; | 145 return; |
| 120 | 146 |
| 121 if (bounds.size() != details_.window->bounds().size()) { | 147 if (bounds.size() != details_.window->bounds().size()) { |
| 122 // Don't attempt to animate a size change. | 148 // Don't attempt to animate a size change. |
| 123 details_.window->SetBounds(bounds); | 149 details_.window->SetBounds(bounds); |
| 124 return; | 150 return; |
| 125 } | 151 } |
| 126 // TODO(oshima|yusukes): This is temporary solution until better drag & move | 152 // TODO(oshima|yusukes): This is temporary solution until better drag & move |
|
Yusuke Sato
2012/08/01 17:44:06
The UX team told us that we should determine the d
| |
| 127 // is implemented. (crbug.com/136816). | 153 // is implemented. (crbug.com/136816). |
| 128 gfx::Rect dst_bounds = | 154 gfx::Rect dst_bounds = |
| 129 ScreenAsh::ConvertRectToScreen(details_.window->parent(), bounds); | 155 ScreenAsh::ConvertRectToScreen(details_.window->parent(), bounds); |
| 130 gfx::Display dst_display = gfx::Screen::GetDisplayMatching(dst_bounds); | 156 gfx::Display dst_display = gfx::Screen::GetDisplayMatching(dst_bounds); |
| 131 if (dst_display.id() != | 157 if (dst_display.id() != |
| 132 gfx::Screen::GetDisplayNearestWindow(details_.window).id()) { | 158 gfx::Screen::GetDisplayNearestWindow(details_.window).id()) { |
| 133 // Don't animate when moving to another display. | 159 // Don't animate when moving to another display. |
| 134 details_.window->SetBoundsInScreen(dst_bounds); | 160 details_.window->SetBoundsInScreen(dst_bounds); |
| 135 } else { | 161 } else { |
| 136 ui::ScopedLayerAnimationSettings scoped_setter( | 162 ui::ScopedLayerAnimationSettings scoped_setter( |
| 137 details_.window->layer()->GetAnimator()); | 163 details_.window->layer()->GetAnimator()); |
| 138 // Use a small duration since the grid is small. | 164 // Use a small duration since the grid is small. |
| 139 scoped_setter.SetTransitionDuration( | 165 scoped_setter.SetTransitionDuration( |
| 140 base::TimeDelta::FromMilliseconds(kSnapDurationMS)); | 166 base::TimeDelta::FromMilliseconds(kSnapDurationMS)); |
| 141 details_.window->SetBounds(bounds); | 167 details_.window->SetBounds(bounds); |
| 142 } | 168 } |
| 143 } | 169 } |
| 144 | 170 |
| 145 void WorkspaceWindowResizer::RevertDrag() { | 171 void WorkspaceWindowResizer::RevertDrag() { |
| 172 drag_phantom_window_controller_.reset(); | |
| 146 phantom_window_controller_.reset(); | 173 phantom_window_controller_.reset(); |
| 147 | 174 |
| 148 if (!did_move_or_resize_) | 175 if (!did_move_or_resize_) |
| 149 return; | 176 return; |
| 150 | 177 |
| 151 details_.window->SetBounds(details_.initial_bounds); | 178 details_.window->SetBounds(details_.initial_bounds); |
| 152 if (details_.window_component == HTRIGHT) { | 179 if (details_.window_component == HTRIGHT) { |
| 153 int last_x = details_.initial_bounds.right(); | 180 int last_x = details_.initial_bounds.right(); |
| 154 for (size_t i = 0; i < attached_windows_.size(); ++i) { | 181 for (size_t i = 0; i < attached_windows_.size(); ++i) { |
| 155 gfx::Rect bounds(attached_windows_[i]->bounds()); | 182 gfx::Rect bounds(attached_windows_[i]->bounds()); |
| (...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 303 if (i == attached_windows_.size()) | 330 if (i == attached_windows_.size()) |
| 304 size = end - current; | 331 size = end - current; |
| 305 current += size; | 332 current += size; |
| 306 sizes->push_back(size); | 333 sizes->push_back(size); |
| 307 } | 334 } |
| 308 } | 335 } |
| 309 } | 336 } |
| 310 | 337 |
| 311 void WorkspaceWindowResizer::AdjustBoundsForMainWindow( | 338 void WorkspaceWindowResizer::AdjustBoundsForMainWindow( |
| 312 gfx::Rect* bounds, int grid_size) const { | 339 gfx::Rect* bounds, int grid_size) const { |
| 313 // Always keep kMinOnscreenHeight on the bottom. | 340 // Always keep kMinOnscreenHeight on the bottom except when an extended |
| 341 // display is available and a window is being dragged. | |
| 314 gfx::Rect work_area( | 342 gfx::Rect work_area( |
| 315 ScreenAsh::GetDisplayWorkAreaBoundsInParent(details_.window)); | 343 ScreenAsh::GetDisplayWorkAreaBoundsInParent(details_.window)); |
| 316 int max_y = AlignToGridRoundUp(work_area.bottom() - kMinOnscreenHeight, | 344 int max_y = AlignToGridRoundUp(work_area.bottom() - kMinOnscreenHeight, |
| 317 grid_size); | 345 grid_size); |
| 318 if (bounds->y() > max_y) | 346 if ((details_.window_component != HTCAPTION || !HasSecondaryRootWindow()) && |
| 347 bounds->y() > max_y) { | |
| 319 bounds->set_y(max_y); | 348 bounds->set_y(max_y); |
| 349 } | |
| 320 | 350 |
| 321 // Don't allow dragging above the top of the display. | 351 // Don't allow dragging above the top of the display except when an extended |
| 322 if (bounds->y() <= work_area.y()) | 352 // display is available and a window is being dragged. |
| 353 if ((details_.window_component != HTCAPTION || !HasSecondaryRootWindow()) && | |
| 354 bounds->y() <= work_area.y()) { | |
| 323 bounds->set_y(work_area.y()); | 355 bounds->set_y(work_area.y()); |
| 356 } | |
| 324 | 357 |
| 325 if (grid_size >= 0 && details_.window_component == HTCAPTION) | 358 if (grid_size >= 0 && details_.window_component == HTCAPTION) |
| 326 SnapToWorkAreaEdges(work_area, bounds, grid_size); | 359 SnapToWorkAreaEdges(work_area, bounds, grid_size); |
| 327 | 360 |
| 328 if (attached_windows_.empty()) | 361 if (attached_windows_.empty()) |
| 329 return; | 362 return; |
| 330 | 363 |
| 331 if (details_.window_component == HTRIGHT) { | 364 if (details_.window_component == HTRIGHT) { |
| 332 bounds->set_width(std::min(bounds->width(), | 365 bounds->set_width(std::min(bounds->width(), |
| 333 work_area.right() - total_min_ - bounds->x())); | 366 work_area.right() - total_min_ - bounds->x())); |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 382 case HTRIGHT: | 415 case HTRIGHT: |
| 383 return x; | 416 return x; |
| 384 case HTBOTTOM: | 417 case HTBOTTOM: |
| 385 return y; | 418 return y; |
| 386 default: | 419 default: |
| 387 NOTREACHED(); | 420 NOTREACHED(); |
| 388 } | 421 } |
| 389 return 0; | 422 return 0; |
| 390 } | 423 } |
| 391 | 424 |
| 425 void WorkspaceWindowResizer::UpdateDragPhantomWindow( | |
| 426 aura::RootWindow* another_root, | |
| 427 const gfx::Rect& window_bounds_in_screen) { | |
| 428 if (!another_root) { | |
| 429 // An extended display is not available. | |
| 430 drag_phantom_window_controller_.reset(); | |
| 431 return; | |
| 432 } | |
| 433 | |
| 434 // It's available. Show a phantom window on the display if needed. | |
| 435 const gfx::Rect root_bounds_in_screen(another_root->GetBoundsInScreen()); | |
| 436 const gfx::Rect phantom( | |
| 437 root_bounds_in_screen.Intersect(window_bounds_in_screen)); | |
| 438 | |
| 439 if (!phantom.IsEmpty()) { | |
| 440 if (!drag_phantom_window_controller_.get()) { | |
| 441 drag_phantom_window_controller_.reset( | |
| 442 new PhantomWindowController(window())); | |
| 443 drag_phantom_window_controller_->Show(phantom); | |
| 444 } else { | |
| 445 drag_phantom_window_controller_->SetBounds(phantom); // no animation | |
| 446 } | |
| 447 } else { | |
| 448 drag_phantom_window_controller_.reset(); | |
| 449 } | |
| 450 } | |
| 451 | |
| 392 void WorkspaceWindowResizer::UpdatePhantomWindow(const gfx::Point& location, | 452 void WorkspaceWindowResizer::UpdatePhantomWindow(const gfx::Point& location, |
| 393 const gfx::Rect& bounds, | 453 const gfx::Rect& bounds, |
| 394 int grid_size) { | 454 int grid_size) { |
| 395 if (!did_move_or_resize_ || details_.window_component != HTCAPTION) | 455 if (!did_move_or_resize_ || details_.window_component != HTCAPTION) |
| 396 return; | 456 return; |
| 397 | 457 |
| 398 SnapType last_type = snap_type_; | 458 SnapType last_type = snap_type_; |
| 399 snap_type_ = GetSnapType(location); | 459 snap_type_ = GetSnapType(location); |
| 400 if (snap_type_ == SNAP_NONE || snap_type_ != last_type) { | 460 if (snap_type_ == SNAP_NONE || snap_type_ != last_type) { |
| 401 phantom_window_controller_.reset(); | 461 phantom_window_controller_.reset(); |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 457 gfx::Rect area(ScreenAsh::GetDisplayBoundsInParent(details_.window)); | 517 gfx::Rect area(ScreenAsh::GetDisplayBoundsInParent(details_.window)); |
| 458 if (location.x() <= area.x()) | 518 if (location.x() <= area.x()) |
| 459 return SNAP_LEFT_EDGE; | 519 return SNAP_LEFT_EDGE; |
| 460 if (location.x() >= area.right() - 1) | 520 if (location.x() >= area.right() - 1) |
| 461 return SNAP_RIGHT_EDGE; | 521 return SNAP_RIGHT_EDGE; |
| 462 return SNAP_NONE; | 522 return SNAP_NONE; |
| 463 } | 523 } |
| 464 | 524 |
| 465 } // namespace internal | 525 } // namespace internal |
| 466 } // namespace ash | 526 } // namespace ash |
| OLD | NEW |