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

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: review 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 22 matching lines...) Expand all
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
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
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
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
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