diff options
-rw-r--r-- | ash/wm/dock/docked_window_layout_manager.cc | 96 | ||||
-rw-r--r-- | ash/wm/dock/docked_window_layout_manager.h | 13 | ||||
-rw-r--r-- | ash/wm/dock/docked_window_layout_manager_unittest.cc | 129 | ||||
-rw-r--r-- | ash/wm/dock/docked_window_resizer.cc | 19 | ||||
-rw-r--r-- | ash/wm/dock/docked_window_resizer_unittest.cc | 31 | ||||
-rw-r--r-- | ash/wm/workspace/workspace_window_resizer.cc | 30 | ||||
-rw-r--r-- | ash/wm/workspace/workspace_window_resizer.h | 6 |
7 files changed, 268 insertions, 56 deletions
diff --git a/ash/wm/dock/docked_window_layout_manager.cc b/ash/wm/dock/docked_window_layout_manager.cc index 1601af2..dee78ac 100644 --- a/ash/wm/dock/docked_window_layout_manager.cc +++ b/ash/wm/dock/docked_window_layout_manager.cc @@ -25,6 +25,7 @@ #include "ui/aura/focus_manager.h" #include "ui/aura/root_window.h" #include "ui/aura/window.h" +#include "ui/aura/window_delegate.h" #include "ui/gfx/rect.h" namespace ash { @@ -37,6 +38,8 @@ const int DockedWindowLayoutManager::kMaxDockWidth = 360; const int DockedWindowLayoutManager::kMinDockWidth = 200; // static const int DockedWindowLayoutManager::kMinDockGap = 2; +//static +const int DockedWindowLayoutManager::kIdealWidth = 250; namespace { @@ -291,13 +294,21 @@ bool DockedWindowLayoutManager::CanDockWindow(aura::Window* window, switches::kAshEnableDockedWindows)) { return false; } + // If a window is wide and cannot be resized down to maximum width allowed + // then it cannot be docked. + if (window->bounds().width() > kMaxDockWidth && + (!wm::GetWindowState(window)->CanResize() || + (window->delegate() && + window->delegate()->GetMinimumSize().width() != 0 && + window->delegate()->GetMinimumSize().width() > kMaxDockWidth))) { + return false; + } // Cannot dock on the other size from an existing dock. const DockedAlignment alignment = CalculateAlignment(); if ((edge == SNAP_LEFT && alignment == DOCKED_ALIGNMENT_RIGHT) || (edge == SNAP_RIGHT && alignment == DOCKED_ALIGNMENT_LEFT)) { return false; } - // Do not allow docking on the same side as launcher shelf. ShelfAlignment shelf_alignment = SHELF_ALIGNMENT_BOTTOM; if (launcher_) @@ -531,6 +542,24 @@ bool DockedWindowLayoutManager::IsAnyWindowDocked() { return CalculateAlignment() != DOCKED_ALIGNMENT_NONE; } +// static +int DockedWindowLayoutManager::GetWindowWidthCloseTo(aura::Window* window, + int target_width) { + if (!wm::GetWindowState(window)->CanResize()) { + DCHECK_LE(window->bounds().width(), kMaxDockWidth); + return window->bounds().width(); + } + int width = std::max(kMinDockWidth, std::min(target_width, kMaxDockWidth)); + if (window->delegate()) { + if (window->delegate()->GetMinimumSize().width() != 0) + width = std::max(width, window->delegate()->GetMinimumSize().width()); + if (window->delegate()->GetMaximumSize().width() != 0) + width = std::min(width, window->delegate()->GetMaximumSize().width()); + } + DCHECK_LE(width, kMaxDockWidth); + return width; +} + void DockedWindowLayoutManager::Relayout() { if (in_layout_) return; @@ -541,7 +570,6 @@ void DockedWindowLayoutManager::Relayout() { gfx::Rect dock_bounds = dock_container_->GetBoundsInScreen(); aura::Window* active_window = NULL; aura::Window::Windows visible_windows; - docked_width_ = 0; for (size_t i = 0; i < dock_container_->children().size(); ++i) { aura::Window* window(dock_container_->children()[i]); @@ -577,9 +605,34 @@ void DockedWindowLayoutManager::Relayout() { dock_container_); const gfx::Rect work_area = display.work_area(); int available_room = work_area.height(); + int ideal_docked_width = 0; for (aura::Window::Windows::const_iterator iter = visible_windows.begin(); iter != visible_windows.end(); ++iter) { - available_room -= (*iter)->bounds().height(); + aura::Window* window = *iter; + available_room -= window->bounds().height(); + + // Adjust the dragged window to the dock. If that is not possible then + // other docked windows area adjusted to the one that is being dragged. + int adjusted_docked_width = window->bounds().width(); + if (window == dragged_window_) { + // Adjust the dragged window width to the current dock size or ideal when + // there are no other docked windows. + adjusted_docked_width = GetWindowWidthCloseTo( + window, (docked_width_ > 0) ? docked_width_ : kIdealWidth); + } else if (!is_dragged_from_dock_ && is_dragged_window_docked_) { + // When a docked window is dragged-in other docked windows' widths are + // adjusted to the new width if necessary. + // When there is no dragged docked window the docked windows retain their + // widths. + // When a dragged window is simply being reordered in the docked area the + // other windows are not resized (but the dragged window can be). + adjusted_docked_width = GetWindowWidthCloseTo(window, 0); + } + ideal_docked_width = std::max(ideal_docked_width, adjusted_docked_width); + + // Restrict docked area width regardless of window restrictions. + ideal_docked_width = std::max(std::min(ideal_docked_width, kMaxDockWidth), + kMinDockWidth); } const int num_windows = visible_windows.size(); const float delta = (float)available_room / @@ -587,18 +640,35 @@ void DockedWindowLayoutManager::Relayout() { num_windows + 1 : num_windows - 1); float y_pos = work_area.y() + ((available_room > 0) ? delta : 0); + // Docked area is shown only if there is at least one non-dragged visible + // docked window. + docked_width_ = ideal_docked_width; + if (visible_windows.empty() || + (visible_windows.size() == 1 && visible_windows[0] == dragged_window_)) { + docked_width_ = 0; + } + // Sort windows by their center positions and fan out overlapping // windows. std::sort(visible_windows.begin(), visible_windows.end(), CompareWindowPos(is_dragged_from_dock_ ? dragged_window_ : NULL, delta)); - is_dragged_from_dock_ = true; for (aura::Window::Windows::const_iterator iter = visible_windows.begin(); iter != visible_windows.end(); ++iter) { aura::Window* window = *iter; gfx::Rect bounds = window->GetBoundsInScreen(); + // A window is extended or shrunk to be as close as possible to the docked + // area width. Windows other than the dragged window are kept at their + // existing size when the dragged window is just being reordered. + // This also enforces the min / max restrictions on the docked area width. + bounds.set_width(GetWindowWidthCloseTo( + window, + (!is_dragged_from_dock_ || window == dragged_window_) ? + ideal_docked_width : bounds.width())); + DCHECK_LE(bounds.width(), ideal_docked_width); + DockedAlignment alignment = alignment_; if (alignment == DOCKED_ALIGNMENT_NONE && window == dragged_window_) { alignment = GetAlignmentOfWindow(window); @@ -606,10 +676,6 @@ void DockedWindowLayoutManager::Relayout() { bounds.set_size(gfx::Size()); } - // Restrict width. - if (bounds.width() > kMaxDockWidth) - bounds.set_width(kMaxDockWidth); - // Fan out windows evenly distributing the overlap or remaining free space. bounds.set_y(std::max(work_area.y(), std::min(work_area.bottom() - bounds.height(), @@ -617,13 +683,15 @@ void DockedWindowLayoutManager::Relayout() { y_pos += bounds.height() + delta; // All docked windows other than the one currently dragged remain stuck - // to the screen edge. + // to the screen edge (flush with the edge or centered in the dock area). switch (alignment) { case DOCKED_ALIGNMENT_LEFT: - bounds.set_x(dock_bounds.x()); + bounds.set_x(dock_bounds.x() + + (ideal_docked_width - bounds.width()) / 2); break; case DOCKED_ALIGNMENT_RIGHT: - bounds.set_x(dock_bounds.right() - bounds.width()); + bounds.set_x(dock_bounds.right() - + (ideal_docked_width + bounds.width()) / 2); break; case DOCKED_ALIGNMENT_NONE: break; @@ -635,14 +703,10 @@ void DockedWindowLayoutManager::Relayout() { // If the following asserts it is probably because not all the children // have been removed when dock was closed. DCHECK_NE(alignment_, DOCKED_ALIGNMENT_NONE); - // Keep the dock at least kMinDockWidth when all windows in it overhang. - docked_width_ = std::min(kMaxDockWidth, - std::max(docked_width_, - bounds.width() > kMaxDockWidth ? - kMinDockWidth : bounds.width())); bounds = ScreenAsh::ConvertRectFromScreen(dock_container_, bounds); SetChildBoundsDirect(window, bounds); } + is_dragged_from_dock_ = true; UpdateStacking(active_window); } diff --git a/ash/wm/dock/docked_window_layout_manager.h b/ash/wm/dock/docked_window_layout_manager.h index 8bea763..2afbd59 100644 --- a/ash/wm/dock/docked_window_layout_manager.h +++ b/ash/wm/dock/docked_window_layout_manager.h @@ -143,15 +143,20 @@ class ASH_EXPORT DockedWindowLayoutManager ShelfVisibilityState new_state) OVERRIDE; private: + FRIEND_TEST_ALL_PREFIXES(DockedWindowResizerTest, AttachTryDetach); FRIEND_TEST_ALL_PREFIXES(DockedWindowResizerTest, AttachTwoWindowsDetachOne); FRIEND_TEST_ALL_PREFIXES(DockedWindowResizerTest, AttachWindowMaximizeOther); FRIEND_TEST_ALL_PREFIXES(DockedWindowResizerTest, AttachOneTestSticky); FRIEND_TEST_ALL_PREFIXES(DockedWindowResizerTest, ResizeTwoWindows); FRIEND_TEST_ALL_PREFIXES(DockedWindowResizerTest, DragToShelf); + FRIEND_TEST_ALL_PREFIXES(DockedWindowLayoutManagerTest, AddOneWindow); FRIEND_TEST_ALL_PREFIXES(DockedWindowLayoutManagerTest, AutoPlacingLeft); FRIEND_TEST_ALL_PREFIXES(DockedWindowLayoutManagerTest, AutoPlacingRight); FRIEND_TEST_ALL_PREFIXES(DockedWindowLayoutManagerTest, AutoPlacingRightSecondScreen); + FRIEND_TEST_ALL_PREFIXES(DockedWindowLayoutManagerTest, TwoWindowsWidthNew); + FRIEND_TEST_ALL_PREFIXES(DockedWindowLayoutManagerTest, + TwoWindowsWidthNonResizableSecond); friend class DockedWindowLayoutManagerTest; friend class DockedWindowResizerTest; @@ -161,6 +166,9 @@ class ASH_EXPORT DockedWindowLayoutManager // Width of the gap between the docked windows and a workspace. static const int kMinDockGap; + // Ideal (starting) width of the dock. + static const int kIdealWidth; + // Minimize / restore window and relayout. void MinimizeDockedWindow(aura::Window* window); void RestoreDockedWindow(aura::Window* window); @@ -174,6 +182,11 @@ class ASH_EXPORT DockedWindowLayoutManager // Returns true if there are any windows currently docked. bool IsAnyWindowDocked(); + // Returns width that is as close as possible to |target_width| while being + // consistent with docked min and max restrictions and respects the |window|'s + // minimum and maximum size. + static int GetWindowWidthCloseTo(aura::Window* window, int target_width); + // Called whenever the window layout might change. void Relayout(); diff --git a/ash/wm/dock/docked_window_layout_manager_unittest.cc b/ash/wm/dock/docked_window_layout_manager_unittest.cc index 68601ad..87bca92 100644 --- a/ash/wm/dock/docked_window_layout_manager_unittest.cc +++ b/ash/wm/dock/docked_window_layout_manager_unittest.cc @@ -30,6 +30,7 @@ #include "base/strings/string_number_conversions.h" #include "ui/aura/client/aura_constants.h" #include "ui/aura/root_window.h" +#include "ui/aura/test/test_window_delegate.h" #include "ui/aura/window.h" #include "ui/base/hit_test.h" #include "ui/gfx/screen.h" @@ -68,10 +69,24 @@ class DockedWindowLayoutManagerTest aura::Window* CreateTestWindow(const gfx::Rect& bounds) { aura::Window* window = CreateTestWindowInShellWithDelegateAndType( - NULL, - window_type_, - 0, - bounds); + NULL, window_type_, 0, bounds); + if (window_type_ == aura::client::WINDOW_TYPE_PANEL) { + test::TestLauncherDelegate* launcher_delegate = + test::TestLauncherDelegate::instance(); + launcher_delegate->AddLauncherItem(window); + PanelLayoutManager* manager = + static_cast<PanelLayoutManager*>(GetPanelContainer(window)-> + layout_manager()); + manager->Relayout(); + } + return window; + } + + aura::Window* CreateTestWindowWithDelegate( + const gfx::Rect& bounds, + aura::test::TestWindowDelegate* delegate) { + aura::Window* window = CreateTestWindowInShellWithDelegateAndType( + delegate, window_type_, 0, bounds); if (window_type_ == aura::client::WINDOW_TYPE_PANEL) { test::TestLauncherDelegate* launcher_delegate = test::TestLauncherDelegate::instance(); @@ -216,9 +231,11 @@ TEST_P(DockedWindowLayoutManagerTest, AddOneWindow) { scoped_ptr<aura::Window> window(CreateTestWindow(bounds)); DragRelativeToEdge(DOCKED_EDGE_RIGHT, window.get(), 0); - // The window should be attached and snapped to the right side of the screen. + // The window should be attached and docked at the right edge. + // Its width should shrink or grow to ideal width. EXPECT_EQ(window->GetRootWindow()->bounds().right(), window->GetBoundsInScreen().right()); + EXPECT_EQ(DockedWindowLayoutManager::kIdealWidth, window->bounds().width()); EXPECT_EQ(internal::kShellWindowId_DockedContainer, window->parent()->id()); } @@ -563,6 +580,108 @@ TEST_P(DockedWindowLayoutManagerTest, ThreeWindowsDraggingSecondScreen) { EXPECT_EQ(0, overlap4); } +// Tests that a second window added to the dock is resized to match. +TEST_P(DockedWindowLayoutManagerTest, TwoWindowsWidthNew) { + if (!SupportsHostWindowResize()) + return; + + scoped_ptr<aura::Window> w1(CreateTestWindow(gfx::Rect(0, 0, 201, 201))); + scoped_ptr<aura::Window> w2(CreateTestWindow(gfx::Rect(0, 0, 280, 202))); + DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT, w1.get(), 20); + // The first window should get resized to ideal width. + EXPECT_EQ(DockedWindowLayoutManager::kIdealWidth, w1->bounds().width()); + + DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT, w2.get(), 300); + // The second window should get resized to the existing dock. + EXPECT_EQ(DockedWindowLayoutManager::kIdealWidth, w2->bounds().width()); +} + +// Tests that a first non-resizable window added to the dock is not resized. +TEST_P(DockedWindowLayoutManagerTest, TwoWindowsWidthNonResizableFirst) { + if (!SupportsHostWindowResize()) + return; + + scoped_ptr<aura::Window> w1(CreateTestWindow(gfx::Rect(0, 0, 201, 201))); + w1->SetProperty(aura::client::kCanResizeKey, false); + scoped_ptr<aura::Window> w2(CreateTestWindow(gfx::Rect(0, 0, 280, 202))); + DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT, w1.get(), 20); + // The first window should not get resized. + EXPECT_EQ(201, w1->bounds().width()); + + DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT, w2.get(), 300); + // The second window should get resized to the first window's width. + EXPECT_EQ(w1->bounds().width(), w2->bounds().width()); +} + +// Tests that a second non-resizable window added to the dock is not resized. +TEST_P(DockedWindowLayoutManagerTest, TwoWindowsWidthNonResizableSecond) { + if (!SupportsHostWindowResize()) + return; + + scoped_ptr<aura::Window> w1(CreateTestWindow(gfx::Rect(0, 0, 201, 201))); + scoped_ptr<aura::Window> w2(CreateTestWindow(gfx::Rect(0, 0, 280, 202))); + w2->SetProperty(aura::client::kCanResizeKey, false); + DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT, w1.get(), 20); + // The first window should get resized to ideal width. + EXPECT_EQ(DockedWindowLayoutManager::kIdealWidth, w1->bounds().width()); + + DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT, w2.get(), 300); + // The second window should not get resized. + EXPECT_EQ(280, w2->bounds().width()); + + // The first window should get resized again - to match the second window. + EXPECT_EQ(w1->bounds().width(), w2->bounds().width()); +} + +// Test that restrictions on minimum and maximum width of windows are honored. +TEST_P(DockedWindowLayoutManagerTest, TwoWindowsWidthRestrictions) { + if (!SupportsHostWindowResize()) + return; + + aura::test::TestWindowDelegate delegate1; + delegate1.set_maximum_size(gfx::Size(240, 0)); + scoped_ptr<aura::Window> w1(CreateTestWindowWithDelegate( + gfx::Rect(0, 0, 201, 201), &delegate1)); + aura::test::TestWindowDelegate delegate2; + delegate2.set_minimum_size(gfx::Size(260, 0)); + scoped_ptr<aura::Window> w2(CreateTestWindowWithDelegate( + gfx::Rect(0, 0, 280, 202), &delegate2)); + DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT, w1.get(), 20); + // The first window should get resized to its maximum width. + EXPECT_EQ(240, w1->bounds().width()); + + DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT, w2.get(), 300); + // The second window should get resized to its minimum width. + EXPECT_EQ(260, w2->bounds().width()); + + // The first window should be centered relative to the second. + EXPECT_EQ(w1->bounds().CenterPoint().x(), w2->bounds().CenterPoint().x()); +} + +// Test that restrictions on minimum and maximum width of windows are honored. +TEST_P(DockedWindowLayoutManagerTest, WidthMoreThanMax) { + if (!SupportsHostWindowResize()) + return; + + aura::test::TestWindowDelegate delegate; + delegate.set_minimum_size(gfx::Size(400, 0)); + scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate( + gfx::Rect(0, 0, 400, 201), &delegate)); + DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT, window.get(), 20); + + // Secondary drag ensures that we are testing the minimum size restriction + // and not just failure to get past the tiling step in SnapSizer. + ASSERT_NO_FATAL_FAILURE(DragStartAtOffsetFromwindowOrigin(window.get(), + 25, 5)); + DragMove(150,0); + DragEnd(); + + // The window should not get docked even though it is dragged past the edge. + EXPECT_NE(window->GetRootWindow()->bounds().right(), + window->GetBoundsInScreen().right()); + EXPECT_NE(internal::kShellWindowId_DockedContainer, window->parent()->id()); +} + // Tests run twice - on both panels and normal windows INSTANTIATE_TEST_CASE_P(NormalOrPanel, DockedWindowLayoutManagerTest, diff --git a/ash/wm/dock/docked_window_resizer.cc b/ash/wm/dock/docked_window_resizer.cc index 2882f3b..c0ca976 100644 --- a/ash/wm/dock/docked_window_resizer.cc +++ b/ash/wm/dock/docked_window_resizer.cc @@ -187,11 +187,6 @@ bool DockedWindowResizer::MaybeSnapToEdge(const gfx::Rect& bounds, GetTarget()->parent(), dock_layout_->dock_container()->GetBoundsInScreen()); - // Distance in pixels that the cursor must move past an edge for a window - // to move beyond that edge. Same constant as in WorkspaceWindowResizer - // is used for consistency. - const int kStickyDistance = WorkspaceWindowResizer::kStickyDistancePixels; - // Short-range magnetism when retaining docked state. Same constant as in // MagnetismMatcher is used for consistency. const int kSnapToDockDistance = MagnetismMatcher::kMagneticDistance; @@ -199,7 +194,7 @@ bool DockedWindowResizer::MaybeSnapToEdge(const gfx::Rect& bounds, if (dock_alignment == DOCKED_ALIGNMENT_LEFT || dock_alignment == DOCKED_ALIGNMENT_NONE) { const int distance = bounds.x() - dock_bounds.x(); - if (distance < kSnapToDockDistance && distance > -kStickyDistance) { + if (distance < kSnapToDockDistance && distance > 0) { offset->set_x(-distance); return true; } @@ -207,7 +202,7 @@ bool DockedWindowResizer::MaybeSnapToEdge(const gfx::Rect& bounds, if (dock_alignment == DOCKED_ALIGNMENT_RIGHT || dock_alignment == DOCKED_ALIGNMENT_NONE) { const int distance = dock_bounds.right() - bounds.right(); - if (distance < kSnapToDockDistance && distance > -kStickyDistance) { + if (distance < kSnapToDockDistance && distance > 0) { offset->set_x(distance); return true; } @@ -249,6 +244,16 @@ void DockedWindowResizer::FinishedDragging() { window_state->panel_attached(); const bool is_resized = (details_.bounds_change & WindowResizer::kBoundsChange_Resizes) != 0; + + // When drag is completed the dragged docked window is resized to the bounds + // calculated by the layout manager that conform to other docked windows. + if (!attached_panel && is_docked_ && !is_resized) { + gfx::Rect bounds = ScreenAsh::ConvertRectFromScreen( + window->parent(), dock_layout_->dragged_bounds()); + if (!bounds.IsEmpty() && bounds.width() != window->bounds().width()) { + window->SetBounds(bounds); + } + } // No longer restore to pre-docked bounds if a window has been resized. if (is_resized && is_docked_) window_state->ClearRestoreBounds(); diff --git a/ash/wm/dock/docked_window_resizer_unittest.cc b/ash/wm/dock/docked_window_resizer_unittest.cc index 024187c..1808be1 100644 --- a/ash/wm/dock/docked_window_resizer_unittest.cc +++ b/ash/wm/dock/docked_window_resizer_unittest.cc @@ -367,17 +367,22 @@ TEST_P(DockedWindowResizerTest, AttachTryDetach) { if (!SupportsHostWindowResize()) return; - scoped_ptr<aura::Window> window(CreateTestWindow(gfx::Rect(0, 0, 201, 201))); + scoped_ptr<aura::Window> window(CreateTestWindow( + gfx::Rect(0, 0, DockedWindowLayoutManager::kIdealWidth + 10, 201))); DragRelativeToEdge(DOCKED_EDGE_RIGHT, window.get(), 0); - // The window should be attached and snapped to the right edge. + // The window should be attached and docked at the right edge. + // Its width should shrink to ideal width. EXPECT_EQ(window->GetRootWindow()->bounds().right(), window->GetBoundsInScreen().right()); + EXPECT_EQ(DockedWindowLayoutManager::kIdealWidth, + window->GetBoundsInScreen().width()); EXPECT_EQ(internal::kShellWindowId_DockedContainer, window->parent()->id()); // Try to detach by dragging left less than kSnapToDockDistance. // The window should stay docked. - ASSERT_NO_FATAL_FAILURE(DragStart(window.get())); + ASSERT_NO_FATAL_FAILURE(DragStartAtOffsetFromwindowOrigin( + window.get(), 10, 0)); DragMove(-4, -10); // Release the mouse and the window should be still attached to the dock. DragEnd(); @@ -389,14 +394,14 @@ TEST_P(DockedWindowResizerTest, AttachTryDetach) { // Try to detach by dragging left by kSnapToDockDistance or more. // The window should get undocked. + const int left_edge = window->bounds().x(); ASSERT_NO_FATAL_FAILURE(DragStart(window.get())); DragMove(-32, -10); // Release the mouse and the window should be no longer attached to the dock. DragEnd(); - // The window should be floating on the desktop again. - EXPECT_EQ(window->GetRootWindow()->bounds().right() - 32, - window->GetBoundsInScreen().right()); + // The window should be floating on the desktop again and moved to the left. + EXPECT_EQ(left_edge - 32, window->GetBoundsInScreen().x()); EXPECT_EQ(internal::kShellWindowId_DefaultContainer, window->parent()->id()); } @@ -445,6 +450,7 @@ TEST_P(DockedWindowResizerTest, AttachTwoWindows) EXPECT_EQ(internal::kShellWindowId_DockedContainer, w2->parent()->id()); // Detach by dragging left (should get undocked). + const int left_edge = w2->bounds().x(); ASSERT_NO_FATAL_FAILURE(DragStart(w2.get())); // Drag up as well to avoid attaching panels to launcher shelf. DragMove(-32, -100); @@ -456,9 +462,8 @@ TEST_P(DockedWindowResizerTest, AttachTwoWindows) w1->GetBoundsInScreen().right()); EXPECT_EQ(internal::kShellWindowId_DockedContainer, w1->parent()->id()); - // The second window should be floating on the desktop again. - EXPECT_EQ(w2->GetRootWindow()->bounds().right() - 32, - w2->GetBoundsInScreen().right()); + // The window should be floating on the desktop again and moved to the left. + EXPECT_EQ(left_edge - 32, w2->GetBoundsInScreen().x()); EXPECT_EQ(internal::kShellWindowId_DefaultContainer, w2->parent()->id()); } @@ -631,19 +636,19 @@ TEST_P(DockedWindowResizerTest, AttachTwoWindowsDetachOne) EXPECT_EQ(internal::kShellWindowId_DockedContainer, w2->parent()->id()); // Detach by dragging left more (should get undocked). + const int left_edge = w2->bounds().x(); ASSERT_NO_FATAL_FAILURE(DragStartAtOffsetFromwindowOrigin( w2.get(), w2->bounds().width()/2 + 10, 0)); // Drag up as well to avoid attaching panels to launcher shelf. - DragMove(-(w2->bounds().width()/2 + 20), -100); + const int drag_x = -(w2->bounds().width()/2 + 20); + DragMove(drag_x, -100); // Release the mouse and the window should be no longer attached to the edge. DragEnd(); // The second window should be floating on the desktop again. - EXPECT_EQ(w2->GetRootWindow()->bounds().right() - - (w2->bounds().width()/2 + 20), - w2->GetBoundsInScreen().right()); + EXPECT_EQ(left_edge + drag_x, w2->bounds().x()); EXPECT_EQ(internal::kShellWindowId_DefaultContainer, w2->parent()->id()); // Dock width should be set to remaining single docked window. EXPECT_EQ(internal::kShellWindowId_DockedContainer, w1->parent()->id()); diff --git a/ash/wm/workspace/workspace_window_resizer.cc b/ash/wm/workspace/workspace_window_resizer.cc index 29be68b..81c34e6 100644 --- a/ash/wm/workspace/workspace_window_resizer.cc +++ b/ash/wm/workspace/workspace_window_resizer.cc @@ -418,7 +418,7 @@ void WorkspaceWindowResizer::Drag(const gfx::Point& location_in_parent, snap_type_ = SNAP_NONE; snap_phantom_window_controller_.reset(); snap_sizer_.reset(); - UpdateDockedState(false); + SetDraggedWindowDocked(false); } } @@ -894,9 +894,10 @@ void WorkspaceWindowResizer::UpdateSnapPhantomWindow(const gfx::Point& location, if (snap_type_ == SNAP_NONE || snap_type_ != last_type) { snap_phantom_window_controller_.reset(); snap_sizer_.reset(); - UpdateDockedState(false); - if (snap_type_ == SNAP_NONE) + if (snap_type_ == SNAP_NONE) { + SetDraggedWindowDocked(false); return; + } } SnapSizer::Edge edge = (snap_type_ == SNAP_LEFT) ? SnapSizer::LEFT_EDGE : SnapSizer::RIGHT_EDGE; @@ -911,20 +912,25 @@ void WorkspaceWindowResizer::UpdateSnapPhantomWindow(const gfx::Point& location, } const bool can_dock = dock_layout_->CanDockWindow(window(), snap_type_); - if (!window_state()->CanSnap() && !can_dock) + const bool can_snap = window_state()->CanSnap(); + if (!can_snap && !can_dock) return; // Update phantom window with snapped or docked guide bounds. // Windows that cannot be snapped or are less wide than kMaxDockWidth can get // docked without going through a snapping sequence. gfx::Rect phantom_bounds; - if (!can_dock || - window()->bounds().width() > DockedWindowLayoutManager::kMaxDockWidth) + if (can_snap && + (!can_dock || + window()->bounds().width() > DockedWindowLayoutManager::kMaxDockWidth)) phantom_bounds = snap_sizer_->target_bounds(); - const bool is_docked = can_dock && - (phantom_bounds.IsEmpty() || snap_sizer_->end_of_sequence()); - UpdateDockedState(is_docked); - if (is_docked) { + const bool should_dock = can_dock && + (phantom_bounds.IsEmpty() || + snap_sizer_->end_of_sequence() || + dock_layout_->is_dragged_window_docked()); + SetDraggedWindowDocked(should_dock); + snap_type_ = GetSnapType(location); + if (dock_layout_->is_dragged_window_docked()) { phantom_bounds = ScreenAsh::ConvertRectFromScreen( window()->parent(), dock_layout_->dragged_bounds()); } @@ -985,8 +991,8 @@ SnapType WorkspaceWindowResizer::GetSnapType( return SNAP_NONE; } -void WorkspaceWindowResizer::UpdateDockedState(bool is_docked) { - if (is_docked && +void WorkspaceWindowResizer::SetDraggedWindowDocked(bool should_dock) { + if (should_dock && dock_layout_->GetAlignmentOfWindow(window()) != DOCKED_ALIGNMENT_NONE) { if (!dock_layout_->is_dragged_window_docked()) dock_layout_->DockDraggedWindow(window()); diff --git a/ash/wm/workspace/workspace_window_resizer.h b/ash/wm/workspace/workspace_window_resizer.h index 1cd0942..5acaf8e 100644 --- a/ash/wm/workspace/workspace_window_resizer.h +++ b/ash/wm/workspace/workspace_window_resizer.h @@ -161,9 +161,9 @@ class ASH_EXPORT WorkspaceWindowResizer : public WindowResizer { // snapping should be used. SnapType GetSnapType(const gfx::Point& location) const; - // Dock when a window is at its last step in snapping sequence, undock - // otherwise. - void UpdateDockedState(bool is_docked); + // Docks the dragged window if |should_dock| and the window can be docked. + // Undocks the window if |should_dock| is false. + void SetDraggedWindowDocked(bool should_dock); aura::Window* window() const { return details_.window; } |