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) {
// smoother resizing visual result.
UpdateSnappedWindowsAndDividerBounds();
for (auto* window : {left_window_, right_window_}) {
if (window == nullptr)
continue;
wm::WindowState* window_state = wm::GetWindowState(window);
window_state->OnCompleteDrag(
GetEndDragLocationInScreen(window, location_in_screen));
window_state->DeleteDragDetails();
}
FinishWindowDrag(left_window_);
FinishWindowDrag(right_window_);
// 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
......@@ -451,6 +445,14 @@ void SplitViewController::EndSplitView() {
if (!IsSplitViewModeActive())
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.
Shell::Get()->RemoveShellObserver(this);
Shell::Get()->activation_client()->RemoveObserver(this);
......@@ -983,6 +985,13 @@ void SplitViewController::OnSnappedWindowMinimizedOrDestroyed(
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 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
......@@ -1249,4 +1258,13 @@ void SplitViewController::EndOverview() {
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
......@@ -303,6 +303,9 @@ class ASH_EXPORT SplitViewController : public mojom::SplitViewController,
void StartOverview();
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.
mojo::BindingSet<mojom::SplitViewController> bindings_;
......
......@@ -19,6 +19,7 @@
#include "ash/wm/splitview/split_view_divider.h"
#include "ash/wm/tablet_mode/tablet_mode_controller.h"
#include "ash/wm/window_state.h"
#include "ash/wm/window_state_delegate.h"
#include "ash/wm/window_util.h"
#include "ash/wm/wm_event.h"
#include "base/stl_util.h"
......@@ -110,6 +111,24 @@ class SplitViewControllerTest : public AshTestBase {
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.
TEST_F(SplitViewControllerTest, Basic) {
const gfx::Rect bounds(0, 0, 400, 400);
......@@ -165,7 +184,7 @@ TEST_F(SplitViewControllerTest, DefaultSnappedWindow) {
// 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
// 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
// that moment.
TEST_F(SplitViewControllerTest, WindowCloseTest) {
......@@ -1266,4 +1285,133 @@ TEST_F(SplitViewControllerTest, NewWindowTest) {
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
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