Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(72)

Side by Side Diff: ash/wm/workspace/workspace_window_resizer.cc

Issue 10834097: Allow the user to drag a window from one display to another (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: address comments Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « ash/wm/workspace/workspace_window_resizer.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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());
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_parent = actual_location.second;
91 aura::Window::ConvertPointToWindow(current_root,
92 window()->parent(),
93 &location_in_parent);
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_parent| instead.
74 aura::RootWindow* current_root = actual_location.first; 96 // When the pointer is on |window()->GetRootWindow()|, |location| and
75 if (current_root != window()->GetRootWindow()) 97 // |location_in_parent| have the same value and both of them are in
76 return; 98 // |window()->parent()|'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()->parent()|'s coordinates.
105 CalculateBoundsForDrag(details_, location_in_parent, grid_size);
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 UpdateSnapPhantomWindow(location_in_parent, bounds, grid_size);
119 else
120 snap_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) {
98 phantom_window_controller_.reset(); 136 drag_phantom_window_controller_.reset();
137 snap_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 }
108 147
(...skipping 24 matching lines...) Expand all
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() {
143 phantom_window_controller_.reset(); 182 drag_phantom_window_controller_.reset();
183 snap_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());
153 bounds.set_x(last_x); 193 bounds.set_x(last_x);
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
226 static_cast<float>(total_available)); 266 static_cast<float>(total_available));
227 } else { 267 } else {
228 compress_fraction_.push_back(0.0f); 268 compress_fraction_.push_back(0.0f);
229 } 269 }
230 } 270 }
231 } 271 }
232 272
233 gfx::Rect WorkspaceWindowResizer::GetFinalBounds( 273 gfx::Rect WorkspaceWindowResizer::GetFinalBounds(
234 const gfx::Rect& bounds, 274 const gfx::Rect& bounds,
235 int grid_size) const { 275 int grid_size) const {
236 if (phantom_window_controller_.get() && 276 if (snap_phantom_window_controller_.get() &&
237 phantom_window_controller_->IsShowing()) { 277 snap_phantom_window_controller_->IsShowing()) {
238 return phantom_window_controller_->bounds(); 278 return snap_phantom_window_controller_->bounds();
239 } 279 }
240 return AdjustBoundsToGrid(bounds, grid_size); 280 return AdjustBoundsToGrid(bounds, grid_size);
241 } 281 }
242 282
243 void WorkspaceWindowResizer::LayoutAttachedWindows( 283 void WorkspaceWindowResizer::LayoutAttachedWindows(
244 const gfx::Rect& bounds, 284 const gfx::Rect& bounds,
245 int grid_size) { 285 int grid_size) {
246 gfx::Rect work_area( 286 gfx::Rect work_area(
247 gfx::Screen::GetDisplayNearestWindow(window()).work_area()); 287 gfx::Screen::GetDisplayNearestWindow(window()).work_area());
248 std::vector<int> sizes; 288 std::vector<int> sizes;
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
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.
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
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
394 void WorkspaceWindowResizer::UpdatePhantomWindow(const gfx::Point& location, 440 void WorkspaceWindowResizer::UpdateDragPhantomWindow(const gfx::Rect& bounds) {
395 const gfx::Rect& bounds, 441 if (!did_move_or_resize_ || details_.window_component != HTCAPTION ||
396 int grid_size) { 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()->parent(), 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
467 void WorkspaceWindowResizer::UpdateSnapPhantomWindow(const gfx::Point& location,
468 const gfx::Rect& bounds,
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 snap_phantom_window_controller_.reset();
404 snap_sizer_.reset(); 477 snap_sizer_.reset();
405 if (snap_type_ == SNAP_NONE) 478 if (snap_type_ == SNAP_NONE)
406 return; 479 return;
407 } 480 }
408 if (!snap_sizer_.get()) { 481 if (!snap_sizer_.get()) {
409 SnapSizer::Edge edge = (snap_type_ == SNAP_LEFT_EDGE) ? 482 SnapSizer::Edge edge = (snap_type_ == SNAP_LEFT_EDGE) ?
410 SnapSizer::LEFT_EDGE : SnapSizer::RIGHT_EDGE; 483 SnapSizer::LEFT_EDGE : SnapSizer::RIGHT_EDGE;
411 snap_sizer_.reset( 484 snap_sizer_.reset(
412 new SnapSizer(details_.window, location, edge, grid_size)); 485 new SnapSizer(details_.window, location, edge, grid_size));
413 } else { 486 } else {
414 snap_sizer_->Update(location); 487 snap_sizer_->Update(location);
415 } 488 }
416 if (!phantom_window_controller_.get()) { 489 if (!snap_phantom_window_controller_.get()) {
417 phantom_window_controller_.reset( 490 snap_phantom_window_controller_.reset(
418 new PhantomWindowController(details_.window)); 491 new PhantomWindowController(details_.window));
419 } 492 }
420 phantom_window_controller_->Show(ScreenAsh::ConvertRectToScreen( 493 snap_phantom_window_controller_->Show(ScreenAsh::ConvertRectToScreen(
421 details_.window->parent(), snap_sizer_->target_bounds())); 494 details_.window->parent(), snap_sizer_->target_bounds()));
422 } 495 }
423 496
424 void WorkspaceWindowResizer::RestackWindows() { 497 void WorkspaceWindowResizer::RestackWindows() {
425 if (attached_windows_.empty()) 498 if (attached_windows_.empty())
426 return; 499 return;
427 // Build a map from index in children to window, returning if there is a 500 // Build a map from index in children to window, returning if there is a
428 // window with a different parent. 501 // window with a different parent.
429 typedef std::map<size_t, aura::Window*> IndexToWindowMap; 502 typedef std::map<size_t, aura::Window*> IndexToWindowMap;
430 IndexToWindowMap map; 503 IndexToWindowMap map;
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
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
OLDNEW
« no previous file with comments | « ash/wm/workspace/workspace_window_resizer.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698