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 |