Index: ash/wm/workspace/workspace_window_resizer.cc |
diff --git a/ash/wm/workspace/workspace_window_resizer.cc b/ash/wm/workspace/workspace_window_resizer.cc |
index 000260c0399eb55341aeaffe356806ce55e4603e..57c70f68d569a3b29c20b19a00c153b20f1c082f 100644 |
--- a/ash/wm/workspace/workspace_window_resizer.cc |
+++ b/ash/wm/workspace/workspace_window_resizer.cc |
@@ -41,6 +41,23 @@ bool ShouldSnapToEdge(int distance_from_edge, int grid_size) { |
distance_from_edge > -grid_size * 2; |
} |
+// Returns true if Ash has more than one root window. |
+bool HasSecondaryRootWindow() { |
+ return Shell::GetAllRootWindows().size() > 1; |
+} |
+ |
+// When there are two root windows, returns one of the root windows which is not |
+// |root_window|. Returns NULL if only one root window exists. |
+aura::RootWindow* GetAnotherRootWindow(aura::RootWindow* root_window) { |
+ Shell::RootWindowList root_windows = Shell::GetAllRootWindows(); |
+ if (root_windows.size() < 2) |
+ return NULL; |
+ DCHECK_EQ(2U, root_windows.size()); |
+ if (root_windows[0] == root_window) |
+ return root_windows[1]; |
+ return root_windows[0]; |
+} |
+ |
} // namespace |
// static |
@@ -69,15 +86,23 @@ WorkspaceWindowResizer* WorkspaceWindowResizer::Create( |
void WorkspaceWindowResizer::Drag(const gfx::Point& location, int event_flags) { |
std::pair<aura::RootWindow*, gfx::Point> actual_location = |
wm::GetRootWindowRelativeToWindow(window()->parent(), location); |
- |
- // TODO(yusukes): Implement dragging a window from one display to another. |
aura::RootWindow* current_root = actual_location.first; |
- if (current_root != window()->GetRootWindow()) |
- return; |
+ gfx::Point location_in_parent = actual_location.second; |
+ aura::Window::ConvertPointToWindow(current_root, |
+ window()->parent(), |
+ &location_in_parent); |
+ |
+ // Do not use |location| below this point, use |location_in_parent| instead. |
+ // When the pointer is on |window()->GetRootWindow()|, |location| and |
+ // |location_in_parent| have the same value and both of them are in |
+ // |window()->parent()|'s coordinates, but once the pointer enters the |
+ // other root window, you will see an unexpected value on the former. See |
+ // comments in wm::GetRootWindowRelativeToWindow() for details. |
int grid_size = event_flags & ui::EF_CONTROL_DOWN ? |
0 : ash::Shell::GetInstance()->GetGridSize(); |
- gfx::Rect bounds = CalculateBoundsForDrag(details_, location, grid_size); |
+ gfx::Rect bounds = // in |window()->parent()|'s coordinates. |
+ CalculateBoundsForDrag(details_, location_in_parent, grid_size); |
if (wm::IsWindowNormal(details_.window)) |
AdjustBoundsForMainWindow(&bounds, grid_size); |
@@ -86,7 +111,20 @@ void WorkspaceWindowResizer::Drag(const gfx::Point& location, int event_flags) { |
RestackWindows(); |
did_move_or_resize_ = true; |
} |
- UpdatePhantomWindow(location, bounds, grid_size); |
+ |
+ const bool in_original_root = (window()->GetRootWindow() == current_root); |
+ // Hide a phantom window for snapping if the cursor is in another root window. |
+ if (in_original_root) |
+ UpdateSnapPhantomWindow(location_in_parent, bounds, grid_size); |
+ else |
+ snap_phantom_window_controller_.reset(); |
+ |
+ // Show a phantom window for dragging in another root window. |
+ if (HasSecondaryRootWindow()) |
+ UpdateDragPhantomWindow(bounds); |
+ else |
+ drag_phantom_window_controller_.reset(); |
+ |
if (!attached_windows_.empty()) |
LayoutAttachedWindows(bounds, grid_size); |
if (bounds != details_.window->bounds()) |
@@ -95,7 +133,8 @@ void WorkspaceWindowResizer::Drag(const gfx::Point& location, int event_flags) { |
} |
void WorkspaceWindowResizer::CompleteDrag(int event_flags) { |
- phantom_window_controller_.reset(); |
+ drag_phantom_window_controller_.reset(); |
+ snap_phantom_window_controller_.reset(); |
if (!did_move_or_resize_ || details_.window_component != HTCAPTION) |
return; |
@@ -140,7 +179,8 @@ void WorkspaceWindowResizer::CompleteDrag(int event_flags) { |
} |
void WorkspaceWindowResizer::RevertDrag() { |
- phantom_window_controller_.reset(); |
+ drag_phantom_window_controller_.reset(); |
+ snap_phantom_window_controller_.reset(); |
if (!did_move_or_resize_) |
return; |
@@ -233,9 +273,9 @@ WorkspaceWindowResizer::WorkspaceWindowResizer( |
gfx::Rect WorkspaceWindowResizer::GetFinalBounds( |
const gfx::Rect& bounds, |
int grid_size) const { |
- if (phantom_window_controller_.get() && |
- phantom_window_controller_->IsShowing()) { |
- return phantom_window_controller_->bounds(); |
+ if (snap_phantom_window_controller_.get() && |
+ snap_phantom_window_controller_->IsShowing()) { |
+ return snap_phantom_window_controller_->bounds(); |
} |
return AdjustBoundsToGrid(bounds, grid_size); |
} |
@@ -312,17 +352,23 @@ void WorkspaceWindowResizer::CalculateAttachedSizes( |
void WorkspaceWindowResizer::AdjustBoundsForMainWindow( |
gfx::Rect* bounds, int grid_size) const { |
- // Always keep kMinOnscreenHeight on the bottom. |
+ // Always keep kMinOnscreenHeight on the bottom except when an extended |
+ // display is available and a window is being dragged. |
gfx::Rect work_area( |
ScreenAsh::GetDisplayWorkAreaBoundsInParent(details_.window)); |
int max_y = AlignToGridRoundUp(work_area.bottom() - kMinOnscreenHeight, |
grid_size); |
- if (bounds->y() > max_y) |
+ if ((details_.window_component != HTCAPTION || !HasSecondaryRootWindow()) && |
+ bounds->y() > max_y) { |
bounds->set_y(max_y); |
+ } |
- // Don't allow dragging above the top of the display. |
- if (bounds->y() <= work_area.y()) |
+ // Don't allow dragging above the top of the display except when an extended |
+ // display is available and a window is being dragged. |
+ if ((details_.window_component != HTCAPTION || !HasSecondaryRootWindow()) && |
+ bounds->y() <= work_area.y()) { |
bounds->set_y(work_area.y()); |
+ } |
if (grid_size >= 0 && details_.window_component == HTCAPTION) |
SnapToWorkAreaEdges(work_area, bounds, grid_size); |
@@ -391,16 +437,43 @@ int WorkspaceWindowResizer::PrimaryAxisCoordinate(int x, int y) const { |
return 0; |
} |
-void WorkspaceWindowResizer::UpdatePhantomWindow(const gfx::Point& location, |
- const gfx::Rect& bounds, |
- int grid_size) { |
+void WorkspaceWindowResizer::UpdateDragPhantomWindow(const gfx::Rect& bounds) { |
+ if (!did_move_or_resize_ || details_.window_component != HTCAPTION || |
+ !ShouldAllowMouseWarp()) { |
+ return; |
+ } |
+ |
+ // It's available. Show a phantom window on the display if needed. |
+ aura::RootWindow* another_root = |
+ GetAnotherRootWindow(window()->GetRootWindow()); |
+ const gfx::Rect root_bounds_in_screen(another_root->GetBoundsInScreen()); |
+ const gfx::Rect bounds_in_screen = |
+ ScreenAsh::ConvertRectToScreen(window()->parent(), bounds); |
+ const gfx::Rect phantom(root_bounds_in_screen.Intersect(bounds_in_screen)); |
+ |
+ if (!phantom.IsEmpty()) { |
+ if (!drag_phantom_window_controller_.get()) { |
+ drag_phantom_window_controller_.reset( |
+ new PhantomWindowController(window())); |
+ drag_phantom_window_controller_->Show(phantom); |
+ } else { |
+ drag_phantom_window_controller_->SetBounds(phantom); // no animation |
+ } |
+ } else { |
+ drag_phantom_window_controller_.reset(); |
+ } |
+} |
+ |
+void WorkspaceWindowResizer::UpdateSnapPhantomWindow(const gfx::Point& location, |
+ const gfx::Rect& bounds, |
+ int grid_size) { |
if (!did_move_or_resize_ || details_.window_component != HTCAPTION) |
return; |
SnapType last_type = snap_type_; |
snap_type_ = GetSnapType(location); |
if (snap_type_ == SNAP_NONE || snap_type_ != last_type) { |
- phantom_window_controller_.reset(); |
+ snap_phantom_window_controller_.reset(); |
snap_sizer_.reset(); |
if (snap_type_ == SNAP_NONE) |
return; |
@@ -413,11 +486,11 @@ void WorkspaceWindowResizer::UpdatePhantomWindow(const gfx::Point& location, |
} else { |
snap_sizer_->Update(location); |
} |
- if (!phantom_window_controller_.get()) { |
- phantom_window_controller_.reset( |
+ if (!snap_phantom_window_controller_.get()) { |
+ snap_phantom_window_controller_.reset( |
new PhantomWindowController(details_.window)); |
} |
- phantom_window_controller_->Show(ScreenAsh::ConvertRectToScreen( |
+ snap_phantom_window_controller_->Show(ScreenAsh::ConvertRectToScreen( |
details_.window->parent(), snap_sizer_->target_bounds())); |
} |