Commit 76107e3c authored by Qiang Xu's avatar Qiang Xu Committed by Commit Bot

cros: Using original-not-changed-by-user bounds when added to workspace

changes:
When window is added to a workspace from another workspace, its current
window bounds possibly is not the original-not-changed-by-user bounds,
for example a resized bounds truncated by available workarea.

Using a member in ash::wm::WindowState to store the windows bounds. It
is used in window added to workspace event from another workspace. It is
set when window is removing from a workspace and it is nullptr (using
pre_auto_manage_window_bounds() if it exists otherwise current window bounds).
It gets reset when window bounds is changed by user.

DisplayMoveWindowUtilTest.KeepWindowBoundsIfNotChangedByUser, also
tested on emulator. Not-user-resized window bounds will not affect the
original bounds when moving between displays.

Bug: 785017, 778438
Test: added the test coverage in
Change-Id: I37d2c79238ea7200b32b5e3a9d5064addc575976
Reviewed-on: https://chromium-review.googlesource.com/770891
Commit-Queue: Qiang(Joe) Xu <warx@chromium.org>
Reviewed-by: default avatarMitsuru Oshima <oshima@chromium.org>
Cr-Commit-Position: refs/heads/master@{#521063}
parent 33c044c7
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include "ash/shell.h" #include "ash/shell.h"
#include "ash/test/ash_test_base.h" #include "ash/test/ash_test_base.h"
#include "ash/wm/mru_window_tracker.h" #include "ash/wm/mru_window_tracker.h"
#include "ash/wm/window_state.h"
#include "ash/wm/window_util.h" #include "ash/wm/window_util.h"
#include "base/macros.h" #include "base/macros.h"
#include "ui/aura/test/test_windows.h" #include "ui/aura/test/test_windows.h"
...@@ -27,23 +28,8 @@ using DisplayMoveWindowUtilTest = AshTestBase; ...@@ -27,23 +28,8 @@ using DisplayMoveWindowUtilTest = AshTestBase;
// Tests that window bounds are not changing after moving to another display. It // Tests that window bounds are not changing after moving to another display. It
// is added as a child window to another root window with the same origin. // is added as a child window to another root window with the same origin.
TEST_F(DisplayMoveWindowUtilTest, WindowBounds) { TEST_F(DisplayMoveWindowUtilTest, WindowBounds) {
display::Screen* screen = display::Screen::GetScreen();
int64_t primary_id = screen->GetPrimaryDisplay().id();
display::DisplayIdList list =
display::test::CreateDisplayIdList2(primary_id, primary_id + 1);
// Layout: [p][1] // Layout: [p][1]
display::DisplayLayoutBuilder builder(primary_id);
builder.AddDisplayPlacement(list[1], primary_id,
display::DisplayPlacement::RIGHT, 0);
display_manager()->layout_store()->RegisterLayoutForDisplayIdList(
list, builder.Build());
UpdateDisplay("400x300,400x300"); UpdateDisplay("400x300,400x300");
EXPECT_EQ(2U, display_manager()->GetNumDisplays());
EXPECT_EQ(gfx::Rect(0, 0, 400, 300),
display_manager()->GetDisplayAt(0).bounds());
EXPECT_EQ(gfx::Rect(400, 0, 400, 300),
display_manager()->GetDisplayAt(1).bounds());
aura::Window* window = aura::Window* window =
CreateTestWindowInShellWithBounds(gfx::Rect(10, 20, 200, 100)); CreateTestWindowInShellWithBounds(gfx::Rect(10, 20, 200, 100));
wm::ActivateWindow(window); wm::ActivateWindow(window);
...@@ -218,23 +204,8 @@ TEST_F(DisplayMoveWindowUtilTest, SelectClosestCandidate) { ...@@ -218,23 +204,8 @@ TEST_F(DisplayMoveWindowUtilTest, SelectClosestCandidate) {
// Tests that a11y alert is sent on handling move window to display. // Tests that a11y alert is sent on handling move window to display.
TEST_F(DisplayMoveWindowUtilTest, A11yAlert) { TEST_F(DisplayMoveWindowUtilTest, A11yAlert) {
display::Screen* screen = display::Screen::GetScreen();
int64_t primary_id = screen->GetPrimaryDisplay().id();
display::DisplayIdList list =
display::test::CreateDisplayIdList2(primary_id, primary_id + 1);
// Layout: [p][1] // Layout: [p][1]
display::DisplayLayoutBuilder builder(primary_id);
builder.AddDisplayPlacement(list[1], primary_id,
display::DisplayPlacement::RIGHT, 0);
display_manager()->layout_store()->RegisterLayoutForDisplayIdList(
list, builder.Build());
UpdateDisplay("400x300,400x300"); UpdateDisplay("400x300,400x300");
EXPECT_EQ(2U, display_manager()->GetNumDisplays());
EXPECT_EQ(gfx::Rect(0, 0, 400, 300),
display_manager()->GetDisplayAt(0).bounds());
EXPECT_EQ(gfx::Rect(400, 0, 400, 300),
display_manager()->GetDisplayAt(1).bounds());
AccessibilityController* controller = AccessibilityController* controller =
Shell::Get()->accessibility_controller(); Shell::Get()->accessibility_controller();
TestAccessibilityControllerClient client; TestAccessibilityControllerClient client;
...@@ -252,36 +223,116 @@ TEST_F(DisplayMoveWindowUtilTest, A11yAlert) { ...@@ -252,36 +223,116 @@ TEST_F(DisplayMoveWindowUtilTest, A11yAlert) {
// Tests that moving window between displays is no-op if active window is not in // Tests that moving window between displays is no-op if active window is not in
// cycle window list. // cycle window list.
TEST_F(DisplayMoveWindowUtilTest, NoMovementIfNotInCycleWindowList) { TEST_F(DisplayMoveWindowUtilTest, NoMovementIfNotInCycleWindowList) {
display::Screen* screen = display::Screen::GetScreen();
int64_t primary_id = screen->GetPrimaryDisplay().id();
display::DisplayIdList list =
display::test::CreateDisplayIdList2(primary_id, primary_id + 1);
// Layout: [p][1] // Layout: [p][1]
display::DisplayLayoutBuilder builder(primary_id);
builder.AddDisplayPlacement(list[1], primary_id,
display::DisplayPlacement::RIGHT, 0);
display_manager()->layout_store()->RegisterLayoutForDisplayIdList(
list, builder.Build());
UpdateDisplay("400x300,400x300"); UpdateDisplay("400x300,400x300");
EXPECT_EQ(2U, display_manager()->GetNumDisplays());
EXPECT_EQ(gfx::Rect(0, 0, 400, 300),
display_manager()->GetDisplayAt(0).bounds());
EXPECT_EQ(gfx::Rect(400, 0, 400, 300),
display_manager()->GetDisplayAt(1).bounds());
// Create a window in app list container, which would be excluded in cycle // Create a window in app list container, which would be excluded in cycle
// window list. // window list.
std::unique_ptr<aura::Window> window = CreateChildWindow( std::unique_ptr<aura::Window> window = CreateChildWindow(
Shell::GetPrimaryRootWindow(), gfx::Rect(10, 20, 200, 100), Shell::GetPrimaryRootWindow(), gfx::Rect(10, 20, 200, 100),
kShellWindowId_AppListContainer); kShellWindowId_AppListContainer);
wm::ActivateWindow(window.get()); wm::ActivateWindow(window.get());
EXPECT_EQ(list[0], screen->GetDisplayNearestWindow(window.get()).id()); display::Screen* screen = display::Screen::GetScreen();
EXPECT_EQ(display_manager()->GetDisplayAt(0).id(),
screen->GetDisplayNearestWindow(window.get()).id());
MruWindowTracker::WindowList cycle_window_list = MruWindowTracker::WindowList cycle_window_list =
Shell::Get()->mru_window_tracker()->BuildWindowForCycleList(); Shell::Get()->mru_window_tracker()->BuildWindowForCycleList();
EXPECT_TRUE(cycle_window_list.empty()); EXPECT_TRUE(cycle_window_list.empty());
HandleMoveWindowToDisplay(DisplayMoveWindowDirection::kRight); HandleMoveWindowToDisplay(DisplayMoveWindowDirection::kRight);
EXPECT_EQ(list[0], screen->GetDisplayNearestWindow(window.get()).id()); EXPECT_EQ(display_manager()->GetDisplayAt(0).id(),
screen->GetDisplayNearestWindow(window.get()).id());
}
// Tests that window bounds should be kept if it is not changed by user, i.e.
// if it is changed by display area difference, it should restore to the
// original bounds when it is moved between displays and there is enough work
// area to show this window.
TEST_F(DisplayMoveWindowUtilTest, KeepWindowBoundsIfNotChangedByUser) {
// Layout:
// +---+---+
// | p | |
// +---+ 1 |
// | |
// +---+
UpdateDisplay("400x300,400x600");
// Create and activate window on display [1].
aura::Window* window =
CreateTestWindowInShellWithBounds(gfx::Rect(410, 20, 200, 400));
wm::ActivateWindow(window);
display::Screen* screen = display::Screen::GetScreen();
EXPECT_EQ(display_manager()->GetDisplayAt(1).id(),
screen->GetDisplayNearestWindow(window).id());
// Move window to display [p]. Its window bounds is adjusted by available work
// area.
HandleMoveWindowToDisplay(DisplayMoveWindowDirection::kLeft);
EXPECT_EQ(display_manager()->GetDisplayAt(0).id(),
screen->GetDisplayNearestWindow(window).id());
EXPECT_EQ(gfx::Rect(10, 20, 200, 252), window->GetBoundsInScreen());
// Move window back to display [1]. Its window bounds should be restored.
HandleMoveWindowToDisplay(DisplayMoveWindowDirection::kRight);
EXPECT_EQ(display_manager()->GetDisplayAt(1).id(),
screen->GetDisplayNearestWindow(window).id());
EXPECT_EQ(gfx::Rect(410, 20, 200, 400), window->GetBoundsInScreen());
// Move window to display [p] and set that its bounds is changed by user.
wm::WindowState* window_state = wm::GetWindowState(window);
HandleMoveWindowToDisplay(DisplayMoveWindowDirection::kLeft);
window_state->set_bounds_changed_by_user(true);
// Move window back to display [1], but its bounds has been changed by user.
// Then window bounds should be kept the same as that in display [p].
HandleMoveWindowToDisplay(DisplayMoveWindowDirection::kRight);
EXPECT_EQ(display_manager()->GetDisplayAt(1).id(),
screen->GetDisplayNearestWindow(window).id());
EXPECT_EQ(gfx::Rect(410, 20, 200, 252), window->GetBoundsInScreen());
}
// Tests auto window management on moving window between displays.
TEST_F(DisplayMoveWindowUtilTest, AutoManaged) {
// Layout: [p][1]
UpdateDisplay("400x300,400x300");
// Create and show window on display [p]. Enable auto window position managed,
// which will center the window on display [p].
aura::Window* window1 =
CreateTestWindowInShellWithBounds(gfx::Rect(10, 20, 200, 100));
wm::WindowState* window1_state = wm::GetWindowState(window1);
window1_state->SetWindowPositionManaged(true);
window1->Hide();
window1->Show();
EXPECT_EQ(gfx::Rect(100, 20, 200, 100), window1->GetBoundsInScreen());
display::Screen* screen = display::Screen::GetScreen();
EXPECT_EQ(display_manager()->GetDisplayAt(0).id(),
screen->GetDisplayNearestWindow(window1).id());
// Create and show window on display [p]. Enable auto window position managed,
// which will do auto window management (pushing the other window to side).
aura::Window* window2 =
CreateTestWindowInShellWithBounds(gfx::Rect(10, 20, 200, 100));
wm::WindowState* window2_state = wm::GetWindowState(window2);
window2_state->SetWindowPositionManaged(true);
window2->Hide();
window2->Show();
EXPECT_EQ(gfx::Rect(0, 20, 200, 100), window1->GetBoundsInScreen());
EXPECT_EQ(gfx::Rect(200, 20, 200, 100), window2->GetBoundsInScreen());
// Activate window2.
wm::ActivateWindow(window2);
EXPECT_EQ(display_manager()->GetDisplayAt(0).id(),
screen->GetDisplayNearestWindow(window2).id());
EXPECT_TRUE(window2_state->pre_auto_manage_window_bounds());
EXPECT_EQ(gfx::Rect(10, 20, 200, 100),
*window2_state->pre_auto_manage_window_bounds());
// Move window2 to display [1] and check auto window management.
HandleMoveWindowToDisplay(DisplayMoveWindowDirection::kRight);
EXPECT_EQ(display_manager()->GetDisplayAt(1).id(),
screen->GetDisplayNearestWindow(window2).id());
// Check |pre_added_to_workspace_window_bounds()|, which should be equal to
// |pre_auto_manage_window_bounds()| in this case.
EXPECT_EQ(*window2_state->pre_auto_manage_window_bounds(),
*window2_state->pre_added_to_workspace_window_bounds());
// Window 1 centers on display [p] again.
EXPECT_EQ(gfx::Rect(100, 20, 200, 100), window1->GetBoundsInScreen());
// Window 2 is positioned by |pre_added_to_workspace_window_bounds()|.
EXPECT_EQ(gfx::Rect(410, 20, 200, 100), window2->GetBoundsInScreen());
} }
} // namespace ash } // namespace ash
...@@ -158,6 +158,11 @@ void DefaultState::HandleWorkspaceEvents(WindowState* window_state, ...@@ -158,6 +158,11 @@ void DefaultState::HandleWorkspaceEvents(WindowState* window_state,
aura::Window* window = window_state->window(); aura::Window* window = window_state->window();
gfx::Rect bounds = window->bounds(); gfx::Rect bounds = window->bounds();
// When window is added to a workspace, |bounds| may be not the original
// not-changed-by-user bounds, for example a resized bounds truncated by
// available workarea.
if (window_state->pre_added_to_workspace_window_bounds())
bounds = *window_state->pre_added_to_workspace_window_bounds();
// Don't adjust window bounds if the bounds are empty as this // Don't adjust window bounds if the bounds are empty as this
// happens when a new views::Widget is created. // happens when a new views::Widget is created.
......
...@@ -146,7 +146,7 @@ void SetBoundsAnimated(aura::Window* window, ...@@ -146,7 +146,7 @@ void SetBoundsAnimated(aura::Window* window,
void AutoPlaceSingleWindow(aura::Window* window, bool animated) { void AutoPlaceSingleWindow(aura::Window* window, bool animated) {
gfx::Rect work_area = ScreenUtil::GetDisplayWorkAreaBoundsInParent(window); gfx::Rect work_area = ScreenUtil::GetDisplayWorkAreaBoundsInParent(window);
gfx::Rect bounds = window->bounds(); gfx::Rect bounds = window->bounds();
const gfx::Rect* user_defined_area = const base::Optional<gfx::Rect> user_defined_area =
wm::GetWindowState(window)->pre_auto_manage_window_bounds(); wm::GetWindowState(window)->pre_auto_manage_window_bounds();
if (user_defined_area) { if (user_defined_area) {
bounds = *user_defined_area; bounds = *user_defined_area;
......
...@@ -318,7 +318,11 @@ std::unique_ptr<WindowState::State> WindowState::SetStateObject( ...@@ -318,7 +318,11 @@ std::unique_ptr<WindowState::State> WindowState::SetStateObject(
} }
void WindowState::SetPreAutoManageWindowBounds(const gfx::Rect& bounds) { void WindowState::SetPreAutoManageWindowBounds(const gfx::Rect& bounds) {
pre_auto_manage_window_bounds_.reset(new gfx::Rect(bounds)); pre_auto_manage_window_bounds_ = base::make_optional(bounds);
}
void WindowState::SetPreAddedToWorkspaceWindowBounds(const gfx::Rect& bounds) {
pre_added_to_workspace_window_bounds_ = base::make_optional(bounds);
} }
void WindowState::AddObserver(WindowStateObserver* observer) { void WindowState::AddObserver(WindowStateObserver* observer) {
...@@ -365,8 +369,10 @@ void WindowState::SetInImmersiveFullscreen(bool enabled) { ...@@ -365,8 +369,10 @@ void WindowState::SetInImmersiveFullscreen(bool enabled) {
void WindowState::set_bounds_changed_by_user(bool bounds_changed_by_user) { void WindowState::set_bounds_changed_by_user(bool bounds_changed_by_user) {
bounds_changed_by_user_ = bounds_changed_by_user; bounds_changed_by_user_ = bounds_changed_by_user;
if (bounds_changed_by_user) if (bounds_changed_by_user) {
pre_auto_manage_window_bounds_.reset(); pre_auto_manage_window_bounds_.reset();
pre_added_to_workspace_window_bounds_.reset();
}
} }
void WindowState::CreateDragDetails(const gfx::Point& point_in_parent, void WindowState::CreateDragDetails(const gfx::Point& point_in_parent,
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "base/gtest_prod_util.h" #include "base/gtest_prod_util.h"
#include "base/macros.h" #include "base/macros.h"
#include "base/observer_list.h" #include "base/observer_list.h"
#include "base/optional.h"
#include "ui/aura/window_observer.h" #include "ui/aura/window_observer.h"
#include "ui/base/ui_base_types.h" #include "ui/base/ui_base_types.h"
...@@ -237,11 +238,17 @@ class ASH_EXPORT WindowState : public aura::WindowObserver { ...@@ -237,11 +238,17 @@ class ASH_EXPORT WindowState : public aura::WindowObserver {
// Gets/Sets the bounds of the window before it was moved by the auto window // Gets/Sets the bounds of the window before it was moved by the auto window
// management. As long as it was not auto-managed, it will return NULL. // management. As long as it was not auto-managed, it will return NULL.
const gfx::Rect* pre_auto_manage_window_bounds() const { base::Optional<gfx::Rect> pre_auto_manage_window_bounds() const {
return pre_auto_manage_window_bounds_.get(); return pre_auto_manage_window_bounds_;
} }
void SetPreAutoManageWindowBounds(const gfx::Rect& bounds); void SetPreAutoManageWindowBounds(const gfx::Rect& bounds);
// Gets/Sets the property that is used on window added to workspace event.
base::Optional<gfx::Rect> pre_added_to_workspace_window_bounds() const {
return pre_added_to_workspace_window_bounds_;
}
void SetPreAddedToWorkspaceWindowBounds(const gfx::Rect& bounds);
// Layout related properties // Layout related properties
void AddObserver(WindowStateObserver* observer); void AddObserver(WindowStateObserver* observer);
...@@ -392,7 +399,11 @@ class ASH_EXPORT WindowState : public aura::WindowObserver { ...@@ -392,7 +399,11 @@ class ASH_EXPORT WindowState : public aura::WindowObserver {
// A property to remember the window position which was set before the // A property to remember the window position which was set before the
// auto window position manager changed the window bounds, so that it can get // auto window position manager changed the window bounds, so that it can get
// restored when only this one window gets shown. // restored when only this one window gets shown.
std::unique_ptr<gfx::Rect> pre_auto_manage_window_bounds_; base::Optional<gfx::Rect> pre_auto_manage_window_bounds_;
// A property which resets when bounds is changed by user and sets when it is
// nullptr, and window is removing from a workspace.
base::Optional<gfx::Rect> pre_added_to_workspace_window_bounds_;
base::ObserverList<WindowStateObserver> observer_list_; base::ObserverList<WindowStateObserver> observer_list_;
......
...@@ -95,7 +95,19 @@ void WorkspaceLayoutManager::OnWindowAddedToLayout(aura::Window* child) { ...@@ -95,7 +95,19 @@ void WorkspaceLayoutManager::OnWindowAddedToLayout(aura::Window* child) {
void WorkspaceLayoutManager::OnWillRemoveWindowFromLayout(aura::Window* child) { void WorkspaceLayoutManager::OnWillRemoveWindowFromLayout(aura::Window* child) {
windows_.erase(child); windows_.erase(child);
child->RemoveObserver(this); child->RemoveObserver(this);
wm::GetWindowState(child)->RemoveObserver(this); wm::WindowState* window_state = wm::GetWindowState(child);
window_state->RemoveObserver(this);
// When a window is removing from a workspace layout, it is going to be added
// to a new workspace layout or destroyed.
if (!window_state->pre_added_to_workspace_window_bounds()) {
if (window_state->pre_auto_manage_window_bounds()) {
window_state->SetPreAddedToWorkspaceWindowBounds(
*window_state->pre_auto_manage_window_bounds());
} else {
window_state->SetPreAddedToWorkspaceWindowBounds(child->bounds());
}
}
if (child->layer()->GetTargetVisibility()) if (child->layer()->GetTargetVisibility())
WindowPositioner::RearrangeVisibleWindowOnHideOrRemove(child); WindowPositioner::RearrangeVisibleWindowOnHideOrRemove(child);
......
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