Commit 76ab6dc5 authored by Eliot Courtney's avatar Eliot Courtney Committed by Commit Bot

End any resizing upon exiting SplitView mode or the window being minimized/destroyed.

This covers the following cases:
1. Transition to clamshell mode while resizing.
2. Minimize/destroy a window while resizing with splitview with two windows.
3. Minimize/destroy a window while resizing with splitview with one window.

BUG=b/72806943

Change-Id: I3d85ea882722b8d2bfe9361287bf78d9cae9d88a
Reviewed-on: https://chromium-review.googlesource.com/1000659
Commit-Queue: Eliot Courtney <edcourtney@chromium.org>
Reviewed-by: default avatarMitsuru Oshima <oshima@chromium.org>
Cr-Commit-Position: refs/heads/master@{#549996}
parent dc3ed43a
...@@ -405,14 +405,8 @@ void SplitViewController::EndResize(const gfx::Point& location_in_screen) { ...@@ -405,14 +405,8 @@ void SplitViewController::EndResize(const gfx::Point& location_in_screen) {
// smoother resizing visual result. // smoother resizing visual result.
UpdateSnappedWindowsAndDividerBounds(); UpdateSnappedWindowsAndDividerBounds();
for (auto* window : {left_window_, right_window_}) { FinishWindowDrag(left_window_);
if (window == nullptr) FinishWindowDrag(right_window_);
continue;
wm::WindowState* window_state = wm::GetWindowState(window);
window_state->OnCompleteDrag(
GetEndDragLocationInScreen(window, location_in_screen));
window_state->DeleteDragDetails();
}
// Need to update snapped windows bounds even if the split view mode may have // Need to update snapped windows bounds even if the split view mode may have
// to exit. Otherwise it's possible for a snapped window stuck in the edge of // to exit. Otherwise it's possible for a snapped window stuck in the edge of
...@@ -451,6 +445,14 @@ void SplitViewController::EndSplitView() { ...@@ -451,6 +445,14 @@ void SplitViewController::EndSplitView() {
if (!IsSplitViewModeActive()) if (!IsSplitViewModeActive())
return; return;
// If we are currently in a resize but split view is ending, make sure to end
// the resize. This can happen, for example, on the transition back to
// clamshell mode or when a task is minimized during a resize.
if (is_resizing_) {
FinishWindowDrag(left_window_);
FinishWindowDrag(right_window_);
}
// Remove observers when the split view mode ends. // Remove observers when the split view mode ends.
Shell::Get()->RemoveShellObserver(this); Shell::Get()->RemoveShellObserver(this);
Shell::Get()->activation_client()->RemoveObserver(this); Shell::Get()->activation_client()->RemoveObserver(this);
...@@ -983,6 +985,13 @@ void SplitViewController::OnSnappedWindowMinimizedOrDestroyed( ...@@ -983,6 +985,13 @@ void SplitViewController::OnSnappedWindowMinimizedOrDestroyed(
right_window_ = nullptr; right_window_ = nullptr;
} }
if (is_resizing_) {
// If the window is minimized or destroyed before the resize ends, if/when
// EndResize() is eventually called, it will have no way of knowing that
// it should finish the drag for the destroyed window. So, do it here.
FinishWindowDrag(window);
}
if (!left_window_ && !right_window_) { if (!left_window_ && !right_window_) {
// If there is no snapped window at this moment, ends split view mode. Note // If there is no snapped window at this moment, ends split view mode. Note
// this will update overview window grid bounds if the overview mode is // this will update overview window grid bounds if the overview mode is
...@@ -1249,4 +1258,13 @@ void SplitViewController::EndOverview() { ...@@ -1249,4 +1258,13 @@ void SplitViewController::EndOverview() {
Shell::Get()->window_selector_controller()->ToggleOverview(); Shell::Get()->window_selector_controller()->ToggleOverview();
} }
void SplitViewController::FinishWindowDrag(aura::Window* window) {
if (window != nullptr) {
wm::WindowState* window_state = wm::GetWindowState(window);
window_state->OnCompleteDrag(
GetEndDragLocationInScreen(window, previous_event_location_));
window_state->DeleteDragDetails();
}
}
} // namespace ash } // namespace ash
...@@ -303,6 +303,9 @@ class ASH_EXPORT SplitViewController : public mojom::SplitViewController, ...@@ -303,6 +303,9 @@ class ASH_EXPORT SplitViewController : public mojom::SplitViewController,
void StartOverview(); void StartOverview();
void EndOverview(); void EndOverview();
// Finalizes and cleans up after a drag or resize is finished for a window.
void FinishWindowDrag(aura::Window* window);
// Bindings for the SplitViewController interface. // Bindings for the SplitViewController interface.
mojo::BindingSet<mojom::SplitViewController> bindings_; mojo::BindingSet<mojom::SplitViewController> bindings_;
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include "ash/wm/splitview/split_view_divider.h" #include "ash/wm/splitview/split_view_divider.h"
#include "ash/wm/tablet_mode/tablet_mode_controller.h" #include "ash/wm/tablet_mode/tablet_mode_controller.h"
#include "ash/wm/window_state.h" #include "ash/wm/window_state.h"
#include "ash/wm/window_state_delegate.h"
#include "ash/wm/window_util.h" #include "ash/wm/window_util.h"
#include "ash/wm/wm_event.h" #include "ash/wm/wm_event.h"
#include "base/stl_util.h" #include "base/stl_util.h"
...@@ -110,6 +111,24 @@ class SplitViewControllerTest : public AshTestBase { ...@@ -110,6 +111,24 @@ class SplitViewControllerTest : public AshTestBase {
DISALLOW_COPY_AND_ASSIGN(SplitViewControllerTest); DISALLOW_COPY_AND_ASSIGN(SplitViewControllerTest);
}; };
class TestWindowStateDelegate : public wm::WindowStateDelegate {
public:
TestWindowStateDelegate() = default;
~TestWindowStateDelegate() override = default;
// wm::WindowStateDelegate:
void OnDragStarted(int component) override { drag_in_progress_ = true; }
void OnDragFinished(bool cancel, const gfx::Point& location) override {
drag_in_progress_ = false;
}
bool drag_in_progress() { return drag_in_progress_; }
private:
bool drag_in_progress_ = false;
DISALLOW_COPY_AND_ASSIGN(TestWindowStateDelegate);
};
// Tests the basic functionalities. // Tests the basic functionalities.
TEST_F(SplitViewControllerTest, Basic) { TEST_F(SplitViewControllerTest, Basic) {
const gfx::Rect bounds(0, 0, 400, 400); const gfx::Rect bounds(0, 0, 400, 400);
...@@ -165,7 +184,7 @@ TEST_F(SplitViewControllerTest, DefaultSnappedWindow) { ...@@ -165,7 +184,7 @@ TEST_F(SplitViewControllerTest, DefaultSnappedWindow) {
// Tests that if there are two snapped windows, closing one of them will open // Tests that if there are two snapped windows, closing one of them will open
// overview window grid on the closed window side of the screen. If there is // overview window grid on the closed window side of the screen. If there is
// only one snapped windows, closing the sanpped window will end split view mode // only one snapped windows, closing the snapped window will end split view mode
// and adjust the overview window grid bounds if the overview mode is active at // and adjust the overview window grid bounds if the overview mode is active at
// that moment. // that moment.
TEST_F(SplitViewControllerTest, WindowCloseTest) { TEST_F(SplitViewControllerTest, WindowCloseTest) {
...@@ -1266,4 +1285,133 @@ TEST_F(SplitViewControllerTest, NewWindowTest) { ...@@ -1266,4 +1285,133 @@ TEST_F(SplitViewControllerTest, NewWindowTest) {
EXPECT_TRUE(Shell::Get()->window_selector_controller()->IsSelecting()); EXPECT_TRUE(Shell::Get()->window_selector_controller()->IsSelecting());
} }
// Tests that when split view ends because of a transition from tablet mode to
// laptop mode during a resize operation, drags are properly completed.
TEST_F(SplitViewControllerTest, ExitTabletModeDuringResizeCompletesDrags) {
const gfx::Rect bounds(0, 0, 400, 400);
std::unique_ptr<aura::Window> window1(CreateWindow(bounds));
std::unique_ptr<aura::Window> window2(CreateWindow(bounds));
auto* w1_state = wm::GetWindowState(window1.get());
auto* w2_state = wm::GetWindowState(window2.get());
// Setup delegates
auto* window_state_delegate1 = new TestWindowStateDelegate();
auto* window_state_delegate2 = new TestWindowStateDelegate();
w1_state->SetDelegate(base::WrapUnique(window_state_delegate1));
w2_state->SetDelegate(base::WrapUnique(window_state_delegate2));
// Set up windows.
split_view_controller()->SnapWindow(window1.get(), SplitViewController::LEFT);
split_view_controller()->SnapWindow(window2.get(),
SplitViewController::RIGHT);
// Start a drag but don't release the mouse button.
gfx::Rect divider_bounds =
split_view_divider()->GetDividerBoundsInScreen(false /* is_dragging */);
const int screen_width =
screen_util::GetDisplayWorkAreaBoundsInParent(window1.get()).width();
GetEventGenerator().set_current_location(divider_bounds.CenterPoint());
GetEventGenerator().PressLeftButton();
GetEventGenerator().MoveMouseTo(screen_width * 0.67f, 0);
// Drag is started for both windows.
EXPECT_TRUE(window_state_delegate1->drag_in_progress());
EXPECT_TRUE(window_state_delegate2->drag_in_progress());
EXPECT_NE(nullptr, w1_state->drag_details());
EXPECT_NE(nullptr, w2_state->drag_details());
// End tablet mode.
Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(false);
// Drag is ended for both windows.
EXPECT_EQ(nullptr, w1_state->drag_details());
EXPECT_EQ(nullptr, w2_state->drag_details());
EXPECT_FALSE(window_state_delegate1->drag_in_progress());
EXPECT_FALSE(window_state_delegate2->drag_in_progress());
}
// Tests that when a single window is present in split view mode is minimized
// during a resize operation, then drags are properly completed.
TEST_F(SplitViewControllerTest,
MinimizeSingleWindowDuringResizeCompletesDrags) {
const gfx::Rect bounds(0, 0, 400, 400);
std::unique_ptr<aura::Window> window1(CreateWindow(bounds));
auto* w1_state = wm::GetWindowState(window1.get());
// Setup delegate
auto* window_state_delegate1 = new TestWindowStateDelegate();
w1_state->SetDelegate(base::WrapUnique(window_state_delegate1));
// Set up window.
split_view_controller()->SnapWindow(window1.get(), SplitViewController::LEFT);
// Start a drag but don't release the mouse button.
gfx::Rect divider_bounds =
split_view_divider()->GetDividerBoundsInScreen(false /* is_dragging */);
const int screen_width =
screen_util::GetDisplayWorkAreaBoundsInParent(window1.get()).width();
GetEventGenerator().set_current_location(divider_bounds.CenterPoint());
GetEventGenerator().PressLeftButton();
GetEventGenerator().MoveMouseTo(screen_width * 0.67f, 0);
// Drag is started.
EXPECT_TRUE(window_state_delegate1->drag_in_progress());
EXPECT_NE(nullptr, w1_state->drag_details());
// Minimize the window.
wm::WMEvent minimize_event(wm::WM_EVENT_MINIMIZE);
wm::GetWindowState(window1.get())->OnWMEvent(&minimize_event);
// Drag is ended.
EXPECT_FALSE(window_state_delegate1->drag_in_progress());
EXPECT_EQ(nullptr, w1_state->drag_details());
}
// Tests that when two windows are present in split view mode and one of them
// is minimized during a resize, then drags are properly completed.
TEST_F(SplitViewControllerTest,
MinimizeOneOfTwoWindowsDuringResizeCompletesDrags) {
const gfx::Rect bounds(0, 0, 400, 400);
std::unique_ptr<aura::Window> window1(CreateWindow(bounds));
std::unique_ptr<aura::Window> window2(CreateWindow(bounds));
auto* w1_state = wm::GetWindowState(window1.get());
auto* w2_state = wm::GetWindowState(window2.get());
// Setup delegates
auto* window_state_delegate1 = new TestWindowStateDelegate();
auto* window_state_delegate2 = new TestWindowStateDelegate();
w1_state->SetDelegate(base::WrapUnique(window_state_delegate1));
w2_state->SetDelegate(base::WrapUnique(window_state_delegate2));
// Set up windows.
split_view_controller()->SnapWindow(window1.get(), SplitViewController::LEFT);
split_view_controller()->SnapWindow(window2.get(),
SplitViewController::RIGHT);
// Start a drag but don't release the mouse button.
gfx::Rect divider_bounds =
split_view_divider()->GetDividerBoundsInScreen(false /* is_dragging */);
const int screen_width =
screen_util::GetDisplayWorkAreaBoundsInParent(window1.get()).width();
GetEventGenerator().set_current_location(divider_bounds.CenterPoint());
GetEventGenerator().PressLeftButton();
GetEventGenerator().MoveMouseTo(screen_width * 0.67f, 0);
// Drag is started for both windows.
EXPECT_TRUE(window_state_delegate1->drag_in_progress());
EXPECT_TRUE(window_state_delegate2->drag_in_progress());
EXPECT_NE(nullptr, w1_state->drag_details());
EXPECT_NE(nullptr, w2_state->drag_details());
// Minimize the left window.
wm::WMEvent minimize_event(wm::WM_EVENT_MINIMIZE);
wm::GetWindowState(window1.get())->OnWMEvent(&minimize_event);
// Drag is ended just for the left window.
EXPECT_FALSE(window_state_delegate1->drag_in_progress());
EXPECT_TRUE(window_state_delegate2->drag_in_progress());
EXPECT_EQ(nullptr, w1_state->drag_details());
EXPECT_NE(nullptr, w2_state->drag_details());
}
} // namespace ash } // namespace ash
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment